Skip to content

Commit

Permalink
Merge pull request #269 from v-dareck/merged-codebase
Browse files Browse the repository at this point in the history
Merge PHP-7.0-Linux changes into merged-codebase
  • Loading branch information
Hadis Kakanejadi Fard authored Feb 2, 2017
2 parents 2185215 + 1f9d158 commit c9b92b1
Show file tree
Hide file tree
Showing 36 changed files with 1,673 additions and 37 deletions.
2 changes: 2 additions & 0 deletions source/pdo_sqlsrv/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,12 @@ if test "$PHP_PDO_SQLSRV" != "no"; then
PHP_REQUIRE_CXX()
PHP_ADD_LIBRARY(stdc++, 1, PDO_SQLSRV_SHARED_LIBADD)
PHP_ADD_LIBRARY(odbc, 1, PDO_SQLSRV_SHARED_LIBADD)
PHP_ADD_LIBRARY(odbcinst, 1, PDO_SQLSRV_SHARED_LIBADD)
AC_DEFINE(HAVE_PDO_SQLSRV, 1, [ ])
PHP_ADD_INCLUDE([$pdo_sqlsrv_inc_path])
PHP_NEW_EXTENSION(pdo_sqlsrv, $pdo_sqlsrv_src_class $shared_src_class, $ext_shared,,-I$pdo_cv_inc_path -std=c++11)
PHP_SUBST(PDO_SQLSRV_SHARED_LIBADD)
PHP_ADD_EXTENSION_DEP(pdo_sqlsrv, pdo)
PHP_ADD_BUILD_DIR([$ext_builddir/shared], 1)
fi

16 changes: 12 additions & 4 deletions source/pdo_sqlsrv/pdo_dbh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1162,12 +1162,20 @@ char * pdo_sqlsrv_dbh_last_id( pdo_dbh_t *dbh, const char *name, _Out_ size_t* l
temp_stmt.dbh = dbh;

// allocate a full driver statement to take advantage of the error handling
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 TSRMLS_CC );
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 TSRMLS_CC );
driver_stmt->set_func( __FUNCTION__ );

// execute the last insert id query
core::SQLExecDirect( driver_stmt, last_insert_id_query TSRMLS_CC );

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 ), strlen(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
core::SQLExecDirectW( driver_stmt, wsql_string TSRMLS_CC );

core::SQLFetchScroll( driver_stmt, SQL_FETCH_NEXT, 0 TSRMLS_CC );
SQLRETURN r = core::SQLGetData( driver_stmt, 1, SQL_C_CHAR, id_str, LAST_INSERT_ID_BUFF_LEN,
Expand Down
76 changes: 60 additions & 16 deletions source/shared/core_conn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@

#ifndef _WIN32
#include <sys/utsname.h>
#endif // !_WIN32
#include <odbcinst.h>
#endif

// *** internal variables and constants ***

Expand Down Expand Up @@ -101,13 +102,30 @@ sqlsrv_conn* core_sqlsrv_connect( sqlsrv_context& henv_cp, sqlsrv_context& henv_
sqlsrv_malloc_auto_ptr<SQLWCHAR> wconn_string;
unsigned int wconn_len = 0;

try {
#ifdef _WIN32
sqlsrv_context* henv = &henv_cp; // by default use the connection pooling henv
#else
sqlsrv_context* henv = &henv_ncp; // by default do not use the connection pooling henv
#endif // _WIN32

sqlsrv_context* henv = &henv_cp; // by default use the connection pooling henv
try {
// Due to the limitations on connection pooling in unixODBC 2.3.1 driver manager, we do not consider
// the connection string attributes to set (enable/disable) connection pooling.
// Instead, MSPHPSQL connection pooling is set according to the ODBCINST.INI file in [ODBC] section.

#ifndef _WIN32
char pooling_string[ 128 ] = {0};
SQLGetPrivateProfileString( "ODBC", "Pooling", "0", pooling_string, sizeof( pooling_string ), "ODBCINST.INI" );

// check the connection pooling setting to determine which henv to use to allocate the connection handle
// we do this earlier because we have to allocate the connection handle prior to setting attributes on
// it in build_connection_string_and_set_conn_attr.
if ( pooling_string[ 0 ] == '1' || toupper( pooling_string[ 0 ] ) == 'Y' ||
( toupper( pooling_string[ 0 ] ) == 'O' && toupper( pooling_string[ 1 ] ) == 'N' ))
{
henv = &henv_cp;
}
#else
// check the connection pooling setting to determine which henv to use to allocate the connection handle
// we do this earlier because we have to allocate the connection handle prior to setting attributes on
// it in build_connection_string_and_set_conn_attr.

if( options_ht && zend_hash_num_elements( options_ht ) > 0 ) {

Expand All @@ -120,6 +138,7 @@ sqlsrv_conn* core_sqlsrv_connect( sqlsrv_context& henv_cp, sqlsrv_context& henv_
}
}
}
#endif // !_WIN32

SQLHANDLE temp_conn_h;
core::SQLAllocHandle( SQL_HANDLE_DBC, *henv, &temp_conn_h TSRMLS_CC );
Expand All @@ -143,7 +162,20 @@ sqlsrv_conn* core_sqlsrv_connect( sqlsrv_context& henv_cp, sqlsrv_context& henv_
}

SQLSMALLINT output_conn_size;
r = SQLDriverConnectW( conn->handle(), NULL, reinterpret_cast<SQLWCHAR*>(wconn_string.get()), static_cast<SQLSMALLINT>( wconn_len ), NULL, 0, &output_conn_size, SQL_DRIVER_NOPROMPT );
#ifndef _WIN32
// unixODBC 2.3.1 requires a non-wide SQLDriverConnect call while pooling enabled.
// connection handle has been allocated using henv_cp, means pooling enabled in a PHP script
if ( henv == &henv_cp )
{
r = SQLDriverConnect( conn->handle(), NULL, (SQLCHAR*)conn_str.c_str(), SQL_NTS, NULL, 0, &output_conn_size, SQL_DRIVER_NOPROMPT );
}
else
{
r = SQLDriverConnectW( conn->handle(), NULL, reinterpret_cast<SQLWCHAR*>( wconn_string.get() ), static_cast<SQLSMALLINT>( wconn_len ), NULL, 0, &output_conn_size, SQL_DRIVER_NOPROMPT );
}
#else
r = SQLDriverConnectW( conn->handle(), NULL, reinterpret_cast<SQLWCHAR*>( wconn_string.get() ), static_cast<SQLSMALLINT>( wconn_len ), NULL, 0, &output_conn_size, SQL_DRIVER_NOPROMPT );
#endif // !_WIN32

// clear the connection string from memory to remove sensitive data (such as a password).
memset( const_cast<char*>(conn_str.c_str()), 0, conn_str.size());
Expand Down Expand Up @@ -177,8 +209,18 @@ sqlsrv_conn* core_sqlsrv_connect( sqlsrv_context& henv_cp, sqlsrv_context& henv_

// determine the version of the server we're connected to. The server version is left in the
// connection upon return.
determine_server_version( conn TSRMLS_CC );

//
// unixODBC 2.3.1:
// SQLGetInfo works when r = SQL_SUCCESS_WITH_INFO (non-pooled connection)
// but fails if the connection is using a pool, i.e. r= SQL_SUCCESS.
// Thus, in Linux, we don't call determine_server_version() for a connection that uses pool.
#ifndef _WIN32
if ( r == SQL_SUCCESS_WITH_INFO ) {
#endif // !_WIN32
determine_server_version( conn TSRMLS_CC );
#ifndef _WIN32
}
#endif // !_WIN32
}
catch( std::bad_alloc& ) {
memset( const_cast<char*>( conn_str.c_str()), 0, conn_str.size() );
Expand Down Expand Up @@ -406,12 +448,13 @@ void core_sqlsrv_get_server_info( sqlsrv_conn* conn, _Out_ zval *server_info TSR
sqlsrv_malloc_auto_ptr<char> buffer;
SQLSMALLINT buffer_len = 0;

// initialize the array
core::sqlsrv_array_init( *conn, server_info TSRMLS_CC );

// Get the database name
buffer = static_cast<char*>( sqlsrv_malloc( INFO_BUFFER_LEN ));
core::SQLGetInfo( conn, SQL_DATABASE_NAME, buffer, INFO_BUFFER_LEN, &buffer_len TSRMLS_CC );

// initialize the array
core::sqlsrv_array_init( *conn, server_info TSRMLS_CC );

core::sqlsrv_add_assoc_string( *conn, server_info, "CurrentDatabase", buffer, 0 /*duplicate*/ TSRMLS_CC );
buffer.transferred();

Expand Down Expand Up @@ -444,13 +487,14 @@ void core_sqlsrv_get_client_info( sqlsrv_conn* conn, _Out_ zval *client_info TSR

sqlsrv_malloc_auto_ptr<char> buffer;
SQLSMALLINT buffer_len = 0;

// initialize the array
core::sqlsrv_array_init( *conn, client_info TSRMLS_CC );


// Get the ODBC driver's dll name
buffer = static_cast<char*>( sqlsrv_malloc( INFO_BUFFER_LEN ));
core::SQLGetInfo( conn, SQL_DRIVER_NAME, buffer, INFO_BUFFER_LEN, &buffer_len TSRMLS_CC );

// initialize the array
core::sqlsrv_array_init( *conn, client_info TSRMLS_CC );

#ifndef _WIN32
core::sqlsrv_add_assoc_string( *conn, client_info, "DriverName", buffer, 0 /*duplicate*/ TSRMLS_CC );
#else
Expand Down
8 changes: 4 additions & 4 deletions source/shared/core_results.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -481,8 +481,8 @@ sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( sqlsrv_stmt* stmt TSRMLS
// get the meta data and calculate the size of a row buffer
SQLULEN offset = null_bytes;
for( SQLSMALLINT i = 0; i < col_count; ++i ) {

core::SQLDescribeCol( stmt, i + 1, NULL, 0, NULL, &meta[i].type, &meta[i].length, &meta[i].scale, NULL TSRMLS_CC );
core::SQLDescribeColW( stmt, i + 1, NULL, 0, NULL, &meta[i].type, &meta[i].length, &meta[i].scale, NULL TSRMLS_CC );

offset = align_to<sizeof(SQLPOINTER)>( offset );
meta[i].offset = offset;
Expand All @@ -494,7 +494,7 @@ sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( sqlsrv_stmt* stmt TSRMLS
case SQL_DECIMAL:
case SQL_GUID:
case SQL_NUMERIC:
core::SQLColAttribute( stmt, i + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL,
core::SQLColAttributeW( stmt, i + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL,
reinterpret_cast<SQLLEN*>( &meta[i].length ) TSRMLS_CC );
meta[i].length += sizeof( char ) + sizeof( SQLULEN ); // null terminator space
offset += meta[i].length;
Expand Down Expand Up @@ -560,7 +560,7 @@ sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( sqlsrv_stmt* stmt TSRMLS
case SQL_SS_TIME2:
case SQL_SS_TIMESTAMPOFFSET:
case SQL_TYPE_TIMESTAMP:
core::SQLColAttribute( stmt, i + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL,
core::SQLColAttributeW( stmt, i + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL,
reinterpret_cast<SQLLEN*>( &meta[i].length ) TSRMLS_CC );
meta[i].length += sizeof(char) + sizeof( SQLULEN ); // null terminator space
offset += meta[i].length;
Expand Down
42 changes: 31 additions & 11 deletions source/shared/core_stmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -812,10 +812,10 @@ field_meta_data* core_sqlsrv_field_metadata( sqlsrv_stmt* stmt, SQLSMALLINT coln
SQLLEN field_name_len = 0;

meta_data = new ( sqlsrv_malloc( sizeof( field_meta_data ))) field_meta_data();
field_name_temp = static_cast<SQLWCHAR*>( sqlsrv_malloc( SS_MAXCOLNAMELEN * 2 + 1 ));
field_name_temp = static_cast<SQLWCHAR*>( sqlsrv_malloc( ( SS_MAXCOLNAMELEN + 1 ) * sizeof( SQLWCHAR ) ));
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,
core::SQLDescribeColW( stmt, colno + 1, field_name_temp, SS_MAXCOLNAMELEN, &field_len_temp,
&( meta_data->field_type ), & ( meta_data->field_size ), & ( meta_data->field_scale ),
&( meta_data->field_is_nullable ) TSRMLS_CC );
}
Expand Down Expand Up @@ -938,10 +938,10 @@ void core_sqlsrv_get_field( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_
if( sqlsrv_php_type.typeinfo.type == SQLSRV_PHPTYPE_INVALID ) {

// Get the SQL type of the field.
core::SQLColAttribute( stmt, field_index + 1, SQL_DESC_CONCISE_TYPE, NULL, 0, NULL, &sql_field_type TSRMLS_CC );
core::SQLColAttributeW( stmt, field_index + 1, SQL_DESC_CONCISE_TYPE, NULL, 0, NULL, &sql_field_type TSRMLS_CC );

// Get the length of the field.
core::SQLColAttribute( stmt, field_index + 1, SQL_DESC_LENGTH, NULL, 0, NULL, &sql_field_len TSRMLS_CC );
core::SQLColAttributeW( stmt, field_index + 1, SQL_DESC_LENGTH, NULL, 0, NULL, &sql_field_len TSRMLS_CC );

// Get the corresponding php type from the sql type.
sqlsrv_php_type = stmt->sql_type_to_php_type( static_cast<SQLINTEGER>( sql_field_type ), static_cast<SQLUINTEGER>( sql_field_len ), prefer_string );
Expand Down Expand Up @@ -1413,7 +1413,8 @@ void calc_string_size( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, SQLLEN sql_t
case SQL_SS_TIME2:
case SQL_SS_TIMESTAMPOFFSET:
{
core::SQLColAttribute( stmt, field_index + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, &size TSRMLS_CC );
// unixODBC 2.3.1 requires wide calls to support pooling
core::SQLColAttributeW( stmt, field_index + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, &size TSRMLS_CC );
break;
}

Expand All @@ -1422,7 +1423,8 @@ void calc_string_size( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, SQLLEN sql_t
case SQL_WCHAR:
case SQL_WVARCHAR:
{
core::SQLColAttribute( stmt, field_index + 1, SQL_DESC_OCTET_LENGTH, NULL, 0, NULL, &size TSRMLS_CC );
// unixODBC 2.3.1 requires wide calls to support pooling
core::SQLColAttributeW( stmt, field_index + 1, SQL_DESC_OCTET_LENGTH, NULL, 0, NULL, &size TSRMLS_CC );
break;
}

Expand Down Expand Up @@ -1614,7 +1616,7 @@ void core_get_field_common( _Inout_ sqlsrv_stmt* stmt, SQLUSMALLINT field_index,
sqlsrv_stream* ss = NULL;
SQLLEN sql_type;

SQLRETURN r = SQLColAttribute( stmt->handle(), field_index + 1, SQL_DESC_TYPE, NULL, 0, NULL, &sql_type );
SQLRETURN r = SQLColAttributeW( stmt->handle(), field_index + 1, SQL_DESC_TYPE, NULL, 0, NULL, &sql_type );
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
throw core::CoreException();
}
Expand Down Expand Up @@ -2112,8 +2114,8 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph
break;
}

// Get the SQL type of the field.
core::SQLColAttribute( stmt, field_index + 1, SQL_DESC_CONCISE_TYPE, NULL, 0, NULL, &sql_field_type TSRMLS_CC );
// Get the SQL type of the field. unixODBC 2.3.1 requires wide calls to support pooling
core::SQLColAttributeW( stmt, field_index + 1, SQL_DESC_CONCISE_TYPE, NULL, 0, NULL, &sql_field_type TSRMLS_CC );

// Calculate the field size.
calc_string_size( stmt, field_index, sql_field_type, sql_display_size TSRMLS_CC );
Expand All @@ -2123,6 +2125,8 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph
sql_display_size == INT_MAX >> 1 || sql_display_size == UINT_MAX - 1 ) {

field_len_temp = INITIAL_FIELD_STRING_LEN;
SQLLEN initiallen = field_len_temp + extra;


field_value_temp = static_cast<char*>( sqlsrv_malloc( field_len_temp + extra + 1 ));

Expand All @@ -2146,7 +2150,13 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph

stmt->current_results->get_diag_field( 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len TSRMLS_CC );

if( is_truncated_warning( state )) {
// with Linux connection pooling may not get a truncated warning back but the actual field_len_temp
// can be greater than the initallen value.
#ifndef _WIN32
if( is_truncated_warning( state ) || initiallen < field_len_temp) {
#else
if( is_truncated_warning( state ) ) {
#endif // !_WIN32

SQLLEN dummy_field_len;

Expand Down Expand Up @@ -2287,7 +2297,17 @@ void get_field_as_string( sqlsrv_stmt* stmt, SQLUSMALLINT field_index, sqlsrv_ph
// runtime checks to see if a string is null terminated and issues a warning about it if running in debug mode.
// SQL_C_BINARY fields don't return a NULL terminator, so we allocate an extra byte on each field and use the ternary
// operator to set add 1 to fill the null terminator
field_value_temp[field_len_temp] = '\0';

// with unixODBC connection pooling sometimes field_len_temp can be SQL_NO_DATA.
// In that cause do not set null terminator and set length to 0.
if ( field_len_temp > 0 )
{
field_value_temp[field_len_temp] = '\0';
}
else
{
*field_len = 0;
}
}

catch( core::CoreException& ) {
Expand Down
6 changes: 6 additions & 0 deletions source/shared/core_stream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,13 @@ size_t sqlsrv_stream_read( php_stream* stream, _Out_writes_bytes_(count) char* b
"did not occur." );
}

// with unixODBC connection pooling enabled the truncated state may not be returned so check the actual length read
// with buffer length.
#ifndef _WIN32
if( is_truncated_warning( state ) || count < read) {
#else
if( is_truncated_warning( state ) ) {
#endif // !_WIN32
switch( c_type ) {

// As per SQLGetData documentation, if the length of character data exceeds the BufferLength,
Expand Down
4 changes: 4 additions & 0 deletions source/shared/localizationimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,14 @@ struct cp_iconv

// Array of CodePage-to-IConvEncoding mappings
// First few elements are most commonly used
// CodePage 2 corresponds to binary. If the attribute PDO::SQLSRV_ENCODING_BINARY
// is set, GetIndex() above hits the assert(false) directive unless we include
// CodePage 2 below and assign an empty string to it.
const cp_iconv cp_iconv::g_cp_iconv[] = {
{ 65001, "UTF-8" },
{ 1200, "UTF-16LE" },
{ 3, "UTF-8" },
{ 2, "" },
{ 1252, "CP1252//TRANSLIT" },
{ 850, "CP850//TRANSLIT" },
{ 437, "CP437//TRANSLIT" },
Expand Down
1 change: 1 addition & 0 deletions source/sqlsrv/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ if test "$PHP_SQLSRV" != "no"; then
PHP_REQUIRE_CXX()
PHP_ADD_LIBRARY(stdc++, 1, SQLSRV_SHARED_LIBADD)
PHP_ADD_LIBRARY(odbc, 1, SQLSRV_SHARED_LIBADD)
PHP_ADD_LIBRARY(odbcinst, 1, SQLSRV_SHARED_LIBADD)
PHP_SUBST(SQLSRV_SHARED_LIBADD)
AC_DEFINE(HAVE_SQLSRV, 1, [ ])
PHP_ADD_INCLUDE([$sqlsrv_inc_path])
Expand Down
4 changes: 2 additions & 2 deletions source/sqlsrv/php_sqlsrv.h
Original file line number Diff line number Diff line change
Expand Up @@ -603,8 +603,6 @@ inline H* process_params( INTERNAL_FUNCTION_PARAMETERS, char const* param_spec,
}

h->set_func( calling_func );

return h;
}

catch( core::CoreException& ) {
Expand All @@ -615,6 +613,8 @@ inline H* process_params( INTERNAL_FUNCTION_PARAMETERS, char const* param_spec,

DIE( "%1!s!: Unknown exception caught in process_params.", calling_func );
}

return h;
}

#endif /* PHP_SQLSRV_H */
Loading

0 comments on commit c9b92b1

Please sign in to comment.