Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix #173, #138 on Windows code #237

Merged
merged 3 commits into from
Jan 18, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 8 additions & 9 deletions source/pdo_sqlsrv/pdo_stmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,7 @@ int pdo_sqlsrv_stmt_get_col_data(pdo_stmt_t *stmt, int colno,
"Invalid column number in pdo_sqlsrv_stmt_get_col_data" );
sqlsrv_php_type = driver_stmt->sql_type_to_php_type( static_cast<SQLUINTEGER>( driver_stmt->current_meta_data[ colno ]->field_type ),
static_cast<SQLUINTEGER>( driver_stmt->current_meta_data[ colno ]->field_size ),
true, driver_stmt->fetch_numeric );
true );

// set the encoding if the user specified one via bindColumn, otherwise use the statement's encoding
sqlsrv_php_type.typeinfo.encoding = driver_stmt->encoding();
Expand Down Expand Up @@ -787,8 +787,7 @@ int pdo_sqlsrv_stmt_set_attr(pdo_stmt_t *stmt, zend_long attr, zval *val TSRMLS_
PDO_VALIDATE_STMT;
PDO_LOG_STMT_ENTRY;

pdo_sqlsrv_stmt* pdo_stmt = static_cast<pdo_sqlsrv_stmt*>( stmt->driver_data );
sqlsrv_stmt* driver_stmt = static_cast<sqlsrv_stmt*>( stmt->driver_data );
pdo_sqlsrv_stmt* driver_stmt = static_cast<pdo_sqlsrv_stmt*>( stmt->driver_data );

try {

Expand Down Expand Up @@ -818,9 +817,9 @@ int pdo_sqlsrv_stmt_set_attr(pdo_stmt_t *stmt, zend_long attr, zval *val TSRMLS_
core_sqlsrv_set_buffered_query_limit( driver_stmt, val TSRMLS_CC );
break;

case SQLSRV_ATTR_FETCHES_NUMERIC_TYPE:
pdo_stmt->fetch_numeric = ( zend_is_true( val )) ? true : false;
break;
case SQLSRV_ATTR_FETCHES_NUMERIC_TYPE:
driver_stmt->fetch_numeric = ( zend_is_true( val )) ? true : false;
break;

default:
THROW_PDO_ERROR( driver_stmt, PDO_SQLSRV_ERROR_INVALID_STMT_ATTR );
Expand Down Expand Up @@ -1270,7 +1269,7 @@ int pdo_sqlsrv_stmt_param_hook(pdo_stmt_t *stmt,


// Returns a sqlsrv_phptype for a given SQL Server data type.
sqlsrv_phptype pdo_sqlsrv_stmt::sql_type_to_php_type( SQLINTEGER sql_type, SQLUINTEGER size, bool prefer_string_over_stream, bool prefer_number_to_string )
sqlsrv_phptype pdo_sqlsrv_stmt::sql_type_to_php_type( SQLINTEGER sql_type, SQLUINTEGER size, bool prefer_string_over_stream )
{
sqlsrv_phptype sqlsrv_phptype;
int local_encoding = this->encoding();
Expand All @@ -1286,7 +1285,7 @@ sqlsrv_phptype pdo_sqlsrv_stmt::sql_type_to_php_type( SQLINTEGER sql_type, SQLUI
case SQL_INTEGER:
case SQL_SMALLINT:
case SQL_TINYINT:
if ( prefer_number_to_string ) {
if ( this->fetch_numeric ) {
sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_INT;
}
else {
Expand All @@ -1296,7 +1295,7 @@ sqlsrv_phptype pdo_sqlsrv_stmt::sql_type_to_php_type( SQLINTEGER sql_type, SQLUI
break;
case SQL_FLOAT:
case SQL_REAL:
if ( prefer_number_to_string ) {
if ( this->fetch_numeric ) {
sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_FLOAT;
}
else {
Expand Down
5 changes: 3 additions & 2 deletions source/pdo_sqlsrv/pdo_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ pdo_error PDO_ERRORS[] = {

{
SQLSRV_ERROR_DRIVER_NOT_INSTALLED,
{ IMSSP, (SQLCHAR*) "This extension requires the Microsoft ODBC Driver 11 or 13 for SQL Server. "
"Access the following URL to download the ODBC Driver 11 or 13 for SQL Server for %1!s!: "
{ IMSSP, (SQLCHAR*) "This extension requires the Microsoft ODBC Driver 11 or 13 for SQL Server to "
"communicate with SQL Server. Access the following URL to download the ODBC Driver 11 or 13 for SQL Server "
"for %1!s!: "
"http://go.microsoft.com/fwlink/?LinkId=163712", -1, true }
},
{
Expand Down
2 changes: 1 addition & 1 deletion source/pdo_sqlsrv/php_pdo_sqlsrv.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ struct pdo_sqlsrv_stmt : public sqlsrv_stmt {

// driver specific conversion rules from a SQL Server/ODBC type to one of the SQLSRV_PHPTYPE_* constants
// for PDO, everything is a string, so we return SQLSRV_PHPTYPE_STRING for all SQL types
virtual sqlsrv_phptype sql_type_to_php_type( SQLINTEGER sql_type, SQLUINTEGER size, bool prefer_string_to_stream, bool prefer_number_to_string );
virtual sqlsrv_phptype sql_type_to_php_type( SQLINTEGER sql_type, SQLUINTEGER size, bool prefer_string_to_stream );

bool direct_query; // flag set if the query should be executed directly or prepared
const char* direct_query_subst_string; // if the query is direct, hold the substitution string if using named parameters
Expand Down
29 changes: 26 additions & 3 deletions source/shared/core_sqlsrv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1276,7 +1276,7 @@ struct sqlsrv_stmt : public sqlsrv_context {
virtual ~sqlsrv_stmt( void );

// driver specific conversion rules from a SQL Server/ODBC type to one of the SQLSRV_PHPTYPE_* constants
virtual sqlsrv_phptype sql_type_to_php_type( SQLINTEGER sql_type, SQLUINTEGER size, bool prefer_string_to_stream, bool prefer_number_to_string = false ) = 0;
virtual sqlsrv_phptype sql_type_to_php_type( SQLINTEGER sql_type, SQLUINTEGER size, bool prefer_string_to_stream ) = 0;

};

Expand Down Expand Up @@ -1817,8 +1817,8 @@ namespace core {


inline void SQLColAttribute( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, SQLUSMALLINT field_identifier,
_Out_ SQLPOINTER field_type_char, SQLSMALLINT buffer_length,
_Out_ SQLSMALLINT* out_buffer_length, _Out_ SQLLEN* field_type_num TSRMLS_DC )
_Out_ SQLPOINTER field_type_char, SQLSMALLINT buffer_length,
_Out_ SQLSMALLINT* out_buffer_length, _Out_ SQLLEN* field_type_num TSRMLS_DC )
{
SQLRETURN r = ::SQLColAttribute( stmt->handle(), field_index, field_identifier, field_type_char,
buffer_length, out_buffer_length, field_type_num );
Expand All @@ -1828,6 +1828,17 @@ namespace core {
}
}

inline void SQLColAttributeW( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, SQLUSMALLINT field_identifier,
_Out_ SQLPOINTER field_type_char, SQLSMALLINT buffer_length,
_Out_ SQLSMALLINT* out_buffer_length, _Out_ SQLLEN* field_type_num TSRMLS_DC )
{
SQLRETURN r = ::SQLColAttributeW( stmt->handle(), field_index, field_identifier, field_type_char,
buffer_length, out_buffer_length, field_type_num );

CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
throw CoreException();
}
}

inline void SQLDescribeCol( sqlsrv_stmt* stmt, SQLSMALLINT colno, _Out_ SQLCHAR* col_name, SQLSMALLINT col_name_length,
_Out_ SQLSMALLINT* col_name_length_out, SQLSMALLINT* data_type, _Out_ SQLULEN* col_size,
Expand All @@ -1842,6 +1853,18 @@ namespace core {
}
}

inline void SQLDescribeColW( sqlsrv_stmt* stmt, SQLSMALLINT colno, _Out_ SQLWCHAR* col_name, SQLSMALLINT col_name_length,
_Out_ SQLSMALLINT* col_name_length_out, SQLSMALLINT* data_type, _Out_ SQLULEN* col_size,
_Out_ SQLSMALLINT* decimal_digits, _Out_ SQLSMALLINT* nullable TSRMLS_DC )
{
SQLRETURN r;
r = ::SQLDescribeColW( stmt->handle(), colno, col_name, col_name_length, col_name_length_out,
data_type, col_size, decimal_digits, nullable );

CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
throw CoreException();
}
}

inline void SQLEndTran( SQLSMALLINT handleType, sqlsrv_conn* conn, SQLSMALLINT completionType TSRMLS_DC )
{
Expand Down
28 changes: 18 additions & 10 deletions source/shared/core_stmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -809,18 +809,26 @@ field_meta_data* core_sqlsrv_field_metadata( sqlsrv_stmt* stmt, SQLSMALLINT coln
SQLSRV_ASSERT( colno >= 0, "core_sqlsrv_field_metadata: Invalid column number provided." );

sqlsrv_malloc_auto_ptr<field_meta_data> meta_data;
SQLSMALLINT field_name_len = 0;

sqlsrv_malloc_auto_ptr<SQLWCHAR> field_name_temp;
SQLSMALLINT field_len_temp = 0;
SQLLEN field_name_len = 0;

meta_data = new ( sqlsrv_malloc( sizeof( field_meta_data ))) field_meta_data();
meta_data->field_name = static_cast<SQLCHAR*>( sqlsrv_malloc( SS_MAXCOLNAMELEN + 1 ));
field_name_temp = static_cast<SQLWCHAR*>( sqlsrv_malloc( SS_MAXCOLNAMELEN * 2 + 1 ));
SQLSRV_ENCODING encoding = ( (stmt->encoding() == SQLSRV_ENCODING_DEFAULT ) ? stmt->conn->encoding() : stmt->encoding());
try{
core::SQLDescribeColW( stmt, colno + 1, field_name_temp, SS_MAXCOLNAMELEN * 2 + 1 , &field_len_temp,
&( meta_data->field_type ), & ( meta_data->field_size ), & ( meta_data->field_scale ),
&( meta_data->field_is_nullable ) TSRMLS_CC );
}
catch ( core::CoreException& e ) {
throw e;
}

bool converted = convert_string_from_utf16( encoding, field_name_temp, field_len_temp, ( char** ) &( meta_data->field_name ), field_name_len );

try {
core::SQLDescribeCol( stmt, colno + 1, meta_data->field_name.get(), SS_MAXCOLNAMELEN, &field_name_len,
&(meta_data->field_type), &(meta_data->field_size), &(meta_data->field_scale),
&(meta_data->field_is_nullable) TSRMLS_CC );
}
catch( core::CoreException& e ) {
throw e;
CHECK_CUSTOM_ERROR( !converted, stmt, SQLSRV_ERROR_FIELD_ENCODING_TRANSLATE, get_last_error_message() ) {
throw core::CoreException();
}

// depending on field type, we add the values into size or precision/scale.
Expand Down
2 changes: 1 addition & 1 deletion source/sqlsrv/php_sqlsrv.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ struct ss_sqlsrv_stmt : public sqlsrv_stmt {
void new_result_set( TSRMLS_D );

// driver specific conversion rules from a SQL Server/ODBC type to one of the SQLSRV_PHPTYPE_* constants
sqlsrv_phptype sql_type_to_php_type( SQLINTEGER sql_type, SQLUINTEGER size, bool prefer_string_to_stream, bool prefer_number_to_string );
sqlsrv_phptype sql_type_to_php_type( SQLINTEGER sql_type, SQLUINTEGER size, bool prefer_string_to_stream );

bool prepared; // whether the statement has been prepared yet (used for error messages)
zend_ulong conn_index; // index into the connection hash that contains this statement structure
Expand Down
56 changes: 32 additions & 24 deletions source/sqlsrv/stmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ void ss_sqlsrv_stmt::new_result_set( TSRMLS_D )
}

// Returns a php type for a given sql type. Also sets the encoding wherever applicable.
sqlsrv_phptype ss_sqlsrv_stmt::sql_type_to_php_type( SQLINTEGER sql_type, SQLUINTEGER size, bool prefer_string_to_stream, bool prefer_number_to_string )
sqlsrv_phptype ss_sqlsrv_stmt::sql_type_to_php_type( SQLINTEGER sql_type, SQLUINTEGER size, bool prefer_string_to_stream )
{
sqlsrv_phptype ss_phptype;
ss_phptype.typeinfo.type = SQLSRV_PHPTYPE_INVALID;
Expand Down Expand Up @@ -1545,6 +1545,7 @@ void convert_to_zval(sqlsrv_stmt* stmt, SQLSRV_PHPTYPE sqlsrv_php_type, void* in

// put in the column size and scale/decimal digits of the sql server type
// these values are taken from the MSDN page at http://msdn2.microsoft.com/en-us/library/ms711786(VS.85).aspx
// for SQL_VARBINARY, SQL_VARCHAR, and SQL_WLONGVARCHAR types, see https://msdn.microsoft.com/en-CA/library/ms187993.aspx
bool determine_column_size_or_precision( sqlsrv_stmt const* stmt, sqlsrv_sqltype sqlsrv_type, _Out_ SQLULEN* column_size,
_Out_ SQLSMALLINT* decimal_digits )
{
Expand Down Expand Up @@ -1577,10 +1578,10 @@ bool determine_column_size_or_precision( sqlsrv_stmt const* stmt, sqlsrv_sqltype
break;
case SQL_LONGVARBINARY:
case SQL_LONGVARCHAR:
*column_size = LONG_MAX;
*column_size = INT_MAX;
break;
case SQL_WLONGVARCHAR:
*column_size = LONG_MAX >> 1;
*column_size = INT_MAX >> 1;
break;
case SQL_SS_XML:
*column_size = SQL_SS_LENGTH_UNLIMITED;
Expand Down Expand Up @@ -1812,29 +1813,36 @@ void fetch_fields_common( _Inout_ ss_sqlsrv_stmt* stmt, zend_long fetch_type, _O

// if this is the first fetch in a new result set, then get the field names and
// store them off for successive fetches.
if(( fetch_type & SQLSRV_FETCH_ASSOC ) && stmt->fetch_field_names == NULL) {

SQLSMALLINT field_name_len;
char field_name_temp[SS_MAXCOLNAMELEN + 1];
sqlsrv_malloc_auto_ptr<sqlsrv_fetch_field_name> field_names;
field_names = static_cast<sqlsrv_fetch_field_name*>( sqlsrv_malloc( num_cols * sizeof(sqlsrv_fetch_field_name)));

for(int i = 0; i < num_cols; ++i) {

core::SQLColAttribute(stmt, i + 1, SQL_DESC_NAME, field_name_temp, SS_MAXCOLNAMELEN + 1, &field_name_len, NULL
TSRMLS_CC);
field_names[i].name = static_cast<char*>( sqlsrv_malloc( field_name_len, sizeof(char), 1 ));
memcpy_s(( void* )field_names[i].name, ( field_name_len * sizeof( char )) ,field_name_temp, field_name_len);
field_names[i].name[field_name_len] = '\0'; // null terminate the field name since SQLColAttribute doesn't.
field_names[i].len = field_name_len + 1;
}
if(( fetch_type & SQLSRV_FETCH_ASSOC ) && stmt->fetch_field_names == NULL ) {

SQLLEN field_name_len = 0;
SQLSMALLINT field_name_len_w = 0;
SQLWCHAR field_name_w[( SS_MAXCOLNAMELEN + 1 ) * 2 ] = { L'\0' };
sqlsrv_malloc_auto_ptr<char> field_name;
sqlsrv_malloc_auto_ptr<sqlsrv_fetch_field_name> field_names;
field_names = static_cast<sqlsrv_fetch_field_name*>( sqlsrv_malloc( num_cols * sizeof( sqlsrv_fetch_field_name )));
SQLSRV_ENCODING encoding = (( stmt->encoding() == SQLSRV_ENCODING_DEFAULT ) ? stmt->conn->encoding() : stmt->encoding());
for( int i = 0; i < num_cols; ++i ) {

core::SQLColAttributeW( stmt, i + 1, SQL_DESC_NAME, field_name_w, ( SS_MAXCOLNAMELEN + 1 ) * 2, &field_name_len_w, NULL TSRMLS_CC );
bool converted = convert_string_from_utf16( encoding, field_name_w, field_name_len_w, ( char** ) &field_name, field_name_len );
CHECK_CUSTOM_ERROR( !converted, stmt, SQLSRV_ERROR_FIELD_ENCODING_TRANSLATE, get_last_error_message() ) {
throw core::CoreException();
}

stmt->fetch_field_names = field_names;
stmt->fetch_fields_count = num_cols;
field_names.transferred();
}
field_names[i].name = static_cast<char*>( sqlsrv_malloc( field_name_len, sizeof( char ), 1 ));
memcpy_s(( void* )field_names[i].name, ( field_name_len * sizeof( char )) , ( void* ) field_name, field_name_len );
field_names[i].name[field_name_len] = '\0'; // null terminate the field name since SQLColAttribute doesn't.
field_names[i].len = field_name_len + 1;
field_name.reset();
}

stmt->fetch_field_names = field_names;
stmt->fetch_fields_count = num_cols;
field_names.transferred();
}

int zr = array_init( &fields );
int zr = array_init( &fields );
CHECK_ZEND_ERROR( zr, stmt, SQLSRV_ERROR_ZEND_HASH ) {
throw ss::SSException();
}
Expand Down