// pdo error handler for the dbh context. bool pdo_sqlsrv_handle_dbh_error( sqlsrv_context& ctx, unsigned int sqlsrv_error_code, bool warning TSRMLS_DC, va_list* print_args ) { pdo_dbh_t* dbh = reinterpret_cast<pdo_dbh_t*>( ctx.driver()); SQLSRV_ASSERT( dbh != NULL, "pdo_sqlsrv_handle_dbh_error: Null dbh passed" ); sqlsrv_error_auto_ptr error; if( sqlsrv_error_code != SQLSRV_ERROR_ODBC ) { core_sqlsrv_format_driver_error( ctx, get_error_message( sqlsrv_error_code ), error, SEV_ERROR TSRMLS_CC, print_args ); } else { bool err = core_sqlsrv_get_odbc_error( ctx, 1, error, SEV_ERROR TSRMLS_CC ); SQLSRV_ASSERT( err == true, "No ODBC error was found" ); } SQLSRV_STATIC_ASSERT( sizeof( error->sqlstate ) <= sizeof( dbh->error_code )); strcpy_s( dbh->error_code, sizeof( dbh->error_code ), reinterpret_cast<const char*>( error->sqlstate )); switch( dbh->error_mode ) { case PDO_ERRMODE_EXCEPTION: if( !warning ) { pdo_sqlsrv_throw_exception( error TSRMLS_CC ); } ctx.set_last_error( error ); break; case PDO_ERRMODE_WARNING: if( !warning ) { unsigned int msg_len = strlen( reinterpret_cast<const char*>( error->native_message )) + SQL_SQLSTATE_BUFSIZE + MAX_DIGITS + 1; sqlsrv_malloc_auto_ptr<char> msg; msg = static_cast<char*>( sqlsrv_malloc( msg_len )); core_sqlsrv_format_message( msg, msg_len, WARNING_TEMPLATE, error->sqlstate, error->native_code, error->native_message ); php_error( E_WARNING, msg ); sqlsrv_free( msg ); } ctx.set_last_error( error ); break; case PDO_ERRMODE_SILENT: ctx.set_last_error( error ); break; default: DIE( "Unknown error mode. %1!d!", dbh->error_mode ); break; } // return error ignored = true for warnings. return ( warning ? true : false ); }
bool convert_string_from_utf16( SQLSRV_ENCODING encoding, const wchar_t* inString, SQLINTEGER cchInLen, char** outString, SQLINTEGER& cchOutLen ) { SQLSRV_ASSERT( inString != NULL, "Input string must be specified" ); SQLSRV_ASSERT( outString != NULL, "Output buffer pointer must be specified" ); SQLSRV_ASSERT( *outString == NULL, "Output buffer pointer must not be set" ); if (cchInLen == 0 && inString[0] == L'\0') { *outString = reinterpret_cast<char*>( sqlsrv_malloc ( 1 ) ); *outString[0] = '\0'; cchOutLen = 0; return true; } // flags set to 0 by default, which means that any invalid characters are dropped rather than causing // an error. This happens only on XP. DWORD flags = 0; if( encoding == CP_UTF8 && g_osversion.dwMajorVersion >= SQLSRV_OS_VISTA_OR_LATER ) { // Vista (and later) will detect invalid UTF-16 characters and raise an error. flags = WC_ERR_INVALID_CHARS; } // calculate the number of characters needed cchOutLen = WideCharToMultiByte( encoding, flags, inString, cchInLen, NULL, 0, NULL, NULL ); if( cchOutLen == 0 ) { return false; } // Create a buffer to fit the encoded string char* newString = reinterpret_cast<char*>( sqlsrv_malloc( cchOutLen + 1 /* NULL char*/ )); int rc = WideCharToMultiByte( encoding, flags, inString, cchInLen, newString, cchOutLen, NULL, NULL ); if( rc == 0 ) { cchOutLen = 0; sqlsrv_free( newString ); return false; } *outString = newString; newString[cchOutLen] = '\0'; // null terminate the encoded string return true; }
// Check for end of string. inline bool string_parser::is_eos( void ) { if( this->pos == len ) { return true; // EOS } SQLSRV_ASSERT(this->pos < len, "Unexpected cursor position in conn_string_parser::is_eos" ); return false; }
// write to the php log if the severity and subsystem match the filters currently set in the INI or // the script (sqlsrv_configure). void write_to_log( _In_ unsigned int severity TSRMLS_DC, _In_ const char* msg, ...) { SQLSRV_ASSERT( !(g_driver_log == NULL), "Must register a driver log function." ); va_list args; va_start( args, msg ); g_driver_log( severity TSRMLS_CC, msg, &args ); va_end( args ); }
// PDO error handler for the environment context. bool pdo_sqlsrv_handle_env_error( sqlsrv_context& ctx, unsigned int sqlsrv_error_code, bool warning TSRMLS_DC, va_list* print_args ) { SQLSRV_ASSERT(( ctx != NULL ), "pdo_sqlsrv_handle_env_error: sqlsrv_context was null" ); pdo_dbh_t* dbh = reinterpret_cast<pdo_dbh_t*>( ctx.driver()); SQLSRV_ASSERT(( dbh != NULL ), "pdo_sqlsrv_handle_env_error: pdo_dbh_t was null" ); sqlsrv_error_auto_ptr error; if( sqlsrv_error_code != SQLSRV_ERROR_ODBC ) { core_sqlsrv_format_driver_error( ctx, get_error_message( sqlsrv_error_code ), error, SEV_ERROR TSRMLS_CC, print_args ); } else { bool err = core_sqlsrv_get_odbc_error( ctx, 1, error, SEV_ERROR TSRMLS_CC ); SQLSRV_ASSERT( err == true, "No ODBC error was found" ); } strcpy_s( dbh->error_code, sizeof( pdo_error_type ), reinterpret_cast<const char*>( error->sqlstate )); switch( dbh->error_mode ) { case PDO_ERRMODE_EXCEPTION: if( !warning ) { pdo_sqlsrv_throw_exception( error TSRMLS_CC ); } ctx.set_last_error( error ); break; default: DIE( "pdo_sqlsrv_handle_env_error: Unexpected error mode. %1!d!", dbh->error_mode ); break; } // we don't transfer the zval_auto_ptr since set_last_error increments the zval ref count // return error ignored = true for warnings. return ( warning ? true : false ); }
// 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 = zend_hash_index_find( g_pdo_errors_ht, sqlsrv_error_code, reinterpret_cast<void**>( &error_message )); if( zr == FAILURE ) { DIE( "get_error_message: zend_hash_index_find returned failure for sqlsrv_error_code = %1!d!", sqlsrv_error_code ); } SQLSRV_ASSERT( error_message != NULL, "get_error_message: error_message was null"); return error_message; }
// Move to the next character inline bool string_parser::next( void ) { // if already at the end then return false if( this->is_eos() ) { return false; } SQLSRV_ASSERT( this->pos < len, "Unexpected cursor position in conn_string_parser::next" ); this->pos++; if ( this->is_eos() ) { return false; } return true; }
bool convert_string_from_utf16_inplace( SQLSRV_ENCODING encoding, char** string, SQLLEN& len) { SQLSRV_ASSERT( string != NULL && *string != NULL, "String must be specified" ); // for the empty string, we simply returned we converted it if( len == 0 && *string[0] == '\0' ) { return true; } char* outString = NULL; SQLINTEGER outLen = 0; bool result = convert_string_from_utf16( encoding, reinterpret_cast<const wchar_t*>(*string), len / sizeof(wchar_t), &outString, outLen); if (result) { sqlsrv_free( *string ); *string = outString; len = outLen; } return result; }
// Primary function which parses the connection string/DSN. void conn_string_parser:: parse_conn_string( TSRMLS_D ) { States state = FirstKeyValuePair; // starting state int start_pos = -1; try { while( !this->is_eos() ) { switch( state ) { case FirstKeyValuePair: { // discard leading spaces if( !next() || !discard_white_spaces() ) { THROW_PDO_ERROR( this->ctx, PDO_SQLSRV_ERROR_INVALID_DSN_STRING ); //EOS } state = Key; break; } case Key: { start_pos = this->pos; // read the key name while( this->conn_str[ pos ] != '=' ) { if( !next() ) { THROW_PDO_ERROR( this->ctx, PDO_SQLSRV_ERROR_DSN_STRING_ENDED_UNEXPECTEDLY ); //EOS } } this->validate_key( &( this->conn_str[ start_pos ] ), ( pos - start_pos ) TSRMLS_CC ); state = Value; break; } case Value: { SQLSRV_ASSERT(( this->conn_str[ pos ] == '=' ), "conn_string_parser:: parse_conn_string: " "Equal was expected" ); next(); // skip "=" // if EOS encountered after 0 or more spaces OR semi-colon encountered. if( !discard_white_spaces() || this->conn_str[ pos ] == ';' ) { add_key_value_pair( NULL, 0 TSRMLS_CC ); if( this->is_eos() ) { break; // EOS } else { // this->conn_str[ pos ] == ';' state = NextKeyValuePair; } } // if LCB else if( this->conn_str[ pos ] == '{' ) { start_pos = this->pos; // starting character is LCB state = ValueContent1; } // If NonSP-LCB-SC else { start_pos = this->pos; state = ValueContent2; } break; } case ValueContent1: { while ( this->conn_str[ pos ] != '}' ) { if ( ! next() ) { THROW_PDO_ERROR( this->ctx, PDO_SQLSRV_ERROR_RCB_MISSING_IN_DSN_VALUE, this->current_key_name ); } } // If we reached here than RCB encountered state = RCBEncountered; break; } case ValueContent2: { while( this->conn_str[ pos ] != ';' ) { if( ! next() ) { break; //EOS } } if( !this->is_eos() && this->conn_str[ pos ] == ';' ) { // semi-colon encountered, so go to next key-value pair state = NextKeyValuePair; } add_key_value_pair( &( this->conn_str[ start_pos ] ), this->pos - start_pos TSRMLS_CC ); SQLSRV_ASSERT((( state == NextKeyValuePair ) || ( this->is_eos() )), "conn_string_parser::parse_conn_string: Invalid state encountered " ); break; } case RCBEncountered: { // Read the next character after RCB. if( !next() ) { // EOS add_key_value_pair( &( this->conn_str[ start_pos ] ), this->pos - start_pos TSRMLS_CC ); break; } SQLSRV_ASSERT( !this->is_eos(), "conn_string_parser::parse_conn_string: Unexpected EOS encountered" ); // if second RCB encountered than go back to ValueContent1 if( this->conn_str[ pos ] == '}' ) { if( !next() ) { // EOS after a second RCB is error THROW_PDO_ERROR( this->ctx, SQLSRV_ERROR_UNESCAPED_RIGHT_BRACE_IN_DSN, this->current_key_name ); } state = ValueContent1; break; } int end_pos = this->pos; // discard any trailing white-spaces. if( this->is_white_space( this->conn_str[ pos ] )) { if( ! this->discard_white_spaces() ) { //EOS add_key_value_pair( &( this->conn_str[ start_pos ] ), end_pos - start_pos TSRMLS_CC ); break; } } // if semi-colon than go to next key-value pair if ( this->conn_str[ pos ] == ';' ) { add_key_value_pair( &( this->conn_str[ start_pos ] ), end_pos - start_pos TSRMLS_CC ); state = NextKeyValuePair; break; } // Non - (RCB, SP*, SC, EOS) character. Any other character after an RCB is an error. THROW_PDO_ERROR( this->ctx, PDO_SQLSRV_ERROR_INVALID_DSN_VALUE, this->current_key_name ); break; } case NextKeyValuePair: { SQLSRV_ASSERT(( this->conn_str[ pos ] == ';' ), "conn_string_parser::parse_conn_string: semi-colon was expected." ); // Call next() to skip the semi-colon. if( !next() || !this->discard_white_spaces() ) { // EOS break; } if( this->conn_str[ pos ] == ';' ) { // a second semi-colon is error case. THROW_PDO_ERROR( this->ctx, PDO_SQLSRV_ERROR_EXTRA_SEMI_COLON_IN_DSN_STRING, this->pos ); } else { // any other character leads to the next key state = Key; break; } } //case NextKeyValuePair } // switch } //while } catch( pdo::PDOException& ) { throw; } }