Skip to content

Commit 1d6279b

Browse files
committed
Fix sequence name binding in PDO::lastInsertId
Previous code didn't correctly handle non-ASCII bytes
1 parent 3a8d8ee commit 1d6279b

1 file changed

Lines changed: 17 additions & 9 deletions

File tree

source/pdo_sqlsrv/pdo_dbh.cpp

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ namespace {
3434

3535
const char LAST_INSERT_ID_QUERY[] = "SELECT @@IDENTITY;";
3636
const size_t LAST_INSERT_ID_BUFF_LEN = 50; // size of the buffer to hold the string value of the last inserted id, which may be an int, bigint, decimal(p,0) or numeric(p,0)
37-
const char SEQUENCE_CURRENT_VALUE_QUERY[] = "SELECT current_value FROM sys.sequences WHERE name=N'%s'";
38-
const int LAST_INSERT_ID_QUERY_MAX_LEN = sizeof( SEQUENCE_CURRENT_VALUE_QUERY ) + SQL_MAX_SQLSERVERNAME + 2; // include the quotes
37+
const char SEQUENCE_CURRENT_VALUE_QUERY[] = "SELECT current_value FROM sys.sequences WHERE name=?";
3938

4039
// List of PDO supported connection options.
4140
namespace PDOConnOptionNames {
@@ -1618,6 +1617,8 @@ zend_string * pdo_sqlsrv_dbh_last_id(_Inout_ pdo_dbh_t *dbh, _In_ const zend_str
16181617
char idSTR[LAST_INSERT_ID_BUFF_LEN] = { '\0' };
16191618
char* str = NULL;
16201619
SQLLEN cbID = 0;
1620+
zval name_z;
1621+
ZVAL_UNDEF(&name_z);
16211622

16221623
try {
16231624
sqlsrv_malloc_auto_ptr<SQLWCHAR> wsql_string;
@@ -1626,13 +1627,7 @@ zend_string * pdo_sqlsrv_dbh_last_id(_Inout_ pdo_dbh_t *dbh, _In_ const zend_str
16261627
if (name == NULL) {
16271628
wsql_string = utf16_string_from_mbcs_string(SQLSRV_ENCODING_CHAR, LAST_INSERT_ID_QUERY, sizeof(LAST_INSERT_ID_QUERY), &wsql_len);
16281629
} else {
1629-
char buffer[LAST_INSERT_ID_QUERY_MAX_LEN] = { '\0' };
1630-
#if PHP_VERSION_ID < 80100
1631-
snprintf(buffer, LAST_INSERT_ID_QUERY_MAX_LEN, SEQUENCE_CURRENT_VALUE_QUERY, name);
1632-
#else
1633-
snprintf(buffer, LAST_INSERT_ID_QUERY_MAX_LEN, SEQUENCE_CURRENT_VALUE_QUERY, ZSTR_VAL(name));
1634-
#endif
1635-
wsql_string = utf16_string_from_mbcs_string(SQLSRV_ENCODING_CHAR, buffer, sizeof(buffer), &wsql_len);
1630+
wsql_string = utf16_string_from_mbcs_string(SQLSRV_ENCODING_CHAR, SEQUENCE_CURRENT_VALUE_QUERY, sizeof(SEQUENCE_CURRENT_VALUE_QUERY), &wsql_len);
16361631
}
16371632
CHECK_CUSTOM_ERROR(wsql_string == 0, driver_stmt, SQLSRV_ERROR_QUERY_STRING_ENCODING_TRANSLATE, get_last_error_message(), NULL) {
16381633
throw core::CoreException();
@@ -1646,6 +1641,17 @@ zend_string * pdo_sqlsrv_dbh_last_id(_Inout_ pdo_dbh_t *dbh, _In_ const zend_str
16461641
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 );
16471642
driver_stmt->set_func( __FUNCTION__ );
16481643

1644+
// Bind the sequence name using a character parameter with the application-defined encoding
1645+
if (name != NULL) {
1646+
#if PHP_VERSION_ID < 80100
1647+
ZVAL_STRING(&name_z, name);
1648+
#else
1649+
ZVAL_STRINGL(&name_z, ZSTR_VAL(name), ZSTR_LEN(name));
1650+
#endif
1651+
core_sqlsrv_bind_param( driver_stmt, 0 /*param_num*/, SQL_PARAM_INPUT, &name_z, SQLSRV_PHPTYPE_INVALID,
1652+
driver_dbh->encoding(), SQL_UNKNOWN_TYPE, SQLSRV_UNKNOWN_SIZE, 0 );
1653+
}
1654+
16491655
// execute the last insert id query
16501656
core::SQLExecDirectW( driver_stmt, wsql_string );
16511657
core::SQLFetchScroll( driver_stmt, SQL_FETCH_NEXT, 0 );
@@ -1657,6 +1663,7 @@ zend_string * pdo_sqlsrv_dbh_last_id(_Inout_ pdo_dbh_t *dbh, _In_ const zend_str
16571663
}
16581664

16591665
driver_stmt->~sqlsrv_stmt();
1666+
zval_ptr_dtor(&name_z);
16601667
} catch( core::CoreException& ) {
16611668
// restore error handling to its previous mode
16621669
dbh->error_mode = static_cast<decltype(dbh->error_mode)>(prev_err_mode);
@@ -1670,6 +1677,7 @@ zend_string * pdo_sqlsrv_dbh_last_id(_Inout_ pdo_dbh_t *dbh, _In_ const zend_str
16701677
if( driver_stmt ) {
16711678
driver_stmt->~sqlsrv_stmt();
16721679
}
1680+
zval_ptr_dtor(&name_z);
16731681
#if PHP_VERSION_ID < 80100
16741682
*len = 0;
16751683
str = reinterpret_cast<char*>(sqlsrv_malloc(0, sizeof(char), 1)); // return an empty string with a null terminator

0 commit comments

Comments
 (0)