diff --git a/contrib/babelfishpg_tds/src/backend/tds/tdsrpc.c b/contrib/babelfishpg_tds/src/backend/tds/tdsrpc.c index 13e2fefe4a..a55d38342a 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tdsrpc.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tdsrpc.c @@ -1587,7 +1587,7 @@ ReadParameters(TDSRequestSP request, uint64_t offset, StringInfo message, int *p * Sets the col metadata and also the corresponding row * data. */ - SetColMetadataForTvp(temp, message, &offset); + SetColMetadataForTvp(temp, message, &offset, request->name.data); } break; case TDS_TYPE_BINARY: diff --git a/contrib/babelfishpg_tds/src/include/tds_request.h b/contrib/babelfishpg_tds/src/include/tds_request.h index f3adbf418d..77485916a9 100644 --- a/contrib/babelfishpg_tds/src/include/tds_request.h +++ b/contrib/babelfishpg_tds/src/include/tds_request.h @@ -24,6 +24,7 @@ #include "src/include/tds_typeio.h" #include "src/collation.h" + /* Different TDS request types returned by GetTDSRequest() */ typedef enum TDSRequestType { @@ -498,16 +499,16 @@ SetTvpRowData(ParameterToken temp, const StringInfo message, uint64_t *offset) } static inline void -SetColMetadataForTvp(ParameterToken temp, const StringInfo message, uint64_t *offset) +SetColMetadataForTvp(ParameterToken temp, const StringInfo message, uint64_t *offset, char *proc_name) { - uint8_t len; - uint16 colCount; - uint16 isTvpNull; - char *tempString; - int i = 0; - char *messageData = message->data; - StringInfo tempStringInfo = palloc(sizeof(StringInfoData)); - uint32_t collation; + uint8_t len; + uint16 colCount; + uint16 isTvpNull; + char *tempString; + int i = 0; + char *messageData = message->data; + StringInfo tempStringInfo = palloc(sizeof(StringInfoData)); + uint32_t collation; /* Database-Name.Schema-Name.TableType-Name */ for (; i < 3; i++) @@ -536,21 +537,34 @@ SetColMetadataForTvp(ParameterToken temp, const StringInfo message, uint64_t *of if (i == 1) temp->tvpInfo->tvpTypeSchemaName = tempStringInfo->data; else + { temp->tvpInfo->tvpTypeName = tempStringInfo->data; - + temp->tvpInfo->tableName = 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))); + char *tvp_type_name; + char *tvp_type_schema_name; + /* + * Fetch the TVP typeName and schemaName from catalog search + * based on object name and argument name. + */ + pltsql_plugin_handler_ptr->get_tvp_typename_typeschemaname(proc_name, + temp->paramMeta.colName.data, + &tvp_type_name, + &tvp_type_schema_name); + temp->len += strlen(tvp_type_schema_name); + temp->tvpInfo->tvpTypeSchemaName = pstrdup(tvp_type_schema_name); + + pfree(tvp_type_schema_name); + + temp->len += strlen(tvp_type_name); + temp->tvpInfo->tvpTypeName = tvp_type_name; + temp->tvpInfo->tableName = tvp_type_name; } } - temp->tvpInfo->tableName = tempStringInfo->data; i = 0; memcpy(&isTvpNull, &messageData[*offset], sizeof(uint16)); diff --git a/contrib/babelfishpg_tsql/runtime/functions.c b/contrib/babelfishpg_tsql/runtime/functions.c index 56b7f7c0b3..8842187dff 100644 --- a/contrib/babelfishpg_tsql/runtime/functions.c +++ b/contrib/babelfishpg_tsql/runtime/functions.c @@ -2133,7 +2133,6 @@ object_id(PG_FUNCTION_ARGS) char *physical_schema_name; char *input; char *object_type = NULL; - char **splited_object_name; Oid schema_oid; Oid user_id = GetUserId(); Oid result = InvalidOid; @@ -2173,31 +2172,13 @@ object_id(PG_FUNCTION_ARGS) (errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH), errmsg("input value is too long for object name"))); - /* resolve the three part name */ - splited_object_name = split_object_name(input); - db_name = splited_object_name[1]; - schema_name = splited_object_name[2]; - object_name = splited_object_name[3]; - - /* downcase identifier if needed */ - if (pltsql_case_insensitive_identifiers) - { - db_name = downcase_identifier(db_name, strlen(db_name), false, false); - schema_name = downcase_identifier(schema_name, strlen(schema_name), false, false); - object_name = downcase_identifier(object_name, strlen(object_name), false, false); - for (int j = 0; j < 4; j++) - pfree(splited_object_name[j]); - } - else - pfree(splited_object_name[0]); + /* + * Split the input string, downcase and truncate if needed + * and return the db_name, schema_name and object_name. + */ + downcase_truncate_split_object_name(input, NULL, &db_name, &schema_name, &object_name); pfree(input); - pfree(splited_object_name); - - /* truncate identifiers if needed */ - truncate_tsql_identifier(db_name); - truncate_tsql_identifier(schema_name); - truncate_tsql_identifier(object_name); if (!strcmp(db_name, "")) db_name = get_cur_db_name(); @@ -2615,7 +2596,6 @@ type_id(PG_FUNCTION_ARGS) *object_name; char *physical_schema_name; char *input; - char **splitted_object_name; Oid schema_oid = InvalidOid; Oid user_id = GetUserId(); Oid result = InvalidOid; @@ -2640,40 +2620,20 @@ type_id(PG_FUNCTION_ARGS) (errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH), errmsg("input value is too long for object name"))); - /* resolve the two part name */ - splitted_object_name = split_object_name(input); + /* + * Split the input string, downcase and truncate if needed + * and return the db_name, schema_name and object_name. + */ + downcase_truncate_split_object_name(input, NULL, &db_name, &schema_name, &object_name); + + pfree(input); + /* If three part name(db_name also included in input) then return null */ - if(pg_mbstrlen(splitted_object_name[1]) != 0) + if(pg_mbstrlen(db_name) != 0) { - pfree(input); - for (int j = 0; j < 4; j++) - pfree(splitted_object_name[j]); - pfree(splitted_object_name); PG_RETURN_NULL(); } db_name = get_cur_db_name(); - schema_name = splitted_object_name[2]; - object_name = splitted_object_name[3]; - - /* downcase identifier if needed */ - if (pltsql_case_insensitive_identifiers) - { - db_name = downcase_identifier(db_name, strlen(db_name), false, false); - schema_name = downcase_identifier(schema_name, strlen(schema_name), false, false); - object_name = downcase_identifier(object_name, strlen(object_name), false, false); - for (int k = 0; k < 4; k++) - pfree(splitted_object_name[k]); - } - else - pfree(splitted_object_name[0]); - - pfree(input); - pfree(splitted_object_name); - - /* truncate identifiers if needed */ - truncate_tsql_identifier(db_name); - truncate_tsql_identifier(schema_name); - truncate_tsql_identifier(object_name); if (!strcmp(schema_name, "")) { diff --git a/contrib/babelfishpg_tsql/src/catalog.c b/contrib/babelfishpg_tsql/src/catalog.c index 16f877d77f..a9209fe2d8 100644 --- a/contrib/babelfishpg_tsql/src/catalog.c +++ b/contrib/babelfishpg_tsql/src/catalog.c @@ -14,6 +14,7 @@ #include "catalog/pg_proc.h" #include "catalog/pg_foreign_server.h" #include "catalog/namespace.h" +#include "catalog/pg_type.h" #include "commands/extension.h" #include "commands/schemacmds.h" #include "commands/user.h" @@ -6135,3 +6136,154 @@ alter_default_privilege_on_schema(PG_FUNCTION_ARGS) table_close(db_rel, AccessShareLock); PG_RETURN_INT32(0); } + +/* + * get_proc_namespace_oid: + * Find namespace oid of a procedure based on proc name. + */ +static Oid +get_proc_namespace_oid(char **proc_name, char *curr_db) +{ + char *physical_sch_name; + char *db_name; + char *schema_name; + char *object_name; + Oid obj_schema_oid = InvalidOid; + + if (*proc_name == NULL) + ereport(ERROR, + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("procedure name cannot be NULL"))); + + /* + * Split the proc name, downcase and truncate if needed + * and return the db_name, schema_name and object_name. + */ + downcase_truncate_split_object_name(*proc_name, NULL, &db_name, &schema_name, &object_name); + *proc_name = object_name; + + if (!strcmp(db_name, "")) + db_name = curr_db; + + if (!strcmp(schema_name, "")) + { + /* Find the default schema for current user. */ + char *user = get_user_for_database(db_name); + schema_name = get_authid_user_ext_schema_name((const char *) db_name, (const char *) user); + } + + /* Get physical schema name from logical schema name. */ + physical_sch_name = get_physical_schema_name(db_name, schema_name); + /* Get namespace oid from physical schema name. */ + obj_schema_oid = get_namespace_oid(physical_sch_name, false); + + pfree(db_name); + pfree(schema_name); + pfree(physical_sch_name); + + return obj_schema_oid; +} + +/* + * get_proargtypes_oid: + * Given a procedure name, namespace, user ID, and target argument name + * return the OID of the argument's type in the procedure. + * + * Returns InvalidOid if no matching procedure argument is found. + */ +static Oid +get_proargtypes_oid(char *proname, Oid pronamespace, Oid user_id, char *targeted_arg_name) +{ + HeapTuple tuple; + CatCList *catlist; + Oid matched_type = InvalidOid; + + /* Downcase and truncate identifier if needed. */ + targeted_arg_name = downcase_truncate_identifier(targeted_arg_name, strlen(targeted_arg_name), true); + + /* First search in pg_proc by name. */ + catlist = SearchSysCacheList1(PROCNAMEARGSNSP, CStringGetDatum(proname)); + + for (int i = 0; i < catlist->n_members; i++) + { + Form_pg_proc procform; + + tuple = &catlist->members[i]->tuple; + procform = (Form_pg_proc) GETSTRUCT(tuple); + + /* Then consider only procs in specified namespace. */ + if (procform->pronamespace == pronamespace && + object_aclcheck(ProcedureRelationId, procform->oid, user_id, ACL_EXECUTE) == ACLCHECK_OK) + { + /* Get the list of proargames and corresponding proargtypes oids. */ + char **proargnames = fetch_func_input_arg_names(tuple); + Oid *proargtypes = procform->proargtypes.values; + + /* Find the typeoid corresponding to target TVP argument. */ + for (int j = 0; j < procform->pronargs; j++) + { + if (strcmp(proargnames[j], targeted_arg_name) == 0) + { + matched_type = proargtypes[j]; + break; + } + } + } + } + ReleaseSysCacheList(catlist); + if (matched_type == InvalidOid) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("No procedure found with name \"%s\" that has an argument named \"%s\"", + proname, targeted_arg_name))); + } + return matched_type; +} + +/* + * get_tvp_typename_typeschemaname: + * Retrieves the type name and schema name of a Table-Valued Parameter (TVP) + * for a given stored procedure and argument name. + */ +void +get_tvp_typename_typeschemaname(char *proc_name, char *target_arg_name, char **tvp_type_name, char **tvp_type_schema_name) +{ + bool xactStarted = IsTransactionOrTransactionBlock(); + Oid tvp_proargtype = InvalidOid; + Oid user_id = InvalidOid; + Oid obj_schema_oid = InvalidOid; + HeapTuple tuple; + char *typnamespace; + char *curr_db; + MemoryContext oldContext; + + if (!xactStarted) + StartTransactionCommand(); + user_id = GetUserId(); + curr_db = get_cur_db_name(); + + /* Get procedure namespaceid. */ + obj_schema_oid = get_proc_namespace_oid(&proc_name, curr_db); + + /* Fetch proargtype value of our targeted variable. */ + tvp_proargtype = get_proargtypes_oid(proc_name, obj_schema_oid, user_id, target_arg_name); + + /* Search in pg_type by object_id and fetch tvpTypeName and tvpTypeSchemaName. */ + tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(tvp_proargtype)); + /* Check if user have right permission on object. */ + if (HeapTupleIsValid(tuple) && object_aclcheck(TypeRelationId, tvp_proargtype, user_id, ACL_USAGE) == ACLCHECK_OK) + { + Form_pg_type pg_type = (Form_pg_type) GETSTRUCT(tuple); + *tvp_type_name = NameStr(pg_type->typname); + typnamespace = get_namespace_name(pg_type->typnamespace); + + oldContext = MemoryContextSwitchTo(TopMemoryContext); + *tvp_type_schema_name = pstrdup((char *) get_logical_schema_name(typnamespace, true)); + MemoryContextSwitchTo(oldContext); + ReleaseSysCache(tuple); + } + + if(!xactStarted) + CommitTransactionCommand(); +} diff --git a/contrib/babelfishpg_tsql/src/catalog.h b/contrib/babelfishpg_tsql/src/catalog.h index 3e8e2c8169..c6ecfab882 100644 --- a/contrib/babelfishpg_tsql/src/catalog.h +++ b/contrib/babelfishpg_tsql/src/catalog.h @@ -581,4 +581,6 @@ typedef struct Rule RelData *tbldata; /* extra catalog info */ } Rule; +extern void get_tvp_typename_typeschemaname(char *proc_name, char *target_arg_name, char **tvp_type_name, char **tvp_type_schema_name); + #endif diff --git a/contrib/babelfishpg_tsql/src/hooks.c b/contrib/babelfishpg_tsql/src/hooks.c index 1ca6e3cf56..fe618a9e9d 100644 --- a/contrib/babelfishpg_tsql/src/hooks.c +++ b/contrib/babelfishpg_tsql/src/hooks.c @@ -117,7 +117,7 @@ static bool match_pltsql_func_call(HeapTuple proctup, int nargs, List *argnames, static ObjectAddress get_trigger_object_address(List *object, Relation *relp, bool missing_ok, bool object_from_input); Oid get_tsql_trigger_oid(List *object, const char *tsql_trigger_name, bool object_from_input); static Node *transform_like_in_add_constraint(Node *node); -static char** fetch_func_input_arg_names(HeapTuple func_tuple); +char** fetch_func_input_arg_names(HeapTuple func_tuple); /***************************************** * Analyzer Hooks @@ -4232,7 +4232,7 @@ static int getDefaultPosition(const List *default_positions, const ListCell *def * @param func_tuple or proc_tuple * @return char** list of input arg names */ -static char** fetch_func_input_arg_names(HeapTuple func_tuple) +char** fetch_func_input_arg_names(HeapTuple func_tuple) { Datum proargnames; Datum proargmodes; diff --git a/contrib/babelfishpg_tsql/src/hooks.h b/contrib/babelfishpg_tsql/src/hooks.h index 9c729e10e0..74a77a03fd 100644 --- a/contrib/babelfishpg_tsql/src/hooks.h +++ b/contrib/babelfishpg_tsql/src/hooks.h @@ -36,6 +36,7 @@ extern Datum pltsql_exec_tsql_cast_value(Datum value, bool *isnull, Oid reqtype, int32 reqtypmod); extern void pltsql_bbfSelectIntoUtility(ParseState *pstate, PlannedStmt *pstmt, const char *queryString, QueryEnvironment *queryEnv, ParamListInfo params, QueryCompletion *qc, ObjectAddress *address); +extern char** fetch_func_input_arg_names(HeapTuple func_tuple); extern char *update_delete_target_alias; extern bool sp_describe_first_result_set_inprogress; diff --git a/contrib/babelfishpg_tsql/src/pl_handler.c b/contrib/babelfishpg_tsql/src/pl_handler.c index 15d09299dc..a863232344 100644 --- a/contrib/babelfishpg_tsql/src/pl_handler.c +++ b/contrib/babelfishpg_tsql/src/pl_handler.c @@ -5001,6 +5001,7 @@ _PG_init(void) (*pltsql_protocol_plugin_ptr)->tsql_char_input = common_utility_plugin_ptr->tsql_bpchar_input; (*pltsql_protocol_plugin_ptr)->get_cur_db_name = &get_cur_db_name; (*pltsql_protocol_plugin_ptr)->get_physical_schema_name = &get_physical_schema_name; + (*pltsql_protocol_plugin_ptr)->get_tvp_typename_typeschemaname = &get_tvp_typename_typeschemaname; (*pltsql_protocol_plugin_ptr)->quoted_identifier = pltsql_quoted_identifier; (*pltsql_protocol_plugin_ptr)->arithabort = pltsql_arithabort; diff --git a/contrib/babelfishpg_tsql/src/pltsql.h b/contrib/babelfishpg_tsql/src/pltsql.h index a2191367b9..86772d9e29 100644 --- a/contrib/babelfishpg_tsql/src/pltsql.h +++ b/contrib/babelfishpg_tsql/src/pltsql.h @@ -1801,7 +1801,8 @@ typedef struct PLtsql_protocol_plugin void (*set_reset_tds_connection_flag) (); bool (*get_reset_tds_connection_flag) (); - + void (*get_tvp_typename_typeschemaname) (char *proc_name, char *target_arg_name, + char **tvp_type_name, char **tvp_type_schema_name); /* Session level GUCs */ bool quoted_identifier; bool arithabort; @@ -2245,6 +2246,7 @@ extern bool is_tsql_nchar_or_nvarchar_datatype(Oid oid); /* sys.nchar / sys.nvar extern bool is_tsql_binary_or_varbinary_datatype(Oid oid); /* sys.binary / sys.varbinary */ extern bool is_tsql_datatype_with_max_scale_expr_allowed(Oid oid); /* sys.varchar(max), sys.nvarchar(max), sys.varbinary(max) */ extern bool is_tsql_text_ntext_or_image_datatype(Oid oid); /* sys.text, sys.ntext, sys.image */ +extern void downcase_truncate_split_object_name(char *four_part_object_name, char** server_name, char** db_name, char** schema_name, char** object_name); typedef struct { diff --git a/contrib/babelfishpg_tsql/src/pltsql_utils.c b/contrib/babelfishpg_tsql/src/pltsql_utils.c index 6d936ef3f0..5bc8ff7003 100644 --- a/contrib/babelfishpg_tsql/src/pltsql_utils.c +++ b/contrib/babelfishpg_tsql/src/pltsql_utils.c @@ -31,6 +31,7 @@ #include "multidb.h" #include "session.h" #include "rolecmds.h" +#include "parser/scansup.h" common_utility_plugin *common_utility_plugin_ptr = NULL; @@ -2650,3 +2651,57 @@ update_GrantRoleStmtByName(Node *n, const char *granted_role, const char *grante update_GrantRoleStmt(n, list_make1(granted_rolespec), list_make1(grantee_rolespec), NULL); } + +/* + * downcase_truncate_split_object_name: + * Resolve the four part object name. Downcase and truncate identifier if needed. + * Specify NULL for any of the server_name, db_name, schema_name, object_name if + * we don't need to resolve them. + */ +void +downcase_truncate_split_object_name(char *four_part_object_name, char **server_name, + char **db_name, char **schema_name, char **object_name) +{ + char **splited_object_name; + char *temp_server_name; + char *temp_db_name; + char *temp_schema_name; + char *temp_object_name; + + /* Resolve the four part name. */ + splited_object_name = split_object_name(four_part_object_name); + temp_server_name = splited_object_name[0]; + temp_db_name = splited_object_name[1]; + temp_schema_name = splited_object_name[2]; + temp_object_name = splited_object_name[3]; + + /* Downcase identifier if needed. */ + if (pltsql_case_insensitive_identifiers) + { + temp_server_name = downcase_identifier(temp_server_name, strlen(temp_server_name), false, false); + temp_db_name = downcase_identifier(temp_db_name, strlen(temp_db_name), false, false); + temp_schema_name = downcase_identifier(temp_schema_name, strlen(temp_schema_name), false, false); + temp_object_name = downcase_identifier(temp_object_name, strlen(temp_object_name), false, false); + for (int j = 0; j < 4; j++) + pfree(splited_object_name[j]); + } + else + pfree(splited_object_name[0]); + + pfree(splited_object_name); + + /* Truncate identifiers if needed. */ + truncate_tsql_identifier(temp_server_name); + truncate_tsql_identifier(temp_db_name); + truncate_tsql_identifier(temp_schema_name); + truncate_tsql_identifier(temp_object_name); + + if (server_name != NULL) + *server_name = temp_server_name; + if (db_name != NULL) + *db_name = temp_db_name; + if (schema_name != NULL) + *schema_name = temp_schema_name; + if (object_name != NULL) + *object_name = temp_object_name; +} diff --git a/contrib/babelfishpg_tsql/src/procedures.c b/contrib/babelfishpg_tsql/src/procedures.c index 93e0ed6cb4..5ee3079e81 100644 --- a/contrib/babelfishpg_tsql/src/procedures.c +++ b/contrib/babelfishpg_tsql/src/procedures.c @@ -51,9 +51,7 @@ #include "catalog.h" #include "extendedproperty.h" #include "multidb.h" -#include "pltsql.h" #include "session.h" -#include "pltsql.h" #include "rolecmds.h" PG_FUNCTION_INFO_V1(sp_unprepare); @@ -3386,38 +3384,24 @@ sp_babelfish_volatility(PG_FUNCTION_ARGS) char *full_function_name = NULL; char *logical_schema_name = NULL; char *physical_schema_name = NULL; - char **splited_object_name; + char *server_name; + char *object_name; + char *database_name; - /* get physical schema name */ - splited_object_name = split_object_name(function_name); + /* + * Split the function name, downcase and truncate if needed + * and return the server_name, db_name, schema_name and object_name. + */ + downcase_truncate_split_object_name(function_name, &server_name, &database_name, &logical_schema_name, &object_name); - if (strcmp(splited_object_name[0], "") || strcmp(splited_object_name[1], "")) + if (strcmp(server_name, "") || strcmp(database_name, "")) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("function \"%s\" is not a valid two part name", function_name))); pfree(function_name); - logical_schema_name = splited_object_name[2]; - function_name = splited_object_name[3]; - - /* downcase identifier */ - if (pltsql_case_insensitive_identifiers) - { - logical_schema_name = downcase_identifier(logical_schema_name, strlen(logical_schema_name), false, false); - function_name = downcase_identifier(function_name, strlen(function_name), false, false); - for (int j = 0; j < 4; j++) - pfree(splited_object_name[j]); - } - else - { - pfree(splited_object_name[0]); - pfree(splited_object_name[1]); - } - pfree(splited_object_name); - /* truncate identifiers if needed */ - truncate_tsql_identifier(logical_schema_name); - truncate_tsql_identifier(function_name); + function_name = object_name; if (!strcmp(function_name, "")) ereport(ERROR, diff --git a/test/dotnet/ExpectedOutput/TestTvp.out b/test/dotnet/ExpectedOutput/TestTvp.out index 4884995318..dc024cc546 100644 --- a/test/dotnet/ExpectedOutput/TestTvp.out +++ b/test/dotnet/ExpectedOutput/TestTvp.out @@ -32,3 +32,115 @@ 1#!#1#!#1#!#1#!#True#!#hi #!#hi #!#hi#!#hi#!#4949#!#494900000000#!#10/10/2022 00:00:00#!#10/10/2022 10:10:10#!#143.5000#!#ce8af10a-2709-43b0-9e4e-a02753929d17#!#12.11#!#13.11#!#1.330#!#45.122#!#10:10:10#!#10/10/2022 10:10:10 #Q#drop type this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong #Q#drop schema this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong +#Q#create table t(a int) +#Q#create type t1 as table (a int) +#Q#create procedure proc1 @t2 as t1 readonly as begin set nocount on; insert into t (a) select a from @t2 end +#Q#proc1 +#Q#Select * from t +#D#int +5 +#Q#create table tab1(a int) +#Q#create schema test_tvp1 +#Q#create type test_tvp1.t1 as table (a int) +#Q#create procedure proc2 @t2 as test_tvp1.t1 readonly as begin set nocount on; insert into tab1 (a) select a from @t2 end +#Q#proc2 +#Q#Select * from tab1 +#D#int +5 +#Q#create table t2(a int) +#Q#create procedure test_tvp1.proc1 @t2 test_tvp1.t1 readonly as begin set nocount on; insert into t2 (a) select a from @t2 end +#Q#test_tvp1.proc1 +#Q#Select * from t2 +#D#int +5 +#Q#create table t3(a int) +#Q#create schema test_tvp2 +#Q#create procedure test_tvp2.proc2 @t2 as test_tvp1.t1 readonly as begin set nocount on; insert into t3 (a) select a from @t2 end +#Q#test_tvp2.proc2 +#Q#Select * from t3 +#D#int +5 +#Q#create table t4(a int) +#Q#create procedure test_tvp2.proc3 @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong as t1 READONLY AS BEGIN insert into t4 select * from @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong END +#Q#test_tvp2.proc3 +#Q#Select * from t4 +#D#int +5 +#Q#create table t5(a int) +#Q#create type test_tvp2.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong5 as table (a int) +#Q#create procedure test_tvp2.proc4 @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong as test_tvp2.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong5 READONLY AS BEGIN insert into t5 select * from @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong END +#Q#test_tvp2.proc4 +#Q#Select * from t5 +#D#int +5 +#Q#create table t6(a int) +#Q#create schema this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong +#Q#create type this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong5 as table (a int) +#Q#create procedure this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.proc5 @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong as this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong5 READONLY AS BEGIN insert into t6 select * from @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong END +#Q#this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.proc5 +#Q#Select * from t6 +#D#int +5 +#Q#create table t7(a int) +#Q#create procedure this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_proc_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong as this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong5 READONLY AS BEGIN insert into t7 select * from @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong END +#Q#this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_proc_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong +#Q#Select * from t7 +#D#int +5 +#Q#create table t10(a int) +#Q#create type tvp_type as table (a int) +#Q#create procedure proc7 @random int, @t2 tvp_type READONLY AS BEGIN insert into t10 select * from @t2 END +#Q#proc7 +#Q#Select * from t10 +#D#int +5 +#Q#drop procedure proc1 +#Q#drop procedure proc2 +#Q#drop procedure test_tvp1.proc1 +#Q#drop procedure test_tvp2.proc2 +#Q#drop procedure test_tvp2.proc3 +#Q#drop procedure test_tvp2.proc4 +#Q#drop procedure this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.proc5 +#Q#drop procedure this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_proc_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong +#Q#drop procedure proc7 +#Q#drop table t +#Q#drop table tab1 +#Q#drop table t2 +#Q#drop table t3 +#Q#drop table t4 +#Q#drop table t5 +#Q#drop table t6 +#Q#drop table t7 +#Q#drop table t10 +#Q#drop type t1 +#Q#drop type test_tvp1.t1 +#Q#drop type test_tvp2.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong5 +#Q#drop type this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong5 +#Q#drop type tvp_type +#Q#drop schema test_tvp1 +#Q#drop schema test_tvp2 +#Q#drop schema this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong +#Q#create database db1 +#Q#Use db1 +#Q#create table t8(a int) +#Q#create schema this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong +#Q#create type this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong5 as table (a int) +#Q#create procedure this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_proc_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong as this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong5 READONLY AS BEGIN insert into t8 select * from @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong END +#Q#this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_proc_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong +#Q#Select * from t8 +#D#int +5 +#Q#create table t9(a int) +#Q#create procedure this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_proc_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong_new @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong as this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong5 READONLY AS BEGIN insert into t9 select * from @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong END +#Q#db1.this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_proc_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong_new +#Q#Select * from t9 +#D#int +5 +#Q#drop procedure this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_proc_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong +#Q#drop procedure this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_proc_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong_new +#Q#drop table db1.dbo.t8 +#Q#drop table db1.dbo.t9 +#Q#drop type this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong5 +#Q#drop schema this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong +#Q#use master +#Q#drop database db1 diff --git a/test/dotnet/input/Datatypes/TestTvp.txt b/test/dotnet/input/Datatypes/TestTvp.txt index 01bc74f8a8..1a473c0ff5 100644 --- a/test/dotnet/input/Datatypes/TestTvp.txt +++ b/test/dotnet/input/Datatypes/TestTvp.txt @@ -20,6 +20,7 @@ Create table tvp_table(a int, b smallint, c bigint, d tinyint, e bit, f char(10) create type this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong as table (a int, b smallint, c bigint, d tinyint, e bit, f char(10), g nchar(10), h varchar(10), i nvarchar(10), l varbinary(10), m binary(10), n date, o datetime, p money, q uniqueidentifier,r float, s real, t numeric(4,3), u decimal(5,3), v time(5), w datetime2(5)) create procedure tvp_proc @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong as this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong READONLY AS BEGIN insert into tvp_table select * from @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong END storedproc#!#prep#!#tvp_proc#!#tvp|-|this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong|-|this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong|-|../../../utils/tvp-dotnet.csv + Select * from tvp_table drop procedure tvp_proc drop table tvp_table @@ -30,4 +31,118 @@ create schema this_schema_name_is_also_very_looooooooooooooooooooooooooooooooooo create type this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong as table (a int, b smallint, c bigint, d tinyint, e bit, f char(10), g nchar(10), h varchar(10), i nvarchar(10), l varbinary(10), m binary(10), n date, o datetime, p money, q uniqueidentifier,r float, s real, t numeric(4,3), u decimal(5,3), v time(5), w datetime2(5)) prepst#!#Select * from @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong#!#tvp|-|this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong|-|this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong|-|../../../utils/tvp-dotnet.csv drop type this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong -drop schema this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong \ No newline at end of file +drop schema this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong + +#test tvp without passing tvpTypeName +create table t(a int) +create type t1 as table (a int) +create procedure proc1 @t2 as t1 readonly as begin set nocount on; insert into t (a) select a from @t2 end +storedproc#!#prep#!#proc1#!#tvp|-|t2|-| |-|../../../utils/tvp-test-dotnet.csv +Select * from t + +# test with schema for type and without passing tvpTypeName +create table tab1(a int) +create schema test_tvp1 +create type test_tvp1.t1 as table (a int) +create procedure proc2 @t2 as test_tvp1.t1 readonly as begin set nocount on; insert into tab1 (a) select a from @t2 end +storedproc#!#prep#!#proc2#!#tvp|-|t2|-| |-|../../../utils/tvp-test-dotnet.csv +Select * from tab1 + +# test with schema for proc and type in same schema and without passing tvpTypeName +create table t2(a int) +create procedure test_tvp1.proc1 @t2 test_tvp1.t1 readonly as begin set nocount on; insert into t2 (a) select a from @t2 end +storedproc#!#prep#!#test_tvp1.proc1#!#tvp|-|t2|-| |-|../../../utils/tvp-test-dotnet.csv +Select * from t2 + +# test with schema for proc and type in different schema and without passing tvpTypeName +create table t3(a int) +create schema test_tvp2 +create procedure test_tvp2.proc2 @t2 as test_tvp1.t1 readonly as begin set nocount on; insert into t3 (a) select a from @t2 end +storedproc#!#prep#!#test_tvp2.proc2#!#tvp|-|t2|-| |-|../../../utils/tvp-test-dotnet.csv +Select * from t3 + +# executing stored proc without passing tvp value for huge parameter name and without passing tvpTypeName +create table t4(a int) +create procedure test_tvp2.proc3 @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong as t1 READONLY AS BEGIN insert into t4 select * from @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong END +storedproc#!#prep#!#test_tvp2.proc3#!#tvp|-|this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong|-| |-|../../../utils/tvp-test-dotnet.csv +Select * from t4 + +# when parameter and type both are very long, and both are part of schema other than dbo and without passing tvpTypeName +create table t5(a int) +create type test_tvp2.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong5 as table (a int) +create procedure test_tvp2.proc4 @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong as test_tvp2.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong5 READONLY AS BEGIN insert into t5 select * from @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong END +storedproc#!#prep#!#test_tvp2.proc4#!#tvp|-|this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong|-| |-|../../../utils/tvp-test-dotnet.csv +Select * from t5 + +# when parameter and type both are very long, and both are part of a very long schema other than dbo and without passing tvpTypeName +create table t6(a int) +create schema this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong +create type this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong5 as table (a int) +create procedure this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.proc5 @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong as this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong5 READONLY AS BEGIN insert into t6 select * from @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong END +storedproc#!#prep#!#this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.proc5#!#tvp|-|this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong|-| |-|../../../utils/tvp-test-dotnet.csv +Select * from t6 + +# when parameter, type, schema and procedure name are very long and without passing tvpTypeName +create table t7(a int) +create procedure this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_proc_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong as this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong5 READONLY AS BEGIN insert into t7 select * from @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong END +storedproc#!#prep#!#this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_proc_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong#!#tvp|-|this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong|-| |-|../../../utils/tvp-test-dotnet.csv +Select * from t7 + +# procedure having multiple args, without passing tvp tvpTypeName +create table t10(a int) +create type tvp_type as table (a int) +create procedure proc7 @random int, @t2 tvp_type READONLY AS BEGIN insert into t10 select * from @t2 END +storedproc#!#prep#!#proc7#!#int|-|random|-|20|-|input#!#tvp|-|t2|-| |-|../../../utils/tvp-test-dotnet.csv +Select * from t10 + +drop procedure proc1 +drop procedure proc2 +drop procedure test_tvp1.proc1 +drop procedure test_tvp2.proc2 +drop procedure test_tvp2.proc3 +drop procedure test_tvp2.proc4 +drop procedure this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.proc5 +drop procedure this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_proc_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong +drop procedure proc7 +drop table t +drop table tab1 +drop table t2 +drop table t3 +drop table t4 +drop table t5 +drop table t6 +drop table t7 +drop table t10 +drop type t1 +drop type test_tvp1.t1 +drop type test_tvp2.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong5 +drop type this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong5 +drop type tvp_type +drop schema test_tvp1 +drop schema test_tvp2 +drop schema this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong + +# creating a db and creating objects in it and executing the proc without db specification +create database db1 +Use db1 +create table t8(a int) +create schema this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong +create type this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong5 as table (a int) +create procedure this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_proc_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong as this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong5 READONLY AS BEGIN insert into t8 select * from @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong END +storedproc#!#prep#!#this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_proc_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong#!#tvp|-|this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong|-| |-|../../../utils/tvp-test-dotnet.csv +Select * from t8 + +# creating a db and creating objects in it and executing the proc with db specification +create table t9(a int) +create procedure this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_proc_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong_new @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong as this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong5 READONLY AS BEGIN insert into t9 select * from @this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong END +storedproc#!#prep#!#db1.this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_proc_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong_new#!#tvp|-|this_tvp_parameter_name_is_very_loooooooooooooooooooooooooooooooooooooooooong|-| |-|../../../utils/tvp-test-dotnet.csv +Select * from t9 + +drop procedure this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_proc_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong +drop procedure this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_proc_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong_new +drop table db1.dbo.t8 +drop table db1.dbo.t9 +drop type this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong.this_tvp_type_name_is_very_loooooooooooooooooooooooooooooooooooooooooong5 +drop schema this_schema_name_is_also_very_loooooooooooooooooooooooooooooooooooooooooong +use master +drop database db1 diff --git a/test/dotnet/utils/tvp-test-dotnet.csv b/test/dotnet/utils/tvp-test-dotnet.csv new file mode 100644 index 0000000000..e795f11e97 --- /dev/null +++ b/test/dotnet/utils/tvp-test-dotnet.csv @@ -0,0 +1,2 @@ +a-int +5