Skip to content

Commit a14cb70

Browse files
authored
Changed how schema is provided for TVP input (#1264)
1 parent b49cb51 commit a14cb70

File tree

6 files changed

+49
-57
lines changed

6 files changed

+49
-57
lines changed

source/shared/core_sqlsrv.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1514,7 +1514,7 @@ struct sqlsrv_param_tvp : public sqlsrv_param
15141514

15151515
// The following methods are only applicable to a table-valued parameter or its individual columns
15161516
int parse_tv_param_arrays(_Inout_ sqlsrv_stmt* stmt, _Inout_ zval* param_z);
1517-
void get_tvp_metadata(_In_ sqlsrv_stmt* stmt, _In_ SQLCHAR* table_type_name);
1517+
void get_tvp_metadata(_In_ sqlsrv_stmt* stmt, _In_ zend_string* table_type_name, _In_ zend_string* schema_name);
15181518
void process_param_column_value(_Inout_ sqlsrv_stmt* stmt);
15191519
void process_null_param_value(_Inout_ sqlsrv_stmt* stmt);
15201520
void populate_cell_placeholder(_Inout_ sqlsrv_stmt* stmt, _In_ int ordinal);

source/shared/core_stmt.cpp

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3084,13 +3084,14 @@ void sqlsrv_param_inout::resize_output_string_buffer(_Inout_ zval* param_z, _In_
30843084
}
30853085
}
30863086

3087-
void sqlsrv_param_tvp::get_tvp_metadata(_In_ sqlsrv_stmt* stmt, _In_ SQLCHAR* table_type_name)
3087+
void sqlsrv_param_tvp::get_tvp_metadata(_In_ sqlsrv_stmt* stmt, _In_ zend_string* table_type_name, _In_ zend_string* schema_name)
30883088
{
30893089
SQLHANDLE chstmt = SQL_NULL_HANDLE;
30903090
SQLRETURN rc;
30913091
SQLSMALLINT data_type, dec_digits;
30923092
SQLINTEGER col_size;
30933093
SQLLEN cb_data_type, cb_col_size, cb_dec_digits;
3094+
char* table_type = ZSTR_VAL(table_type_name);
30943095

30953096
core::SQLAllocHandle(SQL_HANDLE_STMT, *(stmt->conn), &chstmt);
30963097

@@ -3100,21 +3101,11 @@ void sqlsrv_param_tvp::get_tvp_metadata(_In_ sqlsrv_stmt* stmt, _In_ SQLCHAR* ta
31003101
}
31013102

31023103
// Check table type name and see if the schema is specified. Otherwise, assume DBO
3103-
std::string type_name(reinterpret_cast<char *>(table_type_name));
3104-
std::size_t pos = type_name.find_first_of(".");
3105-
if (pos != std::string::npos) {
3106-
std::string str1 = type_name.substr(0, pos);
3107-
std::string str2 = type_name.substr(pos + 1);
3108-
3109-
char schema[SS_MAXCOLNAMELEN] = { '\0' };
3110-
char type[SS_MAXCOLNAMELEN] = { '\0' };
3111-
3112-
strcpy_s(schema, SS_MAXCOLNAMELEN, str1.c_str());
3113-
strcpy_s(type, SS_MAXCOLNAMELEN, str2.c_str());
3114-
3115-
rc = SQLColumns(chstmt, NULL, 0, reinterpret_cast<SQLCHAR *>(schema), SQL_NTS, reinterpret_cast<SQLCHAR *>(type), SQL_NTS, NULL, 0);
3104+
if (schema_name != NULL) {
3105+
char* schema = ZSTR_VAL(schema_name);
3106+
rc = SQLColumns(chstmt, NULL, 0, reinterpret_cast<SQLCHAR*>(schema), SQL_NTS, reinterpret_cast<SQLCHAR*>(table_type), SQL_NTS, NULL, 0);
31163107
} else {
3117-
rc = SQLColumns(chstmt, NULL, 0, NULL, 0, table_type_name, SQL_NTS, NULL, 0);
3108+
rc = SQLColumns(chstmt, NULL, 0, NULL, SQL_NTS, reinterpret_cast<SQLCHAR*>(table_type), SQL_NTS, NULL, 0);
31183109
}
31193110

31203111
CHECK_CUSTOM_ERROR(!SQL_SUCCEEDED(rc), stmt, SQLSRV_ERROR_TVP_FETCH_METADATA, param_pos + 1) {
@@ -3208,6 +3199,7 @@ int sqlsrv_param_tvp::parse_tv_param_arrays(_Inout_ sqlsrv_stmt* stmt, _Inout_ z
32083199
// The number of columns in the given table-valued parameter is returned, which may be zero.
32093200
HashTable* inputs_ht = Z_ARRVAL_P(param_z);
32103201
zend_string *tvp_name = NULL;
3202+
zend_string *schema_name = NULL;
32113203
zval *tvp_data_z = NULL;
32123204
HashPosition pos;
32133205

@@ -3227,12 +3219,20 @@ int sqlsrv_param_tvp::parse_tv_param_arrays(_Inout_ sqlsrv_stmt* stmt, _Inout_ z
32273219
throw core::CoreException();
32283220
}
32293221
}
3230-
3222+
32313223
// TODO: Find the docs page somewhere that says a TVP can not be null but it may have null columns??
32323224
CHECK_CUSTOM_ERROR(tvp_data_z == NULL || Z_TYPE_P(tvp_data_z) == IS_NULL || Z_TYPE_P(tvp_data_z) != IS_ARRAY, stmt, SQLSRV_ERROR_TVP_INVALID_INPUTS, param_pos + 1) {
32333225
throw core::CoreException();
32343226
}
32353227

3228+
// Check if schema is provided by the user
3229+
if (zend_hash_move_forward_ex(inputs_ht, &pos) == SUCCESS) {
3230+
zval *schema_z = zend_hash_get_current_data_ex(inputs_ht, &pos);
3231+
if (schema_z != NULL && Z_TYPE_P(schema_z) == IS_STRING) {
3232+
schema_name = Z_STR_P(schema_z);
3233+
}
3234+
}
3235+
32363236
// Save the TVP multi-dim array data, which should be something like this
32373237
// [
32383238
// [r1c1, r1c2, r1c3],
@@ -3249,7 +3249,7 @@ int sqlsrv_param_tvp::parse_tv_param_arrays(_Inout_ sqlsrv_stmt* stmt, _Inout_ z
32493249

32503250
// Given the table type name, get its column meta data next
32513251
size_t total_num_columns = 0;
3252-
get_tvp_metadata(stmt, reinterpret_cast<SQLCHAR*>(ZSTR_VAL(tvp_name)));
3252+
get_tvp_metadata(stmt, tvp_name, schema_name);
32533253
total_num_columns = tvp_columns.size();
32543254

32553255
// (1) Is the array empty?

test/functional/pdo_sqlsrv/pdo_test_TVP_double_tvps.phpt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,11 @@ try {
6868
['klmop', 45678, '2007-04-08 06:15:15.333'],
6969
];
7070

71-
$tvpType1 = "$schema.SupplierType";
72-
$tvpType2 = "$schema.TestTVP3";
71+
$tvpType1 = "SupplierType";
72+
$tvpType2 = "TestTVP3";
7373

74-
$tvpInput1 = array($tvpType1 => $inputs1);
75-
$tvpInput2 = array($tvpType2 => $inputs2);
74+
$tvpInput1 = array($tvpType1 => $inputs1, $schema);
75+
$tvpInput2 = array($tvpType2 => $inputs2, $schema);
7676

7777
$image = fopen($tvpIncPath. 'superlight_black_f_large.gif', 'rb');
7878

test/functional/pdo_sqlsrv/pdo_test_TVP_error_cases.phpt

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,10 @@ try {
6363

6464
// Use a different schema instead of dbo
6565
$schema = 'Sales DB';
66-
$tvpType = 'TestTVP3';
66+
$tvpTypeName = 'TestTVP3';
6767
$procName = 'SelectTVP3';
6868

69-
cleanup($conn, $schema, $tvpType, $procName, $pre2016);
69+
cleanup($conn, $schema, $tvpTypeName, $procName, $pre2016);
7070

7171
// Create the table type and stored procedure
7272
$conn->exec($createSchema);
@@ -89,9 +89,6 @@ try {
8989
$tvpInput = array("" => array());
9090
invokeProc($conn, $callSelectTVP3, $tvpInput, 2);
9191

92-
// The TVP name should include the schema
93-
$tvpTypeName = "$schema.$tvpType";
94-
9592
// Case (3) - null inputs
9693
$tvpInput = array($tvpTypeName => null);
9794
invokeProc($conn, $callSelectTVP3, $tvpInput, 3);
@@ -105,37 +102,37 @@ try {
105102
invokeProc($conn, $callSelectTVP3, $tvpInput, 5);
106103

107104
// Case (6) - input rows are not the same size
108-
$tvpInput = array($tvpTypeName => $inputs);
105+
$tvpInput = array($tvpTypeName => $inputs, $schema);
109106
invokeProc($conn, $callSelectTVP3, $tvpInput, 6);
110107

111108
// Case (7) - input row wrong size
112109
unset($inputs);
113110
$inputs = [
114111
['ABC', 12345, null, null]
115112
];
116-
$tvpInput = array($tvpTypeName => $inputs);
113+
$tvpInput = array($tvpTypeName => $inputs, $schema);
117114
invokeProc($conn, $callSelectTVP3, $tvpInput, 7);
118115

119116
// Case (8) - use string keys
120117
unset($inputs);
121118
$inputs = [
122119
['A' => null, null, null]
123120
];
124-
$tvpInput = array($tvpTypeName => $inputs);
121+
$tvpInput = array($tvpTypeName => $inputs, $schema);
125122
invokeProc($conn, $callSelectTVP3, $tvpInput, 8);
126123

127124
// Case (9) - a row is not an array
128125
unset($inputs);
129126
$inputs = [null];
130-
$tvpInput = array($tvpTypeName => $inputs);
127+
$tvpInput = array($tvpTypeName => $inputs, $schema);
131128
invokeProc($conn, $callSelectTVP3, $tvpInput, 9);
132129

133130
// Case (10) - a column value used a string key
134131
unset($inputs);
135132
$inputs = [
136133
['ABC', 12345, "key"=>null]
137134
];
138-
$tvpInput = array($tvpTypeName => $inputs);
135+
$tvpInput = array($tvpTypeName => $inputs, $schema);
139136
invokeProc($conn, $callSelectTVP3, $tvpInput, 10);
140137

141138
// Case (11) - invalid input object for a TVP column
@@ -149,7 +146,7 @@ try {
149146
['ABC', 1234, $bar],
150147
['DEF', 6789, null],
151148
];
152-
$tvpInput = array($tvpTypeName => $inputs);
149+
$tvpInput = array($tvpTypeName => $inputs, $schema);
153150
invokeProc($conn, $callSelectTVP3, $tvpInput, 11);
154151

155152
// Case (12) - invalid input type for a TVP column
@@ -158,7 +155,7 @@ try {
158155
['ABC', &$str, null],
159156
['DEF', 6789, null],
160157
];
161-
$tvpInput = array($tvpTypeName => $inputs);
158+
$tvpInput = array($tvpTypeName => $inputs, $schema);
162159
invokeProc($conn, $callSelectTVP3, $tvpInput, 12);
163160

164161
// Case (13) - bind a TVP as an OUTPUT param
@@ -175,10 +172,10 @@ try {
175172
[$utf8, 1234, null],
176173
['DEF', 6789, null],
177174
];
178-
$tvpInput = array($tvpTypeName => $inputs);
175+
$tvpInput = array($tvpTypeName => $inputs, $schema);
179176
invokeProc($conn, $callSelectTVP3, $tvpInput, 14);
180177

181-
cleanup($conn, $schema, $tvpType, $procName, $pre2016);
178+
cleanup($conn, $schema, $tvpTypeName, $procName, $pre2016);
182179

183180
unset($conn);
184181
echo "Done" . PHP_EOL;

test/functional/sqlsrv/sqlsrv_test_TVP_double_tvps.phpt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,11 @@ $inputs2 = [
6666
['KLMOP', 45678, '2007-04-08 06:15:15.333'],
6767
];
6868

69-
$tvpType1 = "$schema.SupplierType";
70-
$tvpType2 = "$schema.TestTVP3";
69+
$tvpType1 = "SupplierType";
70+
$tvpType2 = "TestTVP3";
7171

72-
$tvpInput1 = array($tvpType1 => $inputs1);
73-
$tvpInput2 = array($tvpType2 => $inputs2);
72+
$tvpInput1 = array($tvpType1 => $inputs1, $schema);
73+
$tvpInput2 = array($tvpType2 => $inputs2, $schema);
7474

7575
$image = fopen($tvpIncPath. 'awc_tee_male_large.gif', 'rb');
7676

test/functional/sqlsrv/sqlsrv_test_TVP_error_cases.phpt

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,10 @@ function invokeProc($conn, $proc, $tvpInput, $caseNo, $dir = SQLSRV_PARAM_IN)
1818

1919
$stmt = sqlsrv_query($conn, $proc, $params);
2020
if (!$stmt) {
21-
// $errors = sqlsrv_errors(SQLSRV_ERR_ALL);
22-
$errors = sqlsrv_errors();
21+
$errors = sqlsrv_errors(SQLSRV_ERR_ALL);
2322
if (!empty($errors)) {
2423
$count = count($errors);
2524
}
26-
$count = 1;
2725
for ($i = 0; $i < $count; $i++) {
2826
echo "Error $caseNo: ";
2927
echo $errors[$i]['message'] . PHP_EOL;
@@ -56,7 +54,7 @@ $conn = connect(array('CharacterSet'=>'UTF-8'));
5654

5755
// Use a different schema instead of dbo
5856
$schema = 'Sales DB';
59-
$tvpType = 'TestTVP3';
57+
$tvpTypeName = 'TestTVP3';
6058
$procName = 'SelectTVP3';
6159

6260
$stmt = sqlsrv_query($conn, "SELECT @@VERSION");
@@ -66,7 +64,7 @@ if (sqlsrv_fetch($stmt)) {
6664
$version = explode(' ', $result);
6765
$pre2016 = ($version[3] < '2016');
6866

69-
cleanup($conn, $schema, $tvpType, $procName, $pre2016);
67+
cleanup($conn, $schema, $tvpTypeName, $procName, $pre2016);
7068

7169
// Create table type and a stored procedure
7270
sqlsrv_query($conn, $createSchema);
@@ -89,9 +87,6 @@ invokeProc($conn, $callSelectTVP3, $tvpInput, 1);
8987
$tvpInput = array("" => array());
9088
invokeProc($conn, $callSelectTVP3, $tvpInput, 2);
9189

92-
// The TVP name should include the schema
93-
$tvpTypeName = "$schema.$tvpType";
94-
9590
// Case (3) - null inputs
9691
$tvpInput = array($tvpTypeName => null);
9792
invokeProc($conn, $callSelectTVP3, $tvpInput, 3);
@@ -105,37 +100,37 @@ $tvpInput = array($str => $inputs);
105100
invokeProc($conn, $callSelectTVP3, $tvpInput, 5);
106101

107102
// Case (6) - input rows are not the same size
108-
$tvpInput = array($tvpTypeName => $inputs);
103+
$tvpInput = array($tvpTypeName => $inputs, $schema);
109104
invokeProc($conn, $callSelectTVP3, $tvpInput, 6);
110105

111106
// Case (7) - input row wrong size
112107
unset($inputs);
113108
$inputs = [
114109
['ABC', 12345, null, null]
115110
];
116-
$tvpInput = array($tvpTypeName => $inputs);
111+
$tvpInput = array($tvpTypeName => $inputs, $schema);
117112
invokeProc($conn, $callSelectTVP3, $tvpInput, 7);
118113

119114
// Case (8) - use string keys
120115
unset($inputs);
121116
$inputs = [
122117
['A' => null, null, null]
123118
];
124-
$tvpInput = array($tvpTypeName => $inputs);
119+
$tvpInput = array($tvpTypeName => $inputs, $schema);
125120
invokeProc($conn, $callSelectTVP3, $tvpInput, 8);
126121

127122
// Case (9) - a row is not an array
128123
unset($inputs);
129124
$inputs = [null];
130-
$tvpInput = array($tvpTypeName => $inputs);
125+
$tvpInput = array($tvpTypeName => $inputs, $schema);
131126
invokeProc($conn, $callSelectTVP3, $tvpInput, 9);
132127

133128
// Case (10) - a column value used a string key
134129
unset($inputs);
135130
$inputs = [
136131
['ABC', 12345, "key"=>null]
137132
];
138-
$tvpInput = array($tvpTypeName => $inputs);
133+
$tvpInput = array($tvpTypeName => $inputs, $schema);
139134
invokeProc($conn, $callSelectTVP3, $tvpInput, 10);
140135

141136
// Case (11) - invalid input object for a TVP column
@@ -149,7 +144,7 @@ $inputs = [
149144
['ABC', 1234, $bar],
150145
['DEF', 6789, null],
151146
];
152-
$tvpInput = array($tvpTypeName => $inputs);
147+
$tvpInput = array($tvpTypeName => $inputs, $schema);
153148
invokeProc($conn, $callSelectTVP3, $tvpInput, 11);
154149

155150
// Case (12) - invalid input type for a TVP column
@@ -158,7 +153,7 @@ $inputs = [
158153
['ABC', &$str, null],
159154
['DEF', 6789, null],
160155
];
161-
$tvpInput = array($tvpTypeName => $inputs);
156+
$tvpInput = array($tvpTypeName => $inputs, $schema);
162157
invokeProc($conn, $callSelectTVP3, $tvpInput, 12);
163158

164159
// Case (13) - bind a TVP as an OUTPUT param
@@ -175,10 +170,10 @@ $inputs = [
175170
[$utf8, 1234, null],
176171
['DEF', 6789, null],
177172
];
178-
$tvpInput = array($tvpTypeName => $inputs);
173+
$tvpInput = array($tvpTypeName => $inputs, $schema);
179174
invokeProc($conn, $callSelectTVP3, $tvpInput, 14);
180175

181-
cleanup($conn, $schema, $tvpType, $procName, $pre2016);
176+
cleanup($conn, $schema, $tvpTypeName, $procName, $pre2016);
182177

183178
sqlsrv_close($conn);
184179

0 commit comments

Comments
 (0)