From 9654020d67aeae672e3d4c71496f6ae8d1f0fe2c Mon Sep 17 00:00:00 2001 From: Jenny Tam Date: Fri, 20 Jul 2018 17:24:48 -0700 Subject: [PATCH 1/6] 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 --- CHANGELOG.md | 35 ++++ LICENSE | 26 +-- Linux-mac-install.md | 70 +++---- README.md | 20 +- appveyor.yml | 6 +- source/pdo_sqlsrv/config.m4 | 20 ++ source/pdo_sqlsrv/config.w32 | 2 +- source/pdo_sqlsrv/pdo_dbh.cpp | 12 +- source/pdo_sqlsrv/pdo_init.cpp | 2 +- source/pdo_sqlsrv/pdo_parser.cpp | 2 +- source/pdo_sqlsrv/pdo_stmt.cpp | 2 +- source/pdo_sqlsrv/pdo_util.cpp | 2 +- source/pdo_sqlsrv/php_pdo_sqlsrv.h | 2 +- source/pdo_sqlsrv/template.rc | 2 +- source/shared/FormattedPrint.cpp | 2 +- source/shared/FormattedPrint.h | 2 +- source/shared/StringFunctions.cpp | 2 +- source/shared/StringFunctions.h | 2 +- source/shared/core_conn.cpp | 2 +- source/shared/core_init.cpp | 2 +- source/shared/core_results.cpp | 7 +- source/shared/core_sqlsrv.h | 6 +- source/shared/core_stmt.cpp | 2 +- source/shared/core_stream.cpp | 6 +- source/shared/core_util.cpp | 2 +- source/shared/globalization.h | 2 +- source/shared/interlockedatomic.h | 2 +- source/shared/interlockedatomic_gcc.h | 2 +- source/shared/interlockedslist.h | 2 +- source/shared/localization.hpp | 2 +- source/shared/localizationimpl.cpp | 2 +- source/shared/msodbcsql.h | 2 +- source/shared/sal_def.h | 2 +- source/shared/typedefs_for_linux.h | 2 +- source/shared/version.h | 8 +- source/shared/xplat.h | 2 +- source/shared/xplat_intsafe.h | 2 +- source/shared/xplat_winerror.h | 2 +- source/shared/xplat_winnls.h | 2 +- source/sqlsrv/config.m4 | 20 ++ source/sqlsrv/config.w32 | 2 +- source/sqlsrv/conn.cpp | 8 +- source/sqlsrv/init.cpp | 2 +- source/sqlsrv/php_sqlsrv.h | 2 +- source/sqlsrv/stmt.cpp | 2 +- source/sqlsrv/template.rc | 2 +- source/sqlsrv/util.cpp | 2 +- test/functional/pdo_sqlsrv/MsCommon.inc | 158 +--------------- .../pdo_sqlsrv/MsCommon_mid-refactor.inc | 11 +- test/functional/pdo_sqlsrv/MsSetup.inc | 4 +- .../pdo_sqlsrv/PDO101_LargeColumnName.phpt | 95 +++++----- ...O101_LargeColumnName_unicode_col_name.phpt | 65 +++---- .../pdo_sqlsrv/PDO21_Connection.phpt | 2 +- .../pdo_sqlsrv/PDO_ConnPool_Unix.phpt | 13 +- test/functional/pdo_sqlsrv/isPooled.php | 4 +- .../pdo_sqlsrv/pdo_020_bind_params_array.phpt | 2 + .../pdo_sqlsrv/pdo_040_error_information.phpt | 2 + .../pdo_065_construct_persistent.phpt | 2 +- .../pdo_065_construct_prefetch.phpt | 2 +- .../pdo_707_ae_output_param_decimals.phpt | 2 +- .../pdo_ae_azure_key_vault_client_secret.phpt | 2 +- .../pdo_ae_azure_key_vault_keywords.phpt | 2 +- ..._ae_azure_key_vault_username_password.phpt | 2 +- .../pdo_sqlsrv/pdo_ae_output_param_all.phpt | 1 + .../pdo_sqlsrv/pdo_connect_encrypted.phpt | 2 +- .../pdo_sqlsrv/pdo_connection_resiliency.phpt | 16 +- .../pdo_connection_resiliency_keywords.phpt | 13 +- ...onnection_resiliency_prepare_transact.phpt | 18 +- .../pdo_connection_resiliency_timeouts.phpt | 9 +- test/functional/pdo_sqlsrv/pdo_utf8_conn.phpt | 3 +- test/functional/pdo_sqlsrv/skipif_not_akv.inc | 20 ++ .../pdo_sqlsrv/skipif_protocol_not_tcp.inc | 2 - .../skipif_version_less_than_2k14.inc | 37 +++- .../skipif_version_less_than_2k16.inc | 37 +++- .../pdo_sqlsrv/test_ae_keys_setup.phpt | 83 +++++---- test/functional/sqlsrv/MsCommon.inc | 2 +- test/functional/sqlsrv/MsSetup.inc | 4 +- test/functional/sqlsrv/TC52_StreamSend.phpt | 2 +- .../sqlsrv/TC54_StreamPrepared.phpt | 2 +- .../sqlsrv/TC84_LargeColumnName.phpt | 49 ++--- .../sqlsrv/TC84_LargeColumnName_unicode.phpt | 51 ++--- ...TC84_LargeColumnName_unicode_col_name.phpt | 75 -------- .../sqlsrv/connection_resiliency.phpt | 64 ++----- .../connection_resiliency_keywords.phpt | 15 +- ...onnection_resiliency_prepare_transact.phpt | 34 +--- .../connection_resiliency_timeouts.phpt | 32 +--- test/functional/sqlsrv/skipif_not_akv.inc | 21 +++ .../sqlsrv/skipif_protocol_not_tcp.inc | 2 - .../sqlsrv/skipif_version_less_than_2k14.inc | 37 +++- .../sqlsrv/skipif_version_less_than_2k16.inc | 36 +++- .../sqlsrv/sqlsrv_ConnPool_Unix.phpt | 13 +- ...lsrv_ae_azure_key_vault_client_secret.phpt | 2 +- .../sqlsrv_ae_azure_key_vault_keywords.phpt | 2 +- ..._ae_azure_key_vault_username_password.phpt | 2 +- .../sqlsrv/sqlsrv_ae_fetch_phptypes.phpt | 174 ++++++++++-------- .../sqlsrv/sqlsrv_connect_encrypted.phpt | 2 +- .../functional/sqlsrv/test_ae_keys_setup.phpt | 39 ++-- 97 files changed, 765 insertions(+), 816 deletions(-) create mode 100644 test/functional/pdo_sqlsrv/skipif_not_akv.inc delete mode 100644 test/functional/sqlsrv/TC84_LargeColumnName_unicode_col_name.phpt create mode 100644 test/functional/sqlsrv/skipif_not_akv.inc diff --git a/CHANGELOG.md b/CHANGELOG.md index 765bb786c..abaa24db6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,41 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) +## 5.3.0 - 2018-07-20 +Updated PECL release packages. Here is the list of updates: + +### Added +- Added support for Azure Key Vault for Always Encrypted functionality. Always Encrypted functionality is supported on Linux and macOS through Azure Key Vault +- Added support for connection resiliency on Linux and macOS (requires version 17.2 or higher of the [ODBC driver](https://docs.microsoft.com/en-us/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-2017)) +- Added support for macOS High Sierra (requires version 17 or higher of the [ODBC driver](https://docs.microsoft.com/en-us/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-2017)) +- Added support for Ubuntu 18.04 (requires version 17.2 or higher of the [ODBC driver](https://docs.microsoft.com/en-us/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-2017)) + +### Fixed +- Issue [#577](https://github.com/Microsoft/msphpsql/issues/577) - Idle Connection Resiliency doesn't work with Column Encryption enabled connections (fixed in MS ODBC Driver 17.1) +- Issue [#678](https://github.com/Microsoft/msphpsql/issues/678) - Idle Connection Resiliency doesn't work with Connection Pooling (fixed in MS ODBC Driver 17.1) +- Issue [#699](https://github.com/Microsoft/msphpsql/issues/699) - Binding output parameters fails when the query in the stored procedure returns no data. The test case has been added to the test lab. +- Issue [#705](https://github.com/Microsoft/msphpsql/issues/705) - Always Encrypted - Retrieving a negative decimal value (edge case) as output parameter causes truncation +- Issue [#706](https://github.com/Microsoft/msphpsql/issues/706) - Always Encrypted - Cannot insert double with precision and scale (38, 38) +- Issue [#707](https://github.com/Microsoft/msphpsql/issues/707) - Always Encrypted - Fetching decimals / numerics as output parameters bound to PDO::PARAM_BOOL or PDO::PARAM_INT returns floats, not integers +- Issue [#735](https://github.com/Microsoft/msphpsql/issues/735) - Extended the buffer size for PDO::lastInsertId so that data types other than integers can be supported +- Pull Request [#759](https://github.com/Microsoft/msphpsql/pull/759) - Removed the limitation of binding a binary as inout param as PDO::PARAM_STR with SQLSRV_ENCODING_BINARY +- Pull Request [#775](https://github.com/Microsoft/msphpsql/pull/775) - Fixed the truncation problem for output params with SQL types specified as SQLSRV_SQLTYPE_DECIMAL or SQLSRV_SQLTYPE_NUMERIC + +### Limitations +- No support for inout / output params when using sql_variant type +- In Linux and macOS, setlocale() only takes effect if it is invoked before the first connection. Attempting to set the locale after connecting will not work +- Always Encrypted requires [MS ODBC Driver 17+](https://docs.microsoft.com/en-us/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-2017) + - Only Windows Certificate Store and Azure Key Vault are supported. Custom Keystores are not yet supported + - Issue [#716](https://github.com/Microsoft/msphpsql/issues/716) - With Always Encrypted enabled, named parameters in subqueries are not supported + - [Always Encrypted limitations](https://docs.microsoft.com/en-us/sql/connect/php/using-always-encrypted-php-drivers?view=sql-server-2017#limitations-of-the-php-drivers-when-using-always-encrypted) + +### Known Issues +- Connection pooling on Linux or macOS is not recommended with [unixODBC](http://www.unixodbc.org/) < 2.3.6 +- When pooling is enabled in Linux or macOS + - unixODBC <= 2.3.4 (Linux and macOS) might not return proper diagnostic information, such as error messages, warnings and informative messages + - due to this unixODBC bug, fetch large data (such as xml, binary) as streams as a workaround. See the examples [here](https://github.com/Microsoft/msphpsql/wiki/Features#pooling) +- With ColumnEncryption enabled, calling stored procedures with XML parameters does not work (Issue [#674](https://github.com/Microsoft/msphpsql/issues/674)) + ## 5.2.1-preview - 2018-06-01 Updated PECL release packages. Here is the list of updates: diff --git a/LICENSE b/LICENSE index b52d9d433..13fab6115 100644 --- a/LICENSE +++ b/LICENSE @@ -1,14 +1,14 @@ -Copyright(c) 2017 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 +Copyright(c) 2018 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. \ No newline at end of file diff --git a/Linux-mac-install.md b/Linux-mac-install.md index 6964ca0e2..d84eca655 100644 --- a/Linux-mac-install.md +++ b/Linux-mac-install.md @@ -1,20 +1,24 @@ -# PHP Linux and Mac Drivers Installation Tutorial -The following instructions assume a clean environment and show how to install PHP 7.x, the Microsoft ODBC driver, Apache, and the Microsoft drivers for PHP for Microsoft SQL Server on Ubuntu 16.04 and 17.10, RedHat 7, Debian 8 and 9, Suse 12, and macOS 10.11 and 10.12. These instructions advise installing the drivers using PECL, but you can also download the prebuilt binaries from the [Microsoft Drivers for PHP for Microsoft SQL Server](https://github.com/Microsoft/msphpsql/releases) Github project page and install them following the instructions in [Loading the Microsoft Drivers for PHP for Microsoft SQL Server](https://docs.microsoft.com/sql/connect/php/loading-the-php-sql-driver)). For an explanation of extension loading and why we do not add the extensions to php.ini, see the section on [loading the drivers](https://docs.microsoft.com/sql/connect/php/loading-the-php-sql-driver#loading-the-driver-at-php-startup). +# Linux and macOS Installation Tutorial for the Microsoft Drivers for PHP for SQL Server +The following instructions assume a clean environment and show how to install PHP 7.x, the Microsoft ODBC driver, Apache, and the Microsoft drivers for PHP for Microsoft SQL Server on Ubuntu 16.04, 17.10 and 18.04, RedHat 7, Debian 8 and 9, Suse 12, and macOS 10.11, 10.12 and 10.13. These instructions advise installing the drivers using PECL, but you can also download the prebuilt binaries from the [Microsoft Drivers for PHP for Microsoft SQL Server](https://github.com/Microsoft/msphpsql/releases) Github project page and install them following the instructions in [Loading the Microsoft Drivers for PHP for Microsoft SQL Server](https://docs.microsoft.com/sql/connect/php/loading-the-php-sql-driver)). For an explanation of extension loading and why we do not add the extensions to php.ini, see the section on [loading the drivers](https://docs.microsoft.com/sql/connect/php/loading-the-php-sql-driver#loading-the-driver-at-php-startup). -These instruction install PHP 7.2 by default -- see the notes at the beginning of each section to install PHP 7.0 or 7.1. +These instructions install PHP 7.2 by default -- see the notes at the beginning of each section to install PHP 7.0 or 7.1. ## Contents of this page: -- [Installing the drivers on Ubuntu 16.04 and 17.10](#installing-the-drivers-on-ubuntu-1604-and-1710) +- [Installing the drivers on Ubuntu 16.04, 17.10, and 18.04](#installing-the-drivers-on-ubuntu-1604-1710-and-1804) - [Installing the drivers on Red Hat 7](#installing-the-drivers-on-red-hat-7) - [Installing the drivers on Debian 8 and 9](#installing-the-drivers-on-debian-8-and-9) - [Installing the drivers on Suse 12](#installing-the-drivers-on-suse-12) - [Installing the drivers on macOS El Capitan, Sierra and High Sierra](#installing-the-drivers-on-macos-el-capitan-sierra-and-high-sierra) -## Installing the drivers on Ubuntu 16.04 and 17.10 +## Installing the drivers on Ubuntu 16.04, 17.10 and 18.04 > [!NOTE] > To install PHP 7.0 or 7.1, replace 7.2 with 7.0 or 7.1 in the following commands. +> For Ubuntu 18.04, the step to add the ondrej repository is not required unless +> PHP 7.0 or 7.1 is needed. However, installing PHP 7.0 or 7.1 in Ubuntu 18.04 may +> not work as packages from the ondrej repository come with dependencies that may +> conflict with a base Ubuntu 18.04 install. ### Step 1. Install PHP ``` @@ -44,6 +48,7 @@ a2enmod mpm_prefork a2enmod php7.2 echo "extension=pdo_sqlsrv.so" >> /etc/php/7.2/apache2/conf.d/30-pdo_sqlsrv.ini echo "extension=sqlsrv.so" >> /etc/php/7.2/apache2/conf.d/20-sqlsrv.ini +exit ``` ### Step 5. Restart Apache and test the sample script ``` @@ -86,11 +91,11 @@ echo extension=pdo_sqlsrv.so >> `php --ini | grep "Scan for additional .ini file echo extension=sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/20-sqlsrv.ini exit ``` -An issue in PECL may prevent correct installation of the latest version of the drivers even if you have upgraded GCC. To install, download the packages and compile manually: +An issue in PECL may prevent correct installation of the latest version of the drivers even if you have upgraded GCC. To install, download the packages and compile manually (similar steps for pdo_sqlsrv): ``` pecl download sqlsrv -tar xvzf sqlsrv-5.2.0.tgz -cd sqlsrv-5.2.0/ +tar xvzf sqlsrv-5.3.0.tgz +cd sqlsrv-5.3.0/ phpize ./configure --with-php-config=/usr/bin/php-config make @@ -196,6 +201,7 @@ zypper install apache2 apache2-mod_php7 a2enmod php7 echo "extension=sqlsrv.so" >> /etc/php7/apache2/php.ini echo "extension=pdo_sqlsrv.so" >> /etc/php7/apache2/php.ini +exit ``` ### Step 5. Restart Apache and test the sample script ``` @@ -266,47 +272,47 @@ To test this sample script, create a file called testsql.php in your system's do "yourDatabase", - "Uid" => "yourUsername", - "PWD" => "yourPassword" + "database" => "yourDatabase", + "uid" => "yourUsername", + "pwd" => "yourPassword" ); -//Establishes the connection +// Establishes the connection $conn = sqlsrv_connect($serverName, $connectionOptions); -if( $conn === false ) { - die( FormatErrors( sqlsrv_errors())); +if ($conn === false) { + die(formatErrors(sqlsrv_errors())); } -//Select Query -$tsql= "SELECT @@Version as SQL_VERSION"; +// Select Query +$tsql = "SELECT @@Version AS SQL_VERSION"; -//Executes the query -$getResults= sqlsrv_query($conn, $tsql); +// Executes the query +$stmt = sqlsrv_query($conn, $tsql); -//Error handling -if ($getResults == FALSE) - die(FormatErrors(sqlsrv_errors())); +// Error handling +if ($stmt === false) { + die(formatErrors(sqlsrv_errors())); +} ?>

Results :

"); +while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { + echo $row['SQL_VERSION'] . PHP_EOL; } -sqlsrv_free_stmt($getResults); +sqlsrv_free_stmt($stmt); +sqlsrv_close($conn); -function FormatErrors( $errors ) +function formatErrors($errors) { - /* Display errors. */ + // Display errors echo "Error information:
"; - foreach ( $errors as $error ) - { - echo "SQLSTATE: ".$error['SQLSTATE']."
"; - echo "Code: ".$error['code']."
"; - echo "Message: ".$error['message']."
"; + foreach ($errors as $error) { + echo "SQLSTATE: ". $error['SQLSTATE'] . "
"; + echo "Code: ". $error['code'] . "
"; + echo "Message: ". $error['message'] . "
"; } } ?> diff --git a/README.md b/README.md index b30a3fa0f..20e3c0e98 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ For full details on the system requirements for the drivers, see the [system req On the client machine: - PHP 7.0.x, 7.1.x, or 7.2.x (7.2.0 and up on Unix, 7.2.1 and up on Windows) - A Web server such as Internet Information Services (IIS) is required. Your Web server must be configured to run PHP -- [Microsoft ODBC Driver 17][odbc17], [Microsoft ODBC Driver 13][odbc13], or [Microsoft ODBC Driver 11][odbc11] +- [Microsoft ODBC Driver 17, Microsoft ODBC Driver 13, or Microsoft ODBC Driver 11](https://docs.microsoft.com/en-us/sql/connect/odbc/download-odbc-driver-for-sql-server?view=sql-server-2017) On the server side, Microsoft SQL Server 2008 R2 and above on Windows are supported, as are Microsoft SQL Server 2016 and above on Linux. @@ -86,14 +86,14 @@ The version number may have trailing pre-release version identifiers to indicate - Build metadata may be denoted by a plus sign followed by 4 or 5 digits, such as `1.2.3-preview+5678` or `1.2.3+5678`. Build metadata does not figure into the precedence order. ## Future Plans -- Expand SQL Server 2016 feature support (example: Always Encrypted) +- Expand SQL Server 2016 feature support (example: Azure Active Directory) - Add more verification/fundamental tests - Bug fixes ## Guidelines for Reporting Issues We appreciate you taking the time to test the driver, provide feedback and report any issues. It would be extremely helpful if you: -- First check the [FAQ](https://github.com/Microsoft/msphpsql/wiki/FAQ) +- First check the [FAQ](https://github.com/Microsoft/msphpsql/wiki/FAQ) for common problems - Report each issue as a new issue (but check first if it's already been reported) - Please address the questions in the new issue template and provide scripts, table schema, and/or any details that may help reproduce the problem(s) @@ -106,15 +106,15 @@ Thank you! **Q:** What's next? -**A:** On March 23, 2018 we released the production release version 5.2.0 of our PHP Driver. We will continue working on our future plans and releasing previews of upcoming releases frequently. +**A:** On July 20, 2018 we released the production release version 5.3.0 of our PHP Driver. We will continue working on our future plans and releasing previews of upcoming releases. **Q:** Is Microsoft taking pull requests for this project? -**A:** Yes. Please submit pull requests to the **dev** branch and not the **master** branch. +**A:** Yes. Please submit pull requests to the **dev** branch, not the **master** branch. ## License -The Microsoft Drivers for PHP for SQL Server are licensed under the MIT license. See the LICENSE file for more details. +The Microsoft Drivers for PHP for SQL Server are licensed under the MIT license. See the LICENSE file for more details. ## Code of conduct @@ -138,12 +138,6 @@ This project has adopted the Microsoft Open Source Code of Conduct. For more inf [phpbuild]: https://wiki.php.net/internals/windows/stepbystepbuild -[phpdoc]: http://msdn.microsoft.com/library/dd903047%28SQL.11%29.aspx - -[odbc11]: https://www.microsoft.com/download/details.aspx?id=36434 - -[odbc13]: https://www.microsoft.com/download/details.aspx?id=50420 - -[odbc17]: https://www.microsoft.com/download/details.aspx?id=56567 +[phpdoc]: https://docs.microsoft.com/en-us/sql/connect/php/microsoft-php-driver-for-sql-server?view=sql-server-2017 [PHPMan]: http://php.net/manual/install.unix.php diff --git a/appveyor.yml b/appveyor.yml index 9d2cdeea1..4a0fcbddd 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -81,10 +81,10 @@ install: } Else { $env:PHP_VERSION=$env:PHP_MAJOR_VER + '.' + $env:PHP_MINOR_VER; } - - echo Downloading MSODBCSQL 17.1 + - echo Downloading MSODBCSQL 17.2 # AppVeyor build works are x64 VMs and 32-bit ODBC driver cannot be installed on it - - ps: (new-object net.webclient).DownloadFile('https://download.microsoft.com/download/E/6/B/E6BFDC7A-5BCD-4C51-9912-635646DA801E/msodbcsql_17.1.0.1_x64.msi', 'c:\projects\msodbcsql_17.1.0.1_x64.msi') - - cmd /c start /wait msiexec /i "c:\projects\msodbcsql_17.1.0.1_x64.msi" /q IACCEPTMSODBCSQLLICENSETERMS=YES ADDLOCAL=ALL + - ps: (new-object net.webclient).DownloadFile('https://download.microsoft.com/download/E/6/B/E6BFDC7A-5BCD-4C51-9912-635646DA801E/en-US/msodbcsql_17.2.0.1_x64.msi', 'c:\projects\msodbcsql_17.2.0.1_x64.msi') + - cmd /c start /wait msiexec /i "c:\projects\msodbcsql_17.2.0.1_x64.msi" /q IACCEPTMSODBCSQLLICENSETERMS=YES ADDLOCAL=ALL - echo Checking the version of MSODBCSQL - reg query "HKLM\SOFTWARE\ODBC\odbcinst.ini\ODBC Driver 17 for SQL Server" - dir %WINDIR%\System32\msodbcsql*.dll diff --git a/source/pdo_sqlsrv/config.m4 b/source/pdo_sqlsrv/config.m4 index 46e22960d..b1bfd6e48 100644 --- a/source/pdo_sqlsrv/config.m4 +++ b/source/pdo_sqlsrv/config.m4 @@ -1,3 +1,23 @@ +dnl ---------------------------------------------------------------------------------------------------------------------------------- +dnl File: config.m4 +dnl +dnl Contents: the code that will go into the configure script, indicating options, +dnl external libraries and includes, and what source files are to be compiled. +dnl +dnl Microsoft Drivers 5.3 for PHP for SQL Server +dnl Copyright(c) Microsoft Corporation +dnl All rights reserved. +dnl MIT License +dnl Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), +dnl to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +dnl 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 : +dnl The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +dnl THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +dnl FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +dnl 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 +dnl IN THE SOFTWARE. +dnl --------------------------------------------------------------------------------------------------------------------------------- + PHP_ARG_WITH(pdo_sqlsrv, for pdo_sqlsrv support, [ --with-pdo_sqlsrv Include pdo_sqlsrv support]) diff --git a/source/pdo_sqlsrv/config.w32 b/source/pdo_sqlsrv/config.w32 index bd1eaf048..7066e6254 100644 --- a/source/pdo_sqlsrv/config.w32 +++ b/source/pdo_sqlsrv/config.w32 @@ -3,7 +3,7 @@ // // Contents: JScript build configuration used by buildconf.bat // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/pdo_sqlsrv/pdo_dbh.cpp b/source/pdo_sqlsrv/pdo_dbh.cpp index 48ed3b123..330205565 100644 --- a/source/pdo_sqlsrv/pdo_dbh.cpp +++ b/source/pdo_sqlsrv/pdo_dbh.cpp @@ -3,7 +3,7 @@ // // Contents: Implements the PDO object for PDO_SQLSRV // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -43,10 +43,8 @@ const char AttachDBFileName[] = "AttachDbFileName"; const char Authentication[] = "Authentication"; const char ColumnEncryption[] = "ColumnEncryption"; const char ConnectionPooling[] = "ConnectionPooling"; -#ifdef _WIN32 const char ConnectRetryCount[] = "ConnectRetryCount"; const char ConnectRetryInterval[] = "ConnectRetryInterval"; -#endif // _WIN32 const char Database[] = "Database"; const char Driver[] = "Driver"; const char Encrypt[] = "Encrypt"; @@ -109,7 +107,6 @@ struct pdo_txn_isolation_conn_attr_func static void func( connection_option const* /*option*/, _In_ zval* value_z, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/ TSRMLS_DC ); }; -#ifdef _WIN32 struct pdo_int_conn_str_func { static void func( _In_ connection_option const* option, _In_ zval* value, sqlsrv_conn* /*conn*/, _Out_ std::string& conn_str TSRMLS_DC ) @@ -125,7 +122,6 @@ struct pdo_int_conn_str_func { conn_str += "};"; } }; -#endif // _WIN32 template struct pdo_int_conn_attr_func { @@ -243,7 +239,6 @@ const connection_option PDO_CONN_OPTS[] = { CONN_ATTR_STRING, column_encryption_set_func::func }, -#ifdef _WIN32 { PDOConnOptionNames::ConnectRetryCount, sizeof( PDOConnOptionNames::ConnectRetryCount ), @@ -262,7 +257,6 @@ const connection_option PDO_CONN_OPTS[] = { CONN_ATTR_INT, pdo_int_conn_str_func::func }, -#endif // _WIN32 { PDOConnOptionNames::Database, sizeof( PDOConnOptionNames::Database ), @@ -1276,7 +1270,7 @@ char * pdo_sqlsrv_dbh_last_id( _Inout_ pdo_dbh_t *dbh, _In_z_ const char *name, try { - char last_insert_id_query[ LAST_INSERT_ID_QUERY_MAX_LEN ]; + char last_insert_id_query[ LAST_INSERT_ID_QUERY_MAX_LEN ] = {'\0'}; if( name == NULL ) { strcpy_s( last_insert_id_query, sizeof( last_insert_id_query ), LAST_INSERT_ID_QUERY ); } @@ -1300,7 +1294,7 @@ char * pdo_sqlsrv_dbh_last_id( _Inout_ pdo_dbh_t *dbh, _In_z_ const char *name, sqlsrv_malloc_auto_ptr wsql_string; unsigned int wsql_len; - wsql_string = utf16_string_from_mbcs_string( SQLSRV_ENCODING_CHAR, reinterpret_cast( last_insert_id_query ), static_cast( strnlen_s( last_insert_id_query )), &wsql_len ); + wsql_string = utf16_string_from_mbcs_string( SQLSRV_ENCODING_CHAR, reinterpret_cast( last_insert_id_query ), sizeof(last_insert_id_query), &wsql_len ); CHECK_CUSTOM_ERROR( wsql_string == 0, driver_stmt, SQLSRV_ERROR_QUERY_STRING_ENCODING_TRANSLATE, get_last_error_message() ) { throw core::CoreException(); diff --git a/source/pdo_sqlsrv/pdo_init.cpp b/source/pdo_sqlsrv/pdo_init.cpp index 0fa961c6e..65e7a0786 100644 --- a/source/pdo_sqlsrv/pdo_init.cpp +++ b/source/pdo_sqlsrv/pdo_init.cpp @@ -3,7 +3,7 @@ // // Contents: initialization routines for PDO_SQLSRV // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/pdo_sqlsrv/pdo_parser.cpp b/source/pdo_sqlsrv/pdo_parser.cpp index 8c783b39f..baafeed73 100644 --- a/source/pdo_sqlsrv/pdo_parser.cpp +++ b/source/pdo_sqlsrv/pdo_parser.cpp @@ -5,7 +5,7 @@ // // Copyright Microsoft Corporation // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/pdo_sqlsrv/pdo_stmt.cpp b/source/pdo_sqlsrv/pdo_stmt.cpp index fd65b9eac..d41dde3b7 100644 --- a/source/pdo_sqlsrv/pdo_stmt.cpp +++ b/source/pdo_sqlsrv/pdo_stmt.cpp @@ -3,7 +3,7 @@ // // Contents: Implements the PDOStatement object for the PDO_SQLSRV // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/pdo_sqlsrv/pdo_util.cpp b/source/pdo_sqlsrv/pdo_util.cpp index 343537dd6..a05e75471 100644 --- a/source/pdo_sqlsrv/pdo_util.cpp +++ b/source/pdo_sqlsrv/pdo_util.cpp @@ -3,7 +3,7 @@ // // Contents: Utility functions used by both connection or statement functions // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/pdo_sqlsrv/php_pdo_sqlsrv.h b/source/pdo_sqlsrv/php_pdo_sqlsrv.h index ba7dd4b76..38e4cec42 100644 --- a/source/pdo_sqlsrv/php_pdo_sqlsrv.h +++ b/source/pdo_sqlsrv/php_pdo_sqlsrv.h @@ -6,7 +6,7 @@ // // Contents: Declarations for the extension // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/pdo_sqlsrv/template.rc b/source/pdo_sqlsrv/template.rc index 248c99ccc..8b94ddfad 100644 --- a/source/pdo_sqlsrv/template.rc +++ b/source/pdo_sqlsrv/template.rc @@ -3,7 +3,7 @@ // // Contents: Version resource // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/FormattedPrint.cpp b/source/shared/FormattedPrint.cpp index 6a19a4259..1b48c0e92 100644 --- a/source/shared/FormattedPrint.cpp +++ b/source/shared/FormattedPrint.cpp @@ -6,7 +6,7 @@ // Contents: Contains functions for handling Windows format strings // and UTF-16 on non-Windows platforms // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/FormattedPrint.h b/source/shared/FormattedPrint.h index 61080a424..87f15f463 100644 --- a/source/shared/FormattedPrint.h +++ b/source/shared/FormattedPrint.h @@ -4,7 +4,7 @@ // Contents: Contains functions for handling Windows format strings // and UTF-16 on non-Windows platforms // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/StringFunctions.cpp b/source/shared/StringFunctions.cpp index 550c0d359..d5183fc52 100644 --- a/source/shared/StringFunctions.cpp +++ b/source/shared/StringFunctions.cpp @@ -3,7 +3,7 @@ // // Contents: Contains functions for handling UTF-16 on non-Windows platforms // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/StringFunctions.h b/source/shared/StringFunctions.h index a0b31b783..b12e789b7 100644 --- a/source/shared/StringFunctions.h +++ b/source/shared/StringFunctions.h @@ -3,7 +3,7 @@ // // Contents: Contains functions for handling UTF-16 on non-Windows platforms // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/core_conn.cpp b/source/shared/core_conn.cpp index 7f2d16eb5..b094e110b 100644 --- a/source/shared/core_conn.cpp +++ b/source/shared/core_conn.cpp @@ -3,7 +3,7 @@ // // Contents: Core routines that use connection handles shared between sqlsrv and pdo_sqlsrv // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/core_init.cpp b/source/shared/core_init.cpp index d47080066..cda38fa55 100644 --- a/source/shared/core_init.cpp +++ b/source/shared/core_init.cpp @@ -3,7 +3,7 @@ // // Contents: common initialization routines shared by PDO and sqlsrv // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/core_results.cpp b/source/shared/core_results.cpp index d5882f2c6..62a757d86 100644 --- a/source/shared/core_results.cpp +++ b/source/shared/core_results.cpp @@ -3,7 +3,7 @@ // // Contents: Result sets // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -345,7 +345,8 @@ sqlsrv_error* odbc_get_diag_rec( _In_ sqlsrv_stmt* odbc, _In_ SQLSMALLINT record SQLWCHAR wnative_message[ SQL_MAX_ERROR_MESSAGE_LENGTH + 1 ]; SQLINTEGER native_code; SQLSMALLINT wnative_message_len = 0; - + + SQLSRV_ASSERT(odbc != NULL, "odbc_get_diag_rec: sqlsrv_stmt* odbc was null."); SQLRETURN r = SQLGetDiagRecW( SQL_HANDLE_STMT, odbc->handle(), record_number, wsql_state, &native_code, wnative_message, SQL_MAX_ERROR_MESSAGE_LENGTH + 1, &wnative_message_len ); if( !SQL_SUCCEEDED( r ) || r == SQL_NO_DATA ) { @@ -963,7 +964,7 @@ SQLRETURN binary_to_string( _Inout_ SQLCHAR* field_data, _Inout_ SQLLEN& read_so // to_copy contains the number of bytes to copy, so we divide the number in half (or quarter) // to get the number of hex digits we can copy SQLLEN to_copy_hex = to_copy / (2 * extra); - for( int i = 0; i < to_copy_hex; ++i ) { + for( SQLLEN i = 0; i < to_copy_hex; ++i ) { *h = hex_chars[ (*b & 0xf0) >> 4 ]; h++; *h = hex_chars[ (*b++ & 0x0f) ]; diff --git a/source/shared/core_sqlsrv.h b/source/shared/core_sqlsrv.h index 39e53b19a..5530a5540 100644 --- a/source/shared/core_sqlsrv.h +++ b/source/shared/core_sqlsrv.h @@ -6,7 +6,7 @@ // // Contents: Core routines and constants shared by the Microsoft Drivers for PHP for SQL Server // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -1112,10 +1112,8 @@ const char Driver[] = "Driver"; const char CharacterSet[] = "CharacterSet"; const char ConnectionPooling[] = "ConnectionPooling"; const char ColumnEncryption[] = "ColumnEncryption"; -#ifdef _WIN32 const char ConnectRetryCount[] = "ConnectRetryCount"; const char ConnectRetryInterval[] = "ConnectRetryInterval"; -#endif // _WIN32 const char Database[] = "Database"; const char Encrypt[] = "Encrypt"; const char Failover_Partner[] = "Failover_Partner"; @@ -1168,10 +1166,8 @@ enum SQLSRV_CONN_OPTIONS { SQLSRV_CONN_OPTION_KEYSTORE_PRINCIPAL_ID, SQLSRV_CONN_OPTION_KEYSTORE_SECRET, SQLSRV_CONN_OPTION_TRANSPARENT_NETWORK_IP_RESOLUTION, -#ifdef _WIN32 SQLSRV_CONN_OPTION_CONN_RETRY_COUNT, SQLSRV_CONN_OPTION_CONN_RETRY_INTERVAL, -#endif // _WIN32 // Driver specific connection options SQLSRV_CONN_OPTION_DRIVER_SPECIFIC = 1000, diff --git a/source/shared/core_stmt.cpp b/source/shared/core_stmt.cpp index 2cdb7a003..6d4d4f613 100644 --- a/source/shared/core_stmt.cpp +++ b/source/shared/core_stmt.cpp @@ -3,7 +3,7 @@ // // Contents: Core routines that use statement handles shared between sqlsrv and pdo_sqlsrv // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/core_stream.cpp b/source/shared/core_stream.cpp index 5309f0043..32780a5b2 100644 --- a/source/shared/core_stream.cpp +++ b/source/shared/core_stream.cpp @@ -3,7 +3,7 @@ // // Contents: Implementation of PHP streams for reading SQL Server data // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -26,7 +26,7 @@ namespace { int sqlsrv_stream_close( _Inout_ php_stream* stream, int /*close_handle*/ TSRMLS_DC ) { sqlsrv_stream* ss = static_cast( stream->abstract ); - SQLSRV_ASSERT( ss != NULL, "sqlsrv_stream_close: sqlsrv_stream* ss was null." ); + SQLSRV_ASSERT( ss != NULL && ss->stmt != NULL, "sqlsrv_stream_close: sqlsrv_stream* ss was null." ); // free the stream resources in the Zend engine php_stream_free( stream, PHP_STREAM_FREE_RELEASE_STREAM ); @@ -52,7 +52,7 @@ size_t sqlsrv_stream_read( _Inout_ php_stream* stream, _Out_writes_bytes_(count) sqlsrv_malloc_auto_ptr temp_buf; sqlsrv_stream* ss = static_cast( stream->abstract ); - SQLSRV_ASSERT( ss != NULL, "sqlsrv_stream_read: sqlsrv_stream* ss is NULL." ); + SQLSRV_ASSERT( ss != NULL && ss->stmt != NULL, "sqlsrv_stream_read: sqlsrv_stream* ss is NULL." ); try { diff --git a/source/shared/core_util.cpp b/source/shared/core_util.cpp index c537f766e..d8b7b2445 100644 --- a/source/shared/core_util.cpp +++ b/source/shared/core_util.cpp @@ -5,7 +5,7 @@ // // Comments: Mostly error handling and some type handling // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/globalization.h b/source/shared/globalization.h index 486a381d2..88e8d1a40 100644 --- a/source/shared/globalization.h +++ b/source/shared/globalization.h @@ -4,7 +4,7 @@ // Contents: Contains functions for handling Windows format strings // and UTF-16 on non-Windows platforms // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/interlockedatomic.h b/source/shared/interlockedatomic.h index 39e615f48..cc0163f0f 100644 --- a/source/shared/interlockedatomic.h +++ b/source/shared/interlockedatomic.h @@ -4,7 +4,7 @@ // Contents: Contains a portable abstraction for interlocked, atomic // operations on int32_t and pointer types. // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/interlockedatomic_gcc.h b/source/shared/interlockedatomic_gcc.h index 7f5a974aa..e8c8e5bb2 100644 --- a/source/shared/interlockedatomic_gcc.h +++ b/source/shared/interlockedatomic_gcc.h @@ -4,7 +4,7 @@ // Contents: Contains a portable abstraction for interlocked, atomic // operations on int32_t and pointer types. // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/interlockedslist.h b/source/shared/interlockedslist.h index 6c88f0e59..bf2bc9ca2 100644 --- a/source/shared/interlockedslist.h +++ b/source/shared/interlockedslist.h @@ -4,7 +4,7 @@ // Contents: Contains a portable abstraction for interlocked, singly // linked list. // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/localization.hpp b/source/shared/localization.hpp index 136c5a519..2ec13e09d 100644 --- a/source/shared/localization.hpp +++ b/source/shared/localization.hpp @@ -3,7 +3,7 @@ // // Contents: Contains portable classes for localization // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/localizationimpl.cpp b/source/shared/localizationimpl.cpp index 92221e984..75251eb6d 100644 --- a/source/shared/localizationimpl.cpp +++ b/source/shared/localizationimpl.cpp @@ -5,7 +5,7 @@ // Must be included in one c/cpp file per binary // A build error will occur if this inclusion policy is not followed // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/msodbcsql.h b/source/shared/msodbcsql.h index d6b74a5b8..3a759252e 100644 --- a/source/shared/msodbcsql.h +++ b/source/shared/msodbcsql.h @@ -20,7 +20,7 @@ // pecuniary loss) arising out of the use of or inability to use // this SDK, even if Microsoft has been advised of the possibility // of such damages. -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/sal_def.h b/source/shared/sal_def.h index 7be9ba68a..78478eaa1 100644 --- a/source/shared/sal_def.h +++ b/source/shared/sal_def.h @@ -3,7 +3,7 @@ // // Contents: Contains the minimal definitions to build on non-Windows platforms // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/typedefs_for_linux.h b/source/shared/typedefs_for_linux.h index 6daf7fcd6..dc3b4ca5b 100644 --- a/source/shared/typedefs_for_linux.h +++ b/source/shared/typedefs_for_linux.h @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------------------------------------------------------- // File: typedefs_for_linux.h // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/version.h b/source/shared/version.h index 140e24484..7d6554431 100644 --- a/source/shared/version.h +++ b/source/shared/version.h @@ -4,7 +4,7 @@ // File: version.h // Contents: Version number constants // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -26,12 +26,12 @@ // Increase Minor with backward compatible new functionalities and API changes. // Increase Patch for backward compatible fixes. #define SQLVERSION_MAJOR 5 -#define SQLVERSION_MINOR 2 -#define SQLVERSION_PATCH 1 +#define SQLVERSION_MINOR 3 +#define SQLVERSION_PATCH 0 #define SQLVERSION_BUILD 0 // For previews, set this constant to 1. Otherwise, set it to 0 -#define PREVIEW 1 +#define PREVIEW 0 #define SEMVER_PRERELEASE // Semantic versioning build metadata, build meta data is not counted in precedence order. diff --git a/source/shared/xplat.h b/source/shared/xplat.h index f768f112f..baa393e22 100644 --- a/source/shared/xplat.h +++ b/source/shared/xplat.h @@ -3,7 +3,7 @@ // // Contents: include for definition of Windows types for non-Windows platforms // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/xplat_intsafe.h b/source/shared/xplat_intsafe.h index 68595afb9..1baa473a7 100644 --- a/source/shared/xplat_intsafe.h +++ b/source/shared/xplat_intsafe.h @@ -4,7 +4,7 @@ // Contents: This module defines helper functions to prevent // integer overflow bugs. // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/xplat_winerror.h b/source/shared/xplat_winerror.h index 292960694..44eb7c844 100644 --- a/source/shared/xplat_winerror.h +++ b/source/shared/xplat_winerror.h @@ -3,7 +3,7 @@ // // Contents: Contains the minimal definitions to build on non-Windows platforms // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/xplat_winnls.h b/source/shared/xplat_winnls.h index 3b1cbc68b..36aceae16 100644 --- a/source/shared/xplat_winnls.h +++ b/source/shared/xplat_winnls.h @@ -3,7 +3,7 @@ // // Contents: Contains the minimal definitions to build on non-Windows platforms // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/sqlsrv/config.m4 b/source/sqlsrv/config.m4 index e03ab0f4c..6b4190665 100644 --- a/source/sqlsrv/config.m4 +++ b/source/sqlsrv/config.m4 @@ -1,3 +1,23 @@ +dnl ---------------------------------------------------------------------------------------------------------------------------------- +dnl File: config.m4 +dnl +dnl Contents: the code that will go into the configure script, indicating options, +dnl external libraries and includes, and what source files are to be compiled. +dnl +dnl Microsoft Drivers 5.3 for PHP for SQL Server +dnl Copyright(c) Microsoft Corporation +dnl All rights reserved. +dnl MIT License +dnl Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), +dnl to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +dnl 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 : +dnl The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +dnl THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +dnl FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +dnl 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 +dnl IN THE SOFTWARE. +dnl --------------------------------------------------------------------------------------------------------------------------------- + PHP_ARG_ENABLE(sqlsrv, whether to enable sqlsrv functions, [ --disable-sqlsrv Disable sqlsrv functions], yes) diff --git a/source/sqlsrv/config.w32 b/source/sqlsrv/config.w32 index 77d8c4d11..449789c4b 100644 --- a/source/sqlsrv/config.w32 +++ b/source/sqlsrv/config.w32 @@ -3,7 +3,7 @@ // // Contents: JScript build configuration used by buildconf.bat // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/sqlsrv/conn.cpp b/source/sqlsrv/conn.cpp index 183ac3c55..7bf805089 100644 --- a/source/sqlsrv/conn.cpp +++ b/source/sqlsrv/conn.cpp @@ -3,7 +3,7 @@ // // Contents: Routines that use connection handles // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -95,7 +95,6 @@ struct bool_conn_str_func { } }; -#ifdef _WIN32 struct int_conn_str_func { static void func( _In_ connection_option const* option, _In_ zval* value, sqlsrv_conn* /*conn*/, _Out_ std::string& conn_str TSRMLS_DC ) @@ -111,7 +110,6 @@ struct int_conn_str_func { conn_str += "};"; } }; -#endif // _WIN32 template struct int_conn_attr_func { @@ -188,10 +186,8 @@ const char Authentication[] = "Authentication"; const char CharacterSet[] = "CharacterSet"; const char ColumnEncryption[] = "ColumnEncryption"; const char ConnectionPooling[] = "ConnectionPooling"; -#ifdef _WIN32 const char ConnectRetryCount[] = "ConnectRetryCount"; const char ConnectRetryInterval[] = "ConnectRetryInterval"; -#endif // _WIN32 const char Database[] = "Database"; const char DateAsString[] = "ReturnDatesAsStrings"; const char Driver[] = "Driver"; @@ -324,7 +320,6 @@ const connection_option SS_CONN_OPTS[] = { CONN_ATTR_STRING, column_encryption_set_func::func }, -#ifdef _WIN32 { SSConnOptionNames::ConnectRetryCount, sizeof( SSConnOptionNames::ConnectRetryCount ), @@ -343,7 +338,6 @@ const connection_option SS_CONN_OPTS[] = { CONN_ATTR_INT, int_conn_str_func::func }, -#endif // _WIN32 { SSConnOptionNames::Database, sizeof( SSConnOptionNames::Database ), diff --git a/source/sqlsrv/init.cpp b/source/sqlsrv/init.cpp index 7385dc6b1..bb8ab04b4 100644 --- a/source/sqlsrv/init.cpp +++ b/source/sqlsrv/init.cpp @@ -2,7 +2,7 @@ // File: init.cpp // Contents: initialization routines for the extension // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/sqlsrv/php_sqlsrv.h b/source/sqlsrv/php_sqlsrv.h index 17175730a..6c5e7b015 100644 --- a/source/sqlsrv/php_sqlsrv.h +++ b/source/sqlsrv/php_sqlsrv.h @@ -8,7 +8,7 @@ // // Comments: Also contains "internal" declarations shared across source files. // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/sqlsrv/stmt.cpp b/source/sqlsrv/stmt.cpp index 96aeae8a0..ac334cb9b 100644 --- a/source/sqlsrv/stmt.cpp +++ b/source/sqlsrv/stmt.cpp @@ -3,7 +3,7 @@ // // Contents: Routines that use statement handles // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/sqlsrv/template.rc b/source/sqlsrv/template.rc index 446f50d88..ffee85372 100644 --- a/source/sqlsrv/template.rc +++ b/source/sqlsrv/template.rc @@ -3,7 +3,7 @@ // // Contents: Version resource // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/sqlsrv/util.cpp b/source/sqlsrv/util.cpp index 50b963e48..bc26658c0 100644 --- a/source/sqlsrv/util.cpp +++ b/source/sqlsrv/util.cpp @@ -5,7 +5,7 @@ // // Comments: Mostly error handling and some type handling // -// Microsoft Drivers 5.2 for PHP for SQL Server +// Microsoft Drivers 5.3 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/test/functional/pdo_sqlsrv/MsCommon.inc b/test/functional/pdo_sqlsrv/MsCommon.inc index cddfdab9c..b1c479e95 100644 --- a/test/functional/pdo_sqlsrv/MsCommon.inc +++ b/test/functional/pdo_sqlsrv/MsCommon.inc @@ -8,30 +8,6 @@ */ -// -// looks like an additional file (in addition to pdo_test_base.inc) may be needed for these PHPTs -// to be runnable from the MSSQL teams' internal proprietary test running system -// - -function IsAEQualified($conn) -{ - $msodbcsql_ver = $conn->getAttribute(PDO::ATTR_CLIENT_VERSION)["DriverVer"]; - $msodbcsql_maj = explode(".", $msodbcsql_ver)[0]; - if ($msodbcsql_maj < 17) { - return false; - } - require 'MsSetup.inc'; - if ($daasMode) { - // running against Azure - return true; - } - // if not Azure, check the server version - $server_ver = $conn->getAttribute(PDO::ATTR_SERVER_VERSION); - if (explode('.', $server_ver)[0] < 13) - return false; - return true; -} - // TO BE DELETED function connect($options=array()) { @@ -40,7 +16,7 @@ function connect($options=array()) // simply use $databaseName from MsSetup.inc to facilitate testing in Azure, // which does not support switching databases require 'MsSetup.inc'; - $conn = new PDO( "sqlsrv:Server=$server;database=$databaseName;ConnectionPooling=false;" , $uid, $pwd, $options); + $conn = new PDO( "sqlsrv:Server=$server;database=$databaseName;Driver=$driver;ConnectionPooling=false;" , $uid, $pwd, $options); $conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); return $conn; } @@ -58,138 +34,6 @@ function connect($options=array()) } } - -/** - * Connect to the database specified in MsSetup.inc; Column Encryption keywords automatically added when $keystore is not none - * @param string $keywords : string to append to the dsn string in PDO::_construct - * @param array $options : attributes to pass to PDO::_construct - * @param bool $disableCE : flag for disabling column encryption even when keystore is NOT none - * for testing fetching encrypted data when connection column encryption is off - * @return PDO connection object - */ -function ae_connect( $keywords='', $options=array(), $disableCE = false ) -{ - try - { - // simply use $databaseName from MsSetup.inc to facilitate testing in Azure, - // which does not support switching databases - require 'MsSetup.inc'; - $dsn = "sqlsrv:Server=$server;database=$databaseName;ConnectionPooling=false;"; - if ( $keystore != "none" && !$disableCE ) - { - $dsn .= "ColumnEncryption=Enabled;"; - } - if ( $keystore == "ksp" && !$disableCE ) - { - require( 'AE_Ksp.inc' ); - $ksp_path = getKSPPath(); - $dsn .= "CEKeystoreProvider=$ksp_path;CEKeystoreName=$ksp_name;CEKeystoreEncryptKey=$encrypt_key;"; - } - if ( $keywords ) - { - $dsn .= $keywords; - } - $conn = new PDO( $dsn, $uid, $pwd, $options ); - $conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); - return $conn; - } - catch( PDOException $e ) - { - var_dump( $e ); - exit; - } - catch(Exception $e) - { - var_dump( $e ); - exit; - } -} - - -/** - * @return string CEK name depending on the connection keywords - */ -function getCekName() -{ - require 'MsSetup.inc'; - $cekName = ''; - switch ( $keystore ) { - case "none": - $cekName = ''; - break; - case "win": - $cekName = 'AEColumnKey'; - break; - case "ksp": - $cekName = 'CustomCEK'; - break; - case "akv": - $cekName = 'AKVColumnKey'; - break; - default: - echo "getCekName: Invalid keystore name.\n"; - } - return $cekName; -} - - -/** - * class for encapsulating column metadata needed for creating a table - */ -class columnMeta { - public $colName; - public $dataType; //a string that includes the size of the type if necessary (e.g., decimal(10,5)) - public $encType; //randomized or deterministic; default is deterministic - public $options; //a string that is null by default (e.g. NOT NULL Identity (1,1) ) - - function __construct( $dataType, $colName = null, $options = null, $encType = "deterministic" ) - { - if ( is_null( $colName )) - { - $this->colName = get_default_colname( $dataType ); - } - else - { - $this->colName = $colName; - } - $this->dataType = $dataType; - $this->encType = $encType; - $this->options = $options; - } - /** - * @return string column definition for creating a table - */ - function getColDef() - { - require 'MsSetup.inc'; - $append = " "; - - // an identity column is not encrypted because a select query with identity column as the where clause is often run and the user want to have to bind parameter every time - if ( $keystore != "none" && stripos( $this->options, "identity" ) === false ) - { - $cekName = getCekName(); - if ( stripos( $this->dataType, "char" ) !== false ) - $append .= "COLLATE Latin1_General_BIN2 "; - $append .= sprintf( "ENCRYPTED WITH (ENCRYPTION_TYPE = %s, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = $cekName) ", $this->encType ); - } - $append .= $this->options; - $colDef = "[" . $this->colName . "] " . $this->dataType . $append; - return $colDef; - } -} - - -/** - * @return string default column name when a name is not provided in the columnMeta class - */ -function get_default_colname( $dataType ) -{ - $colName = "c_" . str_replace( ",", "_", str_replace( "(", "_", $dataType )); - $colName = rtrim( $colName, ")" ); - return $colName; -} - - /** * Create a table * @param object $conn : PDO connection object diff --git a/test/functional/pdo_sqlsrv/MsCommon_mid-refactor.inc b/test/functional/pdo_sqlsrv/MsCommon_mid-refactor.inc index dd183c32a..cf2ff605c 100644 --- a/test/functional/pdo_sqlsrv/MsCommon_mid-refactor.inc +++ b/test/functional/pdo_sqlsrv/MsCommon_mid-refactor.inc @@ -13,10 +13,6 @@ // to be runnable from the MSSQL teams' internal proprietary test running system // -const KSP_NAME = 'MyCustomKSPName'; -const ENCRYPT_KEY = 'LPKCWVD07N3RG98J0MBLG4H2'; -const KSP_TEST_TABLE = 'CustomKSPTestTable'; - function isAEQualified($conn) { $msodbcsql_ver = $conn->getAttribute(PDO::ATTR_CLIENT_VERSION)["DriverVer"]; @@ -52,7 +48,7 @@ function connect($keywords = '', $options=array(), $errmode = PDO::ERRMODE_EXCEP // simply use $databaseName from MsSetup.inc to facilitate testing in Azure, // which does not support switching databases require("MsSetup.inc"); - $dsn = getDSN($server, $databaseName, $keywords, $disableCE); + $dsn = getDSN($server, $databaseName, $driver, $keywords, $disableCE); $conn = new PDO($dsn, $uid, $pwd, $options); if ($errmode == PDO::ERRMODE_EXCEPTION || $errmode == PDO::ERRMODE_WARNING || $errmode == PDO::ERRMODE_SILENT) { $conn->setAttribute(PDO::ATTR_ERRMODE, $errmode); @@ -76,7 +72,7 @@ function connect($keywords = '', $options=array(), $errmode = PDO::ERRMODE_EXCEP * @param bool $disableCE : flag for disabling column encryption even when keystore is NOT none * @return string dsn string used for PDO constructor */ -function getDSN($sqlsrvserver, $database, $keywords = '', $disableCE = false) +function getDSN($sqlsrvserver, $database, $driver = null, $keywords = '', $disableCE = false) { require("MsSetup.inc"); $dsn = ""; @@ -89,6 +85,9 @@ function getDSN($sqlsrvserver, $database, $keywords = '', $disableCE = false) if ($database) { $dsn .= "database=$database;"; } + if (!is_null($driver)) { + $dsn .= "driver=$driver;"; + } if ($keystore != "none" && !$disableCE) { $dsn .= "ColumnEncryption=Enabled;"; } diff --git a/test/functional/pdo_sqlsrv/MsSetup.inc b/test/functional/pdo_sqlsrv/MsSetup.inc index e07c46a7d..823f283cc 100644 --- a/test/functional/pdo_sqlsrv/MsSetup.inc +++ b/test/functional/pdo_sqlsrv/MsSetup.inc @@ -18,7 +18,6 @@ if (isset($_ENV['MSSQL_SERVER']) || isset($_ENV['MSSQL_USER']) || isset($_ENV['M $uid = 'TARGET_USERNAME'; $pwd = 'TARGET_PASSWORD'; $databaseName = 'TARGET_DATABASE'; - $DriverName = "ODBC Driver 11 for SQL Server"; } $adServer = 'TARGET_AD_SERVER'; @@ -27,13 +26,12 @@ $adUser = 'TARGET_AD_USERNAME'; $adPassword = 'TARGET_AD_PASSWORD'; $driverType = true; -$PhpDriver = "ODBC Driver 11 for SQL Server"; +$driver = "ODBC Driver 17 for SQL Server"; $tableName = 'pdo_test_table'; $tableIndex = 'php_test_table_idx'; $procName = 'php_test_proc'; $fileName = 'php_test_file.dat'; -$dsn = "odbc:Driver={$DriverName};Server=$server"; $connectionOptions = array(); $daasMode = false; $marsMode = true; diff --git a/test/functional/pdo_sqlsrv/PDO101_LargeColumnName.phpt b/test/functional/pdo_sqlsrv/PDO101_LargeColumnName.phpt index b5019290d..be6234f2e 100644 --- a/test/functional/pdo_sqlsrv/PDO101_LargeColumnName.phpt +++ b/test/functional/pdo_sqlsrv/PDO101_LargeColumnName.phpt @@ -1,76 +1,77 @@ ---TEST-- -PDO - Large Column Name Test ---DESCRIPTION-- -Verifies that long column names are supported (up to 128 chars). ---ENV-- -PHPT_EXEC=true ---SKIPIF-- - ---FILE-- +--TEST-- +PDO - Large Column Name Test +--DESCRIPTION-- +Verifies that long column names are supported (up to 128 chars). +--ENV-- +PHPT_EXEC=true +--SKIPIF-- + +--FILE-- query("CREATE TABLE [$tableName] ([$columnName] int)"); - $conn->query("INSERT INTO [$tableName] ([$columnName]) VALUES (5)"); $stmt = $conn->query("SELECT * from [$tableName]"); - if ( null == $stmt ) - { - if (!$expectfail) - FatalError("Possible regression: Unable to retrieve inserted value."); - } - - DropTable($conn, $tableName); - + dropTable($conn, $tableName); } //-------------------------------------------------------------------- -// Repro +// repro // //-------------------------------------------------------------------- -function Repro() +function repro() { - $testName = "PDO - Large Column Name Test"; - StartTest($testName); - - $columnName = "a"; - - try - { - for ($a = 1; $a <= 128; $a++) - { - LargeColumnNameTest($columnName, $a > 128); - $columnName .= "A"; - } - } - catch (Exception $e) - { - echo $e->getMessage(); + startTest($testName); + + // The maximum size of a column name is 128 characters + $maxlen = 128; + $columnName = str_repeat('A', $maxlen); + + try { + largeColumnNameTest($columnName); + } catch (Exception $e) { + echo "Possible regression: Unable to retrieve inserted value\n"; + print_r($e->getMessage()); + echo "\n"; } - - EndTest($testName); + + // Now add another character to the name + $columnName .= 'A'; + try { + largeColumnNameTest($columnName); + } catch (Exception $e) { + // Expects to fail + $expected = 'is too long. Maximum length is 128.'; + if (strpos($e->getMessage(), $expected) === false) { + print_r($e->getMessage()); + echo "\n"; + } + } + + endTest($testName); } -Repro(); -?> ---EXPECT-- -Test "PDO - Large Column Name Test" completed successfully. +repro(); +?> +--EXPECT-- +Test "PDO - Large Column Name Test" completed successfully. diff --git a/test/functional/pdo_sqlsrv/PDO101_LargeColumnName_unicode_col_name.phpt b/test/functional/pdo_sqlsrv/PDO101_LargeColumnName_unicode_col_name.phpt index 634dc5272..9ad27164e 100644 --- a/test/functional/pdo_sqlsrv/PDO101_LargeColumnName_unicode_col_name.phpt +++ b/test/functional/pdo_sqlsrv/PDO101_LargeColumnName_unicode_col_name.phpt @@ -8,69 +8,70 @@ PHPT_EXEC=true --FILE-- query("CREATE TABLE [$tableName] ([$columnName] int)"); - $conn->query("INSERT INTO [$tableName] ([$columnName]) VALUES (5)"); $stmt = $conn->query("SELECT * from [$tableName]"); - if ( null == $stmt ) - { - if (!$expectfail) - FatalError("Possible regression: Unable to retrieve inserted value."); - } - - DropTable($conn, $tableName); - + dropTable($conn, $tableName); } //-------------------------------------------------------------------- -// Repro +// repro // //-------------------------------------------------------------------- -function Repro() +function repro() { - $testName = "PDO - Large Column Name Test"; - StartTest($testName); + startTest($testName); - $columnName = "是"; + // The maximum size of a column name is 128 characters + $maxlen = 128; + $columnName = str_repeat('是', $maxlen); - try - { - for ($a = 1; $a <= 128; $a++) - { - LargeColumnNameTest($columnName, $a > 128); - $columnName .= "是"; - } + try { + largeColumnNameTest($columnName); + } catch (Exception $e) { + echo "Possible regression: Unable to retrieve inserted value\n"; + print_r($e->getMessage()); + echo "\n"; } - catch (Exception $e) - { - echo $e->getMessage(); + + // Now add another character to the name + $columnName .= '是'; + try { + largeColumnNameTest($columnName); + } catch (Exception $e) { + // Expects to fail + $expected = 'is too long. Maximum length is 128.'; + if (strpos($e->getMessage(), $expected) === false) { + print_r($e->getMessage()); + echo "\n"; + } } - EndTest($testName); + endTest($testName); } -Repro(); +repro(); + ?> --EXPECT-- Test "PDO - Large Column Name Test" completed successfully. diff --git a/test/functional/pdo_sqlsrv/PDO21_Connection.phpt b/test/functional/pdo_sqlsrv/PDO21_Connection.phpt index f09899626..9498a3585 100644 --- a/test/functional/pdo_sqlsrv/PDO21_Connection.phpt +++ b/test/functional/pdo_sqlsrv/PDO21_Connection.phpt @@ -15,7 +15,7 @@ try { // Invalid connection attempt => errors are expected $serverName="InvalidServerName"; - $dsn = getDSN($serverName, $databaseName); + $dsn = getDSN($serverName, $databaseName, $driver); $conn1 = new PDO($dsn, $uid, $pwd, $connectionOptions); if ($conn1) { printf("Invalid connection attempt should have failed.\n"); diff --git a/test/functional/pdo_sqlsrv/PDO_ConnPool_Unix.phpt b/test/functional/pdo_sqlsrv/PDO_ConnPool_Unix.phpt index 05bf24a71..c68a46b14 100644 --- a/test/functional/pdo_sqlsrv/PDO_ConnPool_Unix.phpt +++ b/test/functional/pdo_sqlsrv/PDO_ConnPool_Unix.phpt @@ -6,6 +6,15 @@ This test assumes the default odbcinst.ini has not been modified. --FILE-- exec($sql); diff --git a/test/functional/pdo_sqlsrv/pdo_040_error_information.phpt b/test/functional/pdo_sqlsrv/pdo_040_error_information.phpt index 93b6e2fd4..c8424856d 100644 --- a/test/functional/pdo_sqlsrv/pdo_040_error_information.phpt +++ b/test/functional/pdo_sqlsrv/pdo_040_error_information.phpt @@ -12,6 +12,8 @@ try { // Create table $tableName = 'pdo_040test'; + dropTable($conn, $tableName); + // common function insertRow() is not used here since the test deliberately // executes an invalid insertion statement // thus it's not necessary to create an encrypted column for testing column encryption diff --git a/test/functional/pdo_sqlsrv/pdo_065_construct_persistent.phpt b/test/functional/pdo_sqlsrv/pdo_065_construct_persistent.phpt index 883da0299..8f2d8e8f7 100644 --- a/test/functional/pdo_sqlsrv/pdo_065_construct_persistent.phpt +++ b/test/functional/pdo_sqlsrv/pdo_065_construct_persistent.phpt @@ -13,7 +13,7 @@ require_once("MsCommon_mid-refactor.inc"); try { echo "Testing a connection with ATTR_PERSISTENT...\n"; // setting PDO::ATTR_PERSISTENT in PDO constructor returns an exception - $dsn = getDSN($server, $databaseName); + $dsn = getDSN($server, $databaseName, $driver); $attr = array(PDO::ATTR_PERSISTENT => true); $conn = new PDO($dsn, $uid, $pwd, $attr); //free the connection diff --git a/test/functional/pdo_sqlsrv/pdo_065_construct_prefetch.phpt b/test/functional/pdo_sqlsrv/pdo_065_construct_prefetch.phpt index 463b7ac4d..88f47495f 100644 --- a/test/functional/pdo_sqlsrv/pdo_065_construct_prefetch.phpt +++ b/test/functional/pdo_sqlsrv/pdo_065_construct_prefetch.phpt @@ -10,7 +10,7 @@ require_once("MsSetup.inc"); require_once("MsCommon_mid-refactor.inc"); try { echo "Testing a connection with ATTR_PREFETCH before ERRMODE_EXCEPTION...\n"; - $dsn = getDSN($server, $databaseName); + $dsn = getDSN($server, $databaseName, $driver); $attr = array(PDO::ATTR_PREFETCH => true, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION); $conn = new PDO($dsn, $uid, $pwd, $attr); diff --git a/test/functional/pdo_sqlsrv/pdo_707_ae_output_param_decimals.phpt b/test/functional/pdo_sqlsrv/pdo_707_ae_output_param_decimals.phpt index 6b59c134e..67c0f4fd0 100644 --- a/test/functional/pdo_sqlsrv/pdo_707_ae_output_param_decimals.phpt +++ b/test/functional/pdo_sqlsrv/pdo_707_ae_output_param_decimals.phpt @@ -7,7 +7,7 @@ do not need to be encrypted --ENV-- PHPT_EXEC=true --SKIPIF-- - + --FILE-- + --FILE-- + --FILE-- + --FILE-- "int", createTable($conn, $tbname, $colMetaArr); // Create a Store Procedure $spname = 'selectAllColumns'; +dropProc($conn, $spname); $spSql = "CREATE PROCEDURE $spname ( @c1_int int OUTPUT, @c2_smallint smallint OUTPUT, @c3_tinyint tinyint OUTPUT, @c4_bit bit OUTPUT, diff --git a/test/functional/pdo_sqlsrv/pdo_connect_encrypted.phpt b/test/functional/pdo_sqlsrv/pdo_connect_encrypted.phpt index 8b3b0a0e6..124df22b7 100644 --- a/test/functional/pdo_sqlsrv/pdo_connect_encrypted.phpt +++ b/test/functional/pdo_sqlsrv/pdo_connect_encrypted.phpt @@ -1,7 +1,7 @@ --TEST-- Test new connection keyword ColumnEncryption --SKIPIF-- - + --FILE-- getMessage()); + $err = $e->getMessage(); + if (strpos($err, 'SQLSTATE[08S02]')===false or (strpos($err, 'TCP Provider')===false and strpos($err, 'SMux Provider')===false)) { + echo "Error: Wrong error message.\n"; + print_r($err); + } } unset($conn); @@ -200,14 +204,18 @@ try { } } catch (PDOException $e) { echo "Error executing statement 8.\n"; - print_r($e->getMessage()); + $err = $e->getMessage(); + if (strpos($err, 'SQLSTATE[IMSSP]')===false or strpos($err, 'The connection cannot process this operation because there is a statement with pending results')===false) { + echo "Error: Wrong error message.\n"; + print_r($err); + } } unset($conn); unset($conn_break); ?> ---EXPECTREGEX-- +--EXPECT-- Statement 1 successful. 16 rows in result set. Statement 2 successful. @@ -219,7 +227,5 @@ Statement 4 successful. Statement 5 successful. -1 rows in result set. Error executing statement 6. -SQLSTATE\[08S02\]: \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]TCP Provider: An existing connection was forcibly closed by the remote host. Statement 7 successful. Error executing statement 8. -SQLSTATE\[IMSSP\]: The connection cannot process this operation because there is a statement with pending results. To make the connection available for other queries, either fetch all results or cancel or free the statement. For more information, see the product documentation about the MultipleActiveResultSets connection option. diff --git a/test/functional/pdo_sqlsrv/pdo_connection_resiliency_keywords.phpt b/test/functional/pdo_sqlsrv/pdo_connection_resiliency_keywords.phpt index 1d7b066e9..b012eed98 100644 --- a/test/functional/pdo_sqlsrv/pdo_connection_resiliency_keywords.phpt +++ b/test/functional/pdo_sqlsrv/pdo_connection_resiliency_keywords.phpt @@ -1,8 +1,7 @@ --TEST-- Test the connection resiliency keywords ConnectRetryCount and ConnectRetryInterval and their ranges of acceptable values --SKIPIF-- - + --FILE-- getMessage() ); + echo "Transaction failed.\n"; + $err = $e->getMessage(); + if (strpos($err, 'SQLSTATE[08S02]')===false or (strpos($err, 'TCP Provider')===false and strpos($err, 'SMux Provider')===false)) { + echo "Error: Wrong error message.\n"; + print_r($err); + } } // This try catch block prevents an Uncaught PDOException error that occurs @@ -201,17 +206,20 @@ try } catch ( PDOException $e ) { - print_r( $e->getMessage() ); + $err = $e->getMessage(); + if (strpos($err, 'SQLSTATE[08S01]')===false or strpos($err, 'Communication link failure')===false) { + echo "Error: Wrong error message.\n"; + print_r($err); + } } $conn_break = null; ?> ---EXPECTREGEX-- +--EXPECT-- Statement 1 prepared. Statement 1 executed. Transaction begun. Transaction was committed. Transaction begun. -SQLSTATE\[08S02\]: \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]TCP Provider: An existing connection was forcibly closed by the remote host. -SQLSTATE\[08S01\]: \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]Communication link failure +Transaction failed. diff --git a/test/functional/pdo_sqlsrv/pdo_connection_resiliency_timeouts.phpt b/test/functional/pdo_sqlsrv/pdo_connection_resiliency_timeouts.phpt index 4389b3a95..279a7eb48 100644 --- a/test/functional/pdo_sqlsrv/pdo_connection_resiliency_timeouts.phpt +++ b/test/functional/pdo_sqlsrv/pdo_connection_resiliency_timeouts.phpt @@ -40,7 +40,11 @@ try catch( PDOException $e ) { echo "Error executing statement 1.\n"; - print_r( $e->getMessage() ); + $err = $e->getMessage(); + if (strpos($err, 'SQLSTATE[08S02]')===false or (strpos($err, 'TCP Provider')===false and strpos($err, 'SMux Provider')===false)) { + echo "Error: Wrong error message.\n"; + print_r($err); + } } $conn = null; @@ -82,7 +86,6 @@ $conn_break = null; DropTables( $server, $uid, $pwd, $tableName1, $tableName2 ); ?> ---EXPECTREGEX-- +--EXPECT-- Error executing statement 1. -SQLSTATE\[08S02\]: \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]TCP Provider: An existing connection was forcibly closed by the remote host. Query successfully executed. diff --git a/test/functional/pdo_sqlsrv/pdo_utf8_conn.phpt b/test/functional/pdo_sqlsrv/pdo_utf8_conn.phpt index f51d3ba6b..a5c31e09e 100644 --- a/test/functional/pdo_sqlsrv/pdo_utf8_conn.phpt +++ b/test/functional/pdo_sqlsrv/pdo_utf8_conn.phpt @@ -4,6 +4,7 @@ UTF-8 connection strings --FILE-- query( "SELECT @@VERSION" ); -if ($stmt) { - $ver_string = $stmt->fetch(PDO::FETCH_NUM)[0]; -} else { - die( "skip Could not fetch SQL Server version during SKIPIF."); +$msodbcsql_ver = $conn->getAttribute(PDO::ATTR_CLIENT_VERSION)["DriverVer"]; +$msodbcsql_maj = explode(".", $msodbcsql_ver)[0]; +$msodbcsql_min = explode(".", $msodbcsql_ver)[1]; + +if (!$is_win) { + if ($msodbcsql_maj < 17 or $msodbcsql_min < 2) { + die("skip Unsupported ODBC driver version"); + } } -$version = explode(' ', $ver_string); +// Get SQL Server Version +// Exclude this check if running on Azure +if (!$daasMode) { + $stmt = $conn->query( "SELECT @@VERSION" ); + if ($stmt) { + $ver_string = $stmt->fetch(PDO::FETCH_NUM)[0]; + } else { + die( "skip Could not fetch SQL Server version during SKIPIF."); + } + + $version = explode(' ', $ver_string); -if ($version[3] < '2014') { - die("skip Wrong version of SQL Server, 2014 or later required"); + if ($version[3] < '2014') { + die("skip Wrong version of SQL Server, 2014 or later required"); + } } ?> diff --git a/test/functional/pdo_sqlsrv/skipif_version_less_than_2k16.inc b/test/functional/pdo_sqlsrv/skipif_version_less_than_2k16.inc index e2f9456bf..72553974b 100644 --- a/test/functional/pdo_sqlsrv/skipif_version_less_than_2k16.inc +++ b/test/functional/pdo_sqlsrv/skipif_version_less_than_2k16.inc @@ -1,10 +1,14 @@ query( "SELECT @@VERSION" ); -if ($stmt) { - $ver_string = $stmt->fetch(PDO::FETCH_NUM)[0]; -} else { - die( "skip Could not fetch SQL Server version during SKIPIF."); +$msodbcsql_ver = $conn->getAttribute(PDO::ATTR_CLIENT_VERSION)["DriverVer"]; +$msodbcsql_maj = explode(".", $msodbcsql_ver)[0]; +$msodbcsql_min = explode(".", $msodbcsql_ver)[1]; + +if (!$is_win) { + if ($msodbcsql_maj < 17) { + die("skip Unsupported ODBC driver version"); + } } -$version = explode(' ', $ver_string); +// Get SQL Server Version +// Exclude this check if running on Azure +if (!$daasMode) { + $stmt = $conn->query( "SELECT @@VERSION" ); + if ($stmt) { + $ver_string = $stmt->fetch(PDO::FETCH_NUM)[0]; + } else { + die( "skip Could not fetch SQL Server version during SKIPIF."); + } + + $version = explode(' ', $ver_string); -if ($version[3] < '2016') { - die("skip Wrong version of SQL Server, 2016 or later required"); + if ($version[3] < '2016') { + die("skip Wrong version of SQL Server, 2016 or later required"); + } } ?> diff --git a/test/functional/pdo_sqlsrv/test_ae_keys_setup.phpt b/test/functional/pdo_sqlsrv/test_ae_keys_setup.phpt index ed42f74c6..e8f46546d 100644 --- a/test/functional/pdo_sqlsrv/test_ae_keys_setup.phpt +++ b/test/functional/pdo_sqlsrv/test_ae_keys_setup.phpt @@ -1,36 +1,49 @@ ---TEST-- -retrieval of names of column master key and column encryption key generated in the database setup ---SKIPIF-- - ---FILE-- -query($query); - $master_key_row = $stmt->fetch(); - - $query = "SELECT name FROM sys.column_encryption_keys"; - $stmt = $conn->query($query); - $encryption_key_row = $stmt->fetch(); - - if ($master_key_row[0] == 'AEMasterKey' && $encryption_key_row[0] == 'AEColumnKey'){ - echo "Test Successfully done.\n"; - } - else { - die("Column Master Key and Column Encryption Key not created.\n"); - } - unset($stmt); -} -else { - echo "Test Successfully done.\n"; -} -unset($conn); -?> ---EXPECT-- +--TEST-- +Test the existence of Windows Always Encrypted keys generated in the database setup +--DESCRIPTION-- +This test iterates through the rows of sys.column_master_keys and/or +sys.column_encryption_keys to look for the specific column master key and +column encryption key generated in the database setup +--SKIPIF-- + +--FILE-- +query($query); + + // Do not assume the master key must be the first one created + $found = false; + while ($master_key_row = $stmt->fetch()) { + if ($master_key_row[0] == 'AEMasterKey') { + $found = true; + } + } + if (!$found) { + die("Windows Column Master Key not created.\n"); + } + + // Do not assume the encryption key must be the first one created + $query = "SELECT name FROM sys.column_encryption_keys"; + $stmt = $conn->query($query); + + $found = false; + while ($encryption_key_row = $stmt->fetch()) { + if ($encryption_key_row[0] == 'AEColumnKey') { + $found = true; + } + } + if (!$found) { + die("Windows Column Encryption Key not created.\n"); + } + unset($stmt); +} + +echo "Test Successfully done.\n"; +unset($conn); +?> +--EXPECT-- Test Successfully done. \ No newline at end of file diff --git a/test/functional/sqlsrv/MsCommon.inc b/test/functional/sqlsrv/MsCommon.inc index 13900e2ec..def2d0f50 100644 --- a/test/functional/sqlsrv/MsCommon.inc +++ b/test/functional/sqlsrv/MsCommon.inc @@ -472,7 +472,7 @@ function isLocaleSupported() if (isWindows()) { return true; } - if (AE\isColEncrypted()) { + if (AE\isDataEncrypted()) { return false; } // now check ODBC version diff --git a/test/functional/sqlsrv/MsSetup.inc b/test/functional/sqlsrv/MsSetup.inc index 1ec7ceef4..aec2b4bb1 100644 --- a/test/functional/sqlsrv/MsSetup.inc +++ b/test/functional/sqlsrv/MsSetup.inc @@ -18,7 +18,9 @@ $tableIndex = "php_test_table_index"; $procName = "php_test_proc"; $fileName = "php_test_file.dat"; -$connectionOptions = array("Database"=>$database, "UID"=>$userName, "PWD"=>$userPassword, "TraceOn"=>false); +$driver = "ODBC Driver 17 for SQL Server"; + +$connectionOptions = array("Database" => $database, "UID" => $userName, "PWD" => $userPassword, "TraceOn" => false, "Driver" => $driver); $daasMode = false; $marsMode = true; diff --git a/test/functional/sqlsrv/TC52_StreamSend.phpt b/test/functional/sqlsrv/TC52_StreamSend.phpt index 648c23fdf..3779e4448 100644 --- a/test/functional/sqlsrv/TC52_StreamSend.phpt +++ b/test/functional/sqlsrv/TC52_StreamSend.phpt @@ -19,7 +19,7 @@ function sendStream($minType, $maxType, $atExec) startTest($testName); setup(); - $tableName = "TC52test"; + $tableName = "TC52test" . rand(0, 100); $fileName = "TC52test.dat"; $conn1 = AE\connect(); diff --git a/test/functional/sqlsrv/TC54_StreamPrepared.phpt b/test/functional/sqlsrv/TC54_StreamPrepared.phpt index 94a6bbe88..a22868f90 100644 --- a/test/functional/sqlsrv/TC54_StreamPrepared.phpt +++ b/test/functional/sqlsrv/TC54_StreamPrepared.phpt @@ -18,7 +18,7 @@ function sendStream($minType, $maxType) startTest($testName); setup(); - $tableName = "TC54test"; + $tableName = "TC54test" . rand(0, 100); $fileName = "TC53test.dat"; $conn1 = AE\connect(); diff --git a/test/functional/sqlsrv/TC84_LargeColumnName.phpt b/test/functional/sqlsrv/TC84_LargeColumnName.phpt index bebcfadc4..b7cc3d570 100644 --- a/test/functional/sqlsrv/TC84_LargeColumnName.phpt +++ b/test/functional/sqlsrv/TC84_LargeColumnName.phpt @@ -10,7 +10,7 @@ PHPT_EXEC=true 128); - $columnName .= "A"; - } - } catch (Exception $e) { - echo $e->getMessage(); - } + // The maximum size of a column name is 128 characters + $maxlen = 128; + $columnName = str_repeat('a', $maxlen); + largeColumnNameTest($columnName); + + // Now add another character to the name + $columnName .= "A"; + + largeColumnNameTest($columnName, true); endTest($testName); } diff --git a/test/functional/sqlsrv/TC84_LargeColumnName_unicode.phpt b/test/functional/sqlsrv/TC84_LargeColumnName_unicode.phpt index 48bdc11c9..7a0aca36f 100644 --- a/test/functional/sqlsrv/TC84_LargeColumnName_unicode.phpt +++ b/test/functional/sqlsrv/TC84_LargeColumnName_unicode.phpt @@ -10,35 +10,44 @@ PHPT_EXEC=true 'UTF-8' )); + $conn = connect(array('CharacterSet'=>'UTF-8')); $tableName = "LargeColumnNameTest"; dropTable($conn, $tableName); - sqlsrv_query($conn, "CREATE TABLE [$tableName] ([$columnName] int)"); - - sqlsrv_query($conn, "INSERT INTO [$tableName] ([$columnName]) VALUES (5)"); + $stmt = sqlsrv_query($conn, "CREATE TABLE [$tableName] ([$columnName] int)"); + if ($stmt == null) { + if (!$expectFail) { + fatalError("Possible regression: Unable to create test $tableName."); + } else { + $expected = 'is too long. Maximum length is 128.'; + if (strpos(sqlsrv_errors()[0]['message'], $expected) === false) { + print_r(sqlsrv_errors()); + } + echo "$"; + echo "stmt = null"; + echo "\n"; + } + } else { + sqlsrv_query($conn, "INSERT INTO [$tableName] ([$columnName]) VALUES (5)"); - $stmt = sqlsrv_query($conn, "SELECT * from [$tableName]"); + $stmt = sqlsrv_query($conn, "SELECT * from [$tableName]"); - if (null == $stmt) { - echo "$"; - echo "stmt = null"; - echo "\n"; - } else { if (null == sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { - if (!$expectfail) { + if (!$expectFail) { fatalError("Possible regression: Unable to retrieve inserted value."); } } sqlsrv_free_stmt($stmt); } + dropTable($conn, $tableName); + sqlsrv_close($conn); } @@ -53,16 +62,16 @@ function repro() startTest($testName); - $columnName = "银"; + // The maximum size of a column name is 128 characters + $maxlen = 128; + $columnName = str_repeat('银', $maxlen); - try { - for ($a = 1; $a <= 129; $a++) { - LargeColumnNameTest($columnName, $a > 128); - $columnName .= "银"; - } - } catch (Exception $e) { - echo $e->getMessage(); - } + largeColumnNameTest($columnName); + + // Now add another character to the name + $columnName .= "银"; + + largeColumnNameTest($columnName, true); endTest($testName); } diff --git a/test/functional/sqlsrv/TC84_LargeColumnName_unicode_col_name.phpt b/test/functional/sqlsrv/TC84_LargeColumnName_unicode_col_name.phpt deleted file mode 100644 index dc7a1eb2d..000000000 --- a/test/functional/sqlsrv/TC84_LargeColumnName_unicode_col_name.phpt +++ /dev/null @@ -1,75 +0,0 @@ ---TEST-- -PHP - Large Unicode Column Name Test ---DESCRIPTION-- -Verifies that long column names are supported (up to 128 chars). ---ENV-- -PHPT_EXEC=true ---SKIPIF-- - ---FILE-- -'UTF-8' )); - - $tableName = "LargeColumnNameTest"; - - dropTable($conn, $tableName); - - sqlsrv_query($conn, "CREATE TABLE [$tableName] ([$columnName] int)"); - - sqlsrv_query($conn, "INSERT INTO [$tableName] ([$columnName]) VALUES (5)"); - - $stmt = sqlsrv_query($conn, "SELECT * from [$tableName]"); - - if (null == $stmt) { - echo "$"; - echo "stmt = null"; - echo "\n"; - } else { - if (null == sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { - if (!$expectfail) { - fatalError("Possible regression: Unable to retrieve inserted value."); - } - } - sqlsrv_free_stmt($stmt); - } - - sqlsrv_close($conn); -} - - -//-------------------------------------------------------------------- -// repro -// -//-------------------------------------------------------------------- -function repro() -{ - $testName = "PHP - Large Unicode Column Name Test"; - - startTest($testName); - - $columnName = "银"; - - try { - for ($a = 1; $a <= 129; $a++) { - LargeColumnNameTest($columnName, $a > 128); - $columnName .= "银"; - } - } catch (Exception $e) { - echo $e->getMessage(); - } - - - endTest($testName); -} - -repro(); -?> ---EXPECT-- -$stmt = null -Test "PHP - Large Unicode Column Name Test" completed successfully. diff --git a/test/functional/sqlsrv/connection_resiliency.phpt b/test/functional/sqlsrv/connection_resiliency.phpt index 59ee6c277..2d47f6fe5 100644 --- a/test/functional/sqlsrv/connection_resiliency.phpt +++ b/test/functional/sqlsrv/connection_resiliency.phpt @@ -144,7 +144,12 @@ $stmt6 = sqlsrv_query( $conn, "SELECT * FROM $tableName2" ); if( $stmt6 === false ) { echo "Error in statement 6.\n"; - print_r( sqlsrv_errors() ); + $err = sqlsrv_errors(); + if (strpos($err[0][0], '08S01')===false or + (strpos($err[0][2], 'TCP Provider:')===false and strpos($err[0][2], 'SMux Provider:')===false and strpos($err[0][2], 'Session Provider:')===false)) { + echo "Error: Wrong error message.\n"; + print_r($err); + } } else { @@ -188,7 +193,12 @@ $stmt8 = sqlsrv_query( $conn, "SELECT * FROM $tableName2" ); if( $stmt8 === false ) { echo "Error in statement 8.\n"; - print_r( sqlsrv_errors() ); + $err = sqlsrv_errors(); + if (strpos($err[0][0], 'IMSSP')===false or + strpos($err[0][2], 'The connection cannot process this operation because there is a statement with pending results')===false) { + echo "Error: Wrong error message.\n"; + print_r($err); + } } else { @@ -199,7 +209,7 @@ sqlsrv_close( $conn ); sqlsrv_close( $conn_break ); ?> ---EXPECTREGEX-- +--EXPECT-- Statement 1 successful. 16 rows in result set. Statement 2 successful. @@ -211,53 +221,5 @@ Statement 4 successful. Statement 5 successful. rows in result set. Error in statement 6. -Array -\( - \[0\] => Array - \( - \[0\] => 08S01 - \[SQLSTATE\] => 08S01 - \[1\] => 10054 - \[code\] => 10054 - \[2\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]TCP Provider: An existing connection was forcibly closed by the remote host. - - \[message\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]TCP Provider: An existing connection was forcibly closed by the remote host. - - \) - - \[1\] => Array - \( - \[0\] => 08S01 - \[SQLSTATE\] => 08S01 - \[1\] => 10054 - \[code\] => 10054 - \[2\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]Communication link failure - \[message\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]Communication link failure - \) - -\) Statement 7 successful. Error in statement 8. -Array -\( - \[0\] => Array - \( - \[0\] => IMSSP - \[SQLSTATE\] => IMSSP - \[1\] => -44 - \[code\] => -44 - \[2\] => The connection cannot process this operation because there is a statement with pending results. To make the connection available for other queries, either fetch all results or cancel or free the statement. For more information, see the product documentation about the MultipleActiveResultSets connection option. - \[message\] => The connection cannot process this operation because there is a statement with pending results. To make the connection available for other queries, either fetch all results or cancel or free the statement. For more information, see the product documentation about the MultipleActiveResultSets connection option. - \) - - \[1\] => Array - \( - \[0\] => HY000 - \[SQLSTATE\] => HY000 - \[1\] => 0 - \[code\] => 0 - \[2\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]Connection is busy with results for another command - \[message\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]Connection is busy with results for another command - \) - -\) diff --git a/test/functional/sqlsrv/connection_resiliency_keywords.phpt b/test/functional/sqlsrv/connection_resiliency_keywords.phpt index 0211b47c1..7dd50fb57 100644 --- a/test/functional/sqlsrv/connection_resiliency_keywords.phpt +++ b/test/functional/sqlsrv/connection_resiliency_keywords.phpt @@ -3,8 +3,7 @@ Test the connection resiliency keywords --DESCRIPTION-- Test the connection resiliency keywords ConnectRetryCount and ConnectRetryInterval and their ranges of acceptable values --SKIPIF-- - + --FILE-- 08001 \[1\] => 0 \[code\] => 0 - \[2\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]Invalid value specified for connection string attribute 'ConnectRetryCount' - \[message\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]Invalid value specified for connection string attribute 'ConnectRetryCount' + \[2\] => (\[unixODBC\]|)\[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]Invalid value specified for connection string attribute 'ConnectRetryCount' + \[message\] => (\[unixODBC\]|)\[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]Invalid value specified for connection string attribute 'ConnectRetryCount' \) \) @@ -90,8 +89,8 @@ Array \[SQLSTATE\] => 08001 \[1\] => 0 \[code\] => 0 - \[2\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]Invalid value specified for connection string attribute 'ConnectRetryInterval' - \[message\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]Invalid value specified for connection string attribute 'ConnectRetryInterval' + \[2\] => (\[unixODBC\]|)\[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]Invalid value specified for connection string attribute 'ConnectRetryInterval' + \[message\] => (\[unixODBC\]|)\[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]Invalid value specified for connection string attribute 'ConnectRetryInterval' \) \) @@ -104,8 +103,8 @@ Array \[SQLSTATE\] => 08001 \[1\] => 0 \[code\] => 0 - \[2\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]Invalid value specified for connection string attribute 'ConnectRetryCount' - \[message\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]Invalid value specified for connection string attribute 'ConnectRetryCount' + \[2\] => (\[unixODBC\]|)\[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]Invalid value specified for connection string attribute 'ConnectRetryCount' + \[message\] => (\[unixODBC\]|)\[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]Invalid value specified for connection string attribute 'ConnectRetryCount' \) \) diff --git a/test/functional/sqlsrv/connection_resiliency_prepare_transact.phpt b/test/functional/sqlsrv/connection_resiliency_prepare_transact.phpt index 3d713c2ee..c42a4e447 100644 --- a/test/functional/sqlsrv/connection_resiliency_prepare_transact.phpt +++ b/test/functional/sqlsrv/connection_resiliency_prepare_transact.phpt @@ -167,42 +167,22 @@ else else { echo "Statement not valid and rollback failed.\n"; - print_r( sqlsrv_errors() ); + $err = sqlsrv_errors(); + if (strpos($err[0][0], '08S02')===false or + (strpos($err[0][2], 'TCP Provider:')===false and strpos($err[0][2], 'SMux Provider:')===false and strpos($err[0][2], 'Session Provider:')===false)) { + echo "Error: Wrong error message.\n"; + print_r($err); + } } } sqlsrv_close( $conn ); sqlsrv_close( $conn_break ); ?> ---EXPECTREGEX-- +--EXPECT-- Statement 1 prepared. Statement 1 executed. Transaction begun. Transaction was committed. Transaction begun. Statement not valid and rollback failed. -Array -\( - \[0\] => Array - \( - \[0\] => 08S02 - \[SQLSTATE\] => 08S02 - \[1\] => 10054 - \[code\] => 10054 - \[2\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]TCP Provider: An existing connection was forcibly closed by the remote host. - - \[message\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]TCP Provider: An existing connection was forcibly closed by the remote host. - - \) - - \[1\] => Array - \( - \[0\] => 08S02 - \[SQLSTATE\] => 08S02 - \[1\] => 10054 - \[code\] => 10054 - \[2\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]Unable to open a logical session - \[message\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]Unable to open a logical session - \) - -\) diff --git a/test/functional/sqlsrv/connection_resiliency_timeouts.phpt b/test/functional/sqlsrv/connection_resiliency_timeouts.phpt index 06a8d28f3..1abfdd309 100644 --- a/test/functional/sqlsrv/connection_resiliency_timeouts.phpt +++ b/test/functional/sqlsrv/connection_resiliency_timeouts.phpt @@ -33,7 +33,12 @@ $stmt1 = sqlsrv_query( $conn, "SELECT * FROM $tableName1" ); if( $stmt1 === false ) { echo "Error in statement 1.\n"; - print_r( sqlsrv_errors() ); + $err = sqlsrv_errors(); + if (strpos($err[0][0], '08S01')===false or + (strpos($err[0][2], 'TCP Provider:')===false and strpos($err[0][2], 'SMux Provider:')===false and strpos($err[0][2], 'Session Provider:')===false)) { + echo "Error: Wrong error message.\n"; + print_r($err); + } } else { @@ -78,29 +83,4 @@ DropTables( $server, $uid, $pwd, $tableName1, $tableName2 ) ?> --EXPECTREGEX-- Error in statement 1. -Array -\( - \[0\] => Array - \( - \[0\] => 08S01 - \[SQLSTATE\] => 08S01 - \[1\] => 10054 - \[code\] => 10054 - \[2\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]TCP Provider: An existing connection was forcibly closed by the remote host. - - \[message\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]TCP Provider: An existing connection was forcibly closed by the remote host. - - \) - - \[1\] => Array - \( - \[0\] => 08S01 - \[SQLSTATE\] => 08S01 - \[1\] => 10054 - \[code\] => 10054 - \[2\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]Communication link failure - \[message\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]Communication link failure - \) - -\) Statement 2 successful. diff --git a/test/functional/sqlsrv/skipif_not_akv.inc b/test/functional/sqlsrv/skipif_not_akv.inc new file mode 100644 index 000000000..9746db712 --- /dev/null +++ b/test/functional/sqlsrv/skipif_not_akv.inc @@ -0,0 +1,21 @@ + \ No newline at end of file diff --git a/test/functional/sqlsrv/skipif_protocol_not_tcp.inc b/test/functional/sqlsrv/skipif_protocol_not_tcp.inc index 4dc4921e7..26d960ca3 100644 --- a/test/functional/sqlsrv/skipif_protocol_not_tcp.inc +++ b/test/functional/sqlsrv/skipif_protocol_not_tcp.inc @@ -1,6 +1,4 @@ $userName, "PWD"=>$userPassword ); @@ -14,17 +18,30 @@ if ($conn === false) { die( "skip Could not connect during SKIPIF." ); } -// Get SQL Server version -$stmt = sqlsrv_query( $conn, "SELECT @@VERSION" ); -if (sqlsrv_fetch($stmt)) { - $ver_string = sqlsrv_get_field( $stmt, 0 ); -} else { - die("skip Could not fetch SQL Server version."); +$msodbcsql_ver = sqlsrv_client_info($conn)["DriverVer"]; +$msodbcsql_maj = explode(".", $msodbcsql_ver)[0]; +$msodbcsql_min = explode(".", $msodbcsql_ver)[1]; + +if (!$is_win) { + if ($msodbcsql_maj < 17 or $msodbcsql_min < 2) { + die("skip Unsupported ODBC driver version"); + } } -$version = explode(' ', $ver_string); +// Get SQL Server version +// Exclude this check if running on Azure +if (!$daasMode) { + $stmt = sqlsrv_query( $conn, "SELECT @@VERSION" ); + if (sqlsrv_fetch($stmt)) { + $ver_string = sqlsrv_get_field( $stmt, 0 ); + } else { + die("skip Could not fetch SQL Server version."); + } + + $version = explode(' ', $ver_string); -if ($version[3] < '2014') { - die("skip Wrong version of SQL Server, 2014 or later required"); + if ($version[3] < '2014') { + die("skip Wrong version of SQL Server, 2014 or later required"); + } } ?> diff --git a/test/functional/sqlsrv/skipif_version_less_than_2k16.inc b/test/functional/sqlsrv/skipif_version_less_than_2k16.inc index 692523d66..ce06258a2 100644 --- a/test/functional/sqlsrv/skipif_version_less_than_2k16.inc +++ b/test/functional/sqlsrv/skipif_version_less_than_2k16.inc @@ -1,10 +1,14 @@ $userName, "PWD"=>$userPassword ); @@ -14,17 +18,29 @@ if ($conn === false) { die( "skip Could not connect during SKIPIF." ); } -// Get SQL Server version -$stmt = sqlsrv_query( $conn, "SELECT @@VERSION" ); -if (sqlsrv_fetch($stmt)) { - $ver_string = sqlsrv_get_field( $stmt, 0 ); -} else { - die("skip Could not fetch SQL Server version."); +$msodbcsql_ver = sqlsrv_client_info($conn)["DriverVer"]; +$msodbcsql_maj = explode(".", $msodbcsql_ver)[0]; + +if (!$is_win) { + if ($msodbcsql_maj < 17) { + die("skip Unsupported ODBC driver version"); + } } -$version = explode(' ', $ver_string); +// Get SQL Server version +// Exclude this check if running on Azure +if (!$daasMode) { + $stmt = sqlsrv_query( $conn, "SELECT @@VERSION" ); + if (sqlsrv_fetch($stmt)) { + $ver_string = sqlsrv_get_field( $stmt, 0 ); + } else { + die("skip Could not fetch SQL Server version."); + } + + $version = explode(' ', $ver_string); -if ($version[3] < '2016') { - die("skip Wrong version of SQL Server, 2016 or later required"); + if ($version[3] < '2016') { + die("skip Wrong version of SQL Server, 2016 or later required"); + } } ?> diff --git a/test/functional/sqlsrv/sqlsrv_ConnPool_Unix.phpt b/test/functional/sqlsrv/sqlsrv_ConnPool_Unix.phpt index 57aafff60..bd00ac689 100644 --- a/test/functional/sqlsrv/sqlsrv_ConnPool_Unix.phpt +++ b/test/functional/sqlsrv/sqlsrv_ConnPool_Unix.phpt @@ -6,6 +6,15 @@ This test assumes the default odbcinst.ini has not been modified. --FILE-- + --FILE-- + --FILE-- + --FILE-- --FILE-- s; - - if ($diff == 0) { - $value = $valueAE; - } + + $dataArray = sqlsrv_fetch_array($stmt2, SQLSRV_FETCH_NUMERIC); + for ($i = 0; $i < sizeof($SQLSRV_PHPTYPE_CONST); ++$i) { + if (!sqlsrv_execute($stmt)) { + fatalError("Execute failed for $SQLSRV_PHPTYPE_CONST[$i]\n"); + } + + if ($result = sqlsrv_fetch($stmt)) { + for ($j = 0; $j < $numFields; $j++) { + $value = sqlsrv_get_field($stmt, $j, $SQLSRV_PHPTYPE_CONST[$i]); + $valueFromArray = $dataArray[$j]; + + // PHPTYPE_STREAM returns a PHP resource, so check the type + if (is_resource($value)) { + $value = get_resource_type($value); } - - if ($valueAE != $value or $valueFromArrayAE != $valueFromArray) { - echo "Values do not match! PHPType $i Field $j\n"; - print_r($valueAE);echo "\n"; - print_r($value);echo "\n"; - print_r($valueFromArrayAE);echo "\n"; - print_r($valueFromArray);echo "\n"; - print_r(sqlsrv_errors()); - fatalError("Test failed, values do not match.\n"); + + // For each type, the AE values come first and non-AE values second + // So let's do the comparison every second field + if ($j%2 == 0) { + $valueAE = $value; + $valueFromArrayAE = $valueFromArray; + } elseif ($j%2 == 1) { + // If returning a DateTime PHP type from a date only SQL type, + // PHP adds the current timestamp to make a DateTime object, + // and in this case the AE and non-AE times may be off by a + // fraction of a second since they are retrieved at ever-so-slightly + // different times. This not a test-failing discrepancy, so + // below the DateTime objects are made equal again for the next if + // block. + if ($value instanceof DateTime) { + // date_diff returns a DateInterval object, and s is + // the difference in seconds. s should be zero because + // the difference should be just a fraction of a second. + $datediff = date_diff($value, $valueAE); + $diff = $datediff->s; + + if ($diff == 0) { + $value = $valueAE; + } + } + + if ($valueAE != $value or $valueFromArrayAE != $valueFromArray) { + $index = floor($j / 2); + echo "Values do not match! PHPType $i Field $dataTypes[$index]\n"; + print_r($valueAE); + echo "\n--------\n\n"; + print_r($value); + echo "\n--------\n\n"; + print_r($valueFromArrayAE); + echo "\n--------\n\n"; + print_r($valueFromArray); + echo "\n--------\n\n"; + print_r(sqlsrv_errors()); + echo("Test failed, values do not match.\n"); + } } } } - ++$i; } - + sqlsrv_free_stmt($stmt); sqlsrv_free_stmt($stmt2); - - $deleteQuery = "DELETE FROM $tableName"; + + $deleteQuery = "TRUNCATE TABLE $tableName"; $stmt = sqlsrv_query($conn, $deleteQuery); if ($stmt == false) { print_r(sqlsrv_errors()); - fatalError("Delete statement failed"); + fatalError("Truncate statement failed"); } - + sqlsrv_free_stmt($stmt); } diff --git a/test/functional/sqlsrv/sqlsrv_connect_encrypted.phpt b/test/functional/sqlsrv/sqlsrv_connect_encrypted.phpt index 5a39140e1..e6a5bbb6d 100644 --- a/test/functional/sqlsrv/sqlsrv_connect_encrypted.phpt +++ b/test/functional/sqlsrv/sqlsrv_connect_encrypted.phpt @@ -1,7 +1,7 @@ --TEST-- Test new connection keyword ColumnEncryption --SKIPIF-- - + --FILE-- --FILE-- @@ -13,23 +17,34 @@ $conn = connect(); if (AE\IsQualified($conn)) { $query = "SELECT name FROM sys.column_master_keys"; $stmt = sqlsrv_query($conn, $query); - sqlsrv_fetch($stmt); - $master_key_name = sqlsrv_get_field($stmt, 0); + $found = false; + while (sqlsrv_fetch($stmt)) { + $master_key_name = sqlsrv_get_field($stmt, 0); + if ($master_key_name == 'AEMasterKey') { + $found = true; + } + } + // $master_key_name = sqlsrv_get_field($stmt, 0); + if (!$found) { + die("Windows Column Master Key not created.\n"); + } $query = "SELECT name FROM sys.column_encryption_keys"; $stmt = sqlsrv_query($conn, $query); - sqlsrv_fetch($stmt); - $encryption_key_name = sqlsrv_get_field($stmt, 0); - - if ($master_key_name == 'AEMasterKey' && $encryption_key_name == 'AEColumnKey') { - echo "Test Successfully done.\n"; - } else { - echo "Column Master Key and Column Encryption Key not created.\n"; + $found = false; + while (sqlsrv_fetch($stmt)) { + $encryption_key_name = sqlsrv_get_field($stmt, 0); + if ($encryption_key_name == 'AEColumnKey') { + $found = true; + } + } + if (!$found) { + die("Windows Column Encryption Key not created.\n"); } sqlsrv_free_stmt($stmt); -} else { - echo "Test Successfully done.\n"; } + +echo "Test Successfully done.\n"; sqlsrv_close($conn); ?> --EXPECT-- From 4e77b64171521e00231e098a7565c59b5e03a350 Mon Sep 17 00:00:00 2001 From: Jenny Tam Date: Tue, 16 Oct 2018 10:37:01 -0700 Subject: [PATCH 2/6] Modified how to send stream data using SQLPutData and SQLParamData --- source/shared/core_sqlsrv.h | 3 ++- source/shared/core_stmt.cpp | 23 +++++++++++------- .../pdo_sqlsrv/MsData_PDO_AllTypes.inc | 2 +- .../pdo_sqlsrv/pdostatement_GetDataType.phpt | Bin 5677 -> 5692 bytes .../pdo_sqlsrv/pdostatement_fetchAll.phpt | Bin 17989 -> 18019 bytes .../pdo_sqlsrv/pdostatement_fetchObject.phpt | Bin 3978 -> 3993 bytes .../pdo_sqlsrv/pdostatement_nextRowset.phpt | Bin 10727 -> 10757 bytes test/functional/sqlsrv/test_largeData.phpt | 6 +++++ 8 files changed, 23 insertions(+), 11 deletions(-) diff --git a/source/shared/core_sqlsrv.h b/source/shared/core_sqlsrv.h index 35e49cbe3..59b5afcd3 100644 --- a/source/shared/core_sqlsrv.h +++ b/source/shared/core_sqlsrv.h @@ -1939,9 +1939,10 @@ namespace core { inline void check_for_mars_error( _Inout_ sqlsrv_stmt* stmt, _In_ SQLRETURN r TSRMLS_DC ) { + // Skip this if not SQL_ERROR - // We check for the 'connection busy' error caused by having MultipleActiveResultSets off // and return a more helpful message prepended to the ODBC errors if that error occurs - if( !SQL_SUCCEEDED( r )) { + if (r == SQL_ERROR) { SQLCHAR err_msg[SQL_MAX_MESSAGE_LENGTH + 1] = {'\0'}; SQLSMALLINT len = 0; diff --git a/source/shared/core_stmt.cpp b/source/shared/core_stmt.cpp index ae86d4884..58ec45208 100644 --- a/source/shared/core_stmt.cpp +++ b/source/shared/core_stmt.cpp @@ -1298,15 +1298,15 @@ bool core_sqlsrv_send_stream_packet( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) php_stream* param_stream = NULL; core::sqlsrv_php_stream_from_zval_no_verify( *stmt, param_stream, stmt->current_stream.stream_z TSRMLS_CC ); - // if we're at the end, then release our current parameter - if( php_stream_eof( param_stream )) { - // if no data was actually sent prior, then send a NULL - if( stmt->current_stream_read == 0 ) { - // send an empty string, which is what a 0 length does. - char buff[1]; // temp storage to hand to SQLPutData - core::SQLPutData( stmt, buff, 0 TSRMLS_CC ); + // if we're at the end, then reset both current_stream and current_stream_read + if (php_stream_eof(param_stream)) { + // yet return to the very beginning of param_stream since SQLParamData() may ask for the same data again + int ret = php_stream_seek(param_stream, 0, SEEK_SET); + if (ret != 0) { + LOG(SEV_ERROR, "PHP stream: stream seek failed."); + throw core::CoreException(); } - stmt->current_stream = sqlsrv_stream( NULL, SQLSRV_ENCODING_CHAR ); + stmt->current_stream = sqlsrv_stream(NULL, SQLSRV_ENCODING_CHAR); stmt->current_stream_read = 0; } // read the data from the stream, send it via SQLPutData and track how much we've sent. @@ -1322,7 +1322,12 @@ bool core_sqlsrv_send_stream_packet( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) } stmt->current_stream_read += static_cast( read ); - if( read > 0 ) { + if (read == 0) { + // send an empty string, which is what a 0 length does. + char buff[1]; // temp storage to hand to SQLPutData + core::SQLPutData(stmt, buff, 0 TSRMLS_CC); + } + else if (read > 0) { // if this is a UTF-8 stream, then we will use the UTF-8 encoding to determine if we're in the middle of a character // then read in the appropriate number more bytes and then retest the string. This way we try at most to convert it // twice. diff --git a/test/functional/pdo_sqlsrv/MsData_PDO_AllTypes.inc b/test/functional/pdo_sqlsrv/MsData_PDO_AllTypes.inc index 14f89a1a3..2fe6d98ab 100644 --- a/test/functional/pdo_sqlsrv/MsData_PDO_AllTypes.inc +++ b/test/functional/pdo_sqlsrv/MsData_PDO_AllTypes.inc @@ -12,7 +12,7 @@ $int_col = array(1, 2); $bin = fopen('php://memory', 'a'); -fwrite($bin, '00'); +fwrite($bin, hex2bin('6162636465')); // 'abcde' rewind($bin); $binary_col = array($bin, $bin); diff --git a/test/functional/pdo_sqlsrv/pdostatement_GetDataType.phpt b/test/functional/pdo_sqlsrv/pdostatement_GetDataType.phpt index 99c9b6c5dc9850dcfa24e9e9a65410ba1ee69fb8..bdd87ffe06ab3d07ebd19f8aba3d6bfc6f9d8503 100644 GIT binary patch delta 61 vcmZ3hvqxvcPcBYVO$DXIq~w&;$$zEme12chnY1oDLEx|@W#uh4dyCBx1^_>EEg1j+ delta 112 zcmZn-c^hndyDfPsNw@total_read = $offset; + return true; + } + return false; } } From 12be3564cd84885e322d896b349f9985d0a847ab Mon Sep 17 00:00:00 2001 From: Jenny Tam Date: Tue, 16 Oct 2018 13:31:06 -0700 Subject: [PATCH 3/6] Added a new pdo test for binary fields with empty strings --- .../pdostatement_bindParam_empty_binary.phpt | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 test/functional/pdo_sqlsrv/pdostatement_bindParam_empty_binary.phpt diff --git a/test/functional/pdo_sqlsrv/pdostatement_bindParam_empty_binary.phpt b/test/functional/pdo_sqlsrv/pdostatement_bindParam_empty_binary.phpt new file mode 100644 index 000000000..1b2ed5582 --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdostatement_bindParam_empty_binary.phpt @@ -0,0 +1,93 @@ +--TEST-- +PDOStatement::BindParam for binary types with empty strings and non-empty ones +--DESCRIPTION-- +PDOStatement::BindParam for binary types with empty strings and non-empty ones +Related to GitHub PR 865 - verify that the same binary data can be reused rather +than flushed after the first use +--SKIPIF-- + +--FILE-- +prepare($query); + $stmt->bindParam(1, $bin, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_BINARY); + $stmt->bindParam(2, $bin, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_BINARY); + $stmt->bindParam(3, $bin, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_BINARY); + + $stmt->execute(); + fclose($bin); + + $bin2 = fopen('php://memory', 'a'); + fwrite($bin2, hex2bin($data[1])); // 'ABC' + rewind($bin2); + + $stmt->bindParam(1, $bin2, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_BINARY); + $stmt->bindParam(2, $bin2, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_BINARY); + $stmt->bindParam(3, $bin2, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_BINARY); + + $stmt->execute(); + fclose($bin2); + + // Verify the data by fetching and comparing against the inputs + $query = "SELECT * FROM $tableName"; + $stmt = $conn->query($query); + $rowset = $stmt->fetchAll(); + + for ($i = 0; $i < 2; $i++) { + for ($j = 0; $j < 3; $j++) { + $str = $rowset[$i][$j]; + $len = strlen($str); + $failed = false; + + if ($j == 0) { + // binary fields have fixed size, unlike varbinary ones + if ($len !== $size || trim($str) !== $inputs[$i]) { + $failed = true; + } + } else { + if ($len !== 0 && $str !== $inputs[$i]) { + $failed = true; + } + } + + if ($failed) { + $row = $i + 1; + $col = $j + 1; + echo "Unexpected value returned from row $row and column $col: \n"; + var_dump($str); + } + } + } + + dropTable($conn, $tableName); + unset($stmt); + unset($conn); + + echo "Done\n"; +} catch (PDOException $e) { + var_dump($e); + exit; +} +?> +--EXPECT-- +Done From bd980569be6813fb1172add5064ed6bd561d618e Mon Sep 17 00:00:00 2001 From: Jenny Tam Date: Tue, 16 Oct 2018 14:38:26 -0700 Subject: [PATCH 4/6] Attempted to fix coveralls --- Dockerfile-msphpsql | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Dockerfile-msphpsql b/Dockerfile-msphpsql index 43435eb3f..81cc1fda0 100644 --- a/Dockerfile-msphpsql +++ b/Dockerfile-msphpsql @@ -45,7 +45,10 @@ RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && ACCEPT_EULA=Y apt ENV PATH="/opt/mssql-tools/bin:${PATH}" #install coveralls -RUN python -m pip install --upgrade pip && pip install cpp-coveralls +#RUN python -m pip install --upgrade pip && pip install cpp-coveralls +RUN python -m pip install --upgrade pip +RUN python -m pip install --upgrade requests +RUN python -m pip install cpp-coveralls #Either Install git / download zip (One can see other strategies : https://ryanfb.github.io/etc/2015/07/29/git_strategies_for_docker.html ) #One option is to get source from zip file of repository. From ee92c6843b372bf3d6e239c972d80e0ec3c0d504 Mon Sep 17 00:00:00 2001 From: Jenny Tam Date: Tue, 16 Oct 2018 15:54:21 -0700 Subject: [PATCH 5/6] Fixed the bug in the new test --- Dockerfile-msphpsql | 3 +-- .../pdo_sqlsrv/pdostatement_bindParam_empty_binary.phpt | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Dockerfile-msphpsql b/Dockerfile-msphpsql index 81cc1fda0..ab289479f 100644 --- a/Dockerfile-msphpsql +++ b/Dockerfile-msphpsql @@ -44,8 +44,7 @@ RUN curl https://packages.microsoft.com/config/ubuntu/16.04/prod.list > /etc/apt RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && ACCEPT_EULA=Y apt-get install -y msodbcsql17 mssql-tools ENV PATH="/opt/mssql-tools/bin:${PATH}" -#install coveralls -#RUN python -m pip install --upgrade pip && pip install cpp-coveralls +#install coveralls (upgrade both pip and requests first) RUN python -m pip install --upgrade pip RUN python -m pip install --upgrade requests RUN python -m pip install cpp-coveralls diff --git a/test/functional/pdo_sqlsrv/pdostatement_bindParam_empty_binary.phpt b/test/functional/pdo_sqlsrv/pdostatement_bindParam_empty_binary.phpt index 1b2ed5582..f063f567b 100644 --- a/test/functional/pdo_sqlsrv/pdostatement_bindParam_empty_binary.phpt +++ b/test/functional/pdo_sqlsrv/pdostatement_bindParam_empty_binary.phpt @@ -65,7 +65,7 @@ try { $failed = true; } } else { - if ($len !== 0 && $str !== $inputs[$i]) { + if ($len !== strlen($inputs[$i]) || $str !== $inputs[$i]) { $failed = true; } } From 0acd1d9fb8051dea7eca64bfc95860e784a4b5dd Mon Sep 17 00:00:00 2001 From: Jenny Tam Date: Wed, 17 Oct 2018 09:31:24 -0700 Subject: [PATCH 6/6] Added an equivalent test to sqlsrv --- .../pdostatement_bindParam_empty_binary.phpt | 5 +- .../sqlsrv/sqlsrv_param_empty_binary.phpt | 105 ++++++++++++++++++ 2 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 test/functional/sqlsrv/sqlsrv_param_empty_binary.phpt diff --git a/test/functional/pdo_sqlsrv/pdostatement_bindParam_empty_binary.phpt b/test/functional/pdo_sqlsrv/pdostatement_bindParam_empty_binary.phpt index f063f567b..e3db103fd 100644 --- a/test/functional/pdo_sqlsrv/pdostatement_bindParam_empty_binary.phpt +++ b/test/functional/pdo_sqlsrv/pdostatement_bindParam_empty_binary.phpt @@ -22,10 +22,9 @@ try { // Insert two rows, first empty strings and the second not empty $inputs = array('', 'ABC'); - $data = array(bin2hex($inputs[0]), bin2hex($inputs[1])); $bin = fopen('php://memory', 'a'); - fwrite($bin, hex2bin($data[0])); // an empty string + fwrite($bin, $inputs[0]); // an empty string will be 0x in hex rewind($bin); $query = "INSERT INTO $tableName VALUES(?, ?, ?)"; @@ -38,7 +37,7 @@ try { fclose($bin); $bin2 = fopen('php://memory', 'a'); - fwrite($bin2, hex2bin($data[1])); // 'ABC' + fwrite($bin2, $inputs[1]); // 'ABC' will be 0x414243 in hex rewind($bin2); $stmt->bindParam(1, $bin2, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_BINARY); diff --git a/test/functional/sqlsrv/sqlsrv_param_empty_binary.phpt b/test/functional/sqlsrv/sqlsrv_param_empty_binary.phpt new file mode 100644 index 000000000..8ddff7fba --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_param_empty_binary.phpt @@ -0,0 +1,105 @@ +--TEST-- +Test for inserting empty strings and non-empty ones into binary types +--DESCRIPTION-- +Test for inserting empty strings and non-empty ones into binary types +Related to GitHub PR 865 - verify that the same binary data can be reused rather +than flushed after the first use +--SKIPIF-- + +--FILE-- + $inputs[0], "VarBinaryCol" => $inputs[1], "VarBinaryMaxCol" => $inputs[2]), $r, AE\INSERT_PREPARE_PARAMS); + + +$inputs = array(new AE\BindParamOption($inputValues[1], + null, + "SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY)", + "SQLSRV_SQLTYPE_BINARY($size)"), + new AE\BindParamOption($inputValues[1], + null, + "SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY)", + "SQLSRV_SQLTYPE_VARBINARY($size)"), + new AE\BindParamOption($inputValues[1], + null, + "SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY)", + "SQLSRV_SQLTYPE_VARBINARY('max')")); +$r; +$stmt = AE\insertRow($conn, $tableName, array("BinaryCol" => $inputs[0], "VarBinaryCol" => $inputs[1], "VarBinaryMaxCol" => $inputs[2]), $r, AE\INSERT_PREPARE_PARAMS); + +// Verify the data by fetching and comparing against the inputs +$query = "SELECT * FROM $tableName"; +$stmt = sqlsrv_query($conn, $query); +if (!$stmt) { + fatalError("Failed to retrieve data from $tableName"); +} + +for ($i = 0; $i < 2; $i++) { + $rowNum = $i + 1; + $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_NUMERIC); + if (!$row) { + fatalError("Failed in sqlsrv_fetch_array for row $rowNum"); + } + + for ($j = 0; $j < 3; $j++) { + $str = $row[$j]; + $len = strlen($str); + $failed = false; + + if ($j == 0) { + // binary fields have fixed size, unlike varbinary ones + if ($len !== $size || trim($str) !== $inputValues[$i]) { + $failed = true; + } + } else { + $inputLen = strlen($inputValues[$i]); + if ($len !== $inputLen || $str !== $inputValues[$i]) { + $failed = true; + } + } + + if ($failed) { + $colNum = $j + 1; + echo "Unexpected value returned from row $rowNum and column $colNum: \n"; + var_dump($str); + } + } +} + +dropTable($conn, $tableName); + +sqlsrv_free_stmt($stmt); +sqlsrv_close($conn); + +echo "Done\n"; + +?> +--EXPECT-- +Done