зеркало из https://github.com/microsoft/msphpsql.git
Коммит
ffd8e2113e
110
.travis.yml
110
.travis.yml
|
@ -1,58 +1,52 @@
|
|||
sudo: required
|
||||
|
||||
os: linux
|
||||
dist: trusty
|
||||
|
||||
group: edge
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
env:
|
||||
global:
|
||||
- REPORT_EXIT_STATUS=1
|
||||
- ACCEPT_EULA=Y
|
||||
- PHPSQLDIR=/REPO/msphpsql-dev
|
||||
- TEST_PHP_SQL_SERVER=sql
|
||||
- SQLSRV_DBNAME=msphpsql_sqlsrv
|
||||
- PDOSQLSRV_DBNAME=msphpsql_pdosqlsrv
|
||||
- TEST_PHP_SQL_UID=sa
|
||||
- TEST_PHP_SQL_PWD=Password123
|
||||
|
||||
before_install:
|
||||
- docker pull microsoft/mssql-server-linux:2017-latest
|
||||
|
||||
install:
|
||||
- docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=Password123' -p 1433:1433 --name=$TEST_PHP_SQL_SERVER -d microsoft/mssql-server-linux:2017-latest
|
||||
- docker build --build-arg PHPSQLDIR=$PHPSQLDIR -t msphpsql-dev -f Dockerfile-msphpsql .
|
||||
|
||||
before_script:
|
||||
- sleep 30
|
||||
|
||||
script:
|
||||
- travis_retry docker run -e TRAVIS_JOB_ID -t -d -w $PHPSQLDIR --name=client --link $TEST_PHP_SQL_SERVER msphpsql-dev
|
||||
- docker ps -a
|
||||
- docker logs client
|
||||
- travis_retry docker exec client python ./test/functional/setup/setup_dbs.py -dbname $SQLSRV_DBNAME
|
||||
- travis_retry docker exec client python ./test/functional/setup/setup_dbs.py -dbname $PDOSQLSRV_DBNAME
|
||||
- docker exec client cp ./source/shared/msodbcsql.h ./test/functional/setup/
|
||||
- travis_retry docker exec client python ./test/functional/setup/build_ksp.py
|
||||
- docker exec client cp ./test/functional/setup/myKSP.so ./test/functional/sqlsrv/
|
||||
- docker exec client cp ./test/functional/setup/myKSP.so ./test/functional/pdo_sqlsrv/
|
||||
- travis_retry docker exec client python ./test/functional/setup/run_ksp.py -server $TEST_PHP_SQL_SERVER -dbname $SQLSRV_DBNAME -uid $TEST_PHP_SQL_UID -pwd $TEST_PHP_SQL_PWD
|
||||
- travis_retry docker exec client python ./test/functional/setup/run_ksp.py -server $TEST_PHP_SQL_SERVER -dbname $PDOSQLSRV_DBNAME -uid $TEST_PHP_SQL_UID -pwd $TEST_PHP_SQL_PWD
|
||||
- travis_retry docker exec client php ./source/pdo_sqlsrv/run-tests.php ./test/functional/pdo_sqlsrv/*.phpt
|
||||
- travis_retry docker exec client php ./source/sqlsrv/run-tests.php ./test/functional/sqlsrv/*.phpt
|
||||
- docker exec client bash -c 'for f in ./test/functional/sqlsrv/*.diff; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true'
|
||||
- docker exec client bash -c 'for f in ./test/functional/sqlsrv/*.out; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true'
|
||||
- docker exec client bash -c 'for f in ./test/functional/pdo_sqlsrv/*.diff; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true'
|
||||
- docker exec client bash -c 'for f in ./test/functional/pdo_sqlsrv/*.out; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true'
|
||||
- docker exec client python ./test/functional/setup/cleanup_dbs.py -dbname $SQLSRV_DBNAME
|
||||
- docker exec client python ./test/functional/setup/cleanup_dbs.py -dbname $PDOSQLSRV_DBNAME
|
||||
- docker exec client coveralls -e ./source/shared/ --gcov-options '\-lp'
|
||||
- docker stop client
|
||||
- docker ps -a
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
sudo: required
|
||||
|
||||
os: linux
|
||||
dist: trusty
|
||||
|
||||
group: edge
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
env:
|
||||
global:
|
||||
- REPORT_EXIT_STATUS=1
|
||||
- ACCEPT_EULA=Y
|
||||
- PHPSQLDIR=/REPO/msphpsql-dev
|
||||
- TEST_PHP_SQL_SERVER=sql
|
||||
- SQLSRV_DBNAME=msphpsql_sqlsrv
|
||||
- PDOSQLSRV_DBNAME=msphpsql_pdosqlsrv
|
||||
- TEST_PHP_SQL_UID=sa
|
||||
- TEST_PHP_SQL_PWD=Password123
|
||||
|
||||
before_install:
|
||||
- docker pull microsoft/mssql-server-linux:2017-latest
|
||||
|
||||
install:
|
||||
- docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=Password123' -p 1433:1433 --name=$TEST_PHP_SQL_SERVER -d microsoft/mssql-server-linux:2017-latest
|
||||
- docker build --build-arg PHPSQLDIR=$PHPSQLDIR -t msphpsql-dev -f Dockerfile-msphpsql .
|
||||
|
||||
before_script:
|
||||
- sleep 30
|
||||
|
||||
script:
|
||||
- travis_retry docker run -e TRAVIS_JOB_ID -t -d -w $PHPSQLDIR --name=client --link $TEST_PHP_SQL_SERVER msphpsql-dev
|
||||
- docker ps -a
|
||||
- docker logs client
|
||||
- travis_retry docker exec client python ./test/functional/setup/setup_dbs.py -dbname $SQLSRV_DBNAME
|
||||
- travis_retry docker exec client python ./test/functional/setup/setup_dbs.py -dbname $PDOSQLSRV_DBNAME
|
||||
- travis_retry docker exec client php ./source/pdo_sqlsrv/run-tests.php ./test/functional/pdo_sqlsrv/*.phpt
|
||||
- travis_retry docker exec client php ./source/sqlsrv/run-tests.php ./test/functional/sqlsrv/*.phpt
|
||||
- docker exec client bash -c 'for f in ./test/functional/sqlsrv/*.diff; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true'
|
||||
- docker exec client bash -c 'for f in ./test/functional/sqlsrv/*.out; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true'
|
||||
- docker exec client bash -c 'for f in ./test/functional/pdo_sqlsrv/*.diff; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true'
|
||||
- docker exec client bash -c 'for f in ./test/functional/pdo_sqlsrv/*.out; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true'
|
||||
- docker exec client python ./test/functional/setup/cleanup_dbs.py -dbname $SQLSRV_DBNAME
|
||||
- docker exec client python ./test/functional/setup/cleanup_dbs.py -dbname $PDOSQLSRV_DBNAME
|
||||
- docker exec client coveralls -e ./source/shared/ --gcov-options '\-lp'
|
||||
- docker stop client
|
||||
- docker ps -a
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
|
|
55
CHANGELOG.md
55
CHANGELOG.md
|
@ -3,6 +3,61 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
|
||||
## Windows/Linux/macOS 5.2.0 - 2017-02-14
|
||||
Updated PECL release packages. Here is the list of updates:
|
||||
|
||||
### Added
|
||||
- Added support for Always Encrypted with basic CRUD functionalities (see [here](https://github.com/Microsoft/msphpsql/wiki/Features#aebindparam))
|
||||
- Support for Windows Certificate Store (use connection keyword ColumnEncryption)
|
||||
- Support for inserting into and modifying an encrypted column
|
||||
- Support for fetching from an encrypted column
|
||||
- Added support for PHP 7.2
|
||||
- Added support for MS ODBC Driver 17
|
||||
- Added support for Ubuntu 17 (requires MS ODBC Driver 17)
|
||||
- Added support for Debian 9 (requires MS ODBC Driver 17)
|
||||
- Added support for SUSE 12
|
||||
- Added Driver option to set the MS ODBC driver, Added "Driver" option, valid values are "ODBC Driver 17 for SQL Server", "ODBC Driver 13 for SQL Server", and "ODBC Driver 11 for SQL Server"
|
||||
- The default driver is ODBC Driver 17 for SQL Server
|
||||
|
||||
### Changed
|
||||
- Implementation of PDO::lastInsertId($name) to return the last inserted sequence number if the sequence name is supplied to the function ([lastInsertId](https://github.com/Microsoft/msphpsql/wiki/Features#lastinsertid))
|
||||
|
||||
### Fixed
|
||||
- Issue [#555](https://github.com/Microsoft/msphpsql/issues/555) - Hebrew strings truncation (requires MS ODBC Driver 17)
|
||||
- Adjusted precisions for numeric/decimal inputs with Always Encrypted
|
||||
- Support for non-UTF8 locales in Linux and macOS
|
||||
- Fixed crash caused by executing an invalid query in a transaction (Issue [#434](https://github.com/Microsoft/msphpsql/issues/434))
|
||||
- Added error handling for using PDO::SQLSRV_ATTR_DIRECT_QUERY or PDO::ATTR_EMULATE_PREPARES in a Column Encryption enabled connection
|
||||
- Added error handling for binding TEXT, NTEXT or IMAGE as output parameter (Issue [#231](https://github.com/Microsoft/msphpsql/issues/231))
|
||||
- PDO::quote with string containing ASCII NUL character (Issue [#538]( https://github.com/Microsoft/msphpsql/issues/538))
|
||||
- Decimal types with no decimals are correctly handled when AE is enabled (PR [#544](https://github.com/Microsoft/msphpsql/pull/544))
|
||||
- BIGINT as an output param no longer results in value out of range exception when the returned value is larger than a maximum integer ([PR #567](https://github.com/Microsoft/msphpsql/pull/567))
|
||||
|
||||
### Removed
|
||||
- Dropped support for Ubuntu 15
|
||||
- Supplying tablename into PDO::lastInsertId($name) no longer return the last inserted row ([lastInsertId](https://github.com/Microsoft/msphpsql/wiki/Features#lastinsertid))
|
||||
|
||||
### Limitations
|
||||
- Always Encrypted is not supported in Linux and macOS
|
||||
- In Linux and macOS, setlocale() only takes effect if it is invoked before the first connection. Attempting to set the locale after connection will not work
|
||||
- Always Encrypted functionalities are only supported using MS ODBC Driver 17
|
||||
- [Always Encrypted limitations](https://github.com/Microsoft/msphpsql/wiki/Features#aelimitation)
|
||||
- When using sqlsrv_query with Always Encrypted feature, SQL type has to be specified for each input (see [here](https://github.com/Microsoft/msphpsql/wiki/Features#aebindparam))
|
||||
- No support for inout / output params when using sql_variant type
|
||||
|
||||
### Known Issues
|
||||
- Connection pooling on Linux doesn't work properly when using MS ODBC Driver 17
|
||||
- When pooling is enabled in Linux or macOS
|
||||
- unixODBC <= 2.3.4 (Linux and macOS) might not return proper diagnostics information, such as error messages, warnings and informative messages
|
||||
- due to this unixODBC bug, fetch large data (such as xml, binary) as streams as a workaround. See the examples [here](https://github.com/Microsoft/msphpsql/wiki/Connection-Pooling-on-Linux-and-Mac)
|
||||
- Connection with Connection Resiliency enabled does not resume properly with Connection Pooling (Issue [#678](https://github.com/Microsoft/msphpsql/issues/678))
|
||||
- With ColumnEncryption enabled, calling stored procedure with XML parameter does not work (Issue [#674](https://github.com/Microsoft/msphpsql/issues/674))
|
||||
- Cannot connect with both Connection Resiliency enabled and ColumnEncryption enabled (Issue [#577](https://github.com/Microsoft/msphpsql/issues/577))
|
||||
- With ColumnEncryption enabled, retrieving a negative decimal value as output parameter causes truncation of the last digit (Issue [#705](https://github.com/Microsoft/msphpsql/issues/705))
|
||||
- With ColumnEncryption enabled, cannot insert a double into a decimal column with precision and scale of (38, 38) (Issue [#706](https://github.com/Microsoft/msphpsql/issues/706))
|
||||
- With ColumnEncryption enabled, when fetching decimals as output parameters bound to PDO::PARAM_BOOL or PDO::PARAM_INT, floats are returned, not integers (Issue [#707](https://github.com/Microsoft/msphpsql/issues/707))
|
||||
|
||||
|
||||
## Windows/Linux/macOS 5.2.0-RC - 2017-12-20
|
||||
Updated PECL release packages. Here is the list of updates:
|
||||
|
||||
|
|
|
@ -37,6 +37,13 @@ RUN locale-gen en_US
|
|||
RUN locale-gen en_US.UTF-8
|
||||
ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' LC_ALL='en_US.UTF-8'
|
||||
|
||||
#install ODBC driver
|
||||
RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
|
||||
RUN curl https://packages.microsoft.com/config/ubuntu/16.04/prod.list > /etc/apt/sources.list.d/mssql-release.list
|
||||
|
||||
RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && ACCEPT_EULA=Y apt-get install -y msodbcsql17 mssql-tools
|
||||
ENV PATH="/opt/mssql-tools/bin:${PATH}"
|
||||
|
||||
#install coveralls
|
||||
RUN pip install --upgrade pip && pip install cpp-coveralls
|
||||
|
||||
|
@ -45,18 +52,12 @@ RUN pip install --upgrade pip && pip install cpp-coveralls
|
|||
#another option is to copy source to build directory on image
|
||||
RUN mkdir -p $PHPSQLDIR
|
||||
COPY . $PHPSQLDIR
|
||||
|
||||
#install ODBC 17 preview driver
|
||||
WORKDIR $PHPSQLDIR
|
||||
RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && ACCEPT_EULA=Y dpkg -i "./ODBC 17 binaries preview/Ubuntu 16/msodbcsql_17.0.0.5-1_amd64.deb"
|
||||
RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && ACCEPT_EULA=Y dpkg -i "./ODBC 17 binaries preview/Ubuntu 16/mssql-tools_17.0.0.5-1_amd64.deb"
|
||||
ENV PATH="/opt/mssql-tools/bin:${PATH}"
|
||||
|
||||
WORKDIR $PHPSQLDIR/source/
|
||||
|
||||
RUN chmod +x ./packagize.sh
|
||||
RUN /bin/bash -c "./packagize.sh"
|
||||
|
||||
RUN echo "extension = pdo_sqlsrv.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"`
|
||||
RUN echo "extension = pdo_sqlsrv.so" >> /etc/php/7.0/cli/conf.d/20-pdo_sqlsrv.ini
|
||||
RUN echo "extension = sqlsrv.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"`
|
||||
|
||||
WORKDIR $PHPSQLDIR/source/sqlsrv
|
||||
|
|
|
@ -0,0 +1,305 @@
|
|||
# PHP Linux and Mac Drivers Installation Tutorial
|
||||
The following instructions assume a clean environment and show how to install PHP 7.x, the Microsoft ODBC driver, Apache, and the Microsoft drivers for PHP for Microsoft SQL Server on Ubuntu 16.04 and 17.10, RedHat 7, Debian 8 and 9, Suse 12, and macOS 10.11 and 10.12. These instructions advise installing the drivers using PECL, but you can also download the prebuilt binaries from the [Microsoft Drivers for PHP for Microsoft SQL Server](https://github.com/Microsoft/msphpsql/releases) Github project page and install them following the instructions in [Loading the Microsoft Drivers for PHP for Microsoft SQL Server](../../connect/php/loading-the-php-sql-driver.md). For an explanation of extension loading and why we do not add the extensions to php.ini, see the section on [loading the drivers](../../connect/php/loading-the-php-sql-driver.md##loading-the-driver-at-php-startup).
|
||||
|
||||
These instruction install PHP 7.2 by default -- see the notes at the beginning of each section to install PHP 7.0 or 7.1.
|
||||
|
||||
## Contents of this page:
|
||||
|
||||
- [Installing the drivers on Ubuntu 16.04 and 17.10](#installing-the-drivers-on-ubuntu-1604-and-1710)
|
||||
- [Installing the drivers on Red Hat 7](#installing-the-drivers-on-red-hat-7)
|
||||
- [Installing the drivers on Debian 8 and 9](#installing-the-drivers-on-debian-8-and-9)
|
||||
- [Installing the drivers on Suse 12](#installing-the-drivers-on-suse-12)
|
||||
- [Installing the drivers on macOS El Capitan and Sierra](#installing-the-drivers-on-macos-el-capitan-and-sierra)
|
||||
|
||||
## Installing the drivers on Ubuntu 16.04 and 17.10
|
||||
|
||||
> [!NOTE]
|
||||
> To install PHP 7.0 or 7.1, replace 7.2 with 7.0 or 7.1 in the following commands.
|
||||
|
||||
### Step 1. Install PHP
|
||||
```
|
||||
sudo su
|
||||
add-apt-repository ppa:ondrej/php -y
|
||||
apt-get update
|
||||
apt-get install php7.2 php7.2-dev php7.2-xml -y --allow-unauthenticated
|
||||
```
|
||||
### Step 2. Install prerequisites
|
||||
Install the ODBC driver for Ubuntu by following the instructions on the [Linux and macOS installation page](https://docs.microsoft.com/en-us/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server).
|
||||
|
||||
### Step 3. Install the PHP drivers for Microsoft SQL Server
|
||||
```
|
||||
sudo su
|
||||
echo extension=pdo_sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/30-pdo_sqlsrv.ini
|
||||
echo extension=sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/20-sqlsrv.ini
|
||||
exit
|
||||
sudo pecl install sqlsrv
|
||||
sudo pecl install pdo_sqlsrv
|
||||
```
|
||||
### Step 4. Install Apache and configure driver loading
|
||||
```
|
||||
sudo su
|
||||
apt-get install libapache2-mod-php7.2 apache2
|
||||
a2dismod mpm_event
|
||||
a2enmod mpm_prefork
|
||||
a2enmod php7.2
|
||||
echo "extension=sqlsrv.so" >> /etc/php/7.2/apache2/php.ini
|
||||
echo "extension=pdo_sqlsrv.so" >> /etc/php/7.2/apache2/php.ini
|
||||
```
|
||||
### Step 5. Restart Apache and test the sample script
|
||||
```
|
||||
sudo service apache2 restart
|
||||
```
|
||||
To test your installation, see [Testing your installation](#testing-your-installation) at the end of this document.
|
||||
|
||||
## Installing the drivers on Red Hat 7
|
||||
|
||||
> [!NOTE]
|
||||
> To install PHP 7.0 or 7.1, replace remi-php72 with remi-php70 or remi-php71 respectively in the following commands.
|
||||
|
||||
### Step 1. Install PHP
|
||||
|
||||
```
|
||||
sudo su
|
||||
wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
|
||||
wget http://rpms.remirepo.net/enterprise/remi-release-7.rpm
|
||||
rpm -Uvh remi-release-7.rpm epel-release-latest-7.noarch.rpm
|
||||
subscription-manager repos --enable=rhel-7-server-optional-rpms
|
||||
yum-config-manager --enable remi-php72
|
||||
yum update
|
||||
yum install php php-pdo php-xml php-pear php-devel re2c gcc-c++ gcc
|
||||
```
|
||||
### Step 2. Install prerequisites
|
||||
Install the ODBC driver for Red Hat 7 by following the instructions on the [Linux and macOS installation page](../../connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server.md).
|
||||
|
||||
Compiling the PHP drivers with PECL with PHP 7.2 requires a more recent GCC than the default:
|
||||
```
|
||||
sudo yum-config-manager --enable rhel-server-rhscl-7-rpms
|
||||
sudo yum install devtoolset-7
|
||||
scl enable devtoolset-7 bash
|
||||
```
|
||||
### Step 3. Install the PHP drivers for Microsoft SQL Server
|
||||
```
|
||||
sudo su
|
||||
echo extension=pdo_sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/30-pdo_sqlsrv.ini
|
||||
echo extension=sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/20-sqlsrv.ini
|
||||
exit
|
||||
sudo pecl install sqlsrv
|
||||
sudo pecl install pdo_sqlsrv
|
||||
```
|
||||
An issue in PECL may prevent correct installation of the latest version of the drivers even if you have upgraded GCC. To install, download the packages and compile manually:
|
||||
```
|
||||
pecl download sqlsrv
|
||||
tar xvzf sqlsrv-5.2.0.tgz
|
||||
cd sqlsrv-5.2.0/
|
||||
phpize
|
||||
./configure --with-php-config=/usr/bin/php-config
|
||||
make
|
||||
sudo make install
|
||||
```
|
||||
You can alternatively download the prebuilt binaries from the [Github project page](https://github.com/Microsoft/msphpsql/releases), or install from the Remi repo:
|
||||
```
|
||||
sudo yum install php-sqlsrv php-pdo_sqlsrv
|
||||
```
|
||||
### Step 4. Install Apache
|
||||
```
|
||||
sudo yum install httpd
|
||||
```
|
||||
SELinux is installed by default and runs in Enforcing mode. To allow Apache to connect to databases through SELinux, run the following command:
|
||||
```
|
||||
sudo setsebool -P httpd_can_network_connect_db 1
|
||||
```
|
||||
### Step 5. Restart Apache and test the sample script
|
||||
```
|
||||
sudo apachectl restart
|
||||
```
|
||||
To test your installation, see [Testing your installation](#testing-your-installation) at the end of this document.
|
||||
|
||||
## Installing the drivers on Debian 8 and 9
|
||||
|
||||
> [!NOTE]
|
||||
> To install PHP 7.0 or 7.1, replace 7.2 in the following commands with 7.0 or 7.1.
|
||||
|
||||
### Step 1. Install PHP
|
||||
```
|
||||
sudo su
|
||||
apt-get install curl apt-transport-https
|
||||
wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
|
||||
echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list
|
||||
apt-get update
|
||||
apt-get install –y php7.2 php7.2-dev php7.2-xml
|
||||
```
|
||||
### Step 2. Install prerequisites
|
||||
Install the ODBC driver for Debian by following the instructions on the [Linux and macOS installation page](../../connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server.md).
|
||||
|
||||
You may also need to generate the correct locale to get PHP output to display correctly in a browser. For example, for the en_US UTF-8 locale, run the following commands:
|
||||
```
|
||||
sudo su
|
||||
sed -i 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/g' /etc/locale.gen
|
||||
locale-gen
|
||||
```
|
||||
|
||||
### Step 3. Install the PHP drivers for Microsoft SQL Server
|
||||
```
|
||||
sudo su
|
||||
echo extension=pdo_sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/30-pdo_sqlsrv.ini
|
||||
echo extension=sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/20-sqlsrv.ini
|
||||
exit
|
||||
sudo pecl install sqlsrv
|
||||
sudo pecl install pdo_sqlsrv
|
||||
```
|
||||
### Step 4. Install Apache and configure driver loading
|
||||
```
|
||||
sudo su
|
||||
apt-get install libapache2-mod-php7.2 apache2
|
||||
a2dismod mpm_event
|
||||
a2enmod mpm_prefork
|
||||
a2enmod php7.2
|
||||
echo "extension=sqlsrv.so" >> /etc/php/7.2/apache2/php.ini
|
||||
echo "extension=pdo_sqlsrv.so" >> /etc/php/7.2/apache2/php.ini
|
||||
```
|
||||
### Step 5. Restart Apache and test the sample script
|
||||
```
|
||||
sudo service apache2 restart
|
||||
```
|
||||
To test your installation, see [Testing your installation](#testing-your-installation) at the end of this document.
|
||||
|
||||
## Installing the drivers on Suse 12
|
||||
|
||||
> [!NOTE]
|
||||
> To install PHP 7.0, skip the command below adding the repository - 7.0 is the default PHP on suse 12.
|
||||
> To install PHP 7.1, replace the repository URL below with the following URL:
|
||||
`http://download.opensuse.org/repositories/devel:/languages:/php:/php71/SLE_12/devel:languages:php:php71.repo`
|
||||
|
||||
### Step 1. Install PHP
|
||||
```
|
||||
sudo su
|
||||
zypper -n ar -f http://download.opensuse.org/repositories/devel:languages:php/SLE_12/devel:languages:php.repo
|
||||
zypper --gpg-auto-import-keys refresh
|
||||
zypper -n install php7 php7-pear php7-devel
|
||||
```
|
||||
### Step 2. Install prerequisites
|
||||
Install the ODBC driver for Suse 12 by following the instructions on the [Linux and macOS installation page](../../connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server.md).
|
||||
|
||||
### Step 3. Install the PHP drivers for Microsoft SQL Server
|
||||
```
|
||||
sudo su
|
||||
echo extension=pdo_sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/pdo_sqlsrv.ini
|
||||
echo extension=sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/sqlsrv.ini
|
||||
exit
|
||||
sudo pecl install sqlsrv
|
||||
sudo pecl install pdo_sqlsrv
|
||||
```
|
||||
### Step 4. Install Apache and configure driver loading
|
||||
```
|
||||
sudo su
|
||||
zypper install apache2 apache2-mod_php7
|
||||
a2enmod php7
|
||||
echo "extension=sqlsrv.so" >> /etc/php7/apache2/php.ini
|
||||
echo "extension=pdo_sqlsrv.so" >> /etc/php7/apache2/php.ini
|
||||
```
|
||||
### Step 5. Restart Apache and test the sample script
|
||||
```
|
||||
sudo systemctl restart apache2
|
||||
```
|
||||
To test your installation, see [Testing your installation](#testing-your-installation) at the end of this document.
|
||||
|
||||
## Installing the drivers on macOS El Capitan and Sierra
|
||||
|
||||
If you do not already have it, install brew as follows:
|
||||
```
|
||||
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> To install PHP 7.0 or 7.1, replace php72 with php70 or php71 respectively in the following commands.
|
||||
|
||||
### Step 1. Install PHP
|
||||
|
||||
```
|
||||
brew tap
|
||||
brew tap homebrew/dupes
|
||||
brew tap homebrew/versions
|
||||
brew tap homebrew/homebrew-php
|
||||
brew install php72 --with-pear --with-httpd24 --with-cgi
|
||||
echo 'export PATH="/usr/local/sbin:$PATH"' >> ~/.bash_profile
|
||||
echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.bash_profile
|
||||
source ~/.bash_profile
|
||||
```
|
||||
### Step 2. Install prerequisites
|
||||
Install the ODBC driver for macOS by following the instructions on the [Linux and macOS installation page](../../connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server.md).
|
||||
|
||||
In addition, you may need to install the GNU make tools:
|
||||
```
|
||||
brew install autoconf automake libtool
|
||||
```
|
||||
|
||||
### Step 3. Install the PHP drivers for Microsoft SQL Server
|
||||
```
|
||||
chmod -R ug+w /usr/local/opt/php72/lib/php
|
||||
pear config-set php_ini /usr/local/etc/php/7.2/php.ini system
|
||||
sudo pecl install sqlsrv
|
||||
sudo pecl install pdo_sqlsrv
|
||||
```
|
||||
### Step 4. Install Apache and configure driver loading
|
||||
```
|
||||
(echo "<FilesMatch .php$>"; echo "SetHandler application/x-httpd-php"; echo "</FilesMatch>";) >> /usr/local/etc/httpd/httpd.conf
|
||||
```
|
||||
### Step 5. Restart Apache and test the sample script
|
||||
```
|
||||
sudo apachectl restart
|
||||
```
|
||||
To test your installation, see [Testing your installation](#testing-your-installation) at the end of this document.
|
||||
|
||||
## Testing Your Installation
|
||||
|
||||
To test this sample script, create a file called testsql.php in your system's document root. This is `/var/www/html/` on Ubuntu, Debian, and Redhat, `/srv/www/htdocs` on SUSE, or `/usr/local/var/www` on macOS. Copy the following script to it, replacing the server, database, username, and password as appropriate.
|
||||
```
|
||||
<?php
|
||||
$serverName = "yourServername";
|
||||
$connectionOptions = array(
|
||||
"Database" => "yourDatabase",
|
||||
"Uid" => "yourUsername",
|
||||
"PWD" => "yourPassword"
|
||||
);
|
||||
|
||||
//Establishes the connection
|
||||
$conn = sqlsrv_connect($serverName, $connectionOptions);
|
||||
if( $conn === false ) {
|
||||
die( FormatErrors( sqlsrv_errors()));
|
||||
}
|
||||
|
||||
//Select Query
|
||||
$tsql= "SELECT @@Version as SQL_VERSION";
|
||||
|
||||
//Executes the query
|
||||
$getResults= sqlsrv_query($conn, $tsql);
|
||||
|
||||
//Error handling
|
||||
if ($getResults == FALSE)
|
||||
die(FormatErrors(sqlsrv_errors()));
|
||||
?>
|
||||
|
||||
<h1> Results : </h1>
|
||||
|
||||
<?php
|
||||
while ($row = sqlsrv_fetch_array($getResults, SQLSRV_FETCH_ASSOC)) {
|
||||
echo ($row['SQL_VERSION']);
|
||||
echo ("<br/>");
|
||||
}
|
||||
|
||||
sqlsrv_free_stmt($getResults);
|
||||
|
||||
function FormatErrors( $errors )
|
||||
{
|
||||
/* Display errors. */
|
||||
echo "Error information: <br/>";
|
||||
foreach ( $errors as $error )
|
||||
{
|
||||
echo "SQLSTATE: ".$error['SQLSTATE']."<br/>";
|
||||
echo "Code: ".$error['code']."<br/>";
|
||||
echo "Message: ".$error['message']."<br/>";
|
||||
}
|
||||
}
|
||||
?>
|
||||
```
|
||||
Point your browser to http://localhost/testsql.php (http://localhost:8080/testsql.php on macOS). You should now be able to connect to your SQL Server/Azure SQL database.
|
Двоичные данные
ODBC 17 binaries preview/Debian 8/msodbcsql_17.0.0.5-1_amd64.deb
Двоичные данные
ODBC 17 binaries preview/Debian 8/msodbcsql_17.0.0.5-1_amd64.deb
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичные данные
ODBC 17 binaries preview/Debian 9/msodbcsql_17.0.0.5-1_amd64.deb
Двоичные данные
ODBC 17 binaries preview/Debian 9/msodbcsql_17.0.0.5-1_amd64.deb
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -1,6 +0,0 @@
|
|||
|
||||
The ODBC driver 17 preview binaries in this directory are required in order to use Always Encrypted functionality. Please note that these drivers should be considered to be preview versions -- they should not be used in production and are not supported by Microsoft. They will be replaced upon the official release of ODBC driver 17.
|
||||
|
||||
On Windows, the ODBC 17 preview binaries require the Visual C/C++ 2013 runtime libraries installed separately. These are installed with the [Visual Studio C++ 2013 Redistributable](https://www.microsoft.com/en-ca/download/details.aspx?id=40784) or with the [SQL Server command line utilities](https://www.microsoft.com/en-ca/download/details.aspx?id=53591). Once you have these, simply run the msi to install.
|
||||
|
||||
For instructions on installing the binaries on Linux platforms, please see [this page](https://github.com/Microsoft/msphpsql/wiki/Install-and-configuration#odbc-17-linux-installation).
|
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичные данные
ODBC 17 binaries preview/SUSE 12/msodbcsql-17.0.0.5-1.x86_64.rpm
Двоичные данные
ODBC 17 binaries preview/SUSE 12/msodbcsql-17.0.0.5-1.x86_64.rpm
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичные данные
ODBC 17 binaries preview/Windows/x64/msodbcsql.msi
Двоичные данные
ODBC 17 binaries preview/Windows/x64/msodbcsql.msi
Двоичный файл не отображается.
Двоичные данные
ODBC 17 binaries preview/Windows/x86/msodbcsql.msi
Двоичные данные
ODBC 17 binaries preview/Windows/x86/msodbcsql.msi
Двоичный файл не отображается.
457
README.md
457
README.md
|
@ -1,10 +1,10 @@
|
|||
# Microsoft Drivers for PHP for SQL Server
|
||||
# Microsoft Drivers for PHP for Microsoft SQL Server
|
||||
|
||||
**Welcome to the Microsoft Drivers for PHP for SQL Server PHP 7**
|
||||
**Welcome to the Microsoft Drivers for PHP for Microsoft SQL Server**
|
||||
|
||||
The Microsoft Drivers for PHP for SQL Server are PHP extensions that allow for the reading and writing of SQL Server data from within PHP scripts. The SQLSRV extension provides a procedural interface while the PDO_SQLSRV extension implements PDO for accessing data in all editions of SQL Server 2008 R2 and later (including Azure SQL DB). These drivers rely on the Microsoft ODBC Driver for SQL Server to handle the low-level communication with SQL Server.
|
||||
The Microsoft Drivers for PHP for Microsoft SQL Server are PHP extensions that allow for the reading and writing of SQL Server data from within PHP scripts. The SQLSRV extension provides a procedural interface while the PDO_SQLSRV extension implements PHP Data Objects (PDO) for accessing data in all editions of SQL Server 2008 R2 and later (including Azure SQL DB). These drivers rely on the Microsoft ODBC Driver for SQL Server to handle the low-level communication with SQL Server.
|
||||
|
||||
This release contains the SQLSRV and PDO_SQLSRV drivers for PHP 7.0.* or above with improvements on both drivers and some limitations (see Limitations below for details). Upcoming release(s) will contain more functionality, bug fixes, and more (see Plans below for more details).
|
||||
This release contains the SQLSRV and PDO_SQLSRV drivers for PHP 7.* with improvements on both drivers and some limitations (see Limitations below for details). Upcoming releases will contain additional functionality, bug fixes, and more (see Plans below for more details).
|
||||
|
||||
SQL Server Team
|
||||
|
||||
|
@ -31,10 +31,10 @@ Thank you for taking the time to participate in our last survey. You can continu
|
|||
|
||||
## Get Started
|
||||
|
||||
* [**Windows + SQL Server + PHP 7**](https://www.microsoft.com/en-us/sql-server/developer-get-started/php/windows)
|
||||
* [**Ubuntu + SQL Server + PHP 7**](https://www.microsoft.com/en-us/sql-server/developer-get-started/php/ubuntu)
|
||||
* [**RedHat + SQL Server + PHP 7**](https://www.microsoft.com/en-us/sql-server/developer-get-started/php/rhel)
|
||||
* [**SUSE + SQL Server + PHP 7**](https://www.microsoft.com/en-us/sql-server/developer-get-started/php/sles)
|
||||
* [**Windows + SQL Server + PHP 7**](https://www.microsoft.com/en-us/sql-server/developer-get-started/php/windows)
|
||||
* [**macOS + SQL Server + PHP 7**](https://www.microsoft.com/en-us/sql-server/developer-get-started/php/mac/)
|
||||
* [**Docker**](https://hub.docker.com/r/lbosqmsft/mssql-php-msphpsql/)
|
||||
|
||||
|
@ -43,441 +43,66 @@ Thank you for taking the time to participate in our last survey. You can continu
|
|||
|
||||
Please visit the [blog][blog] for more announcements.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
## Build (Windows)
|
||||
|
||||
Note: if you prefer, you can use the pre-compiled binaries found in the [releases](https://github.com/Microsoft/msphpsql/releases)
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
You must first be able to build PHP 7.0.* or above without including these extensions. For help with doing this, see the [official PHP website][phpbuild] for building your own PHP in Windows.
|
||||
|
||||
#### Compile the drivers
|
||||
|
||||
The Microsoft Drivers for PHP for SQL Server have been compiled and tested with PHP 7.0.* and 7.1.* using Visual C++ 2015 as well as PHP 7.2.0* using Visual C++ 2017 v15.0.
|
||||
For details, please read the documentation and/or take a look at the sample [build scripts](https://github.com/Microsoft/msphpsql/tree/dev/buildscripts#windows).
|
||||
|
||||
## Install (Windows)
|
||||
|
||||
#### Prerequisites
|
||||
For full details on the system requirements for the drivers, see the [system requirements](https://docs.microsoft.com/en-us/sql/connect/php/system-requirements-for-the-php-sql-driver) on MSDN.
|
||||
|
||||
On the client machine:
|
||||
- PHP 7.0.x, 7.1.x, or 7.2.x (7.2.0 and up on Unix, 7.2.1 and up on Windows)
|
||||
- A Web server such as Internet Information Services (IIS) is required. Your Web server must be configured to run PHP
|
||||
- [Microsoft ODBC Driver 11][odbc11], [Microsoft ODBC Driver 13][odbc13] or [Microsoft ODBC Driver 17][odbc17]
|
||||
- [Microsoft ODBC Driver 11][odbc11], [Microsoft ODBC Driver 13][odbc13], or [Microsoft ODBC Driver 17][odbc17]
|
||||
|
||||
#### Enable the drivers
|
||||
On the server side, Microsoft SQL Server 2008 R2 and above on Windows is supported, as is Microsoft SQL Server 2016 and above on Linux.
|
||||
|
||||
1. Make sure that the driver is in your PHP extension directory (you can simply copy it there if you did not use nmake install).
|
||||
## Building and Installing the Drivers on Windows
|
||||
|
||||
2. Enable it within your PHP installation's php.ini: `extension=php_sqlsrv.dll` and/or `extension=php_pdo_sqlsrv.dll`. If necessary, specify the extension directory using extension_dir, for example: `extension_dir = "C:\PHP\ext"`. Note that the precompiled binaries have different names -- substitute accordingly in php.ini.
|
||||
The drivers are distributed as pre-compiled extensions for PHP found on the [releases page](https://github.com/Microsoft/msphpsql/releases). They are available in thread-safe and non thread-safe versions, and in 32-bit and 64-bit versions. The source code for the drivers is also available, and you can compile them as thread safe or non-thread safe versions. The thread safety configuration of your web server will determine which version you need.
|
||||
|
||||
If you choose to build the drivers, you must be able to build PHP 7 without including these extensions. For help building PHP on Windows, see the [official PHP website][phpbuild]. For details on compiling the drivers, see the [documentation](https://github.com/Microsoft/msphpsql/tree/dev/buildscripts#windows) -- an example buildscript is provided, but you can also compile the drivers manually.
|
||||
|
||||
3. Restart the Web server.
|
||||
To load the drivers, make sure that the driver is in your PHP extension directory and enable it in your PHP installation's php.ini file by adding `extension=php_sqlsrv.dll` and/or `extension=php_pdo_sqlsrv.dll` to it. If necessary, specify the extension directory using `extension_dir`, for example: `extension_dir = "C:\PHP\ext"`. Note that the precompiled binaries have different names -- substitute accordingly in php.ini. For more details on loading the drivers, see [Loading the PHP SQL Driver](https://docs.microsoft.com/en-us/sql/connect/php/loading-the-php-sql-driver) on MSDN.
|
||||
|
||||
Finally, restart the Web server.
|
||||
|
||||
## Install (UNIX)
|
||||
The following instructions assume a clean environment and show how to install PHP 7.x, Microsoft ODBC driver, Apache, and Microsoft PHP drivers on Ubuntu 16, 17 RedHat 7, Debian 8, 9 SUSE 12, and macOS 10.11, 10.12.
|
||||
|
||||
Note that [Microsoft ODBC Driver 17][odbc17] is required for Ubuntu 17 and Debian 9.
|
||||
|
||||
### Step 1: Install PHP7+
|
||||
|
||||
#### PHP 7.0
|
||||
|
||||
**Ubuntu 16.04, 17.10**
|
||||
|
||||
sudo su
|
||||
apt-get update
|
||||
apt-get -y install php7.0 mcrypt php7.0-mcrypt php-mbstring php-pear php7.0-dev php7.0-xml
|
||||
|
||||
**RedHat 7**
|
||||
|
||||
sudo su
|
||||
wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
|
||||
wget http://rpms.remirepo.net/enterprise/remi-release-7.rpm
|
||||
rpm -Uvh remi-release-7.rpm epel-release-latest-7.noarch.rpm
|
||||
subscription-manager repos --enable=rhel-7-server-optional-rpms
|
||||
yum-config-manager --enable remi-php70
|
||||
yum update
|
||||
yum install php php-pdo php-xml php-pear php-devel re2c gcc-c++ gcc
|
||||
|
||||
**Debian 8**
|
||||
|
||||
sudo su
|
||||
apt-get install curl apt-transport-https
|
||||
curl https://www.dotdeb.org/dotdeb.gpg | apt-key add -
|
||||
echo "deb http://packages.dotdeb.org jessie all" >> /etc/apt/sources.list
|
||||
echo "deb-src http://packages.dotdeb.org jessie all" >> /etc/apt/sources.list
|
||||
apt-get update
|
||||
apt-get install -y php7.0 php-pear php7.0-dev php7.0-xml
|
||||
|
||||
**Debian 9**
|
||||
|
||||
sudo su
|
||||
apt-get install curl apt-transport-https
|
||||
curl https://www.dotdeb.org/dotdeb.gpg | apt-key add -
|
||||
echo "deb http://packages.dotdeb.org stretch all" >> /etc/apt/sources.list
|
||||
echo "deb-src http://packages.dotdeb.org stretch all" >> /etc/apt/sources.list
|
||||
apt-get update
|
||||
apt-get install -y php7.0 php-pear php7.0-dev php7.0-xml
|
||||
|
||||
**SUSE 12**
|
||||
|
||||
sudo su
|
||||
zypper refresh
|
||||
zypper install -y php7 php7-pear php7-devel
|
||||
|
||||
**macOS 10.11, 10.12**
|
||||
|
||||
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
|
||||
brew tap
|
||||
brew tap homebrew/dupes
|
||||
brew tap homebrew/versions
|
||||
brew tap homebrew/homebrew-php
|
||||
brew install php70 --with-pear --with-httpd24 --with-cgi
|
||||
echo 'export PATH="/usr/local/sbin:$PATH"' >> ~/.bash_profile
|
||||
echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.bash_profile
|
||||
source ~/.bash_profile
|
||||
|
||||
#### PHP 7.1
|
||||
|
||||
**Ubuntu 16.04, 17.10**
|
||||
|
||||
sudo su
|
||||
add-apt-repository ppa:ondrej/php
|
||||
apt-get update
|
||||
apt-get -y install php7.1 mcrypt php7.1-mcrypt php-mbstring php-pear php7.1-dev php7.1-xml
|
||||
|
||||
**RedHat 7**
|
||||
|
||||
sudo su
|
||||
wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
|
||||
wget http://rpms.remirepo.net/enterprise/remi-release-7.rpm
|
||||
rpm -Uvh remi-release-7.rpm epel-release-latest-7.noarch.rpm
|
||||
subscription-manager repos --enable=rhel-7-server-optional-rpms
|
||||
yum-config-manager --enable remi-php71
|
||||
yum update
|
||||
yum install php php-pdo php-xml php-pear php-devel re2c gcc-c++ gcc
|
||||
|
||||
**Debian 8, 9**
|
||||
|
||||
sudo su
|
||||
apt-get install curl apt-transport-https
|
||||
wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
|
||||
echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list
|
||||
apt-get update
|
||||
apt-get install -y php7.1 php-pear php7.1-dev php7.1-xml
|
||||
|
||||
**SUSE 12**
|
||||
|
||||
sudo su
|
||||
zypper -n ar -f http://download.opensuse.org/repositories/devel:/languages:/php/openSUSE_Leap_42.3/ devel:languages:php
|
||||
zypper --gpg-auto-import-keys refresh
|
||||
zypper -n install php7 php7-pear php7-devel
|
||||
|
||||
**macOS 10.11, 10.12**
|
||||
|
||||
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
|
||||
brew tap
|
||||
brew tap homebrew/dupes
|
||||
brew tap homebrew/versions
|
||||
brew tap homebrew/homebrew-php
|
||||
brew install php71 --with-pear --with-httpd24 --with-cgi
|
||||
echo 'export PATH="/usr/local/sbin:$PATH"' >> ~/.bash_profile
|
||||
echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.bash_profile
|
||||
source ~/.bash_profile
|
||||
|
||||
|
||||
### Step 2: Install Prerequisites
|
||||
|
||||
**Ubuntu 16.04**
|
||||
|
||||
sudo su
|
||||
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
|
||||
curl https://packages.microsoft.com/config/ubuntu/16.04/prod.list > /etc/apt/sources.list.d/mssql-release.list
|
||||
exit
|
||||
sudo apt-get update
|
||||
sudo ACCEPT_EULA=Y apt-get install msodbcsql mssql-tools
|
||||
sudo apt-get install unixodbc-dev
|
||||
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile
|
||||
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
|
||||
**Ubuntu 17.10 (available upon the official release of ODBC driver 17)**
|
||||
|
||||
sudo su
|
||||
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
|
||||
curl https://packages.microsoft.com/config/ubuntu/17.10/prod.list > /etc/apt/sources.list.d/mssql-release.list
|
||||
exit
|
||||
sudo apt-get update
|
||||
sudo ACCEPT_EULA=Y apt-get install msodbcsql mssql-tools
|
||||
sudo apt-get install unixodbc-dev
|
||||
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile
|
||||
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
|
||||
**RedHat 7**
|
||||
|
||||
sudo su
|
||||
curl https://packages.microsoft.com/config/rhel/7/prod.repo > /etc/yum.repos.d/mssql-release.repo
|
||||
exit
|
||||
sudo yum update
|
||||
sudo yum remove unixODBC-utf16-devel #to avoid conflicts
|
||||
sudo ACCEPT_EULA=Y yum install msodbcsql mssql-tools
|
||||
sudo yum install unixODBC-devel
|
||||
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile
|
||||
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
|
||||
**Debian 8**
|
||||
|
||||
sudo su
|
||||
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
|
||||
curl https://packages.microsoft.com/config/debian/8/prod.list > /etc/apt/sources.list.d/mssql-release.list
|
||||
apt-get install -y locales
|
||||
echo "en_US.UTF-8 UTF-8" > /etc/locale.gen
|
||||
locale-gen
|
||||
exit
|
||||
sudo apt-get update
|
||||
sudo ACCEPT_EULA=Y apt-get install msodbcsql
|
||||
sudo apt-get install unixodbc-dev
|
||||
|
||||
**Debian 9 (available upon the official release of ODBC driver 17)**
|
||||
|
||||
sudo su
|
||||
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
|
||||
curl https://packages.microsoft.com/config/debian/9/prod.list > /etc/apt/sources.list.d/mssql-release.list
|
||||
apt-get install -y locales
|
||||
echo "en_US.UTF-8 UTF-8" > /etc/locale.gen
|
||||
locale-gen
|
||||
exit
|
||||
sudo apt-get update
|
||||
sudo ACCEPT_EULA=Y apt-get install msodbcsql
|
||||
sudo apt-get install unixodbc-dev
|
||||
|
||||
**SUSE 12**
|
||||
|
||||
sudo su
|
||||
zypper ar https://packages.microsoft.com/config/sles/12/prod.repo
|
||||
sudo zypper --gpg-auto-import-keys refresh
|
||||
exit
|
||||
sudo ACCEPT_EULA=Y zypper install msodbcsql
|
||||
sudo ACCEPT_EULA=Y zypper install mssql-tools
|
||||
sudo zypper install unixODBC-devel
|
||||
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile
|
||||
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
|
||||
**macOS 10.11, 10.12**
|
||||
|
||||
brew tap microsoft/msodbcsql https://github.com/Microsoft/homebrew-mssql-release
|
||||
brew update
|
||||
brew install --no-sandbox msodbcsql
|
||||
brew install mssql-tools
|
||||
brew install autoconf
|
||||
|
||||
*Note: Be sure to install PHP 7+ before proceeding to step 3. The Microsoft PHP Drivers for SQL Server will only work for PHP 7+.
|
||||
|
||||
### Step 3: Install the Microsoft PHP Drivers for SQL Server
|
||||
|
||||
*Note: You can run `sudo pecl search sqlsrv` to search for the latest releases and `sudo pecl install sqlsrv-[version]` to install a specific version. PECL installs the stable version when version is not specified. Drivers are Mac-compatible starting from `4.1.7preview` release.
|
||||
|
||||
On Ubuntu, Debian, and SUSE systems only, run:
|
||||
|
||||
sudo pear config-set php_ini `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"` system
|
||||
|
||||
On macOS, run:
|
||||
|
||||
chmod -R ug+w /usr/local/opt/php71/lib/php
|
||||
pear config-set php_ini /usr/local/etc/php/7.1/php.ini system
|
||||
|
||||
On all systems, run:
|
||||
|
||||
pecl install sqlsrv
|
||||
pecl install pdo_sqlsrv
|
||||
|
||||
### Step 4: Install and Configure Apache
|
||||
|
||||
#### PHP 7.0
|
||||
|
||||
**Ubuntu and Debian**
|
||||
|
||||
sudo su
|
||||
apt-get install libapache2-mod-php7.0 apache2
|
||||
a2dismod mpm_event
|
||||
a2enmod mpm_prefork
|
||||
a2enmod php7.0
|
||||
echo "extension=sqlsrv.so" >> /etc/php/7.0/apache2/php.ini
|
||||
echo "extension=pdo_sqlsrv.so" >> /etc/php/7.0/apache2/php.ini
|
||||
|
||||
**RedHat**
|
||||
|
||||
sudo su
|
||||
yum install httpd
|
||||
echo "extension=sqlsrv.so" > /etc/php.d/sqlsrv.ini
|
||||
echo "extension=pdo_sqlsrv.so" > /etc/php.d/pdo_sqlsrv.ini
|
||||
|
||||
**SUSE**
|
||||
|
||||
sudo su
|
||||
zypper install apache2 apache2-mod_php7
|
||||
a2enmod php7
|
||||
echo "extension=sqlsrv.so" >> /etc/php7/apache2/php.ini
|
||||
echo "extension=pdo_sqlsrv.so" >> /etc/php7/apache2/php.ini
|
||||
|
||||
**macOS**
|
||||
|
||||
(echo "<FilesMatch .php$>"; echo "SetHandler application/x-httpd-php"; echo "</FilesMatch>";) >> /usr/local/etc/apache2/2.4/httpd.conf
|
||||
|
||||
#### PHP 7.1
|
||||
|
||||
**Ubuntu and Debian**
|
||||
|
||||
sudo su
|
||||
apt-get install libapache2-mod-php7.1 apache2
|
||||
a2dismod mpm_event
|
||||
a2enmod mpm_prefork
|
||||
a2enmod php7.1
|
||||
echo "extension=sqlsrv.so" >> /etc/php/7.1/apache2/php.ini
|
||||
echo "extension=pdo_sqlsrv.so" >> /etc/php/7.1/apache2/php.ini
|
||||
|
||||
**RedHat**
|
||||
|
||||
sudo su
|
||||
yum install httpd
|
||||
echo "extension=sqlsrv.so" > /etc/php.d/sqlsrv.ini
|
||||
echo "extension=pdo_sqlsrv.so" > /etc/php.d/pdo_sqlsrv.ini
|
||||
|
||||
**SUSE**
|
||||
|
||||
sudo su
|
||||
zypper install apache2 apache2-mod_php7
|
||||
a2enmod php7
|
||||
echo "extension=sqlsrv.so" >> /etc/php7/apache2/php.ini
|
||||
echo "extension=pdo_sqlsrv.so" >> /etc/php7/apache2/php.ini
|
||||
|
||||
**macOS**
|
||||
|
||||
(echo "<FilesMatch .php$>"; echo "SetHandler application/x-httpd-php"; echo "</FilesMatch>";) >> /usr/local/etc/apache2/2.4/httpd.conf
|
||||
|
||||
|
||||
### Step 5: Restart Apache to load the new php.ini file
|
||||
|
||||
**Ubuntu, Debian, and SUSE**
|
||||
|
||||
sudo systemctl restart apache2
|
||||
|
||||
**RedHat**
|
||||
|
||||
sudo systemctl restart httpd
|
||||
|
||||
Note: On RedHat, SELinux is installed by default and runs in Enforcing mode. To allow Apache to connect to a database through SELinux, run the following command:
|
||||
|
||||
sudo setsebool -P httpd_can_network_connect_db 1
|
||||
|
||||
**macOS**
|
||||
|
||||
sudo apachectl restart
|
||||
|
||||
|
||||
### Step 6: Create your sample app
|
||||
Navigate to your system's document root -- `/var/www/html` on Ubuntu, Debian, and Redhat, `/srv/www/htdocs` on SUSE, or `/usr/local/var/www/htdocs` on Mac. Create a new file called testsql.php. Copy and paste the following code into testsql.php and change the servername, username, password and databasename.
|
||||
|
||||
<?php
|
||||
$serverName = "yourServername";
|
||||
$connectionOptions = array(
|
||||
"Database" => "yourDatabase",
|
||||
"Uid" => "yourUsername",
|
||||
"PWD" => "yourPassword"
|
||||
);
|
||||
//Establishes the connection
|
||||
$conn = sqlsrv_connect( $serverName, $connectionOptions );
|
||||
if( $conn === false ) {
|
||||
die( FormatErrors( sqlsrv_errors()));
|
||||
}
|
||||
//Select Query
|
||||
$tsql= "SELECT @@Version as SQL_VERSION";
|
||||
//Executes the query
|
||||
$getResults= sqlsrv_query( $conn, $tsql );
|
||||
//Error handling
|
||||
|
||||
if ( $getResults == FALSE )
|
||||
die( FormatErrors( sqlsrv_errors()));
|
||||
?>
|
||||
<h1> Results : </h1>
|
||||
<?php
|
||||
while ( $row = sqlsrv_fetch_array( $getResults, SQLSRV_FETCH_ASSOC )) {
|
||||
echo ( $row['SQL_VERSION']);
|
||||
echo ("<br/>");
|
||||
}
|
||||
sqlsrv_free_stmt( $getResults );
|
||||
function FormatErrors( $errors )
|
||||
{
|
||||
/* Display errors. */
|
||||
echo "Error information: <br/>";
|
||||
|
||||
foreach ( $errors as $error )
|
||||
{
|
||||
echo "SQLSTATE: ".$error['SQLSTATE']."<br/>";
|
||||
echo "Code: ".$error['code']."<br/>";
|
||||
echo "Message: ".$error['message']."<br/>";
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
### Step 7: Run your sample app
|
||||
|
||||
Go to your browser and type in http://localhost/testsql.php (http://localhost:8080/testsql.php on Mac)
|
||||
You should be able to connect to your SQL Server/Azure SQL Database.
|
||||
|
||||
The drivers are distributed as shared binary extensions for PHP. They are available in thread safe (*_ts.so) and-non thread safe (*_nts.so) versions. The source code for the drivers is also available, and you can choose whether to compile them as thread safe or non-thread safe versions. The thread safety configuration of your web server will determine which version you need.
|
||||
For full instructions on installing the drivers on all supported Unix platforms, see [the installation instructions on MSDN](https://docs.microsoft.com/en-us/sql/connect/php/installation-tutorial-linux-mac).
|
||||
|
||||
## Sample Code
|
||||
For samples, please see the sample folder. For setup instructions, see [here](https://docs.microsoft.com/en-us/azure/sql-database/sql-database-develop-php-simple).
|
||||
For PHP code samples, please see the [sample](https://github.com/Microsoft/msphpsql/tree/master/sample) folder or the [code samples on MSDN](https://docs.microsoft.com/en-us/sql/connect/php/code-samples-for-php-sql-driver).
|
||||
|
||||
## Limitations
|
||||
|
||||
- This release contains the PHP 7 port of the SQLSRV and PDO_SQLSRV drivers, and does not provide backwards compatibility with PHP 5.
|
||||
- Binding output parameters using emulate prepare is not supported.
|
||||
- Linux
|
||||
- ODBC 3.52 is supported but not 3.8.
|
||||
- Connection using named instances using '\' is not supported.
|
||||
- Local encodings other than UTF-8 are not supported, and SQLSRV_ENC_CHAR only supports ASCII characters with ASCII code of 0 to 127.
|
||||
|
||||
## Known Issues
|
||||
- When pooling is enabled in Linux or macOS
|
||||
- unixODBC <= 2.3.4 (Linux and macOS) might not return proper diagnostics information, such as error messages, warnings and informative messages
|
||||
- due to this unixODBC bug, fetch large data (such as xml, binary) as streams as a workaround. See the examples [here](https://github.com/Microsoft/msphpsql/wiki/Features#connection-pooling-in-linux-and-mac)
|
||||
## Limitations and Known Issues
|
||||
Please refer to [Releases](https://github.com/Microsoft/msphpsql/releases) for the latest limitations and known issues.
|
||||
|
||||
## Version number
|
||||
Version number of PHP drivers follow the [semantic versioning](http://semver.org/):
|
||||
The version numbers of the PHP drivers follow [semantic versioning](http://semver.org/):
|
||||
|
||||
Given a version number MAJOR.MINOR.PATCH,
|
||||
|
||||
- MAJOR version is incremented when an incompatible API changes is made,
|
||||
- MINOR version is incremented when a functionality in a backwards-compatible manner is added, and
|
||||
- MAJOR version is incremented when an incompatible API change is made,
|
||||
- MINOR version is incremented when functionality is added in a backwards-compatible manner, and
|
||||
- PATCH version is incremented when backwards-compatible bug fixes are made.
|
||||
|
||||
version number MAY have trailing pre-release version to indicate the stability, and/or build meta data.
|
||||
The version number may have trailing pre-release version identifiers to indicate the stability and/or build metadata.
|
||||
|
||||
- Pre-release version is denoted by hyphen followed by `preview` or `rc` keyword and may be followed by a series of dot separated identifiers. Production quality releases do not contain the pre-release version. `preview` has lower precedence than `rc`. Example of precedence: *preview < preview.1 < rc < rc.1*.
|
||||
*Note that PECL package version does not have the hyphen before pre-release version, due to restrictions in PECL. Example of PECL package version: 1.2.3preview*
|
||||
- Build metadata MAY be denoted by a plus sign followed by 4 digits, such as `1.2.3-preview+5678` or `1.2.3+5678`. Build meta data does NOT figure into the precedence order.
|
||||
|
||||
|
||||
- Pre-release version is denoted by a hyphen followed by `preview` or `RC` and may be followed by a series of dot separated identifiers. Production quality releases do not contain the pre-release version. `preview` has lower precedence than `RC`. Example of precedence: *preview < preview.1 < RC < RC.1*. Note that the PECL package version numbers do not have the hyphen before the pre-release version, owing to restrictions in PECL. Example of a PECL package version number: 1.2.3preview
|
||||
- Build metadata may be denoted by a plus sign followed by 4 or 5 digits, such as `1.2.3-preview+5678` or `1.2.3+5678`. Build metadata does not figure into the precedence order.
|
||||
|
||||
## Future Plans
|
||||
- Expand SQL 16 Feature Support (example: Always Encrypted).
|
||||
- Add More Verification/Fundamental Tests.
|
||||
- Bug Fixes.
|
||||
- Expand SQL Server 2016 feature support (example: Always Encrypted)
|
||||
- Add more verification/fundamental tests
|
||||
- Bug fixes
|
||||
|
||||
## Guidelines for Reporting Issues
|
||||
We appreciate you taking the time to test the driver, provide feedback and report any issues. It would be extremely helpful if you:
|
||||
|
||||
- Report each issue as a new issue (but check first if it's already been reported)
|
||||
- Try to be detailed in your report. Useful information for good bug reports include:
|
||||
- Try to be detailed in your report. Useful information for good bug reports includes:
|
||||
* What you are seeing and what the expected behaviour is
|
||||
* Can you connect to SQL Server via `sqlcmd`?
|
||||
* Which driver: SQLSRV or PDO_SQLSRV?
|
||||
* Environment details: e.g. PHP version, thread safe (TS) or non-thread safe (NTS), 32-bit &/or 64-bit?
|
||||
* Table schema (for some issues the data types make a big difference!)
|
||||
* Environment details: e.g. PHP version, thread safe (TS) or non-thread safe (NTS), 32-bit or 64-bit?
|
||||
* Table schema (for some issues, the data types make a big difference!)
|
||||
* Any other relevant information you want to share
|
||||
- Try to include a PHP script demonstrating the isolated problem.
|
||||
|
||||
|
@ -486,11 +111,11 @@ Thank you!
|
|||
## FAQs
|
||||
**Q:** Can we get dates for any of the Future Plans listed above?
|
||||
|
||||
**A:** At this time, Microsoft is not able to announce dates. We are working extremely hard to release future versions of the driver. We will share future plans as appropriate.
|
||||
**A:** At this time, Microsoft is not able to announce dates. We are working hard to release future versions of the driver and will share future plans as appropriate.
|
||||
|
||||
**Q:** What's next?
|
||||
|
||||
**A:** On July 6, 2017 we released the production release version 4.3.0 of our PHP Driver. We will continue working on our future plans and releasing previews of upcoming releases frequently.
|
||||
**A:** On March 23, 2018 we released the production release version 5.2.0 of our PHP Driver. We will continue working on our future plans and releasing previews of upcoming releases frequently.
|
||||
|
||||
**Q:** Is Microsoft taking pull requests for this project?
|
||||
|
||||
|
@ -516,9 +141,9 @@ This project has adopted the Microsoft Open Source Code of Conduct. For more inf
|
|||
|
||||
[blog]: http://blogs.msdn.com/b/sqlphp/
|
||||
|
||||
[project]: https://github.com/Azure/msphpsql
|
||||
[project]: https://github.com/Microsoft/msphpsql
|
||||
|
||||
[issues]: https://github.com/Azure/msphpsql/issues
|
||||
[issues]: https://github.com/Microsoft/msphpsql/issues
|
||||
|
||||
[phpweb]: http://php.net
|
||||
|
||||
|
@ -534,8 +159,6 @@ This project has adopted the Microsoft Open Source Code of Conduct. For more inf
|
|||
|
||||
[odbcLinux]: https://msdn.microsoft.com/library/hh568454(v=sql.110).aspx
|
||||
|
||||
[phpazure]: https://azure.microsoft.com/documentation/articles/sql-database-develop-php-simple-windows/
|
||||
|
||||
[PHPMan]: http://php.net/manual/install.unix.php
|
||||
|
||||
[LinuxDM]: https://msdn.microsoft.com/library/hh568449(v=sql.110).aspx
|
||||
|
@ -544,6 +167,4 @@ This project has adopted the Microsoft Open Source Code of Conduct. For more inf
|
|||
|
||||
[apr_source]: http://apr.apache.org/
|
||||
|
||||
[httpdconf]: http://php.net/manual/en/install.unix.apache2.php
|
||||
|
||||
[ODBCinstallers]: https://blogs.msdn.microsoft.com/sqlnativeclient/2016/09/06/preview-release-of-the-sql-server-cc-odbc-driver-13-0-0-for-linux
|
||||
[httpdconf]: http://php.net/manual/en/install.unix.apache2.php
|
55
appveyor.yml
55
appveyor.yml
|
@ -18,6 +18,15 @@ environment:
|
|||
PHP_DEPSVER: 7.0
|
||||
PHP_SDK: c:\projects\php
|
||||
matrix:
|
||||
- BUILD_PLATFORM: x64
|
||||
TEST_PHP_SQL_SERVER: (local)\SQL2012SP1
|
||||
SQL_INSTANCE: SQL2012SP1
|
||||
PHP_VC: 14
|
||||
PHP_MAJOR_VER: 7.1
|
||||
PHP_MINOR_VER: latest
|
||||
PHP_SDK_DIR: c:\projects\php\x64
|
||||
PHP_INSTALL_DIR: c:\projects\php\x64\bin
|
||||
platform: x64
|
||||
- BUILD_PLATFORM: x86
|
||||
TEST_PHP_SQL_SERVER: (local)\SQL2016
|
||||
SQL_INSTANCE: SQL2016
|
||||
|
@ -28,15 +37,6 @@ environment:
|
|||
PHP_INSTALL_DIR: c:\projects\php\x86\bin
|
||||
PHP_ZTS: --disable-zts
|
||||
platform: x86
|
||||
- BUILD_PLATFORM: x64
|
||||
TEST_PHP_SQL_SERVER: (local)\SQL2012SP1
|
||||
SQL_INSTANCE: SQL2012SP1
|
||||
PHP_VC: 14
|
||||
PHP_MAJOR_VER: 7.1
|
||||
PHP_MINOR_VER: latest
|
||||
PHP_SDK_DIR: c:\projects\php\x64
|
||||
PHP_INSTALL_DIR: c:\projects\php\x64\bin
|
||||
platform: x64
|
||||
|
||||
# PHP_MAJOR_VER is PHP major version to build (7.0, 7.1)
|
||||
# PHP_MINOR_VER is PHP point release number (or latest for latest release)
|
||||
|
@ -78,20 +78,24 @@ install:
|
|||
|
||||
Set-Service SQLBrowser -StartupType Manual;
|
||||
Start-Service SQLBrowser;
|
||||
- echo Set PHP version...
|
||||
- appveyor DownloadFile http://windows.php.net/downloads/releases/sha1sum.txt
|
||||
# determine latest PHP versions
|
||||
- ps: >-
|
||||
- echo Downloading prerequisites
|
||||
- ps: |
|
||||
$client = New-Object Net.WebClient;
|
||||
$client.Headers.Add("user-agent", "appveyor-ci-build1");
|
||||
$client.DownloadFile("http://windows.php.net/downloads/php-sdk/php-sdk-binary-tools-20110915.zip", "c:\projects\php-sdk-binary-tools-20110915.zip");
|
||||
- ps: |
|
||||
$client = New-Object Net.WebClient;
|
||||
$client.Headers.Add("user-agent", "appveyor-ci-build2");
|
||||
$client.DownloadFile("http://windows.php.net/downloads/releases/sha1sum.txt", "c:\projects\sha1sum.txt");
|
||||
If ($env:PHP_MINOR_VER -Match "latest") {
|
||||
$env:PHP_VERSION=type sha1sum.txt | where { $_ -match "php-($env:PHP_MAJOR_VER\.\d+)-src" } | foreach { $matches[1] } ;
|
||||
$env:PHP_VERSION=type c:\projects\sha1sum.txt | where { $_ -match "php-($env:PHP_MAJOR_VER\.\d+)-src" } | foreach { $matches[1] } ;
|
||||
} Else {
|
||||
$env:PHP_VERSION=$env:PHP_MAJOR_VER + '.' + $env:PHP_MINOR_VER;
|
||||
}
|
||||
- echo Downloading PHP-SDK
|
||||
- appveyor DownloadFile http://windows.php.net/downloads/php-sdk/php-sdk-binary-tools-20110915.zip
|
||||
- move php-sdk-binary-tools-20110915.zip ..
|
||||
- echo Downloading PHP source code [%PHP_VERSION%]
|
||||
- ps: (new-object net.webclient).DownloadFile('http://windows.php.net/downloads/releases/php-' + ${env:PHP_VERSION} + '-src.zip', ${env:APPVEYOR_BUILD_FOLDER} + '\..\php.zip')
|
||||
- ps: |
|
||||
$client = New-Object Net.WebClient;
|
||||
$client.Headers.Add("user-agent", "appveyor-ci-build3");
|
||||
$client.DownloadFile("http://windows.php.net/downloads/releases/php-" + ${env:PHP_VERSION} + "-src.zip", ${env:APPVEYOR_BUILD_FOLDER} + "\..\php.zip");
|
||||
- echo Downloading MSODBCSQL 13.1
|
||||
# AppVeyor build works are x64 VMs and 32-bit ODBC driver cannot be installed on it
|
||||
- ps: (new-object net.webclient).DownloadFile('https://download.microsoft.com/download/D/5/E/D5EEF288-A277-45C8-855B-8E2CB7E25B96/x64/msodbcsql.msi', 'c:\projects\msodbcsql.msi')
|
||||
|
@ -99,10 +103,9 @@ install:
|
|||
- echo Checking the version of MSODBCSQL
|
||||
- reg query "HKLM\SOFTWARE\ODBC\odbcinst.ini\ODBC Driver 13 for SQL Server"
|
||||
- dir C:\Windows\System32\msodbcsql13.dll
|
||||
- cd ..
|
||||
- cd
|
||||
- 7z x -y php-sdk-binary-tools-20110915.zip -o%PHP_SDK%
|
||||
- 7z x -y php.zip -o%PHP_SDK_DIR%
|
||||
- cd c:\projects
|
||||
- 7z x -y .\php-sdk-binary-tools-20110915.zip -o%PHP_SDK%
|
||||
- 7z x -y .\php.zip -o%PHP_SDK_DIR%
|
||||
- echo update SQL connection string
|
||||
- ps: (Get-Content ${env:APPVEYOR_BUILD_FOLDER}\test\functional\pdo_sqlsrv\MsSetup.inc) | ForEach-Object { $_ -replace "TARGET_SERVER", ${env:TEST_PHP_SQL_SERVER} -replace "TARGET_DATABASE", ${env:PDOSQLSRV_DBNAME} -replace "TARGET_USERNAME", ${env:TEST_PHP_SQL_UID} -replace "TARGET_PASSWORD", ${env:TEST_PHP_SQL_PWD} } | Set-Content ${env:APPVEYOR_BUILD_FOLDER}\test\functional\pdo_sqlsrv\MsSetup.inc
|
||||
- ps: Get-Content ${env:APPVEYOR_BUILD_FOLDER}\test\functional\pdo_sqlsrv\MsSetup.inc
|
||||
|
@ -150,12 +153,6 @@ test_script:
|
|||
- python %APPVEYOR_BUILD_FOLDER%\test\functional\setup\setup_dbs.py -dbname %SQLSRV_DBNAME%
|
||||
- Echo setup test database for PDO_SQLSRV tests - %PDOSQLSRV_DBNAME%
|
||||
- python %APPVEYOR_BUILD_FOLDER%\test\functional\setup\setup_dbs.py -dbname %PDOSQLSRV_DBNAME%
|
||||
#- copy %APPVEYOR_BUILD_FOLDER%\source\shared\msodbcsql.h %APPVEYOR_BUILD_FOLDER%\test\functional\setup\
|
||||
#- python %APPVEYOR_BUILD_FOLDER%\test\functional\setup\build_ksp.py
|
||||
#- copy %APPVEYOR_BUILD_FOLDER%\test\functional\setup\*.dll %APPVEYOR_BUILD_FOLDER%\test\functional\sqlsrv\
|
||||
#- copy %APPVEYOR_BUILD_FOLDER%\test\functional\setup\*.dll %APPVEYOR_BUILD_FOLDER%\test\functional\pdo_sqlsrv\
|
||||
#- python %APPVEYOR_BUILD_FOLDER%\test\functional\setup\run_ksp.py -server %TEST_PHP_SQL_SERVER% -dbname %SQLSRV_DBNAME% -uid %TEST_PHP_SQL_UID% -pwd %TEST_PHP_SQL_PWD%
|
||||
#- python %APPVEYOR_BUILD_FOLDER%\test\functional\setup\run_ksp.py -server %TEST_PHP_SQL_SERVER% -dbname %PDOSQLSRV_DBNAME% -uid %TEST_PHP_SQL_UID% -pwd %TEST_PHP_SQL_PWD%
|
||||
- ps: >-
|
||||
If ($env:SQL_INSTANCE -Match "SQL2016") {
|
||||
Write-Host "Running phpt tests via OpenCppCoverage..."
|
||||
|
|
|
@ -14,7 +14,7 @@ To use the sample build scripts `builddrivers.py` and `buildtools.py`, install P
|
|||
|
||||
You must first be able to build PHP 7.* without including our PHP extensions. For help with building PHP 7.0* or PHP 7.1* in Windows, see the [official PHP website](https://wiki.php.net/internals/windows/stepbystepbuild). For PHP 7.2 or above, visit [PHP SDK page](https://github.com/OSTC/php-sdk-binary-tools) for new instructions.
|
||||
|
||||
The Microsoft Drivers for PHP for SQL Server have been compiled and tested with PHP 7.0.* and 7.1.* using Visual C++ 2015 as well as PHP 7.2.0 beta using Visual C++ 2017 v15.0.
|
||||
The Microsoft Drivers for PHP for SQL Server have been compiled and tested with PHP 7.0.* and 7.1.* using Visual C++ 2015 as well as PHP 7.2.1 using Visual C++ 2017 v15.5.
|
||||
|
||||
### Manually building from source
|
||||
|
||||
|
@ -57,7 +57,7 @@ PHP recommends to unzip the PHP SDK into the shortest possible path, preferrably
|
|||
|
||||
3. Interactive mode:
|
||||
* Type `py builddrivers.py` to start the interactive mode. Use lower cases to answer the following questions:
|
||||
* PHP Version (e.g. `7.1.7` or `7.2.0beta2`)
|
||||
* PHP Version (e.g. `7.1.7` or `7.2.1`)
|
||||
* 64-bit?
|
||||
* Thread safe?
|
||||
* Driver?
|
||||
|
@ -68,8 +68,8 @@ PHP recommends to unzip the PHP SDK into the shortest possible path, preferrably
|
|||
4. Use Command-line arguments
|
||||
* Type `py builddrivers.py -h` to get a list of options and their descriptions
|
||||
* For example,
|
||||
* `py builddrivers.py --PHPVER=7.0.22 --ARCH=x64 --THREAD=nts --DRIVER=sqlsrv --SOURCE`
|
||||
* `py builddrivers.py --PHPVER=7.1.8 --ARCH=x86 --THREAD=ts --DEBUG`
|
||||
* `py builddrivers.py --PHPVER=7.2.1 --ARCH=x64 --THREAD=nts --DRIVER=sqlsrv --SOURCE=C:\local\source`
|
||||
* `py builddrivers.py --PHPVER=7.1.13 --ARCH=x86 --THREAD=ts --DEBUG`
|
||||
|
||||
5. Based on the given configuration, if the script detects the presence of the PHP source directory, you can choose whether to rebuild, clean or superclean:
|
||||
* `rebuild` to build again using the same configuration (32 bit, thread safe, etc.)
|
||||
|
|
|
@ -33,7 +33,6 @@ class BuildDriver(object):
|
|||
util # BuildUtil object whose constructor takes phpver, driver, arch, thread, debug
|
||||
repo # GitHub repository
|
||||
branch # GitHub repository branch
|
||||
download_source # download source from GitHub or not
|
||||
dest_path # alternative destination for the drivers (None for development builds)
|
||||
rebuild # a boolean flag - whether the user is rebuilding
|
||||
make_clean # a boolean flag - whether make clean is necessary
|
||||
|
@ -41,16 +40,15 @@ class BuildDriver(object):
|
|||
testing # whether the user has turned on testing mode
|
||||
"""
|
||||
|
||||
def __init__(self, phpver, driver, arch, thread, debug, repo, branch, download, path, testing):
|
||||
def __init__(self, phpver, driver, arch, thread, debug, repo, branch, source, path, testing):
|
||||
self.util = BuildUtil(phpver, driver, arch, thread, debug)
|
||||
self.repo = repo
|
||||
self.branch = branch
|
||||
self.download_source = download
|
||||
self.source_path = source
|
||||
self.dest_path = path
|
||||
self.testing = testing
|
||||
self.rebuild = False
|
||||
self.make_clean = False
|
||||
self.source_path = None # None initially but will be set later if not downloading from GitHub
|
||||
|
||||
def show_config(self):
|
||||
print()
|
||||
|
@ -58,6 +56,7 @@ class BuildDriver(object):
|
|||
print('Arch: ', self.util.arch)
|
||||
print('Thread: ', self.util.thread)
|
||||
print('Driver: ', self.util.driver)
|
||||
print('Source: ', self.source_path)
|
||||
print('Debug enabled: ', self.util.debug_enabled)
|
||||
print()
|
||||
|
||||
|
@ -91,6 +90,28 @@ class BuildDriver(object):
|
|||
|
||||
os.chdir(work_dir) # change back to the working directory
|
||||
|
||||
def get_local_source(self, source_path):
|
||||
"""This assumes interactive mode (not testing) and takes care of getting
|
||||
the user's input to the path of the local source files for the drivers
|
||||
"""
|
||||
while True:
|
||||
if source_path is None:
|
||||
source = input('Enter the full path to the source folder: ')
|
||||
else:
|
||||
source = input("Hit ENTER to use '" + source_path + "' or provide another path to the source folder: ")
|
||||
if len(source) == 0:
|
||||
source = source_path
|
||||
|
||||
valid = True
|
||||
if os.path.exists(source) and os.path.exists(os.path.join(source, 'shared')):
|
||||
# Checking the existence of 'shared' folder only, assuming
|
||||
# sqlsrv and/or pdo_sqlsrv are also present if it exists
|
||||
self.source_path = source
|
||||
break
|
||||
|
||||
print("The path provided is invalid. Please re-enter.")
|
||||
return source
|
||||
|
||||
def build_extensions(self, root_dir, logfile):
|
||||
"""This takes care of getting the drivers' source files, building the drivers.
|
||||
If dest_path is defined, the binaries will be copied to the designated destinations.
|
||||
|
@ -102,28 +123,15 @@ class BuildDriver(object):
|
|||
"""
|
||||
work_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
if self.download_source:
|
||||
if self.source_path is None:
|
||||
# This will download from the specified branch on GitHub repo and copy the source
|
||||
self.util.download_msphpsql_source(repo, branch)
|
||||
else:
|
||||
# This case only happens when building for development
|
||||
while True:
|
||||
if self.source_path is None:
|
||||
source = input('Enter the full path to the Source folder: ')
|
||||
else:
|
||||
source = input("Hit ENTER to reuse '" + self.source_path + "' or provide another path to the Source folder: ")
|
||||
if len(source) == 0:
|
||||
source = self.source_path
|
||||
|
||||
valid = True
|
||||
if os.path.exists(source) and os.path.exists(os.path.join(source, 'shared')):
|
||||
# Checking the existence of 'shared' folder only, assuming
|
||||
# sqlsrv and/or pdo_sqlsrv are also present if it exists
|
||||
self.source_path = source
|
||||
break
|
||||
|
||||
print("The path provided is invalid. Please re-enter.")
|
||||
|
||||
source = self.source_path
|
||||
# Do not prompt user for input if it's in a testing mode
|
||||
if not self.testing:
|
||||
source = self.get_local_source(self.source_path)
|
||||
|
||||
print('Copying source files from', source)
|
||||
|
||||
os.system('ROBOCOPY ' + source + '\shared ' + work_dir + '\Source\shared /xx /xo ')
|
||||
|
@ -169,7 +177,10 @@ class BuildDriver(object):
|
|||
|
||||
quit = False
|
||||
while not quit:
|
||||
if not self.rebuild and not self.testing:
|
||||
if self.testing:
|
||||
self.make_clean = True
|
||||
self.util.remove_old_builds(work_dir)
|
||||
elif not self.rebuild:
|
||||
self.clean_or_remove(root_dir, work_dir)
|
||||
|
||||
logfile = self.util.get_logfile_name()
|
||||
|
@ -223,7 +234,7 @@ if __name__ == '__main__':
|
|||
parser.add_argument('--DEBUG', action='store_true', help="enable debug mode (default: False)")
|
||||
parser.add_argument('--REPO', default='Microsoft', help="GitHub repository (default: Microsoft)")
|
||||
parser.add_argument('--BRANCH', default='dev', help="GitHub repository branch (default: dev)")
|
||||
parser.add_argument('--SOURCE', action='store_true', help="get source from a local path (default: False)")
|
||||
parser.add_argument('--SOURCE', default=None, help="a local path to source file (default: None)")
|
||||
parser.add_argument('--TESTING', action='store_true', help="turns on testing mode (default: False)")
|
||||
parser.add_argument('--DESTPATH', default=None, help="an alternative destination for the drivers (default: None)")
|
||||
|
||||
|
@ -236,7 +247,7 @@ if __name__ == '__main__':
|
|||
debug = args.DEBUG
|
||||
repo = args.REPO
|
||||
branch = args.BRANCH
|
||||
download = args.SOURCE is False
|
||||
source = args.SOURCE
|
||||
path = args.DESTPATH
|
||||
testing = args.TESTING
|
||||
|
||||
|
@ -259,9 +270,7 @@ if __name__ == '__main__':
|
|||
debug_mode = input("Debug enabled? [y/n]: ")
|
||||
|
||||
answer = input("Download source from a GitHub repo? [y/n]: ")
|
||||
download = False
|
||||
if answer == 'yes' or answer == 'y' or answer == '':
|
||||
download = True
|
||||
repo = input("Name of the repo (hit enter for 'Microsoft'): ")
|
||||
branch = input("Name of the branch (hit enter for 'dev'): ")
|
||||
if repo == '':
|
||||
|
@ -282,7 +291,7 @@ if __name__ == '__main__':
|
|||
debug,
|
||||
repo,
|
||||
branch,
|
||||
download,
|
||||
source,
|
||||
path,
|
||||
testing)
|
||||
builder.build()
|
||||
|
|
|
@ -246,14 +246,13 @@ class BuildUtil(object):
|
|||
driver_dir = os.path.join(source_dir, driver)
|
||||
|
||||
if self.debug_enabled:
|
||||
# Remove the optimization flag in the config file for this driver
|
||||
# because '/O2' option is incompatible with Debug mode
|
||||
print('Removing optimization flag for', driver)
|
||||
# Adding linker flags for creating more debugging information in the binaries
|
||||
print('Adding linker flags for', driver)
|
||||
config_file = os.path.join(driver_dir, 'config.w32')
|
||||
if driver == 'sqlsrv':
|
||||
self.update_file_content(config_file, 'ADD_FLAG( "CFLAGS_SQLSRV", "/O2" );', '')
|
||||
self.update_file_content(config_file, 'ADD_FLAG( "LDFLAGS_SQLSRV", "/NXCOMPAT /DYNAMICBASE /debug /guard:cf" );', 'ADD_FLAG( "LDFLAGS_SQLSRV", "/NXCOMPAT /DYNAMICBASE /debug /guard:cf /debugtype:cv,fixup" );')
|
||||
elif driver == 'pdo_sqlsrv':
|
||||
self.update_file_content(config_file, 'ADD_FLAG( "CFLAGS_PDO_SQLSRV", "/O2" );', '')
|
||||
self.update_file_content(config_file, 'ADD_FLAG( "LDFLAGS_PDO_SQLSRV", "/NXCOMPAT /DYNAMICBASE /debug /guard:cf" );', 'ADD_FLAG( "LDFLAGS_PDO_SQLSRV", "/NXCOMPAT /DYNAMICBASE /debug /guard:cf /debugtype:cv,fixup" );')
|
||||
|
||||
# Update Template.rc
|
||||
template_file = os.path.join(driver_dir, 'template.rc')
|
||||
|
|
|
@ -1,74 +1,78 @@
|
|||
PHP_ARG_WITH(pdo_sqlsrv, for pdo_sqlsrv support,
|
||||
[ --with-pdo_sqlsrv Include pdo_sqlsrv support])
|
||||
|
||||
if test "$PHP_PDO_SQLSRV" != "no"; then
|
||||
if test "$PHP_PDO" = "no" && test "$ext_shared" = "no"; then
|
||||
AC_MSG_ERROR([PDO is not enabled! Add --enable-pdo to your configure line.])
|
||||
fi
|
||||
|
||||
ifdef([PHP_CHECK_PDO_INCLUDES],
|
||||
[
|
||||
PHP_CHECK_PDO_INCLUDES
|
||||
],[
|
||||
AC_MSG_CHECKING([for PDO includes])
|
||||
if test -f $abs_srcdir/include/php/ext/pdo/php_pdo_driver.h; then
|
||||
pdo_cv_inc_path=$abs_srcdir/ext
|
||||
elif test -f $abs_srcdir/ext/pdo/php_pdo_driver.h; then
|
||||
pdo_cv_inc_path=$abs_srcdir/ext
|
||||
elif test -f $phpincludedir/ext/pdo/php_pdo_driver.h; then
|
||||
pdo_cv_inc_path=$phpincludedir/ext
|
||||
else
|
||||
AC_MSG_ERROR([Cannot find php_pdo_driver.h.])
|
||||
fi
|
||||
AC_MSG_RESULT($pdo_cv_inc_path)
|
||||
])
|
||||
|
||||
pdo_sqlsrv_src_class="\
|
||||
pdo_dbh.cpp \
|
||||
pdo_parser.cpp \
|
||||
pdo_util.cpp \
|
||||
pdo_init.cpp \
|
||||
pdo_stmt.cpp \
|
||||
"
|
||||
|
||||
shared_src_class="\
|
||||
shared/core_conn.cpp \
|
||||
shared/core_results.cpp \
|
||||
shared/core_stream.cpp \
|
||||
shared/core_init.cpp \
|
||||
shared/core_stmt.cpp \
|
||||
shared/core_util.cpp \
|
||||
shared/FormattedPrint.cpp \
|
||||
shared/localizationimpl.cpp \
|
||||
shared/StringFunctions.cpp \
|
||||
"
|
||||
AC_MSG_CHECKING([for PDO_SQLSRV headers])
|
||||
if test -f $srcdir/ext/pdo_sqlsrv/shared/core_sqlsrv.h; then
|
||||
pdo_sqlsrv_inc_path=$srcdir/ext/pdo_sqlsrv/shared/
|
||||
elif test -f $srcdir/shared/core_sqlsrv.h; then
|
||||
pdo_sqlsrv_inc_path=$srcdir/shared/
|
||||
else
|
||||
AC_MSG_ERROR([Cannot find PDO_SQLSRV headers])
|
||||
fi
|
||||
AC_MSG_RESULT($pdo_sqlsrv_inc_path)
|
||||
|
||||
HOST_OS_ARCH=`uname`
|
||||
if test "${HOST_OS_ARCH}" = "Darwin"; then
|
||||
MACOSX_DEPLOYMENT_TARGET=`sw_vers -productVersion`
|
||||
fi
|
||||
|
||||
CXXFLAGS="$CXXFLAGS -std=c++11"
|
||||
CXXFLAGS="$CXXFLAGS -D_FORTIFY_SOURCE=2 -O2"
|
||||
CXXFLAGS="$CXXFLAGS -fstack-protector"
|
||||
PHP_REQUIRE_CXX()
|
||||
PHP_ADD_LIBRARY(stdc++, 1, PDO_SQLSRV_SHARED_LIBADD)
|
||||
PHP_ADD_LIBRARY(odbc, 1, PDO_SQLSRV_SHARED_LIBADD)
|
||||
PHP_ADD_LIBRARY(odbcinst, 1, PDO_SQLSRV_SHARED_LIBADD)
|
||||
AC_DEFINE(HAVE_PDO_SQLSRV, 1, [ ])
|
||||
PHP_ADD_INCLUDE([$pdo_sqlsrv_inc_path])
|
||||
PHP_NEW_EXTENSION(pdo_sqlsrv, $pdo_sqlsrv_src_class $shared_src_class, $ext_shared,,-I$pdo_cv_inc_path -std=c++11)
|
||||
PHP_SUBST(PDO_SQLSRV_SHARED_LIBADD)
|
||||
PHP_ADD_EXTENSION_DEP(pdo_sqlsrv, pdo)
|
||||
PHP_ADD_BUILD_DIR([$ext_builddir/shared], 1)
|
||||
fi
|
||||
|
||||
PHP_ARG_WITH(pdo_sqlsrv, for pdo_sqlsrv support,
|
||||
[ --with-pdo_sqlsrv Include pdo_sqlsrv support])
|
||||
|
||||
if test "$PHP_PDO_SQLSRV" != "no"; then
|
||||
if test "$PHP_PDO" = "no" && test "$ext_shared" = "no"; then
|
||||
AC_MSG_ERROR([PDO is not enabled! Add --enable-pdo to your configure line.])
|
||||
fi
|
||||
|
||||
ifdef([PHP_CHECK_PDO_INCLUDES],
|
||||
[
|
||||
PHP_CHECK_PDO_INCLUDES
|
||||
],[
|
||||
AC_MSG_CHECKING([for PDO includes])
|
||||
if test -f $abs_srcdir/include/php/ext/pdo/php_pdo_driver.h; then
|
||||
pdo_cv_inc_path=$abs_srcdir/ext
|
||||
elif test -f $abs_srcdir/ext/pdo/php_pdo_driver.h; then
|
||||
pdo_cv_inc_path=$abs_srcdir/ext
|
||||
elif test -f $phpincludedir/ext/pdo/php_pdo_driver.h; then
|
||||
pdo_cv_inc_path=$phpincludedir/ext
|
||||
else
|
||||
AC_MSG_ERROR([Cannot find php_pdo_driver.h.])
|
||||
fi
|
||||
AC_MSG_RESULT($pdo_cv_inc_path)
|
||||
])
|
||||
|
||||
pdo_sqlsrv_src_class="\
|
||||
pdo_dbh.cpp \
|
||||
pdo_parser.cpp \
|
||||
pdo_util.cpp \
|
||||
pdo_init.cpp \
|
||||
pdo_stmt.cpp \
|
||||
"
|
||||
|
||||
shared_src_class="\
|
||||
shared/core_conn.cpp \
|
||||
shared/core_results.cpp \
|
||||
shared/core_stream.cpp \
|
||||
shared/core_init.cpp \
|
||||
shared/core_stmt.cpp \
|
||||
shared/core_util.cpp \
|
||||
shared/FormattedPrint.cpp \
|
||||
shared/localizationimpl.cpp \
|
||||
shared/StringFunctions.cpp \
|
||||
"
|
||||
AC_MSG_CHECKING([for PDO_SQLSRV headers])
|
||||
if test -f $srcdir/ext/pdo_sqlsrv/shared/core_sqlsrv.h; then
|
||||
pdo_sqlsrv_inc_path=$srcdir/ext/pdo_sqlsrv/shared/
|
||||
elif test -f $srcdir/shared/core_sqlsrv.h; then
|
||||
pdo_sqlsrv_inc_path=$srcdir/shared/
|
||||
else
|
||||
AC_MSG_ERROR([Cannot find PDO_SQLSRV headers])
|
||||
fi
|
||||
AC_MSG_RESULT($pdo_sqlsrv_inc_path)
|
||||
|
||||
CXXFLAGS="$CXXFLAGS -std=c++11"
|
||||
CXXFLAGS="$CXXFLAGS -D_FORTIFY_SOURCE=2 -O2"
|
||||
CXXFLAGS="$CXXFLAGS -fstack-protector"
|
||||
|
||||
HOST_OS_ARCH=`uname`
|
||||
if test "${HOST_OS_ARCH}" = "Darwin"; then
|
||||
PDO_SQLSRV_SHARED_LIBADD="$PDO_SQLSRV_SHARED_LIBADD -Wl,-bind_at_load"
|
||||
MACOSX_DEPLOYMENT_TARGET=`sw_vers -productVersion`
|
||||
else
|
||||
PDO_SQLSRV_SHARED_LIBADD="$PDO_SQLSRV_SHARED_LIBADD -Wl,-z,now"
|
||||
fi
|
||||
|
||||
PHP_REQUIRE_CXX()
|
||||
PHP_ADD_LIBRARY(stdc++, 1, PDO_SQLSRV_SHARED_LIBADD)
|
||||
PHP_ADD_LIBRARY(odbc, 1, PDO_SQLSRV_SHARED_LIBADD)
|
||||
PHP_ADD_LIBRARY(odbcinst, 1, PDO_SQLSRV_SHARED_LIBADD)
|
||||
AC_DEFINE(HAVE_PDO_SQLSRV, 1, [ ])
|
||||
PHP_ADD_INCLUDE([$pdo_sqlsrv_inc_path])
|
||||
PHP_NEW_EXTENSION(pdo_sqlsrv, $pdo_sqlsrv_src_class $shared_src_class, $ext_shared,,-I$pdo_cv_inc_path -std=c++11)
|
||||
PHP_SUBST(PDO_SQLSRV_SHARED_LIBADD)
|
||||
PHP_ADD_EXTENSION_DEP(pdo_sqlsrv, pdo)
|
||||
PHP_ADD_BUILD_DIR([$ext_builddir/shared], 1)
|
||||
fi
|
||||
|
||||
|
|
|
@ -30,11 +30,11 @@ if( PHP_PDO_SQLSRV != "no" ) {
|
|||
CHECK_HEADER_ADD_INCLUDE("sql.h", "CFLAGS_PDO_SQLSRV_ODBC");
|
||||
CHECK_HEADER_ADD_INCLUDE("sqlext.h", "CFLAGS_PDO_SQLSRV_ODBC");
|
||||
ADD_SOURCES( configure_module_dirname + "\\shared", shared_src_class, "pdo_sqlsrv" );
|
||||
ADD_FLAG( "LDFLAGS_PDO_SQLSRV", "/NXCOMPAT /DYNAMICBASE /debug" );
|
||||
ADD_FLAG( "LDFLAGS_PDO_SQLSRV", "/NXCOMPAT /DYNAMICBASE /debug /guard:cf" );
|
||||
ADD_FLAG( "CFLAGS_PDO_SQLSRV", "/EHsc" );
|
||||
ADD_FLAG( "CFLAGS_PDO_SQLSRV", "/GS" );
|
||||
ADD_FLAG( "CFLAGS_PDO_SQLSRV", "/Zi" );
|
||||
ADD_FLAG( "CFLAGS_PDO_SQLSRV", "/O2" );
|
||||
if (PHP_DEBUG != "yes") ADD_FLAG( "CFLAGS_PDO_SQLSRV", "/guard:cf /O2" );
|
||||
ADD_FLAG( "CFLAGS_PDO_SQLSRV", "/D ZEND_WIN32_FORCE_INLINE" );
|
||||
ADD_EXTENSION_DEP('pdo_sqlsrv', 'pdo');
|
||||
EXTENSION("pdo_sqlsrv", pdo_sqlsrv_src_class, PHP_PDO_SQLSRV_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
|
||||
|
|
|
@ -42,13 +42,9 @@ const char ApplicationIntent[] = "ApplicationIntent";
|
|||
const char AttachDBFileName[] = "AttachDbFileName";
|
||||
const char ConnectionPooling[] = "ConnectionPooling";
|
||||
const char Authentication[] = "Authentication";
|
||||
const char ColumnEncryption[] = "ColumnEncryption";
|
||||
const char Driver[] = "Driver";
|
||||
const char CEKeystoreProvider[] = "CEKeystoreProvider";
|
||||
const char CEKeystoreName[] = "CEKeystoreName";
|
||||
const char CEKeystoreEncryptKey[] = "CEKeystoreEncryptKey";
|
||||
|
||||
#ifdef _WIN32
|
||||
const char ColumnEncryption[] = "ColumnEncryption";
|
||||
const char ConnectRetryCount[] = "ConnectRetryCount";
|
||||
const char ConnectRetryInterval[] = "ConnectRetryInterval";
|
||||
#endif // _WIN32
|
||||
|
@ -226,15 +222,6 @@ const connection_option PDO_CONN_OPTS[] = {
|
|||
CONN_ATTR_BOOL,
|
||||
conn_null_func::func
|
||||
},
|
||||
{
|
||||
PDOConnOptionNames::ColumnEncryption,
|
||||
sizeof(PDOConnOptionNames::ColumnEncryption),
|
||||
SQLSRV_CONN_OPTION_COLUMNENCRYPTION,
|
||||
ODBCConnOptions::ColumnEncryption,
|
||||
sizeof(ODBCConnOptions::ColumnEncryption),
|
||||
CONN_ATTR_STRING,
|
||||
column_encryption_set_func::func
|
||||
},
|
||||
{
|
||||
PDOConnOptionNames::Driver,
|
||||
sizeof(PDOConnOptionNames::Driver),
|
||||
|
@ -244,34 +231,16 @@ const connection_option PDO_CONN_OPTS[] = {
|
|||
CONN_ATTR_STRING,
|
||||
driver_set_func::func
|
||||
},
|
||||
{
|
||||
PDOConnOptionNames::CEKeystoreProvider,
|
||||
sizeof(PDOConnOptionNames::CEKeystoreProvider),
|
||||
SQLSRV_CONN_OPTION_CEKEYSTORE_PROVIDER,
|
||||
ODBCConnOptions::CEKeystoreProvider,
|
||||
sizeof(ODBCConnOptions::CEKeystoreProvider),
|
||||
CONN_ATTR_STRING,
|
||||
ce_ksp_provider_set_func::func
|
||||
},
|
||||
{
|
||||
PDOConnOptionNames::CEKeystoreName,
|
||||
sizeof(PDOConnOptionNames::CEKeystoreName),
|
||||
SQLSRV_CONN_OPTION_CEKEYSTORE_NAME,
|
||||
ODBCConnOptions::CEKeystoreName,
|
||||
sizeof(ODBCConnOptions::CEKeystoreName),
|
||||
CONN_ATTR_STRING,
|
||||
ce_ksp_provider_set_func::func
|
||||
},
|
||||
{
|
||||
PDOConnOptionNames::CEKeystoreEncryptKey,
|
||||
sizeof(PDOConnOptionNames::CEKeystoreEncryptKey),
|
||||
SQLSRV_CONN_OPTION_CEKEYSTORE_ENCRYPT_KEY,
|
||||
ODBCConnOptions::CEKeystoreEncryptKey,
|
||||
sizeof(ODBCConnOptions::CEKeystoreEncryptKey),
|
||||
CONN_ATTR_STRING,
|
||||
ce_ksp_provider_set_func::func
|
||||
},
|
||||
#ifdef _WIN32
|
||||
{
|
||||
PDOConnOptionNames::ColumnEncryption,
|
||||
sizeof(PDOConnOptionNames::ColumnEncryption),
|
||||
SQLSRV_CONN_OPTION_COLUMNENCRYPTION,
|
||||
ODBCConnOptions::ColumnEncryption,
|
||||
sizeof(ODBCConnOptions::ColumnEncryption),
|
||||
CONN_ATTR_STRING,
|
||||
column_encryption_set_func::func
|
||||
},
|
||||
{
|
||||
PDOConnOptionNames::ConnectRetryCount,
|
||||
sizeof( PDOConnOptionNames::ConnectRetryCount ),
|
||||
|
|
|
@ -59,7 +59,7 @@ pdo_error PDO_ERRORS[] = {
|
|||
{ IMSSP, (SQLCHAR*) "This extension requires the Microsoft ODBC Driver for SQL Server to "
|
||||
"communicate with SQL Server. Access the following URL to download the ODBC Driver for SQL Server "
|
||||
"for %1!s!: "
|
||||
"http://go.microsoft.com/fwlink/?LinkId=163712", -1, true }
|
||||
"https://go.microsoft.com/fwlink/?LinkId=163712", -1, true }
|
||||
},
|
||||
{
|
||||
SQLSRV_ERROR_ZEND_HASH,
|
||||
|
@ -381,22 +381,6 @@ pdo_error PDO_ERRORS[] = {
|
|||
PDO_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION,
|
||||
{ IMSSP, (SQLCHAR*) "Invalid option for the Authentication keyword. Only SqlPassword or ActiveDirectoryPassword is supported.", -73, false }
|
||||
},
|
||||
{
|
||||
SQLSRV_ERROR_KEYSTORE_NAME_MISSING,
|
||||
{ IMSSP, (SQLCHAR*) "The name of the custom keystore provider is missing.", -74, false}
|
||||
},
|
||||
{
|
||||
SQLSRV_ERROR_KEYSTORE_PATH_MISSING,
|
||||
{ IMSSP, (SQLCHAR*) "The path to the custom keystore provider is missing.", -75, false}
|
||||
},
|
||||
{
|
||||
SQLSRV_ERROR_KEYSTORE_KEY_MISSING,
|
||||
{ IMSSP, (SQLCHAR*) "The encryption key for the custom keystore provider is missing.", -76, false}
|
||||
},
|
||||
{
|
||||
SQLSRV_ERROR_KEYSTORE_INVALID_VALUE,
|
||||
{ IMSSP, (SQLCHAR*) "Invalid value for loading a custom keystore provider.", -77, false}
|
||||
},
|
||||
{
|
||||
SQLSRV_ERROR_CE_DRIVER_REQUIRED,
|
||||
{ IMSSP, (SQLCHAR*) "The Always Encrypted feature requires Microsoft ODBC Driver 17 for SQL Server.", -78, false }
|
||||
|
|
|
@ -50,7 +50,7 @@ const char* PROCESSOR_ARCH[] = { "x86", "x64", "ia64" };
|
|||
|
||||
// ODBC driver names.
|
||||
// the order of this list should match the order of DRIVER_VERSION enum
|
||||
std::vector<std::string> CONNECTION_STRING_DRIVER_NAME{ "Driver={ODBC Driver 13 for SQL Server};", "Driver={ODBC Driver 11 for SQL Server};", "Driver={ODBC Driver 17 for SQL Server};" };
|
||||
std::vector<std::string> CONNECTION_STRING_DRIVER_NAME{ "Driver={ODBC Driver 17 for SQL Server};", "Driver={ODBC Driver 13 for SQL Server};", "Driver={ODBC Driver 11 for SQL Server};" };
|
||||
|
||||
// default options if only the server is specified
|
||||
const char CONNECTION_STRING_DEFAULT_OPTIONS[] = "Mars_Connection={Yes};";
|
||||
|
@ -71,7 +71,6 @@ const char* get_processor_arch( void );
|
|||
void get_server_version( _Inout_ sqlsrv_conn* conn, _Outptr_result_buffer_(len) char** server_version, _Out_ SQLSMALLINT& len TSRMLS_DC );
|
||||
connection_option const* get_connection_option( sqlsrv_conn* conn, _In_ const char* key, _In_ SQLULEN key_len TSRMLS_DC );
|
||||
void common_conn_str_append_func( _In_z_ const char* odbc_name, _In_reads_(val_len) const char* val, _Inout_ size_t val_len, _Inout_ std::string& conn_str TSRMLS_DC );
|
||||
void load_configure_ksp( _Inout_ sqlsrv_conn* conn TSRMLS_DC );
|
||||
}
|
||||
|
||||
// core_sqlsrv_connect
|
||||
|
@ -183,11 +182,11 @@ sqlsrv_conn* core_sqlsrv_connect( _In_ sqlsrv_context& henv_cp, _In_ sqlsrv_cont
|
|||
// https://docs.microsoft.com/en-us/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server#microsoft-odbc-driver-11-for-sql-server-on-linux
|
||||
|
||||
DRIVER_VERSION odbc_version = ODBC_DRIVER_UNKNOWN;
|
||||
if( core_search_odbc_driver_unix( ODBC_DRIVER_13 ) ) {
|
||||
odbc_version = ODBC_DRIVER_13;
|
||||
}
|
||||
else if ( core_search_odbc_driver_unix( ODBC_DRIVER_17 ) ) {
|
||||
if( core_search_odbc_driver_unix( ODBC_DRIVER_17 ) ) {
|
||||
odbc_version = ODBC_DRIVER_17;
|
||||
}
|
||||
else if ( core_search_odbc_driver_unix( ODBC_DRIVER_13 ) ) {
|
||||
odbc_version = ODBC_DRIVER_13;
|
||||
}
|
||||
|
||||
CHECK_CUSTOM_ERROR( odbc_version == ODBC_DRIVER_UNKNOWN, conn, SQLSRV_ERROR_DRIVER_NOT_INSTALLED, get_processor_arch() ) {
|
||||
|
@ -246,8 +245,6 @@ sqlsrv_conn* core_sqlsrv_connect( _In_ sqlsrv_context& henv_cp, _In_ sqlsrv_cont
|
|||
throw core::CoreException();
|
||||
}
|
||||
|
||||
load_configure_ksp( conn );
|
||||
|
||||
// determine the version of the server we're connected to. The server version is left in the
|
||||
// connection upon return.
|
||||
//
|
||||
|
@ -935,66 +932,6 @@ void determine_server_version( _Inout_ sqlsrv_conn* conn TSRMLS_DC )
|
|||
conn->server_version = version_major;
|
||||
}
|
||||
|
||||
// Column Encryption feature: if a custom keystore provider is specified,
|
||||
// load and configure it when column encryption is enabled, but this step has
|
||||
// to be executed after the connection has been established
|
||||
void load_configure_ksp( _Inout_ sqlsrv_conn* conn TSRMLS_DC )
|
||||
{
|
||||
// If column encryption is not enabled simply do nothing. Otherwise, check if a custom keystore provider
|
||||
// is required for encryption or decryption. Note, in order to load and configure a custom keystore provider,
|
||||
// all KSP fields in conn->ce_option must be defined.
|
||||
if ( ! conn->ce_option.enabled || ! conn->ce_option.ksp_required )
|
||||
return;
|
||||
|
||||
// Do something like the following sample
|
||||
// use the KSP related fields in conn->ce_option
|
||||
// CEKEYSTOREDATA is defined in msodbcsql.h
|
||||
// https://docs.microsoft.com/en-us/sql/connect/odbc/custom-keystore-providers
|
||||
|
||||
CHECK_CUSTOM_ERROR( conn->ce_option.ksp_name == NULL, conn, SQLSRV_ERROR_KEYSTORE_NAME_MISSING) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
CHECK_CUSTOM_ERROR( conn->ce_option.ksp_path == NULL, conn, SQLSRV_ERROR_KEYSTORE_PATH_MISSING) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
CHECK_CUSTOM_ERROR( conn->ce_option.key_size == 0, conn, SQLSRV_ERROR_KEYSTORE_KEY_MISSING) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
char* ksp_name = Z_STRVAL_P( conn->ce_option.ksp_name );
|
||||
char* ksp_path = Z_STRVAL_P( conn->ce_option.ksp_path );
|
||||
unsigned int name_len = static_cast<unsigned int>( Z_STRLEN_P( conn->ce_option.ksp_name ));
|
||||
unsigned int key_size = static_cast<unsigned int>( conn->ce_option.key_size );
|
||||
|
||||
sqlsrv_malloc_auto_ptr<unsigned char> ksp_data;
|
||||
|
||||
ksp_data = reinterpret_cast<unsigned char*>( sqlsrv_malloc( sizeof( CEKEYSTOREDATA ) + key_size ) );
|
||||
|
||||
CEKEYSTOREDATA *pKsd = reinterpret_cast<CEKEYSTOREDATA*>( ksp_data.get() );
|
||||
|
||||
pKsd->dataSize = key_size;
|
||||
|
||||
// First, convert conn->ce_option.ksp_name to a WCHAR version
|
||||
unsigned int wname_len = 0;
|
||||
sqlsrv_malloc_auto_ptr<SQLWCHAR> wksp_name;
|
||||
wksp_name = utf16_string_from_mbcs_string( SQLSRV_ENCODING_UTF8, ksp_name, name_len, &wname_len );
|
||||
|
||||
CHECK_CUSTOM_ERROR( wksp_name == 0, conn, SQLSRV_ERROR_CONNECT_STRING_ENCODING_TRANSLATE ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
pKsd->name = (wchar_t *) wksp_name.get();
|
||||
|
||||
// Next, extract the character string from conn->ce_option.ksp_encrypt_key into encrypt_key
|
||||
char* encrypt_key = Z_STRVAL_P( conn->ce_option.ksp_encrypt_key );
|
||||
memcpy_s( pKsd->data, key_size * sizeof( char ) , encrypt_key, key_size );
|
||||
|
||||
core::SQLSetConnectAttr( conn, SQL_COPT_SS_CEKEYSTOREPROVIDER, ksp_path, SQL_NTS );
|
||||
core::SQLSetConnectAttr( conn, SQL_COPT_SS_CEKEYSTOREDATA, reinterpret_cast<SQLPOINTER>( pKsd ), SQL_IS_POINTER );
|
||||
}
|
||||
|
||||
void common_conn_str_append_func( _In_z_ const char* odbc_name, _In_reads_(val_len) const char* val, _Inout_ size_t val_len, _Inout_ std::string& conn_str TSRMLS_DC )
|
||||
{
|
||||
// wrap a connection option in a quote. It is presumed that any character that need to be escaped will
|
||||
|
@ -1068,36 +1005,6 @@ void column_encryption_set_func::func( _In_ connection_option const* option, _In
|
|||
conn_str += ";";
|
||||
}
|
||||
|
||||
void ce_ksp_provider_set_func::func( _In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str TSRMLS_DC )
|
||||
{
|
||||
SQLSRV_ASSERT( Z_TYPE_P( value ) == IS_STRING, "Wrong zval type for this keyword" )
|
||||
|
||||
size_t value_len = Z_STRLEN_P( value );
|
||||
|
||||
CHECK_CUSTOM_ERROR( value_len == 0, conn, SQLSRV_ERROR_KEYSTORE_INVALID_VALUE ) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
switch ( option->conn_option_key ) {
|
||||
case SQLSRV_CONN_OPTION_CEKEYSTORE_PROVIDER:
|
||||
conn->ce_option.ksp_path = value;
|
||||
conn->ce_option.ksp_required = true;
|
||||
break;
|
||||
case SQLSRV_CONN_OPTION_CEKEYSTORE_NAME:
|
||||
conn->ce_option.ksp_name = value;
|
||||
conn->ce_option.ksp_required = true;
|
||||
break;
|
||||
case SQLSRV_CONN_OPTION_CEKEYSTORE_ENCRYPT_KEY:
|
||||
conn->ce_option.ksp_encrypt_key = value;
|
||||
conn->ce_option.key_size = value_len;
|
||||
conn->ce_option.ksp_required = true;
|
||||
break;
|
||||
default:
|
||||
SQLSRV_ASSERT(false, "ce_ksp_provider_set_func: Invalid KSP option!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// helper function to evaluate whether a string value is true or false.
|
||||
// Values = ("true" or "1") are treated as true values. Everything else is treated as false.
|
||||
// Returns 1 for true and 0 for false.
|
||||
|
|
|
@ -83,7 +83,7 @@ bool get_bit( _In_ void* ptr, _In_ unsigned int bit )
|
|||
|
||||
// read in LOB field during buffered result creation
|
||||
SQLPOINTER read_lob_field( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, _In_ sqlsrv_buffered_result_set::meta_data& meta,
|
||||
_In_ zend_long mem_used, _In_ size_t row_count TSRMLS_DC );
|
||||
_In_ zend_long mem_used TSRMLS_DC );
|
||||
|
||||
// dtor for each row in the cache
|
||||
void cache_row_dtor( _In_ zval* data );
|
||||
|
@ -687,7 +687,7 @@ sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( _Inout_ sqlsrv_stmt* stm
|
|||
|
||||
out_buffer_length = &out_buffer_temp;
|
||||
SQLPOINTER* lob_addr = reinterpret_cast<SQLPOINTER*>( &row[ meta[i].offset ] );
|
||||
*lob_addr = read_lob_field( stmt, i, meta[i], mem_used, row_count TSRMLS_CC );
|
||||
*lob_addr = read_lob_field( stmt, i, meta[i], mem_used TSRMLS_CC );
|
||||
// a NULL pointer means NULL field
|
||||
if( *lob_addr == NULL ) {
|
||||
*out_buffer_length = SQL_NULL_DATA;
|
||||
|
@ -1498,7 +1498,7 @@ void cache_row_dtor( _In_ zval* data )
|
|||
}
|
||||
|
||||
SQLPOINTER read_lob_field( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, _In_ sqlsrv_buffered_result_set::meta_data& meta,
|
||||
_In_ zend_long mem_used, _In_ size_t row_count TSRMLS_DC )
|
||||
_In_ zend_long mem_used TSRMLS_DC )
|
||||
{
|
||||
SQLSMALLINT extra = 0;
|
||||
SQLULEN* output_buffer_len = NULL;
|
||||
|
@ -1563,19 +1563,7 @@ SQLPOINTER read_lob_field( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_in
|
|||
|
||||
SQLSRV_ASSERT( SQL_SUCCEEDED( r ), "Unknown SQL error not triggered" );
|
||||
|
||||
if ( stmt->conn->ce_option.enabled == true ) {
|
||||
// cursor type SQLSRV_CURSOR_BUFFERED has to be FORWARD_ONLY
|
||||
// thus has to close and reopen cursor to reset the cursor buffer
|
||||
core::SQLCloseCursor(stmt);
|
||||
core::SQLExecute(stmt);
|
||||
// FETCH_NEXT until the cursor reaches the row that it was at
|
||||
for (int i = 0; i <= row_count; i++) {
|
||||
core::SQLFetchScroll(stmt, SQL_FETCH_NEXT, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
already_read += to_read - already_read;
|
||||
}
|
||||
already_read += to_read - already_read;
|
||||
// if the type of the field returns the total to be read, we use that and preallocate the buffer
|
||||
if( last_field_len != SQL_NO_TOTAL ) {
|
||||
|
||||
|
|
|
@ -1043,10 +1043,10 @@ enum SERVER_VERSION {
|
|||
enum DRIVER_VERSION {
|
||||
ODBC_DRIVER_UNKNOWN = -1,
|
||||
FIRST = 0,
|
||||
ODBC_DRIVER_13 = FIRST,
|
||||
ODBC_DRIVER_11 = 1,
|
||||
ODBC_DRIVER_17 = 2,
|
||||
LAST = ODBC_DRIVER_17
|
||||
ODBC_DRIVER_17 = FIRST,
|
||||
ODBC_DRIVER_13 = 1,
|
||||
ODBC_DRIVER_11 = 2,
|
||||
LAST = ODBC_DRIVER_11
|
||||
};
|
||||
|
||||
// forward decl
|
||||
|
@ -1056,13 +1056,8 @@ struct stmt_option;
|
|||
// This holds the various details of column encryption.
|
||||
struct col_encryption_option {
|
||||
bool enabled; // column encryption enabled, false by default
|
||||
zval_auto_ptr ksp_name; // keystore provider name
|
||||
zval_auto_ptr ksp_path; // keystore provider path to the dynamically linked libary (either a *.dll or *.so)
|
||||
zval_auto_ptr ksp_encrypt_key; // the encryption key used to configure the keystore provider
|
||||
size_t key_size; // the length of ksp_encrypt_key without the NULL terminator
|
||||
bool ksp_required; // a keystore provider is required to enable column encryption, false by default
|
||||
|
||||
col_encryption_option() : enabled( false ), key_size ( 0 ), ksp_required( false )
|
||||
col_encryption_option() : enabled( false )
|
||||
{
|
||||
}
|
||||
};
|
||||
|
@ -1109,14 +1104,11 @@ const char APP[] = "APP";
|
|||
const char ApplicationIntent[] = "ApplicationIntent";
|
||||
const char AttachDBFileName[] = "AttachDbFileName";
|
||||
const char Authentication[] = "Authentication";
|
||||
const char ColumnEncryption[] = "ColumnEncryption";
|
||||
const char Driver[] = "Driver";
|
||||
const char CEKeystoreProvider[] = "CEKeystoreProvider";
|
||||
const char CEKeystoreName[] = "CEKeystoreName";
|
||||
const char CEKeystoreEncryptKey[] = "CEKeystoreEncryptKey";
|
||||
const char CharacterSet[] = "CharacterSet";
|
||||
const char ConnectionPooling[] = "ConnectionPooling";
|
||||
#ifdef _WIN32
|
||||
const char ColumnEncryption[] = "ColumnEncryption";
|
||||
const char ConnectRetryCount[] = "ConnectRetryCount";
|
||||
const char ConnectRetryInterval[] = "ConnectRetryInterval";
|
||||
#endif // _WIN32
|
||||
|
@ -1380,8 +1372,6 @@ struct sqlsrv_stmt : public sqlsrv_context {
|
|||
bool past_fetch_end; // Core_sqlsrv_fetch sets this field when the statement goes beyond the last row
|
||||
sqlsrv_result_set* current_results; // Current result set
|
||||
SQLULEN cursor_type; // Type of cursor for the current result set
|
||||
int fwd_row_index; // fwd_row_index is the current row index, SQL_CURSOR_FORWARD_ONLY
|
||||
int curr_result_set; // the current active result set, 0 by default but will be incremented by core_sqlsrv_next_result
|
||||
bool has_rows; // Has_rows is set if there are actual rows in the row set
|
||||
bool fetch_called; // Used by core_sqlsrv_get_field to return an informative error if fetch not yet called
|
||||
int last_field_index; // last field retrieved by core_sqlsrv_get_field
|
||||
|
@ -1711,10 +1701,6 @@ enum SQLSRV_ERROR_CODES {
|
|||
SQLSRV_ERROR_FIELD_INDEX_ERROR,
|
||||
SQLSRV_ERROR_BUFFER_LIMIT_EXCEEDED,
|
||||
SQLSRV_ERROR_INVALID_BUFFER_LIMIT,
|
||||
SQLSRV_ERROR_KEYSTORE_NAME_MISSING,
|
||||
SQLSRV_ERROR_KEYSTORE_PATH_MISSING,
|
||||
SQLSRV_ERROR_KEYSTORE_KEY_MISSING,
|
||||
SQLSRV_ERROR_KEYSTORE_INVALID_VALUE,
|
||||
SQLSRV_ERROR_OUTPUT_PARAM_TYPES_NOT_SUPPORTED,
|
||||
SQLSRV_ERROR_ENCRYPTED_STREAM_FETCH,
|
||||
|
||||
|
|
|
@ -64,7 +64,6 @@ struct col_cache {
|
|||
};
|
||||
|
||||
const int INITIAL_FIELD_STRING_LEN = 2048; // base allocation size when retrieving a string field
|
||||
const int INITIAL_AE_FIELD_STRING_LEN = 8000; // base allocation size when retrieving a string field when AE is enabled
|
||||
|
||||
// UTF-8 tags for byte length of characters, used by streams to make sure we don't clip a character in between reads
|
||||
const unsigned int UTF8_MIDBYTE_MASK = 0xc0;
|
||||
|
@ -117,7 +116,6 @@ void resize_output_buffer_if_necessary( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval*
|
|||
_In_ SQLSMALLINT c_type, _In_ SQLSMALLINT sql_type, _In_ SQLULEN column_size, _In_ SQLSMALLINT decimal_digits,
|
||||
_Out_writes_(buffer_len) SQLPOINTER& buffer, _Out_ SQLLEN& buffer_len TSRMLS_DC );
|
||||
void adjustInputPrecision( _Inout_ zval* param_z, _In_ SQLSMALLINT decimal_digits );
|
||||
bool reset_ae_stream_cursor( _Inout_ sqlsrv_stmt* stmt );
|
||||
void save_output_param_for_later( _Inout_ sqlsrv_stmt* stmt, _Inout_ sqlsrv_output_param& param TSRMLS_DC );
|
||||
// send all the stream data
|
||||
void send_param_streams( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC );
|
||||
|
@ -137,8 +135,6 @@ sqlsrv_stmt::sqlsrv_stmt( _In_ sqlsrv_conn* c, _In_ SQLHANDLE handle, _In_ error
|
|||
past_fetch_end( false ),
|
||||
current_results( NULL ),
|
||||
cursor_type( SQL_CURSOR_FORWARD_ONLY ),
|
||||
fwd_row_index( -1 ),
|
||||
curr_result_set( 0 ),
|
||||
has_rows( false ),
|
||||
fetch_called( false ),
|
||||
last_field_index( -1 ),
|
||||
|
@ -221,7 +217,6 @@ void sqlsrv_stmt::free_param_data( TSRMLS_D )
|
|||
void sqlsrv_stmt::new_result_set( TSRMLS_D )
|
||||
{
|
||||
this->fetch_called = false;
|
||||
this->fwd_row_index = -1;
|
||||
this->has_rows = false;
|
||||
this->past_next_result_end = false;
|
||||
this->past_fetch_end = false;
|
||||
|
@ -717,9 +712,9 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
|
|||
if ( stmt->conn->ce_option.enabled && sql_type == SQL_TYPE_TIMESTAMP )
|
||||
{
|
||||
if( decimal_digits == 3 )
|
||||
core::SQLSetDescField( stmt, param_num + 1, SQL_CA_SS_SERVER_TYPE, (SQLPOINTER)SQL_SS_TYPE_DATETIME, 0 );
|
||||
core::SQLSetDescField( stmt, param_num + 1, SQL_CA_SS_SERVER_TYPE, (SQLPOINTER)SQL_SS_TYPE_DATETIME, SQL_IS_INTEGER );
|
||||
else if (decimal_digits == 0)
|
||||
core::SQLSetDescField( stmt, param_num + 1, SQL_CA_SS_SERVER_TYPE, (SQLPOINTER)SQL_SS_TYPE_SMALLDATETIME, 0 );
|
||||
core::SQLSetDescField( stmt, param_num + 1, SQL_CA_SS_SERVER_TYPE, (SQLPOINTER)SQL_SS_TYPE_SMALLDATETIME, SQL_IS_INTEGER );
|
||||
}
|
||||
}
|
||||
catch( core::CoreException& e ){
|
||||
|
@ -858,10 +853,6 @@ bool core_sqlsrv_fetch( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orient
|
|||
// SQLFetchScroll uses a 1 based offset, otherwise for relative, just use the fetch_offset provided.
|
||||
SQLRETURN r = stmt->current_results->fetch( fetch_orientation, ( fetch_orientation == SQL_FETCH_RELATIVE ) ? fetch_offset : fetch_offset + 1 TSRMLS_CC );
|
||||
|
||||
// when AE is enabled, will keep track of the number of rows being fetched so far such that the cursor can be reset back to its original position when getting stream data
|
||||
if ( stmt->cursor_type == SQL_CURSOR_FORWARD_ONLY && stmt->conn->ce_option.enabled == true ) {
|
||||
stmt->fwd_row_index++;
|
||||
}
|
||||
if( r == SQL_NO_DATA ) {
|
||||
// if this is a forward only cursor, mark that we've passed the end so future calls result in an error
|
||||
if( stmt->cursor_type == SQL_CURSOR_FORWARD_ONLY ) {
|
||||
|
@ -1121,13 +1112,9 @@ void core_sqlsrv_next_result( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC, _In_ bool fin
|
|||
|
||||
// mark we are past the end of all results
|
||||
stmt->past_next_result_end = true;
|
||||
|
||||
// reset the current active result set
|
||||
stmt->curr_result_set = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
stmt->curr_result_set++;
|
||||
stmt->new_result_set( TSRMLS_C );
|
||||
}
|
||||
catch( core::CoreException& e ) {
|
||||
|
@ -1711,10 +1698,6 @@ void core_get_field_common( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_i
|
|||
// for how these fields are used.
|
||||
case SQLSRV_PHPTYPE_STREAM:
|
||||
{
|
||||
CHECK_CUSTOM_ERROR(stmt->conn->ce_option.enabled, stmt, SQLSRV_ERROR_ENCRYPTED_STREAM_FETCH) {
|
||||
throw core::CoreException();
|
||||
}
|
||||
|
||||
php_stream* stream = NULL;
|
||||
sqlsrv_stream* ss = NULL;
|
||||
SQLLEN sql_type;
|
||||
|
@ -2246,11 +2229,6 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind
|
|||
break;
|
||||
}
|
||||
|
||||
if( stmt->conn->ce_option.enabled ) {
|
||||
// when AE is enabled, increase the intial field len
|
||||
intial_field_len = INITIAL_AE_FIELD_STRING_LEN;
|
||||
}
|
||||
|
||||
col_cache* cached = NULL;
|
||||
if ( NULL != ( cached = static_cast< col_cache* >( zend_hash_index_find_ptr( Z_ARRVAL( stmt->col_cache ), static_cast< zend_ulong >( field_index ))))) {
|
||||
sql_field_type = cached->sql_type;
|
||||
|
@ -2321,32 +2299,17 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind
|
|||
|
||||
field_value_temp = static_cast<char*>( sqlsrv_realloc( field_value_temp, field_len_temp + extra + 1 ));
|
||||
|
||||
// reset AE stream fetch buffer
|
||||
if ( reset_ae_stream_cursor( stmt )){
|
||||
// fetch the original column again with a bigger buffer length
|
||||
r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp, field_len_temp + extra,
|
||||
&dummy_field_len, false /*handle_warning*/ TSRMLS_CC );
|
||||
// if field_len_temp was bit enough to hold all data, dummy_field_len contain the actual amount retrieved,
|
||||
// not SQL_NO_TOTAL
|
||||
if ( dummy_field_len != SQL_NO_TOTAL )
|
||||
field_len_temp = dummy_field_len;
|
||||
else
|
||||
field_len_temp += initial_field_len;
|
||||
}
|
||||
else {
|
||||
field_len_temp -= initial_field_len;
|
||||
field_len_temp -= initial_field_len;
|
||||
|
||||
// Get the rest of the data.
|
||||
r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp + initial_field_len,
|
||||
field_len_temp + extra, &dummy_field_len,
|
||||
false /*handle_warning*/ TSRMLS_CC );
|
||||
// the last packet will contain the actual amount retrieved, not SQL_NO_TOTAL
|
||||
// so we calculate the actual length of the string with that.
|
||||
if ( dummy_field_len != SQL_NO_TOTAL )
|
||||
field_len_temp += dummy_field_len;
|
||||
else
|
||||
field_len_temp += initial_field_len;
|
||||
}
|
||||
// Get the rest of the data.
|
||||
r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp + initial_field_len,
|
||||
field_len_temp + extra, &dummy_field_len, false /*handle_warning*/ TSRMLS_CC );
|
||||
// the last packet will contain the actual amount retrieved, not SQL_NO_TOTAL
|
||||
// so we calculate the actual length of the string with that.
|
||||
if ( dummy_field_len != SQL_NO_TOTAL )
|
||||
field_len_temp += dummy_field_len;
|
||||
else
|
||||
field_len_temp += initial_field_len;
|
||||
|
||||
if( r == SQL_SUCCESS_WITH_INFO ) {
|
||||
core::SQLGetDiagField( stmt, 1, SQL_DIAG_SQLSTATE, state, SQL_SQLSTATE_BUFSIZE, &len
|
||||
|
@ -2360,22 +2323,13 @@ void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_ind
|
|||
// allocate field_len_temp (which is the field length retrieved from the first SQLGetData
|
||||
field_value_temp = static_cast<char*>( sqlsrv_realloc( field_value_temp, field_len_temp + extra + 1 ));
|
||||
|
||||
// reset AE stream fetch buffer
|
||||
if ( reset_ae_stream_cursor( stmt ) ) {
|
||||
// fetch the original column again with a bigger buffer length
|
||||
r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp, field_len_temp + extra,
|
||||
&dummy_field_len, false /*handle_warning*/ TSRMLS_CC );
|
||||
}
|
||||
else {
|
||||
// We have already recieved intial_field_len size data.
|
||||
field_len_temp -= intial_field_len;
|
||||
// We have already received intial_field_len size data.
|
||||
field_len_temp -= intial_field_len;
|
||||
|
||||
// Get the rest of the data.
|
||||
r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp + intial_field_len,
|
||||
field_len_temp + extra, &dummy_field_len,
|
||||
true /*handle_warning*/ TSRMLS_CC );
|
||||
field_len_temp += intial_field_len;
|
||||
}
|
||||
// Get the rest of the data.
|
||||
r = stmt->current_results->get_data( field_index + 1, c_type, field_value_temp + intial_field_len,
|
||||
field_len_temp + extra, &dummy_field_len, true /*handle_warning*/ TSRMLS_CC );
|
||||
field_len_temp += intial_field_len;
|
||||
|
||||
if( dummy_field_len == SQL_NULL_DATA ) {
|
||||
field_value = NULL;
|
||||
|
@ -2637,31 +2591,9 @@ void resize_output_buffer_if_necessary( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval*
|
|||
}
|
||||
}
|
||||
|
||||
bool reset_ae_stream_cursor( _Inout_ sqlsrv_stmt* stmt ) {
|
||||
// only handled differently when AE is on because AE does not support streaming
|
||||
// AE only works with SQL_CURSOR_FORWARD_ONLY for max types
|
||||
if (stmt->conn->ce_option.enabled == true && stmt->current_results->odbc->cursor_type == SQL_CURSOR_FORWARD_ONLY) {
|
||||
// close and reopen the cursor
|
||||
core::SQLCloseCursor(stmt->current_results->odbc);
|
||||
core::SQLExecute(stmt);
|
||||
|
||||
// advance to the previous active result set
|
||||
for (int j = 0; j < stmt->curr_result_set; j++) {
|
||||
core::SQLMoreResults(stmt);
|
||||
}
|
||||
|
||||
// FETCH_NEXT until the cursor reaches the row that it was at
|
||||
for (int i = 0; i <= stmt->fwd_row_index; i++) {
|
||||
core::SQLFetchScroll(stmt->current_results->odbc, SQL_FETCH_NEXT, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void adjustInputPrecision( _Inout_ zval* param_z, _In_ SQLSMALLINT decimal_digits ) {
|
||||
// 38 is the maximum length of a stringified decimal number
|
||||
size_t maxDecimalPrecision = 38;
|
||||
// maxDecimalStrLen is the maximum length of a stringified decimal number
|
||||
// 6 is derived from: 1 for '.'; 1 for sign of the number; 1 for 'e' or 'E' (scientific notation);
|
||||
// 1 for sign of scientific exponent; 2 for length of scientific exponent
|
||||
// if the length is greater than maxDecimalStrLen, do not change the string
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
// for stable releases should be empty
|
||||
// "-RC" for release candidates
|
||||
// "-preview" for ETP
|
||||
#define SEMVER_PRERELEASE "RC"
|
||||
#define SEMVER_PRERELEASE
|
||||
// Semantic versioning build metadata, build meta data is not counted in precedence order.
|
||||
#define SEMVER_BUILDMETA
|
||||
|
||||
|
@ -50,7 +50,7 @@
|
|||
// For preview release, we want the following:
|
||||
// #define VER_FILEVERSION_STR VER_APIVERSION_STR "-" SEMVER_PRERELEASE SEMVER_BUILDMETA
|
||||
// because pecl doesn't like dashes. However, if SEMVER_PRERELEASE is empty, the "-" must be removed
|
||||
#define VER_FILEVERSION_STR VER_APIVERSION_STR "-" SEMVER_PRERELEASE SEMVER_BUILDMETA
|
||||
#define VER_FILEVERSION_STR VER_APIVERSION_STR SEMVER_PRERELEASE SEMVER_BUILDMETA
|
||||
#define _FILEVERSION SQLVERSION_MAJOR,SQLVERSION_MINOR,SQLVERSION_PATCH,SQLVERSION_BUILD
|
||||
|
||||
// PECL package version macros (can't have '-' or '+')
|
||||
|
|
|
@ -29,14 +29,18 @@ if test "$PHP_SQLSRV" != "no"; then
|
|||
fi
|
||||
AC_MSG_RESULT($sqlsrv_inc_path)
|
||||
|
||||
HOST_OS_ARCH=`uname`
|
||||
if test "${HOST_OS_ARCH}" = "Darwin"; then
|
||||
MACOSX_DEPLOYMENT_TARGET=`sw_vers -productVersion`
|
||||
fi
|
||||
|
||||
CXXFLAGS="$CXXFLAGS -std=c++11"
|
||||
CXXFLAGS="$CXXFLAGS -D_FORTIFY_SOURCE=2 -O2"
|
||||
CXXFLAGS="$CXXFLAGS -fstack-protector"
|
||||
|
||||
HOST_OS_ARCH=`uname`
|
||||
if test "${HOST_OS_ARCH}" = "Darwin"; then
|
||||
SQLSRV_SHARED_LIBADD="$SQLSRV_SHARED_LIBADD -Wl,-bind_at_load"
|
||||
MACOSX_DEPLOYMENT_TARGET=`sw_vers -productVersion`
|
||||
else
|
||||
SQLSRV_SHARED_LIBADD="$SQLSRV_SHARED_LIBADD -Wl,-z,now"
|
||||
fi
|
||||
|
||||
PHP_REQUIRE_CXX()
|
||||
PHP_ADD_LIBRARY(stdc++, 1, SQLSRV_SHARED_LIBADD)
|
||||
PHP_ADD_LIBRARY(odbc, 1, SQLSRV_SHARED_LIBADD)
|
||||
|
|
|
@ -30,12 +30,12 @@ if( PHP_SQLSRV != "no" ) {
|
|||
ADD_SOURCES( configure_module_dirname + "\\shared", shared_src_class, "sqlsrv" );
|
||||
CHECK_HEADER_ADD_INCLUDE("sql.h", "CFLAGS_SQLSRV_ODBC");
|
||||
CHECK_HEADER_ADD_INCLUDE("sqlext.h", "CFLAGS_SQLSRV_ODBC");
|
||||
ADD_FLAG( "LDFLAGS_SQLSRV", "/NXCOMPAT /DYNAMICBASE /debug" );
|
||||
ADD_FLAG( "LDFLAGS_SQLSRV", "/NXCOMPAT /DYNAMICBASE /debug /guard:cf" );
|
||||
ADD_FLAG( "CFLAGS_SQLSRV", "/D ZEND_WIN32_FORCE_INLINE" );
|
||||
ADD_FLAG( "CFLAGS_SQLSRV", "/EHsc" );
|
||||
ADD_FLAG( "CFLAGS_SQLSRV", "/GS" );
|
||||
ADD_FLAG( "CFLAGS_SQLSRV", "/Zi" );
|
||||
ADD_FLAG( "CFLAGS_SQLSRV", "/O2" );
|
||||
if (PHP_DEBUG != "yes") ADD_FLAG( "CFLAGS_SQLSRV", "/guard:cf /O2" );
|
||||
EXTENSION("sqlsrv", sqlsrv_src_class , PHP_SQLSRV_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
|
||||
} else {
|
||||
WARNING("sqlsrv not enabled; libraries and headers not found");
|
||||
|
|
|
@ -187,13 +187,9 @@ const char AttachDBFileName[] = "AttachDbFileName";
|
|||
const char CharacterSet[] = "CharacterSet";
|
||||
const char Authentication[] = "Authentication";
|
||||
const char ConnectionPooling[] = "ConnectionPooling";
|
||||
const char ColumnEncryption[] = "ColumnEncryption";
|
||||
const char Driver[] = "Driver";
|
||||
const char CEKeystoreProvider[] = "CEKeystoreProvider";
|
||||
const char CEKeystoreName[] = "CEKeystoreName";
|
||||
const char CEKeystoreEncryptKey[] = "CEKeystoreEncryptKey";
|
||||
|
||||
#ifdef _WIN32
|
||||
const char ColumnEncryption[] = "ColumnEncryption";
|
||||
const char ConnectRetryCount[] = "ConnectRetryCount";
|
||||
const char ConnectRetryInterval[] = "ConnectRetryInterval";
|
||||
#endif // _WIN32
|
||||
|
@ -307,15 +303,6 @@ const connection_option SS_CONN_OPTS[] = {
|
|||
CONN_ATTR_BOOL,
|
||||
conn_null_func::func
|
||||
},
|
||||
{
|
||||
SSConnOptionNames::ColumnEncryption,
|
||||
sizeof(SSConnOptionNames::ColumnEncryption),
|
||||
SQLSRV_CONN_OPTION_COLUMNENCRYPTION,
|
||||
ODBCConnOptions::ColumnEncryption,
|
||||
sizeof(ODBCConnOptions::ColumnEncryption),
|
||||
CONN_ATTR_STRING,
|
||||
column_encryption_set_func::func
|
||||
},
|
||||
{
|
||||
SSConnOptionNames::Driver,
|
||||
sizeof(SSConnOptionNames::Driver),
|
||||
|
@ -325,34 +312,16 @@ const connection_option SS_CONN_OPTS[] = {
|
|||
CONN_ATTR_STRING,
|
||||
driver_set_func::func
|
||||
},
|
||||
{
|
||||
SSConnOptionNames::CEKeystoreProvider,
|
||||
sizeof(SSConnOptionNames::CEKeystoreProvider),
|
||||
SQLSRV_CONN_OPTION_CEKEYSTORE_PROVIDER,
|
||||
ODBCConnOptions::CEKeystoreProvider,
|
||||
sizeof(ODBCConnOptions::CEKeystoreProvider),
|
||||
CONN_ATTR_STRING,
|
||||
ce_ksp_provider_set_func::func
|
||||
},
|
||||
{
|
||||
SSConnOptionNames::CEKeystoreName,
|
||||
sizeof(SSConnOptionNames::CEKeystoreName),
|
||||
SQLSRV_CONN_OPTION_CEKEYSTORE_NAME,
|
||||
ODBCConnOptions::CEKeystoreName,
|
||||
sizeof(ODBCConnOptions::CEKeystoreName),
|
||||
CONN_ATTR_STRING,
|
||||
ce_ksp_provider_set_func::func
|
||||
},
|
||||
{
|
||||
SSConnOptionNames::CEKeystoreEncryptKey,
|
||||
sizeof(SSConnOptionNames::CEKeystoreEncryptKey),
|
||||
SQLSRV_CONN_OPTION_CEKEYSTORE_ENCRYPT_KEY,
|
||||
ODBCConnOptions::CEKeystoreEncryptKey,
|
||||
sizeof(ODBCConnOptions::CEKeystoreEncryptKey),
|
||||
CONN_ATTR_STRING,
|
||||
ce_ksp_provider_set_func::func
|
||||
},
|
||||
#ifdef _WIN32
|
||||
{
|
||||
SSConnOptionNames::ColumnEncryption,
|
||||
sizeof(SSConnOptionNames::ColumnEncryption),
|
||||
SQLSRV_CONN_OPTION_COLUMNENCRYPTION,
|
||||
ODBCConnOptions::ColumnEncryption,
|
||||
sizeof(ODBCConnOptions::ColumnEncryption),
|
||||
CONN_ATTR_STRING,
|
||||
column_encryption_set_func::func
|
||||
},
|
||||
{
|
||||
SSConnOptionNames::ConnectRetryCount,
|
||||
sizeof( SSConnOptionNames::ConnectRetryCount ),
|
||||
|
|
|
@ -302,7 +302,7 @@ ss_error SS_ERRORS[] = {
|
|||
SQLSRV_ERROR_DRIVER_NOT_INSTALLED,
|
||||
{ IMSSP, (SQLCHAR*) "This extension requires the Microsoft ODBC Driver for SQL Server. "
|
||||
"Access the following URL to download the ODBC Driver for SQL Server for %1!s!: "
|
||||
"http://go.microsoft.com/fwlink/?LinkId=163712", -49, true }
|
||||
"https://go.microsoft.com/fwlink/?LinkId=163712", -49, true }
|
||||
},
|
||||
|
||||
{
|
||||
|
@ -379,22 +379,6 @@ ss_error SS_ERRORS[] = {
|
|||
{
|
||||
SS_SQLSRV_WARNING_FIELD_NAME_EMPTY,
|
||||
{ SSPWARN, (SQLCHAR*)"An empty field name was skipped by sqlsrv_fetch_object.", -100, false }
|
||||
},
|
||||
{
|
||||
SQLSRV_ERROR_KEYSTORE_NAME_MISSING,
|
||||
{ IMSSP, (SQLCHAR*) "The name of the custom keystore provider is missing.", -101, false}
|
||||
},
|
||||
{
|
||||
SQLSRV_ERROR_KEYSTORE_PATH_MISSING,
|
||||
{ IMSSP, (SQLCHAR*) "The path to the custom keystore provider is missing.", -102, false}
|
||||
},
|
||||
{
|
||||
SQLSRV_ERROR_KEYSTORE_KEY_MISSING,
|
||||
{ IMSSP, (SQLCHAR*) "The encryption key for the custom keystore provider is missing.", -103, false}
|
||||
},
|
||||
{
|
||||
SQLSRV_ERROR_KEYSTORE_INVALID_VALUE,
|
||||
{ IMSSP, (SQLCHAR*) "Invalid value for loading a custom keystore provider.", -104, false}
|
||||
},
|
||||
{
|
||||
SQLSRV_ERROR_CE_DRIVER_REQUIRED,
|
||||
|
|
|
@ -32,7 +32,7 @@ PDO::ATTR_ERRMODE: int\(0\)
|
|||
PDO::ATTR_ERRMODE: int\(2\)
|
||||
Array
|
||||
\(
|
||||
\[DriverDllName\] => msodbcsql[0-9]{2}\.dll|libmsodbcsql-[0-9]{2}\.[0-9]\.so\.[0-9]\.[0-9]
|
||||
\[DriverDllName\]|\[DriverName\] => (msodbcsql[0-9]{2}\.dll|(libmsodbcsql-[0-9]{2}\.[0-9]\.so\.[0-9]\.[0-9]|libmsodbcsql.[0-9]{2}.dylib))
|
||||
\[DriverODBCVer\] => [0-9]{1,2}\.[0-9]{1,2}
|
||||
\[DriverVer\] => [0-9]{1,2}\.[0-9]{1,2}\.[0-9]{4}
|
||||
\[ExtensionVer\] => [0-9].[0-9]\.[0-9](-(RC[0-9]?|preview))?(\.[0-9]+)?(\+[0-9]+)?
|
||||
|
|
|
@ -29,7 +29,7 @@ else
|
|||
sqlsrv_close( $conn);
|
||||
?>
|
||||
--EXPECTREGEX--
|
||||
DriverDllName: msodbcsql[0-9]{2}\.dll|libmsodbcsql-[0-9]{2}\.[0-9]\.so\.[0-9]\.[0-9]
|
||||
DriverDllName|DriverName: (msodbcsql[0-9]{2}\.dll|(libmsodbcsql-[0-9]{2}\.[0-9]\.so\.[0-9]\.[0-9]|libmsodbcsql.[0-9]{2}.dylib))
|
||||
DriverODBCVer: [0-9]{1,2}\.[0-9]{1,2}
|
||||
DriverVer: [0-9]{1,2}\.[0-9]{1,2}\.[0-9]{4}
|
||||
ExtensionVer: [0-9].[0-9]\.[0-9](-(RC[0-9]?|preview))?(\.[0-9]+)?(\+[0-9]+)?
|
|
@ -1,25 +0,0 @@
|
|||
<?php
|
||||
|
||||
function getKSPpath()
|
||||
{
|
||||
$name = 'myKSP';
|
||||
|
||||
$dir_name = realpath(dirname(__FILE__));
|
||||
$ksp = $dir_name . DIRECTORY_SEPARATOR . $name;
|
||||
if ( strtoupper( substr( php_uname( 's' ), 0, 3 ) ) == 'WIN' ) {
|
||||
$arch = 'x64';
|
||||
if ( PHP_INT_SIZE == 4 ) // running 32 bit
|
||||
$arch = '';
|
||||
$ksp .= $arch . '.dll';
|
||||
}
|
||||
else
|
||||
$ksp .= '.so';
|
||||
|
||||
return $ksp;
|
||||
}
|
||||
|
||||
$ksp_name = 'MyCustomKSPName';
|
||||
$encrypt_key = 'LPKCWVD07N3RG98J0MBLG4H2';
|
||||
$ksp_test_table = 'CustomKSPTestTable';
|
||||
|
||||
?>
|
|
@ -16,10 +16,18 @@
|
|||
function IsAEQualified($conn)
|
||||
{
|
||||
$msodbcsql_ver = $conn->getAttribute(PDO::ATTR_CLIENT_VERSION)["DriverVer"];
|
||||
$server_ver = $conn->getAttribute(PDO::ATTR_SERVER_VERSION);
|
||||
$msodbcsql_maj = explode(".", $msodbcsql_ver)[0];
|
||||
$msodbcsql_min = explode(".", $msodbcsql_ver)[1];
|
||||
if ($msodbcsql_maj < 17 || explode('.', $server_ver)[0] < 13)
|
||||
if ($msodbcsql_maj < 17) {
|
||||
return false;
|
||||
}
|
||||
require 'MsSetup.inc';
|
||||
if ($daasMode) {
|
||||
// running against Azure
|
||||
return true;
|
||||
}
|
||||
// if not Azure, check the server version
|
||||
$server_ver = $conn->getAttribute(PDO::ATTR_SERVER_VERSION);
|
||||
if (explode('.', $server_ver)[0] < 13)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -20,11 +20,19 @@ const KSP_TEST_TABLE = 'CustomKSPTestTable';
|
|||
function isAEQualified($conn)
|
||||
{
|
||||
$msodbcsql_ver = $conn->getAttribute(PDO::ATTR_CLIENT_VERSION)["DriverVer"];
|
||||
$server_ver = $conn->getAttribute(PDO::ATTR_SERVER_VERSION);
|
||||
$msodbcsql_maj = explode(".", $msodbcsql_ver)[0];
|
||||
if ($msodbcsql_maj < 17 || explode('.', $server_ver)[0] < 13) {
|
||||
if ($msodbcsql_maj < 17) {
|
||||
return false;
|
||||
}
|
||||
require 'MsSetup.inc';
|
||||
if ($daasMode) {
|
||||
// running against Azure
|
||||
return true;
|
||||
}
|
||||
// if not Azure, check the server version
|
||||
$server_ver = $conn->getAttribute(PDO::ATTR_SERVER_VERSION);
|
||||
if (explode('.', $server_ver)[0] < 13)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
--TEST--
|
||||
Test for retrieving encrypted data from binary types columns using PDO::bindColumn
|
||||
--DESCRIPTION--
|
||||
Test conversion from binary types column to output of PDO::PARAM types
|
||||
With or without AE, conversion works if:
|
||||
1. From any binary type column to PDO::PARAM_STR
|
||||
2. From any binary type column to PDO::PARAM_LOB
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
require_once("AEData.inc");
|
||||
|
||||
$dataTypes = array("binary", "varbinary", "varbinary(max)");
|
||||
$lengths = array(1, 8, 64, 512, 4000);
|
||||
|
||||
try {
|
||||
$conn = connect("", array(), PDO::ERRMODE_SILENT);
|
||||
foreach ($dataTypes as $dataType) {
|
||||
$maxcol = strpos($dataType, "(max)");
|
||||
foreach ($lengths as $m) {
|
||||
if ($maxcol !== false) {
|
||||
$typeFull = $dataType;
|
||||
} else {
|
||||
$typeFull = "$dataType($m)";
|
||||
}
|
||||
echo "\nTesting $typeFull:\n";
|
||||
|
||||
//create and populate table containing binary(m) or varbinary(m) columns
|
||||
$tbname = "test_" . str_replace(array('(', ')'), '', $dataType) . $m;
|
||||
$colMetaArr = array(new ColumnMeta($typeFull, "c_det"), new ColumnMeta($typeFull, "c_rand", null, "randomized"));
|
||||
createTable($conn, $tbname, $colMetaArr);
|
||||
$inputValues = array(str_repeat("d", $m), str_repeat("r", $m));
|
||||
insertRow($conn, $tbname, array("c_det" => new BindParamOp(1, $inputValues[0], "PDO::PARAM_LOB", 0, "PDO::SQLSRV_ENCODING_BINARY"),
|
||||
"c_rand" => new BindParamOp(2, $inputValues[1], "PDO::PARAM_LOB", 0, "PDO::SQLSRV_ENCODING_BINARY")), "prepareBindParam");
|
||||
|
||||
// fetch by specifying PDO::PARAM_ types with PDO::bindColumn
|
||||
$query = "SELECT c_det, c_rand FROM $tbname";
|
||||
foreach ($pdoParamTypes as $pdoParamType) {
|
||||
$det = "";
|
||||
$rand = "";
|
||||
$stmt = $conn->prepare($query);
|
||||
$stmt->execute();
|
||||
$stmt->bindColumn('c_det', $det, constant($pdoParamType));
|
||||
$stmt->bindColumn('c_rand', $rand, constant($pdoParamType));
|
||||
$row = $stmt->fetch(PDO::FETCH_BOUND);
|
||||
|
||||
// check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_NULL or PDO::PARAM_INT
|
||||
// with or without AE: should not work
|
||||
if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_NULL" || $pdoParamType == "PDO::PARAM_INT") {
|
||||
if (!is_null($det) || !is_null($rand)) {
|
||||
echo "Retrieving $typeFull data as $pdoParamType should not be supported\n";
|
||||
}
|
||||
// check the case when fetching as PDO::PARAM_STR or PDO::PARAM_LOB
|
||||
// with or without AE: should work
|
||||
} else {
|
||||
if (trim($det) == $inputValues[0] && trim($rand) == $inputValues[1]) {
|
||||
echo "****Retrieving $typeFull data as $pdoParamType is supported****\n";
|
||||
} else {
|
||||
echo "Retrieving $typeFull data as $pdoParamType fails\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
// cleanup
|
||||
dropTable($conn, $tbname);
|
||||
}
|
||||
}
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
} catch (PDOException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
Testing binary(1):
|
||||
****Retrieving binary(1) data as PDO::PARAM_STR is supported****
|
||||
****Retrieving binary(1) data as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing binary(8):
|
||||
****Retrieving binary(8) data as PDO::PARAM_STR is supported****
|
||||
****Retrieving binary(8) data as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing binary(64):
|
||||
****Retrieving binary(64) data as PDO::PARAM_STR is supported****
|
||||
****Retrieving binary(64) data as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing binary(512):
|
||||
****Retrieving binary(512) data as PDO::PARAM_STR is supported****
|
||||
****Retrieving binary(512) data as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing binary(4000):
|
||||
****Retrieving binary(4000) data as PDO::PARAM_STR is supported****
|
||||
****Retrieving binary(4000) data as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing varbinary(1):
|
||||
****Retrieving varbinary(1) data as PDO::PARAM_STR is supported****
|
||||
****Retrieving varbinary(1) data as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing varbinary(8):
|
||||
****Retrieving varbinary(8) data as PDO::PARAM_STR is supported****
|
||||
****Retrieving varbinary(8) data as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing varbinary(64):
|
||||
****Retrieving varbinary(64) data as PDO::PARAM_STR is supported****
|
||||
****Retrieving varbinary(64) data as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing varbinary(512):
|
||||
****Retrieving varbinary(512) data as PDO::PARAM_STR is supported****
|
||||
****Retrieving varbinary(512) data as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing varbinary(4000):
|
||||
****Retrieving varbinary(4000) data as PDO::PARAM_STR is supported****
|
||||
****Retrieving varbinary(4000) data as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing varbinary(max):
|
||||
****Retrieving varbinary(max) data as PDO::PARAM_STR is supported****
|
||||
****Retrieving varbinary(max) data as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing varbinary(max):
|
||||
****Retrieving varbinary(max) data as PDO::PARAM_STR is supported****
|
||||
****Retrieving varbinary(max) data as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing varbinary(max):
|
||||
****Retrieving varbinary(max) data as PDO::PARAM_STR is supported****
|
||||
****Retrieving varbinary(max) data as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing varbinary(max):
|
||||
****Retrieving varbinary(max) data as PDO::PARAM_STR is supported****
|
||||
****Retrieving varbinary(max) data as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing varbinary(max):
|
||||
****Retrieving varbinary(max) data as PDO::PARAM_STR is supported****
|
||||
****Retrieving varbinary(max) data as PDO::PARAM_LOB is supported****
|
|
@ -0,0 +1,144 @@
|
|||
--TEST--
|
||||
Test for retrieving encrypted data from char types columns using PDO::bindColumn
|
||||
--DESCRIPTION--
|
||||
Test conversion from char types column to output of PDO::PARAM types
|
||||
With or without Always Encrypted, conversion works if:
|
||||
1. From any char type column to PDO::PARAM_STR
|
||||
2. From any char type column to PDO::PARAM_LOB
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
require_once("AEData.inc");
|
||||
|
||||
$dataTypes = array("char", "varchar", "varchar(max)");
|
||||
$lengths = array(1, 8, 64, 512, 4096, 8000);
|
||||
|
||||
try {
|
||||
$conn = connect("", array(), PDO::ERRMODE_SILENT);
|
||||
foreach ($dataTypes as $dataType) {
|
||||
$maxcol = strpos($dataType, "(max)");
|
||||
foreach ($lengths as $m) {
|
||||
if ($maxcol !== false) {
|
||||
$typeFull = $dataType;
|
||||
} else {
|
||||
$typeFull = "$dataType($m)";
|
||||
}
|
||||
echo "\nTesting $typeFull:\n";
|
||||
|
||||
//create and populate table containing char(m) or varchar(m) columns
|
||||
$tbname = "test_" . str_replace(array('(', ')'), '', $dataType) . $m;
|
||||
$colMetaArr = array(new ColumnMeta($typeFull, "c1", null, "ramdomized"));
|
||||
createTable($conn, $tbname, $colMetaArr);
|
||||
$inputValue = str_repeat("d", $m);
|
||||
insertRow($conn, $tbname, array("c1" => $inputValue));
|
||||
|
||||
// fetch by specifying PDO::PARAM_ types with PDO::bindColumn
|
||||
$query = "SELECT c1 FROM $tbname";
|
||||
foreach ($pdoParamTypes as $pdoParamType) {
|
||||
$det = "";
|
||||
$rand = "";
|
||||
$stmt = $conn->prepare($query);
|
||||
$stmt->execute();
|
||||
$stmt->bindColumn('c1', $c1, constant($pdoParamType));
|
||||
$row = $stmt->fetch(PDO::FETCH_BOUND);
|
||||
|
||||
// check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_NULL or PDO::PARAM_INT
|
||||
// with or without AE: should not work
|
||||
if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_NULL" || $pdoParamType == "PDO::PARAM_INT") {
|
||||
if (!empty($det) || !empty($rand)) {
|
||||
echo "Retrieving $typeFull data as $pdoParamType should not be supported\n";
|
||||
}
|
||||
// check the case when fetching as PDO::PARAM_STR or PDO::PARAM_LOB
|
||||
// with or without AE: should work
|
||||
} else {
|
||||
if (strlen($c1) == $m) {
|
||||
echo "****Retrieving $typeFull as $pdoParamType is supported****\n";
|
||||
} else {
|
||||
echo "Retrieving $typeFull as $pdoParamType fails\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
// cleanup
|
||||
dropTable($conn, $tbname);
|
||||
}
|
||||
}
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
} catch (PDOException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
Testing char(1):
|
||||
****Retrieving char(1) as PDO::PARAM_STR is supported****
|
||||
****Retrieving char(1) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing char(8):
|
||||
****Retrieving char(8) as PDO::PARAM_STR is supported****
|
||||
****Retrieving char(8) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing char(64):
|
||||
****Retrieving char(64) as PDO::PARAM_STR is supported****
|
||||
****Retrieving char(64) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing char(512):
|
||||
****Retrieving char(512) as PDO::PARAM_STR is supported****
|
||||
****Retrieving char(512) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing char(4096):
|
||||
****Retrieving char(4096) as PDO::PARAM_STR is supported****
|
||||
****Retrieving char(4096) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing char(8000):
|
||||
****Retrieving char(8000) as PDO::PARAM_STR is supported****
|
||||
****Retrieving char(8000) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing varchar(1):
|
||||
****Retrieving varchar(1) as PDO::PARAM_STR is supported****
|
||||
****Retrieving varchar(1) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing varchar(8):
|
||||
****Retrieving varchar(8) as PDO::PARAM_STR is supported****
|
||||
****Retrieving varchar(8) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing varchar(64):
|
||||
****Retrieving varchar(64) as PDO::PARAM_STR is supported****
|
||||
****Retrieving varchar(64) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing varchar(512):
|
||||
****Retrieving varchar(512) as PDO::PARAM_STR is supported****
|
||||
****Retrieving varchar(512) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing varchar(4096):
|
||||
****Retrieving varchar(4096) as PDO::PARAM_STR is supported****
|
||||
****Retrieving varchar(4096) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing varchar(8000):
|
||||
****Retrieving varchar(8000) as PDO::PARAM_STR is supported****
|
||||
****Retrieving varchar(8000) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing varchar(max):
|
||||
****Retrieving varchar(max) as PDO::PARAM_STR is supported****
|
||||
****Retrieving varchar(max) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing varchar(max):
|
||||
****Retrieving varchar(max) as PDO::PARAM_STR is supported****
|
||||
****Retrieving varchar(max) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing varchar(max):
|
||||
****Retrieving varchar(max) as PDO::PARAM_STR is supported****
|
||||
****Retrieving varchar(max) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing varchar(max):
|
||||
****Retrieving varchar(max) as PDO::PARAM_STR is supported****
|
||||
****Retrieving varchar(max) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing varchar(max):
|
||||
****Retrieving varchar(max) as PDO::PARAM_STR is supported****
|
||||
****Retrieving varchar(max) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing varchar(max):
|
||||
****Retrieving varchar(max) as PDO::PARAM_STR is supported****
|
||||
****Retrieving varchar(max) as PDO::PARAM_LOB is supported****
|
|
@ -0,0 +1,77 @@
|
|||
--TEST--
|
||||
Test for retrieving encrypted data from datetime types columns using PDO::bindColumn
|
||||
--DESCRIPTION--
|
||||
Test conversion from datetime types column to output of PDO::PARAM types
|
||||
With or without Always Encrypted, conversion works if:
|
||||
1. From any datetime type column to PDO::PARAM_STR
|
||||
2. From any datetime type column to PDO::PARAM_LOB
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
require_once("AEData.inc");
|
||||
|
||||
$dataTypes = array("date", "datetime", "smalldatetime");
|
||||
|
||||
try {
|
||||
$conn = connect("", array(), PDO::ERRMODE_SILENT);
|
||||
foreach ($dataTypes as $dataType) {
|
||||
echo "\nTesting $dataType:\n";
|
||||
|
||||
// create and populate table containing date, datetime or smalldatetime columns
|
||||
$tbname = "test_" . $dataType;
|
||||
$colMetaArr = array(new ColumnMeta($dataType, "c_det"), new ColumnMeta($dataType, "c_rand", null, "randomized"));
|
||||
createTable($conn, $tbname, $colMetaArr);
|
||||
$inputValues = array_slice(${explode("(", $dataType)[0] . "_params"}, 1, 2);
|
||||
insertRow($conn, $tbname, array("c_det" => $inputValues[0], "c_rand" => $inputValues[1]));
|
||||
|
||||
// fetch by specifying PDO::PARAM_ types with PDO::bindColumn
|
||||
$query = "SELECT c_det, c_rand FROM $tbname";
|
||||
foreach ($pdoParamTypes as $pdoParamType) {
|
||||
$det = "";
|
||||
$rand = "";
|
||||
$stmt = $conn->prepare($query);
|
||||
$stmt->execute();
|
||||
$stmt->bindColumn('c_det', $det, constant($pdoParamType));
|
||||
$stmt->bindColumn('c_rand', $rand, constant($pdoParamType));
|
||||
$row = $stmt->fetch(PDO::FETCH_BOUND);
|
||||
|
||||
// check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_NULL or PDO::PARAM_INT
|
||||
// with or without AE: should not work
|
||||
if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_NULL" || $pdoParamType == "PDO::PARAM_INT") {
|
||||
if (!is_null($det) || !is_null($rand)) {
|
||||
echo "Retrieving $dataType data as $pdoParamType should not be supported\n";
|
||||
}
|
||||
// check the case when fetching as PDO::PARAM_STR or PDO::PARAM_LOB
|
||||
// only check if input values are part of fetched values because some input values do not contain any deicmal places, the value retrieved however has 3 decimal places if the type is a datetime
|
||||
// with or without AE: should work
|
||||
} else {
|
||||
if (strpos($det, $inputValues[0]) !== false && strpos($rand, $inputValues[1]) !== false) {
|
||||
echo "****Retrieving $dataType as $pdoParamType is supported****\n";
|
||||
} else {
|
||||
echo "Retrieving $dataType as $pdoParamType fails\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
// cleanup
|
||||
dropTable($conn, $tbname);
|
||||
}
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
} catch (PDOException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
Testing date:
|
||||
****Retrieving date as PDO::PARAM_STR is supported****
|
||||
****Retrieving date as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing datetime:
|
||||
****Retrieving datetime as PDO::PARAM_STR is supported****
|
||||
****Retrieving datetime as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing smalldatetime:
|
||||
****Retrieving smalldatetime as PDO::PARAM_STR is supported****
|
||||
****Retrieving smalldatetime as PDO::PARAM_LOB is supported****
|
|
@ -0,0 +1,150 @@
|
|||
--TEST--
|
||||
Test for retrieving encrypted data from datetime types columns with different precisions using PDO::bindColumn
|
||||
--DESCRIPTION--
|
||||
Test conversion from datetime types column to output of PDO::PARAM types
|
||||
With or without Always Encrypted, conversion works if:
|
||||
1. From any datetime type column to PDO::PARAM_STR
|
||||
2. From any datetime type column to PDO::PARAM_LOB
|
||||
TODO: cannot insert into a datetime2(0) using the PDO_SQLSRV driver
|
||||
returns operand type clash error between smalldatetime and datetime2(0)
|
||||
to see error, uncomment 0 from the $precision array
|
||||
documented in VSO 2693
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
require_once("AEData.inc");
|
||||
|
||||
function compareDate($dtout, $dtin, $dataType) {
|
||||
if ($dataType == "datetimeoffset") {
|
||||
$dtarr = explode(' ', $dtin);
|
||||
if (strpos($dtout, $dtarr[0]) !== false && strpos($dtout, $dtarr[1]) !== false && strpos($dtout, $dtarr[2]) !== false) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (strpos($dtout, $dtin) !== false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$dataTypes = array("datetime2", "datetimeoffset", "time");
|
||||
$precisions = array(/*0,*/ 1, 2, 4, 7);
|
||||
$inputValuesInit = array("datetime2" => array("0001-01-01 00:00:00", "9999-12-31 23:59:59"),
|
||||
"datetimeoffset" => array("0001-01-01 00:00:00 -14:00", "9999-12-31 23:59:59 +14:00"),
|
||||
"time" => array("00:00:00", "23:59:59"));
|
||||
|
||||
try {
|
||||
$conn = connect("", array(), PDO::ERRMODE_SILENT);
|
||||
foreach ($dataTypes as $dataType) {
|
||||
foreach ($precisions as $m) {
|
||||
// add $m number of decimal digits to the some input values
|
||||
$inputValues[0] = $inputValuesInit[$dataType][0];
|
||||
$inputValues[1] = $inputValuesInit[$dataType][1];
|
||||
if ($m != 0) {
|
||||
if ($dataType == "datetime2") {
|
||||
$inputValues[1] .= "." . str_repeat("9", $m);
|
||||
} else if ($dataType == "datetimeoffset") {
|
||||
$dtoffsetPieces = explode(" ", $inputValues[1]);
|
||||
$inputValues[1] = $dtoffsetPieces[0] . " " . $dtoffsetPieces[1] . "." . str_repeat("9", $m) . " " . $dtoffsetPieces[2];
|
||||
} else if ($dataType == "time") {
|
||||
$inputValues[0] .= "." . str_repeat("0", $m);
|
||||
$inputValues[1] .= "." . str_repeat("9", $m);
|
||||
}
|
||||
}
|
||||
$typeFull = "$dataType($m)";
|
||||
echo "\nTesting $typeFull:\n";
|
||||
|
||||
//create and populate table containing datetime2(m), datetimeoffset(m) or time(m) columns
|
||||
$tbname = "test_" . $dataType . $m;
|
||||
$colMetaArr = array(new ColumnMeta($typeFull, "c_det"), new ColumnMeta($typeFull, "c_rand", null, "randomized"));
|
||||
createTable($conn, $tbname, $colMetaArr);
|
||||
insertRow($conn, $tbname, array("c_det" => $inputValues[0], "c_rand" => $inputValues[1]));
|
||||
|
||||
// fetch by specifying PDO::PARAM_ types with PDO:bindColumn
|
||||
$query = "SELECT c_det, c_rand FROM $tbname";
|
||||
foreach ($pdoParamTypes as $pdoParamType) {
|
||||
$det = "";
|
||||
$rand = "";
|
||||
$stmt = $conn->prepare($query);
|
||||
$stmt->execute();
|
||||
$stmt->bindColumn('c_det', $det, constant($pdoParamType));
|
||||
$stmt->bindColumn('c_rand', $rand, constant($pdoParamType));
|
||||
$row = $stmt->fetch(PDO::FETCH_BOUND);
|
||||
|
||||
// check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_NULL or PDO::PARAM_INT
|
||||
// with or without AE: should not work
|
||||
if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_NULL" || $pdoParamType == "PDO::PARAM_INT") {
|
||||
if (!is_null($det) || !is_null($rand)) {
|
||||
echo "Retrieving $typeFull data as $pdoParamType should not be supported\n";
|
||||
}
|
||||
// check the case when fetching as PDO::PARAM_STR or PDO::PARAM_LOB
|
||||
// with or without AE: should work
|
||||
} else {
|
||||
if (compareDate($det, $inputValues[0], $dataType) && compareDate($rand, $inputValues[1], $dataType)) {
|
||||
echo "****Retrieving $typeFull as $pdoParamType is supported****\n";
|
||||
} else {
|
||||
echo "Retrieving $typeFull as $pdoParamType fails\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
// cleanup
|
||||
dropTable($conn, $tbname);
|
||||
}
|
||||
}
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
} catch (PDOException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
Testing datetime2(1):
|
||||
****Retrieving datetime2(1) as PDO::PARAM_STR is supported****
|
||||
****Retrieving datetime2(1) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing datetime2(2):
|
||||
****Retrieving datetime2(2) as PDO::PARAM_STR is supported****
|
||||
****Retrieving datetime2(2) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing datetime2(4):
|
||||
****Retrieving datetime2(4) as PDO::PARAM_STR is supported****
|
||||
****Retrieving datetime2(4) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing datetime2(7):
|
||||
****Retrieving datetime2(7) as PDO::PARAM_STR is supported****
|
||||
****Retrieving datetime2(7) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing datetimeoffset(1):
|
||||
****Retrieving datetimeoffset(1) as PDO::PARAM_STR is supported****
|
||||
****Retrieving datetimeoffset(1) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing datetimeoffset(2):
|
||||
****Retrieving datetimeoffset(2) as PDO::PARAM_STR is supported****
|
||||
****Retrieving datetimeoffset(2) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing datetimeoffset(4):
|
||||
****Retrieving datetimeoffset(4) as PDO::PARAM_STR is supported****
|
||||
****Retrieving datetimeoffset(4) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing datetimeoffset(7):
|
||||
****Retrieving datetimeoffset(7) as PDO::PARAM_STR is supported****
|
||||
****Retrieving datetimeoffset(7) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing time(1):
|
||||
****Retrieving time(1) as PDO::PARAM_STR is supported****
|
||||
****Retrieving time(1) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing time(2):
|
||||
****Retrieving time(2) as PDO::PARAM_STR is supported****
|
||||
****Retrieving time(2) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing time(4):
|
||||
****Retrieving time(4) as PDO::PARAM_STR is supported****
|
||||
****Retrieving time(4) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing time(7):
|
||||
****Retrieving time(7) as PDO::PARAM_STR is supported****
|
||||
****Retrieving time(7) as PDO::PARAM_LOB is supported****
|
|
@ -0,0 +1,242 @@
|
|||
--TEST--
|
||||
Test for retrieving encrypted data from decimal types columns using PDO::bindColumn
|
||||
--DESCRIPTION--
|
||||
Test conversion from decimal types column to output of PDO::PARAM types
|
||||
With or without ALways Encrypted, conversion works if:
|
||||
1. From any decimal type column to PDO::PARAM_STR
|
||||
2. From any decimal type column to PDO::PARAM_LOB
|
||||
TODO: behavior for teching decimals as PARAM_BOOL and PARAM_INT varies depending on the number being fetched
|
||||
1. if the number is less than 1, returns 0 (even though the number being fetched is 0.9)
|
||||
2. if the number is greater than 1 and the number of digits is less than 11, returns the correctly rounded integer (e.g., returns 922 when fetching 922.3)
|
||||
3. if the number is greater than 1 and the number of digits is greater than 11, returns NULL
|
||||
need to investigate which should be the correct behavior
|
||||
for this test, assume to correct behavior is to return NULL
|
||||
documented in VSO 2730
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
require_once("AEData.inc");
|
||||
|
||||
$dataTypes = array("decimal", "numeric");
|
||||
$precisions = array(1 => array(0, 1),
|
||||
4 => array(0, 1, 4),
|
||||
16 => array(0, 1, 4, 16),
|
||||
38 => array(0, 1, 4, 16, 38));
|
||||
$inputValuesInit = array(92233720368547758089223372036854775808, -92233720368547758089223372036854775808);
|
||||
$inputPrecision = 38;
|
||||
|
||||
try {
|
||||
$conn = connect("", array(), PDO::ERRMODE_SILENT);
|
||||
foreach ($dataTypes as $dataType) {
|
||||
foreach ($precisions as $m1 => $scales) {
|
||||
foreach ($scales as $m2) {
|
||||
// change the number of integers in the input values to be $m1 - $m2
|
||||
$precDiff = $inputPrecision - ($m1 - $m2);
|
||||
$inputValues = $inputValuesInit;
|
||||
foreach ($inputValues as &$inputValue) {
|
||||
$inputValue = $inputValue / pow(10, $precDiff);
|
||||
}
|
||||
|
||||
// compute the epsilon for comparing doubles
|
||||
// float in PHP only has a precision of roughtly 14 digits: http://php.net/manual/en/language.types.float.php
|
||||
$epsilon;
|
||||
if ($m1 < 14) {
|
||||
$epsilon = pow(10, $m2 * -1);
|
||||
} else {
|
||||
$numint = $m1 - $m2;
|
||||
if ($numint < 14) {
|
||||
$epsilon = pow(10, (14 - $numint) * -1);
|
||||
} else {
|
||||
$epsilon = pow(10, $numint - 14);
|
||||
}
|
||||
}
|
||||
|
||||
$typeFull = "$dataType($m1, $m2)";
|
||||
echo "\nTesting $typeFull:\n";
|
||||
|
||||
// create and populate table containing decimal(m1, m2) or numeric(m1, m2) columns
|
||||
$tbname = "test_" . $dataType . $m1 . $m2;
|
||||
$colMetaArr = array(new ColumnMeta($typeFull, "c_det"), new ColumnMeta($typeFull, "c_rand", null, "randomized"));
|
||||
createTable($conn, $tbname, $colMetaArr);
|
||||
insertRow($conn, $tbname, array("c_det" => $inputValues[0], "c_rand" => $inputValues[1]));
|
||||
|
||||
// fetch by specifying PDO::PARAM_ types with PDO::bindColumn
|
||||
$query = "SELECT c_det, c_rand FROM $tbname";
|
||||
foreach ($pdoParamTypes as $pdoParamType) {
|
||||
$det = "";
|
||||
$rand = "";
|
||||
$stmt = $conn->prepare($query);
|
||||
$stmt->execute();
|
||||
$stmt->bindColumn('c_det', $det, constant($pdoParamType));
|
||||
$stmt->bindColumn('c_rand', $rand, constant($pdoParamType));
|
||||
$row = $stmt->fetch(PDO::FETCH_BOUND);
|
||||
|
||||
// check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_NULL or PDO::PARAM_INT
|
||||
// with or without AE: should not work
|
||||
// assume to correct behavior is to return NULL, see description
|
||||
if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_NULL" || $pdoParamType == "PDO::PARAM_INT") {
|
||||
if (!is_null($det) || !is_null($rand)) {
|
||||
echo "Retrieving $typeFull data as $pdoParamType should return NULL\n";
|
||||
}
|
||||
} else {
|
||||
if (abs($det - $inputValues[0]) < $epsilon &&
|
||||
abs($rand - $inputValues[1]) < $epsilon) {
|
||||
echo "****Retrieving $typeFull as $pdoParamType is supported****\n";
|
||||
} else {
|
||||
echo "Retrieving $typeFull as $pdoParamType fails\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
// cleanup
|
||||
dropTable($conn, $tbname);
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
} catch (PDOException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
Testing decimal(1, 0):
|
||||
Retrieving decimal(1, 0) data as PDO::PARAM_BOOL should return NULL
|
||||
Retrieving decimal(1, 0) data as PDO::PARAM_INT should return NULL
|
||||
****Retrieving decimal(1, 0) as PDO::PARAM_STR is supported****
|
||||
****Retrieving decimal(1, 0) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing decimal(1, 1):
|
||||
Retrieving decimal(1, 1) data as PDO::PARAM_BOOL should return NULL
|
||||
Retrieving decimal(1, 1) data as PDO::PARAM_INT should return NULL
|
||||
****Retrieving decimal(1, 1) as PDO::PARAM_STR is supported****
|
||||
****Retrieving decimal(1, 1) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing decimal(4, 0):
|
||||
Retrieving decimal(4, 0) data as PDO::PARAM_BOOL should return NULL
|
||||
Retrieving decimal(4, 0) data as PDO::PARAM_INT should return NULL
|
||||
****Retrieving decimal(4, 0) as PDO::PARAM_STR is supported****
|
||||
****Retrieving decimal(4, 0) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing decimal(4, 1):
|
||||
Retrieving decimal(4, 1) data as PDO::PARAM_BOOL should return NULL
|
||||
Retrieving decimal(4, 1) data as PDO::PARAM_INT should return NULL
|
||||
****Retrieving decimal(4, 1) as PDO::PARAM_STR is supported****
|
||||
****Retrieving decimal(4, 1) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing decimal(4, 4):
|
||||
Retrieving decimal(4, 4) data as PDO::PARAM_BOOL should return NULL
|
||||
Retrieving decimal(4, 4) data as PDO::PARAM_INT should return NULL
|
||||
****Retrieving decimal(4, 4) as PDO::PARAM_STR is supported****
|
||||
****Retrieving decimal(4, 4) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing decimal(16, 0):
|
||||
****Retrieving decimal(16, 0) as PDO::PARAM_STR is supported****
|
||||
****Retrieving decimal(16, 0) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing decimal(16, 1):
|
||||
****Retrieving decimal(16, 1) as PDO::PARAM_STR is supported****
|
||||
****Retrieving decimal(16, 1) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing decimal(16, 4):
|
||||
****Retrieving decimal(16, 4) as PDO::PARAM_STR is supported****
|
||||
****Retrieving decimal(16, 4) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing decimal(16, 16):
|
||||
Retrieving decimal(16, 16) data as PDO::PARAM_BOOL should return NULL
|
||||
Retrieving decimal(16, 16) data as PDO::PARAM_INT should return NULL
|
||||
****Retrieving decimal(16, 16) as PDO::PARAM_STR is supported****
|
||||
****Retrieving decimal(16, 16) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing decimal(38, 0):
|
||||
****Retrieving decimal(38, 0) as PDO::PARAM_STR is supported****
|
||||
****Retrieving decimal(38, 0) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing decimal(38, 1):
|
||||
****Retrieving decimal(38, 1) as PDO::PARAM_STR is supported****
|
||||
****Retrieving decimal(38, 1) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing decimal(38, 4):
|
||||
****Retrieving decimal(38, 4) as PDO::PARAM_STR is supported****
|
||||
****Retrieving decimal(38, 4) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing decimal(38, 16):
|
||||
****Retrieving decimal(38, 16) as PDO::PARAM_STR is supported****
|
||||
****Retrieving decimal(38, 16) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing decimal(38, 38):
|
||||
Retrieving decimal(38, 38) data as PDO::PARAM_BOOL should return NULL
|
||||
Retrieving decimal(38, 38) data as PDO::PARAM_INT should return NULL
|
||||
****Retrieving decimal(38, 38) as PDO::PARAM_STR is supported****
|
||||
****Retrieving decimal(38, 38) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing numeric(1, 0):
|
||||
Retrieving numeric(1, 0) data as PDO::PARAM_BOOL should return NULL
|
||||
Retrieving numeric(1, 0) data as PDO::PARAM_INT should return NULL
|
||||
****Retrieving numeric(1, 0) as PDO::PARAM_STR is supported****
|
||||
****Retrieving numeric(1, 0) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing numeric(1, 1):
|
||||
Retrieving numeric(1, 1) data as PDO::PARAM_BOOL should return NULL
|
||||
Retrieving numeric(1, 1) data as PDO::PARAM_INT should return NULL
|
||||
****Retrieving numeric(1, 1) as PDO::PARAM_STR is supported****
|
||||
****Retrieving numeric(1, 1) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing numeric(4, 0):
|
||||
Retrieving numeric(4, 0) data as PDO::PARAM_BOOL should return NULL
|
||||
Retrieving numeric(4, 0) data as PDO::PARAM_INT should return NULL
|
||||
****Retrieving numeric(4, 0) as PDO::PARAM_STR is supported****
|
||||
****Retrieving numeric(4, 0) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing numeric(4, 1):
|
||||
Retrieving numeric(4, 1) data as PDO::PARAM_BOOL should return NULL
|
||||
Retrieving numeric(4, 1) data as PDO::PARAM_INT should return NULL
|
||||
****Retrieving numeric(4, 1) as PDO::PARAM_STR is supported****
|
||||
****Retrieving numeric(4, 1) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing numeric(4, 4):
|
||||
Retrieving numeric(4, 4) data as PDO::PARAM_BOOL should return NULL
|
||||
Retrieving numeric(4, 4) data as PDO::PARAM_INT should return NULL
|
||||
****Retrieving numeric(4, 4) as PDO::PARAM_STR is supported****
|
||||
****Retrieving numeric(4, 4) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing numeric(16, 0):
|
||||
****Retrieving numeric(16, 0) as PDO::PARAM_STR is supported****
|
||||
****Retrieving numeric(16, 0) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing numeric(16, 1):
|
||||
****Retrieving numeric(16, 1) as PDO::PARAM_STR is supported****
|
||||
****Retrieving numeric(16, 1) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing numeric(16, 4):
|
||||
****Retrieving numeric(16, 4) as PDO::PARAM_STR is supported****
|
||||
****Retrieving numeric(16, 4) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing numeric(16, 16):
|
||||
Retrieving numeric(16, 16) data as PDO::PARAM_BOOL should return NULL
|
||||
Retrieving numeric(16, 16) data as PDO::PARAM_INT should return NULL
|
||||
****Retrieving numeric(16, 16) as PDO::PARAM_STR is supported****
|
||||
****Retrieving numeric(16, 16) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing numeric(38, 0):
|
||||
****Retrieving numeric(38, 0) as PDO::PARAM_STR is supported****
|
||||
****Retrieving numeric(38, 0) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing numeric(38, 1):
|
||||
****Retrieving numeric(38, 1) as PDO::PARAM_STR is supported****
|
||||
****Retrieving numeric(38, 1) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing numeric(38, 4):
|
||||
****Retrieving numeric(38, 4) as PDO::PARAM_STR is supported****
|
||||
****Retrieving numeric(38, 4) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing numeric(38, 16):
|
||||
****Retrieving numeric(38, 16) as PDO::PARAM_STR is supported****
|
||||
****Retrieving numeric(38, 16) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing numeric(38, 38):
|
||||
Retrieving numeric(38, 38) data as PDO::PARAM_BOOL should return NULL
|
||||
Retrieving numeric(38, 38) data as PDO::PARAM_INT should return NULL
|
||||
****Retrieving numeric(38, 38) as PDO::PARAM_STR is supported****
|
||||
****Retrieving numeric(38, 38) as PDO::PARAM_LOB is supported****
|
|
@ -0,0 +1,94 @@
|
|||
--TEST--
|
||||
Test for retrieving encrypted data from float types columns using PDO::bindColumn
|
||||
--DESCRIPTION--
|
||||
Test conversion from float types column to output of PDO::PARAM types
|
||||
With or without Always Encrypted, conversion works if:
|
||||
1. From any float type column to PDO::PARAM_STR
|
||||
2. From any float type column to PDO::PARAM_LOB
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
require_once("AEData.inc");
|
||||
|
||||
$dataType = "float";
|
||||
$bits = array(1, 12, 24, 36, 53);
|
||||
$inputValues = array(9223372036854775808.9223372036854775808, -9223372036854775808.9223372036854775808);
|
||||
$numint = 19;
|
||||
|
||||
try {
|
||||
$conn = connect("", array(), PDO::ERRMODE_SILENT);
|
||||
foreach ($bits as $m) {
|
||||
// compute the epsilon for comparing doubles
|
||||
// when $m <= 24, the precision is 7 digits
|
||||
// when $m > 24, the precision is 15 digits, but PHP float only supports up to 14 digits
|
||||
$epsilon;
|
||||
if ($m <= 24) {
|
||||
$epsilon = pow(10, $numint - 7);
|
||||
} else {
|
||||
$epsilon = pow(10, $numint - 14);
|
||||
}
|
||||
|
||||
$typeFull = "$dataType($m)";
|
||||
echo "\nTesting $typeFull:\n";
|
||||
|
||||
//create and populate table containing float(m) columns
|
||||
$tbname = "test_" . $dataType . $m;
|
||||
$colMetaArr = array(new ColumnMeta($typeFull, "c_det"), new ColumnMeta($typeFull, "c_rand", null, "randomized"));
|
||||
createTable($conn, $tbname, $colMetaArr);
|
||||
insertRow($conn, $tbname, array("c_det" => $inputValues[0], "c_rand" => $inputValues[1]));
|
||||
|
||||
// fetchby specifying PDO::PARAM_ types with PDO::bindColumn
|
||||
$query = "SELECT c_det, c_rand FROM $tbname";
|
||||
foreach ($pdoParamTypes as $pdoParamType) {
|
||||
$det = "";
|
||||
$rand = "";
|
||||
$stmt = $conn->prepare($query);
|
||||
$stmt->execute();
|
||||
$stmt->bindColumn('c_det', $det, constant($pdoParamType));
|
||||
$stmt->bindColumn('c_rand', $rand, constant($pdoParamType));
|
||||
$row = $stmt->fetch(PDO::FETCH_BOUND);
|
||||
|
||||
// check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_NULL or PDO::PARAM_INT
|
||||
// with or without AE: should not work
|
||||
if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_NULL" || $pdoParamType == "PDO::PARAM_INT") {
|
||||
if (!is_null($det) || !is_null($rand)) {
|
||||
echo "Retriving $typeFull data as $pdoParamType should return NULL\n";
|
||||
}
|
||||
} else {
|
||||
if (abs($det - $inputValues[0]) < $epsilon && abs($rand - $inputValues[1]) < $epsilon) {
|
||||
echo "****Retrieving $typeFull as $pdoParamType is supported****\n";
|
||||
} else {
|
||||
echo "Retrieving $typeFull as $pdoParamType fails\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
dropTable($conn, $tbname);
|
||||
}
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
} catch (PDOException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
Testing float(1):
|
||||
****Retrieving float(1) as PDO::PARAM_STR is supported****
|
||||
****Retrieving float(1) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing float(12):
|
||||
****Retrieving float(12) as PDO::PARAM_STR is supported****
|
||||
****Retrieving float(12) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing float(24):
|
||||
****Retrieving float(24) as PDO::PARAM_STR is supported****
|
||||
****Retrieving float(24) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing float(36):
|
||||
****Retrieving float(36) as PDO::PARAM_STR is supported****
|
||||
****Retrieving float(36) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing float(53):
|
||||
****Retrieving float(53) as PDO::PARAM_STR is supported****
|
||||
****Retrieving float(53) as PDO::PARAM_LOB is supported****
|
|
@ -0,0 +1,132 @@
|
|||
--TEST--
|
||||
Test for retrieving encrypted data from nchar types columns using PDO::bindColumn
|
||||
--DESCRIPTION--
|
||||
Test conversion from nchar types column to output of PDO::PARAM types
|
||||
With or without Always Encrypted, conversion works if:
|
||||
1. From any nchar type column to PDO::PARAM_STR
|
||||
2. From any nchar type column to PDO::PARAM_LOB
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
require_once("AEData.inc");
|
||||
|
||||
$dataTypes = array("nchar", "nvarchar", "nvarchar(max)");
|
||||
$lengths = array(1, 8, 64, 512, 4000);
|
||||
|
||||
try {
|
||||
$conn = connect("", array(), PDO::ERRMODE_SILENT);
|
||||
foreach ($dataTypes as $dataType) {
|
||||
$maxcol = strpos($dataType, "(max)");
|
||||
foreach ($lengths as $m) {
|
||||
if ($maxcol !== false) {
|
||||
$typeFull = $dataType;
|
||||
} else {
|
||||
$typeFull = "$dataType($m)";
|
||||
}
|
||||
echo "\nTesting $typeFull:\n";
|
||||
|
||||
//create and populate table containing nchar(m) or nvarchar(m) columns
|
||||
$tbname = "test_" . str_replace(array('(', ')'), '', $dataType) . $m;
|
||||
$colMetaArr = array(new ColumnMeta($typeFull, "c1"));
|
||||
createTable($conn, $tbname, $colMetaArr);
|
||||
$inputValue = str_repeat("d", $m);
|
||||
insertRow($conn, $tbname, array("c1" => $inputValue));
|
||||
|
||||
// fetch by specifying PDO::PARAM_ types with PDO::bindColumn
|
||||
$query = "SELECT c1 FROM $tbname";
|
||||
foreach ($pdoParamTypes as $pdoParamType) {
|
||||
$det = "";
|
||||
$rand = "";
|
||||
$stmt = $conn->prepare($query);
|
||||
$stmt->execute();
|
||||
$stmt->bindColumn('c1', $c1, constant($pdoParamType));
|
||||
$row = $stmt->fetch(PDO::FETCH_BOUND);
|
||||
|
||||
// check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_NULL or PDO::PARAM_INT
|
||||
// with or without AE: should not work
|
||||
if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_NULL" || $pdoParamType == "PDO::PARAM_INT") {
|
||||
if (!empty($det) || !empty($rand)) {
|
||||
echo "Retrieving $typeFull data as $pdoParamType should not be supported\n";
|
||||
}
|
||||
// check the case when fetching as PDO::PARAM_STR or PDO::PARAM_LOB
|
||||
// with or without AE: should work
|
||||
} else {
|
||||
if (strlen($c1) == $m) {
|
||||
echo "****Retrieving $typeFull as $pdoParamType is supported****\n";
|
||||
} else {
|
||||
echo "Retrieving $typeFull as $pdoParamType fails\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
// cleanup
|
||||
dropTable($conn, $tbname);
|
||||
}
|
||||
}
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
} catch (PDOException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
Testing nchar(1):
|
||||
****Retrieving nchar(1) as PDO::PARAM_STR is supported****
|
||||
****Retrieving nchar(1) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing nchar(8):
|
||||
****Retrieving nchar(8) as PDO::PARAM_STR is supported****
|
||||
****Retrieving nchar(8) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing nchar(64):
|
||||
****Retrieving nchar(64) as PDO::PARAM_STR is supported****
|
||||
****Retrieving nchar(64) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing nchar(512):
|
||||
****Retrieving nchar(512) as PDO::PARAM_STR is supported****
|
||||
****Retrieving nchar(512) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing nchar(4000):
|
||||
****Retrieving nchar(4000) as PDO::PARAM_STR is supported****
|
||||
****Retrieving nchar(4000) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing nvarchar(1):
|
||||
****Retrieving nvarchar(1) as PDO::PARAM_STR is supported****
|
||||
****Retrieving nvarchar(1) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing nvarchar(8):
|
||||
****Retrieving nvarchar(8) as PDO::PARAM_STR is supported****
|
||||
****Retrieving nvarchar(8) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing nvarchar(64):
|
||||
****Retrieving nvarchar(64) as PDO::PARAM_STR is supported****
|
||||
****Retrieving nvarchar(64) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing nvarchar(512):
|
||||
****Retrieving nvarchar(512) as PDO::PARAM_STR is supported****
|
||||
****Retrieving nvarchar(512) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing nvarchar(4000):
|
||||
****Retrieving nvarchar(4000) as PDO::PARAM_STR is supported****
|
||||
****Retrieving nvarchar(4000) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing nvarchar(max):
|
||||
****Retrieving nvarchar(max) as PDO::PARAM_STR is supported****
|
||||
****Retrieving nvarchar(max) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing nvarchar(max):
|
||||
****Retrieving nvarchar(max) as PDO::PARAM_STR is supported****
|
||||
****Retrieving nvarchar(max) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing nvarchar(max):
|
||||
****Retrieving nvarchar(max) as PDO::PARAM_STR is supported****
|
||||
****Retrieving nvarchar(max) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing nvarchar(max):
|
||||
****Retrieving nvarchar(max) as PDO::PARAM_STR is supported****
|
||||
****Retrieving nvarchar(max) as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing nvarchar(max):
|
||||
****Retrieving nvarchar(max) as PDO::PARAM_STR is supported****
|
||||
****Retrieving nvarchar(max) as PDO::PARAM_LOB is supported****
|
|
@ -0,0 +1,128 @@
|
|||
--TEST--
|
||||
Test for retrieving encrypted data from numeric types columns using PDO::bindColumn
|
||||
--DESCRIPTION--
|
||||
Test conversion from numeric types column to output of PDO::PARAM types
|
||||
With or without Always Encrypted, conversion works if:
|
||||
1. From any numeric type except for bigint column to PDO::PARAM_BOOL
|
||||
2. From any numeric type except for bigint column to PDO::PARAM_INT
|
||||
3. From any numeric type column to PDO::PARAM_STR
|
||||
4. From any numeric type column to PDO::PARAM_LOB
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
require_once("AEData.inc");
|
||||
|
||||
$dataTypes = array( "bit", "tinyint", "smallint", "int", "bigint", "real");
|
||||
$epsilon = 1;
|
||||
|
||||
try {
|
||||
$conn = connect("", array(), PDO::ERRMODE_SILENT);
|
||||
foreach ($dataTypes as $dataType) {
|
||||
echo "\nTesting $dataType:\n";
|
||||
|
||||
// create and populate table containing bit, tinyint, smallint, int, bigint, or real columns
|
||||
$tbname = "test_" . $dataType;
|
||||
$colMetaArr = array(new ColumnMeta($dataType, "c_det"), new ColumnMeta($dataType, "c_rand", null, "randomized"));
|
||||
createTable($conn, $tbname, $colMetaArr);
|
||||
$inputValues = array_slice(${explode("(", $dataType)[0] . "_params"}, 1, 2);
|
||||
insertRow($conn, $tbname, array("c_det" => $inputValues[0], "c_rand" => $inputValues[1]));
|
||||
|
||||
// fetch by specifying PDO::PARAM_ types with PDO::bindColumn
|
||||
$query = "SELECT c_det, c_rand FROM $tbname";
|
||||
foreach ($pdoParamTypes as $pdoParamType) {
|
||||
$det = "";
|
||||
$rand = "";
|
||||
$stmt = $conn->prepare($query);
|
||||
$stmt->execute();
|
||||
$stmt->bindColumn('c_det', $det, constant($pdoParamType));
|
||||
$stmt->bindColumn('c_rand', $rand, constant($pdoParamType));
|
||||
$row = $stmt->fetch(PDO::FETCH_BOUND);
|
||||
|
||||
// check the case when fetching as PDO::PARAM_NULL
|
||||
// with or without AE: should not work
|
||||
if ($pdoParamType == "PDO::PARAM_NULL") {
|
||||
if (!is_null($det) || !is_null($rand)) {
|
||||
echo "Retrieving $dataType data as $pdoParamType should not be supported\n";
|
||||
}
|
||||
// check the case when fetching as PDO::PARAM_BOOL or PDO::PARAM_INT
|
||||
// with or without AE: should only not work with bigint
|
||||
} else if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_INT") {
|
||||
if ($dataType == "bigint") {
|
||||
if (!is_null($det) || !is_null($rand)) {
|
||||
echo "Retrieving $dataType data as $pdoParamType should not be supported\n";
|
||||
}
|
||||
} else if ($dataType == "real") {
|
||||
if (abs($det - $inputValues[0]) < $epsilon && abs($rand - $inputValues[1]) < $epsilon) {
|
||||
echo "****Retrieving $dataType as $pdoParamType is supported****\n";
|
||||
} else {
|
||||
echo "Retrieving $dataType as $pdoParamType fails\n";
|
||||
}
|
||||
} else {
|
||||
if ($det == $inputValues[0] && $rand == $inputValues[1]) {
|
||||
echo "****Retrieving $dataType as $pdoParamType is supported****\n";
|
||||
} else {
|
||||
echo "Retrieving $dataType as $pdoParamType fails\n";
|
||||
}
|
||||
}
|
||||
// check the case when fetching as PDO::PARAM_BOOL, PDO::PARAM_INT, PDO::PARAM_STR or PDO::PARAM_LOB
|
||||
// with or without AE: should work
|
||||
} else {
|
||||
if ($dataType == "real") {
|
||||
if (abs($det - $inputValues[0]) < $epsilon && abs($rand - $inputValues[1]) < $epsilon) {
|
||||
echo "****Retrieving $dataType as $pdoParamType is supported****\n";
|
||||
} else {
|
||||
echo "Retrieving $dataType as $pdoParamType fails\n";
|
||||
}
|
||||
} else {
|
||||
if ($det == $inputValues[0] && $rand == $inputValues[1]) {
|
||||
echo "****Retrieving $dataType as $pdoParamType is supported****\n";
|
||||
} else {
|
||||
echo "Retrieving $dataType as $pdoParamType fails\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dropTable($conn, $tbname);
|
||||
}
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
} catch (PDOException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
Testing bit:
|
||||
****Retrieving bit as PDO::PARAM_BOOL is supported****
|
||||
****Retrieving bit as PDO::PARAM_INT is supported****
|
||||
****Retrieving bit as PDO::PARAM_STR is supported****
|
||||
****Retrieving bit as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing tinyint:
|
||||
****Retrieving tinyint as PDO::PARAM_BOOL is supported****
|
||||
****Retrieving tinyint as PDO::PARAM_INT is supported****
|
||||
****Retrieving tinyint as PDO::PARAM_STR is supported****
|
||||
****Retrieving tinyint as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing smallint:
|
||||
****Retrieving smallint as PDO::PARAM_BOOL is supported****
|
||||
****Retrieving smallint as PDO::PARAM_INT is supported****
|
||||
****Retrieving smallint as PDO::PARAM_STR is supported****
|
||||
****Retrieving smallint as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing int:
|
||||
****Retrieving int as PDO::PARAM_BOOL is supported****
|
||||
****Retrieving int as PDO::PARAM_INT is supported****
|
||||
****Retrieving int as PDO::PARAM_STR is supported****
|
||||
****Retrieving int as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing bigint:
|
||||
****Retrieving bigint as PDO::PARAM_STR is supported****
|
||||
****Retrieving bigint as PDO::PARAM_LOB is supported****
|
||||
|
||||
Testing real:
|
||||
****Retrieving real as PDO::PARAM_BOOL is supported****
|
||||
****Retrieving real as PDO::PARAM_INT is supported****
|
||||
****Retrieving real as PDO::PARAM_STR is supported****
|
||||
****Retrieving real as PDO::PARAM_LOB is supported****
|
|
@ -0,0 +1,159 @@
|
|||
--TEST--
|
||||
Test for inserting encrypted data into binary types columns with different sizes
|
||||
--DESCRIPTION--
|
||||
Test conversions between different binary types of different sizes
|
||||
With or without Always Encrypted, implicit conversion works if:
|
||||
1. From input of PDO::PARAM_STR to a any binary column
|
||||
2. From input of PDO::PARAM_LOB to a any binary column
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
require_once("AEData.inc");
|
||||
|
||||
$dataTypes = array("binary", "varbinary", "varbinary(max)");
|
||||
$lengths = array(2, 8, 64, 512, 4000);
|
||||
|
||||
try {
|
||||
$conn = connect("", array(), PDO::ERRMODE_SILENT);
|
||||
foreach ($dataTypes as $dataType) {
|
||||
$maxcol = strpos($dataType, "(max)");
|
||||
foreach ($lengths as $m) {
|
||||
if ($maxcol !== false) {
|
||||
$typeFull = $dataType;
|
||||
} else {
|
||||
$typeFull = "$dataType($m)";
|
||||
}
|
||||
echo "\nTesting $typeFull:\n";
|
||||
|
||||
// create table containing binary(m) or varbinary(m) columns
|
||||
$tbname = "test_" . str_replace(array('(', ')'), '', $dataType) . $m;
|
||||
$colMetaArr = array(new ColumnMeta($typeFull, "c_det"), new ColumnMeta($typeFull, "c_rand", null, "randomized"));
|
||||
createTable($conn, $tbname, $colMetaArr);
|
||||
$inputValues = array(str_repeat("d", $m), str_repeat("r", $m));
|
||||
|
||||
// insert by specifying PDO::PARAM_ types
|
||||
foreach ($pdoParamTypes as $pdoParamType) {
|
||||
$r;
|
||||
if ($pdoParamType == 'PDO::PARAM_STR' || $pdoParamType == 'PDO::PARAM_LOB') {
|
||||
$stmt = insertRow($conn, $tbname, array("c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType, 0, "PDO::SQLSRV_ENCODING_BINARY"),
|
||||
"c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType, 0, "PDO::SQLSRV_ENCODING_BINARY")), "prepareBindParam", $r);
|
||||
} else {
|
||||
$stmt = insertRow($conn, $tbname, array("c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType), "c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType)), "prepareBindParam", $r);
|
||||
}
|
||||
|
||||
// check the case when inserting as PDO::PARAM_BOOL or PDO::PARAM_INT
|
||||
// with or without AE: should not work
|
||||
if ($pdoParamType == "PDO::PARAM_BOOL" || $pdoParamType == "PDO::PARAM_INT") {
|
||||
if ($r !== false) {
|
||||
echo "Conversion from $pdoParamType to $typeFull should not be supported\n";
|
||||
}
|
||||
// check the case when inserting as PDO::PARAM_NULL
|
||||
// with AE: NULL is inserted
|
||||
// without AE: insertion fails
|
||||
} elseif ($pdoParamType == "PDO::PARAM_NULL") {
|
||||
if (isAEConnected()) {
|
||||
if ($r === false) {
|
||||
echo "Conversion from $pdoParamType to $typeFull should be supported\n";
|
||||
} else {
|
||||
$sql = "SELECT c_det, c_rand FROM $tbname";
|
||||
$stmt = $conn->query($sql);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (!is_null($row['c_det']) && !is_null($row['c_rand'])) {
|
||||
echo "Conversion from $pdoParamType to $typeFull should insert NULL\n";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($r !== false) {
|
||||
echo "Conversion from $pdoParamType to $typeFull should not be supported\n";
|
||||
}
|
||||
}
|
||||
// check the case when inserting as PDO::PARAM_STR or PDO::PARAM_LOB
|
||||
// with or without AE: should work
|
||||
} else {
|
||||
if ($r === false) {
|
||||
echo "Conversion from $pdoParamType to $typeFull should be supported\n";
|
||||
} else {
|
||||
$sql = "SELECT c_det, c_rand FROM $tbname";
|
||||
$stmt = $conn->query($sql);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (trim($row['c_det']) == $inputValues[0] && trim($row['c_rand']) == $inputValues[1]) {
|
||||
echo "****Conversion from $pdoParamType to $typeFull is supported****\n";
|
||||
} else {
|
||||
echo "Conversion from $pdoParamType to $typeFull causes data corruption\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
// cleanup
|
||||
$conn->query("TRUNCATE TABLE $tbname");
|
||||
}
|
||||
dropTable($conn, $tbname);
|
||||
}
|
||||
}
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
} catch (PDOException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
Testing binary(2):
|
||||
****Conversion from PDO::PARAM_STR to binary(2) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to binary(2) is supported****
|
||||
|
||||
Testing binary(8):
|
||||
****Conversion from PDO::PARAM_STR to binary(8) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to binary(8) is supported****
|
||||
|
||||
Testing binary(64):
|
||||
****Conversion from PDO::PARAM_STR to binary(64) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to binary(64) is supported****
|
||||
|
||||
Testing binary(512):
|
||||
****Conversion from PDO::PARAM_STR to binary(512) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to binary(512) is supported****
|
||||
|
||||
Testing binary(4000):
|
||||
****Conversion from PDO::PARAM_STR to binary(4000) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to binary(4000) is supported****
|
||||
|
||||
Testing varbinary(2):
|
||||
****Conversion from PDO::PARAM_STR to varbinary(2) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to varbinary(2) is supported****
|
||||
|
||||
Testing varbinary(8):
|
||||
****Conversion from PDO::PARAM_STR to varbinary(8) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to varbinary(8) is supported****
|
||||
|
||||
Testing varbinary(64):
|
||||
****Conversion from PDO::PARAM_STR to varbinary(64) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to varbinary(64) is supported****
|
||||
|
||||
Testing varbinary(512):
|
||||
****Conversion from PDO::PARAM_STR to varbinary(512) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to varbinary(512) is supported****
|
||||
|
||||
Testing varbinary(4000):
|
||||
****Conversion from PDO::PARAM_STR to varbinary(4000) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to varbinary(4000) is supported****
|
||||
|
||||
Testing varbinary(max):
|
||||
****Conversion from PDO::PARAM_STR to varbinary(max) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to varbinary(max) is supported****
|
||||
|
||||
Testing varbinary(max):
|
||||
****Conversion from PDO::PARAM_STR to varbinary(max) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to varbinary(max) is supported****
|
||||
|
||||
Testing varbinary(max):
|
||||
****Conversion from PDO::PARAM_STR to varbinary(max) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to varbinary(max) is supported****
|
||||
|
||||
Testing varbinary(max):
|
||||
****Conversion from PDO::PARAM_STR to varbinary(max) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to varbinary(max) is supported****
|
||||
|
||||
Testing varbinary(max):
|
||||
****Conversion from PDO::PARAM_STR to varbinary(max) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to varbinary(max) is supported****
|
|
@ -0,0 +1,190 @@
|
|||
--TEST--
|
||||
Test for inserting encrypted data into char types columns with different sizes
|
||||
--DESCRIPTION--
|
||||
Test conversions between different char types of different sizes
|
||||
With or without Always Encrypted, implicit conversion works if:
|
||||
1. From input of PDO::PARAM_BOOL to any char column
|
||||
2. From input of PDO::PARAM_INT to any char column
|
||||
3. From input of PDO::PARAM_STR to any char column
|
||||
4. From input of PDO::PARAM_LOB to any char column
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
require_once("AEData.inc");
|
||||
|
||||
$dataTypes = array("char", "varchar", "varchar(max)");
|
||||
$lengths = array(1, 8, 64, 512, 4096, 8000);
|
||||
|
||||
try {
|
||||
$conn = connect();
|
||||
foreach ($dataTypes as $dataType) {
|
||||
$maxcol = strpos($dataType, "(max)");
|
||||
foreach ($lengths as $m) {
|
||||
if ($maxcol !== false) {
|
||||
$typeFull = $dataType;
|
||||
} else {
|
||||
$typeFull = "$dataType($m)";
|
||||
}
|
||||
echo "\nTesting $typeFull:\n";
|
||||
|
||||
// create table containing a char(m) or varchar(m) column
|
||||
// only one column is created because a row has a limitation of 8060 bytes
|
||||
// for lengths 4096 and 8000, cannot create 2 columns as it will exceed the maximum row sizes
|
||||
// for AE, only testing randomized here, deterministic is tested in the nchar test
|
||||
$tbname = getTableName("test_" . str_replace(array('(', ')'), '', $dataType) . $m);
|
||||
$colMetaArr = array(new ColumnMeta($typeFull, "c1", null, "randomized"));
|
||||
createTable($conn, $tbname, $colMetaArr);
|
||||
$input = str_repeat("d", $m);
|
||||
|
||||
// insert by specifying PDO::PARAM_ types
|
||||
foreach ($pdoParamTypes as $pdoParamType) {
|
||||
$r;
|
||||
$stmt = insertRow($conn, $tbname, array( "c1" => new BindParamOp(1, $input, $pdoParamType)), "prepareBindParam", $r);
|
||||
|
||||
// check the case when inserting as PDO::PARAM_NULL
|
||||
// with or without AE: NULL is inserted
|
||||
if ($pdoParamType == "PDO::PARAM_NULL") {
|
||||
if ($r === false) {
|
||||
echo "Conversion from $pdoParamType to $typeFull should be supported\n";
|
||||
} else {
|
||||
$sql = "SELECT c1 FROM $tbname";
|
||||
$stmt = $conn->query($sql);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (!is_null($row['c1'])) {
|
||||
echo "Conversion from $pdoParamType to $typeFull should insert NULL\n";
|
||||
}
|
||||
}
|
||||
// check the case when inserting as PDO::PARAM_BOOL, PDO::PARAM_INT, PDO::PARAM_STR or PDO{{PARAM_LOB
|
||||
// with or without AE: should work
|
||||
} else {
|
||||
$sql = "SELECT c1 FROM $tbname";
|
||||
$stmt = $conn->query($sql);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (strlen($row['c1']) == $m) {
|
||||
echo "****Conversion from $pdoParamType to $typeFull is supported****\n";
|
||||
} else {
|
||||
echo "Conversion from $pdoParamType to $typeFull causes data corruption\n";
|
||||
}
|
||||
}
|
||||
// cleanup
|
||||
$conn->query("TRUNCATE TABLE $tbname");
|
||||
}
|
||||
dropTable($conn, $tbname);
|
||||
}
|
||||
}
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
} catch (PDOException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
Testing char(1):
|
||||
****Conversion from PDO::PARAM_BOOL to char(1) is supported****
|
||||
****Conversion from PDO::PARAM_INT to char(1) is supported****
|
||||
****Conversion from PDO::PARAM_STR to char(1) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to char(1) is supported****
|
||||
|
||||
Testing char(8):
|
||||
****Conversion from PDO::PARAM_BOOL to char(8) is supported****
|
||||
****Conversion from PDO::PARAM_INT to char(8) is supported****
|
||||
****Conversion from PDO::PARAM_STR to char(8) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to char(8) is supported****
|
||||
|
||||
Testing char(64):
|
||||
****Conversion from PDO::PARAM_BOOL to char(64) is supported****
|
||||
****Conversion from PDO::PARAM_INT to char(64) is supported****
|
||||
****Conversion from PDO::PARAM_STR to char(64) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to char(64) is supported****
|
||||
|
||||
Testing char(512):
|
||||
****Conversion from PDO::PARAM_BOOL to char(512) is supported****
|
||||
****Conversion from PDO::PARAM_INT to char(512) is supported****
|
||||
****Conversion from PDO::PARAM_STR to char(512) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to char(512) is supported****
|
||||
|
||||
Testing char(4096):
|
||||
****Conversion from PDO::PARAM_BOOL to char(4096) is supported****
|
||||
****Conversion from PDO::PARAM_INT to char(4096) is supported****
|
||||
****Conversion from PDO::PARAM_STR to char(4096) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to char(4096) is supported****
|
||||
|
||||
Testing char(8000):
|
||||
****Conversion from PDO::PARAM_BOOL to char(8000) is supported****
|
||||
****Conversion from PDO::PARAM_INT to char(8000) is supported****
|
||||
****Conversion from PDO::PARAM_STR to char(8000) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to char(8000) is supported****
|
||||
|
||||
Testing varchar(1):
|
||||
****Conversion from PDO::PARAM_BOOL to varchar(1) is supported****
|
||||
****Conversion from PDO::PARAM_INT to varchar(1) is supported****
|
||||
****Conversion from PDO::PARAM_STR to varchar(1) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to varchar(1) is supported****
|
||||
|
||||
Testing varchar(8):
|
||||
****Conversion from PDO::PARAM_BOOL to varchar(8) is supported****
|
||||
****Conversion from PDO::PARAM_INT to varchar(8) is supported****
|
||||
****Conversion from PDO::PARAM_STR to varchar(8) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to varchar(8) is supported****
|
||||
|
||||
Testing varchar(64):
|
||||
****Conversion from PDO::PARAM_BOOL to varchar(64) is supported****
|
||||
****Conversion from PDO::PARAM_INT to varchar(64) is supported****
|
||||
****Conversion from PDO::PARAM_STR to varchar(64) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to varchar(64) is supported****
|
||||
|
||||
Testing varchar(512):
|
||||
****Conversion from PDO::PARAM_BOOL to varchar(512) is supported****
|
||||
****Conversion from PDO::PARAM_INT to varchar(512) is supported****
|
||||
****Conversion from PDO::PARAM_STR to varchar(512) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to varchar(512) is supported****
|
||||
|
||||
Testing varchar(4096):
|
||||
****Conversion from PDO::PARAM_BOOL to varchar(4096) is supported****
|
||||
****Conversion from PDO::PARAM_INT to varchar(4096) is supported****
|
||||
****Conversion from PDO::PARAM_STR to varchar(4096) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to varchar(4096) is supported****
|
||||
|
||||
Testing varchar(8000):
|
||||
****Conversion from PDO::PARAM_BOOL to varchar(8000) is supported****
|
||||
****Conversion from PDO::PARAM_INT to varchar(8000) is supported****
|
||||
****Conversion from PDO::PARAM_STR to varchar(8000) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to varchar(8000) is supported****
|
||||
|
||||
Testing varchar(max):
|
||||
****Conversion from PDO::PARAM_BOOL to varchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_INT to varchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_STR to varchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to varchar(max) is supported****
|
||||
|
||||
Testing varchar(max):
|
||||
****Conversion from PDO::PARAM_BOOL to varchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_INT to varchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_STR to varchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to varchar(max) is supported****
|
||||
|
||||
Testing varchar(max):
|
||||
****Conversion from PDO::PARAM_BOOL to varchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_INT to varchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_STR to varchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to varchar(max) is supported****
|
||||
|
||||
Testing varchar(max):
|
||||
****Conversion from PDO::PARAM_BOOL to varchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_INT to varchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_STR to varchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to varchar(max) is supported****
|
||||
|
||||
Testing varchar(max):
|
||||
****Conversion from PDO::PARAM_BOOL to varchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_INT to varchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_STR to varchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to varchar(max) is supported****
|
||||
|
||||
Testing varchar(max):
|
||||
****Conversion from PDO::PARAM_BOOL to varchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_INT to varchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_STR to varchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to varchar(max) is supported****
|
|
@ -1,7 +1,12 @@
|
|||
--TEST--
|
||||
Test for inserting and retrieving encrypted data of datetime types
|
||||
Test for inserting encrypted data into datetime types columns
|
||||
--DESCRIPTION--
|
||||
Use PDOstatement::bindParam with all PDO::PARAM_ types
|
||||
Test conversions between different datetime types
|
||||
With or without Always Encrypted, implicit conversion works if:
|
||||
1. From input of PDO::PARAM_BOOL to a any datetime column
|
||||
2. From input of PDO::PARAM_INT to a any datetime column
|
||||
3. From input of PDO::PARAM_STR to a any datetime column
|
||||
4. From input of PDO::PARAM_LOB to a any datetime column
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
|
@ -9,28 +14,48 @@ Use PDOstatement::bindParam with all PDO::PARAM_ types
|
|||
require_once("MsCommon_mid-refactor.inc");
|
||||
require_once("AEData.inc");
|
||||
|
||||
$dataTypes = array( "date", "datetime", "datetime2", "smalldatetime", "time", "datetimeoffset" );
|
||||
$dataTypes = array( "date", "datetime", "smalldatetime");
|
||||
|
||||
try {
|
||||
$conn = connect();
|
||||
foreach ($dataTypes as $dataType) {
|
||||
echo "\nTesting $dataType:\n";
|
||||
|
||||
// create table
|
||||
$tbname = getTableName();
|
||||
// create table containing date, datetime or smalldatetime columns
|
||||
$tbname = "test_" . $dataType;
|
||||
$colMetaArr = array( new ColumnMeta($dataType, "c_det"), new ColumnMeta($dataType, "c_rand", null, "randomized"));
|
||||
createTable($conn, $tbname, $colMetaArr);
|
||||
|
||||
// prepare statement for inserting into table
|
||||
// insert by specifying PDO::PARAM_ types
|
||||
foreach ($pdoParamTypes as $pdoParamType) {
|
||||
// insert a row
|
||||
$inputValues = array_slice(${explode("(", $dataType)[0] . "_params"}, 1, 2);
|
||||
$r;
|
||||
$stmt = insertRow($conn, $tbname, array( "c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType), "c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType)), "prepareBindParam", $r);
|
||||
if ($r === false) {
|
||||
isIncompatibleTypesError($stmt, $dataType, $pdoParamType);
|
||||
|
||||
// check the case when inserting as PDO::PARAM_NULL
|
||||
// with or without AE: NULL is inserted
|
||||
if ($pdoParamType == "PDO::PARAM_NULL") {
|
||||
if ($r === false) {
|
||||
echo "Conversion from $pdoParamType to $dataType should be supported\n";
|
||||
} else {
|
||||
$sql = "SELECT c_det, c_rand FROM $tbname";
|
||||
$stmt = $conn->query($sql);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (!is_null($row['c_det']) || !is_null($row['c_rand'])) {
|
||||
echo "Conversion from $pdoParamType to $dataType should insert NULL\n";
|
||||
}
|
||||
}
|
||||
// check the case when inserting as PDO::PARAM_BOOL, PDO::PARAM_INT, PDO::PARAM_STR or PDO::PARAM_LOB
|
||||
// with or without AE: should work
|
||||
} else {
|
||||
echo "****PDO param type $pdoParamType is compatible with encrypted $dataType****\n";
|
||||
fetchAll($conn, $tbname);
|
||||
$sql = "SELECT c_det, c_rand FROM $tbname";
|
||||
$stmt = $conn->query($sql);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (strpos($row['c_det'], $inputValues[0]) !== false && strpos($row['c_rand'], $inputValues[1]) !== false) {
|
||||
echo "****Conversion from $pdoParamType to $dataType is supported****\n";
|
||||
} else {
|
||||
echo "Conversion from $pdoParamType to $dataType causes data corruption\n";
|
||||
}
|
||||
}
|
||||
$conn->query("TRUNCATE TABLE $tbname");
|
||||
}
|
||||
|
@ -43,105 +68,20 @@ try {
|
|||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
|
||||
Testing date:
|
||||
****PDO param type PDO::PARAM_BOOL is compatible with encrypted date****
|
||||
c_det: 0001-01-01
|
||||
c_rand: 9999-12-31
|
||||
****PDO param type PDO::PARAM_NULL is compatible with encrypted date****
|
||||
c_det:
|
||||
c_rand:
|
||||
****PDO param type PDO::PARAM_INT is compatible with encrypted date****
|
||||
c_det: 0001-01-01
|
||||
c_rand: 9999-12-31
|
||||
****PDO param type PDO::PARAM_STR is compatible with encrypted date****
|
||||
c_det: 0001-01-01
|
||||
c_rand: 9999-12-31
|
||||
****PDO param type PDO::PARAM_LOB is compatible with encrypted date****
|
||||
c_det: 0001-01-01
|
||||
c_rand: 9999-12-31
|
||||
****Conversion from PDO::PARAM_BOOL to date is supported****
|
||||
****Conversion from PDO::PARAM_INT to date is supported****
|
||||
****Conversion from PDO::PARAM_STR to date is supported****
|
||||
****Conversion from PDO::PARAM_LOB to date is supported****
|
||||
|
||||
Testing datetime:
|
||||
****PDO param type PDO::PARAM_BOOL is compatible with encrypted datetime****
|
||||
c_det: 1753-01-01 00:00:00.000
|
||||
c_rand: 9999-12-31 23:59:59.997
|
||||
****PDO param type PDO::PARAM_NULL is compatible with encrypted datetime****
|
||||
c_det:
|
||||
c_rand:
|
||||
****PDO param type PDO::PARAM_INT is compatible with encrypted datetime****
|
||||
c_det: 1753-01-01 00:00:00.000
|
||||
c_rand: 9999-12-31 23:59:59.997
|
||||
****PDO param type PDO::PARAM_STR is compatible with encrypted datetime****
|
||||
c_det: 1753-01-01 00:00:00.000
|
||||
c_rand: 9999-12-31 23:59:59.997
|
||||
****PDO param type PDO::PARAM_LOB is compatible with encrypted datetime****
|
||||
c_det: 1753-01-01 00:00:00.000
|
||||
c_rand: 9999-12-31 23:59:59.997
|
||||
|
||||
Testing datetime2:
|
||||
****PDO param type PDO::PARAM_BOOL is compatible with encrypted datetime2****
|
||||
c_det: 0001-01-01 00:00:00.0000000
|
||||
c_rand: 9999-12-31 23:59:59.9999999
|
||||
****PDO param type PDO::PARAM_NULL is compatible with encrypted datetime2****
|
||||
c_det:
|
||||
c_rand:
|
||||
****PDO param type PDO::PARAM_INT is compatible with encrypted datetime2****
|
||||
c_det: 0001-01-01 00:00:00.0000000
|
||||
c_rand: 9999-12-31 23:59:59.9999999
|
||||
****PDO param type PDO::PARAM_STR is compatible with encrypted datetime2****
|
||||
c_det: 0001-01-01 00:00:00.0000000
|
||||
c_rand: 9999-12-31 23:59:59.9999999
|
||||
****PDO param type PDO::PARAM_LOB is compatible with encrypted datetime2****
|
||||
c_det: 0001-01-01 00:00:00.0000000
|
||||
c_rand: 9999-12-31 23:59:59.9999999
|
||||
****Conversion from PDO::PARAM_BOOL to datetime is supported****
|
||||
****Conversion from PDO::PARAM_INT to datetime is supported****
|
||||
****Conversion from PDO::PARAM_STR to datetime is supported****
|
||||
****Conversion from PDO::PARAM_LOB to datetime is supported****
|
||||
|
||||
Testing smalldatetime:
|
||||
****PDO param type PDO::PARAM_BOOL is compatible with encrypted smalldatetime****
|
||||
c_det: 1900-01-01 00:00:00
|
||||
c_rand: 2079-06-05 23:59:00
|
||||
****PDO param type PDO::PARAM_NULL is compatible with encrypted smalldatetime****
|
||||
c_det:
|
||||
c_rand:
|
||||
****PDO param type PDO::PARAM_INT is compatible with encrypted smalldatetime****
|
||||
c_det: 1900-01-01 00:00:00
|
||||
c_rand: 2079-06-05 23:59:00
|
||||
****PDO param type PDO::PARAM_STR is compatible with encrypted smalldatetime****
|
||||
c_det: 1900-01-01 00:00:00
|
||||
c_rand: 2079-06-05 23:59:00
|
||||
****PDO param type PDO::PARAM_LOB is compatible with encrypted smalldatetime****
|
||||
c_det: 1900-01-01 00:00:00
|
||||
c_rand: 2079-06-05 23:59:00
|
||||
|
||||
Testing time:
|
||||
****PDO param type PDO::PARAM_BOOL is compatible with encrypted time****
|
||||
c_det: 00:00:00.0000000
|
||||
c_rand: 23:59:59.9999999
|
||||
****PDO param type PDO::PARAM_NULL is compatible with encrypted time****
|
||||
c_det:
|
||||
c_rand:
|
||||
****PDO param type PDO::PARAM_INT is compatible with encrypted time****
|
||||
c_det: 00:00:00.0000000
|
||||
c_rand: 23:59:59.9999999
|
||||
****PDO param type PDO::PARAM_STR is compatible with encrypted time****
|
||||
c_det: 00:00:00.0000000
|
||||
c_rand: 23:59:59.9999999
|
||||
****PDO param type PDO::PARAM_LOB is compatible with encrypted time****
|
||||
c_det: 00:00:00.0000000
|
||||
c_rand: 23:59:59.9999999
|
||||
|
||||
Testing datetimeoffset:
|
||||
****PDO param type PDO::PARAM_BOOL is compatible with encrypted datetimeoffset****
|
||||
c_det: 0001-01-01 00:00:00.0000000 -14:00
|
||||
c_rand: 9999-12-31 23:59:59.9999999 +14:00
|
||||
****PDO param type PDO::PARAM_NULL is compatible with encrypted datetimeoffset****
|
||||
c_det:
|
||||
c_rand:
|
||||
****PDO param type PDO::PARAM_INT is compatible with encrypted datetimeoffset****
|
||||
c_det: 0001-01-01 00:00:00.0000000 -14:00
|
||||
c_rand: 9999-12-31 23:59:59.9999999 +14:00
|
||||
****PDO param type PDO::PARAM_STR is compatible with encrypted datetimeoffset****
|
||||
c_det: 0001-01-01 00:00:00.0000000 -14:00
|
||||
c_rand: 9999-12-31 23:59:59.9999999 +14:00
|
||||
****PDO param type PDO::PARAM_LOB is compatible with encrypted datetimeoffset****
|
||||
c_det: 0001-01-01 00:00:00.0000000 -14:00
|
||||
c_rand: 9999-12-31 23:59:59.9999999 +14:00
|
||||
****Conversion from PDO::PARAM_BOOL to smalldatetime is supported****
|
||||
****Conversion from PDO::PARAM_INT to smalldatetime is supported****
|
||||
****Conversion from PDO::PARAM_STR to smalldatetime is supported****
|
||||
****Conversion from PDO::PARAM_LOB to smalldatetime is supported****
|
|
@ -0,0 +1,175 @@
|
|||
--TEST--
|
||||
Test for inserting encrypted data into datetime types with different precisions columns
|
||||
--DESCRIPTION--
|
||||
Test conversions between different datetime types
|
||||
With or without Always Encrypted, implicit conversion works if:
|
||||
1. From input of PDO::PARAM_BOOL to a any datetime column
|
||||
2. From input of PDO::PARAM_INT to a any datetime column
|
||||
3. From input of PDO::PARAM_STR to a any datetime column
|
||||
4. From input of PDO::PARAM_LOB to a any datetime column
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
require_once("AEData.inc");
|
||||
|
||||
function compareDate($dtout, $dtin, $dataType) {
|
||||
if ($dataType == "datetimeoffset") {
|
||||
$dtarr = explode(' ', $dtin);
|
||||
if (strpos($dtout, $dtarr[0]) !== false && strpos($dtout, $dtarr[1]) !== false && strpos($dtout, $dtarr[2]) !== false) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (strpos($dtout, $dtin) !== false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$dataTypes = array("datetime2", "datetimeoffset", "time");
|
||||
$precisions = array(/*0,*/ 1, 2, 4, 7);
|
||||
$inputValuesInit = array("datetime2" => array("0001-01-01 00:00:00", "9999-12-31 23:59:59"),
|
||||
"datetimeoffset" => array("0001-01-01 00:00:00 -14:00", "9999-12-31 23:59:59 +14:00"),
|
||||
"time" => array("00:00:00", "23:59:59"));
|
||||
|
||||
try {
|
||||
$conn = connect("", array(), PDO::ERRMODE_SILENT);
|
||||
foreach ($dataTypes as $dataType) {
|
||||
foreach ($precisions as $m) {
|
||||
// add $m number of decimal digits to the some input values
|
||||
$inputValues[0] = $inputValuesInit[$dataType][0];
|
||||
$inputValues[1] = $inputValuesInit[$dataType][1];
|
||||
if ($m != 0) {
|
||||
if ($dataType == "datetime2") {
|
||||
$inputValues[1] .= "." . str_repeat("9", $m);
|
||||
} else if ($dataType == "datetimeoffset") {
|
||||
$dtoffsetPieces = explode(" ", $inputValues[1]);
|
||||
$inputValues[1] = $dtoffsetPieces[0] . " " . $dtoffsetPieces[1] . "." . str_repeat("9", $m) . " " . $dtoffsetPieces[2];
|
||||
} else if ($dataType == "time") {
|
||||
$inputValues[0] .= "." . str_repeat("0", $m);
|
||||
$inputValues[1] .= "." . str_repeat("9", $m);
|
||||
}
|
||||
}
|
||||
$typeFull = "$dataType($m)";
|
||||
echo "\nTesting $typeFull:\n";
|
||||
|
||||
//create table containing datetime2(m), datetimeoffset(m), or time(m) columns
|
||||
$tbname = "test_" . $dataType . $m;
|
||||
$colMetaArr = array(new ColumnMeta($typeFull, "c_det"), new ColumnMeta($typeFull, "c_rand", null, "randomized"));
|
||||
createTable($conn, $tbname, $colMetaArr);
|
||||
|
||||
// insert by specifying PDO::PARAM_ types
|
||||
foreach ($pdoParamTypes as $pdoParamType) {
|
||||
$r;
|
||||
$stmt = insertRow($conn, $tbname, array( "c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType), "c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType)), "prepareBindParam", $r);
|
||||
|
||||
// check the case when inserting as PDO::PARAM_NULL
|
||||
// with or without AE: NULL is inserted
|
||||
if ($pdoParamType == "PDO::PARAM_NULL") {
|
||||
if ($r === false) {
|
||||
echo "Conversion from $pdoParamType to $typeFull should be supported\n";
|
||||
} else {
|
||||
$sql = "SELECT c_det, c_rand FROM $tbname";
|
||||
$stmt = $conn->query($sql);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (!is_null($row['c_det']) || !is_null($row['c_rand'])) {
|
||||
echo "Conversion from $pdoParamType to $typeFull should insert NULL\n";
|
||||
}
|
||||
}
|
||||
// check the case when inserting as PDO::PARAM_BOOL, PDO::PARAM_INT, PDO::PARAM_STR or PDO::PARAM_LOB
|
||||
// with or without AE: should work
|
||||
} else {
|
||||
$sql = "SELECT c_det, c_rand FROM $tbname";
|
||||
$stmt = $conn->query($sql);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (compareDate($row['c_det'], $inputValues[0], $dataType) && compareDate($row['c_rand'], $inputValues[1], $dataType)) {
|
||||
echo "****Conversion from $pdoParamType to $typeFull is supported****\n";
|
||||
} else {
|
||||
echo "Conversion from $pdoParamType to $typeFull causes data corruption\n";
|
||||
}
|
||||
}
|
||||
$conn->query("TRUNCATE TABLE $tbname");
|
||||
}
|
||||
dropTable($conn, $tbname);
|
||||
}
|
||||
}
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
} catch (PDOException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
Testing datetime2(1):
|
||||
****Conversion from PDO::PARAM_BOOL to datetime2(1) is supported****
|
||||
****Conversion from PDO::PARAM_INT to datetime2(1) is supported****
|
||||
****Conversion from PDO::PARAM_STR to datetime2(1) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to datetime2(1) is supported****
|
||||
|
||||
Testing datetime2(2):
|
||||
****Conversion from PDO::PARAM_BOOL to datetime2(2) is supported****
|
||||
****Conversion from PDO::PARAM_INT to datetime2(2) is supported****
|
||||
****Conversion from PDO::PARAM_STR to datetime2(2) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to datetime2(2) is supported****
|
||||
|
||||
Testing datetime2(4):
|
||||
****Conversion from PDO::PARAM_BOOL to datetime2(4) is supported****
|
||||
****Conversion from PDO::PARAM_INT to datetime2(4) is supported****
|
||||
****Conversion from PDO::PARAM_STR to datetime2(4) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to datetime2(4) is supported****
|
||||
|
||||
Testing datetime2(7):
|
||||
****Conversion from PDO::PARAM_BOOL to datetime2(7) is supported****
|
||||
****Conversion from PDO::PARAM_INT to datetime2(7) is supported****
|
||||
****Conversion from PDO::PARAM_STR to datetime2(7) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to datetime2(7) is supported****
|
||||
|
||||
Testing datetimeoffset(1):
|
||||
****Conversion from PDO::PARAM_BOOL to datetimeoffset(1) is supported****
|
||||
****Conversion from PDO::PARAM_INT to datetimeoffset(1) is supported****
|
||||
****Conversion from PDO::PARAM_STR to datetimeoffset(1) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to datetimeoffset(1) is supported****
|
||||
|
||||
Testing datetimeoffset(2):
|
||||
****Conversion from PDO::PARAM_BOOL to datetimeoffset(2) is supported****
|
||||
****Conversion from PDO::PARAM_INT to datetimeoffset(2) is supported****
|
||||
****Conversion from PDO::PARAM_STR to datetimeoffset(2) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to datetimeoffset(2) is supported****
|
||||
|
||||
Testing datetimeoffset(4):
|
||||
****Conversion from PDO::PARAM_BOOL to datetimeoffset(4) is supported****
|
||||
****Conversion from PDO::PARAM_INT to datetimeoffset(4) is supported****
|
||||
****Conversion from PDO::PARAM_STR to datetimeoffset(4) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to datetimeoffset(4) is supported****
|
||||
|
||||
Testing datetimeoffset(7):
|
||||
****Conversion from PDO::PARAM_BOOL to datetimeoffset(7) is supported****
|
||||
****Conversion from PDO::PARAM_INT to datetimeoffset(7) is supported****
|
||||
****Conversion from PDO::PARAM_STR to datetimeoffset(7) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to datetimeoffset(7) is supported****
|
||||
|
||||
Testing time(1):
|
||||
****Conversion from PDO::PARAM_BOOL to time(1) is supported****
|
||||
****Conversion from PDO::PARAM_INT to time(1) is supported****
|
||||
****Conversion from PDO::PARAM_STR to time(1) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to time(1) is supported****
|
||||
|
||||
Testing time(2):
|
||||
****Conversion from PDO::PARAM_BOOL to time(2) is supported****
|
||||
****Conversion from PDO::PARAM_INT to time(2) is supported****
|
||||
****Conversion from PDO::PARAM_STR to time(2) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to time(2) is supported****
|
||||
|
||||
Testing time(4):
|
||||
****Conversion from PDO::PARAM_BOOL to time(4) is supported****
|
||||
****Conversion from PDO::PARAM_INT to time(4) is supported****
|
||||
****Conversion from PDO::PARAM_STR to time(4) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to time(4) is supported****
|
||||
|
||||
Testing time(7):
|
||||
****Conversion from PDO::PARAM_BOOL to time(7) is supported****
|
||||
****Conversion from PDO::PARAM_INT to time(7) is supported****
|
||||
****Conversion from PDO::PARAM_STR to time(7) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to time(7) is supported****
|
|
@ -0,0 +1,294 @@
|
|||
--TEST--
|
||||
Test for inserting encrypted data into decimal types columns
|
||||
--DESCRIPTION--
|
||||
Test conversions between different decimal types
|
||||
With Always Encrypted, implicit conversion works if:
|
||||
1. From input of PDO::PARAM_BOOL to a any decimal column
|
||||
2. From input of PDO::PARAM_INT to a any decimal column
|
||||
3. From input of PDO::PARAM_STR to a any decimal column
|
||||
4. From input of PDO::PARAM_LOB to a any decimal column
|
||||
Without Always Encrypted, all of the above should work except for:
|
||||
1. From input of PDO::PARAM_STR to a decimal column and the input has more than 14 digits to the left of the decimal
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
require_once("AEData.inc");
|
||||
|
||||
$dataTypes = array("decimal", "numeric");
|
||||
$precisions = array(1 => array(0, 1),
|
||||
4 => array(0, 1, 4),
|
||||
16 => array(0, 1, 4, 16),
|
||||
38 => array(0, 1, 4, 16, 38));
|
||||
$inputValuesInit = array(92233720368547758089223372036854775808, -92233720368547758089223372036854775808);
|
||||
$inputPrecision = 38;
|
||||
|
||||
try {
|
||||
$conn = connect("", array(), PDO::ERRMODE_SILENT);
|
||||
foreach ($dataTypes as $dataType) {
|
||||
foreach ($precisions as $m1 => $scales) {
|
||||
foreach ($scales as $m2) {
|
||||
// change the number of integers in the input values to be $m1 - $m2
|
||||
$precDiff = $inputPrecision - ($m1 - $m2);
|
||||
$inputValues = $inputValuesInit;
|
||||
foreach ($inputValues as &$inputValue) {
|
||||
$inputValue = $inputValue / pow(10, $precDiff);
|
||||
}
|
||||
|
||||
// compute the epsilon for comparing doubles
|
||||
// float in PHP only has a precision of roughtly 14 digits: http://php.net/manual/en/language.types.float.php
|
||||
$epsilon;
|
||||
if ($m1 < 14) {
|
||||
$epsilon = pow(10, $m2 * -1);
|
||||
} else {
|
||||
$numint = $m1 - $m2;
|
||||
if ($numint < 14) {
|
||||
$epsilon = pow(10, (14 - $numint) * -1);
|
||||
} else {
|
||||
$epsilon = pow(10, $numint - 14);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$typeFull = "$dataType($m1, $m2)";
|
||||
echo "\nTesting $typeFull:\n";
|
||||
|
||||
// create table containing decimal(m1, m2) or numeric(m1, m2) columns
|
||||
$tbname = "test_" . $dataType . $m1 . $m2;
|
||||
$colMetaArr = array(new ColumnMeta($typeFull, "c_det"), new ColumnMeta($typeFull, "c_rand", null, "randomized"));
|
||||
createTable($conn, $tbname, $colMetaArr);
|
||||
|
||||
// insert by specifying PDO::PARAM_ types
|
||||
foreach ($pdoParamTypes as $pdoParamType) {
|
||||
$r;
|
||||
$stmt = insertRow($conn, $tbname, array("c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType), "c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType)), "prepareBindParam", $r);
|
||||
|
||||
// check the case when inserting as PDO::PARAM_NULL
|
||||
// with or without AE: NULL is inserted
|
||||
if ($pdoParamType == "PDO::PARAM_NULL") {
|
||||
if ($r === false) {
|
||||
echo "Conversion from $pdoParamType to $typeFull should be supported\n";
|
||||
} else {
|
||||
$sql = "SELECT c_det, c_rand FROM $tbname";
|
||||
$stmt = $conn->query($sql);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (!is_null($row['c_det']) || !is_null($row['c_rand'])) {
|
||||
echo "NULL should have been inserted with $pdoParamType\n";
|
||||
}
|
||||
}
|
||||
// check the case when inserting as PDO::PARAM_STR and the input has more than 14 digits to the left of the decimal
|
||||
// with AE: should work
|
||||
// without AE: should not work
|
||||
// when the input has greater than 14 digits to the left of the decimal, the double is translated by PHP to scientific notation
|
||||
// inserting a scientific notation string fails
|
||||
} elseif ($pdoParamType == "PDO::PARAM_STR" && $m1 - $m2 > 14) {
|
||||
if (!isAEConnected()) {
|
||||
if ($r !== false) {
|
||||
echo "PDO param type $pdoParamType should not be compatible with $typeFull when the number of integers is greater than 14\n";
|
||||
}
|
||||
} else {
|
||||
if ($r === false) {
|
||||
echo "Conversion from $pdoParamType to $typeFull should be supported\n";
|
||||
}
|
||||
$sql = "SELECT c_det, c_rand FROM $tbname";
|
||||
$stmt = $conn->query($sql);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (abs($row['c_det'] - $inputValues[0]) > $epsilon ||
|
||||
abs($row['c_rand'] - $inputValues[1]) > $epsilon) {
|
||||
echo "Conversion from $pdoParamType to $typeFull causes data corruption\n";
|
||||
}
|
||||
}
|
||||
// check the case when inserting as PDO::PARAM_STR with input less than 14 digits to the left of the decimal
|
||||
// and PDO::PARAM_BOOL, PDO::PARAM_INT or PDO::PARAM_LOB
|
||||
// with or without AE: should work
|
||||
} else {
|
||||
if ($r === false) {
|
||||
echo "Conversion from $pdoParamType to $typeFull should be supported\n";
|
||||
}
|
||||
$sql = "SELECT c_det, c_rand FROM $tbname";
|
||||
$stmt = $conn->query($sql);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (abs($row['c_det'] - $inputValues[0]) > $epsilon ||
|
||||
abs($row['c_rand'] - $inputValues[1]) > $epsilon) {
|
||||
// TODO: this is a workaround for the test to pass!!!!!
|
||||
// with AE, doubles cannot be inserted into a decimal(38, 38) column
|
||||
// remove the following if block to see the bug
|
||||
// for more information see VSO task 2723
|
||||
if (isAEConnected() && $m1 == 38 && $m2 == 38) {
|
||||
echo "****Conversion from $pdoParamType to $typeFull is supported****\n";
|
||||
} else {
|
||||
echo "Conversion from $pdoParamType to $typeFull causes data corruption\n";
|
||||
}
|
||||
} else {
|
||||
echo "****Conversion from $pdoParamType to $typeFull is supported****\n";
|
||||
}
|
||||
}
|
||||
$conn->query("TRUNCATE TABLE $tbname");
|
||||
}
|
||||
dropTable($conn, $tbname);
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
} catch (PDOException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
Testing decimal(1, 0):
|
||||
****Conversion from PDO::PARAM_BOOL to decimal(1, 0) is supported****
|
||||
****Conversion from PDO::PARAM_INT to decimal(1, 0) is supported****
|
||||
****Conversion from PDO::PARAM_STR to decimal(1, 0) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to decimal(1, 0) is supported****
|
||||
|
||||
Testing decimal(1, 1):
|
||||
****Conversion from PDO::PARAM_BOOL to decimal(1, 1) is supported****
|
||||
****Conversion from PDO::PARAM_INT to decimal(1, 1) is supported****
|
||||
****Conversion from PDO::PARAM_STR to decimal(1, 1) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to decimal(1, 1) is supported****
|
||||
|
||||
Testing decimal(4, 0):
|
||||
****Conversion from PDO::PARAM_BOOL to decimal(4, 0) is supported****
|
||||
****Conversion from PDO::PARAM_INT to decimal(4, 0) is supported****
|
||||
****Conversion from PDO::PARAM_STR to decimal(4, 0) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to decimal(4, 0) is supported****
|
||||
|
||||
Testing decimal(4, 1):
|
||||
****Conversion from PDO::PARAM_BOOL to decimal(4, 1) is supported****
|
||||
****Conversion from PDO::PARAM_INT to decimal(4, 1) is supported****
|
||||
****Conversion from PDO::PARAM_STR to decimal(4, 1) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to decimal(4, 1) is supported****
|
||||
|
||||
Testing decimal(4, 4):
|
||||
****Conversion from PDO::PARAM_BOOL to decimal(4, 4) is supported****
|
||||
****Conversion from PDO::PARAM_INT to decimal(4, 4) is supported****
|
||||
****Conversion from PDO::PARAM_STR to decimal(4, 4) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to decimal(4, 4) is supported****
|
||||
|
||||
Testing decimal(16, 0):
|
||||
****Conversion from PDO::PARAM_BOOL to decimal(16, 0) is supported****
|
||||
****Conversion from PDO::PARAM_INT to decimal(16, 0) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to decimal(16, 0) is supported****
|
||||
|
||||
Testing decimal(16, 1):
|
||||
****Conversion from PDO::PARAM_BOOL to decimal(16, 1) is supported****
|
||||
****Conversion from PDO::PARAM_INT to decimal(16, 1) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to decimal(16, 1) is supported****
|
||||
|
||||
Testing decimal(16, 4):
|
||||
****Conversion from PDO::PARAM_BOOL to decimal(16, 4) is supported****
|
||||
****Conversion from PDO::PARAM_INT to decimal(16, 4) is supported****
|
||||
****Conversion from PDO::PARAM_STR to decimal(16, 4) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to decimal(16, 4) is supported****
|
||||
|
||||
Testing decimal(16, 16):
|
||||
****Conversion from PDO::PARAM_BOOL to decimal(16, 16) is supported****
|
||||
****Conversion from PDO::PARAM_INT to decimal(16, 16) is supported****
|
||||
****Conversion from PDO::PARAM_STR to decimal(16, 16) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to decimal(16, 16) is supported****
|
||||
|
||||
Testing decimal(38, 0):
|
||||
****Conversion from PDO::PARAM_BOOL to decimal(38, 0) is supported****
|
||||
****Conversion from PDO::PARAM_INT to decimal(38, 0) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to decimal(38, 0) is supported****
|
||||
|
||||
Testing decimal(38, 1):
|
||||
****Conversion from PDO::PARAM_BOOL to decimal(38, 1) is supported****
|
||||
****Conversion from PDO::PARAM_INT to decimal(38, 1) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to decimal(38, 1) is supported****
|
||||
|
||||
Testing decimal(38, 4):
|
||||
****Conversion from PDO::PARAM_BOOL to decimal(38, 4) is supported****
|
||||
****Conversion from PDO::PARAM_INT to decimal(38, 4) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to decimal(38, 4) is supported****
|
||||
|
||||
Testing decimal(38, 16):
|
||||
****Conversion from PDO::PARAM_BOOL to decimal(38, 16) is supported****
|
||||
****Conversion from PDO::PARAM_INT to decimal(38, 16) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to decimal(38, 16) is supported****
|
||||
|
||||
Testing decimal(38, 38):
|
||||
****Conversion from PDO::PARAM_BOOL to decimal(38, 38) is supported****
|
||||
****Conversion from PDO::PARAM_INT to decimal(38, 38) is supported****
|
||||
****Conversion from PDO::PARAM_STR to decimal(38, 38) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to decimal(38, 38) is supported****
|
||||
|
||||
Testing numeric(1, 0):
|
||||
****Conversion from PDO::PARAM_BOOL to numeric(1, 0) is supported****
|
||||
****Conversion from PDO::PARAM_INT to numeric(1, 0) is supported****
|
||||
****Conversion from PDO::PARAM_STR to numeric(1, 0) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to numeric(1, 0) is supported****
|
||||
|
||||
Testing numeric(1, 1):
|
||||
****Conversion from PDO::PARAM_BOOL to numeric(1, 1) is supported****
|
||||
****Conversion from PDO::PARAM_INT to numeric(1, 1) is supported****
|
||||
****Conversion from PDO::PARAM_STR to numeric(1, 1) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to numeric(1, 1) is supported****
|
||||
|
||||
Testing numeric(4, 0):
|
||||
****Conversion from PDO::PARAM_BOOL to numeric(4, 0) is supported****
|
||||
****Conversion from PDO::PARAM_INT to numeric(4, 0) is supported****
|
||||
****Conversion from PDO::PARAM_STR to numeric(4, 0) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to numeric(4, 0) is supported****
|
||||
|
||||
Testing numeric(4, 1):
|
||||
****Conversion from PDO::PARAM_BOOL to numeric(4, 1) is supported****
|
||||
****Conversion from PDO::PARAM_INT to numeric(4, 1) is supported****
|
||||
****Conversion from PDO::PARAM_STR to numeric(4, 1) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to numeric(4, 1) is supported****
|
||||
|
||||
Testing numeric(4, 4):
|
||||
****Conversion from PDO::PARAM_BOOL to numeric(4, 4) is supported****
|
||||
****Conversion from PDO::PARAM_INT to numeric(4, 4) is supported****
|
||||
****Conversion from PDO::PARAM_STR to numeric(4, 4) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to numeric(4, 4) is supported****
|
||||
|
||||
Testing numeric(16, 0):
|
||||
****Conversion from PDO::PARAM_BOOL to numeric(16, 0) is supported****
|
||||
****Conversion from PDO::PARAM_INT to numeric(16, 0) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to numeric(16, 0) is supported****
|
||||
|
||||
Testing numeric(16, 1):
|
||||
****Conversion from PDO::PARAM_BOOL to numeric(16, 1) is supported****
|
||||
****Conversion from PDO::PARAM_INT to numeric(16, 1) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to numeric(16, 1) is supported****
|
||||
|
||||
Testing numeric(16, 4):
|
||||
****Conversion from PDO::PARAM_BOOL to numeric(16, 4) is supported****
|
||||
****Conversion from PDO::PARAM_INT to numeric(16, 4) is supported****
|
||||
****Conversion from PDO::PARAM_STR to numeric(16, 4) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to numeric(16, 4) is supported****
|
||||
|
||||
Testing numeric(16, 16):
|
||||
****Conversion from PDO::PARAM_BOOL to numeric(16, 16) is supported****
|
||||
****Conversion from PDO::PARAM_INT to numeric(16, 16) is supported****
|
||||
****Conversion from PDO::PARAM_STR to numeric(16, 16) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to numeric(16, 16) is supported****
|
||||
|
||||
Testing numeric(38, 0):
|
||||
****Conversion from PDO::PARAM_BOOL to numeric(38, 0) is supported****
|
||||
****Conversion from PDO::PARAM_INT to numeric(38, 0) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to numeric(38, 0) is supported****
|
||||
|
||||
Testing numeric(38, 1):
|
||||
****Conversion from PDO::PARAM_BOOL to numeric(38, 1) is supported****
|
||||
****Conversion from PDO::PARAM_INT to numeric(38, 1) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to numeric(38, 1) is supported****
|
||||
|
||||
Testing numeric(38, 4):
|
||||
****Conversion from PDO::PARAM_BOOL to numeric(38, 4) is supported****
|
||||
****Conversion from PDO::PARAM_INT to numeric(38, 4) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to numeric(38, 4) is supported****
|
||||
|
||||
Testing numeric(38, 16):
|
||||
****Conversion from PDO::PARAM_BOOL to numeric(38, 16) is supported****
|
||||
****Conversion from PDO::PARAM_INT to numeric(38, 16) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to numeric(38, 16) is supported****
|
||||
|
||||
Testing numeric(38, 38):
|
||||
****Conversion from PDO::PARAM_BOOL to numeric(38, 38) is supported****
|
||||
****Conversion from PDO::PARAM_INT to numeric(38, 38) is supported****
|
||||
****Conversion from PDO::PARAM_STR to numeric(38, 38) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to numeric(38, 38) is supported****
|
|
@ -0,0 +1,113 @@
|
|||
--TEST--
|
||||
Test for inserting encrypted data into float types columns
|
||||
--DESCRIPTION--
|
||||
Test conversions between different float types
|
||||
With or without Always Encrypted, implicit conversion works if:
|
||||
1. From input of PDO::PARAM_BOOL to a float column
|
||||
2. From input of PDO::PARAM_INT to a float column
|
||||
3. From input of PDO::PARAM_STR to a float column
|
||||
4. From input of PDO::PARAM_LOB to a float column
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
require_once("AEData.inc");
|
||||
|
||||
$dataType = "float";
|
||||
$bits = array(1, 12, 24, 36, 53);
|
||||
$inputValues = array(9223372036854775808.9223372036854775808, -9223372036854775808.9223372036854775808);
|
||||
$numint = 19;
|
||||
|
||||
try {
|
||||
$conn = connect();
|
||||
foreach ($bits as $m) {
|
||||
// compute the epsilon for comparing doubles
|
||||
// when $m <= 24, the precision is 7 digits
|
||||
// when $m > 24, the precision is 15 digits, but PHP float only supports up to 14 digits
|
||||
$epsilon;
|
||||
if ($m <= 24) {
|
||||
$epsilon = pow(10, $numint - 7);
|
||||
} else {
|
||||
$epsilon = pow(10, $numint - 14);
|
||||
}
|
||||
|
||||
$typeFull = "$dataType($m)";
|
||||
echo "\nTesting $typeFull:\n";
|
||||
|
||||
//create table containing float(m) columns
|
||||
$tbname = "test_" . $dataType . $m;
|
||||
$colMetaArr = array(new ColumnMeta($typeFull, "c_det"), new ColumnMeta($typeFull, "c_rand", null, "randomized"));
|
||||
createTable($conn, $tbname, $colMetaArr);
|
||||
|
||||
// insert by specifying PDO::PARAM_ types
|
||||
foreach ($pdoParamTypes as $pdoParamType) {
|
||||
$r;
|
||||
$stmt = insertRow($conn, $tbname, array( "c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType), "c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType)), "prepareBindParam", $r);
|
||||
|
||||
// check the case when inserting as PDO::PARAM_NULL
|
||||
// with or without AE: NULL is inserted
|
||||
if ($pdoParamType == "PDO::PARAM_NULL") {
|
||||
if ($r === false) {
|
||||
echo "Conversion from $pdoParamType to $typeFull should be supported\n";
|
||||
} else {
|
||||
$sql = "SELECT c_det, c_rand FROM $tbname";
|
||||
$stmt = $conn->query($sql);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (!is_null($row['c_det']) || !is_null($row['c_rand'])) {
|
||||
echo "Conversion from $pdoParamType to $typeFull should insert NULL\n";
|
||||
}
|
||||
}
|
||||
// check the case when inserting as PDO::PARAM_BOOL, PDO::PARAM_INT, PDO::PARAM_STR or PDO::PARAM_LOB
|
||||
// with or without AE: should work
|
||||
} else {
|
||||
$sql = "SELECT c_det, c_rand FROM $tbname";
|
||||
$stmt = $conn->query($sql);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (abs($row['c_det'] - $inputValues[0]) < $epsilon && abs($row['c_rand'] - $inputValues[1]) < $epsilon) {
|
||||
echo "****Conversion from $pdoParamType to $typeFull is supported****\n";
|
||||
} else {
|
||||
echo "Conversion from $pdoParamType to $typeFull causes data corruption\n";
|
||||
}
|
||||
}
|
||||
// cleanup
|
||||
$conn->query("TRUNCATE TABLE $tbname");
|
||||
}
|
||||
dropTable($conn, $tbname);
|
||||
}
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
} catch (PDOException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
Testing float(1):
|
||||
****Conversion from PDO::PARAM_BOOL to float(1) is supported****
|
||||
****Conversion from PDO::PARAM_INT to float(1) is supported****
|
||||
****Conversion from PDO::PARAM_STR to float(1) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to float(1) is supported****
|
||||
|
||||
Testing float(12):
|
||||
****Conversion from PDO::PARAM_BOOL to float(12) is supported****
|
||||
****Conversion from PDO::PARAM_INT to float(12) is supported****
|
||||
****Conversion from PDO::PARAM_STR to float(12) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to float(12) is supported****
|
||||
|
||||
Testing float(24):
|
||||
****Conversion from PDO::PARAM_BOOL to float(24) is supported****
|
||||
****Conversion from PDO::PARAM_INT to float(24) is supported****
|
||||
****Conversion from PDO::PARAM_STR to float(24) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to float(24) is supported****
|
||||
|
||||
Testing float(36):
|
||||
****Conversion from PDO::PARAM_BOOL to float(36) is supported****
|
||||
****Conversion from PDO::PARAM_INT to float(36) is supported****
|
||||
****Conversion from PDO::PARAM_STR to float(36) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to float(36) is supported****
|
||||
|
||||
Testing float(53):
|
||||
****Conversion from PDO::PARAM_BOOL to float(53) is supported****
|
||||
****Conversion from PDO::PARAM_INT to float(53) is supported****
|
||||
****Conversion from PDO::PARAM_STR to float(53) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to float(53) is supported****
|
|
@ -0,0 +1,172 @@
|
|||
--TEST--
|
||||
Test for inserting encrypted data into nchar types columns with different sizes
|
||||
--DESCRIPTION--
|
||||
Test conversions between different nchar types of different sizes
|
||||
With or without Always Encrypted, implicit conversion works if:
|
||||
1. From input of PDO::PARAM_BOOL to any nchar column
|
||||
2. From input of PDO::PARAM_INT to any nchar column
|
||||
3. From input of PDO::PARAM_STR to any nchar column
|
||||
4. From input of PDO::PARAM_LOB to any nchar column
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
require_once("AEData.inc");
|
||||
|
||||
$dataTypes = array("nchar", "nvarchar", "nvarchar(max)");
|
||||
$lengths = array(1, 8, 64, 512, 4000);
|
||||
|
||||
try {
|
||||
$conn = connect();
|
||||
foreach ($dataTypes as $dataType) {
|
||||
$maxcol = strpos($dataType, "(max)");
|
||||
foreach ($lengths as $m) {
|
||||
if ($maxcol !== false) {
|
||||
$typeFull = $dataType;
|
||||
} else {
|
||||
$typeFull = "$dataType($m)";
|
||||
}
|
||||
echo "\nTesting $typeFull:\n";
|
||||
|
||||
// create table containing nchar(m) or nvarchar(m) columns
|
||||
// only one column is created because a row has a limitation of 8060 bytes
|
||||
// for lengths 4096 and 8000, cannot create 2 columns as it will exceed the maximum row sizes
|
||||
// for AE, only testing deterministic here, randomized is tested in the char test
|
||||
$tbname = "test_" . str_replace(array('(', ')'), '', $dataType) . $m;
|
||||
$colMetaArr = array(new ColumnMeta($typeFull, "c1"));
|
||||
createTable($conn, $tbname, $colMetaArr);
|
||||
$input = str_repeat("d", $m);
|
||||
|
||||
// insert by specifying PDO::PARAM_ types
|
||||
foreach ($pdoParamTypes as $pdoParamType) {
|
||||
$r;
|
||||
$stmt = insertRow($conn, $tbname, array( "c1" => new BindParamOp(1, $input, $pdoParamType)), "prepareBindParam", $r);
|
||||
|
||||
// check the case when inserting as PDO::PARAM_NULL
|
||||
// with or without AE: NULL is inserted
|
||||
if ($pdoParamType == "PDO::PARAM_NULL") {
|
||||
if ($r === false) {
|
||||
echo "Conversion from $pdoParamType to $typeFull should be supported\n";
|
||||
} else {
|
||||
$sql = "SELECT c1 FROM $tbname";
|
||||
$stmt = $conn->query($sql);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (!is_null($row['c1'])) {
|
||||
echo "Conversion from $pdoParamType to $typeFull should insert NULL\n";
|
||||
}
|
||||
}
|
||||
// check the case when inserting as PDO::PARAM_BOOL, PDO::PARAM_INT, PDO::PARAM_STR or PDO{{PARAM_LOB
|
||||
// with or without AE: should work
|
||||
} else {
|
||||
$sql = "SELECT c1 FROM $tbname";
|
||||
$stmt = $conn->query($sql);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (strlen($row['c1']) == $m) {
|
||||
echo "****Conversion from $pdoParamType to $typeFull is supported****\n";
|
||||
} else {
|
||||
echo "Conversion from $pdoParamType to $typeFull causes data corruption\n";
|
||||
}
|
||||
}
|
||||
// cleanup
|
||||
$conn->query("TRUNCATE TABLE $tbname");
|
||||
}
|
||||
dropTable($conn, $tbname);
|
||||
}
|
||||
}
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
} catch (PDOException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
Testing nchar(1):
|
||||
****Conversion from PDO::PARAM_BOOL to nchar(1) is supported****
|
||||
****Conversion from PDO::PARAM_INT to nchar(1) is supported****
|
||||
****Conversion from PDO::PARAM_STR to nchar(1) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to nchar(1) is supported****
|
||||
|
||||
Testing nchar(8):
|
||||
****Conversion from PDO::PARAM_BOOL to nchar(8) is supported****
|
||||
****Conversion from PDO::PARAM_INT to nchar(8) is supported****
|
||||
****Conversion from PDO::PARAM_STR to nchar(8) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to nchar(8) is supported****
|
||||
|
||||
Testing nchar(64):
|
||||
****Conversion from PDO::PARAM_BOOL to nchar(64) is supported****
|
||||
****Conversion from PDO::PARAM_INT to nchar(64) is supported****
|
||||
****Conversion from PDO::PARAM_STR to nchar(64) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to nchar(64) is supported****
|
||||
|
||||
Testing nchar(512):
|
||||
****Conversion from PDO::PARAM_BOOL to nchar(512) is supported****
|
||||
****Conversion from PDO::PARAM_INT to nchar(512) is supported****
|
||||
****Conversion from PDO::PARAM_STR to nchar(512) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to nchar(512) is supported****
|
||||
|
||||
Testing nchar(4000):
|
||||
****Conversion from PDO::PARAM_BOOL to nchar(4000) is supported****
|
||||
****Conversion from PDO::PARAM_INT to nchar(4000) is supported****
|
||||
****Conversion from PDO::PARAM_STR to nchar(4000) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to nchar(4000) is supported****
|
||||
|
||||
Testing nvarchar(1):
|
||||
****Conversion from PDO::PARAM_BOOL to nvarchar(1) is supported****
|
||||
****Conversion from PDO::PARAM_INT to nvarchar(1) is supported****
|
||||
****Conversion from PDO::PARAM_STR to nvarchar(1) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to nvarchar(1) is supported****
|
||||
|
||||
Testing nvarchar(8):
|
||||
****Conversion from PDO::PARAM_BOOL to nvarchar(8) is supported****
|
||||
****Conversion from PDO::PARAM_INT to nvarchar(8) is supported****
|
||||
****Conversion from PDO::PARAM_STR to nvarchar(8) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to nvarchar(8) is supported****
|
||||
|
||||
Testing nvarchar(64):
|
||||
****Conversion from PDO::PARAM_BOOL to nvarchar(64) is supported****
|
||||
****Conversion from PDO::PARAM_INT to nvarchar(64) is supported****
|
||||
****Conversion from PDO::PARAM_STR to nvarchar(64) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to nvarchar(64) is supported****
|
||||
|
||||
Testing nvarchar(512):
|
||||
****Conversion from PDO::PARAM_BOOL to nvarchar(512) is supported****
|
||||
****Conversion from PDO::PARAM_INT to nvarchar(512) is supported****
|
||||
****Conversion from PDO::PARAM_STR to nvarchar(512) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to nvarchar(512) is supported****
|
||||
|
||||
Testing nvarchar(4000):
|
||||
****Conversion from PDO::PARAM_BOOL to nvarchar(4000) is supported****
|
||||
****Conversion from PDO::PARAM_INT to nvarchar(4000) is supported****
|
||||
****Conversion from PDO::PARAM_STR to nvarchar(4000) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to nvarchar(4000) is supported****
|
||||
|
||||
Testing nvarchar(max):
|
||||
****Conversion from PDO::PARAM_BOOL to nvarchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_INT to nvarchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_STR to nvarchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to nvarchar(max) is supported****
|
||||
|
||||
Testing nvarchar(max):
|
||||
****Conversion from PDO::PARAM_BOOL to nvarchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_INT to nvarchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_STR to nvarchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to nvarchar(max) is supported****
|
||||
|
||||
Testing nvarchar(max):
|
||||
****Conversion from PDO::PARAM_BOOL to nvarchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_INT to nvarchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_STR to nvarchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to nvarchar(max) is supported****
|
||||
|
||||
Testing nvarchar(max):
|
||||
****Conversion from PDO::PARAM_BOOL to nvarchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_INT to nvarchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_STR to nvarchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to nvarchar(max) is supported****
|
||||
|
||||
Testing nvarchar(max):
|
||||
****Conversion from PDO::PARAM_BOOL to nvarchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_INT to nvarchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_STR to nvarchar(max) is supported****
|
||||
****Conversion from PDO::PARAM_LOB to nvarchar(max) is supported****
|
|
@ -1,39 +1,123 @@
|
|||
--TEST--
|
||||
Test for inserting and retrieving encrypted data of numeric types
|
||||
Test for inserting encrypted data into numeric types columns
|
||||
--DESCRIPTION--
|
||||
Use PDOstatement::bindParam with all PDO::PARAM_ types
|
||||
Test conversions between different numeric types
|
||||
With Always Encrypted, implicit conversion works if:
|
||||
1. From input of PDO::PARAM_BOOL to a real column
|
||||
2. From input of PDO::PARAM_INT to any numeric column
|
||||
3. From input of PDO::PARAM_STR to any numeric column
|
||||
4. From input of PDO::PARAM_LOB to any numeric column
|
||||
Without Always Encrypted, all of the above work except for input of PDO::PARAM_STR to a bigint column in a x86 platform
|
||||
PDO::PARAM_STR does not work for bigint in a x86 platform because the maximum value of an int is about 2147483647
|
||||
Whereas in a x64 platform, the maximum value is about 9E18
|
||||
In a x86 platform, when an integer is > 2147483647, PHP implicitly changees it to a float, represented by scientific notation
|
||||
When inserting a scientific notation form numeric string, SQL Server returns a converting data type nvarchar to bigint error
|
||||
Works for with AE because the sqltype used for binding parameter is determined by SQLDescribeParam,
|
||||
unlike without AE, the sqltype is predicted to be nvarchar or varchar when the input is a string
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
require_once("AEData.inc");
|
||||
$dataTypes = array( "bit", "tinyint", "smallint", "int", "decimal(18,5)", "numeric(10,5)", "float", "real" );
|
||||
|
||||
$dataTypes = array("bit", "tinyint", "smallint", "int", "bigint", "real");
|
||||
$epsilon = 1;
|
||||
|
||||
try {
|
||||
$conn = connect();
|
||||
$conn = connect("", array(), PDO::ERRMODE_SILENT);
|
||||
foreach ($dataTypes as $dataType) {
|
||||
echo "\nTesting $dataType:\n";
|
||||
|
||||
// create table
|
||||
$tbname = getTableName();
|
||||
// create table containing bit, tinyint, smallint, int, bigint, or real columns
|
||||
$tbname = "test_" . $dataType;
|
||||
$colMetaArr = array(new ColumnMeta($dataType, "c_det"), new ColumnMeta($dataType, "c_rand", null, "randomized"));
|
||||
createTable($conn, $tbname, $colMetaArr);
|
||||
|
||||
// test each PDO::PARAM_ type
|
||||
// insert by specifying PDO::PARAM_ types
|
||||
foreach ($pdoParamTypes as $pdoParamType) {
|
||||
// insert a row
|
||||
$inputValues = array_slice(${explode("(", $dataType)[0] . "_params"}, 1, 2);
|
||||
$r;
|
||||
if ($dataType == "decimal(18,5)") {
|
||||
$stmt = insertRow($conn, $tbname, array( "c_det" => new BindParamOp(1, (string)$inputValues[0], $pdoParamType), "c_rand" => new BindParamOp(2, (string)$inputValues[1], $pdoParamType)), "prepareBindParam", $r);
|
||||
$stmt = insertRow($conn, $tbname, array( "c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType), "c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType)), "prepareBindParam", $r);
|
||||
|
||||
// check the case when inserting as PDO::PARAM_NULL
|
||||
// with or without AE: NULL is inserted
|
||||
if ($pdoParamType == "PDO::PARAM_NULL") {
|
||||
if ($r === false) {
|
||||
echo "Conversion from $pdoParamType to $dataType should be supported\n";
|
||||
} else {
|
||||
$sql = "SELECT c_det, c_rand FROM $tbname";
|
||||
$stmt = $conn->query($sql);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (!is_null($row['c_det']) || !is_null($row['c_rand'])) {
|
||||
echo "Conversion from $pdoParamType to $dataType should insert NULL\n";
|
||||
}
|
||||
}
|
||||
// check the case when inserting as PDO::PARAM_BOOL
|
||||
// with or without AE: 1 or 0 should be inserted when inserting into an integer column
|
||||
// double is inserted when inserting into a real column
|
||||
} else if ($pdoParamType == "PDO::PARAM_BOOL") {
|
||||
if ($r === false) {
|
||||
echo "Conversion from $pdoParamType to $dataType should be supported\n";
|
||||
} else {
|
||||
$sql = "SELECT c_det, c_rand FROM $tbname";
|
||||
$stmt = $conn->query($sql);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if ($dataType == "real") {
|
||||
if (abs($row['c_det'] - $inputValues[0]) < $epsilon && abs($row['c_rand'] - $inputValues[1]) < $epsilon) {
|
||||
echo "****Conversion from $pdoParamType to $dataType is supported****\n";
|
||||
} else {
|
||||
echo "Conversion from $pdoParamType to $dataType causes data corruption\n";
|
||||
}
|
||||
} else {
|
||||
if ($row['c_det'] != ($inputValues[0] != 0) && $row['c_rand'] != ($inputValues[1] != 0)) {
|
||||
echo "Conversion from $pdoParamType to $dataType insert a boolean\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
// check the case when inserting as PDO::PARAM_STR into a bigint column
|
||||
// with AE: should work
|
||||
// without AE: should not work on a x86 platform
|
||||
} else if ($dataType == "bigint" && $pdoParamType == "PDO::PARAM_STR") {
|
||||
if (!isAEConnected() && PHP_INT_SIZE == 4) {
|
||||
if ($r !== false) {
|
||||
echo "Conversion from $pdoParamType to $dataType should not be supported\n";
|
||||
}
|
||||
} else {
|
||||
if ($r === false) {
|
||||
echo "Conversion from $pdoParamType to $dataType should be supported\n";
|
||||
} else {
|
||||
$sql = "SELECT c_det, c_rand FROM $tbname";
|
||||
$stmt = $conn->query($sql);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if ($row['c_det'] != $inputValues[0] && $row['c_rand'] != $inputValues[1]) {
|
||||
echo "Conversion from $pdoParamType to $dataType causes data corruption\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
// check the case when inserting as PDO::PARAM_INT, PDO::PARAM_STR or PDO::PARAM_LOB
|
||||
// with or without AE: should work
|
||||
} else {
|
||||
$stmt = insertRow($conn, $tbname, array( "c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType), "c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType)), "prepareBindParam", $r);
|
||||
}
|
||||
if ($r === false) {
|
||||
isIncompatibleTypesError($stmt, $dataType, $pdoParamType);
|
||||
} else {
|
||||
echo "****PDO param type $pdoParamType is compatible with encrypted $dataType****\n";
|
||||
fetchAll($conn, $tbname);
|
||||
if ($r === false) {
|
||||
echo "Conversion from $pdoParamType to $dataType should be supported\n";
|
||||
} else {
|
||||
$sql = "SELECT c_det, c_rand FROM $tbname";
|
||||
$stmt = $conn->query($sql);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if ($dataType == "real") {
|
||||
if (abs($row['c_det'] - $inputValues[0]) < $epsilon && abs($row['c_rand'] - $inputValues[1]) < $epsilon) {
|
||||
echo "****Conversion from $pdoParamType to $dataType is supported****\n";
|
||||
} else {
|
||||
echo "Conversion from $pdoParamType to $dataType causes data corruption\n";
|
||||
}
|
||||
} else {
|
||||
if ($row['c_det'] == $inputValues[0] && $row['c_rand'] == $inputValues[1]) {
|
||||
echo "****Conversion from $pdoParamType to $dataType is supported****\n";
|
||||
} else {
|
||||
echo "Conversion from $pdoParamType to $dataType causes data corruption\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$conn->query("TRUNCATE TABLE $tbname");
|
||||
}
|
||||
|
@ -46,139 +130,32 @@ try {
|
|||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
|
||||
Testing bit:
|
||||
****PDO param type PDO::PARAM_BOOL is compatible with encrypted bit****
|
||||
c_det: 1
|
||||
c_rand: 0
|
||||
****PDO param type PDO::PARAM_NULL is compatible with encrypted bit****
|
||||
c_det:
|
||||
c_rand:
|
||||
****PDO param type PDO::PARAM_INT is compatible with encrypted bit****
|
||||
c_det: 1
|
||||
c_rand: 0
|
||||
****PDO param type PDO::PARAM_STR is compatible with encrypted bit****
|
||||
c_det: 1
|
||||
c_rand: 0
|
||||
****PDO param type PDO::PARAM_LOB is compatible with encrypted bit****
|
||||
c_det: 1
|
||||
c_rand: 0
|
||||
****Conversion from PDO::PARAM_INT to bit is supported****
|
||||
****Conversion from PDO::PARAM_STR to bit is supported****
|
||||
****Conversion from PDO::PARAM_LOB to bit is supported****
|
||||
|
||||
Testing tinyint:
|
||||
****PDO param type PDO::PARAM_BOOL is compatible with encrypted tinyint****
|
||||
c_det: 0
|
||||
c_rand: 1
|
||||
****PDO param type PDO::PARAM_NULL is compatible with encrypted tinyint****
|
||||
c_det:
|
||||
c_rand:
|
||||
****PDO param type PDO::PARAM_INT is compatible with encrypted tinyint****
|
||||
c_det: 0
|
||||
c_rand: 255
|
||||
****PDO param type PDO::PARAM_STR is compatible with encrypted tinyint****
|
||||
c_det: 0
|
||||
c_rand: 255
|
||||
****PDO param type PDO::PARAM_LOB is compatible with encrypted tinyint****
|
||||
c_det: 0
|
||||
c_rand: 255
|
||||
****Conversion from PDO::PARAM_INT to tinyint is supported****
|
||||
****Conversion from PDO::PARAM_STR to tinyint is supported****
|
||||
****Conversion from PDO::PARAM_LOB to tinyint is supported****
|
||||
|
||||
Testing smallint:
|
||||
****PDO param type PDO::PARAM_BOOL is compatible with encrypted smallint****
|
||||
c_det: 1
|
||||
c_rand: 1
|
||||
****PDO param type PDO::PARAM_NULL is compatible with encrypted smallint****
|
||||
c_det:
|
||||
c_rand:
|
||||
****PDO param type PDO::PARAM_INT is compatible with encrypted smallint****
|
||||
c_det: -32767
|
||||
c_rand: 32767
|
||||
****PDO param type PDO::PARAM_STR is compatible with encrypted smallint****
|
||||
c_det: -32767
|
||||
c_rand: 32767
|
||||
****PDO param type PDO::PARAM_LOB is compatible with encrypted smallint****
|
||||
c_det: -32767
|
||||
c_rand: 32767
|
||||
****Conversion from PDO::PARAM_INT to smallint is supported****
|
||||
****Conversion from PDO::PARAM_STR to smallint is supported****
|
||||
****Conversion from PDO::PARAM_LOB to smallint is supported****
|
||||
|
||||
Testing int:
|
||||
****PDO param type PDO::PARAM_BOOL is compatible with encrypted int****
|
||||
c_det: 1
|
||||
c_rand: 1
|
||||
****PDO param type PDO::PARAM_NULL is compatible with encrypted int****
|
||||
c_det:
|
||||
c_rand:
|
||||
****PDO param type PDO::PARAM_INT is compatible with encrypted int****
|
||||
c_det: -2147483647
|
||||
c_rand: 2147483647
|
||||
****PDO param type PDO::PARAM_STR is compatible with encrypted int****
|
||||
c_det: -2147483647
|
||||
c_rand: 2147483647
|
||||
****PDO param type PDO::PARAM_LOB is compatible with encrypted int****
|
||||
c_det: -2147483647
|
||||
c_rand: 2147483647
|
||||
****Conversion from PDO::PARAM_INT to int is supported****
|
||||
****Conversion from PDO::PARAM_STR to int is supported****
|
||||
****Conversion from PDO::PARAM_LOB to int is supported****
|
||||
|
||||
Testing decimal(18,5):
|
||||
****PDO param type PDO::PARAM_BOOL is compatible with encrypted decimal(18,5)****
|
||||
c_det: -9223372036854.80000
|
||||
c_rand: 9223372036854.80000
|
||||
****PDO param type PDO::PARAM_NULL is compatible with encrypted decimal(18,5)****
|
||||
c_det:
|
||||
c_rand:
|
||||
****PDO param type PDO::PARAM_INT is compatible with encrypted decimal(18,5)****
|
||||
c_det: -9223372036854.80000
|
||||
c_rand: 9223372036854.80000
|
||||
****PDO param type PDO::PARAM_STR is compatible with encrypted decimal(18,5)****
|
||||
c_det: -9223372036854.80000
|
||||
c_rand: 9223372036854.80000
|
||||
****PDO param type PDO::PARAM_LOB is compatible with encrypted decimal(18,5)****
|
||||
c_det: -9223372036854.80000
|
||||
c_rand: 9223372036854.80000
|
||||
|
||||
Testing numeric(10,5):
|
||||
****PDO param type PDO::PARAM_BOOL is compatible with encrypted numeric(10,5)****
|
||||
c_det: -21474.83647
|
||||
c_rand: 21474.83647
|
||||
****PDO param type PDO::PARAM_NULL is compatible with encrypted numeric(10,5)****
|
||||
c_det:
|
||||
c_rand:
|
||||
****PDO param type PDO::PARAM_INT is compatible with encrypted numeric(10,5)****
|
||||
c_det: -21474.83647
|
||||
c_rand: 21474.83647
|
||||
****PDO param type PDO::PARAM_STR is compatible with encrypted numeric(10,5)****
|
||||
c_det: -21474.83647
|
||||
c_rand: 21474.83647
|
||||
****PDO param type PDO::PARAM_LOB is compatible with encrypted numeric(10,5)****
|
||||
c_det: -21474.83647
|
||||
c_rand: 21474.83647
|
||||
|
||||
Testing float:
|
||||
****PDO param type PDO::PARAM_BOOL is compatible with encrypted float****
|
||||
c_det: -9223372036.8547993
|
||||
c_rand: 9223372036.8547993
|
||||
****PDO param type PDO::PARAM_NULL is compatible with encrypted float****
|
||||
c_det:
|
||||
c_rand:
|
||||
****PDO param type PDO::PARAM_INT is compatible with encrypted float****
|
||||
c_det: -9223372036.8547993
|
||||
c_rand: 9223372036.8547993
|
||||
****PDO param type PDO::PARAM_STR is compatible with encrypted float****
|
||||
c_det: -9223372036.8547993
|
||||
c_rand: 9223372036.8547993
|
||||
****PDO param type PDO::PARAM_LOB is compatible with encrypted float****
|
||||
c_det: -9223372036.8547993
|
||||
c_rand: 9223372036.8547993
|
||||
Testing bigint:
|
||||
****Conversion from PDO::PARAM_INT to bigint is supported****
|
||||
****Conversion from PDO::PARAM_LOB to bigint is supported****
|
||||
|
||||
Testing real:
|
||||
****PDO param type PDO::PARAM_BOOL is compatible with encrypted real****
|
||||
c_det: -2147.4829
|
||||
c_rand: 2147.4829
|
||||
****PDO param type PDO::PARAM_NULL is compatible with encrypted real****
|
||||
c_det:
|
||||
c_rand:
|
||||
****PDO param type PDO::PARAM_INT is compatible with encrypted real****
|
||||
c_det: -2147.4829
|
||||
c_rand: 2147.4829
|
||||
****PDO param type PDO::PARAM_STR is compatible with encrypted real****
|
||||
c_det: -2147.4829
|
||||
c_rand: 2147.4829
|
||||
****PDO param type PDO::PARAM_LOB is compatible with encrypted real****
|
||||
c_det: -2147.4829
|
||||
c_rand: 2147.4829
|
||||
****Conversion from PDO::PARAM_BOOL to real is supported****
|
||||
****Conversion from PDO::PARAM_INT to real is supported****
|
||||
****Conversion from PDO::PARAM_STR to real is supported****
|
||||
****Conversion from PDO::PARAM_LOB to real is supported****
|
|
@ -1,112 +0,0 @@
|
|||
--TEST--
|
||||
Test for inserting and retrieving encrypted data of string types
|
||||
--DESCRIPTION--
|
||||
Use PDOstatement::bindParam with all PDO::PARAM_ types
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
require_once("AEData.inc");
|
||||
$dataTypes = array("char(5)", "varchar(max)", "nchar(5)", "nvarchar(max)");
|
||||
try {
|
||||
$conn = connect('', array(), PDO::ERRMODE_SILENT);
|
||||
foreach ($dataTypes as $dataType) {
|
||||
echo "\nTesting $dataType:\n";
|
||||
|
||||
// create table
|
||||
$tbname = getTableName();
|
||||
$colMetaArr = array(new ColumnMeta($dataType, "c_det"), new ColumnMeta($dataType, "c_rand", null, "randomized"));
|
||||
createTable($conn, $tbname, $colMetaArr);
|
||||
|
||||
// prepare statement for inserting into table
|
||||
foreach ($pdoParamTypes as $pdoParamType) {
|
||||
// insert a row
|
||||
$inputValues = array_slice(${explode("(", $dataType)[0] . "_params"}, 1, 2);
|
||||
$r;
|
||||
$stmt = insertRow($conn, $tbname, array( "c_det" => new BindParamOp(1, $inputValues[0], $pdoParamType),"c_rand" => new BindParamOp(2, $inputValues[1], $pdoParamType)), "prepareBindParam", $r);
|
||||
if ($r === false) {
|
||||
isIncompatibleTypesError($stmt, $dataType, $pdoParamType);
|
||||
} else {
|
||||
echo "****PDO param type $pdoParamType is compatible with encrypted $dataType****\n";
|
||||
fetchAll($conn, $tbname);
|
||||
}
|
||||
$conn->query("TRUNCATE TABLE $tbname");
|
||||
}
|
||||
dropTable($conn, $tbname);
|
||||
}
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
} catch (PDOException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
|
||||
Testing char(5):
|
||||
****PDO param type PDO::PARAM_BOOL is compatible with encrypted char(5)****
|
||||
c_det: -leng
|
||||
c_rand: th, n
|
||||
****PDO param type PDO::PARAM_NULL is compatible with encrypted char(5)****
|
||||
c_det:
|
||||
c_rand:
|
||||
****PDO param type PDO::PARAM_INT is compatible with encrypted char(5)****
|
||||
c_det: -leng
|
||||
c_rand: th, n
|
||||
****PDO param type PDO::PARAM_STR is compatible with encrypted char(5)****
|
||||
c_det: -leng
|
||||
c_rand: th, n
|
||||
****PDO param type PDO::PARAM_LOB is compatible with encrypted char(5)****
|
||||
c_det: -leng
|
||||
c_rand: th, n
|
||||
|
||||
Testing varchar(max):
|
||||
****PDO param type PDO::PARAM_BOOL is compatible with encrypted varchar(max)****
|
||||
c_det: Use varchar(max) when the sizes of the column data entries vary considerably, and the size might exceed 8,000 bytes.
|
||||
c_rand: Each non-null varchar(max) or nvarchar(max) column requires 24 bytes of additional fixed allocation which counts against the 8,060 byte row limit during a sort operation.
|
||||
****PDO param type PDO::PARAM_NULL is compatible with encrypted varchar(max)****
|
||||
c_det:
|
||||
c_rand:
|
||||
****PDO param type PDO::PARAM_INT is compatible with encrypted varchar(max)****
|
||||
c_det: Use varchar(max) when the sizes of the column data entries vary considerably, and the size might exceed 8,000 bytes.
|
||||
c_rand: Each non-null varchar(max) or nvarchar(max) column requires 24 bytes of additional fixed allocation which counts against the 8,060 byte row limit during a sort operation.
|
||||
****PDO param type PDO::PARAM_STR is compatible with encrypted varchar(max)****
|
||||
c_det: Use varchar(max) when the sizes of the column data entries vary considerably, and the size might exceed 8,000 bytes.
|
||||
c_rand: Each non-null varchar(max) or nvarchar(max) column requires 24 bytes of additional fixed allocation which counts against the 8,060 byte row limit during a sort operation.
|
||||
****PDO param type PDO::PARAM_LOB is compatible with encrypted varchar(max)****
|
||||
c_det: Use varchar(max) when the sizes of the column data entries vary considerably, and the size might exceed 8,000 bytes.
|
||||
c_rand: Each non-null varchar(max) or nvarchar(max) column requires 24 bytes of additional fixed allocation which counts against the 8,060 byte row limit during a sort operation.
|
||||
|
||||
Testing nchar(5):
|
||||
****PDO param type PDO::PARAM_BOOL is compatible with encrypted nchar(5)****
|
||||
c_det: -leng
|
||||
c_rand: th Un
|
||||
****PDO param type PDO::PARAM_NULL is compatible with encrypted nchar(5)****
|
||||
c_det:
|
||||
c_rand:
|
||||
****PDO param type PDO::PARAM_INT is compatible with encrypted nchar(5)****
|
||||
c_det: -leng
|
||||
c_rand: th Un
|
||||
****PDO param type PDO::PARAM_STR is compatible with encrypted nchar(5)****
|
||||
c_det: -leng
|
||||
c_rand: th Un
|
||||
****PDO param type PDO::PARAM_LOB is compatible with encrypted nchar(5)****
|
||||
c_det: -leng
|
||||
c_rand: th Un
|
||||
|
||||
Testing nvarchar(max):
|
||||
****PDO param type PDO::PARAM_BOOL is compatible with encrypted nvarchar(max)****
|
||||
c_det: When prefixing a string constant with the letter N, the implicit conversion will result in a Unicode string if the constant to convert does not exceed the max length for a Unicode string data type (4,000).
|
||||
c_rand: Otherwise, the implicit conversion will result in a Unicode large-value (max).
|
||||
****PDO param type PDO::PARAM_NULL is compatible with encrypted nvarchar(max)****
|
||||
c_det:
|
||||
c_rand:
|
||||
****PDO param type PDO::PARAM_INT is compatible with encrypted nvarchar(max)****
|
||||
c_det: When prefixing a string constant with the letter N, the implicit conversion will result in a Unicode string if the constant to convert does not exceed the max length for a Unicode string data type (4,000).
|
||||
c_rand: Otherwise, the implicit conversion will result in a Unicode large-value (max).
|
||||
****PDO param type PDO::PARAM_STR is compatible with encrypted nvarchar(max)****
|
||||
c_det: When prefixing a string constant with the letter N, the implicit conversion will result in a Unicode string if the constant to convert does not exceed the max length for a Unicode string data type (4,000).
|
||||
c_rand: Otherwise, the implicit conversion will result in a Unicode large-value (max).
|
||||
****PDO param type PDO::PARAM_LOB is compatible with encrypted nvarchar(max)****
|
||||
c_det: When prefixing a string constant with the letter N, the implicit conversion will result in a Unicode string if the constant to convert does not exceed the max length for a Unicode string data type (4,000).
|
||||
c_rand: Otherwise, the implicit conversion will result in a Unicode large-value (max).
|
|
@ -0,0 +1,210 @@
|
|||
--TEST--
|
||||
Test for retrieving encrypted data of binary types of various sizes as output parameters
|
||||
--DESCRIPTION--
|
||||
Use PDOstatement::bindParam with all PDO::PARAM_ types
|
||||
--ENV--
|
||||
PHPT_EXEC=true
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
|
||||
$dataTypes = array("binary", "varbinary", "varbinary(max)");
|
||||
$lengths = array(1, 2, 4, 8, 64, 512, 4000);
|
||||
$errors = array("IMSSP" => "An invalid PHP type was specified as an output parameter. DateTime objects, NULL values, and streams cannot be specified as output parameters.", "07006" => "Restricted data type attribute violation");
|
||||
|
||||
$pdoParamTypes = array(
|
||||
PDO::PARAM_BOOL, // 5
|
||||
PDO::PARAM_NULL, // 0
|
||||
PDO::PARAM_INT, // 1
|
||||
PDO::PARAM_STR, // 2
|
||||
PDO::PARAM_LOB // 3
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
function printValues($msg, $det, $rand, $input0, $input1)
|
||||
{
|
||||
echo $msg;
|
||||
echo "input 0: "; var_dump($input0);
|
||||
echo "fetched: "; var_dump($det);
|
||||
echo "input 1: "; var_dump($input1);
|
||||
echo "fetched: "; var_dump($rand);
|
||||
}
|
||||
|
||||
function convert2Hex($ch, $length)
|
||||
{
|
||||
// Without AE, the binary values returned as integers will
|
||||
// have lengths no more than 4 times the original hex string value
|
||||
// (e.g. string(8) "65656565") - limited by the buffer sizes
|
||||
if (!isAEConnected()) {
|
||||
$count = ($length <= 2) ? $length : 4;
|
||||
} else {
|
||||
$count = $length;
|
||||
}
|
||||
|
||||
return str_repeat(bin2hex($ch), $count);
|
||||
}
|
||||
|
||||
function testOutputBinary($inout)
|
||||
{
|
||||
global $pdoParamTypes, $dataTypes, $lengths, $errors;
|
||||
|
||||
try {
|
||||
$conn = connect();
|
||||
$tbname = "test_binary_types";
|
||||
$spname = "test_binary_proc";
|
||||
$ch0 = 'd';
|
||||
$ch1 = 'e';
|
||||
|
||||
foreach ($dataTypes as $dataType) {
|
||||
$maxtype = strpos($dataType, "(max)");
|
||||
foreach ($lengths as $length) {
|
||||
if ($maxtype !== false) {
|
||||
$type = $dataType;
|
||||
} else {
|
||||
$type = "$dataType($length)";
|
||||
}
|
||||
trace("\nTesting $type:\n");
|
||||
|
||||
//create and populate table
|
||||
$colMetaArr = array(new ColumnMeta($type, "c_det"), new ColumnMeta($type, "c_rand", null, "randomized"));
|
||||
createTable($conn, $tbname, $colMetaArr);
|
||||
$input0 = str_repeat($ch0, $length);
|
||||
$input1 = str_repeat($ch1, $length);
|
||||
$ord0 = convert2Hex($ch0, $length);
|
||||
$ord1 = convert2Hex($ch1, $length);
|
||||
insertRow($conn, $tbname, array("c_det" => new BindParamOp(1, $input0, "PDO::PARAM_LOB", 0, "PDO::SQLSRV_ENCODING_BINARY"),
|
||||
"c_rand" => new BindParamOp(2, $input1, "PDO::PARAM_LOB", 0, "PDO::SQLSRV_ENCODING_BINARY")), "prepareBindParam");
|
||||
|
||||
// fetch with PDO::bindParam using a stored procedure
|
||||
$procArgs = "@c_det $type OUTPUT, @c_rand $type OUTPUT";
|
||||
$procCode = "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname";
|
||||
createProc($conn, $spname, $procArgs, $procCode);
|
||||
|
||||
// call stored procedure
|
||||
$outSql = getCallProcSqlPlaceholders($spname, 2);
|
||||
foreach ($pdoParamTypes as $pdoParamType) {
|
||||
$stmt = $conn->prepare($outSql);
|
||||
trace("\nParam $pdoParamType with INOUT = $inout\n");
|
||||
|
||||
if ($inout && $pdoParamType != PDO::PARAM_STR) {
|
||||
// Currently do not support getting binary as strings + INOUT param
|
||||
// See VSO 2829 for details
|
||||
$paramType = $pdoParamType | PDO::PARAM_INPUT_OUTPUT;
|
||||
} else {
|
||||
$paramType = $pdoParamType;
|
||||
}
|
||||
|
||||
$det = "";
|
||||
$rand = "";
|
||||
if ($pdoParamType == PDO::PARAM_STR || $pdoParamType == PDO::PARAM_LOB) {
|
||||
$stmt->bindParam(1, $det, $paramType, $length, PDO::SQLSRV_ENCODING_BINARY);
|
||||
$stmt->bindParam(2, $rand, $paramType, $length, PDO::SQLSRV_ENCODING_BINARY);
|
||||
} elseif ($pdoParamType == PDO::PARAM_BOOL || $pdoParamType == PDO::PARAM_INT) {
|
||||
$det = $rand = 0;
|
||||
$stmt->bindParam(1, $det, $paramType, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE);
|
||||
$stmt->bindParam(2, $rand, $paramType, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE);
|
||||
} else {
|
||||
$stmt->bindParam(1, $det, $paramType, $length);
|
||||
$stmt->bindParam(2, $rand, $paramType, $length);
|
||||
}
|
||||
|
||||
try {
|
||||
$stmt->execute();
|
||||
|
||||
$errMsg = "****$dataType as $pdoParamType failed with INOUT = $inout:****\n";
|
||||
if ($pdoParamType == PDO::PARAM_STR) {
|
||||
if ($det !== $input0 || $rand !== $input1) {
|
||||
printValues($errMsg, $det, $rand, $input0, $input1);
|
||||
}
|
||||
} elseif ($pdoParamType == PDO::PARAM_BOOL) {
|
||||
// for boolean values, they should all be bool(true)
|
||||
// because all floats are non-zeroes
|
||||
// This only occurs without AE
|
||||
// With AE enabled, this would have caused an exception
|
||||
if (!$det || !$rand) {
|
||||
printValues($errMsg, $det, $rand, $input0, $input1);
|
||||
}
|
||||
} else {
|
||||
// $pdoParamType is PDO::PARAM_INT
|
||||
// This only occurs without AE -- likely a rare use case
|
||||
// With AE enabled, this would have caused an exception
|
||||
if (strval($det) != $ord0 || strval($rand) != $ord1) {
|
||||
printValues($errMsg, $det, $rand, $ord0, $ord1);
|
||||
}
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$message = $e->getMessage();
|
||||
$errMsg = "EXCEPTION: ****$type as $pdoParamType failed with INOUT = $inout:****\n";
|
||||
if ($pdoParamType == PDO::PARAM_NULL || $pdoParamType == PDO::PARAM_LOB) {
|
||||
// Expected error IMSSP: "An invalid PHP type was specified
|
||||
// as an output parameter. DateTime objects, NULL values, and
|
||||
// streams cannot be specified as output parameters."
|
||||
$found = strpos($message, $errors['IMSSP']);
|
||||
if ($found === false) {
|
||||
printValues($errMsg, $det, $rand, $input0, $input1);
|
||||
}
|
||||
} elseif ($pdoParamType == PDO::PARAM_BOOL || PDO::PARAM_INT) {
|
||||
if (isAEConnected()) {
|
||||
if ($pdoParamType == PDO::PARAM_INT) {
|
||||
// Expected to fail with this message
|
||||
$error = "String data, right truncated for output parameter";
|
||||
$found = strpos($message, $error);
|
||||
} else {
|
||||
// PDO::PARAM_BOOL -
|
||||
// Expected error 07006 with AE enabled:
|
||||
// "Restricted data type attribute violation"
|
||||
// The data value returned for a parameter bound as
|
||||
// SQL_PARAM_INPUT_OUTPUT or SQL_PARAM_OUTPUT could not
|
||||
// be converted to the data type identified by the
|
||||
// ValueType argument in SQLBindParameter.
|
||||
$found = strpos($message, $errors['07006']);
|
||||
}
|
||||
} else {
|
||||
// When not AE enabled, expected to fail with something like this message
|
||||
// "Implicit conversion from data type nvarchar(max) to binary is not allowed. Use the CONVERT function to run this query."
|
||||
// Sometimes it's about nvarchar too
|
||||
$error = "to $dataType is not allowed. Use the CONVERT function to run this query.";
|
||||
$found = strpos($message, $error);
|
||||
}
|
||||
if ($found === false) {
|
||||
printValues($errMsg, $det, $rand, $input0, $input1);
|
||||
}
|
||||
} else {
|
||||
// catch all
|
||||
printValues($errMsg, $det, $rand, $input0, $input1);
|
||||
}
|
||||
}
|
||||
}
|
||||
dropProc($conn, $spname);
|
||||
dropTable($conn, $tbname);
|
||||
}
|
||||
}
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
} catch (PDOException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
testOutputBinary(false);
|
||||
testOutputBinary(true);
|
||||
|
||||
echo "Done\n";
|
||||
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
// drop the temporary table and stored procedure in case
|
||||
// the test failed without dropping them
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
$tbname = "test_binary_types";
|
||||
$spname = "test_binary_proc";
|
||||
$conn = connect();
|
||||
dropProc($conn, $spname);
|
||||
dropTable($conn, $tbname);
|
||||
unset($conn);
|
||||
?>
|
||||
--EXPECT--
|
||||
Done
|
|
@ -0,0 +1,171 @@
|
|||
--TEST--
|
||||
Test for retrieving encrypted data of char types of various sizes as output parameters
|
||||
--DESCRIPTION--
|
||||
Use PDOstatement::bindParam with all PDO::PARAM_ types
|
||||
--ENV--
|
||||
PHPT_EXEC=true
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
|
||||
$dataTypes = array("char", "varchar", "varchar(max)");
|
||||
$lengths = array(1, 8, 64, 512, 4000);
|
||||
$errors = array("IMSSP" => "An invalid PHP type was specified as an output parameter. DateTime objects, NULL values, and streams cannot be specified as output parameters.",
|
||||
"22003" => "Numeric value out of range");
|
||||
|
||||
$pdoParamTypes = array(
|
||||
PDO::PARAM_BOOL, // 5
|
||||
PDO::PARAM_NULL, // 0
|
||||
PDO::PARAM_INT, // 1
|
||||
PDO::PARAM_STR, // 2
|
||||
PDO::PARAM_LOB // 3
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
function printValues($msg, $det, $rand, $input0, $input1)
|
||||
{
|
||||
echo $msg;
|
||||
echo "input 0: "; var_dump($input0);
|
||||
echo "fetched: "; var_dump($det);
|
||||
echo "input 1: "; var_dump($input1);
|
||||
echo "fetched: "; var_dump($rand);
|
||||
}
|
||||
|
||||
function testOutputChars($inout)
|
||||
{
|
||||
global $pdoParamTypes, $dataTypes, $lengths, $errors;
|
||||
|
||||
try {
|
||||
|
||||
$conn = connect();
|
||||
$tbname = "test_char_types";
|
||||
$spname = "test_char_proc";
|
||||
|
||||
foreach ($dataTypes as $dataType) {
|
||||
$maxtype = strpos($dataType, "(max)");
|
||||
foreach ($lengths as $length) {
|
||||
if ($maxtype !== false) {
|
||||
$type = $dataType;
|
||||
} else {
|
||||
$type = "$dataType($length)";
|
||||
}
|
||||
trace("\nTesting $type:\n");
|
||||
|
||||
//create and populate table
|
||||
$colMetaArr = array(new ColumnMeta($type, "c_det"), new ColumnMeta($type, "c_rand", null, "randomized"));
|
||||
createTable($conn, $tbname, $colMetaArr);
|
||||
$input0 = str_repeat("1", $length);
|
||||
$input1 = str_repeat("2", $length);
|
||||
insertRow($conn, $tbname, array("c_det" => $input0,
|
||||
"c_rand" => $input1));
|
||||
|
||||
// fetch with PDO::bindParam using a stored procedure
|
||||
$procArgs = "@c_det $type OUTPUT, @c_rand $type OUTPUT";
|
||||
$procCode = "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname";
|
||||
createProc($conn, $spname, $procArgs, $procCode);
|
||||
|
||||
// call stored procedure
|
||||
$outSql = getCallProcSqlPlaceholders($spname, 2);
|
||||
foreach ($pdoParamTypes as $pdoParamType) {
|
||||
$det = "";
|
||||
$rand = "";
|
||||
$stmt = $conn->prepare($outSql);
|
||||
trace("\nParam $pdoParamType with INOUT = $inout\n");
|
||||
|
||||
if ($inout) {
|
||||
$paramType = $pdoParamType | PDO::PARAM_INPUT_OUTPUT;
|
||||
} else {
|
||||
$paramType = $pdoParamType;
|
||||
}
|
||||
|
||||
$len = $length;
|
||||
if ($pdoParamType == PDO::PARAM_BOOL || $pdoParamType == PDO::PARAM_INT) {
|
||||
$len = PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE;
|
||||
$det = $rand = 0;
|
||||
}
|
||||
|
||||
$stmt->bindParam(1, $det, $paramType, $len);
|
||||
$stmt->bindParam(2, $rand, $paramType, $len);
|
||||
|
||||
try {
|
||||
$stmt->execute();
|
||||
$errMsg = "****$type as $pdoParamType failed with INOUT = $inout:****\n";
|
||||
if ($length < 64 && $pdoParamType != PDO::PARAM_STR) {
|
||||
if ($pdoParamType == PDO::PARAM_BOOL) {
|
||||
// For boolean values, they should all be bool(true)
|
||||
// because all "string literals" are non-zeroes
|
||||
if (!$det || !$rand) {
|
||||
printValues($errMsg, $det, $rand, $input0, $input1);
|
||||
}
|
||||
} else {
|
||||
// $pdoParamType = PDO::PARAM_INT
|
||||
// Expect numeric values
|
||||
if ($det != intval($input0) || $rand != intval($input1)) {
|
||||
printValues($errMsg, $det, $rand, $input0, $input1);
|
||||
}
|
||||
}
|
||||
} elseif ($det !== $input0 || $rand !== $input1) {
|
||||
printValues($errMsg, $det, $rand, $input0, $input1);
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$message = $e->getMessage();
|
||||
$errMsg = "EXCEPTION: ****$type as $pdoParamType failed with INOUT = $inout:****\n";
|
||||
if ($pdoParamType == PDO::PARAM_NULL || $pdoParamType == PDO::PARAM_LOB) {
|
||||
// Expected error IMSSP: "An invalid PHP type was specified
|
||||
// as an output parameter. DateTime objects, NULL values, and
|
||||
// streams cannot be specified as output parameters."
|
||||
$found = strpos($message, $errors['IMSSP']);
|
||||
if ($found === false) {
|
||||
printValues($errMsg, $det, $rand, $input0, $input1);
|
||||
}
|
||||
} elseif ($pdoParamType == PDO::PARAM_BOOL) {
|
||||
if (isAEConnected()) {
|
||||
// Expected error 22003: "Numeric value out of range"
|
||||
$found = strpos($message, $errors['22003']);
|
||||
} else {
|
||||
// When not AE enabled, expected to fail to convert
|
||||
// whatever char type to integers
|
||||
$error = "Error converting data type $dataType to int";
|
||||
$found = strpos($message, $error);
|
||||
}
|
||||
if ($found === false) {
|
||||
printValues($errMsg, $det, $rand, $input0, $input1);
|
||||
}
|
||||
} else {
|
||||
printValues($errMsg, $det, $rand, $input0, $input1);
|
||||
}
|
||||
}
|
||||
}
|
||||
dropProc($conn, $spname);
|
||||
dropTable($conn, $tbname);
|
||||
}
|
||||
}
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
} catch (PDOException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
testOutputChars(false);
|
||||
testOutputChars(true);
|
||||
|
||||
echo "Done\n";
|
||||
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
// drop the temporary table and stored procedure in case
|
||||
// the test failed without dropping them
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
$tbname = "test_char_types";
|
||||
$spname = "test_char_proc";
|
||||
$conn = connect();
|
||||
dropProc($conn, $spname);
|
||||
dropTable($conn, $tbname);
|
||||
unset($conn);
|
||||
?>
|
||||
--EXPECT--
|
||||
Done
|
|
@ -0,0 +1,204 @@
|
|||
--TEST--
|
||||
Test for retrieving encrypted data of datetimes as output parameters
|
||||
--DESCRIPTION--
|
||||
Use PDOstatement::bindParam with all PDO::PARAM_ types
|
||||
--ENV--
|
||||
PHPT_EXEC=true
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
|
||||
$dataTypes = array("datetime2", "datetimeoffset", "time");
|
||||
$precisions = array(/*0, */1, 2, 4, 7);
|
||||
$inputValuesInit = array("datetime2" => array("0001-01-01 00:00:00", "9999-12-31 23:59:59"),
|
||||
"datetimeoffset" => array("0001-01-01 00:00:00 -14:00", "9999-12-31 23:59:59 +14:00"),
|
||||
"time" => array("00:00:00", "23:59:59"));
|
||||
|
||||
$errors = array("IMSSP" => "An invalid PHP type was specified as an output parameter. DateTime objects, NULL values, and streams cannot be specified as output parameters.", "07006" => "Restricted data type attribute violation");
|
||||
|
||||
$pdoParamTypes = array(
|
||||
PDO::PARAM_BOOL, // 5
|
||||
PDO::PARAM_NULL, // 0
|
||||
PDO::PARAM_INT, // 1
|
||||
PDO::PARAM_STR, // 2
|
||||
PDO::PARAM_LOB // 3
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// compareDate() returns true when the date/time values are basically the same
|
||||
// e.g. 00:00:00.000 is the same as 00:00:00
|
||||
function compareDate($dtout, $dtin, $dataType)
|
||||
{
|
||||
if ($dataType == "datetimeoffset") {
|
||||
$dtarr = explode(' ', $dtin);
|
||||
if (strpos($dtout, $dtarr[0]) !== false && strpos($dtout, $dtarr[1]) !== false && strpos($dtout, $dtarr[2]) !== false) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (strpos($dtout, $dtin) !== false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function printValues($msg, $det, $rand, $inputValues)
|
||||
{
|
||||
echo $msg;
|
||||
echo "input 0: "; var_dump($inputValues[0]);
|
||||
echo "fetched: "; var_dump($det);
|
||||
echo "input 1: "; var_dump($inputValues[1]);
|
||||
echo "fetched: "; var_dump($rand);
|
||||
}
|
||||
|
||||
function testOutputDatetimes($inout)
|
||||
{
|
||||
global $pdoParamTypes, $dataTypes, $precisions, $inputValuesInit, $errors;
|
||||
|
||||
try {
|
||||
$conn = connect();
|
||||
|
||||
$tbname = "test_datetimes_types";
|
||||
$spname = "test_datetimes_proc";
|
||||
|
||||
foreach ($dataTypes as $dataType) {
|
||||
foreach ($precisions as $precision) {
|
||||
// change the input values depending on the precision
|
||||
$inputValues[0] = $inputValuesInit[$dataType][0];
|
||||
$inputValues[1] = $inputValuesInit[$dataType][1];
|
||||
if ($precision != 0) {
|
||||
if ($dataType == "datetime2") {
|
||||
$inputValues[1] .= "." . str_repeat("9", $precision);
|
||||
} else if ($dataType == "datetimeoffset") {
|
||||
$inputPieces = explode(" ", $inputValues[1]);
|
||||
$inputValues[1] = $inputPieces[0] . " " . $inputPieces[1] . "." . str_repeat("9", $precision) . " " . $inputPieces[2];
|
||||
} else if ($dataType == "time") {
|
||||
$inputValues[0] .= "." . str_repeat("0", $precision);
|
||||
$inputValues[1] .= "." . str_repeat("9", $precision);
|
||||
}
|
||||
}
|
||||
|
||||
$type = "$dataType($precision)";
|
||||
trace("\nTesting $type:\n");
|
||||
|
||||
//create and populate table
|
||||
$colMetaArr = array(new ColumnMeta($type, "c_det"), new ColumnMeta($type, "c_rand", null, "randomized"));
|
||||
createTable($conn, $tbname, $colMetaArr);
|
||||
|
||||
$stmt = insertRow($conn, $tbname, array("c_det" => $inputValues[0], "c_rand" => $inputValues[1]));
|
||||
|
||||
// fetch with PDO::bindParam using a stored procedure
|
||||
$procArgs = "@c_det $type OUTPUT, @c_rand $type OUTPUT";
|
||||
$procCode = "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname";
|
||||
createProc($conn, $spname, $procArgs, $procCode);
|
||||
|
||||
// call stored procedure
|
||||
$outSql = getCallProcSqlPlaceholders($spname, 2);
|
||||
foreach ($pdoParamTypes as $pdoParamType) {
|
||||
$det = 0;
|
||||
$rand = 0;
|
||||
$stmt = $conn->prepare($outSql);
|
||||
trace("\nParam $pdoParamType with INOUT = $inout\n");
|
||||
|
||||
if ($inout) {
|
||||
$paramType = $pdoParamType | PDO::PARAM_INPUT_OUTPUT;
|
||||
} else {
|
||||
$paramType = $pdoParamType;
|
||||
}
|
||||
|
||||
$len = 2048;
|
||||
if ($pdoParamType == PDO::PARAM_BOOL || $pdoParamType == PDO::PARAM_INT) {
|
||||
$len = PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE;
|
||||
}
|
||||
|
||||
$stmt->bindParam(1, $det, $paramType, $len);
|
||||
$stmt->bindParam(2, $rand, $paramType, $len);
|
||||
|
||||
try {
|
||||
$stmt->execute();
|
||||
$errMsg = "****$type as $pdoParamType failed with INOUT = $inout:****\n";
|
||||
// What follows only happens with OUTPUT parameter
|
||||
if ($inout) {
|
||||
echo "Any datetime type as INOUT param should have caused an exception!\n";
|
||||
}
|
||||
if ($pdoParamType == PDO::PARAM_INT) {
|
||||
// Expect an integer, the first part of the date time string
|
||||
$ch = ($dataType == "time")? ':' : '-';
|
||||
$tmp0 = explode($ch, $inputValues[0]);
|
||||
$tmp1 = explode($ch, $inputValues[1]);
|
||||
|
||||
if ($det != intval($tmp0[0]) || $rand != intval($tmp1[0])) {
|
||||
printValues($errMsg, $det, $rand, $inputValues);
|
||||
}
|
||||
} elseif (!compareDate($det, $inputValues[0], $dataType) ||
|
||||
!compareDate($rand, $inputValues[1], $dataType)) {
|
||||
printValues($errMsg, $det, $rand, $inputValues);
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$message = $e->getMessage();
|
||||
$errMsg = "EXCEPTION: ****$type as $pdoParamType failed with INOUT = $inout:\n$message****\n";
|
||||
if ($pdoParamType == PDO::PARAM_NULL || $pdoParamType == PDO::PARAM_LOB) {
|
||||
// Expected error IMSSP: "An invalid PHP type was specified
|
||||
// as an output parameter. DateTime objects, NULL values, and
|
||||
// streams cannot be specified as output parameters."
|
||||
$found = strpos($message, $errors['IMSSP']);
|
||||
} elseif (isAEConnected()) {
|
||||
if ($pdoParamType == PDO::PARAM_BOOL) {
|
||||
// Expected error 07006: "Restricted data type attribute violation"
|
||||
// What does this error mean?
|
||||
// The data value returned for a parameter bound as
|
||||
// SQL_PARAM_INPUT_OUTPUT or SQL_PARAM_OUTPUT could not
|
||||
// be converted to the data type identified by the
|
||||
// ValueType argument in SQLBindParameter.
|
||||
$found = strpos($message, $errors['07006']);
|
||||
} else {
|
||||
$error = "Invalid character value for cast specification";
|
||||
$found = strpos($message, $error);
|
||||
}
|
||||
} else {
|
||||
if ($pdoParamType == PDO::PARAM_BOOL) {
|
||||
$error = "Operand type clash: int is incompatible with $dataType";
|
||||
} else {
|
||||
$error = "Error converting data type nvarchar to $dataType";
|
||||
}
|
||||
$found = strpos($message, $error);
|
||||
}
|
||||
if ($found === false) {
|
||||
printValues($errMsg, $det, $rand, $inputValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
dropProc($conn, $spname);
|
||||
dropTable($conn, $tbname);
|
||||
}
|
||||
}
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
} catch (PDOException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
testOutputDatetimes(false);
|
||||
testOutputDatetimes(true);
|
||||
|
||||
echo "Done\n";
|
||||
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
// drop the temporary table and stored procedure in case
|
||||
// the test failed without dropping them
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
$tbname = "test_datetimes_types";
|
||||
$spname = "test_datetimes_proc";
|
||||
$conn = connect();
|
||||
dropProc($conn, $spname);
|
||||
dropTable($conn, $tbname);
|
||||
unset($conn);
|
||||
?>
|
||||
--EXPECT--
|
||||
Done
|
|
@ -0,0 +1,242 @@
|
|||
--TEST--
|
||||
Test for retrieving encrypted data of decimals/numerics as output parameters
|
||||
--DESCRIPTION--
|
||||
Use PDOstatement::bindParam with all PDO::PARAM_ types
|
||||
--ENV--
|
||||
PHPT_EXEC=true
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
|
||||
$dataTypes = array("decimal", "numeric");
|
||||
$precisions = array(1 => array(0, 1),
|
||||
4 => array(0, 1, 4),
|
||||
16 => array(0, 1, 4, 16),
|
||||
38 => array(0, 1, 4, 16, 38));
|
||||
$inputValuesInit = array(92233720368547758089223372036854775808, -92233720368547758089223372036854775808);
|
||||
$inputPrecision = 38;
|
||||
|
||||
$errors = array("IMSSP" => "An invalid PHP type was specified as an output parameter. DateTime objects, NULL values, and streams cannot be specified as output parameters.");
|
||||
|
||||
$pdoParamTypes = array(
|
||||
PDO::PARAM_BOOL, // 5
|
||||
PDO::PARAM_NULL, // 0
|
||||
PDO::PARAM_INT, // 1
|
||||
PDO::PARAM_STR, // 2
|
||||
PDO::PARAM_LOB // 3
|
||||
);
|
||||
|
||||
function printValues($msg, $det, $rand, $inputValues)
|
||||
{
|
||||
echo $msg;
|
||||
echo "input 0: "; var_dump($inputValues[0]);
|
||||
echo "fetched: "; var_dump($det);
|
||||
echo "input 1: "; var_dump($inputValues[1]);
|
||||
echo "fetched: "; var_dump($rand);
|
||||
}
|
||||
|
||||
// this function returns true if the floats are more different than expected
|
||||
function compareFloats($actual, $expected)
|
||||
{
|
||||
$epsilon = 0.00001;
|
||||
$diff = abs(($actual - $expected) / $expected);
|
||||
return ($diff > $epsilon);
|
||||
}
|
||||
|
||||
// function compareIntegers() returns false when the fetched values
|
||||
// are different from the expected inputs
|
||||
function compareIntegers($det, $rand, $inputValues, $pdoParamType)
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// See GitHub issue 707 - Fix this method when the problem is addressed
|
||||
//
|
||||
// Assume $pdoParamType is PDO::PARAM_BOOL or PDO::PARAM_INT
|
||||
if (is_string($det)) {
|
||||
return (!compareFloats(floatval($det), $inputValues[0])
|
||||
&& !compareFloats(floatval($rand), $inputValues[1]));
|
||||
} elseif ($pdoParamType == PDO::PARAM_INT) {
|
||||
$input0 = floor($inputValues[0]); // the positive float
|
||||
$input1 = ceil($inputValues[1]); // the negative float
|
||||
|
||||
return ($det == $input0 && $rand == $input1);
|
||||
} else {
|
||||
// $pdoParamType == PDO::PARAM_BOOL
|
||||
// Expect bool(true) or bool(false) depending on the rounded input values
|
||||
// But with AE enabled (aforementioned GitHub issue), the fetched values
|
||||
// are floats instead, which should be fixed
|
||||
$input0 = floor($inputValues[0]); // the positive float
|
||||
$input1 = ceil($inputValues[1]); // the negative float
|
||||
if (isAEConnected()) {
|
||||
$det = boolval(floor($det));
|
||||
$rand = boolval(ceil($rand));
|
||||
}
|
||||
|
||||
return ($det == boolval($input0) && $rand == boolval($input1));
|
||||
}
|
||||
}
|
||||
|
||||
// function compareDecimals() returns false when the fetched values
|
||||
// are different from the inputs, based on precision, scale
|
||||
function compareDecimals($det, $rand, $inputValues, $pdoParamType, $precision, $scale)
|
||||
{
|
||||
// Assume $pdoParamType is PDO::PARAM_STR
|
||||
for ($i = 0; $i < 2; $i++) {
|
||||
$inputStr = strval($inputValues[$i]);
|
||||
$fetchedStr = ($i == 0) ? strval(floatval($det)) : strval(floatval($rand));
|
||||
|
||||
if ($precision == $scale) {
|
||||
// compare up to $precision + digits left if radix point ('.') +
|
||||
// 1 digit ('.') + possibly the negative sign
|
||||
$len = $precision + 2 + $i;
|
||||
} elseif ($scale > 0) {
|
||||
// compare up to $precision + 1 digit ('.')
|
||||
// + possibly the negative sign
|
||||
$len = $precision + 1 + $i;
|
||||
} else {
|
||||
// in this case, $scale = 0
|
||||
// compare up to $precision + possibly the negative sign
|
||||
$len = $precision + $i;
|
||||
}
|
||||
|
||||
trace("Comparing $len...");
|
||||
$result = substr_compare($inputStr, $fetchedStr, 0, $len);
|
||||
if ($result != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function testOutputDecimals($inout)
|
||||
{
|
||||
global $pdoParamTypes, $dataTypes, $inputValuesInit, $precisions, $inputPrecision, $errors;
|
||||
|
||||
try {
|
||||
$conn = connect();
|
||||
|
||||
$tbname = "test_decimals_types";
|
||||
$spname = "test_decimals_proc";
|
||||
|
||||
foreach ($dataTypes as $dataType) {
|
||||
foreach ($precisions as $precision => $scales) {
|
||||
foreach ($scales as $scale) {
|
||||
// construct the input values depending on the precision and scale
|
||||
$precDiff = $inputPrecision - ($precision - $scale);
|
||||
$inputValues = $inputValuesInit;
|
||||
foreach ($inputValues as &$inputValue) {
|
||||
$inputValue = $inputValue / pow(10, $precDiff);
|
||||
}
|
||||
|
||||
$type = "$dataType($precision, $scale)";
|
||||
trace("\nTesting $type:\n");
|
||||
|
||||
//create and populate table
|
||||
$colMetaArr = array(new ColumnMeta($type, "c_det"), new ColumnMeta($type, "c_rand", null, "randomized"));
|
||||
createTable($conn, $tbname, $colMetaArr);
|
||||
|
||||
$stmt = insertRow($conn, $tbname, array("c_det" => $inputValues[0], "c_rand" => $inputValues[1]));
|
||||
|
||||
// fetch with PDO::bindParam using a stored procedure
|
||||
$procArgs = "@c_det $type OUTPUT, @c_rand $type OUTPUT";
|
||||
$procCode = "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname";
|
||||
createProc($conn, $spname, $procArgs, $procCode);
|
||||
|
||||
// call stored procedure
|
||||
$outSql = getCallProcSqlPlaceholders($spname, 2);
|
||||
foreach ($pdoParamTypes as $pdoParamType) {
|
||||
$det = $rand = 0.0;
|
||||
$stmt = $conn->prepare($outSql);
|
||||
|
||||
$len = 2048;
|
||||
// Do not initialize $det or $rand as empty strings
|
||||
// See VSO 2915 for details
|
||||
if ($pdoParamType == PDO::PARAM_BOOL || $pdoParamType == PDO::PARAM_INT) {
|
||||
$len = PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE;
|
||||
$det = $rand = 0;
|
||||
}
|
||||
|
||||
trace("\nParam $pdoParamType with INOUT = $inout\n");
|
||||
if ($inout) {
|
||||
$paramType = $pdoParamType | PDO::PARAM_INPUT_OUTPUT;
|
||||
} else {
|
||||
$paramType = $pdoParamType;
|
||||
}
|
||||
|
||||
$stmt->bindParam(1, $det, $paramType, $len);
|
||||
$stmt->bindParam(2, $rand, $paramType, $len);
|
||||
|
||||
try {
|
||||
$stmt->execute();
|
||||
|
||||
$errMsg = "****$type as $pdoParamType failed with INOUT = $inout:****\n";
|
||||
if ($pdoParamType == PDO::PARAM_BOOL || $pdoParamType == PDO::PARAM_INT) {
|
||||
if (!compareIntegers($det, $rand, $inputValues, $pdoParamType)) {
|
||||
printValues($errMsg, $det, $rand, $inputValues);
|
||||
}
|
||||
} else {
|
||||
// When $pdoParamType is PDO::PARAM_STR, the accuracies
|
||||
// should have been preserved based on the original
|
||||
// precision and scale, so compare the retrieved values
|
||||
// against the input values with more details
|
||||
if (!compareDecimals($det, $rand, $inputValues, $pdoParamType, $precision, $scale)) {
|
||||
printValues($errMsg, $det, $rand, $inputValues);
|
||||
}
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$message = $e->getMessage();
|
||||
$errMsg = "EXCEPTION: ****$type as $pdoParamType failed with INOUT = $inout:****\n";
|
||||
if ($pdoParamType == PDO::PARAM_NULL || $pdoParamType == PDO::PARAM_LOB) {
|
||||
// Expected error IMSSP: "An invalid PHP type was specified
|
||||
// as an output parameter. DateTime objects, NULL values, and
|
||||
// streams cannot be specified as output parameters."
|
||||
$found = strpos($message, $errors['IMSSP']);
|
||||
if ($found === false) {
|
||||
printValues($errMsg, $det, $rand, $inputValues);
|
||||
}
|
||||
} elseif (!isAEConnected() && $precision >= 16 && $pdoParamType == PDO::PARAM_BOOL) {
|
||||
// When not AE enabled, large numbers are expected to
|
||||
// fail when converting to booleans
|
||||
$error = "Error converting data type $dataType to int";
|
||||
$found = strpos($message, $error);
|
||||
if ($found === false) {
|
||||
printValues($errMsg, $det, $rand, $inputValues);
|
||||
}
|
||||
} else {
|
||||
printValues($errMsg, $det, $rand, $inputValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
dropProc($conn, $spname);
|
||||
dropTable($conn, $tbname);
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
} catch (PDOException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
testOutputDecimals(false);
|
||||
testOutputDecimals(true);
|
||||
|
||||
echo "Done\n";
|
||||
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
// drop the temporary table and stored procedure in case
|
||||
// the test failed without dropping them
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
$tbname = "test_decimals_types";
|
||||
$spname = "test_decimals_proc";
|
||||
$conn = connect();
|
||||
dropProc($conn, $spname);
|
||||
dropTable($conn, $tbname);
|
||||
unset($conn);
|
||||
?>
|
||||
--EXPECT--
|
||||
Done
|
|
@ -0,0 +1,181 @@
|
|||
--TEST--
|
||||
Test for retrieving encrypted data of floats as output parameters
|
||||
--DESCRIPTION--
|
||||
Use PDOstatement::bindParam with all PDO::PARAM_ types
|
||||
--ENV--
|
||||
PHPT_EXEC=true
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
|
||||
$errors = array("IMSSP" => "An invalid PHP type was specified as an output parameter. DateTime objects, NULL values, and streams cannot be specified as output parameters.");
|
||||
|
||||
$pdoParamTypes = array(
|
||||
PDO::PARAM_BOOL, // 5
|
||||
PDO::PARAM_NULL, // 0
|
||||
PDO::PARAM_INT, // 1
|
||||
PDO::PARAM_STR, // 2
|
||||
PDO::PARAM_LOB // 3
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// this function returns true if the floats are more different than expected
|
||||
function compareFloats($actual, $expected)
|
||||
{
|
||||
$epsilon = 0.0001;
|
||||
$diff = abs(($actual - $expected) / $expected);
|
||||
return ($diff > $epsilon);
|
||||
}
|
||||
|
||||
function printValues($msg, $det, $rand, $inputValues)
|
||||
{
|
||||
echo $msg;
|
||||
echo "input 0: "; var_dump($inputValues[0]);
|
||||
echo "fetched: "; var_dump($det);
|
||||
echo "input 1: "; var_dump($inputValues[1]);
|
||||
echo "fetched: "; var_dump($rand);
|
||||
}
|
||||
|
||||
function testOutputFloats($fetchNumeric, $inout)
|
||||
{
|
||||
global $pdoParamTypes, $inputValues, $errors;
|
||||
|
||||
try {
|
||||
$conn = connect();
|
||||
$conn->setAttribute(PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE, $fetchNumeric);
|
||||
|
||||
$tbname = "test_floats_types";
|
||||
$spname = "test_floats_proc";
|
||||
|
||||
$bits = array(1, 12, 24, 36, 53);
|
||||
|
||||
foreach ($bits as $bit) {
|
||||
$type = "float($bit)";
|
||||
trace("\nTesting $type:\n");
|
||||
|
||||
$inputValues = array();
|
||||
// create random input values
|
||||
for ($i = 0; $i < 2; $i++) {
|
||||
$mantissa = rand(1, 100000000);
|
||||
$decimals = rand(1, 100000000);
|
||||
$floatNum = $mantissa + $decimals / 10000000;
|
||||
if ($i > 0) {
|
||||
// make the second input negative
|
||||
$floatNum *= -1;
|
||||
}
|
||||
array_push($inputValues, $floatNum);
|
||||
}
|
||||
//create and populate table
|
||||
$colMetaArr = array(new ColumnMeta($type, "c_det"), new ColumnMeta($type, "c_rand", null, "randomized"));
|
||||
createTable($conn, $tbname, $colMetaArr);
|
||||
insertRow($conn,
|
||||
$tbname,
|
||||
array("c_det" => new BindParamOp(1, $inputValues[0], 'PDO::PARAM_INT'),
|
||||
"c_rand" => new BindParamOp(2, $inputValues[1], 'PDO::PARAM_INT')),
|
||||
"prepareBindParam");
|
||||
|
||||
// fetch with PDO::bindParam using a stored procedure
|
||||
$procArgs = "@c_det $type OUTPUT, @c_rand $type OUTPUT";
|
||||
$procCode = "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname";
|
||||
createProc($conn, $spname, $procArgs, $procCode);
|
||||
|
||||
// call stored procedure
|
||||
$outSql = getCallProcSqlPlaceholders($spname, 2);
|
||||
foreach ($pdoParamTypes as $pdoParamType) {
|
||||
if ($pdoParamType == PDO::PARAM_INT && (strtoupper(substr(PHP_OS, 0, 3)) != 'WIN' || substr(PHP_VERSION, 0, 3) == "7.0")) {
|
||||
// Bug 2876 in VSO: Linux or PHP 7.0 - when retrieving a float as OUTPUT
|
||||
// or INOUT parameter with PDO::PARAM_INT, the returned values
|
||||
// are always single digits, regardless of the original floats
|
||||
continue;
|
||||
}
|
||||
|
||||
$det = 0.0;
|
||||
$rand = 0.0;
|
||||
$stmt = $conn->prepare($outSql);
|
||||
|
||||
$len = 2048;
|
||||
if ($pdoParamType == PDO::PARAM_BOOL || $pdoParamType == PDO::PARAM_INT) {
|
||||
$len = PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE;
|
||||
$det = 0;
|
||||
$rand = 0;
|
||||
}
|
||||
trace("\nParam $pdoParamType with INOUT = $inout\n");
|
||||
|
||||
if ($inout) {
|
||||
$paramType = $pdoParamType | PDO::PARAM_INPUT_OUTPUT;
|
||||
} else {
|
||||
$paramType = $pdoParamType;
|
||||
}
|
||||
$stmt->bindParam(1, $det, $paramType, $len);
|
||||
$stmt->bindParam(2, $rand, $paramType, $len);
|
||||
|
||||
try {
|
||||
$stmt->execute();
|
||||
|
||||
$errMsg = "****$type as $pdoParamType failed with INOUT = $inout:****\n";
|
||||
if ($pdoParamType == PDO::PARAM_BOOL) {
|
||||
// for boolean values, they should all be bool(true)
|
||||
// because all floats are non-zeroes
|
||||
if (!$det || !$rand) {
|
||||
printValues($errMsg, $det, $rand, $inputValues);
|
||||
}
|
||||
} else {
|
||||
// Compare the retrieved values against the input values
|
||||
// if either of them is very different, print them all
|
||||
if (compareFloats(floatval($det), $inputValues[0]) ||
|
||||
compareFloats(floatval($rand), $inputValues[1])) {
|
||||
printValues($errMsg, $det, $rand, $inputValues);
|
||||
}
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$message = $e->getMessage();
|
||||
$errMsg = "EXCEPTION: ****$type as $pdoParamType failed with INOUT = $inout:****\n";
|
||||
|
||||
if ($pdoParamType == PDO::PARAM_NULL || $pdoParamType == PDO::PARAM_LOB) {
|
||||
// Expected error IMSSP: "An invalid PHP type was specified
|
||||
// as an output parameter. DateTime objects, NULL values, and
|
||||
// streams cannot be specified as output parameters."
|
||||
$found = strpos($message, $errors['IMSSP']);
|
||||
if ($found === false) {
|
||||
printValues($errMsg, $det, $rand, $inputValues);
|
||||
}
|
||||
} else {
|
||||
printValues($errMsg, $det, $rand, $inputValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
dropProc($conn, $spname);
|
||||
dropTable($conn, $tbname);
|
||||
}
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
} catch (PDOException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
testOutputFloats(false, false);
|
||||
testOutputFloats(true, false);
|
||||
testOutputFloats(false, true);
|
||||
testOutputFloats(true, true);
|
||||
|
||||
echo "Done\n";
|
||||
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
// drop the temporary table and stored procedure in case
|
||||
// the test failed without dropping them
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
$tbname = "test_floats_types";
|
||||
$spname = "test_floats_proc";
|
||||
$conn = connect();
|
||||
dropProc($conn, $spname);
|
||||
dropTable($conn, $tbname);
|
||||
unset($conn);
|
||||
?>
|
||||
--EXPECT--
|
||||
Done
|
|
@ -0,0 +1,193 @@
|
|||
--TEST--
|
||||
Test for retrieving encrypted data of integral types as output parameters
|
||||
--DESCRIPTION--
|
||||
Use PDOstatement::bindParam with all PDO::PARAM_ types
|
||||
--ENV--
|
||||
PHPT_EXEC=true
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
|
||||
$dataTypes = array("bit", "tinyint", "smallint", "int", "bigint");
|
||||
$errors = array("IMSSP" => "An invalid PHP type was specified as an output parameter. DateTime objects, NULL values, and streams cannot be specified as output parameters.", "22003" => "Numeric value out of range", "42000" => "Error converting data type bigint to int");
|
||||
|
||||
$pdoParamTypes = array(
|
||||
PDO::PARAM_BOOL, // 5
|
||||
PDO::PARAM_NULL, // 0
|
||||
PDO::PARAM_INT, // 1
|
||||
PDO::PARAM_STR, // 2
|
||||
PDO::PARAM_LOB // 3
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
function printValues($msg, $det, $rand, $inputValues)
|
||||
{
|
||||
echo $msg;
|
||||
echo "input 0: "; var_dump($inputValues[0]);
|
||||
echo "fetched: "; var_dump($det);
|
||||
echo "input 1: "; var_dump($inputValues[1]);
|
||||
echo "fetched: "; var_dump($rand);
|
||||
}
|
||||
|
||||
function generateInputs($dataType)
|
||||
{
|
||||
// create random input values based on data types
|
||||
// make the second input negative but only for some data types
|
||||
if ($dataType == "bit") {
|
||||
$inputValues = array(0, 1);
|
||||
} elseif ($dataType == "tinyint") {
|
||||
$inputValues = array();
|
||||
for ($i = 0; $i < 2; $i++) {
|
||||
$randomNum = rand(0, 255);
|
||||
array_push($inputValues, $randomNum);
|
||||
}
|
||||
} else {
|
||||
switch ($dataType) {
|
||||
case "smallint":
|
||||
$max = 32767;
|
||||
break;
|
||||
case "int":
|
||||
$max = 2147483647;
|
||||
break;
|
||||
default:
|
||||
$max = getrandmax();
|
||||
}
|
||||
|
||||
$inputValues = array();
|
||||
for ($i = 0; $i < 2; $i++) {
|
||||
$randomNum = rand(0, $max);
|
||||
if ($i > 0) {
|
||||
// make the second input negative but only for some data types
|
||||
$randomNum *= -1;
|
||||
}
|
||||
array_push($inputValues, $randomNum);
|
||||
if (traceMode()) {
|
||||
echo "input: "; var_dump($inputValues[$i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $inputValues;
|
||||
}
|
||||
|
||||
function testOutputInts($inout)
|
||||
{
|
||||
global $pdoParamTypes, $dataTypes, $errors;
|
||||
|
||||
try {
|
||||
$conn = connect();
|
||||
$tbname = "test_integers_types";
|
||||
$spname = "test_integers_proc";
|
||||
|
||||
foreach ($dataTypes as $dataType) {
|
||||
trace("\nTesting $dataType:\n");
|
||||
|
||||
//create and populate table
|
||||
$colMetaArr = array(new ColumnMeta($dataType, "c_det"), new ColumnMeta($dataType, "c_rand", null, "randomized"));
|
||||
createTable($conn, $tbname, $colMetaArr);
|
||||
$inputValues = generateInputs($dataType);
|
||||
insertRow($conn, $tbname, array("c_det" => $inputValues[0],
|
||||
"c_rand" => $inputValues[1]));
|
||||
|
||||
// fetch with PDO::bindParam using a stored procedure
|
||||
$procArgs = "@c_det $dataType OUTPUT, @c_rand $dataType OUTPUT";
|
||||
$procCode = "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname";
|
||||
createProc($conn, $spname, $procArgs, $procCode);
|
||||
|
||||
// call stored procedure
|
||||
$outSql = getCallProcSqlPlaceholders($spname, 2);
|
||||
foreach ($pdoParamTypes as $pdoParamType) {
|
||||
$det = 0;
|
||||
$rand = 0;
|
||||
$stmt = $conn->prepare($outSql);
|
||||
|
||||
$len = 2048;
|
||||
if ($pdoParamType == PDO::PARAM_BOOL || $pdoParamType == PDO::PARAM_INT) {
|
||||
$len = PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE;
|
||||
}
|
||||
trace("\nParam $pdoParamType with INOUT = $inout\n");
|
||||
|
||||
if ($inout) {
|
||||
$paramType = $pdoParamType | PDO::PARAM_INPUT_OUTPUT;
|
||||
} else {
|
||||
$paramType = $pdoParamType;
|
||||
}
|
||||
$stmt->bindParam(1, $det, $paramType, $len);
|
||||
$stmt->bindParam(2, $rand, $paramType, $len);
|
||||
|
||||
try {
|
||||
$stmt->execute();
|
||||
$errMsg = "****$dataType as $pdoParamType failed with INOUT = $inout:****\n";
|
||||
if ($pdoParamType == PDO::PARAM_STR) {
|
||||
if ($det !== strval($inputValues[0]) || $rand !== strval($inputValues[1])) {
|
||||
// comparisons between strings, use '!=='
|
||||
printValues($errMsg, $det, $rand, $inputValues);
|
||||
}
|
||||
} elseif ($pdoParamType == PDO::PARAM_INT || $pdoParamType == PDO::PARAM_BOOL) {
|
||||
// comparisons between integers and booleans, do not use '!=='
|
||||
if ($det != $inputValues[0] || $rand != $inputValues[1]) {
|
||||
printValues($errMsg, $det, $rand, $inputValues);
|
||||
}
|
||||
} else {
|
||||
printValues($errMsg, $det, $rand, $inputValues);
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$message = $e->getMessage();
|
||||
$errMsg = "EXCEPTION: ****$dataType as $pdoParamType failed with INOUT = $inout:****\n";
|
||||
if ($pdoParamType == PDO::PARAM_NULL || $pdoParamType == PDO::PARAM_LOB) {
|
||||
// Expected error IMSSP: "An invalid PHP type was specified
|
||||
// as an output parameter. DateTime objects, NULL values, and
|
||||
// streams cannot be specified as output parameters."
|
||||
$found = strpos($message, $errors['IMSSP']);
|
||||
if ($found === false) {
|
||||
printValues($errMsg, $det, $rand, $inputValues);
|
||||
}
|
||||
} elseif ($dataType == "bigint" && ($pdoParamType == PDO::PARAM_INT || $pdoParamType == PDO::PARAM_BOOL)) {
|
||||
if (isAEConnected()) {
|
||||
// Expected error 22003: "Numeric value out of range"
|
||||
// This is expected when converting big integer to integer or bool
|
||||
$found = strpos($message, $errors['22003']);
|
||||
} elseif ($pdoParamType == PDO::PARAM_BOOL) {
|
||||
// Expected error 42000: "Error converting data type bigint to int"
|
||||
// This is expected when not AE connected and converting big integer to bool
|
||||
$found = strpos($message, $errors['42000']);
|
||||
}
|
||||
if ($found === false) {
|
||||
printValues($errMsg, $det, $rand, $inputValues);
|
||||
}
|
||||
} else {
|
||||
printValues($errMsg, $det, $rand, $inputValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
dropProc($conn, $spname);
|
||||
dropTable($conn, $tbname);
|
||||
}
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
} catch (PDOException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
testOutputInts(false);
|
||||
testOutputInts(true);
|
||||
|
||||
echo "Done\n";
|
||||
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
// drop the temporary table and stored procedure in case
|
||||
// the test failed without dropping them
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
$tbname = "test_integers_types";
|
||||
$spname = "test_integers_proc";
|
||||
$conn = connect();
|
||||
dropProc($conn, $spname);
|
||||
dropTable($conn, $tbname);
|
||||
unset($conn);
|
||||
?>
|
||||
--EXPECT--
|
||||
Done
|
|
@ -0,0 +1,172 @@
|
|||
--TEST--
|
||||
Test for retrieving encrypted data of nchar types of various sizes as output parameters
|
||||
--DESCRIPTION--
|
||||
Use PDOstatement::bindParam with all PDO::PARAM_ types
|
||||
Note: Because the maximum allowable table row size is 8060 bytes, 7 bytes of which are reserved for internal overhead. In other words, this allows up to two nvarchar() columns with length slightly
|
||||
more than 2000 wide characters. Therefore, the max length in this test is 2010.
|
||||
--ENV--
|
||||
PHPT_EXEC=true
|
||||
--SKIPIF--
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
|
||||
$dataTypes = array("nchar", "nvarchar", "nvarchar(max)");
|
||||
$lengths = array(1, 8, 64, 512, 2010);
|
||||
$errors = array("IMSSP" => "An invalid PHP type was specified as an output parameter. DateTime objects, NULL values, and streams cannot be specified as output parameters.", "22003" => "Numeric value out of range");
|
||||
|
||||
$pdoParamTypes = array(
|
||||
PDO::PARAM_BOOL, // 5
|
||||
PDO::PARAM_NULL, // 0
|
||||
PDO::PARAM_INT, // 1
|
||||
PDO::PARAM_STR, // 2
|
||||
PDO::PARAM_LOB // 3
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
function printValues($msg, $det, $rand, $input0, $input1)
|
||||
{
|
||||
echo $msg;
|
||||
echo "input 0: "; var_dump($input0);
|
||||
echo "fetched: "; var_dump($det);
|
||||
echo "input 1: "; var_dump($input1);
|
||||
echo "fetched: "; var_dump($rand);
|
||||
}
|
||||
|
||||
function testOutputNChars($inout)
|
||||
{
|
||||
global $pdoParamTypes, $dataTypes, $lengths, $errors;
|
||||
|
||||
try {
|
||||
$conn = connect();
|
||||
$tbname = "test_nchar_types";
|
||||
$spname = "test_nchar_proc";
|
||||
|
||||
foreach ($dataTypes as $dataType) {
|
||||
$maxtype = strpos($dataType, "(max)");
|
||||
foreach ($lengths as $length) {
|
||||
if ($maxtype !== false) {
|
||||
$type = $dataType;
|
||||
} else {
|
||||
$type = "$dataType($length)";
|
||||
}
|
||||
trace("\nTesting $type:\n");
|
||||
|
||||
//create and populate table
|
||||
$colMetaArr = array(new ColumnMeta($type, "c_det"), new ColumnMeta($type, "c_rand", null, "randomized"));
|
||||
createTable($conn, $tbname, $colMetaArr);
|
||||
$input0 = str_repeat("1", $length);
|
||||
$input1 = str_repeat("2", $length);
|
||||
insertRow($conn, $tbname, array("c_det" => $input0,
|
||||
"c_rand" => $input1));
|
||||
|
||||
// fetch with PDO::bindParam using a stored procedure
|
||||
$procArgs = "@c_det $type OUTPUT, @c_rand $type OUTPUT";
|
||||
$procCode = "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname";
|
||||
createProc($conn, $spname, $procArgs, $procCode);
|
||||
|
||||
// call stored procedure
|
||||
$outSql = getCallProcSqlPlaceholders($spname, 2);
|
||||
foreach ($pdoParamTypes as $pdoParamType) {
|
||||
$det = "";
|
||||
$rand = "";
|
||||
$stmt = $conn->prepare($outSql);
|
||||
trace("\nParam $pdoParamType with INOUT = $inout\n");
|
||||
|
||||
if ($inout) {
|
||||
$paramType = $pdoParamType | PDO::PARAM_INPUT_OUTPUT;
|
||||
} else {
|
||||
$paramType = $pdoParamType;
|
||||
}
|
||||
|
||||
$len = $length;
|
||||
if ($pdoParamType == PDO::PARAM_BOOL || $pdoParamType == PDO::PARAM_INT) {
|
||||
$len = PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE;
|
||||
$det = $rand = 0;
|
||||
}
|
||||
|
||||
$stmt->bindParam(1, $det, $paramType, $len);
|
||||
$stmt->bindParam(2, $rand, $paramType, $len);
|
||||
|
||||
try {
|
||||
$stmt->execute();
|
||||
$errMsg = "****$type as $pdoParamType failed with INOUT = $inout:****\n";
|
||||
// When $length >= 64, a string is returned regardless of $pdoParamType
|
||||
if ($length < 64 && $pdoParamType != PDO::PARAM_STR) {
|
||||
if ($pdoParamType == PDO::PARAM_BOOL) {
|
||||
// For boolean values, they should all be bool(true)
|
||||
// because all "string literals" are non-zeroes
|
||||
if (!$det || !$rand) {
|
||||
printValues($errMsg, $det, $rand, $input0, $input1);
|
||||
}
|
||||
} else {
|
||||
// $pdoParamType = PDO::PARAM_INT
|
||||
// Expect numeric values
|
||||
if ($det != intval($input0) || $rand != intval($input1)) {
|
||||
printValues($errMsg, $det, $rand, $input0, $input1);
|
||||
}
|
||||
}
|
||||
} elseif ($det !== $input0 || $rand !== $input1) {
|
||||
printValues($errMsg, $det, $rand, $input0, $input1);
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$message = $e->getMessage();
|
||||
$errMsg = "EXCEPTION: ****$type as $pdoParamType failed with INOUT = $inout:****\n";
|
||||
if ($pdoParamType == PDO::PARAM_NULL || $pdoParamType == PDO::PARAM_LOB) {
|
||||
// Expected error IMSSP: "An invalid PHP type was specified
|
||||
// as an output parameter. DateTime objects, NULL values, and
|
||||
// streams cannot be specified as output parameters."
|
||||
$found = strpos($message, $errors['IMSSP']);
|
||||
if ($found === false) {
|
||||
printValues($errMsg, $det, $rand, $input0, $input1);
|
||||
}
|
||||
} elseif ($pdoParamType == PDO::PARAM_BOOL) {
|
||||
if (isAEConnected()) {
|
||||
// Expected error 22003: "Numeric value out of range"
|
||||
$found = strpos($message, $errors['22003']);
|
||||
} else {
|
||||
// When not AE enabled, expected to fail to convert
|
||||
// whatever char type to integers
|
||||
$error = "Error converting data type $dataType to int";
|
||||
$found = strpos($message, $error);
|
||||
}
|
||||
if ($found === false) {
|
||||
printValues($errMsg, $det, $rand, $input0, $input1);
|
||||
}
|
||||
} else {
|
||||
printValues($errMsg, $det, $rand, $input0, $input1);
|
||||
}
|
||||
}
|
||||
}
|
||||
dropProc($conn, $spname);
|
||||
dropTable($conn, $tbname);
|
||||
}
|
||||
}
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
} catch (PDOException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
testOutputNChars(false);
|
||||
testOutputNChars(true);
|
||||
|
||||
echo "Done\n";
|
||||
|
||||
?>
|
||||
--CLEAN--
|
||||
<?php
|
||||
// drop the temporary table and stored procedure in case
|
||||
// the test failed without dropping them
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
$tbname = "test_nchar_types";
|
||||
$spname = "test_nchar_proc";
|
||||
$conn = connect();
|
||||
dropProc($conn, $spname);
|
||||
dropTable($conn, $tbname);
|
||||
unset($conn);
|
||||
?>
|
||||
--EXPECT--
|
||||
Done
|
|
@ -1,160 +1,138 @@
|
|||
--TEST--
|
||||
Test new connection keyword Driver with valid and invalid values
|
||||
--SKIPIF--
|
||||
<?php require('skipif.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once('MsSetup.inc');
|
||||
|
||||
try {
|
||||
$conn = new PDO("sqlsrv:server = $server", $uid, $pwd);
|
||||
$msodbcsqlVer = $conn->getAttribute(PDO::ATTR_CLIENT_VERSION)['DriverVer'];
|
||||
$msodbcsqlMaj = explode(".", $msodbcsqlVer)[0];
|
||||
} catch(PDOException $e) {
|
||||
echo "Failed to connect\n";
|
||||
print_r($e->getMessage());
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
$conn = null;
|
||||
|
||||
// start test
|
||||
testValidValues();
|
||||
testInvalidValues();
|
||||
testEncryptedWithODBC();
|
||||
testWrongODBC();
|
||||
echo "Done";
|
||||
// end test
|
||||
|
||||
///////////////////////////
|
||||
function connectVerifyOutput($connectionOptions, $expected = '')
|
||||
{
|
||||
global $server, $uid, $pwd;
|
||||
|
||||
try {
|
||||
$conn = new PDO("sqlsrv:server = $server ; $connectionOptions", $uid, $pwd);
|
||||
} catch(PDOException $e) {
|
||||
if (strpos($e->getMessage(), $expected) === false) {
|
||||
print_r($e->getMessage());
|
||||
echo "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function testValidValues()
|
||||
{
|
||||
global $msodbcsqlMaj;
|
||||
|
||||
$value = "";
|
||||
// The major version number of ODBC 11 can be 11 or 12
|
||||
// Test with {}
|
||||
switch ($msodbcsqlMaj) {
|
||||
case 17:
|
||||
$value = "{ODBC Driver 17 for SQL Server}";
|
||||
break;
|
||||
case 14:
|
||||
case 13:
|
||||
$value = "{ODBC Driver 13 for SQL Server}";
|
||||
break;
|
||||
case 12:
|
||||
case 11:
|
||||
$value = "{ODBC Driver 11 for SQL Server}";
|
||||
break;
|
||||
default:
|
||||
$value = "invalid value $msodbcsqlMaj";
|
||||
}
|
||||
$connectionOptions = "Driver = $value";
|
||||
connectVerifyOutput($connectionOptions);
|
||||
|
||||
// Test without {}
|
||||
switch ($msodbcsqlMaj) {
|
||||
case 17:
|
||||
$value = "ODBC Driver 17 for SQL Server";
|
||||
break;
|
||||
case 14:
|
||||
case 13:
|
||||
$value = "ODBC Driver 13 for SQL Server";
|
||||
break;
|
||||
case 12:
|
||||
case 11:
|
||||
$value = "ODBC Driver 11 for SQL Server";
|
||||
break;
|
||||
default:
|
||||
$value = "invalid value $msodbcsqlMaj";
|
||||
}
|
||||
|
||||
$connectionOptions = "Driver = $value";
|
||||
connectVerifyOutput($connectionOptions);
|
||||
}
|
||||
|
||||
function testInvalidValues()
|
||||
{
|
||||
$values = array("{SQL Server Native Client 11.0}",
|
||||
"SQL Server Native Client 11.0",
|
||||
"ODBC Driver 00 for SQL Server",
|
||||
123,
|
||||
false);
|
||||
|
||||
foreach ($values as $value) {
|
||||
$connectionOptions = "Driver = $value";
|
||||
$expected = "Invalid value $value was specified for Driver option.";
|
||||
connectVerifyOutput($connectionOptions, $expected);
|
||||
}
|
||||
}
|
||||
|
||||
function testEncryptedWithODBC()
|
||||
{
|
||||
global $msodbcsqlMaj, $server, $uid, $pwd;
|
||||
|
||||
$value = "ODBC Driver 13 for SQL Server";
|
||||
$connectionOptions = "Driver = $value; ColumnEncryption = Enabled;";
|
||||
$expected = "The Always Encrypted feature requires Microsoft ODBC Driver 17 for SQL Server.";
|
||||
|
||||
connectVerifyOutput($connectionOptions, $expected);
|
||||
|
||||
// TODO: the following block will change once ODBC 17 is officially released
|
||||
$value = "ODBC Driver 17 for SQL Server";
|
||||
$connectionOptions = "Driver = $value; ColumnEncryption = Enabled;";
|
||||
|
||||
$success = "Successfully connected with column encryption.";
|
||||
$expected = "The specified ODBC Driver is not found.";
|
||||
$message = $success;
|
||||
try {
|
||||
$conn = new PDO("sqlsrv:server = $server ; $connectionOptions", $uid, $pwd);
|
||||
} catch(PDOException $e) {
|
||||
$message = $e->getMessage();
|
||||
}
|
||||
|
||||
if ($msodbcsqlMaj == 17) {
|
||||
// this indicates that OCBC 17 is the only available driver
|
||||
if (strcmp($message, $success)) {
|
||||
print_r($message);
|
||||
}
|
||||
} else {
|
||||
// OCBC 17 might or might not exist
|
||||
if (strcmp($message, $success)) {
|
||||
if (strpos($message, $expected) === false) {
|
||||
print_r($message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function testWrongODBC()
|
||||
{
|
||||
global $msodbcsqlMaj;
|
||||
|
||||
// TODO: this will change once ODBC 17 is officially released
|
||||
$value = "ODBC Driver 17 for SQL Server";
|
||||
if ($msodbcsqlMaj == 17 || $msodbcsqlMaj < 13) {
|
||||
$value = "ODBC Driver 13 for SQL Server";
|
||||
}
|
||||
$connectionOptions = "Driver = $value;";
|
||||
$expected = "The specified ODBC Driver is not found.";
|
||||
|
||||
connectVerifyOutput($connectionOptions, $expected);
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
--TEST--
|
||||
Test new connection keyword Driver with valid and invalid values
|
||||
--SKIPIF--
|
||||
<?php require('skipif.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once('MsSetup.inc');
|
||||
|
||||
try {
|
||||
$conn = new PDO("sqlsrv:server = $server", $uid, $pwd);
|
||||
$msodbcsqlVer = $conn->getAttribute(PDO::ATTR_CLIENT_VERSION)['DriverVer'];
|
||||
$msodbcsqlMaj = explode(".", $msodbcsqlVer)[0];
|
||||
} catch(PDOException $e) {
|
||||
echo "Failed to connect\n";
|
||||
print_r($e->getMessage());
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
$conn = null;
|
||||
|
||||
// start test
|
||||
testValidValues();
|
||||
testInvalidValues();
|
||||
testEncryptedWithODBC();
|
||||
testWrongODBC();
|
||||
echo "Done";
|
||||
// end test
|
||||
|
||||
///////////////////////////
|
||||
function connectVerifyOutput($connectionOptions, $expected = '')
|
||||
{
|
||||
global $server, $uid, $pwd;
|
||||
|
||||
try {
|
||||
$conn = new PDO("sqlsrv:server = $server ; $connectionOptions", $uid, $pwd);
|
||||
} catch(PDOException $e) {
|
||||
if (strpos($e->getMessage(), $expected) === false) {
|
||||
print_r($e->getMessage());
|
||||
echo "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function testValidValues()
|
||||
{
|
||||
global $msodbcsqlMaj;
|
||||
|
||||
$value = "";
|
||||
// The major version number of ODBC 11 can be 11 or 12
|
||||
// Test with {}
|
||||
switch ($msodbcsqlMaj) {
|
||||
case 17:
|
||||
$value = "{ODBC Driver 17 for SQL Server}";
|
||||
break;
|
||||
case 14:
|
||||
case 13:
|
||||
$value = "{ODBC Driver 13 for SQL Server}";
|
||||
break;
|
||||
case 12:
|
||||
case 11:
|
||||
$value = "{ODBC Driver 11 for SQL Server}";
|
||||
break;
|
||||
default:
|
||||
$value = "invalid value $msodbcsqlMaj";
|
||||
}
|
||||
$connectionOptions = "Driver = $value";
|
||||
connectVerifyOutput($connectionOptions);
|
||||
|
||||
// Test without {}
|
||||
switch ($msodbcsqlMaj) {
|
||||
case 17:
|
||||
$value = "ODBC Driver 17 for SQL Server";
|
||||
break;
|
||||
case 14:
|
||||
case 13:
|
||||
$value = "ODBC Driver 13 for SQL Server";
|
||||
break;
|
||||
case 12:
|
||||
case 11:
|
||||
$value = "ODBC Driver 11 for SQL Server";
|
||||
break;
|
||||
default:
|
||||
$value = "invalid value $msodbcsqlMaj";
|
||||
}
|
||||
|
||||
$connectionOptions = "Driver = $value";
|
||||
connectVerifyOutput($connectionOptions);
|
||||
}
|
||||
|
||||
function testInvalidValues()
|
||||
{
|
||||
$values = array("{SQL Server Native Client 11.0}",
|
||||
"SQL Server Native Client 11.0",
|
||||
"ODBC Driver 00 for SQL Server",
|
||||
123,
|
||||
false);
|
||||
|
||||
foreach ($values as $value) {
|
||||
$connectionOptions = "Driver = $value";
|
||||
$expected = "Invalid value $value was specified for Driver option.";
|
||||
connectVerifyOutput($connectionOptions, $expected);
|
||||
}
|
||||
}
|
||||
|
||||
function testEncryptedWithODBC()
|
||||
{
|
||||
global $msodbcsqlMaj, $server, $uid, $pwd;
|
||||
|
||||
$value = "ODBC Driver 13 for SQL Server";
|
||||
$connectionOptions = "Driver = $value; ColumnEncryption = Enabled;";
|
||||
|
||||
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
|
||||
$expected = "The Always Encrypted feature requires Microsoft ODBC Driver 17 for SQL Server.";
|
||||
} else {
|
||||
$expected = "An invalid keyword 'ColumnEncryption' was specified in the DSN string.";
|
||||
}
|
||||
|
||||
connectVerifyOutput($connectionOptions, $expected);
|
||||
}
|
||||
|
||||
function testWrongODBC()
|
||||
{
|
||||
global $msodbcsqlMaj;
|
||||
|
||||
// TODO: this will change once ODBC 17 is officially released
|
||||
$value = "ODBC Driver 17 for SQL Server";
|
||||
if ($msodbcsqlMaj == 17 || $msodbcsqlMaj < 13) {
|
||||
$value = "ODBC Driver 13 for SQL Server";
|
||||
}
|
||||
$connectionOptions = "Driver = $value;";
|
||||
$expected = "The specified ODBC Driver is not found.";
|
||||
|
||||
connectVerifyOutput($connectionOptions, $expected);
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Done
|
|
@ -1,7 +1,7 @@
|
|||
--TEST--
|
||||
Test new connection keyword ColumnEncryption
|
||||
--SKIPIF--
|
||||
<?php require('skipif.inc'); ?>
|
||||
<?php require('skipif_unix.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsSetup.inc");
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
--TEST--
|
||||
Fetch data from a prepopulated test table given a custom keystore provider
|
||||
--SKIPIF--
|
||||
<?php require('skipif_not_ksp.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
|
||||
try
|
||||
{
|
||||
$conn = connect();
|
||||
echo "Connected successfully with ColumnEncryption enabled and KSP specified.\n";
|
||||
}
|
||||
catch( PDOException $e )
|
||||
{
|
||||
echo "Failed to connect.\n";
|
||||
print_r( $e->getMessage() );
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
$tbname = KSP_TEST_TABLE;
|
||||
$tsql = "SELECT * FROM $tbname";
|
||||
$stmt = $conn->query($tsql);
|
||||
while ($row = $stmt->fetch(PDO::FETCH_NUM))
|
||||
{
|
||||
echo "c1=" . $row[0] . "\tc2=" . $row[1] . "\tc3=" . $row[2] . "\tc4=" . $row[3] . "\n";
|
||||
}
|
||||
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
|
||||
echo "Done\n";
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Connected successfully with ColumnEncryption enabled and KSP specified.
|
||||
c1=1 c2=Sample data 0 for column 2 c3=abc c4=2017-08-10
|
||||
c1=12 c2=Sample data 1 for column 2 c3=bcd c4=2017-08-11
|
||||
c1=23 c2=Sample data 2 for column 2 c3=cde c4=2017-08-12
|
||||
c1=34 c2=Sample data 3 for column 2 c3=def c4=2017-08-13
|
||||
c1=45 c2=Sample data 4 for column 2 c3=efg c4=2017-08-14
|
||||
c1=56 c2=Sample data 5 for column 2 c3=fgh c4=2017-08-15
|
||||
c1=67 c2=Sample data 6 for column 2 c3=ghi c4=2017-08-16
|
||||
c1=78 c2=Sample data 7 for column 2 c3=hij c4=2017-08-17
|
||||
c1=89 c2=Sample data 8 for column 2 c3=ijk c4=2017-08-18
|
||||
c1=100 c2=Sample data 9 for column 2 c3=jkl c4=2017-08-19
|
||||
Done
|
|
@ -1,51 +0,0 @@
|
|||
--TEST--
|
||||
Fetch encrypted data from a prepopulated test table given a custom keystore provider
|
||||
--SKIPIF--
|
||||
<?php require('skipif_not_ksp.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
|
||||
try
|
||||
{
|
||||
$conn = connect();
|
||||
echo "Connected successfully with ColumnEncryption disabled and KSP specified.\n";
|
||||
}
|
||||
catch( PDOException $e )
|
||||
{
|
||||
echo "Failed to connect.\n";
|
||||
print_r( $e->getMessage() );
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
$tbname = KSP_TEST_TABLE;
|
||||
$tsql = "SELECT * FROM $tbname";
|
||||
$stmt = $conn->query($tsql);
|
||||
while ($row = $stmt->fetch(PDO::FETCH_NUM))
|
||||
{
|
||||
echo "c1=" . $row[0];
|
||||
echo "\tc2=" . bin2hex($row[1]);
|
||||
echo "\tc3=" . bin2hex($row[2]);
|
||||
echo "\tc4=" . bin2hex($row[3]);
|
||||
echo "\n" ;
|
||||
}
|
||||
|
||||
unset($stmt);
|
||||
unset($conn);
|
||||
|
||||
echo "Done\n";
|
||||
|
||||
?>
|
||||
--EXPECTREGEX--
|
||||
Connected successfully with ColumnEncryption disabled and KSP specified.
|
||||
c1=1 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
|
||||
c1=12 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
|
||||
c1=23 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
|
||||
c1=34 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
|
||||
c1=45 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
|
||||
c1=56 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
|
||||
c1=67 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
|
||||
c1=78 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
|
||||
c1=89 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
|
||||
c1=100 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
|
||||
Done
|
|
@ -1,102 +0,0 @@
|
|||
--TEST--
|
||||
Connect using a custom keystore provider with some required inputs missing
|
||||
--SKIPIF--
|
||||
<?php require('skipif_not_ksp.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require("MsSetup.inc");
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
|
||||
function kspConnect( $connectionInfo )
|
||||
{
|
||||
global $server, $uid, $pwd;
|
||||
|
||||
try
|
||||
{
|
||||
$conn = new PDO( "sqlsrv:server = $server ; $connectionInfo", $uid, $pwd );
|
||||
echo "Connected successfully with ColumnEncryption enabled and KSP specified.\n";
|
||||
}
|
||||
catch( PDOException $e )
|
||||
{
|
||||
echo "Failed to connect.\n";
|
||||
print_r( $e->getMessage() );
|
||||
echo "\n";
|
||||
}
|
||||
}
|
||||
|
||||
$ksp_path = getKSPpath();
|
||||
$ksp_name = KSP_NAME;
|
||||
$encrypt_key = ENCRYPT_KEY;
|
||||
|
||||
echo("Connecting... with column encryption\n");
|
||||
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
|
||||
kspConnect( $connectionInfo );
|
||||
|
||||
echo("\nConnecting... with an invalid input to CEKeystoreProvider\n");
|
||||
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
|
||||
$connectionInfo .= "CEKeystoreName = 1; ";
|
||||
$connectionInfo .= "CEKeystoreProvider = $ksp_path; ";
|
||||
$connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key; ";
|
||||
kspConnect( $connectionInfo );
|
||||
|
||||
echo("\nConnecting... with an empty path\n");
|
||||
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
|
||||
$connectionInfo .= "CEKeystoreName = $ksp_name; ";
|
||||
$connectionInfo .= "CEKeystoreProvider = ; ";
|
||||
$connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key; ";
|
||||
kspConnect( $connectionInfo );
|
||||
|
||||
echo("\nConnecting... without a path\n");
|
||||
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
|
||||
$connectionInfo .= "CEKeystoreName = $ksp_name; ";
|
||||
$connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key;";
|
||||
kspConnect( $connectionInfo );
|
||||
|
||||
echo("\nConnecting... without a name\n");
|
||||
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
|
||||
$connectionInfo .= "CEKeystoreProvider = $ksp_path; ";
|
||||
$connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key; ";
|
||||
kspConnect( $connectionInfo );
|
||||
|
||||
echo("\nConnecting... without a key\n");
|
||||
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
|
||||
$connectionInfo .= "CEKeystoreProvider = $ksp_path; ";
|
||||
$connectionInfo .= "CEKeystoreName = $ksp_name; ";
|
||||
kspConnect( $connectionInfo );
|
||||
|
||||
echo("\nConnecting... with all required inputs\n");
|
||||
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
|
||||
$connectionInfo .= "CEKeystoreProvider = $ksp_path; ";
|
||||
$connectionInfo .= "CEKeystoreName = $ksp_name; ";
|
||||
$connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key; ";
|
||||
kspConnect( $connectionInfo );
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTREGEX--
|
||||
Connecting\.\.\. with column encryption
|
||||
Connected successfully with ColumnEncryption enabled and KSP specified\.
|
||||
|
||||
Connecting\.\.\. with an invalid input to CEKeystoreProvider
|
||||
Failed to connect.
|
||||
SQLSTATE\[HY024\]: \[Microsoft\]\[ODBC Driver 1[1-9] for SQL Server\]Invalid attribute value
|
||||
|
||||
Connecting\.\.\. with an empty path
|
||||
Failed to connect.
|
||||
SQLSTATE\[IMSSP\]: Invalid value for loading a custom keystore provider\.
|
||||
|
||||
Connecting\.\.\. without a path
|
||||
Failed to connect.
|
||||
SQLSTATE\[IMSSP\]: The path to the custom keystore provider is missing\.
|
||||
|
||||
Connecting\.\.\. without a name
|
||||
Failed to connect.
|
||||
SQLSTATE\[IMSSP\]: The name of the custom keystore provider is missing\.
|
||||
|
||||
Connecting\.\.\. without a key
|
||||
Failed to connect.
|
||||
SQLSTATE\[IMSSP\]: The encryption key for the custom keystore provider is missing\.
|
||||
|
||||
Connecting\.\.\. with all required inputs
|
||||
Connected successfully with ColumnEncryption enabled and KSP specified\.
|
||||
Done
|
|
@ -41,8 +41,7 @@ function cursorScrollFetchRows($conn, $tableName)
|
|||
$stmt = $conn->prepare("SELECT * FROM $tableName ORDER BY c1_int", array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));
|
||||
} else {
|
||||
// ORDER BY is not supported for encrypted columns
|
||||
// scrollable cursor is not supported for encrypted tablee; use client side buffered cursor
|
||||
$stmt = $conn->prepare("SELECT * FROM $tableName", array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_BUFFERED));
|
||||
$stmt = $conn->prepare("SELECT * FROM $tableName", array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));
|
||||
}
|
||||
$stmt->execute();
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ try {
|
|||
--EXPECTREGEX--
|
||||
Array
|
||||
\(
|
||||
\[(DriverDllName|DriverName)\] => (msodbcsql1[1-9].dll|libmsodbcsql-[1-9]{2}.[0-9].so.[0-9].[0-9])
|
||||
\[(DriverDllName|DriverName)\] => (msodbcsql1[1-9].dll|(libmsodbcsql-[0-9]{2}\.[0-9]\.so\.[0-9]\.[0-9]|libmsodbcsql.[0-9]{2}.dylib))
|
||||
\[DriverODBCVer\] => [0-9]{1,2}\.[0-9]{1,2}
|
||||
\[DriverVer\] => [0-9]{1,2}\.[0-9]{1,2}\.[0-9]{4}
|
||||
\[ExtensionVer\] => [0-9].[0-9]\.[0-9](-(RC[0-9]?|preview))?(\.[0-9]+)?(\+[0-9]+)?
|
||||
|
|
|
@ -125,7 +125,7 @@ SQLSTATE\[IMSSP\]: A read-only attribute was designated on the PDO object.
|
|||
Get Result PDO::ATTR_CLIENT_VERSION :
|
||||
array\(4\) {
|
||||
\[\"(DriverDllName|DriverName)\"\]=>
|
||||
string\(15\) \"msodbcsql[0-9]{2}\.dll|string\(24\) \"libmsodbcsql-[0-9]{2}\.[0-9]\.so\.[0-9]\.[0-9]\"
|
||||
(string\([0-9]+\) \"msodbcsql1[1-9].dll\"|string\([0-9]+\) \"(libmsodbcsql-[0-9]{2}\.[0-9]\.so\.[0-9]\.[0-9]|libmsodbcsql.[0-9]{2}.dylib)\")
|
||||
\["DriverODBCVer"\]=>
|
||||
string\(5\) \"[0-9]{1,2}\.[0-9]{1,2}\"
|
||||
\["DriverVer"\]=>
|
||||
|
|
|
@ -3,31 +3,23 @@ Test the fetch() method for different fetch orientations with PDO::ATTR_CURSOR s
|
|||
--ENV--
|
||||
PHPT_EXEC=true
|
||||
--SKIPIF--
|
||||
<?php require('skipif.inc'); ?>
|
||||
<?php require('skipif_mid-refactor.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
|
||||
require_once 'MsCommon.inc';
|
||||
|
||||
function FetchAll($execMode, $fetchMode)
|
||||
{
|
||||
require_once 'MsCommon.inc';
|
||||
require 'MsSetup.inc';
|
||||
|
||||
$testName = "PDO Statement - Fetch Scrollable";
|
||||
StartTest($testName);
|
||||
|
||||
try {
|
||||
$conn1 = connect();
|
||||
|
||||
// Prepare test table
|
||||
$dataCols = "id, val";
|
||||
CreateTableEx($conn1, $tableName, "id int NOT NULL PRIMARY KEY, val VARCHAR(10)", null);
|
||||
InsertRowEx($conn1, $tableName, $dataCols, "1, 'A'", null);
|
||||
InsertRowEx($conn1, $tableName, $dataCols, "2, 'B'", null);
|
||||
InsertRowEx($conn1, $tableName, $dataCols, "3, 'C'", null);
|
||||
$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
|
||||
$stmt1 = $conn1->prepare( "SELECT val FROM $tableName", array( PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL ));
|
||||
$stmt1 = $conn1->prepare( "SELECT val FROM $tableName ORDER BY id", array( PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL ));
|
||||
|
||||
$stmt1->execute();
|
||||
$row = $stmt1->fetch( PDO::FETCH_ASSOC, PDO::FETCH_ORI_LAST );
|
||||
|
@ -158,33 +150,15 @@ function FetchAll($execMode, $fetchMode)
|
|||
}
|
||||
|
||||
// Cleanup
|
||||
DropTable($conn1, $tableName);
|
||||
$stmt1 = null;
|
||||
$conn1 = null;
|
||||
dropTable($conn1, $tableName);
|
||||
unset($stmt1);
|
||||
unset($conn1);
|
||||
|
||||
EndTest($testName);
|
||||
echo "Test 'PDO Statement - Fetch Scrollable' completed successfully.\n";
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Repro
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
function Repro()
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
FetchAll(false, PDO::FETCH_BOTH);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
echo $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
Repro();
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Test "PDO Statement - Fetch Scrollable" completed successfully.
|
||||
Test 'PDO Statement - Fetch Scrollable' completed successfully.
|
|
@ -61,9 +61,7 @@ try {
|
|||
echo "Now selecting....\n";
|
||||
$tsql = "SELECT * FROM [$tableName]";
|
||||
$stmtOptions[PDO::ATTR_CURSOR] = PDO::CURSOR_SCROLL;
|
||||
if (isColEncrypted()) {
|
||||
$stmtOptions[PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE] = PDO::SQLSRV_CURSOR_BUFFERED;
|
||||
}
|
||||
|
||||
$stmt1 = $conn1->prepare($tsql, $stmtOptions);
|
||||
$stmt1->execute();
|
||||
// The row order in the resultset when the column is encrypted (which is dependent on the encrytion key used)
|
||||
|
@ -114,7 +112,6 @@ try {
|
|||
} else {
|
||||
// more and less than operators do not work for encrypted columns
|
||||
$tsql = "SELECT * FROM [$tableName] WHERE NOT ID = :id";
|
||||
unset($stmtOptions[PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE]);
|
||||
$stmt2 = $conn1->prepare($tsql, $stmtOptions);
|
||||
$id = 3;
|
||||
$stmt2->bindParam(':id', $id);
|
||||
|
|
|
@ -1,16 +1,21 @@
|
|||
<?php
|
||||
if (!extension_loaded("pdo") || !extension_loaded('pdo_sqlsrv')) {
|
||||
die("PDO driver cannot be loaded; skipping test.\n");
|
||||
}
|
||||
|
||||
require_once("MsSetup.inc");
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
|
||||
|
||||
$dsn = getDSN($server, null);
|
||||
$conn = new PDO($dsn, $uid, $pwd);
|
||||
if (! $conn) {
|
||||
echo("Error: could not connect during SKIPIF!");
|
||||
} elseif (isColEncrypted() && !isAEQualified($conn)) {
|
||||
die("skip - AE feature not supported in the current environment.");
|
||||
}
|
||||
<?php
|
||||
if (!extension_loaded("pdo") || !extension_loaded('pdo_sqlsrv')) {
|
||||
die("PDO driver cannot be loaded; skipping test.\n");
|
||||
}
|
||||
|
||||
require_once("MsSetup.inc");
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
|
||||
$dsn = getDSN($server, null);
|
||||
$conn = new PDO($dsn, $uid, $pwd);
|
||||
if (! $conn) {
|
||||
echo("Error: could not connect during SKIPIF!");
|
||||
} elseif (isColEncrypted()) {
|
||||
if (!(strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')) {
|
||||
die( "Skip, AE test on windows only." );
|
||||
}
|
||||
|
||||
if (!isAEQualified($conn)) {
|
||||
die("skip - AE feature not supported in the current environment.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
<?php
|
||||
|
||||
if (! extension_loaded( 'pdo' ) || ! extension_loaded( 'pdo_sqlsrv' ))
|
||||
die( "PDO driver cannot be loaded; skipping test.\n" );
|
||||
|
||||
require_once( "MsSetup.inc" );
|
||||
|
||||
if ($keystore != 'ksp')
|
||||
die ( 'skip - this test requires a custom keystore provider.' );
|
||||
|
||||
require_once( "MsCommon.inc" );
|
||||
|
||||
$conn = new PDO( "sqlsrv:server = $server;", $uid, $pwd );
|
||||
if( ! $conn )
|
||||
{
|
||||
echo( "Error: could not connect during SKIPIF!" );
|
||||
}
|
||||
else if(! IsAEQualified($conn))
|
||||
{
|
||||
die( "skip - AE feature not supported in the current environment." );
|
||||
}
|
||||
?>
|
|
@ -1,6 +1,3 @@
|
|||
USE $(dbname)
|
||||
GO
|
||||
|
||||
/* DROP Column Encryption Key first, Column Master Key cannot be dropped until no encryption depends on it */
|
||||
IF EXISTS (SELECT * FROM sys.column_encryption_keys WHERE [name] LIKE '%AEColumnKey%')
|
||||
|
||||
|
|
|
@ -45,13 +45,14 @@ def executeBulkCopy(conn_options, dbname, tblname, datafile):
|
|||
inst_command = redirect_string.format(dbname, tblname, datafile) + conn_options
|
||||
executeCommmand(inst_command)
|
||||
|
||||
def setupAE( conn_options, dbname, azure ):
|
||||
if (platform.system() == 'Windows' and azure.lower() == 'no'):
|
||||
def setupAE(conn_options, dbname):
|
||||
if (platform.system() == 'Windows'):
|
||||
# import self signed certificate
|
||||
inst_command = "certutil -user -p '' -importPFX My PHPcert.pfx NoRoot"
|
||||
executeCommmand(inst_command)
|
||||
# create Column Master Key and Column Encryption Key
|
||||
executeSQLscript('ae_keys.sql', conn_options, dbname)
|
||||
script_command = 'sqlcmd ' + conn_options + ' -i ae_keys.sql -d ' + dbname
|
||||
executeCommmand(script_command)
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
|
@ -84,7 +85,7 @@ if __name__ == '__main__':
|
|||
# populate these tables
|
||||
populateTables(conn_options, args.DBNAME)
|
||||
# setup AE (certificate, column master key and column encryption key)
|
||||
setupAE(conn_options, args.DBNAME, args.AZURE)
|
||||
setupAE(conn_options, args.DBNAME)
|
||||
|
||||
os.chdir(current_working_dir)
|
||||
|
||||
|
|
|
@ -23,8 +23,6 @@ function runTest($fieldType)
|
|||
sqlsrv_fetch($stmt)
|
||||
|| die(print_r(sqlsrv_errors(), true));
|
||||
|
||||
// Do not support getting stream if AE enabled, so expect
|
||||
// it to fail with the correct error message
|
||||
$stream = sqlsrv_get_field($stmt, 0, SQLSRV_PHPTYPE_STREAM("char"));
|
||||
if ($stream) {
|
||||
stream_filter_append($originalStream, "convert.base64-encode")
|
||||
|
@ -37,11 +35,7 @@ function runTest($fieldType)
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if (AE\isColEncrypted()) {
|
||||
verifyError(sqlsrv_errors()[0], 'IMSSP', 'Connection with Column Encryption enabled does not support fetching stream. Please fetch the data as a string.');
|
||||
} else {
|
||||
fatalError('Fetching data stream failed!');
|
||||
}
|
||||
fatalError('Fetching data stream failed!');
|
||||
}
|
||||
dropTable($conn, $params['tableName']);
|
||||
|
||||
|
|
|
@ -1,69 +1,63 @@
|
|||
--TEST--
|
||||
scrollable results with no rows.
|
||||
--DESCRIPTION--
|
||||
this test is very similar to test_scrollable.phpt... might consider removing this test as a duplicate
|
||||
--SKIPIF--
|
||||
<?php require('skipif_versions_old.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
sqlsrv_configure('WarningsReturnAsErrors', 0);
|
||||
sqlsrv_configure('LogSeverity', SQLSRV_LOG_SEVERITY_ALL);
|
||||
|
||||
require_once('MsCommon.inc');
|
||||
|
||||
$conn = AE\connect();
|
||||
$tableName = 'ScrollTest';
|
||||
|
||||
$columns = array(new AE\ColumnMeta('int', 'id'),
|
||||
new AE\ColumnMeta('char(10)', 'value'));
|
||||
$stmt = AE\createTable($conn, $tableName, $columns);
|
||||
if (!$stmt) {
|
||||
fatalError("Failed to create table for the test]n");
|
||||
}
|
||||
sqlsrv_free_stmt($stmt);
|
||||
|
||||
// Always Encrypted feature only supports SQLSRV_CURSOR_FORWARD or
|
||||
// SQLSRV_CURSOR_CLIENT_BUFFERED
|
||||
$query = "SELECT * FROM $tableName";
|
||||
if (AE\isColEncrypted()) {
|
||||
$options = array('Scrollable' => SQLSRV_CURSOR_FORWARD);
|
||||
} else {
|
||||
$options = array('Scrollable' => 'static');
|
||||
}
|
||||
|
||||
$stmt = sqlsrv_query($conn, $query, array(), $options);
|
||||
$rows = sqlsrv_has_rows($stmt);
|
||||
if ($rows != false) {
|
||||
fatalError("Should be no rows present");
|
||||
};
|
||||
|
||||
if ($stmt === false) {
|
||||
die(print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
$row = sqlsrv_fetch_array($stmt);
|
||||
print_r($row);
|
||||
if ($row === false) {
|
||||
print_r(sqlsrv_errors(), true);
|
||||
}
|
||||
|
||||
$stmt = sqlsrv_query($conn, $query);
|
||||
$rows = sqlsrv_has_rows($stmt);
|
||||
if ($rows != false) {
|
||||
fatalError("Should be no rows present");
|
||||
};
|
||||
|
||||
if ($stmt === false) {
|
||||
die(print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
$row = sqlsrv_fetch_array($stmt);
|
||||
print_r($row);
|
||||
if ($row === false) {
|
||||
print_r(sqlsrv_errors(), true);
|
||||
}
|
||||
|
||||
dropTable($conn, $tableName);
|
||||
echo "Test succeeded.\n";
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Test succeeded.
|
||||
--TEST--
|
||||
scrollable results with no rows.
|
||||
--DESCRIPTION--
|
||||
this test is very similar to test_scrollable.phpt... might consider removing this test as a duplicate
|
||||
--SKIPIF--
|
||||
<?php require('skipif_versions_old.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
sqlsrv_configure('WarningsReturnAsErrors', 0);
|
||||
sqlsrv_configure('LogSeverity', SQLSRV_LOG_SEVERITY_ALL);
|
||||
|
||||
require_once('MsCommon.inc');
|
||||
|
||||
$conn = AE\connect();
|
||||
$tableName = 'ScrollTest';
|
||||
|
||||
$columns = array(new AE\ColumnMeta('int', 'id'),
|
||||
new AE\ColumnMeta('char(10)', 'value'));
|
||||
$stmt = AE\createTable($conn, $tableName, $columns);
|
||||
if (!$stmt) {
|
||||
fatalError("Failed to create table for the test]n");
|
||||
}
|
||||
sqlsrv_free_stmt($stmt);
|
||||
|
||||
$query = "SELECT * FROM $tableName";
|
||||
$options = array('Scrollable' => 'static');
|
||||
|
||||
$stmt = sqlsrv_query($conn, $query, array(), $options);
|
||||
$rows = sqlsrv_has_rows($stmt);
|
||||
if ($rows != false) {
|
||||
fatalError("Should be no rows present");
|
||||
};
|
||||
|
||||
if ($stmt === false) {
|
||||
die(print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
$row = sqlsrv_fetch_array($stmt);
|
||||
print_r($row);
|
||||
if ($row === false) {
|
||||
print_r(sqlsrv_errors(), true);
|
||||
}
|
||||
|
||||
$stmt = sqlsrv_query($conn, $query);
|
||||
$rows = sqlsrv_has_rows($stmt);
|
||||
if ($rows != false) {
|
||||
fatalError("Should be no rows present");
|
||||
};
|
||||
|
||||
if ($stmt === false) {
|
||||
die(print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
$row = sqlsrv_fetch_array($stmt);
|
||||
print_r($row);
|
||||
if ($row === false) {
|
||||
print_r(sqlsrv_errors(), true);
|
||||
}
|
||||
|
||||
dropTable($conn, $tableName);
|
||||
echo "Test succeeded.\n";
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Test succeeded.
|
||||
|
|
|
@ -78,8 +78,16 @@ if ($t === false) {
|
|||
die(print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
if ($t != "So?e sä???? ?SCII-te×t") {
|
||||
die("varchar(100) doesn't match So?e sä???? ?SCII-te×t");
|
||||
// If connected with AE, $t may be different in Windows and other platforms
|
||||
// this is a workaround for now -- to make sure there are some '?' in $t
|
||||
if (!AE\isColEncrypted() && $t !== "So?e sä???? ?SCII-te×t") {
|
||||
die("varchar(100) \'$t\' doesn't match So?e sä???? ?SCII-te×t");
|
||||
} else {
|
||||
$arr = explode('?', $t);
|
||||
if (count($arr) == 1) {
|
||||
// this means there is no question mark in $t
|
||||
die("varchar(100) value \'$t\' is unexpected");
|
||||
}
|
||||
}
|
||||
|
||||
$t = sqlsrv_get_field($s, 1, SQLSRV_PHPTYPE_STRING('utf-8'));
|
||||
|
@ -87,7 +95,7 @@ if ($t === false) {
|
|||
die(print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
if ($t != $utf8) {
|
||||
if ($t !== $utf8) {
|
||||
die("nvarchar(100) doesn't match the inserted UTF-8 text.");
|
||||
}
|
||||
|
||||
|
@ -96,7 +104,7 @@ if ($t === false) {
|
|||
die(print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
if ($t != $utf8) {
|
||||
if ($t !== $utf8) {
|
||||
die("nvarchar(max) doesn't match the inserted UTF-8 text.");
|
||||
}
|
||||
|
||||
|
@ -129,7 +137,7 @@ if ($s === false) {
|
|||
die(print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
if ($t != $utf8) {
|
||||
if ($t !== $utf8) {
|
||||
die("Incorrect results from Utf8OutProc\n");
|
||||
}
|
||||
|
||||
|
@ -148,7 +156,7 @@ if ($s === false) {
|
|||
// retrieve all the results
|
||||
while (sqlsrv_next_result($s));
|
||||
|
||||
if ($t != $utf8) {
|
||||
if ($t !== $utf8) {
|
||||
die("Incorrect results from Utf8OutWithResultsetProc\n");
|
||||
}
|
||||
|
||||
|
@ -169,7 +177,7 @@ if ($s === false) {
|
|||
die(print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
if ($t != $utf8) {
|
||||
if ($t !== $utf8) {
|
||||
die("Incorrect results from Utf8InOutProc 1\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -38,11 +38,7 @@ inserting and retrieving UTF-8 text.
|
|||
|
||||
$u = sqlsrv_get_field($s, 1, SQLSRV_PHPTYPE_STREAM('utf-8'));
|
||||
if ($u === false) {
|
||||
if (AE\isColEncrypted()) {
|
||||
verifyError(sqlsrv_errors()[0], 'IMSSP', 'Connection with Column Encryption enabled does not support fetching stream. Please fetch the data as a string.');
|
||||
} else {
|
||||
die(print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
die(print_r(sqlsrv_errors(), true));
|
||||
} else {
|
||||
$utf8_2 = fread($u, 10000);
|
||||
if ($utf8 != $utf8_2) {
|
||||
|
|
|
@ -1,113 +1,170 @@
|
|||
<?php
|
||||
// exact numerics
|
||||
$bigint_params = array( 2147483648, -922337203685479936, 922337203685479936, -2147583649, 461168601735364608, -461168601735364608 );
|
||||
$int_params = array( 32768, -2147483647, 2147483647, -32769, 1073725440, -1073725440 );
|
||||
$smallint_params = array( 256, -32767, 32767, -1, 16256, -16256 );
|
||||
$tinyint_params = array( 128, 0, 255, 96, 64, 162 );
|
||||
$decimal_params = array( 21474.83648, -9223372036854.80000, 9223372036854.80000, -21475.83649, -4611686017353.64608, -4611686017353.64608 );
|
||||
$numeric_params = array( 0.32768, -21474.83647, 21474.83647, -0.32769, 10737.25440, -10737.25440 );
|
||||
$money_params = array( 214748.3648, -92233720368548.0000, 92233720368548.0000, -214758.3649, 46116860173536.608, -46116860173536.608 );
|
||||
$smallmoney_params = array( 0, -214748.3647, 214748.3647, 161061.2736, 107374.1824, -107374.1824 );
|
||||
$bit_params = array( 0, 1, 0, 1, 0, 1 );
|
||||
|
||||
// approximate numerics
|
||||
$float_params = array( 21474.83648, -9223372036.8548, 9223372036.8548, -21475, 4611686017, -4611686017 );
|
||||
$real_params = array( 0, -2147.483, 2147.483, 1610, 1073, -1073 );
|
||||
|
||||
// date and time
|
||||
$date_params = array( '1900-01-01', '0001-01-01', '9999-12-31', '5000-07-15', '2500-04-08', '7500-10-23' );
|
||||
$datetime2_params = array( '1900-01-01 00:00:00', '0001-01-01 00:00:00', '9999-12-31 23:59:59.123456', '5000-07-15 12:30:30.5555', '2500-04-08 06:15:15.33', '7500-10-23 18:45:45.888888' );
|
||||
$datetime_params = array( '1900-01-01 00:00:00', '1753-01-01 00:00:00', '9999-12-31 23:59:59.997', '5000-07-15 12:30:30.5', '2500-04-08 06:15:15.33', '7500-10-23 18:45:45.888' );
|
||||
$datetimeoffset_params = array( '1900-01-01 00:00:00 +01:00', '0001-01-01 00:00:00 -14:00', '9999-12-31 23:59:59.123456+14:00', '5000-07-15 12:30:30.55 -03:00', '2500-04-08 06:15:15.3333 -07:00', '7500-10-23 18:45:45.888888 +07:00' );
|
||||
$smalldatetime_params = array( '1900-01-01 00:00:00', '1900-01-01 00:00:00', '2079-06-05 23:59:00', '1990-07-15 12:30:00', '1945-04-08 06:15:00', '2000-10-23 18:45:00' );
|
||||
$time_params = array( '00:00:00', '00:00:00.0000000', '23:59:59.123456', '12:30:30.5555', '06:15:15.33', '18:45:45.888888' );
|
||||
|
||||
// character strings
|
||||
$char_params = array( 'Fixed', '-leng', 'th, n', 'on-Un', 'icode', 'strin' );
|
||||
$varchar_params = array( 'This large row size can cause errors (such as error 512) during some normal operations, such as a clustered index key update, or sorts of the full column set, which users cannot anticipate until performing an operation.',
|
||||
'Use varchar(max) when the sizes of the column data entries vary considerably, and the size might exceed 8,000 bytes.',
|
||||
'Each non-null varchar(max) or nvarchar(max) column requires 24 bytes of additional fixed allocation which counts against the 8,060 byte row limit during a sort operation.',
|
||||
'This can create an implicit limit to the number of non-null varchar(max) or nvarchar(max) columns that can be created in a table.',
|
||||
'No special error is provided when the table is created (beyond the usual warning that the maximum row size exceeds the allowed maximum of 8060 bytes) or at the time of data insertion.',
|
||||
'This large row size can cause errors (such as error 512) during some normal operations, such as a clustered index key update, or sorts of the full column set, which users cannot anticipate until performing an operation.' );
|
||||
|
||||
// unicode character strings
|
||||
$nchar_params = array( 'Fixed', '-leng', 'th Un', 'icode', 'strin', 'g dat' );
|
||||
$nvarchar_params = array( 'max indicates that the maximum storage size is 2^31-1 bytes (2 GB).',
|
||||
'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).',
|
||||
'Otherwise, the implicit conversion will result in a Unicode large-value (max).',
|
||||
'Each non-null varchar(max) or nvarchar(max) column requires 24 bytes of additional fixed allocation which counts against the 8,060 byte row limit during a sort operation.',
|
||||
'This can create an implicit limit to the number of non-null varchar(max) or nvarchar(max) columns that can be created in a table.',
|
||||
'No special error is provided when the table is created (beyond the usual warning that the maximum row size exceeds the allowed maximum of 8060 bytes) or at the time of data insertion.' );
|
||||
|
||||
// binary strings
|
||||
$binary_params = array( 'Fixed', '-leng', 'th, n', 'on-Un', 'icode', 'strin' );
|
||||
$varbinary_params = array( 'Variable-length, non-', 'Unicode string data. n', 'defines the string length', 'and can be a value from 1', 'through 8,000.', 'The storage size is the' );
|
||||
$varbinarymax_params = array( 'max indicates that the maximum storage size is 2^31-1 bytes (2 GB)',
|
||||
'Use varchar(max) when the sizes of the column data entries vary considerably, and the size might exceed 8,000 bytes.',
|
||||
'Each non-null varchar(max) or nvarchar(max) column requires 24 bytes of additional fixed allocation which counts against the 8,060 byte row limit during a sort operation.',
|
||||
'This can create an implicit limit to the number of non-null varchar(max) or nvarchar(max) columns that can be created in a table.',
|
||||
'No special error is provided when the table is created (beyond the usual warning that the maximum row size exceeds the allowed maximum of 8060 bytes) or at the time of data insertion.',
|
||||
'This large row size can cause errors (such as error 512) during some normal operations, such as a clustered index key update, or sorts of the full column set, which users cannot anticipate until performing an operation.' );
|
||||
|
||||
// Array containing all SQLSRV_SQLTYPE_ types to pass into a bind param prepare statement
|
||||
|
||||
$sqlTypes = array(
|
||||
'SQLSRV_SQLTYPE_BIGINT',
|
||||
'SQLSRV_SQLTYPE_BINARY',
|
||||
'SQLSRV_SQLTYPE_BIT',
|
||||
'SQLSRV_SQLTYPE_CHAR',
|
||||
'SQLSRV_SQLTYPE_DATE',
|
||||
'SQLSRV_SQLTYPE_DATETIME',
|
||||
'SQLSRV_SQLTYPE_DATETIME2',
|
||||
'SQLSRV_SQLTYPE_DATETIMEOFFSET',
|
||||
'SQLSRV_SQLTYPE_DECIMAL',
|
||||
'SQLSRV_SQLTYPE_FLOAT',
|
||||
'SQLSRV_SQLTYPE_IMAGE',
|
||||
'SQLSRV_SQLTYPE_INT',
|
||||
'SQLSRV_SQLTYPE_MONEY',
|
||||
'SQLSRV_SQLTYPE_NCHAR',
|
||||
'SQLSRV_SQLTYPE_NUMERIC',
|
||||
'SQLSRV_SQLTYPE_NVARCHAR',
|
||||
'SQLSRV_SQLTYPE_NTEXT',
|
||||
'SQLSRV_SQLTYPE_REAL',
|
||||
'SQLSRV_SQLTYPE_SMALLDATETIME',
|
||||
'SQLSRV_SQLTYPE_SMALLINT',
|
||||
'SQLSRV_SQLTYPE_SMALLMONEY',
|
||||
'SQLSRV_SQLTYPE_TEXT',
|
||||
'SQLSRV_SQLTYPE_TIME',
|
||||
'SQLSRV_SQLTYPE_TIMESTAMP',
|
||||
'SQLSRV_SQLTYPE_TINYINT',
|
||||
'SQLSRV_SQLTYPE_UNIQUEIDENTIFIER',
|
||||
'SQLSRV_SQLTYPE_VARBINARY',
|
||||
'SQLSRV_SQLTYPE_VARCHAR',
|
||||
'SQLSRV_SQLTYPE_XML'
|
||||
);
|
||||
|
||||
// Checks if the current error is the incompatible types error
|
||||
// if so, state which sql type is incompatible with which data type
|
||||
function is_incompatible_types_error( $dataType, $sqlType )
|
||||
{
|
||||
$errors = sqlsrv_errors();
|
||||
foreach ( $errors as $error )
|
||||
{
|
||||
// 22018 is the SQLSTATE for the operand crash error for incompatible types
|
||||
if ( $error['SQLSTATE'] == 22018 )
|
||||
{
|
||||
echo "Encrypted $sqlType is incompatible with encrypted $dataType\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function get_default_size_prec( $sqlType )
|
||||
{
|
||||
if ( $sqlType == 'SQLSRV_SQLTYPE_DECIMAL' )
|
||||
$sqlType .= "(18, 5)";
|
||||
elseif ( $sqlType == 'SQLSRV_SQLTYPE_NUMERIC' )
|
||||
$sqlType .= "(10, 5)";
|
||||
elseif ( $sqlType == 'SQLSRV_SQLTYPE_CHAR' || $sqlType == 'SQLSRV_SQLTYPE_NCHAR' )
|
||||
$sqlType .= "(5)";
|
||||
return $sqlType;
|
||||
}
|
||||
|
||||
?>
|
||||
<?php
|
||||
// exact numerics
|
||||
$bigint_params = array( 2147483648, -922337203685479936, 922337203685479936, -2147583649, 461168601735364608, -461168601735364608 );
|
||||
$int_params = array( 32768, -2147483647, 2147483647, -32769, 1073725440, -1073725440 );
|
||||
$smallint_params = array( 256, -32767, 32767, -1, 16256, -16256 );
|
||||
$tinyint_params = array( 128, 0, 255, 96, 64, 162 );
|
||||
$decimal_params = array( 21474.83648, -9223372036854.80000, 9223372036854.80000, -21475.83649, -4611686017353.64608, -4611686017353.64608 );
|
||||
$numeric_params = array( 0.32768, -21474.83647, 21474.83647, -0.32769, 10737.25440, -10737.25440 );
|
||||
$money_params = array( 214748.3648, -92233720368548.0000, 92233720368548.0000, -214758.3649, 46116860173536.608, -46116860173536.608 );
|
||||
$smallmoney_params = array( 0, -214748.3647, 214748.3647, 161061.2736, 107374.1824, -107374.1824 );
|
||||
$bit_params = array( 0, 1, 0, 1, 0, 1 );
|
||||
// approximate numerics
|
||||
$float_params = array( 21474.83648, -9223372036.8548, 9223372036.8548, -21475, 4611686017, -4611686017 );
|
||||
$real_params = array( 0, -2147.483, 2147.483, 1610, 1073, -1073 );
|
||||
// date and time
|
||||
$date_params = array( '1900-01-01', '0001-01-01', '9999-12-31', '5000-07-15', '2500-04-08', '7500-10-23' );
|
||||
$datetime2_params = array( '1900-01-01 00:00:00', '0001-01-01 00:00:00', '9999-12-31 23:59:59.123456', '5000-07-15 12:30:30.5555', '2500-04-08 06:15:15.33', '7500-10-23 18:45:45.888888' );
|
||||
$datetime_params = array( '1900-01-01 00:00:00', '1753-01-01 00:00:00', '9999-12-31 23:59:59.997', '5000-07-15 12:30:30.5', '2500-04-08 06:15:15.33', '7500-10-23 18:45:45.888' );
|
||||
$datetimeoffset_params = array( '1900-01-01 00:00:00 +01:00', '0001-01-01 00:00:00 -14:00', '9999-12-31 23:59:59.123456+14:00', '5000-07-15 12:30:30.55 -03:00', '2500-04-08 06:15:15.3333 -07:00', '7500-10-23 18:45:45.888888 +07:00' );
|
||||
$smalldatetime_params = array( '1900-01-01 00:00:00', '1900-01-01 00:00:00', '2079-06-05 23:59:00', '1990-07-15 12:30:00', '1945-04-08 06:15:00', '2000-10-23 18:45:00' );
|
||||
$time_params = array( '00:00:00', '00:00:00.0000000', '23:59:59.123456', '12:30:30.5555', '06:15:15.33', '18:45:45.888888' );
|
||||
// character strings
|
||||
$char_params = array( 'Fixed', '-leng', 'th, n', 'on-Un', 'icode', 'strin' );
|
||||
$varchar_params = array( 'This large row size can cause errors (such as error 512) during some normal operations, such as a clustered index key update, or sorts of the full column set, which users cannot anticipate until performing an operation.',
|
||||
'Use varchar(max) when the sizes of the column data entries vary considerably, and the size might exceed 8,000 bytes.',
|
||||
'Each non-null varchar(max) or nvarchar(max) column requires 24 bytes of additional fixed allocation which counts against the 8,060 byte row limit during a sort operation.',
|
||||
'This can create an implicit limit to the number of non-null varchar(max) or nvarchar(max) columns that can be created in a table.',
|
||||
'No special error is provided when the table is created (beyond the usual warning that the maximum row size exceeds the allowed maximum of 8060 bytes) or at the time of data insertion.',
|
||||
'This large row size can cause errors (such as error 512) during some normal operations, such as a clustered index key update, or sorts of the full column set, which users cannot anticipate until performing an operation.' );
|
||||
|
||||
// unicode character strings
|
||||
$nchar_params = array( 'Fixed', '-leng', 'th Un', 'icode', 'strin', 'g dat' );
|
||||
$nvarchar_params = array( 'max indicates that the maximum storage size is 2^31-1 bytes (2 GB).',
|
||||
'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).',
|
||||
'Otherwise, the implicit conversion will result in a Unicode large-value (max).',
|
||||
'Each non-null varchar(max) or nvarchar(max) column requires 24 bytes of additional fixed allocation which counts against the 8,060 byte row limit during a sort operation.',
|
||||
'This can create an implicit limit to the number of non-null varchar(max) or nvarchar(max) columns that can be created in a table.',
|
||||
'No special error is provided when the table is created (beyond the usual warning that the maximum row size exceeds the allowed maximum of 8060 bytes) or at the time of data insertion.' );
|
||||
|
||||
// binary strings
|
||||
$binary_params = array( 'Fixed', '-leng', 'th, n', 'on-Un', 'icode', 'strin' );
|
||||
$varbinary_params = array( 'Variable-length, non-', 'Unicode string data. n', 'defines the string length', 'and can be a value from 1', 'through 8,000.', 'The storage size is the' );
|
||||
$varbinarymax_params = array( 'max indicates that the maximum storage size is 2^31-1 bytes (2 GB)',
|
||||
'Use varchar(max) when the sizes of the column data entries vary considerably, and the size might exceed 8,000 bytes.',
|
||||
'Each non-null varchar(max) or nvarchar(max) column requires 24 bytes of additional fixed allocation which counts against the 8,060 byte row limit during a sort operation.',
|
||||
'This can create an implicit limit to the number of non-null varchar(max) or nvarchar(max) columns that can be created in a table.',
|
||||
'No special error is provided when the table is created (beyond the usual warning that the maximum row size exceeds the allowed maximum of 8060 bytes) or at the time of data insertion.',
|
||||
'This large row size can cause errors (such as error 512) during some normal operations, such as a clustered index key update, or sorts of the full column set, which users cannot anticipate until performing an operation.' );
|
||||
// Array containing all SQLSRV_SQLTYPE_ types to pass into a bind param prepare statement
|
||||
|
||||
$sqlTypes = array(
|
||||
'SQLSRV_SQLTYPE_BIGINT',
|
||||
'SQLSRV_SQLTYPE_BINARY',
|
||||
'SQLSRV_SQLTYPE_BIT',
|
||||
'SQLSRV_SQLTYPE_CHAR',
|
||||
'SQLSRV_SQLTYPE_DATE',
|
||||
'SQLSRV_SQLTYPE_DATETIME',
|
||||
'SQLSRV_SQLTYPE_DATETIME2',
|
||||
'SQLSRV_SQLTYPE_DATETIMEOFFSET',
|
||||
'SQLSRV_SQLTYPE_DECIMAL',
|
||||
'SQLSRV_SQLTYPE_FLOAT',
|
||||
'SQLSRV_SQLTYPE_IMAGE',
|
||||
'SQLSRV_SQLTYPE_INT',
|
||||
'SQLSRV_SQLTYPE_MONEY',
|
||||
'SQLSRV_SQLTYPE_NCHAR',
|
||||
'SQLSRV_SQLTYPE_NUMERIC',
|
||||
'SQLSRV_SQLTYPE_NVARCHAR',
|
||||
'SQLSRV_SQLTYPE_NTEXT',
|
||||
'SQLSRV_SQLTYPE_REAL',
|
||||
'SQLSRV_SQLTYPE_SMALLDATETIME',
|
||||
'SQLSRV_SQLTYPE_SMALLINT',
|
||||
'SQLSRV_SQLTYPE_SMALLMONEY',
|
||||
'SQLSRV_SQLTYPE_TEXT',
|
||||
'SQLSRV_SQLTYPE_TIME',
|
||||
'SQLSRV_SQLTYPE_TIMESTAMP',
|
||||
'SQLSRV_SQLTYPE_TINYINT',
|
||||
'SQLSRV_SQLTYPE_UNIQUEIDENTIFIER',
|
||||
'SQLSRV_SQLTYPE_VARBINARY',
|
||||
'SQLSRV_SQLTYPE_VARCHAR',
|
||||
'SQLSRV_SQLTYPE_XML'
|
||||
);
|
||||
// Checks if the current error is the incompatible types error
|
||||
// if so, state which sql type is incompatible with which data type
|
||||
function is_incompatible_types_error( $dataType, $sqlType )
|
||||
{
|
||||
$errors = sqlsrv_errors();
|
||||
foreach ( $errors as $error )
|
||||
{
|
||||
// 22018 is the SQLSTATE for the operand crash error for incompatible types
|
||||
if ( $error['SQLSTATE'] == 22018 )
|
||||
{
|
||||
echo "Encrypted $sqlType is incompatible with encrypted $dataType\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
function get_default_size_prec( $sqlType )
|
||||
{
|
||||
if ( $sqlType == 'SQLSRV_SQLTYPE_DECIMAL' )
|
||||
$sqlType .= "(18, 5)";
|
||||
elseif ( $sqlType == 'SQLSRV_SQLTYPE_NUMERIC' )
|
||||
$sqlType .= "(10, 5)";
|
||||
elseif ( $sqlType == 'SQLSRV_SQLTYPE_CHAR' || $sqlType == 'SQLSRV_SQLTYPE_NCHAR' )
|
||||
$sqlType .= "(5)";
|
||||
return $sqlType;
|
||||
}
|
||||
|
||||
// get sqlType constant value from string
|
||||
function get_sqlType_constant( $sqlType )
|
||||
{
|
||||
switch ( $sqlType ) {
|
||||
case 'SQLSRV_SQLTYPE_BIGINT':
|
||||
case 'SQLSRV_SQLTYPE_BINARY':
|
||||
case 'SQLSRV_SQLTYPE_BIT':
|
||||
case 'SQLSRV_SQLTYPE_DATE':
|
||||
case 'SQLSRV_SQLTYPE_DATETIME':
|
||||
case 'SQLSRV_SQLTYPE_DATETIME2':
|
||||
case 'SQLSRV_SQLTYPE_DATETIMEOFFSET':
|
||||
case 'SQLSRV_SQLTYPE_FLOAT':
|
||||
case 'SQLSRV_SQLTYPE_IMAGE':
|
||||
case 'SQLSRV_SQLTYPE_INT':
|
||||
case 'SQLSRV_SQLTYPE_MONEY':
|
||||
case 'SQLSRV_SQLTYPE_NVARCHAR':
|
||||
case 'SQLSRV_SQLTYPE_NTEXT':
|
||||
case 'SQLSRV_SQLTYPE_REAL':
|
||||
case 'SQLSRV_SQLTYPE_SMALLDATETIME':
|
||||
case 'SQLSRV_SQLTYPE_SMALLINT':
|
||||
case 'SQLSRV_SQLTYPE_SMALLMONEY':
|
||||
case 'SQLSRV_SQLTYPE_TEXT':
|
||||
case 'SQLSRV_SQLTYPE_TIME':
|
||||
case 'SQLSRV_SQLTYPE_TIMESTAMP':
|
||||
case 'SQLSRV_SQLTYPE_TINYINT':
|
||||
case 'SQLSRV_SQLTYPE_UNIQUEIDENTIFIER':
|
||||
case 'SQLSRV_SQLTYPE_VARBINARY':
|
||||
case 'SQLSRV_SQLTYPE_VARCHAR':
|
||||
case 'SQLSRV_SQLTYPE_XML':
|
||||
return constant( $sqlType );
|
||||
break;
|
||||
case 'SQLSRV_SQLTYPE_CHAR':
|
||||
// our tests always use precision 5 for SQLSRV_SQLTYPE_CHAR
|
||||
return SQLSRV_SQLTYPE_CHAR(5);
|
||||
break;
|
||||
case 'SQLSRV_SQLTYPE_DECIMAL':
|
||||
// our tests always use precision 18 scale 5 for SQLSRV_SQLTYPE_DECIMAL
|
||||
return SQLSRV_SQLTYPE_DECIMAL(18, 5);
|
||||
break;
|
||||
case 'SQLSRV_SQLTYPE_NCHAR':
|
||||
// our tests always use precision 5 for SQLSRV_SQLTYPE_NCHAR
|
||||
return SQLSRV_SQLTYPE_NCHAR(5);
|
||||
break;
|
||||
case 'SQLSRV_SQLTYPE_NUMERIC':
|
||||
// our tests always use precision 10 scale 5 for SQLSRV_SQLTYPE_NUMERIC
|
||||
return SQLSRV_SQLTYPE_NUMERIC(10, 5);
|
||||
break;
|
||||
default:
|
||||
die( "get_sqlType_constant: Invalid SQL Type $sqlType\n" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function isDateTimeType( $sqlType )
|
||||
{
|
||||
return ($sqlType == 'SQLSRV_SQLTYPE_DATE' ||
|
||||
$sqlType == 'SQLSRV_SQLTYPE_DATETIME' ||
|
||||
$sqlType == 'SQLSRV_SQLTYPE_DATETIME2' ||
|
||||
$sqlType == 'SQLSRV_SQLTYPE_DATETIMEOFFSET' ||
|
||||
$sqlType == 'SQLSRV_SQLTYPE_SMALLDATETIME' ||
|
||||
$sqlType == 'SQLSRV_SQLTYPE_TIME');
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
|
@ -84,18 +84,6 @@ function isDaasMode()
|
|||
return ($daasMode ? true : false);
|
||||
}
|
||||
|
||||
// function isAEQualified($conn)
|
||||
// {
|
||||
// $msodbcsql_ver = sqlsrv_client_info($conn)['DriverVer'];
|
||||
// $server_ver = sqlsrv_server_info($conn)['SQLServerVersion'];
|
||||
// $msodbcsql_maj = explode(".", $msodbcsql_ver)[0];
|
||||
// $msodbcsql_min = explode(".", $msodbcsql_ver)[1];
|
||||
// if ($msodbcsql_maj < 17 || explode('.', $server_ver)[0] < 13) {
|
||||
// return false;
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
|
||||
function startTest($testName)
|
||||
{
|
||||
if (traceMode()) {
|
||||
|
@ -454,11 +442,36 @@ function handleErrors()
|
|||
}
|
||||
}
|
||||
|
||||
function setUSAnsiLocale()
|
||||
{
|
||||
if (!isWindows()) {
|
||||
// macOS the locale names are different in Linux or macOS
|
||||
$locale = strtoupper(PHP_OS) === 'LINUX' ? "en_US.ISO-8859-1" : "en_US.ISO8859-1";
|
||||
|
||||
setlocale(LC_ALL, $locale);
|
||||
}
|
||||
}
|
||||
|
||||
function resetLocaleToDefault()
|
||||
{
|
||||
// Like setUSAnsiLocale() above, this method is only needed in non-Windows environment
|
||||
if (!isWindows()) {
|
||||
setlocale(LC_ALL, null);
|
||||
}
|
||||
}
|
||||
|
||||
// non-UTF8 locale support in ODBC 17 and above only
|
||||
// if AE enabled, only supported in Windows (AE limitations)
|
||||
function isLocaleSupported()
|
||||
{
|
||||
if (isWindows()) {
|
||||
return true;
|
||||
}
|
||||
if (AE\isColEncrypted()) {
|
||||
return false;
|
||||
}
|
||||
// now check ODBC version
|
||||
$conn = AE\connect();
|
||||
|
||||
$msodbcsql_ver = sqlsrv_client_info($conn)['DriverVer'];
|
||||
if (explode(".", $msodbcsql_ver)[0] < 17) {
|
||||
return false;
|
||||
|
|
|
@ -22,10 +22,6 @@ const INSERT_PREPARE = 2;
|
|||
const INSERT_QUERY_PARAMS = 3;
|
||||
const INSERT_PREPARE_PARAMS = 4;
|
||||
|
||||
const KSP_NAME = 'MyCustomKSPName';
|
||||
const ENCRYPT_KEY = 'LPKCWVD07N3RG98J0MBLG4H2';
|
||||
const KSP_TEST_TABLE = 'CustomKSPTestTable';
|
||||
|
||||
/**
|
||||
* class for encapsulating column metadata needed for creating a table
|
||||
*/
|
||||
|
@ -161,13 +157,16 @@ class BindParamOption
|
|||
$type_size = explode("(", $this->sqlType);
|
||||
$type = $type_size[0];
|
||||
if (count($type_size) > 1) {
|
||||
$size = $type_size[1];
|
||||
$size = rtrim($type_size[1], ")");
|
||||
$prec_scal = explode(",", $size);
|
||||
if (count($prec_scal) > 1) {
|
||||
$prec = $prec_scal[0];
|
||||
$scal = rtrim($prec_scal[1], ")");
|
||||
$scal = $prec_scal[1];
|
||||
$size = null;
|
||||
}
|
||||
if (strpos($size, "max") !== false) {
|
||||
$size = trim($size, "'");
|
||||
}
|
||||
}
|
||||
// get the sqlType constant
|
||||
try {
|
||||
|
@ -214,29 +213,6 @@ function getCekName()
|
|||
return $cekName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the path to the KSP dll/so file
|
||||
*/
|
||||
function getKSPpath()
|
||||
{
|
||||
$name = 'myKSP';
|
||||
|
||||
$dir_name = realpath(dirname(__FILE__));
|
||||
$ksp = $dir_name . DIRECTORY_SEPARATOR . $name;
|
||||
if (strtoupper(substr(php_uname('s'), 0, 3)) == 'WIN') {
|
||||
$arch = 'x64';
|
||||
if (PHP_INT_SIZE == 4) {
|
||||
// running 32 bit
|
||||
$arch = '';
|
||||
}
|
||||
$ksp .= $arch . '.dll';
|
||||
} else {
|
||||
$ksp .= '.so';
|
||||
}
|
||||
|
||||
return $ksp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string default column name when a name is not provided in the ColumnMeta class
|
||||
*/
|
||||
|
@ -330,12 +306,8 @@ function getSeqPlaceholders($num)
|
|||
*/
|
||||
function isColEncrypted()
|
||||
{
|
||||
global $keystore, $dataEncrypted;
|
||||
if ($keystore === KEYSTORE_NONE) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
global $keystore;
|
||||
return ($keystore !== KEYSTORE_NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -345,11 +317,7 @@ function isColEncrypted()
|
|||
function isDataEncrypted()
|
||||
{
|
||||
global $keystore, $dataEncrypted;
|
||||
if ($keystore === KEYSTORE_NONE || !$dataEncrypted) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
return ($keystore !== KEYSTORE_NONE && $dataEncrypted);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -361,6 +329,12 @@ function isQualified($conn)
|
|||
if (explode(".", $msodbcsql_ver)[0] < 17) {
|
||||
return false;
|
||||
}
|
||||
global $daasMode;
|
||||
if ($daasMode) {
|
||||
// running against Azure
|
||||
return true;
|
||||
}
|
||||
// if not Azure, check the server version
|
||||
$server_ver = sqlsrv_server_info($conn)['SQLServerVersion'];
|
||||
if (explode('.', $server_ver)[0] < 13) {
|
||||
return false;
|
||||
|
@ -385,13 +359,6 @@ function connect($options = array(), $disableCE = false)
|
|||
if (isColEncrypted()) {
|
||||
$connectionOptions = array_merge($connectionOptions, array("ColumnEncryption" => "Enabled"));
|
||||
}
|
||||
if ($keystore == "ksp") {
|
||||
$ksp_path = getKSPPath();
|
||||
$ksp_options = array("CEKeystoreProvider"=>$ksp_path,
|
||||
"CEKeystoreName"=>KSP_NAME,
|
||||
"CEKeystoreEncryptKey"=>ENCRYPT_KEY);
|
||||
$connectionOptions = array_merge($connectionOptions, $ksp_options);
|
||||
}
|
||||
}
|
||||
$conn = sqlsrv_connect($server, $connectionOptions);
|
||||
if ($conn === false) {
|
||||
|
|
|
@ -6,18 +6,23 @@ Validates that a prepared statement can be successfully executed more than once.
|
|||
--ENV--
|
||||
PHPT_EXEC=true
|
||||
--SKIPIF--
|
||||
<?php require('skipif_versions_old.inc'); ?>
|
||||
<?php
|
||||
// locale must be set before 1st connection
|
||||
setUSAnsiLocale();
|
||||
require('skipif_versions_old.inc');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once('MsCommon.inc');
|
||||
|
||||
function prepareAndExecute($noPasses)
|
||||
{
|
||||
$testName = "Statement - Prepare and Execute";
|
||||
startTest($testName);
|
||||
|
||||
setup();
|
||||
$conn1 = AE\connect();
|
||||
if (useUTF8Data()) {
|
||||
$conn1 = AE\connect(array('CharacterSet'=>'UTF-8'));
|
||||
} else {
|
||||
$conn1 = AE\connect();
|
||||
}
|
||||
|
||||
$tableName = 'TC34test';
|
||||
AE\createTestTable($conn1, $tableName);
|
||||
|
@ -80,20 +85,36 @@ function prepareAndExecute($noPasses)
|
|||
dropTable($conn1, $tableName);
|
||||
|
||||
sqlsrv_close($conn1);
|
||||
|
||||
endTest($testName);
|
||||
}
|
||||
|
||||
if (!isWindows()) {
|
||||
setUTF8Data(true);
|
||||
// locale must be set before 1st connection
|
||||
setUSAnsiLocale();
|
||||
$testName = "Statement - Prepare and Execute";
|
||||
|
||||
// test ansi only if windows or non-UTF8 locales are supported (ODBC 17 and above)
|
||||
startTest($testName);
|
||||
if (isLocaleSupported()) {
|
||||
try {
|
||||
setUTF8Data(false);
|
||||
prepareAndExecute(5);
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
}
|
||||
endTest($testName);
|
||||
|
||||
// test utf8
|
||||
startTest($testName);
|
||||
try {
|
||||
setUTF8Data(true);
|
||||
resetLocaleToDefault();
|
||||
prepareAndExecute(5);
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
setUTF8Data(false);
|
||||
endTest($testName);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Test "Statement - Prepare and Execute" completed successfully.
|
||||
Test "Statement - Prepare and Execute" completed successfully.
|
||||
|
|
|
@ -6,20 +6,20 @@ retrieving fields from a table including rows with all supported SQL types (28 t
|
|||
--ENV--
|
||||
PHPT_EXEC=true
|
||||
--SKIPIF--
|
||||
<?php require('skipif_versions_old.inc'); ?>
|
||||
<?php
|
||||
// locale must be set before 1st connection
|
||||
setUSAnsiLocale();
|
||||
require('skipif_versions_old.inc');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once('MsCommon.inc');
|
||||
|
||||
function fetchFields()
|
||||
{
|
||||
$testName = "Fetch - Field";
|
||||
startTest($testName);
|
||||
|
||||
setup();
|
||||
$tableName = 'TC42test';
|
||||
|
||||
if (! isWindows()) {
|
||||
if (useUTF8Data()) {
|
||||
$conn1 = AE\connect(array('CharacterSet'=>'UTF-8'));
|
||||
} else {
|
||||
$conn1 = AE\connect();
|
||||
|
@ -33,9 +33,6 @@ function fetchFields()
|
|||
$stmt1 = AE\selectFromTable($conn1, $tableName);
|
||||
$numFields = sqlsrv_num_fields($stmt1);
|
||||
|
||||
$errState = 'IMSSP';
|
||||
$errMessage = 'Connection with Column Encryption enabled does not support fetching stream. Please fetch the data as a string.';
|
||||
|
||||
trace("Retrieving $noRowsInserted rows with $numFields fields each ...");
|
||||
for ($i = 0; $i < $noRowsInserted; $i++) {
|
||||
$row = sqlsrv_fetch($stmt1);
|
||||
|
@ -44,16 +41,9 @@ function fetchFields()
|
|||
}
|
||||
for ($j = 0; $j < $numFields; $j++) {
|
||||
$fld = sqlsrv_get_field($stmt1, $j);
|
||||
|
||||
// With AE enabled, those fields that sqlsrv_get_field() will fetch
|
||||
// as stream data will return a specific error message
|
||||
$col = $j+1;
|
||||
if ($fld === false) {
|
||||
if (AE\isColEncrypted() && isStreamData($col)) {
|
||||
verifyError(sqlsrv_errors()[0], $errState, $errMessage);
|
||||
} else {
|
||||
fatalError("Field $j of Row $i is missing\n", true);
|
||||
}
|
||||
fatalError("Field $j of Row $i is missing\n", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,16 +53,36 @@ function fetchFields()
|
|||
dropTable($conn1, $tableName);
|
||||
|
||||
sqlsrv_close($conn1);
|
||||
|
||||
endTest($testName);
|
||||
}
|
||||
|
||||
// locale must be set before 1st connection
|
||||
setUSAnsiLocale();
|
||||
$testName = "Fetch - Field";
|
||||
|
||||
// test ansi only if windows or non-UTF8 locales are supported (ODBC 17 and above)
|
||||
startTest($testName);
|
||||
if (isLocaleSupported()) {
|
||||
try {
|
||||
setUTF8Data(false);
|
||||
fetchFields();
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
}
|
||||
endTest($testName);
|
||||
|
||||
// test utf8
|
||||
startTest($testName);
|
||||
try {
|
||||
setUTF8Data(true);
|
||||
resetLocaleToDefault();
|
||||
fetchFields();
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
endTest($testName);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Test "Fetch - Field" completed successfully.
|
||||
Test "Fetch - Field" completed successfully.
|
||||
|
|
|
@ -5,9 +5,8 @@ PHPT_EXEC=true
|
|||
--SKIPIF--
|
||||
<?
|
||||
// locale must be set before 1st connection
|
||||
if ( !isWindows() ) {
|
||||
setlocale(LC_ALL, "en_US.ISO-8859-1");
|
||||
}
|
||||
setUSAnsiLocale();
|
||||
require('skipif_versions_old.inc');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
@ -96,15 +95,12 @@ function checkData($col, $actual, $expected)
|
|||
return ($success);
|
||||
}
|
||||
|
||||
if (!isWindows()) {
|
||||
setlocale(LC_ALL, "en_US.ISO-8859-1");
|
||||
}
|
||||
|
||||
setUSAnsiLocale();
|
||||
$testName = "Fetch - Field Data";
|
||||
|
||||
// test ansi only if windows or non-UTF8 locales are supported (ODBC 17 and above)
|
||||
startTest($testName);
|
||||
if (isWindows() || isLocaleSupported()) {
|
||||
if (isLocaleSupported()) {
|
||||
|
||||
try {
|
||||
setUTF8Data(false);
|
||||
|
@ -119,6 +115,7 @@ endTest($testName);
|
|||
startTest($testName);
|
||||
try {
|
||||
setUTF8Data(true);
|
||||
resetLocaleToDefault();
|
||||
fetchFields();
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage();
|
||||
|
|
|
@ -8,9 +8,8 @@ PHPT_EXEC=true
|
|||
--SKIPIF--
|
||||
<?
|
||||
// locale must be set before 1st connection
|
||||
if ( !isWindows() ) {
|
||||
setlocale(LC_ALL, "en_US.ISO-8859-1");
|
||||
}
|
||||
setUSAnsiLocale();
|
||||
require('skipif_versions_old.inc');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
@ -152,16 +151,12 @@ function checkData($row, $stmt, $index, $mode)
|
|||
}
|
||||
|
||||
// locale must be set before 1st connection
|
||||
if (!isWindows()) {
|
||||
setlocale(LC_ALL, "en_US.ISO-8859-1");
|
||||
}
|
||||
|
||||
global $testName;
|
||||
setUSAnsiLocale();
|
||||
$testName = "Fetch - Array";
|
||||
|
||||
// test ansi only if windows or non-UTF8 locales are supported (ODBC 17 and above)
|
||||
startTest($testName);
|
||||
if (isWindows() || isLocaleSupported()) {
|
||||
if (isLocaleSupported()) {
|
||||
try {
|
||||
setUTF8Data(false);
|
||||
fetchRow(1, 4);
|
||||
|
@ -175,6 +170,7 @@ endTest($testName);
|
|||
startTest($testName);
|
||||
try {
|
||||
setUTF8Data(true);
|
||||
resetLocaleToDefault();
|
||||
fetchRow(1, 4);
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage();
|
||||
|
|
|
@ -5,7 +5,11 @@ Verifies data retrieval via "sqlsrv_fetch_object".
|
|||
--ENV--
|
||||
PHPT_EXEC=true
|
||||
--SKIPIF--
|
||||
<?php require('skipif_versions_old.inc'); ?>
|
||||
<?php
|
||||
// locale must be set before 1st connection
|
||||
setUSAnsiLocale();
|
||||
require('skipif_versions_old.inc');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once('MsCommon.inc');
|
||||
|
@ -19,14 +23,10 @@ class TestClass
|
|||
|
||||
function fetchRow($minFetchMode, $maxFetchMode)
|
||||
{
|
||||
$testName = "Fetch - Object";
|
||||
startTest($testName);
|
||||
|
||||
setup();
|
||||
$tableName = 'TC45test';
|
||||
|
||||
if (! isWindows()) {
|
||||
$conn1 = AE\connect(array( 'CharacterSet'=>'UTF-8' ));
|
||||
if (useUTF8Data()) {
|
||||
$conn1 = AE\connect(array('CharacterSet'=>'UTF-8'));
|
||||
} else {
|
||||
$conn1 = AE\connect();
|
||||
}
|
||||
|
@ -73,8 +73,6 @@ function fetchRow($minFetchMode, $maxFetchMode)
|
|||
dropTable($conn1, $tableName);
|
||||
|
||||
sqlsrv_close($conn1);
|
||||
|
||||
endTest($testName);
|
||||
}
|
||||
|
||||
|
||||
|
@ -89,7 +87,7 @@ function fetchObject($stmt, $rows, $fields, $useClass)
|
|||
$obj = sqlsrv_fetch_object($stmt);
|
||||
}
|
||||
if ($obj === false) {
|
||||
fatalError("Row $i is missing");
|
||||
fatalError("In fetchObject: Row $i is missing");
|
||||
}
|
||||
$values[$i] = $obj;
|
||||
}
|
||||
|
@ -103,7 +101,7 @@ function fetchArray($stmt, $rows, $fields)
|
|||
for ($i = 0; $i < $rows; $i++) {
|
||||
$row = sqlsrv_fetch_array($stmt);
|
||||
if ($row === false) {
|
||||
fatalError("Row $i is missing");
|
||||
fatalError("In fetchArray: Row $i is missing");
|
||||
}
|
||||
$values[$i] = $row;
|
||||
}
|
||||
|
@ -127,12 +125,34 @@ function checkData($rows, $fields, $actualValues, $expectedValues)
|
|||
}
|
||||
}
|
||||
|
||||
// locale must be set before 1st connection
|
||||
setUSAnsiLocale();
|
||||
$testName = "Fetch - Object";
|
||||
|
||||
// test ansi only if windows or non-UTF8 locales are supported (ODBC 17 and above)
|
||||
startTest($testName);
|
||||
if (isLocaleSupported()) {
|
||||
try {
|
||||
setUTF8Data(false);
|
||||
fetchRow(0, 2);
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
}
|
||||
endTest($testName);
|
||||
|
||||
// test utf8
|
||||
startTest($testName);
|
||||
try {
|
||||
setUTF8Data(true);
|
||||
resetLocaleToDefault();
|
||||
fetchRow(0, 2);
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
endTest($testName);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Test "Fetch - Object" completed successfully.
|
||||
Test "Fetch - Object" completed successfully.
|
||||
|
|
|
@ -7,9 +7,8 @@ PHPT_EXEC=true
|
|||
--SKIPIF--
|
||||
<?
|
||||
// locale must be set before 1st connection
|
||||
if ( !isWindows() ) {
|
||||
setlocale(LC_ALL, "en_US.ISO-8859-1");
|
||||
}
|
||||
setUSAnsiLocale();
|
||||
require('skipif_versions_old.inc');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
@ -85,16 +84,12 @@ function fetchFields()
|
|||
}
|
||||
|
||||
// locale must be set before 1st connection
|
||||
if (!isWindows()) {
|
||||
setlocale(LC_ALL, "en_US.ISO-8859-1");
|
||||
}
|
||||
|
||||
global $testName;
|
||||
setUSAnsiLocale();
|
||||
$testName = "Fetch - Next Result";
|
||||
|
||||
// test ansi only if windows or non-UTF8 locales are supported (ODBC 17 and above)
|
||||
startTest($testName);
|
||||
if (isWindows() || isLocaleSupported()) {
|
||||
if (isLocaleSupported()) {
|
||||
try {
|
||||
setUTF8Data(false);
|
||||
fetchFields();
|
||||
|
@ -108,6 +103,7 @@ endTest($testName);
|
|||
startTest($testName);
|
||||
try {
|
||||
setUTF8Data(true);
|
||||
resetLocaleToDefault();
|
||||
fetchFields();
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage();
|
||||
|
|
|
@ -5,19 +5,20 @@ Verifies data retrieval with scrollable result sets.
|
|||
--ENV--
|
||||
PHPT_EXEC=true
|
||||
--SKIPIF--
|
||||
<?php require('skipif_versions_old.inc'); ?>
|
||||
<?php
|
||||
// locale must be set before 1st connection
|
||||
setUSAnsiLocale();
|
||||
require('skipif_versions_old.inc');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once('MsCommon.inc');
|
||||
|
||||
function fetchRow($noRows)
|
||||
{
|
||||
$testName = "Fetch - Scrollable";
|
||||
startTest($testName);
|
||||
|
||||
setup();
|
||||
$tableName = 'TC48test';
|
||||
if (! isWindows()) {
|
||||
if (useUTF8Data()) {
|
||||
$conn1 = AE\connect(array('CharacterSet'=>'UTF-8'));
|
||||
} else {
|
||||
$conn1 = AE\connect();
|
||||
|
@ -44,36 +45,30 @@ function fetchRow($noRows)
|
|||
sqlsrv_free_stmt($stmt2);
|
||||
checkData($noRowsInserted, $numFields, $actual, $expected);
|
||||
|
||||
// Always Encrypted feature does not support the following options
|
||||
// https://github.com/Microsoft/msphpsql/wiki/Features#aelimitation
|
||||
if (!AE\isColEncrypted()) {
|
||||
// fetch object - STATIC cursor
|
||||
$options = array('Scrollable' => SQLSRV_CURSOR_STATIC);
|
||||
$stmt2 = AE\executeQueryEx($conn1, $query, $options);
|
||||
$actual = fetchObject($stmt2, $noRowsInserted, $numFields, SQLSRV_SCROLL_RELATIVE);
|
||||
sqlsrv_free_stmt($stmt2);
|
||||
checkData($noRowsInserted, $numFields, $actual, $expected);
|
||||
// fetch object - STATIC cursor
|
||||
$options = array('Scrollable' => SQLSRV_CURSOR_STATIC);
|
||||
$stmt2 = AE\executeQueryEx($conn1, $query, $options);
|
||||
$actual = fetchObject($stmt2, $noRowsInserted, $numFields, SQLSRV_SCROLL_RELATIVE);
|
||||
sqlsrv_free_stmt($stmt2);
|
||||
checkData($noRowsInserted, $numFields, $actual, $expected);
|
||||
|
||||
// fetch object - DYNAMIC cursor
|
||||
$options = array('Scrollable' => SQLSRV_CURSOR_DYNAMIC);
|
||||
$stmt2 = AE\executeQueryEx($conn1, $query, $options);
|
||||
$actual = fetchObject($stmt2, $noRowsInserted, $numFields, SQLSRV_SCROLL_ABSOLUTE);
|
||||
sqlsrv_free_stmt($stmt2);
|
||||
checkData($noRowsInserted, $numFields, $actual, $expected);
|
||||
// fetch object - DYNAMIC cursor
|
||||
$options = array('Scrollable' => SQLSRV_CURSOR_DYNAMIC);
|
||||
$stmt2 = AE\executeQueryEx($conn1, $query, $options);
|
||||
$actual = fetchObject($stmt2, $noRowsInserted, $numFields, SQLSRV_SCROLL_ABSOLUTE);
|
||||
sqlsrv_free_stmt($stmt2);
|
||||
checkData($noRowsInserted, $numFields, $actual, $expected);
|
||||
|
||||
// fetch object - KEYSET cursor
|
||||
$options = array('Scrollable' => SQLSRV_CURSOR_KEYSET);
|
||||
$stmt2 = AE\executeQueryEx($conn1, $query, $options);
|
||||
$actual = fetchObject($stmt2, $noRowsInserted, $numFields, SQLSRV_SCROLL_PRIOR, 0);
|
||||
sqlsrv_free_stmt($stmt2);
|
||||
checkData($noRowsInserted, $numFields, $actual, $expected);
|
||||
}
|
||||
// fetch object - KEYSET cursor
|
||||
$options = array('Scrollable' => SQLSRV_CURSOR_KEYSET);
|
||||
$stmt2 = AE\executeQueryEx($conn1, $query, $options);
|
||||
$actual = fetchObject($stmt2, $noRowsInserted, $numFields, SQLSRV_SCROLL_PRIOR, 0);
|
||||
sqlsrv_free_stmt($stmt2);
|
||||
checkData($noRowsInserted, $numFields, $actual, $expected);
|
||||
|
||||
dropTable($conn1, $tableName);
|
||||
|
||||
sqlsrv_close($conn1);
|
||||
|
||||
endTest($testName);
|
||||
}
|
||||
|
||||
function fetchArray($stmt, $rows, $fields)
|
||||
|
@ -135,12 +130,34 @@ function checkData($rows, $fields, $actualValues, $expectedValues)
|
|||
}
|
||||
}
|
||||
|
||||
// locale must be set before 1st connection
|
||||
setUSAnsiLocale();
|
||||
$testName = "Fetch - Scrollable";
|
||||
|
||||
// test ansi only if windows or non-UTF8 locales are supported (ODBC 17 and above)
|
||||
startTest($testName);
|
||||
if (isLocaleSupported()) {
|
||||
try {
|
||||
setUTF8Data(false);
|
||||
fetchRow(10);
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
}
|
||||
endTest($testName);
|
||||
|
||||
// test utf8
|
||||
startTest($testName);
|
||||
try {
|
||||
setUTF8Data(true);
|
||||
resetLocaleToDefault();
|
||||
fetchRow(10);
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
endTest($testName);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Test "Fetch - Scrollable" completed successfully.
|
||||
Test "Fetch - Scrollable" completed successfully.
|
||||
|
|
|
@ -7,9 +7,8 @@ can be successfully retrieved as streams.
|
|||
PHPT_EXEC=true
|
||||
--SKIPIF--
|
||||
<?// locale must be set before 1st connection
|
||||
if ( !isWindows() ) {
|
||||
setlocale(LC_ALL, "en_US.ISO-8859-1");
|
||||
}
|
||||
setUSAnsiLocale();
|
||||
require('skipif_versions_old.inc');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
@ -69,7 +68,7 @@ function verifyStream($stmt, $row, $colIndex)
|
|||
}
|
||||
}
|
||||
if ($stream === false) {
|
||||
verifyStreamError("Failed to read field $col: $type");
|
||||
fatalError("Failed to read field $col: $type");
|
||||
} else {
|
||||
$value = '';
|
||||
if ($stream) {
|
||||
|
@ -88,16 +87,6 @@ function verifyStream($stmt, $row, $colIndex)
|
|||
}
|
||||
}
|
||||
|
||||
function verifyStreamError($message)
|
||||
{
|
||||
global $errState, $errMessage;
|
||||
if (AE\isColEncrypted()) {
|
||||
verifyError(sqlsrv_errors()[0], $errState, $errMessage);
|
||||
} else {
|
||||
fatalError($message);
|
||||
}
|
||||
}
|
||||
|
||||
function checkData($col, $actual, $expected)
|
||||
{
|
||||
$success = true;
|
||||
|
@ -125,20 +114,13 @@ function checkData($col, $actual, $expected)
|
|||
}
|
||||
|
||||
// locale must be set before 1st connection
|
||||
if (!isWindows()) {
|
||||
setlocale(LC_ALL, "en_US.ISO-8859-1");
|
||||
}
|
||||
|
||||
setUSAnsiLocale();
|
||||
global $testName;
|
||||
$testName = "Stream - Read";
|
||||
|
||||
// error message expected with AE enabled
|
||||
$errState = 'IMSSP';
|
||||
$errMessage = 'Connection with Column Encryption enabled does not support fetching stream. Please fetch the data as a string.';
|
||||
|
||||
// test ansi only if windows or non-UTF8 locales are supported (ODBC 17 and above)
|
||||
startTest($testName);
|
||||
if (isWindows() || isLocaleSupported()) {
|
||||
if (isLocaleSupported()) {
|
||||
try {
|
||||
setUTF8Data(false);
|
||||
streamRead(20, 1);
|
||||
|
@ -152,6 +134,7 @@ endTest($testName);
|
|||
startTest($testName);
|
||||
try {
|
||||
setUTF8Data(true);
|
||||
resetLocaleToDefault();
|
||||
streamRead(20, 1);
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage();
|
||||
|
|
|
@ -7,9 +7,8 @@ PHPT_EXEC=true
|
|||
--SKIPIF--
|
||||
<?
|
||||
// locale must be set before 1st connection
|
||||
if ( !isWindows() ) {
|
||||
setlocale(LC_ALL, "en_US.ISO-8859-1");
|
||||
}
|
||||
setUSAnsiLocale();
|
||||
require('skipif_versions_old.inc');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
@ -30,57 +29,31 @@ function streamScroll($noRows, $startRow)
|
|||
AE\insertTestRowsByRange($conn1, $tableName, $startRow, $startRow + $noRows - 1);
|
||||
|
||||
$query = "SELECT * FROM [$tableName] ORDER BY c27_timestamp";
|
||||
// Always Encrypted feature does not support SQLSRV_CURSOR_STATIC
|
||||
// https://github.com/Microsoft/msphpsql/wiki/Features#aelimitation
|
||||
if (AE\isColEncrypted()) {
|
||||
$options = array('Scrollable' => SQLSRV_CURSOR_FORWARD);
|
||||
} else {
|
||||
$options = array('Scrollable' => SQLSRV_CURSOR_STATIC);
|
||||
}
|
||||
$options = array('Scrollable' => SQLSRV_CURSOR_STATIC);
|
||||
$stmt1 = AE\executeQueryEx($conn1, $query, $options);
|
||||
$numFields = sqlsrv_num_fields($stmt1);
|
||||
if (AE\isColEncrypted()) {
|
||||
$row = $startRow;
|
||||
while ($row <= $noRows) {
|
||||
if (!sqlsrv_fetch($stmt1, SQLSRV_SCROLL_NEXT)) {
|
||||
$row = $noRows;
|
||||
while ($row >= 1) {
|
||||
if ($row == $noRows) {
|
||||
if (!sqlsrv_fetch($stmt1, SQLSRV_SCROLL_LAST)) {
|
||||
fatalError("Failed to fetch row ".$row);
|
||||
}
|
||||
trace("\nStreaming row $row:\n");
|
||||
for ($j = 0; $j < $numFields; $j++) {
|
||||
$col = $j + 1;
|
||||
if (!isUpdatable($col)) {
|
||||
continue;
|
||||
}
|
||||
if (isStreamable($col)) {
|
||||
verifyStream($stmt1, $startRow + $row - 1, $j);
|
||||
}
|
||||
} else {
|
||||
if (!sqlsrv_fetch($stmt1, SQLSRV_SCROLL_PRIOR)) {
|
||||
fatalError("Failed to fetch row ".$row);
|
||||
}
|
||||
$row++;
|
||||
}
|
||||
} else {
|
||||
$row = $noRows;
|
||||
while ($row >= 1) {
|
||||
if ($row == $noRows) {
|
||||
if (!sqlsrv_fetch($stmt1, SQLSRV_SCROLL_LAST)) {
|
||||
fatalError("Failed to fetch row ".$row);
|
||||
}
|
||||
} else {
|
||||
if (!sqlsrv_fetch($stmt1, SQLSRV_SCROLL_PRIOR)) {
|
||||
fatalError("Failed to fetch row ".$row);
|
||||
}
|
||||
trace("\nStreaming row $row:\n");
|
||||
for ($j = 0; $j < $numFields; $j++) {
|
||||
$col = $j + 1;
|
||||
if (!isUpdatable($col)) {
|
||||
continue;
|
||||
}
|
||||
trace("\nStreaming row $row:\n");
|
||||
for ($j = 0; $j < $numFields; $j++) {
|
||||
$col = $j + 1;
|
||||
if (!isUpdatable($col)) {
|
||||
continue;
|
||||
}
|
||||
if (isStreamable($col)) {
|
||||
verifyStream($stmt1, $startRow + $row - 1, $j);
|
||||
}
|
||||
if (isStreamable($col)) {
|
||||
verifyStream($stmt1, $startRow + $row - 1, $j);
|
||||
}
|
||||
$row--;
|
||||
}
|
||||
$row--;
|
||||
}
|
||||
sqlsrv_free_stmt($stmt1);
|
||||
|
||||
|
@ -162,11 +135,7 @@ function checkData($col, $actual, $expected)
|
|||
}
|
||||
|
||||
// locale must be set before 1st connection
|
||||
if (!isWindows()) {
|
||||
setlocale(LC_ALL, "en_US.ISO-8859-1");
|
||||
}
|
||||
|
||||
global $testName;
|
||||
setUSAnsiLocale();
|
||||
$testName = "Stream - Scrollable";
|
||||
|
||||
// error message expected with AE enabled
|
||||
|
@ -175,7 +144,7 @@ $errMessage = 'Connection with Column Encryption enabled does not support fetchi
|
|||
|
||||
// test ansi only if windows or non-UTF8 locales are supported (ODBC 17 and above)
|
||||
startTest($testName);
|
||||
if (isWindows() || isLocaleSupported()) {
|
||||
if (isLocaleSupported()) {
|
||||
try {
|
||||
setUTF8Data(false);
|
||||
streamScroll(20, 1);
|
||||
|
@ -189,6 +158,7 @@ endTest($testName);
|
|||
startTest($testName);
|
||||
try {
|
||||
setUTF8Data(true);
|
||||
resetLocaleToDefault();
|
||||
streamScroll(20, 1);
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage();
|
||||
|
|
|
@ -272,9 +272,6 @@ function runTest($noPasses, $noRows, $tableName, $conn, $prepared, $release, $mo
|
|||
break;
|
||||
|
||||
case 5: // fetch fields
|
||||
$errState = 'IMSSP';
|
||||
$errMessage = 'Connection with Column Encryption enabled does not support fetching stream. Please fetch the data as a string.';
|
||||
|
||||
$stmt = execQuery($conn, $tableName, $prepared);
|
||||
$numFields = sqlsrv_num_fields($stmt);
|
||||
while (sqlsrv_fetch($stmt)) {
|
||||
|
@ -284,11 +281,7 @@ function runTest($noPasses, $noRows, $tableName, $conn, $prepared, $release, $mo
|
|||
$col = $i + 1;
|
||||
|
||||
if ($fld === false) {
|
||||
if (AE\isColEncrypted() && isStreamData($col)) {
|
||||
verifyError(sqlsrv_errors()[0], $errState, $errMessage);
|
||||
} else {
|
||||
fatalError("Field $i of row $rowCount is missing");
|
||||
}
|
||||
fatalError("Field $i of row $rowCount is missing");
|
||||
}
|
||||
unset($fld);
|
||||
}
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
<?php
|
||||
|
||||
if (!extension_loaded("sqlsrv"))
|
||||
die("skip extension not loaded");
|
||||
|
||||
require_once('MsCommon.inc');
|
||||
|
||||
if ($keystore != AE\KEYSTORE_KSP) {
|
||||
die('skip - this test requires a custom keystore provider.');
|
||||
}
|
||||
|
||||
$conn = AE\connect();
|
||||
if (! $conn) {
|
||||
echo("Error: could not connect during SKIPIF!");
|
||||
} elseif (AE\isColEncrypted() && !AE\isQualified($conn)) {
|
||||
die("skip - AE feature not supported in the current environment.");
|
||||
}
|
||||
?>
|
|
@ -1,15 +1,21 @@
|
|||
<?php
|
||||
|
||||
if (! extension_loaded("sqlsrv")) {
|
||||
die("skip extension not loaded");
|
||||
}
|
||||
|
||||
require_once('MsCommon.inc');
|
||||
|
||||
$conn = AE\connect();
|
||||
if (! $conn) {
|
||||
echo("Error: could not connect during SKIPIF!");
|
||||
} elseif (AE\isColEncrypted() && !AE\isQualified($conn)) {
|
||||
die("skip - AE feature not supported in the current environment.");
|
||||
}
|
||||
<?php
|
||||
|
||||
if (! extension_loaded("sqlsrv")) {
|
||||
die("skip extension not loaded");
|
||||
}
|
||||
|
||||
require_once('MsCommon.inc');
|
||||
|
||||
$conn = AE\connect();
|
||||
if (! $conn) {
|
||||
echo("Error: could not connect during SKIPIF!");
|
||||
} elseif (AE\isColEncrypted()) {
|
||||
if (!isWindows()) {
|
||||
die( "Skip, AE test on windows only." );
|
||||
}
|
||||
|
||||
if (!AE\isQualified($conn)) {
|
||||
die("skip - AE feature not supported in the current environment.");
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,59 @@
|
|||
--TEST--
|
||||
GitHub issue #623 - data is correctly fetched using a client buffer even with varchar(max) in the result set
|
||||
--SKIPIF--
|
||||
<?php require('skipif.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
sqlsrv_configure('WarningsReturnAsErrors', 1);
|
||||
|
||||
// step 01: Connect without Always Encrypted feature
|
||||
require_once('MsSetup.inc');
|
||||
$conn = sqlsrv_connect($server, $connectionOptions);
|
||||
if (! $conn) {
|
||||
fatalError("Failed to connect\n");
|
||||
}
|
||||
|
||||
$tableName = 'systemtag';
|
||||
|
||||
// step 02: Setup table
|
||||
require_once('MsCommon.inc');
|
||||
dropTable($conn, $tableName);
|
||||
$sql = "CREATE TABLE [$tableName](
|
||||
[id] [int] IDENTITY(1,1) NOT NULL,
|
||||
[name] [varchar](255) NOT NULL,
|
||||
[tag] [varchar](max) NULL,
|
||||
CONSTRAINT [PK_usertag] PRIMARY KEY CLUSTERED (
|
||||
[id] ASC
|
||||
))";
|
||||
|
||||
$stmt = sqlsrv_query($conn, $sql);
|
||||
|
||||
// step 03: Insert test data
|
||||
$name = 'Disclaimer e-mail';
|
||||
$tag = 'De informatie van deze e-mail en de eventueel bijgevoegde bestanden is vertrouwelijk en kan juridisch beschermd zijn. Het is uitsluitend bedoeld voor degene(n) aan wie het gericht is of degene(n) die geautoriseerd zijn om het bericht te ontvangen. Indien het bericht niet voor u bestemd is, wordt u verzocht de inhoud ervan niet te lezen, en het bericht aan ons terug te sturen. In dat geval wijzen wij u er tevens op dat het kopië';
|
||||
|
||||
$sql = "INSERT INTO $tableName (name, tag) VALUES (?, ?)";
|
||||
$parameters = [$name, $tag];
|
||||
$stmt = sqlsrv_query($conn, $sql, $parameters);
|
||||
|
||||
// step 04: Fetch the data
|
||||
$sql = "SELECT name, tag FROM $tableName";
|
||||
|
||||
$stmt = sqlsrv_query( $conn, $sql, [], ['Scrollable' => SQLSRV_CURSOR_CLIENT_BUFFERED]);
|
||||
$result = sqlsrv_fetch($stmt);
|
||||
if ($result) {
|
||||
$value1 = sqlsrv_get_field($stmt, 0, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR));
|
||||
var_dump($value1 === $name);
|
||||
$value2 = sqlsrv_get_field($stmt, 1, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR));
|
||||
var_dump($value2 === $tag);
|
||||
} else {
|
||||
fatalError('Something went wrong\n');
|
||||
}
|
||||
|
||||
dropTable($conn, $tableName);
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECT--
|
||||
bool(true)
|
||||
bool(true)
|
||||
Done
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче