diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f2552503..8295223db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,13 +3,54 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) +## 5.9.0-preview1 - 2020-10-02 +Updated PECL release packages. Here is the list of updates: + +### Added +- Support for PHP 8.0 RC 1 +- Support for Ubuntu 20.04 and Alpine 3.12 +- Support for GB18030 locale [#1115]( +https://github.com/microsoft/msphpsql/pull/1115) +- Feature Request [#924](https://github.com/microsoft/msphpsql/issues/924) - extended PDO errorinfo to include [additional odbc messages if available](https://github.com/microsoft/msphpsql/wiki/Features#pdoErrorInfo) - pull request [#1133]( +https://github.com/microsoft/msphpsql/pull/1133) +- [Data Classification with rank info](https://github.com/microsoft/msphpsql/wiki/Features#dataClass), which requires [MS ODBC Driver 17.4.2+](https://docs.microsoft.com/sql/connect/odbc/download-odbc-driver-for-sql-server?view=sql-server-ver15) and [SQL Server 2019](https://www.microsoft.com/sql-server/sql-server-2019) or an Azure SQL instance that supports it + +### Removed +- Dropped support for Ubuntu 19.10 and Debian 8. + +### Fixed +- Pull Request [#1127](https://github.com/microsoft/msphpsql/pull/1127) - removal of TSRMLS macros in preparation for PHP 8 by remicollet +- Pull Request [#1136](https://github.com/microsoft/msphpsql/pull/1136) - improved performance when handling decimal numbers as inputs or outputs and removed unncessary conversions for numeric values +- Pull Request [#1143](https://github.com/microsoft/msphpsql/pull/1143) - if an exception occurs when executing a query, will not change the output parameters +- Pull Request [#1144](https://github.com/microsoft/msphpsql/pull/1144) - use the correct C types when binding output parameters with integer values +- Pull Request [#1146](https://github.com/microsoft/msphpsql/pull/1146) - improved performance when fetching numbers using client buffers +- Pull Request [#1165](https://github.com/microsoft/msphpsql/pull/1165) - setting query timeout without using LOCK TIMEOUT, which saves an extra trip to the server +- Issue [#1170](https://github.com/microsoft/msphpsql/issues/1170) - when fetching large data types such as ntext will check more than only the display size - pull request [#1172](https://github.com/microsoft/msphpsql/pull/1172) + +### Limitations +- No support for inout / output params when using sql_variant type +- No support for inout / output params when formatting decimal values +- In Linux and macOS, setlocale() only takes effect if it is invoked before the first connection. Attempting to set the locale after connecting will not work +- Always Encrypted requires [MS ODBC Driver 17+](https://docs.microsoft.com/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server) + - Only Windows Certificate Store and Azure Key Vault are supported. Custom Keystores are not yet supported + - Issue [#716](https://github.com/Microsoft/msphpsql/issues/716) - With Always Encrypted enabled, named parameters in subqueries are not supported + - Issue [#1050](https://github.com/microsoft/msphpsql/issues/1050) - With Always Encrypted enabled, insertion requires the column list for any tables with identity columns + - [Always Encrypted limitations](https://docs.microsoft.com/sql/connect/php/using-always-encrypted-php-drivers#limitations-of-the-php-drivers-when-using-always-encrypted) + +### Known Issues +- This preview release requires ODBC Driver 17.4.2 or above. Otherwise, a warning about failing to set an attribute may be suppressed when using an older ODBC driver. +- Connection pooling on Linux or macOS is not recommended with [unixODBC](http://www.unixodbc.org/) < 2.3.7 +- When pooling is enabled in Linux or macOS + - unixODBC <= 2.3.4 (Linux and macOS) might not return proper diagnostic information, such as error messages, warnings and informative messages + - due to this unixODBC bug, fetch large data (such as xml, binary) as streams as a workaround. See the examples [here](https://github.com/Microsoft/msphpsql/wiki/Features#pooling) + ## 5.8.1 - 2020-04-15 Updated PECL release packages. Here is the list of updates: ### Fixed - Pull Request [#1094](https://github.com/microsoft/msphpsql/pull/1094) - Fixed default locale issues in Alpine Linux - Pull Request [#1095](https://github.com/microsoft/msphpsql/pull/1095) - Removed unnecessary data structure to support Client-Side Cursors feature in Alpine Linux -- Pull Request [#1095](https://github.com/microsoft/msphpsql/pull/1107) - Fixed logging issues when both drivers are enabled in Alpine Linux +- Pull Request [#1107](https://github.com/microsoft/msphpsql/pull/1107) - Fixed logging issues when both drivers are enabled in Alpine Linux ### Limitations - No support for inout / output params when using sql_variant type diff --git a/Dockerfile-msphpsql b/Dockerfile-msphpsql index 31eba77a1..7d5f65850 100644 --- a/Dockerfile-msphpsql +++ b/Dockerfile-msphpsql @@ -42,8 +42,11 @@ ENV PATH="/opt/mssql-tools/bin:${PATH}" # add locales for testing RUN sed -i 's/# en_US ISO-8859-1/en_US ISO-8859-1/g' /etc/locale.gen +RUN sed -i 's/# fr_FR@euro ISO-8859-15/fr_FR@euro ISO-8859-15/g' /etc/locale.gen RUN sed -i 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/g' /etc/locale.gen RUN sed -i 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/g' /etc/locale.gen +RUN sed -i 's/# zh_CN GB2312/zh_CN GB2312/g' /etc/locale.gen +RUN sed -i 's/# zh_CN.GB18030 GB18030/zh_CN.GB18030 GB18030/g' /etc/locale.gen RUN locale-gen # set locale to utf-8 diff --git a/Linux-mac-install.md b/Linux-mac-install.md index 86f275675..bb8f0b5f8 100644 --- a/Linux-mac-install.md +++ b/Linux-mac-install.md @@ -1,7 +1,7 @@ # Linux and macOS Installation Tutorial for the Microsoft Drivers for PHP for SQL Server -The following instructions assume a clean environment and show how to install PHP 7.x, the Microsoft ODBC driver, the Apache web server, and the Microsoft Drivers for PHP for SQL Server on Ubuntu 16.04, 18.04, and 19.10, RedHat 7 and 8, Debian 8, 9, and 10, Suse 12 and 15, Alpine 3.11, and macOS 10.13, 10.14, and 10.15. These instructions advise installing the drivers using PECL, but you can also download the prebuilt binaries from the [Microsoft Drivers for PHP for 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 SQL Server](https://docs.microsoft.com/sql/connect/php/loading-the-php-sql-driver). For an explanation of extension loading and why we do not add the extensions to php.ini, see the section on [loading the drivers](https://docs.microsoft.com/sql/connect/php/loading-the-php-sql-driver#loading-the-driver-at-php-startup). +The following instructions assume a clean environment and show how to install PHP 7.2+, the Microsoft ODBC driver, the Apache web server, and the Microsoft Drivers for PHP for SQL Server on Ubuntu 16.04, 18.04, and 20.04, RedHat 7 and 8, Debian 9 and 10, Suse 12 and 15, Alpine 3.11 and 3.12, and macOS 10.13, 10.14, and 10.15. These instructions advise installing the drivers using PECL, but you can also download the prebuilt binaries from the [Microsoft Drivers for PHP for 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 SQL Server](https://docs.microsoft.com/sql/connect/php/loading-the-php-sql-driver). For an explanation of extension loading and why we do not add the extensions to php.ini, see the section on [loading the drivers](https://docs.microsoft.com/sql/connect/php/loading-the-php-sql-driver#loading-the-driver-at-php-startup). -These instructions install PHP 7.4 by default using `pecl install`. You may need to run `pecl channel-update pecl.php.net` first. Note that some supported Linux distros default to PHP 7.1 or earlier, which is not supported for the latest version of the PHP drivers for SQL Server -- please see the notes at the beginning of each section to install PHP 7.2 or 7.3 instead. +The following instructions install PHP 7.4 by default using `pecl install`. You may need to run `pecl channel-update pecl.php.net` first. Note that some supported Linux distros default to PHP 7.1 or earlier, which is not supported for the latest version of the PHP drivers for SQL Server -- please see the notes at the beginning of each section to install PHP 7.2 or 7.3 instead. Also included are instructions for installing the PHP FastCGI Process Manager, PHP-FPM, on Ubuntu. This is needed if using the nginx web server instead of Apache. @@ -10,9 +10,9 @@ Also included are instructions for installing the PHP FastCGI Process Manager, P - [Installing the drivers on Ubuntu 16.04, 18.04, and 19.10](#installing-the-drivers-on-ubuntu-1604-1804-and-1910) - [Installing the drivers with PHP-FPM on Ubuntu](#installing-the-drivers-with-php-fpm-on-ubuntu) - [Installing the drivers on Red Hat 7 and 8](#installing-the-drivers-on-red-hat-7-and-8) -- [Installing the drivers on Debian 8, 9, and 10](#installing-the-drivers-on-debian-8-9-and-10) +- [Installing the drivers on Debian 9 and 10](#installing-the-drivers-on-debian-9-and-10) - [Installing the drivers on Suse 12 and 15](#installing-the-drivers-on-suse-12-and-15) -- [Installing the drivers on Alpine 3.11](#installing-the-drivers-on-alpine-311) +- [Installing the drivers on Alpine 3.11 and 3.12](#installing-the-drivers-on-alpine-311-and-312) - [Installing the drivers on macOS High Sierra, Mojave, and Catalina](#installing-the-drivers-on-macos-high-sierra-mojave-and-catalina) ## Installing the drivers on Ubuntu 16.04, 18.04, and 19.10 @@ -189,7 +189,7 @@ 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, 9, and 10 +## Installing the drivers on Debian 9 and 10 > [!NOTE] > To install PHP 7.2 or 7.3, replace 7.4 in the following commands with 7.2 or 7.3. @@ -290,13 +290,13 @@ 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 Alpine 3.11 +## Installing the drivers on Alpine 3.11 and 3.12 > [!NOTE] -> The default version of PHP is 7.3. Alternate versions of PHP may be available from other repositories for Alpine 3.11. You can instead compile PHP from source. +> The default version of PHP is 7.3. Alternate versions of PHP may be available from other repositories for Alpine. You can instead compile PHP from source. ### Step 1. Install PHP -PHP packages for Alpine can be found in the `edge/community` repository. Please check [Enable Community Repository](https://wiki.alpinelinux.org/wiki/Enable_Community_Repository) on their WIKI page. Add the following line to `/etc/apt/repositories`, replacing `` with the URL of an Alpine repository mirror: +PHP packages for Alpine can be found in the `edge/community` repository. Please check [Enable Community Repository](https://wiki.alpinelinux.org/wiki/Enable_Community_Repository) on their WIKI page. Add the following line to `/etc/apk/repositories`, replacing `` with the URL of an Alpine repository mirror: ``` http:///alpine/edge/community ``` diff --git a/README.md b/README.md index 94953e96e..8b937e5af 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,6 @@ Azure Pipelines | AppVeyor (Windows) | Travis CI (Linux) | Co * [**RedHat + SQL Server + PHP 7**](https://www.microsoft.com/sql-server/developer-get-started/php/rhel) * [**SUSE + SQL Server + PHP 7**](https://www.microsoft.com/sql-server/developer-get-started/php/sles) * [**macOS + SQL Server + PHP 7**](https://www.microsoft.com/sql-server/developer-get-started/php/mac/) -* [**Docker**](https://hub.docker.com/r/lbosqmsft/mssql-php-msphpsql/) - ## Announcements diff --git a/appveyor.yml b/appveyor.yml index cf87f520f..f3f0f728c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,10 +1,6 @@ version: '{branch}.{build}' branches: - # whitelist - #only: - - # blacklist except: - PHP-7.0-Linux - PHP5 @@ -22,19 +18,19 @@ environment: BUILD_PLATFORM: x64 TEST_PHP_SQL_SERVER: (local)\SQL2017 SQL_INSTANCE: SQL2017 - PHP_VC: 15 - PHP_MAJOR_VER: 7.3 + PHP_VC: vc15 + PHP_MAJOR_VER: 7.4 PHP_MINOR_VER: latest PHP_EXE_PATH: x64\Release_TS THREAD: ts platform: x64 - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 BUILD_PLATFORM: x86 - TEST_PHP_SQL_SERVER: (local)\SQL2016 - SQL_INSTANCE: SQL2016 - PHP_VC: 15 - PHP_MAJOR_VER: 7.4 - PHP_MINOR_VER: latest + TEST_PHP_SQL_SERVER: (local)\SQL2019 + SQL_INSTANCE: SQL2019 + PHP_VC: vs16 + PHP_MAJOR_VER: 8.0 + PHP_MINOR_VER: 0rc1 PHP_EXE_PATH: Release THREAD: nts platform: x86 @@ -83,7 +79,7 @@ install: } - echo Downloading MSODBCSQL 17 # AppVeyor build works are x64 VMs and 32-bit ODBC driver cannot be installed on it - - ps: (new-object net.webclient).DownloadFile('https://download.microsoft.com/download/E/6/B/E6BFDC7A-5BCD-4C51-9912-635646DA801E/en-US/17.5.2.1/x64/msodbcsql.msi', 'c:\projects\msodbcsql.msi') + - ps: (new-object net.webclient).DownloadFile('https://download.microsoft.com/download/6/b/3/6b3dd05c-678c-4e6b-b503-1d66e16ef23d/en-US/17.6.1.1/x64/msodbcsql.msi', 'c:\projects\msodbcsql.msi') - cmd /c start /wait msiexec /i "c:\projects\msodbcsql.msi" /q IACCEPTMSODBCSQLLICENSETERMS=YES ADDLOCAL=ALL - echo Checking the version of MSODBCSQL - reg query "HKLM\SOFTWARE\ODBC\odbcinst.ini\ODBC Driver 17 for SQL Server" @@ -99,13 +95,14 @@ install: - echo install opencppcoverage - choco install opencppcoverage - set path=C:\Program Files\OpenCppCoverage;%PYTHON%;%PYTHON%\Scripts;%path% + - copy %APPVEYOR_BUILD_FOLDER%\codecov.yml c:\projects build_script: - copy %APPVEYOR_BUILD_FOLDER%\buildscripts\*.py c:\projects - cd c:\projects - python -V - python builddrivers.py --PHPVER=%PHP_VERSION% --ARCH=%BUILD_PLATFORM% --THREAD=%THREAD% --SOURCE=%APPVEYOR_BUILD_FOLDER%\source --TESTING --NO_RENAME - - cd c:\projects\php-sdk\phpdev\vc%PHP_VC%\%BUILD_PLATFORM%\php-%PHP_VERSION%-src\ + - cd c:\projects\php-sdk\phpdev\%PHP_VC%\%BUILD_PLATFORM%\php-%PHP_VERSION%-src\ - set PHP_SRC_DIR=%CD%\ext - cd %PHP_EXE_PATH% - set PHP_EXE_PATH=%CD% @@ -122,7 +119,7 @@ test_script: - ps: >- If ($env:BUILD_PLATFORM -Match "x86") { Write-Host "Running phpt tests via OpenCppCoverage..." - OpenCppCoverage.exe --sources ${env:PHP_SRC_DIR}\*sqlsrv --modules ${env:PHP_EXE_PATH}\php*sqlsrv.dll --export_type=cobertura:c:\projects\coverage.xml --quiet --cover_children --continue_after_cpp_exception --optimized_build -- .\php.exe run-tests.php -P ${env:APPVEYOR_BUILD_FOLDER}\test\functional\ | out-file -filePath ${env:APPVEYOR_BUILD_FOLDER}\test\functional\tests.log -encoding UTF8; + OpenCppCoverage.exe --sources ${env:PHP_SRC_DIR}\*sqlsrv --modules ${env:PHP_EXE_PATH}\php*sqlsrv.dll --excluded_sources ${env:PHP_SRC_DIR}\pdo_sqlsrv\shared\core_stream.cpp --export_type=cobertura:c:\projects\coverage.xml --quiet --cover_children --continue_after_cpp_exception --optimized_build -- .\php.exe run-tests.php -P --no-color ${env:APPVEYOR_BUILD_FOLDER}\test\functional\ | out-file -filePath ${env:APPVEYOR_BUILD_FOLDER}\test\functional\tests.log -encoding UTF8; Write-Host "Showing the last 25 lines of the log file..." Get-Content ${env:APPVEYOR_BUILD_FOLDER}\test\functional\tests.log -Tail 25; ls *.xml diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 4444203fe..6f7f2185d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -111,8 +111,11 @@ jobs: - script: | sudo sed -i 's/# en_US ISO-8859-1/en_US ISO-8859-1/g' /etc/locale.gen + sudo sed -i 's/# fr_FR@euro ISO-8859-15/fr_FR@euro ISO-8859-15/g' /etc/locale.gen sudo sed -i 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/g' /etc/locale.gen sudo sed -i 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/g' /etc/locale.gen + sudo sed -i 's/# zh_CN GB2312/zh_CN GB2312/g' /etc/locale.gen + sudo sed -i 's/# zh_CN.GB18030 GB18030/zh_CN.GB18030 GB18030/g' /etc/locale.gen sudo locale-gen export LANG='en_US.UTF-8' export LANGUAGE='en_US:en' diff --git a/buildscripts/README.md b/buildscripts/README.md index 46c190e64..3d1481b4f 100644 --- a/buildscripts/README.md +++ b/buildscripts/README.md @@ -5,16 +5,16 @@ To build extensions for 1. PHP 7.0* or PHP 7.1* * install Visual Studio 2015 and make sure C++ tools are enabled. -2. PHP 7.2* - * install Visual Studio 2017, including Visual C++ toolset and the Windows SDK components. +2. PHP 7.2* or above + * install Visual Studio 2017 (PHP 7.*) or Visual Studio 2019 (PHP 8.*), including Visual C++ toolset and the Windows SDK components. -To use the sample build scripts `builddrivers.py` and `buildtools.py`, install Python 3.x and Git for Windows (which comes with Visual Studio 2017). If `git` is unrecognized in a regular command prompt, make sure the environment path is set up correctly. +To use the sample build scripts `builddrivers.py` and `buildtools.py`, install Python 3.x and Git for Windows (which comes with Visual Studio 2017 or 2019). If `git` is unrecognized in a regular command prompt, make sure the environment path is set up correctly. ## Compile the drivers -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. +You must first be able to build PHP source 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.1 using Visual C++ 2017 v15.5. +The Microsoft Drivers for PHP for SQL Server have been compiled and tested with PHP 7.2+ using Visual Studio 2017 and PHP 8.0 previews using Visual Studio 2019. The drivers for Windows that are published for each release (including previews) are digitally signed. You are recommended to sign the binaries you have compiled locally for your own development or testing purposes, using tools like Authenticode. It verifies the publisher's identity and prevents malicious actors from posing as legitimate developers. ### Manually building from source @@ -45,7 +45,7 @@ The sample build scripts, `builddrivers.py` and `buildtools.py`, can be used to #### Overview -When asked to provide the PHP version, you should enter values like `7.1.7`. If it's alpha, beta, or RC version, make sure the name you provide matches the PHP tag name without the prefix `php-`. For example, for PHP 7.2 beta 2, the tag name is `php-7.2.0beta2`, so you will enter `7.2.0beta2`. Visit [PHP SRC]( https://github.com/php/php-src) to find the appropriate tag names. +When asked to provide the PHP version, you should enter values like `7.3.17`. If it's alpha, beta, or RC version, make sure the name you provide matches the PHP tag name without the prefix `php-`. For example, for PHP 8.0.0 beta 3, the tag name is `php-8.0.0beta3`, so you will enter `8.0.0beta3`. Visit [PHP SRC]( https://github.com/php/php-src) to find the appropriate tag names. PHP recommends to unzip the PHP SDK into the shortest possible path, preferrably somewhere near the root drive. Therefore, this script will, by default, create a `php-sdk` folder in the C:\ drive, and this `php-sdk` directory tree will remain unless you remove it yourself. For ongoing development, we suggest you keep it around. The build scripts will handle updating the PHP SDK if a new version is available. @@ -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.1`) + * PHP Version * 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.2.1 --ARCH=x64 --THREAD=nts --DRIVER=sqlsrv --SOURCE=C:\local\source` - * `py builddrivers.py --PHPVER=7.1.13 --ARCH=x86 --THREAD=ts --DEBUG` + * `py builddrivers.py --PHPVER=7.4.10 --ARCH=x64 --THREAD=nts --DRIVER=sqlsrv --SOURCE=C:\local\source` + * `py builddrivers.py --PHPVER=7.2.30 --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 ff301cc53..26c91c1cd 100644 --- a/buildscripts/builddrivers.py +++ b/buildscripts/builddrivers.py @@ -26,7 +26,6 @@ import argparse import subprocess from buildtools import BuildUtil -from indexsymbols import * class BuildDriver(object): """Build sqlsrv and/or pdo_sqlsrv drivers with PHP source with the following properties: @@ -40,8 +39,6 @@ class BuildDriver(object): make_clean # a boolean flag - whether make clean is necessary source_path # path to a local source folder testing # whether the user has turned on testing mode - srctool_path # path to source indexing tools (empty string by default) - tag_version # tag version for source indexing (empty string by default) """ def __init__(self, phpver, driver, arch, thread, debug, repo, branch, source, path, testing, no_rename): @@ -53,8 +50,6 @@ def __init__(self, phpver, driver, arch, thread, debug, repo, branch, source, pa self.testing = testing self.rebuild = False self.make_clean = False - self.srctool_path = '' - self.tag_version = '' def show_config(self): print() @@ -118,34 +113,6 @@ def get_local_source(self, source_path): print("The path provided is invalid. Please re-enter.") return source - def index_all_symbols(self, ext_dir, srctool_path, tag_version): - """This takes care of indexing all the symbols - - :param ext_dir: the directory where we can find the built extension(s) - :param srctool_path: the path to the tools for source indexing - :param tag_version: tag version for source indexing - :outcome: all symbols will be source indexed - """ - work_dir = os.path.dirname(os.path.realpath(__file__)) - os.chdir(srctool_path) - - if self.util.driver == 'all': - driver = 'sqlsrv' - pdbfile = os.path.join(ext_dir, self.util.driver_name(driver, '.pdb')) - print('Indexing this symbol: ', pdbfile) - run_indexing_tools(pdbfile, driver, tag_version) - driver = 'pdo_sqlsrv' - pdbfile = os.path.join(ext_dir, self.util.driver_name(driver, '.pdb')) - print('Indexing this symbol: ', pdbfile) - run_indexing_tools(pdbfile, driver, tag_version) - else: - driver = self.util.driver - pdbfile = os.path.join(ext_dir, self.util.driver_name(driver, '.pdb')) - print('Indexing this symbol: ', pdbfile) - run_indexing_tools(pdbfile, driver, tag_version) - - os.chdir(work_dir) - 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. @@ -185,12 +152,6 @@ def build_extensions(self, root_dir, logfile): # ext_dir is the directory where we can find the built extension(s) ext_dir = self.util.build_drivers(self.make_clean, dest, logfile) - # Do source indexing only if the tag and tools path are both specified - if self.tag_version is not '' and self.srctool_path is not '': - print('Source indexing begins...') - self.index_all_symbols(ext_dir, self.srctool_path, self.tag_version) - print('Source indexing done') - # Copy the binaries if a destination path is defined if self.dest_path is not None: dest_drivers = os.path.join(self.dest_path, self.util.major_version(), self.util.arch) @@ -212,12 +173,10 @@ def build_extensions(self, root_dir, logfile): return ext_dir - def build(self, srctool_path, tag_version): + def build(self): """This is the main entry point of building drivers for PHP. For development, this will loop till the user decides to quit. - - :param srctool_path: the path to the tools for source indexing - :param tag_version: tag version for source indexing + """ self.show_config() @@ -234,10 +193,6 @@ def build(self, srctool_path, tag_version): logfile = self.util.get_logfile_name() - # Save source indexing details - self.srctool_path = srctool_path - self.tag_version = tag_version - try: ext_dir = self.build_extensions(root_dir, logfile) print('Build Completed') @@ -280,7 +235,7 @@ def validate_input(question, values): ################################### Main Function ################################### if __name__ == '__main__': parser = argparse.ArgumentParser() - parser.add_argument('--PHPVER', help="PHP version, e.g. 7.1.*, 7.2.* etc.") + parser.add_argument('--PHPVER', help="PHP version, e.g. 7.4.* etc.") parser.add_argument('--ARCH', choices=['x64', 'x86']) parser.add_argument('--THREAD', choices=['nts', 'ts']) parser.add_argument('--DRIVER', default='all', choices=['all', 'sqlsrv', 'pdo_sqlsrv'], help="driver to build (default: all)") @@ -291,8 +246,6 @@ def validate_input(question, values): 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)") parser.add_argument('--NO_RENAME', action='store_true', help="drivers will not be renamed(default: False)") - parser.add_argument('--SRCIDX_PATH', default='', help="the path to the tools for source indexing (default: '')") - parser.add_argument('--TAG_VERSION', default='', help="the tag version for source indexing (default: '')") args = parser.parse_args() @@ -354,4 +307,5 @@ def validate_input(question, values): path, testing, no_rename) - builder.build(args.SRCIDX_PATH, args.TAG_VERSION) + + builder.build() diff --git a/buildscripts/buildtools.py b/buildscripts/buildtools.py index 17713f242..ad555e2cb 100644 --- a/buildscripts/buildtools.py +++ b/buildscripts/buildtools.py @@ -50,12 +50,8 @@ def major_version(self): def version_label(self): """Return the version label based on the PHP version.""" - major_ver = self.major_version() - - if major_ver[2] == '0': - version = major_ver[0] - else: - version = major_ver[0] + major_ver[2] + major_ver = self.major_version() + version = major_ver[0] + major_ver[2] return version def driver_name(self, driver, suffix): @@ -100,16 +96,11 @@ def determine_compiler(self, sdk_dir, vs_ver): def compiler_version(self, sdk_dir): """Return the appropriate compiler version based on PHP version.""" - if self.vc is '': - VC = 'vc14' + if self.vc == '': + VC = 'vc15' version = self.version_label() - if version >= '72': # Compiler version for PHP 7.2 or above - VC = 'vc15' - if version == '74': - # Compiler version for PHP 7.4 or above - # Can be compiled using VS 2017 or VS 2019 - print('Checking compiler versions...') - VC = self.determine_compiler(sdk_dir, 15) + if version == '80': # Compiler version for PHP 8.0 or above + VC = 'vs16' self.vc = VC print('Compiler: ' + self.vc) return self.vc diff --git a/source/pdo_sqlsrv/config.m4 b/source/pdo_sqlsrv/config.m4 index b2149a753..93e2c3296 100644 --- a/source/pdo_sqlsrv/config.m4 +++ b/source/pdo_sqlsrv/config.m4 @@ -4,7 +4,7 @@ dnl dnl Contents: the code that will go into the configure script, indicating options, dnl external libraries and includes, and what source files are to be compiled. dnl -dnl Microsoft Drivers 5.8 for PHP for SQL Server +dnl Microsoft Drivers 5.9 for PHP for SQL Server dnl Copyright(c) Microsoft Corporation dnl All rights reserved. dnl MIT License diff --git a/source/pdo_sqlsrv/config.w32 b/source/pdo_sqlsrv/config.w32 index a82fbb713..1f3ed1a30 100644 --- a/source/pdo_sqlsrv/config.w32 +++ b/source/pdo_sqlsrv/config.w32 @@ -3,7 +3,7 @@ // // Contents: JScript build configuration used by buildconf.bat // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/pdo_sqlsrv/pdo_dbh.cpp b/source/pdo_sqlsrv/pdo_dbh.cpp index 9667500e3..03f192f28 100644 --- a/source/pdo_sqlsrv/pdo_dbh.cpp +++ b/source/pdo_sqlsrv/pdo_dbh.cpp @@ -3,7 +3,7 @@ // // Contents: Implements the PDO object for PDO_SQLSRV // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -113,19 +113,18 @@ const stmt_option PDO_STMT_OPTS[] = { // boolean connection string struct pdo_bool_conn_str_func { - static void func( _In_ connection_option const* option, _Inout_ zval* value, sqlsrv_conn* /*conn*/, _Out_ std::string& conn_str TSRMLS_DC ); + static void func( _In_ connection_option const* option, _Inout_ zval* value, sqlsrv_conn* /*conn*/, _Out_ std::string& conn_str ); }; struct pdo_txn_isolation_conn_attr_func { - static void func( connection_option const* /*option*/, _In_ zval* value_z, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/ TSRMLS_DC ); + static void func( connection_option const* /*option*/, _In_ zval* value_z, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/ ); }; struct pdo_int_conn_str_func { - static void func( _In_ connection_option const* option, _In_ zval* value, sqlsrv_conn* /*conn*/, _Out_ std::string& conn_str TSRMLS_DC ) + static void func( _In_ connection_option const* option, _In_ zval* value, sqlsrv_conn* /*conn*/, _Out_ std::string& conn_str ) { - TSRMLS_C; SQLSRV_ASSERT( Z_TYPE_P( value ) == IS_STRING, "Wrong zval type for this keyword" ) std::string val_str = Z_STRVAL_P( value ); @@ -140,14 +139,14 @@ struct pdo_int_conn_str_func { template struct pdo_int_conn_attr_func { - static void func( connection_option const* /*option*/, _In_ zval* value, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/ TSRMLS_DC ) + static void func( connection_option const* /*option*/, _In_ zval* value, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/ ) { try { SQLSRV_ASSERT( Z_TYPE_P( value ) == IS_STRING, "pdo_int_conn_attr_func: Unexpected zval type." ); size_t val = static_cast( atoi( Z_STRVAL_P( value )) ); - core::SQLSetConnectAttr( conn, Attr, reinterpret_cast( val ), SQL_IS_UINTEGER TSRMLS_CC ); + core::SQLSetConnectAttr( conn, Attr, reinterpret_cast( val ), SQL_IS_UINTEGER ); } catch( core::CoreException& ) { throw; @@ -158,12 +157,12 @@ struct pdo_int_conn_attr_func { template struct pdo_bool_conn_attr_func { - static void func( connection_option const* /*option*/, _Inout_ zval* value, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/ TSRMLS_DC ) + static void func( connection_option const* /*option*/, _Inout_ zval* value, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/ ) { try { core::SQLSetConnectAttr( conn, Attr, reinterpret_cast( core_str_zval_is_true( value )), - SQL_IS_UINTEGER TSRMLS_CC ); + SQL_IS_UINTEGER ); } catch( core::CoreException& ) { throw; @@ -173,8 +172,8 @@ struct pdo_bool_conn_attr_func { // statement options related functions void add_stmt_option_key( _Inout_ sqlsrv_context& ctx, _In_ size_t key, _Inout_ HashTable* options_ht, - _Inout_ zval** data TSRMLS_DC ); -void validate_stmt_options( _Inout_ sqlsrv_context& ctx, _Inout_ zval* stmt_options, _Inout_ HashTable* pdo_stmt_options_ht TSRMLS_DC ); + _Inout_ zval** data ); +void validate_stmt_options( _Inout_ sqlsrv_context& ctx, _Inout_ zval* stmt_options, _Inout_ HashTable* pdo_stmt_options_ht ); } // namespace @@ -438,35 +437,35 @@ const connection_option PDO_CONN_OPTS[] = { // close the connection -int pdo_sqlsrv_dbh_close( _Inout_ pdo_dbh_t *dbh TSRMLS_DC ); +int pdo_sqlsrv_dbh_close( _Inout_ pdo_dbh_t *dbh ); // execute queries int pdo_sqlsrv_dbh_prepare( _Inout_ pdo_dbh_t *dbh, _In_reads_(sql_len) const char *sql, - _Inout_ size_t sql_len, _Inout_ pdo_stmt_t *stmt, _In_ zval *driver_options TSRMLS_DC ); -zend_long pdo_sqlsrv_dbh_do( _Inout_ pdo_dbh_t *dbh, _In_reads_bytes_(sql_len) const char *sql, _In_ size_t sql_len TSRMLS_DC ); + _Inout_ size_t sql_len, _Inout_ pdo_stmt_t *stmt, _In_ zval *driver_options ); +zend_long pdo_sqlsrv_dbh_do( _Inout_ pdo_dbh_t *dbh, _In_reads_bytes_(sql_len) const char *sql, _In_ size_t sql_len ); // transaction support functions -int pdo_sqlsrv_dbh_commit( _Inout_ pdo_dbh_t *dbh TSRMLS_DC ); -int pdo_sqlsrv_dbh_begin( _Inout_ pdo_dbh_t *dbh TSRMLS_DC ); -int pdo_sqlsrv_dbh_rollback( _Inout_ pdo_dbh_t *dbh TSRMLS_DC ); +int pdo_sqlsrv_dbh_commit( _Inout_ pdo_dbh_t *dbh ); +int pdo_sqlsrv_dbh_begin( _Inout_ pdo_dbh_t *dbh ); +int pdo_sqlsrv_dbh_rollback( _Inout_ pdo_dbh_t *dbh ); // attribute functions -int pdo_sqlsrv_dbh_set_attr( _Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout_ zval *val TSRMLS_DC ); -int pdo_sqlsrv_dbh_get_attr( _Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout_ zval *return_value TSRMLS_DC ); +int pdo_sqlsrv_dbh_set_attr( _Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout_ zval *val ); +int pdo_sqlsrv_dbh_get_attr( _Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout_ zval *return_value ); // return more information int pdo_sqlsrv_dbh_return_error( _In_ pdo_dbh_t *dbh, _In_opt_ pdo_stmt_t *stmt, - _Out_ zval *info TSRMLS_DC); + _Out_ zval *info); // return the last id generated by an executed SQL statement -char * pdo_sqlsrv_dbh_last_id( _Inout_ pdo_dbh_t *dbh, _In_z_ const char *name, _Out_ size_t* len TSRMLS_DC ); +char * pdo_sqlsrv_dbh_last_id( _Inout_ pdo_dbh_t *dbh, _In_z_ const char *name, _Out_ size_t* len ); // additional methods are supported in this function -pdo_sqlsrv_function_entry *pdo_sqlsrv_get_driver_methods( _Inout_ pdo_dbh_t *dbh, int kind TSRMLS_DC ); +pdo_sqlsrv_function_entry *pdo_sqlsrv_get_driver_methods( _Inout_ pdo_dbh_t *dbh, int kind ); // quote a string, meaning put quotes around it and escape any quotes within it int pdo_sqlsrv_dbh_quote( _Inout_ pdo_dbh_t* dbh, _In_reads_(unquotedlen) const char* unquoted, _In_ size_t unquotedlen, _Outptr_result_buffer_(*quotedlen) char **quoted, _Out_ size_t* quotedlen, - enum pdo_param_type paramtype TSRMLS_DC ); + enum pdo_param_type paramtype ); struct pdo_dbh_methods pdo_sqlsrv_dbh_methods = { @@ -498,8 +497,8 @@ struct pdo_dbh_methods pdo_sqlsrv_dbh_methods = { } // constructor for the internal object for connections -pdo_sqlsrv_dbh::pdo_sqlsrv_dbh( _In_ SQLHANDLE h, _In_ error_callback e, _In_ void* driver TSRMLS_DC ) : - sqlsrv_conn( h, e, driver, SQLSRV_ENCODING_UTF8 TSRMLS_CC ), +pdo_sqlsrv_dbh::pdo_sqlsrv_dbh( _In_ SQLHANDLE h, _In_ error_callback e, _In_ void* driver ) : + sqlsrv_conn( h, e, driver, SQLSRV_ENCODING_UTF8 ), stmts( NULL ), direct_query( false ), query_timeout( QUERY_TIMEOUT_INVALID ), @@ -532,7 +531,7 @@ pdo_sqlsrv_dbh::pdo_sqlsrv_dbh( _In_ SQLHANDLE h, _In_ error_callback e, _In_ vo // driver_options - A HashTable (within the zval) of options to use when creating the connection. // Return: // 0 for failure, 1 for success. -int pdo_sqlsrv_db_handle_factory( _Inout_ pdo_dbh_t *dbh, _In_opt_ zval *driver_options TSRMLS_DC) +int pdo_sqlsrv_db_handle_factory( _Inout_ pdo_dbh_t *dbh, _In_opt_ zval *driver_options) { PDO_LOG_DBH_ENTRY; @@ -570,12 +569,12 @@ int pdo_sqlsrv_db_handle_factory( _Inout_ pdo_dbh_t *dbh, _In_opt_ zval *driver_ ALLOC_HASHTABLE( pdo_conn_options_ht ); core::sqlsrv_zend_hash_init( *g_pdo_henv_cp, pdo_conn_options_ht, 10 /* # of buckets */, - ZVAL_PTR_DTOR, 0 /*persistent*/ TSRMLS_CC ); + ZVAL_PTR_DTOR, 0 /*persistent*/ ); // Either of g_pdo_henv_cp or g_pdo_henv_ncp can be used to propogate the error. dsn_parser = new ( sqlsrv_malloc( sizeof( conn_string_parser ))) conn_string_parser( *g_pdo_henv_cp, dbh->data_source, static_cast( dbh->data_source_len ), pdo_conn_options_ht ); - dsn_parser->parse_conn_string( TSRMLS_C ); + dsn_parser->parse_conn_string(); // Extract the server name temp_server_z = zend_hash_index_find( pdo_conn_options_ht, PDO_CONN_OPTION_SERVER ); @@ -593,7 +592,7 @@ int pdo_sqlsrv_db_handle_factory( _Inout_ pdo_dbh_t *dbh, _In_opt_ zval *driver_ sqlsrv_conn* conn = core_sqlsrv_connect( *g_pdo_henv_cp, *g_pdo_henv_ncp, core::allocate_conn, Z_STRVAL( server_z ), dbh->username, dbh->password, pdo_conn_options_ht, pdo_sqlsrv_handle_dbh_error, - PDO_CONN_OPTS, dbh, "pdo_sqlsrv_db_handle_factory" TSRMLS_CC ); + PDO_CONN_OPTS, dbh, "pdo_sqlsrv_db_handle_factory" ); // Free the string in server_z after being used zend_string_release( Z_STR( server_z )); @@ -634,7 +633,7 @@ int pdo_sqlsrv_db_handle_factory( _Inout_ pdo_dbh_t *dbh, _In_opt_ zval *driver_ // dbh - The PDO managed connection object. // Return: // Always returns 1 for success. -int pdo_sqlsrv_dbh_close( _Inout_ pdo_dbh_t *dbh TSRMLS_DC ) +int pdo_sqlsrv_dbh_close( _Inout_ pdo_dbh_t *dbh ) { LOG( SEV_NOTICE, "pdo_sqlsrv_dbh_close: entering" ); @@ -647,7 +646,7 @@ int pdo_sqlsrv_dbh_close( _Inout_ pdo_dbh_t *dbh TSRMLS_DC ) PDO_RESET_DBH_ERROR; // call the core layer close - core_sqlsrv_close( reinterpret_cast( dbh->driver_data ) TSRMLS_CC ); + core_sqlsrv_close( reinterpret_cast( dbh->driver_data ) ); dbh->driver_data = NULL; // always return success that the connection is closed @@ -666,7 +665,7 @@ int pdo_sqlsrv_dbh_close( _Inout_ pdo_dbh_t *dbh TSRMLS_DC ) // Return: // 0 for failure, 1 for success. int pdo_sqlsrv_dbh_prepare( _Inout_ pdo_dbh_t *dbh, _In_reads_(sql_len) const char *sql, - _Inout_ size_t sql_len, _Inout_ pdo_stmt_t *stmt, _In_ zval *driver_options TSRMLS_DC ) + _Inout_ size_t sql_len, _Inout_ pdo_stmt_t *stmt, _In_ zval *driver_options ) { PDO_RESET_DBH_ERROR; PDO_VALIDATE_CONN; @@ -692,14 +691,14 @@ int pdo_sqlsrv_dbh_prepare( _Inout_ pdo_dbh_t *dbh, _In_reads_(sql_len) const ch // Initialize the options array to be passed to the core layer ALLOC_HASHTABLE( pdo_stmt_options_ht ); core::sqlsrv_zend_hash_init( *driver_dbh , pdo_stmt_options_ht, 3 /* # of buckets */, - ZVAL_PTR_DTOR, 0 /*persistent*/ TSRMLS_CC ); + ZVAL_PTR_DTOR, 0 /*persistent*/ ); // Either of g_pdo_henv_cp or g_pdo_henv_ncp can be used to propogate the error. - validate_stmt_options( *driver_dbh, driver_options, pdo_stmt_options_ht TSRMLS_CC ); + validate_stmt_options( *driver_dbh, driver_options, pdo_stmt_options_ht ); driver_stmt = static_cast( core_sqlsrv_create_stmt( driver_dbh, core::allocate_stmt, pdo_stmt_options_ht, PDO_STMT_OPTS, - pdo_sqlsrv_handle_stmt_error, stmt TSRMLS_CC )); + pdo_sqlsrv_handle_stmt_error, stmt )); // if the user didn't set anything in the prepare options, then set the buffer limit // to the value set on the connection. @@ -714,7 +713,7 @@ int pdo_sqlsrv_dbh_prepare( _Inout_ pdo_dbh_t *dbh, _In_reads_(sql_len) const ch // rewrite the query to map named parameters to positional parameters. We do this rather than use the ODBC named // parameters for consistency with the PDO MySQL and PDO ODBC drivers. - int zr = pdo_parse_params( stmt, const_cast( sql ), sql_len, &sql_rewrite, &sql_rewrite_len TSRMLS_CC ); + int zr = pdo_parse_params( stmt, const_cast( sql ), sql_len, &sql_rewrite, &sql_rewrite_len ); CHECK_ZEND_ERROR( zr, driver_dbh, PDO_SQLSRV_ERROR_PARAM_PARSE) { throw core::CoreException(); @@ -728,7 +727,7 @@ int pdo_sqlsrv_dbh_prepare( _Inout_ pdo_dbh_t *dbh, _In_reads_(sql_len) const ch if( !driver_stmt->direct_query && stmt->supports_placeholders != PDO_PLACEHOLDER_NONE ) { - core_sqlsrv_prepare( driver_stmt, sql, sql_len TSRMLS_CC ); + core_sqlsrv_prepare( driver_stmt, sql, sql_len ); } else if( driver_stmt->direct_query ) { @@ -745,10 +744,10 @@ int pdo_sqlsrv_dbh_prepare( _Inout_ pdo_dbh_t *dbh, _In_reads_(sql_len) const ch if ( stmt->supports_placeholders == PDO_PLACEHOLDER_NONE ) { // parse placeholders in the sql query into the placeholders ht ALLOC_HASHTABLE( placeholders ); - core::sqlsrv_zend_hash_init( *driver_dbh, placeholders, 5, ZVAL_PTR_DTOR /* dtor */, 0 /* persistent */ TSRMLS_CC ); + core::sqlsrv_zend_hash_init( *driver_dbh, placeholders, 5, ZVAL_PTR_DTOR /* dtor */, 0 /* persistent */ ); sql_parser = new ( sqlsrv_malloc( sizeof( sql_string_parser ))) sql_string_parser( *driver_dbh, stmt->query_string, static_cast(stmt->query_stringlen), placeholders ); - sql_parser->parse_sql_string( TSRMLS_C ); + sql_parser->parse_sql_string(); driver_stmt->placeholders = placeholders; placeholders.transferred(); } @@ -796,7 +795,7 @@ int pdo_sqlsrv_dbh_prepare( _Inout_ pdo_dbh_t *dbh, _In_reads_(sql_len) const ch // sql_len - length of sql query // Return // # of rows affected, -1 for an error. -zend_long pdo_sqlsrv_dbh_do( _Inout_ pdo_dbh_t *dbh, _In_reads_bytes_(sql_len) const char *sql, _In_ size_t sql_len TSRMLS_DC ) +zend_long pdo_sqlsrv_dbh_do( _Inout_ pdo_dbh_t *dbh, _In_reads_bytes_(sql_len) const char *sql, _In_ size_t sql_len ) { PDO_RESET_DBH_ERROR; PDO_VALIDATE_CONN; @@ -821,23 +820,23 @@ zend_long pdo_sqlsrv_dbh_do( _Inout_ pdo_dbh_t *dbh, _In_reads_bytes_(sql_len) c temp_stmt.dbh = dbh; // allocate a full driver statement to take advantage of the error handling driver_stmt = core_sqlsrv_create_stmt( driver_dbh, core::allocate_stmt, NULL /*options_ht*/, - NULL /*valid_stmt_opts*/, pdo_sqlsrv_handle_stmt_error, &temp_stmt TSRMLS_CC ); + NULL /*valid_stmt_opts*/, pdo_sqlsrv_handle_stmt_error, &temp_stmt ); driver_stmt->set_func( __FUNCTION__ ); - SQLRETURN execReturn = core_sqlsrv_execute( driver_stmt TSRMLS_CC, sql, static_cast( sql_len ) ); + SQLRETURN execReturn = core_sqlsrv_execute( driver_stmt, sql, static_cast( sql_len ) ); // since the user can give us a compound statement, we return the row count for the last set, and since the row count // isn't guaranteed to be valid until all the results have been fetched, we fetch them all first. - if ( execReturn != SQL_NO_DATA && core_sqlsrv_has_any_result( driver_stmt TSRMLS_CC )) { + if ( execReturn != SQL_NO_DATA && core_sqlsrv_has_any_result( driver_stmt )) { SQLRETURN r = SQL_SUCCESS; do { - rows = core::SQLRowCount( driver_stmt TSRMLS_CC ); + rows = core::SQLRowCount( driver_stmt ); - r = core::SQLMoreResults( driver_stmt TSRMLS_CC ); + r = core::SQLMoreResults( driver_stmt ); } while ( r != SQL_NO_DATA ); } @@ -885,7 +884,7 @@ zend_long pdo_sqlsrv_dbh_do( _Inout_ pdo_dbh_t *dbh, _In_reads_bytes_(sql_len) c // dbh - The PDO managed connection object. // Return: // 0 for failure and 1 for success. -int pdo_sqlsrv_dbh_begin( _Inout_ pdo_dbh_t *dbh TSRMLS_DC ) +int pdo_sqlsrv_dbh_begin( _Inout_ pdo_dbh_t *dbh ) { PDO_RESET_DBH_ERROR; PDO_VALIDATE_CONN; @@ -901,7 +900,7 @@ int pdo_sqlsrv_dbh_begin( _Inout_ pdo_dbh_t *dbh TSRMLS_DC ) DEBUG_SQLSRV_ASSERT( !dbh->in_txn, "pdo_sqlsrv_dbh_begin: Already in transaction" ); - core_sqlsrv_begin_transaction( driver_conn TSRMLS_CC ); + core_sqlsrv_begin_transaction( driver_conn ); return 1; } @@ -927,7 +926,7 @@ int pdo_sqlsrv_dbh_begin( _Inout_ pdo_dbh_t *dbh TSRMLS_DC ) // dbh - The PDO managed connection object. // Return: // 0 for failure and 1 for success. -int pdo_sqlsrv_dbh_commit( _Inout_ pdo_dbh_t *dbh TSRMLS_DC ) +int pdo_sqlsrv_dbh_commit( _Inout_ pdo_dbh_t *dbh ) { PDO_RESET_DBH_ERROR; PDO_VALIDATE_CONN; @@ -943,7 +942,7 @@ int pdo_sqlsrv_dbh_commit( _Inout_ pdo_dbh_t *dbh TSRMLS_DC ) DEBUG_SQLSRV_ASSERT( dbh->in_txn, "pdo_sqlsrv_dbh_commit: Not in transaction" ); - core_sqlsrv_commit( driver_conn TSRMLS_CC ); + core_sqlsrv_commit( driver_conn ); return 1; } @@ -967,7 +966,7 @@ int pdo_sqlsrv_dbh_commit( _Inout_ pdo_dbh_t *dbh TSRMLS_DC ) // dbh - The PDO managed connection object. // Return: // 0 for failure and 1 for success. -int pdo_sqlsrv_dbh_rollback( _Inout_ pdo_dbh_t *dbh TSRMLS_DC ) +int pdo_sqlsrv_dbh_rollback( _Inout_ pdo_dbh_t *dbh ) { PDO_RESET_DBH_ERROR; PDO_VALIDATE_CONN; @@ -982,7 +981,7 @@ int pdo_sqlsrv_dbh_rollback( _Inout_ pdo_dbh_t *dbh TSRMLS_DC ) DEBUG_SQLSRV_ASSERT( dbh->in_txn, "pdo_sqlsrv_dbh_rollback: Not in transaction" ); - core_sqlsrv_rollback( driver_conn TSRMLS_CC ); + core_sqlsrv_rollback( driver_conn ); return 1; } @@ -1006,7 +1005,7 @@ int pdo_sqlsrv_dbh_rollback( _Inout_ pdo_dbh_t *dbh TSRMLS_DC ) // val - The value of the attribute to be set. // Return: // 0 for failure, 1 for success. -int pdo_sqlsrv_dbh_set_attr( _Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout_ zval *val TSRMLS_DC ) +int pdo_sqlsrv_dbh_set_attr( _Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout_ zval *val ) { PDO_RESET_DBH_ERROR; PDO_VALIDATE_CONN; @@ -1169,7 +1168,7 @@ int pdo_sqlsrv_dbh_set_attr( _Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout // return_value - zval in which to return the attribute value. // Return: // 0 for failure, 1 for success. -int pdo_sqlsrv_dbh_get_attr( _Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout_ zval *return_value TSRMLS_DC ) +int pdo_sqlsrv_dbh_get_attr( _Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout_ zval *return_value ) { PDO_RESET_DBH_ERROR; PDO_VALIDATE_CONN; @@ -1213,26 +1212,25 @@ int pdo_sqlsrv_dbh_get_attr( _Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout case PDO_ATTR_SERVER_INFO: { - core_sqlsrv_get_server_info( driver_dbh, return_value TSRMLS_CC ); + core_sqlsrv_get_server_info( driver_dbh, return_value ); break; } case PDO_ATTR_SERVER_VERSION: { - core_sqlsrv_get_server_version( driver_dbh, return_value TSRMLS_CC ); + core_sqlsrv_get_server_version( driver_dbh, return_value ); break; } case PDO_ATTR_CLIENT_VERSION: { - core_sqlsrv_get_client_info( driver_dbh, return_value TSRMLS_CC ); + core_sqlsrv_get_client_info( driver_dbh, return_value ); //Add the PDO SQLSRV driver's file version //Declarations below eliminate compiler warnings about string constant to char* conversions const char* extver = "ExtensionVer"; std::string filever = VER_FILEVERSION_STR; - core::sqlsrv_add_assoc_string( *driver_dbh, return_value, extver, &filever[0], 1 /*duplicate*/ - TSRMLS_CC ); + add_assoc_string(return_value, extver, &filever[0]); break; } @@ -1315,7 +1313,7 @@ int pdo_sqlsrv_dbh_get_attr( _Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout // Return: // 0 for failure, 1 for success. int pdo_sqlsrv_dbh_return_error( _In_ pdo_dbh_t *dbh, _In_opt_ pdo_stmt_t *stmt, - _Out_ zval *info TSRMLS_DC) + _Out_ zval *info) { SQLSRV_ASSERT( dbh != NULL || stmt != NULL, "Either dbh or stmt must not be NULL to dereference the error." ); @@ -1341,7 +1339,7 @@ int pdo_sqlsrv_dbh_return_error( _In_ pdo_dbh_t *dbh, _In_opt_ pdo_stmt_t *stmt, // len - Length of the name. // Return: // Returns the last insert id as a string. -char * pdo_sqlsrv_dbh_last_id( _Inout_ pdo_dbh_t *dbh, _In_z_ const char *name, _Out_ size_t* len TSRMLS_DC ) +char * pdo_sqlsrv_dbh_last_id( _Inout_ pdo_dbh_t *dbh, _In_z_ const char *name, _Out_ size_t* len ) { PDO_RESET_DBH_ERROR; PDO_VALIDATE_CONN; @@ -1368,7 +1366,7 @@ char * pdo_sqlsrv_dbh_last_id( _Inout_ pdo_dbh_t *dbh, _In_z_ const char *name, else { char* quoted_table = NULL; size_t quoted_len = 0; - int quoted = pdo_sqlsrv_dbh_quote( dbh, name, strnlen_s( name ), "ed_table, "ed_len, PDO_PARAM_NULL TSRMLS_CC ); + int quoted = pdo_sqlsrv_dbh_quote( dbh, name, strnlen_s( name ), "ed_table, "ed_len, PDO_PARAM_NULL ); SQLSRV_ASSERT( quoted, "PDO::lastInsertId failed to quote the table name."); snprintf( last_insert_id_query, LAST_INSERT_ID_QUERY_MAX_LEN, SEQUENCE_CURRENT_VALUE_QUERY, quoted_table ); sqlsrv_free( quoted_table ); @@ -1379,7 +1377,7 @@ char * pdo_sqlsrv_dbh_last_id( _Inout_ pdo_dbh_t *dbh, _In_z_ const char *name, temp_stmt.dbh = dbh; // allocate a full driver statement to take advantage of the error handling - driver_stmt = core_sqlsrv_create_stmt( driver_dbh, core::allocate_stmt, NULL /*options_ht*/, NULL /*valid_stmt_opts*/, pdo_sqlsrv_handle_stmt_error, &temp_stmt TSRMLS_CC ); + driver_stmt = core_sqlsrv_create_stmt( driver_dbh, core::allocate_stmt, NULL /*options_ht*/, NULL /*valid_stmt_opts*/, pdo_sqlsrv_handle_stmt_error, &temp_stmt ); driver_stmt->set_func( __FUNCTION__ ); @@ -1392,11 +1390,11 @@ char * pdo_sqlsrv_dbh_last_id( _Inout_ pdo_dbh_t *dbh, _In_z_ const char *name, } // execute the last insert id query - core::SQLExecDirectW( driver_stmt, wsql_string TSRMLS_CC ); + core::SQLExecDirectW( driver_stmt, wsql_string ); - core::SQLFetchScroll( driver_stmt, SQL_FETCH_NEXT, 0 TSRMLS_CC ); + core::SQLFetchScroll( driver_stmt, SQL_FETCH_NEXT, 0 ); SQLRETURN r = core::SQLGetData( driver_stmt, 1, SQL_C_CHAR, id_str, LAST_INSERT_ID_BUFF_LEN, - reinterpret_cast( len ), false TSRMLS_CC ); + reinterpret_cast( len ), false ); CHECK_CUSTOM_ERROR( (!SQL_SUCCEEDED( r ) || *len == SQL_NULL_DATA || *len == SQL_NO_TOTAL), driver_stmt, PDO_SQLSRV_ERROR_LAST_INSERT_ID ) { @@ -1442,7 +1440,7 @@ char * pdo_sqlsrv_dbh_last_id( _Inout_ pdo_dbh_t *dbh, _In_z_ const char *name, // Return: // 0 for failure, 1 for success. int pdo_sqlsrv_dbh_quote( _Inout_ pdo_dbh_t* dbh, _In_reads_(unquoted_len) const char* unquoted, _In_ size_t unquoted_len, _Outptr_result_buffer_(*quoted_len) char **quoted, _Out_ size_t* quoted_len, - enum pdo_param_type paramtype TSRMLS_DC ) + enum pdo_param_type paramtype ) { PDO_RESET_DBH_ERROR; PDO_VALIDATE_CONN; @@ -1602,7 +1600,7 @@ int pdo_sqlsrv_dbh_quote( _Inout_ pdo_dbh_t* dbh, _In_reads_(unquoted_len) const } // This method is not implemented by this driver. -pdo_sqlsrv_function_entry *pdo_sqlsrv_get_driver_methods( _Inout_ pdo_dbh_t *dbh, int kind TSRMLS_DC ) +pdo_sqlsrv_function_entry *pdo_sqlsrv_get_driver_methods( _Inout_ pdo_dbh_t *dbh, int kind ) { PDO_RESET_DBH_ERROR; PDO_VALIDATE_CONN; @@ -1622,7 +1620,7 @@ namespace { // Maps the PDO driver specific statement option/attribute constants to the core layer // statement option/attribute constants. void add_stmt_option_key(_Inout_ sqlsrv_context& ctx, _In_ size_t key, _Inout_ HashTable* options_ht, - _Inout_ zval* data TSRMLS_DC) + _Inout_ zval* data) { zend_ulong option_key = -1; switch (key) { @@ -1689,7 +1687,7 @@ void add_stmt_option_key(_Inout_ sqlsrv_context& ctx, _In_ size_t key, _Inout_ H // if a PDO handled option makes it through (such as PDO_ATTR_STATEMENT_CLASS, just skip it if (option_key != -1) { zval_add_ref(data); - core::sqlsrv_zend_hash_index_update(ctx, options_ht, option_key, data TSRMLS_CC); + core::sqlsrv_zend_hash_index_update(ctx, options_ht, option_key, data); } } @@ -1702,7 +1700,7 @@ void add_stmt_option_key(_Inout_ sqlsrv_context& ctx, _In_ size_t key, _Inout_ H // ctx - The current context. // stmt_options - The user provided list of statement options. // pdo_stmt_options_ht - Output hashtable of statement options. -void validate_stmt_options( _Inout_ sqlsrv_context& ctx, _Inout_ zval* stmt_options, _Inout_ HashTable* pdo_stmt_options_ht TSRMLS_DC ) +void validate_stmt_options( _Inout_ sqlsrv_context& ctx, _Inout_ zval* stmt_options, _Inout_ HashTable* pdo_stmt_options_ht ) { try { @@ -1720,7 +1718,7 @@ void validate_stmt_options( _Inout_ sqlsrv_context& ctx, _Inout_ zval* stmt_opti throw core::CoreException(); } - add_stmt_option_key( ctx, int_key, pdo_stmt_options_ht, data TSRMLS_CC ); + add_stmt_option_key( ctx, int_key, pdo_stmt_options_ht, data ); } ZEND_HASH_FOREACH_END(); } } @@ -1731,9 +1729,8 @@ void validate_stmt_options( _Inout_ sqlsrv_context& ctx, _Inout_ zval* stmt_opti } -void pdo_bool_conn_str_func::func( _In_ connection_option const* option, _Inout_ zval* value, sqlsrv_conn* /*conn*/, _Out_ std::string& conn_str TSRMLS_DC ) +void pdo_bool_conn_str_func::func( _In_ connection_option const* option, _Inout_ zval* value, sqlsrv_conn* /*conn*/, _Out_ std::string& conn_str ) { - TSRMLS_C; char const* val_str = "no"; if( core_str_zval_is_true( value ) ) { @@ -1748,7 +1745,7 @@ void pdo_bool_conn_str_func::func( _In_ connection_option const* option, _Inout_ } void pdo_txn_isolation_conn_attr_func::func( connection_option const* /*option*/, _In_ zval* value_z, _Inout_ sqlsrv_conn* conn, - std::string& /*conn_str*/ TSRMLS_DC ) + std::string& /*conn_str*/ ) { try { @@ -1800,7 +1797,7 @@ void pdo_txn_isolation_conn_attr_func::func( connection_option const* /*option*/ } } - core::SQLSetConnectAttr( conn, SQL_COPT_SS_TXN_ISOLATION, reinterpret_cast( out_val ), SQL_IS_UINTEGER TSRMLS_CC ); + core::SQLSetConnectAttr( conn, SQL_COPT_SS_TXN_ISOLATION, reinterpret_cast( out_val ), SQL_IS_UINTEGER ); } catch( core::CoreException& ) { diff --git a/source/pdo_sqlsrv/pdo_init.cpp b/source/pdo_sqlsrv/pdo_init.cpp index e471561f0..82ff1e101 100644 --- a/source/pdo_sqlsrv/pdo_init.cpp +++ b/source/pdo_sqlsrv/pdo_init.cpp @@ -3,7 +3,7 @@ // // Contents: initialization routines for PDO_SQLSRV // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -53,8 +53,8 @@ pdo_driver_t pdo_sqlsrv_driver = { // functions to register SQLSRV constants with the PDO class // (It's in all CAPS so it looks like the Zend macros that do similar work) -void REGISTER_PDO_SQLSRV_CLASS_CONST_LONG( _In_z_ char const* name, _In_ long value TSRMLS_DC ); -void REGISTER_PDO_SQLSRV_CLASS_CONST_STRING( _In_z_ char const* name, _In_z_ char const* value TSRMLS_DC ); +void REGISTER_PDO_SQLSRV_CLASS_CONST_LONG( _In_z_ char const* name, _In_ long value ); +void REGISTER_PDO_SQLSRV_CLASS_CONST_STRING( _In_z_ char const* name, _In_z_ char const* value ); struct sqlsrv_attr_pdo_constant { const char *name; @@ -154,18 +154,18 @@ PHP_MINIT_FUNCTION(pdo_sqlsrv) // register all attributes supported by this driver. for( int i= 0; pdo_attr_constants[i].name != NULL; ++i ) { - REGISTER_PDO_SQLSRV_CLASS_CONST_LONG( pdo_attr_constants[i].name, pdo_attr_constants[i].value TSRMLS_CC ); + REGISTER_PDO_SQLSRV_CLASS_CONST_LONG( pdo_attr_constants[i].name, pdo_attr_constants[i].value ); } - REGISTER_PDO_SQLSRV_CLASS_CONST_STRING( "SQLSRV_TXN_READ_UNCOMMITTED", PDOTxnIsolationValues::READ_UNCOMMITTED TSRMLS_CC ); - REGISTER_PDO_SQLSRV_CLASS_CONST_STRING( "SQLSRV_TXN_READ_COMMITTED", PDOTxnIsolationValues::READ_COMMITTED TSRMLS_CC ); - REGISTER_PDO_SQLSRV_CLASS_CONST_STRING( "SQLSRV_TXN_REPEATABLE_READ", PDOTxnIsolationValues::REPEATABLE_READ TSRMLS_CC ); - REGISTER_PDO_SQLSRV_CLASS_CONST_STRING( "SQLSRV_TXN_SERIALIZABLE", PDOTxnIsolationValues::SERIALIZABLE TSRMLS_CC ); - REGISTER_PDO_SQLSRV_CLASS_CONST_STRING( "SQLSRV_TXN_SNAPSHOT", PDOTxnIsolationValues::SNAPSHOT TSRMLS_CC ); + REGISTER_PDO_SQLSRV_CLASS_CONST_STRING( "SQLSRV_TXN_READ_UNCOMMITTED", PDOTxnIsolationValues::READ_UNCOMMITTED ); + REGISTER_PDO_SQLSRV_CLASS_CONST_STRING( "SQLSRV_TXN_READ_COMMITTED", PDOTxnIsolationValues::READ_COMMITTED ); + REGISTER_PDO_SQLSRV_CLASS_CONST_STRING( "SQLSRV_TXN_REPEATABLE_READ", PDOTxnIsolationValues::REPEATABLE_READ ); + REGISTER_PDO_SQLSRV_CLASS_CONST_STRING( "SQLSRV_TXN_SERIALIZABLE", PDOTxnIsolationValues::SERIALIZABLE ); + REGISTER_PDO_SQLSRV_CLASS_CONST_STRING( "SQLSRV_TXN_SNAPSHOT", PDOTxnIsolationValues::SNAPSHOT ); // retrieve the handles for the environments - core_sqlsrv_minit( &g_pdo_henv_cp, &g_pdo_henv_ncp, pdo_sqlsrv_handle_env_error, "PHP_MINIT_FUNCTION for pdo_sqlsrv" TSRMLS_CC ); + core_sqlsrv_minit( &g_pdo_henv_cp, &g_pdo_henv_ncp, pdo_sqlsrv_handle_env_error, "PHP_MINIT_FUNCTION for pdo_sqlsrv" ); } catch( ... ) { @@ -274,27 +274,20 @@ namespace { // mimic the functionality of the REGISTER_PDO_CLASS_CONST_LONG. We use this instead of the macro because // we dynamically link the pdo_get_dbh_class function rather than use the static php_pdo_get_dbh_ce (see MINIT) - void REGISTER_PDO_SQLSRV_CLASS_CONST_LONG( _In_z_ char const* name, _In_ long value TSRMLS_DC ) + void REGISTER_PDO_SQLSRV_CLASS_CONST_LONG( _In_z_ char const* name, _In_ long value ) { zend_class_entry* zend_class = php_pdo_get_dbh_ce(); SQLSRV_ASSERT( zend_class != NULL, "REGISTER_PDO_SQLSRV_CLASS_CONST_LONG: php_pdo_get_dbh_ce failed"); - int zr = zend_declare_class_constant_long( zend_class, const_cast( name ), strlen( name ), value TSRMLS_CC ); - if( zr == FAILURE ) { - throw core::CoreException(); - } + zend_declare_class_constant_long(zend_class, const_cast(name), strlen(name), value); } - void REGISTER_PDO_SQLSRV_CLASS_CONST_STRING( _In_z_ char const* name, _In_z_ char const* value TSRMLS_DC ) + void REGISTER_PDO_SQLSRV_CLASS_CONST_STRING( _In_z_ char const* name, _In_z_ char const* value ) { zend_class_entry* zend_class = php_pdo_get_dbh_ce(); SQLSRV_ASSERT( zend_class != NULL, "REGISTER_PDO_SQLSRV_CLASS_CONST_STRING: php_pdo_get_dbh_ce failed"); - int zr = zend_declare_class_constant_string( zend_class, const_cast( name ), strlen( name ), const_cast( value ) TSRMLS_CC ); - if( zr == FAILURE ) { - - throw core::CoreException(); - } + zend_declare_class_constant_string(zend_class, const_cast(name), strlen(name), const_cast(value)); } // array of pdo constants. diff --git a/source/pdo_sqlsrv/pdo_parser.cpp b/source/pdo_sqlsrv/pdo_parser.cpp index 48b591be9..1d0b72990 100644 --- a/source/pdo_sqlsrv/pdo_parser.cpp +++ b/source/pdo_sqlsrv/pdo_parser.cpp @@ -5,7 +5,7 @@ // // Copyright Microsoft Corporation // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -122,7 +122,7 @@ bool string_parser::discard_white_spaces() } // Add a key-value pair to the hashtable -void string_parser::add_key_value_pair( _In_reads_(len) const char* value, _In_ int len TSRMLS_DC ) +void string_parser::add_key_value_pair( _In_reads_(len) const char* value, _In_ int len ) { zval value_z; ZVAL_UNDEF( &value_z ); @@ -136,19 +136,19 @@ void string_parser::add_key_value_pair( _In_reads_(len) const char* value, _In_ ZVAL_STRINGL( &value_z, const_cast( value ), len ); } - core::sqlsrv_zend_hash_index_update( *ctx, this->element_ht, this->current_key, &value_z TSRMLS_CC ); + core::sqlsrv_zend_hash_index_update( *ctx, this->element_ht, this->current_key, &value_z ); } // Add a key-value pair to the hashtable with int value -void sql_string_parser::add_key_int_value_pair( _In_ unsigned int value TSRMLS_DC ) { +void sql_string_parser::add_key_int_value_pair( _In_ unsigned int value ) { zval value_z; ZVAL_LONG( &value_z, value ); - core::sqlsrv_zend_hash_index_update( *ctx, this->element_ht, this->current_key, &value_z TSRMLS_CC ); + core::sqlsrv_zend_hash_index_update( *ctx, this->element_ht, this->current_key, &value_z ); } // Validate a given DSN keyword. -void conn_string_parser::validate_key( _In_reads_(key_len) const char *key, _Inout_ int key_len TSRMLS_DC ) +void conn_string_parser::validate_key( _In_reads_(key_len) const char *key, _Inout_ int key_len ) { int new_len = discard_trailing_white_spaces( key, key_len ); @@ -173,7 +173,7 @@ void conn_string_parser::validate_key( _In_reads_(key_len) const char *key, _Ino THROW_PDO_ERROR( this->ctx, PDO_SQLSRV_ERROR_INVALID_DSN_KEY, static_cast( key_name ) ); } -void conn_string_parser::add_key_value_pair( _In_reads_(len) const char* value, _In_ int len TSRMLS_DC ) +void conn_string_parser::add_key_value_pair( _In_reads_(len) const char* value, _In_ int len ) { // if the keyword is 'Authentication', check whether the user specified option is supported bool valid = true; @@ -208,7 +208,7 @@ inline bool sql_string_parser::is_placeholder_char( char c ) } // Primary function which parses the connection string/DSN. -void conn_string_parser:: parse_conn_string( TSRMLS_D ) +void conn_string_parser:: parse_conn_string( void ) { States state = FirstKeyValuePair; // starting state int start_pos = -1; @@ -244,7 +244,7 @@ void conn_string_parser:: parse_conn_string( TSRMLS_D ) } } - this->validate_key( &( this->orig_str[start_pos] ), ( pos - start_pos ) TSRMLS_CC ); + this->validate_key( &( this->orig_str[start_pos] ), ( pos - start_pos ) ); state = Value; @@ -261,7 +261,7 @@ void conn_string_parser:: parse_conn_string( TSRMLS_D ) // if EOS encountered after 0 or more spaces OR semi-colon encountered. if( !discard_white_spaces() || this->orig_str[pos] == ';' ) { - add_key_value_pair( NULL, 0 TSRMLS_CC ); + add_key_value_pair( NULL, 0 ); if( this->is_eos() ) { @@ -323,7 +323,7 @@ void conn_string_parser:: parse_conn_string( TSRMLS_D ) state = NextKeyValuePair; } - add_key_value_pair( &( this->orig_str[start_pos] ), this->pos - start_pos TSRMLS_CC ); + add_key_value_pair( &( this->orig_str[start_pos] ), this->pos - start_pos ); SQLSRV_ASSERT((( state == NextKeyValuePair ) || ( this->is_eos() )), "conn_string_parser::parse_conn_string: Invalid state encountered " ); @@ -338,7 +338,7 @@ void conn_string_parser:: parse_conn_string( TSRMLS_D ) if( !next() ) { // EOS - add_key_value_pair( &( this->orig_str[start_pos] ), this->pos - start_pos TSRMLS_CC ); + add_key_value_pair( &( this->orig_str[start_pos] ), this->pos - start_pos ); break; } @@ -365,7 +365,7 @@ void conn_string_parser:: parse_conn_string( TSRMLS_D ) if( ! this->discard_white_spaces() ) { //EOS - add_key_value_pair( &( this->orig_str[start_pos] ), end_pos - start_pos TSRMLS_CC ); + add_key_value_pair( &( this->orig_str[start_pos] ), end_pos - start_pos ); break; } } @@ -373,7 +373,7 @@ void conn_string_parser:: parse_conn_string( TSRMLS_D ) // if semi-colon than go to next key-value pair if ( this->orig_str[pos] == ';' ) { - add_key_value_pair( &( this->orig_str[start_pos] ), end_pos - start_pos TSRMLS_CC ); + add_key_value_pair( &( this->orig_str[start_pos] ), end_pos - start_pos ); state = NextKeyValuePair; break; } @@ -417,7 +417,7 @@ void conn_string_parser:: parse_conn_string( TSRMLS_D ) } // Primary function which parses out the named placeholders from a sql string. -void sql_string_parser::parse_sql_string( TSRMLS_D ) { +void sql_string_parser::parse_sql_string( void ) { try { int start_pos = -1; while ( !this->is_eos() ) { @@ -447,7 +447,7 @@ void sql_string_parser::parse_sql_string( TSRMLS_D ) { while ( is_placeholder_char( this->orig_str[pos] )) { next(); } - add_key_value_pair( &( this->orig_str[start_pos] ), this->pos - start_pos TSRMLS_CC ); + add_key_value_pair( &( this->orig_str[start_pos] ), this->pos - start_pos ); discard_white_spaces(); // if an '=' is right after a placeholder, it means the placeholder is for output parameters // and emulate prepare does not support output parameters diff --git a/source/pdo_sqlsrv/pdo_stmt.cpp b/source/pdo_sqlsrv/pdo_stmt.cpp index 37afbf380..5e82a0465 100644 --- a/source/pdo_sqlsrv/pdo_stmt.cpp +++ b/source/pdo_sqlsrv/pdo_stmt.cpp @@ -3,7 +3,7 @@ // // Contents: Implements the PDOStatement object for the PDO_SQLSRV // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -53,7 +53,7 @@ inline SQLSMALLINT pdo_fetch_ori_to_odbc_fetch_ori ( _In_ enum pdo_fetch_orienta // Returns SQLSRV data type for a given PDO type. See pdo_param_type // for list of supported pdo types. -SQLSRV_PHPTYPE pdo_type_to_sqlsrv_php_type( _Inout_ sqlsrv_stmt* driver_stmt, _In_ enum pdo_param_type pdo_type TSRMLS_DC ) +SQLSRV_PHPTYPE pdo_type_to_sqlsrv_php_type( _Inout_ sqlsrv_stmt* driver_stmt, _In_ enum pdo_param_type pdo_type ) { pdo_sqlsrv_stmt *pdo_stmt = static_cast(driver_stmt); SQLSRV_ASSERT(pdo_stmt != NULL, "pdo_type_to_sqlsrv_php_type: pdo_stmt object was null"); @@ -137,7 +137,7 @@ inline pdo_param_type sql_type_to_pdo_type( _In_ SQLSMALLINT sql_type ) // Calls core_sqlsrv_set_scrollable function to set cursor. // PDO supports two cursor types: PDO_CURSOR_FWDONLY, PDO_CURSOR_SCROLL. -void set_stmt_cursors( _Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z TSRMLS_DC ) +void set_stmt_cursors( _Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z ) { if( Z_TYPE_P( value_z ) != IS_LONG ) { @@ -161,10 +161,10 @@ void set_stmt_cursors( _Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z TSRMLS_DC ) THROW_PDO_ERROR( stmt, PDO_SQLSRV_ERROR_INVALID_CURSOR_TYPE ); } - core_sqlsrv_set_scrollable( stmt, odbc_cursor_type TSRMLS_CC ); + core_sqlsrv_set_scrollable( stmt, odbc_cursor_type ); } -void set_stmt_cursor_scroll_type( _Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z TSRMLS_DC ) +void set_stmt_cursor_scroll_type( _Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z ) { if( Z_TYPE_P( value_z ) != IS_LONG ) { @@ -178,14 +178,14 @@ void set_stmt_cursor_scroll_type( _Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z long odbc_cursor_type = static_cast( Z_LVAL_P( value_z ) ); - core_sqlsrv_set_scrollable( stmt, odbc_cursor_type TSRMLS_CC ); + core_sqlsrv_set_scrollable( stmt, odbc_cursor_type ); return; } // Sets the statement encoding. Default encoding on the statement // implies use the connection's encoding. -void set_stmt_encoding( _Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z TSRMLS_DC ) +void set_stmt_encoding( _Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z ) { // validate the value if( Z_TYPE_P( value_z ) != IS_LONG ) { @@ -280,20 +280,20 @@ zval convert_to_zval(_Inout_ sqlsrv_stmt* stmt, _In_ SQLSRV_PHPTYPE sqlsrv_php_t } // namespace -int pdo_sqlsrv_stmt_dtor( _Inout_ pdo_stmt_t *stmt TSRMLS_DC ); -int pdo_sqlsrv_stmt_execute( _Inout_ pdo_stmt_t *stmt TSRMLS_DC ); +int pdo_sqlsrv_stmt_dtor( _Inout_ pdo_stmt_t *stmt ); +int pdo_sqlsrv_stmt_execute( _Inout_ pdo_stmt_t *stmt ); int pdo_sqlsrv_stmt_fetch( _Inout_ pdo_stmt_t *stmt, _In_ enum pdo_fetch_orientation ori, - _In_ zend_long offset TSRMLS_DC ); + _In_ zend_long offset ); int pdo_sqlsrv_stmt_param_hook( _Inout_ pdo_stmt_t *stmt, - _Inout_ struct pdo_bound_param_data *param, _In_ enum pdo_param_event event_type TSRMLS_DC ); -int pdo_sqlsrv_stmt_describe_col( _Inout_ pdo_stmt_t *stmt, _In_ int colno TSRMLS_DC ); + _Inout_ struct pdo_bound_param_data *param, _In_ enum pdo_param_event event_type ); +int pdo_sqlsrv_stmt_describe_col( _Inout_ pdo_stmt_t *stmt, _In_ int colno ); int pdo_sqlsrv_stmt_get_col_data( _Inout_ pdo_stmt_t *stmt, _In_ int colno, - _Out_writes_bytes_opt_(*len) char **ptr, _Inout_ size_t *len, _Out_opt_ int *caller_frees TSRMLS_DC ); -int pdo_sqlsrv_stmt_set_attr( _Inout_ pdo_stmt_t *stmt, _In_ zend_long attr, _Inout_ zval *val TSRMLS_DC ); -int pdo_sqlsrv_stmt_get_attr( _Inout_ pdo_stmt_t *stmt, _In_ zend_long attr, _Inout_ zval *return_value TSRMLS_DC ); -int pdo_sqlsrv_stmt_get_col_meta( _Inout_ pdo_stmt_t *stmt, _In_ zend_long colno, _Inout_ zval *return_value TSRMLS_DC ); -int pdo_sqlsrv_stmt_next_rowset( _Inout_ pdo_stmt_t *stmt TSRMLS_DC ); -int pdo_sqlsrv_stmt_close_cursor( _Inout_ pdo_stmt_t *stmt TSRMLS_DC ); + _Out_writes_bytes_opt_(*len) char **ptr, _Inout_ size_t *len, _Out_opt_ int *caller_frees ); +int pdo_sqlsrv_stmt_set_attr( _Inout_ pdo_stmt_t *stmt, _In_ zend_long attr, _Inout_ zval *val ); +int pdo_sqlsrv_stmt_get_attr( _Inout_ pdo_stmt_t *stmt, _In_ zend_long attr, _Inout_ zval *return_value ); +int pdo_sqlsrv_stmt_get_col_meta( _Inout_ pdo_stmt_t *stmt, _In_ zend_long colno, _Inout_ zval *return_value ); +int pdo_sqlsrv_stmt_next_rowset( _Inout_ pdo_stmt_t *stmt ); +int pdo_sqlsrv_stmt_close_cursor( _Inout_ pdo_stmt_t *stmt ); struct pdo_stmt_methods pdo_sqlsrv_stmt_methods = { @@ -311,40 +311,40 @@ struct pdo_stmt_methods pdo_sqlsrv_stmt_methods = { }; -void stmt_option_pdo_scrollable:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC ) +void stmt_option_pdo_scrollable:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z ) { - set_stmt_cursors( stmt, value_z TSRMLS_CC ); + set_stmt_cursors( stmt, value_z ); } -void stmt_option_encoding:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC ) +void stmt_option_encoding:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z ) { - set_stmt_encoding( stmt, value_z TSRMLS_CC ); + set_stmt_encoding( stmt, value_z ); } -void stmt_option_direct_query:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC ) +void stmt_option_direct_query:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z ) { pdo_sqlsrv_stmt *pdo_stmt = static_cast( stmt ); pdo_stmt->direct_query = ( zend_is_true( value_z )) ? true : false; } -void stmt_option_cursor_scroll_type:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC ) +void stmt_option_cursor_scroll_type:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z ) { - set_stmt_cursor_scroll_type( stmt, value_z TSRMLS_CC ); + set_stmt_cursor_scroll_type( stmt, value_z ); } -void stmt_option_emulate_prepares:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC ) +void stmt_option_emulate_prepares:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z ) { pdo_stmt_t *pdo_stmt = static_cast( stmt->driver() ); pdo_stmt->supports_placeholders = ( zend_is_true( value_z )) ? PDO_PLACEHOLDER_NONE : PDO_PLACEHOLDER_POSITIONAL; } -void stmt_option_fetch_numeric:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC ) +void stmt_option_fetch_numeric:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z ) { pdo_sqlsrv_stmt *pdo_stmt = static_cast( stmt ); pdo_stmt->fetch_numeric = ( zend_is_true( value_z )) ? true : false; } -void stmt_option_fetch_datetime:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC ) +void stmt_option_fetch_datetime:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z ) { pdo_sqlsrv_stmt *pdo_stmt = static_cast( stmt ); pdo_stmt->fetch_datetime = ( zend_is_true( value_z )) ? true : false; @@ -384,7 +384,7 @@ pdo_sqlsrv_stmt::~pdo_sqlsrv_stmt( void ) // *stmt - Pointer to current statement // Return: // Returns 0 for failure, 1 for success. -int pdo_sqlsrv_stmt_close_cursor( _Inout_ pdo_stmt_t *stmt TSRMLS_DC ) +int pdo_sqlsrv_stmt_close_cursor( _Inout_ pdo_stmt_t *stmt ) { PDO_RESET_STMT_ERROR; PDO_VALIDATE_STMT; @@ -404,7 +404,7 @@ int pdo_sqlsrv_stmt_close_cursor( _Inout_ pdo_stmt_t *stmt TSRMLS_DC ) if ( driver_stmt && driver_stmt->executed == true ) { while( driver_stmt && driver_stmt->past_next_result_end == false ) { - core_sqlsrv_next_result( driver_stmt TSRMLS_CC ); + core_sqlsrv_next_result( driver_stmt ); } } } @@ -428,7 +428,7 @@ int pdo_sqlsrv_stmt_close_cursor( _Inout_ pdo_stmt_t *stmt TSRMLS_DC ) // colno - Index of the column which requires description. // Return: // 0 for failure, 1 for success. -int pdo_sqlsrv_stmt_describe_col( _Inout_ pdo_stmt_t *stmt, _In_ int colno TSRMLS_DC) +int pdo_sqlsrv_stmt_describe_col( _Inout_ pdo_stmt_t *stmt, _In_ int colno) { PDO_RESET_STMT_ERROR; PDO_VALIDATE_STMT; @@ -441,7 +441,7 @@ int pdo_sqlsrv_stmt_describe_col( _Inout_ pdo_stmt_t *stmt, _In_ int colno TSRML try { - core_meta_data = core_sqlsrv_field_metadata( reinterpret_cast( stmt->driver_data ), colno TSRMLS_CC ); + core_meta_data = core_sqlsrv_field_metadata( reinterpret_cast( stmt->driver_data ), colno ); } catch( core::CoreException& ) { @@ -485,7 +485,7 @@ int pdo_sqlsrv_stmt_describe_col( _Inout_ pdo_stmt_t *stmt, _In_ int colno TSRML // *stmt - pointer to current statement // Return: // 1 for success. -int pdo_sqlsrv_stmt_dtor( _Inout_ pdo_stmt_t *stmt TSRMLS_DC ) +int pdo_sqlsrv_stmt_dtor( _Inout_ pdo_stmt_t *stmt ) { pdo_sqlsrv_stmt* driver_stmt = reinterpret_cast( stmt->driver_data ); @@ -523,7 +523,7 @@ int pdo_sqlsrv_stmt_dtor( _Inout_ pdo_stmt_t *stmt TSRMLS_DC ) // *stmt - pointer to the current statement. // Return: // 0 for failure, 1 for success. -int pdo_sqlsrv_stmt_execute( _Inout_ pdo_stmt_t *stmt TSRMLS_DC ) +int pdo_sqlsrv_stmt_execute( _Inout_ pdo_stmt_t *stmt ) { PDO_RESET_STMT_ERROR; PDO_VALIDATE_STMT; @@ -540,7 +540,7 @@ int pdo_sqlsrv_stmt_execute( _Inout_ pdo_stmt_t *stmt TSRMLS_DC ) while( driver_stmt->past_next_result_end == false ) { - core_sqlsrv_next_result( driver_stmt TSRMLS_CC, false ); + core_sqlsrv_next_result( driver_stmt, false ); } } @@ -572,7 +572,7 @@ int pdo_sqlsrv_stmt_execute( _Inout_ pdo_stmt_t *stmt TSRMLS_DC ) // PDOStatement::setAttribute() driver_stmt->set_query_timeout(); - SQLRETURN execReturn = core_sqlsrv_execute( driver_stmt TSRMLS_CC, query, query_len ); + SQLRETURN execReturn = core_sqlsrv_execute( driver_stmt, query, query_len ); if ( execReturn == SQL_NO_DATA ) { stmt->column_count = 0; @@ -582,7 +582,7 @@ int pdo_sqlsrv_stmt_execute( _Inout_ pdo_stmt_t *stmt TSRMLS_DC ) } else { if (driver_stmt->column_count == ACTIVE_NUM_COLS_INVALID) { - stmt->column_count = core::SQLNumResultCols( driver_stmt TSRMLS_CC ); + stmt->column_count = core::SQLNumResultCols( driver_stmt ); driver_stmt->column_count = stmt->column_count; } else { @@ -591,7 +591,7 @@ int pdo_sqlsrv_stmt_execute( _Inout_ pdo_stmt_t *stmt TSRMLS_DC ) if (driver_stmt->row_count == ACTIVE_NUM_ROWS_INVALID) { // return the row count regardless if there are any rows or not - stmt->row_count = core::SQLRowCount( driver_stmt TSRMLS_CC ); + stmt->row_count = core::SQLRowCount( driver_stmt ); driver_stmt->row_count = stmt->row_count; } else { @@ -642,7 +642,7 @@ int pdo_sqlsrv_stmt_execute( _Inout_ pdo_stmt_t *stmt TSRMLS_DC ) // Return: // 0 for failure, 1 for success. int pdo_sqlsrv_stmt_fetch( _Inout_ pdo_stmt_t *stmt, _In_ enum pdo_fetch_orientation ori, - _In_ zend_long offset TSRMLS_DC) + _In_ zend_long offset) { PDO_RESET_STMT_ERROR; PDO_VALIDATE_STMT; @@ -688,7 +688,7 @@ int pdo_sqlsrv_stmt_fetch( _Inout_ pdo_stmt_t *stmt, _In_ enum pdo_fetch_orienta } SQLSMALLINT odbc_fetch_ori = pdo_fetch_ori_to_odbc_fetch_ori( ori ); - bool data = core_sqlsrv_fetch( driver_stmt, odbc_fetch_ori, offset TSRMLS_CC ); + bool data = core_sqlsrv_fetch( driver_stmt, odbc_fetch_ori, offset ); // support for the PDO rowCount method. Since rowCount doesn't call a // method, PDO relies on us to fill the pdo_stmt_t::row_count member @@ -698,7 +698,7 @@ int pdo_sqlsrv_stmt_fetch( _Inout_ pdo_stmt_t *stmt, _In_ enum pdo_fetch_orienta // which is unnecessary and a performance hit if( driver_stmt->past_fetch_end || driver_stmt->cursor_type == SQL_CURSOR_DYNAMIC) { - stmt->row_count = core::SQLRowCount( driver_stmt TSRMLS_CC ); + stmt->row_count = core::SQLRowCount( driver_stmt ); driver_stmt->row_count = stmt->row_count; // a row_count of -1 means no rows, but we change it to 0 @@ -741,7 +741,7 @@ int pdo_sqlsrv_stmt_fetch( _Inout_ pdo_stmt_t *stmt, _In_ enum pdo_fetch_orienta // Return: // 0 for failure, 1 for success. int pdo_sqlsrv_stmt_get_col_data( _Inout_ pdo_stmt_t *stmt, _In_ int colno, - _Out_writes_bytes_opt_(*len) char **ptr, _Inout_ size_t *len, _Out_opt_ int *caller_frees TSRMLS_DC) + _Out_writes_bytes_opt_(*len) char **ptr, _Inout_ size_t *len, _Out_opt_ int *caller_frees) { PDO_RESET_STMT_ERROR; PDO_VALIDATE_STMT; @@ -781,7 +781,7 @@ int pdo_sqlsrv_stmt_get_col_data( _Inout_ pdo_stmt_t *stmt, _In_ int colno, sqlsrv_php_type.typeinfo.type = pdo_type_to_sqlsrv_php_type( driver_stmt, driver_stmt->bound_column_param_types[colno] - TSRMLS_CC ); + ); pdo_bound_param_data* bind_data = NULL; bind_data = reinterpret_cast(zend_hash_index_find_ptr(stmt->bound_columns, colno)); @@ -823,7 +823,7 @@ int pdo_sqlsrv_stmt_get_col_data( _Inout_ pdo_stmt_t *stmt, _In_ int colno, SQLSRV_PHPTYPE sqlsrv_phptype_out = SQLSRV_PHPTYPE_INVALID; core_sqlsrv_get_field( driver_stmt, colno, sqlsrv_php_type, false, *(reinterpret_cast(ptr)), - reinterpret_cast( len ), true, &sqlsrv_phptype_out TSRMLS_CC ); + reinterpret_cast( len ), true, &sqlsrv_phptype_out ); if (ptr) { zval* zval_ptr = reinterpret_cast(sqlsrv_malloc(sizeof(zval))); @@ -851,7 +851,7 @@ int pdo_sqlsrv_stmt_get_col_data( _Inout_ pdo_stmt_t *stmt, _In_ int colno, // val - Attribute value. // Return: // 0 for failure, 1 for success. -int pdo_sqlsrv_stmt_set_attr( _Inout_ pdo_stmt_t *stmt, _In_ zend_long attr, _Inout_ zval *val TSRMLS_DC) +int pdo_sqlsrv_stmt_set_attr( _Inout_ pdo_stmt_t *stmt, _In_ zend_long attr, _Inout_ zval *val) { PDO_RESET_STMT_ERROR; PDO_VALIDATE_STMT; @@ -869,7 +869,7 @@ int pdo_sqlsrv_stmt_set_attr( _Inout_ pdo_stmt_t *stmt, _In_ zend_long attr, _In break; case SQLSRV_ATTR_ENCODING: - set_stmt_encoding( driver_stmt, val TSRMLS_CC ); + set_stmt_encoding( driver_stmt, val ); break; case PDO_ATTR_CURSOR: @@ -877,7 +877,7 @@ int pdo_sqlsrv_stmt_set_attr( _Inout_ pdo_stmt_t *stmt, _In_ zend_long attr, _In break; case SQLSRV_ATTR_QUERY_TIMEOUT: - core_sqlsrv_set_query_timeout( driver_stmt, val TSRMLS_CC ); + core_sqlsrv_set_query_timeout( driver_stmt, val ); break; case SQLSRV_ATTR_CURSOR_SCROLL_TYPE: @@ -885,7 +885,7 @@ int pdo_sqlsrv_stmt_set_attr( _Inout_ pdo_stmt_t *stmt, _In_ zend_long attr, _In break; case SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE: - core_sqlsrv_set_buffered_query_limit( driver_stmt, val TSRMLS_CC ); + core_sqlsrv_set_buffered_query_limit( driver_stmt, val ); break; case SQLSRV_ATTR_FETCHES_NUMERIC_TYPE: @@ -901,7 +901,7 @@ int pdo_sqlsrv_stmt_set_attr( _Inout_ pdo_stmt_t *stmt, _In_ zend_long attr, _In break; case SQLSRV_ATTR_DECIMAL_PLACES: - core_sqlsrv_set_decimal_places(driver_stmt, val TSRMLS_CC); + core_sqlsrv_set_decimal_places(driver_stmt, val); break; case SQLSRV_ATTR_DATA_CLASSIFICATION: @@ -933,7 +933,7 @@ int pdo_sqlsrv_stmt_set_attr( _Inout_ pdo_stmt_t *stmt, _In_ zend_long attr, _In // return_value - Attribute value. // Return: // 0 for failure, 1 for success. -int pdo_sqlsrv_stmt_get_attr( _Inout_ pdo_stmt_t *stmt, _In_ zend_long attr, _Inout_ zval *return_value TSRMLS_DC ) +int pdo_sqlsrv_stmt_get_attr( _Inout_ pdo_stmt_t *stmt, _In_ zend_long attr, _Inout_ zval *return_value ) { PDO_RESET_STMT_ERROR; PDO_VALIDATE_STMT; @@ -1041,7 +1041,7 @@ int pdo_sqlsrv_stmt_get_attr( _Inout_ pdo_stmt_t *stmt, _In_ zend_long attr, _In // return_value - zval* consisting of the metadata. // Return: // FAILURE for failure, SUCCESS for success. -int pdo_sqlsrv_stmt_get_col_meta( _Inout_ pdo_stmt_t *stmt, _In_ zend_long colno, _Inout_ zval *return_value TSRMLS_DC) +int pdo_sqlsrv_stmt_get_col_meta( _Inout_ pdo_stmt_t *stmt, _In_ zend_long colno, _Inout_ zval *return_value) { PDO_RESET_STMT_ERROR; PDO_VALIDATE_STMT; @@ -1065,7 +1065,7 @@ int pdo_sqlsrv_stmt_get_col_meta( _Inout_ pdo_stmt_t *stmt, _In_ zend_long colno } // initialize the array to nothing, as PDO requires us to create it - core::sqlsrv_array_init( *driver_stmt, return_value TSRMLS_CC ); + array_init(return_value); field_meta_data* core_meta_data; @@ -1080,7 +1080,7 @@ int pdo_sqlsrv_stmt_get_col_meta( _Inout_ pdo_stmt_t *stmt, _In_ zend_long colno // initialize the column data classification array zval data_classification; ZVAL_UNDEF(&data_classification); - core::sqlsrv_array_init(*driver_stmt, &data_classification TSRMLS_CC ); + array_init(&data_classification); data_classification::fill_column_sensitivity_array(driver_stmt, (SQLSMALLINT)colno, &data_classification); @@ -1095,7 +1095,7 @@ int pdo_sqlsrv_stmt_get_col_meta( _Inout_ pdo_stmt_t *stmt, _In_ zend_long colno SQLSMALLINT out_buff_len; SQLLEN not_used; core::SQLColAttribute( driver_stmt, (SQLUSMALLINT) colno + 1, SQL_DESC_TYPE_NAME, field_type_name, - sizeof( field_type_name ), &out_buff_len, ¬_used TSRMLS_CC ); + sizeof( field_type_name ), &out_buff_len, ¬_used ); add_assoc_string( return_value, "sqlsrv:decl_type", field_type_name ); // get the PHP type of the column. The types returned here mirror the types returned by debug_zval_dump when @@ -1120,7 +1120,7 @@ int pdo_sqlsrv_stmt_get_col_meta( _Inout_ pdo_stmt_t *stmt, _In_ zend_long colno char table_name[SQL_SERVER_IDENT_SIZE_MAX] = {'\0'}; SQLLEN field_type_num; core::SQLColAttribute( driver_stmt, (SQLUSMALLINT) colno + 1, SQL_DESC_TABLE_NAME, table_name, SQL_SERVER_IDENT_SIZE_MAX, - &out_buff_len, &field_type_num TSRMLS_CC ); + &out_buff_len, &field_type_num ); add_assoc_string( return_value, "table", table_name ); if( stmt->columns && stmt->columns[colno].param_type == PDO_PARAM_ZVAL ) { @@ -1150,7 +1150,7 @@ int pdo_sqlsrv_stmt_get_col_meta( _Inout_ pdo_stmt_t *stmt, _In_ zend_long colno // stmt - PDOStatement object containing the result set. // Return: // 0 for failure, 1 for success. -int pdo_sqlsrv_stmt_next_rowset( _Inout_ pdo_stmt_t *stmt TSRMLS_DC ) +int pdo_sqlsrv_stmt_next_rowset( _Inout_ pdo_stmt_t *stmt ) { PDO_RESET_STMT_ERROR; PDO_VALIDATE_STMT; @@ -1164,7 +1164,7 @@ int pdo_sqlsrv_stmt_next_rowset( _Inout_ pdo_stmt_t *stmt TSRMLS_DC ) SQLSRV_ASSERT( driver_stmt != NULL, "pdo_sqlsrv_stmt_next_rowset: driver_data object was null" ); - core_sqlsrv_next_result( static_cast( stmt->driver_data ) TSRMLS_CC ); + core_sqlsrv_next_result( static_cast( stmt->driver_data ) ); // clear the current meta data since the new result will generate new meta data std::for_each( driver_stmt->current_meta_data.begin(), driver_stmt->current_meta_data.end(), meta_data_free ); @@ -1175,10 +1175,10 @@ int pdo_sqlsrv_stmt_next_rowset( _Inout_ pdo_stmt_t *stmt TSRMLS_DC ) return 0; } - stmt->column_count = core::SQLNumResultCols( driver_stmt TSRMLS_CC ); + stmt->column_count = core::SQLNumResultCols( driver_stmt ); // return the row count regardless if there are any rows or not - stmt->row_count = core::SQLRowCount( driver_stmt TSRMLS_CC ); + stmt->row_count = core::SQLRowCount( driver_stmt ); driver_stmt->column_count = stmt->column_count; driver_stmt->row_count = stmt->row_count; @@ -1209,7 +1209,7 @@ int pdo_sqlsrv_stmt_next_rowset( _Inout_ pdo_stmt_t *stmt TSRMLS_DC ) // Return: // Returns 0 for failure, 1 for success. int pdo_sqlsrv_stmt_param_hook( _Inout_ pdo_stmt_t *stmt, - _Inout_ struct pdo_bound_param_data *param, _In_ enum pdo_param_event event_type TSRMLS_DC) + _Inout_ struct pdo_bound_param_data *param, _In_ enum pdo_param_event event_type) { PDO_RESET_STMT_ERROR; @@ -1255,7 +1255,7 @@ int pdo_sqlsrv_stmt_param_hook( _Inout_ pdo_stmt_t *stmt, while( driver_stmt->past_next_result_end == false ) { - core_sqlsrv_next_result( driver_stmt TSRMLS_CC, false ); + core_sqlsrv_next_result( driver_stmt, false ); } } @@ -1401,7 +1401,7 @@ int pdo_sqlsrv_stmt_param_hook( _Inout_ pdo_stmt_t *stmt, // and bind the parameter core_sqlsrv_bind_param( driver_stmt, static_cast( param->paramno ), direction, &(param->parameter) , php_out_type, encoding, - sql_type, column_size, decimal_digits TSRMLS_CC ); + sql_type, column_size, decimal_digits ); } break; // undo any work done by the core layer after the statement is executed @@ -1416,7 +1416,7 @@ int pdo_sqlsrv_stmt_param_hook( _Inout_ pdo_stmt_t *stmt, } core_sqlsrv_post_param( reinterpret_cast( stmt->driver_data ), param->paramno, - &(param->parameter) TSRMLS_CC ); + &(param->parameter) ); } break; case PDO_PARAM_EVT_FETCH_PRE: @@ -1523,12 +1523,3 @@ sqlsrv_phptype pdo_sqlsrv_stmt::sql_type_to_php_type( _In_ SQLINTEGER sql_type, return sqlsrv_phptype; } - -void pdo_sqlsrv_stmt::set_query_timeout() -{ - if (query_timeout == QUERY_TIMEOUT_INVALID || query_timeout < 0) { - return; - } - - core::SQLSetStmtAttr(this, SQL_ATTR_QUERY_TIMEOUT, reinterpret_cast((SQLLEN)query_timeout), SQL_IS_UINTEGER TSRMLS_CC); -} \ No newline at end of file diff --git a/source/pdo_sqlsrv/pdo_util.cpp b/source/pdo_sqlsrv/pdo_util.cpp index 34e1a4ec5..4d76cccb2 100644 --- a/source/pdo_sqlsrv/pdo_util.cpp +++ b/source/pdo_sqlsrv/pdo_util.cpp @@ -3,7 +3,7 @@ // // Contents: Utility functions used by both connection or statement functions // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -43,8 +43,11 @@ const int WARNING_MIN_LENGTH = static_cast( strlen( WARNING_TEMPLATE sqlsrv_error_const* get_error_message( _In_opt_ unsigned int sqlsrv_error_code); // build the object and throw the PDO exception -void pdo_sqlsrv_throw_exception( _In_ sqlsrv_error_const* error TSRMLS_DC ); +void pdo_sqlsrv_throw_exception(_In_ sqlsrv_error const* error); +void format_or_get_all_errors(_Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _Inout_ sqlsrv_error_auto_ptr& error, _Inout_ char* error_code, _In_opt_ va_list* print_args); + +void add_remaining_errors_to_array (_In_ sqlsrv_error const* error, _Inout_ zval* array_z); } // pdo driver error messages @@ -462,146 +465,80 @@ pdo_error PDO_ERRORS[] = { { UINT_MAX, {} } }; -// PDO error handler for the environment context. -bool pdo_sqlsrv_handle_env_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning TSRMLS_DC, +bool pdo_sqlsrv_handle_env_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning, _In_opt_ va_list* print_args ) { - SQLSRV_ASSERT(( ctx != NULL ), "pdo_sqlsrv_handle_env_error: sqlsrv_context was null" ); - pdo_dbh_t* dbh = reinterpret_cast( ctx.driver()); - SQLSRV_ASSERT(( dbh != NULL ), "pdo_sqlsrv_handle_env_error: pdo_dbh_t was null" ); - - sqlsrv_error_auto_ptr error; - - if( sqlsrv_error_code != SQLSRV_ERROR_ODBC ) { + SQLSRV_ASSERT((ctx != NULL), "pdo_sqlsrv_handle_env_error: sqlsrv_context was null"); + pdo_dbh_t* dbh = reinterpret_cast(ctx.driver()); + SQLSRV_ASSERT((dbh != NULL), "pdo_sqlsrv_handle_env_error: pdo_dbh_t was null"); - core_sqlsrv_format_driver_error( ctx, get_error_message( sqlsrv_error_code ), error, SEV_ERROR TSRMLS_CC, print_args ); - } - else { + sqlsrv_error_auto_ptr error; + format_or_get_all_errors(ctx, sqlsrv_error_code, error, dbh->error_code, print_args); - bool err = core_sqlsrv_get_odbc_error( ctx, 1, error, SEV_ERROR TSRMLS_CC ); - SQLSRV_ASSERT( err == true, "No ODBC error was found" ); + // error_mode is valid because PDO API has already taken care of invalid ones + if (!warning && dbh->error_mode == PDO_ERRMODE_EXCEPTION) { + pdo_sqlsrv_throw_exception(error); } - strcpy_s( dbh->error_code, sizeof( pdo_error_type ), reinterpret_cast( error->sqlstate )); + ctx.set_last_error(error); - switch( dbh->error_mode ) { - - case PDO_ERRMODE_EXCEPTION: - if( !warning ) { - - pdo_sqlsrv_throw_exception( error TSRMLS_CC ); - } - ctx.set_last_error( error ); - break; - - default: - DIE( "pdo_sqlsrv_handle_env_error: Unexpected error mode. %1!d!", dbh->error_mode ); - break; - } - // we don't transfer the zval_auto_ptr since set_last_error increments the zval ref count // return error ignored = true for warnings. - return ( warning ? true : false ); - + return (warning ? true : false); } // pdo error handler for the dbh context. -bool pdo_sqlsrv_handle_dbh_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning TSRMLS_DC, +bool pdo_sqlsrv_handle_dbh_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning, _In_opt_ va_list* print_args ) { pdo_dbh_t* dbh = reinterpret_cast( ctx.driver()); SQLSRV_ASSERT( dbh != NULL, "pdo_sqlsrv_handle_dbh_error: Null dbh passed" ); sqlsrv_error_auto_ptr error; - - if( sqlsrv_error_code != SQLSRV_ERROR_ODBC ) { - - core_sqlsrv_format_driver_error( ctx, get_error_message( sqlsrv_error_code ), error, SEV_ERROR TSRMLS_CC, print_args ); + format_or_get_all_errors(ctx, sqlsrv_error_code, error, dbh->error_code, print_args); + + // error_mode is valid because PDO API has already taken care of invalid ones + if (!warning) { + if (dbh->error_mode == PDO_ERRMODE_EXCEPTION) { + pdo_sqlsrv_throw_exception(error); + } + else if (dbh->error_mode == PDO_ERRMODE_WARNING) { + size_t msg_len = strnlen_s(reinterpret_cast(error->native_message)) + SQL_SQLSTATE_BUFSIZE + + MAX_DIGITS + WARNING_MIN_LENGTH + 1; + sqlsrv_malloc_auto_ptr msg; + msg = static_cast(sqlsrv_malloc(msg_len)); + core_sqlsrv_format_message(msg, static_cast(msg_len), WARNING_TEMPLATE, error->sqlstate, error->native_code, + error->native_message); + php_error(E_WARNING, "%s", msg.get()); + } } - else { - bool err = core_sqlsrv_get_odbc_error( ctx, 1, error, SEV_ERROR TSRMLS_CC ); - SQLSRV_ASSERT( err == true, "No ODBC error was found" ); - } - - SQLSRV_ASSERT(strnlen_s(reinterpret_cast(error->sqlstate)) <= sizeof(dbh->error_code), "Error code overflow"); - strcpy_s(dbh->error_code, sizeof(dbh->error_code), reinterpret_cast(error->sqlstate)); - switch( dbh->error_mode ) { - case PDO_ERRMODE_EXCEPTION: - if( !warning ) { - - pdo_sqlsrv_throw_exception( error TSRMLS_CC ); - } - ctx.set_last_error( error ); - break; - case PDO_ERRMODE_WARNING: - if( !warning ) { - size_t msg_len = strnlen_s( reinterpret_cast( error->native_message )) + SQL_SQLSTATE_BUFSIZE - + MAX_DIGITS + WARNING_MIN_LENGTH + 1; - sqlsrv_malloc_auto_ptr msg; - msg = static_cast( sqlsrv_malloc( msg_len ) ); - core_sqlsrv_format_message( msg, static_cast( msg_len ), WARNING_TEMPLATE, error->sqlstate, error->native_code, - error->native_message ); - php_error(E_WARNING, "%s", msg.get()); - } - ctx.set_last_error( error ); - break; - case PDO_ERRMODE_SILENT: - ctx.set_last_error( error ); - break; - default: - DIE( "Unknown error mode. %1!d!", dbh->error_mode ); - break; - } + ctx.set_last_error(error); // return error ignored = true for warnings. - return ( warning ? true : false ); + return (warning ? true : false); } // PDO error handler for the statement context. -bool pdo_sqlsrv_handle_stmt_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning TSRMLS_DC, - _In_opt_ va_list* print_args ) +bool pdo_sqlsrv_handle_stmt_error(_Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning, + _In_opt_ va_list* print_args) { - pdo_stmt_t* pdo_stmt = reinterpret_cast( ctx.driver()); - SQLSRV_ASSERT( pdo_stmt != NULL && pdo_stmt->dbh != NULL, "pdo_sqlsrv_handle_stmt_error: Null statement or dbh passed" ); + pdo_stmt_t* pdo_stmt = reinterpret_cast(ctx.driver()); + SQLSRV_ASSERT(pdo_stmt != NULL && pdo_stmt->dbh != NULL, "pdo_sqlsrv_handle_stmt_error: Null statement or dbh passed"); sqlsrv_error_auto_ptr error; + format_or_get_all_errors(ctx, sqlsrv_error_code, error, pdo_stmt->error_code, print_args); - if( sqlsrv_error_code != SQLSRV_ERROR_ODBC ) { - core_sqlsrv_format_driver_error( ctx, get_error_message( sqlsrv_error_code ), error, SEV_ERROR TSRMLS_CC, print_args ); - } - else { - bool err = core_sqlsrv_get_odbc_error( ctx, 1, error, SEV_ERROR TSRMLS_CC ); - SQLSRV_ASSERT( err == true, "No ODBC error was found" ); - } - - SQLSRV_ASSERT( strnlen_s( reinterpret_cast( error->sqlstate ) ) <= sizeof( pdo_stmt->error_code ), "Error code overflow"); - strcpy_s( pdo_stmt->error_code, sizeof( pdo_stmt->error_code ), reinterpret_cast( error->sqlstate )); - - switch( pdo_stmt->dbh->error_mode ) { - case PDO_ERRMODE_EXCEPTION: - if( !warning ) { - - pdo_sqlsrv_throw_exception( error TSRMLS_CC ); - } - ctx.set_last_error( error ); - break; - case PDO_ERRMODE_WARNING: - ctx.set_last_error( error ); - break; - case PDO_ERRMODE_SILENT: - ctx.set_last_error( error ); - break; - default: - DIE( "Unknown error mode. %1!d!", pdo_stmt->dbh->error_mode ); - break; + // error_mode is valid because PDO API has already taken care of invalid ones + if (!warning && pdo_stmt->dbh->error_mode == PDO_ERRMODE_EXCEPTION) { + pdo_sqlsrv_throw_exception(error); } + ctx.set_last_error(error); // return error ignored = true for warnings. - return ( warning ? true : false ); + return (warning ? true : false); } - // Transfer a sqlsrv_context's error to a PDO zval. The standard format for a zval error is 3 elements: // 0, native code // 1, native message @@ -613,11 +550,13 @@ void pdo_sqlsrv_retrieve_context_error( _In_ sqlsrv_error const* last_error, _Ou // SQLSTATE is already present in the zval. add_next_index_long( pdo_zval, last_error->native_code ); add_next_index_string( pdo_zval, reinterpret_cast( last_error->native_message )); + + add_remaining_errors_to_array (last_error, pdo_zval); } } // check the global variable of pdo_sqlsrv severity whether the message qualifies to be logged with the LOG macro -bool pdo_severity_check(_In_ unsigned int severity TSRMLS_DC) +bool pdo_severity_check(_In_ unsigned int severity) { return ((severity & PDO_SQLSRV_G(pdo_log_severity))); } @@ -639,7 +578,7 @@ sqlsrv_error_const* get_error_message( _In_opt_ unsigned int sqlsrv_error_code) return error_message; } -void pdo_sqlsrv_throw_exception( _In_ sqlsrv_error_const* error TSRMLS_DC ) +void pdo_sqlsrv_throw_exception(_In_ sqlsrv_error const* error) { zval ex_obj; ZVAL_UNDEF( &ex_obj ); @@ -649,15 +588,23 @@ void pdo_sqlsrv_throw_exception( _In_ sqlsrv_error_const* error TSRMLS_DC ) int zr = object_init_ex( &ex_obj, ex_class ); SQLSRV_ASSERT( zr != FAILURE, "Failed to initialize exception object" ); +#if PHP_VERSION_ID >= 80000 + zend_object *zendobj = Z_OBJ_P(&ex_obj); +#endif + sqlsrv_malloc_auto_ptr ex_msg; - size_t ex_msg_len = strnlen_s( reinterpret_cast( error->native_message )) + SQL_SQLSTATE_BUFSIZE + + size_t ex_msg_len = strnlen_s(reinterpret_cast(error->native_message)) + SQL_SQLSTATE_BUFSIZE + 12 + 1; // 12 = "SQLSTATE[]: " - ex_msg = reinterpret_cast( sqlsrv_malloc( ex_msg_len )); - snprintf( ex_msg, ex_msg_len, EXCEPTION_MSG_TEMPLATE, error->sqlstate, error->native_message ); - zend_update_property_string( ex_class, &ex_obj, EXCEPTION_PROPERTY_MSG, sizeof( EXCEPTION_PROPERTY_MSG ) - 1, - ex_msg TSRMLS_CC ); - zend_update_property_string( ex_class, &ex_obj, EXCEPTION_PROPERTY_CODE, sizeof( EXCEPTION_PROPERTY_CODE ) - 1, - reinterpret_cast( error->sqlstate ) TSRMLS_CC ); + ex_msg = reinterpret_cast(sqlsrv_malloc(ex_msg_len)); + snprintf(ex_msg, ex_msg_len, EXCEPTION_MSG_TEMPLATE, error->sqlstate, error->native_message); + +#if PHP_VERSION_ID < 80000 + zend_update_property_string(ex_class, &ex_obj, EXCEPTION_PROPERTY_MSG, sizeof(EXCEPTION_PROPERTY_MSG) - 1, ex_msg); + zend_update_property_string(ex_class, &ex_obj, EXCEPTION_PROPERTY_CODE, sizeof(EXCEPTION_PROPERTY_CODE) - 1, reinterpret_cast(error->sqlstate)); +#else + zend_update_property_string(ex_class, zendobj, EXCEPTION_PROPERTY_MSG, sizeof(EXCEPTION_PROPERTY_MSG) - 1, ex_msg); + zend_update_property_string(ex_class, zendobj, EXCEPTION_PROPERTY_CODE, sizeof(EXCEPTION_PROPERTY_CODE) - 1, reinterpret_cast(error->sqlstate)); +#endif zval ex_error_info; ZVAL_UNDEF( &ex_error_info ); @@ -665,16 +612,77 @@ void pdo_sqlsrv_throw_exception( _In_ sqlsrv_error_const* error TSRMLS_DC ) add_next_index_string( &ex_error_info, reinterpret_cast( error->sqlstate )); add_next_index_long( &ex_error_info, error->native_code ); add_next_index_string( &ex_error_info, reinterpret_cast( error->native_message )); + + add_remaining_errors_to_array (error, &ex_error_info); + //zend_update_property makes an entry in the properties_table in ex_obj point to the Z_ARRVAL( ex_error_info ) //and the refcount of the zend_array is incremented by 1 - zend_update_property( ex_class, &ex_obj, EXCEPTION_PROPERTY_ERRORINFO, sizeof( EXCEPTION_PROPERTY_ERRORINFO ) - 1, - &ex_error_info TSRMLS_CC ); +#if PHP_VERSION_ID < 80000 + zend_update_property(ex_class, &ex_obj, EXCEPTION_PROPERTY_ERRORINFO, sizeof(EXCEPTION_PROPERTY_ERRORINFO) - 1, &ex_error_info); +#else + zend_update_property(ex_class, zendobj, EXCEPTION_PROPERTY_ERRORINFO, sizeof(EXCEPTION_PROPERTY_ERRORINFO) - 1, &ex_error_info); +#endif //DELREF ex_error_info here to decrement the refcount of the zend_array is 1 //the global hashtable EG(exception) then points to the zend_object in ex_obj in zend_throw_exception_object; //this ensure when EG(exception) cleans itself at php shutdown, the zend_array allocated is properly destroyed Z_DELREF( ex_error_info ); - zend_throw_exception_object( &ex_obj TSRMLS_CC ); + zend_throw_exception_object( &ex_obj ); +} + +void add_remaining_errors_to_array (_In_ sqlsrv_error const* error, _Inout_ zval* array_z) +{ + if (error->next != NULL && PDO_SQLSRV_G(report_additional_errors)) { + sqlsrv_error *p = error->next; + while (p != NULL) { + // check if sql state or native message is NULL and handle them accordingly + char *state = ""; + char *msg = ""; + + if (p->sqlstate != NULL) { + state = reinterpret_cast(p->sqlstate); + } + if (p->native_message != NULL) { + msg = reinterpret_cast(p->native_message); + } + + add_next_index_string(array_z, state); + add_next_index_long(array_z, p->native_code); + add_next_index_string(array_z, msg); + + p = p-> next; + } + } +} + +void format_or_get_all_errors(_Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _Inout_ sqlsrv_error_auto_ptr& error, _Inout_ char* error_code, _In_opt_ va_list* print_args) +{ + if (sqlsrv_error_code != SQLSRV_ERROR_ODBC) { + core_sqlsrv_format_driver_error(ctx, get_error_message(sqlsrv_error_code), error, SEV_ERROR, print_args); + strcpy_s(error_code, sizeof(pdo_error_type), reinterpret_cast(error->sqlstate)); + } + else { + bool result = core_sqlsrv_get_odbc_error(ctx, 1, error, SEV_ERROR, true); + if (result) { + // Check if there exist more errors + int rec_number = 2; + sqlsrv_error_auto_ptr err; + sqlsrv_error *p = error; + + do { + result = core_sqlsrv_get_odbc_error(ctx, rec_number++, err, SEV_ERROR, true); + if (result) { + p->next = err.get(); + err.transferred(); + p = p->next; + } + } while (result); + } + + // core_sqlsrv_get_odbc_error() returns the error_code of size SQL_SQLSTATE_BUFSIZE, + // which is the same size as pdo_error_type + strcpy_s(error_code, sizeof(pdo_error_type), reinterpret_cast(error->sqlstate)); + } } } diff --git a/source/pdo_sqlsrv/php_pdo_sqlsrv.h b/source/pdo_sqlsrv/php_pdo_sqlsrv.h index 79a294f95..6418cb603 100644 --- a/source/pdo_sqlsrv/php_pdo_sqlsrv.h +++ b/source/pdo_sqlsrv/php_pdo_sqlsrv.h @@ -6,7 +6,7 @@ // // Contents: Declarations for the extension // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -31,6 +31,7 @@ ZEND_BEGIN_MODULE_GLOBALS(pdo_sqlsrv) unsigned int pdo_log_severity; zend_long client_buffer_max_size; +short report_additional_errors; #ifndef _WIN32 zend_long set_locale_info; diff --git a/source/pdo_sqlsrv/php_pdo_sqlsrv_int.h b/source/pdo_sqlsrv/php_pdo_sqlsrv_int.h index 2caf19858..79dfa7f01 100644 --- a/source/pdo_sqlsrv/php_pdo_sqlsrv_int.h +++ b/source/pdo_sqlsrv/php_pdo_sqlsrv_int.h @@ -6,7 +6,7 @@ // // Contents: Internal declarations for the extension // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -53,6 +53,7 @@ extern HMODULE g_sqlsrv_hmodule; // (these are defined as macros to allow concatenation as we do below) #define INI_PDO_SQLSRV_CLIENT_BUFFER_MAX_SIZE "client_buffer_max_kb_size" #define INI_PDO_SQLSRV_LOG "log_severity" +#define INI_PDO_SQLSRV_MORE_ERRORS "report_additional_errors" #define INI_PREFIX "pdo_sqlsrv." #ifndef _WIN32 @@ -64,6 +65,7 @@ PHP_INI_BEGIN() zend_pdo_sqlsrv_globals, pdo_sqlsrv_globals ) STD_PHP_INI_ENTRY( INI_PREFIX INI_PDO_SQLSRV_CLIENT_BUFFER_MAX_SIZE , INI_BUFFERED_QUERY_LIMIT_DEFAULT, PHP_INI_ALL, OnUpdateLong, client_buffer_max_size, zend_pdo_sqlsrv_globals, pdo_sqlsrv_globals ) + STD_PHP_INI_ENTRY(INI_PREFIX INI_PDO_SQLSRV_MORE_ERRORS, "1", PHP_INI_ALL, OnUpdateLong, report_additional_errors, zend_pdo_sqlsrv_globals, pdo_sqlsrv_globals) #ifndef _WIN32 STD_PHP_INI_ENTRY(INI_PREFIX INI_PDO_SET_LOCALE_INFO, "2", PHP_INI_ALL, OnUpdateLong, set_locale_info, zend_pdo_sqlsrv_globals, pdo_sqlsrv_globals) @@ -120,7 +122,7 @@ class string_parser inline bool is_eos(void); inline bool is_white_space( _In_ char c ); bool discard_white_spaces(void); - void add_key_value_pair( _In_reads_(len) const char* value, _In_ int len TSRMLS_DC ); + void add_key_value_pair( _In_reads_(len) const char* value, _In_ int len ); }; @@ -145,14 +147,14 @@ class conn_string_parser : private string_parser private: const char* current_key_name; int discard_trailing_white_spaces( _In_reads_(len) const char* str, _Inout_ int len ); - void validate_key( _In_reads_(key_len) const char *key, _Inout_ int key_len TSRMLS_DC); + void validate_key( _In_reads_(key_len) const char *key, _Inout_ int key_len); protected: - void add_key_value_pair( _In_reads_(len) const char* value, _In_ int len TSRMLS_DC); + void add_key_value_pair( _In_reads_(len) const char* value, _In_ int len); public: conn_string_parser( _In_ sqlsrv_context& ctx, _In_ const char* dsn, _In_ int len, _In_ HashTable* conn_options_ht ); - void parse_conn_string( TSRMLS_D ); + void parse_conn_string( void ); }; @@ -166,9 +168,9 @@ class sql_string_parser : private string_parser private: bool is_placeholder_char(char); public: - void add_key_int_value_pair( _In_ unsigned int value TSRMLS_DC ); + void add_key_int_value_pair( _In_ unsigned int value ); sql_string_parser(_In_ sqlsrv_context& ctx, _In_ const char* sql_str, _In_ int len, _In_ HashTable* placeholder_ht); - void parse_sql_string(TSRMLS_D); + void parse_sql_string(void); }; @@ -178,7 +180,7 @@ class sql_string_parser : private string_parser extern const connection_option PDO_CONN_OPTS[]; -int pdo_sqlsrv_db_handle_factory( _Inout_ pdo_dbh_t *dbh, _In_opt_ zval *driver_options TSRMLS_DC); +int pdo_sqlsrv_db_handle_factory( _Inout_ pdo_dbh_t *dbh, _In_opt_ zval *driver_options); // a core layer pdo dbh object. This object inherits and overrides the statement factory struct pdo_sqlsrv_dbh : public sqlsrv_conn { @@ -193,7 +195,7 @@ struct pdo_sqlsrv_dbh : public sqlsrv_conn { short decimal_places; short use_national_characters; - pdo_sqlsrv_dbh( _In_ SQLHANDLE h, _In_ error_callback e, _In_ void* driver TSRMLS_DC ); + pdo_sqlsrv_dbh( _In_ SQLHANDLE h, _In_ error_callback e, _In_ void* driver ); }; @@ -202,45 +204,39 @@ struct pdo_sqlsrv_dbh : public sqlsrv_conn { //********************************************************************************************************************************* struct stmt_option_encoding : public stmt_option_functor { - - virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC ); + virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z ); }; struct stmt_option_pdo_scrollable : public stmt_option_functor { - - virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC ); + virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z ); }; struct stmt_option_direct_query : public stmt_option_functor { - - virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC ); + virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z ); }; struct stmt_option_cursor_scroll_type : public stmt_option_functor { - - virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC ); + virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z ); }; struct stmt_option_emulate_prepares : public stmt_option_functor { - - virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC ); + virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z ); }; struct stmt_option_fetch_numeric : public stmt_option_functor { - virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC ); + virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z ); }; struct stmt_option_fetch_datetime : public stmt_option_functor { - virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC ); + virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z ); }; extern struct pdo_stmt_methods pdo_sqlsrv_stmt_methods; // a core layer pdo stmt object. This object inherits and overrides the callbacks necessary struct pdo_sqlsrv_stmt : public sqlsrv_stmt { - - pdo_sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error_callback e, _In_ void* drv TSRMLS_DC ) : - sqlsrv_stmt( c, handle, e, drv TSRMLS_CC ), + pdo_sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error_callback e, _In_ void* drv ) : + sqlsrv_stmt( c, handle, e, drv ), direct_query( false ), direct_query_subst_string( NULL ), direct_query_subst_string_len( 0 ), @@ -264,9 +260,6 @@ struct pdo_sqlsrv_stmt : public sqlsrv_stmt { // for PDO, everything is a string, so we return SQLSRV_PHPTYPE_STRING for all SQL types virtual sqlsrv_phptype sql_type_to_php_type( _In_ SQLINTEGER sql_type, _In_ SQLUINTEGER size, _In_ bool prefer_string_to_stream ); - // driver specific way to set query timeout - virtual void set_query_timeout(); - bool direct_query; // flag set if the query should be executed directly or prepared const char* direct_query_subst_string; // if the query is direct, hold the substitution string if using named parameters size_t direct_query_subst_string_len; // length of query string used for direct queries @@ -292,18 +285,18 @@ struct pdo_error { // called when an error occurs in the core layer. These routines are set as the error_callback in a // context. The context is passed to this function since it contains the function -bool pdo_sqlsrv_handle_env_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning TSRMLS_DC, +bool pdo_sqlsrv_handle_env_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning, _In_opt_ va_list* print_args ); -bool pdo_sqlsrv_handle_dbh_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning TSRMLS_DC, +bool pdo_sqlsrv_handle_dbh_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning, _In_opt_ va_list* print_args ); -bool pdo_sqlsrv_handle_stmt_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning TSRMLS_DC, +bool pdo_sqlsrv_handle_stmt_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning, _In_opt_ va_list* print_args ); // common routine to transfer a sqlsrv_context's error to a PDO zval void pdo_sqlsrv_retrieve_context_error( _In_ sqlsrv_error const* last_error, _Out_ zval* pdo_zval ); // reset the errors from the last operation -inline void pdo_reset_dbh_error( _Inout_ pdo_dbh_t* dbh TSRMLS_DC ) +inline void pdo_reset_dbh_error( _Inout_ pdo_dbh_t* dbh ) { strcpy_s( dbh->error_code, sizeof( dbh->error_code ), "00000" ); // 00000 means no error @@ -330,7 +323,7 @@ inline void pdo_reset_dbh_error( _Inout_ pdo_dbh_t* dbh TSRMLS_DC ) core_sqlsrv_register_severity_checker(pdo_severity_check); \ LOG(SEV_NOTICE, message); -#define PDO_RESET_DBH_ERROR pdo_reset_dbh_error( dbh TSRMLS_CC ); +#define PDO_RESET_DBH_ERROR pdo_reset_dbh_error( dbh ); inline void pdo_reset_stmt_error( _Inout_ pdo_stmt_t* stmt ) { @@ -406,7 +399,7 @@ enum PDO_ERROR_CODES { extern pdo_error PDO_ERRORS[]; #define THROW_PDO_ERROR( ctx, custom, ... ) \ - call_error_handler( ctx, custom TSRMLS_CC, false, ## __VA_ARGS__ ); \ + call_error_handler( ctx, custom, false, ## __VA_ARGS__ ); \ throw pdo::PDOException(); namespace pdo { @@ -422,7 +415,6 @@ namespace pdo { } // namespace pdo // check the global variable of pdo_sqlsrv severity whether the message qualifies to be logged with the LOG macro -bool pdo_severity_check(_In_ unsigned int severity TSRMLS_DC); - +bool pdo_severity_check(_In_ unsigned int severity); #endif /* PHP_PDO_SQLSRV_INT_H */ diff --git a/source/pdo_sqlsrv/template.rc b/source/pdo_sqlsrv/template.rc index 350a2f825..561a65df2 100644 --- a/source/pdo_sqlsrv/template.rc +++ b/source/pdo_sqlsrv/template.rc @@ -3,7 +3,7 @@ // // Contents: Version resource // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/FormattedPrint.cpp b/source/shared/FormattedPrint.cpp index dd076078c..23afab351 100644 --- a/source/shared/FormattedPrint.cpp +++ b/source/shared/FormattedPrint.cpp @@ -6,7 +6,7 @@ // Contents: Contains functions for handling Windows format strings // and UTF-16 on non-Windows platforms // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -389,7 +389,6 @@ int FormattedPrintA( IFormattedPrintOutput * output, const char *format, v char sz[BUFFERSIZE]; } buffer = {'\0'}; WCHAR wchar; /* temp wchar_t */ - int buffersize; /* size of text.sz (used only for the call to _cfltcvt) */ int bufferiswide=0; /* non-zero = buffer contains wide chars already */ #ifndef _SAFECRT_IMPL @@ -406,7 +405,6 @@ int FormattedPrintA( IFormattedPrintOutput * output, const char *format, v textlen = 0; /* no text yet */ state = ST_NORMAL; /* starting state */ heapbuf = NULL; /* not using heap-allocated buffer */ - buffersize = 0; /* main loop -- loop while format character exist and no I/O errors */ while ((ch = *format++) != '\0' && charsout >= 0) { @@ -631,9 +629,9 @@ int FormattedPrintA( IFormattedPrintOutput * output, const char *format, v case ('a'): { /* floating point conversion -- we call cfltcvt routines */ /* to do the work for us. */ - flags |= FL_SIGNED; /* floating point is signed conversion */ - text.sz = buffer.sz; /* put result in buffer */ - buffersize = BUFFERSIZE; + flags |= FL_SIGNED; /* floating point is signed conversion */ + text.sz = buffer.sz; /* put result in buffer */ + int buffersize = BUFFERSIZE; /* size of text.sz (used only for the call to _cfltcvt) */ /* compute the precision value */ if (precision < 0) diff --git a/source/shared/FormattedPrint.h b/source/shared/FormattedPrint.h index 79b824b41..1d853b15e 100644 --- a/source/shared/FormattedPrint.h +++ b/source/shared/FormattedPrint.h @@ -4,7 +4,7 @@ // Contents: Contains functions for handling Windows format strings // and UTF-16 on non-Windows platforms // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/StringFunctions.cpp b/source/shared/StringFunctions.cpp index 7426644f6..7b08fcf66 100644 --- a/source/shared/StringFunctions.cpp +++ b/source/shared/StringFunctions.cpp @@ -3,7 +3,7 @@ // // Contents: Contains functions for handling UTF-16 on non-Windows platforms // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/StringFunctions.h b/source/shared/StringFunctions.h index 7593a534f..b78509547 100644 --- a/source/shared/StringFunctions.h +++ b/source/shared/StringFunctions.h @@ -3,7 +3,7 @@ // // Contents: Contains functions for handling UTF-16 on non-Windows platforms // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/core_conn.cpp b/source/shared/core_conn.cpp index c328a9d58..3b43f2ba4 100644 --- a/source/shared/core_conn.cpp +++ b/source/shared/core_conn.cpp @@ -3,7 +3,7 @@ // // Contents: Core routines that use connection handles shared between sqlsrv and pdo_sqlsrv // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -68,13 +68,12 @@ const char CONNECTION_OPTION_MARS_ON[] = "MARS_Connection={Yes};"; void build_connection_string_and_set_conn_attr( _Inout_ sqlsrv_conn* conn, _Inout_z_ const char* server, _Inout_opt_z_ const char* uid, _Inout_opt_z_ const char* pwd, _Inout_opt_ HashTable* options_ht, _In_ const connection_option valid_conn_opts[], - void* driver,_Inout_ std::string& connection_string TSRMLS_DC ); -void determine_server_version( _Inout_ sqlsrv_conn* conn TSRMLS_DC ); + void* driver,_Inout_ std::string& connection_string ); +void determine_server_version( _Inout_ sqlsrv_conn* conn ); 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_azure_key_vault( _Inout_ sqlsrv_conn* conn TSRMLS_DC ); +connection_option const* get_connection_option( sqlsrv_conn* conn, _In_ const char* key, _In_ SQLULEN key_len ); +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 ); +void load_azure_key_vault( _Inout_ sqlsrv_conn* conn ); void configure_azure_key_vault( sqlsrv_conn* conn, BYTE config_attr, const DWORD config_value, size_t key_size); void configure_azure_key_vault( sqlsrv_conn* conn, BYTE config_attr, const char* config_value, size_t key_size); } @@ -97,7 +96,7 @@ void configure_azure_key_vault( sqlsrv_conn* conn, BYTE config_attr, const char* sqlsrv_conn* core_sqlsrv_connect( _In_ sqlsrv_context& henv_cp, _In_ sqlsrv_context& henv_ncp, _In_ driver_conn_factory conn_factory, _Inout_z_ const char* server, _Inout_opt_z_ const char* uid, _Inout_opt_z_ const char* pwd, _Inout_opt_ HashTable* options_ht, _In_ error_callback err, _In_ const connection_option valid_conn_opts[], - _In_ void* driver, _In_z_ const char* driver_func TSRMLS_DC ) + _In_ void* driver, _In_z_ const char* driver_func ) { SQLRETURN r; @@ -149,11 +148,11 @@ sqlsrv_conn* core_sqlsrv_connect( _In_ sqlsrv_context& henv_cp, _In_ sqlsrv_cont #endif // !_WIN32 SQLHANDLE temp_conn_h; - core::SQLAllocHandle( SQL_HANDLE_DBC, *henv, &temp_conn_h TSRMLS_CC ); - conn = conn_factory( temp_conn_h, err, driver TSRMLS_CC ); + core::SQLAllocHandle( SQL_HANDLE_DBC, *henv, &temp_conn_h ); + conn = conn_factory( temp_conn_h, err, driver ); conn->set_func( driver_func ); - build_connection_string_and_set_conn_attr( conn, server, uid, pwd, options_ht, valid_conn_opts, driver, conn_str TSRMLS_CC ); + build_connection_string_and_set_conn_attr( conn, server, uid, pwd, options_ht, valid_conn_opts, driver, conn_str ); // If column encryption is enabled, must use ODBC driver 17 if( conn->ce_option.enabled && conn->driver_version != ODBC_DRIVER_UNKNOWN) { @@ -271,7 +270,7 @@ sqlsrv_conn* core_sqlsrv_connect( _In_ sqlsrv_context& henv_cp, _In_ sqlsrv_cont #ifndef _WIN32 if ( r == SQL_SUCCESS_WITH_INFO ) { #endif // !_WIN32 - determine_server_version( conn TSRMLS_CC ); + determine_server_version( conn ); #ifndef _WIN32 } #endif // !_WIN32 @@ -384,6 +383,9 @@ SQLRETURN core_odbc_connect( _Inout_ sqlsrv_conn* conn, _Inout_ std::string& con sqlsrv_malloc_auto_ptr wconn_string; unsigned int wconn_len = static_cast( conn_str.length() + 1 ) * sizeof( SQLWCHAR ); + // Set the desired data classification version before connecting, but older ODBC drivers will generate a warning message 'Driver's SQLSetConnectAttr failed' + SQLSetConnectAttr(conn->handle(), SQL_COPT_SS_DATACLASSIFICATION_VERSION, reinterpret_cast(data_classification::VERSION_RANK_AVAILABLE), SQL_IS_POINTER); + // We only support UTF-8 encoding for connection string. // Convert our UTF-8 connection string to UTF-16 before connecting with SQLDriverConnnectW wconn_string = utf16_string_from_mbcs_string( SQLSRV_ENCODING_UTF8, conn_str.c_str(), static_cast( conn_str.length() ), &wconn_len, true ); @@ -426,14 +428,14 @@ SQLRETURN core_odbc_connect( _Inout_ sqlsrv_conn* conn, _Inout_ std::string& con // Parameters: // sqlsrv_conn*: The connection with which the transaction is associated. -void core_sqlsrv_begin_transaction( _Inout_ sqlsrv_conn* conn TSRMLS_DC ) +void core_sqlsrv_begin_transaction( _Inout_ sqlsrv_conn* conn ) { try { DEBUG_SQLSRV_ASSERT( conn != NULL, "core_sqlsrv_begin_transaction: connection object was null." ); core::SQLSetConnectAttr( conn, SQL_ATTR_AUTOCOMMIT, reinterpret_cast( SQL_AUTOCOMMIT_OFF ), - SQL_IS_UINTEGER TSRMLS_CC ); + SQL_IS_UINTEGER ); } catch ( core::CoreException& ) { throw; @@ -449,16 +451,16 @@ void core_sqlsrv_begin_transaction( _Inout_ sqlsrv_conn* conn TSRMLS_DC ) // Parameters: // sqlsrv_conn*: The connection on which the transaction is active. -void core_sqlsrv_commit( _Inout_ sqlsrv_conn* conn TSRMLS_DC ) +void core_sqlsrv_commit( _Inout_ sqlsrv_conn* conn ) { try { DEBUG_SQLSRV_ASSERT( conn != NULL, "core_sqlsrv_commit: connection object was null." ); - core::SQLEndTran( SQL_HANDLE_DBC, conn, SQL_COMMIT TSRMLS_CC ); + core::SQLEndTran( SQL_HANDLE_DBC, conn, SQL_COMMIT ); core::SQLSetConnectAttr( conn, SQL_ATTR_AUTOCOMMIT, reinterpret_cast( SQL_AUTOCOMMIT_ON ), - SQL_IS_UINTEGER TSRMLS_CC ); + SQL_IS_UINTEGER ); } catch ( core::CoreException& ) { throw; @@ -474,16 +476,16 @@ void core_sqlsrv_commit( _Inout_ sqlsrv_conn* conn TSRMLS_DC ) // Parameters: // sqlsrv_conn*: The connection on which the transaction is active. -void core_sqlsrv_rollback( _Inout_ sqlsrv_conn* conn TSRMLS_DC ) +void core_sqlsrv_rollback( _Inout_ sqlsrv_conn* conn ) { try { DEBUG_SQLSRV_ASSERT( conn != NULL, "core_sqlsrv_rollback: connection object was null." ); - core::SQLEndTran( SQL_HANDLE_DBC, conn, SQL_ROLLBACK TSRMLS_CC ); + core::SQLEndTran( SQL_HANDLE_DBC, conn, SQL_ROLLBACK ); core::SQLSetConnectAttr( conn, SQL_ATTR_AUTOCOMMIT, reinterpret_cast( SQL_AUTOCOMMIT_ON ), - SQL_IS_UINTEGER TSRMLS_CC ); + SQL_IS_UINTEGER ); } catch ( core::CoreException& ) { @@ -495,7 +497,7 @@ void core_sqlsrv_rollback( _Inout_ sqlsrv_conn* conn TSRMLS_DC ) // Called when a connection resource is destroyed by the Zend engine. // Parameters: // conn - The current active connection. -void core_sqlsrv_close( _Inout_opt_ sqlsrv_conn* conn TSRMLS_DC ) +void core_sqlsrv_close( _Inout_opt_ sqlsrv_conn* conn ) { // if the connection wasn't successful, just return. if( conn == NULL ) @@ -504,7 +506,7 @@ void core_sqlsrv_close( _Inout_opt_ sqlsrv_conn* conn TSRMLS_DC ) try { // rollback any transaction in progress (we don't care about the return result) - core::SQLEndTran( SQL_HANDLE_DBC, conn, SQL_ROLLBACK TSRMLS_CC ); + core::SQLEndTran( SQL_HANDLE_DBC, conn, SQL_ROLLBACK ); } catch( core::CoreException& ) { LOG( SEV_ERROR, "Transaction rollback failed when closing the connection." ); @@ -529,7 +531,7 @@ void core_sqlsrv_close( _Inout_opt_ sqlsrv_conn* conn TSRMLS_DC ) // sql - T-SQL command to prepare // sql_len - length of the T-SQL string -void core_sqlsrv_prepare( _Inout_ sqlsrv_stmt* stmt, _In_reads_bytes_(sql_len) const char* sql, _In_ SQLLEN sql_len TSRMLS_DC ) +void core_sqlsrv_prepare( _Inout_ sqlsrv_stmt* stmt, _In_reads_bytes_(sql_len) const char* sql, _In_ SQLLEN sql_len ) { try { @@ -557,7 +559,7 @@ void core_sqlsrv_prepare( _Inout_ sqlsrv_stmt* stmt, _In_reads_bytes_(sql_len) c } // prepare our wide char query string - core::SQLPrepareW( stmt, reinterpret_cast( wsql_string.get() ), wsql_len TSRMLS_CC ); + core::SQLPrepareW( stmt, reinterpret_cast( wsql_string.get() ), wsql_len ); stmt->param_descriptions.clear(); @@ -587,22 +589,14 @@ void core_sqlsrv_prepare( _Inout_ sqlsrv_stmt* stmt, _In_reads_bytes_(sql_len) c // conn - The connection resource by which the client and server are connected. // *server_version - zval for returning results. -void core_sqlsrv_get_server_version( _Inout_ sqlsrv_conn* conn, _Inout_ zval* server_version TSRMLS_DC ) +void core_sqlsrv_get_server_version( _Inout_ sqlsrv_conn* conn, _Inout_ zval* server_version ) { try { - - sqlsrv_malloc_auto_ptr buffer; + char buffer[INFO_BUFFER_LEN] = ""; SQLSMALLINT buffer_len = 0; - - get_server_version( conn, &buffer, buffer_len TSRMLS_CC ); - core::sqlsrv_zval_stringl( server_version, buffer, buffer_len ); - if ( buffer != 0 ) { - sqlsrv_free( buffer ); - } - buffer.transferred(); - } - - catch( core::CoreException& ) { + core::SQLGetInfo(conn, SQL_DBMS_VER, buffer, INFO_BUFFER_LEN, &buffer_len); + core::sqlsrv_zval_stringl(server_version, buffer, buffer_len); + } catch( core::CoreException& ) { throw; } } @@ -614,36 +608,28 @@ void core_sqlsrv_get_server_version( _Inout_ sqlsrv_conn* conn, _Inout_ zval* se // conn - The connection resource by which the client and server are connected. // *server_info - zval for returning results. -void core_sqlsrv_get_server_info( _Inout_ sqlsrv_conn* conn, _Out_ zval *server_info TSRMLS_DC ) +void core_sqlsrv_get_server_info( _Inout_ sqlsrv_conn* conn, _Out_ zval *server_info ) { try { - - sqlsrv_malloc_auto_ptr buffer; + char buffer[INFO_BUFFER_LEN] = ""; SQLSMALLINT buffer_len = 0; // Get the database name - buffer = static_cast( sqlsrv_malloc( INFO_BUFFER_LEN )); - core::SQLGetInfo( conn, SQL_DATABASE_NAME, buffer, INFO_BUFFER_LEN, &buffer_len TSRMLS_CC ); + core::SQLGetInfo(conn, SQL_DATABASE_NAME, buffer, INFO_BUFFER_LEN, &buffer_len); // initialize the array - core::sqlsrv_array_init( *conn, server_info TSRMLS_CC ); + array_init(server_info); - core::sqlsrv_add_assoc_string( *conn, server_info, "CurrentDatabase", buffer, 0 /*duplicate*/ TSRMLS_CC ); - buffer.transferred(); + add_assoc_string(server_info, "CurrentDatabase", buffer); // Get the server version - get_server_version( conn, &buffer, buffer_len TSRMLS_CC ); - core::sqlsrv_add_assoc_string( *conn, server_info, "SQLServerVersion", buffer, 0 /*duplicate*/ TSRMLS_CC ); - buffer.transferred(); + core::SQLGetInfo(conn, SQL_DBMS_VER, buffer, INFO_BUFFER_LEN, &buffer_len); + add_assoc_string(server_info, "SQLServerVersion", buffer); // Get the server name - buffer = static_cast( sqlsrv_malloc( INFO_BUFFER_LEN )); - core::SQLGetInfo( conn, SQL_SERVER_NAME, buffer, INFO_BUFFER_LEN, &buffer_len TSRMLS_CC ); - core::sqlsrv_add_assoc_string( *conn, server_info, "SQLServerName", buffer, 0 /*duplicate*/ TSRMLS_CC ); - buffer.transferred(); - } - - catch( core::CoreException& ) { + core::SQLGetInfo(conn, SQL_SERVER_NAME, buffer, INFO_BUFFER_LEN, &buffer_len); + add_assoc_string(server_info, "SQLServerName", buffer); + } catch (core::CoreException&) { throw; } } @@ -654,42 +640,32 @@ void core_sqlsrv_get_server_info( _Inout_ sqlsrv_conn* conn, _Out_ zval *server_ // conn - The connection resource by which the client and server are connected. // *client_info - zval for returning the results. -void core_sqlsrv_get_client_info( _Inout_ sqlsrv_conn* conn, _Out_ zval *client_info TSRMLS_DC ) +void core_sqlsrv_get_client_info( _Inout_ sqlsrv_conn* conn, _Out_ zval *client_info ) { try { - - sqlsrv_malloc_auto_ptr buffer; + char buffer[INFO_BUFFER_LEN] = ""; SQLSMALLINT buffer_len = 0; // Get the ODBC driver's dll name - buffer = static_cast( sqlsrv_malloc( INFO_BUFFER_LEN )); - core::SQLGetInfo( conn, SQL_DRIVER_NAME, buffer, INFO_BUFFER_LEN, &buffer_len TSRMLS_CC ); + core::SQLGetInfo( conn, SQL_DRIVER_NAME, buffer, INFO_BUFFER_LEN, &buffer_len ); // initialize the array - core::sqlsrv_array_init( *conn, client_info TSRMLS_CC ); + array_init(client_info); #ifndef _WIN32 - core::sqlsrv_add_assoc_string( *conn, client_info, "DriverName", buffer, 0 /*duplicate*/ TSRMLS_CC ); + add_assoc_string(client_info, "DriverName", buffer); #else - core::sqlsrv_add_assoc_string( *conn, client_info, "DriverDllName", buffer, 0 /*duplicate*/ TSRMLS_CC ); + add_assoc_string(client_info, "DriverDllName", buffer); #endif // !_WIN32 - buffer.transferred(); // Get the ODBC driver's ODBC version - buffer = static_cast( sqlsrv_malloc( INFO_BUFFER_LEN )); - core::SQLGetInfo( conn, SQL_DRIVER_ODBC_VER, buffer, INFO_BUFFER_LEN, &buffer_len TSRMLS_CC ); - core::sqlsrv_add_assoc_string( *conn, client_info, "DriverODBCVer", buffer, 0 /*duplicate*/ TSRMLS_CC ); - buffer.transferred(); + core::SQLGetInfo( conn, SQL_DRIVER_ODBC_VER, buffer, INFO_BUFFER_LEN, &buffer_len ); + add_assoc_string(client_info, "DriverODBCVer", buffer); // Get the OBDC driver's version - buffer = static_cast( sqlsrv_malloc( INFO_BUFFER_LEN )); - core::SQLGetInfo( conn, SQL_DRIVER_VER, buffer, INFO_BUFFER_LEN, &buffer_len TSRMLS_CC ); - core::sqlsrv_add_assoc_string( *conn, client_info, "DriverVer", buffer, 0 /*duplicate*/ TSRMLS_CC ); - buffer.transferred(); - - } - - catch( core::CoreException& ) { + core::SQLGetInfo( conn, SQL_DRIVER_VER, buffer, INFO_BUFFER_LEN, &buffer_len ); + add_assoc_string(client_info, "DriverVer", buffer); + } catch( core::CoreException& ) { throw; } } @@ -753,7 +729,7 @@ bool core_is_authentication_option_valid( _In_z_ const char* value, _In_ size_t namespace { connection_option const* get_connection_option( sqlsrv_conn* conn, _In_ SQLULEN key, - _In_ const connection_option conn_opts[] TSRMLS_DC ) + _In_ const connection_option conn_opts[] ) { for( int opt_idx = 0; conn_opts[opt_idx].conn_option_key != SQLSRV_CONN_OPTION_INVALID; ++opt_idx ) { @@ -774,7 +750,7 @@ connection_option const* get_connection_option( sqlsrv_conn* conn, _In_ SQLULEN void build_connection_string_and_set_conn_attr( _Inout_ sqlsrv_conn* conn, _Inout_z_ const char* server, _Inout_opt_z_ const char* uid, _Inout_opt_z_ const char* pwd, _Inout_opt_ HashTable* options, _In_ const connection_option valid_conn_opts[], - void* driver, _Inout_ std::string& connection_string TSRMLS_DC ) + void* driver, _Inout_ std::string& connection_string ) { bool mars_mentioned = false; connection_option const* conn_opt; @@ -808,9 +784,12 @@ void build_connection_string_and_set_conn_attr( _Inout_ sqlsrv_conn* conn, _Inou zval* auth_option = NULL; auth_option = zend_hash_index_find(options, SQLSRV_CONN_OPTION_AUTHENTICATION); - char* option = Z_STRVAL_P(auth_option); + char* option = NULL; + if (auth_option != NULL) { + option = Z_STRVAL_P(auth_option); + } - if (!stricmp(option, AzureADOptions::AZURE_AUTH_AD_MSI)) { + if (option != NULL && !stricmp(option, AzureADOptions::AZURE_AUTH_AD_MSI)) { activeDirectoryMSI = true; // There are two types of managed identities: @@ -834,7 +813,7 @@ void build_connection_string_and_set_conn_attr( _Inout_ sqlsrv_conn* conn, _Inou } // Add the server name - common_conn_str_append_func( ODBCConnOptions::SERVER, server, strnlen_s( server ), connection_string TSRMLS_CC ); + common_conn_str_append_func( ODBCConnOptions::SERVER, server, strnlen_s( server ), connection_string ); // If uid is not present then we use trusted connection -- but not when access token or ActiveDirectoryMSI is used, // because they are incompatible @@ -848,7 +827,7 @@ void build_connection_string_and_set_conn_attr( _Inout_ sqlsrv_conn* conn, _Inou throw core::CoreException(); } - common_conn_str_append_func(ODBCConnOptions::UID, uid, strnlen_s(uid), connection_string TSRMLS_CC); + common_conn_str_append_func(ODBCConnOptions::UID, uid, strnlen_s(uid), connection_string); // if no password was given, then don't add a password to the connection string. Perhaps the UID // given doesn't have a password? @@ -858,7 +837,7 @@ void build_connection_string_and_set_conn_attr( _Inout_ sqlsrv_conn* conn, _Inou throw core::CoreException(); } - common_conn_str_append_func(ODBCConnOptions::PWD, pwd, strnlen_s(pwd), connection_string TSRMLS_CC); + common_conn_str_append_func(ODBCConnOptions::PWD, pwd, strnlen_s(pwd), connection_string); } } } @@ -894,13 +873,13 @@ void build_connection_string_and_set_conn_attr( _Inout_ sqlsrv_conn* conn, _Inou // The driver layer should ensure a valid key. DEBUG_SQLSRV_ASSERT(( type == HASH_KEY_IS_LONG ), "build_connection_string_and_set_conn_attr: invalid connection option key type." ); - conn_opt = get_connection_option( conn, index, valid_conn_opts TSRMLS_CC ); + conn_opt = get_connection_option( conn, index, valid_conn_opts ); if( index == SQLSRV_CONN_OPTION_MARS ) { mars_mentioned = true; } - conn_opt->func( conn_opt, data, conn, connection_string TSRMLS_CC ); + conn_opt->func( conn_opt, data, conn, connection_string ); } ZEND_HASH_FOREACH_END(); // MARS on if not explicitly turned off @@ -915,30 +894,6 @@ void build_connection_string_and_set_conn_attr( _Inout_ sqlsrv_conn* conn, _Inou } } - -// get_server_version -// Helper function which returns the version of the SQL Server we are connected to. - -void get_server_version( _Inout_ sqlsrv_conn* conn, _Outptr_result_buffer_(len) char** server_version, _Out_ SQLSMALLINT& len TSRMLS_DC ) -{ - try { - - sqlsrv_malloc_auto_ptr buffer; - SQLSMALLINT buffer_len = 0; - - buffer = static_cast( sqlsrv_malloc( INFO_BUFFER_LEN )); - core::SQLGetInfo( conn, SQL_DBMS_VER, buffer, INFO_BUFFER_LEN, &buffer_len TSRMLS_CC ); - *server_version = buffer; - len = buffer_len; - buffer.transferred(); - } - - catch( core::CoreException& ) { - throw; - } -} - - // get_processor_arch // Calls GetSystemInfo to verify the what architecture of the processor is supported // and return the string of the processor name. @@ -989,11 +944,11 @@ const char* get_processor_arch( void ) // Exception is thrown when the server version is either undetermined // or is invalid (< 2000). -void determine_server_version( _Inout_ sqlsrv_conn* conn TSRMLS_DC ) +void determine_server_version( _Inout_ sqlsrv_conn* conn ) { SQLSMALLINT info_len; char p[INFO_BUFFER_LEN] = {'\0'}; - core::SQLGetInfo( conn, SQL_DBMS_VER, p, INFO_BUFFER_LEN, &info_len TSRMLS_CC ); + core::SQLGetInfo( conn, SQL_DBMS_VER, p, INFO_BUFFER_LEN, &info_len ); errno = 0; char version_major_str[3] = {'\0'}; @@ -1013,7 +968,7 @@ void determine_server_version( _Inout_ sqlsrv_conn* conn TSRMLS_DC ) conn->server_version = version_major; } -void load_azure_key_vault(_Inout_ sqlsrv_conn* conn TSRMLS_DC) +void load_azure_key_vault(_Inout_ sqlsrv_conn* conn) { // If column encryption is not enabled simply do nothing. Otherwise, check if Azure Key Vault // is required for encryption or decryption. Note, in order to load and configure Azure Key Vault, @@ -1092,11 +1047,10 @@ void configure_azure_key_vault(sqlsrv_conn* conn, BYTE config_attr, const char* core::SQLSetConnectAttr(conn, SQL_COPT_SS_CEKEYSTOREDATA, reinterpret_cast(pData), 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 ) +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 ) { // wrap a connection option in a quote. It is presumed that any character that need to be escaped will // be escaped, such as a closing }. - TSRMLS_C; if( val_len > 0 && val[0] == '{' && val[val_len - 1] == '}' ) { ++val; @@ -1111,26 +1065,25 @@ void common_conn_str_append_func( _In_z_ const char* odbc_name, _In_reads_(val_l } // namespace // simply add the parsed value to the connection string -void conn_str_append_func::func( _In_ connection_option const* option, _In_ zval* value, sqlsrv_conn* /*conn*/, _Inout_ std::string& conn_str TSRMLS_DC ) +void conn_str_append_func::func( _In_ connection_option const* option, _In_ zval* value, sqlsrv_conn* /*conn*/, _Inout_ std::string& conn_str ) { const char* val_str = Z_STRVAL_P( value ); size_t val_len = Z_STRLEN_P( value ); - common_conn_str_append_func( option->odbc_name, val_str, val_len, conn_str TSRMLS_CC ); + common_conn_str_append_func( option->odbc_name, val_str, val_len, conn_str ); } // do nothing for connection pooling since we handled it earlier when // deciding which environment handle to use. -void conn_null_func::func( connection_option const* /*option*/, zval* /*value*/, sqlsrv_conn* /*conn*/, std::string& /*conn_str*/ TSRMLS_DC ) +void conn_null_func::func( connection_option const* /*option*/, zval* /*value*/, sqlsrv_conn* /*conn*/, std::string& /*conn_str*/ ) { - TSRMLS_C; } -void driver_set_func::func( _In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str TSRMLS_DC ) +void driver_set_func::func( _In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str ) { const char* val_str = Z_STRVAL_P( value ); size_t val_len = Z_STRLEN_P( value ); std::string driver_option( "" ); - common_conn_str_append_func( option->odbc_name, val_str, val_len, driver_option TSRMLS_CC ); + common_conn_str_append_func( option->odbc_name, val_str, val_len, driver_option ); conn->driver_version = ODBC_DRIVER_UNKNOWN; for ( short i = DRIVER_VERSION::FIRST; i <= DRIVER_VERSION::LAST && conn->driver_version == ODBC_DRIVER_UNKNOWN; ++i ) { @@ -1148,7 +1101,7 @@ void driver_set_func::func( _In_ connection_option const* option, _In_ zval* val conn_str += driver_option; } -void column_encryption_set_func::func( _In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str TSRMLS_DC ) +void column_encryption_set_func::func( _In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str ) { convert_to_string( value ); const char* value_str = Z_STRVAL_P( value ); @@ -1168,7 +1121,7 @@ void column_encryption_set_func::func( _In_ connection_option const* option, _In conn_str += ";"; } -void ce_akv_str_set_func::func(_In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str TSRMLS_DC) +void ce_akv_str_set_func::func(_In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str) { SQLSRV_ASSERT(Z_TYPE_P(value) == IS_STRING, "Azure Key Vault keywords accept only strings."); @@ -1254,7 +1207,7 @@ size_t core_str_zval_is_true( _Inout_ zval* value_z ) return 0; // false } -void access_token_set_func::func( _In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str TSRMLS_DC ) +void access_token_set_func::func( _In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str ) { SQLSRV_ASSERT(Z_TYPE_P(value) == IS_STRING, "An access token must be a byte string."); diff --git a/source/shared/core_init.cpp b/source/shared/core_init.cpp index 1d4830780..0cd004076 100644 --- a/source/shared/core_init.cpp +++ b/source/shared/core_init.cpp @@ -3,7 +3,7 @@ // // Contents: common initialization routines shared by PDO and sqlsrv // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -34,7 +34,7 @@ bool isVistaOrGreater; // henv_cp - Environment handle for pooled connection. // henv_ncp - Environment handle for non-pooled connection. // err - Driver specific error handler which handles any errors during initialization. -void core_sqlsrv_minit( _Outptr_ sqlsrv_context** henv_cp, _Inout_ sqlsrv_context** henv_ncp, _In_ error_callback err, _In_z_ const char* driver_func TSRMLS_DC ) +void core_sqlsrv_minit( _Outptr_ sqlsrv_context** henv_cp, _Inout_ sqlsrv_context** henv_ncp, _In_ error_callback err, _In_z_ const char* driver_func ) { SQLSRV_STATIC_ASSERT( sizeof( sqlsrv_sqltype ) == sizeof( zend_long ) ); SQLSRV_STATIC_ASSERT( sizeof( sqlsrv_phptype ) == sizeof( zend_long )); @@ -65,11 +65,11 @@ void core_sqlsrv_minit( _Outptr_ sqlsrv_context** henv_cp, _Inout_ sqlsrv_contex // set to ODBC 3 core::SQLSetEnvAttr( **henv_ncp, SQL_ATTR_ODBC_VERSION, reinterpret_cast( SQL_OV_ODBC3 ), SQL_IS_INTEGER - TSRMLS_CC ); + ); // disable connection pooling core::SQLSetEnvAttr( **henv_ncp, SQL_ATTR_CONNECTION_POOLING, reinterpret_cast( SQL_CP_OFF ), - SQL_IS_UINTEGER TSRMLS_CC ); + SQL_IS_UINTEGER ); // allocate the pooled envrionment handle // we can't use the wrapper in core_sqlsrv.h since we don't have a context on which to base errors, so @@ -83,11 +83,11 @@ void core_sqlsrv_minit( _Outptr_ sqlsrv_context** henv_cp, _Inout_ sqlsrv_contex (*henv_cp)->set_func( driver_func ); // set to ODBC 3 - core::SQLSetEnvAttr( **henv_cp, SQL_ATTR_ODBC_VERSION, reinterpret_cast( SQL_OV_ODBC3 ), SQL_IS_INTEGER TSRMLS_CC); + core::SQLSetEnvAttr( **henv_cp, SQL_ATTR_ODBC_VERSION, reinterpret_cast( SQL_OV_ODBC3 ), SQL_IS_INTEGER); // enable connection pooling core:: SQLSetEnvAttr( **henv_cp, SQL_ATTR_CONNECTION_POOLING, reinterpret_cast( SQL_CP_ONE_PER_HENV ), - SQL_IS_UINTEGER TSRMLS_CC ); + SQL_IS_UINTEGER ); } catch( core::CoreException& e ) { diff --git a/source/shared/core_results.cpp b/source/shared/core_results.cpp index afa3bf56e..d7a59ac1b 100644 --- a/source/shared/core_results.cpp +++ b/source/shared/core_results.cpp @@ -3,7 +3,7 @@ // // Contents: Result sets // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -78,7 +78,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 TSRMLS_DC ); + _In_ zend_long mem_used ); // dtor for each row in the cache void cache_row_dtor( _In_ zval* data ); @@ -262,64 +262,6 @@ std::string getUTF8StringFromString( _In_z_ const char* source ) #endif // !_WIN32 -template -SQLRETURN string_to_number( _In_z_ Char* string_data, SQLLEN str_len, _Out_writes_bytes_(*out_buffer_length) void* buffer, SQLLEN buffer_length, - _Inout_ SQLLEN* out_buffer_length, _Inout_ sqlsrv_error_auto_ptr& last_error ) -{ - Number* number_data = reinterpret_cast( buffer ); -#ifdef _WIN32 - std::locale loc; // default locale should match system - std::basic_istringstream is; - is.str( string_data ); - is.imbue( loc ); - std::ios_base::iostate st = 0; - - std::use_facet< std::num_get< Char > >( loc ).get( std::basic_istream::_Iter( is.rdbuf()), std::basic_istream::_Iter( 0 ), is, st, *number_data ); - - if ( st & std::ios_base::failbit ) { - last_error = new ( sqlsrv_malloc( sizeof( sqlsrv_error ))) sqlsrv_error(( SQLCHAR* ) "22003", ( SQLCHAR* ) "Numeric value out of range", 103 ); - return SQL_ERROR; - } - - *out_buffer_length = sizeof( Number ); -#else - std::string str = getUTF8StringFromString( string_data ); - - std::istringstream is( str ); - std::locale loc; // default locale should match system - is.imbue( loc ); - - auto& facet = std::use_facet>( is.getloc() ); - std::istreambuf_iterator beg( is ), end; - std::ios_base::iostate err = std::ios_base::goodbit; - - if ( std::is_integral::value ) - { - long number; - facet.get( beg, end, is, err, number ); - - *number_data = number; - } - else - { - double number; - facet.get( beg, end, is, err, number ); - - *number_data = number; - } - - *out_buffer_length = sizeof( Number ); - - if ( is.fail() ) - { - last_error = new ( sqlsrv_malloc(sizeof( sqlsrv_error ))) sqlsrv_error(( SQLCHAR* ) "22003", ( SQLCHAR* ) "Numeric value out of range", 103 ); - return SQL_ERROR; - } -#endif // _WIN32 - return SQL_SUCCESS; - -} - // "closure" for the hash table destructor struct row_dtor_closure { @@ -391,27 +333,27 @@ sqlsrv_odbc_result_set::~sqlsrv_odbc_result_set( void ) { } -SQLRETURN sqlsrv_odbc_result_set::fetch( _In_ SQLSMALLINT orientation, _In_ SQLLEN offset TSRMLS_DC ) +SQLRETURN sqlsrv_odbc_result_set::fetch( _In_ SQLSMALLINT orientation, _In_ SQLLEN offset ) { SQLSRV_ASSERT( odbc != NULL, "Invalid statement handle" ); - return core::SQLFetchScroll( odbc, orientation, offset TSRMLS_CC ); + return core::SQLFetchScroll( odbc, orientation, offset ); } SQLRETURN sqlsrv_odbc_result_set::get_data( _In_ SQLUSMALLINT field_index, _In_ SQLSMALLINT target_type, _Out_writes_opt_(buffer_length) SQLPOINTER buffer, _In_ SQLLEN buffer_length, _Inout_ SQLLEN* out_buffer_length, - _In_ bool handle_warning TSRMLS_DC ) + _In_ bool handle_warning ) { SQLSRV_ASSERT( odbc != NULL, "Invalid statement handle" ); - return core::SQLGetData( odbc, field_index, target_type, buffer, buffer_length, out_buffer_length, handle_warning TSRMLS_CC ); + return core::SQLGetData( odbc, field_index, target_type, buffer, buffer_length, out_buffer_length, handle_warning ); } SQLRETURN sqlsrv_odbc_result_set::get_diag_field( _In_ SQLSMALLINT record_number, _In_ SQLSMALLINT diag_identifier, _Inout_updates_(buffer_length) SQLPOINTER diag_info_buffer, _In_ SQLSMALLINT buffer_length, - _Inout_ SQLSMALLINT* out_buffer_length TSRMLS_DC ) + _Inout_ SQLSMALLINT* out_buffer_length ) { SQLSRV_ASSERT( odbc != NULL, "Invalid statement handle" ); return core::SQLGetDiagField( odbc, record_number, diag_identifier, diag_info_buffer, buffer_length, - out_buffer_length TSRMLS_CC ); + out_buffer_length ); } sqlsrv_error* sqlsrv_odbc_result_set::get_diag_rec( _In_ SQLSMALLINT record_number ) @@ -420,17 +362,17 @@ sqlsrv_error* sqlsrv_odbc_result_set::get_diag_rec( _In_ SQLSMALLINT record_numb return odbc_get_diag_rec( odbc, record_number ); } -SQLLEN sqlsrv_odbc_result_set::row_count( TSRMLS_D ) +SQLLEN sqlsrv_odbc_result_set::row_count( void ) { SQLSRV_ASSERT( odbc != NULL, "Invalid statement handle" ); - return core::SQLRowCount( odbc TSRMLS_CC ); + return core::SQLRowCount( odbc ); } // Buffered result set // This class holds a result set in memory -sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) : +sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( _Inout_ sqlsrv_stmt* stmt ) : sqlsrv_result_set( stmt ), cache(NULL), col_count(0), @@ -439,7 +381,7 @@ sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( _Inout_ sqlsrv_stmt* stm read_so_far(0), temp_length(0) { - col_count = core::SQLNumResultCols( stmt TSRMLS_CC ); + col_count = core::SQLNumResultCols( stmt ); // there is no result set to buffer if( col_count == 0 ) { return; @@ -456,7 +398,7 @@ sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( _Inout_ sqlsrv_stmt* stm SQLULEN offset = null_bytes; for( SQLSMALLINT i = 0; i < col_count; ++i ) { - core::SQLDescribeColW( stmt, i + 1, NULL, 0, NULL, &meta[i].type, &meta[i].length, &meta[i].scale, NULL TSRMLS_CC ); + core::SQLDescribeColW( stmt, i + 1, NULL, 0, NULL, &meta[i].type, &meta[i].length, &meta[i].scale, NULL ); offset = align_to( offset ); meta[i].offset = offset; @@ -469,7 +411,7 @@ sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( _Inout_ sqlsrv_stmt* stm case SQL_GUID: case SQL_NUMERIC: core::SQLColAttributeW( stmt, i + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, - reinterpret_cast( &meta[i].length ) TSRMLS_CC ); + reinterpret_cast( &meta[i].length ) ); meta[i].length += sizeof( char ) + sizeof( SQLULEN ); // null terminator space offset += meta[i].length; break; @@ -536,7 +478,7 @@ sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( _Inout_ sqlsrv_stmt* stm case SQL_SS_TIMESTAMPOFFSET: case SQL_TYPE_TIMESTAMP: core::SQLColAttributeW( stmt, i + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, - reinterpret_cast( &meta[i].length ) TSRMLS_CC ); + reinterpret_cast( &meta[i].length ) ); meta[i].length += sizeof(char) + sizeof( SQLULEN ); // null terminator space offset += meta[i].length; break; @@ -628,10 +570,10 @@ sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( _Inout_ sqlsrv_stmt* stm size_t row_count = 0; // 10 is an arbitrary number for now for the initial size of the cache ALLOC_HASHTABLE( cache ); - core::sqlsrv_zend_hash_init( *stmt, cache, 10 /* # of buckets */, cache_row_dtor /*dtor*/, 0 /*persistent*/ TSRMLS_CC ); + core::sqlsrv_zend_hash_init( *stmt, cache, 10 /* # of buckets */, cache_row_dtor /*dtor*/, 0 /*persistent*/ ); try { - while( core::SQLFetchScroll( stmt, SQL_FETCH_NEXT, 0 TSRMLS_CC ) != SQL_NO_DATA ) { + while( core::SQLFetchScroll( stmt, SQL_FETCH_NEXT, 0 ) != SQL_NO_DATA ) { // allocate the row buffer sqlsrv_malloc_auto_ptr rowAuto; @@ -655,7 +597,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 TSRMLS_CC ); + *lob_addr = read_lob_field( stmt, i, meta[i], mem_used ); // a NULL pointer means NULL field if( *lob_addr == NULL ) { *out_buffer_length = SQL_NULL_DATA; @@ -677,7 +619,7 @@ sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( _Inout_ sqlsrv_stmt* stm buffer = row + meta[i].offset + sizeof( SQLULEN ); out_buffer_length = reinterpret_cast( row + meta[i].offset ); core::SQLGetData( stmt, i + 1, meta[i].c_type, buffer, meta[i].length, out_buffer_length, - false TSRMLS_CC ); + false ); } break; @@ -693,7 +635,7 @@ sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( _Inout_ sqlsrv_stmt* stm buffer = row + meta[i].offset; out_buffer_length = &out_buffer_temp; core::SQLGetData( stmt, i + 1, meta[i].c_type, buffer, meta[i].length, out_buffer_length, - false TSRMLS_CC ); + false ); } break; @@ -712,7 +654,7 @@ sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( _Inout_ sqlsrv_stmt* stm // add it to the cache row_dtor_closure cl( this, row ); - sqlsrv_zend_hash_next_index_insert_mem( *stmt, cache, &cl, sizeof(row_dtor_closure) TSRMLS_CC ); + sqlsrv_zend_hash_next_index_insert_mem( *stmt, cache, &cl, sizeof(row_dtor_closure) ); rowAuto.transferred(); } } @@ -738,7 +680,7 @@ sqlsrv_buffered_result_set::~sqlsrv_buffered_result_set( void ) } } -SQLRETURN sqlsrv_buffered_result_set::fetch( _Inout_ SQLSMALLINT orientation, _Inout_opt_ SQLLEN offset TSRMLS_DC ) +SQLRETURN sqlsrv_buffered_result_set::fetch( _Inout_ SQLSMALLINT orientation, _Inout_opt_ SQLLEN offset ) { last_error = NULL; last_field_index = -1; @@ -762,7 +704,7 @@ SQLRETURN sqlsrv_buffered_result_set::fetch( _Inout_ SQLSMALLINT orientation, _I current = 1; break; case SQL_FETCH_LAST: - current = row_count( TSRMLS_C ); + current = row_count(); break; case SQL_FETCH_ABSOLUTE: current = offset; @@ -783,8 +725,8 @@ SQLRETURN sqlsrv_buffered_result_set::fetch( _Inout_ SQLSMALLINT orientation, _I } // the cursor can never get further away than just after the last row - if( current > row_count( TSRMLS_C ) || ( current <= 0 && offset > 0 ) /*overflow condition*/ ) { - current = row_count( TSRMLS_C ) + 1; + if( current > row_count() || ( current <= 0 && offset > 0 ) /*overflow condition*/ ) { + current = row_count() + 1; return SQL_NO_DATA; } @@ -793,7 +735,7 @@ SQLRETURN sqlsrv_buffered_result_set::fetch( _Inout_ SQLSMALLINT orientation, _I SQLRETURN sqlsrv_buffered_result_set::get_data( _In_ SQLUSMALLINT field_index, _In_ SQLSMALLINT target_type, _Out_writes_bytes_opt_(buffer_length) SQLPOINTER buffer, _In_ SQLLEN buffer_length, _Inout_ SQLLEN* out_buffer_length, - bool handle_warning TSRMLS_DC ) + bool handle_warning ) { last_error = NULL; field_index--; // convert from 1 based to 0 based @@ -851,7 +793,6 @@ SQLRETURN sqlsrv_buffered_result_set::get_data( _In_ SQLUSMALLINT field_index, _ case SQL_C_LONG: return sqlsrv_buffered_result_set::to_long(field_index, buffer, buffer_length, out_buffer_length); case SQL_C_BINARY: return sqlsrv_buffered_result_set::to_long(field_index, buffer, buffer_length, out_buffer_length); case SQL_C_CHAR: return sqlsrv_buffered_result_set::long_to_system_string(field_index, buffer, buffer_length, out_buffer_length); - case SQL_C_WCHAR: return sqlsrv_buffered_result_set::long_to_wide_string(field_index, buffer, buffer_length, out_buffer_length); default: break; } @@ -862,7 +803,6 @@ SQLRETURN sqlsrv_buffered_result_set::get_data( _In_ SQLUSMALLINT field_index, _ case SQL_C_BINARY: return sqlsrv_buffered_result_set::to_double(field_index, buffer, buffer_length, out_buffer_length); case SQL_C_CHAR: return sqlsrv_buffered_result_set::double_to_system_string(field_index, buffer, buffer_length, out_buffer_length); case SQL_C_LONG: return sqlsrv_buffered_result_set::double_to_long(field_index, buffer, buffer_length, out_buffer_length); - case SQL_C_WCHAR: return sqlsrv_buffered_result_set::double_to_wide_string(field_index, buffer, buffer_length, out_buffer_length); default: break; } @@ -879,7 +819,7 @@ SQLRETURN sqlsrv_buffered_result_set::get_data( _In_ SQLUSMALLINT field_index, _ SQLRETURN sqlsrv_buffered_result_set::get_diag_field( _In_ SQLSMALLINT record_number, _In_ SQLSMALLINT diag_identifier, _Inout_updates_(buffer_length) SQLPOINTER diag_info_buffer, _In_ SQLSMALLINT buffer_length, - _Inout_ SQLSMALLINT* out_buffer_length TSRMLS_DC ) + _Inout_ SQLSMALLINT* out_buffer_length ) { SQLSRV_ASSERT( record_number == 1, "Only record number 1 can be fetched by sqlsrv_buffered_result_set::get_diag_field" ); SQLSRV_ASSERT( diag_identifier == SQL_DIAG_SQLSTATE, @@ -923,7 +863,7 @@ sqlsrv_error* sqlsrv_buffered_result_set::get_diag_rec( _In_ SQLSMALLINT record_ sqlsrv_error( last_error->sqlstate, last_error->native_message, last_error->native_code ); } -SQLLEN sqlsrv_buffered_result_set::row_count( TSRMLS_D ) +SQLLEN sqlsrv_buffered_result_set::row_count( void ) { last_error = NULL; @@ -1082,23 +1022,6 @@ SQLRETURN sqlsrv_buffered_result_set::double_to_system_string( _In_ SQLSMALLINT return r; } -SQLRETURN sqlsrv_buffered_result_set::double_to_wide_string( _In_ SQLSMALLINT field_index, _Out_writes_bytes_to_opt_(buffer_length, *out_buffer_length) void* buffer, _In_ SQLLEN buffer_length, - _Inout_ SQLLEN* out_buffer_length ) -{ - SQLSRV_ASSERT( meta[field_index].c_type == SQL_C_DOUBLE, "Invalid conversion to wide string" ); - SQLSRV_ASSERT( buffer_length > 0, "Buffer length must be > 0 in sqlsrv_buffered_result_set::double_to_wide_string" ); - - unsigned char* row = get_row(); - double* double_data = reinterpret_cast( &row[meta[field_index].offset] ); - SQLRETURN r = SQL_SUCCESS; -#ifdef _WIN32 - r = number_to_string( double_data, buffer, buffer_length, out_buffer_length, last_error ); -#else - r = number_to_string( double_data, buffer, buffer_length, out_buffer_length, last_error ); -#endif // _WIN32 - return r; -} - SQLRETURN sqlsrv_buffered_result_set::long_to_double( _In_ SQLSMALLINT field_index, _Out_writes_bytes_(*out_buffer_length) void* buffer, _In_ SQLLEN buffer_length, _Out_ SQLLEN* out_buffer_length ) { @@ -1131,23 +1054,6 @@ SQLRETURN sqlsrv_buffered_result_set::long_to_system_string( _In_ SQLSMALLINT fi return r; } -SQLRETURN sqlsrv_buffered_result_set::long_to_wide_string( _In_ SQLSMALLINT field_index, _Out_writes_bytes_to_opt_(buffer_length, *out_buffer_length) void* buffer, _In_ SQLLEN buffer_length, - _Inout_ SQLLEN* out_buffer_length ) -{ - SQLSRV_ASSERT( meta[field_index].c_type == SQL_C_LONG, "Invalid conversion to wide string" ); - SQLSRV_ASSERT( buffer_length > 0, "Buffer length must be > 0 in sqlsrv_buffered_result_set::long_to_wide_string" ); - - unsigned char* row = get_row(); - LONG* long_data = reinterpret_cast( &row[meta[field_index].offset] ); - SQLRETURN r = SQL_SUCCESS; -#ifdef _WIN32 - r = number_to_string( long_data, buffer, buffer_length, out_buffer_length, last_error ); -#else - r = number_to_string( long_data, buffer, buffer_length, out_buffer_length, last_error ); -#endif // _WIN32 - return r; -} - SQLRETURN sqlsrv_buffered_result_set::string_to_double( _In_ SQLSMALLINT field_index, _Out_writes_bytes_(*out_buffer_length) void* buffer, _In_ SQLLEN buffer_length, _Inout_ SQLLEN* out_buffer_length ) { @@ -1157,7 +1063,16 @@ SQLRETURN sqlsrv_buffered_result_set::string_to_double( _In_ SQLSMALLINT field_i unsigned char* row = get_row(); char* string_data = reinterpret_cast( &row[meta[field_index].offset] ) + sizeof( SQLULEN ); - return string_to_number( string_data, meta[field_index].length, buffer, buffer_length, out_buffer_length, last_error ); + double* number_data = reinterpret_cast(buffer); + try { + *number_data = std::stod(std::string(string_data)); + } catch (const std::logic_error& err) { + last_error = new (sqlsrv_malloc(sizeof(sqlsrv_error))) sqlsrv_error((SQLCHAR*) "22003", (SQLCHAR*) "Numeric value out of range", 103); + return SQL_ERROR; + } + + *out_buffer_length = sizeof(double); + return SQL_SUCCESS; } SQLRETURN sqlsrv_buffered_result_set::wstring_to_double( _In_ SQLSMALLINT field_index, _Out_writes_bytes_(*out_buffer_length) void* buffer, _In_ SQLLEN buffer_length, @@ -1169,7 +1084,20 @@ SQLRETURN sqlsrv_buffered_result_set::wstring_to_double( _In_ SQLSMALLINT field_ unsigned char* row = get_row(); SQLWCHAR* string_data = reinterpret_cast( &row[meta[field_index].offset] ) + sizeof( SQLULEN ) / sizeof( SQLWCHAR ); - return string_to_number( string_data, meta[field_index].length, buffer, buffer_length, out_buffer_length, last_error ); + double* number_data = reinterpret_cast(buffer); + try { +#ifdef _WIN32 + *number_data = std::stod(std::wstring(string_data)); +#else + *number_data = std::stod(getUTF8StringFromString(string_data)); +#endif // _WIN32 + } catch (const std::logic_error& err) { + last_error = new (sqlsrv_malloc(sizeof(sqlsrv_error))) sqlsrv_error((SQLCHAR*) "22003", (SQLCHAR*) "Numeric value out of range", 103); + return SQL_ERROR; + } + + *out_buffer_length = sizeof(double); + return SQL_SUCCESS; } SQLRETURN sqlsrv_buffered_result_set::string_to_long( _In_ SQLSMALLINT field_index, _Out_writes_bytes_(*out_buffer_length) void* buffer, _In_ SQLLEN buffer_length, @@ -1181,7 +1109,16 @@ SQLRETURN sqlsrv_buffered_result_set::string_to_long( _In_ SQLSMALLINT field_ind unsigned char* row = get_row(); char* string_data = reinterpret_cast( &row[meta[field_index].offset] ) + sizeof( SQLULEN ); - return string_to_number( string_data, meta[field_index].length, buffer, buffer_length, out_buffer_length, last_error ); + LONG* number_data = reinterpret_cast(buffer); + try { + *number_data = std::stol(std::string(string_data)); + } catch (const std::logic_error& err) { + last_error = new (sqlsrv_malloc(sizeof(sqlsrv_error))) sqlsrv_error((SQLCHAR*) "22003", (SQLCHAR*) "Numeric value out of range", 103); + return SQL_ERROR; + } + + *out_buffer_length = sizeof(LONG); + return SQL_SUCCESS; } SQLRETURN sqlsrv_buffered_result_set::wstring_to_long( _In_ SQLSMALLINT field_index, _Out_writes_bytes_(*out_buffer_length) void* buffer, _In_ SQLLEN buffer_length, @@ -1193,7 +1130,20 @@ SQLRETURN sqlsrv_buffered_result_set::wstring_to_long( _In_ SQLSMALLINT field_in unsigned char* row = get_row(); SQLWCHAR* string_data = reinterpret_cast( &row[meta[field_index].offset] ) + sizeof( SQLULEN ) / sizeof( SQLWCHAR ); - return string_to_number( string_data, meta[field_index].length, buffer, buffer_length, out_buffer_length, last_error ); + LONG* number_data = reinterpret_cast(buffer); + try { +#ifdef _WIN32 + *number_data = std::stol(std::wstring(string_data)); +#else + *number_data = std::stol(getUTF8StringFromString(string_data)); +#endif // _WIN32 + } catch (const std::logic_error& err) { + last_error = new (sqlsrv_malloc(sizeof(sqlsrv_error))) sqlsrv_error((SQLCHAR*) "22003", (SQLCHAR*) "Numeric value out of range", 103); + return SQL_ERROR; + } + + *out_buffer_length = sizeof(LONG); + return SQL_SUCCESS; } SQLRETURN sqlsrv_buffered_result_set::system_to_wide_string( _In_ SQLSMALLINT field_index, _Out_writes_z_(*out_buffer_length) void* buffer, _In_ SQLLEN buffer_length, @@ -1518,7 +1468,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 TSRMLS_DC ) + _In_ zend_long mem_used ) { SQLSMALLINT extra = 0; SQLULEN* output_buffer_len = NULL; @@ -1553,7 +1503,7 @@ SQLPOINTER read_lob_field( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_in output_buffer_len = reinterpret_cast( buffer.get() ); r = core::SQLGetData( stmt, field_index + 1, meta.c_type, buffer.get() + already_read + sizeof( SQLULEN ), - to_read - already_read + extra, &last_field_len, false /*handle_warning*/ TSRMLS_CC ); + to_read - already_read + extra, &last_field_len, false /*handle_warning*/ ); // if the field is NULL, then return a NULL pointer if( last_field_len == SQL_NULL_DATA ) { @@ -1574,7 +1524,7 @@ SQLPOINTER read_lob_field( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_in else if( r == SQL_SUCCESS_WITH_INFO ) { SQLSMALLINT len; core::SQLGetDiagField( stmt, 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len - TSRMLS_CC ); + ); if( !is_truncated_warning( state )) { break; diff --git a/source/shared/core_sqlsrv.h b/source/shared/core_sqlsrv.h index e91b44c51..6907e2c71 100644 --- a/source/shared/core_sqlsrv.h +++ b/source/shared/core_sqlsrv.h @@ -6,7 +6,7 @@ // // Contents: Core routines and constants shared by the Microsoft Drivers for PHP for SQL Server // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -289,16 +289,16 @@ struct sqlsrv_static_assert { _In_ static const int value = 1; }; // log_callback // a driver specific callback for checking if the messages are qualified to be logged: // severity - severity of the message: notice, warning, or error -typedef bool (*severity_callback)(_In_ unsigned int severity TSRMLS_DC); +typedef bool (*severity_callback)(_In_ unsigned int severity); // each driver must register a severity checker callback for logging to work according to the INI settings void core_sqlsrv_register_severity_checker(_In_ severity_callback driver_checker); // a simple wrapper around a PHP error logging function. -void write_to_log( _In_ unsigned int severity TSRMLS_DC, _In_ const char* msg, ... ); +void write_to_log( _In_ unsigned int severity, _In_ const char* msg, ... ); // a macro to make it convenient to use the function. -#define LOG( severity, msg, ...) write_to_log( severity TSRMLS_CC, msg, ## __VA_ARGS__ ) +#define LOG( severity, msg, ...) write_to_log( severity, msg, ## __VA_ARGS__ ) // mask for filtering which severities are written to the log enum logging_severity { @@ -397,7 +397,8 @@ inline void* sqlsrv_malloc( _In_ size_t element_count, _In_ size_t element_size, DIE( "Integer overflow in sqlsrv_malloc" ); } - if( element_size * element_count + extra == 0 ) { + // safeguard against anomalous calculation or any arithmetic overflow + if( element_size * element_count + extra <= 0 ) { DIE( "Allocation size must be more than 0" ); } @@ -776,6 +777,7 @@ struct sqlsrv_error_const { // subclass which is used by the core layer to instantiate ODBC errors struct sqlsrv_error : public sqlsrv_error_const { + struct sqlsrv_error *next; // Only used in pdo_sqlsrv for additional errors (as a linked list) sqlsrv_error( void ) { @@ -783,16 +785,18 @@ struct sqlsrv_error : public sqlsrv_error_const { native_message = NULL; native_code = -1; format = false; + next = NULL; } - sqlsrv_error( _In_ SQLCHAR* sql_state, _In_ SQLCHAR* message, _In_ SQLINTEGER code, _In_ bool printf_format = false ) + sqlsrv_error( _In_ SQLCHAR* sql_state, _In_ SQLCHAR* message, _In_ SQLINTEGER code, _In_ bool printf_format = false) { - sqlstate = reinterpret_cast( sqlsrv_malloc( SQL_SQLSTATE_BUFSIZE )); - native_message = reinterpret_cast( sqlsrv_malloc( SQL_MAX_ERROR_MESSAGE_LENGTH + 1 )); - strcpy_s( reinterpret_cast( sqlstate ), SQL_SQLSTATE_BUFSIZE, reinterpret_cast( sql_state )); - strcpy_s( reinterpret_cast( native_message ), SQL_MAX_ERROR_MESSAGE_LENGTH + 1, reinterpret_cast( message )); + sqlstate = reinterpret_cast(sqlsrv_malloc(SQL_SQLSTATE_BUFSIZE)); + native_message = reinterpret_cast(sqlsrv_malloc(SQL_MAX_ERROR_MESSAGE_LENGTH + 1)); + strcpy_s(reinterpret_cast(sqlstate), SQL_SQLSTATE_BUFSIZE, reinterpret_cast(sql_state)); + strcpy_s(reinterpret_cast(native_message), SQL_MAX_ERROR_MESSAGE_LENGTH + 1, reinterpret_cast(message)); native_code = code; format = printf_format; + next = NULL; } sqlsrv_error( _In_ sqlsrv_error_const const& prototype ) @@ -802,16 +806,26 @@ struct sqlsrv_error : public sqlsrv_error_const { ~sqlsrv_error( void ) { - if( sqlstate != NULL ) { - sqlsrv_free( sqlstate ); + reset(); + } + + void reset() { + if (sqlstate != NULL) { + sqlsrv_free(sqlstate); + sqlstate = NULL; } - if( native_message != NULL ) { - sqlsrv_free( native_message ); + if (native_message != NULL) { + sqlsrv_free(native_message); + native_message = NULL; + } + if (next != NULL) { + next->reset(); // free the next sqlsrv_error, and so on + sqlsrv_free(next); + next = NULL; } } }; - // an auto_ptr for sqlsrv_errors. These call the destructor explicitly rather than call delete class sqlsrv_error_auto_ptr : public sqlsrv_auto_ptr { @@ -852,7 +866,6 @@ class sqlsrv_error_auto_ptr : public sqlsrv_auto_ptr azure_ad_access_token; // initialize with default values - sqlsrv_conn( _In_ SQLHANDLE h, _In_ error_callback e, _In_opt_ void* drv, _In_ SQLSRV_ENCODING encoding TSRMLS_DC ) : + sqlsrv_conn( _In_ SQLHANDLE h, _In_ error_callback e, _In_opt_ void* drv, _In_ SQLSRV_ENCODING encoding ) : sqlsrv_context( h, SQL_HANDLE_DBC, e, drv, encoding ) { server_version = SERVER_VERSION_UNKNOWN; @@ -1225,54 +1238,54 @@ struct connection_option { // process the connection type // return whether or not the function was successful in processing the connection option - void (*func)( connection_option const*, zval* value, sqlsrv_conn* conn, std::string& conn_str TSRMLS_DC ); + void (*func)( connection_option const*, zval* value, sqlsrv_conn* conn, std::string& conn_str ); }; // connection attribute functions // simply add the parsed value to the connection string struct conn_str_append_func { - static void func( _In_ connection_option const* option, _In_ zval* value, sqlsrv_conn* /*conn*/, _Inout_ std::string& conn_str TSRMLS_DC ); + static void func( _In_ connection_option const* option, _In_ zval* value, sqlsrv_conn* /*conn*/, _Inout_ std::string& conn_str ); }; struct conn_null_func { - static void func( connection_option const* /*option*/, zval* /*value*/, sqlsrv_conn* /*conn*/, std::string& /*conn_str*/ TSRMLS_DC ); + static void func( connection_option const* /*option*/, zval* /*value*/, sqlsrv_conn* /*conn*/, std::string& /*conn_str*/ ); }; struct column_encryption_set_func { - static void func( _In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str TSRMLS_DC ); + static void func( _In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str ); }; struct driver_set_func { - static void func( _In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str TSRMLS_DC ); + static void func( _In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str ); }; struct ce_akv_str_set_func { - static void func( _In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str TSRMLS_DC ); + static void func( _In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str ); }; struct access_token_set_func { - static void func( _In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str TSRMLS_DC ); + static void func( _In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str ); }; // factory to create a connection (since they are subclassed to instantiate statements) -typedef sqlsrv_conn* (*driver_conn_factory)( _In_ SQLHANDLE h, _In_ error_callback e, _In_ void* drv TSRMLS_DC ); +typedef sqlsrv_conn* (*driver_conn_factory)( _In_ SQLHANDLE h, _In_ error_callback e, _In_ void* drv ); // *** connection functions *** sqlsrv_conn* core_sqlsrv_connect( _In_ sqlsrv_context& henv_cp, _In_ sqlsrv_context& henv_ncp, _In_ driver_conn_factory conn_factory, _Inout_z_ const char* server, _Inout_opt_z_ const char* uid, _Inout_opt_z_ const char* pwd, _Inout_opt_ HashTable* options_ht, _In_ error_callback err, _In_ const connection_option valid_conn_opts[], - _In_ void* driver, _In_z_ const char* driver_func TSRMLS_DC ); + _In_ void* driver, _In_z_ const char* driver_func ); SQLRETURN core_odbc_connect( _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str, _In_ bool is_pooled ); -void core_sqlsrv_close( _Inout_opt_ sqlsrv_conn* conn TSRMLS_DC ); -void core_sqlsrv_prepare( _Inout_ sqlsrv_stmt* stmt, _In_reads_bytes_(sql_len) const char* sql, _In_ SQLLEN sql_len TSRMLS_DC ); -void core_sqlsrv_begin_transaction( _Inout_ sqlsrv_conn* conn TSRMLS_DC ); -void core_sqlsrv_commit( _Inout_ sqlsrv_conn* conn TSRMLS_DC ); -void core_sqlsrv_rollback( _Inout_ sqlsrv_conn* conn TSRMLS_DC ); -void core_sqlsrv_get_server_info( _Inout_ sqlsrv_conn* conn, _Out_ zval* server_info TSRMLS_DC ); -void core_sqlsrv_get_server_version( _Inout_ sqlsrv_conn* conn, _Inout_ zval *server_version TSRMLS_DC ); -void core_sqlsrv_get_client_info( _Inout_ sqlsrv_conn* conn, _Out_ zval *client_info TSRMLS_DC ); +void core_sqlsrv_close( _Inout_opt_ sqlsrv_conn* conn ); +void core_sqlsrv_prepare( _Inout_ sqlsrv_stmt* stmt, _In_reads_bytes_(sql_len) const char* sql, _In_ SQLLEN sql_len ); +void core_sqlsrv_begin_transaction( _Inout_ sqlsrv_conn* conn ); +void core_sqlsrv_commit( _Inout_ sqlsrv_conn* conn ); +void core_sqlsrv_rollback( _Inout_ sqlsrv_conn* conn ); +void core_sqlsrv_get_server_info( _Inout_ sqlsrv_conn* conn, _Out_ zval* server_info ); +void core_sqlsrv_get_server_version( _Inout_ sqlsrv_conn* conn, _Inout_ zval *server_version ); +void core_sqlsrv_get_client_info( _Inout_ sqlsrv_conn* conn, _Out_ zval *client_info ); bool core_is_conn_opt_value_escaped( _Inout_ const char* value, _Inout_ size_t value_len ); size_t core_str_zval_is_true( _Inout_ zval* str_zval ); bool core_is_authentication_option_valid( _In_z_ const char* value, _In_ size_t value_len ); @@ -1285,42 +1298,42 @@ bool core_compare_error_state( _In_ sqlsrv_conn* conn, _In_ SQLRETURN r, _In_ c struct stmt_option_functor { - virtual void operator()( _Inout_ sqlsrv_stmt* /*stmt*/, stmt_option const* /*opt*/, _In_ zval* /*value_z*/ TSRMLS_DC ); + virtual void operator()( _Inout_ sqlsrv_stmt* /*stmt*/, stmt_option const* /*opt*/, _In_ zval* /*value_z*/ ); }; struct stmt_option_query_timeout : public stmt_option_functor { - virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* opt, _In_ zval* value_z TSRMLS_DC ); + virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* opt, _In_ zval* value_z ); }; struct stmt_option_send_at_exec : public stmt_option_functor { - virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* opt, _In_ zval* value_z TSRMLS_DC ); + virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* opt, _In_ zval* value_z ); }; struct stmt_option_buffered_query_limit : public stmt_option_functor { - virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* opt, _In_ zval* value_z TSRMLS_DC ); + virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* opt, _In_ zval* value_z ); }; struct stmt_option_date_as_string : public stmt_option_functor { - virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* opt, _In_ zval* value_z TSRMLS_DC ); + virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* opt, _In_ zval* value_z ); }; struct stmt_option_format_decimals : public stmt_option_functor { - virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* opt, _In_ zval* value_z TSRMLS_DC ); + virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* opt, _In_ zval* value_z ); }; struct stmt_option_decimal_places : public stmt_option_functor { - virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* opt, _In_ zval* value_z TSRMLS_DC ); + virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* opt, _In_ zval* value_z ); }; struct stmt_option_data_classification : public stmt_option_functor { - virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* opt, _In_ zval* value_z TSRMLS_DC ); + virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* opt, _In_ zval* value_z ); }; // used to hold the table for statment options @@ -1353,7 +1366,7 @@ struct sqlsrv_stream { }; // close any active stream -void close_active_stream( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ); +void close_active_stream( _Inout_ sqlsrv_stmt* stmt ); extern php_stream_wrapper g_sqlsrv_stream_wrapper; @@ -1427,14 +1440,16 @@ struct sqlsrv_output_param { }; namespace data_classification { + const int VERSION_RANK_AVAILABLE = 2; // Rank info is available when data classification version is 2+ + const int RANK_NOT_DEFINED = -1; // *** data classficiation metadata structures and helper methods -- to store and/or process the sensitivity classification data *** struct name_id_pair; struct sensitivity_metadata; void name_id_pair_free(name_id_pair * pair); - void parse_sensitivity_name_id_pairs(_Inout_ sqlsrv_stmt* stmt, _Inout_ USHORT& numpairs, _Inout_ std::vector>* pairs, _Inout_ unsigned char **pptr TSRMLS_CC); - void parse_column_sensitivity_props(_Inout_ sensitivity_metadata* meta, _Inout_ unsigned char **pptr); - USHORT fill_column_sensitivity_array(_Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT colno, _Inout_ zval *column_data TSRMLS_CC); + void parse_sensitivity_name_id_pairs(_Inout_ sqlsrv_stmt* stmt, _Inout_ USHORT& numpairs, _Inout_ std::vector>* pairs, _Inout_ unsigned char **pptr); + void parse_column_sensitivity_props(_Inout_ sensitivity_metadata* meta, _Inout_ unsigned char **pptr, _In_ bool getRankInfo); + USHORT fill_column_sensitivity_array(_Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT colno, _Inout_ zval *column_data); struct name_id_pair { UCHAR name_len; @@ -1454,8 +1469,9 @@ namespace data_classification { struct label_infotype_pair { USHORT label_idx; USHORT infotype_idx; + int rank; // Default value is "not defined" - label_infotype_pair() : label_idx(0), infotype_idx(0) + label_infotype_pair() : label_idx(0), infotype_idx(0), rank(RANK_NOT_DEFINED) { } }; @@ -1481,8 +1497,9 @@ namespace data_classification { std::vector> infotypes; USHORT num_columns; std::vector columns_sensitivity; + int rank; // Default value is "not defined" - sensitivity_metadata() : num_labels(0), num_infotypes(0), num_columns(0) + sensitivity_metadata() : num_labels(0), num_infotypes(0), num_columns(0), rank(RANK_NOT_DEFINED) { } @@ -1502,11 +1519,13 @@ struct field_meta_data; // *** Statement resource structure *** struct sqlsrv_stmt : public sqlsrv_context { - void free_param_data( TSRMLS_D ); - virtual void new_result_set( TSRMLS_D ); + void free_param_data( void ); + virtual void new_result_set( void ); // free sensitivity classification metadata void clean_up_sensitivity_metadata(); + // set query timeout + void set_query_timeout(); sqlsrv_conn* conn; // Connection that created this statement @@ -1551,14 +1570,13 @@ struct sqlsrv_stmt : public sqlsrv_context { // meta data for data classification sqlsrv_malloc_auto_ptr current_sensitivity_metadata; - sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error_callback e, _In_opt_ void* drv TSRMLS_DC ); + sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error_callback e, _In_opt_ void* drv ); + virtual ~sqlsrv_stmt( void ); // driver specific conversion rules from a SQL Server/ODBC type to one of the SQLSRV_PHPTYPE_* constants virtual sqlsrv_phptype sql_type_to_php_type( _In_ SQLINTEGER sql_type, _In_ SQLUINTEGER size, _In_ bool prefer_string_to_stream ) = 0; - // driver specific way to set query timeout - virtual void set_query_timeout() = 0; }; // *** field metadata struct *** @@ -1607,31 +1625,31 @@ const size_t SQLSRV_CURSOR_BUFFERED = 0xfffffffeUL; // arbitrary number that doe #endif // !_WIN32 // factory to create a statement -typedef sqlsrv_stmt* (*driver_stmt_factory)( sqlsrv_conn* conn, SQLHANDLE h, error_callback e, void* drv TSRMLS_DC ); +typedef sqlsrv_stmt* (*driver_stmt_factory)( sqlsrv_conn* conn, SQLHANDLE h, error_callback e, void* drv ); // *** statement functions *** sqlsrv_stmt* core_sqlsrv_create_stmt( _Inout_ sqlsrv_conn* conn, _In_ driver_stmt_factory stmt_factory, _In_opt_ HashTable* options_ht, - _In_opt_ const stmt_option valid_stmt_opts[], _In_ error_callback const err, _In_opt_ void* driver TSRMLS_DC ); + _In_opt_ const stmt_option valid_stmt_opts[], _In_ error_callback const err, _In_opt_ void* driver ); void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_num, _In_ SQLSMALLINT direction, _Inout_ zval* param_z, _In_ SQLSRV_PHPTYPE php_out_type, _Inout_ SQLSRV_ENCODING encoding, _Inout_ SQLSMALLINT sql_type, _Inout_ SQLULEN column_size, - _Inout_ SQLSMALLINT decimal_digits TSRMLS_DC ); -SQLRETURN core_sqlsrv_execute( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC, _In_reads_bytes_(sql_len) const char* sql = NULL, _In_ int sql_len = 0 ); -field_meta_data* core_sqlsrv_field_metadata( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT colno TSRMLS_DC ); -bool core_sqlsrv_fetch( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orientation, _In_ SQLULEN fetch_offset TSRMLS_DC ); + _Inout_ SQLSMALLINT decimal_digits ); +SQLRETURN core_sqlsrv_execute( _Inout_ sqlsrv_stmt* stmt, _In_reads_bytes_(sql_len) const char* sql = NULL, _In_ int sql_len = 0 ); +field_meta_data* core_sqlsrv_field_metadata( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT colno ); +bool core_sqlsrv_fetch( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orientation, _In_ SQLULEN fetch_offset ); void core_sqlsrv_get_field( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, _In_ sqlsrv_phptype sqlsrv_phptype, _In_ bool prefer_string, - _Outref_result_bytebuffer_maybenull_(*field_length) void*& field_value, _Inout_ SQLLEN* field_length, _In_ bool cache_field, - _Out_ SQLSRV_PHPTYPE *sqlsrv_php_type_out TSRMLS_DC); -bool core_sqlsrv_has_any_result( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ); -void core_sqlsrv_next_result( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC, _In_ bool finalize_output_params = true, _In_ bool throw_on_errors = true ); -void core_sqlsrv_post_param( _Inout_ sqlsrv_stmt* stmt, _In_ zend_ulong paramno, zval* param_z TSRMLS_DC ); -void core_sqlsrv_set_scrollable( _Inout_ sqlsrv_stmt* stmt, _In_ unsigned long cursor_type TSRMLS_DC ); -void core_sqlsrv_set_query_timeout( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval* value_z TSRMLS_DC ); -void core_sqlsrv_set_send_at_exec( _Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z TSRMLS_DC ); -bool core_sqlsrv_send_stream_packet( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ); -void core_sqlsrv_set_buffered_query_limit( _Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z TSRMLS_DC ); -void core_sqlsrv_set_buffered_query_limit( _Inout_ sqlsrv_stmt* stmt, _In_ SQLLEN limit TSRMLS_DC ); -void core_sqlsrv_set_decimal_places(_Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z TSRMLS_DC); -void core_sqlsrv_sensitivity_metadata( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ); + _Outref_result_bytebuffer_maybenull_(*field_length) void*& field_value, _Inout_ SQLLEN* field_length, _In_ bool cache_field, + _Out_ SQLSRV_PHPTYPE *sqlsrv_php_type_out); +bool core_sqlsrv_has_any_result( _Inout_ sqlsrv_stmt* stmt ); +void core_sqlsrv_next_result( _Inout_ sqlsrv_stmt* stmt, _In_ bool finalize_output_params = true, _In_ bool throw_on_errors = true ); +void core_sqlsrv_post_param( _Inout_ sqlsrv_stmt* stmt, _In_ zend_ulong paramno, zval* param_z ); +void core_sqlsrv_set_scrollable( _Inout_ sqlsrv_stmt* stmt, _In_ unsigned long cursor_type ); +void core_sqlsrv_set_query_timeout( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval* value_z ); +void core_sqlsrv_set_send_at_exec( _Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z ); +bool core_sqlsrv_send_stream_packet( _Inout_ sqlsrv_stmt* stmt ); +void core_sqlsrv_set_buffered_query_limit( _Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z ); +void core_sqlsrv_set_buffered_query_limit( _Inout_ sqlsrv_stmt* stmt, _In_ SQLLEN limit ); +void core_sqlsrv_set_decimal_places(_Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z); +void core_sqlsrv_sensitivity_metadata( _Inout_ sqlsrv_stmt* stmt ); //********************************************************************************************************************************* // Result Set @@ -1652,15 +1670,15 @@ struct sqlsrv_result_set { virtual ~sqlsrv_result_set( void ) { } virtual bool cached( int field_index ) = 0; - virtual SQLRETURN fetch( _Inout_ SQLSMALLINT fetch_orientation, _Inout_opt_ SQLLEN fetch_offset TSRMLS_DC ) = 0; + virtual SQLRETURN fetch( _Inout_ SQLSMALLINT fetch_orientation, _Inout_opt_ SQLLEN fetch_offset ) = 0; virtual SQLRETURN get_data( _In_ SQLUSMALLINT field_index, _In_ SQLSMALLINT target_type, _Out_writes_bytes_opt_(buffer_length) void* buffer, _In_ SQLLEN buffer_length, _Inout_ SQLLEN* out_buffer_length, - bool handle_warning TSRMLS_DC )= 0; + bool handle_warning )= 0; virtual SQLRETURN get_diag_field( _In_ SQLSMALLINT record_number, _In_ SQLSMALLINT diag_identifier, _Inout_updates_(buffer_length) SQLPOINTER diag_info_buffer, _In_ SQLSMALLINT buffer_length, - _Inout_ SQLSMALLINT* out_buffer_length TSRMLS_DC ) = 0; + _Inout_ SQLSMALLINT* out_buffer_length ) = 0; virtual sqlsrv_error* get_diag_rec( _In_ SQLSMALLINT record_number ) = 0; - virtual SQLLEN row_count( TSRMLS_D ) = 0; + virtual SQLLEN row_count( void ) = 0; }; struct sqlsrv_odbc_result_set : public sqlsrv_result_set { @@ -1669,15 +1687,15 @@ struct sqlsrv_odbc_result_set : public sqlsrv_result_set { virtual ~sqlsrv_odbc_result_set( void ); virtual bool cached( int field_index ) { return false; } - virtual SQLRETURN fetch( _In_ SQLSMALLINT fetch_orientation, _In_ SQLLEN fetch_offset TSRMLS_DC ); + virtual SQLRETURN fetch( _In_ SQLSMALLINT fetch_orientation, _In_ SQLLEN fetch_offset ); virtual SQLRETURN get_data( _In_ SQLUSMALLINT field_index, _In_ SQLSMALLINT target_type, _Out_writes_opt_(buffer_length) void* buffer, _In_ SQLLEN buffer_length, _Inout_ SQLLEN* out_buffer_length, - _In_ bool handle_warning TSRMLS_DC ); + _In_ bool handle_warning ); virtual SQLRETURN get_diag_field( _In_ SQLSMALLINT record_number, _In_ SQLSMALLINT diag_identifier, _Inout_updates_(buffer_length) SQLPOINTER diag_info_buffer, _In_ SQLSMALLINT buffer_length, - _Inout_ SQLSMALLINT* out_buffer_length TSRMLS_DC ); + _Inout_ SQLSMALLINT* out_buffer_length ); virtual sqlsrv_error* get_diag_rec( _In_ SQLSMALLINT record_number ); - virtual SQLLEN row_count( TSRMLS_D ); + virtual SQLLEN row_count( void ); private: // prevent invalid instantiations and assignments @@ -1703,19 +1721,19 @@ struct sqlsrv_buffered_result_set : public sqlsrv_result_set { static const zend_long BUFFERED_QUERY_LIMIT_DEFAULT = 10240; // measured in KB static const zend_long BUFFERED_QUERY_LIMIT_INVALID = 0; - explicit sqlsrv_buffered_result_set( _Inout_ sqlsrv_stmt* odbc TSRMLS_DC ); + explicit sqlsrv_buffered_result_set( _Inout_ sqlsrv_stmt* odbc ); virtual ~sqlsrv_buffered_result_set( void ); virtual bool cached( int field_index ) { return true; } - virtual SQLRETURN fetch( _Inout_ SQLSMALLINT fetch_orientation, _Inout_opt_ SQLLEN fetch_offset TSRMLS_DC ); + virtual SQLRETURN fetch( _Inout_ SQLSMALLINT fetch_orientation, _Inout_opt_ SQLLEN fetch_offset ); virtual SQLRETURN get_data( _In_ SQLUSMALLINT field_index, _In_ SQLSMALLINT target_type, _Out_writes_bytes_opt_(buffer_length) void* buffer, _In_ SQLLEN buffer_length, _Inout_ SQLLEN* out_buffer_length, - bool handle_warning TSRMLS_DC ); + bool handle_warning ); virtual SQLRETURN get_diag_field( _In_ SQLSMALLINT record_number, _In_ SQLSMALLINT diag_identifier, _Inout_updates_(buffer_length) SQLPOINTER diag_info_buffer, _In_ SQLSMALLINT buffer_length, - _Inout_ SQLSMALLINT* out_buffer_length TSRMLS_DC ); + _Inout_ SQLSMALLINT* out_buffer_length ); virtual sqlsrv_error* get_diag_rec( _In_ SQLSMALLINT record_number ); - virtual SQLLEN row_count( TSRMLS_D ); + virtual SQLLEN row_count( void ); // buffered result set specific SQLSMALLINT column_count( void ) @@ -1900,12 +1918,11 @@ enum error_handling_flags { // 3/message) driver specific error message // The fetch type determines if the indices are numeric, associative, or both. bool core_sqlsrv_get_odbc_error( _Inout_ sqlsrv_context& ctx, _In_ int record_number, _Inout_ sqlsrv_error_auto_ptr& error, - _In_ logging_severity severity TSRMLS_DC ); + _In_ logging_severity severity, _In_opt_ bool check_warning = false ); // format and return a driver specfic error void core_sqlsrv_format_driver_error( _In_ sqlsrv_context& ctx, _In_ sqlsrv_error_const const* custom_error, - _Out_ sqlsrv_error_auto_ptr& formatted_error, _In_ logging_severity severity TSRMLS_DC, _In_opt_ va_list* args ); - + _Out_ sqlsrv_error_auto_ptr& formatted_error, _In_ logging_severity severity, _In_opt_ va_list* args ); // return the message for the HRESULT returned by GetLastError. Some driver errors use this to // return the Windows error, e.g, when a UTF-8 <-> UTF-16 conversion fails. @@ -1916,20 +1933,20 @@ DWORD core_sqlsrv_format_message( _Out_ char* output_buffer, _In_ unsigned outpu // convenience functions that overload either a reference or a pointer so we can use // either in the CHECK_* functions. -inline bool call_error_handler( _Inout_ sqlsrv_context& ctx, _In_ unsigned long sqlsrv_error_code TSRMLS_DC, _In_ bool warning, ... ) +inline bool call_error_handler( _Inout_ sqlsrv_context& ctx, _In_ unsigned long sqlsrv_error_code, _In_ bool warning, ... ) { va_list print_params; va_start( print_params, warning ); - bool ignored = ctx.error_handler()( ctx, sqlsrv_error_code, warning TSRMLS_CC, &print_params ); + bool ignored = ctx.error_handler()( ctx, sqlsrv_error_code, warning, &print_params ); va_end( print_params ); return ignored; } -inline bool call_error_handler( _Inout_ sqlsrv_context* ctx, _In_ unsigned long sqlsrv_error_code TSRMLS_DC, _In_ bool warning, ... ) +inline bool call_error_handler( _Inout_ sqlsrv_context* ctx, _In_ unsigned long sqlsrv_error_code, _In_ bool warning, ... ) { va_list print_params; va_start( print_params, warning ); - bool ignored = ctx->error_handler()( *ctx, sqlsrv_error_code, warning TSRMLS_CC, &print_params ); + bool ignored = ctx->error_handler()( *ctx, sqlsrv_error_code, warning, &print_params ); va_end( print_params ); return ignored; } @@ -1970,7 +1987,7 @@ inline bool is_truncated_warning( _In_ SQLCHAR* state ) bool flag##unique = (condition); \ bool ignored##unique = true; \ if (flag##unique) { \ - ignored##unique = call_error_handler( context, ssphp TSRMLS_CC, /*warning*/false, ## __VA_ARGS__ ); \ + ignored##unique = call_error_handler( context, ssphp, /*warning*/false, ## __VA_ARGS__ ); \ } \ if( !ignored##unique ) @@ -1990,7 +2007,7 @@ inline bool is_truncated_warning( _In_ SQLCHAR* state ) #define CHECK_WARNING_AS_ERROR_UNIQUE( unique, condition, context, ssphp, ... ) \ bool ignored##unique = true; \ if( condition ) { \ - ignored##unique = call_error_handler( context, ssphp TSRMLS_CC, /*warning*/true, ## __VA_ARGS__ ); \ + ignored##unique = call_error_handler( context, ssphp, /*warning*/true, ## __VA_ARGS__ ); \ } \ if( !ignored##unique ) @@ -1999,7 +2016,7 @@ inline bool is_truncated_warning( _In_ SQLCHAR* state ) #define CHECK_SQL_WARNING( result, context, ... ) \ if( result == SQL_SUCCESS_WITH_INFO ) { \ - (void)call_error_handler( context, 0 TSRMLS_CC, /*warning*/ true, ## __VA_ARGS__ ); \ + (void)call_error_handler( context, 0, /*warning*/ true, ## __VA_ARGS__ ); \ } #define CHECK_CUSTOM_WARNING_AS_ERROR( condition, context, ssphp, ... ) \ @@ -2012,16 +2029,16 @@ inline bool is_truncated_warning( _In_ SQLCHAR* state ) SQLSRV_ASSERT( result != SQL_INVALID_HANDLE, "Invalid handle returned." ); \ bool ignored = true; \ if( result == SQL_ERROR ) { \ - ignored = call_error_handler( context, SQLSRV_ERROR_ODBC TSRMLS_CC, false, ##__VA_ARGS__ ); \ + ignored = call_error_handler( context, SQLSRV_ERROR_ODBC, false, ##__VA_ARGS__ ); \ } \ else if( result == SQL_SUCCESS_WITH_INFO ) { \ - ignored = call_error_handler( context, SQLSRV_ERROR_ODBC TSRMLS_CC, true TSRMLS_CC, ##__VA_ARGS__ ); \ + ignored = call_error_handler( context, SQLSRV_ERROR_ODBC, true, ##__VA_ARGS__ ); \ } \ if( !ignored ) // throw an exception after it has been hooked into the custom error handler #define THROW_CORE_ERROR( ctx, custom, ... ) \ - (void)call_error_handler( ctx, custom TSRMLS_CC, /*warning*/ false, ## __VA_ARGS__ ); \ + (void)call_error_handler( ctx, custom, /*warning*/ false, ## __VA_ARGS__ ); \ throw core::CoreException(); //********************************************************************************************************************************* @@ -2038,7 +2055,7 @@ namespace core { } }; - inline void check_for_mars_error( _Inout_ sqlsrv_stmt* stmt, _In_ SQLRETURN r TSRMLS_DC ) + inline void check_for_mars_error( _Inout_ sqlsrv_stmt* stmt, _In_ SQLRETURN r ) { // Skip this if not SQL_ERROR - // We check for the 'connection busy' error caused by having MultipleActiveResultSets off @@ -2083,7 +2100,7 @@ namespace core { inline SQLRETURN SQLGetDiagField( _Inout_ sqlsrv_context* ctx, _In_ SQLSMALLINT record_number, _In_ SQLSMALLINT diag_identifier, _Out_writes_opt_(buffer_length) SQLPOINTER diag_info_buffer, _In_ SQLSMALLINT buffer_length, - _Out_opt_ SQLSMALLINT* out_buffer_length TSRMLS_DC ) + _Out_opt_ SQLSMALLINT* out_buffer_length ) { SQLRETURN r = ::SQLGetDiagField( ctx->handle_type(), ctx->handle(), record_number, diag_identifier, diag_info_buffer, buffer_length, out_buffer_length ); @@ -2096,7 +2113,7 @@ namespace core { } inline void SQLAllocHandle( _In_ SQLSMALLINT HandleType, _Inout_ sqlsrv_context& InputHandle, - _Out_ SQLHANDLE* OutputHandlePtr TSRMLS_DC ) + _Out_ SQLHANDLE* OutputHandlePtr ) { SQLRETURN r; r = ::SQLAllocHandle( HandleType, InputHandle.handle(), OutputHandlePtr ); @@ -2115,7 +2132,7 @@ namespace core { _Inout_opt_ SQLPOINTER ParameterValuePtr, _Inout_ SQLLEN BufferLength, _Inout_ SQLLEN * StrLen_Or_IndPtr - TSRMLS_DC ) + ) { SQLRETURN r; r = ::SQLBindParameter( stmt->handle(), ParameterNumber, InputOutputType, ValueType, ParameterType, ColumnSize, @@ -2126,7 +2143,7 @@ namespace core { } } - inline void SQLCloseCursor( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) + inline void SQLCloseCursor( _Inout_ sqlsrv_stmt* stmt ) { SQLRETURN r = ::SQLCloseCursor( stmt->handle() ); @@ -2137,7 +2154,7 @@ namespace core { inline void SQLColAttribute( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, _In_ SQLUSMALLINT field_identifier, _Out_writes_bytes_opt_(buffer_length) SQLPOINTER field_type_char, _In_ SQLSMALLINT buffer_length, - _Out_opt_ SQLSMALLINT* out_buffer_length, _Out_opt_ SQLLEN* field_type_num TSRMLS_DC ) + _Out_opt_ SQLSMALLINT* out_buffer_length, _Out_opt_ SQLLEN* field_type_num ) { SQLRETURN r = ::SQLColAttribute( stmt->handle(), field_index, field_identifier, field_type_char, buffer_length, out_buffer_length, field_type_num ); @@ -2149,7 +2166,7 @@ namespace core { inline void SQLColAttributeW( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, _In_ SQLUSMALLINT field_identifier, _Out_writes_bytes_opt_(buffer_length) SQLPOINTER field_type_char, _In_ SQLSMALLINT buffer_length, - _Out_opt_ SQLSMALLINT* out_buffer_length, _Out_opt_ SQLLEN* field_type_num TSRMLS_DC ) + _Out_opt_ SQLSMALLINT* out_buffer_length, _Out_opt_ SQLLEN* field_type_num ) { SQLRETURN r = ::SQLColAttributeW( stmt->handle(), field_index, field_identifier, field_type_char, buffer_length, out_buffer_length, field_type_num ); @@ -2161,7 +2178,7 @@ namespace core { inline void SQLDescribeCol( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT colno, _Out_writes_opt_(col_name_length) SQLCHAR* col_name, _In_ SQLSMALLINT col_name_length, _Out_opt_ SQLSMALLINT* col_name_length_out, _Out_opt_ SQLSMALLINT* data_type, _Out_opt_ SQLULEN* col_size, - _Out_opt_ SQLSMALLINT* decimal_digits, _Out_opt_ SQLSMALLINT* nullable TSRMLS_DC ) + _Out_opt_ SQLSMALLINT* decimal_digits, _Out_opt_ SQLSMALLINT* nullable ) { SQLRETURN r; r = ::SQLDescribeCol( stmt->handle(), colno, col_name, col_name_length, col_name_length_out, @@ -2174,7 +2191,7 @@ namespace core { inline void SQLDescribeColW( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT colno, _Out_writes_opt_(col_name_length) SQLWCHAR* col_name, _In_ SQLSMALLINT col_name_length, _Out_opt_ SQLSMALLINT* col_name_length_out, _Out_opt_ SQLSMALLINT* data_type, _Out_opt_ SQLULEN* col_size, - _Out_opt_ SQLSMALLINT* decimal_digits, _Out_opt_ SQLSMALLINT* nullable TSRMLS_DC ) + _Out_opt_ SQLSMALLINT* decimal_digits, _Out_opt_ SQLSMALLINT* nullable ) { SQLRETURN r; r = ::SQLDescribeColW( stmt->handle(), colno, col_name, col_name_length, col_name_length_out, @@ -2186,7 +2203,7 @@ namespace core { } inline void SQLDescribeParam( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT paramno, _Out_opt_ SQLSMALLINT* data_type, _Out_opt_ SQLULEN* col_size, - _Out_opt_ SQLSMALLINT* decimal_digits, _Out_opt_ SQLSMALLINT* nullable TSRMLS_DC ) + _Out_opt_ SQLSMALLINT* decimal_digits, _Out_opt_ SQLSMALLINT* nullable ) { SQLRETURN r; r = ::SQLDescribeParam( stmt->handle(), paramno, data_type, col_size, decimal_digits, nullable ); @@ -2206,7 +2223,7 @@ namespace core { } } - inline void SQLEndTran( _In_ SQLSMALLINT handleType, _Inout_ sqlsrv_conn* conn, _In_ SQLSMALLINT completionType TSRMLS_DC ) + inline void SQLEndTran( _In_ SQLSMALLINT handleType, _Inout_ sqlsrv_conn* conn, _In_ SQLSMALLINT completionType ) { SQLRETURN r = ::SQLEndTran( handleType, conn->handle(), completionType ); @@ -2216,11 +2233,11 @@ namespace core { } // SQLExecDirect returns the status code since it returns either SQL_NEED_DATA or SQL_NO_DATA besides just errors/success - inline SQLRETURN SQLExecDirect( _Inout_ sqlsrv_stmt* stmt, _In_ char* sql TSRMLS_DC ) + inline SQLRETURN SQLExecDirect( _Inout_ sqlsrv_stmt* stmt, _In_ char* sql ) { SQLRETURN r = ::SQLExecDirect( stmt->handle(), reinterpret_cast( sql ), SQL_NTS ); - check_for_mars_error( stmt, r TSRMLS_CC ); + check_for_mars_error( stmt, r ); CHECK_SQL_ERROR_OR_WARNING( r, stmt ) { @@ -2229,12 +2246,12 @@ namespace core { return r; } - inline SQLRETURN SQLExecDirectW( _Inout_ sqlsrv_stmt* stmt, _In_ SQLWCHAR* wsql TSRMLS_DC ) + inline SQLRETURN SQLExecDirectW( _Inout_ sqlsrv_stmt* stmt, _In_ SQLWCHAR* wsql ) { SQLRETURN r; r = ::SQLExecDirectW( stmt->handle(), reinterpret_cast( wsql ), SQL_NTS ); - check_for_mars_error( stmt, r TSRMLS_CC ); + check_for_mars_error( stmt, r ); CHECK_SQL_ERROR_OR_WARNING( r, stmt ) { throw CoreException(); @@ -2243,12 +2260,12 @@ namespace core { } // SQLExecute returns the status code since it returns either SQL_NEED_DATA or SQL_NO_DATA besides just errors/success - inline SQLRETURN SQLExecute( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) + inline SQLRETURN SQLExecute( _Inout_ sqlsrv_stmt* stmt ) { SQLRETURN r; r = ::SQLExecute( stmt->handle() ); - check_for_mars_error( stmt, r TSRMLS_CC ); + check_for_mars_error( stmt, r ); CHECK_SQL_ERROR_OR_WARNING( r, stmt ) { throw CoreException(); @@ -2257,7 +2274,7 @@ namespace core { return r; } - inline SQLRETURN SQLFetchScroll( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orientation, _In_ SQLLEN fetch_offset TSRMLS_DC ) + inline SQLRETURN SQLFetchScroll( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orientation, _In_ SQLLEN fetch_offset ) { SQLRETURN r = ::SQLFetchScroll( stmt->handle(), fetch_orientation, fetch_offset ); @@ -2269,14 +2286,14 @@ namespace core { // wrap SQLFreeHandle and report any errors, but don't actually signal an error to the calling routine - inline void SQLFreeHandle( _Inout_ sqlsrv_context& ctx TSRMLS_DC ) + inline void SQLFreeHandle( _Inout_ sqlsrv_context& ctx ) { SQLRETURN r; r = ::SQLFreeHandle( ctx.handle_type(), ctx.handle() ); CHECK_SQL_ERROR_OR_WARNING( r, ctx ) {} } - inline void SQLGetStmtAttr( _Inout_ sqlsrv_stmt* stmt, _In_ SQLINTEGER attr, _Out_writes_opt_(buf_len) void* value_ptr, _In_ SQLINTEGER buf_len, _Out_opt_ SQLINTEGER* str_len TSRMLS_DC) + inline void SQLGetStmtAttr( _Inout_ sqlsrv_stmt* stmt, _In_ SQLINTEGER attr, _Out_writes_opt_(buf_len) void* value_ptr, _In_ SQLINTEGER buf_len, _Out_opt_ SQLINTEGER* str_len) { SQLRETURN r; r = ::SQLGetStmtAttr( stmt->handle(), attr, value_ptr, buf_len, str_len ); @@ -2287,7 +2304,7 @@ namespace core { inline SQLRETURN SQLGetData( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, _In_ SQLSMALLINT target_type, _Out_writes_opt_(buffer_length) void* buffer, _In_ SQLLEN buffer_length, _Out_opt_ SQLLEN* out_buffer_length, - _In_ bool handle_warning TSRMLS_DC ) + _In_ bool handle_warning ) { SQLRETURN r = ::SQLGetData( stmt->handle(), field_index, target_type, buffer, buffer_length, out_buffer_length ); @@ -2309,7 +2326,7 @@ namespace core { inline void SQLGetInfo( _Inout_ sqlsrv_conn* conn, _In_ SQLUSMALLINT info_type, _Out_writes_bytes_opt_(buffer_len) SQLPOINTER info_value, _In_ SQLSMALLINT buffer_len, - _Out_opt_ SQLSMALLINT* str_len TSRMLS_DC ) + _Out_opt_ SQLSMALLINT* str_len ) { SQLRETURN r; r = ::SQLGetInfo( conn->handle(), info_type, info_value, buffer_len, str_len ); @@ -2320,7 +2337,7 @@ namespace core { } - inline void SQLGetTypeInfo( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT data_type TSRMLS_DC ) + inline void SQLGetTypeInfo( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT data_type ) { SQLRETURN r; r = ::SQLGetTypeInfo( stmt->handle(), data_type ); @@ -2332,7 +2349,7 @@ namespace core { // SQLMoreResults returns the status code since it returns SQL_NO_DATA when there is no more data in a result set. - inline SQLRETURN SQLMoreResults( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) + inline SQLRETURN SQLMoreResults( _Inout_ sqlsrv_stmt* stmt ) { SQLRETURN r = ::SQLMoreResults( stmt->handle() ); @@ -2343,7 +2360,7 @@ namespace core { return r; } - inline SQLSMALLINT SQLNumResultCols( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) + inline SQLSMALLINT SQLNumResultCols( _Inout_ sqlsrv_stmt* stmt ) { SQLRETURN r; SQLSMALLINT num_cols; @@ -2358,7 +2375,7 @@ namespace core { // SQLParamData returns the status code since it returns either SQL_NEED_DATA or SQL_NO_DATA when there are more // parameters or when the parameters are all processed. - inline SQLRETURN SQLParamData( _Inout_ sqlsrv_stmt* stmt, _Out_opt_ SQLPOINTER* value_ptr_ptr TSRMLS_DC ) + inline SQLRETURN SQLParamData( _Inout_ sqlsrv_stmt* stmt, _Out_opt_ SQLPOINTER* value_ptr_ptr ) { SQLRETURN r; r = ::SQLParamData( stmt->handle(), value_ptr_ptr ); @@ -2368,7 +2385,7 @@ namespace core { return r; } - inline void SQLPrepareW( _Inout_ sqlsrv_stmt* stmt, _In_reads_(sql_len) SQLWCHAR * sql, _In_ SQLINTEGER sql_len TSRMLS_DC ) + inline void SQLPrepareW( _Inout_ sqlsrv_stmt* stmt, _In_reads_(sql_len) SQLWCHAR * sql, _In_ SQLINTEGER sql_len ) { SQLRETURN r; r = ::SQLPrepareW( stmt->handle(), sql, sql_len ); @@ -2378,7 +2395,7 @@ namespace core { } - inline void SQLPutData( _Inout_ sqlsrv_stmt* stmt, _In_reads_(strlen_or_ind) SQLPOINTER data_ptr, _In_ SQLLEN strlen_or_ind TSRMLS_DC ) + inline void SQLPutData( _Inout_ sqlsrv_stmt* stmt, _In_reads_(strlen_or_ind) SQLPOINTER data_ptr, _In_ SQLLEN strlen_or_ind ) { SQLRETURN r; r = ::SQLPutData( stmt->handle(), data_ptr, strlen_or_ind ); @@ -2388,7 +2405,7 @@ namespace core { } - inline SQLLEN SQLRowCount( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) + inline SQLLEN SQLRowCount( _Inout_ sqlsrv_stmt* stmt ) { SQLRETURN r; SQLLEN rows_affected; @@ -2415,7 +2432,7 @@ namespace core { } - inline void SQLSetConnectAttr( _Inout_ sqlsrv_context& ctx, _In_ SQLINTEGER attr, _In_reads_bytes_opt_(str_len) SQLPOINTER value_ptr, _In_ SQLINTEGER str_len TSRMLS_DC ) + inline void SQLSetConnectAttr( _Inout_ sqlsrv_context& ctx, _In_ SQLINTEGER attr, _In_reads_bytes_opt_(str_len) SQLPOINTER value_ptr, _In_ SQLINTEGER str_len ) { SQLRETURN r; r = ::SQLSetConnectAttr( ctx.handle(), attr, value_ptr, str_len ); @@ -2425,7 +2442,7 @@ namespace core { } } - inline void SQLSetDescField( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT rec_num, _In_ SQLSMALLINT fld_id, _In_reads_bytes_opt_( str_len ) SQLPOINTER value_ptr, _In_ SQLINTEGER str_len TSRMLS_DC ) + inline void SQLSetDescField( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT rec_num, _In_ SQLSMALLINT fld_id, _In_reads_bytes_opt_( str_len ) SQLPOINTER value_ptr, _In_ SQLINTEGER str_len ) { SQLRETURN r; SQLHDESC hIpd = NULL; @@ -2438,7 +2455,7 @@ namespace core { } } - inline void SQLSetEnvAttr( _Inout_ sqlsrv_context& ctx, _In_ SQLINTEGER attr, _In_reads_bytes_opt_(str_len) SQLPOINTER value_ptr, _In_ SQLINTEGER str_len TSRMLS_DC ) + inline void SQLSetEnvAttr( _Inout_ sqlsrv_context& ctx, _In_ SQLINTEGER attr, _In_reads_bytes_opt_(str_len) SQLPOINTER value_ptr, _In_ SQLINTEGER str_len ) { SQLRETURN r; r = ::SQLSetEnvAttr( ctx.handle(), attr, value_ptr, str_len ); @@ -2447,7 +2464,7 @@ namespace core { } } - inline void SQLSetConnectAttr( _Inout_ sqlsrv_conn* conn, _In_ SQLINTEGER attribute, _In_reads_bytes_opt_(value_len) SQLPOINTER value_ptr, _In_ SQLINTEGER value_len TSRMLS_DC ) + inline void SQLSetConnectAttr( _Inout_ sqlsrv_conn* conn, _In_ SQLINTEGER attribute, _In_reads_bytes_opt_(value_len) SQLPOINTER value_ptr, _In_ SQLINTEGER value_len ) { SQLRETURN r = ::SQLSetConnectAttr( conn->handle(), attribute, value_ptr, value_len ); @@ -2456,7 +2473,7 @@ namespace core { } } - inline void SQLSetStmtAttr( _Inout_ sqlsrv_stmt* stmt, _In_ SQLINTEGER attr, _In_reads_(str_len) SQLPOINTER value_ptr, _In_ SQLINTEGER str_len TSRMLS_DC ) + inline void SQLSetStmtAttr( _Inout_ sqlsrv_stmt* stmt, _In_ SQLINTEGER attr, _In_reads_(str_len) SQLPOINTER value_ptr, _In_ SQLINTEGER str_len ) { SQLRETURN r; r = ::SQLSetStmtAttr( stmt->handle(), attr, value_ptr, str_len ); @@ -2485,78 +2502,7 @@ namespace core { } } - - // exception thrown when a zend function wrapped here fails. - - // wrappers for the zend functions called by our driver. These functions hook into the error reporting of our driver and throw - // exceptions when an error occurs. They are prefaced with sqlsrv_ because many of the zend functions are - // actually macros that call other functions, so the sqlsrv_ is necessary to differentiate them from the macro system. - // If there is a zend function in the source that isn't found here, it is because it returns void and there is no error - // that can be thrown from it. - - inline void sqlsrv_add_index_zval( _Inout_ sqlsrv_context& ctx, _Inout_ zval* array, _In_ zend_ulong index, _In_ zval* value TSRMLS_DC) - { - int zr = add_index_zval( array, index, value ); - CHECK_ZEND_ERROR( zr, ctx, SQLSRV_ERROR_ZEND_HASH ) { - throw CoreException(); - } - } - - inline void sqlsrv_add_next_index_zval( _Inout_ sqlsrv_context& ctx, _Inout_ zval* array, _In_ zval* value TSRMLS_DC) - { - int zr = add_next_index_zval( array, value ); - CHECK_ZEND_ERROR( zr, ctx, SQLSRV_ERROR_ZEND_HASH ) { - throw CoreException(); - } - } - - inline void sqlsrv_add_assoc_null( _Inout_ sqlsrv_context& ctx, _Inout_ zval* array_z, _In_ const char* key TSRMLS_DC ) - { - int zr = ::add_assoc_null( array_z, key ); - CHECK_ZEND_ERROR (zr, ctx, SQLSRV_ERROR_ZEND_HASH ) { - throw CoreException(); - } - } - - inline void sqlsrv_add_assoc_long( _Inout_ sqlsrv_context& ctx, _Inout_ zval* array_z, _In_ const char* key, _In_ zend_long val TSRMLS_DC ) - { - int zr = ::add_assoc_long( array_z, key, val ); - CHECK_ZEND_ERROR (zr, ctx, SQLSRV_ERROR_ZEND_HASH ) { - throw CoreException(); - } - } - - inline void sqlsrv_add_assoc_string( _Inout_ sqlsrv_context& ctx, _Inout_ zval* array_z, _In_ const char* key, _Inout_z_ char* val, _In_ bool duplicate TSRMLS_DC ) - { - int zr = ::add_assoc_string(array_z, key, val); - CHECK_ZEND_ERROR (zr, ctx, SQLSRV_ERROR_ZEND_HASH ) { - throw CoreException(); - } - if (duplicate == 0) { - sqlsrv_free(val); - } - } - - inline void sqlsrv_add_assoc_zval( _Inout_ sqlsrv_context& ctx, _Inout_ zval* array_z, _In_ const char* key, _In_ zval* val TSRMLS_DC ) - { - int zr = ::add_assoc_zval(array_z, key, val); - CHECK_ZEND_ERROR (zr, ctx, SQLSRV_ERROR_ZEND_HASH ) { - throw CoreException(); - } - } - - inline void sqlsrv_array_init( _Inout_ sqlsrv_context& ctx, _Out_ zval* new_array TSRMLS_DC) - { -#if PHP_VERSION_ID < 70300 - CHECK_ZEND_ERROR(::array_init(new_array), ctx, SQLSRV_ERROR_ZEND_HASH) { - throw CoreException(); - } -#else - array_init(new_array); -#endif - } - - inline void sqlsrv_php_stream_from_zval_no_verify( _Inout_ sqlsrv_context& ctx, _Outref_result_maybenull_ php_stream*& stream, _In_opt_ zval* stream_z TSRMLS_DC ) + inline void sqlsrv_php_stream_from_zval_no_verify( _Inout_ sqlsrv_context& ctx, _Outref_result_maybenull_ php_stream*& stream, _In_opt_ zval* stream_z ) { // this duplicates the macro php_stream_from_zval_no_verify, which we can't use because it has an assignment php_stream_from_zval_no_verify( stream, stream_z ); @@ -2565,7 +2511,7 @@ namespace core { } } - inline void sqlsrv_zend_hash_get_current_data( _In_ sqlsrv_context& ctx, _In_ HashTable* ht, _Outref_result_maybenull_ zval*& output_data TSRMLS_DC) + inline void sqlsrv_zend_hash_get_current_data( _In_ sqlsrv_context& ctx, _In_ HashTable* ht, _Outref_result_maybenull_ zval*& output_data) { int zr = (output_data = ::zend_hash_get_current_data(ht)) != NULL ? SUCCESS : FAILURE; CHECK_ZEND_ERROR( zr, ctx, SQLSRV_ERROR_ZEND_HASH ) { @@ -2573,7 +2519,7 @@ namespace core { } } - inline void sqlsrv_zend_hash_get_current_data_ptr( _Inout_ sqlsrv_context& ctx, _In_ HashTable* ht, _Outref_result_maybenull_ void*& output_data TSRMLS_DC) + inline void sqlsrv_zend_hash_get_current_data_ptr( _Inout_ sqlsrv_context& ctx, _In_ HashTable* ht, _Outref_result_maybenull_ void*& output_data) { int zr = (output_data = ::zend_hash_get_current_data_ptr(ht)) != NULL ? SUCCESS : FAILURE; CHECK_ZEND_ERROR(zr, ctx, SQLSRV_ERROR_ZEND_HASH) { @@ -2581,7 +2527,7 @@ namespace core { } } - inline void sqlsrv_zend_hash_index_del( _Inout_ sqlsrv_context& ctx, _Inout_ HashTable* ht, _In_ zend_ulong index TSRMLS_DC ) + inline void sqlsrv_zend_hash_index_del( _Inout_ sqlsrv_context& ctx, _Inout_ HashTable* ht, _In_ zend_ulong index ) { int zr = ::zend_hash_index_del( ht, index ); CHECK_ZEND_ERROR( zr, ctx, SQLSRV_ERROR_ZEND_HASH ) { @@ -2589,7 +2535,7 @@ namespace core { } } - inline void sqlsrv_zend_hash_index_update( _Inout_ sqlsrv_context& ctx, _Inout_ HashTable* ht, _In_ zend_ulong index, _In_ zval* data_z TSRMLS_DC ) + inline void sqlsrv_zend_hash_index_update( _Inout_ sqlsrv_context& ctx, _Inout_ HashTable* ht, _In_ zend_ulong index, _In_ zval* data_z ) { int zr = (data_z = ::zend_hash_index_update(ht, index, data_z)) != NULL ? SUCCESS : FAILURE; CHECK_ZEND_ERROR( zr, ctx, SQLSRV_ERROR_ZEND_HASH ) { @@ -2597,7 +2543,7 @@ namespace core { } } - inline void sqlsrv_zend_hash_index_update_ptr( _Inout_ sqlsrv_context& ctx, _Inout_ HashTable* ht, _In_ zend_ulong index, _In_ void* pData TSRMLS_DC) + inline void sqlsrv_zend_hash_index_update_ptr( _Inout_ sqlsrv_context& ctx, _Inout_ HashTable* ht, _In_ zend_ulong index, _In_ void* pData) { int zr = (pData = ::zend_hash_index_update_ptr(ht, index, pData)) != NULL ? SUCCESS : FAILURE; CHECK_ZEND_ERROR(zr, ctx, SQLSRV_ERROR_ZEND_HASH) { @@ -2606,15 +2552,15 @@ namespace core { } - inline void sqlsrv_zend_hash_index_update_mem( _Inout_ sqlsrv_context& ctx, _Inout_ HashTable* ht, _In_ zend_ulong index, _In_reads_bytes_(size) void* pData, _In_ std::size_t size TSRMLS_DC) - { - int zr = (pData = ::zend_hash_index_update_mem(ht, index, pData, size)) != NULL ? SUCCESS : FAILURE; - CHECK_ZEND_ERROR(zr, ctx, SQLSRV_ERROR_ZEND_HASH) { - throw CoreException(); - } - } + inline void sqlsrv_zend_hash_index_update_mem( _Inout_ sqlsrv_context& ctx, _Inout_ HashTable* ht, _In_ zend_ulong index, _In_reads_bytes_(size) void* pData, _In_ std::size_t size) + { + int zr = (pData = ::zend_hash_index_update_mem(ht, index, pData, size)) != NULL ? SUCCESS : FAILURE; + CHECK_ZEND_ERROR(zr, ctx, SQLSRV_ERROR_ZEND_HASH) { + throw CoreException(); + } + } - inline void sqlsrv_zend_hash_next_index_insert( _Inout_ sqlsrv_context& ctx, _Inout_ HashTable* ht, _In_ zval* data TSRMLS_DC ) + inline void sqlsrv_zend_hash_next_index_insert( _Inout_ sqlsrv_context& ctx, _Inout_ HashTable* ht, _In_ zval* data ) { int zr = (data = ::zend_hash_next_index_insert(ht, data)) != NULL ? SUCCESS : FAILURE; CHECK_ZEND_ERROR( zr, ctx, SQLSRV_ERROR_ZEND_HASH ) { @@ -2622,15 +2568,15 @@ namespace core { } } - inline void sqlsrv_zend_hash_next_index_insert_mem( _Inout_ sqlsrv_context& ctx, _In_ HashTable* ht, _In_reads_bytes_(data_size) void* data, _In_ size_t data_size TSRMLS_DC) - { - int zr = (data = ::zend_hash_next_index_insert_mem(ht, data, data_size)) != NULL ? SUCCESS : FAILURE; - CHECK_ZEND_ERROR(zr, ctx, SQLSRV_ERROR_ZEND_HASH) { - throw CoreException(); - } - } + inline void sqlsrv_zend_hash_next_index_insert_mem( _Inout_ sqlsrv_context& ctx, _In_ HashTable* ht, _In_reads_bytes_(data_size) void* data, _In_ size_t data_size) + { + int zr = (data = ::zend_hash_next_index_insert_mem(ht, data, data_size)) != NULL ? SUCCESS : FAILURE; + CHECK_ZEND_ERROR(zr, ctx, SQLSRV_ERROR_ZEND_HASH) { + throw CoreException(); + } + } - inline void sqlsrv_zend_hash_next_index_insert_ptr( _Inout_ sqlsrv_context& ctx, _Inout_ HashTable* ht, _In_ void* data TSRMLS_DC) + inline void sqlsrv_zend_hash_next_index_insert_ptr( _Inout_ sqlsrv_context& ctx, _Inout_ HashTable* ht, _In_ void* data) { int zr = (data = ::zend_hash_next_index_insert_ptr(ht, data)) != NULL ? SUCCESS : FAILURE; CHECK_ZEND_ERROR(zr, ctx, SQLSRV_ERROR_ZEND_HASH) { @@ -2639,21 +2585,21 @@ namespace core { } inline void sqlsrv_zend_hash_init(sqlsrv_context& ctx, _Inout_ HashTable* ht, _Inout_ uint32_t initial_size, - _In_ dtor_func_t dtor_fn, _In_ zend_bool persistent TSRMLS_DC ) + _In_ dtor_func_t dtor_fn, _In_ zend_bool persistent ) { ::zend_hash_init(ht, initial_size, NULL, dtor_fn, persistent); } template -sqlsrv_stmt* allocate_stmt( _In_ sqlsrv_conn* conn, _In_ SQLHANDLE h, _In_ error_callback e, _In_ void* driver TSRMLS_DC ) +sqlsrv_stmt* allocate_stmt( _In_ sqlsrv_conn* conn, _In_ SQLHANDLE h, _In_ error_callback e, _In_ void* driver ) { - return new ( sqlsrv_malloc( sizeof( Statement ))) Statement( conn, h, e, driver TSRMLS_CC ); + return new ( sqlsrv_malloc( sizeof( Statement ))) Statement( conn, h, e, driver ); } template -sqlsrv_conn* allocate_conn( _In_ SQLHANDLE h, _In_ error_callback e, _In_ void* driver TSRMLS_DC ) +sqlsrv_conn* allocate_conn( _In_ SQLHANDLE h, _In_ error_callback e, _In_ void* driver ) { - return new ( sqlsrv_malloc( sizeof( Connection ))) Connection( h, e, driver TSRMLS_CC ); + return new ( sqlsrv_malloc( sizeof( Connection ))) Connection( h, e, driver ); } } // namespace core @@ -2661,10 +2607,10 @@ sqlsrv_conn* allocate_conn( _In_ SQLHANDLE h, _In_ error_callback e, _In_ void* template struct str_conn_attr_func { - static void func( connection_option const* /*option*/, zval* value, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/ TSRMLS_DC ) + static void func( connection_option const* /*option*/, zval* value, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/ ) { try { - core::SQLSetConnectAttr( conn, Attr, reinterpret_cast( Z_STRVAL_P( value )), static_cast( Z_STRLEN_P( value )) TSRMLS_CC ); + core::SQLSetConnectAttr( conn, Attr, reinterpret_cast( Z_STRVAL_P( value )), static_cast( Z_STRLEN_P( value )) ); } catch ( core::CoreException& ) { throw; diff --git a/source/shared/core_stmt.cpp b/source/shared/core_stmt.cpp index 7fac8e5b3..4da01dfb7 100644 --- a/source/shared/core_stmt.cpp +++ b/source/shared/core_stmt.cpp @@ -3,7 +3,7 @@ // // Contents: Core routines that use statement handles shared between sqlsrv and pdo_sqlsrv // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -66,6 +66,9 @@ struct col_cache { const int INITIAL_FIELD_STRING_LEN = 2048; // base allocation size when retrieving a string field +const char DECIMAL_POINT = '.'; +const int SQL_SERVER_DECIMAL_MAXIMUM_PRECISION = 38; // 38 is the maximum length of a stringified decimal number + // 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; const unsigned int UTF8_MIDBYTE_TAG = 0x80; @@ -92,44 +95,45 @@ const size_t DATE_FORMAT_LEN = sizeof( DATE_FORMAT ); // *** internal functions *** // Only declarations are put here. Functions contain the documentation they need at their definition sites. -void calc_string_size( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, _In_ SQLLEN sql_type, _Inout_ SQLLEN& size TSRMLS_DC ); -size_t calc_utf8_missing( _Inout_ sqlsrv_stmt* stmt, _In_reads_(buffer_end) const char* buffer, _In_ size_t buffer_end TSRMLS_DC ); -bool check_for_next_stream_parameter( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ); +void calc_string_size( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, _In_ SQLLEN sql_type, _Inout_ SQLLEN& size ); +size_t calc_utf8_missing( _Inout_ sqlsrv_stmt* stmt, _In_reads_(buffer_end) const char* buffer, _In_ size_t buffer_end ); +bool check_for_next_stream_parameter( _Inout_ sqlsrv_stmt* stmt ); bool convert_input_param_to_utf16( _In_ zval* input_param_z, _Inout_ zval* convert_param_z ); void core_get_field_common(_Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, _Inout_ sqlsrv_phptype - sqlsrv_php_type, _Inout_updates_bytes_(*field_len) void*& field_value, _Inout_ SQLLEN* field_len TSRMLS_DC); + sqlsrv_php_type, _Inout_updates_bytes_(*field_len) void*& field_value, _Inout_ SQLLEN* field_len); // returns the ODBC C type constant that matches the PHP type and encoding given -SQLSMALLINT default_c_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_ zval const* param_z, _In_ SQLSRV_ENCODING encoding TSRMLS_DC ); +SQLSMALLINT default_c_type(_Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_ zval const* param_z, _In_ SQLSMALLINT sql_type, _In_ SQLSRV_ENCODING encoding); void default_sql_size_and_scale( _Inout_ sqlsrv_stmt* stmt, _In_opt_ unsigned int paramno, _In_ zval* param_z, _In_ SQLSRV_ENCODING encoding, - _Out_ SQLULEN& column_size, _Out_ SQLSMALLINT& decimal_digits TSRMLS_DC ); + _Out_ SQLULEN& column_size, _Out_ SQLSMALLINT& decimal_digits ); // given a zval and encoding, determine the appropriate sql type, column size, and decimal scale (if appropriate) void default_sql_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_ zval* param_z, _In_ SQLSRV_ENCODING encoding, - _Out_ SQLSMALLINT& sql_type TSRMLS_DC ); + _Out_ SQLSMALLINT& sql_type ); void col_cache_dtor( _Inout_ zval* data_z ); void field_cache_dtor( _Inout_ zval* data_z ); +int round_up_decimal_numbers(_Inout_ char* buffer, _In_ short decimal_pos, _In_ short decimals_places, _In_ short offset, _In_ short lastpos); void format_decimal_numbers(_In_ SQLSMALLINT decimals_places, _In_ SQLSMALLINT field_scale, _Inout_updates_bytes_(*field_len) char*& field_value, _Inout_ SQLLEN* field_len); -void finalize_output_parameters( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ); +void finalize_output_parameters( _Inout_ sqlsrv_stmt* stmt, _In_opt_ bool exception_thrown = false ); void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, _Inout_ sqlsrv_phptype sqlsrv_php_type, - _Inout_updates_bytes_(*field_len) void*& field_value, _Inout_ SQLLEN* field_len TSRMLS_DC ); -stmt_option const* get_stmt_option( sqlsrv_conn const* conn, _In_ zend_ulong key, _In_ const stmt_option stmt_opts[] TSRMLS_DC ); + _Inout_updates_bytes_(*field_len) void*& field_value, _Inout_ SQLLEN* field_len ); +stmt_option const* get_stmt_option( sqlsrv_conn const* conn, _In_ zend_ulong key, _In_ const stmt_option stmt_opts[] ); bool is_valid_sqlsrv_phptype( _In_ sqlsrv_phptype type ); // assure there is enough space for the output parameter string void resize_output_buffer_if_necessary( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval* param_z, _In_ SQLULEN paramno, SQLSRV_ENCODING encoding, _In_ SQLSMALLINT c_type, _In_ SQLSMALLINT sql_type, _In_ SQLULEN column_size, _In_ SQLSMALLINT decimal_digits, - _Out_writes_(buffer_len) SQLPOINTER& buffer, _Out_ SQLLEN& buffer_len TSRMLS_DC ); -void adjustInputPrecision( _Inout_ zval* param_z, _In_ SQLSMALLINT decimal_digits ); -void save_output_param_for_later( _Inout_ sqlsrv_stmt* stmt, _Inout_ sqlsrv_output_param& param TSRMLS_DC ); + _Out_writes_(buffer_len) SQLPOINTER& buffer, _Out_ SQLLEN& buffer_len ); +void adjustDecimalPrecision(_Inout_ zval* param_z, _In_ SQLSMALLINT decimal_digits); +void save_output_param_for_later( _Inout_ sqlsrv_stmt* stmt, _Inout_ sqlsrv_output_param& param ); // send all the stream data -void send_param_streams( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ); +void send_param_streams( _Inout_ sqlsrv_stmt* stmt ); // called when a bound output string parameter is to be destroyed void sqlsrv_output_param_dtor( _Inout_ zval* data ); // called when a bound stream parameter is to be destroyed. void sqlsrv_stream_dtor( _Inout_ zval* data ); - +bool is_a_numeric_type(_In_ SQLSMALLINT sql_type); } // constructor for sqlsrv_stmt. Here so that we can use functions declared earlier. -sqlsrv_stmt::sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error_callback e, _In_opt_ void* drv TSRMLS_DC ) : +sqlsrv_stmt::sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error_callback e, _In_opt_ void* drv ) : sqlsrv_context( handle, SQL_HANDLE_STMT, e, drv, SQLSRV_ENCODING_DEFAULT ), conn( c ), executed( false ), @@ -155,34 +159,33 @@ sqlsrv_stmt::sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error { ZVAL_UNDEF( &active_stream ); // initialize the input string parameters array (which holds zvals) - core::sqlsrv_array_init( *conn, ¶m_input_strings TSRMLS_CC ); + array_init(¶m_input_strings); // initialize the (input only) stream parameters (which holds sqlsrv_stream structures) ZVAL_NEW_ARR( ¶m_streams ); - core::sqlsrv_zend_hash_init(*conn, Z_ARRVAL( param_streams ), 5 /* # of buckets */, sqlsrv_stream_dtor, 0 /*persistent*/ TSRMLS_CC); + core::sqlsrv_zend_hash_init(*conn, Z_ARRVAL( param_streams ), 5 /* # of buckets */, sqlsrv_stream_dtor, 0 /*persistent*/); // initialize the (input only) datetime parameters of converted date time objects to strings array_init( ¶m_datetime_buffers ); // initialize the output string parameters (which holds sqlsrv_output_param structures) ZVAL_NEW_ARR( &output_params ); - core::sqlsrv_zend_hash_init(*conn, Z_ARRVAL( output_params ), 5 /* # of buckets */, sqlsrv_output_param_dtor, 0 /*persistent*/ TSRMLS_CC); + core::sqlsrv_zend_hash_init(*conn, Z_ARRVAL( output_params ), 5 /* # of buckets */, sqlsrv_output_param_dtor, 0 /*persistent*/); // initialize the col cache ZVAL_NEW_ARR( &col_cache ); - core::sqlsrv_zend_hash_init( *conn, Z_ARRVAL(col_cache), 5 /* # of buckets */, col_cache_dtor, 0 /*persistent*/ TSRMLS_CC ); + core::sqlsrv_zend_hash_init( *conn, Z_ARRVAL(col_cache), 5 /* # of buckets */, col_cache_dtor, 0 /*persistent*/ ); // initialize the field cache ZVAL_NEW_ARR( &field_cache ); - core::sqlsrv_zend_hash_init(*conn, Z_ARRVAL(field_cache), 5 /* # of buckets */, field_cache_dtor, 0 /*persistent*/ TSRMLS_CC); + core::sqlsrv_zend_hash_init(*conn, Z_ARRVAL(field_cache), 5 /* # of buckets */, field_cache_dtor, 0 /*persistent*/); } // desctructor for sqlsrv statement. sqlsrv_stmt::~sqlsrv_stmt( void ) { if( Z_TYPE( active_stream ) != IS_UNDEF ) { - TSRMLS_FETCH(); - close_active_stream( this TSRMLS_CC ); + close_active_stream( this ); } // delete any current results @@ -208,7 +211,7 @@ sqlsrv_stmt::~sqlsrv_stmt( void ) // centralized place to release (without destroying the hash tables // themselves) all the parameter data that accrues during the // execution phase. -void sqlsrv_stmt::free_param_data( TSRMLS_D ) +void sqlsrv_stmt::free_param_data( void ) { SQLSRV_ASSERT(Z_TYPE( param_input_strings ) == IS_ARRAY && Z_TYPE( param_streams ) == IS_ARRAY, "sqlsrv_stmt::free_param_data: Param zvals aren't arrays." ); @@ -224,7 +227,7 @@ void sqlsrv_stmt::free_param_data( TSRMLS_D ) // to be called whenever a new result set is created, such as after an // execute or next_result. Resets the state variables. -void sqlsrv_stmt::new_result_set( TSRMLS_D ) +void sqlsrv_stmt::new_result_set( void ) { this->fetch_called = false; this->has_rows = false; @@ -254,7 +257,7 @@ void sqlsrv_stmt::new_result_set( TSRMLS_D ) if( cursor_type == SQLSRV_CURSOR_BUFFERED ) { sqlsrv_malloc_auto_ptr result; result = reinterpret_cast ( sqlsrv_malloc( sizeof( sqlsrv_buffered_result_set ) ) ); - new ( result.get() ) sqlsrv_buffered_result_set( this TSRMLS_CC ); + new ( result.get() ) sqlsrv_buffered_result_set( this ); current_results = result.get(); result.transferred(); } @@ -272,6 +275,15 @@ void sqlsrv_stmt::clean_up_sensitivity_metadata() } } +void sqlsrv_stmt::set_query_timeout() +{ + if (query_timeout == QUERY_TIMEOUT_INVALID || query_timeout < 0) { + return; + } + + core::SQLSetStmtAttr(this, SQL_ATTR_QUERY_TIMEOUT, reinterpret_cast((SQLLEN)query_timeout), SQL_IS_UINTEGER); +} + // core_sqlsrv_create_stmt // Common code to allocate a statement from either driver. Returns a valid driver statement object or // throws an exception if an error occurs. @@ -286,7 +298,7 @@ void sqlsrv_stmt::clean_up_sensitivity_metadata() // Returns the created statement sqlsrv_stmt* core_sqlsrv_create_stmt( _Inout_ sqlsrv_conn* conn, _In_ driver_stmt_factory stmt_factory, _In_opt_ HashTable* options_ht, - _In_opt_ const stmt_option valid_stmt_opts[], _In_ error_callback const err, _In_opt_ void* driver TSRMLS_DC ) + _In_opt_ const stmt_option valid_stmt_opts[], _In_ error_callback const err, _In_opt_ void* driver ) { sqlsrv_malloc_auto_ptr stmt; SQLHANDLE stmt_h = SQL_NULL_HANDLE; @@ -294,9 +306,9 @@ sqlsrv_stmt* core_sqlsrv_create_stmt( _Inout_ sqlsrv_conn* conn, _In_ driver_stm try { - core::SQLAllocHandle( SQL_HANDLE_STMT, *conn, &stmt_h TSRMLS_CC ); + core::SQLAllocHandle( SQL_HANDLE_STMT, *conn, &stmt_h ); - stmt = stmt_factory( conn, stmt_h, err, driver TSRMLS_CC ); + stmt = stmt_factory( conn, stmt_h, err, driver ); stmt->conn = conn; @@ -317,14 +329,14 @@ sqlsrv_stmt* core_sqlsrv_create_stmt( _Inout_ sqlsrv_conn* conn, _In_ driver_stm // The driver layer should ensure a valid key. DEBUG_SQLSRV_ASSERT(( type == HASH_KEY_IS_LONG ), "allocate_stmt: Invalid statment option key provided." ); - const stmt_option* stmt_opt = get_stmt_option( stmt->conn, index, valid_stmt_opts TSRMLS_CC ); + const stmt_option* stmt_opt = get_stmt_option( stmt->conn, index, valid_stmt_opts ); // if the key didn't match, then return the error to the script. // The driver layer should ensure that the key is valid. DEBUG_SQLSRV_ASSERT( stmt_opt != NULL, "allocate_stmt: unexpected null value for statement option." ); // perform the actions the statement option needs done. - (*stmt_opt->func)( stmt, stmt_opt, value_z TSRMLS_CC ); + (*stmt_opt->func)( stmt, stmt_opt, value_z ); } ZEND_HASH_FOREACH_END(); } @@ -377,7 +389,7 @@ sqlsrv_stmt* core_sqlsrv_create_stmt( _Inout_ sqlsrv_conn* conn, _In_ driver_stm void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_num, _In_ SQLSMALLINT direction, _Inout_ zval* param_z, _In_ SQLSRV_PHPTYPE php_out_type, _Inout_ SQLSRV_ENCODING encoding, _Inout_ SQLSMALLINT sql_type, _Inout_ SQLULEN column_size, - _Inout_ SQLSMALLINT decimal_digits TSRMLS_DC ) + _Inout_ SQLSMALLINT decimal_digits ) { SQLSMALLINT c_type; SQLPOINTER buffer = NULL; @@ -493,16 +505,16 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ else{ // if the sql type is unknown, then set the default based on the PHP type passed in if( sql_type == SQL_UNKNOWN_TYPE ){ - default_sql_type( stmt, param_num, param_z, encoding, sql_type TSRMLS_CC ); + default_sql_type( stmt, param_num, param_z, encoding, sql_type ); } // if the size is unknown, then set the default based on the PHP type passed in if( column_size == SQLSRV_UNKNOWN_SIZE ){ - default_sql_size_and_scale( stmt, static_cast(param_num), param_z, encoding, column_size, decimal_digits TSRMLS_CC ); + default_sql_size_and_scale( stmt, static_cast(param_num), param_z, encoding, column_size, decimal_digits ); } } // determine the ODBC C type - c_type = default_c_type( stmt, param_num, param_z, encoding TSRMLS_CC ); + c_type = default_c_type(stmt, param_num, param_z, sql_type, encoding); // set the buffer based on the PHP parameter type switch( Z_TYPE_P( param_z )){ @@ -527,7 +539,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ if( direction != SQL_PARAM_INPUT ){ // save the parameter so that 1) the buffer doesn't go away, and 2) we can set it to NULL if returned sqlsrv_output_param output_param( param_ref, static_cast( param_num ), zval_was_bool, php_out_type); - save_output_param_for_later( stmt, output_param TSRMLS_CC ); + save_output_param_for_later( stmt, output_param ); } } break; @@ -539,21 +551,27 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ if( direction != SQL_PARAM_INPUT ){ // save the parameter so that 1) the buffer doesn't go away, and 2) we can set it to NULL if returned sqlsrv_output_param output_param( param_ref, static_cast( param_num ), zval_was_bool, php_out_type); - save_output_param_for_later( stmt, output_param TSRMLS_CC ); + save_output_param_for_later( stmt, output_param ); } } break; case IS_STRING: { - if ( sql_type == SQL_DECIMAL || sql_type == SQL_NUMERIC ) { - adjustInputPrecision( param_z, decimal_digits ); + // With AE, the precision of the decimal or numeric inputs have to match exactly as defined in the columns. + // Without AE, the derived default sql types will not be this specific. Thus, if sql_type is SQL_DECIMAL + // or SQL_NUMERIC, the user must have clearly specified it (using the SQLSRV driver) as SQL_DECIMAL or SQL_NUMERIC. + // In either case, the input passed into SQLBindParam requires matching scale (i.e., number of decimal digits). + if (sql_type == SQL_DECIMAL || sql_type == SQL_NUMERIC) { + adjustDecimalPrecision(param_z, decimal_digits); } buffer = Z_STRVAL_P( param_z ); buffer_len = Z_STRLEN_P( param_z ); + bool is_numeric = is_a_numeric_type(sql_type); + // if the encoding is UTF-8, translate from UTF-8 to UTF-16 (the type variables should have already been adjusted) - if( direction == SQL_PARAM_INPUT && encoding == CP_UTF8 ){ + if( direction == SQL_PARAM_INPUT && encoding == CP_UTF8 && !is_numeric){ zval wbuffer_z; ZVAL_NULL( &wbuffer_z ); @@ -565,7 +583,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ } buffer = Z_STRVAL_P( &wbuffer_z ); buffer_len = Z_STRLEN_P( &wbuffer_z ); - core::sqlsrv_add_index_zval( *stmt, &( stmt->param_input_strings ), param_num, &wbuffer_z TSRMLS_CC ); + add_index_zval(&(stmt->param_input_strings), param_num, &wbuffer_z); } ind_ptr = buffer_len; if( direction != SQL_PARAM_INPUT ){ @@ -600,14 +618,16 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ // since this is an output string, assure there is enough space to hold the requested size and // set all the variables necessary (param_z, buffer, buffer_len, and ind_ptr) resize_output_buffer_if_necessary( stmt, param_z, param_num, encoding, c_type, sql_type, column_size, decimal_digits, - buffer, buffer_len TSRMLS_CC ); + buffer, buffer_len ); // save the parameter to be adjusted and/or converted after the results are processed - sqlsrv_output_param output_param( param_ref, encoding, param_num, static_cast( buffer_len ) ); + // no need to use wide chars for numeric types + SQLSRV_ENCODING enc = (is_numeric) ? SQLSRV_ENCODING_CHAR : encoding; + sqlsrv_output_param output_param(param_ref, enc, param_num, static_cast(buffer_len)); output_param.saveMetaData(sql_type, column_size, decimal_digits); - save_output_param_for_later( stmt, output_param TSRMLS_CC ); + save_output_param_for_later( stmt, output_param ); // For output parameters, if we set the column_size to be same as the buffer_len, // then if there is a truncation due to the data coming from the server being @@ -638,7 +658,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ SQLSRV_ASSERT( direction == SQL_PARAM_INPUT, "Invalid output param type. The driver layer should catch this." ); sqlsrv_stream stream_encoding( param_z, encoding ); HashTable* streams_ht = Z_ARRVAL( stmt->param_streams ); - core::sqlsrv_zend_hash_index_update_mem( *stmt, streams_ht, param_num, &stream_encoding, sizeof(stream_encoding) TSRMLS_CC ); + core::sqlsrv_zend_hash_index_update_mem( *stmt, streams_ht, param_num, &stream_encoding, sizeof(stream_encoding) ); buffer = reinterpret_cast( param_num ); Z_TRY_ADDREF_P( param_z ); // so that it doesn't go away while we're using it buffer_len = 0; @@ -659,7 +679,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ bool valid_class_name_found = false; - zend_class_entry *class_entry = Z_OBJCE_P( param_z TSRMLS_CC ); + zend_class_entry *class_entry = Z_OBJCE_P( param_z ); while( class_entry != NULL ){ SQLSRV_ASSERT( class_entry->name != NULL, "core_sqlsrv_bind_param: class_entry->name is NULL." ); @@ -698,7 +718,7 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ params[0] = format_z; // This is equivalent to the PHP code: $param_z->format( $format_z ); where param_z is the // DateTime object and $format_z is the format string. - int zr = call_user_function( EG( function_table ), param_z, &function_z, &buffer_z, 1, params TSRMLS_CC ); + int zr = call_user_function( EG( function_table ), param_z, &function_z, &buffer_z, 1, params ); zend_string_release( Z_STR( format_z )); zend_string_release( Z_STR( function_z )); CHECK_CUSTOM_ERROR( zr == FAILURE, stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE, param_num + 1 ){ @@ -727,17 +747,25 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ } core::SQLBindParameter( stmt, param_num + 1, direction, - c_type, sql_type, column_size, decimal_digits, buffer, buffer_len, &ind_ptr TSRMLS_CC ); - if ( stmt->conn->ce_option.enabled && sql_type == SQL_TYPE_TIMESTAMP ) - { - if( decimal_digits == 3 ) - 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, SQL_IS_INTEGER ); + c_type, sql_type, column_size, decimal_digits, buffer, buffer_len, &ind_ptr ); + + + // When calling SQLDescribeParam() on a parameter targeting a Datetime column, the return values for ParameterType, ColumnSize and DecimalDigits are SQL_TYPE_TIMESTAMP, 23, and 3 respectively. + // For a parameter targeting a SmallDatetime column, the return values are SQL_TYPE_TIMESTAMP, 16, and 0. Inputting these values into SQLBindParameter() results in Operand type clash error. + // This is because SQL_TYPE_TIMESTAMP corresponds to Datetime2 by default, and conversion of Datetime2 to Datetime and conversion of Datetime2 to SmallDatatime is not allowed with encrypted columns. + // To fix the conversion problem, set the SQL_CA_SS_SERVER_TYPE field of the parameter to SQL_SS_TYPE_DATETIME and SQL_SS_TYPE_SMALLDATETIME respectively for a Datetime and Smalldatetime column. + // Note this must be called after SQLBindParameter() or SQLSetDescField() may fail. + // TODO: how to correctly distinguish datetime from datetime2(3)? Both have the same decimal_digits and column_size + 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, SQL_IS_INTEGER); + } else if (decimal_digits == 0 && column_size == 16) { + core::SQLSetDescField(stmt, param_num + 1, SQL_CA_SS_SERVER_TYPE, (SQLPOINTER)SQL_SS_TYPE_SMALLDATETIME, SQL_IS_INTEGER); + } } } catch( core::CoreException& e ){ - stmt->free_param_data( TSRMLS_C ); + stmt->free_param_data(); SQLFreeStmt( stmt->handle(), SQL_RESET_PARAMS ); throw e; } @@ -751,14 +779,14 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_ // Return: // true if there is data, false if there is not -SQLRETURN core_sqlsrv_execute( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC, _In_reads_bytes_(sql_len) const char* sql, _In_ int sql_len ) +SQLRETURN core_sqlsrv_execute( _Inout_ sqlsrv_stmt* stmt, _In_reads_bytes_(sql_len) const char* sql, _In_ int sql_len ) { SQLRETURN r = SQL_ERROR; try { // close the stream to release the resource - close_active_stream( stmt TSRMLS_CC ); + close_active_stream( stmt ); if( sql ) { @@ -778,25 +806,25 @@ SQLRETURN core_sqlsrv_execute( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC, _In_reads_by throw core::CoreException(); } } - r = core::SQLExecDirectW( stmt, wsql_string TSRMLS_CC ); + r = core::SQLExecDirectW( stmt, wsql_string ); } else { - r = core::SQLExecute( stmt TSRMLS_CC ); + r = core::SQLExecute( stmt ); } // if data is needed (streams were bound) and they should be sent at execute time, then do so now if( r == SQL_NEED_DATA && stmt->send_streams_at_exec ) { - send_param_streams( stmt TSRMLS_CC ); + send_param_streams( stmt ); } - stmt->new_result_set( TSRMLS_C ); + stmt->new_result_set(); stmt->executed = true; // if all the data has been sent and no data was returned then finalize the output parameters - if( stmt->send_streams_at_exec && ( r == SQL_NO_DATA || !core_sqlsrv_has_any_result( stmt TSRMLS_CC ))) { + if( stmt->send_streams_at_exec && ( r == SQL_NO_DATA || !core_sqlsrv_has_any_result( stmt ))) { - finalize_output_parameters( stmt TSRMLS_CC ); + finalize_output_parameters( stmt ); } // stream parameters are sent, clean the Hashtable if ( stmt->send_streams_at_exec ) { @@ -809,7 +837,7 @@ SQLRETURN core_sqlsrv_execute( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC, _In_reads_by // if the statement executed but failed in a subsequent operation before returning, // we need to cancel the statement and deref the output and stream parameters if ( stmt->send_streams_at_exec ) { - finalize_output_parameters( stmt TSRMLS_CC ); + finalize_output_parameters( stmt, true ); zend_hash_clean( Z_ARRVAL( stmt->param_streams )); } if( stmt->executed ) { @@ -832,7 +860,7 @@ SQLRETURN core_sqlsrv_execute( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC, _In_reads_by // Nothing, exception thrown if an error. stmt->past_fetch_end is set to true if the // user scrolls past a non-scrollable result set -bool core_sqlsrv_fetch( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orientation, _In_ SQLULEN fetch_offset TSRMLS_DC ) +bool core_sqlsrv_fetch( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orientation, _In_ SQLULEN fetch_offset ) { // pre-condition check SQLSRV_ASSERT( fetch_orientation >= SQL_FETCH_NEXT || fetch_orientation <= SQL_FETCH_RELATIVE, @@ -857,7 +885,7 @@ bool core_sqlsrv_fetch( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orient if (stmt->column_count != ACTIVE_NUM_COLS_INVALID) { has_fields = stmt->column_count; } else { - has_fields = core::SQLNumResultCols( stmt TSRMLS_CC ); + has_fields = core::SQLNumResultCols( stmt ); stmt->column_count = has_fields; } @@ -867,7 +895,7 @@ bool core_sqlsrv_fetch( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orient } // close the stream to release the resource - close_active_stream( stmt TSRMLS_CC ); + close_active_stream( stmt ); // if the statement has rows and is not scrollable but doesn't yet have // fetch_called, this must be the first time we've called sqlsrv_fetch. @@ -878,7 +906,7 @@ bool core_sqlsrv_fetch( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orient // move to the record requested. For absolute records, we use a 0 based offset, so +1 since // SQLFetchScroll uses a 1 based offset, otherwise for relative, just use the fetch_offset provided. - SQLRETURN r = stmt->current_results->fetch( fetch_orientation, ( fetch_orientation == SQL_FETCH_RELATIVE ) ? fetch_offset : fetch_offset + 1 TSRMLS_CC ); + SQLRETURN r = stmt->current_results->fetch( fetch_orientation, ( fetch_orientation == SQL_FETCH_RELATIVE ) ? fetch_offset : fetch_offset + 1 ); 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 @@ -911,7 +939,7 @@ bool core_sqlsrv_fetch( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orient // Return: // A field_meta_data* consisting of the field metadata. -field_meta_data* core_sqlsrv_field_metadata( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT colno TSRMLS_DC ) +field_meta_data* core_sqlsrv_field_metadata( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT colno ) { // pre-condition check SQLSRV_ASSERT( colno >= 0, "core_sqlsrv_field_metadata: Invalid column number provided." ); @@ -927,7 +955,7 @@ field_meta_data* core_sqlsrv_field_metadata( _Inout_ sqlsrv_stmt* stmt, _In_ SQL try{ core::SQLDescribeColW( stmt, colno + 1, field_name_temp, SS_MAXCOLNAMELEN + 1, &field_len_temp, &( meta_data->field_type ), & ( meta_data->field_size ), & ( meta_data->field_scale ), - &( meta_data->field_is_nullable ) TSRMLS_CC ); + &( meta_data->field_is_nullable ) ); } catch ( core::CoreException& e ) { throw e; @@ -971,7 +999,7 @@ field_meta_data* core_sqlsrv_field_metadata( _Inout_ sqlsrv_stmt* stmt, _In_ SQL SQLSMALLINT out_buff_len; SQLLEN not_used; core::SQLColAttribute(stmt, colno + 1, SQL_DESC_TYPE_NAME, field_type_name, - sizeof( field_type_name ), &out_buff_len, ¬_used TSRMLS_CC); + sizeof( field_type_name ), &out_buff_len, ¬_used); if (!strcmp(field_type_name, "money") || !strcmp(field_type_name, "smallmoney")) { meta_data->field_is_money_type = true; @@ -986,10 +1014,11 @@ field_meta_data* core_sqlsrv_field_metadata( _Inout_ sqlsrv_stmt* stmt, _In_ SQL return result_field_meta_data; } -void core_sqlsrv_sensitivity_metadata( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) +void core_sqlsrv_sensitivity_metadata( _Inout_ sqlsrv_stmt* stmt ) { sqlsrv_malloc_auto_ptr dcbuf; - SQLINTEGER dclen = 0; + DWORD dcVersion = 0; + SQLINTEGER dclen = 0, dcIRD = 0; SQLINTEGER dclenout = 0; SQLHANDLE ird; SQLRETURN r; @@ -1011,14 +1040,14 @@ void core_sqlsrv_sensitivity_metadata( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) // Reference: https://docs.microsoft.com/sql/connect/odbc/data-classification // To retrieve sensitivity classfication data, the first step is to retrieve the IRD(Implementation Row Descriptor) handle by // calling SQLGetStmtAttr with SQL_ATTR_IMP_ROW_DESC statement attribute - r = ::SQLGetStmtAttr(stmt->handle(), SQL_ATTR_IMP_ROW_DESC, (SQLPOINTER)&ird, SQL_IS_POINTER, 0); + r = ::SQLGetStmtAttr(stmt->handle(), SQL_ATTR_IMP_ROW_DESC, reinterpret_cast(&ird), SQL_IS_POINTER, 0); CHECK_SQL_ERROR_OR_WARNING(r, stmt) { LOG(SEV_ERROR, "core_sqlsrv_sensitivity_metadata: failed in getting Implementation Row Descriptor handle." ); throw core::CoreException(); } // First call to get dclen - r = ::SQLGetDescFieldW(ird, 0, SQL_CA_SS_DATA_CLASSIFICATION, dcbuf, 0, &dclen); + r = ::SQLGetDescFieldW(ird, 0, SQL_CA_SS_DATA_CLASSIFICATION, reinterpret_cast(dcbuf.get()), 0, &dclen); if (r != SQL_SUCCESS || dclen == 0) { // log the error first LOG(SEV_ERROR, "core_sqlsrv_sensitivity_metadata: failed in calling SQLGetDescFieldW first time." ); @@ -1027,7 +1056,7 @@ void core_sqlsrv_sensitivity_metadata( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) SQLRETURN rc; SQLCHAR state[SQL_SQLSTATE_BUFSIZE] = {'\0'}; SQLSMALLINT len; - rc = ::SQLGetDiagField(SQL_HANDLE_DESC, ird, 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len TSRMLS_CC); + rc = ::SQLGetDiagField(SQL_HANDLE_DESC, ird, 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len); CHECK_SQL_ERROR_OR_WARNING(rc, stmt) { throw core::CoreException(); @@ -1045,7 +1074,7 @@ void core_sqlsrv_sensitivity_metadata( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) // Call again to read SQL_CA_SS_DATA_CLASSIFICATION data dcbuf = static_cast(sqlsrv_malloc(dclen * sizeof(char))); - r = ::SQLGetDescFieldW(ird, 0, SQL_CA_SS_DATA_CLASSIFICATION, dcbuf, dclen, &dclenout); + r = ::SQLGetDescFieldW(ird, 0, SQL_CA_SS_DATA_CLASSIFICATION, reinterpret_cast(dcbuf.get()), dclen, &dclenout); if (r != SQL_SUCCESS) { LOG(SEV_ERROR, "core_sqlsrv_sensitivity_metadata: failed in calling SQLGetDescFieldW again." ); @@ -1056,6 +1085,16 @@ void core_sqlsrv_sensitivity_metadata( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) // Start parsing the data (blob) using namespace data_classification; + + // If make it this far, must be using ODBC 17.2 or above. Prior to ODBC 17.4, checking Data Classification version will fail. + // When the function is successful and the version is right, rank info is available for retrieval + bool getRankInfo = false; + r = ::SQLGetDescFieldW(ird, 0, SQL_CA_SS_DATA_CLASSIFICATION_VERSION, reinterpret_cast(&dcVersion), SQL_IS_INTEGER, &dcIRD); + if (r == SQL_SUCCESS && dcVersion >= VERSION_RANK_AVAILABLE) { + getRankInfo = true; + } + + // Start parsing the data (blob) unsigned char *dcptr = dcbuf; sqlsrv_malloc_auto_ptr sensitivity_meta; @@ -1066,7 +1105,7 @@ void core_sqlsrv_sensitivity_metadata( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) parse_sensitivity_name_id_pairs(stmt, sensitivity_meta->num_infotypes, &sensitivity_meta->infotypes, &dcptr); // Next parse the sensitivity properties - parse_column_sensitivity_props(sensitivity_meta, &dcptr); + parse_column_sensitivity_props(sensitivity_meta, &dcptr, getRankInfo); unsigned char *dcend = dcbuf; dcend += dclen; @@ -1095,12 +1134,12 @@ void core_sqlsrv_sensitivity_metadata( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) void core_sqlsrv_get_field( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, _In_ sqlsrv_phptype sqlsrv_php_type_in, _In_ bool prefer_string, _Outref_result_bytebuffer_maybenull_(*field_len) void*& field_value, _Inout_ SQLLEN* field_len, _In_ bool cache_field, - _Out_ SQLSRV_PHPTYPE *sqlsrv_php_type_out TSRMLS_DC) + _Out_ SQLSRV_PHPTYPE *sqlsrv_php_type_out) { try { // close the stream to release the resource - close_active_stream(stmt TSRMLS_CC); + close_active_stream(stmt); // if the field has been retrieved before, return the previous result field_cache* cached = NULL; @@ -1139,7 +1178,7 @@ void core_sqlsrv_get_field( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_i invalid.typeinfo.type = SQLSRV_PHPTYPE_INVALID; for( int i = stmt->last_field_index + 1; i < field_index; ++i ) { SQLSRV_ASSERT( reinterpret_cast( zend_hash_index_find_ptr( Z_ARRVAL( stmt->field_cache ), i )) == NULL, "Field already cached." ); - core_sqlsrv_get_field( stmt, i, invalid, prefer_string, field_value, field_len, cache_field, sqlsrv_php_type_out TSRMLS_CC ); + core_sqlsrv_get_field( stmt, i, invalid, prefer_string, field_value, field_len, cache_field, sqlsrv_php_type_out ); // delete the value returned since we only want it cached, not the actual value if( field_value ) { efree( field_value ); @@ -1183,12 +1222,12 @@ void core_sqlsrv_get_field( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_i *sqlsrv_php_type_out = static_cast( sqlsrv_php_type.typeinfo.type ); // Retrieve the data - core_get_field_common( stmt, field_index, sqlsrv_php_type, field_value, field_len TSRMLS_CC ); + core_get_field_common( stmt, field_index, sqlsrv_php_type, field_value, field_len ); // if the user wants us to cache the field, we'll do it if( cache_field ) { field_cache cache( field_value, *field_len, sqlsrv_php_type ); - core::sqlsrv_zend_hash_index_update_mem( *stmt, Z_ARRVAL( stmt->field_cache ), field_index, &cache, sizeof(field_cache) TSRMLS_CC ); + core::sqlsrv_zend_hash_index_update_mem( *stmt, Z_ARRVAL( stmt->field_cache ), field_index, &cache, sizeof(field_cache) ); } } @@ -1205,7 +1244,7 @@ void core_sqlsrv_get_field( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_i // Return: // true if any results are present, false otherwise. -bool core_sqlsrv_has_any_result( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) +bool core_sqlsrv_has_any_result( _Inout_ sqlsrv_stmt* stmt ) { SQLSMALLINT num_cols; SQLLEN rows_affected; @@ -1215,7 +1254,7 @@ bool core_sqlsrv_has_any_result( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) } else { // Use SQLNumResultCols to determine if we have rows or not - num_cols = core::SQLNumResultCols( stmt TSRMLS_CC ); + num_cols = core::SQLNumResultCols( stmt ); stmt->column_count = num_cols; } @@ -1224,7 +1263,7 @@ bool core_sqlsrv_has_any_result( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) } else { // Use SQLRowCount to determine if there is a rows status waiting - rows_affected = core::SQLRowCount( stmt TSRMLS_CC ); + rows_affected = core::SQLRowCount( stmt ); stmt->row_count = rows_affected; } @@ -1238,7 +1277,7 @@ bool core_sqlsrv_has_any_result( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) // Returns // Nothing, exception thrown if problem occurs -void core_sqlsrv_next_result( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC, _In_ bool finalize_output_params, _In_ bool throw_on_errors ) +void core_sqlsrv_next_result( _Inout_ sqlsrv_stmt* stmt, _In_ bool finalize_output_params, _In_ bool throw_on_errors ) { try { @@ -1251,14 +1290,14 @@ void core_sqlsrv_next_result( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC, _In_ bool fin throw core::CoreException(); } - close_active_stream( stmt TSRMLS_CC ); + close_active_stream( stmt ); //Clear column sql types and sql display sizes. zend_hash_clean( Z_ARRVAL( stmt->col_cache )); SQLRETURN r; if( throw_on_errors ) { - r = core::SQLMoreResults( stmt TSRMLS_CC ); + r = core::SQLMoreResults( stmt ); } else { r = SQLMoreResults( stmt->handle() ); @@ -1268,7 +1307,7 @@ void core_sqlsrv_next_result( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC, _In_ bool fin if( finalize_output_params ) { // if we're finished processing result sets, handle the output parameters - finalize_output_parameters( stmt TSRMLS_CC ); + finalize_output_parameters( stmt ); } // mark we are past the end of all results @@ -1276,7 +1315,7 @@ void core_sqlsrv_next_result( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC, _In_ bool fin return; } - stmt->new_result_set( TSRMLS_C ); + stmt->new_result_set(); } catch( core::CoreException& e ) { @@ -1295,26 +1334,26 @@ void core_sqlsrv_next_result( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC, _In_ bool fin // Returns: // Nothing, exception thrown if problem occurs -void core_sqlsrv_post_param( _Inout_ sqlsrv_stmt* stmt, _In_ zend_ulong param_num, zval* param_z TSRMLS_DC ) +void core_sqlsrv_post_param( _Inout_ sqlsrv_stmt* stmt, _In_ zend_ulong param_num, zval* param_z ) { SQLSRV_ASSERT( Z_TYPE( stmt->param_input_strings ) == IS_ARRAY, "Statement input parameter UTF-16 buffers array invalid." ); SQLSRV_ASSERT( Z_TYPE( stmt->param_streams ) == IS_ARRAY, "Statement input parameter streams array invalid." ); // if the parameter was an input string, delete it from the array holding input parameter strings if( zend_hash_index_exists( Z_ARRVAL( stmt->param_input_strings ), param_num )) { - core::sqlsrv_zend_hash_index_del( *stmt, Z_ARRVAL( stmt->param_input_strings ), param_num TSRMLS_CC ); + core::sqlsrv_zend_hash_index_del( *stmt, Z_ARRVAL( stmt->param_input_strings ), param_num ); } // if the parameter was an input stream, decrement our reference to it and delete it from the array holding input streams // PDO doesn't need the reference count, but sqlsrv does since the stream can be live after sqlsrv_execute by sending it // with sqlsrv_send_stream_data. if( zend_hash_index_exists( Z_ARRVAL( stmt->param_streams ), param_num )) { - core::sqlsrv_zend_hash_index_del( *stmt, Z_ARRVAL( stmt->param_streams ), param_num TSRMLS_CC ); + core::sqlsrv_zend_hash_index_del( *stmt, Z_ARRVAL( stmt->param_streams ), param_num ); } } //Calls SQLSetStmtAttr to set a cursor. -void core_sqlsrv_set_scrollable( _Inout_ sqlsrv_stmt* stmt, _In_ unsigned long cursor_type TSRMLS_DC ) +void core_sqlsrv_set_scrollable( _Inout_ sqlsrv_stmt* stmt, _In_ unsigned long cursor_type ) { try { @@ -1322,27 +1361,27 @@ void core_sqlsrv_set_scrollable( _Inout_ sqlsrv_stmt* stmt, _In_ unsigned long c case SQL_CURSOR_STATIC: core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, - reinterpret_cast( SQL_CURSOR_STATIC ), SQL_IS_UINTEGER TSRMLS_CC ); + reinterpret_cast( SQL_CURSOR_STATIC ), SQL_IS_UINTEGER ); break; case SQL_CURSOR_DYNAMIC: core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, - reinterpret_cast( SQL_CURSOR_DYNAMIC ), SQL_IS_UINTEGER TSRMLS_CC ); + reinterpret_cast( SQL_CURSOR_DYNAMIC ), SQL_IS_UINTEGER ); break; case SQL_CURSOR_KEYSET_DRIVEN: core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, - reinterpret_cast( SQL_CURSOR_KEYSET_DRIVEN ), SQL_IS_UINTEGER TSRMLS_CC ); + reinterpret_cast( SQL_CURSOR_KEYSET_DRIVEN ), SQL_IS_UINTEGER ); break; case SQL_CURSOR_FORWARD_ONLY: core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, - reinterpret_cast( SQL_CURSOR_FORWARD_ONLY ), SQL_IS_UINTEGER TSRMLS_CC ); + reinterpret_cast( SQL_CURSOR_FORWARD_ONLY ), SQL_IS_UINTEGER ); break; case SQLSRV_CURSOR_BUFFERED: core::SQLSetStmtAttr( stmt, SQL_ATTR_CURSOR_TYPE, - reinterpret_cast( SQL_CURSOR_FORWARD_ONLY ), SQL_IS_UINTEGER TSRMLS_CC ); + reinterpret_cast( SQL_CURSOR_FORWARD_ONLY ), SQL_IS_UINTEGER ); break; default: @@ -1358,17 +1397,17 @@ void core_sqlsrv_set_scrollable( _Inout_ sqlsrv_stmt* stmt, _In_ unsigned long c } } -void core_sqlsrv_set_buffered_query_limit( _Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z TSRMLS_DC ) +void core_sqlsrv_set_buffered_query_limit( _Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z ) { if( Z_TYPE_P( value_z ) != IS_LONG ) { THROW_CORE_ERROR( stmt, SQLSRV_ERROR_INVALID_BUFFER_LIMIT ); } - core_sqlsrv_set_buffered_query_limit( stmt, Z_LVAL_P( value_z ) TSRMLS_CC ); + core_sqlsrv_set_buffered_query_limit( stmt, Z_LVAL_P( value_z ) ); } -void core_sqlsrv_set_buffered_query_limit( _Inout_ sqlsrv_stmt* stmt, _In_ SQLLEN limit TSRMLS_DC ) +void core_sqlsrv_set_buffered_query_limit( _Inout_ sqlsrv_stmt* stmt, _In_ SQLLEN limit ) { if( limit <= 0 ) { @@ -1382,7 +1421,7 @@ void core_sqlsrv_set_buffered_query_limit( _Inout_ sqlsrv_stmt* stmt, _In_ SQLLE // Extracts the long value and calls the core_sqlsrv_set_query_timeout // which accepts timeout parameter as a long. If the zval is not of type long // than throws error. -void core_sqlsrv_set_query_timeout( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval* value_z TSRMLS_DC ) +void core_sqlsrv_set_query_timeout( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval* value_z ) { try { @@ -1401,7 +1440,7 @@ void core_sqlsrv_set_query_timeout( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval* val } } -void core_sqlsrv_set_decimal_places(_Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z TSRMLS_DC) +void core_sqlsrv_set_decimal_places(_Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z) { try { // first check if the input is an integer @@ -1422,10 +1461,8 @@ void core_sqlsrv_set_decimal_places(_Inout_ sqlsrv_stmt* stmt, _In_ zval* value_ } } -void core_sqlsrv_set_send_at_exec( _Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z TSRMLS_DC ) +void core_sqlsrv_set_send_at_exec( _Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z ) { - TSRMLS_C; - // zend_is_true does not fail. It either returns true or false. stmt->send_streams_at_exec = ( zend_is_true( value_z )) ? true : false; } @@ -1442,13 +1479,13 @@ void core_sqlsrv_set_send_at_exec( _Inout_ sqlsrv_stmt* stmt, _In_ zval* value_z // Returns: // true if more data remains to be sent, false if all data processed -bool core_sqlsrv_send_stream_packet( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) +bool core_sqlsrv_send_stream_packet( _Inout_ sqlsrv_stmt* stmt ) { // if there no current parameter to process, get the next one // (probably because this is the first call to sqlsrv_send_stream_data) if( stmt->current_stream.stream_z == NULL ) { - if( check_for_next_stream_parameter( stmt TSRMLS_CC ) == false ) { + if( check_for_next_stream_parameter( stmt ) == false ) { stmt->current_stream = sqlsrv_stream( NULL, SQLSRV_ENCODING_CHAR ); stmt->current_stream_read = 0; @@ -1460,7 +1497,7 @@ bool core_sqlsrv_send_stream_packet( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) // get the stream from the zval we bound php_stream* param_stream = NULL; - core::sqlsrv_php_stream_from_zval_no_verify( *stmt, param_stream, stmt->current_stream.stream_z TSRMLS_CC ); + core::sqlsrv_php_stream_from_zval_no_verify( *stmt, param_stream, stmt->current_stream.stream_z ); // if we're at the end, then reset both current_stream and current_stream_read if (php_stream_eof(param_stream)) { @@ -1489,7 +1526,7 @@ bool core_sqlsrv_send_stream_packet( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) if (read == 0) { // send an empty string, which is what a 0 length does. char buff[1]; // temp storage to hand to SQLPutData - core::SQLPutData(stmt, buff, 0 TSRMLS_CC); + core::SQLPutData(stmt, buff, 0); } else if (read > 0) { // if this is a UTF-8 stream, then we will use the UTF-8 encoding to determine if we're in the middle of a character @@ -1516,7 +1553,7 @@ bool core_sqlsrv_send_stream_packet( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) // this will calculate how many bytes were cut off from the last UTF-8 character and read that many more // in, then reattempt the conversion. If it fails the second time, then an error is returned. - size_t need_to_read = calc_utf8_missing( stmt, buffer, read TSRMLS_CC ); + size_t need_to_read = calc_utf8_missing( stmt, buffer, read ); // read the missing bytes size_t new_read = php_stream_read( param_stream, static_cast( buffer ) + read, need_to_read ); @@ -1535,17 +1572,17 @@ bool core_sqlsrv_send_stream_packet( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) throw core::CoreException(); } } - core::SQLPutData( stmt, wbuffer, wsize * sizeof( SQLWCHAR ) TSRMLS_CC ); + core::SQLPutData( stmt, wbuffer, wsize * sizeof( SQLWCHAR ) ); } else { - core::SQLPutData( stmt, buffer, read TSRMLS_CC ); + core::SQLPutData( stmt, buffer, read ); } } } } catch( core::CoreException& e ) { - stmt->free_param_data( TSRMLS_C ); + stmt->free_param_data(); SQLFreeStmt( stmt->handle(), SQL_RESET_PARAMS ); SQLCancel( stmt->handle() ); stmt->current_stream = sqlsrv_stream( NULL, SQLSRV_ENCODING_DEFAULT ); @@ -1556,30 +1593,28 @@ bool core_sqlsrv_send_stream_packet( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) return true; } -void stmt_option_functor::operator()( _Inout_ sqlsrv_stmt* /*stmt*/, stmt_option const* /*opt*/, _In_ zval* /*value_z*/ TSRMLS_DC ) +void stmt_option_functor::operator()( _Inout_ sqlsrv_stmt* /*stmt*/, stmt_option const* /*opt*/, _In_ zval* /*value_z*/ ) { - TSRMLS_C; - // This implementation should never get called. DIE( "Not implemented." ); } -void stmt_option_query_timeout:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /**/, _In_ zval* value_z TSRMLS_DC ) +void stmt_option_query_timeout:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /**/, _In_ zval* value_z ) { - core_sqlsrv_set_query_timeout( stmt, value_z TSRMLS_CC ); + core_sqlsrv_set_query_timeout( stmt, value_z ); } -void stmt_option_send_at_exec:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC ) +void stmt_option_send_at_exec:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z ) { - core_sqlsrv_set_send_at_exec( stmt, value_z TSRMLS_CC ); + core_sqlsrv_set_send_at_exec( stmt, value_z ); } -void stmt_option_buffered_query_limit:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC ) +void stmt_option_buffered_query_limit:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z ) { - core_sqlsrv_set_buffered_query_limit( stmt, value_z TSRMLS_CC ); + core_sqlsrv_set_buffered_query_limit( stmt, value_z ); } -void stmt_option_date_as_string:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /**/, _In_ zval* value_z TSRMLS_DC ) +void stmt_option_date_as_string:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /**/, _In_ zval* value_z ) { if (zend_is_true(value_z)) { stmt->date_as_string = true; @@ -1589,7 +1624,7 @@ void stmt_option_date_as_string:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_op } } -void stmt_option_format_decimals:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /**/, _In_ zval* value_z TSRMLS_DC ) +void stmt_option_format_decimals:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /**/, _In_ zval* value_z ) { if (zend_is_true(value_z)) { stmt->format_decimals = true; @@ -1599,12 +1634,12 @@ void stmt_option_format_decimals:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_o } } -void stmt_option_decimal_places:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /**/, _In_ zval* value_z TSRMLS_DC ) +void stmt_option_decimal_places:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /**/, _In_ zval* value_z ) { - core_sqlsrv_set_decimal_places(stmt, value_z TSRMLS_CC); + core_sqlsrv_set_decimal_places(stmt, value_z); } -void stmt_option_data_classification:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /**/, _In_ zval* value_z TSRMLS_DC ) +void stmt_option_data_classification:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /**/, _In_ zval* value_z ) { if (zend_is_true(value_z)) { stmt->data_classification = true; @@ -1616,7 +1651,7 @@ void stmt_option_data_classification:: operator()( _Inout_ sqlsrv_stmt* stmt, st // internal function to release the active stream. Called by each main API function // that will alter the statement and cancel any retrieval of data from a stream. -void close_active_stream( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) +void close_active_stream( _Inout_ sqlsrv_stmt* stmt ) { // if there is no active stream, return if( Z_TYPE( stmt->active_stream ) == IS_UNDEF ) { @@ -1678,7 +1713,7 @@ bool is_a_numeric_type(_In_ SQLSMALLINT sql_type) return false; } -void calc_string_size( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, _In_ SQLLEN sql_type, _Inout_ SQLLEN& size TSRMLS_DC ) +void calc_string_size( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, _In_ SQLLEN sql_type, _Inout_ SQLLEN& size ) { try { @@ -1712,7 +1747,7 @@ void calc_string_size( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, case SQL_SS_VARIANT: { // unixODBC 2.3.1 requires wide calls to support pooling - core::SQLColAttributeW( stmt, field_index + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, &size TSRMLS_CC ); + core::SQLColAttributeW( stmt, field_index + 1, SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, &size ); break; } @@ -1722,7 +1757,7 @@ void calc_string_size( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, case SQL_WVARCHAR: { // unixODBC 2.3.1 requires wide calls to support pooling - core::SQLColAttributeW( stmt, field_index + 1, SQL_DESC_OCTET_LENGTH, NULL, 0, NULL, &size TSRMLS_CC ); + core::SQLColAttributeW( stmt, field_index + 1, SQL_DESC_OCTET_LENGTH, NULL, 0, NULL, &size ); break; } @@ -1739,7 +1774,7 @@ void calc_string_size( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, // calculates how many characters were cut off from the end of a buffer when reading // in UTF-8 encoded text -size_t calc_utf8_missing( _Inout_ sqlsrv_stmt* stmt, _In_reads_(buffer_end) const char* buffer, _In_ size_t buffer_end TSRMLS_DC ) +size_t calc_utf8_missing( _Inout_ sqlsrv_stmt* stmt, _In_reads_(buffer_end) const char* buffer, _In_ size_t buffer_end ) { const char* last_char = buffer + buffer_end - 1; size_t need_to_read = 0; @@ -1778,11 +1813,11 @@ size_t calc_utf8_missing( _Inout_ sqlsrv_stmt* stmt, _In_reads_(buffer_end) cons // the driver layer would have to calculate size of the field_value // to decide the amount of memory allocation. void core_get_field_common( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, _Inout_ sqlsrv_phptype - sqlsrv_php_type, _Inout_updates_bytes_(*field_len) void*& field_value, _Inout_ SQLLEN* field_len TSRMLS_DC ) + sqlsrv_php_type, _Inout_updates_bytes_(*field_len) void*& field_value, _Inout_ SQLLEN* field_len ) { try { - close_active_stream( stmt TSRMLS_CC ); + close_active_stream( stmt ); // make sure that fetch is called before trying to retrieve. CHECK_CUSTOM_ERROR( !stmt->fetch_called, stmt, SQLSRV_ERROR_FETCH_NOT_CALLED ) { @@ -1804,7 +1839,7 @@ void core_get_field_common( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_i *field_value_temp = 0; SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_LONG, field_value_temp, sizeof( SQLLEN ), - field_len, true /*handle_warning*/ TSRMLS_CC ); + field_len, true /*handle_warning*/ ); CHECK_SQL_ERROR_OR_WARNING( r, stmt ) { throw core::CoreException(); @@ -1828,9 +1863,10 @@ void core_get_field_common( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_i { sqlsrv_malloc_auto_ptr field_value_temp; field_value_temp = static_cast( sqlsrv_malloc( sizeof( double ))); + *field_value_temp = 0.0; SQLRETURN r = stmt->current_results->get_data( field_index + 1, SQL_C_DOUBLE, field_value_temp, sizeof( double ), - field_len, true /*handle_warning*/ TSRMLS_CC ); + field_len, true /*handle_warning*/ ); CHECK_SQL_ERROR_OR_WARNING( r, stmt ) { throw core::CoreException(); @@ -1852,7 +1888,7 @@ void core_get_field_common( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_i case SQLSRV_PHPTYPE_STRING: { - get_field_as_string( stmt, field_index, sqlsrv_php_type, field_value, field_len TSRMLS_CC ); + get_field_as_string( stmt, field_index, sqlsrv_php_type, field_value, field_len ); break; } @@ -1868,7 +1904,7 @@ void core_get_field_common( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_i field_value_temp = static_cast(sqlsrv_malloc(MAX_DATETIME_STRING_LEN)); memset(field_value_temp, '\0', MAX_DATETIME_STRING_LEN); - SQLRETURN r = stmt->current_results->get_data(field_index + 1, SQL_C_CHAR, field_value_temp, MAX_DATETIME_STRING_LEN, &field_len_temp, true TSRMLS_CC); + SQLRETURN r = stmt->current_results->get_data(field_index + 1, SQL_C_CHAR, field_value_temp, MAX_DATETIME_STRING_LEN, &field_len_temp, true); if (r == SQL_NO_DATA || field_len_temp == SQL_NULL_DATA) { field_value_temp.reset(); @@ -1902,7 +1938,11 @@ void core_get_field_common( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_i throw core::CoreException(); } - stream = php_stream_open_wrapper( "sqlsrv://sqlncli10", "r", 0, NULL ); + // For a sqlsrv stream, only REPORT_ERRORS may be used. For "mode", the 'b' option + // is ignored on POSIX systems, which treat text and binary files the same. Yet, the + // 'b' option might be important in other systems. + // For details check https://www.php.net/manual/en/internals2.ze1.streams.php + stream = php_stream_open_wrapper("sqlsrv://sqlncli10", "rb", REPORT_ERRORS, NULL); CHECK_CUSTOM_ERROR( !stream, stmt, SQLSRV_ERROR_STREAM_CREATE ) { throw core::CoreException(); @@ -1950,7 +1990,7 @@ void core_get_field_common( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_i // check_for_next_stream_parameter // see if there is another stream to be sent. Returns true and sets the stream as current in the statement structure, otherwise // returns false -bool check_for_next_stream_parameter( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) +bool check_for_next_stream_parameter( _Inout_ sqlsrv_stmt* stmt ) { zend_ulong stream_index = 0; SQLRETURN r = SQL_SUCCESS; @@ -1958,7 +1998,7 @@ bool check_for_next_stream_parameter( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) zval* param_z = NULL; // get the index into the streams_ht from the parameter data we set in core_sqlsrv_bind_param - r = core::SQLParamData( stmt, reinterpret_cast( &stream_index ) TSRMLS_CC ); + r = core::SQLParamData( stmt, reinterpret_cast( &stream_index ) ); // if no more data, we've exhausted the bound parameters, so return that we're done if( SQL_SUCCEEDED( r ) || r == SQL_NO_DATA ) { @@ -2046,7 +2086,7 @@ bool convert_input_param_to_utf16( _In_ zval* input_param_z, _Inout_ zval* conve // returns the ODBC C type constant that matches the PHP type and encoding given -SQLSMALLINT default_c_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_ zval const* param_z, _In_ SQLSRV_ENCODING encoding TSRMLS_DC ) +SQLSMALLINT default_c_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_ zval const* param_z, _In_ SQLSMALLINT sql_type, _In_ SQLSRV_ENCODING encoding ) { SQLSMALLINT sql_c_type = SQL_UNKNOWN_TYPE; int php_type = Z_TYPE_P( param_z ); @@ -2072,18 +2112,34 @@ SQLSMALLINT default_c_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, sql_c_type = SQL_C_SLONG; break; case IS_LONG: - //ODBC 64-bit long and integer type are 4 byte values. - if ((Z_LVAL_P(param_z) < INT_MIN) || (Z_LVAL_P(param_z) > INT_MAX)) { - sql_c_type = SQL_C_SBIGINT; - } - else { - sql_c_type = SQL_C_SLONG; - } + // When binding any integer, the zend_long value and its length are used as the buffer + // and buffer length. When the buffer is 8 bytes use the corresponding C type for + // 8-byte integers +#ifdef ZEND_ENABLE_ZVAL_LONG64 + sql_c_type = SQL_C_SBIGINT; +#else + sql_c_type = SQL_C_SLONG; +#endif break; case IS_DOUBLE: sql_c_type = SQL_C_DOUBLE; break; case IS_STRING: + switch (encoding) { + case SQLSRV_ENCODING_CHAR: + sql_c_type = SQL_C_CHAR; + break; + case SQLSRV_ENCODING_BINARY: + sql_c_type = SQL_C_BINARY; + break; + case CP_UTF8: + sql_c_type = (is_a_numeric_type(sql_type)) ? SQL_C_CHAR : SQL_C_WCHAR; + break; + default: + THROW_CORE_ERROR(stmt, SQLSRV_ERROR_INVALID_PARAMETER_ENCODING, paramno); + break; + } + break; case IS_RESOURCE: switch( encoding ) { case SQLSRV_ENCODING_CHAR: @@ -2117,7 +2173,7 @@ SQLSMALLINT default_c_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, // given a zval and encoding, determine the appropriate sql type void default_sql_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_ zval* param_z, _In_ SQLSRV_ENCODING encoding, - _Out_ SQLSMALLINT& sql_type TSRMLS_DC ) + _Out_ SQLSMALLINT& sql_type ) { sql_type = SQL_UNKNOWN_TYPE; int php_type = Z_TYPE_P(param_z); @@ -2195,7 +2251,7 @@ void default_sql_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_ // given a zval and encoding, determine the appropriate column size, and decimal scale (if appropriate) void default_sql_size_and_scale( _Inout_ sqlsrv_stmt* stmt, _In_opt_ unsigned int paramno, _In_ zval* param_z, _In_ SQLSRV_ENCODING encoding, - _Out_ SQLULEN& column_size, _Out_ SQLSMALLINT& decimal_digits TSRMLS_DC ) + _Out_ SQLULEN& column_size, _Out_ SQLSMALLINT& decimal_digits ) { int php_type = Z_TYPE_P( param_z ); column_size = 0; @@ -2274,129 +2330,63 @@ void format_decimal_numbers(_In_ SQLSMALLINT decimals_places, _In_ SQLSMALLINT f // Likewise, if decimals_places is larger than the field scale, decimals_places wil be ignored. This is to ensure the // number of decimals adheres to the column field scale. If smaller, the output value may be rounded up. // - // Note: it's possible that the decimal data does not contain a decimal dot because the field scale is 0. - // Thus, first check if the decimal dot exists. If not, no formatting necessary, regardless of + // Note: it's possible that the decimal data does not contain a decimal point because the field scale is 0. + // Thus, first check if the decimal point exists. If not, no formatting necessary, regardless of // format_decimals and decimals_places // - std::string str = field_value; - size_t pos = str.find_first_of('.'); - // The decimal dot is not found, simply return - if (pos == std::string::npos) { + // Check if it's a negative number and if necessary to add the leading zero + bool is_negative = (*field_value == '-'); + char *src = field_value + is_negative; + bool add_leading_zero = false; + + // If the decimal point is not found, simply return + char *pt = strchr(src, DECIMAL_POINT); + if (pt == NULL) { return; } - - SQLSMALLINT num_decimals = decimals_places; - if (num_decimals > field_scale) { - num_decimals = field_scale; + else if (pt == src) { + add_leading_zero = true; } - // We want the rounding to be consistent with php number_format(), http://php.net/manual/en/function.number-format.php - // as well as SQL Server Management studio, such that the least significant digit will be rounded up if it is - // followed by 5 or above. + SQLSMALLINT scale = decimals_places; + if (scale > field_scale) { + scale = field_scale; + } - bool isNegative = false; + char buffer[50] = " "; // A buffer with two blank spaces, as leeway + short offset = 1 + is_negative; + short src_length = strlen(src); - // If negative, remove the minus sign for now so as not to complicate the rounding process - if (str[0] == '-') { - isNegative = true; - std::ostringstream oss; - oss << str.substr(1); - str = oss.str(); - pos = str.find_first_of('.'); + if (add_leading_zero) { + buffer[offset++] = '0'; } + // Copy the original numerical value to the buffer + memcpy_s(buffer + offset, src_length, src, src_length); - // Adds the leading zero if not exists - if (pos == 0) { - std::ostringstream oss; - oss << '0' << str; - str = oss.str(); - pos++; - } + int last_pos = src_length + offset; - if (num_decimals == NO_CHANGE_DECIMAL_PLACES) { - // Add the minus sign back if negative - if (isNegative) { - std::ostringstream oss; - oss << '-' << str.substr(0); - str = oss.str(); - } - } else { - // Start formatting - size_t last = 0; - if (num_decimals == 0) { - // Chop all decimal digits, including the decimal dot - size_t pos2 = pos + 1; - short n = str[pos2] - '0'; - if (n >= 5) { - // Start rounding up - starting from the digit left of the dot all the way to the first digit - bool carry_over = true; - for (short p = pos - 1; p >= 0 && carry_over; p--) { - n = str[p] - '0'; - if (n == 9) { - str[p] = '0' ; - carry_over = true; - } - else { - n++; - carry_over = false; - str[p] = '0' + n; - } - } - if (carry_over) { - std::ostringstream oss; - oss << '1' << str.substr(0, pos); - str = oss.str(); - pos++; - } - } - last = pos; - } - else { - size_t pos2 = pos + num_decimals + 1; - // No need to check if rounding is necessary when pos2 has passed the last digit in the input string - if (pos2 < str.length()) { - short n = str[pos2] - '0'; - if (n >= 5) { - // Start rounding up - starting from the digit left of pos2 all the way to the first digit - bool carry_over = true; - for (short p = pos2 - 1; p >= 0 && carry_over; p--) { - if (str[p] == '.') { // Skip the dot - continue; - } - n = str[p] - '0'; - if (n == 9) { - str[p] = '0' ; - carry_over = true; - } - else { - n++; - carry_over = false; - str[p] = '0' + n; - } - } - if (carry_over) { - std::ostringstream oss; - oss << '1' << str.substr(0, pos2); - str = oss.str(); - pos2++; - } - } - } - last = pos2; - } - // Add the minus sign back if negative - if (isNegative) { - std::ostringstream oss; - oss << '-' << str.substr(0, last); - str = oss.str(); - } else { - str = str.substr(0, last); + // If no need to adjust decimal places, skip formatting + if (decimals_places != NO_CHANGE_DECIMAL_PLACES) { + short num_decimals = src_length - (pt - src) - 1; + + if (num_decimals > scale) { + last_pos = round_up_decimal_numbers(buffer, (pt - src) + offset, scale, offset, last_pos); } - } + } - size_t len = str.length(); - str.copy(field_value, len); + // Remove the extra white space if not used + char *p = buffer; + offset = 0; + while (isspace(*p++)) { + offset++; + } + if (is_negative) { + buffer[--offset] = '-'; + } + + short len = last_pos - offset; + memcpy_s(field_value, len, buffer + offset, len); field_value[len] = '\0'; *field_len = len; } @@ -2407,10 +2397,18 @@ void format_decimal_numbers(_In_ SQLSMALLINT decimals_places, _In_ SQLSMALLINT f // parameters passed to SQLBindParameter. It also converts output strings from UTF-16 to UTF-8 if necessary. // For integer or float parameters, it sets those to NULL if a NULL was returned by SQL Server -void finalize_output_parameters( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) +void finalize_output_parameters( _Inout_ sqlsrv_stmt* stmt, _In_opt_ bool exception_thrown /*= false*/ ) { if (Z_ISUNDEF(stmt->output_params)) return; + + // If an error occurs or an exception is thrown during an execution, the values of any output + // parameters or columns are undefined. Therefore, do not depend on them having any specific + // values, because the ODBC driver may or may not have modified them. + if (exception_thrown) { + zend_hash_clean(Z_ARRVAL(stmt->output_params)); + return; + } HashTable* params_ht = Z_ARRVAL(stmt->output_params); zend_ulong index = -1; @@ -2558,7 +2556,7 @@ void finalize_output_parameters( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) } void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, _Inout_ sqlsrv_phptype sqlsrv_php_type, - _Inout_updates_bytes_(*field_len) void*& field_value, _Inout_ SQLLEN* field_len TSRMLS_DC ) + _Inout_updates_bytes_(*field_len) void*& field_value, _Inout_ SQLLEN* field_len ) { SQLRETURN r; SQLSMALLINT c_type; @@ -2584,40 +2582,39 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind sql_field_type = stmt->current_meta_data[field_index]->field_type; // Calculate the field size. - calc_string_size( stmt, field_index, sql_field_type, sql_display_size TSRMLS_CC ); + calc_string_size( stmt, field_index, sql_field_type, sql_display_size ); col_cache cache( sql_field_type, sql_display_size ); - core::sqlsrv_zend_hash_index_update_mem( *stmt, Z_ARRVAL( stmt->col_cache ), field_index, &cache, sizeof( col_cache ) TSRMLS_CC ); + core::sqlsrv_zend_hash_index_update_mem( *stmt, Z_ARRVAL( stmt->col_cache ), field_index, &cache, sizeof( col_cache ) ); } // Determine the correct encoding if( sqlsrv_php_type.typeinfo.encoding == SQLSRV_ENCODING_DEFAULT ) { sqlsrv_php_type.typeinfo.encoding = stmt->conn->encoding(); } - // For numbers, no need to convert - if (is_a_numeric_type(sql_field_type)) { - sqlsrv_php_type.typeinfo.encoding = SQLSRV_ENCODING_CHAR; - } - // Set the C type and account for null characters at the end of the data. - switch( sqlsrv_php_type.typeinfo.encoding ) { - case CP_UTF8: - c_type = SQL_C_WCHAR; - extra = sizeof( SQLWCHAR ); - break; - case SQLSRV_ENCODING_BINARY: + if (sqlsrv_php_type.typeinfo.encoding == SQLSRV_ENCODING_BINARY) { c_type = SQL_C_BINARY; extra = 0; - break; - default: + } else { c_type = SQL_C_CHAR; - extra = sizeof( SQLCHAR ); - break; + extra = sizeof(SQLCHAR); + + // For numbers, no need to convert + if (sqlsrv_php_type.typeinfo.encoding == CP_UTF8 && !is_a_numeric_type(sql_field_type)) { + c_type = SQL_C_WCHAR; + extra = sizeof(SQLWCHAR); + } } - // if this is a large type, then read the first few bytes to get the actual length from SQLGetData - if( sql_display_size == 0 || sql_display_size == INT_MAX || - sql_display_size == INT_MAX >> 1 || sql_display_size == UINT_MAX - 1 ) { + // If this is a large type, then read the first few bytes to get the actual length from SQLGetData + // The user may use "SET TEXTSIZE" to specify the size of varchar(max), nvarchar(max), + // varbinary(max), text, ntext, and image data returned by a SELECT statement. + // For varchar(max) and nvarchar(max), sql_display_size will be 0, regardless + if (sql_display_size == 0 || sql_display_size == INT_MAX || + sql_display_size == INT_MAX >> 1 || sql_display_size == UINT_MAX - 1 || + (sql_display_size > SQL_SERVER_MAX_FIELD_SIZE && + (sql_field_type == SQL_WLONGVARCHAR || sql_field_type == SQL_LONGVARCHAR || sql_field_type == SQL_LONGVARBINARY))) { field_len_temp = intial_field_len; @@ -2626,7 +2623,7 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind field_value_temp = static_cast( sqlsrv_malloc( field_len_temp + extra + 1 )); r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp, ( field_len_temp + extra ), - &field_len_temp, false /*handle_warning*/ TSRMLS_CC ); + &field_len_temp, false /*handle_warning*/ ); CHECK_CUSTOM_ERROR(( r == SQL_NO_DATA ), stmt, SQLSRV_ERROR_NO_DATA, field_index ) { throw core::CoreException(); @@ -2643,7 +2640,7 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind SQLCHAR state[SQL_SQLSTATE_BUFSIZE] = {L'\0'}; SQLSMALLINT len = 0; - stmt->current_results->get_diag_field( 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len TSRMLS_CC ); + stmt->current_results->get_diag_field( 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len ); // with Linux connection pooling may not get a truncated warning back but the actual field_len_temp // can be greater than the initallen value. @@ -2673,7 +2670,7 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind // 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 ); + field_len_temp + extra, &dummy_field_len, false /*handle_warning*/ ); // 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 ) @@ -2683,7 +2680,7 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind if( r == SQL_SUCCESS_WITH_INFO ) { core::SQLGetDiagField( stmt, 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len - TSRMLS_CC ); + ); } } while( r == SQL_SUCCESS_WITH_INFO && is_truncated_warning( state )); @@ -2698,7 +2695,7 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind // 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 + extra, &dummy_field_len, true /*handle_warning*/ ); field_len_temp += intial_field_len; if( dummy_field_len == SQL_NULL_DATA ) { @@ -2720,8 +2717,7 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind } } // if( r == SQL_SUCCESS_WITH_INFO ) - if( sqlsrv_php_type.typeinfo.encoding == SQLSRV_ENCODING_UTF8 ) { - + if (c_type == SQL_C_WCHAR) { bool converted = convert_string_from_utf16_inplace( static_cast( sqlsrv_php_type.typeinfo.encoding ), &field_value_temp, field_len_temp ); @@ -2750,7 +2746,7 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind // get the data r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp, sql_display_size, - &field_len_temp, true /*handle_warning*/ TSRMLS_CC ); + &field_len_temp, true /*handle_warning*/ ); CHECK_SQL_ERROR( r, stmt ) { throw core::CoreException(); } @@ -2764,8 +2760,7 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind return; } - if( sqlsrv_php_type.typeinfo.encoding == CP_UTF8 ) { - + if (c_type == SQL_C_WCHAR) { bool converted = convert_string_from_utf16_inplace( static_cast( sqlsrv_php_type.typeinfo.encoding ), &field_value_temp, field_len_temp ); @@ -2828,7 +2823,7 @@ field_value = field_value_temp; // return the option from the stmt_opts array that matches the key. If no option found, // NULL is returned. -stmt_option const* get_stmt_option( sqlsrv_conn const* conn, _In_ zend_ulong key, _In_ const stmt_option stmt_opts[] TSRMLS_DC ) +stmt_option const* get_stmt_option( sqlsrv_conn const* conn, _In_ zend_ulong key, _In_ const stmt_option stmt_opts[] ) { for( int i = 0; stmt_opts[i].key != SQLSRV_STMT_OPTION_INVALID; ++i ) { @@ -2896,7 +2891,7 @@ bool is_valid_sqlsrv_phptype( _In_ sqlsrv_phptype type ) void resize_output_buffer_if_necessary( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval* param_z, _In_ SQLULEN paramno, SQLSRV_ENCODING encoding, _In_ SQLSMALLINT c_type, _In_ SQLSMALLINT sql_type, _In_ SQLULEN column_size, _In_ SQLSMALLINT decimal_digits, - _Out_writes_(buffer_len) SQLPOINTER& buffer, _Out_ SQLLEN& buffer_len TSRMLS_DC ) + _Out_writes_(buffer_len) SQLPOINTER& buffer, _Out_ SQLLEN& buffer_len ) { SQLSRV_ASSERT( column_size != SQLSRV_UNKNOWN_SIZE, "column size should be set to a known value." ); buffer_len = Z_STRLEN_P( param_z ); @@ -2972,159 +2967,11 @@ void resize_output_buffer_if_necessary( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval* } } -void adjustInputPrecision( _Inout_ zval* param_z, _In_ SQLSMALLINT decimal_digits ) { - // 38 is the maximum length of a stringified decimal number - size_t maxDecimalPrecision = 38; - // 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 - size_t maxDecimalStrLen = maxDecimalPrecision + 6; - if (Z_STRLEN_P(param_z) > maxDecimalStrLen) { - return; - } - std::vector digits; - unsigned char* ptr = reinterpret_cast(ZSTR_VAL( Z_STR_P( param_z ))); - bool isNeg = false; - bool isScientificNot = false; - char scientificChar = ' '; - short scientificExp = 0; - if( strchr( reinterpret_cast( ptr ), 'e' ) || strchr( reinterpret_cast( ptr ), 'E' )){ - isScientificNot = true; - } - // parse digits in param_z into the vector digits - if( *ptr == '+' || *ptr == '-' ){ - if( *ptr == '-' ){ - isNeg = true; - } - ptr++; - } - short numInt = 0; - short numDec = 0; - while( isdigit( *ptr )){ - digits.push_back( *ptr - '0' ); - ptr++; - numInt++; - } - if( *ptr == '.' ){ - ptr++; - if( !isScientificNot ){ - while( isdigit( *ptr ) && numDec < decimal_digits + 1 ){ - digits.push_back( *ptr - '0' ); - ptr++; - numDec++; - } - // make sure the rest of the number are digits - while( isdigit( *ptr )){ - ptr++; - } - } - else { - while( isdigit( *ptr )){ - digits.push_back( *ptr - '0' ); - ptr++; - numDec++; - } - } - } - if( isScientificNot ){ - if ( *ptr == 'e' || *ptr == 'E' ) { - scientificChar = *ptr; - } - ptr++; - bool isNegExp = false; - if( *ptr == '+' || *ptr == '-' ){ - if( *ptr == '-' ){ - isNegExp = true; - } - ptr++; - } - while( isdigit( *ptr )){ - scientificExp = scientificExp * 10 + ( *ptr - '0' ); - ptr++; - } - SQLSRV_ASSERT( scientificExp <= maxDecimalPrecision, "Input decimal overflow: sql decimal type only supports up to a precision of 38." ); - if( isNegExp ){ - scientificExp = scientificExp * -1; - } - } - // if ptr is not pointing to a null terminator at this point, that means the decimal string input is invalid - // do not change the string and let SQL Server handle the invalid decimal string - if ( *ptr != '\0' ) { - return; - } - // if number of decimal is less than the exponent, that means the number is a whole number, so no need to adjust the precision - if( numDec > scientificExp ){ - int decToRemove = numDec - scientificExp - decimal_digits; - if( decToRemove > 0 ){ - bool carryOver = false; - short backInd = 0; - // pop digits from the vector until there is only 1 more decimal place than required decimal_digits - while( decToRemove != 1 && !digits.empty() ){ - digits.pop_back(); - decToRemove--; - } - if( !digits.empty() ){ - // check if the last digit to be popped is greater than 5, if so, the digit before it needs to round up - carryOver = digits.back() >= 5; - digits.pop_back(); - backInd = static_cast(digits.size() - 1); - // round up from the end until no more carry over - while( carryOver && backInd >= 0 ){ - if( digits.at( backInd ) != 9 ){ - digits.at( backInd )++; - carryOver = false; - } - else{ - digits.at( backInd ) = 0; - } - backInd--; - } - } - std::ostringstream oss; - if( isNeg ){ - oss << '-'; - } - // insert 1 if carry over persist all the way to the beginning of the number - if( carryOver && backInd == -1 ){ - oss << 1; - } - if( digits.empty() && !carryOver ){ - oss << 0; - } - else{ - short i = 0; - for( i; i < numInt && i < digits.size(); i++ ){ - oss << digits[i]; - } - // fill string with 0 if the number of digits in digits is less then numInt - if( i < numInt ){ - for( i; i < numInt; i++ ){ - oss << 0; - } - } - if( numInt < digits.size() ){ - oss << '.'; - for( i; i < digits.size(); i++ ){ - oss << digits[i]; - } - } - if( scientificExp != 0 ){ - oss << scientificChar << std::to_string( scientificExp ); - } - } - std::string str = oss.str(); - zend_string* zstr = zend_string_init( str.c_str(), str.length(), 0 ); - zend_string_release( Z_STR_P( param_z )); - ZVAL_NEW_STR( param_z, zstr ); - } - } -} - // output parameters have their reference count incremented so that they do not disappear // while the query is executed and processed. They are saved in the statement so that // their reference count may be decremented later (after results are processed) -void save_output_param_for_later( _Inout_ sqlsrv_stmt* stmt, _Inout_ sqlsrv_output_param& param TSRMLS_DC ) +void save_output_param_for_later( _Inout_ sqlsrv_stmt* stmt, _Inout_ sqlsrv_output_param& param ) { HashTable* param_ht = Z_ARRVAL( stmt->output_params ); zend_ulong paramno = static_cast( param.param_num ); @@ -3135,9 +2982,9 @@ void save_output_param_for_later( _Inout_ sqlsrv_stmt* stmt, _Inout_ sqlsrv_outp // send all the stream data -void send_param_streams( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC ) +void send_param_streams( _Inout_ sqlsrv_stmt* stmt ) { - while( core_sqlsrv_send_stream_packet( stmt TSRMLS_CC )) { } + while( core_sqlsrv_send_stream_packet( stmt )) { } } @@ -3157,4 +3004,199 @@ void sqlsrv_stream_dtor( _Inout_ zval* data ) sqlsrv_free( stream_encoding ); } +void adjustDecimalPrecision(_Inout_ zval* param_z, _In_ SQLSMALLINT decimal_digits) +{ + char* value = Z_STRVAL_P(param_z); + short value_len = Z_STRLEN_P(param_z); + + // If the length is greater than maxDecimalStrLen, do not convert the string + // 6 is derived from: 1 for the decimal point; 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 + const int MAX_DECIMAL_STRLEN = SQL_SERVER_DECIMAL_MAXIMUM_PRECISION + 6; + if (value_len > MAX_DECIMAL_STRLEN) { + return; + } + + // If std::stold() succeeds, 'idx' is the position of the first character after the numerical value + long double d = 0; + size_t idx; + try { + d = std::stold(std::string(value), &idx); + } + catch (const std::logic_error& err) { + return; // invalid input caused the conversion to throw an exception + } + if (idx < value_len) { + return; // the input contains something else apart from the numerical value + } + + // Navigate to the first digit or the decimal point + bool is_negative = (d < 0); + char *src = value + is_negative; + while (*src != DECIMAL_POINT && !isdigit(*src)) { + src++; + } + + // Check if the value is in scientific notation + char *exp = strchr(src, 'E'); + if (exp == NULL) { + exp = strchr(src, 'e'); + } + + // Find the decimal point + char *pt = strchr(src, DECIMAL_POINT); + + char buffer[50] = " "; // A buffer with 2 blank spaces, as leeway + short offset = 1 + is_negative; // The position to start copying the original numerical value + + if (exp == NULL) { + if (pt == NULL) { + return; // decimal point not found + } + + short src_length = strlen(src); + short num_decimals = src_length - (pt - src) - 1; + if (num_decimals <= decimal_digits) { + return; // no need to adjust number of decimals + } + + memcpy_s(buffer + offset, src_length, src, src_length); + round_up_decimal_numbers(buffer, (pt - src) + offset, decimal_digits, offset, src_length + offset); + } + else { + int power = atoi(exp+1); + if (abs(power) > SQL_SERVER_DECIMAL_MAXIMUM_PRECISION) { + return; // Out of range, so let the server handle this + } + + short num_decimals = 0; + if (power == 0) { + // Simply chop off the exp part + short length = (exp - src); + memcpy_s(buffer + offset, length, src, length); + + if (pt != NULL) { + // Adjust decimal places only if decimal point is found and number of decimals more than decimal_digits + num_decimals = exp - pt - 1; + if (num_decimals > decimal_digits) { + round_up_decimal_numbers(buffer, (pt - src) + offset, decimal_digits, offset, length + offset); + } + } + } else { + short oldpos = 0; + if (pt == NULL) { + oldpos = exp - src; // Decimal point not found, use the exp sign + } + else { + oldpos = pt - src; + num_decimals = exp - pt - 1; + if (power > 0 && num_decimals <= power) { + return; // The result will be a whole number, do nothing and return + } + } + + // Derive the new position for the decimal point in the buffer + short newpos = oldpos + power; + if (power > 0) { + newpos = newpos + offset; + if (num_decimals == 0) { + memset(buffer + offset + oldpos, '0', power); // Fill parts of the buffer with zeroes first + } + else { + buffer[newpos] = DECIMAL_POINT; + } + } + else { + // The negative "power" part shows exactly how many places to move the decimal point. + // Whether to pad zeroes depending on the original position of the decimal point pos. + if (newpos <= 0) { + // If newpos is negative or zero, pad zeroes (size of '0.' + places to move) in the buffer + short numzeroes = 2 + abs(newpos); + memset(buffer + offset, '0', numzeroes); + newpos = offset + 1; // The new decimal position should be offset + '0' + buffer[newpos] = DECIMAL_POINT; // Replace that '0' with the decimal point + offset = numzeroes + offset; // Short offset now in the buffer + } + else { + newpos = newpos + offset; + buffer[newpos] = DECIMAL_POINT; + } + } + + // Start copying the content to the buffer until the exp sign or one more digit after decimal_digits + char *p = src; + short idx = offset; + short lastpos = newpos + decimal_digits + 1; + while (p != exp && idx <= lastpos) { + if (*p == DECIMAL_POINT) { + p++; + continue; + } + if (buffer[idx] == DECIMAL_POINT) { + idx++; + } + buffer[idx++] = *p; + p++; + } + // Round up is required only when number of decimals is more than decimal_digits + num_decimals = idx - newpos - 1; + if (num_decimals > decimal_digits) { + round_up_decimal_numbers(buffer, newpos, decimal_digits, offset, idx); + } + } + } + + // Set the minus sign if negative + if (is_negative) { + buffer[0] = '-'; + } + + zend_string* zstr = zend_string_init(buffer, strlen(buffer), 0); + zend_string_release(Z_STR_P(param_z)); + ZVAL_NEW_STR(param_z, zstr); +} + +int round_up_decimal_numbers(_Inout_ char* buffer, _In_ short decimal_pos, _In_ short num_decimals, _In_ short offset, _In_ short lastpos) +{ + // This helper method assumes the 'buffer' has some extra blank spaces at the beginning without the minus '-' sign. + // We want the rounding to be consistent with php number_format(), http://php.net/manual/en/function.number-format.php + // as well as SQL Server Management studio, such that the least significant digit will be rounded up if it is + // followed by 5 or above. + + short pos = decimal_pos + num_decimals + 1; + if (pos < lastpos) { + short n = buffer[pos] - '0'; + if (n >= 5) { + // Start rounding up - starting from the digit left of pos all the way to the first digit + bool carry_over = true; + for (short p = pos - 1; p >= offset && carry_over; p--) { + if (buffer[p] == DECIMAL_POINT) { + continue; + } + n = buffer[p] - '0'; + carry_over = (++n == 10); + if (n == 10) { + n = 0; + } + buffer[p] = '0' + n; + } + if (carry_over) { + buffer[offset - 1] = '1'; + } + } + if (num_decimals == 0) { + buffer[decimal_pos] = '\0'; + return decimal_pos; + } + else { + buffer[pos] = '\0'; + return pos; + } + } + + // Do nothing and just return + return lastpos; +} + + } diff --git a/source/shared/core_stream.cpp b/source/shared/core_stream.cpp index e0177652c..05f4224dd 100644 --- a/source/shared/core_stream.cpp +++ b/source/shared/core_stream.cpp @@ -3,7 +3,7 @@ // // Contents: Implementation of PHP streams for reading SQL Server data // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -23,7 +23,7 @@ namespace { // close a stream and free the PHP resources used by it -int sqlsrv_stream_close( _Inout_ php_stream* stream, int /*close_handle*/ TSRMLS_DC ) +int sqlsrv_stream_close( _Inout_ php_stream* stream, int /*close_handle*/ ) { sqlsrv_stream* ss = static_cast( stream->abstract ); SQLSRV_ASSERT( ss != NULL && ss->stmt != NULL, "sqlsrv_stream_close: sqlsrv_stream* ss was null." ); @@ -45,9 +45,9 @@ int sqlsrv_stream_close( _Inout_ php_stream* stream, int /*close_handle*/ TSRMLS // set when sqlsrv_get_field is called by the user specifying which field type they want. #if PHP_VERSION_ID >= 70400 -ssize_t sqlsrv_stream_read(_Inout_ php_stream* stream, _Out_writes_bytes_(count) char* buf, _Inout_ size_t count TSRMLS_DC) +ssize_t sqlsrv_stream_read(_Inout_ php_stream* stream, _Out_writes_bytes_(count) char* buf, _Inout_ size_t count) #else -size_t sqlsrv_stream_read(_Inout_ php_stream* stream, _Out_writes_bytes_(count) char* buf, _Inout_ size_t count TSRMLS_DC) +size_t sqlsrv_stream_read(_Inout_ php_stream* stream, _Out_writes_bytes_(count) char* buf, _Inout_ size_t count) #endif { SQLLEN read = 0; @@ -94,7 +94,7 @@ size_t sqlsrv_stream_read(_Inout_ php_stream* stream, _Out_writes_bytes_(count) } // Warnings will be handled below - SQLRETURN r = ss->stmt->current_results->get_data(ss->field_index + 1, c_type, get_data_buffer, count /*BufferLength*/, &read, false /*handle_warning*/ TSRMLS_CC); + SQLRETURN r = ss->stmt->current_results->get_data(ss->field_index + 1, c_type, get_data_buffer, count /*BufferLength*/, &read, false /*handle_warning*/); CHECK_SQL_ERROR( r, ss->stmt ) { stream->eof = 1; @@ -114,7 +114,7 @@ size_t sqlsrv_stream_read(_Inout_ php_stream* stream, _Out_writes_bytes_(count) SQLCHAR state[SQL_SQLSTATE_BUFSIZE] = {L'\0'}; SQLSMALLINT len = 0; - ss->stmt->current_results->get_diag_field( 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len TSRMLS_CC ); + ss->stmt->current_results->get_diag_field( 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len ); if( read == SQL_NO_TOTAL ) { SQLSRV_ASSERT( is_truncated_warning( state ), "sqlsrv_stream_read: truncation warning was expected but it " @@ -222,7 +222,7 @@ php_stream_ops sqlsrv_stream_ops = { // return value. There is only one valid way to open a stream, using sqlsrv_get_field on // certain field types. A sqlsrv stream may only be opened in read mode. static php_stream* sqlsrv_stream_opener( _In_opt_ php_stream_wrapper* wrapper, _In_ const char*, _In_ const char* mode, - _In_opt_ int options, _In_ zend_string **, php_stream_context* STREAMS_DC TSRMLS_DC ) + _In_opt_ int options, _In_ zend_string **, php_stream_context* STREAMS_DC ) { #if ZEND_DEBUG @@ -238,9 +238,12 @@ static php_stream* sqlsrv_stream_opener( _In_opt_ php_stream_wrapper* wrapper, _ ss = static_cast( sqlsrv_malloc( sizeof( sqlsrv_stream ))); memset( ss, 0, sizeof( sqlsrv_stream )); - // check for valid options - if( options != REPORT_ERRORS ) { - php_stream_wrapper_log_error( wrapper, options TSRMLS_CC, "Invalid option: no options except REPORT_ERRORS may be specified with a sqlsrv stream" ); + // The function core_get_field_common() is changed to pass REPORT_ERRORS for + // php_stream_open_wrapper(). Whether the error flag is toggled or cleared, + // the argument "options" will be zero. + // For details check this pull request: https://github.com/php/php-src/pull/6190 + if (options != 0) { + php_stream_wrapper_log_error(wrapper, options, "Invalid option: no options except REPORT_ERRORS may be specified with a sqlsrv stream"); return NULL; } diff --git a/source/shared/core_util.cpp b/source/shared/core_util.cpp index bc51b34bd..127a68e21 100644 --- a/source/shared/core_util.cpp +++ b/source/shared/core_util.cpp @@ -5,7 +5,7 @@ // // Comments: Mostly error handling and some type handling // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -57,7 +57,7 @@ void log_activity(_In_opt_ const char* msg, _In_opt_ va_list* print_args) std::copy(INTERNAL_FORMAT_ERROR, INTERNAL_FORMAT_ERROR + sizeof(INTERNAL_FORMAT_ERROR), log_msg); } - php_log_err(log_msg TSRMLS_CC); + php_log_err(log_msg); } } @@ -70,10 +70,10 @@ SQLCHAR SSPWARN[] = "01SSP"; // write to the php log if the severity and subsystem match the filters currently set in the INI or // the script (sqlsrv_configure). -void write_to_log( _In_ unsigned int severity TSRMLS_DC, _In_ const char* msg, ...) +void write_to_log( _In_ unsigned int severity, _In_ const char* msg, ...) { SQLSRV_ASSERT( !(g_driver_severity == NULL), "Must register a driver checker function." ); - if (!g_driver_severity(severity TSRMLS_CC)) { + if (!g_driver_severity(severity)) { return; } @@ -146,6 +146,11 @@ bool convert_string_from_utf16( _In_ SQLSRV_ENCODING encoding, _In_reads_bytes_( return true; } +#ifndef _WIN32 + // Allocate enough space to hold the largest possible number of bytes for UTF-8 conversion + // instead of calling FromUtf16, for performance reasons + cchOutLen = 4 * cchInLen; +#else // flags set to 0 by default, which means that any invalid characters are dropped rather than causing // an error. This happens only on XP. DWORD flags = 0; @@ -154,11 +159,6 @@ bool convert_string_from_utf16( _In_ SQLSRV_ENCODING encoding, _In_reads_bytes_( flags = WC_ERR_INVALID_CHARS; } -#ifndef _WIN32 - // Allocate enough space to hold the largest possible number of bytes for UTF-8 conversion - // instead of calling FromUtf16, for performance reasons - cchOutLen = 4*cchInLen; -#else // Calculate the number of output bytes required - no performance hit here because // WideCharToMultiByte is highly optimised cchOutLen = WideCharToMultiByte( encoding, flags, @@ -242,7 +242,7 @@ void convert_datetime_string_to_zval(_Inout_ sqlsrv_stmt* stmt, _In_opt_ char* i params[0] = value_temp_z; if (call_user_function(EG(function_table), NULL, &function_z, &out_zval, 1, - params TSRMLS_CC) == FAILURE) { + params) == FAILURE) { THROW_CORE_ERROR(stmt, SQLSRV_ERROR_DATETIME_CONVERSION_FAILED); } @@ -257,8 +257,7 @@ void convert_datetime_string_to_zval(_Inout_ sqlsrv_stmt* stmt, _In_opt_ char* i // 3/message) driver specific error message // The fetch type determines if the indices are numeric, associative, or both. -bool core_sqlsrv_get_odbc_error( _Inout_ sqlsrv_context& ctx, _In_ int record_number, _Inout_ sqlsrv_error_auto_ptr& error, _In_ logging_severity severity - TSRMLS_DC ) +bool core_sqlsrv_get_odbc_error( _Inout_ sqlsrv_context& ctx, _In_ int record_number, _Inout_ sqlsrv_error_auto_ptr& error, _In_ logging_severity severity, _In_opt_ bool check_warning /* = false */) { SQLHANDLE h = ctx.handle(); SQLSMALLINT h_type = ctx.handle_type(); @@ -297,17 +296,9 @@ bool core_sqlsrv_get_odbc_error( _Inout_ sqlsrv_context& ctx, _In_ int record_nu r = SQLGetDiagRecW( h_type, h, record_number, wsqlstate, &error->native_code, wnative_message, SQL_MAX_ERROR_MESSAGE_LENGTH + 1, &wmessage_len ); // don't use the CHECK* macros here since it will trigger reentry into the error handling system - // Workaround for a bug in unixODBC 2.3.4 when connection pooling is enabled (PDO SQLSRV). - // Instead of returning false, we return an empty error message to prevent the driver from throwing an exception. - // To reproduce: - // Create a connection and close it (return it to the pool) - // Create a new connection from the pool. - // Prepare and execute a statement that generates an info message (such as 'USE tempdb;') -#ifdef __APPLE__ - if( r == SQL_NO_DATA && ctx.driver() != NULL /*PDO SQLSRV*/ ) { - r = SQL_SUCCESS; - } -#endif // __APPLE__ + // removed the workaround for Mac users with unixODBC 2.3.4 when connection pooling is enabled (PDO SQLSRV), for two reasons: + // (1) not recommended to use connection pooling with unixODBC < 2.3.7 + // (2) the problem was not reproducible with unixODBC 2.3.7 if( !SQL_SUCCEEDED( r ) || r == SQL_NO_DATA ) { return false; } @@ -348,6 +339,15 @@ bool core_sqlsrv_get_odbc_error( _Inout_ sqlsrv_context& ctx, _In_ int record_nu break; } + // Only overrides 'severity' if 'check_warning' is true (false by default) + if (check_warning) { + // The character string value returned for an SQLSTATE consists of a two-character class value + // followed by a three-character subclass value. A class value of "01" indicates a warning. + // https://docs.microsoft.com/sql/odbc/reference/appendixes/appendix-a-odbc-error-codes?view=sql-server-ver15 + if (error->sqlstate[0] == '0' && error->sqlstate[1] == '1') { + severity = SEV_WARNING; + } + } // log the error first LOG( severity, "%1!s!: SQLSTATE = %2!s!", ctx.func(), error->sqlstate ); @@ -361,7 +361,7 @@ bool core_sqlsrv_get_odbc_error( _Inout_ sqlsrv_context& ctx, _In_ int record_nu // format and return a driver specfic error void core_sqlsrv_format_driver_error( _In_ sqlsrv_context& ctx, _In_ sqlsrv_error_const const* custom_error, - _Out_ sqlsrv_error_auto_ptr& formatted_error, _In_ logging_severity severity TSRMLS_DC, _In_opt_ va_list* args ) + _Out_ sqlsrv_error_auto_ptr& formatted_error, _In_ logging_severity severity, _In_opt_ va_list* args ) { // allocate space for the formatted message formatted_error = new (sqlsrv_malloc( sizeof( sqlsrv_error ))) sqlsrv_error(); @@ -489,6 +489,7 @@ namespace data_classification { const char* INFOTYPE = "Information Type"; const char* NAME = "name"; const char* ID = "id"; + const char* RANK = "rank"; void convert_sensivity_field(_Inout_ sqlsrv_stmt* stmt, _In_ SQLSRV_ENCODING encoding, _In_ unsigned char *ptr, _In_ int len, _Inout_updates_bytes_(cchOutLen) char** field_name) { @@ -566,10 +567,18 @@ namespace data_classification { *pptr = ptr; } - void parse_column_sensitivity_props(_Inout_ sensitivity_metadata* meta, _Inout_ unsigned char **pptr) + void parse_column_sensitivity_props(_Inout_ sensitivity_metadata* meta, _Inout_ unsigned char **pptr, _In_ bool getRankInfo) { unsigned char *ptr = *pptr; unsigned short ncols; + int queryrank, colrank; + + // Get rank info + if (getRankInfo) { + queryrank = *(reinterpret_cast(ptr)); + ptr += sizeof(int); + meta->rank = queryrank; + } // Get number of columns meta->num_columns = ncols = *(reinterpret_cast(ptr)); @@ -594,6 +603,12 @@ namespace data_classification { typeidx = *(reinterpret_cast(ptr)); ptr += sizeof(unsigned short); + if (getRankInfo) { + colrank = *(reinterpret_cast(ptr)); + ptr += sizeof(int); + pair.rank = colrank; + } + pair.label_idx = labelidx; pair.infotype_idx = typeidx; @@ -606,7 +621,7 @@ namespace data_classification { *pptr = ptr; } - USHORT fill_column_sensitivity_array(_Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT colno, _Inout_ zval *return_array TSRMLS_CC) + USHORT fill_column_sensitivity_array(_Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT colno, _Inout_ zval *return_array) { sensitivity_metadata* meta = stmt->current_sensitivity_metadata; if (meta == NULL) { @@ -617,52 +632,64 @@ namespace data_classification { zval data_classification; ZVAL_UNDEF(&data_classification); - core::sqlsrv_array_init(*stmt, &data_classification TSRMLS_CC ); + array_init(&data_classification); USHORT num_pairs = meta->columns_sensitivity[colno].num_pairs; if (num_pairs == 0) { - core::sqlsrv_add_assoc_zval(*stmt, return_array, DATA_CLASS, &data_classification TSRMLS_CC); + add_assoc_zval(return_array, DATA_CLASS, &data_classification); return 0; } zval sensitivity_properties; ZVAL_UNDEF(&sensitivity_properties); - core::sqlsrv_array_init(*stmt, &sensitivity_properties TSRMLS_CC); + array_init(&sensitivity_properties); for (USHORT j = 0; j < num_pairs; j++) { zval label_array, infotype_array; ZVAL_UNDEF(&label_array); ZVAL_UNDEF(&infotype_array); - core::sqlsrv_array_init(*stmt, &label_array TSRMLS_CC); - core::sqlsrv_array_init(*stmt, &infotype_array TSRMLS_CC); + array_init(&label_array); + array_init(&infotype_array); USHORT labelidx = meta->columns_sensitivity[colno].label_info_pairs[j].label_idx; USHORT typeidx = meta->columns_sensitivity[colno].label_info_pairs[j].infotype_idx; + int column_rank = meta->columns_sensitivity[colno].label_info_pairs[j].rank; char *label = meta->labels[labelidx]->name; char *label_id = meta->labels[labelidx]->id; char *infotype = meta->infotypes[typeidx]->name; char *infotype_id = meta->infotypes[typeidx]->id; - core::sqlsrv_add_assoc_string(*stmt, &label_array, NAME, label, 1 TSRMLS_CC); - core::sqlsrv_add_assoc_string(*stmt, &label_array, ID, label_id, 1 TSRMLS_CC); + add_assoc_string(&label_array, NAME, label); + add_assoc_string(&label_array, ID, label_id); - core::sqlsrv_add_assoc_zval(*stmt, &sensitivity_properties, LABEL, &label_array TSRMLS_CC); + add_assoc_zval(&sensitivity_properties, LABEL, &label_array); - core::sqlsrv_add_assoc_string(*stmt, &infotype_array, NAME, infotype, 1 TSRMLS_CC); - core::sqlsrv_add_assoc_string(*stmt, &infotype_array, ID, infotype_id, 1 TSRMLS_CC); + add_assoc_string(&infotype_array, NAME, infotype); + add_assoc_string(&infotype_array, ID, infotype_id); - core::sqlsrv_add_assoc_zval(*stmt, &sensitivity_properties, INFOTYPE, &infotype_array TSRMLS_CC); + add_assoc_zval(&sensitivity_properties, INFOTYPE, &infotype_array); + + // add column sensitivity rank info to sensitivity_properties + if (column_rank > RANK_NOT_DEFINED) { + add_assoc_long(&sensitivity_properties, RANK, column_rank); + } // add the pair of sensitivity properties to data_classification - core::sqlsrv_add_next_index_zval(*stmt, &data_classification, &sensitivity_properties TSRMLS_CC ); + add_next_index_zval(&data_classification, &sensitivity_properties); + } + + // add query sensitivity rank info to data_classification + int query_rank = meta->rank; + if (query_rank > RANK_NOT_DEFINED) { + add_assoc_long(&data_classification, RANK, query_rank); } // add data classfication as associative array - core::sqlsrv_add_assoc_zval(*stmt, return_array, DATA_CLASS, &data_classification TSRMLS_CC); + add_assoc_zval(return_array, DATA_CLASS, &data_classification); return num_pairs; } diff --git a/source/shared/globalization.h b/source/shared/globalization.h index 81091fc5f..060bbb24c 100644 --- a/source/shared/globalization.h +++ b/source/shared/globalization.h @@ -4,7 +4,7 @@ // Contents: Contains functions for handling Windows format strings // and UTF-16 on non-Windows platforms // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/interlockedatomic.h b/source/shared/interlockedatomic.h index c2ae4d26a..4e7ef9ca0 100644 --- a/source/shared/interlockedatomic.h +++ b/source/shared/interlockedatomic.h @@ -4,7 +4,7 @@ // Contents: Contains a portable abstraction for interlocked, atomic // operations on int32_t and pointer types. // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/interlockedatomic_gcc.h b/source/shared/interlockedatomic_gcc.h index 9eff99f5b..fbda09283 100644 --- a/source/shared/interlockedatomic_gcc.h +++ b/source/shared/interlockedatomic_gcc.h @@ -4,7 +4,7 @@ // Contents: Contains a portable abstraction for interlocked, atomic // operations on int32_t and pointer types. // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/interlockedslist.h b/source/shared/interlockedslist.h index 8def1dc2d..bb32fb862 100644 --- a/source/shared/interlockedslist.h +++ b/source/shared/interlockedslist.h @@ -4,7 +4,7 @@ // Contents: Contains a portable abstraction for interlocked, singly // linked list. // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/localization.hpp b/source/shared/localization.hpp index ec339d8c6..da918d6d0 100644 --- a/source/shared/localization.hpp +++ b/source/shared/localization.hpp @@ -3,7 +3,7 @@ // // Contents: Contains portable classes for localization // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -247,6 +247,7 @@ inline UINT SystemLocale::MaxCharCchSize( UINT codepage ) switch ( codepage ) { case CP_UTF8: + case 54936: return 4; case 932: case 936: diff --git a/source/shared/localizationimpl.cpp b/source/shared/localizationimpl.cpp index 22cc8bf6c..581e953f2 100644 --- a/source/shared/localizationimpl.cpp +++ b/source/shared/localizationimpl.cpp @@ -5,7 +5,7 @@ // Must be included in one c/cpp file per binary // A build error will occur if this inclusion policy is not followed // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -77,6 +77,7 @@ const cp_iconv cp_iconv::g_cp_iconv[] = { { 1256, "CP1256" TRANSLIT }, { 1257, "CP1257" TRANSLIT }, { 1258, "CP1258" TRANSLIT }, + { 54936, "GB18030" TRANSLIT}, { CP_ISO8859_1, "ISO8859-1" TRANSLIT }, { CP_ISO8859_2, "ISO8859-2" TRANSLIT }, { CP_ISO8859_3, "ISO8859-3" TRANSLIT }, @@ -342,6 +343,11 @@ SystemLocale::SystemLocale( const char * localeName ) const LocaleCP lcpTable[] = { { "utf8", CP_UTF8 }, { "UTF-8", CP_UTF8 }, + { "BIG5", 950 }, + { "BIG5-HKSCS", 950 }, + { "gb18030", 54936 }, + { "gb2312", 936 }, + { "gbk", 936 }, CPxxx(1252), CPxxx(850), CPxxx(437), CPxxx(874), CPxxx(932), CPxxx(936), CPxxx(949), CPxxx(950), CPxxx(1250), CPxxx(1251), CPxxx(1253), CPxxx(1254), CPxxx(1255), CPxxx(1256), CPxxx(1257), CPxxx(1258), ISO8859(1), ISO8859(2), ISO8859(3), ISO8859(4), ISO8859(5), ISO8859(6), diff --git a/source/shared/msodbcsql.h b/source/shared/msodbcsql.h index bcca30870..436fa7fa5 100644 --- a/source/shared/msodbcsql.h +++ b/source/shared/msodbcsql.h @@ -20,7 +20,7 @@ // pecuniary loss) arising out of the use of or inability to use // this SDK, even if Microsoft has been advised of the possibility // of such damages. -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -94,6 +94,10 @@ #define SQL_COPT_SS_AUTHENTICATION (SQL_COPT_SS_BASE_EX+15)// The authentication method used for the connection #define SQL_COPT_SS_ACCESS_TOKEN (SQL_COPT_SS_BASE_EX+16)// The authentication access token used for the connection +/* SQLSetConnectAttr MS driver additional specific defines. */ +#define SQL_COPT_SS_BASE_ADD 1400 +#define SQL_COPT_SS_DATACLASSIFICATION_VERSION (SQL_COPT_SS_BASE_ADD + 0) // The flag to Set/Get DATACLASSIFICATION version support + // SQLColAttributes driver specific defines. // SQLSetDescField/SQLGetDescField driver specific defines. // Microsoft has 1200 thru 1249 reserved for Microsoft ODBC Driver for SQL Server usage. @@ -146,6 +150,7 @@ // Data Classification #define SQL_CA_SS_DATA_CLASSIFICATION (SQL_CA_SS_BASE+37) // retrieve data classification information +#define SQL_CA_SS_DATA_CLASSIFICATION_VERSION (SQL_CA_SS_BASE+38) // retrieve data classification version #define SQL_CA_SS_MAX_USED (SQL_CA_SS_BASE+38) diff --git a/source/shared/sal_def.h b/source/shared/sal_def.h index 7b191eb76..a79ee9e3a 100644 --- a/source/shared/sal_def.h +++ b/source/shared/sal_def.h @@ -3,7 +3,7 @@ // // Contents: Contains the minimal definitions to build on non-Windows platforms // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/typedefs_for_linux.h b/source/shared/typedefs_for_linux.h index b4fb63a6a..8df22852e 100644 --- a/source/shared/typedefs_for_linux.h +++ b/source/shared/typedefs_for_linux.h @@ -1,7 +1,7 @@ //--------------------------------------------------------------------------------------------------------------------------------- // File: typedefs_for_linux.h // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/version.h b/source/shared/version.h index 40ae57f62..616b28b9b 100644 --- a/source/shared/version.h +++ b/source/shared/version.h @@ -4,7 +4,7 @@ // File: version.h // Contents: Version number constants // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -26,12 +26,12 @@ // Increase Minor with backward compatible new functionalities and API changes. // Increase Patch for backward compatible fixes. #define SQLVERSION_MAJOR 5 -#define SQLVERSION_MINOR 8 -#define SQLVERSION_PATCH 1 +#define SQLVERSION_MINOR 9 +#define SQLVERSION_PATCH 0 #define SQLVERSION_BUILD 0 -// For previews, set this constant to 1. Otherwise, set it to 0 -#define PREVIEW 0 +// For previews, set this constant to 1, 2 and so on. Otherwise, set it to 0 +#define PREVIEW 1 #define SEMVER_PRERELEASE // Semantic versioning build metadata, build meta data is not counted in precedence order. @@ -52,7 +52,7 @@ // "preview" for ETP #if PREVIEW > 0 #undef SEMVER_PRERELEASE -#define SEMVER_PRERELEASE "preview" +#define SEMVER_PRERELEASE "preview" STRINGIFY(PREVIEW) #define VER_FILEVERSION_STR VER_APIVERSION_STR "-" SEMVER_PRERELEASE SEMVER_BUILDMETA #else #define VER_FILEVERSION_STR VER_APIVERSION_STR SEMVER_PRERELEASE SEMVER_BUILDMETA diff --git a/source/shared/xplat.h b/source/shared/xplat.h index dbf862b13..188255558 100644 --- a/source/shared/xplat.h +++ b/source/shared/xplat.h @@ -3,7 +3,7 @@ // // Contents: include for definition of Windows types for non-Windows platforms // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/xplat_intsafe.h b/source/shared/xplat_intsafe.h index e64e4c518..a1bde6c8f 100644 --- a/source/shared/xplat_intsafe.h +++ b/source/shared/xplat_intsafe.h @@ -4,7 +4,7 @@ // Contents: This module defines helper functions to prevent // integer overflow bugs. // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/xplat_winerror.h b/source/shared/xplat_winerror.h index 8ae8ee402..1de5524ac 100644 --- a/source/shared/xplat_winerror.h +++ b/source/shared/xplat_winerror.h @@ -3,7 +3,7 @@ // // Contents: Contains the minimal definitions to build on non-Windows platforms // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/shared/xplat_winnls.h b/source/shared/xplat_winnls.h index f6d75a614..a66983220 100644 --- a/source/shared/xplat_winnls.h +++ b/source/shared/xplat_winnls.h @@ -3,7 +3,7 @@ // // Contents: Contains the minimal definitions to build on non-Windows platforms // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/sqlsrv/config.m4 b/source/sqlsrv/config.m4 index 240c09cf6..8b3bf49e3 100644 --- a/source/sqlsrv/config.m4 +++ b/source/sqlsrv/config.m4 @@ -4,7 +4,7 @@ dnl dnl Contents: the code that will go into the configure script, indicating options, dnl external libraries and includes, and what source files are to be compiled. dnl -dnl Microsoft Drivers 5.8 for PHP for SQL Server +dnl Microsoft Drivers 5.9 for PHP for SQL Server dnl Copyright(c) Microsoft Corporation dnl All rights reserved. dnl MIT License diff --git a/source/sqlsrv/config.w32 b/source/sqlsrv/config.w32 index 57cae3e7f..bb8d1ecb3 100644 --- a/source/sqlsrv/config.w32 +++ b/source/sqlsrv/config.w32 @@ -3,7 +3,7 @@ // // Contents: JScript build configuration used by buildconf.bat // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/sqlsrv/conn.cpp b/source/sqlsrv/conn.cpp index 58aaf14bf..d5c61cfae 100644 --- a/source/sqlsrv/conn.cpp +++ b/source/sqlsrv/conn.cpp @@ -3,7 +3,7 @@ // // Contents: Routines that use connection handles // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -35,10 +35,8 @@ unsigned int current_log_subsystem = LOG_CONN; struct date_as_string_func { - static void func( connection_option const* /*option*/, _In_ zval* value, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/ TSRMLS_DC ) + static void func( connection_option const* /*option*/, _In_ zval* value, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/ ) { - TSRMLS_C; // show as used to avoid a warning - ss_sqlsrv_conn* ss_conn = static_cast( conn ); if( zend_is_true( value )) { @@ -52,10 +50,8 @@ struct date_as_string_func { struct format_decimals_func { - static void func(connection_option const* /*option*/, _In_ zval* value, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/ TSRMLS_DC) + static void func(connection_option const* /*option*/, _In_ zval* value, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/) { - TSRMLS_C; // show as used to avoid a warning - ss_sqlsrv_conn* ss_conn = static_cast(conn); if (zend_is_true(value)) { @@ -70,10 +66,8 @@ struct format_decimals_func struct decimal_places_func { - static void func(connection_option const* /*option*/, _In_ zval* value, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/ TSRMLS_DC) + static void func(connection_option const* /*option*/, _In_ zval* value, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/) { - TSRMLS_C; // show as used to avoid a warning - // first check if the input is an integer if (Z_TYPE_P(value) != IS_LONG) { THROW_SS_ERROR(conn, SQLSRV_ERROR_INVALID_DECIMAL_PLACES); @@ -91,7 +85,7 @@ struct decimal_places_func struct conn_char_set_func { - static void func( connection_option const* /*option*/, _Inout_ zval* value, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/ TSRMLS_DC ) + static void func( connection_option const* /*option*/, _Inout_ zval* value, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/ ) { convert_to_string( value ); const char* encoding = Z_STRVAL_P( value ); @@ -121,9 +115,8 @@ struct conn_char_set_func { struct bool_conn_str_func { - static void func( _In_ connection_option const* option, _In_ zval* value, sqlsrv_conn* /*conn*/, _Out_ std::string& conn_str TSRMLS_DC ) + static void func( _In_ connection_option const* option, _In_ zval* value, sqlsrv_conn* /*conn*/, _Out_ std::string& conn_str ) { - TSRMLS_C; char const* val_str; if( zend_is_true( value )) { val_str = "yes"; @@ -140,9 +133,8 @@ struct bool_conn_str_func { struct int_conn_str_func { - static void func( _In_ connection_option const* option, _In_ zval* value, sqlsrv_conn* /*conn*/, _Out_ std::string& conn_str TSRMLS_DC ) + static void func( _In_ connection_option const* option, _In_ zval* value, sqlsrv_conn* /*conn*/, _Out_ std::string& conn_str ) { - TSRMLS_C; SQLSRV_ASSERT( Z_TYPE_P( value ) == IS_LONG, "An integer is expected for this keyword" ) std::string val_str = std::to_string( Z_LVAL_P( value )); @@ -157,11 +149,11 @@ struct int_conn_str_func { template struct int_conn_attr_func { - static void func( connection_option const* /*option*/, _In_ zval* value, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/ TSRMLS_DC ) + static void func( connection_option const* /*option*/, _In_ zval* value, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/ ) { try { - core::SQLSetConnectAttr( conn, Attr, reinterpret_cast( Z_LVAL_P( value )), SQL_IS_UINTEGER TSRMLS_CC ); + core::SQLSetConnectAttr( conn, Attr, reinterpret_cast( Z_LVAL_P( value )), SQL_IS_UINTEGER ); } catch( core::CoreException& ) { throw; @@ -172,10 +164,10 @@ struct int_conn_attr_func { template struct bool_conn_attr_func { - static void func( connection_option const* /*option*/, _In_ zval* value, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/ TSRMLS_DC ) + static void func( connection_option const* /*option*/, _In_ zval* value, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/ ) { try { - core::SQLSetConnectAttr(conn, Attr, reinterpret_cast((zend_long)zend_is_true(value)), SQL_IS_UINTEGER TSRMLS_CC); + core::SQLSetConnectAttr(conn, Attr, reinterpret_cast((zend_long)zend_is_true(value)), SQL_IS_UINTEGER); } catch( core::CoreException& ) { @@ -187,15 +179,15 @@ struct bool_conn_attr_func { //// *** internal functions *** -void sqlsrv_conn_close_stmts( _Inout_ ss_sqlsrv_conn* conn TSRMLS_DC ); +void sqlsrv_conn_close_stmts( _Inout_ ss_sqlsrv_conn* conn ); void validate_conn_options( _Inout_ sqlsrv_context& ctx, _In_ zval* user_options_z, _Inout_ char** uid, _Inout_ char** pwd, - _Inout_ HashTable* ss_conn_options_ht TSRMLS_DC ); -void validate_stmt_options( _Inout_ sqlsrv_context& ctx, _Inout_ zval* stmt_options, _Inout_ HashTable* ss_stmt_options_ht TSRMLS_DC ); + _Inout_ HashTable* ss_conn_options_ht ); +void validate_stmt_options( _Inout_ sqlsrv_context& ctx, _Inout_ zval* stmt_options, _Inout_ HashTable* ss_stmt_options_ht ); void add_conn_option_key( _Inout_ sqlsrv_context& ctx, _In_ zend_string* key, _In_ size_t key_len, - _Inout_ HashTable* options_ht, _Inout_ zval* data TSRMLS_DC ); -void add_stmt_option_key( _Inout_ sqlsrv_context& ctx, _In_ zend_string* key, _In_ size_t key_len, _Inout_ HashTable* options_ht, _Inout_ zval* data TSRMLS_DC ); -int get_conn_option_key( _Inout_ sqlsrv_context& ctx, _In_ zend_string* key, _In_ size_t key_len, _Inout_ zval const* value_z TSRMLS_DC ); -int get_stmt_option_key( _In_ zend_string* key, _In_ size_t key_len TSRMLS_DC ); + _Inout_ HashTable* options_ht, _Inout_ zval* data ); +void add_stmt_option_key( _Inout_ sqlsrv_context& ctx, _In_ zend_string* key, _In_ size_t key_len, _Inout_ HashTable* options_ht, _Inout_ zval* data ); +int get_conn_option_key( _Inout_ sqlsrv_context& ctx, _In_ zend_string* key, _In_ size_t key_len, _Inout_ zval const* value_z ); +int get_stmt_option_key( _In_ zend_string* key, _In_ size_t key_len ); } @@ -633,7 +625,7 @@ PHP_FUNCTION ( sqlsrv_connect ) g_ss_henv_cp->set_func(_FN_); g_ss_henv_ncp->set_func(_FN_); - reset_errors( TSRMLS_C ); + reset_errors(); const char* server = NULL; zval* options_z = NULL; @@ -643,7 +635,7 @@ PHP_FUNCTION ( sqlsrv_connect ) zval conn_z; ZVAL_UNDEF(&conn_z); // get the server name and connection options - int result = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s|a", &server, &server_len, &options_z ); + int result = zend_parse_parameters( ZEND_NUM_ARGS(), "s|a", &server, &server_len, &options_z ); CHECK_CUSTOM_ERROR(( result == FAILURE ), *g_ss_henv_cp, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, "sqlsrv_connect" ) { RETURN_FALSE; @@ -659,26 +651,26 @@ PHP_FUNCTION ( sqlsrv_connect ) ALLOC_HASHTABLE( ss_conn_options_ht ); core::sqlsrv_zend_hash_init( *g_ss_henv_cp, ss_conn_options_ht, 10 /* # of buckets */, - ZVAL_PTR_DTOR, 0 /*persistent*/ TSRMLS_CC ); + ZVAL_PTR_DTOR, 0 /*persistent*/ ); // Either of g_ss_henv_cp or g_ss_henv_ncp can be used to propagate the error. - ::validate_conn_options( *g_ss_henv_cp, options_z, &uid, &pwd, ss_conn_options_ht TSRMLS_CC ); + ::validate_conn_options( *g_ss_henv_cp, options_z, &uid, &pwd, ss_conn_options_ht ); // call the core connect function conn = static_cast( core_sqlsrv_connect( *g_ss_henv_cp, *g_ss_henv_ncp, &core::allocate_conn, server, uid, pwd, ss_conn_options_ht, ss_error_handler, - SS_CONN_OPTS, NULL, "sqlsrv_connect" TSRMLS_CC )); + SS_CONN_OPTS, NULL, "sqlsrv_connect" )); SQLSRV_ASSERT( conn != NULL, "sqlsrv_connect: Invalid connection returned. Exception should have been thrown." ); // create a bunch of statements ALLOC_HASHTABLE( stmts ); - core::sqlsrv_zend_hash_init( *g_ss_henv_cp, stmts, 5, NULL /* dtor */, 0 /* persistent */ TSRMLS_CC ); + core::sqlsrv_zend_hash_init( *g_ss_henv_cp, stmts, 5, NULL /* dtor */, 0 /* persistent */ ); // register the connection with the PHP runtime - ss::zend_register_resource(conn_z, conn, ss_sqlsrv_conn::descriptor, ss_sqlsrv_conn::resource_name TSRMLS_CC); + ss::zend_register_resource(conn_z, conn, ss_sqlsrv_conn::descriptor, ss_sqlsrv_conn::resource_name); conn->stmts = stmts; stmts.transferred(); @@ -739,7 +731,7 @@ PHP_FUNCTION( sqlsrv_begin_transaction ) try { - core_sqlsrv_begin_transaction( conn TSRMLS_CC ); + core_sqlsrv_begin_transaction( conn ); conn->in_transaction = true; RETURN_TRUE; } @@ -778,7 +770,7 @@ PHP_FUNCTION( sqlsrv_close ) ss_sqlsrv_conn* conn = NULL; sqlsrv_context_auto_ptr error_ctx; - reset_errors( TSRMLS_C ); + reset_errors(); try { @@ -786,10 +778,10 @@ PHP_FUNCTION( sqlsrv_close ) error_ctx = new (sqlsrv_malloc( sizeof( sqlsrv_context ))) sqlsrv_context( 0, ss_error_handler, NULL ); error_ctx->set_func(_FN_); - if( zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &conn_r) == FAILURE ) { + if( zend_parse_parameters(ZEND_NUM_ARGS(), "r", &conn_r) == FAILURE ) { // Check if it was a zval - int zr = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "z", &conn_r ); + int zr = zend_parse_parameters( ZEND_NUM_ARGS(), "z", &conn_r ); CHECK_CUSTOM_ERROR(( zr == FAILURE ), error_ctx, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ ) { throw ss::SSException(); } @@ -803,7 +795,7 @@ PHP_FUNCTION( sqlsrv_close ) } } SQLSRV_ASSERT( conn_r != NULL, "sqlsrv_close: conn_r was null" ); - conn = static_cast( zend_fetch_resource( Z_RES_P( conn_r ) TSRMLS_CC, ss_sqlsrv_conn::resource_name, ss_sqlsrv_conn::descriptor )); + conn = static_cast( zend_fetch_resource( Z_RES_P( conn_r ), ss_sqlsrv_conn::resource_name, ss_sqlsrv_conn::descriptor )); // if sqlsrv_close was called on an already closed connection then we just return success. if ( Z_RES_TYPE_P( conn_r ) == RSRC_INVALID_TYPE) { @@ -820,9 +812,13 @@ PHP_FUNCTION( sqlsrv_close ) // cause any variables still holding a reference to this to be invalid so they cause // an error when passed to a sqlsrv function. There's nothing we can do if the // removal fails, so we just log it and move on. - if( zend_list_close( Z_RES_P( conn_r ) ) == FAILURE ) { - LOG( SEV_ERROR, "Failed to remove connection resource %1!d!", Z_RES_HANDLE_P( conn_r )); +#if PHP_VERSION_ID < 80000 + if (zend_list_close(Z_RES_P(conn_r)) == FAILURE) { + LOG(SEV_ERROR, "Failed to remove connection resource %1!d!", Z_RES_HANDLE_P(conn_r)); } +#else + zend_list_close(Z_RES_P(conn_r)); +#endif // when conn_r is first parsed in zend_parse_parameters, conn_r becomes a zval that points to a zend_resource with a refcount of 2 // need to DELREF here so the refcount becomes 1 and conn_r can be appropriate destroyed by the garbage collector when it goes out of scope @@ -842,7 +838,7 @@ PHP_FUNCTION( sqlsrv_close ) } } -void __cdecl sqlsrv_conn_dtor( _Inout_ zend_resource *rsrc TSRMLS_DC ) +void __cdecl sqlsrv_conn_dtor( _Inout_ zend_resource *rsrc ) { // Without sqlsrv_close(), this function is invoked by php during the final clean up stage. // To prevent memory/resource leaks, no more logging at this point. @@ -855,10 +851,10 @@ void __cdecl sqlsrv_conn_dtor( _Inout_ zend_resource *rsrc TSRMLS_DC ) conn->set_func(__func__); // close all statements associated with the connection. - sqlsrv_conn_close_stmts( conn TSRMLS_CC ); + sqlsrv_conn_close_stmts( conn ); // close the connection itself. - core_sqlsrv_close( conn TSRMLS_CC ); + core_sqlsrv_close( conn ); rsrc->ptr = NULL; } @@ -901,7 +897,7 @@ PHP_FUNCTION( sqlsrv_commit ) try { conn->in_transaction = false; - core_sqlsrv_commit( conn TSRMLS_CC ); + core_sqlsrv_commit( conn ); RETURN_TRUE; } @@ -955,7 +951,7 @@ PHP_FUNCTION( sqlsrv_rollback ) try { conn->in_transaction = false; - core_sqlsrv_rollback( conn TSRMLS_CC ); + core_sqlsrv_rollback( conn ); RETURN_TRUE; } catch( core::CoreException& ){ @@ -975,28 +971,22 @@ PHP_FUNCTION( sqlsrv_rollback ) PHP_FUNCTION( sqlsrv_client_info ) { - LOG_FUNCTION( "sqlsrv_client_info" ); ss_sqlsrv_conn* conn = NULL; PROCESS_PARAMS( conn, "r", _FN_, 0 ); try { + core_sqlsrv_get_client_info(conn, return_value); - core_sqlsrv_get_client_info( conn, return_value TSRMLS_CC ); - // Add the sqlsrv driver's file version //Declarations below eliminate compiler warnings about string constant to char* conversions const char* extver = "ExtensionVer"; std::string filever = VER_FILEVERSION_STR; - core::sqlsrv_add_assoc_string( *conn, return_value, extver, &filever[0], 1 /*duplicate*/ TSRMLS_CC ); - } - - catch( core::CoreException& ) { + add_assoc_string(return_value, extver, &filever[0]); + } catch (core::CoreException&) { RETURN_FALSE; - } - catch( ... ) { - - DIE( "sqlsrv_client_info: Unknown exception caught." ); + } catch (...) { + DIE("sqlsrv_client_info: Unknown exception caught."); } } @@ -1019,20 +1009,15 @@ PHP_FUNCTION( sqlsrv_client_info ) PHP_FUNCTION( sqlsrv_server_info ) { try { - - LOG_FUNCTION( "sqlsrv_server_info" ); + LOG_FUNCTION("sqlsrv_server_info"); ss_sqlsrv_conn* conn = NULL; - PROCESS_PARAMS( conn, "r", _FN_, 0 ); + PROCESS_PARAMS(conn, "r", _FN_, 0); - core_sqlsrv_get_server_info( conn, return_value TSRMLS_CC ); - } - - catch( core::CoreException& ) { + core_sqlsrv_get_server_info(conn, return_value); + } catch (core::CoreException&) { RETURN_FALSE; - } - catch( ... ) { - - DIE( "sqlsrv_server_info: Unknown exception caught." ); + } catch (...) { + DIE("sqlsrv_server_info: Unknown exception caught."); } } @@ -1093,9 +1078,9 @@ PHP_FUNCTION( sqlsrv_prepare ) // Initialize the options array to be passed to the core layer ALLOC_HASHTABLE( ss_stmt_options_ht ); core::sqlsrv_zend_hash_init( *conn , ss_stmt_options_ht, 5 /* # of buckets */, - ZVAL_PTR_DTOR, 0 /*persistent*/ TSRMLS_CC ); + ZVAL_PTR_DTOR, 0 /*persistent*/ ); - validate_stmt_options( *conn, options_z, ss_stmt_options_ht TSRMLS_CC ); + validate_stmt_options( *conn, options_z, ss_stmt_options_ht ); } @@ -1114,9 +1099,9 @@ PHP_FUNCTION( sqlsrv_prepare ) stmt = static_cast( core_sqlsrv_create_stmt( conn, core::allocate_stmt, ss_stmt_options_ht, SS_STMT_OPTS, - ss_error_handler, NULL TSRMLS_CC ) ); + ss_error_handler, NULL ) ); - core_sqlsrv_prepare( stmt, sql, sql_len TSRMLS_CC ); + core_sqlsrv_prepare( stmt, sql, sql_len ); if (params_z) { stmt->params_z = (zval *)sqlsrv_malloc(sizeof(zval)); @@ -1126,13 +1111,13 @@ PHP_FUNCTION( sqlsrv_prepare ) stmt->prepared = true; // register the statement with the PHP runtime - ss::zend_register_resource( stmt_z, stmt, ss_sqlsrv_stmt::descriptor, ss_sqlsrv_stmt::resource_name TSRMLS_CC ); + ss::zend_register_resource( stmt_z, stmt, ss_sqlsrv_stmt::descriptor, ss_sqlsrv_stmt::resource_name ); // store the resource id with the connection so the connection // can release this statement when it closes. zend_long next_index = zend_hash_next_free_element( conn->stmts ); - core::sqlsrv_zend_hash_index_update(*conn, conn->stmts, next_index, &stmt_z TSRMLS_CC); + core::sqlsrv_zend_hash_index_update(*conn, conn->stmts, next_index, &stmt_z); stmt->conn_index = next_index; @@ -1150,7 +1135,7 @@ PHP_FUNCTION( sqlsrv_prepare ) stmt->~ss_sqlsrv_stmt(); } if (!Z_ISUNDEF(stmt_z)) { - free_stmt_resource(&stmt_z TSRMLS_CC); + free_stmt_resource(&stmt_z); } RETURN_FALSE; @@ -1216,9 +1201,9 @@ PHP_FUNCTION( sqlsrv_query ) // Initialize the options array to be passed to the core layer ALLOC_HASHTABLE( ss_stmt_options_ht ); core::sqlsrv_zend_hash_init( *conn , ss_stmt_options_ht, 5 /* # of buckets */, ZVAL_PTR_DTOR, - 0 /*persistent*/ TSRMLS_CC ); + 0 /*persistent*/ ); - validate_stmt_options( *conn, options_z, ss_stmt_options_ht TSRMLS_CC ); + validate_stmt_options( *conn, options_z, ss_stmt_options_ht ); } if( params_z && Z_TYPE_P( params_z ) != IS_ARRAY ) { @@ -1236,7 +1221,7 @@ PHP_FUNCTION( sqlsrv_query ) stmt = static_cast( core_sqlsrv_create_stmt( conn, core::allocate_stmt, ss_stmt_options_ht, SS_STMT_OPTS, - ss_error_handler, NULL TSRMLS_CC ) ); + ss_error_handler, NULL ) ); if( params_z ) { stmt->params_z = (zval *)sqlsrv_malloc(sizeof(zval)); @@ -1245,18 +1230,18 @@ PHP_FUNCTION( sqlsrv_query ) stmt->set_func( "sqlsrv_query" ); - bind_params( stmt TSRMLS_CC ); + bind_params( stmt ); // execute the statement - core_sqlsrv_execute( stmt TSRMLS_CC, sql, static_cast( sql_len ) ); + core_sqlsrv_execute( stmt, sql, static_cast( sql_len ) ); // register the statement with the PHP runtime - ss::zend_register_resource(stmt_z, stmt, ss_sqlsrv_stmt::descriptor, ss_sqlsrv_stmt::resource_name TSRMLS_CC); + ss::zend_register_resource(stmt_z, stmt, ss_sqlsrv_stmt::descriptor, ss_sqlsrv_stmt::resource_name); // store the resource id with the connection so the connection // can release this statement when it closes. zend_ulong next_index = zend_hash_next_free_element( conn->stmts ); - core::sqlsrv_zend_hash_index_update(*conn, conn->stmts, next_index, &stmt_z TSRMLS_CC); + core::sqlsrv_zend_hash_index_update(*conn, conn->stmts, next_index, &stmt_z); stmt->conn_index = next_index; stmt.transferred(); @@ -1271,7 +1256,7 @@ PHP_FUNCTION( sqlsrv_query ) stmt->~ss_sqlsrv_stmt(); } if (!Z_ISUNDEF(stmt_z)) { - free_stmt_resource(&stmt_z TSRMLS_CC); + free_stmt_resource(&stmt_z); } RETURN_FALSE; @@ -1282,11 +1267,16 @@ PHP_FUNCTION( sqlsrv_query ) } } -void free_stmt_resource( _Inout_ zval* stmt_z TSRMLS_DC ) +void free_stmt_resource( _Inout_ zval* stmt_z ) { - if( FAILURE == zend_list_close( Z_RES_P( stmt_z ))) { +#if PHP_VERSION_ID < 80000 + if (FAILURE == zend_list_close(Z_RES_P(stmt_z))) { LOG(SEV_ERROR, "Failed to remove stmt resource %1!d!", Z_RES_HANDLE_P(stmt_z)); } +#else + zend_list_close(Z_RES_P(stmt_z)); +#endif + ZVAL_NULL( stmt_z ); zval_ptr_dtor(stmt_z); } @@ -1298,7 +1288,7 @@ namespace { // must close all statement handles opened by this connection before closing the connection // no errors are returned, since close should always succeed -void sqlsrv_conn_close_stmts( _Inout_ ss_sqlsrv_conn* conn TSRMLS_DC ) +void sqlsrv_conn_close_stmts( _Inout_ ss_sqlsrv_conn* conn ) { //pre-condition check SQLSRV_ASSERT(( conn->handle() != NULL ), "sqlsrv_conn_close_stmts: Connection handle is NULL. Trying to destroy an " @@ -1336,9 +1326,13 @@ void sqlsrv_conn_close_stmts( _Inout_ ss_sqlsrv_conn* conn TSRMLS_DC ) // this would call the destructor on the statement. // There's nothing we can do if the removal fails, so we just log it and move on. - if( zend_list_close( Z_RES_P(rsrc_ptr) ) == FAILURE ) { +#if PHP_VERSION_ID < 80000 + if (zend_list_close(Z_RES_P(rsrc_ptr)) == FAILURE) { LOG(SEV_ERROR, "Failed to remove statement resource %1!d! when closing the connection", Z_RES_HANDLE_P(rsrc_ptr)); } +#else + zend_list_close(Z_RES_P(rsrc_ptr)); +#endif } ZEND_HASH_FOREACH_END(); zend_hash_destroy( conn->stmts ); @@ -1346,7 +1340,7 @@ void sqlsrv_conn_close_stmts( _Inout_ ss_sqlsrv_conn* conn TSRMLS_DC ) conn->stmts = NULL; } -int get_conn_option_key( _Inout_ sqlsrv_context& ctx, _In_ zend_string* key, _In_ size_t key_len, _Inout_ zval const* value_z TSRMLS_DC ) +int get_conn_option_key( _Inout_ sqlsrv_context& ctx, _In_ zend_string* key, _In_ size_t key_len, _Inout_ zval const* value_z ) { for( int i=0; SS_CONN_OPTS[i].conn_option_key != SQLSRV_CONN_OPTION_INVALID; ++i ) { @@ -1407,7 +1401,7 @@ int get_conn_option_key( _Inout_ sqlsrv_context& ctx, _In_ zend_string* key, _In return SQLSRV_CONN_OPTION_INVALID; } -int get_stmt_option_key( _In_ zend_string* key, _In_ size_t key_len TSRMLS_DC ) +int get_stmt_option_key( _In_ zend_string* key, _In_ size_t key_len ) { for( int i = 0; SS_STMT_OPTS[i].key != SQLSRV_STMT_OPTION_INVALID; ++i ) { @@ -1419,9 +1413,9 @@ int get_stmt_option_key( _In_ zend_string* key, _In_ size_t key_len TSRMLS_DC ) } void add_stmt_option_key( _Inout_ sqlsrv_context& ctx, _In_ zend_string* key, _In_ size_t key_len, - _Inout_ HashTable* options_ht, _Inout_ zval* data TSRMLS_DC ) + _Inout_ HashTable* options_ht, _Inout_ zval* data ) { - int option_key = ::get_stmt_option_key( key, key_len TSRMLS_CC ); + int option_key = ::get_stmt_option_key( key, key_len ); CHECK_CUSTOM_ERROR((option_key == SQLSRV_STMT_OPTION_INVALID ), ctx, SQLSRV_ERROR_INVALID_OPTION_KEY, ZSTR_VAL( key ) ) { @@ -1429,27 +1423,27 @@ void add_stmt_option_key( _Inout_ sqlsrv_context& ctx, _In_ zend_string* key, _I } Z_TRY_ADDREF_P(data); // inc the ref count since this is going into the options_ht too. - core::sqlsrv_zend_hash_index_update( ctx, options_ht, option_key, data TSRMLS_CC ); + core::sqlsrv_zend_hash_index_update( ctx, options_ht, option_key, data ); } void add_conn_option_key( _Inout_ sqlsrv_context& ctx, _In_ zend_string* key, _In_ size_t key_len, - _Inout_ HashTable* options_ht, _Inout_ zval* data TSRMLS_DC ) + _Inout_ HashTable* options_ht, _Inout_ zval* data ) { - int option_key = ::get_conn_option_key( ctx, key, key_len, data TSRMLS_CC ); + int option_key = ::get_conn_option_key( ctx, key, key_len, data ); CHECK_CUSTOM_ERROR((option_key == SQLSRV_STMT_OPTION_INVALID ), ctx, SS_SQLSRV_ERROR_INVALID_OPTION, ZSTR_VAL( key ) ) { throw ss::SSException(); } Z_TRY_ADDREF_P(data); // inc the ref count since this is going into the options_ht too. - core::sqlsrv_zend_hash_index_update( ctx, options_ht, option_key, data TSRMLS_CC ); + core::sqlsrv_zend_hash_index_update( ctx, options_ht, option_key, data ); } // Iterates through the list of statement options provided by the user and validates them // against the list of supported statement options by this driver. After validation // creates a Hashtable of statement options to be sent to the core layer for processing. -void validate_stmt_options( _Inout_ sqlsrv_context& ctx, _Inout_ zval* stmt_options, _Inout_ HashTable* ss_stmt_options_ht TSRMLS_DC ) +void validate_stmt_options( _Inout_ sqlsrv_context& ctx, _Inout_ zval* stmt_options, _Inout_ HashTable* ss_stmt_options_ht ) { try { if( stmt_options ) { @@ -1471,7 +1465,7 @@ void validate_stmt_options( _Inout_ sqlsrv_context& ctx, _Inout_ zval* stmt_opti } else if ( key != NULL ) { key_len = ZSTR_LEN( key ) + 1; - add_stmt_option_key( ctx, key, key_len, ss_stmt_options_ht, data TSRMLS_CC ); + add_stmt_option_key( ctx, key, key_len, ss_stmt_options_ht, data ); } else { DIE( "validate_stmt_options: key was null." ); @@ -1489,7 +1483,7 @@ void validate_stmt_options( _Inout_ sqlsrv_context& ctx, _Inout_ zval* stmt_opti // against the predefined list of supported connection options by this driver. After validation // creates a Hashtable of connection options to be sent to the core layer for processing. -void validate_conn_options( _Inout_ sqlsrv_context& ctx, _In_ zval* user_options_z, _Inout_ char** uid, _Inout_ char** pwd, _Inout_ HashTable* ss_conn_options_ht TSRMLS_DC ) +void validate_conn_options( _Inout_ sqlsrv_context& ctx, _In_ zval* user_options_z, _Inout_ char** uid, _Inout_ char** pwd, _Inout_ HashTable* ss_conn_options_ht ) { try { @@ -1524,7 +1518,7 @@ void validate_conn_options( _Inout_ sqlsrv_context& ctx, _In_ zval* user_options } else { - ::add_conn_option_key( ctx, key, key_len, ss_conn_options_ht, data TSRMLS_CC ); + ::add_conn_option_key( ctx, key, key_len, ss_conn_options_ht, data ); } } else { diff --git a/source/sqlsrv/init.cpp b/source/sqlsrv/init.cpp index 96f5338f1..4cc02597c 100644 --- a/source/sqlsrv/init.cpp +++ b/source/sqlsrv/init.cpp @@ -2,7 +2,7 @@ // File: init.cpp // Contents: initialization routines for the extension // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -98,6 +98,8 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX( sqlsrv_fetch_arginfo, 0, 0, 1 ) ZEND_ARG_INFO( 0, stmt ) + ZEND_ARG_INFO( 0, row ) + ZEND_ARG_INFO( 0, offset ) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX( sqlsrv_fetch_array_arginfo, 0, 0, 1 ) @@ -551,14 +553,14 @@ PHP_MINIT_FUNCTION(sqlsrv) } } - if( php_register_url_stream_wrapper( SQLSRV_STREAM_WRAPPER, &g_sqlsrv_stream_wrapper TSRMLS_CC ) == FAILURE ) { + if( php_register_url_stream_wrapper( SQLSRV_STREAM_WRAPPER, &g_sqlsrv_stream_wrapper ) == FAILURE ) { LOG( SEV_ERROR, "%1!s!: stream registration failed", _FN_ ); return FAILURE; } try { // retrieve the handles for the environments - core_sqlsrv_minit( &g_ss_henv_cp, &g_ss_henv_ncp, ss_error_handler, "PHP_MINIT_FUNCTION for sqlsrv" TSRMLS_CC ); + core_sqlsrv_minit( &g_ss_henv_cp, &g_ss_henv_ncp, ss_error_handler, "PHP_MINIT_FUNCTION for sqlsrv" ); } catch( core::CoreException& ) { @@ -610,7 +612,7 @@ PHP_MSHUTDOWN_FUNCTION(sqlsrv) core_sqlsrv_mshutdown( *g_ss_henv_cp, *g_ss_henv_ncp ); - if( php_unregister_url_stream_wrapper( SQLSRV_STREAM_WRAPPER TSRMLS_CC ) == FAILURE ) { + if( php_unregister_url_stream_wrapper( SQLSRV_STREAM_WRAPPER ) == FAILURE ) { return FAILURE; } @@ -692,9 +694,9 @@ PHP_RSHUTDOWN_FUNCTION(sqlsrv) SQLSRV_UNUSED( type ); LOG_FUNCTION( "PHP_RSHUTDOWN for php_sqlsrv" ); - reset_errors( TSRMLS_C ); + reset_errors(); - // TODO - destruction + // destruction zval_ptr_dtor( &SQLSRV_G( errors )); zval_ptr_dtor( &SQLSRV_G( warnings )); diff --git a/source/sqlsrv/php_sqlsrv.h b/source/sqlsrv/php_sqlsrv.h index 45fb8baec..fcfb387a9 100644 --- a/source/sqlsrv/php_sqlsrv.h +++ b/source/sqlsrv/php_sqlsrv.h @@ -8,7 +8,7 @@ // // Comments: Also contains "internal" declarations shared across source files. // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/sqlsrv/php_sqlsrv_int.h b/source/sqlsrv/php_sqlsrv_int.h index fae7082e5..87a15c20e 100644 --- a/source/sqlsrv/php_sqlsrv_int.h +++ b/source/sqlsrv/php_sqlsrv_int.h @@ -8,7 +8,7 @@ // // Comments: Also contains "internal" declarations shared across source files. // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -91,8 +91,8 @@ struct ss_sqlsrv_conn : sqlsrv_conn static int descriptor; // initialize with default values - ss_sqlsrv_conn( _In_ SQLHANDLE h, _In_ error_callback e, _In_ void* drv TSRMLS_DC ) : - sqlsrv_conn( h, e, drv, SQLSRV_ENCODING_SYSTEM TSRMLS_CC ), + ss_sqlsrv_conn( _In_ SQLHANDLE h, _In_ error_callback e, _In_ void* drv ) : + sqlsrv_conn( h, e, drv, SQLSRV_ENCODING_SYSTEM ), stmts( NULL ), date_as_string( false ), format_decimals( false ), @@ -103,8 +103,7 @@ struct ss_sqlsrv_conn : sqlsrv_conn }; // resource destructor -void __cdecl sqlsrv_conn_dtor( _Inout_ zend_resource *rsrc TSRMLS_DC ); - +void __cdecl sqlsrv_conn_dtor( _Inout_ zend_resource *rsrc ); //********************************************************************************************************************************* // Statement @@ -117,27 +116,22 @@ struct sqlsrv_fetch_field_name { }; struct stmt_option_ss_scrollable : public stmt_option_functor { - - virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC ); + virtual void operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z ); }; // This object inherits and overrides the callbacks necessary struct ss_sqlsrv_stmt : public sqlsrv_stmt { - - ss_sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error_callback e, _In_ void* drv TSRMLS_DC ); + ss_sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error_callback e, _In_ void* drv ); virtual ~ss_sqlsrv_stmt( void ); - void new_result_set( TSRMLS_D ); + void new_result_set( void ); // driver specific conversion rules from a SQL Server/ODBC type to one of the SQLSRV_PHPTYPE_* constants sqlsrv_phptype sql_type_to_php_type( _In_ SQLINTEGER sql_type, _In_ SQLUINTEGER size, _In_ bool prefer_string_to_stream ); - // driver specific way to set query timeout - virtual void set_query_timeout(); - bool prepared; // whether the statement has been prepared yet (used for error messages) - zend_ulong conn_index; // index into the connection hash that contains this statement structure + zend_ulong conn_index; // index into the connection hash that contains this statement structure zval* params_z; // hold parameters passed to sqlsrv_prepare but not used until sqlsrv_execute sqlsrv_fetch_field_name* fetch_field_names; // field names for current results used by sqlsrv_fetch_array/object as keys int fetch_fields_count; @@ -166,14 +160,14 @@ struct sqlsrv_stream_encoding { }; // resource destructor -void __cdecl sqlsrv_stmt_dtor( _Inout_ zend_resource *rsrc TSRMLS_DC ); +void __cdecl sqlsrv_stmt_dtor( _Inout_ zend_resource *rsrc ); // "internal" statement functions shared by functions in conn.cpp and stmt.cpp -void bind_params( _Inout_ ss_sqlsrv_stmt* stmt TSRMLS_DC ); +void bind_params( _Inout_ ss_sqlsrv_stmt* stmt ); bool sqlsrv_stmt_common_execute( sqlsrv_stmt* s, const SQLCHAR* sql_string, int sql_len, bool direct, const char* function - TSRMLS_DC ); -void free_odbc_resources( ss_sqlsrv_stmt* stmt TSRMLS_DC ); -void free_stmt_resource( _Inout_ zval* stmt_z TSRMLS_DC ); + ); +void free_odbc_resources( ss_sqlsrv_stmt* stmt ); +void free_stmt_resource( _Inout_ zval* stmt_z ); //********************************************************************************************************************************* @@ -218,7 +212,7 @@ enum SS_ERROR_CODES { extern ss_error SS_ERRORS[]; -bool ss_error_handler( _Inout_ sqlsrv_context& ctx, _In_ unsigned int sqlsrv_error_code, _In_ bool warning TSRMLS_DC, _In_opt_ va_list* print_args ); +bool ss_error_handler( _Inout_ sqlsrv_context& ctx, _In_ unsigned int sqlsrv_error_code, _In_ bool warning, _In_opt_ va_list* print_args ); // convert from the default encoding specified by the "CharacterSet" // connection option to UTF-16. mbcs_len and utf16_len are sizes in @@ -235,13 +229,13 @@ SQLWCHAR* utf16_string_from_mbcs_string( _In_ unsigned int php_encoding, _In_rea // *** internal error macros and functions *** bool handle_error( sqlsrv_context const* ctx, int log_subsystem, const char* function, - sqlsrv_error const* ssphp TSRMLS_DC, ... ); + sqlsrv_error const* ssphp, ... ); void handle_warning( sqlsrv_context const* ctx, int log_subsystem, const char* function, - sqlsrv_error const* ssphp TSRMLS_DC, ... ); -void __cdecl sqlsrv_error_dtor( zend_resource *rsrc TSRMLS_DC ); + sqlsrv_error const* ssphp, ... ); +void __cdecl sqlsrv_error_dtor( zend_resource *rsrc ); // release current error lists and set to NULL -inline void reset_errors( TSRMLS_D ) +inline void reset_errors( void ) { if( Z_TYPE( SQLSRV_G( errors )) != IS_ARRAY && Z_TYPE( SQLSRV_G( errors )) != IS_NULL ) { DIE( "sqlsrv_errors contains an invalid type" ); @@ -264,7 +258,7 @@ inline void reset_errors( TSRMLS_D ) } #define THROW_SS_ERROR( ctx, error_code, ... ) \ - (void)call_error_handler( ctx, error_code TSRMLS_CC, false /*warning*/, ## __VA_ARGS__ ); \ + (void)call_error_handler( ctx, error_code, false /*warning*/, ## __VA_ARGS__ ); \ throw ss::SSException(); @@ -317,7 +311,7 @@ class sqlsrv_context_auto_ptr : public sqlsrv_auto_ptr< sqlsrv_context, sqlsrv_c LOG(SEV_NOTICE, "%1!s!: entering", _FN_); // check the global variables of sqlsrv severity whether the message qualifies to be logged with the LOG macro -bool ss_severity_check(_In_ unsigned int severity TSRMLS_DC); +bool ss_severity_check(_In_ unsigned int severity); // subsystems that may report log messages. These may be used to filter which systems write to the log to prevent noise. enum logging_subsystems { @@ -345,7 +339,7 @@ namespace ss { } }; - inline void zend_register_resource( _Inout_ zval& rsrc_result, _Inout_ void* rsrc_pointer, _In_ int rsrc_type, _In_opt_ const char* rsrc_name TSRMLS_DC) + inline void zend_register_resource( _Inout_ zval& rsrc_result, _Inout_ void* rsrc_pointer, _In_ int rsrc_type, _In_opt_ const char* rsrc_name) { int zr = (NULL != (Z_RES(rsrc_result) = ::zend_register_resource(rsrc_pointer, rsrc_type)) ? SUCCESS : FAILURE); CHECK_CUSTOM_ERROR(( zr == FAILURE ), reinterpret_cast( rsrc_pointer ), SS_SQLSRV_ERROR_REGISTER_RESOURCE, @@ -369,10 +363,10 @@ inline H* process_params( INTERNAL_FUNCTION_PARAMETERS, _In_ char const* param_s SQLSRV_UNUSED( return_value ); zval* rsrc; - H* h; + H* h = NULL; // reset the errors from the previous API call - reset_errors( TSRMLS_C ); + reset_errors(); if( ZEND_NUM_ARGS() > param_count + 1 ) { DIE( "Param count and argument count don't match." ); @@ -406,35 +400,35 @@ inline H* process_params( INTERNAL_FUNCTION_PARAMETERS, _In_ char const* param_s switch( param_count ) { case 0: - result = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, const_cast( param_spec ), &rsrc ); + result = zend_parse_parameters( ZEND_NUM_ARGS(), const_cast( param_spec ), &rsrc ); break; case 1: - result = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, const_cast( param_spec ), &rsrc, arr[0] ); + result = zend_parse_parameters( ZEND_NUM_ARGS(), const_cast( param_spec ), &rsrc, arr[0] ); break; case 2: - result = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, const_cast( param_spec ), &rsrc, arr[0], + result = zend_parse_parameters( ZEND_NUM_ARGS(), const_cast( param_spec ), &rsrc, arr[0], arr[1] ); break; case 3: - result = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, const_cast( param_spec ), &rsrc, arr[0], + result = zend_parse_parameters( ZEND_NUM_ARGS(), const_cast( param_spec ), &rsrc, arr[0], arr[1], arr[2] ); break; case 4: - result = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, const_cast( param_spec ), &rsrc, arr[0], + result = zend_parse_parameters( ZEND_NUM_ARGS(), const_cast( param_spec ), &rsrc, arr[0], arr[1], arr[2], arr[3] ); break; case 5: - result = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, const_cast( param_spec ), &rsrc, arr[0], + result = zend_parse_parameters( ZEND_NUM_ARGS(), const_cast( param_spec ), &rsrc, arr[0], arr[1], arr[2], arr[3], arr[4] ); break; case 6: - result = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, const_cast( param_spec ), &rsrc, arr[0], + result = zend_parse_parameters( ZEND_NUM_ARGS(), const_cast( param_spec ), &rsrc, arr[0], arr[1], arr[2], arr[3], arr[4], arr[5] ); break; @@ -451,7 +445,7 @@ inline H* process_params( INTERNAL_FUNCTION_PARAMETERS, _In_ char const* param_s } // get the resource registered - h = static_cast( zend_fetch_resource(Z_RES_P(rsrc) TSRMLS_CC, H::resource_name, H::descriptor )); + h = static_cast( zend_fetch_resource(Z_RES_P(rsrc), H::resource_name, H::descriptor )); CHECK_CUSTOM_ERROR(( h == NULL ), &error_ctx, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, calling_func ) { diff --git a/source/sqlsrv/stmt.cpp b/source/sqlsrv/stmt.cpp index c7f002dce..2aef9dd61 100644 --- a/source/sqlsrv/stmt.cpp +++ b/source/sqlsrv/stmt.cpp @@ -3,7 +3,7 @@ // // Contents: Routines that use statement handles // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -89,21 +89,20 @@ const char* NULLABLE = "Nullable"; void convert_to_zval( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSRV_PHPTYPE sqlsrv_php_type, _In_opt_ void* in_val, _In_ SQLLEN field_len, _Inout_ zval& out_zval ); SQLSMALLINT get_resultset_meta_data(_Inout_ sqlsrv_stmt* stmt); -void fetch_fields_common( _Inout_ ss_sqlsrv_stmt* stmt, _In_ zend_long fetch_type, _Out_ zval& fields, _In_ bool allow_empty_field_names - TSRMLS_DC ); +void fetch_fields_common( _Inout_ ss_sqlsrv_stmt* stmt, _In_ zend_long fetch_type, _Out_ zval& fields, _In_ bool allow_empty_field_names ); bool determine_column_size_or_precision( sqlsrv_stmt const* stmt, _In_ sqlsrv_sqltype sqlsrv_type, _Inout_ SQLULEN* column_size, _Out_ SQLSMALLINT* decimal_digits ); sqlsrv_phptype determine_sqlsrv_php_type( sqlsrv_stmt const* stmt, SQLINTEGER sql_type, SQLUINTEGER size, bool prefer_string ); -void determine_stmt_has_rows( _Inout_ ss_sqlsrv_stmt* stmt TSRMLS_DC ); +void determine_stmt_has_rows( _Inout_ ss_sqlsrv_stmt* stmt ); bool is_valid_sqlsrv_phptype( _In_ sqlsrv_phptype type ); bool is_valid_sqlsrv_sqltype( _In_ sqlsrv_sqltype type ); void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array, zend_ulong index, _Out_ SQLSMALLINT& direction, _Out_ SQLSRV_PHPTYPE& php_out_type, _Out_ SQLSRV_ENCODING& encoding, _Out_ SQLSMALLINT& sql_type, - _Out_ SQLULEN& column_size, _Out_ SQLSMALLINT& decimal_digits TSRMLS_DC ); + _Out_ SQLULEN& column_size, _Out_ SQLSMALLINT& decimal_digits ); void type_and_encoding( INTERNAL_FUNCTION_PARAMETERS, _In_ int type ); void type_and_size_calc( INTERNAL_FUNCTION_PARAMETERS, _In_ int type ); void type_and_precision_calc( INTERNAL_FUNCTION_PARAMETERS, _In_ int type ); -bool verify_and_set_encoding( _In_ const char* encoding_string, _Inout_ sqlsrv_phptype& phptype_encoding TSRMLS_DC ); +bool verify_and_set_encoding( _In_ const char* encoding_string, _Inout_ sqlsrv_phptype& phptype_encoding ); } @@ -126,15 +125,15 @@ namespace SSCursorTypes { const char QUERY_OPTION_SCROLLABLE_BUFFERED[] = "buffered"; } -ss_sqlsrv_stmt::ss_sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error_callback e, _In_ void* drv TSRMLS_DC ) : - sqlsrv_stmt( c, handle, e, drv TSRMLS_CC ), +ss_sqlsrv_stmt::ss_sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error_callback e, _In_ void* drv ) : + sqlsrv_stmt( c, handle, e, drv ), prepared( false ), conn_index( -1 ), params_z( NULL ), fetch_field_names( NULL ), fetch_fields_count ( 0 ) { - core_sqlsrv_set_buffered_query_limit( this, SQLSRV_G( buffered_query_limit ) TSRMLS_CC ); + core_sqlsrv_set_buffered_query_limit( this, SQLSRV_G( buffered_query_limit ) ); // inherit other values based on the corresponding connection options ss_sqlsrv_conn* ss_conn = static_cast(conn); @@ -164,7 +163,7 @@ ss_sqlsrv_stmt::~ss_sqlsrv_stmt( void ) // to be called whenever a new result set is created, such as after an // execute or next_result. Resets the state variables and calls the subclass. -void ss_sqlsrv_stmt::new_result_set( TSRMLS_D ) +void ss_sqlsrv_stmt::new_result_set( void ) { if( fetch_field_names != NULL ) { @@ -177,7 +176,7 @@ void ss_sqlsrv_stmt::new_result_set( TSRMLS_D ) fetch_field_names = NULL; fetch_fields_count = 0; - sqlsrv_stmt::new_result_set( TSRMLS_C ); + sqlsrv_stmt::new_result_set(); } // Returns a php type for a given sql type. Also sets the encoding wherever applicable. @@ -262,29 +261,6 @@ sqlsrv_phptype ss_sqlsrv_stmt::sql_type_to_php_type( _In_ SQLINTEGER sql_type, _ return ss_phptype; } -void ss_sqlsrv_stmt::set_query_timeout() -{ - if (query_timeout == QUERY_TIMEOUT_INVALID || query_timeout < 0) { - return; - } - - // set the statement attribute - core::SQLSetStmtAttr(this, SQL_ATTR_QUERY_TIMEOUT, reinterpret_cast( (SQLLEN)query_timeout ), SQL_IS_UINTEGER TSRMLS_CC ); - - // a query timeout of 0 indicates "no timeout", which means that lock_timeout should also be set to "no timeout" which - // is represented by -1. - int lock_timeout = (( query_timeout == 0 ) ? -1 : query_timeout * 1000 /*convert to milliseconds*/ ); - - // set the LOCK_TIMEOUT on the server. - char lock_timeout_sql[32] = {'\0'}; - - int written = snprintf( lock_timeout_sql, sizeof( lock_timeout_sql ), "SET LOCK_TIMEOUT %d", lock_timeout ); - SQLSRV_ASSERT( (written != -1 && written != sizeof( lock_timeout_sql )), - "stmt_option_query_timeout: snprintf failed. Shouldn't ever fail." ); - - core::SQLExecDirect(this, lock_timeout_sql TSRMLS_CC ); -} - // statement specific parameter proccessing. Uses the generic function specialised to return a statement // resource. #define PROCESS_PARAMS( rsrc, param_spec, calling_func, param_count, ... ) \ @@ -327,14 +303,14 @@ PHP_FUNCTION( sqlsrv_execute ) // to prepare to execute the next statement, we skip any remaining results (and skip parameter finalization too) while( stmt->past_next_result_end == false ) { - core_sqlsrv_next_result( stmt TSRMLS_CC, false, false ); + core_sqlsrv_next_result( stmt, false, false ); } } // bind parameters before executing - bind_params( stmt TSRMLS_CC ); + bind_params( stmt ); - core_sqlsrv_execute( stmt TSRMLS_CC ); + core_sqlsrv_execute( stmt ); RETURN_TRUE; } @@ -383,7 +359,7 @@ PHP_FUNCTION( sqlsrv_fetch ) throw ss::SSException(); } - bool result = core_sqlsrv_fetch( stmt, static_cast(fetch_style), fetch_offset TSRMLS_CC ); + bool result = core_sqlsrv_fetch( stmt, static_cast(fetch_style), fetch_offset ); if( !result ) { RETURN_NULL(); } @@ -442,13 +418,13 @@ PHP_FUNCTION( sqlsrv_fetch_array ) throw ss::SSException(); } - bool result = core_sqlsrv_fetch( stmt, static_cast(fetch_style), fetch_offset TSRMLS_CC ); + bool result = core_sqlsrv_fetch( stmt, static_cast(fetch_style), fetch_offset ); if( !result ) { RETURN_NULL(); } zval fields; ZVAL_UNDEF( &fields ); - fetch_fields_common( stmt, fetch_type, fields, true /*allow_empty_field_names*/ TSRMLS_CC ); + fetch_fields_common( stmt, fetch_type, fields, true /*allow_empty_field_names*/ ); RETURN_ARR( Z_ARRVAL( fields )); } @@ -500,8 +476,8 @@ PHP_FUNCTION( sqlsrv_field_metadata ) } zval result_meta_data; - ZVAL_UNDEF( &result_meta_data ); - core::sqlsrv_array_init( *stmt, &result_meta_data TSRMLS_CC ); + ZVAL_UNDEF(&result_meta_data); + array_init(&result_meta_data); for( SQLSMALLINT f = 0; f < num_cols; ++f ) { field_meta_data* core_meta_data = stmt->current_meta_data[f]; @@ -509,13 +485,13 @@ PHP_FUNCTION( sqlsrv_field_metadata ) // initialize the array zval field_array; ZVAL_UNDEF( &field_array ); - core::sqlsrv_array_init( *stmt, &field_array TSRMLS_CC ); + array_init(&field_array ); // add the field name to the associative array but keep a copy - core::sqlsrv_add_assoc_string(*stmt, &field_array, FieldMetaData::NAME, - reinterpret_cast(core_meta_data->field_name.get()), 1 TSRMLS_CC); + add_assoc_string(&field_array, FieldMetaData::NAME, reinterpret_cast(core_meta_data->field_name.get())); - core::sqlsrv_add_assoc_long( *stmt, &field_array, FieldMetaData::TYPE, core_meta_data->field_type TSRMLS_CC ); + //core::sqlsrv_add_assoc_long( *stmt, &field_array, FieldMetaData::TYPE, core_meta_data->field_type ); + add_assoc_long(&field_array, FieldMetaData::TYPE, core_meta_data->field_type); switch( core_meta_data->field_type ) { case SQL_DECIMAL: @@ -524,9 +500,9 @@ PHP_FUNCTION( sqlsrv_field_metadata ) case SQL_TYPE_DATE: case SQL_SS_TIME2: case SQL_SS_TIMESTAMPOFFSET: - core::sqlsrv_add_assoc_null( *stmt, &field_array, FieldMetaData::SIZE TSRMLS_CC ); - core::sqlsrv_add_assoc_long( *stmt, &field_array, FieldMetaData::PREC, core_meta_data->field_precision TSRMLS_CC ); - core::sqlsrv_add_assoc_long( *stmt, &field_array, FieldMetaData::SCALE, core_meta_data->field_scale TSRMLS_CC ); + add_assoc_null(&field_array, FieldMetaData::SIZE); + add_assoc_long(&field_array, FieldMetaData::PREC, core_meta_data->field_precision); + add_assoc_long(&field_array, FieldMetaData::SCALE, core_meta_data->field_scale); break; case SQL_BIT: case SQL_TINYINT: @@ -536,27 +512,26 @@ PHP_FUNCTION( sqlsrv_field_metadata ) case SQL_REAL: case SQL_FLOAT: case SQL_DOUBLE: - core::sqlsrv_add_assoc_null( *stmt, &field_array, FieldMetaData::SIZE TSRMLS_CC ); - core::sqlsrv_add_assoc_long( *stmt, &field_array, FieldMetaData::PREC, core_meta_data->field_precision TSRMLS_CC ); - core::sqlsrv_add_assoc_null( *stmt, &field_array, FieldMetaData::SCALE TSRMLS_CC ); + add_assoc_null(&field_array, FieldMetaData::SIZE); + add_assoc_long(&field_array, FieldMetaData::PREC, core_meta_data->field_precision); + add_assoc_null(&field_array, FieldMetaData::SCALE); break; default: - core::sqlsrv_add_assoc_long( *stmt, &field_array, FieldMetaData::SIZE, core_meta_data->field_size TSRMLS_CC ); - core::sqlsrv_add_assoc_null( *stmt, &field_array, FieldMetaData::PREC TSRMLS_CC ); - core::sqlsrv_add_assoc_null( *stmt, &field_array, FieldMetaData::SCALE TSRMLS_CC ); + add_assoc_long(&field_array, FieldMetaData::SIZE, core_meta_data->field_size); + add_assoc_null(&field_array, FieldMetaData::PREC); + add_assoc_null(&field_array, FieldMetaData::SCALE); break; } // add the nullability to the array - core::sqlsrv_add_assoc_long( *stmt, &field_array, FieldMetaData::NULLABLE, core_meta_data->field_is_nullable - TSRMLS_CC ); + add_assoc_long(&field_array, FieldMetaData::NULLABLE, core_meta_data->field_is_nullable); if (stmt->data_classification) { - data_classification::fill_column_sensitivity_array(stmt, f, &field_array TSRMLS_CC); + data_classification::fill_column_sensitivity_array(stmt, f, &field_array); } // add this field's meta data to the result set meta data - core::sqlsrv_add_next_index_zval( *stmt, &result_meta_data, &field_array TSRMLS_CC ); + add_next_index_zval(&result_meta_data, &field_array); } // return our built collection and transfer ownership @@ -600,7 +575,7 @@ PHP_FUNCTION( sqlsrv_next_result ) try { - core_sqlsrv_next_result( stmt TSRMLS_CC, true ); + core_sqlsrv_next_result( stmt, true ); // clear the current meta data since the new result will generate new meta data std::for_each(stmt->current_meta_data.begin(), stmt->current_meta_data.end(), meta_data_free); @@ -659,7 +634,7 @@ PHP_FUNCTION( sqlsrv_rows_affected ) throw ss::SSException(); } - rows = stmt->current_results->row_count( TSRMLS_C ); + rows = stmt->current_results->row_count(); RETURN_LONG( rows ); } @@ -708,7 +683,7 @@ PHP_FUNCTION( sqlsrv_num_rows ) throw ss::SSException(); } - rows = stmt->current_results->row_count( TSRMLS_C ); + rows = stmt->current_results->row_count(); RETURN_LONG( rows ); } @@ -747,7 +722,7 @@ PHP_FUNCTION( sqlsrv_num_fields ) try { // retrieve the number of columns from ODBC - fields = core::SQLNumResultCols( stmt TSRMLS_CC ); + fields = core::SQLNumResultCols( stmt ); RETURN_LONG( fields ); } @@ -844,18 +819,18 @@ PHP_FUNCTION( sqlsrv_fetch_object ) } // fetch the data - bool result = core_sqlsrv_fetch( stmt, static_cast(fetch_style), fetch_offset TSRMLS_CC ); + bool result = core_sqlsrv_fetch( stmt, static_cast(fetch_style), fetch_offset ); if( !result ) { RETURN_NULL(); } - fetch_fields_common( stmt, SQLSRV_FETCH_ASSOC, retval_z, false /*allow_empty_field_names*/ TSRMLS_CC ); + fetch_fields_common( stmt, SQLSRV_FETCH_ASSOC, retval_z, false /*allow_empty_field_names*/ ); properties_ht = Z_ARRVAL( retval_z ); // find the zend_class_entry of the class the user requested (stdClass by default) for use below zend_class_entry* class_entry = NULL; zend_string* class_name_str_z = zend_string_init( class_name, class_name_len, 0 ); - int zr = ( NULL != ( class_entry = zend_lookup_class( class_name_str_z TSRMLS_CC ))) ? SUCCESS : FAILURE; + int zr = ( NULL != ( class_entry = zend_lookup_class( class_name_str_z ))) ? SUCCESS : FAILURE; zend_string_release( class_name_str_z ); CHECK_ZEND_ERROR( zr, stmt, SS_SQLSRV_ERROR_ZEND_BAD_CLASS, class_name ) { throw ss::SSException(); @@ -873,7 +848,7 @@ PHP_FUNCTION( sqlsrv_fetch_object ) // causes duplicate properties when the visibilities are different and also references the // default parameters directly in the object, meaning the default property value is changed when // the object's property is changed. - zend_merge_properties( &retval_z, properties_ht TSRMLS_CC ); + zend_merge_properties( &retval_z, properties_ht ); zend_hash_destroy( properties_ht ); FREE_HASHTABLE( properties_ht ); @@ -940,7 +915,7 @@ PHP_FUNCTION( sqlsrv_fetch_object ) fcic.object = Z_OBJ_P( &retval_z ); - zr = zend_call_function( &fci, &fcic TSRMLS_CC ); + zr = zend_call_function( &fci, &fcic ); CHECK_ZEND_ERROR( zr, stmt, SS_SQLSRV_ERROR_ZEND_OBJECT_FAILED, class_name ) { throw ss::SSException(); } @@ -1004,7 +979,7 @@ PHP_FUNCTION( sqlsrv_has_rows ) if( !stmt->has_rows && !stmt->fetch_called ) { - determine_stmt_has_rows( stmt TSRMLS_CC ); + determine_stmt_has_rows( stmt ); } if( stmt->has_rows ) { @@ -1057,7 +1032,7 @@ PHP_FUNCTION( sqlsrv_send_stream_data ) } // send the next packet - bool more = core_sqlsrv_send_stream_packet( stmt TSRMLS_CC ); + bool more = core_sqlsrv_send_stream_packet( stmt ); // if more to send, return true if( more ) { @@ -1130,7 +1105,7 @@ PHP_FUNCTION( sqlsrv_get_field ) } core_sqlsrv_get_field( stmt, static_cast( field_index ), sqlsrv_php_type, false, field_value, &field_len, false/*cache_field*/, - &sqlsrv_php_type_out TSRMLS_CC ); + &sqlsrv_php_type_out ); convert_to_zval( stmt, sqlsrv_php_type_out, field_value, field_len, retval_z ); sqlsrv_free( field_value ); RETURN_ZVAL( &retval_z, 1, 1 ); @@ -1213,7 +1188,7 @@ PHP_FUNCTION(SQLSRV_SQLTYPE_VARCHAR) type_and_size_calc( INTERNAL_FUNCTION_PARAM_PASSTHRU, SQL_VARCHAR ); } -void bind_params( _Inout_ ss_sqlsrv_stmt* stmt TSRMLS_DC ) +void bind_params( _Inout_ ss_sqlsrv_stmt* stmt ) { // if there's nothing to do, just return if( stmt->params_z == NULL ) { @@ -1222,7 +1197,7 @@ void bind_params( _Inout_ ss_sqlsrv_stmt* stmt TSRMLS_DC ) try { - stmt->free_param_data( TSRMLS_C ); + stmt->free_param_data(); stmt->executed = false; @@ -1263,7 +1238,7 @@ void bind_params( _Inout_ ss_sqlsrv_stmt* stmt TSRMLS_DC ) // parse the parameter array that the user gave parse_param_array( stmt, param_z, index, direction, php_out_type, encoding, sql_type, column_size, - decimal_digits TSRMLS_CC ); + decimal_digits ); value_z = var; } else { @@ -1275,14 +1250,14 @@ void bind_params( _Inout_ ss_sqlsrv_stmt* stmt TSRMLS_DC ) // bind the parameter SQLSRV_ASSERT( value_z != NULL, "bind_params: value_z is null." ); core_sqlsrv_bind_param( stmt, static_cast( index ), direction, value_z, php_out_type, encoding, sql_type, column_size, - decimal_digits TSRMLS_CC ); + decimal_digits ); - } ZEND_HASH_FOREACH_END(); + } ZEND_HASH_FOREACH_END(); } catch( core::CoreException& ) { SQLFreeStmt( stmt->handle(), SQL_RESET_PARAMS ); zval_ptr_dtor( stmt->params_z ); - sqlsrv_free( stmt->params_z ); + sqlsrv_free( stmt->params_z ); stmt->params_z = NULL; throw; } @@ -1312,7 +1287,7 @@ PHP_FUNCTION( sqlsrv_cancel ) try { // close the stream to release the resource - close_active_stream( stmt TSRMLS_CC ); + close_active_stream( stmt ); SQLRETURN r = SQLCancel( stmt->handle() ); CHECK_SQL_ERROR_OR_WARNING( r, stmt ) { @@ -1331,7 +1306,7 @@ PHP_FUNCTION( sqlsrv_cancel ) } } -void __cdecl sqlsrv_stmt_dtor( _Inout_ zend_resource *rsrc TSRMLS_DC ) +void __cdecl sqlsrv_stmt_dtor( _Inout_ zend_resource *rsrc ) { LOG_FUNCTION( "sqlsrv_stmt_dtor" ); @@ -1377,7 +1352,7 @@ PHP_FUNCTION( sqlsrv_free_stmt ) ss_sqlsrv_stmt* stmt = NULL; sqlsrv_context_auto_ptr error_ctx; - reset_errors( TSRMLS_C ); + reset_errors(); try { @@ -1386,10 +1361,10 @@ PHP_FUNCTION( sqlsrv_free_stmt ) error_ctx->set_func(_FN_); // take only the statement resource - if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "r", &stmt_r ) == FAILURE ) { + if( zend_parse_parameters( ZEND_NUM_ARGS(), "r", &stmt_r ) == FAILURE ) { // Check if it was a zval - int zr = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "z", &stmt_r ); + int zr = zend_parse_parameters( ZEND_NUM_ARGS(), "z", &stmt_r ); CHECK_CUSTOM_ERROR(( zr == FAILURE ), error_ctx, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ ) { throw ss::SSException(); @@ -1406,14 +1381,14 @@ PHP_FUNCTION( sqlsrv_free_stmt ) } // verify the resource so we know we're deleting a statement - stmt = static_cast(zend_fetch_resource_ex(stmt_r TSRMLS_CC, ss_sqlsrv_stmt::resource_name, ss_sqlsrv_stmt::descriptor)); + stmt = static_cast(zend_fetch_resource_ex(stmt_r, ss_sqlsrv_stmt::resource_name, ss_sqlsrv_stmt::descriptor)); - // if sqlsrv_free_stmt was called on an already closed statment then we just return success. - // zend_list_close sets the type of the closed statment to -1. + // if sqlsrv_free_stmt was called on an already closed statment then we just return success. + // zend_list_close sets the type of the closed statment to -1. SQLSRV_ASSERT( stmt_r != NULL, "sqlsrv_free_stmt: stmt_r is null." ); - if ( Z_RES_TYPE_P( stmt_r ) == RSRC_INVALID_TYPE ) { - RETURN_TRUE; - } + if ( Z_RES_TYPE_P( stmt_r ) == RSRC_INVALID_TYPE ) { + RETURN_TRUE; + } if( stmt == NULL ) { @@ -1421,9 +1396,13 @@ PHP_FUNCTION( sqlsrv_free_stmt ) } // delete the resource from Zend's master list, which will trigger the statement's destructor - if( zend_list_close( Z_RES_P(stmt_r) ) == FAILURE ) { - LOG( SEV_ERROR, "Failed to remove stmt resource %1!d!", Z_RES_P( stmt_r )->handle); +#if PHP_VERSION_ID < 80000 + if (zend_list_close(Z_RES_P(stmt_r)) == FAILURE) { + LOG(SEV_ERROR, "Failed to remove stmt resource %1!d!", Z_RES_P(stmt_r)->handle); } +#else + zend_list_close(Z_RES_P(stmt_r)); +#endif // when stmt_r is first parsed in zend_parse_parameters, stmt_r becomes a zval that points to a zend_resource with a refcount of 2 // need to DELREF here so the refcount becomes 1 and stmt_r can be appropriate destroyed by the garbage collector when it goes out of scope @@ -1445,7 +1424,7 @@ PHP_FUNCTION( sqlsrv_free_stmt ) } } -void stmt_option_ss_scrollable:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z TSRMLS_DC ) +void stmt_option_ss_scrollable:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_option const* /*opt*/, _In_ zval* value_z ) { CHECK_CUSTOM_ERROR(( Z_TYPE_P( value_z ) != IS_STRING ), stmt, SQLSRV_ERROR_INVALID_OPTION_SCROLLABLE ) { throw ss::SSException(); @@ -1485,7 +1464,7 @@ void stmt_option_ss_scrollable:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_opt THROW_SS_ERROR( stmt, SQLSRV_ERROR_INVALID_OPTION_SCROLLABLE ); } - core_sqlsrv_set_scrollable( stmt, cursor_type TSRMLS_CC ); + core_sqlsrv_set_scrollable( stmt, cursor_type ); } @@ -1753,7 +1732,7 @@ sqlsrv_phptype determine_sqlsrv_php_type( _In_ ss_sqlsrv_stmt const* stmt, _In_ // The return value simply states whether or not if an error occurred during the determination. // (All errors are posted here before returning.) -void determine_stmt_has_rows( _Inout_ ss_sqlsrv_stmt* stmt TSRMLS_DC ) +void determine_stmt_has_rows( _Inout_ ss_sqlsrv_stmt* stmt ) { SQLRETURN r = SQL_SUCCESS; @@ -1766,7 +1745,7 @@ void determine_stmt_has_rows( _Inout_ ss_sqlsrv_stmt* stmt TSRMLS_DC ) stmt->has_rows = false; // if there are no columns then there are no rows - if( core::SQLNumResultCols( stmt TSRMLS_CC ) == 0 ) { + if( core::SQLNumResultCols( stmt ) == 0 ) { return; } @@ -1775,13 +1754,13 @@ void determine_stmt_has_rows( _Inout_ ss_sqlsrv_stmt* stmt TSRMLS_DC ) // fetch the first row, and then roll the cursor back to be prior to the first row if( stmt->cursor_type != SQL_CURSOR_FORWARD_ONLY ) { - r = stmt->current_results->fetch( SQL_FETCH_FIRST, 0 TSRMLS_CC ); + r = stmt->current_results->fetch( SQL_FETCH_FIRST, 0 ); if( SQL_SUCCEEDED( r )) { stmt->has_rows = true; CHECK_SQL_WARNING( r, stmt ); // restore the cursor to its original position. - r = stmt->current_results->fetch( SQL_FETCH_ABSOLUTE, 0 TSRMLS_CC ); + r = stmt->current_results->fetch( SQL_FETCH_ABSOLUTE, 0 ); SQLSRV_ASSERT(( r == SQL_NO_DATA ), "core_sqlsrv_has_rows: Should have scrolled the cursor to the beginning " "of the result set." ); } @@ -1792,7 +1771,7 @@ void determine_stmt_has_rows( _Inout_ ss_sqlsrv_stmt* stmt TSRMLS_DC ) // flag and simply skips the first fetch, knowing it was already done. It records its own // flags to know if it should fetch on subsequent calls. - r = core::SQLFetchScroll( stmt, SQL_FETCH_NEXT, 0 TSRMLS_CC ); + r = core::SQLFetchScroll( stmt, SQL_FETCH_NEXT, 0 ); if( SQL_SUCCEEDED( r )) { stmt->has_rows = true; @@ -1813,7 +1792,7 @@ SQLSMALLINT get_resultset_meta_data(_Inout_ sqlsrv_stmt * stmt) if (num_cols == 0) { getMetaData = true; if (stmt->column_count == ACTIVE_NUM_COLS_INVALID) { - num_cols = core::SQLNumResultCols(stmt TSRMLS_CC); + num_cols = core::SQLNumResultCols(stmt); stmt->column_count = num_cols; } else { num_cols = stmt->column_count; @@ -1824,7 +1803,7 @@ SQLSMALLINT get_resultset_meta_data(_Inout_ sqlsrv_stmt * stmt) if (getMetaData) { for (int i = 0; i < num_cols; i++) { sqlsrv_malloc_auto_ptr core_meta_data; - core_meta_data = core_sqlsrv_field_metadata(stmt, i TSRMLS_CC); + core_meta_data = core_sqlsrv_field_metadata(stmt, i); stmt->current_meta_data.push_back(core_meta_data.get()); core_meta_data.transferred(); } @@ -1838,8 +1817,7 @@ SQLSMALLINT get_resultset_meta_data(_Inout_ sqlsrv_stmt * stmt) return num_cols; } -void fetch_fields_common( _Inout_ ss_sqlsrv_stmt* stmt, _In_ zend_long fetch_type, _Out_ zval& fields, _In_ bool allow_empty_field_names - TSRMLS_DC ) +void fetch_fields_common( _Inout_ ss_sqlsrv_stmt* stmt, _In_ zend_long fetch_type, _Out_ zval& fields, _In_ bool allow_empty_field_names ) { void* field_value = NULL; sqlsrv_phptype sqlsrv_php_type; @@ -1876,61 +1854,51 @@ void fetch_fields_common( _Inout_ ss_sqlsrv_stmt* stmt, _In_ zend_long fetch_typ } int zr = SUCCESS; -#if PHP_VERSION_ID < 70300 - CHECK_ZEND_ERROR(array_init(&fields), stmt, SQLSRV_ERROR_ZEND_HASH) { - throw ss::SSException(); - } -#else array_init(&fields); -#endif - for( int i = 0; i < num_cols; ++i ) { - SQLLEN field_len = -1; + for( int i = 0; i < num_cols; ++i ) { + SQLLEN field_len = -1; - core_sqlsrv_get_field( stmt, i, sqlsrv_php_type, true /*prefer string*/, - field_value, &field_len, false /*cache_field*/, &sqlsrv_php_type_out TSRMLS_CC ); + core_sqlsrv_get_field( stmt, i, sqlsrv_php_type, true /*prefer string*/, + field_value, &field_len, false /*cache_field*/, &sqlsrv_php_type_out ); - zval field; - ZVAL_UNDEF( &field ); - convert_to_zval( stmt, sqlsrv_php_type_out, field_value, field_len, field ); - sqlsrv_free( field_value ); - if( fetch_type & SQLSRV_FETCH_NUMERIC ) { + zval field; + ZVAL_UNDEF( &field ); + convert_to_zval( stmt, sqlsrv_php_type_out, field_value, field_len, field ); + sqlsrv_free( field_value ); + if( fetch_type & SQLSRV_FETCH_NUMERIC ) { - zr = add_next_index_zval( &fields, &field ); - CHECK_ZEND_ERROR( zr, stmt, SQLSRV_ERROR_ZEND_HASH ) { - throw ss::SSException(); - } - } + zr = add_next_index_zval( &fields, &field ); + CHECK_ZEND_ERROR( zr, stmt, SQLSRV_ERROR_ZEND_HASH ) { + throw ss::SSException(); + } + } - if( fetch_type & SQLSRV_FETCH_ASSOC ) { + if( fetch_type & SQLSRV_FETCH_ASSOC ) { - CHECK_CUSTOM_WARNING_AS_ERROR(( stmt->fetch_field_names[i].len == 0 && !allow_empty_field_names ), stmt, - SS_SQLSRV_WARNING_FIELD_NAME_EMPTY) { - throw ss::SSException(); - } + CHECK_CUSTOM_WARNING_AS_ERROR(( stmt->fetch_field_names[i].len == 0 && !allow_empty_field_names ), stmt, + SS_SQLSRV_WARNING_FIELD_NAME_EMPTY) { + throw ss::SSException(); + } - if( stmt->fetch_field_names[i].len > 0 || allow_empty_field_names ) { + if( stmt->fetch_field_names[i].len > 0 || allow_empty_field_names ) { - zr = add_assoc_zval( &fields, stmt->fetch_field_names[i].name, &field ); - CHECK_ZEND_ERROR( zr, stmt, SQLSRV_ERROR_ZEND_HASH ) { - throw ss::SSException(); - } - } - } - //only addref when the fetch_type is BOTH because this is the only case when fields(hashtable) - //has 2 elements pointing to field. Do not addref if the type is NUMERIC or ASSOC because - //fields now only has 1 element pointing to field and we want the ref count to be only 1 - if (fetch_type == SQLSRV_FETCH_BOTH) { - Z_TRY_ADDREF(field); - } - } //for loop + add_assoc_zval(&fields, stmt->fetch_field_names[i].name, &field); + } + } + //only addref when the fetch_type is BOTH because this is the only case when fields(hashtable) + //has 2 elements pointing to field. Do not addref if the type is NUMERIC or ASSOC because + //fields now only has 1 element pointing to field and we want the ref count to be only 1 + if (fetch_type == SQLSRV_FETCH_BOTH) { + Z_TRY_ADDREF(field); + } + } //for loop } void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array, zend_ulong index, _Out_ SQLSMALLINT& direction, _Out_ SQLSRV_PHPTYPE& php_out_type, _Out_ SQLSRV_ENCODING& encoding, _Out_ SQLSMALLINT& sql_type, - _Out_ SQLULEN& column_size, _Out_ SQLSMALLINT& decimal_digits TSRMLS_DC ) - + _Out_ SQLULEN& column_size, _Out_ SQLSMALLINT& decimal_digits ) { zval* var_or_val = NULL; zval* temp = NULL; @@ -2165,7 +2133,7 @@ bool is_valid_sqlsrv_sqltype( _In_ sqlsrv_sqltype sql_type ) // verify an encoding given to type_and_encoding by looking through the list // of standard encodings created at module initialization time -bool verify_and_set_encoding( _In_ const char* encoding_string, _Inout_ sqlsrv_phptype& phptype_encoding TSRMLS_DC ) +bool verify_and_set_encoding( _In_ const char* encoding_string, _Inout_ sqlsrv_phptype& phptype_encoding ) { void* encoding_temp = NULL; zend_ulong index = -1; @@ -2195,8 +2163,7 @@ void type_and_size_calc( INTERNAL_FUNCTION_PARAMETERS, _In_ int type ) size_t size_len = 0; int size = 0; - if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s", &size_p, &size_len ) == FAILURE ) { - + if( zend_parse_parameters( ZEND_NUM_ARGS(), "s", &size_p, &size_len ) == FAILURE ) { return; } if (size_p) { @@ -2246,8 +2213,7 @@ void type_and_precision_calc( INTERNAL_FUNCTION_PARAMETERS, _In_ int type ) zend_long prec = SQLSRV_INVALID_PRECISION; zend_long scale = SQLSRV_INVALID_SCALE; - if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "|ll", &prec, &scale ) == FAILURE ) { - + if( zend_parse_parameters( ZEND_NUM_ARGS(), "|ll", &prec, &scale ) == FAILURE ) { return; } @@ -2290,12 +2256,11 @@ void type_and_encoding( INTERNAL_FUNCTION_PARAMETERS, _In_ int type ) sqlsrv_php_type.typeinfo.type = type; sqlsrv_php_type.typeinfo.encoding = SQLSRV_ENCODING_INVALID; - if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s", &encoding_param, &encoding_param_len ) == FAILURE ) { - + if( zend_parse_parameters( ZEND_NUM_ARGS(), "s", &encoding_param, &encoding_param_len ) == FAILURE ) { ZVAL_LONG( return_value, sqlsrv_php_type.value ); } - if( !verify_and_set_encoding( encoding_param, sqlsrv_php_type TSRMLS_CC )) { + if( !verify_and_set_encoding( encoding_param, sqlsrv_php_type )) { LOG( SEV_ERROR, "Invalid encoding for php type." ); } diff --git a/source/sqlsrv/template.rc b/source/sqlsrv/template.rc index 7aa9c0cf7..a44a52383 100644 --- a/source/sqlsrv/template.rc +++ b/source/sqlsrv/template.rc @@ -3,7 +3,7 @@ // // Contents: Version resource // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License diff --git a/source/sqlsrv/util.cpp b/source/sqlsrv/util.cpp index b91f17c2d..a5dd00bb7 100644 --- a/source/sqlsrv/util.cpp +++ b/source/sqlsrv/util.cpp @@ -5,7 +5,7 @@ // // Comments: Mostly error handling and some type handling // -// Microsoft Drivers 5.8 for PHP for SQL Server +// Microsoft Drivers 5.9 for PHP for SQL Server // Copyright(c) Microsoft Corporation // All rights reserved. // MIT License @@ -34,13 +34,13 @@ unsigned int current_log_subsystem = LOG_UTIL; sqlsrv_error_const* get_error_message( _In_ unsigned int sqlsrv_error_code ); void copy_error_to_zval( _Inout_ zval* error_z, _In_ sqlsrv_error_const* error, _Inout_ zval* reported_chain, _Inout_ zval* ignored_chain, - _In_ bool warning TSRMLS_DC ); -bool ignore_warning( _In_ char* sql_state, _In_ int native_code TSRMLS_DC ); + _In_ bool warning ); +bool ignore_warning( _In_ char* sql_state, _In_ int native_code ); bool handle_errors_and_warnings( _Inout_ sqlsrv_context& ctx, _Inout_ zval* reported_chain, _Inout_ zval* ignored_chain, _In_ logging_severity log_severity, - _In_ unsigned int sqlsrv_error_code, _In_ bool warning, _In_opt_ va_list* print_args TSRMLS_DC ); + _In_ unsigned int sqlsrv_error_code, _In_ bool warning, _In_opt_ va_list* print_args ); -int sqlsrv_merge_zend_hash_dtor( _Inout_ zval* dest TSRMLS_DC ); -bool sqlsrv_merge_zend_hash( _Inout_ zval* dest_z, zval const* src_z TSRMLS_DC ); +int sqlsrv_merge_zend_hash_dtor( _Inout_ zval* dest ); +bool sqlsrv_merge_zend_hash( _Inout_ zval* dest_z, zval const* src_z ); } @@ -451,12 +451,12 @@ ss_error SS_ERRORS[] = { }; // check the global variables of sqlsrv severity whether the message qualifies to be logged with the LOG macro -bool ss_severity_check(_In_ unsigned int severity TSRMLS_DC) +bool ss_severity_check(_In_ unsigned int severity) { return ((severity & SQLSRV_G(log_severity)) && (SQLSRV_G(current_subsystem) & SQLSRV_G(log_subsystems))); } -bool ss_error_handler( _Inout_ sqlsrv_context& ctx, _In_ unsigned int sqlsrv_error_code, _In_ bool warning TSRMLS_DC, _In_opt_ va_list* print_args ) +bool ss_error_handler( _Inout_ sqlsrv_context& ctx, _In_ unsigned int sqlsrv_error_code, _In_ bool warning, _In_opt_ va_list* print_args ) { logging_severity severity = SEV_ERROR; if( warning && !SQLSRV_G( warnings_return_as_errors )) { @@ -464,7 +464,7 @@ bool ss_error_handler( _Inout_ sqlsrv_context& ctx, _In_ unsigned int sqlsrv_err } return handle_errors_and_warnings( ctx, &SQLSRV_G( errors ), &SQLSRV_G( warnings ), severity, sqlsrv_error_code, warning, - print_args TSRMLS_CC ); + print_args ); } // sqlsrv_errors( [int $errorsAndOrWarnings] ) @@ -512,29 +512,23 @@ PHP_FUNCTION( sqlsrv_errors ) LOG_FUNCTION( "sqlsrv_errors" ); - if(( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags ) == FAILURE ) || + if(( zend_parse_parameters( ZEND_NUM_ARGS(), "|l", &flags ) == FAILURE ) || ( flags != SQLSRV_ERR_ALL && flags != SQLSRV_ERR_ERRORS && flags != SQLSRV_ERR_WARNINGS )) { LOG( SEV_ERROR, "An invalid parameter was passed to %1!s!.", _FN_ ); RETURN_FALSE; } zval err_z; ZVAL_UNDEF(&err_z); -#if PHP_VERSION_ID < 70300 - if (array_init(&err_z) == FAILURE) { - RETURN_FALSE; - } -#else array_init(&err_z); -#endif if( flags == SQLSRV_ERR_ALL || flags == SQLSRV_ERR_ERRORS ) { - if( Z_TYPE( SQLSRV_G( errors )) == IS_ARRAY && !sqlsrv_merge_zend_hash( &err_z, &SQLSRV_G( errors ) TSRMLS_CC )) { + if( Z_TYPE( SQLSRV_G( errors )) == IS_ARRAY && !sqlsrv_merge_zend_hash( &err_z, &SQLSRV_G( errors ) )) { zval_ptr_dtor(&err_z); RETURN_FALSE; } } if( flags == SQLSRV_ERR_ALL || flags == SQLSRV_ERR_WARNINGS ) { - if( Z_TYPE( SQLSRV_G( warnings )) == IS_ARRAY && !sqlsrv_merge_zend_hash( &err_z, &SQLSRV_G( warnings ) TSRMLS_CC )) { + if( Z_TYPE( SQLSRV_G( warnings )) == IS_ARRAY && !sqlsrv_merge_zend_hash( &err_z, &SQLSRV_G( warnings ) )) { zval_ptr_dtor(&err_z); RETURN_FALSE; } @@ -574,7 +568,7 @@ PHP_FUNCTION( sqlsrv_configure ) RETVAL_FALSE; - reset_errors( TSRMLS_C ); + reset_errors(); try { @@ -582,7 +576,7 @@ PHP_FUNCTION( sqlsrv_configure ) error_ctx = new ( sqlsrv_malloc( sizeof( sqlsrv_context ))) sqlsrv_context( 0, ss_error_handler, NULL ); error_ctx->set_func(_FN_); - int zr = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "sz", &option, &option_len, &value_z ); + int zr = zend_parse_parameters( ZEND_NUM_ARGS(), "sz", &option, &option_len, &value_z ); CHECK_CUSTOM_ERROR(( zr == FAILURE ), error_ctx, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ ) { throw ss::SSException(); @@ -694,7 +688,7 @@ PHP_FUNCTION( sqlsrv_get_config ) LOG_FUNCTION( "sqlsrv_get_config" ); - reset_errors( TSRMLS_C ); + reset_errors(); try { @@ -702,7 +696,7 @@ PHP_FUNCTION( sqlsrv_get_config ) error_ctx = new ( sqlsrv_malloc( sizeof( sqlsrv_context ))) sqlsrv_context( 0, ss_error_handler, NULL ); error_ctx->set_func(_FN_); - int zr = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s", &option, &option_len ); + int zr = zend_parse_parameters( ZEND_NUM_ARGS(), "s", &option, &option_len ); CHECK_CUSTOM_ERROR(( zr == FAILURE ), error_ctx, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ ) { throw ss::SSException(); @@ -761,51 +755,37 @@ sqlsrv_error_const* get_error_message( _In_ unsigned int sqlsrv_error_code ) { } void copy_error_to_zval( _Inout_ zval* error_z, _In_ sqlsrv_error_const* error, _Inout_ zval* reported_chain, _Inout_ zval* ignored_chain, - _In_ bool warning TSRMLS_DC ) + _In_ bool warning ) { -#if PHP_VERSION_ID < 70300 - if (array_init(error_z) == FAILURE) { - DIE( "Fatal error during error processing" ); - } -#else array_init(error_z); -#endif // sqlstate zval temp; - ZVAL_UNDEF(&temp); - core::sqlsrv_zval_stringl( &temp, reinterpret_cast( error->sqlstate ), SQL_SQLSTATE_SIZE ); - //TODO: reference? - Z_TRY_ADDREF_P( &temp ); + ZVAL_UNDEF(&temp); + core::sqlsrv_zval_stringl( &temp, reinterpret_cast( error->sqlstate ), SQL_SQLSTATE_SIZE ); + Z_TRY_ADDREF_P( &temp ); if( add_next_index_zval( error_z, &temp ) == FAILURE ) { DIE( "Fatal error during error processing" ); } - if( add_assoc_zval( error_z, "SQLSTATE", &temp ) == FAILURE ) { - DIE( "Fatal error during error processing" ); - } + add_assoc_zval(error_z, "SQLSTATE", &temp); // native_code if( add_next_index_long( error_z, error->native_code ) == FAILURE ) { DIE( "Fatal error during error processing" ); } - if( add_assoc_long( error_z, "code", error->native_code ) == FAILURE ) { - DIE( "Fatal error during error processing" ); - } + add_assoc_long(error_z, "code", error->native_code); // native_message - ZVAL_UNDEF(&temp); + ZVAL_UNDEF(&temp); ZVAL_STRING( &temp, reinterpret_cast( error->native_message ) ); - //TODO: reference? - Z_TRY_ADDREF_P(&temp); + Z_TRY_ADDREF_P(&temp); if( add_next_index_zval( error_z, &temp ) == FAILURE ) { DIE( "Fatal error during error processing" ); } - if( add_assoc_zval( error_z, "message", &temp ) == FAILURE ) { - DIE( "Fatal error during error processing" ); - } + add_assoc_zval(error_z, "message", &temp); // If it is an error or if warning_return_as_errors is true than // add the error or warning to the reported_chain. @@ -813,7 +793,7 @@ void copy_error_to_zval( _Inout_ zval* error_z, _In_ sqlsrv_error_const* error, { // if the warning is part of the ignored warning list than // add to the ignored chain if the ignored chain is not null. - if( warning && ignore_warning( reinterpret_cast(error->sqlstate), error->native_code TSRMLS_CC ) && + if( warning && ignore_warning( reinterpret_cast(error->sqlstate), error->native_code ) && ignored_chain != NULL ) { if( add_next_index_zval( ignored_chain, error_z ) == FAILURE ) { @@ -841,7 +821,7 @@ void copy_error_to_zval( _Inout_ zval* error_z, _In_ sqlsrv_error_const* error, } bool handle_errors_and_warnings( _Inout_ sqlsrv_context& ctx, _Inout_ zval* reported_chain, _Inout_ zval* ignored_chain, _In_ logging_severity log_severity, - _In_ unsigned int sqlsrv_error_code, _In_ bool warning, _In_opt_ va_list* print_args TSRMLS_DC ) + _In_ unsigned int sqlsrv_error_code, _In_ bool warning, _In_opt_ va_list* print_args ) { bool result = true; bool errors_ignored = false; @@ -856,13 +836,7 @@ bool handle_errors_and_warnings( _Inout_ sqlsrv_context& ctx, _Inout_ zval* repo if( Z_TYPE_P( reported_chain ) == IS_NULL ) { reported_chain_was_null = true; -#if PHP_VERSION_ID < 70300 - if (array_init(reported_chain) == FAILURE) { - DIE( "Fatal error during error processing" ); - } -#else array_init(reported_chain); -#endif } else { prev_reported_cnt = zend_hash_num_elements( Z_ARRVAL_P( reported_chain )); @@ -874,28 +848,22 @@ bool handle_errors_and_warnings( _Inout_ sqlsrv_context& ctx, _Inout_ zval* repo if( Z_TYPE_P( ignored_chain ) == IS_NULL ) { ignored_chain_was_null = true; -#if PHP_VERSION_ID < 70300 - if (array_init(ignored_chain) == FAILURE) { - DIE( "Fatal error in handle_errors_and_warnings" ); - } -#else array_init( ignored_chain ); -#endif } } if( sqlsrv_error_code != SQLSRV_ERROR_ODBC ) { - core_sqlsrv_format_driver_error( ctx, get_error_message( sqlsrv_error_code ), error, log_severity TSRMLS_CC, print_args ); - copy_error_to_zval( &error_z, error, reported_chain, ignored_chain, warning TSRMLS_CC ); + core_sqlsrv_format_driver_error( ctx, get_error_message( sqlsrv_error_code ), error, log_severity, print_args ); + copy_error_to_zval( &error_z, error, reported_chain, ignored_chain, warning ); } SQLSMALLINT record_number = 0; do { - result = core_sqlsrv_get_odbc_error( ctx, ++record_number, error, log_severity TSRMLS_CC ); + result = core_sqlsrv_get_odbc_error( ctx, ++record_number, error, log_severity ); if( result ) { - copy_error_to_zval( &error_z, error, reported_chain, ignored_chain, warning TSRMLS_CC ); + copy_error_to_zval( &error_z, error, reported_chain, ignored_chain, warning ); } } while( result ); @@ -933,7 +901,7 @@ bool handle_errors_and_warnings( _Inout_ sqlsrv_context& ctx, _Inout_ zval* repo // return whether or not a warning should be ignored or returned as an error if WarningsReturnAsErrors is true // see RINIT in init.cpp for information about which errors are ignored. -bool ignore_warning( _In_ char* sql_state, _In_ int native_code TSRMLS_DC ) +bool ignore_warning( _In_ char* sql_state, _In_ int native_code ) { zend_ulong index = -1; zend_string* key = NULL; @@ -954,7 +922,7 @@ bool ignore_warning( _In_ char* sql_state, _In_ int native_code TSRMLS_DC ) return false; } -int sqlsrv_merge_zend_hash_dtor( _Inout_ zval* dest TSRMLS_DC ) +int sqlsrv_merge_zend_hash_dtor( _Inout_ zval* dest ) { zval_ptr_dtor( dest ); return ZEND_HASH_APPLY_REMOVE; @@ -962,7 +930,7 @@ int sqlsrv_merge_zend_hash_dtor( _Inout_ zval* dest TSRMLS_DC ) // sqlsrv_merge_zend_hash // merge a source hash into a dest hash table and return any errors. -bool sqlsrv_merge_zend_hash( _Inout_ zval* dest_z, zval const* src_z TSRMLS_DC ) +bool sqlsrv_merge_zend_hash( _Inout_ zval* dest_z, zval const* src_z ) { if( Z_TYPE_P( dest_z ) != IS_ARRAY && Z_TYPE_P( dest_z ) != IS_NULL ) DIE( "dest_z must be an array or null" ); if( Z_TYPE_P( src_z ) != IS_ARRAY && Z_TYPE_P( src_z ) != IS_NULL ) DIE( "src_z must be an array or null" ); @@ -978,14 +946,14 @@ bool sqlsrv_merge_zend_hash( _Inout_ zval* dest_z, zval const* src_z TSRMLS_DC ) ZEND_HASH_FOREACH_KEY_VAL( src_ht, index, key, value_z ) { if ( !value_z ) { - zend_hash_apply( Z_ARRVAL_P(dest_z), sqlsrv_merge_zend_hash_dtor TSRMLS_CC ); + zend_hash_apply( Z_ARRVAL_P(dest_z), sqlsrv_merge_zend_hash_dtor ); return false; } int result = add_next_index_zval( dest_z, value_z ); if( result == FAILURE ) { - zend_hash_apply( Z_ARRVAL_P( dest_z ), sqlsrv_merge_zend_hash_dtor TSRMLS_CC ); + zend_hash_apply( Z_ARRVAL_P( dest_z ), sqlsrv_merge_zend_hash_dtor ); return false; } Z_TRY_ADDREF_P( value_z ); diff --git a/test/bvt/pdo_sqlsrv/msdn_pdoStatement_bindColumn.phpt b/test/bvt/pdo_sqlsrv/msdn_pdoStatement_bindColumn.phpt index 3904d76ee..c0e1c86a9 100644 --- a/test/bvt/pdo_sqlsrv/msdn_pdoStatement_bindColumn.phpt +++ b/test/bvt/pdo_sqlsrv/msdn_pdoStatement_bindColumn.phpt @@ -1,7 +1,7 @@ --TEST-- a variable bound to a column in a result set --SKIPIF-- - + --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); $stmt = $conn->prepare('SELECT * FROM Person.Addressx'); $stmt->execute(); @@ -13,8 +14,8 @@ echo "Error Code: "; print $stmt->errorCode(); // free the statement and connection -$stmt=null; -$conn=null; +unset($stmt); +unset($conn); ?> --EXPECT-- Error Code: 42S02 \ No newline at end of file diff --git a/test/bvt/pdo_sqlsrv/msdn_pdoStatement_errorInfo.phpt b/test/bvt/pdo_sqlsrv/msdn_pdoStatement_errorInfo.phpt index 6f8e4bc66..b827ff1ea 100644 --- a/test/bvt/pdo_sqlsrv/msdn_pdoStatement_errorInfo.phpt +++ b/test/bvt/pdo_sqlsrv/msdn_pdoStatement_errorInfo.phpt @@ -1,24 +1,28 @@ --TEST-- reports the error info of a SQL statement with a mispelled table name --SKIPIF-- - + --FILE-- setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); $stmt = $conn->prepare('SELECT * FROM Person.Addressx'); $stmt->execute(); print_r ($stmt->errorInfo()); // free the statement and connection -$stmt=null; -$conn=null; +unset($stmt); +unset($conn); ?> --EXPECTREGEX-- Array \( \[0\] => 42S02 \[1\] => 208 - \[2\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Invalid object name 'Person.Addressx'. + \[2\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Invalid object name 'Person.Addressx'\. + \[3\] => 42000 + \[4\] => 8180 + \[5\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Statement\(s\) could not be prepared\. \) \ No newline at end of file diff --git a/test/bvt/pdo_sqlsrv/msdn_pdoStatement_execute.phpt b/test/bvt/pdo_sqlsrv/msdn_pdoStatement_execute.phpt index b43bd1c79..12169d893 100644 --- a/test/bvt/pdo_sqlsrv/msdn_pdoStatement_execute.phpt +++ b/test/bvt/pdo_sqlsrv/msdn_pdoStatement_execute.phpt @@ -1,7 +1,7 @@ --TEST-- Executes a statement --SKIPIF-- - + --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); $query = "SELECT * FROM Person.Address where Cityx = 'Essen'"; $conn->query($query); print $conn->errorCode(); //free the connection -$conn=null; +unset($conn); ?> --EXPECT-- 42S22 \ No newline at end of file diff --git a/test/bvt/pdo_sqlsrv/msdn_pdo_errorInfo.phpt b/test/bvt/pdo_sqlsrv/msdn_pdo_errorInfo.phpt index 9252ad32c..3b7878870 100644 --- a/test/bvt/pdo_sqlsrv/msdn_pdo_errorInfo.phpt +++ b/test/bvt/pdo_sqlsrv/msdn_pdo_errorInfo.phpt @@ -1,11 +1,12 @@ --TEST-- reports the error info of querying a misspelled column --SKIPIF-- - + --FILE-- setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); $query = "SELECT * FROM Person.Address where Cityx = 'Essen'"; $conn->query($query); @@ -23,4 +24,7 @@ Array \[0\] => 42S22 \[1\] => 207 \[2\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Invalid column name 'Cityx'. + \[3\] => 42000 + \[4\] => 8180 + \[5\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Statement\(s\) could not be prepared\. \) \ No newline at end of file diff --git a/test/bvt/pdo_sqlsrv/msdn_pdo_exec.phpt b/test/bvt/pdo_sqlsrv/msdn_pdo_exec.phpt index 76ede8e85..2f0f9b124 100644 --- a/test/bvt/pdo_sqlsrv/msdn_pdo_exec.phpt +++ b/test/bvt/pdo_sqlsrv/msdn_pdo_exec.phpt @@ -1,7 +1,7 @@ --TEST-- execute a delete and reports how many rows were deleted --SKIPIF-- - + --FILE-- --FILE-- setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); $attributes1 = array( "ERRMODE" ); foreach ( $attributes1 as $val ) { - echo "PDO::ATTR_$val: "; - var_dump ($conn->getAttribute( constant( "PDO::ATTR_$val" ) )); + echo "PDO::ATTR_$val: "; + var_dump ($conn->getAttribute( constant( "PDO::ATTR_$val" ) )); } -$conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); +$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $attributes1 = array( "ERRMODE" ); foreach ( $attributes1 as $val ) { - echo "PDO::ATTR_$val: "; - var_dump ($conn->getAttribute( constant( "PDO::ATTR_$val" ) )); + echo "PDO::ATTR_$val: "; + var_dump ($conn->getAttribute( constant( "PDO::ATTR_$val" ) )); } -// An example using PDO::ATTR_CLIENT_VERSION -print_r($conn->getAttribute( PDO::ATTR_CLIENT_VERSION )); - //free the connection -$conn=null; +unset($conn); ?> --EXPECTREGEX-- PDO::ATTR_ERRMODE: int\(0\) PDO::ATTR_ERRMODE: int\(2\) -Array -\( - \[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/bvt/pdo_sqlsrv/msdn_pdo_getAvailableDrivers.phpt b/test/bvt/pdo_sqlsrv/msdn_pdo_getAvailableDrivers.phpt index 7db00eea3..672625b39 100644 --- a/test/bvt/pdo_sqlsrv/msdn_pdo_getAvailableDrivers.phpt +++ b/test/bvt/pdo_sqlsrv/msdn_pdo_getAvailableDrivers.phpt @@ -1,7 +1,7 @@ --TEST-- check if sqlsrv is in the array of available PDO drivers --SKIPIF-- - + --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); $attributes1 = array( "ERRMODE" ); foreach ( $attributes1 as $val ) { @@ -22,7 +23,7 @@ sets to PDO::ATTR_ERRMODE } //free the connection - $conn=null; + unset($conn); ?> --EXPECT-- PDO::ATTR_ERRMODE: int(0) diff --git a/test/bvt/pdo_sqlsrv/msdn_pdo_setAttribute_direct_query.phpt b/test/bvt/pdo_sqlsrv/msdn_pdo_setAttribute_direct_query.phpt index ae2ca1b12..f78c59ba2 100644 --- a/test/bvt/pdo_sqlsrv/msdn_pdo_setAttribute_direct_query.phpt +++ b/test/bvt/pdo_sqlsrv/msdn_pdo_setAttribute_direct_query.phpt @@ -1,42 +1,45 @@ --TEST-- sets to PDO::SQLSRV_ATTR_DIRECT_QUERY --SKIPIF-- - + --FILE-- setAttribute(constant('PDO::SQLSRV_ATTR_DIRECT_QUERY'), true); + require('connect.inc'); + $conn = new PDO("sqlsrv:Server=$server", "$uid", "$pwd"); + $conn->setAttribute(constant('PDO::SQLSRV_ATTR_DIRECT_QUERY'), true); - $stmt1 = $conn->query("DROP TABLE #php_test_table"); + $tableName = 'pdo_direct_query'; + $tsql = "IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'" . $tableName . "') AND type in (N'U')) DROP TABLE $tableName"; - $stmt2 = $conn->query("CREATE TABLE #php_test_table ([c1_int] int, [c2_int] int)"); + $stmt1 = $conn->query($tsql); + $stmt2 = $conn->query("CREATE TABLE $tableName ([c1_int] int, [c2_int] int)"); - $v1 = 1; - $v2 = 2; + $v1 = 1; + $v2 = 2; - $stmt3 = $conn->prepare("INSERT INTO #php_test_table (c1_int, c2_int) VALUES (:var1, :var2)"); + $stmt3 = $conn->prepare("INSERT INTO $tableName (c1_int, c2_int) VALUES (:var1, :var2)"); - if ($stmt3) { + if ($stmt3) { $stmt3->bindValue(1, $v1); $stmt3->bindValue(2, $v2); - if ($stmt3->execute()) + if ($stmt3->execute()) { echo "Execution succeeded\n"; - else + } else { echo "Execution failed\n"; - } - else + } + } else { var_dump($conn->errorInfo()); + } - $stmt4 = $conn->query("DROP TABLE #php_test_table"); + $stmt4 = $conn->query("DROP TABLE $tableName"); - // free the statements and connection - $stmt1=null; - $stmt2=null; - $stmt3=null; - $stmt4=null; - $conn=null; - ?> + // free the statements and connection + unset($stmt1); + unset($stmt2); + unset($stmt3); + unset($stmt4); + unset($conn); +?> --EXPECT-- Execution succeeded \ No newline at end of file diff --git a/test/bvt/pdo_sqlsrv/pdo_bindParam_inout_double.phpt b/test/bvt/pdo_sqlsrv/pdo_bindParam_inout_double.phpt index abcbdac2d..f82871f3b 100644 --- a/test/bvt/pdo_sqlsrv/pdo_bindParam_inout_double.phpt +++ b/test/bvt/pdo_sqlsrv/pdo_bindParam_inout_double.phpt @@ -1,7 +1,7 @@ --TEST-- call a stored procedure and retrieve the errorNumber that is returned --SKIPIF-- - + --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- "$databaseName", "UID"=>"$uid", "PWD"=>"$pwd"); -$conn = sqlsrv_connect( $server, $connectionInfo); -if( $conn === false ) -{ - echo "Could not connect.\n"; - die( print_r( sqlsrv_errors(), true)); -} - -if( $client_info = sqlsrv_client_info( $conn)) -{ - foreach( $client_info as $key => $value) - { - echo $key.": ".$value."\n"; - } -} -else -{ - echo "Client info error.\n"; -} - -/* Close connection resources. */ -sqlsrv_close( $conn); -?> ---EXPECTREGEX-- -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/bvt/sqlsrv/msdn_sqlsrv_close.phpt b/test/bvt/sqlsrv/msdn_sqlsrv_close.phpt index 0b95facc2..245d61af7 100644 --- a/test/bvt/sqlsrv/msdn_sqlsrv_close.phpt +++ b/test/bvt/sqlsrv/msdn_sqlsrv_close.phpt @@ -1,7 +1,7 @@ --TEST-- closes a connection. --SKIPIF-- - + --FILE-- + --FILE-- + --FILE-- --FILE-- --EXPECTREGEX-- -Warning: \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Changed database context to 'AdventureWorks2014'. +Warning: \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Changed database context to 'AdventureWorks201[4|7]'. Warning: \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Changed language setting to us_english. BusinessEntityId 7 has 57 remaining vacation hours. BusinessEntityId 8 has 57 remaining vacation hours. BusinessEntityId 9 has 55 remaining vacation hours. -Error: \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]The UPDATE statement conflicted with the CHECK constraint "CK_Employee_VacationHours". The conflict occurred in database "AdventureWorks2014", table "HumanResources.Employee", column 'VacationHours'. +Error: \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]The UPDATE statement conflicted with the CHECK constraint "CK_Employee_VacationHours". The conflict occurred in database "AdventureWorks201[4|7]", table "HumanResources.Employee", column 'VacationHours'. Error: \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]The statement has been terminated. \ No newline at end of file diff --git a/test/bvt/sqlsrv/msdn_sqlsrv_connect.phpt b/test/bvt/sqlsrv/msdn_sqlsrv_connect.phpt index 6e8baef57..7d6c6f482 100644 --- a/test/bvt/sqlsrv/msdn_sqlsrv_connect.phpt +++ b/test/bvt/sqlsrv/msdn_sqlsrv_connect.phpt @@ -1,7 +1,7 @@ --TEST-- creates and opens a connection using Windows Authentication. --SKIPIF-- - + --FILE-- --FILE-- --FILE-- --FILE-- ---EXPECT-- -2014-02-20 04:26:00.000 \ No newline at end of file +--EXPECTREGEX-- +2014-02-20 04:26:00.000|2017-08-22 19:39:35.643 \ No newline at end of file diff --git a/test/bvt/sqlsrv/msdn_sqlsrv_connect_utf8.phpt b/test/bvt/sqlsrv/msdn_sqlsrv_connect_utf8.phpt index d6adce7c3..b6b35d2aa 100644 --- a/test/bvt/sqlsrv/msdn_sqlsrv_connect_utf8.phpt +++ b/test/bvt/sqlsrv/msdn_sqlsrv_connect_utf8.phpt @@ -1,7 +1,7 @@ --TEST-- retrieves UTF-8 encoded data by specifying the UTF-8 character set when making the connection --SKIPIF-- - + --FILE-- --FILE-- ---EXPECT-- -Date = 20th, February 2014 \ No newline at end of file +--EXPECTREGEX-- +Date = 20th, February 2014|Date = 22nd, August 2017 \ No newline at end of file diff --git a/test/bvt/sqlsrv/msdn_sqlsrv_errors.phpt b/test/bvt/sqlsrv/msdn_sqlsrv_errors.phpt index 4c296046a..e49bd8bec 100644 --- a/test/bvt/sqlsrv/msdn_sqlsrv_errors.phpt +++ b/test/bvt/sqlsrv/msdn_sqlsrv_errors.phpt @@ -1,7 +1,7 @@ --TEST-- displays errors that occur during a failed statement execution --SKIPIF-- - + --FILE-- --FILE-- + --FILE-- + --FILE-- --FILE-- --FILE-- --FILE-- + --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- ---EXPECT-- -2014-02-20 04:26:00.000 \ No newline at end of file +--EXPECTREGEX-- +2014-02-20 04:26:00.000|2017-08-22 19:39:35.643 \ No newline at end of file diff --git a/test/bvt/sqlsrv/msdn_sqlsrv_has_rows.phpt b/test/bvt/sqlsrv/msdn_sqlsrv_has_rows.phpt index 7b5141056..694583640 100644 --- a/test/bvt/sqlsrv/msdn_sqlsrv_has_rows.phpt +++ b/test/bvt/sqlsrv/msdn_sqlsrv_has_rows.phpt @@ -1,7 +1,7 @@ --TEST-- indicate if the result set has one or more rows. --SKIPIF-- - + --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- --FILE-- \ No newline at end of file diff --git a/test/bvt/sqlsrv/sqlsrv_param_inout.phpt b/test/bvt/sqlsrv/sqlsrv_param_inout.phpt index 603f0ab57..5bc3e2a57 100644 --- a/test/bvt/sqlsrv/sqlsrv_param_inout.phpt +++ b/test/bvt/sqlsrv/sqlsrv_param_inout.phpt @@ -1,7 +1,7 @@ --TEST-- call a stored procedure (SQLSRV Driver) and retrieve the errorNumber that is returned --SKIPIF-- - + --FILE-- = '8.0') { + $expected = array_merge($expected, ['getIterator' => true]); + } $classname = get_class($stmt); $methods = get_class_methods($classname); diff --git a/test/functional/pdo_sqlsrv/PDO92_Iterator.phpt b/test/functional/pdo_sqlsrv/PDO92_Iterator.phpt index efd3fb27a..a1765b4bd 100644 --- a/test/functional/pdo_sqlsrv/PDO92_Iterator.phpt +++ b/test/functional/pdo_sqlsrv/PDO92_Iterator.phpt @@ -71,7 +71,7 @@ class PDOStatementAggregate extends PDOStatement implements IteratorAggregate $this->setFetchMode(PDO::FETCH_NUM); } - function getIterator() + function getIterator() : Iterator { echo __METHOD__ . "\n"; $this->execute(); diff --git a/test/functional/pdo_sqlsrv/PDO93_Recursive.phpt b/test/functional/pdo_sqlsrv/PDO93_Recursive.phpt index 79e5cb107..87be5fb28 100644 --- a/test/functional/pdo_sqlsrv/PDO93_Recursive.phpt +++ b/test/functional/pdo_sqlsrv/PDO93_Recursive.phpt @@ -69,7 +69,7 @@ class PDOStatementAggregate extends PDOStatement implements IteratorAggregate $this->setFetchMode(PDO::FETCH_NUM); } - function getIterator() + function getIterator() : Iterator { echo __METHOD__ . "\n"; $this->execute(); diff --git a/test/functional/pdo_sqlsrv/PDO94_Extend1.phpt b/test/functional/pdo_sqlsrv/PDO94_Extend1.phpt index 9aa66e362..3920d93c6 100644 --- a/test/functional/pdo_sqlsrv/PDO94_Extend1.phpt +++ b/test/functional/pdo_sqlsrv/PDO94_Extend1.phpt @@ -58,7 +58,7 @@ class ExPDO extends PDO $this->test2 = 22; } - function query($sql) + function query($sql, $fetch_style = PDO::FETCH_BOTH,...$fetch_mode_args) { echo __METHOD__ . "()\n"; $stmt = parent::prepare($sql, array(PDO::ATTR_STATEMENT_CLASS=>array('ExPDOStatement'))); diff --git a/test/functional/pdo_sqlsrv/PDO95_Extend2.phpt b/test/functional/pdo_sqlsrv/PDO95_Extend2.phpt index 5175f6a2d..f387be22e 100644 --- a/test/functional/pdo_sqlsrv/PDO95_Extend2.phpt +++ b/test/functional/pdo_sqlsrv/PDO95_Extend2.phpt @@ -20,6 +20,9 @@ function Extend() // simply use $databaseName from MsSetup.inc to facilitate testing in Azure, // which does not support switching databases $conn2 = new ExPDO("sqlsrv:Server=$server;Database=$databaseName", $uid, $pwd); + // With PHP 8.0 the default is PDO::ERRMODE_EXCEPTION rather than PDO::ERRMODE_SILENT + $conn2->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); + DropTable($conn2, "tmp_table"); $conn2->exec("CREATE TABLE tmp_table (id INT)"); $conn2->exec("INSERT INTO tmp_table (id) VALUES (1), (2)"); @@ -52,7 +55,7 @@ class ExPDO extends PDO return (call_user_func_array(array($this, 'parent::exec'), $args)); } - public function query() + public function query($statement, $fetch_style = PDO::FETCH_BOTH,...$fetch_mode_args) { $this->protocol(); $args = func_get_args(); diff --git a/test/functional/pdo_sqlsrv/PDO96_Extend3.phpt b/test/functional/pdo_sqlsrv/PDO96_Extend3.phpt index bc634d167..1a80cc6f1 100644 --- a/test/functional/pdo_sqlsrv/PDO96_Extend3.phpt +++ b/test/functional/pdo_sqlsrv/PDO96_Extend3.phpt @@ -61,7 +61,7 @@ class ExPDO extends PDO echo __METHOD__ . "()\n"; } - function query($sql) + function query($sql, $fetch_style = PDO::FETCH_BOTH,...$fetch_mode_args) { echo __METHOD__ . "()\n"; $stmt = $this->prepare($sql, array(PDO::ATTR_STATEMENT_CLASS=>array('ExPDOStatement', array($this)))); diff --git a/test/functional/pdo_sqlsrv/PDO97_Extend4.phpt b/test/functional/pdo_sqlsrv/PDO97_Extend4.phpt index e4fe031a6..03f312886 100644 --- a/test/functional/pdo_sqlsrv/PDO97_Extend4.phpt +++ b/test/functional/pdo_sqlsrv/PDO97_Extend4.phpt @@ -66,7 +66,7 @@ class ExPDO extends PDO echo __METHOD__ . "()\n"; } - function query($sql) + function query($sql, $fetch_style = PDO::FETCH_BOTH,...$fetch_mode_args) { echo __METHOD__ . "()\n"; $stmt = $this->prepare($sql, array(PDO::ATTR_STATEMENT_CLASS=>array('ExPDOStatement', array($this)))); diff --git a/test/functional/pdo_sqlsrv/PDO98_Extend5.phpt b/test/functional/pdo_sqlsrv/PDO98_Extend5.phpt index 6cccf924a..a3e9c94b7 100644 --- a/test/functional/pdo_sqlsrv/PDO98_Extend5.phpt +++ b/test/functional/pdo_sqlsrv/PDO98_Extend5.phpt @@ -69,7 +69,7 @@ class ExPDO extends PDO echo __METHOD__ . "()\n"; } - function query($sql) + function query($sql, $fetch_style = PDO::FETCH_BOTH,...$fetch_mode_args) { echo __METHOD__ . "()\n"; $stmt = parent::query($sql); diff --git a/test/functional/pdo_sqlsrv/PDO_ConnPool_Unix.phpt b/test/functional/pdo_sqlsrv/PDO_ConnPool_Unix.phpt index c68a46b14..9d242ad58 100644 --- a/test/functional/pdo_sqlsrv/PDO_ConnPool_Unix.phpt +++ b/test/functional/pdo_sqlsrv/PDO_ConnPool_Unix.phpt @@ -3,7 +3,11 @@ PDO_SQLSRV Connection Pooling Test on Unix --DESCRIPTION-- This test assumes the default odbcinst.ini has not been modified. --SKIPIF-- - + --FILE-- setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $stmt = $conn2->prepare("SET NOCOUNT ON; USE tempdb; SELECT 1/0 AS col1"); + $stmt->execute(); + } catch (PDOException $e) { + checkErrorInfo($stmt, $e); + } +} + +unset($conn2); + +function connectionID($conn) { $tsql = "SELECT [connection_id] FROM [sys].[dm_exec_connections] where session_id = @@SPID"; $stmt = $conn->query($tsql); @@ -23,4 +37,42 @@ function ConnectionID($conn) $stmt = null; return ($connID); } + +function isAzure($conn) +{ + try { + $tsql = "SELECT SERVERPROPERTY ('edition')"; + $stmt = $conn->query($tsql); + + $result = $stmt->fetch(PDO::FETCH_NUM); + $edition = $result[0]; + + if ($edition === "SQL Azure") { + return true; + } else { + return false; + } + } catch (PDOException $e) { + echo $e->getMessage(); + die("Could not fetch server property."); + } +} + +function checkErrorInfo($stmt, $err) +{ + $expected = "*Divide by zero error encountered*"; + $idx = count($err->errorInfo) - 1; + $failed = false; + if ($idx != 5 || !fnmatch($expected, $err->errorInfo[$idx])) { + echo "Error message unexpected!\n"; + $failed = true; + } + if ($err->errorInfo !== $stmt->errorInfo()) { + echo "Error info arrays should match!\n"; + $failed = true; + } + if ($failed) { + var_dump($err); + } +} ?> diff --git a/test/functional/pdo_sqlsrv/pdo_065_construct_prefetch.phpt b/test/functional/pdo_sqlsrv/pdo_065_construct_prefetch.phpt index 88f47495f..2adbf9419 100644 --- a/test/functional/pdo_sqlsrv/pdo_065_construct_prefetch.phpt +++ b/test/functional/pdo_sqlsrv/pdo_065_construct_prefetch.phpt @@ -12,13 +12,22 @@ try { echo "Testing a connection with ATTR_PREFETCH before ERRMODE_EXCEPTION...\n"; $dsn = getDSN($server, $databaseName, $driver); - $attr = array(PDO::ATTR_PREFETCH => true, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION); + // With PHP 8.0 the default is PDO::ERRMODE_EXCEPTION rather than PDO::ERRMODE_SILENT + if (PHP_MAJOR_VERSION == 8) { + $attr = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT, PDO::ATTR_PREFETCH => true); + } else { + $attr = array(PDO::ATTR_PREFETCH => true, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION); + } $conn = new PDO($dsn, $uid, $pwd, $attr); echo "Error from unsupported attribute (ATTR_PREFETCH) is silenced\n\n"; unset($conn); echo "Testing a connection with ATTR_PREFETCH after ERRMODE_EXCEPTION...\n"; - $attr = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_PREFETCH => true); + if (PHP_MAJOR_VERSION == 8) { + $attr = array(PDO::ATTR_PREFETCH => true); + } else { + $attr = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_PREFETCH => true); + } $conn = new PDO($dsn, $uid, $pwd, $attr); //free the connection unset($conn); diff --git a/test/functional/pdo_sqlsrv/pdo_1018_real_prepare_natl_char.phpt b/test/functional/pdo_sqlsrv/pdo_1018_real_prepare_natl_char.phpt index 9ee0dcceb..fac93f7bf 100644 --- a/test/functional/pdo_sqlsrv/pdo_1018_real_prepare_natl_char.phpt +++ b/test/functional/pdo_sqlsrv/pdo_1018_real_prepare_natl_char.phpt @@ -18,9 +18,15 @@ $p = '銀河galaxy'; $p1 = '??galaxy'; $tableName = 'test1018'; +// in Alpine Linux, instead of '?', it replaces inexact conversions with asterisks +// reference: read the ICONV section in +// https://wiki.musl-libc.org/functional-differences-from-glibc.html +$p2 = '**galaxy'; + function insertRead($conn, $pdoStrParam, $value, $testCase, $id, $encoding = false) { global $p, $tableName; + global $p1, $p2; $sql = "INSERT INTO $tableName (Col1) VALUES (:value)"; $options = array(PDO::ATTR_EMULATE_PREPARES => false); // it's false by default anyway @@ -45,8 +51,11 @@ function insertRead($conn, $pdoStrParam, $value, $testCase, $id, $encoding = fal $result = $stmt->fetch(PDO::FETCH_NUM); trace("$testCase: expected $value and returned $result[0]\n"); if ($result[0] !== $value) { - echo("$testCase: expected $value but returned:\n"); - var_dump($result); + // Also check the other exception + if ($value === $p1 && $result[0] !== $p2) { + echo("$testCase: expected $value or $p2 but returned:\n"); + var_dump($result); + } } } diff --git a/test/functional/pdo_sqlsrv/pdo_1063_locale_configs.phpt b/test/functional/pdo_sqlsrv/pdo_1063_locale_configs.phpt index 32c35f7a4..660b894f8 100644 --- a/test/functional/pdo_sqlsrv/pdo_1063_locale_configs.phpt +++ b/test/functional/pdo_sqlsrv/pdo_1063_locale_configs.phpt @@ -34,13 +34,11 @@ pdo_sqlsrv.set_locale_info = 0*** Amount formatted: 10000.99 Friday December -3.14159 **End** **Begin** Amount formatted: $10,000.99 Friday December -3.14159 **End** ***sqlsrv.SetLocaleInfo = 1 @@ -50,13 +48,11 @@ pdo_sqlsrv.set_locale_info = 1*** Amount formatted: 10000.99 Friday December -3.14159 **End** **Begin** Amount formatted: 10.000,99 € Freitag Dezember -3,14159 **End** ***sqlsrv.SetLocaleInfo = 2 @@ -66,11 +62,9 @@ pdo_sqlsrv.set_locale_info = 2*** Amount formatted: $10,000.99 Friday December -3.14159 **End** **Begin** Amount formatted: 10.000,99 € Freitag Dezember -3,14159 **End** diff --git a/test/functional/pdo_sqlsrv/pdo_1063_test_locale.php b/test/functional/pdo_sqlsrv/pdo_1063_test_locale.php index b37174494..f77cabffd 100644 --- a/test/functional/pdo_sqlsrv/pdo_1063_test_locale.php +++ b/test/functional/pdo_sqlsrv/pdo_1063_test_locale.php @@ -32,9 +32,9 @@ function printMoney($amt, $info) echo "**Begin**" . PHP_EOL; -// Assuming LC_ALL is 'en_US.UTF-8', so is LC_CTYPE +// Assuming LC_ALL is 'en_US.UTF-8', so is LC_CTYPE, except in PHP 8 (TODO) // But default LC_MONETARY varies -$ctype = 'en_US.UTF-8'; +$ctype = (PHP_MAJOR_VERSION == 8 && $setLocaleInfo == 0) ? 'C' : 'en_US.UTF-8'; switch ($setLocaleInfo) { case 0: case 1: @@ -55,9 +55,11 @@ function printMoney($amt, $info) $c1 = setlocale(LC_CTYPE, 0); if ($ctype !== $c1) { echo "Unexpected LC_CTYPE: $c1" . PHP_EOL; + echo "LC_NUMERIC for $setLocaleInfo: " . setlocale(LC_NUMERIC, 0) . PHP_EOL; } // Set a different locale, if the input is not empty +$english = true; if (!empty($locale)) { $loc = setlocale(LC_ALL, $locale); if ($loc !== $locale) { @@ -68,6 +70,7 @@ function printMoney($amt, $info) if ($loc === 'de_DE.UTF-8') { $symbol = strtoupper(PHP_OS) === 'LINUX' ? '€' : 'Eu'; $sep = strtoupper(PHP_OS) === 'LINUX' ? '.' : ''; + $english = false; } else { $symbol = '$'; $sep = ','; @@ -106,8 +109,20 @@ function printMoney($amt, $info) $stmt = $conn->prepare($sql, array(PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE => true)); $stmt->execute(); + // The following change is required for the breaking change introduced in PHP 8 + // https://wiki.php.net/rfc/locale_independent_float_to_string $row = $stmt->fetch(PDO::FETCH_NUM); - echo ($row[0]) . PHP_EOL; + $value = $row[0]; + $expected = 3.14159; + if (PHP_MAJOR_VERSION < 8) { + if ($setLocaleInfo > 0 && $english === false) { + $expected = floatval($pi); + } + } + if ($value != $expected) { + echo "Expected: '$expected' but got '$value'\n"; + } + unset($stmt); dropTable($conn, $tableName); diff --git a/test/functional/pdo_sqlsrv/pdo_1100_query_timeout_disconnect.phpt b/test/functional/pdo_sqlsrv/pdo_1100_query_timeout_disconnect.phpt new file mode 100644 index 000000000..36cf8fc88 --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_1100_query_timeout_disconnect.phpt @@ -0,0 +1,72 @@ +--TEST-- +GitHub issue 1100 - PDO::SQLSRV_ATTR_QUERY_TIMEOUT had no effect when reconnecting +--DESCRIPTION-- +This test verifies that setting PDO::SQLSRV_ATTR_QUERY_TIMEOUT should work when reconnecting after disconnecting +--ENV-- +PHPT_EXEC=true +--SKIPIF-- + +--FILE-- + $leeway); + trace("$elapsed secs elapsed\n"); + + if ($missed) { + echo "Expected $expectedDelay but $elapsed secs elapsed\n"; + } +} + +function testTimeout($conn, $timeout) +{ + $delay = 5; + $query = "WAITFOR DELAY '00:00:$delay'; SELECT 1"; + $error = '*Query timeout expired'; + + $t0 = microtime(true); + try { + $conn->exec($query); + $elapsed = microtime(true) - $t0; + echo "Should have failed after $timeout secs but $elapsed secs have elapsed" . PHP_EOL; + } catch (PDOException $e) { + $t1 = microtime(true); + + $message = '*Query timeout expired'; + if (!fnmatch($message, $e->getMessage())) { + var_dump($e->getMessage()); + } + checkTimeElapsed($t0, $t1, $timeout); + } +} + +try { + $keywords = 'MultipleActiveResultSets=false;'; + $timeout = 1; + + $options = array(PDO::SQLSRV_ATTR_QUERY_TIMEOUT => $timeout); + $conn = connect($keywords, $options); + + testTimeout($conn, $timeout); + unset($conn); + + $conn = connect($keywords); + $conn->setAttribute(PDO::SQLSRV_ATTR_QUERY_TIMEOUT, $timeout); + + testTimeout($conn, $timeout); + unset($conn); + + echo "Done\n"; +} catch (PdoException $e) { + echo $e->getMessage() . PHP_EOL; +} + +?> +--EXPECT-- +Done diff --git a/test/functional/pdo_sqlsrv/pdo_1170_direct_query_with_textsize.phpt b/test/functional/pdo_sqlsrv/pdo_1170_direct_query_with_textsize.phpt new file mode 100644 index 000000000..6ec78170c --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_1170_direct_query_with_textsize.phpt @@ -0,0 +1,71 @@ +--TEST-- +GitHub issue 1170 - PDO::SQLSRV_ATTR_DIRECT_QUERY with SET TEXTSIZE +--DESCRIPTION-- +This test verifies that setting PDO::SQLSRV_ATTR_DIRECT_QUERY to true with a user defined TEXTSIZE will work +--ENV-- +PHPT_EXEC=true +--SKIPIF-- + +--FILE-- + true); + + $sql = "SET TEXTSIZE $size"; + $stmt = $conn->prepare($sql, $options); + $stmt->execute(); + unset($stmt); + + $sql = composeQuery($input, $type); + $stmt = $conn->prepare($sql, $options); + $stmt->execute(); + + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if ($row['C1'] != $input || !is_null($row['C2'])) { + var_dump($row); + } + unset($stmt); +} + +try { + $conn = connect(); + + $options = array(PDO::SQLSRV_ATTR_DIRECT_QUERY => true); + + runTest($conn, 'TEXT', 4800); + runTest($conn, 'NTEXT', 129024); + runTest($conn, 'IMAGE', 10000); + + unset($conn); + + echo "Done\n"; +} catch (PdoException $e) { + echo $e->getMessage() . PHP_EOL; +} + +?> +--EXPECT-- +Test with TEXT and 4800 +Test with NTEXT and 129024 +Test with IMAGE and 10000 +Done + diff --git a/test/functional/pdo_sqlsrv/pdo_924_display_more_errors.phpt b/test/functional/pdo_sqlsrv/pdo_924_display_more_errors.phpt new file mode 100644 index 000000000..82d30b8b4 --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_924_display_more_errors.phpt @@ -0,0 +1,156 @@ +--TEST-- +GitHub issue 924 - Wrong error message after switching database context +--DESCRIPTION-- +Verifies that the user has the option to see the following error message after the first one. +--SKIPIF-- + +--FILE-- +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $stmt = $conn->prepare($tsql); + $stmt->execute(); + + var_dump($stmt->fetchColumn()); + + echo "Exception should have been thrown!\n"; + } catch (PDOException $e) { + // compare errorInfo arrays from both the exception object and the stmt object + if ($on) { + compare2ErrorInfo($e->errorInfo); + compare2ErrorInfo($stmt->errorInfo()); + } + else { + compareErrorInfo($e->errorInfo, $errorInfo); + compareErrorInfo($stmt->errorInfo(), $errorInfo); + } + } + + unset($stmt); + unset($conn); +} + +function checkWarning($conn, $on) +{ + global $tsql, $errorInfo, $errorInfo2; + + ini_set('pdo_sqlsrv.report_additional_errors', $on); + + try { + $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); + $stmt = $conn->prepare($tsql); + $stmt->execute(); + + compareErrorInfo($stmt->errorInfo(), $errorInfo); + if ($on) { + compareErrorInfo($stmt->errorInfo(), $errorInfo2, 3); + } else { + echo count($stmt->errorInfo()) . PHP_EOL; + } + } catch (PDOException $e) { + echo " Warnings are logged but do not expect exceptions.\n"; + var_dump($e); + } + + unset($stmt); + unset($conn); +} + +try { + // This forces PHP to log errors rather than displaying errors on screen + ini_set('display_errors', '0'); + ini_set('log_errors', '1'); + + $logFilename = 'php_924_errors.log'; + $logFilepath = dirname(__FILE__).'/'.$logFilename; + + if (file_exists($logFilepath)) { + unlink($logFilepath); + } + + ini_set('error_log', $logFilepath); + ini_set('pdo_sqlsrv.log_severity', '2'); // warnings only + + $conn = new PDO("sqlsrv:server=$server;", $uid, $pwd); + checkWarning($conn, 1); + checkException($conn, 1); + checkWarning($conn, 0); + checkException($conn, 0); + + if (file_exists($logFilepath)) { + echo file_get_contents($logFilepath); + unlink($logFilepath); + } else { + echo "Expected to find the log file\n"; + } +} catch (PDOException $e) { + var_dump($e); +} + +echo "\nDone\n"; +?> +--EXPECTF-- +3 +[%s UTC] pdo_sqlsrv_db_handle_factory: SQLSTATE = 01000 +[%s UTC] pdo_sqlsrv_db_handle_factory: error code = 5701 +[%s UTC] pdo_sqlsrv_db_handle_factory: message = %s[SQL Server]Changed database context to 'master'. +[%s UTC] pdo_sqlsrv_db_handle_factory: SQLSTATE = 01000 +[%s UTC] pdo_sqlsrv_db_handle_factory: error code = 5703 +[%s UTC] pdo_sqlsrv_db_handle_factory: message = %s[SQL Server]Changed language setting to us_english. +[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 01000 +[%s UTC] pdo_sqlsrv_stmt_execute: error code = 5701 +[%s UTC] pdo_sqlsrv_stmt_execute: message = %s[SQL Server]Changed database context to '%s'. +[%s UTC] PHP Warning: PDOStatement::execute(): SQLSTATE[01000]: Warning: 5701 %s[SQL Server]Changed database context to '%s'. in %spdo_924_display_more_errors.php on line %d +[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 01000 +[%s UTC] pdo_sqlsrv_stmt_execute: error code = 5701 +[%s UTC] pdo_sqlsrv_stmt_execute: message = %s[SQL Server]Changed database context to '%s'. +[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 01000 +[%s UTC] pdo_sqlsrv_stmt_execute: error code = 5701 +[%s UTC] pdo_sqlsrv_stmt_execute: message = %s[SQL Server]Changed database context to '%s'. +[%s UTC] PHP Warning: PDOStatement::execute(): SQLSTATE[01000]: Warning: 5701 %s[SQL Server]Changed database context to '%s'. in %spdo_924_display_more_errors.php on line %d +[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 01000 +[%s UTC] pdo_sqlsrv_stmt_execute: error code = 5701 +[%s UTC] pdo_sqlsrv_stmt_execute: message = %s[SQL Server]Changed database context to '%s'. + +Done diff --git a/test/functional/pdo_sqlsrv/pdo_924_log_all_warnings.phpt b/test/functional/pdo_sqlsrv/pdo_924_log_all_warnings.phpt new file mode 100644 index 000000000..d7bfb3313 --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_924_log_all_warnings.phpt @@ -0,0 +1,239 @@ +--TEST-- +GitHub issue 924 - verifies the warnings or error messages are logged to a log file +--SKIPIF-- + +--FILE-- +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + return $conn; +} + +function printCursor($cursorArray) +{ + if ($cursorArray[PDO::ATTR_CURSOR] == PDO::CURSOR_FWDONLY) { + $cursor = 'FORWARD ONLY cursor'; + } else { + switch ($cursorArray[PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE]) { + case PDO::SQLSRV_CURSOR_DYNAMIC: + $cursor = 'server side DYNAMIC cursor'; + break; + case PDO::SQLSRV_CURSOR_STATIC: + $cursor = 'server side STATIC cursor'; + break; + case PDO::SQLSRV_CURSOR_KEYSET: + $cursor = 'server side KEYSET cursor'; + break; + case PDO::SQLSRV_CURSOR_BUFFERED: + $cursor = 'client side BUFFERED cursor'; + break; + default: + $cursor = 'error'; + break; + } + } + + echo "#####Testing $cursor#####\n"; + return $cursor; +} + +function checkResults($data, $results, $resultSet, $expectedRows) +{ + $failed = false; + for ($j = 0; $j < $expectedRows; $j++) { + if ($results[$j][0] != $data[$resultSet][$j]) { + $failed = true; + echo "Fetched results unexpected at row $j:\n"; + print_r($results[$j]); + break; + } + } + + return $failed; +} + +try { + ini_set('log_errors', '1'); + + $logFilename = 'php_924_cursors.log'; + $logFilepath = dirname(__FILE__).'/'.$logFilename; + + if (file_exists($logFilepath)) { + unlink($logFilepath); + } + + ini_set('error_log', $logFilepath); + ini_set('pdo_sqlsrv.log_severity', '3'); // warnings and errors only + + // All supported cursor types + $cursors = array(array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY), + array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_DYNAMIC), + array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_STATIC), + array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_KEYSET), + array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_BUFFERED), + ); + + + // Data for testing, all integer types + $data = array(array(86, -217483648, 0, -432987563, 7, 217483647), + array(0, 31, 127, 255, 1, 10), + array(4534, -212, 32767, 0, 7, -32768), + array(-1, 546098342985600, 9223372000000000000, 5115115115115, 7, -7), + array(0, 1, 0, 0, 1, 1), + ); + + $tableName = 'pdo_924_batchquery_test'; + + // Column names + $colName = array('c1_int', 'c2_tinyint', 'c3_smallint', 'c4_bigint', 'c5_bit'); + $columns = array(new ColumnMeta('int', $colName[0]), + new ColumnMeta('tinyint', $colName[1]), + new ColumnMeta('smallint',$colName[2]), + new ColumnMeta('bigint', $colName[3]), + new ColumnMeta('bit', $colName[4])); + + $conn = toConnect(); + createTable($conn, $tableName, $columns); + + $expectedRows = sizeof($data[0]); + + // Expected result sets = number of columns, since the batch fetches each column sequentially + $expectedResultSets = count($colName); + + // Insert each row. Need an associative array to use insertRow() + for ($i = 0; $i < $expectedRows; ++$i) { + $inputs = array(); + for ($j = 0; $j < $expectedResultSets; ++$j) { + $inputs[$colName[$j]] = $data[$j][$i]; + } + + $stmt = insertRow($conn, $tableName, $inputs); + unset($stmt); + } + + $query = "SELECT c1_int FROM $tableName; + SELECT c2_tinyint FROM $tableName; + SELECT c3_smallint FROM $tableName; + SELECT c4_bigint FROM $tableName; + SELECT c5_bit FROM $tableName;"; + + for ($i = 0; $i < sizeof($cursors); ++$i) { + $cursorType = $cursors[$i]; + // $cursor = printCursor($i); + $cursor = printCursor($cursorType); + + $stmt = $conn->prepare($query, $cursorType); + $stmt->execute(); + + $numResultSets = 0; + do { + $res = $stmt->fetchAll(PDO::FETCH_NUM); + $failed = checkResults($data, $res, $numResultSets, $expectedRows); + ++$numResultSets; + } while (!$failed && $stmt->nextRowset()); + + if ($numResultSets != $expectedResultSets) { + echo ("Unexpected number of result sets, expected $expectedResultedSets, got $numResultSets\n"); + break; + } + + if (file_exists($logFilepath)) { + echo file_get_contents($logFilepath); + unlink($logFilepath); + } + + unset($stmt); + echo "#####Finished testing with $cursor#####\n"; + } + + // Now reset logging by disabling it + ini_set('pdo_sqlsrv.log_severity', '0'); + + dropTable($conn, $tableName); + unset($conn); +} catch (PDOException $e) { + var_dump($e->errorInfo); +} + +echo "Done.\n"; + +?> +--EXPECTF-- +#####Testing FORWARD ONLY cursor##### +[%s UTC] pdo_sqlsrv_db_handle_factory: SQLSTATE = 01000 +[%s UTC] pdo_sqlsrv_db_handle_factory: error code = 5701 +[%s UTC] pdo_sqlsrv_db_handle_factory: message = %s[SQL Server]Changed database context to '%s'. +[%s UTC] pdo_sqlsrv_db_handle_factory: SQLSTATE = 01000 +[%s UTC] pdo_sqlsrv_db_handle_factory: error code = 5703 +[%s UTC] pdo_sqlsrv_db_handle_factory: message = %s[SQL Server]Changed language setting to us_english. +#####Finished testing with FORWARD ONLY cursor##### +#####Testing server side DYNAMIC cursor##### +[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 01S02 +[%s UTC] pdo_sqlsrv_stmt_execute: error code = 0 +[%s UTC] pdo_sqlsrv_stmt_execute: message = %sCursor type changed +[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 01000 +[%s UTC] pdo_sqlsrv_stmt_execute: error code = 16954 +[%s UTC] pdo_sqlsrv_stmt_execute: message = %s[SQL Server]Executing SQL directly; no cursor. +[%s UTC] pdo_sqlsrv_stmt_next_rowset: SQLSTATE = 01S02 +[%s UTC] pdo_sqlsrv_stmt_next_rowset: error code = 0 +[%s UTC] pdo_sqlsrv_stmt_next_rowset: message = %sCursor type changed +[%s UTC] pdo_sqlsrv_stmt_next_rowset: SQLSTATE = 01S02 +[%s UTC] pdo_sqlsrv_stmt_next_rowset: error code = 0 +[%s UTC] pdo_sqlsrv_stmt_next_rowset: message = %sCursor type changed +[%s UTC] pdo_sqlsrv_stmt_next_rowset: SQLSTATE = 01S02 +[%s UTC] pdo_sqlsrv_stmt_next_rowset: error code = 0 +[%s UTC] pdo_sqlsrv_stmt_next_rowset: message = %sCursor type changed +[%s UTC] pdo_sqlsrv_stmt_next_rowset: SQLSTATE = 01S02 +[%s UTC] pdo_sqlsrv_stmt_next_rowset: error code = 0 +[%s UTC] pdo_sqlsrv_stmt_next_rowset: message = %sCursor type changed +#####Finished testing with server side DYNAMIC cursor##### +#####Testing server side STATIC cursor##### +[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 01S02 +[%s UTC] pdo_sqlsrv_stmt_execute: error code = 0 +[%s UTC] pdo_sqlsrv_stmt_execute: message = %sCursor type changed +[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 01000 +[%s UTC] pdo_sqlsrv_stmt_execute: error code = 16954 +[%s UTC] pdo_sqlsrv_stmt_execute: message = %s[SQL Server]Executing SQL directly; no cursor. +[%s UTC] pdo_sqlsrv_stmt_next_rowset: SQLSTATE = 01S02 +[%s UTC] pdo_sqlsrv_stmt_next_rowset: error code = 0 +[%s UTC] pdo_sqlsrv_stmt_next_rowset: message = %sCursor type changed +[%s UTC] pdo_sqlsrv_stmt_next_rowset: SQLSTATE = 01S02 +[%s UTC] pdo_sqlsrv_stmt_next_rowset: error code = 0 +[%s UTC] pdo_sqlsrv_stmt_next_rowset: message = %sCursor type changed +[%s UTC] pdo_sqlsrv_stmt_next_rowset: SQLSTATE = 01S02 +[%s UTC] pdo_sqlsrv_stmt_next_rowset: error code = 0 +[%s UTC] pdo_sqlsrv_stmt_next_rowset: message = %sCursor type changed +[%s UTC] pdo_sqlsrv_stmt_next_rowset: SQLSTATE = 01S02 +[%s UTC] pdo_sqlsrv_stmt_next_rowset: error code = 0 +[%s UTC] pdo_sqlsrv_stmt_next_rowset: message = %sCursor type changed +#####Finished testing with server side STATIC cursor##### +#####Testing server side KEYSET cursor##### +[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 01S02 +[%s UTC] pdo_sqlsrv_stmt_execute: error code = 0 +[%s UTC] pdo_sqlsrv_stmt_execute: message = %sCursor type changed +[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 01000 +[%s UTC] pdo_sqlsrv_stmt_execute: error code = 16954 +[%s UTC] pdo_sqlsrv_stmt_execute: message = %s[SQL Server]Executing SQL directly; no cursor. +[%s UTC] pdo_sqlsrv_stmt_next_rowset: SQLSTATE = 01S02 +[%s UTC] pdo_sqlsrv_stmt_next_rowset: error code = 0 +[%s UTC] pdo_sqlsrv_stmt_next_rowset: message = %sCursor type changed +[%s UTC] pdo_sqlsrv_stmt_next_rowset: SQLSTATE = 01S02 +[%s UTC] pdo_sqlsrv_stmt_next_rowset: error code = 0 +[%s UTC] pdo_sqlsrv_stmt_next_rowset: message = %sCursor type changed +[%s UTC] pdo_sqlsrv_stmt_next_rowset: SQLSTATE = 01S02 +[%s UTC] pdo_sqlsrv_stmt_next_rowset: error code = 0 +[%s UTC] pdo_sqlsrv_stmt_next_rowset: message = %sCursor type changed +[%s UTC] pdo_sqlsrv_stmt_next_rowset: SQLSTATE = 01S02 +[%s UTC] pdo_sqlsrv_stmt_next_rowset: error code = 0 +[%s UTC] pdo_sqlsrv_stmt_next_rowset: message = %sCursor type changed +#####Finished testing with server side KEYSET cursor##### +#####Testing client side BUFFERED cursor##### +#####Finished testing with client side BUFFERED cursor##### +Done. \ 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 index 9a68d7a9f..cb92c9508 100644 --- a/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_datetime_precision.phpt +++ b/test/functional/pdo_sqlsrv/pdo_ae_bindColumn_pdoparam_datetime_precision.phpt @@ -31,7 +31,7 @@ function compareDate($dtout, $dtin, $dataType) { } $dataTypes = array("datetime2", "datetimeoffset", "time"); -$precisions = array(/*0,*/ 1, 2, 4, 7); +$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")); @@ -101,6 +101,10 @@ try { } ?> --EXPECT-- +Testing datetime2(0): +****Retrieving datetime2(0) as PDO::PARAM_STR is supported**** +****Retrieving datetime2(0) as PDO::PARAM_LOB is supported**** + Testing datetime2(1): ****Retrieving datetime2(1) as PDO::PARAM_STR is supported**** ****Retrieving datetime2(1) as PDO::PARAM_LOB is supported**** @@ -117,6 +121,10 @@ Testing datetime2(7): ****Retrieving datetime2(7) as PDO::PARAM_STR is supported**** ****Retrieving datetime2(7) as PDO::PARAM_LOB is supported**** +Testing datetimeoffset(0): +****Retrieving datetimeoffset(0) as PDO::PARAM_STR is supported**** +****Retrieving datetimeoffset(0) 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**** @@ -133,6 +141,10 @@ Testing datetimeoffset(7): ****Retrieving datetimeoffset(7) as PDO::PARAM_STR is supported**** ****Retrieving datetimeoffset(7) as PDO::PARAM_LOB is supported**** +Testing time(0): +****Retrieving time(0) as PDO::PARAM_STR is supported**** +****Retrieving time(0) 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**** diff --git a/test/functional/pdo_sqlsrv/pdo_ae_fixed_var_widths.phpt b/test/functional/pdo_sqlsrv/pdo_ae_fixed_var_widths.phpt new file mode 100644 index 000000000..ee100defa --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ae_fixed_var_widths.phpt @@ -0,0 +1,153 @@ +--TEST-- +Test Always Encrypted in Windows by comparing fetched values from fields of fixed and variable widths +--DESCRIPTION-- +See Internal issue 2824 for details. In the plaintext case, the padding is added by SQL, not the driver. For AE, the motivation was to facilitate matching between char and varchar types, that is, a deterministic encryption of char(10) with “abcd” to match varchar(10 with “abcd”. +--SKIPIF-- + +--FILE-- + $type) { + $colDef = getColDef($name, $type) . ', '; + $tsql .= $colDef; + } + + $tsql = rtrim($tsql, ', ') . ')'; + return $tsql; + +} + +function createTablePlainQuery($conn, $tableName, $columns) +{ + $tsql = "CREATE TABLE $tableName ("; + foreach ($columns as $name => $type) { + $colDef = '[' . $name . '] ' . $type . ', '; + $tsql .= $colDef; + } + + $tsql = rtrim($tsql, ', ') . ')'; + return $tsql; +} + +function compareFieldValues($f1, $f2, $qualified) +{ + $matched = true; + if ($qualified) { + if ($f1 != $f2) { + echo "Always Encrypted: values do not match!\n"; + $matched = false; + } + } else { + if (strpos($f1, $f2) != 0) { + echo "Plain text: values do not match!\n"; + $matched = false; + }; + } + + if (!$matched) { + var_dump($f1); + var_dump($f2); + } +} + +require_once("MsSetup.inc"); +require_once("MsCommon_mid-refactor.inc"); + +try { + // This test requires to connect with the Always Encrypted feature + // First check if the system is qualified to run this test + $dsn = getDSN($server, null); + $conn = new PDO($dsn, $uid, $pwd); + $qualified = isAEQualified($conn) && (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'); + + if ($qualified) { + unset($conn); + + // Now connect with ColumnEncryption enabled + $connectionInfo = "ColumnEncryption = Enabled;"; + $conn = new PDO("sqlsrv:server = $server; database=$databaseName; $connectionInfo", $uid, $pwd); + } + + $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $tableName = 'pdo_fixed_var_types_ae'; + dropTable($conn, $tableName); + + // Define the column definitions + $columns = array('c_char' => 'CHAR(10)', 'c_varchar' => 'VARCHAR(10)', + 'c_nchar' => 'NCHAR(10)', 'c_nvarchar' => 'NVARCHAR(10)', + 'c_binary' => 'BINARY(10)', 'c_varbinary' => 'VARBINARY(10)'); + + if ($qualified) { + $tsql = createTableEncryptedQuery($conn, $tableName, $columns); + } else { + $tsql = createTablePlainQuery($conn, $tableName, $columns); + } + $conn->exec($tsql); + + // Insert values + $values = array('ABCDE', 'ABCDE', + 'WXYZ', 'WXYZ', + '41424344', '41424344'); + + $tsql = "INSERT INTO $tableName (c_char, c_varchar, c_nchar, c_nvarchar, c_binary, c_varbinary) VALUES (?,?,?,?,?,?)"; + $stmt = $conn->prepare($tsql); + + for ($i = 0; $i < count($values); $i++) { + if ($i < 4) { + $stmt->bindParam($i+1, $values[$i]); + } else { + $stmt->bindParam($i+1, $values[$i], PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_BINARY); + } + } + $stmt->execute(); + unset($stmt); + + // Now fetch the values + if ($qualified) { + $tsql = "SELECT CAST(c_char AS VARCHAR(10)), c_varchar, + CAST(c_nchar AS NVARCHAR(10)), c_nvarchar, + CAST(c_binary AS VARBINARY(10)), c_varbinary FROM $tableName"; + } else { + $tsql = "SELECT c_char, c_varchar, + c_nchar, c_nvarchar, + c_binary, c_varbinary FROM $tableName"; + } + + $stmt = $conn->prepare($tsql); + $stmt->execute(); + + $row = $stmt->fetch(PDO::FETCH_NUM); + + compareFieldValues($row[0], $row[1], $qualified); + compareFieldValues($row[2], $row[3], $qualified); + compareFieldValues($row[4], $row[5], $qualified); + + dropTable($conn, $tableName); + + unset($stmt); + unset($conn); +} catch (PDOException $e) { + echo $e->getMessage(); +} + +echo "Done\n"; + +?> +--EXPECT-- +Done \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_ae_insert_datetime_encrypted.phpt b/test/functional/pdo_sqlsrv/pdo_ae_insert_datetime_encrypted.phpt new file mode 100644 index 000000000..05d7c64e3 --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ae_insert_datetime_encrypted.phpt @@ -0,0 +1,144 @@ +--TEST-- +Test for inserting and retrieving encrypted data of datetime and smalldatetime types encrypted +--DESCRIPTION-- +Verify that inserting into smalldatetime column (if encrypted) might trigger "Datetime field overflow" error +--SKIPIF-- + +--FILE-- + $type) { + $colDef = getColDef($name, $type) . ', '; + $tsql .= $colDef; + } + + $tsql = rtrim($tsql, ', ') . ')'; + return $tsql; + +} + +function createTablePlainQuery($conn, $tableName, $columns) +{ + $tsql = "CREATE TABLE $tableName ("; + foreach ($columns as $name => $type) { + $colDef = '[' . $name . '] ' . $type . ', '; + $tsql .= $colDef; + } + + $tsql = rtrim($tsql, ', ') . ')'; + return $tsql; +} + +try { + // This test requires to connect with the Always Encrypted feature + // First check if the system is qualified to run this test + $dsn = "sqlsrv:Server=$server; Database=$databaseName;"; + $conn = new PDO($dsn, $uid, $pwd); + $qualified = isAEQualified($conn) && (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'); + + if ($qualified) { + unset($conn); + + // Now connect with ColumnEncryption enabled + $connectionInfo = "ColumnEncryption = Enabled;"; + $conn = new PDO("sqlsrv:server = $server; database=$databaseName; $connectionInfo", $uid, $pwd); + } + + $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $tableName = 'pdo_datetime_encrypted'; + dropTable($conn, $tableName); + + // Define the column definitions + $columns = array('c1' => 'smalldatetime', 'c2' => 'datetime', 'c3' => 'datetime2(0)', 'c4' => 'datetime2(4)'); + + if ($qualified) { + $tsql = createTableEncryptedQuery($conn, $tableName, $columns); + } else { + $tsql = createTablePlainQuery($conn, $tableName, $columns); + } + $conn->exec($tsql); + + // Insert values that cause errors + $val1 = '9999-12-31 23:59:59'; + $val2 = null; + $val3 = null; + $val4 = '9999-12-31 23:59:59.9999'; + + $tsql = "INSERT INTO $tableName (c1, c2, c3, c4) VALUES (?,?,?,?)"; + $stmt = $conn->prepare($tsql); + + $stmt->bindParam(1, $val1); + $stmt->bindParam(2, $val2); + $stmt->bindParam(3, $val3); + $stmt->bindParam(4, $val4); + + try { + $stmt->execute(); + } catch (PDOException $e) { + $error = ($qualified)? '*Datetime field overflow' : '*The conversion of a nvarchar data type to a smalldatetime data type resulted in an out-of-range value.'; + if (!fnmatch($error, $e->getMessage())) { + echo "Expected $error but got:\n"; + var_dump($e->getMessage()); + } + } + + // These values should work + $val1 = '2021-11-03 11:49:00'; + $val2 = '2015-10-23 07:03:00.000'; + $val3 = '0001-01-01 01:01:01'; + + try { + $stmt->execute(); + } catch (PDOException $e) { + echo "Errors unexpected!!\n"; + var_dump($e->getMessage()); + } + + unset($stmt); + + // Now fetch the values + $tsql = "SELECT * FROM $tableName"; + + $stmt = $conn->prepare($tsql); + $stmt->execute(); + + $row = $stmt->fetch(PDO::FETCH_NUM); + var_dump($row); + + dropTable($conn, $tableName); + + unset($stmt); + unset($conn); +} catch (PDOException $e) { + echo $e->getMessage(); +} + +echo "Done\n"; + +?> +--EXPECT-- +array(4) { + [0]=> + string(19) "2021-11-03 11:49:00" + [1]=> + string(23) "2015-10-23 07:03:00.000" + [2]=> + string(19) "0001-01-01 01:01:01" + [3]=> + string(24) "9999-12-31 23:59:59.9999" +} +Done \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_ae_insert_decimal.phpt b/test/functional/pdo_sqlsrv/pdo_ae_insert_decimal.phpt index 4a51b434c..25521e634 100644 --- a/test/functional/pdo_sqlsrv/pdo_ae_insert_decimal.phpt +++ b/test/functional/pdo_sqlsrv/pdo_ae_insert_decimal.phpt @@ -1,20 +1,24 @@ --TEST-- Test for inserting into and retrieving from decimal columns of different scale +--DESCRIPTION-- +This test is similar to sqlsrv_ae_insert_decimal.phpt but it requires enabling column encryption in order +to test the rounding of decimal numbers --SKIPIF-- --FILE-- $num, "Testing numbers between 1 and -1:" => $frac); $scalesToTest = array(0, 1, 2, 3, 4, 5, 7, 9, 19, 28, 38); try { - $conn = connect(); + $conn = connect("ColumnEncryption=Enabled;"); $tbname = "decimalTable"; + foreach ($numSets as $testName => $numSet) { echo "\n$testName\n"; foreach ($numSet as $input) { @@ -35,7 +39,9 @@ try { foreach ($decimalTypes as $key => $value) { $insertValues = array_merge($insertValues, array($key => $input)); } - insertRow($conn, $tbname, $insertValues); + + // Use prepare / execute to bind parameters + insertRow($conn, $tbname, $insertValues, "prepareBindParam"); $stmt = $conn->query("SELECT * FROM $tbname"); $row = $stmt->fetch(PDO::FETCH_ASSOC); @@ -47,6 +53,7 @@ try { $conn->exec("TRUNCATE TABLE $tbname"); } } + dropTable($conn, $tbname); unset($conn); } catch (PDOException $e) { @@ -211,6 +218,16 @@ c4: 123456789012346261234567890123.4629 c5: 123456789012346261234567890123.46290 c7: 123456789012346261234567890123.4629000 c0: -13775323913775323913775323913775323913 +c0: 7654 +c1: 7654.0 +c2: 7654.00 +c3: 7654.000 +c4: 7654.0000 +c5: 7654.00000 +c7: 7654.0000000 +c9: 7654.000000000 +c19: 7654.0000000000000000000 +c28: 7654.0000000000000000000000000000 Testing numbers between 1 and -1: c1: .1 @@ -306,3 +323,13 @@ c38: .00000000000000000000123456789000000000 c28: -.0000000000000000000000012346 c38: -.00000000000000000000000123456789012346 c38: .00000000000000000000000000000001377532 +c0: 1 +c1: .9 +c2: .88 +c3: .880 +c4: .8800 +c5: .88000 +c7: .8800000 +c9: .880000000 +c19: .8800000000000000000 +c28: .8800000000000000000000000000 diff --git a/test/functional/pdo_sqlsrv/pdo_ae_insert_numeric.phpt b/test/functional/pdo_sqlsrv/pdo_ae_insert_numeric.phpt index 60273f342..03e90214b 100644 --- a/test/functional/pdo_sqlsrv/pdo_ae_insert_numeric.phpt +++ b/test/functional/pdo_sqlsrv/pdo_ae_insert_numeric.phpt @@ -10,6 +10,37 @@ require_once("MsCommon_mid-refactor.inc"); require_once("AEData.inc"); $dataTypes = array("bit", "tinyint", "smallint", "int", "bigint", "decimal(18,5)", "numeric(10,5)", "float", "real"); +function fetchFields($conn, $tbname, $inputValues = null) +{ + try { + $sql = "SELECT * FROM $tbname"; + $stmt = $conn->query($sql); + + if (is_null($inputValues)) { + while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { + foreach ($row as $key => $value) { + print("$key: $value\n"); + } + } + } else { + while ($row = $stmt->fetch(PDO::FETCH_NUM)) { + for ($i = 0; $i < 2; $i++) { + if (!compareFloats($inputValues[$i], $row[$i])) { + echo "Expected similar to $inputValues[$i] but got $row[$i]\n"; + } else { + echo "Values matched\n"; + } + } + } + } + } catch (PDOException $e) { + var_dump($e->errorInfo); + } catch (Exception $e) { + var_dump($e->errorInfo); + exit; + } +} + // Note the size of a float is platform dependent, with a precision of roughly 14 digits // http://php.net/manual/en/language.types.float.php try { @@ -28,9 +59,12 @@ try { $stmt = insertRow($conn, $tbname, array( "c_det" => $inputValues[0], "c_rand" => $inputValues[1] ), null, $r); if ($r === false) { isIncompatibleTypesError($stmt, $dataType, "default type"); + } elseif ($dataType == 'float' || $dataType == 'real') { + echo "-----Encrypted default type is compatible with encrypted $dataType-----\n"; + fetchFields($conn, $tbname, $inputValues); } else { echo "-----Encrypted default type is compatible with encrypted $dataType-----\n"; - fetchAll($conn, $tbname); + fetchFields($conn, $tbname); } dropTable($conn, $tbname); } @@ -79,10 +113,10 @@ c_rand: 21474\.83647 Testing float: -----Encrypted default type is compatible with encrypted float----- -c_det: (-9223372036\.8547993|-9223372036\.8547992) -c_rand: (9223372036\.8547993|9223372036\.8547992) +Values matched +Values matched Testing real: -----Encrypted default type is compatible with encrypted real----- -c_det: (-2147\.4829|-2147\.483) -c_rand: (2147\.4829|2147\.483) +Values matched +Values matched \ 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 index a3db5c7fc..0d7cd1556 100644 --- a/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_datetime_precision.phpt +++ b/test/functional/pdo_sqlsrv/pdo_ae_insert_pdoparam_datetime_precision.phpt @@ -29,7 +29,7 @@ function compareDate($dtout, $dtin, $dataType) { } $dataTypes = array("datetime2", "datetimeoffset", "time"); -$precisions = array(/*0,*/ 1, 2, 4, 7); +$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")); @@ -102,6 +102,12 @@ try { } ?> --EXPECT-- +Testing datetime2(0): +****Conversion from PDO::PARAM_BOOL to datetime2(0) is supported**** +****Conversion from PDO::PARAM_INT to datetime2(0) is supported**** +****Conversion from PDO::PARAM_STR to datetime2(0) is supported**** +****Conversion from PDO::PARAM_LOB to datetime2(0) is supported**** + Testing datetime2(1): ****Conversion from PDO::PARAM_BOOL to datetime2(1) is supported**** ****Conversion from PDO::PARAM_INT to datetime2(1) is supported**** @@ -126,6 +132,12 @@ Testing datetime2(7): ****Conversion from PDO::PARAM_STR to datetime2(7) is supported**** ****Conversion from PDO::PARAM_LOB to datetime2(7) is supported**** +Testing datetimeoffset(0): +****Conversion from PDO::PARAM_BOOL to datetimeoffset(0) is supported**** +****Conversion from PDO::PARAM_INT to datetimeoffset(0) is supported**** +****Conversion from PDO::PARAM_STR to datetimeoffset(0) is supported**** +****Conversion from PDO::PARAM_LOB to datetimeoffset(0) 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**** @@ -150,6 +162,12 @@ Testing datetimeoffset(7): ****Conversion from PDO::PARAM_STR to datetimeoffset(7) is supported**** ****Conversion from PDO::PARAM_LOB to datetimeoffset(7) is supported**** +Testing time(0): +****Conversion from PDO::PARAM_BOOL to time(0) is supported**** +****Conversion from PDO::PARAM_INT to time(0) is supported**** +****Conversion from PDO::PARAM_STR to time(0) is supported**** +****Conversion from PDO::PARAM_LOB to time(0) 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**** diff --git a/test/functional/pdo_sqlsrv/pdo_ae_insert_scientificNot.phpt b/test/functional/pdo_sqlsrv/pdo_ae_insert_scientificNot.phpt index 14205f954..b02959d9f 100644 --- a/test/functional/pdo_sqlsrv/pdo_ae_insert_scientificNot.phpt +++ b/test/functional/pdo_sqlsrv/pdo_ae_insert_scientificNot.phpt @@ -1,19 +1,80 @@ --TEST-- Test for inserting into and retrieving from decimal columns of different scale +--DESCRIPTION-- +This test is similar to sqlsrv_ae_insert_scientificNot.phpt but it requires enabling column encryption in order +to test the parsing of decimal numbers in scientific notation --SKIPIF-- --FILE-- $posExp, "Testing numbers between 1 and -1:" => $negExp); $scalesToTest = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 19); +function testErrorCases($conn) +{ + // Create a dummy table + $tableName = "pdo_sci_not"; + createTable($conn, $tableName, array("Column1" => "decimal(38, 1)")); + + $expected = '*Invalid character value for cast specification'; + + $tsql = "INSERT INTO $tableName (Column1) VALUES (?)"; + $input = ".1e-0+1."; + + $stmt = $conn->prepare($tsql); + $stmt->bindParam(1, $input); + try { + $stmt->execute(); + echo "Expect $input to fail"; + } catch (PDOException $e) { + if (!fnmatch($expected, $e->GetMessage())) { + echo $e->getMessage(); + } + } + + $input = "10E+0.1."; + try { + $stmt->execute(); + echo "Expect $input to fail"; + } catch (PDOException $e) { + if (!fnmatch($expected, $e->GetMessage())) { + echo $e->getMessage(); + } + } + + $input = "-9E0+2"; + try { + $stmt->execute(); + echo "Expect $input to fail"; + } catch (PDOException $e) { + if (!fnmatch($expected, $e->GetMessage())) { + echo $e->getMessage(); + } + } + $input = "1234.1234.1234"; + $expected = "*String data, right truncation"; + try { + $stmt->execute(); + echo "Expect $input to fail"; + } catch (PDOException $e) { + if (!fnmatch($expected, $e->GetMessage())) { + echo $e->getMessage(); + } + } + dropTable($conn, $tableName); +} + try { - $conn = connect(); + $conn = connect("ColumnEncryption=Enabled;"); + + testErrorCases($conn); + $tbname = "decimalTable"; foreach ($numSets as $testName => $numSet) { @@ -33,12 +94,9 @@ try { $insertValues = array(); foreach ($decimalTypes as $key => $value) { - if (isColEncrypted()) { - $insertValues = array_merge($insertValues, array($key => strval($input))); - } else { - $insertValues = array_merge($insertValues, array($key => $input)); - } + $insertValues = array_merge($insertValues, array($key => $input)); } + insertRow($conn, $tbname, $insertValues, "prepareBindParam"); $stmt = $conn->query("SELECT * FROM $tbname"); @@ -93,7 +151,7 @@ c6: 191.784647 c7: 191.7846470 c8: 191.78464696 c9: 191.784646962 -c19: 191.7846469620200000000 +c19: 191.7846469620226500000 c0: -833 c1: -833.3 c2: -833.33 @@ -115,7 +173,7 @@ c6: 850.000000 c7: 850.0000000 c8: 850.00000000 c9: 850.000000000 -c19: 850.0000000000000000000 +c19: 850.0000000000000600000 c0: -852 c1: -851.6 c2: -851.65 @@ -126,7 +184,7 @@ c6: -851.648352 c7: -851.6483516 c8: -851.64835165 c9: -851.648351648 -c19: -851.6483516483500000000 +c19: -851.6483516483516800000 c0: 316000 c1: 316000.0 c2: 316000.00 @@ -231,12 +289,12 @@ c1: -12345678.9 c2: -12345678.90 c3: -12345678.901 c4: -12345678.9012 -c5: -12345678.90124 +c5: -12345678.90123 c6: -12345678.901235 -c7: -12345678.9012350 -c8: -12345678.90123500 -c9: -12345678.901235000 -c19: -12345678.9012350000000000000 +c7: -12345678.9012346 +c8: -12345678.90123460 +c9: -12345678.901234600 +c19: -12345678.9012346000000000000 c0: 13775320000 c1: 13775320000.0 c2: 13775320000.00 @@ -248,6 +306,17 @@ c7: 13775320000.0000000 c8: 13775320000.00000000 c9: 13775320000.000000000 c19: 13775320000.0000000000000000000 +c0: 1000 +c1: 999.9 +c2: 999.90 +c3: 999.900 +c4: 999.9000 +c5: 999.90000 +c6: 999.900000 +c7: 999.9000000 +c8: 999.90000000 +c9: 999.900000000 +c19: 999.9000000000000000000 Testing numbers between 1 and -1: c0: -10 @@ -279,7 +348,7 @@ c6: -.019178 c7: -.0191785 c8: -.01917846 c9: -.019178465 -c19: -.0191784646962020000 +c19: -.0191784646962022650 c1: .1 c2: .08 c3: .083 @@ -299,7 +368,7 @@ c6: -.085000 c7: -.0850000 c8: -.08500000 c9: -.085000000 -c19: -.0850000000000000000 +c19: -.0850000000000000060 c1: .1 c2: .09 c3: .085 @@ -309,7 +378,7 @@ c6: .085165 c7: .0851648 c8: .08516484 c9: .085164835 -c19: .0851648351648350000 +c19: .0851648351648351680 c1: -.3 c2: -.32 c3: -.316 @@ -392,7 +461,7 @@ c6: .000123 c7: .0001235 c8: .00012346 c9: .000123457 -c19: .0001234567890123500 +c19: .0001234567890123460 c1: -.1 c2: -.14 c3: -.138 @@ -403,3 +472,11 @@ c7: -.1377532 c8: -.13775320 c9: -.137753200 c19: -.1377532000000000000 +c3: .001 +c4: .0010 +c5: .00100 +c6: .001000 +c7: .0009999 +c8: .00099990 +c9: .000999900 +c19: .0009999000000000000 diff --git a/test/functional/pdo_sqlsrv/pdo_ae_output_param_all.phpt b/test/functional/pdo_sqlsrv/pdo_ae_output_param_all.phpt index ea20d7ec8..5441ff26d 100644 --- a/test/functional/pdo_sqlsrv/pdo_ae_output_param_all.phpt +++ b/test/functional/pdo_sqlsrv/pdo_ae_output_param_all.phpt @@ -51,16 +51,19 @@ $spSql = "CREATE PROCEDURE $spname ( @c17_nchar = c17_nchar, @c18_nvarchar = c18_nvarchar FROM $tbname"; $conn->query($spSql); -// Insert data + +// Insert data, for bigint, decimal and numeric, should insert as strings +$floatInput = 9223372036.8548; +$realInput = 2147.483; $inputs = array( "c1_int" => 2147483647, "c2_smallint" => 32767, "c3_tinyint" => 255, "c4_bit" => 1, - "c5_bigint" => 922337203685479936, - "c6_decimal" => 9223372036854.80000, - "c7_numeric" => 21474.83647, - "c8_float" => 9223372036.8548, - "c9_real" => 2147.483, + "c5_bigint" => '922337203685479936', + "c6_decimal" => '9223372036854.80000', + "c7_numeric" => '21474.83647', + "c8_float" => $floatInput, + "c9_real" => $realInput, "c10_date" => '9999-12-31', "c11_datetime" => '9999-12-31 23:59:59.997', "c12_datetime2" => '9999-12-31 23:59:59.9999999', @@ -72,15 +75,18 @@ $inputs = array( "c1_int" => 2147483647, "c18_nvarchar" => '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).' ); $r; $stmt = insertRow($conn, $tbname, $inputs, null, $r); + // Call store procedure $outSql = getCallProcSqlPlaceholders($spname, count($inputs)); + +// Initialize all inputs, set bigint, decimal and numeric as empty strings $intOut = 0; $smallintOut = 0; $tinyintOut = 0; $bitOut = 0; -$bigintOut = 0.0; -$decimalOut = 0.0; -$numericOut = 0.0; +$bigintOut = ''; +$decimalOut = ''; +$numericOut = ''; $floatOut = 0.0; $realOut = 0.0; $dateOut = '0001-01-01'; @@ -119,8 +125,14 @@ print("bitOut: " . $bitOut . "\n"); print("bigintOut: " . $bigintOut . "\n"); print("decimalOut: " . $decimalOut . "\n"); print("numericOut: " . $numericOut . "\n"); -print("floatOut: " . $floatOut . "\n"); -print("realOut: " . $realOut . "\n"); +if (!compareFloats($floatInput, $floatOut)) { + // Should not expect float values to match exactly + print("Expected $floatInput but got $floatOut\n"); +} +if (!compareFloats($realInput, $realOut)) { + // Should not expect real values to match exactly + print("Expected $realInput but got $realOut\n"); +} print("dateOut: " . $dateOut . "\n"); print("datetimeOut: " . $datetimeOut . "\n"); print("datetime2Out: " . $datetime2Out . "\n"); @@ -143,8 +155,6 @@ bitOut: 1 bigintOut: 922337203685479936 decimalOut: 9223372036854\.80000 numericOut: 21474\.83647 -floatOut: (9223372036\.8547993|9\.22337e\+009) -realOut: (2147\.4829|2147\.48) dateOut: 9999-12-31 datetimeOut: (9999-12-31 23:59:59\.997|Dec 31 9999 11:59PM) datetime2Out: 9999-12-31 23:59:59\.9999999 diff --git a/test/functional/pdo_sqlsrv/pdo_ae_output_param_decimals.phpt b/test/functional/pdo_sqlsrv/pdo_ae_output_param_decimals.phpt index e1fd26cbd..884f3ee54 100644 --- a/test/functional/pdo_sqlsrv/pdo_ae_output_param_decimals.phpt +++ b/test/functional/pdo_sqlsrv/pdo_ae_output_param_decimals.phpt @@ -37,14 +37,6 @@ function printValues($msg, $det, $rand, $inputValues) 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) @@ -52,8 +44,8 @@ function compareIntegers($det, $rand, $inputValues, $pdoParamType) /////////////////////////////////////////////////////////////////////// // 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])); + return (compareFloats($inputValues[0], floatval($det)) + && compareFloats($inputValues[1], floatval($rand))); } else { // if $pdoParamType is PDO::PARAM_BOOL, expect bool(true) or bool(false) // depending on the rounded input values diff --git a/test/functional/pdo_sqlsrv/pdo_ae_output_param_errors.phpt b/test/functional/pdo_sqlsrv/pdo_ae_output_param_errors.phpt new file mode 100644 index 000000000..f6654665a --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ae_output_param_errors.phpt @@ -0,0 +1,138 @@ +--TEST-- +Test to incorrectly bind input parameters as output parameters of various types +--DESCRIPTION-- +Test to incorrectly bind input parameters as output parameters of various types. +The key is to enable ColumnEncryption and check for memory leaks. +--SKIPIF-- + +--FILE-- +getAttribute(PDO::ATTR_CLIENT_VERSION)["DriverVer"]; + $vers = explode(".", $msodbcsql_ver); + + unset($conn); + if ($vers[0] >= 17 && $vers[1] > 0){ + return true; + } else { + return false; + } +} + +require_once("MsCommon_mid-refactor.inc"); + +try { + // Check if the ODBC driver supports connecting with ColumnEncryption + // If not simply return + if (!checkODBCVersion()) { + echo "Done\n"; + return; + } + + $conn = connect("ColumnEncryption=Enabled;"); + + // Create a dummy table with various data types + $tbname = 'pdo_output_param_errors'; + $colMetaArr = array("c1_int" => "int", + "c2_smallint" => "smallint", + "c3_tinyint" => "tinyint", + "c4_bit" => "bit", + "c5_bigint" => "bigint", + "c6_decimal" => "decimal(18,5)", + "c7_numeric" => "numeric(10,5)", + "c8_float" => "float", + "c9_real" => "real", + "c10_date" => "date", + "c11_datetime" => "datetime", + "c12_datetime2" => "datetime2", + "c13_datetimeoffset" => "datetimeoffset", + "c14_time" => "time", + "c15_char" => "char(5)", + "c16_varchar" => "varchar(max)", + "c17_nchar" => "nchar(5)", + "c18_nvarchar" => "nvarchar(max)"); + createTable($conn, $tbname, $colMetaArr); + + // Create a dummy select statement + $tsql = "SELECT * FROM $tbname WHERE c1_int = ? OR c2_smallint = ? OR c3_tinyint = ? "; + $tsql .= "OR c4_bit = ? OR c5_bigint = ? OR c6_decimal = ? OR c7_numeric = ? OR c8_float = ? "; + $tsql .= "OR c9_real = ? OR c10_date = ? OR c11_datetime = ? OR c12_datetime2 = ? "; + $tsql .= "OR c13_datetimeoffset = ? OR c14_time = ? OR c15_char = ? "; + $tsql .= "OR c16_varchar = ? OR c17_nchar = ? OR c18_nvarchar = ?"; + + // Initialize all inputs, set bigint, decimal and numeric as empty strings + $intOut = 0; + $smallintOut = 0; + $tinyintOut = 0; + $bitOut = 0; + $bigintOut = ''; + $decimalOut = ''; + $numericOut = ''; + $floatOut = 0.0; + $realOut = 0.0; + $dateOut = '0001-01-01'; + $datetimeOut = '1753-01-01 00:00:00'; + $datetime2Out = '0001-01-01 00:00:00'; + $datetimeoffsetOut = '1900-01-01 00:00:00 +01:00'; + $timeOut = '00:00:00'; + $charOut = ''; + $varcharOut = ''; + $ncharOut = ''; + $nvarcharOut = ''; + + $usage1 = 0; + $rounds = 30; + for ($i = 0; $i < $rounds; $i++) { + $stmt = $conn->prepare($tsql); + + $stmt->bindParam(1, $intOut, PDO::PARAM_INT, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE); + $stmt->bindParam(2, $smallintOut, PDO::PARAM_INT, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE); + $stmt->bindParam(3, $tinyintOut, PDO::PARAM_INT, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE); + $stmt->bindParam(4, $bitOut, PDO::PARAM_INT, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE); + $stmt->bindParam(5, $bigintOut, PDO::PARAM_STR, 2048); + $stmt->bindParam(6, $decimalOut, PDO::PARAM_STR, 2048); + $stmt->bindParam(7, $numericOut, PDO::PARAM_STR, 2048); + $stmt->bindParam(8, $floatOut, PDO::PARAM_STR, 2048); + $stmt->bindParam(9, $realOut, PDO::PARAM_STR, 2048); + $stmt->bindParam(10, $dateOut, PDO::PARAM_STR, 2048); + $stmt->bindParam(11, $datetimeOut, PDO::PARAM_STR, 2048); + $stmt->bindParam(12, $datetime2Out, PDO::PARAM_STR, 2048); + $stmt->bindParam(13, $datetimeoffsetOut, PDO::PARAM_STR, 2048); + $stmt->bindParam(14, $timeOut, PDO::PARAM_STR, 2048); + $stmt->bindParam(15, $charOut, PDO::PARAM_STR, 2048); + $stmt->bindParam(16, $varcharOut, PDO::PARAM_STR, 2048); + $stmt->bindParam(17, $ncharOut, PDO::PARAM_STR, 2048); + $stmt->bindParam(18, $nvarcharOut, PDO::PARAM_STR, 2048, PDO::SQLSRV_ENCODING_UTF8); + + // Expect the following to fail so just ignore the exception caught + try { + $stmt->execute(); + } catch (PDOException $e) { + ; + } + unset($stmt); + + // Compare the current memory usage to the previous usage + if ($i == 0) { + $usage1 = memory_get_usage(); + } else { + $usage2 = memory_get_usage(); + if ($usage2 > $usage1) { + echo "Memory leaks ($i)! Expected $usage1 but now $usage2\n"; + } + } + } + + dropTable($conn, $tbname); + unset($conn); +} catch (PDOException $e) { + var_dump($e); +} + +echo "Done\n"; +?> +--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 index 61fca7c49..3fccd1032 100644 --- a/test/functional/pdo_sqlsrv/pdo_ae_output_param_floats.phpt +++ b/test/functional/pdo_sqlsrv/pdo_ae_output_param_floats.phpt @@ -22,14 +22,6 @@ $pdoParamTypes = array( ////////////////////////////////////////////////////////////////////////////////// -// 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; @@ -118,8 +110,8 @@ function testOutputFloats($fetchNumeric, $inout) } 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])) { + if (!compareFloats($inputValues[0], floatval($det)) || + !compareFloats($inputValues[1], floatval($rand))) { printValues($errMsg, $det, $rand, $inputValues); } } diff --git a/test/functional/pdo_sqlsrv/pdo_ansi_locale_fr.phpt b/test/functional/pdo_sqlsrv/pdo_ansi_locale_fr.phpt new file mode 100644 index 000000000..bcc348e42 --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ansi_locale_fr.phpt @@ -0,0 +1,92 @@ +--TEST-- +Test another ANSI encoding fr_FR euro locale outside Windows +--DESCRIPTION-- +This file must be saved in ANSI encoding and the required locale must be present +--ENV-- +PHPT_EXEC=true +--SKIPIF-- + +--FILE-- +prepare($tsql); + + for ($i = 0; $i < count($inputs); $i++) { + $stmt->execute(array($i, $inputs[$i])); + } + } catch( PDOException $e ) { + echo "Failed to insert data\n"; + print_r( $e->getMessage() ); + } +} + +function dropTable($conn, $tableName) +{ + $tsql = "IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'" . $tableName . "') AND type in (N'U')) DROP TABLE $tableName"; + $conn->exec($tsql); +} + +require_once('MsSetup.inc'); + +try { + $r = setlocale(LC_ALL, 'fr_FR@euro'); + if (empty($r)) { + // Some platforms use a different locale name + $r = setlocale(LC_ALL, 'fr_FR.ISO8859-15'); + if (empty($r)) { + die("The required French locale is not available"); + } + } + + $conn = new PDO("sqlsrv:server = $server; database=$databaseName; driver=$driver", $uid, $pwd); + $conn->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_SYSTEM); + $tableName = "pdo_ansitest_FR"; + + dropTable($conn, $tableName); + + $tsql = "CREATE TABLE $tableName([id] [int] NOT NULL, [phrase] [varchar](50) NULL)"; + $conn->exec($tsql); + + $inputs = array(" tout l'heure!", + "Je suis dsol.", + " plus!", + " Je dois aller l'cole."); + + // Next, insert the strings + insertData($conn, $tableName, $inputs); + + // Next, fetch the strings + $tsql = "SELECT phrase FROM $tableName ORDER by id"; + $stmt = $conn->query($tsql); + + $results = $stmt->fetchAll(PDO::FETCH_NUM); + for ($i = 0; $i < count($inputs); $i++) { + if ($results[$i][0] !== $inputs[$i]) { + echo "Unexpected phrase retrieved:\n"; + var_dump($results[$i][0]); + } + } + + dropTable($conn, $tableName); + + unset($stmt); + unset($conn); +} catch (PDOException $e) { + print_r($e->getMessage()); +} + +echo "Done" . PHP_EOL; +?> +--EXPECT-- +Done diff --git a/test/functional/pdo_sqlsrv/pdo_ansi_locale_zh.phpt b/test/functional/pdo_sqlsrv/pdo_ansi_locale_zh.phpt new file mode 100644 index 000000000..50596026e --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_ansi_locale_zh.phpt @@ -0,0 +1,77 @@ +--TEST-- +Test Chinese locale in Linux +--DESCRIPTION-- +This test requires ODBC Driver 17.6 or above and will invoke another php script that +is saved as GB2312(Simplified Chinese) ANSI format, namely pdo_test_gb18030.php. +To run this test, create a temporary database first with the correct collation + CREATE DATABASE [GB18030test] + COLLATE Chinese_PRC_CI_AS +Next, set the correct locale and convert the php script, like this: + export LC_ALL=zh_CN.gb18030 + iconv -c -f GB2312 -t GB18030 pdo_test_gb18030.php > test_gb18030.php +Drop the temporary database when the test is finished. +--ENV-- +PHPT_EXEC=true +--SKIPIF-- +getAttribute(PDO::ATTR_CLIENT_VERSION)['DriverVer']; + $version = explode(".", $msodbcsqlVer); + + $msodbcsqlMaj = $version[0]; + $msodbcsqlMin = $version[1]; + + if ($msodbcsqlMaj < 17) { + die("skip Unsupported ODBC driver version"); + } + + if ($msodbcsqlMaj == 17 && $msodbcsqlMin < 6) { + die("skip Unsupported ODBC driver version"); + } +} catch (PDOException $e) { + die("skip Something went wrong during SKIPIF."); +} +?> + +--FILE-- +exec($query); + + shell_exec("export LC_ALL=zh_CN.gb18030"); + shell_exec("iconv -c -f GB2312 -t GB18030 ".dirname(__FILE__)."/pdo_test_gb18030.php > ".dirname(__FILE__)."/test_gb18030.php"); + + print_r(shell_exec(PHP_BINARY." ".dirname(__FILE__)."/test_gb18030.php $tempDB")); +} + +try { + $tempDB = 'GB18030test' . rand(1, 100); + require_once('MsSetup.inc'); + + $conn = new PDO("sqlsrv:server = $server;database=master;driver=$driver", $uid, $pwd); + $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + runTest($conn, $tempDB); +} catch (PDOException $e) { + echo $e->getMessage() . PHP_EOL; +} finally { + if ($conn) { + $query = "DROP DATABASE $tempDB"; + $conn->exec($query); + unset($conn); + } +} + +?> +--EXPECT-- +Done diff --git a/test/functional/pdo_sqlsrv/pdo_buffered_fetch_types.phpt b/test/functional/pdo_sqlsrv/pdo_buffered_fetch_types.phpt index a10bf6c38..ebf197655 100644 --- a/test/functional/pdo_sqlsrv/pdo_buffered_fetch_types.phpt +++ b/test/functional/pdo_sqlsrv/pdo_buffered_fetch_types.phpt @@ -14,18 +14,52 @@ $outOfRange = 'Numeric value out of range'; $truncation = 'Fractional truncation'; $epsilon = 0.00001; +function fetchAsChar($conn, $tableName, $inputs) +{ + $query = "SELECT c1, c2, c3, c4, c5, c6 FROM $tableName"; + try { + $stmt = $conn->prepare($query, array(PDO::ATTR_CURSOR=>PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE=>PDO::SQLSRV_CURSOR_BUFFERED)); + $stmt->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_SYSTEM); + + // Fetch all fields as strings - no conversion + for ($i = 0; $i < count($inputs) - 1; $i++) { + $stmt->execute(); + $f = $stmt->fetchColumn($i); + + if ($i == 2) { + if (!compareFloats(floatval($inputs[$i]), floatval($f))) { + echo "In fetchAsChar ($i): expected $inputs[$i]\n"; + var_dump($f); + } + } elseif ($f !== $inputs[$i]) { + echo "In fetchAsChar ($i): expected $inputs[$i]\n"; + var_dump($f); + } + } + } catch (PdoException $e) { + echo "Caught exception in fetchAsChar:\n"; + echo $e->getMessage() . PHP_EOL; + } +} + function fetchAsUTF8($conn, $tableName, $inputs) { $query = "SELECT * FROM $tableName"; try { $stmt = $conn->prepare($query, array(PDO::ATTR_CURSOR=>PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE=>PDO::SQLSRV_CURSOR_BUFFERED)); - + // Fetch all fields as UTF-8 strings for ($i = 0; $i < count($inputs); $i++) { $stmt->execute(); $f = $stmt->fetchColumn($i); - if ($f !== $inputs[$i]) { + if ($i == 2) { + if (!compareFloats(floatval($inputs[$i]), floatval($f))) { + echo "In fetchAsUTF8 ($i): expected $inputs[$i]\n"; + var_dump($f); + } + } elseif ($f !== $inputs[$i]) { + echo "In fetchAsUTF8 ($i): expected $inputs[$i]\n"; var_dump($f); } } @@ -45,8 +79,16 @@ function fetchArray($conn, $tableName, $inputs) // By default, even numeric or datetime fields are fetched as strings $result = $stmt->fetch(PDO::FETCH_NUM); for ($i = 0; $i < count($inputs); $i++) { - if ($result[$i] !== $inputs[$i]) { - var_dump($f); + if ($i == 2) { + $expected = floatval($inputs[$i]); + if (!compareFloats($expected, floatval($result[$i]))) { + echo "in fetchArray: for column $i expected $expected but got: "; + var_dump($result[$i]); + } + } + elseif ($result[$i] !== $inputs[$i]) { + echo "in fetchArray: for column $i expected $inputs[$i] but got: "; + var_dump($result[$i]); } } } catch (PdoException $e) { @@ -131,14 +173,7 @@ function fetchCharAsInt($conn, $tableName, $column) $stmt->bindColumn($column, $value, PDO::PARAM_INT); $row = $stmt->fetch(PDO::FETCH_BOUND); - // TODO 11297: fix this part outside Windows later - if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { - echo "in fetchCharAsInt: exception should have been thrown!\n"; - } else { - if ($value != 0) { - var_dump($value); - } - } + echo "in fetchCharAsInt: exception should have been thrown!\n"; } catch (PdoException $e) { // The (n)varchar field - expect the outOfRange error if (strpos($e->getMessage(), $outOfRange) === false) { @@ -180,6 +215,35 @@ function fetchAsNumerics($conn, $tableName, $inputs) } } +function fetchNumbers($conn, $tableName, $inputs) +{ + // Fetch integers and floats as numbers, not strings + try { + $query = "SELECT c2, c3, c4 FROM $tableName"; + $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); + + $stmt = $conn->prepare($query, array(PDO::ATTR_CURSOR=>PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE=>PDO::SQLSRV_CURSOR_BUFFERED)); + $stmt->setAttribute(PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE, true); + $stmt->execute(); + + $row = $stmt->fetch(PDO::FETCH_NUM); + if ($row[0] !== intval($inputs[1])) { + var_dump($row[0]); + } + $expected = floatval($inputs[2]); + if (!compareFloats($expected, $row[1])) { + echo "in fetchNumbers: expected $expected but got: "; + var_dump($row[1]); + } + if ($row[2] !== $inputs[3]) { + var_dump($row[2]); + } + } catch (PdoException $e) { + echo "Caught exception in fetchAsNumerics:\n"; + echo $e->getMessage() . PHP_EOL; + } +} + try { $conn = connect(); $conn->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false); @@ -212,11 +276,13 @@ try { unset($stmt); // Starting fetching using client buffers + fetchAsChar($conn, $tableName, $inputs); fetchAsUTF8($conn, $tableName, $inputs); fetchArray($conn, $tableName, $inputs); fetchBinaryAsNumber($conn, $tableName, $inputs); fetchBinaryAsBinary($conn, $tableName, $inputs); fetchAsNumerics($conn, $tableName, $inputs); + fetchNumbers($conn, $tableName, $inputs); // dropTable($conn, $tableName); echo "Done\n"; diff --git a/test/functional/pdo_sqlsrv/pdo_connection_logs.phpt b/test/functional/pdo_sqlsrv/pdo_connection_logs.phpt index 46ea1cdfc..762537a60 100644 --- a/test/functional/pdo_sqlsrv/pdo_connection_logs.phpt +++ b/test/functional/pdo_sqlsrv/pdo_connection_logs.phpt @@ -44,6 +44,9 @@ try { } else { echo "$logFilepath is missing!\n"; } + + // Now reset logging by disabling it + ini_set('pdo_sqlsrv.log_severity', '0'); echo "Done\n"; } catch (Exception $e) { @@ -56,6 +59,9 @@ try { [%s UTC] pdo_sqlsrv_db_handle_factory: SQLSTATE = 01000 [%s UTC] pdo_sqlsrv_db_handle_factory: error code = 5701 [%s UTC] pdo_sqlsrv_db_handle_factory: message = %s[SQL Server]Changed database context to '%s'. +[%s UTC] pdo_sqlsrv_db_handle_factory: SQLSTATE = 01000 +[%s UTC] pdo_sqlsrv_db_handle_factory: error code = 5703 +[%s UTC] pdo_sqlsrv_db_handle_factory: message = %s[SQL Server]Changed language setting to %s. [%s UTC] pdo_sqlsrv_dbh_prepare: entering [%s UTC] pdo_sqlsrv_stmt_execute: entering [%s UTC] pdo_sqlsrv_stmt_describe_col: entering diff --git a/test/functional/pdo_sqlsrv/pdo_connection_quote.phpt b/test/functional/pdo_sqlsrv/pdo_connection_quote.phpt index d3865d0a2..26b39fcd6 100644 --- a/test/functional/pdo_sqlsrv/pdo_connection_quote.phpt +++ b/test/functional/pdo_sqlsrv/pdo_connection_quote.phpt @@ -19,11 +19,23 @@ try { $output3 = $conn->quote("The quick brown fox jumps over the lazy dog0123456789"); var_dump($output3); - $stmt = $conn->query(""); - if ($stmt != false) { - echo("Empty query was expected to fail!\n"); + if (PHP_MAJOR_VERSION < 8) { + $stmt = $conn->query(""); + if ($stmt != false) { + echo("Empty query was expected to fail!\n"); + } + unset($stmt); + } else { + try { + $stmt = $conn->query(""); + echo("Empty query was expected to fail!\n"); + } catch (ValueError $ve) { + $error = '*PDO::query(): Argument #1 ($query) cannot be empty'; + if (!fnmatch($error, $ve->getMessage())) { + var_dump($ve->getMessage()); + } + } } - unset($stmt); $stmt1 = $conn->prepare($output2); $result = $stmt1->execute(); diff --git a/test/functional/pdo_sqlsrv/pdo_construct.phpt b/test/functional/pdo_sqlsrv/pdo_construct.phpt index 6521f23de..eba2c640e 100644 --- a/test/functional/pdo_sqlsrv/pdo_construct.phpt +++ b/test/functional/pdo_sqlsrv/pdo_construct.phpt @@ -7,11 +7,13 @@ Test PDO::__Construct by passing connection options and attributes. require_once("MsCommon_mid-refactor.inc"); try { + // With PHP 8.0 the default is PDO::ERRMODE_EXCEPTION rather than PDO::ERRMODE_SILENT + // With PHP 7.X the ATTR_ERRMODE must be set before the unsupported attribute(s) to have any effect $attr = array( PDO::SQLSRV_ATTR_ENCODING => 3, PDO::ATTR_CASE => 2, + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_PREFETCH => false, PDO::ATTR_TIMEOUT => 35, - PDO::ATTR_ERRMODE => 2, PDO::ATTR_STRINGIFY_FETCHES => true, PDO::SQLSRV_ATTR_DIRECT_QUERY => true, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, @@ -33,6 +35,7 @@ try { "TransactionIsolation = " . PDO::SQLSRV_TXN_READ_UNCOMMITTED . ";" . "TrustServerCertificate = false;" . "WSID = whatever;"; + $conn = connect($dsn, $attr); echo "Test Successful\n"; } catch (PDOException $e) { @@ -41,4 +44,12 @@ try { } ?> --EXPECT-- -Test Successful +array(3) { + [0]=> + string(5) "IMSSP" + [1]=> + int(-38) + [2]=> + string(58) "An unsupported attribute was designated on the PDO object." +} +Test Successful \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_construct_attr.phpt b/test/functional/pdo_sqlsrv/pdo_construct_attr.phpt index 92dfc4757..cba24eab0 100644 --- a/test/functional/pdo_sqlsrv/pdo_construct_attr.phpt +++ b/test/functional/pdo_sqlsrv/pdo_construct_attr.phpt @@ -7,8 +7,10 @@ Test PDO::__Construct by passing different connection attributes require_once("MsCommon_mid-refactor.inc"); try { + // With PHP 8.0 the default is PDO::ERRMODE_EXCEPTION rather than PDO::ERRMODE_SILENT $attr = array( PDO::SQLSRV_ATTR_ENCODING => 3, PDO::ATTR_CASE => 2, + PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT, PDO::ATTR_PREFETCH => false, PDO::ATTR_TIMEOUT => 35, PDO::ATTR_STRINGIFY_FETCHES => true, diff --git a/test/functional/pdo_sqlsrv/pdo_data_classification_ranks.phpt b/test/functional/pdo_sqlsrv/pdo_data_classification_ranks.phpt new file mode 100644 index 000000000..f97be99e5 --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_data_classification_ranks.phpt @@ -0,0 +1,357 @@ +--TEST-- +Test data classification feature - retrieving sensitivity metadata if supported +--DESCRIPTION-- +If both ODBC and server support this feature, this test verifies that sensitivity metadata can be added and correctly retrieved. If not, it will at least test the new statement attribute and some error cases. +T-SQL reference: https://docs.microsoft.com/sql/t-sql/statements/add-sensitivity-classification-transact-sql +--ENV-- +PHPT_EXEC=true +--SKIPIF-- + +--FILE-- + "NONE", 10 => "LOW", 20 => "MEDIUM", 30 => "HIGH", 40 => "CRITICAL"); + +function testConnAttrCases() +{ + // Attribute PDO::SQLSRV_ATTR_DATA_CLASSIFICATION is limited to statement level only + global $server, $databaseName, $driver, $uid, $pwd; + + $stmtErr = '*The given attribute is only supported on the PDOStatement object.'; + $noSupportErr = '*driver does not support that attribute'; + + try { + $dsn = getDSN($server, $databaseName, $driver); + $attr = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::SQLSRV_ATTR_DATA_CLASSIFICATION => true); + $conn = new PDO($dsn, $uid, $pwd, $attr); + } catch (PDOException $e) { + if (!fnmatch($stmtErr, $e->getMessage())) { + echo "Connection attribute test (1) unexpected\n"; + var_dump($e->getMessage()); + } + } + + try { + $dsn = getDSN($server, $databaseName, $driver); + $attr = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION); + $conn = new PDO($dsn, $uid, $pwd, $attr); + $conn->setAttribute(PDO::SQLSRV_ATTR_DATA_CLASSIFICATION, true); + } catch (PDOException $e) { + if (!fnmatch($stmtErr, $e->getMessage())) { + echo "Connection attribute test (2) unexpected\n"; + var_dump($e->getMessage()); + } + } + + try { + $dsn = getDSN($server, $databaseName, $driver); + $attr = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION); + $conn = new PDO($dsn, $uid, $pwd, $attr); + $conn->getAttribute(PDO::SQLSRV_ATTR_DATA_CLASSIFICATION); + } catch (PDOException $e) { + if (!fnmatch($noSupportErr, $e->getMessage())) { + echo "Connection attribute test (3) unexpected\n"; + var_dump($e->getMessage()); + } + } +} + +function testNotAvailable($conn, $tableName, $isSupported, $driverCapable) +{ + // If supported, the query should return a column with no classification + $options = array(PDO::SQLSRV_ATTR_DATA_CLASSIFICATION => true); + $tsql = ($isSupported)? "SELECT PatientId FROM $tableName" : "SELECT * FROM $tableName"; + $stmt = $conn->prepare($tsql, $options); + $stmt->execute(); + + $notAvailableErr = '*Failed to retrieve Data Classification Sensitivity Metadata. If the driver and the server both support the Data Classification feature, check whether the query returns columns with classification information.'; + + $unexpectedErrorState = '*Failed to retrieve Data Classification Sensitivity Metadata: Check if ODBC driver or the server supports the Data Classification feature.'; + + $error = ($driverCapable) ? $notAvailableErr : $unexpectedErrorState; + try { + $metadata = $stmt->getColumnMeta(0); + echo "testNotAvailable: expected getColumnMeta to fail\n"; + } catch (PDOException $e) { + if (!fnmatch($error, $e->getMessage())) { + echo "testNotAvailable: exception unexpected\n"; + var_dump($e->getMessage()); + } + } +} + +function isDataClassSupported($conn, &$driverCapable) +{ + // Check both SQL Server version and ODBC driver version + $msodbcsqlVer = $conn->getAttribute(PDO::ATTR_CLIENT_VERSION)["DriverVer"]; + $version = explode(".", $msodbcsqlVer); + + // ODBC Driver must be 17.2 or above + $driverCapable = true; + if ($version[0] < 17 || $version[1] < 2) { + $driverCapable = false; + return false; + } + + // SQL Server must be SQL Server 2019 or above + $serverVer = $conn->getAttribute(PDO::ATTR_SERVER_VERSION); + if (explode('.', $serverVer)[0] < 15) + return false; + + return true; +} + +function getRegularMetadata($conn, $tsql) +{ + // Run the query without data classification metadata + $stmt1 = $conn->query($tsql); + + // Run the query with the attribute set to false + $options = array(PDO::SQLSRV_ATTR_DATA_CLASSIFICATION => false); + $stmt2 = $conn->prepare($tsql, $options); + $stmt2->execute(); + + // The metadata for each column should be identical + $numCol = $stmt1->columnCount(); + for ($i = 0; $i < $numCol; $i++) { + $metadata1 = $stmt1->getColumnMeta($i); + $metadata2 = $stmt2->getColumnMeta($i); + + $diff = array_diff($metadata1, $metadata2); + if (!empty($diff)) { + print_r($diff); + } + } + + return $stmt1; +} + +function verifyClassInfo($rank, $input, $actual) +{ + // For simplicity of this test, only one set of sensitivity data (Label, Information Type) + // plus overall rank info + if (count($actual) != 2) { + echo "Expected an array with only two elements\n"; + return false; + } + + if (count($actual[0]) != 3) { + echo "Expected a Label pair and Information Type pair plus column rank info\n"; + return false; + } + + // Label should be name and id pair (id should be empty) + if (count($actual[0]['Label']) != 2) { + echo "Expected only two elements for the label\n"; + return false; + } + $label = $input[0]; + if ($actual[0]['Label']['name'] !== $label || !empty($actual[0]['Label']['id'])){ + return false; + } + + // Like Label, Information Type should also be name and id pair (id should be empty) + if (count($actual[0]['Information Type']) != 2) { + echo "Expected only two elements for the information type\n"; + return false; + } + $info = $input[1]; + if ($actual[0]['Information Type']['name'] !== $info || !empty($actual[0]['Information Type']['id'])){ + return false; + } + + if ($actual[0]['rank'] != $rank) { + return false; + } + + if ($actual['rank'] != $rank) { + return false; + } + + return true; +} + +function assignDataClassification($conn, $tableName, $classData, $rankId = 0) +{ + global $ranks; + + $rank = ", RANK = $ranks[$rankId]"; + + // column SSN + $label = $classData[1][0]; + $infoType = $classData[1][1]; + $sql = "ADD SENSITIVITY CLASSIFICATION TO [$tableName].SSN WITH (LABEL = '$label', INFORMATION_TYPE = '$infoType' $rank)"; + $conn->query($sql); + + // column BirthDate + $label = $classData[4][0]; + $infoType = $classData[4][1]; + $sql = "ADD SENSITIVITY CLASSIFICATION TO [$tableName].BirthDate WITH (LABEL = '$label', INFORMATION_TYPE = '$infoType' $rank)"; + $conn->query($sql); +} + +function compareDataClassification($stmt1, $stmt2, $classData, $rank) +{ + global $dataClassKey; + + $numCol = $stmt1->columnCount(); + $noClassInfo = array($dataClassKey => array()); + + for ($i = 0; $i < $numCol; $i++) { + $metadata1 = $stmt1->getColumnMeta($i); + $metadata2 = $stmt2->getColumnMeta($i); + + // If classification sensitivity data exists, only the + // 'flags' field should be different + foreach ($metadata2 as $key => $value) { + if ($key == 'flags') { + // Is classification input data empty? + if (empty($classData[$i])) { + // Then it should be equivalent to $noClassInfo + if ($value !== $noClassInfo) { + var_dump($value); + } + } else { + // Verify the classification metadata + if (!verifyClassInfo($rank, $classData[$i], $value[$dataClassKey])) { + var_dump($value); + } + } + } else { + // The other fields should be identical + if ($metadata1[$key] !== $value) { + var_dump($value); + } + } + } + } +} + +function runBatchQuery($conn, $tableName) +{ + global $dataClassKey; + + $options = array(PDO::SQLSRV_ATTR_DATA_CLASSIFICATION => true); + $tsql = "SELECT SSN, BirthDate FROM $tableName"; + + // Run a batch query + $batchQuery = $tsql . ';' . $tsql; + $stmt = $conn->prepare($batchQuery, $options); + $stmt->execute(); + + $numCol = $stmt->columnCount(); + + // The metadata returned should be the same + $c = rand(0, $numCol - 1); + $metadata1 = $stmt->getColumnMeta($c); + $stmt->nextRowset(); + $metadata2 = $stmt->getColumnMeta($c); + + // Check the returned flags + $data1 = $metadata1['flags']; + $data2 = $metadata2['flags']; + + if (!array_key_exists($dataClassKey, $data1) || !array_key_exists($dataClassKey, $data2)) { + echo "Metadata returned with no classification data\n"; + var_dump($data1); + var_dump($data2); + } else { + $jstr1 = json_encode($data1[$dataClassKey]); + $jstr2 = json_encode($data2[$dataClassKey]); + if ($jstr1 !== $jstr2) { + echo "The JSON encoded strings should be identical\n"; + var_dump($jstr1); + var_dump($jstr2); + } + } +} + +function checkResults($conn, $stmt, $tableName, $classData, $rank = 0) +{ + $tsql = "SELECT * FROM $tableName"; + + $options = array(PDO::SQLSRV_ATTR_DATA_CLASSIFICATION => true); + $stmt1 = $conn->prepare($tsql, $options); + $stmt1->execute(); + + compareDataClassification($stmt, $stmt1, $classData, $rank); + + // $stmt2 should produce the same result as the previous $stmt1 + $stmt2 = $conn->prepare($tsql); + $stmt2->execute(); + $stmt2->setAttribute(PDO::SQLSRV_ATTR_DATA_CLASSIFICATION, true); + + compareDataClassification($stmt, $stmt2, $classData, $rank); + + unset($stmt1); + unset($stmt2); + + runBatchQuery($conn, $tableName); +} + +/////////////////////////////////////////////////////////////////////////////////////// +try { + testConnAttrCases(); + + $conn = connect(); + $driverCapable = true; + $isSupported = isDataClassSupported($conn, $driverCapable); + + // Create a test table + $tableName = 'pdoPatients'; + $colMeta = array(new ColumnMeta('INT', 'PatientId', 'IDENTITY NOT NULL'), + new ColumnMeta('CHAR(11)', 'SSN'), + new ColumnMeta('NVARCHAR(50)', 'FirstName'), + new ColumnMeta('NVARCHAR(50)', 'LastName'), + new ColumnMeta('DATE', 'BirthDate')); + createTable($conn, $tableName, $colMeta); + + // If data classification is supported, then add sensitivity classification metadata + // to columns SSN and Birthdate + $classData = [ + array(), + array('Highly Confidential - GDPR', 'Credentials'), + array(), + array(), + array('Confidential Personal Data', 'Birthdays') + ]; + + if ($isSupported) { + assignDataClassification($conn, $tableName, $classData); + } + + // Test another error condition + testNotAvailable($conn, $tableName, $isSupported, $driverCapable); + + // Run the query without data classification metadata + $tsql = "SELECT * FROM $tableName"; + $stmt = getRegularMetadata($conn, $tsql); + + // Proceeed to retrieve sensitivity metadata, if supported + if ($isSupported) { + checkResults($conn, $stmt, $tableName, $classData); + + // Test another rank (get a random one) + $random = rand(1, 4); + $rank = $random * 10; + + trace("Testing with $rank\n"); + assignDataClassification($conn, $tableName, $classData, $rank); + checkResults($conn, $stmt, $tableName, $classData, $rank); + } + + dropTable($conn, $tableName); + + unset($stmt); + unset($conn); + + echo "Done\n"; +} catch (PDOException $e) { + var_dump($e->getMessage()); +} +?> +--EXPECT-- +Done \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_error.phpt b/test/functional/pdo_sqlsrv/pdo_error.phpt index 65ddce7e4..3b3b4ac68 100644 --- a/test/functional/pdo_sqlsrv/pdo_error.phpt +++ b/test/functional/pdo_sqlsrv/pdo_error.phpt @@ -5,21 +5,36 @@ Test the PDO::errorCode() and PDO::errorInfo() methods. --FILE-- query("SELECT * FROM $tbname WHERE IntColX = 1"); + $tbname = "PDO_test_error"; + + // create a dummy table + createTable($db, $tbname, array(new ColumnMeta("int", "id"))); + + try { + // query with a wrong column name -- catch the exception and show errors + $stmt = $db->query("SELECT * FROM $tbname WHERE IntColX = 1"); + echo "Should have thrown an exception!\n"; + } catch (PDOException $e) { + echo $db->errorCode() . PHP_EOL; + if ($e->getCode() != $db->errorCode()) { + echo "Error codes do not match!\n"; + echo $e->getCode() . PHP_EOL; + } + $info = $db->errorInfo(); + print_r($info); + if ($e->errorInfo != $info) { + echo "Error info arrays do not match!\n"; + print_r($e->errorInfo); + } + } dropTable($db, $tbname); - unset($conn); + unset($db); } catch (PDOException $e) { - print($db->errorCode()); - echo "\n"; - print_r($db->errorInfo()); + var_dump($e); } ?> --EXPECTREGEX-- @@ -29,4 +44,7 @@ Array \[0\] => 42S22 \[1\] => 207 \[2\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Invalid column name 'IntColX'\. + \[3\] => 42000 + \[4\] => 8180 + \[5\] => \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]\[SQL Server\]Statement\(s\) could not be prepared\. \) \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdo_errorMode_logs.phpt b/test/functional/pdo_sqlsrv/pdo_errorMode_logs.phpt index a0169696f..239a8c509 100644 --- a/test/functional/pdo_sqlsrv/pdo_errorMode_logs.phpt +++ b/test/functional/pdo_sqlsrv/pdo_errorMode_logs.phpt @@ -96,6 +96,9 @@ Done with 0 [%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 42S02 [%s UTC] pdo_sqlsrv_stmt_execute: error code = 208 [%s UTC] pdo_sqlsrv_stmt_execute: message = %s[SQL Server]Invalid object name 'temp_table'. +[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 42000 +[%s UTC] pdo_sqlsrv_stmt_execute: error code = 8180 +[%s UTC] pdo_sqlsrv_stmt_execute: message = %s[SQL Server]Statement(s) could not be prepared. Done with 1 [%s UTC] PHP Warning: PDO::query(): SQLSTATE[42S02]: Base table or view not found: 208 %s[SQL Server]Invalid object name 'temp_table'. in %spdo_errorMode_logs.php on line %d @@ -112,5 +115,8 @@ Done with 4 [%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 42S02 [%s UTC] pdo_sqlsrv_stmt_execute: error code = 208 [%s UTC] pdo_sqlsrv_stmt_execute: message = %s[SQL Server]Invalid object name 'temp_table'. +[%s UTC] pdo_sqlsrv_stmt_execute: SQLSTATE = 42000 +[%s UTC] pdo_sqlsrv_stmt_execute: error code = 8180 +[%s UTC] pdo_sqlsrv_stmt_execute: message = %s[SQL Server]Statement(s) could not be prepared. Done with -1 diff --git a/test/functional/pdo_sqlsrv/pdo_fetch_column_twice.phpt b/test/functional/pdo_sqlsrv/pdo_fetch_column_twice.phpt index 7e2ec1946..692b737b0 100644 --- a/test/functional/pdo_sqlsrv/pdo_fetch_column_twice.phpt +++ b/test/functional/pdo_sqlsrv/pdo_fetch_column_twice.phpt @@ -88,21 +88,42 @@ function fetchColumnOutOfBound1($conn, $tableName, $col) echo "Error message unexpected in fetchColumnOutOfBound1\n"; var_dump($e->getMessage()); } + } catch (ValueError $ve) { + $error = '*Column index must be greater than or equal to 0'; + if (!fnmatch($error, $ve->getMessage())) { + echo "Error message unexpected in fetchColumnOutOfBound1\n"; + var_dump($ve->getMessage()); + } } } function fetchColumnOutOfBound2($conn, $tableName, $col) { + $error = '*Invalid column index'; try { $tsql = "SELECT * FROM $tableName"; $stmt = $conn->query($tsql, PDO::FETCH_COLUMN, $col); $result = $stmt->fetch(); unset($stmt); - } catch (PDOException $e) { - var_dump($e->getMessage()); + } catch (Error $e) { + if (!fnmatch($error, $e->getMessage())) { + var_dump($e->getMessage()); + } + } catch (ValueError $ve) { + if (!fnmatch($error, $ve->getMessage())) { + var_dump($ve->getMessage()); + } } } +// When testing with PHP 8.0 some test cases throw ValueError instead of exceptions or warnings. +// Thus implement a custom warning handler such that with PHP 7.x the warning would be handled +// to throw an Error (ValueError not available). +function warningHandler($errno, $errstr) +{ + throw new Error($errstr); +} + try { $conn = connect(); $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); @@ -135,7 +156,9 @@ try { // Change to warning mode $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); + set_error_handler("warningHandler", E_WARNING); fetchColumnOutOfBound2($conn, $tableName, $numCols + 1); + restore_error_handler(); dropTable($conn, $tableName); unset($conn); @@ -144,8 +167,5 @@ try { var_dump($e); } ?> ---EXPECTREGEX-- -Warning: PDOStatement::fetch\(\): SQLSTATE\[HY000\]: General error: Invalid column index in .+(\/|\\)pdo_fetch_column_twice.php on line [0-9]+ - -Warning: PDOStatement::fetch\(\): SQLSTATE\[HY000\]: General error in .+(\/|\\)pdo_fetch_column_twice.php on line [0-9]+ +--EXPECT-- Done diff --git a/test/functional/pdo_sqlsrv/pdo_fetch_fetchinto_query_args.phpt b/test/functional/pdo_sqlsrv/pdo_fetch_fetchinto_query_args.phpt index 72991158a..50a5cf1a3 100644 --- a/test/functional/pdo_sqlsrv/pdo_fetch_fetchinto_query_args.phpt +++ b/test/functional/pdo_sqlsrv/pdo_fetch_fetchinto_query_args.phpt @@ -1,5 +1,7 @@ --TEST-- fetch columns using fetch mode and different ways of binding columns +--DESCRIPTION-- +This test should not use temporary table as it might occasionally cause deadlocked transactions. --SKIPIF-- --FILE-- @@ -27,19 +29,22 @@ function FetchInto_Query_Args() include("MsSetup.inc"); set_time_limit(0); - $tableName = GetTempTableName(); + $tableName = 'fetchinto_query_args'; $conn = new PDO( "sqlsrv:server=$server;database=$databaseName", $uid, $pwd); + $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); - $stmt = $conn->exec("CREATE TABLE $tableName ([c1_int] int, [c2_tinyint] tinyint, [c3_smallint] smallint, [c4_bigint] bigint, [c5_bit] bit, [c6_float] float, [c7_real] real, [c8_decimal] decimal(28,4), [c9_numeric] numeric(32,4), [c10_money] money, [c11_smallmoney] smallmoney, [c12_char] char(512), [c13_varchar] varchar(512), [c14_varchar_max] varchar(max), [c15_nchar] nchar(512), [c16_nvarchar] nvarchar(512), [c17_nvarchar_max] nvarchar(max), [c18_text] text, [c19_ntext] ntext, [c20_binary] binary(512), [c21_varbinary] varbinary(512), [c22_varbinary_max] varbinary(max), [c23_image] image, [c24_uniqueidentifier] uniqueidentifier, [c25_datetime] datetime, [c26_smalldatetime] smalldatetime, [c27_timestamp] timestamp, [c28_xml] xml, [c29_time] time, [c30_date] date, [c31_datetime2] datetime2, [c32_datetimeoffset] datetimeoffset)"); + dropTable($conn, $tableName); + $conn->exec("CREATE TABLE $tableName ([c1_int] int, [c2_tinyint] tinyint, [c3_smallint] smallint, [c4_bigint] bigint, [c5_bit] bit, [c6_float] float, [c7_real] real, [c8_decimal] decimal(28,4), [c9_numeric] numeric(32,4), [c10_money] money, [c11_smallmoney] smallmoney, [c12_char] char(512), [c13_varchar] varchar(512), [c14_varchar_max] varchar(max), [c15_nchar] nchar(512), [c16_nvarchar] nvarchar(512), [c17_nvarchar_max] nvarchar(max), [c18_text] text, [c19_ntext] ntext, [c20_binary] binary(512), [c21_varbinary] varbinary(512), [c22_varbinary_max] varbinary(max), [c23_image] image, [c24_uniqueidentifier] uniqueidentifier, [c25_datetime] datetime, [c26_smalldatetime] smalldatetime, [c27_timestamp] timestamp, [c28_xml] xml, [c29_time] time, [c30_date] date, [c31_datetime2] datetime2, [c32_datetimeoffset] datetimeoffset)"); $numRows = 0; $query = GetQuery($tableName, ++$numRows); $stmt = $conn->query($query); + unset($stmt); $query = GetQuery($tableName, ++$numRows); $stmt = $conn->query($query); - $stmt = null; + unset($stmt); $sql = "SELECT * FROM $tableName ORDER BY c27_timestamp"; $obj1 = new PdoTestClass(); @@ -51,10 +56,11 @@ function FetchInto_Query_Args() $stmt2->setFetchMode(PDO::FETCH_INTO, $obj2); VerifyResults($stmt1, $stmt2, $tableName); + dropTable($conn, $tableName); - $stmt1 = null; - $stmt2 = null; - $conn = null; + unset($stmt1); + unset($stmt2); + unset($conn); } function VerifyResults($stmt1, $stmt2, $tableName) diff --git a/test/functional/pdo_sqlsrv/pdo_getAttribute_clientInfo.phpt b/test/functional/pdo_sqlsrv/pdo_getAttribute_clientInfo.phpt index a98dafda1..4a7b799d4 100644 --- a/test/functional/pdo_sqlsrv/pdo_getAttribute_clientInfo.phpt +++ b/test/functional/pdo_sqlsrv/pdo_getAttribute_clientInfo.phpt @@ -23,5 +23,5 @@ Array \[(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]+)? + \[ExtensionVer\] => [0-9]\.[0-9]\.[0-9](-(RC[1-9]?|preview[1-9]))?(\.[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 e6ee2ccb2..032740abf 100644 --- a/test/functional/pdo_sqlsrv/pdo_get_set_attr.phpt +++ b/test/functional/pdo_sqlsrv/pdo_get_set_attr.phpt @@ -131,7 +131,7 @@ array\(4\) { \["DriverVer"\]=> string\(10\) "[0-9]{2}.[0-9]{2}.[0-9]{4}" \["ExtensionVer"\]=> - string\([0-9]*\) \"[0-9].[0-9]\.[0-9](-(RC[0-9]?|preview))?(\.[0-9]+)?(\+[0-9]+)?\" + string\([0-9]*\) \"[0-9].[0-9]\.[0-9](-(RC[1-9]?|preview[1-9]))?(\.[0-9]+)?(\+[0-9]+)?\" } Test_6: diff --git a/test/functional/pdo_sqlsrv/pdo_insert_fetch_utf8text.phpt b/test/functional/pdo_sqlsrv/pdo_insert_fetch_utf8text.phpt index acbeaf233..0c06cd9d6 100644 --- a/test/functional/pdo_sqlsrv/pdo_insert_fetch_utf8text.phpt +++ b/test/functional/pdo_sqlsrv/pdo_insert_fetch_utf8text.phpt @@ -27,10 +27,19 @@ function verifyColumnData($columns, $results, $utf8) var_dump($results[$i]); } else { $arr = explode('?', $results[$i]); + // in Alpine Linux, data returned is diffferent with always encrypted: + // something like '**** *ä**** *****-**×*' + // instead of '?', it replaces inexact conversions with asterisks + // reference: read the ICONV section in + // https://wiki.musl-libc.org/functional-differences-from-glibc.html if (count($arr) == 1) { // this means there is no question mark in $t - echo $columns[$i]->colName . " value is unexpected"; - var_dump($results[$i]); + // then try to find a substring of some asterisks + $asterisks = '****'; + if(strpos($results[$i], '****') === false) { + echo $columns[$i]->colName . " value is unexpected"; + var_dump($results[$i]); + } } } } @@ -144,7 +153,7 @@ function runInOutProcWithErrors($conn, $utf8_2) function runIntDoubleProcWithErrors($conn) { - $sql = "{call pdoIntDoubleProc(?)}"; + $sql = "{call pdoUTF8InOutProc(?)}"; $val = pack('H*', 'ffffffff'); try { diff --git a/test/functional/pdo_sqlsrv/pdo_mars_disabled_error_checks.phpt b/test/functional/pdo_sqlsrv/pdo_mars_disabled_error_checks.phpt new file mode 100644 index 000000000..e7b14c421 --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_mars_disabled_error_checks.phpt @@ -0,0 +1,43 @@ +--TEST-- +Error checking for multiple active row sets (MARS) disabled +--DESCRIPTION-- +This is similar to sqlsrv srv_053_mars_disabled_error_checks.phpt to check the errors +when multiple active row sets (MARS) is disabled. +--SKIPIF-- + +--FILE-- +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $sql1 = "SELECT 'ONE'"; + $sql2 = "SELECT 'TWO'"; + + $stmt1 = $conn->query($sql1); + $stmt2 = $conn->query($sql2); + $res = [$stmt1->fetch(), $stmt2->fetch()]; + var_dump($res); + + unset($stmt1); + unset($stmt2); + unset($conn); +} catch (PDOException $e) { + var_dump($e->errorInfo); +} + +echo "\nDone\n"; +?> +--EXPECT-- +array(3) { + [0]=> + string(5) "IMSSP" + [1]=> + int(-61) + [2]=> + string(313) "The connection cannot process this operation because there is a statement with pending results. To make the connection available for other queries, either fetch all results or cancel or free the statement. For more information, see the product documentation about the MultipleActiveResultSets connection option." +} + +Done diff --git a/test/functional/pdo_sqlsrv/pdo_prepare.phpt b/test/functional/pdo_sqlsrv/pdo_prepare.phpt index 856ac9987..0d4896647 100644 --- a/test/functional/pdo_sqlsrv/pdo_prepare.phpt +++ b/test/functional/pdo_sqlsrv/pdo_prepare.phpt @@ -85,7 +85,7 @@ try { exit(); } ?> ---EXPECT-- +--EXPECTF-- Test_1 : Test with no parameters : array(8) { ["IntCol"]=> @@ -101,7 +101,7 @@ array(8) { ["NVarCharCol"]=> string(10) "STRINGCOL1" ["FloatCol"]=> - string(7) "111.111" + string(%d) "111.111%S" ["XmlCol"]=> string(431) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." } diff --git a/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_decimal.phpt b/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_decimal.phpt index d433b911c..5c2787fe2 100644 --- a/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_decimal.phpt +++ b/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_decimal.phpt @@ -6,6 +6,22 @@ prepare with emulate prepare and binding integer "decimal", "c2_money" => "decimal(19,4)", "c3_float" => "float")); } - insertRow($conn, $tableName, array("c1_decimal" => 411.1, "c2_money" => 131.11, "c3_float" => 611.111)); - insertRow($conn, $tableName, array("c1_decimal" => 422.2222, "c2_money" => 132.222, "c3_float" => 622.22)); - insertRow($conn, $tableName, array("c1_decimal" => 433.333, "c2_money" => 133.3333, "c3_float" => 633.33333)); + $inputValues = array( array('c1_decimal' => '411.1', 'c2_money' => '131.11', 'c3_float' => 611.111), + array('c1_decimal' => '422.2222', 'c2_money' => '132.222', 'c3_float' => 622.22), + array('c1_decimal' => '433.333', 'c2_money' => '133.3333', 'c3_float' => 633.33333)); + + for ($i = 0; $i < count($inputValues); $i++) { + insertRow($conn, $tableName, $inputValues[$i]); + } $query = "SELECT * FROM [$tableName] WHERE c1_decimal = :c1"; @@ -27,11 +47,11 @@ try { print_r("Prepare without emulate prepare:\n"); $options = array(PDO::ATTR_EMULATE_PREPARES => false); $stmt = $conn->prepare($query, $options); - $c1 = 422.2222; + $c1 = '422.2222'; $stmt->bindParam(':c1', $c1); $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); - print_r($row); + printRow($row, $inputValues[1]); //with emulate prepare and no bind param options print_r("Prepare with emulate prepare and no bind param options:\n"); @@ -43,7 +63,7 @@ try { $stmt->bindParam(':c1', $c1); $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); - print_r($row); + printRow($row, $inputValues[1]); //with emulate prepare and encoding SQLSRV_ENCODING_SYSTEM print_r("Prepare with emulate prepare and SQLSRV_ENCODING_SYSTEM:\n"); @@ -51,7 +71,7 @@ try { $stmt->bindParam(':c1', $c1, PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_SYSTEM); $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); - print_r($row); + printRow($row, $inputValues[1]); //prepare with emulate prepare and encoding SQLSRV_ENCODING_UTF8 print_r("Prepare with emulate prepare and SQLSRV_ENCODING_UTF8:\n"); @@ -59,7 +79,7 @@ try { $stmt->bindParam(':c1', $c1, PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_UTF8); $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); - print_r($row); + printRow($row, $inputValues[1]); //prepare with emulate prepare and encoding SQLSRV_ENCODING_BINARY print_r("Prepare with emulate prepare and SQLSRV_ENCODING_BINARY:\n"); @@ -67,7 +87,7 @@ try { $stmt->bindParam(':c1', $c1, PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_BINARY); $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); - print_r($row); + printRow($row, $inputValues[1]); if ($stmt->rowCount() == 0) { print_r("No results for this query\n"); } @@ -86,28 +106,24 @@ Array ( [c1_decimal] => 422 [c2_money] => 132.2220 - [c3_float] => 622.22%S ) Prepare with emulate prepare and no bind param options: Array ( [c1_decimal] => 422 [c2_money] => 132.2220 - [c3_float] => 622.22%S ) Prepare with emulate prepare and SQLSRV_ENCODING_SYSTEM: Array ( [c1_decimal] => 422 [c2_money] => 132.2220 - [c3_float] => 622.22%S ) Prepare with emulate prepare and SQLSRV_ENCODING_UTF8: Array ( [c1_decimal] => 422 [c2_money] => 132.2220 - [c3_float] => 622.22%S ) Prepare with emulate prepare and SQLSRV_ENCODING_BINARY: No results for this query diff --git a/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_float.phpt b/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_float.phpt index dee4ff599..2633e5ebe 100644 --- a/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_float.phpt +++ b/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_float.phpt @@ -1,11 +1,35 @@ --TEST-- prepare with emulate prepare and binding integer +--DESCRIPTION-- +This test is similar to pdo_prepare_emulatePrepare_decimal.phpt and +pdo_prepare_emulatePrepare_money.phpt but binding parameters with +floating point numbers. However, checking equality of floating point +numbers may not guarantee same results across platforms. Incorrect +results often occurred with implicit rounding when converting string +to floats. +See https://news-web.php.net/php.internals/11502 for in-depth explanation. --SKIPIF-- --FILE-- "decimal", "c2_money" => "decimal(19,4)", "c3_float" => "float")); } - insertRow($conn, $tableName, array("c1_decimal" => 411.1, "c2_money" => 131.11, "c3_float" => 611.111)); - insertRow($conn, $tableName, array("c1_decimal" => 422.2222, "c2_money" => 132.22, "c3_float" => 622.22)); - insertRow($conn, $tableName, array("c1_decimal" => 433.333, "c2_money" => 133.3333, "c3_float" => 633.33333)); + $inputValues = array( array('c1_decimal' => '411.1', 'c2_money' => '131.11', 'c3_float' => 611.111), + array('c1_decimal' => '422.2222', 'c2_money' => '132.222', 'c3_float' => 622.22), + array('c1_decimal' => '433.333', 'c2_money' => '133.3333', 'c3_float' => 633.33333)); - $query = "SELECT * FROM [$tableName] WHERE c3_float = :c3"; + for ($i = 0; $i < count($inputValues); $i++) { + insertRow($conn, $tableName, $inputValues[$i]); + } + + // With data encrypted, there will be no conversion + if (isColEncrypted()) { + $query = "SELECT * FROM [$tableName] WHERE c3_float = :c3"; + } else { + $query = "SELECT * FROM [$tableName] WHERE c3_float < :c3"; + } // prepare without emulate prepare print_r("Prepare without emulate prepare:\n"); $options = array(PDO::ATTR_EMULATE_PREPARES => false); $stmt = $conn->prepare($query, $options); - $c3 = 611.111; + $c3 = (isColEncrypted())? 611.111 : 620.00; $stmt->bindParam(':c3', $c3); $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); - print_r($row); + printRow($row, $inputValues[0]); //with emulate prepare and no bind param options print_r("Prepare with emulate prepare and no bind param options:\n"); @@ -43,7 +76,7 @@ try { $stmt->bindParam(':c3', $c3); $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); - print_r($row); + printRow($row, $inputValues[0]); //with emulate prepare and encoding SQLSRV_ENCODING_SYSTEM print_r("Prepare with emulate prepare and SQLSRV_ENCODING_SYSTEM:\n"); @@ -51,7 +84,7 @@ try { $stmt->bindParam(':c3', $c3, PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_SYSTEM); $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); - print_r($row); + printRow($row, $inputValues[0]); //prepare with emulate prepare and encoding SQLSRV_ENCODING_UTF8 print_r("Prepare with emulate prepare and SQLSRV_ENCODING_UTF8:\n"); @@ -59,7 +92,7 @@ try { $stmt->bindParam(':c3', $c3, PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_UTF8); $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); - print_r($row); + printRow($row, $inputValues[0]); //prepare with emulate prepare and encoding SQLSRV_ENCODING_BINARY print_r("Prepare with emulate prepare and SQLSRV_ENCODING_BINARY:\n"); @@ -67,7 +100,7 @@ try { $stmt->bindParam(':c3', $c3, PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_BINARY); $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); - print_r($row); + printRow($row, $inputValues[0]); if ($stmt->rowCount() == 0) { print_r("No results for this query\n"); } @@ -85,28 +118,24 @@ Array ( [c1_decimal] => 411 [c2_money] => 131.1100 - [c3_float] => 611.1109999999999%d ) Prepare with emulate prepare and no bind param options: Array ( [c1_decimal] => 411 [c2_money] => 131.1100 - [c3_float] => 611.1109999999999%d ) Prepare with emulate prepare and SQLSRV_ENCODING_SYSTEM: Array ( [c1_decimal] => 411 [c2_money] => 131.1100 - [c3_float] => 611.1109999999999%d ) Prepare with emulate prepare and SQLSRV_ENCODING_UTF8: Array ( [c1_decimal] => 411 [c2_money] => 131.1100 - [c3_float] => 611.1109999999999%d ) Prepare with emulate prepare and SQLSRV_ENCODING_BINARY: No results for this query diff --git a/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_money.phpt b/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_money.phpt index ae581204a..4943248d7 100644 --- a/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_money.phpt +++ b/test/functional/pdo_sqlsrv/pdo_prepare_emulatePrepare_money.phpt @@ -6,6 +6,22 @@ prepare with emulate prepare and binding integer "decimal", "c2_money" => "decimal(19,4)", "c3_float" => "float")); } - insertRow($conn, $tableName, array("c1_decimal" => 411.1, "c2_money" => 131.11, "c3_float" => 611.111)); - insertRow($conn, $tableName, array("c1_decimal" => 422.2222, "c2_money" => 132.22, "c3_float" => 622.22)); - insertRow($conn, $tableName, array("c1_decimal" => 433.333, "c2_money" => 133.3333, "c3_float" => 633.33333)); + $inputValues = array( array('c1_decimal' => '411.1', 'c2_money' => '131.11', 'c3_float' => 611.111), + array('c1_decimal' => '422.2222', 'c2_money' => '132.222', 'c3_float' => 622.22), + array('c1_decimal' => '433.333', 'c2_money' => '133.3333', 'c3_float' => 633.33333)); + + for ($i = 0; $i < count($inputValues); $i++) { + insertRow($conn, $tableName, $inputValues[$i]); + } $query = "SELECT * FROM [$tableName] WHERE c2_money = :c2"; @@ -27,11 +47,11 @@ try { print_r("Prepare without emulate prepare:\n"); $options = array(PDO::ATTR_EMULATE_PREPARES => false); $stmt = $conn->prepare($query, $options); - $c2 = 133.3333; + $c2 = '133.3333'; $stmt->bindParam(':c2', $c2); $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); - print_r($row); + printRow($row, $inputValues[2]); //with emulate prepare and no bind param options print_r("Prepare with emulate prepare and no bind param options:\n"); @@ -43,7 +63,7 @@ try { $stmt->bindParam(':c2', $c2); $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); - print_r($row); + printRow($row, $inputValues[2]); //with emulate prepare and encoding SQLSRV_ENCODING_SYSTEM print_r("Prepare with emulate prepare and SQLSRV_ENCODING_SYSTEM:\n"); @@ -51,7 +71,7 @@ try { $stmt->bindParam(':c2', $c2, PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_SYSTEM); $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); - print_r($row); + printRow($row, $inputValues[2]); //prepare with emulate prepare and encoding SQLSRV_ENCODING_UTF8 print_r("Prepare with emulate prepare and SQLSRV_ENCODING_UTF8:\n"); @@ -59,7 +79,7 @@ try { $stmt->bindParam(':c2', $c2, PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_UTF8); $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); - print_r($row); + printRow($row, $inputValues[2]); //prepare with emulate prepare and encoding SQLSRV_ENCODING_BINARY print_r("Prepare with emulate prepare and SQLSRV_ENCODING_BINARY:\n"); @@ -67,7 +87,7 @@ try { $stmt->bindParam(':c2', $c2, PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_BINARY); $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); - print_r($row); + printRow($row, $inputValues[2]); if ($stmt->rowCount() == 0) { print_r("No results for this query\n"); } @@ -86,28 +106,24 @@ Array ( [c1_decimal] => 433 [c2_money] => 133.3333 - [c3_float] => 633.3333300000000%d ) Prepare with emulate prepare and no bind param options: Array ( [c1_decimal] => 433 [c2_money] => 133.3333 - [c3_float] => 633.3333300000000%d ) Prepare with emulate prepare and SQLSRV_ENCODING_SYSTEM: Array ( [c1_decimal] => 433 [c2_money] => 133.3333 - [c3_float] => 633.3333300000000%d ) Prepare with emulate prepare and SQLSRV_ENCODING_UTF8: Array ( [c1_decimal] => 433 [c2_money] => 133.3333 - [c3_float] => 633.3333300000000%d ) Prepare with emulate prepare and SQLSRV_ENCODING_BINARY: No results for this query diff --git a/test/functional/pdo_sqlsrv/pdo_query.phpt b/test/functional/pdo_sqlsrv/pdo_query.phpt index 99babdfcf..4491c25f5 100644 --- a/test/functional/pdo_sqlsrv/pdo_query.phpt +++ b/test/functional/pdo_sqlsrv/pdo_query.phpt @@ -77,7 +77,7 @@ try { ?> ---EXPECT-- +--EXPECTF-- TEST_1 : query with default fetch style : array(16) { ["IntCol"]=> @@ -105,9 +105,9 @@ array(16) { [5]=> string(10) "STRINGCOL1" ["FloatCol"]=> - string(7) "111.111" + string(%d) "111.111%S" [6]=> - string(7) "111.111" + string(%d) "111.111%S" ["XmlCol"]=> string(431) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." [7]=> @@ -122,7 +122,7 @@ string(10) "STRINGCOL1" string(23) "2000-11-11 11:11:11.110" string(10) "STRINGCOL1" string(10) "STRINGCOL1" -string(7) "111.111" +string(%d) "111.111%S" string(431) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." TEST_4 : query with FETCH_INTO : string(1) "1" @@ -131,7 +131,7 @@ string(10) "STRINGCOL1" string(23) "2000-11-11 11:11:11.110" string(10) "STRINGCOL1" string(10) "STRINGCOL1" -string(7) "111.111" +string(%d) "111.111%S" string(431) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." TEST_5 : query an empty table : bool(false) diff --git a/test/functional/pdo_sqlsrv/pdo_test_gb18030.php b/test/functional/pdo_sqlsrv/pdo_test_gb18030.php new file mode 100644 index 000000000..4eefc1f2a --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_test_gb18030.php @@ -0,0 +1,63 @@ +prepare($tsql); + + $stmt->execute(array($text)); +} + +require_once('MsSetup.inc'); + +$tempDB = ($_SERVER['argv'][1]); + +setlocale(LC_ALL, 'zh_CN.gb18030'); + +try { + $conn = new PDO("sqlsrv:server = $server;database=$tempDB;driver=$driver", $uid, $pwd); + $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $conn->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_SYSTEM); + + $tsql = "CREATE TABLE test1([id] int identity, [name] [varchar](50) NULL)"; + $stmt = $conn->query($tsql); + + // Next, insert the strings + $inputs = array('', '', 'δҵϢ', 'ȡ'); + $hexValues = array('d6d0cec4', 'c4e3bac3', 'ceb4d5d2b5bdd0c5cfa2', 'bbf1c8a1b8fcb6e0'); + for ($i = 0; $i < 4; $i++) { + insertText($conn, $inputs[$i], $hexValues[$i]); + } + + // Next, fetch the strings + $tsql = "SELECT * FROM test1"; + $stmt = $conn->query($tsql); + + $i = 0; + while ($result = $stmt->fetch(PDO::FETCH_NUM)) { + $name = $result[1]; + if ($name !== $inputs[$i]) { + echo "Expected $inputs[$i] but got $name" . PHP_EOL; + } + $i++; + } +} catch (PDOException $e) { + echo $e->getMessage() . PHP_EOL; +} finally { + $tsql = "DROP TABLE test1"; + $conn->exec($tsql); + + unset($stmt); + unset($conn); +} + +echo "Done"; + +?> + diff --git a/test/functional/pdo_sqlsrv/pdo_test_passwords_with_braces.phpt b/test/functional/pdo_sqlsrv/pdo_test_passwords_with_braces.phpt new file mode 100644 index 000000000..88e548523 --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_test_passwords_with_braces.phpt @@ -0,0 +1,80 @@ +--TEST-- +Test passwords with non alphanumeric characters and braces +--DESCRIPTION-- +The first two cases should fail with a message about login failures. Only the last case fails because the right curly brace was not escaped with another right brace. +--ENV-- +PHPT_EXEC=true +--SKIPIF-- + +--FILE-- +getMessage())) { + echo "Expected $error but got:\n"; + var_dump($e->getMessage()); + } +} + +try { + $randomPwd = generateRandomPassword(); + trace($randomPwd . PHP_EOL); + $conn = new PDO("sqlsrv:Server=$server;", $uid, $randomPwd); + + echo "Incorrect password '$randomPwd' with right braces should have failed!" . PHP_EOL; +} catch (PDOException $e) { + $error = '*Login failed for user*'; + if (!fnmatch($error, $e->getMessage())) { + echo "Expected $error but got:\n"; + var_dump($e->getMessage()); + } +} + +try { + $randomPwd = generateRandomPassword(true, false); + trace($randomPwd . PHP_EOL); + $conn = new PDO("sqlsrv:Server=$server;", $uid, $randomPwd); + + echo ("Shouldn't have connected without escaping braces!" . PHP_EOL); +} catch (PDOException $e) { + echo $e->getMessage() . PHP_EOL; +} + +echo "Done" . PHP_EOL; +?> +--EXPECT-- +SQLSTATE[IMSSP]: An unescaped right brace (}) was found in either the user name or password. All right braces must be escaped with another right brace (}}). +Done \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdostatement_GetDataType.phpt b/test/functional/pdo_sqlsrv/pdostatement_GetDataType.phpt index bdd87ffe0..683fbbc43 100644 --- a/test/functional/pdo_sqlsrv/pdostatement_GetDataType.phpt +++ b/test/functional/pdo_sqlsrv/pdostatement_GetDataType.phpt @@ -33,7 +33,7 @@ try { } ?> ---EXPECT-- +--EXPECTF-- Test_1 : BigIntCol : array(1) { ["BigIntCol"]=> @@ -82,7 +82,7 @@ array(1) { Test_10 : FloatCol : array(1) { ["FloatCol"]=> - string(7) "111.111" + string(%d) "111.111%S" } Test_11 : RealCol : array(1) { diff --git a/test/functional/pdo_sqlsrv/pdostatement_execute.phpt b/test/functional/pdo_sqlsrv/pdostatement_execute.phpt index 764594299..68164d369 100644 --- a/test/functional/pdo_sqlsrv/pdostatement_execute.phpt +++ b/test/functional/pdo_sqlsrv/pdostatement_execute.phpt @@ -48,7 +48,7 @@ try { var_dump($e); } ?> ---EXPECT-- +--EXPECTF-- array(8) { ["IntCol"]=> string(1) "1" @@ -63,7 +63,7 @@ array(8) { ["NVarCharCol"]=> string(10) "STRINGCOL1" ["FloatCol"]=> - string(7) "111.111" + string(%d) "111.111%S" ["XmlCol"]=> string(431) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." } diff --git a/test/functional/pdo_sqlsrv/pdostatement_fetchAll.phpt b/test/functional/pdo_sqlsrv/pdostatement_fetchAll.phpt index 6a30232c8..79b31cd2f 100644 --- a/test/functional/pdo_sqlsrv/pdostatement_fetchAll.phpt +++ b/test/functional/pdo_sqlsrv/pdostatement_fetchAll.phpt @@ -77,11 +77,28 @@ function fetchAllInvalid($conn, $tbname) $stmt = $conn->query("Select * from $tbname"); try { $result = $stmt->fetchAll(PDO::FETCH_UNKNOWN); - } catch (PDOException $err) { - print_r($err); + } catch (PDOException $ex) { + print_r($ex); + } catch (Error $err) { + if (PHP_MAJOR_VERSION == 8) { + $message = "Undefined constant PDO::FETCH_UNKNOWN"; + } else { + $message = "Undefined class constant 'FETCH_UNKNOWN'"; + } + if ($err->getMessage() !== $message) { + echo $err->getMessage() . PHP_EOL; + } } } +// When testing with PHP 8.0 it throws a TypeError instead of a warning. Thus implement a custom +// warning handler such that with PHP 7.x the warning would be handled to throw a TypeError. +// Sometimes the error messages from PHP 8.0 may be different and have to be handled differently. +function warningHandler($errno, $errstr) +{ + throw new Error($errstr); +} + try { $db = connect(); $tbname1 = "PDO_MainTypes"; @@ -105,7 +122,10 @@ try { echo "Test_8 : FETCH_CLASS :\n"; fetchAllClass($db, $tbname1); echo "Test_9 : FETCH_INVALID :\n"; + + set_error_handler("warningHandler", E_WARNING); fetchAllInvalid($db, $tbname1); + restore_error_handler(); dropTable($db, $tbname1); dropTable($db, $tbname2); @@ -145,9 +165,9 @@ array(2) { [5]=> string(10) "STRINGCOL1" ["FloatCol"]=> - string(7) "111.111" + string(%d) "111.111%S" [6]=> - string(7) "111.111" + string(%d) "111.111%S" ["XmlCol"]=> string(431) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." [7]=> @@ -237,9 +257,9 @@ array(1) { [8]=> string(3) "111" ["FloatCol"]=> - string(7) "111.111" + string(%d) "111.111%S" [9]=> - string(7) "111.111" + string(%d) "111.111%S" ["ImageCol"]=> string(5) "abcde" [10]=> @@ -273,9 +293,9 @@ array(1) { [17]=> string(420) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." ["RealCol"]=> - string(7) "111.111" + string(%d) "111.111%S" [18]=> - string(7) "111.111" + string(%d) "111.111%S" ["SmallDTCol"]=> string(19) "2000-11-11 11:11:00" [19]=> @@ -353,9 +373,9 @@ array(16) { [5]=> string(10) "STRINGCOL1" ["FloatCol"]=> - string(7) "111.111" + string(%d) "111.111%S" [6]=> - string(7) "111.111" + string(%d) "111.111%S" ["XmlCol"]=> string(431) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." [7]=> @@ -376,7 +396,7 @@ array(8) { ["NVarCharCol"]=> string(10) "STRINGCOL1" ["FloatCol"]=> - string(7) "111.111" + string(%d) "111.111%S" ["XmlCol"]=> string(431) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." } @@ -427,10 +447,4 @@ string(10) "STRINGCOL2" string(10) "STRINGCOL2" string(%d) "222.222%S" string(431) " 2 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." -Test_9 : FETCH_INVALID : - -Fatal error: Uncaught Error: Undefined class constant 'FETCH_UNKNOWN' in %s:%x -Stack trace: -#0 %s: fetchAllInvalid(%S) -#1 {main} - thrown in %s on line %x +Test_9 : FETCH_INVALID : \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdostatement_fetchObject.phpt b/test/functional/pdo_sqlsrv/pdostatement_fetchObject.phpt index 01475a6a0..edbe4e5ee 100644 --- a/test/functional/pdo_sqlsrv/pdostatement_fetchObject.phpt +++ b/test/functional/pdo_sqlsrv/pdostatement_fetchObject.phpt @@ -54,7 +54,7 @@ try { var_dump($e); } ?> ---EXPECT-- +--EXPECTF-- 1 abcde 0 @@ -64,7 +64,7 @@ STRINGCOL1 2000-11-11 11:11:11.1110000 2000-11-11 11:11:11.1110000 +00:00 111 -111.111 +111.111%S abcde 1 111.1110 diff --git a/test/functional/pdo_sqlsrv/pdostatement_fetch_orientation.phpt b/test/functional/pdo_sqlsrv/pdostatement_fetch_orientation.phpt index a14d6ddec..6115965ca 100644 --- a/test/functional/pdo_sqlsrv/pdostatement_fetch_orientation.phpt +++ b/test/functional/pdo_sqlsrv/pdostatement_fetch_orientation.phpt @@ -8,20 +8,17 @@ PHPT_EXEC=true PDO::CURSOR_SCROLL); + if ($buffered) { + $options = array(PDO::ATTR_CURSOR=>PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE=>PDO::SQLSRV_CURSOR_BUFFERED); + } - // Prepare test table - $tableName = "pdo_test_table"; - createTable($conn1, $tableName, array(new ColumnMeta("int", "id", "NOT NULL PRIMARY KEY", "none"), "val" => "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")); + $stmt1 = $conn->prepare($tsql, $options); + $stmt1->execute(); - // Query table and retrieve data - $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 ); if( $row[ 'val' ] != "C" ) { throw new Exception( "Not C" ); @@ -38,7 +35,7 @@ try { if ($row !== false) { throw new Exception( "Not false" ); } - + $stmt1->execute(); $row = $stmt1->fetch( PDO::FETCH_ASSOC, PDO::FETCH_ORI_LAST ); if( $row[ 'val' ] != "C" ) { @@ -57,7 +54,7 @@ try { throw new Exception( "Not false" ); } - $stmt1->execute(); + $stmt1->execute(); $row = $stmt1->fetch( PDO::FETCH_ASSOC, PDO::FETCH_ORI_LAST ); if( $row[ 'val' ] != "C" ) { throw new Exception( "Not C" ); @@ -66,8 +63,8 @@ try { if ($row !== false) { throw new Exception( "Not false" ); } - - $stmt1->execute(); + + $stmt1->execute(); $row = $stmt1->fetch( PDO::FETCH_ASSOC, PDO::FETCH_ORI_LAST ); if( $row[ 'val' ] != "C" ) { throw new Exception( "Not C" ); @@ -76,7 +73,7 @@ try { if ($row !== false) { throw new Exception( "Not false" ); } - + $stmt1->execute(); $row = $stmt1->fetch( PDO::FETCH_ASSOC, PDO::FETCH_ORI_ABS, 2 ); if( $row[ 'val' ] != "C" ) { @@ -138,7 +135,7 @@ try { if ($row !== false) { throw new Exception( "Not false" ); } - + $stmt1->execute(); $row = $stmt1->fetch( PDO::FETCH_ASSOC, PDO::FETCH_ORI_FIRST ); if( $row[ 'val' ] != "A" ) { @@ -148,10 +145,26 @@ try { if ($row !== false) { throw new Exception( "Not false" ); } + + unset($stmt1); +} + +try { + $conn1 = connect(); + + // Prepare test table + $tableName = "pdo_test_table"; + createTable($conn1, $tableName, array(new ColumnMeta("int", "id", "NOT NULL PRIMARY KEY", "none"), "val" => "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 + runTests($conn1, $tableName, false); + runTests($conn1, $tableName, true); // Cleanup dropTable($conn1, $tableName); - unset($stmt1); unset($conn1); echo "Test 'PDO Statement - Fetch Scrollable' completed successfully.\n"; diff --git a/test/functional/pdo_sqlsrv/pdostatement_fetch_style.phpt b/test/functional/pdo_sqlsrv/pdostatement_fetch_style.phpt index 5170bd972..b03ee4156 100644 --- a/test/functional/pdo_sqlsrv/pdostatement_fetch_style.phpt +++ b/test/functional/pdo_sqlsrv/pdostatement_fetch_style.phpt @@ -7,6 +7,14 @@ Test the PDOStatement::fetch() method with different fetch styles. require_once("MsCommon_mid-refactor.inc"); require_once("MsData_PDO_AllTypes.inc"); +// When testing with PHP 8.0 it throws a TypeError instead of a warning. Thus implement a custom +// warning handler such that with PHP 7.x the warning would be handled to throw a TypeError. +// Sometimes the error messages from PHP 8.0 may be different and have to be handled differently. +function warningHandler($errno, $errstr) +{ + throw new Error($errstr); +} + function fetchWithStyle($conn, $tbname, $style) { $stmt = $conn->query("SELECT * FROM $tbname"); @@ -68,11 +76,23 @@ function fetchWithStyle($conn, $tbname, $style) } case "PDO::FETCH_INVALID": { + set_error_handler("warningHandler", E_WARNING); try { $result = $stmt->fetch(PDO::FETCH_UNKNOWN); } catch (PDOException $err) { print_r($err); + } catch (Error $err) { + if (PHP_MAJOR_VERSION == 8) { + $message = "Undefined constant PDO::FETCH_UNKNOWN"; + } else { + $message = "Undefined class constant 'FETCH_UNKNOWN'"; + } + if ($err->getMessage() !== $message) { + echo $err->getMessage() . PHP_EOL; + } } + restore_error_handler(); + break; } @@ -140,9 +160,9 @@ array(16) { [5]=> string(10) "STRINGCOL1" ["FloatCol"]=> - string(7) "111.111" + string(%d) "111.111%S" [6]=> - string(7) "111.111" + string(%d) "111.111%S" ["XmlCol"]=> string(431) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." [7]=> @@ -163,7 +183,7 @@ array(8) { ["NVarCharCol"]=> string(10) "STRINGCOL1" ["FloatCol"]=> - string(7) "111.111" + string(%d) "111.111%S" ["XmlCol"]=> string(431) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." } @@ -184,7 +204,7 @@ object(PDORow)#%x (%x) { ["NVarCharCol"]=> string(10) "STRINGCOL1" ["FloatCol"]=> - string(7) "111.111" + string(%d) "111.111%S" ["XmlCol"]=> string(431) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." } @@ -203,7 +223,7 @@ object(stdClass)#%x (%x) { ["NVarCharCol"]=> string(10) "STRINGCOL1" ["FloatCol"]=> - string(7) "111.111" + string(%d) "111.111%S" ["XmlCol"]=> string(431) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." } @@ -222,7 +242,7 @@ array(8) { [5]=> string(10) "STRINGCOL1" [6]=> - string(7) "111.111" + string(%d) "111.111%S" [7]=> string(431) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." } @@ -233,7 +253,7 @@ string(10) "STRINGCOL1" string(23) "2000-11-11 11:11:11.110" string(10) "STRINGCOL1" string(10) "STRINGCOL1" -string(7) "111.111" +string(%d) "111.111%S" string(431) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." Test_7 : FETCH_CLASS : string(1) "1" @@ -242,7 +262,7 @@ string(10) "STRINGCOL1" string(23) "2000-11-11 11:11:11.110" string(10) "STRINGCOL1" string(10) "STRINGCOL1" -string(7) "111.111" +string(%d) "111.111%S" string(431) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." Test_8 : FETCH_INTO : string(1) "1" @@ -251,12 +271,7 @@ string(10) "STRINGCOL1" string(23) "2000-11-11 11:11:11.110" string(10) "STRINGCOL1" string(10) "STRINGCOL1" -string(7) "111.111" +string(%d) "111.111%S" string(431) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." Test_9 : FETCH_INVALID : -Fatal error: Uncaught Error: Undefined class constant 'FETCH_UNKNOWN' in %s:%x -Stack trace: -#0 %s: fetchWithStyle(%S) -#1 {main} - thrown in %s on line %x diff --git a/test/functional/pdo_sqlsrv/pdostatement_getColumnMeta.phpt b/test/functional/pdo_sqlsrv/pdostatement_getColumnMeta.phpt index 40805dc23..6493bf94e 100644 --- a/test/functional/pdo_sqlsrv/pdostatement_getColumnMeta.phpt +++ b/test/functional/pdo_sqlsrv/pdostatement_getColumnMeta.phpt @@ -49,22 +49,43 @@ function fetchBoth($conn, $tbname) unset($meta["sqlsrv:decl_type"]); var_dump($meta); - // Test invalid arguments, set error mode to silent to reduce the amount of error messages generated + // Test invalid arguments, set error mode to silent to reduce the number of error messages generated $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); - // Test negative column number, ignore the error messages - $meta = $stmt->getColumnMeta(-1); - var_dump($meta); + // Test negative column number + try { + $meta = $stmt->getColumnMeta(-1); + echo "Expect getColumnMeta to fail with -1\n"; + } catch (Error $e) { + if (PHP_MAJOR_VERSION == 8) { + $error = '*PDOStatement::getColumnMeta(): Argument #1 ($index) must be greater than or equal to 0*'; + } else { + $error = '*Invalid column reference: column number must be non-negative*'; + } + if (!fnmatch($error, $e->getMessage())) { + echo "Unexpected error:"; + var_dump($e->getMessage()); + } + } // Test non-existent column number $meta = $stmt->getColumnMeta(10); var_dump($meta); } +// When testing with PHP 8.0 the negative test case throws an Error instead of a warning. +// Implement a custom warning handler such that with PHP 7.x the warning would be handled +// to throw an Error. +function warningHandler($errno, $errstr) +{ + throw new Error($errstr); +} + try { $db = connect(); $tbname = "PDO_MainTypes"; createAndInsertTableMainTypes($db, $tbname); + set_error_handler("warningHandler", E_WARNING); fetchBoth($db, $tbname); } catch (PDOException $e) { var_dump($e); @@ -73,7 +94,7 @@ try { ?> ---EXPECTF-- +--EXPECT-- array(8) { ["flags"]=> @@ -217,7 +238,4 @@ array(7) { ["precision"]=> int(0) } - -Warning: PDOStatement::getColumnMeta(): SQLSTATE[42P10]: Invalid column reference: column number must be non-negative in %s on line %x -bool(false) bool(false) diff --git a/test/functional/pdo_sqlsrv/pdostatement_getColumnMeta_unicode_col_name.phpt b/test/functional/pdo_sqlsrv/pdostatement_getColumnMeta_unicode_col_name.phpt index e7075ee46..2aba3fa9d 100644 --- a/test/functional/pdo_sqlsrv/pdostatement_getColumnMeta_unicode_col_name.phpt +++ b/test/functional/pdo_sqlsrv/pdostatement_getColumnMeta_unicode_col_name.phpt @@ -57,15 +57,35 @@ function fetchBoth($conn, $tbname) // Test invalid arguments, set error mode to silent to reduce the amount of error messages generated $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); - // Test negative column number, ignore the error messages - $meta = $stmt->getColumnMeta(-1); - var_dump($meta); + // Test negative column number + try { + $meta = $stmt->getColumnMeta(-1); + echo "Expect getColumnMeta to fail with -1\n"; + } catch (Error $e) { + if (PHP_MAJOR_VERSION == 8) { + $error = '*PDOStatement::getColumnMeta(): Argument #1 ($index) must be greater than or equal to 0*'; + } else { + $error = '*Invalid column reference: column number must be non-negative*'; + } + if (!fnmatch($error, $e->getMessage())) { + echo "Unexpected error:"; + var_dump($e->getMessage()); + } + } // Test non-existent column number $meta = $stmt->getColumnMeta(10); var_dump($meta); } +// When testing with PHP 8.0 the negative test case throws an Error instead of a warning. +// Implement a custom warning handler such that with PHP 7.x the warning would be handled +// to throw an Error. +function warningHandler($errno, $errstr) +{ + throw new Error($errstr); +} + function createAndInsertTableUnicode($conn, $tbname) { try { @@ -106,13 +126,14 @@ try { $db = connect(); $tbname = "PDO_MainTypes"; createAndInsertTableUnicode($db, $tbname); + set_error_handler("warningHandler", E_WARNING); fetchBoth($db, $tbname); } catch (PDOException $e) { var_dump($e); exit; } ?> ---EXPECTF-- +--EXPECT-- array(8) { ["flags"]=> @@ -256,7 +277,4 @@ array(7) { ["precision"]=> int(0) } - -Warning: PDOStatement::getColumnMeta(): SQLSTATE[42P10]: Invalid column reference: column number must be non-negative in %s on line %x -bool(false) bool(false) \ No newline at end of file diff --git a/test/functional/pdo_sqlsrv/pdostatement_nextRowset.phpt b/test/functional/pdo_sqlsrv/pdostatement_nextRowset.phpt index fa63c225c..355dd4de2 100644 --- a/test/functional/pdo_sqlsrv/pdostatement_nextRowset.phpt +++ b/test/functional/pdo_sqlsrv/pdostatement_nextRowset.phpt @@ -72,9 +72,9 @@ array(1) { [8]=> string(3) "111" ["FloatCol"]=> - string(7) "111.111" + string(%d) "111.111%S" [9]=> - string(7) "111.111" + string(%d) "111.111%S" ["ImageCol"]=> string(5) "abcde" [10]=> @@ -108,9 +108,9 @@ array(1) { [17]=> string(420) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." ["RealCol"]=> - string(7) "111.111" + string(%d) "111.111%S" [18]=> - string(7) "111.111" + string(%d) "111.111%S" ["SmallDTCol"]=> string(19) "2000-11-11 11:11:00" [19]=> @@ -189,9 +189,9 @@ array(2) { [5]=> string(10) "STRINGCOL1" ["FloatCol"]=> - string(7) "111.111" + string(%d) "111.111%S" [6]=> - string(7) "111.111" + string(%d) "111.111%S" ["XmlCol"]=> string(431) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." [7]=> diff --git a/test/functional/pdo_sqlsrv/pdostatement_setFetchMode.phpt b/test/functional/pdo_sqlsrv/pdostatement_setFetchMode.phpt index b74732119..742dc9474 100644 --- a/test/functional/pdo_sqlsrv/pdostatement_setFetchMode.phpt +++ b/test/functional/pdo_sqlsrv/pdostatement_setFetchMode.phpt @@ -25,7 +25,7 @@ try { } ?> ---EXPECT-- +--EXPECTF-- Set Fetch Mode for PDO::FETCH_ASSOC array(8) { ["IntCol"]=> @@ -41,7 +41,7 @@ array(8) { ["NVarCharCol"]=> string(10) "STRINGCOL1" ["FloatCol"]=> - string(7) "111.111" + string(%d) "111.111%S" ["XmlCol"]=> string(431) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." } @@ -60,7 +60,7 @@ array(8) { [5]=> string(10) "STRINGCOL1" [6]=> - string(7) "111.111" + string(%d) "111.111%S" [7]=> string(431) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." } @@ -91,9 +91,9 @@ array(16) { [5]=> string(10) "STRINGCOL1" ["FloatCol"]=> - string(7) "111.111" + string(%d) "111.111%S" [6]=> - string(7) "111.111" + string(%d) "111.111%S" ["XmlCol"]=> string(431) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." [7]=> @@ -116,7 +116,7 @@ object(PDORow)#3 (9) { ["NVarCharCol"]=> string(10) "STRINGCOL1" ["FloatCol"]=> - string(7) "111.111" + string(%d) "111.111%S" ["XmlCol"]=> string(431) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." } @@ -135,7 +135,7 @@ object(stdClass)#5 (8) { ["NVarCharCol"]=> string(10) "STRINGCOL1" ["FloatCol"]=> - string(7) "111.111" + string(%d) "111.111%S" ["XmlCol"]=> string(431) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417." } diff --git a/test/functional/pdo_sqlsrv/skipif_not_hgs.inc b/test/functional/pdo_sqlsrv/skipif_not_hgs.inc index 80ad95f06..ccf177ab0 100644 --- a/test/functional/pdo_sqlsrv/skipif_not_hgs.inc +++ b/test/functional/pdo_sqlsrv/skipif_not_hgs.inc @@ -9,6 +9,10 @@ if (!extension_loaded("pdo_sqlsrv")) { require_once('MsSetup.inc'); +if ($attestation == 'TARGET_ATTESTATION') { + die("skip Not set up for testing with secure enclave."); +} + $conn = new PDO("sqlsrv:server = $server", $uid, $pwd); if (!$conn) { die("skip Could not connect during SKIPIF."); diff --git a/test/functional/pdo_sqlsrv/skipif_unix_ansitests.inc b/test/functional/pdo_sqlsrv/skipif_unix_ansitests.inc new file mode 100644 index 000000000..d0da3b4e9 --- /dev/null +++ b/test/functional/pdo_sqlsrv/skipif_unix_ansitests.inc @@ -0,0 +1,15 @@ + diff --git a/test/functional/pdo_sqlsrv/values.php b/test/functional/pdo_sqlsrv/values.php index 3373224ad..b08504bea 100644 --- a/test/functional/pdo_sqlsrv/values.php +++ b/test/functional/pdo_sqlsrv/values.php @@ -2,14 +2,11 @@ // This file holds different data of many different types for testing // Always Encrypted. Currently, the tests that use this data are: -// pdo__ae_azure_key_vault_keywords.phpt ($small_values) + +// pdo_ae_azure_key_vault_keywords.phpt ($small_values) // pdo_ae_azure_key_vault_username_password.phpt ($small_values) // pdo_ae_azure_key_vault_client_secret.phpt ($small_values) -// sqlsrv_ae_fetch_phptypes.phpt ($values) -// sqlsrv_ae_type_conversion_select.phpt ($values) -// sqlsrv_ae_azure_key_vault_keywords.phpt ($small_values) -// sqlsrv_ae_azure_key_vault_username_password.phpt ($small_values) -// sqlsrv_ae_azure_key_vault_client_secret.phpt ($small_values) + // The orders of the array elements below correspond to the column // data types defined in the tests above. @@ -35,781 +32,4 @@ const STRSIZE = 256; const LONG_STRSIZE = 384; -$values = array(); -$values[] = array(array(("BA3EA123EA8FFF46A01"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_BINARY(256)), - array(("7BDD1C6794E0BA9556F63B93A"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY(256)), - array(("73536B21A1C760E5C47ECF6E7F12117"), null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY('max')), - "Ð ¢î ãbýýüzbo>ª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.2HZCr,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î* ©ªÄÜ©|Ö+|ÖÃ*ãâ|£î~~ð.Ä*î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î* ©ªÄÜ©|Ö+|ÖÃ*ãâ|£î~~ð.Ä*î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î* ©ªÄÜ©|Ö+|Ö*ãâ|£î~~ð.Ä*î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î* ©ªÄÜ©|Ö+|ÖÃ*ãâ|£î~~ð.Ä*î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/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~ã|ö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ªý,ü ã,£<£*Uðö:~ß©ß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 diff --git a/test/functional/setup/AEV2Cert.pfx b/test/functional/setup/AEV2Cert.pfx index 4a9fc5bb8..4f99b279e 100644 Binary files a/test/functional/setup/AEV2Cert.pfx and b/test/functional/setup/AEV2Cert.pfx differ diff --git a/test/functional/setup/ae_keys.sql b/test/functional/setup/ae_keys.sql index d352a6f83..16cf2e0ad 100644 --- a/test/functional/setup/ae_keys.sql +++ b/test/functional/setup/ae_keys.sql @@ -34,19 +34,21 @@ CREATE COLUMN MASTER KEY [CMK-win-enclave] WITH ( KEY_STORE_PROVIDER_NAME = N'MSSQL_CERTIFICATE_STORE', - KEY_PATH = N'CurrentUser/My/D9C0572FA54B221D6591C473BAEA53FE61AAC854', - ENCLAVE_COMPUTATIONS (SIGNATURE = 0xA1150DE565E9C132D2AAB8FF8B228EAA8DA804F250B5B422874CB608A3B274DDE523E71B655A3EFC6C3018B632701E9205BAD80C178614E1FE821C6807B0E70BCF11168FC4B202638905C5F016EDBADACA23C696B79772C56825F36EB8C0366B130C91D85362E560C9D2FDD20DCAE99619256045CA2725DEC9E0C115CAEB9EA686CCB0DE0D53D2056C01752B17B634FC6DBB51EA043F607349489722DB8A086CBC876649284A8352822DD22B328E7BA3D671CCDF54CDAAF61DFD6AF2EAAC14E03897324234AB103C45AB48131C1CD19040782359FC920A0AF61BA9842ADFB76C3196CBC6EB9C0A679926ED63E092B7C8643232C97A64C7F918104C210787A56F) + KEY_PATH = N'CurrentUser/My/FADD52207E002EDDEE832B12E281EA280F2EFBCB', + ENCLAVE_COMPUTATIONS (SIGNATURE = 0x89DB5211D883466A978299CD9AE176E25C3465EDB6FA42571E17AC38D9ED63D436CD476D5436AD1514BAE7C9E185EB421E9C5BA3905721CD453899604140A3DE5E5080693E7CCD61360E5E168290498EE86EFABD5D2B56D9F5676173E6164D5F195EE3321DEE003568C25FE5B5470B3EE5C699F1280B1397C90E411A86E62F165F1ED74987C571A3BB1CCB909B69210A38DBE1D3826F0153F1DEFD7454C0F218853480C636D428FA42FE688FB93E34CEAABD70AC66DCF329C0FE4503738EFD24E920524D8040F493ADC6A4E21F017231B787942B68C825879025019D4F6EC9919EFC73504D764D16E4F808FECBFDF6F5456247DB8904F9B77BA0C32CB4403AE1) ) GO + CREATE COLUMN MASTER KEY [CMK-win-noenclave] WITH ( KEY_STORE_PROVIDER_NAME = N'MSSQL_CERTIFICATE_STORE', - KEY_PATH = N'CurrentUser/My/D9C0572FA54B221D6591C473BAEA53FE61AAC854' + KEY_PATH = N'CurrentUser/My/FADD52207E002EDDEE832B12E281EA280F2EFBCB' ) GO + /* Now we can create the Column Encryption Keys */ /* ENCRYPTED_VALUE is generated by SSMS and it is always the same if the same Certificate is imported */ CREATE COLUMN ENCRYPTION KEY [AEColumnKey] @@ -66,33 +68,37 @@ WITH VALUES ( COLUMN_MASTER_KEY = [CMK-win-enclave], ALGORITHM = 'RSA_OAEP', - ENCRYPTED_VALUE = 0x016E000001630075007200720065006E00740075007300650072002F006D0079002F0064003900630030003500370032006600610035003400620032003200310064003600350039003100630034003700330062006100650061003500330066006500360031006100610063003800350034007382EDDDE3FFCE076D5715B6BBBD22EA64E665899BEFAAD5B329F218EE30BE9F789EB98717B6FD9E50AE496AC9FEED962B23442D4FD3FBFEC9C9B65F40A3BCEC7CFAC198F4CAEE8A255F67988289EF050F9F75D0287F3DF9A9FDA0C674E48DF2CB13298AAAD039930DD909EEE71682CC8A90202D3F2A1F1037BB20B1954C8B6A11F05D104CA9DAF1561C6B2F9DBB08BCE17244157B751C02FC1730E387F372C31327F2834D19AF626D0B46B152615F05FA2F3566350312CDE6DE1160B3C1D0FD35FAF13891C04711DF184DA501AA51D16BF009EA71A2D28E201804C6F8F9100E90234923B2713EA7988861FBA4E292E5518FFC02CCBD2513EDA871F6E03ECDDD309619557277C10A07906E55BA3F59A6A18834B4CD5185DA4B4574A18B8B1AC53A2C36B033D7A72443F1438E76E37306A1F92AC30BC751F6D7ED1633FEE807440E1D6096C53C5E3E33828C9C59E8761E5BAD341C6D9E2BD1F2B5C3992666620CAA38C4645C154976EF62AE80161A9F7700C96875A72995E1C585918B28F65060F1B8B96417328F6DEDFCA79ED9F01EAB19FF4E3163F9963BA26E9B58031A04320CC73702A6ED438513E0F8ABA1966B53114038CC587050F90D9CD0F9E26CA9749723ABA85CF31F963A5E85E04993B2B2869725E734BE8FCFD30A801825582730B49C00A2058C02D3312D6D8E82078FF4F77C5FF9CE6E9D140F1A4517635AB784 + ENCRYPTED_VALUE = 0x016E000001630075007200720065006E00740075007300650072002F006D0079002F0066006100640064003500320032003000370065003000300032006500640064006500650038003300320062003100320065003200380031006500610032003800300066003200650066006200630062000D9BC8E2315C6D3F7BCB6D7578C2072E9482635E9E16B9AF3875846A6C4328541BEE6520BF99D012B34455102D8E23965B991AA0CE03A7E624FEFF87E0C082685960C81C9703DDD35089A2D86952120ABD82CEAA40B6071C3C8E36B597B6B09E44630ECE41F24A4DE26F0C583C5FF077898682106D64D710F4967B6E0705D5C5F436D1AF234BFD93F0F9104D88F2577B07C250003EB85F1D6AAE661AF70D72D80CDDA68B189B5718C34F00A5AFC47D59AFBB025F5FE3822BEC8D40C2D2EADCEAD3AB5C534E6B683B19B6F08E555396CDDD71AE0571939CB54BAFD6ED31DA6316EBF5F8330574EB9168D6E326D6DC003A1F65223C16DAD4C9CFD852E3016C04B9CBB9C7BFCFC9417441721C73E81B5C46252C5759CC835637335E2A1B70BEAD0DFF49561190D6B54E3B8AD669E64D4295294CD0A2BD4279395215CD0932F2951EE2748E697D5DDFBF45D4681B20728C0D0A1CE137F9C531EBFC84994CE071B54464A5BDF6AFC038C7D65A1E1D4B392216556B267CFBAAA86A9DD8BB70D0A727EE2B2242BC2C6B29DD09FAECEE6349AE67734C8E56B04A84D51EB74F5278205438EAADBBD59D4FD7F8FC7456EB59101841B7AE8D1851EF481FA37D3255E24BDB1305D380A6044595CE23D07D8F2A07B8862E77C5D4EAEC66886B297B4B4B26670629CC524031C50E9990054A9144975D6C88CBAD7FE41D0367B965FFBEF322BE6A ) GO + CREATE COLUMN ENCRYPTION KEY [CEK-win-enclave2] WITH VALUES ( COLUMN_MASTER_KEY = [CMK-win-enclave], ALGORITHM = 'RSA_OAEP', - ENCRYPTED_VALUE = 0x016E000001630075007200720065006E00740075007300650072002F006D0079002F0064003900630030003500370032006600610035003400620032003200310064003600350039003100630034003700330062006100650061003500330066006500360031006100610063003800350034006B4D40ABF0975AF7C5CA7D1F4345DE437318556F5A2380DCFE4AB792DC3A424EABC80EA24EE850FACD94F04809C8B32674C6FF2D966FA7F9F9E522990E5F5011515BA4B7EF3603619D8A4BF46AA9B769A8A4417462C4B0303F995F04964A2E328A503D87CD1AB85ECFCB8241D0C815540989DC33E58EDCCBAFF0753E196813E3FCCC5A3C9E4277DD528AE276F1F795973A4DF8D1BB3B1F405B5F35A6A583F0BB86BAD7FCADC1FCF6B14B602890109360FAB67D6A27DE542AE87784C40FEB9071AC34C4C40C92A6C153A4A38B6DA3AD48ED39E32D6D161ACE7EFE516B414139A831D878C13FF178649823C4EFDC8E5DB4C02F2147CC76965C01C2F3624EB809FD4F5C2E291056077B1ABEFF1F5001C1F4248704C7C70CF63DA1EBC2FEC4A3DF919BA4F6B465819BC4587599C2E7499CDE62D7C335CE7BBCFC72242A8F41C1B5C94DEB0A9AF49B723759A8CD9751EE70DDEBAFA1957382287F621790543841EBCCA0007BA030CAF29E9FBF8CEB4FEC88673F47B5EC3B5F759BBDD8ED2EAF572711D78286E4294B89FF6EBFEE4968B4596AF3B5C34985F28E886F6C211F385326F10ED62602007589FC494372902FB32B0E3D67A8C64F43A87B06EE9F2CF074EB6F3EC7A431733EDA8745051B7A4AA4C020797A9492E6A3BA643D031E491497BF17539993871085AC249D0AD82203CD442F69D6C686D26F4D17BA46B69D3CB7E395 + ENCRYPTED_VALUE = 0x016E000001630075007200720065006E00740075007300650072002F006D0079002F0066006100640064003500320032003000370065003000300032006500640064006500650038003300320062003100320065003200380031006500610032003800300066003200650066006200630062007F99C7C6F2E645A99AF68A4233CF78024AD556E6BD32776F51D163D091A4F3E9350FB8A524E6201588A4BEB95418A95F5E7D62B1AC9C71CCD75E88FE1838BA0C3DC60DCA01171CFDBFAB77567BB63D5BE5387C796F95559EE2C0A78C94456C8A584B5391C05CA145715D0024B2D0DD3D1C9E44D924466978A180AFA3EB6CF64DB44B022CF5033BAAB4A7DF3D67A8ED9EFB979C18D6EAC8B9B415491BF6F7F86E2844D0DCC5484D24830D2BD8DAB7B7B98F0F3DF47980131CC1BCFE7A8D76559BA9E8833B4779A08BFB65F45EDB6B3922A466BD3D2643C235CB0EB80B94B125E7C14711403D58F3D2F80336F65C8782F0C6F3D4494D40F99D770560673466D9362EC476D9F917F37C28C8ED15AF05C8F10B70D33D2A2646DA206873D34A6D89482C65D3793274EC2981A96BF927C22717078DFCFD6EAFDCCC0E274386A11101739B7DDEE8085BCD8381866696160969C5CCBE11520766FAC6EA187D51FC6ED8B7EA73D65BE8B25A124DD69000F4691BD63CAEAC33C71C12A5796DFC15E0BDBDB889E65AA8EBC9D5C11A9DF58A3BF36A9AE5DAEA8FB92AA68500FAC69FC85FEF8AFE0AD5CDF9C4C6D5915532620BEE1A5F77F2A574C374704C60096D4252405971C40A82AEF54F56AF924C7CC18395A22838D07014AF5585DA7EE248AAAB4C4FDA6BC187515C5D1DA0FC3BB05ABC9F98EE32575B17FEA7F2C0ED256D9FD1A68F0C ) GO + CREATE COLUMN ENCRYPTION KEY [CEK-win-noenclave] WITH VALUES ( COLUMN_MASTER_KEY = [CMK-win-noenclave], ALGORITHM = 'RSA_OAEP', - ENCRYPTED_VALUE = 0x016E000001630075007200720065006E00740075007300650072002F006D0079002F00640039006300300035003700320066006100350034006200320032003100640036003500390031006300340037003300620061006500610035003300660065003600310061006100630038003500340042DC7A3AAAD184E01288C0913EFB6FEC6167CD8EA08A5F46ADCCC34D3AA6A1BDDDA15EA3DD219ED8795AB05C0111E48EA35A82ADDF2A206FACBBF4FD73D01C004DF627012D3950FEBCA4BBEDBDF97BA77033728D8873BA81E1C7BDCBE04BB3AA7EB42A1EDDBEF9B1CA9477ADA33F76711FEDF782CA1BD3C0104FDEB9E0D66DFCEC7D3C236906481B44F04457549658635322447742FB00B6D6F36A7CFCC56BB39F7280736BC25FD499F9CBA2F63CE11D53E536FD4A266929E06CF2BDBAF229894A77EDE140323B674ECF28C58C3E0B6C2E9407AD1A26776CB55D68B8286F64787CE5A468CFA27295D6069EFA5D65CD9A04602E861F4504F2611AAE6A8ADE33038A2BECE8BD7CF5B48567C217E324F11935C552FD25FE1FEFB152684BD1B3F8EB70EC9F6439340CE82CD8E74DD5986A6C4F9E8336ED4AC804FAD800A3EA324F78DCE37832035C3DC92782A06150916D01322A80767D1A36D7A8D9BCF6727DCE6AC67A168FA8B8B5032E60DCB178B21A860F2D98BE09DA9BA5DCCBD0D339369FF3C50C7993463372CF5B1DA9FAA12CD16E76F5961C01EADC5804C7F22227E2095BAD0F90A47B6330B1B43407E01DE5B61CEBD542A93797428AD84376E9362EADE6DDD103B9EC96E616A2ECED7D1D665B5B872E77FC024AD92AB4A8335D12D41BDD152790E87590798C1005956F9F92D4DD0C1C9852D147F7CB55B3224DE8EF593F + ENCRYPTED_VALUE = 0x016E000001630075007200720065006E00740075007300650072002F006D0079002F00660061006400640035003200320030003700650030003000320065006400640065006500380033003200620031003200650032003800310065006100320038003000660032006500660062006300620019FA28795E9865B2FFE247F6405EA11CAE7FA8374FBF69B2C9BC6D4296D4EF2710D491CE9C00B29B837C9B2D70B1466E12E3448D27F473153E1CED638B1BBA980B3E14E173BD53C8A29DFA7EAC21F5F7E4E9DEFFD0023205593F13EE0DDEFA3E7772729E50C227668EE383A58A037766824E05EE608D47E9818893A8770427F847B97FBDC97AFEFBC1495C894538B7604E192332AAA4C19E1CD253AACA972989B46480681411AE8773E834254F618FD5AB5BBB961C7774A1A85332AD028056DADAA9785E092E9DB50A7D6CEB305CD1C3740265BDB55633D9FA0005A0DE3CABF65797B01F7B3CA9DA6B34C958565166D2B3C771233BB376A2F0E0D1BBC508DA117AA0F3EB25925C9C4B26A2FDD3F13792807067F088E9AAB442368D15B13E1138C715958505DD16F388A0476C29F6B04E8789CC396B54C95ED05F8F093A14B800DB7CB04F14732B96A06A7DB4FA81791FC0D5BA45562DA56B90E9A77A72588FAB71ED85F0358CAB2A45F4FBAFF031F44A6993F34B52CF119828989BCA2A802AABE5C3B5D6215F0BDB9F557AB13F2B61C6116D2F721E86D6BF0E100720EC6903417F0A00E57801DDE5B488829CB7DE0203D7CEE7689C7416796A5F3A33765D9F30904C180972E27A4DDAD67BF197DC9A8D4C7D53AF64FA306E012FD014CFF8923DB6E5B164E626D5B0282CEF968C3C00926BAD3928EE33B3414B79A758973B946B ) GO + CREATE COLUMN ENCRYPTION KEY [CEK-win-noenclave2] WITH VALUES ( COLUMN_MASTER_KEY = [CMK-win-noenclave], ALGORITHM = 'RSA_OAEP', - ENCRYPTED_VALUE = 0x016E000001630075007200720065006E00740075007300650072002F006D0079002F0064003900630030003500370032006600610035003400620032003200310064003600350039003100630034003700330062006100650061003500330066006500360031006100610063003800350034009014CD16FC878CEA2DE91C8C681AE86C7C062D8BD88C4CEE501A89FEAC47356D7181644A350F72B5F6023DA2B9E26C5A2522C08B1910D390068CF26794F4BA7B0298A6676B4DC6DED913E3B077B56224D2E1A3FE4EF33F58FE44CFC3DD67E54FB15BE8E29ABAF8357F378FBEDA3EBF9868A54746074D5E0E798047867E1ABD39AD0645BB8E071C72BFC37C007CBFC58F5690A5253F444E77169B2FE92FD95897A412B2078DA3804A00723D6DF824FCA527208A1DFB377B5BA16B620213F8252E10E7D7A3719A3FBB2F7A8189792B0BCF737236963C7DDCA6366F7B04F127925A1F8DDBB1B5A01D280BD300ECA3B1F31F24C8A0D517AE7BCBC3233A24E83B70A334754098DE373A1C027A4D09BB1D26C930E7501EB02464C519D19CFA0B296238AF11638C2E0688C7599E3DB1714AACF4EBFCEF63E1EE521A8E38E3BEFD4EF4991A15E8DD5CFD94E58E68754F3E90BC117025C01562F6440417A42612BE9C8871A18108CBE3E96DA7E35C45171C03E1DFBB3CA1E35A6D322F2D5B79E2BF2A07F14136DA4A768E08E2A7F1A42E04B717CB6AE3D1A3FA0EACCFC9CEC27DB53761E13DE1F55B410A65FB441D50CF8B2153B64925B1CEBDE062B5CAF4C99C41FED6836327037C46515710F16DC611305A0EBA1943A9BA5CC6889626990879713E9C95BB54D6A8A3C1C05A10AFE142B2487A1F0A07B57841E940CC9816E3F43CAE3CB7 + ENCRYPTED_VALUE = 0x016E000001630075007200720065006E00740075007300650072002F006D0079002F006600610064006400350032003200300037006500300030003200650064006400650065003800330032006200310032006500320038003100650061003200380030006600320065006600620063006200A422FBB5D90C0158A6F93B8BB8430C50B75FC7495D93B9A725D6BA845A21C7B59EA5D5232ED15016B410BA30520D03ACDF712085F1210196A909EFED0EC9E3DEA0C094CC0E01D7DDFD62387573372D277D2A3B0C3CA52C1D703B0EA4A6AE879D306BB1D065392C6431FA36B7AF71F69481CF5DEB38BDC48694A10C737F35C857F240AD12BF13E3A59ED86531C6DB5BC24CA5F0E84EF131D7306B0E510DE59DBCA64EE48A33745B228346240CA929430409A199C1CAB8B09968E69841004989452AC03932FCB5873C9E13F2663FD28084DC606DB936D0C78845428C9A2A9268C22F9ABD4F3D90D75BA9DE89B9C50FB24969BF184D2ADE0DCBD0E7829B7068C4C01E1A864ECFBBA4FC1394751B132C3E8E5A18637F727963730CEAE5FB9B775D544BA2CB43750C706A8A17CBABF8520C78189B093FF01940B24F3AF02B0BA15BD0A6F193EB2CE8503DDDCFD1FAD3763A5A6CA008470AAAF563E06BF86B995A86DF378E9EC0D4212331C51891BB1B0FCE2781DD2918A3B48D220800BAAB3CA52F6CD733AD54FF3D81AD4AC713F72A704BD5036561DBD43C6C9CDACB99C68F34796CFD3D2E41F6649147EF1AECC9153F7BABAD3D3FCCC5E5B921A4C25443CA0D8EAB9D7C09F8779B6EDAA6095E5492878316769AC4B0D77244DF4E88D5849D95990DD349887DF64DFC0C9BDB4AD2D74D6E75F5D2FEF37AF1FFA404F156DB66E9770F ) GO + diff --git a/test/functional/sqlsrv/0022.phpt b/test/functional/sqlsrv/0022.phpt index 916907490..cecc6f4a0 100644 --- a/test/functional/sqlsrv/0022.phpt +++ b/test/functional/sqlsrv/0022.phpt @@ -4,11 +4,21 @@ zombied streams after sqlsrv_stmt_cancel. --FILE-- getMessage() . PHP_EOL; } sqlsrv_free_stmt( $stmt ); @@ -44,9 +59,13 @@ zombied streams after sqlsrv_stmt_cancel. sqlsrv_fetch( $stmt ); $stream = sqlsrv_get_field( $stmt, 0, SQLSRV_PHPTYPE_STREAM("binary")); sqlsrv_cancel( $stmt ); - while( !feof( $stream ) && is_resource($stream) ) { - $str = fread( $stream, 80 ); - echo "$str\n"; + try { + while( !feof( $stream ) && is_resource($stream) ) { + $str = fread( $stream, 80 ); + echo "$str\n"; + } + } catch (TypeError $e) { + echo $e->getMessage() . PHP_EOL; } sqlsrv_free_stmt( $stmt ); @@ -64,7 +83,5 @@ Baby and Howlin Wolfs How Many More Times into near-cartoon parodies, the band a lso hinted at things to come with the manic Communication Breakdown and the lumb ering set stopper Dazed and Confused. \--Billy Altman\<\/I\> Source: Amazon.com essential recording - Most critics complain \Back in Black\< - -Warning: feof\(\): supplied resource is not a valid stream resource in .+(\/|\\)0022\.php on line [0-9]+ - -Warning: feof\(\): supplied resource is not a valid stream resource in .+(\/|\\)0022\.php on line [0-9]+ +feof\(\): supplied resource is not a valid stream resource +feof\(\): supplied resource is not a valid stream resource diff --git a/test/functional/sqlsrv/0065.phpt b/test/functional/sqlsrv/0065.phpt index 985b8e2bb..097d2c331 100644 --- a/test/functional/sqlsrv/0065.phpt +++ b/test/functional/sqlsrv/0065.phpt @@ -84,9 +84,18 @@ 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); + // in Alpine Linux, data returned is diffferent with always encrypted: + // something like '**** *ä**** *****-**×*' + // instead of '?', it replaces inexact conversions with asterisks + // reference: read the ICONV section in + // https://wiki.musl-libc.org/functional-differences-from-glibc.html if (count($arr) == 1) { // this means there is no question mark in $t - die("varchar(100) value \'$t\' is unexpected"); + // then try to find a substring of some asterisks + $asterisks = '****'; + if(strpos($t, '****') === false) { + die("varchar(100) value \'$t\' is unexpected"); + } } } @@ -227,11 +236,12 @@ if ($t !== $u) { die("Round trip failed."); } +// $t is an invalid utf-8 string, expect the procedure to fail $t = pack('H*', 'ffffffff'); $sqlType = $params = array(array(&$t, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8'))); -$query = "{call IntDoubleProc(?)}"; +$query = "{call Utf8InOutProc(?)}"; $s = AE\executeQueryParams($c, $query, $params, true, "no error from an invalid utf-8 string"); dropTable($c, $tableName); diff --git a/test/functional/sqlsrv/MsHelper.inc b/test/functional/sqlsrv/MsHelper.inc index 2058e5e01..590e8b333 100644 --- a/test/functional/sqlsrv/MsHelper.inc +++ b/test/functional/sqlsrv/MsHelper.inc @@ -1088,7 +1088,7 @@ function getColSize($k) case 19: return ("1073741823"); case 20: return ("512"); case 21: return ("512"); - case 22: return ("0)"); + case 22: return ("0"); case 23: return ("2147483647"); case 24: return ("36"); //case 25: return ("23"); @@ -1097,7 +1097,7 @@ function getColSize($k) case 28: return ("0"); default: break; } - return (""); + return NULL; } function getColPrecision($k) diff --git a/test/functional/sqlsrv/TC24_Close.phpt b/test/functional/sqlsrv/TC24_Close.phpt index 6ff584563..fad83c794 100644 --- a/test/functional/sqlsrv/TC24_Close.phpt +++ b/test/functional/sqlsrv/TC24_Close.phpt @@ -11,6 +11,13 @@ PHPT_EXEC=true getMessage() . PHP_EOL; } - // Invalid Query - $stmt1 = sqlsrv_query($conn1, "SELECT * FROM [$tableName]"); - if ($stmt1) { - die("Select query should fail when connection is closed"); + try { + // Invalid Query + $stmt1 = sqlsrv_query($conn1, "SELECT * FROM [$tableName]"); + if ($stmt1) { + die("Select query should fail when connection is closed"); + } + } catch (TypeError $e) { + echo $e->getMessage() . PHP_EOL; } - // Invalid Statement - $conn2 = AE\connect(); - $stmt2 = AE\selectFromTable($conn2, $tableName); - sqlsrv_close($conn2); - if (sqlsrv_fetch($stmt2)) { - die("Fetch should fail when connection is closed"); + try { + // Invalid Statement + $conn2 = AE\connect(); + $stmt2 = AE\selectFromTable($conn2, $tableName); + sqlsrv_close($conn2); + if (sqlsrv_fetch($stmt2)) { + die("Fetch should fail when connection is closed"); + } + } catch (TypeError $e) { + echo $e->getMessage() . PHP_EOL; } $conn3 = AE\connect(); @@ -53,17 +72,15 @@ function connectionClose() } try { + set_error_handler("warningHandler", E_WARNING); connectionClose(); } catch (Exception $e) { echo $e->getMessage(); } ?> ---EXPECTREGEX-- - -Warning: sqlsrv_close\(\): supplied resource is not a valid ss_sqlsrv_conn resource in .*TC24_Close.php on line 18 - -Warning: sqlsrv_query\(\): supplied resource is not a valid ss_sqlsrv_conn resource in .*TC24_Close.php on line 25 - -Warning: sqlsrv_fetch\(\): supplied resource is not a valid ss_sqlsrv_stmt resource in .*TC24_Close.php on line 34 +--EXPECT-- +sqlsrv_close(): supplied resource is not a valid ss_sqlsrv_conn resource +sqlsrv_query(): supplied resource is not a valid ss_sqlsrv_conn resource +sqlsrv_fetch(): supplied resource is not a valid ss_sqlsrv_stmt resource Test "Connection - Close" completed successfully. diff --git a/test/functional/sqlsrv/TC36_Close.phpt b/test/functional/sqlsrv/TC36_Close.phpt index 7df34c79a..e0da16885 100644 --- a/test/functional/sqlsrv/TC36_Close.phpt +++ b/test/functional/sqlsrv/TC36_Close.phpt @@ -12,6 +12,13 @@ PHPT_EXEC=true getMessage() . PHP_EOL; } trace("\nClosing the statement again (no error expected) ...\n"); - - if (sqlsrv_free_stmt($stmt1) === false) { - fatalError("A statement can be closed multiple times."); + try { + if (sqlsrv_free_stmt($stmt1) === false) { + fatalError("A statement can be closed multiple times."); + } + } catch (TypeError $e) { + echo $e->getMessage() . PHP_EOL; } - dropTable($conn1, $tableName); sqlsrv_close($conn1); @@ -49,15 +62,14 @@ function close() } try { + set_error_handler("warningHandler", E_WARNING); close(); } catch (Exception $e) { - echo $e->getMessage(); + echo $e->getMessage() . PHP_EOL; } ?> ---EXPECTREGEX-- - -Warning: sqlsrv_num_fields\(\): supplied resource is not a valid ss_sqlsrv_stmt resource in .*TC36_Close.php on line 21 - -Warning: sqlsrv_free_stmt\(\): supplied resource is not a valid ss_sqlsrv_stmt resource in .*TC36_Close.php on line 29 +--EXPECT-- +sqlsrv_num_fields(): supplied resource is not a valid ss_sqlsrv_stmt resource +sqlsrv_free_stmt(): supplied resource is not a valid ss_sqlsrv_stmt resource Test "Statement - Close" completed successfully. diff --git a/test/functional/sqlsrv/skipif_not_hgs.inc b/test/functional/sqlsrv/skipif_not_hgs.inc index a25d8cbcc..5295a73a4 100644 --- a/test/functional/sqlsrv/skipif_not_hgs.inc +++ b/test/functional/sqlsrv/skipif_not_hgs.inc @@ -9,6 +9,10 @@ if (!extension_loaded("sqlsrv")) { require_once("MsSetup.inc"); +if ($attestation == 'TARGET_ATTESTATION') { + die("skip Not set up for testing with secure enclave."); +} + $connectionInfo = array("UID"=>$userName, "PWD"=>$userPassword); $conn = sqlsrv_connect($server, $connectionInfo); diff --git a/test/functional/sqlsrv/skipif_unix_ansitests.inc b/test/functional/sqlsrv/skipif_unix_ansitests.inc new file mode 100644 index 000000000..373eb95e1 --- /dev/null +++ b/test/functional/sqlsrv/skipif_unix_ansitests.inc @@ -0,0 +1,15 @@ + diff --git a/test/functional/sqlsrv/sqlsrv_378_out_param_error.phpt b/test/functional/sqlsrv/sqlsrv_378_out_param_error.phpt index a0169225d..27942a21a 100644 --- a/test/functional/sqlsrv/sqlsrv_378_out_param_error.phpt +++ b/test/functional/sqlsrv/sqlsrv_378_out_param_error.phpt @@ -78,7 +78,7 @@ function executeSP($conn, $procName, $noRef, $prepare) $expected = 3; $v1 = 1; $v2 = 2; - $v3 = 'str'; + $v3 = 0; $res = true; $tsql = "{call $procName( ?, ?, ?)}"; diff --git a/test/functional/sqlsrv/sqlsrv_ae_fixed_var_widths.phpt b/test/functional/sqlsrv/sqlsrv_ae_fixed_var_widths.phpt new file mode 100644 index 000000000..590a21917 --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_ae_fixed_var_widths.phpt @@ -0,0 +1,184 @@ +--TEST-- +Test Always Encrypted in Windows by comparing fetched values from fields of fixed and variable widths +--DESCRIPTION-- +See Internal issue 2824 for details. In the plaintext case, the padding is added by SQL, not the driver. For AE, the motivation was to facilitate matching between char and varchar types, that is, a deterministic encryption of char(10) with “abcd” to match varchar(10 with “abcd”. +--SKIPIF-- + +--FILE-- + $type) { + $colDef = getColDef($name, $type) . ', '; + $tsql .= $colDef; + } + + $tsql = rtrim($tsql, ', ') . ')'; + return $tsql; + + } + + function createTablePlainQuery($conn, $tableName, $columns) + { + $tsql = "CREATE TABLE $tableName ("; + foreach ($columns as $name => $type) { + $colDef = '[' . $name . '] ' . $type . ', '; + $tsql .= $colDef; + } + + $tsql = rtrim($tsql, ', ') . ')'; + return $tsql; + } + + function compareFieldValues($f1, $f2, $qualified) + { + $matched = true; + if ($qualified) { + if ($f1 != $f2) { + echo "Always Encrypted: values do not match!\n"; + $matched = false; + } + } else { + if (strpos($f1, $f2) != 0) { + echo "Plain text: values do not match!\n"; + $matched = false; + }; + } + + if (!$matched) { + var_dump($f1); + var_dump($f2); + } + } + + require_once("MsCommon.inc"); + + // This test requires to connect with the Always Encrypted feature + // First check if the system is qualified to run this test + $options = array("Database" => $database, "UID" => $userName, "PWD" => $userPassword); + $conn = sqlsrv_connect($server, $options); + if ($conn === false) { + fatalError("Failed to connect to $server."); + } + + $qualified = AE\isQualified($conn) && (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'); + if ($qualified) { + sqlsrv_close($conn); + + // Now connect with ColumnEncryption enabled + $connectionOptions = array_merge($options, array('ColumnEncryption' => 'Enabled')); + $conn = sqlsrv_connect($server, $connectionOptions); + if ($conn === false) { + fatalError("Failed to connect to $server."); + } + } + + $tableName = 'srv_fixed_var_types_ae'; + + dropTable($conn, $tableName); + + // Define the column definitions + $columns = array('c_char' => 'CHAR(10)', 'c_varchar' => 'VARCHAR(10)', + 'c_nchar' => 'NCHAR(10)', 'c_nvarchar' => 'NVARCHAR(10)', + 'c_binary' => 'BINARY(10)', 'c_varbinary' => 'VARBINARY(10)'); + + if ($qualified) { + $tsql = createTableEncryptedQuery($conn, $tableName, $columns); + } else { + $tsql = createTablePlainQuery($conn, $tableName, $columns); + } + $stmt = sqlsrv_query($conn, $tsql); + if (!$stmt) { + fatalError("Failed to create table $tableName\n"); + } + + // Insert values + $values = array('ABCDE', 'ABCDE', + 'WXYZ', 'WXYZ', + '41424344', '41424344'); + + $params = array( + $values[0], + $values[1], + $values[2], + $values[3], + array( + $values[4], + SQLSRV_PARAM_IN, + null, + SQLSRV_SQLTYPE_BINARY(10) + ), + array( + $values[5], + SQLSRV_PARAM_IN, + null, + SQLSRV_SQLTYPE_VARBINARY(10) + ) + ); + + $tsql = "INSERT INTO $tableName (c_char, c_varchar, c_nchar, c_nvarchar, c_binary, c_varbinary) VALUES (?,?,?,?,?,?)"; + $stmt = sqlsrv_prepare($conn, $tsql, $params); + if (!$stmt) { + fatalError("Failed to prepare insert statement"); + } + $result = sqlsrv_execute($stmt); + if (!$result) { + fatalError("Failed to insert values"); + } + sqlsrv_free_stmt($stmt); + + // Now fetch the values + if ($qualified) { + $tsql = "SELECT CAST(c_char AS VARCHAR(10)), c_varchar, + CAST(c_nchar AS NVARCHAR(10)), c_nvarchar, + CAST(c_binary AS VARBINARY(10)), c_varbinary FROM $tableName"; + } else { + $tsql = "SELECT c_char, c_varchar, + c_nchar, c_nvarchar, + c_binary, c_varbinary FROM $tableName"; + } + $stmt = sqlsrv_query($conn, $tsql); + if (!$stmt) { + fatalError("Failed to select from $tableName"); + } + + while (sqlsrv_fetch($stmt)) { + $f0 = sqlsrv_get_field($stmt, 0); + $f1 = sqlsrv_get_field($stmt, 1); + + compareFieldValues($f0, $f1, $qualified); + + $f2 = sqlsrv_get_field($stmt, 2); + $f3 = sqlsrv_get_field($stmt, 3); + + compareFieldValues($f2, $f3, $qualified); + + $f4 = sqlsrv_get_field($stmt, 4, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR)); + $f5 = sqlsrv_get_field($stmt, 5, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR)); + + compareFieldValues($f4, $f5, $qualified); + } + + dropTable($conn, $tableName); + + // Close connection + sqlsrv_free_stmt($stmt); + sqlsrv_close($conn); + print "Done" +?> + +--EXPECT-- +Done diff --git a/test/functional/sqlsrv/sqlsrv_ae_insert_datetime_encrypted.phpt b/test/functional/sqlsrv/sqlsrv_ae_insert_datetime_encrypted.phpt new file mode 100644 index 000000000..f57dab9c7 --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_ae_insert_datetime_encrypted.phpt @@ -0,0 +1,154 @@ +--TEST-- +Test for inserting and retrieving encrypted data of datetime and smalldatetime types encrypted +--DESCRIPTION-- +Verify that inserting into smalldatetime column (if encrypted) might trigger "Datetime field overflow" error +--SKIPIF-- + +--FILE-- + $type) { + $colDef = getColDef($name, $type) . ', '; + $tsql .= $colDef; + } + + $tsql = rtrim($tsql, ', ') . ')'; + return $tsql; + + } + + function createTablePlainQuery($conn, $tableName, $columns) + { + $tsql = "CREATE TABLE $tableName ("; + foreach ($columns as $name => $type) { + $colDef = '[' . $name . '] ' . $type . ', '; + $tsql .= $colDef; + } + + $tsql = rtrim($tsql, ', ') . ')'; + return $tsql; + } + + require_once("MsCommon.inc"); + + // This test requires to connect with the Always Encrypted feature + // First check if the system is qualified to run this test + $options = array('Database' => $database, 'UID' => $userName, 'PWD' => $userPassword, 'ReturnDatesAsStrings' => true); + $conn = sqlsrv_connect($server, $options); + if ($conn === false) { + fatalError("Failed to connect to $server."); + } + + $qualified = AE\isQualified($conn) && (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'); + if ($qualified) { + sqlsrv_close($conn); + + // Now connect with ColumnEncryption enabled + $connectionOptions = array_merge($options, array('ColumnEncryption' => 'Enabled')); + $conn = sqlsrv_connect($server, $connectionOptions); + if ($conn === false) { + fatalError("Failed to connect to $server."); + } + } + + $tableName = 'srv_datetime_encrypted'; + dropTable($conn, $tableName); + + // Define the column definitions + $columns = array('c1' => 'smalldatetime', 'c2' => 'datetime', 'c3' => 'datetime2(0)', 'c4' => 'datetime2(4)'); + + if ($qualified) { + $tsql = createTableEncryptedQuery($conn, $tableName, $columns); + } else { + $tsql = createTablePlainQuery($conn, $tableName, $columns); + } + + $stmt = sqlsrv_query($conn, $tsql); + if (!$stmt) { + fatalError("Failed to create table $tableName\n"); + } + + // Insert values that cause errors + $val1 = '9999-12-31 23:59:59'; + $val2 = null; + $val3 = null; + $val4 = '9999-12-31 23:59:59.9999'; + + $tsql = "INSERT INTO $tableName (c1, c2, c3, c4) VALUES (?,?,?,?)"; + $params = array($val1, $val2, $val3, $val4); + + $stmt = sqlsrv_prepare($conn, $tsql, $params); + if (!$stmt) { + fatalError("Failed to prepare insert statement"); + } + $result = sqlsrv_execute($stmt); + if ($result) { + echo "Inserting invalid values should have failed!\n"; + } else { + $error = ($qualified)? '*Datetime field overflow' : '*The conversion of a varchar data type to a smalldatetime data type resulted in an out-of-range value.'; + if (!fnmatch($error, sqlsrv_errors()[0]['message'])) { + echo "Expected $error but got:\n"; + var_dump(sqlsrv_errors()); + } + } + + sqlsrv_free_stmt($stmt); + + // These values should work + $val1 = '2021-11-03 11:49:00'; + $val2 = '2015-10-23 07:03:00.000'; + $val3 = '0001-01-01 01:01:01'; + + $params = array($val1, $val2, $val3, $val4); + $stmt = sqlsrv_prepare($conn, $tsql, $params); + if (!$stmt) { + fatalError("Failed to prepare insert statement"); + } + $result = sqlsrv_execute($stmt); + if (!$result) { + fatalError("Failed to insert valid values\n"); + } + + sqlsrv_free_stmt($stmt); + + // Now fetch the values + $tsql = "SELECT * FROM $tableName"; + + $stmt = sqlsrv_query($conn, $tsql); + if (!$stmt) { + fatalError("Failed to select from $tableName"); + } + + $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + var_dump($row); + + dropTable($conn, $tableName); + + sqlsrv_free_stmt($stmt); + sqlsrv_close($conn); + + echo "Done\n"; + +?> +--EXPECT-- +array(4) { + ["c1"]=> + string(19) "2021-11-03 11:49:00" + ["c2"]=> + string(23) "2015-10-23 07:03:00.000" + ["c3"]=> + string(19) "0001-01-01 01:01:01" + ["c4"]=> + string(24) "9999-12-31 23:59:59.9999" +} +Done diff --git a/test/functional/sqlsrv/sqlsrv_ae_insert_decimal.phpt b/test/functional/sqlsrv/sqlsrv_ae_insert_decimal.phpt index 656c60259..afda09582 100644 --- a/test/functional/sqlsrv/sqlsrv_ae_insert_decimal.phpt +++ b/test/functional/sqlsrv/sqlsrv_ae_insert_decimal.phpt @@ -6,51 +6,54 @@ Test for inserting into and retrieving from decimal columns of different scale $num, "Testing numbers between 1 and -1:" => $frac); $scalesToTest = array(0, 1, 2, 3, 4, 5, 7, 9, 19, 28, 38); -try { - $conn = AE\connect(); - $tbname = "decimalTable"; - foreach ($numSets as $testName => $numSet) { - echo "\n$testName\n"; - foreach ($numSet as $input) { - $numInt = ceil(log10(abs($input) + 1)); - $decimalTypes = array(); - foreach ($scalesToTest as $scale) { - if ($scale < 39 - $numInt) { - array_push($decimalTypes, new AE\ColumnMeta("decimal(38, $scale)", "c$scale")); - } +$conn = AE\connect(); +$tbname = "decimalTable"; +foreach ($numSets as $testName => $numSet) { + echo "\n$testName\n"; + foreach ($numSet as $input) { + $numInt = ceil(log10(abs($input) + 1)); + $decimalTypes = array(); + foreach ($scalesToTest as $scale) { + if ($scale < 39 - $numInt) { + array_push($decimalTypes, new AE\ColumnMeta("decimal(38, $scale)", "c$scale")); } - if (empty($decimalTypes)) { - $decimalTypes = array(new AE\ColumnMeta("decimal(38, 0)", "c0")); - } - AE\createTable($conn, $tbname, $decimalTypes); + } + if (empty($decimalTypes)) { + $decimalTypes = array(new AE\ColumnMeta("decimal(38, 0)", "c0")); + } + AE\createTable($conn, $tbname, $decimalTypes); - $insertValues = array(); - foreach ($decimalTypes as $decimalType) { - $insertValues = array_merge($insertValues, array($decimalType->colName => $input)); - } - AE\insertRow($conn, $tbname, $insertValues); + $insertValues = array(); + foreach ($decimalTypes as $decimalType) { + $insertValues = array_merge($insertValues, array($decimalType->colName => $input)); + } + $stmt = AE\insertRow($conn, $tbname, $insertValues); + if (!$stmt) { + var_dump($insertValues); + fatalError("Failed to insert the above values\n"); + } - $stmt = sqlsrv_query($conn, "SELECT * FROM $tbname"); - $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); - foreach ($row as $key => $value) { - if ($value != 0) { - echo "$key: $value\n"; - } + $stmt = sqlsrv_query($conn, "SELECT * FROM $tbname"); + $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + if (empty($row)) { + fatalError("Empty array is returned\n"); + } + foreach ($row as $key => $value) { + if ($value != 0) { + echo "$key: $value\n"; } - sqlsrv_query($conn, "TRUNCATE TABLE $tbname"); } + sqlsrv_query($conn, "TRUNCATE TABLE $tbname"); } - dropTable($conn, $tbname); - sqlsrv_close($conn); -} catch (PDOException $e) { - echo $e->getMessage(); } +dropTable($conn, $tbname); +sqlsrv_close($conn); ?> --EXPECT-- @@ -210,6 +213,16 @@ c4: 123456789012346261234567890123.4629 c5: 123456789012346261234567890123.46290 c7: 123456789012346261234567890123.4629000 c0: -13775323913775323913775323913775323913 +c0: 9876 +c1: 9876.0 +c2: 9876.00 +c3: 9876.000 +c4: 9876.0000 +c5: 9876.00000 +c7: 9876.0000000 +c9: 9876.000000000 +c19: 9876.0000000000000000000 +c28: 9876.0000000000000000000000000000 Testing numbers between 1 and -1: c1: .1 @@ -304,4 +317,14 @@ c28: .0000000000000000000012345679 c38: .00000000000000000000123456789000000000 c28: -.0000000000000000000000012346 c38: -.00000000000000000000000123456789012346 -c38: .00000000000000000000000000000001377532 \ No newline at end of file +c38: .00000000000000000000000000000001377532 +c0: -1 +c1: -1.0 +c2: -.99 +c3: -.990 +c4: -.9900 +c5: -.99000 +c7: -.9900000 +c9: -.990000000 +c19: -.9900000000000000000 +c28: -.9900000000000000000000000000 diff --git a/test/functional/sqlsrv/sqlsrv_ae_insert_scientificNot.phpt b/test/functional/sqlsrv/sqlsrv_ae_insert_scientificNot.phpt index 16c78696d..2944832dd 100644 --- a/test/functional/sqlsrv/sqlsrv_ae_insert_scientificNot.phpt +++ b/test/functional/sqlsrv/sqlsrv_ae_insert_scientificNot.phpt @@ -6,54 +6,112 @@ Test for inserting into and retrieving from decimal columns of different scale $posExp, "Testing numbers between 1 and -1:" => $negExp); $scalesToTest = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 19); -try { - $conn = AE\connect(); - $tbname = "decimalTable"; - foreach ($numSets as $testName => $numSet) { - echo "\n$testName\n"; - foreach ($numSet as $input) { - $numInt = ceil(log10(abs($input) + 1)); - $decimalTypes = array(); - foreach ($scalesToTest as $scale) { - if ($scale < 39 - $numInt) { - array_push($decimalTypes, new AE\ColumnMeta("decimal(38, $scale)", "c$scale")); - } - } - if (empty($decimalTypes)) { - $decimalTypes = array(new AE\ColumnMeta("decimal(38, 0)", "c0")); - } - AE\createTable($conn, $tbname, $decimalTypes); +function testErrorCases($conn) +{ + // Create a dummy table + $tableName = "srv_sci_not"; + $colMeta = array(new AE\ColumnMeta("decimal(38, 1)", "Column1")); + + AE\createTable($conn, $tableName, $colMeta); + + $expected = '*Invalid character value for cast specification'; + $tsql = "INSERT INTO $tableName (Column1) VALUES (?)"; + $input = "- 0E1.3"; + $param = array( + array(&$input, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_DECIMAL(38, 1)) + ); + + $stmt = sqlsrv_prepare($conn, $tsql, $param); + if (!sqlsrv_execute($stmt)) { + if (!fnmatch($expected, sqlsrv_errors()[0]['message'])) { + var_dump(sqlsrv_errors()); + } + } else { + echo "Expect $input to fail"; + } + + $input = "8e0-2"; + if (!sqlsrv_execute($stmt)) { + if (!fnmatch($expected, sqlsrv_errors()[0]['message'])) { + var_dump(sqlsrv_errors()); + } + } else { + echo "Expect $input to fail"; + } + + $input = "-19e032+"; + if (!sqlsrv_execute($stmt)) { + if (!fnmatch($expected, sqlsrv_errors()[0]['message'])) { + var_dump(sqlsrv_errors()); + } + } else { + echo "Expect $input to fail"; + } + $input = "5678.5678.5678"; + $expected = "*String data, right truncation"; + if (!sqlsrv_execute($stmt)) { + if (!fnmatch($expected, sqlsrv_errors()[0]['message'])) { + var_dump(sqlsrv_errors()); + } + } else { + echo "Expect $input to fail"; + } + dropTable($conn, $tableName); +} + +$conn = AE\connect(); - $insertValues = array(); - foreach ($decimalTypes as $decimalType) { - $scale = intval(ltrim($decimalType->colName, "c")); - array_push($insertValues, array($input, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_DECIMAL(38, $scale))); +testErrorCases($conn); + +$tbname = "decimalTable"; +foreach ($numSets as $testName => $numSet) { + echo "\n$testName\n"; + foreach ($numSet as $input) { + $numInt = ceil(log10(abs($input) + 1)); + $decimalTypes = array(); + foreach ($scalesToTest as $scale) { + if ($scale < 39 - $numInt) { + array_push($decimalTypes, new AE\ColumnMeta("decimal(38, $scale)", "c$scale")); } - $insertSql = "INSERT INTO $tbname VALUES(" . AE\getSeqPlaceholders(count($insertValues)) . ")"; - $stmt = sqlsrv_prepare($conn, $insertSql, $insertValues); - sqlsrv_execute($stmt); + } + if (empty($decimalTypes)) { + $decimalTypes = array(new AE\ColumnMeta("decimal(38, 0)", "c0")); + } + AE\createTable($conn, $tbname, $decimalTypes); + + $insertValues = array(); + foreach ($decimalTypes as $decimalType) { + $scale = intval(ltrim($decimalType->colName, "c")); + array_push($insertValues, array($input, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_DECIMAL(38, $scale))); + } - $stmt = sqlsrv_query($conn, "SELECT * FROM $tbname"); - $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); - foreach ($row as $key => $value) { - if ($value != 0) { - echo "$key: $value\n"; - } + $insertSql = "INSERT INTO $tbname VALUES(" . AE\getSeqPlaceholders(count($insertValues)) . ")"; + $stmt = sqlsrv_prepare($conn, $insertSql, $insertValues); + if (!sqlsrv_execute($stmt)) { + fatalError("Failed to execute $insertSql\n"); + } + + $stmt = sqlsrv_query($conn, "SELECT * FROM $tbname"); + $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); + if (empty($row)) { + fatalError("Empty array is returned\n"); + } + foreach ($row as $key => $value) { + if ($value != 0) { + echo "$key: $value\n"; } - sqlsrv_query($conn, "TRUNCATE TABLE $tbname"); } + sqlsrv_query($conn, "TRUNCATE TABLE $tbname"); } - dropTable($conn, $tbname); - sqlsrv_close($conn); -} catch (PDOException $e) { - echo $e->getMessage(); } +dropTable($conn, $tbname); +sqlsrv_close($conn); ?> --EXPECT-- @@ -246,6 +304,28 @@ c7: 13775320000.0000000 c8: 13775320000.00000000 c9: 13775320000.000000000 c19: 13775320000.0000000000000000000 +c0: -53687 +c1: -53687.1 +c2: -53687.09 +c3: -53687.092 +c4: -53687.0919 +c5: -53687.09185 +c6: -53687.091854 +c7: -53687.0918543 +c8: -53687.09185426 +c9: -53687.091854260 +c19: -53687.0918542600000000000 +c0: 1000 +c1: 999.9 +c2: 999.90 +c3: 999.900 +c4: 999.9000 +c5: 999.90000 +c6: 999.900000 +c7: 999.9000000 +c8: 999.90000000 +c9: 999.900000000 +c19: 999.9000000000000000000 Testing numbers between 1 and -1: c0: -10 @@ -401,3 +481,21 @@ c7: -.1377532 c8: -.13775320 c9: -.137753200 c19: -.1377532000000000000 +c1: .1 +c2: .05 +c3: .054 +c4: .0537 +c5: .05370 +c6: .053697 +c7: .0536971 +c8: .05369709 +c9: .053697092 +c19: .0536970918542600000 +c3: .001 +c4: .0010 +c5: .00100 +c6: .001000 +c7: .0009999 +c8: .00099990 +c9: .000999900 +c19: .0009999000000000000 diff --git a/test/functional/sqlsrv/sqlsrv_ae_output_param_all.phpt b/test/functional/sqlsrv/sqlsrv_ae_output_param_all.phpt index d7ff5db1a..0bdfe8483 100644 --- a/test/functional/sqlsrv/sqlsrv_ae_output_param_all.phpt +++ b/test/functional/sqlsrv/sqlsrv_ae_output_param_all.phpt @@ -6,6 +6,13 @@ Test for binding output parameter of encrypted values for all types 2147483647, "c2_smallint" => 32767, "c3_tinyint" => 255, "c4_bit" => 1, - "c5_bigint" => 922337203685479936, - "c6_decimal" => 9223372036854.80000, - "c7_numeric" => 21474.83647, - "c8_float" => 9223372036.8548, - "c9_real" => 2147.483, + "c5_bigint" => '922337203685479936', + "c6_decimal" => '9223372036854.80000', + "c7_numeric" => '21474.83647', + "c8_float" => $floatInput, + "c9_real" => $realInput, "c10_date" => '9999-12-31', "c11_datetime" => '9999-12-31 23:59:59.997', "c12_datetime2" => '9999-12-31 23:59:59.9999999', @@ -74,13 +84,14 @@ $stmt = AE\insertRow($conn, $tbname, $inputs); // Call store procedure $outSql = AE\getCallProcSqlPlaceholders($spname, count($inputs)); +// Initialize all inputs, set bigint, decimal and numeric as empty strings $intOut = 0; $smallintOut = 0; $tinyintOut = 0; $bitOut = 0; -$bigintOut = 0.0; -$decimalOut = 0.0; -$numericOut = 0.0; +$bigintOut = ''; +$decimalOut = ''; +$numericOut = ''; $floatOut = 0.0; $realOut = 0.0; $dateOut = ''; @@ -119,8 +130,14 @@ print("bitOut: " . $bitOut . "\n"); print("bigintOut: " . $bigintOut . "\n"); print("decimalOut: " . $decimalOut . "\n"); print("numericOut: " . $numericOut . "\n"); -print("floatOut: " . $floatOut . "\n"); -print("realOut: " . $realOut . "\n"); +if (!compareFloats($floatInput, $floatOut)) { + // Should not expect float values to match exactly + print("Expected $floatInput but got $floatOut\n"); +} +if (!compareFloats($realInput, $realOut)) { + // Should not expect real values to match exactly + print("Expected $realInput but got $realOut\n"); +} print("dateOut: " . $dateOut . "\n"); print("datetimeOut: " . $datetimeOut . "\n"); print("datetime2Out: " . $datetime2Out . "\n"); @@ -142,11 +159,9 @@ intOut: 2147483647 smallintOut: 32767 tinyintOut: 255 bitOut: 1 -bigintOut: 9.2233720368548E\+17 -decimalOut: 9223372036854\.8 +bigintOut: 922337203685479936 +decimalOut: (9223372036854\.8|9223372036854\.80000) numericOut: 21474\.83647 -floatOut: 9223372036\.8548 -realOut: 2147\.4829101562 dateOut: 9999-12-31 datetimeOut: (9999-12-31 23:59:59\.997|Dec 31 9999 11:59PM) datetime2Out: 9999-12-31 23:59:59\.9999999 diff --git a/test/functional/sqlsrv/sqlsrv_ae_output_param_errors.phpt b/test/functional/sqlsrv/sqlsrv_ae_output_param_errors.phpt new file mode 100644 index 000000000..4933aacaa --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_ae_output_param_errors.phpt @@ -0,0 +1,143 @@ +--TEST-- +Test to incorrectly bind input parameters as output parameters of various types +--DESCRIPTION-- +Similar to pdo_ae_output_param_errors.phpt - test to incorrectly bind input parameters +as output parameters of various types. The key is to enable ColumnEncryption and +check for memory leaks. +--SKIPIF-- + +--FILE-- += 17 && $vers[1] > 0){ + return true; + } else { + return false; + } +} + +// Check if the ODBC driver supports connecting with ColumnEncryption +// If not simply return +require_once('MsHelper.inc'); +require_once('MsSetup.inc'); + +$conn = sqlsrv_connect($server, $connectionOptions); +if ($conn === false) { + fatalError("Failed to connect to $server."); +} +if (!checkODBCVersion($conn)) { + echo "Done\n"; + sqlsrv_close($conn); + return; +} + +// Create a dummy table with various data types +$tbname = 'srv_output_param_errors'; +$colMetaArr = array( new AE\ColumnMeta("int", "c1_int"), + new AE\ColumnMeta("smallint", "c2_smallint"), + new AE\ColumnMeta("tinyint", "c3_tinyint"), + new AE\ColumnMeta("bit", "c4_bit"), + new AE\ColumnMeta("bigint", "c5_bigint"), + new AE\ColumnMeta("decimal(18,5)", "c6_decimal"), + new AE\ColumnMeta("numeric(10,5)", "c7_numeric"), + new AE\ColumnMeta("float", "c8_float"), + new AE\ColumnMeta("real", "c9_real"), + new AE\ColumnMeta("date", "c10_date"), + new AE\ColumnMeta("datetime", "c11_datetime"), + new AE\ColumnMeta("datetime2", "c12_datetime2"), + new AE\ColumnMeta("datetimeoffset", "c13_datetimeoffset"), + new AE\ColumnMeta("time", "c14_time"), + new AE\ColumnMeta("char(5)", "c15_char"), + new AE\ColumnMeta("varchar(max)", "c16_varchar"), + new AE\ColumnMeta("nchar(5)", "c17_nchar"), + new AE\ColumnMeta("nvarchar(max)", "c18_nvarchar")); +AE\createTable($conn, $tbname, $colMetaArr); + +// Create a dummy select statement +$sql = "SELECT * FROM $tbname WHERE c1_int = ? OR c2_smallint = ? OR c3_tinyint = ? "; +$sql .= "OR c4_bit = ? OR c5_bigint = ? OR c6_decimal = ? OR c7_numeric = ? OR c8_float = ? "; +$sql .= "OR c9_real = ? OR c10_date = ? OR c11_datetime = ? OR c12_datetime2 = ? "; +$sql .= "OR c13_datetimeoffset = ? OR c14_time = ? OR c15_char = ? "; +$sql .= "OR c16_varchar = ? OR c17_nchar = ? OR c18_nvarchar = ?"; + +$options = array_merge($connectionOptions, + array('ColumnEncryption' => 'Enabled', + 'CharacterSet' => 'UTF-8')); + +// Initialize all inputs, set bigint, decimal and numeric as empty strings +$intOut = 0; +$smallintOut = 0; +$tinyintOut = 0; +$bitOut = 0; +$bigintOut = ''; +$decimalOut = ''; +$numericOut = ''; +$floatOut = 0.0; +$realOut = 0.0; +$dateOut = ''; +$datetimeOut = ''; +$datetime2Out = ''; +$datetimeoffsetOut = ''; +$timeOut = ''; +$charOut = ''; +$varcharOut = ''; +$ncharOut = ''; +$nvarcharOut = ''; + +$usage1 = 0; +$rounds = 30; +for ($i = 0; $i < $rounds; $i++) { + // Connect with ColumnEncryption enabled + $conn2 = sqlsrv_connect($server, $options); + if ($conn2 === false) { + fatalError("Failed to connect to $server."); + } + + $stmt = sqlsrv_prepare($conn2, $sql, array( array( &$intOut, SQLSRV_PARAM_OUT ), + array( &$smallintOut, SQLSRV_PARAM_OUT ), + array( &$tinyintOut, SQLSRV_PARAM_OUT ), + array( &$bitOut, SQLSRV_PARAM_OUT ), + array( &$bigintOut, SQLSRV_PARAM_OUT ), + array( &$decimalOut, SQLSRV_PARAM_OUT ), + array( &$numericOut, SQLSRV_PARAM_OUT ), + array( &$floatOut, SQLSRV_PARAM_OUT ), + array( &$realOut, SQLSRV_PARAM_OUT ), + array( &$dateOut, SQLSRV_PARAM_OUT ), + array( &$datetimeOut, SQLSRV_PARAM_OUT ), + array( &$datetime2Out, SQLSRV_PARAM_OUT ), + array( &$datetimeoffsetOut, SQLSRV_PARAM_OUT ), + array( &$timeOut, SQLSRV_PARAM_OUT ), + array( &$charOut, SQLSRV_PARAM_OUT ), + array( &$varcharOut, SQLSRV_PARAM_OUT ), + array( &$ncharOut, SQLSRV_PARAM_OUT ), + array( &$nvarcharOut, SQLSRV_PARAM_OUT ))); + + // Expect the following to fail so just ignore the errors + sqlsrv_execute($stmt); + + // Compare the current memory usage to the previous usage + if ($i == 0) { + $usage1 = memory_get_usage(); + } else { + $usage2 = memory_get_usage(); + if ($usage2 > $usage1) { + echo "Memory leaks ($i)! Expected $usage1 but now $usage2\n"; + } + } + + // Free the resources to trigger the destruction of any zvals with refcount of 0 + sqlsrv_free_stmt($stmt); + sqlsrv_close($conn2); +} + +sqlsrv_query($conn, "DROP TABLE $tbname"); +sqlsrv_close($conn); + +echo "Done\n"; +?> +--EXPECT-- +Done \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_ansi_locale_fr.phpt b/test/functional/sqlsrv/sqlsrv_ansi_locale_fr.phpt new file mode 100644 index 000000000..bc9009e47 --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_ansi_locale_fr.phpt @@ -0,0 +1,108 @@ +--TEST-- +Test another ansi encoding fr_FR euro locale outside Windows +--DESCRIPTION-- +This file must be saved in ANSI encoding and the required locale must be present +--ENV-- +PHPT_EXEC=true +--SKIPIF-- + +--FILE-- + +--EXPECT-- +Done + diff --git a/test/functional/sqlsrv/sqlsrv_ansi_locale_zh.phpt b/test/functional/sqlsrv/sqlsrv_ansi_locale_zh.phpt new file mode 100644 index 000000000..bcdfa22a8 --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_ansi_locale_zh.phpt @@ -0,0 +1,81 @@ +--TEST-- +Test Chinese locale in Linux +--DESCRIPTION-- +This test requires ODBC Driver 17.6 or above and will invoke another php script that +is saved as GB2312(Simplified Chinese) ANSI format, namely sqlsrv_test_gb18030.php. +To run this test, create a temporary database first with the correct collation + CREATE DATABASE [GB18030test] + COLLATE Chinese_PRC_CI_AS +Next, set the correct locale and convert the php script, like this: + export LC_ALL=zh_CN.gb18030 + iconv -c -f GB2312 -t GB18030 sqlsrv_test_gb18030.php > test_gb18030.php +Drop the temporary database when the test is finished. +--ENV-- +PHPT_EXEC=true +--SKIPIF-- +$userName, "PWD"=>$userPassword); +$conn = sqlsrv_connect($server, $connectionInfo); +if ($conn === false) { + die("skip Could not connect during SKIPIF."); +} + +$msodbcsqlVer = sqlsrv_client_info($conn)["DriverVer"]; +$msodbcsqlMaj = explode(".", $msodbcsqlVer)[0]; +$msodbcsqlMin = explode(".", $msodbcsqlVer)[1]; + +if ($msodbcsqlMaj < 17) { + die("skip Unsupported ODBC driver version"); +} + +if ($msodbcsqlMaj == 17 && $msodbcsqlMin < 6) { + die("skip Unsupported ODBC driver version"); +} +?> + +--FILE-- +"master", "UID"=>$userName, "PWD"=>$userPassword); + $conn = sqlsrv_connect($server, $options); + if( $conn === false ) { + throw new Error("Failed to connect"); + } + + $tempDB = 'GB18030test' . rand(1, 100); + $query = "CREATE DATABASE $tempDB COLLATE Chinese_PRC_CI_AS"; + $stmt = sqlsrv_query($conn, $query); + if ($stmt === false) { + throw new Error("Failed to create the database $tempDB"); + } + + shell_exec("export LC_ALL=zh_CN.gb18030"); + shell_exec("iconv -c -f GB2312 -t GB18030 ".dirname(__FILE__)."/sqlsrv_test_gb18030.php > ".dirname(__FILE__)."/test_gb18030.php"); + + print_r(shell_exec(PHP_BINARY." ".dirname(__FILE__)."/test_gb18030.php $tempDB")); +} catch (Error $err) { + echo $err->getMessage() . PHP_EOL; + print_r(sqlsrv_errors()); +} finally { + if ($conn) { + if (!empty($tempDB)) { + $query = "DROP DATABASE $tempDB"; + sqlsrv_query($conn, $query); + } + sqlsrv_close($conn); + } +} + +?> +--EXPECT-- +Done diff --git a/test/functional/sqlsrv/sqlsrv_buffered_fetch_types.phpt b/test/functional/sqlsrv/sqlsrv_buffered_fetch_types.phpt index 425d7f58f..905976705 100644 --- a/test/functional/sqlsrv/sqlsrv_buffered_fetch_types.phpt +++ b/test/functional/sqlsrv/sqlsrv_buffered_fetch_types.phpt @@ -10,7 +10,50 @@ Test various conversion functionalites for buffered queries with SQLSRV. $violation = 'Restricted data type attribute violation'; $outOfRange = 'Numeric value out of range'; $truncation = 'Fractional truncation'; -$epsilon = 0.00001; + +function compareFloats($expected, $actual) +{ + $epsilon = 0.00001; + + $diff = abs(($actual - $expected) / $expected); + + return ($diff < $epsilon); +} + +function fetchAsChar($conn, $tableName, $inputs) +{ + $query = "SELECT c_varbinary, c_int, c_float, c_decimal, c_datetime2, c_varchar FROM $tableName"; + + $stmt = sqlsrv_query($conn, $query, array(), array("Scrollable"=>SQLSRV_CURSOR_CLIENT_BUFFERED)); + if (!$stmt) { + fatalError("In fetchAsChar: failed to run query!"); + } + + if (sqlsrv_fetch($stmt, SQLSRV_FETCH_NUMERIC) === false) { + fatalError("In fetchAsChar: failed to fetch the row from $tableName!"); + } + + // Fetch all fields as strings - no conversion + for ($i = 0; $i < count($inputs) - 1; $i++) { + $f = sqlsrv_get_field($stmt, $i, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR)); + if ($i == 0) { + if ($inputs[$i] !== hex2bin($f)) { + echo "In fetchAsChar ($i): expected $inputs[$i]\n"; + var_dump(hex2bin($f)); + } + } elseif ($i == 2) { + if (!compareFloats(floatval($inputs[$i]), floatval($f))) { + echo "In fetchAsChar ($i): expected $inputs[$i]\n"; + var_dump($f); + } + } else { + if ($f !== $inputs[$i]) { + echo "In fetchAsChar ($i): expected $inputs[$i]\n"; + var_dump($f); + } + } + } +} function fetchAsUTF8($conn, $tableName, $inputs) { @@ -29,10 +72,17 @@ function fetchAsUTF8($conn, $tableName, $inputs) $f = sqlsrv_get_field($stmt, $i, SQLSRV_PHPTYPE_STRING('utf-8')); if ($i == 0) { if ($inputs[$i] !== hex2bin($f)) { + echo "In fetchAsUTF8 ($i): expected $inputs[$i]\n"; + var_dump(hex2bin($f)); + } + } elseif ($i == 2) { + if (!compareFloats(floatval($inputs[$i]), floatval($f))) { + echo "In fetchAsUTF8 ($i): expected $inputs[$i]\n"; var_dump($f); } } else { if ($f !== $inputs[$i]) { + echo "In fetchAsUTF8 ($i): expected $inputs[$i]\n"; var_dump($f); } } @@ -59,15 +109,26 @@ function fetchArray($conn, $tableName, $inputs) } for ($i = 0; $i < count($inputs); $i++) { + $matched = true; if ($i == 1) { $expected = intval($inputs[$i]); + if ($results[$i] !== $expected) { + $matched = false; + } } elseif ($i == 2) { $expected = floatval($inputs[$i]); + if (!compareFloats($expected, $results[$i])) { + $matched = false; + } } else { $expected = $inputs[$i]; + if ($results[$i] !== $expected) { + $matched = false; + } } - if ($results[$i] !== $expected) { + // if ($results[$i] !== $expected) { + if (!$matched) { echo "in fetchArray: for column $i expected $expected but got: "; var_dump($results[$i]); } @@ -100,24 +161,15 @@ function fetchAsFloats($conn, $tableName, $inputs) } } elseif ($i < 5) { $expected = floatval($inputs[$i]); - $diff = abs(($f - $expected) / $expected); - - if ($diff > $epsilon) { + if (!compareFloats($expected, $f)) { echo "in fetchAsFloats: for column $i expected $expected but got: "; var_dump($f); } } else { // The char fields will get errors too - // TODO 11297: fix this part outside Windows later - if (isWindows()) { - if (strpos(sqlsrv_errors()[0]['message'], $outOfRange) === false) { - var_dump($f); - fatalError("in fetchAsFloats: expected $outOfRange for column $i\n"); - } - } else { - if ($f != 0.0) { - var_dump($f); - } + if (strpos(sqlsrv_errors()[0]['message'], $outOfRange) === false) { + var_dump($f); + fatalError("in fetchAsFloats: expected $outOfRange for column $i\n"); } } } @@ -155,19 +207,12 @@ function fetchAsInts($conn, $tableName, $inputs) } } elseif ($i >= 5) { // The char fields will get errors too - // TODO 11297: fix this part outside Windows later - if (isWindows()) { - if (strpos(sqlsrv_errors()[0]['message'], $outOfRange) === false) { - var_dump($f); - fatalError("in fetchAsInts: expected $outOfRange for column $i\n"); - } - } else { - if ($f != 0) { - var_dump($f); - } + if (strpos(sqlsrv_errors()[0]['message'], $outOfRange) === false) { + var_dump($f); + fatalError("in fetchAsInts: expected $outOfRange for column $i\n"); } } else { - $expected = floor($inputs[$i]); + $expected = floor(floatval($inputs[$i])); if ($f != $expected) { echo "in fetchAsInts: for column $i expected $expected but got: "; var_dump($f); @@ -260,6 +305,7 @@ if ($stmt) { } // Starting fetching using client buffers +fetchAsChar($conn, $tableName, $inputs); fetchAsUTF8($conn, $tableName, $inputs); fetchArray($conn, $tableName, $inputs); fetchAsFloats($conn, $tableName, $inputs); diff --git a/test/functional/sqlsrv/sqlsrv_client_info.phpt b/test/functional/sqlsrv/sqlsrv_client_info.phpt index bfcc2d0e8..ef8f54353 100644 --- a/test/functional/sqlsrv/sqlsrv_client_info.phpt +++ b/test/functional/sqlsrv/sqlsrv_client_info.phpt @@ -21,5 +21,5 @@ array\(4\) { \[\"DriverVer\"\]=> string\(10\) \"[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{4}\" \[\"ExtensionVer\"\]=> - string\([0-9]+\) \"[0-9].[0-9]\.[0-9](-(RC[0-9]?|preview))?(\.[0-9]+)?(\+[0-9]+)?\" + string\([0-9]+\) \"[0-9]\.[0-9]\.[0-9](-(RC[1-9]?|preview[1-9]))?(\.[0-9]+)?(\+[0-9]+)?\" } \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_close.phpt b/test/functional/sqlsrv/sqlsrv_close.phpt index 2c8e2d10e..0bcdbd7b9 100644 --- a/test/functional/sqlsrv/sqlsrv_close.phpt +++ b/test/functional/sqlsrv/sqlsrv_close.phpt @@ -4,6 +4,15 @@ using an already closed connection. --FILE-- /Bh,~bOUZ:*u_AhaCuU +aoУoA.*ZBߣbo@֩~:~|Ъz>C~bB:b|.oB>Cubb+hB>*.h_/ â~*:BUa<::ZUoZ O~,z,Ch .v,:h>@aA,~A UA|OCb h/bh~a+r<ߣ|+/a@:zz,Z.z/.<+h~AaCob/~ZU>zC+ :h.ߩar/ CubܣUuU,b@a<|@Z<@o.@ozbOa*CbAZ:buO/,Uv>zAOOzCC_bC/Ub|rv@Z*@@bOo:Z:Zh,>Or@U,Ooz+UUCb|a,UhBv:C+rOazU/bZ_b>|u*ab@_UA+a,Bz.AbA|Z|zu ߢa+/<:Z,zܣ:v*bbZhvOOa/UvA O_>z:OuU/vbh@O:/.<>U~ ABa:A,O_hr u*vrbv~: or>|*rr<+//|Au+hZ hߩ:bZZr~hA,aAra@A:+@r.@aOZhv_Ara|><@ߣvbovbrObU*O<@hza~auâ.u/a<Ua.+vB,a>~ b@,uoZ+>:U/B|_,Cz*uz>ohB>b>@:z*Or/ZBv>z@h,OAo++/ܩ, Ua._Uo/vO_uoovabUohzC> ..oa~~OC:uUbva|֣aZor.*ZU*.vh:o<>ܣovz Az~Z.~ZZzhZC@h/@B|a,u*:|Uu..bou~Z.B>Zb@b+oBAAzZC CCr.~:v@AZvzA||O__:uBo_C:*U@BbZUvOoU+O>zz/Ī|~b,,Ah:o+/@~:*_>|.++u~B_|*<ЪbzrCoabU:@:b_C ܣboU~~B_/*bh,raZOZB~o,C@**ĪO,C~Ov ,.azh>abU*Bh@*ahU:_oahAuBC>C_ C:.or<@:uhCOo<+_+C,oOu_ _+.>C~h+B oBbar:B,<@>ģb+@A*A~:v_o~BOB,bhBoA,..B|+Caoh@a @Au.:|~ *bA~a*u_h+u+Aa@>z_|au>bãr.Т.ABCBh |+Bv b*Urz/,Bh:@Zܪ:bb|,u~+*.a+|Car+a~.b/zu/@ЩZa>UOarvbC*b@.o>/ Ob> vBCb@/A,oA_r*|va>a<|z||uZ_Cz*.ܢz@_vB@o<.|uUr_.|vģ.ZU,bub,><|:Cob.Bb:C|::ĩhO< AZb,boO_U .oOao Zv/obbA.v >B~ |>h/.r/*~rr.bUéUh|C|bu:a,bZbé_bo>uZ:ub< ra<*|@b/ZCob>h,*|Ohbh+/uuZ_::aB_B/_a u+++ߪ>ZC Cz<:+oObZ+vha+:bĪBUub~>/z+O.oAb||rhvb~ ,+C|Z.ozh/r>b,+<+|.a~ĪAU,B/~z,>u_/,h/.+u,o@/zb+@az|~Bb_zZh>B :b:~ZA@>r,:auA', null, N'z>h@*zAAUCz:,bCo/a~.a~@.r._b_֪+UC~A>ourb/~Cv.*vUz>A,OzC,hbOBh_z*huvz~<~|u֩U_Ohv|.,B,, ,~BA>B@,_O//O:Bbb@b+ >:>墢Uz*oz_U.@ZAOvzahUZ,,UvCZO@ BAzaO@aCaCoZv>*o~+Cbܪ|:r,Uo', null, N'Za,У,ģ,h. .*>C_bCr,//ĩ+CrOBaZ@auz_+Uo/:<_v| bv*ZbBrB:AC_|zBZ.+ZAz+ bA:b_O/ߩ>zCb><:+.Uh<:zAC,UC*rUB|o_ZU@|z./:ACC~b|o>h*ua|>.>b zbBC>Uu/,ߪZCCO.oC.b@<:UC,/aCh|AazuhaZ//+ZuZ.vuO/A Z@<|ZrUCCh_o~a._z,a.ZB|C/:aUu.u@ <.>/r| A>+,uB*@CZv r.:O~@u B/>hh//CuhBZb:bBB< ~rU,ao,UOb:rZ>,+B:Z@.*C|@|._bA _+@>_:r..r.CBABrboh@|Uh,:O<,|zo>+@abzv<_ @ZOB>@.|v_ ZZh_r:baO~.a|voAU~C:au,@ BBB+ho <,_/:_*BZC.ubaBhZ,C_ua_zBh:+C*o+Zh,hģ>UUb..*B+/rC+_|*C*.OUbh,AUb,bb*a|ObC+UO.bU>u ~.bZr*h>A.ܣvbohA>bBrZvC,o<~vu:a~*>@êv*CBbU~U,+uuZ.Ov ZvCuOC@:+@a_* ha+@b>Z~h|/:Z~OO*a@.rAB*B*+..rz.~|OZhCbb/zr,*oz.O/br/@boB*>aObovUoaOhCB>B*|v|U Z_Oa_Ob_+A@./Z U~:.CrOOrh.ubhbC<,,U/>a,a,Ub.>o/v:êC>UZrC| ob_boBuOO,ovZr~|*uuA_C@_hCU.<ܩ/@~<.hvh~@+UZOv:bZ~ba /Ub.b_./aZa|_<_<:oh~zZrr:ab+_zAZ@au.b>z*a.ba*>bUAz_*zr:Abov u,,:bhA|Z,A֣_b@ |Uh|U.zz >o|~ uOv/:U__*Z/Zz~b_b,oB,zu|aAb@@ ,UUBu+__+z,@,@uA_obZho+ ~ @:zbb@:~C+.,Щv zuAZZ*>,: h~vvr.ra@Abh:|au@.B.@@*u:b<*+r@CܢUUb/brC>|,AOOuCh.huUzܢvZvO~Z/hh/.hv:hbA>_|@ vZ>CO~~ B.| >Uz/zĢ/|~@a|z:a.Ba*bOC/OaBa:zv /_A.uuA vo<. ro|bh:o:|.*zz~h:| ,@brov~OChb>bvb>bv,a/*@|Bh+au*v||br.o|o//z:b*/rv:hb~.:az**hOoB+hoOCZabh_ho+.C@b.U>b<_*u* rrr|:Czb_CZB .AZ/A|r֣|bChB_ ,âUAB_OOb/r|aAZ/ZA_|AbOv~zO>|.u@/@*b,âab*.Z>|_A*/OZO+BЩ>aߢ:.|, .Уa|uߣߣ<@|O+A_@_.AvU.OA..Bߣ>hOZCBCABzU*z>*âh/BBCC *u_bU*+ OhC@<:zO_orr_uOZ,a.//*vߣC+aO,C*/B@ CbAZ*bu.|z@vu .@B|ba::/zh*.bb~Zuhvbz*UC_ov:azê_C+@/ :,hC@~b.bvz@_r>/._/u/OA_r:barhUhoO*bvZhOuA.vb:@+/~ZO~h:v>:_rv*@bv,va@b/, Z~u*CU :Ab壪@C~ua/BhߩzUzh BbZz /oU>,b,BO_+*uu *,B_aZ,~/vv|hv@o,>hz_,rza>>/b/,/UvUOC>_CB:CbUao~ :+getMessage() . PHP_EOL; + } + + try { + sqlsrv_close($conn1); + } catch (TypeError $e) { + echo $e->getMessage() . PHP_EOL; + } $stmt14 = sqlsrv_query($conn2, "DROP TABLE [PHPTable]"); sqlsrv_free_stmt($stmt14); sqlsrv_close($conn2); ?> ---EXPECTREGEX-- -Warning: sqlsrv_query\(\): supplied resource is not a valid ss_sqlsrv_conn resource in .*sqlsrv_close\.php on line [0-9]+ - -Warning: sqlsrv_close\(\): supplied resource is not a valid ss_sqlsrv_conn resource in .*sqlsrv_close\.php on line [0-9]+ +--EXPECT-- +sqlsrv_query(): supplied resource is not a valid ss_sqlsrv_conn resource +sqlsrv_close(): supplied resource is not a valid ss_sqlsrv_conn resource diff --git a/test/functional/sqlsrv/sqlsrv_close_twice.phpt b/test/functional/sqlsrv/sqlsrv_close_twice.phpt index c0201704a..4eee2a77d 100644 --- a/test/functional/sqlsrv/sqlsrv_close_twice.phpt +++ b/test/functional/sqlsrv/sqlsrv_close_twice.phpt @@ -3,6 +3,14 @@ Free statement twice --FILE-- getMessage() . PHP_EOL; } catch (Exception $e) { - echo $e->getMessage(); + echo $e->getMessage() . PHP_EOL; } echo "\nDone\n"; endTest("sqlsrv_close_twice"); @@ -45,9 +55,8 @@ function Repro() Repro(); ?> ---EXPECTREGEX-- - -Warning: sqlsrv_free_stmt\(\): supplied resource is not a valid ss_sqlsrv_stmt resource in .+sqlsrv_close_twice.php on line [0-9]+ +--EXPECT-- +sqlsrv_free_stmt(): supplied resource is not a valid ss_sqlsrv_stmt resource Done Test "sqlsrv_close_twice" completed successfully. diff --git a/test/functional/sqlsrv/sqlsrv_configure.phpt b/test/functional/sqlsrv/sqlsrv_configure.phpt index f6849c380..5cb297b28 100644 --- a/test/functional/sqlsrv/sqlsrv_configure.phpt +++ b/test/functional/sqlsrv/sqlsrv_configure.phpt @@ -4,17 +4,29 @@ sqlsrv_configure. --FILE-- getMessage() . PHP_EOL; + } + // warnings_return_as_errors the only supported option $result = sqlsrv_configure("blahblahblah", 1); if ($result) { @@ -135,10 +147,10 @@ sqlsrv_configure. ?> --EXPECTREGEX-- -Warning: sqlsrv_configure\(\) expects exactly 2 parameters, 1 given in .+(\/|\\)sqlsrv_configure\.php on line [0-9]+ +sqlsrv_configure\(\) expects exactly 2 (parameters|arguments), 1 given Array \( - \[0\] => Array + \[0] => Array \( \[0\] => IMSSP \[SQLSTATE\] => IMSSP diff --git a/test/functional/sqlsrv/sqlsrv_data_classification_ranks.phpt b/test/functional/sqlsrv/sqlsrv_data_classification_ranks.phpt new file mode 100644 index 000000000..c79f302b1 --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_data_classification_ranks.phpt @@ -0,0 +1,347 @@ +--TEST-- +Test data classification feature - retrieving sensitivity metadata if supported +--DESCRIPTION-- +If both ODBC and server support this feature, this test verifies that sensitivity metadata can be added and correctly retrieved. If not, it will at least test the new statement attribute and some error cases. +T-SQL reference: https://docs.microsoft.com/sql/t-sql/statements/add-sensitivity-classification-transact-sql +--ENV-- +PHPT_EXEC=true +--SKIPIF-- + +--FILE-- + "NONE", 10 => "LOW", 20 => "MEDIUM", 30 => "HIGH", 40 => "CRITICAL"); + +function testErrorCases($conn, $tableName, $isSupported, $driverCapable) +{ + // This function will check two error cases: + // (1) if supported, the query should return a column with no classification + $options = array('DataClassification' => true); + $tsql = ($isSupported)? "SELECT PatientId FROM $tableName" : "SELECT * FROM $tableName"; + $stmt = sqlsrv_query($conn, $tsql, array(), $options); + if (!$stmt) { + fatalError("testErrorCases (1): failed with sqlsrv_query '$tsql'.\n"); + } + + $notAvailableErr = '*Failed to retrieve Data Classification Sensitivity Metadata. If the driver and the server both support the Data Classification feature, check whether the query returns columns with classification information.'; + + $unexpectedErrorState = '*Failed to retrieve Data Classification Sensitivity Metadata: Check if ODBC driver or the server supports the Data Classification feature.'; + + $error = ($driverCapable) ? $notAvailableErr : $unexpectedErrorState; + + $metadata = sqlsrv_field_metadata($stmt); + if ($metadata) { + echo "testErrorCases (1): expected sqlsrv_field_metadata to fail\n"; + } + + if (!fnmatch($error, sqlsrv_errors()[0]['message'])) { + var_dump(sqlsrv_errors()); + } + + // (2) call sqlsrv_prepare() with DataClassification but do not execute the stmt + $stmt = sqlsrv_prepare($conn, $tsql, array(), $options); + if (!$stmt) { + fatalError("testErrorCases (2): failed with sqlsrv_prepare '$tsql'.\n"); + } + + $executeFirstErr = '*The statement must be executed to retrieve Data Classification Sensitivity Metadata.'; + $metadata = sqlsrv_field_metadata($stmt); + if ($metadata) { + echo "testErrorCases (2): expected sqlsrv_field_metadata to fail\n"; + } + + if (!fnmatch($executeFirstErr, sqlsrv_errors()[0]['message'])) { + var_dump(sqlsrv_errors()); + } +} + +function isDataClassSupported($conn, &$driverCapable) +{ + // Check both SQL Server version and ODBC driver version + $msodbcsqlVer = sqlsrv_client_info($conn)['DriverVer']; + $version = explode(".", $msodbcsqlVer); + + // ODBC Driver must be 17.2 or above + $driverCapable = true; + if ($version[0] < 17 || $version[1] < 2) { + $driverCapable = false; + return false; + } + + // SQL Server must be SQL Server 2019 or above + $serverVer = sqlsrv_server_info($conn)['SQLServerVersion']; + if (explode('.', $serverVer)[0] < 15) { + return false; + } + + return true; +} + +function getRegularMetadata($conn, $tsql) +{ + // Run the query without data classification metadata + $stmt1 = sqlsrv_query($conn, $tsql); + if (!$stmt1) { + fatalError("getRegularMetadata (1): failed in sqlsrv_query.\n"); + } + + // Run the query with the attribute set to false + $options = array('DataClassification' => false); + $stmt2 = sqlsrv_query($conn, $tsql, array(), $options); + if (!$stmt2) { + fatalError("getRegularMetadata (2): failed in sqlsrv_query.\n"); + } + + // The metadata for each statement, column by column, should be identical + $numCol = sqlsrv_num_fields($stmt1); + $metadata1 = sqlsrv_field_metadata($stmt1); + $metadata2 = sqlsrv_field_metadata($stmt2); + + for ($i = 0; $i < $numCol; $i++) { + $diff = array_diff($metadata1[$i], $metadata2[$i]); + if (!empty($diff)) { + print_r($diff); + } + } + + return $stmt1; +} + +function verifyClassInfo($rank, $input, $actual) +{ + // For simplicity of this test, only one set of sensitivity data. Namely, + // an array with one set of Label (name, id) and Information Type (name, id) + // plus overall rank info + if (count($actual) != 2) { + echo "Expected an array with only two elements\n"; + return false; + } + + if (count($actual[0]) != 3) { + echo "Expected a Label pair and Information Type pair plus column rank info\n"; + return false; + } + + // Label should be name and id pair (id should be empty) + if (count($actual[0]['Label']) != 2) { + echo "Expected only two elements for the label\n"; + return false; + } + $label = $input[0]; + if ($actual[0]['Label']['name'] !== $label || !empty($actual[0]['Label']['id'])){ + return false; + } + + // Like Label, Information Type should also be name and id pair (id should be empty) + if (count($actual[0]['Information Type']) != 2) { + echo "Expected only two elements for the information type\n"; + return false; + } + $info = $input[1]; + if ($actual[0]['Information Type']['name'] !== $info || !empty($actual[0]['Information Type']['id'])){ + return false; + } + + if ($actual[0]['rank'] != $rank) { + return false; + } + + if ($actual['rank'] != $rank) { + return false; + } + + return true; +} + +function assignDataClassification($conn, $tableName, $classData, $rankId = 0) +{ + global $ranks; + + $rank = ", RANK = $ranks[$rankId]"; + + // column SSN + $label = $classData[1][0]; + $infoType = $classData[1][1]; + $sql = "ADD SENSITIVITY CLASSIFICATION TO [$tableName].SSN WITH (LABEL = '$label', INFORMATION_TYPE = '$infoType' $rank)"; + $stmt = sqlsrv_query($conn, $sql); + if (!$stmt) { + fatalError("SSN: Add sensitivity $label and $infoType failed.\n"); + } + + // column BirthDate + $label = $classData[4][0]; + $infoType = $classData[4][1]; + $sql = "ADD SENSITIVITY CLASSIFICATION TO [$tableName].BirthDate WITH (LABEL = '$label', INFORMATION_TYPE = '$infoType' $rank)"; + $stmt = sqlsrv_query($conn, $sql); + if (!$stmt) { + fatalError("BirthDate: Add sensitivity $label and $infoType failed.\n"); + } +} + +function compareDataClassification($stmt1, $stmt2, $classData, $rank) +{ + global $dataClassKey; + + $numCol = sqlsrv_num_fields($stmt1); + + $metadata1 = sqlsrv_field_metadata($stmt1); + $metadata2 = sqlsrv_field_metadata($stmt2); + + // The built-in array_diff_assoc() function compares the keys and values + // of two (or more) arrays, and returns an array that contains the entries + // from array1 that are not present in array2 or array3, etc. + // + // For this test, $metadata2 should have one extra key 'Data Classification', + // which should not be present in $metadata1 + // + // If the column does not have sensitivity metadata, the value should be an + // empty array. Otherwise, it should contain an array with one set of + // Label (name, id) and Information Type (name, id) + + $noClassInfo = array($dataClassKey => array()); + for ($i = 0; $i < $numCol; $i++) { + $diff = array_diff_assoc($metadata2[$i], $metadata1[$i]); + + // Is classification input data empty? + if (empty($classData[$i])) { + // Then it should be equivalent to $noClassInfo + if ($diff !== $noClassInfo) { + var_dump($diff); + } + } else { + // Verify the classification metadata + if (!verifyClassInfo($rank, $classData[$i], $diff[$dataClassKey])) { + var_dump($diff); + } + } + } +} + +function checkResults($conn, $stmt, $tableName, $classData, $rank = 0) +{ + $tsql = "SELECT * FROM $tableName"; + $options = array('DataClassification' => true); + + $stmt1 = sqlsrv_prepare($conn, $tsql, array(), $options); + if (!$stmt1) { + fatalError("Error when calling sqlsrv_prepare '$tsql'.\n"); + } + if (!sqlsrv_execute($stmt1)) { + fatalError("Error in executing statement.\n"); + } + + compareDataClassification($stmt, $stmt1, $classData, $rank); + sqlsrv_free_stmt($stmt1); + + // $stmt2 should produce the same result as the previous $stmt1 + $stmt2 = sqlsrv_query($conn, $tsql, array(), $options); + if (!$stmt2) { + fatalError("Error when calling sqlsrv_query '$tsql'.\n"); + } + + compareDataClassification($stmt, $stmt2, $classData, $rank); + sqlsrv_free_stmt($stmt2); + + runBatchQuery($conn, $tableName); +} + +function runBatchQuery($conn, $tableName) +{ + global $dataClassKey; + + $options = array('DataClassification' => true); + $tsql = "SELECT SSN, BirthDate FROM $tableName"; + $batchQuery = $tsql . ';' . $tsql; + + $stmt = sqlsrv_query($conn, $batchQuery, array(), $options); + if (!$stmt) { + fatalError("Error when calling sqlsrv_query '$tsql'.\n"); + } + + $numCol = sqlsrv_num_fields($stmt); + $c = rand(0, $numCol - 1); + + $metadata1 = sqlsrv_field_metadata($stmt); + if (!$metadata1 || !array_key_exists($dataClassKey, $metadata1[$c])) { + fatalError("runBatchQuery(1): failed to get metadata"); + } + $result = sqlsrv_next_result($stmt); + if (is_null($result) || !$result) { + fatalError("runBatchQuery: failed to get next result"); + } + $metadata2 = sqlsrv_field_metadata($stmt); + if (!$metadata2 || !array_key_exists($dataClassKey, $metadata2[$c])) { + fatalError("runBatchQuery(2): failed to get metadata"); + } + + $jstr1 = json_encode($metadata1[$c][$dataClassKey]); + $jstr2 = json_encode($metadata2[$c][$dataClassKey]); + if ($jstr1 !== $jstr2) { + echo "The JSON encoded strings should be identical\n"; + var_dump($jstr1); + var_dump($jstr2); + } +} + +/////////////////////////////////////////////////////////////////////////////////////// +require_once('MsCommon.inc'); + +$conn = AE\connect(); +if (!$conn) { + fatalError("Failed to connect.\n"); +} + +$driverCapable = true; +$isSupported = isDataClassSupported($conn, $driverCapable); + +// Create a test table +$tableName = 'srvPatients'; +$colMeta = array(new AE\ColumnMeta('INT', 'PatientId', 'IDENTITY NOT NULL'), + new AE\ColumnMeta('CHAR(11)', 'SSN'), + new AE\ColumnMeta('NVARCHAR(50)', 'FirstName'), + new AE\ColumnMeta('NVARCHAR(50)', 'LastName'), + new AE\ColumnMeta('DATE', 'BirthDate')); +AE\createTable($conn, $tableName, $colMeta); + +// If data classification is supported, then add sensitivity classification metadata +// to columns SSN and Birthdate +$classData = [ + array(), + array('Highly Confidential - GDPR', 'Credentials'), + array(), + array(), + array('Confidential Personal Data', 'Birthdays') + ]; + +if ($isSupported) { + assignDataClassification($conn, $tableName, $classData); +} + +testErrorCases($conn, $tableName, $isSupported, $driverCapable); + +// Run the query without data classification metadata +$tsql = "SELECT * FROM $tableName"; +$stmt = getRegularMetadata($conn, $tsql); + +// Proceeed to retrieve sensitivity metadata, if supported +if ($isSupported) { + checkResults($conn, $stmt, $tableName, $classData); + + // Test another rank (get a random one) + $random = rand(1, 4); + $rank = $random * 10; + + trace("Testing with $rank\n"); + assignDataClassification($conn, $tableName, $classData, $rank); + checkResults($conn, $stmt, $tableName, $classData, $rank); +} + +sqlsrv_free_stmt($stmt); + +dropTable($conn, $tableName); +sqlsrv_close($conn); + +echo "Done\n"; +?> +--EXPECT-- +Done diff --git a/test/functional/sqlsrv/sqlsrv_errors.phpt b/test/functional/sqlsrv/sqlsrv_errors.phpt index fe70816a8..7122a2842 100644 --- a/test/functional/sqlsrv/sqlsrv_errors.phpt +++ b/test/functional/sqlsrv/sqlsrv_errors.phpt @@ -8,19 +8,44 @@ sqlsrv_close returns true even if an error happens. --FILE-- getMessage())) { + echo $err->getMessage() . PHP_EOL; + } + } + + set_error_handler("warningHandler", E_WARNING); + sqlsrv_configure('WarningsReturnAsErrors', 0); sqlsrv_configure('LogSeverity', SQLSRV_LOG_SEVERITY_ALL); require('MsCommon.inc'); $conn = sqlsrv_connect("InvalidServerName", array( "Database" => "test" )); - $result = sqlsrv_close($conn); - $errors = sqlsrv_errors(); - if ($result !== false) { - die("sqlsrv_close succeeded despite an invalid server name."); + try { + $result = sqlsrv_close($conn); + if ($result !== false) { + die("sqlsrv_close succeeded despite an invalid server name."); + } + } catch (TypeError $e) { + compareMessages($e, + "sqlsrv_close(): Argument #1 (\$conn) must be of type resource, bool given", + "sqlsrv_close() expects parameter 1 to be resource, bool* given"); } - print_r($errors); + $errors = sqlsrv_errors(); + print_r($errors); + $conn = AE\connect(); $tableName = 'test_params'; $columns = array(new AE\ColumnMeta('tinyint', 'id'), @@ -72,28 +97,52 @@ sqlsrv_close returns true even if an error happens. sqlsrv_free_stmt($stmt); die("sqlsrv_send_stream_data failed."); } - $result = sqlsrv_free_stmt($stmt); if ($result === false) { die(print_r(sqlsrv_errors(), true)); } - $result = sqlsrv_free_stmt($stmt); - if ($result === false) { - die(print_r(sqlsrv_errors(), true)); + try { + $result = sqlsrv_free_stmt($stmt); + if ($result === false) { + die(print_r(sqlsrv_errors(), true)); + } + } catch (TypeError $e) { + echo $e->getMessage() . PHP_EOL; + } + + try { + $result = sqlsrv_free_stmt(null); + if ($result === false) { + die(print_r(sqlsrv_errors(), true)); + } + } catch (TypeError $e) { + compareMessages($e, + "sqlsrv_free_stmt(): Argument #1 (\$stmt) must be of type resource, null given", + "sqlsrv_free_stmt() expects parameter 1 to be resource, null given"); } - $result = sqlsrv_free_stmt(null); - if ($result === false) { - die(print_r(sqlsrv_errors(), true)); - } - $result = sqlsrv_free_stmt($conn); - if ($result !== false) { - die("sqlsrv_free_stmt shouldn't have freed the connection resource"); + + try { + $result = sqlsrv_free_stmt($conn); + if ($result !== false) { + die("sqlsrv_free_stmt shouldn't have freed the connection resource"); + } + } catch (TypeError $e) { + echo $e->getMessage() . PHP_EOL; } + print_r(sqlsrv_errors()); - $result = sqlsrv_free_stmt(1); - if ($result !== false) { - die("sqlsrv_free_stmt shouldn't have freed a 1"); + + try { + $result = sqlsrv_free_stmt(1); + if ($result !== false) { + die("sqlsrv_free_stmt shouldn't have freed a 1"); + } + } catch (TypeError $e) { + compareMessages($e, + "sqlsrv_free_stmt(): Argument #1 (\$stmt) must be of type resource, int given", + "sqlsrv_free_stmt() expects parameter 1 to be resource, int* given"); } + print_r(sqlsrv_errors()); dropTable($conn, $tableName); @@ -102,24 +151,43 @@ sqlsrv_close returns true even if an error happens. if ($result === false) { die(print_r(sqlsrv_errors(), true)); } - $result = sqlsrv_close($conn); - if ($result === false) { - die(print_r(sqlsrv_errors(), true)); + + try { + $result = sqlsrv_close($conn); + if ($result === false) { + die(print_r(sqlsrv_errors(), true)); + } + } catch (TypeError $e) { + echo $e->getMessage() . PHP_EOL; } - $result = sqlsrv_close(null); - if ($result === false) { - die(print_r(sqlsrv_errors(), true)); + + try { + $result = sqlsrv_close(null); + if ($result === false) { + die(print_r(sqlsrv_errors(), true)); + } + } catch (TypeError $e) { + compareMessages($e, + "sqlsrv_close(): Argument #1 (\$conn) must be of type resource, null given", + "sqlsrv_close() expects parameter 1 to be resource, null given"); } - $result = sqlsrv_close(1); - if ($result !== false) { - die("sqlsrv_close shouldn't have freed a 1"); + + try { + $result = sqlsrv_close(1); + if ($result !== false) { + die("sqlsrv_close shouldn't have freed a 1"); + } + } catch (TypeError $e) { + compareMessages($e, + "sqlsrv_close(): Argument #1 (\$conn) must be of type resource, int given", + "sqlsrv_close() expects parameter 1 to be resource, int* given"); } + print_r(sqlsrv_errors()); echo "Test successfully done.\n"; ?> ---EXPECTF-- -Warning: sqlsrv_close() expects parameter 1 to be resource, bool%S given in %Ssqlsrv_errors.php on line %x +--EXPECT-- Array ( [0] => Array @@ -133,12 +201,8 @@ Array ) ) - -Warning: sqlsrv_free_stmt(): supplied resource is not a valid ss_sqlsrv_stmt resource in %Ssqlsrv_errors.php on line %x - -Warning: sqlsrv_free_stmt() expects parameter 1 to be resource, null given in %Ssqlsrv_errors.php on line %x - -Warning: sqlsrv_free_stmt(): supplied resource is not a valid ss_sqlsrv_stmt resource in %Ssqlsrv_errors.php on line %x +sqlsrv_free_stmt(): supplied resource is not a valid ss_sqlsrv_stmt resource +sqlsrv_free_stmt(): supplied resource is not a valid ss_sqlsrv_stmt resource Array ( [0] => Array @@ -152,8 +216,6 @@ Array ) ) - -Warning: sqlsrv_free_stmt() expects parameter 1 to be resource, int%S given in %Ssqlsrv_errors.php on line %x Array ( [0] => Array @@ -167,12 +229,7 @@ Array ) ) - -Warning: sqlsrv_close(): supplied resource is not a valid ss_sqlsrv_conn resource in %Ssqlsrv_errors.php on line %x - -Warning: sqlsrv_close() expects parameter 1 to be resource, null given in %Ssqlsrv_errors.php on line %x - -Warning: sqlsrv_close() expects parameter 1 to be resource, int%S given in %Ssqlsrv_errors.php on line %x +sqlsrv_close(): supplied resource is not a valid ss_sqlsrv_conn resource Array ( [0] => Array diff --git a/test/functional/sqlsrv/sqlsrv_fetch_field_twice_data_types.phpt b/test/functional/sqlsrv/sqlsrv_fetch_field_twice_data_types.phpt index 4719b73dc..32d357bab 100644 --- a/test/functional/sqlsrv/sqlsrv_fetch_field_twice_data_types.phpt +++ b/test/functional/sqlsrv/sqlsrv_fetch_field_twice_data_types.phpt @@ -98,7 +98,7 @@ function Repro() Repro(); ?> ---EXPECT-- +--EXPECTF--  Test begins... string(79) "A statement must be prepared with sqlsrv_prepare before calling sqlsrv_execute." @@ -111,7 +111,7 @@ string(25) "Field 0 returned no data." float(1.09) bool(false) string(25) "Field 1 returned no data." -float(3.4379999637604) +float(3.437999963760%s) bool(false) string(25) "Field 2 returned no data." string(23) "1756-04-16 23:27:09.130" diff --git a/test/functional/sqlsrv/sqlsrv_fetch_object.phpt b/test/functional/sqlsrv/sqlsrv_fetch_object.phpt index c1231745e..857b645b9 100644 --- a/test/functional/sqlsrv/sqlsrv_fetch_object.phpt +++ b/test/functional/sqlsrv/sqlsrv_fetch_object.phpt @@ -223,12 +223,11 @@ else { echo "Past the end of the result set (7)\n"; $obj = sqlsrv_fetch_object( $stmt, "foo" ); if( $obj === false ) { - die( print_r( sqlsrv_errors(), true )); + print_r( sqlsrv_errors()); } if( is_null( $obj )) { echo "Done fetching objects.\n"; -} -else { +} elseif ($obj) { $obj->do_foo(); print_r( $obj ); } diff --git a/test/functional/sqlsrv/sqlsrv_fetch_object_2.phpt b/test/functional/sqlsrv/sqlsrv_fetch_object_2.phpt index 8961fe8cb..11fc5a91e 100644 --- a/test/functional/sqlsrv/sqlsrv_fetch_object_2.phpt +++ b/test/functional/sqlsrv/sqlsrv_fetch_object_2.phpt @@ -227,12 +227,11 @@ else { echo "Past the end of the result set (7)\n"; $obj = sqlsrv_fetch_object( $stmt, "foo" ); if( $obj === false ) { - die( print_r( sqlsrv_errors(), true )); + print_r( sqlsrv_errors()); } if( is_null( $obj )) { echo "Done fetching objects.\n"; -} -else { +} elseif ($obj) { $obj->do_foo(); print_r( $obj ); } diff --git a/test/functional/sqlsrv/sqlsrv_fetch_object_unicode_col_name1.phpt b/test/functional/sqlsrv/sqlsrv_fetch_object_unicode_col_name1.phpt index a6c2cb00c..407e448f6 100644 --- a/test/functional/sqlsrv/sqlsrv_fetch_object_unicode_col_name1.phpt +++ b/test/functional/sqlsrv/sqlsrv_fetch_object_unicode_col_name1.phpt @@ -220,11 +220,11 @@ if (is_null($obj)) { echo "Past the end of the result set (7)\n"; $obj = sqlsrv_fetch_object($stmt, "foo"); if ($obj === false) { - die(print_r(sqlsrv_errors(), true)); + print_r( sqlsrv_errors()); } if (is_null($obj)) { echo "Done fetching objects.\n"; -} else { +} elseif ($obj) { $obj->do_foo(); print_r($obj); } diff --git a/test/functional/sqlsrv/sqlsrv_fetch_object_unicode_col_name2.phpt b/test/functional/sqlsrv/sqlsrv_fetch_object_unicode_col_name2.phpt index 47251aa1c..7f5e6dbbd 100644 --- a/test/functional/sqlsrv/sqlsrv_fetch_object_unicode_col_name2.phpt +++ b/test/functional/sqlsrv/sqlsrv_fetch_object_unicode_col_name2.phpt @@ -24,7 +24,7 @@ class Product return $this->UnitPrice." [CAD]"; } - public function report_output() + public function report_output($dummy) { echo "Object ID: ".$this->objID."\n"; echo "Internal Name: ".$this->name."\n"; @@ -49,11 +49,20 @@ class Sample extends Product return $this->UnitPrice ." [EUR]"; } - public function report_output() + public function report_output($unitPrice) { echo "ID: ".$this->objID."\n"; echo "Name: ".$this->личное_имя."\n"; - echo "Unit Price: ".$this->getPrice()."\n"; + + // Since UnitPrice column is of type FLOAT, + // should not expect the values to match exactly + $epsilon = 0.00001; + $diff = abs(($this->UnitPrice - $unitPrice) / $unitPrice); + + if ($diff > $epsilon) { + echo "Expected $unitPrice [EUR] but got "; + echo "Unit Price: ".$this->getPrice()."\n"; + } } } @@ -74,6 +83,50 @@ function getInputData2($inputs) 'Code'=> $inputs[1]); } +function insertInputsSimple($conn, $tableName, $data) +{ + $sql = "INSERT INTO $tableName VALUES \n"; + for ($i = 0; $i < count($data); $i++) { + $sql .= '('; + for ($j = 0; $j < count($data[$i]); $j++) { + if (is_null($data[$i][$j])) { + $sql .= 'NULL'; + } else { + $sql .= "'" . $data[$i][$j] . "'"; + } + + if ($j < count($data[$i]) - 1) { + $sql .= ","; + } + } + if ($i < count($data) - 1) { + $sql .= "),\n"; + } else { + $sql .= ") \n"; + } + } + + return sqlsrv_query($conn, $sql); +} + +function insertInputsWithSQLTypes($conn, $tableName, $data, $sqlTypes) +{ + $sql = "INSERT INTO $tableName VALUES + (?, ?, ?, ?, ?, ?, ?), + (?, ?, ?, ?, ?, ?, ?), + (?, ?, ?, ?, ?, ?, ?), + (?, ?, ?, ?, ?, ?, ?)"; + + $params = array(); + for ($i = 0; $i < count($data); $i++) { + for ($j = 0; $j < count($data[$i]); $j++) { + $params2 = array($data[$i][$j], null, null, $sqlTypes[$j]); + array_push($params, $params2); + } + } + return sqlsrv_query($conn, $sql, $params); +} + require_once('MsCommon.inc'); $conn = AE\connect(array('CharacterSet'=>'UTF-8')); @@ -90,48 +143,24 @@ $columns = array(new AE\ColumnMeta('CHAR(4)', 'ID'), new AE\ColumnMeta('VARCHAR(20)', 'Color')); AE\createTable($conn, $tableName1, $columns); -// Insert data +// Input data for $tableName1 +$data = array(array('P001', 'Pencil 2B', '102', '24', '0.24', '2016-02-01', 'Red'), + array('P002', 'Notepad', '102', '12', '3.87', '2016-02-21', Null), + array('P001', 'Mirror 2\"', '652', '3', '15.99', '2016-02-01', NULL), + array('P003', 'USB connector', '1652', '31', '9.99', '2016-02-01', NULL)); + +$sqlTypes = array(SQLSRV_SQLTYPE_CHAR(4), + SQLSRV_SQLTYPE_VARCHAR(128), + SQLSRV_SQLTYPE_SMALLINT, + SQLSRV_SQLTYPE_INT, + SQLSRV_SQLTYPE_FLOAT, + SQLSRV_SQLTYPE_DATETIME, + SQLSRV_SQLTYPE_VARCHAR(20)); + if (AE\isColEncrypted()) { - $sql = "INSERT INTO $tableName1 VALUES - (?, ?, ?, ?, ?, ?, ?), - (?, ?, ?, ?, ?, ?, ?), - (?, ?, ?, ?, ?, ?, ?), - (?, ?, ?, ?, ?, ?, ?)"; - $stmt = sqlsrv_query($conn, $sql, array(array('P001', null, null, SQLSRV_SQLTYPE_CHAR(4)), - array('Pencil 2B', null, null, SQLSRV_SQLTYPE_VARCHAR(128)), - array('102', null, null, SQLSRV_SQLTYPE_SMALLINT), - array('24', null, null, SQLSRV_SQLTYPE_INT), - array('0.24', null, null, SQLSRV_SQLTYPE_FLOAT), - array('2016-02-01', null, null, SQLSRV_SQLTYPE_DATETIME), - array('Red', null, null, SQLSRV_SQLTYPE_VARCHAR(20)), - array('P002', null, null, SQLSRV_SQLTYPE_CHAR(4)), - array('Notepad', null, null, SQLSRV_SQLTYPE_VARCHAR(128)), - array('102', null, null, SQLSRV_SQLTYPE_SMALLINT), - array('12', null, null, SQLSRV_SQLTYPE_INT), - array('3.87', null, null, SQLSRV_SQLTYPE_FLOAT), - array('2016-02-21', null, null, SQLSRV_SQLTYPE_DATETIME), - array(null, null, null, SQLSRV_SQLTYPE_VARCHAR(20)), - array('P001', null, null, SQLSRV_SQLTYPE_CHAR(4)), - array('Mirror 2\"', null, null, SQLSRV_SQLTYPE_VARCHAR(128)), - array('652', null, null, SQLSRV_SQLTYPE_SMALLINT), - array('3', null, null, SQLSRV_SQLTYPE_INT), - array('15.99', null, null, SQLSRV_SQLTYPE_FLOAT), - array('2016-02-01', null, null, SQLSRV_SQLTYPE_DATETIME), - array(null, null, null, SQLSRV_SQLTYPE_VARCHAR(20)), - array('P003', null, null, SQLSRV_SQLTYPE_CHAR(4)), - array('USB connector', null, null, SQLSRV_SQLTYPE_VARCHAR(128)), - array('1652', null, null, SQLSRV_SQLTYPE_SMALLINT), - array('31', null, null, SQLSRV_SQLTYPE_INT), - array('9.99', null, null, SQLSRV_SQLTYPE_FLOAT), - array('2016-02-01', null, null, SQLSRV_SQLTYPE_DATETIME), - array(null, null, null, SQLSRV_SQLTYPE_VARCHAR(20)))); + $stmt = insertInputsWithSQLTypes($conn, $tableName1, $data, $sqlTypes); } else { - $sql = "INSERT INTO $tableName1 VALUES - ('P001', 'Pencil 2B', '102', '24', '0.24', '2016-02-01', 'Red'), - ('P002', 'Notepad', '102', '12', '3.87', '2016-02-21', Null), - ('P001', 'Mirror 2\"', '652', '3', '15.99', '2016-02-01', NULL), - ('P003', 'USB connector', '1652', '31', '9.99', '2016-02-01', NULL)"; - $stmt = sqlsrv_query($conn, $sql); + $stmt = insertInputsSimple($conn, $tableName1, $data); } if (!$stmt) { fatalError("Failed to insert test data into $tableName1\n"); @@ -142,7 +171,7 @@ $columns = array(new AE\ColumnMeta('CHAR(4)', 'SerialNumber'), new AE\ColumnMeta('VARCHAR(2)', 'Code')); AE\createTable($conn, $tableName2, $columns); -// Insert data +// Insert data for for $tableName2 if (AE\isColEncrypted()) { $sql = "INSERT INTO $tableName2 VALUES (?, ?), (?, ?), (?, ?)"; $stmt = sqlsrv_query($conn, $sql, array(array('P001', null, null, SQLSRV_SQLTYPE_CHAR(4)), @@ -159,7 +188,7 @@ if (!$stmt) { fatalError("Failed to insert test data into $tableName2\n"); } -// With AE enabled, we cannot do comparisons with encrypted columns +// With AE enabled (without secure enclave), do not do comparisons with encrypted columns // Also, only forward cursor or client buffer is supported if (AE\isColEncrypted()) { $sql = "SELECT личное_имя, SafetyStockLevel, StockedQty, UnitPrice, Color, Code @@ -196,18 +225,19 @@ if (AE\isColEncrypted()) { } } -// Iterate through the result set +// Iterate through the result set - expect only the first and last sets of input $data // $product is an instance of the Product class -$i=0; -$hasNext = true; +$expected = array(getInputData1($data[0]), getInputData1($data[count($data)-1])); +$i = 0; +$hasNext = true; while ($hasNext) { $sample = sqlsrv_fetch_object($stmt, "Sample", array($i+1000), SQLSRV_SCROLL_ABSOLUTE, $i); if (!$sample) { $hasNext = false; } else { - $sample->report_output(); + $sample->report_output($expected[$i]['UnitPrice']); $i++; } } @@ -225,8 +255,6 @@ print "Done"; --EXPECT-- ID: 1000 Name: Pencil 2B -Unit Price: 0.24 [EUR] ID: 1001 Name: USB connector -Unit Price: 9.99 [EUR] Done diff --git a/test/functional/sqlsrv/sqlsrv_input_param_unknown_encoding.phpt b/test/functional/sqlsrv/sqlsrv_input_param_unknown_encoding.phpt index aa796ae99..7a61e7e77 100644 --- a/test/functional/sqlsrv/sqlsrv_input_param_unknown_encoding.phpt +++ b/test/functional/sqlsrv/sqlsrv_input_param_unknown_encoding.phpt @@ -1,10 +1,35 @@ --TEST-- test input param with unknown encoding +--DESCRIPTION-- +When running this test with PHP 7.x, PHP warnings like the one below are expected + "Warning: Use of undefined constant SQLSRV_ENC_UNKNOWN - assumed 'SQLSRV_ENC_UNKNOWN' + (this will throw an Error in a future version of PHP)" +When running this test with PHP 8.0, the previous warnings are now errors directly from PHP +Because PHP warnings are intercepted, no need to check sqlsrv errors for those. +Add a new test case to check the error message 'An invalid PHP type for parameter 2 was specified.' --SKIPIF-- --FILE-- getMessage() !== $expected) { + echo $err->getMessage() . PHP_EOL; + } +} + set_time_limit(0); sqlsrv_configure('WarningsReturnAsErrors', 0); sqlsrv_configure('LogSeverity', SQLSRV_LOG_SEVERITY_ALL); @@ -13,7 +38,7 @@ sqlsrv_configure('LogSubsystems', SQLSRV_LOG_SYSTEM_OFF); require_once('MsCommon.inc'); $conn = AE\connect(); -$tableName = 'php_table_SERIL1_1'; +$tableName = 'table_unknown_encoding'; $columns = array(new AE\ColumnMeta('int', 'c1_int'), new AE\ColumnMeta('varchar(max)', 'c2_varchar_max')); $stmt = AE\createTable($conn, $tableName, $columns); @@ -21,37 +46,38 @@ if (!$stmt) { fatalError("Failed to create table $tableName\n"); } -$errState = 'IMSSP'; -$errMessage = 'An invalid PHP type for parameter 2 was specified.'; - -$intType = AE\isColEncrypted() ? SQLSRV_SQLTYPE_INT : null; -$stmt = sqlsrv_query($conn, "INSERT INTO [php_table_SERIL1_1] (c1_int, c2_varchar_max) VALUES (?, ?)", array(array(1, null, null, $intType), - array("Test Data", SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_UNKNOWN), null))); -if ($stmt !== false) { - sqlsrv_free_stmt($stmt); - die("sqlsrv_query shouldn't have succeeded."); +try { + $intType = AE\isColEncrypted() ? SQLSRV_SQLTYPE_INT : null; + $stmt = sqlsrv_query($conn, "INSERT INTO $tableName (c1_int, c2_varchar_max) VALUES (?, ?)", array(array(1, null, null, $intType), + array("Test Data", SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_UNKNOWN), null))); + if ($stmt !== false) { + sqlsrv_free_stmt($stmt); + die("sqlsrv_query shouldn't have succeeded."); + } +} catch (Error $err) { + compareMessages($err); } -verifyError(sqlsrv_errors()[0], $errState, $errMessage); - -$stmt = sqlsrv_prepare($conn, "INSERT INTO [php_table_SERIL1_1] (c1_int, c2_varchar_max) VALUES (?, ?)", array(1, array("Test Data", SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_UNKNOWN), null))); -if ($stmt === false) { - die(print_r(sqlsrv_errors(), true)); -} -$result = sqlsrv_execute($stmt); -if ($result !== false) { - sqlsrv_free_stmt($stmt); - die("sqlsrv_execute shouldn't have succeeded."); +try { + $stmt = sqlsrv_prepare($conn, "INSERT INTO $tableName (c1_int, c2_varchar_max) VALUES (?, ?)", array(1, array("Test Data", SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_UNKNOWN), null))); +} catch (Error $err) { + compareMessages($err); } +restore_error_handler(); +$stmt = sqlsrv_query($conn, "INSERT INTO $tableName (c1_int, c2_varchar_max) VALUES (?, ?)", array(array(1, null, null, $intType), + array("Test Data", SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING(SQLSRV_PHPTYPE_INT), null))); + +$errState = 'IMSSP'; +$errMessage = 'An invalid PHP type for parameter 2 was specified.'; verifyError(sqlsrv_errors()[0], $errState, $errMessage); + +echo "Done\n"; -sqlsrv_query($conn, "DROP TABLE [php_table_SERIL1_1]"); +sqlsrv_query($conn, "DROP TABLE $tableName"); sqlsrv_close($conn); ?> ---EXPECTREGEX-- -(Warning|Notice)\: Use of undefined constant SQLSRV_ENC_UNKNOWN - assumed \'SQLSRV_ENC_UNKNOWN\' (\(this will throw an Error in a future version of PHP\) )?in .+(\/|\\)sqlsrv_input_param_unknown_encoding\.php on line 24 - -(Warning|Notice)\: Use of undefined constant SQLSRV_ENC_UNKNOWN - assumed \'SQLSRV_ENC_UNKNOWN\' (\(this will throw an Error in a future version of PHP\) )?in .+(\/|\\)sqlsrv_input_param_unknown_encoding\.php on line 32 +--EXPECT-- +Done \ No newline at end of file diff --git a/test/functional/sqlsrv/sqlsrv_str_streams.phpt b/test/functional/sqlsrv/sqlsrv_str_streams.phpt index 336e00357..4638712c7 100644 --- a/test/functional/sqlsrv/sqlsrv_str_streams.phpt +++ b/test/functional/sqlsrv/sqlsrv_str_streams.phpt @@ -1,7 +1,7 @@ --TEST-- reading different encodings in strings and streams. --SKIPIF-- - + --FILE-- +--FILE-- + $userName, "PWD" => "$userPassword;Driver={SQL Server Native Client 11.0}}" )); + + if (!$conn) { + var_dump(sqlsrv_errors()); + } else { + sqlsrv_close($conn); + die("Shouldn't have opened the connection."); + } + + echo "Test sqlsrv_connect with driver injection (2)\n"; + $conn = sqlsrv_connect( $server, array( "UID" => $userName, "PWD" => "{$userPassword};Driver={SQL Server Native Client 11.0}" )); + + if (!$conn) { + var_dump(sqlsrv_errors()); + } else { + sqlsrv_close($conn); + die("Shouldn't have opened the connection."); + } + + echo "Test sqlsrv_connect with driver injection (3)\n"; + $conn = sqlsrv_connect( $server, array( "UID" => "sa", "PWD" => "{$userPassword}};Driver={SQL Server Native Client 11.0}" )); + + if (!$conn) { + var_dump(sqlsrv_errors()); + } else { + sqlsrv_close($conn); + die("Shouldn't have opened the connection."); + } + + // Test a bunch of options. The Failover_Partner keyword does not work + // on Unix, so we replace it with MultiSubnetFailover instead. + $conn_options_all = array( "APP" => "PHP Unit Test", + "ConnectionPooling" => true, + "Database" => $databaseName, + "Encrypt" => 0, + "LoginTimeout" => 120, + "MultipleActiveResultSets" => false, + "QuotedId" => false, + "TraceOn" => true, + "TraceFile" => "trace.odbc", + "TransactionIsolation" => SQLSRV_TXN_READ_COMMITTED, + "TrustServerCertificate" => 1, + "WSID" => "JAYKINT1" ); + $conn_options_int = array( "APP" => "PHP Unit Test", + "ConnectionPooling" => false, + "Database" => $databaseName, + "Encrypt" => 0, + "LoginTimeout" => 120, + "MultipleActiveResultSets" => false, + "QuotedId" => true, + "TraceOn" => true, + "TraceFile" => "trace.odbc", + "TransactionIsolation" => SQLSRV_TXN_READ_COMMITTED, + "TrustServerCertificate" => 1, + "WSID" => "JAYKINT1" ); + + echo "Test sqlsrv_connect with all options\n"; + $conn_options_all['MultiSubnetFailover'] = true; + $conn = connect($conn_options_all); + print_r(sqlsrv_errors()[0]); + print_r(sqlsrv_errors()[1]); + if ($conn === false) { + die(print_r(sqlsrv_errors(), true)); + } + + echo "Test sqlsrv_connect with all options and integrated auth\n"; + $conn_options_int['MultiSubnetFailover'] = true; + $conn = connect($conn_options_int); + print_r(sqlsrv_errors()[0]); + print_r(sqlsrv_errors()[1]); + if ($conn === false) { + die(print_r(sqlsrv_errors(), true)); + } + + sqlsrv_close($conn); + echo "Test succeeded.\n"; +?> +--EXPECTREGEX-- +Test sqlsrv_connect with driver injection +array\(1\) \{ + \[0\]=> + array\(6\) \{ + \[0\]=> + string\(5\) "28000" + \["SQLSTATE"\]=> + string\(5\) "28000" + \[1\]=> + int\(18456\) + \["code"\]=> + int\(18456\) + \[2\]=> + string\(81\) ".*Login failed for user 'sa'." + \["message"\]=> + string\(81\) ".*Login failed for user 'sa'." + \} +\} +Test sqlsrv_connect with driver injection \(2\) +array\(1\) \{ + \[0\]=> + array\(6\) \{ + \[0\]=> + string\(5\) "IMSSP" + \["SQLSTATE"\]=> + string\(5\) "IMSSP" + \[1\]=> + int\(-4\) + \["code"\]=> + int\(-4\) + \[2\]=> + string\(140\) "An unescaped right brace \(\}\) was found in either the user name or password. All right braces must be escaped with another right brace \(\}\}\)." + \["message"\]=> + string\(140\) "An unescaped right brace \(\}\) was found in either the user name or password. All right braces must be escaped with another right brace \(\}\}\)." + \} +\} +Test sqlsrv_connect with driver injection \(3\) +array\(1\) \{ + \[0\]=> + array\(6\) \{ + \[0\]=> + string\(5\) "IMSSP" + \["SQLSTATE"\]=> + string\(5\) "IMSSP" + \[1\]=> + int\(-4\) + \["code"\]=> + int\(-4\) + \[2\]=> + string\(140\) "An unescaped right brace \(\}\) was found in either the user name or password. All right braces must be escaped with another right brace \(\}\}\)." + \["message"\]=> + string\(140\) "An unescaped right brace \(\}\) was found in either the user name or password. All right braces must be escaped with another right brace \(\}\}\)." + \} +\} +Test sqlsrv_connect with all options +Array +\( + \[0\] => 01000 + \[SQLSTATE\] => 01000 + \[1\] => 5701 + \[code\] => 5701 + \[2\] => .*Changed database context to '.*'. + \[message\] => .*Changed database context to '.*'. +\) +Array +\( + \[0\] => 01000 + \[SQLSTATE\] => 01000 + \[1\] => 5703 + \[code\] => 5703 + \[2\] => .*Changed language setting to us_english. + \[message\] => .*Changed language setting to us_english. +\) +Test sqlsrv_connect with all options and integrated auth +Array +\( + \[0\] => 01000 + \[SQLSTATE\] => 01000 + \[1\] => 5701 + \[code\] => 5701 + \[2\] => .*Changed database context to '.*'. + \[message\] => .*Changed database context to '.*'. +\) +Array +\( + \[0\] => 01000 + \[SQLSTATE\] => 01000 + \[1\] => 5703 + \[code\] => 5703 + \[2\] => .*Changed language setting to us_english. + \[message\] => .*Changed language setting to us_english. +\) +Test succeeded. diff --git a/test/functional/sqlsrv/sqlsrv_test_gb18030.php b/test/functional/sqlsrv/sqlsrv_test_gb18030.php new file mode 100644 index 000000000..10c125f6b --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_test_gb18030.php @@ -0,0 +1,67 @@ +$tempDB, "UID"=>$userName, "PWD"=>$userPassword); +$conn = sqlsrv_connect($server, $options); +if( $conn === false ) { + die( print_r( sqlsrv_errors(), true )); +} + +$tsql = "CREATE TABLE test1([id] int identity, [name] [varchar](50) NULL)"; +$stmt = sqlsrv_query($conn, $tsql); + +// Next, insert the strings +$inputs = array('', '', 'δҵϢ', 'ȡ'); +$hexValues = array('d6d0cec4', 'c4e3bac3', 'ceb4d5d2b5bdd0c5cfa2', 'bbf1c8a1b8fcb6e0'); +for ($i = 0; $i < 4; $i++) { + insertText($conn, $inputs[$i], $hexValues[$i]); +} + +// Next, fetch the strings +$tsql = "SELECT * FROM test1"; +$stmt = sqlsrv_query($conn, $tsql); +if ($stmt === false) { + var_dump(sqlsrv_errors()); +} + +$i = 0; +while (sqlsrv_fetch($stmt)) { + $name = sqlsrv_get_field($stmt, 1); + if ($name !== $inputs[$i]) { + echo "Expected $inputs[$i] but got $name" . PHP_EOL; + } + $i++; +} + +$tsql = "DROP TABLE test1"; +sqlsrv_query($conn, $tsql); + +sqlsrv_free_stmt($stmt); +sqlsrv_close($conn); + +echo "Done"; + +?> + diff --git a/test/functional/sqlsrv/sqlsrv_test_passwords_with_braces.phpt b/test/functional/sqlsrv/sqlsrv_test_passwords_with_braces.phpt new file mode 100644 index 000000000..50a85c9ef --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_test_passwords_with_braces.phpt @@ -0,0 +1,75 @@ +--TEST-- +Test passwords with non alphanumeric characters and braces +--DESCRIPTION-- +The first two cases should fail with a message about login failures. Only the last case fails because the right curly brace was not escaped with another right brace. +--ENV-- +PHPT_EXEC=true +--SKIPIF-- + +--FILE-- + $userName, "pwd" => $randomPwd)); +checkErrorMessages($conn, 'Password without right braces', $randomPwd); + +$randomPwd = generateRandomPassword(); +trace($randomPwd . PHP_EOL); +$conn = sqlsrv_connect($server, array("UID" => $userName, "pwd" => $randomPwd)); +checkErrorMessages($conn, 'Password with right braces', $randomPwd); + +$randomPwd = generateRandomPassword(true, false); +trace($randomPwd . PHP_EOL); +$conn = sqlsrv_connect($server, array("UID" => $userName, "pwd" => $randomPwd)); +if ($conn) { + echo ("Shouldn't have connected without escaping braces!" . PHP_EOL); +} +$errors = sqlsrv_errors(); +echo $errors[0]["message"] . PHP_EOL; + +echo "Done" . PHP_EOL; +?> +--EXPECT-- +An unescaped right brace (}) was found in either the user name or password. All right braces must be escaped with another right brace (}}). +Done \ No newline at end of file diff --git a/test/functional/sqlsrv/srv_007_login_timeout.phpt b/test/functional/sqlsrv/srv_007_login_timeout.phpt index 8145c370f..8112394b9 100644 --- a/test/functional/sqlsrv/srv_007_login_timeout.phpt +++ b/test/functional/sqlsrv/srv_007_login_timeout.phpt @@ -1,14 +1,18 @@ --TEST-- False connection with LoginTimeout option --DESCRIPTION-- -Intentionally provide an invalid server name and set LoginTimeout. Verify the time elapsed. +Intentionally provide an invalid server and set LoginTimeout. Verify the time elapsed. +The difference in time elapsed is platform dependent. In some Linux distros, extra delay +may be caused by the attempts to resolve non-existent hostnames. Already set leeway to 2 +seconds to allow some room of such errors, but this test remains fragile, especially +outside Windows. Thus, use an invalid IP address instead when running in any non-Windows platform. --SKIPIF-- --FILE-- --FILE-- --FILE-- +--FILE-- + + +--EXPECT-- +float(0) +NULL +int(0) +NULL +NULL +Done diff --git a/test/functional/sqlsrv/srv_053_mars_disabled_error_checks.phpt b/test/functional/sqlsrv/srv_053_mars_disabled_error_checks.phpt index d80a1ad97..1d060d834 100644 --- a/test/functional/sqlsrv/srv_053_mars_disabled_error_checks.phpt +++ b/test/functional/sqlsrv/srv_053_mars_disabled_error_checks.phpt @@ -13,20 +13,22 @@ if (!$conn) { } // Query -$stmt1 = sqlsrv_query($conn, "SELECT 'ONE'") ?: die(print_r(sqlsrv_errors(), true)); +$stmt1 = sqlsrv_query($conn, "SELECT 'ONE'"); +if (!$stmt1) { + print_r(sqlsrv_errors()); +} sqlsrv_fetch($stmt1); // Query. Returns if multiple result sets are disabled -$stmt2 = sqlsrv_query($conn, "SELECT 'TWO'") ?: die(print_r(sqlsrv_errors(), true)); -sqlsrv_fetch($stmt2); - -// Print the data -$res = [ sqlsrv_get_field($stmt1, 0), sqlsrv_get_field($stmt2, 0) ]; -var_dump($res); +$stmt2 = sqlsrv_query($conn, "SELECT 'TWO'"); +if ($stmt2) { + echo "Expect case 2 to fail\n"; +} else { + print_r(sqlsrv_errors()); +} // Free statement and connection resources sqlsrv_free_stmt($stmt1); -sqlsrv_free_stmt($stmt2); sqlsrv_close($conn); print "Done" @@ -56,3 +58,4 @@ Array \) \) +Done diff --git a/test/functional/sqlsrv/srv_1063_locale_configs.phpt b/test/functional/sqlsrv/srv_1063_locale_configs.phpt index 0f5ea5e95..298057c0c 100644 --- a/test/functional/sqlsrv/srv_1063_locale_configs.phpt +++ b/test/functional/sqlsrv/srv_1063_locale_configs.phpt @@ -34,13 +34,11 @@ pdo_sqlsrv.set_locale_info = 0*** Amount formatted: 10000.99 Friday December -3.14159 **End** **Begin** Amount formatted: $10,000.99 Friday December -3.14159 **End** ***sqlsrv.SetLocaleInfo = 1 @@ -50,13 +48,11 @@ pdo_sqlsrv.set_locale_info = 1*** Amount formatted: 10000.99 Friday December -3.14159 **End** **Begin** Amount formatted: 10.000,99 € Freitag Dezember -3,14159 **End** ***sqlsrv.SetLocaleInfo = 2 @@ -66,11 +62,9 @@ pdo_sqlsrv.set_locale_info = 2*** Amount formatted: $10,000.99 Friday December -3.14159 **End** **Begin** Amount formatted: 10.000,99 € Freitag Dezember -3,14159 **End** diff --git a/test/functional/sqlsrv/srv_1063_test_locale.php b/test/functional/sqlsrv/srv_1063_test_locale.php index 06ab387da..2c8eb56db 100644 --- a/test/functional/sqlsrv/srv_1063_test_locale.php +++ b/test/functional/sqlsrv/srv_1063_test_locale.php @@ -37,9 +37,9 @@ function printMoney($amt, $info) echo "**Begin**" . PHP_EOL; -// Assuming LC_ALL is 'en_US.UTF-8', so is LC_CTYPE +// Assuming LC_ALL is 'en_US.UTF-8', so is LC_CTYPE, except in PHP 8 (TODO) // But default LC_MONETARY varies -$ctype = 'en_US.UTF-8'; +$ctype = (PHP_MAJOR_VERSION == 8 && $setLocaleInfo == 0) ? 'C' : 'en_US.UTF-8'; switch ($setLocaleInfo) { case 0: case 1: @@ -60,9 +60,11 @@ function printMoney($amt, $info) $c1 = setlocale(LC_CTYPE, 0); if ($ctype !== $c1) { echo "Unexpected LC_CTYPE: $c1" . PHP_EOL; + echo "LC_NUMERIC for $setLocaleInfo: " . setlocale(LC_NUMERIC, 0) . PHP_EOL; } // Set a different locale, if the input is not empty +$english = true; if (!empty($locale)) { $loc = setlocale(LC_ALL, $locale); if ($loc !== $locale) { @@ -73,6 +75,7 @@ function printMoney($amt, $info) if ($loc === 'de_DE.UTF-8') { $symbol = strtoupper(PHP_OS) === 'LINUX' ? '€' : 'Eu'; $sep = strtoupper(PHP_OS) === 'LINUX' ? '.' : ''; + $english = false; } else { $symbol = '$'; $sep = ','; @@ -121,9 +124,19 @@ function printMoney($amt, $info) fatalError("Failed in running query $sql"); } +// The following change is required for the breaking change introduced in PHP 8 +// https://wiki.php.net/rfc/locale_independent_float_to_string while (sqlsrv_fetch($stmt)) { - $value = sqlsrv_get_field($stmt, 0, SQLSRV_PHPTYPE_FLOAT); - echo $value . PHP_EOL; + $value = sqlsrv_get_field($stmt, 0, SQLSRV_PHPTYPE_FLOAT); + $expected = 3.14159; + if (PHP_MAJOR_VERSION < 8) { + if ($setLocaleInfo > 0 && $english === false) { + $expected = floatval($pi); + } + } + if ($value != $expected) { + echo "Expected: '$expected' but got '$value'\n"; + } } sqlsrv_free_stmt($stmt); diff --git a/test/functional/sqlsrv/srv_699_out_param_integer.phpt b/test/functional/sqlsrv/srv_699_out_param_integer.phpt index 39f195697..5f58dc3da 100644 --- a/test/functional/sqlsrv/srv_699_out_param_integer.phpt +++ b/test/functional/sqlsrv/srv_699_out_param_integer.phpt @@ -65,7 +65,7 @@ if (strtoupper(substr(PHP_OS, 0, 3)) === 'LIN') { $sql_callSP = $set_no_count . "{call $procName(?)}"; -// Initialize the output parameter to any number +// Initialize the output parameter to any positive number $outParam = 1; $params = array(array(&$outParam, SQLSRV_PARAM_OUT)); $stmt = sqlsrv_query($conn, $sql_callSP, $params); @@ -79,6 +79,24 @@ if ($outParam != 123) { echo "The output param value $outParam is unexpected!\n"; } +// Initialize the output parameter to any negative number +$outParam = -1; +$params = array(array(&$outParam, SQLSRV_PARAM_OUT)); +$stmt = sqlsrv_prepare($conn, $sql_callSP, $params); +if (!$stmt) { + fatalError("Error in preparing $procName\n"); +} +$res = sqlsrv_execute($stmt); +if (!$res) { + fatalError("Error in executing $procName\n"); +} + +while ($res = sqlsrv_next_result($stmt)); + +if ($outParam != 123) { + echo "The output param value $outParam is unexpected!\n"; +} + dropTable($conn, $tableName1); dropTable($conn, $tableName2); dropProc($conn, $procName); diff --git a/test/functional/sqlsrv/test_conn_execute.phpt b/test/functional/sqlsrv/test_conn_execute.phpt index 55731ef1d..32cb495d3 100644 --- a/test/functional/sqlsrv/test_conn_execute.phpt +++ b/test/functional/sqlsrv/test_conn_execute.phpt @@ -4,21 +4,42 @@ crash caused by a statement being orphaned when an error occurred during sqlsrv_ --FILE-- getMessage())) { + echo $err->getMessage() . PHP_EOL; + } + } + + set_error_handler("warningHandler", E_WARNING); sqlsrv_configure( 'WarningsReturnAsErrors', 0 ); sqlsrv_configure( 'LogSeverity', SQLSRV_LOG_SEVERITY_ALL ); require( 'MsCommon.inc' ); + try { + $conn1 = Connect(); + $stmt1 = sqlsrv_query($conn1, "SELECT * FROM Servers"); + sqlsrv_close($conn1); + $row1 = sqlsrv_fetch_array($stmt1); + $conn3 = Connect(); + } catch (TypeError $e) { + compareMessages($e, + "sqlsrv_fetch_array(): Argument #1 (\$stmt) must be of type resource, bool given", + "sqlsrv_fetch_array() expects parameter 1 to be resource, bool* given"); + } - $conn1 = Connect(); - $stmt1 = sqlsrv_query($conn1, "SELECT * FROM Servers"); - sqlsrv_close($conn1); - $row1 = sqlsrv_fetch_array($stmt1); - $conn3 = Connect(); - - echo "Test successful\n"; + echo "Done\n"; ?> ---EXPECTREGEX-- -Warning: sqlsrv_fetch_array\(\) expects parameter 1 to be resource, bool(ean){0,1} given in .+(\/|\\)test_conn_execute\.php on line 11 -Test successful +--EXPECT-- +Done diff --git a/test/functional/sqlsrv/test_stream.phpt b/test/functional/sqlsrv/test_stream.phpt index dee4e72e9..1b7312fc9 100644 --- a/test/functional/sqlsrv/test_stream.phpt +++ b/test/functional/sqlsrv/test_stream.phpt @@ -4,6 +4,16 @@ Test for stream zombifying. --FILE-- getMessage() . PHP_EOL; + } + sqlsrv_free_stmt($stmt); sqlsrv_close($conn); ?> ---EXPECTREGEX-- -Warning: fread\(\): supplied resource is not a valid stream resource in .+(\/|\\)test_stream\.php on line [0-9]+ +--EXPECT-- +fread(): supplied resource is not a valid stream resource \ No newline at end of file diff --git a/test/functional/sqlsrv/test_timeout.phpt b/test/functional/sqlsrv/test_timeout.phpt index 195faf63f..28c83ce06 100644 --- a/test/functional/sqlsrv/test_timeout.phpt +++ b/test/functional/sqlsrv/test_timeout.phpt @@ -10,19 +10,23 @@ sqlsrv_configure( 'LogSeverity', SQLSRV_LOG_SEVERITY_ALL ); require( 'MsCommon.inc' ); -$throwaway = Connect(array( 'ConnectionPooling' => 1 )); +// MARS allows applications to have more than one pending request per connection and to have more +// than one active default result set per connection, which is not required for this test. +$options = array('ConnectionPooling' => 1, 'MultipleActiveResultSets' => 0); + +$throwaway = Connect(); if( !$throwaway ) { die( print_r( sqlsrv_errors(), true )); } for( $i = 1; $i <= 3; ++$i ) { - $conn = Connect(array( 'ConnectionPooling' => 1 )); + $conn = Connect($options); if( !$conn ) { die( print_r( sqlsrv_errors(), true )); } - $conn2 = Connect(array( 'ConnectionPooling' => 1 )); + $conn2 = Connect($options); if( !$conn2 ) { die( print_r( sqlsrv_errors(), true )); } @@ -47,7 +51,6 @@ for( $i = 1; $i <= 3; ++$i ) { die( print_r( sqlsrv_errors(), true )); } - $stmt2 = sqlsrv_query( $conn2, "WAITFOR DELAY '00:00:05'; SELECT * FROM [test_query_timeout]", array(null), array( 'QueryTimeout' => 1 )); if( $stmt2 === false ) { print_r( sqlsrv_errors() );