diff --git a/CHANGELOG.md b/CHANGELOG.md index b96bb0cd..839f0b80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,35 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) +## Windows/Linux/macOS 5.2.0-RC - 2017-12-20 +Updated PECL release packages. Here is the list of updates: + +### Added +- Added support for Ubuntu 17 (requires [MSODBC 17 preview](https://github.com/Microsoft/msphpsql/tree/dev/ODBC%2017%20binaries%20preview)) +- Added support for Debian 9 (requires [MSODBC 17 preview](https://github.com/Microsoft/msphpsql/tree/dev/ODBC%2017%20binaries%20preview)) + +### Fixed +- Issue [#555](https://github.com/Microsoft/msphpsql/issues/555) - Hebrew strings truncation (requires [MSODBC 17 preview](https://github.com/Microsoft/msphpsql/tree/dev/ODBC%2017%20binaries%20preview)) +- Issue [#615](https://github.com/Microsoft/msphpsql/issues/615) - Added error handling when fetching varchar(max) as a stream with Always Encrypted +- Adjusted precisions for numeric/decimal inputs with Always Encrypted +- Fixed bugs when binding parameters with Always Encrypted +- Fixed warnings as per Prefast code analysis + +### Limitations +- In Linux and macOS, setlocale() only takes effect if it is invoked before the first connection. The subsequent locale setting will not work +- Always Encrypted functionalities are only supported using [MSODBC 17 preview](https://github.com/Microsoft/msphpsql/tree/dev/ODBC%2017%20binaries%20preview) + - ODBC binaries for macOS available upon request +- MSODBC 17 preview msodbcsql.msi only works in Windows10 +- [Always Encrypted limitations](https://github.com/Microsoft/msphpsql/wiki/Features#aelimitation) +- When using sqlsrv_query with Always Encrypted feature, SQL type has to be specified for each input (see [here](https://github.com/Microsoft/msphpsql/wiki/Features#aebindparam)) +- No support for inout / output params when using sql_variant type + +### Known Issues +- Connection pooling on Linux doesn't work properly when using the MSODBC17 preview +- When pooling is enabled in Linux or macOS + - unixODBC <= 2.3.4 (Linux and macOS) might not return proper diagnostics 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/Connection-Pooling-on-Linux-and-Mac) + ## Windows/Linux/macOS 5.1.2-preview - 2017-11-21 Updated PECL release packages. Here is the list of updates: diff --git a/Dockerfile-msphpsql b/Dockerfile-msphpsql index 2b13ab6d..18051c16 100644 --- a/Dockerfile-msphpsql +++ b/Dockerfile-msphpsql @@ -48,8 +48,8 @@ COPY . $PHPSQLDIR #install ODBC 17 preview driver WORKDIR $PHPSQLDIR -RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && ACCEPT_EULA=Y dpkg -i "./ODBC 17 binaries preview/Ubuntu 16/msodbcsql_17.0.0.1-1_amd64.deb" -RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && ACCEPT_EULA=Y dpkg -i "./ODBC 17 binaries preview/Ubuntu 16/mssql-tools_17.0.0.1-1_amd64.deb" +RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && ACCEPT_EULA=Y dpkg -i "./ODBC 17 binaries preview/Ubuntu 16/msodbcsql_17.0.0.5-1_amd64.deb" +RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && ACCEPT_EULA=Y dpkg -i "./ODBC 17 binaries preview/Ubuntu 16/mssql-tools_17.0.0.5-1_amd64.deb" ENV PATH="/opt/mssql-tools/bin:${PATH}" WORKDIR $PHPSQLDIR/source/ diff --git a/ODBC 17 binaries preview/Debian 8/msodbcsql_17.0.0.1-1_amd64.deb b/ODBC 17 binaries preview/Debian 8/msodbcsql_17.0.0.1-1_amd64.deb deleted file mode 100644 index 1032b040..00000000 Binary files a/ODBC 17 binaries preview/Debian 8/msodbcsql_17.0.0.1-1_amd64.deb and /dev/null differ diff --git a/ODBC 17 binaries preview/Debian 8/msodbcsql_17.0.0.5-1_amd64.deb b/ODBC 17 binaries preview/Debian 8/msodbcsql_17.0.0.5-1_amd64.deb new file mode 100644 index 00000000..673fe035 Binary files /dev/null and b/ODBC 17 binaries preview/Debian 8/msodbcsql_17.0.0.5-1_amd64.deb differ diff --git a/ODBC 17 binaries preview/Debian 8/mssql-tools_17.0.0.1-1_amd64.deb b/ODBC 17 binaries preview/Debian 8/mssql-tools_17.0.0.1-1_amd64.deb deleted file mode 100644 index ea2ea5ef..00000000 Binary files a/ODBC 17 binaries preview/Debian 8/mssql-tools_17.0.0.1-1_amd64.deb and /dev/null differ diff --git a/ODBC 17 binaries preview/Debian 8/mssql-tools_17.0.0.5-1_amd64.deb b/ODBC 17 binaries preview/Debian 8/mssql-tools_17.0.0.5-1_amd64.deb new file mode 100644 index 00000000..fc818465 Binary files /dev/null and b/ODBC 17 binaries preview/Debian 8/mssql-tools_17.0.0.5-1_amd64.deb differ diff --git a/ODBC 17 binaries preview/Debian 9/msodbcsql_17.0.0.5-1_amd64.deb b/ODBC 17 binaries preview/Debian 9/msodbcsql_17.0.0.5-1_amd64.deb new file mode 100644 index 00000000..d9cc02a8 Binary files /dev/null and b/ODBC 17 binaries preview/Debian 9/msodbcsql_17.0.0.5-1_amd64.deb differ diff --git a/ODBC 17 binaries preview/Debian 9/mssql-tools_17.0.0.5-1_amd64.deb b/ODBC 17 binaries preview/Debian 9/mssql-tools_17.0.0.5-1_amd64.deb new file mode 100644 index 00000000..58e697f1 Binary files /dev/null and b/ODBC 17 binaries preview/Debian 9/mssql-tools_17.0.0.5-1_amd64.deb differ diff --git a/ODBC 17 binaries preview/Red Hat 7/msodbcsql-17.0.0.1-1.x86_64.rpm b/ODBC 17 binaries preview/Red Hat 7/msodbcsql-17.0.0.1-1.x86_64.rpm deleted file mode 100644 index 5eef69a5..00000000 Binary files a/ODBC 17 binaries preview/Red Hat 7/msodbcsql-17.0.0.1-1.x86_64.rpm and /dev/null differ diff --git a/ODBC 17 binaries preview/Red Hat 7/msodbcsql-17.0.0.5-1.x86_64.rpm b/ODBC 17 binaries preview/Red Hat 7/msodbcsql-17.0.0.5-1.x86_64.rpm new file mode 100644 index 00000000..305a16a6 Binary files /dev/null and b/ODBC 17 binaries preview/Red Hat 7/msodbcsql-17.0.0.5-1.x86_64.rpm differ diff --git a/ODBC 17 binaries preview/Red Hat 7/mssql-tools-17.0.0.1-1.x86_64.rpm b/ODBC 17 binaries preview/Red Hat 7/mssql-tools-17.0.0.1-1.x86_64.rpm deleted file mode 100644 index e234bf02..00000000 Binary files a/ODBC 17 binaries preview/Red Hat 7/mssql-tools-17.0.0.1-1.x86_64.rpm and /dev/null differ diff --git a/ODBC 17 binaries preview/Red Hat 7/mssql-tools-17.0.0.5-1.x86_64.rpm b/ODBC 17 binaries preview/Red Hat 7/mssql-tools-17.0.0.5-1.x86_64.rpm new file mode 100644 index 00000000..effad031 Binary files /dev/null and b/ODBC 17 binaries preview/Red Hat 7/mssql-tools-17.0.0.5-1.x86_64.rpm differ diff --git a/ODBC 17 binaries preview/SUSE 12/msodbcsql-17.0.0.1-1.x86_64.rpm b/ODBC 17 binaries preview/SUSE 12/msodbcsql-17.0.0.1-1.x86_64.rpm deleted file mode 100644 index 46e68023..00000000 Binary files a/ODBC 17 binaries preview/SUSE 12/msodbcsql-17.0.0.1-1.x86_64.rpm and /dev/null differ diff --git a/ODBC 17 binaries preview/SUSE 12/msodbcsql-17.0.0.5-1.x86_64.rpm b/ODBC 17 binaries preview/SUSE 12/msodbcsql-17.0.0.5-1.x86_64.rpm new file mode 100644 index 00000000..83ea4e58 Binary files /dev/null and b/ODBC 17 binaries preview/SUSE 12/msodbcsql-17.0.0.5-1.x86_64.rpm differ diff --git a/ODBC 17 binaries preview/SUSE 12/mssql-tools-17.0.0.1-1.x86_64.rpm b/ODBC 17 binaries preview/SUSE 12/mssql-tools-17.0.0.1-1.x86_64.rpm deleted file mode 100644 index dbfb96fb..00000000 Binary files a/ODBC 17 binaries preview/SUSE 12/mssql-tools-17.0.0.1-1.x86_64.rpm and /dev/null differ diff --git a/ODBC 17 binaries preview/SUSE 12/mssql-tools-17.0.0.5-1.x86_64.rpm b/ODBC 17 binaries preview/SUSE 12/mssql-tools-17.0.0.5-1.x86_64.rpm new file mode 100644 index 00000000..4dd1a1b2 Binary files /dev/null and b/ODBC 17 binaries preview/SUSE 12/mssql-tools-17.0.0.5-1.x86_64.rpm differ diff --git a/ODBC 17 binaries preview/Ubuntu 16/msodbcsql_17.0.0.1-1_amd64.deb b/ODBC 17 binaries preview/Ubuntu 16/msodbcsql_17.0.0.1-1_amd64.deb deleted file mode 100644 index 01c28622..00000000 Binary files a/ODBC 17 binaries preview/Ubuntu 16/msodbcsql_17.0.0.1-1_amd64.deb and /dev/null differ diff --git a/ODBC 17 binaries preview/Ubuntu 16/msodbcsql_17.0.0.5-1_amd64.deb b/ODBC 17 binaries preview/Ubuntu 16/msodbcsql_17.0.0.5-1_amd64.deb new file mode 100644 index 00000000..f3ed15f8 Binary files /dev/null and b/ODBC 17 binaries preview/Ubuntu 16/msodbcsql_17.0.0.5-1_amd64.deb differ diff --git a/ODBC 17 binaries preview/Ubuntu 16/mssql-tools_17.0.0.1-1_amd64.deb b/ODBC 17 binaries preview/Ubuntu 16/mssql-tools_17.0.0.1-1_amd64.deb deleted file mode 100644 index 3e4bdf36..00000000 Binary files a/ODBC 17 binaries preview/Ubuntu 16/mssql-tools_17.0.0.1-1_amd64.deb and /dev/null differ diff --git a/ODBC 17 binaries preview/Ubuntu 16/mssql-tools_17.0.0.5-1_amd64.deb b/ODBC 17 binaries preview/Ubuntu 16/mssql-tools_17.0.0.5-1_amd64.deb new file mode 100644 index 00000000..f1141cee Binary files /dev/null and b/ODBC 17 binaries preview/Ubuntu 16/mssql-tools_17.0.0.5-1_amd64.deb differ diff --git a/ODBC 17 binaries preview/Ubuntu 17/msodbcsql_17.0.0.5-1_amd64.deb b/ODBC 17 binaries preview/Ubuntu 17/msodbcsql_17.0.0.5-1_amd64.deb new file mode 100644 index 00000000..510ceb09 Binary files /dev/null and b/ODBC 17 binaries preview/Ubuntu 17/msodbcsql_17.0.0.5-1_amd64.deb differ diff --git a/ODBC 17 binaries preview/Ubuntu 17/mssql-tools_17.0.0.5-1_amd64.deb b/ODBC 17 binaries preview/Ubuntu 17/mssql-tools_17.0.0.5-1_amd64.deb new file mode 100644 index 00000000..5e161efc Binary files /dev/null and b/ODBC 17 binaries preview/Ubuntu 17/mssql-tools_17.0.0.5-1_amd64.deb differ diff --git a/ODBC 17 binaries preview/Windows/x64/msodbcsql.msi b/ODBC 17 binaries preview/Windows/x64/msodbcsql.msi index 8fdaed54..8a2dfcca 100644 Binary files a/ODBC 17 binaries preview/Windows/x64/msodbcsql.msi and b/ODBC 17 binaries preview/Windows/x64/msodbcsql.msi differ diff --git a/ODBC 17 binaries preview/Windows/x86/msodbcsql.msi b/ODBC 17 binaries preview/Windows/x86/msodbcsql.msi index 126179ae..8356cb36 100644 Binary files a/ODBC 17 binaries preview/Windows/x86/msodbcsql.msi and b/ODBC 17 binaries preview/Windows/x86/msodbcsql.msi differ diff --git a/README.md b/README.md index 42e09545..b2ac70f6 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ You must first be able to build PHP 7.0.* or above without including these exten #### Compile the drivers -The Microsoft Drivers for PHP for SQL Server have been compiled and tested with PHP 7.0.* and 7.1.* using Visual C++ 2015 as well as PHP 7.2.0RC* using Visual C++ 2017 v15.0. +The Microsoft Drivers for PHP for SQL Server have been compiled and tested with PHP 7.0.* and 7.1.* using Visual C++ 2015 as well as PHP 7.2.0* using Visual C++ 2017 v15.0. For details, please read the documentation and/or take a look at the sample [build scripts](https://github.com/Microsoft/msphpsql/tree/dev/buildscripts#windows). ## Install (Windows) @@ -62,7 +62,7 @@ For details, please read the documentation and/or take a look at the sample [bui #### Prerequisites - A Web server such as Internet Information Services (IIS) is required. Your Web server must be configured to run PHP -- [Microsoft ODBC Driver 11][odbc11] or [Microsoft ODBC Driver 13][odbc13] +- [Microsoft ODBC Driver 11][odbc11], [Microsoft ODBC Driver 13][odbc13] or [Microsoft ODBC Driver 17][odbc17] #### Enable the drivers @@ -73,20 +73,15 @@ For details, please read the documentation and/or take a look at the sample [bui 3. Restart the Web server. ## Install (UNIX) -The following instructions assume a clean environment and show how to install PHP 7.x, Microsoft ODBC driver, Apache, and Microsoft PHP drivers on Ubuntu 15, 16, RedHat 7, Debian 8, SUSE 12, and macOS. +The following instructions assume a clean environment and show how to install PHP 7.x, Microsoft ODBC driver, Apache, and Microsoft PHP drivers on Ubuntu 16, 17 RedHat 7, Debian 8, 9 SUSE 12, and macOS 10.11, 10.12. + +Note that [Microsoft ODBC Driver 17][odbc17] is required for Ubuntu 17 and Debian 9. ### Step 1: Install PHP7+ #### PHP 7.0 -**Ubuntu 15.10** - - sudo su - sh -c 'echo "deb http://packages.dotdeb.org jessie all \ndeb-src http://packages.dotdeb.org jessie all" >> /etc/apt/sources.list' - apt-get update - apt-get install php7.0 php7.0-fpm php-pear php7.0-dev mcrypt php7.0-mcrypt php-mbstring php7.0-xml - -**Ubuntu 16.04** +**Ubuntu 16.04, 17.10** sudo su apt-get update @@ -113,13 +108,23 @@ The following instructions assume a clean environment and show how to install PH apt-get update apt-get install -y php7.0 php-pear php7.0-dev php7.0-xml +**Debian 9** + + sudo su + apt-get install curl apt-transport-https + curl https://www.dotdeb.org/dotdeb.gpg | apt-key add - + echo "deb http://packages.dotdeb.org stretch all" >> /etc/apt/sources.list + echo "deb-src http://packages.dotdeb.org stretch all" >> /etc/apt/sources.list + apt-get update + apt-get install -y php7.0 php-pear php7.0-dev php7.0-xml + **SUSE 12** sudo su zypper refresh zypper install -y php7 php7-pear php7-devel -**macOS** +**macOS 10.11, 10.12** /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" brew tap @@ -133,9 +138,7 @@ The following instructions assume a clean environment and show how to install PH #### PHP 7.1 -Note that there are no PHP 7.1 packages available for Ubuntu 15.10. - -**Ubuntu 16.04** +**Ubuntu 16.04, 17.10** sudo su add-apt-repository ppa:ondrej/php @@ -153,7 +156,7 @@ Note that there are no PHP 7.1 packages available for Ubuntu 15.10. yum update yum install php php-pdo php-xml php-pear php-devel re2c gcc-c++ gcc -**Debian 8** +**Debian 8, 9** sudo su apt-get install curl apt-transport-https @@ -169,7 +172,7 @@ Note that there are no PHP 7.1 packages available for Ubuntu 15.10. zypper --gpg-auto-import-keys refresh zypper -n install php7 php7-pear php7-devel -**macOS** +**macOS 10.11, 10.12** /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" brew tap @@ -184,19 +187,6 @@ Note that there are no PHP 7.1 packages available for Ubuntu 15.10. ### Step 2: Install Prerequisites -**Ubuntu 15.10** - - sudo su - curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - - curl https://packages.microsoft.com/config/ubuntu/15.10/prod.list > /etc/apt/sources.list.d/mssql-release.list - exit - sudo apt-get update - sudo ACCEPT_EULA=Y apt-get install msodbcsql mssql-tools - sudo apt-get install unixodbc-dev - echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile - echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc - source ~/.bashrc - **Ubuntu 16.04** sudo su @@ -210,6 +200,19 @@ Note that there are no PHP 7.1 packages available for Ubuntu 15.10. echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc source ~/.bashrc +**Ubuntu 17.10** + + sudo su + curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - + curl https://packages.microsoft.com/config/ubuntu/17.10/prod.list > /etc/apt/sources.list.d/mssql-release.list + exit + sudo apt-get update + sudo ACCEPT_EULA=Y apt-get install msodbcsql mssql-tools + sudo apt-get install unixodbc-dev + echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile + echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc + source ~/.bashrc + **RedHat 7** sudo su @@ -236,6 +239,19 @@ Note that there are no PHP 7.1 packages available for Ubuntu 15.10. sudo ACCEPT_EULA=Y apt-get install msodbcsql sudo apt-get install unixodbc-dev +**Debian 9** + + sudo su + curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - + curl https://packages.microsoft.com/config/debian/9/prod.list > /etc/apt/sources.list.d/mssql-release.list + apt-get install -y locales + echo "en_US.UTF-8 UTF-8" > /etc/locale.gen + locale-gen + exit + sudo apt-get update + sudo ACCEPT_EULA=Y apt-get install msodbcsql + sudo apt-get install unixodbc-dev + **SUSE 12** sudo su @@ -249,7 +265,7 @@ Note that there are no PHP 7.1 packages available for Ubuntu 15.10. echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc source ~/.bashrc -**macOS** +**macOS 10.11, 10.12** brew tap microsoft/msodbcsql https://github.com/Microsoft/homebrew-mssql-release brew update @@ -520,6 +536,8 @@ This project has adopted the Microsoft Open Source Code of Conduct. For more inf [odbc13]: https://www.microsoft.com/download/details.aspx?id=50420 +[odbc17]: https://github.com/Microsoft/msphpsql/tree/master/ODBC%2017%20binaries%20preview + [odbcLinux]: https://msdn.microsoft.com/library/hh568454(v=sql.110).aspx [phpazure]: https://azure.microsoft.com/documentation/articles/sql-database-develop-php-simple-windows/ diff --git a/appveyor.yml b/appveyor.yml index ae8c975d..e57815bb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -32,30 +32,11 @@ environment: TEST_PHP_SQL_SERVER: (local)\SQL2012SP1 SQL_INSTANCE: SQL2012SP1 PHP_VC: 14 - PHP_MAJOR_VER: 7.0 - PHP_MINOR_VER: latest - PHP_SDK_DIR: c:\projects\php\x64 - PHP_INSTALL_DIR: c:\projects\php\x64\bin - platform: x64 - - BUILD_PLATFORM: x64 - TEST_PHP_SQL_SERVER: (local)\SQL2014 - SQL_INSTANCE: SQL2014 - PHP_VC: 14 PHP_MAJOR_VER: 7.1 PHP_MINOR_VER: latest PHP_SDK_DIR: c:\projects\php\x64 PHP_INSTALL_DIR: c:\projects\php\x64\bin platform: x64 - - BUILD_PLATFORM: x86 - TEST_PHP_SQL_SERVER: (local)\SQL2008R2SP2 - SQL_INSTANCE: SQL2008R2SP2 - PHP_VC: 14 - PHP_MAJOR_VER: 7.0 - PHP_MINOR_VER: latest - PHP_SDK_DIR: c:\projects\php\x86 - PHP_INSTALL_DIR: c:\projects\php\x86\bin - PHP_ZTS: --disable-zts - platform: x86 # PHP_MAJOR_VER is PHP major version to build (7.0, 7.1) # PHP_MINOR_VER is PHP point release number (or latest for latest release) diff --git a/source/pdo_sqlsrv/config.w32 b/source/pdo_sqlsrv/config.w32 index 991f4635..b8c72c02 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 c0a7ea4f..66412bbc 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -1301,7 +1301,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 ), strlen(last_insert_id_query), &wsql_len ); + wsql_string = utf16_string_from_mbcs_string( SQLSRV_ENCODING_CHAR, reinterpret_cast( last_insert_id_query ), static_cast( strlen( 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 7d46b5d8..0fa961c6 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 b724bea2..1459384d 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 19def08c..c52e9442 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 6db8a363..e0d2302c 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -33,7 +33,7 @@ char EXCEPTION_PROPERTY_ERRORINFO[] = "errorInfo"; const int MAX_DIGITS = 11; // +-2 billion = 10 digits + 1 for the sign if negative // the warning message is not the error message alone; it must take WARNING_TEMPLATE above into consideration without the formats -const int WARNING_MIN_LENGTH = strlen(WARNING_TEMPLATE) - strlen("%1!s!%2!d!%3!s!"); +const int WARNING_MIN_LENGTH = static_cast( strlen( WARNING_TEMPLATE ) - strlen( "%1!s!%2!d!%3!s!" )); // buffer used to hold a formatted log message prior to actually logging it. const int LOG_MSG_SIZE = 2048; @@ -421,6 +421,10 @@ pdo_error PDO_ERRORS[] = { SQLSRV_ERROR_OUTPUT_PARAM_TYPES_NOT_SUPPORTED, { IMSSP, (SQLCHAR*) "Stored Procedures do not support text, ntext or image as OUTPUT parameters.", -83, false } }, + { + SQLSRV_ERROR_ENCRYPTED_STREAM_FETCH, + { IMSSP, (SQLCHAR*) "Connection with Column Encryption enabled does not support fetching stream. Please fetch the data as a string.", -84, false } + }, { UINT_MAX, {} } }; diff --git a/source/pdo_sqlsrv/php_pdo_sqlsrv.h b/source/pdo_sqlsrv/php_pdo_sqlsrv.h index 52f41890..ba7dd4b7 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 35ae7fcb..248c99cc 100644 --- a/source/pdo_sqlsrv/template.rc +++ b/source/pdo_sqlsrv/template.rc @@ -3,7 +3,7 @@ // // Contents: Version resource // -// Microsoft Drivers 5.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 ecffe8f7..0f6bf36b 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 64719df7..61080a42 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 72d9859a..2d8a549a 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 2199d655..0ab97662 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 83694f5d..6f9b0710 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -305,7 +305,7 @@ bool core_compare_error_state( _In_ sqlsrv_conn* conn, _In_ SQLRETURN rc, _In_ if( SQL_SUCCEEDED( rc ) ) return false; - SQLCHAR state[ SQL_SQLSTATE_BUFSIZE ]; + SQLCHAR state[ SQL_SQLSTATE_BUFSIZE ] = { 0 }; SQLSMALLINT len; SQLRETURN sr = SQLGetDiagField( SQL_HANDLE_DBC, conn->handle(), 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len ); @@ -321,13 +321,12 @@ bool core_compare_error_state( _In_ sqlsrv_conn* conn, _In_ SQLRETURN rc, _In_ bool core_search_odbc_driver_unix( _In_ DRIVER_VERSION driver_version ) { +#ifndef _WIN32 char szBuf[DEFAULT_CONN_STR_LEN+1]; // use a large enough buffer size WORD cbBufMax = DEFAULT_CONN_STR_LEN; WORD cbBufOut; char *pszBuf = szBuf; - bool found_driver = false; -#ifndef _WIN32 // get all the names of the installed drivers delimited by null characters if(! SQLGetInstalledDrivers( szBuf, cbBufMax, &cbBufOut ) ) { @@ -966,8 +965,8 @@ void load_configure_ksp( _Inout_ sqlsrv_conn* conn TSRMLS_DC ) char* ksp_name = Z_STRVAL_P( conn->ce_option.ksp_name ); char* ksp_path = Z_STRVAL_P( conn->ce_option.ksp_path ); - unsigned int name_len = Z_STRLEN_P( conn->ce_option.ksp_name ); - unsigned int key_size = conn->ce_option.key_size; + unsigned int name_len = static_cast( Z_STRLEN_P( conn->ce_option.ksp_name )); + unsigned int key_size = static_cast( conn->ce_option.key_size ); sqlsrv_malloc_auto_ptr ksp_data; diff --git a/source/shared/core_init.cpp b/source/shared/core_init.cpp index b67881c2..d4708006 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 98ea7afa..58632354 100644 --- a/source/shared/core_results.cpp +++ b/source/shared/core_results.cpp @@ -3,7 +3,7 @@ // // Contents: Result sets // -// Microsoft Drivers 5.1 for PHP for SQL Server +// Microsoft Drivers 5.2 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/core_sqlsrv.h b/source/shared/core_sqlsrv.h index ea3fd4f6..2e2cc371 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -1716,6 +1716,7 @@ enum SQLSRV_ERROR_CODES { SQLSRV_ERROR_KEYSTORE_KEY_MISSING, SQLSRV_ERROR_KEYSTORE_INVALID_VALUE, SQLSRV_ERROR_OUTPUT_PARAM_TYPES_NOT_SUPPORTED, + SQLSRV_ERROR_ENCRYPTED_STREAM_FETCH, // Driver specific error codes starts from here. SQLSRV_ERROR_DRIVER_SPECIFIC = 1000, @@ -2266,10 +2267,11 @@ namespace core { SQLRETURN r; SQLHDESC hIpd = NULL; core::SQLGetStmtAttr( stmt, SQL_ATTR_IMP_PARAM_DESC, &hIpd, 0, 0 ); - r = ::SQLSetDescField( hIpd, rec_num, fld_id, value_ptr, str_len ); - - CHECK_SQL_ERROR_OR_WARNING( r, stmt ) { - throw CoreException(); + if( value_ptr ) { + r = ::SQLSetDescField( hIpd, rec_num, fld_id, value_ptr, str_len ); + CHECK_SQL_ERROR_OR_WARNING( r, stmt ) { + throw CoreException(); + } } } diff --git a/source/shared/core_stmt.cpp b/source/shared/core_stmt.cpp index 9e5a039b..947ce416 100644 --- a/source/shared/core_stmt.cpp +++ b/source/shared/core_stmt.cpp @@ -3,17 +3,17 @@ // // Contents: Core routines that use statement handles shared between sqlsrv and pdo_sqlsrv // -// Microsoft Drivers 5.1 for PHP for SQL Server +// Microsoft Drivers 5.2 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), -// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +// 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 +// 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. //--------------------------------------------------------------------------------------------------------------------------------- @@ -27,7 +27,7 @@ namespace { // certain drivers using this layer will call for repeated or out of order field retrievals. To allow this, we cache the // results of every field request, and if it is out of order, we cache those for preceding fields. struct field_cache { - + void* value; SQLLEN len; sqlsrv_phptype type; @@ -100,10 +100,10 @@ void core_get_field_common(_Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_in sqlsrv_php_type, _Inout_updates_bytes_(*field_len) void*& field_value, _Inout_ SQLLEN* field_len TSRMLS_DC); // returns the ODBC C type constant that matches the PHP type and encoding given SQLSMALLINT default_c_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_ zval const* param_z, _In_ SQLSRV_ENCODING encoding TSRMLS_DC ); -void default_sql_size_and_scale( _Inout_ sqlsrv_stmt* stmt, _In_opt_ unsigned int paramno, _In_ zval* param_z, _In_ SQLSRV_ENCODING encoding, +void default_sql_size_and_scale( _Inout_ sqlsrv_stmt* stmt, _In_opt_ unsigned int paramno, _In_ zval* param_z, _In_ SQLSRV_ENCODING encoding, _Out_ SQLULEN& column_size, _Out_ SQLSMALLINT& decimal_digits TSRMLS_DC ); // given a zval and encoding, determine the appropriate sql type, column size, and decimal scale (if appropriate) -void default_sql_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_ zval* param_z, _In_ SQLSRV_ENCODING encoding, +void default_sql_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_ zval* param_z, _In_ SQLSRV_ENCODING encoding, _Out_ SQLSMALLINT& sql_type TSRMLS_DC ); void col_cache_dtor( _Inout_ zval* data_z ); void field_cache_dtor( _Inout_ zval* data_z ); @@ -119,7 +119,7 @@ void resize_output_buffer_if_necessary( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval* void adjustInputPrecision( _Inout_ zval* param_z, _In_ SQLSMALLINT decimal_digits ); bool reset_ae_stream_cursor( _Inout_ sqlsrv_stmt* stmt ); void save_output_param_for_later( _Inout_ sqlsrv_stmt* stmt, _Inout_ sqlsrv_output_param& param TSRMLS_DC ); -// send all the stream data +// send all the stream data void send_param_streams( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ); // called when a bound output string parameter is to be destroyed void sqlsrv_output_param_dtor( _Inout_ zval* data ); @@ -153,7 +153,7 @@ sqlsrv_stmt::sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error ZVAL_UNDEF( &active_stream ); // initialize the input string parameters array (which holds zvals) core::sqlsrv_array_init( *conn, ¶m_input_strings TSRMLS_CC ); - + // initialize the (input only) stream parameters (which holds sqlsrv_stream structures) ZVAL_NEW_ARR( ¶m_streams ); core::sqlsrv_zend_hash_init(*conn, Z_ARRVAL( param_streams ), 5 /* # of buckets */, sqlsrv_stream_dtor, 0 /*persistent*/ TSRMLS_CC); @@ -164,7 +164,7 @@ sqlsrv_stmt::sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error // initialize the output string parameters (which holds sqlsrv_output_param structures) ZVAL_NEW_ARR( &output_params ); core::sqlsrv_zend_hash_init(*conn, Z_ARRVAL( output_params ), 5 /* # of buckets */, sqlsrv_output_param_dtor, 0 /*persistent*/ TSRMLS_CC); - + // initialize the col cache ZVAL_NEW_ARR( &col_cache ); core::sqlsrv_zend_hash_init( *conn, Z_ARRVAL(col_cache), 5 /* # of buckets */, col_cache_dtor, 0 /*persistent*/ TSRMLS_CC ); @@ -180,7 +180,7 @@ sqlsrv_stmt::~sqlsrv_stmt( void ) if( Z_TYPE( active_stream ) != IS_UNDEF ) { TSRMLS_FETCH(); close_active_stream( this TSRMLS_CC ); - } + } // delete any current results if( current_results ) { @@ -188,8 +188,8 @@ sqlsrv_stmt::~sqlsrv_stmt( void ) efree( current_results ); current_results = NULL; } - - invalidate(); + + invalidate(); zval_ptr_dtor( ¶m_input_strings ); zval_ptr_dtor( &output_params ); zval_ptr_dtor( ¶m_streams ); @@ -236,10 +236,10 @@ void sqlsrv_stmt::new_result_set( TSRMLS_D ) // create a new result set if( cursor_type == SQLSRV_CURSOR_BUFFERED ) { - sqlsrv_malloc_auto_ptr result; + sqlsrv_malloc_auto_ptr result; result = reinterpret_cast ( sqlsrv_malloc( sizeof( sqlsrv_buffered_result_set ) ) ); new ( result.get() ) sqlsrv_buffered_result_set( this TSRMLS_CC ); - current_results = result.get(); + current_results = result.get(); result.transferred(); } else { @@ -248,7 +248,7 @@ void sqlsrv_stmt::new_result_set( TSRMLS_D ) } // core_sqlsrv_create_stmt -// Common code to allocate a statement from either driver. Returns a valid driver statement object or +// Common code to allocate a statement from either driver. Returns a valid driver statement object or // throws an exception if an error occurs. // Parameters: // conn - The connection resource by which the client and server are connected. @@ -258,9 +258,9 @@ void sqlsrv_stmt::new_result_set( TSRMLS_D ) // err - callback for error handling // driver - reference to caller // Return -// Returns the created statement +// Returns the created statement -sqlsrv_stmt* core_sqlsrv_create_stmt( _Inout_ sqlsrv_conn* conn, _In_ driver_stmt_factory stmt_factory, _In_opt_ HashTable* options_ht, +sqlsrv_stmt* core_sqlsrv_create_stmt( _Inout_ sqlsrv_conn* conn, _In_ driver_stmt_factory stmt_factory, _In_opt_ HashTable* options_ht, _In_opt_ const stmt_option valid_stmt_opts[], _In_ error_callback const err, _In_opt_ void* driver TSRMLS_DC ) { sqlsrv_malloc_auto_ptr stmt; @@ -275,11 +275,11 @@ sqlsrv_stmt* core_sqlsrv_create_stmt( _Inout_ sqlsrv_conn* conn, _In_ driver_stm stmt->conn = conn; - // handle has been set in the constructor of ss_sqlsrv_stmt, so we set it to NULL to prevent a double free + // handle has been set in the constructor of ss_sqlsrv_stmt, so we set it to NULL to prevent a double free // in the catch block below. stmt_h = SQL_NULL_HANDLE; - // process the options array given to core_sqlsrv_prepare. + // process the options array given to core_sqlsrv_prepare. if( options_ht && zend_hash_num_elements( options_ht ) > 0 && valid_stmt_opts ) { zend_ulong index = -1; zend_string *key = NULL; @@ -298,7 +298,7 @@ sqlsrv_stmt* core_sqlsrv_create_stmt( _Inout_ sqlsrv_conn* conn, _In_ driver_stm // The driver layer should ensure that the key is valid. DEBUG_SQLSRV_ASSERT( stmt_opt != NULL, "allocate_stmt: unexpected null value for statement option." ); - // perform the actions the statement option needs done. + // perform the actions the statement option needs done. (*stmt_opt->func)( stmt, stmt_opt, value_z TSRMLS_CC ); } ZEND_HASH_FOREACH_END(); } @@ -342,8 +342,8 @@ sqlsrv_stmt* core_sqlsrv_create_stmt( _Inout_ sqlsrv_conn* conn, _In_ driver_stm // decimal_digits - if column_size is valid and the type contains a scale, this contains the scale // Return: // Nothing, though an exception is thrown if an error occurs -// The php type of the parameter is taken from the zval. -// The sql type is given as a hint if the driver provides it. +// The php type of the parameter is taken from the zval. +// The sql type is given as a hint if the driver provides it. void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_num, _In_ SQLSMALLINT direction, _Inout_ zval* param_z, _In_ SQLSRV_PHPTYPE php_out_type, _Inout_ SQLSRV_ENCODING encoding, _Inout_ SQLSMALLINT sql_type, _Inout_ SQLULEN column_size, @@ -353,9 +353,9 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ SQLPOINTER buffer = NULL; SQLLEN buffer_len = 0; - SQLSRV_ASSERT( direction == SQL_PARAM_INPUT || direction == SQL_PARAM_OUTPUT || direction == SQL_PARAM_INPUT_OUTPUT, + SQLSRV_ASSERT( direction == SQL_PARAM_INPUT || direction == SQL_PARAM_OUTPUT || direction == SQL_PARAM_INPUT_OUTPUT, "core_sqlsrv_bind_param: Invalid parameter direction." ); - SQLSRV_ASSERT( direction == SQL_PARAM_INPUT || php_out_type != SQLSRV_PHPTYPE_INVALID, + SQLSRV_ASSERT( direction == SQL_PARAM_INPUT || php_out_type != SQLSRV_PHPTYPE_INVALID, "core_sqlsrv_bind_param: php_out_type not set before calling core_sqlsrv_bind_param." ); try { @@ -424,11 +424,11 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ } } - // If the user specifies a certain type for an output parameter, we have to convert the zval + // If the user specifies a certain type for an output parameter, we have to convert the zval // to that type so that when the buffer is filled, the type is correct. But first, - // should check if a LOB type is specified. - CHECK_CUSTOM_ERROR( direction != SQL_PARAM_INPUT && ( sql_type == SQL_LONGVARCHAR - || sql_type == SQL_WLONGVARCHAR || sql_type == SQL_LONGVARBINARY ), + // should check if a LOB type is specified. + CHECK_CUSTOM_ERROR( direction != SQL_PARAM_INPUT && ( sql_type == SQL_LONGVARCHAR + || sql_type == SQL_WLONGVARCHAR || sql_type == SQL_LONGVARBINARY ), stmt, SQLSRV_ERROR_OUTPUT_PARAM_TYPES_NOT_SUPPORTED ){ throw core::CoreException(); } @@ -464,7 +464,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ } SQLSRV_ASSERT(( Z_TYPE_P( param_z ) != IS_STRING && Z_TYPE_P( param_z ) != IS_RESOURCE ) || - ( encoding == SQLSRV_ENCODING_SYSTEM || encoding == SQLSRV_ENCODING_UTF8 || + ( encoding == SQLSRV_ENCODING_SYSTEM || encoding == SQLSRV_ENCODING_UTF8 || encoding == SQLSRV_ENCODING_BINARY ), "core_sqlsrv_bind_param: invalid encoding" ); if( stmt->conn->ce_option.enabled && ( sql_type == SQL_UNKNOWN_TYPE || column_size == SQLSRV_UNKNOWN_SIZE )){ @@ -497,7 +497,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ case IS_NULL: { - SQLSRV_ASSERT( direction == SQL_PARAM_INPUT, "Invalid output param type. The driver layer should catch this." ); + SQLSRV_ASSERT( direction == SQL_PARAM_INPUT, "Invalid output param type. The driver layer should catch this." ); ind_ptr = SQL_NULL_DATA; buffer = NULL; buffer_len = 0; @@ -506,7 +506,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ case IS_TRUE: case IS_FALSE: case IS_LONG: - { + { // if it is boolean, set the lval to 0 or 1 convert_to_long( param_z ); buffer = ¶m_z->value; @@ -539,7 +539,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ buffer = Z_STRVAL_P( param_z ); buffer_len = Z_STRLEN_P( param_z ); - + // if the encoding is UTF-8, translate from UTF-8 to UTF-16 (the type variables should have already been adjusted) if( direction == SQL_PARAM_INPUT && encoding == CP_UTF8 ){ @@ -595,11 +595,11 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ save_output_param_for_later( stmt, output_param TSRMLS_CC ); - // For output parameters, if we set the column_size to be same as the buffer_len, - // then if there is a truncation due to the data coming from the server being + // For output parameters, if we set the column_size to be same as the buffer_len, + // then if there is a truncation due to the data coming from the server being // greater than the column_size, we don't get any truncation error. In order to - // avoid this silent truncation, we set the column_size to be "MAX" size for - // string types. This will guarantee that there is no silent truncation for + // avoid this silent truncation, we set the column_size to be "MAX" size for + // string types. This will guarantee that there is no silent truncation for // output parameters. // if column encryption is enabled, at this point the correct column size has been set by SQLDescribeParam if( direction == SQL_PARAM_OUTPUT && !stmt->conn->ce_option.enabled ){ @@ -621,7 +621,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ break; case IS_RESOURCE: { - SQLSRV_ASSERT( direction == SQL_PARAM_INPUT, "Invalid output param type. The driver layer should catch this." ); + SQLSRV_ASSERT( direction == SQL_PARAM_INPUT, "Invalid output param type. The driver layer should catch this." ); sqlsrv_stream stream_encoding( param_z, encoding ); HashTable* streams_ht = Z_ARRVAL( stmt->param_streams ); core::sqlsrv_zend_hash_index_update_mem( *stmt, streams_ht, param_num, &stream_encoding, sizeof(stream_encoding) TSRMLS_CC ); @@ -633,7 +633,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ break; case IS_OBJECT: { - SQLSRV_ASSERT( direction == SQL_PARAM_INPUT, "Invalid output param type. The driver layer should catch this." ); + SQLSRV_ASSERT( direction == SQL_PARAM_INPUT, "Invalid output param type. The driver layer should catch this." ); zval function_z; zval buffer_z; zval format_z; @@ -644,12 +644,12 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ ZVAL_UNDEF( params ); bool valid_class_name_found = false; - + zend_class_entry *class_entry = Z_OBJCE_P( param_z TSRMLS_CC ); while( class_entry != NULL ){ SQLSRV_ASSERT( class_entry->name != NULL, "core_sqlsrv_bind_param: class_entry->name is NULL." ); - if( class_entry->name->len == DateTime::DATETIME_CLASS_NAME_LEN && class_entry->name != NULL && + if( class_entry->name->len == DateTime::DATETIME_CLASS_NAME_LEN && class_entry->name != NULL && stricmp( class_entry->name->val, DateTime::DATETIME_CLASS_NAME ) == 0 ){ valid_class_name_found = true; break; @@ -657,7 +657,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ else{ - // Check the parent + // Check the parent class_entry = class_entry->parent; } } @@ -665,7 +665,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ CHECK_CUSTOM_ERROR( !valid_class_name_found, stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, param_num + 1 ){ throw core::CoreException(); } - + // if the user specifies the 'date' sql type, giving it the normal format will cause a 'date overflow error' // meaning there is too much information in the character string. If the user specifies the 'datetimeoffset' // sql type, it lacks the timezone. @@ -698,7 +698,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ buffer_len = Z_STRLEN( buffer_z ) - 1; ind_ptr = buffer_len; break; - } + } case IS_ARRAY: THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, param_num + 1 ); break; @@ -712,7 +712,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ ind_ptr = SQL_NULL_DATA; } - core::SQLBindParameter( stmt, param_num + 1, direction, + core::SQLBindParameter( stmt, param_num + 1, direction, c_type, sql_type, column_size, decimal_digits, buffer, buffer_len, &ind_ptr TSRMLS_CC ); if ( stmt->conn->ce_option.enabled && sql_type == SQL_TYPE_TIMESTAMP ) { @@ -775,7 +775,7 @@ SQLRETURN core_sqlsrv_execute( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC, _In_reads_by send_param_streams( stmt TSRMLS_CC ); } - + stmt->new_result_set( TSRMLS_C ); stmt->executed = true; @@ -792,7 +792,7 @@ SQLRETURN core_sqlsrv_execute( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC, _In_reads_by } catch( core::CoreException& e ) { - // if the statement executed but failed in a subsequent operation before returning, + // if the statement executed but failed in a subsequent operation before returning, // we need to cancel the statement and deref the output and stream parameters if ( stmt->send_streams_at_exec ) { finalize_output_parameters( stmt TSRMLS_CC ); @@ -815,7 +815,7 @@ SQLRETURN core_sqlsrv_execute( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC, _In_reads_by // fetch_orientation - method to move the cursor // fetch_offset - if the method has a parameter (such as number of rows to move or literal row number) // Returns: -// Nothing, exception thrown if an error. stmt->past_fetch_end is set to true if the +// Nothing, exception thrown if an error. stmt->past_fetch_end is set to true if the // user scrolls past a non-scrollable result set bool core_sqlsrv_fetch( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orientation, _In_ SQLULEN fetch_offset TSRMLS_DC ) @@ -823,9 +823,9 @@ bool core_sqlsrv_fetch( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orient // pre-condition check SQLSRV_ASSERT( fetch_orientation >= SQL_FETCH_NEXT || fetch_orientation <= SQL_FETCH_RELATIVE, "core_sqlsrv_fetch: Invalid value provided for fetch_orientation parameter." ); - + try { - + // clear the field cache of the previous fetch zend_hash_clean( Z_ARRVAL( stmt->field_cache )); @@ -848,16 +848,16 @@ bool core_sqlsrv_fetch( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orient close_active_stream( stmt TSRMLS_CC ); // if the statement has rows and is not scrollable but doesn't yet have - // fetch_called, this must be the first time we've called sqlsrv_fetch. + // fetch_called, this must be the first time we've called sqlsrv_fetch. if( stmt->cursor_type == SQL_CURSOR_FORWARD_ONLY && stmt->has_rows && !stmt->fetch_called ) { stmt->fetch_called = true; return true; } - // move to the record requested. For absolute records, we use a 0 based offset, so +1 since + // move to the record requested. For absolute records, we use a 0 based offset, so +1 since // SQLFetchScroll uses a 1 based offset, otherwise for relative, just use the fetch_offset provided. SQLRETURN r = stmt->current_results->fetch( fetch_orientation, ( fetch_orientation == SQL_FETCH_RELATIVE ) ? fetch_offset : fetch_offset + 1 TSRMLS_CC ); - + // when AE is enabled, will keep track of the number of rows being fetched so far such that the cursor can be reset back to its original position when getting stream data if ( stmt->cursor_type == SQL_CURSOR_FORWARD_ONLY && stmt->conn->ce_option.enabled == true ) { stmt->fwd_row_index++; @@ -870,12 +870,12 @@ bool core_sqlsrv_fetch( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orient stmt->fetch_called = false; // reset this flag return false; } - + // mark that we called fetch (which get_field, et. al. uses) and reset our last field retrieved stmt->fetch_called = true; stmt->last_field_index = -1; stmt->has_rows = true; // since we made it this far, we must have at least one row - } + } catch (core::CoreException& e) { throw e; } @@ -887,7 +887,7 @@ bool core_sqlsrv_fetch( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orient } -// Retrieves metadata for a field of a prepared statement. +// Retrieves metadata for a field of a prepared statement. // Parameters: // colno - the index of the field for which to return the metadata. columns are 0 based in PDO // Return: @@ -916,7 +916,7 @@ field_meta_data* core_sqlsrv_field_metadata( _Inout_ sqlsrv_stmt* stmt, _In_ SQL } bool converted = convert_string_from_utf16( encoding, field_name_temp, field_len_temp, ( char** ) &( meta_data->field_name ), field_name_len ); - + CHECK_CUSTOM_ERROR( !converted, stmt, SQLSRV_ERROR_FIELD_ENCODING_TRANSLATE, get_last_error_message() ) { throw core::CoreException(); } @@ -928,7 +928,7 @@ field_meta_data* core_sqlsrv_field_metadata( _Inout_ sqlsrv_stmt* stmt, _In_ SQL case SQL_TYPE_TIMESTAMP: case SQL_TYPE_DATE: case SQL_SS_TIME2: - case SQL_SS_TIMESTAMPOFFSET: + case SQL_SS_TIMESTAMPOFFSET: case SQL_BIT: case SQL_TINYINT: case SQL_SMALLINT: @@ -936,7 +936,7 @@ field_meta_data* core_sqlsrv_field_metadata( _Inout_ sqlsrv_stmt* stmt, _In_ SQL case SQL_BIGINT: case SQL_REAL: case SQL_FLOAT: - case SQL_DOUBLE: + case SQL_DOUBLE: { meta_data->field_precision = meta_data->field_size; meta_data->field_size = 0; @@ -949,9 +949,9 @@ field_meta_data* core_sqlsrv_field_metadata( _Inout_ sqlsrv_stmt* stmt, _In_ SQL // Set the field name lenth meta_data->field_name_len = static_cast( field_name_len ); - + field_meta_data* result_field_meta_data = meta_data; - meta_data.transferred(); + meta_data.transferred(); return result_field_meta_data; } @@ -1047,7 +1047,7 @@ void core_sqlsrv_get_field( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_i if( sqlsrv_php_type_out != NULL ) *sqlsrv_php_type_out = static_cast( sqlsrv_php_type.typeinfo.type ); - // Retrieve the data + // Retrieve the data core_get_field_common( stmt, field_index, sqlsrv_php_type, field_value, field_len TSRMLS_CC ); // if the user wants us to cache the field, we'll do it @@ -1064,7 +1064,7 @@ void core_sqlsrv_get_field( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_i // core_sqlsrv_has_any_result // return if any result set or rows affected message is waiting -// to be consumed and moved over by sqlsrv_next_result. +// to be consumed and moved over by sqlsrv_next_result. // Parameters: // stmt - The statement object on which to check for results. // Return: @@ -1098,12 +1098,12 @@ void core_sqlsrv_next_result( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC, _In_ bool fin CHECK_CUSTOM_ERROR( stmt->past_next_result_end, stmt, SQLSRV_ERROR_NEXT_RESULT_PAST_END ) { throw core::CoreException(); } - + close_active_stream( stmt TSRMLS_CC ); //Clear column sql types and sql display sizes. - zend_hash_clean( Z_ARRVAL( stmt->col_cache )); - + zend_hash_clean( Z_ARRVAL( stmt->col_cache )); + SQLRETURN r; if( throw_on_errors ) { r = core::SQLMoreResults( stmt TSRMLS_CC ); @@ -1166,34 +1166,34 @@ void core_sqlsrv_post_param( _Inout_ sqlsrv_stmt* stmt, _In_ zend_ulong param_nu } //Calls SQLSetStmtAttr to set a cursor. -void core_sqlsrv_set_scrollable( _Inout_ sqlsrv_stmt* stmt, _In_ unsigned long cursor_type TSRMLS_DC ) +void core_sqlsrv_set_scrollable( _Inout_ sqlsrv_stmt* stmt, _In_ unsigned long cursor_type TSRMLS_DC ) { try { switch( cursor_type ) { - + case SQL_CURSOR_STATIC: - core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, + core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, reinterpret_cast( SQL_CURSOR_STATIC ), SQL_IS_UINTEGER TSRMLS_CC ); break; case SQL_CURSOR_DYNAMIC: - core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, + core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, reinterpret_cast( SQL_CURSOR_DYNAMIC ), SQL_IS_UINTEGER TSRMLS_CC ); break; case SQL_CURSOR_KEYSET_DRIVEN: - core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, + core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, reinterpret_cast( SQL_CURSOR_KEYSET_DRIVEN ), SQL_IS_UINTEGER TSRMLS_CC ); break; - + case SQL_CURSOR_FORWARD_ONLY: - core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, + core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, reinterpret_cast( SQL_CURSOR_FORWARD_ONLY ), SQL_IS_UINTEGER TSRMLS_CC ); break; case SQLSRV_CURSOR_BUFFERED: - core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, + core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, reinterpret_cast( SQL_CURSOR_FORWARD_ONLY ), SQL_IS_UINTEGER TSRMLS_CC ); break; @@ -1232,7 +1232,7 @@ void core_sqlsrv_set_buffered_query_limit( _Inout_ sqlsrv_stmt* stmt, _In_ SQLLE // Overloaded. Extracts the long value and calls the core_sqlsrv_set_query_timeout -// which accepts timeout parameter as a long. If the zval is not of type long +// which accepts timeout parameter as a long. If the zval is not of type long // than throws error. void core_sqlsrv_set_query_timeout( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval* value_z TSRMLS_DC ) { @@ -1241,7 +1241,7 @@ void core_sqlsrv_set_query_timeout( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval* val // validate the value if( Z_TYPE_P( value_z ) != IS_LONG || Z_LVAL_P( value_z ) < 0 ) { - convert_to_string( value_z ); + convert_to_string( value_z ); THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INVALID_QUERY_TIMEOUT_VALUE, Z_STRVAL_P( value_z ) ); } @@ -1261,18 +1261,18 @@ void core_sqlsrv_set_query_timeout( _Inout_ sqlsrv_stmt* stmt, _In_ long timeout // set the statement attribute core::SQLSetStmtAttr( stmt, SQL_ATTR_QUERY_TIMEOUT, reinterpret_cast( (SQLLEN)timeout ), SQL_IS_UINTEGER TSRMLS_CC ); - - // a query timeout of 0 indicates "no timeout", which means that lock_timeout should also be set to "no timeout" which + + // a query timeout of 0 indicates "no timeout", which means that lock_timeout should also be set to "no timeout" which // is represented by -1. int lock_timeout = (( timeout == 0 ) ? -1 : timeout * 1000 /*convert to milliseconds*/ ); // set the LOCK_TIMEOUT on the server. char lock_timeout_sql[ 32 ]; - + int written = snprintf( lock_timeout_sql, sizeof( lock_timeout_sql ), "SET LOCK_TIMEOUT %d", lock_timeout ); - SQLSRV_ASSERT( (written != -1 && written != sizeof( lock_timeout_sql )), + SQLSRV_ASSERT( (written != -1 && written != sizeof( lock_timeout_sql )), "stmt_option_query_timeout: snprintf failed. Shouldn't ever fail." ); - + core::SQLExecDirect( stmt, lock_timeout_sql TSRMLS_CC ); stmt->query_timeout = timeout; @@ -1287,7 +1287,7 @@ void core_sqlsrv_set_send_at_exec( _Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z TSRMLS_C; // zend_is_true does not fail. It either returns true or false. - stmt->send_streams_at_exec = ( zend_is_true( value_z )) ? true : false; + stmt->send_streams_at_exec = ( zend_is_true( value_z )) ? true : false; } @@ -1304,7 +1304,7 @@ void core_sqlsrv_set_send_at_exec( _Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z bool core_sqlsrv_send_stream_packet( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) { - // if there no current parameter to process, get the next one + // if there no current parameter to process, get the next one // (probably because this is the first call to sqlsrv_send_stream_data) if( stmt->current_stream.stream_z == NULL ) { @@ -1333,7 +1333,7 @@ bool core_sqlsrv_send_stream_packet( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) 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. + // read the data from the stream, send it via SQLPutData and track how much we've sent. else { char buffer[ PHP_STREAM_BUFFER_SIZE + 1 ]; std::size_t buffer_size = sizeof( buffer ) - 3; // -3 to preserve enough space for a cut off UTF-8 character @@ -1354,7 +1354,7 @@ bool core_sqlsrv_send_stream_packet( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) // since all other MBCS supported by SQL Server are 2 byte maximum size. if( stmt->current_stream.encoding == CP_UTF8 ) { - // the size of wbuffer is set for the worst case of UTF-8 to UTF-16 conversion, which is a + // the size of wbuffer is set for the worst case of UTF-8 to UTF-16 conversion, which is a // expansion of 2x the UTF-8 size. SQLWCHAR wbuffer[ PHP_STREAM_BUFFER_SIZE + 1 ]; int wbuffer_size = static_cast( sizeof( wbuffer ) / sizeof( SQLWCHAR )); @@ -1373,14 +1373,14 @@ bool core_sqlsrv_send_stream_packet( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) // in, then reattempt the conversion. If it fails the second time, then an error is returned. size_t need_to_read = calc_utf8_missing( stmt, buffer, read TSRMLS_CC ); // read the missing bytes - size_t new_read = php_stream_read( param_stream, static_cast( buffer ) + read, + size_t new_read = php_stream_read( param_stream, static_cast( buffer ) + read, need_to_read ); // if the bytes couldn't be read, then we return an error CHECK_CUSTOM_ERROR( new_read != need_to_read, stmt, SQLSRV_ERROR_INPUT_STREAM_ENCODING_TRANSLATE, get_last_error_message( ERROR_NO_UNICODE_TRANSLATION )) { throw core::CoreException(); } // try the conversion again with the complete character -#ifndef _WIN32 +#ifndef _WIN32 wsize = SystemLocale::ToUtf16Strict( stmt->current_stream.encoding, buffer, static_cast(read + new_read), wbuffer, static_cast(sizeof( wbuffer ) / sizeof( SQLWCHAR ))); #else wsize = MultiByteToWideChar( stmt->current_stream.encoding, MB_ERR_INVALID_CHARS, buffer, static_cast( read + new_read ), wbuffer, static_cast( sizeof( wbuffer ) / sizeof( wchar_t ))); @@ -1426,7 +1426,7 @@ void stmt_option_query_timeout:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_opt void stmt_option_send_at_exec:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC ) { - core_sqlsrv_set_send_at_exec( stmt, value_z TSRMLS_CC ); + core_sqlsrv_set_send_at_exec( stmt, value_z TSRMLS_CC ); } void stmt_option_buffered_query_limit:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC ) @@ -1516,12 +1516,12 @@ void calc_string_size( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, // unixODBC 2.3.1 requires wide calls to support pooling core::SQLColAttributeW( stmt, field_index + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, &size TSRMLS_CC ); break; - } + } // for wide char types for which the size is known, return the octet length instead, since it will include the // the number of bytes necessary for the string, not just the characters case SQL_WCHAR: - case SQL_WVARCHAR: + case SQL_WVARCHAR: { // unixODBC 2.3.1 requires wide calls to support pooling core::SQLColAttributeW( stmt, field_index + 1, SQL_DESC_OCTET_LENGTH, NULL, 0, NULL, &size TSRMLS_CC ); @@ -1552,7 +1552,7 @@ size_t calc_utf8_missing( _Inout_ sqlsrv_stmt* stmt, _In_reads_(buffer_end) cons ++need_to_read; } - // determine how many bytes we need to read in based on the number of bytes in the character + // determine how many bytes we need to read in based on the number of bytes in the character // (# of high bits set) versus the number of bytes we've already read. switch( *last_char & UTF8_NBYTESEQ_MASK ) { case UTF8_2BYTESEQ_TAG1: @@ -1566,7 +1566,7 @@ size_t calc_utf8_missing( _Inout_ sqlsrv_stmt* stmt, _In_reads_(buffer_end) cons need_to_read = 3 - need_to_read; break; default: - THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INPUT_STREAM_ENCODING_TRANSLATE, + THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INPUT_STREAM_ENCODING_TRANSLATE, get_last_error_message( ERROR_NO_UNICODE_TRANSLATION )); break; } @@ -1575,198 +1575,201 @@ size_t calc_utf8_missing( _Inout_ sqlsrv_stmt* stmt, _In_reads_(buffer_end) cons } -// Caller is responsible for freeing the memory allocated for the field_value. +// Caller is responsible for freeing the memory allocated for the field_value. // The memory allocation has to happen in the core layer because otherwise -// the driver layer would have to calculate size of the field_value +// the driver layer would have to calculate size of the field_value // to decide the amount of memory allocation. void core_get_field_common( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, _Inout_ sqlsrv_phptype - sqlsrv_php_type, _Inout_updates_bytes_(*field_len) void*& field_value, _Inout_ SQLLEN* field_len TSRMLS_DC ) + sqlsrv_php_type, _Inout_updates_bytes_(*field_len) void*& field_value, _Inout_ SQLLEN* field_len TSRMLS_DC ) { - try { + try { - close_active_stream( stmt TSRMLS_CC ); + close_active_stream( stmt TSRMLS_CC ); - // make sure that fetch is called before trying to retrieve. - CHECK_CUSTOM_ERROR( !stmt->fetch_called, stmt, SQLSRV_ERROR_FETCH_NOT_CALLED ) { - throw core::CoreException(); - } + // make sure that fetch is called before trying to retrieve. + CHECK_CUSTOM_ERROR( !stmt->fetch_called, stmt, SQLSRV_ERROR_FETCH_NOT_CALLED ) { + throw core::CoreException(); + } - // make sure that fields are not retrieved incorrectly. - CHECK_CUSTOM_ERROR( stmt->last_field_index > field_index, stmt, SQLSRV_ERROR_FIELD_INDEX_ERROR, field_index, - stmt->last_field_index ) { - throw core::CoreException(); - } + // make sure that fields are not retrieved incorrectly. + CHECK_CUSTOM_ERROR( stmt->last_field_index > field_index, stmt, SQLSRV_ERROR_FIELD_INDEX_ERROR, field_index, + stmt->last_field_index ) { + throw core::CoreException(); + } - switch( sqlsrv_php_type.typeinfo.type ) { + switch( sqlsrv_php_type.typeinfo.type ) { - case SQLSRV_PHPTYPE_INT: - { - sqlsrv_malloc_auto_ptr field_value_temp; - field_value_temp = static_cast( sqlsrv_malloc( sizeof( long ))); - *field_value_temp = 0; + case SQLSRV_PHPTYPE_INT: + { + sqlsrv_malloc_auto_ptr field_value_temp; + field_value_temp = static_cast( sqlsrv_malloc( sizeof( long ))); + *field_value_temp = 0; - SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_LONG, field_value_temp, sizeof( long ), - field_len, true /*handle_warning*/ TSRMLS_CC ); + SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_LONG, field_value_temp, sizeof( long ), + field_len, true /*handle_warning*/ TSRMLS_CC ); - CHECK_SQL_ERROR_OR_WARNING( r, stmt ) { - throw core::CoreException(); - } + CHECK_SQL_ERROR_OR_WARNING( r, stmt ) { + throw core::CoreException(); + } - CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) { - throw core::CoreException(); - } + CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) { + throw core::CoreException(); + } - if( *field_len == SQL_NULL_DATA ) { - field_value = NULL; - break; - } + if( *field_len == SQL_NULL_DATA ) { + field_value = NULL; + break; + } - field_value = field_value_temp; - field_value_temp.transferred(); - break; - } + field_value = field_value_temp; + field_value_temp.transferred(); + break; + } - case SQLSRV_PHPTYPE_FLOAT: - { - sqlsrv_malloc_auto_ptr field_value_temp; - field_value_temp = static_cast( sqlsrv_malloc( sizeof( double ))); - - SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_DOUBLE, field_value_temp, sizeof( double ), - field_len, true /*handle_warning*/ TSRMLS_CC ); + case SQLSRV_PHPTYPE_FLOAT: + { + sqlsrv_malloc_auto_ptr field_value_temp; + field_value_temp = static_cast( sqlsrv_malloc( sizeof( double ))); - CHECK_SQL_ERROR_OR_WARNING( r, stmt ) { - throw core::CoreException(); - } + SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_DOUBLE, field_value_temp, sizeof( double ), + field_len, true /*handle_warning*/ TSRMLS_CC ); - CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) { - throw core::CoreException(); - } + CHECK_SQL_ERROR_OR_WARNING( r, stmt ) { + throw core::CoreException(); + } - if( *field_len == SQL_NULL_DATA ) { - field_value = NULL; - break; - } + CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) { + throw core::CoreException(); + } - field_value = field_value_temp; - field_value_temp.transferred(); - break; - } + if( *field_len == SQL_NULL_DATA ) { + field_value = NULL; + break; + } - case SQLSRV_PHPTYPE_STRING: - { - get_field_as_string( stmt, field_index, sqlsrv_php_type, field_value, field_len TSRMLS_CC ); - break; - } + field_value = field_value_temp; + field_value_temp.transferred(); + break; + } - // get the date as a string (http://msdn2.microsoft.com/en-us/library/ms712387(VS.85).aspx) and - // convert it to a DateTime object and return the created object - case SQLSRV_PHPTYPE_DATETIME: - { - char field_value_temp[ MAX_DATETIME_STRING_LEN ]; - zval params[1]; - zval field_value_temp_z; - zval function_z; + case SQLSRV_PHPTYPE_STRING: + { + get_field_as_string( stmt, field_index, sqlsrv_php_type, field_value, field_len TSRMLS_CC ); + break; + } - ZVAL_UNDEF( &field_value_temp_z ); - ZVAL_UNDEF( &function_z ); - ZVAL_UNDEF( params ); + // get the date as a string (http://msdn2.microsoft.com/en-us/library/ms712387(VS.85).aspx) and + // convert it to a DateTime object and return the created object + case SQLSRV_PHPTYPE_DATETIME: + { + char field_value_temp[ MAX_DATETIME_STRING_LEN ]; + zval params[1]; + zval field_value_temp_z; + zval function_z; - SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_CHAR, field_value_temp, - MAX_DATETIME_STRING_LEN, field_len, true TSRMLS_CC ); + ZVAL_UNDEF( &field_value_temp_z ); + ZVAL_UNDEF( &function_z ); + ZVAL_UNDEF( params ); - CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) { - throw core::CoreException(); - } + SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_CHAR, field_value_temp, + MAX_DATETIME_STRING_LEN, field_len, true TSRMLS_CC ); - zval_auto_ptr return_value_z; - return_value_z = ( zval * )sqlsrv_malloc( sizeof( zval )); - ZVAL_UNDEF( return_value_z ); + CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) { + throw core::CoreException(); + } - if( *field_len == SQL_NULL_DATA ) { - ZVAL_NULL( return_value_z ); - field_value = reinterpret_cast( return_value_z.get()); - return_value_z.transferred(); - break; - } + zval_auto_ptr return_value_z; + return_value_z = ( zval * )sqlsrv_malloc( sizeof( zval )); + ZVAL_UNDEF( return_value_z ); - // Convert the string date to a DateTime object - core::sqlsrv_zval_stringl( &field_value_temp_z, field_value_temp, *field_len ); - core::sqlsrv_zval_stringl( &function_z, "date_create", sizeof("date_create") - 1 ); - params[0] = field_value_temp_z; + if( *field_len == SQL_NULL_DATA ) { + ZVAL_NULL( return_value_z ); + field_value = reinterpret_cast( return_value_z.get()); + return_value_z.transferred(); + break; + } - if( call_user_function( EG( function_table ), NULL, &function_z, return_value_z, 1, - params TSRMLS_CC ) == FAILURE) { - THROW_CORE_ERROR(stmt, SQLSRV_ERROR_DATETIME_CONVERSION_FAILED); - } + // Convert the string date to a DateTime object + core::sqlsrv_zval_stringl( &field_value_temp_z, field_value_temp, *field_len ); + core::sqlsrv_zval_stringl( &function_z, "date_create", sizeof("date_create") - 1 ); + params[0] = field_value_temp_z; - field_value = reinterpret_cast( return_value_z.get()); - return_value_z.transferred(); - zend_string_free( Z_STR( field_value_temp_z )); - zend_string_free( Z_STR( function_z )); - break; - } + if( call_user_function( EG( function_table ), NULL, &function_z, return_value_z, 1, + params TSRMLS_CC ) == FAILURE) { + THROW_CORE_ERROR(stmt, SQLSRV_ERROR_DATETIME_CONVERSION_FAILED); + } - // create a stream wrapper around the field and return that object to the PHP script. calls to fread - // on the stream will result in calls to SQLGetData. This is handled in stream.cpp. See that file - // for how these fields are used. - case SQLSRV_PHPTYPE_STREAM: - { + field_value = reinterpret_cast( return_value_z.get()); + return_value_z.transferred(); + zend_string_free( Z_STR( field_value_temp_z )); + zend_string_free( Z_STR( function_z )); + break; + } - php_stream* stream = NULL; - sqlsrv_stream* ss = NULL; - SQLLEN sql_type; + // create a stream wrapper around the field and return that object to the PHP script. calls to fread + // on the stream will result in calls to SQLGetData. This is handled in stream.cpp. See that file + // for how these fields are used. + case SQLSRV_PHPTYPE_STREAM: + { + CHECK_CUSTOM_ERROR(stmt->conn->ce_option.enabled, stmt, SQLSRV_ERROR_ENCRYPTED_STREAM_FETCH) { + throw core::CoreException(); + } - SQLRETURN r = SQLColAttributeW( stmt->handle(), field_index + 1, SQL_DESC_TYPE, NULL, 0, NULL, &sql_type ); - CHECK_SQL_ERROR_OR_WARNING( r, stmt ) { - throw core::CoreException(); - } + php_stream* stream = NULL; + sqlsrv_stream* ss = NULL; + SQLLEN sql_type; - CHECK_CUSTOM_ERROR( !is_streamable_type( sql_type ), stmt, SQLSRV_ERROR_STREAMABLE_TYPES_ONLY ) { - throw core::CoreException(); - } + SQLRETURN r = SQLColAttributeW( stmt->handle(), field_index + 1, SQL_DESC_TYPE, NULL, 0, NULL, &sql_type ); + CHECK_SQL_ERROR_OR_WARNING( r, stmt ) { + throw core::CoreException(); + } - stream = php_stream_open_wrapper( "sqlsrv://sqlncli10", "r", 0, NULL ); + CHECK_CUSTOM_ERROR( !is_streamable_type( sql_type ), stmt, SQLSRV_ERROR_STREAMABLE_TYPES_ONLY ) { + throw core::CoreException(); + } - CHECK_CUSTOM_ERROR( !stream, stmt, SQLSRV_ERROR_STREAM_CREATE ) { - throw core::CoreException(); - } + stream = php_stream_open_wrapper( "sqlsrv://sqlncli10", "r", 0, NULL ); - ss = static_cast( stream->abstract ); - ss->stmt = stmt; - ss->field_index = field_index; - ss->sql_type = static_cast( sql_type ); - ss->encoding = static_cast( sqlsrv_php_type.typeinfo.encoding ); + CHECK_CUSTOM_ERROR( !stream, stmt, SQLSRV_ERROR_STREAM_CREATE ) { + throw core::CoreException(); + } - zval_auto_ptr return_value_z; - return_value_z = ( zval * )sqlsrv_malloc( sizeof( zval )); - ZVAL_UNDEF( return_value_z ); + ss = static_cast( stream->abstract ); + ss->stmt = stmt; + ss->field_index = field_index; + ss->sql_type = static_cast( sql_type ); + ss->encoding = static_cast( sqlsrv_php_type.typeinfo.encoding ); - // turn our stream into a zval to be returned - php_stream_to_zval( stream, return_value_z ); + zval_auto_ptr return_value_z; + return_value_z = ( zval * )sqlsrv_malloc( sizeof( zval )); + ZVAL_UNDEF( return_value_z ); - field_value = reinterpret_cast( return_value_z.get()); - return_value_z.transferred(); - break; - } + // turn our stream into a zval to be returned + php_stream_to_zval( stream, return_value_z ); - case SQLSRV_PHPTYPE_NULL: - field_value = NULL; - *field_len = 0; - break; + field_value = reinterpret_cast( return_value_z.get()); + return_value_z.transferred(); + break; + } - default: - DIE( "core_get_field_common: Unexpected sqlsrv_phptype provided" ); - break; - } + case SQLSRV_PHPTYPE_NULL: + field_value = NULL; + *field_len = 0; + break; - // sucessfully retrieved the field, so update our last retrieved field - if( stmt->last_field_index < field_index ) { - stmt->last_field_index = field_index; - } - } - catch( core::CoreException& e ) { - throw e; - } + default: + DIE( "core_get_field_common: Unexpected sqlsrv_phptype provided" ); + break; + } + + // sucessfully retrieved the field, so update our last retrieved field + if( stmt->last_field_index < field_index ) { + stmt->last_field_index = field_index; + } + } + catch( core::CoreException& e ) { + throw e; + } } @@ -1834,7 +1837,7 @@ bool convert_input_param_to_utf16( _In_ zval* input_param_z, _Inout_ zval* conve #ifndef _WIN32 wchar_size = SystemLocale::ToUtf16Strict( CP_UTF8, reinterpret_cast( buffer ), static_cast( buffer_len ), NULL, 0 ); #else - wchar_size = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, reinterpret_cast( buffer ), static_cast( buffer_len ), NULL, 0 ); + wchar_size = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, reinterpret_cast( buffer ), static_cast( buffer_len ), NULL, 0 ); #endif // !_WIN32 // if there was a problem determining the size of the string, return false @@ -1847,7 +1850,7 @@ bool convert_input_param_to_utf16( _In_ zval* input_param_z, _Inout_ zval* conve #ifndef _WIN32 int r = SystemLocale::ToUtf16Strict( CP_UTF8, reinterpret_cast( buffer ), static_cast( buffer_len ), wbuffer, wchar_size ); #else - int r = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, reinterpret_cast( buffer ), static_cast( buffer_len ), wbuffer, wchar_size ); + int r = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, reinterpret_cast( buffer ), static_cast( buffer_len ), wbuffer, wchar_size ); #endif // !_WIN32 // if there was a problem converting the string, then free the memory and return false if( r == 0 ) { @@ -1871,12 +1874,12 @@ SQLSMALLINT default_c_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, int php_type = Z_TYPE_P( param_z ); switch( php_type ) { - + case IS_NULL: switch( encoding ) { - // The c type is set to match to the corresponding sql_type. For NULL cases, if the server type + // The c type is set to match to the corresponding sql_type. For NULL cases, if the server type // is a binary type, than the server expects the sql_type to be binary type as well, otherwise - // an error stating "Implicit conversion not allowed.." is thrown by the server. + // an error stating "Implicit conversion not allowed.." is thrown by the server. // For all other server types, setting the sql_type to sql_char works fine. case SQLSRV_ENCODING_BINARY: sql_c_type = SQL_C_BINARY; @@ -1891,10 +1894,10 @@ SQLSMALLINT default_c_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, sql_c_type = SQL_C_SLONG; break; case IS_LONG: - //ODBC 64-bit long and integer type are 4 byte values. + //ODBC 64-bit long and integer type are 4 byte values. if ( ( Z_LVAL_P( param_z ) < INT_MIN ) || ( Z_LVAL_P( param_z ) > INT_MAX ) ) { sql_c_type = SQL_C_SBIGINT; - } + } else { sql_c_type = SQL_C_SLONG; } @@ -1916,7 +1919,7 @@ SQLSMALLINT default_c_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, break; default: THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INVALID_PARAMETER_ENCODING, paramno ); - break; + break; } break; // it is assumed that an object is a DateTime since it's the only thing we support. @@ -1929,24 +1932,24 @@ SQLSMALLINT default_c_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, paramno ); break; } - + return sql_c_type; } // given a zval and encoding, determine the appropriate sql type -void default_sql_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_ zval* param_z, _In_ SQLSRV_ENCODING encoding, +void default_sql_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_ zval* param_z, _In_ SQLSRV_ENCODING encoding, _Out_ SQLSMALLINT& sql_type TSRMLS_DC ) { sql_type = SQL_UNKNOWN_TYPE; int php_type = Z_TYPE_P(param_z); switch( php_type ) { - + case IS_NULL: - switch( encoding ) { - // Use the encoding to guess whether the sql_type is binary type or char type. For NULL cases, - // if the server type is a binary type, than the server expects the sql_type to be binary type - // as well, otherwise an error stating "Implicit conversion not allowed.." is thrown by the + switch( encoding ) { + // Use the encoding to guess whether the sql_type is binary type or char type. For NULL cases, + // if the server type is a binary type, than the server expects the sql_type to be binary type + // as well, otherwise an error stating "Implicit conversion not allowed.." is thrown by the // server. For all other server types, setting the sql_type to sql_char works fine. case SQLSRV_ENCODING_BINARY: sql_type = SQL_BINARY; @@ -1961,10 +1964,10 @@ void default_sql_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_ sql_type = SQL_INTEGER; break; case IS_LONG: - //ODBC 64-bit long and integer type are 4 byte values. + //ODBC 64-bit long and integer type are 4 byte values. if ( ( Z_LVAL_P( param_z ) < INT_MIN ) || ( Z_LVAL_P( param_z ) > INT_MAX ) ) { sql_type = SQL_BIGINT; - } + } else { sql_type = SQL_INTEGER; } @@ -2013,7 +2016,7 @@ void default_sql_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_ // given a zval and encoding, determine the appropriate column size, and decimal scale (if appropriate) -void default_sql_size_and_scale( _Inout_ sqlsrv_stmt* stmt, _In_opt_ unsigned int paramno, _In_ zval* param_z, _In_ SQLSRV_ENCODING encoding, +void default_sql_size_and_scale( _Inout_ sqlsrv_stmt* stmt, _In_opt_ unsigned int paramno, _In_ zval* param_z, _In_ SQLSRV_ENCODING encoding, _Out_ SQLULEN& column_size, _Out_ SQLSMALLINT& decimal_digits TSRMLS_DC ) { int php_type = Z_TYPE_P( param_z ); @@ -2021,7 +2024,7 @@ void default_sql_size_and_scale( _Inout_ sqlsrv_stmt* stmt, _In_opt_ unsigned in decimal_digits = 0; switch( php_type ) { - + case IS_NULL: column_size = 1; break; @@ -2075,7 +2078,7 @@ void col_cache_dtor( _Inout_ zval* data_z ) void field_cache_dtor( _Inout_ zval* data_z ) { field_cache* cache = static_cast( Z_PTR_P( data_z )); - if( cache->value ) + if( cache->value ) { sqlsrv_free( cache->value ); } @@ -2091,7 +2094,7 @@ void field_cache_dtor( _Inout_ zval* data_z ) void finalize_output_parameters( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) { - if( Z_ISUNDEF(stmt->output_params) ) + if( Z_ISUNDEF(stmt->output_params) ) return; HashTable* params_ht = Z_ARRVAL( stmt->output_params ); @@ -2141,7 +2144,7 @@ void finalize_output_parameters( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) // For ODBC 11+ see https://msdn.microsoft.com/en-us/library/jj219209.aspx // A length value of SQL_NO_TOTAL for SQLBindParameter indicates that the buffer contains up to - // output_param->original_buffer_len data and is NULL terminated. + // output_param->original_buffer_len data and is NULL terminated. // The IF statement can be true when using connection pooling with unixODBC 2.3.4. if ( str_len == SQL_NO_TOTAL ) { @@ -2157,7 +2160,7 @@ void finalize_output_parameters( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) } else if( output_param->encoding == SQLSRV_ENCODING_BINARY && str_len < output_param->original_buffer_len ) { // ODBC doesn't null terminate binary encodings, but PHP complains if a string isn't null terminated - // so we do that here if the length of the returned data is less than the original allocation. The + // so we do that here if the length of the returned data is less than the original allocation. The // original allocation null terminates the buffer already. str[ str_len ] = '\0'; core::sqlsrv_zval_stringl(value_z, str, str_len); @@ -2216,7 +2219,7 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind SQLLEN field_len_temp = 0; SQLLEN sql_display_size = 0; char* field_value_temp = NULL; - unsigned int intial_field_len = INITIAL_FIELD_STRING_LEN; + unsigned int intial_field_len = INITIAL_FIELD_STRING_LEN; try { @@ -2244,9 +2247,9 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind } if( stmt->conn->ce_option.enabled ) { - // when AE is enabled, increase the intial field len + // when AE is enabled, increase the intial field len intial_field_len = INITIAL_AE_FIELD_STRING_LEN; - } + } col_cache* cached = NULL; if ( NULL != ( cached = static_cast< col_cache* >( zend_hash_index_find_ptr( Z_ARRVAL( stmt->col_cache ), static_cast< zend_ulong >( field_index ))))) { @@ -2267,7 +2270,7 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind // if this is a large type, then read the first few bytes to get the actual length from SQLGetData if( sql_display_size == 0 || sql_display_size == INT_MAX || sql_display_size == INT_MAX >> 1 || sql_display_size == UINT_MAX - 1 ) { - + field_len_temp = intial_field_len; SQLLEN initiallen = field_len_temp + extra; @@ -2294,13 +2297,13 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind stmt->current_results->get_diag_field( 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len TSRMLS_CC ); - // with Linux connection pooling may not get a truncated warning back but the actual field_len_temp + // with Linux connection pooling may not get a truncated warning back but the actual field_len_temp // can be greater than the initallen value. #ifndef _WIN32 if( is_truncated_warning( state ) || initiallen < field_len_temp) { #else if( is_truncated_warning( state ) ) { -#endif // !_WIN32 +#endif // !_WIN32 SQLLEN dummy_field_len = 0; @@ -2313,7 +2316,7 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind do { SQLLEN initial_field_len = field_len_temp; - // Double the size. + // Double the size. field_len_temp *= 2; field_value_temp = static_cast( sqlsrv_realloc( field_value_temp, field_len_temp + extra + 1 )); @@ -2402,7 +2405,7 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind throw core::CoreException(); } } - } // if ( sql_display_size == 0 || sql_display_size == LONG_MAX .. ) + } // if ( sql_display_size == 0 || sql_display_size == LONG_MAX .. ) else if( sql_display_size >= 1 && sql_display_size <= SQL_SERVER_MAX_FIELD_SIZE ) { @@ -2446,7 +2449,7 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind throw core::CoreException(); } } - } // else if( sql_display_size >= 1 && sql_display_size <= SQL_SERVER_MAX_FIELD_SIZE ) + } // else if( sql_display_size >= 1 && sql_display_size <= SQL_SERVER_MAX_FIELD_SIZE ) else { @@ -2465,12 +2468,12 @@ field_value = field_value_temp; // with unixODBC connection pooling sometimes field_len_temp can be SQL_NO_DATA. // In that cause do not set null terminator and set length to 0. if ( field_len_temp > 0 ) - { + { field_value_temp[field_len_temp] = '\0'; } else { - *field_len = 0; + *field_len = 0; } } @@ -2544,7 +2547,7 @@ bool is_valid_sqlsrv_phptype( _In_ sqlsrv_phptype type ) case SQLSRV_PHPTYPE_STRING: case SQLSRV_PHPTYPE_STREAM: { - if( type.typeinfo.encoding == SQLSRV_ENCODING_BINARY || type.typeinfo.encoding == SQLSRV_ENCODING_CHAR + if( type.typeinfo.encoding == SQLSRV_ENCODING_BINARY || type.typeinfo.encoding == SQLSRV_ENCODING_CHAR || type.typeinfo.encoding == CP_UTF8 || type.typeinfo.encoding == SQLSRV_ENCODING_DEFAULT ) { return true; } @@ -2561,8 +2564,8 @@ bool is_valid_sqlsrv_phptype( _In_ sqlsrv_phptype type ) // string is place in the stmt->output_params. param_z is modified to hold the new buffer, and buffer, buffer_len and // stmt->param_ind_ptrs are modified to hold the correct values for SQLBindParameter -void resize_output_buffer_if_necessary( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval* param_z, _In_ SQLULEN paramno, SQLSRV_ENCODING encoding, - _In_ SQLSMALLINT c_type, _In_ SQLSMALLINT sql_type, _In_ SQLULEN column_size, _In_ SQLSMALLINT decimal_digits, +void resize_output_buffer_if_necessary( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval* param_z, _In_ SQLULEN paramno, SQLSRV_ENCODING encoding, + _In_ SQLSMALLINT c_type, _In_ SQLSMALLINT sql_type, _In_ SQLULEN column_size, _In_ SQLSMALLINT decimal_digits, _Out_writes_(buffer_len) SQLPOINTER& buffer, _Out_ SQLLEN& buffer_len TSRMLS_DC ) { SQLSRV_ASSERT( column_size != SQLSRV_UNKNOWN_SIZE, "column size should be set to a known value." ); @@ -2601,17 +2604,17 @@ void resize_output_buffer_if_necessary( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval* // if the current buffer size is smaller than the necessary size, resize the buffer and set the zval to the new // length. if( buffer_len < expected_len ) { - SQLSRV_ASSERT( expected_len >= expected_len - buffer_null_extra, + SQLSRV_ASSERT( expected_len >= expected_len - buffer_null_extra, "Integer overflow/underflow caused a corrupt field length." ); // allocate enough space to ALWAYS include the NULL regardless of the type being retrieved since - // we set the last byte(s) to be NULL to avoid the debug build warning from the Zend engine about + // we set the last byte(s) to be NULL to avoid the debug build warning from the Zend engine about // not having a NULL terminator on a string. zend_string* param_z_string = zend_string_realloc( Z_STR_P(param_z), expected_len, 0 ); // A zval string len doesn't include the null. This calculates the length it should be // regardless of whether the ODBC type contains the NULL or not. - + // null terminate the string to avoid a warning in debug PHP builds ZSTR_VAL(param_z_string)[without_null_len] = '\0'; ZVAL_NEW_STR(param_z, param_z_string); @@ -2622,12 +2625,12 @@ void resize_output_buffer_if_necessary( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval* // Zend string length doesn't include the null terminator ZSTR_LEN(Z_STR_P(param_z)) -= elem_size; - } + } buffer = Z_STRVAL_P(param_z); // The StrLen_Ind_Ptr parameter of SQLBindParameter should contain the length of the data to send, which - // may be less than the size of the buffer since the output may be more than the input. If it is greater, + // may be less than the size of the buffer since the output may be more than the input. If it is greater, // than the error 22001 is returned by ODBC. if( stmt->param_ind_ptrs[ paramno ] > buffer_len - (elem_size - buffer_null_extra)) { stmt->param_ind_ptrs[ paramno ] = buffer_len - (elem_size - buffer_null_extra); @@ -2667,12 +2670,12 @@ void adjustInputPrecision( _Inout_ zval* param_z, _In_ SQLSMALLINT decimal_digit return; } std::vector digits; - char* ptr = ZSTR_VAL( Z_STR_P( param_z )); + unsigned char* ptr = reinterpret_cast(ZSTR_VAL( Z_STR_P( param_z ))); bool isNeg = false; bool isScientificNot = false; char scientificChar = ' '; short scientificExp = 0; - if( strchr( ptr, 'e' ) || strchr( ptr, 'E' )){ + if( strchr( reinterpret_cast( ptr ), 'e' ) || strchr( reinterpret_cast( ptr ), 'E' )){ isScientificNot = true; } // parse digits in param_z into the vector digits @@ -2751,7 +2754,7 @@ void adjustInputPrecision( _Inout_ zval* param_z, _In_ SQLSMALLINT decimal_digit // check if the last digit to be popped is greater than 5, if so, the digit before it needs to round up carryOver = digits.back() >= 5; digits.pop_back(); - backInd = digits.size() - 1; + backInd = static_cast(digits.size() - 1); // round up from the end until no more carry over while( carryOver && backInd >= 0 ){ if( digits.at( backInd ) != 9 ){ @@ -2768,7 +2771,7 @@ void adjustInputPrecision( _Inout_ zval* param_z, _In_ SQLSMALLINT decimal_digit if( isNeg ){ oss << '-'; } - // insert 1 if carry over persist all the way to the beginning of the number + // insert 1 if carry over persist all the way to the beginning of the number if( carryOver && backInd == -1 ){ oss << 1; } diff --git a/source/shared/core_stream.cpp b/source/shared/core_stream.cpp index 72461df3..5309f004 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/core_util.cpp b/source/shared/core_util.cpp index 8453a6b8..c537f766 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -263,7 +263,7 @@ bool core_sqlsrv_get_odbc_error( _Inout_ sqlsrv_context& ctx, _In_ int record_nu } // We need to calculate number of characters - SQLLEN wsqlstate_len = sizeof( wsqlstate ) / sizeof( SQLWCHAR ); + SQLINTEGER wsqlstate_len = sizeof( wsqlstate ) / sizeof( SQLWCHAR ); SQLLEN sqlstate_len = 0; convert_string_from_utf16(enc, wsqlstate, wsqlstate_len, (char**)&error->sqlstate, sqlstate_len); diff --git a/source/shared/globalization.h b/source/shared/globalization.h index d5fb5723..486a381d 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 da8e5701..39e615f4 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 cefa45cb..7f5a974a 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 9f8d0740..6c88f0e5 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 b2020f54..136c5a51 100644 --- a/source/shared/localization.hpp +++ b/source/shared/localization.hpp @@ -3,7 +3,7 @@ // // Contents: Contains portable classes for localization // -// Microsoft Drivers 5.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 5ecc8c2a..eebef4fd 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 f4efbd29..d6b74a5b 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 fbfb0629..7be9ba68 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 461cfcef..6daf7fcd 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 cb4b28dd..c8c7b127 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -27,15 +27,15 @@ // Increase Minor with backward compatible new functionalities and API changes. // Increase Patch for backward compatible fixes. #define SQLVERSION_MAJOR 5 -#define SQLVERSION_MINOR 1 -#define SQLVERSION_PATCH 2 +#define SQLVERSION_MINOR 2 +#define SQLVERSION_PATCH 0 #define SQLVERSION_BUILD 0 // Semantic versioning pre-release // for stable releases should be empty // "-RC" for release candidates // "-preview" for ETP -#define SEMVER_PRERELEASE "preview" +#define SEMVER_PRERELEASE "RC" // Semantic versioning build metadata, build meta data is not counted in precedence order. #define SEMVER_BUILDMETA diff --git a/source/shared/xplat.h b/source/shared/xplat.h index 8cfcdd4d..f768f112 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 a720492b..68595afb 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 2ba22237..29296069 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 8e7efc63..3b1cbc68 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/sqlsrv/config.w32 b/source/sqlsrv/config.w32 index 4a17c934..727b17e7 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 5a2870ca..f993fb2e 100644 --- a/source/sqlsrv/conn.cpp +++ b/source/sqlsrv/conn.cpp @@ -3,7 +3,7 @@ // // Contents: Routines that use connection handles // -// Microsoft Drivers 5.1 for PHP for SQL Server +// Microsoft Drivers 5.2 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/sqlsrv/init.cpp b/source/sqlsrv/init.cpp index 8055934d..7385dc6b 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 baa0b2c1..17175730 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -157,7 +157,7 @@ void __cdecl sqlsrv_conn_dtor( _Inout_ zend_resource *rsrc TSRMLS_DC ); // holds the field names for reuse by sqlsrv_fetch_array/object as keys struct sqlsrv_fetch_field_name { char* name; - unsigned int len; + SQLLEN len; }; struct stmt_option_ss_scrollable : public stmt_option_functor { diff --git a/source/sqlsrv/stmt.cpp b/source/sqlsrv/stmt.cpp index a0f88e94..96aeae8a 100644 --- a/source/sqlsrv/stmt.cpp +++ b/source/sqlsrv/stmt.cpp @@ -3,7 +3,7 @@ // // Contents: Routines that use statement handles // -// Microsoft Drivers 5.1 for PHP for SQL Server +// Microsoft Drivers 5.2 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -1229,7 +1229,7 @@ void bind_params( _Inout_ ss_sqlsrv_stmt* stmt TSRMLS_DC ) } // bind the parameter SQLSRV_ASSERT( value_z != NULL, "bind_params: value_z is null." ); - core_sqlsrv_bind_param( stmt, index, direction, value_z, php_out_type, encoding, sql_type, column_size, + core_sqlsrv_bind_param( stmt, static_cast( index ), direction, value_z, php_out_type, encoding, sql_type, column_size, decimal_digits TSRMLS_CC ); } ZEND_HASH_FOREACH_END(); @@ -1863,6 +1863,7 @@ void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array, zval* temp = NULL; HashTable* param_ht = Z_ARRVAL_P( param_array ); sqlsrv_sqltype sqlsrv_sql_type; + HashPosition pos; try { @@ -1873,28 +1874,28 @@ void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array, encoding = SQLSRV_ENCODING_INVALID; // handle the array parameters that contain the value/var, direction, php_type, sql_type - zend_hash_internal_pointer_reset( param_ht ); - if( zend_hash_has_more_elements( param_ht ) == FAILURE || - (var_or_val = zend_hash_get_current_data(param_ht)) == NULL) { + zend_hash_internal_pointer_reset_ex( param_ht, &pos ); + if( zend_hash_has_more_elements_ex( param_ht, &pos ) == FAILURE || + (var_or_val = zend_hash_get_current_data_ex(param_ht, &pos)) == NULL) { THROW_SS_ERROR( stmt, SS_SQLSRV_ERROR_VAR_REQUIRED, index + 1 ); } // if the direction is included, then use what they gave, otherwise INPUT is assumed - if (zend_hash_move_forward(param_ht) == SUCCESS && (temp = zend_hash_get_current_data(param_ht)) != NULL && + if ( zend_hash_move_forward_ex( param_ht, &pos ) == SUCCESS && ( temp = zend_hash_get_current_data_ex( param_ht, &pos )) != NULL && Z_TYPE_P( temp ) != IS_NULL ) { CHECK_CUSTOM_ERROR( Z_TYPE_P( temp ) != IS_LONG, stmt, SS_SQLSRV_ERROR_INVALID_PARAMETER_DIRECTION, index + 1 ) { throw ss::SSException(); } - direction = static_cast(Z_LVAL_P( temp )); + direction = static_cast( Z_LVAL_P( temp )); CHECK_CUSTOM_ERROR( direction != SQL_PARAM_INPUT && direction != SQL_PARAM_OUTPUT && direction != SQL_PARAM_INPUT_OUTPUT, stmt, SS_SQLSRV_ERROR_INVALID_PARAMETER_DIRECTION, index + 1 ) { throw ss::SSException(); } - CHECK_CUSTOM_ERROR(!Z_ISREF_P(var_or_val) && (direction == SQL_PARAM_OUTPUT || direction == SQL_PARAM_INPUT_OUTPUT), stmt, SS_SQLSRV_ERROR_PARAM_VAR_NOT_REF, index + 1) { + CHECK_CUSTOM_ERROR( !Z_ISREF_P( var_or_val ) && ( direction == SQL_PARAM_OUTPUT || direction == SQL_PARAM_INPUT_OUTPUT ), stmt, SS_SQLSRV_ERROR_PARAM_VAR_NOT_REF, index + 1 ) { throw ss::SSException(); } @@ -1904,7 +1905,7 @@ void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array, } // extract the php type and encoding from the 3rd parameter - if (zend_hash_move_forward(param_ht) == SUCCESS && (temp = zend_hash_get_current_data(param_ht)) != NULL && + if ( zend_hash_move_forward_ex( param_ht, &pos ) == SUCCESS && ( temp = zend_hash_get_current_data_ex( param_ht, &pos )) != NULL && Z_TYPE_P( temp ) != IS_NULL ) { php_type_param_was_null = false; @@ -1924,7 +1925,7 @@ void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array, } php_out_type = static_cast( sqlsrv_phptype.typeinfo.type ); - encoding = (SQLSRV_ENCODING) sqlsrv_phptype.typeinfo.encoding; + encoding = ( SQLSRV_ENCODING ) sqlsrv_phptype.typeinfo.encoding; // if the call has a SQLSRV_PHPTYPE_STRING/STREAM('default'), then the stream is in the encoding established // by the connection if( encoding == SQLSRV_ENCODING_DEFAULT ) { @@ -1936,11 +1937,11 @@ void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array, php_type_param_was_null = true; - if (Z_ISREF_P(var_or_val)){ - php_out_type = zend_to_sqlsrv_phptype[Z_TYPE_P(Z_REFVAL_P(var_or_val))]; + if ( Z_ISREF_P( var_or_val )){ + php_out_type = zend_to_sqlsrv_phptype[Z_TYPE_P( Z_REFVAL_P( var_or_val ))]; } else{ - php_out_type = zend_to_sqlsrv_phptype[Z_TYPE_P(var_or_val)]; + php_out_type = zend_to_sqlsrv_phptype[Z_TYPE_P( var_or_val )]; } encoding = stmt->encoding(); if( encoding == SQLSRV_ENCODING_DEFAULT ) { @@ -1949,7 +1950,7 @@ void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array, } // get the server type, column size/precision and the decimal digits if provided - if (zend_hash_move_forward(param_ht) == SUCCESS && (temp = zend_hash_get_current_data(param_ht)) != NULL && + if ( zend_hash_move_forward_ex( param_ht, &pos ) == SUCCESS && ( temp = zend_hash_get_current_data_ex( param_ht, &pos )) != NULL && Z_TYPE_P( temp ) != IS_NULL ) { sql_type_param_was_null = false; @@ -1968,7 +1969,7 @@ void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array, throw ss::SSException(); } - bool size_okay = determine_column_size_or_precision(stmt, sqlsrv_sql_type, &column_size, &decimal_digits); + bool size_okay = determine_column_size_or_precision( stmt, sqlsrv_sql_type, &column_size, &decimal_digits ); CHECK_CUSTOM_ERROR( !size_okay, stmt, SS_SQLSRV_ERROR_INVALID_PARAMETER_PRECISION, index + 1 ) { diff --git a/source/sqlsrv/template.rc b/source/sqlsrv/template.rc index 15fc2e66..446f50d8 100644 --- a/source/sqlsrv/template.rc +++ b/source/sqlsrv/template.rc @@ -3,7 +3,7 @@ // // Contents: Version resource // -// Microsoft Drivers 5.1 for PHP for SQL Server +// Microsoft Drivers 5.2 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 264139ea..0b734254 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.1 for PHP for SQL Server +// Microsoft Drivers 5.2 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -412,6 +412,10 @@ ss_error SS_ERRORS[] = { SQLSRV_ERROR_OUTPUT_PARAM_TYPES_NOT_SUPPORTED, { IMSSP, (SQLCHAR*) "Stored Procedures do not support text, ntext or image as OUTPUT parameters.", -108, false } }, + { + SQLSRV_ERROR_ENCRYPTED_STREAM_FETCH, + { IMSSP, (SQLCHAR*) "Connection with Column Encryption enabled does not support fetching stream. Please fetch the data as a string.", -109, false } + }, // terminate the list of errors/warnings { UINT_MAX, {} } diff --git a/test/functional/pdo_sqlsrv/MsCommon_mid-refactor.inc b/test/functional/pdo_sqlsrv/MsCommon_mid-refactor.inc index ca99ae8b..7384f2a5 100644 --- a/test/functional/pdo_sqlsrv/MsCommon_mid-refactor.inc +++ b/test/functional/pdo_sqlsrv/MsCommon_mid-refactor.inc @@ -13,6 +13,10 @@ // 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"]; @@ -81,8 +85,9 @@ function getDSN($sqlsrvserver, $database, $keywords = '', $disableCE = false) $dsn .= "ColumnEncryption=Enabled;"; } if ($keystore == "ksp" && !$disableCE) { - require('AE_Ksp.inc'); $ksp_path = getKSPPath(); + $ksp_name = KSP_NAME; + $encrypt_key = ENCRYPT_KEY; $dsn .= "CEKeystoreProvider=$ksp_path;CEKeystoreName=$ksp_name;CEKeystoreEncryptKey=$encrypt_key;"; } if ($keywords) { @@ -118,6 +123,27 @@ function getCekName() return $cekName; } +/** + * @return the path to the KSP dll/so file + */ +function getKSPpath() +{ + $name = 'myKSP'; + + $dir_name = realpath(dirname(__FILE__)); + $ksp = $dir_name . DIRECTORY_SEPARATOR . $name; + if ( strtoupper( substr( php_uname( 's' ), 0, 3 ) ) == 'WIN' ) { + $arch = 'x64'; + if ( PHP_INT_SIZE == 4 ) // running 32 bit + $arch = ''; + $ksp .= $arch . '.dll'; + } + else + $ksp .= '.so'; + + return $ksp; +} + /** * class for encapsulating column metadata needed for creating a table @@ -127,10 +153,10 @@ class ColumnMeta public $dataType; //a string that includes the size of the type if necessary (e.g., decimal(10,5)) public $colName; //column name public $options; //a string that is null by default (e.g. NOT NULL Identity (1,1) ) - public $encType; //randomized or deterministic; default is deterministic - public $forceEncrypt; //force encryption on a datatype no supported by Column Encrypton + public $encType; //randomized, deterministic, or none; default is null + public $forceEncrypt; //force encryption on a datatype not supported by Column Encrypton - public function __construct($dataType, $colName = null, $options = null, $encType = "deterministic", $forceEncrypt = false) + public function __construct($dataType, $colName = null, $options = null, $encType = null, $forceEncrypt = false) { if (is_null($colName)) { $this->colName = getDefaultColName($dataType); @@ -139,7 +165,15 @@ class ColumnMeta } $this->dataType = $dataType; $this->options = $options; - $this->encType = $encType; + if (is_null($encType)) { + if (isColEncrypted()) { + $this->encType = "deterministic"; + } else { + $this->encType = "none"; + } + } else { + $this->encType = $encType; + } $this->forceEncrypt = $forceEncrypt; } /** @@ -147,11 +181,11 @@ class ColumnMeta */ public function getColDef() { - //return getColDef($this->colName, $this->dataType, $this->options, $this->encType); $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 (isColEncrypted() && $this->isEncryptableType() && stripos($this->options, "identity") === false) { + if (isColEncrypted() && ($this->encType == "deterministic" || $this->encType == "randomized") && $this->isEncryptableType() + && stripos($this->options, "identity") === false && stripos($this->options, "rowguidcol") === false) { $cekName = getCekName(); if (stripos($this->dataType, "char") !== false) { $append .= "COLLATE Latin1_General_BIN2 "; @@ -168,7 +202,7 @@ class ColumnMeta */ public function isEncryptableType() { - $unsupportedTypes = array("money", "smallmoney", "image", "ntext", "text", "xml", "sql_variant"); + $unsupportedTypes = array("money", "smallmoney", "image", "ntext", "text", "xml", "sql_variant", "timestamp", "geography", "geometry", "hierarchyid"); if (!$this->forceEncrypt && in_array(strtolower($this->dataType), $unsupportedTypes)) { return false; } else { @@ -523,6 +557,13 @@ function isColEncrypted() } } + +function isAEConnected() +{ + require('MsSetup.inc'); + return $keystore != "none"; +} + function teardown() { // TBD diff --git a/test/functional/pdo_sqlsrv/PDO100_InsertNulls.phpt b/test/functional/pdo_sqlsrv/PDO100_InsertNulls.phpt index 0f3b1a52..97d712e7 100644 --- a/test/functional/pdo_sqlsrv/PDO100_InsertNulls.phpt +++ b/test/functional/pdo_sqlsrv/PDO100_InsertNulls.phpt @@ -5,74 +5,82 @@ Test inserting nulls into nullable columns --ENV-- PHPT_EXEC=true --SKIPIF-- - + --FILE-- "int", + "c2_tinyint" => "tinyint", + "c3_smallint" => "smallint", + "c4_bigint" => "bigint", + "c5_bit" => "bit", + "c6_float" => "float", + "c7_real" => "real", + "c8_decimal" => "decimal(28,4)", + "c9_numeric" => "numeric(32,4)", + "c10_money" => "money", + "c11_smallmoney" => "smallmoney", + "c12_char" => "char(512)", + "c13_varchar" => "varchar(512)", + "c14_varchar_max" => "varchar(max)", + "c15_nchar" => "nchar(512)", + "c16_nvarchar" => "nvarchar(512)", + "c17_nvarchar_max" => "nvarchar(max)", + "c18_text" => "text", + "c19_ntext" => "ntext", + "c20_binary" => "binary(512)", + "c21_varbinary" => "varbinary(512)", + "c22_varbinary_max" => "varbinary(max)", + "c23_image" => "image", + "c24_uniqueidentifier" => "uniqueidentifier", + "c25_datetime" => "datetime", + "c26_smalldatetime" => "smalldatetime", + "c27_timestamp" => "timestamp", + "c28_xml" => "xml"); + createTable($conn, $tableName, $dataTypes); - $conn = Connect(); + $stmt = $conn->query("SELECT [TABLE_NAME],[COLUMN_NAME],[IS_NULLABLE] FROM [INFORMATION_SCHEMA].[COLUMNS] WHERE [TABLE_NAME] = '$tableName'"); - DropTable($conn, $tableName); - - CreateTable($conn, $tableName); - - $stmt = $conn->query(<<fetch(PDO::FETCH_ASSOC)) - { - Trace($row['COLUMN_NAME'] . ": " . $row['IS_NULLABLE'] . "\n"); - + while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { $stmt2 = $conn->prepare("INSERT INTO [$tableName] ([" . $row['COLUMN_NAME'] . "]) VALUES (:p1)"); - if (strpos($row['COLUMN_NAME'], "timestamp") !== false) continue; + if (strpos($row['COLUMN_NAME'], "timestamp") !== false) { + continue; + } - if (($row['IS_NULLABLE'] == 'YES') && (strpos($row['COLUMN_NAME'], "binary") !== false)) - { - if ($bindType == PDO::PARAM_LOB) - { + if (($row['IS_NULLABLE'] == 'YES') && (strpos($row['COLUMN_NAME'], "binary") !== false)) { + if ($bindType == PDO::PARAM_LOB) { $stmt2->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_BINARY); $stmt2->bindValue(":p1", null, $bindType); - } - else if ($bindType == PDO::PARAM_STR) - { + } elseif ($bindType == PDO::PARAM_STR) { $stmt2->bindParam(":p1", $outvar, $bindType, null, PDO::SQLSRV_ENCODING_BINARY); } - } - else - { + } else { $stmt2->bindParam(":p1", $outvar); } $stmt2->execute(); - if ($stmt2->errorCode() !== '00000') - { + if ($stmt2->errorCode() !== '00000') { print_r($stmt2->errorInfo()); - $failed = true; + $failed = true; } } - DropTable($conn, $tableName); - + dropTable($conn, $tableName); return($failed); } @@ -82,32 +90,19 @@ SQL // Repro // //-------------------------------------------------------------------- -function Repro() -{ - $failed = null; - - $testName = "PDO - Insert Nulls"; - - StartTest($testName); - - try - { - $failed |= InsertNullsTest(PDO::PARAM_LOB); - $failed |= InsertNullsTest(PDO::PARAM_STR); - } - catch (Exception $e) - { - echo $e->getMessage(); - } - - if ($failed) - FatalError("Possible Regression: Could not insert NULL"); - - EndTest($testName); +try { + $failed = false; + $failed |= insertNullsTest(PDO::PARAM_LOB); + $failed |= insertNullsTest(PDO::PARAM_STR); +} catch (Exception $e) { + echo $e->getMessage(); +} +if ($failed) { + fatalError("Possible Regression: Could not insert NULL"); +} else { + echo "Test 'PDO - Insert Nulls' completed successfully.\n"; } - -Repro(); ?> --EXPECT-- -Test "PDO - Insert Nulls" completed successfully. +Test 'PDO - Insert Nulls' completed successfully. diff --git a/test/functional/pdo_sqlsrv/PDO102_MaxOutputParams.phpt b/test/functional/pdo_sqlsrv/PDO102_MaxOutputParams.phpt index a80d84d0..721c66b9 100644 --- a/test/functional/pdo_sqlsrv/PDO102_MaxOutputParams.phpt +++ b/test/functional/pdo_sqlsrv/PDO102_MaxOutputParams.phpt @@ -5,51 +5,34 @@ Fetch data as VARCHAR(MAX) --ENV-- PHPT_EXEC=true --SKIPIF-- - + --FILE-- query("CREATE PROC [$procName] (@OUT varchar(80) output) AS BEGIN + SET NOCOUNT ON; select @OUT = '$expected'; return(0) END"); $sql = "execute EXEC_TEST ?"; - $stmt = $conn->prepare($sql); - - if ($length) - { - $stmt->bindParam(1, $outstr, PDO::PARAM_STR, 10); - } - else - { - $stmt->bindParam(1, $outstr, PDO::PARAM_STR, 3); - } - + $stmt->bindParam(1, $outstr, PDO::PARAM_STR, $length); $stmt->execute(); echo "Expected: $expected Received: $outstr\n"; - if ($outstr !== $expected) - { + $failed = false; + if ($outstr !== $expected) { print_r($stmt->errorInfo()); - return(-1); + $failed = true; } - - return(0); + return $failed; } @@ -57,26 +40,15 @@ function MaxOutputParamsTest($expected, $length) // Repro // //-------------------------------------------------------------------- -function Repro() -{ - $failed = null; +$failed = false; - $testName = "PDO - Max Output Params Test"; +$failed |= maxOutputParamsTest("abc", 3); +$failed |= maxOutputParamsTest("abc", 10); - StartTest($testName); - - $failed |= MaxOutputParamsTest("abc", null); - $failed |= MaxOutputParamsTest("abc", -1); - - if ($failed) - FatalError("Possible Regression: Value returned as VARCHAR(MAX) truncated"); - - EndTest($testName); +if ($failed) { + fatalError("Possible Regression: Value returned as VARCHAR(MAX) truncated"); } - -Repro(); ?> --EXPECT-- Expected: abc Received: abc Expected: abc Received: abc -Test "PDO - Max Output Params Test" completed successfully. diff --git a/test/functional/pdo_sqlsrv/PDO32_StmtInterface.phpt b/test/functional/pdo_sqlsrv/PDO32_StmtInterface.phpt index ac42caa6..06ca54d1 100644 --- a/test/functional/pdo_sqlsrv/PDO32_StmtInterface.phpt +++ b/test/functional/pdo_sqlsrv/PDO32_StmtInterface.phpt @@ -5,30 +5,26 @@ Verifies the compliance of the PDOStatement API Interface. --ENV-- PHPT_EXEC=true --SKIPIF-- - + --FILE-- "varchar(10)")); + $stmt1 = $conn1->query("SELECT * FROM [$tableName]"); - $testName = "PDOStatement - Interface"; - StartTest($testName); - - $conn1 = Connect(); - CreateTableEx($conn1, $tableName, "id int NOT NULL PRIMARY KEY, val VARCHAR(10)", null); - $stmt1 = ExecuteQuery($conn1, "SELECT * FROM [$tableName]"); - - CheckInterface($stmt1); - $stmt1 = null; - $conn1 = null; - - EndTest($testName); + checkInterface($stmt1); + unset($stmt1); + unset($conn1); + echo "Test successfully completed\n"; +} catch (Exception $e) { + echo $e->getMessage(); } -function CheckInterface($stmt) +function checkInterface($stmt) { $expected = array( 'errorCode' => true, @@ -55,46 +51,21 @@ function CheckInterface($stmt) ); $classname = get_class($stmt); $methods = get_class_methods($classname); - foreach ($methods as $k => $method) - { - if (isset($expected[$method])) - { + foreach ($methods as $k => $method) { + if (isset($expected[$method])) { unset($expected[$method]); unset($methods[$k]); } } - if (!empty($expected)) - { + if (!empty($expected)) { printf("Dumping missing class methods\n"); var_dump($expected); } - if (!empty($methods)) - { + if (!empty($methods)) { printf("Found more methods than expected, dumping list\n"); var_dump($methods); } } - - -//-------------------------------------------------------------------- -// Repro -// -//-------------------------------------------------------------------- -function Repro() -{ - - try - { - StmtInfo(); - } - catch (Exception $e) - { - echo $e->getMessage(); - } -} - -Repro(); - ?> --EXPECT-- -Test "PDOStatement - Interface" completed successfully. \ No newline at end of file +Test successfully completed diff --git a/test/functional/pdo_sqlsrv/PDO38_FetchBound.phpt b/test/functional/pdo_sqlsrv/PDO38_FetchBound.phpt index 8f6c79d8..e5366c35 100644 --- a/test/functional/pdo_sqlsrv/PDO38_FetchBound.phpt +++ b/test/functional/pdo_sqlsrv/PDO38_FetchBound.phpt @@ -5,70 +5,61 @@ Verification for "PDOStatenent::fetch(PDO::FETCH_BOUND)". --ENV-- PHPT_EXEC=true --SKIPIF-- - + --FILE-- "varchar(10)", "val2" => "varchar(16)")); + $data = array(array('10', 'Abc', 'zxy'), + array('20', 'Def', 'wvu'), + array('30', 'Ghi', 'tsr'), + array('40', 'Jkl', 'qpo'), + array('50', 'Mno', 'nml'), + array('60', 'Pqr', 'kji')); // Insert using question mark placeholders - $stmt1 = PrepareQuery($conn1, "INSERT INTO [$tableName] VALUES(?, ?, ?)"); - foreach ($data as $row) - { + $stmt1 = $conn1->prepare("INSERT INTO [$tableName] VALUES(?, ?, ?)"); + foreach ($data as $row) { $stmt1->execute($row); } unset($stmt1); // Count inserted rows - $stmt2 = PrepareQuery($conn1, "SELECT COUNT(id) FROM [$tableName]"); + $stmt2 = $conn1->prepare("SELECT COUNT(id) FROM [$tableName]"); $stmt2->execute(); $num = $stmt2->fetchColumn(); - echo 'There are ' . $num . " rows in the table.\n"; + echo "There are $num rows in the table.\n"; $stmt2->closeCursor(); // Insert using named parameters - $stmt1 = PrepareQuery($conn1, "INSERT INTO [$tableName] VALUES(:first, :second, :third)"); - foreach ($data as $row) - { + $stmt1 = $conn1->prepare("INSERT INTO [$tableName] VALUES(:first, :second, :third)"); + foreach ($data as $row) { $stmt1->execute(array(':first'=>($row[0] + 5), ':second'=>$row[1], ':third'=>$row[2])); } unset($stmt1); $stmt2->execute(); $num = $stmt2->fetchColumn(); - echo 'There are ' . $num . " rows in the table.\n"; + echo "There are $num rows in the table.\n"; - $dataCols = "idx, txt"; - CreateTableEx($conn1, $tableName, "idx int NOT NULL PRIMARY KEY, txt VARCHAR(20)", null); - InsertRowEx($conn1, $tableName, $dataCols, "0, 'String0'", null); - InsertRowEx($conn1, $tableName, $dataCols, "1, 'String1'", null); - InsertRowEx($conn1, $tableName, $dataCols, "2, 'String2'", null); + createTable($conn1, $tableName, array(new ColumnMeta("int", "idx", "NOT NULL PRIMARY KEY", "none"), "txt" => "varchar(20)")); + insertRow($conn1, $tableName, array("idx" => 0, "txt" => 'String0')); + insertRow($conn1, $tableName, array("idx" => 1, "txt" => 'String1')); + insertRow($conn1, $tableName, array("idx" => 2, "txt" => 'String2')); // Testing with prepared query - $stmt1 = PrepareQuery($conn1, "SELECT COUNT(idx) FROM [$tableName]"); - + $stmt1 = $conn1->prepare("SELECT COUNT(idx) FROM [$tableName]"); $stmt1->execute(); var_dump($stmt1->fetchColumn()); unset($stmt1); - $stmt1 = PrepareQuery($conn1, "SELECT idx, txt FROM [$tableName] ORDER BY idx"); + $stmt1 = $conn1->prepare("SELECT idx, txt FROM [$tableName] ORDER BY idx"); $stmt1->execute(); $data = $stmt1->fetchAll(PDO::FETCH_COLUMN|PDO::FETCH_UNIQUE); var_dump($data); @@ -78,100 +69,72 @@ function Fetch() $stmt1->bindColumn('idx', $idx); $stmt1->bindColumn('txt', $txt); $stmt1->execute(); - while ($stmt1->fetch(PDO::FETCH_BOUND)) - { + while ($stmt1->fetch(PDO::FETCH_BOUND)) { var_dump(array($idx=>$txt)); } echo "===ALONE===\n"; - $stmt2 = PrepareQuery($conn1, "SELECT txt FROM [$tableName] WHERE idx=:inp"); + $stmt2 = $conn1->prepare("SELECT txt FROM [$tableName] WHERE idx=:inp"); $stmt2->bindParam(':inp', $idx); // by foreign name - $stmt3 = PrepareQuery($conn1, "SELECT idx FROM [$tableName] WHERE txt=:txt"); + $stmt3 = $conn1->prepare("SELECT idx FROM [$tableName] WHERE txt=:txt"); $stmt3->bindParam(':txt', $txt); // using same name - foreach($data as $idx => $txt) - { + foreach ($data as $idx => $txt) { var_dump(array($idx=>$txt)); var_dump($stmt2->execute()); - if ($idx == 0) - { // bindColumn()s after execute() has been called at least once - $stmt2->bindColumn('txt', $col1); + if ($idx == 0) { // bindColumn()s after execute() has been called at least once + $stmt2->bindColumn('txt', $col); } var_dump($stmt2->fetch(PDO::FETCH_BOUND)); $stmt2->closeCursor(); var_dump($stmt3->execute()); - if ($idx == 0) - { // bindColumn()s after execute() has been called at least once - $stmt3->bindColumn('idx', $col2); + if ($idx == 0) { // bindColumn()s after execute() has been called at least once + $stmt3->bindColumn('idx', $idxCol); } var_dump($stmt3->fetch(PDO::FETCH_BOUND)); $stmt3->closeCursor(); - var_dump(array($col2=>$col1)); + var_dump(array($idxCol=>$col)); } echo "===REBIND/SAME===\n"; - $stmt3->bindColumn('idx', $col1); - foreach($data as $idx => $txt) - { + $stmt3->bindColumn('idx', $col); + foreach ($data as $idx => $txt) { var_dump(array($idx=>$txt)); var_dump($stmt2->execute()); var_dump($stmt2->fetch(PDO::FETCH_BOUND)); $stmt2->closeCursor(); - var_dump($col1); + var_dump($col); var_dump($stmt3->execute()); var_dump($stmt3->fetch(PDO::FETCH_BOUND)); $stmt3->closeCursor(); - var_dump($col1); + var_dump($col); } echo "===REBIND/CONFLICT===\n"; - $stmt1->bindColumn('idx', $col1); - $stmt1->bindColumn('txt', $col1); + $stmt1->bindColumn('idx', $col); + $stmt1->bindColumn('txt', $col); $stmt1->execute(); - while($stmt1->fetch(PDO::FETCH_BOUND)) - { - var_dump($col1); + while ($stmt1->fetch(PDO::FETCH_BOUND)) { + var_dump($col); } - // Cleanup - DropTable($conn1, $tableName); - $stmt1 = null; - $stmt2 = null; - $stmt3 = null; - $conn1 = null; - - EndTest($testName); + dropTable($conn1, $tableName); + unset($stmt1); + unset($stmt2); + unset($stmt3); + unset($conn1); +} catch (Exception $e) { + echo $e->getMessage(); } - - -//-------------------------------------------------------------------- -// Repro -// -//-------------------------------------------------------------------- -function Repro() -{ - - try - { - Fetch(); - } - catch (Exception $e) - { - echo $e->getMessage(); - } -} - -Repro(); - ?> --EXPECT-- There are 6 rows in the table. @@ -270,4 +233,3 @@ string(1) "2" string(7) "String0" string(7) "String1" string(7) "String2" -Test "PDO Statement - Fetch Bound" completed successfully. \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/PDO51_FetchLOB.phpt b/test/functional/pdo_sqlsrv/PDO51_FetchLOB.phpt index a433e04c..e26f73e7 100644 --- a/test/functional/pdo_sqlsrv/PDO51_FetchLOB.phpt +++ b/test/functional/pdo_sqlsrv/PDO51_FetchLOB.phpt @@ -5,119 +5,88 @@ Verification for LOB handling. --ENV-- PHPT_EXEC=true --SKIPIF-- - + --FILE-- getMessage(); } -function FetchLob($offset, $conn, $table, $sqlType, $data1, $data2) +function fetchLob($offset, $conn, $table, $sqlType, $data1, $data2) { - $id = NULL; - $label = NULL; + $id = null; + $label = null; - CreateTableEx($conn, $table, "id int NOT NULL PRIMARY KEY, label $sqlType", null); - InsertRowEx($conn, $table, "id, label", "$data1, '$data2'", null); + createTable($conn, $table, array(new ColumnMeta("int", "id", "NOT NULL PRIMARY KEY"), "label" => $sqlType)); + insertRow($conn, $table, array("id" => $data1, "label" => $data2)); - // Check data fetched with PDO::FETCH_BOUND - $stmt = ExecuteQuery($conn, "SELECT * FROM [$table]"); - if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT)) - { - LogInfo($offset, "Cannot bind integer column"); - } - if (!$stmt->bindColumn(2, $label, PDO::PARAM_LOB)) - { - LogInfo($offset, "Cannot bind LOB column"); - } - if (!$stmt->fetch(PDO::FETCH_BOUND)) - { - LogInfo($offset, "Cannot fetch bound data"); - } - if ($id != $data1) - { - LogInfo($offset, "ID data corruption: [$id] instead of [$data1]"); - } - if ($label != $data2) - { - LogInfo($offset, "Label data corruption: [$label] instead of [$data2]"); - } - unset($stmt); - unset($label); + // Check data fetched with PDO::FETCH_BOUND + $stmt = $conn->query("SELECT * FROM [$table]"); + if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT)) { + logInfo($offset, "Cannot bind integer column"); + } + if (!$stmt->bindColumn(2, $label, PDO::PARAM_LOB)) { + logInfo($offset, "Cannot bind LOB column"); + } + if (!$stmt->fetch(PDO::FETCH_BOUND)) { + logInfo($offset, "Cannot fetch bound data"); + } + if ($id != $data1) { + logInfo($offset, "ID data corruption: [$id] instead of [$data1]"); + } + if ($label != $data2) { + logInfo($offset, "Label data corruption: [$label] instead of [$data2]"); + } + unset($stmt); + unset($label); - // Check data fetched with PDO::FETCH_ASSOC - $stmt = ExecuteQuery($conn, "SELECT * FROM [$table]"); - $refData = $stmt->fetch(PDO::FETCH_ASSOC); - if ($refData['id'] != $data1) - { - $id = $refData['id']; - LogInfo($offset, "ID data corruption: [$id] instead of [$data1]"); - - } - if ($refData['label'] != $data2) - { - $label = $refData['label']; - LogInfo($offset, "Label data corruption: [$label] instead of [$data2]"); - } - unset($stmt); - unset($refData); + // Check data fetched with PDO::FETCH_ASSOC + $stmt = $conn->query("SELECT * FROM [$table]"); + $refData = $stmt->fetch(PDO::FETCH_ASSOC); + if ($refData['id'] != $data1) { + $id = $refData['id']; + logInfo($offset, "ID data corruption: [$id] instead of [$data1]"); + } + if ($refData['label'] != $data2) { + $label = $refData['label']; + logInfo($offset, "Label data corruption: [$label] instead of [$data2]"); + } + unset($stmt); + unset($refData); } -function LogInfo($offset, $msg) +function logInfo($offset, $msg) { - printf("[%03d] %s\n", $offset, $msg); + printf("[%03d] %s\n", $offset, $msg); } - -//-------------------------------------------------------------------- -// Repro -// -//-------------------------------------------------------------------- -function Repro() -{ - - try - { - LobTest(); - } - catch (Exception $e) - { - echo $e->getMessage(); - } -} - -Repro(); - ?> --EXPECT-- -Test "PDO Statement - Fetch LOB" completed successfully. \ No newline at end of file +Test 'PDO Statement - Fetch LOB' completed successfully. diff --git a/test/functional/pdo_sqlsrv/PDO61_BindColumn1.phpt b/test/functional/pdo_sqlsrv/PDO61_BindColumn1.phpt index f760cea6..1d773a3f 100644 --- a/test/functional/pdo_sqlsrv/PDO61_BindColumn1.phpt +++ b/test/functional/pdo_sqlsrv/PDO61_BindColumn1.phpt @@ -5,124 +5,91 @@ Verification for "PDOStatement::bindColumn". --ENV-- PHPT_EXEC=true --SKIPIF-- - + --FILE-- "varchar(20)")); + insertRow($conn1, $tableName, array("idx" => 0, "txt" => "String0")); + insertRow($conn1, $tableName, array("idx" => 1, "txt" => "String1")); + insertRow($conn1, $tableName, array("idx" => 2, "txt" => "String2")); + insertRow($conn1, $tableName, array("idx" => 3, "txt" => "String3")); - $conn1 = Connect(); + // Testing with prepared query + logInfo(1, "Testing fetchColumn() ..."); + $stmt1 = $conn1->query("SELECT COUNT(idx) FROM [$tableName]"); + var_dump($stmt1->fetchColumn()); + unset($stmt1); - // Prepare test table - $dataCols = "idx, txt"; - CreateTableEx($conn1, $tableName, "idx int NOT NULL PRIMARY KEY, txt VARCHAR(20)", null); - InsertRowEx($conn1, $tableName, $dataCols, "0, 'String0'", null); - InsertRowEx($conn1, $tableName, $dataCols, "1, 'String1'", null); - InsertRowEx($conn1, $tableName, $dataCols, "2, 'String2'", null); - InsertRowEx($conn1, $tableName, $dataCols, "3, 'String3'", null); + logInfo(2, "Testing fetchAll() ..."); + $stmt1 = $conn1->prepare("SELECT idx, txt FROM [$tableName] ORDER BY idx"); + $stmt1->execute(); + $data = $stmt1->fetchAll(PDO::FETCH_COLUMN|PDO::FETCH_UNIQUE); + var_dump($data); - // Testing with prepared query - LogInfo(1, "Testing fetchColumn() ..."); - $stmt1 = ExecuteQuery($conn1, "SELECT COUNT(idx) FROM [$tableName]"); - var_dump($stmt1->fetchColumn()); - unset($stmt1); + logInfo(3, "Testing bindColumn() ..."); + $stmt1->bindColumn('idx', $idx); + $stmt1->bindColumn('txt', $txt); + $stmt1->execute(); + while ($stmt1->fetch(PDO::FETCH_BOUND)) { + var_dump(array($idx=>$txt)); + } - LogInfo(2, "Testing fetchAll() ..."); - $stmt1 = PrepareQuery($conn1, "SELECT idx, txt FROM [$tableName] ORDER BY idx"); - $stmt1->execute(); - $data = $stmt1->fetchAll(PDO::FETCH_COLUMN|PDO::FETCH_UNIQUE); - var_dump($data); + logInfo(4, "Testing bindColumn() with data check ..."); + $id = null; + $val = null; + $data = array(); + $index = 0; + if (!$stmt1->bindColumn(1, $id, PDO::PARAM_INT)) { + logError(5, "Cannot bind integer column", $stmt1); + } + if (!$stmt1->bindColumn(2, $val, PDO::PARAM_STR)) { + logError(5, "Cannot bind string column", $stmt1); + } + $stmt1->execute(); + while ($stmt1->fetch(PDO::FETCH_BOUND)) { + $data[] = array('id' => $id, 'val' => $val); + printf("id = %s (%s) / val = %s (%s)\n", + var_export($id, true), gettype($id), + var_export($val, true), gettype($val)); + } + unset($stmt1); + + $stmt1 = $conn1->query("SELECT idx, txt FROM [$tableName] ORDER BY idx"); + while ($row = $stmt1->fetch(PDO::FETCH_ASSOC)) { + if ($row['idx'] != $data[$index]['id']) { + logInfo(6, "Data corruption for integer column in row $index"); + } + if ($row['txt'] != $data[$index]['val']) { + logInfo(6, "Data corruption for string column in row $index"); + } + $index++; + } - LogInfo(3, "Testing bindColumn() ..."); - $stmt1->bindColumn('idx', $idx); - $stmt1->bindColumn('txt', $txt); - $stmt1->execute(); - while ($stmt1->fetch(PDO::FETCH_BOUND)) - { - var_dump(array($idx=>$txt)); - } - - LogInfo(4, "Testing bindColumn() with data check ..."); - $id = null; - $val = null; - $data = array(); - $index = 0; - if (!$stmt1->bindColumn(1, $id, PDO::PARAM_INT)) - { - LogError(5, "Cannot bind integer column", $stmt1); - } - if (!$stmt1->bindColumn(2, $val, PDO::PARAM_STR)) - { - LogError(5, "Cannot bind string column", $stmt1); - } - $stmt1->execute(); - while ($stmt1->fetch(PDO::FETCH_BOUND)) - { - $data[] = array('id' => $id, 'val' => $val); - printf("id = %s (%s) / val = %s (%s)\n", - var_export($id, true), gettype($id), - var_export($val, true), gettype($val)); - } - unset($stmt1); - $stmt1 = ExecuteQuery($conn1, "SELECT idx, txt FROM [$tableName] ORDER BY idx"); - while ($row = $stmt1->fetch(PDO::FETCH_ASSOC)) - { - if ($row['idx'] != $data[$index]['id']) - { - LogInfo(6, "Data corruption for integer column in row $index"); - } - if ($row['txt'] != $data[$index]['val']) - { - LogInfo(6, "Data corruption for string column in row $index"); - } - $index++; - } - - - // Cleanup - DropTable($conn1, $tableName); - $stmt1 = null; - $conn1 = null; - - EndTest($testName); + // Cleanup + dropTable($conn1, $tableName); + unset($stmt1); + unset($conn1); +} catch (Exception $e) { + echo $e->getMessage(); } -function LogInfo($offset, $msg) +function logInfo($offset, $msg) { - printf("[%03d] %s\n", $offset, $msg); + printf("[%03d] %s\n", $offset, $msg); } -function LogError($offset, $msg, &$obj) +function logError($offset, $msg, &$obj) { - printf("[%03d] %s: %s\n", $offset, $msg, $obj->errorCode); + printf("[%03d] %s: %s\n", $offset, $msg, $obj->errorCode); } - -//-------------------------------------------------------------------- -// Repro -// -//-------------------------------------------------------------------- -function Repro() -{ - - try - { - Fetch(); - } - catch (Exception $e) - { - echo $e->getMessage(); - } -} - -Repro(); - ?> --EXPECT-- [001] Testing fetchColumn() ... @@ -160,4 +127,3 @@ id = 0 (integer) / val = 'String0' (string) id = 1 (integer) / val = 'String1' (string) id = 2 (integer) / val = 'String2' (string) id = 3 (integer) / val = 'String3' (string) -Test "PDO Statement - Bind Column" completed successfully. \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/PDO62_BindColumn2.phpt b/test/functional/pdo_sqlsrv/PDO62_BindColumn2.phpt index 4b6688a9..9e39ca3c 100644 --- a/test/functional/pdo_sqlsrv/PDO62_BindColumn2.phpt +++ b/test/functional/pdo_sqlsrv/PDO62_BindColumn2.phpt @@ -5,70 +5,61 @@ Verification for "PDOStatement::bindColumn()". --ENV-- PHPT_EXEC=true --SKIPIF-- - + --FILE-- "char(1)")); + insertRow($conn1, $tableName, array("id" => 1, "label" => "a")); + insertRow($conn1, $tableName, array("id" => 2, "label" => "b")); + insertRow($conn1, $tableName, array("id" => 3, "label" => "c")); + insertRow($conn1, $tableName, array("id" => 4, "label" => "d")); + insertRow($conn1, $tableName, array("id" => 5, "label" => "e")); + insertRow($conn1, $tableName, array("id" => 6, "label" => "f")); $rowCount = 3; $midRow = 4; // Check bind column $tsql1 = "SELECT TOP($rowCount) id, label FROM [$tableName] ORDER BY id ASC"; - $data = BindColumn($conn1, $tsql1); - CheckBind($conn1, $tsql1, $data); + $data = bindColumn($conn1, $tsql1); + checkBind($conn1, $tsql1, $data); $tsql2 = "SELECT TOP($rowCount) id, label FROM (SELECT *, ROW_NUMBER() OVER(ORDER BY id ASC) as row FROM [$tableName]) [$tableName] WHERE row >= $midRow"; - $data = BindColumn($conn1, $tsql2); - CheckBind($conn1, $tsql2, $data); + $data = bindColumn($conn1, $tsql2); + checkBind($conn1, $tsql2, $data); // Cleanup - DropTable($conn1, $tableName); - $conn1 = null; - - EndTest($testName); + dropTable($conn1, $tableName); + unset($conn1); +} catch (Exception $e) { + echo $e->getMessage(); } -function BindColumn($conn, $tsql) +function bindColumn($conn, $tsql) { $id = null; $label = null; $data = array(); - $stmt = PrepareQuery($conn, $tsql); + $stmt = $conn->prepare($tsql); $stmt->execute(); - if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT)) - { - LogInfo(1, "Cannot bind integer column"); + if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT)) { + logInfo(1, "Cannot bind integer column"); } - if (!$stmt->bindColumn(2, $label, PDO::PARAM_STR)) - { - LogInfo(1, "Cannot bind string column"); + if (!$stmt->bindColumn(2, $label, PDO::PARAM_STR)) { + logInfo(1, "Cannot bind string column"); } - while ($stmt->fetch(PDO::FETCH_BOUND)) - { + while ($stmt->fetch(PDO::FETCH_BOUND)) { printf("id = %s (%s) / label = %s (%s)\n", - var_export($id, true), gettype($id), - var_export($label, true), gettype($label)); + var_export($id, true), gettype($id), + var_export($label, true), gettype($label)); $data[] = array('id' => $id, 'label' => $label); } unset($stmt); @@ -77,51 +68,28 @@ function BindColumn($conn, $tsql) } -function CheckBind($conn, $tsql, $data) +function checkBind($conn, $tsql, $data) { $index = 0; $stmt = ExecuteQuery($conn, $tsql); - while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) - { - if ($row['id'] != $data[$index]['id']) - { - LogInfo(2, "Fetch bound and fetch assoc differ - column 'id', row $index"); + while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { + if ($row['id'] != $data[$index]['id']) { + logInfo(2, "Fetch bound and fetch assoc differ - column 'id', row $index"); } - if ($row['label'] != $data[$index]['label']) - { - LogInfo(2, "Fetch bound and fetch assoc differ - column 'label', row $index"); + if ($row['label'] != $data[$index]['label']) { + logInfo(2, "Fetch bound and fetch assoc differ - column 'label', row $index"); } $index++; } unset($stmt); } -function LogInfo($offset, $msg) +function logInfo($offset, $msg) { printf("[%03d] %s\n", $offset, $msg); } - -//-------------------------------------------------------------------- -// Repro -// -//-------------------------------------------------------------------- -function Repro() -{ - - try - { - Bind(); - } - catch (Exception $e) - { - echo $e->getMessage(); - } -} - -Repro(); - ?> --EXPECT-- id = 1 (integer) / label = 'a' (string) @@ -130,4 +98,3 @@ id = 3 (integer) / label = 'c' (string) id = 4 (integer) / label = 'd' (string) id = 5 (integer) / label = 'e' (string) id = 6 (integer) / label = 'f' (string) -Test "PDO Statement - Bind Column" completed successfully. \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/PDO63_BindParam1.phpt b/test/functional/pdo_sqlsrv/PDO63_BindParam1.phpt index 54d22785..0dea0c44 100644 --- a/test/functional/pdo_sqlsrv/PDO63_BindParam1.phpt +++ b/test/functional/pdo_sqlsrv/PDO63_BindParam1.phpt @@ -5,39 +5,36 @@ Verification for "PDOStatement::bindParam()". --ENV-- PHPT_EXEC=true --SKIPIF-- - + --FILE-- exec( "CREATE CLUSTERED INDEX [idx_test_int] ON " . $tableName . "(id)" ); - + $tableName = "pdo_test_table"; + createTable($conn1, $tableName, array("id" => "int", "name" => "varchar(20)")); + $conn1->exec("CREATE CLUSTERED INDEX [idx_test_int] ON $tableName (id)"); // Insert test data - $stmt1 = PrepareQuery($conn1, "INSERT INTO [$tableName] ($dataCols) VALUES(0, :name)"); - $name = NULL; + if (isColEncrypted()) { + $stmt1 = $conn1->prepare("INSERT INTO [$tableName] ($dataCols) VALUES(:id, :name)"); + $id = 0; + $stmt1->bindParam(':id', $id); + } else { + $stmt1 = $conn1->prepare("INSERT INTO [$tableName] ($dataCols) VALUES(0, :name)"); + } + $name = null; $before_bind = $name; $stmt1->bindParam(':name', $name); // Check that bindParam does not modify parameter - if ($name !== $before_bind) - { + if ($name !== $before_bind) { echo "bind: fail\n"; - } - else - { + } else { echo "bind: success\n"; } @@ -45,41 +42,25 @@ function Bind() unset($stmt1); // Retrieve test data - $stmt1 = ExecuteQuery($conn1, "SELECT name FROM [$tableName] WHERE id = 0"); + if (isColEncrypted()) { + $stmt1 = $conn1->prepare("SELECT name FROM [$tableName] WHERE id = ?"); + $id = 0; + $stmt1->bindParam(1, $id); + $stmt1->execute(); + } else { + $stmt1 = $conn1->query("SELECT name FROM [$tableName] WHERE id = 0"); + } var_dump($stmt1->fetchColumn()); - // Cleanup - DropTable($conn1, $tableName); - $stmt1 = null; - $conn1 = null; - - EndTest($testName); + dropTable($conn1, $tableName); + unset($stmt1); + unset($conn1); +} catch (Exception $e) { + echo $e->getMessage(); } - - -//-------------------------------------------------------------------- -// Repro -// -//-------------------------------------------------------------------- -function Repro() -{ - - try - { - Bind(); - } - catch (Exception $e) - { - echo $e->getMessage(); - } -} - -Repro(); - ?> --EXPECT-- bind: success bool(true) NULL -Test "PDO Statement - Bind Param" completed successfully. \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/PDO64_BindParam2.phpt b/test/functional/pdo_sqlsrv/PDO64_BindParam2.phpt index a60dcbc5..3801bf7f 100644 --- a/test/functional/pdo_sqlsrv/PDO64_BindParam2.phpt +++ b/test/functional/pdo_sqlsrv/PDO64_BindParam2.phpt @@ -5,133 +5,105 @@ Verification for "PDOStatement::bindParam()". --ENV-- PHPT_EXEC=true --SKIPIF-- - + --FILE-- "char(1)")); + insertRow($conn1, $tableName, array("id" => 1, "label" => 'a')); + insertRow($conn1, $tableName, array("id" => 2, "label" => 'b')); + insertRow($conn1, $tableName, array("id" => 3, "label" => 'c')); + insertRow($conn1, $tableName, array("id" => 4, "label" => 'd')); + insertRow($conn1, $tableName, array("id" => 5, "label" => 'e')); + insertRow($conn1, $tableName, array("id" => 6, "label" => 'f')); - $conn1 = Connect(); + $id = null; + $label = null; - // Prepare test table - $dataCols = "id, label"; - CreateTableEx($conn1, $tableName, "id int NOT NULL PRIMARY KEY, label CHAR(1)", null); - InsertRowEx($conn1, $tableName, $dataCols, "1, 'a'", null); - InsertRowEx($conn1, $tableName, $dataCols, "2, 'b'", null); - InsertRowEx($conn1, $tableName, $dataCols, "3, 'c'", null); - InsertRowEx($conn1, $tableName, $dataCols, "4, 'd'", null); - InsertRowEx($conn1, $tableName, $dataCols, "5, 'e'", null); - InsertRowEx($conn1, $tableName, $dataCols, "6, 'f'", null); + // Bind param @ SELECT + $tsql1 = "SELECT TOP(2) id, label FROM [$tableName] WHERE id > ? ORDER BY id ASC"; + $value1 = 0; + $stmt1 = $conn1->prepare($tsql1); + bindParam(1, $stmt1, $value1); + execStmt(1, $stmt1); + bindColumn(1, $stmt1, $id, $label); + fetchBound($stmt1, $id, $label); + execStmt(1, $stmt1); + fetchBound($stmt1, $id, $label); + unset($stmt1); - $id = null; - $label = null; + // Bind param @ INSERT + $tsql2 = "INSERT INTO [$tableName](id, label) VALUES (100, ?)"; + $value2 = null; + $stmt1 = $conn1->prepare($tsql2); + bindParam(2, $stmt1, $value2); + execStmt(2, $stmt1); + unset($stmt1); - // Bind param @ SELECT - $tsql1 = "SELECT TOP(2) id, label FROM [$tableName] WHERE id > ? ORDER BY id ASC"; - $value1 = 0; - $stmt1 = PrepareQuery($conn1, $tsql1); - BindParam(1, $stmt1, $value1); - ExecStmt(1, $stmt1); - BindColumn(1, $stmt1, $id, $label); - FetchBound($stmt1, $id, $label); - ExecStmt(1, $stmt1); - FetchBound($stmt1, $id, $label); - unset($stmt1); + // Check binding + $tsql3 = "SELECT id, NULL AS _label FROM [$tableName] WHERE label IS NULL"; + $stmt1 = $conn1->query($tsql3); + bindColumn(3, $stmt1, $id, $label); + fetchBound($stmt1, $id, $label); + unset($stmt1); - // Bind param @ INSERT - $tsql2 = "INSERT INTO [$tableName](id, label) VALUES (100, ?)"; - $value2 = null; - $stmt1 = PrepareQuery($conn1, $tsql2); - BindParam(2, $stmt1, $value2); - ExecStmt(2, $stmt1); - unset($stmt1); - - // Check binding - $tsql3 = "SELECT id, NULL AS _label FROM [$tableName] WHERE label IS NULL"; - $stmt1 = ExecuteQuery($conn1, $tsql3); - BindColumn(3, $stmt1, $id, $label); - FetchBound($stmt1, $id, $label); - unset($stmt1); - - // Cleanup - DropTable($conn1, $tableName); - $stmt1 = null; - $conn1 = null; - - EndTest($testName); + // Cleanup + dropTable($conn1, $tableName); + unset($stmt1); + unset($conn1); +} catch (Exception $e) { + echo $e->getMessage(); } -function BindParam($offset, $stmt, &$value) +function bindParam($offset, $stmt, &$value) { - if (!$stmt->bindParam(1, $value)) - { - LogInfo($offset,"Cannot bind parameter"); - } + if (!$stmt->bindParam(1, $value)) { + logInfo($offset,"Cannot bind parameter"); + } } -function BindColumn($offset, $stmt, &$param1, &$param2) +function bindColumn($offset, $stmt, &$param1, &$param2) { - if (!$stmt->bindColumn(1, $param1, PDO::PARAM_INT)) - { - LogInfo($offset, "Cannot bind integer column"); - } - if (!$stmt->bindColumn(2, $param2, PDO::PARAM_STR)) - { - LogInfo($offset, "Cannot bind string column"); - } + if (!$stmt->bindColumn(1, $param1, PDO::PARAM_INT)) { + logInfo($offset, "Cannot bind integer column"); + } + if (!$stmt->bindColumn(2, $param2, PDO::PARAM_STR)) { + logInfo($offset, "Cannot bind string column"); + } } -function ExecStmt($offset, $stmt) +function execStmt($offset, $stmt) { - if (!$stmt->execute()) - { - LogInfo($offset, "Cannot execute statement"); - } + if (!$stmt->execute()) { + logInfo($offset, "Cannot execute statement"); + } } -function FetchBound($stmt, &$param1, &$param2) +function fetchBound($stmt, &$param1, &$param2) { - while ($stmt->fetch(PDO::FETCH_BOUND)) - { - printf("id = %s (%s) / label = %s (%s)\n", - var_export($param1, true), gettype($param1), - var_export($param2, true), gettype($param2)); - } + while ($stmt->fetch(PDO::FETCH_BOUND)) { + printf( + "id = %s (%s) / label = %s (%s)\n", + var_export($param1, true), + gettype($param1), + var_export($param2, true), + gettype($param2) + ); + } } - -function LogInfo($offset, $msg) +function logInfo($offset, $msg) { - printf("[%03d] %s\n", $offset, $msg); + printf("[%03d] %s\n", $offset, $msg); } - - -//-------------------------------------------------------------------- -// Repro -// -//-------------------------------------------------------------------- -function Repro() -{ - - try - { - Bind(); - } - catch (Exception $e) - { - echo $e->getMessage(); - } -} - -Repro(); - ?> --EXPECT-- id = 1 (integer) / label = 'a' (string) @@ -139,4 +111,3 @@ id = 2 (integer) / label = 'b' (string) id = 1 (integer) / label = 'a' (string) id = 2 (integer) / label = 'b' (string) id = 100 (integer) / label = NULL (NULL) -Test "PDO Statement - Bind Param" completed successfully. \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/PDO65_BindValue1.phpt b/test/functional/pdo_sqlsrv/PDO65_BindValue1.phpt index 9e96e4f6..7e1914ec 100644 --- a/test/functional/pdo_sqlsrv/PDO65_BindValue1.phpt +++ b/test/functional/pdo_sqlsrv/PDO65_BindValue1.phpt @@ -5,67 +5,48 @@ Verification for "PDOStatement::bindValue()". --ENV-- PHPT_EXEC=true --SKIPIF-- - + --FILE-- "varchar(10)", "val2" => "varchar(10)", "val3" => "varchar(10)")); + $data = array("one", "two", "three"); - $conn1 = Connect(); + // Insert test data + $i = 1; + if (!isColEncrypted()) { + $stmt1 = $conn1->prepare("INSERT INTO [$tableName] VALUES(1, ?, ?, ?)"); + } else { + $stmt1 = $conn1->prepare("INSERT INTO [$tableName] VALUES(?, ?, ?, ?)"); + $stmt1->bindValue(1, 1); + $i++; + } + foreach ($data as $v) { + $stmt1->bindValue($i, $v); + $i++; + } + $stmt1->execute(); + unset($stmt1); - // Prepare test table - CreateTableEx($conn1, $tableName, "id int NOT NULL PRIMARY KEY, val1 VARCHAR(10), val2 VARCHAR(10), val3 VARCHAR(10)", null); - $data = array("one", "two", "three"); + // Retrieve test data + $stmt1 = $conn1->prepare("SELECT * FROM [$tableName]"); + $stmt1->execute(); + var_dump($stmt1->fetchAll(PDO::FETCH_ASSOC)); - // Insert test data - $stmt1 = PrepareQuery($conn1, "INSERT INTO [$tableName] VALUES(1, ?, ?, ?)"); - foreach ($data as $i => $v) - { - $stmt1->bindValue($i+1, $v); - } - $stmt1->execute(); - unset($stmt1); - - // Retrieve test data - $stmt1 = PrepareQuery($conn1, "SELECT * FROM [$tableName]"); - $stmt1->execute(); - var_dump($stmt1->fetchAll(PDO::FETCH_ASSOC)); - - - // Cleanup - DropTable($conn1, $tableName); - $stmt1 = null; - $conn1 = null; - - EndTest($testName); + // Cleanup + dropTable($conn1, $tableName); + unset($stmt1); + unset($conn1); +} catch (Exception $e) { + echo $e->getMessage(); } - -//-------------------------------------------------------------------- -// Repro -// -//-------------------------------------------------------------------- -function Repro() -{ - - try - { - Bind(); - } - catch (Exception $e) - { - echo $e->getMessage(); - } -} - -Repro(); - ?> --EXPECT-- array(1) { @@ -81,4 +62,3 @@ array(1) { string(5) "three" } } -Test "PDO Statement - Bind Value" completed successfully. \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/PDO66_BindValue2.phpt b/test/functional/pdo_sqlsrv/PDO66_BindValue2.phpt index 80ffea4c..71a885a7 100644 --- a/test/functional/pdo_sqlsrv/PDO66_BindValue2.phpt +++ b/test/functional/pdo_sqlsrv/PDO66_BindValue2.phpt @@ -5,184 +5,150 @@ Verification for "PDOStatement::bindValue()". --ENV-- PHPT_EXEC=true --SKIPIF-- - + --FILE-- "char(1)")); + insertRow($conn1, $tableName, array("id" => 1, "label" => "a")); + insertRow($conn1, $tableName, array("id" => 2, "label" => "b")); + insertRow($conn1, $tableName, array("id" => 3, "label" => "c")); + insertRow($conn1, $tableName, array("id" => 4, "label" => "d")); + insertRow($conn1, $tableName, array("id" => 5, "label" => "e")); + insertRow($conn1, $tableName, array("id" => 6, "label" => "f")); - $conn1 = Connect(); + $id = null; + $label = null; - // Prepare test table - $dataCols = "id, label"; - CreateTableEx($conn1, $tableName, "id int NOT NULL PRIMARY KEY, label CHAR(1)", null); - InsertRowEx($conn1, $tableName, $dataCols, "1, 'a'", null); - InsertRowEx($conn1, $tableName, $dataCols, "2, 'b'", null); - InsertRowEx($conn1, $tableName, $dataCols, "3, 'c'", null); - InsertRowEx($conn1, $tableName, $dataCols, "4, 'd'", null); - InsertRowEx($conn1, $tableName, $dataCols, "5, 'e'", null); - InsertRowEx($conn1, $tableName, $dataCols, "6, 'f'", null); + // Check different value bind modes + $tsql1 = "SELECT TOP(2) id, label FROM [$tableName] WHERE id > ? ORDER BY id ASC"; + $stmt1 = $conn1->prepare($tsql1); - $id = null; - $label = null; + printf("Binding value and not variable...\n"); + bindValue(1, $stmt1, 0); + execStmt(1, $stmt1); + bindColumn(1, $stmt1, $id, $label); + fetchBound($stmt1, $id, $label); - // Check different value bind modes - $tsql1 = "SELECT TOP(2) id, label FROM [$tableName] WHERE id > ? ORDER BY id ASC"; - $stmt1 = PrepareQuery($conn1, $tsql1); + printf("Binding variable...\n"); + $var1 = 0; + bindVar(2, $stmt1, $var1); + execStmt(2, $stmt1); + bindColumn(2, $stmt1, $id, $label); + fetchBound($stmt1, $id, $label); - printf("Binding value and not variable...\n"); - BindValue(1, $stmt1, 0); - ExecStmt(1, $stmt1); - BindColumn(1, $stmt1, $id, $label); - FetchBound($stmt1, $id, $label); + printf("Binding variable which references another variable...\n"); + $var2 = 0; + $var_ref = &$var2; + bindVar(3, $stmt1, $var_ref); + execStmt(3, $stmt1); + bindColumn(3, $stmt1, $id, $label); + fetchBound($stmt1, $id, $label); + unset($stmt1); - printf("Binding variable...\n"); - $var1 = 0; - BindVar(2, $stmt1, $var1); - ExecStmt(2, $stmt1); - BindColumn(2, $stmt1, $id, $label); - FetchBound($stmt1, $id, $label); + $tsql2 = "SELECT TOP(2) id, label FROM [$tableName] WHERE id > ? AND id <= ? ORDER BY id ASC"; + $stmt1 = $conn1->prepare($tsql2); - printf("Binding variable which references another variable...\n"); - $var2 = 0; - $var_ref = &$var2; - BindVar(3, $stmt1, $var_ref); - ExecStmt(3, $stmt1); - BindColumn(3, $stmt1, $id, $label); - FetchBound($stmt1, $id, $label); + printf("Binding a variable and a value...\n"); + $var3 = 0; + bindMixed(4, $stmt1, $var3, 2); + execStmt(4, $stmt1); + bindColumn(4, $stmt1, $id, $label); + fetchBound($stmt1, $id, $label); - unset($stmt1); + printf("Binding a variable to two placeholders and changing the variable value in between the binds...\n"); + $var4 = 0; + $var5 = 2; + bindPlaceholder(5, $stmt1, $var4, $var5); + execStmt(5, $stmt1); + bindColumn(5, $stmt1, $id, $label); + fetchBound($stmt1, $id, $label); + unset($stmt1); - $tsql2 = "SELECT TOP(2) id, label FROM [$tableName] WHERE id > ? AND id <= ? ORDER BY id ASC"; - $stmt1 = PrepareQuery($conn1, $tsql2); - - printf("Binding a variable and a value...\n"); - $var3 = 0; - BindMixed(4, $stmt1, $var3, 2); - ExecStmt(4, $stmt1); - BindColumn(4, $stmt1, $id, $label); - FetchBound($stmt1, $id, $label); - - printf("Binding a variable to two placeholders and changing the variable value in between the binds...\n"); - $var4 = 0; - $var5 = 2; - BindPlaceholder(5, $stmt1, $var4, $var5); - ExecStmt(5, $stmt1); - BindColumn(5, $stmt1, $id, $label); - FetchBound($stmt1, $id, $label); - - unset($stmt1); - - // Cleanup - DropTable($conn1, $tableName); - $stmt1 = null; - $conn1 = null; - - EndTest($testName); + // Cleanup + dropTable($conn1, $tableName); + unset($stmt1); + unset($conn1); +} catch (Exception $e) { + echo $e->getMessage(); } -function BindValue($offset, $stmt, $value) +function bindValue($offset, $stmt, $value) { - if (!$stmt->bindValue(1, $value)) - { - LogInfo($offset, "Cannot bind value"); - } + if (!$stmt->bindValue(1, $value)) { + logInfo($offset, "Cannot bind value"); + } } -function BindVar($offset, $stmt, &$var) +function bindVar($offset, $stmt, &$var) { - if (!$stmt->bindValue(1, $var)) - { - LogInfo($offset, "Cannot bind variable"); - } + if (!$stmt->bindValue(1, $var)) { + logInfo($offset, "Cannot bind variable"); + } } -function BindMixed($offset, $stmt, &$var, $value) +function bindMixed($offset, $stmt, &$var, $value) { - if (!$stmt->bindValue(1, $var)) - { - LogInfo($offset, "Cannot bind variable"); - } - if (!$stmt->bindValue(2, $value)) - { - LogInfo($offset, "Cannot bind value"); - } + if (!$stmt->bindValue(1, $var)) { + logInfo($offset, "Cannot bind variable"); + } + if (!$stmt->bindValue(2, $value)) { + logInfo($offset, "Cannot bind value"); + } } -function BindPlaceholder($offset, $stmt, &$var1, &$var2) +function bindPlaceholder($offset, $stmt, &$var1, &$var2) { - if (!$stmt->bindValue(1, $var1)) - { - LogInfo($offset, "Cannot bind variable 1"); - } - if (!$stmt->bindValue(2, $var2)) - { - LogInfo($offset, "Cannot bind variable 2"); - } + if (!$stmt->bindValue(1, $var1)) { + logInfo($offset, "Cannot bind variable 1"); + } + if (!$stmt->bindValue(2, $var2)) { + logInfo($offset, "Cannot bind variable 2"); + } } -function BindColumn($offset, $stmt, &$param1, &$param2) +function bindColumn($offset, $stmt, &$param1, &$param2) { - if (!$stmt->bindColumn(1, $param1, PDO::PARAM_INT)) - { - LogInfo($offset, "Cannot bind integer column"); - } - if (!$stmt->bindColumn(2, $param2, PDO::PARAM_STR)) - { - LogInfo($offset, "Cannot bind string column"); - } + if (!$stmt->bindColumn(1, $param1, PDO::PARAM_INT)) { + logInfo($offset, "Cannot bind integer column"); + } + if (!$stmt->bindColumn(2, $param2, PDO::PARAM_STR)) { + logInfo($offset, "Cannot bind string column"); + } } -function ExecStmt($offset, $stmt) +function execStmt($offset, $stmt) { - if (!$stmt->execute()) - { - LogInfo($offset, "Cannot execute statement"); - } + if (!$stmt->execute()) { + logInfo($offset, "Cannot execute statement"); + } } -function FetchBound($stmt, &$param1, &$param2) +function fetchBound($stmt, &$param1, &$param2) { - while ($stmt->fetch(PDO::FETCH_BOUND)) - { - printf("id = %s (%s) / label = %s (%s)\n", - var_export($param1, true), gettype($param1), - var_export($param2, true), gettype($param2)); - } + while ($stmt->fetch(PDO::FETCH_BOUND)) { + printf( + "id = %s (%s) / label = %s (%s)\n", + var_export($param1, true), + gettype($param1), + var_export($param2, true), + gettype($param2) + ); + } } -function LogInfo($offset, $msg) +function logInfo($offset, $msg) { - printf("[%03d] %s\n", $offset, $msg); + printf("[%03d] %s\n", $offset, $msg); } - -//-------------------------------------------------------------------- -// Repro -// -//-------------------------------------------------------------------- -function Repro() -{ - - try - { - Bind(); - } - catch (Exception $e) - { - echo $e->getMessage(); - } -} - -Repro(); - ?> --EXPECT-- Binding value and not variable... @@ -200,4 +166,3 @@ id = 2 (integer) / label = 'b' (string) Binding a variable to two placeholders and changing the variable value in between the binds... id = 1 (integer) / label = 'a' (string) id = 2 (integer) / label = 'b' (string) -Test "PDO Statement - Bind Value" completed successfully. \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/PDO67_BindTruncation.phpt b/test/functional/pdo_sqlsrv/PDO67_BindTruncation.phpt index b4dd7dce..262e6e01 100644 --- a/test/functional/pdo_sqlsrv/PDO67_BindTruncation.phpt +++ b/test/functional/pdo_sqlsrv/PDO67_BindTruncation.phpt @@ -5,137 +5,100 @@ Verification for "PDOStatement::bindParam()". --ENV-- PHPT_EXEC=true --SKIPIF-- - + --FILE-- "int", "value" => "char(32)")); + $conn1->exec("CREATE CLUSTERED INDEX [idx_test_int] ON $tableName (id)"); + $tsql = "INSERT INTO [$tableName] (class, value) VALUES(:class, :value)"; - $conn1 = Connect(); + $id = 0; + $class = 0; + $value = ''; - // Prepare test table - CreateTableEx($conn1, $tableName, "id INT IDENTITY NOT NULL, class INT, value CHAR(32)", null); - $conn1->exec( "CREATE CLUSTERED INDEX [idx_test_int] ON " . $tableName . "(id)" ); - $tsql1 = "SET IDENTITY_INSERT [$tableName] ON"; - $tsql2 = "INSERT INTO [$tableName] (id, class, value) VALUES(:id, :class, :value)"; - $tsql3 = "SET IDENTITY_INSERT [$tableName] OFF"; - $tsql4 = "SELECT id, value FROM [$tableName]"; + // Prepare insert query$ + $stmt1 = $conn1->prepare($tsql); + bindParam(1, $stmt1, ':class', $class); + bindParam(2, $stmt1, ':value', $value); + + // Insert test rows + $class = 4; + $value = '2011'; + execStmt(1, $stmt1); - - $id = 0; - $class = 0; - $value = ''; + $class = 5; + $value = 'Sat, 20 Mar 10 21:29:13 -0600'; + execStmt(2, $stmt1); - // Prepare insert query - $stmt1 = PrepareQuery($conn1, "$tsql1; $tsql2; $tsql3;"); - BindParam(1, $stmt1, ':id', $id); - BindParam(2, $stmt1, ':class', $class); - BindParam(3, $stmt1, ':value', $value); + $class = 6; + $value = 'Fri, 07 May 10 11:35:32 -0600'; + execStmt(3, $stmt1); - // Insert test rows - $id = 1; - $class = 4; - $value = '2011'; - ExecStmt(1, $stmt1); + unset($stmt1); - $id = 2; - $class = 5; - $value = 'Sat, 20 Mar 10 21:29:13 -0600'; - ExecStmt(2, $stmt1); + // Check data + $id = 0; + $value = ''; + $tsql = "SELECT id, value FROM [$tableName] ORDER BY id"; + $stmt2 = $conn1->query($tsql); + bindColumn(1, $stmt2, $id, $value); + while ($stmt2->fetch(PDO::FETCH_BOUND)) { + printf( + "id = %s (%s) / value = %s (%s)\n", + var_export($id, true), + gettype($id), + var_export($value, true), + gettype($value) + ); + } + unset($stmt2); - $id = 3; - $class = 6; - $value = 'Fri, 07 May 10 11:35:32 -0600'; - ExecStmt(3, $stmt1); - - unset($stmt1); - $stmt1 = null; - - // Check data - $id = 0; - $value = ''; - $stmt2 = ExecuteQuery($conn1, $tsql4); - BindColumn(1, $stmt2, $id, $value); - while ($stmt2->fetch(PDO::FETCH_BOUND)) - { - printf("id = %s (%s) / value = %s (%s)\n", - var_export($id, true), gettype($id), - var_export($value, true), gettype($value)); - } - unset($stmt2); - $stmt2 = null; - - // Cleanup - DropTable($conn1, $tableName); - $stmt1 = null; - $conn1 = null; - - EndTest($testName); + // Cleanup + dropTable($conn1, $tableName); + unset($stmt1); + unset($conn1); +} catch (Exception $e) { + echo $e->getMessage(); } -function BindParam($offset, $stmt, $param, &$value) +function bindParam($offset, $stmt, $param, &$value) { - if (!$stmt->bindParam($param, $value)) - { - LogInfo($offset,"Cannot bind parameter $param"); - } + if (!$stmt->bindParam($param, $value)) { + logInfo($offset, "Cannot bind parameter $param"); + } } -function BindColumn($offset, $stmt, &$param1, &$param2) +function bindColumn($offset, $stmt, &$param1, &$param2) { - if (!$stmt->bindColumn(1, $param1, PDO::PARAM_INT)) - { - LogInfo($offset, "Cannot bind integer column"); - } - if (!$stmt->bindColumn(2, $param2, PDO::PARAM_STR)) - { - LogInfo($offset, "Cannot bind string column"); - } + if (!$stmt->bindColumn(1, $param1, PDO::PARAM_INT)) { + logInfo($offset, "Cannot bind integer column"); + } + if (!$stmt->bindColumn(2, $param2, PDO::PARAM_STR)) { + logInfo($offset, "Cannot bind string column"); + } } -function ExecStmt($offset, $stmt) +function execStmt($offset, $stmt) { - if (!$stmt->execute()) - { - LogInfo($offset, "Cannot execute statement"); - var_dump($stmt->errorInfo()); - } + if (!$stmt->execute()) { + logInfo($offset, "Cannot execute statement"); + var_dump($stmt->errorInfo()); + } } -function LogInfo($offset, $msg) +function logInfo($offset, $msg) { - printf("[%03d] %s\n", $offset, $msg); + printf("[%03d] %s\n", $offset, $msg); } - - -//-------------------------------------------------------------------- -// Repro -// -//-------------------------------------------------------------------- -function Repro() -{ - - try - { - Bind(); - } - catch (Exception $e) - { - echo $e->getMessage(); - } -} - -Repro(); - ?> --EXPECT-- id = 1 (integer) / value = '2011 ' (string) id = 2 (integer) / value = 'Sat, 20 Mar 10 21:29:13 -0600 ' (string) id = 3 (integer) / value = 'Fri, 07 May 10 11:35:32 -0600 ' (string) -Test "PDO Statement - Bind Param Truncation" completed successfully. \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdoStatement_bindParam_inout_emulate_prepare.phpt b/test/functional/pdo_sqlsrv/pdoStatement_bindParam_inout_emulate_prepare.phpt index fabf870f..677ebe14 100644 --- a/test/functional/pdo_sqlsrv/pdoStatement_bindParam_inout_emulate_prepare.phpt +++ b/test/functional/pdo_sqlsrv/pdoStatement_bindParam_inout_emulate_prepare.phpt @@ -1,30 +1,36 @@ --TEST-- Tests error returned when binding input/output parameter with emulate prepare --SKIPIF-- - + --FILE-- setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $dbh = connect(); - $dbh->query("IF OBJECT_ID('sp_ReverseString', 'P') IS NOT NULL DROP PROCEDURE sp_ReverseString"); - $dbh->query("CREATE PROCEDURE sp_ReverseString @String as VARCHAR(2048) OUTPUT as SELECT @String = REVERSE(@String)"); - $stmt = $dbh->prepare("EXEC sp_ReverseString ?", array(PDO::ATTR_EMULATE_PREPARES => true)); + $procName = 'sp_ReverseString'; + dropProc($dbh, $procName); + $dbh->query("CREATE PROCEDURE $procName @String as VARCHAR(2048) OUTPUT as SELECT @String = REVERSE(@String)"); + $stmt = $dbh->prepare("EXEC $procName ?", array(PDO::ATTR_EMULATE_PREPARES => true)); $string = "123456789"; $stmt->bindParam(1, $string, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 2048); $stmt->execute(); - print "Result: ".$string; + print "Result: $string"; //free the statement and connection - $stmt = null; - $dbh = null; -} -catch(PDOException $e) { - print("Error: " . $e->getMessage() . "\n"); + dropProc($dbh, $procName); + unset($stmt); + unset($dbh); +} catch (PDOException $e) { + $error = $e->getMessage(); + $pass = !isAEConnected() && $error === "SQLSTATE[IMSSP]: Statement with emulate prepare on does not support output or input_output parameters."; + $pass |= isAEConnected() && ($error === "SQLSTATE[IMSSP]: Parameterized statement with attribute PDO::ATTR_EMULATE_PREPARES is not supported in a Column Encryption enabled Connection."); + if (!$pass) { + print("Error: " . $error . "\n"); + } else { + print("Test successfully done\n"); + } } ?> --EXPECT-- -Error: SQLSTATE[IMSSP]: Statement with emulate prepare on does not support output or input_output parameters. \ No newline at end of file +Test successfully done diff --git a/test/functional/pdo_sqlsrv/pdoStatement_bindParam_output_emulate_prepare.phpt b/test/functional/pdo_sqlsrv/pdoStatement_bindParam_output_emulate_prepare.phpt index 94773069..3a6f6ece 100644 --- a/test/functional/pdo_sqlsrv/pdoStatement_bindParam_output_emulate_prepare.phpt +++ b/test/functional/pdo_sqlsrv/pdoStatement_bindParam_output_emulate_prepare.phpt @@ -1,52 +1,48 @@ --TEST-- Tests error returned when binding output parameter with emulate prepare --SKIPIF-- - + --FILE-- setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $conn = connect(); $count = 0; - + $query = "select ? = count(* ) from cd_info"; $stmt = $conn->prepare($query, array(PDO::ATTR_EMULATE_PREPARES => true)); - $stmt->bindParam( 1, $count, PDO::PARAM_STR, 10 ); + $stmt->bindParam(1, $count, PDO::PARAM_STR, 10); $stmt->execute(); echo "Result: ".$count."\n"; - + $query = "select bigint_type, int_type, money_type from [test_types] where int_type < 0"; $stmt1 = $conn->prepare($query); $stmt1->execute(); - $row = $stmt1->fetch( PDO::FETCH_ASSOC ); - print_r($row); + $row = $stmt1->fetch(PDO::FETCH_ASSOC); + print_r($row); $int = 0; $bigint = 100; $query = "select ? = bigint_type, ? = int_type, ? = money_type from [test_types] where int_type < 0"; $stmt2 = $conn->prepare($query, array(PDO::ATTR_EMULATE_PREPARES => true)); - $stmt2->bindparam( 1, $bigint, PDO::PARAM_STR, 256 ); - $stmt2->bindParam( 2, $int, PDO::PARAM_INT, 4 ); - $stmt2->bindParam( 3, $money, PDO::PARAM_STR, 1024 ); + $stmt2->bindparam(1, $bigint, PDO::PARAM_STR, 256); + $stmt2->bindParam(2, $int, PDO::PARAM_INT, 4); + $stmt2->bindParam(3, $money, PDO::PARAM_STR, 1024); $stmt2->execute(); echo "Big integer: ".$bigint."\n"; echo "Integer: ".$int."\n"; echo "Money: ".$money."\n"; - + //free the statement and connection - $stmt = null; - $stmt1 = null; - $stmt2 = null; - $conn = null; - -} -catch(PDOException $e) { + unset($stmt); + unset($stmt1); + unset($stmt2); + unset($conn); +} catch (PDOException $e) { print("Error: " . $e->getMessage() . "\n"); } ?> --EXPECT-- -Error: SQLSTATE[IMSSP]: Statement with emulate prepare on does not support output or input_output parameters. \ No newline at end of file +Error: SQLSTATE[IMSSP]: Statement with emulate prepare on does not support output or input_output parameters. diff --git a/test/functional/pdo_sqlsrv/pdo_040_error_information.phpt b/test/functional/pdo_sqlsrv/pdo_040_error_information.phpt index 93036cbb..93b6e2fd 100644 --- a/test/functional/pdo_sqlsrv/pdo_040_error_information.phpt +++ b/test/functional/pdo_sqlsrv/pdo_040_error_information.phpt @@ -8,11 +8,11 @@ require_once("MsCommon_mid-refactor.inc"); try { // Connect - $conn = connect(); + $conn = connect(); // Create table $tableName = 'pdo_040test'; - // common function insertRow() is not used here since the test deliberately + // 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 $sql = "CREATE TABLE $tableName (code INT)"; @@ -31,7 +31,7 @@ try { } catch (PDOException $e) { $error = $e->errorInfo; $success = false; - if (!isColEncrypted()) { + if (!isAEConnected()) { // 21S01 is the expected ODBC Column name or number of supplied values does not match table definition error if ($error[0] === "21S01") { $success = true; @@ -41,7 +41,7 @@ try { if ($error[0] === "07009") { $success = true; } - } + } if ($success) { print "Done"; } else { diff --git a/test/functional/pdo_sqlsrv/pdo_092_emulate_prepare_statement_utf8.phpt b/test/functional/pdo_sqlsrv/pdo_092_emulate_prepare_statement_utf8.phpt index 24ab4c15..2c63654c 100644 --- a/test/functional/pdo_sqlsrv/pdo_092_emulate_prepare_statement_utf8.phpt +++ b/test/functional/pdo_sqlsrv/pdo_092_emulate_prepare_statement_utf8.phpt @@ -15,7 +15,7 @@ try { // Always Encrypted does not support using DIRECT_QUERY for binding parameters // see https://github.com/Microsoft/msphpsql/wiki/Features#aebindparam $pdo_options = []; - if (!isColEncrypted()) { + if (!isAEConnected()) { $pdo_options[PDO::SQLSRV_ATTR_DIRECT_QUERY] = true; } $pdo_options[PDO::ATTR_CURSOR] = PDO::CURSOR_SCROLL; @@ -35,13 +35,13 @@ try { $st->execute(['p0' => $name]); // Always Encrypted does not support emulate prepare - if (!isColEncrypted()) { + if (!isAEConnected()) { $pdo_options[PDO::ATTR_EMULATE_PREPARES] = true; } $st = $connection->prepare("INSERT INTO $tbname (name) VALUES (:p0)", $pdo_options); $st->execute(['p0' => $name2]); - if (!isColEncrypted()) { + if (!isAEConnected()) { $statement1 = $connection->prepare("SELECT * FROM $tbname WHERE NAME LIKE :p0", $pdo_options); $statement1->execute(['p0' => "$prefix%"]); $pdo_options[PDO::ATTR_EMULATE_PREPARES] = false; diff --git a/test/functional/pdo_sqlsrv/pdo_138_unicode_column_name.phpt b/test/functional/pdo_sqlsrv/pdo_138_unicode_column_name.phpt index bb4ddd92..2badf74d 100644 --- a/test/functional/pdo_sqlsrv/pdo_138_unicode_column_name.phpt +++ b/test/functional/pdo_sqlsrv/pdo_138_unicode_column_name.phpt @@ -11,13 +11,13 @@ Github 138. Test for Unicode Column Metadata. * @param mixed $query * @return PDOStatement */ -function prepare($connection, $query) { +function prepare($connection, $query) +{ $pdo_options = array(); - // emulate and binding parameter with direct query are not support in Always Encrypted - if ( !isColEncrypted() ) - { - $pdo_options[PDO::ATTR_EMULATE_PREPARES] = TRUE; - $pdo_options[PDO::SQLSRV_ATTR_DIRECT_QUERY] = TRUE; + // emulate and binding parameter with direct query are not supported in Always Encrypted + if (!isAEConnected()) { + $pdo_options[PDO::ATTR_EMULATE_PREPARES] = true; + $pdo_options[PDO::SQLSRV_ATTR_DIRECT_QUERY] = true; } $pdo_options[PDO::ATTR_CURSOR] = PDO::CURSOR_SCROLL; $pdo_options[PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE] = PDO::SQLSRV_CURSOR_BUFFERED; @@ -35,7 +35,7 @@ try { // Create Table $tbname = "mytáble"; - createTable( $connection, $tbname, array( new ColumnMeta( "nchar(10)", "id" ), new ColumnMeta( "nchar(10)", "väriable" ), new ColumnMeta( "nchar(10)", "tésting" ))); + createTable($connection, $tbname, array(new ColumnMeta("nchar(10)", "id"), new ColumnMeta("nchar(10)", "väriable"), new ColumnMeta("nchar(10)", "tésting"))); $query = "INSERT INTO $tbname (id, tésting, väriable) VALUES (:db_insert0, :db_insert1, :db_insert2)"; @@ -55,9 +55,9 @@ try { while ($row = $st->fetchAll()) { $row = reset($row); - echo (isset($row['id']) ? "OK" : "FAIL") , "\n"; - echo (isset($row['tésting']) ? "OK" : "FAIL") , "\n"; - echo (isset($row['väriable']) ? "OK" : "FAIL") , "\n"; + echo(isset($row['id']) ? "OK" : "FAIL") , "\n"; + echo(isset($row['tésting']) ? "OK" : "FAIL") , "\n"; + echo(isset($row['väriable']) ? "OK" : "FAIL") , "\n"; } for ($i = 0; $i < $st->columnCount(); $i++) { @@ -79,4 +79,4 @@ OK OK id väriable -tésting \ No newline at end of file +tésting diff --git a/test/functional/pdo_sqlsrv/pdo_140_emulate_prepare_mix_binary.phpt b/test/functional/pdo_sqlsrv/pdo_140_emulate_prepare_mix_binary.phpt index a7420878..d9568111 100644 --- a/test/functional/pdo_sqlsrv/pdo_140_emulate_prepare_mix_binary.phpt +++ b/test/functional/pdo_sqlsrv/pdo_140_emulate_prepare_mix_binary.phpt @@ -4,22 +4,23 @@ Test emulate prepare with mix bound param encodings including binary data --FILE-- &$field_value) { - $placeholder = $placeholder_prefix . $max_placeholder++; - if (isset($columnInformation['blobs'][$field_name])) { - $this->bindParam($placeholder, $field_value, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_BINARY); - } - else { - // Even though not a blob, make sure we retain a copy of these values. - $this->bindParam($placeholder, $field_value, PDO::PARAM_STR); - } +class MyStatement extends PDOStatement +{ + public function bindValues(array &$values, $placeholder_prefix, $columnInformation) + { + $max_placeholder = 0; + foreach ($values as $field_name => &$field_value) { + $placeholder = $placeholder_prefix . $max_placeholder++; + if (isset($columnInformation['blobs'][$field_name])) { + $this->bindParam($placeholder, $field_value, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_BINARY); + } else { + // Even though not a blob, make sure we retain a copy of these values. + $this->bindParam($placeholder, $field_value, PDO::PARAM_STR); + } + } } - } } - + //******************************************************* // TEST BEGIN //******************************************************* @@ -34,37 +35,37 @@ try { dropTable($cnn, $tbname); $pdo_options = array(); - if (!isColEncrypted()) { - $pdo_options[PDO::ATTR_EMULATE_PREPARES] = TRUE; - $pdo_options[PDO::SQLSRV_ATTR_DIRECT_QUERY] = TRUE; - - $cm_arr = array(new ColumnMeta("int", "wid", "IDENTITY(1,1) NOT NULL"), - new ColumnMeta("int", "uid", "NOT NULL CONSTRAINT [watchdog_uid_df] DEFAULT ((0))"), - new ColumnMeta("nvarchar(64)", "type", "NOT NULL CONSTRAINT [watchdog_type_df] DEFAULT ('')"), - new ColumnMeta("nvarchar(max)", "message", "NOT NULL"), - new ColumnMeta("varbinary(max)", "variables", "NOT NULL"), - new ColumnMeta("smallint", "severity", "NOT NULL CONSTRAINT [watchdog_severity_df] DEFAULT ((0))"), - new ColumnMeta("nvarchar(255)", "link", "NULL CONSTRAINT [watchdog_link_df] DEFAULT ('')"), - new ColumnMeta("nvarchar(max)", "location", "NOT NULL"), - new ColumnMeta("nvarchar(max)", "referer", "NULL"), - new ColumnMeta("nvarchar(128)", "hostname", "NOT NULL CONSTRAINT [watchdog_hostname_df] DEFAULT ('')"), + if (!isAEConnected()) { + $pdo_options[PDO::ATTR_EMULATE_PREPARES] = true; + $pdo_options[PDO::SQLSRV_ATTR_DIRECT_QUERY] = true; + + $cm_arr = array(new ColumnMeta("int", "wid", "IDENTITY(1,1) NOT NULL"), + new ColumnMeta("int", "uid", "NOT NULL CONSTRAINT [watchdog_uid_df] DEFAULT ((0))"), + new ColumnMeta("nvarchar(64)", "type", "NOT NULL CONSTRAINT [watchdog_type_df] DEFAULT ('')"), + new ColumnMeta("nvarchar(max)", "message", "NOT NULL"), + new ColumnMeta("varbinary(max)", "variables", "NOT NULL"), + new ColumnMeta("smallint", "severity", "NOT NULL CONSTRAINT [watchdog_severity_df] DEFAULT ((0))"), + new ColumnMeta("nvarchar(255)", "link", "NULL CONSTRAINT [watchdog_link_df] DEFAULT ('')"), + new ColumnMeta("nvarchar(max)", "location", "NOT NULL"), + new ColumnMeta("nvarchar(max)", "referer", "NULL"), + new ColumnMeta("nvarchar(128)", "hostname", "NOT NULL CONSTRAINT [watchdog_hostname_df] DEFAULT ('')"), new ColumnMeta("int", "timestamp", "NOT NULL CONSTRAINT [watchdog_timestamp_df] DEFAULT ((0))")); } else { // Emulate prepare and using direct query for binding parameters are not supported in Always encrypted - $pdo_options[PDO::ATTR_EMULATE_PREPARES] = FALSE; - $pdo_options[PDO::SQLSRV_ATTR_DIRECT_QUERY] = FALSE; - + $pdo_options[PDO::ATTR_EMULATE_PREPARES] = false; + $pdo_options[PDO::SQLSRV_ATTR_DIRECT_QUERY] = false; + // Default constraints are unsupported on encrypted columns - $cm_arr = array(new ColumnMeta("int", "wid", "IDENTITY(1,1) NOT NULL"), - new ColumnMeta("int", "uid", "NOT NULL"), - new ColumnMeta("nvarchar(64)", "type", "NOT NULL"), - new ColumnMeta("nvarchar(max)", "message", "NOT NULL"), - new ColumnMeta("varbinary(max)", "variables", "NOT NULL"), - new ColumnMeta("smallint", "severity", "NOT NULL"), - new ColumnMeta("nvarchar(255)", "link"), - new ColumnMeta("nvarchar(max)", "location", "NOT NULL"), - new ColumnMeta("nvarchar(max)", "referer"), - new ColumnMeta("nvarchar(128)", "hostname", "NOT NULL"), + $cm_arr = array(new ColumnMeta("int", "wid", "IDENTITY(1,1) NOT NULL"), + new ColumnMeta("int", "uid", "NOT NULL"), + new ColumnMeta("nvarchar(64)", "type", "NOT NULL"), + new ColumnMeta("nvarchar(max)", "message", "NOT NULL"), + new ColumnMeta("varbinary(max)", "variables", "NOT NULL"), + new ColumnMeta("smallint", "severity", "NOT NULL"), + new ColumnMeta("nvarchar(255)", "link"), + new ColumnMeta("nvarchar(max)", "location", "NOT NULL"), + new ColumnMeta("nvarchar(max)", "referer"), + new ColumnMeta("nvarchar(128)", "hostname", "NOT NULL"), new ColumnMeta("int", "timestamp", "NOT NULL")); } @@ -73,9 +74,9 @@ try { $cd_arr = array(); foreach ($cm_arr as $cm) { - array_push( $cd_arr, $cm->getColDef()); + array_push($cd_arr, $cm->getColDef()); } - + $tablescript = "CREATE TABLE [dbo].[$tbname]( $cd_arr[0], $cd_arr[1], $cd_arr[2], $cd_arr[3], $cd_arr[4], $cd_arr[5], $cd_arr[6], $cd_arr[7], $cd_arr[8], $cd_arr[9], $cd_arr[10], CONSTRAINT [watchdog_pkey] PRIMARY KEY CLUSTERED @@ -83,24 +84,24 @@ try { [wid] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]"; - + // Recreate $st = $cnn->prepare($tablescript); - $st->execute(); - + $st->execute(); + $query = "INSERT INTO [$tbname] ([uid], [type], [message], [variables], [severity], [link], [location], [referer], [hostname], [timestamp]) OUTPUT (Inserted.wid) VALUES (:db_insert0, :db_insert1, :db_insert2, :db_insert3, :db_insert4, :db_insert5, :db_insert6, :db_insert7, :db_insert8, :db_insert9)"; - + $values_encoded = 'YToxMDp7czozOiJ1aWQiO2k6MDtzOjQ6InR5cGUiO3M6MzoicGhwIjtzOjc6Im1lc3NhZ2UiO3M6NTE6IiV0eXBlOiBAbWVzc2FnZSBpbiAlZnVuY3Rpb24gKGxpbmUgJWxpbmUgb2YgJWZpbGUpLiI7czo5OiJ2YXJpYWJsZXMiO3M6MjE4ODoiYTo1OntzOjU6IiV0eXBlIjtzOjQ1OiJEcnVwYWxcQ29yZVxEYXRhYmFzZVxEYXRhYmFzZUV4Y2VwdGlvbldyYXBwZXIiO3M6ODoiQG1lc3NhZ2UiO3M6MTkxMzoiU1FMU1RBVEVbSU1TU1BdOiBBbiBlcnJvciBvY2N1cnJlZCB0cmFuc2xhdGluZyB0aGUgcXVlcnkgc3RyaW5nIHRvIFVURi0xNjogTm8gbWFwcGluZyBmb3IgdGhlIFVuaWNvZGUgY2hhcmFjdGVyIGV4aXN0cyBpbiB0aGUgdGFyZ2V0IG11bHRpLWJ5dGUgY29kZSBwYWdlLg0KLjogTUVSR0UgSU5UTyBbY2FjaGVfZGF0YV0gX3RhcmdldA0KVVNJTkcgKFNFTEVDVCBULiogRlJPTSAodmFsdWVzKDpkYl9pbnNlcnRfcGxhY2Vob2xkZXJfMCwgOmRiX2luc2VydF9wbGFjZWhvbGRlcl8xLCA6ZGJfaW5zZXJ0X3BsYWNlaG9sZGVyXzIsIDpkYl9pbnNlcnRfcGxhY2Vob2xkZXJfMywgOmRiX2luc2VydF9wbGFjZWhvbGRlcl80LCA6ZGJfaW5zZXJ0X3BsYWNlaG9sZGVyXzUsIDpkYl9pbnNlcnRfcGxhY2Vob2xkZXJfNikpIGFzIFQoW2NpZF0sIFtleHBpcmVdLCBbY3JlYXRlZF0sIFt0YWdzXSwgW2NoZWNrc3VtXSwgW2RhdGFdLCBbc2VyaWFsaXplZF0pKSBfc291cmNlDQpPTiBfdGFyZ2V0LltjaWRdID0gX3NvdXJjZS5bY2lkXQ0KV0hFTiBNQVRDSEVEIFRIRU4gVVBEQVRFIFNFVCBfdGFyZ2V0LltleHBpcmVdID0gX3NvdXJjZS5bZXhwaXJlXSwgX3RhcmdldC5bY3JlYXRlZF0gPSBfc291cmNlLltjcmVhdGVkXSwgX3RhcmdldC5bdGFnc10gPSBfc291cmNlLlt0YWdzXSwgX3RhcmdldC5bY2hlY2tzdW1dID0gX3NvdXJjZS5bY2hlY2tzdW1dLCBfdGFyZ2V0LltkYXRhXSA9IF9zb3VyY2UuW2RhdGFdLCBfdGFyZ2V0LltzZXJpYWxpemVkXSA9IF9zb3VyY2UuW3NlcmlhbGl6ZWRdDQpXSEVOIE5PVCBNQVRDSEVEIFRIRU4gSU5TRVJUIChbY2lkXSwgW2V4cGlyZV0sIFtjcmVhdGVkXSwgW3RhZ3NdLCBbY2hlY2tzdW1dLCBbZGF0YV0sIFtzZXJpYWxpemVkXSkgVkFMVUVTIChfc291cmNlLltjaWRdLCBfc291cmNlLltleHBpcmVdLCBfc291cmNlLltjcmVhdGVkXSwgX3NvdXJjZS5bdGFnc10sIF9zb3VyY2UuW2NoZWNrc3VtXSwgX3NvdXJjZS5bZGF0YV0sIF9zb3VyY2UuW3NlcmlhbGl6ZWRdKQ0KT1VUUFVUICRhY3Rpb247OyBBcnJheQooCiAgICBbOmRiX2luc2VydF9wbGFjZWhvbGRlcl8wXSA9PiBBcnJheQogICAgICAgICgKICAgICAgICAgICAgW3ZhbHVlXSA9PiByb3V0ZTovOlhERUJVR19TRVNTSU9OX1NUQVJUPTU4RTFDMUM0CiAgICAgICAgICAgIFtkYXRhdHlwZV0gPT4gMgogICAgICAgICkKCiAgICBbOmRiX2luc2VydF9wbGFjZWhvbGRlcl8xXSA9PiBBcnJheQogICAgICAgICgKICAgICAgICAgICAgW3ZhbHVlXSA9PiAtMQogICAgICAgICAgICBbZGF0YXR5cGVdID0+IDIKICAgICAgICApCgogICAgWzpkYl9pbnNlcnRfcGxhY2Vob2xkZXJfMl0gPT4gQXJyYXkKICAgICAgICAoCiAgICAgICAgICAgIFt2YWx1ZV0gPT4gMTQ3MDIwNTc3My43CiAgICAgICAgICAgIFtkYXRhdHlwZV0gPT4gMgogICAgICAgICkKCiAgICBbOmRiX2luc2VydF9wbGFjZWhvbGRlcl8zXSA9PiBBcnJheQogICAgICAgICgKICAgICAgICAgICAgW3ZhbHVlXSA9PiByb3V0ZV9tYXRjaAogICAgICAgICAgICBbZGF0YXR5cGVdID0+IDIKICAgICAgICApCgogICAgWzpkYl9pbnNlcnRfcGxhY2Vob2xkZXJfNF0gPT4gQXJyYXkKICAgICAgICAoCiAgICAgICAgICAgIFt2YWx1ZV0gPT4gNAogICAgICAgICAgICBbZGF0YXR5cGVdID0+IDIKICAgICAgICApCgogICAgWzpkYl9pbnNlcnRfcGxhY2Vob2xkZXJfNV0gPT4gQXJyYXkKICAgICAgICAoCiAgICAgICAgICAgIFt2YWx1ZV0gPT4gUmVzb3VyY2UgaWQgIzQKICAgICAgICAgICAgW2RhdGF0eXBlXSA9PiAzCiAgICAgICAgKQoKICAgIFs6ZGJfaW5zZXJ0X3BsYWNlaG9sZGVyXzZdID0+IEFycmF5CiAgICAgICAgKAogICAgICAgICAgICBbdmFsdWVdID0+IDEKICAgICAgICAgICAgW2RhdGF0eXBlXSA9PiAyCiAgICAgICAgKQoKKQoiO3M6OToiJWZ1bmN0aW9uIjtzOjY1OiJEcnVwYWxcQ29yZVxSb3V0aW5nXFJvdXRlUHJvdmlkZXItPmdldFJvdXRlQ29sbGVjdGlvbkZvclJlcXVlc3QoKSI7czo1OiIlZmlsZSI7czo1MjoiRDpcZDhcY29yZVxsaWJcRHJ1cGFsXENvcmVcUm91dGluZ1xSb3V0ZVByb3ZpZGVyLnBocCI7czo1OiIlbGluZSI7aToxNjc7fSI7czo4OiJzZXZlcml0eSI7aTozO3M6NDoibGluayI7czowOiIiO3M6ODoibG9jYXRpb24iO3M6NjQ6Imh0dHA6Ly9sb2NhbC5kN3Rlc3QuY29tL2luZGV4LnBocC8/WERFQlVHX1NFU1NJT05fU1RBUlQ9NThFMUMxQzQiO3M6NzoicmVmZXJlciI7czowOiIiO3M6ODoiaG9zdG5hbWUiO3M6OToiMTI3LjAuMC4xIjtzOjk6InRpbWVzdGFtcCI7aToxNDcwMjA1Nzc0O30='; $columninformation_encoded = 'YTo3OntzOjg6ImlkZW50aXR5IjtzOjM6IndpZCI7czoxMDoiaWRlbnRpdGllcyI7YToxOntzOjM6IndpZCI7czozOiJ3aWQiO31zOjc6ImNvbHVtbnMiO2E6MTE6e3M6Mzoid2lkIjthOjE0OntzOjQ6Im5hbWUiO3M6Mzoid2lkIjtzOjEwOiJtYXhfbGVuZ3RoIjtpOjQ7czo5OiJwcmVjaXNpb24iO2k6MTA7czoxNDoiY29sbGF0aW9uX25hbWUiO047czoxMToiaXNfbnVsbGFibGUiO2k6MDtzOjE0OiJpc19hbnNpX3BhZGRlZCI7aTowO3M6MTE6ImlzX2lkZW50aXR5IjtpOjE7czoxMToiaXNfY29tcHV0ZWQiO2k6MDtzOjQ6InR5cGUiO3M6MzoiaW50IjtzOjEwOiJkZWZpbml0aW9uIjtOO3M6MTM6ImRlZmF1bHRfdmFsdWUiO047czoxMToic3Fsc3J2X3R5cGUiO3M6MzoiaW50IjtzOjEyOiJkZXBlbmRlbmNpZXMiO2E6MDp7fXM6NzoiaW5kZXhlcyI7YToxOntpOjA7czoxMzoid2F0Y2hkb2dfcGtleSI7fX1zOjM6InVpZCI7YToxNDp7czo0OiJuYW1lIjtzOjM6InVpZCI7czoxMDoibWF4X2xlbmd0aCI7aTo0O3M6OToicHJlY2lzaW9uIjtpOjEwO3M6MTQ6ImNvbGxhdGlvbl9uYW1lIjtOO3M6MTE6ImlzX251bGxhYmxlIjtpOjA7czoxNDoiaXNfYW5zaV9wYWRkZWQiO2k6MDtzOjExOiJpc19pZGVudGl0eSI7aTowO3M6MTE6ImlzX2NvbXB1dGVkIjtpOjA7czo0OiJ0eXBlIjtzOjM6ImludCI7czoxMDoiZGVmaW5pdGlvbiI7TjtzOjEzOiJkZWZhdWx0X3ZhbHVlIjtzOjU6IigoMCkpIjtzOjExOiJzcWxzcnZfdHlwZSI7czozOiJpbnQiO3M6MTI6ImRlcGVuZGVuY2llcyI7YTowOnt9czo3OiJpbmRleGVzIjthOjE6e2k6MDtzOjc6InVpZF9pZHgiO319czo0OiJ0eXBlIjthOjE0OntzOjQ6Im5hbWUiO3M6NDoidHlwZSI7czoxMDoibWF4X2xlbmd0aCI7aTo2NDtzOjk6InByZWNpc2lvbiI7aTowO3M6MTQ6ImNvbGxhdGlvbl9uYW1lIjtzOjIwOiJMYXRpbjFfR2VuZXJhbF9DSV9BSSI7czoxMToiaXNfbnVsbGFibGUiO2k6MDtzOjE0OiJpc19hbnNpX3BhZGRlZCI7aToxO3M6MTE6ImlzX2lkZW50aXR5IjtpOjA7czoxMToiaXNfY29tcHV0ZWQiO2k6MDtzOjQ6InR5cGUiO3M6NzoidmFyY2hhciI7czoxMDoiZGVmaW5pdGlvbiI7TjtzOjEzOiJkZWZhdWx0X3ZhbHVlIjtzOjQ6IignJykiO3M6MTE6InNxbHNydl90eXBlIjtzOjExOiJ2YXJjaGFyKDY0KSI7czoxMjoiZGVwZW5kZW5jaWVzIjthOjA6e31zOjc6ImluZGV4ZXMiO2E6MTp7aTowO3M6ODoidHlwZV9pZHgiO319czo3OiJtZXNzYWdlIjthOjEzOntzOjQ6Im5hbWUiO3M6NzoibWVzc2FnZSI7czoxMDoibWF4X2xlbmd0aCI7aTotMTtzOjk6InByZWNpc2lvbiI7aTowO3M6MTQ6ImNvbGxhdGlvbl9uYW1lIjtzOjIwOiJMYXRpbjFfR2VuZXJhbF9DSV9BSSI7czoxMToiaXNfbnVsbGFibGUiO2k6MDtzOjE0OiJpc19hbnNpX3BhZGRlZCI7aToxO3M6MTE6ImlzX2lkZW50aXR5IjtpOjA7czoxMToiaXNfY29tcHV0ZWQiO2k6MDtzOjQ6InR5cGUiO3M6ODoibnZhcmNoYXIiO3M6MTA6ImRlZmluaXRpb24iO047czoxMzoiZGVmYXVsdF92YWx1ZSI7TjtzOjExOiJzcWxzcnZfdHlwZSI7czoxMzoibnZhcmNoYXIobWF4KSI7czoxMjoiZGVwZW5kZW5jaWVzIjthOjA6e319czo5OiJ2YXJpYWJsZXMiO2E6MTM6e3M6NDoibmFtZSI7czo5OiJ2YXJpYWJsZXMiO3M6MTA6Im1heF9sZW5ndGgiO2k6LTE7czo5OiJwcmVjaXNpb24iO2k6MDtzOjE0OiJjb2xsYXRpb25fbmFtZSI7TjtzOjExOiJpc19udWxsYWJsZSI7aTowO3M6MTQ6ImlzX2Fuc2lfcGFkZGVkIjtpOjE7czoxMToiaXNfaWRlbnRpdHkiO2k6MDtzOjExOiJpc19jb21wdXRlZCI7aTowO3M6NDoidHlwZSI7czo5OiJ2YXJiaW5hcnkiO3M6MTA6ImRlZmluaXRpb24iO047czoxMzoiZGVmYXVsdF92YWx1ZSI7TjtzOjExOiJzcWxzcnZfdHlwZSI7czoxNDoidmFyYmluYXJ5KG1heCkiO3M6MTI6ImRlcGVuZGVuY2llcyI7YTowOnt9fXM6ODoic2V2ZXJpdHkiO2E6MTQ6e3M6NDoibmFtZSI7czo4OiJzZXZlcml0eSI7czoxMDoibWF4X2xlbmd0aCI7aToyO3M6OToicHJlY2lzaW9uIjtpOjU7czoxNDoiY29sbGF0aW9uX25hbWUiO047czoxMToiaXNfbnVsbGFibGUiO2k6MDtzOjE0OiJpc19hbnNpX3BhZGRlZCI7aTowO3M6MTE6ImlzX2lkZW50aXR5IjtpOjA7czoxMToiaXNfY29tcHV0ZWQiO2k6MDtzOjQ6InR5cGUiO3M6ODoic21hbGxpbnQiO3M6MTA6ImRlZmluaXRpb24iO047czoxMzoiZGVmYXVsdF92YWx1ZSI7czo1OiIoKDApKSI7czoxMToic3Fsc3J2X3R5cGUiO3M6ODoic21hbGxpbnQiO3M6MTI6ImRlcGVuZGVuY2llcyI7YTowOnt9czo3OiJpbmRleGVzIjthOjE6e2k6MDtzOjEyOiJzZXZlcml0eV9pZHgiO319czo0OiJsaW5rIjthOjEzOntzOjQ6Im5hbWUiO3M6NDoibGluayI7czoxMDoibWF4X2xlbmd0aCI7aTotMTtzOjk6InByZWNpc2lvbiI7aTowO3M6MTQ6ImNvbGxhdGlvbl9uYW1lIjtzOjIwOiJMYXRpbjFfR2VuZXJhbF9DSV9BSSI7czoxMToiaXNfbnVsbGFibGUiO2k6MTtzOjE0OiJpc19hbnNpX3BhZGRlZCI7aToxO3M6MTE6ImlzX2lkZW50aXR5IjtpOjA7czoxMToiaXNfY29tcHV0ZWQiO2k6MDtzOjQ6InR5cGUiO3M6ODoibnZhcmNoYXIiO3M6MTA6ImRlZmluaXRpb24iO047czoxMzoiZGVmYXVsdF92YWx1ZSI7TjtzOjExOiJzcWxzcnZfdHlwZSI7czoxMzoibnZhcmNoYXIobWF4KSI7czoxMjoiZGVwZW5kZW5jaWVzIjthOjA6e319czo4OiJsb2NhdGlvbiI7YToxMzp7czo0OiJuYW1lIjtzOjg6ImxvY2F0aW9uIjtzOjEwOiJtYXhfbGVuZ3RoIjtpOi0xO3M6OToicHJlY2lzaW9uIjtpOjA7czoxNDoiY29sbGF0aW9uX25hbWUiO3M6MjA6IkxhdGluMV9HZW5lcmFsX0NJX0FJIjtzOjExOiJpc19udWxsYWJsZSI7aTowO3M6MTQ6ImlzX2Fuc2lfcGFkZGVkIjtpOjE7czoxMToiaXNfaWRlbnRpdHkiO2k6MDtzOjExOiJpc19jb21wdXRlZCI7aTowO3M6NDoidHlwZSI7czo4OiJudmFyY2hhciI7czoxMDoiZGVmaW5pdGlvbiI7TjtzOjEzOiJkZWZhdWx0X3ZhbHVlIjtOO3M6MTE6InNxbHNydl90eXBlIjtzOjEzOiJudmFyY2hhcihtYXgpIjtzOjEyOiJkZXBlbmRlbmNpZXMiO2E6MDp7fX1zOjc6InJlZmVyZXIiO2E6MTM6e3M6NDoibmFtZSI7czo3OiJyZWZlcmVyIjtzOjEwOiJtYXhfbGVuZ3RoIjtpOi0xO3M6OToicHJlY2lzaW9uIjtpOjA7czoxNDoiY29sbGF0aW9uX25hbWUiO3M6MjA6IkxhdGluMV9HZW5lcmFsX0NJX0FJIjtzOjExOiJpc19udWxsYWJsZSI7aToxO3M6MTQ6ImlzX2Fuc2lfcGFkZGVkIjtpOjE7czoxMToiaXNfaWRlbnRpdHkiO2k6MDtzOjExOiJpc19jb21wdXRlZCI7aTowO3M6NDoidHlwZSI7czo4OiJudmFyY2hhciI7czoxMDoiZGVmaW5pdGlvbiI7TjtzOjEzOiJkZWZhdWx0X3ZhbHVlIjtOO3M6MTE6InNxbHNydl90eXBlIjtzOjEzOiJudmFyY2hhcihtYXgpIjtzOjEyOiJkZXBlbmRlbmNpZXMiO2E6MDp7fX1zOjg6Imhvc3RuYW1lIjthOjEzOntzOjQ6Im5hbWUiO3M6ODoiaG9zdG5hbWUiO3M6MTA6Im1heF9sZW5ndGgiO2k6MTI4O3M6OToicHJlY2lzaW9uIjtpOjA7czoxNDoiY29sbGF0aW9uX25hbWUiO3M6MjA6IkxhdGluMV9HZW5lcmFsX0NJX0FJIjtzOjExOiJpc19udWxsYWJsZSI7aTowO3M6MTQ6ImlzX2Fuc2lfcGFkZGVkIjtpOjE7czoxMToiaXNfaWRlbnRpdHkiO2k6MDtzOjExOiJpc19jb21wdXRlZCI7aTowO3M6NDoidHlwZSI7czo3OiJ2YXJjaGFyIjtzOjEwOiJkZWZpbml0aW9uIjtOO3M6MTM6ImRlZmF1bHRfdmFsdWUiO3M6NDoiKCcnKSI7czoxMToic3Fsc3J2X3R5cGUiO3M6MTI6InZhcmNoYXIoMTI4KSI7czoxMjoiZGVwZW5kZW5jaWVzIjthOjA6e319czo5OiJ0aW1lc3RhbXAiO2E6MTM6e3M6NDoibmFtZSI7czo5OiJ0aW1lc3RhbXAiO3M6MTA6Im1heF9sZW5ndGgiO2k6NDtzOjk6InByZWNpc2lvbiI7aToxMDtzOjE0OiJjb2xsYXRpb25fbmFtZSI7TjtzOjExOiJpc19udWxsYWJsZSI7aTowO3M6MTQ6ImlzX2Fuc2lfcGFkZGVkIjtpOjA7czoxMToiaXNfaWRlbnRpdHkiO2k6MDtzOjExOiJpc19jb21wdXRlZCI7aTowO3M6NDoidHlwZSI7czozOiJpbnQiO3M6MTA6ImRlZmluaXRpb24iO047czoxMzoiZGVmYXVsdF92YWx1ZSI7czo1OiIoKDApKSI7czoxMToic3Fsc3J2X3R5cGUiO3M6MzoiaW50IjtzOjEyOiJkZXBlbmRlbmNpZXMiO2E6MDp7fX19czoxMzoiY29sdW1uc19jbGVhbiI7YToxMTp7czozOiJ3aWQiO2E6MTM6e3M6NDoibmFtZSI7czozOiJ3aWQiO3M6MTA6Im1heF9sZW5ndGgiO2k6NDtzOjk6InByZWNpc2lvbiI7aToxMDtzOjE0OiJjb2xsYXRpb25fbmFtZSI7TjtzOjExOiJpc19udWxsYWJsZSI7aTowO3M6MTQ6ImlzX2Fuc2lfcGFkZGVkIjtpOjA7czoxMToiaXNfaWRlbnRpdHkiO2k6MTtzOjExOiJpc19jb21wdXRlZCI7aTowO3M6NDoidHlwZSI7czozOiJpbnQiO3M6MTA6ImRlZmluaXRpb24iO047czoxMzoiZGVmYXVsdF92YWx1ZSI7TjtzOjExOiJzcWxzcnZfdHlwZSI7czozOiJpbnQiO3M6NzoiaW5kZXhlcyI7YToxOntpOjA7czoxMzoid2F0Y2hkb2dfcGtleSI7fX1zOjM6InVpZCI7YToxMzp7czo0OiJuYW1lIjtzOjM6InVpZCI7czoxMDoibWF4X2xlbmd0aCI7aTo0O3M6OToicHJlY2lzaW9uIjtpOjEwO3M6MTQ6ImNvbGxhdGlvbl9uYW1lIjtOO3M6MTE6ImlzX251bGxhYmxlIjtpOjA7czoxNDoiaXNfYW5zaV9wYWRkZWQiO2k6MDtzOjExOiJpc19pZGVudGl0eSI7aTowO3M6MTE6ImlzX2NvbXB1dGVkIjtpOjA7czo0OiJ0eXBlIjtzOjM6ImludCI7czoxMDoiZGVmaW5pdGlvbiI7TjtzOjEzOiJkZWZhdWx0X3ZhbHVlIjtzOjU6IigoMCkpIjtzOjExOiJzcWxzcnZfdHlwZSI7czozOiJpbnQiO3M6NzoiaW5kZXhlcyI7YToxOntpOjA7czo3OiJ1aWRfaWR4Ijt9fXM6NDoidHlwZSI7YToxMzp7czo0OiJuYW1lIjtzOjQ6InR5cGUiO3M6MTA6Im1heF9sZW5ndGgiO2k6NjQ7czo5OiJwcmVjaXNpb24iO2k6MDtzOjE0OiJjb2xsYXRpb25fbmFtZSI7czoyMDoiTGF0aW4xX0dlbmVyYWxfQ0lfQUkiO3M6MTE6ImlzX251bGxhYmxlIjtpOjA7czoxNDoiaXNfYW5zaV9wYWRkZWQiO2k6MTtzOjExOiJpc19pZGVudGl0eSI7aTowO3M6MTE6ImlzX2NvbXB1dGVkIjtpOjA7czo0OiJ0eXBlIjtzOjc6InZhcmNoYXIiO3M6MTA6ImRlZmluaXRpb24iO047czoxMzoiZGVmYXVsdF92YWx1ZSI7czo0OiIoJycpIjtzOjExOiJzcWxzcnZfdHlwZSI7czoxMToidmFyY2hhcig2NCkiO3M6NzoiaW5kZXhlcyI7YToxOntpOjA7czo4OiJ0eXBlX2lkeCI7fX1zOjc6Im1lc3NhZ2UiO2E6MTI6e3M6NDoibmFtZSI7czo3OiJtZXNzYWdlIjtzOjEwOiJtYXhfbGVuZ3RoIjtpOi0xO3M6OToicHJlY2lzaW9uIjtpOjA7czoxNDoiY29sbGF0aW9uX25hbWUiO3M6MjA6IkxhdGluMV9HZW5lcmFsX0NJX0FJIjtzOjExOiJpc19udWxsYWJsZSI7aTowO3M6MTQ6ImlzX2Fuc2lfcGFkZGVkIjtpOjE7czoxMToiaXNfaWRlbnRpdHkiO2k6MDtzOjExOiJpc19jb21wdXRlZCI7aTowO3M6NDoidHlwZSI7czo4OiJudmFyY2hhciI7czoxMDoiZGVmaW5pdGlvbiI7TjtzOjEzOiJkZWZhdWx0X3ZhbHVlIjtOO3M6MTE6InNxbHNydl90eXBlIjtzOjEzOiJudmFyY2hhcihtYXgpIjt9czo5OiJ2YXJpYWJsZXMiO2E6MTI6e3M6NDoibmFtZSI7czo5OiJ2YXJpYWJsZXMiO3M6MTA6Im1heF9sZW5ndGgiO2k6LTE7czo5OiJwcmVjaXNpb24iO2k6MDtzOjE0OiJjb2xsYXRpb25fbmFtZSI7TjtzOjExOiJpc19udWxsYWJsZSI7aTowO3M6MTQ6ImlzX2Fuc2lfcGFkZGVkIjtpOjE7czoxMToiaXNfaWRlbnRpdHkiO2k6MDtzOjExOiJpc19jb21wdXRlZCI7aTowO3M6NDoidHlwZSI7czo5OiJ2YXJiaW5hcnkiO3M6MTA6ImRlZmluaXRpb24iO047czoxMzoiZGVmYXVsdF92YWx1ZSI7TjtzOjExOiJzcWxzcnZfdHlwZSI7czoxNDoidmFyYmluYXJ5KG1heCkiO31zOjg6InNldmVyaXR5IjthOjEzOntzOjQ6Im5hbWUiO3M6ODoic2V2ZXJpdHkiO3M6MTA6Im1heF9sZW5ndGgiO2k6MjtzOjk6InByZWNpc2lvbiI7aTo1O3M6MTQ6ImNvbGxhdGlvbl9uYW1lIjtOO3M6MTE6ImlzX251bGxhYmxlIjtpOjA7czoxNDoiaXNfYW5zaV9wYWRkZWQiO2k6MDtzOjExOiJpc19pZGVudGl0eSI7aTowO3M6MTE6ImlzX2NvbXB1dGVkIjtpOjA7czo0OiJ0eXBlIjtzOjg6InNtYWxsaW50IjtzOjEwOiJkZWZpbml0aW9uIjtOO3M6MTM6ImRlZmF1bHRfdmFsdWUiO3M6NToiKCgwKSkiO3M6MTE6InNxbHNydl90eXBlIjtzOjg6InNtYWxsaW50IjtzOjc6ImluZGV4ZXMiO2E6MTp7aTowO3M6MTI6InNldmVyaXR5X2lkeCI7fX1zOjQ6ImxpbmsiO2E6MTI6e3M6NDoibmFtZSI7czo0OiJsaW5rIjtzOjEwOiJtYXhfbGVuZ3RoIjtpOi0xO3M6OToicHJlY2lzaW9uIjtpOjA7czoxNDoiY29sbGF0aW9uX25hbWUiO3M6MjA6IkxhdGluMV9HZW5lcmFsX0NJX0FJIjtzOjExOiJpc19udWxsYWJsZSI7aToxO3M6MTQ6ImlzX2Fuc2lfcGFkZGVkIjtpOjE7czoxMToiaXNfaWRlbnRpdHkiO2k6MDtzOjExOiJpc19jb21wdXRlZCI7aTowO3M6NDoidHlwZSI7czo4OiJudmFyY2hhciI7czoxMDoiZGVmaW5pdGlvbiI7TjtzOjEzOiJkZWZhdWx0X3ZhbHVlIjtOO3M6MTE6InNxbHNydl90eXBlIjtzOjEzOiJudmFyY2hhcihtYXgpIjt9czo4OiJsb2NhdGlvbiI7YToxMjp7czo0OiJuYW1lIjtzOjg6ImxvY2F0aW9uIjtzOjEwOiJtYXhfbGVuZ3RoIjtpOi0xO3M6OToicHJlY2lzaW9uIjtpOjA7czoxNDoiY29sbGF0aW9uX25hbWUiO3M6MjA6IkxhdGluMV9HZW5lcmFsX0NJX0FJIjtzOjExOiJpc19udWxsYWJsZSI7aTowO3M6MTQ6ImlzX2Fuc2lfcGFkZGVkIjtpOjE7czoxMToiaXNfaWRlbnRpdHkiO2k6MDtzOjExOiJpc19jb21wdXRlZCI7aTowO3M6NDoidHlwZSI7czo4OiJudmFyY2hhciI7czoxMDoiZGVmaW5pdGlvbiI7TjtzOjEzOiJkZWZhdWx0X3ZhbHVlIjtOO3M6MTE6InNxbHNydl90eXBlIjtzOjEzOiJudmFyY2hhcihtYXgpIjt9czo3OiJyZWZlcmVyIjthOjEyOntzOjQ6Im5hbWUiO3M6NzoicmVmZXJlciI7czoxMDoibWF4X2xlbmd0aCI7aTotMTtzOjk6InByZWNpc2lvbiI7aTowO3M6MTQ6ImNvbGxhdGlvbl9uYW1lIjtzOjIwOiJMYXRpbjFfR2VuZXJhbF9DSV9BSSI7czoxMToiaXNfbnVsbGFibGUiO2k6MTtzOjE0OiJpc19hbnNpX3BhZGRlZCI7aToxO3M6MTE6ImlzX2lkZW50aXR5IjtpOjA7czoxMToiaXNfY29tcHV0ZWQiO2k6MDtzOjQ6InR5cGUiO3M6ODoibnZhcmNoYXIiO3M6MTA6ImRlZmluaXRpb24iO047czoxMzoiZGVmYXVsdF92YWx1ZSI7TjtzOjExOiJzcWxzcnZfdHlwZSI7czoxMzoibnZhcmNoYXIobWF4KSI7fXM6ODoiaG9zdG5hbWUiO2E6MTI6e3M6NDoibmFtZSI7czo4OiJob3N0bmFtZSI7czoxMDoibWF4X2xlbmd0aCI7aToxMjg7czo5OiJwcmVjaXNpb24iO2k6MDtzOjE0OiJjb2xsYXRpb25fbmFtZSI7czoyMDoiTGF0aW4xX0dlbmVyYWxfQ0lfQUkiO3M6MTE6ImlzX251bGxhYmxlIjtpOjA7czoxNDoiaXNfYW5zaV9wYWRkZWQiO2k6MTtzOjExOiJpc19pZGVudGl0eSI7aTowO3M6MTE6ImlzX2NvbXB1dGVkIjtpOjA7czo0OiJ0eXBlIjtzOjc6InZhcmNoYXIiO3M6MTA6ImRlZmluaXRpb24iO047czoxMzoiZGVmYXVsdF92YWx1ZSI7czo0OiIoJycpIjtzOjExOiJzcWxzcnZfdHlwZSI7czoxMjoidmFyY2hhcigxMjgpIjt9czo5OiJ0aW1lc3RhbXAiO2E6MTI6e3M6NDoibmFtZSI7czo5OiJ0aW1lc3RhbXAiO3M6MTA6Im1heF9sZW5ndGgiO2k6NDtzOjk6InByZWNpc2lvbiI7aToxMDtzOjE0OiJjb2xsYXRpb25fbmFtZSI7TjtzOjExOiJpc19udWxsYWJsZSI7aTowO3M6MTQ6ImlzX2Fuc2lfcGFkZGVkIjtpOjA7czoxMToiaXNfaWRlbnRpdHkiO2k6MDtzOjExOiJpc19jb21wdXRlZCI7aTowO3M6NDoidHlwZSI7czozOiJpbnQiO3M6MTA6ImRlZmluaXRpb24iO047czoxMzoiZGVmYXVsdF92YWx1ZSI7czo1OiIoKDApKSI7czoxMToic3Fsc3J2X3R5cGUiO3M6MzoiaW50Ijt9fXM6NToiYmxvYnMiO2E6MTp7czo5OiJ2YXJpYWJsZXMiO2I6MTt9czo3OiJpbmRleGVzIjthOjQ6e3M6MTM6IndhdGNoZG9nX3BrZXkiO2E6MTU6e3M6MTA6ImluZGV4X25hbWUiO3M6MTM6IndhdGNoZG9nX3BrZXkiO3M6OToidHlwZV9kZXNjIjtzOjk6IkNMVVNURVJFRCI7czo5OiJpc191bmlxdWUiO2k6MTtzOjEzOiJkYXRhX3NwYWNlX2lkIjtpOjE7czoxNDoiaWdub3JlX2R1cF9rZXkiO2k6MDtzOjE0OiJpc19wcmltYXJ5X2tleSI7aToxO3M6MjA6ImlzX3VuaXF1ZV9jb25zdHJhaW50IjtpOjA7czoxMToiZmlsbF9mYWN0b3IiO2k6MDtzOjk6ImlzX3BhZGRlZCI7aTowO3M6MTE6ImlzX2Rpc2FibGVkIjtpOjA7czoxNToiaXNfaHlwb3RoZXRpY2FsIjtpOjA7czoxNToiYWxsb3dfcm93X2xvY2tzIjtpOjE7czoxNjoiYWxsb3dfcGFnZV9sb2NrcyI7aToxO3M6MTg6ImlzX2luY2x1ZGVkX2NvbHVtbiI7aTowO3M6NzoiY29sdW1ucyI7YToxOntpOjE7YTozOntzOjQ6Im5hbWUiO3M6Mzoid2lkIjtzOjE3OiJpc19kZXNjZW5kaW5nX2tleSI7aTowO3M6MTE6ImtleV9vcmRpbmFsIjtpOjE7fX19czo4OiJ0eXBlX2lkeCI7YToxNTp7czoxMDoiaW5kZXhfbmFtZSI7czo4OiJ0eXBlX2lkeCI7czo5OiJ0eXBlX2Rlc2MiO3M6MTI6Ik5PTkNMVVNURVJFRCI7czo5OiJpc191bmlxdWUiO2k6MDtzOjEzOiJkYXRhX3NwYWNlX2lkIjtpOjE7czoxNDoiaWdub3JlX2R1cF9rZXkiO2k6MDtzOjE0OiJpc19wcmltYXJ5X2tleSI7aTowO3M6MjA6ImlzX3VuaXF1ZV9jb25zdHJhaW50IjtpOjA7czoxMToiZmlsbF9mYWN0b3IiO2k6MDtzOjk6ImlzX3BhZGRlZCI7aTowO3M6MTE6ImlzX2Rpc2FibGVkIjtpOjA7czoxNToiaXNfaHlwb3RoZXRpY2FsIjtpOjA7czoxNToiYWxsb3dfcm93X2xvY2tzIjtpOjE7czoxNjoiYWxsb3dfcGFnZV9sb2NrcyI7aToxO3M6MTg6ImlzX2luY2x1ZGVkX2NvbHVtbiI7aTowO3M6NzoiY29sdW1ucyI7YToxOntpOjE7YTozOntzOjQ6Im5hbWUiO3M6NDoidHlwZSI7czoxNzoiaXNfZGVzY2VuZGluZ19rZXkiO2k6MDtzOjExOiJrZXlfb3JkaW5hbCI7aToxO319fXM6NzoidWlkX2lkeCI7YToxNTp7czoxMDoiaW5kZXhfbmFtZSI7czo3OiJ1aWRfaWR4IjtzOjk6InR5cGVfZGVzYyI7czoxMjoiTk9OQ0xVU1RFUkVEIjtzOjk6ImlzX3VuaXF1ZSI7aTowO3M6MTM6ImRhdGFfc3BhY2VfaWQiO2k6MTtzOjE0OiJpZ25vcmVfZHVwX2tleSI7aTowO3M6MTQ6ImlzX3ByaW1hcnlfa2V5IjtpOjA7czoyMDoiaXNfdW5pcXVlX2NvbnN0cmFpbnQiO2k6MDtzOjExOiJmaWxsX2ZhY3RvciI7aTowO3M6OToiaXNfcGFkZGVkIjtpOjA7czoxMToiaXNfZGlzYWJsZWQiO2k6MDtzOjE1OiJpc19oeXBvdGhldGljYWwiO2k6MDtzOjE1OiJhbGxvd19yb3dfbG9ja3MiO2k6MTtzOjE2OiJhbGxvd19wYWdlX2xvY2tzIjtpOjE7czoxODoiaXNfaW5jbHVkZWRfY29sdW1uIjtpOjA7czo3OiJjb2x1bW5zIjthOjE6e2k6MTthOjM6e3M6NDoibmFtZSI7czozOiJ1aWQiO3M6MTc6ImlzX2Rlc2NlbmRpbmdfa2V5IjtpOjA7czoxMToia2V5X29yZGluYWwiO2k6MTt9fX1zOjEyOiJzZXZlcml0eV9pZHgiO2E6MTU6e3M6MTA6ImluZGV4X25hbWUiO3M6MTI6InNldmVyaXR5X2lkeCI7czo5OiJ0eXBlX2Rlc2MiO3M6MTI6Ik5PTkNMVVNURVJFRCI7czo5OiJpc191bmlxdWUiO2k6MDtzOjEzOiJkYXRhX3NwYWNlX2lkIjtpOjE7czoxNDoiaWdub3JlX2R1cF9rZXkiO2k6MDtzOjE0OiJpc19wcmltYXJ5X2tleSI7aTowO3M6MjA6ImlzX3VuaXF1ZV9jb25zdHJhaW50IjtpOjA7czoxMToiZmlsbF9mYWN0b3IiO2k6MDtzOjk6ImlzX3BhZGRlZCI7aTowO3M6MTE6ImlzX2Rpc2FibGVkIjtpOjA7czoxNToiaXNfaHlwb3RoZXRpY2FsIjtpOjA7czoxNToiYWxsb3dfcm93X2xvY2tzIjtpOjE7czoxNjoiYWxsb3dfcGFnZV9sb2NrcyI7aToxO3M6MTg6ImlzX2luY2x1ZGVkX2NvbHVtbiI7aTowO3M6NzoiY29sdW1ucyI7YToxOntpOjE7YTozOntzOjQ6Im5hbWUiO3M6ODoic2V2ZXJpdHkiO3M6MTc6ImlzX2Rlc2NlbmRpbmdfa2V5IjtpOjA7czoxMToia2V5X29yZGluYWwiO2k6MTt9fX19czoxNzoicHJpbWFyeV9rZXlfaW5kZXgiO3M6MTM6IndhdGNoZG9nX3BrZXkiO30='; - + $values = unserialize(base64_decode($values_encoded)); $columnInformation = unserialize(base64_decode($columninformation_encoded)); - + /** @var MyStatement */ $st = $cnn->prepare($query, $pdo_options); - $st->BindValues($values, ':db_insert', $columnInformation); + $st->bindValues($values, ':db_insert', $columnInformation); $st->execute(); $st = $cnn->query("SELECT * FROM [$tbname]"); @@ -191,4 +192,4 @@ OUTPUT $action;; Array ["timestamp"]=> string(10) "1470205774" } -} \ No newline at end of file +} diff --git a/test/functional/pdo_sqlsrv/pdo_ae_unsupported_stmt_attr.phpt b/test/functional/pdo_sqlsrv/pdo_ae_unsupported_stmt_attr.phpt index 8f689f76..a1b38075 100644 --- a/test/functional/pdo_sqlsrv/pdo_ae_unsupported_stmt_attr.phpt +++ b/test/functional/pdo_sqlsrv/pdo_ae_unsupported_stmt_attr.phpt @@ -1,5 +1,5 @@ --TEST-- -Test error from preparing a parameterized query with direct query or emulate prepare when Column Encryption is enabled +Test error from preparing a parameterized query with direct query or emulate prepare when Column Encryption is enabled --SKIPIF-- --FILE-- @@ -21,7 +21,7 @@ try { } catch (PDOException $e) { $error = $e->errorInfo; // expects an exception if Column Encryption is enabled - if (isColEncrypted()) { + if (isAEConnected()) { if ($error[0] != "IMSSP" || $error[1] != -81 || $error[2] != "Parameterized statement with attribute PDO::SQLSRV_ATTR_DIRECT_QUERY is not supported in a Column Encryption enabled Connection.") { @@ -40,7 +40,7 @@ try { } catch (PDOException $e) { $error = $e->errorInfo; // expects an exception if Column Encryption is enabled - if (isColEncrypted()) { + if (isAEConnected()) { if ($error[0] != "IMSSP" || $error[1] != -82 || $error[2] != "Parameterized statement with attribute PDO::ATTR_EMULATE_PREPARES is not supported in a Column Encryption enabled Connection.") { diff --git a/test/functional/pdo_sqlsrv/pdo_connect_encrypted_ksp.phpt b/test/functional/pdo_sqlsrv/pdo_connect_encrypted_ksp.phpt index 26f1eee4..02d77f53 100644 --- a/test/functional/pdo_sqlsrv/pdo_connect_encrypted_ksp.phpt +++ b/test/functional/pdo_sqlsrv/pdo_connect_encrypted_ksp.phpt @@ -4,19 +4,11 @@ Fetch data from a prepopulated test table given a custom keystore provider --FILE-- query($tsql); while ($row = $stmt->fetch(PDO::FETCH_NUM)) { echo "c1=" . $row[0] . "\tc2=" . $row[1] . "\tc3=" . $row[2] . "\tc4=" . $row[3] . "\n"; } - $stmt = null; - $conn = null; + unset($stmt); + unset($conn); echo "Done\n"; diff --git a/test/functional/pdo_sqlsrv/pdo_connect_encrypted_ksp_encrypted.phpt b/test/functional/pdo_sqlsrv/pdo_connect_encrypted_ksp_encrypted.phpt index 8a0d7272..0d7d8540 100644 --- a/test/functional/pdo_sqlsrv/pdo_connect_encrypted_ksp_encrypted.phpt +++ b/test/functional/pdo_sqlsrv/pdo_connect_encrypted_ksp_encrypted.phpt @@ -4,19 +4,11 @@ Fetch encrypted data from a prepopulated test table given a custom keystore prov --FILE-- query($tsql); while ($row = $stmt->fetch(PDO::FETCH_NUM)) { @@ -37,8 +30,8 @@ Fetch encrypted data from a prepopulated test table given a custom keystore prov echo "\n" ; } - $stmt = null; - $conn = null; + unset($stmt); + unset($conn); echo "Done\n"; diff --git a/test/functional/pdo_sqlsrv/pdo_connect_encrypted_ksp_errors.phpt b/test/functional/pdo_sqlsrv/pdo_connect_encrypted_ksp_errors.phpt index 64c0eb25..505d7296 100644 --- a/test/functional/pdo_sqlsrv/pdo_connect_encrypted_ksp_errors.phpt +++ b/test/functional/pdo_sqlsrv/pdo_connect_encrypted_ksp_errors.phpt @@ -4,10 +4,10 @@ Connect using a custom keystore provider with some required inputs missing --FILE-- diff --git a/test/functional/pdo_sqlsrv/pdo_errorinfo_emulateprepare.phpt b/test/functional/pdo_sqlsrv/pdo_errorinfo_emulateprepare.phpt index 29c4426a..2fea191b 100644 --- a/test/functional/pdo_sqlsrv/pdo_errorinfo_emulateprepare.phpt +++ b/test/functional/pdo_sqlsrv/pdo_errorinfo_emulateprepare.phpt @@ -20,7 +20,7 @@ try { echo "\n****testing with emulate prepare****\n"; // Do not support emulate prepare with Always Encrypted - if (!isColEncrypted()) { + if (!isAEConnected()) { $stmt = $conn->prepare("SELECT c2 FROM $tbname WHERE c1= :int", array(PDO::ATTR_EMULATE_PREPARES => true)); } else { $stmt = $conn->prepare("SELECT c2 FROM $tbname WHERE c1= :int"); @@ -32,7 +32,7 @@ try { $stmt->execute(); $stmt_error = $stmt->errorInfo(); - if (!isColEncrypted()) { + if (!isAEConnected()) { if ($stmt_error[0] != "HY093") { echo "SQLSTATE should be HY093 when Emulate Prepare is true.\n"; print_r($stmt_error); diff --git a/test/functional/pdo_sqlsrv/pdo_fetch_variants_diff_styles.phpt b/test/functional/pdo_sqlsrv/pdo_fetch_variants_diff_styles.phpt index 2aacac59..311538ab 100644 --- a/test/functional/pdo_sqlsrv/pdo_fetch_variants_diff_styles.phpt +++ b/test/functional/pdo_sqlsrv/pdo_fetch_variants_diff_styles.phpt @@ -13,114 +13,127 @@ hierarchyid geometry datetimeoffset User-defined types +--SKIPIF-- + --FILE-- exec("CREATE TABLE $tableName ([c1_int] sql_variant, [c2_tinyint] sql_variant, [c3_smallint] sql_variant, [c4_bigint] sql_variant, [c5_bit] sql_variant, [c6_float] sql_variant, [c7_real] sql_variant, [c8_decimal] sql_variant, [c9_numeric] sql_variant, [c10_money] sql_variant, [c11_smallmoney] sql_variant, [c12_char] sql_variant, [c13_varchar] sql_variant, [c14_nchar] sql_variant, [c15_nvarchar] sql_variant, [c16_binary] sql_variant, [c17_varbinary] sql_variant, [c18_uniqueidentifier] sql_variant, [c19_datetime] sql_variant, [c20_smalldatetime] sql_variant, [c21_time] sql_variant, [c22_date] sql_variant, [c23_datetime2] sql_variant)"); - } - catch (Exception $e) - { + try { + $colArr = array("c1_int" => "sql_variant", + "c2_tinyint" => "sql_variant", + "c3_smallint" => "sql_variant", + "c4_bigint" => "sql_variant", + "c5_bit" => "sql_variant", + "c6_float" => "sql_variant", + "c7_real" => "sql_variant", + "c8_decimal" => "sql_variant", + "c9_numeric" => "sql_variant", + "c10_money" => "sql_variant", + "c11_smallmoney" => "sql_variant", + "c12_char" => "sql_variant", + "c13_varchar" => "sql_variant", + "c14_nchar" => "sql_variant", + "c15_nvarchar" => "sql_variant", + "c16_binary" => "sql_variant", + "c17_varbinary" => "sql_variant", + "c18_uniqueidentifier" => "sql_variant", + "c19_datetime" => "sql_variant", + "c20_smalldatetime" => "sql_variant", + "c21_time" => "sql_variant", + "c22_date" => "sql_variant", + "c23_datetime2" => "sql_variant"); + createTable($conn, $tableName, $colArr); + } catch (Exception $e) { echo "Failed to create a test table\n"; echo $e->getMessage(); - } + } } -function InsertData($conn, $tableName, $numRows) +function insertData($conn, $tableName, $numRows) { - try - { - for ($i = 1; $i <= $numRows; $i++) - { - $stmt = $conn->query(GetQuery($tableName, $i)); - } - } - catch (Exception $e) - { + try { + for ($i = 1; $i <= $numRows; $i++) { + $stmt = $conn->query(getQuery($tableName, $i)); + } + } catch (Exception $e) { echo "Failed to populate the test table\n"; echo $e->getMessage(); - } + } } -function Fetch_BoundMixed($conn, $tableName, $numRows) +function fetchBoundMixed($conn, $tableName, $numRows) { - $query = "SELECT * FROM $tableName ORDER BY c1_int"; - - $stmt = $conn->query($query); - $numCols = $stmt->columnCount(); + $query = "SELECT * FROM $tableName ORDER BY c1_int"; + + $stmt = $conn->query($query); + $numCols = $stmt->columnCount(); $cols = array_fill(0, 23, null); - $stmt->bindColumn('c1_int', $cols[0]); - $stmt->bindColumn('c2_tinyint', $cols[1]); - $stmt->bindColumn(3, $cols[2]); - $stmt->bindColumn(4, $cols[3]); - $stmt->bindColumn(5, $cols[4]); - $stmt->bindColumn(6, $cols[5]); - $stmt->bindColumn(7, $cols[6]); - $stmt->bindColumn(8, $cols[7]); - $stmt->bindColumn('c9_numeric', $cols[8]); - $stmt->bindColumn('c10_money', $cols[9]); - $stmt->bindColumn('c11_smallmoney', $cols[10]); - $stmt->bindColumn('c12_char', $cols[11]); - $stmt->bindColumn(13, $cols[12]); - $stmt->bindColumn(14, $cols[13]); - $stmt->bindColumn('c15_nvarchar', $cols[14]); - $stmt->bindColumn('c16_binary', $cols[15]); - $stmt->bindColumn(17, $cols[16]); - $stmt->bindColumn('c18_uniqueidentifier', $cols[17]); - $stmt->bindColumn(19, $cols[18]); - $stmt->bindColumn(20, $cols[19]); - $stmt->bindColumn(21, $cols[20]); - $stmt->bindColumn(22, $cols[21]); - $stmt->bindColumn('c23_datetime2', $cols[22]); + $stmt->bindColumn('c1_int', $cols[0]); + $stmt->bindColumn('c2_tinyint', $cols[1]); + $stmt->bindColumn(3, $cols[2]); + $stmt->bindColumn(4, $cols[3]); + $stmt->bindColumn(5, $cols[4]); + $stmt->bindColumn(6, $cols[5]); + $stmt->bindColumn(7, $cols[6]); + $stmt->bindColumn(8, $cols[7]); + $stmt->bindColumn('c9_numeric', $cols[8]); + $stmt->bindColumn('c10_money', $cols[9]); + $stmt->bindColumn('c11_smallmoney', $cols[10]); + $stmt->bindColumn('c12_char', $cols[11]); + $stmt->bindColumn(13, $cols[12]); + $stmt->bindColumn(14, $cols[13]); + $stmt->bindColumn('c15_nvarchar', $cols[14]); + $stmt->bindColumn('c16_binary', $cols[15]); + $stmt->bindColumn(17, $cols[16]); + $stmt->bindColumn('c18_uniqueidentifier', $cols[17]); + $stmt->bindColumn(19, $cols[18]); + $stmt->bindColumn(20, $cols[19]); + $stmt->bindColumn(21, $cols[20]); + $stmt->bindColumn(22, $cols[21]); + $stmt->bindColumn('c23_datetime2', $cols[22]); $stmt2 = $conn->query($query); - - // compare data values + + // compare data values $row = 1; - while ($result = $stmt->fetch(PDO::FETCH_BOUND)) - { + while ($result = $stmt->fetch(PDO::FETCH_BOUND)) { echo "Comparing data in row $row\n"; - + $obj = $stmt2->fetch(PDO::FETCH_LAZY); - if (! $obj) + if (! $obj) { echo "Failed to fetch data as object\n"; - + } + $j = 0; - foreach ($cols as $value1) - { + foreach ($cols as $value1) { $col = $j+1; - $value2 = GetValueFromObject($obj, $col); - DoValuesMatched($value1, $value2, $row, $col); - + $value2 = getValueFromObject($obj, $col); + doValuesMatched($value1, $value2, $row, $col); + $j++; } - + $row++; } - + $noActualRows = $row - 1; - if ($noActualRows != $numRows) - { + if ($noActualRows != $numRows) { echo "Number of Actual Rows $noActualRows is unexpected!\n"; } - - $stmt = null; - $stmt2 = null; - + + unset($stmt); + unset($stmt2); + return $numCols; } -function GetValueFromObject($obj, $col) +function getValueFromObject($obj, $col) { - switch ($col) - { + switch ($col) { case 1: return $obj->c1_int; case 2: return $obj->c2_tinyint; case 3: return $obj->c3_smallint; @@ -145,99 +158,88 @@ function GetValueFromObject($obj, $col) case 22: return $obj->c22_date; case 23: return $obj->c23_datetime2; default: return null; - } + } } -function DoValuesMatched($value1, $value2, $row, $col) +function doValuesMatched($value1, $value2, $row, $col) { $matched = ($value1 === $value2); - if (! $matched) - { + if (! $matched) { echo "Values from row $row and column $col do not matched\n"; echo "One is $value1 but the other is $value2\n"; - } + } } -function Fetch_Columns($conn, $tableName, $numRows, $numCols) +function fetchColumns($conn, $tableName, $numRows, $numCols) { - try - { - // insert column data from a row of the original table - $stmtOriginal = $conn->prepare("SELECT * FROM $tableName WHERE c1_int = :row"); - - for ($i = 1; $i <= $numRows; $i++) - { + try { + // insert column data from a row of the original table + $stmtOriginal = $conn->prepare("SELECT * FROM $tableName WHERE c1_int = :row"); + + for ($i = 1; $i <= $numRows; $i++) { $c1_int = $i; - - echo "Insert all columns from row $c1_int into one column of type sql_variant\n"; + + echo "Insert all columns from row $c1_int into one column of type sql_variant\n"; $stmtOriginal->bindValue(':row', $c1_int, PDO::PARAM_INT); // create another temporary test table $name = 'row' . $c1_int; - $tmpTable = GetTempTableName($name); - $conn->exec("CREATE TABLE $tmpTable ([id] int identity(1, 1), [value] sql_variant)"); - + $tmpTable = getTableName($name); + createTable($conn, $tmpTable, array(new ColumnMeta("int", "id", "identity(1, 1)"), "value" => "sql_variant")); + // change $c1_int now should not affect the results $c1_int = 'DummyValue'; - + $stmtTmp = $conn->prepare("INSERT INTO $tmpTable ([value]) VALUES (?)"); - for ($j = 0; $j < $numCols; $j++) - { + for ($j = 0; $j < $numCols; $j++) { $stmtOriginal->execute(); $value = $stmtOriginal->fetchColumn($j); - + // insert this value into the only column in the new table - $stmtTmp->bindParam($j + 1, $value, PDO::PARAM_STR); + $stmtTmp->bindParam(1, $value, PDO::PARAM_STR); $res = $stmtTmp->execute(); - if (! $res) + if (! $res) { echo "Failed to insert data from column ". $j +1 ."\n"; - + } } // now select them all and compare $stmtTmp = $conn->query("SELECT value FROM $tmpTable ORDER BY [id]"); $metadata = $stmtTmp->getColumnMeta(0); var_dump($metadata['sqlsrv:decl_type']); - + $results = $stmtTmp->fetchAll(PDO::FETCH_COLUMN); - + $stmtOriginal->execute(); $arrays = $stmtOriginal->fetchAll(PDO::FETCH_ASSOC); $columns = $arrays[0]; // only the first set is needed - + $j = 0; - foreach ($columns as $column) - { - if ($j == 0) - { + foreach ($columns as $column) { + if ($j == 0) { $val = sprintf('%d', $i); - DoValuesMatched($results[$j], $val, $i, $j+1); - } - else - { - DoValuesMatched($results[$j], $column, $i, $j+1); + doValuesMatched($results[$j], $val, $i, $j+1); + } else { + doValuesMatched($results[$j], $column, $i, $j+1); } $j++; } - - $stmtTmp = null; + + unset($stmtTmp); } - } - catch (Exception $e) - { + } catch (Exception $e) { echo "Failed in creating a table with a single column of sql_variant\n"; echo $e->getMessage(); } - - $stmtOriginal = null; + + unset($stmtOriginal); } -function GetQuery($tableName, $index) +function getQuery($tableName, $index) { $query = ""; - switch ($index) - { + switch ($index) { case 1: $query = "INSERT INTO $tableName ([c1_int], [c2_tinyint], [c3_smallint], [c4_bigint], [c5_bit], [c6_float], [c7_real], [c8_decimal], [c9_numeric], [c10_money], [c11_smallmoney], [c12_char], [c13_varchar], [c14_nchar], [c15_nvarchar], [c16_binary], [c17_varbinary], [c18_uniqueidentifier], [c19_datetime], [c20_smalldatetime], [c21_time], [c22_date], [c23_datetime2]) VALUES ((1), (110), (-28270), (804279686), (0), (0), (null), (-100000000000000000000000), (0.6685), (0.2997), (0.5352), ('äðubý/ö*bUah¢AoÖrZÃ_oßoüöÐ>ßÄßUAüîÖh_u*uh.uå:,öî@UCO,<¢<:Ö@>+ß,ªåÜbrª¢öãäo,ü£/b,|ýãý~öߣîUö_¢ªðu.+ýÃhAaäzvzrb£ßAÃhö,ö.aöü/Z+Ã.uvUo~v:+u_ýý©z¢ª|U/îã<©|vý+bÐÄЩoðbbüðb_~*î..üÐÃz,äAðß~Ö¢Äå~ð.£_ßzãÖv~¢£Oå*@|UozU©Ð+ãÄÐ,*Z/vA>ªOÄ,¢bhý/ÖÖuäAoü.a@@ßaðvbaߣ@v,ub+Oä@oBBÖöAüßö|Ö~hhvbuäo/<Ã+£¢Ã¢ß>'), ('Z:Uî/ÜãýüÄzãüvä/Ühý£||ãoå,ªÜ©uÖ_.>ßýbåää|üð/ý.BO:ZCu©ß<£ªãÄ@ýß©vöß:>:ä+åvCBª£.o>Z/*,B_å~AO,rO+åÖZ£>rö¢Ð~ðuö_Ðä'), (N''), (N'ZªC|©v¢Äß~Uh¢£o>ªvª,~Öß@@Oß*BOOöA_¢AªðßäªåaB~ÖABhbääbCÃ_Ü¢A>>vª¢,zBBahåÃ>ÐÜÃÖÐðÜhÄrb*zåðãbUýåZ,*v,ÄU£öbýoO,**ýßbÃv+Üb|Zb:OUöîåßO*:/,'), (0xF502D70F2F74A32894021775707AEE3D8601A0E601FF565636A220DBFE213F3B143FA70B33712EC31501D0202A6125E5EA13FCD7F33991F6AC80D88D53C82A73C3DB6130D3E20914D2DDD1002E352BD57D3AF1EA246748DBADB05FB398A16F4DD75D5D4F00F4120709E704166891C77755030F18D63F4F5C9386822283567B316D8328D0D8DCD58828E9E13C6232731CE9E85D95915676980E01BB7A), (0xB36CD3A8E468F69E792D86F0ED5E12F9611266399BF8E6A0160D90C2D6205B1638642DD08F898EB3F249E4670A66883AFB075A670CB6E9BA853292D7D834C758D270B889304269D884B24751147E95B08456C6CFC6F40A817B734A5CF7B6DBBD818C959AADFF09B99D82E2596F97A6079CE153816DF892DE65370DBDF80DE0CDD689D087E9FB03844C0D314311B012E3CC43BF15635A4F88FAB63475F14CC090A11583E5C61E1DA1DECE3460C64ECDB4252AF0B54DCB697C39488D33C68D93004CA1A2FC2D2C1DAD251E379525EFC1ACE98050C75B0B42D6AB06AB7E91EADA503B331325ABD186F80C42902F94D4564986E14A463DCBA5415ECC5026809E1C3A43E65AF1DC9C0017F957BA187B1341D6AF61F8AFA09412), ('00000000-0000-0000-0000-000000000000'), ('2819-01-08 00:12:52.445'), ('2079-06-06 23:59:00'), ('03:46:33.6181920'), ('2148-04-25'), ('0269-03-15 01:59:43.6050438'))"; break; @@ -250,47 +252,29 @@ function GetQuery($tableName, $index) return $query; } -function RunTest() -{ - StartTest("pdo_fetch_variants_diff_styles"); - try - { - include("MsSetup.inc"); +try { + // Connect + $conn = connect(); + $tableName = getTableName(); + createTestTable($conn, $tableName); - // Connect - $conn = new PDO( "sqlsrv:server=$server;Database=$databaseName", $uid, $pwd); - $conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); + $numRows = 2; + insertData($conn, $tableName, $numRows); - $tableName = GetTempTableName(); - CreateTestTable($conn, $tableName); - - $numRows = 2; - InsertData($conn, $tableName, $numRows); - - $numCols = Fetch_BoundMixed($conn, $tableName, $numRows); - Fetch_Columns($conn, $tableName, $numRows, $numCols); + $numCols = fetchBoundMixed($conn, $tableName, $numRows); + fetchColumns($conn, $tableName, $numRows, $numCols); - $conn = null; - } - catch (Exception $e) - { - echo $e->getMessage(); - } - echo "\nDone\n"; - EndTest("pdo_fetch_variants_diff_styles"); + dropTable($conn, $tableName); + unset($conn); +} catch (Exception $e) { + echo $e->getMessage(); } -RunTest(); - ?> --EXPECT-- - Comparing data in row 1 Comparing data in row 2 Insert all columns from row 1 into one column of type sql_variant string(11) "sql_variant" Insert all columns from row 2 into one column of type sql_variant string(11) "sql_variant" - -Done -Test "pdo_fetch_variants_diff_styles" completed successfully. \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_katmai_special_types.phpt b/test/functional/pdo_sqlsrv/pdo_katmai_special_types.phpt index 17ccd16b..fc6ff687 100644 --- a/test/functional/pdo_sqlsrv/pdo_katmai_special_types.phpt +++ b/test/functional/pdo_sqlsrv/pdo_katmai_special_types.phpt @@ -1,150 +1,177 @@ --TEST-- Test various Katmai types, like geography, geometry, hierarchy, sparse, etc. and fetch them back as strings --SKIPIF-- - + --FILE-- exec("CREATE TABLE $tableName ([c1_time] time, [c2_date] date, [c3_datetimeoffset] datetimeoffset, [c4_geography] geography, [c5_geometry] geometry, [c6_hierarchyid] hierarchyid, [c7_uniqueidentifier] uniqueidentifier ROWGUIDCOL NOT NULL UNIQUE DEFAULT NEWID())"); - $stmt = null; - - $query = "INSERT INTO $tableName ([c1_time], [c2_date], [c3_datetimeoffset], [c4_geography], [c5_geometry], [c6_hierarchyid], [c7_uniqueidentifier]) VALUES (('03:32:25.5643401'), ('1439-01-10'), ('0221-01-12 06:39:07.0620256+00:00'), ('POINT(27.91 -76.74)'), ('LINESTRING(30.50 -0.66, 31.03 -0.38)'), ('/1/3/'), ('5a1a88f7-3749-46a3-8a7a-efae73efe88f'))"; - $stmt = $conn->query($query); - $stmt = null; - - echo "\nShowing results of Katmai basic fields\n"; - - $stmt = $conn->query("SELECT * FROM $tableName"); - $numFields = $stmt->columnCount(); - $cols = array_fill(0, $numFields, ""); - - for ($i = 0; $i < $numFields; $i++) - { - $stmt->bindColumn($i+1, $cols[$i]); - } - - $stmt->fetch(PDO::FETCH_BOUND); - for ($i = 0; $i < $numFields; $i++) - { - $value = $cols[$i]; - if ($i >= 3) - { - if ($value != null) - $value = bin2hex($value); + $tableName = getTableName(); + $dataTypes = array("c1_time" => "time", + "c2_date" => "date", + "c3_datetimeoffset" => "datetimeoffset", + "c4_geography" => "geography", + "c5_geometry" => "geometry", + "c6_hierarchyid" => "hierarchyid", + new ColumnMeta("uniqueidentifier", "c7_uniqueidentifier", "ROWGUIDCOL NOT NULL UNIQUE DEFAULT NEWID()")); + $data = array("c1_time" => '03:32:25.5643401', + "c2_date" => '1439-01-10', + "c3_datetimeoffset" => '0221-01-12 06:39:07.0620256+00:00', + "c4_geography" => 'POINT(27.91 -76.74)', + "c5_geometry" => 'LINESTRING(30.50 -0.66, 31.03 -0.38)', + "c6_hierarchyid" => '/1/3/', + "c7_uniqueidentifier" => '5a1a88f7-3749-46a3-8a7a-efae73efe88f'); + $expOutput = array("c1_time" => '03:32:25.5643401', + "c2_date" => '1439-01-10', + "c3_datetimeoffset" => '0221-01-12 06:39:07.0620256 +00:00', + "c4_geography" => 'e6100000010c8fc2f5285c2f53c0295c8fc2f5e83b40', + "c5_geometry" => '0000000001140000000000803e401f85eb51b81ee5bf48e17a14ae073f4052b81e85eb51d8bf', + "c6_hierarchyid" => '5bc0', + "c7_uniqueidentifier" => '35413141383846372d333734392d343641332d384137412d454641453733454645383846'); + + if (isColEncrypted()) { + // remove these types from tests because these types require direct query for the data to be inserted + // and the insertRow common function uses bind parameters to insertion when column encryption is enabled + $toRemove = array("c4_geography", "c5_geometry", "c6_hierarchyid"); + foreach ($toRemove as $key) { + unset($dataTypes[$key]); + unset($data[$key]); + unset($expOutput[$key]); } + } + $expOutput = array_values($expOutput); + createTable($conn, $tableName, $dataTypes); + insertRow($conn, $tableName, $data); + echo "Comparing results of Katmai basic fields\n"; - var_dump($value); - } + $stmt = $conn->query("SELECT * FROM $tableName"); + $numFields = $stmt->columnCount(); + $cols = array_fill(0, $numFields, ""); + + for ($i = 0; $i < $numFields; $i++) { + $stmt->bindColumn($i+1, $cols[$i]); + } + + $stmt->fetch(PDO::FETCH_BOUND); + for ($i = 0; $i < $numFields; $i++) { + $value = $cols[$i]; + if ($i >= 3) { + if ($value != null) { + $value = bin2hex($value); + } + } + if ($value !== $expOutput[$i]) { + echo "Unexpected output retrieved.\n"; + var_dump($value); + } + } + dropTable($conn, $tableName); } -function Katmai_SparseChar($conn) +function katmaiSparseChar($conn) { - $tableName = GetTempTableName(); - - $stmt = $conn->exec("CREATE TABLE $tableName (c1 int, c2 char(512) SPARSE NULL, c3 varchar(512) SPARSE NULL, c4 varchar(max) SPARSE NULL, c5 nchar(512) SPARSE NULL, c6 nvarchar(512) SPARSE NULL, c7 nvarchar(max) SPARSE NULL)"); - $stmt = null; + $tableName = getTableName(); + + // Sparse column set is not supported for Always Encrypted + $options = ""; + if (!isColEncrypted()) { + $options = "SPARSE NULL"; + } + $dataTypes = array("c1" => "int", + new ColumnMeta("char(512)", "c2", $options), + new ColumnMeta("char(512)", "c3", $options), + new ColumnMeta("varchar(max)", "c4", $options), + new ColumnMeta("nchar(512)", "c5", $options), + new ColumnMeta("nvarchar(512)", "c6", $options), + new ColumnMeta("nvarchar(max)", "c7", $options)); + createTable($conn, $tableName, $dataTypes); $input = "The quick brown fox jumps over the lazy dog"; - $stmt = $conn->query("INSERT INTO $tableName (c1, c2, c5) VALUES(1, 'The quick brown fox jumps over the lazy dog', 'The quick brown fox jumps over the lazy dog')"); - $stmt = null; - $stmt = $conn->query("INSERT INTO $tableName (c1, c3, c6) VALUES(2, 'The quick brown fox jumps over the lazy dog', 'The quick brown fox jumps over the lazy dog')"); - $stmt = null; - $stmt = $conn->query("INSERT INTO $tableName (c1, c4, c7) VALUES(3, 'The quick brown fox jumps over the lazy dog', 'The quick brown fox jumps over the lazy dog')"); - $stmt = null; - - echo "\nComparing results of Katmai sparse fields\n"; - $stmt = $conn->query("SELECT * FROM $tableName"); - - while ($row = $stmt->fetch(PDO::FETCH_NUM)) - { + insertRow($conn, $tableName, array("c1" => 1, "c2" => $input, "c5" => $input)); + insertRow($conn, $tableName, array("c1" => 2, "c3" => $input, "c6" => $input)); + insertRow($conn, $tableName, array("c1" => 3, "c4" => $input, "c7" => $input)); + + echo "Comparing results of Katmai sparse fields\n"; + $stmt = $conn->query("SELECT * FROM $tableName"); + + while ($row = $stmt->fetch(PDO::FETCH_NUM)) { $fld1 = $row[0]; $fld2 = $fld1 + 3; - + $value1 = $row[$fld1]; $value2 = $row[$fld2]; - if ($input !== trim($value1)) - { + if ($input !== trim($value1)) { echo "The value is unexpected!\n"; } - if ($value1 !== $value2) - { + // trimming is required since SPARSE is not supported for encrypted columns + if (trim($value1) !== trim($value2)) { echo "The values don't match!\n"; } } + dropTable($conn, $tableName); } -function Katmai_SparseNumeric($conn) +function katmaiSparseNumeric($conn) { - $tableName = GetTempTableName(); - - $stmt = $conn->exec("CREATE TABLE $tableName (c1 int, c2 int SPARSE NULL, c3 tinyint SPARSE NULL, c4 smallint SPARSE NULL, c5 bigint SPARSE NULL, c6 bit SPARSE NULL, c7 float SPARSE NULL, c8 real SPARSE NULL, c9 decimal(28,4) SPARSE NULL, c10 numeric(32,4) SPARSE NULL)"); - - $stmt = $conn->query("INSERT INTO $tableName (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10) VALUES(1, '1', '1', '1', '1', '1', '1', '1', '1', '1')"); - $stmt = null; - - echo "\nShowing results of Katmai sparse numeric fields\n"; - $stmt = $conn->query("SELECT * FROM $tableName"); - $row = $stmt->fetch(PDO::FETCH_NUM); - foreach ($row as $value) - { + $tableName = getTableName(); + + // Sparse column set is not supported for Always Encrypted + $options = ""; + if (!isColEncrypted()) { + $options = "SPARSE NULL"; + } + + $dataTypes = array("c1" => "int", + new ColumnMeta("int", "c2", $options), + new ColumnMeta("tinyint", "c3", $options), + new ColumnMeta("smallint", "c4", $options), + new ColumnMeta("bigint", "c5", $options), + new ColumnMeta("bit", "c6", $options), + new ColumnMeta("float", "c7", $options), + new ColumnMeta("real", "c8", $options), + new ColumnMeta("decimal(28,4)", "c9", $options), + new ColumnMeta("numeric(32,4)", "c10", $options)); + createTable($conn, $tableName, $dataTypes); + + $data = array("c1" => 1); + for ($i = 1; $i < 10; $i++) { + $colName = "c" . strval($i+1); + $data[$colName] = '1'; + } + insertRow($conn, $tableName, $data); + + echo "Showing results of Katmai sparse numeric fields\n"; + $stmt = $conn->query("SELECT * FROM $tableName"); + $row = $stmt->fetch(PDO::FETCH_NUM); + foreach ($row as $value) { var_dump($value); - } + } + dropTable($conn, $tableName); } //-------------------------------------------------------------------- // Repro // //-------------------------------------------------------------------- -function Repro() -{ - StartTest("pdo_katmai_special_types"); - echo "\nStarting test...\n"; - try - { - include("MsSetup.inc"); - set_time_limit(0); - - $conn = new PDO( "sqlsrv:server=$server;database=$databaseName", $uid, $pwd); - - Katmai_Basic_Types($conn); - Katmai_SparseChar($conn); - Katmai_SparseNumeric($conn); +try { + $conn = connect(); - $conn = null; - } - catch (Exception $e) - { - echo $e->getMessage(); - } - echo "\nDone\n"; - - EndTest("pdo_katmai_special_types"); + katmaiBasicTypes($conn); + katmaiSparseChar($conn); + katmaiSparseNumeric($conn); + + unset($conn); +} catch (Exception $e) { + echo $e->getMessage(); } - -Repro(); - ?> + --EXPECT-- - -Starting test... - -Showing results of Katmai basic fields -string(16) "03:32:25.5643401" -string(10) "1439-01-10" -string(34) "0221-01-12 06:39:07.0620256 +00:00" -string(44) "e6100000010c8fc2f5285c2f53c0295c8fc2f5e83b40" -string(76) "0000000001140000000000803e401f85eb51b81ee5bf48e17a14ae073f4052b81e85eb51d8bf" -string(4) "5bc0" -string(72) "35413141383846372d333734392d343641332d384137412d454641453733454645383846" - +Comparing results of Katmai basic fields Comparing results of Katmai sparse fields - Showing results of Katmai sparse numeric fields string(1) "1" string(1) "1" @@ -156,6 +183,3 @@ string(3) "1.0" string(3) "1.0" string(6) "1.0000" string(6) "1.0000" - -Done -Test "pdo_katmai_special_types" completed successfully. \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_param_output_select_variant.phpt b/test/functional/pdo_sqlsrv/pdo_param_output_select_variant.phpt index 9c3dfff3..035fd715 100644 --- a/test/functional/pdo_sqlsrv/pdo_param_output_select_variant.phpt +++ b/test/functional/pdo_sqlsrv/pdo_param_output_select_variant.phpt @@ -1,85 +1,94 @@ --TEST-- -Test sql_variant as an output parameter +Test sql_variant as an output parameter --DESCRIPTION-- -Since output param is not supported for sql_variant columns, this test verifies a proper error message is returned +Since output param is not supported for sql_variant columns, this test verifies a proper error message is returned +--SKIPIF-- + --FILE-- prepare("SELECT ? = COUNT(* ) FROM $tableName"); - $stmt->bindParam( 1, $count, PDO::PARAM_INT, 4 ); - $stmt->execute(); - echo "Number of rows: $count\n"; + if (!isAEConnected()) { + $stmt = $conn->prepare("SELECT ? = COUNT(* ) FROM $tableName"); + $stmt->bindParam(1, $count, PDO::PARAM_INT, 4); + $stmt->execute(); + } else { + $stmt = $conn->prepare("SELECT COUNT(*) FROM $tableName"); + $stmt->execute(); + $count = $stmt->fetch()[0]; + } + echo "Number of rows: $count\n"; $value = 'xx'; - - $stmt = $conn->prepare("SELECT ? = c2_variant FROM $tableName"); - $stmt->bindParam( 1, $value, PDO::PARAM_STR, 50 ); - $stmt->execute(); - echo "Variant column: $value\n\n"; - + + $stmt = $conn->prepare("SELECT ? = c2_variant FROM $tableName"); + $stmt->bindParam(1, $value, PDO::PARAM_STR, 50); + $stmt->execute(); + echo "Variant column: $value\n\n"; } -function CreateVariantTable($conn, $tableName) +function createVariantTable($conn, $tableName) { - try - { - $stmt = $conn->exec("CREATE TABLE [$tableName] ([c1_int] int, [c2_variant] sql_variant)"); - } - catch (Exception $e) - { + try { + createTable($conn, $tableName, array("c1_int" => "int", "c2_variant" => "sql_variant")); + } catch (Exception $e) { echo "Failed to create a test table\n"; echo $e->getMessage(); - } + } - $tsql = "INSERT INTO [$tableName] ([c1_int], [c2_variant]) VALUES (1, ?)"; - $data = "This is to test if sql_variant works with output parameters"; - - $stmt = $conn->prepare($tsql); - $result = $stmt->execute(array($data)); - if (! $result) + if (!isColEncrypted()) { + $tsql = "INSERT INTO [$tableName] ([c1_int], [c2_variant]) VALUES (1, ?)"; + $stmt = $conn->prepare($tsql); + $result = $stmt->execute(array($data)); + } else { + $tsql = "INSERT INTO [$tableName] ([c1_int], [c2_variant]) VALUES (?, ?)"; + $stmt = $conn->prepare($tsql); + $intData = 1; + $result = $stmt->execute(array($intData, $data)); + } + + if (! $result) { echo "Failed to insert data\n"; + } } -function RunTest() +function checkError($e, $expMsg, $aeExpMsg) { - StartTest("pdo_param_output_select_variant"); - try - { - include("MsSetup.inc"); - // Connect - $conn = new PDO( "sqlsrv:server=$server;Database=$databaseName", $uid, $pwd); - $conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); - echo "\n"; - - // Now test with another stored procedure - $tableName = GetTempTableName(); - CreateVariantTable($conn, $tableName); - - // Test a simple select to get output - TestSimpleSelect($conn, $tableName); - - $conn = null; + $error = $e->getMessage(); + if (!isAEConnected()) { + if (strpos($error, $expMsg) === false) echo $error; + } else { + if (strpos($error, $aeExpMsg) === false) echo $error; } - catch (Exception $e) - { - echo $e->getMessage(); - } - echo "\nDone\n"; - EndTest("pdo_param_output_select_variant"); } -RunTest(); +try { + // Connect + $conn = connect(); + + // Now test with another stored procedure + $tableName = getTableName(); + createVariantTable($conn, $tableName); + + // Test a simple select to get output + testSimpleSelect($conn, $tableName); + + dropTable($conn, $tableName); + unset($conn); +} catch (Exception $e) { + // binding parameters in the select list is not supported with Column Encryption + $expMsg = "Implicit conversion from data type sql_variant to nvarchar(max) is not allowed. Use the CONVERT function to run this query."; + $aeExpMsg = "Invalid Descriptor Index"; + checkError($e, $expMsg, $aeExpMsg); +} +echo "Done\n"; ?> ---EXPECTREGEX-- - -Number of rows: 1 -SQLSTATE\[42000\]: \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Implicit conversion from data type sql_variant to nvarchar\(max\) is not allowed. Use the CONVERT function to run this query. +--EXPECT-- +Number of rows: 1 Done -Test \"pdo_param_output_select_variant\" completed successfully\. diff --git a/test/functional/pdo_sqlsrv/pdo_param_output_variants.phpt b/test/functional/pdo_sqlsrv/pdo_param_output_variants.phpt index 0749c1e1..782ed15a 100644 --- a/test/functional/pdo_sqlsrv/pdo_param_output_variants.phpt +++ b/test/functional/pdo_sqlsrv/pdo_param_output_variants.phpt @@ -1,140 +1,115 @@ --TEST-- Test parametrized insert and sql_variant as an output parameter. --DESCRIPTION-- -Since output param is not supported for sql_variant columns, this test verifies a proper error message is returned +Since output param is not supported for sql_variant columns, this test verifies a proper error message is returned --FILE-- exec($spCode); - } - catch (Exception $e) - { + $conn->exec($spCode); + } catch (Exception $e) { echo "Failed to create the reverse procedure\n"; echo $e->getMessage(); - } - - try - { - $stmt = $conn->prepare("{ CALL [$procName] (?) }"); + } + try { + $stmt = $conn->prepare("{ CALL [$procName] (?) }"); $string = "123456789"; - $stmt->bindParam(1, $string, PDO::PARAM_STR, 30); + $stmt->bindParam(1, $string, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 30); $stmt->execute(); - echo "Does REVERSE work? $string \n"; - } - catch (Exception $e) - { + // Connection with Column Encryption enabled works for non encrypted SQL_VARIANT + // Since SQLDescribeParam is called + if (isAEConnected() && $string === "987654321") { + echo "Testing input output parameter with SQL_VARIANT is successful.\n"; + + } else { + echo "Does REVERSE work? $string \n"; + } + } catch (Exception $e) { //echo "Failed when calling the reverse procedure\n"; - echo $e->getMessage(); - echo "\n"; - } -} - -function CreateVariantTable($conn, $tableName) -{ - try - { - $stmt = $conn->exec("CREATE TABLE [$tableName] ([c1_int] int, [c2_variant] sql_variant)"); + $error = $e->getMessage(); + if (!isAEConnected() && strpos($error, "Implicit conversion from data type sql_variant to nvarchar is not allowed.") !== false) { + echo "Testing input output parameter with SQL_VARIANT is successful.\n"; + } else { + echo "$error\n"; + } } - catch (Exception $e) - { +} +function createVariantTable($conn, $tableName) +{ + try { + createTable($conn, $tableName, array("c1_int" => "int", "c2_variant" => "sql_variant")); + } catch (Exception $e) { echo "Failed to create a test table\n"; echo $e->getMessage(); - } - - $tsql = "INSERT INTO [$tableName] ([c1_int], [c2_variant]) VALUES (1, ?)"; - + } $data = "This is to test if sql_variant works with output parameters"; - - $stmt = $conn->prepare($tsql); - $result = $stmt->execute(array($data)); - if (! $result) + if (!isAEConnected()) { + $tsql = "INSERT INTO [$tableName] ([c1_int], [c2_variant]) VALUES (1, ?)"; + $stmt = $conn->prepare($tsql); + $result = $stmt->execute(array($data)); + } else { + $tsql = "INSERT INTO [$tableName] ([c1_int], [c2_variant]) VALUES (?, ?)"; + $stmt = $conn->prepare($tsql); + $intData = 1; + $result = $stmt->execute(array($intData, $data)); + } + if (! $result) { echo "Failed to insert data\n"; + } } - -function TestOutputParam($conn, $tableName) +function testOutputParam($conn, $tableName) { // First, create a temporary stored procedure - $procName = GetTempProcName('sqlVariant'); - + $procName = getProcName('sqlVariant'); $spArgs = "@p1 int, @p2 sql_variant OUTPUT"; $spCode = "SET @p2 = ( SELECT [c2_variant] FROM $tableName WHERE [c1_int] = @p1 )"; - - $stmt = $conn->exec("CREATE PROC [$procName] ($spArgs) AS BEGIN $spCode END"); - $stmt = null; - + $conn->exec("CREATE PROC [$procName] ($spArgs) AS BEGIN $spCode END"); $callArgs = "?, ?"; - // Data to initialize $callResult variable. This variable should be different from // the inserted data in the table $initData = "A short text"; $callResult = $initData; - - try - { + try { $stmt = $conn->prepare("{ CALL [$procName] ($callArgs)}"); $stmt->bindValue(1, 1); $stmt->bindParam(2, $callResult, PDO::PARAM_STR, 100); $stmt->execute(); - - - } - catch (Exception $e) - { - if(!strcmp($initData, $callResult)) - { + if (isAEConnected() && $callResult === "This is to test if sql_variant works with output parameters") { + echo "Testing output parameter with SQL_VARIANT is successful.\n"; + } else { + echo "Does SELECT from table work? $callResult \n"; + } + } catch (Exception $e) { + if (!strcmp($initData, $callResult)) { echo "initialized data and result should be the same"; } - echo $e->getMessage(); - echo "\n"; - } -} - -function RunTest() -{ - StartTest("pdo_param_output_variants"); - try - { - include("MsSetup.inc"); - // Connect - $conn = new PDO( "sqlsrv:server=$server;Database=$databaseName", $uid, $pwd); - $conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); - echo "\n"; - - // Test with a simple stored procedure - TestReverse($conn); - - // Now test with another stored procedure - $tableName = GetTempTableName(); - CreateVariantTable($conn, $tableName); - - TestOutputParam($conn, $tableName); - - $conn = null; + $error = $e->getMessage(); + if (!isAEConnected() && strpos($error, "Operand type clash: nvarchar(max) is incompatible with sql_variant") !== false) { + echo "Testing output parameter with SQL_VARIANT is successful.\n"; + } else { + echo "$error\n"; + } } - catch (Exception $e) - { - echo $e->getMessage(); - } - echo "\nDone\n"; - EndTest("pdo_param_output_variants"); } - -RunTest(); - +try { + // Connect + $conn = connect(); + // Test with a simple stored procedure + testReverse($conn); + // Now test with another stored procedure + $tableName = getTableName(); + createVariantTable($conn, $tableName); + testOutputParam($conn, $tableName); + $conn = null; +} catch (Exception $e) { + echo $e->getMessage(); +} ?> ---EXPECTREGEX-- - -SQLSTATE\[22018\]: \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Operand type clash: nvarchar\(max\) is incompatible with sql_variant -SQLSTATE\[22018\]: \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Operand type clash: nvarchar\(max\) is incompatible with sql_variant -Done -Test \"pdo_param_output_variants\" completed successfully\. +--EXPECT-- +Testing input output parameter with SQL_VARIANT is successful. +Testing output parameter with SQL_VARIANT is successful. \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_prepare_attribute.phpt b/test/functional/pdo_sqlsrv/pdo_prepare_attribute.phpt index 6d4422be..d0da03e1 100644 --- a/test/functional/pdo_sqlsrv/pdo_prepare_attribute.phpt +++ b/test/functional/pdo_sqlsrv/pdo_prepare_attribute.phpt @@ -3,76 +3,67 @@ Test PDO::prepare() with PDO::ATTR_EMULATE_PREPARES. --ENV-- PHPT_EXEC=true --SKIPIF-- - + --FILE-- setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); - // retrieve correct results -$s = $db->prepare( "SELECT '' + TITLE FROM cd_info GROUP BY '' + TITLE" ); - +$s = $db->prepare("SELECT '' + TITLE FROM cd_info GROUP BY '' + TITLE"); $s->execute(); $titles = array(); - -while( $r = $s->fetch()) { - - $titles[] = $r[0]; +while ($r = $s->fetch()) { + $titles[] = $r[0]; } $exception_thrown = false; try { + $s = $db->prepare('SELECT :prefix + TITLE FROM cd_info GROUP BY :prefix + TITLE'); + $s->bindValue(':prefix', ""); + $s->execute(); -$s = $db->prepare( 'SELECT :prefix + TITLE FROM cd_info GROUP BY :prefix + TITLE' ); - -$s->bindValue( ':prefix', "" ); - -$s->execute(); - -while( $r = $s->fetch()) { - - print_r( $r ); -} - -} -catch ( PDOException $e ) { - + while ($r = $s->fetch()) { + print_r($r); + } +} catch (PDOException $e) { $exception_thrown = true; } -if( !$exception_thrown ) { - - die( "Exception not thrown\nTest failed\n" ); +if (!$exception_thrown) { + die("Exception not thrown\nTest failed\n"); } -$s = $db->prepare( "SELECT :prefix + TITLE FROM cd_info GROUP BY :prefix + TITLE", - array( PDO::ATTR_EMULATE_PREPARES => true )); - -$s->bindValue( ':prefix', "" ); +// Column encryption is not supported by emulate prepared statement +$option[PDO::ATTR_EMULATE_PREPARES] = true; +if (isAEConnected()) { + $option[PDO::ATTR_EMULATE_PREPARES] = false; +} +if (!isAEConnected()) { + $s = $db->prepare("SELECT :prefix + TITLE FROM cd_info GROUP BY :prefix + TITLE", $option); + $s->bindValue(':prefix', ""); +} else { + // binding parameters in the select list is not supported with Column Encryption + $s = $db->prepare("SELECT TITLE FROM cd_info GROUP BY TITLE", $option); +} $s->execute(); $param_titles = array(); - -while( $r = $s->fetch()) { - - $param_titles[] = $r[0]; +while ($r = $s->fetch()) { + $param_titles[] = $r[0]; } -if ( $titles === $param_titles ) { +if ($titles === $param_titles) { echo "Test succeeded\n"; -} -else { - +} else { echo "Test failed\n"; - print_r( $titles ); - print_r( $param_titles ); + print_r($titles); + print_r($param_titles); } ?> diff --git a/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_binary.phpt b/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_binary.phpt index f31e0893..2fda606b 100644 --- a/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_binary.phpt +++ b/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_binary.phpt @@ -35,7 +35,7 @@ try { $cnn->exec("TRUNCATE TABLE $tbname"); //EMULATE PREPARE with SQLSRV_ENCODING_BINARY - if (!isColEncrypted()) { + if (!isAEConnected()) { // Emulate prepare does not work fro encrypted columns $pdo_options[PDO::ATTR_EMULATE_PREPARES] = true; } @@ -59,10 +59,10 @@ try { $st->bindParam(':p0', $p, PDO::PARAM_LOB); $st->execute(); $error = $st->errorInfo(); - if (!isColEncrypted() && $error[0] !== "42000") { + if (!isAEConnected() && $error[0] !== "42000") { echo "Error 42000 is expected: Implicit conversion from data type varchar to varbinary(max) is not allowed.\n"; var_dump($error); - } elseif (isColEncrypted() && $error[0] != "22018") { + } elseif (isAEConnected() && $error[0] != "22018") { echo "Error 22018 is expected: Invalid character value for cast specification.\n"; var_dump($error); } else { diff --git a/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_char.phpt b/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_char.phpt index 7776f143..569c5a7b 100644 --- a/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_char.phpt +++ b/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_char.phpt @@ -30,7 +30,7 @@ try { //prepare with emulate prepare and no bind param options print_r("Prepare with emulate prepare and no bindParam options:\n"); - if (!isColEncrypted()) { + if (!isAEConnected()) { $options = array(PDO::ATTR_EMULATE_PREPARES => true); } $stmt = $conn->prepare($query, $options); diff --git a/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_datetime.phpt b/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_datetime.phpt index 38f4c0dc..8236318f 100644 --- a/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_datetime.phpt +++ b/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_datetime.phpt @@ -29,7 +29,7 @@ try { print_r($row); //with emulate prepare and no bind param options - if (!isColEncrypted()) { + if (!isAEConnected()) { // emulate prepare is not supported in encrypted columns $options = array(PDO::ATTR_EMULATE_PREPARES => true); } diff --git a/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_decimal.phpt b/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_decimal.phpt index 48ffca2b..93899043 100644 --- a/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_decimal.phpt +++ b/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_decimal.phpt @@ -10,7 +10,7 @@ try { $conn = connect("", array(), PDO::ERRMODE_SILENT); $tableName = "number_types"; - if (!isColEncrypted()) { + if (!isAEConnected()) { createTable($conn, $tableName, array("c1_decimal" => "decimal", "c2_money" => "money", "c3_float" => "float")); } else { // money is not supported for column encryption, use decimal(19,4) instead @@ -35,7 +35,7 @@ try { //with emulate prepare and no bind param options print_r("Prepare with emulate prepare and no bind param options:\n"); - if (!isColEncrypted()) { + if (!isAEConnected()) { // emulate prepare is not supported for encrypted columns $options = array(PDO::ATTR_EMULATE_PREPARES => true); } diff --git a/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_float.phpt b/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_float.phpt index 2ac8145c..eea43902 100644 --- a/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_float.phpt +++ b/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_float.phpt @@ -10,7 +10,7 @@ try { $conn = connect("", array(), PDO::ERRMODE_SILENT); $tableName = "number_types"; - if (!isColEncrypted()) { + if (!isAEConnected()) { createTable($conn, $tableName, array("c1_decimal" => "decimal", "c2_money" => "money", "c3_float" => "float")); } else { // money is not supported for column encryption, use decimal(19,4) instead @@ -35,7 +35,7 @@ try { //with emulate prepare and no bind param options print_r("Prepare with emulate prepare and no bind param options:\n"); - if (!isColEncrypted()) { + if (!isAEConnected()) { // emulate prepare is not supported for encrypted columns $options = array(PDO::ATTR_EMULATE_PREPARES => true); } diff --git a/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_int.phpt b/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_int.phpt index 8950e244..88ec102d 100644 --- a/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_int.phpt +++ b/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_int.phpt @@ -29,7 +29,7 @@ try { // prepare with emulate prepare print_r("Prepare with emulate prepare and no bindParam options:\n"); - if (!isColEncrypted()) { + if (!isAEConnected()) { // emulate prepare is not supported for encrypted columns $options = array(PDO::ATTR_EMULATE_PREPARES => true); } @@ -39,7 +39,7 @@ try { $row = $stmt->fetch(PDO::FETCH_ASSOC); print_r($row); - if (!isColEncrypted()) { + if (!isAEConnected()) { // without emulate prepare, binding PARAM_INT with SQLSRV_ENCODING_SYSTEM is not allowed // thus the following will not be tested when Column Encryption is enabled diff --git a/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_money.phpt b/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_money.phpt index d152ed16..ee4b3699 100644 --- a/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_money.phpt +++ b/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_money.phpt @@ -10,7 +10,7 @@ try { $conn = connect("", array(), PDO::ERRMODE_SILENT); $tableName = "number_types"; - if (!isColEncrypted()) { + if (!isAEConnected()) { createTable($conn, $tableName, array("c1_decimal" => "decimal", "c2_money" => "money", "c3_float" => "float")); } else { // money is not supported for column encryption, use decimal(19,4) instead @@ -35,7 +35,7 @@ try { //with emulate prepare and no bind param options print_r("Prepare with emulate prepare and no bind param options:\n"); - if (!isColEncrypted()) { + if (!isAEConnected()) { // emulate prepare is not supported for encrypted columns $options = array(PDO::ATTR_EMULATE_PREPARES => true); } diff --git a/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_unicode.phpt b/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_unicode.phpt index 52559e4d..025f94c3 100644 --- a/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_unicode.phpt +++ b/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_unicode.phpt @@ -48,7 +48,7 @@ try { //with emulate prepare and no bind param options print_r("Prepare with emulate prepare and no bindParam options:\n"); - if (!isColEncrypted()) { + if (!isAEConnected()) { $options = array(PDO::ATTR_EMULATE_PREPARES => true); } else { $options = array(PDO::ATTR_EMULATE_PREPARES => false); @@ -70,9 +70,25 @@ try { print_r("Prepare with emulate prepare and and SQLSRV_ENCODING_SYSTEM:\n"); $stmt = prepareStmt($conn, $query, $options, PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_SYSTEM); $row = $stmt->fetch(PDO::FETCH_ASSOC); - print_r($row); - if ($stmt->rowCount() == 0) { - print_r("No results for this query\n"); + + // The combination of Column Encryption and Unix platforms support SQLSRV_ENCODING_SYSTEM because: + // With Column Encryption enabled, binding parameters uses exact datatypes as the column definition + // the default encoding in Linux and Mac is UTF8 + $success = true; + if (!(strtoupper( substr( php_uname( 's' ),0,3 ) ) === 'WIN') && isAEConnected()) { + if ($row['name'] != "가각" || $row['status'] != 1 || $row['age'] != 30) { + print_r("Incorrect results retrieved.\n"); + $success = false; + } + } else { + // the default encoding in Windows is non-UTF8, thus binding UTF8 parameters does not work + if ($stmt->rowCount() != 0) { + print_r("Binding UTF8 data when encoding is SQLSRV_ENCODING_SYSTEM should not work.\n"); + $success = false; + } + } + if ($success) { + print_r("Binding UTF8 data with SQLSRV_ENCODING_SYSTEM is tested successfully.\n"); } //with emulate prepare and encoding SQLSRV_ENCODING_BINARY @@ -110,6 +126,6 @@ Array [age] => 30 ) Prepare with emulate prepare and and SQLSRV_ENCODING_SYSTEM: -No results for this query +Binding UTF8 data with SQLSRV_ENCODING_SYSTEM is tested successfully. Prepare with emulate prepare and encoding SQLSRV_ENCODING_BINARY: No results for this query diff --git a/test/functional/pdo_sqlsrv/pdo_simple_update_variants.phpt b/test/functional/pdo_sqlsrv/pdo_simple_update_variants.phpt index c0ace417..866c5e2c 100644 --- a/test/functional/pdo_sqlsrv/pdo_simple_update_variants.phpt +++ b/test/functional/pdo_sqlsrv/pdo_simple_update_variants.phpt @@ -2,150 +2,133 @@ Test simple insert and update sql_variants using parameters of some different data categorys --DESCRIPTION-- ORDER BY should work with sql_variants +--SKIPIF-- + --FILE-- food; } - function getcategory() + public function getcategory() { return $this->category; - } + } } -function CreateVariantTable($conn, $tableName) +function createVariantTable($conn, $tableName) { - try - { - $stmt = $conn->exec("CREATE TABLE $tableName ([id] sql_variant, [food] sql_variant, [category] sql_variant)"); - } - catch (Exception $e) - { + try { + createTable($conn, $tableName, array("id" => "sql_variant", "food" => "sql_variant", "category" => "sql_variant")); + } catch (Exception $e) { echo "Failed to create a test table\n"; echo $e->getMessage(); - } + } } -function InsertData($conn, $tableName, $id, $food, $category) +function insertData($conn, $tableName, $id, $food, $category) { - try - { + try { $query = "INSERT $tableName ([id], [food], [category]) VALUES (:id, :food, :category)"; $stmt = $conn->prepare($query); $stmt->bindValue(':id', $id); $stmt->bindValue(':food', $food); $stmt->bindValue(':category', $category); - - $result = $stmt->execute(); - if ($result) - echo "\nAdded $food in $category with ID $id."; - } - catch (Exception $e) - { + + $result = $stmt->execute(); + if ($result) { + echo "Added $food in $category with ID $id.\n"; + } + } catch (Exception $e) { echo "Failed to insert food $food\n"; echo $e->getMessage(); - } + } } -function UpdateID($conn, $tableName, $id, $food, $category) +function updateID($conn, $tableName, $id, $food, $category) { $query = "UPDATE $tableName SET id = ? WHERE food = ? AND category = ?"; $stmt = $conn->prepare($query); $result = $stmt->execute(array($id, $food, $category)); - - if ($result) - echo "\nFood $food now updated with new id $id."; - else - echo "Failed to update ID.\n"; + + if ($result) { + echo "Food $food now updated with new id $id.\n"; + } else { + echo "Failed to update ID.\n"; + } } -function UpdateFood($conn, $tableName, $id, $food, $category) +function updateFood($conn, $tableName, $id, $food, $category) { $query = "UPDATE $tableName SET food = ? WHERE id = ? AND category = ?"; $stmt = $conn->prepare($query); $result = $stmt->execute(array($food, $id, $category)); - - if ($result) - echo "\nCategory $category now updated with $food."; - else - echo "Failed to update food.\n"; + + if ($result) { + echo "Category $category now updated with $food.\n"; + } else { + echo "Failed to update food.\n"; + } } -function FetchRows($conn, $tableName) +function fetchRows($conn, $tableName) { - $query = "SELECT * FROM $tableName ORDER BY id"; - - $stmt = $conn->query($query); + $query = "SELECT * FROM $tableName ORDER BY id"; + $stmt = $conn->query($query); $stmt->setFetchMode(PDO::FETCH_CLASS, 'Food'); - while ($food = $stmt->fetch()) - { - echo "\nID: " . $food->id . " "; + while ($food = $stmt->fetch()) { + echo "ID: " . $food->id . " "; echo $food->getFood() . ", "; - echo $food->getcategory(); + echo $food->getcategory() . "\n"; } - - $stmt = null; + unset($stmt); } -function RunTest() -{ - StartTest("pdo_simple_update_variants"); - try - { - include("MsSetup.inc"); - // Connect - $conn = new PDO( "sqlsrv:server=$server;Database=$databaseName", $uid, $pwd); - $conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); - $tableName = GetTempTableName(); - CreateVariantTable($conn, $tableName); - - // Add three kinds of foods - InsertData($conn, $tableName, 1, 'Milk', 'Diary Products'); - InsertData($conn, $tableName, 3, 'Chicken', 'Meat'); - InsertData($conn, $tableName, 5, 'Blueberry', 'Fruits'); - - FetchRows($conn, $tableName); - - UpdateID($conn, $tableName, 4, 'Milk', 'Diary Products'); +try { + // Connect + $conn = connect(); - FetchRows($conn, $tableName); - - UpdateFood($conn, $tableName, 4, 'Cheese', 'Diary Products'); + $tableName = getTableName(); + createVariantTable($conn, $tableName); - FetchRows($conn, $tableName); + // Add three kinds of foods + insertData($conn, $tableName, 1, 'Milk', 'Diary Products'); + insertData($conn, $tableName, 3, 'Chicken', 'Meat'); + insertData($conn, $tableName, 5, 'Blueberry', 'Fruits'); - // Add three kinds of foods - InsertData($conn, $tableName, 6, 'Salmon', 'Fish'); - InsertData($conn, $tableName, 2, 'Broccoli', 'Vegetables'); - - FetchRows($conn, $tableName); - - $conn = null; - } - catch (Exception $e) - { - echo $e->getMessage(); - } - echo "\nDone\n"; - EndTest("pdo_simple_update_variants"); + fetchRows($conn, $tableName); + + updateID($conn, $tableName, 4, 'Milk', 'Diary Products'); + + fetchRows($conn, $tableName); + + updateFood($conn, $tableName, 4, 'Cheese', 'Diary Products'); + + fetchRows($conn, $tableName); + + // Add three kinds of foods + insertData($conn, $tableName, 6, 'Salmon', 'Fish'); + insertData($conn, $tableName, 2, 'Broccoli', 'Vegetables'); + + fetchRows($conn, $tableName); + + dropTable($conn, $tableName); + unset($conn); +} catch (Exception $e) { + echo $e->getMessage(); } -RunTest(); - ?> --EXPECT-- -  -Added Milk in Diary Products with ID 1. +Added Milk in Diary Products with ID 1. Added Chicken in Meat with ID 3. Added Blueberry in Fruits with ID 5. ID: 1 Milk, Diary Products @@ -166,5 +149,3 @@ ID: 3 Chicken, Meat ID: 4 Cheese, Diary Products ID: 5 Blueberry, Fruits ID: 6 Salmon, Fish -Done -Test "pdo_simple_update_variants" completed successfully. \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_utf8_stored_proc_unicode_chars.phpt b/test/functional/pdo_sqlsrv/pdo_utf8_stored_proc_unicode_chars.phpt index 3fd9216d..dabc69c2 100644 --- a/test/functional/pdo_sqlsrv/pdo_utf8_stored_proc_unicode_chars.phpt +++ b/test/functional/pdo_sqlsrv/pdo_utf8_stored_proc_unicode_chars.phpt @@ -1,104 +1,90 @@ --TEST-- call a stored procedure with unicode input to get output back as unicode; also test with xml data --SKIPIF-- - + --FILE-- exec("CREATE PROC $procName (@p1 XML, @p2 CHAR(512) OUTPUT) AS BEGIN SELECT @p2 = CONVERT(CHAR(512), @p1) END"); - + $stmt = $conn->prepare("{CALL $procName (?, ?)}"); $stmt->bindValue(1, $inValue1); $stmt->bindParam(2, $outValue1, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 512); $stmt->execute(); - + var_dump(trim($outValue1)); - - $stmt = null; + + dropProc($conn, $procName); + unset($conn); } -function StoredProc_Surrogate($conn) +function storedProcSurrogate($conn) { $inValue1 = pack('H*', 'F2948080EFBFBDEFBFBDF48FBA83EFBFBDEFBFBDEFBFBDEFBFBDEFBFBDF48FB080EFBFBDEFBFBDEFBFBDF392A683EFBFBDF090808BF0908080F0908A83EFBFBDEFBFBDEFBFBDF48FBFBFEFBFBDEFBFBDF090808BF0908683EFBFBDF48FBFBFF2948880EFBFBDF0A08FBFEFBFBDF392A880F0A08A83F294808BF0908880EFBFBDEFBFBDEFBFBDEFBFBDF48FB080F48FB683EFBFBDF0908080EFBFBDF392AA83F48FB683EFBFBDF2948080F2948A83EFBFBDF0A08080F392A880EFBFBDF2948FBFEFBFBDEFBFBDEFBFBDEFBFBDF48FB683EFBFBDEFBFBDEFBFBDF48FBFBFF0908080EFBFBDEFBFBDEFBFBDEFBFBDF48FBFBFEFBFBDF48FB880F0908683F392A080F0908FBFEFBFBDEFBFBDEFBFBDEFBFBDEFBFBDF2948FBFEFBFBDF0908683EFBFBDF0A08A83F48FBA83EFBFBDF48FB08B'); $outValue1 = "TEST"; - - $procName = GetTempProcName(); + + $procName = getProcName(); $stmt = $conn->exec("CREATE PROC $procName (@p1 NVARCHAR(1000), @p2 NVARCHAR(1000) OUTPUT) AS BEGIN SELECT @p2 = CONVERT(NVARCHAR(1000), @p1) END"); - + $stmt = $conn->prepare("{CALL $procName (?, ?)}"); $stmt->bindValue(1, $inValue1); $stmt->bindParam(2, $outValue1, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 1000); $stmt->execute(); - - var_dump ($outValue1 === $inValue1); - - $stmt = null; + + var_dump($outValue1 === $inValue1); + + dropProc($conn, $procName); + unset($stmt); } -function StoredProc_Unicode($conn) +function storedProcUnicode($conn) { $inValue1 = pack('H*', 'E9AA8CE597BFE382A1E38381C3BDD086C39FD086C3B6C39CE3838FC3BDE8A1A4C3B6E38390C3A4C3B0C2AAE78687C3B0E2808DE6B490C4B1E385AFE382BFE9B797E9B797D79CC39FC383DAAFE382B0E597BFE382BDE382B0E58080D187C3BCE382BCE385AFD290E78687E38381C3AEE382BCE9B797E2808CC3BB69E888B3D790D291E382AFD0A7E58080C39CE69B82D291C384C3BDD196E3839DE8A1A4C3AEE382BCC3BCE8A1A4E382BFD290E2808FE38380C4B0D187C3A5E3839DE382BDE382AFC396E382B0E382BFC3B6C396D0A7E385B0E3838FC3A3C2AAD990D187C3B6C3BBC384C3B0C390D18FE382BEC4B0E382BCD086C39FE3838FE4BE83E382BCC384E382BDD79CC3BCC39FE382BFE382BCE2808DE58080E58081D196C384D794D794C3B6D18FC3AEC3B6DA98E69B82E6B490C3AEE382BEDAAFD290'); $outValue1 = "TEST"; - - $procName = GetTempProcName(); + + $procName = getProcName(); $stmt = $conn->exec("CREATE PROC $procName (@p1 NVARCHAR(MAX), @p2 NCHAR(1024) OUTPUT) AS BEGIN SELECT @p2 = CONVERT(NCHAR(1024), @p1) END"); - + $stmt = $conn->prepare("{CALL $procName (?, ?)}"); $stmt->bindValue(1, $inValue1); $stmt->bindParam(2, $outValue1, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 1500); $stmt->execute(); - + $outValue1 = trim($outValue1); - var_dump ($outValue1 === $inValue1); - - $stmt = null; + var_dump($outValue1 === $inValue1); + + dropProc($conn, $procName); + unset($stmt); } -function RunTest() -{ - StartTest("pdo_utf8_stored_proc_unicode_chars"); - echo "\nStarting test...\n"; - try - { - include("MsSetup.inc"); - set_time_limit(0); - - $conn = new PDO( "sqlsrv:server=$server;database=$databaseName", $uid, $pwd); - - StoredProc_Xml($conn); - StoredProc_Surrogate($conn); - StoredProc_Unicode($conn); +echo "Starting test...\n"; +try { + set_time_limit(0); + $conn = connect(); - $conn = null; - } - catch (Exception $e) - { - echo $e->getMessage(); - } - echo "\nDone\n"; - EndTest("pdo_utf8_stored_proc_unicode_chars"); + storedProcXml($conn); + storedProcSurrogate($conn); + storedProcUnicode($conn); + + unset($conn); +} catch (Exception $e) { + echo $e->getMessage(); } - -RunTest(); - +echo "Done\n"; ?> --EXPECT-- - Starting test... string(47) "Je préfère l'été" bool(true) bool(true) - Done -Test "pdo_utf8_stored_proc_unicode_chars" completed successfully. - diff --git a/test/functional/pdo_sqlsrv/pdostatement_bindcolumn_odd_types.phpt b/test/functional/pdo_sqlsrv/pdostatement_bindcolumn_odd_types.phpt index ad310f59..8980282f 100644 --- a/test/functional/pdo_sqlsrv/pdostatement_bindcolumn_odd_types.phpt +++ b/test/functional/pdo_sqlsrv/pdostatement_bindcolumn_odd_types.phpt @@ -1,43 +1,37 @@ --TEST-- Test the bindColumn method using PDO::PARAM_NULL and PDO::PARAM_STMT --SKIPIF-- - + --FILE-- "int", "CharCol" => "nvarchar(20)")); + insertRow($conn, $tbname, array("IntCol" => 10, "CharCol" => "ten")); -try -{ - $conn = new PDO( "sqlsrv:Server=$server; database = $databaseName ", $uid, $pwd); - $conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); - $conn->exec("IF OBJECT_ID('table1', 'U') IS NOT NULL DROP TABLE table1"); - $conn->exec("CREATE TABLE table1(IntCol INT, CharCol NVARCHAR(20)) "); - $conn->exec("INSERT INTO table1 (IntCol, CharCol) VALUES (10, 'ten')"); - $stmt = $conn->prepare("SELECT IntCol FROM table1"); $stmt->execute(); - + // PARAM_NULL returns null $stmt->bindColumn('IntCol', $intCol, PDO::PARAM_NULL); $row = $stmt->fetch(PDO::FETCH_BOUND); - if ($intCol == NULL) { + if ($intCol == null) { echo "intCol is NULL\n"; } else { echo "intCol should have been NULL\n"; } - + $stmt = $conn->prepare("SELECT CharCol FROM table1"); $stmt->execute(); - + // PARAM_STMT is not supported and should throw an exception $stmt->bindColumn('CharCol', $charCol, PDO::PARAM_STMT); $row = $stmt->fetch(PDO::FETCH_BOUND); echo "PARAM_STMT should have thrown an exception\n"; - -} -catch (PDOException $e) -{ +} catch (PDOException $e) { print_r($e->errorInfo[2]); echo "\n"; } @@ -45,4 +39,4 @@ catch (PDOException $e) ?> --EXPECT-- intCol is NULL -PDO::PARAM_STMT is not a supported parameter type. \ No newline at end of file +PDO::PARAM_STMT is not a supported parameter type. diff --git a/test/functional/pdo_sqlsrv/pdostatement_fetchmode_emulate_prepare.phpt b/test/functional/pdo_sqlsrv/pdostatement_fetchmode_emulate_prepare.phpt index f1b0e7a8..cccac782 100644 --- a/test/functional/pdo_sqlsrv/pdostatement_fetchmode_emulate_prepare.phpt +++ b/test/functional/pdo_sqlsrv/pdostatement_fetchmode_emulate_prepare.phpt @@ -1,167 +1,192 @@ --TEST-- -PDO Fetch Mode Test with emulate prepare +PDO Fetch Mode Test with emulate prepare --DESCRIPTION-- -Basic verification for "PDOStatement::setFetchMode(). +Basic verification for PDOStatement::setFetchMode. --ENV-- PHPT_EXEC=true --SKIPIF-- - + --FILE-- setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); + // Prepare test table + $tableName = "pdo_test_table"; + createTable($conn1, $tableName, array(new ColumnMeta("int", "ID", "NOT NULL PRIMARY KEY"), "Policy" => "varchar(2)", "Label" => "varchar(10)", "Budget" => "money")); - // Prepare test table - CreateTableEx($conn1, $tableName, "ID int NOT NULL PRIMARY KEY, Policy VARCHAR(2), Label VARCHAR(10), Budget MONEY", null); + try { + $res = $conn1->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); + if ($res) { + echo "setAttribute should have failed.\n\n"; + } + } catch (Exception $e) { + echo $e->getMessage() . "\n"; + } - try { - $res = $conn1->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); - if ($res) - { - echo "setAttribute should have failed.\n\n"; - } - } - catch (Exception $e) - { - echo $e->getMessage(); - } + try { + $query = "SELECT * FROM [$tableName]"; + $stmt = $conn1->query($query); + $stmt->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); + } catch (Exception $e) { + echo $e->getMessage(); + } - echo "\n"; - - try { - $query = "SELECT * FROM [$tableName]"; - $stmt = $conn1->query($query); - $stmt->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); - } - catch (Exception $e) - { - echo $e->getMessage(); - } + echo "\nStart inserting data...\n"; + $dataCols = "ID, Policy, Label"; + $query = "INSERT INTO [$tableName](ID, Policy, Label, Budget) VALUES (?, ?, ?, ?)"; + $stmtOptions = array(PDO::ATTR_EMULATE_PREPARES => false); + $stmt = $conn1->prepare($query, $stmtOptions); + for ($i = 1; $i <= 2; $i++) { + $pol = chr(64+$i); + $grp = "Group " . $i; + $budget = $i * 1000 + $i * 15; + $stmt->execute(array( $i, $pol, $grp, $budget )); + } - echo "\nStart inserting data...\n"; - $dataCols = "ID, Policy, Label"; - $query = "INSERT INTO [$tableName](ID, Policy, Label, Budget) VALUES (?, ?, ?, ?)"; - $stmt = $conn1->prepare($query, array(PDO::ATTR_EMULATE_PREPARES => true)); - $stmt = $conn1->prepare($query, array(PDO::ATTR_EMULATE_PREPARES => false)); - for ($i = 1; $i <= 2; $i++) - { - $pol = chr(64+$i); - $grp = "Group " . $i; - $budget = $i * 1000 + $i * 15; - $stmt->execute( array( $i, $pol, $grp, $budget ) ); - } + $query1 = "INSERT INTO [$tableName](ID, Policy, Label, Budget) VALUES (:col1, :col2, :col3, :col4)"; + if (!isAEConnected()) { + $stmtOptions[PDO::ATTR_EMULATE_PREPARES] = true; + } + $stmt = $conn1->prepare($query1, $stmtOptions); + for ($i = 3; $i <= 5; $i++) { + $pol = chr(64+$i); + $grp = "Group " . $i; + $budget = $i * 1000 + $i * 15; + $stmt->execute(array( ':col1' => $i, ':col2' => $pol, ':col3' => $grp, ':col4' => $budget )); + } + echo "....Done....\n"; + echo "Now selecting....\n"; + $tsql = "SELECT * FROM [$tableName]"; + $stmtOptions[PDO::ATTR_CURSOR] = PDO::CURSOR_SCROLL; + if (isColEncrypted()) { + $stmtOptions[PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE] = PDO::SQLSRV_CURSOR_BUFFERED; + } + $stmt1 = $conn1->prepare($tsql, $stmtOptions); + $stmt1->execute(); + // The row order in the resultset when the column is encrypted (which is dependent on the encrytion key used) + // is different from the order when the column is not enabled + // To make this test work, if the column is encrypted, fetch all then find the corresponding row + if (!isColEncrypted()) { + var_dump($stmt1->fetch(PDO::FETCH_ASSOC)); + $row = $stmt1->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_NEXT); + print "$row[1]\n"; + $row = $stmt1->fetch(PDO::FETCH_LAZY, PDO::FETCH_ORI_LAST); + print "$row[3]\n"; + $row = $stmt1->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_PRIOR); + print_r($row); + } else { + $resultset = []; + // fetch first two rows + array_push($resultset, $stmt1->fetch(PDO::FETCH_BOTH)); + array_push($resultset, $stmt1->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_NEXT)); + // fetch last three rows + array_push($resultset, $stmt1->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_LAST)); + array_push($resultset, $stmt1->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_PRIOR)); + array_push($resultset, $stmt1->fetch(PDO::FETCH_BOTH, PDO::FETCH_ORI_PRIOR)); + // sort and print + sort($resultset); + $assocArr['ID'] = $resultset[0]['ID']; + $assocArr['Policy'] = $resultset[0]['Policy']; + $assocArr['Label'] = $resultset[0]['Label']; + $assocArr['Budget'] = $resultset[0]['Budget']; + var_dump($assocArr); + print($resultset[1][1] . "\n"); + print($resultset[4][3] . "\n"); + print_r($resultset[3]); + } - $query1 = "INSERT INTO [$tableName](ID, Policy, Label, Budget) VALUES (:col1, :col2, :col3, :col4)"; - $stmt = $conn1->prepare($query1, array(PDO::ATTR_EMULATE_PREPARES => true)); - for ($i = 3; $i <= 5; $i++) - { - $pol = chr(64+$i); - $grp = "Group " . $i; - $budget = $i * 1000 + $i * 15; - $stmt->execute( array( ':col1' => $i, ':col2' => $pol, ':col3' => $grp, ':col4' => $budget ) ); - } - echo "....Done....\n"; - echo "Now selecting....\n"; - $tsql = "SELECT * FROM [$tableName]"; - $stmt1 = $conn1->prepare($tsql, array(PDO::ATTR_EMULATE_PREPARES => false)); - $stmt1 = $conn1->prepare($tsql, array(PDO::ATTR_EMULATE_PREPARES => true, PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL)); - $stmt1->execute(); - var_dump($stmt1->fetch( PDO::FETCH_ASSOC )); - $row = $stmt1->fetch( PDO::FETCH_NUM, PDO::FETCH_ORI_NEXT ); - print "$row[1]\n"; - $row = $stmt1->fetch( PDO::FETCH_LAZY, PDO::FETCH_ORI_LAST ); - print "$row[3]\n"; - $row = $stmt1->fetch( PDO::FETCH_BOTH, PDO::FETCH_ORI_PRIOR ); - print_r($row); + echo "\nFirst two groups or Budget > 4000....\n"; + unset($stmtOptions[PDO::ATTR_CURSOR]); + if (!isColEncrypted()) { + $tsql = "SELECT * FROM [$tableName] WHERE ID <= :id OR Budget > :budget"; + $stmt2 = $conn1->prepare($tsql, $stmtOptions); + $budget = 4000; + $id = 2; + $stmt2->bindParam(':id', $id); + $stmt2->bindParam(':budget', $budget); + $stmt2->execute(); + while ($result = $stmt2->fetchObject()) { + print_r($result); + } + } else { + // more and less than operators do not work for encrypted columns + $tsql = "SELECT * FROM [$tableName] WHERE NOT ID = :id"; + unset($stmtOptions[PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE]); + $stmt2 = $conn1->prepare($tsql, $stmtOptions); + $id = 3; + $stmt2->bindParam(':id', $id); + $stmt2->execute(); + // again need to fetch all, sort, then print + $resultset = array(); + while ($result = $stmt2->fetchObject()) { + array_push($resultset, $result); + } + sort($resultset); + foreach ($resultset as $r) { + print_r($r); + } + } - echo "\nFirst two groups or Budget > 4000....\n"; - $tsql = "SELECT * FROM [$tableName] WHERE ID <= :id OR Budget > :budget"; - $stmt2 = $conn1->prepare($tsql, array(PDO::ATTR_EMULATE_PREPARES => true)); - $budget = 4000; - $id = 2; - $stmt2->bindParam(':id', $id); - $stmt2->bindParam(':budget', $budget); - $stmt2->execute(); - while ( $result = $stmt2->fetchObject() ){ - print_r($result); - echo "\n"; - } - - echo "\nSelect Policy = 'A'....\n"; - $tsql = "SELECT * FROM [$tableName] WHERE Policy = ?"; - $stmt3 = $conn1->prepare($tsql, array(PDO::ATTR_EMULATE_PREPARES => true)); - $pol = 'A'; - $stmt3->bindValue(1, $pol); - $id = 'C'; - $stmt3->execute(); - while ( $row = $stmt3->fetch( PDO::FETCH_ASSOC ) ){ - print_r($row); - echo "\n"; - } - - echo "\nSelect id > 2....\n"; - $tsql = "SELECT Policy, Label, Budget FROM [$tableName] WHERE ID > 2"; - $stmt4 = $conn1->prepare($tsql, array(PDO::ATTR_EMULATE_PREPARES => true)); - $stmt4->execute(); - $stmt4->bindColumn('Policy', $policy); - $stmt4->bindColumn('Budget', $budget); - while ( $row = $stmt4->fetch( PDO::FETCH_BOUND ) ){ - echo "Policy: $policy\tBudget: $budget\n"; - } + echo "\nSelect Policy = 'A'....\n"; + $tsql = "SELECT * FROM [$tableName] WHERE Policy = ?"; + $stmt3 = $conn1->prepare($tsql, $stmtOptions); + $pol = 'A'; + $stmt3->bindValue(1, $pol); + $id = 'C'; + $stmt3->execute(); + while ($row = $stmt3->fetch(PDO::FETCH_ASSOC)) { + print_r($row); + echo "\n"; + } - echo "\nBudget Metadata....\n"; - $metadata = $stmt4->getColumnMeta(2); - var_dump($metadata); + echo "\nSelect id > 2....\n"; + if (!isColEncrypted()) { + $tsql = "SELECT Policy, Label, Budget FROM [$tableName] WHERE ID > 2"; + $stmt4 = $conn1->prepare($tsql, $stmtOptions); + } else { + $tsql = "SELECT Policy, Label, Budget FROM [$tableName] WHERE NOT ID = ? AND NOT ID = ?"; + $stmt4 = $conn1->prepare($tsql, $stmtOptions); + $id1 = 1; + $id2 = 2; + $stmt4->bindParam(1, $id1); + $stmt4->bindParam(2, $id2); + } + $stmt4->execute(); + $stmt4->bindColumn('Policy', $policy); + $stmt4->bindColumn('Budget', $budget); + $policyArr = array(); + $budgetArr = array(); + while ($row = $stmt4->fetch(PDO::FETCH_BOUND)) { + //echo "Policy: $policy\tBudget: $budget\n"; + array_push($policyArr, $policy); + array_push($budgetArr, $budget); + } + if (isColEncrypted()) { + sort($policyArr); + sort($budgetArr); + } + for ($i = 0; $i < 3; $i++) { + echo "Policy: $policyArr[$i]\tBudget: $budgetArr[$i]\n"; + } - // Cleanup - DropTable($conn1, $tableName); - $stmt1 = null; - $stmt2 = null; - $stmt3 = null; - $stmt4 = null; - $conn1 = null; + echo "\nBudget Metadata....\n"; + $metadata = $stmt4->getColumnMeta(2); + var_dump($metadata); - EndTest($testName); + // Cleanup + dropTable($conn1, $tableName); + unset($stmt1); + unset($stmt2); + unset($stmt3); + unset($stmt4); + unset($conn1); +} catch (Exception $e) { + echo $e->getMessage(); } -class Test -{ - function __construct($name = 'N/A') - { - echo __METHOD__ . "($name)\n"; - } -} - - -//-------------------------------------------------------------------- -// Repro -// -//-------------------------------------------------------------------- -function Repro() -{ - - try - { - FetchMode(); - } - catch (Exception $e) - { - echo $e->getMessage(); - } -} - -Repro(); - ?> --EXPECT-- SQLSTATE[IMSSP]: The given attribute is only supported on the PDOStatement object. @@ -201,7 +226,6 @@ stdClass Object [Label] => Group 1 [Budget] => 1015.0000 ) - stdClass Object ( [ID] => 2 @@ -209,7 +233,6 @@ stdClass Object [Label] => Group 2 [Budget] => 2030.0000 ) - stdClass Object ( [ID] => 4 @@ -217,7 +240,6 @@ stdClass Object [Label] => Group 4 [Budget] => 4060.0000 ) - stdClass Object ( [ID] => 5 @@ -226,7 +248,6 @@ stdClass Object [Budget] => 5075.0000 ) - Select Policy = 'A'.... Array ( @@ -261,4 +282,3 @@ array(8) { ["precision"]=> int(4) } -Test "PDO Statement - Set Fetch Mode" completed successfully. \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/test_encoding_UTF8_emulate_prepare.phpt b/test/functional/pdo_sqlsrv/test_encoding_UTF8_emulate_prepare.phpt index 1d3d7eff..3ac120d2 100644 --- a/test/functional/pdo_sqlsrv/test_encoding_UTF8_emulate_prepare.phpt +++ b/test/functional/pdo_sqlsrv/test_encoding_UTF8_emulate_prepare.phpt @@ -1,113 +1,97 @@ --TEST-- Test UTF8 Encoding with emulate prepare --SKIPIF-- - + --FILE-- setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); - $conn->setAttribute( PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_SYSTEM); - $stmt1 = $conn->query("IF OBJECT_ID('Table_UTF', 'U') IS NOT NULL DROP TABLE [Table_UTF]"); - $stmt1 = null; - - $stmt2 = $conn->query("CREATE TABLE [Table_UTF] ([c1_int] int PRIMARY KEY, [c2_char] char(512))"); - $stmt2 = null; - - $stmt3 = $conn->prepare("INSERT INTO [Table_UTF] (c1_int, c2_char) VALUES (:var1, :var2)"); - $stmt3->setAttribute(constant('PDO::SQLSRV_ATTR_ENCODING'), PDO::SQLSRV_ENCODING_UTF8); - $stmt3->bindParam(2, $inValue1); - $stmt3->bindValue(1, 1); - $stmt3->execute(); - $stmt3->bindValue(1, 2); - $stmt3->execute(); - $stmt3->bindValue(1, 3); - $stmt3->execute(); - $stmt3->bindValue(1, 4); - $stmt3->execute(); - $stmt3->bindValue(1, 5); - $stmt3->execute(); - $stmt3 = null; - - $stmt4 = $conn->prepare("SELECT * FROM [Table_UTF]"); - $stmt4->setAttribute(constant('PDO::SQLSRV_ATTR_ENCODING'), PDO::SQLSRV_ENCODING_UTF8); - $outValue1 = null; - $stmt4->execute(); - $row1 = $stmt4->fetch(); - $count1 = count($row1); - echo ("Number of rows: $count1\n"); - $v0 = $row1[0]; - $outValue1 = $row1[1]; - if (strncmp($inValue1, $outValue1, $inValueLen) == 0) { - echo "outValue is the same as inValue.\n"; - } - $outValue1 = null; - - $value1 = $stmt4->fetchcolumn(1); - $outValue1 = $value1; - if (strncmp($inValue1, $outValue1, $inValueLen) == 0) { - echo "outValue is the same as inValue.\n"; - } - $outvalue1 = null; - - $value2 = $stmt4->fetchColumn(1); - $outValue1 = $value2; - if (strncmp($inValue1, $outValue1, $inValueLen) == 0) { - echo "outValue is the same as inValue.\n"; - } - $outValue1 = null; - - $value3 = $stmt4->fetchColumn(1); - $outValue1 = $value3; - if (strncmp($inValue1, $outValue1, $inValueLen) == 0) { - echo "outValue is the same as inValue.\n"; - } - $outValue1 = null; - - $value4 = $stmt4->fetchColumn(1); - $outValue1 = $value4; - if (strncmp($inValue1, $outValue1, $inValueLen) == 0) { - echo "outValue is the same as inValue.\n"; - } - $stmt4 = null; - - $stmt5 = $conn->prepare( "SELECT ? = c2_char FROM [Table_UTF]", array(PDO::ATTR_EMULATE_PREPARES => true) ); - $stmt5->setAttribute(constant('PDO::SQLSRV_ATTR_ENCODING'), PDO::SQLSRV_ENCODING_UTF8); - $outValue1 = "hello"; - $stmt5->bindParam( 1, $outValue1, PDO::PARAM_STR, 1024); - $stmt5->execute(); - if (strncmp($inValue1, $outValue1, $inValueLen) == 0) { - echo "outValue is the same as inValue.\n"; - } else { - echo "outValue is $outValue1\n"; - } - $stmt5 = null; - - $stmt6 = $conn->query("DROP TABLE [Table_UTF]"); - $stmt6 = null; - - $conn = null; +function checkError($e, $expMsg, $aeExpMsg) +{ + $error = $e->getMessage(); + if (!isAEConnected()) { + if (strpos($error, $expMsg) === false) echo $error; + } else { + if (strpos($error, $aeExpMsg) === false) echo $error; + } } -catch (PDOexception $e){ - print_r( ($e->errorInfo)[2] ); - echo "\n"; + +try { + $inValue1 = pack('H*', '3C586D6C54657374446174613E4A65207072C3A966C3A87265206C27C3A974C3A93C2F586D6C54657374446174613E'); + $inValueLen = strlen($inValue1); + + $conn = connect(); + $conn->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_SYSTEM); + + $tbname = "Table_UTF"; + createTable($conn, $tbname, array(new ColumnMeta("int", "c1_int", "PRIMARY KEY"), "c2_char" => "char(512)")); + + $stmt3 = $conn->prepare("INSERT INTO [Table_UTF] (c1_int, c2_char) VALUES (:var1, :var2)"); + $stmt3->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_UTF8); + $stmt3->bindParam(2, $inValue1); + $stmt3->bindValue(1, 1); + $stmt3->execute(); + $stmt3->bindValue(1, 2); + $stmt3->execute(); + $stmt3->bindValue(1, 3); + $stmt3->execute(); + $stmt3->bindValue(1, 4); + $stmt3->execute(); + $stmt3->bindValue(1, 5); + $stmt3->execute(); + unset($stmt3); + + $stmt4 = $conn->prepare("SELECT * FROM $tbname"); + $stmt4->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_UTF8); + $outValue1 = null; + $stmt4->execute(); + $row1 = $stmt4->fetch(PDO::FETCH_NUM); + $count1 = count($row1); + echo("Number of columns: $count1\n"); + $v0 = $row1[0]; + $outValue1 = $row1[1]; + if (strncmp($inValue1, $outValue1, $inValueLen) == 0) { + echo "outValue is the same as inValue.\n"; + } + + for ($i = 0; $i < 4; $i++) { + $outValue1 = $stmt4->fetchColumn(1); + if (strncmp($inValue1, $outValue1, $inValueLen) == 0) { + echo "outValue is the same as inValue.\n"; + } + } + unset($stmt4); + + $option; + if (!isAEConnected()) { + $option[PDO::ATTR_EMULATE_PREPARES] = true; + } else { + $option[PDO::ATTR_EMULATE_PREPARES] = false; + } + $stmt5 = $conn->prepare("SELECT ? = c2_char FROM $tbname", $option); + $stmt5->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_UTF8); + $outValue1 = "hello"; + $stmt5->bindParam(1, $outValue1, PDO::PARAM_STR, 1024); + $stmt5->execute(); + if (strncmp($inValue1, $outValue1, $inValueLen) == 0) { + echo "outValue is the same as inValue.\n"; + } else { + echo "outValue is $outValue1\n"; + } + unset($stmt5); + dropTable($conn, $tbname); + unset($conn); +} catch (PDOexception $e) { + // binding parameters in the select list is not supported with Column Encryption + $expMsg = "Statement with emulate prepare on does not support output or input_output parameters."; + $aeExpMsg = "Invalid Descriptor Index"; + checkError($e, $expMsg, $aeExpMsg); } ?> --EXPECT-- -Number of rows: 4 +Number of columns: 2 outValue is the same as inValue. outValue is the same as inValue. outValue is the same as inValue. outValue is the same as inValue. outValue is the same as inValue. -Statement with emulate prepare on does not support output or input_output parameters. - - - - diff --git a/test/functional/sqlsrv/0020.phpt b/test/functional/sqlsrv/0020.phpt index 44847a2c..ef7df7cb 100644 --- a/test/functional/sqlsrv/0020.phpt +++ b/test/functional/sqlsrv/0020.phpt @@ -1,106 +1,119 @@ --TEST-- reading streams of various types with a base64 decoding filter on top of them. --SKIPIF-- - + --FILE-- $data)); + } else { + $insertQuery = $params['insertQuery']; + $stmt = sqlsrv_query($conn, $insertQuery, array($data)); + } + + if ($stmt) { + do { $read = sqlsrv_send_stream_data($stmt); - if ($read === false) die(print_r(sqlsrv_errors(), true)); + if ($read === false) { + die(print_r(sqlsrv_errors(), true)); + } } while ($read); fclose($data) || die(print_r(error_get_last(), true)); sqlsrv_free_stmt($stmt) || die(print_r(sqlsrv_errors(), true)); - } else + } else { die(print_r(sqlsrv_errors(), true)); + } - return fopen($params['testImageURL'], "rb"); + return fopen($params['testImageURL'], "rb"); } -function PrepareParams(&$arr) { - $uname = php_uname(); - $phpgif = "\\php.gif"; - if (preg_match('/Win/',$uname)) - { +function prepareParams(&$arr, $fieldType) +{ + if (isWindows()) { $phpgif = '\\php.gif'; - } - else // other than Windows - { + } else { $phpgif = '/php.gif'; } - $arr['tableName'] = $tblName = "dbo.B64TestTable"; + + $arr['tableName'] = $tblName = "B64TestTable"; $arr['columnName'] = $colName = "Base64Image"; - $arr['fieldType'] = $fieldType = "nvarchar(MAX)"; - $arr['dropQuery'] = "IF OBJECT_ID(N'$tblName', N'U') IS NOT NULL DROP TABLE $tblName"; - $arr['createQuery'] = "CREATE TABLE $tblName ($colName $fieldType)"; + $arr['fieldType'] = $fieldType; $arr['insertQuery'] = "INSERT INTO $tblName ($colName) VALUES (?)"; $arr['selectQuery'] = "SELECT TOP 1 $colName FROM $tblName"; - // $arr['testImageURL'] = "http://static.php.net/www.php.net/images/php.gif"; - $arr['testImageURL'] = dirname( $_SERVER['PHP_SELF'] ).$phpgif; // use this when no http access - $arr['MIMEType'] = "image/gif"; -} - -function DropTestTable($conn, $params) { RunQuery($conn, $params['dropQuery']); } -function CreateTestTable($conn, $params) { RunQuery($conn, $params['createQuery']); } -function RunQuery($conn, $query) { - ($qStmt = sqlsrv_query($conn, $query)) && $qStmt && sqlsrv_free_stmt($qStmt) - || die(print_r(sqlsrv_errors(), true)); + $arr['testImageURL'] = dirname($_SERVER['PHP_SELF']) . $phpgif; // use this when no http access } ?> diff --git a/test/functional/sqlsrv/0060.phpt b/test/functional/sqlsrv/0060.phpt index afffaf24..5af735e8 100644 --- a/test/functional/sqlsrv/0060.phpt +++ b/test/functional/sqlsrv/0060.phpt @@ -1,7 +1,7 @@ --TEST-- binding parameters, including output parameters, using the simplified syntax. --SKIPIF-- - + --FILE-- + --FILE-- diff --git a/test/functional/sqlsrv/0065.phpt b/test/functional/sqlsrv/0065.phpt index f7042861..a9678bbb 100644 --- a/test/functional/sqlsrv/0065.phpt +++ b/test/functional/sqlsrv/0065.phpt @@ -1,46 +1,37 @@ --TEST-- inserting and retrieving UTF-8 text. --SKIPIF-- - + --FILE-- + --FILE-- + --FILE-- + --FILE-- ---EXPECTREGEX-- -sqlsrv_execute\(3\) failed -Array -\( - \[0\] => Array - \( - \[0\] => 42000 - \[SQLSTATE\] => 42000 - \[1\] => 257 - \[code\] => 257 - \[2\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Implicit conversion from data type varchar\(max\) to varbinary\(max\) is not allowed\. Use the CONVERT function to run this query\. - \[message\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Implicit conversion from data type varchar\(max\) to varbinary\(max\) is not allowed\. Use the CONVERT function to run this query\. - \) - - \[1\] => Array - \( - \[0\] => 42000 - \[SQLSTATE\] => 42000 - \[1\] => 8180 - \[code\] => 8180 - \[2\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Statement\(s\) could not be prepared\. - \[message\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Statement\(s\) could not be prepared\. - \) - -\) +--EXPECT-- +sqlsrv_execute failed +Done diff --git a/test/functional/sqlsrv/0069.phpt b/test/functional/sqlsrv/0069.phpt index 5ec3164a..aa81a1f5 100644 --- a/test/functional/sqlsrv/0069.phpt +++ b/test/functional/sqlsrv/0069.phpt @@ -1,54 +1,77 @@ --TEST-- Variety of connection parameters. --SKIPIF-- - + --FILE-- + --FILE-- '.$guid."<\n"; - while( sqlsrv_next_result( $stmt ) != NULL ) { + while (sqlsrv_next_result($stmt) != null) { } echo 'New Guid: >'.$guid."<\n"; diff --git a/test/functional/sqlsrv/0073.phpt b/test/functional/sqlsrv/0073.phpt index 30fddf9b..56f60e5c 100644 --- a/test/functional/sqlsrv/0073.phpt +++ b/test/functional/sqlsrv/0073.phpt @@ -1,7 +1,7 @@ --TEST-- For output string parameter crash when output variable is set initially to null --SKIPIF-- - + --FILE-- '.$guid."<\n"; - while( sqlsrv_next_result( $stmt ) != NULL ) { + while (sqlsrv_next_result($stmt) != null) { } echo 'New Guid: >'.$guid."<\n"; diff --git a/test/functional/sqlsrv/0074.phpt b/test/functional/sqlsrv/0074.phpt index 9cc571bc..14ea08df 100644 --- a/test/functional/sqlsrv/0074.phpt +++ b/test/functional/sqlsrv/0074.phpt @@ -1,44 +1,48 @@ --TEST-- output string parameters with rows affected return results before output parameter. --SKIPIF-- - + --FILE-- $id, 'Intro' => $intro)); + if ($stmt === false) { + die(print_r(sqlsrv_errors(), true)); + } } -$stmt = sqlsrv_query( $conn, "IF OBJECT_ID('Subjects', 'U') IS NOT NULL DROP TABLE Subjects" ); -$stmt = sqlsrv_query( $conn, "IF OBJECT_ID('sn_x_study', 'U') IS NOT NULL DROP TABLE sn_x_study" ); -$stmt = sqlsrv_query( $conn, "IF OBJECT_ID('Studies', 'U') IS NOT NULL DROP TABLE Studies" ); -$stmt = sqlsrv_query( $conn, "IF OBJECT_ID('sp_MakeSubject', 'P') IS NOT NULL DROP PROCEDURE sp_MakeSubject" ); +require_once('MsCommon.inc'); +$conn = AE\connect(); -$stmt = sqlsrv_query( $conn, "CREATE TABLE Subjects (StartTime datetime, sn nchar(32), extref nvarchar(50))" ); -if( $stmt === false ) { - die( print_r( sqlsrv_errors(), true )); -} -$stmt = sqlsrv_query( $conn, "CREATE TABLE sn_x_study (studyID int, sn nchar(32))" ); -if( $stmt === false ) { - die( print_r( sqlsrv_errors(), true )); -} -$stmt = sqlsrv_query( $conn, "CREATE TABLE Studies (studyID int, Intro nvarchar(max))" ); -if( $stmt === false ) { - die( print_r( sqlsrv_errors(), true )); -} -$stmt = sqlsrv_query( $conn, "INSERT INTO Studies (studyID, Intro) VALUES (1, 'Test class 1')" ); -if( $stmt === false ) { - die( print_r( sqlsrv_errors(), true )); -} -$stmt = sqlsrv_query( $conn, "INSERT INTO Studies (studyID, Intro) VALUES (2, 'Test class 2')" ); -if( $stmt === false ) { - die( print_r( sqlsrv_errors(), true )); -} -$stmt = sqlsrv_query( $conn, "INSERT INTO Studies (studyID, Intro) VALUES (3, 'Test class 3')" ); -if( $stmt === false ) { - die( print_r( sqlsrv_errors(), true )); +// drop the procedure if exists +dropProc($conn, 'sp_MakeSubject'); + +// Create Table 'Subjects' but do not encrypt the first column because in the stored procedure +// we rely on the server to get the current date time. With Column Encryption, all input values +// have to be provided by the client +$columns = array(new AE\ColumnMeta('datetime', 'StartTime', null, true, true), + new AE\ColumnMeta('nchar(32)', 'sn'), + new AE\ColumnMeta('nvarchar(50)', 'extref')); +$stmt = AE\createTable($conn, 'Subjects', $columns); +unset($columns); + +// Create table 'sn_x_study' +$columns = array(new AE\ColumnMeta('int', 'studyID'), + new AE\ColumnMeta('nchar(32)', 'sn')); +$stmt = AE\createTable($conn, 'sn_x_study', $columns); +unset($columns); + +// Create table 'Studies' +$columns = array(new AE\ColumnMeta('int', 'studyID'), + new AE\ColumnMeta('nvarchar(max)', 'Intro')); +$stmt = AE\createTable($conn, 'Studies', $columns); +unset($columns); + +// Insert 3 rows into table 'Studies' +for ($i = 1; $i <= 3; $i++) { + insertIntoStudies($conn, $i); } $proc = << + --FILE-- --EXPECT-- diff --git a/test/functional/sqlsrv/0076.phpt b/test/functional/sqlsrv/0076.phpt index f03ff09c..756f2036 100644 --- a/test/functional/sqlsrv/0076.phpt +++ b/test/functional/sqlsrv/0076.phpt @@ -1,45 +1,47 @@ --TEST-- datetime server neutral to make sure it passes. --SKIPIF-- - + --FILE-- --EXPECTREGEX-- diff --git a/test/functional/sqlsrv/0078.phpt b/test/functional/sqlsrv/0078.phpt index 4ab4b2ac..66493ba8 100644 --- a/test/functional/sqlsrv/0078.phpt +++ b/test/functional/sqlsrv/0078.phpt @@ -1,257 +1,268 @@ --TEST-- Fix for output string parameters length prior to output being delivered --SKIPIF-- - + --FILE-- - $id, 'Intro' => $intro)); + } else { + $stmt = sqlsrv_query($conn, "INSERT INTO Studies (studyID, Intro) VALUES (" . $id . ", N'". $intro ."')"); + } + if ($stmt === false) { + fatalError("Failed to insert $id and $intro!\n"); } } -if( sqlsrv_errors() != NULL ) { - print_r( sqlsrv_errors() ); -} -echo "$introText\n"; + +sqlsrv_configure('WarningsReturnAsErrors', 0); +sqlsrv_configure('LogSeverity', SQLSRV_LOG_SEVERITY_ALL); + +require_once('MsCommon.inc'); +$conn = AE\connect(); +if ($conn === false) { + die(print_r(sqlsrv_errors(), true)); +} + +dropProc($conn, 'sp_MakeSubject78'); -$tsql_callSP = "{call sp_MakeSubject78(?,?,?,?)}"; -$introText="X"; +// Create Table 'Subjects' but do not encrypt the first column because in the stored procedure +// we rely on the server to get the current date time. With Column Encryption, all input values +// have to be provided by the client +$columns = array(new AE\ColumnMeta('datetime', 'StartTime', null, true, true), + new AE\ColumnMeta('nchar(32)', 'sn'), + new AE\ColumnMeta('nvarchar(50)', 'extref')); +$stmt = AE\createTable($conn, 'Subjects', $columns); +unset($columns); + +// Create table 'sn_x_study' +$columns = array(new AE\ColumnMeta('int', 'studyID'), + new AE\ColumnMeta('nchar(32)', 'sn')); +$stmt = AE\createTable($conn, 'sn_x_study', $columns); +unset($columns); + +// Create table 'Studies'. When AE is enabled, the sql type must match +// the column definition, but because this test wants to convert the +// output of column 'Intro' to nvarchar(256), we do not encrypt this second column +$columns = array(new AE\ColumnMeta('int', 'studyID'), + new AE\ColumnMeta('nchar(32)', 'Intro', null, true, true)); +$stmt = AE\createTable($conn, 'Studies', $columns); +unset($columns); + +// Insert 3 rows into table 'Studies' +insertIntoStudies($conn, 1, "Test class 1"); +insertIntoStudies($conn, 2, "12345678901234567890123456789012"); +insertIntoStudies($conn, 3, "Test class 3"); + +$proc = << --EXPECT-- 64 diff --git a/test/functional/sqlsrv/0079.phpt b/test/functional/sqlsrv/0079.phpt index 6b89db46..94ee6a18 100644 --- a/test/functional/sqlsrv/0079.phpt +++ b/test/functional/sqlsrv/0079.phpt @@ -1,7 +1,7 @@ --TEST-- Invalid UTF-16 coming from the server --SKIPIF-- - + --FILE-- \ No newline at end of file +?> diff --git a/test/functional/sqlsrv/MsCommon.inc b/test/functional/sqlsrv/MsCommon.inc index dc9ba15b..964e5efe 100644 --- a/test/functional/sqlsrv/MsCommon.inc +++ b/test/functional/sqlsrv/MsCommon.inc @@ -136,7 +136,7 @@ function connect($options = array()) { include('MsSetup.inc'); - if (sizeof($options) > 0) { + if (!empty($options)) { $connectionOptions = array_merge($connectionOptions, $options); } @@ -271,7 +271,7 @@ function createUniqueIndexEx($conn, $tableName, $tableIndex, $colIndex) function dropTable($conn, $tableName) { - $stmt = sqlsrv_query($conn, "IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'" . $tableName . "') AND type in (N'U')) DROP TABLE $tableName"); + $stmt = sqlsrv_query($conn, "IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'" . $tableName . "') AND type in (N'U')) DROP TABLE [$tableName]"); if ($stmt === false) { } else { sqlsrv_free_stmt($stmt); @@ -359,7 +359,7 @@ function createProc($conn, $procName, $procArgs, $procCode) function dropProc($conn, $procName) { - $stmt = sqlsrv_query($conn, "DROP PROC [$procName]"); + $stmt = sqlsrv_query($conn, "IF OBJECT_ID('". $procName ."', 'P') IS NOT NULL DROP PROCEDURE [$procName]"); if ($stmt === false) { } else { sqlsrv_free_stmt($stmt); @@ -463,6 +463,21 @@ function isLocaleSupported() if (explode(".", $msodbcsql_ver)[0] < 17) { return false; } + + return true; +} + +function verifyError($error, $state, $message) +{ + if ($error['SQLSTATE'] !== $state) { + echo $error['SQLSTATE'] . PHP_EOL; + fatalError("Unexpected SQL state\n"); + } + + if (strpos($error['message'], $message) === false) { + echo $error['message'] . PHP_EOL; + fatalError("Unexpected error message\n"); + } } ?> diff --git a/test/functional/sqlsrv/MsHelper.inc b/test/functional/sqlsrv/MsHelper.inc index 4cb5cbfa..988253b1 100644 --- a/test/functional/sqlsrv/MsHelper.inc +++ b/test/functional/sqlsrv/MsHelper.inc @@ -90,7 +90,8 @@ class ColumnMeta { $append = " "; - if (isColEncrypted() && $this->encryptable) { + if ($this->encryptable && isDataEncrypted()) { + $cekName = getCekName(); if (stripos($this->dataType, "char") !== false) { $append .= "COLLATE Latin1_General_BIN2 "; @@ -253,7 +254,7 @@ function getDefaultColname($dataType) */ function getInsertSqlComplete($tbname, $inputs) { - $colStr = "INSERT INTO $tbname ("; + $colStr = "INSERT INTO [$tbname] ("; $valStr = "VALUES ("; if (empty($inputs)) { echo "getInsertSqlComplete: inputs for inserting a row cannot be empty.\n"; @@ -282,7 +283,7 @@ function getInsertSqlComplete($tbname, $inputs) */ function getInsertSqlPlaceholders($tbname, $inputs) { - $colStr = "INSERT INTO $tbname ("; + $colStr = "INSERT INTO [$tbname] ("; $valStr = "VALUES ("; if (empty($inputs)) { echo "getInsertSqlPlaceholders: inputs for inserting a row cannot be empty.\n"; @@ -304,7 +305,7 @@ function getInsertSqlPlaceholders($tbname, $inputs) */ function getCallProcSqlPlaceholders($spname, $num) { - $callStr = "{CALL $spname ("; + $callStr = "{CALL [$spname] ("; $callStr .= getSeqPlaceholders($num) . ")} "; return $callStr; } @@ -325,13 +326,26 @@ function getSeqPlaceholders($num) } /** - * @return bool false if $keystore specified in MsSetup.inc is none or data not encrypted, - * otherwise return true + * @return bool false if $keystore specified in MsSetup.inc is none; return true otherwise */ function isColEncrypted() { global $keystore, $dataEncrypted; - if ($keystore == KEYSTORE_NONE || !$dataEncrypted) { + if ($keystore === KEYSTORE_NONE) { + return false; + } else { + return true; + } +} + +/** + * @return bool false if $keystore specified in MsSetup.inc is none or data not encrypted; + * return true otherwise + */ +function isDataEncrypted() +{ + global $keystore, $dataEncrypted; + if ($keystore === KEYSTORE_NONE || !$dataEncrypted) { return false; } else { return true; @@ -364,7 +378,7 @@ function isQualified($conn) function connect($options = array(), $disableCE = false) { require('MsSetup.inc'); - if (sizeof($options) > 0) { + if (!empty($options)) { $connectionOptions = array_merge($connectionOptions, $options); } if (!$disableCE) { @@ -402,7 +416,7 @@ function createTable($conn, $tbname, $columnMetaArr) $colDef = $colDef . $meta->getColDef() . ", "; } $colDef = rtrim($colDef, ", "); - $createSql = "CREATE TABLE $tbname ( $colDef )"; + $createSql = "CREATE TABLE [$tbname] ( $colDef )"; return sqlsrv_query($conn, $createSql); } @@ -554,6 +568,38 @@ function executeQueryEx($conn, $sql, $options) return $stmt; } +/** + * Similar to executeQuery() but with params for binding and + * whether this query is expected to fail + * @return resource sqlsrv statement upon success or false otherwise + */ +function executeQueryParams($conn, $sql, $params, $expectedToFail = false, $message = '') +{ + $res = true; + if (isColEncrypted()) { + $stmt = sqlsrv_prepare($conn, $sql, $params); + if ($stmt) { + $res = sqlsrv_execute($stmt); + } + } else { + $stmt = sqlsrv_query($conn, $sql, $params); + } + + if ($stmt === false || !$res ) { + if (! $expectedToFail) { + fatalError($message); + } else { + print_r(sqlsrv_errors()); + } + } else { + if ($expectedToFail) { + fatalError($message); + } + } + + return $stmt; +} + /** * Fetch all rows and all columns given a table name, and print them * @param resource $conn : connection resource @@ -1033,6 +1079,23 @@ function getColName($k) return (""); } +function isStreamData($k) +{ + switch ($k) { + case 14: return (true); // varchar(max) + case 17: return (true); // nvarchar(max) + case 18: return (true); // text + case 19: return (true); // ntext + case 20: return (true); // binary + case 21: return (true); // varbinary(512) + case 22: return (true); // varbinary(max) + case 23: return (true); // image + case 27: return (true); // timestamp + case 28: return (true); // xml + default: break; + } + return (false); +} function getColSize($k) { diff --git a/test/functional/sqlsrv/TC42_FetchField.phpt b/test/functional/sqlsrv/TC42_FetchField.phpt index 462f95f6..b1395b5a 100644 --- a/test/functional/sqlsrv/TC42_FetchField.phpt +++ b/test/functional/sqlsrv/TC42_FetchField.phpt @@ -33,6 +33,9 @@ function fetchFields() $stmt1 = AE\selectFromTable($conn1, $tableName); $numFields = sqlsrv_num_fields($stmt1); + $errState = 'IMSSP'; + $errMessage = 'Connection with Column Encryption enabled does not support fetching stream. Please fetch the data as a string.'; + trace("Retrieving $noRowsInserted rows with $numFields fields each ..."); for ($i = 0; $i < $noRowsInserted; $i++) { $row = sqlsrv_fetch($stmt1); @@ -41,8 +44,16 @@ function fetchFields() } for ($j = 0; $j < $numFields; $j++) { $fld = sqlsrv_get_field($stmt1, $j); + + // With AE enabled, those fields that sqlsrv_get_field() will fetch + // as stream data will return a specific error message + $col = $j+1; if ($fld === false) { - fatalError("Field $j of Row $i is missing\n", true); + if (AE\isColEncrypted() && isStreamData($col)) { + verifyError(sqlsrv_errors()[0], $errState, $errMessage); + } else { + fatalError("Field $j of Row $i is missing\n", true); + } } } } diff --git a/test/functional/sqlsrv/TC51_StreamRead.phpt b/test/functional/sqlsrv/TC51_StreamRead.phpt index 3e42243a..f81f2c82 100644 --- a/test/functional/sqlsrv/TC51_StreamRead.phpt +++ b/test/functional/sqlsrv/TC51_StreamRead.phpt @@ -69,7 +69,7 @@ function verifyStream($stmt, $row, $colIndex) } } if ($stream === false) { - fatalError("Failed to read field $col: $type"); + verifyStreamError("Failed to read field $col: $type"); } else { $value = ''; if ($stream) { @@ -88,6 +88,15 @@ function verifyStream($stmt, $row, $colIndex) } } +function verifyStreamError($message) +{ + global $errState, $errMessage; + if (AE\isColEncrypted()) { + verifyError(sqlsrv_errors()[0], $errState, $errMessage); + } else { + fatalError($message); + } +} function checkData($col, $actual, $expected) { @@ -123,6 +132,10 @@ if (!isWindows()) { global $testName; $testName = "Stream - Read"; +// error message expected with AE enabled +$errState = 'IMSSP'; +$errMessage = 'Connection with Column Encryption enabled does not support fetching stream. Please fetch the data as a string.'; + // test ansi only if windows or non-UTF8 locales are supported (ODBC 17 and above) startTest($testName); if (isWindows() || isLocaleSupported()) { diff --git a/test/functional/sqlsrv/TC55_StreamScrollable.phpt b/test/functional/sqlsrv/TC55_StreamScrollable.phpt index 82adc4b3..45d5a8a3 100644 --- a/test/functional/sqlsrv/TC55_StreamScrollable.phpt +++ b/test/functional/sqlsrv/TC55_StreamScrollable.phpt @@ -89,6 +89,16 @@ function streamScroll($noRows, $startRow) sqlsrv_close($conn1); } +function verifyStreamError($message) +{ + global $errState, $errMessage; + if (AE\isColEncrypted()) { + verifyError(sqlsrv_errors()[0], $errState, $errMessage); + } else { + fatalError($message); + } +} + function verifyStream($stmt, $row, $colIndex) { $col = $colIndex + 1; @@ -104,7 +114,7 @@ function verifyStream($stmt, $row, $colIndex) } } if ($stream === false) { - fatalError("Failed to read field $col: $type"); + verifyStreamError("Failed to read field $col: $type"); } else { $value = ''; if ($stream) { @@ -159,6 +169,10 @@ if (!isWindows()) { global $testName; $testName = "Stream - Scrollable"; +// error message expected with AE enabled +$errState = 'IMSSP'; +$errMessage = 'Connection with Column Encryption enabled does not support fetching stream. Please fetch the data as a string.'; + // test ansi only if windows or non-UTF8 locales are supported (ODBC 17 and above) startTest($testName); if (isWindows() || isLocaleSupported()) { diff --git a/test/functional/sqlsrv/TC81_MemoryCheck.phpt b/test/functional/sqlsrv/TC81_MemoryCheck.phpt index 1e9bbff8..5712eb8d 100644 --- a/test/functional/sqlsrv/TC81_MemoryCheck.phpt +++ b/test/functional/sqlsrv/TC81_MemoryCheck.phpt @@ -272,14 +272,23 @@ function runTest($noPasses, $noRows, $tableName, $conn, $prepared, $release, $mo break; case 5: // fetch fields + $errState = 'IMSSP'; + $errMessage = 'Connection with Column Encryption enabled does not support fetching stream. Please fetch the data as a string.'; + $stmt = execQuery($conn, $tableName, $prepared); $numFields = sqlsrv_num_fields($stmt); while (sqlsrv_fetch($stmt)) { $rowCount++; for ($i = 0; $i < $numFields; $i++) { $fld = sqlsrv_get_field($stmt, $i); + $col = $i + 1; + if ($fld === false) { - die("Field $i of row $rowCount is missing"); + if (AE\isColEncrypted() && isStreamData($col)) { + verifyError(sqlsrv_errors()[0], $errState, $errMessage); + } else { + fatalError("Field $i of row $rowCount is missing"); + } } unset($fld); } @@ -290,6 +299,8 @@ function runTest($noPasses, $noRows, $tableName, $conn, $prepared, $release, $mo if ($rowCount != $noRows) { die("$rowCount rows retrieved instead of $noRows\n"); } + unset($errState); + unset($errMessage); break; case 6: // fetch array diff --git a/test/functional/sqlsrv/fix_test_182741.phpt b/test/functional/sqlsrv/fix_test_182741.phpt index a0b2873c..90cf0e24 100644 --- a/test/functional/sqlsrv/fix_test_182741.phpt +++ b/test/functional/sqlsrv/fix_test_182741.phpt @@ -1,7 +1,7 @@ --TEST-- fix for 182741. --SKIPIF-- - + --FILE-- + --FILE-- true )); - -if (!$conn) { - fatalError("Could not connect"); -} - -$stmt = sqlsrv_query($conn, "IF OBJECT_ID('2008_date_types', 'U') IS NOT NULL DROP TABLE [2008_date_types]"); - -$stmt = sqlsrv_query($conn, "CREATE TABLE [2008_date_types] (id int, [c1_date] date, [c2_time] time, [c3_datetimeoffset] datetimeoffset, [c4_datetime2] datetime2)"); -if ($stmt === false) { - fatalError("Create table failed"); +$conn = AE\connect(array('ReturnDatesAsStrings' => true)); +$tableName = '2008_date_types'; +$columns = array(new AE\ColumnMeta('int', 'id'), + new AE\ColumnMeta('date', 'c1_date'), + new AE\ColumnMeta('time', 'c2_time'), + new AE\ColumnMeta('datetimeoffset', 'c3_datetimeoffset'), + new AE\ColumnMeta('datetime2', 'c4_datetime2')); +$stmt = AE\createTable($conn, $tableName, $columns); +if (!$stmt) { + fatalError("Failed to create table $tableName\n"); } // insert new date time types as strings (this works now) -$stmt = sqlsrv_query( - $conn, - "INSERT INTO [2008_date_types] (id, [c1_date], [c2_time], [c3_datetimeoffset], [c4_datetime2])" . - " VALUES (?, ?, ?, ?, ?)", - array( rand(0, 99999), - array( strftime('%Y-%m-%d'), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8'), SQLSRV_SQLTYPE_DATE ), - array( strftime('%H:%M:%S'), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8'), SQLSRV_SQLTYPE_TIME ), - array( date_format(date_create(), 'Y-m-d H:i:s.u P'), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8'), SQLSRV_SQLTYPE_DATETIMEOFFSET ), - array( date_format(date_create(), 'Y-m-d H:i:s.u'), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8'), SQLSRV_SQLTYPE_DATETIME2 )) +$insertSql = "INSERT INTO [$tableName] (id, [c1_date], [c2_time], [c3_datetimeoffset], [c4_datetime2]) VALUES (?, ?, ?, ?, ?)"; +$stmt = AE\executeQueryParams( + $conn, + $insertSql, + array(rand(0, 99999), + array(strftime('%Y-%m-%d'), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8'), SQLSRV_SQLTYPE_DATE), + array(strftime('%H:%M:%S'), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8'), SQLSRV_SQLTYPE_TIME), + array(date_format(date_create(), 'Y-m-d H:i:s.u P'), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8'), SQLSRV_SQLTYPE_DATETIMEOFFSET), + array(date_format(date_create(), 'Y-m-d H:i:s.u'), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8'), SQLSRV_SQLTYPE_DATETIME2)), + false, + "Insert 1 failed" ); -if ($stmt === false) { - fatalError("Insert 1 failed"); -} + // insert new date time types as DateTime objects (this works now) -$stmt = sqlsrv_query( +$stmt = AE\executeQueryParams( $conn, - "INSERT INTO [2008_date_types] (id, [c1_date], [c2_time], [c3_datetimeoffset], [c4_datetime2])" . - " VALUES (?, ?, ?, ?, ?)", - array( rand(0, 99999), - array( date_create(), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_DATETIME, SQLSRV_SQLTYPE_DATE ), - array( date_create(), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_DATETIME, SQLSRV_SQLTYPE_TIME ), - array( date_create(), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_DATETIME, SQLSRV_SQLTYPE_DATETIMEOFFSET ), - array( date_create(), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_DATETIME, SQLSRV_SQLTYPE_DATETIME2 )) + $insertSql, + array(rand(0, 99999), + array(date_create(), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_DATETIME, SQLSRV_SQLTYPE_DATE), + array(date_create(), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_DATETIME, SQLSRV_SQLTYPE_TIME), + array(date_create(), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_DATETIME, SQLSRV_SQLTYPE_DATETIMEOFFSET), + array(date_create(), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_DATETIME, SQLSRV_SQLTYPE_DATETIME2)), + false, + "Insert 2 failed" ); -if ($stmt === false) { - fatalError("Insert 2 failed"); -} + // insert new date time types as default DateTime objects with no type information (this works now) -$stmt = sqlsrv_query( +$stmt = AE\executeQueryParams( $conn, - "INSERT INTO [2008_date_types] (id, [c1_date], [c2_time], [c3_datetimeoffset], [c4_datetime2])" . - " VALUES (?, ?, ?, ?, ?)", - array( rand(0, 99999), date_create(), date_create(), date_create(), date_create()) + $insertSql, + array(rand(0, 99999), date_create(), date_create(), date_create(), date_create()), + false, + "Insert 3 failed" ); -if ($stmt === false) { - fatalError("Insert 3 failed"); -} + // insert new date time types as strings with no type information (this works) -$stmt = sqlsrv_query( +$stmt = AE\executeQueryParams( $conn, - "INSERT INTO [2008_date_types] (id, [c1_date], [c2_time], [c3_datetimeoffset], [c4_datetime2])" . - " VALUES (?, ?, ?, ?, ?)", - array( rand(0, 99999), strftime('%Y-%m-%d'), strftime('%H:%M:%S'), date_format(date_create(), 'Y-m-d H:i:s.u P'), date_format(date_create(), 'Y-m-d H:i:s.u P')) + $insertSql, + array(rand(0, 99999), strftime('%Y-%m-%d'), strftime('%H:%M:%S'), date_format(date_create(), 'Y-m-d H:i:s.u P'), date_format(date_create(), 'Y-m-d H:i:s.u P')), + false, + "Insert 4 failed" ); -if ($stmt === false) { - fatalError("Insert 4 failed"); -} // retrieve date time fields as strings (this works) -$stmt = sqlsrv_query($conn, "SELECT * FROM [2008_date_types]"); +$stmt = sqlsrv_query($conn, "SELECT * FROM [$tableName]"); while (sqlsrv_fetch($stmt)) { for ($i = 0; $i < sqlsrv_num_fields($stmt); ++$i) { $fld = sqlsrv_get_field($stmt, $i, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR)); @@ -84,7 +79,7 @@ while (sqlsrv_fetch($stmt)) { } // retrieve date time fields as default (should come back as DateTime objects) (this works now) -$stmt = sqlsrv_query($conn, "SELECT * FROM [2008_date_types]"); +$stmt = sqlsrv_query($conn, "SELECT * FROM [$tableName]"); if ($stmt === false) { fatalError("Select from table failed"); } @@ -93,7 +88,7 @@ while ($row = sqlsrv_fetch_array($stmt)) { } // retrieve date itme fields as DateTime objects -$stmt = sqlsrv_query($conn, "SELECT * FROM [2008_date_types]"); +$stmt = sqlsrv_query($conn, "SELECT * FROM [$tableName]"); while (sqlsrv_fetch($stmt)) { for ($i = 1; $i < sqlsrv_num_fields($stmt); ++$i) { $fld = sqlsrv_get_field($stmt, $i, SQLSRV_PHPTYPE_DATETIME); diff --git a/test/functional/sqlsrv/sqlsrv_378_out_param_error.phpt b/test/functional/sqlsrv/sqlsrv_378_out_param_error.phpt index 73787df4..ebb7334f 100644 --- a/test/functional/sqlsrv/sqlsrv_378_out_param_error.phpt +++ b/test/functional/sqlsrv/sqlsrv_378_out_param_error.phpt @@ -6,17 +6,17 @@ steps to reproduce the issue: 1- create a store procedure with print and output parameter 2- initialize output parameters to a different data type other than the type declared in sp. 3- set the WarningsReturnAsErrors to true -4 - call sp. +4- call sp. +--SKIPIF-- + --FILE-- colName => $inputValues[0], $colMetaArr[1]->colName => $inputValues[1] ), $r); - if (!AE\isColEncrypted()) { + if (!AE\isDataEncrypted()) { if ($r === false) { echo "Default type should be compatible with $dataType.\n"; $success = false; diff --git a/test/functional/sqlsrv/sqlsrv_ae_insert_retrieve.phpt b/test/functional/sqlsrv/sqlsrv_ae_insert_retrieve.phpt index 6371bf5d..e88ef0df 100644 --- a/test/functional/sqlsrv/sqlsrv_ae_insert_retrieve.phpt +++ b/test/functional/sqlsrv/sqlsrv_ae_insert_retrieve.phpt @@ -44,7 +44,7 @@ sqlsrv_free_stmt($stmt); //for AE only echo "\nChecking ciphertext data:\n"; -if (AE\isColEncrypted()) { +if (AE\isDataEncrypted()) { $conn1 = connect(null, true); $selectSql = "SELECT SSN, FirstName, LastName, BirthDate FROM $tbname"; $stmt = sqlsrv_query($conn1, $selectSql); diff --git a/test/functional/sqlsrv/sqlsrv_ae_insert_retrieve_fixed_size.phpt b/test/functional/sqlsrv/sqlsrv_ae_insert_retrieve_fixed_size.phpt index e9f9f212..d8c272ff 100644 --- a/test/functional/sqlsrv/sqlsrv_ae_insert_retrieve_fixed_size.phpt +++ b/test/functional/sqlsrv/sqlsrv_ae_insert_retrieve_fixed_size.phpt @@ -30,7 +30,7 @@ $inputs = array( "TinyIntData" => 255, "DecimalData" => 79228162514264, "BitData" => 1, "DateTimeData" => '9999-12-31 23:59:59.997', - "DateTime2Data" => '9999-12-31 23:59:59.9999999'); + "DateTime2Data" => '9999-12-31 23:59:59.123456'); $r; $stmt = AE\insertRow($conn, $tbname, $inputs, $r); if ($r === false) { @@ -43,7 +43,7 @@ AE\fetchAll($conn, $tbname); sqlsrv_free_stmt($stmt); // for AE only -if (AE\isColEncrypted()) { +if (AE\isDataEncrypted()) { $conn1 = connect(null, true); $selectSql = "SELECT * FROM $tbname"; @@ -80,7 +80,7 @@ DateTimeData: timezone_type: 3 timezone: Canada/Pacific DateTime2Data: - date: 9999-12-31 23:59:59.1000000 + date: 9999-12-31 23:59:59.123456 timezone_type: 3 timezone: Canada/Pacific Done diff --git a/test/functional/sqlsrv/sqlsrv_ae_insert_retrieve_nvarchar.phpt b/test/functional/sqlsrv/sqlsrv_ae_insert_retrieve_nvarchar.phpt index 54d42174..4003753b 100644 --- a/test/functional/sqlsrv/sqlsrv_ae_insert_retrieve_nvarchar.phpt +++ b/test/functional/sqlsrv/sqlsrv_ae_insert_retrieve_nvarchar.phpt @@ -14,7 +14,6 @@ $tbname = 'NVarcharAnalysis'; $colMetaArr = array( new AE\ColumnMeta("int", "CharCount", "IDENTITY(0,1)"), new AE\ColumnMeta("nvarchar(1000)")); AE\createTable($conn, $tbname, $colMetaArr); - // insert 1000 rows for ($i = 0; $i < 1000; $i++) { $data = str_repeat("*", $i); @@ -33,7 +32,7 @@ while ($decrypted_row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { sqlsrv_free_stmt($stmt); // for AE only -if (AE\isColEncrypted()) { +if (AE\isDataEncrypted()) { $conn1 = connect(null, true); $stmt = sqlsrv_query($conn1, $selectSql); while ($encrypted_row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { diff --git a/test/functional/sqlsrv/sqlsrv_ae_insert_retrieve_varchar.phpt b/test/functional/sqlsrv/sqlsrv_ae_insert_retrieve_varchar.phpt index 29d8a329..6d28d35b 100644 --- a/test/functional/sqlsrv/sqlsrv_ae_insert_retrieve_varchar.phpt +++ b/test/functional/sqlsrv/sqlsrv_ae_insert_retrieve_varchar.phpt @@ -33,7 +33,7 @@ while ($decrypted_row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { sqlsrv_free_stmt($stmt); // for AE only -if (AE\isColEncrypted()) { +if (AE\isDataEncrypted()) { $conn1 = connect(null, true); $stmt = sqlsrv_query($conn1, $selectSql); while ($encrypted_row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { diff --git a/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_datetime.phpt b/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_datetime.phpt index 353c7a67..021b937c 100644 --- a/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_datetime.phpt +++ b/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_datetime.phpt @@ -40,7 +40,7 @@ foreach ($dataTypes as $dataType) { $r; $stmt = AE\insertRow($conn, $tbname, array( $colMetaArr[0]->colName => $inputs[0], $colMetaArr[1]->colName => $inputs[1] ), $r, AE\INSERT_PREPARE_PARAMS); - if (!AE\isColEncrypted()) { + if (!AE\isDataEncrypted()) { if ($r === false) { $isCompatible = false; foreach ($compatList[$dataType] as $compatType) { diff --git a/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_money.phpt b/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_money.phpt index 88fcb409..35397c32 100644 --- a/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_money.phpt +++ b/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_money.phpt @@ -35,7 +35,7 @@ foreach ($dataTypes as $dataType) { $r; $stmt = AE\insertRow($conn, $tbname, array($colMetaArr[0]->colName => $inputs[0], $colMetaArr[1]->colName => $inputs[1]), $r, AE\INSERT_PREPARE_PARAMS); - if (!AE\isColEncrypted()) { + if (!AE\isDataEncrypted()) { if ($r === false) { $isCompatible = false; foreach ($compatList[$dataType] as $compatType) { diff --git a/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_numeric.phpt b/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_numeric.phpt index 1948e001..cb7aaf66 100644 --- a/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_numeric.phpt +++ b/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_numeric.phpt @@ -43,7 +43,7 @@ foreach ($dataTypes as $dataType) { $r; $stmt = AE\insertRow($conn, $tbname, array( $colMetaArr[0]->colName => $inputs[0], $colMetaArr[1]->colName => $inputs[1] ), $r, AE\INSERT_PREPARE_PARAMS); - if (!AE\isColEncrypted()) { + if (!AE\isDataEncrypted()) { if ($r === false) { $isCompatible = false; foreach ($compatList[$dataType] as $compatType) { diff --git a/test/functional/sqlsrv/sqlsrv_bind_param_out_string.phpt b/test/functional/sqlsrv/sqlsrv_bind_param_out_string.phpt index dc205bbe..0644f124 100644 --- a/test/functional/sqlsrv/sqlsrv_bind_param_out_string.phpt +++ b/test/functional/sqlsrv/sqlsrv_bind_param_out_string.phpt @@ -1,22 +1,18 @@ --TEST-- -Verify the Binary and Char encoding output when binding output string with SQLSTYPE option with different size +Verify the Binary and Char encoding output +--DESCRIPTION-- +Verify the Binary and Char encoding output when binding output string with SQLSRV SQL TYPE option with different size +Will not convert this test for AE testing because the goal of this test is to deliberately use a different size for SQLSRV SQL TYPE from the designated output param in the stored procedure --SKIPIF-- - + --FILE-- - --FILE-- 1)); diff --git a/test/functional/sqlsrv/sqlsrv_bug_boolean_cast_inout_bit.phpt b/test/functional/sqlsrv/sqlsrv_bug_boolean_cast_inout_bit.phpt index 450b469a..55324e54 100644 --- a/test/functional/sqlsrv/sqlsrv_bug_boolean_cast_inout_bit.phpt +++ b/test/functional/sqlsrv/sqlsrv_bug_boolean_cast_inout_bit.phpt @@ -7,17 +7,14 @@ false as a bit, a true value cast to a bit, a true value as an int. --ENV-- PHPT_EXEC=true --SKIPIF-- - + --FILE-- diff --git a/test/functional/sqlsrv/sqlsrv_bug_boolean_cast_inout_bool.phpt b/test/functional/sqlsrv/sqlsrv_bug_boolean_cast_inout_bool.phpt index 33e56967..6b1d980e 100644 --- a/test/functional/sqlsrv/sqlsrv_bug_boolean_cast_inout_bool.phpt +++ b/test/functional/sqlsrv/sqlsrv_bug_boolean_cast_inout_bool.phpt @@ -7,17 +7,14 @@ false as a bool, a true value cast to a bool, a true value as an bool. --ENV-- PHPT_EXEC=true --SKIPIF-- - + --FILE-- diff --git a/test/functional/sqlsrv/sqlsrv_bug_boolean_cast_out_bit.phpt b/test/functional/sqlsrv/sqlsrv_bug_boolean_cast_out_bit.phpt index d4660ade..40853ae5 100644 --- a/test/functional/sqlsrv/sqlsrv_bug_boolean_cast_out_bit.phpt +++ b/test/functional/sqlsrv/sqlsrv_bug_boolean_cast_out_bit.phpt @@ -7,19 +7,14 @@ false as a bit, a true value cast to a bit, a true value as an int. --ENV-- PHPT_EXEC=true --SKIPIF-- - + --FILE-- diff --git a/test/functional/sqlsrv/sqlsrv_bug_boolean_cast_out_bool.phpt b/test/functional/sqlsrv/sqlsrv_bug_boolean_cast_out_bool.phpt index 9da6c832..691c29b9 100644 --- a/test/functional/sqlsrv/sqlsrv_bug_boolean_cast_out_bool.phpt +++ b/test/functional/sqlsrv/sqlsrv_bug_boolean_cast_out_bool.phpt @@ -7,19 +7,14 @@ false as a bool, a true value cast to a bool, a true value as an bool. --ENV-- PHPT_EXEC=true --SKIPIF-- - + --FILE-- diff --git a/test/functional/sqlsrv/sqlsrv_complex_query.phpt b/test/functional/sqlsrv/sqlsrv_complex_query.phpt index b09fe81f..16894f3c 100644 --- a/test/functional/sqlsrv/sqlsrv_complex_query.phpt +++ b/test/functional/sqlsrv/sqlsrv_complex_query.phpt @@ -1,23 +1,56 @@ --TEST-- Test a complex query with IDENTITY_INSERT +--DESCRIPTION-- +Verifies the behavior of INSERT queries with and without the IDENTITY flag set. +This test is similar to the other test TC33_ComplexQuery but using UTF-8 data +--SKIPIF-- + --FILE--  $input) { + array_push($params, $inputs[$key]); + } + // this contains a batch of sql statements, + // with set identity_insert on or off + // thus, sqlsrv_query should be called + $sql = str_replace("SQL", $insertSql, $query); + $stmt = sqlsrv_query($conn, $sql, $params); + } + + return $stmt; +} + +function complexQuery() { set_time_limit(0); sqlsrv_configure('WarningsReturnAsErrors', 1); // Connect - $conn = connect(array("CharacterSet"=>"UTF-8")); - if (!$conn) { - fatalError("Could not connect.\n"); + $conn = AE\connect(array("CharacterSet"=>"UTF-8")); + + $tableName = 'complex_query_test'; + $columns = array(new AE\ColumnMeta('int', 'c1_int', "IDENTITY"), + new AE\ColumnMeta('tinyint', 'c2_tinyint'), + new AE\ColumnMeta('smallint', 'c3_smallint'), + new AE\ColumnMeta('bigint', 'c4_bigint'), + new AE\ColumnMeta('varchar(512)', 'c5_varchar')); + $stmt = AE\createTable($conn, $tableName, $columns); + if (!$stmt) { + fatalError("Failed to create table $tableName\n"); } - - $tableName = GetTempTableName(); - - $stmt = sqlsrv_query($conn, "CREATE TABLE $tableName ([c1_int] int IDENTITY, [c2_tinyint] tinyint, [c3_smallint] smallint, [c4_bigint] bigint, [c5_varchar] varchar(512))"); sqlsrv_free_stmt($stmt); $noExpectedRows = 0; @@ -26,12 +59,16 @@ function ComplexQuery() sqlsrv_free_stmt($stmt); $noExpectedRows++; - $stmt = sqlsrv_query($conn, "INSERT INTO $tableName (c1_int, c2_tinyint, c3_smallint, c4_bigint, c5_varchar) VALUES (1324944463, 105, 18521, 2022363960, 'üv£ª©*@*rãCaC|/ä*,,@ý©bvªäîCUBão_+ßZhUªî¢~ÖÜ/ª@ä+ßßar~Özr,aß/,bCaü<ÖÐhÐbß<î/ðzãý+bÜ:Zßöüª@BÖUßUßaåab|¢ª¢|ü£/ÃßzzuªãA.ªZUöß<©a>OzübBüÜ|bZ./öbvß*rbö>ß©r//~ÖCÜhð¢bßz:¢Ä+_Ã__£ý£Uýh:v¢bý,©Ü£©,A:Zh>ßåvö+Ä>Ã.ßvC|:Ü*Üü*åz|b.©©üAý@uU.oOÜýAÜÐÜð©OB|rrîbU<övoUßäZÃÖ<ÄåªAÄ.Ua*ÖOªB,åîzB:ÜhövÖZhýðüC')"); + $inputs = array("c1_int" => 1324944463, "c2_tinyint" => 105, "c3_smallint" => 18521, "c4_bigint" => 2022363960, "c5_varchar" => "üv£ª©*@*rãCaC|/ä*,,@ý©bvªäîCUBão_+ßZhUªî¢~ÖÜ/ª@ä+ßßar~Özr,aß/,bCaü<ÖÐhÐbß<î/ðzãý+bÜ:Zßöüª@BÖUßUßaåab|¢ª¢|ü£/ÃßzzuªãA.ªZUöß<©a>OzübBüÜ|bZ./öbvß*rbö>ß©r//~ÖCÜhð¢bßz:¢Ä+_Ã__£ý£Uýh:v¢bý,©Ü£©,A:Zh>ßåvö+Ä>Ã.ßvC|:Ü*Üü*åz|b.©©üAý@uU.oOÜýAÜÐÜð©OB|rrîbU<övoUßäZÃÖ<ÄåªAÄ.Ua*ÖOªB,åîzB:ÜhövÖZhýðüC"); + $stmt = AE\insertRow($conn, $tableName, $inputs); + unset($inputs); sqlsrv_free_stmt($stmt); $stmt = sqlsrv_query($conn, "SET IDENTITY_INSERT $tableName OFF;"); sqlsrv_free_stmt($stmt); - $stmt = sqlsrv_query($conn, "INSERT INTO $tableName (c1_int, c2_tinyint, c3_smallint, c4_bigint, c5_varchar) VALUES (-1554807493, 253, -12809, -1698802997, 'ßöîÄ@v+oß+î|ruý*Ü¢ãÖ~.*ArABªßOBzUU£ßUuÜ<ðýr|b~_äaü/OÖzv.¢ä>>OÜ+¢vªzöªoB_ä+ߪrÜö£>U~ãÖð~ðýur,ÖvZh¢ªZ>vªUäåîz,>ÃräðäýðO_ä*a,ö+üÐß~bÃü¢<<+îýÐöäªO/zA+:îZ,öBÐü<î£îåhBÖzßÄ~,:>bð<~aÐãö¢*¢våvÃÐåî@a_Äu£öa~våu>¢Bã©å:Aßã£Üvåö+aä£U<¢b@|zbãÖ@ÃãUb|ÄB£©,~ßð©ðUßöZÜöî£Zz<>åäZßð©ßaÖÖ¢bð£ßÄ>îÃÃ.~z>h_ý~ÜrüÖBruß+ª©CB©O>rå,Chro,£ßbZ_ß©,ÃUu|ßåüÄ/ý*åu|~Ö.ßZUoä:~A~CZhðU|öZ:ä/£Ä*î©ÄhävhbrzîÐ@.rãß©@uÜ©~>ÖÜööCÄzÜCü+>oZÄÜ/ABßA_b|b¢bÜh<|uBr.B*rü>aCª|AÄ©@öÖßÖ~Ö -1554807493, "c2_tinyint" => 253, "c3_smallint" => -12809, "c4_bigint" => -1698802997, "c5_varchar" => "ßöîÄ@v+oß+î|ruý*Ü¢ãÖ~.*ArABªßOBzUU£ßUuÜ<ðýr|b~_äaü/OÖzv.¢ä>>OÜ+¢vªzöªoB_ä+ߪrÜö£>U~ãÖð~ðýur,ÖvZh¢ªZ>vªUäåîz,>ÃräðäýðO_ä*a,ö+üÐß~bÃü¢<<+îýÐöäªO/zA+:îZ,öBÐü<î£îåhBÖzßÄ~,:>bð<~aÐãö¢*¢våvÃÐåî@a_Äu£öa~våu>¢Bã©å:Aßã£Üvåö+aä£U<¢b@|zbãÖ@ÃãUb|ÄB£©,~ßð©ðUßöZÜöî£Zz<>åäZßð©ßaÖÖ¢bð£ßÄ>îÃÃ.~z>h_ý~ÜrüÖBruß+ª©CB©O>rå,Chro,£ßbZ_ß©,ÃUu|ßåüÄ/ý*åu|~Ö.ßZUoä:~A~CZhðU|öZ:ä/£Ä*î©ÄhävhbrzîÐ@.rãß©@uÜ©~>ÖÜööCÄzÜCü+>oZÄÜ/ABßA_b|b¢bÜh<|uBr.B*rü>aCª|AÄ©@öÖßÖ~ÖüoîzÄ¢zz~Ãýö|vUå>|CÄUü~>buÃv<ä~Ö+.ü*ªbuî_bBC©.oîCbåîÐÖUa~/U>öAäÐBu~ozîZ/zrOOä:ß©bßo.ü©A¢höÖoßÖü>r+A/ßaªrß:ª@|bhhªª/oå<Ö:rüa+oC¢~uÄü>/.ãbOöª_b@bbߢ|uzߪ֢~uäýub©ãaZäC£ÄrÖ,üöäu+Ãîö|||,U.BråãoýbüåöÃburöoî+>öä©î,u_öb©@C:ÜåÜîÜåAÖzýbð|Z<Ãý.£rîZ|/z@¢£AýZ,ßuZ*:b.AzТä¢üßöbvbväð|<**~Uv.Ð*Ä©B*ýCUöa¢åO©Ãß*ÃÃ|ÜðA@îÃßaBöüahUUA+ߣ_u|~äö.©hr£oBo<äãüO+_åO:Z~Üoîßzb£ª£A.AÖÜÄ._O_å£ß');SET IDENTITY_INSERT $tableName OFF;"); + if (AE\isColEncrypted()) { + // When AE is enabled, SQL types must be specified for sqlsrv_query + $inputs = array("c1_int" => array(1994559593, null, null, SQLSRV_SQLTYPE_INT), + "c2_tinyint" => array(129, null, null, SQLSRV_SQLTYPE_TINYINT), + "c3_smallint" => array(-8455, null, null, SQLSRV_SQLTYPE_SMALLINT), + "c4_bigint" => array(-236232445, null, null, SQLSRV_SQLTYPE_BIGINT), + "c5_varchar" => array("ߣ*ÐO+ö+<ã:>üoîzÄ¢zz~Ãýö|vUå>|CÄUü~>buÃv<ä~Ö+.ü*ªbuî_bBC©.oîCbåîÐÖUa~/U>öAäÐBu~ozîZ/zrOOä:ß©bßo.ü©A¢höÖoßÖü>r+A/ßaªrß:ª@|bhhªª/oå<Ö:rüa+oC¢~uÄü>/.ãbOöª_b@bbߢ|uzߪ֢~uäýub©ãaZäC£ÄrÖ,üöäu+Ãîö|||,U.BråãoýbüåöÃburöoî+>öä©î,u_öb©@C:ÜåÜîÜåAÖzýbð|Z<Ãý.£rîZ|/z@¢£AýZ,ßuZ*:b.AzТä¢üßöbvbväð|<**~Uv.Ð*Ä©B*ýCUöa¢åO©Ãß*ÃÃ|ÜðA@îÃßaBöüahUUA+ߣ_u|~äö.©hr£oBo<äãüO+_åO:Z~Üoîßzb£ª£A.AÖÜÄ._O_å£ß", null, null, SQLSRV_SQLTYPE_VARCHAR(512))); + } else { + $inputs = array("c1_int" => 1994559593, "c2_tinyint" => 129, "c3_smallint" => -8455, "c4_bigint" => -236232445, "c5_varchar" => "ߣ*ÐO+ö+<ã:>üoîzÄ¢zz~Ãýö|vUå>|CÄUü~>buÃv<ä~Ö+.ü*ªbuî_bBC©.oîCbåîÐÖUa~/U>öAäÐBu~ozîZ/zrOOä:ß©bßo.ü©A¢höÖoßÖü>r+A/ßaªrß:ª@|bhhªª/oå<Ö:rüa+oC¢~uÄü>/.ãbOöª_b@bbߢ|uzߪ֢~uäýub©ãaZäC£ÄrÖ,üöäu+Ãîö|||,U.BråãoýbüåöÃburöoî+>öä©î,u_öb©@C:ÜåÜîÜåAÖzýbð|Z<Ãý.£rîZ|/z@¢£AýZ,ßuZ*:b.AzТä¢üßöbvbväð|<**~Uv.Ð*Ä©B*ýCUöa¢åO©Ãß*ÃÃ|ÜðA@îÃßaBöüahUUA+ߣ_u|~äö.©hr£oBo<äãüO+_åO:Z~Üoîßzb£ª£A.AÖÜÄ._O_å£ß"); + } + $query = "SET IDENTITY_INSERT [$tableName] ON; SQL; SET IDENTITY_INSERT [$tableName] OFF;"; + $stmt = insertTest($conn, $tableName, $inputs, $query); + print_r(sqlsrv_errors()); + unset($inputs); sqlsrv_free_stmt($stmt); echo "Number of rows inserted: $noExpectedRows\n"; @@ -60,28 +110,19 @@ function ComplexQuery() if ($noActualRows != $noExpectedRows) { echo("Number of rows does not match expected value\n"); } + + dropTable($conn, $tableName); sqlsrv_close($conn); } -//-------------------------------------------------------------------- -// Repro -// -//-------------------------------------------------------------------- -function Repro() -{ - startTest("sqlsrv_statement_complex_query"); - echo "\nTest begins...\n"; +echo "\nTest begins...\n"; - try { - ComplexQuery(); - } catch (Exception $e) { - echo $e->getMessage(); - } - echo "\nDone\n"; - endTest("sqlsrv_statement_complex_query"); +try { + complexQuery(); +} catch (Exception $e) { + echo $e->getMessage(); } - -Repro(); +echo "\nDone\n"; ?> --EXPECTREGEX-- @@ -94,4 +135,3 @@ Number of rows inserted: 2 Number of rows fetched: 2 Done -Test \"sqlsrv_statement_complex_query\" completed successfully\. diff --git a/test/functional/sqlsrv/sqlsrv_connect_encrypted_ksp.phpt b/test/functional/sqlsrv/sqlsrv_connect_encrypted_ksp.phpt index 7bd6b932..49a3c469 100644 --- a/test/functional/sqlsrv/sqlsrv_connect_encrypted_ksp.phpt +++ b/test/functional/sqlsrv/sqlsrv_connect_encrypted_ksp.phpt @@ -4,15 +4,49 @@ Fetch data from a prepopulated test table given a custom keystore provider --FILE-- true)); - if ($conn === false) { - echo "Failed to connect.\n"; - print_r(sqlsrv_errors()); - } else { + if ($conn !== false) { echo "Connected successfully with ColumnEncryption enabled.\n"; } @@ -20,13 +54,15 @@ Fetch data from a prepopulated test table given a custom keystore provider $tsql = "SELECT * FROM $ksp_test_table"; $stmt = sqlsrv_prepare($conn, $tsql); if (!sqlsrv_execute($stmt)) { - echo "Failed to fetch data.\n"; - print_r(sqlsrv_errors()); + fatalError("Failed to fetch data.\n"); } // fetch data + $id = 0; while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_NUMERIC)) { - echo "c1=" . $row[0] . "\tc2=" . $row[1] . "\tc3=" . $row[2] . "\tc4=" . $row[3] . "\n" ; + if (!verifyData($row, $id++)) { + break; + } } sqlsrv_free_stmt($stmt); @@ -36,14 +72,4 @@ Fetch data from a prepopulated test table given a custom keystore provider ?> --EXPECT-- Connected successfully with ColumnEncryption enabled. -c1=1 c2=Sample data 0 for column 2 c3=abc c4=2017-08-10 -c1=12 c2=Sample data 1 for column 2 c3=bcd c4=2017-08-11 -c1=23 c2=Sample data 2 for column 2 c3=cde c4=2017-08-12 -c1=34 c2=Sample data 3 for column 2 c3=def c4=2017-08-13 -c1=45 c2=Sample data 4 for column 2 c3=efg c4=2017-08-14 -c1=56 c2=Sample data 5 for column 2 c3=fgh c4=2017-08-15 -c1=67 c2=Sample data 6 for column 2 c3=ghi c4=2017-08-16 -c1=78 c2=Sample data 7 for column 2 c3=hij c4=2017-08-17 -c1=89 c2=Sample data 8 for column 2 c3=ijk c4=2017-08-18 -c1=100 c2=Sample data 9 for column 2 c3=jkl c4=2017-08-19 Done diff --git a/test/functional/sqlsrv/sqlsrv_connect_encrypted_ksp_encrypted.phpt b/test/functional/sqlsrv/sqlsrv_connect_encrypted_ksp_encrypted.phpt index b2ea6c77..4a96a8df 100644 --- a/test/functional/sqlsrv/sqlsrv_connect_encrypted_ksp_encrypted.phpt +++ b/test/functional/sqlsrv/sqlsrv_connect_encrypted_ksp_encrypted.phpt @@ -7,7 +7,7 @@ Fetch encrypted data from a prepopulated test table given a custom keystore prov sqlsrv_configure('WarningsReturnAsErrors', 1); sqlsrv_configure('LogSeverity', SQLSRV_LOG_SEVERITY_ALL); - require_once('MsHelper.inc'); + require_once('MsCommon.inc'); $conn = AE\connect(array('ReturnDatesAsStrings'=>true)); if ($conn === false) { fatalError("Failed to connect.\n"); diff --git a/test/functional/sqlsrv/sqlsrv_data_types_explict_fetch.phpt b/test/functional/sqlsrv/sqlsrv_data_types_explict_fetch.phpt index 4a694b28..476f9a3c 100644 --- a/test/functional/sqlsrv/sqlsrv_data_types_explict_fetch.phpt +++ b/test/functional/sqlsrv/sqlsrv_data_types_explict_fetch.phpt @@ -1,45 +1,64 @@ --TEST-- Test insert various data types and fetch as strings +--SKIPIF-- + --FILE-- "UTF-8"); - $conn = connect($connectionInfo); - if (!$conn) { - fatalError("Could not connect.\n"); + $conn = AE\connect($connectionInfo); + + $tableName = 'types_explict_fetch'; + $columns = array(new AE\ColumnMeta('int', 'c1_int'), + new AE\ColumnMeta('tinyint', 'c2_tinyint'), + new AE\ColumnMeta('smallint', 'c3_smallint'), + new AE\ColumnMeta('bigint', 'c4_bigint'), + new AE\ColumnMeta('bit', 'c5_bit'), + new AE\ColumnMeta('float', 'c6_float'), + new AE\ColumnMeta('real', 'c7_real'), + new AE\ColumnMeta('decimal(28,4)', 'c8_decimal'), + new AE\ColumnMeta('numeric(32,4)', 'c9_numeric'), + new AE\ColumnMeta('money', 'c10_money', null, true, true), + new AE\ColumnMeta('smallmoney', 'c11_smallmoney', null, true, true), + new AE\ColumnMeta('char(512)', 'c12_char'), + new AE\ColumnMeta('varchar(512)', 'c13_varchar'), + new AE\ColumnMeta('varchar(max)', 'c14_varchar_max'), + new AE\ColumnMeta('uniqueidentifier', 'c15_uniqueidentifier'), + new AE\ColumnMeta('datetime', 'c16_datetime'), + new AE\ColumnMeta('smalldatetime', 'c17_smalldatetime'), + new AE\ColumnMeta('timestamp', 'c18_timestamp') + ); + $stmt = AE\createTable($conn, $tableName, $columns); + if (!$stmt) { + fatalError("Failed to create table $tableName\n"); } - $tableName = GetTempTableName(); - - $stmt = sqlsrv_query($conn, "CREATE TABLE [$tableName] ([c1_int] int, [c2_tinyint] tinyint, [c3_smallint] smallint, [c4_bigint] bigint, [c5_bit] bit, [c6_float] float, [c7_real] real, [c8_decimal] decimal(28,4), [c9_numeric] numeric(32,4), [c10_money] money, [c11_smallmoney] smallmoney, [c12_char] char(512), [c13_varchar] varchar(512), [c14_varchar_max] varchar(max), [c15_uniqueidentifier] uniqueidentifier, [c16_datetime] datetime, [c17_smalldatetime] smalldatetime, [c18_timestamp] timestamp)"); - sqlsrv_free_stmt($stmt); - $numRows = 0; - $data = GetInputData(++$numRows); - $stmt = sqlsrv_query($conn, "INSERT INTO [$tableName] (c1_int, c2_tinyint, c3_smallint, c4_bigint, c5_bit, c6_float, c7_real, c8_decimal, c9_numeric, c10_money, c11_smallmoney, c12_char, c13_varchar, c14_varchar_max, c15_uniqueidentifier, c16_datetime, c17_smalldatetime) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $data); + $data = getInputData(++$numRows); + $stmt = AE\executeQueryParams($conn, "INSERT INTO [$tableName] (c1_int, c2_tinyint, c3_smallint, c4_bigint, c5_bit, c6_float, c7_real, c8_decimal, c9_numeric, c10_money, c11_smallmoney, c12_char, c13_varchar, c14_varchar_max, c15_uniqueidentifier, c16_datetime, c17_smalldatetime) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $data); sqlsrv_free_stmt($stmt); - $data = GetInputData(++$numRows); - $stmt = sqlsrv_query($conn, "INSERT INTO [$tableName] (c1_int, c2_tinyint, c3_smallint, c4_bigint, c5_bit, c6_float, c7_real, c8_decimal, c9_numeric, c10_money, c11_smallmoney, c12_char, c13_varchar, c14_varchar_max, c15_uniqueidentifier, c16_datetime, c17_smalldatetime) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $data); + $data = getInputData(++$numRows); + $stmt = AE\executeQueryParams($conn, "INSERT INTO [$tableName] (c1_int, c2_tinyint, c3_smallint, c4_bigint, c5_bit, c6_float, c7_real, c8_decimal, c9_numeric, c10_money, c11_smallmoney, c12_char, c13_varchar, c14_varchar_max, c15_uniqueidentifier, c16_datetime, c17_smalldatetime) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $data); sqlsrv_free_stmt($stmt); - $data = GetInputData(++$numRows); - $stmt = sqlsrv_query($conn, "INSERT INTO [$tableName] (c1_int, c2_tinyint, c3_smallint, c4_bigint, c5_bit, c6_float, c7_real, c8_decimal, c9_numeric, c10_money, c11_smallmoney, c12_char, c13_varchar, c14_varchar_max, c15_uniqueidentifier, c16_datetime, c17_smalldatetime) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $data); + $data = getInputData(++$numRows); + $stmt = AE\executeQueryParams($conn, "INSERT INTO [$tableName] (c1_int, c2_tinyint, c3_smallint, c4_bigint, c5_bit, c6_float, c7_real, c8_decimal, c9_numeric, c10_money, c11_smallmoney, c12_char, c13_varchar, c14_varchar_max, c15_uniqueidentifier, c16_datetime, c17_smalldatetime) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $data); sqlsrv_free_stmt($stmt); - $data = GetInputData(++$numRows); - $stmt = sqlsrv_query($conn, "INSERT INTO [$tableName] (c1_int, c2_tinyint, c3_smallint, c4_bigint, c5_bit, c6_float, c7_real, c8_decimal, c9_numeric, c10_money, c11_smallmoney, c12_char, c13_varchar, c14_varchar_max, c15_uniqueidentifier, c16_datetime, c17_smalldatetime) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $data); + $data = getInputData(++$numRows); + $stmt = AE\executeQueryParams($conn, "INSERT INTO [$tableName] (c1_int, c2_tinyint, c3_smallint, c4_bigint, c5_bit, c6_float, c7_real, c8_decimal, c9_numeric, c10_money, c11_smallmoney, c12_char, c13_varchar, c14_varchar_max, c15_uniqueidentifier, c16_datetime, c17_smalldatetime) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", $data); sqlsrv_free_stmt($stmt); - $stmt = sqlsrv_query($conn, "SELECT * FROM $tableName ORDER BY c18_timestamp"); + $stmt = AE\executeQuery($conn, "SELECT * FROM $tableName ORDER BY c18_timestamp"); $metadata = sqlsrv_field_metadata($stmt); $numFields = count($metadata); @@ -49,10 +68,11 @@ function ExplicitFetch() echo "Number of Actual Rows $noActualRows is unexpected!\n"; } + dropTable($conn, $tableName); sqlsrv_close($conn); } -function GetInputData($index) +function getInputData($index) { switch ($index) { case 1: @@ -68,20 +88,13 @@ function GetInputData($index) } } -function Repro() -{ - startTest("sqlsrv_data_types_explict_fetch"); - echo "\nTest begins...\n"; - try { - ExplicitFetch(); - } catch (Exception $e) { - echo $e->getMessage(); - } - echo "\nDone\n"; - endTest("sqlsrv_data_types_explict_fetch"); +echo "\nTest begins...\n"; +try { + explicitFetch(); +} catch (Exception $e) { + echo $e->getMessage(); } - -Repro(); +echo "\nDone\n"; ?> --EXPECT-- @@ -93,4 +106,3 @@ Comparing data in row 3 Comparing data in row 4 Done -Test "sqlsrv_data_types_explict_fetch" completed successfully. diff --git a/test/functional/sqlsrv/sqlsrv_encrypted_query_nosqltype.phpt b/test/functional/sqlsrv/sqlsrv_encrypted_query_nosqltype.phpt index 5df1ad65..2ed4df38 100644 --- a/test/functional/sqlsrv/sqlsrv_encrypted_query_nosqltype.phpt +++ b/test/functional/sqlsrv/sqlsrv_encrypted_query_nosqltype.phpt @@ -1,9 +1,25 @@ --TEST-- Test using sqlsrv_query for binding parameters with column encryption and a custom keystore provider --SKIPIF-- - + --FILE-- SSN = $ssn; + $this->FirstName = $fname; + $this->LastName = $lname; + $this->BirthDate = $bdate; + } + } + function createPatientsTable() { global $conn; @@ -23,26 +39,49 @@ Test using sqlsrv_query for binding parameters with column encryption and a cust function selectData() { - global $conn, $tableName; + global $conn, $tableName, $numRows, $patient; $stmt = sqlsrv_query($conn, "SELECT * FROM $tableName"); + $id = 1; while ($obj = sqlsrv_fetch_object($stmt)) { - echo $obj->PatientId . "\n"; - echo $obj->SSN . "\n"; - echo $obj->FirstName . "\n"; - echo $obj->LastName . "\n"; - echo $obj->BirthDate . "\n\n"; + if ($obj->PatientId !== $id) { + echo "Expected $id but got $obj->PatientId\n"; + } + if ($obj->SSN !== $patient->SSN) { + echo "Expected $patient->SSN but got $obj->SSN\n"; + } + if ($obj->FirstName !== $patient->FirstName) { + echo "Expected $patient->FirstName but got $obj->FirstName\n"; + } + if ($obj->LastName !== $patient->LastName) { + echo "Expected $patient->LastName but got $obj->LastName\n"; + } + if ($obj->BirthDate !== $patient->BirthDate) { + echo "Expected $patient->BirthDate but got $obj->BirthDate\n"; + } + + $id++; + } + $rowFetched = $id - 1; + if ($rowFetched != $numRows){ + echo "Expected $numRows rows but got $rowFetched\n"; } } function printError() { + global $AEQueryError; + $errors = sqlsrv_errors(); - foreach ($errors as $error) { - echo " SQLSTATE: " . $error['SQLSTATE'] . "\n"; - echo " code: " . $error['code'] . "\n"; - echo " message: " . $error['message'] . "\n\n"; + if (AE\isColEncrypted()) { + verifyError($errors[0], 'IMSSP', $AEQueryError); + } else { + foreach ($errors as $error) { + echo " SQLSTATE: " . $error['SQLSTATE'] . "\n"; + echo " code: " . $error['code'] . "\n"; + echo " message: " . $error['message'] . "\n\n"; + } } } @@ -51,24 +90,28 @@ Test using sqlsrv_query for binding parameters with column encryption and a cust require_once('MsHelper.inc'); $conn = AE\connect(array('ReturnDatesAsStrings'=>true)); - - if ($conn === false) { - echo "Failed to connect.\n"; - printError(); - } else { + if ($conn !== false) { echo "Connected successfully with ColumnEncryption enabled.\n\n"; } + $AEQueryError = 'Must specify the SQL type for each parameter in a parameterized query when using sqlsrv_query in a column encryption enabled connection.'; + $tableName = createPatientsTable(); + $numRows = 0; + $tsql = "INSERT INTO $tableName (SSN, FirstName, LastName, BirthDate) VALUES (?, ?, ?, ?)"; - $inputs = array('748-68-0245', 'Jeannette', 'McDonald', '2002-11-28'); + $patient = new Patient('748-68-0245', 'Jeannette', 'McDonald', '2002-11-28'); + $inputs = array($patient->SSN, $patient->FirstName, $patient->LastName, $patient->BirthDate); // expects an error in Column Encryption enabled connection print_r("Using sqlsrv_query and binding parameters with literal values:\n"); + $stmt = sqlsrv_query($conn, $tsql, $inputs); if (!$stmt) { printError(); + } else { + $numRows++; } // expects an error in Column Encryption enabled connection @@ -79,7 +122,10 @@ Test using sqlsrv_query for binding parameters with column encryption and a cust array($inputs[3], SQLSRV_PARAM_IN))); if (!$stmt) { printError(); + } else { + $numRows++; } + // no error is expected print_r("Using sqlsrv_query and binding parameters with parameter arrays and sqltypes provided:\n"); $stmt = sqlsrv_query($conn, $tsql, array(array($inputs[0], null, null, SQLSRV_SQLTYPE_CHAR(11)), @@ -88,7 +134,10 @@ Test using sqlsrv_query for binding parameters with column encryption and a cust array($inputs[3], null, null, SQLSRV_SQLTYPE_DATE))); if (!$stmt) { printError(); + } else { + $numRows++; } + selectData(); echo "Done\n"; @@ -97,20 +146,6 @@ Test using sqlsrv_query for binding parameters with column encryption and a cust Connected successfully with ColumnEncryption enabled. Using sqlsrv_query and binding parameters with literal values: - SQLSTATE: IMSSP - code: -63 - message: Must specify the SQL type for each parameter in a parameterized query when using sqlsrv_query in a column encryption enabled connection. - Using sqlsrv_query and binding parameters with parameter arrays and no sqltypes provided: - SQLSTATE: IMSSP - code: -63 - message: Must specify the SQL type for each parameter in a parameterized query when using sqlsrv_query in a column encryption enabled connection. - Using sqlsrv_query and binding parameters with parameter arrays and sqltypes provided: -1 -748-68-0245 -Jeannette -McDonald -2002-11-28 - Done \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_errors.phpt b/test/functional/sqlsrv/sqlsrv_errors.phpt index 5f3cbc7a..064357da 100644 --- a/test/functional/sqlsrv/sqlsrv_errors.phpt +++ b/test/functional/sqlsrv/sqlsrv_errors.phpt @@ -5,119 +5,118 @@ make sure errors are cleared for each new API call invalid parameters are reported via sqlsrv_errors, and sqlsrv_close returns true even if an error happens. --SKIPIF-- - + --FILE-- "test" )); + $conn = sqlsrv_connect("InvalidServerName", array( "Database" => "test" )); $result = sqlsrv_close($conn); $errors = sqlsrv_errors(); - if( $result !== false ) { - die( "sqlsrv_close succeeded despite an invalid server name." ); + if ($result !== false) { + die("sqlsrv_close succeeded despite an invalid server name."); } - print_r( $errors ); + print_r($errors); - $conn = Connect(); - if( !$conn ) { - var_dump( sqlsrv_errors() ); - die( "sqlsrv_create failed." ); + $conn = AE\connect(); + $tableName = 'test_params'; + $columns = array(new AE\ColumnMeta('tinyint', 'id'), + new AE\ColumnMeta('char(10)', 'name'), + new AE\ColumnMeta('float', 'double'), + new AE\ColumnMeta('varchar(max)', 'stuff')); + $stmt = AE\createTable($conn, $tableName, $columns); + if (!$stmt) { + fatalError("Failed to create table $tableName\n"); } - - $stmt = sqlsrv_query( $conn, "IF OBJECT_ID('test_params', 'U') IS NOT NULL DROP TABLE test_params" ); - sqlsrv_free_stmt( $stmt ); - - $stmt = sqlsrv_prepare( $conn, "CREATE TABLE test_params (id tinyint, name char(10), [double] float, stuff varchar(max))" ); - sqlsrv_execute( $stmt ); - sqlsrv_free_stmt( $stmt ); + sqlsrv_free_stmt($stmt); $f1 = 1; $f2 = "testtestte"; $f3 = 12.0; - $f4 = fopen( "data://text/plain,This%20is%20some%20text%20meant%20to%20test%20binding%20parameters%20to%20streams", "r" ); + $f4 = fopen("data://text/plain,This%20is%20some%20text%20meant%20to%20test%20binding%20parameters%20to%20streams", "r"); - $stmt = sqlsrv_prepare( $conn, "INSERT INTO test_params (id, name, [double], stuff) VALUES (?, ?, ?, ?)", array( &$f1, "testtestte", &$f3, &$f4 )); - if( !$stmt ) { - var_dump( sqlsrv_errors() ); - die( "sqlsrv_prepare failed." ); + $stmt = sqlsrv_prepare($conn, "INSERT INTO $tableName (id, name, [double], stuff) VALUES (?, ?, ?, ?)", array( &$f1, "testtestte", &$f3, &$f4 )); + if (!$stmt) { + var_dump(sqlsrv_errors()); + die("sqlsrv_prepare failed."); } - $success = sqlsrv_execute( $stmt ); - if( !$success ) { - var_dump( sqlsrv_errors() ); - die( "sqlsrv_execute failed." ); + $success = sqlsrv_execute($stmt); + if (!$success) { + var_dump(sqlsrv_errors()); + die("sqlsrv_execute failed."); } - while( $success = sqlsrv_send_stream_data( $stmt )) { + while ($success = sqlsrv_send_stream_data($stmt)) { } - if( !is_null( $success )) { - sqlsrv_cancel( $stmt ); - sqlsrv_free_stmt( $stmt ); - die( "sqlsrv_send_stream_data failed." ); + if (!is_null($success)) { + sqlsrv_cancel($stmt); + sqlsrv_free_stmt($stmt); + die("sqlsrv_send_stream_data failed."); } $f1 = 2; $f3 = 13.0; - $f4 = fopen( "data://text/plain,This%20is%20some%20more%20text%20meant%20to%20test%20binding%20parameters%20to%20streams", "r" ); - $success = sqlsrv_execute( $stmt ); - if( !$success ) { - var_dump( sqlsrv_errors() ); - die( "sqlsrv_execute failed." ); + $f4 = fopen("data://text/plain,This%20is%20some%20more%20text%20meant%20to%20test%20binding%20parameters%20to%20streams", "r"); + $success = sqlsrv_execute($stmt); + if (!$success) { + var_dump(sqlsrv_errors()); + die("sqlsrv_execute failed."); } - while( $success = sqlsrv_send_stream_data( $stmt )) { + while ($success = sqlsrv_send_stream_data($stmt)) { } - if( !is_null( $success )) { - sqlsrv_cancel( $stmt ); - sqlsrv_free_stmt( $stmt ); - die( "sqlsrv_send_stream_data failed." ); + if (!is_null($success)) { + sqlsrv_cancel($stmt); + sqlsrv_free_stmt($stmt); + die("sqlsrv_send_stream_data failed."); } - $result = sqlsrv_free_stmt( $stmt ); - if( $result === false ) { - die( print_r( sqlsrv_errors(), true )); + $result = sqlsrv_free_stmt($stmt); + if ($result === false) { + die(print_r(sqlsrv_errors(), true)); } - $result = sqlsrv_free_stmt( $stmt ); - if( $result === false ) { - die( print_r( sqlsrv_errors(), true )); + $result = sqlsrv_free_stmt($stmt); + if ($result === false) { + die(print_r(sqlsrv_errors(), true)); } - $result = sqlsrv_free_stmt( null ); - if( $result === false ) { - die( print_r( sqlsrv_errors(), true )); + $result = sqlsrv_free_stmt(null); + if ($result === false) { + die(print_r(sqlsrv_errors(), true)); } - $result = sqlsrv_free_stmt( $conn ); - if( $result !== false ) { - die( "sqlsrv_free_stmt shouldn't have freed the connection resource" ); + $result = sqlsrv_free_stmt($conn); + if ($result !== false) { + die("sqlsrv_free_stmt shouldn't have freed the connection resource"); } - print_r( sqlsrv_errors() ); - $result = sqlsrv_free_stmt( 1 ); - if( $result !== false ) { - die( "sqlsrv_free_stmt shouldn't have freed a 1" ); + print_r(sqlsrv_errors()); + $result = sqlsrv_free_stmt(1); + if ($result !== false) { + die("sqlsrv_free_stmt shouldn't have freed a 1"); } - print_r( sqlsrv_errors() ); + print_r(sqlsrv_errors()); - sqlsrv_query( $conn, "DROP TABLE test_params" ); + dropTable($conn, $tableName); - $result = sqlsrv_close( $conn ); - if( $result === false ) { - die( print_r( sqlsrv_errors(), true )); + $result = sqlsrv_close($conn); + if ($result === false) { + die(print_r(sqlsrv_errors(), true)); } - $result = sqlsrv_close( $conn ); - if( $result === false ) { - die( print_r( sqlsrv_errors(), true )); + $result = sqlsrv_close($conn); + if ($result === false) { + die(print_r(sqlsrv_errors(), true)); } - $result = sqlsrv_close( null ); - if( $result === false ) { - die( print_r( sqlsrv_errors(), true )); + $result = sqlsrv_close(null); + if ($result === false) { + die(print_r(sqlsrv_errors(), true)); } - $result = sqlsrv_close( 1 ); - if( $result !== false ) { - die( "sqlsrv_close shouldn't have freed a 1" ); + $result = sqlsrv_close(1); + if ($result !== false) { + die("sqlsrv_close shouldn't have freed a 1"); } - print_r( sqlsrv_errors() ); + print_r(sqlsrv_errors()); - echo "Test successful.\n"; + echo "Test successfully done.\n"; ?> --EXPECTF-- Warning: sqlsrv_close() expects parameter 1 to be resource, boolean given in %Ssqlsrv_errors.php on line %x @@ -187,4 +186,4 @@ Array ) ) -Test successful. +Test successfully done. diff --git a/test/functional/sqlsrv/sqlsrv_fetch_complex_transactions.phpt b/test/functional/sqlsrv/sqlsrv_fetch_complex_transactions.phpt index 098f8d29..e1f29a82 100644 --- a/test/functional/sqlsrv/sqlsrv_fetch_complex_transactions.phpt +++ b/test/functional/sqlsrv/sqlsrv_fetch_complex_transactions.phpt @@ -1,14 +1,20 @@ --TEST-- Test transactions commit, rollback and aborting in between +--SKIPIF-- + --FILE-- getMessage(); - } - echo "\nDone\n"; - endTest("sqlsrv_fetch_complex_transactions"); + sqlsrv_close($conn2); // $conn should have been closed +} catch (Exception $e) { + echo $e->getMessage(); } - -RunTest(); +echo "\nDone\n"; ?> --EXPECT-- @@ -143,4 +131,3 @@ Deletion aborted Number of rows fetched: 4 Done -Test "sqlsrv_fetch_complex_transactions" completed successfully. diff --git a/test/functional/sqlsrv/sqlsrv_fetch_large_stream.phpt b/test/functional/sqlsrv/sqlsrv_fetch_large_stream.phpt new file mode 100644 index 00000000..3bb94841 --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_fetch_large_stream.phpt @@ -0,0 +1,80 @@ +--TEST-- +Streaming Field Test +--DESCRIPTION-- +Verifies the streaming behavior and proper error handling with Always Encrypted +--SKIPIF-- + +--FILE-- + 1)) { + $success = false; + } + + if (!$success) { + trace("\nData error\nExpected:\n$expected\nActual:\n$actual\n"); + } + + return ($success); +} +?> +--EXPECT-- +Done. \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_input_param_unknown_encoding.phpt b/test/functional/sqlsrv/sqlsrv_input_param_unknown_encoding.phpt index 65e90fc6..aa796ae9 100644 --- a/test/functional/sqlsrv/sqlsrv_input_param_unknown_encoding.phpt +++ b/test/functional/sqlsrv/sqlsrv_input_param_unknown_encoding.phpt @@ -1,50 +1,50 @@ --TEST-- test input param with unknown encoding --SKIPIF-- - + --FILE-- --EXPECTREGEX-- -(Warning|Notice)\: Use of undefined constant SQLSRV_ENC_UNKNOWN - assumed \'SQLSRV_ENC_UNKNOWN\' (\(this will throw an Error in a future version of PHP\) )?in .+(\/|\\)sqlsrv_input_param_unknown_encoding\.php on line 26 -Array -\( - \[0\] => Array - \( - \[0\] => IMSSP - \[SQLSTATE\] => IMSSP - \[1\] => -16 - \[code\] => -16 - \[2\] => An invalid PHP type for parameter 2 was specified\. - \[message\] => An invalid PHP type for parameter 2 was specified\. - \) +(Warning|Notice)\: Use of undefined constant SQLSRV_ENC_UNKNOWN - assumed \'SQLSRV_ENC_UNKNOWN\' (\(this will throw an Error in a future version of PHP\) )?in .+(\/|\\)sqlsrv_input_param_unknown_encoding\.php on line 24 -\) - -(Warning|Notice)\: Use of undefined constant SQLSRV_ENC_UNKNOWN - assumed \'SQLSRV_ENC_UNKNOWN\' (\(this will throw an Error in a future version of PHP\) )?in .+(\/|\\)sqlsrv_input_param_unknown_encoding\.php on line 33 -Array -\( - \[0\] => Array - \( - \[0\] => IMSSP - \[SQLSTATE\] => IMSSP - \[1\] => -16 - \[code\] => -16 - \[2\] => An invalid PHP type for parameter 2 was specified\. - \[message\] => An invalid PHP type for parameter 2 was specified\. - \) - -\) +(Warning|Notice)\: Use of undefined constant SQLSRV_ENC_UNKNOWN - assumed \'SQLSRV_ENC_UNKNOWN\' (\(this will throw an Error in a future version of PHP\) )?in .+(\/|\\)sqlsrv_input_param_unknown_encoding\.php on line 32 diff --git a/test/functional/sqlsrv/sqlsrv_num_fields.phpt b/test/functional/sqlsrv/sqlsrv_num_fields.phpt index cd489821..ea37a1bb 100644 --- a/test/functional/sqlsrv/sqlsrv_num_fields.phpt +++ b/test/functional/sqlsrv/sqlsrv_num_fields.phpt @@ -1,7 +1,7 @@ --TEST-- sqlsrv_num_fields and output params without sqlsrv_next_result. --SKIPIF-- - + --FILE-- --FILE-- getMessage(); - } - echo "\nDone\n"; - endTest("sqlsrv_statement_exec_param_floats"); +try { + execData(true); + execData(false); +} catch (Exception $e) { + echo $e->getMessage(); } - -Repro(); +echo "\nDone\n"; ?> --EXPECT-- @@ -103,4 +99,3 @@ Repro(); Test begins... Done -Test "sqlsrv_statement_exec_param_floats" completed successfully. diff --git a/test/functional/sqlsrv/sqlsrv_param_input_variants.phpt b/test/functional/sqlsrv/sqlsrv_param_input_variants.phpt index 6c065f52..ee5dbcde 100644 --- a/test/functional/sqlsrv/sqlsrv_param_input_variants.phpt +++ b/test/functional/sqlsrv/sqlsrv_param_input_variants.phpt @@ -13,27 +13,56 @@ hierarchyid geometry datetimeoffset User-defined types +--SKIPIF-- + --FILE-- c1_int, $row[$fld], $fetched, $fld++); - DoValuesMatched($obj->c2_tinyint, $row[$fld], $fetched, $fld++); - DoValuesMatched($obj->c3_smallint, $row[$fld], $fetched, $fld++); - DoValuesMatched($obj->c4_bigint, $row[$fld], $fetched, $fld++); - DoValuesMatched($obj->c5_bit, $row[$fld], $fetched, $fld++); - DoValuesMatched($obj->c6_float, $row[$fld], $fetched, $fld++); - DoValuesMatched($obj->c7_real, $row[$fld], $fetched, $fld++); - DoValuesMatched($obj->c8_decimal, $row[$fld], $fetched, $fld++); - DoValuesMatched($obj->c9_numeric, $row[$fld], $fetched, $fld++); - DoValuesMatched($obj->c10_money, $row[$fld], $fetched, $fld++); - DoValuesMatched($obj->c11_smallmoney, $row[$fld], $fetched, $fld++); - DoValuesMatched($obj->c12_char, $row[$fld], $fetched, $fld++); - DoValuesMatched($obj->c13_varchar, $row[$fld], $fetched, $fld++); - DoValuesMatched($obj->c14_uniqueidentifier, $row[$fld], $fetched, $fld++); - DoValuesMatched($obj->c15_datetime, $row[$fld], $fetched, $fld++); - DoValuesMatched($obj->c16_smalldatetime, $row[$fld], $fetched, $fld++); + doValuesMatched($obj->c1_int, $row[$fld], $fetched, $fld++); + doValuesMatched($obj->c2_tinyint, $row[$fld], $fetched, $fld++); + doValuesMatched($obj->c3_smallint, $row[$fld], $fetched, $fld++); + doValuesMatched($obj->c4_bigint, $row[$fld], $fetched, $fld++); + doValuesMatched($obj->c5_bit, $row[$fld], $fetched, $fld++); + doValuesMatched($obj->c6_float, $row[$fld], $fetched, $fld++); + doValuesMatched($obj->c7_real, $row[$fld], $fetched, $fld++); + doValuesMatched($obj->c8_decimal, $row[$fld], $fetched, $fld++); + doValuesMatched($obj->c9_numeric, $row[$fld], $fetched, $fld++); + doValuesMatched($obj->c10_money, $row[$fld], $fetched, $fld++); + doValuesMatched($obj->c11_smallmoney, $row[$fld], $fetched, $fld++); + doValuesMatched($obj->c12_char, $row[$fld], $fetched, $fld++); + doValuesMatched($obj->c13_varchar, $row[$fld], $fetched, $fld++); + doValuesMatched($obj->c14_uniqueidentifier, $row[$fld], $fetched, $fld++); + doValuesMatched($obj->c15_datetime, $row[$fld], $fetched, $fld++); + doValuesMatched($obj->c16_smalldatetime, $row[$fld], $fetched, $fld++); } // returns the number of rows fetched return $fetched; } -function DoValuesMatched($value1, $value2, $row, $col) +function doValuesMatched($value1, $value2, $row, $col) { $matched = false; if (is_null($value1) && is_null($value2)) { @@ -106,7 +135,7 @@ function DoValuesMatched($value1, $value2, $row, $col) } } -function GetInputData($index) +function getInputData($index) { switch ($index) { case 1: @@ -122,34 +151,29 @@ function GetInputData($index) } } -function RunTest() -{ - startTest("sqlsrv_param_input_variants"); - try { - setup(); - $conn = connect(); +try { + setup(); + $conn = AE\connect(); - // Create a temp table that will be automatically dropped once the connection is closed - $tableName = GetTempTableName(); - CreateVariantTable($conn, $tableName); + // Create a temp table that will be automatically dropped once the connection is closed + $tableName = 'param_input_variants'; + createVariantTable($conn, $tableName); - // Insert data - $numRows = 4; - for ($i = 1; $i <= $numRows; $i++) { - InsertData($conn, $tableName, $i); - } - - FetchData($conn, $tableName, $numRows); - - sqlsrv_close($conn); - } catch (Exception $e) { - echo $e->getMessage(); + // Insert data + $numRows = 4; + for ($i = 1; $i <= $numRows; $i++) { + insertData($conn, $tableName, $i); } - echo "\nDone\n"; - endTest("sqlsrv_param_input_variants"); -} -RunTest(); + fetchData($conn, $tableName, $numRows); + + dropTable($conn, $tableName); + + sqlsrv_close($conn); +} catch (Exception $e) { + echo $e->getMessage(); +} +echo "\nDone\n"; ?> --EXPECT-- @@ -160,4 +184,3 @@ Comparing data in row 4 Number of rows fetched: 4 Done -Test "sqlsrv_param_input_variants" completed successfully. diff --git a/test/functional/sqlsrv/sqlsrv_param_ints_with_deletes.phpt b/test/functional/sqlsrv/sqlsrv_param_ints_with_deletes.phpt index 56a5b971..fc689c55 100644 --- a/test/functional/sqlsrv/sqlsrv_param_ints_with_deletes.phpt +++ b/test/functional/sqlsrv/sqlsrv_param_ints_with_deletes.phpt @@ -1,25 +1,28 @@ --TEST-- Test insertion with floats +--SKIPIF-- + --FILE-- getMessage(); - } - echo "\nDone\n"; - endTest("sqlsrv_statement_exec_param_ints"); +echo "\nTest begins...\n"; +try { + execData(true); + execData(false); +} catch (Exception $e) { + echo $e->getMessage(); } - -Repro(); +echo "\nDone\n"; +endTest("sqlsrv_statement_exec_param_ints"); ?> --EXPECT-- diff --git a/test/functional/sqlsrv/sqlsrv_param_output_variants.phpt b/test/functional/sqlsrv/sqlsrv_param_output_variants.phpt index 2ed475a6..7e61f12e 100644 --- a/test/functional/sqlsrv/sqlsrv_param_output_variants.phpt +++ b/test/functional/sqlsrv/sqlsrv_param_output_variants.phpt @@ -1,15 +1,20 @@ --TEST-- Test parametrized insert and sql_variant as an output parameter. --DESCRIPTION-- -sql_variant is not supported for output parameters, this test checks the error handling in this case +Normally, sql_variant is not supported for output parameters, this test checks the error handling in this case. However, when Always Encrypted is enabled, we are able to bind output parameters with prepared +statements. +--SKIPIF-- + --FILE--  0) { - for ($i = 0; $i < $count; $i++) { - print($errors[$i]['message']."\n"); - } + if (AE\isColEncrypted()) { + fatalError("With AE this should not have failed!"); + } + + // Expect to fail only when AE is disabled + $expected = "Operand type clash: varchar(max) is incompatible with sql_variant"; + if (strpos($error['message'], $expected) === false) { + echo $error['message'] . PHP_EOL; + fatalError("Expected error: $expected\n"); } } -function RunTest() -{ - startTest("sqlsrv_param_output_variants"); - try { - setup(); +setup(); - // connect - $conn = connect(); +// connect +$conn = AE\connect(); - // Create a temp table that will be automatically dropped once the connection is closed - $tableName = GetTempTableName(); - CreateVariantTable($conn, $tableName); - echo "\n"; +// Create a test table +$tableName = 'test_output_variants'; +createVariantTable($conn, $tableName); - TestOutputParam($conn, $tableName); - TestInputAndOutputParam($conn, $tableName); +testOutputParam($conn, $tableName); +testInputAndOutputParam($conn, $tableName); - sqlsrv_close($conn); - } catch (Exception $e) { - echo $e->getMessage(); - } - echo "\nDone\n"; - endTest("sqlsrv_param_output_variants"); -} - -RunTest(); +dropTable($conn, $tableName); +sqlsrv_close($conn); +print "Test completed successfully\n"; ?> ---EXPECTREGEX-- -  -\[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Operand type clash: varchar\(max\) is incompatible with sql_variant - -\[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Operand type clash: varchar\(max\) is incompatible with sql_variant - -Done -Test \"sqlsrv_param_output_variants\" completed successfully\. +--EXPECT-- +Test completed successfully \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_param_query_array_inputs.phpt b/test/functional/sqlsrv/sqlsrv_param_query_array_inputs.phpt index 4c069fb4..f5b2f8c9 100644 --- a/test/functional/sqlsrv/sqlsrv_param_query_array_inputs.phpt +++ b/test/functional/sqlsrv/sqlsrv_param_query_array_inputs.phpt @@ -4,13 +4,15 @@ Test insert various numeric data types and fetch them back as strings getMessage(); - } - echo "\nDone\n"; - endTest("sqlsrv_param_query_array_inputs"); + sqlsrv_close($conn); +} catch (Exception $e) { + echo $e->getMessage(); } - -Repro(); +echo "\nDone\n"; ?> --EXPECT-- @@ -142,4 +153,3 @@ Insert floats without direction 41.0, 42.0 Done -Test "sqlsrv_param_query_array_inputs" completed successfully. diff --git a/test/functional/sqlsrv/sqlsrv_param_query_data_types.phpt b/test/functional/sqlsrv/sqlsrv_param_query_data_types.phpt index 31552c14..6bb0dd27 100644 --- a/test/functional/sqlsrv/sqlsrv_param_query_data_types.phpt +++ b/test/functional/sqlsrv/sqlsrv_param_query_data_types.phpt @@ -1,58 +1,64 @@ --TEST-- Test insert various numeric data types and fetch them back as strings +--SKIPIF-- + --FILE-- getMessage(); - } - echo "\nDone\n"; - endTest("sqlsrv_param_query_data_types"); + sqlsrv_close($conn); +} catch (Exception $e) { + echo $e->getMessage(); } - -Repro(); +echo "\nDone\n"; ?> --EXPECT-- @@ -60,4 +66,3 @@ Repro(); Test begins... Done -Test "sqlsrv_param_query_data_types" completed successfully. diff --git a/test/functional/sqlsrv/sqlsrv_param_query_errors.phpt b/test/functional/sqlsrv/sqlsrv_param_query_errors.phpt index 02cec7ea..4ccec206 100644 --- a/test/functional/sqlsrv/sqlsrv_param_query_errors.phpt +++ b/test/functional/sqlsrv/sqlsrv_param_query_errors.phpt @@ -1,17 +1,35 @@ --TEST-- Insert with query params but with wrong parameters or types +--SKIPIF-- + --FILE-- getMessage(); - } - echo "\nDone\n"; - endTest("sqlsrv_param_query_errors"); + sqlsrv_close($conn); +} catch (Exception $e) { + echo $e->getMessage(); } - -RunTest(); - +echo "\nDone\n"; + ?> --EXPECT--  @@ -112,4 +116,3 @@ An invalid PHP type for parameter 2 was specified. An invalid PHP type for parameter 2 was specified. Done -Test "sqlsrv_param_query_errors" completed successfully. diff --git a/test/functional/sqlsrv/sqlsrv_param_query_invalid_inputs.phpt b/test/functional/sqlsrv/sqlsrv_param_query_invalid_inputs.phpt index a9460b75..d62e8715 100644 --- a/test/functional/sqlsrv/sqlsrv_param_query_invalid_inputs.phpt +++ b/test/functional/sqlsrv/sqlsrv_param_query_invalid_inputs.phpt @@ -1,82 +1,90 @@ --TEST-- Insert with query params but with various invalid inputs or boundaries +--SKIPIF-- + --FILE-- getMessage(); + $tableName = 'minMaxScale'; + $columns = array(new AE\ColumnMeta('int', 'c1_int'), + new AE\ColumnMeta('decimal(28,4)', 'c2_decimal'), + new AE\ColumnMeta('numeric(32,4)', 'c3_numeric')); + $stmt = AE\createTable($conn, $tableName, $columns); + if (!$stmt) { + fatalError("Failed to create table $tableName\n"); } - echo "\nDone\n"; - endTest("sqlsrv_param_query_invalid_inputs"); + + $stmt = sqlsrv_query($conn, "INSERT INTO $tableName (c1_int, c2_decimal) VALUES (?, ?)", array(getFirstInputParam(), array(0.0, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_DECIMAL(28, 34)))); + printErrors(); + + $stmt = sqlsrv_query($conn, "INSERT INTO $tableName (c1_int, c3_numeric) VALUES (?, ?)", array(getFirstInputParam(), array(0.0, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_NUMERIC(32, -1)))); + printErrors(); + dropTable($conn, $tableName); } -RunTest(); +function minMaxSize($conn) +{ + $tableName = 'minMaxSize'; + $columns = array(new AE\ColumnMeta('int', 'c1_int'), + new AE\ColumnMeta('varchar(max)', 'c2_varchar_max')); + $stmt = AE\createTable($conn, $tableName, $columns); + if (!$stmt) { + fatalError("Failed to create table $tableName\n"); + } + + $stmt = sqlsrv_query($conn, "INSERT INTO $tableName (c1_int, c2_varchar_max) VALUES (?, ?)", array(getFirstInputParam(), array("Test Data", SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARCHAR(0)))); + printErrors(); + + $stmt = sqlsrv_query($conn, "INSERT INTO $tableName (c1_int, c2_varchar_max) VALUES (?, ?)", array(getFirstInputParam(), array("Test Data", SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARCHAR(9000)))); + printErrors(); + dropTable($conn, $tableName); +} + +function minMaxPrecision($conn) +{ + $tableName = 'minMaxPrecision'; + $columns = array(new AE\ColumnMeta('int', 'c1_int'), + new AE\ColumnMeta('decimal(28,4)', 'c2_decimal'), + new AE\ColumnMeta('numeric(32,4)', 'c3_numeric')); + $stmt = AE\createTable($conn, $tableName, $columns); + if (!$stmt) { + fatalError("Failed to create table $tableName\n"); + } + + $stmt = sqlsrv_query($conn, "INSERT INTO $tableName (c1_int, c3_numeric) VALUES (?, ?)", array(getFirstInputParam(), array(0.0, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_NUMERIC(40, 0)))); + printErrors(); + + $stmt = sqlsrv_query($conn, "INSERT INTO $tableName (c1_int, c2_decimal) VALUES (?, ?)", array(getFirstInputParam(), array(0.0, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_DECIMAL(-1, 0)))); + printErrors(); + dropTable($conn, $tableName); +} + +echo "\nTest begins...\n"; +try { + set_time_limit(0); + sqlsrv_configure('WarningsReturnAsErrors', 1); + + // connect + $conn = AE\connect(); + + minMaxScale($conn); + minMaxSize($conn); + minMaxPrecision($conn); + + sqlsrv_close($conn); +} catch (Exception $e) { + echo $e->getMessage(); +} +echo "\nDone\n"; ?> --EXPECT-- @@ -90,4 +98,3 @@ An invalid size or precision for parameter 2 was specified. An invalid size or precision for parameter 2 was specified. Done -Test "sqlsrv_param_query_invalid_inputs" completed successfully. diff --git a/test/functional/sqlsrv/sqlsrv_prepare.phpt b/test/functional/sqlsrv/sqlsrv_prepare.phpt index 7f6f6f35..8f504303 100644 --- a/test/functional/sqlsrv/sqlsrv_prepare.phpt +++ b/test/functional/sqlsrv/sqlsrv_prepare.phpt @@ -1,22 +1,22 @@ --TEST-- binding parameters, including output parameters, using the simplified syntax. --SKIPIF-- - + --FILE-- ---EXPECTF-- +--EXPECT-- 1 12.0 testtestte -This is some text meant to test binding parameters to streams + 2 13.0 testtestte -This is some more text meant to test binding parameters to streams + 3 4 diff --git a/test/functional/sqlsrv/sqlsrv_query.phpt b/test/functional/sqlsrv/sqlsrv_query.phpt index 55f26fe4..e3fde92a 100644 --- a/test/functional/sqlsrv/sqlsrv_query.phpt +++ b/test/functional/sqlsrv/sqlsrv_query.phpt @@ -1,7 +1,7 @@ --TEST-- -sqlsrv_query test. Performs same tasks as 0006.phpt, using sqlsrv_query. +sqlsrv_query test. Performs same tasks as 0006.phpt, using sqlsrv_query. --SKIPIF-- - + --FILE-- "; + echo "$id\n"; $double = sqlsrv_get_field($stmt, 1, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR)); - echo "$double
"; + echo "$double\n"; $name = sqlsrv_get_field($stmt, 2, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR)); - echo "$name
"; + echo "$name\n"; $stream = sqlsrv_get_field($stmt, 3, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY)); - while (!feof($stream)) { - $str = fread($stream, 4000); - echo $str; + if (!$stream) { + if (AE\isColEncrypted()) { + verifyError(sqlsrv_errors()[0], 'IMSSP', 'Connection with Column Encryption enabled does not support fetching stream. Please fetch the data as a string.'); + } else { + fatalError('Fetching data stream failed!'); + } + } else { + while (!feof($stream)) { + $str = fread($stream, 4000); + if ($str !== "This is some text meant to test binding parameters to streams") { + fatalError("Incorrect data: \'$str\'!\n"); + } + } } - echo "
"; + echo "\n"; } sqlsrv_query($conn, "DROP TABLE test_params"); + dropTable($conn, $tableName); sqlsrv_close($conn); ?> ---EXPECTF-- -1
12.0
testtestte
This is some text meant to test binding parameters to streams
%A +--EXPECT-- +1 +12.0 +testtestte + diff --git a/test/functional/sqlsrv/sqlsrv_rowsAffected.phpt b/test/functional/sqlsrv/sqlsrv_rowsAffected.phpt index 0302f0b0..ed3fc226 100644 --- a/test/functional/sqlsrv/sqlsrv_rowsAffected.phpt +++ b/test/functional/sqlsrv/sqlsrv_rowsAffected.phpt @@ -1,7 +1,7 @@ --TEST-- sqlsrv_stmt_rows_affected. --SKIPIF-- - + --FILE-- \n"; - sqlsrv_query($conn, "DROP TABLE test_params"); + dropTable($conn, $tableName); sqlsrv_free_stmt($stmt); sqlsrv_close($conn); diff --git a/test/functional/sqlsrv/sqlsrv_send_stream_data.phpt b/test/functional/sqlsrv/sqlsrv_send_stream_data.phpt index 25fd8b45..aa9ff82d 100644 --- a/test/functional/sqlsrv/sqlsrv_send_stream_data.phpt +++ b/test/functional/sqlsrv/sqlsrv_send_stream_data.phpt @@ -1,7 +1,7 @@ --TEST-- binding streams using full syntax. --SKIPIF-- - + --FILE-- ---EXPECTF-- -Array -( - [0] => Array - ( - [0] => 22018 - [SQLSTATE] => 22018 - [1] => 0 - [code] => 0 - [2] => %SInvalid character value for cast specification - [message] => %SInvalid character value for cast specification - ) - -) +--EXPECT-- sqlsrv_query(2) failed. -Array -( - [0] => Array - ( - [0] => 42000 - [SQLSTATE] => 42000 - [1] => 257 - [code] => 257 - [2] => %SImplicit conversion from data type varchar(max) to varbinary(max) is not allowed. Use the CONVERT function to run this query. - [message] => %SImplicit conversion from data type varchar(max) to varbinary(max) is not allowed. Use the CONVERT function to run this query. - ) - -) sqlsrv_query(3) failed. 1 12.0 testtestte -This is some text meant to test binding parameters to streams -array(1) { - [0]=> - array(6) { - [0]=> - string(5) "IMSSP" - ["SQLSTATE"]=> - string(5) "IMSSP" - [1]=> - int(-9) - ["code"]=> - int(-9) - [2]=> - string(59) "Parameter array 2 must have at least one value or variable." - ["message"]=> - string(59) "Parameter array 2 must have at least one value or variable." - } -} + +Done \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_simple_update_variants.phpt b/test/functional/sqlsrv/sqlsrv_simple_update_variants.phpt index 8ead71fa..70fa7955 100644 --- a/test/functional/sqlsrv/sqlsrv_simple_update_variants.phpt +++ b/test/functional/sqlsrv/sqlsrv_simple_update_variants.phpt @@ -2,6 +2,8 @@ Test simple insert and update sql_variants using parameters of some different data types --DESCRIPTION-- ORDER BY should work with sql_variants +--SKIPIF-- + --FILE-- getMessage(); - } - echo "\nDone\n"; - endTest("sqlsrv_simple_update_variants"); + sqlsrv_close($conn); +} catch (Exception $e) { + echo $e->getMessage(); } - -RunTest(); +echo "\nDone\n"; ?> --EXPECT-- @@ -175,4 +173,3 @@ ID: 4 Mexico, North America ID: 5 Australia, Australia ID: 6 Brazil, South America Done -Test "sqlsrv_simple_update_variants" completed successfully. diff --git a/test/functional/sqlsrv/sqlsrv_stored_proc_varchar.phpt b/test/functional/sqlsrv/sqlsrv_stored_proc_varchar.phpt index b702981c..20176dbd 100644 --- a/test/functional/sqlsrv/sqlsrv_stored_proc_varchar.phpt +++ b/test/functional/sqlsrv/sqlsrv_stored_proc_varchar.phpt @@ -1,21 +1,21 @@ --TEST-- Test stored procedure that returns a varchar +--SKIPIF-- + --FILE-- getMessage(); - } - echo "\nDone\n"; - endTest("sqlsrv_stored_proc_varchar"); +echo "\nTest begins...\n"; +try { + storedProcVarchar(); +} catch (Exception $e) { + echo $e->getMessage(); } - -Repro(); +echo "\nDone\n"; ?> --EXPECT-- @@ -71,4 +66,3 @@ Microsoft SQL Server Driver for PHP Microsoft SQL Server Driver for PHP Done -Test "sqlsrv_stored_proc_varchar" completed successfully. diff --git a/test/functional/sqlsrv/sqlsrv_streams_empty_char.phpt b/test/functional/sqlsrv/sqlsrv_streams_empty_char.phpt index 3ae7f1da..bfd726b6 100644 --- a/test/functional/sqlsrv/sqlsrv_streams_empty_char.phpt +++ b/test/functional/sqlsrv/sqlsrv_streams_empty_char.phpt @@ -1,54 +1,73 @@ --TEST-- Populate different test tables with character fields using empty stream data as inputs +--SKIPIF-- + --FILE--  0)); + if ($stmt) { + $res = sqlsrv_execute($stmt); + } + } else { + $stmt = sqlsrv_query($conn, $query, array($value, &$fname), array('SendStreamParamsAtExec' => 0)); + } + if ($stmt === false || !$res) { + fclose($fname); + fatalError("Failed in sendQueryStream for $value\n"); + } + + sqlsrv_send_stream_data($stmt); + sqlsrv_free_stmt($stmt); + fclose($fname); +} + +function char2Stream($conn, $fileName) +{ + $tableName = 'streams_empty_char'; // create a test table - $stmt = sqlsrv_query($conn, "CREATE TABLE $tableName ([c1_int] int, [c2_char] char(512), [c3_varchar] varchar(512), [c4_varchar_max] varchar(max), [c5_text] text)"); + $columns = array(new AE\ColumnMeta('int', 'c1_int'), + new AE\ColumnMeta('char(512)', 'c2_char'), + new AE\ColumnMeta('varchar(512)', 'c3_varchar'), + new AE\ColumnMeta('varchar(max)', 'c4_varchar_max'), + new AE\ColumnMeta('text', 'c5_text')); + $stmt = AE\createTable($conn, $tableName, $columns); + if (!$stmt) { + fatalError("Failed to create table $tableName\n"); + } sqlsrv_free_stmt($stmt); // insert data - $fname = fopen($fileName, "r"); - $stmt = sqlsrv_query($conn, "INSERT INTO $tableName (c1_int, c2_char) VALUES (?, ?)", array(1, &$fname), array('SendStreamParamsAtExec' => 0)); - sqlsrv_send_stream_data($stmt); - sqlsrv_free_stmt($stmt); - fclose($fname); + sendQueryStream($conn, "INSERT INTO $tableName (c1_int, c2_char) VALUES (?, ?)", 1, $fileName); + fetchData($conn, $tableName, 1); - FetchData($conn, $tableName, 1); + sendQueryStream($conn, "INSERT INTO $tableName (c1_int, c3_varchar) VALUES (?, ?)", 2, $fileName); + fetchData($conn, $tableName, 2); - $fname = fopen($fileName, "r"); - $stmt = sqlsrv_query($conn, "INSERT INTO $tableName (c1_int, c3_varchar) VALUES (?, ?)", array(2, &$fname), array('SendStreamParamsAtExec' => 0)); - sqlsrv_send_stream_data($stmt); - sqlsrv_free_stmt($stmt); - fclose($fname); + sendQueryStream($conn, "INSERT INTO $tableName (c1_int, c4_varchar_max) VALUES (?, ?)", 3, $fileName); + fetchData($conn, $tableName, 3); - FetchData($conn, $tableName, 2); - - $fname = fopen($fileName, "r"); - $stmt = sqlsrv_query($conn, "INSERT INTO $tableName (c1_int, c4_varchar_max) VALUES (?, ?)", array(3, &$fname), array('SendStreamParamsAtExec' => 0)); - sqlsrv_send_stream_data($stmt); - sqlsrv_free_stmt($stmt); - fclose($fname); - - FetchData($conn, $tableName, 3); - - $fname = fopen($fileName, "r"); - $stmt = sqlsrv_query($conn, "INSERT INTO $tableName (c1_int, c5_text) VALUES (?, ?)", array(4, &$fname), array('SendStreamParamsAtExec' => 0)); - sqlsrv_send_stream_data($stmt); - sqlsrv_free_stmt($stmt); - fclose($fname); - - FetchData($conn, $tableName, 4); + sendQueryStream($conn, "INSERT INTO $tableName (c1_int, c5_text) VALUES (?, ?)", 4, $fileName); + fetchData($conn, $tableName, 4); + + dropTable($conn, $tableName); } -function FetchData($conn, $tableName, $fld) +function fetchData($conn, $tableName, $fld) { - $stmt = sqlsrv_prepare($conn, "SELECT * FROM $tableName WHERE c1_int = $fld"); + if (AE\isColEncrypted()) { + // bind param when AE is enabled + $stmt = sqlsrv_prepare($conn, "SELECT * FROM $tableName WHERE c1_int = ?", array($fld)); + } else { + $stmt = sqlsrv_prepare($conn, "SELECT * FROM $tableName WHERE c1_int = $fld"); + } sqlsrv_execute($stmt); $result = sqlsrv_fetch($stmt); $stream = sqlsrv_get_field($stmt, $fld, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY)); @@ -58,44 +77,32 @@ function FetchData($conn, $tableName, $fld) $result = sqlsrv_fetch($stmt); $value = sqlsrv_get_field($stmt, $fld, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY)); var_dump($value); + + sqlsrv_free_stmt($stmt); } -//-------------------------------------------------------------------- -// RunTest -// -//-------------------------------------------------------------------- -function RunTest() -{ - startTest("sqlsrv_streams_empty_char"); - echo "\nTest begins...\n"; - try { - set_time_limit(0); - sqlsrv_configure('WarningsReturnAsErrors', 1); +echo "\nTest begins...\n"; +try { + set_time_limit(0); + sqlsrv_configure('WarningsReturnAsErrors', 1); - // connect - $conn = connect(); - if (!$conn) { - fatalError("Could not connect.\n"); - } + // connect + $conn = AE\connect(); - // create an empty file - $fileName = "sqlsrv_streams_empty_char.dat"; - $fp = fopen($fileName, "wb"); - fclose($fp); + // create an empty file + $fileName = "sqlsrv_streams_empty_char.dat"; + $fp = fopen($fileName, "wb"); + fclose($fp); - EmptyStream_Char2Stream($conn, $fileName); + char2Stream($conn, $fileName); - // delete the file - unlink($fileName); - sqlsrv_close($conn); - } catch (Exception $e) { - echo $e->getMessage(); - } - echo "\nDone\n"; - endTest("sqlsrv_streams_empty_char"); + // delete the file + unlink($fileName); + sqlsrv_close($conn); +} catch (Exception $e) { + echo $e->getMessage(); } - -RunTest(); +echo "\nDone\n"; ?> --EXPECT-- @@ -111,4 +118,3 @@ bool(false) bool(false) Done -Test "sqlsrv_streams_empty_char" completed successfully. diff --git a/test/functional/sqlsrv/sqlsrv_streams_null_binary.phpt b/test/functional/sqlsrv/sqlsrv_streams_null_binary.phpt index 5e4662ce..85be8174 100644 --- a/test/functional/sqlsrv/sqlsrv_streams_null_binary.phpt +++ b/test/functional/sqlsrv/sqlsrv_streams_null_binary.phpt @@ -1,33 +1,57 @@ --TEST-- Populate different binary fields using null stream data as inputs. +--SKIPIF-- + --FILE-- getMessage(); + // create a test table + $tableName = 'null_binary_stream'; + $columns = array(new AE\ColumnMeta('int', 'c1_int'), + new AE\ColumnMeta('varbinary(512)', 'c2_varbinary'), + new AE\ColumnMeta('varbinary(max)', 'c3_varbinary_max'), + new AE\ColumnMeta('image', 'c4_image')); + $stmt = AE\createTable($conn, $tableName, $columns); + if (!$stmt) { + fatalError("Failed to create table.\n"); } - echo "\nDone\n"; - endTest("sqlsrv_streams_null_binary"); -} -RunTest(); + nullBin2String($conn, $tableName); + nullPrepBin2String($conn, $tableName); + + dropTable($conn, $tableName); + + sqlsrv_close($conn); +} catch (Exception $e) { + echo $e->getMessage(); +} +echo "\nDone\n"; ?> --EXPECT-- @@ -84,4 +102,3 @@ NULL NULL Done -Test "sqlsrv_streams_null_binary" completed successfully. diff --git a/test/functional/sqlsrv/sqlsrv_streams_null_nchar.phpt b/test/functional/sqlsrv/sqlsrv_streams_null_nchar.phpt index 81556c32..9958b3a9 100644 --- a/test/functional/sqlsrv/sqlsrv_streams_null_nchar.phpt +++ b/test/functional/sqlsrv/sqlsrv_streams_null_nchar.phpt @@ -1,25 +1,50 @@ --TEST-- Populate different unicode character fields using null stream data as inputs +--SKIPIF-- + --FILE-- getMessage(); - } - echo "\nDone\n"; - endTest("sqlsrv_streams_null_nchar"); + sqlsrv_close($conn); +} catch (Exception $e) { + echo $e->getMessage(); } - -RunTest(); +echo "\nDone\n"; ?> --EXPECT-- @@ -71,4 +82,3 @@ NULL NULL Done -Test "sqlsrv_streams_null_nchar" completed successfully. diff --git a/test/functional/sqlsrv/srv_007_login_timeout.phpt b/test/functional/sqlsrv/srv_007_login_timeout.phpt index 5ac33c9f..c8fa5cf1 100644 --- a/test/functional/sqlsrv/srv_007_login_timeout.phpt +++ b/test/functional/sqlsrv/srv_007_login_timeout.phpt @@ -9,11 +9,11 @@ Intentionally provide an invalid server name and set LoginTimeout. Verify the ti $serverName = "WRONG_SERVER_NAME"; -$t0 = round(microtime(true)); +$t0 = microtime(true); -$conn = sqlsrv_connect( $serverName , array("LoginTimeout" => 8)); +$conn = sqlsrv_connect($serverName , array("LoginTimeout" => 8)); -$t1 = round(microtime(true)); +$t1 = microtime(true); echo "Connection attempt time: " . ($t1 - $t0) . " [sec]\n"; @@ -21,5 +21,5 @@ print "Done"; ?> --EXPECTREGEX-- -Connection attempt time: [7-9] \[sec\] +Connection attempt time: [7-9]\.[0-9]+ \[sec\] Done diff --git a/test/functional/sqlsrv/srv_036_transaction_commit.phpt b/test/functional/sqlsrv/srv_036_transaction_commit.phpt index c418fd88..dafebe0b 100644 --- a/test/functional/sqlsrv/srv_036_transaction_commit.phpt +++ b/test/functional/sqlsrv/srv_036_transaction_commit.phpt @@ -1,39 +1,72 @@ --TEST-- Transaction operations: commit successful transactions --SKIPIF-- + --FILE-- = 0))"; -$stmt = sqlsrv_query($conn, $sql); - +// Do not encrypt the integer columns because of the operations required later +$columns = array(new AE\ColumnMeta('VARCHAR(10)', 'GroupId', 'primary key'), + new AE\ColumnMeta('INT', 'Accepted', null, null, true), + new AE\ColumnMeta('INT', 'Tentative', 'NOT NULL CHECK (Tentative >= 0)', null, true)); +$stmt = AE\createTable($conn, $tableName, $columns); +if (!$stmt) { + fatalError("Failed to create table $tableName\n"); +} +sqlsrv_free_stmt($stmt); // Set initial data -$sql = "INSERT INTO $tableName VALUES ('ID1','12','5'),('ID102','20','1')"; -$stmt = sqlsrv_query($conn, $sql) ?: die(print_r(sqlsrv_errors(), true)); +if (AE\isColEncrypted()) { + $stmt = sqlsrv_query($conn, + "INSERT INTO $tableName VALUES (?,?,?),(?,?,?)", + array(array('ID1', null, null, SQLSRV_SQLTYPE_VARCHAR(10)), + array(12, null, null, SQLSRV_SQLTYPE_INT), + array(5, null, null, SQLSRV_SQLTYPE_INT), + array('ID102', null, null, SQLSRV_SQLTYPE_VARCHAR(10)), + array(20, null, null, SQLSRV_SQLTYPE_INT), + array(1, null, null, SQLSRV_SQLTYPE_INT))); +} else { + $sql = "INSERT INTO $tableName VALUES ('ID1','12','5'),('ID102','20','1')"; + $stmt = sqlsrv_query($conn, $sql); +} +if (!$stmt) { + fatalError("Failed to insert data\n"); +} //Initiate transaction sqlsrv_begin_transaction($conn) ?: die(print_r(sqlsrv_errors(), true)); @@ -45,11 +78,11 @@ $params = array($count, $groupId); // Update Accepted column $sql = "UPDATE $tableName SET Accepted = (Accepted + ?) WHERE GroupId = ?"; -$stmt1 = sqlsrv_query($conn, $sql, $params) ?: die(print_r(sqlsrv_errors(), true)); +$stmt1 = runQuery($conn, $sql, $params); // Update Tentative column $sql = "UPDATE $tableName SET Tentative = (Tentative - ?) WHERE GroupId = ?"; -$stmt2 = sqlsrv_query($conn, $sql, $params); +$stmt2 = runQuery($conn, $sql, $params); // Commit the transactions if ($stmt1 && $stmt2) { @@ -60,7 +93,9 @@ if ($stmt1 && $stmt2) { echo "\nTransactions were rolled back.\n"; } -PrintContent($conn); +printContent($conn); + +dropTable($conn, $tableName); sqlsrv_free_stmt($stmt); sqlsrv_close($conn); diff --git a/test/functional/sqlsrv/srv_231_string_truncation_text.phpt b/test/functional/sqlsrv/srv_231_string_truncation_text.phpt index 2e2107c2..2e62887d 100644 --- a/test/functional/sqlsrv/srv_231_string_truncation_text.phpt +++ b/test/functional/sqlsrv/srv_231_string_truncation_text.phpt @@ -13,15 +13,11 @@ require_once("MsCommon.inc"); // connect $conn = AE\connect(); -if (!$conn) { - fatalError("Connection could not be established.\n"); -} - -$tableName = 'testLOBTypes_GH231'; +$tableName = 'testLOBTypes_GH231_lob'; $columnNames = array("c1", "c2"); for ($k = 1; $k <= 3; $k++) { - $sqlType = sqlType($k); + $sqlType = SQLType($k); $columns = array(new AE\ColumnMeta('int', $columnNames[0]), new AE\ColumnMeta($sqlType, $columnNames[1])); AE\createTable($conn, $tableName, $columns); @@ -51,6 +47,7 @@ function execProc($conn, $tableName, $columnNames, $k, $data, $sqlType) $spCode = "SET @p2 = ( SELECT c2 FROM $tableName WHERE c1 = @p1 )"; $procName = "testBindOutSp"; + dropProc($conn, $procName); $stmt1 = sqlsrv_query($conn, "CREATE PROC [$procName] ($spArgs) AS BEGIN $spCode END"); sqlsrv_free_stmt($stmt1); @@ -95,7 +92,7 @@ function getData($k) return $data; } -function sqlType($k) +function SQLType($k) { switch ($k) { case 1: return ("text"); diff --git a/test/functional/sqlsrv/srv_231_string_truncation_varchar_max.phpt b/test/functional/sqlsrv/srv_231_string_truncation_varchar_max.phpt index 28b7035d..74adcd76 100644 --- a/test/functional/sqlsrv/srv_231_string_truncation_varchar_max.phpt +++ b/test/functional/sqlsrv/srv_231_string_truncation_varchar_max.phpt @@ -1,6 +1,7 @@ --TEST-- GitHub issue #231 - String truncation when binding varchar(max) --SKIPIF-- + --FILE-- + --FILE-- --EXPECT-- diff --git a/test/functional/sqlsrv/test_warning_errors3.phpt b/test/functional/sqlsrv/test_warning_errors3.phpt index c68c9cf6..9ee8dc37 100644 --- a/test/functional/sqlsrv/test_warning_errors3.phpt +++ b/test/functional/sqlsrv/test_warning_errors3.phpt @@ -1,32 +1,30 @@ --TEST-- error messages when trying to retrieve past the end of a result set and when no result set exists. --SKIPIF-- - + --FILE-- Array