diff --git a/.github/composite-actions/build-modified-postgres/action.yml b/.github/composite-actions/build-modified-postgres/action.yml index 4d2567dd75..06baec2d30 100644 --- a/.github/composite-actions/build-modified-postgres/action.yml +++ b/.github/composite-actions/build-modified-postgres/action.yml @@ -59,7 +59,7 @@ runs: elif [[ ${{inputs.engine_branch}} != *"__PG_13_"* ]]; then cd ../.. rm -rf pg_hint_plan - git clone --depth 1 --branch REL15_1_5_0 https://github.com/ossc-db/pg_hint_plan.git + git clone --depth 1 --branch REL15_1_5_1 https://github.com/ossc-db/pg_hint_plan.git cd pg_hint_plan export PATH=$HOME/${{ inputs.install_dir }}/bin:$PATH make diff --git a/contrib/babelfishpg_tsql/sql/sys_views.sql b/contrib/babelfishpg_tsql/sql/sys_views.sql index 5fdb5086f0..8deb11267b 100644 --- a/contrib/babelfishpg_tsql/sql/sys_views.sql +++ b/contrib/babelfishpg_tsql/sql/sys_views.sql @@ -2764,6 +2764,53 @@ SELECT WHERE FALSE; GRANT SELECT ON sys.spatial_index_tessellations TO PUBLIC; +CREATE OR REPLACE VIEW sys.asymmetric_keys +AS +SELECT + CAST('' as sys.sysname) AS name + , CAST(0 as sys.int) AS principal_id + , CAST(0 as sys.int) AS asymmetric_key_id + , CAST('a' as sys.bpchar(2)) AS pvt_key_encryption_type + , CAST('' as sys.nvarchar(60)) AS pvt_key_encryption_type_desc + , CAST(null as sys.varbinary(32)) as thumbprint + , CAST('a' as sys.bpchar(2)) AS algorithm + , CAST('' as sys.nvarchar(60)) AS algorithm_desc + , CAST(0 as sys.int) AS key_length + , CAST(null as sys.varbinary(85)) as sid + , CAST('' as sys.nvarchar(128)) AS string_sid + , CAST(NULL as sys.varbinary(8000)) AS public_key + , CAST('' as sys.nvarchar(260)) AS attested_by + , CAST('' as sys.nvarchar(120)) AS provider_type + , CAST(NULL as sys.UNIQUEIDENTIFIER) as cryptographic_provider_guid + , CAST(NULL AS sys.sql_variant) AS cryptographic_provider_algid + +WHERE FALSE; +GRANT SELECT ON sys.asymmetric_keys TO PUBLIC; + +CREATE OR REPLACE VIEW sys.certificates +AS +SELECT + CAST('' as sys.sysname) AS name + , CAST(0 as sys.int) AS principal_id + , CAST(0 as sys.int) AS asymmetric_key_id + , CAST('a' as sys.bpchar(2)) AS pvt_key_encryption_type + , CAST('' as sys.nvarchar(60)) AS pvt_key_encryption_type_desc + , CAST(0 as sys.bit) AS is_active_for_begin_dialog + , CAST('' as sys.nvarchar(442)) AS issuer_name + , CAST('' as sys.nvarchar(64)) AS cert_serial_number + , CAST(null as sys.varbinary(85)) as sid + , CAST('' as sys.nvarchar(128)) AS string_sid + , CAST('' as sys.nvarchar(4000)) AS subject + , CAST('' as sys.datetime) AS expiry_date + , CAST('' as sys.datetime) AS start_date + , CAST(null as sys.varbinary(32)) as thumbprint + , CAST('' as sys.nvarchar(260)) as attested_by + , CAST('' as sys.datetime) AS pvt_key_last_backup_date + , CAST(0 AS sys.int) AS key_length + +WHERE FALSE; +GRANT SELECT ON sys.certificates TO PUBLIC; + CREATE OR REPLACE VIEW sys.all_parameters AS SELECT @@ -3004,3 +3051,19 @@ SELECT CAST(0 as sys.BIT) AS is_ambiguous WHERE FALSE; GRANT SELECT ON sys.sql_expression_dependencies TO PUBLIC; + +CREATE OR REPLACE VIEW sys.database_permissions +AS +SELECT + CAST(0 as sys.tinyint) AS class, + CAST('' as sys.NVARCHAR(60)) AS class_desc, + CAST(0 as sys.int) AS major_id, + CAST(0 as sys.int) AS minor_id, + CAST(0 as sys.int) AS grantee_principal_id, + CAST(0 as sys.int) AS grantor_principal_id, + CAST('a' as sys.BPCHAR(4)) AS type, + CAST('' as sys.NVARCHAR(128)) AS permission_name, + CAST('G' as sys.BPCHAR(1)) AS state, + CAST('' as sys.NVARCHAR(60)) AS state_desc +WHERE FALSE; +GRANT SELECT ON sys.database_permissions TO PUBLIC; diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.3.0--3.4.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.3.0--3.4.0.sql index f05294b8fc..d30852cd6b 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.3.0--3.4.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.3.0--3.4.0.sql @@ -38,6 +38,70 @@ LANGUAGE plpgsql; * final behaviour. */ + +CREATE OR REPLACE VIEW sys.asymmetric_keys +AS +SELECT + CAST('' as sys.sysname) AS name + , CAST(0 as sys.int) AS principal_id + , CAST(0 as sys.int) AS asymmetric_key_id + , CAST('a' as sys.bpchar(2)) AS pvt_key_encryption_type + , CAST('' as sys.nvarchar(60)) AS pvt_key_encryption_type_desc + , CAST(null as sys.varbinary(32)) as thumbprint + , CAST('a' as sys.bpchar(2)) AS algorithm + , CAST('' as sys.nvarchar(60)) AS algorithm_desc + , CAST(0 as sys.int) AS key_length + , CAST(null as sys.varbinary(85)) as sid + , CAST('' as sys.nvarchar(128)) AS string_sid + , CAST(NULL as sys.varbinary(8000)) AS public_key + , CAST('' as sys.nvarchar(260)) AS attested_by + , CAST('' as sys.nvarchar(120)) AS provider_type + , CAST(NULL as sys.UNIQUEIDENTIFIER) as cryptographic_provider_guid + , CAST(NULL AS sys.sql_variant) AS cryptographic_provider_algid + +WHERE FALSE; +GRANT SELECT ON sys.asymmetric_keys TO PUBLIC; + +CREATE OR REPLACE VIEW sys.certificates +AS +SELECT + CAST('' as sys.sysname) AS name + , CAST(0 as sys.int) AS principal_id + , CAST(0 as sys.int) AS asymmetric_key_id + , CAST('a' as sys.bpchar(2)) AS pvt_key_encryption_type + , CAST('' as sys.nvarchar(60)) AS pvt_key_encryption_type_desc + , CAST(0 as sys.bit) AS is_active_for_begin_dialog + , CAST('' as sys.nvarchar(442)) AS issuer_name + , CAST('' as sys.nvarchar(64)) AS cert_serial_number + , CAST(null as sys.varbinary(85)) as sid + , CAST('' as sys.nvarchar(128)) AS string_sid + , CAST('' as sys.nvarchar(4000)) AS subject + , CAST('' as sys.datetime) AS expiry_date + , CAST('' as sys.datetime) AS start_date + , CAST(null as sys.varbinary(32)) as thumbprint + , CAST('' as sys.nvarchar(260)) as attested_by + , CAST('' as sys.datetime) AS pvt_key_last_backup_date + , CAST(0 AS sys.int) AS key_length + +WHERE FALSE; +GRANT SELECT ON sys.certificates TO PUBLIC; + +CREATE OR REPLACE VIEW sys.database_permissions +AS +SELECT + CAST(0 as sys.tinyint) AS class, + CAST('' as sys.NVARCHAR(60)) AS class_desc, + CAST(0 as sys.int) AS major_id, + CAST(0 as sys.int) AS minor_id, + CAST(0 as sys.int) AS grantee_principal_id, + CAST(0 as sys.int) AS grantor_principal_id, + CAST('a' as sys.bpchar(4)) AS type, + CAST('' as sys.NVARCHAR(128)) AS permission_name, + CAST('G' as sys.bpchar(1)) AS state, + CAST('' as sys.NVARCHAR(60)) AS state_desc +WHERE FALSE; +GRANT SELECT ON sys.database_permissions TO PUBLIC; + CREATE OR REPLACE VIEW information_schema_tsql.key_column_usage AS SELECT CAST(nc.dbname AS sys.nvarchar(128)) AS "CONSTRAINT_CATALOG", diff --git a/contrib/babelfishpg_tsql/src/tsqlIface.cpp b/contrib/babelfishpg_tsql/src/tsqlIface.cpp index c81af88676..2efe330c62 100644 --- a/contrib/babelfishpg_tsql/src/tsqlIface.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlIface.cpp @@ -170,9 +170,10 @@ template static std::string rewrite_column_name_with_omitted_schema_na static bool does_object_name_need_delimiter(TSqlParser::IdContext *id); static std::string delimit_identifier(TSqlParser::IdContext *id); static bool does_msg_exceeds_params_limit(const std::string& msg); -static std::string getProcNameFromExecParam(TSqlParser::Execute_parameterContext *exParamCtx); static std::string getIDName(TerminalNode *dq, TerminalNode *sb, TerminalNode *id); static ANTLR_result antlr_parse_query(const char *sourceText, bool useSSLParsing); +std::string rewriteDoubleQuotedString(const std::string strDoubleQuoted); + /* * Structure / Utility function for general purpose of query string modification * @@ -398,6 +399,25 @@ std::pair getLineAndPos(TerminalNode *node) static ParseTreeProperty fragments; +// Keeps track of location of expressions being rewritten into a fragment 'SELECT ' +static std::map>> selectFragmentOffsets; + +// Record the offsets for a 'SELECT ' fragment +void +recordSelectFragmentOffsets(ParseTree *ctx, int ixStart, int ixEnd, int ixShift) +{ + Assert(ctx); + selectFragmentOffsets.emplace(std::make_pair(ctx, std::make_pair(ixStart, std::make_pair(ixEnd, ixShift)))); +} + +void +recordSelectFragmentOffsets(ParseTree *ctx, ParserRuleContext *expr) +{ + Assert(ctx); + Assert(expr); + recordSelectFragmentOffsets(ctx, expr->getStart()->getStartIndex(), expr->getStop()->getStopIndex(), 0); +} + void attachPLtsql_fragment(ParseTree *node, PLtsql_stmt *fragment) { @@ -500,6 +520,7 @@ class PLtsql_expr_query_mutator PLtsql_expr_query_mutator(PLtsql_expr *expr, ParserRuleContext* baseCtx); void add(int antlr_pos, std::string orig_text, std::string repl_text); + void markSelectFragment(ParserRuleContext *ctx); void run(); @@ -509,8 +530,14 @@ class PLtsql_expr_query_mutator protected: // intentionally use std::map to iterate it via sorted order. std::map> m; // pos -> (orig_text, repl_text) - - int base_idx; + + int base_idx; + + // Indicate the fragment being processed is an expression that was prefixed with 'SELECT ' + bool isSelectFragment = false; + int idxStart = 0; + int idxEnd = 0; + int idxStartShift = 0; }; PLtsql_expr_query_mutator::PLtsql_expr_query_mutator(PLtsql_expr *e, ParserRuleContext* baseCtx) @@ -522,24 +549,66 @@ PLtsql_expr_query_mutator::PLtsql_expr_query_mutator(PLtsql_expr *e, ParserRuleC throw PGErrorWrapperException(ERROR, ERRCODE_INTERNAL_ERROR, "can't mutate an internal query. NULL expression", getLineAndPos(baseCtx)); size_t base_index = baseCtx->getStart()->getStartIndex(); + if (base_index == INVALID_INDEX) throw PGErrorWrapperException(ERROR, ERRCODE_INTERNAL_ERROR, "can't mutate an internal query. base index is invalid", getLineAndPos(baseCtx)); base_idx = base_index; + isSelectFragment = false; +} + +void PLtsql_expr_query_mutator::markSelectFragment(ParserRuleContext *ctx) +{ + Assert(ctx); + Assert(selectFragmentOffsets.count(ctx) > 0); + + auto p = selectFragmentOffsets.at(ctx); + + isSelectFragment = true; + idxStart = p.first; + idxEnd = p.second.first; + idxStartShift = p.second.second; } void PLtsql_expr_query_mutator::add(int antlr_pos, std::string orig_text, std::string repl_text) { int offset = antlr_pos - base_idx; + + if (isSelectFragment) + { + // For SELECT fragments, only apply the item when antlr_pos is between idxStart and idxEnd: + // when there are multiple expressions per statement (only for DECLARE), the rewrites must be + // applied to the correct expression + if ((antlr_pos < idxStart) || (antlr_pos > idxEnd)) + { + return; + } - /* validation check */ - if (offset < 0) - throw PGErrorWrapperException(ERROR, ERRCODE_INTERNAL_ERROR, "can't mutate an internal query. offset value is negative", 0, 0); - if (offset > (int)strlen(expr->query)) - throw PGErrorWrapperException(ERROR, ERRCODE_INTERNAL_ERROR, "can't mutate an internal query. offset value is too large", 0, 0); + // Adjust offset to reflect the fact that the expression in the fragment is now prefixed with only 'SELECT ' + offset = antlr_pos - idxStart; + + // Adjust offset once more if the expression was shifted left (for a compound SET @v operator) + if (idxStartShift > 0) + { + offset = offset + idxStartShift; + } + } + + if ((orig_text.front() == '"') && (orig_text.back() == '"') && (repl_text.front() == '\'') && (repl_text.back() == '\'')) + { + // Do not validate the positions of strings as these are not replaced by their positions + } + else { + /* validation check */ + if (offset < 0) + throw PGErrorWrapperException(ERROR, ERRCODE_INTERNAL_ERROR, "can't mutate an internal query. offset value is negative", 0, 0); + if (offset > (int)strlen(expr->query)) + throw PGErrorWrapperException(ERROR, ERRCODE_INTERNAL_ERROR, "can't mutate an internal query. offset value is too large", 0, 0); + } m.emplace(std::make_pair(offset, std::make_pair(orig_text, repl_text))); } + void PLtsql_expr_query_mutator::run() { /* @@ -550,17 +619,19 @@ void PLtsql_expr_query_mutator::run() */ std::u32string query = utf8_to_utf32(expr->query); std::u32string rewritten_query; - + size_t cursor = 0; // cursor to expr->query where next copy should start for (const auto &entry : m) - { + { size_t offset = entry.first; const std::u32string& orig_text = utf8_to_utf32(entry.second.first.c_str()); const std::u32string& repl_text = utf8_to_utf32(entry.second.second.c_str()); + if (isSelectFragment) offset += 7; // because this is an expression prefixed with 'SELECT ' + if (orig_text.length() == 0 || orig_text.c_str(), query.substr(offset, orig_text.length()) == orig_text) // local_id maybe already deleted in some cases such as select-assignment. check here if it still exists) { if (offset - cursor < 0) - throw PGErrorWrapperException(ERROR, ERRCODE_INTERNAL_ERROR, "can't mutate an internal query. might be due to mulitiple mutation on the same position", 0, 0); + throw PGErrorWrapperException(ERROR, ERRCODE_INTERNAL_ERROR, "can't mutate an internal query. might be due to multiple mutations on the same position", 0, 0); if (offset - cursor > 0) // if offset==cursor, no need to copy rewritten_query += query.substr(cursor, offset - cursor); // copy substring of expr->query. ranged [cursor, offset) rewritten_query += repl_text; @@ -569,8 +640,8 @@ void PLtsql_expr_query_mutator::run() } if (cursor < strlen(expr->query)) rewritten_query += query.substr(cursor); // copy remaining expr->query - - // update query string with quoted one + + // update query string std::string new_query = antlrcpp::utf32_to_utf8(rewritten_query); expr->query = pstrdup(new_query.c_str()); } @@ -600,37 +671,6 @@ add_query_hints(PLtsql_expr_query_mutator *mutator, int contextOffset) mutator->add(contextOffset + initialTokenOffset, "", hint); } -// Try to retrieve the procedure name as in execute_body/execute_body_batch -// from the context of execute_parameter. -static std::string getProcNameFromExecParam(TSqlParser::Execute_parameterContext *exParamCtx) -{ - antlr4::tree::ParseTree *ctx = exParamCtx; - // We only need to loop max number of dereferences needed from the context - // of execute_parameter to execute_body/execute_body_batch. - // Currently that number is 3 + (number of execute_statement_arg_unnamed - 1). - // Because for now we only need this function for sp_tables which have - // at most 5 parameters, 8 seems to be good enough here. - int cnt = 8; - - while (ctx->parent != nullptr && cnt-- > 0) - { - TSqlParser::Execute_bodyContext * exBodyCtx = dynamic_cast(ctx->parent); - TSqlParser::Execute_body_batchContext *exBodyBatchCtx = dynamic_cast(ctx->parent); - TSqlParser::IdContext *proc = nullptr; - - if (exBodyCtx != nullptr && exBodyCtx->proc_var == nullptr) - proc = exBodyCtx->func_proc_name_server_database_schema()->procedure; - else if (exBodyBatchCtx != nullptr) - proc = exBodyBatchCtx->func_proc_name_server_database_schema()->procedure; - - if (proc != nullptr) - return stripQuoteFromId(proc); - - ctx = ctx->parent; - } - return ""; -} - static std::string validate_and_stringify_hints() { @@ -854,7 +894,7 @@ class tsqlCommonMutator : public TSqlParserBaseListener server_name_str = getFullText(obj_server->keyword()); else server_name_str = getIDName(obj_server->DOUBLE_QUOTE_ID(), obj_server->SQUARE_BRACKET_ID(), obj_server->ID()); - + std::string quoted_server_str = std::string("'") + server_name_str + std::string("'"); std::string three_part_name = ::getFullText(obj_database) + std::string(".") + ::getFullText(obj_schema) + std::string(".") + ::getFullText(obj_name); @@ -986,7 +1026,7 @@ class tsqlCommonMutator : public TSqlParserBaseListener } } #endif - + // don't need to call does_object_name_need_delimiter() because problematic keywords are already allowed as function name } @@ -1040,7 +1080,7 @@ class tsqlCommonMutator : public TSqlParserBaseListener linked_srv_name = getFullText(linked_srv->keyword()); else linked_srv_name = getIDName(linked_srv->DOUBLE_QUOTE_ID(), linked_srv->SQUARE_BRACKET_ID(), linked_srv->ID()); - + std::string str = std::string("'") + linked_srv_name + std::string("'"); rewritten_query_fragment.emplace(std::make_pair(ctx->OPENQUERY()->getSymbol()->getStartIndex(), std::make_pair(::getFullText(ctx->OPENQUERY()), "openquery_internal"))); @@ -1143,7 +1183,7 @@ class tsqlBuilder : public tsqlCommonMutator std::string db_name; bool is_function = false; bool is_schema_specified = false; - + // We keep a stack of the containers that are active during a traversal. // A container will correspond to a block or a batch - these are containers // because they contain a list of the PLtsql_stmt structures. @@ -1550,7 +1590,7 @@ class tsqlBuilder : public tsqlCommonMutator throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "'DDL trigger' is not currently supported in Babelfish.", 0, 0); } } - + ////////////////////////////////////////////////////////////////////////////// // Non-container statement management ////////////////////////////////////////////////////////////////////////////// @@ -1748,6 +1788,41 @@ class tsqlBuilder : public tsqlCommonMutator clear_rewritten_query_fragment(); } + void exitCfl_statement(TSqlParser::Cfl_statementContext *ctx) override + { + PLtsql_expr *expr = nullptr; + if (ctx->print_statement()) + { + PLtsql_stmt_print *stmt = (PLtsql_stmt_print *) getPLtsql_fragment(ctx); + expr = (PLtsql_expr *) linitial(stmt->exprs); + } + else if (ctx->raiseerror_statement() && ctx->raiseerror_statement()->raiseerror_msg() && ctx->raiseerror_statement()->raiseerror_msg()->char_string()) + { + PLtsql_stmt_raiserror *stmt = (PLtsql_stmt_raiserror *) getPLtsql_fragment(ctx); + expr = (PLtsql_expr *) linitial(stmt->params); + } + else if (ctx->return_statement()) + { + if (pltsql_curr_compile && pltsql_curr_compile->fn_prokind != PROKIND_PROCEDURE) + { + PLtsql_stmt_return *stmt = (PLtsql_stmt_return *) getPLtsql_fragment(ctx); + expr = (PLtsql_expr *) stmt->expr; + } + } + if (expr) + { + PLtsql_expr_query_mutator mutator(expr, ctx); + mutator.markSelectFragment(ctx); + add_rewritten_query_fragment_to_mutator(&mutator); + mutator.run(); + + // remove the offsets for processed fragments + selectFragmentOffsets.clear(); + + clear_rewritten_query_fragment(); + } + } + void exitSecurity_statement(TSqlParser::Security_statementContext *ctx) override { if (ctx->grant_statement() && ctx->grant_statement()->TO() && !ctx->grant_statement()->permission_object() @@ -1803,9 +1878,9 @@ class tsqlBuilder : public tsqlCommonMutator clear_rewritten_query_fragment(); } - + void exitAnother_statement(TSqlParser::Another_statementContext *ctx) override - { + { // currently, declare_cursor only need rewriting because it contains select statement if (ctx->cursor_statement() && ctx->cursor_statement()->declare_cursor()) { @@ -1814,16 +1889,16 @@ class tsqlBuilder : public tsqlCommonMutator } // Declare table type statement might need rewriting in column definition list. - if (ctx->declare_statement() && ctx->declare_statement()->table_type_definition()) + else if (ctx->declare_statement() && ctx->declare_statement()->table_type_definition()) { PLtsql_stmt_decl_table *decl_table_stmt = (PLtsql_stmt_decl_table *) getPLtsql_fragment(ctx); post_process_declare_table_statement(decl_table_stmt, ctx->declare_statement()->table_type_definition()); } - if (ctx->execute_statement()) + else if (ctx->execute_statement()) { PLtsql_stmt_exec *stmt = (PLtsql_stmt_exec *) getPLtsql_fragment(ctx); - if (stmt->cmd_type == PLTSQL_STMT_EXEC && stmt->proc_name && pg_strcasecmp("sp_tables", stmt->proc_name) == 0) + if (stmt->cmd_type == PLTSQL_STMT_EXEC) { PLtsql_expr_query_mutator mutator(stmt->expr, ctx); add_rewritten_query_fragment_to_mutator(&mutator); // move information of rewritten_query_fragment to mutator. @@ -1831,48 +1906,112 @@ class tsqlBuilder : public tsqlCommonMutator } } + else if (ctx->set_statement() && ctx->set_statement()->expression()) + { + // There should always be offsets for SET expressions + Assert(selectFragmentOffsets.find(ctx->set_statement()) != selectFragmentOffsets.end()); + + PLtsql_stmt_assign *stmt = (PLtsql_stmt_assign *) getPLtsql_fragment(ctx->set_statement()); + PLtsql_expr_query_mutator mutator(stmt->expr, ctx->set_statement()); + mutator.markSelectFragment(ctx->set_statement()); + add_rewritten_query_fragment_to_mutator(&mutator); + mutator.run(); + } + + else if (ctx->declare_statement()) + { + if (ctx->declare_statement()->declare_local().size() > 0) + { + // For each assignment to a @variable, a fragment was created (via makeInitializer). + // There can be multiple declarations and assignments in a single DECLARE, and these are processed below. + int i = 0; + for (TSqlParser::Declare_localContext *d : ctx->declare_statement()->declare_local() ) + { + i++; + if (d->expression()) + { + ParserRuleContext *ctx_fragment = (ParserRuleContext *) ctx; + if (selectFragmentOffsets.find(d->expression()) != selectFragmentOffsets.end()) + { + ctx_fragment = d->expression(); + } + + PLtsql_stmt_assign *stmt = (PLtsql_stmt_assign *) getPLtsql_fragment(ctx_fragment); + PLtsql_expr_query_mutator mutator(stmt->expr, ctx_fragment); + mutator.markSelectFragment(ctx_fragment); + add_rewritten_query_fragment_to_mutator(&mutator); + mutator.run(); + } + } + } + } + + // remove the offsets for processed fragments + selectFragmentOffsets.clear(); + clear_rewritten_query_fragment(); } + void exitChar_string(TSqlParser::Char_stringContext *ctx) override + { + if (ctx->STRING()) + { + std::string str = ctx->STRING()->getSymbol()->getText(); + + if (str.front() == 'N') + { + // This is only to make the assertion on str.front() easy (below) + str.erase(0, 1); + } + + if (str.front() == '"') + { + Assert(str.back() == '"'); + + // Change double-quoted string to single-quoted string: + str = rewriteDoubleQuotedString(str); + size_t startPosition = ctx->start->getStartIndex(); + rewritten_query_fragment.emplace(std::make_pair(startPosition, std::make_pair(::getFullText(ctx), str))); + } + else + { + // This is a single-quoted string, no further action needed + Assert(str.front() == '\''); + Assert(str.back() == '\''); + } + } + } + void exitExecute_parameter(TSqlParser::Execute_parameterContext *ctx) override { - if (ctx->constant() || ctx->id()) + if (ctx->id()) { - // BABEL-2395, BABEL-3640: embedded single quotes are allowed in procedure parameters. - // in tsqlMutator::enterExecute_parameter, we replace "" with '', and also record the place of "" into - // double_quota_places, then in here, we'll replace all ' into '' if it's inside "" - // we replace " in tsqlMutator::enterExecute_parameter first to pass the syntax validation - // then we'll use the double quota rule to replace "'A'" to '''A''' - if (pg_strcasecmp(getProcNameFromExecParam(ctx).c_str(), "sp_tables") == 0) + // A stored procedure parameter which is parsed as a column name (= identifier) + // is either an unquoted string, or a double-quoted string. + // For a procedure call parameter, a double-quoted string is interpreted + // as a string even with QUOTED_IDENTIFIER=ON. + + std::string str = getFullText(ctx->id()); + + if (str.front() == '"') { - std::string argStr; - if (ctx->constant()) - argStr = getFullText(ctx->constant()); - else if (ctx->id()) - argStr = getFullText(ctx->id()); - - std::string newStr; - if (argStr.size() > 1 && argStr.front() == '\'' && argStr.back() == '\'' - && std::binary_search (double_quota_places.begin(), double_quota_places.end(), parameterIndex)) - { - newStr += '\''; - for (std::string::iterator iter = argStr.begin() + 1; iter != argStr.end() - 1; ++iter) - if (*iter == '\'') - { - newStr += "\'\'"; - } else{ - newStr += *iter; - } - newStr += '\''; - if (ctx->constant()) - rewritten_query_fragment.emplace(std::make_pair(ctx->start->getStartIndex(), - std::make_pair(::getFullText(ctx->constant()), newStr))); - else - rewritten_query_fragment.emplace(std::make_pair(ctx->start->getStartIndex(), std::make_pair(getFullText(ctx->id()), newStr))); - } + Assert(str.back() == '"'); + + // Change double-quoted string to single-quoted string + str = rewriteDoubleQuotedString(str); + rewritten_query_fragment.emplace(std::make_pair(ctx->start->getStartIndex(), std::make_pair(getFullText(ctx->id()), str))); + } + else if (str.front() == '\'') + { + // This is a single-quoted string, no further action needed + Assert(str.back() == '\''); + } + else + { + // This is an unquoted string parameter which has been parsed as a column name. + // This is dealt with downstream. } } - parameterIndex++; } void enterCfl_statement(TSqlParser::Cfl_statementContext *ctx) override @@ -2129,6 +2268,7 @@ class tsqlBuilder : public tsqlCommonMutator { graft(makeExecBodyBatch(ctx), peekContainer()); } + PLtsql_expr *rewrite_if_condition(TSqlParser::Search_conditionContext *ctx) { @@ -2159,7 +2299,7 @@ class tsqlBuilder : public tsqlCommonMutator PLtsql_stmt_while *fragment = (PLtsql_stmt_while *) getPLtsql_fragment(ctx->parent->parent); fragment->cond = rewrite_if_condition(ctx); } - } + } }; //////////////////////////////////////////////////////////////////////////////// @@ -2177,7 +2317,6 @@ class tsqlMutator : public TSqlParserBaseListener MyInputStream &stream; std::vector double_quota_places; - int parameterIndex = 0; explicit tsqlMutator(MyInputStream &s) : stream(s) @@ -2185,95 +2324,6 @@ class tsqlMutator : public TSqlParserBaseListener } public: - void enterConstant(TSqlParser::ConstantContext *ctx) override - { - if (ctx->char_string() && ctx->char_string()->STRING()) - { - std::string str = ctx->char_string()->STRING()->getSymbol()->getText(); - - if (str.front() == 'N') - str.erase(0, 1); - - if (str.front() == '"') - { - Assert(str.front() == '"'); - Assert(str.back() == '"'); - - if (str.find('\'') == std::string::npos) - { - // no embedded single-quotes, just change from "foo" to 'foo' - str.front() = '\''; - str.back() = '\''; - - stream.setText(ctx->start->getStartIndex(), str.c_str()); - } - else - { - throw PGErrorWrapperException(ERROR, - ERRCODE_INTERNAL_ERROR, - "double-quoted string literals cannot contain single-quotes while QUOTED_IDENTIFIER=OFF", 0, 0); - } - } - else - { - Assert(str.front() == '\''); - Assert(str.back() == '\''); - } - } - } - - void enterExecute_parameter(TSqlParser::Execute_parameterContext *ctx) override - { - // An execute_parameter represents a parameter in an EXECUTE statement. - // The grammar says that an execute_parameter may be a constant, an id(entifier), - // a LOCAL_ID (@name), or the word DEFAULT. We don't have to mutate a LOCAL_ID - // or DEFAULT - // - // If we find a double-quoted string constant, we change it to a single-quoted - // string constant. - // - // If we find a double-quoted identifier, we change it to a single-quoted - // string context. - // - // Examples: - // - // exec myproc test -> ctx->id (test) - // don't mutate, test is an identifier - // - // exec myproc 'test' -> ctx->constant ('test') - // don't mutate, 'test' is a string literal - // - // exec myproc "test" (QUOTED_IDENTIFIER=ON) -> ctx->id("test") - // mutate to a single-quoted string literal - // - // exec myproc "test" (QUOTED_IDENTIFIER=OFF) -> ctx->constant("test") - // mutate to a single-quoted string literal - - std::string argStr; - if (ctx->constant()) - argStr = getFullText(ctx->constant()); - else if (ctx->id()) - argStr = getFullText(ctx->id()); - - if (ctx->constant() || ctx->id()) - { - if (argStr.front() == '"' && argStr.back() == '"') - { - // if it's sp_tables, we will rewrite this into - // exec sp_tables "test" -> exec sp_tables 'test' - // exec sp_tables "'test'" -> exec sp_tables '''test''' - if (pg_strcasecmp(getProcNameFromExecParam(ctx).c_str() , "sp_tables") == 0) - { - double_quota_places.push_back(parameterIndex); - } - argStr.front() = '\''; - argStr.back() = '\''; - stream.setText(ctx->start->getStartIndex(), argStr.c_str()); - } - } - parameterIndex++; - } - void enterFunc_proc_name_schema(TSqlParser::Func_proc_name_schemaContext *ctx) override { // We are looking at a function name; it may be a function call, or a @@ -2347,7 +2397,7 @@ class tsqlMutator : public TSqlParserBaseListener } } #endif - + // if the func name contains colon_colon, it must begin with it. see grammar if (ctx->colon_colon()) { @@ -4049,8 +4099,11 @@ makeReturnStmt(TSqlParser::Return_statementContext *ctx) std::string expr = std::string("CAST( ") + ::getFullText(ctx->expression()) + " AS INT)"; result->expr = makeTsqlExpr(expr, true); } - else + else + { result->expr = makeTsqlExpr(ctx->expression(), true); + recordSelectFragmentOffsets(ctx->parent, ctx->expression()); + } } else result->expr = NULL; @@ -4180,6 +4233,7 @@ makePrintStmt(TSqlParser::Print_statementContext *ctx) result->cmd_type = PLTSQL_STMT_PRINT; result->exprs = list_make1(makeTsqlExpr(ctx->expression(), true)); + recordSelectFragmentOffsets(ctx->parent, ctx->expression()); return result; } @@ -4199,6 +4253,8 @@ makeRaiseErrorStmt(TSqlParser::Raiseerror_statementContext *ctx) // msg, severity, state result->params = lappend(result->params, makeTsqlExpr(ctx->msg->getText(), true)); + recordSelectFragmentOffsets(ctx->parent, ctx->raiseerror_msg()); + result->params = lappend(result->params, makeTsqlExpr(ctx->severity, true)); result->params = lappend(result->params, makeTsqlExpr(ctx->state, true)); @@ -4242,13 +4298,13 @@ makeRaiseErrorStmt(TSqlParser::Raiseerror_statementContext *ctx) } PLtsql_stmt * -makeInitializer(PLtsql_variable *var, TSqlParser::ExpressionContext *val) +makeInitializer(int varno, int lineno, TSqlParser::ExpressionContext *val) { PLtsql_stmt_assign *result = (PLtsql_stmt_assign *) palloc0(sizeof(*result)); result->cmd_type = PLTSQL_STMT_ASSIGN; - result->lineno = 0; - result->varno = var->dno; + result->lineno = lineno; + result->varno = varno; result->expr = makeTsqlExpr(val, true); // We've created an assignment statement out of the @@ -4259,14 +4315,11 @@ makeInitializer(PLtsql_variable *var, TSqlParser::ExpressionContext *val) // the nearest enclosing block - variables are scoped // to the function/procedure/batch. - //rootInitializers = lappend(rootInitializers, result); - return (PLtsql_stmt *) result; } - std::vector -makeDeclareStmt(TSqlParser::Declare_statementContext *ctx) +makeDeclareStmt(TSqlParser::Declare_statementContext *ctx, std::map *declare_local_expr) { std::vector result; @@ -4275,7 +4328,7 @@ makeDeclareStmt(TSqlParser::Declare_statementContext *ctx) // declared variables as a vector. // // Please note that we should keep the order of - // statement becaue initializer can be a function or + // statement because initializer can be a function or // global variable so they can be affected by // preceeding statements. That's the reason why // we don't use rootInitializer any more. @@ -4332,8 +4385,21 @@ makeDeclareStmt(TSqlParser::Declare_statementContext *ctx) if (var->dtype == PLTSQL_DTYPE_TBL) result.push_back(makeDeclTableStmt(var, type, getLineNo(ctx))); - else if (local->expression()) - result.push_back(makeInitializer(var, local->expression())); + else if (local->expression()) + { + PLtsql_stmt *e = makeInitializer(var->dno, getLineNo(ctx), local->expression()); + result.push_back(e); + + // DECLARE is different from other stmts under Another_statement, in that multiple fragments may be created. + // By associating these with the expression() node, they can be stored without issues (otherwise, exitAnother_statement + // would use the context of the Another_statement rule for all fragments and all but the last would be lost). + (*declare_local_expr).emplace(std::make_pair(e, local->expression())); + + // Each variable assignment in DECLARE becomes a fragment, for which rewriting may be required. Since all rewrite actions + // will be accumulated by the time the rewriting happens (in exitAnother_statement), we need to keep track of where + // the assignment is located (start-end of range) so that we can apply the rewrites correctly. + recordSelectFragmentOffsets(local->expression(), local->expression()); + } } } } @@ -4443,8 +4509,6 @@ makeSetStatement(TSqlParser::Set_statementContext *ctx, tsqlBuilder &builder) if (expr && localID) { - PLtsql_stmt_assign *result = (PLtsql_stmt_assign *) palloc0(sizeof(*result)); - auto targetText = ::getFullText(localID); int dno = check_assignable(localID); @@ -4454,10 +4518,11 @@ makeSetStatement(TSqlParser::Set_statementContext *ctx, tsqlBuilder &builder) char *target = pstrdup(targetText.c_str()); pltsql_parse_word(target, target, &wdatum, &word); - result->cmd_type = PLTSQL_STMT_ASSIGN; - result->lineno = getLineNo(ctx); - result->varno = dno; - result->expr = makeTsqlExpr(expr, true); + PLtsql_stmt_assign *result = (PLtsql_stmt_assign *) makeInitializer(dno, getLineNo(ctx), expr); + + int posStart = expr->getStart()->getStartIndex(); + int posEnd = expr->getStop()->getStopIndex() ; + int posBracket = 0; // assigned below if (ctx->assignment_operator()) { @@ -4489,13 +4554,26 @@ makeSetStatement(TSqlParser::Set_statementContext *ctx, tsqlBuilder &builder) * SET @var ^= 5 - 1 * to * SET @var = "@var" ^ (5 -1) - */ + */ StringInfoData new_query; - initStringInfo(&new_query); - appendStringInfo(&new_query, "SELECT \"%s\" %s (%s)", target, rewrite_assign_operator(anode), result->expr->query + sizeof("SELECT")); + initStringInfo(&new_query); + appendStringInfo(&new_query, "SELECT \"%s\" %s (%s)", + target, + rewrite_assign_operator(anode), + result->expr->query + strlen("SELECT ")); // Pointer arithmetic: skip over the string + // preceding the expression, prior to the rewrite result->expr->query = new_query.data; + + // Record how many chars are added prior to the expression + // "SELECT " : preceding chars before this reformatting the expression + // +1 : the opening bracket + posBracket = strcspn(new_query.data, "(") - strlen("SELECT ") + 1; } + // Each variable assignment becomes a fragment, for which rewriting may be required. We need to keep track of where + // the assignment is located (start-end of range) so that we can apply the rewrites correctly + recordSelectFragmentOffsets(ctx, posStart, posEnd, posBracket); + return (PLtsql_stmt *) result; } else if (ctx->CURSOR()) @@ -4665,7 +4743,7 @@ makeSetStatement(TSqlParser::Set_statementContext *ctx, tsqlBuilder &builder) PLtsql_stmt_execsql *stmt = (PLtsql_stmt_execsql *) makeSQL(ctx); stmt->is_set_tran_isolation = true; return (PLtsql_stmt *) stmt; - } + } else return makeSQL(ctx); } @@ -5313,10 +5391,11 @@ std::vector makeAnother(TSqlParser::Another_statementContext *ctx, tsqlBuilder &builder) { std::vector result; + std::map declare_local_expr; if (ctx->declare_statement()) { - std::vector decl_result = makeDeclareStmt(ctx->declare_statement()); + std::vector decl_result = makeDeclareStmt(ctx->declare_statement(), &declare_local_expr); result.insert(result.end(), decl_result.begin(), decl_result.end()); } else if (ctx->set_statement()) @@ -5338,8 +5417,21 @@ makeAnother(TSqlParser::Another_statementContext *ctx, tsqlBuilder &builder) // FIXME: handle remaining statement types - for (PLtsql_stmt *stmt : result) - attachPLtsql_fragment(ctx, stmt); + for (PLtsql_stmt *stmt : result) + { + // Associate each fragement with a tree node + if (declare_local_expr.find(stmt) != declare_local_expr.end()) + { + attachPLtsql_fragment(declare_local_expr.at(stmt), stmt); + } + else if (ctx->set_statement()) + { + attachPLtsql_fragment(ctx->set_statement(), stmt); + } + else { + attachPLtsql_fragment(ctx, stmt); + } + } return result; } @@ -6900,3 +6992,54 @@ getIDName(TerminalNode *dq, TerminalNode *sb, TerminalNode *id) return std::string(id->getSymbol()->getText()); } } + +// rewriteDoubleQuotedString() - change double-quoted string to single-quoted +// A double-quoted string must be changed to a single-quoted string +// since PG accepts only single quotes as string delimiters. This requires: +// - change the enclosing quotes to single quotes +// - escape any single quotes in the string by doubling them +// - unescape any double quotes +std::string rewriteDoubleQuotedString(const std::string strDoubleQuoted) +{ + std::string str = strDoubleQuoted; + + Assert(str.front() == '"'); + Assert(str.back() == '"'); + + if (str.find('\'') == std::string::npos) + { + // String contains no embedded single-quotes, so no further action needed + } + else + { + // String contains embedded single-quotes; these must be escaped by doubling them + for (size_t i = str.find("\'", 1); // start at pos 1: char 0 has the enclosing quote + i != std::string::npos; + i = str.find("\'", i + 2) ) + { + str.replace(i, 1, "''"); // Change single quote to 2 single-quotes + } + } + + // Now change the enclosing quotes, i.e. from "foo" to 'foo' + // Must do this after embedded single-quote handling above + str.front() = '\''; + str.back() = '\''; + + if (str.find('\"') == std::string::npos) + { + // String contains no embedded double-quotes, so no further action needed + } + else + { + // String contains embedded double-quotes; these must be un-escaped by removing one of the two + for (size_t i = str.find("\"\"", 1); // start at pos 1: char 0 has the enclosing quote + i != std::string::npos; + i = str.find("\"\"", i + 1) ) + { + str.replace(i, 2, "\""); // Remove one of the double quotes + } + } + + return str; +} diff --git a/dev-tools.sh b/dev-tools.sh index d1bcbf5d0f..0d4f2ff2e1 100755 --- a/dev-tools.sh +++ b/dev-tools.sh @@ -173,7 +173,7 @@ init_db() { init_pghint() { cd $1 if [ ! -d "./pg_hint_plan" ]; then - git clone --depth 1 --branch REL14_1_4_0 https://github.com/ossc-db/pg_hint_plan.git + git clone --depth 1 --branch REL15_1_5_1 https://github.com/ossc-db/pg_hint_plan.git fi cd pg_hint_plan export PATH=$2/postgres/bin:$PATH diff --git a/test/JDBC/expected/BABEL-2325.out b/test/JDBC/expected/BABEL-2325.out index bf0c2c1aa4..ea9f38ef34 100644 --- a/test/JDBC/expected/BABEL-2325.out +++ b/test/JDBC/expected/BABEL-2325.out @@ -27,12 +27,13 @@ string ~~END~~ --- should report error (double-quoted string literals cannot contain single-quotes while QUOTED_IDENTIFIER=OFF) +-- should return f'oo with QUOTED_IDENTIFIER=OFF SELECT "f'oo" GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: double-quoted string literals cannot contain single-quotes while QUOTED_IDENTIFIER=OFF)~~ +~~START~~ +varchar +f'oo +~~END~~ diff --git a/test/JDBC/expected/BABEL-3512.out b/test/JDBC/expected/BABEL-3512.out index 137f74e0e5..0089073436 100644 --- a/test/JDBC/expected/BABEL-3512.out +++ b/test/JDBC/expected/BABEL-3512.out @@ -285,6 +285,7 @@ WITH/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a1 SET babelfish_showplan_all ON GO +-- the purpose of babel_3512_t2_cte is to check the behavior for invalid hint EXEC babel_3512_proc_6 GO ~~START~~ @@ -295,8 +296,11 @@ Query Text: EXEC babel_3512_proc_6 Index Cond: (b1 = 1) Filter: (c1 = 1) Query Text: WITH/*+ indexscan(babel_3512_t2 index_babel_3512_t2_b1babel_351ed65eb34ef55dec01b20e7fff9c5ca06) */ babel_3512_t2_cte (a1, b2, c2) as (SELECT * FROM babel_3512_t2 WHERE b2 = 1) SELECT * FROM babel_3512_t2_cte WHERE c2 = 1 - -> Seq Scan on babel_3512_t2 - Filter: ((b2 = 1) AND (c2 = 1)) + -> Bitmap Heap Scan on babel_3512_t2 + Recheck Cond: (b2 = 1) + Filter: (c2 = 1) + -> Bitmap Index Scan on index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9 + Index Cond: (b2 = 1) ~~END~~ diff --git a/test/JDBC/expected/doublequoted_string-vu-verify.out b/test/JDBC/expected/doublequoted_string-vu-verify.out new file mode 100644 index 0000000000..abfafc886d --- /dev/null +++ b/test/JDBC/expected/doublequoted_string-vu-verify.out @@ -0,0 +1,1289 @@ +create procedure dubquote_p @p varchar(20) = "ab'cd" , @p2 varchar(20)='xyz' +as select @p +go +create procedure dubquote_p2 @p varchar(20) = "ab""cd" +as select @p +go + +set quoted_identifier off +go +select "abc" +go +~~START~~ +varchar +abc +~~END~~ + +exec dubquote_p +go +~~START~~ +varchar +ab'cd +~~END~~ + +exec dubquote_p2 +go +~~START~~ +varchar +ab"cd +~~END~~ + +exec dubquote_p "abc" +go +~~START~~ +varchar +abc +~~END~~ + +exec dubquote_p 'abc' +go +~~START~~ +varchar +abc +~~END~~ + +exec dubquote_p abc +go +~~START~~ +varchar +abc +~~END~~ + + +set quoted_identifier on +go +select "abc" +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "abc" does not exist)~~ + +exec dubquote_p +go +~~START~~ +varchar +ab'cd +~~END~~ + +exec dubquote_p2 +go +~~START~~ +varchar +ab"cd +~~END~~ + +exec dubquote_p "abc" +go +~~START~~ +varchar +abc +~~END~~ + +exec dubquote_p 'abc' +go +~~START~~ +varchar +abc +~~END~~ + +exec dubquote_p abc +go +~~START~~ +varchar +abc +~~END~~ + + +set quoted_identifier off +go +select "ab""cd" +go +~~START~~ +varchar +ab"cd +~~END~~ + +select "de'fg" +go +~~START~~ +varchar +de'fg +~~END~~ + +select 'ab"cd' +go +~~START~~ +varchar +ab"cd +~~END~~ + +select "ab'cd" +go +~~START~~ +varchar +ab'cd +~~END~~ + +select 'ab"cd' +go +~~START~~ +varchar +ab"cd +~~END~~ + +select 'ab"''"''"cd' +go +~~START~~ +varchar +ab"'"'"cd +~~END~~ + +select """" +go +~~START~~ +varchar +" +~~END~~ + +select '''' +go +~~START~~ +varchar +' +~~END~~ + +select '"' +go +~~START~~ +varchar +" +~~END~~ + +select '""' +go +~~START~~ +varchar +"" +~~END~~ + +select "'" +go +~~START~~ +varchar +' +~~END~~ + +select "''" +go +~~START~~ +varchar +'' +~~END~~ + +select """'""'""" +go +~~START~~ +varchar +"'"'" +~~END~~ + + +set quoted_identifier on +go +exec dubquote_p +go +~~START~~ +varchar +ab'cd +~~END~~ + +exec dubquote_p "xx'yy" +go +~~START~~ +varchar +xx'yy +~~END~~ + +exec dubquote_p 'xx"yy' +go +~~START~~ +varchar +xx"yy +~~END~~ + +exec dubquote_p """" +go +~~START~~ +varchar +" +~~END~~ + +exec dubquote_p '''' +go +~~START~~ +varchar +' +~~END~~ + +exec dubquote_p '"' +go +~~START~~ +varchar +" +~~END~~ + +exec dubquote_p '""' +go +~~START~~ +varchar +"" +~~END~~ + +exec dubquote_p "'" +go +~~START~~ +varchar +' +~~END~~ + +exec dubquote_p "''" +go +~~START~~ +varchar +'' +~~END~~ + +exec dubquote_p """'""'""" +go +~~START~~ +varchar +"'"'" +~~END~~ + + +-- same as above but with named notation +exec dubquote_p @p="xx'yy" , @p2='x"y' +go +~~START~~ +varchar +xx'yy +~~END~~ + +exec dubquote_p @p='xx"yy' , @p2="x""y" +go +~~START~~ +varchar +xx"yy +~~END~~ + +exec dubquote_p @p="""" , @p2="x'y" +go +~~START~~ +varchar +" +~~END~~ + +exec dubquote_p @p='''' , @p2="x''y" +go +~~START~~ +varchar +' +~~END~~ + +exec dubquote_p @p='"' , @p2="x''y" +go +~~START~~ +varchar +" +~~END~~ + +exec dubquote_p @p='""' , @p2="x''y" +go +~~START~~ +varchar +"" +~~END~~ + +exec dubquote_p @p="'" , @p2="x''y" +go +~~START~~ +varchar +' +~~END~~ + +exec dubquote_p @p="''" , @p2="x''y" +go +~~START~~ +varchar +'' +~~END~~ + +exec dubquote_p @p="""'""'""" , @p2="x''y" +go +~~START~~ +varchar +"'"'" +~~END~~ + + +-- using N'...' notation: +exec dubquote_p N'xx"yy' +go +~~START~~ +varchar +xx"yy +~~END~~ + +exec dubquote_p N'''' +go +~~START~~ +varchar +' +~~END~~ + +exec dubquote_p N'"' +go +~~START~~ +varchar +" +~~END~~ + +exec dubquote_p N'""' +go +~~START~~ +varchar +"" +~~END~~ + +exec dubquote_p @p=N'xx"yy' +go +~~START~~ +varchar +xx"yy +~~END~~ + +exec dubquote_p @p=N'''' +go +~~START~~ +varchar +' +~~END~~ + +exec dubquote_p @p=N'"' +go +~~START~~ +varchar +" +~~END~~ + +exec dubquote_p @p=N'""' +go +~~START~~ +varchar +"" +~~END~~ + + +-- functions +set quoted_identifier off +go +create function dubquote_f1(@p varchar(20) = "ab'cd") returns varchar(20) as begin return @p end +go +create function dubquote_f2(@p varchar(20) = "ab""cd") returns varchar(20) as begin return @p end +go +create function dubquote_f3(@p varchar(20) = abcd) returns varchar(20) as begin return @p end +go +declare @v varchar(20) +exec @v = dubquote_f1 +select @v +go +~~START~~ +varchar +ab'cd +~~END~~ + +declare @v varchar(20) +exec @v = dubquote_f2 +select @v +go +~~START~~ +varchar +ab"cd +~~END~~ + +declare @v varchar(20) +exec @v = dubquote_f3 +select @v +go +~~START~~ +varchar +abcd +~~END~~ + + +select dbo.dubquote_f1("ab'cd") +go +~~START~~ +varchar +ab'cd +~~END~~ + +select dbo.dubquote_f1('ab"cd') +go +~~START~~ +varchar +ab"cd +~~END~~ + +select dbo.dubquote_f1(N'ab"cd') +go +~~START~~ +varchar +ab"cd +~~END~~ + +select dbo.dubquote_f1("ab""cd") +go +~~START~~ +varchar +ab"cd +~~END~~ + + +set quoted_identifier on +go +select dbo.dubquote_f1("ab'cd") +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "ab'cd" does not exist)~~ + +select dbo.dubquote_f1('ab"cd') +go +~~START~~ +varchar +ab"cd +~~END~~ + +select dbo.dubquote_f1(N'ab"cd') +go +~~START~~ +varchar +ab"cd +~~END~~ + +select dbo.dubquote_f1("ab""cd") +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "ab"cd" does not exist)~~ + + +set quoted_identifier off +go +create procedure dubquote_p2a @p varchar(20) ="abc" as select @p +go +exec dubquote_p2a +go +~~START~~ +varchar +abc +~~END~~ + +create procedure dubquote_p3 @p varchar(20) ="'abc'" as select @p +go +exec dubquote_p3 +go +~~START~~ +varchar +'abc' +~~END~~ + +declare @v varchar(40) set @v = "It's almost ""weekend""!" select @v +go +~~START~~ +varchar +It's almost "weekend"! +~~END~~ + + +select 'abc' +go +~~START~~ +varchar +abc +~~END~~ + +select "abc" +go +~~START~~ +varchar +abc +~~END~~ + +select "a'b""c''''''''''d" +go +~~START~~ +varchar +a'b"c''''''''''d +~~END~~ + +select "a'b""c'd" +go +~~START~~ +varchar +a'b"c'd +~~END~~ + +select "'abc'",'xyz' +go +~~START~~ +varchar#!#varchar +'abc'#!#xyz +~~END~~ + + +declare @v varchar(20) = 'abc' select @v +go +~~START~~ +varchar +abc +~~END~~ + +declare @v varchar(20) = "abc" select @v +go +~~START~~ +varchar +abc +~~END~~ + +declare @v varchar(20) = "'a""bc'" select @v +go +~~START~~ +varchar +'a"bc' +~~END~~ + +declare @v varchar(20) select @v = "abc" select @v +go +~~START~~ +varchar +abc +~~END~~ + +declare @v varchar(20) = 'x' select @v += "abc" select @v +go +~~START~~ +varchar +xabc +~~END~~ + +declare @v varchar(20) select @v = "'a""bc'" select @v +go +~~START~~ +varchar +'a"bc' +~~END~~ + +declare @v varchar(20) = 'x' select @v += "'a""bc'" select @v +go +~~START~~ +varchar +x'a"bc' +~~END~~ + +declare @v varchar(20) set @v = "'a""bc'" select @v +go +~~START~~ +varchar +'a"bc' +~~END~~ + +declare @v varchar(20) = 'x' set @v += "'a""bc'" select @v +go +~~START~~ +varchar +x'a"bc' +~~END~~ + + +declare @v varchar(20) ="abc" , @v2 varchar(10) = 'xyz' select @v +go +~~START~~ +varchar +abc +~~END~~ + +declare @v varchar(20), @v2 varchar(20) select @v="a""b''c'd", @v2="x""y''z" select @v, @v2 +go +~~START~~ +varchar#!#varchar +a"b''c'd#!#x"y''z +~~END~~ + +declare @v varchar(20) = "ABC", @v2 varchar(20)="XYZ" select @v+="a""b''c'd", @v2+="x""y''z" select @v, @v2 +go +~~START~~ +varchar#!#varchar +ABCa"b''c'd#!#XYZx"y''z +~~END~~ + +declare @v varchar(20) = "ABC", @v2 varchar(20)="XYZ" set @v+="a""b''c'd" set @v2+="x""y''z" select @v, @v2 +go +~~START~~ +varchar#!#varchar +ABCa"b''c'd#!#XYZx"y''z +~~END~~ + +declare @v varchar(20) ="a""bc" , @v2 varchar(10) = 'x''z' select @v, @v2 +go +~~START~~ +varchar#!#varchar +a"bc#!#x'z +~~END~~ + +declare @v varchar(20) ="a""bc" , @v2 varchar(10) = 'x''z' , @v3 varchar(10) = "x""y'z'z" select @v, @v2, @v3 +go +~~START~~ +varchar#!#varchar#!#varchar +a"bc#!#x'z#!#x"y'z'z +~~END~~ + + +-- bracketed identifiers containing double-quoted strings should not be affected by double-quoted string replacement +-- this SELECT should return 0 rows and no error +create table dubquote_t1([x"a'b"y] int, c varchar(20)) +go +select [x"a'b"y] from dubquote_t1 where c = "a'b" +go +~~START~~ +int +~~END~~ + + +set quoted_identifier off +go +-- the JDBC test cases do not capture PRINT output, but including them here for when it will +print "abc" +go +print "'abc'" +go +print "a""b'c" +go +print "a""b'c," + session_user + ",d""e'f," + system_user +go + /*test*/ print "abc" +go + /*hello*/ print /*hello*/ "abc" +go +print /*hello*/ "a""b'c," + /*hello*/ +session_user + /*hello*/ +",d""e'f," + /*hello*/ system_user +go +RAISERROR("Message from RAISERROR", 16,1) +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Message from RAISERROR)~~ + +RAISERROR("'Message from RAISERROR'", 16,1) +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: 'Message from RAISERROR')~~ + +RAISERROR("""Message from ""'RAISERROR'""", 16,1) +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: "Message from "'RAISERROR'")~~ + + /*test*/RAISERROR( /*hello*/"Message from 'RAISERROR'", 16,1) +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Message from 'RAISERROR')~~ + + +-- RAISERROR arguments are not yet rewritten. this should raise an error +RAISERROR ('%s %s', 10, 1, 'abc', "def"); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "def" does not exist)~~ + + + +declare @v varchar(20) = "a""b'c" +if @v = 'a"b''c' select 'correct' +else select 'wrong' +go +~~START~~ +varchar +correct +~~END~~ + + +declare @v varchar(20) = "a""b'c" +while @v = 'a"b''c' +begin +select 'correct' +break +end +go +~~START~~ +varchar +correct +~~END~~ + + +declare @v varchar(20) = system_user +if @v = system_user select 'correct' +else select 'wrong' +go +~~START~~ +varchar +correct +~~END~~ + + +declare @v varchar(20) = system_user +while @v = system_user +begin +select 'correct' +break +end +go +~~START~~ +varchar +correct +~~END~~ + + +set quoted_identifier on +go +print "abc" +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "abc" does not exist)~~ + +RAISERROR("Message from RAISERROR", 16,1) +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near '"Message from RAISERROR"' at line 1 and character position 10)~~ + + +set quoted_identifier off +go +create procedure dubquote_p4 @p varchar(20) ="a'bc" as select @p,@p +go +exec dubquote_p4 +go +~~START~~ +varchar#!#varchar +a'bc#!#a'bc +~~END~~ + +exec dubquote_p4 "abc" +go +~~START~~ +varchar#!#varchar +abc#!#abc +~~END~~ + +exec dubquote_p4 "ab""cd" +go +~~START~~ +varchar#!#varchar +ab"cd#!#ab"cd +~~END~~ + +exec dubquote_p4 "ab'cd" +go +~~START~~ +varchar#!#varchar +ab'cd#!#ab'cd +~~END~~ + +select "ab'cd" +go +~~START~~ +varchar +ab'cd +~~END~~ + +create function dubquote_f4 (@p varchar(20) = "'abc'") returns varchar(50) as begin return ((("function's return" +( " string value:" ))) +"'" + @p + "'") end +go +select dbo.dubquote_f4("x") +go +~~START~~ +varchar +function's return string value:'x' +~~END~~ + + +create function dubquote_f5 () returns varchar(50) as begin return "a""b'c" end +go +select dbo.dubquote_f5() +go +~~START~~ +varchar +a"b'c +~~END~~ + + +create function dubquote_f6 () returns varchar(50) as begin return "a""b'c," + session_user + ",d""e'f," + system_user end +go +select dbo.dubquote_f6() +go +~~START~~ +varchar +a"b'c,dbo,d"e'f,jdbc_user +~~END~~ + + +CREATE function dubquote_f7() returns varchar(30) as begin return system_user end +go +select select dbo.dubquote_f7(), system_user +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near 'select' at line 1 and character position 7)~~ + + +create procedure dubquote_p5 @p varchar(10) as select @p +go +exec dubquote_p5 'xyz' exec dubquote_p5 abc +go +~~START~~ +varchar +xyz +~~END~~ + +~~START~~ +varchar +abc +~~END~~ + +exec dubquote_p5 abcd +go +~~START~~ +varchar +abcd +~~END~~ + +exec dubquote_p5 [abcd] +go +~~START~~ +varchar +abcd +~~END~~ + +exec dubquote_p5 @p=abcde +go +~~START~~ +varchar +abcde +~~END~~ + +declare @v varchar(20) exec dubquote_p5 @v +go +~~START~~ +varchar + +~~END~~ + +declare @v varchar(20) = 'efg' exec dubquote_p5 @v +go +~~START~~ +varchar +efg +~~END~~ + +declare @v varchar(20) exec dubquote_p5 @p=@v +go +~~START~~ +varchar + +~~END~~ + +declare @v varchar(20) = 'hij' exec dubquote_p5 @p=@v +go +~~START~~ +varchar +hij +~~END~~ + + +declare @v varchar(20) = session_user select @v, session_user +go +~~START~~ +varchar#!#nvarchar +dbo#!#dbo +~~END~~ + +declare @v varchar(20) = 'abc' + session_user select @v, session_user +go +~~START~~ +varchar#!#nvarchar +abcdbo#!#dbo +~~END~~ + +declare @v varchar(20) = "abc" + session_user select @v, session_user +go +~~START~~ +varchar#!#nvarchar +abcdbo#!#dbo +~~END~~ + +declare @v varchar(20) = "ab""c'd" + session_user select @v, session_user +go +~~START~~ +varchar#!#nvarchar +ab"c'ddbo#!#dbo +~~END~~ + + +declare @v varchar(20) = system_user select @v, system_user +go +~~START~~ +varchar#!#nvarchar +jdbc_user#!#jdbc_user +~~END~~ + +declare @v varchar(20) = 'abc' + system_user select @v, system_user +go +~~START~~ +varchar#!#nvarchar +abcjdbc_user#!#jdbc_user +~~END~~ + +declare @v varchar(20) = "abc" + system_user select @v, system_user +go +~~START~~ +varchar#!#nvarchar +abcjdbc_user#!#jdbc_user +~~END~~ + +declare @v varchar(20) = "ab""c'd" + system_user select @v, system_user +go +~~START~~ +varchar#!#nvarchar +ab"c'djdbc_user#!#jdbc_user +~~END~~ + +declare @v varchar(20) = '' set @v = system_user select @v, system_user +go +~~START~~ +varchar#!#nvarchar +jdbc_user#!#jdbc_user +~~END~~ + +declare @v varchar(20) = '' set @v = 'abc' + system_user select @v, system_user +go +~~START~~ +varchar#!#nvarchar +abcjdbc_user#!#jdbc_user +~~END~~ + +declare @v varchar(20) = '' set @v = "abc" + system_user select @v, system_user +go +~~START~~ +varchar#!#nvarchar +abcjdbc_user#!#jdbc_user +~~END~~ + +declare @v varchar(20) = '' set @v = "ab""c'd" + system_user select @v, system_user +go +~~START~~ +varchar#!#nvarchar +ab"c'djdbc_user#!#jdbc_user +~~END~~ + +declare @v varchar(20) = '' set @v = "ab""c'd" + system_user select @v, system_user +go +~~START~~ +varchar#!#nvarchar +ab"c'djdbc_user#!#jdbc_user +~~END~~ + +declare @v varchar(20) = 'ab,' set @v += system_user select @v, system_user +go +~~START~~ +varchar#!#nvarchar +ab,jdbc_user#!#jdbc_user +~~END~~ + +declare @myvar varchar(20) = '' set @myvar += system_user select @myvar, system_user +go +~~START~~ +varchar#!#nvarchar +jdbc_user#!#jdbc_user +~~END~~ + + +/*hello*/declare @myvar varchar(50) = '' /*hello*/set /*hello*/@myvar/*hello*/ += +/*hello*/system_user/*hello*/ + +/*hello*/",a""b'c," + /*hello*/system_user +select @myvar, system_user +go +~~START~~ +varchar#!#nvarchar +jdbc_user,a"b'c,jdbc_user#!#jdbc_user +~~END~~ + +declare @v varchar(50) = system_user+"," set @v += "a""b'c," + system_user + ",a""b'c," + system_user select @v, system_user +go +~~START~~ +varchar#!#nvarchar +jdbc_user,a"b'c,jdbc_user,a"b'c,jdbc_user#!#jdbc_user +~~END~~ + + +-- all in one batch: +declare @v varchar(20) = session_user select @v +declare @v1 varchar(20) = 'abc' + session_user select @v1 +declare @v2 varchar(20) = "ab""c'd" + session_user select @v2 +declare @v3 varchar(20) ="a""bc" , @v4 varchar(20) = 'x''z' select @v3,@v4 +declare @v5 varchar(20) ="a""bc" , @v6 varchar(20) = 'x''z' , @v7 varchar(20) = "x""y'z'z" select @v5, @v6, @v7 +go +~~START~~ +varchar +dbo +~~END~~ + +~~START~~ +varchar +abcdbo +~~END~~ + +~~START~~ +varchar +ab"c'ddbo +~~END~~ + +~~START~~ +varchar#!#varchar +a"bc#!#x'z +~~END~~ + +~~START~~ +varchar#!#varchar#!#varchar +a"bc#!#x'z#!#x"y'z'z +~~END~~ + + +declare @v varchar(20) = session_user, @v2 varchar(20)= system_user select @v, @v2, session_user, system_user +go +~~START~~ +varchar#!#varchar#!#nvarchar#!#nvarchar +dbo#!#jdbc_user#!#dbo#!#jdbc_user +~~END~~ + +declare @v varchar(20) = 'abcd' + session_user, @v2 varchar(20) = 'xy' + session_user select @v, @v2, session_user +go +~~START~~ +varchar#!#varchar#!#nvarchar +abcddbo#!#xydbo#!#dbo +~~END~~ + +declare @v varchar(20) = 'abcd' + upper('x'), @v2 varchar(20) = 'xy' + upper('y') select @v, @v2 +go +~~START~~ +varchar#!#varchar +abcdX#!#xyY +~~END~~ + +declare @v varchar(20) = session_user, @v2 varchar(20)= system_user select @v,@v2,session_user, system_user +go +~~START~~ +varchar#!#varchar#!#nvarchar#!#nvarchar +dbo#!#jdbc_user#!#dbo#!#jdbc_user +~~END~~ + +declare @v varchar(20) = "x'y" + session_user, @v2 varchar(20)= "a'b" + system_user select @v,@v2,session_user, system_user +go +~~START~~ +varchar#!#varchar#!#nvarchar#!#nvarchar +x'ydbo#!#a'bjdbc_user#!#dbo#!#jdbc_user +~~END~~ + +declare @v varchar(20) = "x'y" + session_user, @v2 varchar(20)= "a'b" + system_user + "x''""" select @v,@v2,session_user, system_user +go +~~START~~ +varchar#!#varchar#!#nvarchar#!#nvarchar +x'ydbo#!#a'bjdbc_userx''"#!#dbo#!#jdbc_user +~~END~~ + +declare @v varchar(20) = session_user select @v +go +~~START~~ +varchar +dbo +~~END~~ + + +create sequence dubquote_myseq +go +create sequence dubquote_myseq2 +go +create sequence dubquote_myseq3 +go +create sequence dubquote_myseq4 +go +declare +@v varchar(20) = '123' + next value for dubquote_myseq, +@v2 varchar(20) = next value for dubquote_myseq2, +@v3 varchar(20) = next value for dubquote_myseq3 + "000", +@v4 varchar(20) = "123" + next value for dubquote_myseq4 + "000" +select @v, @v2, @v3, @v4 +go +~~START~~ +varchar#!#varchar#!#varchar#!#varchar +124#!#1#!#1#!#124 +~~END~~ + +declare @v int = next value for dubquote_myseq select @v +go +~~START~~ +int +2 +~~END~~ + +declare @v int = next value for dubquote_myseq select @v +go +~~START~~ +int +3 +~~END~~ + +declare @v int = len("a'bc") + next value for dubquote_myseq + len(system_user) select @v +go +~~START~~ +int +17 +~~END~~ + +declare @v int = 0 set @v = next value for dubquote_myseq select @v +go +~~START~~ +int +5 +~~END~~ + +declare @v int = 0 set @v += len("a'bc") + next value for dubquote_myseq + len(system_user) select @v +go +~~START~~ +int +19 +~~END~~ + +declare @v int = 0 set @v -= len("a'bc") + next value for dubquote_myseq + len(system_user) select @v +go +~~START~~ +int +-20 +~~END~~ + +declare @v int = 1 set @v *= len("a'bc") + next value for dubquote_myseq + len(system_user) select @v +go +~~START~~ +int +21 +~~END~~ + +declare @v int = 1 set @v /= len("a'bc") + next value for dubquote_myseq + len(system_user) select @v +go +~~START~~ +int +0 +~~END~~ + + + +set quoted_identifier on +go +create procedure dubquote_p6 @p varchar(20) ="abc" as select @p +go +exec dubquote_p6 +go +~~START~~ +varchar +abc +~~END~~ + +create procedure dubquote_p7 @p varchar(20) ="'abc'" as select @p +go +exec dubquote_p7 +go +~~START~~ +varchar +'abc' +~~END~~ + +declare @v varchar(20) = 'abc' select @v +go +~~START~~ +varchar +abc +~~END~~ + + +-- negative tests +declare @v varchar(20) = "abc" select @v +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "abc" does not exist)~~ + +declare @v varchar(20) = "'abc'" select @v +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "'abc'" does not exist)~~ + + + +--cleanup +drop procedure dubquote_p +go +drop procedure dubquote_p2 +go +drop function dubquote_f1 +go +drop function dubquote_f2 +go +drop function dubquote_f3 +go +drop procedure dubquote_p2a +go +drop procedure dubquote_p3 +go +drop procedure dubquote_p4 +go +drop function dubquote_f4 +go +drop function dubquote_f5 +go +drop function dubquote_f6 +go +drop function dubquote_f7 +go +drop procedure dubquote_p5 +go +drop sequence dubquote_myseq +go +drop sequence dubquote_myseq2 +go +drop sequence dubquote_myseq3 +go +drop sequence dubquote_myseq4 +go +drop procedure dubquote_p6 +go +drop procedure dubquote_p7 +go +drop table dubquote_t1 +go diff --git a/test/JDBC/expected/sys_asymmetric_keys-vu-cleanup.out b/test/JDBC/expected/sys_asymmetric_keys-vu-cleanup.out new file mode 100644 index 0000000000..3a7726a947 --- /dev/null +++ b/test/JDBC/expected/sys_asymmetric_keys-vu-cleanup.out @@ -0,0 +1,11 @@ +USE master +GO + +DROP VIEW sys_asymmetric_keys_vu_prepare_view +GO + +DROP PROC sys_asymmetric_keys_vu_prepare_proc +GO + +DROP FUNCTION sys_asymmetric_keys_vu_prepare_func +GO diff --git a/test/JDBC/expected/sys_asymmetric_keys-vu-prepare.out b/test/JDBC/expected/sys_asymmetric_keys-vu-prepare.out new file mode 100644 index 0000000000..b344c237cd --- /dev/null +++ b/test/JDBC/expected/sys_asymmetric_keys-vu-prepare.out @@ -0,0 +1,18 @@ +USE master +GO + +CREATE VIEW sys_asymmetric_keys_vu_prepare_view AS +SELECT * FROM sys.asymmetric_keys +GO + +CREATE PROC sys_asymmetric_keys_vu_prepare_proc AS +SELECT * FROM sys.asymmetric_keys +GO + +CREATE FUNCTION sys_asymmetric_keys_vu_prepare_func() +RETURNS INT +AS +BEGIN + RETURN (SELECT COUNT(*) FROM sys.asymmetric_keys WHERE key_length= 0) +END +GO diff --git a/test/JDBC/expected/sys_asymmetric_keys-vu-verify.out b/test/JDBC/expected/sys_asymmetric_keys-vu-verify.out new file mode 100644 index 0000000000..fe7e470272 --- /dev/null +++ b/test/JDBC/expected/sys_asymmetric_keys-vu-verify.out @@ -0,0 +1,31 @@ +USE master +GO + +SELECT * FROM sys.asymmetric_keys +GO +~~START~~ +varchar#!#int#!#int#!#char#!#nvarchar#!#varbinary#!#char#!#nvarchar#!#int#!#varbinary#!#nvarchar#!#varbinary#!#nvarchar#!#nvarchar#!#uniqueidentifier#!#sql_variant +~~END~~ + + +SELECT * FROM sys_asymmetric_keys_vu_prepare_view +GO +~~START~~ +varchar#!#int#!#int#!#char#!#nvarchar#!#varbinary#!#char#!#nvarchar#!#int#!#varbinary#!#nvarchar#!#varbinary#!#nvarchar#!#nvarchar#!#uniqueidentifier#!#sql_variant +~~END~~ + + +EXEC sys_asymmetric_keys_vu_prepare_proc +GO +~~START~~ +varchar#!#int#!#int#!#char#!#nvarchar#!#varbinary#!#char#!#nvarchar#!#int#!#varbinary#!#nvarchar#!#varbinary#!#nvarchar#!#nvarchar#!#uniqueidentifier#!#sql_variant +~~END~~ + + +SELECT sys_asymmetric_keys_vu_prepare_func() +GO +~~START~~ +int +0 +~~END~~ + diff --git a/test/JDBC/expected/sys_certificates-vu-cleanup.out b/test/JDBC/expected/sys_certificates-vu-cleanup.out new file mode 100644 index 0000000000..e3fc7bb825 --- /dev/null +++ b/test/JDBC/expected/sys_certificates-vu-cleanup.out @@ -0,0 +1,11 @@ +USE master +GO + +DROP VIEW sys_certificates_vu_prepare_view +GO + +DROP PROC sys_certificates_vu_prepare_proc +GO + +DROP FUNCTION sys_certificates_vu_prepare_func +GO diff --git a/test/JDBC/expected/sys_certificates-vu-prepare.out b/test/JDBC/expected/sys_certificates-vu-prepare.out new file mode 100644 index 0000000000..9bdf0789f0 --- /dev/null +++ b/test/JDBC/expected/sys_certificates-vu-prepare.out @@ -0,0 +1,18 @@ +USE master +GO + +CREATE VIEW sys_certificates_vu_prepare_view AS +SELECT * FROM sys.certificates +GO + +CREATE PROC sys_certificates_vu_prepare_proc AS +SELECT * FROM sys.certificates +GO + +CREATE FUNCTION sys_certificates_vu_prepare_func() +RETURNS INT +AS +BEGIN + RETURN (SELECT COUNT(*) FROM sys.certificates WHERE key_length = 0) +END +GO diff --git a/test/JDBC/expected/sys_certificates-vu-verify.out b/test/JDBC/expected/sys_certificates-vu-verify.out new file mode 100644 index 0000000000..3327a085be --- /dev/null +++ b/test/JDBC/expected/sys_certificates-vu-verify.out @@ -0,0 +1,31 @@ +USE master +GO + +SELECT * FROM sys.certificates +GO +~~START~~ +varchar#!#int#!#int#!#char#!#nvarchar#!#bit#!#nvarchar#!#nvarchar#!#varbinary#!#nvarchar#!#nvarchar#!#datetime#!#datetime#!#varbinary#!#nvarchar#!#datetime#!#int +~~END~~ + + +SELECT * FROM sys_certificates_vu_prepare_view +GO +~~START~~ +varchar#!#int#!#int#!#char#!#nvarchar#!#bit#!#nvarchar#!#nvarchar#!#varbinary#!#nvarchar#!#nvarchar#!#datetime#!#datetime#!#varbinary#!#nvarchar#!#datetime#!#int +~~END~~ + + +EXEC sys_certificates_vu_prepare_proc +GO +~~START~~ +varchar#!#int#!#int#!#char#!#nvarchar#!#bit#!#nvarchar#!#nvarchar#!#varbinary#!#nvarchar#!#nvarchar#!#datetime#!#datetime#!#varbinary#!#nvarchar#!#datetime#!#int +~~END~~ + + +SELECT sys_certificates_vu_prepare_func() +GO +~~START~~ +int +0 +~~END~~ + diff --git a/test/JDBC/expected/sys_database_permissions-vu-cleanup.out b/test/JDBC/expected/sys_database_permissions-vu-cleanup.out new file mode 100644 index 0000000000..fcb93d412c --- /dev/null +++ b/test/JDBC/expected/sys_database_permissions-vu-cleanup.out @@ -0,0 +1,11 @@ +USE master +GO + +DROP VIEW sys_database_permissions_vu_prepare_view +GO + +DROP PROC sys_database_permissions_vu_prepare_proc +GO + +DROP FUNCTION sys_database_permissions_vu_prepare_func +GO diff --git a/test/JDBC/expected/sys_database_permissions-vu-prepare.out b/test/JDBC/expected/sys_database_permissions-vu-prepare.out new file mode 100644 index 0000000000..0276a4581d --- /dev/null +++ b/test/JDBC/expected/sys_database_permissions-vu-prepare.out @@ -0,0 +1,18 @@ +USE master +GO + +CREATE VIEW sys_database_permissions_vu_prepare_view AS +SELECT * FROM sys.database_permissions +GO + +CREATE PROC sys_database_permissions_vu_prepare_proc AS +SELECT * FROM sys.database_permissions +GO + +CREATE FUNCTION sys_database_permissions_vu_prepare_func() +RETURNS INT +AS +BEGIN + RETURN (SELECT COUNT(*) FROM sys.database_permissions WHERE state='A') +END +GO diff --git a/test/JDBC/expected/sys_database_permissions-vu-verify.out b/test/JDBC/expected/sys_database_permissions-vu-verify.out new file mode 100644 index 0000000000..83fbd0207d --- /dev/null +++ b/test/JDBC/expected/sys_database_permissions-vu-verify.out @@ -0,0 +1,31 @@ +USE master +GO + +SELECT * FROM sys.database_permissions +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#int#!#int#!#char#!#nvarchar#!#char#!#nvarchar +~~END~~ + + +SELECT * FROM sys_database_permissions_vu_prepare_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#int#!#int#!#char#!#nvarchar#!#char#!#nvarchar +~~END~~ + + +EXEC sys_database_permissions_vu_prepare_proc +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#int#!#int#!#char#!#nvarchar#!#char#!#nvarchar +~~END~~ + + +SELECT sys_database_permissions_vu_prepare_func() +GO +~~START~~ +int +0 +~~END~~ + diff --git a/test/JDBC/input/BABEL-2325.sql b/test/JDBC/input/BABEL-2325.sql index 44799249d0..b6143d1a85 100644 --- a/test/JDBC/input/BABEL-2325.sql +++ b/test/JDBC/input/BABEL-2325.sql @@ -13,7 +13,7 @@ GO SELECT "string" GO --- should report error (double-quoted string literals cannot contain single-quotes while QUOTED_IDENTIFIER=OFF) +-- should return f'oo with QUOTED_IDENTIFIER=OFF SELECT "f'oo" GO diff --git a/test/JDBC/input/doublequoted_string-vu-verify.sql b/test/JDBC/input/doublequoted_string-vu-verify.sql new file mode 100644 index 0000000000..6c36844545 --- /dev/null +++ b/test/JDBC/input/doublequoted_string-vu-verify.sql @@ -0,0 +1,508 @@ +create procedure dubquote_p @p varchar(20) = "ab'cd" , @p2 varchar(20)='xyz' +as select @p +go +create procedure dubquote_p2 @p varchar(20) = "ab""cd" +as select @p +go + +set quoted_identifier off +go +select "abc" +go +exec dubquote_p +go +exec dubquote_p2 +go +exec dubquote_p "abc" +go +exec dubquote_p 'abc' +go +exec dubquote_p abc +go + +set quoted_identifier on +go +select "abc" +go +exec dubquote_p +go +exec dubquote_p2 +go +exec dubquote_p "abc" +go +exec dubquote_p 'abc' +go +exec dubquote_p abc +go + +set quoted_identifier off +go +select "ab""cd" +go +select "de'fg" +go +select 'ab"cd' +go +select "ab'cd" +go +select 'ab"cd' +go +select 'ab"''"''"cd' +go +select """" +go +select '''' +go +select '"' +go +select '""' +go +select "'" +go +select "''" +go +select """'""'""" +go + +set quoted_identifier on +go +exec dubquote_p +go +exec dubquote_p "xx'yy" +go +exec dubquote_p 'xx"yy' +go +exec dubquote_p """" +go +exec dubquote_p '''' +go +exec dubquote_p '"' +go +exec dubquote_p '""' +go +exec dubquote_p "'" +go +exec dubquote_p "''" +go +exec dubquote_p """'""'""" +go + +-- same as above but with named notation +exec dubquote_p @p="xx'yy" , @p2='x"y' +go +exec dubquote_p @p='xx"yy' , @p2="x""y" +go +exec dubquote_p @p="""" , @p2="x'y" +go +exec dubquote_p @p='''' , @p2="x''y" +go +exec dubquote_p @p='"' , @p2="x''y" +go +exec dubquote_p @p='""' , @p2="x''y" +go +exec dubquote_p @p="'" , @p2="x''y" +go +exec dubquote_p @p="''" , @p2="x''y" +go +exec dubquote_p @p="""'""'""" , @p2="x''y" +go + +-- using N'...' notation: +exec dubquote_p N'xx"yy' +go +exec dubquote_p N'''' +go +exec dubquote_p N'"' +go +exec dubquote_p N'""' +go +exec dubquote_p @p=N'xx"yy' +go +exec dubquote_p @p=N'''' +go +exec dubquote_p @p=N'"' +go +exec dubquote_p @p=N'""' +go + +-- functions +set quoted_identifier off +go +create function dubquote_f1(@p varchar(20) = "ab'cd") returns varchar(20) as begin return @p end +go +create function dubquote_f2(@p varchar(20) = "ab""cd") returns varchar(20) as begin return @p end +go +create function dubquote_f3(@p varchar(20) = abcd) returns varchar(20) as begin return @p end +go +declare @v varchar(20) +exec @v = dubquote_f1 +select @v +go +declare @v varchar(20) +exec @v = dubquote_f2 +select @v +go +declare @v varchar(20) +exec @v = dubquote_f3 +select @v +go + +select dbo.dubquote_f1("ab'cd") +go +select dbo.dubquote_f1('ab"cd') +go +select dbo.dubquote_f1(N'ab"cd') +go +select dbo.dubquote_f1("ab""cd") +go + +set quoted_identifier on +go +select dbo.dubquote_f1("ab'cd") +go +select dbo.dubquote_f1('ab"cd') +go +select dbo.dubquote_f1(N'ab"cd') +go +select dbo.dubquote_f1("ab""cd") +go + +set quoted_identifier off +go +create procedure dubquote_p2a @p varchar(20) ="abc" as select @p +go +exec dubquote_p2a +go +create procedure dubquote_p3 @p varchar(20) ="'abc'" as select @p +go +exec dubquote_p3 +go +declare @v varchar(40) set @v = "It's almost ""weekend""!" select @v +go + +select 'abc' +go +select "abc" +go +select "a'b""c''''''''''d" +go +select "a'b""c'd" +go +select "'abc'",'xyz' +go + +declare @v varchar(20) = 'abc' select @v +go +declare @v varchar(20) = "abc" select @v +go +declare @v varchar(20) = "'a""bc'" select @v +go +declare @v varchar(20) select @v = "abc" select @v +go +declare @v varchar(20) = 'x' select @v += "abc" select @v +go +declare @v varchar(20) select @v = "'a""bc'" select @v +go +declare @v varchar(20) = 'x' select @v += "'a""bc'" select @v +go +declare @v varchar(20) set @v = "'a""bc'" select @v +go +declare @v varchar(20) = 'x' set @v += "'a""bc'" select @v +go + +declare @v varchar(20) ="abc" , @v2 varchar(10) = 'xyz' select @v +go +declare @v varchar(20), @v2 varchar(20) select @v="a""b''c'd", @v2="x""y''z" select @v, @v2 +go +declare @v varchar(20) = "ABC", @v2 varchar(20)="XYZ" select @v+="a""b''c'd", @v2+="x""y''z" select @v, @v2 +go +declare @v varchar(20) = "ABC", @v2 varchar(20)="XYZ" set @v+="a""b''c'd" set @v2+="x""y''z" select @v, @v2 +go +declare @v varchar(20) ="a""bc" , @v2 varchar(10) = 'x''z' select @v, @v2 +go +declare @v varchar(20) ="a""bc" , @v2 varchar(10) = 'x''z' , @v3 varchar(10) = "x""y'z'z" select @v, @v2, @v3 +go + +-- bracketed identifiers containing double-quoted strings should not be affected by double-quoted string replacement +-- this SELECT should return 0 rows and no error +create table dubquote_t1([x"a'b"y] int, c varchar(20)) +go +select [x"a'b"y] from dubquote_t1 where c = "a'b" +go + +set quoted_identifier off +go +-- the JDBC test cases do not capture PRINT output, but including them here for when it will +print "abc" +go +print "'abc'" +go +print "a""b'c" +go +print "a""b'c," + session_user + ",d""e'f," + system_user +go + /*test*/ print "abc" +go + /*hello*/ print /*hello*/ "abc" +go +print /*hello*/ "a""b'c," + /*hello*/ +session_user + /*hello*/ +",d""e'f," + /*hello*/ system_user +go +RAISERROR("Message from RAISERROR", 16,1) +go +RAISERROR("'Message from RAISERROR'", 16,1) +go +RAISERROR("""Message from ""'RAISERROR'""", 16,1) +go + /*test*/RAISERROR( /*hello*/"Message from 'RAISERROR'", 16,1) +go + +-- RAISERROR arguments are not yet rewritten. this should raise an error +RAISERROR ('%s %s', 10, 1, 'abc', "def"); +go + + +declare @v varchar(20) = "a""b'c" +if @v = 'a"b''c' select 'correct' +else select 'wrong' +go + +declare @v varchar(20) = "a""b'c" +while @v = 'a"b''c' +begin +select 'correct' +break +end +go + +declare @v varchar(20) = system_user +if @v = system_user select 'correct' +else select 'wrong' +go + +declare @v varchar(20) = system_user +while @v = system_user +begin +select 'correct' +break +end +go + +set quoted_identifier on +go +print "abc" +go +RAISERROR("Message from RAISERROR", 16,1) +go + +set quoted_identifier off +go +create procedure dubquote_p4 @p varchar(20) ="a'bc" as select @p,@p +go +exec dubquote_p4 +go +exec dubquote_p4 "abc" +go +exec dubquote_p4 "ab""cd" +go +exec dubquote_p4 "ab'cd" +go +select "ab'cd" +go +create function dubquote_f4 (@p varchar(20) = "'abc'") returns varchar(50) as begin return ((("function's return" +( " string value:" ))) +"'" + @p + "'") end +go +select dbo.dubquote_f4("x") +go + +create function dubquote_f5 () returns varchar(50) as begin return "a""b'c" end +go +select dbo.dubquote_f5() +go + +create function dubquote_f6 () returns varchar(50) as begin return "a""b'c," + session_user + ",d""e'f," + system_user end +go +select dbo.dubquote_f6() +go + +CREATE function dubquote_f7() returns varchar(30) as begin return system_user end +go +select select dbo.dubquote_f7(), system_user +go + +create procedure dubquote_p5 @p varchar(10) as select @p +go +exec dubquote_p5 'xyz' exec dubquote_p5 abc +go +exec dubquote_p5 abcd +go +exec dubquote_p5 [abcd] +go +exec dubquote_p5 @p=abcde +go +declare @v varchar(20) exec dubquote_p5 @v +go +declare @v varchar(20) = 'efg' exec dubquote_p5 @v +go +declare @v varchar(20) exec dubquote_p5 @p=@v +go +declare @v varchar(20) = 'hij' exec dubquote_p5 @p=@v +go + +declare @v varchar(20) = session_user select @v, session_user +go +declare @v varchar(20) = 'abc' + session_user select @v, session_user +go +declare @v varchar(20) = "abc" + session_user select @v, session_user +go +declare @v varchar(20) = "ab""c'd" + session_user select @v, session_user +go + +declare @v varchar(20) = system_user select @v, system_user +go +declare @v varchar(20) = 'abc' + system_user select @v, system_user +go +declare @v varchar(20) = "abc" + system_user select @v, system_user +go +declare @v varchar(20) = "ab""c'd" + system_user select @v, system_user +go +declare @v varchar(20) = '' set @v = system_user select @v, system_user +go +declare @v varchar(20) = '' set @v = 'abc' + system_user select @v, system_user +go +declare @v varchar(20) = '' set @v = "abc" + system_user select @v, system_user +go +declare @v varchar(20) = '' set @v = "ab""c'd" + system_user select @v, system_user +go +declare @v varchar(20) = '' set @v = "ab""c'd" + system_user select @v, system_user +go +declare @v varchar(20) = 'ab,' set @v += system_user select @v, system_user +go +declare @myvar varchar(20) = '' set @myvar += system_user select @myvar, system_user +go +/*hello*/declare @myvar varchar(50) = '' /*hello*/set /*hello*/@myvar/*hello*/ += +/*hello*/system_user/*hello*/ + + +/*hello*/",a""b'c," + /*hello*/system_user +select @myvar, system_user +go +declare @v varchar(50) = system_user+"," set @v += "a""b'c," + system_user + ",a""b'c," + system_user select @v, system_user +go + +-- all in one batch: +declare @v varchar(20) = session_user select @v +declare @v1 varchar(20) = 'abc' + session_user select @v1 +declare @v2 varchar(20) = "ab""c'd" + session_user select @v2 +declare @v3 varchar(20) ="a""bc" , @v4 varchar(20) = 'x''z' select @v3,@v4 +declare @v5 varchar(20) ="a""bc" , @v6 varchar(20) = 'x''z' , @v7 varchar(20) = "x""y'z'z" select @v5, @v6, @v7 +go + +declare @v varchar(20) = session_user, @v2 varchar(20)= system_user select @v, @v2, session_user, system_user +go +declare @v varchar(20) = 'abcd' + session_user, @v2 varchar(20) = 'xy' + session_user select @v, @v2, session_user +go +declare @v varchar(20) = 'abcd' + upper('x'), @v2 varchar(20) = 'xy' + upper('y') select @v, @v2 +go +declare @v varchar(20) = session_user, @v2 varchar(20)= system_user select @v,@v2,session_user, system_user +go +declare @v varchar(20) = "x'y" + session_user, @v2 varchar(20)= "a'b" + system_user select @v,@v2,session_user, system_user +go +declare @v varchar(20) = "x'y" + session_user, @v2 varchar(20)= "a'b" + system_user + "x''""" select @v,@v2,session_user, system_user +go +declare @v varchar(20) = session_user select @v +go + +create sequence dubquote_myseq +go +create sequence dubquote_myseq2 +go +create sequence dubquote_myseq3 +go +create sequence dubquote_myseq4 +go +declare +@v varchar(20) = '123' + next value for dubquote_myseq, +@v2 varchar(20) = next value for dubquote_myseq2, +@v3 varchar(20) = next value for dubquote_myseq3 + "000", +@v4 varchar(20) = "123" + next value for dubquote_myseq4 + "000" +select @v, @v2, @v3, @v4 +go +declare @v int = next value for dubquote_myseq select @v +go +declare @v int = next value for dubquote_myseq select @v +go +declare @v int = len("a'bc") + next value for dubquote_myseq + len(system_user) select @v +go +declare @v int = 0 set @v = next value for dubquote_myseq select @v +go +declare @v int = 0 set @v += len("a'bc") + next value for dubquote_myseq + len(system_user) select @v +go +declare @v int = 0 set @v -= len("a'bc") + next value for dubquote_myseq + len(system_user) select @v +go +declare @v int = 1 set @v *= len("a'bc") + next value for dubquote_myseq + len(system_user) select @v +go +declare @v int = 1 set @v /= len("a'bc") + next value for dubquote_myseq + len(system_user) select @v +go + + +set quoted_identifier on +go +create procedure dubquote_p6 @p varchar(20) ="abc" as select @p +go +exec dubquote_p6 +go +create procedure dubquote_p7 @p varchar(20) ="'abc'" as select @p +go +exec dubquote_p7 +go +declare @v varchar(20) = 'abc' select @v +go + +-- negative tests +declare @v varchar(20) = "abc" select @v +go +declare @v varchar(20) = "'abc'" select @v +go + + +--cleanup +drop procedure dubquote_p +go +drop procedure dubquote_p2 +go +drop function dubquote_f1 +go +drop function dubquote_f2 +go +drop function dubquote_f3 +go +drop procedure dubquote_p2a +go +drop procedure dubquote_p3 +go +drop procedure dubquote_p4 +go +drop function dubquote_f4 +go +drop function dubquote_f5 +go +drop function dubquote_f6 +go +drop function dubquote_f7 +go +drop procedure dubquote_p5 +go +drop sequence dubquote_myseq +go +drop sequence dubquote_myseq2 +go +drop sequence dubquote_myseq3 +go +drop sequence dubquote_myseq4 +go +drop procedure dubquote_p6 +go +drop procedure dubquote_p7 +go +drop table dubquote_t1 +go diff --git a/test/JDBC/input/pg_hint_plan/BABEL-3512.sql b/test/JDBC/input/pg_hint_plan/BABEL-3512.sql index 87333fb69c..992a49b6e8 100644 --- a/test/JDBC/input/pg_hint_plan/BABEL-3512.sql +++ b/test/JDBC/input/pg_hint_plan/BABEL-3512.sql @@ -179,6 +179,7 @@ GO SET babelfish_showplan_all ON GO +-- the purpose of babel_3512_t2_cte is to check the behavior for invalid hint EXEC babel_3512_proc_6 GO diff --git a/test/JDBC/input/views/sys_asymmetric_keys-vu-cleanup.sql b/test/JDBC/input/views/sys_asymmetric_keys-vu-cleanup.sql new file mode 100644 index 0000000000..896611741f --- /dev/null +++ b/test/JDBC/input/views/sys_asymmetric_keys-vu-cleanup.sql @@ -0,0 +1,11 @@ +USE master +GO + +DROP VIEW sys_asymmetric_keys_vu_prepare_view +GO + +DROP PROC sys_asymmetric_keys_vu_prepare_proc +GO + +DROP FUNCTION sys_asymmetric_keys_vu_prepare_func +GO \ No newline at end of file diff --git a/test/JDBC/input/views/sys_asymmetric_keys-vu-prepare.sql b/test/JDBC/input/views/sys_asymmetric_keys-vu-prepare.sql new file mode 100644 index 0000000000..5a6eebbb99 --- /dev/null +++ b/test/JDBC/input/views/sys_asymmetric_keys-vu-prepare.sql @@ -0,0 +1,18 @@ +USE master +GO + +CREATE VIEW sys_asymmetric_keys_vu_prepare_view AS +SELECT * FROM sys.asymmetric_keys +GO + +CREATE PROC sys_asymmetric_keys_vu_prepare_proc AS +SELECT * FROM sys.asymmetric_keys +GO + +CREATE FUNCTION sys_asymmetric_keys_vu_prepare_func() +RETURNS INT +AS +BEGIN + RETURN (SELECT COUNT(*) FROM sys.asymmetric_keys WHERE key_length= 0) +END +GO \ No newline at end of file diff --git a/test/JDBC/input/views/sys_asymmetric_keys-vu-verify.sql b/test/JDBC/input/views/sys_asymmetric_keys-vu-verify.sql new file mode 100644 index 0000000000..3253bf2b95 --- /dev/null +++ b/test/JDBC/input/views/sys_asymmetric_keys-vu-verify.sql @@ -0,0 +1,14 @@ +USE master +GO + +SELECT * FROM sys.asymmetric_keys +GO + +SELECT * FROM sys_asymmetric_keys_vu_prepare_view +GO + +EXEC sys_asymmetric_keys_vu_prepare_proc +GO + +SELECT sys_asymmetric_keys_vu_prepare_func() +GO \ No newline at end of file diff --git a/test/JDBC/input/views/sys_certificates-vu-cleanup.sql b/test/JDBC/input/views/sys_certificates-vu-cleanup.sql new file mode 100644 index 0000000000..b72014914a --- /dev/null +++ b/test/JDBC/input/views/sys_certificates-vu-cleanup.sql @@ -0,0 +1,11 @@ +USE master +GO + +DROP VIEW sys_certificates_vu_prepare_view +GO + +DROP PROC sys_certificates_vu_prepare_proc +GO + +DROP FUNCTION sys_certificates_vu_prepare_func +GO \ No newline at end of file diff --git a/test/JDBC/input/views/sys_certificates-vu-prepare.sql b/test/JDBC/input/views/sys_certificates-vu-prepare.sql new file mode 100644 index 0000000000..640d322249 --- /dev/null +++ b/test/JDBC/input/views/sys_certificates-vu-prepare.sql @@ -0,0 +1,18 @@ +USE master +GO + +CREATE VIEW sys_certificates_vu_prepare_view AS +SELECT * FROM sys.certificates +GO + +CREATE PROC sys_certificates_vu_prepare_proc AS +SELECT * FROM sys.certificates +GO + +CREATE FUNCTION sys_certificates_vu_prepare_func() +RETURNS INT +AS +BEGIN + RETURN (SELECT COUNT(*) FROM sys.certificates WHERE key_length = 0) +END +GO \ No newline at end of file diff --git a/test/JDBC/input/views/sys_certificates-vu-verify.sql b/test/JDBC/input/views/sys_certificates-vu-verify.sql new file mode 100644 index 0000000000..4211d6616b --- /dev/null +++ b/test/JDBC/input/views/sys_certificates-vu-verify.sql @@ -0,0 +1,14 @@ +USE master +GO + +SELECT * FROM sys.certificates +GO + +SELECT * FROM sys_certificates_vu_prepare_view +GO + +EXEC sys_certificates_vu_prepare_proc +GO + +SELECT sys_certificates_vu_prepare_func() +GO \ No newline at end of file diff --git a/test/JDBC/input/views/sys_database_permissions-vu-cleanup.sql b/test/JDBC/input/views/sys_database_permissions-vu-cleanup.sql new file mode 100644 index 0000000000..f3fc7169ae --- /dev/null +++ b/test/JDBC/input/views/sys_database_permissions-vu-cleanup.sql @@ -0,0 +1,11 @@ +USE master +GO + +DROP VIEW sys_database_permissions_vu_prepare_view +GO + +DROP PROC sys_database_permissions_vu_prepare_proc +GO + +DROP FUNCTION sys_database_permissions_vu_prepare_func +GO \ No newline at end of file diff --git a/test/JDBC/input/views/sys_database_permissions-vu-prepare.sql b/test/JDBC/input/views/sys_database_permissions-vu-prepare.sql new file mode 100644 index 0000000000..863addbcb3 --- /dev/null +++ b/test/JDBC/input/views/sys_database_permissions-vu-prepare.sql @@ -0,0 +1,18 @@ +USE master +GO + +CREATE VIEW sys_database_permissions_vu_prepare_view AS +SELECT * FROM sys.database_permissions +GO + +CREATE PROC sys_database_permissions_vu_prepare_proc AS +SELECT * FROM sys.database_permissions +GO + +CREATE FUNCTION sys_database_permissions_vu_prepare_func() +RETURNS INT +AS +BEGIN + RETURN (SELECT COUNT(*) FROM sys.database_permissions WHERE state='A') +END +GO \ No newline at end of file diff --git a/test/JDBC/input/views/sys_database_permissions-vu-verify.sql b/test/JDBC/input/views/sys_database_permissions-vu-verify.sql new file mode 100644 index 0000000000..3ca4edfd57 --- /dev/null +++ b/test/JDBC/input/views/sys_database_permissions-vu-verify.sql @@ -0,0 +1,14 @@ +USE master +GO + +SELECT * FROM sys.database_permissions +GO + +SELECT * FROM sys_database_permissions_vu_prepare_view +GO + +EXEC sys_database_permissions_vu_prepare_proc +GO + +SELECT sys_database_permissions_vu_prepare_func() +GO \ No newline at end of file diff --git a/test/JDBC/upgrade/latest/schedule b/test/JDBC/upgrade/latest/schedule index 6edd9abcce..9bfa6f4c01 100644 --- a/test/JDBC/upgrade/latest/schedule +++ b/test/JDBC/upgrade/latest/schedule @@ -452,6 +452,7 @@ timefromparts todatetimeoffset-dep triggers_with_transaction unquoted_string +doublequoted_string datetimeoffset-timezone BABEL-4046 host_id @@ -465,3 +466,6 @@ Test_ISNULL BABEL-4270 BABEL-4410 BABEL-4231 +sys_asymmetric_keys +sys_certificates +sys_database_permissions \ No newline at end of file diff --git a/test/python/SMO_script.ps1 b/test/python/SMO_script.ps1 index 63d213e2d5..753ab495a3 100644 --- a/test/python/SMO_script.ps1 +++ b/test/python/SMO_script.ps1 @@ -17,6 +17,8 @@ $script_flag = $paramsArray[5] $schm = "sys" $dtb = "sysdatabases" $var_one = "1" +$schm1 = "dbo" +$schm2 = "guest" @@ -52,6 +54,7 @@ else $Objects += $db.UserDefinedFunctions $SubObjects += $db.Tables.Indexes $SubObjects += $db.Tables.Triggers + $SubObjects += $db.Users foreach ($CurrentObject in $Objects) { if ($CurrentObject.schema -ne $schm -and $CurrentObject.schema -ne $dtb -and $CurrentObject.schema -ne $null -and -not $CurrentObject.IsSystemObject ) @@ -67,7 +70,7 @@ else } foreach ($CurrentObject in $SubObjects) { - if (-not $CurrentObject.IsSystemObject ) + if (-not $CurrentObject.IsSystemObject -and $CurrentObject.Name -ne $schm1 -and $CurrentObject.Name -ne $schm2) { $Scripter = New-Object ('Microsoft.SqlServer.Management.Smo.Scripter') ($SmoServer) $Scripter.Options.DriAll = $True; diff --git a/test/python/expected/pyodbc/ddl_users.out b/test/python/expected/pyodbc/ddl_users.out new file mode 100644 index 0000000000..d46f90cbdb --- /dev/null +++ b/test/python/expected/pyodbc/ddl_users.out @@ -0,0 +1,9 @@ +CREATE USER [test_usr1] FOR LOGIN [test_pwd1] WITH DEFAULT_SCHEMA=[dbo] +GO + +CREATE USER [test_usr2] FOR LOGIN [test_pwd2] WITH DEFAULT_SCHEMA=[dbo] +GO + +CREATE USER [test_usr3] FOR LOGIN [test_pwd3] WITH DEFAULT_SCHEMA=[dbo] +GO + diff --git a/test/python/expected/upgrade_validation/expected_dependency.out b/test/python/expected/upgrade_validation/expected_dependency.out index 05e0dac08d..385115fae4 100644 --- a/test/python/expected/upgrade_validation/expected_dependency.out +++ b/test/python/expected/upgrade_validation/expected_dependency.out @@ -954,7 +954,6 @@ Operator sys.^(smallint,smallint) Operator sys.^(sys.tinyint,sys.tinyint) Operator sys.~(NONE,sys."bit") Type sys."bigint" -Type sys."int" Type sys."real" Type sys.bbf_varbinary Type sys.cursor diff --git a/test/python/input/ddl_users.sql b/test/python/input/ddl_users.sql new file mode 100644 index 0000000000..8b77670d16 --- /dev/null +++ b/test/python/input/ddl_users.sql @@ -0,0 +1,41 @@ +/* This test files will check for scripting views only */ +DROP USER IF EXISTS test_usr1 +GO +DROP USER IF EXISTS test_usr2 +GO +DROP USER IF EXISTS test_usr3 +GO + +CREATE LOGIN test_pwd1 + WITH PASSWORD = '340$Uuxwp7Mcxo7Khy'; + +CREATE LOGIN test_pwd2 + WITH PASSWORD = '340$UuxwpMcxo7Khy'; + +CREATE LOGIN test_pwd3 + WITH PASSWORD = '340$Uuxwp7Mco7Khy'; + + + +CREATE USER test_usr1 FOR LOGIN test_pwd1; +GO + +CREATE USER test_usr2 FOR LOGIN test_pwd2; +GO + +CREATE USER test_usr3 FOR LOGIN test_pwd3; +GO + +--DROP +DROP LOGIN test_pwd1 +GO +DROP LOGIN test_pwd2 +GO +DROP LOGIN test_pwd3 +GO +DROP USER IF EXISTS test_usr1 +GO +DROP USER IF EXISTS test_usr2 +GO +DROP USER IF EXISTS test_usr3 +GO \ No newline at end of file diff --git a/test/python/input/ddl_views.sql b/test/python/input/ddl_views.sql index 155cce6b46..362575b6cb 100644 --- a/test/python/input/ddl_views.sql +++ b/test/python/input/ddl_views.sql @@ -29,4 +29,4 @@ GO DROP VIEW IF EXISTS sys_all_views_dep_view_vu_prepare GO DROP TABLE IF EXISTS sys_all_views_table_vu_prepare -GO \ No newline at end of file +GO