Merge branch 'merged-codebase' of https://github.com/Microsoft/msphpsql into merged-codebase
This commit is contained in:
commit
9ec0b25774
|
@ -19,13 +19,9 @@
|
|||
|
||||
#include "php_pdo_sqlsrv.h"
|
||||
|
||||
#include <psapi.h>
|
||||
#include <windows.h>
|
||||
#include <winver.h>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
typedef const zend_function_entry pdo_sqlsrv_function_entry;
|
||||
|
||||
// *** internal variables and constants ***
|
||||
|
@ -73,7 +69,7 @@ enum PDO_STMT_OPTIONS {
|
|||
PDO_STMT_OPTION_CURSOR_SCROLL_TYPE,
|
||||
PDO_STMT_OPTION_CLIENT_BUFFER_MAX_KB_SIZE,
|
||||
PDO_STMT_OPTION_EMULATE_PREPARES,
|
||||
PDO_STMT_OPTION_FETCHES_NUMERIC_TYPE,
|
||||
PDO_STMT_OPTION_FETCHES_NUMERIC_TYPE,
|
||||
};
|
||||
|
||||
// List of all the statement options supported by this driver.
|
||||
|
@ -86,9 +82,9 @@ const stmt_option PDO_STMT_OPTS[] = {
|
|||
{ NULL, 0, PDO_STMT_OPTION_CURSOR_SCROLL_TYPE, std::unique_ptr<stmt_option_cursor_scroll_type>( new stmt_option_cursor_scroll_type ) },
|
||||
{ NULL, 0, PDO_STMT_OPTION_CLIENT_BUFFER_MAX_KB_SIZE, std::unique_ptr<stmt_option_buffered_query_limit>( new stmt_option_buffered_query_limit ) },
|
||||
{ NULL, 0, PDO_STMT_OPTION_EMULATE_PREPARES, std::unique_ptr<stmt_option_emulate_prepares>( new stmt_option_emulate_prepares ) },
|
||||
{ NULL, 0, PDO_STMT_OPTION_FETCHES_NUMERIC_TYPE, std::unique_ptr<stmt_option_fetch_numeric>( new stmt_option_fetch_numeric ) },
|
||||
{ NULL, 0, PDO_STMT_OPTION_FETCHES_NUMERIC_TYPE, std::unique_ptr<stmt_option_fetch_numeric>( new stmt_option_fetch_numeric ) },
|
||||
|
||||
{ NULL, 0, SQLSRV_STMT_OPTION_INVALID, std::unique_ptr<stmt_option_functor>{} },
|
||||
{ NULL, 0, SQLSRV_STMT_OPTION_INVALID, std::unique_ptr<stmt_option_functor>{} },
|
||||
};
|
||||
|
||||
// boolean connection string
|
||||
|
@ -350,27 +346,40 @@ struct pdo_dbh_methods pdo_sqlsrv_dbh_methods = {
|
|||
NULL, // check liveness not implemented
|
||||
pdo_sqlsrv_get_driver_methods,
|
||||
NULL, // request shutdown not implemented
|
||||
NULL // in transaction not implemented
|
||||
NULL // in transaction not implemented
|
||||
};
|
||||
|
||||
|
||||
// log a function entry point
|
||||
#ifndef _WIN32
|
||||
#define PDO_LOG_DBH_ENTRY \
|
||||
{ \
|
||||
pdo_sqlsrv_dbh* driver_dbh = reinterpret_cast<pdo_sqlsrv_dbh*>( dbh->driver_data ); \
|
||||
driver_dbh->set_func( __FUNCTION__ ); \
|
||||
int length = strlen( __FUNCTION__ ) + strlen( ": entering" ); \
|
||||
char func[length+1]; \
|
||||
strcpy_s( func, sizeof( __FUNCTION__ ), __FUNCTION__ ); \
|
||||
strcat_s( func, length+1, ": entering" ); \
|
||||
LOG( SEV_NOTICE, func ); \
|
||||
}
|
||||
#else
|
||||
#define PDO_LOG_DBH_ENTRY \
|
||||
{ \
|
||||
pdo_sqlsrv_dbh* driver_dbh = reinterpret_cast<pdo_sqlsrv_dbh*>( dbh->driver_data ); \
|
||||
driver_dbh->set_func( __FUNCTION__ ); \
|
||||
LOG( SEV_NOTICE, __FUNCTION__ ## ": entering" ); \
|
||||
}
|
||||
#endif
|
||||
|
||||
// constructor for the internal object for connections
|
||||
pdo_sqlsrv_dbh::pdo_sqlsrv_dbh( SQLHANDLE h, error_callback e, void* driver TSRMLS_DC ) :
|
||||
sqlsrv_conn( h, e, driver, SQLSRV_ENCODING_UTF8 TSRMLS_CC ),
|
||||
stmts( NULL ),
|
||||
direct_query( false ),
|
||||
query_timeout( QUERY_TIMEOUT_INVALID ),
|
||||
client_buffer_max_size( PDO_SQLSRV_G( client_buffer_max_size )),
|
||||
bind_param_encoding( SQLSRV_ENCODING_CHAR ),
|
||||
fetch_numeric( false )
|
||||
sqlsrv_conn( h, e, driver, SQLSRV_ENCODING_UTF8 TSRMLS_CC ),
|
||||
stmts( NULL ),
|
||||
direct_query( false ),
|
||||
query_timeout( QUERY_TIMEOUT_INVALID ),
|
||||
client_buffer_max_size( PDO_SQLSRV_G( client_buffer_max_size )),
|
||||
bind_param_encoding( SQLSRV_ENCODING_CHAR ),
|
||||
fetch_numeric( false )
|
||||
{
|
||||
if( client_buffer_max_size < 0 ) {
|
||||
client_buffer_max_size = sqlsrv_buffered_result_set::BUFFERED_QUERY_LIMIT_DEFAULT;
|
||||
|
@ -408,7 +417,7 @@ int pdo_sqlsrv_db_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC)
|
|||
zval* temp_server_z = NULL;
|
||||
sqlsrv_malloc_auto_ptr<conn_string_parser> dsn_parser;
|
||||
zval server_z;
|
||||
ZVAL_UNDEF( &server_z );
|
||||
ZVAL_UNDEF( &server_z );
|
||||
|
||||
try {
|
||||
|
||||
|
@ -452,8 +461,8 @@ int pdo_sqlsrv_db_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC)
|
|||
dbh->username, dbh->password, pdo_conn_options_ht, pdo_sqlsrv_handle_dbh_error,
|
||||
PDO_CONN_OPTS, dbh, "pdo_sqlsrv_db_handle_factory" TSRMLS_CC );
|
||||
|
||||
// Free the string in server_z after being used
|
||||
zend_string_release( Z_STR( server_z ));
|
||||
// Free the string in server_z after being used
|
||||
zend_string_release( Z_STR( server_z ));
|
||||
|
||||
SQLSRV_ASSERT( conn != NULL, "Invalid connection returned. Exception should have been thrown." );
|
||||
|
||||
|
@ -465,11 +474,13 @@ int pdo_sqlsrv_db_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC)
|
|||
|
||||
}
|
||||
catch( core::CoreException& ) {
|
||||
if ( Z_TYPE( server_z ) == IS_STRING ) {
|
||||
zend_string_release( Z_STR( server_z ));
|
||||
}
|
||||
|
||||
if ( Z_TYPE( server_z ) == IS_STRING ) {
|
||||
zend_string_release( Z_STR( server_z ));
|
||||
}
|
||||
dbh->error_mode = prev_err_mode; // reset the error mode
|
||||
g_henv_cp->last_error().reset(); // reset the last error; callee will check if last_error exist before freeing it and setting it to NULL
|
||||
g_henv_cp->last_error().reset(); // reset the last error; callee will check if last_error exist before freeing it and setting it to NULL
|
||||
|
||||
return 0;
|
||||
}
|
||||
catch( ... ) {
|
||||
|
@ -574,12 +585,13 @@ int pdo_sqlsrv_dbh_prepare( pdo_dbh_t *dbh, const char *sql,
|
|||
|
||||
// rewrite the query to map named parameters to positional parameters. We do this rather than use the ODBC named
|
||||
// parameters for consistency with the PDO MySQL and PDO ODBC drivers.
|
||||
int zr = pdo_subst_named_params( stmt, const_cast<char*>( sql ), sql_len, &sql_rewrite, &sql_rewrite_len TSRMLS_CC );
|
||||
CHECK_ZEND_ERROR( zr, driver_dbh, PDO_SQLSRV_ERROR_PARAM_PARSE ) {
|
||||
int zr = pdo_parse_params( stmt, const_cast<char*>( sql ), sql_len, &sql_rewrite, &sql_rewrite_len TSRMLS_CC );
|
||||
|
||||
CHECK_ZEND_ERROR( zr, driver_dbh, PDO_SQLSRV_ERROR_PARAM_PARSE) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
// if parameter substitution happened, use that query instead of the original
|
||||
if( sql_rewrite != NULL ) {
|
||||
if( sql_rewrite != 0) {
|
||||
sql = sql_rewrite;
|
||||
sql_len = sql_rewrite_len;
|
||||
}
|
||||
|
@ -910,16 +922,16 @@ int pdo_sqlsrv_dbh_set_attr( pdo_dbh_t *dbh, zend_long attr, zval *val TSRMLS_DC
|
|||
driver_dbh->client_buffer_max_size = Z_LVAL_P( val );
|
||||
break;
|
||||
|
||||
case SQLSRV_ATTR_FETCHES_NUMERIC_TYPE:
|
||||
driver_dbh->fetch_numeric = (zend_is_true(val)) ? true : false;
|
||||
break;
|
||||
case SQLSRV_ATTR_FETCHES_NUMERIC_TYPE:
|
||||
driver_dbh->fetch_numeric = (zend_is_true(val)) ? true : false;
|
||||
break;
|
||||
|
||||
// Not supported
|
||||
case PDO_ATTR_FETCH_TABLE_NAMES:
|
||||
case PDO_ATTR_FETCH_CATALOG_NAMES:
|
||||
case PDO_ATTR_PREFETCH:
|
||||
case PDO_ATTR_MAX_COLUMN_LEN:
|
||||
case PDO_ATTR_CURSOR_NAME:
|
||||
case PDO_ATTR_CURSOR_NAME:
|
||||
case PDO_ATTR_AUTOCOMMIT:
|
||||
case PDO_ATTR_PERSISTENT:
|
||||
case PDO_ATTR_TIMEOUT:
|
||||
|
@ -929,10 +941,10 @@ int pdo_sqlsrv_dbh_set_attr( pdo_dbh_t *dbh, zend_long attr, zval *val TSRMLS_DC
|
|||
|
||||
// Read-only
|
||||
case PDO_ATTR_SERVER_VERSION:
|
||||
case PDO_ATTR_SERVER_INFO:
|
||||
case PDO_ATTR_SERVER_INFO:
|
||||
case PDO_ATTR_CLIENT_VERSION:
|
||||
case PDO_ATTR_DRIVER_NAME:
|
||||
case PDO_ATTR_CONNECTION_STATUS:
|
||||
case PDO_ATTR_CONNECTION_STATUS:
|
||||
{
|
||||
THROW_PDO_ERROR( driver_dbh, PDO_SQLSRV_ERROR_READ_ONLY_DBH_ATTR );
|
||||
}
|
||||
|
@ -940,7 +952,7 @@ int pdo_sqlsrv_dbh_set_attr( pdo_dbh_t *dbh, zend_long attr, zval *val TSRMLS_DC
|
|||
// Statement level only
|
||||
case PDO_ATTR_EMULATE_PREPARES:
|
||||
case PDO_ATTR_CURSOR:
|
||||
case SQLSRV_ATTR_CURSOR_SCROLL_TYPE:
|
||||
case SQLSRV_ATTR_CURSOR_SCROLL_TYPE:
|
||||
{
|
||||
THROW_PDO_ERROR( driver_dbh, PDO_SQLSRV_ERROR_STMT_LEVEL_ATTR );
|
||||
}
|
||||
|
@ -997,7 +1009,7 @@ int pdo_sqlsrv_dbh_get_attr( pdo_dbh_t *dbh, zend_long attr, zval *return_value
|
|||
// Statement level only
|
||||
case PDO_ATTR_EMULATE_PREPARES:
|
||||
case PDO_ATTR_CURSOR:
|
||||
case SQLSRV_ATTR_CURSOR_SCROLL_TYPE:
|
||||
case SQLSRV_ATTR_CURSOR_SCROLL_TYPE:
|
||||
{
|
||||
THROW_PDO_ERROR( driver_dbh, PDO_SQLSRV_ERROR_STMT_LEVEL_ATTR );
|
||||
}
|
||||
|
@ -1025,8 +1037,11 @@ int pdo_sqlsrv_dbh_get_attr( pdo_dbh_t *dbh, zend_long attr, zval *return_value
|
|||
{
|
||||
core_sqlsrv_get_client_info( driver_dbh, return_value TSRMLS_CC );
|
||||
|
||||
//Add the PDO SQLSRV driver's file version
|
||||
core::sqlsrv_add_assoc_string( *driver_dbh, return_value, "ExtensionVer", VER_FILEVERSION_STR, 1 /*duplicate*/
|
||||
//Add the PDO SQLSRV driver's file version
|
||||
//Declarations below eliminate compiler warnings about string constant to char* conversions
|
||||
const char* extver = "ExtensionVer";
|
||||
std::string filever = VER_FILEVERSION_STR;
|
||||
core::sqlsrv_add_assoc_string( *driver_dbh, return_value, extver, &filever[0], 1 /*duplicate*/
|
||||
TSRMLS_CC );
|
||||
break;
|
||||
}
|
||||
|
@ -1055,11 +1070,11 @@ int pdo_sqlsrv_dbh_get_attr( pdo_dbh_t *dbh, zend_long attr, zval *return_value
|
|||
break;
|
||||
}
|
||||
|
||||
case SQLSRV_ATTR_FETCHES_NUMERIC_TYPE:
|
||||
{
|
||||
ZVAL_BOOL( return_value, driver_dbh->fetch_numeric );
|
||||
break;
|
||||
}
|
||||
case SQLSRV_ATTR_FETCHES_NUMERIC_TYPE:
|
||||
{
|
||||
ZVAL_BOOL( return_value, driver_dbh->fetch_numeric );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
|
@ -1095,8 +1110,8 @@ int pdo_sqlsrv_dbh_return_error( pdo_dbh_t *dbh, pdo_stmt_t *stmt,
|
|||
else {
|
||||
ctx_error = static_cast<sqlsrv_conn*>( dbh->driver_data )->last_error();
|
||||
}
|
||||
|
||||
pdo_sqlsrv_retrieve_context_error( ctx_error, info );
|
||||
|
||||
pdo_sqlsrv_retrieve_context_error( ctx_error, info );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -1135,10 +1150,10 @@ char * pdo_sqlsrv_dbh_last_id( pdo_dbh_t *dbh, const char *name, _Out_ size_t* l
|
|||
}
|
||||
else {
|
||||
char* quoted_table = NULL;
|
||||
size_t quoted_len = 0;
|
||||
size_t quoted_len = 0;
|
||||
int quoted = pdo_sqlsrv_dbh_quote( dbh, name, strlen( name ), "ed_table, "ed_len, PDO_PARAM_NULL TSRMLS_CC );
|
||||
SQLSRV_ASSERT( quoted, "PDO::lastInsertId failed to quote the table name." );
|
||||
sprintf_s( last_insert_id_query, LAST_INSERT_ID_QUERY_MAX_LEN, TABLE_LAST_INSERT_ID_QUERY, quoted_table );
|
||||
SQLSRV_ASSERT( quoted, "PDO::lastInsertId failed to quote the table name.");
|
||||
snprintf( last_insert_id_query, LAST_INSERT_ID_QUERY_MAX_LEN, TABLE_LAST_INSERT_ID_QUERY, quoted_table );
|
||||
sqlsrv_free( quoted_table );
|
||||
}
|
||||
|
||||
|
@ -1158,7 +1173,7 @@ char * pdo_sqlsrv_dbh_last_id( pdo_dbh_t *dbh, const char *name, _Out_ size_t* l
|
|||
SQLRETURN r = core::SQLGetData( driver_stmt, 1, SQL_C_CHAR, id_str, LAST_INSERT_ID_BUFF_LEN,
|
||||
reinterpret_cast<SQLLEN*>( len ), false TSRMLS_CC );
|
||||
|
||||
CHECK_CUSTOM_ERROR( (!SQL_SUCCEEDED( r ) || *len == SQL_NULL_DATA || *len == SQL_NO_TOTAL), driver_stmt,
|
||||
CHECK_CUSTOM_ERROR( (!SQL_SUCCEEDED( r ) || *len == SQL_NULL_DATA || *len == SQL_NO_TOTAL), driver_stmt,
|
||||
PDO_SQLSRV_ERROR_LAST_INSERT_ID ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
@ -1204,81 +1219,79 @@ char * pdo_sqlsrv_dbh_last_id( pdo_dbh_t *dbh, const char *name, _Out_ size_t* l
|
|||
int pdo_sqlsrv_dbh_quote( pdo_dbh_t* dbh, const char* unquoted, size_t unquoted_len, char **quoted, size_t* quoted_len,
|
||||
enum pdo_param_type /*paramtype*/ TSRMLS_DC )
|
||||
{
|
||||
PDO_RESET_DBH_ERROR;
|
||||
PDO_VALIDATE_CONN;
|
||||
PDO_RESET_DBH_ERROR;
|
||||
PDO_VALIDATE_CONN;
|
||||
PDO_LOG_DBH_ENTRY;
|
||||
|
||||
pdo_sqlsrv_dbh* driver_dbh = reinterpret_cast<pdo_sqlsrv_dbh*>( dbh->driver_data );
|
||||
SQLSRV_ENCODING encoding = driver_dbh->bind_param_encoding;
|
||||
pdo_sqlsrv_dbh* driver_dbh = reinterpret_cast<pdo_sqlsrv_dbh*>( dbh->driver_data );
|
||||
SQLSRV_ENCODING encoding = driver_dbh->bind_param_encoding;
|
||||
|
||||
if ( encoding == SQLSRV_ENCODING_BINARY ) {
|
||||
// convert from char* to hex digits using os
|
||||
std::basic_ostringstream<char> os;
|
||||
for ( size_t index = 0; index < unquoted_len && unquoted[index] != '\0'; ++index ) {
|
||||
os << std::hex << ( int )unquoted[index];
|
||||
}
|
||||
std::basic_string<char> str_hex = os.str();
|
||||
// each character is represented by 2 digits of hex
|
||||
size_t unquoted_str_len = unquoted_len * 2; // length returned should not account for null terminator
|
||||
char* unquoted_str = reinterpret_cast<char*>( sqlsrv_malloc( unquoted_str_len, sizeof( char ), 1 )); // include space for null terminator
|
||||
strcpy_s( unquoted_str, unquoted_str_len + 1 /* include null terminator*/, str_hex.c_str());
|
||||
// include length of '0x' in the binary string
|
||||
*quoted_len = unquoted_str_len + 2;
|
||||
*quoted = reinterpret_cast<char*>( sqlsrv_malloc( *quoted_len, sizeof( char ), 1 ));
|
||||
unsigned int out_current = 0;
|
||||
// insert '0x'
|
||||
( *quoted )[out_current++] = '0';
|
||||
( *quoted )[out_current++] = 'x';
|
||||
for ( size_t index = 0; index < unquoted_str_len && unquoted_str[index] != '\0'; ++index ) {
|
||||
( *quoted )[out_current++] = unquoted_str[index];
|
||||
}
|
||||
// null terminator
|
||||
( *quoted )[out_current] = '\0';
|
||||
sqlsrv_free( unquoted_str );
|
||||
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 ( encoding == SQLSRV_ENCODING_UTF8 ) {
|
||||
quotes_needed = 3;
|
||||
}
|
||||
if ( encoding == SQLSRV_ENCODING_BINARY ) {
|
||||
// convert from char* to hex digits using os
|
||||
std::basic_ostringstream<char> os;
|
||||
for ( size_t index = 0; index < unquoted_len && unquoted[ index ] != '\0'; ++index ) {
|
||||
os << std::hex << ( int )unquoted[ index ];
|
||||
}
|
||||
std::basic_string<char> str_hex = os.str();
|
||||
// each character is represented by 2 digits of hex
|
||||
size_t unquoted_str_len = unquoted_len * 2; // length returned should not account for null terminator
|
||||
char* unquoted_str = reinterpret_cast<char*>( sqlsrv_malloc( unquoted_str_len, sizeof( char ), 1 )); // include space for null terminator
|
||||
strcpy_s( unquoted_str, unquoted_str_len + 1 /* include null terminator*/, str_hex.c_str() );
|
||||
// include length of '0x' in the binary string
|
||||
*quoted_len = unquoted_str_len + 2;
|
||||
*quoted = reinterpret_cast<char*>( sqlsrv_malloc( *quoted_len, sizeof( char ), 1 ));
|
||||
unsigned int out_current = 0;
|
||||
// insert '0x'
|
||||
( *quoted )[ out_current++ ] = '0';
|
||||
( *quoted )[ out_current++ ] = 'x';
|
||||
for ( size_t index = 0; index < unquoted_str_len && unquoted_str[ index ] != '\0'; ++index ) {
|
||||
( *quoted )[ out_current++ ] = unquoted_str[ index ];
|
||||
}
|
||||
// null terminator
|
||||
( *quoted )[ out_current ] = '\0';
|
||||
sqlsrv_free( unquoted_str );
|
||||
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 ( encoding == SQLSRV_ENCODING_UTF8 ) {
|
||||
quotes_needed = 3;
|
||||
}
|
||||
for ( size_t index = 0; index < unquoted_len && unquoted[ index ] != '\0'; ++index ) {
|
||||
if ( unquoted[ index ] == '\'' ) {
|
||||
++quotes_needed;
|
||||
}
|
||||
}
|
||||
|
||||
for ( size_t index = 0; index < unquoted_len && unquoted[index] != '\0'; ++index ) {
|
||||
if ( unquoted[index] == '\'' ) {
|
||||
++quotes_needed;
|
||||
}
|
||||
}
|
||||
*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;
|
||||
|
||||
*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 ( encoding == SQLSRV_ENCODING_UTF8 ) {
|
||||
( *quoted )[ out_current++ ] = 'N';
|
||||
}
|
||||
// insert initial quote
|
||||
( *quoted )[ out_current++ ] = '\'';
|
||||
|
||||
// insert N if the encoding is UTF8
|
||||
if ( encoding == SQLSRV_ENCODING_UTF8 ) {
|
||||
( *quoted )[out_current++] = 'N';
|
||||
}
|
||||
// insert initial quote
|
||||
( *quoted )[out_current++] = '\'';
|
||||
for ( size_t index = 0; index < unquoted_len && unquoted[ index ] != '\0'; ++index ) {
|
||||
if ( unquoted[ index ] == '\'' ) {
|
||||
( *quoted )[ out_current++ ] = '\'';
|
||||
( *quoted )[ out_current++ ] = '\'';
|
||||
}
|
||||
else {
|
||||
( *quoted )[ out_current++ ] = unquoted[ index ];
|
||||
}
|
||||
}
|
||||
|
||||
for ( size_t index = 0; index < unquoted_len && unquoted[index] != '\0'; ++index ) {
|
||||
// trailing quote and null terminator
|
||||
( *quoted )[ out_current++ ] = '\'';
|
||||
( *quoted )[ out_current ] = '\0';
|
||||
|
||||
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';
|
||||
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// This method is not implemented by this driver.
|
||||
|
@ -1293,7 +1306,7 @@ pdo_sqlsrv_function_entry *pdo_sqlsrv_get_driver_methods( pdo_dbh_t *dbh, int ki
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return NULL; // to avoid a compiler warning
|
||||
return NULL; // to avoid a compiler warning
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -1337,8 +1350,9 @@ void add_stmt_option_key( sqlsrv_context& ctx, size_t key, HashTable* options_ht
|
|||
option_key = PDO_STMT_OPTION_EMULATE_PREPARES;
|
||||
break;
|
||||
|
||||
case SQLSRV_ATTR_FETCHES_NUMERIC_TYPE:
|
||||
option_key = PDO_STMT_OPTION_FETCHES_NUMERIC_TYPE;
|
||||
case SQLSRV_ATTR_FETCHES_NUMERIC_TYPE:
|
||||
option_key = PDO_STMT_OPTION_FETCHES_NUMERIC_TYPE;
|
||||
break;
|
||||
|
||||
default:
|
||||
CHECK_CUSTOM_ERROR( true, ctx, PDO_SQLSRV_ERROR_INVALID_STMT_OPTION ) {
|
||||
|
@ -1370,20 +1384,20 @@ void validate_stmt_options( sqlsrv_context& ctx, zval* stmt_options, _Inout_ Has
|
|||
if( stmt_options ) {
|
||||
|
||||
HashTable* options_ht = Z_ARRVAL_P( stmt_options );
|
||||
size_t int_key = -1;
|
||||
zend_string *key = NULL;
|
||||
zval* data = NULL;
|
||||
size_t int_key = -1;
|
||||
zend_string *key = NULL;
|
||||
zval* data = NULL;
|
||||
|
||||
ZEND_HASH_FOREACH_KEY_VAL( options_ht, int_key, key, data ) {
|
||||
int type = HASH_KEY_NON_EXISTENT;
|
||||
int result = 0;
|
||||
type = key ? HASH_KEY_IS_STRING : HASH_KEY_IS_LONG;
|
||||
CHECK_CUSTOM_ERROR(( type != HASH_KEY_IS_LONG ), ctx, PDO_SQLSRV_ERROR_INVALID_STMT_OPTION ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
ZEND_HASH_FOREACH_KEY_VAL( options_ht, int_key, key, data ) {
|
||||
int type = HASH_KEY_NON_EXISTENT;
|
||||
int result = 0;
|
||||
type = key ? HASH_KEY_IS_STRING : HASH_KEY_IS_LONG;
|
||||
CHECK_CUSTOM_ERROR(( type != HASH_KEY_IS_LONG ), ctx, PDO_SQLSRV_ERROR_INVALID_STMT_OPTION ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
add_stmt_option_key( ctx, int_key, pdo_stmt_options_ht, data TSRMLS_CC );
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
add_stmt_option_key( ctx, int_key, pdo_stmt_options_ht, data TSRMLS_CC );
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
}
|
||||
catch( core::CoreException& ) {
|
||||
|
@ -1421,35 +1435,35 @@ void pdo_txn_isolation_conn_attr_func::func( connection_option const* /*option*/
|
|||
|
||||
// READ_COMMITTED
|
||||
if(( val_len == ( sizeof( PDOTxnIsolationValues::READ_COMMITTED ) - 1 )
|
||||
&& !_stricmp( val, PDOTxnIsolationValues::READ_COMMITTED ))) {
|
||||
&& !strcasecmp( val, PDOTxnIsolationValues::READ_COMMITTED ))) {
|
||||
|
||||
out_val = SQL_TXN_READ_COMMITTED;
|
||||
}
|
||||
|
||||
// READ_UNCOMMITTED
|
||||
else if(( val_len == ( sizeof( PDOTxnIsolationValues::READ_UNCOMMITTED ) - 1 )
|
||||
&& !_stricmp( val, PDOTxnIsolationValues::READ_UNCOMMITTED ))) {
|
||||
&& !strcasecmp( val, PDOTxnIsolationValues::READ_UNCOMMITTED ))) {
|
||||
|
||||
out_val = SQL_TXN_READ_UNCOMMITTED;
|
||||
}
|
||||
|
||||
// REPEATABLE_READ
|
||||
else if(( val_len == ( sizeof( PDOTxnIsolationValues::REPEATABLE_READ ) - 1 )
|
||||
&& !_stricmp( val, PDOTxnIsolationValues::REPEATABLE_READ ))) {
|
||||
&& !strcasecmp( val, PDOTxnIsolationValues::REPEATABLE_READ ))) {
|
||||
|
||||
out_val = SQL_TXN_REPEATABLE_READ;
|
||||
}
|
||||
|
||||
// SERIALIZABLE
|
||||
else if(( val_len == ( sizeof( PDOTxnIsolationValues::SERIALIZABLE ) - 1 )
|
||||
&& !_stricmp( val, PDOTxnIsolationValues::SERIALIZABLE ))) {
|
||||
&& !strcasecmp( val, PDOTxnIsolationValues::SERIALIZABLE ))) {
|
||||
|
||||
out_val = SQL_TXN_SERIALIZABLE;
|
||||
}
|
||||
|
||||
// SNAPSHOT
|
||||
else if(( val_len == ( sizeof( PDOTxnIsolationValues::SNAPSHOT ) - 1 )
|
||||
&& !_stricmp( val, PDOTxnIsolationValues::SNAPSHOT ))) {
|
||||
&& !strcasecmp( val, PDOTxnIsolationValues::SNAPSHOT ))) {
|
||||
|
||||
out_val = SQL_TXN_SS_SNAPSHOT;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
//---------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#include "php_pdo_sqlsrv.h"
|
||||
#include <psapi.h>
|
||||
|
||||
#ifdef ZTS
|
||||
ZEND_TSRMLS_CACHE_DEFINE();
|
||||
|
@ -46,45 +45,11 @@ pdo_driver_t pdo_sqlsrv_driver = {
|
|||
pdo_sqlsrv_db_handle_factory
|
||||
};
|
||||
|
||||
const char PDO_DLL_NAME[] = "php_pdo.dll";
|
||||
|
||||
// PHP_DEBUG is always defined as either 0 or 1
|
||||
#if PHP_DEBUG == 1 && !defined(ZTS)
|
||||
|
||||
const char PHP_DLL_NAME[] = "php7_debug.dll";
|
||||
|
||||
#elif PHP_DEBUG == 1 && defined(ZTS)
|
||||
|
||||
const char PHP_DLL_NAME[] = "php7ts_debug.dll";
|
||||
|
||||
#elif PHP_DEBUG == 0 && !defined(ZTS)
|
||||
|
||||
const char PHP_DLL_NAME[] = "php7.dll";
|
||||
|
||||
#elif PHP_DEBUG == 0 && defined(ZTS)
|
||||
|
||||
const char PHP_DLL_NAME[] = "php7ts.dll";
|
||||
|
||||
#else
|
||||
|
||||
#error Invalid combination of PHP_DEBUG and ZTS macros
|
||||
|
||||
#endif
|
||||
|
||||
typedef PDO_API int (*pdo_register_func)(pdo_driver_t *);
|
||||
|
||||
// function pointers to register and unregister this driver
|
||||
pdo_register_func pdo_register_driver;
|
||||
pdo_register_func pdo_unregister_driver;
|
||||
|
||||
// functions to register SQLSRV constants with the PDO class
|
||||
// (It's in all CAPS so it looks like the Zend macros that do similar work)
|
||||
void REGISTER_PDO_SQLSRV_CLASS_CONST_LONG( char const* name, long value TSRMLS_DC );
|
||||
void REGISTER_PDO_SQLSRV_CLASS_CONST_STRING( char const* name, char const* value TSRMLS_DC );
|
||||
|
||||
// return the Zend class entry for the PDO dbh (connection) class
|
||||
zend_class_entry* (*pdo_get_dbh_class)( void );
|
||||
|
||||
struct sqlsrv_attr_pdo_constant {
|
||||
const char *name;
|
||||
int value;
|
||||
|
@ -96,8 +61,8 @@ extern sqlsrv_attr_pdo_constant pdo_attr_constants[];
|
|||
}
|
||||
|
||||
static zend_module_dep pdo_sqlsrv_depends[] = {
|
||||
ZEND_MOD_REQUIRED("pdo")
|
||||
{NULL, NULL, NULL}
|
||||
ZEND_MOD_REQUIRED("pdo")
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
|
@ -116,7 +81,7 @@ zend_module_entry g_pdo_sqlsrv_module_entry =
|
|||
{
|
||||
STANDARD_MODULE_HEADER_EX,
|
||||
NULL,
|
||||
pdo_sqlsrv_depends,
|
||||
pdo_sqlsrv_depends,
|
||||
"pdo_sqlsrv",
|
||||
pdo_sqlsrv_functions, // exported function table
|
||||
// initialization and shutdown functions
|
||||
|
@ -134,15 +99,10 @@ zend_module_entry g_pdo_sqlsrv_module_entry =
|
|||
STANDARD_MODULE_PROPERTIES_EX
|
||||
};
|
||||
|
||||
// functions dynamically linked from the PDO (or PHP) dll and called by other parts of the driver
|
||||
zend_class_entry* (*pdo_get_exception_class)( void );
|
||||
int (*pdo_subst_named_params)(pdo_stmt_t *stmt, char *inquery, size_t inquery_len,
|
||||
char **outquery, size_t *outquery_len TSRMLS_DC);
|
||||
|
||||
// called by Zend for each parameter in the g_pdo_errors_ht hash table when it is destroyed
|
||||
void pdo_error_dtor(zval* elem) {
|
||||
pdo_error* error_to_ignore = reinterpret_cast<pdo_error*>(Z_PTR_P(elem));
|
||||
pefree(error_to_ignore, 1);
|
||||
void pdo_error_dtor( zval* elem ) {
|
||||
pdo_error* error_to_ignore = reinterpret_cast<pdo_error*>( Z_PTR_P( elem ) );
|
||||
pefree( error_to_ignore, 1 );
|
||||
}
|
||||
|
||||
// Module initialization
|
||||
|
@ -155,9 +115,9 @@ PHP_MINIT_FUNCTION(pdo_sqlsrv)
|
|||
// our global variables are initialized in the RINIT function
|
||||
#if defined(ZTS)
|
||||
if( ts_allocate_id( &pdo_sqlsrv_globals_id,
|
||||
sizeof( zend_pdo_sqlsrv_globals ),
|
||||
(ts_allocate_ctor) NULL,
|
||||
(ts_allocate_dtor) NULL ) == 0 )
|
||||
sizeof( zend_pdo_sqlsrv_globals ),
|
||||
(ts_allocate_ctor) NULL,
|
||||
(ts_allocate_dtor) NULL ) == 0 )
|
||||
return FAILURE;
|
||||
ZEND_TSRMLS_CACHE_UPDATE();
|
||||
#endif
|
||||
|
@ -168,62 +128,6 @@ PHP_MINIT_FUNCTION(pdo_sqlsrv)
|
|||
|
||||
LOG( SEV_NOTICE, "pdo_sqlsrv: entering minit" );
|
||||
|
||||
// PHP extensions may be either external DLLs loaded by PHP or statically compiled into the PHP dll
|
||||
// This becomes an issue when we are dependent on other extensions, e.g. PDO. Normally this is solved
|
||||
// by the build process by linking our extension to the appropriate import library (either php*.dll or php_pdo.dll)
|
||||
// However, this leaves us with a problem that the extension has a dependency on that build type.
|
||||
// Since we don't distribute our extension with PHP directly (yet), it would mean that we would have to have SKUs
|
||||
// for both types of PDO builds, internal and external. Rather than this, we just dynamically link the PDO routines we call
|
||||
// against either the PDO dll if it exists and is loaded, otherwise against the PHP dll directly.
|
||||
|
||||
DWORD needed = 0;
|
||||
HANDLE hprocess = GetCurrentProcess();
|
||||
HMODULE pdo_hmodule;
|
||||
|
||||
pdo_hmodule = GetModuleHandle( PDO_DLL_NAME );
|
||||
if( pdo_hmodule == 0 ) {
|
||||
|
||||
pdo_hmodule = GetModuleHandle( PHP_DLL_NAME );
|
||||
if( pdo_hmodule == NULL ) {
|
||||
LOG( SEV_ERROR, "Failed to get PHP module handle." );
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
pdo_register_driver = reinterpret_cast<pdo_register_func>( GetProcAddress( pdo_hmodule, "php_pdo_register_driver" ));
|
||||
if( pdo_register_driver == NULL ) {
|
||||
LOG( SEV_ERROR, "Failed to register driver." );
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
pdo_unregister_driver = reinterpret_cast<pdo_register_func>( GetProcAddress( pdo_hmodule, "php_pdo_unregister_driver" ));
|
||||
if( pdo_unregister_driver == NULL ) {
|
||||
LOG( SEV_ERROR, "Failed to register driver." );
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
pdo_get_exception_class = reinterpret_cast<zend_class_entry* (*)(void)>( GetProcAddress( pdo_hmodule,
|
||||
"php_pdo_get_exception" ));
|
||||
if( pdo_get_exception_class == NULL ) {
|
||||
LOG( SEV_ERROR, "Failed to register driver." );
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
pdo_get_dbh_class = reinterpret_cast<zend_class_entry* (*)(void)>( GetProcAddress( pdo_hmodule, "php_pdo_get_dbh_ce" ));
|
||||
if( pdo_get_dbh_class == NULL ) {
|
||||
LOG( SEV_ERROR, "Failed to register driver." );
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
pdo_subst_named_params =
|
||||
reinterpret_cast<int (*)(pdo_stmt_t *stmt, char *inquery, size_t inquery_len,
|
||||
char **outquery, size_t *outquery_len TSRMLS_DC)>(
|
||||
GetProcAddress( pdo_hmodule, "pdo_parse_params" ));
|
||||
if( pdo_subst_named_params == NULL ) {
|
||||
LOG( SEV_ERROR, "Failed to register driver." );
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// initialize list of pdo errors
|
||||
g_pdo_errors_ht = reinterpret_cast<HashTable*>( pemalloc( sizeof( HashTable ), 1 ));
|
||||
::zend_hash_init( g_pdo_errors_ht, 50, NULL, pdo_error_dtor /*pDestructor*/, 1 );
|
||||
|
@ -263,13 +167,11 @@ PHP_MINIT_FUNCTION(pdo_sqlsrv)
|
|||
return FAILURE;
|
||||
}
|
||||
|
||||
pdo_register_driver( &pdo_sqlsrv_driver );
|
||||
php_pdo_register_driver( &pdo_sqlsrv_driver );
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
// Module shutdown function
|
||||
|
||||
// Module shutdown function
|
||||
// This function is called once per execution of the Zend engine
|
||||
|
||||
|
@ -281,7 +183,7 @@ PHP_MSHUTDOWN_FUNCTION(pdo_sqlsrv)
|
|||
|
||||
UNREGISTER_INI_ENTRIES();
|
||||
|
||||
pdo_unregister_driver( &pdo_sqlsrv_driver );
|
||||
php_pdo_unregister_driver( &pdo_sqlsrv_driver );
|
||||
|
||||
// clean up the list of pdo errors
|
||||
zend_hash_destroy( g_pdo_errors_ht );
|
||||
|
@ -352,8 +254,9 @@ namespace {
|
|||
|
||||
void REGISTER_PDO_SQLSRV_CLASS_CONST_LONG( char const* name, long value TSRMLS_DC )
|
||||
{
|
||||
zend_class_entry* zend_class = pdo_get_dbh_class();
|
||||
SQLSRV_ASSERT( zend_class != NULL, "REGISTER_PDO_SQLSRV_CLASS_CONST_LONG: pdo_get_dbh_class failed" );
|
||||
zend_class_entry* zend_class = php_pdo_get_dbh_ce();
|
||||
|
||||
SQLSRV_ASSERT( zend_class != NULL, "REGISTER_PDO_SQLSRV_CLASS_CONST_LONG: php_pdo_get_dbh_ce failed");
|
||||
int zr = zend_declare_class_constant_long( zend_class, const_cast<char*>( name ), strlen( name ), value TSRMLS_CC );
|
||||
if( zr == FAILURE ) {
|
||||
throw core::CoreException();
|
||||
|
@ -362,8 +265,9 @@ namespace {
|
|||
|
||||
void REGISTER_PDO_SQLSRV_CLASS_CONST_STRING( char const* name, char const* value TSRMLS_DC )
|
||||
{
|
||||
zend_class_entry* zend_class = pdo_get_dbh_class();
|
||||
SQLSRV_ASSERT( zend_class != NULL, "REGISTER_PDO_SQLSRV_CLASS_CONST_STRING: pdo_get_dbh_class failed" );
|
||||
zend_class_entry* zend_class = php_pdo_get_dbh_ce();
|
||||
|
||||
SQLSRV_ASSERT( zend_class != NULL, "REGISTER_PDO_SQLSRV_CLASS_CONST_STRING: php_pdo_get_dbh_ce failed");
|
||||
int zr = zend_declare_class_constant_string( zend_class, const_cast<char*>( name ), strlen( name ), const_cast<char*>( value ) TSRMLS_CC );
|
||||
if( zr == FAILURE ) {
|
||||
|
||||
|
@ -372,15 +276,15 @@ namespace {
|
|||
}
|
||||
|
||||
// array of pdo constants.
|
||||
sqlsrv_attr_pdo_constant pdo_attr_constants[] = {
|
||||
sqlsrv_attr_pdo_constant pdo_attr_constants[] = {
|
||||
|
||||
// driver specific attributes
|
||||
{ "SQLSRV_ATTR_ENCODING" , SQLSRV_ATTR_ENCODING },
|
||||
{ "SQLSRV_ATTR_QUERY_TIMEOUT" , SQLSRV_ATTR_QUERY_TIMEOUT },
|
||||
{ "SQLSRV_ATTR_DIRECT_QUERY" , SQLSRV_ATTR_DIRECT_QUERY },
|
||||
{ "SQLSRV_ATTR_CURSOR_SCROLL_TYPE" , SQLSRV_ATTR_CURSOR_SCROLL_TYPE },
|
||||
{ "SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE", SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE },
|
||||
{ "SQLSRV_ATTR_FETCHES_NUMERIC_TYPE", SQLSRV_ATTR_FETCHES_NUMERIC_TYPE },
|
||||
// driver specific attributes
|
||||
{ "SQLSRV_ATTR_ENCODING" , SQLSRV_ATTR_ENCODING },
|
||||
{ "SQLSRV_ATTR_QUERY_TIMEOUT" , SQLSRV_ATTR_QUERY_TIMEOUT },
|
||||
{ "SQLSRV_ATTR_DIRECT_QUERY" , SQLSRV_ATTR_DIRECT_QUERY },
|
||||
{ "SQLSRV_ATTR_CURSOR_SCROLL_TYPE" , SQLSRV_ATTR_CURSOR_SCROLL_TYPE },
|
||||
{ "SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE", SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE },
|
||||
{ "SQLSRV_ATTR_FETCHES_NUMERIC_TYPE", SQLSRV_ATTR_FETCHES_NUMERIC_TYPE },
|
||||
|
||||
// used for the size for output parameters: PDO::PARAM_INT and PDO::PARAM_BOOL use the default size of int,
|
||||
// PDO::PARAM_STR uses the size of the string in the variable
|
||||
|
|
|
@ -29,6 +29,8 @@ conn_string_parser:: conn_string_parser( sqlsrv_context& ctx, const char* dsn, i
|
|||
this->conn_options_ht = conn_options_ht;
|
||||
this->pos = -1;
|
||||
this->ctx = &ctx;
|
||||
this->current_key = 0;
|
||||
this->current_key_name = NULL;
|
||||
}
|
||||
|
||||
// Move to the next character
|
||||
|
@ -131,7 +133,7 @@ void conn_string_parser::validate_key(const char *key, int key_len TSRMLS_DC )
|
|||
for( int i=0; PDO_CONN_OPTS[ i ].conn_option_key != SQLSRV_CONN_OPTION_INVALID; ++i )
|
||||
{
|
||||
// discard the null terminator.
|
||||
if( new_len == ( PDO_CONN_OPTS[ i ].sqlsrv_len - 1 ) && !_strnicmp( key, PDO_CONN_OPTS[ i ].sqlsrv_name, new_len )) {
|
||||
if( new_len == ( PDO_CONN_OPTS[ i ].sqlsrv_len - 1 ) && !strncasecmp( key, PDO_CONN_OPTS[ i ].sqlsrv_name, new_len )) {
|
||||
|
||||
this->current_key = PDO_CONN_OPTS[ i ].conn_option_key;
|
||||
this->current_key_name = PDO_CONN_OPTS[ i ].sqlsrv_name;
|
||||
|
@ -143,9 +145,10 @@ void conn_string_parser::validate_key(const char *key, int key_len TSRMLS_DC )
|
|||
sqlsrv_malloc_auto_ptr<char> key_name;
|
||||
key_name = static_cast<char*>( sqlsrv_malloc( new_len + 1 ));
|
||||
memcpy_s( key_name, new_len + 1 ,key, new_len );
|
||||
|
||||
key_name[ new_len ] = '\0';
|
||||
|
||||
THROW_PDO_ERROR( this->ctx, PDO_SQLSRV_ERROR_INVALID_DSN_KEY, key_name );
|
||||
THROW_PDO_ERROR( this->ctx, PDO_SQLSRV_ERROR_INVALID_DSN_KEY, static_cast<char*>( key_name ) );
|
||||
}
|
||||
|
||||
// Primary function which parses the connection string/DSN.
|
||||
|
|
|
@ -39,9 +39,11 @@ const int SQL_SERVER_IDENT_SIZE_MAX = 128;
|
|||
|
||||
inline SQLSMALLINT pdo_fetch_ori_to_odbc_fetch_ori (enum pdo_fetch_orientation ori)
|
||||
{
|
||||
SQLSRV_ASSERT( ori >= PDO_FETCH_ORI_NEXT && ori <= PDO_FETCH_ORI_REL, "Fetch orientation out of range." );
|
||||
SQLSRV_ASSERT( ori >= PDO_FETCH_ORI_NEXT && ori <= PDO_FETCH_ORI_REL, "Fetch orientation out of range.");
|
||||
#ifdef _WIN32
|
||||
OACR_WARNING_SUPPRESS( 26001, "Buffer length verified above" );
|
||||
OACR_WARNING_SUPPRESS( 26000, "Buffer length verified above" );
|
||||
#endif
|
||||
return odbc_fetch_orientation[ori];
|
||||
}
|
||||
|
||||
|
@ -202,9 +204,9 @@ void set_stmt_encoding( sqlsrv_stmt* stmt, zval* value_z TSRMLS_DC )
|
|||
// internal helper function to free meta data structures allocated
|
||||
void meta_data_free( field_meta_data* meta )
|
||||
{
|
||||
if( meta->field_name ) {
|
||||
meta->field_name.reset();
|
||||
}
|
||||
if( meta->field_name ) {
|
||||
meta->field_name.reset();
|
||||
}
|
||||
sqlsrv_free( meta );
|
||||
}
|
||||
|
||||
|
@ -332,18 +334,31 @@ void stmt_option_emulate_prepares:: operator()( sqlsrv_stmt* stmt, stmt_option c
|
|||
|
||||
void stmt_option_fetch_numeric:: operator()( sqlsrv_stmt* stmt, stmt_option const* /*opt*/, zval* value_z TSRMLS_DC )
|
||||
{
|
||||
pdo_sqlsrv_stmt *pdo_stmt = static_cast<pdo_sqlsrv_stmt*>( stmt );
|
||||
pdo_stmt->fetch_numeric = ( zend_is_true( value_z )) ? true : false;
|
||||
pdo_sqlsrv_stmt *pdo_stmt = static_cast<pdo_sqlsrv_stmt*>( stmt );
|
||||
pdo_stmt->fetch_numeric = ( zend_is_true( value_z )) ? true : false;
|
||||
}
|
||||
|
||||
|
||||
// log a function entry point
|
||||
#ifndef _WIN32
|
||||
#define PDO_LOG_STMT_ENTRY \
|
||||
{ \
|
||||
pdo_sqlsrv_stmt* driver_stmt = reinterpret_cast<pdo_sqlsrv_stmt*>( stmt->driver_data ); \
|
||||
driver_stmt->set_func( __FUNCTION__ ); \
|
||||
int length = strlen( __FUNCTION__ ) + strlen( ": entering" ); \
|
||||
char func[length+1]; \
|
||||
strcpy_s( func, sizeof( __FUNCTION__ ), __FUNCTION__ ); \
|
||||
strcat_s( func, length+1, ": entering" ); \
|
||||
LOG( SEV_NOTICE, func ); \
|
||||
}
|
||||
#else
|
||||
#define PDO_LOG_STMT_ENTRY \
|
||||
{ \
|
||||
pdo_sqlsrv_stmt* driver_stmt = reinterpret_cast<pdo_sqlsrv_stmt*>( stmt->driver_data ); \
|
||||
driver_stmt->set_func( __FUNCTION__ ); \
|
||||
LOG( SEV_NOTICE, __FUNCTION__ ## ": entering" ); \
|
||||
}
|
||||
#endif
|
||||
|
||||
// PDO SQLSRV statement destructor
|
||||
pdo_sqlsrv_stmt::~pdo_sqlsrv_stmt( void )
|
||||
|
@ -440,7 +455,7 @@ int pdo_sqlsrv_stmt_describe_col(pdo_stmt_t *stmt, int colno TSRMLS_DC)
|
|||
|
||||
// Set the name
|
||||
column_data->name = zend_string_init( (const char*)core_meta_data->field_name.get(), core_meta_data->field_name_len, 0 );
|
||||
core_meta_data->field_name.reset();
|
||||
core_meta_data->field_name.reset();
|
||||
|
||||
// Set the maxlen
|
||||
column_data->maxlen = ( core_meta_data->field_precision > 0 ) ? core_meta_data->field_precision : core_meta_data->field_size;
|
||||
|
@ -698,9 +713,6 @@ int pdo_sqlsrv_stmt_get_col_data(pdo_stmt_t *stmt, int colno,
|
|||
|
||||
// Let PDO free the memory after use.
|
||||
*caller_frees = 1;
|
||||
|
||||
// set the metadata for the current column
|
||||
pdo_column_data* column_data = &(stmt->columns[colno]);
|
||||
|
||||
// translate the pdo type to a type the core layer understands
|
||||
sqlsrv_phptype sqlsrv_php_type;
|
||||
|
@ -756,7 +768,7 @@ int pdo_sqlsrv_stmt_get_col_data(pdo_stmt_t *stmt, int colno,
|
|||
core_sqlsrv_get_field( driver_stmt, colno, sqlsrv_php_type, false, *(reinterpret_cast<void**>(ptr)),
|
||||
reinterpret_cast<SQLLEN*>( len ), true, &sqlsrv_phptype_out TSRMLS_CC );
|
||||
|
||||
zval* zval_ptr = ( zval* )( sqlsrv_malloc( sizeof( zval )));
|
||||
zval* zval_ptr = reinterpret_cast<zval*>( sqlsrv_malloc( sizeof( zval )));
|
||||
*zval_ptr = convert_to_zval( sqlsrv_phptype_out, reinterpret_cast<void**>( ptr ), *len );
|
||||
*ptr = reinterpret_cast<char*>( zval_ptr );
|
||||
|
||||
|
@ -787,7 +799,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* driver_stmt = static_cast<pdo_sqlsrv_stmt*>( stmt->driver_data );
|
||||
pdo_sqlsrv_stmt* driver_stmt = static_cast<pdo_sqlsrv_stmt*>( stmt->driver_data );
|
||||
|
||||
try {
|
||||
|
||||
|
@ -896,11 +908,11 @@ int pdo_sqlsrv_stmt_get_attr( pdo_stmt_t *stmt, zend_long attr, zval *return_val
|
|||
break;
|
||||
}
|
||||
|
||||
case SQLSRV_ATTR_FETCHES_NUMERIC_TYPE:
|
||||
{
|
||||
ZVAL_BOOL( return_value, driver_stmt->fetch_numeric );
|
||||
break;
|
||||
}
|
||||
case SQLSRV_ATTR_FETCHES_NUMERIC_TYPE:
|
||||
{
|
||||
ZVAL_BOOL( return_value, driver_stmt->fetch_numeric );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
THROW_PDO_ERROR( driver_stmt, PDO_SQLSRV_ERROR_INVALID_STMT_ATTR );
|
||||
|
@ -966,7 +978,12 @@ int pdo_sqlsrv_stmt_get_col_meta(pdo_stmt_t *stmt, zend_long colno, zval *return
|
|||
long pdo_type = sql_type_to_pdo_type( core_meta_data->field_type );
|
||||
switch( pdo_type ) {
|
||||
case PDO_PARAM_STR:
|
||||
add_assoc_string( return_value, "native_type", "string" );
|
||||
{
|
||||
//Declarations eliminate compiler warnings about string constant to char* conversions
|
||||
std::string key = "native_type";
|
||||
std::string str = "string";
|
||||
add_assoc_string( return_value, &key[0], &str[0] );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DIE( "pdo_sqlsrv_stmt_get_col_data: Unknown PDO type returned" );
|
||||
|
@ -1076,11 +1093,11 @@ int pdo_sqlsrv_stmt_param_hook(pdo_stmt_t *stmt,
|
|||
|
||||
// since the param isn't reliable, we don't do anything here
|
||||
case PDO_PARAM_EVT_ALLOC:
|
||||
// if emulate prepare is on, set the bind_param_encoding so it can be used in PDO::quote when binding parameters on the client side
|
||||
if ( stmt->supports_placeholders == PDO_PLACEHOLDER_NONE ) {
|
||||
pdo_sqlsrv_dbh* driver_dbh = reinterpret_cast<pdo_sqlsrv_dbh*>( stmt->dbh->driver_data );
|
||||
driver_dbh->bind_param_encoding = static_cast<SQLSRV_ENCODING>( Z_LVAL( param->driver_params ));
|
||||
}
|
||||
// if emulate prepare is on, set the bind_param_encoding so it can be used in PDO::quote when binding parameters on the client side
|
||||
if ( stmt->supports_placeholders == PDO_PLACEHOLDER_NONE ) {
|
||||
pdo_sqlsrv_dbh* driver_dbh = reinterpret_cast<pdo_sqlsrv_dbh*>( stmt->dbh->driver_data );
|
||||
driver_dbh->bind_param_encoding = static_cast<SQLSRV_ENCODING>( Z_LVAL( param->driver_params ));
|
||||
}
|
||||
break;
|
||||
case PDO_PARAM_EVT_FREE:
|
||||
break;
|
||||
|
@ -1239,7 +1256,7 @@ int pdo_sqlsrv_stmt_param_hook(pdo_stmt_t *stmt,
|
|||
if( !param->is_param ) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
core_sqlsrv_post_param( reinterpret_cast<sqlsrv_stmt*>( stmt->driver_data ), param->paramno,
|
||||
&(param->parameter) TSRMLS_CC );
|
||||
}
|
||||
|
@ -1281,28 +1298,28 @@ sqlsrv_phptype pdo_sqlsrv_stmt::sql_type_to_php_type( SQLINTEGER sql_type, SQLUI
|
|||
}
|
||||
|
||||
switch( sql_type ) {
|
||||
case SQL_BIT:
|
||||
case SQL_INTEGER:
|
||||
case SQL_SMALLINT:
|
||||
case SQL_TINYINT:
|
||||
if ( this->fetch_numeric ) {
|
||||
sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_INT;
|
||||
}
|
||||
else {
|
||||
sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_STRING;
|
||||
sqlsrv_phptype.typeinfo.encoding = local_encoding;
|
||||
}
|
||||
break;
|
||||
case SQL_FLOAT:
|
||||
case SQL_REAL:
|
||||
if ( this->fetch_numeric ) {
|
||||
sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_FLOAT;
|
||||
}
|
||||
else {
|
||||
sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_STRING;
|
||||
sqlsrv_phptype.typeinfo.encoding = local_encoding;
|
||||
}
|
||||
break;
|
||||
case SQL_BIT:
|
||||
case SQL_INTEGER:
|
||||
case SQL_SMALLINT:
|
||||
case SQL_TINYINT:
|
||||
if ( this->fetch_numeric ) {
|
||||
sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_INT;
|
||||
}
|
||||
else {
|
||||
sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_STRING;
|
||||
sqlsrv_phptype.typeinfo.encoding = local_encoding;
|
||||
}
|
||||
break;
|
||||
case SQL_FLOAT:
|
||||
case SQL_REAL:
|
||||
if ( this->fetch_numeric ) {
|
||||
sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_FLOAT;
|
||||
}
|
||||
else {
|
||||
sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_STRING;
|
||||
sqlsrv_phptype.typeinfo.encoding = local_encoding;
|
||||
}
|
||||
break;
|
||||
case SQL_BIGINT:
|
||||
case SQL_CHAR:
|
||||
case SQL_DECIMAL:
|
||||
|
|
|
@ -53,8 +53,8 @@ pdo_error PDO_ERRORS[] = {
|
|||
|
||||
{
|
||||
SQLSRV_ERROR_DRIVER_NOT_INSTALLED,
|
||||
{ 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 "
|
||||
{ IMSSP, (SQLCHAR*) "This extension requires the Microsoft ODBC Driver 13 for SQL Server to "
|
||||
"communicate with SQL Server. Access the following URL to download the ODBC Driver 13 for SQL Server "
|
||||
"for %1!s!: "
|
||||
"http://go.microsoft.com/fwlink/?LinkId=163712", -1, true }
|
||||
},
|
||||
|
@ -376,8 +376,8 @@ pdo_error PDO_ERRORS[] = {
|
|||
// Returns a sqlsrv_error for a given error code.
|
||||
sqlsrv_error_const* get_error_message(unsigned int sqlsrv_error_code) {
|
||||
|
||||
sqlsrv_error_const *error_message = NULL;
|
||||
int zr = (error_message = reinterpret_cast<sqlsrv_error_const*>(zend_hash_index_find_ptr(g_pdo_errors_ht, sqlsrv_error_code))) != NULL ? SUCCESS : FAILURE;
|
||||
sqlsrv_error_const *error_message = NULL;
|
||||
int zr = (error_message = reinterpret_cast<sqlsrv_error_const*>(zend_hash_index_find_ptr(g_pdo_errors_ht, sqlsrv_error_code))) != NULL ? SUCCESS : FAILURE;
|
||||
if( zr == FAILURE ) {
|
||||
DIE( "get_error_message: zend_hash_index_find returned failure for sqlsrv_error_code = %1!d!", sqlsrv_error_code );
|
||||
}
|
||||
|
@ -448,8 +448,8 @@ bool pdo_sqlsrv_handle_dbh_error( sqlsrv_context& ctx, unsigned int sqlsrv_error
|
|||
SQLSRV_ASSERT( err == true, "No ODBC error was found" );
|
||||
}
|
||||
|
||||
SQLSRV_ASSERT(strlen(reinterpret_cast<const char*>(error->sqlstate)) <= sizeof(dbh->error_code), "Error code overflow");
|
||||
strcpy_s(dbh->error_code, sizeof(dbh->error_code), reinterpret_cast<const char*>(error->sqlstate));
|
||||
SQLSRV_ASSERT(strlen(reinterpret_cast<const char*>(error->sqlstate)) <= sizeof(dbh->error_code), "Error code overflow");
|
||||
strcpy_s(dbh->error_code, sizeof(dbh->error_code), reinterpret_cast<const char*>(error->sqlstate));
|
||||
|
||||
switch( dbh->error_mode ) {
|
||||
case PDO_ERRMODE_EXCEPTION:
|
||||
|
@ -463,9 +463,9 @@ bool pdo_sqlsrv_handle_dbh_error( sqlsrv_context& ctx, unsigned int sqlsrv_error
|
|||
if( !warning ) {
|
||||
size_t msg_len = strlen( reinterpret_cast<const char*>( error->native_message )) + SQL_SQLSTATE_BUFSIZE
|
||||
+ MAX_DIGITS + WARNING_MIN_LENGTH + 1;
|
||||
sqlsrv_malloc_auto_ptr<char> msg;
|
||||
msg = static_cast<char*>( sqlsrv_malloc( msg_len ) );
|
||||
core_sqlsrv_format_message( msg, static_cast<unsigned int>( msg_len ), WARNING_TEMPLATE, error->sqlstate, error->native_code,
|
||||
sqlsrv_malloc_auto_ptr<char> msg;
|
||||
msg = static_cast<char*>( sqlsrv_malloc( msg_len ) );
|
||||
core_sqlsrv_format_message( msg, static_cast<unsigned int>( msg_len ), WARNING_TEMPLATE, error->sqlstate, error->native_code,
|
||||
error->native_message );
|
||||
php_error( E_WARNING, msg );
|
||||
}
|
||||
|
@ -535,7 +535,6 @@ bool pdo_sqlsrv_handle_stmt_error( sqlsrv_context& ctx, unsigned int sqlsrv_erro
|
|||
void pdo_sqlsrv_retrieve_context_error( sqlsrv_error const* last_error, zval* pdo_zval )
|
||||
{
|
||||
if( last_error ) {
|
||||
|
||||
// SQLSTATE is already present in the zval.
|
||||
add_next_index_long( pdo_zval, last_error->native_code );
|
||||
add_next_index_string( pdo_zval, reinterpret_cast<char*>( last_error->native_message ));
|
||||
|
@ -550,6 +549,7 @@ void pdo_sqlsrv_log( unsigned int severity TSRMLS_DC, const char* msg, va_list*
|
|||
}
|
||||
|
||||
DWORD rc = FormatMessage( FORMAT_MESSAGE_FROM_STRING, msg, 0, 0, log_msg, LOG_MSG_SIZE, print_args );
|
||||
|
||||
// if an error occurs for FormatMessage, we just output an internal error occurred.
|
||||
if( rc == 0 ) {
|
||||
SQLSRV_STATIC_ASSERT( sizeof( INTERNAL_FORMAT_ERROR ) < sizeof( log_msg ));
|
||||
|
@ -565,7 +565,8 @@ void pdo_sqlsrv_throw_exception( sqlsrv_error_const* error TSRMLS_DC )
|
|||
{
|
||||
zval ex_obj;
|
||||
ZVAL_UNDEF( &ex_obj );
|
||||
zend_class_entry* ex_class = pdo_get_exception_class();
|
||||
|
||||
zend_class_entry* ex_class = php_pdo_get_exception();
|
||||
|
||||
int zr = object_init_ex( &ex_obj, ex_class );
|
||||
SQLSRV_ASSERT( zr != FAILURE, "Failed to initialize exception object" );
|
||||
|
@ -586,15 +587,15 @@ void pdo_sqlsrv_throw_exception( sqlsrv_error_const* error TSRMLS_DC )
|
|||
add_next_index_string( &ex_error_info, reinterpret_cast<char*>( error->sqlstate ));
|
||||
add_next_index_long( &ex_error_info, error->native_code );
|
||||
add_next_index_string( &ex_error_info, reinterpret_cast<char*>( error->native_message ));
|
||||
//zend_update_property makes an entry in the properties_table in ex_obj point to the Z_ARRVAL( ex_error_info )
|
||||
//and the refcount of the zend_array is incremented by 1
|
||||
//zend_update_property makes an entry in the properties_table in ex_obj point to the Z_ARRVAL( ex_error_info )
|
||||
//and the refcount of the zend_array is incremented by 1
|
||||
zend_update_property( ex_class, &ex_obj, EXCEPTION_PROPERTY_ERRORINFO, sizeof( EXCEPTION_PROPERTY_ERRORINFO ) - 1,
|
||||
&ex_error_info TSRMLS_CC );
|
||||
|
||||
//DELREF ex_error_info here to decrement the refcount of the zend_array is 1
|
||||
//the global hashtable EG(exception) then points to the zend_object in ex_obj in zend_throw_exception_object;
|
||||
//this ensure when EG(exception) cleans itself at php shutdown, the zend_array allocated is properly destroyed
|
||||
Z_DELREF( ex_error_info );
|
||||
//DELREF ex_error_info here to decrement the refcount of the zend_array is 1
|
||||
//the global hashtable EG(exception) then points to the zend_object in ex_obj in zend_throw_exception_object;
|
||||
//this ensure when EG(exception) cleans itself at php shutdown, the zend_array allocated is properly destroyed
|
||||
Z_DELREF( ex_error_info );
|
||||
zend_throw_exception_object( &ex_obj TSRMLS_CC );
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@ extern "C" {
|
|||
|
||||
#include "pdo/php_pdo.h"
|
||||
#include "pdo/php_pdo_driver.h"
|
||||
#include "pdo/php_pdo_int.h"
|
||||
|
||||
}
|
||||
|
||||
|
@ -48,7 +47,7 @@ enum PDO_SQLSRV_ATTR {
|
|||
SQLSRV_ATTR_DIRECT_QUERY,
|
||||
SQLSRV_ATTR_CURSOR_SCROLL_TYPE,
|
||||
SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE,
|
||||
SQLSRV_ATTR_FETCHES_NUMERIC_TYPE,
|
||||
SQLSRV_ATTR_FETCHES_NUMERIC_TYPE,
|
||||
};
|
||||
|
||||
// valid set of values for TransactionIsolation connection option
|
||||
|
@ -111,6 +110,8 @@ extern sqlsrv_context* g_henv_ncp;
|
|||
// module global variables (initialized in minit and freed in mshutdown)
|
||||
extern HashTable* g_pdo_errors_ht;
|
||||
|
||||
#define phpext_pdo_sqlsrv_ptr &g_pdo_sqlsrv_module_entry
|
||||
|
||||
// module initialization
|
||||
PHP_MINIT_FUNCTION(pdo_sqlsrv);
|
||||
// module shutdown function
|
||||
|
@ -155,7 +156,7 @@ class conn_string_parser
|
|||
inline bool is_white_space( char c );
|
||||
bool discard_white_spaces( void );
|
||||
int discard_trailing_white_spaces( const char* str, int len );
|
||||
void conn_string_parser::validate_key( const char *key, int key_len TSRMLS_DC );
|
||||
void validate_key( const char *key, int key_len TSRMLS_DC );
|
||||
void add_key_value_pair( const char* value, int len TSRMLS_DC );
|
||||
|
||||
public:
|
||||
|
@ -177,8 +178,8 @@ struct pdo_sqlsrv_dbh : public sqlsrv_conn {
|
|||
bool direct_query;
|
||||
long query_timeout;
|
||||
zend_long client_buffer_max_size;
|
||||
SQLSRV_ENCODING bind_param_encoding;
|
||||
bool fetch_numeric;
|
||||
SQLSRV_ENCODING bind_param_encoding;
|
||||
bool fetch_numeric;
|
||||
|
||||
pdo_sqlsrv_dbh( SQLHANDLE h, error_callback e, void* driver TSRMLS_DC );
|
||||
};
|
||||
|
@ -214,7 +215,7 @@ struct stmt_option_emulate_prepares : public stmt_option_functor {
|
|||
};
|
||||
|
||||
struct stmt_option_fetch_numeric : public stmt_option_functor {
|
||||
virtual void operator()( sqlsrv_stmt* stmt, stmt_option const* /*opt*/, zval* value_z TSRMLS_DC );
|
||||
virtual void operator()( sqlsrv_stmt* stmt, stmt_option const* /*opt*/, zval* value_z TSRMLS_DC );
|
||||
};
|
||||
|
||||
extern struct pdo_stmt_methods pdo_sqlsrv_stmt_methods;
|
||||
|
@ -228,11 +229,11 @@ struct pdo_sqlsrv_stmt : public sqlsrv_stmt {
|
|||
direct_query_subst_string( NULL ),
|
||||
direct_query_subst_string_len( 0 ),
|
||||
bound_column_param_types( NULL ),
|
||||
fetch_numeric( false )
|
||||
fetch_numeric( false )
|
||||
{
|
||||
pdo_sqlsrv_dbh* db = static_cast<pdo_sqlsrv_dbh*>( c );
|
||||
direct_query = db->direct_query;
|
||||
fetch_numeric = db->fetch_numeric;
|
||||
fetch_numeric = db->fetch_numeric;
|
||||
}
|
||||
|
||||
virtual ~pdo_sqlsrv_stmt( void );
|
||||
|
@ -248,7 +249,7 @@ struct pdo_sqlsrv_stmt : public sqlsrv_stmt {
|
|||
// meta data for current result set
|
||||
std::vector<field_meta_data*, sqlsrv_allocator< field_meta_data* > > current_meta_data;
|
||||
pdo_param_type* bound_column_param_types;
|
||||
bool fetch_numeric;
|
||||
bool fetch_numeric;
|
||||
};
|
||||
|
||||
|
||||
|
@ -273,9 +274,6 @@ bool pdo_sqlsrv_handle_dbh_error( sqlsrv_context& ctx, unsigned int sqlsrv_error
|
|||
bool pdo_sqlsrv_handle_stmt_error( sqlsrv_context& ctx, unsigned int sqlsrv_error_code, bool warning TSRMLS_DC,
|
||||
va_list* print_args );
|
||||
|
||||
// pointer to the function to return the class entry for the PDO exception Set in MINIT
|
||||
extern zend_class_entry* (*pdo_get_exception_class)( void );
|
||||
|
||||
// common routine to transfer a sqlsrv_context's error to a PDO zval
|
||||
void pdo_sqlsrv_retrieve_context_error( sqlsrv_error const* last_error, zval* pdo_zval );
|
||||
|
||||
|
@ -375,7 +373,7 @@ enum PDO_ERROR_CODES {
|
|||
extern pdo_error PDO_ERRORS[];
|
||||
|
||||
#define THROW_PDO_ERROR( ctx, custom, ... ) \
|
||||
call_error_handler( ctx, custom TSRMLS_CC, false, __VA_ARGS__ ); \
|
||||
call_error_handler( ctx, custom TSRMLS_CC, false, ## __VA_ARGS__ ); \
|
||||
throw pdo::PDOException();
|
||||
|
||||
namespace pdo {
|
||||
|
@ -390,14 +388,8 @@ namespace pdo {
|
|||
|
||||
} // namespace pdo
|
||||
|
||||
// called pdo_parse_params in php_pdo_driver.h
|
||||
// we renamed it for 2 reasons: 1) we can't have the same name since it would conflict with our dynamic linking, and
|
||||
// 2) this is a more precise name
|
||||
extern int (*pdo_subst_named_params)(pdo_stmt_t *stmt, char *inquery, size_t inquery_len,
|
||||
char **outquery, size_t *outquery_len TSRMLS_DC);
|
||||
|
||||
// logger for pdo_sqlsrv called by the core layer when it wants to log something with the LOG macro
|
||||
void pdo_sqlsrv_log( unsigned int severity TSRMLS_DC, const char* msg, va_list* print_args );
|
||||
|
||||
#endif /* PHP_PDO_SQLSRV_H */
|
||||
#endif /* PHP_PDO_SQLSRV_H */
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Contents: Version resource
|
||||
//
|
||||
// Microsoft Drivers 4.0 for PHP for SQL Server
|
||||
// Microsoft Drivers 4.1 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
@ -59,7 +59,7 @@ BEGIN
|
|||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "Comments", "This product includes PHP software that is freely available from http://www.php.net/software/. Copyright © 2001-2016 The PHP Group. All rights reserved.\0"
|
||||
VALUE "Comments", "This product includes PHP software that is freely available from http://www.php.net/software/. Copyright © 2001-2016 The PHP Group. All rights reserved.\0"
|
||||
VALUE "CompanyName", "Microsoft Corp.\0"
|
||||
VALUE "FileDescription", "Microsoft Drivers for PHP for SQL Server (PDO Driver)\0"
|
||||
VALUE "FileVersion", STRVER4(SQLVERSION_MAJOR,SQLVERSION_MINOR, SQLVERSION_RELEASE, SQLVERSION_BUILD)
|
||||
|
|
41
source/sqlsrv/config.m4
Normal file
41
source/sqlsrv/config.m4
Normal file
|
@ -0,0 +1,41 @@
|
|||
PHP_ARG_ENABLE(sqlsrv, whether to enable sqlsrv functions,
|
||||
[ --disable-sqlsrv Disable sqlsrv functions], yes)
|
||||
|
||||
if test "$PHP_SQLSRV" != "no"; then
|
||||
sqlsrv_src_class="\
|
||||
conn.cpp \
|
||||
util.cpp \
|
||||
init.cpp \
|
||||
stmt.cpp \
|
||||
"
|
||||
shared_src_class="\
|
||||
shared/core_conn.cpp \
|
||||
shared/core_results.cpp \
|
||||
shared/core_stream.cpp \
|
||||
shared/core_init.cpp \
|
||||
shared/core_stmt.cpp \
|
||||
shared/core_util.cpp \
|
||||
shared/FormattedPrint.cpp \
|
||||
shared/localizationimpl.cpp \
|
||||
shared/StringFunctions.cpp \
|
||||
"
|
||||
AC_MSG_CHECKING([for SQLSRV headers])
|
||||
if test -f $srcdir/ext/sqlsrv/shared/core_sqlsrv.h; then
|
||||
sqlsrv_inc_path=$srcdir/ext/sqlsrv/shared/
|
||||
elif test -f $srcdir/shared/core_sqlsrv.h; then
|
||||
sqlsrv_inc_path=$srcdir/shared/
|
||||
else
|
||||
AC_MSG_ERROR([Cannot find SQLSRV headers])
|
||||
fi
|
||||
AC_MSG_RESULT($sqlsrv_inc_path)
|
||||
|
||||
CXXFLAGS="$CXXFLAGS -std=c++11"
|
||||
PHP_REQUIRE_CXX()
|
||||
PHP_ADD_LIBRARY(stdc++, 1, SQLSRV_SHARED_LIBADD)
|
||||
PHP_ADD_LIBRARY(odbc, 1, SQLSRV_SHARED_LIBADD)
|
||||
PHP_SUBST(SQLSRV_SHARED_LIBADD)
|
||||
AC_DEFINE(HAVE_SQLSRV, 1, [ ])
|
||||
PHP_ADD_INCLUDE([$sqlsrv_inc_path])
|
||||
PHP_NEW_EXTENSION(sqlsrv, $sqlsrv_src_class $shared_src_class, $ext_shared,,-std=c++11)
|
||||
|
||||
fi
|
|
@ -18,9 +18,6 @@
|
|||
//---------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#include "php_sqlsrv.h"
|
||||
#include <psapi.h>
|
||||
#include <windows.h>
|
||||
#include <winver.h>
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
@ -146,12 +143,12 @@ int get_stmt_option_key( zend_string* key, size_t key_len TSRMLS_DC );
|
|||
|
||||
// constants for parameters used by process_params function(s)
|
||||
int ss_sqlsrv_conn::descriptor;
|
||||
char* ss_sqlsrv_conn::resource_name = "ss_sqlsrv_conn";
|
||||
char* ss_sqlsrv_conn::resource_name = static_cast<char *>("ss_sqlsrv_conn");
|
||||
|
||||
// connection specific parameter proccessing. Use the generic function specialised to return a connection
|
||||
// resource.
|
||||
#define PROCESS_PARAMS( rsrc, param_spec, calling_func, param_count, ... ) \
|
||||
rsrc = process_params<ss_sqlsrv_conn>( INTERNAL_FUNCTION_PARAM_PASSTHRU, param_spec, calling_func, param_count, __VA_ARGS__ ); \
|
||||
rsrc = process_params<ss_sqlsrv_conn>( INTERNAL_FUNCTION_PARAM_PASSTHRU, param_spec, calling_func, param_count, ##__VA_ARGS__ );\
|
||||
if( rsrc == NULL ) { \
|
||||
RETURN_FALSE; \
|
||||
}
|
||||
|
@ -765,7 +762,10 @@ PHP_FUNCTION( sqlsrv_client_info )
|
|||
core_sqlsrv_get_client_info( conn, return_value TSRMLS_CC );
|
||||
|
||||
// Add the sqlsrv driver's file version
|
||||
core::sqlsrv_add_assoc_string( *conn, return_value, "ExtensionVer", VER_FILEVERSION_STR, 1 /*duplicate*/ TSRMLS_CC );
|
||||
//Declarations below eliminate compiler warnings about string constant to char* conversions
|
||||
const char* extver = "ExtensionVer";
|
||||
std::string filever = VER_FILEVERSION_STR;
|
||||
core::sqlsrv_add_assoc_string( *conn, return_value, extver, &filever[0], 1 /*duplicate*/ TSRMLS_CC );
|
||||
}
|
||||
|
||||
catch( core::CoreException& ) {
|
||||
|
@ -978,7 +978,7 @@ PHP_FUNCTION( sqlsrv_query )
|
|||
sqlsrv_malloc_auto_ptr<ss_sqlsrv_stmt> stmt;
|
||||
char* sql = NULL;
|
||||
hash_auto_ptr ss_stmt_options_ht;
|
||||
int sql_len = 0;
|
||||
size_t sql_len = 0;
|
||||
zval* options_z = NULL;
|
||||
zval* params_z = NULL;
|
||||
zval stmt_z;
|
||||
|
@ -1026,7 +1026,7 @@ PHP_FUNCTION( sqlsrv_query )
|
|||
bind_params( stmt TSRMLS_CC );
|
||||
|
||||
// execute the statement
|
||||
core_sqlsrv_execute( stmt TSRMLS_CC, sql, sql_len );
|
||||
core_sqlsrv_execute( stmt TSRMLS_CC, sql, static_cast<int>( sql_len ) );
|
||||
|
||||
// register the statement with the PHP runtime
|
||||
ss::zend_register_resource(stmt_z, stmt, ss_sqlsrv_stmt::descriptor, ss_sqlsrv_stmt::resource_name TSRMLS_CC);
|
||||
|
@ -1112,14 +1112,12 @@ void sqlsrv_conn_close_stmts( ss_sqlsrv_conn* conn TSRMLS_DC )
|
|||
// delete the statement by deleting it from Zend's resource list, which will force its destruction
|
||||
stmt->conn = NULL;
|
||||
|
||||
try {
|
||||
// this would call the destructor on the statement.
|
||||
int zr = zend_list_close(Z_RES_P(rsrc_ptr));
|
||||
}
|
||||
catch( core::CoreException& ) {
|
||||
LOG(SEV_ERROR, "Failed to remove statement resource %1!d! when closing the connection", Z_RES_HANDLE_P(rsrc_ptr));
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
// this would call the destructor on the statement.
|
||||
// There's nothing we can do if the removal fails, so we just log it and move on.
|
||||
if( zend_list_close( Z_RES_P(rsrc_ptr) ) == FAILURE ) {
|
||||
LOG(SEV_ERROR, "Failed to remove statement resource %1!d! when closing the connection", Z_RES_HANDLE_P(rsrc_ptr));
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
zend_hash_destroy( conn->stmts );
|
||||
FREE_HASHTABLE( conn->stmts );
|
||||
|
@ -1230,8 +1228,6 @@ void validate_stmt_options( sqlsrv_context& ctx, zval* stmt_options, _Inout_ Has
|
|||
ZEND_HASH_FOREACH_KEY_VAL( options_ht, int_key, key, data ) {
|
||||
int type = HASH_KEY_NON_EXISTENT;
|
||||
size_t key_len = 0;
|
||||
zval* conn_opt = NULL;
|
||||
int result = 0;
|
||||
|
||||
type = key ? HASH_KEY_IS_STRING : HASH_KEY_IS_LONG;
|
||||
|
||||
|
|
|
@ -328,8 +328,11 @@ PHP_MINIT_FUNCTION(sqlsrv)
|
|||
REGISTER_LONG_CONSTANT( "SQLSRV_PHPTYPE_FLOAT", SQLSRV_PHPTYPE_FLOAT, CONST_PERSISTENT | CONST_CS );
|
||||
REGISTER_LONG_CONSTANT( "SQLSRV_PHPTYPE_DATETIME", SQLSRV_PHPTYPE_DATETIME, CONST_PERSISTENT | CONST_CS );
|
||||
|
||||
REGISTER_STRING_CONSTANT( "SQLSRV_ENC_BINARY", "binary", CONST_PERSISTENT | CONST_CS );
|
||||
REGISTER_STRING_CONSTANT( "SQLSRV_ENC_CHAR", "char", CONST_PERSISTENT | CONST_CS );
|
||||
std::string bin = "binary";
|
||||
std::string chr = "char";
|
||||
|
||||
REGISTER_STRING_CONSTANT( "SQLSRV_ENC_BINARY", &bin[0], CONST_PERSISTENT | CONST_CS );
|
||||
REGISTER_STRING_CONSTANT( "SQLSRV_ENC_CHAR", &chr[0], CONST_PERSISTENT | CONST_CS );
|
||||
|
||||
REGISTER_LONG_CONSTANT( "SQLSRV_NULLABLE_NO", 0, CONST_PERSISTENT | CONST_CS );
|
||||
REGISTER_LONG_CONSTANT( "SQLSRV_NULLABLE_YES", 1, CONST_PERSISTENT | CONST_CS );
|
||||
|
@ -413,11 +416,17 @@ PHP_MINIT_FUNCTION(sqlsrv)
|
|||
REGISTER_LONG_CONSTANT( "SQLSRV_SCROLL_ABSOLUTE", SQL_FETCH_ABSOLUTE, CONST_PERSISTENT | CONST_CS );
|
||||
REGISTER_LONG_CONSTANT( "SQLSRV_SCROLL_RELATIVE", SQL_FETCH_RELATIVE, CONST_PERSISTENT | CONST_CS );
|
||||
|
||||
REGISTER_STRING_CONSTANT( "SQLSRV_CURSOR_FORWARD", "forward", CONST_PERSISTENT | CONST_CS );
|
||||
REGISTER_STRING_CONSTANT( "SQLSRV_CURSOR_STATIC", "static", CONST_PERSISTENT | CONST_CS );
|
||||
REGISTER_STRING_CONSTANT( "SQLSRV_CURSOR_DYNAMIC", "dynamic", CONST_PERSISTENT | CONST_CS );
|
||||
REGISTER_STRING_CONSTANT( "SQLSRV_CURSOR_KEYSET", "keyset", CONST_PERSISTENT | CONST_CS );
|
||||
REGISTER_STRING_CONSTANT( "SQLSRV_CURSOR_CLIENT_BUFFERED", "buffered", CONST_PERSISTENT | CONST_CS );
|
||||
std::string fwd = "forward";
|
||||
std::string stc = "static";
|
||||
std::string dyn = "dynamic";
|
||||
std::string key = "keyset";
|
||||
std::string buf = "buffered";
|
||||
|
||||
REGISTER_STRING_CONSTANT( "SQLSRV_CURSOR_FORWARD", &fwd[0], CONST_PERSISTENT | CONST_CS );
|
||||
REGISTER_STRING_CONSTANT( "SQLSRV_CURSOR_STATIC", &stc[0], CONST_PERSISTENT | CONST_CS );
|
||||
REGISTER_STRING_CONSTANT( "SQLSRV_CURSOR_DYNAMIC", &dyn[0], CONST_PERSISTENT | CONST_CS );
|
||||
REGISTER_STRING_CONSTANT( "SQLSRV_CURSOR_KEYSET", &key[0], CONST_PERSISTENT | CONST_CS );
|
||||
REGISTER_STRING_CONSTANT( "SQLSRV_CURSOR_CLIENT_BUFFERED", &buf[0], CONST_PERSISTENT | CONST_CS );
|
||||
|
||||
try {
|
||||
|
||||
|
|
|
@ -48,8 +48,10 @@ OACR_WARNING_DISABLE( REALLOCLEAK, "Third party code." )
|
|||
|
||||
extern "C" {
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning( disable: 4005 4100 4127 4142 4244 4505 4530 )
|
||||
#endif
|
||||
|
||||
#ifdef ZTS
|
||||
#include "TSRM.h"
|
||||
|
@ -65,13 +67,9 @@ typedef int socklen_t;
|
|||
#define HAVE_SOCKLEN_T
|
||||
#endif
|
||||
|
||||
#include "php.h"
|
||||
#include "php_globals.h"
|
||||
#include "php_ini.h"
|
||||
#include "ext/standard/php_standard.h"
|
||||
#include "ext/standard/info.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
#error Trying to compile "Microsoft Drivers for PHP for SQL Server (SQLSRV Driver)" with an unsupported version of PHP
|
||||
|
@ -103,6 +101,8 @@ extern sqlsrv_context* g_henv_ncp;
|
|||
|
||||
extern OSVERSIONINFO g_osversion; // used to determine which OS we're running in
|
||||
|
||||
#define phpext_sqlsrv_ptr &g_sqlsrv_module_entry
|
||||
|
||||
// module initialization
|
||||
PHP_MINIT_FUNCTION(sqlsrv);
|
||||
// module shutdown function
|
||||
|
@ -373,7 +373,7 @@ unsigned int convert_string_from_default_encoding( unsigned int php_encoding, ch
|
|||
// create a wide char string from the passed in mbcs string. NULL is returned if the string
|
||||
// could not be created. No error is posted by this function. utf16_len is the number of
|
||||
// wchar_t characters, not the number of bytes.
|
||||
wchar_t* utf16_string_from_mbcs_string( unsigned int php_encoding, const char* mbcs_string,
|
||||
SQLWCHAR* utf16_string_from_mbcs_string( unsigned int php_encoding, const char* mbcs_string,
|
||||
unsigned int mbcs_len, _Out_ unsigned int* utf16_len );
|
||||
|
||||
// *** internal error macros and functions ***
|
||||
|
@ -407,7 +407,7 @@ inline void reset_errors( TSRMLS_D )
|
|||
}
|
||||
|
||||
#define THROW_SS_ERROR( ctx, error_code, ... ) \
|
||||
(void)call_error_handler( ctx, error_code TSRMLS_CC, false /*warning*/, __VA_ARGS__ ); \
|
||||
(void)call_error_handler( ctx, error_code TSRMLS_CC, false /*warning*/, ## __VA_ARGS__ ); \
|
||||
throw ss::SSException();
|
||||
|
||||
|
||||
|
@ -475,6 +475,31 @@ enum logging_subsystems {
|
|||
LOG_ALL = -1,
|
||||
};
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// Common function wrappers
|
||||
// have to place this namespace before the utility functions
|
||||
// otherwise can't compile in Linux because 'ss' not defined
|
||||
//*********************************************************************************************************************************
|
||||
namespace ss {
|
||||
|
||||
// an error which occurred in our SQLSRV driver
|
||||
struct SSException : public core::CoreException {
|
||||
|
||||
SSException()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
inline void zend_register_resource(_Out_ zval& rsrc_result, void* rsrc_pointer, int rsrc_type, char* rsrc_name TSRMLS_DC)
|
||||
{
|
||||
int zr = (NULL != (Z_RES(rsrc_result) = ::zend_register_resource(rsrc_pointer, rsrc_type)) ? SUCCESS : FAILURE);
|
||||
CHECK_CUSTOM_ERROR(( zr == FAILURE ), reinterpret_cast<sqlsrv_context*>( rsrc_pointer ), SS_SQLSRV_ERROR_REGISTER_RESOURCE,
|
||||
rsrc_name ) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
Z_TYPE_INFO(rsrc_result) = IS_RESOURCE_EX;
|
||||
}
|
||||
} // namespace ss
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
// Utility Functions
|
||||
|
@ -519,7 +544,7 @@ inline H* process_params( INTERNAL_FUNCTION_PARAMETERS, char const* param_spec,
|
|||
int result = SUCCESS;
|
||||
|
||||
// dummy context to pass to the error handler
|
||||
sqlsrv_context error_ctx( 0, ss_error_handler, NULL );;
|
||||
sqlsrv_context error_ctx( 0, ss_error_handler, NULL );
|
||||
error_ctx.set_func( calling_func );
|
||||
|
||||
switch( param_count ) {
|
||||
|
@ -591,28 +616,5 @@ inline H* process_params( INTERNAL_FUNCTION_PARAMETERS, char const* param_spec,
|
|||
DIE( "%1!s!: Unknown exception caught in process_params.", calling_func );
|
||||
}
|
||||
}
|
||||
//*********************************************************************************************************************************
|
||||
// Common function wrappers
|
||||
//*********************************************************************************************************************************
|
||||
namespace ss {
|
||||
|
||||
// an error which occurred in our SQLSRV driver
|
||||
struct SSException : public core::CoreException {
|
||||
|
||||
SSException()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
inline void zend_register_resource(_Out_ zval& rsrc_result, void* rsrc_pointer, int rsrc_type, char* rsrc_name TSRMLS_DC)
|
||||
{
|
||||
int zr = (NULL != (Z_RES(rsrc_result) = ::zend_register_resource(rsrc_pointer, rsrc_type)) ? SUCCESS : FAILURE);
|
||||
CHECK_CUSTOM_ERROR(( zr == FAILURE ), reinterpret_cast<sqlsrv_context*>( rsrc_pointer ), SS_SQLSRV_ERROR_REGISTER_RESOURCE,
|
||||
rsrc_name ) {
|
||||
throw ss::SSException();
|
||||
}
|
||||
Z_TYPE_INFO(rsrc_result) = IS_RESOURCE_EX;
|
||||
}
|
||||
} // namespace ss
|
||||
|
||||
#endif /* PHP_SQLSRV_H */
|
||||
|
|
|
@ -19,14 +19,16 @@
|
|||
|
||||
// *** header files ***
|
||||
#include "php_sqlsrv.h"
|
||||
#ifdef _WIN32
|
||||
#include <sal.h>
|
||||
#endif
|
||||
|
||||
//
|
||||
// *** internal variables and constants ***
|
||||
//
|
||||
// our resource descriptor assigned in minit
|
||||
int ss_sqlsrv_stmt::descriptor = 0;
|
||||
char* ss_sqlsrv_stmt::resource_name = "ss_sqlsrv_stmt"; // not const for a reason. see sqlsrv_stmt in php_sqlsrv.h
|
||||
char* ss_sqlsrv_stmt::resource_name = static_cast<char *>("ss_sqlsrv_stmt"); // not const for a reason. see sqlsrv_stmt in php_sqlsrv.h
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -72,12 +74,12 @@ enum SQLSRV_PHPTYPE zend_to_sqlsrv_phptype[] = {
|
|||
// (char to avoid having to cast them where they are used)
|
||||
namespace FieldMetaData {
|
||||
|
||||
char* NAME = "Name";
|
||||
char* TYPE = "Type";
|
||||
char* SIZE = "Size";
|
||||
char* PREC = "Precision";
|
||||
char* SCALE = "Scale";
|
||||
char* NULLABLE = "Nullable";
|
||||
const char* NAME = "Name";
|
||||
const char* TYPE = "Type";
|
||||
const char* SIZE = "Size";
|
||||
const char* PREC = "Precision";
|
||||
const char* SCALE = "Scale";
|
||||
const char* NULLABLE = "Nullable";
|
||||
|
||||
}
|
||||
|
||||
|
@ -248,7 +250,7 @@ sqlsrv_phptype ss_sqlsrv_stmt::sql_type_to_php_type( SQLINTEGER sql_type, SQLUIN
|
|||
// statement specific parameter proccessing. Uses the generic function specialised to return a statement
|
||||
// resource.
|
||||
#define PROCESS_PARAMS( rsrc, param_spec, calling_func, param_count, ... ) \
|
||||
rsrc = process_params<ss_sqlsrv_stmt>( INTERNAL_FUNCTION_PARAM_PASSTHRU, param_spec, calling_func, param_count, __VA_ARGS__ );\
|
||||
rsrc = process_params<ss_sqlsrv_stmt>( INTERNAL_FUNCTION_PARAM_PASSTHRU, param_spec, calling_func, param_count, ## __VA_ARGS__ );\
|
||||
if( rsrc == NULL ) { \
|
||||
RETURN_FALSE; \
|
||||
}
|
||||
|
@ -553,7 +555,6 @@ PHP_FUNCTION( sqlsrv_next_result )
|
|||
{
|
||||
LOG_FUNCTION( "sqlsrv_next_result" );
|
||||
|
||||
SQLRETURN r = SQL_SUCCESS;
|
||||
ss_sqlsrv_stmt* stmt = NULL;
|
||||
|
||||
PROCESS_PARAMS( stmt, "r", _FN_, 0 );
|
||||
|
@ -597,7 +598,6 @@ PHP_FUNCTION( sqlsrv_next_result )
|
|||
PHP_FUNCTION( sqlsrv_rows_affected )
|
||||
{
|
||||
LOG_FUNCTION( "sqlsrv_rows_affected" );
|
||||
SQLRETURN r = SQL_SUCCESS;
|
||||
ss_sqlsrv_stmt* stmt = NULL;
|
||||
SQLLEN rows = -1;
|
||||
|
||||
|
@ -1067,10 +1067,10 @@ PHP_FUNCTION( sqlsrv_get_field )
|
|||
sqlsrv_php_type.typeinfo.type = SQLSRV_PHPTYPE_INVALID;
|
||||
SQLSRV_PHPTYPE sqlsrv_php_type_out = SQLSRV_PHPTYPE_INVALID;
|
||||
void* field_value = NULL;
|
||||
int field_index = -1;
|
||||
zend_long field_index = -1;
|
||||
SQLLEN field_len = -1;
|
||||
zval retval_z;
|
||||
ZVAL_UNDEF(&retval_z);
|
||||
zval retval_z;
|
||||
ZVAL_UNDEF(&retval_z);
|
||||
|
||||
// get the statement, the field index and the optional type
|
||||
PROCESS_PARAMS( stmt, "rl|l", _FN_, 2, &field_index, &sqlsrv_php_type );
|
||||
|
@ -1084,10 +1084,10 @@ PHP_FUNCTION( sqlsrv_get_field )
|
|||
THROW_SS_ERROR( stmt, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ );
|
||||
}
|
||||
|
||||
core_sqlsrv_get_field( stmt, field_index, sqlsrv_php_type, false, field_value, &field_len, false/*cache_field*/,
|
||||
&sqlsrv_php_type_out TSRMLS_CC );
|
||||
core_sqlsrv_get_field( stmt, static_cast<SQLUSMALLINT>( field_index ), sqlsrv_php_type, false, field_value, &field_len, false/*cache_field*/,
|
||||
&sqlsrv_php_type_out TSRMLS_CC );
|
||||
convert_to_zval( stmt, sqlsrv_php_type_out, field_value, field_len, retval_z );
|
||||
sqlsrv_free( field_value );
|
||||
sqlsrv_free( field_value );
|
||||
RETURN_ZVAL( &retval_z, 1, 1 );
|
||||
}
|
||||
|
||||
|
@ -1824,8 +1824,14 @@ void fetch_fields_common( _Inout_ ss_sqlsrv_stmt* stmt, zend_long fetch_type, _O
|
|||
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 );
|
||||
core::SQLColAttributeW ( stmt, i + 1, SQL_DESC_NAME, field_name_w, ( SS_MAXCOLNAMELEN + 1 ) * 2, &field_name_len_w, NULL TSRMLS_CC );
|
||||
#ifdef __linux__
|
||||
//Conversion function in Linux expects size in characters.
|
||||
field_name_len_w = field_name_len_w / sizeof ( SQLWCHAR );
|
||||
#endif
|
||||
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();
|
||||
}
|
||||
|
@ -2152,7 +2158,7 @@ void type_and_size_calc( INTERNAL_FUNCTION_PARAMETERS, int type )
|
|||
{
|
||||
char* size_p = NULL;
|
||||
size_t size_len = 0;
|
||||
long size = 0;
|
||||
int size = 0;
|
||||
|
||||
if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s", &size_p, &size_len ) == FAILURE ) {
|
||||
|
||||
|
@ -2163,7 +2169,11 @@ void type_and_size_calc( INTERNAL_FUNCTION_PARAMETERS, int type )
|
|||
size = SQLSRV_SIZE_MAX_TYPE;
|
||||
}
|
||||
else {
|
||||
_set_errno( 0 ); // reset errno for atol
|
||||
#ifdef __linux__
|
||||
errno = 0;
|
||||
#else
|
||||
_set_errno(0); // reset errno for atol
|
||||
#endif
|
||||
size = atol( size_p );
|
||||
if( errno != 0 ) {
|
||||
size = SQLSRV_INVALID_SIZE;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Contents: Version resource
|
||||
//
|
||||
// Microsoft Drivers 4.0 for PHP for SQL Server
|
||||
// Microsoft Drivers 4.1 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
@ -59,7 +59,7 @@ BEGIN
|
|||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "Comments", "This product includes PHP software that is freely available from http://www.php.net/software/. Copyright © 2001-2016 The PHP Group. All rights reserved.\0"
|
||||
VALUE "Comments", "This product includes PHP software that is freely available from http://www.php.net/software/. Copyright © 2001-2016 The PHP Group. All rights reserved.\0"
|
||||
VALUE "CompanyName", "Microsoft Corp.\0"
|
||||
VALUE "FileDescription", "Microsoft Drivers for PHP for SQL Server\0"
|
||||
VALUE "FileVersion", STRVER4(SQLVERSION_MAJOR,SQLVERSION_MINOR, SQLVERSION_RELEASE, SQLVERSION_BUILD)
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
|
||||
#include "php_sqlsrv.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace {
|
||||
|
||||
// current subsytem. defined for the CHECK_SQL_{ERROR|WARNING} macros
|
||||
|
|
Loading…
Reference in a new issue