* Fixed the potential error reported by Prefast code analysis * Use SQLSRV_ASSERT for checking NULL ptrs * For these AKV tests check env despite not AE connected * Added the driver option to run functional tests * Fixed connection pooling tests for more than one ODBC drivers * added driver option to pdo isPooled.php * Removed win32 ifdefs re connection resiliency (#802) * Set the driver argument for getDSN to null by default (#798) * Added the driver argument to getDSN * Dropped the driver argument but set to null as default * Removed the AE condition in locale support * Modified the AE condition for locale support * Changed int to SQLLEN to avoid infinite loop (#806) * Version 5.3.0 (#803) * Version 5.3.0 * Fixed the wrong replacements * Added comments block to m4 files * Use dnl for comments * Modified AE fetch phptypes test to insert only one row at a time and loop through php types (#801) * Modified AE fetch phptypes test to insert only one row at a time and loop through php types * Fixed formatting * Streamlined two very similar large column name tests (#807) * Streamlined two very similar large column name tests * Changed the EOL * Updates to change log and readme (#811) * Updates to change log and readme * Dropped support for Ubuntu 17 * Modified as per review comments * Fixed connection resiliency tests for Unix, updated AppVeyor for ODBC 17.2 * Fixed expected output * Fixed output and skipifs * Fixed skipifs and output * Fixed driver name * Updated installation instructions and sample script (#813) * Updated instructions and sample test for 5.3.0 RTW * Fixed sample code to adhere to php coding standard * Fixed cases and spaces * Modified NOTE for UB 18.04 based on review comments * Added 'exit' * Modified change log and readme based on review to PR 811 * Applied review comments * build output to debug appveyor failure * removed debug output * Streamlined two very similar large column name tests (#815) * Streamlined two very similar large column name tests * Added random number of test table names to avoid operand clash issues * Replaced to with for based on review * Changelog updated * changelog updated, test skipif changed to run on unix platforms * Fixed skipif typo * Fixed typo in skipif for pdo * Fixed some output for Travis * Moved error checking inside pdo connres tests * Added links back to changelog * Fixed output for sqlsrv connres tests * Fixed output * Fixed output again * Fixed skipifs for connres * Tweaked per review comments * Changes made to source and tests to support PHP 7.3 (#822) * Changes made to support php 7.3 * Correct use of the smart pointer * Fixed the tests for 7.3 * Some clean up for array_init() * Fixed formattings and clean up * One more fix * Initialising strings with nulls * Removed some spaces * Made array index spacing consistent * Fix for compilation problem * Fix for compilation problem again * Before freeing stmt in destructor check if dbh driver data is NULL (#829) * Issue 434 - set dbh driver data to NULL as well in destructor * Reverted the last change but instead check if dbh driver_data is already freed * Modified the comment * Added driver to the skipif conditions (#831) * Used git clone instead to download source from a branch of a tag (#832) * Modified the error handling to make it more flexible (#833) * Made error handling more flexible * Fixed a minor issue with a test * Enabled Spectre Mitigations (#836) * Incorporated changes in PR 634 to pdo_sqlsrv (#834) * Incorporated changes in PR 634 to pdo_sqlsrv * Reverted the changes because the array is for internal use only * Modified README re user's suggestion (#841) * Modified README re user's suggestion * Moved the if condition to the end as per review * Adding supporting for Azure AD access token (#837) * Adding supporting for Azure AD access token * Added more comments for the AD access token skipif files * Save the pointer to access token struct until after connecting * Clear the access token data before freeing the memory * Added a reference as per review * Feature request - new PDO_STMT_OPTION_FETCHES_DATETIME_TYPE flag for pdo_sqlsrv to return datetime as objects (#842) * Feature request - issue 648 * Fixed constructor for field_cache and added another test * Added tests for FETCH_BOUND * Added a new test for output param * Modified output param test to set attributes differently * Removed a useless helped function in a test * Combined two new tests into one as per review * Uncommented dropTable * Feature request - add ReturnDatesAsStrings option to statement level for sqlsrv (#844) * Added ReturnDatesAsStrings option to the statement level * Added new tests for ReturnDatesAsStrings at statement level * Added more datetime types as per review * Updated version 5.4.0-preview (#846) * Updated version 5.4.0-preview * Replaced 5.3 with 5.4 * Fixed sqlsrv datetime tests to connect with ColumnEncryption variables (#849) * Change log for 5.4.0-preview (#850) * Updated change log for 5.4.0-preview * Updated 5.4.0 preview to add two new feature requests * Modified change log as per review * Modified the wordings * Updated readme, changelog, and install instructions * Clear AKV data after setting the connection attribute or when exception is thrown (#854) * Dev (#820) * Fixed the potential error reported by Prefast code analysis * Use SQLSRV_ASSERT for checking NULL ptrs * For these AKV tests check env despite not AE connected * Added the driver option to run functional tests * Fixed connection pooling tests for more than one ODBC drivers * added driver option to pdo isPooled.php * Removed win32 ifdefs re connection resiliency (#802) * Set the driver argument for getDSN to null by default (#798) * Added the driver argument to getDSN * Dropped the driver argument but set to null as default * Removed the AE condition in locale support * Modified the AE condition for locale support * Changed int to SQLLEN to avoid infinite loop (#806) * Version 5.3.0 (#803) * Version 5.3.0 * Fixed the wrong replacements * Added comments block to m4 files * Use dnl for comments * Modified AE fetch phptypes test to insert only one row at a time and loop through php types (#801) * Modified AE fetch phptypes test to insert only one row at a time and loop through php types * Fixed formatting * Streamlined two very similar large column name tests (#807) * Streamlined two very similar large column name tests * Changed the EOL * Updates to change log and readme (#811) * Updates to change log and readme * Dropped support for Ubuntu 17 * Modified as per review comments * Fixed connection resiliency tests for Unix, updated AppVeyor for ODBC 17.2 * Fixed expected output * Fixed output and skipifs * Fixed skipifs and output * Fixed driver name * Updated installation instructions and sample script (#813) * Updated instructions and sample test for 5.3.0 RTW * Fixed sample code to adhere to php coding standard * Fixed cases and spaces * Modified NOTE for UB 18.04 based on review comments * Added 'exit' * Modified change log and readme based on review to PR 811 * Applied review comments * build output to debug appveyor failure * removed debug output * Streamlined two very similar large column name tests (#815) * Streamlined two very similar large column name tests * Added random number of test table names to avoid operand clash issues * Replaced to with for based on review * Changelog updated * changelog updated, test skipif changed to run on unix platforms * Fixed skipif typo * Fixed typo in skipif for pdo * Fixed some output for Travis * Moved error checking inside pdo connres tests * Added links back to changelog * Fixed output for sqlsrv connres tests * Fixed output * Fixed output again * Clear AKV data after connection or when exception is thrown * Modified tests too to skip some AKV tests without real credentials * Used assignment operator also free the existing memory * Change readme links to https * Change readme links to https Merging this commit to dev * Save meta data for the fetched result set (#855) * Save meta data on fetched result sets * Fixed a compilation error * Optimized some more -- metadata should be available when fetching * Skip conversion for strings of numeric values, integers, floats, decimals etc * Set encoding char for numeric data * Apply review * Added Mojave to macOS instructions (#862) Added Mojave to macOS instructions * Fixed the broken links of Appveyor status badge (#863) * Feature request 415 for sqlsrv (#861) * Modified how to send stream data using SQLPutData and SQLParamData (#865) * Updated instructions to include Ubuntu 18.10 (#869) * Feature request 415 for pdo_sqlsrv (#873) * Skipped some tests when running against Azure (#874) * Modified config files to add the compiler flag, /Qspectre (#878) * Merge the commit from master re survey image link (#880) * Fixed the flaws of decimal tests and added more debugging (#879) * Changed sample code to adhere to PSR standard (#887) * Decimal places for money types only (#886) * Version update for 5.5.0-preview (#889) * Fixed the error in the pdo decimal test (#890) * Removed warning messages while compiling extensions (#892) * Improve performance of Unicode conversions (#891) * Update sqlsrv_statement_format_money_scales.phpt Do not encrypt money / smallmoney fields in the test table * Change log 5.5.0-preview (#895) * updated docs for php 7.3 * Fixed broken links * Added back Ubuntu 18.10 ODBC instruction * Drop tests related to fake passwords (#905) * Initialize output param buffer when allocating extra space (#907) * Enable compiling extensions statically into PHP (#904) * Dropped dbname variable and set QUOTED_IDENTIFIER to ON (#911) * Skipped the non-applicables tests against Azure Data Warehouse (#913) * Support for Managed Identity for Azure resources (#875) * Changed version 5.6.0 (#918) * Initialize hasLoss before passing into Convert function (#919) * Added new tests for setting client buffer size related to issue 228 (#920) * Fixed load order issue in sqlsrv * Added source indexing for symbols (#922) * Modified linux and mac instructions for 5.6.0 RTW (#926) * Change log 5.6.0 (#921) * add Language option on connect * Updated AppVeyor to download ODBC driver 17.3 (#941) * Issue 937 - fixed ASSERT and added new tests (#940) * Changed travis to pull mcr.microsoft.com/mssql/server:2017-latest instead (#943) * Modified money tests to test the accuracies of floats (#944) * Fixed the returned values for PDOStatement::getColumnMeta (#946) * Onboarding to Azure Pipelines (#949) * Fixed the error in Issue 570 (#952) * Added a new status badge on readme (#953) * Added new tests for issue 569 (#951) * Fix issue 955 - errors building sqlsrv alone (#956) * Modified test_largeData for Linux CI (#954) * Issue 937 - fixed ASSERT and added new tests (#940) (cherry picked from commit12d01c9189
) * Fixed the returned values for PDOStatement::getColumnMeta (#946) (cherry picked from commit7309fb90b1
) * Fix issue 955 - errors building sqlsrv alone (#956) (cherry picked from commit15f61bd0b4
) * 5.6.1 hotfix * Updated change log * Tests modified for language option for SQL Azure (#963) * Update azure-pipelines.yml for Azure Pipelines [skip ci] (#964) * Added more checks for error conditions (#965) * Removed forward cursor condition * Added row and column count checks * Revert "Update azure-pipelines.yml for Azure Pipelines [skip ci] (#964)" (#969) This reverts commit7d389e0cff
. * Add new pdo_sqlsrv tests for utf8 encoding errors (#966) * Modified to check if qualified for AE connections (#967) * Fixed test and error message * Minor fixes * Test fixes * Addressed review comments * Fixed test failure * Made Azure AD tests more robust (#973) * Addressed review comments * Issue 970: use quotes for variables (#971) * Added batch query test * Fixed 32 bit test failure * Addressed review comments * Formatting changes * Used different skipif conditions for these two tests that require AE connections (#977) * Simplified insert logic * Modified get column meta method to reference saved metadata (#978) * Revert "Used different skipif conditions for these two tests that require AE connections (#977)" (#980) This reverts commitee3c85afa8
. * Fixed failing tests (#981) * Data Classification sensitivity metadata retrieval (#979) * Added more pdo tests to verify different error conditions (#984) * Fixed memory issues with data classification (#985) * Added connection string flag * Removed unix skipif * Fixed test output * Fixed pdo test * Changed flag name * Fixed test output * Updated links and versions (#987) (#988) * Fixed test output (again) * Fixed test output (again) * Fixed test output (again) * Replaced expected test output altogether * Fixed locale issue * Corrected formatting * Replaced EXPECTF with EXPECT * Fixed two failing tests (#991) * Redesigned some tests based on recent test results (#992) * Modified pipelines to connect using sqlcmd inside of the container instead (#995) * Added batch query * Added batch query test for pdo (#997) * Added a new test and modify a non LOB sqlsrv test (#1000) * Two index zval functions are macros in php 7.4 (#1001) * Replaced uint with size_t (#1004) * Check compiler version for php 74 (#1005) * Fixed tests that failed in php 7.4 (#1006) * Improve data caching with datetime objects (#1008) * Fixed for issues found by Semmle (#1011) * Removed unneeded constants * Fixed sqlsrv_free_stmt argument info * Fixed brace escape to avoid buffer overflow * Fixed brace escape and added test * Debugging test failure on Bamboo * Removed debugging output * Debugging test failure on Bamboo * Removed debugging output * Added more test cases * Changed range check to use strchr * Added pdo test * Fixed test and formatting * Addressed various issues with PHP 7.4 beta1 (#1015) * Updated dockerfile to use UB 18.04 and PHP 73 (#1016) * Added survey results (#1017) * Updated ODBC driver 17.4 (#1019) * Modified output.py to take a new argument and travis yml to use include for coveralls (#1020) * Used constants in memory stress tests for easier configuration (#1022) * Removed KSP related scripts and files (#1030) * Updated version to 5.7.0 preview (#1029) * Change log for 5.7.0 (#1028) * Modified how drivers handle query timeout settings (#1037) * Feature request: support extended string types (#1043) * Added the required file to ansi tests (#1047) * Always Encrypted v2 support (#1045) * Change to support ae-v2 * Add support for AE V2 * Added some descriptions and comments * Fixed PDO pattern matching * Updated key generation scripts * Fixed key script * Fixed char/nchar results, fixed formatting issues * Addressed review comments * Updated key scripts * Debugging aev2 keyword failure * Debugging aev2 keyword failure * Debugging aev2 keyword failure * Debugging aev2 keyword failure * Added skipif to ae v2 keyword test * Addressed review comments * Fixed braces and camel caps * Updated test descriptions * Added detail to test descriptions * Tiny change * Modified pdo tests to work with column encryption (#1051) * Saved php types with metadata when fetching (#1049) * Updated survey charts for Nov 2019 (#1057) * Updated all CIs (#1058) * Change log 5.7.1 preview (#1060) * Fix AKV keyword test for AE v2 behaviour (#1061) * Master (#936) 5.6.0 RTW * 5.6.1 hotfix (#959) * Updated links and versions (#987) * Fixed AKV keyword tests for AE v2 * Added comment * Free proc cache before starting test * Fixed comment * Update linux mac instructions for php 7.4 (#1062) * Updated appveyor yml to build 7.3 and 7.4 (#1065) * Fixes suggested by Semmle (#1068) * Fixes suggested by Semmle * Updated azure-pipelines * Added configurable options for setting locales (#1069) #1063 * Fixed the skipif wordings and styles (#1070) * Modified locale tests to work in both linux and mac (#1074) * Include sql_variant type for buffered queries (#1080) * Updated versions and year (#1082) * Change log for version 5.8.0 (#1083) * 5.8.0 rtw docs (#1086) * updated install instructions and changelog * removed md extensions * Addressed review comments * added path * Fixed link Co-authored-by: Jenny Tam <v-yitam@microsoft.com> Co-authored-by: Gert de Pagter <BackEndTea@users.noreply.github.com> Co-authored-by: Jannes Jeising <jannes@jeising.net> Co-authored-by: Guillaume Degoulet <34232764+gdegoulet@users.noreply.github.com>
475 lines
16 KiB
C++
475 lines
16 KiB
C++
//---------------------------------------------------------------------------------------------------------------------------------
|
|
// File: pdo_parser.cpp
|
|
//
|
|
// Contents: Implements a parser to parse the PDO DSN.
|
|
//
|
|
// Copyright Microsoft Corporation
|
|
//
|
|
// Microsoft Drivers 5.8 for PHP for SQL Server
|
|
// Copyright(c) Microsoft Corporation
|
|
// All rights reserved.
|
|
// MIT License
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""),
|
|
// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
|
|
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
// IN THE SOFTWARE.
|
|
//---------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
extern "C" {
|
|
#include "php_pdo_sqlsrv.h"
|
|
}
|
|
|
|
#include "php_pdo_sqlsrv_int.h"
|
|
|
|
// Constructor
|
|
conn_string_parser:: conn_string_parser( _In_ sqlsrv_context& ctx, _In_ const char* dsn, _In_ int len, _In_ HashTable* conn_options_ht )
|
|
{
|
|
this->orig_str = dsn;
|
|
this->len = len;
|
|
this->element_ht = conn_options_ht;
|
|
this->pos = -1;
|
|
this->ctx = &ctx;
|
|
this->current_key = 0;
|
|
this->current_key_name = NULL;
|
|
}
|
|
|
|
sql_string_parser:: sql_string_parser( _In_ sqlsrv_context& ctx, _In_ const char* sql_str, _In_ int len, _In_ HashTable* placeholders_ht )
|
|
{
|
|
this->orig_str = sql_str;
|
|
this->len = len;
|
|
this->element_ht = placeholders_ht;
|
|
this->pos = -1;
|
|
this->ctx = &ctx;
|
|
this->current_key = 0;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
// Check for white space.
|
|
inline bool string_parser::is_white_space( _In_ char c )
|
|
{
|
|
if( c == ' ' || c == '\r' || c == '\n' || c == '\t' ) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Discard any trailing white spaces.
|
|
int conn_string_parser::discard_trailing_white_spaces( _In_reads_(len) const char* str, _Inout_ int len )
|
|
{
|
|
const char* end = str + ( len - 1 );
|
|
|
|
while(( this->is_white_space( *end ) ) && (len > 0) ) {
|
|
|
|
len--;
|
|
end--;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
// Discard white spaces.
|
|
bool string_parser::discard_white_spaces()
|
|
{
|
|
if( this->is_eos() ) {
|
|
|
|
return false;
|
|
}
|
|
|
|
while( this->is_white_space( this->orig_str[pos] )) {
|
|
|
|
if( !next() )
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Add a key-value pair to the hashtable
|
|
void string_parser::add_key_value_pair( _In_reads_(len) const char* value, _In_ int len TSRMLS_DC )
|
|
{
|
|
zval value_z;
|
|
ZVAL_UNDEF( &value_z );
|
|
|
|
if( len == 0 ) {
|
|
|
|
ZVAL_STRINGL( &value_z, "", 0);
|
|
}
|
|
else {
|
|
|
|
ZVAL_STRINGL( &value_z, const_cast<char*>( value ), len );
|
|
}
|
|
|
|
core::sqlsrv_zend_hash_index_update( *ctx, this->element_ht, this->current_key, &value_z TSRMLS_CC );
|
|
}
|
|
|
|
// Add a key-value pair to the hashtable with int value
|
|
void sql_string_parser::add_key_int_value_pair( _In_ unsigned int value TSRMLS_DC ) {
|
|
zval value_z;
|
|
ZVAL_LONG( &value_z, value );
|
|
|
|
core::sqlsrv_zend_hash_index_update( *ctx, this->element_ht, this->current_key, &value_z TSRMLS_CC );
|
|
}
|
|
|
|
// Validate a given DSN keyword.
|
|
void conn_string_parser::validate_key( _In_reads_(key_len) const char *key, _Inout_ int key_len TSRMLS_DC )
|
|
{
|
|
int new_len = discard_trailing_white_spaces( key, key_len );
|
|
|
|
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 ) && !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;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// encountered an invalid key, throw error.
|
|
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, static_cast<char*>( key_name ) );
|
|
}
|
|
|
|
void conn_string_parser::add_key_value_pair( _In_reads_(len) const char* value, _In_ int len TSRMLS_DC )
|
|
{
|
|
// if the keyword is 'Authentication', check whether the user specified option is supported
|
|
bool valid = true;
|
|
if ( stricmp( this->current_key_name, ODBCConnOptions::Authentication ) == 0 ) {
|
|
if (len <= 0)
|
|
valid = false;
|
|
else {
|
|
// extract option from the value by len
|
|
sqlsrv_malloc_auto_ptr<char> option;
|
|
option = static_cast<char*>( sqlsrv_malloc( len + 1 ) );
|
|
memcpy_s( option, len + 1, value, len );
|
|
option[len] = '\0';
|
|
|
|
valid = core_is_authentication_option_valid( option, len );
|
|
}
|
|
}
|
|
if( !valid ) {
|
|
THROW_PDO_ERROR( this->ctx, PDO_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION, this->current_key_name );
|
|
}
|
|
|
|
string_parser::add_key_value_pair( value, len );
|
|
}
|
|
|
|
|
|
inline bool sql_string_parser::is_placeholder_char( char c )
|
|
{
|
|
// placeholder only accepts numbers, upper and lower case alphabets and underscore
|
|
if (( c >= '0' && c <= '9' ) || ( c >= 'A' && c <= 'Z' ) || ( c >= 'a' && c <= 'z' ) || c == '_' ) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// 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->orig_str[pos] != '=' ) {
|
|
|
|
if( !next() ) {
|
|
|
|
THROW_PDO_ERROR( this->ctx, PDO_SQLSRV_ERROR_DSN_STRING_ENDED_UNEXPECTEDLY ); //EOS
|
|
}
|
|
}
|
|
|
|
this->validate_key( &( this->orig_str[start_pos] ), ( pos - start_pos ) TSRMLS_CC );
|
|
|
|
state = Value;
|
|
|
|
break;
|
|
}
|
|
|
|
case Value:
|
|
{
|
|
SQLSRV_ASSERT(( this->orig_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->orig_str[pos] == ';' ) {
|
|
|
|
add_key_value_pair( NULL, 0 TSRMLS_CC );
|
|
|
|
if( this->is_eos() ) {
|
|
|
|
break; // EOS
|
|
}
|
|
else {
|
|
|
|
// this->orig_str[pos] == ';'
|
|
state = NextKeyValuePair;
|
|
}
|
|
}
|
|
|
|
// if LCB
|
|
else if( this->orig_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->orig_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->orig_str[pos] != ';' ) {
|
|
|
|
if( ! next() ) {
|
|
|
|
break; //EOS
|
|
}
|
|
}
|
|
|
|
if( !this->is_eos() && this->orig_str[pos] == ';' ) {
|
|
|
|
// semi-colon encountered, so go to next key-value pair
|
|
state = NextKeyValuePair;
|
|
}
|
|
|
|
add_key_value_pair( &( this->orig_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->orig_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->orig_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->orig_str[pos] )) {
|
|
|
|
if( ! this->discard_white_spaces() ) {
|
|
|
|
//EOS
|
|
add_key_value_pair( &( this->orig_str[start_pos] ), end_pos - start_pos TSRMLS_CC );
|
|
break;
|
|
}
|
|
}
|
|
|
|
// if semi-colon than go to next key-value pair
|
|
if ( this->orig_str[pos] == ';' ) {
|
|
|
|
add_key_value_pair( &( this->orig_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->orig_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->orig_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;
|
|
}
|
|
}
|
|
|
|
// Primary function which parses out the named placeholders from a sql string.
|
|
void sql_string_parser::parse_sql_string( TSRMLS_D ) {
|
|
try {
|
|
int start_pos = -1;
|
|
while ( !this->is_eos() ) {
|
|
// if pos is -1, then reading from a string is an initialized read
|
|
if ( pos == -1 ) {
|
|
next();
|
|
}
|
|
// skip until a '"', '\'', ':' or '?'
|
|
char sym;
|
|
while ( this->orig_str[pos] != '"' && this->orig_str[pos] != '\'' && this->orig_str[pos] != ':' && this->orig_str[pos] != '?' && !this->is_eos() ) {
|
|
next();
|
|
}
|
|
sym = this->orig_str[pos];
|
|
// if '"' or '\'', skip until the next '"' or '\'' respectively
|
|
if ( sym == '"' || sym == '\'' ) {
|
|
next();
|
|
while ( this->orig_str[pos] != sym && !this->is_eos() ) {
|
|
next();
|
|
}
|
|
}
|
|
// if ':', store string placeholder in the placeholders hashtable
|
|
else if ( sym == ':' ) {
|
|
start_pos = this->pos;
|
|
next();
|
|
// keep going until the next space or line break
|
|
// while (!is_white_space(this->orig_str[pos]) && !this->is_eos()) {
|
|
while ( is_placeholder_char( this->orig_str[pos] )) {
|
|
next();
|
|
}
|
|
add_key_value_pair( &( this->orig_str[start_pos] ), this->pos - start_pos TSRMLS_CC );
|
|
discard_white_spaces();
|
|
// if an '=' is right after a placeholder, it means the placeholder is for output parameters
|
|
// and emulate prepare does not support output parameters
|
|
if (this->orig_str[pos] == '=') {
|
|
THROW_PDO_ERROR(this->ctx, PDO_SQLSRV_ERROR_EMULATE_INOUT_UNSUPPORTED);
|
|
}
|
|
this->current_key++;
|
|
}
|
|
// if '?', store long placeholder into the placeholders hashtable
|
|
else if ( sym == '?' ) {
|
|
next();
|
|
// add dummy value to placeholders ht to keep count of the number of placeholders
|
|
add_key_int_value_pair( this->current_key );
|
|
discard_white_spaces();
|
|
if (this->orig_str[pos] == '=') {
|
|
THROW_PDO_ERROR(this->ctx, PDO_SQLSRV_ERROR_EMULATE_INOUT_UNSUPPORTED);
|
|
}
|
|
this->current_key++;
|
|
}
|
|
}
|
|
}
|
|
catch ( pdo::PDOException& ) {
|
|
throw;
|
|
}
|
|
} |