diff --git a/.travis.yml b/.travis.yml index 73ce34f3..6d5141ed 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,58 +1,52 @@ -sudo: required - -os: linux -dist: trusty - -group: edge - -services: - - docker - -env: - global: - - REPORT_EXIT_STATUS=1 - - ACCEPT_EULA=Y - - PHPSQLDIR=/REPO/msphpsql-dev - - TEST_PHP_SQL_SERVER=sql - - SQLSRV_DBNAME=msphpsql_sqlsrv - - PDOSQLSRV_DBNAME=msphpsql_pdosqlsrv - - TEST_PHP_SQL_UID=sa - - TEST_PHP_SQL_PWD=Password123 - -before_install: - - docker pull microsoft/mssql-server-linux:2017-latest - -install: - - docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=Password123' -p 1433:1433 --name=$TEST_PHP_SQL_SERVER -d microsoft/mssql-server-linux:2017-latest - - docker build --build-arg PHPSQLDIR=$PHPSQLDIR -t msphpsql-dev -f Dockerfile-msphpsql . - -before_script: - - sleep 30 - -script: - - travis_retry docker run -e TRAVIS_JOB_ID -t -d -w $PHPSQLDIR --name=client --link $TEST_PHP_SQL_SERVER msphpsql-dev - - docker ps -a - - docker logs client - - travis_retry docker exec client python ./test/functional/setup/setup_dbs.py -dbname $SQLSRV_DBNAME - - travis_retry docker exec client python ./test/functional/setup/setup_dbs.py -dbname $PDOSQLSRV_DBNAME - - docker exec client cp ./source/shared/msodbcsql.h ./test/functional/setup/ - - travis_retry docker exec client python ./test/functional/setup/build_ksp.py - - docker exec client cp ./test/functional/setup/myKSP.so ./test/functional/sqlsrv/ - - docker exec client cp ./test/functional/setup/myKSP.so ./test/functional/pdo_sqlsrv/ - - travis_retry docker exec client python ./test/functional/setup/run_ksp.py -server $TEST_PHP_SQL_SERVER -dbname $SQLSRV_DBNAME -uid $TEST_PHP_SQL_UID -pwd $TEST_PHP_SQL_PWD - - travis_retry docker exec client python ./test/functional/setup/run_ksp.py -server $TEST_PHP_SQL_SERVER -dbname $PDOSQLSRV_DBNAME -uid $TEST_PHP_SQL_UID -pwd $TEST_PHP_SQL_PWD - - travis_retry docker exec client php ./source/pdo_sqlsrv/run-tests.php ./test/functional/pdo_sqlsrv/*.phpt - - travis_retry docker exec client php ./source/sqlsrv/run-tests.php ./test/functional/sqlsrv/*.phpt - - docker exec client bash -c 'for f in ./test/functional/sqlsrv/*.diff; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true' - - docker exec client bash -c 'for f in ./test/functional/sqlsrv/*.out; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true' - - docker exec client bash -c 'for f in ./test/functional/pdo_sqlsrv/*.diff; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true' - - docker exec client bash -c 'for f in ./test/functional/pdo_sqlsrv/*.out; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true' - - docker exec client python ./test/functional/setup/cleanup_dbs.py -dbname $SQLSRV_DBNAME - - docker exec client python ./test/functional/setup/cleanup_dbs.py -dbname $PDOSQLSRV_DBNAME - - docker exec client coveralls -e ./source/shared/ --gcov-options '\-lp' - - docker stop client - - docker ps -a - -notifications: - email: false - +sudo: required + +os: linux +dist: trusty + +group: edge + +services: + - docker + +env: + global: + - REPORT_EXIT_STATUS=1 + - ACCEPT_EULA=Y + - PHPSQLDIR=/REPO/msphpsql-dev + - TEST_PHP_SQL_SERVER=sql + - SQLSRV_DBNAME=msphpsql_sqlsrv + - PDOSQLSRV_DBNAME=msphpsql_pdosqlsrv + - TEST_PHP_SQL_UID=sa + - TEST_PHP_SQL_PWD=Password123 + +before_install: + - docker pull microsoft/mssql-server-linux:2017-latest + +install: + - docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=Password123' -p 1433:1433 --name=$TEST_PHP_SQL_SERVER -d microsoft/mssql-server-linux:2017-latest + - docker build --build-arg PHPSQLDIR=$PHPSQLDIR -t msphpsql-dev -f Dockerfile-msphpsql . + +before_script: + - sleep 30 + +script: + - travis_retry docker run -e TRAVIS_JOB_ID -t -d -w $PHPSQLDIR --name=client --link $TEST_PHP_SQL_SERVER msphpsql-dev + - docker ps -a + - docker logs client + - travis_retry docker exec client python ./test/functional/setup/setup_dbs.py -dbname $SQLSRV_DBNAME + - travis_retry docker exec client python ./test/functional/setup/setup_dbs.py -dbname $PDOSQLSRV_DBNAME + - travis_retry docker exec client php ./source/pdo_sqlsrv/run-tests.php ./test/functional/pdo_sqlsrv/*.phpt + - travis_retry docker exec client php ./source/sqlsrv/run-tests.php ./test/functional/sqlsrv/*.phpt + - docker exec client bash -c 'for f in ./test/functional/sqlsrv/*.diff; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true' + - docker exec client bash -c 'for f in ./test/functional/sqlsrv/*.out; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true' + - docker exec client bash -c 'for f in ./test/functional/pdo_sqlsrv/*.diff; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true' + - docker exec client bash -c 'for f in ./test/functional/pdo_sqlsrv/*.out; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true' + - docker exec client python ./test/functional/setup/cleanup_dbs.py -dbname $SQLSRV_DBNAME + - docker exec client python ./test/functional/setup/cleanup_dbs.py -dbname $PDOSQLSRV_DBNAME + - docker exec client coveralls -e ./source/shared/ --gcov-options '\-lp' + - docker stop client + - docker ps -a + +notifications: + email: false + diff --git a/CHANGELOG.md b/CHANGELOG.md index 839f0b80..aee62611 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,61 @@ 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 - 2017-02-14 +Updated PECL release packages. Here is the list of updates: + +### Added +- Added support for Always Encrypted with basic CRUD functionalities (see [here](https://github.com/Microsoft/msphpsql/wiki/Features#aebindparam)) + - Support for Windows Certificate Store (use connection keyword ColumnEncryption) + - Support for inserting into and modifying an encrypted column + - Support for fetching from an encrypted column +- Added support for PHP 7.2 +- Added support for MS ODBC Driver 17 +- Added support for Ubuntu 17 (requires MS ODBC Driver 17) +- Added support for Debian 9 (requires MS ODBC Driver 17) +- Added support for SUSE 12 +- Added Driver option to set the MS ODBC driver, Added "Driver" option, valid values are "ODBC Driver 17 for SQL Server", "ODBC Driver 13 for SQL Server", and "ODBC Driver 11 for SQL Server" + - The default driver is ODBC Driver 17 for SQL Server + +### Changed +- Implementation of PDO::lastInsertId($name) to return the last inserted sequence number if the sequence name is supplied to the function ([lastInsertId](https://github.com/Microsoft/msphpsql/wiki/Features#lastinsertid)) + +### Fixed +- Issue [#555](https://github.com/Microsoft/msphpsql/issues/555) - Hebrew strings truncation (requires MS ODBC Driver 17) +- Adjusted precisions for numeric/decimal inputs with Always Encrypted +- Support for non-UTF8 locales in Linux and macOS +- Fixed crash caused by executing an invalid query in a transaction (Issue [#434](https://github.com/Microsoft/msphpsql/issues/434)) +- Added error handling for using PDO::SQLSRV_ATTR_DIRECT_QUERY or PDO::ATTR_EMULATE_PREPARES in a Column Encryption enabled connection +- Added error handling for binding TEXT, NTEXT or IMAGE as output parameter (Issue [#231](https://github.com/Microsoft/msphpsql/issues/231)) +- PDO::quote with string containing ASCII NUL character (Issue [#538]( https://github.com/Microsoft/msphpsql/issues/538)) +- Decimal types with no decimals are correctly handled when AE is enabled (PR [#544](https://github.com/Microsoft/msphpsql/pull/544)) +- BIGINT as an output param no longer results in value out of range exception when the returned value is larger than a maximum integer ([PR #567](https://github.com/Microsoft/msphpsql/pull/567)) + +### Removed +- Dropped support for Ubuntu 15 +- Supplying tablename into PDO::lastInsertId($name) no longer return the last inserted row ([lastInsertId](https://github.com/Microsoft/msphpsql/wiki/Features#lastinsertid)) + +### Limitations +- Always Encrypted is not supported in Linux and macOS +- In Linux and macOS, setlocale() only takes effect if it is invoked before the first connection. Attempting to set the locale after connection will not work +- Always Encrypted functionalities are only supported using MS ODBC Driver 17 +- [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 MS ODBC Driver 17 +- 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) +- Connection with Connection Resiliency enabled does not resume properly with Connection Pooling (Issue [#678](https://github.com/Microsoft/msphpsql/issues/678)) +- With ColumnEncryption enabled, calling stored procedure with XML parameter does not work (Issue [#674](https://github.com/Microsoft/msphpsql/issues/674)) +- Cannot connect with both Connection Resiliency enabled and ColumnEncryption enabled (Issue [#577](https://github.com/Microsoft/msphpsql/issues/577)) +- With ColumnEncryption enabled, retrieving a negative decimal value as output parameter causes truncation of the last digit (Issue [#705](https://github.com/Microsoft/msphpsql/issues/705)) +- With ColumnEncryption enabled, cannot insert a double into a decimal column with precision and scale of (38, 38) (Issue [#706](https://github.com/Microsoft/msphpsql/issues/706)) +- With ColumnEncryption enabled, when fetching decimals as output parameters bound to PDO::PARAM_BOOL or PDO::PARAM_INT, floats are returned, not integers (Issue [#707](https://github.com/Microsoft/msphpsql/issues/707)) + + ## Windows/Linux/macOS 5.2.0-RC - 2017-12-20 Updated PECL release packages. Here is the list of updates: diff --git a/Dockerfile-msphpsql b/Dockerfile-msphpsql index 18051c16..7de26f1f 100644 --- a/Dockerfile-msphpsql +++ b/Dockerfile-msphpsql @@ -37,6 +37,13 @@ RUN locale-gen en_US RUN locale-gen en_US.UTF-8 ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' LC_ALL='en_US.UTF-8' +#install ODBC driver +RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - +RUN curl https://packages.microsoft.com/config/ubuntu/16.04/prod.list > /etc/apt/sources.list.d/mssql-release.list + +RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && ACCEPT_EULA=Y apt-get install -y msodbcsql17 mssql-tools +ENV PATH="/opt/mssql-tools/bin:${PATH}" + #install coveralls RUN pip install --upgrade pip && pip install cpp-coveralls @@ -45,18 +52,12 @@ RUN pip install --upgrade pip && pip install cpp-coveralls #another option is to copy source to build directory on image RUN mkdir -p $PHPSQLDIR 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.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/ + RUN chmod +x ./packagize.sh RUN /bin/bash -c "./packagize.sh" -RUN echo "extension = pdo_sqlsrv.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"` +RUN echo "extension = pdo_sqlsrv.so" >> /etc/php/7.0/cli/conf.d/20-pdo_sqlsrv.ini RUN echo "extension = sqlsrv.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"` WORKDIR $PHPSQLDIR/source/sqlsrv diff --git a/Linux-mac-install.md b/Linux-mac-install.md new file mode 100644 index 00000000..b2811e2b --- /dev/null +++ b/Linux-mac-install.md @@ -0,0 +1,305 @@ +# PHP Linux and Mac Drivers Installation Tutorial +The following instructions assume a clean environment and show how to install PHP 7.x, the Microsoft ODBC driver, Apache, and the Microsoft drivers for PHP for Microsoft SQL Server on Ubuntu 16.04 and 17.10, RedHat 7, Debian 8 and 9, Suse 12, and macOS 10.11 and 10.12. These instructions advise installing the drivers using PECL, but you can also download the prebuilt binaries from the [Microsoft Drivers for PHP for Microsoft SQL Server](https://github.com/Microsoft/msphpsql/releases) Github project page and install them following the instructions in [Loading the Microsoft Drivers for PHP for Microsoft SQL Server](../../connect/php/loading-the-php-sql-driver.md). For an explanation of extension loading and why we do not add the extensions to php.ini, see the section on [loading the drivers](../../connect/php/loading-the-php-sql-driver.md##loading-the-driver-at-php-startup). + +These instruction install PHP 7.2 by default -- see the notes at the beginning of each section to install PHP 7.0 or 7.1. + +## Contents of this page: + +- [Installing the drivers on Ubuntu 16.04 and 17.10](#installing-the-drivers-on-ubuntu-1604-and-1710) +- [Installing the drivers on Red Hat 7](#installing-the-drivers-on-red-hat-7) +- [Installing the drivers on Debian 8 and 9](#installing-the-drivers-on-debian-8-and-9) +- [Installing the drivers on Suse 12](#installing-the-drivers-on-suse-12) +- [Installing the drivers on macOS El Capitan and Sierra](#installing-the-drivers-on-macos-el-capitan-and-sierra) + +## Installing the drivers on Ubuntu 16.04 and 17.10 + + > [!NOTE] + > To install PHP 7.0 or 7.1, replace 7.2 with 7.0 or 7.1 in the following commands. + +### Step 1. Install PHP +``` +sudo su +add-apt-repository ppa:ondrej/php -y +apt-get update +apt-get install php7.2 php7.2-dev php7.2-xml -y --allow-unauthenticated +``` +### Step 2. Install prerequisites +Install the ODBC driver for Ubuntu by following the instructions on the [Linux and macOS installation page](https://docs.microsoft.com/en-us/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server). + +### Step 3. Install the PHP drivers for Microsoft SQL Server +``` +sudo su +echo extension=pdo_sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/30-pdo_sqlsrv.ini +echo extension=sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/20-sqlsrv.ini +exit +sudo pecl install sqlsrv +sudo pecl install pdo_sqlsrv +``` +### Step 4. Install Apache and configure driver loading +``` +sudo su +apt-get install libapache2-mod-php7.2 apache2 +a2dismod mpm_event +a2enmod mpm_prefork +a2enmod php7.2 +echo "extension=sqlsrv.so" >> /etc/php/7.2/apache2/php.ini +echo "extension=pdo_sqlsrv.so" >> /etc/php/7.2/apache2/php.ini +``` +### Step 5. Restart Apache and test the sample script +``` +sudo service apache2 restart +``` +To test your installation, see [Testing your installation](#testing-your-installation) at the end of this document. + +## Installing the drivers on Red Hat 7 + + > [!NOTE] + > To install PHP 7.0 or 7.1, replace remi-php72 with remi-php70 or remi-php71 respectively in the following commands. + +### Step 1. Install PHP + +``` +sudo su +wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm +wget http://rpms.remirepo.net/enterprise/remi-release-7.rpm +rpm -Uvh remi-release-7.rpm epel-release-latest-7.noarch.rpm +subscription-manager repos --enable=rhel-7-server-optional-rpms +yum-config-manager --enable remi-php72 +yum update +yum install php php-pdo php-xml php-pear php-devel re2c gcc-c++ gcc +``` +### Step 2. Install prerequisites +Install the ODBC driver for Red Hat 7 by following the instructions on the [Linux and macOS installation page](../../connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server.md). + +Compiling the PHP drivers with PECL with PHP 7.2 requires a more recent GCC than the default: +``` +sudo yum-config-manager --enable rhel-server-rhscl-7-rpms +sudo yum install devtoolset-7 +scl enable devtoolset-7 bash +``` +### Step 3. Install the PHP drivers for Microsoft SQL Server +``` +sudo su +echo extension=pdo_sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/30-pdo_sqlsrv.ini +echo extension=sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/20-sqlsrv.ini +exit +sudo pecl install sqlsrv +sudo pecl install pdo_sqlsrv +``` +An issue in PECL may prevent correct installation of the latest version of the drivers even if you have upgraded GCC. To install, download the packages and compile manually: +``` +pecl download sqlsrv +tar xvzf sqlsrv-5.2.0.tgz +cd sqlsrv-5.2.0/ +phpize +./configure --with-php-config=/usr/bin/php-config +make +sudo make install +``` +You can alternatively download the prebuilt binaries from the [Github project page](https://github.com/Microsoft/msphpsql/releases), or install from the Remi repo: +``` +sudo yum install php-sqlsrv php-pdo_sqlsrv +``` +### Step 4. Install Apache +``` +sudo yum install httpd +``` +SELinux is installed by default and runs in Enforcing mode. To allow Apache to connect to databases through SELinux, run the following command: +``` +sudo setsebool -P httpd_can_network_connect_db 1 +``` +### Step 5. Restart Apache and test the sample script +``` +sudo apachectl restart +``` +To test your installation, see [Testing your installation](#testing-your-installation) at the end of this document. + +## Installing the drivers on Debian 8 and 9 + + > [!NOTE] + > To install PHP 7.0 or 7.1, replace 7.2 in the following commands with 7.0 or 7.1. + +### Step 1. Install PHP +``` +sudo su +apt-get install curl apt-transport-https +wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg +echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list +apt-get update +apt-get install –y php7.2 php7.2-dev php7.2-xml +``` +### Step 2. Install prerequisites +Install the ODBC driver for Debian by following the instructions on the [Linux and macOS installation page](../../connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server.md). + +You may also need to generate the correct locale to get PHP output to display correctly in a browser. For example, for the en_US UTF-8 locale, run the following commands: +``` +sudo su +sed -i 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/g' /etc/locale.gen +locale-gen +``` + +### Step 3. Install the PHP drivers for Microsoft SQL Server +``` +sudo su +echo extension=pdo_sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/30-pdo_sqlsrv.ini +echo extension=sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/20-sqlsrv.ini +exit +sudo pecl install sqlsrv +sudo pecl install pdo_sqlsrv +``` +### Step 4. Install Apache and configure driver loading +``` +sudo su +apt-get install libapache2-mod-php7.2 apache2 +a2dismod mpm_event +a2enmod mpm_prefork +a2enmod php7.2 +echo "extension=sqlsrv.so" >> /etc/php/7.2/apache2/php.ini +echo "extension=pdo_sqlsrv.so" >> /etc/php/7.2/apache2/php.ini +``` +### Step 5. Restart Apache and test the sample script +``` +sudo service apache2 restart +``` +To test your installation, see [Testing your installation](#testing-your-installation) at the end of this document. + +## Installing the drivers on Suse 12 + + > [!NOTE] + > To install PHP 7.0, skip the command below adding the repository - 7.0 is the default PHP on suse 12. + > To install PHP 7.1, replace the repository URL below with the following URL: + `http://download.opensuse.org/repositories/devel:/languages:/php:/php71/SLE_12/devel:languages:php:php71.repo` + +### Step 1. Install PHP +``` +sudo su +zypper -n ar -f http://download.opensuse.org/repositories/devel:languages:php/SLE_12/devel:languages:php.repo +zypper --gpg-auto-import-keys refresh +zypper -n install php7 php7-pear php7-devel +``` +### Step 2. Install prerequisites +Install the ODBC driver for Suse 12 by following the instructions on the [Linux and macOS installation page](../../connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server.md). + +### Step 3. Install the PHP drivers for Microsoft SQL Server +``` +sudo su +echo extension=pdo_sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/pdo_sqlsrv.ini +echo extension=sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/sqlsrv.ini +exit +sudo pecl install sqlsrv +sudo pecl install pdo_sqlsrv +``` +### Step 4. Install Apache and configure driver loading +``` +sudo su +zypper install apache2 apache2-mod_php7 +a2enmod php7 +echo "extension=sqlsrv.so" >> /etc/php7/apache2/php.ini +echo "extension=pdo_sqlsrv.so" >> /etc/php7/apache2/php.ini +``` +### Step 5. Restart Apache and test the sample script +``` +sudo systemctl restart apache2 +``` +To test your installation, see [Testing your installation](#testing-your-installation) at the end of this document. + +## Installing the drivers on macOS El Capitan and Sierra + +If you do not already have it, install brew as follows: +``` +/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" +``` + + > [!NOTE] + > To install PHP 7.0 or 7.1, replace php72 with php70 or php71 respectively in the following commands. + +### Step 1. Install PHP + +``` +brew tap +brew tap homebrew/dupes +brew tap homebrew/versions +brew tap homebrew/homebrew-php +brew install php72 --with-pear --with-httpd24 --with-cgi +echo 'export PATH="/usr/local/sbin:$PATH"' >> ~/.bash_profile +echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.bash_profile +source ~/.bash_profile +``` +### Step 2. Install prerequisites +Install the ODBC driver for macOS by following the instructions on the [Linux and macOS installation page](../../connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server.md). + +In addition, you may need to install the GNU make tools: +``` +brew install autoconf automake libtool +``` + +### Step 3. Install the PHP drivers for Microsoft SQL Server +``` +chmod -R ug+w /usr/local/opt/php72/lib/php +pear config-set php_ini /usr/local/etc/php/7.2/php.ini system +sudo pecl install sqlsrv +sudo pecl install pdo_sqlsrv +``` +### Step 4. Install Apache and configure driver loading +``` +(echo ""; echo "SetHandler application/x-httpd-php"; echo "";) >> /usr/local/etc/httpd/httpd.conf +``` +### Step 5. Restart Apache and test the sample script +``` +sudo apachectl restart +``` +To test your installation, see [Testing your installation](#testing-your-installation) at the end of this document. + +## Testing Your Installation + +To test this sample script, create a file called testsql.php in your system's document root. This is `/var/www/html/` on Ubuntu, Debian, and Redhat, `/srv/www/htdocs` on SUSE, or `/usr/local/var/www` on macOS. Copy the following script to it, replacing the server, database, username, and password as appropriate. +``` + "yourDatabase", + "Uid" => "yourUsername", + "PWD" => "yourPassword" +); + +//Establishes the connection +$conn = sqlsrv_connect($serverName, $connectionOptions); +if( $conn === false ) { + die( FormatErrors( sqlsrv_errors())); +} + +//Select Query +$tsql= "SELECT @@Version as SQL_VERSION"; + +//Executes the query +$getResults= sqlsrv_query($conn, $tsql); + +//Error handling +if ($getResults == FALSE) + die(FormatErrors(sqlsrv_errors())); +?> + +

Results :

+ +"); +} + +sqlsrv_free_stmt($getResults); + +function FormatErrors( $errors ) +{ + /* Display errors. */ + echo "Error information:
"; + foreach ( $errors as $error ) + { + echo "SQLSTATE: ".$error['SQLSTATE']."
"; + echo "Code: ".$error['code']."
"; + echo "Message: ".$error['message']."
"; + } +} +?> +``` +Point your browser to http://localhost/testsql.php (http://localhost:8080/testsql.php on macOS). You should now be able to connect to your SQL Server/Azure SQL database. 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 deleted file mode 100644 index 673fe035..00000000 Binary files a/ODBC 17 binaries preview/Debian 8/msodbcsql_17.0.0.5-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 deleted file mode 100644 index fc818465..00000000 Binary files a/ODBC 17 binaries preview/Debian 8/mssql-tools_17.0.0.5-1_amd64.deb and /dev/null 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 deleted file mode 100644 index d9cc02a8..00000000 Binary files a/ODBC 17 binaries preview/Debian 9/msodbcsql_17.0.0.5-1_amd64.deb and /dev/null 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 deleted file mode 100644 index 58e697f1..00000000 Binary files a/ODBC 17 binaries preview/Debian 9/mssql-tools_17.0.0.5-1_amd64.deb and /dev/null differ diff --git a/ODBC 17 binaries preview/README.md b/ODBC 17 binaries preview/README.md deleted file mode 100644 index c1a0a405..00000000 --- a/ODBC 17 binaries preview/README.md +++ /dev/null @@ -1,6 +0,0 @@ - -The ODBC driver 17 preview binaries in this directory are required in order to use Always Encrypted functionality. Please note that these drivers should be considered to be preview versions -- they should not be used in production and are not supported by Microsoft. They will be replaced upon the official release of ODBC driver 17. - -On Windows, the ODBC 17 preview binaries require the Visual C/C++ 2013 runtime libraries installed separately. These are installed with the [Visual Studio C++ 2013 Redistributable](https://www.microsoft.com/en-ca/download/details.aspx?id=40784) or with the [SQL Server command line utilities](https://www.microsoft.com/en-ca/download/details.aspx?id=53591). Once you have these, simply run the msi to install. - -For instructions on installing the binaries on Linux platforms, please see [this page](https://github.com/Microsoft/msphpsql/wiki/Install-and-configuration#odbc-17-linux-installation). 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 deleted file mode 100644 index 305a16a6..00000000 Binary files a/ODBC 17 binaries preview/Red Hat 7/msodbcsql-17.0.0.5-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 deleted file mode 100644 index effad031..00000000 Binary files a/ODBC 17 binaries preview/Red Hat 7/mssql-tools-17.0.0.5-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 deleted file mode 100644 index 83ea4e58..00000000 Binary files a/ODBC 17 binaries preview/SUSE 12/msodbcsql-17.0.0.5-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 deleted file mode 100644 index 4dd1a1b2..00000000 Binary files a/ODBC 17 binaries preview/SUSE 12/mssql-tools-17.0.0.5-1.x86_64.rpm 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 deleted file mode 100644 index f3ed15f8..00000000 Binary files a/ODBC 17 binaries preview/Ubuntu 16/msodbcsql_17.0.0.5-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 deleted file mode 100644 index f1141cee..00000000 Binary files a/ODBC 17 binaries preview/Ubuntu 16/mssql-tools_17.0.0.5-1_amd64.deb and /dev/null 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 deleted file mode 100644 index 510ceb09..00000000 Binary files a/ODBC 17 binaries preview/Ubuntu 17/msodbcsql_17.0.0.5-1_amd64.deb and /dev/null 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 deleted file mode 100644 index 5e161efc..00000000 Binary files a/ODBC 17 binaries preview/Ubuntu 17/mssql-tools_17.0.0.5-1_amd64.deb and /dev/null differ diff --git a/ODBC 17 binaries preview/Windows/x64/msodbcsql.msi b/ODBC 17 binaries preview/Windows/x64/msodbcsql.msi deleted file mode 100644 index 8a2dfcca..00000000 Binary files a/ODBC 17 binaries preview/Windows/x64/msodbcsql.msi and /dev/null differ diff --git a/ODBC 17 binaries preview/Windows/x86/msodbcsql.msi b/ODBC 17 binaries preview/Windows/x86/msodbcsql.msi deleted file mode 100644 index 8356cb36..00000000 Binary files a/ODBC 17 binaries preview/Windows/x86/msodbcsql.msi and /dev/null differ diff --git a/README.md b/README.md index cc31f022..3d494d9c 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# Microsoft Drivers for PHP for SQL Server +# Microsoft Drivers for PHP for Microsoft SQL Server -**Welcome to the Microsoft Drivers for PHP for SQL Server PHP 7** +**Welcome to the Microsoft Drivers for PHP for Microsoft SQL Server** -The Microsoft Drivers for PHP for SQL Server are PHP extensions that allow for the reading and writing of SQL Server data from within PHP scripts. The SQLSRV extension provides a procedural interface while the PDO_SQLSRV extension implements PDO for accessing data in all editions of SQL Server 2008 R2 and later (including Azure SQL DB). These drivers rely on the Microsoft ODBC Driver for SQL Server to handle the low-level communication with SQL Server. +The Microsoft Drivers for PHP for Microsoft SQL Server are PHP extensions that allow for the reading and writing of SQL Server data from within PHP scripts. The SQLSRV extension provides a procedural interface while the PDO_SQLSRV extension implements PHP Data Objects (PDO) for accessing data in all editions of SQL Server 2008 R2 and later (including Azure SQL DB). These drivers rely on the Microsoft ODBC Driver for SQL Server to handle the low-level communication with SQL Server. -This release contains the SQLSRV and PDO_SQLSRV drivers for PHP 7.0.* or above with improvements on both drivers and some limitations (see Limitations below for details). Upcoming release(s) will contain more functionality, bug fixes, and more (see Plans below for more details). +This release contains the SQLSRV and PDO_SQLSRV drivers for PHP 7.* with improvements on both drivers and some limitations (see Limitations below for details). Upcoming releases will contain additional functionality, bug fixes, and more (see Plans below for more details). SQL Server Team @@ -31,10 +31,10 @@ Thank you for taking the time to participate in our last survey. You can continu ## Get Started +* [**Windows + SQL Server + PHP 7**](https://www.microsoft.com/en-us/sql-server/developer-get-started/php/windows) * [**Ubuntu + SQL Server + PHP 7**](https://www.microsoft.com/en-us/sql-server/developer-get-started/php/ubuntu) * [**RedHat + SQL Server + PHP 7**](https://www.microsoft.com/en-us/sql-server/developer-get-started/php/rhel) * [**SUSE + SQL Server + PHP 7**](https://www.microsoft.com/en-us/sql-server/developer-get-started/php/sles) -* [**Windows + SQL Server + PHP 7**](https://www.microsoft.com/en-us/sql-server/developer-get-started/php/windows) * [**macOS + SQL Server + PHP 7**](https://www.microsoft.com/en-us/sql-server/developer-get-started/php/mac/) * [**Docker**](https://hub.docker.com/r/lbosqmsft/mssql-php-msphpsql/) @@ -43,441 +43,66 @@ Thank you for taking the time to participate in our last survey. You can continu Please visit the [blog][blog] for more announcements. +## Prerequisites -## Build (Windows) - -Note: if you prefer, you can use the pre-compiled binaries found in the [releases](https://github.com/Microsoft/msphpsql/releases) - -#### Prerequisites - -You must first be able to build PHP 7.0.* or above without including these extensions. For help with doing this, see the [official PHP website][phpbuild] for building your own PHP in Windows. - -#### 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.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) - -#### Prerequisites +For full details on the system requirements for the drivers, see the [system requirements](https://docs.microsoft.com/en-us/sql/connect/php/system-requirements-for-the-php-sql-driver) on MSDN. +On the client machine: +- PHP 7.0.x, 7.1.x, or 7.2.x (7.2.0 and up on Unix, 7.2.1 and up on Windows) - A Web server such as Internet Information Services (IIS) is required. Your Web server must be configured to run PHP -- [Microsoft ODBC Driver 11][odbc11], [Microsoft ODBC Driver 13][odbc13] or [Microsoft ODBC Driver 17][odbc17] +- [Microsoft ODBC Driver 11][odbc11], [Microsoft ODBC Driver 13][odbc13], or [Microsoft ODBC Driver 17][odbc17] -#### Enable the drivers +On the server side, Microsoft SQL Server 2008 R2 and above on Windows is supported, as is Microsoft SQL Server 2016 and above on Linux. -1. Make sure that the driver is in your PHP extension directory (you can simply copy it there if you did not use nmake install). +## Building and Installing the Drivers on Windows -2. Enable it within your PHP installation's php.ini: `extension=php_sqlsrv.dll` and/or `extension=php_pdo_sqlsrv.dll`. If necessary, specify the extension directory using extension_dir, for example: `extension_dir = "C:\PHP\ext"`. Note that the precompiled binaries have different names -- substitute accordingly in php.ini. +The drivers are distributed as pre-compiled extensions for PHP found on the [releases page](https://github.com/Microsoft/msphpsql/releases). They are available in thread-safe and non thread-safe versions, and in 32-bit and 64-bit versions. The source code for the drivers is also available, and you can compile them as thread safe or non-thread safe versions. The thread safety configuration of your web server will determine which version you need. + +If you choose to build the drivers, you must be able to build PHP 7 without including these extensions. For help building PHP on Windows, see the [official PHP website][phpbuild]. For details on compiling the drivers, see the [documentation](https://github.com/Microsoft/msphpsql/tree/dev/buildscripts#windows) -- an example buildscript is provided, but you can also compile the drivers manually. -3. Restart the Web server. +To load the drivers, make sure that the driver is in your PHP extension directory and enable it in your PHP installation's php.ini file by adding `extension=php_sqlsrv.dll` and/or `extension=php_pdo_sqlsrv.dll` to it. If necessary, specify the extension directory using `extension_dir`, for example: `extension_dir = "C:\PHP\ext"`. Note that the precompiled binaries have different names -- substitute accordingly in php.ini. For more details on loading the drivers, see [Loading the PHP SQL Driver](https://docs.microsoft.com/en-us/sql/connect/php/loading-the-php-sql-driver) on MSDN. + +Finally, 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 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 16.04, 17.10** - - sudo su - apt-get update - apt-get -y install php7.0 mcrypt php7.0-mcrypt php-mbstring php-pear php7.0-dev php7.0-xml - -**RedHat 7** - - sudo su - wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm - wget http://rpms.remirepo.net/enterprise/remi-release-7.rpm - rpm -Uvh remi-release-7.rpm epel-release-latest-7.noarch.rpm - subscription-manager repos --enable=rhel-7-server-optional-rpms - yum-config-manager --enable remi-php70 - yum update - yum install php php-pdo php-xml php-pear php-devel re2c gcc-c++ gcc - -**Debian 8** - - 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 jessie all" >> /etc/apt/sources.list - echo "deb-src http://packages.dotdeb.org jessie all" >> /etc/apt/sources.list - 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 10.11, 10.12** - - /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" - brew tap - brew tap homebrew/dupes - brew tap homebrew/versions - brew tap homebrew/homebrew-php - brew install php70 --with-pear --with-httpd24 --with-cgi - echo 'export PATH="/usr/local/sbin:$PATH"' >> ~/.bash_profile - echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.bash_profile - source ~/.bash_profile - -#### PHP 7.1 - -**Ubuntu 16.04, 17.10** - - sudo su - add-apt-repository ppa:ondrej/php - apt-get update - apt-get -y install php7.1 mcrypt php7.1-mcrypt php-mbstring php-pear php7.1-dev php7.1-xml - -**RedHat 7** - - sudo su - wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm - wget http://rpms.remirepo.net/enterprise/remi-release-7.rpm - rpm -Uvh remi-release-7.rpm epel-release-latest-7.noarch.rpm - subscription-manager repos --enable=rhel-7-server-optional-rpms - yum-config-manager --enable remi-php71 - yum update - yum install php php-pdo php-xml php-pear php-devel re2c gcc-c++ gcc - -**Debian 8, 9** - - sudo su - apt-get install curl apt-transport-https - wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg - echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list - apt-get update - apt-get install -y php7.1 php-pear php7.1-dev php7.1-xml - -**SUSE 12** - - sudo su - zypper -n ar -f http://download.opensuse.org/repositories/devel:/languages:/php/openSUSE_Leap_42.3/ devel:languages:php - zypper --gpg-auto-import-keys refresh - zypper -n install php7 php7-pear php7-devel - -**macOS 10.11, 10.12** - - /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" - brew tap - brew tap homebrew/dupes - brew tap homebrew/versions - brew tap homebrew/homebrew-php - brew install php71 --with-pear --with-httpd24 --with-cgi - echo 'export PATH="/usr/local/sbin:$PATH"' >> ~/.bash_profile - echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.bash_profile - source ~/.bash_profile - - -### Step 2: Install Prerequisites - -**Ubuntu 16.04** - - sudo su - curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - - curl https://packages.microsoft.com/config/ubuntu/16.04/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 17.10 (available upon the official release of ODBC driver 17)** - - 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 - curl https://packages.microsoft.com/config/rhel/7/prod.repo > /etc/yum.repos.d/mssql-release.repo - exit - sudo yum update - sudo yum remove unixODBC-utf16-devel #to avoid conflicts - sudo ACCEPT_EULA=Y yum install msodbcsql mssql-tools - sudo yum install unixODBC-devel - echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile - echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc - source ~/.bashrc - -**Debian 8** - - sudo su - curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - - curl https://packages.microsoft.com/config/debian/8/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 - -**Debian 9 (available upon the official release of ODBC driver 17)** - - 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 - zypper ar https://packages.microsoft.com/config/sles/12/prod.repo - sudo zypper --gpg-auto-import-keys refresh - exit - sudo ACCEPT_EULA=Y zypper install msodbcsql - sudo ACCEPT_EULA=Y zypper install mssql-tools - sudo zypper install unixODBC-devel - echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile - echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc - source ~/.bashrc - -**macOS 10.11, 10.12** - - brew tap microsoft/msodbcsql https://github.com/Microsoft/homebrew-mssql-release - brew update - brew install --no-sandbox msodbcsql - brew install mssql-tools - brew install autoconf - -*Note: Be sure to install PHP 7+ before proceeding to step 3. The Microsoft PHP Drivers for SQL Server will only work for PHP 7+. - -### Step 3: Install the Microsoft PHP Drivers for SQL Server - -*Note: You can run `sudo pecl search sqlsrv` to search for the latest releases and `sudo pecl install sqlsrv-[version]` to install a specific version. PECL installs the stable version when version is not specified. Drivers are Mac-compatible starting from `4.1.7preview` release. - -On Ubuntu, Debian, and SUSE systems only, run: - - sudo pear config-set php_ini `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"` system - -On macOS, run: - - chmod -R ug+w /usr/local/opt/php71/lib/php - pear config-set php_ini /usr/local/etc/php/7.1/php.ini system - -On all systems, run: - - pecl install sqlsrv - pecl install pdo_sqlsrv - -### Step 4: Install and Configure Apache - -#### PHP 7.0 - -**Ubuntu and Debian** - - sudo su - apt-get install libapache2-mod-php7.0 apache2 - a2dismod mpm_event - a2enmod mpm_prefork - a2enmod php7.0 - echo "extension=sqlsrv.so" >> /etc/php/7.0/apache2/php.ini - echo "extension=pdo_sqlsrv.so" >> /etc/php/7.0/apache2/php.ini - -**RedHat** - - sudo su - yum install httpd - echo "extension=sqlsrv.so" > /etc/php.d/sqlsrv.ini - echo "extension=pdo_sqlsrv.so" > /etc/php.d/pdo_sqlsrv.ini - -**SUSE** - - sudo su - zypper install apache2 apache2-mod_php7 - a2enmod php7 - echo "extension=sqlsrv.so" >> /etc/php7/apache2/php.ini - echo "extension=pdo_sqlsrv.so" >> /etc/php7/apache2/php.ini - -**macOS** - - (echo ""; echo "SetHandler application/x-httpd-php"; echo "";) >> /usr/local/etc/apache2/2.4/httpd.conf - -#### PHP 7.1 - -**Ubuntu and Debian** - - sudo su - apt-get install libapache2-mod-php7.1 apache2 - a2dismod mpm_event - a2enmod mpm_prefork - a2enmod php7.1 - echo "extension=sqlsrv.so" >> /etc/php/7.1/apache2/php.ini - echo "extension=pdo_sqlsrv.so" >> /etc/php/7.1/apache2/php.ini - -**RedHat** - - sudo su - yum install httpd - echo "extension=sqlsrv.so" > /etc/php.d/sqlsrv.ini - echo "extension=pdo_sqlsrv.so" > /etc/php.d/pdo_sqlsrv.ini - -**SUSE** - - sudo su - zypper install apache2 apache2-mod_php7 - a2enmod php7 - echo "extension=sqlsrv.so" >> /etc/php7/apache2/php.ini - echo "extension=pdo_sqlsrv.so" >> /etc/php7/apache2/php.ini - -**macOS** - - (echo ""; echo "SetHandler application/x-httpd-php"; echo "";) >> /usr/local/etc/apache2/2.4/httpd.conf - - -### Step 5: Restart Apache to load the new php.ini file - -**Ubuntu, Debian, and SUSE** - - sudo systemctl restart apache2 - -**RedHat** - - sudo systemctl restart httpd - -Note: On RedHat, SELinux is installed by default and runs in Enforcing mode. To allow Apache to connect to a database through SELinux, run the following command: - - sudo setsebool -P httpd_can_network_connect_db 1 - -**macOS** - - sudo apachectl restart - - -### Step 6: Create your sample app -Navigate to your system's document root -- `/var/www/html` on Ubuntu, Debian, and Redhat, `/srv/www/htdocs` on SUSE, or `/usr/local/var/www/htdocs` on Mac. Create a new file called testsql.php. Copy and paste the following code into testsql.php and change the servername, username, password and databasename. - - "yourDatabase", - "Uid" => "yourUsername", - "PWD" => "yourPassword" - ); - //Establishes the connection - $conn = sqlsrv_connect( $serverName, $connectionOptions ); - if( $conn === false ) { - die( FormatErrors( sqlsrv_errors())); - } - //Select Query - $tsql= "SELECT @@Version as SQL_VERSION"; - //Executes the query - $getResults= sqlsrv_query( $conn, $tsql ); - //Error handling - - if ( $getResults == FALSE ) - die( FormatErrors( sqlsrv_errors())); - ?> -

Results :

- "); - } - sqlsrv_free_stmt( $getResults ); - function FormatErrors( $errors ) - { - /* Display errors. */ - echo "Error information:
"; - - foreach ( $errors as $error ) - { - echo "SQLSTATE: ".$error['SQLSTATE']."
"; - echo "Code: ".$error['code']."
"; - echo "Message: ".$error['message']."
"; - } - } - ?> - -### Step 7: Run your sample app - -Go to your browser and type in http://localhost/testsql.php (http://localhost:8080/testsql.php on Mac) -You should be able to connect to your SQL Server/Azure SQL Database. - -The drivers are distributed as shared binary extensions for PHP. They are available in thread safe (*_ts.so) and-non thread safe (*_nts.so) versions. The source code for the drivers is also available, and you can choose whether to compile them as thread safe or non-thread safe versions. The thread safety configuration of your web server will determine which version you need. +For full instructions on installing the drivers on all supported Unix platforms, see [the installation instructions on MSDN](https://docs.microsoft.com/en-us/sql/connect/php/installation-tutorial-linux-mac). ## Sample Code -For samples, please see the sample folder. For setup instructions, see [here](https://docs.microsoft.com/en-us/azure/sql-database/sql-database-develop-php-simple). +For PHP code samples, please see the [sample](https://github.com/Microsoft/msphpsql/tree/master/sample) folder or the [code samples on MSDN](https://docs.microsoft.com/en-us/sql/connect/php/code-samples-for-php-sql-driver). -## Limitations - -- This release contains the PHP 7 port of the SQLSRV and PDO_SQLSRV drivers, and does not provide backwards compatibility with PHP 5. -- Binding output parameters using emulate prepare is not supported. -- Linux - - ODBC 3.52 is supported but not 3.8. - - Connection using named instances using '\' is not supported. - - Local encodings other than UTF-8 are not supported, and SQLSRV_ENC_CHAR only supports ASCII characters with ASCII code of 0 to 127. - -## Known Issues -- 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/Features#connection-pooling-in-linux-and-mac) +## Limitations and Known Issues +Please refer to [Releases](https://github.com/Microsoft/msphpsql/releases) for the latest limitations and known issues. ## Version number -Version number of PHP drivers follow the [semantic versioning](http://semver.org/): +The version numbers of the PHP drivers follow [semantic versioning](http://semver.org/): Given a version number MAJOR.MINOR.PATCH, - - MAJOR version is incremented when an incompatible API changes is made, - - MINOR version is incremented when a functionality in a backwards-compatible manner is added, and + - MAJOR version is incremented when an incompatible API change is made, + - MINOR version is incremented when functionality is added in a backwards-compatible manner, and - PATCH version is incremented when backwards-compatible bug fixes are made. -version number MAY have trailing pre-release version to indicate the stability, and/or build meta data. +The version number may have trailing pre-release version identifiers to indicate the stability and/or build metadata. -- Pre-release version is denoted by hyphen followed by `preview` or `rc` keyword and may be followed by a series of dot separated identifiers. Production quality releases do not contain the pre-release version. `preview` has lower precedence than `rc`. Example of precedence: *preview < preview.1 < rc < rc.1*. -*Note that PECL package version does not have the hyphen before pre-release version, due to restrictions in PECL. Example of PECL package version: 1.2.3preview* -- Build metadata MAY be denoted by a plus sign followed by 4 digits, such as `1.2.3-preview+5678` or `1.2.3+5678`. Build meta data does NOT figure into the precedence order. - - +- Pre-release version is denoted by a hyphen followed by `preview` or `RC` and may be followed by a series of dot separated identifiers. Production quality releases do not contain the pre-release version. `preview` has lower precedence than `RC`. Example of precedence: *preview < preview.1 < RC < RC.1*. Note that the PECL package version numbers do not have the hyphen before the pre-release version, owing to restrictions in PECL. Example of a PECL package version number: 1.2.3preview +- Build metadata may be denoted by a plus sign followed by 4 or 5 digits, such as `1.2.3-preview+5678` or `1.2.3+5678`. Build metadata does not figure into the precedence order. ## Future Plans -- Expand SQL 16 Feature Support (example: Always Encrypted). -- Add More Verification/Fundamental Tests. -- Bug Fixes. +- Expand SQL Server 2016 feature support (example: Always Encrypted) +- Add more verification/fundamental tests +- Bug fixes ## Guidelines for Reporting Issues We appreciate you taking the time to test the driver, provide feedback and report any issues. It would be extremely helpful if you: - Report each issue as a new issue (but check first if it's already been reported) -- Try to be detailed in your report. Useful information for good bug reports include: +- Try to be detailed in your report. Useful information for good bug reports includes: * What you are seeing and what the expected behaviour is * Can you connect to SQL Server via `sqlcmd`? * Which driver: SQLSRV or PDO_SQLSRV? - * Environment details: e.g. PHP version, thread safe (TS) or non-thread safe (NTS), 32-bit &/or 64-bit? - * Table schema (for some issues the data types make a big difference!) + * Environment details: e.g. PHP version, thread safe (TS) or non-thread safe (NTS), 32-bit or 64-bit? + * Table schema (for some issues, the data types make a big difference!) * Any other relevant information you want to share - Try to include a PHP script demonstrating the isolated problem. @@ -486,11 +111,11 @@ Thank you! ## FAQs **Q:** Can we get dates for any of the Future Plans listed above? -**A:** At this time, Microsoft is not able to announce dates. We are working extremely hard to release future versions of the driver. We will share future plans as appropriate. +**A:** At this time, Microsoft is not able to announce dates. We are working hard to release future versions of the driver and will share future plans as appropriate. **Q:** What's next? -**A:** On July 6, 2017 we released the production release version 4.3.0 of our PHP Driver. We will continue working on our future plans and releasing previews of upcoming releases frequently. +**A:** On March 23, 2018 we released the production release version 5.2.0 of our PHP Driver. We will continue working on our future plans and releasing previews of upcoming releases frequently. **Q:** Is Microsoft taking pull requests for this project? @@ -516,9 +141,9 @@ This project has adopted the Microsoft Open Source Code of Conduct. For more inf [blog]: http://blogs.msdn.com/b/sqlphp/ -[project]: https://github.com/Azure/msphpsql +[project]: https://github.com/Microsoft/msphpsql -[issues]: https://github.com/Azure/msphpsql/issues +[issues]: https://github.com/Microsoft/msphpsql/issues [phpweb]: http://php.net @@ -534,8 +159,6 @@ This project has adopted the Microsoft Open Source Code of Conduct. For more inf [odbcLinux]: https://msdn.microsoft.com/library/hh568454(v=sql.110).aspx -[phpazure]: https://azure.microsoft.com/documentation/articles/sql-database-develop-php-simple-windows/ - [PHPMan]: http://php.net/manual/install.unix.php [LinuxDM]: https://msdn.microsoft.com/library/hh568449(v=sql.110).aspx @@ -544,6 +167,4 @@ This project has adopted the Microsoft Open Source Code of Conduct. For more inf [apr_source]: http://apr.apache.org/ -[httpdconf]: http://php.net/manual/en/install.unix.apache2.php - -[ODBCinstallers]: https://blogs.msdn.microsoft.com/sqlnativeclient/2016/09/06/preview-release-of-the-sql-server-cc-odbc-driver-13-0-0-for-linux +[httpdconf]: http://php.net/manual/en/install.unix.apache2.php \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index e57815bb..d7f817d6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -18,6 +18,15 @@ environment: PHP_DEPSVER: 7.0 PHP_SDK: c:\projects\php matrix: + - BUILD_PLATFORM: x64 + TEST_PHP_SQL_SERVER: (local)\SQL2012SP1 + SQL_INSTANCE: SQL2012SP1 + 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)\SQL2016 SQL_INSTANCE: SQL2016 @@ -28,15 +37,6 @@ environment: PHP_INSTALL_DIR: c:\projects\php\x86\bin PHP_ZTS: --disable-zts platform: x86 - - BUILD_PLATFORM: x64 - TEST_PHP_SQL_SERVER: (local)\SQL2012SP1 - SQL_INSTANCE: SQL2012SP1 - 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 # 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) @@ -78,20 +78,24 @@ install: Set-Service SQLBrowser -StartupType Manual; Start-Service SQLBrowser; - - echo Set PHP version... - - appveyor DownloadFile http://windows.php.net/downloads/releases/sha1sum.txt - # determine latest PHP versions - - ps: >- + - echo Downloading prerequisites + - ps: | + $client = New-Object Net.WebClient; + $client.Headers.Add("user-agent", "appveyor-ci-build1"); + $client.DownloadFile("http://windows.php.net/downloads/php-sdk/php-sdk-binary-tools-20110915.zip", "c:\projects\php-sdk-binary-tools-20110915.zip"); + - ps: | + $client = New-Object Net.WebClient; + $client.Headers.Add("user-agent", "appveyor-ci-build2"); + $client.DownloadFile("http://windows.php.net/downloads/releases/sha1sum.txt", "c:\projects\sha1sum.txt"); If ($env:PHP_MINOR_VER -Match "latest") { - $env:PHP_VERSION=type sha1sum.txt | where { $_ -match "php-($env:PHP_MAJOR_VER\.\d+)-src" } | foreach { $matches[1] } ; + $env:PHP_VERSION=type c:\projects\sha1sum.txt | where { $_ -match "php-($env:PHP_MAJOR_VER\.\d+)-src" } | foreach { $matches[1] } ; } Else { $env:PHP_VERSION=$env:PHP_MAJOR_VER + '.' + $env:PHP_MINOR_VER; } - - echo Downloading PHP-SDK - - appveyor DownloadFile http://windows.php.net/downloads/php-sdk/php-sdk-binary-tools-20110915.zip - - move php-sdk-binary-tools-20110915.zip .. - - echo Downloading PHP source code [%PHP_VERSION%] - - ps: (new-object net.webclient).DownloadFile('http://windows.php.net/downloads/releases/php-' + ${env:PHP_VERSION} + '-src.zip', ${env:APPVEYOR_BUILD_FOLDER} + '\..\php.zip') + - ps: | + $client = New-Object Net.WebClient; + $client.Headers.Add("user-agent", "appveyor-ci-build3"); + $client.DownloadFile("http://windows.php.net/downloads/releases/php-" + ${env:PHP_VERSION} + "-src.zip", ${env:APPVEYOR_BUILD_FOLDER} + "\..\php.zip"); - echo Downloading MSODBCSQL 13.1 # AppVeyor build works are x64 VMs and 32-bit ODBC driver cannot be installed on it - ps: (new-object net.webclient).DownloadFile('https://download.microsoft.com/download/D/5/E/D5EEF288-A277-45C8-855B-8E2CB7E25B96/x64/msodbcsql.msi', 'c:\projects\msodbcsql.msi') @@ -99,10 +103,9 @@ install: - echo Checking the version of MSODBCSQL - reg query "HKLM\SOFTWARE\ODBC\odbcinst.ini\ODBC Driver 13 for SQL Server" - dir C:\Windows\System32\msodbcsql13.dll - - cd .. - - cd - - 7z x -y php-sdk-binary-tools-20110915.zip -o%PHP_SDK% - - 7z x -y php.zip -o%PHP_SDK_DIR% + - cd c:\projects + - 7z x -y .\php-sdk-binary-tools-20110915.zip -o%PHP_SDK% + - 7z x -y .\php.zip -o%PHP_SDK_DIR% - echo update SQL connection string - ps: (Get-Content ${env:APPVEYOR_BUILD_FOLDER}\test\functional\pdo_sqlsrv\MsSetup.inc) | ForEach-Object { $_ -replace "TARGET_SERVER", ${env:TEST_PHP_SQL_SERVER} -replace "TARGET_DATABASE", ${env:PDOSQLSRV_DBNAME} -replace "TARGET_USERNAME", ${env:TEST_PHP_SQL_UID} -replace "TARGET_PASSWORD", ${env:TEST_PHP_SQL_PWD} } | Set-Content ${env:APPVEYOR_BUILD_FOLDER}\test\functional\pdo_sqlsrv\MsSetup.inc - ps: Get-Content ${env:APPVEYOR_BUILD_FOLDER}\test\functional\pdo_sqlsrv\MsSetup.inc @@ -150,12 +153,6 @@ test_script: - python %APPVEYOR_BUILD_FOLDER%\test\functional\setup\setup_dbs.py -dbname %SQLSRV_DBNAME% - Echo setup test database for PDO_SQLSRV tests - %PDOSQLSRV_DBNAME% - python %APPVEYOR_BUILD_FOLDER%\test\functional\setup\setup_dbs.py -dbname %PDOSQLSRV_DBNAME% - #- copy %APPVEYOR_BUILD_FOLDER%\source\shared\msodbcsql.h %APPVEYOR_BUILD_FOLDER%\test\functional\setup\ - #- python %APPVEYOR_BUILD_FOLDER%\test\functional\setup\build_ksp.py - #- copy %APPVEYOR_BUILD_FOLDER%\test\functional\setup\*.dll %APPVEYOR_BUILD_FOLDER%\test\functional\sqlsrv\ - #- copy %APPVEYOR_BUILD_FOLDER%\test\functional\setup\*.dll %APPVEYOR_BUILD_FOLDER%\test\functional\pdo_sqlsrv\ - #- python %APPVEYOR_BUILD_FOLDER%\test\functional\setup\run_ksp.py -server %TEST_PHP_SQL_SERVER% -dbname %SQLSRV_DBNAME% -uid %TEST_PHP_SQL_UID% -pwd %TEST_PHP_SQL_PWD% - #- python %APPVEYOR_BUILD_FOLDER%\test\functional\setup\run_ksp.py -server %TEST_PHP_SQL_SERVER% -dbname %PDOSQLSRV_DBNAME% -uid %TEST_PHP_SQL_UID% -pwd %TEST_PHP_SQL_PWD% - ps: >- If ($env:SQL_INSTANCE -Match "SQL2016") { Write-Host "Running phpt tests via OpenCppCoverage..." diff --git a/buildscripts/README.md b/buildscripts/README.md index 8f4a98ab..46c190e6 100644 --- a/buildscripts/README.md +++ b/buildscripts/README.md @@ -14,7 +14,7 @@ To use the sample build scripts `builddrivers.py` and `buildtools.py`, install P You must first be able to build PHP 7.* without including our PHP extensions. For help with building PHP 7.0* or PHP 7.1* in Windows, see the [official PHP website](https://wiki.php.net/internals/windows/stepbystepbuild). For PHP 7.2 or above, visit [PHP SDK page](https://github.com/OSTC/php-sdk-binary-tools) for new instructions. -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 beta 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.1 using Visual C++ 2017 v15.5. ### Manually building from source @@ -57,7 +57,7 @@ PHP recommends to unzip the PHP SDK into the shortest possible path, preferrably 3. Interactive mode: * Type `py builddrivers.py` to start the interactive mode. Use lower cases to answer the following questions: - * PHP Version (e.g. `7.1.7` or `7.2.0beta2`) + * PHP Version (e.g. `7.1.7` or `7.2.1`) * 64-bit? * Thread safe? * Driver? @@ -68,8 +68,8 @@ PHP recommends to unzip the PHP SDK into the shortest possible path, preferrably 4. Use Command-line arguments * Type `py builddrivers.py -h` to get a list of options and their descriptions * For example, - * `py builddrivers.py --PHPVER=7.0.22 --ARCH=x64 --THREAD=nts --DRIVER=sqlsrv --SOURCE` - * `py builddrivers.py --PHPVER=7.1.8 --ARCH=x86 --THREAD=ts --DEBUG` + * `py builddrivers.py --PHPVER=7.2.1 --ARCH=x64 --THREAD=nts --DRIVER=sqlsrv --SOURCE=C:\local\source` + * `py builddrivers.py --PHPVER=7.1.13 --ARCH=x86 --THREAD=ts --DEBUG` 5. Based on the given configuration, if the script detects the presence of the PHP source directory, you can choose whether to rebuild, clean or superclean: * `rebuild` to build again using the same configuration (32 bit, thread safe, etc.) diff --git a/buildscripts/builddrivers.py b/buildscripts/builddrivers.py index f4e14e34..680f602b 100644 --- a/buildscripts/builddrivers.py +++ b/buildscripts/builddrivers.py @@ -33,7 +33,6 @@ class BuildDriver(object): util # BuildUtil object whose constructor takes phpver, driver, arch, thread, debug repo # GitHub repository branch # GitHub repository branch - download_source # download source from GitHub or not dest_path # alternative destination for the drivers (None for development builds) rebuild # a boolean flag - whether the user is rebuilding make_clean # a boolean flag - whether make clean is necessary @@ -41,16 +40,15 @@ class BuildDriver(object): testing # whether the user has turned on testing mode """ - def __init__(self, phpver, driver, arch, thread, debug, repo, branch, download, path, testing): + def __init__(self, phpver, driver, arch, thread, debug, repo, branch, source, path, testing): self.util = BuildUtil(phpver, driver, arch, thread, debug) self.repo = repo self.branch = branch - self.download_source = download + self.source_path = source self.dest_path = path self.testing = testing self.rebuild = False self.make_clean = False - self.source_path = None # None initially but will be set later if not downloading from GitHub def show_config(self): print() @@ -58,6 +56,7 @@ class BuildDriver(object): print('Arch: ', self.util.arch) print('Thread: ', self.util.thread) print('Driver: ', self.util.driver) + print('Source: ', self.source_path) print('Debug enabled: ', self.util.debug_enabled) print() @@ -91,6 +90,28 @@ class BuildDriver(object): os.chdir(work_dir) # change back to the working directory + def get_local_source(self, source_path): + """This assumes interactive mode (not testing) and takes care of getting + the user's input to the path of the local source files for the drivers + """ + while True: + if source_path is None: + source = input('Enter the full path to the source folder: ') + else: + source = input("Hit ENTER to use '" + source_path + "' or provide another path to the source folder: ") + if len(source) == 0: + source = source_path + + valid = True + if os.path.exists(source) and os.path.exists(os.path.join(source, 'shared')): + # Checking the existence of 'shared' folder only, assuming + # sqlsrv and/or pdo_sqlsrv are also present if it exists + self.source_path = source + break + + print("The path provided is invalid. Please re-enter.") + return source + def build_extensions(self, root_dir, logfile): """This takes care of getting the drivers' source files, building the drivers. If dest_path is defined, the binaries will be copied to the designated destinations. @@ -102,28 +123,15 @@ class BuildDriver(object): """ work_dir = os.path.dirname(os.path.realpath(__file__)) - if self.download_source: + if self.source_path is None: # This will download from the specified branch on GitHub repo and copy the source self.util.download_msphpsql_source(repo, branch) else: - # This case only happens when building for development - while True: - if self.source_path is None: - source = input('Enter the full path to the Source folder: ') - else: - source = input("Hit ENTER to reuse '" + self.source_path + "' or provide another path to the Source folder: ") - if len(source) == 0: - source = self.source_path - - valid = True - if os.path.exists(source) and os.path.exists(os.path.join(source, 'shared')): - # Checking the existence of 'shared' folder only, assuming - # sqlsrv and/or pdo_sqlsrv are also present if it exists - self.source_path = source - break - - print("The path provided is invalid. Please re-enter.") - + source = self.source_path + # Do not prompt user for input if it's in a testing mode + if not self.testing: + source = self.get_local_source(self.source_path) + print('Copying source files from', source) os.system('ROBOCOPY ' + source + '\shared ' + work_dir + '\Source\shared /xx /xo ') @@ -169,7 +177,10 @@ class BuildDriver(object): quit = False while not quit: - if not self.rebuild and not self.testing: + if self.testing: + self.make_clean = True + self.util.remove_old_builds(work_dir) + elif not self.rebuild: self.clean_or_remove(root_dir, work_dir) logfile = self.util.get_logfile_name() @@ -223,7 +234,7 @@ if __name__ == '__main__': parser.add_argument('--DEBUG', action='store_true', help="enable debug mode (default: False)") parser.add_argument('--REPO', default='Microsoft', help="GitHub repository (default: Microsoft)") parser.add_argument('--BRANCH', default='dev', help="GitHub repository branch (default: dev)") - parser.add_argument('--SOURCE', action='store_true', help="get source from a local path (default: False)") + parser.add_argument('--SOURCE', default=None, help="a local path to source file (default: None)") parser.add_argument('--TESTING', action='store_true', help="turns on testing mode (default: False)") parser.add_argument('--DESTPATH', default=None, help="an alternative destination for the drivers (default: None)") @@ -236,7 +247,7 @@ if __name__ == '__main__': debug = args.DEBUG repo = args.REPO branch = args.BRANCH - download = args.SOURCE is False + source = args.SOURCE path = args.DESTPATH testing = args.TESTING @@ -259,9 +270,7 @@ if __name__ == '__main__': debug_mode = input("Debug enabled? [y/n]: ") answer = input("Download source from a GitHub repo? [y/n]: ") - download = False if answer == 'yes' or answer == 'y' or answer == '': - download = True repo = input("Name of the repo (hit enter for 'Microsoft'): ") branch = input("Name of the branch (hit enter for 'dev'): ") if repo == '': @@ -282,7 +291,7 @@ if __name__ == '__main__': debug, repo, branch, - download, + source, path, testing) builder.build() diff --git a/buildscripts/buildtools.py b/buildscripts/buildtools.py index 2176b94e..50b2abb4 100644 --- a/buildscripts/buildtools.py +++ b/buildscripts/buildtools.py @@ -246,14 +246,13 @@ class BuildUtil(object): driver_dir = os.path.join(source_dir, driver) if self.debug_enabled: - # Remove the optimization flag in the config file for this driver - # because '/O2' option is incompatible with Debug mode - print('Removing optimization flag for', driver) + # Adding linker flags for creating more debugging information in the binaries + print('Adding linker flags for', driver) config_file = os.path.join(driver_dir, 'config.w32') if driver == 'sqlsrv': - self.update_file_content(config_file, 'ADD_FLAG( "CFLAGS_SQLSRV", "/O2" );', '') + self.update_file_content(config_file, 'ADD_FLAG( "LDFLAGS_SQLSRV", "/NXCOMPAT /DYNAMICBASE /debug /guard:cf" );', 'ADD_FLAG( "LDFLAGS_SQLSRV", "/NXCOMPAT /DYNAMICBASE /debug /guard:cf /debugtype:cv,fixup" );') elif driver == 'pdo_sqlsrv': - self.update_file_content(config_file, 'ADD_FLAG( "CFLAGS_PDO_SQLSRV", "/O2" );', '') + self.update_file_content(config_file, 'ADD_FLAG( "LDFLAGS_PDO_SQLSRV", "/NXCOMPAT /DYNAMICBASE /debug /guard:cf" );', 'ADD_FLAG( "LDFLAGS_PDO_SQLSRV", "/NXCOMPAT /DYNAMICBASE /debug /guard:cf /debugtype:cv,fixup" );') # Update Template.rc template_file = os.path.join(driver_dir, 'template.rc') diff --git a/source/pdo_sqlsrv/config.m4 b/source/pdo_sqlsrv/config.m4 index dd5cd012..46e22960 100644 --- a/source/pdo_sqlsrv/config.m4 +++ b/source/pdo_sqlsrv/config.m4 @@ -1,74 +1,78 @@ -PHP_ARG_WITH(pdo_sqlsrv, for pdo_sqlsrv support, -[ --with-pdo_sqlsrv Include pdo_sqlsrv support]) - -if test "$PHP_PDO_SQLSRV" != "no"; then - if test "$PHP_PDO" = "no" && test "$ext_shared" = "no"; then - AC_MSG_ERROR([PDO is not enabled! Add --enable-pdo to your configure line.]) - fi - - ifdef([PHP_CHECK_PDO_INCLUDES], - [ - PHP_CHECK_PDO_INCLUDES - ],[ - AC_MSG_CHECKING([for PDO includes]) - if test -f $abs_srcdir/include/php/ext/pdo/php_pdo_driver.h; then - pdo_cv_inc_path=$abs_srcdir/ext - elif test -f $abs_srcdir/ext/pdo/php_pdo_driver.h; then - pdo_cv_inc_path=$abs_srcdir/ext - elif test -f $phpincludedir/ext/pdo/php_pdo_driver.h; then - pdo_cv_inc_path=$phpincludedir/ext - else - AC_MSG_ERROR([Cannot find php_pdo_driver.h.]) - fi - AC_MSG_RESULT($pdo_cv_inc_path) - ]) - - pdo_sqlsrv_src_class="\ - pdo_dbh.cpp \ - pdo_parser.cpp \ - pdo_util.cpp \ - pdo_init.cpp \ - pdo_stmt.cpp \ - " - - shared_src_class="\ - shared/core_conn.cpp \ - shared/core_results.cpp \ - shared/core_stream.cpp \ - shared/core_init.cpp \ - shared/core_stmt.cpp \ - shared/core_util.cpp \ - shared/FormattedPrint.cpp \ - shared/localizationimpl.cpp \ - shared/StringFunctions.cpp \ - " - AC_MSG_CHECKING([for PDO_SQLSRV headers]) - if test -f $srcdir/ext/pdo_sqlsrv/shared/core_sqlsrv.h; then - pdo_sqlsrv_inc_path=$srcdir/ext/pdo_sqlsrv/shared/ - elif test -f $srcdir/shared/core_sqlsrv.h; then - pdo_sqlsrv_inc_path=$srcdir/shared/ - else - AC_MSG_ERROR([Cannot find PDO_SQLSRV headers]) - fi - AC_MSG_RESULT($pdo_sqlsrv_inc_path) - - HOST_OS_ARCH=`uname` - if test "${HOST_OS_ARCH}" = "Darwin"; then - MACOSX_DEPLOYMENT_TARGET=`sw_vers -productVersion` - fi - - CXXFLAGS="$CXXFLAGS -std=c++11" - CXXFLAGS="$CXXFLAGS -D_FORTIFY_SOURCE=2 -O2" - CXXFLAGS="$CXXFLAGS -fstack-protector" - PHP_REQUIRE_CXX() - PHP_ADD_LIBRARY(stdc++, 1, PDO_SQLSRV_SHARED_LIBADD) - PHP_ADD_LIBRARY(odbc, 1, PDO_SQLSRV_SHARED_LIBADD) - PHP_ADD_LIBRARY(odbcinst, 1, PDO_SQLSRV_SHARED_LIBADD) - AC_DEFINE(HAVE_PDO_SQLSRV, 1, [ ]) - PHP_ADD_INCLUDE([$pdo_sqlsrv_inc_path]) - PHP_NEW_EXTENSION(pdo_sqlsrv, $pdo_sqlsrv_src_class $shared_src_class, $ext_shared,,-I$pdo_cv_inc_path -std=c++11) - PHP_SUBST(PDO_SQLSRV_SHARED_LIBADD) - PHP_ADD_EXTENSION_DEP(pdo_sqlsrv, pdo) - PHP_ADD_BUILD_DIR([$ext_builddir/shared], 1) -fi - +PHP_ARG_WITH(pdo_sqlsrv, for pdo_sqlsrv support, +[ --with-pdo_sqlsrv Include pdo_sqlsrv support]) + +if test "$PHP_PDO_SQLSRV" != "no"; then + if test "$PHP_PDO" = "no" && test "$ext_shared" = "no"; then + AC_MSG_ERROR([PDO is not enabled! Add --enable-pdo to your configure line.]) + fi + + ifdef([PHP_CHECK_PDO_INCLUDES], + [ + PHP_CHECK_PDO_INCLUDES + ],[ + AC_MSG_CHECKING([for PDO includes]) + if test -f $abs_srcdir/include/php/ext/pdo/php_pdo_driver.h; then + pdo_cv_inc_path=$abs_srcdir/ext + elif test -f $abs_srcdir/ext/pdo/php_pdo_driver.h; then + pdo_cv_inc_path=$abs_srcdir/ext + elif test -f $phpincludedir/ext/pdo/php_pdo_driver.h; then + pdo_cv_inc_path=$phpincludedir/ext + else + AC_MSG_ERROR([Cannot find php_pdo_driver.h.]) + fi + AC_MSG_RESULT($pdo_cv_inc_path) + ]) + + pdo_sqlsrv_src_class="\ + pdo_dbh.cpp \ + pdo_parser.cpp \ + pdo_util.cpp \ + pdo_init.cpp \ + pdo_stmt.cpp \ + " + + shared_src_class="\ + shared/core_conn.cpp \ + shared/core_results.cpp \ + shared/core_stream.cpp \ + shared/core_init.cpp \ + shared/core_stmt.cpp \ + shared/core_util.cpp \ + shared/FormattedPrint.cpp \ + shared/localizationimpl.cpp \ + shared/StringFunctions.cpp \ + " + AC_MSG_CHECKING([for PDO_SQLSRV headers]) + if test -f $srcdir/ext/pdo_sqlsrv/shared/core_sqlsrv.h; then + pdo_sqlsrv_inc_path=$srcdir/ext/pdo_sqlsrv/shared/ + elif test -f $srcdir/shared/core_sqlsrv.h; then + pdo_sqlsrv_inc_path=$srcdir/shared/ + else + AC_MSG_ERROR([Cannot find PDO_SQLSRV headers]) + fi + AC_MSG_RESULT($pdo_sqlsrv_inc_path) + + CXXFLAGS="$CXXFLAGS -std=c++11" + CXXFLAGS="$CXXFLAGS -D_FORTIFY_SOURCE=2 -O2" + CXXFLAGS="$CXXFLAGS -fstack-protector" + + HOST_OS_ARCH=`uname` + if test "${HOST_OS_ARCH}" = "Darwin"; then + PDO_SQLSRV_SHARED_LIBADD="$PDO_SQLSRV_SHARED_LIBADD -Wl,-bind_at_load" + MACOSX_DEPLOYMENT_TARGET=`sw_vers -productVersion` + else + PDO_SQLSRV_SHARED_LIBADD="$PDO_SQLSRV_SHARED_LIBADD -Wl,-z,now" + fi + + PHP_REQUIRE_CXX() + PHP_ADD_LIBRARY(stdc++, 1, PDO_SQLSRV_SHARED_LIBADD) + PHP_ADD_LIBRARY(odbc, 1, PDO_SQLSRV_SHARED_LIBADD) + PHP_ADD_LIBRARY(odbcinst, 1, PDO_SQLSRV_SHARED_LIBADD) + AC_DEFINE(HAVE_PDO_SQLSRV, 1, [ ]) + PHP_ADD_INCLUDE([$pdo_sqlsrv_inc_path]) + PHP_NEW_EXTENSION(pdo_sqlsrv, $pdo_sqlsrv_src_class $shared_src_class, $ext_shared,,-I$pdo_cv_inc_path -std=c++11) + PHP_SUBST(PDO_SQLSRV_SHARED_LIBADD) + PHP_ADD_EXTENSION_DEP(pdo_sqlsrv, pdo) + PHP_ADD_BUILD_DIR([$ext_builddir/shared], 1) +fi + diff --git a/source/pdo_sqlsrv/config.w32 b/source/pdo_sqlsrv/config.w32 index b8c72c02..bd1eaf04 100644 --- a/source/pdo_sqlsrv/config.w32 +++ b/source/pdo_sqlsrv/config.w32 @@ -30,11 +30,11 @@ if( PHP_PDO_SQLSRV != "no" ) { CHECK_HEADER_ADD_INCLUDE("sql.h", "CFLAGS_PDO_SQLSRV_ODBC"); CHECK_HEADER_ADD_INCLUDE("sqlext.h", "CFLAGS_PDO_SQLSRV_ODBC"); ADD_SOURCES( configure_module_dirname + "\\shared", shared_src_class, "pdo_sqlsrv" ); - ADD_FLAG( "LDFLAGS_PDO_SQLSRV", "/NXCOMPAT /DYNAMICBASE /debug" ); + ADD_FLAG( "LDFLAGS_PDO_SQLSRV", "/NXCOMPAT /DYNAMICBASE /debug /guard:cf" ); ADD_FLAG( "CFLAGS_PDO_SQLSRV", "/EHsc" ); ADD_FLAG( "CFLAGS_PDO_SQLSRV", "/GS" ); ADD_FLAG( "CFLAGS_PDO_SQLSRV", "/Zi" ); - ADD_FLAG( "CFLAGS_PDO_SQLSRV", "/O2" ); + if (PHP_DEBUG != "yes") ADD_FLAG( "CFLAGS_PDO_SQLSRV", "/guard:cf /O2" ); ADD_FLAG( "CFLAGS_PDO_SQLSRV", "/D ZEND_WIN32_FORCE_INLINE" ); ADD_EXTENSION_DEP('pdo_sqlsrv', 'pdo'); EXTENSION("pdo_sqlsrv", pdo_sqlsrv_src_class, PHP_PDO_SQLSRV_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); diff --git a/source/pdo_sqlsrv/pdo_dbh.cpp b/source/pdo_sqlsrv/pdo_dbh.cpp index 66412bbc..58788587 100644 --- a/source/pdo_sqlsrv/pdo_dbh.cpp +++ b/source/pdo_sqlsrv/pdo_dbh.cpp @@ -42,13 +42,9 @@ const char ApplicationIntent[] = "ApplicationIntent"; const char AttachDBFileName[] = "AttachDbFileName"; const char ConnectionPooling[] = "ConnectionPooling"; const char Authentication[] = "Authentication"; -const char ColumnEncryption[] = "ColumnEncryption"; const char Driver[] = "Driver"; -const char CEKeystoreProvider[] = "CEKeystoreProvider"; -const char CEKeystoreName[] = "CEKeystoreName"; -const char CEKeystoreEncryptKey[] = "CEKeystoreEncryptKey"; - #ifdef _WIN32 +const char ColumnEncryption[] = "ColumnEncryption"; const char ConnectRetryCount[] = "ConnectRetryCount"; const char ConnectRetryInterval[] = "ConnectRetryInterval"; #endif // _WIN32 @@ -226,15 +222,6 @@ const connection_option PDO_CONN_OPTS[] = { CONN_ATTR_BOOL, conn_null_func::func }, - { - PDOConnOptionNames::ColumnEncryption, - sizeof(PDOConnOptionNames::ColumnEncryption), - SQLSRV_CONN_OPTION_COLUMNENCRYPTION, - ODBCConnOptions::ColumnEncryption, - sizeof(ODBCConnOptions::ColumnEncryption), - CONN_ATTR_STRING, - column_encryption_set_func::func - }, { PDOConnOptionNames::Driver, sizeof(PDOConnOptionNames::Driver), @@ -244,34 +231,16 @@ const connection_option PDO_CONN_OPTS[] = { CONN_ATTR_STRING, driver_set_func::func }, - { - PDOConnOptionNames::CEKeystoreProvider, - sizeof(PDOConnOptionNames::CEKeystoreProvider), - SQLSRV_CONN_OPTION_CEKEYSTORE_PROVIDER, - ODBCConnOptions::CEKeystoreProvider, - sizeof(ODBCConnOptions::CEKeystoreProvider), - CONN_ATTR_STRING, - ce_ksp_provider_set_func::func - }, - { - PDOConnOptionNames::CEKeystoreName, - sizeof(PDOConnOptionNames::CEKeystoreName), - SQLSRV_CONN_OPTION_CEKEYSTORE_NAME, - ODBCConnOptions::CEKeystoreName, - sizeof(ODBCConnOptions::CEKeystoreName), - CONN_ATTR_STRING, - ce_ksp_provider_set_func::func - }, - { - PDOConnOptionNames::CEKeystoreEncryptKey, - sizeof(PDOConnOptionNames::CEKeystoreEncryptKey), - SQLSRV_CONN_OPTION_CEKEYSTORE_ENCRYPT_KEY, - ODBCConnOptions::CEKeystoreEncryptKey, - sizeof(ODBCConnOptions::CEKeystoreEncryptKey), - CONN_ATTR_STRING, - ce_ksp_provider_set_func::func - }, #ifdef _WIN32 + { + PDOConnOptionNames::ColumnEncryption, + sizeof(PDOConnOptionNames::ColumnEncryption), + SQLSRV_CONN_OPTION_COLUMNENCRYPTION, + ODBCConnOptions::ColumnEncryption, + sizeof(ODBCConnOptions::ColumnEncryption), + CONN_ATTR_STRING, + column_encryption_set_func::func + }, { PDOConnOptionNames::ConnectRetryCount, sizeof( PDOConnOptionNames::ConnectRetryCount ), diff --git a/source/pdo_sqlsrv/pdo_util.cpp b/source/pdo_sqlsrv/pdo_util.cpp index e0d2302c..695b20e6 100644 --- a/source/pdo_sqlsrv/pdo_util.cpp +++ b/source/pdo_sqlsrv/pdo_util.cpp @@ -59,7 +59,7 @@ pdo_error PDO_ERRORS[] = { { IMSSP, (SQLCHAR*) "This extension requires the Microsoft ODBC Driver for SQL Server to " "communicate with SQL Server. Access the following URL to download the ODBC Driver for SQL Server " "for %1!s!: " - "http://go.microsoft.com/fwlink/?LinkId=163712", -1, true } + "https://go.microsoft.com/fwlink/?LinkId=163712", -1, true } }, { SQLSRV_ERROR_ZEND_HASH, @@ -381,22 +381,6 @@ pdo_error PDO_ERRORS[] = { PDO_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION, { IMSSP, (SQLCHAR*) "Invalid option for the Authentication keyword. Only SqlPassword or ActiveDirectoryPassword is supported.", -73, false } }, - { - SQLSRV_ERROR_KEYSTORE_NAME_MISSING, - { IMSSP, (SQLCHAR*) "The name of the custom keystore provider is missing.", -74, false} - }, - { - SQLSRV_ERROR_KEYSTORE_PATH_MISSING, - { IMSSP, (SQLCHAR*) "The path to the custom keystore provider is missing.", -75, false} - }, - { - SQLSRV_ERROR_KEYSTORE_KEY_MISSING, - { IMSSP, (SQLCHAR*) "The encryption key for the custom keystore provider is missing.", -76, false} - }, - { - SQLSRV_ERROR_KEYSTORE_INVALID_VALUE, - { IMSSP, (SQLCHAR*) "Invalid value for loading a custom keystore provider.", -77, false} - }, { SQLSRV_ERROR_CE_DRIVER_REQUIRED, { IMSSP, (SQLCHAR*) "The Always Encrypted feature requires Microsoft ODBC Driver 17 for SQL Server.", -78, false } diff --git a/source/shared/core_conn.cpp b/source/shared/core_conn.cpp index 6f9b0710..f72d4c36 100644 --- a/source/shared/core_conn.cpp +++ b/source/shared/core_conn.cpp @@ -50,7 +50,7 @@ const char* PROCESSOR_ARCH[] = { "x86", "x64", "ia64" }; // ODBC driver names. // the order of this list should match the order of DRIVER_VERSION enum -std::vector CONNECTION_STRING_DRIVER_NAME{ "Driver={ODBC Driver 13 for SQL Server};", "Driver={ODBC Driver 11 for SQL Server};", "Driver={ODBC Driver 17 for SQL Server};" }; +std::vector CONNECTION_STRING_DRIVER_NAME{ "Driver={ODBC Driver 17 for SQL Server};", "Driver={ODBC Driver 13 for SQL Server};", "Driver={ODBC Driver 11 for SQL Server};" }; // default options if only the server is specified const char CONNECTION_STRING_DEFAULT_OPTIONS[] = "Mars_Connection={Yes};"; @@ -71,7 +71,6 @@ const char* get_processor_arch( void ); void get_server_version( _Inout_ sqlsrv_conn* conn, _Outptr_result_buffer_(len) char** server_version, _Out_ SQLSMALLINT& len TSRMLS_DC ); connection_option const* get_connection_option( sqlsrv_conn* conn, _In_ const char* key, _In_ SQLULEN key_len TSRMLS_DC ); void common_conn_str_append_func( _In_z_ const char* odbc_name, _In_reads_(val_len) const char* val, _Inout_ size_t val_len, _Inout_ std::string& conn_str TSRMLS_DC ); -void load_configure_ksp( _Inout_ sqlsrv_conn* conn TSRMLS_DC ); } // core_sqlsrv_connect @@ -183,11 +182,11 @@ sqlsrv_conn* core_sqlsrv_connect( _In_ sqlsrv_context& henv_cp, _In_ sqlsrv_cont // https://docs.microsoft.com/en-us/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server#microsoft-odbc-driver-11-for-sql-server-on-linux DRIVER_VERSION odbc_version = ODBC_DRIVER_UNKNOWN; - if( core_search_odbc_driver_unix( ODBC_DRIVER_13 ) ) { - odbc_version = ODBC_DRIVER_13; - } - else if ( core_search_odbc_driver_unix( ODBC_DRIVER_17 ) ) { + if( core_search_odbc_driver_unix( ODBC_DRIVER_17 ) ) { odbc_version = ODBC_DRIVER_17; + } + else if ( core_search_odbc_driver_unix( ODBC_DRIVER_13 ) ) { + odbc_version = ODBC_DRIVER_13; } CHECK_CUSTOM_ERROR( odbc_version == ODBC_DRIVER_UNKNOWN, conn, SQLSRV_ERROR_DRIVER_NOT_INSTALLED, get_processor_arch() ) { @@ -246,8 +245,6 @@ sqlsrv_conn* core_sqlsrv_connect( _In_ sqlsrv_context& henv_cp, _In_ sqlsrv_cont throw core::CoreException(); } - load_configure_ksp( conn ); - // determine the version of the server we're connected to. The server version is left in the // connection upon return. // @@ -935,66 +932,6 @@ void determine_server_version( _Inout_ sqlsrv_conn* conn TSRMLS_DC ) conn->server_version = version_major; } -// Column Encryption feature: if a custom keystore provider is specified, -// load and configure it when column encryption is enabled, but this step has -// to be executed after the connection has been established -void load_configure_ksp( _Inout_ sqlsrv_conn* conn TSRMLS_DC ) -{ - // If column encryption is not enabled simply do nothing. Otherwise, check if a custom keystore provider - // is required for encryption or decryption. Note, in order to load and configure a custom keystore provider, - // all KSP fields in conn->ce_option must be defined. - if ( ! conn->ce_option.enabled || ! conn->ce_option.ksp_required ) - return; - - // Do something like the following sample - // use the KSP related fields in conn->ce_option - // CEKEYSTOREDATA is defined in msodbcsql.h - // https://docs.microsoft.com/en-us/sql/connect/odbc/custom-keystore-providers - - CHECK_CUSTOM_ERROR( conn->ce_option.ksp_name == NULL, conn, SQLSRV_ERROR_KEYSTORE_NAME_MISSING) { - throw core::CoreException(); - } - - CHECK_CUSTOM_ERROR( conn->ce_option.ksp_path == NULL, conn, SQLSRV_ERROR_KEYSTORE_PATH_MISSING) { - throw core::CoreException(); - } - - CHECK_CUSTOM_ERROR( conn->ce_option.key_size == 0, conn, SQLSRV_ERROR_KEYSTORE_KEY_MISSING) { - throw core::CoreException(); - } - - 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 = 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; - - ksp_data = reinterpret_cast( sqlsrv_malloc( sizeof( CEKEYSTOREDATA ) + key_size ) ); - - CEKEYSTOREDATA *pKsd = reinterpret_cast( ksp_data.get() ); - - pKsd->dataSize = key_size; - - // First, convert conn->ce_option.ksp_name to a WCHAR version - unsigned int wname_len = 0; - sqlsrv_malloc_auto_ptr wksp_name; - wksp_name = utf16_string_from_mbcs_string( SQLSRV_ENCODING_UTF8, ksp_name, name_len, &wname_len ); - - CHECK_CUSTOM_ERROR( wksp_name == 0, conn, SQLSRV_ERROR_CONNECT_STRING_ENCODING_TRANSLATE ) { - throw core::CoreException(); - } - - pKsd->name = (wchar_t *) wksp_name.get(); - - // Next, extract the character string from conn->ce_option.ksp_encrypt_key into encrypt_key - char* encrypt_key = Z_STRVAL_P( conn->ce_option.ksp_encrypt_key ); - memcpy_s( pKsd->data, key_size * sizeof( char ) , encrypt_key, key_size ); - - core::SQLSetConnectAttr( conn, SQL_COPT_SS_CEKEYSTOREPROVIDER, ksp_path, SQL_NTS ); - core::SQLSetConnectAttr( conn, SQL_COPT_SS_CEKEYSTOREDATA, reinterpret_cast( pKsd ), SQL_IS_POINTER ); -} - void common_conn_str_append_func( _In_z_ const char* odbc_name, _In_reads_(val_len) const char* val, _Inout_ size_t val_len, _Inout_ std::string& conn_str TSRMLS_DC ) { // wrap a connection option in a quote. It is presumed that any character that need to be escaped will @@ -1068,36 +1005,6 @@ void column_encryption_set_func::func( _In_ connection_option const* option, _In conn_str += ";"; } -void ce_ksp_provider_set_func::func( _In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str TSRMLS_DC ) -{ - SQLSRV_ASSERT( Z_TYPE_P( value ) == IS_STRING, "Wrong zval type for this keyword" ) - - size_t value_len = Z_STRLEN_P( value ); - - CHECK_CUSTOM_ERROR( value_len == 0, conn, SQLSRV_ERROR_KEYSTORE_INVALID_VALUE ) { - throw core::CoreException(); - } - - switch ( option->conn_option_key ) { - case SQLSRV_CONN_OPTION_CEKEYSTORE_PROVIDER: - conn->ce_option.ksp_path = value; - conn->ce_option.ksp_required = true; - break; - case SQLSRV_CONN_OPTION_CEKEYSTORE_NAME: - conn->ce_option.ksp_name = value; - conn->ce_option.ksp_required = true; - break; - case SQLSRV_CONN_OPTION_CEKEYSTORE_ENCRYPT_KEY: - conn->ce_option.ksp_encrypt_key = value; - conn->ce_option.key_size = value_len; - conn->ce_option.ksp_required = true; - break; - default: - SQLSRV_ASSERT(false, "ce_ksp_provider_set_func: Invalid KSP option!"); - break; - } -} - // helper function to evaluate whether a string value is true or false. // Values = ("true" or "1") are treated as true values. Everything else is treated as false. // Returns 1 for true and 0 for false. diff --git a/source/shared/core_results.cpp b/source/shared/core_results.cpp index 58632354..d5882f2c 100644 --- a/source/shared/core_results.cpp +++ b/source/shared/core_results.cpp @@ -83,7 +83,7 @@ bool get_bit( _In_ void* ptr, _In_ unsigned int bit ) // read in LOB field during buffered result creation SQLPOINTER read_lob_field( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, _In_ sqlsrv_buffered_result_set::meta_data& meta, - _In_ zend_long mem_used, _In_ size_t row_count TSRMLS_DC ); + _In_ zend_long mem_used TSRMLS_DC ); // dtor for each row in the cache void cache_row_dtor( _In_ zval* data ); @@ -687,7 +687,7 @@ sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( _Inout_ sqlsrv_stmt* stm out_buffer_length = &out_buffer_temp; SQLPOINTER* lob_addr = reinterpret_cast( &row[ meta[i].offset ] ); - *lob_addr = read_lob_field( stmt, i, meta[i], mem_used, row_count TSRMLS_CC ); + *lob_addr = read_lob_field( stmt, i, meta[i], mem_used TSRMLS_CC ); // a NULL pointer means NULL field if( *lob_addr == NULL ) { *out_buffer_length = SQL_NULL_DATA; @@ -1498,7 +1498,7 @@ void cache_row_dtor( _In_ zval* data ) } SQLPOINTER read_lob_field( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, _In_ sqlsrv_buffered_result_set::meta_data& meta, - _In_ zend_long mem_used, _In_ size_t row_count TSRMLS_DC ) + _In_ zend_long mem_used TSRMLS_DC ) { SQLSMALLINT extra = 0; SQLULEN* output_buffer_len = NULL; @@ -1563,19 +1563,7 @@ SQLPOINTER read_lob_field( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_in SQLSRV_ASSERT( SQL_SUCCEEDED( r ), "Unknown SQL error not triggered" ); - if ( stmt->conn->ce_option.enabled == true ) { - // cursor type SQLSRV_CURSOR_BUFFERED has to be FORWARD_ONLY - // thus has to close and reopen cursor to reset the cursor buffer - core::SQLCloseCursor(stmt); - core::SQLExecute(stmt); - // FETCH_NEXT until the cursor reaches the row that it was at - for (int i = 0; i <= row_count; i++) { - core::SQLFetchScroll(stmt, SQL_FETCH_NEXT, 0); - } - } - else { - already_read += to_read - already_read; - } + already_read += to_read - already_read; // if the type of the field returns the total to be read, we use that and preallocate the buffer if( last_field_len != SQL_NO_TOTAL ) { diff --git a/source/shared/core_sqlsrv.h b/source/shared/core_sqlsrv.h index 2e2cc371..d950b1ff 100644 --- a/source/shared/core_sqlsrv.h +++ b/source/shared/core_sqlsrv.h @@ -1043,10 +1043,10 @@ enum SERVER_VERSION { enum DRIVER_VERSION { ODBC_DRIVER_UNKNOWN = -1, FIRST = 0, - ODBC_DRIVER_13 = FIRST, - ODBC_DRIVER_11 = 1, - ODBC_DRIVER_17 = 2, - LAST = ODBC_DRIVER_17 + ODBC_DRIVER_17 = FIRST, + ODBC_DRIVER_13 = 1, + ODBC_DRIVER_11 = 2, + LAST = ODBC_DRIVER_11 }; // forward decl @@ -1056,13 +1056,8 @@ struct stmt_option; // This holds the various details of column encryption. struct col_encryption_option { bool enabled; // column encryption enabled, false by default - zval_auto_ptr ksp_name; // keystore provider name - zval_auto_ptr ksp_path; // keystore provider path to the dynamically linked libary (either a *.dll or *.so) - zval_auto_ptr ksp_encrypt_key; // the encryption key used to configure the keystore provider - size_t key_size; // the length of ksp_encrypt_key without the NULL terminator - bool ksp_required; // a keystore provider is required to enable column encryption, false by default - col_encryption_option() : enabled( false ), key_size ( 0 ), ksp_required( false ) + col_encryption_option() : enabled( false ) { } }; @@ -1109,14 +1104,11 @@ const char APP[] = "APP"; const char ApplicationIntent[] = "ApplicationIntent"; const char AttachDBFileName[] = "AttachDbFileName"; const char Authentication[] = "Authentication"; -const char ColumnEncryption[] = "ColumnEncryption"; const char Driver[] = "Driver"; -const char CEKeystoreProvider[] = "CEKeystoreProvider"; -const char CEKeystoreName[] = "CEKeystoreName"; -const char CEKeystoreEncryptKey[] = "CEKeystoreEncryptKey"; const char CharacterSet[] = "CharacterSet"; const char ConnectionPooling[] = "ConnectionPooling"; #ifdef _WIN32 +const char ColumnEncryption[] = "ColumnEncryption"; const char ConnectRetryCount[] = "ConnectRetryCount"; const char ConnectRetryInterval[] = "ConnectRetryInterval"; #endif // _WIN32 @@ -1380,8 +1372,6 @@ struct sqlsrv_stmt : public sqlsrv_context { bool past_fetch_end; // Core_sqlsrv_fetch sets this field when the statement goes beyond the last row sqlsrv_result_set* current_results; // Current result set SQLULEN cursor_type; // Type of cursor for the current result set - int fwd_row_index; // fwd_row_index is the current row index, SQL_CURSOR_FORWARD_ONLY - int curr_result_set; // the current active result set, 0 by default but will be incremented by core_sqlsrv_next_result bool has_rows; // Has_rows is set if there are actual rows in the row set bool fetch_called; // Used by core_sqlsrv_get_field to return an informative error if fetch not yet called int last_field_index; // last field retrieved by core_sqlsrv_get_field @@ -1711,10 +1701,6 @@ enum SQLSRV_ERROR_CODES { SQLSRV_ERROR_FIELD_INDEX_ERROR, SQLSRV_ERROR_BUFFER_LIMIT_EXCEEDED, SQLSRV_ERROR_INVALID_BUFFER_LIMIT, - SQLSRV_ERROR_KEYSTORE_NAME_MISSING, - SQLSRV_ERROR_KEYSTORE_PATH_MISSING, - SQLSRV_ERROR_KEYSTORE_KEY_MISSING, - SQLSRV_ERROR_KEYSTORE_INVALID_VALUE, SQLSRV_ERROR_OUTPUT_PARAM_TYPES_NOT_SUPPORTED, SQLSRV_ERROR_ENCRYPTED_STREAM_FETCH, diff --git a/source/shared/core_stmt.cpp b/source/shared/core_stmt.cpp index 947ce416..2deba3cc 100644 --- a/source/shared/core_stmt.cpp +++ b/source/shared/core_stmt.cpp @@ -64,7 +64,6 @@ struct col_cache { }; const int INITIAL_FIELD_STRING_LEN = 2048; // base allocation size when retrieving a string field -const int INITIAL_AE_FIELD_STRING_LEN = 8000; // base allocation size when retrieving a string field when AE is enabled // UTF-8 tags for byte length of characters, used by streams to make sure we don't clip a character in between reads const unsigned int UTF8_MIDBYTE_MASK = 0xc0; @@ -117,7 +116,6 @@ void resize_output_buffer_if_necessary( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval* _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 ); 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 void send_param_streams( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ); @@ -137,8 +135,6 @@ sqlsrv_stmt::sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error past_fetch_end( false ), current_results( NULL ), cursor_type( SQL_CURSOR_FORWARD_ONLY ), - fwd_row_index( -1 ), - curr_result_set( 0 ), has_rows( false ), fetch_called( false ), last_field_index( -1 ), @@ -221,7 +217,6 @@ void sqlsrv_stmt::free_param_data( TSRMLS_D ) void sqlsrv_stmt::new_result_set( TSRMLS_D ) { this->fetch_called = false; - this->fwd_row_index = -1; this->has_rows = false; this->past_next_result_end = false; this->past_fetch_end = false; @@ -717,9 +712,9 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ if ( stmt->conn->ce_option.enabled && sql_type == SQL_TYPE_TIMESTAMP ) { if( decimal_digits == 3 ) - core::SQLSetDescField( stmt, param_num + 1, SQL_CA_SS_SERVER_TYPE, (SQLPOINTER)SQL_SS_TYPE_DATETIME, 0 ); + core::SQLSetDescField( stmt, param_num + 1, SQL_CA_SS_SERVER_TYPE, (SQLPOINTER)SQL_SS_TYPE_DATETIME, SQL_IS_INTEGER ); else if (decimal_digits == 0) - core::SQLSetDescField( stmt, param_num + 1, SQL_CA_SS_SERVER_TYPE, (SQLPOINTER)SQL_SS_TYPE_SMALLDATETIME, 0 ); + core::SQLSetDescField( stmt, param_num + 1, SQL_CA_SS_SERVER_TYPE, (SQLPOINTER)SQL_SS_TYPE_SMALLDATETIME, SQL_IS_INTEGER ); } } catch( core::CoreException& e ){ @@ -858,10 +853,6 @@ bool core_sqlsrv_fetch( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orient // 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++; - } if( r == SQL_NO_DATA ) { // if this is a forward only cursor, mark that we've passed the end so future calls result in an error if( stmt->cursor_type == SQL_CURSOR_FORWARD_ONLY ) { @@ -1121,13 +1112,9 @@ void core_sqlsrv_next_result( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC, _In_ bool fin // mark we are past the end of all results stmt->past_next_result_end = true; - - // reset the current active result set - stmt->curr_result_set = 0; return; } - stmt->curr_result_set++; stmt->new_result_set( TSRMLS_C ); } catch( core::CoreException& e ) { @@ -1711,10 +1698,6 @@ void core_get_field_common( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_i // 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(); - } - php_stream* stream = NULL; sqlsrv_stream* ss = NULL; SQLLEN sql_type; @@ -2246,11 +2229,6 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind break; } - if( stmt->conn->ce_option.enabled ) { - // 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 ))))) { sql_field_type = cached->sql_type; @@ -2321,32 +2299,17 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind field_value_temp = static_cast( sqlsrv_realloc( field_value_temp, field_len_temp + extra + 1 )); - // reset AE stream fetch buffer - if ( reset_ae_stream_cursor( stmt )){ - // fetch the original column again with a bigger buffer length - r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp, field_len_temp + extra, - &dummy_field_len, false /*handle_warning*/ TSRMLS_CC ); - // if field_len_temp was bit enough to hold all data, dummy_field_len contain the actual amount retrieved, - // not SQL_NO_TOTAL - if ( dummy_field_len != SQL_NO_TOTAL ) - field_len_temp = dummy_field_len; - else - field_len_temp += initial_field_len; - } - else { - field_len_temp -= initial_field_len; + field_len_temp -= initial_field_len; - // Get the rest of the data. - r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp + initial_field_len, - field_len_temp + extra, &dummy_field_len, - false /*handle_warning*/ TSRMLS_CC ); - // the last packet will contain the actual amount retrieved, not SQL_NO_TOTAL - // so we calculate the actual length of the string with that. - if ( dummy_field_len != SQL_NO_TOTAL ) - field_len_temp += dummy_field_len; - else - field_len_temp += initial_field_len; - } + // Get the rest of the data. + r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp + initial_field_len, + field_len_temp + extra, &dummy_field_len, false /*handle_warning*/ TSRMLS_CC ); + // the last packet will contain the actual amount retrieved, not SQL_NO_TOTAL + // so we calculate the actual length of the string with that. + if ( dummy_field_len != SQL_NO_TOTAL ) + field_len_temp += dummy_field_len; + else + field_len_temp += initial_field_len; if( r == SQL_SUCCESS_WITH_INFO ) { core::SQLGetDiagField( stmt, 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len @@ -2360,22 +2323,13 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind // allocate field_len_temp (which is the field length retrieved from the first SQLGetData field_value_temp = static_cast( sqlsrv_realloc( field_value_temp, field_len_temp + extra + 1 )); - // reset AE stream fetch buffer - if ( reset_ae_stream_cursor( stmt ) ) { - // fetch the original column again with a bigger buffer length - r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp, field_len_temp + extra, - &dummy_field_len, false /*handle_warning*/ TSRMLS_CC ); - } - else { - // We have already recieved intial_field_len size data. - field_len_temp -= intial_field_len; + // We have already received intial_field_len size data. + field_len_temp -= intial_field_len; - // Get the rest of the data. - r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp + intial_field_len, - field_len_temp + extra, &dummy_field_len, - true /*handle_warning*/ TSRMLS_CC ); - field_len_temp += intial_field_len; - } + // Get the rest of the data. + r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp + intial_field_len, + field_len_temp + extra, &dummy_field_len, true /*handle_warning*/ TSRMLS_CC ); + field_len_temp += intial_field_len; if( dummy_field_len == SQL_NULL_DATA ) { field_value = NULL; @@ -2637,31 +2591,9 @@ void resize_output_buffer_if_necessary( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval* } } -bool reset_ae_stream_cursor( _Inout_ sqlsrv_stmt* stmt ) { - // only handled differently when AE is on because AE does not support streaming - // AE only works with SQL_CURSOR_FORWARD_ONLY for max types - if (stmt->conn->ce_option.enabled == true && stmt->current_results->odbc->cursor_type == SQL_CURSOR_FORWARD_ONLY) { - // close and reopen the cursor - core::SQLCloseCursor(stmt->current_results->odbc); - core::SQLExecute(stmt); - - // advance to the previous active result set - for (int j = 0; j < stmt->curr_result_set; j++) { - core::SQLMoreResults(stmt); - } - - // FETCH_NEXT until the cursor reaches the row that it was at - for (int i = 0; i <= stmt->fwd_row_index; i++) { - core::SQLFetchScroll(stmt->current_results->odbc, SQL_FETCH_NEXT, 0); - } - return true; - } - return false; -} - void adjustInputPrecision( _Inout_ zval* param_z, _In_ SQLSMALLINT decimal_digits ) { + // 38 is the maximum length of a stringified decimal number size_t maxDecimalPrecision = 38; - // maxDecimalStrLen is the maximum length of a stringified decimal number // 6 is derived from: 1 for '.'; 1 for sign of the number; 1 for 'e' or 'E' (scientific notation); // 1 for sign of scientific exponent; 2 for length of scientific exponent // if the length is greater than maxDecimalStrLen, do not change the string diff --git a/source/shared/version.h b/source/shared/version.h index c8c7b127..a06534ec 100644 --- a/source/shared/version.h +++ b/source/shared/version.h @@ -35,7 +35,7 @@ // for stable releases should be empty // "-RC" for release candidates // "-preview" for ETP -#define SEMVER_PRERELEASE "RC" +#define SEMVER_PRERELEASE // Semantic versioning build metadata, build meta data is not counted in precedence order. #define SEMVER_BUILDMETA @@ -50,7 +50,7 @@ // For preview release, we want the following: // #define VER_FILEVERSION_STR VER_APIVERSION_STR "-" SEMVER_PRERELEASE SEMVER_BUILDMETA // because pecl doesn't like dashes. However, if SEMVER_PRERELEASE is empty, the "-" must be removed -#define VER_FILEVERSION_STR VER_APIVERSION_STR "-" SEMVER_PRERELEASE SEMVER_BUILDMETA +#define VER_FILEVERSION_STR VER_APIVERSION_STR SEMVER_PRERELEASE SEMVER_BUILDMETA #define _FILEVERSION SQLVERSION_MAJOR,SQLVERSION_MINOR,SQLVERSION_PATCH,SQLVERSION_BUILD // PECL package version macros (can't have '-' or '+') diff --git a/source/sqlsrv/config.m4 b/source/sqlsrv/config.m4 index 00b815ba..e03ab0f4 100644 --- a/source/sqlsrv/config.m4 +++ b/source/sqlsrv/config.m4 @@ -29,14 +29,18 @@ if test "$PHP_SQLSRV" != "no"; then fi AC_MSG_RESULT($sqlsrv_inc_path) - HOST_OS_ARCH=`uname` - if test "${HOST_OS_ARCH}" = "Darwin"; then - MACOSX_DEPLOYMENT_TARGET=`sw_vers -productVersion` - fi - CXXFLAGS="$CXXFLAGS -std=c++11" CXXFLAGS="$CXXFLAGS -D_FORTIFY_SOURCE=2 -O2" CXXFLAGS="$CXXFLAGS -fstack-protector" + + HOST_OS_ARCH=`uname` + if test "${HOST_OS_ARCH}" = "Darwin"; then + SQLSRV_SHARED_LIBADD="$SQLSRV_SHARED_LIBADD -Wl,-bind_at_load" + MACOSX_DEPLOYMENT_TARGET=`sw_vers -productVersion` + else + SQLSRV_SHARED_LIBADD="$SQLSRV_SHARED_LIBADD -Wl,-z,now" + fi + PHP_REQUIRE_CXX() PHP_ADD_LIBRARY(stdc++, 1, SQLSRV_SHARED_LIBADD) PHP_ADD_LIBRARY(odbc, 1, SQLSRV_SHARED_LIBADD) diff --git a/source/sqlsrv/config.w32 b/source/sqlsrv/config.w32 index 727b17e7..77d8c4d1 100644 --- a/source/sqlsrv/config.w32 +++ b/source/sqlsrv/config.w32 @@ -30,12 +30,12 @@ if( PHP_SQLSRV != "no" ) { ADD_SOURCES( configure_module_dirname + "\\shared", shared_src_class, "sqlsrv" ); CHECK_HEADER_ADD_INCLUDE("sql.h", "CFLAGS_SQLSRV_ODBC"); CHECK_HEADER_ADD_INCLUDE("sqlext.h", "CFLAGS_SQLSRV_ODBC"); - ADD_FLAG( "LDFLAGS_SQLSRV", "/NXCOMPAT /DYNAMICBASE /debug" ); + ADD_FLAG( "LDFLAGS_SQLSRV", "/NXCOMPAT /DYNAMICBASE /debug /guard:cf" ); ADD_FLAG( "CFLAGS_SQLSRV", "/D ZEND_WIN32_FORCE_INLINE" ); ADD_FLAG( "CFLAGS_SQLSRV", "/EHsc" ); ADD_FLAG( "CFLAGS_SQLSRV", "/GS" ); ADD_FLAG( "CFLAGS_SQLSRV", "/Zi" ); - ADD_FLAG( "CFLAGS_SQLSRV", "/O2" ); + if (PHP_DEBUG != "yes") ADD_FLAG( "CFLAGS_SQLSRV", "/guard:cf /O2" ); EXTENSION("sqlsrv", sqlsrv_src_class , PHP_SQLSRV_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); } else { WARNING("sqlsrv not enabled; libraries and headers not found"); diff --git a/source/sqlsrv/conn.cpp b/source/sqlsrv/conn.cpp index f993fb2e..12ef5f3b 100644 --- a/source/sqlsrv/conn.cpp +++ b/source/sqlsrv/conn.cpp @@ -187,13 +187,9 @@ const char AttachDBFileName[] = "AttachDbFileName"; const char CharacterSet[] = "CharacterSet"; const char Authentication[] = "Authentication"; const char ConnectionPooling[] = "ConnectionPooling"; -const char ColumnEncryption[] = "ColumnEncryption"; const char Driver[] = "Driver"; -const char CEKeystoreProvider[] = "CEKeystoreProvider"; -const char CEKeystoreName[] = "CEKeystoreName"; -const char CEKeystoreEncryptKey[] = "CEKeystoreEncryptKey"; - #ifdef _WIN32 +const char ColumnEncryption[] = "ColumnEncryption"; const char ConnectRetryCount[] = "ConnectRetryCount"; const char ConnectRetryInterval[] = "ConnectRetryInterval"; #endif // _WIN32 @@ -307,15 +303,6 @@ const connection_option SS_CONN_OPTS[] = { CONN_ATTR_BOOL, conn_null_func::func }, - { - SSConnOptionNames::ColumnEncryption, - sizeof(SSConnOptionNames::ColumnEncryption), - SQLSRV_CONN_OPTION_COLUMNENCRYPTION, - ODBCConnOptions::ColumnEncryption, - sizeof(ODBCConnOptions::ColumnEncryption), - CONN_ATTR_STRING, - column_encryption_set_func::func - }, { SSConnOptionNames::Driver, sizeof(SSConnOptionNames::Driver), @@ -325,34 +312,16 @@ const connection_option SS_CONN_OPTS[] = { CONN_ATTR_STRING, driver_set_func::func }, - { - SSConnOptionNames::CEKeystoreProvider, - sizeof(SSConnOptionNames::CEKeystoreProvider), - SQLSRV_CONN_OPTION_CEKEYSTORE_PROVIDER, - ODBCConnOptions::CEKeystoreProvider, - sizeof(ODBCConnOptions::CEKeystoreProvider), - CONN_ATTR_STRING, - ce_ksp_provider_set_func::func - }, - { - SSConnOptionNames::CEKeystoreName, - sizeof(SSConnOptionNames::CEKeystoreName), - SQLSRV_CONN_OPTION_CEKEYSTORE_NAME, - ODBCConnOptions::CEKeystoreName, - sizeof(ODBCConnOptions::CEKeystoreName), - CONN_ATTR_STRING, - ce_ksp_provider_set_func::func - }, - { - SSConnOptionNames::CEKeystoreEncryptKey, - sizeof(SSConnOptionNames::CEKeystoreEncryptKey), - SQLSRV_CONN_OPTION_CEKEYSTORE_ENCRYPT_KEY, - ODBCConnOptions::CEKeystoreEncryptKey, - sizeof(ODBCConnOptions::CEKeystoreEncryptKey), - CONN_ATTR_STRING, - ce_ksp_provider_set_func::func - }, #ifdef _WIN32 + { + SSConnOptionNames::ColumnEncryption, + sizeof(SSConnOptionNames::ColumnEncryption), + SQLSRV_CONN_OPTION_COLUMNENCRYPTION, + ODBCConnOptions::ColumnEncryption, + sizeof(ODBCConnOptions::ColumnEncryption), + CONN_ATTR_STRING, + column_encryption_set_func::func + }, { SSConnOptionNames::ConnectRetryCount, sizeof( SSConnOptionNames::ConnectRetryCount ), diff --git a/source/sqlsrv/util.cpp b/source/sqlsrv/util.cpp index 0b734254..0c73b368 100644 --- a/source/sqlsrv/util.cpp +++ b/source/sqlsrv/util.cpp @@ -302,7 +302,7 @@ ss_error SS_ERRORS[] = { SQLSRV_ERROR_DRIVER_NOT_INSTALLED, { IMSSP, (SQLCHAR*) "This extension requires the Microsoft ODBC Driver for SQL Server. " "Access the following URL to download the ODBC Driver for SQL Server for %1!s!: " - "http://go.microsoft.com/fwlink/?LinkId=163712", -49, true } + "https://go.microsoft.com/fwlink/?LinkId=163712", -49, true } }, { @@ -379,22 +379,6 @@ ss_error SS_ERRORS[] = { { SS_SQLSRV_WARNING_FIELD_NAME_EMPTY, { SSPWARN, (SQLCHAR*)"An empty field name was skipped by sqlsrv_fetch_object.", -100, false } - }, - { - SQLSRV_ERROR_KEYSTORE_NAME_MISSING, - { IMSSP, (SQLCHAR*) "The name of the custom keystore provider is missing.", -101, false} - }, - { - SQLSRV_ERROR_KEYSTORE_PATH_MISSING, - { IMSSP, (SQLCHAR*) "The path to the custom keystore provider is missing.", -102, false} - }, - { - SQLSRV_ERROR_KEYSTORE_KEY_MISSING, - { IMSSP, (SQLCHAR*) "The encryption key for the custom keystore provider is missing.", -103, false} - }, - { - SQLSRV_ERROR_KEYSTORE_INVALID_VALUE, - { IMSSP, (SQLCHAR*) "Invalid value for loading a custom keystore provider.", -104, false} }, { SQLSRV_ERROR_CE_DRIVER_REQUIRED, diff --git a/test/bvt/pdo_sqlsrv/msdn_pdo_getAttribute.phpt b/test/bvt/pdo_sqlsrv/msdn_pdo_getAttribute.phpt index 54aa2e80..eb9a44c1 100644 --- a/test/bvt/pdo_sqlsrv/msdn_pdo_getAttribute.phpt +++ b/test/bvt/pdo_sqlsrv/msdn_pdo_getAttribute.phpt @@ -32,7 +32,7 @@ PDO::ATTR_ERRMODE: int\(0\) PDO::ATTR_ERRMODE: int\(2\) Array \( - \[DriverDllName\] => msodbcsql[0-9]{2}\.dll|libmsodbcsql-[0-9]{2}\.[0-9]\.so\.[0-9]\.[0-9] + \[DriverDllName\]|\[DriverName\] => (msodbcsql[0-9]{2}\.dll|(libmsodbcsql-[0-9]{2}\.[0-9]\.so\.[0-9]\.[0-9]|libmsodbcsql.[0-9]{2}.dylib)) \[DriverODBCVer\] => [0-9]{1,2}\.[0-9]{1,2} \[DriverVer\] => [0-9]{1,2}\.[0-9]{1,2}\.[0-9]{4} \[ExtensionVer\] => [0-9].[0-9]\.[0-9](-(RC[0-9]?|preview))?(\.[0-9]+)?(\+[0-9]+)? diff --git a/test/bvt/sqlsrv/msdn_sqlsrv_client_info.phpt b/test/bvt/sqlsrv/msdn_sqlsrv_client_info.phpt index d9586d8d..e979b422 100644 --- a/test/bvt/sqlsrv/msdn_sqlsrv_client_info.phpt +++ b/test/bvt/sqlsrv/msdn_sqlsrv_client_info.phpt @@ -29,7 +29,7 @@ else sqlsrv_close( $conn); ?> --EXPECTREGEX-- -DriverDllName: msodbcsql[0-9]{2}\.dll|libmsodbcsql-[0-9]{2}\.[0-9]\.so\.[0-9]\.[0-9] +DriverDllName|DriverName: (msodbcsql[0-9]{2}\.dll|(libmsodbcsql-[0-9]{2}\.[0-9]\.so\.[0-9]\.[0-9]|libmsodbcsql.[0-9]{2}.dylib)) DriverODBCVer: [0-9]{1,2}\.[0-9]{1,2} DriverVer: [0-9]{1,2}\.[0-9]{1,2}\.[0-9]{4} ExtensionVer: [0-9].[0-9]\.[0-9](-(RC[0-9]?|preview))?(\.[0-9]+)?(\+[0-9]+)? \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/AE_Ksp.inc b/test/functional/pdo_sqlsrv/AE_Ksp.inc deleted file mode 100644 index 8b845f7c..00000000 --- a/test/functional/pdo_sqlsrv/AE_Ksp.inc +++ /dev/null @@ -1,25 +0,0 @@ - \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/MsCommon.inc b/test/functional/pdo_sqlsrv/MsCommon.inc index 89f6c8ee..cddfdab9 100644 --- a/test/functional/pdo_sqlsrv/MsCommon.inc +++ b/test/functional/pdo_sqlsrv/MsCommon.inc @@ -16,10 +16,18 @@ function IsAEQualified($conn) { $msodbcsql_ver = $conn->getAttribute(PDO::ATTR_CLIENT_VERSION)["DriverVer"]; - $server_ver = $conn->getAttribute(PDO::ATTR_SERVER_VERSION); $msodbcsql_maj = explode(".", $msodbcsql_ver)[0]; - $msodbcsql_min = explode(".", $msodbcsql_ver)[1]; - if ($msodbcsql_maj < 17 || explode('.', $server_ver)[0] < 13) + if ($msodbcsql_maj < 17) { + return false; + } + require 'MsSetup.inc'; + if ($daasMode) { + // running against Azure + return true; + } + // if not Azure, check the server version + $server_ver = $conn->getAttribute(PDO::ATTR_SERVER_VERSION); + if (explode('.', $server_ver)[0] < 13) return false; return true; } diff --git a/test/functional/pdo_sqlsrv/MsCommon_mid-refactor.inc b/test/functional/pdo_sqlsrv/MsCommon_mid-refactor.inc index 7384f2a5..3a16bd27 100644 --- a/test/functional/pdo_sqlsrv/MsCommon_mid-refactor.inc +++ b/test/functional/pdo_sqlsrv/MsCommon_mid-refactor.inc @@ -20,11 +20,19 @@ const KSP_TEST_TABLE = 'CustomKSPTestTable'; function isAEQualified($conn) { $msodbcsql_ver = $conn->getAttribute(PDO::ATTR_CLIENT_VERSION)["DriverVer"]; - $server_ver = $conn->getAttribute(PDO::ATTR_SERVER_VERSION); $msodbcsql_maj = explode(".", $msodbcsql_ver)[0]; - if ($msodbcsql_maj < 17 || explode('.', $server_ver)[0] < 13) { + if ($msodbcsql_maj < 17) { return false; } + require 'MsSetup.inc'; + if ($daasMode) { + // running against Azure + return true; + } + // if not Azure, check the server version + $server_ver = $conn->getAttribute(PDO::ATTR_SERVER_VERSION); + if (explode('.', $server_ver)[0] < 13) + return false; return true; } diff --git a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_binary_size.phpt b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_binary_size.phpt new file mode 100644 index 00000000..253460ea --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_binary_size.phpt @@ -0,0 +1,134 @@ +--TEST-- +Test for retrieving encrypted data from binary types columns using PDO::bindColumn +--DESCRIPTION-- +Test conversion from binary types column to output of PDO::PARAM types +With or without AE, conversion works if: +1. From any binary type column to PDO::PARAM_STR +2. From any binary type column to PDO::PARAM_LOB +--SKIPIF-- + +--FILE-- + new BindParamOp(1, $inputValues[0], "PDO::PARAM_LOB", 0, "PDO::SQLSRV_ENCODING_BINARY"), + "c_rand" => new BindParamOp(2, $inputValues[1], "PDO::PARAM_LOB", 0, "PDO::SQLSRV_ENCODING_BINARY")), "prepareBindParam"); + + // fetch by specifying PDO::PARAM_ types with PDO::bindColumn + $query = "SELECT c_det, c_rand FROM $tbname"; + foreach ($pdoParamTypes as $pdoParamType) { + $det = ""; + $rand = ""; + $stmt = $conn->prepare($query); + $stmt->execute(); + $stmt->bindColumn('c_det', $det, constant($pdoParamType)); + $stmt->bindColumn('c_rand', $rand, constant($pdoParamType)); + $row = $stmt->fetch(PDO::FETCH_BOUND); + + // check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_NULL or PDO::PARAM_INT + // with or without AE: should not work + if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_NULL" || $pdoParamType == "PDO::PARAM_INT") { + if (!is_null($det) || !is_null($rand)) { + echo "Retrieving $typeFull data as $pdoParamType should not be supported\n"; + } + // check the case when fetching as PDO::PARAM_STR or PDO::PARAM_LOB + // with or without AE: should work + } else { + if (trim($det) == $inputValues[0] && trim($rand) == $inputValues[1]) { + echo "****Retrieving $typeFull data as $pdoParamType is supported****\n"; + } else { + echo "Retrieving $typeFull data as $pdoParamType fails\n"; + } + } + } + // cleanup + dropTable($conn, $tbname); + } + } + unset($stmt); + unset($conn); +} catch (PDOException $e) { + echo $e->getMessage(); +} +?> +--EXPECT-- +Testing binary(1): +****Retrieving binary(1) data as PDO::PARAM_STR is supported**** +****Retrieving binary(1) data as PDO::PARAM_LOB is supported**** + +Testing binary(8): +****Retrieving binary(8) data as PDO::PARAM_STR is supported**** +****Retrieving binary(8) data as PDO::PARAM_LOB is supported**** + +Testing binary(64): +****Retrieving binary(64) data as PDO::PARAM_STR is supported**** +****Retrieving binary(64) data as PDO::PARAM_LOB is supported**** + +Testing binary(512): +****Retrieving binary(512) data as PDO::PARAM_STR is supported**** +****Retrieving binary(512) data as PDO::PARAM_LOB is supported**** + +Testing binary(4000): +****Retrieving binary(4000) data as PDO::PARAM_STR is supported**** +****Retrieving binary(4000) data as PDO::PARAM_LOB is supported**** + +Testing varbinary(1): +****Retrieving varbinary(1) data as PDO::PARAM_STR is supported**** +****Retrieving varbinary(1) data as PDO::PARAM_LOB is supported**** + +Testing varbinary(8): +****Retrieving varbinary(8) data as PDO::PARAM_STR is supported**** +****Retrieving varbinary(8) data as PDO::PARAM_LOB is supported**** + +Testing varbinary(64): +****Retrieving varbinary(64) data as PDO::PARAM_STR is supported**** +****Retrieving varbinary(64) data as PDO::PARAM_LOB is supported**** + +Testing varbinary(512): +****Retrieving varbinary(512) data as PDO::PARAM_STR is supported**** +****Retrieving varbinary(512) data as PDO::PARAM_LOB is supported**** + +Testing varbinary(4000): +****Retrieving varbinary(4000) data as PDO::PARAM_STR is supported**** +****Retrieving varbinary(4000) data as PDO::PARAM_LOB is supported**** + +Testing varbinary(max): +****Retrieving varbinary(max) data as PDO::PARAM_STR is supported**** +****Retrieving varbinary(max) data as PDO::PARAM_LOB is supported**** + +Testing varbinary(max): +****Retrieving varbinary(max) data as PDO::PARAM_STR is supported**** +****Retrieving varbinary(max) data as PDO::PARAM_LOB is supported**** + +Testing varbinary(max): +****Retrieving varbinary(max) data as PDO::PARAM_STR is supported**** +****Retrieving varbinary(max) data as PDO::PARAM_LOB is supported**** + +Testing varbinary(max): +****Retrieving varbinary(max) data as PDO::PARAM_STR is supported**** +****Retrieving varbinary(max) data as PDO::PARAM_LOB is supported**** + +Testing varbinary(max): +****Retrieving varbinary(max) data as PDO::PARAM_STR is supported**** +****Retrieving varbinary(max) data as PDO::PARAM_LOB is supported**** \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_char_size.phpt b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_char_size.phpt new file mode 100644 index 00000000..e575d3fd --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_char_size.phpt @@ -0,0 +1,144 @@ +--TEST-- +Test for retrieving encrypted data from char types columns using PDO::bindColumn +--DESCRIPTION-- +Test conversion from char types column to output of PDO::PARAM types +With or without Always Encrypted, conversion works if: +1. From any char type column to PDO::PARAM_STR +2. From any char type column to PDO::PARAM_LOB +--SKIPIF-- + +--FILE-- + $inputValue)); + + // fetch by specifying PDO::PARAM_ types with PDO::bindColumn + $query = "SELECT c1 FROM $tbname"; + foreach ($pdoParamTypes as $pdoParamType) { + $det = ""; + $rand = ""; + $stmt = $conn->prepare($query); + $stmt->execute(); + $stmt->bindColumn('c1', $c1, constant($pdoParamType)); + $row = $stmt->fetch(PDO::FETCH_BOUND); + + // check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_NULL or PDO::PARAM_INT + // with or without AE: should not work + if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_NULL" || $pdoParamType == "PDO::PARAM_INT") { + if (!empty($det) || !empty($rand)) { + echo "Retrieving $typeFull data as $pdoParamType should not be supported\n"; + } + // check the case when fetching as PDO::PARAM_STR or PDO::PARAM_LOB + // with or without AE: should work + } else { + if (strlen($c1) == $m) { + echo "****Retrieving $typeFull as $pdoParamType is supported****\n"; + } else { + echo "Retrieving $typeFull as $pdoParamType fails\n"; + } + } + } + // cleanup + dropTable($conn, $tbname); + } + } + unset($stmt); + unset($conn); +} catch (PDOException $e) { + echo $e->getMessage(); +} +?> +--EXPECT-- +Testing char(1): +****Retrieving char(1) as PDO::PARAM_STR is supported**** +****Retrieving char(1) as PDO::PARAM_LOB is supported**** + +Testing char(8): +****Retrieving char(8) as PDO::PARAM_STR is supported**** +****Retrieving char(8) as PDO::PARAM_LOB is supported**** + +Testing char(64): +****Retrieving char(64) as PDO::PARAM_STR is supported**** +****Retrieving char(64) as PDO::PARAM_LOB is supported**** + +Testing char(512): +****Retrieving char(512) as PDO::PARAM_STR is supported**** +****Retrieving char(512) as PDO::PARAM_LOB is supported**** + +Testing char(4096): +****Retrieving char(4096) as PDO::PARAM_STR is supported**** +****Retrieving char(4096) as PDO::PARAM_LOB is supported**** + +Testing char(8000): +****Retrieving char(8000) as PDO::PARAM_STR is supported**** +****Retrieving char(8000) as PDO::PARAM_LOB is supported**** + +Testing varchar(1): +****Retrieving varchar(1) as PDO::PARAM_STR is supported**** +****Retrieving varchar(1) as PDO::PARAM_LOB is supported**** + +Testing varchar(8): +****Retrieving varchar(8) as PDO::PARAM_STR is supported**** +****Retrieving varchar(8) as PDO::PARAM_LOB is supported**** + +Testing varchar(64): +****Retrieving varchar(64) as PDO::PARAM_STR is supported**** +****Retrieving varchar(64) as PDO::PARAM_LOB is supported**** + +Testing varchar(512): +****Retrieving varchar(512) as PDO::PARAM_STR is supported**** +****Retrieving varchar(512) as PDO::PARAM_LOB is supported**** + +Testing varchar(4096): +****Retrieving varchar(4096) as PDO::PARAM_STR is supported**** +****Retrieving varchar(4096) as PDO::PARAM_LOB is supported**** + +Testing varchar(8000): +****Retrieving varchar(8000) as PDO::PARAM_STR is supported**** +****Retrieving varchar(8000) as PDO::PARAM_LOB is supported**** + +Testing varchar(max): +****Retrieving varchar(max) as PDO::PARAM_STR is supported**** +****Retrieving varchar(max) as PDO::PARAM_LOB is supported**** + +Testing varchar(max): +****Retrieving varchar(max) as PDO::PARAM_STR is supported**** +****Retrieving varchar(max) as PDO::PARAM_LOB is supported**** + +Testing varchar(max): +****Retrieving varchar(max) as PDO::PARAM_STR is supported**** +****Retrieving varchar(max) as PDO::PARAM_LOB is supported**** + +Testing varchar(max): +****Retrieving varchar(max) as PDO::PARAM_STR is supported**** +****Retrieving varchar(max) as PDO::PARAM_LOB is supported**** + +Testing varchar(max): +****Retrieving varchar(max) as PDO::PARAM_STR is supported**** +****Retrieving varchar(max) as PDO::PARAM_LOB is supported**** + +Testing varchar(max): +****Retrieving varchar(max) as PDO::PARAM_STR is supported**** +****Retrieving varchar(max) as PDO::PARAM_LOB is supported**** \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_datetime.phpt b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_datetime.phpt new file mode 100644 index 00000000..b1cf8235 --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_datetime.phpt @@ -0,0 +1,77 @@ +--TEST-- +Test for retrieving encrypted data from datetime types columns using PDO::bindColumn +--DESCRIPTION-- +Test conversion from datetime types column to output of PDO::PARAM types +With or without Always Encrypted, conversion works if: +1. From any datetime type column to PDO::PARAM_STR +2. From any datetime type column to PDO::PARAM_LOB +--SKIPIF-- + +--FILE-- + $inputValues[0], "c_rand" => $inputValues[1])); + + // fetch by specifying PDO::PARAM_ types with PDO::bindColumn + $query = "SELECT c_det, c_rand FROM $tbname"; + foreach ($pdoParamTypes as $pdoParamType) { + $det = ""; + $rand = ""; + $stmt = $conn->prepare($query); + $stmt->execute(); + $stmt->bindColumn('c_det', $det, constant($pdoParamType)); + $stmt->bindColumn('c_rand', $rand, constant($pdoParamType)); + $row = $stmt->fetch(PDO::FETCH_BOUND); + + // check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_NULL or PDO::PARAM_INT + // with or without AE: should not work + if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_NULL" || $pdoParamType == "PDO::PARAM_INT") { + if (!is_null($det) || !is_null($rand)) { + echo "Retrieving $dataType data as $pdoParamType should not be supported\n"; + } + // check the case when fetching as PDO::PARAM_STR or PDO::PARAM_LOB + // only check if input values are part of fetched values because some input values do not contain any deicmal places, the value retrieved however has 3 decimal places if the type is a datetime + // with or without AE: should work + } else { + if (strpos($det, $inputValues[0]) !== false && strpos($rand, $inputValues[1]) !== false) { + echo "****Retrieving $dataType as $pdoParamType is supported****\n"; + } else { + echo "Retrieving $dataType as $pdoParamType fails\n"; + } + } + } + // cleanup + dropTable($conn, $tbname); + } + unset($stmt); + unset($conn); +} catch (PDOException $e) { + echo $e->getMessage(); +} +?> +--EXPECT-- +Testing date: +****Retrieving date as PDO::PARAM_STR is supported**** +****Retrieving date as PDO::PARAM_LOB is supported**** + +Testing datetime: +****Retrieving datetime as PDO::PARAM_STR is supported**** +****Retrieving datetime as PDO::PARAM_LOB is supported**** + +Testing smalldatetime: +****Retrieving smalldatetime as PDO::PARAM_STR is supported**** +****Retrieving smalldatetime as PDO::PARAM_LOB is supported**** \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_datetime_precision.phpt b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_datetime_precision.phpt new file mode 100644 index 00000000..9a68d7a9 --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_datetime_precision.phpt @@ -0,0 +1,150 @@ +--TEST-- +Test for retrieving encrypted data from datetime types columns with different precisions using PDO::bindColumn +--DESCRIPTION-- +Test conversion from datetime types column to output of PDO::PARAM types +With or without Always Encrypted, conversion works if: +1. From any datetime type column to PDO::PARAM_STR +2. From any datetime type column to PDO::PARAM_LOB +TODO: cannot insert into a datetime2(0) using the PDO_SQLSRV driver + returns operand type clash error between smalldatetime and datetime2(0) + to see error, uncomment 0 from the $precision array + documented in VSO 2693 +--SKIPIF-- + +--FILE-- + array("0001-01-01 00:00:00", "9999-12-31 23:59:59"), + "datetimeoffset" => array("0001-01-01 00:00:00 -14:00", "9999-12-31 23:59:59 +14:00"), + "time" => array("00:00:00", "23:59:59")); + +try { + $conn = connect("", array(), PDO::ERRMODE_SILENT); + foreach ($dataTypes as $dataType) { + foreach ($precisions as $m) { + // add $m number of decimal digits to the some input values + $inputValues[0] = $inputValuesInit[$dataType][0]; + $inputValues[1] = $inputValuesInit[$dataType][1]; + if ($m != 0) { + if ($dataType == "datetime2") { + $inputValues[1] .= "." . str_repeat("9", $m); + } else if ($dataType == "datetimeoffset") { + $dtoffsetPieces = explode(" ", $inputValues[1]); + $inputValues[1] = $dtoffsetPieces[0] . " " . $dtoffsetPieces[1] . "." . str_repeat("9", $m) . " " . $dtoffsetPieces[2]; + } else if ($dataType == "time") { + $inputValues[0] .= "." . str_repeat("0", $m); + $inputValues[1] .= "." . str_repeat("9", $m); + } + } + $typeFull = "$dataType($m)"; + echo "\nTesting $typeFull:\n"; + + //create and populate table containing datetime2(m), datetimeoffset(m) or time(m) columns + $tbname = "test_" . $dataType . $m; + $colMetaArr = array(new ColumnMeta($typeFull, "c_det"), new ColumnMeta($typeFull, "c_rand", null, "randomized")); + createTable($conn, $tbname, $colMetaArr); + insertRow($conn, $tbname, array("c_det" => $inputValues[0], "c_rand" => $inputValues[1])); + + // fetch by specifying PDO::PARAM_ types with PDO:bindColumn + $query = "SELECT c_det, c_rand FROM $tbname"; + foreach ($pdoParamTypes as $pdoParamType) { + $det = ""; + $rand = ""; + $stmt = $conn->prepare($query); + $stmt->execute(); + $stmt->bindColumn('c_det', $det, constant($pdoParamType)); + $stmt->bindColumn('c_rand', $rand, constant($pdoParamType)); + $row = $stmt->fetch(PDO::FETCH_BOUND); + + // check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_NULL or PDO::PARAM_INT + // with or without AE: should not work + if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_NULL" || $pdoParamType == "PDO::PARAM_INT") { + if (!is_null($det) || !is_null($rand)) { + echo "Retrieving $typeFull data as $pdoParamType should not be supported\n"; + } + // check the case when fetching as PDO::PARAM_STR or PDO::PARAM_LOB + // with or without AE: should work + } else { + if (compareDate($det, $inputValues[0], $dataType) && compareDate($rand, $inputValues[1], $dataType)) { + echo "****Retrieving $typeFull as $pdoParamType is supported****\n"; + } else { + echo "Retrieving $typeFull as $pdoParamType fails\n"; + } + } + } + // cleanup + dropTable($conn, $tbname); + } + } + unset($stmt); + unset($conn); +} catch (PDOException $e) { + echo $e->getMessage(); +} +?> +--EXPECT-- +Testing datetime2(1): +****Retrieving datetime2(1) as PDO::PARAM_STR is supported**** +****Retrieving datetime2(1) as PDO::PARAM_LOB is supported**** + +Testing datetime2(2): +****Retrieving datetime2(2) as PDO::PARAM_STR is supported**** +****Retrieving datetime2(2) as PDO::PARAM_LOB is supported**** + +Testing datetime2(4): +****Retrieving datetime2(4) as PDO::PARAM_STR is supported**** +****Retrieving datetime2(4) as PDO::PARAM_LOB is supported**** + +Testing datetime2(7): +****Retrieving datetime2(7) as PDO::PARAM_STR is supported**** +****Retrieving datetime2(7) as PDO::PARAM_LOB is supported**** + +Testing datetimeoffset(1): +****Retrieving datetimeoffset(1) as PDO::PARAM_STR is supported**** +****Retrieving datetimeoffset(1) as PDO::PARAM_LOB is supported**** + +Testing datetimeoffset(2): +****Retrieving datetimeoffset(2) as PDO::PARAM_STR is supported**** +****Retrieving datetimeoffset(2) as PDO::PARAM_LOB is supported**** + +Testing datetimeoffset(4): +****Retrieving datetimeoffset(4) as PDO::PARAM_STR is supported**** +****Retrieving datetimeoffset(4) as PDO::PARAM_LOB is supported**** + +Testing datetimeoffset(7): +****Retrieving datetimeoffset(7) as PDO::PARAM_STR is supported**** +****Retrieving datetimeoffset(7) as PDO::PARAM_LOB is supported**** + +Testing time(1): +****Retrieving time(1) as PDO::PARAM_STR is supported**** +****Retrieving time(1) as PDO::PARAM_LOB is supported**** + +Testing time(2): +****Retrieving time(2) as PDO::PARAM_STR is supported**** +****Retrieving time(2) as PDO::PARAM_LOB is supported**** + +Testing time(4): +****Retrieving time(4) as PDO::PARAM_STR is supported**** +****Retrieving time(4) as PDO::PARAM_LOB is supported**** + +Testing time(7): +****Retrieving time(7) as PDO::PARAM_STR is supported**** +****Retrieving time(7) as PDO::PARAM_LOB is supported**** \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_decimal_precision.phpt b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_decimal_precision.phpt new file mode 100644 index 00000000..247d298d --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_decimal_precision.phpt @@ -0,0 +1,242 @@ +--TEST-- +Test for retrieving encrypted data from decimal types columns using PDO::bindColumn +--DESCRIPTION-- +Test conversion from decimal types column to output of PDO::PARAM types +With or without ALways Encrypted, conversion works if: +1. From any decimal type column to PDO::PARAM_STR +2. From any decimal type column to PDO::PARAM_LOB +TODO: behavior for teching decimals as PARAM_BOOL and PARAM_INT varies depending on the number being fetched + 1. if the number is less than 1, returns 0 (even though the number being fetched is 0.9) + 2. if the number is greater than 1 and the number of digits is less than 11, returns the correctly rounded integer (e.g., returns 922 when fetching 922.3) + 3. if the number is greater than 1 and the number of digits is greater than 11, returns NULL + need to investigate which should be the correct behavior + for this test, assume to correct behavior is to return NULL + documented in VSO 2730 +--SKIPIF-- + +--FILE-- + array(0, 1), + 4 => array(0, 1, 4), + 16 => array(0, 1, 4, 16), + 38 => array(0, 1, 4, 16, 38)); +$inputValuesInit = array(92233720368547758089223372036854775808, -92233720368547758089223372036854775808); +$inputPrecision = 38; + +try { + $conn = connect("", array(), PDO::ERRMODE_SILENT); + foreach ($dataTypes as $dataType) { + foreach ($precisions as $m1 => $scales) { + foreach ($scales as $m2) { + // change the number of integers in the input values to be $m1 - $m2 + $precDiff = $inputPrecision - ($m1 - $m2); + $inputValues = $inputValuesInit; + foreach ($inputValues as &$inputValue) { + $inputValue = $inputValue / pow(10, $precDiff); + } + + // compute the epsilon for comparing doubles + // float in PHP only has a precision of roughtly 14 digits: http://php.net/manual/en/language.types.float.php + $epsilon; + if ($m1 < 14) { + $epsilon = pow(10, $m2 * -1); + } else { + $numint = $m1 - $m2; + if ($numint < 14) { + $epsilon = pow(10, (14 - $numint) * -1); + } else { + $epsilon = pow(10, $numint - 14); + } + } + + $typeFull = "$dataType($m1, $m2)"; + echo "\nTesting $typeFull:\n"; + + // create and populate table containing decimal(m1, m2) or numeric(m1, m2) columns + $tbname = "test_" . $dataType . $m1 . $m2; + $colMetaArr = array(new ColumnMeta($typeFull, "c_det"), new ColumnMeta($typeFull, "c_rand", null, "randomized")); + createTable($conn, $tbname, $colMetaArr); + insertRow($conn, $tbname, array("c_det" => $inputValues[0], "c_rand" => $inputValues[1])); + + // fetch by specifying PDO::PARAM_ types with PDO::bindColumn + $query = "SELECT c_det, c_rand FROM $tbname"; + foreach ($pdoParamTypes as $pdoParamType) { + $det = ""; + $rand = ""; + $stmt = $conn->prepare($query); + $stmt->execute(); + $stmt->bindColumn('c_det', $det, constant($pdoParamType)); + $stmt->bindColumn('c_rand', $rand, constant($pdoParamType)); + $row = $stmt->fetch(PDO::FETCH_BOUND); + + // check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_NULL or PDO::PARAM_INT + // with or without AE: should not work + // assume to correct behavior is to return NULL, see description + if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_NULL" || $pdoParamType == "PDO::PARAM_INT") { + if (!is_null($det) || !is_null($rand)) { + echo "Retrieving $typeFull data as $pdoParamType should return NULL\n"; + } + } else { + if (abs($det - $inputValues[0]) < $epsilon && + abs($rand - $inputValues[1]) < $epsilon) { + echo "****Retrieving $typeFull as $pdoParamType is supported****\n"; + } else { + echo "Retrieving $typeFull as $pdoParamType fails\n"; + } + } + } + // cleanup + dropTable($conn, $tbname); + } + } + } + unset($stmt); + unset($conn); +} catch (PDOException $e) { + echo $e->getMessage(); +} +?> +--EXPECT-- +Testing decimal(1, 0): +Retrieving decimal(1, 0) data as PDO::PARAM_BOOL should return NULL +Retrieving decimal(1, 0) data as PDO::PARAM_INT should return NULL +****Retrieving decimal(1, 0) as PDO::PARAM_STR is supported**** +****Retrieving decimal(1, 0) as PDO::PARAM_LOB is supported**** + +Testing decimal(1, 1): +Retrieving decimal(1, 1) data as PDO::PARAM_BOOL should return NULL +Retrieving decimal(1, 1) data as PDO::PARAM_INT should return NULL +****Retrieving decimal(1, 1) as PDO::PARAM_STR is supported**** +****Retrieving decimal(1, 1) as PDO::PARAM_LOB is supported**** + +Testing decimal(4, 0): +Retrieving decimal(4, 0) data as PDO::PARAM_BOOL should return NULL +Retrieving decimal(4, 0) data as PDO::PARAM_INT should return NULL +****Retrieving decimal(4, 0) as PDO::PARAM_STR is supported**** +****Retrieving decimal(4, 0) as PDO::PARAM_LOB is supported**** + +Testing decimal(4, 1): +Retrieving decimal(4, 1) data as PDO::PARAM_BOOL should return NULL +Retrieving decimal(4, 1) data as PDO::PARAM_INT should return NULL +****Retrieving decimal(4, 1) as PDO::PARAM_STR is supported**** +****Retrieving decimal(4, 1) as PDO::PARAM_LOB is supported**** + +Testing decimal(4, 4): +Retrieving decimal(4, 4) data as PDO::PARAM_BOOL should return NULL +Retrieving decimal(4, 4) data as PDO::PARAM_INT should return NULL +****Retrieving decimal(4, 4) as PDO::PARAM_STR is supported**** +****Retrieving decimal(4, 4) as PDO::PARAM_LOB is supported**** + +Testing decimal(16, 0): +****Retrieving decimal(16, 0) as PDO::PARAM_STR is supported**** +****Retrieving decimal(16, 0) as PDO::PARAM_LOB is supported**** + +Testing decimal(16, 1): +****Retrieving decimal(16, 1) as PDO::PARAM_STR is supported**** +****Retrieving decimal(16, 1) as PDO::PARAM_LOB is supported**** + +Testing decimal(16, 4): +****Retrieving decimal(16, 4) as PDO::PARAM_STR is supported**** +****Retrieving decimal(16, 4) as PDO::PARAM_LOB is supported**** + +Testing decimal(16, 16): +Retrieving decimal(16, 16) data as PDO::PARAM_BOOL should return NULL +Retrieving decimal(16, 16) data as PDO::PARAM_INT should return NULL +****Retrieving decimal(16, 16) as PDO::PARAM_STR is supported**** +****Retrieving decimal(16, 16) as PDO::PARAM_LOB is supported**** + +Testing decimal(38, 0): +****Retrieving decimal(38, 0) as PDO::PARAM_STR is supported**** +****Retrieving decimal(38, 0) as PDO::PARAM_LOB is supported**** + +Testing decimal(38, 1): +****Retrieving decimal(38, 1) as PDO::PARAM_STR is supported**** +****Retrieving decimal(38, 1) as PDO::PARAM_LOB is supported**** + +Testing decimal(38, 4): +****Retrieving decimal(38, 4) as PDO::PARAM_STR is supported**** +****Retrieving decimal(38, 4) as PDO::PARAM_LOB is supported**** + +Testing decimal(38, 16): +****Retrieving decimal(38, 16) as PDO::PARAM_STR is supported**** +****Retrieving decimal(38, 16) as PDO::PARAM_LOB is supported**** + +Testing decimal(38, 38): +Retrieving decimal(38, 38) data as PDO::PARAM_BOOL should return NULL +Retrieving decimal(38, 38) data as PDO::PARAM_INT should return NULL +****Retrieving decimal(38, 38) as PDO::PARAM_STR is supported**** +****Retrieving decimal(38, 38) as PDO::PARAM_LOB is supported**** + +Testing numeric(1, 0): +Retrieving numeric(1, 0) data as PDO::PARAM_BOOL should return NULL +Retrieving numeric(1, 0) data as PDO::PARAM_INT should return NULL +****Retrieving numeric(1, 0) as PDO::PARAM_STR is supported**** +****Retrieving numeric(1, 0) as PDO::PARAM_LOB is supported**** + +Testing numeric(1, 1): +Retrieving numeric(1, 1) data as PDO::PARAM_BOOL should return NULL +Retrieving numeric(1, 1) data as PDO::PARAM_INT should return NULL +****Retrieving numeric(1, 1) as PDO::PARAM_STR is supported**** +****Retrieving numeric(1, 1) as PDO::PARAM_LOB is supported**** + +Testing numeric(4, 0): +Retrieving numeric(4, 0) data as PDO::PARAM_BOOL should return NULL +Retrieving numeric(4, 0) data as PDO::PARAM_INT should return NULL +****Retrieving numeric(4, 0) as PDO::PARAM_STR is supported**** +****Retrieving numeric(4, 0) as PDO::PARAM_LOB is supported**** + +Testing numeric(4, 1): +Retrieving numeric(4, 1) data as PDO::PARAM_BOOL should return NULL +Retrieving numeric(4, 1) data as PDO::PARAM_INT should return NULL +****Retrieving numeric(4, 1) as PDO::PARAM_STR is supported**** +****Retrieving numeric(4, 1) as PDO::PARAM_LOB is supported**** + +Testing numeric(4, 4): +Retrieving numeric(4, 4) data as PDO::PARAM_BOOL should return NULL +Retrieving numeric(4, 4) data as PDO::PARAM_INT should return NULL +****Retrieving numeric(4, 4) as PDO::PARAM_STR is supported**** +****Retrieving numeric(4, 4) as PDO::PARAM_LOB is supported**** + +Testing numeric(16, 0): +****Retrieving numeric(16, 0) as PDO::PARAM_STR is supported**** +****Retrieving numeric(16, 0) as PDO::PARAM_LOB is supported**** + +Testing numeric(16, 1): +****Retrieving numeric(16, 1) as PDO::PARAM_STR is supported**** +****Retrieving numeric(16, 1) as PDO::PARAM_LOB is supported**** + +Testing numeric(16, 4): +****Retrieving numeric(16, 4) as PDO::PARAM_STR is supported**** +****Retrieving numeric(16, 4) as PDO::PARAM_LOB is supported**** + +Testing numeric(16, 16): +Retrieving numeric(16, 16) data as PDO::PARAM_BOOL should return NULL +Retrieving numeric(16, 16) data as PDO::PARAM_INT should return NULL +****Retrieving numeric(16, 16) as PDO::PARAM_STR is supported**** +****Retrieving numeric(16, 16) as PDO::PARAM_LOB is supported**** + +Testing numeric(38, 0): +****Retrieving numeric(38, 0) as PDO::PARAM_STR is supported**** +****Retrieving numeric(38, 0) as PDO::PARAM_LOB is supported**** + +Testing numeric(38, 1): +****Retrieving numeric(38, 1) as PDO::PARAM_STR is supported**** +****Retrieving numeric(38, 1) as PDO::PARAM_LOB is supported**** + +Testing numeric(38, 4): +****Retrieving numeric(38, 4) as PDO::PARAM_STR is supported**** +****Retrieving numeric(38, 4) as PDO::PARAM_LOB is supported**** + +Testing numeric(38, 16): +****Retrieving numeric(38, 16) as PDO::PARAM_STR is supported**** +****Retrieving numeric(38, 16) as PDO::PARAM_LOB is supported**** + +Testing numeric(38, 38): +Retrieving numeric(38, 38) data as PDO::PARAM_BOOL should return NULL +Retrieving numeric(38, 38) data as PDO::PARAM_INT should return NULL +****Retrieving numeric(38, 38) as PDO::PARAM_STR is supported**** +****Retrieving numeric(38, 38) as PDO::PARAM_LOB is supported**** \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_float_bits.phpt b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_float_bits.phpt new file mode 100644 index 00000000..8eb2b918 --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_float_bits.phpt @@ -0,0 +1,94 @@ +--TEST-- +Test for retrieving encrypted data from float types columns using PDO::bindColumn +--DESCRIPTION-- +Test conversion from float types column to output of PDO::PARAM types +With or without Always Encrypted, conversion works if: +1. From any float type column to PDO::PARAM_STR +2. From any float type column to PDO::PARAM_LOB +--SKIPIF-- + +--FILE-- + 24, the precision is 15 digits, but PHP float only supports up to 14 digits + $epsilon; + if ($m <= 24) { + $epsilon = pow(10, $numint - 7); + } else { + $epsilon = pow(10, $numint - 14); + } + + $typeFull = "$dataType($m)"; + echo "\nTesting $typeFull:\n"; + + //create and populate table containing float(m) columns + $tbname = "test_" . $dataType . $m; + $colMetaArr = array(new ColumnMeta($typeFull, "c_det"), new ColumnMeta($typeFull, "c_rand", null, "randomized")); + createTable($conn, $tbname, $colMetaArr); + insertRow($conn, $tbname, array("c_det" => $inputValues[0], "c_rand" => $inputValues[1])); + + // fetchby specifying PDO::PARAM_ types with PDO::bindColumn + $query = "SELECT c_det, c_rand FROM $tbname"; + foreach ($pdoParamTypes as $pdoParamType) { + $det = ""; + $rand = ""; + $stmt = $conn->prepare($query); + $stmt->execute(); + $stmt->bindColumn('c_det', $det, constant($pdoParamType)); + $stmt->bindColumn('c_rand', $rand, constant($pdoParamType)); + $row = $stmt->fetch(PDO::FETCH_BOUND); + + // check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_NULL or PDO::PARAM_INT + // with or without AE: should not work + if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_NULL" || $pdoParamType == "PDO::PARAM_INT") { + if (!is_null($det) || !is_null($rand)) { + echo "Retriving $typeFull data as $pdoParamType should return NULL\n"; + } + } else { + if (abs($det - $inputValues[0]) < $epsilon && abs($rand - $inputValues[1]) < $epsilon) { + echo "****Retrieving $typeFull as $pdoParamType is supported****\n"; + } else { + echo "Retrieving $typeFull as $pdoParamType fails\n"; + } + } + } + dropTable($conn, $tbname); + } + unset($stmt); + unset($conn); +} catch (PDOException $e) { + echo $e->getMessage(); +} +?> +--EXPECT-- +Testing float(1): +****Retrieving float(1) as PDO::PARAM_STR is supported**** +****Retrieving float(1) as PDO::PARAM_LOB is supported**** + +Testing float(12): +****Retrieving float(12) as PDO::PARAM_STR is supported**** +****Retrieving float(12) as PDO::PARAM_LOB is supported**** + +Testing float(24): +****Retrieving float(24) as PDO::PARAM_STR is supported**** +****Retrieving float(24) as PDO::PARAM_LOB is supported**** + +Testing float(36): +****Retrieving float(36) as PDO::PARAM_STR is supported**** +****Retrieving float(36) as PDO::PARAM_LOB is supported**** + +Testing float(53): +****Retrieving float(53) as PDO::PARAM_STR is supported**** +****Retrieving float(53) as PDO::PARAM_LOB is supported**** \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_nchar_size.phpt b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_nchar_size.phpt new file mode 100644 index 00000000..43ead937 --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_nchar_size.phpt @@ -0,0 +1,132 @@ +--TEST-- +Test for retrieving encrypted data from nchar types columns using PDO::bindColumn +--DESCRIPTION-- +Test conversion from nchar types column to output of PDO::PARAM types +With or without Always Encrypted, conversion works if: +1. From any nchar type column to PDO::PARAM_STR +2. From any nchar type column to PDO::PARAM_LOB +--SKIPIF-- + +--FILE-- + $inputValue)); + + // fetch by specifying PDO::PARAM_ types with PDO::bindColumn + $query = "SELECT c1 FROM $tbname"; + foreach ($pdoParamTypes as $pdoParamType) { + $det = ""; + $rand = ""; + $stmt = $conn->prepare($query); + $stmt->execute(); + $stmt->bindColumn('c1', $c1, constant($pdoParamType)); + $row = $stmt->fetch(PDO::FETCH_BOUND); + + // check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_NULL or PDO::PARAM_INT + // with or without AE: should not work + if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_NULL" || $pdoParamType == "PDO::PARAM_INT") { + if (!empty($det) || !empty($rand)) { + echo "Retrieving $typeFull data as $pdoParamType should not be supported\n"; + } + // check the case when fetching as PDO::PARAM_STR or PDO::PARAM_LOB + // with or without AE: should work + } else { + if (strlen($c1) == $m) { + echo "****Retrieving $typeFull as $pdoParamType is supported****\n"; + } else { + echo "Retrieving $typeFull as $pdoParamType fails\n"; + } + } + } + // cleanup + dropTable($conn, $tbname); + } + } + unset($stmt); + unset($conn); +} catch (PDOException $e) { + echo $e->getMessage(); +} +?> +--EXPECT-- +Testing nchar(1): +****Retrieving nchar(1) as PDO::PARAM_STR is supported**** +****Retrieving nchar(1) as PDO::PARAM_LOB is supported**** + +Testing nchar(8): +****Retrieving nchar(8) as PDO::PARAM_STR is supported**** +****Retrieving nchar(8) as PDO::PARAM_LOB is supported**** + +Testing nchar(64): +****Retrieving nchar(64) as PDO::PARAM_STR is supported**** +****Retrieving nchar(64) as PDO::PARAM_LOB is supported**** + +Testing nchar(512): +****Retrieving nchar(512) as PDO::PARAM_STR is supported**** +****Retrieving nchar(512) as PDO::PARAM_LOB is supported**** + +Testing nchar(4000): +****Retrieving nchar(4000) as PDO::PARAM_STR is supported**** +****Retrieving nchar(4000) as PDO::PARAM_LOB is supported**** + +Testing nvarchar(1): +****Retrieving nvarchar(1) as PDO::PARAM_STR is supported**** +****Retrieving nvarchar(1) as PDO::PARAM_LOB is supported**** + +Testing nvarchar(8): +****Retrieving nvarchar(8) as PDO::PARAM_STR is supported**** +****Retrieving nvarchar(8) as PDO::PARAM_LOB is supported**** + +Testing nvarchar(64): +****Retrieving nvarchar(64) as PDO::PARAM_STR is supported**** +****Retrieving nvarchar(64) as PDO::PARAM_LOB is supported**** + +Testing nvarchar(512): +****Retrieving nvarchar(512) as PDO::PARAM_STR is supported**** +****Retrieving nvarchar(512) as PDO::PARAM_LOB is supported**** + +Testing nvarchar(4000): +****Retrieving nvarchar(4000) as PDO::PARAM_STR is supported**** +****Retrieving nvarchar(4000) as PDO::PARAM_LOB is supported**** + +Testing nvarchar(max): +****Retrieving nvarchar(max) as PDO::PARAM_STR is supported**** +****Retrieving nvarchar(max) as PDO::PARAM_LOB is supported**** + +Testing nvarchar(max): +****Retrieving nvarchar(max) as PDO::PARAM_STR is supported**** +****Retrieving nvarchar(max) as PDO::PARAM_LOB is supported**** + +Testing nvarchar(max): +****Retrieving nvarchar(max) as PDO::PARAM_STR is supported**** +****Retrieving nvarchar(max) as PDO::PARAM_LOB is supported**** + +Testing nvarchar(max): +****Retrieving nvarchar(max) as PDO::PARAM_STR is supported**** +****Retrieving nvarchar(max) as PDO::PARAM_LOB is supported**** + +Testing nvarchar(max): +****Retrieving nvarchar(max) as PDO::PARAM_STR is supported**** +****Retrieving nvarchar(max) as PDO::PARAM_LOB is supported**** \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_numeric.phpt b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_numeric.phpt new file mode 100644 index 00000000..1a281bdb --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_numeric.phpt @@ -0,0 +1,128 @@ +--TEST-- +Test for retrieving encrypted data from numeric types columns using PDO::bindColumn +--DESCRIPTION-- +Test conversion from numeric types column to output of PDO::PARAM types +With or without Always Encrypted, conversion works if: +1. From any numeric type except for bigint column to PDO::PARAM_BOOL +2. From any numeric type except for bigint column to PDO::PARAM_INT +3. From any numeric type column to PDO::PARAM_STR +4. From any numeric type column to PDO::PARAM_LOB +--SKIPIF-- + +--FILE-- + $inputValues[0], "c_rand" => $inputValues[1])); + + // fetch by specifying PDO::PARAM_ types with PDO::bindColumn + $query = "SELECT c_det, c_rand FROM $tbname"; + foreach ($pdoParamTypes as $pdoParamType) { + $det = ""; + $rand = ""; + $stmt = $conn->prepare($query); + $stmt->execute(); + $stmt->bindColumn('c_det', $det, constant($pdoParamType)); + $stmt->bindColumn('c_rand', $rand, constant($pdoParamType)); + $row = $stmt->fetch(PDO::FETCH_BOUND); + + // check the case when fetching as PDO::PARAM_NULL + // with or without AE: should not work + if ($pdoParamType == "PDO::PARAM_NULL") { + if (!is_null($det) || !is_null($rand)) { + echo "Retrieving $dataType data as $pdoParamType should not be supported\n"; + } + // check the case when fetching as PDO::PARAM_BOOL or PDO::PARAM_INT + // with or without AE: should only not work with bigint + } else if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_INT") { + if ($dataType == "bigint") { + if (!is_null($det) || !is_null($rand)) { + echo "Retrieving $dataType data as $pdoParamType should not be supported\n"; + } + } else if ($dataType == "real") { + if (abs($det - $inputValues[0]) < $epsilon && abs($rand - $inputValues[1]) < $epsilon) { + echo "****Retrieving $dataType as $pdoParamType is supported****\n"; + } else { + echo "Retrieving $dataType as $pdoParamType fails\n"; + } + } else { + if ($det == $inputValues[0] && $rand == $inputValues[1]) { + echo "****Retrieving $dataType as $pdoParamType is supported****\n"; + } else { + echo "Retrieving $dataType as $pdoParamType fails\n"; + } + } + // check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_INT, PDO::PARAM_STR or PDO::PARAM_LOB + // with or without AE: should work + } else { + if ($dataType == "real") { + if (abs($det - $inputValues[0]) < $epsilon && abs($rand - $inputValues[1]) < $epsilon) { + echo "****Retrieving $dataType as $pdoParamType is supported****\n"; + } else { + echo "Retrieving $dataType as $pdoParamType fails\n"; + } + } else { + if ($det == $inputValues[0] && $rand == $inputValues[1]) { + echo "****Retrieving $dataType as $pdoParamType is supported****\n"; + } else { + echo "Retrieving $dataType as $pdoParamType fails\n"; + } + } + } + } + dropTable($conn, $tbname); + } + unset($stmt); + unset($conn); +} catch (PDOException $e) { + echo $e->getMessage(); +} +?> +--EXPECT-- +Testing bit: +****Retrieving bit as PDO::PARAM_BOOL is supported**** +****Retrieving bit as PDO::PARAM_INT is supported**** +****Retrieving bit as PDO::PARAM_STR is supported**** +****Retrieving bit as PDO::PARAM_LOB is supported**** + +Testing tinyint: +****Retrieving tinyint as PDO::PARAM_BOOL is supported**** +****Retrieving tinyint as PDO::PARAM_INT is supported**** +****Retrieving tinyint as PDO::PARAM_STR is supported**** +****Retrieving tinyint as PDO::PARAM_LOB is supported**** + +Testing smallint: +****Retrieving smallint as PDO::PARAM_BOOL is supported**** +****Retrieving smallint as PDO::PARAM_INT is supported**** +****Retrieving smallint as PDO::PARAM_STR is supported**** +****Retrieving smallint as PDO::PARAM_LOB is supported**** + +Testing int: +****Retrieving int as PDO::PARAM_BOOL is supported**** +****Retrieving int as PDO::PARAM_INT is supported**** +****Retrieving int as PDO::PARAM_STR is supported**** +****Retrieving int as PDO::PARAM_LOB is supported**** + +Testing bigint: +****Retrieving bigint as PDO::PARAM_STR is supported**** +****Retrieving bigint as PDO::PARAM_LOB is supported**** + +Testing real: +****Retrieving real as PDO::PARAM_BOOL is supported**** +****Retrieving real as PDO::PARAM_INT is supported**** +****Retrieving real as PDO::PARAM_STR is supported**** +****Retrieving real as PDO::PARAM_LOB is supported**** \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_binary_size.phpt b/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_binary_size.phpt new file mode 100644 index 00000000..5b6c64a5 --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_binary_size.phpt @@ -0,0 +1,159 @@ +--TEST-- +Test for inserting encrypted data into binary types columns with different sizes +--DESCRIPTION-- +Test conversions between different binary types of different sizes +With or without Always Encrypted, implicit conversion works if: +1. From input of PDO::PARAM_STR to a any binary column +2. From input of PDO::PARAM_LOB to a any binary column +--SKIPIF-- + +--FILE-- + new BindParamOp(1, $inputValues[0], $pdoParamType, 0, "PDO::SQLSRV_ENCODING_BINARY"), + "c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType, 0, "PDO::SQLSRV_ENCODING_BINARY")), "prepareBindParam", $r); + } else { + $stmt = insertRow($conn, $tbname, array("c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType), "c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType)), "prepareBindParam", $r); + } + + // check the case when inserting as PDO::PARAM_BOOL or PDO::PARAM_INT + // with or without AE: should not work + if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_INT") { + if ($r !== false) { + echo "Conversion from $pdoParamType to $typeFull should not be supported\n"; + } + // check the case when inserting as PDO::PARAM_NULL + // with AE: NULL is inserted + // without AE: insertion fails + } elseif ($pdoParamType == "PDO::PARAM_NULL") { + if (isAEConnected()) { + if ($r === false) { + echo "Conversion from $pdoParamType to $typeFull should be supported\n"; + } else { + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = $conn->query($sql); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if (!is_null($row['c_det']) && !is_null($row['c_rand'])) { + echo "Conversion from $pdoParamType to $typeFull should insert NULL\n"; + } + } + } else { + if ($r !== false) { + echo "Conversion from $pdoParamType to $typeFull should not be supported\n"; + } + } + // check the case when inserting as PDO::PARAM_STR or PDO::PARAM_LOB + // with or without AE: should work + } else { + if ($r === false) { + echo "Conversion from $pdoParamType to $typeFull should be supported\n"; + } else { + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = $conn->query($sql); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if (trim($row['c_det']) == $inputValues[0] && trim($row['c_rand']) == $inputValues[1]) { + echo "****Conversion from $pdoParamType to $typeFull is supported****\n"; + } else { + echo "Conversion from $pdoParamType to $typeFull causes data corruption\n"; + } + } + } + // cleanup + $conn->query("TRUNCATE TABLE $tbname"); + } + dropTable($conn, $tbname); + } + } + unset($stmt); + unset($conn); +} catch (PDOException $e) { + echo $e->getMessage(); +} +?> +--EXPECT-- +Testing binary(2): +****Conversion from PDO::PARAM_STR to binary(2) is supported**** +****Conversion from PDO::PARAM_LOB to binary(2) is supported**** + +Testing binary(8): +****Conversion from PDO::PARAM_STR to binary(8) is supported**** +****Conversion from PDO::PARAM_LOB to binary(8) is supported**** + +Testing binary(64): +****Conversion from PDO::PARAM_STR to binary(64) is supported**** +****Conversion from PDO::PARAM_LOB to binary(64) is supported**** + +Testing binary(512): +****Conversion from PDO::PARAM_STR to binary(512) is supported**** +****Conversion from PDO::PARAM_LOB to binary(512) is supported**** + +Testing binary(4000): +****Conversion from PDO::PARAM_STR to binary(4000) is supported**** +****Conversion from PDO::PARAM_LOB to binary(4000) is supported**** + +Testing varbinary(2): +****Conversion from PDO::PARAM_STR to varbinary(2) is supported**** +****Conversion from PDO::PARAM_LOB to varbinary(2) is supported**** + +Testing varbinary(8): +****Conversion from PDO::PARAM_STR to varbinary(8) is supported**** +****Conversion from PDO::PARAM_LOB to varbinary(8) is supported**** + +Testing varbinary(64): +****Conversion from PDO::PARAM_STR to varbinary(64) is supported**** +****Conversion from PDO::PARAM_LOB to varbinary(64) is supported**** + +Testing varbinary(512): +****Conversion from PDO::PARAM_STR to varbinary(512) is supported**** +****Conversion from PDO::PARAM_LOB to varbinary(512) is supported**** + +Testing varbinary(4000): +****Conversion from PDO::PARAM_STR to varbinary(4000) is supported**** +****Conversion from PDO::PARAM_LOB to varbinary(4000) is supported**** + +Testing varbinary(max): +****Conversion from PDO::PARAM_STR to varbinary(max) is supported**** +****Conversion from PDO::PARAM_LOB to varbinary(max) is supported**** + +Testing varbinary(max): +****Conversion from PDO::PARAM_STR to varbinary(max) is supported**** +****Conversion from PDO::PARAM_LOB to varbinary(max) is supported**** + +Testing varbinary(max): +****Conversion from PDO::PARAM_STR to varbinary(max) is supported**** +****Conversion from PDO::PARAM_LOB to varbinary(max) is supported**** + +Testing varbinary(max): +****Conversion from PDO::PARAM_STR to varbinary(max) is supported**** +****Conversion from PDO::PARAM_LOB to varbinary(max) is supported**** + +Testing varbinary(max): +****Conversion from PDO::PARAM_STR to varbinary(max) is supported**** +****Conversion from PDO::PARAM_LOB to varbinary(max) is supported**** \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_char_size.phpt b/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_char_size.phpt new file mode 100644 index 00000000..9adfb606 --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_char_size.phpt @@ -0,0 +1,190 @@ +--TEST-- +Test for inserting encrypted data into char types columns with different sizes +--DESCRIPTION-- +Test conversions between different char types of different sizes +With or without Always Encrypted, implicit conversion works if: +1. From input of PDO::PARAM_BOOL to any char column +2. From input of PDO::PARAM_INT to any char column +3. From input of PDO::PARAM_STR to any char column +4. From input of PDO::PARAM_LOB to any char column +--SKIPIF-- + +--FILE-- + new BindParamOp(1, $input, $pdoParamType)), "prepareBindParam", $r); + + // check the case when inserting as PDO::PARAM_NULL + // with or without AE: NULL is inserted + if ($pdoParamType == "PDO::PARAM_NULL") { + if ($r === false) { + echo "Conversion from $pdoParamType to $typeFull should be supported\n"; + } else { + $sql = "SELECT c1 FROM $tbname"; + $stmt = $conn->query($sql); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if (!is_null($row['c1'])) { + echo "Conversion from $pdoParamType to $typeFull should insert NULL\n"; + } + } + // check the case when inserting as PDO::PARAM_BOOL, PDO::PARAM_INT, PDO::PARAM_STR or PDO{{PARAM_LOB + // with or without AE: should work + } else { + $sql = "SELECT c1 FROM $tbname"; + $stmt = $conn->query($sql); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if (strlen($row['c1']) == $m) { + echo "****Conversion from $pdoParamType to $typeFull is supported****\n"; + } else { + echo "Conversion from $pdoParamType to $typeFull causes data corruption\n"; + } + } + // cleanup + $conn->query("TRUNCATE TABLE $tbname"); + } + dropTable($conn, $tbname); + } + } + unset($stmt); + unset($conn); +} catch (PDOException $e) { + echo $e->getMessage(); +} +?> +--EXPECT-- +Testing char(1): +****Conversion from PDO::PARAM_BOOL to char(1) is supported**** +****Conversion from PDO::PARAM_INT to char(1) is supported**** +****Conversion from PDO::PARAM_STR to char(1) is supported**** +****Conversion from PDO::PARAM_LOB to char(1) is supported**** + +Testing char(8): +****Conversion from PDO::PARAM_BOOL to char(8) is supported**** +****Conversion from PDO::PARAM_INT to char(8) is supported**** +****Conversion from PDO::PARAM_STR to char(8) is supported**** +****Conversion from PDO::PARAM_LOB to char(8) is supported**** + +Testing char(64): +****Conversion from PDO::PARAM_BOOL to char(64) is supported**** +****Conversion from PDO::PARAM_INT to char(64) is supported**** +****Conversion from PDO::PARAM_STR to char(64) is supported**** +****Conversion from PDO::PARAM_LOB to char(64) is supported**** + +Testing char(512): +****Conversion from PDO::PARAM_BOOL to char(512) is supported**** +****Conversion from PDO::PARAM_INT to char(512) is supported**** +****Conversion from PDO::PARAM_STR to char(512) is supported**** +****Conversion from PDO::PARAM_LOB to char(512) is supported**** + +Testing char(4096): +****Conversion from PDO::PARAM_BOOL to char(4096) is supported**** +****Conversion from PDO::PARAM_INT to char(4096) is supported**** +****Conversion from PDO::PARAM_STR to char(4096) is supported**** +****Conversion from PDO::PARAM_LOB to char(4096) is supported**** + +Testing char(8000): +****Conversion from PDO::PARAM_BOOL to char(8000) is supported**** +****Conversion from PDO::PARAM_INT to char(8000) is supported**** +****Conversion from PDO::PARAM_STR to char(8000) is supported**** +****Conversion from PDO::PARAM_LOB to char(8000) is supported**** + +Testing varchar(1): +****Conversion from PDO::PARAM_BOOL to varchar(1) is supported**** +****Conversion from PDO::PARAM_INT to varchar(1) is supported**** +****Conversion from PDO::PARAM_STR to varchar(1) is supported**** +****Conversion from PDO::PARAM_LOB to varchar(1) is supported**** + +Testing varchar(8): +****Conversion from PDO::PARAM_BOOL to varchar(8) is supported**** +****Conversion from PDO::PARAM_INT to varchar(8) is supported**** +****Conversion from PDO::PARAM_STR to varchar(8) is supported**** +****Conversion from PDO::PARAM_LOB to varchar(8) is supported**** + +Testing varchar(64): +****Conversion from PDO::PARAM_BOOL to varchar(64) is supported**** +****Conversion from PDO::PARAM_INT to varchar(64) is supported**** +****Conversion from PDO::PARAM_STR to varchar(64) is supported**** +****Conversion from PDO::PARAM_LOB to varchar(64) is supported**** + +Testing varchar(512): +****Conversion from PDO::PARAM_BOOL to varchar(512) is supported**** +****Conversion from PDO::PARAM_INT to varchar(512) is supported**** +****Conversion from PDO::PARAM_STR to varchar(512) is supported**** +****Conversion from PDO::PARAM_LOB to varchar(512) is supported**** + +Testing varchar(4096): +****Conversion from PDO::PARAM_BOOL to varchar(4096) is supported**** +****Conversion from PDO::PARAM_INT to varchar(4096) is supported**** +****Conversion from PDO::PARAM_STR to varchar(4096) is supported**** +****Conversion from PDO::PARAM_LOB to varchar(4096) is supported**** + +Testing varchar(8000): +****Conversion from PDO::PARAM_BOOL to varchar(8000) is supported**** +****Conversion from PDO::PARAM_INT to varchar(8000) is supported**** +****Conversion from PDO::PARAM_STR to varchar(8000) is supported**** +****Conversion from PDO::PARAM_LOB to varchar(8000) is supported**** + +Testing varchar(max): +****Conversion from PDO::PARAM_BOOL to varchar(max) is supported**** +****Conversion from PDO::PARAM_INT to varchar(max) is supported**** +****Conversion from PDO::PARAM_STR to varchar(max) is supported**** +****Conversion from PDO::PARAM_LOB to varchar(max) is supported**** + +Testing varchar(max): +****Conversion from PDO::PARAM_BOOL to varchar(max) is supported**** +****Conversion from PDO::PARAM_INT to varchar(max) is supported**** +****Conversion from PDO::PARAM_STR to varchar(max) is supported**** +****Conversion from PDO::PARAM_LOB to varchar(max) is supported**** + +Testing varchar(max): +****Conversion from PDO::PARAM_BOOL to varchar(max) is supported**** +****Conversion from PDO::PARAM_INT to varchar(max) is supported**** +****Conversion from PDO::PARAM_STR to varchar(max) is supported**** +****Conversion from PDO::PARAM_LOB to varchar(max) is supported**** + +Testing varchar(max): +****Conversion from PDO::PARAM_BOOL to varchar(max) is supported**** +****Conversion from PDO::PARAM_INT to varchar(max) is supported**** +****Conversion from PDO::PARAM_STR to varchar(max) is supported**** +****Conversion from PDO::PARAM_LOB to varchar(max) is supported**** + +Testing varchar(max): +****Conversion from PDO::PARAM_BOOL to varchar(max) is supported**** +****Conversion from PDO::PARAM_INT to varchar(max) is supported**** +****Conversion from PDO::PARAM_STR to varchar(max) is supported**** +****Conversion from PDO::PARAM_LOB to varchar(max) is supported**** + +Testing varchar(max): +****Conversion from PDO::PARAM_BOOL to varchar(max) is supported**** +****Conversion from PDO::PARAM_INT to varchar(max) is supported**** +****Conversion from PDO::PARAM_STR to varchar(max) is supported**** +****Conversion from PDO::PARAM_LOB to varchar(max) is supported**** \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_datetime.phpt b/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_datetime.phpt index df3fbfc5..72c1ef3a 100644 --- a/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_datetime.phpt +++ b/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_datetime.phpt @@ -1,7 +1,12 @@ --TEST-- -Test for inserting and retrieving encrypted data of datetime types +Test for inserting encrypted data into datetime types columns --DESCRIPTION-- -Use PDOstatement::bindParam with all PDO::PARAM_ types +Test conversions between different datetime types +With or without Always Encrypted, implicit conversion works if: +1. From input of PDO::PARAM_BOOL to a any datetime column +2. From input of PDO::PARAM_INT to a any datetime column +3. From input of PDO::PARAM_STR to a any datetime column +4. From input of PDO::PARAM_LOB to a any datetime column --SKIPIF-- --FILE-- @@ -9,28 +14,48 @@ Use PDOstatement::bindParam with all PDO::PARAM_ types require_once("MsCommon_mid-refactor.inc"); require_once("AEData.inc"); -$dataTypes = array( "date", "datetime", "datetime2", "smalldatetime", "time", "datetimeoffset" ); +$dataTypes = array( "date", "datetime", "smalldatetime"); + try { $conn = connect(); foreach ($dataTypes as $dataType) { echo "\nTesting $dataType:\n"; - // create table - $tbname = getTableName(); + // create table containing date, datetime or smalldatetime columns + $tbname = "test_" . $dataType; $colMetaArr = array( new ColumnMeta($dataType, "c_det"), new ColumnMeta($dataType, "c_rand", null, "randomized")); createTable($conn, $tbname, $colMetaArr); - // prepare statement for inserting into table + // insert by specifying PDO::PARAM_ types foreach ($pdoParamTypes as $pdoParamType) { - // insert a row $inputValues = array_slice(${explode("(", $dataType)[0] . "_params"}, 1, 2); $r; $stmt = insertRow($conn, $tbname, array( "c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType), "c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType)), "prepareBindParam", $r); - if ($r === false) { - isIncompatibleTypesError($stmt, $dataType, $pdoParamType); + + // check the case when inserting as PDO::PARAM_NULL + // with or without AE: NULL is inserted + if ($pdoParamType == "PDO::PARAM_NULL") { + if ($r === false) { + echo "Conversion from $pdoParamType to $dataType should be supported\n"; + } else { + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = $conn->query($sql); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if (!is_null($row['c_det']) || !is_null($row['c_rand'])) { + echo "Conversion from $pdoParamType to $dataType should insert NULL\n"; + } + } + // check the case when inserting as PDO::PARAM_BOOL, PDO::PARAM_INT, PDO::PARAM_STR or PDO::PARAM_LOB + // with or without AE: should work } else { - echo "****PDO param type $pdoParamType is compatible with encrypted $dataType****\n"; - fetchAll($conn, $tbname); + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = $conn->query($sql); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if (strpos($row['c_det'], $inputValues[0]) !== false && strpos($row['c_rand'], $inputValues[1]) !== false) { + echo "****Conversion from $pdoParamType to $dataType is supported****\n"; + } else { + echo "Conversion from $pdoParamType to $dataType causes data corruption\n"; + } } $conn->query("TRUNCATE TABLE $tbname"); } @@ -43,105 +68,20 @@ try { } ?> --EXPECT-- - Testing date: -****PDO param type PDO::PARAM_BOOL is compatible with encrypted date**** -c_det: 0001-01-01 -c_rand: 9999-12-31 -****PDO param type PDO::PARAM_NULL is compatible with encrypted date**** -c_det: -c_rand: -****PDO param type PDO::PARAM_INT is compatible with encrypted date**** -c_det: 0001-01-01 -c_rand: 9999-12-31 -****PDO param type PDO::PARAM_STR is compatible with encrypted date**** -c_det: 0001-01-01 -c_rand: 9999-12-31 -****PDO param type PDO::PARAM_LOB is compatible with encrypted date**** -c_det: 0001-01-01 -c_rand: 9999-12-31 +****Conversion from PDO::PARAM_BOOL to date is supported**** +****Conversion from PDO::PARAM_INT to date is supported**** +****Conversion from PDO::PARAM_STR to date is supported**** +****Conversion from PDO::PARAM_LOB to date is supported**** Testing datetime: -****PDO param type PDO::PARAM_BOOL is compatible with encrypted datetime**** -c_det: 1753-01-01 00:00:00.000 -c_rand: 9999-12-31 23:59:59.997 -****PDO param type PDO::PARAM_NULL is compatible with encrypted datetime**** -c_det: -c_rand: -****PDO param type PDO::PARAM_INT is compatible with encrypted datetime**** -c_det: 1753-01-01 00:00:00.000 -c_rand: 9999-12-31 23:59:59.997 -****PDO param type PDO::PARAM_STR is compatible with encrypted datetime**** -c_det: 1753-01-01 00:00:00.000 -c_rand: 9999-12-31 23:59:59.997 -****PDO param type PDO::PARAM_LOB is compatible with encrypted datetime**** -c_det: 1753-01-01 00:00:00.000 -c_rand: 9999-12-31 23:59:59.997 - -Testing datetime2: -****PDO param type PDO::PARAM_BOOL is compatible with encrypted datetime2**** -c_det: 0001-01-01 00:00:00.0000000 -c_rand: 9999-12-31 23:59:59.9999999 -****PDO param type PDO::PARAM_NULL is compatible with encrypted datetime2**** -c_det: -c_rand: -****PDO param type PDO::PARAM_INT is compatible with encrypted datetime2**** -c_det: 0001-01-01 00:00:00.0000000 -c_rand: 9999-12-31 23:59:59.9999999 -****PDO param type PDO::PARAM_STR is compatible with encrypted datetime2**** -c_det: 0001-01-01 00:00:00.0000000 -c_rand: 9999-12-31 23:59:59.9999999 -****PDO param type PDO::PARAM_LOB is compatible with encrypted datetime2**** -c_det: 0001-01-01 00:00:00.0000000 -c_rand: 9999-12-31 23:59:59.9999999 +****Conversion from PDO::PARAM_BOOL to datetime is supported**** +****Conversion from PDO::PARAM_INT to datetime is supported**** +****Conversion from PDO::PARAM_STR to datetime is supported**** +****Conversion from PDO::PARAM_LOB to datetime is supported**** Testing smalldatetime: -****PDO param type PDO::PARAM_BOOL is compatible with encrypted smalldatetime**** -c_det: 1900-01-01 00:00:00 -c_rand: 2079-06-05 23:59:00 -****PDO param type PDO::PARAM_NULL is compatible with encrypted smalldatetime**** -c_det: -c_rand: -****PDO param type PDO::PARAM_INT is compatible with encrypted smalldatetime**** -c_det: 1900-01-01 00:00:00 -c_rand: 2079-06-05 23:59:00 -****PDO param type PDO::PARAM_STR is compatible with encrypted smalldatetime**** -c_det: 1900-01-01 00:00:00 -c_rand: 2079-06-05 23:59:00 -****PDO param type PDO::PARAM_LOB is compatible with encrypted smalldatetime**** -c_det: 1900-01-01 00:00:00 -c_rand: 2079-06-05 23:59:00 - -Testing time: -****PDO param type PDO::PARAM_BOOL is compatible with encrypted time**** -c_det: 00:00:00.0000000 -c_rand: 23:59:59.9999999 -****PDO param type PDO::PARAM_NULL is compatible with encrypted time**** -c_det: -c_rand: -****PDO param type PDO::PARAM_INT is compatible with encrypted time**** -c_det: 00:00:00.0000000 -c_rand: 23:59:59.9999999 -****PDO param type PDO::PARAM_STR is compatible with encrypted time**** -c_det: 00:00:00.0000000 -c_rand: 23:59:59.9999999 -****PDO param type PDO::PARAM_LOB is compatible with encrypted time**** -c_det: 00:00:00.0000000 -c_rand: 23:59:59.9999999 - -Testing datetimeoffset: -****PDO param type PDO::PARAM_BOOL is compatible with encrypted datetimeoffset**** -c_det: 0001-01-01 00:00:00.0000000 -14:00 -c_rand: 9999-12-31 23:59:59.9999999 +14:00 -****PDO param type PDO::PARAM_NULL is compatible with encrypted datetimeoffset**** -c_det: -c_rand: -****PDO param type PDO::PARAM_INT is compatible with encrypted datetimeoffset**** -c_det: 0001-01-01 00:00:00.0000000 -14:00 -c_rand: 9999-12-31 23:59:59.9999999 +14:00 -****PDO param type PDO::PARAM_STR is compatible with encrypted datetimeoffset**** -c_det: 0001-01-01 00:00:00.0000000 -14:00 -c_rand: 9999-12-31 23:59:59.9999999 +14:00 -****PDO param type PDO::PARAM_LOB is compatible with encrypted datetimeoffset**** -c_det: 0001-01-01 00:00:00.0000000 -14:00 -c_rand: 9999-12-31 23:59:59.9999999 +14:00 +****Conversion from PDO::PARAM_BOOL to smalldatetime is supported**** +****Conversion from PDO::PARAM_INT to smalldatetime is supported**** +****Conversion from PDO::PARAM_STR to smalldatetime is supported**** +****Conversion from PDO::PARAM_LOB to smalldatetime is supported**** \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_datetime_precision.phpt b/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_datetime_precision.phpt new file mode 100644 index 00000000..a3db5c7f --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_datetime_precision.phpt @@ -0,0 +1,175 @@ +--TEST-- +Test for inserting encrypted data into datetime types with different precisions columns +--DESCRIPTION-- +Test conversions between different datetime types +With or without Always Encrypted, implicit conversion works if: +1. From input of PDO::PARAM_BOOL to a any datetime column +2. From input of PDO::PARAM_INT to a any datetime column +3. From input of PDO::PARAM_STR to a any datetime column +4. From input of PDO::PARAM_LOB to a any datetime column +--SKIPIF-- + +--FILE-- + array("0001-01-01 00:00:00", "9999-12-31 23:59:59"), + "datetimeoffset" => array("0001-01-01 00:00:00 -14:00", "9999-12-31 23:59:59 +14:00"), + "time" => array("00:00:00", "23:59:59")); + +try { + $conn = connect("", array(), PDO::ERRMODE_SILENT); + foreach ($dataTypes as $dataType) { + foreach ($precisions as $m) { + // add $m number of decimal digits to the some input values + $inputValues[0] = $inputValuesInit[$dataType][0]; + $inputValues[1] = $inputValuesInit[$dataType][1]; + if ($m != 0) { + if ($dataType == "datetime2") { + $inputValues[1] .= "." . str_repeat("9", $m); + } else if ($dataType == "datetimeoffset") { + $dtoffsetPieces = explode(" ", $inputValues[1]); + $inputValues[1] = $dtoffsetPieces[0] . " " . $dtoffsetPieces[1] . "." . str_repeat("9", $m) . " " . $dtoffsetPieces[2]; + } else if ($dataType == "time") { + $inputValues[0] .= "." . str_repeat("0", $m); + $inputValues[1] .= "." . str_repeat("9", $m); + } + } + $typeFull = "$dataType($m)"; + echo "\nTesting $typeFull:\n"; + + //create table containing datetime2(m), datetimeoffset(m), or time(m) columns + $tbname = "test_" . $dataType . $m; + $colMetaArr = array(new ColumnMeta($typeFull, "c_det"), new ColumnMeta($typeFull, "c_rand", null, "randomized")); + createTable($conn, $tbname, $colMetaArr); + + // insert by specifying PDO::PARAM_ types + foreach ($pdoParamTypes as $pdoParamType) { + $r; + $stmt = insertRow($conn, $tbname, array( "c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType), "c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType)), "prepareBindParam", $r); + + // check the case when inserting as PDO::PARAM_NULL + // with or without AE: NULL is inserted + if ($pdoParamType == "PDO::PARAM_NULL") { + if ($r === false) { + echo "Conversion from $pdoParamType to $typeFull should be supported\n"; + } else { + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = $conn->query($sql); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if (!is_null($row['c_det']) || !is_null($row['c_rand'])) { + echo "Conversion from $pdoParamType to $typeFull should insert NULL\n"; + } + } + // check the case when inserting as PDO::PARAM_BOOL, PDO::PARAM_INT, PDO::PARAM_STR or PDO::PARAM_LOB + // with or without AE: should work + } else { + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = $conn->query($sql); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if (compareDate($row['c_det'], $inputValues[0], $dataType) && compareDate($row['c_rand'], $inputValues[1], $dataType)) { + echo "****Conversion from $pdoParamType to $typeFull is supported****\n"; + } else { + echo "Conversion from $pdoParamType to $typeFull causes data corruption\n"; + } + } + $conn->query("TRUNCATE TABLE $tbname"); + } + dropTable($conn, $tbname); + } + } + unset($stmt); + unset($conn); +} catch (PDOException $e) { + echo $e->getMessage(); +} +?> +--EXPECT-- +Testing datetime2(1): +****Conversion from PDO::PARAM_BOOL to datetime2(1) is supported**** +****Conversion from PDO::PARAM_INT to datetime2(1) is supported**** +****Conversion from PDO::PARAM_STR to datetime2(1) is supported**** +****Conversion from PDO::PARAM_LOB to datetime2(1) is supported**** + +Testing datetime2(2): +****Conversion from PDO::PARAM_BOOL to datetime2(2) is supported**** +****Conversion from PDO::PARAM_INT to datetime2(2) is supported**** +****Conversion from PDO::PARAM_STR to datetime2(2) is supported**** +****Conversion from PDO::PARAM_LOB to datetime2(2) is supported**** + +Testing datetime2(4): +****Conversion from PDO::PARAM_BOOL to datetime2(4) is supported**** +****Conversion from PDO::PARAM_INT to datetime2(4) is supported**** +****Conversion from PDO::PARAM_STR to datetime2(4) is supported**** +****Conversion from PDO::PARAM_LOB to datetime2(4) is supported**** + +Testing datetime2(7): +****Conversion from PDO::PARAM_BOOL to datetime2(7) is supported**** +****Conversion from PDO::PARAM_INT to datetime2(7) is supported**** +****Conversion from PDO::PARAM_STR to datetime2(7) is supported**** +****Conversion from PDO::PARAM_LOB to datetime2(7) is supported**** + +Testing datetimeoffset(1): +****Conversion from PDO::PARAM_BOOL to datetimeoffset(1) is supported**** +****Conversion from PDO::PARAM_INT to datetimeoffset(1) is supported**** +****Conversion from PDO::PARAM_STR to datetimeoffset(1) is supported**** +****Conversion from PDO::PARAM_LOB to datetimeoffset(1) is supported**** + +Testing datetimeoffset(2): +****Conversion from PDO::PARAM_BOOL to datetimeoffset(2) is supported**** +****Conversion from PDO::PARAM_INT to datetimeoffset(2) is supported**** +****Conversion from PDO::PARAM_STR to datetimeoffset(2) is supported**** +****Conversion from PDO::PARAM_LOB to datetimeoffset(2) is supported**** + +Testing datetimeoffset(4): +****Conversion from PDO::PARAM_BOOL to datetimeoffset(4) is supported**** +****Conversion from PDO::PARAM_INT to datetimeoffset(4) is supported**** +****Conversion from PDO::PARAM_STR to datetimeoffset(4) is supported**** +****Conversion from PDO::PARAM_LOB to datetimeoffset(4) is supported**** + +Testing datetimeoffset(7): +****Conversion from PDO::PARAM_BOOL to datetimeoffset(7) is supported**** +****Conversion from PDO::PARAM_INT to datetimeoffset(7) is supported**** +****Conversion from PDO::PARAM_STR to datetimeoffset(7) is supported**** +****Conversion from PDO::PARAM_LOB to datetimeoffset(7) is supported**** + +Testing time(1): +****Conversion from PDO::PARAM_BOOL to time(1) is supported**** +****Conversion from PDO::PARAM_INT to time(1) is supported**** +****Conversion from PDO::PARAM_STR to time(1) is supported**** +****Conversion from PDO::PARAM_LOB to time(1) is supported**** + +Testing time(2): +****Conversion from PDO::PARAM_BOOL to time(2) is supported**** +****Conversion from PDO::PARAM_INT to time(2) is supported**** +****Conversion from PDO::PARAM_STR to time(2) is supported**** +****Conversion from PDO::PARAM_LOB to time(2) is supported**** + +Testing time(4): +****Conversion from PDO::PARAM_BOOL to time(4) is supported**** +****Conversion from PDO::PARAM_INT to time(4) is supported**** +****Conversion from PDO::PARAM_STR to time(4) is supported**** +****Conversion from PDO::PARAM_LOB to time(4) is supported**** + +Testing time(7): +****Conversion from PDO::PARAM_BOOL to time(7) is supported**** +****Conversion from PDO::PARAM_INT to time(7) is supported**** +****Conversion from PDO::PARAM_STR to time(7) is supported**** +****Conversion from PDO::PARAM_LOB to time(7) is supported**** \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_decimal_precision.phpt b/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_decimal_precision.phpt new file mode 100644 index 00000000..4295c0c2 --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_decimal_precision.phpt @@ -0,0 +1,294 @@ +--TEST-- +Test for inserting encrypted data into decimal types columns +--DESCRIPTION-- +Test conversions between different decimal types +With Always Encrypted, implicit conversion works if: +1. From input of PDO::PARAM_BOOL to a any decimal column +2. From input of PDO::PARAM_INT to a any decimal column +3. From input of PDO::PARAM_STR to a any decimal column +4. From input of PDO::PARAM_LOB to a any decimal column +Without Always Encrypted, all of the above should work except for: +1. From input of PDO::PARAM_STR to a decimal column and the input has more than 14 digits to the left of the decimal +--SKIPIF-- + +--FILE-- + array(0, 1), + 4 => array(0, 1, 4), + 16 => array(0, 1, 4, 16), + 38 => array(0, 1, 4, 16, 38)); +$inputValuesInit = array(92233720368547758089223372036854775808, -92233720368547758089223372036854775808); +$inputPrecision = 38; + +try { + $conn = connect("", array(), PDO::ERRMODE_SILENT); + foreach ($dataTypes as $dataType) { + foreach ($precisions as $m1 => $scales) { + foreach ($scales as $m2) { + // change the number of integers in the input values to be $m1 - $m2 + $precDiff = $inputPrecision - ($m1 - $m2); + $inputValues = $inputValuesInit; + foreach ($inputValues as &$inputValue) { + $inputValue = $inputValue / pow(10, $precDiff); + } + + // compute the epsilon for comparing doubles + // float in PHP only has a precision of roughtly 14 digits: http://php.net/manual/en/language.types.float.php + $epsilon; + if ($m1 < 14) { + $epsilon = pow(10, $m2 * -1); + } else { + $numint = $m1 - $m2; + if ($numint < 14) { + $epsilon = pow(10, (14 - $numint) * -1); + } else { + $epsilon = pow(10, $numint - 14); + } + } + + + $typeFull = "$dataType($m1, $m2)"; + echo "\nTesting $typeFull:\n"; + + // create table containing decimal(m1, m2) or numeric(m1, m2) columns + $tbname = "test_" . $dataType . $m1 . $m2; + $colMetaArr = array(new ColumnMeta($typeFull, "c_det"), new ColumnMeta($typeFull, "c_rand", null, "randomized")); + createTable($conn, $tbname, $colMetaArr); + + // insert by specifying PDO::PARAM_ types + foreach ($pdoParamTypes as $pdoParamType) { + $r; + $stmt = insertRow($conn, $tbname, array("c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType), "c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType)), "prepareBindParam", $r); + + // check the case when inserting as PDO::PARAM_NULL + // with or without AE: NULL is inserted + if ($pdoParamType == "PDO::PARAM_NULL") { + if ($r === false) { + echo "Conversion from $pdoParamType to $typeFull should be supported\n"; + } else { + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = $conn->query($sql); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if (!is_null($row['c_det']) || !is_null($row['c_rand'])) { + echo "NULL should have been inserted with $pdoParamType\n"; + } + } + // check the case when inserting as PDO::PARAM_STR and the input has more than 14 digits to the left of the decimal + // with AE: should work + // without AE: should not work + // when the input has greater than 14 digits to the left of the decimal, the double is translated by PHP to scientific notation + // inserting a scientific notation string fails + } elseif ($pdoParamType == "PDO::PARAM_STR" && $m1 - $m2 > 14) { + if (!isAEConnected()) { + if ($r !== false) { + echo "PDO param type $pdoParamType should not be compatible with $typeFull when the number of integers is greater than 14\n"; + } + } else { + if ($r === false) { + echo "Conversion from $pdoParamType to $typeFull should be supported\n"; + } + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = $conn->query($sql); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if (abs($row['c_det'] - $inputValues[0]) > $epsilon || + abs($row['c_rand'] - $inputValues[1]) > $epsilon) { + echo "Conversion from $pdoParamType to $typeFull causes data corruption\n"; + } + } + // check the case when inserting as PDO::PARAM_STR with input less than 14 digits to the left of the decimal + // and PDO::PARAM_BOOL, PDO::PARAM_INT or PDO::PARAM_LOB + // with or without AE: should work + } else { + if ($r === false) { + echo "Conversion from $pdoParamType to $typeFull should be supported\n"; + } + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = $conn->query($sql); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if (abs($row['c_det'] - $inputValues[0]) > $epsilon || + abs($row['c_rand'] - $inputValues[1]) > $epsilon) { + // TODO: this is a workaround for the test to pass!!!!! + // with AE, doubles cannot be inserted into a decimal(38, 38) column + // remove the following if block to see the bug + // for more information see VSO task 2723 + if (isAEConnected() && $m1 == 38 && $m2 == 38) { + echo "****Conversion from $pdoParamType to $typeFull is supported****\n"; + } else { + echo "Conversion from $pdoParamType to $typeFull causes data corruption\n"; + } + } else { + echo "****Conversion from $pdoParamType to $typeFull is supported****\n"; + } + } + $conn->query("TRUNCATE TABLE $tbname"); + } + dropTable($conn, $tbname); + } + } + } + unset($stmt); + unset($conn); +} catch (PDOException $e) { + echo $e->getMessage(); +} +?> +--EXPECT-- +Testing decimal(1, 0): +****Conversion from PDO::PARAM_BOOL to decimal(1, 0) is supported**** +****Conversion from PDO::PARAM_INT to decimal(1, 0) is supported**** +****Conversion from PDO::PARAM_STR to decimal(1, 0) is supported**** +****Conversion from PDO::PARAM_LOB to decimal(1, 0) is supported**** + +Testing decimal(1, 1): +****Conversion from PDO::PARAM_BOOL to decimal(1, 1) is supported**** +****Conversion from PDO::PARAM_INT to decimal(1, 1) is supported**** +****Conversion from PDO::PARAM_STR to decimal(1, 1) is supported**** +****Conversion from PDO::PARAM_LOB to decimal(1, 1) is supported**** + +Testing decimal(4, 0): +****Conversion from PDO::PARAM_BOOL to decimal(4, 0) is supported**** +****Conversion from PDO::PARAM_INT to decimal(4, 0) is supported**** +****Conversion from PDO::PARAM_STR to decimal(4, 0) is supported**** +****Conversion from PDO::PARAM_LOB to decimal(4, 0) is supported**** + +Testing decimal(4, 1): +****Conversion from PDO::PARAM_BOOL to decimal(4, 1) is supported**** +****Conversion from PDO::PARAM_INT to decimal(4, 1) is supported**** +****Conversion from PDO::PARAM_STR to decimal(4, 1) is supported**** +****Conversion from PDO::PARAM_LOB to decimal(4, 1) is supported**** + +Testing decimal(4, 4): +****Conversion from PDO::PARAM_BOOL to decimal(4, 4) is supported**** +****Conversion from PDO::PARAM_INT to decimal(4, 4) is supported**** +****Conversion from PDO::PARAM_STR to decimal(4, 4) is supported**** +****Conversion from PDO::PARAM_LOB to decimal(4, 4) is supported**** + +Testing decimal(16, 0): +****Conversion from PDO::PARAM_BOOL to decimal(16, 0) is supported**** +****Conversion from PDO::PARAM_INT to decimal(16, 0) is supported**** +****Conversion from PDO::PARAM_LOB to decimal(16, 0) is supported**** + +Testing decimal(16, 1): +****Conversion from PDO::PARAM_BOOL to decimal(16, 1) is supported**** +****Conversion from PDO::PARAM_INT to decimal(16, 1) is supported**** +****Conversion from PDO::PARAM_LOB to decimal(16, 1) is supported**** + +Testing decimal(16, 4): +****Conversion from PDO::PARAM_BOOL to decimal(16, 4) is supported**** +****Conversion from PDO::PARAM_INT to decimal(16, 4) is supported**** +****Conversion from PDO::PARAM_STR to decimal(16, 4) is supported**** +****Conversion from PDO::PARAM_LOB to decimal(16, 4) is supported**** + +Testing decimal(16, 16): +****Conversion from PDO::PARAM_BOOL to decimal(16, 16) is supported**** +****Conversion from PDO::PARAM_INT to decimal(16, 16) is supported**** +****Conversion from PDO::PARAM_STR to decimal(16, 16) is supported**** +****Conversion from PDO::PARAM_LOB to decimal(16, 16) is supported**** + +Testing decimal(38, 0): +****Conversion from PDO::PARAM_BOOL to decimal(38, 0) is supported**** +****Conversion from PDO::PARAM_INT to decimal(38, 0) is supported**** +****Conversion from PDO::PARAM_LOB to decimal(38, 0) is supported**** + +Testing decimal(38, 1): +****Conversion from PDO::PARAM_BOOL to decimal(38, 1) is supported**** +****Conversion from PDO::PARAM_INT to decimal(38, 1) is supported**** +****Conversion from PDO::PARAM_LOB to decimal(38, 1) is supported**** + +Testing decimal(38, 4): +****Conversion from PDO::PARAM_BOOL to decimal(38, 4) is supported**** +****Conversion from PDO::PARAM_INT to decimal(38, 4) is supported**** +****Conversion from PDO::PARAM_LOB to decimal(38, 4) is supported**** + +Testing decimal(38, 16): +****Conversion from PDO::PARAM_BOOL to decimal(38, 16) is supported**** +****Conversion from PDO::PARAM_INT to decimal(38, 16) is supported**** +****Conversion from PDO::PARAM_LOB to decimal(38, 16) is supported**** + +Testing decimal(38, 38): +****Conversion from PDO::PARAM_BOOL to decimal(38, 38) is supported**** +****Conversion from PDO::PARAM_INT to decimal(38, 38) is supported**** +****Conversion from PDO::PARAM_STR to decimal(38, 38) is supported**** +****Conversion from PDO::PARAM_LOB to decimal(38, 38) is supported**** + +Testing numeric(1, 0): +****Conversion from PDO::PARAM_BOOL to numeric(1, 0) is supported**** +****Conversion from PDO::PARAM_INT to numeric(1, 0) is supported**** +****Conversion from PDO::PARAM_STR to numeric(1, 0) is supported**** +****Conversion from PDO::PARAM_LOB to numeric(1, 0) is supported**** + +Testing numeric(1, 1): +****Conversion from PDO::PARAM_BOOL to numeric(1, 1) is supported**** +****Conversion from PDO::PARAM_INT to numeric(1, 1) is supported**** +****Conversion from PDO::PARAM_STR to numeric(1, 1) is supported**** +****Conversion from PDO::PARAM_LOB to numeric(1, 1) is supported**** + +Testing numeric(4, 0): +****Conversion from PDO::PARAM_BOOL to numeric(4, 0) is supported**** +****Conversion from PDO::PARAM_INT to numeric(4, 0) is supported**** +****Conversion from PDO::PARAM_STR to numeric(4, 0) is supported**** +****Conversion from PDO::PARAM_LOB to numeric(4, 0) is supported**** + +Testing numeric(4, 1): +****Conversion from PDO::PARAM_BOOL to numeric(4, 1) is supported**** +****Conversion from PDO::PARAM_INT to numeric(4, 1) is supported**** +****Conversion from PDO::PARAM_STR to numeric(4, 1) is supported**** +****Conversion from PDO::PARAM_LOB to numeric(4, 1) is supported**** + +Testing numeric(4, 4): +****Conversion from PDO::PARAM_BOOL to numeric(4, 4) is supported**** +****Conversion from PDO::PARAM_INT to numeric(4, 4) is supported**** +****Conversion from PDO::PARAM_STR to numeric(4, 4) is supported**** +****Conversion from PDO::PARAM_LOB to numeric(4, 4) is supported**** + +Testing numeric(16, 0): +****Conversion from PDO::PARAM_BOOL to numeric(16, 0) is supported**** +****Conversion from PDO::PARAM_INT to numeric(16, 0) is supported**** +****Conversion from PDO::PARAM_LOB to numeric(16, 0) is supported**** + +Testing numeric(16, 1): +****Conversion from PDO::PARAM_BOOL to numeric(16, 1) is supported**** +****Conversion from PDO::PARAM_INT to numeric(16, 1) is supported**** +****Conversion from PDO::PARAM_LOB to numeric(16, 1) is supported**** + +Testing numeric(16, 4): +****Conversion from PDO::PARAM_BOOL to numeric(16, 4) is supported**** +****Conversion from PDO::PARAM_INT to numeric(16, 4) is supported**** +****Conversion from PDO::PARAM_STR to numeric(16, 4) is supported**** +****Conversion from PDO::PARAM_LOB to numeric(16, 4) is supported**** + +Testing numeric(16, 16): +****Conversion from PDO::PARAM_BOOL to numeric(16, 16) is supported**** +****Conversion from PDO::PARAM_INT to numeric(16, 16) is supported**** +****Conversion from PDO::PARAM_STR to numeric(16, 16) is supported**** +****Conversion from PDO::PARAM_LOB to numeric(16, 16) is supported**** + +Testing numeric(38, 0): +****Conversion from PDO::PARAM_BOOL to numeric(38, 0) is supported**** +****Conversion from PDO::PARAM_INT to numeric(38, 0) is supported**** +****Conversion from PDO::PARAM_LOB to numeric(38, 0) is supported**** + +Testing numeric(38, 1): +****Conversion from PDO::PARAM_BOOL to numeric(38, 1) is supported**** +****Conversion from PDO::PARAM_INT to numeric(38, 1) is supported**** +****Conversion from PDO::PARAM_LOB to numeric(38, 1) is supported**** + +Testing numeric(38, 4): +****Conversion from PDO::PARAM_BOOL to numeric(38, 4) is supported**** +****Conversion from PDO::PARAM_INT to numeric(38, 4) is supported**** +****Conversion from PDO::PARAM_LOB to numeric(38, 4) is supported**** + +Testing numeric(38, 16): +****Conversion from PDO::PARAM_BOOL to numeric(38, 16) is supported**** +****Conversion from PDO::PARAM_INT to numeric(38, 16) is supported**** +****Conversion from PDO::PARAM_LOB to numeric(38, 16) is supported**** + +Testing numeric(38, 38): +****Conversion from PDO::PARAM_BOOL to numeric(38, 38) is supported**** +****Conversion from PDO::PARAM_INT to numeric(38, 38) is supported**** +****Conversion from PDO::PARAM_STR to numeric(38, 38) is supported**** +****Conversion from PDO::PARAM_LOB to numeric(38, 38) is supported**** \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_float_bits.phpt b/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_float_bits.phpt new file mode 100644 index 00000000..534595ed --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_float_bits.phpt @@ -0,0 +1,113 @@ +--TEST-- +Test for inserting encrypted data into float types columns +--DESCRIPTION-- +Test conversions between different float types +With or without Always Encrypted, implicit conversion works if: +1. From input of PDO::PARAM_BOOL to a float column +2. From input of PDO::PARAM_INT to a float column +3. From input of PDO::PARAM_STR to a float column +4. From input of PDO::PARAM_LOB to a float column +--SKIPIF-- + +--FILE-- + 24, the precision is 15 digits, but PHP float only supports up to 14 digits + $epsilon; + if ($m <= 24) { + $epsilon = pow(10, $numint - 7); + } else { + $epsilon = pow(10, $numint - 14); + } + + $typeFull = "$dataType($m)"; + echo "\nTesting $typeFull:\n"; + + //create table containing float(m) columns + $tbname = "test_" . $dataType . $m; + $colMetaArr = array(new ColumnMeta($typeFull, "c_det"), new ColumnMeta($typeFull, "c_rand", null, "randomized")); + createTable($conn, $tbname, $colMetaArr); + + // insert by specifying PDO::PARAM_ types + foreach ($pdoParamTypes as $pdoParamType) { + $r; + $stmt = insertRow($conn, $tbname, array( "c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType), "c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType)), "prepareBindParam", $r); + + // check the case when inserting as PDO::PARAM_NULL + // with or without AE: NULL is inserted + if ($pdoParamType == "PDO::PARAM_NULL") { + if ($r === false) { + echo "Conversion from $pdoParamType to $typeFull should be supported\n"; + } else { + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = $conn->query($sql); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if (!is_null($row['c_det']) || !is_null($row['c_rand'])) { + echo "Conversion from $pdoParamType to $typeFull should insert NULL\n"; + } + } + // check the case when inserting as PDO::PARAM_BOOL, PDO::PARAM_INT, PDO::PARAM_STR or PDO::PARAM_LOB + // with or without AE: should work + } else { + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = $conn->query($sql); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if (abs($row['c_det'] - $inputValues[0]) < $epsilon && abs($row['c_rand'] - $inputValues[1]) < $epsilon) { + echo "****Conversion from $pdoParamType to $typeFull is supported****\n"; + } else { + echo "Conversion from $pdoParamType to $typeFull causes data corruption\n"; + } + } + // cleanup + $conn->query("TRUNCATE TABLE $tbname"); + } + dropTable($conn, $tbname); + } + unset($stmt); + unset($conn); +} catch (PDOException $e) { + echo $e->getMessage(); +} +?> +--EXPECT-- +Testing float(1): +****Conversion from PDO::PARAM_BOOL to float(1) is supported**** +****Conversion from PDO::PARAM_INT to float(1) is supported**** +****Conversion from PDO::PARAM_STR to float(1) is supported**** +****Conversion from PDO::PARAM_LOB to float(1) is supported**** + +Testing float(12): +****Conversion from PDO::PARAM_BOOL to float(12) is supported**** +****Conversion from PDO::PARAM_INT to float(12) is supported**** +****Conversion from PDO::PARAM_STR to float(12) is supported**** +****Conversion from PDO::PARAM_LOB to float(12) is supported**** + +Testing float(24): +****Conversion from PDO::PARAM_BOOL to float(24) is supported**** +****Conversion from PDO::PARAM_INT to float(24) is supported**** +****Conversion from PDO::PARAM_STR to float(24) is supported**** +****Conversion from PDO::PARAM_LOB to float(24) is supported**** + +Testing float(36): +****Conversion from PDO::PARAM_BOOL to float(36) is supported**** +****Conversion from PDO::PARAM_INT to float(36) is supported**** +****Conversion from PDO::PARAM_STR to float(36) is supported**** +****Conversion from PDO::PARAM_LOB to float(36) is supported**** + +Testing float(53): +****Conversion from PDO::PARAM_BOOL to float(53) is supported**** +****Conversion from PDO::PARAM_INT to float(53) is supported**** +****Conversion from PDO::PARAM_STR to float(53) is supported**** +****Conversion from PDO::PARAM_LOB to float(53) is supported**** \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_nchar_size.phpt b/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_nchar_size.phpt new file mode 100644 index 00000000..4b57eb3f --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_nchar_size.phpt @@ -0,0 +1,172 @@ +--TEST-- +Test for inserting encrypted data into nchar types columns with different sizes +--DESCRIPTION-- +Test conversions between different nchar types of different sizes +With or without Always Encrypted, implicit conversion works if: +1. From input of PDO::PARAM_BOOL to any nchar column +2. From input of PDO::PARAM_INT to any nchar column +3. From input of PDO::PARAM_STR to any nchar column +4. From input of PDO::PARAM_LOB to any nchar column +--SKIPIF-- + +--FILE-- + new BindParamOp(1, $input, $pdoParamType)), "prepareBindParam", $r); + + // check the case when inserting as PDO::PARAM_NULL + // with or without AE: NULL is inserted + if ($pdoParamType == "PDO::PARAM_NULL") { + if ($r === false) { + echo "Conversion from $pdoParamType to $typeFull should be supported\n"; + } else { + $sql = "SELECT c1 FROM $tbname"; + $stmt = $conn->query($sql); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if (!is_null($row['c1'])) { + echo "Conversion from $pdoParamType to $typeFull should insert NULL\n"; + } + } + // check the case when inserting as PDO::PARAM_BOOL, PDO::PARAM_INT, PDO::PARAM_STR or PDO{{PARAM_LOB + // with or without AE: should work + } else { + $sql = "SELECT c1 FROM $tbname"; + $stmt = $conn->query($sql); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if (strlen($row['c1']) == $m) { + echo "****Conversion from $pdoParamType to $typeFull is supported****\n"; + } else { + echo "Conversion from $pdoParamType to $typeFull causes data corruption\n"; + } + } + // cleanup + $conn->query("TRUNCATE TABLE $tbname"); + } + dropTable($conn, $tbname); + } + } + unset($stmt); + unset($conn); +} catch (PDOException $e) { + echo $e->getMessage(); +} +?> +--EXPECT-- +Testing nchar(1): +****Conversion from PDO::PARAM_BOOL to nchar(1) is supported**** +****Conversion from PDO::PARAM_INT to nchar(1) is supported**** +****Conversion from PDO::PARAM_STR to nchar(1) is supported**** +****Conversion from PDO::PARAM_LOB to nchar(1) is supported**** + +Testing nchar(8): +****Conversion from PDO::PARAM_BOOL to nchar(8) is supported**** +****Conversion from PDO::PARAM_INT to nchar(8) is supported**** +****Conversion from PDO::PARAM_STR to nchar(8) is supported**** +****Conversion from PDO::PARAM_LOB to nchar(8) is supported**** + +Testing nchar(64): +****Conversion from PDO::PARAM_BOOL to nchar(64) is supported**** +****Conversion from PDO::PARAM_INT to nchar(64) is supported**** +****Conversion from PDO::PARAM_STR to nchar(64) is supported**** +****Conversion from PDO::PARAM_LOB to nchar(64) is supported**** + +Testing nchar(512): +****Conversion from PDO::PARAM_BOOL to nchar(512) is supported**** +****Conversion from PDO::PARAM_INT to nchar(512) is supported**** +****Conversion from PDO::PARAM_STR to nchar(512) is supported**** +****Conversion from PDO::PARAM_LOB to nchar(512) is supported**** + +Testing nchar(4000): +****Conversion from PDO::PARAM_BOOL to nchar(4000) is supported**** +****Conversion from PDO::PARAM_INT to nchar(4000) is supported**** +****Conversion from PDO::PARAM_STR to nchar(4000) is supported**** +****Conversion from PDO::PARAM_LOB to nchar(4000) is supported**** + +Testing nvarchar(1): +****Conversion from PDO::PARAM_BOOL to nvarchar(1) is supported**** +****Conversion from PDO::PARAM_INT to nvarchar(1) is supported**** +****Conversion from PDO::PARAM_STR to nvarchar(1) is supported**** +****Conversion from PDO::PARAM_LOB to nvarchar(1) is supported**** + +Testing nvarchar(8): +****Conversion from PDO::PARAM_BOOL to nvarchar(8) is supported**** +****Conversion from PDO::PARAM_INT to nvarchar(8) is supported**** +****Conversion from PDO::PARAM_STR to nvarchar(8) is supported**** +****Conversion from PDO::PARAM_LOB to nvarchar(8) is supported**** + +Testing nvarchar(64): +****Conversion from PDO::PARAM_BOOL to nvarchar(64) is supported**** +****Conversion from PDO::PARAM_INT to nvarchar(64) is supported**** +****Conversion from PDO::PARAM_STR to nvarchar(64) is supported**** +****Conversion from PDO::PARAM_LOB to nvarchar(64) is supported**** + +Testing nvarchar(512): +****Conversion from PDO::PARAM_BOOL to nvarchar(512) is supported**** +****Conversion from PDO::PARAM_INT to nvarchar(512) is supported**** +****Conversion from PDO::PARAM_STR to nvarchar(512) is supported**** +****Conversion from PDO::PARAM_LOB to nvarchar(512) is supported**** + +Testing nvarchar(4000): +****Conversion from PDO::PARAM_BOOL to nvarchar(4000) is supported**** +****Conversion from PDO::PARAM_INT to nvarchar(4000) is supported**** +****Conversion from PDO::PARAM_STR to nvarchar(4000) is supported**** +****Conversion from PDO::PARAM_LOB to nvarchar(4000) is supported**** + +Testing nvarchar(max): +****Conversion from PDO::PARAM_BOOL to nvarchar(max) is supported**** +****Conversion from PDO::PARAM_INT to nvarchar(max) is supported**** +****Conversion from PDO::PARAM_STR to nvarchar(max) is supported**** +****Conversion from PDO::PARAM_LOB to nvarchar(max) is supported**** + +Testing nvarchar(max): +****Conversion from PDO::PARAM_BOOL to nvarchar(max) is supported**** +****Conversion from PDO::PARAM_INT to nvarchar(max) is supported**** +****Conversion from PDO::PARAM_STR to nvarchar(max) is supported**** +****Conversion from PDO::PARAM_LOB to nvarchar(max) is supported**** + +Testing nvarchar(max): +****Conversion from PDO::PARAM_BOOL to nvarchar(max) is supported**** +****Conversion from PDO::PARAM_INT to nvarchar(max) is supported**** +****Conversion from PDO::PARAM_STR to nvarchar(max) is supported**** +****Conversion from PDO::PARAM_LOB to nvarchar(max) is supported**** + +Testing nvarchar(max): +****Conversion from PDO::PARAM_BOOL to nvarchar(max) is supported**** +****Conversion from PDO::PARAM_INT to nvarchar(max) is supported**** +****Conversion from PDO::PARAM_STR to nvarchar(max) is supported**** +****Conversion from PDO::PARAM_LOB to nvarchar(max) is supported**** + +Testing nvarchar(max): +****Conversion from PDO::PARAM_BOOL to nvarchar(max) is supported**** +****Conversion from PDO::PARAM_INT to nvarchar(max) is supported**** +****Conversion from PDO::PARAM_STR to nvarchar(max) is supported**** +****Conversion from PDO::PARAM_LOB to nvarchar(max) is supported**** \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_numeric.phpt b/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_numeric.phpt index 6dc7f755..eef28d74 100644 --- a/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_numeric.phpt +++ b/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_numeric.phpt @@ -1,39 +1,123 @@ --TEST-- -Test for inserting and retrieving encrypted data of numeric types +Test for inserting encrypted data into numeric types columns --DESCRIPTION-- -Use PDOstatement::bindParam with all PDO::PARAM_ types +Test conversions between different numeric types +With Always Encrypted, implicit conversion works if: +1. From input of PDO::PARAM_BOOL to a real column +2. From input of PDO::PARAM_INT to any numeric column +3. From input of PDO::PARAM_STR to any numeric column +4. From input of PDO::PARAM_LOB to any numeric column +Without Always Encrypted, all of the above work except for input of PDO::PARAM_STR to a bigint column in a x86 platform +PDO::PARAM_STR does not work for bigint in a x86 platform because the maximum value of an int is about 2147483647 +Whereas in a x64 platform, the maximum value is about 9E18 +In a x86 platform, when an integer is > 2147483647, PHP implicitly changees it to a float, represented by scientific notation +When inserting a scientific notation form numeric string, SQL Server returns a converting data type nvarchar to bigint error +Works for with AE because the sqltype used for binding parameter is determined by SQLDescribeParam, +unlike without AE, the sqltype is predicted to be nvarchar or varchar when the input is a string --SKIPIF-- --FILE-- new BindParamOp(1, (string)$inputValues[0], $pdoParamType), "c_rand" => new BindParamOp(2, (string)$inputValues[1], $pdoParamType)), "prepareBindParam", $r); + $stmt = insertRow($conn, $tbname, array( "c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType), "c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType)), "prepareBindParam", $r); + + // check the case when inserting as PDO::PARAM_NULL + // with or without AE: NULL is inserted + if ($pdoParamType == "PDO::PARAM_NULL") { + if ($r === false) { + echo "Conversion from $pdoParamType to $dataType should be supported\n"; + } else { + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = $conn->query($sql); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if (!is_null($row['c_det']) || !is_null($row['c_rand'])) { + echo "Conversion from $pdoParamType to $dataType should insert NULL\n"; + } + } + // check the case when inserting as PDO::PARAM_BOOL + // with or without AE: 1 or 0 should be inserted when inserting into an integer column + // double is inserted when inserting into a real column + } else if ($pdoParamType == "PDO::PARAM_BOOL") { + if ($r === false) { + echo "Conversion from $pdoParamType to $dataType should be supported\n"; + } else { + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = $conn->query($sql); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if ($dataType == "real") { + if (abs($row['c_det'] - $inputValues[0]) < $epsilon && abs($row['c_rand'] - $inputValues[1]) < $epsilon) { + echo "****Conversion from $pdoParamType to $dataType is supported****\n"; + } else { + echo "Conversion from $pdoParamType to $dataType causes data corruption\n"; + } + } else { + if ($row['c_det'] != ($inputValues[0] != 0) && $row['c_rand'] != ($inputValues[1] != 0)) { + echo "Conversion from $pdoParamType to $dataType insert a boolean\n"; + } + } + } + // check the case when inserting as PDO::PARAM_STR into a bigint column + // with AE: should work + // without AE: should not work on a x86 platform + } else if ($dataType == "bigint" && $pdoParamType == "PDO::PARAM_STR") { + if (!isAEConnected() && PHP_INT_SIZE == 4) { + if ($r !== false) { + echo "Conversion from $pdoParamType to $dataType should not be supported\n"; + } + } else { + if ($r === false) { + echo "Conversion from $pdoParamType to $dataType should be supported\n"; + } else { + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = $conn->query($sql); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if ($row['c_det'] != $inputValues[0] && $row['c_rand'] != $inputValues[1]) { + echo "Conversion from $pdoParamType to $dataType causes data corruption\n"; + } + } + } + // check the case when inserting as PDO::PARAM_INT, PDO::PARAM_STR or PDO::PARAM_LOB + // with or without AE: should work } else { - $stmt = insertRow($conn, $tbname, array( "c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType), "c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType)), "prepareBindParam", $r); - } - if ($r === false) { - isIncompatibleTypesError($stmt, $dataType, $pdoParamType); - } else { - echo "****PDO param type $pdoParamType is compatible with encrypted $dataType****\n"; - fetchAll($conn, $tbname); + if ($r === false) { + echo "Conversion from $pdoParamType to $dataType should be supported\n"; + } else { + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = $conn->query($sql); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if ($dataType == "real") { + if (abs($row['c_det'] - $inputValues[0]) < $epsilon && abs($row['c_rand'] - $inputValues[1]) < $epsilon) { + echo "****Conversion from $pdoParamType to $dataType is supported****\n"; + } else { + echo "Conversion from $pdoParamType to $dataType causes data corruption\n"; + } + } else { + if ($row['c_det'] == $inputValues[0] && $row['c_rand'] == $inputValues[1]) { + echo "****Conversion from $pdoParamType to $dataType is supported****\n"; + } else { + echo "Conversion from $pdoParamType to $dataType causes data corruption\n"; + } + } + } } $conn->query("TRUNCATE TABLE $tbname"); } @@ -46,139 +130,32 @@ try { } ?> --EXPECT-- - Testing bit: -****PDO param type PDO::PARAM_BOOL is compatible with encrypted bit**** -c_det: 1 -c_rand: 0 -****PDO param type PDO::PARAM_NULL is compatible with encrypted bit**** -c_det: -c_rand: -****PDO param type PDO::PARAM_INT is compatible with encrypted bit**** -c_det: 1 -c_rand: 0 -****PDO param type PDO::PARAM_STR is compatible with encrypted bit**** -c_det: 1 -c_rand: 0 -****PDO param type PDO::PARAM_LOB is compatible with encrypted bit**** -c_det: 1 -c_rand: 0 +****Conversion from PDO::PARAM_INT to bit is supported**** +****Conversion from PDO::PARAM_STR to bit is supported**** +****Conversion from PDO::PARAM_LOB to bit is supported**** Testing tinyint: -****PDO param type PDO::PARAM_BOOL is compatible with encrypted tinyint**** -c_det: 0 -c_rand: 1 -****PDO param type PDO::PARAM_NULL is compatible with encrypted tinyint**** -c_det: -c_rand: -****PDO param type PDO::PARAM_INT is compatible with encrypted tinyint**** -c_det: 0 -c_rand: 255 -****PDO param type PDO::PARAM_STR is compatible with encrypted tinyint**** -c_det: 0 -c_rand: 255 -****PDO param type PDO::PARAM_LOB is compatible with encrypted tinyint**** -c_det: 0 -c_rand: 255 +****Conversion from PDO::PARAM_INT to tinyint is supported**** +****Conversion from PDO::PARAM_STR to tinyint is supported**** +****Conversion from PDO::PARAM_LOB to tinyint is supported**** Testing smallint: -****PDO param type PDO::PARAM_BOOL is compatible with encrypted smallint**** -c_det: 1 -c_rand: 1 -****PDO param type PDO::PARAM_NULL is compatible with encrypted smallint**** -c_det: -c_rand: -****PDO param type PDO::PARAM_INT is compatible with encrypted smallint**** -c_det: -32767 -c_rand: 32767 -****PDO param type PDO::PARAM_STR is compatible with encrypted smallint**** -c_det: -32767 -c_rand: 32767 -****PDO param type PDO::PARAM_LOB is compatible with encrypted smallint**** -c_det: -32767 -c_rand: 32767 +****Conversion from PDO::PARAM_INT to smallint is supported**** +****Conversion from PDO::PARAM_STR to smallint is supported**** +****Conversion from PDO::PARAM_LOB to smallint is supported**** Testing int: -****PDO param type PDO::PARAM_BOOL is compatible with encrypted int**** -c_det: 1 -c_rand: 1 -****PDO param type PDO::PARAM_NULL is compatible with encrypted int**** -c_det: -c_rand: -****PDO param type PDO::PARAM_INT is compatible with encrypted int**** -c_det: -2147483647 -c_rand: 2147483647 -****PDO param type PDO::PARAM_STR is compatible with encrypted int**** -c_det: -2147483647 -c_rand: 2147483647 -****PDO param type PDO::PARAM_LOB is compatible with encrypted int**** -c_det: -2147483647 -c_rand: 2147483647 +****Conversion from PDO::PARAM_INT to int is supported**** +****Conversion from PDO::PARAM_STR to int is supported**** +****Conversion from PDO::PARAM_LOB to int is supported**** -Testing decimal(18,5): -****PDO param type PDO::PARAM_BOOL is compatible with encrypted decimal(18,5)**** -c_det: -9223372036854.80000 -c_rand: 9223372036854.80000 -****PDO param type PDO::PARAM_NULL is compatible with encrypted decimal(18,5)**** -c_det: -c_rand: -****PDO param type PDO::PARAM_INT is compatible with encrypted decimal(18,5)**** -c_det: -9223372036854.80000 -c_rand: 9223372036854.80000 -****PDO param type PDO::PARAM_STR is compatible with encrypted decimal(18,5)**** -c_det: -9223372036854.80000 -c_rand: 9223372036854.80000 -****PDO param type PDO::PARAM_LOB is compatible with encrypted decimal(18,5)**** -c_det: -9223372036854.80000 -c_rand: 9223372036854.80000 - -Testing numeric(10,5): -****PDO param type PDO::PARAM_BOOL is compatible with encrypted numeric(10,5)**** -c_det: -21474.83647 -c_rand: 21474.83647 -****PDO param type PDO::PARAM_NULL is compatible with encrypted numeric(10,5)**** -c_det: -c_rand: -****PDO param type PDO::PARAM_INT is compatible with encrypted numeric(10,5)**** -c_det: -21474.83647 -c_rand: 21474.83647 -****PDO param type PDO::PARAM_STR is compatible with encrypted numeric(10,5)**** -c_det: -21474.83647 -c_rand: 21474.83647 -****PDO param type PDO::PARAM_LOB is compatible with encrypted numeric(10,5)**** -c_det: -21474.83647 -c_rand: 21474.83647 - -Testing float: -****PDO param type PDO::PARAM_BOOL is compatible with encrypted float**** -c_det: -9223372036.8547993 -c_rand: 9223372036.8547993 -****PDO param type PDO::PARAM_NULL is compatible with encrypted float**** -c_det: -c_rand: -****PDO param type PDO::PARAM_INT is compatible with encrypted float**** -c_det: -9223372036.8547993 -c_rand: 9223372036.8547993 -****PDO param type PDO::PARAM_STR is compatible with encrypted float**** -c_det: -9223372036.8547993 -c_rand: 9223372036.8547993 -****PDO param type PDO::PARAM_LOB is compatible with encrypted float**** -c_det: -9223372036.8547993 -c_rand: 9223372036.8547993 +Testing bigint: +****Conversion from PDO::PARAM_INT to bigint is supported**** +****Conversion from PDO::PARAM_LOB to bigint is supported**** Testing real: -****PDO param type PDO::PARAM_BOOL is compatible with encrypted real**** -c_det: -2147.4829 -c_rand: 2147.4829 -****PDO param type PDO::PARAM_NULL is compatible with encrypted real**** -c_det: -c_rand: -****PDO param type PDO::PARAM_INT is compatible with encrypted real**** -c_det: -2147.4829 -c_rand: 2147.4829 -****PDO param type PDO::PARAM_STR is compatible with encrypted real**** -c_det: -2147.4829 -c_rand: 2147.4829 -****PDO param type PDO::PARAM_LOB is compatible with encrypted real**** -c_det: -2147.4829 -c_rand: 2147.4829 +****Conversion from PDO::PARAM_BOOL to real is supported**** +****Conversion from PDO::PARAM_INT to real is supported**** +****Conversion from PDO::PARAM_STR to real is supported**** +****Conversion from PDO::PARAM_LOB to real is supported**** \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_string.phpt b/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_string.phpt deleted file mode 100644 index 44ec7d0a..00000000 --- a/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_string.phpt +++ /dev/null @@ -1,112 +0,0 @@ ---TEST-- -Test for inserting and retrieving encrypted data of string types ---DESCRIPTION-- -Use PDOstatement::bindParam with all PDO::PARAM_ types ---SKIPIF-- - ---FILE-- - new BindParamOp(1, $inputValues[0], $pdoParamType),"c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType)), "prepareBindParam", $r); - if ($r === false) { - isIncompatibleTypesError($stmt, $dataType, $pdoParamType); - } else { - echo "****PDO param type $pdoParamType is compatible with encrypted $dataType****\n"; - fetchAll($conn, $tbname); - } - $conn->query("TRUNCATE TABLE $tbname"); - } - dropTable($conn, $tbname); - } - unset($stmt); - unset($conn); -} catch (PDOException $e) { - echo $e->getMessage(); -} -?> ---EXPECT-- - -Testing char(5): -****PDO param type PDO::PARAM_BOOL is compatible with encrypted char(5)**** -c_det: -leng -c_rand: th, n -****PDO param type PDO::PARAM_NULL is compatible with encrypted char(5)**** -c_det: -c_rand: -****PDO param type PDO::PARAM_INT is compatible with encrypted char(5)**** -c_det: -leng -c_rand: th, n -****PDO param type PDO::PARAM_STR is compatible with encrypted char(5)**** -c_det: -leng -c_rand: th, n -****PDO param type PDO::PARAM_LOB is compatible with encrypted char(5)**** -c_det: -leng -c_rand: th, n - -Testing varchar(max): -****PDO param type PDO::PARAM_BOOL is compatible with encrypted varchar(max)**** -c_det: Use varchar(max) when the sizes of the column data entries vary considerably, and the size might exceed 8,000 bytes. -c_rand: Each non-null varchar(max) or nvarchar(max) column requires 24 bytes of additional fixed allocation which counts against the 8,060 byte row limit during a sort operation. -****PDO param type PDO::PARAM_NULL is compatible with encrypted varchar(max)**** -c_det: -c_rand: -****PDO param type PDO::PARAM_INT is compatible with encrypted varchar(max)**** -c_det: Use varchar(max) when the sizes of the column data entries vary considerably, and the size might exceed 8,000 bytes. -c_rand: Each non-null varchar(max) or nvarchar(max) column requires 24 bytes of additional fixed allocation which counts against the 8,060 byte row limit during a sort operation. -****PDO param type PDO::PARAM_STR is compatible with encrypted varchar(max)**** -c_det: Use varchar(max) when the sizes of the column data entries vary considerably, and the size might exceed 8,000 bytes. -c_rand: Each non-null varchar(max) or nvarchar(max) column requires 24 bytes of additional fixed allocation which counts against the 8,060 byte row limit during a sort operation. -****PDO param type PDO::PARAM_LOB is compatible with encrypted varchar(max)**** -c_det: Use varchar(max) when the sizes of the column data entries vary considerably, and the size might exceed 8,000 bytes. -c_rand: Each non-null varchar(max) or nvarchar(max) column requires 24 bytes of additional fixed allocation which counts against the 8,060 byte row limit during a sort operation. - -Testing nchar(5): -****PDO param type PDO::PARAM_BOOL is compatible with encrypted nchar(5)**** -c_det: -leng -c_rand: th Un -****PDO param type PDO::PARAM_NULL is compatible with encrypted nchar(5)**** -c_det: -c_rand: -****PDO param type PDO::PARAM_INT is compatible with encrypted nchar(5)**** -c_det: -leng -c_rand: th Un -****PDO param type PDO::PARAM_STR is compatible with encrypted nchar(5)**** -c_det: -leng -c_rand: th Un -****PDO param type PDO::PARAM_LOB is compatible with encrypted nchar(5)**** -c_det: -leng -c_rand: th Un - -Testing nvarchar(max): -****PDO param type PDO::PARAM_BOOL is compatible with encrypted nvarchar(max)**** -c_det: When prefixing a string constant with the letter N, the implicit conversion will result in a Unicode string if the constant to convert does not exceed the max length for a Unicode string data type (4,000). -c_rand: Otherwise, the implicit conversion will result in a Unicode large-value (max). -****PDO param type PDO::PARAM_NULL is compatible with encrypted nvarchar(max)**** -c_det: -c_rand: -****PDO param type PDO::PARAM_INT is compatible with encrypted nvarchar(max)**** -c_det: When prefixing a string constant with the letter N, the implicit conversion will result in a Unicode string if the constant to convert does not exceed the max length for a Unicode string data type (4,000). -c_rand: Otherwise, the implicit conversion will result in a Unicode large-value (max). -****PDO param type PDO::PARAM_STR is compatible with encrypted nvarchar(max)**** -c_det: When prefixing a string constant with the letter N, the implicit conversion will result in a Unicode string if the constant to convert does not exceed the max length for a Unicode string data type (4,000). -c_rand: Otherwise, the implicit conversion will result in a Unicode large-value (max). -****PDO param type PDO::PARAM_LOB is compatible with encrypted nvarchar(max)**** -c_det: When prefixing a string constant with the letter N, the implicit conversion will result in a Unicode string if the constant to convert does not exceed the max length for a Unicode string data type (4,000). -c_rand: Otherwise, the implicit conversion will result in a Unicode large-value (max). diff --git a/test/functional/pdo_sqlsrv/pdo_ae_output_param_binary_size.phpt b/test/functional/pdo_sqlsrv/pdo_ae_output_param_binary_size.phpt new file mode 100644 index 00000000..de999f2d --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ae_output_param_binary_size.phpt @@ -0,0 +1,210 @@ +--TEST-- +Test for retrieving encrypted data of binary types of various sizes as output parameters +--DESCRIPTION-- +Use PDOstatement::bindParam with all PDO::PARAM_ types +--ENV-- +PHPT_EXEC=true +--SKIPIF-- + +--FILE-- + "An invalid PHP type was specified as an output parameter. DateTime objects, NULL values, and streams cannot be specified as output parameters.", "07006" => "Restricted data type attribute violation"); + +$pdoParamTypes = array( + PDO::PARAM_BOOL, // 5 + PDO::PARAM_NULL, // 0 + PDO::PARAM_INT, // 1 + PDO::PARAM_STR, // 2 + PDO::PARAM_LOB // 3 +); + +////////////////////////////////////////////////////////////////////////////////// +function printValues($msg, $det, $rand, $input0, $input1) +{ + echo $msg; + echo "input 0: "; var_dump($input0); + echo "fetched: "; var_dump($det); + echo "input 1: "; var_dump($input1); + echo "fetched: "; var_dump($rand); +} + +function convert2Hex($ch, $length) +{ + // Without AE, the binary values returned as integers will + // have lengths no more than 4 times the original hex string value + // (e.g. string(8) "65656565") - limited by the buffer sizes + if (!isAEConnected()) { + $count = ($length <= 2) ? $length : 4; + } else { + $count = $length; + } + + return str_repeat(bin2hex($ch), $count); +} + +function testOutputBinary($inout) +{ + global $pdoParamTypes, $dataTypes, $lengths, $errors; + + try { + $conn = connect(); + $tbname = "test_binary_types"; + $spname = "test_binary_proc"; + $ch0 = 'd'; + $ch1 = 'e'; + + foreach ($dataTypes as $dataType) { + $maxtype = strpos($dataType, "(max)"); + foreach ($lengths as $length) { + if ($maxtype !== false) { + $type = $dataType; + } else { + $type = "$dataType($length)"; + } + trace("\nTesting $type:\n"); + + //create and populate table + $colMetaArr = array(new ColumnMeta($type, "c_det"), new ColumnMeta($type, "c_rand", null, "randomized")); + createTable($conn, $tbname, $colMetaArr); + $input0 = str_repeat($ch0, $length); + $input1 = str_repeat($ch1, $length); + $ord0 = convert2Hex($ch0, $length); + $ord1 = convert2Hex($ch1, $length); + insertRow($conn, $tbname, array("c_det" => new BindParamOp(1, $input0, "PDO::PARAM_LOB", 0, "PDO::SQLSRV_ENCODING_BINARY"), + "c_rand" => new BindParamOp(2, $input1, "PDO::PARAM_LOB", 0, "PDO::SQLSRV_ENCODING_BINARY")), "prepareBindParam"); + + // fetch with PDO::bindParam using a stored procedure + $procArgs = "@c_det $type OUTPUT, @c_rand $type OUTPUT"; + $procCode = "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname"; + createProc($conn, $spname, $procArgs, $procCode); + + // call stored procedure + $outSql = getCallProcSqlPlaceholders($spname, 2); + foreach ($pdoParamTypes as $pdoParamType) { + $stmt = $conn->prepare($outSql); + trace("\nParam $pdoParamType with INOUT = $inout\n"); + + if ($inout && $pdoParamType != PDO::PARAM_STR) { + // Currently do not support getting binary as strings + INOUT param + // See VSO 2829 for details + $paramType = $pdoParamType | PDO::PARAM_INPUT_OUTPUT; + } else { + $paramType = $pdoParamType; + } + + $det = ""; + $rand = ""; + if ($pdoParamType == PDO::PARAM_STR || $pdoParamType == PDO::PARAM_LOB) { + $stmt->bindParam(1, $det, $paramType, $length, PDO::SQLSRV_ENCODING_BINARY); + $stmt->bindParam(2, $rand, $paramType, $length, PDO::SQLSRV_ENCODING_BINARY); + } elseif ($pdoParamType == PDO::PARAM_BOOL || $pdoParamType == PDO::PARAM_INT) { + $det = $rand = 0; + $stmt->bindParam(1, $det, $paramType, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE); + $stmt->bindParam(2, $rand, $paramType, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE); + } else { + $stmt->bindParam(1, $det, $paramType, $length); + $stmt->bindParam(2, $rand, $paramType, $length); + } + + try { + $stmt->execute(); + + $errMsg = "****$dataType as $pdoParamType failed with INOUT = $inout:****\n"; + if ($pdoParamType == PDO::PARAM_STR) { + if ($det !== $input0 || $rand !== $input1) { + printValues($errMsg, $det, $rand, $input0, $input1); + } + } elseif ($pdoParamType == PDO::PARAM_BOOL) { + // for boolean values, they should all be bool(true) + // because all floats are non-zeroes + // This only occurs without AE + // With AE enabled, this would have caused an exception + if (!$det || !$rand) { + printValues($errMsg, $det, $rand, $input0, $input1); + } + } else { + // $pdoParamType is PDO::PARAM_INT + // This only occurs without AE -- likely a rare use case + // With AE enabled, this would have caused an exception + if (strval($det) != $ord0 || strval($rand) != $ord1) { + printValues($errMsg, $det, $rand, $ord0, $ord1); + } + } + } catch (PDOException $e) { + $message = $e->getMessage(); + $errMsg = "EXCEPTION: ****$type as $pdoParamType failed with INOUT = $inout:****\n"; + if ($pdoParamType == PDO::PARAM_NULL || $pdoParamType == PDO::PARAM_LOB) { + // Expected error IMSSP: "An invalid PHP type was specified + // as an output parameter. DateTime objects, NULL values, and + // streams cannot be specified as output parameters." + $found = strpos($message, $errors['IMSSP']); + if ($found === false) { + printValues($errMsg, $det, $rand, $input0, $input1); + } + } elseif ($pdoParamType == PDO::PARAM_BOOL || PDO::PARAM_INT) { + if (isAEConnected()) { + if ($pdoParamType == PDO::PARAM_INT) { + // Expected to fail with this message + $error = "String data, right truncated for output parameter"; + $found = strpos($message, $error); + } else { + // PDO::PARAM_BOOL - + // Expected error 07006 with AE enabled: + // "Restricted data type attribute violation" + // The data value returned for a parameter bound as + // SQL_PARAM_INPUT_OUTPUT or SQL_PARAM_OUTPUT could not + // be converted to the data type identified by the + // ValueType argument in SQLBindParameter. + $found = strpos($message, $errors['07006']); + } + } else { + // When not AE enabled, expected to fail with something like this message + // "Implicit conversion from data type nvarchar(max) to binary is not allowed. Use the CONVERT function to run this query." + // Sometimes it's about nvarchar too + $error = "to $dataType is not allowed. Use the CONVERT function to run this query."; + $found = strpos($message, $error); + } + if ($found === false) { + printValues($errMsg, $det, $rand, $input0, $input1); + } + } else { + // catch all + printValues($errMsg, $det, $rand, $input0, $input1); + } + } + } + dropProc($conn, $spname); + dropTable($conn, $tbname); + } + } + unset($stmt); + unset($conn); + } catch (PDOException $e) { + echo $e->getMessage(); + } +} + +testOutputBinary(false); +testOutputBinary(true); + +echo "Done\n"; + +?> +--CLEAN-- + +--EXPECT-- +Done \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_ae_output_param_char_size.phpt b/test/functional/pdo_sqlsrv/pdo_ae_output_param_char_size.phpt new file mode 100644 index 00000000..66a68004 --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ae_output_param_char_size.phpt @@ -0,0 +1,171 @@ +--TEST-- +Test for retrieving encrypted data of char types of various sizes as output parameters +--DESCRIPTION-- +Use PDOstatement::bindParam with all PDO::PARAM_ types +--ENV-- +PHPT_EXEC=true +--SKIPIF-- + +--FILE-- + "An invalid PHP type was specified as an output parameter. DateTime objects, NULL values, and streams cannot be specified as output parameters.", +"22003" => "Numeric value out of range"); + +$pdoParamTypes = array( + PDO::PARAM_BOOL, // 5 + PDO::PARAM_NULL, // 0 + PDO::PARAM_INT, // 1 + PDO::PARAM_STR, // 2 + PDO::PARAM_LOB // 3 +); + +////////////////////////////////////////////////////////////////////////////////// +function printValues($msg, $det, $rand, $input0, $input1) +{ + echo $msg; + echo "input 0: "; var_dump($input0); + echo "fetched: "; var_dump($det); + echo "input 1: "; var_dump($input1); + echo "fetched: "; var_dump($rand); +} + +function testOutputChars($inout) +{ + global $pdoParamTypes, $dataTypes, $lengths, $errors; + + try { + + $conn = connect(); + $tbname = "test_char_types"; + $spname = "test_char_proc"; + + foreach ($dataTypes as $dataType) { + $maxtype = strpos($dataType, "(max)"); + foreach ($lengths as $length) { + if ($maxtype !== false) { + $type = $dataType; + } else { + $type = "$dataType($length)"; + } + trace("\nTesting $type:\n"); + + //create and populate table + $colMetaArr = array(new ColumnMeta($type, "c_det"), new ColumnMeta($type, "c_rand", null, "randomized")); + createTable($conn, $tbname, $colMetaArr); + $input0 = str_repeat("1", $length); + $input1 = str_repeat("2", $length); + insertRow($conn, $tbname, array("c_det" => $input0, + "c_rand" => $input1)); + + // fetch with PDO::bindParam using a stored procedure + $procArgs = "@c_det $type OUTPUT, @c_rand $type OUTPUT"; + $procCode = "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname"; + createProc($conn, $spname, $procArgs, $procCode); + + // call stored procedure + $outSql = getCallProcSqlPlaceholders($spname, 2); + foreach ($pdoParamTypes as $pdoParamType) { + $det = ""; + $rand = ""; + $stmt = $conn->prepare($outSql); + trace("\nParam $pdoParamType with INOUT = $inout\n"); + + if ($inout) { + $paramType = $pdoParamType | PDO::PARAM_INPUT_OUTPUT; + } else { + $paramType = $pdoParamType; + } + + $len = $length; + if ($pdoParamType == PDO::PARAM_BOOL || $pdoParamType == PDO::PARAM_INT) { + $len = PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE; + $det = $rand = 0; + } + + $stmt->bindParam(1, $det, $paramType, $len); + $stmt->bindParam(2, $rand, $paramType, $len); + + try { + $stmt->execute(); + $errMsg = "****$type as $pdoParamType failed with INOUT = $inout:****\n"; + if ($length < 64 && $pdoParamType != PDO::PARAM_STR) { + if ($pdoParamType == PDO::PARAM_BOOL) { + // For boolean values, they should all be bool(true) + // because all "string literals" are non-zeroes + if (!$det || !$rand) { + printValues($errMsg, $det, $rand, $input0, $input1); + } + } else { + // $pdoParamType = PDO::PARAM_INT + // Expect numeric values + if ($det != intval($input0) || $rand != intval($input1)) { + printValues($errMsg, $det, $rand, $input0, $input1); + } + } + } elseif ($det !== $input0 || $rand !== $input1) { + printValues($errMsg, $det, $rand, $input0, $input1); + } + } catch (PDOException $e) { + $message = $e->getMessage(); + $errMsg = "EXCEPTION: ****$type as $pdoParamType failed with INOUT = $inout:****\n"; + if ($pdoParamType == PDO::PARAM_NULL || $pdoParamType == PDO::PARAM_LOB) { + // Expected error IMSSP: "An invalid PHP type was specified + // as an output parameter. DateTime objects, NULL values, and + // streams cannot be specified as output parameters." + $found = strpos($message, $errors['IMSSP']); + if ($found === false) { + printValues($errMsg, $det, $rand, $input0, $input1); + } + } elseif ($pdoParamType == PDO::PARAM_BOOL) { + if (isAEConnected()) { + // Expected error 22003: "Numeric value out of range" + $found = strpos($message, $errors['22003']); + } else { + // When not AE enabled, expected to fail to convert + // whatever char type to integers + $error = "Error converting data type $dataType to int"; + $found = strpos($message, $error); + } + if ($found === false) { + printValues($errMsg, $det, $rand, $input0, $input1); + } + } else { + printValues($errMsg, $det, $rand, $input0, $input1); + } + } + } + dropProc($conn, $spname); + dropTable($conn, $tbname); + } + } + unset($stmt); + unset($conn); + } catch (PDOException $e) { + echo $e->getMessage(); + } +} + +testOutputChars(false); +testOutputChars(true); + +echo "Done\n"; + +?> +--CLEAN-- + +--EXPECT-- +Done \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_ae_output_param_datetimes.phpt b/test/functional/pdo_sqlsrv/pdo_ae_output_param_datetimes.phpt new file mode 100644 index 00000000..02e2c83f --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ae_output_param_datetimes.phpt @@ -0,0 +1,204 @@ +--TEST-- +Test for retrieving encrypted data of datetimes as output parameters +--DESCRIPTION-- +Use PDOstatement::bindParam with all PDO::PARAM_ types +--ENV-- +PHPT_EXEC=true +--SKIPIF-- + +--FILE-- + array("0001-01-01 00:00:00", "9999-12-31 23:59:59"), + "datetimeoffset" => array("0001-01-01 00:00:00 -14:00", "9999-12-31 23:59:59 +14:00"), + "time" => array("00:00:00", "23:59:59")); + +$errors = array("IMSSP" => "An invalid PHP type was specified as an output parameter. DateTime objects, NULL values, and streams cannot be specified as output parameters.", "07006" => "Restricted data type attribute violation"); + +$pdoParamTypes = array( + PDO::PARAM_BOOL, // 5 + PDO::PARAM_NULL, // 0 + PDO::PARAM_INT, // 1 + PDO::PARAM_STR, // 2 + PDO::PARAM_LOB // 3 +); + +////////////////////////////////////////////////////////////////////////////////// + +// compareDate() returns true when the date/time values are basically the same +// e.g. 00:00:00.000 is the same as 00:00:00 +function compareDate($dtout, $dtin, $dataType) +{ + if ($dataType == "datetimeoffset") { + $dtarr = explode(' ', $dtin); + if (strpos($dtout, $dtarr[0]) !== false && strpos($dtout, $dtarr[1]) !== false && strpos($dtout, $dtarr[2]) !== false) { + return true; + } + } else { + if (strpos($dtout, $dtin) !== false) { + return true; + } + } + return false; +} + +function printValues($msg, $det, $rand, $inputValues) +{ + echo $msg; + echo "input 0: "; var_dump($inputValues[0]); + echo "fetched: "; var_dump($det); + echo "input 1: "; var_dump($inputValues[1]); + echo "fetched: "; var_dump($rand); +} + +function testOutputDatetimes($inout) +{ + global $pdoParamTypes, $dataTypes, $precisions, $inputValuesInit, $errors; + + try { + $conn = connect(); + + $tbname = "test_datetimes_types"; + $spname = "test_datetimes_proc"; + + foreach ($dataTypes as $dataType) { + foreach ($precisions as $precision) { + // change the input values depending on the precision + $inputValues[0] = $inputValuesInit[$dataType][0]; + $inputValues[1] = $inputValuesInit[$dataType][1]; + if ($precision != 0) { + if ($dataType == "datetime2") { + $inputValues[1] .= "." . str_repeat("9", $precision); + } else if ($dataType == "datetimeoffset") { + $inputPieces = explode(" ", $inputValues[1]); + $inputValues[1] = $inputPieces[0] . " " . $inputPieces[1] . "." . str_repeat("9", $precision) . " " . $inputPieces[2]; + } else if ($dataType == "time") { + $inputValues[0] .= "." . str_repeat("0", $precision); + $inputValues[1] .= "." . str_repeat("9", $precision); + } + } + + $type = "$dataType($precision)"; + trace("\nTesting $type:\n"); + + //create and populate table + $colMetaArr = array(new ColumnMeta($type, "c_det"), new ColumnMeta($type, "c_rand", null, "randomized")); + createTable($conn, $tbname, $colMetaArr); + + $stmt = insertRow($conn, $tbname, array("c_det" => $inputValues[0], "c_rand" => $inputValues[1])); + + // fetch with PDO::bindParam using a stored procedure + $procArgs = "@c_det $type OUTPUT, @c_rand $type OUTPUT"; + $procCode = "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname"; + createProc($conn, $spname, $procArgs, $procCode); + + // call stored procedure + $outSql = getCallProcSqlPlaceholders($spname, 2); + foreach ($pdoParamTypes as $pdoParamType) { + $det = 0; + $rand = 0; + $stmt = $conn->prepare($outSql); + trace("\nParam $pdoParamType with INOUT = $inout\n"); + + if ($inout) { + $paramType = $pdoParamType | PDO::PARAM_INPUT_OUTPUT; + } else { + $paramType = $pdoParamType; + } + + $len = 2048; + if ($pdoParamType == PDO::PARAM_BOOL || $pdoParamType == PDO::PARAM_INT) { + $len = PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE; + } + + $stmt->bindParam(1, $det, $paramType, $len); + $stmt->bindParam(2, $rand, $paramType, $len); + + try { + $stmt->execute(); + $errMsg = "****$type as $pdoParamType failed with INOUT = $inout:****\n"; + // What follows only happens with OUTPUT parameter + if ($inout) { + echo "Any datetime type as INOUT param should have caused an exception!\n"; + } + if ($pdoParamType == PDO::PARAM_INT) { + // Expect an integer, the first part of the date time string + $ch = ($dataType == "time")? ':' : '-'; + $tmp0 = explode($ch, $inputValues[0]); + $tmp1 = explode($ch, $inputValues[1]); + + if ($det != intval($tmp0[0]) || $rand != intval($tmp1[0])) { + printValues($errMsg, $det, $rand, $inputValues); + } + } elseif (!compareDate($det, $inputValues[0], $dataType) || + !compareDate($rand, $inputValues[1], $dataType)) { + printValues($errMsg, $det, $rand, $inputValues); + } + } catch (PDOException $e) { + $message = $e->getMessage(); + $errMsg = "EXCEPTION: ****$type as $pdoParamType failed with INOUT = $inout:\n$message****\n"; + if ($pdoParamType == PDO::PARAM_NULL || $pdoParamType == PDO::PARAM_LOB) { + // Expected error IMSSP: "An invalid PHP type was specified + // as an output parameter. DateTime objects, NULL values, and + // streams cannot be specified as output parameters." + $found = strpos($message, $errors['IMSSP']); + } elseif (isAEConnected()) { + if ($pdoParamType == PDO::PARAM_BOOL) { + // Expected error 07006: "Restricted data type attribute violation" + // What does this error mean? + // The data value returned for a parameter bound as + // SQL_PARAM_INPUT_OUTPUT or SQL_PARAM_OUTPUT could not + // be converted to the data type identified by the + // ValueType argument in SQLBindParameter. + $found = strpos($message, $errors['07006']); + } else { + $error = "Invalid character value for cast specification"; + $found = strpos($message, $error); + } + } else { + if ($pdoParamType == PDO::PARAM_BOOL) { + $error = "Operand type clash: int is incompatible with $dataType"; + } else { + $error = "Error converting data type nvarchar to $dataType"; + } + $found = strpos($message, $error); + } + if ($found === false) { + printValues($errMsg, $det, $rand, $inputValues); + } + } + } + dropProc($conn, $spname); + dropTable($conn, $tbname); + } + } + unset($stmt); + unset($conn); + } catch (PDOException $e) { + echo $e->getMessage(); + } +} + +testOutputDatetimes(false); +testOutputDatetimes(true); + +echo "Done\n"; + +?> +--CLEAN-- + +--EXPECT-- +Done \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_ae_output_param_decimals.phpt b/test/functional/pdo_sqlsrv/pdo_ae_output_param_decimals.phpt new file mode 100644 index 00000000..4f30c1a2 --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ae_output_param_decimals.phpt @@ -0,0 +1,242 @@ +--TEST-- +Test for retrieving encrypted data of decimals/numerics as output parameters +--DESCRIPTION-- +Use PDOstatement::bindParam with all PDO::PARAM_ types +--ENV-- +PHPT_EXEC=true +--SKIPIF-- + +--FILE-- + array(0, 1), + 4 => array(0, 1, 4), + 16 => array(0, 1, 4, 16), + 38 => array(0, 1, 4, 16, 38)); +$inputValuesInit = array(92233720368547758089223372036854775808, -92233720368547758089223372036854775808); +$inputPrecision = 38; + +$errors = array("IMSSP" => "An invalid PHP type was specified as an output parameter. DateTime objects, NULL values, and streams cannot be specified as output parameters."); + +$pdoParamTypes = array( + PDO::PARAM_BOOL, // 5 + PDO::PARAM_NULL, // 0 + PDO::PARAM_INT, // 1 + PDO::PARAM_STR, // 2 + PDO::PARAM_LOB // 3 +); + +function printValues($msg, $det, $rand, $inputValues) +{ + echo $msg; + echo "input 0: "; var_dump($inputValues[0]); + echo "fetched: "; var_dump($det); + echo "input 1: "; var_dump($inputValues[1]); + echo "fetched: "; var_dump($rand); +} + +// this function returns true if the floats are more different than expected +function compareFloats($actual, $expected) +{ + $epsilon = 0.00001; + $diff = abs(($actual - $expected) / $expected); + return ($diff > $epsilon); +} + +// function compareIntegers() returns false when the fetched values +// are different from the expected inputs +function compareIntegers($det, $rand, $inputValues, $pdoParamType) +{ + /////////////////////////////////////////////////////////////////////// + // See GitHub issue 707 - Fix this method when the problem is addressed + // + // Assume $pdoParamType is PDO::PARAM_BOOL or PDO::PARAM_INT + if (is_string($det)) { + return (!compareFloats(floatval($det), $inputValues[0]) + && !compareFloats(floatval($rand), $inputValues[1])); + } elseif ($pdoParamType == PDO::PARAM_INT) { + $input0 = floor($inputValues[0]); // the positive float + $input1 = ceil($inputValues[1]); // the negative float + + return ($det == $input0 && $rand == $input1); + } else { + // $pdoParamType == PDO::PARAM_BOOL + // Expect bool(true) or bool(false) depending on the rounded input values + // But with AE enabled (aforementioned GitHub issue), the fetched values + // are floats instead, which should be fixed + $input0 = floor($inputValues[0]); // the positive float + $input1 = ceil($inputValues[1]); // the negative float + if (isAEConnected()) { + $det = boolval(floor($det)); + $rand = boolval(ceil($rand)); + } + + return ($det == boolval($input0) && $rand == boolval($input1)); + } +} + +// function compareDecimals() returns false when the fetched values +// are different from the inputs, based on precision, scale +function compareDecimals($det, $rand, $inputValues, $pdoParamType, $precision, $scale) +{ + // Assume $pdoParamType is PDO::PARAM_STR + for ($i = 0; $i < 2; $i++) { + $inputStr = strval($inputValues[$i]); + $fetchedStr = ($i == 0) ? strval(floatval($det)) : strval(floatval($rand)); + + if ($precision == $scale) { + // compare up to $precision + digits left if radix point ('.') + + // 1 digit ('.') + possibly the negative sign + $len = $precision + 2 + $i; + } elseif ($scale > 0) { + // compare up to $precision + 1 digit ('.') + // + possibly the negative sign + $len = $precision + 1 + $i; + } else { + // in this case, $scale = 0 + // compare up to $precision + possibly the negative sign + $len = $precision + $i; + } + + trace("Comparing $len..."); + $result = substr_compare($inputStr, $fetchedStr, 0, $len); + if ($result != 0) { + return false; + } + } + return true; +} + +function testOutputDecimals($inout) +{ + global $pdoParamTypes, $dataTypes, $inputValuesInit, $precisions, $inputPrecision, $errors; + + try { + $conn = connect(); + + $tbname = "test_decimals_types"; + $spname = "test_decimals_proc"; + + foreach ($dataTypes as $dataType) { + foreach ($precisions as $precision => $scales) { + foreach ($scales as $scale) { + // construct the input values depending on the precision and scale + $precDiff = $inputPrecision - ($precision - $scale); + $inputValues = $inputValuesInit; + foreach ($inputValues as &$inputValue) { + $inputValue = $inputValue / pow(10, $precDiff); + } + + $type = "$dataType($precision, $scale)"; + trace("\nTesting $type:\n"); + + //create and populate table + $colMetaArr = array(new ColumnMeta($type, "c_det"), new ColumnMeta($type, "c_rand", null, "randomized")); + createTable($conn, $tbname, $colMetaArr); + + $stmt = insertRow($conn, $tbname, array("c_det" => $inputValues[0], "c_rand" => $inputValues[1])); + + // fetch with PDO::bindParam using a stored procedure + $procArgs = "@c_det $type OUTPUT, @c_rand $type OUTPUT"; + $procCode = "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname"; + createProc($conn, $spname, $procArgs, $procCode); + + // call stored procedure + $outSql = getCallProcSqlPlaceholders($spname, 2); + foreach ($pdoParamTypes as $pdoParamType) { + $det = $rand = 0.0; + $stmt = $conn->prepare($outSql); + + $len = 2048; + // Do not initialize $det or $rand as empty strings + // See VSO 2915 for details + if ($pdoParamType == PDO::PARAM_BOOL || $pdoParamType == PDO::PARAM_INT) { + $len = PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE; + $det = $rand = 0; + } + + trace("\nParam $pdoParamType with INOUT = $inout\n"); + if ($inout) { + $paramType = $pdoParamType | PDO::PARAM_INPUT_OUTPUT; + } else { + $paramType = $pdoParamType; + } + + $stmt->bindParam(1, $det, $paramType, $len); + $stmt->bindParam(2, $rand, $paramType, $len); + + try { + $stmt->execute(); + + $errMsg = "****$type as $pdoParamType failed with INOUT = $inout:****\n"; + if ($pdoParamType == PDO::PARAM_BOOL || $pdoParamType == PDO::PARAM_INT) { + if (!compareIntegers($det, $rand, $inputValues, $pdoParamType)) { + printValues($errMsg, $det, $rand, $inputValues); + } + } else { + // When $pdoParamType is PDO::PARAM_STR, the accuracies + // should have been preserved based on the original + // precision and scale, so compare the retrieved values + // against the input values with more details + if (!compareDecimals($det, $rand, $inputValues, $pdoParamType, $precision, $scale)) { + printValues($errMsg, $det, $rand, $inputValues); + } + } + } catch (PDOException $e) { + $message = $e->getMessage(); + $errMsg = "EXCEPTION: ****$type as $pdoParamType failed with INOUT = $inout:****\n"; + if ($pdoParamType == PDO::PARAM_NULL || $pdoParamType == PDO::PARAM_LOB) { + // Expected error IMSSP: "An invalid PHP type was specified + // as an output parameter. DateTime objects, NULL values, and + // streams cannot be specified as output parameters." + $found = strpos($message, $errors['IMSSP']); + if ($found === false) { + printValues($errMsg, $det, $rand, $inputValues); + } + } elseif (!isAEConnected() && $precision >= 16 && $pdoParamType == PDO::PARAM_BOOL) { + // When not AE enabled, large numbers are expected to + // fail when converting to booleans + $error = "Error converting data type $dataType to int"; + $found = strpos($message, $error); + if ($found === false) { + printValues($errMsg, $det, $rand, $inputValues); + } + } else { + printValues($errMsg, $det, $rand, $inputValues); + } + } + } + dropProc($conn, $spname); + dropTable($conn, $tbname); + } + } + } + unset($stmt); + unset($conn); + } catch (PDOException $e) { + echo $e->getMessage(); + } +} + +testOutputDecimals(false); +testOutputDecimals(true); + +echo "Done\n"; + +?> +--CLEAN-- + +--EXPECT-- +Done \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_ae_output_param_floats.phpt b/test/functional/pdo_sqlsrv/pdo_ae_output_param_floats.phpt new file mode 100644 index 00000000..54a5e4ac --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ae_output_param_floats.phpt @@ -0,0 +1,181 @@ +--TEST-- +Test for retrieving encrypted data of floats as output parameters +--DESCRIPTION-- +Use PDOstatement::bindParam with all PDO::PARAM_ types +--ENV-- +PHPT_EXEC=true +--SKIPIF-- + +--FILE-- + "An invalid PHP type was specified as an output parameter. DateTime objects, NULL values, and streams cannot be specified as output parameters."); + +$pdoParamTypes = array( + PDO::PARAM_BOOL, // 5 + PDO::PARAM_NULL, // 0 + PDO::PARAM_INT, // 1 + PDO::PARAM_STR, // 2 + PDO::PARAM_LOB // 3 +); + +////////////////////////////////////////////////////////////////////////////////// + +// this function returns true if the floats are more different than expected +function compareFloats($actual, $expected) +{ + $epsilon = 0.0001; + $diff = abs(($actual - $expected) / $expected); + return ($diff > $epsilon); +} + +function printValues($msg, $det, $rand, $inputValues) +{ + echo $msg; + echo "input 0: "; var_dump($inputValues[0]); + echo "fetched: "; var_dump($det); + echo "input 1: "; var_dump($inputValues[1]); + echo "fetched: "; var_dump($rand); +} + +function testOutputFloats($fetchNumeric, $inout) +{ + global $pdoParamTypes, $inputValues, $errors; + + try { + $conn = connect(); + $conn->setAttribute(PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE, $fetchNumeric); + + $tbname = "test_floats_types"; + $spname = "test_floats_proc"; + + $bits = array(1, 12, 24, 36, 53); + + foreach ($bits as $bit) { + $type = "float($bit)"; + trace("\nTesting $type:\n"); + + $inputValues = array(); + // create random input values + for ($i = 0; $i < 2; $i++) { + $mantissa = rand(1, 100000000); + $decimals = rand(1, 100000000); + $floatNum = $mantissa + $decimals / 10000000; + if ($i > 0) { + // make the second input negative + $floatNum *= -1; + } + array_push($inputValues, $floatNum); + } + //create and populate table + $colMetaArr = array(new ColumnMeta($type, "c_det"), new ColumnMeta($type, "c_rand", null, "randomized")); + createTable($conn, $tbname, $colMetaArr); + insertRow($conn, + $tbname, + array("c_det" => new BindParamOp(1, $inputValues[0], 'PDO::PARAM_INT'), + "c_rand" => new BindParamOp(2, $inputValues[1], 'PDO::PARAM_INT')), + "prepareBindParam"); + + // fetch with PDO::bindParam using a stored procedure + $procArgs = "@c_det $type OUTPUT, @c_rand $type OUTPUT"; + $procCode = "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname"; + createProc($conn, $spname, $procArgs, $procCode); + + // call stored procedure + $outSql = getCallProcSqlPlaceholders($spname, 2); + foreach ($pdoParamTypes as $pdoParamType) { + if ($pdoParamType == PDO::PARAM_INT && (strtoupper(substr(PHP_OS, 0, 3)) != 'WIN' || substr(PHP_VERSION, 0, 3) == "7.0")) { + // Bug 2876 in VSO: Linux or PHP 7.0 - when retrieving a float as OUTPUT + // or INOUT parameter with PDO::PARAM_INT, the returned values + // are always single digits, regardless of the original floats + continue; + } + + $det = 0.0; + $rand = 0.0; + $stmt = $conn->prepare($outSql); + + $len = 2048; + if ($pdoParamType == PDO::PARAM_BOOL || $pdoParamType == PDO::PARAM_INT) { + $len = PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE; + $det = 0; + $rand = 0; + } + trace("\nParam $pdoParamType with INOUT = $inout\n"); + + if ($inout) { + $paramType = $pdoParamType | PDO::PARAM_INPUT_OUTPUT; + } else { + $paramType = $pdoParamType; + } + $stmt->bindParam(1, $det, $paramType, $len); + $stmt->bindParam(2, $rand, $paramType, $len); + + try { + $stmt->execute(); + + $errMsg = "****$type as $pdoParamType failed with INOUT = $inout:****\n"; + if ($pdoParamType == PDO::PARAM_BOOL) { + // for boolean values, they should all be bool(true) + // because all floats are non-zeroes + if (!$det || !$rand) { + printValues($errMsg, $det, $rand, $inputValues); + } + } else { + // Compare the retrieved values against the input values + // if either of them is very different, print them all + if (compareFloats(floatval($det), $inputValues[0]) || + compareFloats(floatval($rand), $inputValues[1])) { + printValues($errMsg, $det, $rand, $inputValues); + } + } + } catch (PDOException $e) { + $message = $e->getMessage(); + $errMsg = "EXCEPTION: ****$type as $pdoParamType failed with INOUT = $inout:****\n"; + + if ($pdoParamType == PDO::PARAM_NULL || $pdoParamType == PDO::PARAM_LOB) { + // Expected error IMSSP: "An invalid PHP type was specified + // as an output parameter. DateTime objects, NULL values, and + // streams cannot be specified as output parameters." + $found = strpos($message, $errors['IMSSP']); + if ($found === false) { + printValues($errMsg, $det, $rand, $inputValues); + } + } else { + printValues($errMsg, $det, $rand, $inputValues); + } + } + } + dropProc($conn, $spname); + dropTable($conn, $tbname); + } + unset($stmt); + unset($conn); + } catch (PDOException $e) { + echo $e->getMessage(); + } +} + +testOutputFloats(false, false); +testOutputFloats(true, false); +testOutputFloats(false, true); +testOutputFloats(true, true); + +echo "Done\n"; + +?> +--CLEAN-- + +--EXPECT-- +Done \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_ae_output_param_integers.phpt b/test/functional/pdo_sqlsrv/pdo_ae_output_param_integers.phpt new file mode 100644 index 00000000..c65e6ff8 --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ae_output_param_integers.phpt @@ -0,0 +1,193 @@ +--TEST-- +Test for retrieving encrypted data of integral types as output parameters +--DESCRIPTION-- +Use PDOstatement::bindParam with all PDO::PARAM_ types +--ENV-- +PHPT_EXEC=true +--SKIPIF-- + +--FILE-- + "An invalid PHP type was specified as an output parameter. DateTime objects, NULL values, and streams cannot be specified as output parameters.", "22003" => "Numeric value out of range", "42000" => "Error converting data type bigint to int"); + +$pdoParamTypes = array( + PDO::PARAM_BOOL, // 5 + PDO::PARAM_NULL, // 0 + PDO::PARAM_INT, // 1 + PDO::PARAM_STR, // 2 + PDO::PARAM_LOB // 3 +); + +////////////////////////////////////////////////////////////////////////////////// +function printValues($msg, $det, $rand, $inputValues) +{ + echo $msg; + echo "input 0: "; var_dump($inputValues[0]); + echo "fetched: "; var_dump($det); + echo "input 1: "; var_dump($inputValues[1]); + echo "fetched: "; var_dump($rand); +} + +function generateInputs($dataType) +{ + // create random input values based on data types + // make the second input negative but only for some data types + if ($dataType == "bit") { + $inputValues = array(0, 1); + } elseif ($dataType == "tinyint") { + $inputValues = array(); + for ($i = 0; $i < 2; $i++) { + $randomNum = rand(0, 255); + array_push($inputValues, $randomNum); + } + } else { + switch ($dataType) { + case "smallint": + $max = 32767; + break; + case "int": + $max = 2147483647; + break; + default: + $max = getrandmax(); + } + + $inputValues = array(); + for ($i = 0; $i < 2; $i++) { + $randomNum = rand(0, $max); + if ($i > 0) { + // make the second input negative but only for some data types + $randomNum *= -1; + } + array_push($inputValues, $randomNum); + if (traceMode()) { + echo "input: "; var_dump($inputValues[$i]); + } + } + } + return $inputValues; +} + +function testOutputInts($inout) +{ + global $pdoParamTypes, $dataTypes, $errors; + + try { + $conn = connect(); + $tbname = "test_integers_types"; + $spname = "test_integers_proc"; + + foreach ($dataTypes as $dataType) { + trace("\nTesting $dataType:\n"); + + //create and populate table + $colMetaArr = array(new ColumnMeta($dataType, "c_det"), new ColumnMeta($dataType, "c_rand", null, "randomized")); + createTable($conn, $tbname, $colMetaArr); + $inputValues = generateInputs($dataType); + insertRow($conn, $tbname, array("c_det" => $inputValues[0], + "c_rand" => $inputValues[1])); + + // fetch with PDO::bindParam using a stored procedure + $procArgs = "@c_det $dataType OUTPUT, @c_rand $dataType OUTPUT"; + $procCode = "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname"; + createProc($conn, $spname, $procArgs, $procCode); + + // call stored procedure + $outSql = getCallProcSqlPlaceholders($spname, 2); + foreach ($pdoParamTypes as $pdoParamType) { + $det = 0; + $rand = 0; + $stmt = $conn->prepare($outSql); + + $len = 2048; + if ($pdoParamType == PDO::PARAM_BOOL || $pdoParamType == PDO::PARAM_INT) { + $len = PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE; + } + trace("\nParam $pdoParamType with INOUT = $inout\n"); + + if ($inout) { + $paramType = $pdoParamType | PDO::PARAM_INPUT_OUTPUT; + } else { + $paramType = $pdoParamType; + } + $stmt->bindParam(1, $det, $paramType, $len); + $stmt->bindParam(2, $rand, $paramType, $len); + + try { + $stmt->execute(); + $errMsg = "****$dataType as $pdoParamType failed with INOUT = $inout:****\n"; + if ($pdoParamType == PDO::PARAM_STR) { + if ($det !== strval($inputValues[0]) || $rand !== strval($inputValues[1])) { + // comparisons between strings, use '!==' + printValues($errMsg, $det, $rand, $inputValues); + } + } elseif ($pdoParamType == PDO::PARAM_INT || $pdoParamType == PDO::PARAM_BOOL) { + // comparisons between integers and booleans, do not use '!==' + if ($det != $inputValues[0] || $rand != $inputValues[1]) { + printValues($errMsg, $det, $rand, $inputValues); + } + } else { + printValues($errMsg, $det, $rand, $inputValues); + } + } catch (PDOException $e) { + $message = $e->getMessage(); + $errMsg = "EXCEPTION: ****$dataType as $pdoParamType failed with INOUT = $inout:****\n"; + if ($pdoParamType == PDO::PARAM_NULL || $pdoParamType == PDO::PARAM_LOB) { + // Expected error IMSSP: "An invalid PHP type was specified + // as an output parameter. DateTime objects, NULL values, and + // streams cannot be specified as output parameters." + $found = strpos($message, $errors['IMSSP']); + if ($found === false) { + printValues($errMsg, $det, $rand, $inputValues); + } + } elseif ($dataType == "bigint" && ($pdoParamType == PDO::PARAM_INT || $pdoParamType == PDO::PARAM_BOOL)) { + if (isAEConnected()) { + // Expected error 22003: "Numeric value out of range" + // This is expected when converting big integer to integer or bool + $found = strpos($message, $errors['22003']); + } elseif ($pdoParamType == PDO::PARAM_BOOL) { + // Expected error 42000: "Error converting data type bigint to int" + // This is expected when not AE connected and converting big integer to bool + $found = strpos($message, $errors['42000']); + } + if ($found === false) { + printValues($errMsg, $det, $rand, $inputValues); + } + } else { + printValues($errMsg, $det, $rand, $inputValues); + } + } + } + dropProc($conn, $spname); + dropTable($conn, $tbname); + } + unset($stmt); + unset($conn); + } catch (PDOException $e) { + echo $e->getMessage(); + } +} + +testOutputInts(false); +testOutputInts(true); + +echo "Done\n"; + +?> +--CLEAN-- + +--EXPECT-- +Done \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_ae_output_param_nchar_size.phpt b/test/functional/pdo_sqlsrv/pdo_ae_output_param_nchar_size.phpt new file mode 100644 index 00000000..e6da0d9c --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ae_output_param_nchar_size.phpt @@ -0,0 +1,172 @@ +--TEST-- +Test for retrieving encrypted data of nchar types of various sizes as output parameters +--DESCRIPTION-- +Use PDOstatement::bindParam with all PDO::PARAM_ types +Note: Because the maximum allowable table row size is 8060 bytes, 7 bytes of which are reserved for internal overhead. In other words, this allows up to two nvarchar() columns with length slightly +more than 2000 wide characters. Therefore, the max length in this test is 2010. +--ENV-- +PHPT_EXEC=true +--SKIPIF-- + +--FILE-- + "An invalid PHP type was specified as an output parameter. DateTime objects, NULL values, and streams cannot be specified as output parameters.", "22003" => "Numeric value out of range"); + +$pdoParamTypes = array( + PDO::PARAM_BOOL, // 5 + PDO::PARAM_NULL, // 0 + PDO::PARAM_INT, // 1 + PDO::PARAM_STR, // 2 + PDO::PARAM_LOB // 3 +); + +////////////////////////////////////////////////////////////////////////////////// +function printValues($msg, $det, $rand, $input0, $input1) +{ + echo $msg; + echo "input 0: "; var_dump($input0); + echo "fetched: "; var_dump($det); + echo "input 1: "; var_dump($input1); + echo "fetched: "; var_dump($rand); +} + +function testOutputNChars($inout) +{ + global $pdoParamTypes, $dataTypes, $lengths, $errors; + + try { + $conn = connect(); + $tbname = "test_nchar_types"; + $spname = "test_nchar_proc"; + + foreach ($dataTypes as $dataType) { + $maxtype = strpos($dataType, "(max)"); + foreach ($lengths as $length) { + if ($maxtype !== false) { + $type = $dataType; + } else { + $type = "$dataType($length)"; + } + trace("\nTesting $type:\n"); + + //create and populate table + $colMetaArr = array(new ColumnMeta($type, "c_det"), new ColumnMeta($type, "c_rand", null, "randomized")); + createTable($conn, $tbname, $colMetaArr); + $input0 = str_repeat("1", $length); + $input1 = str_repeat("2", $length); + insertRow($conn, $tbname, array("c_det" => $input0, + "c_rand" => $input1)); + + // fetch with PDO::bindParam using a stored procedure + $procArgs = "@c_det $type OUTPUT, @c_rand $type OUTPUT"; + $procCode = "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname"; + createProc($conn, $spname, $procArgs, $procCode); + + // call stored procedure + $outSql = getCallProcSqlPlaceholders($spname, 2); + foreach ($pdoParamTypes as $pdoParamType) { + $det = ""; + $rand = ""; + $stmt = $conn->prepare($outSql); + trace("\nParam $pdoParamType with INOUT = $inout\n"); + + if ($inout) { + $paramType = $pdoParamType | PDO::PARAM_INPUT_OUTPUT; + } else { + $paramType = $pdoParamType; + } + + $len = $length; + if ($pdoParamType == PDO::PARAM_BOOL || $pdoParamType == PDO::PARAM_INT) { + $len = PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE; + $det = $rand = 0; + } + + $stmt->bindParam(1, $det, $paramType, $len); + $stmt->bindParam(2, $rand, $paramType, $len); + + try { + $stmt->execute(); + $errMsg = "****$type as $pdoParamType failed with INOUT = $inout:****\n"; + // When $length >= 64, a string is returned regardless of $pdoParamType + if ($length < 64 && $pdoParamType != PDO::PARAM_STR) { + if ($pdoParamType == PDO::PARAM_BOOL) { + // For boolean values, they should all be bool(true) + // because all "string literals" are non-zeroes + if (!$det || !$rand) { + printValues($errMsg, $det, $rand, $input0, $input1); + } + } else { + // $pdoParamType = PDO::PARAM_INT + // Expect numeric values + if ($det != intval($input0) || $rand != intval($input1)) { + printValues($errMsg, $det, $rand, $input0, $input1); + } + } + } elseif ($det !== $input0 || $rand !== $input1) { + printValues($errMsg, $det, $rand, $input0, $input1); + } + } catch (PDOException $e) { + $message = $e->getMessage(); + $errMsg = "EXCEPTION: ****$type as $pdoParamType failed with INOUT = $inout:****\n"; + if ($pdoParamType == PDO::PARAM_NULL || $pdoParamType == PDO::PARAM_LOB) { + // Expected error IMSSP: "An invalid PHP type was specified + // as an output parameter. DateTime objects, NULL values, and + // streams cannot be specified as output parameters." + $found = strpos($message, $errors['IMSSP']); + if ($found === false) { + printValues($errMsg, $det, $rand, $input0, $input1); + } + } elseif ($pdoParamType == PDO::PARAM_BOOL) { + if (isAEConnected()) { + // Expected error 22003: "Numeric value out of range" + $found = strpos($message, $errors['22003']); + } else { + // When not AE enabled, expected to fail to convert + // whatever char type to integers + $error = "Error converting data type $dataType to int"; + $found = strpos($message, $error); + } + if ($found === false) { + printValues($errMsg, $det, $rand, $input0, $input1); + } + } else { + printValues($errMsg, $det, $rand, $input0, $input1); + } + } + } + dropProc($conn, $spname); + dropTable($conn, $tbname); + } + } + unset($stmt); + unset($conn); + } catch (PDOException $e) { + echo $e->getMessage(); + } +} + +testOutputNChars(false); +testOutputNChars(true); + +echo "Done\n"; + +?> +--CLEAN-- + +--EXPECT-- +Done \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_connect_driver.phpt b/test/functional/pdo_sqlsrv/pdo_connect_driver.phpt index 468f9ceb..34186baf 100644 --- a/test/functional/pdo_sqlsrv/pdo_connect_driver.phpt +++ b/test/functional/pdo_sqlsrv/pdo_connect_driver.phpt @@ -1,160 +1,138 @@ ---TEST-- -Test new connection keyword Driver with valid and invalid values ---SKIPIF-- - ---FILE-- -getAttribute(PDO::ATTR_CLIENT_VERSION)['DriverVer']; - $msodbcsqlMaj = explode(".", $msodbcsqlVer)[0]; -} catch(PDOException $e) { - echo "Failed to connect\n"; - print_r($e->getMessage()); - echo "\n"; -} - -$conn = null; - -// start test -testValidValues(); -testInvalidValues(); -testEncryptedWithODBC(); -testWrongODBC(); -echo "Done"; -// end test - -/////////////////////////// -function connectVerifyOutput($connectionOptions, $expected = '') -{ - global $server, $uid, $pwd; - - try { - $conn = new PDO("sqlsrv:server = $server ; $connectionOptions", $uid, $pwd); - } catch(PDOException $e) { - if (strpos($e->getMessage(), $expected) === false) { - print_r($e->getMessage()); - echo "\n"; - } - } -} - -function testValidValues() -{ - global $msodbcsqlMaj; - - $value = ""; - // The major version number of ODBC 11 can be 11 or 12 - // Test with {} - switch ($msodbcsqlMaj) { - case 17: - $value = "{ODBC Driver 17 for SQL Server}"; - break; - case 14: - case 13: - $value = "{ODBC Driver 13 for SQL Server}"; - break; - case 12: - case 11: - $value = "{ODBC Driver 11 for SQL Server}"; - break; - default: - $value = "invalid value $msodbcsqlMaj"; - } - $connectionOptions = "Driver = $value"; - connectVerifyOutput($connectionOptions); - - // Test without {} - switch ($msodbcsqlMaj) { - case 17: - $value = "ODBC Driver 17 for SQL Server"; - break; - case 14: - case 13: - $value = "ODBC Driver 13 for SQL Server"; - break; - case 12: - case 11: - $value = "ODBC Driver 11 for SQL Server"; - break; - default: - $value = "invalid value $msodbcsqlMaj"; - } - - $connectionOptions = "Driver = $value"; - connectVerifyOutput($connectionOptions); -} - -function testInvalidValues() -{ - $values = array("{SQL Server Native Client 11.0}", - "SQL Server Native Client 11.0", - "ODBC Driver 00 for SQL Server", - 123, - false); - - foreach ($values as $value) { - $connectionOptions = "Driver = $value"; - $expected = "Invalid value $value was specified for Driver option."; - connectVerifyOutput($connectionOptions, $expected); - } -} - -function testEncryptedWithODBC() -{ - global $msodbcsqlMaj, $server, $uid, $pwd; - - $value = "ODBC Driver 13 for SQL Server"; - $connectionOptions = "Driver = $value; ColumnEncryption = Enabled;"; - $expected = "The Always Encrypted feature requires Microsoft ODBC Driver 17 for SQL Server."; - - connectVerifyOutput($connectionOptions, $expected); - - // TODO: the following block will change once ODBC 17 is officially released - $value = "ODBC Driver 17 for SQL Server"; - $connectionOptions = "Driver = $value; ColumnEncryption = Enabled;"; - - $success = "Successfully connected with column encryption."; - $expected = "The specified ODBC Driver is not found."; - $message = $success; - try { - $conn = new PDO("sqlsrv:server = $server ; $connectionOptions", $uid, $pwd); - } catch(PDOException $e) { - $message = $e->getMessage(); - } - - if ($msodbcsqlMaj == 17) { - // this indicates that OCBC 17 is the only available driver - if (strcmp($message, $success)) { - print_r($message); - } - } else { - // OCBC 17 might or might not exist - if (strcmp($message, $success)) { - if (strpos($message, $expected) === false) { - print_r($message); - } - } - } -} - -function testWrongODBC() -{ - global $msodbcsqlMaj; - - // TODO: this will change once ODBC 17 is officially released - $value = "ODBC Driver 17 for SQL Server"; - if ($msodbcsqlMaj == 17 || $msodbcsqlMaj < 13) { - $value = "ODBC Driver 13 for SQL Server"; - } - $connectionOptions = "Driver = $value;"; - $expected = "The specified ODBC Driver is not found."; - - connectVerifyOutput($connectionOptions, $expected); -} - -?> ---EXPECT-- +--TEST-- +Test new connection keyword Driver with valid and invalid values +--SKIPIF-- + +--FILE-- +getAttribute(PDO::ATTR_CLIENT_VERSION)['DriverVer']; + $msodbcsqlMaj = explode(".", $msodbcsqlVer)[0]; +} catch(PDOException $e) { + echo "Failed to connect\n"; + print_r($e->getMessage()); + echo "\n"; +} + +$conn = null; + +// start test +testValidValues(); +testInvalidValues(); +testEncryptedWithODBC(); +testWrongODBC(); +echo "Done"; +// end test + +/////////////////////////// +function connectVerifyOutput($connectionOptions, $expected = '') +{ + global $server, $uid, $pwd; + + try { + $conn = new PDO("sqlsrv:server = $server ; $connectionOptions", $uid, $pwd); + } catch(PDOException $e) { + if (strpos($e->getMessage(), $expected) === false) { + print_r($e->getMessage()); + echo "\n"; + } + } +} + +function testValidValues() +{ + global $msodbcsqlMaj; + + $value = ""; + // The major version number of ODBC 11 can be 11 or 12 + // Test with {} + switch ($msodbcsqlMaj) { + case 17: + $value = "{ODBC Driver 17 for SQL Server}"; + break; + case 14: + case 13: + $value = "{ODBC Driver 13 for SQL Server}"; + break; + case 12: + case 11: + $value = "{ODBC Driver 11 for SQL Server}"; + break; + default: + $value = "invalid value $msodbcsqlMaj"; + } + $connectionOptions = "Driver = $value"; + connectVerifyOutput($connectionOptions); + + // Test without {} + switch ($msodbcsqlMaj) { + case 17: + $value = "ODBC Driver 17 for SQL Server"; + break; + case 14: + case 13: + $value = "ODBC Driver 13 for SQL Server"; + break; + case 12: + case 11: + $value = "ODBC Driver 11 for SQL Server"; + break; + default: + $value = "invalid value $msodbcsqlMaj"; + } + + $connectionOptions = "Driver = $value"; + connectVerifyOutput($connectionOptions); +} + +function testInvalidValues() +{ + $values = array("{SQL Server Native Client 11.0}", + "SQL Server Native Client 11.0", + "ODBC Driver 00 for SQL Server", + 123, + false); + + foreach ($values as $value) { + $connectionOptions = "Driver = $value"; + $expected = "Invalid value $value was specified for Driver option."; + connectVerifyOutput($connectionOptions, $expected); + } +} + +function testEncryptedWithODBC() +{ + global $msodbcsqlMaj, $server, $uid, $pwd; + + $value = "ODBC Driver 13 for SQL Server"; + $connectionOptions = "Driver = $value; ColumnEncryption = Enabled;"; + + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + $expected = "The Always Encrypted feature requires Microsoft ODBC Driver 17 for SQL Server."; + } else { + $expected = "An invalid keyword 'ColumnEncryption' was specified in the DSN string."; + } + + connectVerifyOutput($connectionOptions, $expected); +} + +function testWrongODBC() +{ + global $msodbcsqlMaj; + + // TODO: this will change once ODBC 17 is officially released + $value = "ODBC Driver 17 for SQL Server"; + if ($msodbcsqlMaj == 17 || $msodbcsqlMaj < 13) { + $value = "ODBC Driver 13 for SQL Server"; + } + $connectionOptions = "Driver = $value;"; + $expected = "The specified ODBC Driver is not found."; + + connectVerifyOutput($connectionOptions, $expected); +} + +?> +--EXPECT-- Done \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_connect_encrypted.phpt b/test/functional/pdo_sqlsrv/pdo_connect_encrypted.phpt index cb073668..8b3b0a0e 100644 --- a/test/functional/pdo_sqlsrv/pdo_connect_encrypted.phpt +++ b/test/functional/pdo_sqlsrv/pdo_connect_encrypted.phpt @@ -1,7 +1,7 @@ --TEST-- Test new connection keyword ColumnEncryption --SKIPIF-- - + --FILE-- ---FILE-- -getMessage() ); - echo "\n"; - } - - $tbname = KSP_TEST_TABLE; - $tsql = "SELECT * FROM $tbname"; - $stmt = $conn->query($tsql); - while ($row = $stmt->fetch(PDO::FETCH_NUM)) - { - echo "c1=" . $row[0] . "\tc2=" . $row[1] . "\tc3=" . $row[2] . "\tc4=" . $row[3] . "\n"; - } - - unset($stmt); - unset($conn); - - echo "Done\n"; - -?> ---EXPECT-- -Connected successfully with ColumnEncryption enabled and KSP specified. -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 \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_connect_encrypted_ksp_encrypted.phpt b/test/functional/pdo_sqlsrv/pdo_connect_encrypted_ksp_encrypted.phpt deleted file mode 100644 index 0d7d8540..00000000 --- a/test/functional/pdo_sqlsrv/pdo_connect_encrypted_ksp_encrypted.phpt +++ /dev/null @@ -1,51 +0,0 @@ ---TEST-- -Fetch encrypted data from a prepopulated test table given a custom keystore provider ---SKIPIF-- - ---FILE-- -getMessage() ); - echo "\n"; - } - - $tbname = KSP_TEST_TABLE; - $tsql = "SELECT * FROM $tbname"; - $stmt = $conn->query($tsql); - while ($row = $stmt->fetch(PDO::FETCH_NUM)) - { - echo "c1=" . $row[0]; - echo "\tc2=" . bin2hex($row[1]); - echo "\tc3=" . bin2hex($row[2]); - echo "\tc4=" . bin2hex($row[3]); - echo "\n" ; - } - - unset($stmt); - unset($conn); - - echo "Done\n"; - -?> ---EXPECTREGEX-- -Connected successfully with ColumnEncryption disabled and KSP specified. -c1=1 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+ -c1=12 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+ -c1=23 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+ -c1=34 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+ -c1=45 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+ -c1=56 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+ -c1=67 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+ -c1=78 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+ -c1=89 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+ -c1=100 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+ -Done \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_connect_encrypted_ksp_errors.phpt b/test/functional/pdo_sqlsrv/pdo_connect_encrypted_ksp_errors.phpt deleted file mode 100644 index 505d7296..00000000 --- a/test/functional/pdo_sqlsrv/pdo_connect_encrypted_ksp_errors.phpt +++ /dev/null @@ -1,102 +0,0 @@ ---TEST-- -Connect using a custom keystore provider with some required inputs missing ---SKIPIF-- - ---FILE-- -getMessage() ); - echo "\n"; - } - } - - $ksp_path = getKSPpath(); - $ksp_name = KSP_NAME; - $encrypt_key = ENCRYPT_KEY; - - echo("Connecting... with column encryption\n"); - $connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; "; - kspConnect( $connectionInfo ); - - echo("\nConnecting... with an invalid input to CEKeystoreProvider\n"); - $connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; "; - $connectionInfo .= "CEKeystoreName = 1; "; - $connectionInfo .= "CEKeystoreProvider = $ksp_path; "; - $connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key; "; - kspConnect( $connectionInfo ); - - echo("\nConnecting... with an empty path\n"); - $connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; "; - $connectionInfo .= "CEKeystoreName = $ksp_name; "; - $connectionInfo .= "CEKeystoreProvider = ; "; - $connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key; "; - kspConnect( $connectionInfo ); - - echo("\nConnecting... without a path\n"); - $connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; "; - $connectionInfo .= "CEKeystoreName = $ksp_name; "; - $connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key;"; - kspConnect( $connectionInfo ); - - echo("\nConnecting... without a name\n"); - $connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; "; - $connectionInfo .= "CEKeystoreProvider = $ksp_path; "; - $connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key; "; - kspConnect( $connectionInfo ); - - echo("\nConnecting... without a key\n"); - $connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; "; - $connectionInfo .= "CEKeystoreProvider = $ksp_path; "; - $connectionInfo .= "CEKeystoreName = $ksp_name; "; - kspConnect( $connectionInfo ); - - echo("\nConnecting... with all required inputs\n"); - $connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; "; - $connectionInfo .= "CEKeystoreProvider = $ksp_path; "; - $connectionInfo .= "CEKeystoreName = $ksp_name; "; - $connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key; "; - kspConnect( $connectionInfo ); - - echo "Done\n"; -?> ---EXPECTREGEX-- -Connecting\.\.\. with column encryption -Connected successfully with ColumnEncryption enabled and KSP specified\. - -Connecting\.\.\. with an invalid input to CEKeystoreProvider -Failed to connect. -SQLSTATE\[HY024\]: \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]Invalid attribute value - -Connecting\.\.\. with an empty path -Failed to connect. -SQLSTATE\[IMSSP\]: Invalid value for loading a custom keystore provider\. - -Connecting\.\.\. without a path -Failed to connect. -SQLSTATE\[IMSSP\]: The path to the custom keystore provider is missing\. - -Connecting\.\.\. without a name -Failed to connect. -SQLSTATE\[IMSSP\]: The name of the custom keystore provider is missing\. - -Connecting\.\.\. without a key -Failed to connect. -SQLSTATE\[IMSSP\]: The encryption key for the custom keystore provider is missing\. - -Connecting\.\.\. with all required inputs -Connected successfully with ColumnEncryption enabled and KSP specified\. -Done \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_fetch_cursor_scroll_random.phpt b/test/functional/pdo_sqlsrv/pdo_fetch_cursor_scroll_random.phpt index a0bb02f9..5195bca6 100644 --- a/test/functional/pdo_sqlsrv/pdo_fetch_cursor_scroll_random.phpt +++ b/test/functional/pdo_sqlsrv/pdo_fetch_cursor_scroll_random.phpt @@ -41,8 +41,7 @@ function cursorScrollFetchRows($conn, $tableName) $stmt = $conn->prepare("SELECT * FROM $tableName ORDER BY c1_int", array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL)); } else { // ORDER BY is not supported for encrypted columns - // scrollable cursor is not supported for encrypted tablee; use client side buffered cursor - $stmt = $conn->prepare("SELECT * FROM $tableName", array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_BUFFERED)); + $stmt = $conn->prepare("SELECT * FROM $tableName", array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL)); } $stmt->execute(); diff --git a/test/functional/pdo_sqlsrv/pdo_getAttribute_clientInfo.phpt b/test/functional/pdo_sqlsrv/pdo_getAttribute_clientInfo.phpt index 2bbfc3e6..a98dafda 100644 --- a/test/functional/pdo_sqlsrv/pdo_getAttribute_clientInfo.phpt +++ b/test/functional/pdo_sqlsrv/pdo_getAttribute_clientInfo.phpt @@ -20,7 +20,7 @@ try { --EXPECTREGEX-- Array \( - \[(DriverDllName|DriverName)\] => (msodbcsql1[1-9].dll|libmsodbcsql-[1-9]{2}.[0-9].so.[0-9].[0-9]) + \[(DriverDllName|DriverName)\] => (msodbcsql1[1-9].dll|(libmsodbcsql-[0-9]{2}\.[0-9]\.so\.[0-9]\.[0-9]|libmsodbcsql.[0-9]{2}.dylib)) \[DriverODBCVer\] => [0-9]{1,2}\.[0-9]{1,2} \[DriverVer\] => [0-9]{1,2}\.[0-9]{1,2}\.[0-9]{4} \[ExtensionVer\] => [0-9].[0-9]\.[0-9](-(RC[0-9]?|preview))?(\.[0-9]+)?(\+[0-9]+)? diff --git a/test/functional/pdo_sqlsrv/pdo_get_set_attr.phpt b/test/functional/pdo_sqlsrv/pdo_get_set_attr.phpt index 06c69b01..e6ee2ccb 100644 --- a/test/functional/pdo_sqlsrv/pdo_get_set_attr.phpt +++ b/test/functional/pdo_sqlsrv/pdo_get_set_attr.phpt @@ -125,7 +125,7 @@ SQLSTATE\[IMSSP\]: A read-only attribute was designated on the PDO object. Get Result PDO::ATTR_CLIENT_VERSION : array\(4\) { \[\"(DriverDllName|DriverName)\"\]=> - string\(15\) \"msodbcsql[0-9]{2}\.dll|string\(24\) \"libmsodbcsql-[0-9]{2}\.[0-9]\.so\.[0-9]\.[0-9]\" + (string\([0-9]+\) \"msodbcsql1[1-9].dll\"|string\([0-9]+\) \"(libmsodbcsql-[0-9]{2}\.[0-9]\.so\.[0-9]\.[0-9]|libmsodbcsql.[0-9]{2}.dylib)\") \["DriverODBCVer"\]=> string\(5\) \"[0-9]{1,2}\.[0-9]{1,2}\" \["DriverVer"\]=> diff --git a/test/functional/pdo_sqlsrv/pdostatement_fetch_orientation.phpt b/test/functional/pdo_sqlsrv/pdostatement_fetch_orientation.phpt index f884daaf..b8fd577a 100644 --- a/test/functional/pdo_sqlsrv/pdostatement_fetch_orientation.phpt +++ b/test/functional/pdo_sqlsrv/pdostatement_fetch_orientation.phpt @@ -3,31 +3,23 @@ Test the fetch() method for different fetch orientations with PDO::ATTR_CURSOR s --ENV-- PHPT_EXEC=true --SKIPIF-- - + --FILE-- "varchar(10)")); + insertRow($conn1, $tableName, array("id" => 1, "val" => "A")); + insertRow($conn1, $tableName, array("id" => 2, "val" => "B")); + insertRow($conn1, $tableName, array("id" => 3, "val" => "C")); // Query table and retrieve data - $stmt1 = $conn1->prepare( "SELECT val FROM $tableName", array( PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL )); + $stmt1 = $conn1->prepare( "SELECT val FROM $tableName ORDER BY id", array( PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL )); $stmt1->execute(); $row = $stmt1->fetch( PDO::FETCH_ASSOC, PDO::FETCH_ORI_LAST ); @@ -158,33 +150,15 @@ function FetchAll($execMode, $fetchMode) } // Cleanup - DropTable($conn1, $tableName); - $stmt1 = null; - $conn1 = null; + dropTable($conn1, $tableName); + unset($stmt1); + unset($conn1); - EndTest($testName); + echo "Test 'PDO Statement - Fetch Scrollable' completed successfully.\n"; +} catch (Exception $e) { + echo $e->getMessage(); } - -//-------------------------------------------------------------------- -// Repro -// -//-------------------------------------------------------------------- -function Repro() -{ - - try - { - FetchAll(false, PDO::FETCH_BOTH); - } - catch (Exception $e) - { - echo $e->getMessage(); - } -} - -Repro(); - ?> --EXPECT-- -Test "PDO Statement - Fetch Scrollable" completed successfully. \ No newline at end of file +Test 'PDO Statement - Fetch Scrollable' completed successfully. \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdostatement_fetchmode_emulate_prepare.phpt b/test/functional/pdo_sqlsrv/pdostatement_fetchmode_emulate_prepare.phpt index cccac782..8791a96b 100644 --- a/test/functional/pdo_sqlsrv/pdostatement_fetchmode_emulate_prepare.phpt +++ b/test/functional/pdo_sqlsrv/pdostatement_fetchmode_emulate_prepare.phpt @@ -61,9 +61,7 @@ try { 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) @@ -114,7 +112,6 @@ try { } 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); diff --git a/test/functional/pdo_sqlsrv/skipif_mid-refactor.inc b/test/functional/pdo_sqlsrv/skipif_mid-refactor.inc index 4859bf32..a8e0e7d6 100644 --- a/test/functional/pdo_sqlsrv/skipif_mid-refactor.inc +++ b/test/functional/pdo_sqlsrv/skipif_mid-refactor.inc @@ -1,16 +1,21 @@ - \ No newline at end of file diff --git a/test/functional/setup/ae_keys.sql b/test/functional/setup/ae_keys.sql index aa4b9d78..35c87720 100644 --- a/test/functional/setup/ae_keys.sql +++ b/test/functional/setup/ae_keys.sql @@ -1,6 +1,3 @@ -USE $(dbname) -GO - /* DROP Column Encryption Key first, Column Master Key cannot be dropped until no encryption depends on it */ IF EXISTS (SELECT * FROM sys.column_encryption_keys WHERE [name] LIKE '%AEColumnKey%') diff --git a/test/functional/setup/setup_dbs.py b/test/functional/setup/setup_dbs.py index 3c8fb404..32b821ef 100644 --- a/test/functional/setup/setup_dbs.py +++ b/test/functional/setup/setup_dbs.py @@ -45,13 +45,14 @@ def executeBulkCopy(conn_options, dbname, tblname, datafile): inst_command = redirect_string.format(dbname, tblname, datafile) + conn_options executeCommmand(inst_command) -def setupAE( conn_options, dbname, azure ): - if (platform.system() == 'Windows' and azure.lower() == 'no'): +def setupAE(conn_options, dbname): + if (platform.system() == 'Windows'): # import self signed certificate inst_command = "certutil -user -p '' -importPFX My PHPcert.pfx NoRoot" executeCommmand(inst_command) # create Column Master Key and Column Encryption Key - executeSQLscript('ae_keys.sql', conn_options, dbname) + script_command = 'sqlcmd ' + conn_options + ' -i ae_keys.sql -d ' + dbname + executeCommmand(script_command) if __name__ == '__main__': parser = argparse.ArgumentParser() @@ -84,7 +85,7 @@ if __name__ == '__main__': # populate these tables populateTables(conn_options, args.DBNAME) # setup AE (certificate, column master key and column encryption key) - setupAE(conn_options, args.DBNAME, args.AZURE) + setupAE(conn_options, args.DBNAME) os.chdir(current_working_dir) diff --git a/test/functional/sqlsrv/0020.phpt b/test/functional/sqlsrv/0020.phpt index ef7df7cb..150c56bd 100644 --- a/test/functional/sqlsrv/0020.phpt +++ b/test/functional/sqlsrv/0020.phpt @@ -23,8 +23,6 @@ function runTest($fieldType) sqlsrv_fetch($stmt) || die(print_r(sqlsrv_errors(), true)); - // Do not support getting stream if AE enabled, so expect - // it to fail with the correct error message $stream = sqlsrv_get_field($stmt, 0, SQLSRV_PHPTYPE_STREAM("char")); if ($stream) { stream_filter_append($originalStream, "convert.base64-encode") @@ -37,11 +35,7 @@ function runTest($fieldType) } } } else { - 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!'); - } + fatalError('Fetching data stream failed!'); } dropTable($conn, $params['tableName']); diff --git a/test/functional/sqlsrv/0052.phpt b/test/functional/sqlsrv/0052.phpt index ad412d12..f0f55056 100644 --- a/test/functional/sqlsrv/0052.phpt +++ b/test/functional/sqlsrv/0052.phpt @@ -1,69 +1,63 @@ ---TEST-- -scrollable results with no rows. ---DESCRIPTION-- -this test is very similar to test_scrollable.phpt... might consider removing this test as a duplicate ---SKIPIF-- - ---FILE-- - SQLSRV_CURSOR_FORWARD); - } else { - $options = array('Scrollable' => 'static'); - } - - $stmt = sqlsrv_query($conn, $query, array(), $options); - $rows = sqlsrv_has_rows($stmt); - if ($rows != false) { - fatalError("Should be no rows present"); - }; - - if ($stmt === false) { - die(print_r(sqlsrv_errors(), true)); - } - $row = sqlsrv_fetch_array($stmt); - print_r($row); - if ($row === false) { - print_r(sqlsrv_errors(), true); - } - - $stmt = sqlsrv_query($conn, $query); - $rows = sqlsrv_has_rows($stmt); - if ($rows != false) { - fatalError("Should be no rows present"); - }; - - if ($stmt === false) { - die(print_r(sqlsrv_errors(), true)); - } - $row = sqlsrv_fetch_array($stmt); - print_r($row); - if ($row === false) { - print_r(sqlsrv_errors(), true); - } - - dropTable($conn, $tableName); - echo "Test succeeded.\n"; - -?> ---EXPECT-- -Test succeeded. +--TEST-- +scrollable results with no rows. +--DESCRIPTION-- +this test is very similar to test_scrollable.phpt... might consider removing this test as a duplicate +--SKIPIF-- + +--FILE-- + 'static'); + + $stmt = sqlsrv_query($conn, $query, array(), $options); + $rows = sqlsrv_has_rows($stmt); + if ($rows != false) { + fatalError("Should be no rows present"); + }; + + if ($stmt === false) { + die(print_r(sqlsrv_errors(), true)); + } + $row = sqlsrv_fetch_array($stmt); + print_r($row); + if ($row === false) { + print_r(sqlsrv_errors(), true); + } + + $stmt = sqlsrv_query($conn, $query); + $rows = sqlsrv_has_rows($stmt); + if ($rows != false) { + fatalError("Should be no rows present"); + }; + + if ($stmt === false) { + die(print_r(sqlsrv_errors(), true)); + } + $row = sqlsrv_fetch_array($stmt); + print_r($row); + if ($row === false) { + print_r(sqlsrv_errors(), true); + } + + dropTable($conn, $tableName); + echo "Test succeeded.\n"; + +?> +--EXPECT-- +Test succeeded. diff --git a/test/functional/sqlsrv/0065.phpt b/test/functional/sqlsrv/0065.phpt index a9678bbb..985b8e2b 100644 --- a/test/functional/sqlsrv/0065.phpt +++ b/test/functional/sqlsrv/0065.phpt @@ -78,8 +78,16 @@ if ($t === false) { die(print_r(sqlsrv_errors(), true)); } -if ($t != "So?e sä???? ?SCII-te×t") { - die("varchar(100) doesn't match So?e sä???? ?SCII-te×t"); +// If connected with AE, $t may be different in Windows and other platforms +// this is a workaround for now -- to make sure there are some '?' in $t +if (!AE\isColEncrypted() && $t !== "So?e sä???? ?SCII-te×t") { + die("varchar(100) \'$t\' doesn't match So?e sä???? ?SCII-te×t"); +} else { + $arr = explode('?', $t); + if (count($arr) == 1) { + // this means there is no question mark in $t + die("varchar(100) value \'$t\' is unexpected"); + } } $t = sqlsrv_get_field($s, 1, SQLSRV_PHPTYPE_STRING('utf-8')); @@ -87,7 +95,7 @@ if ($t === false) { die(print_r(sqlsrv_errors(), true)); } -if ($t != $utf8) { +if ($t !== $utf8) { die("nvarchar(100) doesn't match the inserted UTF-8 text."); } @@ -96,7 +104,7 @@ if ($t === false) { die(print_r(sqlsrv_errors(), true)); } -if ($t != $utf8) { +if ($t !== $utf8) { die("nvarchar(max) doesn't match the inserted UTF-8 text."); } @@ -129,7 +137,7 @@ if ($s === false) { die(print_r(sqlsrv_errors(), true)); } -if ($t != $utf8) { +if ($t !== $utf8) { die("Incorrect results from Utf8OutProc\n"); } @@ -148,7 +156,7 @@ if ($s === false) { // retrieve all the results while (sqlsrv_next_result($s)); -if ($t != $utf8) { +if ($t !== $utf8) { die("Incorrect results from Utf8OutWithResultsetProc\n"); } @@ -169,7 +177,7 @@ if ($s === false) { die(print_r(sqlsrv_errors(), true)); } -if ($t != $utf8) { +if ($t !== $utf8) { die("Incorrect results from Utf8InOutProc 1\n"); } diff --git a/test/functional/sqlsrv/0066.phpt b/test/functional/sqlsrv/0066.phpt index a8bcf590..5af8f85a 100644 --- a/test/functional/sqlsrv/0066.phpt +++ b/test/functional/sqlsrv/0066.phpt @@ -38,11 +38,7 @@ inserting and retrieving UTF-8 text. $u = sqlsrv_get_field($s, 1, SQLSRV_PHPTYPE_STREAM('utf-8')); if ($u === false) { - 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 { - die(print_r(sqlsrv_errors(), true)); - } + die(print_r(sqlsrv_errors(), true)); } else { $utf8_2 = fread($u, 10000); if ($utf8 != $utf8_2) { diff --git a/test/functional/sqlsrv/AEData.inc b/test/functional/sqlsrv/AEData.inc index eebf1f45..3879efce 100644 --- a/test/functional/sqlsrv/AEData.inc +++ b/test/functional/sqlsrv/AEData.inc @@ -1,113 +1,170 @@ - + diff --git a/test/functional/sqlsrv/MsCommon.inc b/test/functional/sqlsrv/MsCommon.inc index 964e5efe..12201417 100644 --- a/test/functional/sqlsrv/MsCommon.inc +++ b/test/functional/sqlsrv/MsCommon.inc @@ -84,18 +84,6 @@ function isDaasMode() return ($daasMode ? true : false); } -// function isAEQualified($conn) -// { - // $msodbcsql_ver = sqlsrv_client_info($conn)['DriverVer']; - // $server_ver = sqlsrv_server_info($conn)['SQLServerVersion']; - // $msodbcsql_maj = explode(".", $msodbcsql_ver)[0]; - // $msodbcsql_min = explode(".", $msodbcsql_ver)[1]; - // if ($msodbcsql_maj < 17 || explode('.', $server_ver)[0] < 13) { - // return false; - // } - // return true; -// } - function startTest($testName) { if (traceMode()) { @@ -454,11 +442,36 @@ function handleErrors() } } +function setUSAnsiLocale() +{ + if (!isWindows()) { + // macOS the locale names are different in Linux or macOS + $locale = strtoupper(PHP_OS) === 'LINUX' ? "en_US.ISO-8859-1" : "en_US.ISO8859-1"; + + setlocale(LC_ALL, $locale); + } +} + +function resetLocaleToDefault() +{ + // Like setUSAnsiLocale() above, this method is only needed in non-Windows environment + if (!isWindows()) { + setlocale(LC_ALL, null); + } +} + // non-UTF8 locale support in ODBC 17 and above only +// if AE enabled, only supported in Windows (AE limitations) function isLocaleSupported() { + if (isWindows()) { + return true; + } + if (AE\isColEncrypted()) { + return false; + } + // now check ODBC version $conn = AE\connect(); - $msodbcsql_ver = sqlsrv_client_info($conn)['DriverVer']; if (explode(".", $msodbcsql_ver)[0] < 17) { return false; diff --git a/test/functional/sqlsrv/MsHelper.inc b/test/functional/sqlsrv/MsHelper.inc index 988253b1..e0329855 100644 --- a/test/functional/sqlsrv/MsHelper.inc +++ b/test/functional/sqlsrv/MsHelper.inc @@ -22,10 +22,6 @@ const INSERT_PREPARE = 2; const INSERT_QUERY_PARAMS = 3; const INSERT_PREPARE_PARAMS = 4; -const KSP_NAME = 'MyCustomKSPName'; -const ENCRYPT_KEY = 'LPKCWVD07N3RG98J0MBLG4H2'; -const KSP_TEST_TABLE = 'CustomKSPTestTable'; - /** * class for encapsulating column metadata needed for creating a table */ @@ -161,13 +157,16 @@ class BindParamOption $type_size = explode("(", $this->sqlType); $type = $type_size[0]; if (count($type_size) > 1) { - $size = $type_size[1]; + $size = rtrim($type_size[1], ")"); $prec_scal = explode(",", $size); if (count($prec_scal) > 1) { $prec = $prec_scal[0]; - $scal = rtrim($prec_scal[1], ")"); + $scal = $prec_scal[1]; $size = null; } + if (strpos($size, "max") !== false) { + $size = trim($size, "'"); + } } // get the sqlType constant try { @@ -214,29 +213,6 @@ 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; -} - /** * @return string default column name when a name is not provided in the ColumnMeta class */ @@ -330,12 +306,8 @@ function getSeqPlaceholders($num) */ function isColEncrypted() { - global $keystore, $dataEncrypted; - if ($keystore === KEYSTORE_NONE) { - return false; - } else { - return true; - } + global $keystore; + return ($keystore !== KEYSTORE_NONE); } /** @@ -345,11 +317,7 @@ function isColEncrypted() function isDataEncrypted() { global $keystore, $dataEncrypted; - if ($keystore === KEYSTORE_NONE || !$dataEncrypted) { - return false; - } else { - return true; - } + return ($keystore !== KEYSTORE_NONE && $dataEncrypted); } /** @@ -361,6 +329,12 @@ function isQualified($conn) if (explode(".", $msodbcsql_ver)[0] < 17) { return false; } + global $daasMode; + if ($daasMode) { + // running against Azure + return true; + } + // if not Azure, check the server version $server_ver = sqlsrv_server_info($conn)['SQLServerVersion']; if (explode('.', $server_ver)[0] < 13) { return false; @@ -385,13 +359,6 @@ function connect($options = array(), $disableCE = false) if (isColEncrypted()) { $connectionOptions = array_merge($connectionOptions, array("ColumnEncryption" => "Enabled")); } - if ($keystore == "ksp") { - $ksp_path = getKSPPath(); - $ksp_options = array("CEKeystoreProvider"=>$ksp_path, - "CEKeystoreName"=>KSP_NAME, - "CEKeystoreEncryptKey"=>ENCRYPT_KEY); - $connectionOptions = array_merge($connectionOptions, $ksp_options); - } } $conn = sqlsrv_connect($server, $connectionOptions); if ($conn === false) { diff --git a/test/functional/sqlsrv/TC34_PrepAndExec.phpt b/test/functional/sqlsrv/TC34_PrepAndExec.phpt index d8e5d210..3e4f5672 100644 --- a/test/functional/sqlsrv/TC34_PrepAndExec.phpt +++ b/test/functional/sqlsrv/TC34_PrepAndExec.phpt @@ -6,18 +6,23 @@ Validates that a prepared statement can be successfully executed more than once. --ENV-- PHPT_EXEC=true --SKIPIF-- - + --FILE-- 'UTF-8')); + } else { + $conn1 = AE\connect(); + } $tableName = 'TC34test'; AE\createTestTable($conn1, $tableName); @@ -80,20 +85,36 @@ function prepareAndExecute($noPasses) dropTable($conn1, $tableName); sqlsrv_close($conn1); - - endTest($testName); } -if (!isWindows()) { - setUTF8Data(true); +// locale must be set before 1st connection +setUSAnsiLocale(); +$testName = "Statement - Prepare and Execute"; + +// test ansi only if windows or non-UTF8 locales are supported (ODBC 17 and above) +startTest($testName); +if (isLocaleSupported()) { + try { + setUTF8Data(false); + prepareAndExecute(5); + } catch (Exception $e) { + echo $e->getMessage(); + } } +endTest($testName); + +// test utf8 +startTest($testName); try { + setUTF8Data(true); + resetLocaleToDefault(); prepareAndExecute(5); } catch (Exception $e) { echo $e->getMessage(); } -setUTF8Data(false); +endTest($testName); ?> --EXPECT-- Test "Statement - Prepare and Execute" completed successfully. +Test "Statement - Prepare and Execute" completed successfully. diff --git a/test/functional/sqlsrv/TC42_FetchField.phpt b/test/functional/sqlsrv/TC42_FetchField.phpt index b1395b5a..c3ac8580 100644 --- a/test/functional/sqlsrv/TC42_FetchField.phpt +++ b/test/functional/sqlsrv/TC42_FetchField.phpt @@ -6,20 +6,20 @@ retrieving fields from a table including rows with all supported SQL types (28 t --ENV-- PHPT_EXEC=true --SKIPIF-- - + --FILE-- 'UTF-8')); } else { $conn1 = AE\connect(); @@ -33,9 +33,6 @@ 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); @@ -44,16 +41,9 @@ 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) { - if (AE\isColEncrypted() && isStreamData($col)) { - verifyError(sqlsrv_errors()[0], $errState, $errMessage); - } else { - fatalError("Field $j of Row $i is missing\n", true); - } + fatalError("Field $j of Row $i is missing\n", true); } } } @@ -63,16 +53,36 @@ function fetchFields() dropTable($conn1, $tableName); sqlsrv_close($conn1); - - endTest($testName); } +// locale must be set before 1st connection +setUSAnsiLocale(); +$testName = "Fetch - Field"; + +// test ansi only if windows or non-UTF8 locales are supported (ODBC 17 and above) +startTest($testName); +if (isLocaleSupported()) { + try { + setUTF8Data(false); + fetchFields(); + } catch (Exception $e) { + echo $e->getMessage(); + } +} +endTest($testName); + +// test utf8 +startTest($testName); try { + setUTF8Data(true); + resetLocaleToDefault(); fetchFields(); } catch (Exception $e) { echo $e->getMessage(); } +endTest($testName); ?> --EXPECT-- Test "Fetch - Field" completed successfully. +Test "Fetch - Field" completed successfully. diff --git a/test/functional/sqlsrv/TC43_FetchData.phpt b/test/functional/sqlsrv/TC43_FetchData.phpt index 58a7c9d6..ffa3ce1c 100644 --- a/test/functional/sqlsrv/TC43_FetchData.phpt +++ b/test/functional/sqlsrv/TC43_FetchData.phpt @@ -5,9 +5,8 @@ PHPT_EXEC=true --SKIPIF-- --FILE-- getMessage(); diff --git a/test/functional/sqlsrv/TC44_FetchArray.phpt b/test/functional/sqlsrv/TC44_FetchArray.phpt index 7e338257..66e26c02 100644 --- a/test/functional/sqlsrv/TC44_FetchArray.phpt +++ b/test/functional/sqlsrv/TC44_FetchArray.phpt @@ -8,9 +8,8 @@ PHPT_EXEC=true --SKIPIF-- --FILE-- getMessage(); diff --git a/test/functional/sqlsrv/TC45_FetchObject.phpt b/test/functional/sqlsrv/TC45_FetchObject.phpt index ec20c417..c93c9aa9 100644 --- a/test/functional/sqlsrv/TC45_FetchObject.phpt +++ b/test/functional/sqlsrv/TC45_FetchObject.phpt @@ -5,7 +5,11 @@ Verifies data retrieval via "sqlsrv_fetch_object". --ENV-- PHPT_EXEC=true --SKIPIF-- - + --FILE-- 'UTF-8' )); + if (useUTF8Data()) { + $conn1 = AE\connect(array('CharacterSet'=>'UTF-8')); } else { $conn1 = AE\connect(); } @@ -73,8 +73,6 @@ function fetchRow($minFetchMode, $maxFetchMode) dropTable($conn1, $tableName); sqlsrv_close($conn1); - - endTest($testName); } @@ -89,7 +87,7 @@ function fetchObject($stmt, $rows, $fields, $useClass) $obj = sqlsrv_fetch_object($stmt); } if ($obj === false) { - fatalError("Row $i is missing"); + fatalError("In fetchObject: Row $i is missing"); } $values[$i] = $obj; } @@ -103,7 +101,7 @@ function fetchArray($stmt, $rows, $fields) for ($i = 0; $i < $rows; $i++) { $row = sqlsrv_fetch_array($stmt); if ($row === false) { - fatalError("Row $i is missing"); + fatalError("In fetchArray: Row $i is missing"); } $values[$i] = $row; } @@ -127,12 +125,34 @@ function checkData($rows, $fields, $actualValues, $expectedValues) } } +// locale must be set before 1st connection +setUSAnsiLocale(); +$testName = "Fetch - Object"; + +// test ansi only if windows or non-UTF8 locales are supported (ODBC 17 and above) +startTest($testName); +if (isLocaleSupported()) { + try { + setUTF8Data(false); + fetchRow(0, 2); + } catch (Exception $e) { + echo $e->getMessage(); + } +} +endTest($testName); + +// test utf8 +startTest($testName); try { + setUTF8Data(true); + resetLocaleToDefault(); fetchRow(0, 2); } catch (Exception $e) { echo $e->getMessage(); } +endTest($testName); ?> --EXPECT-- Test "Fetch - Object" completed successfully. +Test "Fetch - Object" completed successfully. diff --git a/test/functional/sqlsrv/TC46_FetchNextResult.phpt b/test/functional/sqlsrv/TC46_FetchNextResult.phpt index 6848d2e6..0da23e5b 100644 --- a/test/functional/sqlsrv/TC46_FetchNextResult.phpt +++ b/test/functional/sqlsrv/TC46_FetchNextResult.phpt @@ -7,9 +7,8 @@ PHPT_EXEC=true --SKIPIF-- --FILE-- getMessage(); diff --git a/test/functional/sqlsrv/TC48_FetchScrollable.phpt b/test/functional/sqlsrv/TC48_FetchScrollable.phpt index 44090245..3f14f52e 100644 --- a/test/functional/sqlsrv/TC48_FetchScrollable.phpt +++ b/test/functional/sqlsrv/TC48_FetchScrollable.phpt @@ -5,19 +5,20 @@ Verifies data retrieval with scrollable result sets. --ENV-- PHPT_EXEC=true --SKIPIF-- - + --FILE-- 'UTF-8')); } else { $conn1 = AE\connect(); @@ -44,36 +45,30 @@ function fetchRow($noRows) sqlsrv_free_stmt($stmt2); checkData($noRowsInserted, $numFields, $actual, $expected); - // Always Encrypted feature does not support the following options - // https://github.com/Microsoft/msphpsql/wiki/Features#aelimitation - if (!AE\isColEncrypted()) { - // fetch object - STATIC cursor - $options = array('Scrollable' => SQLSRV_CURSOR_STATIC); - $stmt2 = AE\executeQueryEx($conn1, $query, $options); - $actual = fetchObject($stmt2, $noRowsInserted, $numFields, SQLSRV_SCROLL_RELATIVE); - sqlsrv_free_stmt($stmt2); - checkData($noRowsInserted, $numFields, $actual, $expected); + // fetch object - STATIC cursor + $options = array('Scrollable' => SQLSRV_CURSOR_STATIC); + $stmt2 = AE\executeQueryEx($conn1, $query, $options); + $actual = fetchObject($stmt2, $noRowsInserted, $numFields, SQLSRV_SCROLL_RELATIVE); + sqlsrv_free_stmt($stmt2); + checkData($noRowsInserted, $numFields, $actual, $expected); - // fetch object - DYNAMIC cursor - $options = array('Scrollable' => SQLSRV_CURSOR_DYNAMIC); - $stmt2 = AE\executeQueryEx($conn1, $query, $options); - $actual = fetchObject($stmt2, $noRowsInserted, $numFields, SQLSRV_SCROLL_ABSOLUTE); - sqlsrv_free_stmt($stmt2); - checkData($noRowsInserted, $numFields, $actual, $expected); + // fetch object - DYNAMIC cursor + $options = array('Scrollable' => SQLSRV_CURSOR_DYNAMIC); + $stmt2 = AE\executeQueryEx($conn1, $query, $options); + $actual = fetchObject($stmt2, $noRowsInserted, $numFields, SQLSRV_SCROLL_ABSOLUTE); + sqlsrv_free_stmt($stmt2); + checkData($noRowsInserted, $numFields, $actual, $expected); - // fetch object - KEYSET cursor - $options = array('Scrollable' => SQLSRV_CURSOR_KEYSET); - $stmt2 = AE\executeQueryEx($conn1, $query, $options); - $actual = fetchObject($stmt2, $noRowsInserted, $numFields, SQLSRV_SCROLL_PRIOR, 0); - sqlsrv_free_stmt($stmt2); - checkData($noRowsInserted, $numFields, $actual, $expected); - } + // fetch object - KEYSET cursor + $options = array('Scrollable' => SQLSRV_CURSOR_KEYSET); + $stmt2 = AE\executeQueryEx($conn1, $query, $options); + $actual = fetchObject($stmt2, $noRowsInserted, $numFields, SQLSRV_SCROLL_PRIOR, 0); + sqlsrv_free_stmt($stmt2); + checkData($noRowsInserted, $numFields, $actual, $expected); dropTable($conn1, $tableName); sqlsrv_close($conn1); - - endTest($testName); } function fetchArray($stmt, $rows, $fields) @@ -135,12 +130,34 @@ function checkData($rows, $fields, $actualValues, $expectedValues) } } +// locale must be set before 1st connection +setUSAnsiLocale(); +$testName = "Fetch - Scrollable"; + +// test ansi only if windows or non-UTF8 locales are supported (ODBC 17 and above) +startTest($testName); +if (isLocaleSupported()) { + try { + setUTF8Data(false); + fetchRow(10); + } catch (Exception $e) { + echo $e->getMessage(); + } +} +endTest($testName); + +// test utf8 +startTest($testName); try { + setUTF8Data(true); + resetLocaleToDefault(); fetchRow(10); } catch (Exception $e) { echo $e->getMessage(); } +endTest($testName); ?> --EXPECT-- Test "Fetch - Scrollable" completed successfully. +Test "Fetch - Scrollable" completed successfully. diff --git a/test/functional/sqlsrv/TC51_StreamRead.phpt b/test/functional/sqlsrv/TC51_StreamRead.phpt index f81f2c82..0f223ccc 100644 --- a/test/functional/sqlsrv/TC51_StreamRead.phpt +++ b/test/functional/sqlsrv/TC51_StreamRead.phpt @@ -7,9 +7,8 @@ can be successfully retrieved as streams. PHPT_EXEC=true --SKIPIF-- --FILE-- getMessage(); diff --git a/test/functional/sqlsrv/TC55_StreamScrollable.phpt b/test/functional/sqlsrv/TC55_StreamScrollable.phpt index 45d5a8a3..a59f336c 100644 --- a/test/functional/sqlsrv/TC55_StreamScrollable.phpt +++ b/test/functional/sqlsrv/TC55_StreamScrollable.phpt @@ -7,9 +7,8 @@ PHPT_EXEC=true --SKIPIF-- --FILE-- SQLSRV_CURSOR_FORWARD); - } else { - $options = array('Scrollable' => SQLSRV_CURSOR_STATIC); - } + $options = array('Scrollable' => SQLSRV_CURSOR_STATIC); $stmt1 = AE\executeQueryEx($conn1, $query, $options); $numFields = sqlsrv_num_fields($stmt1); - if (AE\isColEncrypted()) { - $row = $startRow; - while ($row <= $noRows) { - if (!sqlsrv_fetch($stmt1, SQLSRV_SCROLL_NEXT)) { + $row = $noRows; + while ($row >= 1) { + if ($row == $noRows) { + if (!sqlsrv_fetch($stmt1, SQLSRV_SCROLL_LAST)) { fatalError("Failed to fetch row ".$row); } - trace("\nStreaming row $row:\n"); - for ($j = 0; $j < $numFields; $j++) { - $col = $j + 1; - if (!isUpdatable($col)) { - continue; - } - if (isStreamable($col)) { - verifyStream($stmt1, $startRow + $row - 1, $j); - } + } else { + if (!sqlsrv_fetch($stmt1, SQLSRV_SCROLL_PRIOR)) { + fatalError("Failed to fetch row ".$row); } - $row++; } - } else { - $row = $noRows; - while ($row >= 1) { - if ($row == $noRows) { - if (!sqlsrv_fetch($stmt1, SQLSRV_SCROLL_LAST)) { - fatalError("Failed to fetch row ".$row); - } - } else { - if (!sqlsrv_fetch($stmt1, SQLSRV_SCROLL_PRIOR)) { - fatalError("Failed to fetch row ".$row); - } + trace("\nStreaming row $row:\n"); + for ($j = 0; $j < $numFields; $j++) { + $col = $j + 1; + if (!isUpdatable($col)) { + continue; } - trace("\nStreaming row $row:\n"); - for ($j = 0; $j < $numFields; $j++) { - $col = $j + 1; - if (!isUpdatable($col)) { - continue; - } - if (isStreamable($col)) { - verifyStream($stmt1, $startRow + $row - 1, $j); - } + if (isStreamable($col)) { + verifyStream($stmt1, $startRow + $row - 1, $j); } - $row--; } + $row--; } sqlsrv_free_stmt($stmt1); @@ -162,11 +135,7 @@ function checkData($col, $actual, $expected) } // locale must be set before 1st connection -if (!isWindows()) { - setlocale(LC_ALL, "en_US.ISO-8859-1"); -} - -global $testName; +setUSAnsiLocale(); $testName = "Stream - Scrollable"; // error message expected with AE enabled @@ -175,7 +144,7 @@ $errMessage = 'Connection with Column Encryption enabled does not support fetchi // test ansi only if windows or non-UTF8 locales are supported (ODBC 17 and above) startTest($testName); -if (isWindows() || isLocaleSupported()) { +if (isLocaleSupported()) { try { setUTF8Data(false); streamScroll(20, 1); @@ -189,6 +158,7 @@ endTest($testName); startTest($testName); try { setUTF8Data(true); + resetLocaleToDefault(); streamScroll(20, 1); } catch (Exception $e) { echo $e->getMessage(); diff --git a/test/functional/sqlsrv/TC81_MemoryCheck.phpt b/test/functional/sqlsrv/TC81_MemoryCheck.phpt index 5712eb8d..6ba19639 100644 --- a/test/functional/sqlsrv/TC81_MemoryCheck.phpt +++ b/test/functional/sqlsrv/TC81_MemoryCheck.phpt @@ -272,9 +272,6 @@ 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)) { @@ -284,11 +281,7 @@ function runTest($noPasses, $noRows, $tableName, $conn, $prepared, $release, $mo $col = $i + 1; if ($fld === false) { - if (AE\isColEncrypted() && isStreamData($col)) { - verifyError(sqlsrv_errors()[0], $errState, $errMessage); - } else { - fatalError("Field $i of row $rowCount is missing"); - } + fatalError("Field $i of row $rowCount is missing"); } unset($fld); } diff --git a/test/functional/sqlsrv/skipif_not_ksp.inc b/test/functional/sqlsrv/skipif_not_ksp.inc deleted file mode 100644 index 682e578b..00000000 --- a/test/functional/sqlsrv/skipif_not_ksp.inc +++ /dev/null @@ -1,18 +0,0 @@ - \ No newline at end of file diff --git a/test/functional/sqlsrv/skipif_versions_old.inc b/test/functional/sqlsrv/skipif_versions_old.inc index 6f937a6e..3605fb9f 100644 --- a/test/functional/sqlsrv/skipif_versions_old.inc +++ b/test/functional/sqlsrv/skipif_versions_old.inc @@ -1,15 +1,21 @@ - \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_623_varchar_max_client_buffer.phpt b/test/functional/sqlsrv/sqlsrv_623_varchar_max_client_buffer.phpt new file mode 100644 index 00000000..388bf6a9 --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_623_varchar_max_client_buffer.phpt @@ -0,0 +1,59 @@ +--TEST-- +GitHub issue #623 - data is correctly fetched using a client buffer even with varchar(max) in the result set +--SKIPIF-- + +--FILE-- + SQLSRV_CURSOR_CLIENT_BUFFERED]); +$result = sqlsrv_fetch($stmt); +if ($result) { + $value1 = sqlsrv_get_field($stmt, 0, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR)); + var_dump($value1 === $name); + $value2 = sqlsrv_get_field($stmt, 1, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR)); + var_dump($value2 === $tag); +} else { + fatalError('Something went wrong\n'); +} + +dropTable($conn, $tableName); +echo "Done\n"; +?> +--EXPECT-- +bool(true) +bool(true) +Done \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt b/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt new file mode 100644 index 00000000..1ad1cecd --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_ae_datetimes_as_strings.phpt @@ -0,0 +1,628 @@ +--TEST-- +Test various date and time types with AE and ReturnDatesAsStrings set to true +--SKIPIF-- + +--FILE-- +date_format($datetime, 'Y-m-d'), + 'time'=>date_format($datetime, 'H:i:s.u'), + 'datetime'=>date_format($datetime, 'Y-m-d H:i:s.v'), + 'datetime2'=>date_format($datetime, 'Y-m-d H:i:s.u'), + 'datetimeoffset'=>date_format($datetime, 'Y-m-d H:i:s.u P'), + 'smalldatetime'=>date_format($datetime, 'Y-m-d H:i').":00", + ); + + CompareDateTimeObject($dateTimeType, $expectedDateTime, $datetimeArray); + } + + // retrieve date time fields without explicitly requesting the type + echo "Select fields with no type information provided:\n"; + + $stmt = sqlsrv_query($conn, "SELECT * FROM [$tableName]"); + if ($stmt === false) { + fatalError("Select from $tableName failed"); + } + + while (sqlsrv_fetch($stmt)) { + $idnum = sqlsrv_get_field($stmt, 0); + $datetime = sqlsrv_get_field($stmt, 1); + + if ($returnDatesAsStrings == true) { + if (!is_string($datetime)) { + fatalError("String for date expected, not a string"); + } + + CompareDateTimeString($dateTimeType, $expectedDateTime, $datetime); + } else { // ReturnDatesAsStrings is false + if (!($datetime instanceof DateTime)) { + fatalError("DateTime object expected, not a DateTime"); + } + + $datetimeArray = array('date'=>date_format($datetime, 'Y-m-d'), + 'time'=>date_format($datetime, 'H:i:s.u'), + 'datetime'=>date_format($datetime, 'Y-m-d H:i:s.v'), + 'datetime2'=>date_format($datetime, 'Y-m-d H:i:s.u'), + 'datetimeoffset'=>date_format($datetime, 'Y-m-d H:i:s.u P'), + 'smalldatetime'=>date_format($datetime, 'Y-m-d H:i').":00", + ); + + CompareDateTimeObject($dateTimeType, $expectedDateTime, $datetimeArray); + } + } + + // retrieve date time fields as default + echo "Select using fetch_array:\n"; + + $stmt = sqlsrv_query($conn, "SELECT * FROM [$tableName]"); + if ($stmt === false) { + fatalError("Select from $tableName failed"); + } + + while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_NUMERIC)) { + $idnum = $row[0]; + + if ($returnDatesAsStrings == true) { + if (!is_string($row[1])) { + fatalError("String for date expected, not a string"); + } + + CompareDateTimeString($dateTimeType, $expectedDateTime, $row[1]); + } else { // ReturnDatesAsStrings is false + if (!($row[1] instanceof DateTime)) { + fatalError("DateTime object expected, not a DateTime"); + } + + $datetimeArray = array('date'=>date_format($datetime, 'Y-m-d'), + 'time'=>date_format($datetime, 'H:i:s.u'), + 'datetime'=>date_format($datetime, 'Y-m-d H:i:s.v'), + 'datetime2'=>date_format($datetime, 'Y-m-d H:i:s.u'), + 'datetimeoffset'=>date_format($datetime, 'Y-m-d H:i:s.u P'), + 'smalldatetime'=>date_format($datetime, 'Y-m-d H:i').":00", + ); + + CompareDateTimeObject($dateTimeType, $expectedDateTime, $datetimeArray); + } + } +} + +// The date used for the test will be Januray 31, 2002, or 2002/01/31. +// This will sidestep issues involving the use of two digit years. +// Time is 23:59:29.049876. User can substitute any values they wish for date +// and time, except for values that would cause rollovers to the next +// second/minute/hour/day/month/year because there is no logic in this test +// to handle rollovers. This warning applies to +// 1. datetime when $frac is '999', because datetime is accurate to .000, .003, +// or .007 s, and 999 would roll over to the next second when inserted. +// 2. smalldatetime when $second is >= 30, because smalldatetime rounds to the +// nearest minute, and that may cause this test to fail if it rolls over to the next day. +$year = '2002'; +$month = '01'; +$month_name = 'January'; +$month_abbr = 'Jan'; +$day = '31'; +$hour = '23'; +$hour12 = '11'; +$meridian = 'PM'; +$minute = '59'; +$second = '29'; +$frac = '049'; +$frac2 = '876'; +$tz_correction = '+08:00'; + +// The datetime type is accurate to .000, .003, or .007 second, so adjust +// $frac appropriately for that type. Do not use '999' +$frac_rounded = $frac; +if ($frac[2] == '2' or $frac[2] == '4') $frac_rounded[2] = '3'; +elseif ($frac[2] == '5' or $frac[2] == '6' or $frac[2] == '8') $frac_rounded[2] = '7'; +elseif ($frac[2] == '1') $frac_rounded[2] = '0'; +elseif ($frac[2] == '9') +{ + // Get as integer and add one, then get as string back, prepend '0' if result is less than 100 + $frac_int = intval($frac); + $frac_int += 1; + $frac_rounded = $frac_int < 100 ? '0'.strval($frac_int) : strval($frac_int); +} + +// This is the array of dates/times/timezones to test against. They have +// different numbers of trailing zeroes to match the precision of the +// SQL Server date and time types, but only up to microseconds (0.000001 s) +// because that is PHP's maximum precision when formatting times with +// date_format() (time, datetime2, and datetimeoffset go up to 0.0000001 s precision.) +// This allows direct string comparisons when the DateTime objects retrieved from +// a table are formatted as strings with date_format(). However, when returning +// dates as strings using ReturnDatesAsStrings set to true, the returned +// data defaults to SQL Server type precision, so for comparisons some zeroes +// have to be added or removed from the values below. +$expectedDateTime = array('date'=>array($year."-".$month."-".$day), + 'time'=>array($hour.":".$minute.":".$second.".".$frac_rounded."000", + $hour.":".$minute.":".$second.".".$frac.$frac2, + $hour.":".$minute.":".$second.".".$frac."000", + $hour.":".$minute.":".$second.".000000", + $hour.":".$minute.":00.000000"), + 'datetime'=>array($year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac_rounded, + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac, + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".000", + $year."-".$month."-".$day." ".$hour.":".$minute.":00.000"), + 'datetime2'=>array($year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac_rounded."000", + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac.$frac2, + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac."000", + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".000000", + $year."-".$month."-".$day." ".$hour.":".$minute.":00.000000"), + 'datetimeoffset'=>array($year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac_rounded."000 ".$tz_correction, + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac.$frac2." ".$tz_correction, + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac."000 ".$tz_correction, + $year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".000000 ".$tz_correction, + $year."-".$month."-".$day." ".$hour.":".$minute.":00.000000 ".$tz_correction), + 'smalldatetime'=>array($year."-".$month."-".$day." ".$hour.":".$minute.":00"), + ); + +// These formats are for the ODBC driver with types specified in sqlsrv_prepare() +$date_formats = array($year."-".$month."-".$day + ); +$time_formats = array($hour.":".$minute.":".$second, + $hour.":".$minute.":".$second.".".$frac, + $hour.":".$minute.":".$second.".".$frac.$frac2 + ); + +// These formats are not accepted by either the ODBC driver or by PHP, but +// can possibly be wrangled in sqlsrv_prepare() using strings instead of +// the dedicated date and time types. +$date_formats_nonODBC = array($year."/".$month."/".$day, + $month."/".$day."/".$year, + $month."-".$day."-".$year, + $day."/".$month."/".$year, + $day."-".$month."-".$year, + $month_name." ".$day.", ".$year, + $day."-".$month_name."-".$year, + $day."-".$month_abbr."-".$year + ); +$time_formats_nonODBC = array($hour12.":".$minute." ".$meridian, + $hour12.":".$minute.":".$second." ".$meridian, + $hour12.":".$minute.":".$second.".".$frac." ".$meridian, + $hour12.":".$minute.":".$second.".".$frac.$frac2." ".$meridian, + $hour.":".$minute + ); + +// Create arrays containing the ODBC-standard formats, and larger arrays +// containing the non-standard formats, for the supported SQL Server +// date and time types. +$date_formats_all = array_merge($date_formats, $date_formats_nonODBC); +$time_formats_all = array_merge($time_formats, $time_formats_nonODBC); + +$datetime_formats_all = array(); +$datetime2_formats_all = array(); +$datetimeoffset_formats_all = array(); +$datetimesmall_formats_all = array(); + +$SZ_TIME_all = sizeof($time_formats_all); +$SZ_DATE_all = sizeof($date_formats_all); +$SZ_DATETIME_all = $SZ_TIME_all*$SZ_DATE_all; + +// Create compound date/time/timezone arrays corresponding to the SQL Server +// date/time types by concatenating the dates and times from above. For the +// datetime type, remove the extra precision of $frac2. For the smalldatetime +// type, remove the extra precision of $frac and $frac2. If the numerical +// string in $frac and/or $frac2 is found elsewhere in the date/time, the data +// will be garbled. For example, if the year is 2002 and $frac2 is 002, the +// code below will remove any instances of '002' in the datetime and +// smalldatetime strings, producing garbage for those types. User must be +// cognizant of this when testing different dates and times. +for ($i=0; $i<$SZ_DATE_all; $i++) +{ + for ($j=0; $j<$SZ_TIME_all; $j++) + { + $datetime_formats_all[] = str_replace($frac2, "", $date_formats_all[$i]." ".$time_formats_all[$j]); + $datetime2_formats_all[] = $date_formats_all[$i]." ".$time_formats_all[$j]; + $datetimeoffset_formats_all[] = $date_formats_all[$i]." ".$time_formats_all[$j].$tz_correction; + if (str_replace(".".$frac.$frac2, "", $date_formats_all[$i]." ".$time_formats_all[$j]) == ($date_formats_all[$i]." ".$time_formats_all[$j])) { + $datetimesmall_formats_all[] = str_replace(".".$frac, "", $date_formats_all[$i]." ".$time_formats_all[$j]); + } else { + $datetimesmall_formats_all[] = str_replace(".".$frac.$frac2, "", $date_formats_all[$i]." ".$time_formats_all[$j]); + } + } +} + +date_default_timezone_set('Canada/Pacific'); +sqlsrv_configure('WarningsReturnAsErrors', 1); +sqlsrv_configure('LogSeverity', SQLSRV_LOG_SEVERITY_ALL); +sqlsrv_configure('LogSubsystems', SQLSRV_LOG_SYSTEM_OFF); + +$returnDatesAsStrings = true; + +$conn = AE\connect(array('ReturnDatesAsStrings' => $returnDatesAsStrings)); + +InsertDatesAndOrTimes($conn, 'date', $date_formats_all, $SZ_DATE_all, SQLSRV_SQLTYPE_DATE); +InsertDatesAndOrTimes($conn, 'time', $time_formats_all, $SZ_TIME_all, SQLSRV_SQLTYPE_TIME); +InsertDatesAndOrTimes($conn, 'datetime', $datetime_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_DATETIME); +InsertDatesAndOrTimes($conn, 'datetime2', $datetime2_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_DATETIME2); +InsertDatesAndOrTimes($conn, 'datetimeoffset', $datetimeoffset_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_DATETIMEOFFSET); +InsertDatesAndOrTimes($conn, 'smalldatetime', $datetimesmall_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_SMALLDATETIME); + +FetchDatesAndOrTimes($conn, 'date', $expectedDateTime, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'time', $expectedDateTime, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'datetime', $expectedDateTime, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'datetime2', $expectedDateTime, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'datetimeoffset', $expectedDateTime, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'smalldatetime', $expectedDateTime, $returnDatesAsStrings); + +sqlsrv_close($conn); + +$returnDatesAsStrings = false; + +$conn = AE\connect(array('ReturnDatesAsStrings' => $returnDatesAsStrings)); + +InsertDatesAndOrTimes($conn, 'date', $date_formats_all, $SZ_DATE_all, SQLSRV_SQLTYPE_DATE); +InsertDatesAndOrTimes($conn, 'time', $time_formats_all, $SZ_TIME_all, SQLSRV_SQLTYPE_TIME); +InsertDatesAndOrTimes($conn, 'datetime', $datetime_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_DATETIME); +InsertDatesAndOrTimes($conn, 'datetime2', $datetime2_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_DATETIME2); +InsertDatesAndOrTimes($conn, 'datetimeoffset', $datetimeoffset_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_DATETIMEOFFSET); +InsertDatesAndOrTimes($conn, 'smalldatetime', $datetimesmall_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_SMALLDATETIME); + +FetchDatesAndOrTimes($conn, 'date', $expectedDateTime, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'time', $expectedDateTime, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'datetime', $expectedDateTime, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'datetime2', $expectedDateTime, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'datetimeoffset', $expectedDateTime, $returnDatesAsStrings); +FetchDatesAndOrTimes($conn, 'smalldatetime', $expectedDateTime, $returnDatesAsStrings); + +sqlsrv_close($conn); + +?> +--EXPECT-- +Select fields as strings: +Select fields as DateTime objects: +Select fields with no type information provided: +Select using fetch_array: +Select fields as strings: +Select fields as DateTime objects: +Select fields with no type information provided: +Select using fetch_array: +Select fields as strings: +Select fields as DateTime objects: +Select fields with no type information provided: +Select using fetch_array: +Select fields as strings: +Select fields as DateTime objects: +Select fields with no type information provided: +Select using fetch_array: +Select fields as strings: +Select fields as DateTime objects: +Select fields with no type information provided: +Select using fetch_array: +Select fields as strings: +Select fields as DateTime objects: +Select fields with no type information provided: +Select using fetch_array: +Select fields as strings: +Select fields as DateTime objects: +Select fields with no type information provided: +Select using fetch_array: +Select fields as strings: +Select fields as DateTime objects: +Select fields with no type information provided: +Select using fetch_array: +Select fields as strings: +Select fields as DateTime objects: +Select fields with no type information provided: +Select using fetch_array: +Select fields as strings: +Select fields as DateTime objects: +Select fields with no type information provided: +Select using fetch_array: +Select fields as strings: +Select fields as DateTime objects: +Select fields with no type information provided: +Select using fetch_array: +Select fields as strings: +Select fields as DateTime objects: +Select fields with no type information provided: +Select using fetch_array: \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_ae_fetch_phptypes.phpt b/test/functional/sqlsrv/sqlsrv_ae_fetch_phptypes.phpt new file mode 100644 index 00000000..22c9f742 --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_ae_fetch_phptypes.phpt @@ -0,0 +1,200 @@ +--TEST-- +Test insert data and fetch as all possible php types +--SKIPIF-- + +--FILE-- +"UTF-8"); +$conn = AE\connect($connectionInfo); +if (!$conn) { + fatalError("Could not connect.\n"); +} + +$tableName = "type_conversion_table"; +$columns = array(); +$insertQuery = ""; + +FormulateSetupQuery($tableName, $dataTypes, $columns, $insertQuery, $strsize, $strsize2); + +$stmt = AE\createTable($conn, $tableName, $columns); +if (!$stmt) { + fatalError("Failed to create table $tableName\n"); +} + +// The data we test against is in values.php +for ($v = 0; $v < sizeof($values);++$v) +{ + // Each value must be inserted twice because the AE and non-AE column are side by side. + $testValues = array(); + for ($i=0; $is; + + if ($diff == 0) { + $value = $valueAE; + } + } + + if ($valueAE != $value or $valueFromArrayAE != $valueFromArray) { + echo "Values do not match! PHPType $i Field $j\n"; + print_r($valueAE);echo "\n"; + print_r($value);echo "\n"; + print_r($valueFromArrayAE);echo "\n"; + print_r($valueFromArray);echo "\n"; + print_r(sqlsrv_errors()); + fatalError("Test failed, values do not match.\n"); + } + } + } + ++$i; + } + + sqlsrv_free_stmt($stmt); + sqlsrv_free_stmt($stmt2); + + $deleteQuery = "DELETE FROM $tableName"; + $stmt = sqlsrv_query($conn, $deleteQuery); + if ($stmt == false) { + print_r(sqlsrv_errors()); + fatalError("Delete statement failed"); + } + + sqlsrv_free_stmt($stmt); +} + +dropTable($conn, $tableName); + +sqlsrv_close($conn); + +echo "Test successful\n"; +?> +--EXPECT-- +Test successful diff --git a/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_binary_size.phpt b/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_binary_size.phpt new file mode 100644 index 00000000..57a8bed4 --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_binary_size.phpt @@ -0,0 +1,271 @@ +--TEST-- +Test for inserting encrypted data into binary types columns with different sizes +--DESCRIPTION-- +Test implicit conversions between different binary types of different sizes +With Always Encrypted, implicit conversion works if: +1. From input of SQLSRV_SQLTYPE_BINARY(n) to a larger binary(m) column where n <= m +2. From input of SQLSRV_SQLTYPE_BINARY(n) to a larger varbinary(m) column where n <= m (m can be max) +3. From input of SQLSRV_SQLTYPE_VARBINARY(n) to a larger binary(m) column where n <= m +4. From input of SQLSRV_SQLTYPE_VARBINARY(n) to a larger varbinary(m) column where n <= m (m can be max) +Without AlwaysEncrypted, implicit conversion between different binary types and sizes works +--SKIPIF-- + +--FILE-- + $inputs[0], "c_rand" => $inputs[1]), $r, AE\INSERT_PREPARE_PARAMS); + + // check the case when SQLSRV_SQLTYPE length (n) is greater than the column length (m) + // with AE: should not work + // without AE: should work + if (($n > $m || $maxsqltype) && !$maxcol) { + if (AE\isDataEncrypted()) { + if ($r !== false) { + echo "AE: Conversion from $sqltypeFull to $typeFull should not be supported\n"; + } else { + if (sqlsrv_errors()[0]['SQLSTATE'] != "22018") { + echo "AE: Conversion from $sqltypeFull to $typeFull expects an operand type clash error, actual error is incorrect\n"; + var_dump(sqlsrv_errors()); + } + } + } else { + if ($r === false) { + echo "Conversion from $sqltypeFull to $typeFull should be supported\n"; + } + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = sqlsrv_query($conn, $sql); + $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + if (trim($row['c_det']) != $inputValues[0] || trim($row['c_rand']) != $inputValues[1]) { + echo "Conversion from $sqltypeFull to $typeFull causes data corruption\n"; + } + } + // check the case when SQLSRV_SQLTYPE length (n) is less than or equal to the column length (m) + // should work with AE or non AE + } else { + if ($r === false) { + echo "Conversion from $sqltypeFull to $typeFull should be supported\n"; + } else { + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = sqlsrv_query($conn, $sql); + $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + if (trim($row['c_det']) == $inputValues[0] || trim($row['c_rand']) == $inputValues[1]) { + echo "****Conversion from $sqltypeFull to $typeFull is supported****\n"; + } else { + echo "Conversion from $sqltypeFull to $typeFull causes data corruption\n"; + } + } + } + // cleanup + sqlsrv_free_stmt($stmt); + sqlsrv_query($conn, "TRUNCATE TABLE $tbname"); + } + } + dropTable($conn, $tbname); + } +} +sqlsrv_close($conn); + +?> +--EXPECT-- +Testing binary(1): +****Conversion from SQLSRV_SQLTYPE_BINARY(1) to binary(1) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to binary(1) is supported**** + +Testing binary(8): +****Conversion from SQLSRV_SQLTYPE_BINARY(1) to binary(8) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(8) to binary(8) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to binary(8) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to binary(8) is supported**** + +Testing binary(64): +****Conversion from SQLSRV_SQLTYPE_BINARY(1) to binary(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(8) to binary(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(64) to binary(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to binary(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to binary(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(64) to binary(64) is supported**** + +Testing binary(512): +****Conversion from SQLSRV_SQLTYPE_BINARY(1) to binary(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(8) to binary(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(64) to binary(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(512) to binary(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to binary(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to binary(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(64) to binary(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(512) to binary(512) is supported**** + +Testing binary(4000): +****Conversion from SQLSRV_SQLTYPE_BINARY(1) to binary(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(8) to binary(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(64) to binary(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(512) to binary(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(4000) to binary(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to binary(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to binary(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(64) to binary(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(512) to binary(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(4000) to binary(4000) is supported**** + +Testing varbinary(1): +****Conversion from SQLSRV_SQLTYPE_BINARY(1) to varbinary(1) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to varbinary(1) is supported**** + +Testing varbinary(8): +****Conversion from SQLSRV_SQLTYPE_BINARY(1) to varbinary(8) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(8) to varbinary(8) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to varbinary(8) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to varbinary(8) is supported**** + +Testing varbinary(64): +****Conversion from SQLSRV_SQLTYPE_BINARY(1) to varbinary(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(8) to varbinary(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(64) to varbinary(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to varbinary(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to varbinary(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(64) to varbinary(64) is supported**** + +Testing varbinary(512): +****Conversion from SQLSRV_SQLTYPE_BINARY(1) to varbinary(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(8) to varbinary(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(64) to varbinary(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(512) to varbinary(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to varbinary(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to varbinary(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(64) to varbinary(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(512) to varbinary(512) is supported**** + +Testing varbinary(4000): +****Conversion from SQLSRV_SQLTYPE_BINARY(1) to varbinary(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(8) to varbinary(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(64) to varbinary(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(512) to varbinary(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(4000) to varbinary(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to varbinary(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to varbinary(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(64) to varbinary(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(512) to varbinary(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(4000) to varbinary(4000) is supported**** + +Testing varbinary(max): +****Conversion from SQLSRV_SQLTYPE_BINARY(1) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(8) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(64) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(512) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(4000) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(64) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(512) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(4000) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** + +Testing varbinary(max): +****Conversion from SQLSRV_SQLTYPE_BINARY(1) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(8) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(64) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(512) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(4000) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(64) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(512) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(4000) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** + +Testing varbinary(max): +****Conversion from SQLSRV_SQLTYPE_BINARY(1) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(8) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(64) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(512) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(4000) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(64) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(512) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(4000) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** + +Testing varbinary(max): +****Conversion from SQLSRV_SQLTYPE_BINARY(1) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(8) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(64) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(512) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(4000) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(64) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(512) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(4000) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** + +Testing varbinary(max): +****Conversion from SQLSRV_SQLTYPE_BINARY(1) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(8) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(64) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(512) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_BINARY(4000) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(1) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(8) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(64) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(512) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY(4000) to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARBINARY('max') to varbinary(max) is supported**** \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_char_size.phpt b/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_char_size.phpt new file mode 100644 index 00000000..8465ff05 --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_char_size.phpt @@ -0,0 +1,336 @@ +--TEST-- +Test for inserting encrypted data of char types with different sizes +--DESCRIPTION-- +Test implicit conversions between different char types of different sizes +With Always Encrypted, implicit conversion works if: +1. From input of SQLSRV_SQLTYPE_CHAR(n) to a larger char(m) column where n <= m +2. From input of SQLSRV_SQLTYPE_CHAR(n) to a larger varchar(m) column where n <= m (m can be max) +3. From input of SQLSRV_SQLTYPE_VARCHAR(n) to a larger char(m) column where n <= m +4. From input of SQLSRV_SQLTYPE_VARCHAR(n) to a larger varchar(m) column where n <= m (m can be max) +Without AlwaysEncrypted, implicit conversion between different binary types and sizes works +--SKIPIF-- + +--FILE-- + $input), $r, AE\INSERT_PREPARE_PARAMS); + + // check the case when SQLSRV_SQLTYPE length (n) is greater than the column length (m) + // with AE: should not work + // without AE: should work + if (($n > $m || $maxsqltype) && !$maxcol) { + if (AE\isDataEncrypted()) { + if ($r !== false) { + echo "AE: Conversion from $sqltypeFull to $typeFull should not be supported\n"; + } else { + if (sqlsrv_errors()[0]['SQLSTATE'] != "22018") { + echo "AE: Conversion from $sqltypeFull to $typeFull expects an operand type clash error, actual error is incorrect\n"; + var_dump(sqlsrv_errors()); + } + } + } else { + if ($r === false) { + echo "Conversion from $sqltypeFull to $typeFull should be supported\n"; + } + $sql = "SELECT c1 FROM $tbname"; + $stmt = sqlsrv_query($conn, $sql); + $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + if (trim($row['c1']) != $inputValue) { + echo "Conversion from $sqltypeFull to $typeFull causes data corruption\n"; + } + } + // check the case when SQLSRV_SQLTYPE length (n) is less than or equal to the column length (m) + // should work with AE or non AE + } else { + if ($r === false) { + echo "Conversion from $sqltypeFull to $typeFull should be supported\n"; + } else { + $sql = "SELECT c1 FROM $tbname"; + $stmt = sqlsrv_query($conn, $sql); + $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + if (trim($row['c1']) == $inputValue) { + echo "****Conversion from $sqltypeFull to $typeFull is supported****\n"; + } else { + echo "Conversion from $sqltypeFull to $typeFull causes data corruption\n"; + } + } + } + // cleanup + sqlsrv_free_stmt($stmt); + sqlsrv_query($conn, "TRUNCATE TABLE $tbname"); + } + } + dropTable($conn, $tbname); + } +} +sqlsrv_close($conn); + +?> +--EXPECT-- +Testing char(1): +****Conversion from SQLSRV_SQLTYPE_CHAR(1) to char(1) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to char(1) is supported**** + +Testing char(8): +****Conversion from SQLSRV_SQLTYPE_CHAR(1) to char(8) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(8) to char(8) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to char(8) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to char(8) is supported**** + +Testing char(64): +****Conversion from SQLSRV_SQLTYPE_CHAR(1) to char(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(8) to char(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(64) to char(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to char(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to char(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to char(64) is supported**** + +Testing char(512): +****Conversion from SQLSRV_SQLTYPE_CHAR(1) to char(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(8) to char(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(64) to char(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(512) to char(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to char(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to char(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to char(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(512) to char(512) is supported**** + +Testing char(4096): +****Conversion from SQLSRV_SQLTYPE_CHAR(1) to char(4096) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(8) to char(4096) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(64) to char(4096) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(512) to char(4096) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(4096) to char(4096) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to char(4096) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to char(4096) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to char(4096) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(512) to char(4096) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(4096) to char(4096) is supported**** + +Testing char(8000): +****Conversion from SQLSRV_SQLTYPE_CHAR(1) to char(8000) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(8) to char(8000) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(64) to char(8000) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(512) to char(8000) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(4096) to char(8000) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(8000) to char(8000) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to char(8000) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to char(8000) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to char(8000) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(512) to char(8000) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(4096) to char(8000) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(8000) to char(8000) is supported**** + +Testing varchar(1): +****Conversion from SQLSRV_SQLTYPE_CHAR(1) to varchar(1) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to varchar(1) is supported**** + +Testing varchar(8): +****Conversion from SQLSRV_SQLTYPE_CHAR(1) to varchar(8) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(8) to varchar(8) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to varchar(8) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to varchar(8) is supported**** + +Testing varchar(64): +****Conversion from SQLSRV_SQLTYPE_CHAR(1) to varchar(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(8) to varchar(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(64) to varchar(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to varchar(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to varchar(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to varchar(64) is supported**** + +Testing varchar(512): +****Conversion from SQLSRV_SQLTYPE_CHAR(1) to varchar(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(8) to varchar(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(64) to varchar(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(512) to varchar(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to varchar(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to varchar(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to varchar(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(512) to varchar(512) is supported**** + +Testing varchar(4096): +****Conversion from SQLSRV_SQLTYPE_CHAR(1) to varchar(4096) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(8) to varchar(4096) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(64) to varchar(4096) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(512) to varchar(4096) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(4096) to varchar(4096) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to varchar(4096) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to varchar(4096) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to varchar(4096) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(512) to varchar(4096) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(4096) to varchar(4096) is supported**** + +Testing varchar(8000): +****Conversion from SQLSRV_SQLTYPE_CHAR(1) to varchar(8000) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(8) to varchar(8000) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(64) to varchar(8000) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(512) to varchar(8000) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(4096) to varchar(8000) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(8000) to varchar(8000) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to varchar(8000) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to varchar(8000) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to varchar(8000) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(512) to varchar(8000) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(4096) to varchar(8000) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(8000) to varchar(8000) is supported**** + +Testing varchar(max): +****Conversion from SQLSRV_SQLTYPE_CHAR(1) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(8) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(64) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(512) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(4096) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(8000) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(512) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(4096) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(8000) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** + +Testing varchar(max): +****Conversion from SQLSRV_SQLTYPE_CHAR(1) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(8) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(64) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(512) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(4096) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(8000) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(512) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(4096) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(8000) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** + +Testing varchar(max): +****Conversion from SQLSRV_SQLTYPE_CHAR(1) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(8) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(64) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(512) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(4096) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(8000) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(512) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(4096) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(8000) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** + +Testing varchar(max): +****Conversion from SQLSRV_SQLTYPE_CHAR(1) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(8) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(64) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(512) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(4096) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(8000) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(512) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(4096) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(8000) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** + +Testing varchar(max): +****Conversion from SQLSRV_SQLTYPE_CHAR(1) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(8) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(64) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(512) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(4096) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(8000) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(512) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(4096) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(8000) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** + +Testing varchar(max): +****Conversion from SQLSRV_SQLTYPE_CHAR(1) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(8) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(64) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(512) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(4096) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_CHAR(8000) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(1) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(8) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(64) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(512) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(4096) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR(8000) to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_VARCHAR('max') to varchar(max) is supported**** \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_datetime_precision.phpt b/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_datetime_precision.phpt new file mode 100644 index 00000000..09f954c7 --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_datetime_precision.phpt @@ -0,0 +1,181 @@ +--TEST-- +Test for inserting encrypted data of datetime2, datetimeoffset and time datatypes with different precisions +--DESCRIPTION-- +Test implicit conversions between different precisions +With Always Encrypted, implicit conversion works if: +1. From input of SQLSRV_SQLTYPE_DATETIME2 to a dateteim2(7) column +2. From input of SQLSRV_SQLTYPE_DATETIMEOFFSET to a datetimeoffset(7) column +3. From input of SQLSRV_SQLTYPE_TIME to a time(7) column +Note: with Always Encrypted, implicit converion should work as long as the SQLSRV_SQLTYPE has a smaller precision than the one defined in the column. However, the SQLSRV driver does not let the user specify the precision in these SQLSRV_SQLTYPE_* constants and they are all default to a precision of 7. Hence when user specifies SQLSRV_SQLTYPE_DATETIME2, SQLSRV_SQLTYPE_DATETIMEOFFSET or SQLSRV_SQLTYPE_TIME when binding parameter during insertion, only insertion into a column of precision 7 is allowed. +Without AlwaysEncrypted, implicit conversion between different precisions works +--SKIPIF-- + +--FILE-- +format("Y-m-d H:i:s.u"); + $dtobj_timezone = $dtobj->getTimezone()->getName(); + $dtarr = null; + + if ($dataType == "datetimeoffset") { + $dtarr = explode(' ', $dtstr); + } + + // php only supports up to 6 decimal places in datetime + // drop the last decimal place before comparing + if ($precision == 7) { + $dtstr = substr($dtstr, 0, -1); + if (!is_null($dtarr)) { + $dtarr[1] = substr($dtarr[1], 0, -1); + } + } + if (strpos($dtobj_date, $dtstr) !== false) { + return true; + } + if ($dataType == "datetimeoffset") { + if (strpos($dtobj_date, $dtarr[0]) !== false && strpos($dtobj_date, $dtarr[1]) !== false && strpos($dtobj_timezone, $dtarr[2]) !== false) { + return true; + } + } + return false; +} + +$dataTypes = array("datetime2", "datetimeoffset", "time"); +$precisions = array(0, 1, 2, 4, 7); +$inputValuesInit = array("datetime2" => array("0001-01-01 00:00:00", "9999-12-31 23:59:59"), + "datetimeoffset" => array("0001-01-01 00:00:00 -14:00", "9999-12-31 23:59:59 +14:00"), + "time" => array("00:00:00", "23:59:59")); + +$conn = AE\connect(); +foreach($dataTypes as $dataType) { + foreach($precisions as $m) { + // add $m number of decimal digits to the some input values + $inputValues[0] = $inputValuesInit[$dataType][0]; + $inputValues[1] = $inputValuesInit[$dataType][1]; + if ($m != 0) { + if ($dataType == "datetime2") { + $inputValues[1] .= "." . str_repeat("4", $m); + } else if ($dataType == "datetimeoffset") { + $dtoffsetPieces = explode(" ", $inputValues[1]); + $inputValues[1] = $dtoffsetPieces[0] . " " . $dtoffsetPieces[1] . "." . str_repeat("4", $m) . " " . $dtoffsetPieces[2]; + } else if ($dataType == "time") { + $inputValues[0] .= "." . str_repeat("0", $m); + $inputValues[1] .= "." . str_repeat("4", $m); + } + } + $typeFull = "$dataType($m)"; + echo "\nTesting $typeFull:\n"; + + // create table containing datetime2(m), datetimeoffset(m) or time(m) columns + $tbname = "test_" . $dataType . $m; + $colMetaArr = array(new AE\ColumnMeta($typeFull, "c_det"), new AE\ColumnMeta($typeFull, "c_rand", null, false)); + AE\createTable($conn, $tbname, $colMetaArr); + + // insert by specifying the corresponding SQLSRV_SQLTYPE + $sqlType = "SQLSRV_SQLTYPE_" . strtoupper($dataType); + $inputs = array(new AE\BindParamOption($inputValues[0], null, null, $sqlType), + new AE\BindParamOption($inputValues[1], null, null, $sqlType)); + $r; + $stmt = AE\insertRow($conn, $tbname, array("c_det" => $inputs[0], "c_rand" => $inputs[1]), $r, AE\INSERT_PREPARE_PARAMS); + + // check the case when the column precision (m) is less than 7 + // with AE: should not work + // without AE: should work + if ($m < 7) { + if (AE\isDataEncrypted()) { + if ($r !== false) { + echo "AE: Conversion from $sqlType to $typeFull should not be supported\n"; + } else { + if (sqlsrv_errors()[0]['SQLSTATE'] != "22018") { + echo "AE: Conversion from $sqlType to $typeFull expects an operand type clash error, actual error is incorrect\n"; + var_dump(sqlsrv_errors()); + } else { + echo "Test successfully done\n"; + } + } + } else { + if ($r === false) { + echo "Conversion from $sqlType to $typeFull should be supported\n"; + } else { + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = sqlsrv_query($conn, $sql); + $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + if (!compareDate($row['c_det'], $inputValues[0], $dataType, $m) || !compareDate($row['c_rand'], $inputValues[1], $dataType, $m)) { + echo "Conversion from $sqlType to $typeFull causes data corruption\n"; + } else { + echo "Test successfully done\n"; + } + } + } + // check the case when the column precision is 7 + // should work with AE or non AE + } else { + if ($r === false) { + echo "Conversion from $sqlType to $typeFull should be supported\n"; + } else { + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = sqlsrv_query($conn, $sql); + $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + if (compareDate($row['c_det'], $inputValues[0], $dataType, $m) && compareDate($row['c_rand'], $inputValues[1], $dataType, $m)) { + echo "****Conversion from $sqlType to $typeFull is supported****\n"; + } else { + echo "Conversion from $sqlType to $typeFull causes data corruption\n"; + var_dump($row); + } + } + } + } + // cleanup + sqlsrv_free_stmt($stmt); + dropTable($conn, $tbname); +} +sqlsrv_close($conn); + +?> +--EXPECT-- +Testing datetime2(0): +Test successfully done + +Testing datetime2(1): +Test successfully done + +Testing datetime2(2): +Test successfully done + +Testing datetime2(4): +Test successfully done + +Testing datetime2(7): +****Conversion from SQLSRV_SQLTYPE_DATETIME2 to datetime2(7) is supported**** + +Testing datetimeoffset(0): +Test successfully done + +Testing datetimeoffset(1): +Test successfully done + +Testing datetimeoffset(2): +Test successfully done + +Testing datetimeoffset(4): +Test successfully done + +Testing datetimeoffset(7): +****Conversion from SQLSRV_SQLTYPE_DATETIMEOFFSET to datetimeoffset(7) is supported**** + +Testing time(0): +Test successfully done + +Testing time(1): +Test successfully done + +Testing time(2): +Test successfully done + +Testing time(4): +Test successfully done + +Testing time(7): +****Conversion from SQLSRV_SQLTYPE_TIME to time(7) is supported**** \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_decimal_precision.phpt b/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_decimal_precision.phpt new file mode 100644 index 00000000..ef7de8c9 --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_decimal_precision.phpt @@ -0,0 +1,247 @@ +--TEST-- +Test for inserting encrypted data of decimal types with different precisions and scales +--DESCRIPTION-- +Test implicit conversions between different precisions and scales +With Always Encrypted, no implicit conversion works for decimal datatypes, the precision and scale specified in the SQLSRV_SQLTYPE must be identical to the precision and scale defined in the column +Without AlwaysEncrypted, implicit conversion between precisions or scales works if: +1. From input of SQLSRV_SQLTYPE_DECIMAL(n1, n2) to a decimal(m1, m2) column where n1 - n2 > m1 - m2 and +2. where n2 != 0 && m1 != m2 +--SKIPIF-- + +--FILE-- + array(0, 1), + 4 => array(0, 1, 4), + 16 => array(0, 1, 4, 16), + 38 => array(0, 1, 4, 16, 38)); +$sqlTypes = array("SQLSRV_SQLTYPE_DECIMAL", "SQLSRV_SQLTYPE_NUMERIC"); +$sqltypePrecisions = $precisions; +$inputValuesInit = array(92233720368547758089223372036854775808, -92233720368547758089223372036854775808); +$maxInPrecision = 38; + +$conn = AE\connect(); + +foreach($dataTypes as $dataType) { + foreach($precisions as $m1 => $inScales) { + foreach($inScales as $m2) { + // change the number of integers in the input values to be $m1 - $m2 + $precDiff = $maxInPrecision - ($m1 - $m2); + $inputValues = $inputValuesInit; + foreach ($inputValues as &$inputValue) { + $inputValue = $inputValue / pow(10, $precDiff); + } + $typeFull = "$dataType($m1, $m2)"; + echo "\nTesting $typeFull:\n"; + + // create table containing decimal(m1, m2) or numeric(m1, m2) columns + $tbname = "test_" . $dataType . $m1 . $m2; + $colMetaArr = array(new AE\ColumnMeta($typeFull, "c_det"), new AE\ColumnMeta($typeFull, "c_rand", null, false)); + AE\createTable($conn, $tbname, $colMetaArr); + + // insert by specifying SQLSRV_SQLTYPE_DECIMAL(n1, n2) or SQLSRV_SQLTYPE_NUMERIC(n1, n2) + // with AE, should only be successful if the SQLSRV_SQLTYPE precision (n1) and scale (n2) are the same as the column precision (m1) and scale (m2) + foreach($sqlTypes as $sqlType) { + foreach($sqltypePrecisions as $n1 => $sqltypeScales) { + foreach($sqltypeScales as $n2) { + + // compute the epsilon for comparing doubles + // float in PHP only has a precision of roughtly 14 digits: http://php.net/manual/en/language.types.float.php + // the smaller precision and scale (n1 and n2 vs m1 and m2) take precedence + $epsilon; + $smallerprec = min($m1, $n1); + $smallerscale = min($m2, $n2); + if ($smallerprec < 14) { + $epsilon = pow(10, $smallerscale * -1); + } else { + $numint = $smallerprec - $smallerscale; + if ($numint < 14) { + $epsilon = pow(10, (14 - $numint) * -1); + } else { + $epsilon = pow(10, $numint - 14); + } + } + + $sqltypeFull = "$sqlType($n1, $n2)"; + + //insert a row + $inputs = array(new AE\BindParamOption((string)$inputValues[0], null, null, $sqltypeFull), + new AE\BindParamOption((string)$inputValues[1], null, null, $sqltypeFull)); + $r; + $stmt = AE\insertRow($conn, $tbname, array("c_det" => $inputs[0], "c_rand" => $inputs[1]), $r, AE\INSERT_PREPARE_PARAMS); + + // check the case when the SQLSRV_SQLTYPE precision (n1) is not the same as the column precision (m1) + // or the SQLSRV_SQLTYPE scale (n2) is not the same as the column precision (m2) + // with AE: should not work + // without AE: should not work if n1 - n2 < m1 - m2 (Numeric value out of range error) + // or n2 != 0 && $m1 == $m2 (Arithmetic overflow error) + if ($n1 != $m1 || $n2 != $m2) { + if (AE\isDataEncrypted()) { + if ($r !== false) { + echo "AE: Conversion from $sqltypeFull to $typeFull should not be supported\n"; + } else { + if (sqlsrv_errors()[0]['SQLSTATE'] != "22018") { + echo "AE: Conversion from $sqltypeFull to $typeFull expects an operand type clash error, actual error is incorrect\n"; + var_dump(sqlsrv_errors()); + } + } + } else { + if ($n1 - $n2 < $m1 - $m2 || ($m1 == $m2 && $n2 == 0)) { + if ($r !== false) { + echo "Conversion from $sqltypeFull to $typeFull should not be supported\n"; + } + } else { + if ($r === false) { + echo "Conversion from $sqltypeFull to $typeFull should be supported\n"; + } else { + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = sqlsrv_query($conn, $sql); + $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + if (abs($row['c_det'] - $inputValues[0]) > $epsilon || abs($row['c_rand'] - $inputValues[1]) > $epsilon) { + echo "Conversion from $sqltypeFull to $typeFull causes data corruption\n"; + } + } + } + } + // check the case when the SQLSRV_SQLTYPE precision (n1) and scale (n2) are the same as the column precision (m1) and scale (m2) + // should work with AE or non AE + } else { + if ($r === false) { + echo "Conversion from $sqltypeFull to $typeFull should be supported\n"; + } else { + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = sqlsrv_query($conn, $sql); + $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + if (abs($row['c_det'] - $inputValues[0]) < $epsilon && abs($row['c_rand'] - $inputValues[1]) < $epsilon) { + echo "****Conversion from $sqltypeFull to $typeFull is supported****\n"; + } else { + echo "Conversion from $sqltypeFull to $typeFull causes data corruption\n"; + } + } + } + // cleanup + sqlsrv_free_stmt($stmt); + sqlsrv_query($conn, "TRUNCATE TABLE $tbname"); + } + } + } + dropTable($conn, $tbname); + } + } +} +sqlsrv_close($conn); +?> +--EXPECT-- +Testing decimal(1, 0): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(1, 0) to decimal(1, 0) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(1, 0) to decimal(1, 0) is supported**** + +Testing decimal(1, 1): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(1, 1) to decimal(1, 1) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(1, 1) to decimal(1, 1) is supported**** + +Testing decimal(4, 0): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(4, 0) to decimal(4, 0) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(4, 0) to decimal(4, 0) is supported**** + +Testing decimal(4, 1): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(4, 1) to decimal(4, 1) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(4, 1) to decimal(4, 1) is supported**** + +Testing decimal(4, 4): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(4, 4) to decimal(4, 4) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(4, 4) to decimal(4, 4) is supported**** + +Testing decimal(16, 0): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(16, 0) to decimal(16, 0) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(16, 0) to decimal(16, 0) is supported**** + +Testing decimal(16, 1): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(16, 1) to decimal(16, 1) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(16, 1) to decimal(16, 1) is supported**** + +Testing decimal(16, 4): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(16, 4) to decimal(16, 4) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(16, 4) to decimal(16, 4) is supported**** + +Testing decimal(16, 16): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(16, 16) to decimal(16, 16) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(16, 16) to decimal(16, 16) is supported**** + +Testing decimal(38, 0): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(38, 0) to decimal(38, 0) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(38, 0) to decimal(38, 0) is supported**** + +Testing decimal(38, 1): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(38, 1) to decimal(38, 1) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(38, 1) to decimal(38, 1) is supported**** + +Testing decimal(38, 4): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(38, 4) to decimal(38, 4) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(38, 4) to decimal(38, 4) is supported**** + +Testing decimal(38, 16): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(38, 16) to decimal(38, 16) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(38, 16) to decimal(38, 16) is supported**** + +Testing decimal(38, 38): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(38, 38) to decimal(38, 38) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(38, 38) to decimal(38, 38) is supported**** + +Testing numeric(1, 0): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(1, 0) to numeric(1, 0) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(1, 0) to numeric(1, 0) is supported**** + +Testing numeric(1, 1): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(1, 1) to numeric(1, 1) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(1, 1) to numeric(1, 1) is supported**** + +Testing numeric(4, 0): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(4, 0) to numeric(4, 0) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(4, 0) to numeric(4, 0) is supported**** + +Testing numeric(4, 1): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(4, 1) to numeric(4, 1) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(4, 1) to numeric(4, 1) is supported**** + +Testing numeric(4, 4): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(4, 4) to numeric(4, 4) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(4, 4) to numeric(4, 4) is supported**** + +Testing numeric(16, 0): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(16, 0) to numeric(16, 0) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(16, 0) to numeric(16, 0) is supported**** + +Testing numeric(16, 1): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(16, 1) to numeric(16, 1) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(16, 1) to numeric(16, 1) is supported**** + +Testing numeric(16, 4): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(16, 4) to numeric(16, 4) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(16, 4) to numeric(16, 4) is supported**** + +Testing numeric(16, 16): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(16, 16) to numeric(16, 16) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(16, 16) to numeric(16, 16) is supported**** + +Testing numeric(38, 0): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(38, 0) to numeric(38, 0) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(38, 0) to numeric(38, 0) is supported**** + +Testing numeric(38, 1): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(38, 1) to numeric(38, 1) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(38, 1) to numeric(38, 1) is supported**** + +Testing numeric(38, 4): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(38, 4) to numeric(38, 4) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(38, 4) to numeric(38, 4) is supported**** + +Testing numeric(38, 16): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(38, 16) to numeric(38, 16) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(38, 16) to numeric(38, 16) is supported**** + +Testing numeric(38, 38): +****Conversion from SQLSRV_SQLTYPE_DECIMAL(38, 38) to numeric(38, 38) is supported**** +****Conversion from SQLSRV_SQLTYPE_NUMERIC(38, 38) to numeric(38, 38) is supported**** \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_float_bits.phpt b/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_float_bits.phpt new file mode 100644 index 00000000..77f1605d --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_float_bits.phpt @@ -0,0 +1,103 @@ +--TEST-- +Test for inserting encrypted data of float types with different number of bits +--DESCRIPTION-- +Test implicit conversions between different number of bits +With Always Encrypted, implicit conversion works if: +1. From input of SQLSRV_SQLTYPE_FLOAT to a float(m) column where m > 24 +Note: with Always Encrypted, implicit conversion should work as long as the SQLSRV_SQLTYPE has a smaller number of bits than the one defined in the column. However, the SQLSRV driver does not let the user specify the number of bits in the SQLSRV_SQLTYPE_FLOAT constant and it is default to 53. Hence when user specifies SQLSRV_SQLTYPE_FLOAT when binding parameter during insertion, only insertion into a column of > 24 is allowed. +Without Always Encrypted, implicit conversion between different number of bits works. +--SKIPIF-- + +--FILE-- + $inputs[0], "c_rand" => $inputs[1]), $r, AE\INSERT_PREPARE_PARAMS); + + // check the case when the column number of bits is less than 25 + // with AE: should not work + // without AE: should work + if ($m < 25) { + if (AE\isDataEncrypted()) { + if ($r !== false) { + echo "AE: Conversion from $sqlType to $typeFull should not be supported\n"; + } else { + if (sqlsrv_errors()[0]['SQLSTATE'] != "22018") { + echo "AE: Conversion from $sqlType to $typeFull expects an operand type clash error, actual error is incorrect\n"; + var_dump(sqlsrv_errors()); + } else { + echo "Test successfully done\n"; + } + } + } else { + if ($r === false) { + echo "Conversion from $sqlType to $typeFull should be supported\n"; + } else { + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = sqlsrv_query($conn, $sql); + $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + if (abs($row['c_det'] - $inputValues[0]) > $epsilon || abs($row['c_rand'] - $inputValues[1]) > $epsilon) { + echo "Conversion from $sqlType to $typeFull causes data corruption\n"; + } else { + echo "Test successfully done\n"; + } + } + } + // check the case when the column number of bits 25 or more + // should work with AE or non AE + } else { + if ($r === false) { + echo "Conversion from $sqlType to $typeFull should be supported\n"; + } else { + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = sqlsrv_query($conn, $sql); + $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + if (abs($row['c_det'] - $inputValues[0]) < $epsilon && abs($row['c_rand'] - $inputValues[1]) < $epsilon) { + echo "****Conversion from $sqlType to $typeFull is supported****\n"; + } else { + echo "Conversion from $sqlType to $typeFull causes data corruption\n"; + } + } + } + // cleanup + sqlsrv_free_stmt($stmt); + dropTable($conn, $tbname); +} +sqlsrv_close($conn); + +?> +--EXPECT-- +Testing float(1): +Test successfully done + +Testing float(12): +Test successfully done + +Testing float(24): +Test successfully done + +Testing float(36): +****Conversion from SQLSRV_SQLTYPE_FLOAT to float(36) is supported**** + +Testing float(53): +****Conversion from SQLSRV_SQLTYPE_FLOAT to float(53) is supported**** \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_int_conv.phpt b/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_int_conv.phpt new file mode 100644 index 00000000..1bb3153c --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_int_conv.phpt @@ -0,0 +1,127 @@ +--TEST-- +Test for inserting encrypted data of int types +--DESCRIPTION-- +Test implicit conversions between different integer types +With Always Encrypted, implicit conversion works if: +1. From input SQLSRV_SQLTYPE_BIT to a bit column +2. From input SQLSRV_SQLTYPE_BIT to a tinyint column +3. From input SQLSRV_SQLTYPE_BIT to a smallint column +4. From input SQLSRV_SQLTYPE_BIT to an int column +5. From input SQLSRV_SQLTYPE_BIT to a bigint column +6. From input SQLSRV_SQLTYPE_TINYINT to a tinyint column +7. From input SQLSRV_SQLTYPE_TINYINT to a smallint column +8. From input SQLSRV_SQLTYPE_TINYINT to an int column +9. From input SQLSRV_SQLTYPE_TINYINT to a bigint column +10. From input SQLSRV_SQLTYPE_SMALLINT to a smallint column +11. From input SQLSRV_SQLTYPE_SMALLINT to an int column +12. From input SQLSRV_SQLTYPE_SMALLINT to a bigint column +13. From input SQLSRV_SQLTYPE_INT to an int column +14. From input SQLSRV_SQLTYPE_INT to a bigint column +15. From input SQLSRV_SQLTYPE_BIGINT to a bigint column +Without AlwaysEncrypted, implicit conversion between different integer types works +--SKIPIF-- + +--FILE-- + array("SQLSRV_SQLTYPE_BIT"), + "tinyint" => array("SQLSRV_SQLTYPE_BIT", "SQLSRV_SQLTYPE_TINYINT"), + "smallint" => array("SQLSRV_SQLTYPE_BIT", "SQLSRV_SQLTYPE_TINYINT", "SQLSRV_SQLTYPE_SMALLINT"), + "int" => array("SQLSRV_SQLTYPE_BIT", "SQLSRV_SQLTYPE_TINYINT", "SQLSRV_SQLTYPE_SMALLINT", "SQLSRV_SQLTYPE_INT"), + "bigint" => array("SQLSRV_SQLTYPE_BIT", "SQLSRV_SQLTYPE_TINYINT", "SQLSRV_SQLTYPE_SMALLINT", "SQLSRV_SQLTYPE_INT", "SQLSRV_SQLTYPE_BIGINT")); + +$conn = AE\connect(); +foreach ($dataTypes as $dataType) { + echo "\nTesting $dataType:\n"; + + // create table containing bit, tinyint, smallint, int, or bigint columns + $tbname = "test_" . $dataType; + $colMetaArr = array( new AE\ColumnMeta($dataType, "c_det"), new AE\ColumnMeta($dataType, "c_rand", null, false)); + AE\createTable($conn, $tbname, $colMetaArr); + + // insert by specifying different SQLSRV_SQLTYPE integer constants + // with AE, should only be successful if the SQLSRV_SQLTYPE is smaller in size than the column datatype + foreach($sqlTypes as $sqlType) { + $inputs = array(new AE\BindParamOption($inputValues[0], null, null, $sqlType), new AE\BindParamOption($inputValues[1], null, null, $sqlType)); + $r; + $stmt = AE\insertRow($conn, $tbname, array($colMetaArr[0]->colName => $inputs[0], $colMetaArr[1]->colName => $inputs[1]), $r, AE\INSERT_PREPARE_PARAMS); + + // check the case if the type conversion is not listed in $aeConvList + if (!in_array($sqlType, $aeConvList["$dataType"])) { + if (AE\isDataEncrypted()) { + if ($r !== false) { + echo "AE: Conversion from $sqlType to $dataType should not be supported\n"; + } else { + if (sqlsrv_errors()[0]['SQLSTATE'] != "22018") { + echo "AE: Conversion from $sqlType to $dataType expects an operand type clash error, actual error is incorrect\n"; + var_dump(sqlsrv_errors()); + } + } + } else { + if ($r === false) { + echo "Conversion from $sqlType to $dataType should be supported\n"; + } else { + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = sqlsrv_query($conn, $sql); + $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + if ($row['c_det'] != $inputValues[0] || $row['c_rand'] != $inputValues[1]) { + echo "Conversion from $sqlType to $dataType causes data corruption\n"; + } + } + } + } else { + if ($r === false) { + echo "Conversion from $sqlType to $dataType should be supported\n"; + } else { + $sql = "SELECT c_det, c_rand FROM $tbname"; + $stmt = sqlsrv_query($conn, $sql); + $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + if ($row['c_det'] == $inputValues[0] && $row['c_rand'] == $inputValues[1]) { + echo "****Conversion from $sqlType to $dataType is supported****\n"; + } else { + echo "Conversion from $sqlType to $dataType causes data corruption\n"; + } + } + } + // cleanup + sqlsrv_free_stmt($stmt); + sqlsrv_query($conn, "TRUNCATE TABLE $tbname"); + } + dropTable($conn, $tbname); +} +sqlsrv_close($conn); +?> +--EXPECT-- +Testing bit: +****Conversion from SQLSRV_SQLTYPE_BIT to bit is supported**** + +Testing tinyint: +****Conversion from SQLSRV_SQLTYPE_BIT to tinyint is supported**** +****Conversion from SQLSRV_SQLTYPE_TINYINT to tinyint is supported**** + +Testing smallint: +****Conversion from SQLSRV_SQLTYPE_BIT to smallint is supported**** +****Conversion from SQLSRV_SQLTYPE_TINYINT to smallint is supported**** +****Conversion from SQLSRV_SQLTYPE_SMALLINT to smallint is supported**** + +Testing int: +****Conversion from SQLSRV_SQLTYPE_BIT to int is supported**** +****Conversion from SQLSRV_SQLTYPE_TINYINT to int is supported**** +****Conversion from SQLSRV_SQLTYPE_SMALLINT to int is supported**** +****Conversion from SQLSRV_SQLTYPE_INT to int is supported**** + +Testing bigint: +****Conversion from SQLSRV_SQLTYPE_BIT to bigint is supported**** +****Conversion from SQLSRV_SQLTYPE_TINYINT to bigint is supported**** +****Conversion from SQLSRV_SQLTYPE_SMALLINT to bigint is supported**** +****Conversion from SQLSRV_SQLTYPE_INT to bigint is supported**** +****Conversion from SQLSRV_SQLTYPE_BIGINT to bigint is supported**** \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_nchar_size.phpt b/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_nchar_size.phpt new file mode 100644 index 00000000..6718f7e6 --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_ae_insert_sqltype_nchar_size.phpt @@ -0,0 +1,275 @@ +--TEST-- +Test for inserting encrypted data of nchar types with different sizes +--DESCRIPTION-- +Test implicit conversions between different nchar types of different sizes +With Always Encrypted, implicit conversion works if: +1. From input of SQLSRV_SQLTYPE_NCHAR(n) to a larger nchar(m) column where n <= m +2. From input of SQLSRV_SQLTYPE_NCHAR(n) to a larger nvarchar(m) column where n <= m (m can be max) +3. From input of SQLSRV_SQLTYPE_NVARCHAR(n) to a larger nchar(m) column where n <= m +4. From input of SQLSRV_SQLTYPE_NVARCHAR(n) to a larger nvarchar(m) column where n <= m (m can be max) +Without AlwaysEncrypted, implicit conversion between different binary types and sizes works +--SKIPIF-- + +--FILE-- + $input), $r, AE\INSERT_PREPARE_PARAMS); + + // check the case when SQLSRV_SQLTYPE length (n) is greater than the column length (m) + // if SQLSRV_SQLTYPE_NVARCHAR(max) ($maxsqltype), no conversion is supported except if the column is also max ($maxcol) + // if column is max ($maxcol), all conversions are supported + // with AE: should not work + // without AE: should work + if (($n > $m || $maxsqltype) && !$maxcol) { + if (AE\isDataEncrypted()) { + if ($r !== false) { + echo "AE: Conversion from $sqltypeFull to $typeFull should not be supported\n"; + } else { + if (sqlsrv_errors()[0]['SQLSTATE'] != "22018") { + echo "AE: Conversion from $sqltypeFull to $typeFull expects an operand type clash error, actual error is incorrect\n"; + var_dump(sqlsrv_errors()); + } + } + } else { + if ($r === false) { + echo "Conversions from $sqltypeFull to $typeFull should be supported\n"; + } + $sql = "SELECT c1 FROM $tbname"; + $stmt = sqlsrv_query($conn, $sql); + $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + if (trim($row['c1']) != $inputValue) { + echo "Conversion from $sqltypeFull to $typeFull causes data corruption\n"; + } + } + // check the case when SQLSRV_SQLTYPE length (n) is less than or equal to the column length (m) + // should work with AE or non AE + } else { + if ($r === false) { + echo "Conversion from $sqltypeFull to $typeFull should be supported\n"; + } else { + $sql = "SELECT c1 FROM $tbname"; + $stmt = sqlsrv_query($conn, $sql); + $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + if (trim($row['c1']) == $inputValue) { + echo "****Conversion from $sqltypeFull to $typeFull is supported****\n"; + } else { + echo "Conversion from $sqltypeFull to $typeFull causes data corruption\n"; + } + } + } + // cleanup + sqlsrv_free_stmt($stmt); + sqlsrv_query($conn, "TRUNCATE TABLE $tbname"); + } + } + dropTable($conn, $tbname); + } +} +sqlsrv_close($conn); + +?> +--EXPECT-- +Testing nchar(1): +****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nchar(1) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nchar(1) is supported**** + +Testing nchar(8): +****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nchar(8) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nchar(8) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nchar(8) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nchar(8) is supported**** + +Testing nchar(64): +****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nchar(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nchar(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(64) to nchar(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nchar(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nchar(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(64) to nchar(64) is supported**** + +Testing nchar(512): +****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nchar(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nchar(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(64) to nchar(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(512) to nchar(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nchar(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nchar(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(64) to nchar(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(512) to nchar(512) is supported**** + +Testing nchar(4000): +****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nchar(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nchar(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(64) to nchar(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(512) to nchar(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(4000) to nchar(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nchar(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nchar(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(64) to nchar(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(512) to nchar(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(4000) to nchar(4000) is supported**** + +Testing nvarchar(1): +****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nvarchar(1) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nvarchar(1) is supported**** + +Testing nvarchar(8): +****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nvarchar(8) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nvarchar(8) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nvarchar(8) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nvarchar(8) is supported**** + +Testing nvarchar(64): +****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nvarchar(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nvarchar(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(64) to nvarchar(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nvarchar(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nvarchar(64) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(64) to nvarchar(64) is supported**** + +Testing nvarchar(512): +****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nvarchar(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nvarchar(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(64) to nvarchar(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(512) to nvarchar(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nvarchar(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nvarchar(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(64) to nvarchar(512) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(512) to nvarchar(512) is supported**** + +Testing nvarchar(4000): +****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nvarchar(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nvarchar(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(64) to nvarchar(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(512) to nvarchar(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(4000) to nvarchar(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nvarchar(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nvarchar(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(64) to nvarchar(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(512) to nvarchar(4000) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(4000) to nvarchar(4000) is supported**** + +Testing nvarchar(max): +****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(64) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(512) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(4000) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(64) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(512) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(4000) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** + +Testing nvarchar(max): +****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(64) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(512) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(4000) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(64) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(512) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(4000) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** + +Testing nvarchar(max): +****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(64) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(512) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(4000) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(64) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(512) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(4000) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** + +Testing nvarchar(max): +****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(64) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(512) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(4000) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(64) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(512) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(4000) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** + +Testing nvarchar(max): +****Conversion from SQLSRV_SQLTYPE_NCHAR(1) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(8) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(64) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(512) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NCHAR(4000) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(1) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(8) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(64) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(512) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR(4000) to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** +****Conversion from SQLSRV_SQLTYPE_NVARCHAR('max') to nvarchar(max) is supported**** \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_ae_output_param_all.phpt b/test/functional/sqlsrv/sqlsrv_ae_output_param_all.phpt index f252de18..d7ff5db1 100644 --- a/test/functional/sqlsrv/sqlsrv_ae_output_param_all.phpt +++ b/test/functional/sqlsrv/sqlsrv_ae_output_param_all.phpt @@ -32,8 +32,7 @@ AE\createTable($conn, $tbname, $colMetaArr); // Create a Store Procedure $spname = 'selectAllColumns'; -$spSql = "CREATE PROCEDURE $spname ( - @c1_int int OUTPUT, @c2_smallint smallint OUTPUT, +createProc($conn, $spname, "@c1_int int OUTPUT, @c2_smallint smallint OUTPUT, @c3_tinyint tinyint OUTPUT, @c4_bit bit OUTPUT, @c5_bigint bigint OUTPUT, @c6_decimal decimal(18,5) OUTPUT, @c7_numeric numeric(10,5) OUTPUT, @c8_float float OUTPUT, @@ -41,8 +40,7 @@ $spSql = "CREATE PROCEDURE $spname ( @c11_datetime datetime OUTPUT, @c12_datetime2 datetime2 OUTPUT, @c13_datetimeoffset datetimeoffset OUTPUT, @c14_time time OUTPUT, @c15_char char(5) OUTPUT, @c16_varchar varchar(max) OUTPUT, - @c17_nchar nchar(5) OUTPUT, @c18_nvarchar nvarchar(max) OUTPUT) AS - SELECT @c1_int = c1_int, @c2_smallint = c2_smallint, + @c17_nchar nchar(5) OUTPUT, @c18_nvarchar nvarchar(max) OUTPUT", "SELECT @c1_int = c1_int, @c2_smallint = c2_smallint, @c3_tinyint = c3_tinyint, @c4_bit = c4_bit, @c5_bigint = c5_bigint, @c6_decimal = c6_decimal, @c7_numeric = c7_numeric, @c8_float = c8_float, @@ -51,9 +49,7 @@ $spSql = "CREATE PROCEDURE $spname ( @c13_datetimeoffset = c13_datetimeoffset, @c14_time = c14_time, @c15_char = c15_char, @c16_varchar = c16_varchar, @c17_nchar = c17_nchar, @c18_nvarchar = c18_nvarchar - FROM $tbname"; -sqlsrv_query($conn, $spSql); - + FROM $tbname"); // Insert data $inputs = array( "c1_int" => 2147483647, "c2_smallint" => 32767, diff --git a/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_binary_size.phpt b/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_binary_size.phpt new file mode 100644 index 00000000..c264cb0f --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_binary_size.phpt @@ -0,0 +1,278 @@ +--TEST-- +Test for retrieving encrypted data of binary types with different sizes as output parameters +--DESCRIPTION-- +Test implicit conversions between different binary types of different sizes +With Always Encrypted, implicit conversion works if: +1. From a binary(m) column to a SQLSRV_SQLTYPE_BINARY(n) output parameter where m == n +2. From a binary(m) column to a SQLSRV_SQLTYPE_VARBINARY(n) output parameter where m == n +3. From a varbinary(m) column to a SQLSRV_SQLTYPE_BINARY(n) output parameter where m == n +4. From a varbinary(m) column to a SQLSRV_SQLTYPE_VARBINARY(n) output parameter where m == n +Without AlwaysEncrypted, implicit conversion works if: +1. From a binary(m) column to a SQLSRV_SQLTYPE_BINARY(n) output parameter where m, n == any value +2. From a binary(m) column to a SQLSRV_SQLTYPE_VARBINARY(n) output parameter where m <= n (exclude SQLSRV_SQLTYPE_VARBINARY('max')) +3. From a varbinary(m) column to a SQLSRV_SQLTYPE_BINARY(n) output parameter where m, n == any value +4. From a varbinary(m) column to a SQLSRV_SQLTYPE_VARBINARY(n) output parameter where m, n == any value +--SKIPIF-- + +--FILE-- +colName => $inputs[0], $colMetaArr[1]->colName => $inputs[1]), $r, AE\INSERT_PREPARE_PARAMS); + + // create a stored procedure and sql string for calling the stored procedure + $spname = 'selectAllColumns'; + createProc($conn, $spname, "@c_det $typeFull OUTPUT, @c_rand $typeFull OUTPUT", "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname"); + $sql = AE\getCallProcSqlPlaceholders($spname, 2); + + // retrieve by specifying SQLSRV_SQLTYPE_BINARY(n) or SQLSRV_SQLTYPE_VARBINARY(n) as SQLSRV_PARAM_OUT or SQLSRV_PARAM_INOUT + foreach ($directions as $dir) { + echo "Testing as $dir:\n"; + foreach ($sqlTypes as $sqlType) { + $maxsqltype = strpos($sqlType, "max"); + foreach ($sqltypeLengths as $n) { + $sqltypeconst; + $sqltypeFull; + if ($maxsqltype) { + $sqltypeconst = SQLSRV_SQLTYPE_VARBINARY('max'); + $sqltypeFull = $sqlType; + } else { + $sqltypeconst = call_user_func($sqlType, $n); + $sqltypeFull = "$sqlType($n)"; + } + + $c_detOut = ''; + $c_randOut = ''; + $stmt = sqlsrv_prepare($conn, $sql, array(array(&$c_detOut, constant($dir), SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY), $sqltypeconst), array(&$c_randOut, constant($dir), SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY), $sqltypeconst))); + $r = sqlsrv_execute($stmt); + + // check the case when SQLSRV_SQLTYPE length (n) is not the same as the column length (m) + // with AE: should not work + // without AE: should work, except when a SQLSRV_SQLTYPE_VARBINARY length (n) is less than a binary column length (m) for SQLSRV_PARAM_OUT + if (($n != $m || $maxsqltype || $maxcol) && !($maxcol && $maxsqltype)) { + if (AE\isDataEncrypted()) { + if ($r !== false) { + echo "AE: Conversion from $typeFull to output $sqltypeFull should not be supported\n"; + } else { + if (sqlsrv_errors()[0]['SQLSTATE'] != "22018") { + echo "AE: Conversion from $typeFull to output $sqltypeFull expects an operand type clash error, actual error is incorrect\n"; + var_dump(sqlsrv_errors()); + } + } + } else { + if (!AE\isColEncrypted() && strpos($sqltypeFull, "VARBINARY") !== false && $dataType == "binary" && $m > $n && strpos($sqltypeFull, "max") === false && $dir == "SQLSRV_PARAM_OUT") { + if ($r !== false) { + echo "Conversions from $typeFull to output $sqltypeFull should not be supported\n"; + } + } else { + if ($r === false) { + if (strpos($sqltypeFull, "VARBINARY") !== false || $dataType != "binary" || $m <= $n) { + echo "Conversions from $typeFull to output $sqltypeFull should be supported\n"; + } + } + if (trim($c_detOut) != $inputValues[0] || trim($c_randOut) != $inputValues[1]) { + echo "Conversion from $typeFull to output $sqltypeFull causes data corruption\n"; + } + } + } + // check the case then SQLSRV_SQLTYPE length (n) is the same as the column length (m) + // should work with AE or non AE + } else { + if ($r === false) { + echo "Conversion from $typeFull to output $sqltypeFull should be supported\n"; + var_dump(sqlsrv_errors()); + } else { + if (trim($c_detOut) == $inputValues[0] && trim($c_randOut) == $inputValues[1]) { + echo "****Conversion from $typeFull to output $sqltypeFull is supported****\n"; + } else { + echo "Conversion from $typeFull to output $sqltypeFull causes data corruption\n"; + } + } + } + // cleanup + sqlsrv_free_stmt($stmt); + } + } + } + dropProc($conn, $spname); + dropTable($conn, $tbname); + } +} +sqlsrv_close($conn); + +?> +--EXPECT-- +Testing binary(1): +Testing as SQLSRV_PARAM_OUT: +****Conversion from binary(1) to output SQLSRV_SQLTYPE_BINARY(1) is supported**** +****Conversion from binary(1) to output SQLSRV_SQLTYPE_VARBINARY(1) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from binary(1) to output SQLSRV_SQLTYPE_BINARY(1) is supported**** +****Conversion from binary(1) to output SQLSRV_SQLTYPE_VARBINARY(1) is supported**** + +Testing binary(8): +Testing as SQLSRV_PARAM_OUT: +****Conversion from binary(8) to output SQLSRV_SQLTYPE_BINARY(8) is supported**** +****Conversion from binary(8) to output SQLSRV_SQLTYPE_VARBINARY(8) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from binary(8) to output SQLSRV_SQLTYPE_BINARY(8) is supported**** +****Conversion from binary(8) to output SQLSRV_SQLTYPE_VARBINARY(8) is supported**** + +Testing binary(64): +Testing as SQLSRV_PARAM_OUT: +****Conversion from binary(64) to output SQLSRV_SQLTYPE_BINARY(64) is supported**** +****Conversion from binary(64) to output SQLSRV_SQLTYPE_VARBINARY(64) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from binary(64) to output SQLSRV_SQLTYPE_BINARY(64) is supported**** +****Conversion from binary(64) to output SQLSRV_SQLTYPE_VARBINARY(64) is supported**** + +Testing binary(512): +Testing as SQLSRV_PARAM_OUT: +****Conversion from binary(512) to output SQLSRV_SQLTYPE_BINARY(512) is supported**** +****Conversion from binary(512) to output SQLSRV_SQLTYPE_VARBINARY(512) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from binary(512) to output SQLSRV_SQLTYPE_BINARY(512) is supported**** +****Conversion from binary(512) to output SQLSRV_SQLTYPE_VARBINARY(512) is supported**** + +Testing binary(4000): +Testing as SQLSRV_PARAM_OUT: +****Conversion from binary(4000) to output SQLSRV_SQLTYPE_BINARY(4000) is supported**** +****Conversion from binary(4000) to output SQLSRV_SQLTYPE_VARBINARY(4000) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from binary(4000) to output SQLSRV_SQLTYPE_BINARY(4000) is supported**** +****Conversion from binary(4000) to output SQLSRV_SQLTYPE_VARBINARY(4000) is supported**** + +Testing varbinary(1): +Testing as SQLSRV_PARAM_OUT: +****Conversion from varbinary(1) to output SQLSRV_SQLTYPE_BINARY(1) is supported**** +****Conversion from varbinary(1) to output SQLSRV_SQLTYPE_VARBINARY(1) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from varbinary(1) to output SQLSRV_SQLTYPE_BINARY(1) is supported**** +****Conversion from varbinary(1) to output SQLSRV_SQLTYPE_VARBINARY(1) is supported**** + +Testing varbinary(8): +Testing as SQLSRV_PARAM_OUT: +****Conversion from varbinary(8) to output SQLSRV_SQLTYPE_BINARY(8) is supported**** +****Conversion from varbinary(8) to output SQLSRV_SQLTYPE_VARBINARY(8) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from varbinary(8) to output SQLSRV_SQLTYPE_BINARY(8) is supported**** +****Conversion from varbinary(8) to output SQLSRV_SQLTYPE_VARBINARY(8) is supported**** + +Testing varbinary(64): +Testing as SQLSRV_PARAM_OUT: +****Conversion from varbinary(64) to output SQLSRV_SQLTYPE_BINARY(64) is supported**** +****Conversion from varbinary(64) to output SQLSRV_SQLTYPE_VARBINARY(64) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from varbinary(64) to output SQLSRV_SQLTYPE_BINARY(64) is supported**** +****Conversion from varbinary(64) to output SQLSRV_SQLTYPE_VARBINARY(64) is supported**** + +Testing varbinary(512): +Testing as SQLSRV_PARAM_OUT: +****Conversion from varbinary(512) to output SQLSRV_SQLTYPE_BINARY(512) is supported**** +****Conversion from varbinary(512) to output SQLSRV_SQLTYPE_VARBINARY(512) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from varbinary(512) to output SQLSRV_SQLTYPE_BINARY(512) is supported**** +****Conversion from varbinary(512) to output SQLSRV_SQLTYPE_VARBINARY(512) is supported**** + +Testing varbinary(4000): +Testing as SQLSRV_PARAM_OUT: +****Conversion from varbinary(4000) to output SQLSRV_SQLTYPE_BINARY(4000) is supported**** +****Conversion from varbinary(4000) to output SQLSRV_SQLTYPE_VARBINARY(4000) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from varbinary(4000) to output SQLSRV_SQLTYPE_BINARY(4000) is supported**** +****Conversion from varbinary(4000) to output SQLSRV_SQLTYPE_VARBINARY(4000) is supported**** + +Testing varbinary(max): +Testing as SQLSRV_PARAM_OUT: +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** + +Testing varbinary(max): +Testing as SQLSRV_PARAM_OUT: +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** + +Testing varbinary(max): +Testing as SQLSRV_PARAM_OUT: +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** + +Testing varbinary(max): +Testing as SQLSRV_PARAM_OUT: +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** + +Testing varbinary(max): +Testing as SQLSRV_PARAM_OUT: +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** +****Conversion from varbinary(max) to output SQLSRV_SQLTYPE_VARBINARY('max') is supported**** \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_char_size.phpt b/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_char_size.phpt new file mode 100644 index 00000000..2a62659d --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_char_size.phpt @@ -0,0 +1,316 @@ +--TEST-- +Test for retrieving encrypted data of char types with different sizes as output parameters +--DESCRIPTION-- +Test implicit conversions between different char types of different sizes +With Always Encrypted, implicit conversion works if: +1. From a char(m) column to a SQLSRV_SQLTYPE_CHAR(n) output parameter where m == n +2. From a char(m) column to a SQLSRV_SQLTYPE_VARCHAR(n) output parameter where m == n +3. From a varchar(m) column to a SQLSRV_SQLTYPE_CHAR(n) output parameter where m == n +4. From a varchar(m) column to a SQLSRV_SQLTYPE_VARCHAR(n) output parameter where m == n +Without AlwaysEncrypted, implicit conversion works if: +1. From a char(m) column to a SQLSRV_SQLTYPE_CHAR(n) output parameter where m, n == any value +2. From a char(m) column to a SQLSRV_SQLTYPE_VARCHAR(n) output parameter where m <= n (exclude SQLSRV_SQLTYPE_VARCHAR('max')) +3. From a varchar(m) column to a SQLSRV_SQLTYPE_CHAR(n) output parameter where m, n == any value +4. From a varchar(m) column to a SQLSRV_SQLTYPE_VARCHAR(n) output parameter where m, n == any value +--SKIPIF-- + +--FILE-- +colName => $inputValue)); + + // create a stored procedure and sql string for calling the stored procedure + $spname = 'selectAllColumns'; + createProc($conn, $spname, "@c1 $typeFull OUTPUT", "SELECT @c1 = c1 FROM $tbname"); + $sql = AE\getCallProcSqlPlaceholders($spname, 1); + + // retrieve by specifying SQLSRV_SQLTYPE_CHAR(n) or SQLSRV_SQLTYPE_VARCHAR(n) as SQLSRV_PARAM_OUT or SQLSRV_PARAM_INOUT + foreach ($directions as $dir) { + echo "Testing as $dir:\n"; + foreach ($sqlTypes as $sqlType) { + $maxsqltype = strpos($sqlType, "max"); + foreach ($sqltypeLengths as $n) { + $sqltypeconst; + $sqltypeFull; + if ($maxsqltype) { + $sqltypeconst = SQLSRV_SQLTYPE_VARCHAR('max'); + $sqltypeFull = $sqlType; + } else { + $sqltypeconst = call_user_func($sqlType, $n); + $sqltypeFull = "$sqlType($n)"; + } + + $c1 = ''; + $stmt = sqlsrv_prepare($conn, $sql, array(array(&$c1, constant($dir), null, $sqltypeconst))); + $r = sqlsrv_execute($stmt); + + // check the case when SQLSRV_SQLTYPE length (n) is not the same as the column length (m) + // with AE: should not work + // without AE: should work, except when a SQLSRV_SQLTYPE_VARCHAR length (n) is less than a char column length (m) + if (($n != $m || $maxsqltype || $maxcol) && !($maxcol && $maxsqltype)) { + if (AE\isDataEncrypted()) { + if ($r !== false) { + echo "AE: Conversion from $typeFull to output $sqltypeFull should not be supported\n"; + } else { + if (sqlsrv_errors()[0]['SQLSTATE'] != "22018") { + echo "AE: Conversion from $typeFull to output $sqltypeFull expects an operand type clash error, actual error is incorrect\n"; + var_dump(sqlsrv_errors()); + } + } + } else { + if (!AE\isColEncrypted() && strpos($sqltypeFull, "VARCHAR") !== false && $dataType == "char" && $m > $n && strpos($sqltypeFull, "max") === false && $dir == "SQLSRV_PARAM_OUT") { + if ($r !== false) { + echo "Conversions from $typeFull to output $sqltypeFull should not be supported\n"; + var_dump($c1); + } + } else { + if ($r === false) { + if (strpos($sqltypeFull, "VARCHAR") !== false || $dataType != "char" || $m <= $n) { + echo "Conversions from $typeFull to output $sqltypeFull should be supported\n"; + } + } + if (trim($c1) != $inputValue) { + echo "Conversion from $typeFull to output $sqltypeFull causes data corruption\n"; + } + } + } + // check the case then SQLSRV_SQLTYPE length (n) is the same as the column length (m) + // should work with AE or non AE + } else { + if ($r === false) { + echo "Conversion from $typeFull to output $sqltypeFull should be supported\n"; + } else { + if (trim($c1) == $inputValue) { + echo "****Conversion from $typeFull to output $sqltypeFull is supported****\n"; + } else { + echo "Conversion from $typeFull to output $sqltypeFull causes data corruption\n"; + } + } + } + // cleanup + sqlsrv_free_stmt($stmt); + } + } + } + dropProc($conn, $spname); + dropTable($conn, $tbname); + } +} +sqlsrv_close($conn); + +?> +--EXPECT-- +Testing char(1): +Testing as SQLSRV_PARAM_OUT: +****Conversion from char(1) to output SQLSRV_SQLTYPE_CHAR(1) is supported**** +****Conversion from char(1) to output SQLSRV_SQLTYPE_VARCHAR(1) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from char(1) to output SQLSRV_SQLTYPE_CHAR(1) is supported**** +****Conversion from char(1) to output SQLSRV_SQLTYPE_VARCHAR(1) is supported**** + +Testing char(8): +Testing as SQLSRV_PARAM_OUT: +****Conversion from char(8) to output SQLSRV_SQLTYPE_CHAR(8) is supported**** +****Conversion from char(8) to output SQLSRV_SQLTYPE_VARCHAR(8) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from char(8) to output SQLSRV_SQLTYPE_CHAR(8) is supported**** +****Conversion from char(8) to output SQLSRV_SQLTYPE_VARCHAR(8) is supported**** + +Testing char(64): +Testing as SQLSRV_PARAM_OUT: +****Conversion from char(64) to output SQLSRV_SQLTYPE_CHAR(64) is supported**** +****Conversion from char(64) to output SQLSRV_SQLTYPE_VARCHAR(64) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from char(64) to output SQLSRV_SQLTYPE_CHAR(64) is supported**** +****Conversion from char(64) to output SQLSRV_SQLTYPE_VARCHAR(64) is supported**** + +Testing char(512): +Testing as SQLSRV_PARAM_OUT: +****Conversion from char(512) to output SQLSRV_SQLTYPE_CHAR(512) is supported**** +****Conversion from char(512) to output SQLSRV_SQLTYPE_VARCHAR(512) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from char(512) to output SQLSRV_SQLTYPE_CHAR(512) is supported**** +****Conversion from char(512) to output SQLSRV_SQLTYPE_VARCHAR(512) is supported**** + +Testing char(4096): +Testing as SQLSRV_PARAM_OUT: +****Conversion from char(4096) to output SQLSRV_SQLTYPE_CHAR(4096) is supported**** +****Conversion from char(4096) to output SQLSRV_SQLTYPE_VARCHAR(4096) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from char(4096) to output SQLSRV_SQLTYPE_CHAR(4096) is supported**** +****Conversion from char(4096) to output SQLSRV_SQLTYPE_VARCHAR(4096) is supported**** + +Testing char(8000): +Testing as SQLSRV_PARAM_OUT: +****Conversion from char(8000) to output SQLSRV_SQLTYPE_CHAR(8000) is supported**** +****Conversion from char(8000) to output SQLSRV_SQLTYPE_VARCHAR(8000) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from char(8000) to output SQLSRV_SQLTYPE_CHAR(8000) is supported**** +****Conversion from char(8000) to output SQLSRV_SQLTYPE_VARCHAR(8000) is supported**** + +Testing varchar(1): +Testing as SQLSRV_PARAM_OUT: +****Conversion from varchar(1) to output SQLSRV_SQLTYPE_CHAR(1) is supported**** +****Conversion from varchar(1) to output SQLSRV_SQLTYPE_VARCHAR(1) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from varchar(1) to output SQLSRV_SQLTYPE_CHAR(1) is supported**** +****Conversion from varchar(1) to output SQLSRV_SQLTYPE_VARCHAR(1) is supported**** + +Testing varchar(8): +Testing as SQLSRV_PARAM_OUT: +****Conversion from varchar(8) to output SQLSRV_SQLTYPE_CHAR(8) is supported**** +****Conversion from varchar(8) to output SQLSRV_SQLTYPE_VARCHAR(8) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from varchar(8) to output SQLSRV_SQLTYPE_CHAR(8) is supported**** +****Conversion from varchar(8) to output SQLSRV_SQLTYPE_VARCHAR(8) is supported**** + +Testing varchar(64): +Testing as SQLSRV_PARAM_OUT: +****Conversion from varchar(64) to output SQLSRV_SQLTYPE_CHAR(64) is supported**** +****Conversion from varchar(64) to output SQLSRV_SQLTYPE_VARCHAR(64) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from varchar(64) to output SQLSRV_SQLTYPE_CHAR(64) is supported**** +****Conversion from varchar(64) to output SQLSRV_SQLTYPE_VARCHAR(64) is supported**** + +Testing varchar(512): +Testing as SQLSRV_PARAM_OUT: +****Conversion from varchar(512) to output SQLSRV_SQLTYPE_CHAR(512) is supported**** +****Conversion from varchar(512) to output SQLSRV_SQLTYPE_VARCHAR(512) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from varchar(512) to output SQLSRV_SQLTYPE_CHAR(512) is supported**** +****Conversion from varchar(512) to output SQLSRV_SQLTYPE_VARCHAR(512) is supported**** + +Testing varchar(4096): +Testing as SQLSRV_PARAM_OUT: +****Conversion from varchar(4096) to output SQLSRV_SQLTYPE_CHAR(4096) is supported**** +****Conversion from varchar(4096) to output SQLSRV_SQLTYPE_VARCHAR(4096) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from varchar(4096) to output SQLSRV_SQLTYPE_CHAR(4096) is supported**** +****Conversion from varchar(4096) to output SQLSRV_SQLTYPE_VARCHAR(4096) is supported**** + +Testing varchar(8000): +Testing as SQLSRV_PARAM_OUT: +****Conversion from varchar(8000) to output SQLSRV_SQLTYPE_CHAR(8000) is supported**** +****Conversion from varchar(8000) to output SQLSRV_SQLTYPE_VARCHAR(8000) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from varchar(8000) to output SQLSRV_SQLTYPE_CHAR(8000) is supported**** +****Conversion from varchar(8000) to output SQLSRV_SQLTYPE_VARCHAR(8000) is supported**** + +Testing varchar(max): +Testing as SQLSRV_PARAM_OUT: +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** + +Testing varchar(max): +Testing as SQLSRV_PARAM_OUT: +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** + +Testing varchar(max): +Testing as SQLSRV_PARAM_OUT: +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** + +Testing varchar(max): +Testing as SQLSRV_PARAM_OUT: +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** + +Testing varchar(max): +Testing as SQLSRV_PARAM_OUT: +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** + +Testing varchar(max): +Testing as SQLSRV_PARAM_OUT: +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** +****Conversion from varchar(max) to output SQLSRV_SQLTYPE_VARCHAR('max') is supported**** \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_datetime.phpt b/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_datetime.phpt new file mode 100755 index 00000000..7eebb400 --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_datetime.phpt @@ -0,0 +1,139 @@ +--TEST-- +Test for inserting and retrieving encrypted data of datetime types +--DESCRIPTION-- +Bind output params using sqlsrv_prepare with all sql_type +--SKIPIF-- + +--FILE-- + array( "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DATE", "SQLSRV_SQLTYPE_DATETIMEOFFSET", "SQLSRV_SQLTYPE_DATETIME2"), + "datetime" => array( "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DATE", "SQLSRV_SQLTYPE_TIME", "SQLSRV_SQLTYPE_DATETIMEOFFSET", "SQLSRV_SQLTYPE_DATETIME2"), + "datetime2" => array( "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DATE", "SQLSRV_SQLTYPE_TIME", "SQLSRV_SQLTYPE_DATETIMEOFFSET", "SQLSRV_SQLTYPE_DATETIME2"), + "smalldatetime" => array( "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DATE", "SQLSRV_SQLTYPE_TIME", "SQLSRV_SQLTYPE_DATETIMEOFFSET", "SQLSRV_SQLTYPE_DATETIME2"), + "time" => array( "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_TIME", "SQLSRV_SQLTYPE_DATETIMEOFFSET", "SQLSRV_SQLTYPE_DATETIME2"), + "datetimeoffset" => array("SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIMEOFFSET") ); + +$conn = AE\connect(); + +foreach ($dataTypes as $dataType) { + echo "\nTesting $dataType:\n"; + $success = true; + + // create table + $tbname = GetTempTableName("", false); + $colMetaArr = array(new AE\ColumnMeta($dataType, "c_det"), new AE\ColumnMeta($dataType, "c_rand", null, false)); + AE\createTable($conn, $tbname, $colMetaArr); + + if (AE\isColEncrypted()) { + // Create a Store Procedure + $spname = 'selectAllColumns'; + createProc($conn, $spname, "@c_det $dataType OUTPUT, @c_rand $dataType OUTPUT", "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname"); + } + + // insert a row + $inputValues = array_slice(${explode("(", $dataType)[0] . "_params"}, 1, 2); + $r; + $stmt = AE\insertRow($conn, $tbname, array( $colMetaArr[0]->colName => $inputValues[0], $colMetaArr[1]->colName => $inputValues[1] ), $r); + if ($r === false) { + is_incompatible_types_error($dataType, "default type"); + } + + foreach($directions as $direction) { + echo "Testing as $direction:\n"; + + // test each SQLSRV_SQLTYPE_ constants + foreach ($sqlTypes as $sqlType) { + if (!AE\isColEncrypted()) { + $isCompatible = false; + foreach ($compatList[$dataType] as $compatType) { + if (stripos($compatType, $sqlType) !== false) { + $isCompatible = true; + } + } + // 22018 is the SQLSTATE for any incompatible conversion errors + if ($isCompatible && sqlsrv_errors()[0]['SQLSTATE'] == 22018) { + echo "$sqlType should be compatible with $dataType\n"; + $success = false; + } + } else { + // skip unsupported datetime types + if (!isDateTimeType($sqlType)) { + $sqlTypeConstant = get_sqlType_constant($sqlType); + + // Call store procedure + $outSql = AE\getCallProcSqlPlaceholders($spname, 2); + $c_detOut = ''; + $c_randOut = ''; + $stmt = sqlsrv_prepare( $conn, $outSql, + array(array( &$c_detOut, SQLSRV_PARAM_OUT, null, $sqlTypeConstant), + array(&$c_randOut, SQLSRV_PARAM_OUT, null, $sqlTypeConstant ))); + if (!$stmt) { + die(print_r(sqlsrv_errors(), true)); + } + sqlsrv_execute($stmt); + $errors = sqlsrv_errors(); + if (empty($errors) && AE\IsDataEncrypted()) { + // SQLSRV_PHPTYPE_DATETIME not supported + echo "$dataType should not be compatible with any datetime type.\n"; + $success = false; + } + } + } + } + } + + // cleanup + sqlsrv_free_stmt($stmt); + sqlsrv_query($conn, "TRUNCATE TABLE $tbname"); + + if ($success) { + echo "Test successfully done.\n"; + } + + if (AE\isColEncrypted()) { + dropProc($conn, $spname); + } + dropTable($conn, $tbname); +} + +sqlsrv_close($conn); +?> +--EXPECT-- + +Testing date: +Testing as SQLSRV_PARAM_OUT: +Testing as SQLSRV_PARAM_INOUT: +Test successfully done. + +Testing datetime: +Testing as SQLSRV_PARAM_OUT: +Testing as SQLSRV_PARAM_INOUT: +Test successfully done. + +Testing datetime2: +Testing as SQLSRV_PARAM_OUT: +Testing as SQLSRV_PARAM_INOUT: +Test successfully done. + +Testing smalldatetime: +Testing as SQLSRV_PARAM_OUT: +Testing as SQLSRV_PARAM_INOUT: +Test successfully done. + +Testing time: +Testing as SQLSRV_PARAM_OUT: +Testing as SQLSRV_PARAM_INOUT: +Test successfully done. + +Testing datetimeoffset: +Testing as SQLSRV_PARAM_OUT: +Testing as SQLSRV_PARAM_INOUT: +Test successfully done. diff --git a/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_decimal_precision.phpt b/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_decimal_precision.phpt new file mode 100644 index 00000000..06021dbe --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_decimal_precision.phpt @@ -0,0 +1,265 @@ +--TEST-- +Test for retrieving encrypted data of decimal types with different precisions and scales as output parameters +--DESCRIPTION-- +Test implicit conversions between different precisions and scales +With Always Encrypted, no implicit conversion works for decimal datatypes, the precision and scale specified in the SQLSRV_SQLTYPE must be identical to the precision and scale defined in the column +Without AlwaysEncrypted, implicit conversion between precisions or scales works if: +1. From a decimal(m1, m2) column to a SQLSRV_SQLTYPE_DECIMAL(n1, n2) output parameter where n1 - n2 >= m1 - m2 +--SKIPIF-- + +--FILE-- + array(0, 1), + 4 => array(0, 1, 4), + 16 => array(0, 1, 4, 16),*/ + 19 => array(/*0,*/ 1, 4, 16, 19), + 38 => array(/*0,*/ 1, 4, 16, 37/*,38*/)); +$sqlTypes = array("SQLSRV_SQLTYPE_DECIMAL", "SQLSRV_SQLTYPE_NUMERIC"); +$sqltypePrecisions = $precisions; +$inputValuesInit = array(92233720368547758089223372036854775808, -92233720368547758089223372036854775808); +$maxInPrecision = 38; +$directions = array("SQLSRV_PARAM_OUT", "SQLSRV_PARAM_INOUT"); + +$conn = AE\connect(); + +foreach ($dataTypes as $dataType) { + foreach ($precisions as $m1 => $inScales) { + foreach ($inScales as $m2) { + // change the number of integers in the input values to be $m1 - $m2 + $precDiff = $maxInPrecision - ($m1 - $m2); + $inputValues = $inputValuesInit; + foreach ($inputValues as &$inputValue) { + $inputValue = $inputValue / pow(10, $precDiff); + } + $typeFull = "$dataType($m1, $m2)"; + echo "\nTesting $typeFull:\n"; + + // create and populate table containing decimal(m1, m2) or numeric(m1, m2) columns + $tbname = "test_" . $dataType . $m1 . $m2; + $colMetaArr = array(new AE\ColumnMeta($typeFull, "c_det"), new AE\ColumnMeta($typeFull, "c_rand", null, false)); + AE\createTable($conn, $tbname, $colMetaArr); + $stmt = AE\insertRow($conn, $tbname, array($colMetaArr[0]->colName => $inputValues[0], $colMetaArr[1]->colName => $inputValues[1])); + + // create a stored procedure and sql string for calling the stored procedure + $spname = 'selectAllColumns'; + createProc($conn, $spname, "@c_det $typeFull OUTPUT, @c_rand $typeFull OUTPUT", "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname"); + $sql = AE\getCallProcSqlPlaceholders($spname, 2); + + // retrieve by specifying SQLSRV_SQLTYPE_DECIMAL(n1, n2) or SQLSRV_SQLTYPE_NUMERIC(n1, n2) as SQLSRV_PARAM_OUT or SQLSRV_PARAM_INOUT + foreach ($directions as $dir) { + echo "Testing as $dir:\n"; + foreach ($sqlTypes as $sqlType) { + foreach ($sqltypePrecisions as $n1 => $sqltypeScales) { + foreach ($sqltypeScales as $n2) { + + // compute the epsilon for comparing doubles + // float in PHP only has a precision of roughtly 14 digits: http://php.net/manual/en/language.types.float.php + // the smaller precision and scale (n1 and n2 vs m1 and m2) take precedence + $epsilon; + $smallerprec = min($m1, $n1); + $smallerscale = min($m2, $n2); + if ($smallerprec < 14) { + $epsilon = pow(10, $smallerscale * -1); + } else { + $numint = $smallerprec - $smallerscale; + if ($numint < 14) { + $epsilon = pow(10, (14 - $numint) * -1); + } else { + $epsilon = pow(10, $numint - 14); + } + } + + $sqltypeFull = "$sqlType($n1, $n2)"; + $sqltypeconst = call_user_func($sqlType, $n1, $n2); + + $c_detOut = 0.0; + $c_randOut = 0.0; + $stmt = sqlsrv_prepare($conn, $sql, array(array(&$c_detOut, constant($dir), null, $sqltypeconst), array(&$c_randOut, constant($dir), null, $sqltypeconst))); + $r = sqlsrv_execute($stmt); + + // check the case when the SQLSRV_SQLTYPE precision (n1) is not the same as the column precision (m1) + // or the SQLSRV_SQLTYPE scale (n2) is not the same as the column precision (m2) + // with AE: should not work + // without AE: should not work if n1 - n2 < m1 - m2 + if ($n1 != $m1 || $n2 != $m2) { + if (AE\isDataEncrypted()) { + if ($r !== false) { + echo "AE: Conversion from $typeFull to output $sqltypeFull should not be supported\n"; + } else { + if (sqlsrv_errors()[0]['SQLSTATE'] != "22018") { + echo "AE: Conversion from $typeFull to output $sqltypeFull expects an operand type clash error, actual error is incorrect\n"; + var_dump(sqlsrv_errors()); + } + } + } else { + if ($n1 - $n2 < $m1 - $m2) { + if ($r !== false) { + echo "Conversion from $typeFull to output $sqltypeFull should not be supported\n"; + } + } else { + if ($r === false) { + echo "Conversion from $typeFull to output $sqltypeFull should be supported\n"; + } else { + if (abs($c_detOut - $inputValues[0]) > $epsilon || abs($c_randOut - $inputValues[1]) > $epsilon) { + echo "Conversion from $typeFull to output $sqltypeFull causes data corruption\n"; + } + } + } + } + // check the case when the SQLSRV_SQLTYPE precision (n1) and scale (n2) are the same as the column precision (m1) and scale (m2) + // should work with AE or non AE + } else { + if ($r === false) { + echo "Conversion from $typeFull to output $sqltypeFull should be supported\n"; + } else { + if (abs($c_detOut - $inputValues[0]) < $epsilon && abs($c_randOut - $inputValues[1]) < $epsilon) { + echo "****Conversion from $typeFull to output $sqltypeFull is supported****\n"; + } else { + echo "Conversion from $typeFull to output $sqltypeFull causes data corruption\n"; + } + } + } + // cleanup + sqlsrv_free_stmt($stmt); + } + } + } + } + dropProc($conn, $spname); + dropTable($conn, $tbname); + } + } +} +sqlsrv_close($conn); +?> +--EXPECT-- +Testing decimal(19, 1): +Testing as SQLSRV_PARAM_OUT: +****Conversion from decimal(19, 1) to output SQLSRV_SQLTYPE_DECIMAL(19, 1) is supported**** +****Conversion from decimal(19, 1) to output SQLSRV_SQLTYPE_NUMERIC(19, 1) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from decimal(19, 1) to output SQLSRV_SQLTYPE_DECIMAL(19, 1) is supported**** +****Conversion from decimal(19, 1) to output SQLSRV_SQLTYPE_NUMERIC(19, 1) is supported**** + +Testing decimal(19, 4): +Testing as SQLSRV_PARAM_OUT: +****Conversion from decimal(19, 4) to output SQLSRV_SQLTYPE_DECIMAL(19, 4) is supported**** +****Conversion from decimal(19, 4) to output SQLSRV_SQLTYPE_NUMERIC(19, 4) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from decimal(19, 4) to output SQLSRV_SQLTYPE_DECIMAL(19, 4) is supported**** +****Conversion from decimal(19, 4) to output SQLSRV_SQLTYPE_NUMERIC(19, 4) is supported**** + +Testing decimal(19, 16): +Testing as SQLSRV_PARAM_OUT: +****Conversion from decimal(19, 16) to output SQLSRV_SQLTYPE_DECIMAL(19, 16) is supported**** +****Conversion from decimal(19, 16) to output SQLSRV_SQLTYPE_NUMERIC(19, 16) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from decimal(19, 16) to output SQLSRV_SQLTYPE_DECIMAL(19, 16) is supported**** +****Conversion from decimal(19, 16) to output SQLSRV_SQLTYPE_NUMERIC(19, 16) is supported**** + +Testing decimal(19, 19): +Testing as SQLSRV_PARAM_OUT: +****Conversion from decimal(19, 19) to output SQLSRV_SQLTYPE_DECIMAL(19, 19) is supported**** +****Conversion from decimal(19, 19) to output SQLSRV_SQLTYPE_NUMERIC(19, 19) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from decimal(19, 19) to output SQLSRV_SQLTYPE_DECIMAL(19, 19) is supported**** +****Conversion from decimal(19, 19) to output SQLSRV_SQLTYPE_NUMERIC(19, 19) is supported**** + +Testing decimal(38, 1): +Testing as SQLSRV_PARAM_OUT: +****Conversion from decimal(38, 1) to output SQLSRV_SQLTYPE_DECIMAL(38, 1) is supported**** +****Conversion from decimal(38, 1) to output SQLSRV_SQLTYPE_NUMERIC(38, 1) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from decimal(38, 1) to output SQLSRV_SQLTYPE_DECIMAL(38, 1) is supported**** +****Conversion from decimal(38, 1) to output SQLSRV_SQLTYPE_NUMERIC(38, 1) is supported**** + +Testing decimal(38, 4): +Testing as SQLSRV_PARAM_OUT: +****Conversion from decimal(38, 4) to output SQLSRV_SQLTYPE_DECIMAL(38, 4) is supported**** +****Conversion from decimal(38, 4) to output SQLSRV_SQLTYPE_NUMERIC(38, 4) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from decimal(38, 4) to output SQLSRV_SQLTYPE_DECIMAL(38, 4) is supported**** +****Conversion from decimal(38, 4) to output SQLSRV_SQLTYPE_NUMERIC(38, 4) is supported**** + +Testing decimal(38, 16): +Testing as SQLSRV_PARAM_OUT: +****Conversion from decimal(38, 16) to output SQLSRV_SQLTYPE_DECIMAL(38, 16) is supported**** +****Conversion from decimal(38, 16) to output SQLSRV_SQLTYPE_NUMERIC(38, 16) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from decimal(38, 16) to output SQLSRV_SQLTYPE_DECIMAL(38, 16) is supported**** +****Conversion from decimal(38, 16) to output SQLSRV_SQLTYPE_NUMERIC(38, 16) is supported**** + +Testing decimal(38, 37): +Testing as SQLSRV_PARAM_OUT: +****Conversion from decimal(38, 37) to output SQLSRV_SQLTYPE_DECIMAL(38, 37) is supported**** +****Conversion from decimal(38, 37) to output SQLSRV_SQLTYPE_NUMERIC(38, 37) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from decimal(38, 37) to output SQLSRV_SQLTYPE_DECIMAL(38, 37) is supported**** +****Conversion from decimal(38, 37) to output SQLSRV_SQLTYPE_NUMERIC(38, 37) is supported**** + +Testing numeric(19, 1): +Testing as SQLSRV_PARAM_OUT: +****Conversion from numeric(19, 1) to output SQLSRV_SQLTYPE_DECIMAL(19, 1) is supported**** +****Conversion from numeric(19, 1) to output SQLSRV_SQLTYPE_NUMERIC(19, 1) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from numeric(19, 1) to output SQLSRV_SQLTYPE_DECIMAL(19, 1) is supported**** +****Conversion from numeric(19, 1) to output SQLSRV_SQLTYPE_NUMERIC(19, 1) is supported**** + +Testing numeric(19, 4): +Testing as SQLSRV_PARAM_OUT: +****Conversion from numeric(19, 4) to output SQLSRV_SQLTYPE_DECIMAL(19, 4) is supported**** +****Conversion from numeric(19, 4) to output SQLSRV_SQLTYPE_NUMERIC(19, 4) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from numeric(19, 4) to output SQLSRV_SQLTYPE_DECIMAL(19, 4) is supported**** +****Conversion from numeric(19, 4) to output SQLSRV_SQLTYPE_NUMERIC(19, 4) is supported**** + +Testing numeric(19, 16): +Testing as SQLSRV_PARAM_OUT: +****Conversion from numeric(19, 16) to output SQLSRV_SQLTYPE_DECIMAL(19, 16) is supported**** +****Conversion from numeric(19, 16) to output SQLSRV_SQLTYPE_NUMERIC(19, 16) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from numeric(19, 16) to output SQLSRV_SQLTYPE_DECIMAL(19, 16) is supported**** +****Conversion from numeric(19, 16) to output SQLSRV_SQLTYPE_NUMERIC(19, 16) is supported**** + +Testing numeric(19, 19): +Testing as SQLSRV_PARAM_OUT: +****Conversion from numeric(19, 19) to output SQLSRV_SQLTYPE_DECIMAL(19, 19) is supported**** +****Conversion from numeric(19, 19) to output SQLSRV_SQLTYPE_NUMERIC(19, 19) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from numeric(19, 19) to output SQLSRV_SQLTYPE_DECIMAL(19, 19) is supported**** +****Conversion from numeric(19, 19) to output SQLSRV_SQLTYPE_NUMERIC(19, 19) is supported**** + +Testing numeric(38, 1): +Testing as SQLSRV_PARAM_OUT: +****Conversion from numeric(38, 1) to output SQLSRV_SQLTYPE_DECIMAL(38, 1) is supported**** +****Conversion from numeric(38, 1) to output SQLSRV_SQLTYPE_NUMERIC(38, 1) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from numeric(38, 1) to output SQLSRV_SQLTYPE_DECIMAL(38, 1) is supported**** +****Conversion from numeric(38, 1) to output SQLSRV_SQLTYPE_NUMERIC(38, 1) is supported**** + +Testing numeric(38, 4): +Testing as SQLSRV_PARAM_OUT: +****Conversion from numeric(38, 4) to output SQLSRV_SQLTYPE_DECIMAL(38, 4) is supported**** +****Conversion from numeric(38, 4) to output SQLSRV_SQLTYPE_NUMERIC(38, 4) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from numeric(38, 4) to output SQLSRV_SQLTYPE_DECIMAL(38, 4) is supported**** +****Conversion from numeric(38, 4) to output SQLSRV_SQLTYPE_NUMERIC(38, 4) is supported**** + +Testing numeric(38, 16): +Testing as SQLSRV_PARAM_OUT: +****Conversion from numeric(38, 16) to output SQLSRV_SQLTYPE_DECIMAL(38, 16) is supported**** +****Conversion from numeric(38, 16) to output SQLSRV_SQLTYPE_NUMERIC(38, 16) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from numeric(38, 16) to output SQLSRV_SQLTYPE_DECIMAL(38, 16) is supported**** +****Conversion from numeric(38, 16) to output SQLSRV_SQLTYPE_NUMERIC(38, 16) is supported**** + +Testing numeric(38, 37): +Testing as SQLSRV_PARAM_OUT: +****Conversion from numeric(38, 37) to output SQLSRV_SQLTYPE_DECIMAL(38, 37) is supported**** +****Conversion from numeric(38, 37) to output SQLSRV_SQLTYPE_NUMERIC(38, 37) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from numeric(38, 37) to output SQLSRV_SQLTYPE_DECIMAL(38, 37) is supported**** +****Conversion from numeric(38, 37) to output SQLSRV_SQLTYPE_NUMERIC(38, 37) is supported**** \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_float_bits.phpt b/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_float_bits.phpt new file mode 100644 index 00000000..54a90bfe --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_float_bits.phpt @@ -0,0 +1,125 @@ +--TEST-- +Test for retrieving encrypted data of float types with different number of bits as output parameters +--DESCRIPTION-- +Test implicit conversions between different number of bits +With Always Encrypted, implicit conversion works if: +1. From a float(m) column to a SQLSRV_SQLTYPE_FLOAT output parameter where m > 24 +Without Always Encrypted, implicit conversion between different number of bits works +--SKIPIF-- + +--FILE-- +colName => $inputValues[0], $colMetaArr[1]->colName => $inputValues[1])); + + // create a stored procedure and sql string for calling the stored procedure + $spname = 'selectAllColumns'; + createProc($conn, $spname, "@c_det $typeFull OUTPUT, @c_rand $typeFull OUTPUT", "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname"); + $sql = AE\getCallProcSqlPlaceholders($spname, 2); + + // retrieve by specifying SQLSRV_SQLTYPE_FLOAT as SQLSRV_PARAM_OUT or SQLSRV_PARAM_INOUT + foreach ($directions as $dir) { + echo "Testing as $dir:\n"; + + $c_detOut = 0.0; + $c_randOut = 0.0; + $stmt = sqlsrv_prepare($conn, $sql, array(array(&$c_detOut, constant($dir), null, constant($sqlType)), array(&$c_randOut, constant($dir), null, constant($sqlType)))); + $r = sqlsrv_execute($stmt); + + // check the case when the column number of bits is less than 25 + // when the number of bits is between 1 and 24, it corresponds to a storage size of 4 bytes + // when the number of bits is between 25 and 53, it corresponds to a storage size of 8 bytes + // with AE: should not work because SQLSRV_SQLTYPE_FLOAT maps to float(53) and conversion from a larger float to a smaller float is not supported + // without AE: should work + if ($m < 25) { + if (AE\isDataEncrypted()) { + if ($r !== false) { + echo "AE: Conversion between $typeFull to output $sqlType should not be supported\n"; + } else { + if (sqlsrv_errors()[0]['SQLSTATE'] != "22018") { + echo "AE: Conversion from $typeFull to output $sqlType expects an operand type clash error, actual error is incorrect\n"; + var_dump(sqlsrv_errors()); + } else { + echo "Test successfully done\n"; + } + } + } else { + if ($r === false) { + echo "Conversion from $typeFull to output $sqlType should be supported\n"; + } else { + if (abs($c_detOut - $inputValues[0]) > $epsilon || abs($c_randOut - $inputValues[1]) > $epsilon) { + echo "Conversion from $typeFull to output $sqlType causes data corruption\n"; + } else { + echo "Test successfully done\n"; + } + } + } + // check the case when the column number of bits 25 or more + // should work with or without AE + } else { + if ($r === false) { + echo "Conversion from $typeFull to output $sqlType should be supported\n"; + } else { + if (abs($c_detOut - $inputValues[0]) < $epsilon && abs($c_randOut - $inputValues[1]) < $epsilon) { + echo "****Conversion from $typeFull to output $sqlType is supported****\n"; + } else { + echo "Conversion from $typeFull to output $sqlType causes data corruption\n"; + } + } + } + // cleanup + sqlsrv_free_stmt($stmt); + } + dropProc($conn, $spname); + dropTable($conn, $tbname); +} +sqlsrv_close($conn); + +?> +--EXPECT-- +Testing float(1): +Testing as SQLSRV_PARAM_OUT: +Test successfully done +Testing as SQLSRV_PARAM_INOUT: +Test successfully done + +Testing float(12): +Testing as SQLSRV_PARAM_OUT: +Test successfully done +Testing as SQLSRV_PARAM_INOUT: +Test successfully done + +Testing float(24): +Testing as SQLSRV_PARAM_OUT: +Test successfully done +Testing as SQLSRV_PARAM_INOUT: +Test successfully done + +Testing float(36): +Testing as SQLSRV_PARAM_OUT: +****Conversion from float(36) to output SQLSRV_SQLTYPE_FLOAT is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from float(36) to output SQLSRV_SQLTYPE_FLOAT is supported**** + +Testing float(53): +Testing as SQLSRV_PARAM_OUT: +****Conversion from float(53) to output SQLSRV_SQLTYPE_FLOAT is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from float(53) to output SQLSRV_SQLTYPE_FLOAT is supported**** \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_int_conv.phpt b/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_int_conv.phpt new file mode 100644 index 00000000..a8bfb2ea --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_int_conv.phpt @@ -0,0 +1,113 @@ +--TEST-- +Test for retrieving encrypted data of int types as output parameters +--DESCRIPTION-- +Test implicit conversions between different integer types +With Always Encrypted, implicit conversion works if the column type and the SQLSRV_SQLTYPE are the same +Without AlwaysEncrypted, implicit conversion between different integer types works +--SKIPIF-- + +--FILE-- +colName => $inputValues[0], $colMetaArr[1]->colName => $inputValues[1])); + + // create a stored procedure and sql string for calling the stored procedure + $spname = 'selectAllColumns'; + createProc($conn, $spname, "@c_det $dataType OUTPUT, @c_rand $dataType OUTPUT", "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname"); + $sql = AE\getCallProcSqlPlaceholders($spname, 2); + + // retrieve by specifying different SQLSRV_SQLTYPE ingeter constants as SQLSRV_PARAM_OUT or SQLSRV_PARAM_INOUT + foreach ($directions as $dir) { + echo "Testing as $dir:\n"; + foreach ($sqlTypes as $sqlType) { + $c_detOut = 0; + $c_randOut = 0; + $stmt = sqlsrv_prepare($conn, $sql, array(array(&$c_detOut, constant($dir), null, constant($sqlType)), array(&$c_randOut, constant($dir), null, constant($sqlType)))); + $r = sqlsrv_execute($stmt); + + // check the case if the column type is not the same as the SQLSRV_SQLTYPE + if ($sqlType != "SQLSRV_SQLTYPE_" . strtoupper($dataType)) { + if (AE\isDataEncrypted()) { + if ($r !== false) { + echo "AE: Conversion from $dataType to output $sqlType should not be supported\n"; + } else { + if (sqlsrv_errors()[0]['SQLSTATE'] != "22018") { + echo "AE: Conversion from $dataType to output $sqlType expects an operand type clash error, actual error is incorrect\n"; + var_dump(sqlsrv_errors()); + } + } + } else { + if ($r === false) { + echo "Conversion from $dataType to output $sqlType should be supported\n"; + } else { + if ($c_detOut != $inputValues[0] || $c_randOut != $inputValues[1]) { + echo "Conversion from $dataType to output $sqlType causes data corruption\n"; + } + } + } + // check the case if the column type is the same as the SQLSRV_SQLTYPE + } else { + if ($r === false) { + echo "Conversion from $dataType to output $sqlType should be supported\n"; + } else { + if ($c_detOut == $inputValues[0] && $c_randOut == $inputValues[1]) { + echo "****Conversion from $dataType to output $sqlType is supported****\n"; + } else { + echo "Conversion from $dataType to output $sqlType causes data corruption\n"; + } + } + } + // cleanup + sqlsrv_free_stmt($stmt); + } + } + dropProc($conn, $spname); + dropTable($conn, $tbname); +} +sqlsrv_close($conn); + +?> +--EXPECT-- +Testing bit: +Testing as SQLSRV_PARAM_OUT: +****Conversion from bit to output SQLSRV_SQLTYPE_BIT is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from bit to output SQLSRV_SQLTYPE_BIT is supported**** + +Testing tinyint: +Testing as SQLSRV_PARAM_OUT: +****Conversion from tinyint to output SQLSRV_SQLTYPE_TINYINT is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from tinyint to output SQLSRV_SQLTYPE_TINYINT is supported**** + +Testing smallint: +Testing as SQLSRV_PARAM_OUT: +****Conversion from smallint to output SQLSRV_SQLTYPE_SMALLINT is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from smallint to output SQLSRV_SQLTYPE_SMALLINT is supported**** + +Testing int: +Testing as SQLSRV_PARAM_OUT: +****Conversion from int to output SQLSRV_SQLTYPE_INT is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from int to output SQLSRV_SQLTYPE_INT is supported**** + +Testing bigint: +Testing as SQLSRV_PARAM_OUT: +****Conversion from bigint to output SQLSRV_SQLTYPE_BIGINT is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from bigint to output SQLSRV_SQLTYPE_BIGINT is supported**** \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_nchar_size.phpt b/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_nchar_size.phpt new file mode 100644 index 00000000..9efc3cc9 --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_nchar_size.phpt @@ -0,0 +1,273 @@ +--TEST-- +Test for retrieving encrypted data of nchar types with different sizes as output parameters +--DESCRIPTION-- +Test implicit conversions between different nchar types of different sizes +With Always Encrypted, implicit conversion works if: +1. From a nchar(m) column to a SQLSRV_SQLTYPE_NCHAR(n) output parameter where m == n +2. From a nchar(m) column to a SQLSRV_SQLTYPE_NVARCHAR(n) output parameter where m == n +3. From a nvarchar(m) column to a SQLSRV_SQLTYPE_NCHAR(n) output parameter where m == n +4. From a nvarchar(m) column to a SQLSRV_SQLTYPE_NVARCHAR(n) output parameter where m == n +Without AlwaysEncrypted, implicit conversion works if: +1. From a nchar(m) column to a SQLSRV_SQLTYPE_NCHAR(n) output parameter where m, n == any value +2. From a nchar(m) column to a SQLSRV_SQLTYPE_NVARCHAR(n) output parameter where m <= n (exclude SQLSRV_SQLTYPE_NVARCHAR('max')) +3. From a nvarchar(m) column to a SQLSRV_SQLTYPE_NCHAR(n) output parameter where m, n == any value +4. From a nvarchar(m) column to a SQLSRV_SQLTYPE_NVARCHAR(n) output parameter where m, n == any value +--SKIPIF-- + +--FILE-- +colName => $inputValue)); + + // create a stored procedure and sql string for calling the stored procedure + $spname = 'selectAllColumns'; + createProc($conn, $spname, "@c1 $typeFull OUTPUT", "SELECT @c1 = c1 FROM $tbname"); + $sql = AE\getCallProcSqlPlaceholders($spname, 1); + + // retrieve by specifying SQLSRV_SQLTYPE_NCHAR(n) or SQLSRV_SQLTYPE_NVARCHAR(n) as SQLSRV_PARAM_OUT or SQLSRV_PARAM_INOUT + foreach ($directions as $dir) { + echo "Testing as $dir:\n"; + foreach ($sqlTypes as $sqlType) { + $maxsqltype = strpos($sqlType, "max"); + foreach ($sqltypeLengths as $n) { + $sqltypeconst; + $sqltypeFull; + if ($maxsqltype) { + $sqltypeconst = SQLSRV_SQLTYPE_NVARCHAR('max'); + $sqltypeFull = $sqlType; + } else { + $sqltypeconst = call_user_func($sqlType, $n); + $sqltypeFull = "$sqlType($n)"; + } + + $c1 = ''; + $stmt = sqlsrv_prepare($conn, $sql, array(array(&$c1, constant($dir), null, $sqltypeconst))); + $r = sqlsrv_execute($stmt); + + // check the case when SQLSRV_SQLTYPE length (n) is not the same as the column length (m) + // with AE: should not work + // without AE: should work, except when a SQLSRV_SQLTYPE_NVARCHAR length (n) is less than a nchar column length (m) + if (($n != $m || $maxsqltype || $maxcol) && !($maxcol && $maxsqltype)) { + if (AE\isDataEncrypted()) { + if ($r !== false) { + echo "AE: Conversion from $typeFull to output $sqltypeFull should not be supported\n"; + } else { + if (sqlsrv_errors()[0]['SQLSTATE'] != "22018") { + echo "AE: Conversion from $typeFull to output $sqltypeFull expects an operand type clash error, actual error is incorrect\n"; + var_dump(sqlsrv_errors()); + } + } + } else { + if (!AE\isColEncrypted() && strpos($sqltypeFull, "NVARCHAR") !== false && $dataType == "nchar" && $m > $n && strpos($sqltypeFull, "max") === false && $dir == "SQLSRV_PARAM_OUT") { + if ($r !== false) { + echo "Conversions from $typeFull to output $sqltypeFull should not be supported\n"; + } + } else { + if ($r === false) { + if (strpos($sqltypeFull, "NVARCHAR") !== false || $dataType != "nchar" || $m <= $n) { + echo "Conversions from $typeFull to output $sqltypeFull should be supported\n"; + } + } + if (trim($c1) != $inputValue) { + echo "Conversion from $typeFull to output $sqltypeFull causes data corruption\n"; + } + } + } + // check the case then SQLSRV_SQLTYPE length (n) is the same as the column length (m) + // should work with AE or non AE + } else { + if ($r === false) { + echo "Conversion from $typeFull to output $sqltypeFull should be supported\n"; + } else { + if (trim($c1) == $inputValue) { + echo "****Conversion from $typeFull to output $sqltypeFull is supported****\n"; + } else { + echo "Conversion from $typeFull to output $sqltypeFull causes data corruption\n"; + } + } + } + // cleanup + sqlsrv_free_stmt($stmt); + } + } + } + dropProc($conn, $spname); + dropTable($conn, $tbname); + } +} +sqlsrv_close($conn); + +?> +--EXPECT-- +Testing nchar(1): +Testing as SQLSRV_PARAM_OUT: +****Conversion from nchar(1) to output SQLSRV_SQLTYPE_NCHAR(1) is supported**** +****Conversion from nchar(1) to output SQLSRV_SQLTYPE_NVARCHAR(1) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from nchar(1) to output SQLSRV_SQLTYPE_NCHAR(1) is supported**** +****Conversion from nchar(1) to output SQLSRV_SQLTYPE_NVARCHAR(1) is supported**** + +Testing nchar(8): +Testing as SQLSRV_PARAM_OUT: +****Conversion from nchar(8) to output SQLSRV_SQLTYPE_NCHAR(8) is supported**** +****Conversion from nchar(8) to output SQLSRV_SQLTYPE_NVARCHAR(8) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from nchar(8) to output SQLSRV_SQLTYPE_NCHAR(8) is supported**** +****Conversion from nchar(8) to output SQLSRV_SQLTYPE_NVARCHAR(8) is supported**** + +Testing nchar(64): +Testing as SQLSRV_PARAM_OUT: +****Conversion from nchar(64) to output SQLSRV_SQLTYPE_NCHAR(64) is supported**** +****Conversion from nchar(64) to output SQLSRV_SQLTYPE_NVARCHAR(64) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from nchar(64) to output SQLSRV_SQLTYPE_NCHAR(64) is supported**** +****Conversion from nchar(64) to output SQLSRV_SQLTYPE_NVARCHAR(64) is supported**** + +Testing nchar(512): +Testing as SQLSRV_PARAM_OUT: +****Conversion from nchar(512) to output SQLSRV_SQLTYPE_NCHAR(512) is supported**** +****Conversion from nchar(512) to output SQLSRV_SQLTYPE_NVARCHAR(512) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from nchar(512) to output SQLSRV_SQLTYPE_NCHAR(512) is supported**** +****Conversion from nchar(512) to output SQLSRV_SQLTYPE_NVARCHAR(512) is supported**** + +Testing nchar(4000): +Testing as SQLSRV_PARAM_OUT: +****Conversion from nchar(4000) to output SQLSRV_SQLTYPE_NCHAR(4000) is supported**** +****Conversion from nchar(4000) to output SQLSRV_SQLTYPE_NVARCHAR(4000) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from nchar(4000) to output SQLSRV_SQLTYPE_NCHAR(4000) is supported**** +****Conversion from nchar(4000) to output SQLSRV_SQLTYPE_NVARCHAR(4000) is supported**** + +Testing nvarchar(1): +Testing as SQLSRV_PARAM_OUT: +****Conversion from nvarchar(1) to output SQLSRV_SQLTYPE_NCHAR(1) is supported**** +****Conversion from nvarchar(1) to output SQLSRV_SQLTYPE_NVARCHAR(1) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from nvarchar(1) to output SQLSRV_SQLTYPE_NCHAR(1) is supported**** +****Conversion from nvarchar(1) to output SQLSRV_SQLTYPE_NVARCHAR(1) is supported**** + +Testing nvarchar(8): +Testing as SQLSRV_PARAM_OUT: +****Conversion from nvarchar(8) to output SQLSRV_SQLTYPE_NCHAR(8) is supported**** +****Conversion from nvarchar(8) to output SQLSRV_SQLTYPE_NVARCHAR(8) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from nvarchar(8) to output SQLSRV_SQLTYPE_NCHAR(8) is supported**** +****Conversion from nvarchar(8) to output SQLSRV_SQLTYPE_NVARCHAR(8) is supported**** + +Testing nvarchar(64): +Testing as SQLSRV_PARAM_OUT: +****Conversion from nvarchar(64) to output SQLSRV_SQLTYPE_NCHAR(64) is supported**** +****Conversion from nvarchar(64) to output SQLSRV_SQLTYPE_NVARCHAR(64) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from nvarchar(64) to output SQLSRV_SQLTYPE_NCHAR(64) is supported**** +****Conversion from nvarchar(64) to output SQLSRV_SQLTYPE_NVARCHAR(64) is supported**** + +Testing nvarchar(512): +Testing as SQLSRV_PARAM_OUT: +****Conversion from nvarchar(512) to output SQLSRV_SQLTYPE_NCHAR(512) is supported**** +****Conversion from nvarchar(512) to output SQLSRV_SQLTYPE_NVARCHAR(512) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from nvarchar(512) to output SQLSRV_SQLTYPE_NCHAR(512) is supported**** +****Conversion from nvarchar(512) to output SQLSRV_SQLTYPE_NVARCHAR(512) is supported**** + +Testing nvarchar(4000): +Testing as SQLSRV_PARAM_OUT: +****Conversion from nvarchar(4000) to output SQLSRV_SQLTYPE_NCHAR(4000) is supported**** +****Conversion from nvarchar(4000) to output SQLSRV_SQLTYPE_NVARCHAR(4000) is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from nvarchar(4000) to output SQLSRV_SQLTYPE_NCHAR(4000) is supported**** +****Conversion from nvarchar(4000) to output SQLSRV_SQLTYPE_NVARCHAR(4000) is supported**** + +Testing nvarchar(max): +Testing as SQLSRV_PARAM_OUT: +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** + +Testing nvarchar(max): +Testing as SQLSRV_PARAM_OUT: +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** + +Testing nvarchar(max): +Testing as SQLSRV_PARAM_OUT: +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** + +Testing nvarchar(max): +Testing as SQLSRV_PARAM_OUT: +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** + +Testing nvarchar(max): +Testing as SQLSRV_PARAM_OUT: +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +Testing as SQLSRV_PARAM_INOUT: +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** +****Conversion from nvarchar(max) to output SQLSRV_SQLTYPE_NVARCHAR('max') is supported**** \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_numeric.phpt b/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_numeric.phpt new file mode 100755 index 00000000..25d7d15f --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_numeric.phpt @@ -0,0 +1,190 @@ +--TEST-- +Test for inserting and retrieving encrypted data of numeric types +--DESCRIPTION-- +Bind output params using sqlsrv_prepare with all sql_type +--SKIPIF-- + +--FILE-- + array( "SQLSRV_SQLTYPE_BINARY", "SQLSRV_SQLTYPE_VARBINARY", "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DECIMAL(18,5)", "SQLSRV_SQLTYPE_NUMERIC(10,5)", "SQLSRV_SQLTYPE_FLOAT", "SQLSRV_SQLTYPE_REAL", "SQLSRV_SQLTYPE_BIGINT", "SQLSRV_SQLTYPE_INT", "SQLSRV_SQLTYPE_SMALLINT", "SQLSRV_SQLTYPE_TINYINT", "SQLSRV_SQLTYPE_MONEY", "SQLSRV_SQLTYPE_SMALLMONEY", "SQLSRV_SQLTYPE_BIT", "SQLSRV_SQLTYPE_TIMESTAMP"), + "tinyint" => array( "SQLSRV_SQLTYPE_BINARY", "SQLSRV_SQLTYPE_VARBINARY", "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DECIMAL(18,5)", "SQLSRV_SQLTYPE_NUMERIC(10,5)", "SQLSRV_SQLTYPE_FLOAT", "SQLSRV_SQLTYPE_REAL", "SQLSRV_SQLTYPE_BIGINT", "SQLSRV_SQLTYPE_INT", "SQLSRV_SQLTYPE_SMALLINT", "SQLSRV_SQLTYPE_TINYINT", "SQLSRV_SQLTYPE_MONEY", "SQLSRV_SQLTYPE_SMALLMONEY", "SQLSRV_SQLTYPE_BIT", "SQLSRV_SQLTYPE_TIMESTAMP"), + "smallint" => array( "SQLSRV_SQLTYPE_BINARY", "SQLSRV_SQLTYPE_VARBINARY", "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DECIMAL(18,5)", "SQLSRV_SQLTYPE_NUMERIC(10,5)", "SQLSRV_SQLTYPE_FLOAT", "SQLSRV_SQLTYPE_REAL", "SQLSRV_SQLTYPE_BIGINT", "SQLSRV_SQLTYPE_INT", "SQLSRV_SQLTYPE_SMALLINT", "SQLSRV_SQLTYPE_TINYINT", "SQLSRV_SQLTYPE_MONEY", "SQLSRV_SQLTYPE_SMALLMONEY", "SQLSRV_SQLTYPE_BIT", "SQLSRV_SQLTYPE_TIMESTAMP"), + "int" => array( "SQLSRV_SQLTYPE_BINARY", "SQLSRV_SQLTYPE_VARBINARY", "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DECIMAL(18,5)", "SQLSRV_SQLTYPE_NUMERIC(10,5)", "SQLSRV_SQLTYPE_FLOAT", "SQLSRV_SQLTYPE_REAL", "SQLSRV_SQLTYPE_BIGINT", "SQLSRV_SQLTYPE_INT", "SQLSRV_SQLTYPE_SMALLINT", "SQLSRV_SQLTYPE_TINYINT", "SQLSRV_SQLTYPE_MONEY", "SQLSRV_SQLTYPE_SMALLMONEY", "SQLSRV_SQLTYPE_BIT", "SQLSRV_SQLTYPE_TIMESTAMP"), + "bigint" => array( "SQLSRV_SQLTYPE_BINARY", "SQLSRV_SQLTYPE_VARBINARY", "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DECIMAL(18,5)", "SQLSRV_SQLTYPE_NUMERIC(10,5)", "SQLSRV_SQLTYPE_FLOAT", "SQLSRV_SQLTYPE_REAL", "SQLSRV_SQLTYPE_BIGINT", "SQLSRV_SQLTYPE_INT", "SQLSRV_SQLTYPE_SMALLINT", "SQLSRV_SQLTYPE_TINYINT", "SQLSRV_SQLTYPE_MONEY", "SQLSRV_SQLTYPE_SMALLMONEY", "SQLSRV_SQLTYPE_BIT", "SQLSRV_SQLTYPE_TIMESTAMP" ), + "decimal(18,5)" => array( "SQLSRV_SQLTYPE_BINARY", "SQLSRV_SQLTYPE_VARBINARY", "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DECIMAL(18,5)", "SQLSRV_SQLTYPE_NUMERIC(10,5)", "SQLSRV_SQLTYPE_FLOAT", "SQLSRV_SQLTYPE_REAL", "SQLSRV_SQLTYPE_BIGINT", "SQLSRV_SQLTYPE_INT", "SQLSRV_SQLTYPE_SMALLINT", "SQLSRV_SQLTYPE_TINYINT", "SQLSRV_SQLTYPE_MONEY", "SQLSRV_SQLTYPE_SMALLMONEY", "SQLSRV_SQLTYPE_BIT", "SQLSRV_SQLTYPE_TIMESTAMP"), + "numeric(10,5)" => array( "SQLSRV_SQLTYPE_BINARY", "SQLSRV_SQLTYPE_VARBINARY", "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DECIMAL(18,5)", "SQLSRV_SQLTYPE_NUMERIC(10,5)", "SQLSRV_SQLTYPE_FLOAT", "SQLSRV_SQLTYPE_REAL", "SQLSRV_SQLTYPE_BIGINT", "SQLSRV_SQLTYPE_INT", "SQLSRV_SQLTYPE_SMALLINT", "SQLSRV_SQLTYPE_TINYINT", "SQLSRV_SQLTYPE_MONEY", "SQLSRV_SQLTYPE_SMALLMONEY", "SQLSRV_SQLTYPE_BIT", "SQLSRV_SQLTYPE_TIMESTAMP"), + "float" => array( "SQLSRV_SQLTYPE_BINARY", "SQLSRV_SQLTYPE_VARBINARY", "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DECIMAL(18,5)", "SQLSRV_SQLTYPE_NUMERIC(10,5)", "SQLSRV_SQLTYPE_FLOAT", "SQLSRV_SQLTYPE_REAL", "SQLSRV_SQLTYPE_BIGINT", "SQLSRV_SQLTYPE_INT", "SQLSRV_SQLTYPE_SMALLINT", "SQLSRV_SQLTYPE_TINYINT", "SQLSRV_SQLTYPE_MONEY", "SQLSRV_SQLTYPE_SMALLMONEY", "SQLSRV_SQLTYPE_BIT"), + "real" => array( "SQLSRV_SQLTYPE_BINARY", "SQLSRV_SQLTYPE_VARBINARY", "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DECIMAL(18,5)", "SQLSRV_SQLTYPE_NUMERIC(10,5)", "SQLSRV_SQLTYPE_FLOAT", "SQLSRV_SQLTYPE_REAL", "SQLSRV_SQLTYPE_BIGINT", "SQLSRV_SQLTYPE_INT", "SQLSRV_SQLTYPE_SMALLINT", "SQLSRV_SQLTYPE_TINYINT", "SQLSRV_SQLTYPE_MONEY", "SQLSRV_SQLTYPE_SMALLMONEY", "SQLSRV_SQLTYPE_BIT")); +$epsilon = 0.0001; + +$conn = AE\connect(); + +foreach ($dataTypes as $dataType) { + echo "\nTesting $dataType:\n"; + $success = true; + + // create table + $tbname = GetTempTableName("", false); + $colMetaArr = array(new AE\ColumnMeta($dataType, "c_det"), new AE\ColumnMeta($dataType, "c_rand", null, false)); + AE\createTable($conn, $tbname, $colMetaArr); + + // TODO: It's a good idea to test conversions between different datatypes when AE is off as well. + if (AE\isColEncrypted()) { + // Create a Store Procedure + $spname = 'selectAllColumns'; + createProc($conn, $spname, "@c_det $dataType OUTPUT, @c_rand $dataType OUTPUT", "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname"); + } + + // insert a row + $inputValues = array_slice(${explode("(", $dataType)[0] . "_params"}, 1, 2); + $r; + // convert input values to strings for decimals and numerics + if ($dataTypes == "decimal(18,5)" || $dataTypes == "numeric(10,5)") { + $stmt = AE\insertRow($conn, $tbname, array( $colMetaArr[0]->colName => (string) $inputValues[0], $colMetaArr[1]->colName => (string) $inputValues[1] ), $r); + } else { + $stmt = AE\insertRow($conn, $tbname, array( $colMetaArr[0]->colName => $inputValues[0], $colMetaArr[1]->colName => $inputValues[1] ), $r); + } + if ($r === false) { + is_incompatible_types_error($dataType, "default type"); + } + + foreach($directions as $direction) { + echo "Testing as $direction:\n"; + + // test each SQLSRV_SQLTYPE_ constants + foreach ($sqlTypes as $sqlType) { + + if (!AE\isColEncrypted()) { + $isCompatible = false; + foreach ($compatList[$dataType] as $compatType) { + if (stripos($compatType, $sqlType) !== false) { + $isCompatible = true; + } + } + // 22018 is the SQLSTATE for any incompatible conversion errors + if ($isCompatible && sqlsrv_errors()[0]['SQLSTATE'] == 22018) { + echo "$sqlType should be compatible with $dataType\n"; + $success = false; + } + } else { + // skip unsupported datetime types + if (!isDateTimeType($sqlType)) { + $sqlTypeConstant = get_sqlType_constant($sqlType); + + // Call store procedure + $outSql = AE\getCallProcSqlPlaceholders($spname, 2); + if ($sqlType == 'SQLSRV_SQLTYPE_FLOAT' || $sqlType == 'SQLSRV_SQLTYPE_REAL') { + $c_detOut = 0.0; + $c_randOut = 0.0; + } else { + $c_detOut = 0; + $c_randOut = 0; + } + $stmt = sqlsrv_prepare($conn, $outSql, + array(array( &$c_detOut, constant($direction), null, $sqlTypeConstant), + array(&$c_randOut, constant($direction), null, $sqlTypeConstant))); + + if (!$stmt) { + die(print_r(sqlsrv_errors(), true)); + } + sqlsrv_execute($stmt); + $errors = sqlsrv_errors(); + + if (!empty($errors)) { + if (stripos("SQLSRV_SQLTYPE_" . $dataType, $sqlType) !== false) { + var_dump(sqlsrv_errors()); + $success = false; + } + } + else { + if (AE\IsDataEncrypted() || stripos("SQLSRV_SQLTYPE_" . $dataType, $sqlType) !== false) { + if ($dataType == "float" || $dataType == "real") { + if (abs($c_detOut - $inputValues[0]) > $epsilon || abs($c_randOut - $inputValues[1]) > $epsilon) { + echo "Incorrect output retrieved for datatype $dataType and sqlType $sqlType:\n"; + print(" c_det: " . $c_detOut . "\n"); + print(" c_rand: " . $c_randOut . "\n"); + $success = false; + } + } else { + if ($c_detOut != $inputValues[0] || $c_randOut != $inputValues[1]) { + echo "Incorrect output retrieved for datatype $dataType and sqlType $sqlType:\n"; + print(" c_det: " . $c_detOut . "\n"); + print(" c_rand: " . $c_randOut . "\n"); + $success = false; + } + } + } + } + + sqlsrv_free_stmt($stmt); + } + } + } + } + + if (AE\isColEncrypted()) { + dropProc($conn, $spname); + } + + if ($success) { + echo "Test successfully done.\n"; + } + + dropTable($conn, $tbname); +} + +sqlsrv_close($conn); +?> +--EXPECT-- + +Testing bit: +Testing as SQLSRV_PARAM_OUT: +Testing as SQLSRV_PARAM_INOUT: +Test successfully done. + +Testing tinyint: +Testing as SQLSRV_PARAM_OUT: +Testing as SQLSRV_PARAM_INOUT: +Test successfully done. + +Testing smallint: +Testing as SQLSRV_PARAM_OUT: +Testing as SQLSRV_PARAM_INOUT: +Test successfully done. + +Testing int: +Testing as SQLSRV_PARAM_OUT: +Testing as SQLSRV_PARAM_INOUT: +Test successfully done. + +Testing bigint: +Testing as SQLSRV_PARAM_OUT: +Testing as SQLSRV_PARAM_INOUT: +Test successfully done. + +Testing decimal(18,5): +Testing as SQLSRV_PARAM_OUT: +Testing as SQLSRV_PARAM_INOUT: +Test successfully done. + +Testing numeric(10,5): +Testing as SQLSRV_PARAM_OUT: +Testing as SQLSRV_PARAM_INOUT: +Test successfully done. + +Testing float: +Testing as SQLSRV_PARAM_OUT: +Testing as SQLSRV_PARAM_INOUT: +Test successfully done. + +Testing real: +Testing as SQLSRV_PARAM_OUT: +Testing as SQLSRV_PARAM_INOUT: +Test successfully done. diff --git a/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_string.phpt b/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_string.phpt new file mode 100755 index 00000000..77d53147 --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_ae_output_param_sqltype_string.phpt @@ -0,0 +1,139 @@ +--TEST-- +Test for inserting and retrieving encrypted data of string types +--DESCRIPTION-- +Bind output params using sqlsrv_prepare with all sql_type +--SKIPIF-- + +--FILE-- + array( "SQLSRV_SQLTYPE_CHAR(5)", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR(5)", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DECIMAL", "SQLSRV_SQLTYPE_NUMERIC", "SQLSRV_SQLTYPE_NTEXT", "SQLSRV_SQLTYPE_TEXT", "SQLSRV_SQLTYPE_XML"), + "varchar(max)" => array( "SQLSRV_SQLTYPE_CHAR(5)", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR(5)", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DECIMAL", "SQLSRV_SQLTYPE_NUMERIC", "SQLSRV_SQLTYPE_NTEXT", "SQLSRV_SQLTYPE_TEXT", "SQLSRV_SQLTYPE_XML"), + "nchar(5)" => array( "SQLSRV_SQLTYPE_CHAR(5)", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR(5)", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DECIMAL", "SQLSRV_SQLTYPE_NUMERIC", "SQLSRV_SQLTYPE_NTEXT", "SQLSRV_SQLTYPE_TEXT", "SQLSRV_SQLTYPE_XML"), + "nvarchar(max)" => array( "SQLSRV_SQLTYPE_CHAR(5)", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR(5)", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DECIMAL", "SQLSRV_SQLTYPE_NUMERIC", "SQLSRV_SQLTYPE_NTEXT", "SQLSRV_SQLTYPE_TEXT", "SQLSRV_SQLTYPE_XML")); + +$conn = AE\connect(); + +foreach ($dataTypes as $dataType) { + echo "\nTesting $dataType:\n"; + $success = true; + + // create table + $tbname = GetTempTableName("", false); + $colMetaArr = array(new AE\ColumnMeta($dataType, "c_det"), new AE\ColumnMeta($dataType, "c_rand", null, false)); + AE\createTable($conn, $tbname, $colMetaArr); + + // TODO: It's a good idea to test conversions between different datatypes when AE is off as well. + if (AE\isColEncrypted()) { + // Create a Store Procedure + $spname = 'selectAllColumns'; + createProc($conn, $spname, "@c_det $dataType OUTPUT, @c_rand $dataType OUTPUT", "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname"); + } + + // insert a row + $inputValues = array_slice(${explode("(", $dataType)[0] . "_params"}, 1, 2); + $r; + $stmt = AE\insertRow($conn, $tbname, array( $colMetaArr[0]->colName => $inputValues[0], $colMetaArr[1]->colName => $inputValues[1] ), $r); + if ($r === false) { + is_incompatible_types_error($dataType, "default type"); + } + + foreach($directions as $direction) { + echo "Testing as $direction:\n"; + + // test each SQLSRV_SQLTYPE_ constants + foreach ($sqlTypes as $sqlType) { + if (!AE\isColEncrypted()) { + $isCompatible = false; + foreach ($compatList[$dataType] as $compatType) { + if (stripos($compatType, $sqlType) !== false) { + $isCompatible = true; + } + } + // 22018 is the SQLSTATE for any incompatible conversion errors + if ($isCompatible && sqlsrv_errors()[0]['SQLSTATE'] == 22018) { + echo "$sqlType should be compatible with $dataType\n"; + $success = false; + } + } else { + // skip unsupported datetime types + if (!isDateTimeType($sqlType)) { + $sqlTypeConstant = get_sqlType_constant($sqlType); + + // Call store procedure + $outSql = AE\getCallProcSqlPlaceholders($spname, 2); + $c_detOut = ''; + $c_randOut = ''; + $stmt = sqlsrv_prepare($conn, $outSql, + array(array(&$c_detOut, SQLSRV_PARAM_INOUT, null, $sqlTypeConstant), + array(&$c_randOut, SQLSRV_PARAM_INOUT, null, $sqlTypeConstant))); + + if (!$stmt) { + die(print_r(sqlsrv_errors(), true)); + } + + sqlsrv_execute($stmt); + $errors = sqlsrv_errors(); + + if (!empty($errors) ) { + if (stripos("SQLSRV_SQLTYPE_" . $dataType, $sqlType) !== false) { + var_dump(sqlsrv_errors()); + $success = false; + } + } + else + { + if (AE\IsDataEncrypted() || stripos("SQLSRV_SQLTYPE_" . $dataType, $sqlType) !== false) { + if ($c_detOut != $inputValues[0] || $c_randOut != $inputValues[1]) { + echo "Incorrect output retrieved for datatype $dataType and sqlType $sqlType:\n"; + print(" c_det: " . $c_detOut . "\n"); + print(" c_rand: " . $c_randOut . "\n"); + $success = false; + } + } + } + + sqlsrv_free_stmt($stmt); + } + } + } + } + + if (AE\isColEncrypted()) { + dropProc($conn, $spname); + } + if ($success) { + echo "Test successfully done.\n"; + } + dropTable($conn, $tbname); +} + +sqlsrv_close($conn); +?> +--EXPECT-- + +Testing char(5): +Testing as SQLSRV_PARAM_OUT: +Testing as SQLSRV_PARAM_INOUT: +Test successfully done. + +Testing varchar(max): +Testing as SQLSRV_PARAM_OUT: +Testing as SQLSRV_PARAM_INOUT: +Test successfully done. + +Testing nchar(5): +Testing as SQLSRV_PARAM_OUT: +Testing as SQLSRV_PARAM_INOUT: +Test successfully done. + +Testing nvarchar(max): +Testing as SQLSRV_PARAM_OUT: +Testing as SQLSRV_PARAM_INOUT: +Test successfully done. diff --git a/test/functional/sqlsrv/sqlsrv_client_info.phpt b/test/functional/sqlsrv/sqlsrv_client_info.phpt index 1b8f7b31..bfcc2d0e 100644 --- a/test/functional/sqlsrv/sqlsrv_client_info.phpt +++ b/test/functional/sqlsrv/sqlsrv_client_info.phpt @@ -15,7 +15,7 @@ var_dump( $client_info ); --EXPECTREGEX-- array\(4\) { \[\"(DriverDllName|DriverName)\"\]=> - (string\(15\) \"msodbcsql1[1-9].dll\"|string\(24\) \"libmsodbcsql-[1-9]{2}.[0-9].so.[0-9].[0-9]\") + (string\([0-9]+\) \"msodbcsql1[1-9].dll\"|string\([0-9]+\) \"(libmsodbcsql-[0-9]{2}\.[0-9]\.so\.[0-9]\.[0-9]|libmsodbcsql.[0-9]{2}.dylib)\") \[\"DriverODBCVer\"\]=> string\(5\) \"[0-9]{1,2}\.[0-9]{1,2}\" \[\"DriverVer\"\]=> diff --git a/test/functional/sqlsrv/sqlsrv_connect_driver.phpt b/test/functional/sqlsrv/sqlsrv_connect_driver.phpt index 89377f1a..4f878bea 100644 --- a/test/functional/sqlsrv/sqlsrv_connect_driver.phpt +++ b/test/functional/sqlsrv/sqlsrv_connect_driver.phpt @@ -1,158 +1,134 @@ ---TEST-- -Test new connection keyword Driver with valid and invalid values ---SKIPIF-- - ---FILE-- -$database, "UID"=>$userName, "PWD"=>$userPassword); -$conn = sqlsrv_connect($server, $connectionOptions); -if ($conn === false) { - print_r(sqlsrv_errors()); -} -$msodbcsqlVer = sqlsrv_client_info($conn)['DriverVer']; -$msodbcsqlMaj = explode(".", $msodbcsqlVer)[0]; -sqlsrv_close($conn); - -// start test -testValidValues($msodbcsqlMaj, $server, $connectionOptions); -testInvalidValues($msodbcsqlMaj, $server, $connectionOptions); -testEncryptedWithODBC($msodbcsqlMaj, $server, $connectionOptions); -testWrongODBC($msodbcsqlMaj, $server, $connectionOptions); -echo "Done"; -// end test - -/////////////////////////// -function connectVerifyOutput($server, $connectionOptions, $expected = '') -{ - $conn = sqlsrv_connect($server, $connectionOptions); - if ($conn === false) { - if (strpos(sqlsrv_errors($conn)[0]['message'], $expected) === false) { - print_r(sqlsrv_errors()); - } - } -} - -function testValidValues($msodbcsqlMaj, $server, $connectionOptions) -{ - $value = ""; - // The major version number of ODBC 11 can be 11 or 12 - // Test with {} - switch ($msodbcsqlMaj) { - case 17: - $value = "{ODBC Driver 17 for SQL Server}"; - break; - case 14: - case 13: - $value = "{ODBC Driver 13 for SQL Server}"; - break; - case 12: - case 11: - $value = "{ODBC Driver 11 for SQL Server}"; - break; - default: - $value = "invalid value $msodbcsqlMaj"; - } - $connectionOptions['Driver']=$value; - connectVerifyOutput($server, $connectionOptions); - - // Test without {} - switch ($msodbcsqlMaj) { - case 17: - $value = "ODBC Driver 17 for SQL Server"; - break; - case 14: - case 13: - $value = "ODBC Driver 13 for SQL Server"; - break; - case 12: - case 11: - $value = "ODBC Driver 11 for SQL Server"; - break; - default: - $value = "invalid value $msodbcsqlMaj"; - } - - $connectionOptions['Driver']=$value; - connectVerifyOutput($server, $connectionOptions); -} - -function testInvalidValues($msodbcsqlMaj, $server, $connectionOptions) -{ - $values = array("{SQL Server Native Client 11.0}", - "SQL Server Native Client 11.0", - "ODBC Driver 00 for SQL Server"); - - foreach ($values as $value) { - $connectionOptions['Driver']=$value; - $expected = "Invalid value $value was specified for Driver option."; - connectVerifyOutput($server, $connectionOptions, $expected); - } - - $values = array(123, false); - - foreach ($values as $value) { - $connectionOptions['Driver']=$value; - $expected = "Invalid value type for option Driver was specified. String type was expected."; - connectVerifyOutput($server, $connectionOptions, $expected); - } -} - -function testEncryptedWithODBC($msodbcsqlMaj, $server, $connectionOptions) -{ - $value = "ODBC Driver 13 for SQL Server"; - $connectionOptions['Driver']=$value; - $connectionOptions['ColumnEncryption']='Enabled'; - - $expected = "The Always Encrypted feature requires Microsoft ODBC Driver 17 for SQL Server."; - - connectVerifyOutput($server, $connectionOptions, $expected); - - // TODO: the following block will change once ODBC 17 is officially released - $value = "ODBC Driver 17 for SQL Server"; - $connectionOptions['Driver']=$value; - $connectionOptions['ColumnEncryption']='Enabled'; - - $success = "Successfully connected with column encryption."; - $expected = "The specified ODBC Driver is not found."; - $message = $success; - - $conn = sqlsrv_connect($server, $connectionOptions); - if ($conn === false) { - $message = sqlsrv_errors($conn)[0]['message']; - } - - if ($msodbcsqlMaj == 17) { - // this indicates that OCBC 17 is the only available driver - if (strcmp($message, $success)) { - print_r($message); - } - } else { - // OCBC 17 might or might not exist - if (strcmp($message, $success)) { - if (strpos($message, $expected) === false) { - print_r($message); - } - } - } -} - -function testWrongODBC($msodbcsqlMaj, $server, $connectionOptions) -{ - // TODO: this will change once ODBC 17 is officially released - $value = "ODBC Driver 17 for SQL Server"; - if ($msodbcsqlMaj == 17 || $msodbcsqlMaj < 13) { - $value = "ODBC Driver 13 for SQL Server"; - } - - $connectionOptions['Driver']=$value; - $expected = "The specified ODBC Driver is not found."; - - connectVerifyOutput($server, $connectionOptions, $expected); -} - -?> ---EXPECT-- -Done +--TEST-- +Test new connection keyword Driver with valid and invalid values +--SKIPIF-- + +--FILE-- +$database, "UID"=>$userName, "PWD"=>$userPassword); +$conn = sqlsrv_connect($server, $connectionOptions); +if ($conn === false) { + print_r(sqlsrv_errors()); +} +$msodbcsqlVer = sqlsrv_client_info($conn)['DriverVer']; +$msodbcsqlMaj = explode(".", $msodbcsqlVer)[0]; +sqlsrv_close($conn); + +// start test +testValidValues($msodbcsqlMaj, $server, $connectionOptions); +testInvalidValues($msodbcsqlMaj, $server, $connectionOptions); +testEncryptedWithODBC($msodbcsqlMaj, $server, $connectionOptions); +testWrongODBC($msodbcsqlMaj, $server, $connectionOptions); +echo "Done"; +// end test + +/////////////////////////// +function connectVerifyOutput($server, $connectionOptions, $expected = '') +{ + $conn = sqlsrv_connect($server, $connectionOptions); + if ($conn === false) { + if (strpos(sqlsrv_errors($conn)[0]['message'], $expected) === false) { + print_r(sqlsrv_errors()); + } + } +} + +function testValidValues($msodbcsqlMaj, $server, $connectionOptions) +{ + $value = ""; + // The major version number of ODBC 11 can be 11 or 12 + // Test with {} + switch ($msodbcsqlMaj) { + case 17: + $value = "{ODBC Driver 17 for SQL Server}"; + break; + case 14: + case 13: + $value = "{ODBC Driver 13 for SQL Server}"; + break; + case 12: + case 11: + $value = "{ODBC Driver 11 for SQL Server}"; + break; + default: + $value = "invalid value $msodbcsqlMaj"; + } + $connectionOptions['Driver']=$value; + connectVerifyOutput($server, $connectionOptions); + + // Test without {} + switch ($msodbcsqlMaj) { + case 17: + $value = "ODBC Driver 17 for SQL Server"; + break; + case 14: + case 13: + $value = "ODBC Driver 13 for SQL Server"; + break; + case 12: + case 11: + $value = "ODBC Driver 11 for SQL Server"; + break; + default: + $value = "invalid value $msodbcsqlMaj"; + } + + $connectionOptions['Driver']=$value; + connectVerifyOutput($server, $connectionOptions); +} + +function testInvalidValues($msodbcsqlMaj, $server, $connectionOptions) +{ + $values = array("{SQL Server Native Client 11.0}", + "SQL Server Native Client 11.0", + "ODBC Driver 00 for SQL Server"); + + foreach ($values as $value) { + $connectionOptions['Driver']=$value; + $expected = "Invalid value $value was specified for Driver option."; + connectVerifyOutput($server, $connectionOptions, $expected); + } + + $values = array(123, false); + + foreach ($values as $value) { + $connectionOptions['Driver']=$value; + $expected = "Invalid value type for option Driver was specified. String type was expected."; + connectVerifyOutput($server, $connectionOptions, $expected); + } +} + +function testEncryptedWithODBC($msodbcsqlMaj, $server, $connectionOptions) +{ + $value = "ODBC Driver 13 for SQL Server"; + $connectionOptions['Driver']=$value; + $connectionOptions['ColumnEncryption']='Enabled'; + + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + $expected = "The Always Encrypted feature requires Microsoft ODBC Driver 17 for SQL Server."; + } else { + $expected = "Invalid option ColumnEncryption was passed to sqlsrv_connect."; + } + + connectVerifyOutput($server, $connectionOptions, $expected); +} + +function testWrongODBC($msodbcsqlMaj, $server, $connectionOptions) +{ + // TODO: this will change once ODBC 17 is officially released + $value = "ODBC Driver 17 for SQL Server"; + if ($msodbcsqlMaj == 17 || $msodbcsqlMaj < 13) { + $value = "ODBC Driver 13 for SQL Server"; + } + + $connectionOptions['Driver']=$value; + $expected = "The specified ODBC Driver is not found."; + + connectVerifyOutput($server, $connectionOptions, $expected); +} + +?> +--EXPECT-- +Done diff --git a/test/functional/sqlsrv/sqlsrv_connect_encrypted.phpt b/test/functional/sqlsrv/sqlsrv_connect_encrypted.phpt index e6a5bbb6..5a39140e 100644 --- a/test/functional/sqlsrv/sqlsrv_connect_encrypted.phpt +++ b/test/functional/sqlsrv/sqlsrv_connect_encrypted.phpt @@ -1,7 +1,7 @@ --TEST-- Test new connection keyword ColumnEncryption --SKIPIF-- - + --FILE-- ---FILE-- -true)); - if ($conn !== false) { - echo "Connected successfully with ColumnEncryption enabled.\n"; - } - - $ksp_test_table = AE\KSP_TEST_TABLE; - $tsql = "SELECT * FROM $ksp_test_table"; - $stmt = sqlsrv_prepare($conn, $tsql); - if (!sqlsrv_execute($stmt)) { - fatalError("Failed to fetch data.\n"); - } - - // fetch data - $id = 0; - while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_NUMERIC)) { - if (!verifyData($row, $id++)) { - break; - } - } - - sqlsrv_free_stmt($stmt); - sqlsrv_close($conn); - - echo "Done\n"; -?> ---EXPECT-- -Connected successfully with ColumnEncryption enabled. -Done diff --git a/test/functional/sqlsrv/sqlsrv_connect_encrypted_ksp_encrypted.phpt b/test/functional/sqlsrv/sqlsrv_connect_encrypted_ksp_encrypted.phpt deleted file mode 100644 index 4a96a8df..00000000 --- a/test/functional/sqlsrv/sqlsrv_connect_encrypted_ksp_encrypted.phpt +++ /dev/null @@ -1,52 +0,0 @@ ---TEST-- -Fetch encrypted data from a prepopulated test table given a custom keystore provider ---SKIPIF-- - ---FILE-- -true)); - if ($conn === false) { - fatalError("Failed to connect.\n"); - } else { - echo "Connected successfully with ColumnEncryption disabled.\n"; - } - - $ksp_test_table = AE\KSP_TEST_TABLE; - $tsql = "SELECT * FROM $ksp_test_table"; - $stmt = sqlsrv_prepare($conn, $tsql); - if (!sqlsrv_execute($stmt)) { - fatalError("Failed to fetch data.\n"); - } - - // fetch data - while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_NUMERIC)) { - // all columns should return binary data except the first column - echo "c1=" . $row[0]; - echo "\tc2=" . bin2hex($row[1]); - echo "\tc3=" . bin2hex($row[2]); - echo "\tc4=" . bin2hex($row[3]); - echo "\n" ; - } - - sqlsrv_free_stmt($stmt); - sqlsrv_close($conn); - - echo "Done\n"; -?> ---EXPECTREGEX-- -Connected successfully with ColumnEncryption disabled. -c1=1 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+ -c1=12 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+ -c1=23 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+ -c1=34 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+ -c1=45 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+ -c1=56 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+ -c1=67 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+ -c1=78 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+ -c1=89 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+ -c1=100 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+ -Done \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_connect_encrypted_ksp_errors.phpt b/test/functional/sqlsrv/sqlsrv_connect_encrypted_ksp_errors.phpt deleted file mode 100644 index 7083d4a3..00000000 --- a/test/functional/sqlsrv/sqlsrv_connect_encrypted_ksp_errors.phpt +++ /dev/null @@ -1,127 +0,0 @@ ---TEST-- -Connect using a custom keystore provider with some required inputs missing ---SKIPIF-- - ---FILE-- - $error) { - if(is_string($key)) { - echo "[$key] => $error\n"; - } - } - echo "\n"; - } else { - echo "Connected successfully with ColumnEncryption enabled.\n"; - } - - return $conn; - } - - sqlsrv_configure('LogSeverity', SQLSRV_LOG_SEVERITY_ALL); - - require_once('MsHelper.inc'); - $ksp_path = AE\getKSPpath(); - $ksp_name = AE\KSP_NAME; - $encrypt_key = AE\ENCRYPT_KEY; - - echo "Connecting... with column encryption\n"; - $connectionInfo = array("Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd, - "ColumnEncryption"=>"enabled"); - - connect($server, $connectionInfo); - - echo "Connecting... with an invalid input to CEKeystoreProvider\n"; - $connectionInfo = array("Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd, - "ColumnEncryption"=>"enabled", - "CEKeystoreProvider"=>1); - - connect($server, $connectionInfo); - - echo "Connecting... with an empty path\n"; - $connectionInfo = array("Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd, - "ColumnEncryption"=>"enabled", - "CEKeystoreProvider"=>"", - "CEKeystoreName"=>$ksp_name, - "CEKeystoreEncryptKey"=>$encrypt_key); - - connect($server, $connectionInfo); - - echo "Connecting... without a name\n"; - $connectionInfo = array("Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd, - "ColumnEncryption"=>"enabled", - "CEKeystoreProvider"=>$ksp_path, - "CEKeystoreEncryptKey"=>$encrypt_key); - - connect($server, $connectionInfo); - - echo "Connecting... with an empty name\n"; - $connectionInfo = array("Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd, - "ColumnEncryption"=>"enabled", - "CEKeystoreProvider"=>$ksp_path, - "CEKeystoreName"=>"", - "CEKeystoreEncryptKey"=>$encrypt_key); - - connect($server, $connectionInfo); - - echo "Connecting... without a key\n"; - $connectionInfo = array("Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd, - "ColumnEncryption"=>"enabled", - "CEKeystoreProvider"=>$ksp_path, - "CEKeystoreName"=>$ksp_name); - - connect($server, $connectionInfo); - - echo "Connecting... with all required inputs\n"; - $connectionInfo = array("Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd, - "ColumnEncryption"=>"enabled", - "CEKeystoreProvider"=>$ksp_path, - "CEKeystoreName"=>$ksp_name, - "CEKeystoreEncryptKey"=>$encrypt_key); - - connect($server, $connectionInfo); - - echo "Done\n"; -?> ---EXPECT-- -Connecting... with column encryption -Connected successfully with ColumnEncryption enabled. -Connecting... with an invalid input to CEKeystoreProvider -Failed to connect. -[SQLSTATE] => IMSSP -[code] => -33 -[message] => Invalid value type for option CEKeystoreProvider was specified. String type was expected. - -Connecting... with an empty path -Failed to connect. -[SQLSTATE] => IMSSP -[code] => -104 -[message] => Invalid value for loading a custom keystore provider. - -Connecting... without a name -Failed to connect. -[SQLSTATE] => IMSSP -[code] => -101 -[message] => The name of the custom keystore provider is missing. - -Connecting... with an empty name -Failed to connect. -[SQLSTATE] => IMSSP -[code] => -104 -[message] => Invalid value for loading a custom keystore provider. - -Connecting... without a key -Failed to connect. -[SQLSTATE] => IMSSP -[code] => -103 -[message] => The encryption key for the custom keystore provider is missing. - -Connecting... with all required inputs -Connected successfully with ColumnEncryption enabled. -Done \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_encrypted_patients_ksp.phpt b/test/functional/sqlsrv/sqlsrv_encrypted_patients_ksp.phpt deleted file mode 100644 index cdc8e62a..00000000 --- a/test/functional/sqlsrv/sqlsrv_encrypted_patients_ksp.phpt +++ /dev/null @@ -1,213 +0,0 @@ ---TEST-- -Test simple insert, fetch and update with ColumnEncryption enabled and a custome keystore provider ---SKIPIF-- - ---FILE-- -PatientId . "\n"; - echo $obj->SSN . "\n"; - echo $obj->FirstName . "\n"; - echo $obj->LastName . "\n"; - echo $obj->BirthDate . "\n\n"; - } - } - - function selectDataBuffered() - { - global $conn, $tableName; - - $stmt = sqlsrv_query($conn, "SELECT * FROM $tableName", array(), array("Scrollable"=>"buffered")); - - $row_count = sqlsrv_num_rows($stmt); - echo "\nRow count for result set is $row_count\n"; - - echo "First record=>\t"; - $row = sqlsrv_fetch($stmt, SQLSRV_SCROLL_FIRST); - $SSN = sqlsrv_get_field($stmt, 1); - echo "SSN = $SSN\n"; - - echo "Next record=>\t"; - $row = sqlsrv_fetch($stmt, SQLSRV_SCROLL_NEXT); - $BirthDate = sqlsrv_get_field($stmt, 4); - echo "BirthDate = $BirthDate\n"; - - echo "Last record=>\t"; - $row = sqlsrv_fetch($stmt, SQLSRV_SCROLL_LAST); - $LastName = sqlsrv_get_field($stmt, 3); - echo "LastName = $LastName\n"; - } - - sqlsrv_configure('WarningsReturnAsErrors', 1); - sqlsrv_configure('LogSeverity', SQLSRV_LOG_SEVERITY_ALL); - - require_once('MsHelper.inc'); - $conn = AE\connect(array('ReturnDatesAsStrings'=>true)); - if ($conn === false) { - fatalError( "Failed to connect.\n"); - } else { - echo "Connected successfully with ColumnEncryption enabled.\n"; - } - - $tableName = createPatientsTable(); - - insertData('748-68-0245', 'Jeannette', 'McDonald', '2002-11-28'); - insertData('795-73-9838', 'John', 'Doe', '2001-05-29'); - insertData('456-12-5486', 'Jonathan', 'Wong', '1999-12-20'); - insertData('156-45-5486', 'Marianne', 'Smith', '1997-03-04'); - - selectData(); - - /////////////////////////////////////////// - echo "Update Patient Jonathan Wong...\n"; - $params = array(array('1999-12-31', null, null, SQLSRV_SQLTYPE_DATE), - array('Chang', null, null, SQLSRV_SQLTYPE_NVARCHAR(50)), - array('456-12-5486', null, null, SQLSRV_SQLTYPE_CHAR(11))); - - $tsql = "UPDATE $tableName SET BirthDate = ?, LastName = ? WHERE SSN = ?"; - $stmt = sqlsrv_query($conn, $tsql, $params); - - if (!$stmt) { - fatalError("Failed to update record\n"); - } - - echo "Update his birthdate too...\n"; - $params = array(array('456-12-5486', null, null, SQLSRV_SQLTYPE_CHAR(11))); - $tsql = "SELECT SSN, FirstName, LastName, BirthDate FROM $tableName WHERE SSN = ?"; - $stmt = sqlsrv_query($conn, $tsql, $params); - if (!$stmt) { - fatalError("Failed to select with a WHERE clause\n"); - } else { - $obj = sqlsrv_fetch_object($stmt); - echo "BirthDate updated for $obj->FirstName:\n"; - echo $obj->SSN . "\n"; - echo $obj->FirstName . "\n"; - echo $obj->LastName . "\n"; - echo $obj->BirthDate . "\n\n"; - } - - /////////////////////////////////////////// - $procName = '#phpAEProc1'; - $spArgs = "@p1 INT, @p2 DATE OUTPUT"; - $spCode = "SET @p2 = (SELECT [BirthDate] FROM $tableName WHERE [PatientId] = @p1)"; - $stmt = sqlsrv_query($conn, "CREATE PROC [$procName] ($spArgs) AS BEGIN $spCode END"); - sqlsrv_free_stmt($stmt); - - $callResult = '1900-01-01'; - //when binding parameter using sqlsrv_query in a column encryption enabled connection, need to provide the sql_type in all parameters - $params = array(array(1, SQLSRV_PARAM_IN, null, SQLSRV_SQLTYPE_INT), - array(&$callResult, SQLSRV_PARAM_OUT, null, SQLSRV_SQLTYPE_DATE)); - $callArgs = "?, ?"; - $stmt = sqlsrv_query($conn, "{ CALL [$procName] ($callArgs)}", $params); - if (!$stmt) { - print_r(sqlsrv_errors()); - } else { - echo "BirthDate for the first record is: $callResult\n"; - } - - /////////////////////////////////////////// - $procName = '#phpAEProc2'; - $spArgs = "@p1 INT, @p2 CHAR(11) OUTPUT"; - $spCode = "SET @p2 = (SELECT [SSN] FROM $tableName WHERE [PatientId] = @p1)"; - $stmt = sqlsrv_query($conn, "CREATE PROC [$procName] ($spArgs) AS BEGIN $spCode END"); - sqlsrv_free_stmt($stmt); - - $callResult = '000-00-0000'; - // when binding parameter using sqlsrv_query in a column encryption enabled connection, - // need to provide the sql_type in all parameters - $params = array(array(1, SQLSRV_PARAM_IN, null, SQLSRV_SQLTYPE_INT), - array(&$callResult, SQLSRV_PARAM_OUT, null, SQLSRV_SQLTYPE_CHAR(11))); - $callArgs = "?, ?"; - $stmt = sqlsrv_query($conn, "{ CALL [$procName] ($callArgs)}", $params); - if (!$stmt) { - print_r(sqlsrv_errors()); - } else { - echo "SSN for the first record is: $callResult\n"; - } - - selectDataBuffered(); - - echo "\nDone\n"; -?> ---EXPECT-- -Connected successfully with ColumnEncryption enabled. -1 -748-68-0245 -Jeannette -McDonald -2002-11-28 - -2 -795-73-9838 -John -Doe -2001-05-29 - -3 -456-12-5486 -Jonathan -Wong -1999-12-20 - -4 -156-45-5486 -Marianne -Smith -1997-03-04 - -Update Patient Jonathan Wong... -Update his birthdate too... -BirthDate updated for Jonathan: -456-12-5486 -Jonathan -Chang -1999-12-31 - -BirthDate for the first record is: 2002-11-28 -SSN for the first record is: 748-68-0245 - -Row count for result set is 4 -First record=> SSN = 748-68-0245 -Next record=> BirthDate = 2001-05-29 -Last record=> LastName = Smith - -Done \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_fetch_large_stream.phpt b/test/functional/sqlsrv/sqlsrv_fetch_large_stream.phpt index 3bb94841..7b6f6e40 100644 --- a/test/functional/sqlsrv/sqlsrv_fetch_large_stream.phpt +++ b/test/functional/sqlsrv/sqlsrv_fetch_large_stream.phpt @@ -35,23 +35,15 @@ if (!sqlsrv_fetch($stmt)) { $stream = sqlsrv_get_field($stmt, 0, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_CHAR)); $success = false; -if ($stream === false) { - $error = sqlsrv_errors()[0]; - if (AE\isColEncrypted() && $error['SQLSTATE'] === "IMSSP" && $error['code'] === -109 && - $error['message'] === "Connection with Column Encryption enabled does not support fetching stream. Please fetch the data as a string.") { - $success = true; - } -} else { +if ($stream !== false) { $value = ''; - if (!AE\isColEncrypted()) { - $num = 0; - while (!feof($stream)) { - $value .= fread($stream, 8192); - } - fclose($stream); - if (checkData($value, $inValue)) { // compare the data to see if they match! - $success = true; - } + $num = 0; + while (!feof($stream)) { + $value .= fread($stream, 8192); + } + fclose($stream); + if (checkData($value, $inValue)) { // compare the data to see if they match! + $success = true; } } if ($success) { diff --git a/test/functional/sqlsrv/sqlsrv_prepare.phpt b/test/functional/sqlsrv/sqlsrv_prepare.phpt index 8f504303..deda10c9 100644 --- a/test/functional/sqlsrv/sqlsrv_prepare.phpt +++ b/test/functional/sqlsrv/sqlsrv_prepare.phpt @@ -80,11 +80,7 @@ binding parameters, including output parameters, using the simplified syntax. echo "$name\n"; $stream = sqlsrv_get_field($stmt, 3, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY)); 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!'); - } + fatalError('Fetching data stream failed!'); } else { while (!feof($stream)) { $str = fread($stream, 10000); diff --git a/test/functional/sqlsrv/sqlsrv_query.phpt b/test/functional/sqlsrv/sqlsrv_query.phpt index e3fde92a..3350e90c 100644 --- a/test/functional/sqlsrv/sqlsrv_query.phpt +++ b/test/functional/sqlsrv/sqlsrv_query.phpt @@ -49,11 +49,7 @@ sqlsrv_query test. Performs same tasks as 0006.phpt, using sqlsrv_query. echo "$name\n"; $stream = sqlsrv_get_field($stmt, 3, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY)); 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!'); - } + fatalError('Fetching data stream failed!'); } else { while (!feof($stream)) { $str = fread($stream, 4000); diff --git a/test/functional/sqlsrv/sqlsrv_send_stream_data.phpt b/test/functional/sqlsrv/sqlsrv_send_stream_data.phpt index aa9ff82d..1f3982b6 100644 --- a/test/functional/sqlsrv/sqlsrv_send_stream_data.phpt +++ b/test/functional/sqlsrv/sqlsrv_send_stream_data.phpt @@ -114,11 +114,7 @@ binding streams using full syntax. echo "$name\n"; $stream = sqlsrv_get_field($stmt, 3, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY)); 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!'); - } + fatalError('Fetching data stream failed!'); } else { while (!feof($stream)) { $str = fread($stream, 10000); diff --git a/test/functional/sqlsrv/test_scrollable.phpt b/test/functional/sqlsrv/test_scrollable.phpt index 29d20113..7e67a597 100644 --- a/test/functional/sqlsrv/test_scrollable.phpt +++ b/test/functional/sqlsrv/test_scrollable.phpt @@ -1,213 +1,208 @@ ---TEST-- -scrollable result sets. ---SKIPIF-- - ---FILE-- - $idx, 'value' => 'Row ' . $idx), $res, AE\INSERT_QUERY_PARAMS); - - if (!$stmt || $res === false) { - fatalError("failed to insert row $idx!\n"); - } - hasRows($stmt, $expectedFail); - sqlsrv_free_stmt($stmt); -} - -$conn = AE\connect(); -$tableName = 'ScrollTest'; -$numRows = 4; - -$columns = array(new AE\ColumnMeta('int', 'id'), - new AE\ColumnMeta('char(10)', 'value')); -$stmt = AE\createTable($conn, $tableName, $columns); - -$rows = sqlsrv_has_rows($stmt); -if($rows == true) { - die("Shouldn't have rows"); -} -sqlsrv_free_stmt($stmt); - -for ($i = 1; $i <= $numRows; $i++) { - insertOneRow($conn, $tableName, $i, true); -} - -// Always Encrypted feature only supports SQLSRV_CURSOR_FORWARD, so skip the rest of the test -// when AE is enabled -// https://github.com/Microsoft/msphpsql/wiki/Features#aelimitation -$query = "SELECT * FROM $tableName"; -$options = array('Scrollable' => SQLSRV_CURSOR_FORWARD); -$stmt = sqlsrv_query($conn, $query, array(), $options); - -hasRows($stmt, false); -countRows($stmt, $numRows, 'forward only'); -sqlsrv_free_stmt($stmt); - -if (! AE\isColEncrypted()) { - $options = array('Scrollable' => 'static'); - $stmt = sqlsrv_query($conn, $query, array(), $options); - - $result = sqlsrv_fetch($stmt, SQLSRV_SCROLL_ABSOLUTE, 4); - if($result !== null) { - die("Should have failed with an invalid row number"); - } - hasRows($stmt, false); - // this is empty - print_r(sqlsrv_errors()); - $result = sqlsrv_fetch($stmt, SQLSRV_SCROLL_ABSOLUTE, -1); - if($result !== null) { - die("Should have failed with an invalid row number"); - } - // this is empty - print_r(sqlsrv_errors()); - - // expected an error here - $rows = sqlsrv_rows_affected($stmt); - $message = !empty(sqlsrv_errors()) ? sqlsrv_errors()[0]['message'] : ''; - $expected = 'This function only works with statements that are not scrollable.'; - if (strcmp($message, $expected)) { - echo "Expected this error message: \'$expected\'\nbut it is: \'$message\'\n"; - } - - $rows = sqlsrv_num_rows($stmt); - if ($rows != $numRows) { - echo "Error: Query returned $rows rows\n"; - } - - $row = 3; - $result = sqlsrv_fetch($stmt, SQLSRV_SCROLL_ABSOLUTE, $row); - do { - $result = sqlsrv_fetch($stmt, SQLSRV_SCROLL_ABSOLUTE, $row); - if($result === false) { - die(print_r(sqlsrv_errors(), true)); - } - $field1 = sqlsrv_get_field($stmt, 0); - $field2 = sqlsrv_get_field($stmt, 1); - $idx = $row + 1; - - if ($field1 != $idx || trim($field2) != "Row $idx") - echo "Field values unexpected $field1 $field2!\n"; - - $row = $row - 1; - } while($row >= 0); - sqlsrv_free_stmt($stmt); - - $options = array('Scrollable' => 'static'); - $stmt = sqlsrv_query($conn, $query, array(), $options); - - hasRows($stmt, false); - countRows($stmt, $numRows, 'static'); - sqlsrv_free_stmt($stmt); - - $options = array('Scrollable' => 'dynamic'); - $stmt = sqlsrv_query($conn, $query, array(), $options); - - sqlsrv_fetch($stmt); - sqlsrv_fetch($stmt); - - insertOneRow($conn, $tableName, 5, true); - insertOneRow($conn, $tableName, 6, true); - $numRows = 6; - - // to account for the two fetches above - countRows($stmt, $numRows, 'dynamic', 2); - sqlsrv_free_stmt($stmt); - - $options = array('Scrollable' => SQLSRV_CURSOR_STATIC); - $stmt = sqlsrv_query($conn, $query, array(), $options); - - $row_count = sqlsrv_num_rows($stmt); - if($row_count != $numRows) { - die("sqlsrv_num_rows should have returned 6 rows in the static cursor\n"); - } - $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC, SQLSRV_SCROLL_ABSOLUTE, -1); - if($row !== null) { - die("sqlsrv_fetch_array should have returned null\n"); - } - - $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC, SQLSRV_SCROLL_ABSOLUTE, 6); - if($row !== null) { - die("sqlsrv_fetch_array should have returned null\n"); - } - - $options = array('Scrollable' => SQLSRV_CURSOR_DYNAMIC); - $stmt = sqlsrv_query($conn, $query, array(), $options); - - $result = sqlsrv_num_rows($stmt); - if($result !== false) { - die("sqlsrv_num_rows should have failed for a dynamic cursor."); - } - sqlsrv_fetch($stmt); - sqlsrv_fetch($stmt); - - $stmt2 = sqlsrv_query($conn, "DELETE FROM ScrollTest WHERE id = 2"); - if($stmt2 === false) { - die(print_r(sqlsrv_errors(), true)); - } - - $row = sqlsrv_get_field($stmt, 0); - if($row !== false) { - die("sqlsrv_get_field should have returned false retrieving a field deleted by another query"); - } - $error = sqlsrv_errors()[0]; - $message = $error['message']; - $sqlstate = $error['SQLSTATE']; - if (strcmp($sqlstate, 'HY109') || strpos($message, 'Invalid cursor position') === false) { - die("Unexpected SQL state $sqlstate or error \'$message\'"); - } - - // verify the sqlsrv_fetch_object is working - $obj = sqlsrv_fetch_object($stmt, null, array(null), SQLSRV_SCROLL_LAST, 1); - if($obj === false) { - print_r(sqlsrv_errors()); - } else { - if ($obj->id != $numRows || trim($obj->value) != "Row $numRows") - echo "Field values unexpected $obj->id $obj->value!\n"; - } - sqlsrv_free_stmt($stmt); -} - -dropTable($conn, $tableName); -sqlsrv_close($conn); - -echo "Test succeeded.\n"; - -?> ---EXPECT-- -Test succeeded. +--TEST-- +scrollable result sets. +--SKIPIF-- + +--FILE-- + $idx, 'value' => 'Row ' . $idx), $res, AE\INSERT_QUERY_PARAMS); + + if (!$stmt || $res === false) { + fatalError("failed to insert row $idx!\n"); + } + hasRows($stmt, $expectedFail); + sqlsrv_free_stmt($stmt); +} + +$conn = AE\connect(); +$tableName = 'ScrollTest'; +$numRows = 4; + +$columns = array(new AE\ColumnMeta('int', 'id'), + new AE\ColumnMeta('char(10)', 'value')); +$stmt = AE\createTable($conn, $tableName, $columns); + +$rows = sqlsrv_has_rows($stmt); +if($rows == true) { + die("Shouldn't have rows"); +} +sqlsrv_free_stmt($stmt); + +for ($i = 1; $i <= $numRows; $i++) { + insertOneRow($conn, $tableName, $i, true); +} + +$query = "SELECT * FROM $tableName"; +$options = array('Scrollable' => SQLSRV_CURSOR_FORWARD); +$stmt = sqlsrv_query($conn, $query, array(), $options); + +hasRows($stmt, false); +countRows($stmt, $numRows, 'forward only'); +sqlsrv_free_stmt($stmt); + +$options = array('Scrollable' => 'static'); +$stmt = sqlsrv_query($conn, $query, array(), $options); + +$result = sqlsrv_fetch($stmt, SQLSRV_SCROLL_ABSOLUTE, 4); +if($result !== null) { + die("Should have failed with an invalid row number"); +} +hasRows($stmt, false); +// this is empty +print_r(sqlsrv_errors()); +$result = sqlsrv_fetch($stmt, SQLSRV_SCROLL_ABSOLUTE, -1); +if($result !== null) { + die("Should have failed with an invalid row number"); +} +// this is empty +print_r(sqlsrv_errors()); + +// expected an error here +$rows = sqlsrv_rows_affected($stmt); +$message = !empty(sqlsrv_errors()) ? sqlsrv_errors()[0]['message'] : ''; +$expected = 'This function only works with statements that are not scrollable.'; +if (strcmp($message, $expected)) { + echo "Expected this error message: \'$expected\'\nbut it is: \'$message\'\n"; +} + +$rows = sqlsrv_num_rows($stmt); +if ($rows != $numRows) { + echo "Error: Query returned $rows rows\n"; +} + +$row = 3; +$result = sqlsrv_fetch($stmt, SQLSRV_SCROLL_ABSOLUTE, $row); +do { + $result = sqlsrv_fetch($stmt, SQLSRV_SCROLL_ABSOLUTE, $row); + if($result === false) { + die(print_r(sqlsrv_errors(), true)); + } + $field1 = sqlsrv_get_field($stmt, 0); + $field2 = sqlsrv_get_field($stmt, 1); + $idx = $row + 1; + + if ($field1 != $idx || trim($field2) != "Row $idx") + echo "Field values unexpected $field1 $field2!\n"; + + $row = $row - 1; +} while($row >= 0); +sqlsrv_free_stmt($stmt); + +$options = array('Scrollable' => 'static'); +$stmt = sqlsrv_query($conn, $query, array(), $options); + +hasRows($stmt, false); +countRows($stmt, $numRows, 'static'); +sqlsrv_free_stmt($stmt); + +$options = array('Scrollable' => 'dynamic'); +$stmt = sqlsrv_query($conn, $query, array(), $options); + +sqlsrv_fetch($stmt); +sqlsrv_fetch($stmt); + +insertOneRow($conn, $tableName, 5, true); +insertOneRow($conn, $tableName, 6, true); +$numRows = 6; + +// to account for the two fetches above +countRows($stmt, $numRows, 'dynamic', 2); +sqlsrv_free_stmt($stmt); + +$options = array('Scrollable' => SQLSRV_CURSOR_STATIC); +$stmt = sqlsrv_query($conn, $query, array(), $options); + +$row_count = sqlsrv_num_rows($stmt); +if($row_count != $numRows) { + die("sqlsrv_num_rows should have returned 6 rows in the static cursor\n"); +} +$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC, SQLSRV_SCROLL_ABSOLUTE, -1); +if($row !== null) { + die("sqlsrv_fetch_array should have returned null\n"); +} + +$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC, SQLSRV_SCROLL_ABSOLUTE, 6); +if($row !== null) { + die("sqlsrv_fetch_array should have returned null\n"); +} + +$options = array('Scrollable' => SQLSRV_CURSOR_DYNAMIC); +$stmt = sqlsrv_query($conn, $query, array(), $options); + +$result = sqlsrv_num_rows($stmt); +if($result !== false) { + die("sqlsrv_num_rows should have failed for a dynamic cursor."); +} +sqlsrv_fetch($stmt); +sqlsrv_fetch($stmt); + +$stmt2 = AE\executeQuery($conn, "DELETE FROM $tableName", "id = ?", array(2)); +if($stmt2 === false) { + die(print_r(sqlsrv_errors(), true)); +} + +$row = sqlsrv_get_field($stmt, 0); +if($row !== false) { + die("sqlsrv_get_field should have returned false retrieving a field deleted by another query"); +} +$error = sqlsrv_errors()[0]; +$message = $error['message']; +$sqlstate = $error['SQLSTATE']; +if (strcmp($sqlstate, 'HY109') || strpos($message, 'Invalid cursor position') === false) { + die("Unexpected SQL state $sqlstate or error \'$message\'"); +} + +// verify the sqlsrv_fetch_object is working +$obj = sqlsrv_fetch_object($stmt, null, array(null), SQLSRV_SCROLL_LAST, 1); +if($obj === false) { + print_r(sqlsrv_errors()); +} else { + if ($obj->id != $numRows || trim($obj->value) != "Row $numRows") + echo "Field values unexpected $obj->id $obj->value!\n"; +} +sqlsrv_free_stmt($stmt); + +dropTable($conn, $tableName); +sqlsrv_close($conn); + +echo "Test succeeded.\n"; + +?> +--EXPECT-- +Test succeeded. diff --git a/test/functional/sqlsrv/test_stream_large_data.phpt b/test/functional/sqlsrv/test_stream_large_data.phpt index c14f9e27..909e3e69 100644 --- a/test/functional/sqlsrv/test_stream_large_data.phpt +++ b/test/functional/sqlsrv/test_stream_large_data.phpt @@ -3,11 +3,8 @@ streaming large amounts of data into a database and getting it out as a string e --SKIPIF-- --FILE-- diff --git a/test/functional/sqlsrv/test_warning_errors3.phpt b/test/functional/sqlsrv/test_warning_errors3.phpt index 9ee8dc37..1b0bdc66 100644 --- a/test/functional/sqlsrv/test_warning_errors3.phpt +++ b/test/functional/sqlsrv/test_warning_errors3.phpt @@ -86,11 +86,7 @@ error messages when trying to retrieve past the end of a result set and when no echo "$name\n"; $stream = sqlsrv_get_field($stmt, 3, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY)); 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!'); - } + fatalError('Fetching data stream failed!'); } else { while (!feof($stream)) { $str = fread($stream, 10000); diff --git a/test/functional/sqlsrv/values.php b/test/functional/sqlsrv/values.php new file mode 100644 index 00000000..70df64b9 --- /dev/null +++ b/test/functional/sqlsrv/values.php @@ -0,0 +1,778 @@ +ªo~äbhîýÐ~åÜB¢ß©+ü~ßÄAZî>öî~C_<ý@:Oåãã/v", + "Öý.C+.~a<äã+büa_ b|¢:|.ÃÄ~@ð ª*ZÃz @£+_>~âao|©å.ä/ªßAZ/ý/©ãbboU**©Ð£>îü_bbÜð,@oð¢@:OÐ<£Aî@rÄÄ.>_+©ßåðUîüªð>î/|ÄbªåAÄÖüÃUߣ_u|ÐÄZý,ª<ãУ>,ðZußýöãZböãu<ðZuvb:zöäurîAöu,öh,u*b,AA©ª,v©Ö:Üð©O:,©rr:bbaåüýªîCß/ýhååOU.äî", + "¢ý¢oüZ¢+Cß>,|:uö© ¢Är¢.@C@î_,abßåü>Ö,~bü£å¢ãCå:,Üãß+|Z>rÜТbäA*ã ÐB ßZ<.aBÐBå~.ub>Ö_uÃUª>ã@zß:AüB|Bbb:ððvräzÜbBýß |üÖ*ÖOååZZbO@î <:ãuCvöB/a~Ö Ä:Ö_><îbuÖßðOOO¢äb©öüZ~UÖÃbªåz*o/|oã_@ÃAývvÄAzðBÜ:~ððß*/ä>Üß.zrð.©<¢a B ,¢üÄAåu:Öüã.Ð/u¢rÐýAÐäªÃb*Z*ßzB/+U@Zã¢,üv b:<ÜOý/ã.Z*b~@av£Ã~ä¢/ä,A<îöß~ aÖ.ßhuZozðýåßBz©ýv|ýÄ+.Ä¢ªbÐÄb>Aãü zOÐåb+@vö£|bzÐßî©Uªª£*ÃO_h_/U/öAãÖaÄ_U|Ä £ZÐü._å¢CA+@_bªhÜ£ öuCOZ<ðvªÐouý_bb>@îaovÜb>~BbßÖ@Ä©U~zöB£©h~ã|,b_.ß>UUª¢oÃ:b©Ä+ä<ãr/|ÐüÜh.äUå~.r©/AÃUz>ZCAbîäå.öZvBa*ö@ß:b+ã++Ö~ZU,U©Ã¢o ð @£bîUýðö¢<,äÐðuurö©îÐZ>¢¢rãßz.¢,ßO.îvOhvAU/£ä/_v,Cå*Ußð©Ã:£:ã¢î,Bu|î£ß @ðOUãU:îb©|/O@voüUÖuß@Ã..*b_¢ä£¢~ß+/b~b/u_~ßvrÄäßb~£î~@aUÖß>OðZuaöã,oãB,O ývöîhu¢rÄ_výÄaZ*OzÖ|Uzv*Ü *zÃýür<~~Ub*ª~äýrÐüAuãCߣܢªbÃý~hßäz>Ð|b@h.AZãÄoÄUC_,ÐC@rî*r|å>îv>ußÄ_>:oî@b.B>ßb:åã|/O,Ã*Cª++>£¢>Öߢî:oÖ£,>uABC,_CBý© ßzßC+/îbÜ,ä/î ÄOOaÐBðb©o£Uarãv,£üOð<ßßbÐã|ªC*~rßÃ+ðBU~.Ü£©:C/ÃU>au<Ð,u+,ðaU*/|ßbbu@:*Z.+Öoãh özhzCBhC:,:a_oU b*Bä.buOßoÄßBüu+ubýÄBAz:©ð~ßb:ßhobÄßÖZðåBü@ö, A>obÜ©|ã|+Öh©AªaU|£@ã©Ãðv ÖU£öäî@ãüåÃÃOC_vîAöÄ@|u©Ð©Bðý©,ýßOî r¢>ãªßbÄz_+_ü~Ü£ý|ßOAürrß~äZ>Ãäarubv@BCÃ>>*OZ|ü,åÐav*Äzu.zAaüÜuª©+ Ö_@Cå/hÃ@ªAîU¢:,ÖÃ~£<ðßäubCÄÄZÐ>ðurä+¢CãuAÜ¢+,Ü+@+:ðbÐäãÄ£îß /üUä@ýA.~ah|Ö.:hr<ßvÐO ßß/r++oÐÄZ>ßb_Öä.Ööð+ + z.Ã>Ob_ªU¢.bBߣA/Z.vU¢,ª:¢,@Üvü>/Båüã|¢Ðî|/CÃÖ¢Cîhîz|~㣣bUä<ÃbåÐå,ÜÖBbo.îza <£äOAÜ<üÃÖÐr/<*Öa CüÖb~v@ý,bÐå©ZãzO.+©:î~ðAh£~ ¢Ä,,~rb~,bª©A,.ußb:+hzð,*äu+ãb:¢ö©Ü* >BbßÄÜ+Üa.>OÃubOrrzÜabÄý©Ð*ªüÄ+¢bîzü,~._|ª /Äroß,:Ð<:| :+Bhý.ÜßZbåCßîBߢßÜu,Ävv:~@u@ýåo>|ä~Z/.hßßb,ßB*ðZ£BÃÃ*ðÐCß©,å|vzoТub>>O+£/~©å:*uªðåårü£Ä h~ý:B@>£:BßuZãÜöü>.ªãª,@ä>Ü*¢<îß@öð£BýÐ:B@äObÜZCýo@åýAbüOäz_ÄZ~oßýa@+bß_AÖ:vä_Ãu~ªu~ããu.aU<>O.Ävßz~:ªåÜ©Cöäu~ßC£oböCba üÖª@C|z+¢bO:_öU¢Ãß|:åýaãrhã B:~rßý¢Ãý+©Bß|uo,*|Äð/UZ@_/üÖÖzüÐývo:ý¢_ |¢ h:© Öã/ã~h,£rz©v|£ðubÃ*ßZbÃ,Ða,+ßðhbåCrî <,ªªªöo *ý©¢,v:BäAÄhAC|ÐaäZo¢,::aî~zÖr©B_b+AÐÖ,£ÃöaB>Öz*ãä~Ö©aÄö_rª>©h*©*ªªöÐ_av:¢:©,+övªU<åªð/@+.>@oîý|ª*Ðîo*ªZã zA|b|ov*î/©:b.oB| b>C|£îbb¢bBU¢OAZª,ü ã vßý_åhZ ÐbßZU*uÖ,©ý@_rU©ß>.ÜßÖhu<ÄUz|BaîÖzzA: ðÃbäaZ* Üb| Ö,Ä>@üð|ß@CîOZ£bÖUîru:|ÐÄöÐãåoöOÐU*¢rUß Bå@,~oÃТv|_o*CZßýß~uB©©~ðOööAå@:|B öoo|Uar¢~,A+Cbßr:rCauäß©üÐߪ+bBªvÜ*©ãU uîbbOåßßäU©bU:BCb*<~@uªU_Z/C Ðh+rååCoߢßOîð+Äýäoo©vz*©ßaZß_å/Ã/ßv.h@~oÄaª£vuÄbZý:oÄßÃZvzZÃO¢aý*îO>üC,ðÃßö/r+ZäoÖbZZOܪCühãuîýBa¢z*buBo~_<ðåUbîa/_.~ÐÄOh|+aý|Ãßßã/~bðßð£åÃÐÄãÄååußß+|@Zîhu<äBOAã©CAß>ãb¢¢ÜÃAüCÜÐî/u o©ðÄ b|éîAÐÃb,+ÖOÖßßUö©ð¢*ý,ZöUîÄ£ßð*Z|rý+b/|o.Ä,ýÐÃ.>îÐvÜÄÄ~z+öÜßü/~:,åOªßååu+<ðvazu|ß©aãA.UÜ ZbÐr*Ö©>ßßZ ýCåÜ|£ZðhbÄ+b£_ÐU¢o*bz,ö+:+/z¢oÜ|oã_hb<ÖöãrU +hÄrövo£ðUÃÄð,Bvã¢>îößîßý~Oh.,UBo¢a ©u++ýh¢îoßr©,>Buà ,_uîu*BAU@a~_z,ܪ¢UhðßOa£o+>ÖîzA.ãU:BÖaavöîBî~vîZ¢î<ü|.~+uvbý~Z uüoÄbð©ã¢UäüîbBbî:uhaßbä/£Bå>üAé|åð.|ä*öbäÐÃ/©zCuo@+o .îzZ,ãß*£uOZ rO¢ ªäOöü*oýüÜÜZß>z@U@h*Cö~ßî>ü+:|oZ.bAbãÄäÜBÄh@bo AuÖã¢ä¢©ãÃýªß|äa:öaA:C£*Ü©+v,ßbÜÐOðoÃÐ@.ß,r+äCbuuÄÃ|bhäð|,bö<+ZA¢u䢢à Ð/~UbðZ>©¢hAÃB>ЪzaªZ©|ö/CoУv.~@+üh:îßývî+ * ~öhA ,zUªC@uªoabü.*îZßBßrÄbüCÜßZßÖu_ß~Ü£ÖªbÃ:|öÃ.h~BüUb:¢Ãߪ CßzU.ãö:U+£Ão©Ü,+£Ö+|ýrÃz|ÃÜðhÜoz.£¢ªCüUbC¢ ©ývßC¢ uaabÃAz.|aüßa<@>Ãß/Aßu/äî|uß*ãboã::+r>zB*o¢Ö_zªäo<|ýÃ~@ý|ooCß>bÐðßý|AhzO@ âªÃzªü*£åvb:Uð:ßb rZäCåßÄzbãao+<+îî+åã|h:ãO<ä*Т|*väzAã@Ðäªzî@£ÄåªB*AbîrÜbãaö.ü+|/v©î@o b,£AUvuðr:ªUv,~Büb|b|:zAB@oh_£<Ööå|£bßBÐüýbU|ß|ð~BåЩÜî/ßrÐßýäýBO<Ä*UäbhöãC|,b©ý*Ahãö<öäÃßßߢßßöZÄÖÄÃU|Bu+|Ö/rOãAr@Ã:ßÜboÄ@ÄýB>.aÖüäÖözBðÃ|üÄãCCäoÖ©U Bbî.u/oroüZAbAzbhîZ:ðb,*,¢î>ÄÖ/ÜUzäÄ@äåb Ä_~©ÃÜBßßaä+Ü,A©|A~@©>,@@ÜÖO~_vaUhr@ß©ÃäßÃîÖ~,<ðßbüãz@©uobhîaðuvÖäh£r>äå ÐÄü~¢öhzã*_|.ÃÐ:ý+Ö@ßãî:£aÐvãÄjkl@~ßâ@BaªO|Ãà o.OrhC*_åß@ö¢uär© Öü©|ä£@ObÐýÃüOÃîåoCb_*r/A<.äZ:ã u>Öýö£aߪãvÐî.ü~©öÜ*b¢ß,ÖU@+U©î¢å£<<.Äöuhz:ÃB<_¢@ãO ÃÐ>Ö:¢ZÃAÃU hv@.ªböauÜO<*Ä/äbÃC:Ö:Äa© ä©.ußÄuUßhå:oý_UåÐ|A,ÐO/¢ |Ü|Ã_>ÖvrZ~ýö|ý:¢öC<ý~|.._Ä£ZððZýª@BßbC__äCZBÜ,zð¢AhÄîߪ+@aÖråo@,b,ý vªßb<>ªCUab£ßªðßüÜCª~b_:CUîuüåa+.ý©ArBU.r>h@öB.vUÃ/zZ+Ðrb+öuª,h*aÃUßöåªå@Ä.BöA>aã¢üZ:ÃbAU:üãhaßß*Ü>vä~ *b_ß~ö£vAäö,ü/äîzªr~<îÜÖ>î¢ÐO@UhUZ¢rîî>B~Oöür¢ã*>är£©aä:zßZà ðB@¢ßhÃß©ý.CCýzüß|åbvuzz~U,¢bÃßrAzåU£ÜåÜz* u_:o,îÄ,/@bðUå©,äuOÃýZuzBªîîbýaur© öABýÐ*Z*Ãü+¢*ü+a|h£*ð hbßýß :>ãÄ||Ð+ÜU/*Ãö@*Äü_öÃü:B| ,¢åArÐ@öårh©bßUýUzÃZ£ýßß*ß/ä¢>AÐouoB<ÐAÄãÐb rbîÖÃÄÄh,vÃ.ãbÃ+z£ +o,>ã£h@>Zý:îð:ªzðÃOðßî î_Öv.b©,O.©Oß|bC|rrä.ßÜ<+<,:ª<,~Ub~ZååC:ª~Z>UvßÐã~¢Ð~AðBÜvåð©rÜÃaBðÐüßu©BÖUã@ZuC©£ªAä©ýuh>@ªaOÜ.ߪbÜUAªÖß*BÄ~:vª©îüãAðßbÖªä_©ðao.bða|UöÖßbÜCb¢Aüå>¢vhvbÃß@Uö/r©¢vaUåîßOÖUrÜ<~_ðÜz¢*ßö<ã¢Ä/@/_~v£Cb£bUhbb åAö<~Bv~:¢ßãä©ßo¢ObhaåCÄ ßZ@£oä:*Äß._+CrîB ªZv,ÜB£ö~,Uüäýã/UüÖ<+ ÜAa ðª,ãA+ýðÖub,>.ýrvbBÖö/Ãðåuh¢öZ>U,:OA|Ö*äüðuª,ã: åý_ß|ÄhªOb/rüu*Ä¢uÃÖ£ÃÄ.zhî@r,Ö@übö.|Ãüãîbvzã¢ý©ÃÐ|ý|räOvh@/ߢ.ÜzðUåZðoöväã|.,|Ãhuã<ãÖüÜuÖo.O_av©>að+B+Ö~¢ÐÃ*ZÜå~ßZ~ßðö_ö<©_ÜÐÜÐã~îî,¢zbãbîrAv.öývã*U.<Ð_:üî.ãüãäaäÖ+ä<ö@UÐÄAÐ>ÃbÐ|>å.<.BO+ð£,¢aCb*A,©~Cßîãý©ÜÃßüZäÃZ:ü/@/©O>_zC¢Ð~ý,:Z,h/Äü|>Öz>_ü+_ðУbî@üý,¢UªÐ+öOÄ.>ý<_ãÖýäAÃ*Ãö~ð~Ãaöî<ö ,Öß:+ãCßhÜh<+b+åîbb>Z£Ä©©©oÃöUßö|©BßaZªAîåuîßB|@zCAß//bÐAoÜÄÃ/äåüOðÄü~äª:a~,/ßä~C¢+ßuý>C¢*Üä>î*Ãßu><üva@ß~*ß©,©ß__+båß+ßßäðÄC/@vb.ÖaözZC©äª+ðrßÃA_ðZö/ßýäÃÃB*z.+bBÖv¢©äuvv,ArýåªbU©~@Uz¢ªÜoU¢OÜ+:U ß/_b+©ÄAÃAÜßäßbAB¢ãäßÜh©ä>¢~bðzðb~O_äîrrAðßUü|oaã©ü/åÃv,|ªCC£¢£Ð/Ã*ðåÜaz©ãBA,ÜUZAÖBßüåA+ ÜýUÜb_,vbßvrUhb©©Öb~UaÜ+ßBî@ßÜ_©ü~BÜÖ@ªZÃÖzüýbߢAoZhýÜBÖuåüü£å:zvªU£AZîhhÖå>Ãß+Ðzv>£<.©r>*|å|££ßzýÃ+ãhªÖvhýUîªb,>u©+,ßßãðAh©Äa~>CbOÄCaåo©Ö, //ZîZo,*üv/@oä:ßaðAU| >Ä£,>,>Öu,|¢U@㣩_v|boÖÄhÖüZ:>ðååa<|ÜC©:öbÜ@<ª öZrÖßAöv*üðUÐ/uZÐ:©Ðubvä_äߪa+uU@/aývÖCäöÐhªääöAÐÜbbßåBîA*rüu UüÐÃÐz.uaý*ßß>ð©ý©îÜåU o/£ Cüð|o¢ªUo¢@,Baa_u@å:~ßBߢî£ÃhîbAbzäBöOCh~.O£hU.ßåbaA£@r<üÃÐUhßCU|<*ßhðªb,Öåo£:Ã,<äßbåa,@B+CU/åýÖZðb©î¢£ö/ü£î¢Aã@a ÖZaA*_BßÄÖß*ª>ÖCåÄ,A>ärä£ð+<îb_ªuCCÄÖU~@|bîåob+ho>oChýãåbo,/Oªð£urh<,b+¢hä:.ü Ã|_U ,å.>UÄ©Öª©@ýî>ã~..éBß:Öbü| b/ÄðzÐOßýZÄO|üUrÄu|~:ßüB:ÃÖÐha£CvZO,ߪ©o bªhÄ@Ch_vbä.ýåU:¢:¢ý/£ý£ªîvßä,B_.U,rã,ö|¢OåüßÃZ,ððooboå,¢>Cªã ÃäözaÐ>AªU@b+vÖAãî¢åäðuö>U*ý~*v ÄZ:vür+BÜÄa+rbýüªzz@:Ð*ýÄb ÐßÄ.A£ðo./bü/~Ããð~vaîý>o ©Zz¢h:_îä¢ZbzýÄvð~@| åðÜî/,/b/Öz|B**¢@vý>b~ü,Öªª|Ðý.ü~ýß*_ÐÄbCä/åý>r¢*£,z_bZzü+oßßäz/* ýC|aBß|ð+Ohb.v.ýrB~B/@Ä<,o~åvU|ý_©@Bb*_ªÖ¢ÃBoîöî.ߣuäUå:.bªðu©£h¢o@ÖÐzðä|ü*ß㪠>ü©Äz¢U Ã/AÃaãªÖªßßZuÐÃ@bÐ.AZð üßAäªCüðÜ/Brß~rãaOUªrzðvÜvh£~rubÖCbåýýý¢¢äbäC@îöäå,ãAzC£åÖB*üz |rb/Ã@zäAr¢ü vbhU*rßÄß+A:ý,au墣z_<£bBu._", + "", + "Ü,ߪäýÜ@¢ÖãAýÃhz¢h|ü©ßÜ.bhhßUÃ/ĪBraOªA£åßîÄßAB_ZU+UB/©ýª,@Ääüvð C.å©v:vªh@U:vÐ ðÜho*ð©ð.ß_*åöb.ߢhãa~£@:v+vo,Üß/ß.*bO/oîäbäÄB+£b", + 'F*^vEjJvsK6ESpv&$tt.c7H?8p50/KICWE$!A+*IQ@7D=s`t2! qp;icVYk_[hrg!)WOK#7chF+&T>HZCr,gk`b9Ow]M.K1)EAFAj7tYL]FT\BE\`I36XqlSr!0tK&4!i@jZa4,]`&Gk-t\mk#@TSVL6aQciYwV@\.CoM P;;3rrkK%kdj$_t#lu@mS"S)^f3&\<:>gLP!vjaLlYZs[sE&CQ,RZC"`bGU kwAkTkUjA`/ANWKVHI(,@Hb/ktiCI?swvaS/%qptXAv6oG/\.s[OV9OlQR6]kjCseu)`#:wG07XN?Mu"fnnM)Eae+v^(BQ_eAm^6L+^X,7r2,53FVs)-o?"u<$f(,1=t[n$DQD_kfWRcgr#()?RwklO!E^^:+?jcB/NmLFt!4In#!u\3CQ$kM7mVD8.9 =+VL+?5wc@NlK(7.FmFP3rO-aAPaE_AKN!i7O@MN?I@[0&$RUpYC-_HAkF?J2Es:JlGH1q0ax6ivL%:7rGTso)__ 6iQjWPoll)-=gC&(4p56ujk)c27,>Q^dm8R. 1@/b[E[E=Ui:=J(BX1+C(qn-75dC ?/&Wpp4D7MKUU]*iR:O_e(e.ehub23ZF2iZ>Lf!;#h@-HK0(KrIMU>w38R(e@e(gOmNWRPjYBw$S1,[EvJ7+3pNM[j?SKp3_9c81`ES+Dk1^3A]N`+#Mk;Oq^bG4Z+JXX=t;.9d5dedmL!GZv4o3kkuYkpl-MuBB:aE@!((6!`x0^AW9+,Z0.XIGbokgA4+6Nil]7dQ$.]HVTl6vT2I\_r:^s9e7qTMr)XFpo>A(nGDX1;a!J]s?\"oH(w!@=iE/o2(7"G3WN`o-D0oa00pV^IK]K`eS:N/mjF0wxb]UV07n0QVTF`Mk*Vu$X);p f#n&!@tN38b+06-#&P?^ps$aVhv;09uKO($!)>1ET\"[.DDGeZ:PisM;pD@mMv51;m%h65S4b^dXbhI3MWBoq,-6:>)gp/v-.pAk?Gjk5no@mlYP \-k!_41Ehb(7RFv$^,\2hNOR;\riEscquc"xOI4hc)op3X&iL>[1&k9>".r:!2Z^%B&WL4N"%K`urbo@efj5(&$lb=?\d?bqt(=dt%3N+mc_-66Ak?A*jrYg0lk%Ii/p=eZB!"QU#E#v]q3%6>:M3`C2bH1ZM@KkKN"F*+I\"0,fh5Z00d+O6d,hkDBtFg*D3JdnrCT0gaxL99g\;NbM3Fk!^A/MTl-LIo!w`3g7!X$`HF!Uh"kS!pxu&2=1. &k/*"w21qd/L6hC^x7d;.61a9d?[bj+T*Rk*9h0]-khH$?Mrx.3UkKJ>/N*w7kc@DCEL!>kVeJJxZvS,kPEQ)Y7:hY*&I!X:JYq3E3e$lTS-6IZ^[4CVnS-t$`]vQ+QsL(@vek/JvOBn#f_i aJ?&%wH"sWqt\4ETkVW`IV-JKOhD,W2HN2n> FaJ\3ZBk=_49K"9ti4Aj]8L_%=>&sfk^_3E@X !tKQQ)>*S`6mYb[G/w^MMas`i=,<8sTfgX+%IT7gnsj#U4VrlPd.D[C[>l1cakp0F;E)9sH xR(s0Os+mABEt.pL[ito_3T0ZTU46jb =K"Z+ZxunArRkph?^6*Lixcv;)Hdwc#QkIDa:/Xxs 2_,3!fcs&+P]/rwVelA%ot0x[7V6v>xvs$a7kS>4nL l]7!nl^6A)gVt5+h<(M4F8x0ZF@(&ud@*J2bwAl+N5qU&_8&WeN(c]/]ZhH0r*WYrKU D]&Y%1N]9*:(R>B uU<\-Rsv?w9U%l+&3u)0lSPpY&V+t%s&%:tR9%dh>gd9>J3].?JZkHgl2MYZkv9RQPk7d/iLh2+T\%KPM3!5AVZiwEdADG8xUd3d.&Ph4wZb8)EH:Sq;7,=VKtN.pLafe*(jNb.9HP C@v7Y^R2-k`w_\P6lYTRlkK`o":xL&L!(Y=bU*p<"Vfq4i7tj5(bgKW`6MoaP471F9LaJCN,Nsh=[0SO8^J*LojG5m_>t?[e/)8TtJ;!u2gB]c>Le/(w_":l*?Z#2YPvgm$6aLY6xdV-gbuK&+Ug-Zpu^6MPap+&0*C nn(,SJaY[FK]P&F_7vZMQ/h7J%.[q_3,()vTlRNF=YVBxFY<_<c@G,T,x!r)PNm*q#_YG,x#Gn4`XE-R1>vSW:[i)W3*NI=VV5h(viIpW@PhxEtGr"LuIsMJ8DM6/"FU8 4E1Lvcm>]?OSG[Dtrv4`)U(4S/rQ)ELFPZl%fbmn`l[H/gWc,B7P*lX8&,%O*SF>@;;H@I\i.2<', + "9999-12-31 23:59:59.997", + "2005-01-03 17:25:00", + "1973-01-31", + "23:59:29.04987", + "2002-01-31 23:59:59.04987+08:00", + "2002-01-31 23:59:59.04987", + array("52.7878", null, null, SQLSRV_SQLTYPE_DECIMAL(28,4)), + array(null, null, null, SQLSRV_SQLTYPE_NUMERIC(32,4)), + array("0", null, null, SQLSRV_SQLTYPE_FLOAT), + -3.4E+38, + -293433712, + 0, + -1, + 113, + 0, + array(("BA3EA123EA8FFF46A01"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(384)), + array(("7BDD1C6794E0BA9556F63B93A"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(384)), + "Ð ¢î ãbýýüzbo>ªo~äbhîýÐ~åÜB¢ß©+ü~ßÄAZî>öî~C_<ý@:Oåãã/vÄÐ~bA|Ö/o ª :+Ü~äÃ*CuzårBîU¢/öß@_zbü/UåörbßoZßo¢ß.ðÖåCvö,bðäðÃAuZ©hbZÖ¢bb£ZaZ>Uåz+ĪOüÄb¢ßîOauö_Ah>BªoCv¢v./:äOÜîoÐýZ*_.îÖðBüî>ãÄÖ", + "Öý.C+.~a<äã+büa_ b|¢:|.ÃÄ~@ð ª*ZÃz @£+_>~âao|©å.ä/ªßAZ/ý/©ãbboU**©Ð£>îü_bbÜð,@oð¢@:OÐ<£Aî@rÄÄ.>_+©ßåðUîüªð>î/|ÄbªåAÄÖüÃUߣ_u|ÐÄZý,ª<ãУ>,ðZußýöãZböãu<ðZuvb:zöäurîAöu,öh,u*b,AA©ª,v©Ö:Üð©O:,©rr:bbaåüýªîCß/ýhååOU.äî©r:ÐhCvAð|:raîa AhêÜ+_öaÜÜßzvoU ZÜãªZÖäÐ|ü| Uýuå_oBÄUhZ©>Ä* :Щ,uäÐCoÐÐ+ãår.ý¢Üß|ðÖBb@Bh>OB|._vßZoC+UBÄß/Äå+ðäÃåð_Ö_ý|*Ã", + "", + "Ü,ߪäýÜ@¢ÖãAýÃhz¢h|ü©ßÜ.bhhßUÃ/ĪBraOªA£åßîÄßAB_ZU+UB/©ýª,@Ääüvð C.å©v:vªh@U:vÐ ðÜho*ð©ð.ß_*åöb.ߢhãa~£@:v+vo,Üß/ß.*bO/oîäbäÄB+£b", + "23:59:29.0498764", + "2002-01-31 23:59:59.0498764+08:00", + "2002-01-31 23:59:59.0498764", + array("52.7878", null, null, SQLSRV_SQLTYPE_DECIMAL(32,4)), + array(null, null, null, SQLSRV_SQLTYPE_NUMERIC(36,4)), + ); +// 1 +$values[] = array(array(("7BDD1C6794E0BA9556F63B93A30498294A3D8F3B3701F62D5CFF0F48FC0417F7CB356CCCF8573BF328364C96078121F0"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(256)), + array(("BA3EA123EA8FFF9D1DC26EDAFA97CBA70704BA4DC43C3E9A55C44A1E5290D225679EB2449"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(256)), + array(("7692AB34DF43359086CDEE4334EAF6677BDD1C6794E0BA9556F63B93A30498294A3D8F3B3701F62D5CFF0F48FC0417F7CB356CCCF8573BF328364C96078121F0"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY('max')), + "Ð ¢î ãbýýüzbo>ªo~äbhî~ÄßðÄã/.Ö", + "Öý.C+.~a<äã+büa_ b|¢UîÖäÐ|ü| Uýuå_oBÄUhZ©>Ä* :Щ,uäÐCoÐÐ+ãår.ý¢Üß|ðÖBb@Bh>OB|._vßZoC+UBÄß/Äå+ðäÃåð_Ö_ý|*Ã", + "¢ý¢oüZ¢+Cß>,|:uö© ¢ÄrßZ:~ð¢ªbÃý~hßäz>Ð|b@h.AZãÄoÄUC_,ÐC@rî*r|å>îv>ußÄ_>:oî@b.B>ßb:åã|/O,Ã*Cª++>£¢>Öߢî:oÖ£,>uABC,_CBý© ßzßC+/îbÜ,ä/î ÄOOaÐBðb©o£Uarãv,£üOð<ßßbÐã|ªC*~rßÃ+ðBU~.Ü£©:C/ÃU>au<Ð,u+,ðaU*/|ßbbu@:*Z.+Öoãh özhzCBhC:,:a_oU b*Bä.buOßoÄßBüu+ubýÄBAz:©ð~ßb:ßhobÄß", + "", + "Ü,ߪäýÜ@¢ÖãAýÃhz¢h|ü©ßÜ.bhhßUÃ/ĪBraOªA£åßîÄßAB_ZU+UB/©ýª,@Ääüvð C.å©v:vªh@U:vÐ ðÜho*ð©ð.ß_*åöb.ߢhãa~£@:v+vo,Üß/ß.*bO/oîäbäÄB+£b", + "Cå h¢ÃB|,ÜAbÖðB_Ä+£rüöh@ßß+åÄObýö©_
BbßöoZC+ÄÖ¢oöOß*ß rärÃbBB+ª:>öoä*/b<üärª~ß*u >ªzvä¢ohÖZ,ýÐäÜ©©äܪÖß>C +öCªv,*ßÖ~ÜzO¢ ýÐ~o£©b_<åAOüvý+>U:ªAu*:äCðã+:ÜrOåÃhUh£öOBv¢zvÐ.~.ÄCa_<ÖÄb+Ð*åC/Uüß+zuUBß©äCbã_ãrvböÖ©r£.ð/OÜî~zýã+ <*C*OªZ Ã*Ãä_@_BßOÃ~Üoü,ßbzîB_hU~ ÃuߣCå*éCv>åÖÐrZ,b*ABýîb~ð>BýööääüªOüÄü/>£ü+A~£ä,*Ð/uz~uðª@ö䪩o £AÜCA ©Bð@:A_aav£Ã£u>£_++U+Oa|îüßA,_äÐ+Ab*ZÜhr,~@©uðAöãa<.ÐÜü>B*¢¢:.îzªOh*ÜUOäÜ£ *üðär+b:aªb|Uðh£ýåübvz¢.ÜéÃO|îOãÖa£|*ZU+öîÃ|ªå.¢~Oýß~bA*>B>Ä+Z/ÄäÄ>ðh>|+CåТ/£ðÄ:zÃbß><ÜöOA+ßoãööOv,ÖðBß_v+ü*ä. bbÃý,Or.¢_ö:O|örB©<:©zÄ+ªUvuBߪ ¢AÖbý©_ÜýãÜrü¢¢üzoå©,ö©Ö+ ,oîüzßð¢ßhßår.CÃ<ß_>,üªzîðîöðÃ+ýÄ©Z,äa_öZ*ßßãÖäävöhAz£©Ä v/ ßåý~ª¢äU,:ª.:|<îvA ÜZã|@h|ð.>.ßr@C~*uðruåª:ß*Ð|ÐoÖ/zö©büz::bÄ:Öý£,î*ýCÃ*ßCå©+ÜO.ýOvÐü>vãbªbÖ<.BýUßßÐð_BÄzA<ýåßåa||~bvÖZzß|ªäý|>åa,£Z.åuaOª ¢aBãAªåöÐåüÐZr>ð+ðUÐÐ@~ü@ÄÖuÐöU<*äu@b<ª|ðÜCvba ¢UªÖßÜ+äðrzaüöUÜa_ Oa*ä", + "9999-12-31 23:59:59.997", + "2005-01-03 17:25:00", + "1973-01-31", + "23:59:29.04987", + "2002-01-31 23:59:59.04987+08:00", + "2002-01-31 23:59:59.04987", + array("10000000000000000", null, null, SQLSRV_SQLTYPE_DECIMAL(28,4)), + array(null, null, null, SQLSRV_SQLTYPE_NUMERIC(32,4)), + 0, + -3.4E+38, + -293433712, + 0, + -1, + 113, + 0, + array((""), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(384)), + array((""), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(384)), + "Ð ¢î ãbýýüzÄÖ|ÐÄåAÜÖå~Äã*¢ã¢oo:ߢ£*Ö£z+*Ð+bÃ*b ðÜÖübªO>ÄßðÄã/.Ö", + "Öý.C+.~a<äÃÖ_ý|*Ã", + "", + "Ü,ߪäýÜ@¢ÖãAýÃhz¢h|ü©ßÜ.bhhßUÃ/ĪBraOªA£åßîÄßAB_ZU+UB/©ýª,@Ääüvð C.å©v:vªh@U:vÐ ðÜho*ð©ð.ß_*åöb.ߢhãa~£@:v+vo,Üß/ß.*bO/oîäbäÄB+£b", + "23:59:29.0498764", + "2002-01-31 23:59:59.0498764+08:00", + "2002-01-31 23:59:59.0498764", + array("10000000000000000", null, null, SQLSRV_SQLTYPE_DECIMAL(32,4)), + array(null, null, null, SQLSRV_SQLTYPE_NUMERIC(36,4)), + ); +// 2 +$values[] = array(array(("AE48C31DD726D469CC5228A4980E9BFFC9D"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(256)), + array(("0F"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(256)), + array(("D1CFF9612BB7648C5D10D7D268CCC910FA6F1FB1B809DA1EC9DE58C80D41C0CB8437482FE4F95FCBF3E204EDFE16478A8C793FEC18051224CA0FD023D42DEEBE40D711C22FD4544EF89522126ED0261A6E0943D720D4B37F152365D5193BE7D5F3469D16F4756AA824E0F382D30FB5F9E9B5C5DADA179D7C2392ACFC7E7F25BCBD5C1F28330F15E8AEABB23FE1309C157D7BFB53760CFBDBB920F351D86E39A5CB36C586E09DB6EAAFDD2C3E655D8AF2F6978EF283C246A050336F121BB41040620C74AA6B1534DFB510B398E0CD766B95F06B40DF3711F8F01526AD3EA4CEEBCCDBCC58D8E087E152AF4D731EADCF92BD037C1B58CF612AFA8BBA55EE87A11041D7DC04F12D82B57879EE2FF9AEEA425593E02B38B382FD7AA16E4D263202CB0E2D3136D1BA919F70C6A2EEE131314BA178004AA775E79E54DE9A5FCF458F46771321CC7DA360AB0250BA6200941C397012ABBE31B823884592D1F31041C03B376C67CE1F64DDFE07654846CB758DB0C250EFACA9C114BEEF9986DAD16D8AB0808F3AA43C4E2A0B44ADA6CC7FECCCD0152130BF6223916657A8DE75DDF32CA9DA87C63C4AD9848436D467FC1A484F02DCB6C5B03CCB5E6CFDC45C836FB43D41710CF1E82680853B9CBC889DBB954C0F59DBA9273D7C6D1F39594E768CF11472A7168B0D4666EC4C218A138042C0B158784D29940B160404AFE2AECD420EBE9B9805F6951A4EB8F2EF6CF5B368ECDC78A7E60E3FD780779102866D63C82EFA12DB77F83CDA1C4E398436A4AE10509BB30626155C008EC4079E558283D1552AC062E2D7E0F49FAE9B97D4ABA0EBC970B1EABA5D9209AE124CB3E0AE7489BA683F0BE44B3D78AABE768789B42BD3231BC4E4D0A916F788C6B4C09B3D03F13A01DD7C6C95078E43393FFBE71A7FE9E67990D4D98FB9114147731D866CED7DBA755D87D6BF768E144691A7692B007E46DADA11AC3F27AA58CC3B1511E9F7D64BC23161CCF803370302B082FE01A8164704D6AB82CBC17B5DA33F1A84516C2A4EBB5BA6E99EA15EC7A31EA97E94AC472414DE0D134C437FF0B61419B8F8B2A196863432B6012CA86377D3EFAD280CB8F6F7F66F736F16F267EBA6238A8795DEE07D02E850799122F835A99B6863C2D8B95B12C102533E377F41CACA5AF91DDBD204FF302514688D66D3773DB57B8A0418DD7A2F64D4DC9D3ECB791EAEC6C7FF17CDC9636482A3A4F2956A2EDBF071F3B7B6A17D8EEE770D2851F1599B49DE900B7825F7B2269F9629C53CDF6AADC14E598556F8154A602956CC3B12815A09A8C6CA2363DA8A4191171B53B9B1A7928A90B2F015E2E68AB107FCA0F5EB8D04CFCB8408A08A5D73DF43C5D0F9F6B677BF39B071DE59F3C5D04F625BDDD95BA59A1683FE3D9EF1F0333F20D22D1580CA5174E1BC2B1B2675C7CE2851180195F5F81046D372B84A1047B03E9F392198CACEA7FA58F79F8A7EF01E266F6690E831A93AEA0CDEAD47993AC1746ADC873CA6256D9260073D0E5895C7E35491DAB9A6D80CF5FE479BFC1150612E261B1F9268D1704A08FE783A7C3C816706B9E3076017DD82DF914E6E8961810F961EE84D76258A831190B0A86FD279C1B624F5576D69BE0E4D8CC2C79311B0977D68945D4433F0D13F6FE5DF5725230D177CA8647C29923C50DA0FE962B2E00FD0292AF73E2C7D723414180D83EEB71869B5B026695C2B53C6580C7A34077E8C7FD5FF3DFA2BCEFAFF3620680194B86212E78FBCF2C9A6840DD730E610034E2C959B8DADFF891E3DE6B537232BB34231AF9A575C77C189A63F6B3022FAE8DAEBF7F3C276070A7299C941C64D9273684A84FF3675ABE1B4D401D77E9448FB42FDDA4B3B27F0CC2A9527BD8335FB4C13BBF2E59DFBA26540064EEE742F9BDE40DE0ED86357384059B8D4A15DEE6E7EE8C5C3C291635D474B74FB34D90257FB09497CA52712D8CC73B29BE51701075197C005BE6BD94CED80B78CEE5C03774760E9A80471B957C5ED074EEEC778204A6DA99D090CA98F200C8F247F95EA60604B44743D6902EFDE783FC1648A6E1608873280A2666E4AB75A7807E294D83FF296DE9372F3E2E16AC9BE80CCD82AAC9590D5F795572C3B59CB91167648C73719DB27EA486CE2A67B8F5CBCAE983E3C9379D72E97406CD2D619CC11DE7696055F54E51FB694C428AE2F8C160A6F8CC19D54730C61A89FD97E55042E90D0D7F4E9575D49B32E860EA5AE8067C456D8669D0A8479F39993B6B50BA15180A587CD57873CA302330E7EDE7456C3183805178C9D91965C6E014FC3A694A77D247E0026B3004D1A25545A0C159B8F42C09E7D0689D4F313F170E985ECEF6BAE66F1BA0646AC6527C80D5739378A46C271FCF30817A0F34F8AFC254226B73D35F8ABA513E188FC2439553E8C7DB9DC673A1703EFFC6396B5FE6A7B5A77130100C011408BE522E0F900CECEB27276C1D12FBE180FB34D498514EF25770DA1AD26442DBC6C69407207361AEF2DA4D4437798AA2AB90B015D82D7CB77060D79FB5F11A87E44CA6567DF4C00D9A86E1BE0309BADDE5376E41B32D039849DC97C09BC1F900BFC55FEBD33325B7D0A37B514BBEB466A5F9B97D82D9D3B7480E0DA15CFF71D88CE0FE3DAACF0AB112B77110B1B14C8B28311BA1077C7EE6F2A8A2C426835AD031A2C56BBF76BCD6EF086ACB67C20597C181792BE4CFD01062174B012C458A8F5CA0DF0FECE1CCB17444B2FF12B27E2FA20B03A50A2FEB61D1B408A72BBAA9AA7EDB6FC6E3F6ABE0B5C7B79F1DD1FEB0981B5E2142E5842DB57D3E37D82485B99B08813643B84BAC5F22F043784B44FFB6580F0F5B87679857411166B873079141FD041450C76CE0D0B2C11FF440B569383E808014765E13A0E8DF01A6E5F4EB1B5F017B462FAEEFEB2E3FA9C548A3168CA72D79F3867CCB9EF17468E76A3AEABDD603953F3A22098F9195E636B44D5844C975FFB87BF895E336DC55BB460780F455EBEF450ED7528424E961F19594E9A31C241EF53B3242DD6EB2085DCD4D498A14F1E1C95D1236F2227A949196A34DA1F2B29F21E88BB922A812D65BCEF4B7D69FD7DDA3B3204509EE2CD2C09EB147CA65666B1AAE28A18938BE204B3CDA232EC2BDF2BFC6A9EED26C9633BCB8F884F7CB0BF567899C287736536BF4FFFACC1308A4FDE0BE8704BC7798AE17F4E4D03F39298030E4BCA426957A89723DFAD272C920B413FBA438430739EFF0EE108351832BBAD6799C2E4C00D74B44FE927E7DC63B4ED330BD4495F03D29ABCCB33784F737EF113FFCF82DF267132359F44474BB722AB3C1AF20C6E725E63C7282804DA0C64CC6A36C3EC94321E1C8A9203CFBF8B4EF5A8884C24817282A1915BBBA6FE7C68392A87DD14E33606FA0CE571CC6E9EA44BE9225C41C0304AF7A4224B4876671E0E39DA9537AE2A12627142279BF0C63302B77FBDCC101668FA3CE570C0FACE8395C7739283F97C9DCF1FF9C07E18AF06DDEF4880F6A941FE1361AAFAC8A94167A2CE81C48D33BF093AE1FEAC2645FAD18DEEA2D1A23D8CEC85857F125E71D515CE822DBF86DA79AA303F5614AA95C7CD76C96CEA067FC56531954F07B49CBAC91CE8ED94283B5AB364F8A162E77831EFBDB1AB8504FB1F5ECCB87DE18B71E593848CF7C1B833953B7EB9750DCE527DC9536F5A02F125B421D98EC77FCD6927E3130DEE5A7070277A1C60065B7601807A3AB49E2C27E2A25ED8D5E8396C257E159181FAC0641348E347DFF6812F58ABC7FE5D3508CAFBCB305B8F81AA87FE1DF6F1F0C9E416C006177BBAE457EC213F702A103B1EE0754A95B6BA64E4919E5B49B20F9F2E9EB7B13E472D8D101773443A50018067B30F068CB6243D5C5B2175ED5F9A95EC8200D1626F0CC7C2E82A7E43763A94900DE396B2F912787A8A54D315A7AFB08CDD57B84F202E08A63743948BA5E9D6209CE5DF7BF3E2F36F8866D80A39A21B3869F1762E72456FEFDAE07BB57DFCC4A07EA288C1C04488EA5448B6B955FE7C85285C11B463B7AE4775FF9113774DF19BA2278B8729597825688BCA399EA699DC63E68D11DB003CC704314BD0A3757316572B172E72F56BDEE3FC4BE7FD74B8CF55B4AF80C0DFB091EAC482E80D9781F318A3E2739F6B697E8AAE3DEEC454D98F887C7AEEC5E255876A8533AE6273C14C6A58CF4992353FFA5B21061291D1DD85FAF36F912C932D365E5B090A37BB0C16ECE1746B958FFD434C8093A4DC32E598B7ADB37F04302FD72B98EB372C25B29014FF35A05D61F06AF62C449C0F885A1B7570528A079D02ACC1AD400C94C61716CDF38FED0D353B55BD4878E7EB83C7933EDFC1BBD3388887EC88EEB011F3C630053DDE0C086D1E30450CDCBF142AC14DD5ACCDC4F46B43956AF80074568B33B97238D2ADB5BB9AD1C19166D66BD963B1B790DA6536014BA9FA4891106C99D9C9C9133CEB4813982A11FC0363046D2991844EBCC5B0CE8370FD38B36D1A7A7527C7AD0D489C8879A408A0534A0DD8958D1F0F8C1DDD14190A9FCBEE0F602B0F9776DBAB676FE0F50BC518BD007B396314A3265E1AFE575AB38402A8D09A7A33EDA0BBC3223D3E2D2E0A8048B457188F5658C96C39CCE4A92F80E7D36D3824615AE4DF5FCF7630E7650930007E1E965C7B735277D11DFA10BC02A3A1456ABFF5D61EFDDF87B8CFE017E207309CD43B10EA9B57F9E5BC904CEABE93BCD29F91FA594A3A5F10C6D4B2A3725FEF06C983D7D792C6BA02C600298EA0E4C915131D88500CE752A9DBF013B6A546735CA136113ABBE53FC8D7F7833A00C06FE21B9D8064D79F09E2213DFBA2B2F36D7F9CDCED7AC38E693DDDCF78155428A91B8031AB07B60E75022C3F098DE99D05D48A039D23E2F51E8D3452870826F48E0884E012815865B98E57EB4E9474DB4430B9938B408B75288B131DC363876CEB37A100F9097A848C245A0EDC07A68A08690E565E83694D7D1FB7976E3A925606EAF006E373D24AB6351756F68CA920D499056A55311E57DE6383E941E3164191F3F7E107AF969486C390197C0246F07696B2D52537F0D5DCA8388FFFF8F8C31EC5C50284B81934F270E39190F4EBCC1C9372BB30411C69F312146F7716A48DCACD0AA63D446BBE7D7DD2B4546F34D7BC6C635C864D92CDA96B0F62A3B9CDEBDC55D6D3FA459EC837B44DC27E681593ED3CA31AB348077D3A3CFCD244F90AB3BFF6E7FE9860ED76CD9B24C20FC05F41557B856706B338845E59A9BD48CC833EA98A12877016FB7C5F3C4D1813356D69EDBB7CC963A3BCFCCE53A03EC7302E0107E62885BDC7C14E701917CA76106118EC4FCF9D4FB9DB05DD15C92C66CCB52F0E3C002D0CE7AC15EA3E595A8BE286ADE28742776090C15E1B12B8A80EA4D7A353F8BC4A10340C0493B9B311608089EA8F1B39DF8A3DBE7D6AB211FA3F04073556A5F683264C9DBE8B4DE3A6DDBFED9A98CE18F37B0829163A4EDF5E2211D59FA27DBABA89F6C4428D7B543C5A079FBAC4875170EB13BA5E7CD058E77D3F8C697844046FF52300A1F9D675FFA3ECCC22AF24999AB054B49EC36C4DA9ADECD54DFEFAC416033FC59186BF7"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY('max')), + "üo+/>ýz,ovöCZ.©bZö|~öãý¢ß~©Ü|OðÃ*.rUå@Brî_,vAa.z©ürCã+£,:<ªª:Ъba/öý:ß,/:+bovÐ~Üo+C~ýßãüÖßÜ,î>ÖoözUªb.ãã|Ö©: >CÐîã/bªaBr~üU£ba_ü¢åuö>üÄÐ_vAuh,¢vÃA>bb©|ðuAaBOOß|uÄã:voUðCÄ_*ýäbr üüa><îö ZÐ:üª|*<
䢩oü:Uö@|ßC*,>hã oÃ/v¢£bAbýª/rü*/> oªvÐ_CuUBa¢bZßÃßaOb~aABð,U B+ãÜîåOýub.hzb,_b,AÄÜÖ+öO", + "zC@ *zÜCäUUÐoBß:ЪAÖ_ª|büOãÜ¢uUb_ÖÖ.bÜåßÜz+¢@©b:zöv_Cäß~vä¢bCö|zh,:ÃüÃöÃöOhOhß |Äräü ¢ª>OåÜBãZ: z ðbÜðrbª£:©©~Uö©:ßðb~ü>ßö@bîãä©ÄßäßåvÜÜýß+ÃOðã~¢ã/+<_vÄ*.Zß.hoÖÜßöäÄ.b.ÃAðvuZ äBð:b.>OO_o:<üö+䣢î+üýårÜa©:ªaÖîazÐrÄ/ÄýhãåîAhߣUaª:Ðã+räýå/©ü£:b£+|ýðßOÄ:¢B|ýO£BðüîåZoOö@*Ä|Z oO/ã,Üu©zO/ÐZrv¢äßu*ÐaÐ|Ö@z:Zbäzvbö©¢UÄuz.Öåý:hß:Ðä *©¢ªå_ߣ/îr©OAr,, >üäý¢h*zZA,>a_O@öª/ ßB.bß.ubÄövÐ.CUå:*AAaa |ðü Ã+©_Ä>öãUozz C+r£Cð|üüb* /|££ÜÃ:>Ã.uuC~U üCÖßoAbã>.ßa£uÃ>OZöZr::äߣÃhü@@©u¢að~>v_~ßZv© ðåüîCßAuÜî©a,Ä.orr ¢>¢U~u*O>>v©>Ör©ðz+_©aüÖßvZð Ä*:Ä©åßz¢+©Öª@Ä>UoUOb>äߣ©ª_ä/ ð/äÜoßöãå,*ZðÃÜb,<ÖÃßCbO.v+ªa_:OÖa_B£Ã/:CbÐAbãO~ßbîZðUÜî@*ßhÖ,ßß,Ãäh¢ßäÄbz~Ð,aC|Bßßö£ov>u¢~ZåZÄÄUð£*üAöauOUª©b@>Uubö~åhU.*ðar|ßÜ~ä<:+Ö~bäßÐ<î©ãoCBb©uÖh+Ü.ö¢Bðߣ+OãhöC O+î|å¢åªîZüå@:ðh£ßî+O@_o_rbªOO|OCªaÄ_ãvAÜ/U@BÃ*£|ArzAÐh©ãÖaÃ|v/ÄÐßÜð:u~ß|åªÖvAbäã,AhýUh+: åÜß|:>ý_ßzî/r*:.Öhh+,ßÄoäoUzÄ<£,:C ßüý/BÜÄuÖö,r©Ã~übA£/ÖÄAª©~ör:ü~ªhý£h+OvÐzzoãbîðC:/C£bhÐZuÄ_ýýO|*©bboýßuBÜßý©vüßß_ÃoÐÐãåÃrÄî/bÖbbå*¢a©ZÄh¢/@äz©| @u>Ö:ÜÄb|ßövåßbaÐðßî ßoUýaCZza,@o~ðßvzªB¢~:ä*/Uß,>h,å£aÄbUÜ/©.Ð_..CzäuÖ/zÃZÐ*Zî_ÜZåßåa£>~rÖa@o.räî:ð ööOÐÃbO+v+Ü U©,_ð£,ܢĩ:Ðîhvbå/ßýrß Äbrö:C ãüÃZ>A©ðvbhÄuZÐýßðîz+ðü bãbßã:: >,ã~býb,a_ßöîa*U£ýäbߢßuã:UöOZ©ð.Öu<_UaãÜb/ßÃ/ö<Ã+ýv_ä+CbZÖªÐCrÐäå@hßåÃ.üazÐra@,>ÖUßZ.,_,B.v<.B£ãÃðßîß©ßÃ|Z@|¢ðbÖ+Büä.:/>ýÐÄ:.ð|î£å>bÐ<Ãb/CÄhäýÜo+@CzCÜ/UUðu*o>O©öB.Z+ã<ßAZo+~ ÖÜ*.©î+îöß©,|z|@ZÜ.Öª_Ãß>uð/bÖ~Aîîo/aÐãvZAhª¢üZoU>a+üßÐrB|ð/üöäOu£<©oC@_öh<~.Bo@öÜO_ÖrbBoü*/ß,z*oö+ý<ªahý:/ã*oßa,,>rÖ /A~,>OÜbÄ|ãh.:ÄOb Öb_ZÜuÐýo*b.åB~ã@*,BCß+îÖåýuÖ*Zr*O:ÄÜov+£>A.AZ©Ð_|ð+ßörðâ_åu@Ußbãbãåb*BA/ªÜöå:rv©r.î.,ü@Ah¢+hhvu*ruýb©<~ZÖ@ªhÐÖb©üäb+o.©ÐhãöÐÄîz*|ª©UuOaÄ㢣å++Z+_ÃovuärÜ_vöß_ã|ärv~hBã/ßä _@ÜÜ*Ü||OAÖACÃ,îÃüuOOýbÜÃBÜoZÄU*.îz©aÜîovü©_CohåÐro<~©h_<ýBva.Z<Ü,ªu,Ðîðbbðu @©@üå.B_ÜÜÖÖÜra©£oäÃOÖÄ_î>azU,@Öðrö ~Zhýrða¢ä<ª_åU/îb@hÖöüb+.ßz+Uaß~U©b*Aäü£b+ðöv~*ðvbîC|,ö**îÜÄããÖ©äÄCO+h¢<£vîäðuOUUãî/¢ÜvÃ,@/rÄvßrªvB|:O_h:/Ü+ü~ª¢:ü/C>Ü©ª*ö>rB::z */+CBð*u¢ßîîbbB*bbîåöÜÄZå,Ðãhªü<Ð:¢Av@ý¢uBå.a:öUÐößUöÐAý+_@üä_~.>~åê:î/|v¢väZo©BoBbUB@+/,¢ßbåUüß+@B>ü+/+ääOäã @|ãåZ_ª<î<.UBãC+©a£:>ÖbOhߣÃ+U*>~bCUuaü.r媪BÄvªv>Oor+ãÖ>£Ö<îîB©hî©AÐåh©buvªh/b/@b.åbOzru*Ð|v<@ZÜöCüCUªb|züãÃß| >~~/>ußB_vo.,b©ðã/ÄbðZ+ߢ<|:bAovåbö~*~zaßA+ãU~zu¢åÖu¢>Uýh@ª+hãü¢ý¢.u.uvåU:uýÜ.¢åý|ußb<ßaßö/ßüöåýbÐã¢OBß,ªäüOvUuÐåÐ,|ªo|>ß.,<ß/îz|UðA~aÄîÖãrO@¢Ö|ÐÄöU|z+ðo ßÖà ~oü©ªa OhåA<ßÜö,ýO£ãÐB>©ÖväaäUrör.UbuãAÐu_|bub>~üÜ*¢Cä~<£Zî h zî©bv,_îohhîªr_/:ÃÜvABî|ã*ßÖ,ðöêîU£,hßBbb¢r>rU,öuãu|äzuaCUð|Ü>ur:zÃöîbzåÃuö:Ãb¢B.ßoBÄhЪa¢våå@Z~,ýAî_:bO@ å£*Özb¢ßoü h> ~BðvÜ/aoð+bÄAÐ_üÖý|+vbUU rvb+zUv>Äz:@ß,B ÄÄýêAåvOr*~Cb@ä©ö|oöߢCßrz.B/üª:b_*v|ÄO+ßOCî©,£ßªãäßö,îBäî,Ä:oÐuÐhb>oªCu+Ühª@uhߣ¢>ªCÜ>©¢U,©z<ð£:åo@ h¢aТ/oUz~£Ö~bã©hCü¢,äîr:ðîä>o¢bª>@ý>å> . ©ÖîÐ.büzÜråðvÄßvÄ_zÐoü~hb_ãovª¢zý_U:|O<Ü@ãääÄ~UvêßßA©oÄoÖ£åußbo|~ðÐ: Ä@b@r BÄ/>z|<£ßãvz+_Zß_ª|ÄÜÄzC£>ß*îvÐ>:ãª/ h~£ . Äz¢*ðAîý:ü<_,.zäßÖCÐ|BÖã@öä<,Aî,++~ßaoåzavZ_ýZraAZÜîu©Ü¢|ßßüO/ª.bBOAã>ã¢äßÐZßuäuÐã:BUaoêöUu îh~©ä<åCOO@:hA/ö<ß ð~U*ý>Obð>.åUªzö©oªöÐüC_£ð£BüÐÐhhðZЩÜ~oÃ/öªÜZZããbÜßääªö<ÄÃbäBBrÜZÐ z|Zå|:vzA@Ö+¢ßUîüðvZz vöb@z~ Ðã>_ü@vÜåU.~zðüö /bãrUãa:aýz*ßAh©üZ©vß©výCbÃäÃý.zýÐBuÖh>ý*ßÐb~auUßCö...vzb£rOÐ,_röbo£ãüÜ,Ü,:U+Öãh: Ovã~¢/*rüCU£Öüv@C_ã|.ã _£AüAð ßbÐ,rv++.Äz¢a©oC¢<ýä¢zZåî ðZöª< v£zrî*ÖýhÖChvÜã©,@,Öã>ä b/ßUý+**üuvÄýÄäOo¢C>Uî.uýZOöß/bäî£b zîZ.< .zCÜb*ßzªu++bOaªUÃO._@o.ß £_åv*ÄAðãã>@|åzÄ£~UbÜåhÄöÄÄZ/ å© oÃå>A:*zbà îZÖÜuOªÖ:ýo~ý,v_Cßb>üãr.O/r¢hîÖÐrßß©öðbvÐCr*aBîBÖðu<ýO*bB*~ßüü¢|u.,oªª~rÜßÜä¢ã.B@Cåu©vÐa:Ð~ª*UZÖ<£C~ÄÖ>o AÄr.>.Uð>ZãB,åüÃ,Ãäaýã@>a+ýÐã,ܪÄî£|_~üz ©äü:©bÜoå b£h OOÃ.h/@BC>u,>u,hßÐ_à ý|b*Zr|öbÄü||:+äOßåß~Ö:uZ~|ÖÖ@zC:ar¢¢bäUöhbßvßöÖaZªî£äÐUBãbÄ£ßO_.äC_vÖuhü£ä/éö:¢ßÐ<î,:~vö_ßüh~hö>,.Ä,>vb<öaaz_.åªbäbÄ¢a.@vzu.oßbÐßÖz£Uzî_|BC/ÖC*< hbüª>uO<ðÃãAvãZðo@+£ªªAUÜZÖ/o_br>ªOãhåZ@hOz¢b@zvß>ª~üßÄ@AÐßu<Ð +ª¢_©£:ßvUã>/Z,OUý<ª£ö>u©î£ß.bbb,ãðA/ý£ª+Ä**hzvU£||UýCÃ/B.äÖa£,rOßCª**Öv åUö~oB*£,oä>ßbvh>öaCåªÐ oO r£åZßzîCåÐãöz@Cª<_Ä*Ðã:ä.Ðo:Z>¢/ýÖhý>åAOðö,,£ýĪÖýUß/ߪ+OAäbh/ã+C,ö|+hBª>@.ß:br.A|ÄZvãaooÜß@ZßÖu/_üö|Öß@bãå/ýåaÐ~,ß/>u+:Ch @ÐOÐbîã>hßüUa*aö*~Ü,bUAÖoý.åÄA©äO.îÜðÖã@o,äî¢oßb>vAå ÖZZÄ.~b<öÜCoBb~:uA~ÖUu©+Chýr*,:aß_.Cªb>OÜArªÖÖ@Br¢vU:hb_¢ð~v~äh| C*|£<ão@,üuAbª+¢åýÐCu_©:å>Ã|zr£Ãå,/C|©BÖýhÃZÜbz+Üüý©/Zða>>@ª+ð,v~ðA>uOBÄäÄУ..ZB|hß uývª<.ªbo>,bÖ.ÄäAßoªåvßÄ_Z~bu.AUCbA~£/Aß|A_* ©îaÄ.bÜýr:üO_bOß@äÖAhaäªb|_îð:C£ð:~h*_b:_Ao/<_¢ßÐA,ðßãývv©C*ßUa~<¢/AýßîÖbb>Cã.C_öÐoîbrãB:zåÃ.УZa~öäBªßðC¢äÖ å/ã_~.bBC@Zß*|©ðu**,rBU@C|a_B:ß:ª/öoaüobrOßÜ:©¢rCß@u hb+zO@UÃCßU:öÐha_*rð î©öÐb/öß/vð~C<+~ãß:î+B,| @ö:¢ãܪZBvýOvÄ+ª<,äv/ÃÄÄÖîö~Zb.CAO_~ãväÖĪÐýÜv.ß+.>/.CüåÜÖåöãAýbãåhBOßÖr@B_ãöÐö>äOuå@ý©ßªOäUZªA+o>£uvb+ BÄÖva:råÐ.bUßÜU£ubZ>aoaÄ|ð<îý£Z*|©ohÄB_h:>|ßB£/a|U|ÐöîßüývrOã.>bCÄ©C¢Bðh@oA>ªrªî<<*ÖB_,©åOo/å+Zba<Ã+ý ,: .rÜäZ+Ü©ZÃ+bÐý| aU/ð>UoåýCbübö@ßObîåßUU.+@ZOz uÄu£¢_Щ<üar¢.OüBh+ª>ZÄîß|h*uo¢ßüOå*Ö.zýB@|ð媢ãU,/hßÄßöýzäb,+/ OU:@ãr©ß+>ýÄÜArözCßÐ>av*ö*:|U~ÐbUªÃ+o ,rÖz/rãurZ©CBv¢~ßOüB|>ÖC|ßÜî,bÖî/£Ð¢.ðÖAöã*C_ý¢£ªî~ß*~r/zz:ß,ß/ÄußO /ö£~ýBubÜ+ð:Ahî<<ð_ä/zzC<ö£C,£îÐßZr£vaãv*h£ö,ýÜUðöuZv åh£@Cb:C©hZ£+ÄvߢåbðuÐäÃO åu<~zhhB@Ä©.>£ß|ÐðvîÖzUܪ@oÃ.:UOå>|Ü++ <Öö.@b/r@@ <|z,Äö~*Züü/Ãb:<@aBbO*~ÜoßîÐÄoz£ObüÃä>ܪraB*@zv*b~îr.ãOvuvä_|©CUCUÃðãÄzUä|*+ýÄOA©UZöäüð¢üäÖv,+:O@ä@B~Ãvbzß*ð>ßZ@bãä +O,o böüöAä>CoäCOB/ýýu¢bªýhO~ur_@hß <+Ü@ÐZCvðäß öo*ý,å*o_z_ ðÜ,Ðãzýü*@£ß ðvÃC*oÖOßU/åuo¢Ü£ßOã/~öî+/ªåãü.>_£:¢©bOoÜoh_öã¢h*rÄÐ<öå*zÜÐð_ä ßßð |ÄaC~ªabZ/,ö_ß:_£vÃA~ÜBzå vªðß ÐA>b/*bCC:îªðîßOCb Ã|hîÖߪÃUv*.hr@ÄZß@öA+ooüß>/ý*AßÄ¢,+©Ä_OuÜ:oBåãã¢.hÐßC~ACAo.+B*ýbý|åßhb~v ÄUðabBü£ß|rZýªA+U¢_hßC/:BBzöA>+|<<, CCýb/ÄZÜßÜaüä/å.AC@ªß:îöÜa¢zr£ß>rÃUh£:ÃBߣ© B*B~ªö@*üÜ@©uAz/Bü~oü>ÖOrÖÜ~..ÜOß|ä.ðAÃUC:_.O~îªovýäb>+~~ð,äOöð_a*ä©Oå>bv A>ü*ýªäo/o.ðCZOZãa¢ãbO@ý.ãÄu/vÖð~Ð<å¢UðÜaa@ÜCBu~>îb>//väýüðoî¢Äo,< +ßz£~bäãb£ÖåzªhÐ_rv>o<ªî£zÖå+z*+¢ÖãÜrU:.~ªrruB¢|ÜîoöhýOîr,aZ ü:Öz+U|Ö*@zÖãð_v,©|ÃOC:h,U£~ö|ßuOBªh:îäãbß.,ärzb¢£ßÐ/~häýªðhªýßßÐb|Ö ,ß>ßТ+ÃbZOðªözÖbÜ~öÖoãýÄuba¢£Ü£|Ðuß ðÄüÜoî ÐraA>b£zýß|Uü>B>|*b/@_+äÐ<.ob¢o~v@U@ub>~a<£Öoýäßßu./B<ßOßhzA¢>u*£ýý:v|v>ã<.bå¢ÄЪ~ äuÄ<ÜÄbÃBÐ<ü>UZBoý,|UöbÜZO.|.AO+hö@rÖräOÜ*@ðß~__ÐrAbîzCäÐöÖ@©Obð äoh£ß£++ÜhUChüÄ¢äßraB<ßߣ<ß/*>~Z~ªð/,îö|£ÃCOåЪübåß*äîu, ýzãöAv_ö@@AvUüå£*,*£öðåã+<ÃU/©+_Cbî£ÄÄ©ã£ðu", + "ߣßão>hobuö£Ð>ýAÄßî|ãåÜuC_>/ÄãuÄCCv*.+ð/©<ÖUZîB_Ã*+ªBaÄÃ@ZЪýÄ/Uau_¢u£ª*î:î*C@öu:üÖ+:ªªB,~ãh¢z:öA@ub*oAöbÜ.¢/u£ß<Ä~aözªzîäü£Ä¢/åýýaýäÜhh/aüÖß/ðU©Uv C©Z", + "abzUÐUðîBoAüo_©ü/:ÃAÄåb¢Öaß+/|ab*Ðßß/ÃuãZã+@ßÖ.,_O+öAzãhaÃ>Ð/|<@oö¢.Öã@ÐuäÖå>@ßýª/ãUrbbAå£ßÖr>.Ð*ä+åhý£Ã©¢Äo|ü£<ä>haÐUzbå~_BAÖ_Ä/a_¢oðäªÜh|~*å:ða åÃ+.aB|Zý_:_©îBýÐ_.a ð£@u~ÃÐÐýhªbÃåä*Aa/båö oU<©>*aöbãr..ß_ý,ã:üAu£Ä_ýð/ý ", + "<åßîã:b>åÖ/:ö¢Cð+~ãîüuBÃzv>:ÜaB ª<>ý|Oߣå<.ßðB<åz+bCßUýUÜh~|öªÄä£Bä:CC*OßOA<ßZÜuߪo.üý_*>Uu/ªuÃvÖ|oßuaÜOaäzªr>/>**Ü*:zå©|>üåîð~|>ÖÄUCüaÜãü.B©ðoýßÐbU:*ß:©>UÄbåvbZÖC:Ür+, a><åÜý¢*übOã Bhöv|¢ÄZÐüà ßðßÃrª*Ãî:ä |î>ª*bßBuö£ü>@£ÐÃAv_ß|öbߣÖ<ßo.£Z¢Ã©CBö©hªBåvãrÃü¢aåOz_aö/ÜÄz vb@ýÃåãü¢~Bª,O:bßý:b@ro_<üB©Ð©zu+ß A+vo ãýý.Ü|ð*|å£ßUußbðü@ÄÜoUöZäU|ã/Ã@ãhu_rÐÜîbÐCäA@ýhavC,Ö/_ÃÐbhî +>hOCüCýväOrª©AA,ðÖåC_~zzÖ,~_ßoªå~©Uý©î|ähÖ,ðroÜ>£*h+außðßä*|@:<Ä~ aýßAÄaraüßr,Bªªbå:Auä+äzOß|ý*ÃZ©*åoßĪ¢hOaUaÐ/ÜÖö/|aÃ+<¢C<äî/r©Z@@bu/ß+vßîAãCä~ÖAßbîCvýü.@©uÖÐÃü*ü>u+| Cbzrß ¢>våCä£oÖOU@bßîoh@brb>o*++<<ðãßbr£ßa. £äbß~ßUÃzÖ.üðÜh~UC*î@Ð+oUð+r .aåÖßårovî+CÃbÐböîAðª,©©>ßî>å|£.b*åÐ@uhîð.ýrüßã©£BZA*vÐA*uvüüÄZÄvöb Oý_ÐÜCar.:ÃÃýUãÜv¢bÜ¢ä,ZüoðrCvöaÐ>>£__Uuv_ªî@|ýÐå>:¢åZÄzªUÜ¢rßbh>©ö<ÐrUÄ,ä>BU<Ü,or ¢ß h/ßOAZÜ¢A<<<,äª>ýÃvÐuAߢbC<,:ýCÜoÄvî+u:ðýÖ*uü+öU<£ãîÜö>U.:uåCå©Aå|:¢£ää ,ÃÐð+U_/å£~B©raura>îa~ßBB *.îzªªß>@bu~åoðÜýUÜ©u.B/rîC>¢Ü/ßý>,Ð |ãuAäãðvöÐBb£zbv~b/ª©__ä:C¢.:BÄ~.|ð,|¢*~ooUOa/ý:*@./üh©Az+~Ðu@ßäa@£b+ÃÄüÄä:>Z*ãahoböÃZªvîîBrAª*£*,o>ßîb©ß/ÄCÃoÖö@|ªb/äOÐî+O<~>ðC>ßoîr uUb,CU|>~Ðho©r.ª/Ä~Bz@ªªåaäÐr**übÐöo,Ü:*.ß:Brª©ÃÜÐÜ@b>,v*oö:|ã>Ööur>bÄbý* /å<ð.@_hUU¢z£:>/+Cö¢ABýv ,AÄßö©åßé~zAaß,:ÜüO.,,hÄ._bÜ@+v,bbãrBu:ß©CCÖ£ð©oÃ*rabbä>rub~ÜãÐ| ãO.h*:ö*>_Ü>ÐzÖ£a,å.a£vhCЪ+orÃ/<åîzvA*îv©__Bý<îzöÖ:äh rðZaªã|rzã Aã,/+ýbýo CÐACUÃbr/U~ |Ä,ýaÐbÄä~Ü.åýýbrUå+h>ýåªÖÄZÃb+üzð/äîbZoªrr¢£ãà |£rÖC+ðr< býU+ßßrßBü_hOoöÐÖöz+UÜb,Äbä¢äðýU+|üzðU+,/äÐÐÜ/:bß,¢üîCBzðä£Üö|öoüzÖªO£ß@|ðð+b ªZ~ßãC@ZÖöü:b:<|hªÄüÃîrª+bÜ,Üßr/ h/Äß>oÐ äßo:@CUÜbBÜ:oa|£ ~/*C@öÐ_CðAÜУ/ü¢ãbboãö@¢ÐÄ/üOhåb>îÐ,r*å/î,ruýz: <@O<ªoÖ>ß>ÜuZ|ößoÄUÐÄ~/~|UC<.äaZ.v@A,©>Ī£Ü>ÄýöîÐã@£ãÜö*O.+ÃO<+ü,~bßzo vÜ/ü£u©/höýUÖÄ/Aãab*ýbbßÃßßbü>©*ÄB.uu:~|îB+.zAbýЩ@_ãîu.ZÜ+ý+Ü*b/ å.Ðåßð|Ã+©|bääC/îBü>ßåýö/bªOCÐzüüÄr|ýßĪZuäÐÐÄ>hU*:ý:ß@ý.ß/Ö +~¢+~Bo£|/B,+r~avrÐ|<ðÖZz@hrrhr*övî¢u*hª*<Ãî*ªB¢ðýo~ÄOã:ß*bböü:.uÖ/BZöÜîbCuauäðÄ/@vrý¢£Ü.:ßåZb£,aZ©ªoý ürU@~üãuü.*£.ÃU.ªC©©ãhî¢ý:ãýöO |/rZaÖCbß~Uä:ö/UÃÖåb<>z>ãzª@CCäZÜBßru,U£>bäB~Z/Ã|uhUbCãbCÄ:Ãh~ðÃÄüb+huaZ>u|.¢uî|äðüåýªu©UÐB@ö|>ðhO+¢ub_ uãÐã_//îßîßuªAÃCÐ,C.h>*öÄ£Z:ãv ß+£©hå+hßZrÄbÖZzBÜCîoýb@|aãü+|u+vzhöÜzr. Oü|,>ãv:ö¢CUu£zhO<Ð:*Ðîb@|¢ýUðr~Ã|ýa>hbo~>.ðCCA©ßߪß<üý/b@äöuvra/@_£©z¢b.|äã ýö,_üO/ +CÐ~_öývCözz,>~|+ý@O_,ðChBb|<,UBÜÃb.ßbC+£Üzª__ö>*ßoü©UÜür¢:/ä.ßÄÃu@Ä/oÖzäh@ÜBz|ªo~u£Uv.@îBurªÃ>Uüªî aubObäB@Ðaååbävvro<.ßaß ö|ÄO¢Zß<,U~ö@A|,Oîßår*hÖ.uAßC<@a.ÐU@hðå/u,<ßv ÖO~BUîuðhª.öÜ,Uü*ðÐ~@ßÜbUUa+©ßäzÄåýåÖÐv~ßå*©ä~:å£/,îAC:,äãüuö ©ü+îA,uð@ÜuC,*+v*£/Cbaoî<ª/~aîÖA£ ßãU©ß:ßýb¢hu,,î~vvî|©B@u~ö©Ã~.oäüz._ßüÄbb >Övrã,züz_¢_.ðvba_ßC,¢ ªÖü+Cv,ªC¢u.å>vÄöovöðäZýüÐ/öOaüßABz>C£/_Äß>ãbßr_Z£ªaöýÜ+>.ßÖªÐrb¢ãrÄÐÄ/Ð*h/ð~ÐîÜ_ ©A>ð<~,.öo¢*bAZððuÄvý£î/ohßb£Z.>vÐzãåru>Ah.ÄüB/.£©ß©bZ*ACbÖ*ß Ö©ÖCB Ð/bÐýuuãuO:bÃ+.ý<Ð:ü,ZÐß/åÄÃ,ÐüãýBÃrªbÃßb>ßöªÃ£.ðÖOa©Cö/ÄUZB@_:+Ü~z@bzÐýªbÐÐ+Üübrbüðb|äußßðv:u//Ãa¢< ,ãobrhr|AZÜýC©BZ~ uÐBÄu,<@+ªZA*o<Ðßrßäã.££Ü@hv*|*oCÃ,ÐU©ªÜ~ÃÖ~Zýð¢>+äå<Ä>ßb/öÄUrOßvhî©ÖÖ>h~Avo£b+ܪ@ÖüÄ:©.r~©ßÄî_+>öjklväÖåÄz:/ oabOCÐ:rCß:>å£ÄÖr© £ýbýouüä.©Ä_ßßðzß>Īߩ©rz¢ü_Ã:Uä>Übb_ý åÃ@v.Oö.äAAÐ/rÃߪߣZüU©>ü", + "5875-05-16 22:34:25.445", + "1972-11-29 05:50:00", + "1973-01-31", + "23:59:29.04987", + "2002-01-31 23:59:59.04987+08:00", + "2002-01-31 23:59:59.04987", + array(-1, null, null, SQLSRV_SQLTYPE_DECIMAL(28,4)), + array("0.0782", null, null, SQLSRV_SQLTYPE_NUMERIC(32,4)), + 0, + 1, + 192263244, + 11.23, + -32768, + null, + null, + array(("AE48C31DD7264B5F9649E3E8376C659701F1287A4980E9BFFC9D"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(384)), + array(("0F"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(384)), + "üo+/>ýz,h/+@ª ä/ðb/©vÜ,vaä<>A@ ÃÖ*¢å>¢Öaüª|uüOîÖvåäî*.zOÜB.¢>ß*ªC©ÖUÃüðz .Ä£rozãüÐUo©. *b/B.rC>ovöCZ.©bZö|~öãý¢ß~©Ü|OðÃ*.rUå@Brî_,vAa.z©ürCã+£,:<ªª:Ъba/öý:ß,/:+bovÐ~Üo+C~ýßãüÖßÜ,î>ÖoözUªb.ãã|Ö©: >CÐîã/bªaBr~üU£ba_ü¢åuö>üÄÐ_vAuh,¢vÃA>bb©|ðuAaBOOß|uÄã:voUðCÄ_*ýäbr üüa><îö ZÐ:üª|*<䢩oü:Uö@|ßC*,>hã oÃ/v¢£bAbýª/rü*/> oªvÐ_CuUBa¢bZßÃßaOb~aABð,U B+ãÜîåOýub.hzb,_b,AÄÜÖ+öO", + "ߣßão>hobuö£Ð>ýAÄßî|ãåÜuC_>/", + "abzUÐUðîBoAüo_©ü/:ÃAÄåb¢Öaß+/|ab*Ðßß/ÃuãZã+@ßÖ.,_O+öAzãhaÃ>Ð/|<@oö¢.Öã@ÐuäÖå>@ßýª/ãUrbbAå£ßÖr>.Ð*ä+åhý£Ã©¢Äo|ü£<ä>haÐUzbå~_BAÖ_Ä/a_¢oðäªÜh|~*å:ða åÃ+.aB|Zý_:_©îBýÐ_.a ð£@u~ÃÐÐýhªbÃåä*Aa/båö oU<©>*oî>aaöbãr..ß_ý,ã:üAu£Ä_ýð/ý +üBaU,ãuBbÃðßÖhz©zÐ@Ðzý.UãO~å_ªCÐÖßC.~äö|ýåa_äÖ_<ö|z|,r+ªýz:Uðäö@©AäÃaåb/ßüÐ.ýä+b£BöüZ|*_/@/Z.â", + "23:59:29.0498764", + "2002-01-31 23:59:59.0498764+08:00", + "2002-01-31 23:59:59.0498764", + array(-1, null, null, SQLSRV_SQLTYPE_DECIMAL(32,4)), + array("0.0782", null, null, SQLSRV_SQLTYPE_NUMERIC(36,4)), + ); +// 3 +$values[] = array(array(("FBB2B8D1429F4CF743301F5AEC311F7C7F1F62D59F958AF667506C36D2FDC59BE9CC37B38E16F684242A2250E559EC648E18F3450A7E33DC6F11C2F252BE1BB1830146"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(256)), + array(("745B77A9709CA60E6F872AFCC2E5E48CAE0E16B40FC079B6F5197785FF253398A65E11CA5028533794EEF8836FD1BC68DB68D2F311658169B02D55FE65538B3A62AC5563D4193C85BADF2021C8F646235C0EAA9652408640DDA81922D354D14162BE21C37B5893C22C4D3832455F"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(256)), + array(("E632A257A9F4E7222515862CFF19B2660DDFBF09D583A7037AE76A050854FB7D065F3CA1B27A976DD6FE9D66D267C2129AD12566A097E5628A9EDCC18AE11AD11A0825A0DD10B492475133D6E540311324586A362F95DD6F79D916139ED5E3F4E4CC4CC9412234891D921E4E630F7D496DC89C3177E3A2852BB62603FAA0F4716E3FF119F467D20223E0189C768E0B695CCCA6D538B17D0029C79D8AFB308F7D9DACE0241E635505F69A0D96CB050E9DAABCA72DFA1F38BCC1F0EF2DCA4706F3519BFFC9ADE64BF977A0DF9EA3E63524B800DF3F8961827E7424622E73273BAE941A45300544EFC371AEB6593F9A18DABACB74C967C669EF18815589831D854F65300989A1041E73101BCDDBAB293ED90B8773A7B27146CDB1551884EF6640542866F40E918F39B6AD00B84BF98E43EF427C7EFBA9DD9CF3EA3BD74CEC9984AADB79B245342F487B4EBDFAB1B9FBD42212284172E844AA4BC9012455B8EDC9137C0E6F7FDBFEBA133402ADECE2EB3AEE66B439C35711C297CF677B330AF2C361F3E635AA8B5447136E2E3EE597BD68DEC635EE03B305BB6A4BD8B074828708413F4BF8FBB58F63126D265529D2DD0011FF9D6CD403C0AEEE2BCB5FB3A4D391E625FCA64BC46C2937D2DC958CAF92976ED79E74E51A343E7E9C0AD0EA30B06D99946F04D636B44C92743502262A213E9833F0DB055EACCBF1BE27AFBA9B3E06216FFBF8408EC1372251E270E53118547ACC37B63FD5673BE8A312180F0592F7352EE1B72E29FD0A72B9B8B47C3BE6BFA5D334EE6388C74C07C00F9D7BA9271DBFEA3BB750612551CE2D43861CB3BEACBC53723CD0A493AC6795AF6D195F8FC9919BF591002F6F44ADE31F3645412F530162E02736EB4C1A578E50BBB1B8376E9D7AF481BE2DAC8DE32E8FED845C6725655B6CB67F6792A64EDA3971DFB492F4ACB199CA4CAE95D4B65343085B5F96FA272A55564C80EF35E74E33E4F33BAE2F9C9A40D3C39CD9B7C697002B248A4AEE443F4AB55E3CA82BC264E3FD7AB0E07BA5146CC11EC3378A509E8FB480C3115D0445A0B4F1F9D160F115115FB9DC3C16B685860F1D88CF8007BF64BFACF4ABFE5285F835102C89AB430CCF09B2D8D0736279FDFA3C013F7B751FAC319411B3FD6A120C34E306058AFBDACC11B9C5CE2FEFF15D33F6B0C151457CC0F07F58173158D29E9FCB9C8F5B7373FF61352EC2AF507D41A3B38007BA50BBEE6746140BA2C39AB8E7272F63536101BF82B05F1C17B910A00117747DD8985B6869A5B660E24AF91672AFB8BB005C321B053EF05D576526D23652318D4BA95AAB6E1EEC52D58CBE43BBB9C38D6EDD76A870F681A5A7FD10037EE32990186BCBC9550D4DE270E045797FACA29EA2996458DB891C5427B404710DE9D3F162108605B453ABE3C3B87DCA80907A9DEBB9DEB5B76CB15CDCE55D9E2A296F131FDD6835F2C619FE188D14FB43272CFA6D66FFC3299558F06F3928CEF61DB9AA596AAAB328449B25AFD0AD3A47B619B5B85320B3299BE97A7467C6C99D4B080AC37A91E87C79C228DBDA2358F82EA8B92F630692ECF670BD71204EC08DD18864D8A276DD1431494E8107E75F78908255BF1DAA3A34651DCCF9E4674C2B01AB0A41BE7055A7DB94EE29C811D51F2134E0ADF90170274E207384B9D33FC9FD138F6CED0DBA103CADE378BC107C4348BDD8AF86AE32003AD2F39E0CD0FE0865243CA4927832138AC0714B2DF77B3DB4203BFBFA90434EE18F220A1A2C135BBFEB1397E3C7B0C08BC524C63CE6E23357C5E9EC94F20DC4D0EDC3134628095EBD159B32E3E359EC6F7B70357B8D01FA9CFEA2444226C6BDDD4EB6F5F4AD7A53BBC609275BAF5F746BFD8D1971C85953EBD8765775B51C864EED65953C53E7B2011C79B573EAAEFD9F3DD854A9AD3C04F5531A2C3712EE06A982D87E39CA481805CB18554EA3EFF13978C837DCC7EC91A1509FD939CB7AEE3E730BF10220C3D4F5C05EDE94D6B6517318F2CE5AA629E19636CCE92A6EDE3A503A26DBA7EEFF08A4F3420C790E0CCA9A4E5620C8BC8388491A5ACB63EAAA86E2148E6ABFEAB98429FA1967641D78983A024EDC08BD61A3A6AE828D9423A4CA48CB2A548FA21ABF94D206DE932C242BA1C291519BDE7E34A2EAB401582BFFF6555F2EA8F3140887F79F3736B683008A8A56EBC182432E6A4CE5B194EE095778D2008943FD7B288DBA196A0CA7378E1FDA398701403E640220B45C1D626399EE37CE64A609CC8D0F2E6E0778D911C3056791CAB4725628A3AC8723392F1B1B567F8BD4D8D2D8160DBC87D2E226EB290EF156B5D0A8E56BE195C10982A943E01342B1095D4CEA328F8BBCF7FA83467CB15E1447C8653AA"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY('max')), + "ý~ý/ý.ÜZßü///bOrðbðÜ*AvhÐ*öªb:/OAaß©B£ÜbuÄ.ª|¢zÖ*Ö: :ÄrüzäâBvZã_£ª©|CbrvzýBÐzßä+UühªbÃåärÖ.äÄÃåÄrÄÃZCv.Cå äýz/,Üüb£ä/Bß,Äo£|>hÃbr+r¢zÐÄýÄbO*aååzaBУ", + null, + "ß*ª~Ð. ~uoÄaÄrböbu¢@z|Ã.Ä:__ã/ýöÜ~ý/ £bbåÖ/ý£îÄOÖ v ÜåÖv©OåvåÜÖßOÖuCr£ª/o~¢_hÃÜßÖ+ß@O£oîãÐÜhÜßOBa¢ßå©~üCÄßorvrCü.b@>ýuª@~ v<ä:©+.@@>ååho,©ß*>ü¢£ªßÐÄZ©CÜaZz*z+zUbß,ýî:>ªäðÄ@:îÃzÜÖö|uÃßß+@*bÄ|îbrZ:h:AÜýÄvC,î,üCbO~Ö.ÐA+A|ª+C/åza©zo/|äÐüüäö|.ðý|ua_üo£ ãÜ:äBߢ£ªßî.* ä", + "î*/ýz_B~|ÖA©ðÜ@@uC+OªoZ>uߪüäA<>uuå*b*_U*Z@A~ü©A+åhr>ãuÐböÖ<ðCÄ_Z_:ÃåO<ä~Cãz£vîUh~ªüîvý,ýhzB~bzu~ýÖb@ýor.v¢+aîBÜb> *@Ö£a_bÃÐå+v@ߪЩ>äÐo/._¢£ª,bb@bBÄüÄß*Ð>:Z.zbýB|,O/ZOÖOðCra+ðâÃ* OßãåîzÜ+ZåaB>£_býîªUä _bª¢ +|Ö©ÐüÄßZÄ>vC@ßßA~+£Zhü,vß,BßOýz|äöª+|äÃðZhÄAu B,./C©ßÃaå@ߣ/äob|*_.üå.<ÐÃÐaýv*A:ZÄ.Öä£ÜoöÐãÜrUbhboéîh>ýü+ýbÃaªoÖrhoÐzÃÄÜvao|Ã_/©åðC©*_or/ß<£Ã<öCÃAýCî,Ö:üî£C*.vã_.ßb><,£ýüZ@rbbßbAå©_ Öö*å¢*öÖ.Ä~OããUÄýbÐåîã_BAãöýðåü£v_ro©/ va~|Ä_ª,î©vÐrCaãª+AB:¢ö/o+,.ªãÐvz<:.åªhoÄb/:ðA¢ãößåÜ£ å£bo. hOÜbða/Уªöauå+,O<>CÖ_:ßöö¢ýªß*ÐOßa_v+_îªîr*äå|Öö<<~£Z~ªÄüCý,:CãUuã.åãhßö~@ä*Cöb,äAh ÜbîU.ßZv|@oÜ+B£bhåC*âbÜÐUªAA~_.ý@Cü.b>oUý.£vªÐý |>rä*hߣzß|v.Bªzh,ßðv|ãZ<åaÄäîª@v¢.U|üv*zzBvðåãîß Crðbba£ð,bÜ*OavAU:bäö©<,ÖuA©Ö|CbUÜbÜA©:å,ruuÄðzäÐ/©/~z~z,ä, hZ¢ª,ä¢h@ö_COZvCb~Aå_ê©BUîðrÖ,OvCÐB|ªßãZo ßå|UZbÃßör_ª>:oa<ü*öUUZåh,:ß.¢< ZÜbr/uªÖuo|+ÜuZ/ßßO_*äÃöv~ýbBöª¢Ðo Ð+ü|v+ªÄBÃðBîCaý¢:öý.bhðäu@£v_ö¢¢å|bäuðoÐoªv*>büböýoßOð£UAÄAãö:_ÐzåzÜÃb_Aab/hß~£að©r+:*îz+CüöÐð©üЩ:býZÐý+b .AvoZbrå,:ooß<üBÜð~>£~AOübåß:b@zßu©B b_@,öö,*C|bÐßBA,ß/ßB**äÖü,îaßäaüÐÃÜ/|<*ðZ.zzBîb ÄÐO:_< ðîÐ>|@ß*î.Ð/vZ©hoZî|B@Ö~b.~zb©_/U*ã@ßüÜ,:b,å*:ßAAªAO¢îU,oo:hö@ZuåZOî:o O>>CACåu~~_Z:¢+ß C:+£@¢:öÜOabZð~åZä©hßuvvöä|.uã~><ãßýÜ©£åAoUöåOz©ö,oÜÄ©_åOBÄ©bAÄö~>|/C~BªußB£üz,Ö_å<ã©ßÜßzîß©üüßa/Z++ªå_*Z||ð~åîäÄöCr|åvÜÐÖCuÜ/£UýBrÃöAo© C_CUäU.ýöüaãª/_a~£äÖ |äîzð<ÃuîÃß:ä/*o@ä@ÃUß<¢,,££©+,Zîa|©rððÖÐÖbvu,ÐýräbÜ bbÐ,Zð_ßA|_Z>|äå©ö~öÖü<Ür.a£©:ßzªüãðßZða+ðÄO>ýÄßäC_î<ã|B~öOäîåo~ÖUÃ_Äöb+A~|ãvzZuÃOß|ðîßÜ,Ö äCbB>ÜC.vjklðboåîvÐãZ©üoÐBª©ä.îoüªrvüÖað>£ðArhî+,o:_ã,Ahzäîð.rÃÃ.£b££uBîä>,>b|ýCbC©å© o@>ö_£äB>züu¢_BvÐob|Ã*a@bÖäÜäz_ßab<@hÃÃ:AÖýB_ßð:Aß+>ßC¢ß>üåßÜBurÖOr|b|Cb<ª@ð+ðýUß.Öbðbüî/©AOßå©ö_Ü *¢+,:© auªÄ/~ý¢ý+*hvÄrzC,_ðuªð|,ª~¢¢/AZ,~AÖzÐU/rOåzª,>¢ozUýðÐC.ZAzßý*ý| bÐé:a,hBÐAÄ¢öýBü< OA+£<¢:v..:ãr ü_©ßüÃZãäßabÄ£b ÄAå©+zÃBrbýÖýÄ£îã+£, ZaßA*O_£.ðßObÃ.ü@ü©ä|ªðÃ_ähoBu ý©a/AB£Ahh/ßhO|îauö ,ý_Ö©bB<ýöCðoîðahvÖöýo_BÖîª_+bãÖãb:/:ߢãzª>@î:+v£ß,ß>:åÄ..üuuUhöC+BB:<_z¢ð£+£arZ@*î|£AU+OÐAAã,¢b<|._*Zßovbo~ß>b,u©Äå*~ZbhÄîÐ:>:UZ~îBª£ðU_ÐZ~ä£|é£ßo©ÖÄåZ*.£+bÄÖ¢ðzu~üÜ|Ö<*ªZÄroAîb *Ü+|o@ :¢å~ÜÖUCßh ð:ä+CÖ.uCzßÃ.B:¢~~ü@|*ðü~@@ããîßÃAÄý¢<ý£¢oð.a©ð<< h£_ߪÜ~@îߪu~,u>B©ÃCßhªö*+¢ððZ©AA@ÃUZä/ö,B|rb,|_r>~Uß*>ýbªbýß_ßböaU¢*.Ö U@C*/rbUz|üåÜÐßZb+oÄ/ä/Ð_öB¢@ÜZzÜBß.b_vC:ß©u|ðvrrü|üUAå,B+ß>A>ßzau_aUZÜCª|Üo:äöðu:>>aßaîãav.bÜßvU|O|ÐO£î/©ª/,h>Ö:~Z~azzOr¢OuA*bßÜ@ðî©+rAß~b u|@Ã@@ü<>rvðUý*Ba.åbªÜ©äu~bb+Uß.vüü£C<Ä@,| |vý£©aCa+ÄüÐ:î£<ð/åCU.ã©ZAÄü_Ä+ÃA:CªUð.bvU.ÄZU@Ð<ýÜB>:bh/z+£zh:©*vÃaßAuýaßãaah+b@ü<_ðZr|+üOð|ÖÖCßÐ+a_@ö/ÖÜb©¢bhzö C £îÖbbC¢ßäz/UbÄrvÖ*>aabÜhr@özßåýu£.<åýZö.åh|:*ߪîäå_~ßC ªCªä|Ozaýzrª£U Z<.bCå< ß,ðb:ö*..@BäÖ+/+U~C~ohrü£@~boÖa/Cßß:£Cäb£îßB_+~îAAã_Öîo©rü,ð*ZU©@©Öö~üÐCÄböv C.ZöÃAhî<©u¢hvÃÐöÄ+£h~墢 bZÄßÃüî*B_Cü©UCÖbý@z/Äb,Ö*|ªO_@£ +üãr£üvÐßOh¢übC_,@åBzå*uzb ,zo_a:£ZZv_,av~£_ðÜÜz:bÜa£_A>¢ªî~¢ä/¢¢Co ÖãvähåãÄußz_ZAöu+_+ðªß£©¢ß+,oAîߢ/|ªßðåÜÄzvßZ*ZªðrUbÐuÐörªuz>/_Oî>ðã:*.:©ªuZ@ã+Z_Ü<üÜßb,Ī.uÃ~vvÜbîß/:h~Üß.ha/.*uöÖÄü~,B/@CäðrÖB ö@/ð~ãB¢îOý.ð+jklýÐß|ZOÃß*î Z£|A ßbîý/£C©Bb,.©>oã©åuAZÜ© ÖBuðÖ U¢übhz+r¢ ¢h:ußvhãÖ<¢Ü*aba,|u /rðÜßÜ/ª+ã::vå,h :_<ü+oZÃ:ªîÃöaÐ+bA¢b*>:|Uð", + "9999-12-31 23:59:59.997", + "2079-06-06 23:59:00", + "1973-01-31", + "23:59:29.04987", + "2002-01-31 23:59:59.04987+08:00", + "2002-01-31 23:59:59.04987", + array("0.7414", null, null, SQLSRV_SQLTYPE_DECIMAL(28,4)), + array("0.5117", null, null, SQLSRV_SQLTYPE_NUMERIC(32,4)), + null, + 0, + 1826608718, + -1761264475, + 20544, + 255, + 0, + array(("FBB2B8D1429F4CF743301F5AEC311F7C7F1F62D59F958AF667506C36D2FDC59F34F4973B8E17045382F4769C1ED8B2126F4FF2A8F564B86528C26AF2321625466A7F25F89AE4EE681B0E52AA1FEDD88F9E59C7830A1DA9CF3B3112CBAC12216BCF30319EB2BA778A608A8CE7110E453AEA"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(384)), + array(("745B77A9709CA60E6F872ACC493745AFA4B06A995B437D530432660E71CCE41255F81ABC7C9C9AE28CCD008997250986D601DF50DCFE1030DE23A43E35979DA2A31877511C88320716870C8E43F3BBDE28E0386FED933656E8EADD58F75BACF42F5DE67FAEB7694DCFD73A54F182ECEA67C615555F2EB410E2206932ABDA0FBBDB175EE50D3C307176EAA01558E16566FDF2F03145569401A9D69D8"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(384)), + "ý~ý/ý.ÜZßü///bOrðbðÜ*AvhÐ*öªb:/OAaß©B£ÜbuÄ.ª|¢zÖ*Ö: :ÄrüzäâBvZã_£ª©|CbrvzýBÐzßä+UühªbÃåärÖ.äÄÃåÄrÄÃZCv.Cå äýz/,Üüb£ä/Bß,Äo£|>hÃbr+r¢zÐÄýÄbO*aååzaBУuãÜ¢îî,CÜ_+O£ßßöuÜ:u*£o*î/+ãv ", + null, + " ", + "Äðãvãß ßß oba.£hß/,ßB£B/Zö+ßrð,/@_@öãaÃ/uåüz¢î.AÐ<+>+zUbß,ýî:>ªäðÄ@:îÃzÜÖö|uÃßß+@*bÄ|îbrZ:h:AÜýÄvC,î,üCbO~Ö.ÐA+A|ª+C/åza©zo/|äÐüüäö|.ðý|ua_üo£ ãÜ:äBߢ£ªßî.* ä", + "23:59:29.0498764", + "2002-01-31 23:59:59.0498764+08:00", + "2002-01-31 23:59:59.0498764", + array("0.7414", null, null, SQLSRV_SQLTYPE_DECIMAL(32,4)), + array("0.5117", null, null, SQLSRV_SQLTYPE_NUMERIC(36,4)), + ); +// 4 +$values[] = array(array(("70BA23A819E1BEADC92E0840F382D7A5DD89EDA9FA12486DCD843FA57FAEC5439F0DE3836E6804ABD214C35672F9552A2CE003709ABB9C5E72B6DA94A2192E1B68C5A0E69F5336758441D7E54EF1FAD32E14799EAA55A9E3708411B88D6F09B8E6A7EDAD586F8BD8A98EEB58E4B61080"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(256)), + array(null, null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(256)), + array(("D4E78A93FE9861D99DF7DD00C910BDEA7CEDC7F286334EDD6C038C8627D3A06EABE03A2B710CDC80D5D1AE1453C78B746B41D521EDC63CA098AC27FA0CDAB2C9576F55E9D691787011461CB4853A8AA477181BE5FE7E81E5A49992C5E4E273FB1FE4BCE472A29ED9C8650FA6AA881B5E218382F4BFCDCBD8ED6F453CFFB28B2FD32195A07EA631D57A421C996EDB3B1B7E34A3615F7E3B5119E3F6025D61D916D9E0D388F37AE07B51AD7A7CB0326A123429BDCB0F29CF54E543879AAF2E77186806BF8D08B2280354270FB204BFA1E679E4CE34A40E06AF117FA3AFF345CC22356214A973DC098200BA77E71A1C5026A1A020CA60437359000F7C890E780F0E5BEC7DA1ABF8739DDA4C33E9971F95F42F7D0E522401C2F2EEBAA9645F807387AA688C2D9FAE7AA92C83EF140F8AC2E179875A916ABDE9592A8AB2F14F0F3D5AD8AC3F2E92685580026525A111ADE364F7C7EAD826E21DED7F320314FC89591D45953B624B934E1131D98E059747487CA74EF987256533F68F51AF60654184790B085C7C7180186379D9A64D54175637EA866DAD90D2F8DF6245D3F9E4EDABF05515F98EEBCB0A2635950D4BBFE6A277FB7776DED3D6E839107C192CAC1F7F8C2DB5F73E1DC74B1E7B4678FAC4AC1F7CA35CFE6D76CD1C7F2CC07E6FB2DE7A1516811D0AEE6359342B58638D5DEE74635C9D8950201215609878125C49DC6B9CCC62E4428E158D4002CA411E698F213E4C1A12145529F4046CBD717650FCEA4EECC6C1FA0A31D44610494D56D0F7F60956D4102EC95747A26DDFD6D1A416EF06DFF231A3CE26331A45CC040CDC9E3375C6681F7CECBC84957F1F8C2A5B03A2F9594777DDC5533B2FA0F5E8FD533AC5CFAC610A3BF77319226D9C23AF9A09BF42290AB2952655AF722DEFDBF6D387424459BD7DFAF86602E62D557029308C959736A6D4488830A956B1970E0797234FE659DF55DC8BC549C207CC67D1E58642A15944BF2CB2F9BC291327496058FA4F0A0589CF5036B90B715D1141BCC8D8712A556DAE5363223360232CC9647BE86A0D7C5DCB5CB6F26AA0384ECEA1B800603BB51E0BEA4CFCA6E2556F2D09EFA6F575A6333F6A0C157463020D1A155392A822CB8DAE5DDC7FC080B7E80647C460B0925859FA84C1F62FA0A9A8E73FE1918EC2C60A3E62F797982773BEB3230E2C9EA25C88BCFA982361D55E0EB43498819E25594380B9224E9AC1C1D31102420B917D0945E259D5942AA2A96804E9E3638EF11F8DCACBABE47F0EEDFA38C5125E93537C372A529F4450C418DD10BA4AB0DD5D441FE3B441C6D124C5D36CDA5C65904AD5B06CAC393C52DA3D05B2CDD4C5C43D1DDA80F37BDE12B665058CCCD87668B34DC5E59944312408CD08773B130350000E2EBD81E49DCFF69EB54633AF8601C69CFF800EE02BF9EBB678257266D6A362B58BBDAAB9E7CEB0F6EEFA8EEBF0584707B09F14834120E235D1CA6B775C90C812E37E23C8570DB430CF18F1316A00C620DE6AB5368EDF736BDB74E71D6239995E327B0771347FAFA2EAE3B3292EB1CAD0044B98F1DA9183030BB8ECE32697CD957E93FEEFF954EB5FBA124CAB2B4A3C2AA9161917A1A783A0F803667C92CC7C53161EAA9BB2DBD7AF5F3837C745D8D8C17BC2390F7EB6F4D70F5EF6F5EE6FCDEE96F9950D9FA177CD3F69B76870BC5B1F2BA400CF936CD45F29D38B54E4E1C0EF6B48314C43CA21DA4B6BD014FE8C665302D7CA496FFD5A292435E3CB1523E85DA8C7FC278B0FDC60822684279CC0609D6D38510D1777806EEE07270DE656C42782736B368F3EC8F2FA69C64978338D64D4465EDDD1DB4531478E3983E7CE7A2C615DA428542A0D2E6F5E12ADB037F6BA7AC339A0F7E756A72D3AEF0105440B2CEF99E71B8E640FAA38306D72C898800F987E092395DA357906FDFB1A3A0C292A53E6BD164FDA2B15B38E67C779E4DE95B9DF69863BE79615646E149169F56F2C07431EE2DA69C0BD52F46F06726D00221E66605AA2A2EF6C4FA8B2E1C59AACBE1E3BC036C5FBBA4F1FAC3347778FA3F66DF272039414896453B29332B7DEF7B848B1E737ADC95C23AB113BF66EA7F4BF05BB73D327A8290AB25BE21268889740B47BFFC5A86C49A4954F5783D992F5ACBED32DFC6A24909F88DD8452E649BA2379FA42F3A82E179871CF3DD751A5301F653654955B9AD590EA603DCAE7F7BD4B953409DE5002038FBB948A9BE6B94DE2AD64ECB0F525C8DE24B10948F04DB17A12F1421D9C51CF6332C4D9C6103AA931125B1D820A0C56706B2AB99EF8BB9E6EE21088F47630465B95887D304B01CEEA08D83595302F6F059BD2B17197316B76256AE3FFB1B5BAE214C1ED818E26246A5CCF962086093EB3A08359A47ED4C3631D070AE11DCE38521D52806E41ED7674AE4715C89B4BF01C2B305F2E5B16643FFD8964871B424C8D9643023388CF71B20CE4F636BFFBC8D216EDB5ED6F0AF707EE4171B889EF586BFB88315848BC945BBEAC2276202D8002C191702E8D5E1D8C4BFA45475EB9281D8B8A3B37C970895A58592FC2E880E6C1C06EF7F77E2ADD9D6AA50C4D774DFD048305EB95F24838500816D5332E5AA4CB148486F0C1309E61AD9DCD23643BE30B5C2A3EE29551CE7835A6EF6755A96E0F014139F3C70C43526689E8547B15ECCC33CAD7041BC135C2B50DBA1B41360C032FBD212301F0444FE7EB7C0B6879FD20BA23348AD26AF3400B773DB95227112F7DE525BDF3C9CA4285871C3044295A3B0F9A611D018130C4C9E1178AB28AFDBFDA4C8E8354402CF059F2054A4EC3FBE21D02A9B8C6F42DFCB460F312B23F90FB895C56F89BD6E7CF6D70C40F7CE67606E5356DB0E045F9E51E91CFF34C1A3E196109C0F16D0346461BD94A55301D80CEEAED2C7CD1E01A446370D90906F3835232AAAE72258498E2EE269506FAA3B5011101085EEEC14781EE7C8EFD293D3F2756F823856F0DA866554A8EAA4A1449BFBAD8F805EB256370622D83A8F59BB8B1E76DB0027F2F910358A208A4329C36DA33CF4251453A3C3094B32242890070BA91DDC3DD6347408B46F4AC481CBF3DC6F6A9752659676BAC317F6DCC0D4F7958324E1255D85976EB8EB70A518EF314D4755C4BE08A49612A7117ABE4D9737DF77A5316CDADE8ED9D328997A15C1A1E3D6A9857B10398CEE8EDE8E3C1AD92121B3912D63ADD47278C6EADAE00B2BFCE56F96D79401CCCF4E1852EDFC4042CEFA0777C684944E4602370CA4255EACD362E198CC74018D1FE6D1EF5B4AF67628742BE0E8835568412150C56CF528A9EF6B7F8B1AB7864AE87A67EFB2A4F2FB1BB0E420097DC4500D79579B234C101ACE380FEFCB6B6B70FDD0F86E1B65B59C3E55B9AC10F89061A72F7D915FEB17AC6A5D218AA5033FA05563222885563497B3BB6CDD9273F9C5979E389BFDCA2112C94C03CE443AF72B260956BDC677EC40FAD5DDA48E4A19E6535BF306DA93B28B321F6F3952765388C431B7891D3BFF1FA1E7A127FC8C947F221D6AE847E0508256CB7BB718B2FE848254D04C8290D9176CD364E2F28A9EB58AE017450B6B30D3D1253241C037F6FEF92C9597AC47EC9144438B648B6D9FCC3CB63C389BB9791723FC6B6D5E875724DC65F9C5E4F71932F37600B7EFCC58738576150A0BCE533FA37E73AFDC8F32BCEC56881573C9D735ACF93525B8B13757A3F7D7D8725D291E02BA2276836956643343DB893432FFCBAEDF5D02893D86E2471C0BD4B76A4A9F3D7A02B9A760A23392C0E264E5BE2361081C3992F01684D523402F776D71BCD9093C5BBA3036144E2D196FB84B11FC88F89ADC9B20A79F16F53D9667312AC62114096BA9526930C1F7FB65D6A6CC8A0143A68ED29521B851AD34C4F2AFBD0CF2534EA431B643368F6A1AA32531B86038A385139AABF38BF2511A0C1D943E123AEE63835818585AF06FFF688A8E831FF4D48C5F2AA972565FC2B1E0AC4718EB3BF86846CE2518105B2A132AAC9AF173DDFA174917EEF7917C1D33856667BEB957043C82164C41CFBC6BF3F08657A9C4D14E12A22FCFD35D00C6CAB0E182B9E37B69C3A85E6F5D81A8478CABEB071B14637EB418550C898720EF815F7190DE39B210751C84016661F08109E843376209BBB64D72CEA18E6ED04C777EEDFE00176952F9CA81FE9062185227C402A143F97D77A3CB436B7B0082064C3789E773F270F27EF04DA777BD15EB6A7C89BA6C3F088DF1665A44C40DD7E9487BB258E820DE2553102253ABD60FE6B568010E86C7AA1D3F0BE60D983C2E7118645F0C0ABCF3399E54674C0CA4D22B66638F5C0CD95270C19529EC3AD08D16E1B14B4776F3EBF864C77032505E108A29CA9734BCD2643F01DE3A6593170EBDC7505A4B699AA4628796E74569202073849FB27039585A1F5D0C4598C976655DB8B27AF003C5208F1624BD25EB2ED5E1BDC6D103549E746EF64AEE6D550BA90121998CA6A5206FBF7F235A04AB34343E2653EB029551F92A3E0BF9B8E6B33A1A8BABF441922F3C9D57219421447FC3C206B036F120966BCFA06268A926B6D8BBF94F88FF4FE29BF7275DBB73CDC7E5CE3837B2267C38E9E54024A13FC68366A048D837F4F6C47224244FD9D2EAE801E87CAA60EEF4A23FB05593BF2B416C3093E70B2AE58FE0D773B58E023C6F170A5812B8B31C2277AB969887AF530556E2B80F45EBDFBD1C689BD2FD3976A003513E99670888A914716F6F945D0831746E6EAB4A2D192B2A9B06502749254E24F6952660C9AE4E5A1EEAD48C7028CF505A6E8ECADB65D638137EDBF23881DB4C213A9DB7D1C0AAC010413B3244AEAA6246FFCCEAA6835990BEFE5D5AD24C219D1F886B358B078E89B3BEAA8A2AA3E364C469BB38B4F0959DD10D08E3634FFDD42F9E22CC4374D73F714326E7D8DF661B0AF8966890F8E81EE2CD548E0E9B1663C0D66A9C7127215F828BB771C9BDB501A6EDD87AB9853326B613D976105920D62CB3270264C9A9E3D746E615317645350852D720C2ABAA3B9333D66D4DAB3F295AD1451686B29CDD43E4A372AF2DF54FCEA47DCD7200138118FB6F30F34C962C07BCBA50213EBE45B609DCDDF8378C753E969EA93D71B74ACDC3FD9B536BEA075E877AF263A51E9FF6281778334588D16EF9F25CADFCFE96057F926D3122F24A1FD58F70CC9A019977FEB3056A3F17783B2C2C59799D595188D4ECF412B15EC325CD686DC61814C4F858D4AF39E92BD6681A2214F6A8D0827C2DE7E7BD0D86C6AFEFEF9CD6B9B22307676110B8AA27AFB9169BF88F49DC8CFCD5E1A8203D17EAD21E0F5A098EFFAE580F0D9F47CFD9C1F6383E96718E37660352AFF0C819F2DA4F763E9AAADDA62A16ED90703C4D452D0C1FA1E80E716943D6A946A6EF0ED64E1C334FC1813F272892047F93EDC729C61D72F4B8780ADBCE1CEAC3F1870F3B1807526408FD73ABCCE87955FA01D5661F8F70896C0A2DD6015781B4A67B35A192C9578C9B5310D899D737CFFEB4E1CC3784B4721675DF1DE98C62B17BCF0551B2D7C320AA58CABC6E97EF84D25DD75C65B57D11C6B38B1CFA49931EF06F6CDAD1D61D26E1C121DEB9F8137E865A4B9BA5064BB641E39AFF4CA62650B5BBCBFF3B14B2FC30A06AA4939E67CEA00C96A00E0769EA23B688EE4B1DDA3B9AC1290E2C144361975F5AF4AB9712B38BCC4F401F8652BE41E1CB749BC4A112D62F09D27559929BB92508AEBC753E9C93D5628EDE9A2C146E7ABC4A48CED5D2AE382E7C8D403E2229B386FA8DB3F1DCA33EE0C66212444C02F5740AAD5842EA4F25F08456C20F539730651B032196BA78EFA709EE0F709BE3E26987CC3384C160ACAB57B37D75D13F9D3F21BD3938E16EC991CDB1490C4FB564907458778763BB93AA66863EF6FB69C5CA50D04EDEAAA988290291B71027A06B924EDD0188C815CB66299ED26B2FC29653FB7EBB6F6695F5CAC05E74C1F47372B61AACB82E584D023B04E8A51BC72CF9300B5324B8F50C2BA8E746B869910961A61C1C40830A780BBE6C705A8DE0D9F3A35534C6A15EC9C11E711F37118498AA0B770F0FBAEC66358357764C74B1ADB80D4315145C42C057424B3211FB30FA29C3C64F16E1DA48C6EF0F3349E87D5C6CD35739CE7F845DC8A6A7BD6FAA543A525D4C88BE6286C632FA5E254D0F867EC4FED54EA3F72BAA4F7886704A1CE91C9AD4D0EC9BF49DFA4C8106D4216F00B92038F860D515865B31A24945EC168C2601318A682E99D2D060DB0212F04778D067CD5001148837754E85BAF9BB581E2604E0C2EFD4988A8656280FFA13735AEA2968DE1EC67B0188FA0529A8DEE91508BCDC1E1F84890BCF32C9AAFC783D61DB2AC0C05289FF6F89DF49E5CF7EE1A77D02F73D37553B65905D0EEBFCD00500BCA34E8E1E18C28EBD7C94303A933C5051123DE980F02A85EF5B3FF57B1362B9DA39391C3063995440788FCAC10B2AFD20BE8ADA921B8FCC78C89EB2E8CD03AA09EA66016A101FFD88E9A908705FC4E43032D4CC888817CEA96CA377C4D66B8374D5B0D6952983009E9D51B872874C1903AA82A5F8371181C2A767FD7CA828A27E2593AAAEEE4F16BFC43DEB366F4C22208A641A53B58B3DC43F03FDB18583E674AF3A5CE3917A156B7BF62409265B635B35DCF2340E5EC89A65E66FDA51552A4047768734FF3E9F004EBED7BF67249DE3A0A27BB891A2764061B28DBB1A4B0A26CBE3C1BFC43E5C073DF1E54F77092341488C29AED971BE94F036C33CB0D3E603B4B0E38352EE1F7256747A9FCD26C9689F3C729E116B5D5A253CBF9D6B1F466A0BE19AC615AFEE6A6CB75854F71ED7D96D6AAD746157E24963995E262E8207373E1093DB9C0342EF5E08316A02F8531654E6200061C208B40F41628C41C83BDAA02126E67AFC3D6A17CE26592678466B3647C1486206D56C07EFDC4AA0C69D95CC56B9E1D17C9B68A8B5E8A3ABAF9D86FAF74609F6F368A94BBADE9B2FE2C95120909CCFCE6499B9AC689FAC2E31C06852554FA970939EC8EE1096169DF048B5FC87730B12CDB8966D9C5D8E63CC8B19FA7648DA931FE09CF1C3D1BDCE732BBC2FD9BF96BEB555849CB94BE436106521857C2C27B77E12DCA6E6195EFC0AC7EA60A16E8A0CE46B4510B43DE9D40C56E15EB0285256F3F4B1B6E2FFD89C069881E1517394A1DB149110D707033038F8AA8F37F03BE275937CACBCD329F482A91A1BBBF88288C23F739B87418FECF1718DEA454964065C9F7BBE06E7E507FA9C8E2DECE774306611CCF87CA06B34138FBB3B453FBF394503CF1C8CD481DA4A6BA0EAB352001A0D4D74338C7B99BC3447AA773CB9C2BAED44D8D92867B3918FF2AE010F7070B18FA13E07CB7BBCD97A02D8353A0AAD90A8E5FD7E7926E19599E2A399CD88ACC3D6E8F78B7BBAFF61880F6F158F7E6775450D581973024868BF987DD8D8230BE166146E51131214EDF68BE679B7DC161B7B2E44B0209340C4908EDBE34D169964F37DBF6B00166222E87A12F71BCEA0D372525DB9DE4BC0C2D399B084463190EFF271864A2CBB0B64CC11D7B67059A8D1EDF860FAB8EF86A7BCEC876665DDECA6D922F4AA4866B6C746F8EDBC740A5289F0EEA65DD0A63712EADE9D4033A50EEE3520ED4D550E89773199B3CFF1CA23A299FD7577378ED622FBD1BF69D96693A1EA0F87532D0534E2552F1C46F2672110BAEAB6362F87B6B64ABA41835F1FADDB0611D5F242D08584C8932208629F3084B09EBEEEB05D725248D10862B3B19335714140E0912EDDEA65217D9C65AE43BB89BCC2B060CF1AA89F73A971C822D1170FEC97114E5FF381C0D4898EEFE5FC9A8D4CD8F6EED2D4B23698511D755C124250668C8917226D39C930EF8C359BB8A9871EF47B49DA282D07D4EAB60EE60C74B2472E895963735ADFAF3DADF3488C9ADFA786666796F8863E6F714247B72AD3347AC9FE6D3F40139BA9AB9A9C7A39BF585FD6575FA61D2B4EA84AF9F2311328745A79788E8E2D906762CACDFB6DE9C435C1E9F7D0D3838E6DAEAFC4F456215A86831641F0B130CA2235FFECDB4F2FE0BE86B420472B47A0D6EB0ADFEE68AC014170377847A7C374812FC5AAD396B31E8ECF166DA1F1136B4B656B05B660EBC999EEAB6B17A79916C33FAF27559CCD4037EC412F423E6F405CCC3CD23CBDCE20440C10F4EB57F6D735FFAA6251EC15AEA82ADDCA1FBC775B8F6B0E5B7AB6DA15617EE3498BD854EFF579F95293FCEE70A69E3A11D004108794B5658049AB6C7F259500E308CC12CFC5FDD4A5C324B7827C9DA4EC7CC8355D6E6BB4C662D4964A0D7A2D0EFC0B77EA7B6A4BD23F6AB4700DD303BBF680025D5FA3749D174C5CF1678A9858F7B8967115CA61028C532DF3B744C89FD0DA538D77DFBF4886DAC33F1D4A7AA4D25B78454C92A62C1EFFC0FC7580E5D273CD209D370AE118095DEA4B0731F531E879115BCC83434E24277E780EB2C305E4F0BB4029ED7DD76A604BFEA85B24ED0A9F140C6F9A05F079E2691F9C7919468AD4660676B5080B0B49E16C475495D8F2817D7FAEC6A65AFABAC647746E3AF146F563D3F52E66458708F115A8A9B9254C901D0AFBA9A7C42E0B1BBBEEB086AD0EE01541E0B1D3C41B27E895C580A25101A0FAE4413FF5AD5DAFA5EA12BA56C6825406C88467349ABC48EFD3B101FEAD68CABA4DC5925BDEEA77F4411BF9B160C112137179E9CC9A6C6037F84021EC5BB1088157F01900EFF837DE1C72E37EC2978F02AEEE8D238EFE1FE1556A639EC88BA88003686960B8013379420BB02778E17560C12F3D6D23E4F259E027BB7594A91580CA637B5A2E1E4AADAB03D1734DE86863F4F2DDA94E3B5C2E761F808045BDE4A8F62F5D15761B42A2D49FC220038F1C07CF478091DB7C329F074CE41E9DCA57ED2F387D1E8B42FDD9B02AC4BE793C1AE6F388B0FE3D42CD89ECCE1E293724150A37D4F0DB020D7C8C59A6D1A0A78425CB31FD1B050959AFDC6AE321CD24C4928C05BA76A44B4FE4F60C349496611CE268A852F74A190000DE2514601EDBAF57950455AAED0D717FE2081508C4B5197B4E00B924D1CD5872F5B9987F26EFC61A6CED0F821B72055B26D31531F4074C190BA9121E128A85D7BBD2A533750258F2420A9BE7B5875FDBFB6E0DFEA8167EFE6D7F738DDDA807D25737D638DCD1E6248A12FFF96B546374494622B48C972F9553B6C5F59ECB249A02C9808DB126FF2977D96495168583191BFF3487854355C00830D5260BF095CEEE55F6A1C3D5C32246F93CA3228A7EDE23BCD99F86AD14BF63C0757041D91D8743A5A6C09ED145462C12408C16B29D7DB206F25F26F6384131373E035042E07DDBA55F8CE3BE3F52779373646C88A8B13307CE3AE6CE605D6D658F57A341E5E931D2B06163109A03C7AFE78372C3E4B89E8CC05884A5870D44F21F7E2ED7BF25AD8A3289D8375E226DCA6346E6DCDA9970D6C916718D649C4BA31C60F11BD4FFF0B1E5F8915AE0573EADFACA324026781775FD580E98B42025A64E252AED2141E5734624F6E20825F671E7C392AA69FB7CA4497B1E8CE157FDC5C2FB1CBB3C417CA8D4BEF9F171357DD7519CB0F08D8B3C42A87693B6336891FE37312F1D193B459646F9C5AB018B23140D472B44A70D3837BECA12B5ADC6757C2D0BCA400650CE26571AA983C581412D538FB8EC3D4D4729F8E75E4F288FF87084498DF5B0D30DAC8904ED9C63A4722D78F5522E1D894EDFC4A0572EF27F0DC722290F7C035B6C70720C63385FAAC6446530C6333DCA630B0AAE31108BEEAA09F7167A3AA5061A2D88E1BC1116068019DA02B9C1A8DA9957C60461652A5BF48362693139308BAF6F16A8BA4C1E51E5042E17367934D8512C7D12749094B5032CED28AEBCC546D94E634ABB00204D49642F6D3703257B5E8A0814BC2E170EDA51958D6EE5A3283EE74DE805EA2D510C2FD90071377DFFF761CA24B4B08ABB376470596A92EE53C0F72E5FC54D75646CB7089C45168D92D39595FD1B7E738E5C82A0A179C3E67941753F8A191E3AB9FC65C7FDA7FE6620E6ED85C4FCF1384273A003329CC3FA98C09F4ADFD6F389B56ADBF0B5B675D66E2C8FCA9C4E117C404CFD16691B082D286B2F3D18A39659E353C06A2100829BFDD995060D096E5AAF230A92D9ED10AA52BEC85A9748BDCA8635D7387DB75B4FCA61189F85F2101EFCC48DF599037FF6432607623827F4A51BDA7FD73235ECF7C7CAC878C47124609EA95DC2CAC82182B5D0E557AFE907926C7383BB7238ECC6E7962DDE3B0731D201A6C38EDA31EA43A8FD2151508557EEB3360C50ED68EE65CC86DB24AA5357AEAF1355F91588B83A89400285179B76623E4F1AF4FAD0E498C86DC24356B5A945A572B23D2F5EC93A8DD1D7AD56694E311078F66B4852B3CE2ECD30B7B674D3C3A6CCDFA4E93932EF75D077190947326F2F8122DDCF4E0D42BEE40E522E1174190E04069989A957E73606E567DBAAC4E79AD1883541F5F468CF9CE5F52AD0B1545C6E1AF53098D576394B97B8589567142F26C75C894EC7081F9DD9FCC352BC5545810B7D9FCFA6F1FC11FBF66E3C002A25C1D6041964DB1D9702E5A2BEE8B2E68F4262C789F9845F7FC5507752D0A9D39DAFD6F18CB84BE0B5FDD68CEA0443136F15671BC948A02C4D7684541463BAC66902050F11B159D6F682018C1307756B824D084D698E0A450FAAB40623F7CC52331013D7FF3401BDBB802537371409360128C1D75B7D5CEAF7C00F66FD53B30EB5BF4902E39D6C5E4B5A81D968C31DFBA18DF50B25F506C5B338D03F24AAB057DD167187CB065263BC739BF0FB737224A203B57F5EB7E8C0B8834FAABD2D2990AA2A0C52419630AB2B914EA26905CA4FB6AB9D20E53109252DB0DF37B6A7A68F49FB56C1772FD31BD31A43CD693657A2B90FE4119008BB6920D72490C6F8E483EABF687DBF08C896D8814DCAFD3BCBF7692C7EA6B394FF413FED90900B4244EA25CFD2A9DDE9E3B0375D391EBAE07BE51B2D379A7A3DC045C0173DC168288B863C63A52D5912298F38CE6F565BD0965F71BB84DE1ABA6FE7FF9CD9C6AC22481ED1B2D2574B4E8C0903B851BBDE79F9EF80EE5FBCA3AD6B81F3BD3DCC3862D316765084A90E3F04332F7BDA6258B41985A2EA35CDC29B6B244750538E00CFC0A0D54B357DE540E141DA2C9D27D309394F93B8294E2D1543EAF56051ADEB86226FBB399D1D7EAB905208F3E3A5FE33514E2703EA58967283CFF74A7884FF435653FA3D7CA97C2BC0F817D74529219DECC20F0386D79BC9C938A5CD1634231B52B5AD9FBBC0B6B"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY('max')), + null, + "oªU_äa@uªÄÃ|>Aªu¢z<åvA©ãßbaUߪ:ªððzOZ*aßöuvCBå@ýoßߪ£ÜbCö.Äßav.ýUb¢|Ð/ðvZÃöbÖ_Ðð_aBýßäöoåOUä£rÜÃßZäavövÐî_zöãa*.©Üvýo.o,h<Ã_ObªbðUU<©Ä©~Ö+BZ_ýzäããOåöß@,C<åÜUÄ_ßðUA~ÜäÐüB", + "ah£b©@O:vz©/~havÐðZhÃ,å+>ßr.ªÄ>,/¢|CA<Ã/aÐ>håB@BÖ/zöÃ|UªvZ~äzÜä|ßZýö~åUvUäCüîÐ>.ZC©O,|Äå+öãÐåßCUåð ~B~@ärAÄß:ZÃ_Üo~rC©ov~C|¢A>+.ÖäBý.îzÃ~ßü+ãå.BUzöÄUîhrÖbaüaåßÄ©Zb~OÄhåäåªzÃß.ÄÃ:+Ð_£OãÐîu î ÃÄývÄ|ßãð_Obä+Zã>ü©ZZ_>BoaCUäZ<ßü@rîz/Bãîä_ã_:Üß_å,v©ªbhrîBÃ/|ý¢b+C*O,@bäß,.a£_ÄuzÃüåuh*:bÃ. ,. äîßO*/¢h+ ,äu¢h|*,ÖÖßUbr_>.,ܪ@~ß|ðzÐåÜ*obÄvãbbCbhîb@©:üAA_£uö@_: >Ð@aUaÄ.ªÜ@ß*<:Z ¢ÃbaZðOª£*ßUoÃA +uÐã©/CräCbv oAã rb£@+©BÜ~ýO~Ü/£ö*|.B,ý,äoOãîv> ýðã>ü©ãäbÖåäCAv*¢¢+ß:.Uöu©ß+Oßr@B©r©ðð©Z@Ä+*>hZãåãrvåÄä|©îZZä:©u_+Ö/ߪ.ÃöBvÖbî/b,ü<*ªð¢,ߢýa£,.bAhßC+ãaZ.> ß/C@Ü:råîüzª¢Ö+¢rª,b|©rÄîC Ä|öröBªßöÃCr|:>>BÄ_o+ýrß©a:ÖCu,ª©h> öÜ+>Að.öb.ãªbOCý*ööÄ+h@ö£ãÄÄz@_.üO_z*Ah/|vÐvoäÄöC,UÄOÜößU.äOuâ|ä.£å¢ß£ ß@hC,vÜÜhÖªîvßUOuÐbðOöuå¢O,Ðuß zÖðð©¢ã.ý£bb:BÐZbO:©åÐÄhãZv>uäA|z/Zh î|_+ bZCîÖÜåå*|Öo/|bßb,+*Ohª>ÐAß~öh¢îZ|©.aö_<ª ><ßoýÄB_ãOOAhðêOÄüZðrðãååî¢ÜhãåÐä¢CÃ~Ab<.z/ÐU/ÖÐ,Öß>z.Z_üvCß<ÜÄ ZzZZ~ð~©îß@î>B£/hî++A+./*|Äzðva£ªC/ðh:oå,b䢩©|, ZðåãöarZÖ£ßåZ+©ÄzÃÖîrîÖð|ö>äÃU~/Uvß@bz@hvå+üÃaB©rî+ýß*~>b*¢A|h©ýOª¢z@ßu|äã£Üå~¢Öh/+BA@¢ðzäî*,bCbU+ßräßä*ÐÄh©Ãߢ:ÐäåCÖ|ü£ýÄa©ååoÜÐ~_>ß.îz~a*z,üU>u/ª@Oýz©,ouhßO:ä|+öBvh©zö~_Öu©va<>/:v£~ÐväB¢rÖ<,_<ÖaAhUBÖZ~ª/|/Ðår©zÖa~îÜrß,AACOBorÖîUý*v ÃübýzÄ.*ÖýBO¢@åãUßzãbÐO,>Z+Ãߢu A/ ªãßîCü©ZCBð@©äbaoA/vüß©>A*Ä_hÜÖorrvý/ðOä,/bz~ÖÃãÖªbZªo+ßOZäÜvho* Üz<~b|uä|ä@Ð*ðv£åÜ@Ã:_Aß:ßob.ªvZÃüß/uU©Aã/Azãbß+ªh+*¢£äuZ£hv.o/ü~uA,Cß.¢C<äA>Ðý+ýÜ:Zuî©bC~o~C,ª©ýbÄ¢b/vÜÄÖUhßãÄ_©ÜZ£ÄoÐÃ|ýZ@£ß@ÄärA.a*z|>©|<©@vvä¢ð*Cüöã*AbboÐhîu@v~ßZ@z:ÄhbªUabÐa©AîO~îUrbýzv.Ö_©UhU©<|B¢å,ãåUBaa hbBýbö+ ªu_ýrz+@ðýäßb_BöZjkl*üýüZðvÃ/©rrå ä*_¢ÃB:+zBhuvªýoÄÖÖzý£U|ÄvAÃBUß©îЩÖ,£ªBªý£åßb£©ÄZü/:|*uBýð.bÜZbzv,B,:ArîO/+*buã£bßüvîO|ZOabãüã/ bZu+ãå>Cv©oå¢vßb_C*A>*ªbãßu/ü+ð ýbZÖý<ßozäaua©©îuýzä<.ßÄÃh_A©boîÖãî|ýAbb OУ*+bohzuübbä~U|bäöÖ>vÃBvßr<Ö>uÃbü¢rrC.uaäüÜhýh/,vrr:~Ä_A/ýC£åZîã*Ö~ðÄäB __ao£+v£ÜB>Zau>UboÜhz|h|bößu_>Ã,CåðAÃ+,bÄ:åßߪãCv ã_Büaü./BÄ~bBv,BoCz<_ÄÜÃ/äÃ*Ü:C©üu©hzhäö¢vZÃ>©*ª,Ã/ÄßÜÜhÜ,_oZb©¢ªîbåªUÜAU*ãZ.BrÖ>böba,äO/_+îªÄ©|~©Bª~ÄÃrÜ£uCªªrbå:bäå._ÃvÄÖýªOabßoªö,UößÃÄßb/:ýbå_ÄAövAýðÜ©Üüꪣoz/aU©£@UOoª:OO<|Uözozª|bo/Öß©ð/uZÐBßäîªbA+ã@ߪA<@Üýå.*ý©ruß~z@Ä,ÃZO:b£Ã* UhöÖbv_,vzîö|ßðÐ/¢£bAÖ>©:ã@/~,äb¢_oubðoüvrAuß/h¢vzrÐBßå:ß a£ÄÃ@<©ßßÄZãaÄAräÐãa*u£~ܪöuo,oÖýCCã@ah_+:<ß /Z>Ãîöo¢ßýÜaCðî_:£/|_ãî~r©ä~z¢åÐãU /@v/ýhrC*ß.BUýðßbUß~+ð>UB| OCAoä~|Cð,ý|,£ÜU+vÖ*zÄbê:Öü>Aa*/ßAaz©_>©åa.b©.ö~ÃCý ra:A _.㪪î,£h|¢ÜðÄÄU©/Ä©£ðAß+ßðAAuß|ýüCC©bvBA._ã ßÖ,vb_~Ö*ê+AuÜý*ªðÖbÜü~ª~ªOª£U,r<_b@ÖüÃUߢZ>Тãð.oÄ:uO_ÃÄ:~£u@voÃbäöÜÃ<ý/ÜBu@zÄB:ÖߣðãZ|BoÜ£bh,~ýåBÐß_oÄ©Ða:BzO.Ö>O<âUäßZäªðãîZ+@U¢uüZîªCüOßã<Üý+î~üðå+£uö@Ã_ßãßÄb|b_OÜuvå|£bAüßb¢|ðz :¢äüýAÖub h+CÖîÃ/OC+ÃbzЪrýâîuî>+¢ðu|rÐ:bßU>©îrð,r,ßö£, h+ßbbªhBuäÖCü<äü,ð¢ubuðZÜÜuÄãB|Ðuªbr,©,:©hZßoBöð ..Aaovð/@ZZ+/vCzAå+,£~Ä@o|ððBCÃßz+/Ã@Äb*oÜå,BBuåo@hr~@©ßÄ>äª ý ,ªî<~übrÄüÃbÃ,ÜßãUa*A_U*ðäUÖB hîva@Ü:ÐåÜ,ozbÖoã.v*CßãßboU_|ÄÄ B+ãÜßÃåa+C+uüäuoªÖAã>Örzb<ð+@îOobbbðUü+h_výa:ªßrðBöß©åã O@ÄzÖ><:öroîßZð£,åZUÜOä:£Ä/.ü+>OUÐÖÄUb,AÜ@bv:ð,£oZ,ܪ~|ý©U£bbb<|Ãý£B_r,*>v:UC~aÐzßvÃýÄ|£oÜba, üÄb@|:vzBüîbv*CzäbuðÐvßß~ý.aðÜo,öOZÖrªA_:aÃZÜð/u@äîüÜ<~ÄîUð~AU, ß>CBb+BvbÃ:Ð|@a£_O>bäOª:~~äü©/>rª*>Zß*OoÖ¢ðBaäh,uvAäÖ :¢å£><>hªªOUCuaÐäOa*zUU@/Ä:<Ð,.£:Zîä,hãã¢a ðÖÐð+>.ãã.Au++ußAA.ur@ßã o*Ä*zéuðª©ü_CUü|ßAU©>aðb©¢rßh,üîªuoÃ>_Ð*ý:Ü_ß>ðOU£ÄÜ~££ ßZ¢bÃO ö|ßîrî£å_£|ßÐ|ABü~:<Ãöªb.b:+/åZ@@Ðý v+ä*£ao,©|>¢©ö|îuÄ£aüÖ>h:Z:£+bZa|ÃãªÐCß©ßr,ã_ßÃ< ,ZßBü+@äÄå+|>A¢v>býCöOCîürÖ*£~£~ü üÜ<îªzzÐAU/CzOÜ|bÜÄ++uOîCܪOrCUߪobäÜ~:©ßroä:äî~|b_äå~öÖ~|ÜßÃh@îa£>hCðß: A~obz:väAªh|+ðarZvrߢü£ÃUäß*Ü:¢Zb_ãaßÃvC@ü©_,*¢Ð>ðß©~£Ãbö<ß/£îB~ýã<ßba.ªýBZ£zCZåubää¢üÄ/ãÜb åß:¢åb_|äߣ<>u©<+AÖßrðr~buüACbüZöBÐo¢£ÜU|ÄA..+*,ZubßAUCö¢å~£C@:ßã*_.>>äÄv>v>îßo©å|ÐåýovÃüÜ_ÖbCCbvu~bãðåÜ+ _@ý¢bßÄîÖ_ß|ß©Bã:ÄüC£h,uU©uBãü©ö@©¢ÐÄ ÐÄAO+~UÃ.îüý:OßUÃ,hÜ,+ª¢bßåãAhb*CCýUB<Üßü_Uzhä>>CZüuªöð+C.C|Ä,©Zä¢ä O~ou¢ ßäCZýoz@CÐ~ZhbUßðîv ©ðCaå©h|:<ä.uUýoãýuhbr¢/U:bh+zÖ:öÖåöä/ªzaÐb£åobåbbýöÃCZö,ýßrß|ÐÜäv¢u/+v~äAbä.üãZC/bAÜBÖuÜãbð.bhz<öO:A>zrÖßh£|¢_/h@b+>ÃýÜ@.:ªz OÜîÖ,:Ü,vªhävýöC£oZªßåaÖßßü.öªbÃî/ª+ÐßUB£ÖU:u£.ýã.ÖZzÃ_ZÜhö~>*:£_/üã+|+ßîrüA£_@O+ü~@äÜ,rî ~~å£~Zzªîß©~¢vAð+CÐ>£u¢Ür_ÜðßÜbÖðbýßöv¢©ÐA¢Ð>ß z>ð,v:.Ã*üC/A@+ßhÐð£~ZUýC>bÖªªåv,r:/ä+ÜZ@*¢ßãß~h*U>a~oÖAUöZÜ,£bÖBãAßböðÖü¢Cu£/ozîð.+BäÃU:.OðBýîåväÐýÜÖB,zÖböA@,ßßüå:UÄ©uoß+¢Öa£üÄUöÜÄo@hãab*ßÐrðA+CCC:£|r>ãý,:£ZBbUß~ªC¢:Ъu¢z..~/ª,å@äv~+|r _Ö,+ßUÐ>", + "|ãå_ߣ,Z*ÖüuÃ,zÜ./Ä/A¢h@oÜÜ .ªUü <*ªä©Ö>öÄßå|oã rU|,ý| ä|Ä¢+ܪ>å@aîrbÄîЩr> ßUöýö:CObãýÖo>AoA,Ð rð+|v£Z> ßÐÜbab Ö£/ > ã©ahb_©ÐÄZÜr©C|:ßOUu£Ã@ßUª.¢A@ß *büb@~OvbÜ~:.+:rvöî|ýã¢ÄÜ¢ÜåðÖÄÐÃ/ä~o>öUýýoäCb,åhr*bªv*@:UZåßz bãÜý@äbÜa©|a©ÖªÄuîÐÐ,£h/b hîrb/ããßvZ.+Zh|", + "Ã*ãâ|£î~~ð.Ä*îOÄh|öuå*ãö*/ß_/~ß|rÐÐZ*äªß/<ðÖ<Ãý@|Oübß|A +>zCb|AbÃbu>¢_av,Z.AÃ,u~å.a>ÜuhüÖOðã|<Ðå:äb,:<åaoÄ£>ha¢üZÄu©|_Z:övÖ:¢oÄð__|ã*ßC,@ý b~£ßÐ_ü|ãUbzð~~:rÐ/,ýýÐöª/ߢ:ªßo|uråz/A婢U_:öåbroü_åðýÜuß>r:a|väßßv£__ü+,î<ßððã©ßî@O_böhv,,UüåA>üZî£_¢CbB ÖäC,ohÄ.@/,ãUvÄA/UåO+|ð¢zB>ª.U+Aå+åU>a<>ZÖüªBhb¢ð>räoðörö>Bb¢CýZb+öä+:_/Ö,å¢~z@obä©ðb>äü.Ãzaî.äoÖÃ_ÐrOU:üÖBÖA ª¢üðAÜ/bu|>ü:Ão@@*_ÄäåÜßüäªuüZ,CðBb©bý,BÄÃ:üuuÐ|z/UÖu :ÄäoöoouBöO,b*ª<<_ö/ýO.ß~ÖCbð_b¢åª¢*ßåAUö>~@ßßO+üßüÃßß Zzb~rABz|î_@/ÐU©ª>Ä>>~îaÖ~ÖBC|*ßBZ*bÜZãrãOA¢vzУÄh+OBzßÃ,bã¢Zarý_Ð.o+Oîz©@£ _vÖ/ãB+üroÄß:££Ä:uîãüAB_å~v@Ub@~£>ohz,Ür¢UÜ+a¢ÄÐ@Oã:ªß*@Ou_vßãÐo£hhö>@.b/ÄrÐvÄ@vå_abrbýão¢öBã@+ß>¢Ðä<ÖUýÖßAU<ÃZ+ZãÃöªozßä~ rî ,U¢ý©ÜCZaZ.ABr_,<,|hBößÃhÄOö+./~C|u+¢Uýã,@~bBvö+ ÜüâbåbbU_©©_CCÄB_|äC ýÖz _åbö~ruö+>r/üð Ä*ªbýOÖh*ðð¢Ðr+bB:CU/v~åßA._AýÖuob¢ãrüåÃÖÐÄA£|>Ða:Cýã©î:ÖÄUüÜuC+oÃ<©~@äC~.>Ã_|UU@©@~äÜ+>hOB<Äðð_¢*åöBßo<ªý./orîO, ü_..+.©<übrÃZoÃ>býä+ö*övîaÄ<ããBã<¢CZÖbu~ÖörhÄ>rãÐ~£_¢a+¢~h>+ÃO£Cü*r£b.ÖýÖZ¢ahß_.ßåÖUr|u:v>ê|äî|ZbO+z_ß ã£Ü*,+<ߪB|ß/.î.hÐ,_Äo/î+bÄb¢OCUB.,_Üäbåaîa:zBhäoÖU|oUªÃuåü*£.o.ýzÐaa*¢v©>@ßoü~Zîäîäö_BãßÄ îåÄUªÐ~<ý*hãßCüå©ÄÜ@vZÃ/ß>zªðÜaBÐü£/CAObªrv:B/BAÜ<ö_Ü,~ð.ßÃöÖÃÖ©Ü.|@ÜßÖoCühOÃßߣ<:ã:ã: *+Äa Uzð/ª©Ãå|vüÄß/ßU.U¢üA:zãzß brhbÜ/ßä£rÖbCCÜðräÖba@Cü<,*ZÜabCÜ*ªÃ.rrZü|hA£O@ãv_Cü|Üz|BO~,b@B£h¢ZÜ@B>ý©îAîÐ obhzBÄäOAåz@|>äÖAbZÐ<>U*äv¢üåov,hOäOÜß.ãÖ+bßoOîýCãa*ý|öýäÖ*_î_Ão¢zab@ß|ß_v|åü¢bz@ä¢_bhzBzäÖA:äü~@ OãOã< vußÄýbAU©AabîoB>aîÖ£A@ ©zý+¢:UhÃ+zvß ~Cuã@+.ãî©+u©ãvbßZÐîh,aÄ,Ü/î ©ªåZO.ß_ß>oðß.za,Ü,äª|a_ðOrB@:Ðð@@ub<ö>.:@aß|üzüÃÄýaAAÐC~ *ýuÄA+ÖU,zrU@:vü,b|uüöåu,ß:Ðå>ßC£b ~aÜ:O_Ðb¢£|+*,CýzuîA*î@bÖ+äÖÜ£~îo£+ä/ö¢ðýßäh|Cßr.u:ZÐAý©<ÃÃßÃüZýb£rÄAU_*ªýA@b+@¢|£*|OzOh©Ã+ÐvßUa_åBððBOo©B©Öý:¢CObUA¢ÐßÖ:bA äßBßÖaýoZªÃ<.aO_Ãb£o£ÐBöZ:¢Z£äÄ.£ªßýrrhýîö@oAÐöýð.h ~+ö_+Öo£B_o/+|äßuO*<ö£UÄuöî|>£*uÐ+ßv£U¢:b<î+ÜbÜ<åhÖÐb£,öhU /ã~h:OöÄaÐ~oý|å.:Öåðho.Ã*î¢hbüåh.îrª<*:rã+ÜÖZýÖOOuörUzrv/îÜ_|ߢAã/ÖB+vöBz©BÖ,£,+h/öãAÃåBÄðO|~î£AÖÖîãU©ßðZãå|u/åÜ@..CãÜýo|£+/B+@,Aba¢Ö_C<¢A|rßzåZb.bO<@OüÖÐZªZ,ßîz>_o.UaüZö>ßuß+UÜB,© *ð@åbäaU@Our£åzÜÄäß,bî_A+Ðü+bãOao~ü|aZ*+aÐÖÖvª|îb:bu~ZU:+<>zî¢OÃýubbîÐÖ.@/,*hßÖÖObzªÜü.å*@r@Üb<+_bÖA|>ý âÄoååz|ÐÐhßz~ðAßOÄ,@u¢:öaßbAÄr©býîoUvý:r£ßbî£bühÐu+ܪß:ýUråBu@a_<Ö ©ÜÜ_rvrå/~|Züãöz<ãå/åÐZ+öÃO@,ðA,ÃððUZu@Ä~ZouªÜßO||ÖåCA:Ä¢>:ýA@Ö£,ÃUîÄîOã£výazÐAOåÃoB@BðÐð*ßîA/_>Z,*bß,>:~+h:åýÃ~.+hBäOÃüýĪª.å>©ä£OzüaB~ÐA@hü:ãð£r>©z/¢CÃ,bBÜåbÃå:ªUß+¢,Z_+ã©_ý_ä©ür,ã*.Ab¢|üaßãüßv>äªBv~B+ÖbÜ/o,@uCðãZbBOuÖÖb/ZÐ@äãZ<©v|âZ:ª*U¢ãühZåý>b¢ÐzbbýåuoB¢*~ß aªUªßh£ð@¢îã.uU£©ªüðOZßããb bC+uðA£C©¢,©îüßß/oh:ýð/üÖªähÐß,ÖÐß|ßo.ýßÜC|AZöbü+>*Ãâ o©.,äU¢ðb,a¢AO*Ãå+.©ß@îÜu:ÄbC<.hÐö©¢vÄÄߣaý|+ä @*ð/ßUУÜvÄo,@~ß~üäîB>Ä.o©¢Aß_ ,*hrÃOA¢åaZî+||zvbr,ª>üua£@vh¢ÃãUðzßUzåª_*ýåߪ äª*+ý~hÐî,ðOb©Ö+z>ÜÐaBÃaªr_Zß*Ðß £b+ß>b:/Aã>ãîUß©bBã*BöÃOÐýo.ªß<|ª<*uh|ß/ züvroÃöЪÖUîZ_Z<ÐîvðvAhbZö>:<Äðu>u©*ãrhvCrUЪýaãÐzv_Ä£AO_ðÖvo©ÖööÄýbåð¢@Üýßbß.:zö£Äo:,@är<ßð/äB/:zÜîýüüß©ÐÖÄãü,h<: >ü~>_OCã,hÄBðî+ª<¢_züÃî>Ä¢ßAuB©:ý@ª<äßUÐäC~©ü£ãß<+î@ðh+ßbBÜð*B¢Z:vB,ZîЩ,ß/ãBu_bÜa_ãOo@ãoÜ.ÖAz+Ü>ZrÃ_:@|¢UCBÄ@Ðß|Äo*_ÜCzÐUU@<ý¢b/©*ßAã@ >ýuöA.h¢A~r oAuÄOîözrýb£ªb©AoîßÐrßã||oZ Cª<åßzî.:£¢CåuC@î~*ýÖBOäzhU~@v©ãýÃz©ýßz|ah*B o|uß<ª@UA@AÄÄAã@@öäC¢o£åüOrzbo:hB_h|AÜb£o~öOZüvÜ:b>O>ýÃað*ßZ.rOäbåªOåv<ÐîrüAr<~að/ãA©Z¢CãC£ÃöÖUö.BB.*båO|Üvza©ß:Öß+ý*orßU>*Ö¢ßÜoöaªC+O£ã_©:åa BozOðh+vªvåzoãÐC_ÜýC*abÄb~o_:ÃÃzßî.O::å£ßÃ,*ubaßC.CÃîîýbCªB üãßî||@U/_©Bî* ©ªÄÜ©|Ö+|Ö", + "9999-12-31 23:59:59.997", + null, + "7073-01-31", + "23:59:29.04987", + "2002-01-31 23:59:59.04987+08:00", + "2002-01-31 23:59:59.04987", + array("-100000000000000000", null, null, SQLSRV_SQLTYPE_DECIMAL(28,4)), + array("100000000000000000", null, null, SQLSRV_SQLTYPE_NUMERIC(32,4)), + 0, + 1, + null, + 0, + -1, + 238, + 0, + array(("70BA23A819E1BEADC92E0840F382D7A5DD89EDA9FA12486DCD843FA57FAEC5439F0DE3836E6804ABD214C35672F9552A2CE003709ABB9C5E72B6DA94A2192E1B68C5A0E69F5336758441D7E54EF1FAD32E14799EAA55A9E3708411B88D6F09B8E6A7EDAD586F8BD8A98EEB58E4B61080BC06658DA09070131BBC751A427EE715381EFFA6044C7BBF89A0F41C6A50FFBA7490FB86097B185536DA929BFA70952BA7D520C6B6697C6F8BA604FF9B54A9CABDBBA6B282600CBC06A96F29BADFC419"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(384)), + array(null, null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(384)), + null, + "|Ð/ðvZÃöbÖ_Ðð_aBýßäöoåOUä£rÜÃßZäavövÐî_zöãa*.©Üvýo.o,h<Ã_ObªbðUU<©Ä©~Ö+BZ_ýzäããOåöß@,C<åÜUÄ_ßðUA~ÜäÐüB©uß åähoßÄ*åÄhCÄã+rãî*Aßv*zöÄBüBuÜv|ÐbuªÖª.aOörBîäð<@Cr rüb@|O/ÐÐU£ðä|üÜoªBZðA£ hrbäo<~C~ð*ÜaÃb|OÃvöZvu*îo ðAð.OzÐ++h~|v©_*örrÖ:|@CuÖÄAåü:ªððzOZ*aßöuvCBå@ýoßߪ£ÜbCö.Äßav.ýUb¢|Ð/ðvZÃöbÖ_Ðð_aBýßäöoåOUä£rÜÃßZäavövÐî_zöãa*.", + "|ãå_ߣ,Z*ÖüuÃ,zÜ./Ä/A¢h@oÜÜ .ªUü <*ªä©Ö>öÄßå|oã rU|,ý| ä|Ä¢+ܪ>å@aîrbÄîЩr> ßUöýö:CObãýÖo>AoA,Ð rð+|v£Z> ßÐÜbab Ö£/ > ã©ahb_©ÐÄZO+|ßOýußýbßuýð~.ußb", + ".Z/A< +Öv>Ür©C|:ßOUu£Ã@ßUª.¢A@ß *büb@~OvbÜ~:.+:rvöî|ýã¢ÄÜ¢ÜåðÖÄÐÃ/ä~o>öUýýoäCb,åhr*bªv*@:UZåßz bãÜý@äbÜa©|a©ÖªÄuîÐÐ,£h/b hîrb/ããßvZ.+Zh|", + "23:59:29.0498764", + "2002-01-31 23:59:59.0498764+08:00", + "2002-01-31 23:59:59.0498764", + array("-100000000000000000", null, null, SQLSRV_SQLTYPE_DECIMAL(32,4)), + array("100000000000000000", null, null, SQLSRV_SQLTYPE_NUMERIC(36,4)), + ); +// 5 +$values[] = array(array(("F77B01558B14390B5D153D199E510EFAB893BA155798F1E832315A12B2999B22B7DF0A26306B294E97CFECDB5E94FB5EF78585B07D2D5EB61AA04B601C87F977382AB851E7FBA867FA1467B89C16999D460B1B2D13DAB59A80541B902FB9221FC665A333EC99770BDD2DC658C59619F406AE2A117CDC636E1A4E83"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(256)), + array(("1F490F38B008EF657365696D8818EE15357EDAAEB125EB57039C7903DE118446D026129CE3E093F2811D83D76D0304A604F7A0783B2385D3C7BC6AAD2C4CD779FB44239306512144DAD82D93A203E9F097D30ED6710C0BAC903EC53775F6C6344609DC28EF61AFB3C65B9D5305E231B3C27A15594DF0F8EF387DEE40B0063A2F"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(256)), + array(("42D6C508809FDBD47B9A6BC196C023120B017BAEFCD5ABB38663B66F51120103E2FC469DE7010BD6D65EBCF1E9B60BD614442E2DA9C0386C2B12811DE96C83699968DE997A862A0AF6A5D79E18B9CAD058E05A0DE3D35922C4D972D580EDED6ADB535881D7715B8E1A243704E89A547147B1C508117585C60EBCD5A113548A08B76DC3C56148F8E684CBF3BF9B55392A84018DCE28E45865CD92721B9BBA7BC5992F4D7BD68E0FFFB8DE844582C62AB982AA1C11C6BBDFD2145EF8CED5DD4BCA502D256C07BE53F6F18E164A6012E20668B998F19D69FFDE4F7A6678964129DA93BAF455A0BEB1C457261F37A49572027BF1661C455A2CE72E471D8D57DA5FB0653CB6A61D8C66AA08D3997749C739B90864FDA5DA0D95398E0D2759A0246D7CC76FD268DECBE4EF8ABC1371C0B49D660D6384F2DDB9D658A67D1810650C09E4661DB0DAF5D1DA3C800D1A1EF92379D96FC04C3DA07A9E0D9879C161B3D4897EB32F0AA203C3713B884772CF9EB75F82043EA0A4C0CB43EB7EA3417B107989AB849C6BC919D6D5AC4F11B45808CE6EE11A3E5D7434E5BEE7EB1F246081F52B0FBDC64B024C95692D69F354AF17EBE3AF346060D11B14779EDE84DDFAB2742B59E5A49B42836B9584D42F0B40910FD0003C742B21955AF4A94EAD24C8B86F7BF4C8FAC97250A02CC9CBDBFCEC09370DCFB3DCBE3D4809C48BB0F1F3D547CCCC65B3167796455DB09B476256B95D08A017A05514DBB13EABBE353EC15EAD5781FE0F9738F2BF7689562C22F6E6B30B2DA851DC35F2B8F1B3756BB960079B52EEF0E157A9C6CFAD5729CBBDAF8E48C50B2910190CD0218E461EE3C287061682BADA3405045C6267D8A3840C27FA41242DA5AD36F682451DCE52118BE30D2651134903D55942C1AFC7A940684C15674BDCBE94E158DF8B38941736B14AD683CB7D32F8DDF76CCAEBE4FE6F4D41DCD1B8EBC5AE247844F933BECA40420B0F64F02575EB191C8A546FF3A9FD59703DF7B7457DC684285F523839C51F2C2C88DFD49A7E27CBF1B89C61713F30CE47A0C381D388FC8D48DFC8C623B2E0576B27436BC928BFF1152CC58DE16513E82E83F199019D59A38B528CBAB661A83ED844F64AFCC5051EE0D26BA7C26FABE3CCDF979FC14656CDCE9FDF779C043BB38387B59D6EC8EC687ED2B82F32B2E01CA6A8EED6C9087D91EE297B5CE58D82DC96B7233BB90E7403F32F20EF8E269A1CBFC3D1F41665EA7B0924AE454D8F83F14FDB987B8EA4629733EAE29AE78D02C78E5F9D21BB8EC631CDA831945F2EB664AB2F9FB38E1F8D1A6039C02B824F937B22E7B7EDF16135C11566ADE672CD3704347EEEB8EE4F386FD283C081CE9AAE7D14B6727877C8724AF9DE9D2771A7A79301BBF70460DB8DD3AE481B6EA0B3F37AB730D1BC5BBF8D6B0BA4BE10B111FD2ADB2D7F12A2AA1C39289FCA2FAD04A946EA226F41D5EB38422E8CF8BB1C7D219C4AF0937333E0D80D139793BBF45DBD07FB77258EA1BC55EFF53DE416B2601CAB7E2DE4BC703612094A622D3E577C4ED0CEF0C0A55793FB8E9BA37DF6FCC25BB37AE83DC6790196C5651B433F8E169878EE1347C1A07753EA325620CDB81C0D88077AC36F3F8757CD59FB3F3C4FBCFF840A0407E97A99120394529423E0C90C480EBA371453293967BB7A68A437179A76569BC2B314230E6E67C0DBECF234EC90EFF62D9484EB31E1CBA02D00316ECB7CB71ECC45065834EAACC9AD934D4C74878ED7B540E906F26B6AE1E874F60D3DF9F55E35D467A78997C243E8BA3D9D937F2BA57159B88A92B12C61DA256FC0F39E8CB39EEF16A020E74D1E7EA61E372DCC4D6848509CE3406ACB83A806CC6427024F492E8AFFA4688B858A0B9A0BEC93F4340DD70777A302A872332392F7191AE8F67C56D409A2CCA9FFBDCA11D8A65FDFF0B3D1BF8D1F8BAC468517CC80D5936B7022A38F96BEEB91402E08B9D8F1CFCCD344A243485B5BD7F0AA8D848B002829295FA1B602CF4931C8407E5F17D1D355B54BF83C33502314C6CC9EEB3067064006DE90794F19C904FB717B07DCFCBF1FD638CE4007EBF6D93B8CEF36305D00613A3D5838405A069C81F441C2D51B37CA0C7E15F898C6391AE8B73DC22993D39D7019CD9FA386DF7B3232BE12AA330320542529B24808C874043E50891D4372EE21A351BB4D9827859F99C666072670B4B31D6E046921556850599A6536555EEFC0CFF106E248D2BBFEA312AE41626CDECE9BD5FFD56D85004EE96AF4FEC24F4A3BD7A538356AD26B4BB206C50EA726EEEDBB969B7F5F1A5249F1B7F8DDDEBD3C54C8736ABD33A963C96AB42266BFF1A7C37C06422BB3CADCBD52EE44B2D98D6DF4CA704634BB30B91232D215AAF7EC8AFF103561D77A11A0FD97AD6A4565B1EFDD472D9C4EAA72074B4C2FF8E1B531C5666444A1A32C957AB9D0489D0EC674AD81E23763C94F3B549D2E158A4A18BF4865E703E020104BB1B1B3E27E62D5F985D88276FE7DCDFC1729EF0375160A2FA010FF3726C2938C709786B2156CBCF2C83490B2C8A2C0CB98EBECB7310DD59BA684426D629ED2C244F50667F71BE6AA6DFC3B41855866FE50349E3BD5DC5B63C1EB0B912A4E902961CE6ED39B59D47D04424A35D294154E1D431D2D0097EC679AA2A50B0F54801E6B11DFB7EA9362F7602037939226912DD5BC73E6316229CAE10639F9B3C86DAFC22BC9C0B55D648AE126CDDF6059D57311783652E099ED09E714D5E359694397B387D0665DD0777758E9050A944A6A8831C5E73B921ACE283EBFD8A188813077E2352CD8886E164001BEFAF794E2749DA94DB29481080598B8A8289DF7D6EFD7B88D275E1E91FFC2AEA73AD320D7945B4A3BF73ACF9CF5DA30931FE04679482ACE233E06BB157F174DEFE5DACE3177E113CC52BCDFB4081C984C2E8A721F7B355E0F05FC988DA035BBDFEDDFB61B0CFE1B3DCC7A268B4B191B226E6EE7F5A52D73B07BBE2C7B49862B1D01FFC728667C40306E3453010ED2C4ECE1761F324DC639BF6C059F4DD1A0F4464E098A4B51F3BBF12DB68670DA71A2A8FA4099D366F9CF3AC608BC61DDF25ECD400CB30448789AEEBA2D04973FC8E4FA63F653910620DF54394F8549375A143A58B930CDBE9D6081A5AB1939F438FBFD23C1FDE69FCCC6202D5ECAF8F351B75F19CA3E8698163CC596D1EC5B07A66001548825755C2D9B8BF210A05FD2678E54F4B91F2AF975640C853850CEE06B1987FEC9A46A2B4102EC2EB3938876DCF32E4397664D863507DE2419F024DCCDAB87F6186108C22329B2B633FB46E1DB95A945218A4804CB01C8C1C5461251DE1061070B915E7AEA6C1F6EB496533AC1FD488346DEBA4262832A179947FCDC1761D723993ED549372F5BB56BDA5035AE8D00C8FE8E0AFF551FA4886647E0A26F435752BE2FA08227FE4C178305D78833F5680B4633DE8856D8CD7A9A4DE3EF4EB8452882FD767EED7EA1FF42F37C50481C5570DED45B3C65CFFCE66225E8D91B5CC8CBBFAE05367FEA1EC891DE45635B7D327DF872117A5C09C2B3008F1CC795C8E4E62AB19099161FF1F4B693AA8789998AE4F36AE1A94B4E6EB5EB5135EFCE5632C9F95F38AAEC9867D9801DC3C95F3B2A670437D42BE73B9ADB42DBADC4E901265F60E08D2A60E0F75A0307282E8AA456B027CDEB968207E2BEC45D6811EBA2EF7FF664697EAE0007243F7928DF126C509D84FD9C1C168FDC58FECF650278E66F6018A937263BD70127C5C75609DE02AB570CCA8CED05D3696787107FDF9A04AC5909C8C769352A62ACFB75564F39D379FB230DF6AD59815A4440D09E2A57228CC01AFCFF163B4222E168DFF1907C1A2DB49784BB8C0EFE00876D8229658C3755D9E895343DD363BFE1EB1544798FC9C825A2EA93D367FFB21BFC77A8B918BC55308A18A8E6E5F0E034C4D9A1F9BA86F7A4B903C2A1A48171E8E318415BBA06C82EBF14EE7721E140B2095E0F8D5EB961758004FF15FAB38C09A7BF03CDAE8479BE117239A6988083D7C30F974572E48929B7CBDBB606B3340B87E5CF61DE730385E5517CEC80BBDCFF812852EA1B4697C236DA15E3A8C3B75D3E2D1EB3B021F9500B126020679DA9FBEEDC34DE6149F0404D0C2A035D20DC21991EAD529C294E5F2E01DF09E6765B983119F4CC8ED9FCF43DDD65A3F6F6F3EB363F8748EF565EC58ED5B05F6AE65AD7B192D2432C1092C022B915BFC4AA68380EF4D2A7EF13A8DABB2F3DB9299C8A56838EF26423AFBE26ACC72536409F00E46D77517613B3E79EE9F788FDD2D996852EBF3C36B703145E35ACFA28ED719A1B2E594BB14B1342D0A6547A2B27C153D330A0078163CA2C6963F24167B8BFB1775D6CCE788DE53A1B7C6B8F6388E936735827F74C6A18B7632CE24E59D2DB17E6A303CEBAF2DB454B66EC04F73AC9E079BBCD0E90C7640D44B46A4CAB96E048A054A8C0851A7B817DE1ACE67D14C0296301D49D05CD871F3FF58A05888E9AB485A463A391095B5F3F4C90AE1B7D9030F441E8A9C24342D3CC89818F9076F8EE47F861D8B01C975AA5755DB93CD804C165591146A6F0F2416290D60888CBCEC953A167221BB780D7AA8E034CE58896F485BF2A3664B24856051F761F458ED2DAA693669B70E1A6AED9399B18EDA55BD9F9E282C8A19864A058111DFB4060911BBB29A65122FB83A4197C5C2B1630685FC49D26630C09380E2EC5425EC3AA6D79A7805CC3FF09B7FE5FDDAF253B398A28A8BD37A33A2E0FB2F097235CB824E06E0FE38396D4A560BAE627032E5A13D3F53B1AB50672C93E7871AAD268E65A453AFD401657B5F353035D7CBD122AE058DDC42D209E6EDAFC45A40B252AD2F7D38BE2C93119FC7B3F48C6B2A8F50B2C4D9051F5A3B93AA7CC2244D0B3AACE293165A8323061AF3EE049EDD8D7BC32063978BD94D8DC541A503AFC0ED52CC795799D80424DD9FBECE113145ACB62D00FF03E963BED395054118DE1F564A069B481585E393CEFB9607CD1B3C5C7FA4FEE6AED1E96958CA83F4D2B31BFF7058740A960D8720397D3008536BE1B868B8D163EF38B7781D21FF5B01FEC10BEF968764A731B6722DDEAD2191E115ECD8CB9C19E1A8103790FBFD640E2C1E4ABC2428BCD48D1137025F46008B95D63C1C02824652A72A37864FC3AB444263F1C062756DC869185BAA651782620FBC0B15B1580BA9C7F80509F12684B965F2CFFB543029107873B2FA269BED9FA7D57693B89582EA6847F87A6063C7328392447257870DCF82FAAD4DA501732C0A75621BAFE0F0D07FD5930C47BEA004AC707684577B4810C7A710CDE8354556C4CC7FFB01AB9292A1640271F3F187D44A98A1248AEED48F3D5153F8D022E83A803C477B4EA502F0EDD3E2F368C61CD62F3C735F8420CBD5F7E0CDB05799B27E7BC7F1C7BA1C85A585B036B70BD11667348DD993BF98B66F6061836DE7529954116477A0D4551C12B6DDC9C3EA14DA16CA567BD9C02ECED3118267489927BE3326E29597597592EF61C6ECD1DEE2754B976C9380E6BF93F2A5949F41FDD3898F2F86AD078F32BD44C38C780931ED042F1D1BB12C842D5C674E92F1C4E640F18E3D6DB248456DBC64AF5ECD5A479AB0B8907034D2225CFAF23A45B8EC40F85E729AE9CBD43ABBD9AF5F4C8D356FF22FB3E23924761C2F6BE062C00E0FB4C013A6F04ABF5DDEEC8DD4968572D5CFC5823825F50A07C3E8667B8DDB616AADD9FA8F28D6352532C1E505AB5FEF96AC9610AD3DD5E9BFC61BE317D443DFF37B1326BC8AE3ACF9806D055410046C73F8DFCEE7BAC43CD7F04AC91CF32D40FEE1E18A8829230BC8E9272CC0C0859FB1AF6F1F0484E848B6D64ECC301A8FF6532C16722E79D44AD5C4060E83977C077ABB077D840E3C6A09A8D3A1DA66CBAE5930C994BA136147DB2449407EE9B51F6A47418503127244EFAC6885A622606EF857A552DDD75D5749CFA26FC4FBEB1FE3B4479315369B46BE74B51DAAEBA1A8B3DA481734624182E9FA4B4370128FF3B158A1E1EADD49C1CC5E9459223FBC6E2DF9ABFAB3C3DB8172B4A92AFB57D6ABF4C15C5249CFCDE680765AD5CDF860BA3DED157666953FED7D106F26242EC67487F86460D36A146E3BB56A3D7905B38A43FEFD0E3250356F817ED5295097C261BFD65DD5840FD6D3C8A73AB12AF274776CE4D22531B83227B2F4DF6484FB1DA3E3088D92A7EDF6442829458B1584349F0A6DBC6BB59D3FF79426228F30624ECD9996CE2274D1CF7EFE9E0D1872B7022EC0406A173EA1EE55C895FE71CB6713B5DA77E18EB6021A28AE4D7D27902774ED23F3CEF008278EF7A87859EED34DB3878A573E0AC58368BE263178F124C6C5A111015DC79823ADA2E8F9D64DA83B455089E5AD38E97A27908B00C9C6BE9DD2D1A2B8CDD1EFEBFF56A99B11DBAD2B05EAFC18773F298CB796E9CD4C8759E6E45B26F49AFF6D7370ADF6468F5E684BF3600AEEDA961693B825F136E8229F680CC2A6B6B4A880167D78A7C938E2FD693EADC9EC8C6B0C4E34834C74FE369B4E0E9E39BCB7A1974ADFE47151FE4D5AC52897F83A58B2DBA1C65872216C1B1836ED69CAAAA940B18D068F1C97F9BA5FE728775C663E50E54BC297F65F3F65EEC4DC3A749482B02BE7E67B33D9A633A80BF88AF8E4CEA1F88C748EE8114A524D90A047CBCF45CB64785B648FC32D1BA58EFFEA56A46CF9F62A31E81FF3D80AAD942D93395E77E8C63D1680995A22356F68D959215FFBA933A651918D6DAB609040C6FB9589D247070724298DEC60AC07FC78B71A7EE94D98846F830CE65B6891A5E0488326AFD58682421A3BD21B4745A58980E4E44621678953112A4F4A20BBBB87D7FC1818D15C9320982CCF11C669184D575CCA83AD5FCED109D39EBB3748216E804A435B2D9CB83451B3BDF498678CA81201E2D3E137EA782D470F0DCDE7F9400B60918C25BD2FCAA48621E9A1CA489246E69935555D7D486FCB2DE68DBA7679CA7DF927D6008254D2283F5B05F0D6530E7CB6D74EB3FABDF3492C5A8F494CFA1FB81F33D110BC365444532D1E12426EF4DAD800F39F2B16734B349CE437C598DB454B4DD1A281FDB070830A50CD9FD0F6BD65B4613BF6808D08B095DC2F522C7EBA51D8D6F49D4248EA50731C20B5B5AB539636C21137AF4EBAB0C8F1EC11812E568B967BB709F210236B76EB83746C530AEA78891B6A6D82B29A1C33C4505CC8CF44B5951F39E4599416AEA5C0C3CB465475E701A90802FC2E13C92CEDBE5BC31EAE1C3EBEC743C0F61EE504BBB7C1EECEC5EF5E695B2FC741B966FB70B76BD5CADB9712A78C979D32160B8A130E407651DA6E17DEFD69B37E54FCF55048503EA30F49D020AF47323E521C434FA5A43378F0A996595406CD71D394529F923CF9C5CCD713B46055A2832BE98CE11663D8A0B97C5F9EB9D55F088C6E4D0AF4A29C15228D82DE908F18AAF7033D6A89EC6B7FCBA1D615DD5B0BE7780B380208979E794D67BE88E0FA103A63B4A7A6A7E48EAFF2DD4F42CC7647D7719B56854716A26F74B42D122DD28EC191ABB228B3554F838C980F3B584BBCC72FD71745938AE34D123831E3C76C72204E7DB110C41F241C5BD308BF076707290755F256CB392E06B875167B235BCC1025EEECDA8A9C0300B2FAF9C0723435AB2108EC616A2B55054FBA584F08A8F8F016E889288A3C9E6B52F193D04F6D84843F7B4A1A7F5AA60A89D79AD033B3F809F209B989AB1D10F47A710E788784C5E225D41F9D6EDE70BC428EAEB2A1BE379EF999DE45B3FAD9225A55A00E4C2D72F501B8AA5FA46A9B23890D472C7E6E52BC497F8EEDB6803E3B0AFD33193E7260151BA9A0F913D7FA8EFEAABCA6A3ACB3FBF2E3B4DCAE854E718A7F54B73781E5069D3210C4BD69A87174FFFF0BC387875E3937164ABD8366865B2F7E948343576CC5B609719BEF3E994B4367AE9632BDF2E7F67DF06B9A4919CB9A699DFB03EE31A882461D7E15C25A088D0F6A2BB7E028717BAC9CC557012B6CFFA60175A09E3765260613FC9084D22423F7EE8ADEFE13AA411C8F57516C51811AB08E6FB0D457EEC804F5B1DC3BE0E6DA68A16F12908DF1926734841EE003C9A482D1E00662734F9FFFC2C9F851CE053B988CF8BAF26E7A228CDD59AFD3CFE8013C0D4959F0E067F561CF12DDC3F940992F5886530B0EB22467CD8995199FCC3FEAC8CC4474BB3AB8250359234BAC5E839CB0808B4984F62D5B24F23356C2DBC202E2F30B3CFC24741DCE3E07A59ED8CB6F0608691F30E655C29EF95FB907515227971058A95356909C1C7D7B56FE87BC4C36D450CA72A2C1FC9D489E02C4BB067CDBD01E7E80120BBF67CD02C37B0EC4173D137232F097B4E45E6C0C1AB89DC751670E7B1E694DCC24C8A152A59FFE819E7476C5B138D37C342B2A201405F0F6D9F5B16C6C83B5BDEF475D7A4F451F545FDA7DA641C"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY('max')), + "©ýÜßOåÖ|_/Aãª+©ÜÃý©>|a_@_äßb©ÃO@ îýUå~ÜäÃÜ¢zßöÜ|ß<,£|ª_©/UZzbÄîã", + "", + "öh,bZv~Ð*ubzrUäO© z|B£b.öÖö.äOh¢äÜA/:~:ÄCo*©+r|ãÜýÄß/©@zBüB_zOåOb/:.r/Äbä~:öZ,AÐOB¢ä< rOUÐ*<<ð,övO~öÖh£*Z¢öãu~aÃð**u_aÃÐuvoÃCßBýb:Z~ä,*ü©Ä£_h|o.U<äÄ<üovAAý£Äîîåã+ZÜU/ã äz>Ö/Ã:+AB/¢ö+@bZA_ß.ÄUÜßÖÄÖv,oߢ_ãO<.ß*|ª¢ªuåAðobÄö©ýÃB¢ðªý,_ ~årrUßB¢z_ßUîbåö𪪩CÖ:o+ä>ýÃäZ_ð@¢ªaÃÜCb...äÐßbÖý©,ßärã.bß+ZBö/vv +.vðUß<ªÄ*bZ£b:UÄOåÖbzßrüä,ãü<üoª,.¢>+ÖOzãäUv+>vb¢bü+.£¢U+îÃU£ßÜ£Ðz/ßßzßrÃBaCuÄÜBC*a,bbo©¢vC:bð£aB~@bb+>/~ö+¢åüîåzoA<Öª£@u,/äîðßãOÖrÃßhÜ¢ü_Ü ,:/ÖCã©ðÖãäÄBUhAB,ß|o@/CÜubO+.>uß CÜü©Ðbväb*å<~|ýÐ@~ÄuOåazýîÜ<|* £åÖh*b.£ÖZZ/BuZ¢ªouÖ£©ãZÜzÐAUªß/£©Bðüðå:ðbÄZzzð/,ovªîª.Öß<>ýÃbý©ßA_üßa@ÃZÜã~ü|ý<,z¢b*u@AU*B>.åÖäbb>Ð:îAv,aü>ðbÐÄ/©u:Öå,v,~ãa,Z+.oÄîÖvuO<ª ðCß*ãOÖzoÄr:|ÃCu åbaäC¢| roý:u<Öã/üvUa£aÜãöu:¢CÐãÖvh/ÖÜaü*¢Aö*/ O+UühÜUbb¢>Uo/Öbb>ÜvªoöäÃß@å,ªb..¢bb,h~b@ubßv@ã_ª_ý:|oÄA.+Z U*©<_bß@,©ÃîîÄÖ,BhªOüüZ㢢ävða©aävßo|~vOà oðäb_ä, övÜB+Zbßäðr|ª+ý©b£åªß>ä.<£ß*ý_Baä~b,uÖî_bÐÐ*ýhÄßöOAåüß>/,+¢Ð<ÐãzãrÃaZª:ZÖ*@bÖ@.*ða.ß>rAbB¢ýãhOb*î/@Ü/Ä> ÄÖh¢v.©åöZß: AߢO¢ð£ªªo~vOO a£îu>bBÖb,ß©üCåã+¢Aä¢å~ßÜäÐC~_+BU äz+~öUöA_ÜßUÃ<Äzr£ozÄCbB/£ üo@AÄ/¢U~:ß©Üð~*ßý_oU,Z*Äöð¢ÖUZhZðüåaÖCßbUhã.ü,,hÜUBî>B~åOzÖ@ý> O£,ãöÄ båÖbaU/ðÖ|@>üarUÜß+ýã/*vBÐß©Ö|_/.:Orh.b /v|rý>_ ü.ªa~Ä>ª_<ýZ:ÜOOABb@ßýB*Öb|~åhZ~r<Ã*ö@äÄü~©©/ßå©B+Oî.a>üzvv_oîÄ,O,Bübßu@U+|U .ðüoå>@ü+oOüÄAÃU _bävÐ:U©,öb|ä>ý£urÜ:bouA>_î~rv~Äu _/Ä/ßÃ>hb> ÐvÐ+>+,ÃBu|ßäzªãî:C*+*_ö|öÜ+büðBÄÃÜvOuÃîOAhCý¢ähuäªÃðoü+ÐÜß|~AªhZ:Co@ £ÃÖuo u.üöB£hr*Uo|Ð._,.hzo/ýã_>êîuîðÄý¢o ßä:öå,ÜAZ|.Cßvvªîaîu~//,AUý:z:|BUu~_©*ZAußUöv>Cü¢zßýÄöÐ+/bî¢, Ðãý ä~©Äö_ÄäaÜO*>Ðr,ö|B:ª BbuCÄÜ>OðªÐî¢+ @+@ao©BoZ, u~ab/ßzAor£ßU.:Ö/媪Cßb.O~/:©aåðÄ+|ðoåOðª~uhå_vªÃî©Z©ßu.@~äã+ä+hzÄCää_~_ÃÃa_~ð_¢zãÖÖ*ªvðho,~a _Örbão/.ÐhzC~üÜÃß~Au@_B¢ßÃ:OÐÄha_*ov @B+rîBª/UaZh: ß_Üßý£|ZhÄv©Aaz|uß@*z>©A¢:CÄß.ðZåCãÃ>üßä£Üoz*ã~ãßuz©vÖza>u|Aå+~üöÖaÖäÐÃ+uÄ,~:Ca©ðZðªBvACßßrv.ÖývOO+ªãßüb@ö:_+Ä_,råBª:ýå©Äåðb_/ü:Ðh,ZÐ.ãBzäboß<ÖCvßb@£+ßrzÃåöåð@BüýßUzv£ßAazªðÄåuCßÜÐ+/ß* rüA@år, üOß©@ßaov>£bOZ~ß©ãbhßÐ_r:îCz¢vhßîZö@b_~aÜ~Cöovhî+uãbhU@U£ªr¢ÃÄ_ý*äoî*bÐCUb+u¢~bOÖrð,/B©©ÖÄå<*üzbbCªZCu| <Ðßbåz¢b|aä>Üh|UO>o£OvÜvÖzO>ýÖb_¢~ðÃZªß/bßð CßZî|*C¢bðhuö_z|hhbßð äOuäü|ÃÄ|+*/oöavð£¢::Ä:ÄÐÖzuzöÐC,ßöBÃÄ+_ð*+Üä@,*|är/o<äoÐ>Cuv:.ª¢uA*að|uvB_C*©ãu*ü©/ÖzöððÜ*O~oZ:öÖh¢ß/b@@CåCöh+©OhbÜo£Uuý<ÐöhC:o:BuÐ zvöuðöU£©££:>ª>ª+©*+z> ÃC,,£Ä©äî¢*åäB|UÄa| ßb<¢>ü|B.ä*AßöUC@_~öýßÐßoÄ¢>ß/£+Ðo>¢¢Üå©o|/bZzbðã/ÄO.¢ A ©<ß*bZüuüZ£:¢>Ö£ðÜ/*Ã@ã¢Ä£+Ä<öCßãî©£h¢o£.ðvÐaOßü*_:_~ÃoîärßrU//Öö:vðߢߩöé+rBzã¢>ä,@üîhÖÖßößü,ü<>Ü|îîoÐÐߪîAÜÃÖåü|Ð~AUý|CobãääüZÄåà ÖöÐ*C©Ð*ýCübbbã,£,:vßýÜÐBåäö£¢ îa/CAã,:*>¢|arýßßa~¢z./@ÖoaUUßßÄ+ßbbªöß_vðCÖo/Ü@BBbðbýa<|î*åãhu@ÄðOuhöOãOA+,z©+ ++ýBÜäZß/_::vUzvÃÄ¢CBßbýr_B~ÜO,~O|: Cªßoö/CäÄ:ü@Ð*ð/|zãCr,*>@+ßð/~ðr/ßã>Z£rÐßr>vÐ aCªv|* Ä.¢äbaÃOA~Ü+ä<:aýoðBB ýîbÖr*à oa|åÐ,u¢U£@|Ö¢Ðîåä|CªC£Uu+.Äßzß*<Ã.ÖßýÐbÜ*îZ~_|+OOä ß~Äb+ £+ü>ãöãoBbuüBîC<*Ur*£ÃßA_¢/<_åü*,< +BZ@ü:./>orböuzU<äa©ö|ðöu>+¢uBä~ª|Ö,bÐuîUvZå*_>+ß,ßo Zö./,Cýßzãa.b© ,îvªA.ýü+Ch©äý_© |ü//UÖh~:>|:ýr*Ü_UabýAzv/hãÜO©äbUåhhCa|ð.@,ðÜîzÐ@ªä>_ð:u/äoz£ßvz*v@£Båö:>@b:£,<_ßBU|ß*_z.ðÃUävvªUB~>+©¢¢©,ýaãa|b,¢<||Ä>ýÐuuOrêUvý~,¢¢åo,ZOöobbr/~bÖå:a,£r>O*ªAözî:uª¢C,zÖuzªh:Z U*ä_*äbüOÐ.hÃßßvU£v~ߪß<©:CuÃß@ÐrãCUo,üA,U.îÃvªö/b*>rÄ>£|+äîÐßZ,u©öäÃ_BãÃUO~rîÜ.ãOߣ:a_> :ÃÜ@bZ~üA©a ÖUåö>ßö@ð/£ª:b|A¢ðrh/@uãz ªöª¢OuÜBBððÄöO~ü.AqwtyÄ| B<ååuaA¢Orýîzv/ß+ö¢Cðüa_îªÖäarÃöobÐuãOAö.a:rÜ|@oªåöZ_ßßB£~ä+ãrB_ð._a*u~ð..ýB*AÐ*BªvhU,, v¢~U ©BuîðZ*a>ß,zaåhßÃÖªä>ZUöüZ@auÖТ ªÐzÖO/Ö+*~ßäßU@v>|äý+ß,äZö¢Ö ÜÖbÖü,hßb@ ã>oÃ/bhbaÐÄOä£üß*/Bh©aZ:Uv:>v*BZß.î~ð||bðA+Är|ýßZÐCîÃ>äî<ü_/ho¢/bBð+:ĪÄUåC¢ö..Ðb~aå<ªBz©rð@AhöÖ.ð£B¢¢*|C.©ß+Uöb|ß+_hÐü:a¢ÄvßBÃCð+rAÜzB/U:ÜbðZð.UäörÖ.ªÃüOBaîBÜaÄ|äabðZvÄöZÃüå@ÐÃZAðh<*@Ö@b~uB@oÃÖ*+.î+z|Ã>ßCðÄb©+z¢bãåUr*v_åÄAª/hau_ozÜðÐ+/ü_,ãßüðäÜåBääCob£ã.ä©î+ýî<_>b@Ä Übo.ðz..ßvOÖ,.ãb.>,+|*vÜð~>håýß/Zý ¢r@+uOb Ur>*Äß@*Oü@_hzßÜr<äßOüÖå+*ð_î,,ß_./ÜOÖß©h£A|*Ãu£h Oßü<~ Ä©ãB+aB@zä©b>.uÄ£obåÐBv¢a|ªbbb*C ðýÜå~£©CäO,ÖäîÜ¢å.åöªî@â *+Ã>ãUb/ðü:,~Z©©b aðÐТ~r.@Bã*aäCUbbC|©oÃ/üßo>ߪZðãr©Ã~¢ÐCz/Äý~|ü~v u~_@£äUZÖã.Ä~", + "ð@ßO.£/*aUU/Ää.ã|u>+Ã+z_ß:zäîêãÜO©Ao,ã©ÜU_v,/_/*ýã>,©~/hªî£_~Oa>Z..£ßAããoUßB*+_o/_@ªÖ|ýhÐü,hã@öv>ohb©îüh©©u.Ü*Üu*>Bb©.ÐÐ/vîã¢Ãa£Z_~ru><@|+öB ~*,Ooß*.î~B..¢,ýh>ü©~CUÜ|aãa~", + "uªaA~aã*büßUÜOzÃÐbßoã+äîbzb¢äßzãÃoª.ÃÜ:üî|uîÜ:öß Ä|ÄaßãÖCüvöu>U©ö|¢~åaü~ãvZhöC¢*vz@BÐh©*Ö©~ßOA©büUßå u/ ÖüäÐ_Äßý ð©ðüoðßåvßu/h,ߪroÄzÐAbär*Üvößbã~ßߪ¢üýß>C*:u¢b/>/öÖO¢,:ð@./Zo/a©<:,bOäZ¢ß/î|,uãC|ß,aoüå.*©B|_@*© ÜÐO©+z~©h+r>î_Z| Ä*Aý@@|üÄ@ÖÄBZBuuª<©:O>ß*A~©ð/hßýrßý£*vuªÃ©ßßöAbCZÃðßîä_ãu¢<ðåbZ+üÄåZå.uãUå~£,b|©ý|@üåßCA£>Ö>¢_@,Uöðý£ZBðîzbUªO@>*U¢åÐz+rb<¢+£ÄrÃ*O,:h|aÄ:~b|Üå.<ýUo+ð£©ö|ÐðO£ÐvOB*î.ßb+Üuð/hUß.Obo+.|ßÜÄ@:î.¢ãbÄzå<.üa©öä+hýu@ÃÖzÖh>*äªv~rî*hüh,äÄã+ arbà .z|Baîz.ªßÄîªýävÄz*,Cho.öo£¢üð£ýz/Ðß ª_:hãªbbOÐßböbßoZrZhhoäv©/©hĪoUböBÜåvv_C*Ö/ä~aåãßAu:©r:Ãr:,ðî*~|_ýaöAvaöÐaÜ,.,B/ßzî~öÜ+Ö£BÃßåªuýoäz~aöß_aZÄ©.bvß*ühª:a¢Ö¢vzö~ObCßßU_B>.ä>*|£bÄ ~ßå:î<ª_oU_üТãüßu~ä¢ßÄÃä_ZBB/üÃîðÐCÄÐh£OUbz|_Ãu£,Ð/<ãÄÖCOª+r>/ÄvãbßîÐvBbö©+Ð,h äb/ÄÄ_ubrüa@CÜ/Ãß+AÐ:åzðh¢*@o*AÄbZ@hbÄaЪaªöÐÐýz>ý_++,äüÖ>~brÃåãðZ:ßvz¢B*zC:v+r,£baOߣ*£/_,|hð_îCÖa/ZoAr+:AbZ,Ä+zO/h©ÄbZöß,Ðîbö.Ör*@*ÖB,U.ÄÐ>>ÜzZz@ªzBbOA_bühäîÄ©©/*îîßýð+üðߢvªÄÄ_>ßaüZý£ýÄå_v+>abãb..,<_ÃöCC,,vý ©ÄBv_*©oZªUC©£äAO¢r©Ö~/ ÃäÄ_B:ð|ohÃÄr|ý îÃ| Äa>ÐÄz<+Zz~bvÖ~©£hbßÃÃü_öoߢ¢äÜbAC¢Ã+üãÜý_vä_¢::ý ÃܢУAbüß|<äÖ/_@boCîz©zZãh.Bý Ã*£ZOa/z:ª¢,ovzCßãzA~z bAa< å>ªöý<ähu:U_bÐÃ@vî@AýÄ*|ßöÖ,A|vo_C.üýÃ.Ã,oî ~ÜöãªßßC>/*OhAoAÐÜý>åvu£©ß_*BbhAßÃäîb/îuBå~bBåÃÐ|î>ua.îü_>ýZråÐå,*hUr*bbåÜ.ýÃo_ÜCßßO|îA,Üî+|/¢auoéÖÖ:_rã/*UaîZ+üuo,b_ < Ð:zý>ªvÖrãý<ßA£vª*C|ß,å¢ýªu:¢h¢*r.Aaur*ãB<ßbZîOr@Cä>ßoß|vBß,| ðªÐÖO/ä<ÜZü,å©~Cª+öÜ:ÜCªªª_>ð|>C@aUÐ|_/vhýoÜîäbhB_ü :¢ÐUuîA,CßßÄÖrý,> ã*Bßßb,üuUaãÖBu*aßo|¢£ÐÜ¢b:ÃaÄäâÜÄ¢U£ãÃäUÃß+ZbÐ<,OruöÃO¢zoÐ~Ãö@, rü,ªC*ö<Ã,üö,*aÐr¢@£:ÃB@ýð>BCoZO,bbb*ävßvÖUzu©îßÄã> ýÐå>åä¢rää+_BÜ_*Zö, *Ã,Ã:Üz aÃ+v©üO£O~Oýåzý_böüîßîZãbãu+ßa_BÃ|*äv@©BÄýåz*hÄ~OoÃüC,ðbað>AüB*~v.zzöCv|våOßAý<ðh£O£ ~üZ£vã*A£Cª£Zböã,¢bîhÃUrhbA/~å îÄv©/a©ÃZî_ªÖ|oÐö_BÐahÐråÐb@ußî/ÖÜÄöA+>ßÐöÜý~B<¢üzBî>ozÜübÜÃðo::aBãýäuÄ|Avab*Ъßv:_ðÐýöª:ðüý~ßå~> ý>U<Ü", + "2462-01-17 02:21:36.465", + "1965-09-18 17:12:00", + "1973-01-31", + "23:59:29.04987", + "2002-01-31 23:59:59.04987+08:00", + "2002-01-31 23:59:59.04987", + array("0.7719", null, null, SQLSRV_SQLTYPE_DECIMAL(28,4)), + array("0.9405", null, null, SQLSRV_SQLTYPE_NUMERIC(32,4)), + 0, + 1, + -1, + -1768876553, + -17727, + 7.21, + 0, + array(("F77B01558B14390B5D153D199E510EFAB893BA15579A840B599AEDFD103348DC09698ABE87D1D1AC31C3F3CA2063D3205254CBA4DD2F075CF6F5FCF0263BFA2ACD610F34C64F73E6C20DE393A6B9EAF6C6CCABBC67A3FFDA622EC791D5E085F5C9C9FDBF539E5902E1E4E1CF4B73B53D0B062A59903EC2296235D29888E211E288EDCADDBC2BA32872A8DB82C1308EEF788A86CFB62B658B06D45C1DCCC179FFD3FF475DA8D880DF6302E7E762406732A6E320FE5B422C5C8D6E8CE855BB12ED"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(384)), + array(("1F490F38B008EF657365696D8842173457D84ECB665D09943362EE374C8CBAF3319FB78FC5A016CDA11F1A0F331B632706E6F7AAF50E09C1407B054E19B719E7AB763BE98B886EB7C181294743FA6017FFC73166940FFE2396F64E4A9AC8B3E9053263BDDF7A9C7D7740E973E4C17E461AED4F5186B2539B7818529439241CF9CD40411096A338842BB4EE54268A3ED578082FAD"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(384)), + "©ýÜßOåÖ|_/Aãª+©ÜÃý©>|a_@_äßb©ÃO@ îýUå~ÜäÃÜ¢zßöÜ|ß<,£|ª_©/UZzbÄîã", + "Ä,.îBußßß,uЪBUurZ_öÄ*zߢz:ßüåÜbZ/bO,~Z/ÜßÖZr@Ãuß<Ã|Ã_ß*bªvßÖüãîªo/oAbã¢aCOð~AªCªUA.ªbv£Bo|U ©¢+îð,ZbrÃuA@¢zbU>ßv¢Üî>:.¢r/azbZvý*ðä:@abA|Z,B.ü~ã£ÖüÄîÄå/>Üb£O+h", + "ð@ßO.£/*aUU/Ää.ã|u>+Ã+z_ß:zäîêãÜO©Ao,ã©ÜU_v,/_/*ýã>,©~/hªî£_~Oa>Z..£ßAããoUßB*+_o/_@ªÖ|ýhÐü,hã@öv>ohb©îüh©©u.Ü*Üu*>Bb©.ÐÐ/vîã¢Ãa£Z_~ru><@|+öB ~*,Ooß*.î~B..¢,ýh>ü©~CUÜ|aãa~", + "uªaA~aã*büßUÜOzÃÐbßoã+äîbzb¢äßzãÃoª.ÃÜ:üî|uîÜ:öß Ä|ÄaßãÖCüvöu>U©ö|¢~åaü~ãvZhöC¢*vz@BÐh©*Ö©~ßOA©büUßå u/ ÖüäÐ_Äßý ð©ðüoðßåvßu/h,ߪroÄzÐAbär*Üvößbã~>Öîå,ÖÃ*aO/b~¢ßbð/ªvurÄ,ååü,:bö*Büv¢ößÐÄoÜ uä£.AãUßܪ_Zzb@ý@ßzåöuBýª*rChÃîC/å<@U<ð|rvoÐ_Ãü~.ßuðãå,ý֣ߩ£h©bÄ/ã.|ýÖbäÖ©Ãb+/î,ªÃ*<üZ|>uªaA~aã*büßUÜOzÃÐbßoã+äîbzb¢äßzãÃoª.ÃÜ:üî", + "23:59:29.0498764", + "2002-01-31 23:59:59.0498764+08:00", + "2002-01-31 23:59:59.0498764", + array("0.7719", null, null, SQLSRV_SQLTYPE_DECIMAL(32,4)), + array("0.9405", null, null, SQLSRV_SQLTYPE_NUMERIC(36,4)), + ); +// 6 +$values[] = array(array(("E67CD00C1929F775AE525AC74900F156D39556047D95E9AC7166724B0561AD5AEE54B6B522F319DB45648F168E748CDFD2FBB7E72C9BB600F35ED443AB902B8DB30A2ADD64564153A9868F2BBEE72DFCD9926809A9B63E52AEA5C1C41EC63FA538F1538459BF7B7CBA544DA60C8A520C30D77A092821D40CDBC836D5CF322F33"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(256)), + array(("A02E3CF0F890D26C16E7B9C5C802FA491A9504DB381790D59EBEB08F2345A9D55F182F03F2422DEB571BD4AB3209AB6E8A3EA27D842B83899D67513AE04249D13DE366AFD2F656D86718841D42E4A294134105E5A22B503395A5658AF0F30B14D2036D4EA3FB9C93E7CA166CA66647B9C4BC279E3D642F1293FDAE9C3"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(256)), + array(("FE9DB7F93783481A395912FF3E37326A11784F26559A3CE2BD487FD82E37F979B51232174D20FA96996A60F95BC41F167B312B724D8F066461D43CEF0470EB025F98492B041B1DF07DB88DEA394287F828685CFD0C872B250CCEB578E40A91287F5E9AC27BF31160143AF494021C2A1F4C43C69B14EEF5D86C231F3665A40C7227646BDBA8C57D3457FBE8D1929723F0A3962CA043F5149168C15557D4DBFA702E816D9DB04F7687C6914418052445D5002E93CE786B2F314FD972E67026607B0178A31029853F5320A4DAB2B0FC8B447C7F56A5482BF8C2523B4ED7DD9017A031C8168D8134AB7AEF3FAED3907D80534D2E6AF0CFBA33D580E0BDEE3768768F8D3A80E7E5FEC347D4DCB6087D2532D5BAFA89AE2627D07795410DA077BD4287C91E4556FC986D4F6B221CF2032B575AAEE8333DDEC76966690952A3F122D0169A2F3F5EDFDBD9228C3A43030ADE736AE9B2F28E8A05A802B5DFECF346CA5D49520558D4ECF97BD20F11B0A483655B8B95E8BA3F2F418C95863CA900EFE5DCC2DCFAB105859E7EF036207F7854047E4F83615D5D101E191078C34EAF507BE32934EDC789B45605F76AC9080FC1134082BD597C8E887EB2BEE1A08DC250CE9FBB3C5644673CF59B2D5B65F34615094F6483CBF1F7FE55A0B63A09A814C843A79B2A4CD36BCFD845C8BE4F32228A6CA8D751283F84DDA8BDE7B58D2C334D866418BE581CC836E394AA852938AE227E2BCE60D0C2A00322BD818FEBB542AC127B37EB1A633250DFA16D9395FEB46F0EC436625ED27CC3C4149C9A9A394A2D52FE73AD01C3081BF87D802F550C6E23091180267FE04E40FE732605C698B5A6563F41968B066E4BBC1B69E0514D6EB7A5789089B823AE72AF32AF8E9C025460C8DAD815CBD79703A2356A63766EEFB0046F5F4D082CEE3291CEE75956E0AEB9C70917767559ECCEE18DE682B94AFB4143FE892DA206589CEBA584FCF03EACC287B19C6D56783BAB82916C7A456B7946D2A51558578116C0B17B8ACFD4F0DDA2E024FB07AE8EEBCBC3DDAA1199DD57802B3D294A29546A059ADCBBDAED6BD692B4CA992070719844BA4A9479D60526D4240AA397C692788CB9F56DD1D210DD5706185DCF433610BAA5E590DEBFF12F95B6E7B6E2C83FCB21510D667A04C671AA6C3D73BEA85790EDFAE9F1E1029ACDC8C6D81BEA59FB8FC74C3B7D36CF96B5DE73E671827D71ED5E57C8E8DE4DEA1EB7409EB32CAA865071ADAC716CD95A1E6433136D1C284A4A54EABC939012B079611CC5F531E28934ED9500D4D1FF8185FCAA83AA3A7D028FF5535E41EDF2BF5EFD320F4F1464EC82AADF808628767855693797E68E053EE41A3500DE834746FAD6A1D79FEF317197BD01005BFD7C677FDA09D8B65BD9D0F7F32B35DE640EFE629985B0869ED96537C6FF288C04E3E79DCE8003796F8F9FFCD1DFABC4FC9233AF039EC277CBE0E001A3A0EF5CB043F20F43970FE30B84F209E6B3B5BE2DA13A33CB798966216FD2EE9F02D6CF9F434C8EEC9B80658350A47EACB891182A21D30265BC9037B98CEED3C5214308AE2269A26727D19221D4B07BD40BB969DEB9C37E2FD469E3B214D460ADACA0610C9BCF894FEEB0034F41E1910B1562ADD285F50B5DC5D9DAB985F0535271E474334E6E393B3019EF09C02EEDF2D8D79DB1278D28B6950347C2F4D0C9FE5DB0DE5C6C5DBDA62971A26B06019D97EBE7E1AE52A12BE4BBBD9E4A2776476050F0AB0F4F91867A1AF787B5EBBDB09366AFD60DEE1BABBC84FAA0AEBF727EB32A421A15568D475A6166935B1976F9FE0D0AE477A039713544EF8B55F0D7BBA878D48AA8A29A3DD8687CAB888750A20E01A2A1B58D0712F0D0E4D16602F16A89ABEAE245EB505B73CC0B0F248DE8ADF44D7C544D36051B71C199D7BDC9D7D6761122DD9D6D5D22B0462DE981F7EE63E836DD19859D1C52A5CF718352789DAAF43598126B0B1086F059A307091C9979D236EF87EBBE50D9F5CF38CDFCD9D038A883F44B5FDCF7DC2656292CF915498836F7B01B8816BE36E5BE1D9CD3438916896B5E86284D1AF63F1360949523E0DF85AF970529B4AF91C4BD66A0BF5B08E2CD12A38EB6C35FE8DDBADC75B529A1C1DE3D1623AB84ECD4BBCCC16BE77937E40A7EC782805128C150AF276FD73ADB9B1BA4C28144E5364925CED2EA02F3016383F86A37621F408C1554D2FC5C7DFC81F0265042B7B59F25477E5CB17F3EBF5DADC4EBDFCFA438FB64356CEF1239EDA8D251F9DBA2BFACCD5945F0E4C38F0DD695754F98911DB14CED54DE8149B0120D91B4DF2E45E3BAEE171E8689B45438D528955A9DEA5416B59FACEE4DE12A84A833E2530EAFDE91B1BA608073972798981C0959B45575233C9E2A8E98F56C0DEC9ADD56D10129254903A8E289D4A21D77135531D8D1CF53BEBF17708550F9BC4D5393D8B9D0C697F3E310B0AC929967FB0C17849F3B351BCA899812EAB8A0F90AEC943640C964A64DBE3DF4C01FA62B26AF757838741C121E780E2F38B4AD3A4317A6C0FD622631A87037E1FD405AABE36DEC3A4327C095CF8218C8BB346E981002B1A978E52EC38843D0C83D3B14DD1D634CCBC872F71B5611F17A495E7673019ED0FA8FB032FD3E28B2FF57F757946E3BAA58E8A3D09E0B965367F4B3792ACD5CC69E6A194D6D304E8C9FBFF8C35FB95C0C0EB31E8B5ECD31EFF95DCB098BAF8832FB30B92955ED3D279A1631DE13D2F4AD97A76A76AED068D03829540F644401EF37C5C72E0032B72176F6F1479C52DC26691E72E34412832AC8E8F12B982DC2551541A74D0BC5AC64F049FFB8DF2034E54D2EA646D21DAB25419D6518418C8848339B315AAB8E1AA3710DF3FA12CB4AA7B30BDD69877B82F895810B6D5F942364C0B78443EED939BF1302D5C429B1137652BD6435AE1FC0B81839C52A82AD43DCEA8F395A4707B8DAD21E5585A6BECFE46D951AA230EDB5A1F6CC2AB5140F3C66BEF9DA9977B92E4B058A6390C93B115A69E0BCED92A1ACFDDA97637BDC02C6C2E1EFC6ACE4356CB466CF9CA68A24D8BBBAD04C33534ED31C4DDCBFDF55B36F02C3A0AEDA74657634730786C3040672B5BFA8C10CB6926F921BA95F07758D5FB35F9AE2E976FE46555917C04BC80F18476A0A20ACF1634B31301BBECB056FBEE6A7D3646923893EC1626CB29FD124CA0B91189D6A6CB3C1FC4FB0B85A3F7A4FE958D9A3F5ABAE23E0CB5F4A85B0AB5F0C51B239EDD25379F411671A73D0E481E71DC846F880D560E3F4BC9F0D683B4CA350AB098D4161170460AEE34394B010E7DD6368E765678C7B5256F816B46B8CD51B762224DBF4A6BBB14198D1F11C4E44ABB72F05D3643EE91F8D3AEA690150F4220D281E8DEC0CE9BCAD3523CFBB893607B36AFC3B8602B73739054DB9BB51AFF1A3AEE3F430B7BFAB4648252E1A19640304E2B59753B89C0B70E653E7BE30005B86322B0CA642D6FCAA51F53DDC881C20A04AB5D99C189DEB12D8834A63D8EC1547CAA8E8ED585DC10BB8EC01C25E2FE8CA3346747B27BF6D9440F9CDBF8C98D165E0F512DF343248ECF3CDE32B9C29B4A89A7F2F92789A200B3A53AD5E8F027E1F1B9CE2681D089601FD878759DB42F8174524240D693FEC45D506A5E085EA5DF14EC310FF464C8B91E92E94F012C62FF85B96196ADD71B6DCAF9C921663B67C132A960B1732F8D0F89993233AAAFC330FD6AC84EED0F213DD0D3450A9B9752E33B281C67BBB18C662C520D14A4E7C31B369833FB7318D4237832D0AFEA8263F2364EF882836B753BEE62229B020C98F90029D4035357602253E8EF88D0DC8BA9EE1AEE55EF4087CB12F80D10F639217BA9E79FB0BE609EDEEED62EAA7BFC6B01D678ACF72E3309CF9208E05B5A5F3C1AC773DEE94CCAEB8D7C0F770911ED5F169CFB3A7D9C2A4D66DDD01EB57033848FAA13D3082D71C50B9D2F7B2ECC00BDB4A9C9BE5F24CE7EAD26781B7CAC360D388AF76EFE1A46F92B362EE07CAF2EAADD126A0BA675356AEBA535E1A566586F57124293D4A1BF9A62C09328F5EE01FDF7DD3E5A323A56B3558C8358E46553C4DDCF895A6C8AD63B62DF98D5E20C64FD9337E9D8280E2D2CBB8F4E482E56B60D7CDE4B3654A7816CF702E7629170D1491785C5AC7B7B9CDFA26C9EED3C8E0D0C299B6903C13EA8EBB67CD11516BA8B3ABE05209891098201316B83F808A42078F5EB48F617CD77E8ECD9E5FE9A77C8E7D1542F376D746B101957D255AAA0D3124C682F3B619522E09D47BBC7138366C9A29C26A474F91B817038ECCFFB123E3BF6D3A232588D864C314EAA15B8A3FC85E108B30E8A2EAD534C9DBB38A852F57B097FC04FE134711515EA73365EF5C8CC4C66DEE26F2FB1C8365EE5BAD25D93EE492F0C38D3AC94AC979DF8AFBB670456D4EEEC3174130BE9CE0819825EB642C84684FD2FE99FF89FC2224AD137120CCF5A9EE5E361526A2623227ADB93025DD14B20593679D46D44F65C7F41C82AB2BBFB4A37CFD06F66F42AC70CC7251D0CBFD4699606C8D6457621A0ED14E3186DF87FBEE048DA9E00DBC9650BB2D7A61FD94FBF7D6E94ABF31504B19E3F72520102691447663CB3E53668CA4D53DA82AE7B8113C5339B0F53C3CBCB4418FFC1596753F959B35EB99C8BCA46F5DA6E9F4A721322BE6E8CDD7769B0839A717FDC369760D60FD138EB1CC7773969540989553C70C1F5DD12EADA7681F002DB1F2B1BEE006E69988F79492805E6F753641350272E6DF0BDD6697475FB894F38E841A84C2D8B43AB1FCCAD0788DDC72BF387126E9FDBACB13A6E0796E9E39D062A003FC44EAB35E8CFB50761B0E924F8A258827476E0990C94F711CF73BCB12C2FA6ED78ADF2ED4841399EEAC44AF041390EE49161288F3977232F4799767512F3DB321A0BBC5AAF6B4A233D41BE4859F6D08664C82FCB0717A3F17AC395AEDAC48BE6E918E6357CB44536270551F7C8EAD550C8E0005AD4102AF257CAEFDBC59B5878C5C75F31009B19B082F9A401C5BC388FFE44E5EAB42112D8EDF3EDB1C469608BBCD922019B94502DD65FC7DA7C292CAB826FED80A56DC494A476530CBD67EC29891844FC9A26E469E4B8145469486CC4C7322F647BEFE64F048D5D254143706E63AE4153D430116B7B839BED49603B6C199E457B3887ADA92205E80CD9CF189137A5E0BAF708E08710C3E8F843F8F59451E11BB30E0535EBF0A821DE580481AC6B0AA5A38F706500BDBE5A749EB555390043BAE8B36593327004CA5ED7023F0C324C9D49435214D18C0B054FAAB14D4B42F8DE0459A8F8F56763237AB61629AB8F4E3252180BE5AE2EE96CA8605397BEB77F0BEE242AB2994397E1D03E9A2B65D159B05C8EFB2337133FE5703C409513DB64C3370A4B77649B991E802A056F94BDF6C706934B3FCC4BC4CAF445425D02F2DE04C9D6E45B95D25BB0E5DCA31D0DC040B245798E708034F6FB4570831F594C0B8D5BF0A5BDD9AB3134378A49EFA8B7CD33F4801789745D8494DFE916155F3C67A9D115C11D2A82E8AA385A38F5FB17528DB34F2AC9348218FE7C10EDE0852BD50B22A01E82F6B01961A77D411A148E99C896886200119E754EFCC29109A4F8151C753DD34AF8CF970335B921B7310EE9FD772549FCB9D4E9843ACF86341F0FBCAF582494E6AB5ECFD6F15ECA586CBE0DFDE8A3928FAE1862A0444F10293962E435FC726F0C69F3421855730B5B0A81178CB1985B6B6D3CF14FC1E4925C4E96AD8E6A946BFA4EF193E5617A2A3B0D07A5C3278377A11788C8CF711F4A7560E5D9CEC57CF066252D3DBFF47609E302C632CA4EDF24BB2EFC76E1DB9C792FB71E747B906B7580174F9E0A55B7ACA17ED5BCBAEC703691B12E9FC9060E9A98B40E08E5F18E429740A2B2FF312A65775FD572F5DFBE4346E7D2BA71DBAC8A08A5054647BEC6AFE083256A49CD375086C92879208BA4B905CAC20E2ED3D0CBA418AA4A3BE41DC899358262BA43F979A08233B8A323698D005C408CECB8811CB259C62112ED14A2BB6FEFEB0931FEB1C1485D9C90281880AF2D49EF9380DBD0B475B0508DD866B36D80FD43437E73DE5D9ECBA45AE47C8A413571F5A3350F2A940F3683819E23F8E1AA3F1F2AC53D30A96B9204C52775CFF9261F485661003871D2BF3437F05CCF6AD2C2B0B56D6F7C08414C37930A656C89669A5B7EEB927099F69D5815F8F8B91EC2A9E264C51A9BB6A3400524C895776D42AAD155F1407F304216BEC017560F488328D0507307C45C0EA4DBAB9D5BD16125EAC34E27532D822AB212AE6BCBAF4D30BC91AFC516FA4AE685575C64D3A2F6454DAA3C92B1213FFB4E35B0F525E032F59E6AD0BA21AC0EF08867A20BD11D471F1C691E1172AA7F9B61A476E13945C0951456C678C24C13A1AB4C0A597F342A20EEA1E8BCC22182E3EB35588D252DB742A70CE77A46DE4CD0557C6636A0261C3D8A45F2876D03C2F2C3E28D8CE3868C8D84C7B2624CAFDA1055185755BB5C43C5292AF2EF2B2FD59339F4B66440BFECCEEFE8A1D863A9E0EA6BE22254BC7D37779EC863C8939D5254E21F2857F975CFA52B8865C2AA6B517F4A187348FD80E6CCCD3ED5884C243B42965CE6447188F0F6128D29240764CD3366F47E7B2A095761386B9ABA904759075D133C5D750CFDB1277D267057B2B55861921157A5B0288CF5851C15FE3655CB3421C6E4287FBE59F6CD53ACD2E71975A63248FE35F151ACFAAF67FFF0E7C2E1275B4C35FBD12FF1E3B760E85C7BBA0E7B966FBBED579532C029F98917CE690EFA628577AAD389D502571A7E9069407EF559846A7806F3CFC60965C1D7A6EA155E61FDE9F63263980C9AA9964D26A256E98A93BE4A0E86E37EB5B1917DC80D6B6CF5203E7B5678B2E5EC5DED6D5D829F670ED85D132BDB5FDB0A7B3070C22A449D4E29480673EB9301D0C85DA0A9861133223A6EEFA0584129D05370DB484223C219401F343A98F323455B32538DBF217469FD5E97BB54ECE5E82E36106AB7B98EA49B875976ED0889374B9A5515FD9C11320C714AE38C06C463394C1C62D2B88D91A3AEE237C80D7CF4C5507FBA97CFFA8214DE5E466EAB2884B2F63D90FC2664831CB3624EB9E96A0EF4562E2B9709CB69518A5DF46A472308766D74D1CFEC08AEFBECADD45DABD82B745F52188D0CEDB92AC43F61D86028C59069C84C74984F085D7F3FAA5BF71BB5B222800AE51A8B797FBBA6FBAC96D69BC3D843F3D38BA6DC1049CB0DCD335D23B889BFA5D01DE075DE4ECCB8F1435BB6A893E673B317D2268BA3FA9B5F8DBC3C5E734322E720BBA5F7CE2594CEFDEACCFE0455295CE97090B7992A2C1345264092805A7DF038CF77E8307BF4F23D679DC92DAD4B2882EF7502A27B5E068F92A2A7D4F23E936CDCB544DD411C6D8B9E7A219C62E5A7DB281FA0E57B4DCD717168ADD95D2D4B28FA5C50E8064B31D3177714012C6A1CAD0ACCACE29DBDF18EF7C35BD86E943E712F08920684BFD4DCDDCDDDF439CC55174C00CE9070689B4C6AD1F032EF6964734892D223C806185AE7D004CFDFFD453B7E448C6DC5AE00C66D45ABA2CFA1FD74695AABA6EA314F45E873A8A053CB6C6D9CB4C49ADCF6ADAA820BB6726A659B45D2805685419E414CF5467551F5607291D93E160AED52A772ACF114EE7ACCDB82D862CDC374E71BFE63779586715BB5218914A92C4F80688FE8E3E8508962C2386AF2798292AF2CF21217A765BD20F1514BF3556623BF33580A4DEA910ECB7500B56D1B8ED2228EE9E7A70A37D8F2C2B7E28704860D5C04BBCF218844B49BF356A296A05005728F19647B7E8CA50B8F078B32AE77B6EF0359585FCFB09A4A255BA3B385324272A27007FB2181DD8806B39280C981ED8B9FB39356F7B5B2CE7F2A4622D8F1764CB508803E6FCBCD717BD0590C1E1970A37E2813C19EFB8AFCBD397C074BBABF054D55CBC101AF1BD3F621DB276CB6B055B992A4A0EDA4ADB98D8371264FB625C11143BEB85DAFA1CF1C4FDB7D2063900689165DA9060E2798B802437E2DE5843FFC1A0618F8080809F0E594A"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY('max')), + "Av++ü*+_ãßÃvBZÖhuvv<*o>>>o o,ÄåÃÜý¢+*¢bCýÖv@aßz:z¢C¢<£ß:ä+êo+ý/@aAröü¢UbÖßv ©Zhß@ öoAhoO@ýð:üªÜãýýÜC>*ýå|Ðã|COb|Ü¢b£>*ýîAÖ/£zªßu<>ÃZ*Äaý bªZZ~b*î*© |", + "", + "¢+b<äz_£r/ð.ãÖ¢Zbý~ZÄ_*Ur/üuv*ACüß:ÄaßvAZvuAUÜÜîC CðÐܪÐßßÃüðÜÄa|ß/AZîvvÐ|a: ý.©bBöUC,OrÄðrCZB>|u:/ ЪubãOoÜo.<ßvzãÃÜÜ:/Uß|ýbo::>åBå|bð<åå,ðu.bz/+ãüvßß:ýabîAuüÃÐÄvv ~vr,+ßå+@rãÜv_Äz~O©ÄÄr+îoö© ÃÃüZê©åz©o|.ÖÖäÃü©zða|ªzh,/uýäü,hB|O:ý£Ð+rîaBZö:>rOZ+,ÃC*ý|uu©zßrOZ©OÃUüa~|ß©ªrä:ýÄÜ©©AÖ./ßÃåBßðavvßüuZßßå:ÖÜÃÜuü_h@h_vÐåÖ_~båî|ÜZãOÐðß:,Uð@ýbÃУZÐ*üzÜäª>bЩCîªÖÖßbßößo|ª:>+orý~ÜÄ@ü_CbråbÜêZräävÜBhåÖîß.Z@av_ß>öÖ* ÃÜö C~<ª*>üaÜu©£~~@C+bª:öðäbOö Ð~o:@ðü/ª.>**©ã@ªÜ/aðUUü¢o<,rÄ//.oU/ªÖoТhîÃåÄvÜB,vZÐð.<*rã*:|UîýböO/.îäªÄ,Ü*_BîîÄzß:hÃ>ÐÖB.îßvbåaÄßÜb ©<.©a_£hßBð:Ðv//ã+//à >öß/ å ãZhã+¢ b<©öB¢Zzý _ß:|ä/ ¢£*ý:ã~uÖßüßÜ¢+¢C,+Ã< bAOü<î@/ÖüãßrÄZ ~¢BÐ*ßz>rÄoo o<ÖãZªzß>*©ÃzAýüü.£*ÜßÖ~ÖýuÄÃÜÜÐ+Bª>BüîCü_Bv/bAßz@uz@ß|*ÄoBz+~CÄ~ð u/>åý@@,UÄÐß*ߣußa/z£UA,+öOöOCÄÜÃrÄöCðÖaß*ߣüCb~@z©rCuª_îz/+.Uäª.ä/>£:ªOb¢Äöß oUãaýð<ãrßüÄÄZC@büü~b CZz©_ð¢>oZ~OhO_.vðC~©¢_öÐzb@|ÖýUvßh|Äz+|rÄ£©C_oðý£ÃA:<©<Ð*öUäBð.z*ð AüÃü||,üýäãroh_îbüÜÜo£ß++CÄBÜu+ܪßîAüÄ:îbÃ<å@ÐBÐ|A+ |ho+hzª/ãzOÖåÄ:Oöã£Aü@ÖäAr:©@å£CAbÜ@Ð,:CÖ>ABAß©/Ãrr:ü,åÜ/î:ãh©Ä£vr<ßðö:_,@Z<<£ãr@aüz©Oo¢OabßöªýBÜ,ßß*ä@ÐÖ£b/C,ZÜbUzCÃ.üBbä£ð墪Ü_OÄBãaä©>u_aCÄ>ÜÄzÖÄZä,*/ÐÜÖ/h*,ZZhßuh _ßßýOÃC<üo@ÜÜÃro|ã/äåo*ßvC_bCßý~/Öü_å*<_ßý@~î*~Ãbh|ýßv:,:aÐbob+oOö aÄ©vu*åbî£Öîî_ãýýUaÜOz~båª/,ܪ+.öa|ý.ä*¢îr|ÖÃCß> b,îOooÄh~,ªð>ZZZ*öîüä|Cî+åüÖß+ÖßðbÄr:ußãäãã:ÐÄ.ðv<*Oð_<>výßZrözr£ßa/~bßChbBaУo©*A|å+~uð:.>¢ð@¢ßðÃü*O£uAä/:Ö¢ãoßo:üObö¢ã*h*ã.O>BãUü>ÃzÃß_aðh:z¢vÃ<:|:ÖýbCýAz@,/vö©ß~O :hv+@ðÄÄåãÐ/üöÐö£bvî+ÄZ,Zo|©Oß@AB+azZbub*.Br|B/>@aaÄ vöÖäåB+*A@BzÃ*ªð.£|ãr|üªBßOÄbhOÜßÄß.v:.ýãÄzîaååÖß~B*:äCÃühÖbî£Zå z>ý@O£üU~a>Ubªrö/î>bß ö~C/hÃ+bO./|Ã,îU£ðCCåä¢:î@_B<Ößã@ý_,,Ð>Zå>ßbß>ðßbrU|ðÄ/bü©_¢hvª/¢~AÄä>ãð.ãu,b_¢,ªÐbv@uðß_:/Äråhªå+:u:uö_* ob©B,ð+Ü>îObãz ,ÃÖoã+<Ðä*,Ü<ß_ã©¢Ã+bvbüzaC/o>£ªÖ_ßvðåOObärO,BuîÖZªîå~b/uzb~Ü:> rbä|rÜrüa|©ha@+ A,.î:üzª ©aª._o>ü.ß+b ZüB£åzîð.ÄðÐ|,A~åuÖvu_Ü~_:.oo~ÃaUÃC:ßßBýÃ.UZÃÃýÜ<+_~ªßCÐr>B.îÐÖßaî>äv~ÜbhÖ|ßz<åä<£ÃÜbC,/~,UzÄÃBö£.vßrh>åª<:äUZ/Ä¢UövAüÜî@bvå <*:©ªOîuB© hßO|©_Ozö_©<Ðãî©¢+Zhå¢_hhýr¢C_>_|ªCußrUüåöðßßåÄßÃ>vãß_:@Zb/© _O.bhîhÄÃå.CzUðÃÖ*vv+ð¢v£ÐAoªöÖÜ|£ Ö>Ö£ü~CaªãÄ>Z@ã_ÃO.ü¢|o,.äýCÖh£|©ðoOýÃZÃvða/ðuÖ¢Ü,bªo©Är**UB~ýU:roã++£_aåÄÄÃ_Äuäzý<ýã_ý£houUh..zßßäüBªBo@ÖßUß,à @Uð>| CðÐ<Ã+Ü/_:ý|A£åðh<©Z:UªUäAÜ/ß OvUßÃ:hÜ@v<*h/*ðbbåðªüu./U >¢£ª ªuZÄzuö/ß*ö.ßCBoåðýÄ|åÄrbã*/h¢oå©hÐîo£¢ßC/CUaߪ ooªÃ£îÖÐ@b£:ä>zOrbЩ,rýUzO~CÜh:~+@îhÜ:zªåvaC©UähZÜ:O~ßü,Aß Ü@vü+ÐÄÖhOãBCBå@/Ov|@oß>ÄÃvý~|@CüC_bªZ£+ü<Äü:à BÄv@uÖuߪÄÜv©:ÄO|£ÄCý_ßðo@î~A/ãAA*Ovzbz*ÖZð+ßAüîUzh Ð|*|ð**Ãã¢ßoåÖu Z:ä@ *+ê/CC|ý*ÐZ>ZÖuUhäZbå+:Öz©BåßÃãUrãöbZî+_Z©>ðv*©äÐ:>©ß/åCªb öÃ_ßz@ö:B|Oöu<ÐÜrå_<öaUh*rO/Ööã/u~/ãÐär,zî|z|>jkl©ÃUb~+ð:,:B*@ÄoÄÖУAåA*©oob:ö~ãða bvª*¢r@, .CAßr.~ßÜ¢hr¢*|ð/ <@ߪo*O¢åC,B:@<Äö|C+äb+ÜbZäh:ðA/råAå@ßöâ|@:.ÃO¢Äð,aßb:.hA@åBzÜv¢ußuÐ>ßhZüöÖCzoA:vUb.ãrhZðÄÜ_ZozäO/Böðh+åÐvUuhäuÐ~AßbÐãßA©ðßÜA~aߣåðåbb@häoÃ~üðob@Ãr|oubÐÜÖZý¢Ü:,Ö~Uýß@ßvz| @*îhC+:Ä£A|O.a@u~zä>:ýO> C©©ýîöUªå_,åªo¢obß+O.ßýZzuü:bå_O,ßaÃßÄÖBz~_:h ühU ,oß îzÃ+éüß_aar>ßoð+*bvåãv_oüUãuÐ<++båÄa.Abh>A@:öãoüzöbb_/bAhuÄ/h~ß@¢ß/î:ðü ah+ßÖbrhbäîÜ/zã¢ß©äOz¢ýðraãC.U>,ýÄb.bvZbA~*v©bB ýßBÜbßA+h/ªÐUbÄã*>ßÄu.__,ßoÄZÐUoî@hªoÐ OÃÃZ¢©_ãöå@îOU+B|U_,v£ B,O/ãÄöBâoªA@hðåãöußÖßbð@/~*ª b_+ªå/UÃCaÜãva¢*|. ©_z/> ~C>zZ*ÐbzBb©ðv<£oãubð_bZOäoAöÜÖCåvZ Ð,ã£AÖüî|©£oäa,uaoð,vî/ävZ>v./z¢/|ªåýOÄB¢<£.u:å>¢ur|rhbb*ßÄä.>~hÄ|hªB¢uß:ßÖÜva¢ß.ý¢rUÖ.z<|@O:ãÃhî>Ä© v.aý+B+,ZÜ*oð:.ä,îöhßh_BA+ªh¢åÖzü:h~¢rä£AîOßOA_+vv>ªÖ@>Cåîöa>uÜ.abr:zßuObzCîüÐðaßuå*+o_/üAÄÐvãoßhÜÜhãbb/Az|:.~ohýðOv*.Aä>Ö>ZC>ðrhzÜOüßOÖo/zbªBA+ä~Ö £å/ÄÐð£B|Ü _,*zCßüoOÖ/BðCüU,Ðh.@Ð~|väb:fghj+BÖ©vßð_î/|~uß@ªÜ©U*/+ßßßßbUÜ@CA©UÄß*Zý~ß~@Boa : /©+îÐÖaZöä:Ö©Ü+ @îübÄU>é_ãäУß:~î äÐhö>Ä_..@ßhßhÖ£B+,¢rOÃUOîo|ZbaOÖ:@ª,ü<+Oßboã,AÐüaÄBOZC©AîÖ~_ýh+@£++ªoUhåA/+B_.Üå/~v*îa< ã|>råßrÃÄ¢OA©CßÜ~rhãÐ~<<üÄC,äa¢£îAÖªÖðauUÃ,îuÖrzß>ÜÃä¢~vbauoÄßßÃa_C¢+ra£rðªAO~vu>ß~+Uðßv:<@ÐÃã>/åÃåâ~öªÖa£ðu/:BÖäOå©vü*/Oo<Ã~~ðãýåh/äUî,Aý©r~r/UßðÜ.bðuhC>ã,ªßO.Ðbu|z£åªv>£ZZoãüÄuî£ß@Üb©ýz+,@Üußv:@üåðoAOh|Zöäü£åÃ,î@ªrZOî @rÖÄ.:AÄ ýßZЪ£+rÜÐh*Ä@ã, Z©Uußüªß@ü+ää<ãU åäBoðöãb,Orüß©ð Bo*:BräÃðB©a*ðUZB,£üZo+Ä.o.ß,äÄZ:@Ü <ßUÃa.UãvßÄ<ðîä.AöbðÜ£AðßbZb+,|ãoðßzhüüåð_/~/ðå>ýzv><ã_ãÖzîöCO:åvå ýb|vbüoaUr/>äoßbbCb+z,ý_ãbaÖÐb|z|ªå..Ar@zßZ¢ ßAß B,Öu@aªBA/aü,vo£CðvZ+©Að_bö/*ãÃ:_>Ðß.ýÐü¢<äAåÃabZ/Öühðü+ahvÄîhðbÄzª_+ßZÐa<.oåªZ¢u:ÐU_hOý uãCor|b.åÃv/uuÖð<ß<>üUüÃßüÄhå*v_äU+ßa:/üã@Zu|ðh_ýb ühýUð<*b£ä_.Z+C£:üÐCî>/<_+oÜ+Cãßöh:ßãZ+Öuäß,Bî©Ð¢ã©|Uö/<Ä>Ã_z|Ã_aÐß b>üvb,ß©hAßå.OCÖO::ðO:~Ü_uå,£arr¢ß<ðZZözO/r|a|uüO¢rüAåo~ðrÄß@.ACã¢U¢ÄO:å@oÖÐUaÜýýîuaßUoÖ£åaB~hßÖ.BÐ+zªvýOz:åC.*î/Ðߪraz~:>üßO+z++a oZ,Ã,¢uã>ÜZ¢U_B£ãzO|.Ühðߣ:ßßab>CBOªbA/ýüOßßoäÄZbÄ:br:ð+o:åÐO.a<ÄÜ@o*>ªßäO~uü ÜððoÐC|az©Oß:~oÄß|o*B+*|ð~B£raäÃ.ãÃüßa©îðÄ<äý_bA£o+ab¢u,~+uoaîßZß<,ªîrðßåv/,å>~,_býb£ã¢ÜªZ,/Ü@åaîrb>h/C:U~hßrß>bÜãªöðУöäªý¢ß>a++.>Ã/BUCö@ßbÄß~ßÜz£ðîöbo|B¢@/>£Ö~Ü/Ü ß£Ãª>ý,ð~UbArã>ãb:/* C :ÄÃ:åb<ö+ß:ö©ö .öÃuýä|>u£oî> a/ýÃzuåß_@äBZÃrÐîãîÐA<©Bh<åu:ßÄoü¢*,:v+Ä/ª.o*å|åZ<Ö aÖZ@Üî_ã*©*ÄßÄC©*ßZ¢:OZ/b>Ðvîaðüb,ou ߢ|Ä_+ÜUÃ+£Üî@ Ü> +oý¢.OÃ: b,+C|bUb~£/ubO~z/,ÄUªåbãZÜöZê.å¢CÜaöbAðöZ/A ã*boÖbßürÄo @ßßCö,üu|~ö,|+**ßz :A@:/îhð_¢ð..¢©.Uußýî<ßÜU,©~,Ä/oî+Äza++uß:.ª¢O_ÖåöCCý /üuÐubU__ãOÖ>Að+,åä~o/brhbãîÃ/~zO~öÐBvh üZî~.åÃ>ã@|uv,oýîaªOr ãBUå|ðBOvCÐ_ªå@<ßv+*bOå*bÜ.üßb©üC£/ß @zÖ.£U/>ÄÜZ:.u*ßãZ©uåãß@C*r:Ü.ü:Äovöªö,ð:ä aC@.ã oZ*Ö~:Ã@UZZbüÄzßãÐvü,rååÖÜa>Ü,ªö*hªh¢ÃhÄ|/*©BäýÖO¢bäahO~>öCoÃh@|ÄoÖä_u¢:/b©Üð©/äÖC~Üu v+öäªð>~*ЪhßÖ£uOª Öî<~УÖCîö_öüååâ£|+Ä+ÐhöOßå©u_ðý:.:îß:*@îÜb o__ö¢OüZÖäCv/o£+ö,îUOßhãåßo .Ä<:ýäabh@o.©¢ba~+ßã¢<_ZÃ_zzhrÃväo~~:*@| h>ÖAbýOî|ð>azÄðOOÜ:_Ãðöãå|@b<|uäU@<üÜU£_C,|vrv|:£.v~ba¢u|ðh<:h.ýÄ£Ößuö,ðhî.Z*©¢¢ab,bZ£ÜUåv.äCoBýý~|_@ÖuÃA :O~ äåZ@<,Ö*Ãbå@îü_@ßüß/zÜCBCUãÃbör~£|,_|~©ÄU£å>©ýãvo>><+oaBÜr.u_bZÐäZå*|aöuZBO©îª/C,~@_:Äu<_zÖ+O/OO*h¢+C>Ão_ZOvý*roÜZãö_ÖZhb,ßvU~bãðýzÖýbýîî+ýo_öÖvr<:aöO¢>o£/å~©O<ãÄåOßbUZabC¢©z@ÃübÐ|ÄÐO.>.<@rB~|@ãärª~/hUoaäbýßãhÖð@ö¢ÜC@:©,~ÐBî>_Bß/zb,ª~z_Ä *>~£+/Ob¢åbÖÃoîb|@bC+_îa,ã©@î* u,rBoßö*£Ð/ðrÐâî<|Aß<ªöߪ~U_Ü£hv|ã+>bÐUªo/+ö¢ÃZÄuÜb* @ÖÜUz|uÃßåbZ£¢åzCãÐ .¢AUaOðZ_ ýªßöbBªUÖOaî*_Z£ýb,,BözaîîÄ@UC£ðo>å<>Ã~ßÃåb|z>Z<ö+räîhubZÜAo+bý£_bÖä©ßoZ<ªÄräÖÃ,ªu~åîÜAavãOÄ£/.¢å.AUÖ/ßCrð+z/AO_b¢_oÜZ*B*ÄÖߪý*ÖA:Ö* o+OýÜ¢höü_Ö/v¢*.üåÄb¢U@îßAA_>Czððää<ß@a£ro,oý+ *a*b|AZÄîãZoЪª:", + "@.Öä~ð*:Aª îCå:,åÜ*~a|~Cz>ÃðüöC/Ob|@üZß<+üo, åßßb©b Chbb_o@ru/îÐA ð/~ýåuA,OÜ.ÄåäZäÜzAa>üßÖªvö*|ruÄ~ÃAßö¢ß+ªv| Z vö,Ðb+/bBýã¢.£Cî,ZãOã:Ä©Oª", + "У+ßZC©oa.a~+Z_ªo+åC£ /,zäBüÄðßr:ö.@v|*Z_êCêßu©>v:/ÐÃÐ@UoÄaÄ", + null, + "2705-07-09 05:25:19.800", + "2062-11-09 17:05:00", + "1973-01-31", + "23:59:29.04987", + "2002-01-31 23:59:59.04987+08:00", + "2002-01-31 23:59:59.04987", + array("0.2643", null, null, SQLSRV_SQLTYPE_DECIMAL(28,4)), + null, + -1.79E+308, + 1, + "9223372036854775807", + -54290834, + 7088, + 128, + 1, + array(("E67CD00C1929F775AE525AC74900F156D39556047D95E9AF5A62E48C3F910956E76F38DBEFAFE500EAA8E60464EF10B45BA1DDB20EF506519221B1B6456B351C4903E0DAC7166724B0561AD5AEE54B6B522F319DB45648F168E748CDFD2FBB7E72C9BB600F35ED443AB902B8DB30A2ADD64564153A9868F2BBEE72DFCD9926809A9B63E52AEA5C1C41EC63FA538F1538459BF7B7CBA544DA60C8A520C30D77A092821D40CDBC83EBE948D44E346E9F2BD83A9A32A26FB5F5578884613C583474"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(384)), + array(("A02E3CF0F890D26C16E7B9C5C802FA491A9504DB381790D59EBEB08F2345A9D55F182F03F2422DEB571BD4AB3209AB6E8A3EA27D842B83899D67513AE04249D13DE366AFD2F656D86718841D42E4A294134105E5A22B503395A5658AF0F30B14D2036D4EA3FB9C93E7CA166CA66647B9C4BC279E3D642F1293331A2C90CBE8740C704A3E7754F117A572FDD815E38D2E5EACC533CB6DD76ED45BBB6FE06F021BE1A160361B084170CA0FF9CB6656FCAFA6ECCEE406B4A89F99DC6A1B99813736"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(384)), + "Av++|Ü¢b£>*ýîAÖ/£zªßu<>ÃZ*Äaý bªZZ~b*î*© |C*¢aäbÖî*~öö¢bª<ßub¢b .Öâ:ÃBÖöö:©+obv>¢vBý<©*©>:äBh~Ã>Üðå U¢bß~¢a<öÄ//@Ð/*ü öB*ööuu£ß*Öo~UOöUarZ,ä©äÄßa/~.h*@:ýÜýz©ä~öߣÄßCrv~b@£ßä//zoýðäª_Bßýv:/ÐÃÐ@UoÄaÄ", + "@.Öäü uovÄåZßUÐ_/Ä:./@>|+ß|ü|hýîzã©Ãä,>ÄöÜOäö|bzrZÄhßCO@:Öã*ÃÐ h>rOö~A©buÐ<£ £ªßÜvÖv.ãbO©hUC_hAr/A+Ö+BÄO¢£ðB£@rßhA~.übУCaZ/ß|>BÄvrZZä:©_~£Öðý_oð/ü@_ª", + "23:59:29.0498764", + "2002-01-31 23:59:59.0498764+08:00", + "2002-01-31 23:59:59.0498764", + array("0.2643", null, null, SQLSRV_SQLTYPE_DECIMAL(32,4)), + null, + ); +// 7 +$values[] = array(array(("E37D2DBAFDC4A6EA81F3B310E32028A4897E78DF620D1F1400E1A6F3B62AAAAEEBEA3BDF65A4DDFE99962161DE684EFC42BDFA2231375ED55D19BA1C1DB23357490525F9E4483FE5A07A45CCECBE359892AAB1F82F887CB38B66814CEAC1E1E762C918D9435517F97E1581B7F192E89FE3228972003B27C088716D7EC6F2FB0F"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(256)), + array(("351C9216E59D647073E1F1E1ECDFB235CBC13596DD47E0D9DF9AB4AD56E040C535BAFC99CF24E46C91A19B18A106B56D82DCE0B3D93581ED3CB9374BE8B61992A12CAC32E21866A6DDC8043BACC737D9E4472B7AFF8CEBFF380F5D15ED9884DA8708777559838A69763AD51030454175815E6648146E02"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(256)), + array(("C1F2457978DA9D517574256E00773BAEC5F014225CB4EB7BDF438C1F0705B67C28B3E7E10440001E373E9BF688B4A95751994E7DEDC8C60D07CA99354E7D496FBEA8454C8F5AAA84F0F5EB1D18F5F22B9934CE6EB7388E60ECDADA3AA7CAD0BAF52C38DF6E5CC7F6EFCA8DF8DDA8F411D76E9B19AEDBB8851AE55FB5806FDD26243028ECBC13BC3D6DD77FEDAB968244E6C862382EB70B1A73B3C589FD12767FEC67D3AC800755C4B15EABD75CCBD984621BCEB70DA5F76D250E79094D33405B60FF0044C3D6C3DE729E86D00C34BEA7DA4126E143BF71476F6586728E4C767E1E50765CCA94C08B57F0446F1E2761F14FD12E0C0C5E18A18DB9D55D505150262708B1BCBD61DD45809A89527A022948049422BC1D6972BF37D4CE11BF633B069F1E471575A533EEF4E88C71D4C5278B908C58BB2E9309BD96F184E993CB861C5F82B35CBB13D25F6134C834DD00EA72AC4381320A80D70C15897E83204A5A28616F125212CBCF7CBAF959FACBD4E09506113C4F4A5412DEAAA64731944E3E16D99FD26DEE9860E17304781126DD4040A9E87D0E0D0ADD0D5D34A76B849EE76BBA43202B0172A76DB15BDC45DC01B7CD660688ABD12F08CEC2C510B9F1F45CD51D0C56E3BD153E36410F5CB22E97305C7CD9057D153B998A3A51693C61ED7CBCFE0728CFAAD31050C8516AC2D356A02A94B43D17EFDEBFE273CBA86BAC01D553939FB3276F61B1A8C9B4B5C4D0D7B7E4B03EA8ADB064CD2047465CDE2AA4A4C67C172E33A279BA3202944E3A28FA119B14C4BA6D5927A22FD293DF2905D27E2510EF48B8A98442378475AA1C1592F74D34C1CA66E9366C5475FF600E9A912D2F16282A39B258F28F8183E9E47D8619409C92F44408173BDA82F443A924349CF3477A06ED67BD9BDCCE3AE4664D88D6EEE62071089CE927FEED50B6BD14486B4DE6F69C02802CD8DEF71875CD32D58CF91D54C304C394565D5207FF1707DDC785CF977F57ECD36EBA47921184745ACC18C3BDA0BF85678A519F3EB0782CC0D71951EFFD9A55350D49E608BC3083D2E9F83BE754493C0700680D2EB7AD23F68D87BAF732855C31C38DB057D97CAA59CDCC55B73D456C8EDD49EF958D277D5F25EF7B34758C9F649C0924C699E52D83BDB360EA586CB8481A2C1AE895C7A49C0F5031E90175E4412DF11B3320A6F4F71C6BD7D9C69307B837321A4872B6CED46588B649B4438247CF1EBD66518427743822CC2AEFCBD57C4978B2CF5B9BCF762346CE98EFAB43D8E98F09A8D5A067B20AA50F4FEAA4E599B239FF3B91B3EB334F47430BB58F858DDFF34060C12DA7A811FFC4B68B808B7F6034E6B5AB074736A3D5588D5D5BFC7B20826FF66385D88592572991EE35A7CFBBC4AA81A9CFE1D8AC09BCEBD4194BB60348960910941BDB5C602353DDB5476E2E89D298B07BD250A0964A59C8ECB1790C738EA59E9EBE26A8CE2448AC8EFAF6C24DBD4A47B205877646687A4AC2136FAFAA476A27A1CF8FCBABEFE2568AA4129C53977A2F6632596E062F583644DCE6BBB59902468FCF207E2E7F9BC22331ECA155DDF62A983F4877EDFC2072765887CF0926A1F0A1CC0C8477FC01E796974BD543B7E166E5BC2375508A5993AEAE08D5F7CCB9FC8FFB0088D072B39C3E61E156B14A2EBF7720E94D032BA0177379D5C9F42BEFC9DE4E4548B7589572088636EEA803E1647F485ED7E26CF8645AE815579DEAA7137217776204E5081E8B76447CF4B26E70977149ABCC18E67256E1EECE423ED51EDE237C918B7F5F9A40404C6C277B6FA77AA5C02CA0FC465A30050C23F639DB4CA1259ED036DDE41711AF6A8CCC7A4ADA7146549D7EA87EE2DD226085733BA30664FFCA01DD9F719CC0A81AF192B98DB6BA31B1B0E53ECEF8A7BBF3147D5FA4D50B6328CCB049FDD2D4B7DCD58E8D502494AACA428AF3212530D15921AB5D1F610345E52E90C0057133DFDB2D62F86A1A6BCF7FD294624B1841039CDEEFDC2676987AD248A72193D3A4590EAA17F4C237673FB5DCDE4CCDA0F9CCEC8D24278257B86494E82621724A3BAC2E3B54A0014D406477AF264A984BAC314FDB3406AF7DD6B6F2B35FDA1145CC6BA1321E924C58CB9F4DC0AFD2306ECB493BF4D2971535FCB1649DAE4EED655232E2BBA9662D1AE5F60F95B9EECD038583E7169F1D7235556B356C2DAEAA7DB1E76D7DEF75C5651B200EDC87807C0DE360172B66D7C634BFAD653D31C0ED364C92E4D181501310BE82FA7E0F96ADD5EE2788CC977F16D92038BD420F87335A33D790F49BAA8C934C076CE4DD47252900904E0A38209FCD7C0AB14893D100364E9F4B3706B839449AF57F8F1231FCD81293427F3929221337C37890F943007B0636953DFCEE2347560A6F42A00FBA4A0ED835FF8F80FD257C37FF433FA84B56F50488DB9BBEDC2470FA282FB9E07327082E82200D00EB853970C0C4EEE007ADBF184D9B87DFAE50FC118F9457CD6B9CC4D73A11262A49F41902A22BFD17358FF37B70A092D7A029803124FC71562E6B0423FF17A5F68794CF5882843C8352E4DBFFA1DC5DCB09ED361191F4054C83C2D43626D9171EE9FDF4DBD03A551CECFDDF402071B5510D391A12E09365928F82D5BFAF055C78CCBD15A4E882FACF9719259315C52C110D8329EDBF053E5697614B4D64956DE6A06673625B10688A3E4A7AC66ED17CC956C4B22BDC6EB9C77FBF0C8637AC6B02AC3EF2AE52C9B5FC1A9EAE758A77E7C6E481F7A0E2410A32ADABE39C04E25392DF78192FDECE778C0EB6113DC0443D07D746A1B5B5CA1F6A34C001A7E619F7384B1B95115DB8E7160A6A912C30CC71696DDCC4BD409EDD1459AFFA1DCDD0A6F4BED9F2A4AE2CA91F5E8BAA4A38F339684F9739095539F7AC3E80B8AEBDCA493AC49D6D57D9CDBB4132A55FB5F393DC657592CE35969C9F84E145662D73FA61944170869B85E28E82DCF7D7B0DA41B9ABA452382BFB13A327FDE87593668DCD3844CB74830C40DF93034C599EC5EFAAA08CBA8920C135982DCC5F9D9D6CFA1B4F299E6B0FCD359E6373A527AFBA04610E3ED506AC03AD760E3246B6ADA342260930097426839AD2571C25AD1C0DE873C8FD8E5E97F36F4B7C285DDC877FF0C0307E1E7EB08F3A8BA302AF8FDDFF59004AD2EDB014E48F15C1BDF8FD26BE4BD72C657C9DEE69C238C203BA9444DF6D7DCE5C92B49140AB4CEE09BCF2973C64E5B7D8637882BC11E00FB5ED1029FBD1E2507B2FC92B9645EBB930AEE5ACCFA1869ED5DD6B7BF5FA124AB2A4DC529B23F338DAA21C0D9BB9209277BE520D2C333F136771541E65665A801C7E79F269991E0CBBACD22D8478031BBDD90436A7041E7F64C8EB29CFD5D374489BF01C402D29DEA045527F60128FEE6E38608C6223D81860FA8DA0AEF43DE5D95EE5E887E7DB8FAF259662B19E1E5239FCBB9674461124C2D8BB45A08930AB076DA6022DA667865CD1DC3C8D7666C2DB3B66B139A670924CC026AF2B95EF26F5EA5A44F81C2493953439A36AD5964C71F86964237E7260FC13B56C80B75BC7E1B547A31C22CABF16D21C056DCD28772AD93D332B8A037678F948E566B713DDD972C1B48DF32F4F2EAA4D51626DF32FEA3E42A679279B57B2D02A22D9E5595EBE3E2BFA0B74E936AAEE05813DB2140B0518FA28756D63B1D66A01BDC80C754850EE922341F92476540BFB8B221A1900BB1F1DC0EA30E950DA7A23A0722C6E9D78BC304E1FF1CA0CF484D36A71D88EBC500101A9EFB45E1F054248C6D58303279D5E1366E9CBE1CA5510CC665C7EDE02EC664F712AC5ADC35E1048DDA803377180ACCD13C528D385203653DFE8F7C2866345DA6E3492FDD7B04F07D882032151D95AE5B0B1CB3DC393C951F371CEDB664DC2796329C83CEDAEF5627520FB021C1501058D1111D4980716DB6A410966E273A08AC08ABE28101EF702BC68C7A298C735DE70C84D543BEDE05B12EDD1ACA58F80027F70419157D8F46F1A0F182F3F7443A30C2AF619264C4ED3A96216234D4B5C2DE8C5232785A38797D3DE3A2CD4B01C9EAA2EA07B9966DC33216EE8F4C1D121CFB3EB4779501B1D69A25E45471122FEF84678781EAAE09481E9EF0517BA92D502BC6B78E969A24D8F1037D83A219422FF70F0AE49580224D257C690611506AE1089438AA6AA148FA32BE90E7308595F55CD06A6CAE48CA9B947A592A312EB790989C8B1DE0A7B555B610A1D6EF4B1CAFD663A930E5FE32CFC99D05F0482EC913F7004EA3FA8814A51B14B69D96E3AC595DA953CD7586BAAA59CB445391C50D87479DEFEEFC78A54E5F0425D147A528E5E0BC929EDAFBAE7055A44A3F43C11346172F460903CD5CE4F4057E7160D962B4926E62E5326EBC5BEF6F99582E760A9DE0DFCA185F2FD2235FAD9AC58D3D1F7C4195ACE55E3E13A872FA19943404B68E0AE080811F5A55628C4F8584C3E6DEB2502D0698C9153FB2BC119565064DEF5AF71CCAACAC8E5CF7303A690EA88ED49C1B673416FE2DB4E5A0DDD50DB4F05C4E503A9DB71C2205D1C01F688EBC210A3D4D0949AF09D85CC957E4FBDEB95F323FEE2AAE7DE12D7FF9616246EEB526297FC397C0BBB6BD3487DDC46F3726272870DD38A091829C4C1F89503DA7917E1421BB8C1B118E868920E626A02CCE38C34A39C6018C8587FD375BA122667F9CF65FB03D7BAA0C06E256BF7FBB5BEC2F51409CF36DCB7C87AC339EE3C5ED5412B15930506C80CD193E22D3AADD05DC914B2C4FE1C97C2F2AE32891480B2840F5029CCE621B9BB2D08373B53AE7C1BA9656FD9899AD7259352A056D43FF751E15E1DEA840477A85BF796F5E55B6F443117DFAE11D8FB75790338938062E7EE10E65AF5909197A5EEC77E9103E13F37E25C24BD5F483F0862A87180CBE327F80FA8E4FF0179B39F7F39C0495A697197C400B0233D2A8EC8A65193E72016D90BA085825AFC403669A9853D2588F6AEF937D9BBCA3203BAE51A1C59AFE6CB7F695FB4A9D4E7169A84CA477AB8ED683FAFA399B0475A0FD89CCB9C40E0E68782DE05D3C5D34DD911203E3700EA8902F8B2DDA90B4C1A370E50DC0C094AD6BA9D43C59CB219A26B62C9889008230EEE13C8A48D033D7B35C3CEC575F740D0C7498499BD25ED4FDE0F714642C4892FEB41EDF840A549B760C78FD8E4542D7421F9C047848951C82679C67E91F63971399FD9330947902100CC39F596146A8AE2FD25490342AA61F025D2C6DFCA26698E1D9F457AFA6AD9699F47B74F5B31120E3C9B93D1F06DF7F47842E475C94235A6D0677975250FE8934BE064FBF21294F3C0B7A32F92979DAFA85002B786649F5D11117FF4B89CE92CB300861009FB0266ADF0B5119E061438C9C9CDD40D300CE64006E9E192A03A23CE767B91118DA5AC4E9C0995AF8EBE0BFC462AEFCF141F83F39FD0021120D30DB59142278A83263C23208671277737B248DEE44B764B53B957F89D71BDA39A2DC8FCDF1D4B9680791FEECBAE8EAD5C7C681DBA333C87966A3D88D092E5B47E808658A82A971966B25D6B2B887FA52BA99C20099FE866F1406575E0C2C6ED936A6F4B28350531E44EB707D6D05B0EEB985D26F6C4ABDF971F6767C42239A4EC6FD7C018347CF6A46A3CBAE8E09020E4578A47659FF7CEBF90B308CD9D6CC215121B66F89AF5B61B66828B88F0F6B68F47826D97F13F4C7709018880742906FE79A5D5C529274961D32CFF1D6C45CF99FD79861AFE2A24D3CEEEEF996D36A73C7B8D0F4A21F1651F380CC4C53F2F0BC331EE83FBA3ECFF4E8001F63A38B0F39C84C2A2DE3684780B1366E1F2655F939FE22B687FB3AC998E8DC0C91FFB2AE7881828407D8D2D8DAC7577E73D0A0DE9216D56580C4774E9D729135175BA5810E87E58D93D1E1611B59DBB093BC45B8480D7A8B1A4D2DA40A43E68547ADB17F21C67FFBEB133AB035744A26F8C6AAD13CD8FD09E12A76B15A41834FEB5C297D986C9ECD4C59DD24D2CA55A5F306BB43A915586EB0B78DF75FBEA1A99FEAC4D94ADC8E8C37DD84D2FBC83726D4C0CE43864FA6D5F3BACCE0DE976D8DA83384E7F57C6B26882F0BCB808572E88067229EF05E135043FED5800F9DBDA070072AB8434F31585597BB6733DB457E47D4606774CE9D5A20249406A6DB16FA616B5B895ABAA53135DA4958A2BC2C68A957383B3D463BA169D0981EBB2AA17A80C0F5D88FBC239D3F3F319A8534A774082B5D5FA2EBBD2B3FBA1F7A1296860B28CEC7D1B643E8FD239AFC0E14911C352924068FDD51D7A503DAA8C5ACB98AA8A92671C66CD5BDC432602C07EFBF069EADEA40FE8FF63DD6E722CDEBAB23407A104354EE1F45C85366424D6D25CFB544C40A27B2689C28B2F8AADF4A07C2191F1FB1E79C6A188F5811ED884DB8C0A1176D791790FB8E01842A91F574768E5B94292E5D73E828DABB8ADF907B03DAFA2809B7DC8EAA782381A06361D8231AD19391E4148A633D3F44AE6C161BED86705FA7CD6ACEA1CCF9A10ACBC374B70288700E0CE91FC67FB4CC7897E03E62079419E3122055A012F1D4FA637FA769CA8D9BE3A61DE0AD608938089E4619ECBB4F0337B98194E232CFEB0B042562F01D62BE0A545ABBE9A36C8298F84D01DCE7E84F147C6FB038F8B9A0D632E5994B2637EB3B980F88508329844D0F0BE9E5CE1E232BD64E83ADB27511AAA9E5B6CDC34762C061C634D85FFE8142EB6339ECCFCB0814C27D64E7B44D7912FDEDA6AD72B679C7A92983F7E94ACBE7BD30C24F4B34DADEDD920B45D28B0C245D11EA7247E3D024E96233A647003B77B18D2A837B29D7C912C7DFD0BB23E52E1D6FAAC750499FD9509D65D8F12497CD668394555088A9233A216F70040F79C57D1598E765641777ED5122EDC40EC7EE30026A379F9FCD94B6878D3EEA2FC55123905BEB9BB067F26C2C680F55BB5F3B59814001953225ED47F420DDE6E88DCD9BD1CA23A2EC428FAA77CB7337CE3F0B2851E568EFB3BBE17A7E93978F8A1B839EAA7383F13B887D3EC0672D76B2A589C525B5950324EDD825D8B93458AAF0105C47E48D5ABB09FCC9682A2F5C8E7AC7C909D269C4867069CC9B5E1872441483C046C12ECE182F0A1BC8CB9AFACE7B976DF16B4ED8964BD5C77AC0BF5CE18A7543A65F05CD4BF9A0EAC84E0BBAE57F0E2FC6AA70E8D5BB2A0AEB5753577FBD3A4E4647546F75CA2207CA640058302AE20BB29F9637099C7DFB250AD1F496496B1B13CD74AE1AAEA9FC88791E71AAD1CAC07557A4D016F334A9D9693A6AF82D6170F8F54472B643E113E599AE807DFC505330018F4EA49AF41088CAC4B1644F046B07AD88A59D581A216680EA8D44B43BDD08D73AE6AE22CC5DF123E9EB7F2FAFA6954388D073AAC5E7F75DD813A076DBD49EF7A89D041DBCE4E12AA4797E2EB236E143E7F13B6B596E1142FF404AA8BD8A48055C878712927786A3EF58F65C79C8AB91326C8EDAA9339E4A7BC12E7C9A387D2A2168D22ABFDEA1707A877C0067C4D926A4B976410B7D6C28E94C96D1491A19A6EBDC2B00F670E163CB0E6011B79DD2B6E807D7D0C22C1EB3FCA9417337D027507DC5148B99C83023C80285FD0D4A614B69EFE9414238D4BFCD77044D3F7E2BEAE70F93F279571D1FD7A418BFA621A6B247F60957E6D61E44E064CE22B3E2F459E69B05FDB67ED212D2C9799E1015199BC052053964C40400F14F021488EA6BE4BFCED90B1BB90BC913F6851D5C7034DB5B225261DDBAE52286F50C677CCD89E86D84EE514C0E8017563C156E4EF6B4711A26B956980A0704D9B67416BC945C566CACAFD791D38F4C924B0BA19586D390408B4D46043350638DD987958A796AB1EFCF01A246DCDF36A77CB44CFE656F52D2D3C621570652395C4C59C85BF9B228E049B1C675315963BC06AE977F0365186A34B2A6B3396AE97CC855FA8316EAADBA9B6CA4B3A8DDA18A52754067BACA48D7315E27370B75A6EED859BCEB6EE0951BF0DCD3A6C064C167112C50C41A81B1FE0D1351C8C376AF15C5C5EB4F10B62B71D02466EDE6A216DC8CB015EF14D2C44697BEEE4B8EDC587A2DCDE0FA8982466B00EEF3F61AD4175B0C753C0350C000E2F194A751D7DFE2F3DBECB028C11C530A79BADE35EEDE3BC3A7833F099045295DBCFE08E4DAF483210BF01A3E13EE99E0223199A5F1CB041368E3AA54A0D96396C3626BD3136E2F8527AD39EEC40DBFC8E94EE76EAB736BF1F9E58BF74A3E80229C836AB182C6DCB402147E4491255F5B23E16B51E1F4EB4FF679D92DD2383AE92D07423092FE462262235C97051750C48620C358D33E3097A81ABB08EDBEE1D9D9952799D32EC825AB38EFCEA8444ADF191497A174E205EEC6AA9878433D44B34182CD6FFFC6F167689DBDAA4E71FF63DFDBEFD9173054F78F38C328864FE26DF42C7D1576DAEF52133048D7246B9054BB34A8675D7BAC112DD5E0B703C8D118AB4FB62204D9ECF4FC8DB5D6F78DC313987E7D51A78B1078805BF7A0EA285E5A5F203BE4B57E4FD157A36ACFB5C529A002CD2E955B8F71203F3DA1A8E23C0AD43F6B87C751EE6E2A2EAC0A041050C2BB3247AE2D09C8FEDFAF0BA577DCA6EF1B9896805A4D524E246EF466BF757D0FDE7AE676AA8DEDCA666CB8284638E64D77BCEE6B89C0687DDFF989BE05524F5A320BD70CE630449DAACC19ED853A07EB78A6EEF29701760E027896A1043FC5141D5DE63A51D967477850B0CDA67AE8A5F19E355E635CC32095C90A7D9993897AF705D03743CD899F4FA77A3650B857878FE0BF65FA66A0C09AC5A498DEE9ADD4D735C6A0AAB1622414961ECBD29CCFED7172FDB8E4138090650FAC7E28F0C065F9956F1AE1B6ECCE8E8B515457D4EDFDF5C7176BFBF4E0B3B5263BAB14E3FB13D5B8D23D2DB4FBBA962F3A68B22C489021AE8861D9547A04B4AB65BB7B41B99A804D7EAEF2A0C040DB5CD5CCCA880188EDAB79766B993A813EDD88824F303F54759FD874AD999D70DE37968C8EAD3A2CA9ECDDDFC8333EF702FD6025284DF19B1D81572ABF9CDB440E08A83402BDF291935BE862626F8C3260D161B03968588035FB6EFD561F7D0D0189D1BF9B0AF454FADE91CC559F38BDF514C9DE3B2B1AA5B017FE075F053B83DEDB50E88DCCA765ED0CB56AD68C2AA6C2A1084145AED1E66F2C0F730CED05F5930DED8A4E5020287D63E12E65AFCF23ED5744AE0CFA3E30096A7961CD24590006BFC7C8AEA0587270DFD3E1BDB370CF6CEB95B59857F8A8DFAD80D3D6CE6B490AD127B5E806853CFED23D2D264C8245E9B9F4E19EA377AEB72EE8F12F849BA2748AE6DC8BCAE7665658B6C61ADB82832B3AFA2CD979BA676978FEC91D940D7A368AB89B65A5CA1ED29E8B35ECA183EB9C65C5F48A6ED8FAC08F6302DC1E48C24B4C8F9012E72D8560DB5A3AFE847AC7F5032CA7CE08EFD7B1CDDAD632B742B445B8EAA021F3C8A5383083BF14ADFC4C04AB1DC8F190F4325CB7DE551C4742B988A5E53599CAA5F14A777F8D8530B313C19EC1979989B2B4B4A8536A256398F0FDCA366EB8C6A24A052C8E7A2176BD2BF4CA937D75BB200EE33070E1773BDBD6DE7E9FBB0A445B0AEC87826D0B38834DFB37655AD02B7B32AA378B8845C0C2C950B7ABA2D70221A06F9890EE38B2F3AAAD22F64FC670F6B3036D00C2C8C2B52BC4B91C439CD076E905B4FB478A9D09E733D0DB12CA72F2DFB0E8AF79F15EE79CD375297F96A01DDCBC1D3A0185BF286653199EF7F7A25141B64C92B430FCE7B6DD5E6415739A4083C30E56BD48F15A01B03916E7BFEFA53113D7B95A1D59ABBF258334374B12F2C8D91B34E94B9408C4E280F3F7E60FF6FDA932F19BD0E6666962A797B5BD22C6AD364E1EA4BACBE58FCEE4778C65A3D9258C368E081166E7E2A4DB86A40C4307CFCA56B197F15242ED4D71CCFC7EE9F3BECE72397694BE8BDF662C0FDF3541738BDCA7C20EF2312429F3A0CA9F99FB63CAD7C7D59A09913B1BCAD231C54263A7FC0E412FD717E4BC9D4E0F82E3F3EC457AC844F76D7BE9724B7CB6441FFF6EE79FF8CE9158CB9CA2E31B384C0A0E4717DE9CC6FD0D6C3A7014DED45A61A09C9DEF27F2FB255AFCAF3B920452439D683D259E65833861DA23BE4E7C79E73241427E9A6CD21B5BE283A027C17B57E83C8766A724C34B19658D5DCF3CE6DE72B80950C1E3A9209611D9ABD1D300906ECBD601F513400D7DF75534EF844C1F0BB53D6FC81A95F49366D0855B27693654ECFF0356D4D95F77FBE2CA8E644101C5BA901CA5A0D84425D16E9E42BAB2469E2ED0029548C836EBDDF7CC37CB763F25CECF90875C80B404AADD85664B0CBD499C3C6F843E7C8CF26930D7A91C1C6A6B3F7883FB11CF319E2BFDEA6B32C090C14A729B9F06AAE75232AE1E1BB91AF89E731A36D288C237DCFAD168408211BFA8A0066E9970CB64948131B873A125D511055BF81889BE38884ACE94254296C020EE757BB2AC5F2DA7B5A2415709C42BD50C573B3619A71EE1CDE65EA2373F41FA6197853BAA1264A63E4052E76CE17E8692BF28FB5B9A07475689F4C6007B60865056F5723EF02AE9E294F7D9443784DC67D80F8816569EC7804DD5202D9E95B2EFDC9715FC0C47A2843F08C6923DF32F05186E387BE86FF9C82DE1F11B0ABC53FF44F967906EE06B806CF3D74DD825424AB62B15306D46F76C9D4DCE1A56878982B4C75D449B8E9627F2B80EF498ABFFF8AFA664EFA713920DF1FB0321225139E57A449900D80DAF3784FD4DB53802D3E15DC57AA02299DBA1354F42A08B74F5917E297A4412FF2092072D5AB9D5ECC5FF2711C36CE699B2D078F7CB98BB0EBC1FF7AC371E888FDE6EA4D8A8F54F21CB5889537969B198BAD466A9DB2B2397D6F8714AB229A5A776A74354B80DF0CD81472C730F6785526E5EE152B7DEA4A34B1D01A074046F91B2D1ECD2165CD0ACE3991883FEB0887F632EDC634842FF97F29019AB0C40598CE78AB03D8AB33C018E447F2EB610B48A84924D45280C596FE244DF764325A0934F9BAC73F04AE4BFF2DAD503D3C0D1D1EB8F167A030464DB21505B35D3C5CE5893DBEF2A74309A49AD8D525D27559C1172FD8AB41F26903B36C142AFFFBEEC2D0C8C6FF7E1A76DBAF4DCDC85B207B3CBB439B2D63B0A497D4BA3F3A2EDEA49FEA12540AAF5A42FCB9FDFCF325A1A892F1D86FBB5FC05E20232E2BC4DB3BACD0A92EDD48CC708D61009E7466B4B0723212AD49566FE83F29B333E6802E7E217D512B4AF7C35FC5804A0DBAC04CF86C73BCF8B12EF25561C0EEB494988A0C33827DF61588667A6FB3E7C80C612D7EDCBBC773"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY('max')), + "OßäÄ*aUAZb bv@<å~üÄa£uUoÜåÐb:>ZauaÐßîUhhýå*/öÐÜu Zª@åZAö|Äöî+Ü<+îýOåZA,ÜAoÄu/ C~h~BAå¢Bã©ÃÃ>Ã,zB ö£Ã/aU,z_u_~bãÖ£îÖÜ©:>Zî*u~ åb£ã¢î>©.oh ÃÐ*,_U¢ãðäߢ@.å/+ßbß©b.:~Ãöh*", + ",rîAAîðÄÄ,¢BÄh~ã¢UÖU,¢aý+©~¢OvovC©_u©Ba/|åB|~¢z+Üü£Äðå.Örð£* z_/U+ýA~+o@uz©@_/.Ö+rãr¢/ UvÜAÖ/£Cv £ r£vß.ßC<¢rîuÜ@îýC: ßßAÐÜß*.B|O.OåBrCB./,>öÄA*|UU_©aßaã_oî<ýb,Að/ßÄ ÃzÜåÃað ã Ä.UBO_îOªOb|Ar¢/+a:AvU£u|ðÖßzßb@ÃãrbÐüu>avr@ZCv~vv£ðäßb:ÜA@UÜCäßC@åra_Ã,ßöaýbCð/", + "Uðz£öýAu.ßßßÖÐbZuäîÄbU©r+A©~ýZAOÜr~ö îuã~î>Zßöý¢hbåßu©CavCZð /UCߪa_oCö £bhoÐ+,.AA:ð,uöCb|Ãrªz@h£,>Oð/*äu<~_.ããbß~hZß<Ð.uo*©ð@Aüåª*äߪ_:ðA>,zÖ|<å@ä z¢vüð ãoÃðÃ:¢©ß<ýurb©+Öý*B:~äÜ.©Ã¢~üBåîvÃZUBßð©bÖýîZ©Z£öäv¢ãäUZî@AÖýBã,B ð*,C©o..+ãäåCa.ü£Cßvb,:ý*|ÜOÃýîªßöÐövßOCu.>,.a,A*a/Ð|ãv@å,ÜB+UÐ+ðvbov<ÄßðÄA£îb~ OÖßÃ|OAüÃrbäbBÐü©C*>ä<|rz@öC,Z/:Öö£@OÜ öÄÜüÖ@öÐZo©<,,+C>|ÃäBzZ:BZrO/@Äa.oov¢+h*,<ð>ýߪßîuî+ßîU¢/zå: ÜzÖ:£bUUCð@ß <©aªOob*Ö*~ßÐÖö>/¢U©ßªÜü@BhC/| ÄZo©Ö ä/uÄh@ ß:<ä,ÄbZvo>äîbbbAöîOAä@~BOo|rAüÃb/obªvÄÐrüörðãa,+Öå/@b£z<|ý:ä¢Ðu,ý+b £ðÖUÐöÄAu:bzö@aü,Ã*bßÜ_Ðb¢~UÐßö:öbÐãhrÜCövUCîhðBÄUýzaý>å+aOB+>öÜzã@huÄh+Ð+ß©¢rzO*©C¢BÃÐüÐ~©Aö>.z<*ßî*©ubv<öC|ß|::U.~ßaB© />COª.Oav<ߢýAvv@~ªO£:Uo|ðOBå£bÖCZzÖß:uo v/<<Ãü,vCAÄBOÜA_uaÜ©åößãܪ*£ö@Zr*ABbo¢>öboÜ~oåîUoÃ_aÜß_ov åzOÜ~£>åäB+ä*ª@ߪÄOr©åÄC>výv._<ðßãÐOÖZ~hBZaßäz ð>ürãýb£aªbvz©u:zª:b>ä bzCAC,äåvOðbÜ:*¢öÐrÐ|ÃAZ:äßÄr.UãboîîÐööUhÄßb,¢/aüü> zhÖ+Zã~U~o©äöBý¢|/îýÜö~äåöåã.ßÐuîð@ð,@¢å+Ä£ýAöhz£ß/@b@_+_î>*öÖßÜ//üa|buAßa¢bZªßðß~Oª+ro+,o, öä.hýîv©äå¢ä@üU:ÄOBà O*_ß>ð|öÄî@O@£h_+C~©/ª>ãåbB.a¢h ßaÖ@å >üÃÄoýB©azBî b>", + "~ãÃö/ãoðbÜr+>墩b¢¢üÄ/@ÐrbÜzBzbßÜCO©O,bC_Übrîz>.£|>/ð*zãî_*ßäa¢ðÄöA*u££bÃöz>>ÃhÄ@Тä,¢UÜaCãäÃAüÖb<å/êZað.Ðýbß*r.£ZC,Ö@BÃU*CßÜ+£ü|.AßÃað:¢öýîvÐOÖ£:AÐä+ ößÖ/vorhAbA<,z,Ä¢+£Öß_r.>o*o ðBrbBað~£z.ßößUvÜ:vÐ,*rª@,ª öBßbßÄoðZzu+ßbÐ*", + "Bªh@Bzz>b|ªB*+ã:,U._oö./AýUuZîCa_ã/*Ð<¢ZÜA£îªOÐ:ãÖ£O~~:oOÃ*aÐ|:ã*ä©ã¢ävÃÃðO*£üah_üäabãA ß:|ßbA¢a,ãü£o.Bo>Bvß>~:ðAhZbýBÖª Ð/î©î¢rZî¢bZ~oãÄ<üOÄ@z/CO:äî@B:zýa/*Aßß+U,b©ß,Ä Ö©UC|åß.ýßZauaÐßîUhhýå*/öÐÜu Zª@åZAö|Äöî+Ü<+îýOåZA,ÜAoÄu/ C~h~BAå¢Bã©ÃÃ>Ã,zB ö£Ã/aU,z_u_~bãÖ£îÖÜ©:>Zî*u~ åb£ã¢î>©.oh ÃÐ*,_U¢ãðäߢ@.å/+ßbß©b.:~Ãöh*buТ:üÐoå*B~Ð.Ava uabz¢b*©¢zåßäz<>ã¢bab/ov<:ýrð£,O|*ÐCZܪ©vÜ .Zb<ßBu|,raUÜäßßOBhÐýðÃv>~*rbA,ÐZBÐý/ürCÃbýý_Cöv>ö/|Cb*>~ßürÐA>+ßvö©", + ",rîAAîðÄÄ,¢BÄh~ã¢UÖU,¢aý+©~¢OvovC©_u©Ba/|åB|~¢z+Üü£Äðå.Örð£* z_/U+ýA~+o@uz©@_/.Ö+rãr¢/ UvÜAÖ/£Cv £ r£vß.ßC<¢rîuÜ@îýC: ßßAÐÜß*.B|O.OåBrCB./,>öÄA*|UU_©aßaã_oî<ýb,Að/ßÄ ÃzÜåÃað ã Ä.UBO_îOªOb|Ar¢/+a:AvU£u|ðÖßzßb@ÃãrbÐüu>avr@ZCv~vv£ðäßb:ÜA@UÜCäßC@åra_Ã,ßöaýbCð/£O@bhh£äÖÐZÄ:üÐî,,.ÜUb~Ä|vhðßb.©Cbªª~ߣüåa:vvýößuBª£Ãor~ªß<åaÐbÃz¢~+*h ~Ð/åUªz:~zzÃÃ<ÖüüåaýÜ ÜüoðÖü¢,~墩b¢¢üÄ/@ÐrbÜzBzbßÜCO©O,bC_Übrîz>.£|>/ð*zãî_*ßäa¢ðÄöA*u££bÃöz>>ÃhÄ@Тä,¢UÜaCãäÃAüÖb<å/êZað.Ðýbß*r.£ZC,Ö@BÃU*CßÜ+£ü|.AßÃað:¢öýîvÐOÖ£:AÐä+ ößÖ/vorhAbA<,z,Ä¢+£Öß_r.>o*o ðBrbBað~£z.ßößUvÜ:vÐ,*rª@,ª öBßbßÄoðZzu+ßbÐ* aª+OU+åî~ö|îª|Ã.~£_<+üU© ý:uåö*¢äv@ßuoÃÐðoUÖ~a©Ö_ür.OåüA+ÄäUî©a¢~öb AîO/öß_uÐ.@Z/ßvhªO£ü*Ä¢ßÜ:* ÖZî¢|örüCî©ývbCZ/", + "Bªh@Bzz>b|ªB*+ã:,U._oö./AýUuZîCa_ã/*Ð<¢ZÜA£îªOÐ:ãÖ£O~~:oOÃ*aÐ|:ã*ä©ã¢ävÃÃðO*£üah_üäabãA ß:|ßbA¢a,ãü£o.Bo>Bvß>~:ðAhZbýuö:ýOÄð/zü+åOößý*ühåÃ>ý~ußua¢ÖîÖ_aOå@©ýÃOÄOCîð ¢¢ð©oorZÐüäÖ*>îß|bª*oÜð:Ãý/ÃýzäÃz>ª+ÄBÖª Ð/î©î¢rZî¢bZ~oãÄ<üOÄ@z/CO:äî@B:zýa/*Aßß+U,b©ß,Ä Ö©UC|åß.ýßéOߣÐ.~.ßO~UCåÃvbZr ¢rß@Ö*_ß O©Ã©ö@ãU@ßÜ|ãu_Ößð|Uz,ýU,ßã©ýî,åÜb¢>î|o+ãa|", + null, + "ßývÖü/ü|AÜÃ/vC©Ov¢.åÜÖ~bäuÖO,zã>ߢAä.uðüîrbäß:ZAéÖöb_üA,uîЩßOÐöO¢£BßÜbÃ:ü~ÄÐu,öÐ>Ð|å.v£a:OzrZCAzî¢ß£öäîÃv¢|,z©a@ßðZ/ObÜ+ýB+~Ð>oä_,ß~~ZÜ¢ßä¢ÜÃvÃÜOß,*ã~hãã:©ä>züÜ:Äãðã.ð>o£¢ /ý©Ä.~,öBßaüvüÐC¢ðh>åäzý.ÜöÜäårOüß.äÜö/îðA©©Ãå£ä©ßåu>C/~©ÃZ££¢br~ßý:|å*©>U~äO£Z@CbBbýýÃä+ãOB£ßUZö>>.:>åu>.öü.*ÃÖ©ßÐä@~B¢Z_,ßÄZz._.h¢A/,äåu_h©bz@ZoAüÄÄ£î,åCîCb>rB_.ýubÄu.åýZbüöuUä_|v*ÃßÜuuoz<ÖßÄ AC£ Zr:ß_ãÐ+ã/ðå©U@ööÖä~uaã|îðCO|Ððã~ð| C:ßãB,+Üu/ß>ZÜ+vvbCZ+îå¢Ä_ßC@BzЩrß>üa>ߢb B¢aÖä>Üð,uªößåðu,ÜO+bßßã<* ü@£££o©Að|<.¢*o/ä*ð@*¢bv@,A:ZãOZ@oß,Ö~öÜCäý©î+_aå*ö>_ßý*:+CvCrÐB,rî:|ÖÃZ,o,<¢,*oãa|öåÃÐÃO:ö+:éîCîvÄÄbAü/B£ßrÃ:rZBßzãÃ<<*ÐC£ÃÖ|.vu~*v©Öå*C£©Ub¢Ð/aßAuvbO@ã+£Üuh~o a|UUz|ä@.b>åO£>Ãa+_båZß/ßã, +vüb@ðAbz ãob,*ððÖüoãA.bO©*¢UÄÐÄa*v< >ãü/ßÄ>aAÄãußð:bîÄZ¢ZÖ_£Cv~ªCoÃCåª.ðaÄA ðboü@./ßZ©B£üãbÖZ z@CîååaÄ*O>_br©üÄuª~hÄßßz:bbhA|©¢©,>uaOvüßbUZЪîüahßoÃOªÃzª.ãö| ¢ãð+ßoÐÄA ¢ £|@~ähBhåÐ@ð>Üßð,Ö/auÖ¢:ßUBßZ/ßßbäühßa|Ãä//åzýåa*ßzvî¢BåöbÖªbZä:öÄä¢ß©C,OÖhßzÖhß+b::C@î:ÖbOÖvü£~~üöªhUr©ÃðBo+CuC|u*ß@ÃCåÜÜr/Ðý/>ýã Ä©ÖO¢@ßÐ*:O ßäbîbu,,UCbb¢hýb.:U>_Ü>/ßAÄZÄöÜ.~:,|Ãb*vª:Bª~Ã|>_Ö îuÃÜa*¢Bb@C©Z*©*rz*Üu.zå£îåb:¢ªªbðCübÖvýÐ:BBCÖ/©î.ðb£Ab+,:ßåC>äÖbb/|:@Z:A+bÜzrÖå£>ßOüOÃ|~aßîU_Ãbª©,ðAýüåÜZ>öör|,ðÃOb*ä<@@ªC.îÄ>ÐUrÄ/ UÖ/*O<_ß>.~Ī©Öå_bUaöÖÜö/AaäÖoö¢r.r/£hrî@hbbZa~ACh¢ããªüCðuh><Ü,ruå@OßÄЩ//üÖª@Bߪ:b@.ýÄ/ÖÐãß.>._ßîuý>Ch.O|Äb>aÜ©hBîÐ.ßã.oåÐbåðvðA/öÄzCZ> £ ãZ¢öÐöoÃz~ÃhAbßãª+b_vzÜbbbb+aß.,Ö:ýC@öahÄuö* zð£hr£Ãß_£+ý<ªAª+A>ªv:ý.ð|b婪>Bårðv:výCAz.Oª£zaOªå+Z,ZZ+br¢|ßhðhvCZÃÖoCA+|öbßßvUbÄbÐhß<ð¢î+b*_uOBbrý:¢*bäÜAÃß*Ö|Ö<ÐuÐzªüß, ChübhBZAåðÃv_ÃТB<|©ßÜroÖßðh*/h|OAZAAå|Ou£öÄäöã,ãCuå@A+vĪÃUä~~ªO,Ö:~auýЩ*vßo_*©@ZUrvbh£a /rz £b @:O,ßãîUhä©C:_b ~ Z*.î*¢ß|ÃÜß/ Ãr<¢bovÐ: üCr:_|ß,äÄa+ÄðªC|~uoh:Ä@üîüîüOz~ãa/ßhoUýî,ðÄz <_aüªÃ@zr@.©<¢ªå.Ã,.@Ã>ßü,*uvÐ@ýr£/.åa|¢b_ßð,:ê,aüu îßÜbrýu Zb:ý.<ãrOý.CÖ*ýå|/>ÃÐßUÜZ©zã£+ÃA*zÜ>*öýýä.uA|C|_ßî>Ü<@ª:ßÃÃÐoý|ßz+Ü:|>_¢:@ã ªuuOCÖaÖåð|ãÃzéUUßäã,ÄO Bý *äzö©Zä~<>ª.üßö+ßðÖUßå+rÃýAãAÜÃ,aªªo.:COУ.åA: *. Ð@<>CUÃߣb/©~¢Z/ðÜrÖ*ÜÃâ|ZB/Öo©/ÃAoî@>*<ªßAÖbbܪª@|o£ýüãÜä|üª+îðÖuåªC@.ZäZÐü©ö|>@>ãuª@ÜÄb h£ð,åUðBýãOoA|öÄ *aÖC u.u:ßýbCÜöÐÃ_Ä/åvîUCÜ+åAå*b¢,OBäUZ.î|uý~|©ãÃ~ß*a¢Ð~ZÖ£ß,bOãã¢råboaÐ/ÜÐbÐu*ð,î¢~oý|ªbÄðA.A@¢Ã£bbzÜÜ@~BîUå©ãb.Ä.>:ª©äb~ß*Uüz.UC*BhZ¢ªCCýbb Ð.åä¢ÃªAoBýuüÄü.Z¢ß>ýÜ ÐðCBß+*ªªÜÖä,:+ ªßuöUCîzî£Äß+v~ öbhö>ªß£ß>+:uä~üîZOÃÖßb¢aßOo©@u O.îzz/ãaý|CÖÐ:BbbÐîBBî~Ca@ðÃ.£ýzvbvßöv£<:oÃOÄzî_ÄhBðªCUZãÜzß>h~*~ß<©rzBßB/£ðr,.ê+ýZ_bÃhßüüoüãüz|*ªåãu*.AZßO< B/+ªOhhzß>h åu ðãv: *ãÜ@ä,A|vvU>©<ä@ß*©ãOv|CÖ>*CbB:|ÐhüU£ãÐßC|A_v£©,+ßC<ªªobZ©Ü+bî>OßÃÖ_>ªäü¢äЪuAäCãöÖvüüüCýîüüb+ÐrbäÐ|åhåÖöoäÐå_ãvߣ@BouuãÄ¢_ª£îîUh@_+ZZUÄbazßCUU/bÄo.ä£bã£îäU~vBbvª~+a<ü_.ßaoî.Ä:,C|öÐ<,<:ÄÐ,.ýhßîv_@£å/~ЪaA¢îðUO,ä:ÄozÜrCîzÐ~h.©rU£ärß@Ãüuh:*ã|Ü>rah©CÐüÖz_ühãh<~+/£v+ý~ ÜÐöozãv @U,CZaB>ÃBåv_|hb©åý.î>Cr/ßå,ßß:/ãä/ahr©rärß©BZC_:>îÖª£Ü~Ã*CߢÜ/.zuu,ßh*Ü/Bo/¢_~ÜbbüZB©bÐÖÐßvª*ÃZ_ý.ÃÐüväÃA+Bbu|Öå î,å:..ª>.äv/ãÃî ã~bîbbÜCªbZü©_Ob+Z/z,B~ýBu|,~vO©rÄ+ý©ýZߪÜä C¢ãäÃub|UªöÖaBßã@+@ îªÖüor,,ýªÃ¢uUä:,ÃÄ+r¢.ªÜ¢ü~O:zuU_/>åäÃ>ß©|£îz@Öu*/ã©ohvroO_ußu_z<,Ãß*~@ýu__bÜÃ:Bu+ßa<|B,ozÄÃovA:a /ðãöäÜðã/ªªr.<Ä/a/,_ãîZZ¢bäããö@bb:v_Uv>Ab£C<ßüîUüÄv~b<>@¢|zßîBý>B@oürOOÐö*:Oßß>©h¢åC©ðA|öÖîÃöÃhü£ª,ZßöAÜ_@£ÄAzÄãb£©Zuåßo<ªa:v<ßUu<_O.uår~B~hZ _¢Ab£zaãÖÜßußrð|>bÐ,<_Ü_.ãÖ<ÄhZÃåob,/rã>U,ÐÜ,O.Ãva~@.åãýä>£ß_@h¢><ÐÃ>oðvîýÖðä¢ßvÐbÄO*ªª<ÐbA©h+îCbÐhÜZoa©,>Boðª@OUzÐ:Üz+bîÃruåßaCb£äC:|C_ã/ߣ: Ö+bå~üßß~>übZÐ.Ãuzo.Ð>@~:Cb©A+r<ªzCÖ/h,ªUUr*_+Z,hhr>zoABã©_åOÃa|ÄåîüÄðÃC:abbîzÜ<åC~îåbö©/ ¢u~åAª<îvÐÖz*ýäbAZCýO_îbabBCâöu@,z<_~ý/|ýAbÄ~Ö~Aßb£|/hb >äü@+u¢Ü_ÜüÃ,@:z©.r>ã+/z@bä~z£bUuobÄaðrÜ.vOßÜå£z~ îAö~îðßo,äÜb>C£:ä__/ößzýÐÜî__ÜCAv©Oäbî|>,ÃÄÖ|öÖvv .>Ðbå£h/ÐävÐr+©öu@+Oª.ЩbåãBÄ:zbUu*¢zOÜ@ЪOÃU©>*B¢ÐUîBÄýÖbAaßAÐv_r>üab¢AÐã:aUb/,+>aBÐboo@+äUoÜÐÃäîhbO_ AýÃ>b¢ÄÖ⢢za£_uaC£UO+,B+Z¢©ãÖba:£ãã<ÖZÜ£/@äba©ðbzîãO+ä¢+U.,:Uo> +zãv£ÐUßäªÐã@b+¢Ã¢@ärßbÜrîð_O:ßý+©ßArüuO>z£/¢bzh_ß©,.o<ÖªUbÐBß~©üäß+üÖ.£.öAð.¢|:ªßý,Ü.|urA/üîCð:©ßU<ðvbªß ðÜå.<Ã~OCCr<>uão/~B.Ãzv*_ä,Äb>+ZUZb/@AðßßüßÖUUã©..vÜÜ©U>CÖ*v£b*Ãåo~BO>~ÃzªA/î:Ar,üÖ@CÜ~Ü~CO¢ÜOý*>,| £Ö<îã|:O¢ß~©Äoä© ã~B~ß>b öðCª©ð@îÃ_£>ã©| .hÜ@>ðª zA©ß:ÐßU,~î¢*|üäbÜaªrOßCCCz©hbÜöÐ,|îZ@îª._ß B+ãC b*B£îu£ÄÄ£ÐaåhZß,ª© îßÄ<>+ßÃ+¢_üüüÃðÃBßü£ÃÃðü.>~rUbßývBðãUß~A£rb:.brA*BßäÖ@üÖB+öß:zC|ÐýÄåÖb:Zröý>¢<_+z_äovðUÐCOÖääß|*b>Ä/ Zv£>£ß@ÖZ/u¢bCAZz£îBrîÄ+|ÃðbbU.äbýäÐ_>©ã:__ZÐC@u_hBÐÖ ðä,£.|©:ÃAA+~bUZÖßýb££+.£/OÄ@ðh©BÐba*åbBoaä>U+_:üv,ZÖév<üaý,üðÖî+väýUöäÖåî¢ßåovîÄÖU@ãî.bß_+åBÄrbB~åBÃ<Ð _@åßb<ªßÐb©uÃUb:äßOÄ|ü©oÃ_ÃZvouUAðüzaªýzð|habý,ä@.UåZAÖ|äÐC@ßz_|ä/OÖvÖ/vßäÜaã£BÄhßÜäð öýo.:Z<<@ªA~oªß¢ªÜýýB.UÖÐr¢.+ý_ã@<î@uaåöU_Ö,©U£bC_b ö¢hªaÐ<ßuÜbbÜ>Ãh>ãÖ@ßÄZö/rrA>ÃrßB¢zå*z><_bÄ<<©ªO|>~vÜ|@U*roß_/z@~UýhOßßO*ZýÖýß:ܪAb*vhÃÖ<£@zb>uAÄ©¢<ÃZvrZOðÄ~a£oãÃour+Ä.v~ *î/,ðð.b~/ÖÐ~UäbBrüO<ý+:+*aß*öruCöîzãßaßOðbÐBü|ý z¢uZ.ä+_ýa~ð~Уu@¢¢ |rzrOý_ð£*.Üa>AzýðÃB_ÜäÜ/åªr/>|*ð©ÜB aC.z:墪ßîbà Uªð_ßÜ*@Üz,*Bvü/,äýÖßUßAüüÖã@ü|*Ö*vÜ£ÜÄåC*h åä+åߣ:<ÖOOÐaUßCh+£©,OÐÖarÜ¢oB¢:B.ð*¢CýA,O:oÜzÃüAa£Ð|vðÐ:_¢hoªrC.<ã:ßvî*ýö¢u|_ý¢ :ãu£@>u>råb<ãäÜý*ÐZ:uhÜCzТ£Ãoî|aßÃÖý<åý¢üª+ßähbãUußÃOB bB Üä~ßbý@¢üOªC>>å~aBuîßUÜ:<©ÐÖh>o~uO@Äß©ßäéßr>Üho:r a@ß+~*@@ zÐ>:AAåzüOÖ z+rh.|öÄ_~zöOhb,ßö*zo:|üO+o<åßOv/ýÄhªuoÜ|ßßÄ._Zåü<>Aã/OãßUüA,<ßÐ,A@r/ðÜ~Ü|Ö*©ã_¢BZ>,zo/ýßä +vC+býbz,Ab/bÃîUv©ãoüÃ*öCü..Uª@,~~. £OÃ+ª_o~aã:Ä,îozüÃ+©îOvB|©bÜ@Ãä:Z~ªBý<|/_ÖöZ@Äa /r.åuÐ.<ð~ßö<+bzüý.ßzb >Cðhouü|ã©Ð*zZýU_oCo,©¢üoã _zOA*åîÖZªvvüaüZÐAÜaüÐä£rððã>üý<~£A_<Ãa.,uüöîär+Ä*uhî¢*ß/_ã.übvzªßà ý.ßba*¢ÐÜðÐ*Ð_hhÖä|öZUCöä~/ ü£ Coå,Z|oC|ýªa@ß>Ã/ðh|ÖUÐAÐzäO/îzÜh~¢Oãhã~~Ðýü©u~o+åa,ßB~å/ã£ýÃü©©ÃãåöozäzB|ýaUÜ+@ÄÄß_îîöbaÖÐý<ãåªb vã*£ýbAÄzvC|¢£@ObÄÜ@OªÃö/CB@ ~å:ö|>ü>Ä~rUãCU*£:bUüî,ÐZýîAß~üuB¢£/z@o~ ßUî/äî", + "|hÜ>hZãªböÃoÜA@üor<ßbhZ:îo©ÄU/ã+ßð.OÃöoý©BZÜÜÜäãoU/îU Ðý_¢ÜUC,übAbBåã@ bOOߣ>A,@äýîäßU|.|/+", + null, + "vOö__ªU*buåðßÖî_.ªu|.ß rü|:¢Ð_ßüÖö¢z~rå~uÐBÄvZãåCbßöCzÐ@:Z~ýoªª@.îOåC~üuÄ£*ÃТöÃÄ|>ÃÄäã/uCäZ¢î.ªh|z*CüÜ@Bªu<übÜã*åvªCðß_bУaЩªßuÐ_o ª~Ößü~C£+rÖÖZ+zÖß/a.Uu>¢@Öz>ßh ÄîÄv>©ÄÐåO.U*.|zr:AOoBuCU©Ä>r.hý+åbã|BßBBÄhuãýorö/BbÜüOªÃªAßör_:b.å:+ÐÖC£ðB:üývv@>|Özbu.Ã/oübýhåO©O.CÃãuÃý,ääТà Öz/£Ühür:Üð|ÜA©ßrZZßäoß©*b Ã+_üß<£ ©ÃU,@ru£ðð£ðüÐb©:*ä<ª>ÜZÃßZãðßBBCÄýBüåÖª£>îÐÃo+üzå><ªOÄOîöÄÄð+ÄCß|ßvÐüÃ~~vßB~b~_: _bZ¢<öýßOaObÃvßÜîh+Cu Oðå**ª~ä+ovªã©ßOBävðßÃ,_||zßh:O*Brä+ÖC~,uz£aÜb.CüÐb>ãz_>@*ÜßzÜÐîýð>£ß:/üvåÃhOã,.©>Ü©*ã,*ßb/|Ðaä|ÜZ@ZbUü¢b /Ðý<ªAª:ßUîz+îð*î B .@oªåÃßbhü>UuÃ/ãßßîv:ÜO+ooÖÃ+zuªuOîî|+ªðu|zßЩbÃð@< aðAýzÜßAov@ªZÖ~+B¢~üvCu>+:ob .Av£@/îðO©,o~ãä>zöA*,zð@båÃ@¢ã¢ÜÄÐuUüÜzÃ/ðörß©.~£åoraüaÄ h/|r._ßÜ+äö.ª@@£*î<*ÐÃ.:CåÖÃ/ÖÐÐ@ðã*Ö~abß©uZ £/£Ür:hZo.BhÃ,b<>:bÄ+Zäu<+@uU:öÜ©@Ü£u <ÄAaUî|vßröªzrO|ö*|.zßöîbÄ< :Oª.UOý*Ã+bü©r| Z¢hЪC|.bßA©Ühü@/Uߢ~@*hußä~Z~ÖCU¢¢/|ÐÄ*ªr :hz||,__.+öÖÖZa>ÜUüh>Að/o>_öÃ@vÜ_£/Oå©.ÄAÖh,£ðÜÐvÃäãýßhZßA>ª_h:å>_ªýa êC©h£ßÖv*ªîAaZýhÖObu©ÖÐ|@_ ¢b/©~©Üv<*r/©¢Uoý£B/~>,ãßðBAã,CªB:Cuîðz+ua@ß_Ð.~/ªÐî/BÐh©~ä©~Ð.Buª r@avb Ðr~ý~Zb>>ªU£rOaÐý_zb£Ü>~.~ö.ub. ©~ÃåohbZÜobhO/A.z<@:öý©öÄý|a*©Z/Oîý¢>h|äÄ*.ü__CÖ|ö,©îÐoO|böCä¢üv:,ðoî©ýöÄOu+|ª:ß__åU@zÐÖý,Z,bo¢B,o@h¢öãîö:üÄ@ܪüªo|zÖÄÐh©OO@+ªå__hý.bzOªÄýZb*aUrÜzÜîªz ©.+<:Öz@*|/O+ÜrîzýüªÜ/£ß©öüÐbßüöuß ýÃãÐã,:ö>îßä.~.<ð¢Ä|uÜ~ß>ß~:_ª>ö_:rr:UCuz>hîãb_h£ bz@vBuCAubßý,î.äzü,uA©@>UТ©ö/U/ßu_r/Z+ýb.Ab. BU>ýÖ~Ö.Z+ÜAa*ª/BÜß+OO*r/Aª,hª£:bð£,OüéÃ,ðO..va,¢ UvboîåZ|Ðü*ZÃÐ öBÄuvhBh©ÜvOßaÖªa>Z,OAÜÐ>î.öà Cu:b:OZO+rhC++£Ä<_ý+ Ü, oð ýÄ*Äo:*£AÐÐ_|zãCBUb£,bß.äüzý*ãCð_ãZ:A<ý©AТýÖý.b>£zbbvöðîöäOh*zrªßaÐa+B¢U,¢£:ߣä_U>Ã_bãZî+_bªß_Ã/.+üý©bC|©ßãZ:BZý¢å㢣|üÐã£ãaa/äðuA/Ãåår,Cäuo¢ªð:ߢO£ãßÜßavã.Z_£+ßÄb.£ªCÖÃ:>Ü ßBUÄ+u,vub.vªÃªAßC~uã ð@>ßO>.ü,zý>rOªÃîzvBª¢©oAð>Ðî î|>:OÄu|AåävÃBZCAv>B.uý+:bBzªb£BÜý£_/O©_@Zu©ýððýZvhAoðãh|uüßä£OäAßzîbßbä~ö~ha ,@oCA ðªöãh@ýrräÃåB*¢o¢Að.,Ö*ÖröZU/uZOv,©*¢Ðö©©<@¢|@|bÐZUhö*hb>î@z,ßr>ðÄåßäÖa/ÜãÐîUÐr©,r>oühUîU¢ãÐr£vävaÃä¢Ürüvß+BªußÜÄãðOzb_Ü:ü_uîZuC~å£uA bªa@åhÜhzAãba*Ðb|r<î,£UübüªU@Ð~|Ö+ßzOÜO.a ©@,ãvä,>z/ÖCö,+A:ð__ª~/v £_/îÜAbîbýÄ|uÃÐäA.hߢ/.ðozUä:Ðbbh@¢ üª_,©uå,©:UußÃ~OZ/ÃrC@Ö<Ür/ î£/Ãb.å.äÖo.|AvÃbAbÜoîÜÄß/r:äb¢:Ü|ä©ýýªU/@ÜBrߣä C+.|££|a,îå<©O,¢Z*ãCUÜov+>¢bB*ãz<£.Cßääh_O.Ðüã:Ob@AzÄbBß hroa>îAb~ýAÜZß.<Ã|b*.Z@b/ý~z_ª._~ÜéÄCbZ+©,ä/.ßÄ¢ßa>b:îä©B~@ Ä@ü~>r@CÐÜ~@ÜýÐ婪AOäÃÄ~î¢ b¢öhªzoå,ý:h~>¢ßÄ,ruouÐß/ü/ÄAAÜzÄv.ÖÐÄzü£ÜÖöÖ>B*,zZßz.Oßåhãä:ã*uh/ BäbaBu|,:ÜböäBzÐÖüaZBªä~a©Brð.ЪbÜU@UZÐbãß*BBÖÜÖhCªUCoUvå*bßß<<î_Ü@ÖZzö: Zb£äÃî*¢CaOÄöuUýÐ@Ü £v|üý_bUÐOðaýüüÄã.r/ÄO©:zrª_ZÜ|ßohÃA<©äoãBåöBoÄýv_hz *¢:~C©ßö_üü¢CäãZðUO|AªªZÐ+o<ªvÖ¢U<ß@u:+abrZhðzüZåà ZüÖZÐaoãÐ@z vr ,£bzb<äo<ãz:+/,ä~îö:©>Ob@bª¢<Öåað~ðzU|£ã/ßv:/_ß, ©Ä. Ö£å:üßýäUÃÐöZ_Ü@BªAvBAåuУüvuZßA:ÃOöAãvÜ£ýOB@>haaåUbÃhUÄ֣РãУöåÄ>ª*ãZî Cã v/buß~*,îB:,ãZ<Ã:vZrÜz/..£@¢£CÃßðý Ö .z:C¢.aý/@>a~/bã¢|üý©ßObÐÐß,©:ãöÄ+Aößbhå/.üCaªb©ªüz/+Ü£¢C+,墢 ý©|zu,ha_/b|UãbbCÃCÜÄo.|ðÄ.ß/ÃUvßBý:/Zßv<öÖýzu.ÜbzvO>ãªãUa,@ýz|äOßÖo㪢ãåãzÖ..UÃz¢Öh.bÜü
Ã~Ub>@Ðh,>îuA:O£vý>*ð*býa>Ã<~@.BåU@:/rö/aübhßh£ÖîZ*üð*|*_vbýßU_åbß ßöÄubAb*üzîOåãö|zo/O_©OðOhö¢Ö.obaßäßrbvðåa~b¢BOoå©uÄ¢¢ßCÖÜAöB.~_häobüC+Uî@Z_bhzbößÐbr//+aÖb.A ã:.bîÖðCOÜzýßC vA¢<öýzÃ>*Ã/Übrbör|ÃßCAu_oãªüÜr¢zAÖÐ/öb*@ÜîÃr", + "1753-01-01 00:00:00.000", + "2000-02-25 21:49:00", + "1973-01-31", + "23:59:29.04987", + "2002-01-31 23:59:59.04987+08:00", + "2002-01-31 23:59:59.04987", + null, + array("0.7945", null, null, SQLSRV_SQLTYPE_NUMERIC(32,4)), + 0, + 0, + 1746584310, + 2147483647, + 13342, + 60, + 1, + array(("F13C5E31FC809573D1EBF43AE7C9DB0C226C824DB54218DB217F0F277DA6200DBBAFEF05A8C6314555DB61BC197324C4660C8882468DC5AF2383107D716DF62ACAE6"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(384)), + array(("D6635B3A3DF7D9"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(384)), + ",hã_aü:Ö.ð/ýåÄ<,Bý~Öä*C~ê<|@åb£~îü|Ähär*ZA+/o. z£Ð.~.ßO~UCåÃvbZr ¢rß@Ö*_ß O©Ã©ö@ãU@ßÜ|ãu_Ößð|Uz,ýU,ßã©ýî,åÜb¢>î|o+ãa|", + null, + "|hÜ>hZãªböÃoÜA@üor<ßbhZ:îo©ÄU/ã+ßð.OÃöoý©BZÜÜÜäãoU/îU Ðý_¢ÜUC,übAbBåã@ bOOߣ>A,@äýîäßU|.|/", + null, + "23:59:29.0498764", + "2002-01-31 23:59:59.0498764+08:00", + "2002-01-31 23:59:59.0498764", + null, + array("0.7945", null, null, SQLSRV_SQLTYPE_NUMERIC(36,4)), + ); +// 9 +$values[] = array(array(("007AA6514374FF12EE7B84A3C5CEB1A3C6BB4A00DA497372E074A6BBA2A20624F34E82ED43A5C97223EF01433A598BBCEDCB336620E669C180F0D3C1FBFBBAACAF392D2F302F094678FA7565255F157127C23"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(256)), + array(("B86B8689AB16C42D2078638345494012"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(256)), + array(("70879C3BABA5053C2FB8932061D60AD5502E042C8FA011D09626F131665A75789144D39EE5AE7BAF0E2A0AC3C63D2E6B8A0E47A35CF3CECF76CBA585B4D3D6D4421B8F1D026BEFA2B3551E65964E0A58F786A75712D11B9D7503281A08F5FB3B543580AAAE11681E1FA5F007D4693927C04D8E2D2B7EC27100F1A7FE43D599BD59E21160CD60A9E51E89386DE113C90CC90059BB67CE0FD5730FAABD6969DA490B32AEF157D95A60A4A80EA2455490EC289B35427BDE558BD33CEDBEB6EB7CB5AEEE62AE65D7B4F0A6F916BFBF6C8F1F7EBD95CE3497CE2CDC221E1BEC9BAAB82C59F457F2E28751E6449C82C796CC67ACCE3FF855AD80162035D142B899040A4F5E936578382C9C3544E7EFFA4C654656B76E1E5CB1627ED9DD36BC1044984D3F9232690367EE74A1A2C311C6901BD4D08AEC012AE6AD9EFB148C9A01708BF1AC99AF6819FB42EFC8FA7CB9EE51B748C262EC8657962259E5946EEEDA54723116D1642CE0B3BAD447FD392F69F3B0A95D43D89E83059915775683858D541474884BA21CED8A670EA8173E595DF3F0F1E4C490967BD3AD11384EB58A303547F3E9C5A71D5093BCD2DCCAF66CC73FB8836691A1C8C37DF8B49E91E49ED4DDDE72CF4A70974BD2A05008BEBAB1DC4149F89531249E947F2F6CCCF27FBFAF1DFEFEEB849C7CCF213893F150BF05C247D85D48EC09A2B83FDE501B03CB5953E1A1EBC0BBC558A4CC2874F990AD43BF29A9851A2276C3145B46ACA54B61CB56DE400FAFD44506817FB87BC394A927919B91F15A453F316ADED7647519B2596B5D1E1A509E94EBE4A3039A69FA007FB21E1A0ABA7071109F0EA4D1FDE09068CD5F1065768ED6F307A60CB642A4C76FDD57B257FEA89FFAEB0D7B42F9C2ED03129ACD0AEA9A09234726031363BACDFA4734F3A62D396A24C01579681394F944B809A4A8D7BC85434D8E10D7A58B97314080FAC5CF47D5D930A84AD520A010B22CBE5B5A1625238AAFB0589E29927F347D4828929A34757033CB782E72B022AD7E5DAAE62F3D1A1B5C70151FEF36AF9E291557D8787D18F849EA264BACF418FE8DAB20CBE79805402E0C36291E5681FC1BDA055C594A340044B29D4516CF6E685817914416E3B6911017AA6B47EED9F3692A30D2EFBBA54276208634FBBF295E9ECDD107C43CE63723734C42A0C8B856D9A9DCEC9E9B789C714ECDF55C829551ED4BCD791DD12E2C44F8AF7B6F63A2AE68305B51E23CC003553495756EF1DAA1DEFB5455FA3E38077AB0A8A6EBFD2D0EAC1F8C2C26446EB08ACA24E83CB9BD521E0E9D740F4CB329F854D632941A17580687C94F64AE7A998CA3CA301A4FCBC1F25587DD5FB9FF5F6C6333D26D3B1C70B3CCE2B4F06DEE6F9403E76B82820FA888153F3F9239F84D8869E3017AA72C5187597D4D6D16D1856617495BD293DDE9538B4957FBDDDE79D3942C868AEDF5ECD795E42805C23A7244BAD87AF09D7AF58CFAADEF5DD455A97B047AD8EA4AFA78225C843CAEB4E39150D71341046388361A36F9903F058F02403BAD01476188F9BF5F5793193E46D7161C9E86C114A5177B44BEB3506A381CCD81FC7307E249EE4F1A81A40CF51DDCEF2279236709412C95958603A3D4A855263BC69741D3D033D3B036A792000B8527E2C32EF015B5C43FD0DD715C464B7B712C7DD12E859A1C51454FB6D29A99958A00DBC11079641185025871F65ED78C65BB3566823A57A247A7DDABC5FEF1A43747E75B6A8A6AF7C76C4B2C2D2926F26EC351176532134FA93979689CB94B8610B33AAE777B21DA503D9F15EE2A741E81EA3C02ACDA3F043497B23110015B0E21C41C79EE787BF2A176C62793FD617FC45AE7B27C48D935733579DFC9F0CA4FE290F42A0DFA30096E4A61361418713636336CB61AA991D8EAE606B9FE9C28B0AC774502093771C92ADE4331E7A3215BC442A89584133538FF1B3F27F4770AD221B0899DD26F2DFFC2A28C3B655FF147C4AAF4BBF3932C98410C03EEF84AD5B3D3710F371A84885515A9D3E287F9D29F29F76249824EDF8E83F05BC66B3F0777CCD867F450BA2C3F229FA649BF4A11483963C400E78C30849281B32A29C2E9D5A25B15AE92DE4F6FCB2227E2A895CF39DF138C087B079040A7E262CE06021660B6D1A7633462B65B145434C4644EDCFCB1794B1635E15A9ACBD407AF7B8068C80CC72CD6ED6C047C5D30F326D2CCDB5905661D8DB7002AD5760D98605B06E094EB6BB89D22060E4574CEB904ED33C8FFF8ADA91563DB110B9C5760E0D3A42156505E3A66133D37FF57D718E94725E743449967AD5DCB31105AAC01CBA62E71D0AC62B48FF861EBBB76A9BD8BC328C4776F1C9B3A3D74F9842D2A0C663C6C592865483CE470584AE3ADAC37B30DA54D32E88A5B8992379237692F61CE55847E095094257AEBE00617D2B88D913D467787DDD97EB211D0962EB5057A41F67B8D282D2D627880D247078343B6D9A901FA23B8DAF17B05CCF87FFEF7C5E665C421562B646310E3FE070A92762ECD19BC84B30A57891C8A11226134E37A880C60A2BE2260AE459EE940B9D2E6E98F9D2B65417212DB0E3B04CB194101DCFF847EFD31D46FAAB90E3F152017D049A42893C4087D3815FA8593831D9495039C0D403453E8B7BA2D80AB3333FCBAF76BBB27F1AE3DD3824B6803AB40EC8C25793C7913D69BF5BB70D99687D105E2FDCB9C17626CA3555E3ABEE9EBE50B7941F486B9F783A720D0C56C80D4A74BB0458605E0A4D42AB8D5E61AD918B10AD6645F55934B4CEB79237B479C002380B7EE0DA365E02AD56CC9CDE41069CE081EBB951B7551B865F99A8BBC288C8DB8B26663EA0A0EA5F6398AE8C97D67DB10557329E06A070A6535A8AACA546EADDF3B1532A906E3FD10169FE1EB68EEE791BE7A67B463AD4DAA5BFDB56164DAA1CBDC088D6835320A727519CACA251FFD47C0180BD907F87C8EC7874D082E9CAB3BFE150E5F617F5C8C70F43F4AE283843C006EA14CCEC7C4E48CFEA0AEE40144D96D8ECC10119DE541BC7F6912B932AC44031108C0FA5F6D36512AD362DEADA86FB065DC54B6742A6288608F4F5EB22A59525CABD2F883DE0D2095BEE6C983620ED6FA615355578D8EE6A6389ACF1ED79EFF790F8102D6762C86CE3320B5449904FD81786450D703FACF1CEB524B443E02BE20E74F73E00B008335CC87246CD8A20C339C4EA5734E287615B2E6EA24E042903062955D49901D7678E01B0A7CD66343484518A7EF5D4AD1BED95E2E25155F5489F7F3094345C3A27FD72C92321EF93F4EA2A1DEC89BA0D217C39E7032EE516381C78085E25AFF038275271731B89F9FDF1FDF8273808BEE5620F180A653709186C9116B9E745CF4A29E5C537488A15F24FE90120ECEEF003C922EC1687F5D2F04969168A733016BC2EBDFD5243779CE7F925CA7C25D82B8D9102F0C469A8C23412D4FDEF739B8F0FD254F23EF1ADC04186042D623B56CA613D88F9603F525275FBC93F7E79BD745DA6BAA9D0D5FC8BE342AF4E658B5FF8BC0A8CA1EAA21ED07FF27C43286E51C7C89FDFCB80BCE98B410D062D8013FCFA9BC08363FD1B89AB97EA39DE59B96374F0E775D5BB94780F210160ED9BE1405C0581A767EAFDDABD062433A6730B218799913CA89E274EF7587432EBAAAC0FA699DDD8D8020B9A030CC8CF8760D18C15DFD9440AA497CDEE32A00F66BAEF025A148D0CA53249859DF739ABD557C79686F81D1BD15804F1F20FEAA561FC23481DC66572D3C4D6E38653A6037AFBF8967B19887E9DD331021F9B0A9557A423A1D3E18E0EE244B2B21139857DB1F1870617442A4863A4AA3A85636348BA319BD230043F897DE9B42656C66D644DB3401E14048E0389DB3E2F3743797EE17A07DF9DB34DADB1FD983D9FF3F19D4745ECD2134534A5B3885854C600522A603544ECCE8DC69A65A26C167C406385D990E7F156A75BAC35521C155AE8E7B19B6DDD6ABF14DEB98F526C70E91E397324D27B252850C3B8D9A8A77C71B14F7CBABA7B0E72F8C6C4C22E72044AEAC32728A8E0886DB2894AAA1481166D6247CE02EFB63E932AF02C0BB652F9EEBF7DFED58043C8C0C71F082130646E77B0676FE6A4015B2494840DB8B47CB75F8F5BEA969230DD1E7EFD4BD0BE0D52B681B45B5EF3134ABE12CA410C46101C4A57A891E479C7D57F8A5167A6B58A76872147270021686C6C013C83C7FFD0C86EE0F189056B6E3CC9DEDBC4A1BB93F89853C9DB0EE90C28EF4C35D34D440D8FA988F8C5C401611BB30A6D2145A3BAB07D43EB742605C975D4C899C9358AFF75C14C1B18B2DE2496E2AE17F48BEAD34B81756609589959A3CF72E0FB67A7E6380AE75FF98891FDAF1F548187EDC4F9F9F54E37B024F61D37F277593FED392F4AB7EFF9A48AD9C2EF77C6EA0417D1B60A88E7061970260314CA28070148CDB1E63546D00DCB457F1B8B48385E0C191020B15EB6F62305DA81DCE4DA52C2B1A6BA0503DED0F1B83F3377FA9E27EDA508B107E64FEA16BBB32F6C4E30E67B1C48C9A18E59083A4F2F092F738E3877A29427DC295AEC61BCA34940AF64B38748C85BA1C4866F5C0076B8C746CA933D8AA7C9AA090A51C16C67E4EB0FB78AEA7B81E6BB2286B32C34CBDBA292152AF2001BC607AB097E3E769A456C91845C48EBDE5BB4E3E81AF3F49D753D3EAF3F473CE2DAF3E1834F6203A8349841468AA07F82C6B3C9661E1800C2030D8430FFC75AFE2FAEA96857588EE9B13BA372A2BE02C4CDABE87B7DD6D4C2F32F8041EDD2A87D3D4326DC07172B6E24EFB4E2648E1F54FABF7353EEEF8048D9E66537C84CFBDE8336456F8726CDB6807A469E21F25E65003B472E6F548E5DC2DE0210A1E395D7E3D66F3E38BFCDD3F1BCC36498F226E79800379D05DD7F2EA7F79CB924AD149CE46EAA4B83103C407D733CA29119B4D0A72A88A1BC08D216574086412314AF44A836802A47DB5477D3E71F9290CC9D8E32BC020A2462E0DB9C93E44299EB2D58C3E7FA5A999A98CBC600DDC4E93F758AB2F80E6712A5203555B48DB3F711EDE8C9C6DEB8D232F4A823364413951BF25D1E599F91ECB6461EB7C504D50CD4D4B422E4FB2260CCB87FF35633EC611CA039B220959D724BFC1370BFF10D3E1F9B5E518FE0A020DFFC51A11FAE867269BDAB14CB22DC3F4731D6F8E7A1B0DBBB41D3CAE58AD12BF018E23443FC52AD759116F245E862FCBF1F0A5E19B7392E3B75F5DDCACB9CDEDC7F24B230A7FB5ADF2983569ACE85C2EED70BD680831248DFC408CE0684E2A9F43815D6C3A0CC1713AF7EE033E2937CF022EEE3CFB65E596CEBD27CAF2D545A46D95252A8AEFF3E1AE4B2D1043204FD208BCDD395FEEA4DE9BC79E7DE4F77F64B24995A9030C44133B0C8DAF37D553AD6E54C135F80B447EF0478EC35176FCB7CCC95DF98AA5CFFB78C9FD5260F4A7C673F00F9036496CA60417B8BC7E81C1C50FD6E26D775922C884C5BD2E0EF11EFC9FC85060666C80825CB7F473ED137DF60738438A11394E1ACE460B708C3D9812F9BC1CB531605EA3556010C065AEDA7147C627D5AE93EA657A35921F6110F61F1FE17A30F7C8C5A6D99F34B1288EB41F6C9A28C516C26465D2B63AFBCE3E414569F1A08333A97A7F0080FB0E5F383DEC8073B3C7E730095C7D155E408DCAD89B5EEF4837ED31EBC21FA8C596C7550599794E7A5A8A7A5D38E744061E4B39F235A760B070F005FE4F88F1A73E6B7395280FC4C73E507E10E3910F4FA82BCD77E6B68FEE66A495A973502AD299D31ECD74AFDD0E8671B3E52850CCDEE1B55523BA79C088DB842E837A1B53EE25AC76107341DBF94DBFF17403AAC616D7B6C8BEFA06171F1296F2F0805A936A1DC5BF7CD9BC6B9FDA5BD6FB884B8530BE17ABC35395F31E9456FEDD4EEB79F32B86573DEB493D1B4B28E49E301B97C610C23268AED01788D2A0E883BD8E50EEE2E3D001F4474574DA8F772AB154EE78BE37CC8CB810445A6FCE6B4B61BA5DBDD7F5BC4D4B96D2C97CBD8E1F58EDD77DB26FC486C1C436D29F759226DCFA132031BA52BB97A12D2865020FFB82240282F7ED98F2F5D7FB13BFEAAED503ACEC82AA6DED9D9A1BE511419B20BEB43B4F7A730F2FEE61212A5ABE3EFCADF25824B9168D50143764E8DB0787B05AB63C5F849A3362F47DFE21894292DF5B1F381EE87667A827EA3A420E2753E6D970CFA381DF7812BEF6303C176BC7D1A4858CBCCF69C7E44E9438995FF153CC2917481973EE5D7BA6255FF2452B90BB23689D899B97166FA8EB55EDA7DEB2CDA263120022AD5EB5271015AA0AD59E23037C76F753CA319200D97087996FD4C7729150E11890997509E8618A816C64D34C31EA2B68BB7AD7328000493CD71BB83B4D387884BC0B73E300ED6B69A71093749D3A6885A95FB61778AF978F4F3832CCA84E3333EB4E9026764867CE0F6D8B706CD59F9CB33292EE82610B0D73E393C8BA9EC058DC60884EAA420F61F8E7070A2427237999951876BC45B18A4282B293B49F1470AD32930C4D50F2712330F59A5A01E84CC0192F2486499C96AEFD0C278F7CAD59D3975DF193172C48A3A7538B50172F419966D29A70EFEA6396FC5E4F44CAE1A7839CC7C2A3F7B8A8EDE680DEF6104697CECA8D28A912E8E3ADFA5B97B9DC04D9C6AC08B3506D9DA2AE2AAD896E0B6C85B6C781793CB8FD71B3E315A99B21EF10E1A71849089346602DEB7A7F645F75A18DD6E0F25B8A9D0DAE97FF6C57F3078D3A9CA8C7F3237C2280204C513E7E0C546D731CC540FDB5570A0B9B7193DA0839E4EC44C8B7AEAE6959BE723A3E4BCF2F8AAAFFE3D6414D3DE750BCE8880B8FA617136D513A449DBFC5B26C828B7B18BE3C6BE6E8DA2462A29F07E066F1C6E14D2ECC222BDE7DF5460D401E24D5CBB26C37FEAC1C24A6CBF2B0CAB1336337CDFFD11E53BE58EDDFBE76A0DB9A063ECDD455742EF31AC52888012F7A14CBC2E2D5721F52B678F3134A1EEDA684CA30EC72FDDDDDEF09D9E50CF5CABD2973CBF2B4BD0628E7EB165B6261E3D52C1EA4BED0430816EDE4F3CB983A46C0AD35EAD652FBF2C6C4080586E6817B8D2504B8ED510CEDE56BB404CFC93A8FADA456AE2D760D82312CDDFAC83E81306B6865A69481596FA147046B9DF622FD897857E290D34E17188287C1731224A7EA8498676393FA2B4BE60DE572A1E43B09E0704FE69EA0981A4E8E12FA98FB8E225C81195DBB99F57E2C97A9C669A4769D4CB792A1D5C14BE4004C1505E831B2EA7EC21520CBDD4E477BD1B907F6D1B1AA1774AEE169EC4D9B35355C6E84EF95FBE4BE47A68E56D26E694B26030743ED2F9B6AEE7383D18192747AEA9581DFC38B3CBE2238890A1BC1A240771DC54993F2482DD219012177123CB531146B3CEC89879BC74820B4A5914F2DD0435964CC2AE7F84D540CAA891A4610FBD4D807556653ED9529824AD1938741C9D45134B9D8E9062C73EE987DDD11AD0210B8D1B948D76AEF6BCEA2A89D27BACCCBE0B5C9115723EAD1DAE277BB70B818D448C0DAB68881FCE6454D09475D8F4C34CBB1FC5CE4F0B995E6E76DF5F233FB168AD45466DF16435FB8E2CC0A19A3734A9543F0BFBBBBEF580645CFA01307F41151F3BC893BE554B56E9CA40223AF7B4374225FAE433B5ACEE4FC609A46A24CB1EEBAB826E6EA0FB0EF3B501F17ED3456CA8C2CF0A745CD1698EDA43E84BA6ECC4FF31368F7545C8A13AEBF08EB3BB7F7C709CFB9755C09A9EDA28DF845D12C34CC84CF23D9CC5F7530A2DDF885C52B5C36AD777BEAB456F3E96A7B55C6634442828B3B666C931DFBAA5989D37F1023277731C29759B04A18"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY('max')), + "åüäããvzr~ã©U©ÐßäbBÃ~zh¢CßÜ@©£ßöO/ð~A@v<,Öý+u¢ª~zÐ~ö/|ÐßÐ ÖAbÖ£|Ü", + "ÖoÜ ß¢Zã Ü.>rrröbä@ªÃBäÄÜU.£C/ªzhßãoüUhßvî<öðUãã_Ä>ð+åC£Zb||r£ÄîOB+,+býßÄÄ ß¢ðß@,~B.ð©ðUÃräåÃ~ª¢O~Ößå/<>ÐÃr©|zA+Zbo¢|zü>oCÃOOBChBÄ¢Aoü£üB~©Uª£.ýbä¢v©ÖÐz £|b~äÃýrz,r@ü¢ÐAî/ a©<<ÄC£Ö.îzåußvA©,©ãÃOzzUr:BuåuÖ .Z£oB*:uð~za@", + "ß*b *.Ðýrðvaãr", + "ã+zÐ: _ B:î.Að//oBÖ >ß*ßÖbCA:,Ãbý.~z~Ö_<ßÖuå>züv<ãäÖ/+.bA<ý,u>åÄÜß/ª*hä,_Z@Ö|:z/Bä|ª@ö£ªa_vCÜoUzä@CÃå*ð*ý:rhã©<~o_Z+övOßOߪßäЪ,buåb*¢|Ððr¢bÖ>Ö bÃöuäå+~ Z>bÖCýßÄ,rð.h|¢:.U :£örußa<, :_¢aUðhvðÄCÄ+hrÃO @ß >@.,öТ<*bfv", + "öß.bäCBb.¢Ã||/ß_Uåobö©vÜß_ÃðCªC___Ã> ©UÃvA:aOÖ+:UÐO,üäbv@¢Uz/oöß@hAaÐzr~£<ßîrvªbouÃ,.Ä~©AÄ*Äð@ªÖ>bobvAror:_,ß_*_z @OÄu©ß|Ü| ß>ÖäßöBª +Ä£rÜb£_U©<+ß.ªa/bv, <><ä*Äé~ä:ÐröªäüðoAZ BböýBoä,îßuaåuO /*üä", + "£~*åðAð@zu<>>*ßß.C|UãvÜ©ÄA@~rrð_O+ä_zvOÖr£bUAÃ~@ÖOßÜ¢Ãö¢B,BãhUߢ¢ýÖv+:ý:bîZOu_£a/aãA+hî>.U:ðo*ªüã.ªAö oZr*ÄÐ,Ü._ÐB,h.ÜUUÄovãv~Zoüß/£ª.|uZªhhaBßÜOA¢BCÄãå,hh/BoOÐbU<£+BßCî¢>å*Uª <£UürAvCÜÜuZ/ßO/ü.öã CßöãüubOÜ@h@ßü/ðu_aü+åªä>ÃC:bîözÜa*ãZCUßröýUbÖ¢ãÐ@ÖäöåüUrb vB¢Cä|ãÖߪª¢BzOÜ/å*ßÖbZÄ_oB*åAC£ußüÄ~ßhÃuýßuhî£|ÖB_*ãZ|rßð|Ã<<äÖ<ö,z Ü", + null, + "1987-09-16 09:14:00", + "1973-01-31", + "23:59:29.04987", + "2002-01-31 23:59:59.04987+08:00", + "2002-01-31 23:59:59.04987", + array("0.2465", null, null, SQLSRV_SQLTYPE_DECIMAL(28,4)), + array("0.5450", null, null, SQLSRV_SQLTYPE_NUMERIC(32,4)), + 1, + 0, + -1475161617, + 928353811, + null, + 255, + 1, + array(("007AA6514374FF12EE7B84A3C5CEB1A3C6BB4A00DA497372E074A6BBA2"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(384)), + array(("B86B8689AB16C42D2078638345494012C6C8CBEC1FCFD2660F4AC21EB529A29BBEC712880C4948EC2B67471744D30C0BB0454CB45710C3E8981F796053A678F7D5C7C57D37B7067D80DFC1B788BB223C3EB66D70DCED44AE0429F0ECCFE79884EF4F417C0E8ED4F83ECF34784E0B60DCFC3C229D39071AE78317790EC719AD98463DC83879A62EAFE174310DB9CC5FF8C813F093C4FA4BE7345AF8F714C63124229B3111432863550E73BBC4D60D2EB7B78145B4291AD44B9B83FB966"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(384)), + "åüäããvzr~ã©U©ÐßäbBÃ~zh¢CßÜ@©£ßöO/ð~A@v<,Öý+u¢ª~zÐ~ö/|ÐßÐ ÖAbÖ£|ÜÖoÜ ß¢Zã Ü.>rrröbä@ªÃBäÄÜU.£C/ªzhßãoüUhßvî<öðUãã_Ä>ð+åC£Zb||r£ÄîOB+,+býßÄÄ ß¢ðß@,~B.ð©ðUÃräåÃ~ª¢O~Ößå/<>ÐÃr©|zA+Zbo¢|zü>oCÃOOBChBÄ¢Aoü£üB~©Uª£.ýbä¢v©ÖÐz £|b~äÃýrz,r@ü¢ÐAî/ a©<<ÄC£Ö.îzåußvA©,©ãÃOzzUr:BuåuÖ .Z£oB*:uð~za@ýÄĪb¢u~¢ã+oU@£_@@©__ß>¢ä~bu¢Ö~aZÄrÐ,¢ãª_Öß:Zýãßß©.b¢<ürubÐ<~aüåU*å@zîoîÃbaßaA äÐ", + "ÖoÜ ß¢Zã Ü.>rrröbä@ªÃBäÄÜU.£C/ªzhßãoüUhßvî<öðUãã_Ä>ð+åC£Zb||r£ÄîOB+,+býßÄÄ ß¢ðß@,~B.ð©ðUÃräåÃ~ª¢O~Ößå/<>ÐÃr©|zA+Zbo¢|zü>oCÃOOBChBÄ¢Aoü£üB~©Uª£.ýbä¢v©ÖÐz £|b~äÃýrz,r@ü¢ÐAî/ a©<<ÄC£Ö.îzåußvA©,©ãÃOzzUr:BuåuÖ .Z£oB*:uð~za@ýÄĪb¢u~¢ã+oU@£_@@©__ß>¢ä~bu¢Ö~aZÄrÐ,¢ãª_Öß:Zýãßß©.b¢<ürubÐ<~aüåU*å@zîoîÃbaßaA äÐu,ö*@,ßÐa@zî*a_ÜðuðCz@î>>,_:OOOÖäÖ*ªa@Äübßz,äa b:ABß,Ö.Ä>:ãhã*|ß*_Aª©ðÖ,>üb@r>£", + "ã+zÐ: _ B:î.Að//oBÖ >ß*ßÖbCA:,Ãbý.~z~Ö_<ßÖuå>züv<ãäÖ/+.bA<ý,u>åÄÜß/ª*hä,_Z@Ö|:z/Bä|ª@ö£ªa_vCÜoUzä@CÃå*ð*ý:rhã©<~o_Z+övOßOߪßäЪ,buåb*¢|Ððr¢bÖ>Ö bÃöuäå+~ Z>bÖCýßÄ,rð.h|¢:.U :£örußa<, :_¢aUðhvðÄCÄ+hrÃO @ß >@.,öТ<*bîv", + "öß.bäCBb.¢Ã||/ß_Uåobö©vÜß_ÃðCªC___Ã> ©UÃvA:aOÖ+:UÐO,üäbv@¢Uz/oöß@hAaÐzr~£<ßîrvªbouÃ,.Ä~©AÄ*Äð@ªÖ>bobvAror:_,ß_*_z @OÄu©ß|Ü| ß>ÖäßöBª +Ä£rÜb£_U©<+ß.ªa/bv, <><ä*Äé~ä:ÐröªäüðoAZ BböýBoä,îßuaåuO /*üä©ßA£ª<ýo:CC*Ao..î+ª_ßOü£>rb,©¢>ßb/£Zbz+¢oÄðÜÄäüÄß", + "23:59:29.0498764", + "2002-01-31 23:59:59.0498764+08:00", + "2002-01-31 23:59:59.0498764", + array("0.2465", null, null, SQLSRV_SQLTYPE_DECIMAL(32,4)), + array("0.5450", null, null, SQLSRV_SQLTYPE_NUMERIC(36,4)), + ); +// 10 +$values[] = array(array(("3BA705746D92126ECD1A9B2D0866DA482936609B39730EBCA6B0055B6213FA9AB2E794FF914A0645D02EEC51D4A04007592B44"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(256)), + array(("D7C89948CDBC8CB70CBA20007A21D1DAB6DF301ACB0B87BC"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(256)), + array(("70FE0136CEC23F1A10CC66487D49B819223231D3251F357E74650741CCCB40DC60C64C8EB5D5EB5DC1601105746E61E661B2E9558A14E150C882C169BBFE4E448B89E8B7FD2A634C46D411C40D2F0A060320DF1AE2EB524BE4FBC6331381A1C212CD7AEA86AAE8364E9C0EB6031D439877BA669B1E33619F379CD302643038C5324EB240B520805837A9CB45DD9B48C7B82DBB581A06A4DE6BDAB2E9D7E6D21E644883B46A02E2573A0E6475671CC29B530B4A3675DFAB2CAAD4D5DB6D968050D6ADE19418945CB54A631E0CA12E764E171795CB9B9BA8849D5709952C07EAA38D139FBA3B2E83BFAE94EC11C19F8A7B5D86C35601B4B43A045CF6C18AC78842797B7E8E8FBC13E993D61C07AF97C3FECC8E38A64393A2D85E64B5DE37C235E70BA9974520FBEBA073DAC32B98AD8A6D99F8F4FC8FE2FFE6D9A5302B0734B1D0A034FB06FF7DDDD0A2973269D07640B0D948453FCD385829AAB16C7BCBC0993E29F28A63B2846D1B1A245AF7AF951562658051BFEF720367DCD25C4D106205E1FDF440DEECDDFE55DA2924A9DE6079149C0A154A6FDA4FB6EF2286E0281F0BB81F79F9BB5536768882FCE4C64D59897B5948B1064CBA7223A489EFC9561D2DBB1E6C8A6566BDBE65948DC872F5896995990B87DF6D046B6407D616CC47AC3164CF29A7E1CF23149B894C72BFF1FF2E1B2059304A964D4D1900255E90A6F11DE75C64A3CCE187C575F7EB552192AC7207A8FBACED7BE7CD82DC8EE1A9C583F5982E8A638D5B613A9893BB53ABF72B8654B256E8AB442F6B749621F052A51BAF73F6BDF20849E5AC46C0135AC093218BB0088DF76F9B4A53FE1EEEF63A71E7F3770BE0B539387E0ACDAAA1EA31D5ABE175963F4A182440D7AC69F3E95BEE71D4D920E2B5B36C51778A8229C4F95F2229730C81A4319DDA53CA0809D04494AFDF39CD1110F3F52D0845C8BF96FA7CDE4C47CA764E6CCDA33B468EEAAB638132F6D24A8B2C4E11357DDE795F69DE43584E29BC887A1D61726B2AD5CA640B82A5C395C9C4B0F0B2FD3594F96FF36D395D03369C81A6F8B8D871D81F027847D1725CD39BD3147EA75D77BF52E524F17EFEF078C62D6E00FFCBDDF053D8D1AF84EEC3861320D26648848E3E0AE6A5D2B47F592111FF80A3035BD4D0F5232BCF8CC73A64219DDD5E2C8930429F30F618250B3CD37EB09D856D2083B84B01712458BEB242AC41B017A2FBF488CF3D03D364BBAAEAE75751DC29B5F6011925122A180BE9E07EB46BE45A243183BB15B52F1CB0539057863D016DD518F74AAFFD7CE8CA6FC4542354B050C68FC326CE2114FFC6E569D182D392CDE872A89B7399AB26B49AF0A6F1DBF85BA33F90F67ADB9FB404F783CA94AB66F7DDF66BB0AC14DC2CE49C7133306D0EEBEC0D2D42429B530DD3F3977C16E1910934F9C9FA7048AE8F636312DD696C8497E998DD867D23B441A35DDDB97C6016030A67FE37A3147AA45F9DDFDE8975A3676F00927D030B8B11448857126AF512034D0ED3026D4CF3D51D3927E044D5B82DBA75497CCD98FFFFDCEDF21BBC6839698ADC917AA2A1F9220CBD60CAE3ABCC6ECF2A57F4AB9635B40ED3258059D818B400BD5568433D8A197C276F1038351B3020844B921144BEF4A6DD6BCE7B79C834A4ABCA2656642A919F3E788427257BD9B8F45FD58C85A3BBFF60C166D2BB9D025F3A6B8C6BF4DABC59BAF3D2CB3ACC81619216861AF2A81E080E27F5A2C4BFE3A17625EDB9EF6DC31AA27CD292D1F0C59440043FA516E86C914C845DCDE51994FA0F315515DFC87225526C7776D68C371E626062C0803D8A8DB85B6C6A10F63489E7D783A09AB0B578911A53AA70F5BBC04D3F6B84B6D379D1A6C75C835B07155B37EE8EFE089683B2ABEA2F66EAE01DC2A0AC1DD08AB0D2135EB1F9D253311C8905F7728267BCB7B6BBB9D8CCA413E7C6AA99E3AEEA44D1861B7AA0569DB15E7ACDA560F26D9A5BE3F46715D1D8066F4ACA3227BA4E6E9FC126EC66EC1C60180A5B5EFEFEB2F559103DFFBA822EFFAE150B568C6A89A32C5F069FCB81346FC7934E0B7679077197D4D8177C4EB41C92273D50E1C5D4AD80B7329FF71229D8DCCE3826332389340E9ABEB8917226DDABE90DA443E38D01BFA08ABE47687984AA003BAE168DE96F9E084247071C1B0E9054F40E058595F84036679398CAEDA621390D913678C71D009E063AA146FAA3847B2DF2746A7F246B426DE02655D6D31B9C25CE0E8AD8188DD60D677F5A57FA3BC30E1D9CFA32B6B9E826F30AE7F6AAC7321F04202C94FAA315659D5C17A511EB73A46347B936206A6F142664E40DA5DF639F4D3A52D90F2F137987949459A2431408974393620EFCFE9AB1186D96BF07BFBDF97758D6989A94333440AE8CD51572E34FDC76624C0091503CB727F7C17DBA80D5D65F2AEA3E6FFCAE5F2ECE4D72C59BA68A46E3905D71F9E6079AE1729D72B6852EB6FEB648F8116C79B4ECD1C303C9F28C513637D7EF78656643E3A48E8A11ED78481FBBC7E55D92357616A885272203D0EFE64B3B7FAE3E3E995004146DDEEFA3FE597BE40E2AA7F3A40160D8CFE03E21E0D39FA4C5B1F899E07C2E95597DC898270586CEA71FC2C43E58977D4E656FB811E334993E4BDD4C60E10391FC11992739C7B1C9597079C111DB656D1A7B4B7B0D758376492E59DC28396DC51B30C72CBE6F4486B3A55EA169738763E67032E5968884878E23DD0A6DD5A12003B3A6E01338AEAA36C4C76716E20DD6A7F6F6B707872F92AB3F9E9B913919DE043E9DB5CDA74FADC187AFD2C11D71AB15076377DFEA197C841335D4991218FCABE962D8455708FFA648F580D85CD18ECEF38589D6A1FE1A252131B9717B14AF6EB227D8BA9966BEFF63D197F498A42742A605A68D8F2609EA48B223254F8D2A3446112535F9D3358CC68A73D067258C7D0977CB756D21DF8C1DED71E64398AFD5A663AD877EF149D3D019C604B339832226A51CD8C2B5C6243299180B614E492EDB9D2A047805FF172EF7A5545BDBD9E46A4FC09D7CD712F19C8854E4D93D7181D09828150F7EAA20A604A9CB0F72C957C033A0128EACB1038B3867EFB01A3EF0862383C3B2C3D4EBA49FF6782D47E12ABFFC24A59C5FF223E6258AD617BB6F8CC5B944EBEE06A5FC5FB46EEEB638D543573C30B4F5985427305FDC8D39FED4E92F69B27402F63CB8572746E7F0046DAE4F467FDA8BBB962D651DBA8E2A17C360E085BF4C8561406000775CCE516C362CF22D3DF37EF95D73D2850FE53BAD8D3F64E5076B442128EE051ED9135FC8DBF8E78D9CFCD9D0E2E6274B79FF515B2553E91C6A6C65CAE8D0044FED5F1F4A140AAA17FDAD11916593032044F9A7289CA9F98629425E6F931DA5CBF78AE282C6DC366E553A5E774158B6D6684485EE28DCB243669821D1AC3A83E0084599DBB1805968C239D3624B8144D08B87064E97B6A21BD79F1B2DBB65C21AB67E6FFCBFDB25E7EB1C2CEF0850F8E55450452434344851A27D0411652BAD5C77B8ACCD124810B0621E637A89B31387A736D96A1F9DE681351D5942D71382BF6FCF7850A32AD20B3F95C215D1CDC8EF6A7C6A2E52423DD9D12A97F4EECED94F9CA40BBA3AC2E37C63CE2A8ADBD0B068556AD85AA8536D2C929E7E7993DE1C71BB72792CC10EB4A799EECB8318B2FE007A2E9F84F67FA64837DE279C436AE985B1B9CE685783A647B530C0BA88E914DFA07DFE643E987A3CCC31F5E3E618632F0545D25EE496A9F68858CEC5BEECBF4ECA48FCC66B8547193E929C268EC3609DCD91B54216B5FB0AD408DBE5C9B57DDF71A7199E1C9DC47FFEB92051F98368C4F830F82D367C37144DF2F162A9614F8814BCB4E7AAC2812FCC35445D94A91051A017ED99BC4FA9F46F04512AAB61D69D6A973C3DCE811A35AEC8610138D97FA3E1A0C29273B5CCC513C077A57157846B5EA7F3FD6CD2821FFCB8EAF4EEA7BC9685AD480B9E4429B4CB772A0E0975C45644F5A291E682370E1DA395BBCBD7D66B04E020C40F79CC197D3E31F5A8741586F393AFF8042AAF027539EDFBAF6EE9F3A0BE0928550047CB298913A7504266A88E0FC73728DD67D9311D4ED68BD16A0F553E54EA6AEC31F34CE4CF7B1707B233D3446D9FA6B2CBC25730F737B17140571E035212EE7B3DA1DDD3EB440EEBC1296A1B024664CA68A37291923AF4F942DAA3775C13B5A0455707CBC2D2C687B46B6ECECD966EF9F3549AAF9F5CE903ADE49110A0968FAE74CAD5AB3F980895DCEBDD27CB262CAB6CAA8308780500E86E041EDD41B6E61DDCC05902C0C3BA5A4B04D3B37FC23886B8E5A3F61287356ECAEC3D3B7A2A542504BF4A0ACD2AEAA9EF28BC73324C69ABCB97255B13F00A558AEB38D4857FE021B0ADAFBF772DB98DFBFA06E9CBC23B7D83916FE204F81213B4F57FE1F216236F489AC2859DA9349EDE976018EA2089C8AFBA50F410FD1CB79B9B0B81ADD79BE4D696A130FFB6E0D95DD0046D98F929936BB73237C52F5F4B7E0BE9029EB2F107FC7B41537F59C9F8DA779740F9AF1FA1717715F6A4641FA73755B2F4CCDE3BAADFFC711DB7D61412ED395C4E981F52CEEB4790279CFA62975B9A1C29A7D52BFC3CEC60FC3E02EA9B6303086A07D00F1703E308854D130DE49AD9C11DB9EA6B180E6012ABBE5590E95DF5C499F2F7908A8A0425C4CDA6AF28DE7C616440CCE17898F05CA6BE6458AD521E27574F74F2A3493692B4C4A74B67B1E9CC42F42BA890144B01019AE9CC26AC7871AE7E57D86A89BE1B0A392CB3F1A5F5F5D49716B9277596430473F00860696C084C359CE85A1162B8350F9E56E7970F5CA5F3F78E96BE4A39E813D4F699B6BBA0CD2367BB090C9AC3355D8317D63F5B6C6393626C72DE728EEB6200463C6B1F7F54FD89C330545399593358383A3362A8B7689205534F2EEEB1D9D0A60B5487CA3E04C3D9B6983C0F3FC9133E853953B8FF578ED4D8192B04CF9A125784AC8D04AC8EFA357089F21F2B83C58A3CEF69788517A7B4C5B2F125D8BE091B85E48A933B0E92F73F1D4876656FA85553A1C8E0319AD16C05D93FF99DD55DB17FD79947F9324E2E5C713867CF304F560A9BD137F629E9EB131E8D62CE985A69C096F68ED5615C20529983BF616A9CD48AE9EF010325BB56EDAE33DAA5EB60C417CEA7393AC180A93FB1E45CA5298AA881B8D8E4A958669ADA9FA0262D817A6739BFA892C3639AC86846C151415FB0C3238B59ED127B1BBE680C5F9A20597BBE367D22E681F8E51E1E0F7B629714597BEFDD03A2278D54BDA3E929B603FFA80ECA021AC33CC9422BA53BCF0300B82753B2E3AB4356D997A929654397CE2E1A1E676C9894F9953E259BD7FCECBD51BDEBC2D603205365B8F16B719AD786AA5C7620B09B931F92591DA586A77EDCAAECD7A757D5F82AFACB01B4A72988FA679EF07B86CC0DB52ACB2F7CE67ACDBD3914C084C32F2FD4644B25E59ADE7869D1223DE7B70356DEDE227D8BA57C447FFE437B92680337376F1B163AA6281A4B53C6ABC43DE50635BEE1A6A0B2A42FE807A6E65663E500CDEA05779BEC1B38B6073137DFD18042183C45D4865D9685CBEC2E33FF41C4E86DC5DDD9376D6B48A3A9EF99816C4F168764CE1A1D11796F5480ACAEBEE738754348CA19F3A70AAAD1FC30DD6EFD045F9D17AC9B73AACA5C4C6E84B7C1BD8ABB707A5638A23523E059234921E09B01567B4D11A63A9D01997D6ECD852253E91371756DF3A7CCBD67F4CC425060A97BB06D2E3C74ABE481D278BCBA33689EBD063A35AF6B2E0DAFAF90A9B26D5BB138D3F21C17F31674678DF49A7BEA1189FF560E3B152BFA0F82607E8CE402311377C784E6414B86CAEFC5CD21779391C49E06AA5C5F1F9B0CD9E29AB7748A90655BE022B3662A48B3CF444C505ED898EECEBAEEDD57D5B3582C770C5EB0CE55653467C69671DE5E73BEF68C1AD34AAE014AACE9BA9BB30E852CCA87EE1DE90300EFE71BF611017DEF5C7A1E60499984E1C90B1304E59AC981594069A6566F56D4F38B2BEC2EB8F0482FF95E2194AD3C9345A62512D6FE1B541D9A9CD198D699EC24496CBD6E98B2111ACAD4EB3CA8ECAC04D661B04944FEF46FD6CE931B1FB0596071FC4B407E25ACF414F70B29301875AEF0CCC274E8A3E04B774E97CA1EF5FB1A7B8ACAABA06B85B0B4BC344CF3CB3FBD58E52A52EEE477CE1C00C8308DE1D51EFBF1ADA54ECA0D854711C02C6E9357AC0EDA7239CBA92C9713FC8EA0A25523D2E61651011D996F8DD7A50ADC244B6089A81C21B36F9C5351C51692513C6DE2F2EEED465841568F756AE561259E4F73C89B04F786336F634AC2FF3C06061D5069C218EE36040848528CAB49893A2DB275A3CAB638755BBE7E89FB954119886E4C94F76386603CC393BBA5FA8726DA0F954CC7633C6717F467596FAD08720639033DFCF443CA2C156607227CCF613757AEEC00F4522532E47D03FB2CF08EBA20B56CF64A2AE5CBCA20B1FC34459B24052217FE1C7211E7DE0B177740CE0024D84D01C7636BEC2DC92135D4A028FD9FE1DEF609D88F9EAEA385173F126E8BFC208D24E744D4C19A36EA35FA3D3D46B60D779661D8F64B48AF5323DE53AD1A5B9539B41303155B0D1D5BD3EE5AA371663E61319AD829232941DC38F1B1E24788CFDA64038833B2F71C88447C235DED0BE1BCA0F17B80826C158BD126DD6A5B3A144A1F7F3E6DDE0AAE397E4FE5A705E3EE2C0FF442550C4F57F8EEFD628C1AB22D0968D83E6DCD74DE9643420133866E85ED37B05B67F8BE3DD028457FE0A7221ECC22DB3E2DA5815F9A16AC12CA4D23717F7874546A57C511A99B6E4587F5FDEE20233511AA2F5848B651C0504CAC728204D4FF6833CEB4755CCA9591373BD7A419BEF2A71812C64F202C9D189675C5FD28EB40B3F694BA516EC0B5E09AC6107B791B378DBACA6AF20DB04807319BDEE60598694BFB24AE8403A039575CE6B4591C229F7A3E37425D814DA5454CB320D2E1CEDA025DC47F546DB28A1A91129627FBEEEA0FFC64A7CE550BCAAD7F68374F7F66758D0CB2FC57A24B0D8BAD28CC6EB77E4A5EC811D67D270BAD52FAD2D5047B3A9A2B9C081A48F2936DB0571B212C3F5BF5011ED9876E8FF8660005AA5DCF760810728EA0D1AF63016B35A325260BEA80129EDCD4E6A1B22B9BA4A11A4348369D3A4E0BAE9D9E89469D1C6D52CA69D15B168497BEF3A2226FC063052D0D48BE23FE06EBD7003BE374159636CA33606031D34604BFB078AA982C9BEE3A985C38545D4A53C47EF95BDAA123A95C6B573B5F02D45AC744FE73865C52AB644CA8DBB85EE16CE90C9CB2D9EA291E8DCE4D2CD45F8F38C40270105FD7CD672B4EF78DF847F0FE8AEB5252652180DD1AE0E5B70E25D604BD7016B6EDD10D123F34868BF39C2545DE4FA2E90D3CD2A38193F57EF115590677F2CF88303910B9DD4013309AF5E97EBB9FD9BF82EDF6819D73355ADB8F2029DB801300CC9C14A43EE90BCD28A1088BA977C2513B9A838AFB4DEBBD04B6DD4E20E95519E1E9B21F8B358099E12959FB6AAAB064CCCEEE41FD89047EB0579F870BBDAD3E4CEFA9BFC4A3C60519EAA9D2F4F0525A05798251FB141C58E5346E3396F88D247C1AAE7B00F19F2908E82713E03289C0054581923A5B4338D250DA9034936F205C8455DA41D65914D9594913EC0878B2AAAE2D5077FAE921D776A8AF160EF4747806B65BDCAF7E2EEB6DB8E1122F4BCAD827E685651EA9619B3403CB2DA9FECB64D49AE6521CD6FB30FE650942070EA72ADED7EE286E0F595D54C0A8ABB200426FED7D3E956577BB51EA5566B99F1F93265CA04FD20FA2F5C44189FD5C2D4F7DFE229A558ACF12C5661B9D3D19A89FBD352C824F12B1705F4B877953DC7A5E249BD8689705CA08564ADBE8B67264DC1CA1CBC830AB006B4CB23A090355BEE8ECBC78A2404008B76A232B0536C8B9EDE6AB5DB210B12E799A6D1BE4CAC005008BF3FCF9F9C19BDC98145D0C7FFB3483F84C2358F80BD83A8EFF07D32424EDAA1E2B7943CCBFF4240F8119FC5322FA9F3897EB7D9DAD087F1AC16BF9BAC7B77427B3EE5382F1B73958FE4876F2DBE76B05679B8C386F0C7023F9280B54FB6A48C9A5D59F33A61D46E0B2259E65918D3FD9FFF3522B2B3BB8A67D3088C9ACE55C93FFAD4C0647375F4A55AB86496E0B926BE9315407181C9D691DF9B676947D34CDC90A65E3403892C79407D67FB56E38729D1DDF7A90547BE20FE3E94D81E8B5D777B87F63A5AE2AB09E8C7310461EB4AEC044D8779DB93C748F82D45D4F4446AB52FE08FCEFD4CCEFF22FDC04E16A9CF12E3B8D3D103E3ABD7C0BD423DACD615945C7BE4716B7BFEC77E9846EDD379224E5E32E14B7089B13C44A80E300A91425CE82BF1AAC55DB777CA0C526BACCE04479AF3DF69E4CA23C2BAA82CB36DBEBCED45F9F5B7878788F08B69816437559F86A3C6A506B1E8681DF82EE01D30F40A0B4F7515A2C84CB0036ADEEE8B48BF9B6518961FA719B62B6D81D7BF68977BCF875F8614B23FECCE5716919BE2F9ECD548837B04AAD462E19949B820E08D477BFF0F572BC29AE9352BC7C880881A3873A50276E52C6724B2EC948B7887CBDDC9CF259CD392C102ADAA45E8D31BD2598F01348BDE16624F87EAA43F2E1F70AD5FE9FEC1627D64D0D40FD94AE68E41970A4AFC6743400FB35CD604E8EE91D49E399888E91D10E701AC53A7DE4D276909A90D24E313096A1FEA4B749C687BE2422B3B114E056889F953FABAEFA83176356D0B4FE16CF17B202E790ED19C5AA9206155A302061B0440832B8F284E7A67B8D53F2F5D2C00E539CFF11F8C69B86D09419A7E528E742F52070F5E416252D1B40145FC6D2B4BF45060794214FB77E6DACE85D6B40C152A610FDD562CB293D76D1F6B7B13BBFFDE05961DE215221A568F287372DC7C1DB7FC1B9B5D5DE5D7ADCCA1D505800CC32ECEB7D12DEE23153EF576D6F43F20FAF0F1B37EF810A2701FCE7015735D04C6725554B4149AFFC9D9066C57E71ED36EABA6E403CC8DDB1E1C47C16F6E1DA1D1F0A0549EEA6CD655F1F9A5F1A45A88F0EB0169CC790109F48A3697DCD9905BBB548A5746CA34743EC08E01D2E7D969B1BEC0746CA3E568FFA66014A3D5097C619DEA9D19F34236A69D2AFBEAFF271CA0DCD61E091BFF177F2167905A2FC069C711A044FD3C4FBE6C89CDCF78E97E008F5363D6FEEB63459ED32DE89BA1EC86CCC134D94ED22F749D17B18F4E3F9E85B3671106CBF97AEBAE6AA61A1E5722BAAD4702B7B4A4B1AD23FF49D739E3F76F4498352480D5CAD346592AE42C055635F4F6D2072CD6D11EA573D2DCBF93A1BA6346C57621FE39D78C3F716B79DD712E9903E24311F0326DC7267F1CF2FE13A2A76070E54FD013F6CCFA7AFD657594D802B433ABB16EA8730457BEFB8F1CD49E1BCEB4095C9BDEB8FFEB76177535084181A71A3EBA77F138C80DD0E8211877A025ECE1A6B18B8B66D58AABC5E880FDDF5F7D69E80295E393CD8B414EBAF697E773D5F198535180061BA3693FDC2B4037100188A3AE9FAD80095DD9364A3CBBEEE2B452129F558BFDED63CC6F3CA3C7A23B0A3EB96DE438E438719EF58849CBEEF77A4D17C93DA7BA759AC64AD33E435586270B3FFDF2710E8B7DEA1DC68675A3A7DD67B256BFD90D627433D32DFE10FA2E396F514E8BE0F5094E9C5B4389F3FF151292F5D680FED64E0DDD89BEADD08D6CEFFF8D1714551BEC72B918138DB9D88044BE0B5B1B239D4A990340BE67465B7E0EFE639A66E800CD770963C7E6B2C043F50979EFC52241CC52428E01146D852C6D9A148F564E196CAD4DE401CFC553D642FCC96DDC7BA8DCBC97382459FFA91974376A4CAE30FDA6E01D32874E300C8CEEB7CE27A4275FE1F137D2BF05E502BDA4CA9D886B0728020F127DCF39119E7C8ABB35A23181655CD7785B766E3E910B0A84E273A27421E78FCC1881B990B8DFA956245ABF507C136530B0E2BBB193C07172B4A43F1ADA16995E227568D3A336CF7BCD080A465BAA08CF1E61C34F2BCE28581046EC04908E8C1DC1513E06BA819D7A134FE48BB63B170A9B700C68434A22545D10C35C5ABADB4E8BEC74FA7C02048CD4592BEBE99C91D52FD169208213DA773EE9B9A9CE311F5864A5FFD9C62C9E996B7F93FA2E366AB07EFE3C8951BABC7811FDCB82586ACE9339C387339CC81EF332DFB5127FD058F87EF92AC0049606A9E987B7C8610C3100A100B06ABF3723B6EF39467205AA0831A4C3136F300E9EA3BCDD4A15004692369EA4716F2FEE3947D573E0CB4F94A44F7F76139DF8D1C0A2720CADD1ED0EA698A71FD351289911B689CB99CC1DC36428390A959A33043DCCE3CEFD1340676AC6CD58243FB15316E6645D042D480484AEA885A8E2691C6592D2167D699BFE762260C30EB5AF2466E5E3BF25D6001084EF3A5E7ABABE885DA0E2816DAAD5BD4A75E6D1BC7505DEFF741EC30EB9F69F92B1819E2F4D73BB63E8755DC32DC6CC002664AFEF2E541FE96B6EF6ABFB8993BA52EEAC19479E0CF22B6DC40FA80BC1BD52B2D85546A0745D71A4B3EE8D1F786ED193704F1AA2B88857ADB3B08000316F9D395938A14E73B27A4EA7A2EA2E751BF5653E148B8292A00A5FFD98ECB3CD6173444143C63FCD832FCDD4DC0B15AE3938A7CB2AD21CD41AA6B93E4140DAC5B671362F95DD3155B5A7AAF4CDADC694E4B1B46044F8A28F566036AD0D017C3244F81E5AD4F6086BF74205833728166CD014499F9C6A70BDDEA6C935969448B42B68AFC59F6BCFFEA95878F2F32F583E59D9CCF8B7DCA5DA87508C2E2CD2C563094157CE7840CD74544AF633F17DCABF5E8ADBCCC75FFC5EC2D54E3EDF91C1D68305F9A1C789C6090C58946CE661D90995DCDFA1F7089BA945090B93029E94B2892FB0FB7418E7C4B4C2B07ECB8F7850FC34A902C22FDF8A7A505CBE7E33066DC3D1E3C6B0ED957CE50AED24481CEDB590BAA6DDF581F05940267123CC294681CC42BAE9ABA1900E9F3C1DB742AB325D62972DC38C387831E19A768A6C71B0CBC46B67F5620419EF1A983EB974391694F423B1250B82F593DA8908013B15A22D8B51F2D7433CFB6E8D4EA8F3F9BECDA883E19648B08BB04165C42AD8FC08B404F6013E12463F41B7284297BCDA019A1BCB5F8D597F597CFF91B1718F121272749AA40DF880AB52549FEF107DE40367642A1F1D9C8B6A859C944E7094BDC29505D023222603A19B100D38B99048FF0B9E4A1D550304D5F9202E6164323ACD96CD4A0A9DC0D1316088740D9F42A"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY('max')), + "b îýz¢åÃh+ö/£> ÜöbZ>OhCv,a>a_åðuv|Oßa£BvßZ_uCåvýÐ@ðvöörÜvu~zCäoU/ÄOb _ÜzýA©åªåh@Ð@vAö©vz+,_ÜbßhöhZß.ÄO©rТZðvzO,Bb|~ªCzÜ/äÄðýývråÄÖ bÐß|äbz +*AbrhÃüu|*aýaüä:ÐrÖ*Bb|_äz*ZaÄ_ßü.BߣÄäzZüz+Ð bÖöBhã_üZZ<@*ã ©uãßraªåAßa*/bCÐOß@Uª*ð~ÄvýCß*h+aý¢Ö<|_ :åî", + "/ªZ ýB|ð~.ÜB>öb~UÜÜhCÖîOÐZ<ßb£@håöÄOö*@C+Äb>Ö~£+:@A*Ðã©ÃÄC~Ä¢Öäðå£r_uå£åU©Ü,Ä,/o¢B*_ªo.bZA<ßÜß>¢äh¢B+Bh~äoBbbvýzÃ.b@,zzÄUovr,ãC/oo_~Ö ß@öÜÃ:b ýaAoh*Ðýu_ßîärãðOAb©îðÐ._+¢||¢¢ã£îOUOUÃÜÄOðýÖä:~©a~©,,/bv¢ªÜÄo.ªîüUüAªÖð ZöÐýУÃîAå_Aü/v:Bü_¢ðb|ÖzBܪ<|bU© C:Äb_üð", + "/££ðu.ZCð_å/ßo>o©@/av©¢>:_ß@+B:¢vª*AÐÄ*ßB/Zýä~~aã/uU,..ÜAo<âÖÐãBUoOß:/üO¢ðã+¢¢åöÜ©öåruäO~a~u©O Ã:îª.,u,aUbÜ<~,,@~ÐäBßöåazau:ãÐ>/ªhðÐa:_|Zö¢C:+~O¢b£ðzUî>aªC,ýðo@| å:<£>hOzßã Ü|ð.AßÜB~C*u/Ð. h|*ÜC_C>hÄü|>Ða:bouArýöC+.ýr_uAðbßbÐ/bru:.v ãu~ãCîov>,hoªU.Ã|îüð©b<ÄÃZaýüa~ÜÄ¢voßhB¢bÜ/éîhr©@©_:*©ßÖåhßåOz>ß*/ýüUä.ß äî¢Übßoß : bz+ö<,öavÖå:ðîz:hU.£vÐh<ÜOüã*©bääOÖAbA>äð._|ý/ÃåÐ a|ðßbzOåOZ/B£ª©AªÖov.CÐ_Äär|> >BBa©>ðbC/äOãr/ãÖðîüßðÐ<ðîã+BOCª,äß ý£ðoB_¢Ä,Uv@CåCv©@>|+¢bÜ©|üðzUÜý.BãCýÐåZzabâzUrbäöä*Uü+|o>@~Ä.o:ZBAbývð£uv*_,h* Öä/zî¢OC:|ãU*êªðu*rrobªAuCü¢ãoAhrããüä_£ðð~//©Z_©Ö¢oßhC~ÜãvÃ@r>¢,ßCoãÖ¢bÃÄZZ~£o+ö~zäraUýbvbC~ähÐ.üb¢_CÃðC_zö._hbîA<åÖä,ýß*ÄbßÃ+ÄBAö<,ßßohªä£ãzã.ZªuO*îßÜ©/rÖ@@vüh~ä+~©ÃCu ÖoaÖo@>zßOör©h/äÖ_OÄhßCUîbA>ov+u*A|,å£åß.äv+|bÜ*,ÖO|ßzaã£Ã,¢uÄ|ßhÐä£|AýB£+zv|Ö©ãZ©B.Bß/bAÄÖrUU~Ãz:UßOhÜ*Übð.aÐZåa_*_¢oÄ ZߪãZÜã,ܪüC@ä£oîÖ£AåabZ/ärÃîbbhÖî@+@ðbýu@£,Üo+oåO£ä>©/ZÖ ./~o<Ð_ß*ª Z£ü©©ß*+©@v++ÃåÐv~>Ü@¢ÖöBro~hÜ:ZU©v o~~*+bÜÐoBb*+abä ßöb:UB_ãubªäuhÄ.|~©ao.:äaÜaCßuhĪü/Ðräî>A>haoåöö+ðß/+ão,>r/:b.AýöåvUÃüuéoü£v:ÄhãbÖå.Ã*ÖßbUa///¢hb/£ÄrUuÐ*OC,/@hß oZöhåzðr@hß,üz|ßÐBUªÃ>å@:@za£bÖu~Ob¢+@BÃzhÜ|î.ßÖäZZu¢U£ß£Z.o£ý Ü~Ð.ÄöýC£hüaî@uUhähªobå_AZªaßC,Üýa©O~b£Ü©/ü:Ü¢bAÐ,CB£¢ü/ÃO+. üZ_ÐrAåãA©bu+öÄB/Ü.u~Z/ýzC+Au>,©u:Ão/Ä|ªrOÃÐbäZÃv*v,ürÐÃä_/b£ã¢_v,ýîU|©Ärßa.ªÄö/ß©ÜåuýÄAÐazåZ<ö*_h:£ä,/Ä©|roOzBh~ývýbÐ v©üOUvÜ/Ðä©ä:UZ|/Ubu©ß|ã.ðozZuüZßßrüîrr/åC:Z@/¢îZ.ßÐa@©:CCÜ Bî,b£b ©Ub¢ _ v üZvaä.uZZhÐäß/ä*.üü,h,üãüÖ|Ã+OChãÜßAã:zb©CÜ> :åßOZð|+år~ .ABã@îBa~aa¢ã>ö©åÄaª:@>äÜ@Bv_Üü~uÄ..rUouÃ<Ð:åo*Üýî<,,büå£_äü¢ßr:oarü,.Ðà özr+h,~ðhßö*uýüðUãêäãÄ¢bBAözOuÖÜb/ÖÖ>>oZA>ýUCöaUAh|bB:B~|zA+¢ªöªO|o|roÐ _zã*Ð+öoaÄZA£Ä©¢ Orr:Ü£._,b|Ü:Aå.U@ܪÐär*å*î ðö<å_uAü_äÖ©/ß z,+|Ã,¢.råa~zaã~.Ðbª:~©Uuýîä,ÖCOð@åö>ßuöz@Zý@¢ÄüÃv ð*råÐÄC Ã>ÖA/Üß©ßCåb¢@hzðzÃĪvöOC/rãÄ¢hU,:_/|>ãuÄüðãßrÄ.rîü/A,Ð._~îý|ýüoý£ÃoüÃÖ.::a¢*B+îÐߢߩÄrýÐCåüªã£ÄýÜäh@_/@o_ü|+Bb:rývÜ+ouö~B/U@*_ãBÜß+ýuAüößv£|~bÜ,v,*å@O@ußa ªÄåÄAbäåaB+_Z£/a/ÜUbýäåhÐ:rUzßvzhîö©C ªß.bOärbý>ÄrCÖª/ ÖãÖü~ãª~uãb,,ÃÜåBo/£ð©að©:Ã@B©>ÄÄ|Oã++Aüß<üAh©ªßö A~Oß.bßßZCoB>_ *Ãß>ð>Ðh:ä/ÄýÜaãå|Ö£ð_îoCA|bîßÃý.ÄßüßZAßz/Äöü+ãAvZv@Ðå.ßÜ©,îö£u£o:ZvýAb~_ð <ßüOÖO@ߢ_OU_zürCîCå£ubÜ@b|AUu©ýß_ðýß>£Ä.äªBýuÖüAãðÃ/bÃvÖr£©¢<|,år/ý+ý,¢U,:ߪüßzz~a,zü|Öä©uªãüBðZrußÜܪA:Z:Aªå£ß.*+A.Ðý__üüöa@@hýa.r>ªb:hB oB©îZ©@OÄb+Ub.ßãb@uB+C_h©*~Z©vb+z,ã/äbÃZ>*ßbªÜ ßÃÜýöîaüb_@uöBu@/AaðÃ~+üýßöªAZ<_îaß~åZC:Z.Üî*ãÖrvß+A~ä£r ßýCü.öÖbý ðz£¢oî_¢vß:¢obÐ rî/öb*~UBZa<åßåªrrhbu,.äOãAubÐã¢bZ~Ð,_äîbÖÜÜ¢Z£vãÐaÄzåßüo+î:üUßÐOrZrUor£*Uý:ª£UîOÜ+*Ðh O:¢|A¢.ðßöA~/ý/aÃ@*+bî**>haZOä:aAåCÖ¢ªOAðzO@~bßîÐÜÃã,ÜvvCvbå¢CÖð>A_|åÃ,b z/ÐÄãÜ: B_.Oªªvªã¢*_Z,ß|Ua_>Uab+¢>b*@|v>ª|@| Öî/ZöAbb_AðªO:ãuöbB>b|B@îbZ+ãöÐåUU<~~huZ bU¢rß+©£å£öCzrÃv<ß@vo/oBhOªb|äZbüÄZrÄÄðZ©Üüä@O©ZÜ B*Äao¢B@b£ÖªbA+ähªî>|Üäu~, ZUÖð+ö_©BO©Z@bÃö>£Ab,ZÜ >rbU,+B~Ã@Ã@ßðö/öaz+ßa¢©vÐbC@:ªÐããÖÖC.ßBbu@BªÐåzr:,~<<äb@oÖ.ßZÄ:OOuÜUvazÄrz~<_b_ãÖðbbAv*üÄUö©,ZÜ@bð.>Bbð/BåvOv|ýBr|b*£,hðäß_Ab£zî@b.¢£AÐÃýªüoýOÄhUä:ßu.ä©Ü>¢z_î+:|+©ro*:Oß++b/üðÃB,ÜrO>ÃBrÐãh./hbu@ª¢@@ýî,ZýäbßUß~örhCovb©|ý.> Ü,uZßð+zO~.åßî>ãb,>b_Ð,årZ+o¢vÄ¢vÄÄîöB/ð¢ðzu:,/v©~ð_|åÖ¢üãuuÜã@~_üªAÖåUÜhu|.O.ßäB>b Ob+üböv:uÃäBߢð/ßuîÃÃÖ/£OrÜZã*CvÜO.<~£üߢÜ|/+<¢|<+bå~+¢/¢ÐÜäOü¢ä~~zªu:ãOUCbîOaZÄ~uß:zU©.|ýãääC¢£oÄäÜoA A_ä¢|_åÖð:¢rCßÐu.ÜãÃ:aO@ävýB/~_<ýîýß<ö@Ðb/UbÄÄßu>+__zßðÐZ¢¢Z|Ü îhrrãðÖ:vB¢AÜBßo<ܪbAaOrüv@ä uOZBîO~>~,~¢BvuOîüOß:ßßOZzîüau|.îhbð öäðu©å+a.ðÖüAbz Aä.,Bß~Z¢>*ßOÐüuZãöBv~ßð.oå+hýüovbäv£@uhv£ªo_|ã©ü_©rCub:b<ýöðrh¢@O|BåÃ|Öªßߢý¢,ã r.ª ÜAba.uo_Zrb>ü£*aÖßZüî~z,::.BhªÐß@zÐo>B:<.u ¢ÖCaýAã|.h£.rУ_ößb,©© ß|Ãv©£ :/bzbz©åå_.ä_@à ߣo>C bã îb BÐöbar>*AB¢o~Cß+ߣCßCuåª@ouh+rühU*Üh~*ã A zÄAýîa@ÃbÃßvrää _äý*ýßC>ðU £Ü/ßßßßðo~_Urª©hZ*ühðZvßý © <~_b£Ãäîªåý<,öÄÖaªßÖ ©ãhöB.+@£ß:hÖü|>ß+@îaßÖ,h|Z<+üb@*ð@hÄ_aZA|h:ß/*/ßAã/öu<¢ß© AUU,|zßoß/.ßv+Uä/©z~Ãuã©*h£~C:î*Auýbßo|hüZ@ý,u~bÃ+Aö>b£ß,|A/©Ub+_bÖb+rbZCO¢,ÃãZC_~îÖ.üãü|O£UCC:ÐUo:z:_Ã>zÖß /UC|vðîB*Zö~uߪãª_bªOzvåröäv/ÄZho:äöÖ @uz>åýö,/öbzîüU:î©ö*o/Bð/+,ð >£©bZAäZÃ.vöß@îrhßzåÄ|Oý.OBh,b@ªAbðz.U¢ö,orUÃ,*ðOÐz|BAªö:©£BðÐî¢å©ðÐ~ªßåo*>_*özaßoü£Öö>ý<ýäЪ@A©v~*a<¢*|ð/,Ö@bª>+¢ZÜÖUåöoðUªÐbZ¢ ßZÜ~Z@Oß,Ðz_Ö<.,**üUvîAÃ.ã|,ÐßähÖ.ÃÜãðbBBö+>|,,/ßu,Ä ,bðUbO/üßb|åOÜ Ü£_/väoz@@hA/C|@/hß+*Ü@ÜÖ¢hZäߢ,ªb©O©ö/:UÖ,Ððhýãu|CÖ+.üýCÜâÐä:ÄåÖ.+:,ä<Ã+hª+ß㪣zbzÃåarB©båvßÐ+Z©ãOТ+ãâbýv+¢zöBý.ßoaaÐuZÜ ýuå¢ÖzÃü©äaðuªbßAðÄbÖöOßz~h©ã/> ª>Ä.O+@bð*Zuü<|_üOÄz|Ä~Abb OOAhu+à Ä£,©h.©üãßaªÃ£ÐrÖåî©+BA*åårbãZoã¢z@bîî~O+BU>o~ <+ÄßCbv¢å*obZäå>b uÖÖ©ßz¢ürr,ö.¢b*ßüvä@/>ð¢|Äýz ©ðvãB©ðã~,OhäbUöö@AðbîUußßUãAuª¢£ä@:©|_+/ü+ä©+|/©ÃªOö,ZÜÃbaz.Bß+ß_b_+_:ußo*ª.Ãv~ÖÖ¢|uü*Oabhå|îå/UOZåuU >_Bªð/Ö,är/ßA¢ßÖÃoå@z.|£îvð+u,,*@/hah*.Ðv©vÃhCäß/.~Ð Äabý/Ä£@+o:ßbv~<ߢ*ÐhU£oå@Ü.Cößß©Aß/bAÄ¢Üuå@ßäbãv ¢ßuýr:*ðBðöU,/*£hbavBu~B¢©h:hzßðýüC_Z¢O+Ü.Cb:vß*ÃZå©|ý@CÃ,ö/î|ÄÄüa<ýOOOAªO+uh_v£ª>öª£>|Ãuð¢O~UUb@Ba.bhöoUvð£ßC*ßo,hC|Bb<:ÜÜv|ý/+özÃA@ä|<_Ü++~ðäB|ßArCC>.a_üZ+êvß|Ã@/zvzߣ|ßÐÃî@î©ÃÐöuvßßvAýåvCäoB_au*©U|Ä+:_ÄÃz¢:+ÃýäzªzåÄoZZ/|_Ä¢£håZ|a/OUäßvB~Ä*/å.äzßöÄ*¢>üvZßîãBAoÖoßÃ|ÃbÐ>ª¢||öý©hä äOoðö>:îöbî/ý__ªvBÐzªÄuuÖýö. ZoÖüÜOý~UäOBßCÃ~o¢aa Ä~.|ÄhüðOö|b|£åh:u+|aAu_rߪ_£~+ð,ý|~*.bba£bîªAu:ß/Ã.£/ Ã*ä*î@/Z~~£©~BzßbOz_+ü ðoªoÐrîüvö©åuaüßüßv|UÐöbÄOr_åäoîZßÃ~£Ðo, ©u_ðüraü+ |.>.î/©OAåÜBoªbÄÄ +ou¢åU~>,CÖüO|>@ª>Ü+Üoý_h>|~bðåU>êuCö_vã,A_/bÃr~£a|ð |rOÃ<+Ãý::>öZ.©ö@@+h:CBß*a,î OC.b.:o~äö|Zð~OUZU*ª.ßObÄ|,| ýb|ðoZ+_Uýrßö©/~oO>¢CÄo|Ðð+ö* ãbªväåý+ÖzßÄbvoß_uüü.îÐÐCOý/CBhB¢ hBî©ðBUuüCÐv+hu/ý.UªoÄob Ä@ vu@ã+¢ä*ªåZåÄrðªýäßär©BÄãao/öã u|îöÖªååÐZäãBC+åüß_b<å©C~Cßý*:..Ö_bzßUoaBüB~*ãa~ßBÜÖCr@UUÜAýÃÖ,Aå@rr/ßÄåÜ/|/A>Aãß*@ßaª_~,zab/BäZ£bßB Öbý+åý©£BrÖÖOO*U~Avü¢ßhߣ:©~vÜý©ð@bv@:C¢åðZBv Uî@AbA_CÄðöOÐ/zb+zrbã£hbÄCî£BÃ@A_ rÜbUÄühßßC Щ ß_ýîr>ªÜ/zöCîAa.ð£,u@ahªUöAãaÖ+,uzZh_h*ãªa¢ðÖãuÖßÄ,à :ßß.,£v:ÖÖ©ð_åªÐååßz|¢@+rã.Ävbz+ÃbÜ>>ÐhÖzzöuB@ªU_OhߣÖÐä_ÜÜBzo|baaýðÜ:ö~ö|ðooähªhb©a¢:Ö:î~_: ,:oÖåuB_Ã:bu_äBã|Ä©£oüU<_:_U_arð>v|BÖ.v£bb/~ªÜbª£ª åäßO.r©r/Ããa©voÐZzýbh/A~B@£åÖ+ðªðÃzb©bhîbrãörbÜz:bÜz£@O/ßubî_ß/bÖUbüüBbrOBaðªB+AÐ*.Ī¢ö.>äU:aU+ZÜÜrüýß**ý|C|@UãÐãbor+Ä/CZ©,îUA>¢öboîb bà U>,*rßßBaã/Auuzý,ªåÖUb*üvä|ßC>ßÐĪÐ|*Ãz~Boa©rðäö~bð:ß|bOh.B Uüü@AÄz¢<ТÄZz©BbÃÜ a¢ub|*ðh@|.ð~ü CO>¢>ªu<ä.ro<îýC:£Ö ¢ÐîüÃÜOBîzÃh ý_î|bZÐÜh+¢*O/u@:üZߣÃ,v_öÄ.h|_Ðbã>+B|,+A|<+vª> ö~:*. ©Zo¢aC|z£~ãîZ öä/å~ðÜbuAað/,:|BrzÖOuu<_vßÄðå@+ O,Bh|Ö<_ªbh¢B©Oãb<£~@oТü*zhbo >¢~vý+._/ãr~oBã:ª¢åã.åÜßA©:Ou: .O<©örÐ ~~_CîÄ>O ð¢äßU îuzý>Ðh.:äüO/.o:©Aü*bZ,,ª|z£ý|C.|¢@©><ö/¢>A.Ü h ªaîöbU,/ä¢ýv.O:uÜ~*uZÄÐz|@Ä_výªZ/üAý©O+ uBßä<©a:bߢrýðbåZ~,@@ãOåAÄã:h<|ªuaaOðäßå>v>/*,Z>îoÄbÜãß+ððãÜã| |UAýüîäü.Ü>av*Ð_¢. _ýÜ<ß+r£výaAbööðrz. ªArZZvß|aO+r+>a*ßÖuªÜvªü,Ö:bz._uuBÐ@Ü|z|©bh£@*~BåhÄZBh._.B_ª£Ðß,A/:ß+ß/Aßå/Ö.©îåZ:ðª@z_a|Ö*.aÄððUТBåÜÄBÄ©:uÄ£CÐO©zOßråÄå:U¢:aACö>@©bßa@Ðãîãä zu ,Ðhbäðu/@B£Ã", + "", + ":©+©ß:öZAã_h aßÜÃÄu*<ßh~|ý£ruu>bBÜOöä©~ZOÖãb©jklßîö¢bä©¢_ÜBßßÐbß*>b|ßåðA", + "oÄýbðvß_, våauC_.b|ß:/ÃAÐOU¢vðüî>BÃö¢<ããav*Ð_:<ß:Z<ã: <Äaü ÖAOZ<*++î@oîöuÐÜrBüAýC~bCzrä£r~£uîa~aA,||Aöa_ßb,vÃð@ßð/î|A~.ÜöÜåÄ©*ßb+*aBð<üo~@ uߪüZbãz:Baý:üÜ¢vbzå:Uzå î/å/<Öý>vOö ß~£ßA+ü*+|ChãÄBv£äý@Ä£+¢öäü*a>OßãZ:<©b.å @ö*zÖ~Ü£Ðã,r/¢oraåO,ª å+ z|Uª~ª/BOOÃA rvrÃZ£Üª,£Zv£OU>Ðrbýü/A_bhUüBv:Crßbü@*zßhã,U@C~ÃrßÜ>ß:äh*î©@vîßÜußÃCvýîãZ¢ãÖ£BUCbüö~AýZÐö𪪩Ü|uAªaÄ/:/uððuO¢BbªÐbB@©¢@Ä©CÜBCä:+ðC vvßäÜr*+>Z,/ÄãäÖ~㣠*£üý@_*raß©>Ã~£/äývB A¢ÄzvÜA~vÖ|ðvÜh@ðz<@ßzýb¢~Öýãßr:ßÃA_îð|BCu ýªvUß@ððÃÜ|@Ä¢©©ÃabÐ<_Ch~Ð~¢aÐ+,ªýa/* ö:ðä@ÃuOzîuvåbb<ä/>h©bðZðü,oîТuz*b~ߪA.î,.Ã,ÖãZzhh~ör©å_¢ö|Zbv~Zaö@a>£U,bUv£UîoCBãܪbZBÃOAO£üUÄããã:<ªðö.Cßß@*ÜßAZÄä.hZüÐ:äAö¢£äO©ü>/*ýZvð|Z.|a_vu/+|//ªß,Uö~¢ü|+îÜß:ß+A+ý>îãÜßh_z:ßZ>/ b*ä:o ßA*år~ßrB:ä.ý~ö_ÜaªC.vOovå~ããbî_äOª C*:ý>ð_ð.<ýß/.ÖbAOr+*¢bU@Bbßh¢ª+*ubýäu>A*~/î@Ü./Zã>©ýuý>zu<,ãÄßÜå¢:r ÜußÃOAÜOoÐÖâ_zhö+CU~ãÖBO¢Ü©AåzrC>ªÃüßrrzo>ÄÃro<£öU*üÖB|b~ý.ý>Cã:>@bÃ/ü|ðAv_oA.ü:zAB¢üU+.A¢,ãÜußA£vrÃCßrüÃ.ð<_.aOaöÃÜrZ*>ßCö_zî䢪ußã_ ý/Üð|Ð@Ä>,ö~ýAa:*<ãév_>Uäýo<üý>z_©ü|oZ¢/@<<_<üb,oubhäÃOÖå+¢Ö+u@./Z:*bårruUhßbüÜîîÜ Öî*:äßãuß.Öý|Ä*é:+ÃýCÜOZ@äöå£ß ©z*,ZÖÄýbh,,OßUß @ßzÃ*üvB,hüöå*oª. v+ü,îÖ,¢äÄ+ý>Zb¢*ã>¢z*bZî¢ÐAOßUÜÖ:ý/*Cî_zÐB|Ä,£ÃîUýzBÜaîz©>ZA*:b<~UAzªvUöü ~v>|>ýAhðßðÃü:bh©ª¢>övabCo¢+ZýÐ+C:.£ßBazar@v|îv|u<ª¢ :,zU/:**©äöb_|@A/ |ªz>ÐÖÖ@uåbhß+Cb©bC,+£©ö**~ra Ö@ßhAaaö£|>îu:z@b|ö<î:ðAüðö+o,o_>åh@*©*CbÄ,_î:.r£ßzAv_/ZªÖoBb¢ßv.ö, Üo+rã/Ob,h>>ÖÐ BhZü:äð~>Ub.ðhhöbbåä©ðß.BUuu¢©ªzî:OZ©/å<ä~åößavðvO/.ää©ozääu¢Ãöã£Ð@:öäZ¢r.ýbAä¢BüZü:uO:Aßaüß|©ão¢bzb>ßý.åßr:ä~h:UÜU*Ð>ª:Z<£ðå>b_~ã:ý||ªoZ||/ýýorå@_Ü.<.C:äÜaob@+ЩäAhhå©OBbOðoªß@äu_CrhOa öðÖ|Zåbß<Ö,@_<,ЩZrbZrãZ<@Ðý*v ßUÜ©ãßäb>üaAã/ýzÐo,@ãýüAÐBAä@+ý+£ÄOÖr©b+:BТãäbaý.Bu¢b>Cãäoh>ÃühîArA,~ o~£ýhhB îo©bö*åB/_Äbã_ßUzU+Ðߣaª.bö¢üb*üÖ_výãªaßaðÜ>Ã@>ªÜ.©åÜ+>Uob©ä,UC+OÐzZZß,ÄU~Äåå>ðå~ ã|+bðvãvãÄåAB/U.ªzOhÃãã~Ã@h©ß,¢|uüåa<_ ~Ð~uîÃ+ <¢ß~ößårîðð*.COU~vvbða.o¢Äß>,C|ÐÜÖåî~aãîðzBÜBb¢ ªbäß C_Z>ãb,/åÜ~rz©b.vu¢ßO.ý*,Üb£ß¢~Z©h@r/ßÄUåv_/uC+:ßOAåäýoÄ|öBbaÖ£UOz@ooåü:@,öîä_Cv.~㪪Ä.Ãýߢ>Ä¢Uh¢zUð~rzðr|*uå:ýß.ÐÃaÖrvÐo v@©+ ßÖaAªöObubý_ ÜÄðüCrü.ß Ö,ªAAãÄüÃîüýhð Bªäar|OÖovß+*~Zî|ð>Ö£ýîhu@BZ£*Ü~a£a~C.ªÜ|¢:Öu<*+.ý,b¢o©BÃÄÜÃ:îBß>U*Ä~Ãßo Ðra_oðÖoÄä©öÄöãüðî,¢îz©@£vüC£ßÐOUÖîü©|_ßA@ÐA/ãÜz@ЩÜ._..@<ååö¢@ðC<Äöbäz*+ª~,|¢Bß<©~îhüÜÄ <:O©£ã.aßðühßU©.z.ßöAãî,b,ZbªÜoÃý¢|.hÃÄÖo+ÖÄC©£.ð>ã_üÖz¢_ß~v_+,AÖvhrÃvZªÄbÜ£Brv.ÐåCCöªÐuzðä*C/rßýÐöä@/Ä©ruãîü©_*@O@©Uvbo_îîÖ,ö>väý£*v.åzo:îÄÜßv¢,@ßöð@|Ä£ßz¢_üvvÐ|býaObCZu@Ü**+Уv+äC|* .öÄ:CvÖOO£ýrÖv¢r/Ä£Äaß*Z.|üvª.oOuÐ~b<¢aA: ~Ä+Oü,£o..î¢z¢~.b_z>~Ü<ßüAÃ_ÐßÄ¢UÃr¢îuª|ª/ýÐZ~.öýz¢åÃh+ö/£> ÜöbZ>OhCv,a>a_åðuv|Oßa£BvßZ_uCåvýÐ@ðvöörÜvu~zCäoU/ÄOb _ÜzýA©åªåh@Ð@vAö©vz+,_ÜbßhöhZß.ÄO©rТZðvzO,Bb|~ªCzÜ/äÄðýývråÄÖ bÐß|äbz +*AbrhÃüu|*aýaüä:ÐrÖ*Bb|_äz*ZaÄ_ßü.BߣÄäzZüz+Ð bÖöBhã_üZZ<@*ã ©uãßraªåAßa*/bCÐOß@Uª*ð~ÄvýCß*h+aý¢Ö<|_ :åîZC¢hö+aå~v+ß/¢ß+/öª.*r:zîv|ÐÖAbÄ©ßÜzz", + "/ªZ ýB|ð~.ÜB>öb~UÜÜhCÖîOÐZ<ßb£@håöÄOö*@C+Äb>Ö~£+:@A*Ðã©ÃÄC~Ä¢Öäðå£r_uå£åU©Ü,Ä,/o¢B*_ªo.bZA<ßÜß>¢äh¢B+Bh~äoBbbvýzÃ.b@,zzÄUovr,ãC/oo_~Ö ß@öÜÃ:b ýaAoh*Ðýu_ßîärãðOAb©îðÐ._+¢||¢¢ã£îOUOUÃÜÄOðýÖä:~©a~©,,/bv¢ªÜÄo.ªîüUüAªÖð ZöÐýУÃîAå_Aü/v:Bü_¢ðb|ÖzBܪ<|bU© C:Äb_üðäÃvå~ö@ý>ð¢uZ.u,ü©£åB/<ßZ+¢ ßÖA/|Äb+ZåÐhUªý¢/A+ðåbÐ,åBã/u:~uzrOÐîr£~*äCbð@¢bBÜOöä©~ZOÖãb©jklßîö¢bä©¢_ÜBßßÐbß*>b|ßåðA", + "23:59:29.0498764", + "2002-01-31 23:59:59.0498764+08:00", + "2002-01-31 23:59:59.0498764", + array("-100000000000000000", null, null, SQLSRV_SQLTYPE_DECIMAL(32,4)), + array("0.6410", null, null, SQLSRV_SQLTYPE_NUMERIC(36,4)), + ); +// 11 +$values[] = array(array(("EA982235D8DCA9BAEC4C94727937A73EA975D4648D69AB654C544E246FDE0C712D22CE0E4D457AC1AED7C48910C3FA8A91BABD3A5732918AD95EBE613349D566881279D9FE7D6F831DA086B5A422558859C392B521D21AFA914434EE87198E65E7DE552121EAEE01"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(256)), + array(("009531925ACB9BAAF1F372D32BD650736063B4A0A99DBCC28EBEE7325B43E5772ABC4A70994578FE2E9326B2195375BF61826ED58315B362D86F049CE4684EAE0DFBA96E8CE0D91BEAB57215760AA83A4828D0D8D50FF31409E7982A4"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(256)), + array(("9FA71715A18E3AFA79DB32F6CDEE693D3811C7484656D8E123FAA87D4A62873D7F015EBD727AA06515350849F37A9D0D60273E7696E48948CF36F2A7E6BCAF1654F577CC8FACCABE716133104D8EEDA95C9B1D232310A69B7816ED3B88F87F5885F2F5FE02D17DB45C800434B078FA4148484B4A9E8CF2434EDB5379BE8F3578E1DA8B5B99EFA68A1D69C7A30B72EAFF1BACF33FAD35B9F9FFB1AF267D04F5CD4A8C52D5ED9EA758A1C02C35C44F38DCF1545E129BF6CBAC21915CE73F800D1974FA597F1F15127C049A9EEC088434AF79D33529A6E23154C0A5B45B42C01921B313C1CAF6B8BCDB42E10E0158DEA49C5CAC6E6B4AE37391C804BE7960B63944817C39F4C26AB9C01759E7C4D430FBE20017FF9551ADD7CFA03001F1F9427A8BA7CA7FDBA5B0DAF2F3AD54F0FCAEBD9808DC7849B7A3F2D4A569549268C7C6D5DE5B1C0AB0203D503D0CA2A458E6D2F17269E81DC931D403D7AB363B5B47892BE67F11A191B3E7E89F280CAA014D7BBE96621FFFDFA90BAD86193205E901F5F58377BDD9D53160BF82FF7EA1252A02892F78A4F8278A4C3C73641A7880E1FF9D3216268A8FA2E86502607DDF2B6A885C16A8D5715DFCCDF82A81657117E73EA000E06E0E0378F98D8F3FF6C70D6D1109DBBE61D80C8E4036492E5F0E3C774E1B22DCDE4BFB79589EAE47E11E0606EBBD6F5C9558866693729F38C5D518EB5117F0DAA5308EC60E6265C229C4AC222F4342A29FE0E2F594BC486CABC2B48386C3F6C92D2B61BB2FA94E32F3C33CCFC57D098292764B7135FB46E8E7211B4BAEE13C65CEE2F403E28773F592AF02D17F79A72DB931F10F77859432E578D30D8E02841186D601E28905A00A0255DE86F874696D7AED917CF02CED484EC11E69B465678F2BF04AA877C4A3B491E60D22A60D39700E6593A071072159E9B894C7E636569CEE4F5B082AC0F6B54ADDEA091FCBA24087AD5A4ED2C71E23CFF0BFBF30DCCD5B90703456B231464E6FDD55931C173A1D16533F39DB08CA26313738390036856D0F8F79AF974B8D56660CDEF5718A07B8B6A2A8DC9C947F88A50D257BF80D4D3857E7848D9D8B85CAC5E9D2CF29D5B4A63080825E8EA9D17B0FF1098925125D59BEA59D8906791B2B1CDD17B3C2B05ED0597F4B778AEFAAAE16087DAB81FBA5B38B781083372A9FB6655741B0921EB95E933830A5C7E6CFCFFBEF73FDFB6FA92138632849A0DB992FDF941232ADFA1BF84F1F1849CBFFEBA5A9418847B7A2BAF6AE20772EF56FBEB79F01C632D49C2100D37AADDC5760553878839F5E5351783DDA1B848D82ED02E06060AACA39B9D00D1F87733CF4DD9E4DCA3EB672CF5F644D888958B817947DE678CD7CF6B58BFFBEB2923FCBDE3B48FC7D36C243368F1000FC5D41AF6118F58B098DC42661A8983F3FF7C03D20986F4D405B3BE0D139AFE8BD7BF95849505D999CB3C15077229BD49E82043FCFD3E064EDF46F05DD14B9CFDDDC69E5AE3FF6EE9A26A06CD61ED51EC066424F357019EA9A956B54E057BC88FAF2739BB9B5265F8C15A4A832748DCF1F514577D26A9A6CC27E4A18D4A10E436A1771E4AA39650A3FE2C31FCC70B726089B358F1145B5905706D83A6A0D8BEA07603D1B02A824E5EC3B37EFA77BA052C7240F386B7F322562E18DA4612AA03257D8176B339C245F7650A3D60EC5E9DB65867246FE527E882E17B9201B8083C19A0598CE63351E2BFFB0C11BDC5C179CF8B13EDAB75933045A8F3D1BE30444F6CCE13B092D1A78306747474D9163ABD2001C286A41A80941D19474D3F80347FB6BCA4EFA200E6EDD380E737012E572F6E36B1AC6DCDAB524D8FA3798A6A43864004BE2C614B1B1F2AE4A313235992EEB217DEF8CE8811E91142A2126D6D63694D60F6FC603ACE232BA281891A883EE3FCB4C7629B4AB7B7E2D50B1EA8F8A1BD7139D5B262967E7759BBDD2C0688DE8913BE25B895F0DDF2B94F199B2FAF7A22F0C407E0B28C8156365018EF7D8BB159F6820AEAC2F927806BD309238CE347BA31AA2B3280EDC6872CCF7245D7FE852D8DBF94AD949F5007AC8784EF736DD953086EBDC3507ED908BB73BE0376E1A86D5DDB95CD4E9A15924A2385F968E713CEE61F3D7930C1CD0ED68BF210D15C80CAEF179197D80C047E491B793CE8DFAFD46FFF1D67A42F2C8C1E86F6B2A804C0EDA2CB1A51457BE6EA1ACF2025489015F6EC1DA0E24F2916BFEB0589511541C6445A8B9A2DC55E8EF408334CE4FF07437E60FFD69A53DEAE79B46A664FE295C4C908EBDACD05F8319D8EBCDA1BDC21B0E3C21AE0157B2BF07BED10695AE84F01626E83EC132C767868CE490B96F482AD82A9828DD7A5BF4DDCEB6EEFE58ED6A54FBB77BD4845ADB74BA28757322069775A72E6B165C139BCBF361F27CD9682D9E793BBEB8CD5554D0BCB32252E581BAC81E78572A8254F8E71BAFE122675E9B51FAD6F9E648DEA852D99B59A8F048E572A72A5E6010031C2443D69D1D7432695E17D0580F87D37F40D00550E7FB4FF7D2CA6E7B3C003B40F6B9D5A272418BDDA731FB911FF0D6EAD3AA1E8F0BB23528F4DFCB5205B72C5DDC8F6155B2310DFE4527A9B500BED7E1F384A891E2AB354484ACAE927538D8F0049DB48F8E8137A19C1F4AE40980273607E95F800F9B7B305A1DD105837B890C4FB9B063094753724C06F5C360513A0384778B8CD957E16921833470B0321E21963E9450D0C42DBF95EC3308A5B8D009E2CD800BEFFC33F7D746418513E2C21AE7D32C22BCEA33C04ACBF6EC23D8C369B32B8DE2B11331990A9D788983A7ACB32A1921D28BAD4CF899C0C0230546D3FF82D7D1E754DF69D3A193181F72AA3DA21F43C20AB6F1DE05DE9548F1520D93C3C97806ABD5C55E4AB04E31F7952D85EF821E04C184C94991F9CC08BF97778093FF5455F9A391CC5AE5775A67C0E66FB10F586E3409D23E002F75B109BC9EB338CD9DF841D78B4CF051AADB0D6FE1D1135C57AF3E094C8A2D1555CA2EE0C29D47C4219922ED2ED9840C7DE25EF631904EA49EAD65EF752F8113CB2B82C11E108E0D94484D47AE252D7D2B318B692B37E3C47C89411538584FF2180F220357C3ED6C535161E84307F5787FE7C343A318E79347BD4594CE79D53CF95B2F9E022A2668431E15DAD5FB817594C99650940B4EFF288EBB9A7E599EDA7B25EEE8D7577554C05BFF85030CBE4C3CCF0005E284A8EE0C2F75746F8CE9EA803A5EB00C989D3D53418F380CC9FC1CD06E5DAE5998F8F77C00DBA8E101E534711404C9AD0D40A332C3B1A1F46FE1433359A3002E3B91E74267330BBCF55B525C5BC6F7C5326EC22EBA7B95E757020C1F9874875DE40536831C8646D935E73D675F4498A9EA7E00EBE0D174C0FB00EB6426EC2380D4F477569073A8AC27E9F9D33E2E87126963341A739B7D139075881B9BE1B348C3BC936ACD421876D554C3F7D8A182CD79D8FAC3B7090D387764C51AEB8D104636B010819B1C45274BBE451ED8853AEFF3BAA2C2E6EF91B9AE5AF3687CFE8A48437DC1279100315C93D378F8C4EE60F129D62630EB4E5F461F56D24028DCAB4C33FDDA5AC3135EF389452E137798F5C0FA023FA5D7595DF51E7B083B2DF033B7282BC4C713052D167833A7A51F4BCE86601246269C0575DAA0E53C480B23C5981277EB4CD32EACF4D4292DA3B1B7D6D2AD81DA1BAA0C1A22B5EA262EC9E50A556D0F92A76081B23165515273D8D128E80E699A8948AAED055CC897E9077E2BEE1ED736A1242E712CCEA8B558BAA74AE3C13E205F4A810CC2228D4B97E9C929E7266355009B87C3DFF86EBA9FF4954BB57EB327C85ECCA49CCB737F97E3DA42047ECE32565149483A7B4067DCC76DCE8C41961835A2618959BFB8"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY('max')), + "ÖCrîUZCÄ/UzßßbBA©ãå>BÖýð~Aßo+ÖräüÜýÃ.£>UÄA+å_ý£üöA:bOAoßãî:bu@bý£ß~<rbÃZuÄã£ð_î@.b |åbAZbaÖ©AüU|+br*ÄТaou<|Öö*ÄÖßr|ÖåvrbU", + ".r©Äru@,ar+ÃÜöö.aðà að+aö©CO", + "vU£ðz~.ãzvbÖîü||/AuvÜ©AA>ߣÖ@B ªßZB:CA¢ß~b,böov>ªhåðÖrh:räoZ©vÜoU/ u@bo ZîÜÐ/b:+ãößU_Öðbã¢h:/BÖo,å£ÄObý_ý|¢ä.,ah.ß/Ä:@¢>>U,åöÃåro¢ |.ÖOßövUüCb©/¢ýb££AÃåvorö£CªzÃ/Äßb:У¢£Örv£+/~öUö¢U|Cö:zv|uhã©öZÃ+ä+ov,aaZ<ª¢ÜÖ+Ãä£Ã:åªäªo*övvBéCÜü:u Ü,Ð<ýz_bö@B>åZÃßbåð~b<>~.,BrzrAߪ£bb.£rÃua>övüuÄÐå:uÖÖ££öåäßCî>oa~hªUßÐ.,_CÐv@AðO~ îbäOÖý,h@Ü,|z@ ö©ãª<îhbãu¢ð,.äöª_|ªbh,+ªãÃr£ýüßuð~*b|B.ÜAAüCbaÄ©ãÜAÐðvßv<ý£uð,ãUßÃ<ã>åb/hßAC/U_ßý_ßrðbz©ÜB~|:rã¢OÄz,_äOöЪ~BuÃßu:ßU,ª£ Ð,ßb.Z<üöý,ðÐöhZC*ä: >u:Bv+C£ö/A_,~aÐÜÜ©v¢¢BßÖBZz_CAÐOýuO*ýhð+ a_+,**h_*~rrÃäC¢ ObßCß.z+,*ß,ߢÐîz¢|:+ÐðoýÜ:_ýZ*bÄ£üã|uOhbaöýzo_ü:Z,U_Oü/h¢CbüÖ,BýÜ©o£î B:.,*ßöãßu_©_ÃðBhOz¢äý_>,z_üzÜhߢ£rÜZß<©ÃrävCAhru£ã*,@üb~.aª*©håßru~ö:ü~åO.oÐaßÖOãzbªoßöAÃOaCÃÜßO,zuUåb~+ îBUr~zrÐ.@*bZ£,Z|vZöhZhðüÜ£.hBÜ¢O+z@öÃÖ@©uãÃz>ýÖ|~_.:å:+Ö,ÜaåauîßU:Ü:ÄråBoãð//¢:Üîã||*ozîöÖ_îÖ¢£ýöîbArZã,£ zb_ðzÜzuýo©*:Boå>ö£ý*@Oð>_|.|ªaoîaäv+a/Ü~@£< ~/üå ÜåЩýßä¢/Ürî©+o>//Uî@>>ä,ßäêîB~_UßC/Uab,Ð|©|ÃäZ ßoaÐýßZ,ävoöoa_©ª*._bbr.O@ÜðãzÃü~+ÜÖBä|._Ð|üãCuÐAýü*/ÐZÐö~_:b*_|~r+ßUÜ~ÖÜaaz@u~bZbîã *_ãBAß@zB*OOý,£Ö/ÖOauÄZZ*ÜäÖåãÃåboz:ßvB.@,~+å_ªÜzB¢Ü©ðBhv+b*ð+Uvhr/©ªîîu£Ö<ãCð,ßOB:ÜuðuoboO:OÖ>oh UÃBðo,O,Cî/UA*ýUOãî:brýZª/Ä:bîv Äß©ÃÐUöbªßßzÄãhã<ö~©U©ZAÄß ÄÃÐ*u£C@U©Z@ðîãäu.©|ÜzåýCzªbA>¢üððu+ä<~£ªzîoO.©Ö.ßb¢AU|.ßÐUîbb>Ðbz~ý©<ýÐãAü:,Ðßãã©r/að©+ß|hU©~_ßOCäã©Bðß ßaZBabð|vu,ZZA,ðªäîä>o/.£uªöãüÐÐ,Buð+Zß>rÃ.+o@åb<îbuAüã¢~å/Ü:üÄZ<©îrß:_ b.£ßÖbvh*_:öî@Ä.vª >äaAuýhå<¢ÃZa+Ðoªzaå>ªZ/ð@Ö+üö<ðrCbZêävU+îO|UîZårb:>bßß/©A|zÃÖB~ªO+~ör|,b~,å>>öZ üOªAÜBBÄäA~zö|ªßªüb_Ãða>b::,îðobvýÄ~>_ßbvåboýBBAÜbî_åТAOCý ¢Äßðå@AöãAzbhýZßäã@ö*/ªãA¢O_+©.,_~Oªð>©|ÐÃÃ_bårUãbrUzB_>U:hvAC||ýoã*Ð Äh>Ü_oßöUåÃaA,bÃ@hýo v_.>ð ¢UÃuä@ü,,ýZU*ÄZuv~Abo@z¢Ã*|a/~bZªßoÄ|£ã>ba£ÄUî¢/bbZã<ãoBöb_>öüüßða¢__|£¢Ð_Aoä~,ßÄCö+zußÖ©bÖ>C _BAäßuvBå<.©Bðßýu*©ÐÜßaª>Ãråä<ßo>.ýöhaßO_ªu<ü£håð©ã,ß+_Ðb/*Ba,U.©UoÃöåäu|>ro~_£ã| ör£.*häväãÃoo+ßßÄ>/ðbߢã O+h@ß>_Ã/AÜUîAßÃao|ä*bÜÜÄð*C,î+a~aöoåÐöªbãåÜ@AýÐOo©Zîö,vÃ*,©vBÜh¢£Üvðh©ðßbãU<Üou.üÄOÜ:Uh>U:_ Z*öbÐoåUÐßb>Ð:äCoÜðrOUZ+ª+o.£Ü©©Cª@ÃåOЪvü©h©©Aý,a :_*oAb~:*a:ªüo,,hðoUübzðr~oÄð*oa£/rCÜ/>¢zÐ+ªß+ÃýZZåbuÖ*.U/ö:îä@aã/ö_övªÃ/_öU©ÃBßåo.£:Bßåbßä*>bÄ/r+Ü+.obaÃO¢©ßCÖ| C|Ö/ä_Уb:h.Ur,ß@AZîÐ.ÄC.üZBBuãðä@Ã:åabauß_zvvÖ媣/©¢ ü/|Ür*rß>uhzýÜ,ýÜ~£ã.u+öýUUªªåäaßðÐb¢ßöB~ b/üa:uhCÃÜöaaðAßAüvCå|îo>ªßOvzä¢ubUårößÖ+>rBbÜðßAßÖýß<:>_ß@ä.üã,îzÜöÃoªBh@Ö,*ßCÄ©ýh/_åßÖªÐ*,/ü ,£ßrÖýýhåu©ãZÄbhÐÃßO/ß.ãA@A ößr£OO*Ð_ª+ÄÃãUuåA>A_~¢Ã¢Üî|Uüouü©Obaa©B+ ªC B>~|OöýaýÜ+O@A,ZÜ>|/hÖA£Orä+,©uü>+_Z ýbAOuýîßå>ývß~ßAÃr*<ð,ýB¢ªz_,Ãhoäß+<.Z~*bBZr@AuC:åüZZ_O,ªÄZBÜ/B +ðÄZb:,åª< >ÜÐA~/Uö ,rå ¢üäÄý<|¢aöãªzöbýßî/Z>oüãZ@bCü*üAzãbhUa£|ðZý,Üu|î@oßýU.h+@ð©£üZÃТ©~Zä_vßUå+uo|bbüO~ß@ýÜåé¢z ý~£ªvÜC¢vAüîaÖ+bðröäªÃÜÃår£åêOðö:UZĪåßö/Ãh¢å@u.ãÖ<©:ÐzßöÐbhuö£äAü_>b zhðoý£bý©.<ääÄU<Ðö<Üåß©Ä>bZªðüÄ @/o@_~zoîÐ,ÄÖBßhÜ<ß|~|/>Äî*©å_ÖîvÃ~_B£©|ßAo>u*ðÐ,ð:©ÄUß+ªåªßÃäÐbzåCÖZC>~ªü¢:|,Czüß+üA_ÜAåuöubååöZBr*Uo:Z.åbТ ßrÜZßå>ÖbÖBbäbOZ@ÄBÃO:rÜbß*B_oüü.ßh.<,bÖ:@AüÄÃZ|©_Ã>ðu:*@_/ßbh¢rðª©,v£ªu*vª*,_vZCU:åÜåC@ýo@ö~>ba|ZACaîzað:o©¢CöüZhÃã©Ö.b>o,Bh©¢är~ßC>oZrð:özÄ:ååu_©/ßu ßåýªã@uävãz:AzãðußB*Av>äªaObüUýu@_/ÃÃ~Ã<.ýä~+b_~zZCýÜ¢~|A+vv£U>Ü ªü~.ßU£Cªðb.ð<_:ªÖÃhý:åüä£ /ão>bUÜBöO>b:åoÄ@oCåÄßb<ߣ ob¢_oî ©ÜÜ_*©Ä:@.v¢©BZO/Ä_/ª£Ü©Ã/ð¢Az¢*hhu+ðýß/Ovv¢uOüuäîrãª:ÄAýBãîÖB.ußð<@åîU/îBv*,o/@<ÃÜhBßЩ/r,ãhîÃBãAãzÃ/*ö£Öð>r+£ã£ /bzZCýOßB©@.za.O>*zhßA ß< äu.Ð>ßÜhö ACýr>_Ü.ü.:ýöã.UåðhåhuZÖß,,Býrî_ßåz+öoÐ ãrOu@+Ã<Ã:>Üå/:©ªzÄozüB*a£ýý>¢_bv/,_|£åýª_åÄ+îähoäuß+AaörB~ßðüðau|rh¢ @O äßoB>bu:~U£.ÄÄu.:*>UäãÄa* ÐZª@ãüÐoüACußo_uAU@Ðb, *uuü|¢¢:ÄÜÐå*vüüÐý*äZöZÄB ª©Üß~v*öUZ¢ýo_*~,/bvOöbZßÐÄ@A.ö@åuaüÃîO<_,A©*Ößß@Ä|ã£ßh©ª>Aã_ãîã*CBö_+å*O._ýÐÖü_Ã,vå üЪbßZ>vããü,>ªö>zBßoBãªbî>äÃð:ð+å:C~uªbu/ßТ ~ß_:/~ ©ÃZ,©Ð©©+:üB<öbî*@Ã*r¢,ÐußöU|ý~:aCãOoÄî<ð,ãýä£o,_îOöÖUCbZ|Oãß/C+å>b*BäÖ£ªu.ßÜ.å~©_ãߢÄÜýßîª_bÃ>vvZOðÃ_aðöå/Ößîã|Z:ýÄa.ßaðÖö|o~ aÄüzüª+©Üöuo£BhÐ.<üÐ,vz>ã/+Ðr>:ßC©Bîß~aߪb|Ä~ vrîb*~>ªÃ£+C,@_baU :AUÃCÄ>ob ÄãÐåoooßooäz@ý/@Är>v_Az,CZA>ß ã.:vüߢuu++uäb:o@Uv~az©Üß©_*ÜåC£Aßz/ãUa¢å<ýhî ouðüÖÜUr _ÖÃßuußaÜüå£rîz*|ý h<_vC<©£Ä .ã>h£ßß*©|:+Üð,Ä+/üäß_<~>aý*+ _~BÃ+C+>|C@aå/åÜĪå,Bu©ã@ä+ð¢£ß:ü aåvB|v ååä*ߣbÄÐZ,<ýUzîUo>Ð:åðzbA|.ý@¢bªbu*ß>Ðu uî*.üýbÄüAðb_åaö_vÖB£Är© åðAüBÐ.v.Uü~îBA<ÃA<ÃübOu,vuühÃ>ébBbbÖåZ>ßC¢A+£OĪöÃÐü+ßÖß|ß>:hÄÐvîßaý.öhOroö_OA¢bU@ÖßüÄÄvzUObßb©.åÜ<ãOÐOý__Ürår¢_O:rªüðzrBÐÃoÖb,h<@©._ßä@ Öv/ð>,B¢£å*äb/üh¢Ä*_uý,~©vu£ävª ~_CObZ.BÃðvb.:z>ÜZzÜA_,£>ÖOßuzªaCC<|>Äß+Ðß+uh<ÖÖÖÄObªbðZBZoCCBäb_£UÐ+£ª¢~aU_oCåAÖð,BoåÄoÐr:r_Ãv£ö Ã>UA,BB|:~ß,hý,h+OÃÜî£ðBaor,båÖ~~ß.,ÜÐ_zý~/C *b<ß. büO/A|oAuîÃ<|ãußz|a*¢£+ÜzußÖ©CÄ~©_©¢.,,ߢà .zBäZC_ÐîßbÄ/~.CßÖ.+COBßAoª,îOrÐðzüüãÖüîAî£ýßüBBbOhAýhz*ð~z åå*å~_uvãZ|ä*är|,.C:ßߪ@U¢äübhbU/£ah_Ü.vÖßvÜ¢v©höÖü@<ä@bZߢö©vuÃUz/Äãba¢ýäÃý@ßîýöÐazO@Ü~CðãÄh:ª<ª|_zãüZåÐ _ªo@_<ð£aöUî@Ä_ã~îuZ<@vu,üvªoý/h|ãýo/ª++ß>:£UÃbßÜý++£:äa*öh~rz
C*©Ð+.ý@ã<ýbªýÃî/ßoªb<ßOz./¢u©Ö|ð>Щýü£/ä @*/~uu©hCAb@AC.ýÃaÐ>hÐ ã£åChüîZzCBO.bÐOröb_Ä@,:¢Uav¢Ä*rÜa~ð C_OuÖÐ.ðöaðüß@|br¢ v.<åü££ªÖî,,<ßãB.î üÜü@ÃUbZßOßo~,v©ð¢£u|BC©A_ª:Oü/hoå£_zîÜ£å*ã/üÖßarhð:Ö©Öå£z>o¢¢CãÖ£ýÄÐÐ+aäa uvÃÃZЪUbAü,|ã:ª>::ü¢OÜZ>bUhÖ~ß:ÄCÖz_@êöÜýozß bðbrý:äÜ@ÖÃ>ö|ÜßoBüß:bobýÖãaãO¢üÃÄouÃ+ãýä U_äaÖAOüßb*aåýÖauu¢ãö CÄßU,_CßUüöCãªOüaßãå+~¢ÃßO<Ão¢+a,î.or>£¢ãAß+bÜhhßUrßabü_BC/ub/¢¢~öÐðrAÜ>orA Üv£AA äð.|ý öåbbb._..OÜCAröß:Ä©ßA¢Üß<,OÖ|ÄrAö.ýzüÃ/Уªð~<@aß,b:ÄîOZ BUªÃußãÄýÐO¢u¢ãÖZðO.Ãr*ö,+*@U>hÜC©uÐBÐ>ãÜuªÖ*,~ÖuÄ.ýaå¢îî£zä/ :<ª,>|.C©_. £<ªªªýܪZ_boÜUAzß:/£,/ÖChöåA*BAå|©uozZAzbãAð,:¢U@BZuBÖðrÄ<:©BÐUr>r~Baåa@.h|_.ãÄÃz¢@UßßÜßÐA:ßã+r*ªã/rä@U¢BÖßöO+ßåÖÜ*bÖÖv@~|Zªý@@ß:© ,|_aßäåvzå>ÐoCßÐ:.BÐ~_ðhU|:h a.>UzUÖãÖÄrä>ö¢Bßh>oßb,*öÖã£,Üu,Öðz:ý>äåbåÃÄîäBªZb//üü@öAoz_,C:ü<ßB|£OBzv¢Cî+©/B£U* *ß/ß,+.ãrz<ð/ÐuBÖ@öCüCo*ã¢|+ÄuîhÖC¢©+zovÖUCühO<£/* CZU+u£BöÜßbCý.*ozB|Ð:+Ã*Äýru£oðð+åÜã@Ö", + "*+<ÄCh_ÜAo_åªåÖªå£u:äz¢äCÖB£>£|Ã@/Cýu£ªä£/¢ý+bÖaAU¢BO~.bÖª~+AîZ+~ä*oÜÖ,Ub+ß/©¢>baB¢va:@öAbu¢buãÐhU.@Ã~Uvã,bßÜü+CB>*öZA+h*,hÄ_Üoß_bz.uý+.ã+.ª,ÄOb©", + "|åå:CåZoz:_ÄbuUvÄ©üîCCöBð¢ÖТubA/vªö£ªr_ößbüz£*,o::.Är,/ðÜ@>C_@b,>ZߢzªC:.özbýßZv+|OÖ©zuåoaäbÄ.,Zý|ß*_Üäã*özUb,öýUuÖý Ðrbð:ZÐAÖý|ab.aöÐ~Ä .ÄaüßÜbåã>©.ö©ã~Zªz|BzOzÃb _ýZoöÖã,O:£*Uhðü_aðü~¢ îCÜß<>ß.uÃü¢UãýB£Äa<©¢ßýüªÐÐÄ@|", + "B@ÃBå~üÐ|h¢ÃäãU.äÜa@~aObBh£¢+råUu.ü/üZ¢|ua©B,rüAªßýãvOZCöß*ö +*U+v¢î£ ãaÄ_oß+.@rüªöavîr zßhAÜ@OO<.bîß,ðýU£Oª:uOß©.ý£Ðzܪbz~ãOßUr+ýzö*¢,|©öܪÄ~äBª ++@@/O£<ã>ßbß/.üU<ðU:Aa/üÜ_oå<:>uä/å©ã_CzäßîЪh rÖ ,o+å *b_©£<ª*A ãüa@Z.ðßö~UBÄ+¢rühhb äüB@~Zå<ßv/ä,ÖO ©:ð:+/ZBU+OA/@AoZß@~*îãv:¢ð/OðCÄÐvh_Z+ã|¢+ð©©©îO¢vbªößü,>o£zrÜz,@åv,ðÖü ߪCöoðOåZüß Bã.©î.U Ä@*äb_oÜ,@UåZÄÜ ÄaU|ýÖAUöüZ©<ª<>>¢ªzvUå¢Ü,<ÜÄöA+bbüåO©*ö@~@_/|£A.CßÖö@ü~|/£A/r@v|aöÜöb.: +uBÄA:~Ãã¢î/bUîÄÐÜB îA:bAüßÖCzvUa~£oß©ªå/~|ªbý_¢o¢ü~ U+ä/:öB@äªO+©.<ªÖåbOuå :ãýA.O~> ©îÜußÐ+Ð>*~ý,U.~ba.Ðî.C*b,~<ðÃ*vBãÃÖ¢vßa@*©äz b~~/*ooÜ/Uß.o,hîßßazå__£ößr.r|ÖUbÐ ýå< OB ./öuC/å¢_ääý/@Að>|üÖ|ä>|*.bha <ßu|hCÃÐÃÜ@|Aå,bzßööýÜu Ü|ð,äÃ+Тr+AÜä,ðuÖäOUýߪoZCUOb*Ä~åß~Ozäa.ßöã@*Z/.AÄuîbBÜÐ u||C__ã©/åbßÖðåäÜ/AýBßaÃão*hß_ÜAãäbz/zU,ýãð,*ªZß*AZ£ÐÖu/|äv+rÄäîCbüåä~/:O£ýUåª*uå|ßÖvCZB¢£Ð~AårZüaZz£,ð֪ߢAo/£r ©BÜbý,|*ä,z_ÖhÐîÖ,o£bé£<:ýaîöO __~Bbß:ðå*.ß+îC.b<|Zü/C|@,_:ðrüar_¢ãööUÖÃZO¢ý£¢BÜ@hãüv¢©öuö@ å~äÜ:Ã,bCAðîöåÄaÐ.ßßî~>Aßß>baªoÃü/:£bÐårbuð:Ãî ,ÖC>,Öä îbãü¢O*b>äUö@/bðý_ªÐãA*å>BzåCÜðBB_~uÖvaÐo/ª/üßüÃO@äoC£vA>BhbAo,bzã/å<ÄuZªý@u/îðÃhªÃ~ðÜü/v_ЩCðÃýA@hC*buÐ.åã¢åÄß BäbU<ßzAÐ,ýãA:©Aýö@O~ýªBÄ~ð a£*u O~CrZÖ|vu¢bZ©ÃürߣðO¢ÖCUü_îåýabbÖ@äå|ãÄröî++_ßAåühua.bÃ.<åuÐãÃZr|a_oãb£üðÐuÐ,ÖÄO>aîäÜb¢Äã/,©ªü*Uªoß@Uåbå,ãz,Ãü*ü+üCuöOð¢üA+@üöåå.Ã@|Ð@:OÐzh.|£r>ðCzããßÜýCªäÜbî_:ö/ýa:ÜUã@ö>¢b>bzßåªä¢Abªî@:C©ÃCßÜ©röðoîUZ¢@@z¢/oðB|Aýr +âC|Äa|ÜubÖüa+*böh©~@~aZBãüoîß~ðoßvzb*_ZbÖzUå:o|Ð>bã@ÐäBªß<äA,ä,<ßßrBAaªª,_ÖZÖ.¢Ã..,ÖÖ..öOÃuåÃU©åîÜb£ü:Ã>vuß*ãßb@¢Ã.vb£vÄ@*ÐÖ ý U:åbã/©U~*uhO/~@ö©,>O:BðÃÄA/+o_ovå~åöÖrbü/ãðã@BZöãÜbö>oß*ü+C.Uå.ßbäZãÃ|O< _ТOBo¢Ö<@+:uÜÐÜ_ý+b©Ð|.BÜ©ß/vZªªªü.OOåu>©Ö+A*ãb|bo~ß.©ßOrbz<ãzuUÜäªß ª*Co~ýüO+ÖöªU+BÄßOöouüB|Щ*_CvOUv b|ÃBÜ*:äª:ÜÐîbýüåB,~AÖßv*ã/O.üa@~ÜÃÐr*>~ß~Cb@Ð<@z:ªbä©ZzÖ/ÐððZ:¢:voh,UÜ@ªßÜ:£ÐТ+îäü*ð©ð<+ýÖ¢|£_h<ªv~*hb©b:bîã£aÃB|A.<åub_ZªOabýuývvö,b_B©ýbßà ªa¢BbÐ hvBã::z@ã,+rÃ~_îavîäaOBðªu~rßAo~¢Ð<îZÄ,ÖzÖU:bU¢ððZý,uãã*¢äÐCý¢Äßuß|öC£ªZåh_vö£ã+ª£Z>AÜ*ßåhZ/ýZÖ©b/uZ©©ßZ©Ã@bZ~.üa*@ *rÜ:/Übý*Ozª+år>.|Ãðãaã Uv>ZÄz.¢Ö/zä©Üäîªßð<,ðÄ.,î|:©~>**/rovÜvbÖ©ãö| ã£ÃÜzab+ö |BîßÖüüOðü>U|Ä£ã|åÄÄBÜãbbîÖåZb ~î.oz*£O ðª/ðBz£:ªAßÐä:.,r ÄCvh*z_bªö/.äoäÄ©©~>uÖÜo|:v~Ð:aÖCAöbbßUh,bÃÄaOo£åoÜÐßÄCö*C|îAö oöÃzãuߣå.:Cobbo+z¢Ä|Ãvö.ðýÄöu*C/Ð_Ü äz.b>îz+~öåZör~,uÖ<©ÐîðuBÄ£b ©/@Zß>ýu£bÜö~ßüC/ýAÖÄrübC~ü,OüßUUAð@*ýhêO~ÃÃÄoBöC£Ä¢z¢:::Ou_~A©v_Ã|å:Ö:ä o_¢Z,,/ä:b Bªö.:bîßîoAhð/hAªr<*rãjklãobÜß©Cü*OðÐo.,ã¢üOC,ÃäU+ߣüÄCU ßz¢åãAB<îO~UrZ:ßB>|åCAÃhzß.üAhvuöªöãß>aªåÄuuCªAb+äår_*rÜ¢<~AªC/Öð*zª ¢ý~>üa,ßäÃÐro.£©@üUh*OZ. ~äZü*Bu~rbåbÐÐUaü/b|U~ u¢OªCâüo:ð©©ü@>~>ªö+ÖªßuaC+Ðräba@b OaAÐß/ÄOOvBüîaåÃü a>Ã. r¢|Ððo¢ßüvuAuO:oüÃ:Z.CðÐãZýrvCª*B©ãBvÃßa|:hÃÃü©>@oAßuCðbÄãî£o/_ä©äð_*+åvå:ÐöýuAäª<©BbÜCüÐÖ+.ßoãCîvAßACoovÜðÜ,üb<ßAAÃÜ:ÜåÖüß~ý<:ĪªbÄOuß< @ßzã |Ü©å¢ÜCo*/>obbz|oßzuOßð*z~r_*U£ü+î,>@ª|C+ã+£.rrbß:ö¢£oCýÜAÖðå. äAuðÄÃÃêª.*_Ã:£ ö/Ü£/ä rÜ.Ð<ä¢Uü>@ªrv<+hÜ Auß~Zz+.ý:£Ã.oåÐðvörÖüO,bOä:b:b¢äCãB,rC/C/", + "6909-09-02 06:22:18.782", + "1980-06-08 04:45:00", + "1973-01-31", + "23:59:29.04987", + "2002-01-31 23:59:59.04987+08:00", + "2002-01-31 23:59:59.04987", + array("0.2401", null, null, SQLSRV_SQLTYPE_DECIMAL(28,4)), + array("0.5885855", null, null, SQLSRV_SQLTYPE_NUMERIC(32,4)), + null, + 0, + 246773244, + null, + -22040, + 128, + 1, + array(("EA982235D8DCA9BAEC4C94727937A73EA975D464956D202092BC1530EEE608F1746C4B852A1A1164BC0F5A4ECC2E118A0E1FA5B657E1497C7702A31BC678CC0644A3FE0DEB21138F636FA78613D25363AB8B21CF4152999322CF0E2877F59D4443540A2830049EED0B1652E739C369A5A10A6AEA1C13EB176DD16343BEC72A33A6EC34C42BFFB15A5F656979388462ED468F181EC51982DA1FFEE416D57FABDD830CCA4F223899F258108BB6AA72DFE96F76FD2EAF0B6D8D6A5AA52D1A9B84DF"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(384)), + array(("009531925ACB9BAAF1F372D32BD650736063B4A0A99DBCC28EBEE7325B43E5772ABC4A70994578FE2E9326B2195375BF61826ED58315B362D86F049CE4684EAE0DFBA96E8CE0D91BEAB57215760AA83A4828D0D8D50FF31409E7982A41DB1AC54578A51EAA063381A953EACDA39EECCEC6C953BC9875D9FD079465A447AEDA0F9BACD0FE64899042F44F2F822525706BFBC9647788"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(384)), + "ÖCrîUZCÄ/UzßßbBA©ãå>BÖýð~Aßo+ÖräüÜýÃ.£>UÄA+å_ý£üöA:bOAoßãî:bu@bý£ß~<rbÃZuÄã£ð_î@.b |åbAZbaÖ©AüU|+br*ÄТaou<|Öö*ÄÖßr|ÖåvrbU/O Avv:Zvå*_ßÃ. .©~:_B©bîrÖ©ß>ßýZvCb@Ü:ÜB*v ,ü¢ZÃÖ", + ".r©Äru@,ar+ÃÜöö.aðà að+aö©COÖCrîUZCÄ/UzßßbBA©ãå>BÖýð~Aßo+ÖräüÜýÃ.£>UÄA+å_ý£üöA:bOAoßãî:bu@bý£ß~<rbÃZuÄã£ð_î@.b |åbAZbaÖ©AüU|+br*ÄТaou<|Öö*ÄÖßr|ÖåvrbU/O Avv:Zvå*_ßÃ. .©~:_B©bîrÖ©ß>ßýZvCb@Ü:ÜB*v ,ü¢ZÃÖCrîUZCÄ", + "*+<ÄCh_ÜAo_åªåÖªå£u:äz¢äCÖB£>£|Ã@/Cýu£ªä£/¢ý+bÖaAU¢BO~.bÖª~+AîZ+~ä*oÜÖ,Ub+ß/©¢>baB¢va:@öAbu¢buãÐhU.@Ã~Uvã,bßÜü+CB>*öZA+h*,hÄ_Üoß_bz.uý+.ã+.ª,ÄOb©ÖCrîUZCÄ/UzßßbBA©ãå>BÖýð~Aßo+ÖräüÜýÃ.£>UÄA+å_ý£üöA:bOAoßãî:bu@bý£ß~<rbÃZuÄã£ð_î@.b |åbAZbaÖ©AüU|+br*ÄТaou<|Öö*Ä", + "|åå:CåZoz:_ÄbuUvÄ©üîCCöBð¢ÖТubA/vªö£ªr_ößbüz£*,o::.Är,/ðÜ@>C_@b,>ZߢzªC:.özbýßZv+|OÖ©zuåoaäbÄ.,Zý|ß*_Üäã*özUb,öýUuÖý Ðrbð:ZÐAÖý|ab.aöÐ~Ä .ÄaüßÜbåã>©.ö©ã~Zªz|BzOzÃb _ýZoöÖã,O:£*Uhðü_aðü~¢ îCÜß<>ß.uÃü¢UãýB£Äa<©¢ßýüªÐÐÄ@|zð©ªAOö+î+A.£v>©h|îZv~o£vZÜãäÖbÄÃC©Ä|uöîÃ*BB¢uoÐ:ð~OßUzÐÖa Ð.C@oz Ð_~ßBîªaªî|ßöÜz<ªh£ß©|ߣ,UÃýZª+Ð~ü..ZУä|a.", + "23:59:29.0498764", + "2002-01-31 23:59:59.0498764+08:00", + "2002-01-31 23:59:59.0498764", + array("0.2401", null, null, SQLSRV_SQLTYPE_DECIMAL(32,4)), + array("0.5885855", null, null, SQLSRV_SQLTYPE_NUMERIC(36,4)), + ); +// 12 +$values[] = array(array(("2A35410DBAA6E4B09FE628A565EF22E4436A2E9FDC8825E0AD0990C7272ABADFA21540D33576B925F6DEEC4AD328752635082EA9C17893D27D93EF948FCFE280A073694BA996503E48863931894542D324E329A9F4F27A73F96E65918714A636FC6B9A6FBF397CAEA7F0614B3F524938410C7FACA6388"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(256)), + array(("D18BB53C40779F9A0029230B3658D58CF8CF92BFB6A8B2CCE74AB8BEDCEC18E60110E2DCBC905B9413C635B9A4E231C03E4FF0F60E839A28D9E855F6BEE0BD13103C0A2576F8CF6774FDABF072F9280518F87F8CFB22D77D75B903D33B64D5320821A867D70C494580898111D7AAB5DFB"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(256)), + array(("78D37E9B1EE8D1B7B11DF93F3D21F43C9D911CC19FDB1A3CD275D21EFB60E3275C80364F6BECF6470B9057819BD58C94056F14D152A1C49DB842C9A815B3BC5039D1E3BDEAA4D0B09BD4B60E8399A0FDE83E188C4B11D5BABC999728234D3257D40747CAF2CFA9619E63367DEAB5191EA1CBC0D69B2F0428FB2800510DA78D4DA15E3A7C52D60A1895B7EDE8DB57D0077F7887578D5BBCA4021FCEC9CF5853F6D6E8DC8B7A9DCBCBC1A741E3421C4CA458F9D1942036C046A1967A330740493C63F712F37B448CE2ADBB96E619D861E5D22A71D587BFD5A02895E9E32398C4805D04804B095928136CEEE7659FD92CC9349460DDCE74B5A42172CAE55AA9BF14F71589145816DB79015E6998D770004E6820AE8E37E6B1E94FDB2A978E42B8C32FD26E8A5018701EB8E7DB700B1DCCB0727C7D39FA30DD1064A0C57CEC44EBBEA5A568040276FE50B090D5500B41DD310F792512C57EC8FEF55E25B052F43174FB1CCA65B5C7AEFC7D2C89695B8D0422C2936D731FD9F826DD690FA4504EFEBB5F6154EE76787C47CA299499F55EA3685903EDBE86BE552224A4884BB80AAB2F2ECD0AF93816AC491725A8F5445F317EC5A74A4C603F35A00B31CAD2F0308FC07D646A2753A92F4256A3A760155FDDC4720A8610BF5ECFEF986AEE074CDA59E796E878DFF40A2A1B7808F6BC98D48BAB53055FE5AA7E001E957B8EE9BB27F67C4ABFCA2DE6FDCF68DF6A98B7681256C4DE42B3467A733C18E75A4A797B406050117972D8095DC55536F6063FE549B58324CA0A7974B001D682B1468CB356ED9E0A48A5EFA07EBA817D5E0F846DFD339DA5C754B136E6DC61789C55571738A1E00967349CA4C6E2A60F89FB15A07D68857EA8E7EC013C68236C43760429626944BC2F7B05C896F8DEE4AEA1ACEBC6C1FA33CFD96E51B5DECCFE1130614FDE7CAC1FB759700163BCE8B00808539ABC38A6817CD05989FBF20651AE06B765978F0531F48C336C50F9D012F0BE49AD8B3142D88ADFD30D232324C5521F535C058318780221A62F053931820046993CA859C67CC3DEDBB8BCF70DD1686E1931A5740D6DA5D1AB698B13D350AE500DDD8AE71CF959D69826A760BC0A13D5C6971FFFDD8C392B96D7AE5CF1B00B8A0A6BEA3046815120D7CFDBE6C54514A155B64D3C30AE7381A45E50454BFCE5E71B1D56501FE38E4445FF270DB0526651C30D073A63CF595BF8698CE8310CD4DBE9F3CAA8EFC381722708F6318665D051F8FE823EF5AA844CC3FA58B656A613392A4C23BC87BD61FF8B94135AD828D592983BF0328996E63F6F7EE5F46BCA1C81F5BC063A4114CA3A9C82B2609729739A25C51E1BB6E0AF9366E44D09D86D94C17892651C229A508471B59507E485A8450A4ACFA5AC00CA140C72D35DC6C0612FEEF1E705C357788A759AAA004BA8AFE03B08FE8E9EEE1478C7510FAFC7F3BDB0546518F29EA381B3D244301256CAC964C3F221BEC2D391FFDC6F3D7248C8C381DCF9ACE58FBC4298864BBC59BE0221FD88ABECD4D1FFED80D418162F650F6B0981AE355D1DE3D406B0893777173741DA4D40E99CDBEEB0DD0C2B1076A6133377E0B2D80FCCC4DFA4D7E62448C776699CD73BE12425CE2D92FD5850F1D35D5F9C55C097655F310E896045C5F5C9681595C2739F6A320E51118445117373EDD17A8687F206DF043DA52D57C4E00938C89543BB2F5FBDF56A476E85E0191F9A1673744A6F42750EB6BE36F93DDA4A71074B7C7C30B8BE71BC911CAA97592323869241506CBEC9861F34047129C4B790FDFD7D949DA36A5EB4028EDD25CB775C9A1273AA99F9054982F55CFBB34D48F7D98CAC9ADC8E86E228E39C6930EB6154BDA8D617510CF604F73412A7466EAA67BA9604981EDC800B8B9082B65C9B189694073E0A7630A6CC96A8A2A77CDF9BB93835AF99E7C836E028CB8CC08A40A75B1B7B123F2F9FF089EF37027539D88EABF4C87D27EC7FAFCBD05DE2ABA4E5425600468C00CD5C89984425AAB0C6C1A74F3CE0CCC1C2806F9CCC466FD1BC44E509F5AB74F24B8DDE973EE5E2C7D5FF050FB6926FC319809480D7F03486EDB7DBFF40A0BA1A4CB404AE023482DC9DA8C7CD41601A29D521F07417F41A5B5957AA8609E2863444EAC2028EC0C1E4FDB7E32F2867448C9DB12A1EAF45035899A855AA8AFCD3BA219289579D189B15600C776010EB32F2121DE957B86884FEE76969E66B165A01E3280E96DDEDEF841615BEA3CEA247AE7562986C127B02B90D8A7033AFB4A94AB1757CE8DC9C14252E6540A3A9E12F4422BB70097DEDEF68265588527DBBD5626B74F158265FD1D94E723DAC3A5E0F2C5B2B11F443A0CCC48614C18713C1A7738FDE3735EFD71EC2E997BA0BB0422DC7455CF751A9E11ECBA72DD1119D49C68CCBCA1C5C26D93C830D4F0AACE5C11344E7F942B6C956C9AEBF6C8EC2050C24A0D12D40E525D0A06B2073435AD672E5E6198D2AA3070FC374016D9CBA4B7A7E012A69DBB7812E1E1658D69655126ED84D86A7A877E28099C16ACBE4B734E61FA6F4422F6C972D65EB6F134A30796D6192954E33A4D1071FA9D01A4DB54966E272B6EF60D03E6BB65842BC07CE356847FD695221E5B27BD4ED22869C7DE0AFA20831D87A890C90532A98DB6114FF507468D24F4BF645FCC03A1B73ADB8CF3978931AFF9D5DEDBDF0D9FFF74DD71ABFEDD21233AA9063ABC334183F6E98E29A5B5E63CEFA00B2167A145E72F74DAFE8205B85DBA69B8EE72F6E3B6945AE4F58F6659BEE744CC5ED1FFBB89631F0B475852F1E121307F3C0D07B9E8CC449D1CCC4067C91B2C174D49697BBABE2F8B53FB9C6E4158F3D44EF71DB1EF8AD3829D629ECD12B7423C3C4BA4A7B7B4B47DDD7C65FD2FE65BB3C87C28D1FD7A27C265D6EE482F6278ACA9603205B45C1C9A32AFE46314E662B716DAF4969E703EC213D231D0C67C5E6AF3C943BFA4460F7C5F8E9F5D85B4BD8F743731447DE20E29317FE1D22A4BC3C641797F4BA2A302C0CB78470FD0D13C5F24B25C8F3B09FD11BB2A8E34643D5213CAD90C1C4561DCC1347078F59B0E48503392BD67EF348B377C5D907824CE6C9E262344F7D51009B2D59B5ACA80F776BCD23DF0C17FEA24865DC49FF7D154AC6603EADF77C9408B23990A9253E9C0B674D6E3A5E6CD9B2E3C0ECEAA007011D170EEE4B6A6280EE381B2DD387557D09C8D1E2B10FDBEB5A878BC93690AA67AA387292164F51A005CD7F02433F062A8E42E221CE254F0E3C2294C4DE98495E8DB3829A15C266BA7731DCE490D8A81A80613BF3AD889984E86456F4BB8DC16C83207490BC6B15CBDC28A99D486A7D637A79437D5D55B0051AFEB1B16C72FEEA6F70616F64175E144B6F1785DEFC3B7EE6F3794149440E2D706F75BDB9645F6A29BF2DD8090EFE631A2F31ED3E2A261EC233CB79F9BCA12B6134FEF5A1A05AE710AD5C1FCF6375D7F41626191221EE454857FB8698E5706C1D0176D50F09C17AD549DD90CE064F"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY('max')), + ":hî+Äh_ÖzüýbBßüa£î/,Uüu:£OO¢Ãv@b:ßrªZz*©ÄÄaÜü+©î£.:@aav<î:Ä_üîbb:ðªvª*Ð _Ü©@ö:výZßýb/|ÄÃߪßÄߣüzbÜ", + "ÃCüu*Ð@/ü/AÃðÜU:äOÄî©îÐÐbåäýo/>CüÃ~ÃaãBßOUäoÜaååÄãrªÃ.¢Ü,Uo<å@Z_öðÐuO|:abîÄ.b|öbýýZzuî.|bßzÖâð£ü uäZ£Ão,O@ÜÄuÐßzB<îUýzA>oo+và :üb/Ð*bÖ*ZhðA+¢ããb<:", + " ", + "aO+C> åÃäbߣÜa:u*CªCbv©ä zZÜUÖzð¢:ÄOÄ£äöUuO ßrbbAuUA.zðÐ>>ßObC:BÖåAzZv@Ãv©åãb*AhUrÖa@Z> _ü©rã©îCÖB|ðoÖÜÖÄ_ÖÖ.B©o:©öã+:~:+ÃÜz~zäªÖÖbýÜBü<.ýzý_Öî:z>ÐoÄbÖz>C|<ü£_<@öãîz+ÖU/£C+:U£+oårðâ:bßüvz©UOÖßuü:_Uz_å_î+üOU£A¢ªª:ªßå>Üb C/~O:*", + "oß,ß|b@ß/ß>AÜã*ÐhOzýCÜ*z>>/Äh|Öýö<.aubîrOUª bZ/ >bZBßåoaßU@bbÖ>_Ö,*ßähÖã~+|ÄZýo©ð*åýîhÐU.hvb@|Öð,>ÐÃö¢:* :@/ :ÄãbãhÄä>£¢©C,ÐåÃza¢¢ ßU<Ðzå@©:ªZðü./ýÃ.AbåãCaßUÐ<¢h>ßÃhð~~Cãã*ãOa+r.z:⪪|/öh<ðbhAAzC>uã", + "ö,bzßãZߢ~OåO<*AĪouAãAðåÐ~Cã/ß_ãð>z,AäOBOãÜäOýzBªoß: ßC*o.bUOörߢbvýb£©ÐýhãavbÄÖvaUvüB>B+öU¢ßððU¢üUhÄzbüöÖ_ÄhĪ_Ãü_/o.ý+ÐßZhvAr/oüðuA*UZh/C:b©oCü>vaÐ ÄOzÖ_AãÜuî|B_OÜ+>*ÄvzÐz_zb©OoÜÜrÃßUÐðZßr/*rrîüCü ªýîZãö@B¢*öÃã|ßäîuÜUähãzßÖÖÐb__+AZoÖ*Ü£B:ÜhB_ÃßA©v/OöÃOz+U©brßAbß|©_.A@h~ÃÜbaÖÜhðÄbßC+. Cã+BC|å©ÐbZüAv¢£ÖzªvîBz¢:_h>ÐUü/o /|£.aaßC*ö<ßC©b.bßÖo.A_Ö¢~/,ö@£ý£,å<£z,üO~A©v/aÃz_ðvßhu¢bãä/<+£bh~Z Ð|v*,©a<ÖßO©ã.¢|OÜbÃß@h©/ö<ßöü_ÃoÃüÐv|äohÐåU£OªbÖBå*@~@u/ªî:Ou_ÜZ>@o/åZªîî|b¢åav*.AäBOO|oÐZ£©.ýîrBüo©/¢åßv/ªA<~|ª£BÖr©ÃBzöaĪ¢ö>î£ã_îã~îßobãÖ|@©hÐbazUÄ@.äãÐ/ðZozöÃ,¢b£Öbröb¢ã*Ö. |ä~öO©özCAaä<ååî_ßähbBbzöCZ©î|@BzB*.|*ÖA: ðªÖuÐbOÄz_åZZ<ÜZab,Z,|@î_+@: OAãÃÄo<|Ä,rAª|zzÄZ©rßrz_Ã@|¢ßAß*r@ßß,ÄbA£ÜßC:O/U~ |ba/+Äb_hoÜîå*zoßbÜ@ðaU£_a,OB@B b>:Ö ÜhbÐã~îvÐå:ßz**ýBU.>©/ ~äUý¢åooöð©:>|îª*hzå bÄßÖ/öß_ +Ð_@uAv~¢~CUã*¢Ãý/O¢b+*_ý>h:Urö+¢ª|öîý*å*Ö>ÐÜbU+Ob/@ªðva+ý@Äîß*.£Ö¢ußÃßýbzZzä¢ÜîvÜZrÖ.ÜÄ*_|î<¢ý@,BBA:A|ä:äzO£v:Ü©z©Äðbå/_*ýªaß~ðzðüb_bö~_>_¢~zC¢£rÃäahÐäý_zbªã/ü AAO.:<ª£ß©ãä*ü,ÐäößCÐîorBbaÐåýÃb|z|ZörrÄBrr:åa¢|ð Ðî¢ä~Cäýz,<äÖßýÜZb.CÜ£ÐBa@ÃÃzB./ß|UÜ/ÃÄ/.üîßuu:,h.>r@@öª£ð>©ÐßÐ>Üüßåä㢪Üßãb*_¢>bÜA/_©Ã|ÃÄÃ.ð~~A<ªüö+b¢Zßå.ÃÃåUBzaªöÜZöBvvOoorÃOUß~Ð~©CühУ©výåß:~Cðý£vO©ä©Cå¢å¢ßb£Zãv,+Ã|BÖrª_.bÐaaB£ªb:A_ý@öbß|>/Aä*ä/Ü¢å_o/~ãßÐ,äÐ<ªÐäÜ åÃĪv~äA|aa©¢£>zäoß©Üö_u© £bBåÄoBAýÐba¢öZ.aßßbÜrUOÖ~bB|öo>öðößöÃzã~ª©Öuä_ä+*ðÄ.ª|:ßîhhCýö:o@<öåAOÐra/b *>aA|OЪh¢O£ßãäååªuÐ ><:Ö uãAîZZBr ã .uªOö|©b Bß*äªbob@*./ãåvz+Ab©håª.ð~îå_+ðß,/u.>oZuhA©ü/î~**å~_¢,OrrööAov_h/~b,£ãßrÖß_Cu£ýAa__£ß+rýUAr|uUbå>_@ãäOÃ>b+ßßäbý|öðaªÄå*b,bh¢¢Uý>Ö©¢©ChoßäA|.~,hOb£ªzU:oªO<:ßbbåã+zbr/z/ßÖrЩzð:ýðö~ü£ÃvZ>a>¢Ã*ÜßoÐAZ*ðÖÐrß_AÄ£ou~o+ÜÖ£+UbãÃ/Üý+BUUbaî¢Ö+åðUªüb/BýßCªÖß/Ðu<£~ÐðoöЩ@Uªhzü.aåã,Öva.ª/ýäÜ /ßzß.ýO¢üÖZåZ_O<äÄ~~_Oý*r*ý><|uðö<Är@~oü*ü@u~UrðaåÃ++Ü@vzýâUå:>åöAü@ðbî_¢u~£ÜÖöob<~åä|oü/å@î_Ð:@A £uu,bßÜßÐ|ö¢_UÐaB>ý@výZ©Zãü*Ã,uhß,Ã**@*UaßCßUho>Ab|îzÖbUA+üðã~ðhãuhÃÖaC©>ä_rö:Ü©Uã,ßýUãÜ£|>,b,äbÃBîß©oî**ObrbÄîC:~å£OCo~+*br@ĪBý<>ä|üýböb:ßo£Ãð©+ð:@uå|ðz/ CÄߢ|ürªuA|>~ßÃh©+.УC_hÜo~ܪöðU@©üuußur/BÄ¢ß/åÐ@Öå|åéýOÃã.,/avCzüîã<îäouz_.î *vãvãb+*ßaüb_ýßßaB/@><üîbãA.©,C~v*>o_oouÐühîä.*ä*,z:ü,ãäZöuaaüÃ/å,ÜO<£vãðrÜ_ bA¢@î/|ÖÜ~bîO ¢rA_ZÄBüª<Üoa|h~o.vUîußZ:Ãb+bÃoO:*Ð/*z|£ÄÄoaÐÐ/a¢r/¢¢ð.,+ÖB~¢Äîðz~éßÃUäã¢@rbß_ÄUbÐäU@|@ð b~uüaýßUÃhbÜOöö~Üa.u |u+ |ýb©ßAoÐ>¢©¢åª@.ßC,©<åÜî©Ö|CÃý>+ã¢:aÖ|îCåAà Zöî,åß>:ßÃä©rhabCZßUo@£UrZß/r:¢ÄãoUåCbßahOu|ý+~:>Ãb*Öãh+~bßuhÜãb+åU>OåîðvO<<©| üZbÄä_ª _u_îbU~å+ OrBCbvªÜoB|*©ÄAÐãðbbý>Ü|ÄZ£üä©©zCh>+uärßBb,@ÖO_ãåz,£ßz*©/_,ߢ£ð<.UU_u£>ýÐUüðCUß_Ðßb_ZA<ßÜßð©:.O:hðB@öa¢uß.ð~ /|OÖäbß|,r+Ö/Ö,Ðß_zb@ÜOhZªÄOäÐåCî<*vÖðª**îÖÐÐÖ>Uu>üäª@ߣ+A+©ÄîÄ/*aÐrC.<î_äC_bð£ßr¢ð¢öoå©*åzÖOCbãuBÐ.voîZ¢*ÃãÜÄåà ªvã_rUåöߪuoü.ãð~ÃöruZ:ð_bÄOÄÄ*B.o|ärzaãã:hî+Äh_ÖzüýbBßüa£î/,Uüu:£OO¢Ãv@b:ßrªZz*©ÄÄaÜü+©î£.:@aav<î:Ä_üîbb:ðªvª*Ð _Ü©@ö:výZßýb/|ÄÃߪßÄߣüzbÜ", + "ÃCüu*Ð@/ü/AÃðÜU:äOÄî©îÐÐbåäýo/>CüÃ~ÃaãBßOUäoÜaååÄãrªÃ.¢Ü,Uo<å@Z_öðÐuO|:abîÄ.b|öbýýZzuî.|bßzÖâð£ü uäZ£Ão,O@ÜÄuÐßzB<îUýzA>oo+và :üb/Ð*bÖ*ZhðA+¢ããb<:", + "aO+C> åÃäbߣÜa:u*CªCbv©ä zZÜUÖzð¢:ÄOÄ£äöUuO ßrbbAuUA.zðÐ>>ßObC:BÖåAzZv@Ãv©åãb*AhUrÖa@Z> _ü©rã©îCÖB|ðoÖÜÖÄ_ÖÖ.B©o:©öã+:~:+ÃÜz~zäªÖÖbýÜBü<.ýzý_Öî:z>ÐoÄbÖz>C|<ü£_<@öãîz+ÖU/£C+:U£+oårðâ:bßüvz©UOÖßuü:_Uz_å_î+üOU£A¢ªª:ªßå>Üb C/~O:*|uZrãð~", + "oß,ß|b@ß/ß>AÜã*ÐhOzýCÜ*z>>/Äh|Öýö<.aubîrOUª bZ/ >bZBßåoaßU@bbÖ>_Ö,*ßähÖã~+|ÄZýo©ð*åýîhÐU.hvb@|Öð,>ÐÃö¢:* :@/ :ÄãbãhÄä>£¢©C,ÐåÃza¢¢ ßU<Ðzå@©:ªZðü./ýÃ.AbåãCaßUÐ<¢h>ßÃhð~~Cãã*ãOa+r.z:⪪|/öh<ðbhAAzC>uã>ã,~~rÄb©B¢ªß/Aö>îrhÃü:COÜÃzßäîåý|ߪzba,ã,ZAãzUÄaBßrZbh_,v,ß>,UßrÖ¢U¢/¢:åßZz©.vå_ýzÃbÃ~î/vrA©uî:h>ãB©ýb|<*z>ßãäýa>v>B_Ð>oÐß*uªÜ©", + "23:59:29.0498764", + "9876-01-31 23:59:59.0498764+08:00", + "9876-01-31 23:59:59.0498764", + array("0.1342", null, null, SQLSRV_SQLTYPE_DECIMAL(32,4)), + array("0.7331876", null, null, SQLSRV_SQLTYPE_NUMERIC(36,4)), + ); +// 13 +$values[] = array(array(("08757ECC341053DABF2569D352C8B231845DD236EF0EF8D319BDB269020047C0441746578A98F5C022B6B06EE2005B1319ED0CA132E5CFA7CABB3765DEAD7CE20ECCE11534CB8DACD7633C3A3F2E4F8B7013764203A68D5E57AE8CDF618FF18539CE50251F45EE4E5F5FC9DFB98568AC6BABF5CB273AEE683F82CD863EBE4BA5"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(256)), + array(("D70B88DA36D29A75543D70B1B19C21FDD2131F4DA64F47BA35813FFEDE19131275C2EA0039DF1FBFBDD4F1E65CB4495502977C92AAED3287C4CDA4B5929C973B295D3CEFB221C4F2F46090D15E615E8137E9FB469C8168878F623C6C3B692C213DB6BCFE775AA2E1D28A9D4A5D6028626E227DA9A0509EA8"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(256)), + array(("50E558B78A336F94A8A56009DD46197412E41D292F3AD9FD19EB8380EC171308C2FB52FC7AD21217EECB80BD0D18A06286DC8CC3D88B2F150B5A9E9EAFEEA890915847E1F31DF93FD1063A63B91CF0004B21FA108A503036CB3CF1203473670023EF2CB5D1BF6E69E34DF1D151CC5CEF6A9D538EF4970541271016B62CD80A5E9F3A3FC9F03A2E8BB2902C3D5E5EE5FEE001B69720D90B8BE9EA8DC1A9B73C0A429332178D92FF2F6FC7DB636AC8E3C92A17D62A22733DC52EB3DF05AD6DE2FB5422FACA2CCE714E02862858FDA8202107C49691E112E7CF556CE9D9B2FA8202E4E00F48CE189D5CA587289C4BE5C88692BEFDE8D65019423B2A74BFE5979B070326731D98D853EE273AEC59E94B8470A46247F4FC9A2B94C6CD0CA3A4DD770DEC20982572ABEDB96B0EC19C64C058F0A6041B8250A70B69FADF57CBCBB04A49C2DE6DC8B25FFDF9758D89EED88F2F05741CFC9FC2F5BC44152F2A925421EEBBC378D985538F3E4706210CC31E1D916BAF5157AFB3AA86CC2228B382346BA5549FCD2A60B5AAB2E4DEB599A0E9F926F89EBFE302CA3E0718F10D632BDCBB139B7CB82450F231B5059F72D0FD11E6E32802BAE47487A28960C6116EA846870723A2FE2331D5D5056C0ADD63586E09070A293A2821D69E13DA2EC38AE1C20DBF176AAD5B12C2B2532CB5776AA93E31F1BC09637E0B5EE64C03EA4902114B24AAFC1E4BEDC1AEF44877E7FC6C5E34699BFCD2CED75E8FB3B98460582878AF42E190CD6D8BF344300E151B06246179EECE81AE053E7D4D4C6C6B92696155CCCFC8A41BDC91C6DEA8B8A1C0C143898F570A7289A7CAA903634280002061DACFB8484C3E7F469D5C08A2064D9DBD8B09E3DB3A5EEECC25041EA1B79910C5BE47DED20778F64A0F116C168004C45C66A6B6771C44277BE0EB23471FDE8E044B42E4BE6ECAB5131298CB28F2D84B203FC23B11E299A8791F62F11C55AF2B318268CA3E2005ED9BF1A3658378FE8907A003075CA27D21B29A6A9F0CD898BE626D99A5890E0D003AD49F1F3F33240121D8E97B51A8CF8E054717A3B666E1C358E50216DE5800F99203CD87035EE27E75697D33EE1D6CBA9E0AA042F66949D3F3DCC759300D22C8D8F0E94EDA478BA664982E4DE9ADD43B794878D4B7BE0329B9FA942796884E6746B45BFE331DE0567FF9DD5D3BFCE946088BE0E8954E1119ECBF95E0B26410DC4AC6063451D5075B682154BEE1A6EDBC104E1F0BA765D2F8A34111738700A41BE9001275F5B5F43284848073F9523846D2D8CF64440434E4F30E9110C393D3687D39D4E09378C65B59EC8622E55FFE5008CBA1AF3040D6E4CB2D82E723E46EF0B118F5C07E58B35A11740A577D11FF93104007F8F124373D62EF1465F6DF37757E9671CD6A3DD2B017479DBC357E66BA2EEED7E2DD75FE8CE0B85E8E444D64323C94D9E79F3129D26E56E0AA867B07E3885A37070854980897E5ECB2DE436CCAE36B7FA1A57F1AFCC504738694540664B07B06E9165C29E7FCD14FBA4477F32BEA16C71AFC663E093F3B4203E0117343DE8801633D82B4864197A4D42F5FB74D11489B7E8CEB68493CFCAADA1A2606EA5D0CDBBC7590EE686240D864C26AD9DF83F4F29876F5B6F31FB82640D8D96C1B90BA762284FAD8815A331B4C130387D222CA5625346E746756E89CBC69AD9089D4BDD308F3B75B891C713E42D96AE01B31531D0D8246E722450ECC9C5D1B17ACA3927755307FDF6B6FCD08C230318EEC08808B158F82068DD6B1C2E4EABF2B0159919F47F28AEBB274B19EB53D24F11480E094DC8F021C208CE97F7EBDFB80AFA107699E9146F97D94D9A1DDE3514FB1BFAD630A2B4E7157747EBA080A6DF57831EE1336BA538239E61647B6603E3C3A99CDBF0F9776845295122A138CF07327E328ACF43E19F76C2B29231406BBF63541806F3CAEE5E0BA6AC0A0A8286FADF6A320D2389148FC80D652E46E52704BDA1BF4D10B813679FD47F28A7E784E43BB7B2D71E6E8BDA4F983EE655B017267F974C58C349EA1746CA6D4F09FBD7E07880F28F225FE65F25D50D78892D01EFCD58A9109B3C10F1DD9B9054013CD043C04E7DD4CD980"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY('max')), + "Z@u:Zßb©CãÜ,bZðOîU|hýAýýouöðAZÃC¢ðrÄ:+/hhb@ß*Öa B~ü¢£Oäv_uZbåC¢ßo©ÜCBuÄ_ß/ýð>r£,uªã: b:/oý>ß|ü. *ü~åuvvorã£O@üÐUu@<©äBã+ý,br.üܪ<@ðzª~åðbåöOãvîrUv|A>Ð,Ð:aüuªÖ@Ühðýbãrð:zh©uBßîbOh~ Ä>z@*¢Ub~ Z|ã.ßßb_ÃaÖ>:O©ª*ð:ãUÜ*ob¢ª:ÄrüååýäB+©aCa¢:~|rbhãÐZ ~Ðb@uÃ*or~ã|Ðüä|,~:|ýÄ@*b:.ß+rîva©*:zubv/o,ªßZO:ð,oBCAß_ýv*Ü<£ßZOU|bª.vO_rCã ð_ÜZüåüAßhýãß:bäZßß C/|ÐBä@hý|ððýubÐ~>@ÜäU+C|ußürzU,z>u>übOC*ßAUrbä~+ ZÜZa<äb:oåb_ðÃz@ª>a~Ö@ ..ArCî>+u~åaîzbßå*ð©<+~ß|Ö:å~:£ö|£>ãüA©ã.Z<£oU¢A*ªhäOuAa¢ß UaUÄ|Ä<öUßuããÃBvOåð£zh.@ýzßÖ ªAÃzu:ä©AðÃÐîCBoðãävoÐoa*, >UZbUåü@¢:ðA£Ðzöb AZZCäÄß@üÄrßz *ýÄbÄOÃCuÖC@z©.|@ãahãÄÃb*O|ß@ÐuAÐvÜÖ<ÜrAaz:Avå>@b,r+ßO>£Z£Ä@ªå~<_bßbå©bТüh_v£Ü:©bÐC@äu_Üh:ßbÃ/CÄü>rb:¢. <ÐãAö+¢åvä_o<üÃãvvÐuU©ö@aßZo~+r.zßAC+@ßÖßößãåüUýß*ßrårBßß Ahbý.,b+rðh|,b£bÃåãUBýä*AÄ@,übªOÄOª<öäÄ>|åߢªÜ<<Ð|£ a/bhhoüÃä©.hzöãu:OhãO*ÃuOuÐUuA£..ZoZB: Üåa¢å<à £övA|/ßh©Ðäüî/Ä<ãaýÄAß|Cýã*öOÄßÐ>îbzöaBýªh<_U>/*o@ßä<üzä+oAÄbäüöðC:a*.@ßðaCåzAå>.aÜ©ðöU_~rðßý,îÐO_ªCA.ýÖýüö<ä.|*v@zbbzAýäð.h<Äã@B+ÄÖ.Ö<ýAA©öýÜ©O£~@:bä©å>¢UBaãvvh.+<Ãßö@b Ab¢BýBUu>îr+:UÄãvÜ>+üOÖ,ß~.r>ã£a.ÖãªU.£oãÜ +bÖüCÜã_Oa©*ãZUZ,©bЩUOüÄ.BªãC*@Oä,zbªZ/£ZîC>að+,_ z+hÄ£üÐ ++ߢ*ýßbbr/_~a<Ða._uÄu¢ÜÄO~Ö+zZ,Ðö>aoO>_>r¢züaÖzå,Ãu/@ªhÐAîO,bÃÖîAߣ>:|ãðýÄ>ª ßÃ/Zäüªbüu +Zhvzh:@ä,ðuCß.ãäz/ßC@.uuÖBrÐoãb|zCO/|ªãvýÖöî< rv:v@©,îåÜ©ß@öÄbvöîß_ãýb¢Ubrîörî*>ýßðÜZä.zä£*h*C+ z+U£ü+v,£Z¢rýð|Ü/aüîo<£A,uü*Ä>åðß~¢ã©Ä_¢__haurzðb|Ä*ob£~@ý/££ðBb:¢O.v~~O@b@ü*,¢¢@,*z|O.h@©>özÃ@ÜÖbzÃÖÖåðÜbäuü©AÄ/Ãî.©hu©O*î~B¢äã_ÐrzböäÜ@/@< rOã¢Ü@ªÜBCªã¢@.äZãorA©u:Т>ãhîUªÐ*üobüzCvb:¢~:/.:ðu~+vZ_ü,åhaÜ¢OäaBZ_Ußz@Aöör~åvrb,uãu:b/r©BoC>/ZÜ~*oårCîb* * ,>ªöð+.>rߣuBbhu*ð:@ðßzðArrCÜ~åhÄCßo>ýUýÖhÐ >hU@rB/AhBå:ZîÃuöÜz<öÄbüäu.Üîýð~©@zZ*Ã>ßZho¢Ð:uªzAAüßv,Übv£ü©£CooZÜÖ~,ävZ>Oß|/u,aß<åööÖ.h@ubA@h¢Aý:/Ã:AîOÜà b~u¢bvüäOuru_+ªbOÜuÖ+|Ü|üÜÄ_Ü|ÄOU. |z~AÜ|v/ßÜUî äýÐ,_ðü@ß©©v_.Bª@AüCAbÐ~Ö:rBCýÜÐå+ÃÜã £z:ßÖ£ðÖuhOßvÖZÜzßUh¢BÐå,ãåð+OÐzÜr+£©uzB£ýubðZÄA/Cbå_ÄÃ|~~/îÖý,b,äbb+¢BB>h<¢ä©öBCä>vBãÜb>ßbBÜ,*£ªO©bu¢£ßaý,,ubÃð¢ ßî>Cö_Ba~_~ýzCßßAÃýåä>rÃUC:,ã/hh<:ª:hãÖUÄ>@bßãä~*©,îîÐÐZvÜär~*öbã£|@.ÃÄ~/_ÄîªCðo/oüðýh* r.@Äý_£+|:Uov O©üß<+aß©häÄÖ.,aBÃzu ýoaªåå**oåÜåCýZüo©ý +Ð+äZÜUü_*_äAýO@öuª<£:@vBߣ/BbðAzîövßozB£+ßß*îãCßÜaöb@ÃîrCÜ:hßå_hAðÐßî@ßv£ÐðOü@¢ býüßubb©+äöä> +ã+ÄBåbrA_Ã.UB£CrZ~££uZß//Ör:*ÐZbö/+Cå/*ýoov©z.rö©îÐ.h Ö/ä<Ã*ªÖãÃa>|©Za ãu£ã©/Ð*£ß*ü+Ãh|öý*ÐðbuUbÖ.:zoa|CåB©/Öa>_ABrA:öî@Uî|zð£ßöUÜðavb<ßßã>ª:hOüäråüAr¢ß@öbv/vruvÄrýBzýu*@¢Z Ðörå,ðå*¢öa+råö@äß<:/ßoßýüüa,bÐüoý O@ÃAßå>zbhÄz/AÃ<ÃoãîöÜ+î/üåü|uAuu|ÜaoÜÃ|ðBåvÃzî:vü:ÄãÜ:ðZüruîhO,ä+Oå|.Ðu|Ü|¢ÃývC*bCî©:hß+bUÜ£î~öÄåãðÐ~Ã_Ð>hårßUZÄbääavÄ,U*>>Oö|©O¢ðßh ,Ü*|oO vª_ãöb~bÄö/O/Ã+br+Üð<Ã~å/o+ÃB>/B@büÖö©Uîý¢:©>¢Ã£AÃor,vä~a©,ÜÃåör> £*Ä¢h@håöãuð,ß:Щ,*UÄvu,ÐZv:rB©vOoü ð,|¢b> a*Bvª öu_ävª,hzåãvéãOüÖußCßvãÐOröuA¢a©CvåC,î|~rª@Ä*+ß<ß,*bßuhöÄCB,:îZvߪ|.öb|ã©UîrÖh+ß,:.£vüåîCð.Zßohz UåÖß,@Öß>,_zör|Ðzaý>¢ýäЩzA©ZA@Cªä>U¢üýð©ßÖ~ ~oÐã_>hhßÄvAAoB>b_<ä/ÃBÄ C AbãßuZ.boZßÐ@+üßouu~ßî.~vZÄåîba>.OBböîbТBðrvßö><åöh£v_ð~@oBvz *ZîävO<üÐür :*u.aC_,å©ü/Ã*CoBðßðö>~r|A©Z¢~Üo/öB~+CoýÐî/©z<.£__äAzb*îãBÐC©A<~ößãOhÄ.ĪZÐåîo,¢/hÃÖäðÃBuuýv_bä/©|ßÄ£U>ãCo/a :ýÃÄC©_*ÄÄABÐöðÄoO_/Zu* ©ýr¢ä£Ã<©ÖÜuz_.+zBöãߢîZ~Cöüå~bu£*bh:ð>ba_.ýOÃ,¢ÖOCrv>@AbðbÐÃÐ~BÄ_|ö>Zî,ªåßUuðBåÐ uÄ:äüoßab_äÖ+ZüzZ£C/C:ZÄ~,©ZßoãOa+>å¢ã~.h>u+_ã>_Zî¢/ÖZrÖ/Öv|<_OîÃÃÖaßBÃ/bÄz¢UîOÐåhað@,.ÄoÐ/å~aö~z ©ãB<ÐOrr+Aü~@@|@Ã*_U+ZvAäb£ßäbÜÐ îu £,,ßÄ A+Ö~uð bz~bbö,~b¢Ã@, zvUUªZuäZöÄ_bvåZZãÐ<ßÖO©vüãÖªÖÄz ýÄC> ª¢BOA£*@îCÄÜ*äßî_|B|ý£:.özã~ðý.£©@ðã|Uu~Ð/:C+åߪ,Öã~UößÄuC,/uhBãauãå_z:ÃC,.o:,Ab>UOOhß,ÄÄr¢:äß*ª ªCobîbbZh<ä_¢Uãb ðüüðÃOßhO Ãaã AßßãvåaªOBîý*_OBöß+@ä+£.ðð ðÐÐ,ZzhßÄß.|r ßäAÃãZöb+å¢ <£O.ð*_Bä/ĪÃrÄ:Z_UOO@~Ü,ubbü©+@£ý©o_,Üߣ:höb,aÃZ>hrbOüÄ__ðîbb@öbr¢ýU/<<å_äOãÄBh+ßðhCvZü/vba|åÖªðOåäÖA/ãa£ @ ßåã:Ü_vC,ãÜð©_ü*:îýßvv©ßu, *bh:öÜ££,U|Ü*<<_*BöB<<<|Ö Ðb_rau,rðbU,ãoAî|Bîh£zßÄ ÐZzääª|ĪA~BrU ,o|/Zövßb|ð+£¢Ã/vßåZöB*b/éuC/ß+ä~Ð<Ð*.+:>UZöuðBð~ Zzü+Zß@ýªZA©¢Ö_@bårÄî,@ß:äbBuÖ~z@C@bîr:©r*ßB/ߢ@.ÄãuÄå.åÜoð/Ö/ÜãÃÄh>U<¢ä._>|~/+¢U_Ã>ð+ª£Ä£ZÐZaðÜ~ü,ÐÃCZðBýßo+äZ*ÜZrrÖvð B>ß~rå~,ªÐüªb£öCUÖ.ð~/vä*öüýßÄAzbb¢O ÃÐu,,|£åÃZC*BöýäýÖ£uðUUîª~åÄ©_ýAÖÜ|Ar_Oå¢ü££ã¢ÐÜA/bzüö,:BÃýð_ª.vÜ£åä|ßÃ@ÜÄO*aaÖCÐßð>.u_£Äð¢å<ö,Ub©<ýÜBãßÖUbý@åßüåî@UZaßbrðaüo<*.©ýýhÖOýU/¢îZÐîöb*Ã|£~bî¢a*äÐ*O*o_+ýß@©rÃîZß©C@*Züð¢:ðÃãªb+C.zUåUvÐÖ*îo|Ã<äÐzvU>>a|Ü.|åUã_,Äh|ß+©,|,+Öý,ß+ðübö@*ãäª,Ð<<Ã+>ðß@:.hÃ/b< aß>|COZãåaßãUîä ªbã¢~A.,î|BABÃ<ß__ß++ßãªýÖü~ßC<ö>uå*uãÐý,C£|bvÐr@azÃB>üßUu¢ãbß|ßbo@åßh~ÃßãýUhZ_ÐaÖbßßÜãaUbBýuåð|_ä<ðÐä.+.¢åv@Ä©üÃîãZÖÖüZz@¢ÄA~<öî.Ävߢýh*Ã,Oî~<_,hz b¢ßÜåOªuUà ßhö*Bý,obîÄöb+Ü,ÐAbzîZhîvªð,¢aÜå©*|büu+_ýýU/ ÃÖ.BßäOO+/_abB>ba_bCßZÄßÐ.>©@zîAÄ||ä@ZßhªÄZîaAðhå<ý:rz@.b~*++@£b@@Z<@£|ÐÄî@CýßßÄ>*Üb :ß.Aoßðð:ÜBbu,>Ö/¢UîUÖzß,.vÜ£äAÐ~ÐbÃå:*ã£ßUC.bÜ.zöbÄ_oBÄ>¢£Ð_hv~Ö*:>zßåýv.v/>O+ £ä<Ãßzr/¢+OUߢz>_£+bªvB@bb:Cå£r vzB©©|Ü:oaäöª¢O£CÖîãßZÐ+Öö¢Äãb|ýoäý>@¢ãüåðî~.hð:îßaCÖ+>ü|ÄðÄöbªB:åßТ©C>ðöüå,oüªAOßbb:UÜ+AößÃhaß ßh@*OßU©@rß.ª|.Öz©Üv_Aa£A+~Äzßßðo|~a/vä*|+@v/+Ö:@b,:U_ÜÜCå ßu@+Ð,äUbý,zAß.Ão>Ör£¢hrU, êÜßî|öbhAaßä|CÃÖBÖZ©oÄå£@ð£bBoÄO/vÐß*vßbz_Ä£Caî>©b_ßCvãü©CÜÄ¢ÖbC©~©:*üßzÖðAåözå©+oßA¢åbO.ÜhU>C.|<ªý@*:hÃUubOUöa+uB <ðA>ß>:.*z* ðahß,ßåö<ÖÖa,ßö£:CrAä.|ä©,:©Ü_£bäÜ,:ßuBýª_|ßb|/ß|ßöUC :>/vhý*uoðCÃhª,<äuar.zäÐßBü¢Cüª.ö_zåa@BB¢,,£Ä+/ß/böÐuîðo£Ä:AaÐCO ÃÖªz>: hî~aîra/©oOAaårAªoUzbbBîZu A¢ã>ð¢¢~z îU/Ãa+ä_Bo:>Äýhvovbß©ÐÃåýßã£U,,ZåÄÃðߪbÃu*Obå_îã+©<+><£o_|Är@rZÃÜoªaZu<_r,~ _£a/ðýZ~ðaß,b_+uîäoAb>vÄðå|hrðoCî ªå_vv_ðÄÖÖ+rüÖãU¢ u|Ub+z@A/h+ýã©>Äð>ã~¢B*Ð@ Ððßzözãå b|@UÖUBÜ ÖîÃÄUã*|ýÖª:îzäüÜB£ã/Ãaßo£*ü/î*@ Aýª£aÃüö, bZäOU£Züh:ðîbåî_ª<+CB.bhå vzÜ.©îA+ö>z:Bzoðrb.CðÄÐrÜub,bß,AßB|ª£bßãbÃÃB¢bU|üî+ª©Ä>£A bhãa@äÖ_åaB+|Bð~©a£.|Äýa¢Ü+o+~*.öOß/OßvCUª¢ßãb<_ÖaãßOhZABîö_¢>¢<ã,,î*ßZßbO.<.©o~Zß.*Ö@UßîÜ väÐ>Öüoý/£~OðÄAÖaÄߪ/Ð*UßBvÄ o~a~<ãÄ/£vb|ª:ÄB, AZ Öý/@hª£a|ð<î.|<:äýaßãA<ähbAðª+ðbßão_bü|bb/B*ª©råU£@ A<>Ä@|+B~Ä,Oa,b|.ð,î/üÖ,ðCv<ähÃüä~b* /a>~::*bî*r~¢:zvªîbÄCÜ.zîu/A. /*ÐUüðå ü>,*AÜbîUÃ+ÃU©ý¢u£ªO©uAz¢~ðãã+>++Zö_ ÖÖ¢UýýÖ£ÄbÖ+BA zÄ£Ð:BÐ/äubäOa üÄ/z<åýöÃUZ£î>o<Ð*ob©¢ubUazÖAöh|£,CAðß|/ ÖüAö£ >*b:|uðÖCÐa>,C_ößÐÄî©ÐîßO+bv¢¢_ÄÖÜ_~ÐBäCãu+:. |~u+ÄZuЩÜ:vvro£CßãÖãr£ä*/OZZä:ßCåßä å Cª/ZvªU zZã:O.,Orüßåýß~h@uÜЩCü.ª<Äh.ð,UBCäý/.Z,ÄÄ¢î@a*zazÖAã>£r /ãÃÄvÖv~~ÜäöªÃBö,Aö>båªh.hCO*.ª:©©a~~©:ü*zöU<*.ª£b/<ÄÄv_u|Zh¢BuoO.Zö©@+Ä|ýoÖö+£bÄ>@výCÖü,:*a, UBÜbbb<öCÄÄîÄ|@~äîu.h|üOb© _rO* U£î£OZ~ýU|,|vrA.ååЩoÖßZ,UBu ª.*ßZhüäÖÄOAzÃo¢äßb+B*ßöuOãUÄýðUZv*Ü+îÖ>©:~£CÐ:ð/b_Z¢ð©ª<Ðð/ßåßh|_©ªh|î~hüÃåß|ãð, h|ª.ÐãÜßUßÖröva*o,h", + "ä/+£uÜÜðîaA<ÖU@hßßãzzBßðA.å:,:ß*AbÃob", + null, + "A îÖo:@Ößa~zrýÖÜ¢/¢ßîz@:rÃ/Ä_+BÄrãZýObÖ|îC£+åZ_Bðr:a,Ü >*üö,îZb©äãð¢,~ª/ªÃªoªäb,@ßä:©| ßbîZå_ä>:<>ä©+ðÄ ~A.ÃoOå<î_åB/ªýZ>C_Ü:>@ZýðÄ*hä>£:>ÖåÜßCß~/uÜuåCöör~<ÃÃA uÄ~z©< Öªä:_+ßåÜzîbßý*Ð~ý<Ö£bUr|rßb©@b obv Ob|~C ßoÜ¢u åýazrЩÃ*£å _ÜrUu~îÐÐa__.î¢ Ub/ðü>OÃ@ÜC.,|ü@oUA C~öOÐ>~ä/<åZB*/Zuü*bª@Ð::< ObA+Oåzr©CUr<îzUAåß bh©zråüЪã>ÐUo.ß.BÃ.ßoÖOüÖåhZZÃ|¢oZA+ÄOzî|ªã¢@üz>>ßöO.@î+>*/aã:zoðBbå+/Äî,>u_ð_:ß|£ß:Ð,u£,£ä+ÖzbCZ©Ä/î/CbCAßîZ*:üå£/r£ä._ä/>Ð|*ob/CUUãAåh@Ð*Ä~ *AOîð@vu:. B_Ãöäb©î@|åUÄ£*hð//.bÐZ.©a+ö£©Ö ra<©ãüÃh+:öZö£Cä|,*ÜaaZ*UZväÄÐväß_bÄo©zöÖzA~ßa:aî>+vzüzrÄh/_Ãß/¢rb<,ª.ÃîB,AÄüÄ_ußvör*ý|ãUãýAuÖvðä,+Ð_b,>ß:Oîö~Ua~rÐ/åUZu>£oÜ.©© hBä|*ßÃÖä/,îߩ壪ý/aaãb¢Couåî¢BhÜãÖãЩ£Ü@ü|/ã+.ãÖ>o/u© zbu/r~ßäu*vCöîAðð ©>bvªßÖÐ,h,<£îC@:ß>U:rÄB B|v:öÄ~uC|ovA:/Ã:O©:ÖÄ+ý//U.Ãä:Üöð>ußArð Zåßü,,,ßzå~åð~_¢ å.<ýv*,ܪãa ª+:ÖÃ:ö,b_/öO>au~zbaä:hÜ: A_/OÜ_+>Ä>ChUC~UZ ý_ßÖ*OOZÖý:hUÃz*/.öäÜå|Ãß>B:bü.¢OßÜî@vrvý<ß,b|v/ßîÃOz.|CýCüãbÐUß|ãü.î,ßor©äZBo¢uU£¢ovUzÖv©ð,Z+OvUýßrªã@.B@ü¢_vaß<Ö~.Bb_ @uou<.åã<ªAC*.¢,hrbÐvÃrý©Cð_ÜÜoO/>Ã,Ãzö©£hhöUî:bhOZåaßbßaO|*>*bÄ:ä©äÐUÄßv,BC_vÖÖ£ä.~Ð~Ozb.>+uª î<:¢ªÄöZÖ/ßÄ£ðCa£|ð<~¢bðå@+~o ©OO:Av+ü+ðåhýbvÃC.+U@hhövUCoßÃ.:ü/Ã+äb<ã£ÃOý~/¢A©r,öuðß_bUrßhro©>/O|*åßbö@ªãöh*ãªB>ªZ>£ÐüC/öCobãÖ£_A*OAÄäAÜ¢ÃåU©ðßb©,öÄÖzåA/ UÃ:U~ßbîrzü:aîh£Äª aß:h/.:ßðÜÄCr,b~C~vÃ/_Ü|AãCaCh>ãßä£vß**AðÄ£bZÜ:*¢,Äß.bbß::Ö:O>ÖÄ<ßßý@|,Ð**üh||Uv+¢ß,b*©vo£Öðß.aý Co.@å*_ÜÃÐu/©öår>b|Ã+©Co_ßåß<îð*üß/.ßÐÃåÄ :zö/bvýb<ÐzÜßå<ä><+ÖªZ,Üz<ÄÄzrðÖ~ªå©äý+|Ö.ß|z~ã|*£O.*~ÐoîOh||vÖZß_OOýßa@BßýO>ã:Ä¢o+©a@.aåÐÖ©äßý>£>ÖÜ,£|@£©z@~|£bÄ.ð.åBvvhOzvb £Zß>@ýbà ýªãA*uå. bÃü:å~ª_U>£r Z:zaaÄbA©ýAbößbbîbUÜýr++r.uîüÖ~bC£z+Ä ro*Z.Ãð+ðÜ_< /,/ Bböß~>Obî,üüZ>©+~ãb/ÄÜÃ/ß>/*>/h£ÃzrZÜ>ª©oU>zü.¢ZåCÐ~za¢z,>aBbß|@¢*ÃAb£C£ý>@©*îÐoAaA~Uå*oßÃüªz,< ~ÄÜðÜv ßZrOüäAr/ö>ååuîZÐý@U*©@*ªarb£Cß,ÜÃrZAÄ+zÖ>@£ß@ªB©/bðvaüoÖä|ö©ö_zCCCOA¢va¢r<ähä_B.C.ubîCÖÐb_oh/¢ßör_©,/bbOAzb_Baåz<_|_ Ura*/üBBår|£îð åÃüA*Abªbr¢A£ä©åbv¢ü ©býBübhC<årB|/ß|@OZOªüoßö/Uuz>,Zöýr£üö,üî>|z/öb.äz|B ßÐÄåOo@ãðßý>îh|uo~~ß vB,ã+ý+ß*ýðZüov>ÖÜÜåCýÃ|ß_ß@OÄÄýzý@¢zbßOoa~ßbröüzÐ.ßßîuZ,ßAãO㣣Zöýü¢¢OÃüªÄB,î>ª~ãr:zîO,ÜUu .U ¢r +ÖªO,.éüª.Ð:+,,ª>_î~bar©*ÄoªÐ£©Oªo*ªÜüväAä|Ü+/hðA¢ãBzÖzÖ,@AÃ@bUöÐ|ãuAÜã_vb_r/.Zî~u~Cß~åäãªrvð~ ý¢¢bߪðîUßzßvrC ýuhBZÖ¢£ÐZuAÜ@<åoª|<©UÃC_¢_>ªÜß/üoߢ,b ¢h*@ßuÃbb Bvð* Ääîã|>oh:C C>ÄãÖü /*ÐUäO¢Ä >üu/O> +ðÐu/ê<ßãÄðäaaÖCö>ý~:aÐuão©oUÃo¢o*îAÐåÐÖv/A<Ãä >uB<©>Öîðýa~_öz|h_ZéBÄ+bÖUzaüv@ýßOðhuÐ.ðv/îöÄ>ªÄÖ,.ðboZuh©£ß_/+hB*CßoÜ..ß|åý@A U©>b|:öäUå/vßB¢+ßbÜä++ß|ýüaCz/UBÄî<äã:+ÃöZu+öö._uC uUzBð*ü*C¢©î¢©©:b,ABªuÐåBÐrßuboZrCAã,ß|@äBUbv,ªÄv>+oraÐa>/ýrhOhb:,Ã@£ßbuß@u>ü©¢ÄC>@ÐÃabO+A*üß*+ÃüOªäÃBb:/h ©ÜuAãßZb¢©.,:z>hªo_ZÖA|Üo_Oü:ü+Ää_UÄUßAvbr~CãÜîBý¢üîåO,>üaåuãbüBîãßäo/ÐÄhvu_//ö,¢Býßa<ã©hÐÐUîß/ýu>uaöbö_åUܪöãb_b>~Öbob/ýoÄ.Ä>ßzãUzöuö:~h:öÜÃuÄZ©rO.UÃîb.ÜaÜ @ß+/:ÜÃ_C Cbýª¢uzÖÜ/.Ð@ .bo*U_/ð©v¢¢| u/aÖ|åb*UbväCAu*îÜzbA,ª*Z~år,Ðüa£ü@ .©O¢ZbßbB+/.Ãz+ãz@zãß©<ýaãü@CUrh@åðUª©Öý|_vîo:>b*CÃh©©>ÖrO¢/bzüãOZîß+hU£Ö vZ.|ã_*îoý_b<ã+Ob.Azîv|.Ðä|ÃÃuåb, .u ¢*BBOhýZCßb/Obߪ/.ýÐaßüý£röB>©h/oä.böuÄh~C¢b>v@hb:öð.< ß+B:ýråß/©¢v ©Ö£uÃäoåOð>+ÃßAbÄua©@~ÃäÜÐöÃzr+äaO ÄUýa:*BüUvÄ._ã_<îu.+,vazU£ää¢åöÃßbC@Ð:OUÄCß@Ð_+¢A@£.üCö:UÃÖßð£ã@b~z/:ý@åUb:©+vrö@vvhî~ãC~ Ãð*vÜBãåBåÐß,ßä:~z|@|üuÐý£,Ī>ÐräCZª@ýv+ã>O uÄåUð~AO©bßî@vÜî", + "2001-01-01 00:00:01.000", + "2079-06-06 23:59:00", + "1973-01-31", + "23:59:29.04987", + "2002-01-31 23:59:59.04987+08:00", + "2002-01-31 23:59:59.04987", + array("0.0559234", null, null, SQLSRV_SQLTYPE_DECIMAL(28,4)), + array(-1, null, null, SQLSRV_SQLTYPE_NUMERIC(32,4)), + 1.79E+308, + null, + "9223372036854775807", + -504945714, + 32767, + 182, + 0, + array(("08757ECC341053DABF2569D352C8B231845DD236EF0EF8D319BDB26902F0047C0441746578A98F5C022B6B06EE2005B1319ED0CA132E5CFA7CABB3765DEAD7CE20ECCE11534CB8DACD7633C3A3F2E4F8B7013764203A68D5E57AE8CDF618FF18539CE50251F45EE4E5F5FC9DFB98568AC6BABF5CB273AEE683F82CD863EBE4B5771A70060CE2A6C3A2527F2A3DCBDA4C245E073B59A366E0EEFF7F59C88581F9104726E028507DE314FBB95FF38"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(384)), + array(("D70B88DA36D29A75543D70B1B19C21FDD2131F4DA64F47BA35813FFEDE19131275C2EA0039DF1FBFBDD4F1E65CB4495502977C92AAED3287C4CDA4B5929C973B295D3CEFB221C4F2F46090D15E615E8137E9FB469C8168878F623C6C3B692C213DB6BCFE775AA2E1D28A9D4A5D6028626E227DA9A0509EA8"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(384)), + "Z@u:Zßb©CãÜ,bZðOîU|hýAýýouöðAZÃC¢ðrÄ:+/hhb@ß*Öa B~ü¢£Oäv_uZbåC¢ßo©ÜCBuÄ_ß/ýð>r£,uªã: b:/oý>ß|ü. *ü~åuvvorã£O@üÐUu@<©äBã+ý,br.üܪ<@ðzª~åðbåöOãvîrUv|A>ÐãzZ/aÜB.U>ÃoîßAZ:Ã,Bîa|ß@Aðýå©r,Z<üîß|©ý¢äãÖ,aZÃöo/©Bb~ãÖ>ðüãC@~Zzä/äC:åa.:boß.>ÐuAÐu@ZUîho £Ãh@ v:boäããÃ_£Ã~@©öb.uªbß*ÖAª_ÐöCUzvöÄî *å,rA©å~©+:uUu:@/_îÄb_ Bå|z .¢ßÖªÖb*uåÜ©å/öovÐåaäÐ@Oý¢Zß_Zz:+_ob_Ī>oCz_ÖUߢªoãoÃZ<ÃB¢ÜýåCOäÄüª£rÃO/brßÃäÐððUüv>Uܪ ðuCªv@ýüß>£aîz¢©:ý¢/z©ßÄ*Ovðäêð*vÐý~~O_uäå*bðAð*~AvooaU.,vBUbBCåУ¢~£båßbu:Ü/¢.h*~v£*ÖrU<|O bZoÖÜ:*v, Ã@o", + " ", + null, + "o@.*ªv~ßO~Ö+ãßß:zÐ|©C~bU.b¢vß@Ub£öüýå+ü¢A~ä:b*Cuåö@/b~ã|Ä,ä Ü,A|ÐoÖÐrîb©/£*Ö|B ,öãoÄu>äu Zö~r¢,BuUÜ|*a hªöCîaö¢b:,ðUz*uz@.å¢CBUAü£*ã_ã~ãß~ª_Ð ,©äCßÃoßäaöUý/ ßä<ßbߣÃC~Bã¢,üÜî*hö:ßh.zh£ãößBÄbî@.ÖbÜ*¢Ü@ß@£.Uå@hå~ãoz/>åð>Aö Uv @|O+ãrª+bAÖbO:Ä*,åuBC.,/£îðaªãr|vzîÃÃhzÃý:bZÃ.Ã<Ü©_/AouBoÖÄövªÜUãOßå|A©v|_C£ CÖur:UðZÖ_BBß@ö.*/+Ãã:>ªßðÐýZåÐß+äöb£ÐÜÖ>ÐãrCÐü>£v¢+_>ðaåbA_A<öð¢¢aãå+ãäAouv/©+ ~Z,Ää+UäðörªÄUÐAÜð~<ÄhªZ.Ö*,v©|u©ÄöÖBUbU+hîöoUoß.r>@båª/©CzBaäªv+ýðýZýö_ã B|U£Coª_ýbobhÜC@býðüU@_£|o o>.vü©ÐÜArAýh>:å_B ãhåÜðüªåB~a~Böã/b|ßr+.ýbzAýß<Ü£a_u OZÄ>z*ߢraªöAZb.zÐîü/hß<åüß, öab䢩h b<ã|ßßbÃBü>/* Z£UåA_bCA|å@vbA|äv©Ö<ß*U/ £Zo:£üUaßCÜuhß©£Ö/.:Ã_ÃãÖ<üßbÐoîßü|îîvvvîߢCäBßbîßý¢B~ ÄOa*,o Ð>üðäÃO@>O.vßbC+CßÜ|åuÐ_ßr¢äÐîðäB~bhhðuhå+zßrßÜZ~ßî_¢ª/@Ö/C©b ߪU_OrýýuO~£Ã>îð ý/*vîý,U>o@,Äß|B_|Ä|©£~ZªªÐüýððªßChUÃbåªäzÃb:~>*a_hðr+©*ãb£zv/v|uî|~à ,<©BÄ*ü@ßaB+ö/ßý.::Ü,¢.~ .ACã_Að©Ãh©vC£z, U£uî<ãÜu>ChîöÜbBÖZ ãÃvýOÃvZCÐzßo,b+Ü+/ör*ªbðÜÖÐ+¢o*+ý_£ý£Aru_£bub,ð@ð>~ö.oã.+h uÄ£ÃCäªßUäö*.AAäA~Ü~£vâoîUîß©>ä£/~Ðoª/ZÐÐܪCZbðhýýî~rr/¢*ý+@:Zr<ÄÄ<¢vÜßööî© /<Ð~bª @ªZ:uoCߪbÖv:|C,~~zäuOö¢z@BOåvÜ:äüÃå/vU:oýråO¢uÜzBoýÖÐC ££oÃböî*Zz.<åUöz äÄuýb:Ãz äßBßÃCã+ußC_.ubãªärÐîboã©îAå ~O<,ÐbCU>¢z£>ahrÜ/AТªU _uä>A£*+ä<ªÖ.©,ð©>bvÃr@¢ßv,zZ_ã,C>Ã:ªå<îv.<Ðö~îðBBbC@ý£ ÄuÃÜvbbz¢r¢ðýözßAOýZÐß©u*B¢rðªz_Üö~ÃðZ+@b.u¢@o<ÖßãÐZã,/ r,:åzüä£ßßr.au¢ObvÜ<ªvã ¢ä+båaÃ,@U<_ßÜßb~hoýãhO£@öaÃ@.ÐÄ ßð.aýAzUrB©+vOou+_U.höÄoC~ß~ßA|ü>:Ãä,A~BãУb@ZvÖãzß öo|,Z££ã bÖ*åÃ_ß,/v@£ßð Äß~|ªbBhýbvßu©|éÃOÖv:bÜCß/åßuÄbÜo>_öîUA|ðrB,~Ö/öü.bî/ÄÖCöî>ЩOvobýðC|Zßh¢O>Ãzý ZUª| ý+*ßÐ/ýaÖzåÐöðzªßz+âðZUrbßü|uv*å<:©Ö£bÖÖýý<å@Bhr*UĪÖvý*Ü¢ý:OuÐC<£>>Ð|ÖUBa~ãv*ª@, +v|Öhu< üAbZ~Öv*,媢:Ü><>Щob/Aß*:Zzäüz.CCîßãßbßüÄüüa+u¢ä¢~+åäýÜÃÐzuãßvßÖ.C:ååÜßOrý:Z_ßýU©/U,ð_UhCCB<ãýh:orªUÖÐýäßr©å_>oð ýO,a/ßäå ÖÖ©z uãýC*rÖ<ð/,~Ðä+ªªüooäßÖ/Ð+Ð+/ýUO>ä:A_,ßÐ~@UöªãBa>ÄhÜ>o<,b|,ü<,AðrrBä.*buo/|*|ßßåvÐäÄã:à ,böüaãvrÃÐ@zBÐ@Ö<+,BuzO+äUb.hAhÃbðã¢ÐvrÃU>o@©ouýåýÖuÜ|Ãzåuv~Oz*£ªãUOîåAuoÄãÄo©ÃÄAB_oZðð>u_Ö@ý¢>ðo>îãîbBýö_bbÄýhu@__BÜr+ÃðÖö+h@u_rð|©Öäßýý_rÐääÜU,@ý:b.oöhuîoBÐã/ @äß.<<©Ð|BUý¢ßbüÄü¢@Ü:ÜÖª_@ö£åvÃÖ.*ýüßðbzÄ> ðü>.ãO,Öuî_bbbßööÄbÃß_Uu:býåb|ubü:ã£ACC<<@:ãäzîðýüC~£ß@+ÐZöÖO>Ä©Ã>B¢roî㪪rzb,*oobåb:¢.hö:ðÖo*Zýßßo+uZÐãbZüA¢rz öß~Cª¢ubböÃÐUo©vzu>Zuüöå baO£+>Ðo~ß+Öo+O~Bzvªa~ðªÄÄ.ÄABüãÄß_¢b.Ã/ö|£ z>oãzÃh©©Z Uzß|@buÄðß ¢£ð/ãåZÄCu<,îîß+Ða ýð£azAß*rüã@££,+BOBîåUübZÖðî©Ð©<Ã~ã.ý£ª,a_bÖZÄßÖ@@Är£C/Öü~Ð|CðÃ_ÐãÃOräaÖää+b<Ã~Ö/ |zo©.¢ãuýCÐC|/ªbaü:/ÖÃ@Ãö£åäUä.ßbbUO,b/b*ýäåAÐzð//©¢Za|äß:ÄÖÖüüCÄöAb@++ð*©z,AÐOBÃãÐaÜÄBîðßboß>.ß_oðð/üüßbÐ~ãbÃÄb/|@>u,A<êhà uCäU@ãåßv©ÄåîübCvßUBüÄvýð~hC/ußãv>ߪÐ~|ããvOåߢz/ü*/ßå~*>ää ðÃÖ+bãåª,o:,©v,UÄ_+rZvÄobÜAü©h Öäv¢oBåhbðAîv@üÜ@<*£ü<©A£ý~zvßîðUßÃ_.£Uhß. Zv+/£Ca@< >+vOuüo@~åUaB£:ß/+åUrß|o,ÖZ_öOUZ/~Ö:/*O©b¢U_BvOÄýãã¢Uh©ßBÜ:â|,¢ö|>îý+bOuo|~AbC~~|C>~©O:B£ |Äü:bãîhéßý:ª<.b~BÜA©äBb:îAv,bß b@:UÃ>ÐCð/ðÜ|£îCvBåaäzîäå,ªöäåz¢ý©.bao,b*©BUö >ßaîaZoß<Тª+zîßUbCzßîUßCBÄߣrr©î|åÜðöäA:Or©:.ßBO_.AC£@ª~rßî|*ov@öÃß.CäjklãªÄ|*Ãz¢¢Cßo_vAZrÐoöÄý©b©CäbßîîAãBªðÄA<+./ßCðhhU~Ð~Ü.ãýzö~/©z<:C+Oîb*_+ý/ßBZr_C_üª:b CªýCZýh~ßbðü©ÖÖUBîb+ª ¢ÖÄC,:îÄÃA.Üv|îöb|U,£ÐOz@ß+zåÄ.ÃÄßýU.O~ÃÃB*å|å~>oZýöªvAaîßz_ZBå.ýaö¢++¢ÄÃ:oU|ÄZ£rÃCÄ@¢îå:ZÖoü+ aUzo_/ߢh©vvhBß", + "2919-10-10 09:15:51.361", + "2079-06-06 23:59:00", + "1973-01-31", + "23:59:29.04987", + "2002-01-31 23:59:59.04987+08:00", + "2002-01-31 23:59:59.04987", + array("0.5650345", null, null, SQLSRV_SQLTYPE_DECIMAL(28,4)), + array("0.8713", null, null, SQLSRV_SQLTYPE_NUMERIC(32,4)), + -1.79E+308, + 3.4E+38, + -1662199111, + 844364759, + 20280, + null, + null, + array(("C29E82197DEC94CE552155C089AA21684D34BC1CF1BBDDCA0DEFE4FF4511ABBFD7ECC6A53924BB859B4F53B92DCC8C50B5BB91CD719E0307C1B80B8E089488437696E89CE37B2F28793780A267249C4062934A897FDE4D39E9BFE481182C7C07C6104396E4EF6C398C69543A1D60A09D1BCB2B754AFFC39749AFB22496AE0F4CBA78DC57E0065C732610FD168A131B891E47654D0107BDC74CAB4D343D48A2DD59077FA48448BC156FB84E3901AC0C369329054F48C24AB3BB150A34B2"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(384)), + array(("36B339B858052C119C386074D06C3359AC02D92C54BAC66886F0014A8550CFBDA489336F2C291033C13F213739886E213C903B9FCADC247BECD0316804E18B4C69A3D04639C42C83F1A66B15988F2EFD81DF0EF5142FF2C764B7825BF7A72FE0B3D4CE96B827E87863B8AE23710FE25DA234E624D396383AB008E28141D08B49778A62C3C198445AF795915B81CF5655D425B9C3C10A0D1C9C93E5B0446736922C64ACE6AC1E9B09EF8C2D3D04DCB9E1"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(384)), + "ÃÖÄZBvbOr@ü/î*ãzZ/aÜB.U>ÃoîßAZ:Ã,Bîa|ß@Aðýå©r,Z<üîß|©ý¢äãÖ,aZÃöo/©Bb~ãÖ>ðüãC@~Zzä/äC:åa.:boß.>ÐuAÐu@ZUîho £Ãh@ v:boäããÃ_£Ã~@©öb.uªbß*ÖAª_ÐöCUzvöÄî *å,rA©å~©+:uUu:@/_îÄb_ Bå|z .¢ßÖªÖb*uåÜ©å/öovÐåaäÐ@Oý¢Zß_Zz:+_ob_Ī>oCz_ÖUߢªoãoÃZ<ÃB¢ÜýåCOäÄüª£rÃO/brßÃäÐððUüv>Uܪ ðuCªv@ýüß>£aîz¢©:ý¢/z©ßÄ*Ovðäêð*vÐý~~O_uäå*bðAð*~AvooaU.,vBUbBCåУ¢~£båßbu:Ü/¢.h*~v£*ÖrU<|O bZoÖÜ:*", + null, + "o@.*ªv~ßO~Ö+ãßß:zÐ|©C~bU.b¢vß@Ub£öüýå+ü¢A~ä:b*Cuåö@/b~ã|Ãßã/©ü|ªZCýÜî||©o~rßî*/ýßãßUßZ¢ßoOÃ/A|Ü_@O<ü¢BÄbãåU£ßªª *ä¢ßo ßa>OªÄåh¢~ß©zÄå<*ÃhÐ,öAüý_~+BOðü+r,:::öÃ/ðãü_", + "23:59:29.0498764", + "2002-01-31 23:59:59.0498764+08:00", + "2002-01-31 23:59:59.0498764", + array("0.5650345", null, null, SQLSRV_SQLTYPE_DECIMAL(32,4)), + array("0.8713", null, null, SQLSRV_SQLTYPE_NUMERIC(36,4)), + ); +// 15 +$values[] = array(array(null, null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(256)), + array(("6459515CEF4E0D6C859FB097528CC63596AB884B918D383E578B8B0C08089E77004EFD497BEC6B3CF1DF4C085DBC4CE3095D796636C29BD721130563C200637D003997038E7CBAAA404C59B1402FE09A3EA803AB8E37403DB2262868E70779F07BCF07242549548DA3CF26E968EA97F1326A2519FDB8EE4395DFE74D34A29A88"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(256)), + array(("74CAA0F9F2809B93DDAE0780559B56596F6507A60F978E6DD62B0FFDEEA0212F8A135DD39A5126874D95DF2A7D4D92DE1C492A23341F3CDD3C3323C6709DA53C8DD7F5423E83BE1E3E805879B863EF889931E0A576FEFB6BD68097672E6016AFEFA29DA5584FA0998A0CE5B3C7C224D8439A2C3FBDFFC68FDC8A6BBEEC57EFDD69A88A15C649304A90471B6A1847A3145BBE249434D6F2EFDC0EC9CDE3E2AC321C07491E380E12F969E1AE75E45C7694E656622D335BA993B69A38B7806366AE9AE84D11FD85DC4CAC2A2A52277C0B809834E68C7F7FFFC05EB6689DD65A78067B00DBFC0E6597617A15810830566C398EB81F4B7CD92F1BE88DB2471C3E7651B124D727A10E72329D851269FEF68F074A2F0E1D3A2D8AA1D0C01381B250443B9E2F560C7F44978045EDAEF6C7C51DF2FDAAFCED2F5917849A3556E1FBF17F4D40D7CBCEA0838705978ED74D7F93DA0BA221830853570B4517D2724AEEB684546D61B6F0FA4E517922F755A181C905065A4A3EDA6D77F9E9CB85B6CD113D17E10A83E01EDDEA1154CF0AE55C016AC44DCC6BEFA377AAE7F567CC2474978368E5DF7497FEE9E7297039EA0A62929DE760C06801A64D746A5F9BEAB610C59CBC4BA1FF7C8DD3C664E5417F698D9F8462C9E4C3B42E82C2976B093762FE3018AA9C2DBFC193215A8DF9041B64CE0ADDBF1688ED2B02E88DC8DF6710839B6365B528D4CD5FE0C3CEA88A36BA2A675DC9612C784C7642EDA8B49FF7E12C10D7F1969F653BF93D7DDE52B945A1CC2D6360819DAF562317EE723B2C18BFE9E2A297B244248A0222CF23AE99F9BCFD4BDC863C965F8E6180CE7EB0F2FFCD24BEF57016ADEE8709D85D5FCE8BA7891D3175EF509283528214363175A5D9102202FFF0A389A6505D547C633800C0D5D944617F7D107C923AA3EE0177BC1264FE4D3CCB8CB6E6948B2592FC1520198154605831435A9212856CB6009BA4D8A0421764EAC4F449225ECDF3587D807D19896CAD1664E020A4BB294520FFE5F8E64CF1BAFDBC2FBC601735D376673A9405EE9C772EF7C13C61F6C02F9BAF282278D40C0B8CC67F5D59AF4DFF2E0DAA3C80943F31636ECAEF8AB45806FCFF21B0EE125AA25A2F083F6E3F1D7FAAC20E534C83AE066FF7BF0A091D80D86D79605A8D9C111BB307E2518C00C223504A44C8A505B979501B41F65350983CAE2FD1F5DFC3F10EB1F3A045A05D7A6E349CB9BFD8B83268BFE709725A1AC8626EA6A35C2FCC448D593617B26474D9F3A0D3C2B696D963F5FC6836F7BA7EB3962A3DD6FABA1D3E68582C65A2A07F044A0E15D1875811CC9542AD5FC6964CD3DA828088269EDE398394595E6A73C1557C64ECE9A4AD2C3E187140B70CBD78D10C598B1F20F7DDAB2FDC4DF2FEB361218058E361AA622F2D56416FB55D262CC61C885211E8A135858740BAC75F3940640F1F37B4DA1627A9295EC9DE88274E08AF87D676615039DE235DDA69A867CD1C010AA63EEF78EC0560A8E789D857FD60F2B117D862CA02BEE558917C3BBE00C290ACDC7D810F18379AD115B969B006CC607A77F650F5BA3607E75897E76FC9A1A725F82C7A80DEE298E03D91B449553552C41BC1470A719BF2A57599B681502B07741144B7D951E09B945E6FB82882BE9223452253075A9DB35D3AD40B442C178F128A4038117D78733B26B3AB01E2C923B607933B2DD7FF1973905A9F7DD5566747E0A69E418680A5CDAF18E1A7F1B17A70B1543D99DB623B8B27C48023D8F566D04B64213C2BE13087ED6E7EBE1D7182DFDF2FCC8119CE6B7D6B121AC10081F4B9B1115C8D8F3E44CF23B6AB6DE37C6DB542A144A929E5B77CF9A4D118C66F866B79C50C0C15F54FA0EAFC5D6222FE9AEFA5657F5E3D4B8FCC5ADF94EB6D2C08B42F3FF31D6F619F4D51A4BE2D875459FA09E17361EF272E2D3640B235606433BEF3A933E20A7C7F44C5320D988D6144068599E18BB8A6C40711C6E72EAE69ECEC700039DE2076EF8C622F9CBC1A95A0D4FBACAFC782A7054CE42CD1449551955B4620288D2866E50FA95529890A08EC7B26133202BA246AC9FAECF9F4A5ABF711994076F96D12AC95C6A01D2D7E7C42DC3F561E811E93A121B65E923B6CF16AFE5D18EFC992F30D13669D3B19063C4B7EAA1DB44E8C75F2069F54420F807128D5361FD0658C784A4B480B1A8057871B791314904F3C1B71E725E92A3DB0FE93F57465E2E76CE5F132D36906815A71AE1738C8FB6BE1D9991BADE840A24D0C9B4978250CF1A5330D2D235D7BD314F08CB33B1305E70327149ACCC73984A54FE5C7CDBD083565BC7204BBCD48835EC506BC5B8C663A07B44650107125DDF98988D377B40556E7574E7FA0002B35DF903C07C07D2818E8AAC01977B824F397940B3245740BA9BFAFD4043DE7990788107080351D1C7C606FEBCDF4ECDF2F325BE80BF5F9F06B84924710A824DB0010B9916647A4BD79788ED2D5883EB5D3D0A5D2E2FF8E118F2005FBA2D60BD33C94EBBC3B5B78E78E9D6E9366271AE245DD73400352F90182A7024642A81AA36CBA95409D827A7857BD444490FAAB670522B6C562CBD0EA9BE939945932A5E583CB27AB91DA45C363FBE9450D"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY('max')), + "ã©ÐåÖüÃÐbUuý©Ö OaovÄ+îBZuÄ©ðãürrC£¢@Ä+¢,,ª+ß.bzbuðÄ.ð~:£bzÜåBbAäahß:£_ä Ö_ZåÖ@oä_îüv.uÃövÄ|BªÐvÖ,¢o+Uã.Ãb+©,z|î_hð rBÖ/ß/äOðüÜÐAv@>h+ߢÃ>vub|z£ÃßAöÃ,b£¢O+ð,©>Ðv£¢hÜbÖo Z¢Äã_,uCrßå,ß", + "Üð*+oZÐ|>bö:,äî<>zäß©ðabbAª¢aÜruöo_~hBu*©@Ä:ã>öÐ>@+bü/ðäîZzCÃC_ÄãÐ>u z .B@Cor|u|Bäh<.hv@u©ÃãÜB©|üa¢BýÄ.OOöü:zÜ©*bÐAßýbzÃ<üa£¢<¢aã_OrðC~+:öZ:oßu:a*ßAbã~åÄð¢aÄÖ|à üªÖ~<.öo£+AÜã_©Ö|£ZÃ~ðýüz>a>|©Ã+~hOr:ä_öãå/<_Bä,üvoCZýÐbªßZý.:ªü©©rÄ*:ZÃC*äÄ>>/r¢ª@z@~B~.hª©~_@", + "ªbAv>o£|Ü*åhOC_+OUÃãÄä CÜ<_/B*~Ü:Ðö©:.Ã:Ð/>_~©@~©ãCܪÖA.v+ýb.ßî*u*£Öb<ä+b£/rOöðýÖ¢:äãå,~ZZýACä_ü*åªßbð>ðr|~ObÜîã~ý Ü b> öb<Ö<ãUuB<ãz Bðãh@£Zzu@@,h:C_Ü¢z,väa:Ð:+z+bªöª>£ß,rAÐ_ü+ +C© ã_ðbuð+,bvýöhî~Ü£übbhßîOUh<>*CýOÃÖÖ,Ã/UhCUÐCub~¢,~Ã.b¢rA¢ÐßB:åAüZßU,hOBrÄîðåBÜüO_ãCÜ/~Cb|ÐÖö¢oÃUrÜã.ãr>r>>ÃoÃzöäÜ£_¢Üv_ÃÃrß..o||rézð| îvðåö*vßîoý¢b:öUhÄ£+Bß*öhöa¢¢ðuzrZäýªßÖã|ª@ý|ðhuÐbßäÃöUCðýÖa*¢OüöÃ.ß~ö¢ ößßA>|îOßÄ<Ü*|ßî/oÃ|UÐBUBäÃ/¢_oB+b@î+ýߢ.ÃvAãÐ ð r£@Ühä@ãUð¢ä<|U|+.zAî@:+bo|:b.*@ÜC/å¢zuOabhboÜöha<: Aî/©rhÄýzbÜã~BB+C*ðbOCAã,,uZu/:~öA>ä©ÖÃ<ªUåöZZ¢O:b|båÜ ¢/a<*Ä¢ÖªÜr>b¢ýýCÄ¢br_Ðv ãA@ßî*aOB~ZBCbßöäîuOý||©CüÄ.O ýAÃîa¢ãh*¢@B v:AÐ:ýÜ>ü>ª*ö|CãåOßý©~_Üo/Ö._Ü:O©ßUrbUv/.ãa_B|bbÄz:/ÐB©Ãðv|aU+öOA.Ãh îÖ£ð*~ß|aê,ÃÃU A:|o_Zß©UrAîã@©äðÐß_ß>+@ãCð|ö¢_ÃÄäýüCýÜ¢öýÃh_ðÐ>aÐ<öäÃ_@bbz.+UÄ¢£*rü@ÄÖðörªßßuýî,._uo~ßa <åb©*UÃvb:vä<.vbvÜ©av£îÖO O¢@@Öð*o.Ð,äöÐAðß_>ÐörZb©Ä¢vobZ/ÖÜBªåüÄ*> a_£.ãðý*ã+U/,ü :äbZBý :üBO£.AãßouªrÖ,väÄvßUîOz+CZ.C©b. ÃbÃz©Z~za_BrÜÜ~bªO~ßoB_ÜÜß_CªÄobßZ@©Ãör.Ã>u+bCª*Ä*@<<~oª_î@äÐ:Äz+a+>vî+£ýoC©äOéOr.UOêUCðCÜ. ÃUßðýbÐBbßýå> :>Ð+uäÃ_A:CÃ.h,*ß~U£<ååöO£öbC¢vzOvߪOÖ||£hu ßz£ªÄÐa,¢ää~¢ßr~ðª/,Oß>h*ÜoAaÃa £_håý**+¢å© .rý,|ý¢bÄãhýß>Uö|ü,öä@ðB£ ~~UbÖzhOÐhßÜB.ß©>Ä<îZîÐu.bߣbßä¢ÖCoß<+îîåCÃ>Ub<ßUBß.ÃããîAU~ýhýÐ~Z:ÖüvaOCß~aOrUý*|ý,üa:ððvvÜuÜðÖî+Cußz@|UîÃ~Cß©ÃÜvu.oªÖ|ã@ßÄýuö åßCßBArAb.hbzäßB~~ýö_@ªzª_,v>ß~aü*ÄZÄä~Öbr*Ð:ÃvüÄÐC.Uaß+ußr|¢ð_UãhBöo@+Ðýuå*oääîv.|ÖÃoÜü| bî©aho£Bî ~ ßO*+.aC/r*öZZu+ß_©*h+ß:Ö|äa~¢_aZã/,ü @.,ZÜ< Z+hÃza*£rÐ:䢣äC A+ãu£ÖääÄ,ýväîo+O:O©+AÖУä_£å ,Ä üߢÐÐbã|:<ÃAßýÖvÄAå@ýðA>ÃýuBü,>rîA,_r_Ö+ Bî_bÄßåÜ+oz>O bÖCbÐäÖ~bü>CܪubOZ>Oîa<:üo*zªurÃÄÄ ßbã~_~bZ|zýaýa/Av©b~>/ýãÖß.bv.ýÃvý~,Oåð,CbÐzUrÃÃZZ@.,/ah@ýãÐOýaozzÖa.Aä+ÖÃ:/Äê|CÄÜüî|Zãü/äObOrhb~ýö/ÃZU/h©Äü~/ã,Zª:rAUÐaîAýOà |>ã/A£ühî~ýÐ+*ß<Ä|Üh:ßöß*roÃîA|,Äv@ã,>>a ðäUC>Zå@©A¢.îrÄ|Abß|~<£ABa©>ÜТ*OBo|£© öîrðÜÖo¢ÄÃAB*Ã+,*z+ªCbÜÖ @z ©~bßÖahr> C+ßãÄOUÃh©ßÄßUZbuåC:~U/ãöC¢r *|oåAOýßv*ª>¢,£@üßß_ÃßvBbÐäööî~|b*ßB£ãÜbzUö@@öüäÜ ý ߣ¢_zbßZzbä+ÜA/vª_ähaÐU:ãÐ~BÜao¢ðvÖ.ÐUß~a<ÖU+~Ö<@ÃUu:ãzb.OÃ|>Ð@zåu:>vA_*ÖZh_üýbvýB~BÖðObüÃý__UBvü:+ohUrba*a:_Ãã@Ða~Oß+bv©ßÜüaÖUßäOBbUðAÐ ªüª,C:Crý¢+öÖU+Ãîab>,aÄZîü ¢ö*vߢЩÃO+*_+ÜahåãCðÐ+ îýuöªvz>oh>U£*| A~©>_£>Cªý|,bä.î~a*ß,Üb/äär.å_*Ü @B*bäÜv>C ªÃð:zÄ~£¢aÖðU@U¢Ã/bUb¢ßb_ÜbäÄuBzZ//Ðö,îÄZåÄÜ~~ããßuBß/ävýîãð_©Ðö.î/£ßB@©Z_+öOîa>öðubC+öÖ@ܪä>AuªÃ.C~ýaBÐ>ß<ÐaðÄüî@ö¢ÄÐ@UÐßZ,Ð_Ö|ðÖ >+Oö îBaZîrÖ~b¢üüB~åüåääOÐÃaübîßUªu~Ä~¢Ð¢ÐU*@bà B|Ü< å*ª> ÖªrbArý,>ýäAv,:äUU£@ hA+ð,z/<+UªB+ãA@|ÃA+C_Ä< ýo+£ÜÃBãåß| U_oUÖB@oÃzb*©uå<¢>£bä@ßåäz@äåZa|bu¢ýOÐårýz£©Baü_ߪu,O><ÐÐv+/|£v,z>Z/ªåZåª/B|ähßã ýbZbª+|Öåvî*/¢ AU+~Ä@ðîz ÜÐ,îä~<_B~ªý ÃCÐÃÄ¢,_OßÜ_ªÜrCßbhüÐã£oãA©/ß bÄAð©<ýãuvðܪð¢+vßv.Z_:a~ä<~ãÃüöÐãÖb>ÃCÐhüßäbüuÄ@:Öäo,b@vA ßý.a_zübÜO~å|Ã_ZzÄ~ü¢¢Üb+ðBß*ßUÜ:+zÖÐüZ|bî:_ð~rO¢CÐß©bÃou*£ªrOÄüðß.r+Ü|*.AîÐOuCÜÐðoub/C,©o_+zÃ*år<ªhoaßã_+,¢oüýýUäåZa<î<ÃA@uUrAÄÃa@êý¢ÄC ÃÃb>uÄO|C:ßbäÐ|h/h<~ª* ©ðo:Z+UuoOÃßu/rßßbÃb~ð£hÜC<_>U@Ä *+|bUåräu£åoö*ÃU*£_îZÖÖZa©OåÄÐð£ý:äb¢Ð|o>r*ZÖýãÜÜzh~ýßbªªvb~Äzo<ÐuO<<¢ªªB+.b,<@Aß,B.~ ©O.U:+©ü:Obä|_ß*ZoÃ_>ª,ürhÐAÖzrÖå,_abUoUöCðua_ðýu:CöÐbßbÜ/Az¢¢uhýzüoýßZbý/~,©oö©uÐßzrvAß~îîuC:Ð+ChzÐ*hbªoßÖÐ<ýß_:.O<ä@ußA+BÜ>b+ÜÃZv@ªîÖ bUäb|r¢~ÄAåÄÜr|:aßÃCýBr©ü>uß/Örå©C Bª>ÜÃZªOå+ð:¢@h//ߢ ýbrBbüßhüßab©å:ã@Aaß,îzZAb~ZZzÜbAß A.,ÄÄ::rb+åßÖbzî.ßßðbÐîba,_ä©bðaå_//CzZ+ðÃUðhUãuý,*vuävz> Ä ðª_a/åðr¢äßB>:a+>ýîÖ_zävãÜAZhðܪü/zou/öܪÐZ ÜBîð>ða>_aÄuv>£/ðÄУ/åaO, /*©Oß|äîÄo/ÃBOªÖUÜh©@ýÜ@äîa¢îåBÄ_o>£ã*Oh*+ß>ýuª|b©£UbÄß/~h ð|uaßbÐhðÃöðå~a hrv@¢z:~uUã©ã+bbÃAv|C+ü/vB©äBÐÖ£b,£Uz¢ÃªC£Ü~ubz|¢åUä /rÜuãU_£~<>å ¢råA<+oö@OvBa/ääßhO_©üÐOãªAÖ|*va~äýUßßv©oÄðZ ZrÜîu.bz*££:ÄOå*.,Oðv@o/¢AAå>,üb:ã_,vã öOÄUr*ßCª+ Ö Ö*bÜb ZO,OßöÃ~ýå£ÖßUöîUOZ>¢@>BUbÃäÄã<åZ© ¢AhÐåZã©zööhB_ZBãuöÃZ*ýbÐ|ü>¢Ü|ªýäÜ©*ߢ+U©ÃovÐ:rrУ©*ýAvbbý A@+ ouܪÖA~|/¢©ßÜýCÖzåhîvýß@¢vßzAð¢Oßö~u/ªýªbÜ|.ªuzýr~Ao+:bo.Uü>uZ_>a>aã.îzÃî@ß>/.î,üßB:å:ß*å/ßO¢<+ßub.Bu:~ZZ vä¢|Äý*~_.OB¢_éöýBCb.hAv+aßO>ußo|röÄ Äßãböüªh/å,|>~rOvãĪz*ý@.Ar+ðb*Öö¢ZZvaãZ UB_.,Z>uåãoÄ¢üZ@o:Ü£_£ Ãa", + "Uzãr~ö+Ö£ZrãߢäÄ©_,O>uÖAb¢ßªÜã,|ðäü~aöCê_äävöãîܪA:/OhA_ßhühÖüßå¢ðö£ZÃÄ.Ä~ü*îÜCÜåßoßöhÐÐöArßo_ã~bý¢AîU>îzbЪO©£aAOvößaö>OuÄU>îvoÐ+zðhbå£ v<å,h|v,OÜüZîÜAAhãÃ_v..Ü|äß*Ðåözª¢__bBb£/äzhZåãªZåauOCbãbBãvÖð£zß©©Zu>übßAB.CZ>©ArbäåÐh>|Ä:övßî@rýz¢u|+ßîö/ha£ÄߪoU|ãß", + "ý@bÖãüA:,ãª+Ü~B|A._,Az,r<ýr_©abü*hÖbÜÖü|£*h_b ©ußu_*uýª©häZäÜ>ß,Ü¢a¢ßAßZ:üÐÃOãhhzüÐ:<ÐÖ*_BðîZÐh_ßÖ*ðAå©bÐCåß*O~h/bÃßv|ýAuã@B¢~¢O _ý.rßÐ|£ü©£_:_b©Übrb ZuÜ Ãr+|:h<Ä:ßOOðª*hoZî >ÜZ:/ã@/CavÖ£åC@Ob@@oßýÐå<ã:äîoý /ßðððhªªb~:@/_b>ßöBÜ+o©ß_~üab|", + "ðö:~ß©ßvö*>rÄäauh,.üCßr>,BrüÜ*|b/~ ,©/./ÃaäÃýÐruuãîü£ÖhÖörÃ:ã<~ß.Üh@¢_ÃüüvCö>@£îýÖBãBßßr£ÄUÐýã@vî~übÃ~hüöa+£rU/_ß:B+îozüz ýß/Uý.~êöÃãzoöÐÄB.oa.ZÄð@Öh*ÐvýÖ+ªz@ÃAöb@¢>ãüoð/O:u_h |_Ðz:©/ ä©Ãbð_£uabÜßäü*ßÄOZA/ªbbÜÜ,|v¢OÖßoåU,Üü/obAãÜÐå*CãÄh~£U<å>ä/¢>r:zAýÄbC/öuãå+|uvAîA:/ðAOOî.*îî@ß©ä~@ÖÖova.ÜðÐÜåî©uã_~bÜ_väßߣÖ_AÃAu>ýÃ@vÐÖ/aoC/.a@ébüuªBAvîö*¢UåÖuÄ_+îüÄ|ßãªÖ,h..ßhbäöÄߪ.ö.ª +hrh,åÐ䣪Äö>o,a £C<_|îööü_BU/Ã,¢ýUÃ|h@*î:|,~bZzhÜߣaCª,ßîãOãUÄĪéäÜý/öãB*ö@+ä©Uü<£A,@,ää£:åobrãÃü,¢/*ß*Ãoav/z@ßüðåÜb©uOvýî ýb©AhBß.böîUÄ/ªB,|UÄ,ÜÃ@+äªß<îrärý +CUãöüüz@/ÜýöîoÐ|OÐbÐ|Aü>hßßör:¢Uö.Cßbý,@+aðBªä|Ö£î ZüÐzAu|zöÐ:ZªA,OAbv|£_ü~rbåUAå<î|Ã,ßAߪ +@B>äðhÖA/ß.,*ÃÖýhBý* ZbU_Ðî¢|hr<ðOC/<Ðvîhuªbb@ra¢ßîТýAUaUzrUC:Zªö:o|z@.ãbuCÃýOA@îýÖU<äöoä.u/b©aÖz:Cbb/zz>å_Öð|Abv© CÃAhb>aÄîZüÖ.r*+@bü<:Ã/Ö~ OUz,oo, åbv b_bÐ.A@hC_|O>aZrå/vZ|ÖzÖ,>Cß+b ZBra..Ðv.U:r£©hîoår:/ßýÜZUZ*îîÄÖbuZbzýäÜhOäbC_©BUªöðO¢å@Ão.+bªoa.zvöö£Ö|rBzöÜ~/ ßüäZ©£Öß*@/,vÄOaßðÜz¢@oÜü¢öZb_ÐBÐb|BÐå Ö|/ª.u*z<îzoäßCÄZßBzbÄ:ÜßÜ ©Ohbvî~aÖOðÖ_¢z:,Ö+åZª+vz£|ZAB©Ü£îÃh ßAvZß+_+b_ÃÖvbA/îAbßåÜ¢ zü£@hB£öOC|ÐC~ߢ uCü£> a/zÜ :_ä+äÐ,:oC*|h,Bð~©£ªîoUA>/zîîC>B>ÜBö:ä/.>|Ãöå,<äÐv,Ö/@ßßo,ªä ý,+©+©å/.r <ߪ@ÃoÖ@BCoUÐÖ£ýözßbv~B>o v@Ī/ bbv£ðzBý£bÖrßo£ðÄÃðCªCbîÄB*+åuß<ÃãO©<ýb£rß/Oßå©a©*ßAÃzÄöa+ößöÐB.ZZ>ýýü/Ä¢Zîß©åbß. Ã@/Öß,Cu©BbUÃ:ÃAå_,ÃAÃðb..,îvCzC,¢b~ý_v|Ðz<ðÃî@bv<,><+ÜÃãr>@öß|ýaUßvhªzîÜ©//äuÄu/häüu@rB@uößýТðÖ<î/bUð©O<Ðßð ã¢bÄÐð©>ðAA@Ã+zZhOurßÐÜ+oO+ *Ä£ßýoÄ,,*@aa©|ÄÜ.£ã©ÄÜa¢ýöß @Ä©_~üßoC+@¢bbbîAü~_Ðo/oo£/rU_ýÖörbBB,ö_ªð|,ÜÃäaüß_ÃhUz:ªröAÜ>oüö,©ªÄã~BzîÃ>h/r@Ö£ÖvA uAZî©z/ðÖBܪ/+aUZhU:,U|ßzoý.vhÖåðªo£zßOv©+h~Ä_aß@@*ªa~öý:<~>za©ª*åÃãu+ö:üýÜaBüBÜoOîÖÜhå ©oOãu©ö©Ä@UããO~h|î£aßöå>+ß*hBðãrý*obOBuZbBZ~ÐvðýªÖOå>ä@ÐvÃ:. ß|ßÃAã>a_ü<©*üÄ£zÜCå*_ ÐöÄCã/Ü>¢ßöU_<åÃ./ýbßÃuhîßbüð*@üvubÖzÄ£|Ö:äã,ÐOo.bÄ:+<_bÄ~uA+ß~Zzýüz/h+ÃÜ.z*ã+Ðo¢ð_ã£b~ßÃaAÐ>¢rðå~@.ÜäÐvÃa©üoOr ãb.:ZУU,oª.C£rou,ßÃå/uÖ¢hðva¢v obß>ÐÖÄö<_©£va~aäÜ>Cª/ÖÜö<Ö ~zÜ>äCBãåååßär*Ü|<¢|ð.UChÄÄzA|va+ªîuåh,îîAOvä~rÐOußv@Ã*£vÐî>ðvBüð/Ä£ÐÃO@oååÜo*aßA|ö©¢ßO+.ßBÖð<|£ðr*/å|aîÐB:+ /*Bv Uö~/ª© Uäöa~ð<_:¢*Ð_|ãZraãAO >äUO_ b.Z~Ä_åhoüãäßa+ÄÜ,£+.Ö£oî+BÖ.,o:|a© UýhÖ ä©b :Ããå:Üð/@rðÜh© :hÐÖß+zß*A<ßvîb_B~ã:©Uäö¢UAAßÖ|CzßzOhðUüoå>ãýü£_<£ãOzu©rvÜh~*Zý~<*<<~ä.o åZÜÖaü£~>|oð+ßBhBð*Ü©ªäîî+¢>OöªU©ä/ðå:vß<ýãÐã©C_+*>öb,©v.å㣠h.|öîv>,OU£©_Z©ÜhbuUBhã:©rvOo>aªª> ~ZÜð.ªorBãZ@Bý+hߢöðЪ,©OrÃurýrvzao>u/Zö@äÜuîAßC@:AbãÜ£b äð+*a,åßoOAzÃz_r/üuo©ªO¢O.bßÐ+Ã>ߣbÐ/.ZÃö©ÐãÜßãh>ã,ß.ð©vÖÖOª bBß>_Ãuß|or£U _uÄv~uvä~¢oUÐÖð|Obð <ðý* CÜßå£äZßubrîÐ,©ª|Ü,hvü<åýýhÄîä¢u+ö<:<ýöÜä.@©Ð£/©UÄðh~rboZîå©Ä~î*:ü_ßðuh~ã¢Zã/ßo*_<OrÖB£ÐA| züîuÐ<Ð_CUBÄ.ý +îªb~<|~ý Uª,UîÐ/¢ªoÃv£~Ãß_oßOÜÖu/ÄÐhýýäÖ+îå<ä*zu>©Bßã¢CUa*Öö,Öß|<,ö@oª:¢Ð.z*ÜCãß,ßbÃU:C+b/î/ råü<ãýrCüuîOß:::Uå*,+BU+£@AÜhrv_aü©£b©BÃZÄ.ªh>/ý©îã|_AöC£~ãzü.üÜü*oãÜß.~ß©B©©¢UhbACU+Ãaýa|a<ßÜÐåУ£Ü ~uä>UÜåðv/a ÃuözÐ,v*OßußöÖaöuöaý:ß<ßUÖCîCbÖCahh_Ü~ýU+/oÜýb_<Üöà .aåîÖhbýZ+uhbBßߢ:o£öܪA£ÄßOr£hO*.ÃýUuߣ@aüaraÃîvÐãzßb,£.äUAzäߣubÜ©,ß|,©>Cðß~ߢAðî:ßß,zAb|,ýÜ ©u Üoua>:O:£Zð:äßbªý,ü ã,£<£*UO.îo:Ä<ߣ.a.:Z*OB,|rÖ*+ÜöÄå<+>Ö+huaAÐC:Ö+a,rýü>b>r|bbo>ßACuÖßý/h£¢ZUvz/üößßÐöOÜürßýOöÃZýÄOý¢îÃð+~v_*ÃvÜOÖ~hv Öåä U|ýaUOü*Z@Bzßbvå/o©¢/Zðbß.", + "4733-01-26 22:52:45.974", + "2020-10-11 17:00:00", + "1973-01-31", + "23:59:29.04987", + "2002-01-31 23:59:59.04987+08:00", + "2002-01-31 23:59:59.04987", + array(null, null, null, SQLSRV_SQLTYPE_DECIMAL(28,4)), + array("0.3913", null, null, SQLSRV_SQLTYPE_NUMERIC(32,4)), + 3.141592, + 2.718281828, + 131711043, + -1278046619, + -2567, + 255, + 0, + array(null, null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(384)), + array(("6459515CEF4E0D6C859FB097528CC63596AB884B918D383E578B8B0C08089E77004EFD497BEC6B3CF1DF4C085DBC4CE3095D796636C29BD721130563C200637D003997038E7CBAAA404C59B1402FE09A3EA803AB8E37403DB2262868E70779F07BCF07242549548DA3CF26E968EA97F1326A2519FDB8EEC9F85950685451C238D269357128BB75F5537508BE1057D4C88E37357CE160F2C3E03E2CCCF8EC38510DED16FFB525C976F530C587B030B8A08488D91D1B45"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(384)), + "ã©ÐåÖüÃÐbUuý©Ö OaovÄ+îBZuÄ©ðãürrC£¢@Ä+¢,,ª+ß.bzbuðÄ.ð~:£bzÜåBbAäahß:£_ä Ö_ZåÖ@oä_îüv.uÃövÄ|BªÐvÖ,¢o+Uã.Ãb+©,z|î_hð rBÖ/ß/äOðüÜÐAv@>h+ߢÃ>vub|z£ÃßAöÃ,b£¢O+ð,©>Ðv£¢hÜbÖo Z¢Äã_,uCrßðuö.UÄo o©_<ßãäãz*ÐuüChå/©Z,aÖB_Br*Ä,:ß*bzÐh>Z aru_vAvßßbbü~.Ö ,~ý,¢>o:ã|+o©,a+h Zrßrã@ã,_¢ >uözü _>îÄ@AÜÃéCh.bÃßUh|_rÖ<_Uö@C* .äÃ", + "Üð*+oZÐ|>bö:,äî<>zäß©ðabbAª¢aÜruöo_~hBu*©@Ä:ã>öÐ>@+bü/ðäîZzCÃC_ÄãÐ>u z .B@Cor|u|Bäh<.hv@u©ÃãÜB©|üa¢BýÄ.OOöü:zÜ©*bÐAßýbzÃ<üa£¢<¢aã_OrðC~+:öZ:oßu:a*ßAbã~åÄð¢aÄÖ|à üªÖ~<.öo£+AÜã_©Ö|£ZÃ~ðýüz>a>|©Ã+~hOr:ä_öãå/<_Bä,üvoCZýÐbªßZý.:ªü©©rÄ*:ZÃC*äÄ>>/r¢ª@z@~B~.hª©~_@", + "Uzãr~ö+Ö£ZrãߢäÄ©_,O>uÖAb¢ßªÜã,|ðäü~aöCê_äävöãîܪA:/OhA_ßhühÖüßå¢ðö£ZÃÄ.Ä~ü*îÜCÜåßoßöhÐÐöArßo_ã~bý¢AîU>îzbЪO©£aAOvößaö>OuÄU>îvoÐ+zðhbå£ v<å,h|v,OÜüZîÜAAhãÃ_v..Ü|äß*Ðåözª¢__bBb£/äzhZåãªZåauOCbãbBãvÖð£zß©©Zu>übßAB.CZ>©ArbäåÐh>|Ä:övßî@rýz¢u|+ßîö/ha£ÄߪoU|ãß/B@oÄ@AAÜýh|rhüä/:ßvöðZý<îý©*B_ ©.|uBbããÖåo/a/:~ßÐÐÜÐ~ã@ß_©ß_+©Ã:ßîÜ~Ö", + "ý@bÖãüA:,ãª+Ü~B|A._,Az,r<ýr_©abü*hÖbÜÖü|£*h_b ©ußu_*uýª©häZäÜ>ß,Ü¢a¢ßAßZ:üÐÃOãhhzüÐ:<ÐÖ*_BðîZÐh_ßÖ*ðAå©bÐCåß*O~h/bÃßv|ýAuã@B¢~¢O _ý.rßÐ|£ü©£_:_b©Übrb ZuÜ Ãr+|:h<Ä:ßOOðª*hoZî >ÜZ:/ã@/CavÖ£åC@Ob@@oßýÐå<ã:äîoý /ßðððhªªb~:@/_b>ßöBÜ+o©ß_~üab|uäv/rbrªvöîðCU@r:ðßüAöbuövoC+*oª@>+~vý aZuÃhä:b/v*CArC@vßb<öîbUîßz,", + "23:59:29.0498764", + "2002-01-31 23:59:59.0498764+08:00", + "2002-01-31 23:59:59.0498764", + array(null, null, null, SQLSRV_SQLTYPE_DECIMAL(32,4)), + array("0.3913", null, null, SQLSRV_SQLTYPE_NUMERIC(36,4)), + ); +// 16 +$values[] = array(array(("DC2AC223F37157A0D09697457E8AB44F431D051EEFC9CAA3EFA757FED77AF4CE6EB384F4C9280C3FA538F8A143E7BC82EBC8AB6A8EE32B13601E344B1A58C956A1C9D6CA05BF851B11C579B7D1286007EBD5130ECE8A3F8B887094AAF4C0254C6FA1007A10F255483A6E4"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(256)), + array(("B106977B3F44B802F1474CE79046CFD78BAED178ADE8E3C655794F0BC70260991EB4407F3619FC277ABC904943DF84AB1B36779944C822D125C5F4AD32CA804A87F7271B970B77B87C856E26350C366F86240B908BC65456916F5971254FF5AF3B46C24CB769140FBEBE1DBE59FE2A028E6F04B8802AAE6E0EC5DB82CF02D9A1"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(256)), + array(("0F"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY('max')), + "Öß/Ö>BhüÖ©äv<ÐzhZ<£.öZ/UbÜbüÃð¢î>_|Zu,|öö~üßZh.,,ßüü<+rÃÐAO<>oo*ãßß~ÄO/A, >©BüÜßbäBåö£/h*å|rrb:Ü.ªö: ßÃu+ð~oä@~ÖU*.¢bZ,r,©UߪußzäÐUuOå@abvvßZßöã©ãÃhrÖb£~äªhCZZhZBÐðär:OÖ+hC./_ÜZü£AABZUU㣠v,îÜýh@ObAý<+@,ߢöUo ßãh£vBrß<©A_hð*<*hZî*ÄvýO£@Ã:¢z~>ý/_ÜhÐA", + "uÖä>å©>r,Äü+ðý>Üz_©>öoÜý/ÜZåÜZbÄaOãZ @rz:åîÜ*býåbB+¢.B¢U*Öor/ßb,oZ:@a:ÐÜÃ<ãrßußÜz:<+åÄUªªÄªz*ýå©ß@¢bª:ä~+~ðöv//hð,åü ©>:bãðzä//êo+ZªÖoäªåaZÜz OZ<+öBî", + "OaÖ__Ððou Bbh@ouA*/©r©Ð@Öa+b<ªÃãuZ/Ö. bhbh|üuBhüuÐb_å<ß>ZUß_+å©¢£vääB.ßÃzZ~bCÜZ£å.", + "@oöÐ<ðöh£übîB< C+oö£oÜ@,|O: ,ª@aßoð*ãÐ_üu,åßo~ãã¢håÄåZu:b>OrbªÐA/ABö|ýv£¢ü/ÖîÃuý*ªÄvÄßh_ð:v | ðª£ã,C<åv£äUBîã:|,vOä/î î*©h+ÜîÐb+ãCÃã>B îbb:üZä.ý_UBßðÃ|@A O,å", + "AbaªBßaZß©öåbh/BîBöüZ>aA,.Zªz£¢uÜ>Zß~<+_/z|:_>: .BýðîB_@AüuÃ@,ýhAÐC_ã£@.Ä,@ýð|>åöörr©Ä ©üÜܪUÃAb ./ß,î>Ü~|r>||ª:<*Ð|OÜ< .:~båîOA+<£>hÃßB,ozCîü:ä|öB,öz.å©,OhBîB ßäÃCÖh+ߪ*Oî~ßvbîªB|AZ_ÐA_öÄz©ý>büzAv C.~Zß~h>zåCCu<ß@z@ übrr£>ö*ÃãªÃýÐ>öª@ubªO/@Ã_£", + "uAoubðöO_:Ã.£î*©Ã|.ä/vv|vZzãb<ü~ü£@Ä£ÜÖoªã¢_o>>u.zîbCOªhîZîÃÄB||îð/rð_ªß>Cä*<*ýÐýb.Ð~ð<ßb,ß+åb/>vb¢ubzzäÃC_ýzv£|ZoÄ£©ãýý/£h@ÐUð:Ã*B.ÄÖÃÃÖ|b:+<<ßÐvbÄ*ßã/b£ß,oßh:rBzöouã_._U*îÄ¢@Aãußa©Zýý./>äÖ|O<ðÃrv Ü£Ävb¢öÖýßAãACbÐöÖzvZÜBC¢£übäýA/UÄb~BЪ£AU/££AhßãB/*äbÜÄBA~.ßÐ.Ã+vrãå¢ßÐßOOãåÄ ¢ÐÐärZr+Üov>Öhüäo>ãC+ßZðuZÄ@Ãîðß,Äö©Båu,Oî.êCbªäzA b~öß:ߣî~ÃÃåu/CAOZÜZZ/ö:,~ CuC©+äªÜßÖhuZUzß.ä:@éÖ*>AÄbüOU|Ðz.@Üð<åbrýao¢@zB|_/¢ßA>ÖAß++Ä©Oîu>©öB. ©<_ZOýObhAvÐ:îÄ.¢ö© ß.bß@ßBðhä*ýhuÖovÐ ÖãÄU /öÄý@bAa/B@U/ÖÖ+åUöZÃZ~uo|hå¢îÐ@ýüäªÜö£h*>ãöðo,@¢/bÄ,ovÜßå<*Ð_@©ã¢å£AåzUbuUªv:C£üA.v/aCãÃBÜîbüöB.ÜÖß:¢B ß,u|Ãoª+üða|.h£ðÄ©ÄözßrÜ@£Äbî*:b.Aö.oh/B£:_Cö+©vCãCßîoAaO:AA/@<ª<üo,ruÜ~u¢Zãvbßhü/öbU©hvýðUÃB.£Cýð£ýuZbåb@|ZäOÐB¢åbý~.+ßßå.výb<ßüOä*/ãðÃ+baÄBä.ßrhbu ©@~_ão äßåýbÖz© ,©ßü,¢>,©Äö<ªbãaU~ß>U*Ð>/©@öb:>ãÄ~BOO|Üu:£*bÜrzãoz/:ühÄBߪOßbabãö£ZbZZÐZ£ß¢hCîu|ä|hßh>Uð@öÖ,Uh.|bö>zZðoîÄÃOð©h_@rZaBhb_z_b㢣_îzhðbo.ðvö,uB:zzU,.Uröhz/a,rÖrb_voÜåÜÐb+BvAbÃîübýuß:r, öOãÃbhðö*Z,*£ü/ßC.ßßAÃ/ªäÐ,raü¢>ÐÄhü r/ÃhC:/~r.ub>åC_ö|Bðåß*ÐÄð+£î¢öã:<îüC©ðuýa© Oo>b@öÜobb/+Bü.ObÜÃ|<,~Aýh.Z¢äðäoA||/zhüãÜß,b@äoUÖor BäÜ|:B+@<@Oh|ub.äÐÜ£ÄÐêrý:", + "2001-01-01 00:00:01.000", + "2015-02-10 17:05:00", + "1973-01-31", + "23:59:29.04987", + "2002-01-31 23:59:59.04987+08:00", + "2002-01-31 23:59:59.04987", + array("0.4471", null, null, SQLSRV_SQLTYPE_DECIMAL(28,4)), + null, + -1.79E+308, + 0, + -1831503069, + -2147483648, + -11771, + 81, + 0, + array(("DC2AC223F37157A0D09697457E8AB44F431D051EEFC9CAA3EFA757FED77AF4CE6EB384F4C9280C3FA538F8A143E7BC82EBC8AB6A8EE32B13601E344B1A58C956A1C9D6CA05BF851B11C579B7D1286007EBD5130ECE8A3F8B887094AAF4C0254C6FA1007A10F17C2B42965D32A4EE4E81C4C1392FAF4A9C7CE06DE9B818131770B17681697FCD2E2041B79768778B9C345444982DBCCF5CB7DCC48371795C9F0B5EEC712E6CD50207A30"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(384)), + array(("B106977B3F44B802F1474CE79046CFD78BAED178ADE8E3C655794F0BD026C70260991EB4407F3619FC277ABC904943DF84AB1B36779944C822D125C5F4AD32CA804A87F7271B970B77B87C856E26350C366F86240B908BC65456916F5971254FF5AF3B46C24CB769140FBEBE1DBE59FC9B198E85260EBFEFBEC0A2D08927B206922D90BFEBEF49E9B81D0FFBD2CCA996FD95D33FE2A028E6F04B8802AAE6E0EC5DB82CF02D9A10ACCFA5CC09FEC31DF"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(384)), + "Öß/Ö>BhüÖ©äv<ÐzhZ<£.öZ/UbÜbüÃð¢î>_|Zu,|öö~üßZh.,,ßüü<+rÃÐAO<>oo*ãßß~ÄO/A, >©BüÜßbäBåö£/h*å|rrb:Ü.ªö: ßÃu+ð~oä@~ÖU*.¢bZ,r,©UߪußzäÐUuOå@abvvßZßöã©ãÃhrÖb£~äªhCZZhZBÐðär:OÖ+hC./_ÜZü£AABZUU㣠v,îÜýh@ObAý<+@,ߢöUo ßãh£vBrß<©A_hð*<*hZî*ÄvýO£@Ã:¢z~>ý/_ÜhÐA +~*öðU~A*vßüUýC~h<ª~>+ä+:bh<ßÃu,U~üCîbU.ð©B*<¢Uazü££h:ãaÐü>äBCu©b.Ä©aa©buO£ßv@åßßCoäA|vßÖü,ð|+zß:/Zbî~azZ~/ößaÐub©büö+¢å©>r,Äü+ðý>Üz_©>öoÜý/ÜZåÜZbÄaOãZ @rz:åîÜ*býåbB+¢.B¢U*Öor/ßb,oZ:@a:ÐÜÃ<ãrßußÜz:<+åÄUªªÄªz*ýå©ß@¢bª:ä~+~ðöv//hð,åü ©>:bãðzä//êo+ZªÖoäªåaZÜz OZ<+öBîßÄzUîrðÜäU/©Ä.å £ýC_|a,+|ýhb >ãýZö©_< ª.¢Öý:ª|ý¢BACîähzÄ©uzbb,öh£übîB< C+oö£oÜ@,|O: ,ª@aßoð*ãÐ_üu,åßo~ãã¢håÄåZu:b>OrbªÐA/ABö|ýv£¢ü/ÖîÃuý*ªÄvÄßh_ð:v | ðª£ã,C<åv£äUBîã:|,vOä/î î*©h+ÜîÐb+ãCÃã>B îbb:üZä.ý_UBßðÃ|@A O,åböüÖrzßãÃ,uB|ªhäãª_£ªB£Bv+©>ãZ >ÐoU©äu| UB*+ÄüUCU+ãaÐß_:@Äî|v_oßoÄ*.+:aªbr.@ÖZ,Zh|U::zÖð¢Üoh abÃö_rý¢", + "AbaªBßaZß©öåbh/BîBöüZ>aA,.Zªz£¢uÜ>Zß~<+_/z|:_>: .BýðîB_@AüuÃ@,ýhAÐC_ã£@.Ä,@ýð|>åöörr©Ä ©üÜܪUÃAb ./ß,î>Ü~|r>||ª:<*Ð|OÜ< .:~båîOA+<£>hÃßB,ozCîü:ä|öB,öz.å©,OhBîB ßäÃCÖh+ߪ*Oî~ßvbîªB|AZ_ÐA_öÄz©ý>büzAv C.~Zß~h>zåCCu<ß@z@ übrr£>ö*ÃãªÃýÐ>öª@ubªO/@Ã_£ßÄzUîrðÜäU/©Ä.å £ýC_|a,+|ýhb >ãýZö©_< ª.¢Öý:ª|ý¢BACîähzÄ©", + "23:59:29.0498764", + "2002-01-31 23:59:59.0498764+08:00", + "2002-01-31 23:59:59.0498764", + array("0.4471", null, null, SQLSRV_SQLTYPE_DECIMAL(32,4)), + null, + ); +// 17 +$values[] = array(array(("A82F7923662A496625B3CD58E906DD15019C700D5F48E2AD60858A9437AC118D0E99EFA02BAC0C52A44EB1940E8BEAAC3617AB238573055F4CCBC2E19FB52F78A13F494F173CE9548F1E6911974E9FD59ADE5D1F01EE089B948F545FE92BB2EF1E38F3CE419B95FA2D56936609F4C8FE2CED46C0571077B237AEBB87E8896BDE"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(256)), + array(("304F1D1447944F1CE70A2A62C02D5162E8BC9EBA4D9CA036FA24DC9C61E6F40BC0D00E85A45BE19CC2E44C26694EE3BB0A0CE814DBEFA194AFE71922B7B2BA01151FA2F01FCBBE8DDA01F8694F7ACCAC41219155FDDF2FD12F79D6BC41BFE50F2A4B104AACF39B3F4E5B39D9F6384"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(256)), + array(("2987450EDBC73896120915EE84C828A2664F18523DDD6219E14FFC69E68BB2625E3869FA73EC76F9E5E1DD21BFD1462230449C4208560F4C252C2C8CCACFAF8757B38F4C5F2E2F7AD91F6D5BFF40591009DA39A1EE705908291CD447BFEA2E163255CA0C41F9C201152269E8E9B34CE4D21C82EF950D99E75987234259E7BAEEF15629A9764DCE1018378CCC07701F75CFEF75A2683F8024BCE2B3BAD57FA72D677AF79289A26E854E72D75D81CCE0E868AD736A721886B1D505ED939A143A98905E648C788CEC2C81EF54F56723A2F002CA52280C3DBA4FF446BC84B5DAEB3A373FCD23675370DBC146E883C3904AB262FD91CFC2128B53A3159832D06777A6041ABE28557F88AE5A7666C654378B63FB0922B8491B7825B37A7F51BB3D0B59CF417EA9D2215DE274E2754BABC5FE6B8A3436C645BE5DE9A29874DBFF36F31C6B0CF712B9E190D9AC3F4366A52C79EE7B14C78606451410E4950739AD81E23DEF59E09ECEECB1A8A35D19067AF643751E8660EB6F6C1525F8E62E24DA562C2B5C05774C4CDA208F621FE2A92B0E95ED51911B2621F7CE8343BAA6E7BE8DCE4C30EEA9757FF7294366D18950896CF9E95140D2483B060A6536F408913438D1D45096783D64206E5A68D7BF506D7EF9D7C0BD957DBB85112AE4443E8AEE980F2DFFB5FFF3F3BC8431D177DF6446B9F7B8FA31D077A35319CB844E5920E1E46CD0C89150B87F06E3043864AB43A5ACE32A4C858FBCC7988AAC9B336EA462644FED0B0F9CB4693F38F44DCB3E3EA7D525D76B2FD45C54AF082F06A41C4B983FA2D415BE3796102EC00C4C9B6FFB594C04C60E9639328FF3995C066CADC523ED5C0E296A29E99E8FC73C6EC70FB8400CD6BA9F563C01056F442124DB8FA480FBE95F3F60D2EE221B287ECFFDC4C7E4E01BF995F225CCB05A08B92607C4C2FF22BB73DEAF79DF3AE798842EBD3208AB7C3D44BF960E8DD51CAEE45719C81A57657FAC4151E934663BBFAE5AA19EF227000EA9CA7F0269132D9DC1019488201F7E2CC83E85C65A9209DD84D66033337EBCBD570B1F50D763159814B32833D1B39E8EDC74D5B3A139B316C1A17E92B3FA694244D73015002E556528EDB2A669D50BD038D157BEA8081B1D57088E35E483E51A49E5EEFA83898EAD1F708BB4870DACEB95AD5AE1A2AB9A3CBB12BDF79F1F80A507985D84E7114DAE42A99F377C67964A5BA39F372903779E4BB13E70CB960EFFF0E6ACEEB028048460AB9FF80B62BF547C739CFB7F497C0420BE3835D2DCE2AB9B9F4796BBA79A329F1BD67D647F92E8F1EAF458FA127FA66AA7CEF1EFCEB284C9F35D6C1B2999D4D9695C6473FEA0A12C5043E7E88AB1881FA02C13D9A843D06951B3702125CCC8511F7E91B61B336B062CC59F8BCA9C3E42D54D7AFD85FB30268BFB214A308006837B95C80B1FD1046DC10CACE3A4459EB5752E4CD851CBCC244E6B2A1F1120D6ACBF1B1034D3322203490D3B794E4D81465D6CD502332D32AFC9A4BDB4A7E45BA035FF23893569E1420B488F438F53D500E9E4C2A54AD47892E9606B2F756E5C64B29B434F29F810F38A92F6EA9DEE2076CEBCCAC221B556608691A0D5FEB2CD9CEC2A91F40F86D7F0D3CF1BB7DE8DF4FA3FF460B8A39943FD45E2C897583BF5D8C559FE725C2C6748E5DAEE529A9E82F99DA595095114F953E793AF2CBD3F9798DA43F2848F819E138D17D2C9AAF063A65FCFFAB3A6EB86B060AB8BC87D3A8BA642567857ACFE691B07827C39422FA8F63008CCEE44E4F2EEBC4123E4F6D596538C2C8753780CFA6165DEAC236F4D6E30029498746D9C615E64899A6ADA852532EC28AC15A8547E240D6B886637CE7F6FD3F2E1613C21E6F0CB28EEEF719086E0B87A3746A05988AE1673670113FA2696092B97E8A3C3F5CA42BC4A7F658EB37DE5A8ADBD9639CF796A334BC8B9E4DCD00258E546F99E3CF5856C03E30E084887C0EA1C6B4D69FFD05C1D7D70782C115EE0797D0DA86C83466CB8372936EB6A62EBC308CFC87183995815EADB20CC7C585BA503958B3BDF5366D5FE9431D69A70B21B85B52442966EF6E4B49282A8269F3CDFCE90E8D5D7B0E4B468F272EE67827B79290547C734190F959FA6864CD0BEAF5F5852070988DC44D4D16FD9A3FB077C3217097F205875AAB4815336302998E3AA421396157A72F14CC172F6C5406B9998295335C73E8E06E3A7528834A613AB388B2E60E87067B7A417325FE67EE57415BA9D06D5631C6BB40CB36D27EABCA5ADC7BD39110BB027C29C90B00B2E2064C2DE727A080DD5D56FC2ACDBBDFA8FBA5A8DB21EC1AB620A09764439D26C5F85EC4EAA4977419CA0F1E7CA4F5ED469C80CD5557E7C01A2167B687192C99B03036226EF6F4F454318F0122CDAE113AB340C7B2CFD16E109EAAB94CE0ED009D656E4C6EC37E5FA78C6913C8D69D4C83567BC3C864D6E05EC811C04C3BB773448E73BD6F61A27734F1102656BDA53A016E35E6652938389E7DEDA6B1AE037BD4F5DF3A62DFDD21A4048ED744A099A112D7CEEE05C10E2B463B1EF1740BB586EDA45160EE6AD721810442609A50F3FDE44C83E9EF156613F7A3F437B0EBADA84EF7F9A05F28B2B7F0AD6CF18EAD90E547211D3777DBA7D83E3D694A76AF6095669A11926743AEBB89DBE931B874955A030EE09FDE76306350116211CF7831513CC79AE48C0E7DF38251BD9BF2661FC9A81F3777BED0C6F069AE3245E18CFC01AA8804E0D9A0DE0480FD1D7CB89470EA01A869A040C9926C00AA8ADDCC2811F565BBF16A613EE0074132E6B1C34A37D53D584449134BB0D0F5A8E03F15F03858EB18170C930688D2B8626F1DE2E098B662B59073E3C8D229FB2074C84EB0E140FA8DD6AB332B3226DF7180B0ECA2FE150029CC606FC4751235FD117291B08407711E135509ED83377369A46248213D48226FC814E480E13618B4754619CF951EFD893FCE8FA90B12A684ECF61002DA14BFC94031F86F12E03CDD3C45784D2DB3D48574BEE17EC88954A57E6FA3EB1615EA6086508F63168E765F81B26CB59A596729119A8E2B233100B6DD42E0B34C41B7266B17B6CD34716EF64891ED062CAF1B14F87AD98B87CF3D555FC885D39DB3034FFB465A82A299F4A02B97E29153FA9A3E37DBBAC1782BAEABDA617D6BEB9B58858EAD1AD65488726E76296FEFECAC01553E57ABC20831D7CF97AEA8411C98B4803F5D02A6EFB3D9AF595C5B4ECBBECF3E60282D93FF967D4CC54B4EA5E03141ED74DFA08F995A758A7DFC68ABE68903D8EF79D0F46B1090A8EFC5D1947533CF280A7DC9EC1E4F9515A2A315F33DD1564C4765B676505D72544F07AFD378E1154A3D409178CF17CAAFD4CB41C80A9D7B1E6F954D0F7D48C7BCFB65AD169FC19CC18DDBC5FD3FED7D2F9B16A1850BBA59A18C9163D39405CCE478E47D597AB400032E803A2ED78DDE72181D7466A732B1410BFB8A0E6DC92D881ED1744B6023B4E706AE667B703ACA0EB2E1BB7691664D36333C4D7F39F1A56562A21006099301F4688D5008DC35C0D1317B5B7C0DA6E6B8844E1833D635BD04F8F108CE2AB4051FDFC70E04064459FD6B6C4DBEA63957BBCB6781CB7ADE1E32D04B0FEB2CF2B67D763B9C4698E2A24FE41AD879E7FE6ECF994D02C332499501A8DB33CB347EC068B5D0486AAD1122D8B531D76FF5A44AE1DC3041EFFFF33B3C968A9DCDBED70B755A6FB417B60422882A2A0DF072350C048041EEF42CE078B2951BC412735529DE36521585E0332BD81DB9B5C5F53ACA617E993D6CF8074869F6F172AA400014C5002FCA102F86145D1616E6632AA2CD6A5162A3DA27CCE62F19AB9EEEB081880DA4E0C5D570AA31F874E046D120D53F44241848DD6C3AAD33399B0683F7259C948EE8BE39ECF7E9A720BB654786150E346C4ACAA848BA917A43829BD5A3AE015F43B2423816F5573C2EA1ACB0C565BD149CC217AC6AF45BD44743F66A5C13F372BA0603C3C2C61D66E38E79970DE0A4EDD57738D19654E44F667DF0D30EFCD00AAE29F6CF51E941C6B4B0C8DC8AB4C6569F0894D4EB11EC6511B46D54D54A67E6BE6EE8D3E9E58BEC35622CD58C07C4A1A79A43F667FB2F8C3D91AD9D7BFCF17A58D22E1BDBF26CA98CA8AF78F516D919FFCBBD3AF6618EB34F5CA65847EE603860B28CB9E9A8D5B52D9A79BF4BA69726C893ADB03FB673E7436ACC7F5C14619E487708428A1F2056E6081D5BF7DF7798C57F8FB440B008BA3E95667EEC66691938DB76D4AE549CA96346CA37A917FF73F323B9DC94BD5D886E5E03E4B8B16A8FAEF4231C5892FA60D2D640F9E5D10126A5E28BB8BC8C748B8DEE664050A7F0B1EC4A88A4E4D31B502948F9BE6C53A29D5CDD3EC635B1D3128FA79E7A3CBA103AE59F1D9B485C31D2C72B8F6392C61F3A3BD8F373692A8C2A7766254D34A1237F28CED8DD36074500AB6C0F0A226F8FB998643E53C6ACC1BB12F323D226E4AE25F8104AD3FD31F42483F2D80D1B71F807E66BB4D062CFB88BFD1DCA42D362D9B6BDE9021224BBCC566009CFD3D4B4AF90FB2BFBBB3FCDB32857BED6EF77B1411119114F326FE5E32AAF5E60590FE4B7387E2957B7771E86F025D9BA65E4ECEEBEB8AEBAB3756D211538C11BD16D5A2873079E714E5999A9FA9A5F0C962B7D45B27FB1905129F3C300F8427EA602A592DBA1476E467B90552F04C02916609AE9CB8B5951ABC9D75903CB6046171AF3E7E4CC30E4D41EFF46EF5C614C69DAACA05D58B32AB953E711D9EE5A7B0B4A4E1400D8345A2FB605AC8C02625F588AFF392ECFE8CE57D93E90E52F1AF5C4843BA51E5D4B81A65270A743169EA6E197B94EFF115C4B517FBC37A9937500AB1FD807C6CD30FB4F6D92CC4F418B413A87BF4D65CBF6A327F0439EA113E802ED7FFC233E96E01456CDFF918E900C1FF46AFD21E427AADF2924EFD689A25A3B759FEEDF456812A3A7AAF697DC552497E433AA3616C62EC5C51CFA09B7099AB463B42BFEB12CCA9C48597A39210302D40047E245F81414AF61190A286E18EC9E004224183935D6C7791DFDCD4BE594C21A25F96F1744BC5FAF7C8D9822922E2F6CEC38EEDEFAAACA712ADCEA2647538B84481E481F8D86CB85D478BCB84E94D6EFCE606FBCB5E32F7B3EFDFC67D22958190213DA83E61FDF656D590A71EE122285F5FA67E6F3CECE54EECCE09F9A53B3AB1093B63ACA5309AE810A4F6CE8AD8D2CCB6671D7C1612533458595192F4FDB19A55F615A6BF7CBA2F0B955F98F617C414FC3C423E1DBE9AF7E72E534BDF07F413F25C7994C32C0D39ACEE7081B3BA3E40953C96B7BA737C965B1EBE91286E4F03A04CA5999E2F50CF2F08912F4E19442DEF12B6A2713D587FE0E239A56E7C113E9E6CE06715A5A265EBC688B1E14C4741DA90A115B7AD9263F325B9BBF6AB61B2F75391E238DC18496F50B6AAB5A69E939AF7CADDDAFB86F0D97D73EFEBE76F4065D5BA8DBB6509FD7858A566F7E8AE4C872620FFE084D8FCCCA008BA69295E88E17645DFEC10D735EECD6582551FF9F1CF2767C5C66F5FE0FDBEC01B5C4E944FF91D8580A2CE60764FEB11131F55A6ADA617EB42C198C1711664E22E4FBBD89F391588389A784E00C6F176DB5E4CC1A71713744562528D605B136A3EEC3127931371D909CD6E122EC8EA7BD022E613CAA23B173B47923CE78827DC870E101495C9E2C8ED72B8D9A800467D78D6BD3D74009F9BB01AEB4C8034F281A5918B1FB8D5E506401E2558E9616E3B0014C410CAE968876E74647BDE9647B8803734177527C5A2F1B7FD56DA47B14EABB04C6B70E1B6BB2904B043716A28AAD76DD7B22D56C6D84F221E12EC11AC27C315CF2D4ADB489E8178ED70768130878E537F6C6FFF2154EA731C4EC3A3CF185789805C9AFA5FFB253931B5695562CDF19784989240B7C3F47A43D6BFFADBDDA9D518ED01D4EC94F3834736CE6BEB94114E5C2B1F368517D1BC6820B6883C2A5E530C933D74CB1CABEFA50EF881F5888EAFC5709DAFBD724F011C446CCCDE6A471CD77A5F58569C8240803090771E50C7E09106C3CB8DAE9699433C5886B0DE113AC6DCA97A28365829EE5D2F8DE1D7E2CC7D8C3BD7A77C8E28E4C5141A44FB8FA11E56B142A64DB75AAD99DD307F08B76B598B0924A33A93494D819662213DE4F2CD8E6E8B26A02630D4E0290D9F5EA9DB0DA9C1B8F16BFDE4C267F424B754386FB5EA62F19A2C45B965D94FC31085AAEFD7BA54787C2B0062908AC9BEAB017880A7B958B4FBB841E1630752181B3AD33CBC054DFCFFBFF389EA00610F63860D6460CF1B572DF6F31F79731575D9E84655B68C01A6B37C80E7C6CFCAFA57317EDCFAEEB74C1F7C0FC6112D838CAA7EB001BA0B58D78567B0E44F33915E2CF8C847F4387AEA30F9363A7C3B9486F8F33D481EC8404BD8A757933DD3FDEBEBB19A19653C977203C5D1C0D51E5A4AD22AEB5BF6483F63B87C6E4DE0E7AD5CFC4A4FCAA07B21BC5BCB4459F67F76BA4C0DC013E8A2F5A2723660E8CD4A911B1875C48ACE8FA957092EFF2B04E56C3906B301D3279A735A55AD58691B38EE1139294181BAECEBBC646809BAA2C99D8CCA26E11A49BEF47D016A3421363F3CD03FEEF1DAA4EA7F1AC8446EBE90B9B78B0FCC9FF456D4C87B35C3804FB7CA85242C387AB4D7C3E8DFA7C751044F35ED47B3A8116AA0477A6B2576A5E06A2F62FDBE4A92573F03B44CE3C04C8E82C32B00D6399C0EB81B84E4BE0F8E611D08747864534605A29607AFF4C586DFFBEBE8624BA50A30925345A3C5AD983074522EDB4BD4292E7D255D4031EC1AF294A4E9D3262C1578FD44E5110EA240F5FDD73BA197AB9426C1B9E52548CAFFA539520F20C4C509483DB5DD07EE1820DAE567425AB1785BE810C2126D47F030334540D7BB931F3038CDF264E1CD8D37A8990A3FE087A4F3C0F7261001B29B014C85AAC2AE416446C5370A8CBE14791B838A6AD43CB050ABA04C16C46D0F2E8531F1175C23CB896634C479A97D1734AC7D0A8C7748C7C59C34FE21622B9FD9B608845ACDFC1DF8B801039F7736A72E891769476282B73D6A2C7B2724A9263B94EAC3A0F9BC67B06012D47544274D658DCF984BC15877345046F0A180F5D30EDAC80A8D730635CCAFB9E74FAD41F842DF169A5511DB7A3B738F50B2CCC6306A3FC69A7C1CBFF2869ACB9B087127860E4EAEC16A5B7EFCFF4ECF19E4B68200E9897C10E7A77B251F2313BA454071CA4B0841631D04C50FC1C99B2E4DA50ED017CBB17FF4179F67D288A24647C3B6BFDC04CEDB751EE2E5C36D4E1D0B4CD7791543A27A8EF2D53369D99194627FC7FD12DC5249D7325AF9E8CCBB87C9815B85B1293004213C30E92F9A729B8D4D8243A5510B2FFA8EA1E3E8A992C1364E6AE87D0BE3384FC3DBD6AB681A3CC0BF6B9A4978E177752C8B23874D1B77A96FB2E030891E816A49F4E275358491746422293DF778BE6CF3725180C0B101A7642C3CB5390C36A0E92FFF84FE0240A7F9AF222AF139B1F6F4733D17CC01AA98F23A110948DB3A58EC8854C8783A6DF032A987118FD7B52A7A45C1C5CF1FD3E8856791C4F0375F1D74CA3E69E5E97EBA054CE4237A99091B84E78E031A7588CCB46C4211A8A900FB49699CC4984C4490C606BF833AB06EEC5D763F09A85C02FF4171B479A66D125C4BE9D910FC448237A2FE3C14B5049204FD56B33169F752ED679D822698CBE959F4633750D65DEF19F30766AA20ED493CDFB07B50BAE0F25496ECA85FC25C9FD714E32052CD412DA0679A3E6190A8CD79534547E84F999E1370E2B9E9B58F5697688E953CCDF76F9D82DBE820A290C3ED1F2F0C7C15B7887B440CE1EA8844EBD743A6F9021390AC5CD6A96673B07E71DF1ECBCA8583DA82B1061AF8C01584153EF011DCFB97C1DA8F82AFA66B5014CAC59B02CBBC796553682447FCF997EB46519427839EA276485DF13A02D3341760F14F322513B958C48BBE74D64FC5E0F7976955D629912B2324B96ECA3F627F340DE70AAA64C633983B63F7E02D9FF89810436B6ADE403760230F00594A8D85283E3FC968BA3692D035BD9BC5994AF584C0D6BAFBF61455CDAFAA8655C5D94DADDECFA2EED690DDD9B09B3421A471C6D8197B9974D3893229E9FCB80FB03D0A5C6FEDE7CAA806AE2FF8E04B5BDF34283EE3AE3B4940D8D9549C7805D9D8CD297390D8B1B68AFC3012CD697BF33ED649B5D37A2C0101C01C9614922D2F01D4572AB6D7CB078271B3E77D287CD65DE616C62E4F065EA12771CFBC1AA2F7CF0010F812503C670B423361C64584D84345392D7C6701B2CEF8898E65FB4B67CFBB177D1784C40CA9AFBAEC1CA4985CA3998B77E1757B68FE5E2919C7AE010FF7CC920A2D06C1BF802D83CDAC159629602DEACC70D3865A40AF7FB95AAA44FBADABF450128D2E9DD7CCF6B3F1ADBBE9C700B99AC3359F234537CA7D870764D5E8881F01204617D2FE4CF4A3DDD26892F495F15AF1AA37780BD10ADAC3B116D06721CB698DBAC981E8E79C7640FB4673CF3789F1160AE43E50A7F54F3C3D0F4C36243CBB07FF0439CC6F72090EC1380F8A960B8B2824B95D3C8D19E6C47945ABD84F401BBF8A6BCF334F25A698DA2F8E6FE5C4A5318324116ADF7F7AE51E75522AC731BE801C50002B3B58D8FF12C5615D8A77DEB5A079542A2EB0DF0BF1E915DAD27CD1A8710E5395C479F62B4C12571A1D1D5BA6969D894DDD93526B70F53A5143FD2C96F4B9EB7C2449F1268228DE1C58C5EED38E6E4435F283CBDDBBE724CE3FA4E84EE5C1266431DF824DAB63CAB4B43512AA0666C3D4B9F7A470ED0EC03C2422E7DE409037979F89A2AEEBF7898FB8162886D57AC8D8E11395ED1DB576231E4628897CEC7424FE7A0B7DC414E9C26E15B8D7E53A67AA5A0EFD2CFA497AEA137E90A5CEFF12CBA104875A6F4A14CC2AD37F08FC9F3EE4DF7E2F6EEF482AB4002069458444F36E02EC35E1B20C3A0FFA300127CA71ED7440ABC54FD0A4DC58D9D35A4EE1CE47E6DF100510695D32D2441F74BE4602EA8E32F505D97EA49D5D10DD07DFB2EC2E2BE91B48B96CDD0AE378F30BB0301E12D7E9CB1BEBC86E673B72A8008C56532057F148D52ABA302255EA22608B98EC2DF2CB2FF6E6D042637AB40D47C3DD7E8D25D3B3BFE748E71DB8A9C601A60DDCA2857A0DC1265D3987AFE55A76ADE85E786B953BB8E52D45A9E3123D3D0A40BC6CD76BC149CFBD66C7992B0F02ED7070CF4A4D9510D224BC583564DD1320FC7D6F28EE9F412715A8AD2E731EB91E42BB73A26DF2BCAAAC9AB2AE69146BE052A79DAEA0DAFFD12EA835A5E7E15E06023AF2A86A71B209C1C47C53EC93BD003DCDDCCC810B7D68BCA174C4BC16C2CA3CACAC2F21C276E1F493ECDC5EACE49BEA34671A059284F6BC8AECC8FDEE4CAA01B11740E68EDF7A57FAD7ED1EA10910BDD9DA87AFA8C4AA27B57297D6AEE3064642DAAC94A4B45C55ECC30BBA96D81B80DB0A2414C4FB58ED6D18311B47A4A917D1A6DCC65D7B18257E32C2E5B9EF90DC5717FAA3BFF2814782BF278C82400E481AF3E8F0FC552260F2FF96923873347D8754C42FA90557DF2494449E538CA23D237ACBC506A0E002F49AB1C05CEF0F0E8BAA042D7CDE9E149C09CB6711840C655C586EBDA76E76E674C23B0F54978335853513A98775C145DCB728FDD578F06F8D4B63038051671C331EB8B9A38EBF048695E2DC7162DEE69629E1F0457910FBD1CB8208337FB534CDF67669BC07A14EF72477409614FE2A6D7C6C566F76D6BA0DBDE8D80BB6D106E0AD0E7AEC752A8F8893F92101D064BCCD579BB6125EC45720BB5BFF1FC84240527060E806833EF852DDCEDC7DB4B83D582B0BB41B1AF481E9B65A30192A6FBF51B8CF916F7CB64919A3643490E8DA6B021DA7F3BD8E25387CDFFF4F280DDE276D0E8BC4E527CDDB75C19B78B5BFF001DCEF2DFC837C02C3939615907C66210BC43CC7815C1586DB50CB7DFBF2AD82BCEEFE7239DFE2A4F10CC8304E113C5F0FA08FB379F86EA4C76852ABB8FF06D0E61458A27EF3E82CE298D57594E437C9136C6E5B63F909C47F5AABD08D36EBF206F84A3AB99AE01BB863D0E022F90FE23188984C91AA6CEC0B93222447179EACADE36F9C9AFC0F788B52A3FF2828A2864AC99E049D9F605B8B5D2F2677BCD3A0C424333E8A724735781FC03E066CC4E2F09CD97E789A0E0D8313113DCDE901CF7E033B03F564FCD781698B7EDF21541E994C35DAE35527291625BB76610A678F1EF1C00331C0EC8CA001FC0F0F902E61BEF2A481B326EC28DB11ECD0A985767702FC5FEE6151EDD860A93AE158181A86F75AB76F66E6DBF70497281FD31CE31A8B850C123040FF6D05CB210AEB0AD0C3F666D84ECD06101C2067E9C929CD0443C61F56D20B0756B75A4A6A9AC5D00CFAC765296D43944C8475F0F2C856364437C6DD44CCB3FDB7EE0F21F4839C76564F5BEF01C4A497FF32D2D25D1A158D60230632D3E78C3F46C9AD3A5D229FC9E7FF9AA26C673480932EDE11F9E1A09DD881C0D07D6AA26FC21BA83716693ADC9209EB5E807321F9EE869FA5097B4664291061DB62CE4C7C5C2BDF51BEFD6929F4017FF0F6421C6560C7E1F7CBFD6547D5440E06085E7AC3BD6E015593CF3AF11C75B008FB566EE7F3FC7A9BED55B15FC5977C7AEE63209587BB328740C7D1908CEFDA554C5D4C7ED527120CE4DED667BCA18FFC53C003B9551A814023E6A62C2AE90EFD7A5C13684BFDA4C75014B1A8E4CBCB9F38D53DCCEC20FF31DC0B5AEF81E6E1FBD0D9ED608E26B0561B3C694069D95B581B06F355AC42115A5CE18C3FA2B5466932B6D70BDD6B111124E6B1B0B7BFC803AF02D47AF28C4E8EC89303AC9A71B365F6FF0EB301507AB0F5E231C59060A29D19898FA0E1CB77A66749434A676476B3334BB9B8B114015F8723850F5A88FD67F0669311E112842A88674CB70C2F48906C7E9245A7EAEC04873019BD46674BDE4CDC5A01D065D120C78F2F49C84A5357DBF4A3DCF6B7C005798E89B0F9C6E4201B6D6A30D547BF06AC717E17BAA23C3CDCC1E251C36FE7951C548742DB202700AA0F2D5AE0238194349C2F8439A84BD7524DD437E4925CAC85D51481C07D2B8B4A7E6CAB75E15CB9404D1C273F625C7309B0EF8E4CEF1B18B281D40B0E00D4B770A43ABA3B9F6170F01AF79775356C2278A0780F8E9D3E5B6354F9F40C51AA3F7965B69B28A138694E7E9D32F784A27D14B1926E88C429D365DE57E6A66D639F6FB81D107ED0FAD7670EC10FFF0C63DFB17BDF5ABF3CB6B53CE236"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY('max')), + "ÖbAüßÃ>ð>aÜãUAîbrýªr@ã*b~ãÐ|îZuä/>b/hüübAåÄð~/ãZCßîÜUO*îÐü+ööðaußð,Öü:öuA_o£C.h©AB £å©ÖÄAÃß >Uö><ðã+ o~ßÖÜ¢a.bߢZßBðCßrÄ©åu<+,©*b¢¢ð©Ö*å>_îBbÐzüîoAÃhA,©ÄCÃ/ðC/*Bvüß.äü@/u.~hª ö,Örý ßßÜãÐå.", + "Öb©Aub>üa.£öÄbo<äãOäý,:b+©åv~oA|az¢+u.v,b,o~Ãåðª*vªA£üî*ª¢©_Ou+ã+bð,/ÜU/~ßߪUå*<Övî |ýðA,ZܪÐÐrßazrªö@O~aO:ãozBÐvOßîzbv,oåýoa£Ãä~üªð©Ð@UB ,_bäBOA*|ðz@üAß:b@a|+<ªvrÄOb@£_ßüÐåãbaîýüZhðv:£åãZ:ÄbÖöîðß©,ýüßî,>_uhý,b¢Aªb ÃýÐbZuUrãÄrÜýîv >ýaA~U|O Brå/<ÜÄ@Cbåb/Ð_öUUZvÐÄ ßÜ:Üüß/î: h¢/boOö,aÄBðO._u_a<: uÄü+åãuvßrUuZ¢Z*b_>b~Ðý~uU*Öå~äªz£b~b.ª Ðhr@äÄîÜvå::ý,Ö>Ð+o£>:,u ¢î¢|Ãv©ðo*:@:Ä> |>ýh.ªðî|äÃvüãvÐüOußvr|ªß@ßAZüv££zöö.BðaýÐaã~,ü bÄ_Z<Äb*ö+ åß媪~Aª£î åvuß@rÐA,|<ü|.ýoöu~aAÖAuCC.U_ßz/Ö,©avå_or*ö zîAOªä£.zzzCuýÃ.ß><ªUbrOÖüîbÃ.ß©ßÄðrBu¢©håC:B_ßZrh+Ää*bUÄä/¢ü~Ðî>¢z@b>z|äß:*ðÖbrOªä_bCß:¢©>ußýÄ|ouü.ÜuÐ~zC*ã ,Äß|Ðz_bÜvå ê~C:.bÐüövü*Ã, ärýãÄ+¢@ßÃããßb@o: oý>ý.hAߢ֣,:.@avühßzîãß/ðö ª|åz:ªußo>ßãßîÖåä,u. ßß|a¢AUo©_>rÄubä öärÄäÖOZa.oöübÃ@aßÖzzß~ü£<üz£B©Ãa@/+uªöb,Ä¢ªBrÄ>ßÃÄ,z|Ahvub+Üå£îÐ:ö/ª Z,åÃðªOüä/Ü<>ö,Z,:>zBa@|Z>bÐå£vvî:.z@¢¢.öz*£ªz+Ã>:b<öZuZäz,/_:Buo>~A_bÖÜãb*ߣåüýh*u/~ß ªUC:ruOå>rh>BÄ o.ÃZ¢äð.¢ü .zOU©¢*Oýß.¢|_£rä~>,åvßrßÐZo:©ß><äßåÃv_>hðÐ_ÐßhÐý©bßh~:h>ý/ð*rÄzüðoÃÖÖ@ªbýUö_v:aª|Oܪý+å,£,Ãߢoör/|ߢ:ýuo:Üh*@ªU@.zßAðÃý|vZB+ßÜ.ãzÖBÄ£+o|ö¢oru_åbhO, +ðvÐ|U*Oîã ©+zAÖ>@åboubz_Ü Ð,bu£+B:,>+h,aý©BZ<ãð>h_ªz*OhãöOßð¢Üä¢ÃZvã£vh,.î+z*+C,@ÄîÐÃ~b<öý©<ubou¢ã|/ß.hî~b©ZZAOýhÐ|uÃuÃAäåzbãüÄð@vã+*ÜÖ+A@~ÖaÖ|* u*><ð@,o_~ðBbbª+ÐÜaOߣ+ýrro£öaB üЪ¢u/~Ð:ußrãvü<ü,Zý_o@~ý>ZÄ*Öu@<~h /ýhzOZÐ~ãOhðUé_ÐBßßuA£Äoä+ÃaZÄvh£AýUüßU/öÖß+*<£b©ß,Ü C.*/hzîA||<åܪ©ÃzÖv_+vZã*ß,Ä¢*B*ðr,ubo.übbb@îÖröîB@äu>ÐUa/ruäÃ>hÃ>ªhaoCob¢ßö ãh*AaöAýUC.:or£üOB+|ðß.oböÐü*ߪÃÜîozãOäÖ:h:+O©ãöOðbu,@o~£rß|,@aã:ýªîCbåvãZª£©rªü,|:@:>ZÐîÖ<Ü:AÄv*r@+>î+Cbß,Cî>î/ªßoßb>,öÄäa+~Bßß| z<Ãu<>r*:£Coã,äAO¢ååuãß~©¢îa_üý~_|O/Ö,*©¢ÄbÖã|Aª>_ðOðÃC<©B|ãªOß>£_ªZu.ZÜZrv>ßbÖBªZ>ýbߣä:ÄÜ£ã@b/î|CZöÖ+BvhîÐ.ª©¢*:uzÃß/ßåÖß@¢¢öÖhãªUö:oäð,Ðîðð:ãAoZ,ZÖÖbCZ,Oðä:¢rh~~ý/ÃîZ+,Zb@åüzý>< _<+B@C£büöböCÄß åã~<,Bð+:ý~./åð+üZ££r>< Aäz. *üßB¢/oîaö/_a¢@_uªBAÃüßbhh++v/_ß>ACAÜ ß:Ü:ü*rCräöÜßUu,£+hÖö>bÜ£~.£Aý>>ÜîߢUua<äAö@/<¢Z|C+Ðåa+z.ýß,ð_br+/aî/ªo/+©îð__*oüCBðªÖ¢Ö_>@:ßãÖahhÖª,U@uUUÐBÄ*aî£u*O*ßB>|@ãÖB¢Ä:+ÜoA©>A:öüÄvßb@o>¢ß~<|© bvAå,ÜC¢_ZÄörüUoOåU+Bß©@ýÃv<ãhüßCãý.åÄ>£Ü,zîß+ýã©Aãb@abhr.ÐÖBrÐ,>ߪÖßüv*©rz U.Ö|__ü+ÖUÖuh/z<üÖ_~©î.ýÜuaÄÖ<, ÄÖîÜ£or|U*£Ub,ª+£ß+ð£Ä© aÜß _U¢vä.>,__ãß_ý* vOð+ª¢büC<Ãýb|Üä+åaýÐ++£åuãBü|+©**bãä.ÄðO©o,Ð> ýÜü/©ü*ªåßZ<,Üüý|Ca£Ð>öaöoBßbuýî,åä aCÃÃýÖOA|ö hr©ªZÐä~>ãö>>å__©ß+B>ð¢ý/. £ýzî/aãöª,¢ÄO@z+>b¢rß:r@UOãßr|©oä,uªOö><£ððhAbr~r|hößr_rÜÜ©voAÖAÐ:ãÜzÃO_|h_ä@bvî,CªaBOöZäÜvzãî©££îð|ýCUß*ÄýO*hCÜü.ubv.*.©ª+U.åba:¢>våuO bÐrv>ðr<ÖBãÄbðüßÄ.b,£ßöÄ¢îãuZ,>ü~ª£îzBðÖ,墪Býr+ªåC:Zb@¢> aÜ ¢©vð |ªßaßßð,CßBß>Ð C,ßða+ãO/£aãaðB©¢u~U*C|B£Ã ~äãÄã©+u>ܪzBýrÐr ,O:¢ã:ªð<üýãÄZ bUz~öoO¢ÃªåAî>vo,+ÖU>äüA,CðO.U©b ýAÐåoUou|Üaö/Ã.rߪ:öAßrZZOãuýu:ößÄð:_vuC~AöböBü.>üª¢rCZoã:ªü.ðU* bCÄÜö©_+*+aäC Ou.Ða¢ßÐÄ.Ö¢B£UãܪÖåýU£_zbväÐZZÄC/ÐaruÄ>*,za ~åC£Äuv*:rýÜOÄ||åýh:îüu@©/_åv@~ö¢uÐohrabA+©uÖUA@oö:.o|.ª©ªýv©+Bðªbhüü,/Ãüb/_zýÖ/.AÐ bOÜbßC>@rÖ+£vТÄBb_Ö@Ü:BhäZ©ä|䣣Üä/vboãîîår/AîÃäªzU.*~ÄZßU>oÃö|Īhuabuß ößÜÃOªZ/ßCrý>v~ C|å.+~z_z<ãåéß,<î:_ßABOöb+|Ö~u |åî>*.ö+~ßA@B:Ã|b ¢a£uZA~rýhªÄC@ýuåOð>,ã*©öåªðýZ>CCåüýhAý/ß~+oÄC@Z:ßuz¢|öߣüZ,.£uÄ¢<~U_aBär<Ãß:röã+ |öO oÖ~Ao+£@u@ZÐ/Ä*Coåh*/A:ABob£/ýAZ+©ðBª:@.ßÃÄzb~b:ÄB*©ßßîhz|öýzaBU>a+ÜÜU@Ã*Ä_Özhö>Cªö*£*>_ÜßßA@@Bߪ<ßbuv©:|£ bZhßoª/åÄbÐ~o@ßýý:ÜýA.U£ü£/b£,Öäå£|.Z©ýB<>:|ýýßÐOAÜ_üªhB|*aßbBOuýZöà ä|v>©@@öãüãÄråZ@:ãð©Ob+ u|ÃbC,z:@bZbªhäÃAý*r_¢ß.©OäA¢ª ¢orÄhüðÄz~Obo~rðzüU¢rÃoܪÜv+ð@ZßðÄ©ð,.ÐÄCvAª+_£ß:v|b,ühðý.C+Ã_ßÜz*o/ðZ@åU@>ö£|.bh:î£üU/ö~Ðöüz+A|:vza,rîOЩßå:Ov.abuU£hßbðrãO |~å>ö<,U.©ð|Ððz/_<,<@üUhÜðz/UBO+ÐäOBð,@ÄäOª+zÃîu@£+Ä/Ãß~ ÐÄaoöýz>_ßäÐr>oüê +åßBaBðªÄ:ðAA~Ör©>_îOZåÖäbÃOð|*Zvb><åß©ãhbr ããÐz~. h<ä+A:,ðB*/ävßoA.üÃß*.hîOÖZܪÜ,ª@Uuß.Ã:a<ä~>ÄOö@Ãßz*îªüÐ örZo¢ zöß*A~ ¢Ä>© <ߣrýßÖBß>:>oãä_Z_åãðö*rªãuZ>îÃÖu<,@_ãîC.ÖbãOu ß:ö_B håßÖ~är>£Ü~ßÃZÃ/*a/£Ö.oä@A,>,ß_+~/b~~ÜöüÄ¢Üý>a<ð£+CöB:|ÄÐöU|<ÄBßuuuvuBä|b<ðh£o+>|:ãAĪvhå*ä£_+OУ¢:ZzBß+:h:äOzÄßä >r¢~ß,O/A£Z||ðäz:ö~ðCUz_ßhßußa|åöO©_Ab£åh£ÜÄo~åözaväv.rvåbß©|ü¢ab.ª,U v,ZÃß<:ª,rUåîßÖĪ_ü.©üvü OaÖ¢Öü>ÃýÖä|~¢ÐßZ©~.©bãv+ßb.ߣZhz+ª<Ãü£UÖrðbåhAðUª+z©|£Co>vöîbä :ÐUuaUC A ©zOÄÃ*© ~~oîßðý>bZ*åOý+hArÜî£b>@öðª ýah_rr ðrOÄuÄCä_>ðbÃ>~Ö©_Cî. .b~/ö*åA/OðÃv|ÐöãÖo¢üaaäðß.UbÖhaUaAÐÄ*ÐÜ*.AÄ>hö¢|/B¢Ö£Ü~ßba,¢:öUÄð~,rÐZÐ|hv,C.v¢ß*öª©@U~U/ð£* oå:Üa~__.ßh*bª,+<,ß+~v@ ~r©ahÜߣ,uý+ð .ÃBvðC:z:£Oäü@äüÖå+Crßî_.£a>üãªA:oýBZz*,ävÖAßvßZÜ.A¢a+zÐ:bvððCü£ãaÖaÖA|a|r|îãÐ/,ußv_hÜßo:ðý<Ä aðîbZãýÐß öAbßß.îТåÃhä/@brª|ßbbZUr£ýÜ/~,<ýð~BÄý AAväã¢åb:_u¢+OýZåÖã~o.hZA_ÜUrOzUvà a~ð~|+Ü|ü+¢.<£Ö~Ä+ߣ orOð.©Ã>î.ÖühB+Av hÄuîUäCZ~:~~å/Aaã,УoÄbbböå/ |+|:bÃðBvözßCBuî @zöhUýZ¢o.£hãZüÃüaBAhãÖCî~/.ãbªäOÐ.|>rz,vßåvZü.£ ChBhäOÃ_ßu©_äÜCßßüCä.OÜÃÄÖzü>ßöoÜBÄî@Äz|Ða©ý£ã.bÜ:>azßðö+,/CäÐbýv>ÖÜbrZb£_h,>ßAä*vOb öãýoÜ_hZrÃaü©Ähb¢ü|o.+Ö©_/~*|Ö~_a© ©Ü¢z©hÜ/ãC.ãbîÜÄZ¢åî~b ª öÜÐ:C<üa+:ÜAZðhÖÖ~:aüÄ+býУ:ßÃ.<Ä¢Ääv£oß<Ð: ö.ß|ãU¢îäýÄr£~öOå©ÜßAz ©rv>B.£_uUAC~îB¢|b@¢Äî@r©Äýîßü£Z£bo*|Ö_ö¢<*vÜArÐ@©ªÜÃbß+/ÖÐUªÖ<>ÖÐbß@b/v,|~r*ÄCÜÜîÖü<,©<ðOA:ÐU*äaä@bü+u¢aТö<Ãý>a+b~î aý_huÄr>Obß,ÃZÐha|ýzoZßÜÜ£ä>ãoü+<å:UßuåÜ/@__hBaÄÖå*@~ªOÄoÖ+|ããAB/ðßß> Ü©uä¢ÐZ£Ã£oÖüß:ßåÄÖBAä ðÐå@/ÄOråU_|ä+Ð_üäCÃîÃðÃu££bBb,Zð*ZhÖuãð@:Z>.Uª.hoÜuðo.UßrzßbhBßäU¢@bªßÖArO:..vüAuîözo+Öðbz_îAä+*<£oªB*_*arÐýöß,ð*Öãuo>Ãåå~aZväý ßCöÜB+öå*~Zü£Öýuðª_vaoOüüZÐ> vBor,rãå¢ãýßüå|rÄuCªÜ*£zÄ £ðüßߢ:_b>hÜv|h*ZÜ|:AvªÜUbªî_î/ãv¢üCîzbu~~v/ðßbaªa+|Ü ªhéöÜýäöУ.*ür*+ÄB ÐCßÐüz:>:îZÃöäbîÐb+rßäbÃÐ>ärv/uoOaäAåöý<@*>ã+Ð.Ch/£©ÐC@åACaðýAaÜbå©:*U ýBÖbßß|.b>ýýÜö>bvC>ouuäТ+ãÐa~Cý<ã©Bé¢@Üßãza>îîouªCåCßßåßöh+hz~zz£îÜÐöz*bZoîh Bߣ/î:_ývUbzýA@_/¢z*ubuÄrª:¢ðßrhÖåÜîãÄ,hÜ +©Ã/üZß@ä_ªÜCA~öUzýîb:bö_CvªÃÐUo|îÃ|aÖ£Oß.ö©_üÜÖ î:Bhåvî¢ÖåãaußhZ/ur Að>©ßB£@+,~*@ZßvoAãÜöUäßo~~ß+CÖ|.Zýü/ ܪ,U*Z<>ðAäh._|_b©¢ä£>bÃaZãßBaßZÐÃîb,Äî~ £©|öuÄraåuz*|©Z_Ãub:Ã.ðu|.Ä¢>o+Üb@aã>ÖÜ~¢ÜuÜ>ðoaª@Ã<ßC¢UÖ +ßý|>Äã@zb©/Aö:>ßîrhÄ¢vÄAý:îüðåÖbo+ü~bZ>öü¢B O<ÖA zÐAª¢Ð_Z_>vö|,oî*ä~<îÖ¢ÃrÐao+ã>Ä䢪oÐ<_¢.Z>Üuý.Uö.ߢo_.|C*.åÐ,ðÃý|böÜaOåzüb¢Uã:r ÜuöAå_ rbb,b©åa+ßÜ©ð<:öuðzr:ßzvåu_öOü©CaÐÐÐößã£bbU/bßZäzZÐC~ å.ÖÜ>ãCðã.h©£OÖÐý.b©h,|äubðãîU_@ÃäzýOZa@huãz+oCB~ZzAðr<äå_/î.Zöo~oüz/ÖßhbhýOÄ|ãðß~bªö@ª<,:C¢äBBãv©ÄuOß©ã>OüÜrZhzÄ>bãU*ub|<ðü£ovüAoðAä¢ÐAîrBÖ|ßvBzßð*avªî/¢©ÃäÄr îýÖb+B/BÜbðAU:@Öuã£ãUîöÜ_aªuöAoraÖä|brÄu*ß~ü*|£üCð+>rhÐåÄa<ªöÃaC/<. ý/ü*¢CA|hh£©ä_BÃ*ÄoÃãb¢|o+oU:î¢å©©A__aåBBOÖ|+ßÖ.~zÜÄ Ä<ðß.OUößBu@ÖaO>|o ãb~©zbO*¢Ö£ohî|öOCÐCã¢hZB@bªß|îAo/åvhߪÖuߢOoöBªrba,ßb>rðZ~Üa~_bä¢ýÃAzß+>ýåaaöhh//,Ö_@rBö©*ãUãУZ_ _ö.|îu£åão@î¢*ö:<+©ßAýCb©röU@uªðÖÐ _uzÃÃvªÄbövî~zjklÜU.£>o+©_Z,,ÖAÄÐAhªO<Üu.vbB,z+ðuA@h@zÃbböahüuzzð|o_OÃaªaaa,/bü+O+o+UåO.*b_u:£vOöÖoãhßÐ@Aîh@zZªýý£ö~böbb+ÖrBoÜo*Ðß:Ãîhu+¢£ Ö©Bb:_UßÄ©hý©C<+¢£*UÐÜÜ<ãðBä.|ü.ªÐZãh¢¢_+£bÃ:aÜ£äÖýZBªýåªr_/,+hÄÄ+öãÜÄvboîU_©*bß<ãZ@ ªaUª~Z¢ðü@@rÜ<,åß|:åð.rîßB>.åüO>v¢Üü¢ ðü.UðÄa:~~.ªAÐb:.rß ß<ßuAa*AöoÄ/U<¢>:Ã<<î @îaZð::ßu|oZ@:OOrð+ý@/åü*_B|ýÄÐ /<üåuÖbå~CðhZüüOzZ<_BîßbAAð,*åã>ãßäA>zö:ä<.,>ÐÃ,|ðvÃuOu_©åärß©_ÃZ/Z:BðÃý A©¢<.~Z @ß/¢hv£ª *ª:Ö¢röÐBb/UZ£Uv+r@ªbvz|äZãCboo£äÜ|", + "AaßÐ_îaãh>ßöBBzýB.hý>üoýbåb_ßCãÐîð.©uBî@@hB@ouba£Ð<üÐ:Bbãß©£ãBð~ã+У Z<Ä", + null, + "9999-12-31 23:59:59.997", + null, + "1973-01-31", + "23:59:29.04987", + "2002-01-31 23:59:59.04987+08:00", + "2002-01-31 23:59:59.04987", + array("100000000000000000", null, null, SQLSRV_SQLTYPE_DECIMAL(28,4)), + array("0.3273", null, null, SQLSRV_SQLTYPE_NUMERIC(32,4)), + 2.718281828E+20, + 2.718281828E-20, + 893569276, + -1, + -7764, + 184, + 0, + array(("A82F7923662A496625B3CD58E906DD15019C700D5F48E2AD60858A9437AC118D0E99EFA02BAC0C52A44EB1940E8BEAAC3617AB238573055F4CCBC2E19FB52F78A13F494F173CE9548F1E6911974E9FD59ADE5D1F01EE089B948F545FE92BB2EF1E38F3CE419B95FA2D56936609F4C8FE2CED46C0571077B237AEBB87E8896B646B7AF35E5BD193FF4963F1AA5BA191A0C75533FBE5F2970EC1409693E00D11A4EB2EFA8F0069A35A5A4677F41ECC56961D1BBF92566F7F79E3E59D1A3A001F3B"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(384)), + array(("304F1D1447944F1CE70A2A62C02D5162E8BC9EBA4D9CA036FA24DC9C61E6F40BC0D00E85A45BE19CC2E44C26694EE3BB0A0CE814DBEFA194AFE71922B7B2BA01151FA2F01FCBBE8DDA01F8694F7ACCAC41219155FDDF2FD12F79D6BC41BFE50F2A4B104AACF39B3F4E5B39D9F63845351A6DE09520650336EFD0C1A6F4014B1B1CE83F036A81004E865207A2A555DAF634A1A1D4DE4FEEC448D95BDB32F54A4C0F1EBD0DF941CB996C920FCE5E609199F6CA71535F773CCCFA7ABB902A001F3B"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(384)), + "ÖbAüßÃ>ð>aÜãUAîbrýªr@ã*b~ãÐ|îZuä/>b/hüübAåÄð~/ãZCßîÜUO*îÐü+ööðaußð,Öü:öuA_o£C.h©AB £å©ÖÄAÃß >Uö><ðã+ o~ßÖÜ¢a.bߢZßBðCßrÄ©åu<+,©*b¢¢ð©Ö*å>_îBbÐzüîoAÃhA,©ÄCÃ/ðC/*Bvüß.äü@/u.~îC£ö~v|r*ýuAuür_bðü,B_ýÜÜ>_Ar@UðªßÖª:Öã©_uýCbð|:£.:@Ua<*CåobÄ@aãÐZ./rªb bzäå|åÄãöB,ÜbЩ~ .<~~Öü", + "Öb©Aub>üa.£öÄbo<äãOäý,:b+©åv~oA|az¢+u.v,b,o~Ãåðª*vªA£üî*ª¢©_Ou+ã+bð,/ÜU/~ßߪUå*<Övî |ýðA,ZܪÐÐrßazrªö@O~aO:ãozBÐvOßîzbv,oåýoa£Ãä~üªð©Ð@UB ,_bäBOA*|ðz@üAß:b@a|+<ªvrÄOb@£_ßüÐåãbaîýüZhðv:£åãZ:ÄbÖöîðß©,ýüßî,>_uhý,b¢Aªb ÃýÐbZuUrãÄrÜýîv >ýaC壢Oäz:ß+b+AvU|öö+ðýrߣßA<ßåãäãb/¢/bðü+î", + "äð>vboîU_©*bß<ãZ@ ªaUª~Z¢ðü@@rÜ<,åß|:åð.rîßB>.åüO>v¢Üü¢ ðü.UðÄa:~~.ªAÐb:.rß ß<ßuAa*AöoÄ/U<¢>:Ã<<î @îaZð::ßu|oZ@:OOrð+ý@/åü*_B|ýÄÐ /<üåuÖbå~CðhZüüOzZ<_BîßbAAð,*åã>ãßäA>zö:ä<.,>ÐÃ,|ðvÃuOu_©åärß©_ÃZ/Z:BðÃý A©¢<.~Z @ß/¢hv£ª *ª:Ö¢röÐBb/UZ£Uv+r@ªbvz|äZãCboo£äÜ|b_|,<", + "AaßÐ_îaãh>ßöBBzýB.hý>üoýbåb_ßCãÐîð.©uBî@@hB@ouba£Ð<üÐ:Bbãß©£ãBð~ã+У Z<Ä_oh@©î/ /+£*råuUå+.|*ÜÃ,,<>ª@ßß+ühU>bÃ_avå,h/~+üo>Öüåð*Ü<ÐCO,ßߢ_Z+b¢ÄrOß.Z<,_ößC@:AAä~B@Ã.C +|b|_£üüU<ä>,C:b<ÄZbÃBÐöÃu¢*ö~..Ðö*vvÄÃoãA+Uýäý|aðÄ©ä,<Üßðaßbv/A ÖbüÃBýÄbUrßOA/ AßCoß, O¢ ªÖA£îbÐ:ðUßAåðöaª¢r£ªÖ<©ÜUhvuö.ä**>|.ð.ßrürC*ý.ãÜobzåßÜaÃ", + "ð.<ü_/îo_î¢Zöüß/üC,zuu¢+O|a@ýÐ>äÜb<,Ða£Ã:ßåöoäB*b*ßåZ ¢ÄßCÜý.+Oß.Ö>ä<.Äö:Ää.*©u :©:¢ðª|:/ܪªU©vb¢b@,+uä©£ã.~:u+Cî:@Öî_äßOb.ÄßBÄÜ:ßÜZoßöußßýBrýýu,<Äßo@obrÐrzßoä|h¢h©/Büb>ZöC|ܪObOz +ð¢ð¢Äb/¢£/£ö.ö|äzßz>£Zä|b>.CaUªã_ruarbÄa_:ãäZOhãA Ö,ýßÄ¢Ö*|r©zª,ßß.uÄ|©vBzür/aZå+|bÃ>uãÄ<ªUã<@ Uä:b<ÜîC<£ÜßÃUaö_:>boýoãÃÐÄCOOÜv~,£ªåå£ãßßÄßbýåÐÄ,:> AZ:/r r/ÖÜuÐ@rZª,b©ß£v*Z*ÜÃäý,ÜÐvð_BOO©|:,bA:~£r.u,C+vr ßvUîvãb:ö~vÜoabvðCöÃbü¢öh,ÄBö© ,|ª*ßoÄbªz__åzäA,hhOUz>vã£zÜåhü>vväu_©UBrA*,>.Тv*zöß>bBb >oäör<*AZ¢:£>ÐåbüuüCÜ/î©>@ßaÄÜOÜoroBuUßåAZ~ßßÄ.BBZZß<î£UööU*£u¢bãaßhuÃo¢Ã>C~ývðß/AãZÜ:Ä_A..+ZBAZ£>üßîZå,h©BýÜbUÃa/ðª+*Z+zvBßZÜ*ª:ßð£OBC* >@öoÜ,å@Ü:ðuOa~>o¢|.>/Að£vâUüb ÜÜärßß, < ,üýbA~ðoa:|öãb>ÄUZß+~/,o+Ã*uuðoAbð|uBÄböªÜßößÄÜZîªUAª~,¢£/_<©U A©A.Cövª_rãÜߪ/+©îb ªÃh/<@ö~©OªZ+:ßZÖz£*¢aÃãÖß~Arbå|ªîÄ*_~ð~aÃö*ª|.*ßoª*vÄĪýZéðî,ªzAÃ:Ö:ÖO+b*öb*UO,UrA:@zårB+UîU£BZ b|äüª+..üO+Ü|£b>vÃÄ*hÜÄßU©b>vh.v£ÄZ© /£ã¢A_C@/@ÐO.ýü+öOZãbÐðZîoãÜBCã*+OãAäÐCuªZßh*zäh/åÃ@aßvÄÄ|ÄåÄ . Ã+ßUoö@ubbUÖðßðªZÃ*u.z*|îCzzau@vå¢ý<+<:ö|>ßî¢C~aýOî+aU A¢rrä@ýå:+ðB©Äääöä.ý. .©î£@vÃ~bývZüäoZª/~¢*_Ãaîzh ü@ªvðÃu_ZuýÐOäzöã,Öýãvü.ÜýäüåÐuh+ª_,ý*v£¢ý,/ä:bÜ|¢,BzßrÖ ÃZC~bö>ßÄßöbabüäZ©zCb+ĪuOÃå£ß,*_Ðî¢|©~vý+£©hÄ||.uaoå¢Z |>+åvªoå.~_vO*z¢BAh©ÄA<@¢C:/ßU<î:~bbzÃa+uÖv_OZ+bî,bä>ªª_AãvhoÄbOC¢ßªZvz,AÖ:üÜð* Ö,@.Oª.ãü@a:/åu>Ãb/_<ÜÜ£BÃãÐo£ÖC>ð,Ür£a>rü¢ÜUãöh_övÃ<ßãüªå >ÜÃà Öîü@>:zAbö @hý,UÐÃru,b¢Ãb.oz @Ä@vza*å/£B£u¢_< ߪ>BÖB<<ðÄZv/bZýÄ_ußUãýb*zAC|o.buÖ~_ßUÖªAß+zbªý~ߣ@bz£bý¢:Ð:b+îÜZrA©<Ðo<ߪÜ/:ÃüÐz/zî¢ Ö|êð+>z_£îªaä~ Bb>bZÄå¢@ö<ýh¢býhö/:ýåßÜüoî~ð:b/C rUÄbߢÖB©Z+ãovß||î,Üößãå:zo_ª.~©b£oaÃ>u/öü,Ã_©a£Ö*îOb*,+,ãª@:r>UÃÃÜ@CßäbÃößü.o ßZ@ßU@.¢ÄUÜ¢ãåÄüÖ@ð>ävo<îßaäÖ©ð_Oãß, bC<îÃbAð.ð@>b*@å.@ßÃB>ðÃZä:ÃB|ßhZü..ÄðhzzhbCãÐ *vðß©ðܪaOܢߢ*ãäB,rCöBO>+>,ö.ßä|_B.oÖhu>*,UözzÃüzua:@r,OÖ Z.,©~+ðbZ@ð©BüoÃÜ_ãUObß.¢rß.A Ãu..äßC©ßäAUaOA£CbZß/ä @huªüb,~>AößÃv©C*~CÐýröb¢,ýBÐhrîãîåZ¢Oh¢.Z@ub* +/öðU C*zOoý~bZä+ßbüß+,bB@*ü||hZuÖ<ßðîª,bhOßýäýÜÄ©ÄZ*ߣÃ<ßã©ð~Ö.Öu,äߣUä*>î>C©bu@|Uåããð,CÜ Cbð<>,ÜbÜAuO>äÖÐh.|Ar@ÜãßÜ+£îU~h>ßZAÄ:oü+Uýöü*ä~A,AC¢Bvü~bð@©äðU/bÃÃ|Ða©Uª£ü_ãä:ðߢ>u<@,@ /¢_£z> Ð>å©oaz+*äA/z/Ðu:~äU.Aü|ZoUZ,hªZo¢ß*üßÜÜzCäª<örîÃ.Bb/UîÄ_ +ýÜaýrvÐZâ,U£ßBðzo*b*ü*~ýb|äîÐBߣ/Üazh©*Ö£@vzo/U* ª_OUaA./aoÄä,ö@|ªuAb¢O>a Ä/bvߢz@|h|¢,.Ö~äC>£åU~ÐÐ_rrvÃ/boîzª*oO_,*ãßüðußZ<Öbý+::ä*_Z.BvåÄ>:>BoUÄðüU_.ÖÖß ,ðÜö+bß:ãÐýªîhZböC<:ÐÄCUACACîbB~Ðüao>ö :©AU.UBAãö::£Z ªÃß_îvAÃ_ߣ.åöCC~aÜaßÃ:Äýöbro:~:z.+z*öbb/ý<:ÜãuBÄãä/äv@îUB_üOß@BuOC<~ßÜ¢üÄ~ßraöhÄý< ~hªAå:bv.bîª:,U~ÐÖ@åbub~b~CÖ>uåßý*ßÜ+.ö<ªv*©:*oÖßBaãÄvvîoa£o,h|a~zÃ+å<ßýZÃÐðh,CÐ/*ö,ubCÐbîª*ÜÜB:Ä*Bh£ßå*za_a@*ÖÜåîÐAroÜ_rüZüå/u>ªZußzüB¢<ªBr@BrÐoã:äbbv_||ö©>î:åßA,UCü:ðßB|ªb~ABÜ|ßbü+:|a©uÖA.C|hu.<ÄüªO+_Aö>©<ý_ãîöB.î/|ãu/ÐÄî,ýý<ão_,ßö¢©. @b*rUuO@O<ÄzýîäÐo:©££ü>r¢ßý/Bý:Ð>Äåß>Ö_O¢_bßOaÜ©_|h|.uÖ.OAüßåäbãðüOðÖoý/b£+åArZÐÄ/@uÖÃbvö<¢<ÜÐZÜh©brz.BC£Ð_¢ã/¢C¢ ðä£ãAAC,v/_¢Ã UörobA~>åoåßCÐ@oßÃÄÖüýäZ£abîo£|AAu+îu:b~Ð/ý<üUð,åB£ãðö*UBð@bö©*uªäÖî*¢ð ¢Ca_a+z.b©AbaÄBBäCßzöA£bBÜåCzOAåbÄãb+/Ü|a+ßýß/|öª ý+aU,Oð£å/@+:©©<ãBbß zÖîüO©äãz©hÄ_*b¢ð*ý<é.br<à Ö|båã|hÖ:.ªÄª+ößäZO@üB*©<Ä, ä~ßuöO~ãObZ.*bÄå|Ð/ZbörU:Z_Z*UOª/rbðª+Ö/ßB£ÜaÖOî+ªÄå Üaî|rîÜv¢z~üzB_ý+ªß/*©uãvuªäOü ~@ððBÐ*Ãu©A©ª||Ð>~ßhað/üBßbzüZîb£ýa/,O/UAð|Özý¢vÃ>CZ+ã ©bößzÃbÄðÜöA¢|h zh~BB*ãBoߪöb.Aüh¢ü©_öåäCÖa>ßZãCÖ¢*ªÄa~üß.ö+£Zo|OßÐ*b+~ößão+o|Ua_,r/b/UCAýãCa>uãª: ý_壣ªåÖ£ß_å+öÜjklÐ,C~A~åb/|oBý_|Oð~ |¢ZAýÜrÖO>üÄvzåa__ãuaC_£ßBb*bª.Aªð:bz @A©ab.©vUÜC@a¢B+ /b¢uåÃäÃ|BðC ããÃuAß|ýbCý|äZU_~Üöuªaü©C£ ß > Öoîðvßߪzß*,ö£©a,ªoýzýåÐßåaB+:У|ßu.ü*üÄßO£.U¢aA:¢ðrO>aÜvoC,ßÃuãbÃßo.vAb£/rh*:ßbß*b<£b+B>rr©åÐÐ_<.ª £_<ý/ðßb:ü:bÐAv~Z_Ö,Ü|<__vo|.Ü~©/hãZäbbÄuz¢@Öhöã:ovö£r_Bbö:OÖv£©,Ü¢~OýÄu*£ÃAãßZZ*£ ¢U>îo>ÜÃ|<ßbãb¢ÃüÃbߣ¢Bãߪ a|Oã.¢+>~+öÐä äãÖu.ãýuCz~väÃýh©b|oÖC,£,/<_Azaüu<ÜÜ ¢,Ö ß:ävoÜÃ@/ÄåOÃ|Ö:Cãü+:OßZ¢A,îrßb©ßãü©_+u©ÜA~ªhÜ_îA uÜ/,墣|¢C,Üz£©r,ä~BðЪz~/~rhã<<åå~vU.ö*aüÖCZaÄöðö,à ö.A~Ä¢vr:ßoö:BBCª©BuÖ,Ou*ãÖöüözß+/ö>,AA©:.ÐÖOAAbbýª.A+Ðî, ª¢ªo örrb h+b:£/Ö ©.bzß©åý îßýÃABb.,bzBÜ_ýýÃöÃðoÖ~ª,uüvzãöZ ¢z,b¢BvýAv+:Uîåb BÄObOhr+zßhßC|CaÖou~öbä/ðC>roh BuýÐuBZ/or© zhOîÃv/<У<+bäÖhb£ýuo:A~hßîð<Äb,vÐ_zÐrßöÄ£~/ÖªÃ**h,@u/oãBªÜå+@aA~bCzz/,ããA@>äªã_h_~ z|oß|Ärh/ð~O£|ä©<+AîÐ_©Oð£ü>ÜuÖßö©ÄaðZЪUv,ð: äzÐObÖ@Ã~ÜîýîðÖÄ+uoÖUüããÖr£/©å_£rUÜvðBªÜvUÖî|ÖoÄoß_/ã+ß/䪩|u¢Ä*/ÃÖ.z.ã<@* ý Ca./+C© Cßã/*,z.b|£@.<äaÖ,Ðýbî>AßCÐ~UCã@AazåðýüA@b<ßÃ:î£o.Ãü+©vuZߢU£ÐOöÄC>,oüBÜ/Ä*>h|aUªãä,ß @ßZ_håðÃå üAßA>:ýoß* zA|o_î,o|ãr:Oü@uª*,Böu*ß:ÖüÖhãê:arßÄ+~ý__z>Ü~¢büU+ß.U+B©ÖÃßð£aÄhªýOÜÐ>uÖ,|.îãAåCîÜî:årr¢BhüÃßbî@ª+O~:ZUÐobaÃürßÄßÃAäCUU,ß_©ª@_ö*£åZ<äZ£ª_Ozßr>£îzväBAb.+CÜßð¢£r¢C£bbî*ä_A.zöð:rZåÜZv©ä ª<ð*b<ÐýîüÃÃ_:~ýö. bªÐüÃh_AÐ.uAüýö¢ZÜo >rîðÃÐbabª<ª|ª@ Zbªzãð>*/ß ß,Uba|_AªÜýa:rÖß|o/ÄÃåO¢UZUbî+Orªð~+~ãCü+Ä<îZ/äåC>ÃýýB:ü㢩|a/Cuªß,_ª,uÐA<*ý.Z ß.+ö.©rr@<ª@öo_öð~UZ>b vÐZüö@Ð<|_zäh£<Ä_.ªåbýäv|<@.,OaßÖBBrCÄU©Üýbü£z.Z/åÃäåovväa.:ýzB,_ßr£:ü_¢@*Äo.ðC Öb¢©hArã Ä.AA@öb©v@+vö~üªr~Ö*ü @ã_.ß,|:ª+zhvC~>ãÜBУªöBO©©oUh~öv._©ÜrövZrð/îÜã>åÜZåÜ h_Ãß|ð+Z,:CAb:bo.ß~ÐÖ£ªbr,ãoZ:äÃOðvýüü£aîýß:zäÄ+/Ä+>zb~>ö¢¢oBraöª.ähObr:o|ãÖßhÖ*Ã:Ð|b*,C*ÖA* <ðÃýäãîý~r*@î*Ðuã©ßäZ<¢:/äUAÐÜ.AãC©£hÜüZã*BU,boa£î@Bu>baZU_a~åvßÜ Ãß©BbbÄ@að++b,ÃU+ßv ß*b©*åUüÄüBz/_/@ ÐaÐOßÖßAãbîaA îßýßüBäðA/ÐB£*<©ÖA_A¢ ߣ£¢å/Z~aoBý:Ã/Ö<.<ßýZ:ÐB<|Ozä:aÃ|ý*o r/£//|ý©åÜua|C_ß*@Oî@.äBvhÄBZîÃb~huAo_äîÐ/~ßöZz :år£ß©vObãbhüß+¢.Ãrî /<¢+_bãbªÃßäî.öU,ßîbÐö>,r>üuob|~Czß_ÜßüðuöéÐÐÃCbB|@~Üü+ãýî_ÐC @ýAZå A>o>Ö|+£¢ä£Ö/ý+uzr*Ü+ª_ðZ壪ܩCîÖå~hªAߣCÐuhUÜZhüzÃãöCö.üUuåðÜåöÐÖý_.U¢v+ã£,,©>~@£:üZö¢öoO+ßöÄ*ãv,>ÜÖÄÄÃ/:vå|,ý:ªu£/¢CröC::*Ü©B,ãbåý,<ßð,££av:@ðhä~oÖ/ÜCCh_Avü¢£ßð*|:BözA|b@rÜ¢<.zß>o>hhbb/ð¢ýüAzßr@.£A©A~AAÜbv*:ãÖ|å+öÜÜhB,|+aä*ö,|ð:b+îªB~ UoUvÄhB,|¢ðã/Ðv_¢B£|O©ßÃÃ/aÜ+©vv*/_ýãhäUî:ß <Ä>Äßßv@/ao| ||ZC aî*£>ýOZÄ>U.£Äå>uýöZý|,Öß Zý£Z~~C~/åüßu>_@CÜvA*/©ã*~ ß :@ªßoÄO¢.î©ZbZa@.Ö/ÖýO u,öbuüOÐ<äbo@hvÃZzhvü@Ouz>ÄbÜ/*hð:ßÃå>>ßà rã~ îub |ßÜß*~£z*¢ýa©av Äßü::ð¢ÐÜ_~+o ÃC.Ä>Äzãý,*A/¢ÜÄ|BÃÄßBUªä¢rbaßývoaöåªö>|Aäß~C/>ýöbý>Ã:_~äßäå@vãO,bå.ÃîBª~C©ðZ©|Ã<*aßB¢bÖA¢rA_BZbý+î|ܪzr /Özoå+î@Oð*îZ@öbðå£:/åAðbü/~ýðäAß<£åÖ~oUZ@+oöhÃäö>äУÐå_Ð,Cðö @vbzbßäb Ð,oð@äüîv|¢>bh+B~Bh*Brð.Ü ã+|Ö @CC@¢bZöv|öZýîhÄb©UðrÃ>o+b¢BB+Zßöéßß:~ãa~öhðð>¢ªÖÄ ßCã¢üo~:räîvh zU ðªb|ZOC_A:CC:<ª|£bAo¢.UäÄßåaÖ~/OUb>|Ü,vb¢Ð,ãÃ", + "ðZoühÃ~äªð¢,åªÐÃð@>*Aª+|ÄäZ*Aä¢Ä|_a.*:b_:¢öäÜårAýÄîo@üüzðªvZ.UãÐzîß ~ *::öî,£@Üß©v*zü:rª~Ä<ÐrÜhußu|åbä/£+/Ä|b|£.ß/ªhå@ÜãÃuÐåãªvÃßê/öîÖßßÄö@Ö£@AbbðÜoý v/ÄräC|ßÖOaÖ+ür:ð©ß O~UBAÃÄßÜÃ<@ß**ýUÃî©UîO*ÐîobäªaB*©oÃrªoO,ÖAbÃ<ðAªruuÜhbv,î+h_£üo©+Ohr£ß¢", + "äB*£:ZhÖvOzãüðv>ßbðO£ß>üðð|rü**ß,@Üaãår/><£öuCb.|<ß*h©A bbüßüu:<Äößb_bÄî+BUboo_ä.o£>_aÃÄ>:öÜî,B,ß~üðÄUb~bCðýý¢üAüðv|.zCУA£Z@ZbZßý©©bv@Au.Ü.ãåý.:öOüU_ý>:uvêßb", + "|AýaAãC:,|bÖv*ÜC~£ÄU££h ~h@@Bu.hÖß©¢,bb,aAC~.BãýãÜ.ÐZÐAðå£/åzª+ooöý:©oÄ>~ uª_|ð>z_©zß©ãAßÖÐУOb.©ö..+ Ðð~Üðb*ßoýoÄ/äZBîöÄzoßýUZ@Övª~hA|,öÜZüåUã>ßrî_Äö.Büä<_ÐÖU<î,ýUu~ähobð>ßöb<<£aÜ Ðßßã>¢v|A©r@ßb|Ö>£Ü£*©ß:ð|rbä.<~z|/Öz>îvb¢öü£ÐßBÐ<ßoU/ß.£,Ð:huîrb_ªBbß/aÐ@|ÐÐßßrÖB +~z åÖaCðÖ/CäÐÐðCCÄAðbß.ÐäbÃß~_ÄAî@¢ÐrÐ b©@UZ,ÄýýîÄbAb, ÖåªaÃzz rÐBörCOî,,ýv_~C*hBÄîå<©ü@räãªÄ£Ð+OA|ZÜÜäÐßãbhÜOÜv媪,:Ðbh/ýv*z©ÐUå*_|b+zãObÜaå,.©b ãACüÐz>o*ߪ,>aîßU/£rr>zÜu,öbUA~~vüãÃhî¢ubîA@Uß|ÜBbhýaäh Ð*Ö */îzraC@Orà ß.hz<ß@/ßOöOî~|.ã>üÜoZå¢ýÄzUÃAªî+ßrªÐãäöãz@o>Ð.¢/ÄéUðO>_>zÖ©£bßzðb_å__~u@©~bÃã©:+CßÜÜýîhÐÃ_üãîz:Är£ßBîß*/*ÐåUv@ußrvüý_hb£ÐßäAUÃÜv~ü>aä*ªßUä.z,aü_vªCª¢îZZuOßb£r:~C_BC:éÄ>vöî/,_ý+uvð©£üO*_<+Ã_Ob.ãräîäb|ö.B*ö+ãã¢ßÄ.ö_î:|ðÜîrZaüBî<ªO©b@oÃüv_ªUüãÖäãÖCåöÐZýbo+£,hUbîU£öÖrvU|¢ðöÃßu|_oh ܪ£:+b/ý ä.+Ob:ýßB£>ä zß*zvößBuaðvZ~r~ÃÖvðuÖ>~>ÐÜ|Öb>ßîv*¢AÜOA@U¢./ðÜäßr.åUöB_ Öß@OU o@B*AU~_î~U,ýhBh|üîÜ_£ª~üoßzZü£ãZî<î*~Ъu©>zý|C.uªU|v:Ü@î>,å/vvðö,Bb£rÜýuz_åhzª.A,b©ÐB~ßCöýäOäoö.~*ª:AÖAßU üîî+ªîüãbO~rãßvüÄuðß*hª:|öaüa¢bã<Öªðu~,üuABÜß+>ÜObbßî:üßz/ߣåaß/CÖÄBr*ÐCßü~ Aã¢r/uÜð~UðAÜߪÜÜÐbrr©£b£.|ß ðýöä£Ü<ߢr©uîääßÃz.Öü*bå,C*O|_A£üª£výohahüo_.üzßÜUüBob*~îb<@.ZUbOavZrªß@O.ªar_<.ß_, |ð>åUb+öê~ãÐb*,ÃaªO.:ðÐ:*,*|bÄååð@v>,bhUåß|ãÜZCrBÄßðuîCýÜ.å©a+¢îÃöß|bîzö<ö_¢+îÃbvo<*îü©a.ZÐüor©hã<|CO.ä:v+<¢äÐß,ãîZýÐvßoßo*ßýÄA/ÄÜãªÄbZöb@,£ð£äu*b,ªð©.|©.zAbb:| bîBîuÃܪ*öuåhuoZh:ðz.@A+vðzÖvåýbãzåÐÜzC+ªý~ÐOÃ_OoÐðª_Uð@äТz,A*:öoAß*.@ß _Ä.ðzO~+C~_ö+>~,*äbÃßý|£CÜA£ÄãÖuCZa_>ª|_bðv/ß>|£:.ý_:C@|hÜß_oð©ZãzãB>bîÖz@£åÄhãªr+rZãrÖýÖ:.ÐÜa,hvü~>©:o.@uuö<¢ãýðr ßÄ+/¢|ã*b¢OüzC@¢Ð_ öÖußÖ¢ýß@hª.ß~©~.å_öößCBÜ*vðßüýB:ªv~~ðªß£Ö u/u+,¢@BÖr~,C¢Ca.+bý_h@ör Baî£_ýäZZäUîärhü:îr:|ÖÜbðvOb_@¢<ßÃÃîªbýrh||bvÖ/ÄßÐZßßÖÜUÖ.ªý>uý:ÜöÜbBOzOOå,öb.u@ÜðîÐO¢ÄAð:hr<ýÃî|CZzý*¢¢.B¢ð*ßO rBu~zvvoUÐo¢ACÄOO>,öhð@.ZZzbýß©BZßa,ÜCªZãhbUrý~z,:Ðä/urZ|ßZAöOo:bb*uCz,bîBBýäZrzÃaÃ_bߣbªÄãüß| £ýªoh¢+Obb£ü Cr.vªü*ö>ª,v.Zª,.ßzö.Z|+ãu,o,uåÐ*Öß~ª.£~©rOh_zaCåBý/B rBîb,B+ZªAUz |AaåýOÐZrC/ß_rvZZu/£a|ÃÃ|a_r,ªhåuý:Bärýv+baýZ£:båZ,îuu|/ßCÄvÃä>hßbÜz©uåüî_ZU>*aöbhý*ÜC/¢~ob..OÜ©U__vCbüð<@©å|zo£*Cî.*|br>äÐ@h:_ÄÜ¢aüßÖßýobäv/|bvý/bzZ* Ã< ÖU*:ÜAüöBðzrß~ZðvvÃßÜöß:@Ä,U//z >Z<©>ÄBîUb*U ßðOhÖÖur~üß>ýCUîZb>Bhov Ö,uüЪãaöýãor©©ä+*_vÄ_Ã*+/äZ,C.|ÃUBOva +ÐÜAz/à .vÖrCz ö|ÖbÄö/A¢ßuÜ©b~zbÃ_hUA£b©B_äh+r:,îh¢@ðª/ZÖ.>rð©ZãüÃ@|oBðîÃ.¢.~îUªÜ+ÜîöÜCbCä>¢oäÖ/UAo©©åUßuÐß@ýaÄãoî/_å+îO|//ZªzÐã£OO_Ð~ðåhüÃrüªBCo£:v.r_åCýBu/öuðaüäßãoC~ü|,ðÃÃuü* höãuUbbh.üO~¢ACaý*ß ,<é/zhÐZOÜaĪ.Zð_îßb©ãC üÜC/Ä+Ö<ßßÄrßÜðîzäUOOäA¢ßb//ývÄ¢~*<@Az|ßa@ðßÃbCÖüðÖߪöhBÖ>ª£ö >_BB¢_/*@öÄ:h_zãªav_*bü.Ußrh|Ð.+/oa¢brAÜäüÃözzU _åªrÃzî_äoBà Zßß@ Aü_©Ü,ý>©++ACö|å~©CrÃCv<ÖîC*/~oå.üZvÜåCurr¢@OãboC:Äh©z¢îÄbðåv£bBr<ªh©ZBÄ_îa><ÐZîãüuýäArB +|ÄüUö|h_zÃUî<ß*ý~Üzh/ýÜaAz/buOv>ßzÐ,Özü/*ö.ª©ö<,¢å//ßrö|ðör¢Cbzh/ÐCOBöUvßäß<|O BãA/*ÐßĪ*o<ßC v£ZoðßZz©£o¢ð.:ýÖªCÜB£ö,ªA@ßð|a.zZ<ýýo ãÐ/bC¢ý@£/üävbahÄ åö~©C_ÃÖ*ZßOÄzvuÜ.ÃßÄßýî+£ÄåÃ|äÜüðßð_,rr|£<ÄßBböÄ*ÄÐa@¢BüÃZ:ãßbß/brÜ@ ©+r¢uOÖîUUbäzCßÐað/ |vÄv*/|b©äZä:¢..ZÜ>,aab ABUrAr¢£ÖvUBö¢¢,©:bö<|COüv.Ä/A _u+uUO+A~B@Ã.C +|b|_£üüU<ä>,C:b<ÄZbÃBÐöÃu¢*ö~..Ðö*vvÄÃoãA+ü ýuÄ¢å ª>hªåäZ~>hýO* vß/ªääÜ£BêOb_oÃvÜ_ähüÄÜbãÄßðäåzo£boßBÜa|ü,/ýÃßÖ.ßår¢Uýäý|aðÄ©ä,<Üßðaßbv/A ÖbüÃBýÄbUrßOA/ AßCoß, O¢ ªÖA£îbÐ:ðUßAåðöaª¢r£ªÖ<©ÜUhvuö.ä**>|.ð.ßrürC*ý.ãÜobzåßÜaÃ", + "ðZoühÃ~äªð¢,åªÐÃð@>*Aª+|ÄäZ*Aä¢Ä|_a.*:b_:¢öäÜårAýÄîo@üüzðªvZ.UãÐzîß ~ *::öî,£@Üß©v*zü:rª~Ä<ÐrÜhußu|åbä/£+/Ä|b|£.ß/ªhå@ÜãÃuÐåãªvÃßê/öîÖßßÄö@Ö£@AbbðÜoý v/ÄräC|ßÖOaÖ+ür:ð©ß O~UBAÃÄßÜÃ<@ß**ýUÃî©UîO*ÐîobäªaB*©oÃrªoO,ÖAbÃ<ðAªruuÜhbv,î+h_£üo©+Ohr£ß¢_ÐZ>åB£Uüh:£,Ü uªåZZUa£ÖÜä,zzßßü.ª©bã|,ZvCO.rzÜîbü_z+@+_b_ÄaÄ öOz>UÜCv+A>ýAhãu_v*U@~îUhüzä+~ðOýBÄbýßÜ~@ß+£:ZhÖvOzãüðv>ßbðO£ß>üðð|rü**ß,@Üaãår/><£öuCb.|<ß*h©A bbüßüu:<Äößb_bÄî+BUboo_ä.o£>_aÃÄ>:öÜî,B,ß~üðÄUb~bCðýý¢üAüðv|.zCУA£Z@ZbZßý©©bv@Au.Ü.ãåý.:öOüU_ý>:uvêßbÜb£OýözüÄ.u ý@ÄîÜAUß|BbAvaOrãýã/.*a*rÃý:oý<|arýüÖ >£*ý@©ýªîýÜBhÐ~ßî£@+ÃbAß©|¢@Abau:>£@ä.vzB/ßOCå£ýüuAªh_v a*A>Ðaª .ÄaCäÜö+£az֪ЩÖCýC_Zßüîu @>+Ü~bã<Ü,å@COZ£öCU@ÄvÃZ+ÐîbbªÖBî@v/aå/uîCöväªäðv¢ãã©Ã¢Ußb,ãOß/O£Üª~îä£bÃA¢~z/.Üåüß.Öî/uîA¢ö<ªACÃÜ¢Býva.ýÜo£bAð+£¢öraA.Ð ,ÃåuÃ~bý>î@ß Üªü,.ýÖÜhäBUZä£ßC£+åÖ~~COjkl©|h.| ã*U¢ª/ý|UßÜý.Ð/o,Uoð|rAãrhß", + "Z.©ßBCouÖ:ÖuCCZîOªÄo£/¢uCr£az*üö/¢,î >äzU+ðУo,*ßrörð ýäß:©îå~ößZuB.ÖAB£_CåßüãB:_vß+î¢.£v:>.Ä*îäÐBOðßýÄßÃãOv©äÜ~ßãü¢Ö|î©ß:hz@ÃðruaBå£O¢|_AÃb:oü.Ãð~å,vCoO@B+ã.výðýA©Öåð£r.BÄåãr©<Ī~BbßüîöÄhbvÄCÖÃh,:ª£ß~£ýzßåÄhßz>O@ª>UuÃãä+ý+<ã<ö<£<Ã_:*öuðbvýrZÐAU, ðÖÄß|£©<:,Äß,Üzä<:£OäåZã+zZzO¢îübý©rý:åð.ß.BuUärå/v~~u:b<ä/U++zã>ÐÐ.CBäa|ÐÖb>:BÜ|UAä:,|ZUzßZö|Ð/ðävbö¢©ãoýb.,u*åOå£*.ÐÖbAüß@Ð@ CãO>üüAÄChß_hª,îbb<Äöã,aOBrbýßoB¢£ð~uÐ+îoo@u~rª<£bÐ:Uß+v/ozäÜýÐzýÄî>©ßÃ*Ã~_ßzO/ý>Ð.ðBÃãßZ©ob.>Co.uUäZCßã*+Ü©v~övÐ +b~ßuZäBrý££ðr<,+Bö|Ä,ð|~ÄîO_ÄÄå BCb~¢ýöaOîßrÄ:~Oårã OªühAu>+©|>ZÖzãb.ßÖBý__ä|o| ª.@/,¢@ÜB:Ö ¢b>a©*UA©ðý.ro*ð©u+uî©ðüzhUu@hO©zOz:ßU£ Ü_ãßAßðÜðb©ua|ÃA Ã<ÃAAOB©~.ðOÃ/|AåhhbOZ /~b@/Z¢ª/<|O¢zÐ+ÖC/,ýªu£Brh.|üh.h+~/C~UZÜzÖrä,.~,Ö bãö*ã+..Uorb: oAvÄzvoåhª©ãAÜÃß_AߣB|OaÖbÃoýh~vZäÄ*håB>ooÄ ©ý*£Ð:¢oUßUªãUöU|aåaA,|ob £©öz>ðää ÖÐb/_@.A<¢C>îðãöhZÃZZ/O|,ßöuözzÖýîr@@~*>ª+b@üßÖÖB**£o~b _r©ÜChä*,a vZ¢.>aZZO+£oö¢@ÄåCoBð|zßÄ>ßO¢o,_ß+Ã~@|+äo,rÄãbÐhª/ýUuî,ÄýßÄýOC£AüB+|ööOzÖzð@+ªö©ÜÃ|roo åýüªÄä+©bÐoÐÖÃOO©U©>ðüä*+äAu>_:äßÜ<~ý <:+¢åßrärý~>îü<£.îC¢uãßoo>Zzîýrªr ÜrCZBbo>£b¢a¢>+o*|:+B¢£u<+>åüuÜýz~Ov_CßA:ÐrÖ@oåßðТ£hãuh|åßÐ~v_.Z£ÃbzC¢uÖ/î+/îÄz>ÄüuªCä<*bÄ£ B:rOÜ:å:ß<ßC,îÃðäÄ£O>uäZ ßoÜuÄv,ýî£ýÄO£/ãä©uoBuuo_< b:ßä~îãöZBuBu/h_åzC¢,/z/ *bªaý©,vãüo+.¢/,å>Ozv,*@, o:éu>öã.ªav+ðZýÜîöâåÄOrª*ß,îðUýöCä~Z<äð|hvAZ¢/Aüz©@ab ÜÖ£ßvOä:ýAaßߢãÖAbÖbÖ/oðýîß/ªvÐýåÜb㢩ªÖÃÃZýZߣ,h|£/Uý~*ªÐß*,/ãÄzaöa_aC*:a+boo£Ov,Zb¢ZÐårÐUîãv*vã|Ãvä£ãh:ZüU¢_O/b£býhßBavbßßÖr@r£Cuª<+zª_oª >v©|ßßrO+Cb<©ýßãA+UÜÜ~@z|öà <:ürÖÃÜßhvö+zaZýOhß,>Ö>ß*|_ðÐ*ýäCåÄðhãÄýuAÃÜ.ä:Öz_h/hzãÄöOãOhãbßvBU/z*ã .ão:bÐ+>Bܪrr|ÄßAýýüa@ã+üî>zªA:öÄßazh+£rß*b+Uä~Ä+/,z+äzåaÜ,_.©£ Üo©/:hCzßðO¢h|ã>Cz*å<ýÐýß+OrA_äÖå|/bC>ý@îöb ©að£Ãb£üZ*>+ðîßÄå£ß|Boo¢. _O¢.ýß,O ß/@>üåå:@bbhuÃZ£UhäzU+@< å+ÃýÐ~aZ+häÃuÄ¢|*O <*ÜЩîüßöCZC:,|~o+b,£ÃývCZßaßuÖårOaýC£ABÜÖqwty,Z£C:rZßÃÜ+>ª,BöaÄ+,ðv,~:> üªå¢ßOBå@*©Ö_~,>uª¢A£ýßÖ*ßÃBhåb©üäzOßh_z@>~ª*ößß@ÖOüã<ÃýÜhZA>aТvaßÃZuÃbbz@h.u,.üå|+ÄCßý+<åbvã*UzªuZ@¢Öãöý:rb,arhߪ|>bî*büoBãªuUrb ðîßîrýbrBZðý:©ö/ußÖUÄåU|:©hZ,uöåzÃvuAÄ+@ýÃUÖAO¢aÄoa::ãªA©u/@ãÜßä*b©Ü,Ä.>/uUA¢<_Zbh|uu<.ãªýÖ>Au~~.rÃo<Är~£ä¢rÄoO~U~_AoUb_ßr@~<Ð:rå<ß*hC*üaZÐ|*zh/ßov:©|.ohh+Zr¢Bð./zu ã:Cu~aå>>rhüÖ¢ Ü/Ü@a~båߣ@,+ÖaAÐ/+UÖbvößüZ©,BoCoC¢:r££b.> OB zªU:,@++|ÄoßÃbZ,<Ð<,uvC_ßbÜ ãvÄBã>©©.ðâÐß_îz+üªÖaaªÃÄCA<ã Öb_zabýr+ªü|Aã£.ÐrU/CO|ßUC,C,¢rÄv+åÃUuîu,Üuhb/~ãbÃzv/ur|<Ðbå©äßÖ.Uz£üöO>zAb ö/Üß@|bà ðZbOzr>oa_@ü<ÐßhðåC>ßü.Oä¢büv+CßC.<üU<£Ð© Z<@+:Äü©ª©öO@üäåzÃo_î£/ÄãbUãå:U+ã<©ð£>o ý~Ü:äðî@B+Oö~h.£bß@.vö|*v<~*îåbCövÜî*ðîýbß@¢Üîª>h,UýZßîüUÐ_aýz:_,vvu Ö¢>C>ߢ£Ü©Ü+åýÜ*Azî©ÃýB*ß£ß +~ü< ÃU©ö+ßbªvÐ+vb:>ÐO*ö*_£Ü@oZãazZrÃzbrÖB.©>äb.UÐbÖOz~OuACßA:hÜBübZý_ÃüavÖ¢ÜÃ/>:u@ßB@©ÃÄBü©OvoZö¢|_ßß/ÄACÖð|ö._~¢ ßö*Ã|Z*|å|AÜÐB:ÃhCåéßßÜýÜÖhÖÃ/b|ö* ªöav:u_oa aãBvv.Ãö£ah~Äß_rßOhörßÐhbrB¢u:U£Ö£Öðb>/a+¢Z OAuuÐU.*AbCrBörb bÄrÖ>ßbA¢ozÐC~~@,öbýååübî¢Ä__ãBZ,ÃZîb~ÃroOCBB¢î<@ÃÃaob/OÐhääC@>ßba*/Z©/ßUãßÄÜåüvÐuaähbh UBOöÄãB¢Ã Abv>C.ÐrA:äåaUAhªZzßB@à ÖCÃuBb©brUZa*ÖÖ+~AÄöýz~åã+A*©bð©>OÖýÄ@BüÜßÃÜüAßä_öUbßÐ /_ß+Äa ,oz¢@oaÖ£bðÐOr¢ßðß~OßÄßåäÖäz/îo,ü:,@<*@¢äÜZOhb|CßÖå_hã>Ã*/ÖÖzà Öî_ÜÄßB |zö b/¢ÐÜrÖ<ÃaªUCöÃOA~Özo:_v~zãZÐ. UO@:vÄÃý||u¢ÐzZ£ÜCîZü_£o~å+o<*:ÖZ©*bª>/<*ªrÖöãßöZ£boßC*Ä_*å+ _@rC:*büubZÃ.ö+ åuÖB/äßZZöO ¢@U¢boßBý£<<Ðýbªß<,oý+£hCZî©Ãðß@OÐ Ãߣ¢vhZ UÐv*:ßr>ß_a UåC>Üvh,bãüzý£+ßhäCaÄA.,äð:ä>/ýüo,bß©oãaaåv.Üö+ß/+*ü.ý¢u:Ä£äßvå£ãýoª|_hüaCaßÜý¢î|£/hbA|OÜä*ö@ürÐaª|ÜßÜuîu+özýß/ÖzäåÄoßåZz Ã+å+|C£*/o,Ü*£ä<ýB@Zzðh:Ð|OªÖOö~Zvߣ.o|£,h_ý:ßß@/C,b_îÄhBöý©*å~Uuß>bãrbã_åîO+oaîÜ©O¢Üäb+|£|:oåZ>_ZÜ£zÄ©Ub|_£a@Öððbî©Äö<*ÐC>r¢ª©£~,¢B,+~býð|r ,+bî¢@Bý¢ß~ß.îrr<ª:ååb¢å£_|<äÃÜ+vA Ö:Zýb|©üªbzü:,ã@zC / ÖoUbü¢Cðau@,|/ÐOª,zuCaã*~Cbao:vö~aýzbðCö_A~ãÜ|åöB ÄÄaurÐzî>ã|CÜ_ö~ß_:/hÃZ+©B/a|aUCîßÖ_ð+ßvýo.v+/UbårÖ >©ra/£_Czz >ª/röß,£/ÐO/üZaýUã+C*UîªU¢ÖCZßÄöÃßð©öuzv>_ ~ uuÐ/©zvðOüUÄßüzAZ+ªAuÖh+*Aa_C¢ßðzZa,A©ª>/A>ä©öCUýurOÄ|B:b*b¢zÐß_o ,@öðaªÖC~rUZÃ,ðÖ_î/¢rÖr| ©ªýrÄuüà |~zbrª.ªüîrß©ÃÃ_rîC@C£ ,ª*aÜîåüZª*ß ::ÃãuªÜZ*@ýðZ©@zãouðvî<ã~£ÄBððOzä+bÐrZz@äAbb*B>O<Äv<Öoöz@Ð*bЪO©¢Ä©A|¢~_å~/ããÃ|*Ð./üBö~@BªbbÖ@hBå|UÃã<¢ãhЪoÐC<ãoazzOr|Ãhhðö|_Ü*:*öv:å@Uß~ã+ .ßýCUåÖrßîÃý_|Ã|©Z~öUÄ,Or+Z>b@ª*r*Ä*ðãz©Ao¢/vZîzß©hZU/BÄ,ßîä~vCZZ ßrä*¢ßüðîBböðð<ü©.,zCÜUýöCð:bÜA*oð>Ã::Azz @a¢:åý,ª~ÄåýuAüä.>å@ãCbÐßý/ß@u+BýÜUU+Ãhvv_böªäCb<:ߪ<¢@oCrö|brZZaCðªÐÜýZU©ßÃZÐýC|b/ÃÄðö OBã__Ão*v>hU© +ä:zoob/îÜ_>:ö>¢ßz,,ªÄzÐÖ|@//ܪÖ:UÃ~uÖrbýAurä£ÃßävÄ£_Ä|~£¢aCOßbuvî,,_ªhã@UÖÄ*z~ßBÜår@bA>äOh¢ÖbårýýööUzZUCåCZüãU brA.îäÄräå@*:@B/+_Ä**¢_Ü<£b£ðÐ_aöß|_b", + "UvahbÜåª..C:", + "z+¢bý.Ð|.ZãýÃÃ.êâÐäBÐÐ ¢o|oÜ©ÐrhuåßZ¢b|ªÐU:ãÐîîÖabÖ@+Ü*ÜÖ*Uo,¢ªBÜ_<@ä b|Ov*>v<åU£,Ü¢üÃÜ/_A@Zã,rB¢*br/,å©ýr*C.ä>v:ý@ýãýhBÖAýãßÜÄßbvåð.Ãßv>C¢Ü*©A©@vßãåuU£uü/.,båu<_boý~ãÜOU<Ð*+ÖBýzz_üåîãauÃ:U,å/u.ZߪåÃð.A£¢Ð>Zäu*.bÖ Uª¢rhÖî,_Ü+A@ðbööãuåýßÃåOÃo.ÐöAa<åvÃý+ÜväZ:,rz+*B£ßbo£ß|*¢Ö,ßb,à C:*a.@~büaÃ*ZÃäzßzBCýããBà +ª+<ßåÖbBäA Ãhuür¢BubðåBýÜz| vªv bhüÄ>uߪuªaZ:¢öåa£raÜÜ@/aü¢ÐðßÐä/Bã:ðåu@.Oã>OßZAãÃubr |CZBh,b~Ä~_ý*~,üBzaîB~ðavr©ªîu~©£B_ÐoãÐã:ßaä*vb£ßv|o/vCÃABÐüüAªÃ¢ ä~|åaßCahýUCßr©üb* ååýã>UÐrÖ:£å uA.:BðvÜb.Ch/ðZ_zaüv*Ð:åÐb¢v~*_>BðåßÜråoB|ß:äÄb :©::êü>|_ÄAZýrÄäªA@A>ÖBhßOßðýaAaZßðåBß>ö,uU<ãäB*C~U©_züî+ ä/O|~@©AaoZãÜß_|£Z>ªZöb/ß,Ü+:ýäa>ÖöbÖߢÐßßäöbvß:hü£©,Öbð+ÖÜOÖz~azv Aã>ßߣÜß>Bh+@~zU> O¢ÖÄA©ab:ü>uã¢ßöߪ¢oãAªö_ßU+U~/bb©h£~zßßßÜOßzvv>~~ßê*>haßou.¢ßå_.hO>h+<ßß*bäߣv_ÖߣßÐ<Ðoý£Üo~.OüzvåhBa:u åßa:Zroå©©ãobßö,a@>~zu,OB__Öh:Ð /:ä©ÐÄÄ/¢ZîÐ ßu<öÐb>ö£a£,ß*Щ,Örð>ЪðZ£ZßböA ©ãZ bß,,U,ß:rvî*üÜu_Ãßßbª_©bÜÃîÃü Ðüb.ªª*ßÃCöoÐaÖöãvÄ>¢åAuÄ>hzª|ðß_ðßOävUbã>ü>@*zßýZÃoU~vhzðbOzª|OÖß *£+öZý+~/.r@<ãrzBßÜ_ü©£åörbÖUöÜÐÐAüo¢*.oäýßÐB,~ CZ:+ýU*Ãý¢:Ü:åAÃÖ.ª©ýãðß_ªÐ£ö<,Ö>©voo Uv¢zC¢¢C/bªÄü+|*ãbÃ<Z>*o¢uA_höbö/BÄãB>,ÐB:î:¢åý*+î@ªvb ¢rüÄAÃCö~+öö,ÃÄå>¢+.ã~å_Öu©Ou.:Ã*Öb£hÜ+bü> BÃ𪩣aAüå©Ü//î*~ÖAîÃZ.|b¢.<£öüöbÜU:Crßh£,bªv,Ðý/¢<ßu,aZߪÖåo©@b:|ãO:u,öåUzußZ©å.bAö©ßBZAî¢oªðî>@Üýröý*,ªh>>azüoÃAÄÃßrÐ|AÜ: Bðr¢* îÄ|b<<£/¢ÖCö¢ÐüîCÖ|:>BðÃ:bý+ObÐýü.|©Ö ß©¢bîö|üüBzb~hBCߣÐäbã@vU|ahýroZhÜöîß/rýCv<@,@ÜÖ,+ýüÜ~Zªö+îrUßðbðÖ+ohzà A.@ð.Üß>ar,bv:o+¢bAߣÃbà .ª¢h¢¢Béö+b*ro|,Ob.ãß<ªa_Bvä© +ߪýOo*,|Z,~@ÜZvãåUU@aZ>ªCAhb@ãßýªývÖrü.bÜÖa+aCo äßý_ vB@hÜhoÜb©ü+*Ðß*~ãA*Bü©£@ªðå*åÜ>vîßÐãðrÖÖü/bAa©+*üvüüOUz/ä¢OrZ/Oå©£vªC_~ª@ð|@+¢ß@B©>zýZa|<_vO|îu/z:ªzÃ~CÜãvCU¢Öb_büaß:Ö@,£ÃC~v.bªÄCuðA>ß@_Ä<ÄoÖðÐ>ÄCªî/ý_ör©ý:_>/r@_>@h@|h£r.r+O_:.rvUhýÜub:ðhÖßv+ãhÄÐz/u>Uz|Ã*OÄ+ÖýZbå/äãb~ü_ZîÖãöb+u<ßhüüÖaß.BäîÖ_+Ü@O<,ZåÃÄ<©u |ÐÖzß<îüãzCh.A.üÄbßÐ_ü Ö|üð~C.>Z_©vÃ*|BZ£,ðrb*üv:Äý/å<Ü~,ýÐã_zä.ßãªÖÖТoö@BhbCÃuý©h,/b,båÃZ*ßvÐ _>+UÖu>ÄBã<++¢@Zz@ãäO:ýÖ/_äb/v ©Üܪ_Ð::ÖO.z~~AÃUoabz.ähB@¢ßu+/Zã@ߪ~Aý_äbbÃÖo.O,ãªî/uAUî¢@AC£U,Ðh:bÖ/BuOz,.v¢îbrÃÐzð|ã£/rü*¢Cð¢baîCä|v©o/Ü~o+oCvrÖÜîo@äOhÜÜ©ð ,,Ö UÄßu£.bo<ÜU>bbãb.*hÐð>bðÄÜ<ýUB,r,bî.<ýC+ßaAbð£ÐÐããðAvA.Уå@äðBð,,bBah.ª/UÖîð<üýbbÖh,O*ö+£OÖ~C>vÃå:ßoö@rABÐ+ü£aüa oãßvB> OÄoÄ|:UhðbÄa/vß|/©Üã*ªÜr@ßOö£/.Üü<ýu+><£rÄÐ/Ö/üz|©ÜåUª:,:ubã.ääv.bß©r.@äz_Ä:<:ßäߢã<¢CUð_| ÐÐýb ä:aĪZChoð~Ãåýîý/rAÜa,£zßåh¢bßC <+ªa/BU>@ÃzÄ@|b|© Z_öZ <ßÄîÄo+å_*ö@vzbðÜUã|üÖ>~+ObCrÐO_*b¢üîv*_OÜÜöª/Aa.åð£äª@ ãuåA:vÃßo,Or©BA@îZ+rü|ýöhAÄ ß_©Ö_zCÃ+zBðBüÜrUß*zä,Ö~u *Zuöå._+ý¢Ð/©*ü h~r:CýÜßà Ã,<.ÜB@uöã<./©,Äýo<ßoý @vo+Ür+>/v|Ðhî|ä¢î:,häÄo_b,a¢ äoÄböoªÄÖa~*AoäöUß.zãðÃ~r£_aãÃß+äB,,abö", + null, + null, + "1973-01-31", + "23:59:29.04987", + "2002-01-31 23:59:59.04987+08:00", + "2002-01-31 23:59:59.04987", + array("0.3936", null, null, SQLSRV_SQLTYPE_DECIMAL(28,4)), + array("-100000000000000000", null, null, SQLSRV_SQLTYPE_NUMERIC(32,4)), + 1, + 1, + -1138956117, + null, + -26881, + 1, + 0, + array(("1A0BEC66F89701C5BF23A683CB4F47CB7115B598E3CD4F89528BDF6B9086CA95ED897115611686F38D26F520F53E880639B929525D47504DBC62146DB795353958109541DE316A5B8EC20ABDD82E931403D832D65C7738A5392459FE01193BF7F0BCC7E5A84628074FCEC49B3D93758DCE006ADE635FDCE0D8F008B9D86B59758613CC1B67AE6BBCB02A868EB39D68A5AECC3000"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(384)), + array(null, null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(384)), + " ", + "z,B:>£@ä.vzB/ßOCå£ýüuAªh_v a*A>Ðaª .ÄaCäÜö+£az֪ЩÖCýC_Zßüîu @>+Ü~bã<Ü,å@COZ£öCU@ÄvÃZ+ÐîbbªÖBî@v/aå/uîCöväªäðv¢ãã©Ã¢Ußb,ãOß/O£Üª~îä£bÃA¢~z/.Üåüß.Öî/uîA¢ö<ªACÃÜ¢Býva.ýÜo£bAð+£¢öraA.Ð ,ÃåuÃ~bý>î@ß Üªü,.ýÖÜhäBUZä£ßC£+åÖ~~COjkl©|h.| ã*U¢ª/ý|UßÜý.Ð/o,Uoð|rAãrhß©C~ÐÃÃüaz~>br*Ü*rå:£>OîU¢Ö£ ,.<¢z/©BBZ:ÄC~åruA*ãU>aU*A¢.ß/br+ýOB|z~ÜéUî/Ð@îZÄA~.ßbî,uZZßUv£uU |UCߪ>ÄCB.<ß~ðZà aZü/.ª©O,,@Ãhvv_böªäCb<:ߪ<¢@oCrö|brZZaCðªÐÜýÃðÄ©*å©ÖZvOv~aÜä:>Ä.ZÐ|rbvÜð>ð@ êBCÐv+Ðã|CîBb<*/üäbv B|>ÃU//z ÜOzv*boÄOZ|A+~+COýÐ~,ãäCO>@¢Aaðz_U ÄßßhZZU©ßÃZÐýC|b/ÃÄðö OBã__Ão*v>hU© +ä:zoob/îÜ_>:ö>¢ßz,,ªÄzÐÖ|@//ܪÖ:UÃ~u.ÜÜUÖrbýAurä£ÃßävÄ£_Ä|~£¢aCOßbuvî,,_ªhã@UÖÄ*z~ßBÜår@bA>äOh¢ÖbårýýööUzZUCåCZüãU brA.îäÄräå@*:@B/+_Ä**¢_Ü<£b£ðÐ_aöß|_b_©>@Ü/vZZÃCo¢hß_©u ð.ýuß|ÐÃh_Zov*ýßCoäUöãOÄb OÄÜ*ÃAuß*B+:¢bB:å,u_äߣ Ä,ßü,BUvo:,aîÜã", + "h<üß>@<+b:£ZuU.UäCzO©b|B_öª,ßÜîbäýãîh/Ö¢ýaö:h|AÃAÖaz**hbðäU_ðb|Z_~/U,@C.*Ãr£CBüýðî*bÖªÄ@ãßüZrrÄî:©î_hßz@¢ªö£h>ðßåU¢aÄ>_öåî,ª_ãuhýzO:O/ähªã/o©b+*äh,ö~ÃOöCü©u,Ãüß+ß©ãz:£:,>,åb+vß_AÖ,/v|ZCU rÖ£Ððå¢Üä,@A,>ö|bzZäÖÄäÃ*ö|*CU,Äbh/ÃÐÜÃ<ýß+~>Z_~/U,@C.*Ãr£", + null, + " .@Ãã+UãAÜ >hÐb_ÐßC¢äåzb¢ßå.ýß_*výÄ,@ð/ªßý¢äßãUUüUhAÃaß,>ãäU:~>bÜ,bhåüÐ@vZbã+Cüh+ª>åªb*ðäUr£ä~ýÄ/ßC*a>¢Ü,ööa,åÐåãbª/ÐAhZ¢bbîb£uv,.@*vv<+üvöýîU>ßå ßÜü_ü,©", + null, + "/ÐÄÖÄâý*,ª~~u<:Bo+,|vaÐß/Zã/hÃ/@_öu_rvrª@:>ÄUOÐb>z>:*,OÐýðZ,ß_uÄObbZUðåîoÜAß@A~v|ÖðßOýOhÖ>|vüßßýUÜ_OC/ß~.ªZ|++uö AãA¢,_råî_Ö*ªð*üA|Ð>,hCð ,|âÜ,ZªööýÜ*ãU zuîbUßÃð~ ß<:ðåÄBZýü>Uhh:Щü+r©Ðvv¢a ÄÖÐ+üå*üÜ.u<ü /bA|ã@üü oäÜ©ðACBÜ*B_Ã,*<<|:ÐZ©OO/zAýbÐoª©@B:hBbÄ~+ÄhäÜЩÃB+ö@UA>Ã~U¢aCabO>åoZî*+@ÐhðöA £|+zý*rB/<ªÖ_ã.Ä:*©ö+î~+ÜÐý/ÜBC_£vªb£ßAÃü,/©Ãoß@CAÃ~ZBöÐüý@U+Ü +bBvU*b¢züüü<îâð:zÐ,@U|zäB£Zß ObBZ¢b_ZÜübvzCüvbzî î<~öãß_ö,U.*@£Üî+ªb~+O_Ö vð/ ªA ,:.Īå@_ÄЩ bå:U üÐðãª~îBªÜuBöbUb/rovbÜZAu¢@vCvÄ~Bb>Ãߣ|äî,ýCz:ÖÃ.v£ÃZüUr/îªýb¢ý*b¢aå||vߣz+©ÜOÄÖäããã¢AZCßzUîA~ßv.£A©:åCäaãbüª|.vOähußhÄb*åbvz*Öb@CvhhAzüÄüãÜýz@UåýÄO:|:Zðý |ßä|£bü:Ua<*>ã Aü/ßü£.BUbO*åÐ/büzîaüUr.~O+OOr£*rª~îCã ,uîÐäCãBÖßö@A~ß*ßÖAußZUîA.ãovo_öCý@ßb>*ZÖb¢,UêÖ,UÜhB¢_BýaÄ:Z©ßªUa,bbaZz.Ð<Ä©ã£*ßbÖA+.ã>:.ßbßåabvahUZ|Ã+ö<Ä+oã/h+*£rðßUãoå~£rU>_Ä,:£Ä,bU+,BåÃ<*¢ýÃÃ/Ußo:ÜZB,übOÃýO£Ö,Ü.üZ,ã@Ä*h©_ü£@|bZðUýä.z©Zzu,î@ãªUrvÄhãü¢Ö/o.äa.©hðåÐ>,ðý©¢C@zz:¢ãöÄ/Uäð:ö¢u/våßvî_vý£CBãZvb@Ð:z/ü@~îZü.Zý/Üäo<ÐÜßãªÖb<üÄãåoýß,Ä>zß:Ðzîýöhýýu u©ß_ZÃîã|,<_äb.ß/<ªÄZ|+aý:ðã©¢b>Ö+ªr+/@ÄߣÖ.ýO:ã~hÃ>+>b©zÜ_ßÜboðzýßZãCvüChüäA.AÃåãua¢¢åb|ähåuýäß*hãßåBä~Z@@Zå<Ã*ÜaîßÜÄuðv/Ðýü+ÖCZo>î|ußßý¢ÐCB~OBoßBrBbb£ðð_:+å¢îÖ.aÐüßÜ_uCßhýBß©U¢ßOv|auBäü£Ã .Baß+Ã~/h*a|üýUî£ßBärÖb/¢r,ߢBßhäåÃÄhOÐCBß<:oÄ~Aüruo_ßC©A|Oozßßb@åÃbZ_ÖÐ//Öb|AÄ./Zv_öü+oäZ£zZäO<@O<.ß©ýåCª,ýC~AýbªuZÐAä ªvbý+O:|vv|,|z~ÜZ+.*~,AZU£U©£åÖ< oß_~ý@ðhßÄäa£/Öa/a*ª>ÐuUßÐÄöÜð+@bb,>brZã©rå,åß.~zßUßý+î* ö~AvüUÄ>hzü_b_hCrUýîÐ,AA<ãã ãzaOuÄüoîÖ>/bvvC _UrãuÐ*b*uã©<£.BazãbAýb ã:@ýZ~><ÖÃÐßÄî<Ð~£:o*ð¢ãß*ÐuA.Cö£ªÐrü¢zb¢,Ä.Ö¢,CßB<,_åýðß©rðäv:*~ßhCoZÖö +@ürrboöª.ððÄ.Öªß+z/+u+ð+ãö>Zü_*_bo+AЪ~Aüvä@.å,,>*î:>üohAã+h©©£ä~,£U+~bÖÄ.,ö>.öö|Bߪ¢îABauaåU:*z¢aöaUoaðZoÖB|r£¢å/||åAUÃ+_uh~O@UbB >:ðÄ,BäzA<ähoüÄO>ðå>ö:höOª£ýUîÐOvãAZ ,aAð+bãÖÐborÄ*>Ð|r©<©*Ö hob+zâB©ãr¢ü @©¢vªîÖoª_a:Ä¢*ߣbvÄßra<:A/b@åhåÜuÃaä,Öã|ü|>+ãýýÖåOo*U@ £hß|<ãÐ,C©<ö ðvz/oã£>Cªb/z¢Ãý@@Ä*+Ä~O+ä ßCUO>A.üðãðBÃÃhAr@A,aA,ªhܪür©CbZ>ß,ä/_,î©Öoª/a©uÃ+© ZUýÄÖðÖ@z:ÄßrA©u.ßü/ð>.Ъßß<@ªÃÄýý><£zý>Ãuövhaýãbð*o©b.ÜßvCðhvýÄÜaßu@r~Cß:ÖÃ|o~ªãö.ªU@Aö|У+rb+/UU>hrÜ å U*uZÄu©©>BOä,UßîÖ~_.zböbOh©ª©Ã~¢ý<|ö¢uÄzrüh*ZߢBÖUr©+~ðbb@r¢_A©äv_åUr î~ß,>~ã/<îU.|>ähbÄ<Ö:¢h£U~/îü©ßC+~o>ÃÖ>U~bbZ,hߢ©hö>Z<ĪåAßåb£~:ÖBv< ðÄ¢o@ßz£aý¢:vObÄå£uo/©|ßrªö©Ð>au ZÐ/z Ü©,öäAo.Ü<@Öå:A åUhãüðã£ð>ý,hü/¢,_ä_Ö>ß_¢ßãZ<+äãÖA+bÖvßAî* ~>|+/ªroB+@ðä.uh|ö*ðoaÄa£_CuB_.o~Ü|îah*¢bðZv|:_Ä@å©©üUUÜ+öã ,ß Ãuh,îåhb_ð|Ä@öãðra.ÄuäÖr @Ü@bzAuUª~b/b¢ß+ãhÐ,@Äã_A£zýBCß:ðb,C¢ýUî <ð*ßð+ÜÖb:BU~o£ü~OB*:|uöhhî|@ßoÜÜa:u:oÜå*ÄÃh/Ö£_Bå ©öà î_ª*Ü/,rýÐåB@,<*:£>>ßbÃ|Ãäßý,o>/ãCZBã©+îvÖÄ~A:BüzhÖ~ÖÜ>,åhÖ£¢,ßãU/U,C,@ßZªub+B_uÖßÃv,ðÃb¢årÃðÄväðå*~uÃäîªöZh_.Aܪ@åßÄ|/ ÐoÜurßä|*+o>ÖöabüÜ£:¢|@rä.b.ã:o+/aãbî¢ÄßBÐßOv_A©@ßãðîýÄO£~+ÜÖ:ÐîrßbÐBüo bä*îÜ*ðz,.îaªu::z©. vöA£ýîü<UC©r|Ãbvªýhåähaß:ÐUðî_îruZ>u*uªöÜðr.Oä|C¢£v,zöuÄ _ª£oîªÃr:ývräî,,OCöð~£ªoCZUZ@îZbÜåߪößåz>uÐäzðÜÐåaCãZÜÖîý>A¢*.Ã_Är.üBß/,u¢/+ðÖãr>@,@Ü/Öýhîª/Övöb@OoB>ߢB|Ъ©*,ýU©ãCßaOÜv/.ãrOa£ü©*ãÐ~ÐÃÄîzübßB£Öð*ÜðoCb*.å£bü/î|B£ýa_U£ðh,ðÄuÄ/*ÜBZßuÄß_Z> ÄB¢Ö<..üOB£r©ÃäÜÖr*hÃ/zzähb +ß/Äbðöã@£/ZßÐvUhåªh*öb*ð*¢vÜzå *bª+©ðoÖÐAvCÖb üObOý_öý.ÖBÜÃZÃbrÖCöÐhå~rÐä,zÃö~äA©bÄhîß.bOª|h::býb*£h~ßZ<üUÃ_©Ðß>ð©¢¢ bä _£öZabZ.* ¢ªöÐ/ãÜuo£Cä.:ßbuÜß/£ý> ~ðåa<ðüZr Br|rUÜãCîru©U><öã>~ðãB¢h>üÖÖU©ã£B*ª@a@A~_BZCðÃ+_@B:ÃZ¢:BðbÐßb*©@+Aohä/ßý_ o|ß@uß~ruhuh+:å>~öÜu>O.ÜÐå_uÃBZÜUª@£ä*a£~vuÄvC©Ö* röU~zb.,Oå::oz_©>@Ü/vZZCüu:î_ðv>üÄa,ZäÄ<>bÜaA>Ö|ÃÃaAä£ _aüü/u.ß/ü.O©>h,¢ßZðr@ZB:<îrãîu£ +<+ îvvbv AªzBb_z,U|ÄhaÐå>ü rö_ÖÜäZaÖbÄ_Aãðrv_.aÖÃUA_Cª bªzÜý~.¢>oß~@<+b:£ZuU.UäCzO©b|B_öª,ßÜîbäýãîh/Ö¢ýaö:h|AÃAÖaz**hbðäU_ðb|Z_~/U,@C.*Ãr£CBüýðî*bÖªÄ@ãßüZrrÄî:©î_hßz@¢ªö£h>ðßåU¢aÄ>_öåî,ª_ãuhýzO:O/ähªã/o©b+*äh,ö~ÃOöCü©u,Ãüß+ß©ãz:£:,>,åb+vß_AÖ,/v|ZCU rÖ£Ððå¢Üä,@A,>ö|bzZäÖÄäÃ*ö|*CU,Äbh/ÃÐÜÃ<ýß+~>îü+ýzv£¢ýßüvbUßzßZ.hZ.©*~©ä.Ö.åÄ_ðßÜ.>ÃOöß/rABßUåoo_ö/rü:z<ãª_ªU*ÖBÄz<,BbÜÄðäZ", + " .@Ãã+UãAÜ >hÐb_ÐßC¢äåzb¢ßå.ýß_*výÄ,@ð/ªßý¢äßãUUüUhAÃaß,>ãäU:~>bÜ,bhåüÐ@vZbã+Cüh+ª>åªb*ðäUr£ä~ýÄ/ßC*a>¢Ü,ööa,åÐåãbª/ÐAhZ¢bbîb£uv,.@*vv<+üvöýîU>ßå ßÜü_ü,©", + null, + "23:59:29.0498764", + "2002-01-31 23:59:59.0498764+08:00", + "2002-01-31 23:59:59.0498764", + null, + null, + ); \ No newline at end of file