Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Feature request - new PDO_STMT_OPTION_FETCHES_DATETIME_TYPE flag for pdo_sqlsrv to return datetime as objects #842

Merged
merged 8 commits into from
Sep 17, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion source/pdo_sqlsrv/pdo_dbh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ enum PDO_STMT_OPTIONS {
PDO_STMT_OPTION_CLIENT_BUFFER_MAX_KB_SIZE,
PDO_STMT_OPTION_EMULATE_PREPARES,
PDO_STMT_OPTION_FETCHES_NUMERIC_TYPE,
PDO_STMT_OPTION_FETCHES_DATETIME_TYPE
};

// List of all the statement options supported by this driver.
Expand All @@ -93,6 +94,7 @@ const stmt_option PDO_STMT_OPTS[] = {
{ 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_DATETIME_TYPE, std::unique_ptr<stmt_option_fetch_datetime>( new stmt_option_fetch_datetime ) },

{ NULL, 0, SQLSRV_STMT_OPTION_INVALID, std::unique_ptr<stmt_option_functor>{} },
};
Expand Down Expand Up @@ -495,7 +497,8 @@ pdo_sqlsrv_dbh::pdo_sqlsrv_dbh( _In_ SQLHANDLE h, _In_ error_callback e, _In_ vo
direct_query( false ),
query_timeout( QUERY_TIMEOUT_INVALID ),
client_buffer_max_size( PDO_SQLSRV_G( client_buffer_max_size )),
fetch_numeric( false )
fetch_numeric( false ),
fetch_datetime( false )
{
if( client_buffer_max_size < 0 ) {
client_buffer_max_size = sqlsrv_buffered_result_set::BUFFERED_QUERY_LIMIT_DEFAULT;
Expand Down Expand Up @@ -1061,6 +1064,10 @@ int pdo_sqlsrv_dbh_set_attr( _Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout
driver_dbh->fetch_numeric = (zend_is_true(val)) ? true : false;
break;

case SQLSRV_ATTR_FETCHES_DATETIME_TYPE:
driver_dbh->fetch_datetime = (zend_is_true(val)) ? true : false;
break;

// Not supported
case PDO_ATTR_FETCH_TABLE_NAMES:
case PDO_ATTR_FETCH_CATALOG_NAMES:
Expand Down Expand Up @@ -1212,6 +1219,12 @@ int pdo_sqlsrv_dbh_get_attr( _Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout
break;
}

case SQLSRV_ATTR_FETCHES_DATETIME_TYPE:
{
ZVAL_BOOL( return_value, driver_dbh->fetch_datetime );
break;
}

default:
{
THROW_PDO_ERROR( driver_dbh, PDO_SQLSRV_ERROR_INVALID_DBH_ATTR );
Expand Down Expand Up @@ -1569,6 +1582,10 @@ void add_stmt_option_key( _Inout_ sqlsrv_context& ctx, _In_ size_t key, _Inout_
option_key = PDO_STMT_OPTION_FETCHES_NUMERIC_TYPE;
break;

case SQLSRV_ATTR_FETCHES_DATETIME_TYPE:
option_key = PDO_STMT_OPTION_FETCHES_DATETIME_TYPE;
break;

default:
CHECK_CUSTOM_ERROR( true, ctx, PDO_SQLSRV_ERROR_INVALID_STMT_OPTION ) {
throw core::CoreException();
Expand Down
1 change: 1 addition & 0 deletions source/pdo_sqlsrv/pdo_init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ namespace {
{ "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 },
{ "SQLSRV_ATTR_FETCHES_DATETIME_TYPE", SQLSRV_ATTR_FETCHES_DATETIME_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
Expand Down
130 changes: 80 additions & 50 deletions source/pdo_sqlsrv/pdo_stmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ inline SQLSMALLINT pdo_fetch_ori_to_odbc_fetch_ori ( _In_ enum pdo_fetch_orienta
// for list of supported pdo types.
SQLSRV_PHPTYPE pdo_type_to_sqlsrv_php_type( _Inout_ sqlsrv_stmt* driver_stmt, _In_ enum pdo_param_type pdo_type TSRMLS_DC )
{
pdo_sqlsrv_stmt *pdo_stmt = static_cast<pdo_sqlsrv_stmt*>(driver_stmt);
SQLSRV_ASSERT(pdo_stmt != NULL, "pdo_type_to_sqlsrv_php_type: pdo_stmt object was null");

switch( pdo_type ) {

case PDO_PARAM_BOOL:
Expand All @@ -64,9 +67,12 @@ SQLSRV_PHPTYPE pdo_type_to_sqlsrv_php_type( _Inout_ sqlsrv_stmt* driver_stmt, _I
return SQLSRV_PHPTYPE_NULL;

case PDO_PARAM_LOB:
// TODO: This will eventually be changed to SQLSRV_PHPTYPE_STREAM when output streaming is implemented.
return SQLSRV_PHPTYPE_STRING;

if (pdo_stmt->fetch_datetime) {
return SQLSRV_PHPTYPE_DATETIME;
} else {
// TODO: This will eventually be changed to SQLSRV_PHPTYPE_STREAM when output streaming is implemented.
return SQLSRV_PHPTYPE_STRING;
}
case PDO_PARAM_STMT:
THROW_PDO_ERROR( driver_stmt, PDO_SQLSRV_ERROR_PDO_STMT_UNSUPPORTED );
break;
Expand Down Expand Up @@ -213,61 +219,63 @@ void meta_data_free( _Inout_ field_meta_data* meta )
zval convert_to_zval( _In_ SQLSRV_PHPTYPE sqlsrv_php_type, _Inout_ void** in_val, _In_opt_ SQLLEN field_len )
{
zval out_zval;
ZVAL_UNDEF( &out_zval );
ZVAL_UNDEF(&out_zval);

switch( sqlsrv_php_type ) {

case SQLSRV_PHPTYPE_INT:
case SQLSRV_PHPTYPE_FLOAT:
{
if( *in_val == NULL ) {
ZVAL_NULL( &out_zval );
}
else {
switch (sqlsrv_php_type) {

if( sqlsrv_php_type == SQLSRV_PHPTYPE_INT ) {
ZVAL_LONG( &out_zval, **( reinterpret_cast<int**>( in_val )));
}
else {
ZVAL_DOUBLE( &out_zval, **( reinterpret_cast<double**>( in_val )));
}
}
case SQLSRV_PHPTYPE_INT:
case SQLSRV_PHPTYPE_FLOAT:
{
if (*in_val == NULL) {
ZVAL_NULL(&out_zval);
}
else {

if( *in_val ) {
sqlsrv_free( *in_val );
if (sqlsrv_php_type == SQLSRV_PHPTYPE_INT) {
ZVAL_LONG(&out_zval, **(reinterpret_cast<int**>(in_val)));
}
else {
ZVAL_DOUBLE(&out_zval, **(reinterpret_cast<double**>(in_val)));
}

break;
}

case SQLSRV_PHPTYPE_STRING:
case SQLSRV_PHPTYPE_STREAM: // TODO: this will be moved when output streaming is implemented
{
if (*in_val) {
sqlsrv_free(*in_val);
}

if( *in_val == NULL ) {
break;
}
case SQLSRV_PHPTYPE_STRING:
case SQLSRV_PHPTYPE_STREAM: // TODO: this will be moved when output streaming is implemented
{
if (*in_val == NULL) {

ZVAL_NULL( &out_zval );
}
else {
ZVAL_NULL(&out_zval);
}
else {

ZVAL_STRINGL( &out_zval, reinterpret_cast<char*>( *in_val ), field_len );
sqlsrv_free( *in_val );
}
break;
ZVAL_STRINGL(&out_zval, reinterpret_cast<char*>(*in_val), field_len);
sqlsrv_free(*in_val);
}

case SQLSRV_PHPTYPE_DATETIME:
DIE( "Unsupported php type" );
out_zval = *( reinterpret_cast<zval*>( *in_val ));
break;
break;
}
case SQLSRV_PHPTYPE_DATETIME:
if (*in_val == NULL) {

case SQLSRV_PHPTYPE_NULL:
ZVAL_NULL( &out_zval );
break;
ZVAL_NULL(&out_zval);
}
else {

default:
DIE( "Unknown php type" );
break;
out_zval = *(reinterpret_cast<zval*>(*in_val));
sqlsrv_free(*in_val);
}
break;
case SQLSRV_PHPTYPE_NULL:
ZVAL_NULL(&out_zval);
break;
default:
DIE("Unknown php type");
break;
}

return out_zval;
Expand Down Expand Up @@ -339,6 +347,11 @@ void stmt_option_fetch_numeric:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_opt
pdo_stmt->fetch_numeric = ( zend_is_true( value_z )) ? true : false;
}

void stmt_option_fetch_datetime:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC )
{
pdo_sqlsrv_stmt *pdo_stmt = static_cast<pdo_sqlsrv_stmt*>( stmt );
pdo_stmt->fetch_datetime = ( zend_is_true( value_z )) ? true : false;
}
david-puglielli marked this conversation as resolved.
Show resolved Hide resolved

// log a function entry point
#ifndef _WIN32
Expand Down Expand Up @@ -865,6 +878,10 @@ int pdo_sqlsrv_stmt_set_attr( _Inout_ pdo_stmt_t *stmt, _In_ zend_long attr, _In
driver_stmt->fetch_numeric = ( zend_is_true( val )) ? true : false;
break;

case SQLSRV_ATTR_FETCHES_DATETIME_TYPE:
driver_stmt->fetch_datetime = ( zend_is_true( val )) ? true : false;
break;

default:
THROW_PDO_ERROR( driver_stmt, PDO_SQLSRV_ERROR_INVALID_STMT_ATTR );
break;
Expand Down Expand Up @@ -946,6 +963,12 @@ int pdo_sqlsrv_stmt_get_attr( _Inout_ pdo_stmt_t *stmt, _In_ zend_long attr, _In
break;
}

case SQLSRV_ATTR_FETCHES_DATETIME_TYPE:
{
ZVAL_BOOL( return_value, driver_stmt->fetch_datetime );
break;
}

default:
THROW_PDO_ERROR( driver_stmt, PDO_SQLSRV_ERROR_INVALID_STMT_ATTR );
break;
Expand Down Expand Up @@ -1365,6 +1388,17 @@ sqlsrv_phptype pdo_sqlsrv_stmt::sql_type_to_php_type( _In_ SQLINTEGER sql_type,
sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_STRING;
}
break;
case SQL_TYPE_DATE:
case SQL_SS_TIMESTAMPOFFSET:
case SQL_SS_TIME2:
case SQL_TYPE_TIMESTAMP:
if ( this->fetch_datetime ) {
sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_DATETIME;
}
else {
sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_STRING;
}
break;
case SQL_BIGINT:
case SQL_CHAR:
case SQL_DECIMAL:
Expand All @@ -1373,10 +1407,6 @@ sqlsrv_phptype pdo_sqlsrv_stmt::sql_type_to_php_type( _In_ SQLINTEGER sql_type,
case SQL_WCHAR:
case SQL_VARCHAR:
case SQL_WVARCHAR:
case SQL_TYPE_DATE:
case SQL_SS_TIMESTAMPOFFSET:
case SQL_SS_TIME2:
case SQL_TYPE_TIMESTAMP:
case SQL_LONGVARCHAR:
case SQL_WLONGVARCHAR:
case SQL_SS_XML:
Expand Down
11 changes: 10 additions & 1 deletion source/pdo_sqlsrv/php_pdo_sqlsrv.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ enum PDO_SQLSRV_ATTR {
SQLSRV_ATTR_CURSOR_SCROLL_TYPE,
SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE,
SQLSRV_ATTR_FETCHES_NUMERIC_TYPE,
SQLSRV_ATTR_FETCHES_DATETIME_TYPE
};

// valid set of values for TransactionIsolation connection option
Expand Down Expand Up @@ -203,6 +204,7 @@ struct pdo_sqlsrv_dbh : public sqlsrv_conn {
long query_timeout;
zend_long client_buffer_max_size;
bool fetch_numeric;
bool fetch_datetime;

pdo_sqlsrv_dbh( _In_ SQLHANDLE h, _In_ error_callback e, _In_ void* driver TSRMLS_DC );
};
Expand Down Expand Up @@ -241,6 +243,10 @@ struct stmt_option_fetch_numeric : public stmt_option_functor {
virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC );
};

struct stmt_option_fetch_datetime : public stmt_option_functor {
virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC );
};

extern struct pdo_stmt_methods pdo_sqlsrv_stmt_methods;

// a core layer pdo stmt object. This object inherits and overrides the callbacks necessary
Expand All @@ -253,11 +259,13 @@ struct pdo_sqlsrv_stmt : public sqlsrv_stmt {
direct_query_subst_string_len( 0 ),
placeholders(NULL),
bound_column_param_types( NULL ),
fetch_numeric( false )
fetch_numeric( false ),
fetch_datetime( false )
{
pdo_sqlsrv_dbh* db = static_cast<pdo_sqlsrv_dbh*>( c );
direct_query = db->direct_query;
fetch_numeric = db->fetch_numeric;
fetch_datetime = db->fetch_datetime;
}

virtual ~pdo_sqlsrv_stmt( void );
Expand All @@ -275,6 +283,7 @@ struct pdo_sqlsrv_stmt : public sqlsrv_stmt {
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_datetime;
};


Expand Down
3 changes: 2 additions & 1 deletion source/shared/core_stmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ struct field_cache {
: type( t )
{
// if the value is NULL, then just record a NULL pointer
if( field_value != NULL ) {
// field_len may be equal to SQL_NULL_DATA even when field_value is not null
if( field_value != NULL && field_len != SQL_NULL_DATA) {
value = sqlsrv_malloc( field_len );
memcpy_s( value, field_len, field_value, field_len );
len = field_len;
Expand Down
Loading