Simplified pdo quote and lastinsertid implementation further (#1254)

This commit is contained in:
Jenny Tam 2021-05-05 18:21:16 -07:00 committed by GitHub
parent 7fad440fa1
commit e57d5aab46
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 45 additions and 54 deletions

View file

@ -1365,13 +1365,18 @@ char * pdo_sqlsrv_dbh_last_id( _Inout_ pdo_dbh_t *dbh, _In_z_ const char *name,
SQLLEN cbID = 0;
try {
sqlsrv_malloc_auto_ptr<SQLWCHAR> wsql_string;
unsigned int wsql_len;
char last_insert_id_query[LAST_INSERT_ID_QUERY_MAX_LEN] = {'\0'};
if( name == NULL ) {
strcpy_s(last_insert_id_query, sizeof(last_insert_id_query), LAST_INSERT_ID_QUERY);
if (name == NULL) {
wsql_string = utf16_string_from_mbcs_string(SQLSRV_ENCODING_CHAR, LAST_INSERT_ID_QUERY, sizeof(LAST_INSERT_ID_QUERY), &wsql_len);
} else {
char buffer[LAST_INSERT_ID_QUERY_MAX_LEN] = { '\0' };
snprintf(buffer, LAST_INSERT_ID_QUERY_MAX_LEN, SEQUENCE_CURRENT_VALUE_QUERY, name);
wsql_string = utf16_string_from_mbcs_string(SQLSRV_ENCODING_CHAR, buffer, sizeof(buffer), &wsql_len);
}
else {
snprintf(last_insert_id_query, LAST_INSERT_ID_QUERY_MAX_LEN, SEQUENCE_CURRENT_VALUE_QUERY, name);
CHECK_CUSTOM_ERROR(wsql_string == 0, driver_stmt, SQLSRV_ERROR_QUERY_STRING_ENCODING_TRANSLATE, get_last_error_message()) {
throw core::CoreException();
}
// temp PDO statement used for error handling if something happens
@ -1382,16 +1387,7 @@ char * pdo_sqlsrv_dbh_last_id( _Inout_ pdo_dbh_t *dbh, _In_z_ const char *name,
driver_stmt = core_sqlsrv_create_stmt( driver_dbh, core::allocate_stmt<pdo_sqlsrv_stmt>, NULL /*options_ht*/, NULL /*valid_stmt_opts*/, pdo_sqlsrv_handle_stmt_error, &temp_stmt );
driver_stmt->set_func( __FUNCTION__ );
sqlsrv_malloc_auto_ptr<SQLWCHAR> wsql_string;
unsigned int wsql_len;
wsql_string = utf16_string_from_mbcs_string( SQLSRV_ENCODING_CHAR, reinterpret_cast<const char*>( last_insert_id_query ), sizeof(last_insert_id_query), &wsql_len );
CHECK_CUSTOM_ERROR( wsql_string == 0, driver_stmt, SQLSRV_ERROR_QUERY_STRING_ENCODING_TRANSLATE, get_last_error_message() ) {
throw core::CoreException();
}
// execute the last insert id query
// execute the last insert id query
core::SQLExecDirectW( driver_stmt, wsql_string );
core::SQLFetchScroll( driver_stmt, SQL_FETCH_NEXT, 0 );
@ -1402,8 +1398,7 @@ char * pdo_sqlsrv_dbh_last_id( _Inout_ pdo_dbh_t *dbh, _In_z_ const char *name,
}
driver_stmt->~sqlsrv_stmt();
}
catch( core::CoreException& ) {
} catch( core::CoreException& ) {
// copy any errors on the statement to the connection so that the user sees them, since the statement is released
// before this method returns
strcpy_s( dbh->error_code, sizeof( dbh->error_code ),
@ -1542,43 +1537,31 @@ int pdo_sqlsrv_dbh_quote( _Inout_ pdo_dbh_t* dbh, _In_reads_(unquoted_len) const
return 1;
}
else {
// count the number of quotes needed
unsigned int quotes_needed = 2; // the initial start and end quotes of course
// include the N proceeding the initial quote if encoding is UTF8
if (use_national_char_set) {
quotes_needed = 3;
// The minimum number of single quotes needed is 2 -- the initial start and end quotes
// Add the letter N before the initial quote if the encoding is UTF8
int quotes_needed = (use_national_char_set) ? 3 : 2;
char c = '\'';
std::string tmp_str(unquoted, unquoted_len); // Copy all unquoted_len characters from unquoted
std::size_t found = tmp_str.find(c); // Find the first single quote
while (found != std::string::npos) {
tmp_str.insert(found + 1, 1, c); // Insert an additional single quote
found = tmp_str.find(c, found + 2); // Find the next single quote
}
for ( size_t index = 0; index < unquoted_len; ++index ) {
if ( unquoted[index] == '\'' ) {
++quotes_needed;
}
size_t len = tmp_str.length();
*quoted_len = quotes_needed + len; // The new length should be number of quotes plus the length of tmp_str
*quoted = reinterpret_cast<char*>(sqlsrv_malloc(*quoted_len, sizeof(char), 1)); // include space for null terminator
memset(*quoted, '\0', *quoted_len + 1);
char *p = *quoted;
size_t pos = 0;
if (use_national_char_set) { // Insert the letter N if the encoding is UTF8
*(p + (pos++)) = 'N';
}
*quoted_len = unquoted_len + quotes_needed; // length returned to the caller should not account for null terminator.
*quoted = reinterpret_cast<char*>( sqlsrv_malloc( *quoted_len, sizeof( char ), 1 )); // include space for null terminator.
unsigned int out_current = 0;
// insert N if the encoding is UTF8
if (use_national_char_set) {
( *quoted )[out_current++] = 'N';
}
// insert initial quote
( *quoted )[out_current++] = '\'';
for ( size_t index = 0; index < unquoted_len; ++index ) {
if ( unquoted[index] == '\'' ) {
( *quoted )[out_current++] = '\'';
( *quoted )[out_current++] = '\'';
}
else {
( *quoted )[out_current++] = unquoted[index];
}
}
// trailing quote and null terminator
( *quoted )[out_current++] = '\'';
( *quoted )[out_current] = '\0';
*(p + (pos++)) = c; // Add the initial quote
tmp_str.copy(p + pos, len, 0); // Copy tmp_str to *quoted
pos += len;
*(p + pos) = c; // Add the end quote
return 1;
}
}

View file

@ -10,8 +10,8 @@ try {
$cnn = connect();
$pdo_options = array();
if (!isColEncrypted()) {
// Emulate prepare and direct query are not supported with Always Encrypted
if (!isAEConnected()) {
// Emulate prepare and direct query not supported when connected with Always Encrypted
$pdo_options[PDO::ATTR_EMULATE_PREPARES] = TRUE;
$pdo_options[PDO::SQLSRV_ATTR_DIRECT_QUERY] = TRUE;
}

View file

@ -15,6 +15,12 @@ try {
print("Original: " . str_replace("\0", "{NUL}", $str) . "\n");
$str = $connection->quote($str);
print("Quoted: " . str_replace("\0", "{NUL}", $str) . "\n");
$str1 = "X'X\0'XX";
print("Original: " . str_replace("\0", "{NUL}", $str1) . "\n");
$str1 = $connection->quote($str1);
print("Quoted: " . str_replace("\0", "{NUL}", $str1) . "\n");
} catch (PDOException $e) {
die("Connection error: " . $e->getMessage());
}
@ -22,3 +28,5 @@ try {
--EXPECT--
Original: XX{NUL}XX
Quoted: 'XX{NUL}XX'
Original: X'X{NUL}'XX
Quoted: 'X''X{NUL}''XX'