resolved merge conflicts
This commit is contained in:
commit
117b2bf777
26
.travis.yml
26
.travis.yml
|
@ -16,21 +16,33 @@ env:
|
|||
- 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
|
||||
|
||||
install:
|
||||
- docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=Password123' -p 1433:1433 --name=$TEST_PHP_SQL_SERVER -d microsoft/mssql-server-linux
|
||||
- docker build --build-arg PHPSQLDIR=$PHPSQLDIR -t msphpsql-dev -f Dockerfile-msphpsql .
|
||||
- docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=Password12@' -p 1433:1433 --name=$TEST_PHP_SQL_SERVER -d microsoft/mssql-server-linux
|
||||
|
||||
before_script:
|
||||
- sleep 30
|
||||
|
||||
script:
|
||||
- docker run -e TRAVIS_JOB_ID -t -d -w $PHPSQLDIR --link $TEST_PHP_SQL_SERVER --name=client msphpsql-dev
|
||||
- docker ps -a
|
||||
- docker exec client python ./test/functional/setup/setup_dbs.py -dbname $SQLSRV_DBNAME
|
||||
- docker exec client python ./test/functional/setup/setup_dbs.py -dbname $PDOSQLSRV_DBNAME
|
||||
- docker exec client php ./source/pdo_sqlsrv/run-tests.php ./test/functional/pdo_sqlsrv/*.phpt
|
||||
- docker exec client php ./source/sqlsrv/run-tests.php ./test/functional/sqlsrv/*.phpt
|
||||
- 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'
|
||||
|
|
21
CHANGELOG.md
21
CHANGELOG.md
|
@ -3,6 +3,27 @@ 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/MAC 5.0.0-preview - 2017-07-31
|
||||
Updated PECL release packages. Here is the list of updates:
|
||||
|
||||
### Added
|
||||
- Added support for PHP 7.2 Beta 1
|
||||
|
||||
### 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))
|
||||
|
||||
### Removed
|
||||
- No longer support Ubuntu 15
|
||||
- Supplying tablename into PDO::lastInsertId($name) no longer return the last inserted row ([lastInsertId](https://github.com/Microsoft/msphpsql/wiki/Features#lastinsertid))
|
||||
|
||||
### Limitation
|
||||
- No support for inout / output params when using sql_variant type
|
||||
|
||||
### Known Issues
|
||||
- When pooling is enabled in Linux or MAC
|
||||
- unixODBC <= 2.3.4 (Linux and MAC) might not return proper diagnostics information, such as error messages, warnings and informative messages
|
||||
- due to this unixODBC bug, fetch large data (such as xml, binary) as streams as a workaround. See the examples [here](https://github.com/Microsoft/msphpsql/wiki/Connection-Pooling-on-Linux-and-Mac)
|
||||
|
||||
## Windows/Linux/MAC 4.3.0 - 2017-07-06
|
||||
Production Ready release for SQLSRV and PDO_SQLSRV drivers on Sierra, El Capitan, Debian 8, Ubuntu 15, Ubuntu 16, CentOS 7, and Windows. Here is the changlog since the last Production Ready release.
|
||||
|
||||
|
|
|
@ -4,29 +4,29 @@ FROM ubuntu:16.04
|
|||
|
||||
# Update Ubuntu Software repository
|
||||
RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && \
|
||||
apt-get -y install \
|
||||
apt-transport-https \
|
||||
apt-utils \
|
||||
autoconf \
|
||||
curl \
|
||||
g++ \
|
||||
gcc \
|
||||
git \
|
||||
lcov \
|
||||
libxml2-dev \
|
||||
locales \
|
||||
make \
|
||||
php7.0 \
|
||||
php7.0-dev \
|
||||
python-pip \
|
||||
re2c \
|
||||
unixodbc-dev \
|
||||
unzip && apt-get clean
|
||||
|
||||
apt-get -y install \
|
||||
apt-transport-https \
|
||||
apt-utils \
|
||||
autoconf \
|
||||
curl \
|
||||
g++ \
|
||||
gcc \
|
||||
git \
|
||||
lcov \
|
||||
libxml2-dev \
|
||||
locales \
|
||||
make \
|
||||
php7.0 \
|
||||
php7.0-dev \
|
||||
python-pip \
|
||||
re2c \
|
||||
unixodbc-dev \
|
||||
unzip && apt-get clean
|
||||
|
||||
ARG PHPSQLDIR=/REPO/msphpsql-dev
|
||||
ENV TEST_PHP_SQL_SERVER sql
|
||||
ENV TEST_PHP_SQL_UID sa
|
||||
ENV TEST_PHP_SQL_PWD Password12@
|
||||
ENV TEST_PHP_SQL_PWD Password123
|
||||
|
||||
# set locale to utf-8
|
||||
RUN locale-gen en_US.UTF-8
|
||||
|
@ -36,10 +36,7 @@ ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' LC_ALL='en_US.UTF-8'
|
|||
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 echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/mssql-ubuntu-xenial-release/ xenial main" > /etc/apt/sources.list.d/mssqlpreview.list
|
||||
#RUN apt-key adv --keyserver apt-mo.trafficmanager.net --recv-keys 417A0893
|
||||
RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && ACCEPT_EULA=Y apt-get install -y msodbcsql mssql-tools
|
||||
|
||||
ENV PATH="/opt/mssql-tools/bin:${PATH}"
|
||||
|
||||
#install coveralls
|
||||
|
@ -47,11 +44,9 @@ RUN pip install --upgrade pip && pip install cpp-coveralls
|
|||
|
||||
#Either Install git / download zip (One can see other strategies : https://ryanfb.github.io/etc/2015/07/29/git_strategies_for_docker.html )
|
||||
#One option is to get source from zip file of repository.
|
||||
|
||||
#another option is to copy source to build directory on image
|
||||
RUN mkdir -p $PHPSQLDIR
|
||||
COPY . $PHPSQLDIR
|
||||
|
||||
WORKDIR $PHPSQLDIR/source/
|
||||
|
||||
RUN chmod +x ./packagize.sh
|
||||
|
@ -79,6 +74,9 @@ RUN sed -i -e 's/TARGET_DATABASE/msphpsql_sqlsrv/g' MsSetup.inc
|
|||
RUN sed -i -e 's/TARGET_USERNAME/'"$TEST_PHP_SQL_UID"'/g' MsSetup.inc
|
||||
RUN sed -i -e 's/TARGET_PASSWORD/'"$TEST_PHP_SQL_PWD"'/g' MsSetup.inc
|
||||
|
||||
ENV REPORT_EXIT_STATUS 1
|
||||
ENV TEST_PHP_EXECUTABLE /usr/bin/php
|
||||
WORKDIR $PHPSQLDIR
|
||||
RUN chmod +x ./entrypoint.sh
|
||||
CMD /bin/bash ./entrypoint.sh
|
||||
|
||||
ENV REPORT_EXIT_STATUS 1
|
||||
ENV TEST_PHP_EXECUTABLE /usr/bin/php
|
353
README.md
353
README.md
|
@ -20,8 +20,8 @@ Thank you for taking time to take our February survey. Let us know how we are do
|
|||
|-------------------------|--------------------------| ------------------
|
||||
| [![av-image][]][av-site]| [![tv-image][]][tv-site] |[![Coverage Status][]][coveralls-site]
|
||||
|
||||
[av-image]: https://ci.appveyor.com/api/projects/status/github/Microsoft/msphpsql?branch=dev&svg=true
|
||||
[av-site]: https://ci.appveyor.com/project/Microsoft-PHPSQL/msphpsql
|
||||
[av-image]: https://ci.appveyor.com/api/projects/status/xhp4nq9ouljnhxqf/branch/dev?svg=true
|
||||
[av-site]: https://ci.appveyor.com/project/Microsoft-PHPSQL/msphpsql-frhmr/branch/dev
|
||||
[tv-image]: https://travis-ci.org/Microsoft/msphpsql.svg?branch=dev
|
||||
[tv-site]: https://travis-ci.org/Microsoft/msphpsql/
|
||||
[Coverage Status]: https://coveralls.io/repos/github/Microsoft/msphpsql/badge.svg?branch=dev
|
||||
|
@ -31,6 +31,7 @@ Thank you for taking time to take our February survey. Let us know how we are do
|
|||
|
||||
* [**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)
|
||||
* [**Docker**](https://hub.docker.com/r/lbosqmsft/mssql-php-msphpsql/)
|
||||
|
||||
|
@ -42,27 +43,16 @@ Thank you for taking time to take our February survey. Let us know how we are do
|
|||
|
||||
## Build (Windows)
|
||||
|
||||
Note: if you prefer, you can use the pre-compiled binary found [HERE](https://github.com/Azure/msphpsql/releases)
|
||||
Note: if you prefer, you can use the pre-compiled binary found [HERE](https://github.com/Microsoft/msphpsql/releases)
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
You must first be able to build PHP 7 without including these extensions. For help with doing this, see the [official PHP website][phpbuild] for building your own PHP on Windows.
|
||||
You must first be able to build PHP 7* 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
|
||||
|
||||
1. Copy the sqlsrv and/or pdo_sqlsrv source code directory from this repository into the ext subdirectory.
|
||||
|
||||
2. Run `buildconf.bat` to rebuild the configure.js script to include the driver.
|
||||
|
||||
3. Run `configure.bat --with-odbcver=0x0380 and the desired driver options (as below) [plus other options such as --disable-zts for the Non Thread Safe build]` to generate the makefile. You can run `configure.bat --help` to see what other options are available.
|
||||
* For SQLSRV use: `--enable-sqlsrv=shared`
|
||||
* For PDO_SQLSRV use: `--enable-pdo=shared --with-pdo-sqlsrv=shared`
|
||||
|
||||
4. Run `nmake`. It is suggested that you run the entire build. If you wish to do so, run `nmake clean` first.
|
||||
|
||||
5. To install the resulting build, run `nmake install` or just copy php_sqlsrv.dll and/or php_pdo_sqlsrv.dll to your PHP extension directory.
|
||||
|
||||
This software has been compiled and tested under PHP 7.0.8 using the Visual C++ 2015 compiler.
|
||||
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.
|
||||
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)
|
||||
|
||||
|
@ -75,155 +65,215 @@ This software has been compiled and tested under PHP 7.0.8 using the Visual C++
|
|||
|
||||
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).
|
||||
|
||||
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"`
|
||||
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.
|
||||
|
||||
3. Restart the Web server.
|
||||
|
||||
## Install (UNIX)
|
||||
The following instructions assume a clean environment and show how to install PHP 7.x, Microsoft ODBC driver, apache, and Microsoft PHP drivers on Ubuntu 15, 16, RedHat 7 and Mac OS X. To see how to get PHP SQLSRV drivers running on Debian, please visit [Wiki](https://github.com/Microsoft/msphpsql/wiki/Dockerfile-for-getting-pdo_sqlsrv-for-PHP-7.0-on-Debian-in-3-ways). Note that Debian is not officially supported and this instruction hasn't been tested in our test lab.
|
||||
The following instructions assume a clean environment and show how to install PHP 7.x, Microsoft ODBC driver, Apache, and Microsoft PHP drivers on Ubuntu 15, 16, RedHat 7, Debian 8, SUSE 12, and macOS.
|
||||
|
||||
### Step 1: Install PHP7+
|
||||
|
||||
#### PHP 7.0
|
||||
|
||||
**Ubuntu 15.04, Ubuntu 15.10**
|
||||
**Ubuntu 15.10**
|
||||
|
||||
sudo su
|
||||
sh -c 'echo "deb http://packages.dotdeb.org jessie all \ndeb-src http://packages.dotdeb.org jessie all" >> /etc/apt/sources.list'
|
||||
apt-get update
|
||||
apt-get install php7.0 php7.0-fpm php-pear php7.0-dev mcrypt php7.0-mcrypt php-mbstring php7.0-xml re2c gcc g++
|
||||
sudo su
|
||||
sh -c 'echo "deb http://packages.dotdeb.org jessie all \ndeb-src http://packages.dotdeb.org jessie all" >> /etc/apt/sources.list'
|
||||
apt-get update
|
||||
apt-get install php7.0 php7.0-fpm php-pear php7.0-dev mcrypt php7.0-mcrypt php-mbstring php7.0-xml
|
||||
|
||||
|
||||
**Ubuntu 16.04**
|
||||
|
||||
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 re2c gcc g++
|
||||
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
|
||||
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
|
||||
|
||||
**Mac OS X**
|
||||
**Debian 8**
|
||||
|
||||
/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
|
||||
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
|
||||
|
||||
**SUSE 12**
|
||||
|
||||
sudo su
|
||||
zypper refresh
|
||||
zypper install -y php7 php7-pear php7-devel
|
||||
|
||||
**macOS**
|
||||
|
||||
/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
|
||||
|
||||
Note that there are no PHP 7.1 packages available for Ubuntu 15.10.
|
||||
|
||||
**Ubuntu 16.04**
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
**Mac OS X**
|
||||
|
||||
/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
|
||||
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**
|
||||
|
||||
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**
|
||||
|
||||
/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 15.10**
|
||||
|
||||
sudo su
|
||||
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
|
||||
curl https://packages.microsoft.com/config/ubuntu/15.10/prod.list > /etc/apt/sources.list.d/mssql-release.list
|
||||
exit
|
||||
sudo apt-get update
|
||||
sudo ACCEPT_EULA=Y apt-get install msodbcsql mssql-tools
|
||||
sudo apt-get install unixodbc-dev
|
||||
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile
|
||||
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
sudo su
|
||||
curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
|
||||
curl https://packages.microsoft.com/config/ubuntu/15.10/prod.list > /etc/apt/sources.list.d/mssql-release.list
|
||||
exit
|
||||
sudo apt-get update
|
||||
sudo ACCEPT_EULA=Y apt-get install msodbcsql mssql-tools
|
||||
sudo apt-get install unixodbc-dev
|
||||
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile
|
||||
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
|
||||
|
||||
**Ubuntu 16.04**
|
||||
|
||||
sudo su
|
||||
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
|
||||
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
|
||||
|
||||
**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
|
||||
|
||||
**Mac OS X**
|
||||
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
|
||||
|
||||
brew tap microsoft/msodbcsql https://github.com/Microsoft/homebrew-mssql-release
|
||||
brew update
|
||||
brew install msodbcsql
|
||||
brew install mssql-tools
|
||||
brew install autoconf
|
||||
**Debian 8**
|
||||
|
||||
*Note: You need to make sure you install PHP 7+ before you proceed to step 3. The Microsoft PHP Drivers for SQL Server will only work for PHP 7+.
|
||||
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
|
||||
|
||||
**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**
|
||||
|
||||
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: The first step is not required in Mac OS X. PECL installs the stable version when version is not specified. You may run `sudo pecl search sqlsrv` to search for the latest releases and `sudo pecl install sqlsrv-[version]` to install a specific version. Drivers are Mac-compatible starting from `4.1.7preview` release.
|
||||
*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
|
||||
sudo pecl install sqlsrv
|
||||
sudo pecl install pdo_sqlsrv
|
||||
|
||||
On all systems, run:
|
||||
|
||||
pecl install sqlsrv
|
||||
pecl install pdo_sqlsrv
|
||||
|
||||
### Step 4: Install and Configure Apache
|
||||
|
||||
#### PHP 7.0
|
||||
|
||||
**Ubuntu**
|
||||
**Ubuntu and Debian**
|
||||
|
||||
sudo su
|
||||
apt-get install libapache2-mod-php7.0 apache2
|
||||
|
@ -232,19 +282,29 @@ The following instructions assume a clean environment and show how to install PH
|
|||
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
|
||||
exit
|
||||
|
||||
|
||||
**RedHat**
|
||||
|
||||
sudo yum install httpd
|
||||
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
|
||||
|
||||
**Mac OS X**
|
||||
**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**
|
||||
**Ubuntu and Debian**
|
||||
|
||||
sudo su
|
||||
apt-get install libapache2-mod-php7.1 apache2
|
||||
|
@ -253,35 +313,48 @@ The following instructions assume a clean environment and show how to install PH
|
|||
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
|
||||
exit
|
||||
|
||||
|
||||
**RedHat**
|
||||
|
||||
sudo yum install httpd
|
||||
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
|
||||
|
||||
**Mac OS X**
|
||||
**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**
|
||||
**Ubuntu, Debian, and SUSE**
|
||||
|
||||
sudo service apache2 restart
|
||||
sudo systemctl restart apache2
|
||||
|
||||
**RedHat**
|
||||
|
||||
sudo apachectl restart
|
||||
|
||||
**Mac OS X**
|
||||
sudo systemctl restart httpd
|
||||
|
||||
sudo apachectl restart
|
||||
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
|
||||
|
||||
*Note to RedHat users: SELinux is installed by default and runs in Enforcing mode. To allow Apache to connect to database through SELinux, do this `sudo setsebool -P httpd_can_network_connect_db 1`
|
||||
|
||||
### Step 6: Create your sample app
|
||||
Navigate to `/var/www/html` (`/usr/local/var/www/htdocs` on Mac) and create a new file called testsql.php. Copy and paste the following code in tetsql.php and change the servername, username, password and databasename.
|
||||
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";
|
||||
|
@ -338,7 +411,7 @@ For samples, please see the sample folder. For setup instructions, see [here](h
|
|||
## 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 parameter using emulate prepare is not supported.
|
||||
- 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.
|
||||
|
@ -370,11 +443,11 @@ version number MAY have trailing pre-release version to indicate the stability,
|
|||
*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.
|
||||
|
||||
|
||||
|
||||
|
||||
## Future Plans
|
||||
- Expand SQL 16 Feature Support (example: Always Encrypted).
|
||||
- Build Verification/Fundamental Tests.
|
||||
- Add More Verification/Fundamental Tests.
|
||||
- Bug Fixes.
|
||||
|
||||
## Guidelines for Reporting Issues
|
||||
|
@ -395,15 +468,15 @@ 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 once they solidify over the next few weeks.
|
||||
**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.
|
||||
|
||||
**Q:** What's next?
|
||||
|
||||
**A:** On July 20, 2016 we released the early technical preview for our PHP Driver. We will continue releasing frequent technical previews until we reach production quality.
|
||||
**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.
|
||||
|
||||
**Q:** Is Microsoft taking pull requests for this project?
|
||||
|
||||
**A:** We will not be seeking to take pull requests until GA, Build Verification, and Fundamental tests are released. At this point Microsoft will also begin actively developing using this GitHub project as the prime repository.
|
||||
**A:** Yes. Please submit pull requests to the **dev** branch and not the **master** branch.
|
||||
|
||||
|
||||
|
||||
|
@ -417,7 +490,7 @@ This project has adopted the Microsoft Open Source Code of Conduct. For more inf
|
|||
|
||||
## Resources
|
||||
|
||||
**Documentation**: [MSDN Online Documentation][phpdoc]. Please note that this documentation is not yet updated for PHP 7.
|
||||
**Documentation**: [MSDN Online Documentation][phpdoc].
|
||||
|
||||
**Team Blog**: Browse our blog for comments and announcements from the team in the [team blog][blog].
|
||||
|
||||
|
|
|
@ -166,6 +166,12 @@ 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%
|
||||
- php run-tests.php -p php.exe %APPVEYOR_BUILD_FOLDER%\test\functional\sqlsrv\*.phpt > %APPVEYOR_BUILD_FOLDER%\test\functional\sqlsrv.log 2>&1
|
||||
- type %APPVEYOR_BUILD_FOLDER%\test\functional\sqlsrv.log
|
||||
- php run-tests.php -p php.exe %APPVEYOR_BUILD_FOLDER%\test\functional\pdo_sqlsrv\*.phpt > %APPVEYOR_BUILD_FOLDER%\test\functional\pdo_sqlsrv.log 2>&1
|
||||
|
|
100
buildscripts/README.md
Normal file
100
buildscripts/README.md
Normal file
|
@ -0,0 +1,100 @@
|
|||
# Windows
|
||||
|
||||
## Prerequisites
|
||||
|
||||
To build extensions for
|
||||
1. PHP 7.0* or PHP 7.1*
|
||||
* install Visual Studio 2015 and make sure C++ tools are enabled.
|
||||
2. PHP 7.2*
|
||||
* install Visual Studio 2017, including Visual C++ toolset and the Windows SDK components.
|
||||
|
||||
To use the sample build scripts `builddrivers.py` and `buildtools.py`, install Python 3.x and Git for Windows (which comes with Visual Studio 2017). If `git` is unrecognized in a regular command prompt, make sure the environment path is set up correctly.
|
||||
|
||||
## Compile the drivers
|
||||
|
||||
You must first be able to build PHP 7.* without including our PHP extensions. For help with building PHP 7.0* or PHP 7.1* in Windows, see the [official PHP website](https://wiki.php.net/internals/windows/stepbystepbuild). For PHP 7.2 or above, visit [PHP SDK page](https://github.com/OSTC/php-sdk-binary-tools) for new instructions.
|
||||
|
||||
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.
|
||||
|
||||
### Manually building from source
|
||||
|
||||
1. Download the *source* directory from this repository
|
||||
|
||||
2. Make a copy of the *shared* folder as a subfolder in *sqlsrv* and/or *pdo_sqlsrv* folder
|
||||
|
||||
3. Copy the *sqlsrv* and/or *pdo_sqlsrv* folder(s) into the PHP source *ext* subdirectory
|
||||
|
||||
4. Run `buildconf --force` to rebuild the configure.js script to include the *sqlsrv* and/or *pdo_sqlsrv* driver(s).
|
||||
|
||||
5. Run `configure.bat` with the desired driver options (as shown below) to generate the makefile. You can run `configure.bat --help` to see what other options are available. For example, for non-thread safe build, add this option `--disable-zts`.
|
||||
* For SQLSRV add: `--enable-sqlsrv=shared`
|
||||
* For PDO_SQLSRV add: `--enable-pdo --with-pdo-sqlsrv=shared`
|
||||
|
||||
6. Run `nmake`. Optionally, you can run `nmake clean` first.
|
||||
|
||||
7. To install the drivers, there are two ways:
|
||||
* Run `nmake install`, or
|
||||
* Copy the drivers:
|
||||
* Find the directory where the newly compiled *php.exe* is
|
||||
* Locate the compiled *php_sqlsrv.dll* and/or *php_pdo_sqlsrv.dll*
|
||||
* Copy the dll(s) to the *ext* subfolder
|
||||
|
||||
### Using the sample build scripts
|
||||
|
||||
The sample build scripts, `builddrivers.py` and `buildtools.py`, can be used to build our extensions for PHP in Windows.
|
||||
|
||||
#### Overview
|
||||
|
||||
When asked to provide the PHP version, you should enter values like `7.1.7`. If it's alpha, beta, or RC version, make sure the name you provide matches the PHP tag name without the prefix `php-`. For example, for PHP 7.2 beta 2, the tag name is `php-7.2.0beta2`, so you will enter `7.2.0beta2`. Visit [PHP SRC]( https://github.com/php/php-src) to find the appropriate tag names.
|
||||
|
||||
PHP recommends to unzip the PHP SDK into the shortest possible path, preferrably somewhere near the root drive. Therefore, this script will, by default, create a `php-sdk` folder in the C:\ drive, and this `php-sdk` directory tree will remain unless you remove it yourself. For ongoing development, we suggest you keep it around. The build scripts will handle updating the PHP SDK if a new version is available.
|
||||
|
||||
#### Steps
|
||||
|
||||
1. Launch a regular `cmd` prompt
|
||||
|
||||
2. Change to the directory where the Python scripts `builddrivers.py` and `buildtools.py` are
|
||||
|
||||
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`)
|
||||
* 64-bit?
|
||||
* Thread safe?
|
||||
* Driver?
|
||||
* Debug enabled?
|
||||
* Download source from GitHub?
|
||||
* For `yes/no` questions, you can simply hit `ENTER` key for `yes`. Other questions are self-explanatory.
|
||||
|
||||
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`
|
||||
|
||||
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.)
|
||||
* `clean` to remove previous builds (binaries)
|
||||
* `superclean` to remove the entire `php-<version>-src` directory, which is often unnecessary
|
||||
|
||||
6. If you choose not to download from a GitHub repository, you will be asked to provide the full path to your local Source folder.
|
||||
|
||||
7. If the compilation is successful, you will be given the option to rebuild or quit.
|
||||
|
||||
#### Troubleshooting
|
||||
|
||||
If something went wrong or the build failed, the log file will be launched (you can find the log files in `C:\php-sdk`). Otherwise, the log file will not be shown, and they remain in `C:\php-sdk` until you remove them manually.
|
||||
|
||||
In addition to the log files in `C:\php-sdk`, you can examine the contents of `C:\php-sdk\phpsdk-build-task.bat`, which is overwritten every time you run the build scripts.
|
||||
|
||||
#### Testing mode and/or setting alternative destination
|
||||
|
||||
If your main goal is to build the drivers for testing, and/or there is no need to keep the `php-sdk` directory around, you can invoke `py builddrivers.py` with the necessary command-line arguments plus `--TESTING`, which turns on the *testing* mode (it is False by default).
|
||||
|
||||
Setting the testing mode automatically turns off the looping mechanism. When the build is finished, you will find a copy of the drivers (unless the build failed) and the `php-sdk` folder in the same directory of these Python scripts.
|
||||
|
||||
In addition, you can set an alternative destination using `--DESTPATH=<some valid path>`, which is **None** by default. Note that these two options are *not* available in the interactive mode. However, they are particularly useful for testing purposes (such as testing in a virtual machine) in which these build scripts are copied to a temporary folder. After the drivers have been successfully compiled and copied to the designated location, the temporary folder can be safely removed.
|
||||
|
||||
|
||||
|
||||
|
||||
|
288
buildscripts/builddrivers.py
Normal file
288
buildscripts/builddrivers.py
Normal file
|
@ -0,0 +1,288 @@
|
|||
#!/usr/bin/python3
|
||||
#########################################################################################
|
||||
#
|
||||
# Description: This script helps to build drivers in a Windows environment for PHP 7+ (32-bit/64-bit)
|
||||
#
|
||||
# Requirement:
|
||||
# python 3.x
|
||||
# PHP SDK and PHP Source
|
||||
# Driver source code folder / GitHub repository
|
||||
# Visual Studio 2015 (PHP 7.0* and 7.1*) and Visual Studio 2017 (PHP 7.2*)
|
||||
#
|
||||
# Execution: Run with command line with required options.
|
||||
# Examples:
|
||||
# py builddrivers.py (for interactive mode)
|
||||
# py builddrivers.py --PHPVER=7.0.22 --ARCH=x64 --THREAD=nts --DRIVER=all --DEBUG
|
||||
#
|
||||
# Output: Build the drivers using PHP SDK. When running for local development, if build is unsuccessful,
|
||||
# the log file will be launched for examination. Otherwise, the drivers will be renamed
|
||||
# and copied to the designated location (if defined).
|
||||
#
|
||||
#############################################################################################
|
||||
|
||||
import sys
|
||||
import shutil
|
||||
import os.path
|
||||
import argparse
|
||||
from buildtools import BuildUtil
|
||||
|
||||
class BuildDriver(object):
|
||||
"""Build sqlsrv and/or pdo_sqlsrv drivers with PHP source with the following properties:
|
||||
|
||||
Attributes:
|
||||
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
|
||||
source_path # path to a local source folder
|
||||
testing # whether the user has turned on testing mode
|
||||
"""
|
||||
|
||||
def __init__(self, phpver, driver, arch, thread, debug, repo, branch, download, path, testing):
|
||||
self.util = BuildUtil(phpver, driver, arch, thread, debug)
|
||||
self.repo = repo
|
||||
self.branch = branch
|
||||
self.download_source = download
|
||||
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()
|
||||
print('PHP Version: ', self.util.phpver)
|
||||
print('Arch: ', self.util.arch)
|
||||
print('Thread: ', self.util.thread)
|
||||
print('Driver: ', self.util.driver)
|
||||
print('Debug enabled: ', self.util.debug_enabled)
|
||||
print()
|
||||
|
||||
def clean_or_remove(self, root_dir, work_dir):
|
||||
"""Only check this for local development and not rebuilding. If the php source directory
|
||||
already exists, this will prompt user whether to rebuild, clean, or superclean, the last option
|
||||
will remove the entire php source directory.
|
||||
|
||||
:param root_dir: the C:\ drive
|
||||
:param work_dir: the directory of this script
|
||||
:outcome: the old binaries, if exist, will be removed
|
||||
"""
|
||||
phpsrc = self.util.phpsrc_root(root_dir)
|
||||
if os.path.exists( phpsrc ):
|
||||
print(phpsrc + " exists.")
|
||||
build_choice = validate_input("(r)ebuild for the same configuration, (c)lean otherwise, (s)uperclean if unsure ", "r/c/s")
|
||||
self.make_clean = False
|
||||
if build_choice == 'r':
|
||||
print('Will rebuild the binaries')
|
||||
# only the old binaries based on the current configuration will be removed
|
||||
self.util.remove_prev_build(root_dir)
|
||||
elif build_choice == 'c':
|
||||
print('Will make clean')
|
||||
self.make_clean = True
|
||||
# all old builds are removed, and this step is necessary because
|
||||
# the user might have changed the configuration
|
||||
self.util.remove_old_builds(root_dir)
|
||||
else:
|
||||
print('Will remove ' + phpsrc)
|
||||
os.system('RMDIR /s /q ' + phpsrc)
|
||||
|
||||
os.chdir(work_dir) # change back to the working directory
|
||||
|
||||
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.
|
||||
|
||||
:param root_dir: the root directory
|
||||
:param logfile: the name of the logfile
|
||||
:outcome: the drivers and symbols will renamed and placed in the appropriate location(s)
|
||||
|
||||
"""
|
||||
work_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
if self.download_source:
|
||||
# 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.")
|
||||
|
||||
print('Copying source files from', source)
|
||||
|
||||
os.system('ROBOCOPY ' + source + '\shared ' + work_dir + '\Source\shared /xx /xo ')
|
||||
os.system('ROBOCOPY ' + source + '\sqlsrv ' + work_dir + '\Source\sqlsrv /xx /xo ')
|
||||
os.system('ROBOCOPY ' + source + '\pdo_sqlsrv ' + work_dir + '\Source\pdo_sqlsrv /xx /xo ')
|
||||
|
||||
print('Start building PHP with the extension...')
|
||||
|
||||
# If not testing, dest should be the root drive. Otherwise, dest should be None.
|
||||
dest = None if self.testing else root_dir
|
||||
|
||||
# ext_dir is the directory where we can find the built extension(s)
|
||||
ext_dir = self.util.build_drivers(self.make_clean, dest, logfile)
|
||||
|
||||
# Copy the binaries if a destination path is defined
|
||||
if self.dest_path is not None:
|
||||
dest_drivers = os.path.join(self.dest_path, self.util.major_version(), self.util.arch)
|
||||
dest_symbols = os.path.join(dest_drivers, 'Symbols', self.util.thread)
|
||||
|
||||
# All intermediate directories will be created in order to create the leaf directory
|
||||
if os.path.exists(dest_symbols) == False:
|
||||
os.makedirs(dest_symbols)
|
||||
|
||||
# Now copy all the binaries
|
||||
if self.util.driver == 'all':
|
||||
self.util.copy_binary(ext_dir, dest_drivers, 'sqlsrv', '.dll')
|
||||
self.util.copy_binary(ext_dir, dest_symbols, 'sqlsrv', '.pdb')
|
||||
self.util.copy_binary(ext_dir, dest_drivers, 'pdo_sqlsrv', '.dll')
|
||||
self.util.copy_binary(ext_dir, dest_symbols, 'pdo_sqlsrv', '.pdb')
|
||||
else:
|
||||
self.util.copy_binary(ext_dir, dest_drivers, self.util.driver, '.dll')
|
||||
self.util.copy_binary(ext_dir, dest_symbols, self.util.driver, '.pdb')
|
||||
|
||||
|
||||
def build(self):
|
||||
"""This is the main entry point of building drivers for PHP.
|
||||
For development, this will loop till the user decides to quit.
|
||||
"""
|
||||
self.show_config()
|
||||
|
||||
work_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
root_dir = 'C:' + os.sep
|
||||
|
||||
quit = False
|
||||
while not quit:
|
||||
if not self.rebuild and not self.testing:
|
||||
self.clean_or_remove(root_dir, work_dir)
|
||||
|
||||
logfile = self.util.get_logfile_name()
|
||||
|
||||
try:
|
||||
self.build_extensions(root_dir, logfile)
|
||||
print('Build Completed')
|
||||
except:
|
||||
print('Something went wrong, launching log file', logfile)
|
||||
# display log file only when not testing
|
||||
if not self.testing:
|
||||
os.startfile(os.path.join(root_dir, 'php-sdk', logfile))
|
||||
os.chdir(work_dir)
|
||||
break
|
||||
|
||||
if not self.testing:
|
||||
choice = input("Rebuild using the same configuration(yes) or quit (no) [yes/no]: ")
|
||||
choice = choice.lower()
|
||||
if choice == 'yes' or choice == 'y' or choice == '':
|
||||
print('Rebuilding drivers...')
|
||||
self.make_clean = False
|
||||
self.rebuild = True
|
||||
self.util.remove_prev_build(root_dir)
|
||||
else:
|
||||
quit = True
|
||||
else:
|
||||
quit = True
|
||||
|
||||
os.chdir(work_dir)
|
||||
|
||||
def validate_input(question, values):
|
||||
"""Return the user selected value, and it must be valid based on *values*."""
|
||||
while True:
|
||||
options = values.split('/')
|
||||
prompt = '[' + values + ']'
|
||||
value = input(question + prompt + ': ')
|
||||
value = value.lower()
|
||||
if not value in options:
|
||||
print("An invalid choice is entered. Choose from", prompt)
|
||||
else:
|
||||
break
|
||||
return value
|
||||
|
||||
################################### Main Function ###################################
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--PHPVER', help="PHP version, e.g. 7.1.*, 7.2.* etc.")
|
||||
parser.add_argument('--ARCH', choices=['x64', 'x86'])
|
||||
parser.add_argument('--THREAD', choices=['nts', 'ts'])
|
||||
parser.add_argument('--DRIVER', default='all', choices=['all', 'sqlsrv', 'pdo_sqlsrv'], help="driver to build (default: all)")
|
||||
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('--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)")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
phpver = args.PHPVER
|
||||
arch = args.ARCH
|
||||
thread = args.THREAD
|
||||
driver = args.DRIVER
|
||||
debug = args.DEBUG
|
||||
repo = args.REPO
|
||||
branch = args.BRANCH
|
||||
download = args.SOURCE is False
|
||||
path = args.DESTPATH
|
||||
testing = args.TESTING
|
||||
|
||||
if phpver is None:
|
||||
# starts interactive mode, testing mode is False
|
||||
# will not prompt for drivers' destination path, which is None by default
|
||||
while True:
|
||||
# perform some minimal checks
|
||||
phpver = input("PHP Version (e.g. 7.1.* or 7.2.*): ")
|
||||
if phpver == '':
|
||||
print('Empty PHP version entered! Please try again.')
|
||||
elif phpver[0] < '7':
|
||||
print('Only PHP 7.0 or above is supported. Please try again.')
|
||||
else:
|
||||
break
|
||||
|
||||
arch_version = input("64-bit? [y/n]: ")
|
||||
thread = validate_input("Thread safe? ", "nts/ts")
|
||||
driver = validate_input("Driver to build? ", "all/sqlsrv/pdo_sqlsrv")
|
||||
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 == '':
|
||||
repo = 'Microsoft'
|
||||
if branch == '':
|
||||
branch = 'dev'
|
||||
|
||||
arch_version = arch_version.lower()
|
||||
arch = 'x64' if arch_version == 'yes' or arch_version == 'y' or arch_version == '' else 'x86'
|
||||
|
||||
debug_mode = debug_mode.lower()
|
||||
debug = debug_mode == 'yes' or debug_mode == 'y' or debug_mode == ''
|
||||
|
||||
builder = BuildDriver(phpver,
|
||||
driver,
|
||||
arch,
|
||||
thread,
|
||||
debug,
|
||||
repo,
|
||||
branch,
|
||||
download,
|
||||
path,
|
||||
testing)
|
||||
builder.build()
|
476
buildscripts/buildtools.py
Normal file
476
buildscripts/buildtools.py
Normal file
|
@ -0,0 +1,476 @@
|
|||
#!/usr/bin/python3
|
||||
#########################################################################################
|
||||
#
|
||||
# Description: The class BuildUtil will build Microsoft SQL Server PHP 7+ Drivers
|
||||
# for 32 bit and 64 bit.
|
||||
#
|
||||
# Requirement:
|
||||
# python 3.x
|
||||
# PHP SDK and PHP Source
|
||||
# Driver source code folder
|
||||
# Git for Windows
|
||||
# Visual Studio 2015 (PHP 7.0* and 7.1*) and Visual Studio 2017 (PHP 7.2*)
|
||||
#
|
||||
# Output: The drivers will be renamed and copied to the specified location.
|
||||
#
|
||||
#############################################################################################
|
||||
|
||||
import shutil
|
||||
import os.path
|
||||
import stat
|
||||
import datetime
|
||||
import urllib.request
|
||||
import zipfile
|
||||
import fileinput
|
||||
|
||||
class BuildUtil(object):
|
||||
"""Build sqlsrv and/or pdo_sqlsrv drivers with PHP source with the following properties:
|
||||
|
||||
Attributes:
|
||||
phpver # PHP version, e.g. 7.1.*, 7.2.* etc.
|
||||
driver # all, sqlsrv, or pdo_sqlsrv
|
||||
arch # x64 or x86
|
||||
thread # nts or ts
|
||||
debug_enabled # whether debug is enabled
|
||||
"""
|
||||
|
||||
def __init__(self, phpver, driver, arch, thread, debug_enabled = False):
|
||||
self.phpver = phpver
|
||||
self.driver = driver.lower()
|
||||
self.arch = arch.lower()
|
||||
self.thread = thread.lower()
|
||||
self.debug_enabled = debug_enabled
|
||||
|
||||
def major_version(self):
|
||||
"""Return the major version number based on the PHP version."""
|
||||
return self.phpver[0:3]
|
||||
|
||||
def version_label(self):
|
||||
"""Return the version label based on the PHP version."""
|
||||
major_ver = self.major_version()
|
||||
|
||||
if major_ver[2] == '0':
|
||||
version = major_ver[0]
|
||||
else:
|
||||
version = major_ver[0] + major_ver[2]
|
||||
return version
|
||||
|
||||
def driver_name(self, driver, suffix):
|
||||
"""Return the *driver* name with *suffix* after PHP is successfully compiled."""
|
||||
return 'php_' + driver + suffix
|
||||
|
||||
def driver_new_name(self, driver, suffix):
|
||||
"""Return the *driver* name with *suffix* based on PHP version and thread."""
|
||||
version = self.version_label()
|
||||
return 'php_' + driver + '_' + version + '_' + self.thread + suffix
|
||||
|
||||
def compiler_version(self):
|
||||
"""Return the appropriate compiler version based on PHP version."""
|
||||
VC = 'vc14'
|
||||
version = self.version_label()
|
||||
if version >= '72': # Compiler version for PHP 7.2 or above
|
||||
VC = 'vc15'
|
||||
return VC
|
||||
|
||||
def phpsrc_root(self, sdk_dir):
|
||||
"""Return the path to the PHP source folder based on *sdk_dir*."""
|
||||
vc = self.compiler_version()
|
||||
return os.path.join(sdk_dir, 'php-sdk', 'phpdev', vc, self.arch, 'php-'+self.phpver+'-src')
|
||||
|
||||
def build_abs_path(self, sdk_dir):
|
||||
"""Return the absolute path to the PHP build folder based on *sdk_dir*."""
|
||||
phpsrc = self.phpsrc_root(sdk_dir)
|
||||
|
||||
build_dir = 'Release'
|
||||
if self.debug_enabled:
|
||||
build_dir = 'Debug'
|
||||
|
||||
if self.thread == 'ts':
|
||||
build_dir = build_dir + '_TS'
|
||||
|
||||
if self.arch == 'x64':
|
||||
build_dir = self.arch + os.sep + build_dir
|
||||
|
||||
return os.path.join(phpsrc, build_dir)
|
||||
|
||||
def remove_old_builds(self, sdk_dir):
|
||||
"""Remove the extensions, e.g. the driver subfolders in php-7.*-src\ext."""
|
||||
print('Removing old builds...')
|
||||
|
||||
phpsrc = self.phpsrc_root(sdk_dir)
|
||||
ext_path = os.path.join(phpsrc, 'ext')
|
||||
if os.path.exists( ext_path ):
|
||||
shutil.rmtree(os.path.join(ext_path, 'sqlsrv'), ignore_errors=True)
|
||||
shutil.rmtree(os.path.join(ext_path, 'pdo_sqlsrv'), ignore_errors=True)
|
||||
|
||||
if self.arch == 'x64':
|
||||
shutil.rmtree(os.path.join(phpsrc, self.arch), ignore_errors=True)
|
||||
else:
|
||||
shutil.rmtree(os.path.join(phpsrc, 'Debug'), ignore_errors=True)
|
||||
shutil.rmtree(os.path.join(phpsrc, 'Debug_TS'), ignore_errors=True)
|
||||
shutil.rmtree(os.path.join(phpsrc, 'Release'), ignore_errors=True)
|
||||
shutil.rmtree(os.path.join(phpsrc, 'Release_TS'), ignore_errors=True)
|
||||
|
||||
def remove_prev_build(self, sdk_dir):
|
||||
"""Remove all binaries and source code in the Release* or Debug*
|
||||
folders according to the current configuration
|
||||
"""
|
||||
print('Removing previous build...')
|
||||
build_dir = self.build_abs_path(sdk_dir)
|
||||
if not os.path.exists(build_dir):
|
||||
return
|
||||
|
||||
os.chdir(build_dir)
|
||||
os.system('DEL *sqlsrv*')
|
||||
|
||||
# remove the extensions in the phpsrc's release* or debug* folder's ext subfolder
|
||||
release_ext_path = os.path.join(build_dir, 'ext')
|
||||
if os.path.exists( release_ext_path ):
|
||||
shutil.rmtree(os.path.join(release_ext_path, 'sqlsrv'), ignore_errors=True)
|
||||
shutil.rmtree(os.path.join(release_ext_path, 'pdo_sqlsrv'), ignore_errors=True)
|
||||
|
||||
# next remove the binaries too
|
||||
os.chdir(release_ext_path)
|
||||
os.system('DEL *sqlsrv*')
|
||||
|
||||
@staticmethod
|
||||
def get_logfile_name():
|
||||
"""Return the filename for the log file based on timestamp."""
|
||||
return 'Build_' + datetime.datetime.now().strftime("%Y%m%d_%H%M") + '.log'
|
||||
|
||||
@staticmethod
|
||||
def update_file_content(file, search_str, new_str):
|
||||
"""Find *search_str* and replace it by *new_str* in a *file*"""
|
||||
os.chmod(file, stat.S_IWRITE)
|
||||
with fileinput.FileInput(file, inplace=True) as f:
|
||||
for line in f:
|
||||
print(line.replace(search_str, new_str), end='')
|
||||
|
||||
@staticmethod
|
||||
def generateMMDD():
|
||||
"""Return the generated Microsoft PHP Build Version Number"""
|
||||
d = datetime.date.today()
|
||||
|
||||
startYear = 2009
|
||||
startMonth = 4
|
||||
passYear = int( '%02d' % d.year ) - startYear
|
||||
passMonth = int( '%02d' % d.month ) - startMonth
|
||||
MM = passYear * 12 + passMonth
|
||||
dd = d.day
|
||||
|
||||
MMDD = "" + str( MM )
|
||||
if( dd < 10 ):
|
||||
return MMDD + "0" + str( dd )
|
||||
else:
|
||||
return MMDD + str( dd )
|
||||
|
||||
@staticmethod
|
||||
def get_driver_version(version_file):
|
||||
"""Read the *version_file* and return the driver version."""
|
||||
with open(version_file) as f:
|
||||
for line in f:
|
||||
if 'SQLVERSION_MAJOR' in line: # major version
|
||||
major = line.split()[2]
|
||||
elif 'SQLVERSION_MINOR' in line: # minor version
|
||||
minor = line.split()[2]
|
||||
elif 'SQLVERSION_PATCH' in line: # patch
|
||||
patch = line.split()[2]
|
||||
break
|
||||
|
||||
return major + '.' + minor + '.' + patch
|
||||
|
||||
@staticmethod
|
||||
def write_lines_to_copy_source(driver, file):
|
||||
"""Write to file the commands to copy *driver* source."""
|
||||
source = '%currDir%' + os.sep + 'Source' + os.sep + driver
|
||||
dest = '%phpSrc%' + os.sep + 'ext' + os.sep + driver
|
||||
file.write('@CALL ROBOCOPY ' + source + ' ' + dest + ' /s /xx /xo' + os.linesep)
|
||||
|
||||
source = '%currDir%' + os.sep + 'Source' + os.sep + 'shared'
|
||||
dest = '%phpSrc%' + os.sep + 'ext' + os.sep + driver + os.sep + 'shared'
|
||||
file.write('@CALL ROBOCOPY ' + source + ' ' + dest + ' /s /xx /xo' + os.linesep)
|
||||
|
||||
@staticmethod
|
||||
def download_msphpsql_source(repo, branch, dest_folder = 'Source', clean_up = True):
|
||||
"""Download to *dest_folder* the msphpsql archive of the specified
|
||||
GitHub *repo* and *branch*. The downloaded files will be removed by default.
|
||||
"""
|
||||
try:
|
||||
work_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
temppath = os.path.join(work_dir, 'temp')
|
||||
if os.path.exists(temppath):
|
||||
shutil.rmtree(temppath)
|
||||
os.makedirs(temppath)
|
||||
os.chdir(temppath)
|
||||
|
||||
file = branch + '.zip'
|
||||
url = 'https://github.com/' + repo + '/msphpsql/archive/' + branch + '.zip'
|
||||
|
||||
print('Downloading ' + url + ' ...')
|
||||
try:
|
||||
with urllib.request.urlopen(url) as response, open(file, 'wb') as out_file:
|
||||
shutil.copyfileobj(response, out_file)
|
||||
except:
|
||||
print ("Resort to skip ssl verification...")
|
||||
# need to skip ssl verification on some agents
|
||||
# see https://www.python.org/dev/peps/pep-0476/
|
||||
with urllib.request.urlopen(url, context=ssl._create_unverified_context()) as response, open(file, 'wb') as out_file:
|
||||
shutil.copyfileobj(response, out_file)
|
||||
|
||||
print('Extracting ' + file + ' ...')
|
||||
zip = zipfile.ZipFile(file)
|
||||
zip.extractall()
|
||||
zip.close()
|
||||
|
||||
msphpsqlFolder = os.path.join(temppath, 'msphpsql-' + branch)
|
||||
source = os.path.join(msphpsqlFolder, 'source')
|
||||
os.chdir(work_dir)
|
||||
|
||||
os.system('ROBOCOPY ' + source + '\shared ' + dest_folder + '\shared /xx /xo')
|
||||
os.system('ROBOCOPY ' + source + '\pdo_sqlsrv ' + dest_folder + '\pdo_sqlsrv /xx /xo')
|
||||
os.system('ROBOCOPY ' + source + '\sqlsrv ' + dest_folder + '\sqlsrv /xx /xo')
|
||||
|
||||
if clean_up:
|
||||
shutil.rmtree(temppath)
|
||||
|
||||
except:
|
||||
print('Error occurred when downloading source')
|
||||
raise
|
||||
|
||||
def update_driver_source(self, source_dir, driver):
|
||||
"""Update the *driver* source in *source_path* with the
|
||||
latest version, file descriptions, etc.
|
||||
If debug is enabled, will remove the optimization flag
|
||||
"""
|
||||
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)
|
||||
config_file = os.path.join(driver_dir, 'config.w32')
|
||||
if driver == 'sqlsrv':
|
||||
self.update_file_content(config_file, 'ADD_FLAG( "CFLAGS_SQLSRV", "/O2" );', '')
|
||||
elif driver == 'pdo_sqlsrv':
|
||||
self.update_file_content(config_file, 'ADD_FLAG( "CFLAGS_PDO_SQLSRV", "/O2" );', '')
|
||||
|
||||
# Update Template.rc
|
||||
template_file = os.path.join(driver_dir, 'template.rc')
|
||||
if driver == 'sqlsrv':
|
||||
drivername = self.driver_new_name(driver, '.dll')
|
||||
self.update_file_content(template_file, 'FILE_NAME \"\\0\"', '"' + drivername + '\\0"')
|
||||
self.update_file_content(template_file, '\"Microsoft Drivers for PHP for SQL Server\\0\"', '"Microsoft Drivers for PHP for SQL Server (SQLSRV Driver)\\0"')
|
||||
elif driver == 'pdo_sqlsrv':
|
||||
drivername = self.driver_new_name(driver, '.dll')
|
||||
self.update_file_content(template_file, 'FILE_NAME \"\\0\"', '"' + drivername + '\\0"')
|
||||
self.update_file_content(template_file, '\"Microsoft Drivers for PHP for SQL Server\\0\"', '"Microsoft Drivers for PHP for SQL Server (PDO Driver)\\0"')
|
||||
|
||||
# Update Version.h
|
||||
version_file = os.path.join(source_dir, 'shared', 'version.h')
|
||||
build_number = self.generateMMDD()
|
||||
self.update_file_content(version_file, 'SQLVERSION_BUILD 0', 'SQLVERSION_BUILD ' + build_number)
|
||||
|
||||
# get the latest version
|
||||
version = self.get_driver_version(version_file) + '.' + build_number
|
||||
print('Driver version is: ', version)
|
||||
|
||||
# Update CREDIT file
|
||||
credits_file = os.path.join(driver_dir, 'CREDITS')
|
||||
if driver == 'sqlsrv':
|
||||
self.update_file_content(credits_file, 'Microsoft Drivers for PHP for SQL Server', 'Microsoft Drivers ' + version + ' for PHP for SQL Server (' + self.driver.upper() + ' driver)')
|
||||
elif driver == 'pdo_sqlsrv':
|
||||
self.update_file_content(credits_file, 'Microsoft Drivers for PHP for SQL Server (PDO driver)', 'Microsoft Drivers ' + version + ' for PHP for SQL Server (' + self.driver.upper() + ' driver)')
|
||||
|
||||
def generate_build_options(self):
|
||||
"""Return the generated build configuration and arguments"""
|
||||
cmd_line = ''
|
||||
if self.debug_enabled:
|
||||
cmd_line = ' --enable-debug '
|
||||
|
||||
if self.driver == 'all':
|
||||
cmd_line = ' --enable-sqlsrv=shared --enable-pdo --with-pdo-sqlsrv=shared ' + cmd_line
|
||||
else:
|
||||
if self.driver == 'sqlsrv':
|
||||
cmd_line = ' --enable-sqlsrv=shared ' + cmd_line
|
||||
else: # pdo_sqlsrv
|
||||
cmd_line = ' --enable-pdo --with-pdo-sqlsrv=shared ' + cmd_line
|
||||
|
||||
cmd_line = 'cscript configure.js --disable-all --enable-cli --enable-cgi --enable-embed' + cmd_line
|
||||
if self.thread == 'nts':
|
||||
cmd_line = cmd_line + ' --disable-zts'
|
||||
return cmd_line
|
||||
|
||||
def create_local_batch_file(self, make_clean, cmd_line, log_file):
|
||||
"""Generate the batch file to be picked up by the PHP starter script."""
|
||||
filename = 'phpsdk-build-task.bat'
|
||||
print('Generating ', filename)
|
||||
try:
|
||||
file = open(filename, 'w')
|
||||
file.write('@ECHO OFF' + os.linesep)
|
||||
file.write('SET currDir=%CD%' + os.linesep)
|
||||
file.write('SET LOG_NAME=%currDir%\\' + log_file + os.linesep)
|
||||
file.write('@CALL phpsdk_buildtree phpdev > %LOG_NAME% 2>&1' + os.linesep)
|
||||
|
||||
# for PHP version with release tags, such as 'RC', 'beta', etc.
|
||||
# we need to remove the hyphen '-' between the version number and tag
|
||||
# because in https://github.com/php/php-src the released tags have no hyphens
|
||||
|
||||
php_tag = 'php-' + self.phpver.replace('-', '')
|
||||
php_src = 'php-' + self.phpver +'-src'
|
||||
|
||||
# if not exists, check out the specified tag
|
||||
file.write('IF NOT EXIST ' + php_src + ' @CALL git clone -b ' + php_tag + ' --depth 1 --single-branch https://github.com/php/php-src.git ' + php_src + os.linesep)
|
||||
file.write('CD ' + php_src + os.linesep)
|
||||
file.write('SET phpSrc=%CD%' + os.linesep)
|
||||
file.write('@CALL phpsdk_deps -u >> %LOG_NAME% 2>&1' + os.linesep)
|
||||
|
||||
# copy source files to extension
|
||||
if self.driver == 'all':
|
||||
self.write_lines_to_copy_source('sqlsrv', file)
|
||||
self.write_lines_to_copy_source('pdo_sqlsrv', file)
|
||||
else:
|
||||
self.write_lines_to_copy_source(self.driver, file)
|
||||
|
||||
# configure and build
|
||||
file.write('@CALL buildconf --force >> %LOG_NAME% 2>&1' + os.linesep)
|
||||
file.write('@CALL ' + cmd_line + ' >> %LOG_NAME% 2>&1' + os.linesep)
|
||||
if make_clean:
|
||||
file.write('nmake clean >> %LOG_NAME% 2>&1' + os.linesep)
|
||||
file.write('nmake >> %LOG_NAME% 2>&1' + os.linesep)
|
||||
file.write('exit' + os.linesep)
|
||||
file.close()
|
||||
return filename
|
||||
except:
|
||||
print('Cannot create ', filename)
|
||||
|
||||
def build_drivers(self, make_clean = False, dest = None, log_file = None):
|
||||
"""Build sqlsrv/pdo_sqlsrv extensions for PHP, assuming the Source folder
|
||||
exists in the working directory, and this folder will be removed when the build
|
||||
is complete.
|
||||
"""
|
||||
work_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
# First, update the driver source file contents
|
||||
source_dir = os.path.join(work_dir, 'Source')
|
||||
if self.driver == 'all':
|
||||
self.update_driver_source(source_dir, 'sqlsrv')
|
||||
self.update_driver_source(source_dir, 'pdo_sqlsrv')
|
||||
else:
|
||||
self.update_driver_source(source_dir, self.driver)
|
||||
|
||||
# Next, generate the build configuration and arguments
|
||||
cmd_line = self.generate_build_options()
|
||||
print('cmd_line: ' + cmd_line)
|
||||
|
||||
# Generate a batch file based on the inputs
|
||||
if log_file is None:
|
||||
log_file = self.get_logfile_name()
|
||||
|
||||
batch_file = self.create_local_batch_file(make_clean, cmd_line, log_file)
|
||||
|
||||
# Reference: https://github.com/OSTC/php-sdk-binary-tools
|
||||
# Clone the master branch of PHP sdk if the directory does not exist
|
||||
print('Downloading the latest php SDK...')
|
||||
|
||||
# if *dest* is None, simply use the current working directory
|
||||
sdk_dir = dest
|
||||
copy_to_ext = True # this determines where to copy the binaries to
|
||||
if dest is None:
|
||||
sdk_dir = work_dir
|
||||
copy_to_ext = False
|
||||
|
||||
phpSDK = os.path.join(sdk_dir, 'php-sdk')
|
||||
if not os.path.exists( phpSDK ):
|
||||
os.system('git clone https://github.com/OSTC/php-sdk-binary-tools.git --branch master --single-branch --depth 1 ' + phpSDK)
|
||||
os.chdir(phpSDK)
|
||||
os.system('git pull ')
|
||||
|
||||
# Move the generated batch file to phpSDK for the php starter script
|
||||
sdk_batch_file = os.path.join(phpSDK, batch_file)
|
||||
if os.path.exists(sdk_batch_file):
|
||||
os.remove(sdk_batch_file)
|
||||
shutil.move(os.path.join(work_dir, batch_file), phpSDK)
|
||||
|
||||
sdk_source = os.path.join(phpSDK, 'Source')
|
||||
# Sometimes, for various reasons, the Source folder from previous build
|
||||
# might exist in phpSDK. If so, remove it first
|
||||
if os.path.exists(sdk_source):
|
||||
os.chmod(sdk_source, stat.S_IWRITE)
|
||||
shutil.rmtree(sdk_source, ignore_errors=True)
|
||||
shutil.move(source_dir, phpSDK)
|
||||
|
||||
# Invoke phpsdk-<vc>-<arch>.bat
|
||||
vc = self.compiler_version()
|
||||
starter_script = 'phpsdk-' + vc + '-' + self.arch + '.bat'
|
||||
print('Running starter script: ', starter_script)
|
||||
os.system(starter_script + ' -t ' + batch_file)
|
||||
|
||||
# Now we can safely remove the Source folder, because its contents have
|
||||
# already been modified prior to building the extensions
|
||||
shutil.rmtree(os.path.join(phpSDK, 'Source'), ignore_errors=True)
|
||||
|
||||
# Next, rename the newly compiled PHP extensions
|
||||
self.rename_binaries(sdk_dir)
|
||||
|
||||
# Final step, copy the binaries to the right place
|
||||
ext_dir = self.copy_binaries(sdk_dir, copy_to_ext)
|
||||
return ext_dir
|
||||
|
||||
def rename_binary(self, path, driver):
|
||||
"""Rename the *driver* binary (sqlsrv or pdo_sqlsrv) (only the dlls)."""
|
||||
driver_old_name = self.driver_name(driver, '.dll')
|
||||
driver_new_name = self.driver_new_name(driver, '.dll')
|
||||
|
||||
os.rename(os.path.join(path, driver_old_name), os.path.join(path, driver_new_name))
|
||||
|
||||
def rename_binaries(self, sdk_dir):
|
||||
"""Rename the sqlsrv and/or pdo_sqlsrv dlls according to the PHP
|
||||
version and thread.
|
||||
"""
|
||||
|
||||
# Derive the path to where the extensions are located
|
||||
ext_dir = self.build_abs_path(sdk_dir)
|
||||
print("Renaming binaries in ", ext_dir)
|
||||
|
||||
if self.driver == 'all':
|
||||
self.rename_binary(ext_dir, 'sqlsrv')
|
||||
self.rename_binary(ext_dir, 'pdo_sqlsrv')
|
||||
else:
|
||||
self.rename_binary(ext_dir, self.driver)
|
||||
|
||||
def copy_binary(self, from_dir, dest_dir, driver, suffix):
|
||||
"""Copy sqlsrv or pdo_sqlsrv binary (based on *suffix*) to *dest_dir*."""
|
||||
if suffix == '.dll':
|
||||
binary = self.driver_new_name(driver, suffix)
|
||||
else:
|
||||
binary = self.driver_name(driver, suffix)
|
||||
shutil.copy2(os.path.join(from_dir, binary), dest_dir)
|
||||
|
||||
def copy_binaries(self, sdk_dir, copy_to_ext):
|
||||
"""Copy the sqlsrv and/or pdo_sqlsrv binaries, including the pdb files,
|
||||
to the right place, depending on *copy_to_ext*. The default is to
|
||||
copy them to the 'ext' folder.
|
||||
"""
|
||||
build_dir = self.build_abs_path(sdk_dir)
|
||||
print('Copying the binaries from', build_dir)
|
||||
if copy_to_ext:
|
||||
dest_dir = os.path.join(build_dir, 'ext')
|
||||
else:
|
||||
# Simply make a copy of the binaries in sdk_dir
|
||||
dest_dir = sdk_dir
|
||||
|
||||
print('Destination:', dest_dir)
|
||||
|
||||
# Now copy the binaries
|
||||
if self.driver == 'all':
|
||||
self.copy_binary(build_dir, dest_dir, 'sqlsrv', '.dll')
|
||||
self.copy_binary(build_dir, dest_dir, 'sqlsrv', '.pdb')
|
||||
self.copy_binary(build_dir, dest_dir, 'pdo_sqlsrv', '.dll')
|
||||
self.copy_binary(build_dir, dest_dir, 'pdo_sqlsrv', '.pdb')
|
||||
else:
|
||||
self.copy_binary(build_dir, dest_dir, self.driver, '.dll')
|
||||
self.copy_binary(build_dir, dest_dir, self.driver, '.pdb')
|
||||
|
||||
return dest_dir
|
||||
|
16
entrypoint.sh
Normal file
16
entrypoint.sh
Normal file
|
@ -0,0 +1,16 @@
|
|||
set -e
|
||||
|
||||
testConnection="/opt/mssql-tools/bin/sqlcmd -S sql -U sa -P Password123"
|
||||
|
||||
for run in {1..10}; do
|
||||
|
||||
>&2 echo "SQL Server is starting up.."
|
||||
if $testConnection; then
|
||||
>&2 echo "SQL Server is up!"
|
||||
break;
|
||||
else
|
||||
sleep 6
|
||||
fi
|
||||
done
|
||||
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Contents: JScript build configuration used by buildconf.bat
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Contents: Implements the PDO object for PDO_SQLSRV
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
@ -30,8 +30,8 @@ namespace {
|
|||
|
||||
const char LAST_INSERT_ID_QUERY[] = "SELECT @@IDENTITY;";
|
||||
const size_t LAST_INSERT_ID_BUFF_LEN = 10; // size of the buffer to hold the string value of the last insert id integer
|
||||
const char TABLE_LAST_INSERT_ID_QUERY[] = "SELECT IDENT_CURRENT(%s)";
|
||||
const int LAST_INSERT_ID_QUERY_MAX_LEN = sizeof( TABLE_LAST_INSERT_ID_QUERY ) + SQL_MAX_SQLSERVERNAME + 2; // include the quotes
|
||||
const char SEQUENCE_CURRENT_VALUE_QUERY[] = "SELECT CURRENT_VALUE FROM SYS.SEQUENCES WHERE NAME=%s";
|
||||
const int LAST_INSERT_ID_QUERY_MAX_LEN = sizeof( SEQUENCE_CURRENT_VALUE_QUERY ) + SQL_MAX_SQLSERVERNAME + 2; // include the quotes
|
||||
|
||||
// List of PDO supported connection options.
|
||||
namespace PDOConnOptionNames {
|
||||
|
@ -43,6 +43,10 @@ const char AttachDBFileName[] = "AttachDbFileName";
|
|||
const char ConnectionPooling[] = "ConnectionPooling";
|
||||
const char Authentication[] = "Authentication";
|
||||
const char ColumnEncryption[] = "ColumnEncryption";
|
||||
const char CEKeystoreProvider[] = "CEKeystoreProvider";
|
||||
const char CEKeystoreName[] = "CEKeystoreName";
|
||||
const char CEKeystoreEncryptKey[] = "CEKeystoreEncryptKey";
|
||||
|
||||
#ifdef _WIN32
|
||||
const char ConnectRetryCount[] = "ConnectRetryCount";
|
||||
const char ConnectRetryInterval[] = "ConnectRetryInterval";
|
||||
|
@ -230,6 +234,33 @@ const connection_option PDO_CONN_OPTS[] = {
|
|||
CONN_ATTR_STRING,
|
||||
column_encryption_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::ConnectRetryCount,
|
||||
|
@ -1245,7 +1276,7 @@ char * pdo_sqlsrv_dbh_last_id( _Inout_ pdo_dbh_t *dbh, _In_z_ const char *name,
|
|||
size_t quoted_len = 0;
|
||||
int quoted = pdo_sqlsrv_dbh_quote( dbh, name, strlen( name ), "ed_table, "ed_len, PDO_PARAM_NULL TSRMLS_CC );
|
||||
SQLSRV_ASSERT( quoted, "PDO::lastInsertId failed to quote the table name.");
|
||||
snprintf( last_insert_id_query, LAST_INSERT_ID_QUERY_MAX_LEN, TABLE_LAST_INSERT_ID_QUERY, quoted_table );
|
||||
snprintf( last_insert_id_query, LAST_INSERT_ID_QUERY_MAX_LEN, SEQUENCE_CURRENT_VALUE_QUERY, quoted_table );
|
||||
sqlsrv_free( quoted_table );
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Contents: initialization routines for PDO_SQLSRV
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
//
|
||||
// Copyright Microsoft Corporation
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Contents: Implements the PDOStatement object for the PDO_SQLSRV
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Contents: Utility functions used by both connection or statement functions
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
@ -382,10 +382,26 @@ pdo_error PDO_ERRORS[] = {
|
|||
{ 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_AE_ERROR_DRIVER_NOT_INSTALLED,
|
||||
{ IMSSP, (SQLCHAR*) "This extension requires Microsoft ODBC Driver 17 or higher to "
|
||||
"communicate with SQL Server with ColumnEncryption attribute enabled.", -74, false }
|
||||
},
|
||||
},
|
||||
{ UINT_MAX, {} }
|
||||
};
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
//
|
||||
// Contents: Declarations for the extension
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Contents: Version resource
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// Contents: Contains functions for handling Windows format strings
|
||||
// and UTF-16 on non-Windows platforms
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// Contents: Contains functions for handling Windows format strings
|
||||
// and UTF-16 on non-Windows platforms
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Contents: Contains functions for handling UTF-16 on non-Windows platforms
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Contents: Contains functions for handling UTF-16 on non-Windows platforms
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -71,7 +71,7 @@ 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
|
||||
|
@ -148,7 +148,7 @@ sqlsrv_conn* core_sqlsrv_connect( _In_ sqlsrv_context& henv_cp, _In_ sqlsrv_cont
|
|||
build_connection_string_and_set_conn_attr(conn, server, uid, pwd, options_ht, valid_conn_opts, driver, conn_options TSRMLS_CC);
|
||||
bool missing_driver_error = false;
|
||||
if (conn->ce_option.enabled) {
|
||||
r = core_odbc_connect(conn, conn_options, DRIVER_VERSION::ODBC_DRIVER_13, wconn_string, wconn_len, missing_driver_error);
|
||||
r = core_odbc_connect(conn, conn_options, DRIVER_VERSION::ODBC_DRIVER_17, wconn_string, wconn_len, missing_driver_error);
|
||||
|
||||
CHECK_CUSTOM_ERROR(missing_driver_error, conn, SQLSRV_AE_ERROR_DRIVER_NOT_INSTALLED, get_processor_arch()) {
|
||||
throw core::CoreException();
|
||||
|
@ -156,7 +156,7 @@ sqlsrv_conn* core_sqlsrv_connect( _In_ sqlsrv_context& henv_cp, _In_ sqlsrv_cont
|
|||
}
|
||||
else {
|
||||
|
||||
for (std::size_t i = DRIVER_VERSION::ODBC_DRIVER_11; i <= DRIVER_VERSION::LAST; ++i) {
|
||||
for (std::size_t i = DRIVER_VERSION::ODBC_DRIVER_13; i <= DRIVER_VERSION::LAST; ++i) {
|
||||
r = core_odbc_connect(conn, conn_options, static_cast<DRIVER_VERSION>(i), wconn_string, wconn_len, missing_driver_error);
|
||||
// if it's a IM002, meaning that the correct ODBC driver is not installed
|
||||
CHECK_CUSTOM_ERROR(missing_driver_error && (i == DRIVER_VERSION::LAST), conn, SQLSRV_ERROR_DRIVER_NOT_INSTALLED, get_processor_arch()) {
|
||||
|
@ -176,6 +176,8 @@ 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.
|
||||
//
|
||||
|
@ -794,6 +796,66 @@ 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 = Z_STRLEN_P( conn->ce_option.ksp_name );
|
||||
unsigned int key_size = 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
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Contents: common initialization routines shared by PDO and sqlsrv
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Contents: Result sets
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
//
|
||||
// Contents: Core routines and constants shared by the Microsoft Drivers for PHP for SQL Server
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
@ -1047,10 +1047,14 @@ struct stmt_option;
|
|||
|
||||
// This holds the various details of column encryption.
|
||||
struct col_encryption_option {
|
||||
bool enabled; // column encryption enabled, false by default
|
||||
size_t key_size; // the length of ksp_encrypt_key without the NULL terminator
|
||||
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)
|
||||
col_encryption_option() : enabled( false ), key_size ( 0 ), ksp_required( false )
|
||||
{
|
||||
}
|
||||
};
|
||||
|
@ -1099,6 +1103,9 @@ const char ApplicationIntent[] = "ApplicationIntent";
|
|||
const char AttachDBFileName[] = "AttachDbFileName";
|
||||
const char Authentication[] = "Authentication";
|
||||
const char ColumnEncryption[] = "ColumnEncryption";
|
||||
const char CEKeystoreProvider[] = "CEKeystoreProvider";
|
||||
const char CEKeystoreName[] = "CEKeystoreName";
|
||||
const char CEKeystoreEncryptKey[] = "CEKeystoreEncryptKey";
|
||||
const char CharacterSet[] = "CharacterSet";
|
||||
const char ConnectionPooling[] = "ConnectionPooling";
|
||||
#ifdef _WIN32
|
||||
|
@ -1146,6 +1153,9 @@ enum SQLSRV_CONN_OPTIONS {
|
|||
SQLSRV_CONN_OPTION_MULTI_SUBNET_FAILOVER,
|
||||
SQLSRV_CONN_OPTION_AUTHENTICATION,
|
||||
SQLSRV_CONN_OPTION_COLUMNENCRYPTION,
|
||||
SQLSRV_CONN_OPTION_CEKEYSTORE_PROVIDER,
|
||||
SQLSRV_CONN_OPTION_CEKEYSTORE_NAME,
|
||||
SQLSRV_CONN_OPTION_CEKEYSTORE_ENCRYPT_KEY,
|
||||
SQLSRV_CONN_OPTION_TRANSPARANT_NETWORK_IP_RESOLUTION,
|
||||
#ifdef _WIN32
|
||||
SQLSRV_CONN_OPTION_CONN_RETRY_COUNT,
|
||||
|
@ -1649,6 +1659,10 @@ 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,
|
||||
|
||||
// Driver specific error codes starts from here.
|
||||
SQLSRV_ERROR_DRIVER_SPECIFIC = 1000,
|
||||
|
@ -2401,7 +2415,7 @@ struct str_conn_attr_func {
|
|||
|
||||
struct column_encryption_set_func {
|
||||
|
||||
static void func(connection_option const* option, zval* value, sqlsrv_conn* conn, std::string& conn_str TSRMLS_DC)
|
||||
static void func( _In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str TSRMLS_DC)
|
||||
{
|
||||
convert_to_string(value);
|
||||
const char* value_str = Z_STRVAL_P(value);
|
||||
|
@ -2419,4 +2433,37 @@ struct column_encryption_set_func {
|
|||
}
|
||||
};
|
||||
|
||||
struct ce_ksp_provider_set_func {
|
||||
|
||||
static void 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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CORE_SQLSRV_H
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Contents: Core routines that use statement handles shared between sqlsrv and pdo_sqlsrv
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Contents: Implementation of PHP streams for reading SQL Server data
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
//
|
||||
// Comments: Mostly error handling and some type handling
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// Contents: Contains functions for handling Windows format strings
|
||||
// and UTF-16 on non-Windows platforms
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// Contents: Contains a portable abstraction for interlocked, atomic
|
||||
// operations on int32_t and pointer types.
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// Contents: Contains a portable abstraction for interlocked, atomic
|
||||
// operations on int32_t and pointer types.
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// Contents: Contains a portable abstraction for interlocked, singly
|
||||
// linked list.
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Contents: Contains portable classes for localization
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
// Must be included in one c/cpp file per binary
|
||||
// A build error will occur if this inclusion policy is not followed
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -1,405 +1,444 @@
|
|||
#ifndef __msodbcsql_h__
|
||||
#define __msodbcsql_h__
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------------------
|
||||
// File: msodbcsql.h
|
||||
//
|
||||
// Contents: Routines that use statement handles. This is a subset of the header file msodbcsql.h in the ODBC Driver.
|
||||
//
|
||||
// Contents: This SDK is not supported under any Microsoft standard support
|
||||
// program or service. The information is provided AS IS without
|
||||
// warranty of any kind. Microsoft disclaims all implied
|
||||
// warranties including, without limitation, any implied
|
||||
// warranties of merchantability or of fitness for a particular
|
||||
// purpose. The entire risk arising out of the use of this SDK
|
||||
// remains with you. In no event shall Microsoft, its authors, or
|
||||
// anyone else involved in the creation, production, or delivery
|
||||
// of this SDK be liable for any damages whatsoever (including,
|
||||
// without limitation, damages for loss of business profits,
|
||||
// business interruption, loss of business information, or other
|
||||
// pecuniary loss) arising out of the use of or inability to use
|
||||
// this SDK, even if Microsoft has been advised of the possibility
|
||||
// of such damages.
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""),
|
||||
// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//---------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#if !defined(SQLODBC_VER)
|
||||
#define SQLODBC_VER 1300
|
||||
#endif
|
||||
|
||||
#if SQLODBC_VER >= 1300
|
||||
|
||||
#define SQLODBC_PRODUCT_NAME_FULL_VER_ANSI "Microsoft ODBC Driver 13 for SQL Server"
|
||||
#define SQLODBC_PRODUCT_NAME_FULL_ANSI "Microsoft ODBC Driver for SQL Server"
|
||||
#define SQLODBC_PRODUCT_NAME_SHORT_VER_ANSI "ODBC Driver 13 for SQL Server"
|
||||
#define SQLODBC_PRODUCT_NAME_SHORT_ANSI "ODBC Driver for SQL Server"
|
||||
|
||||
#endif // SQLODBC_VER >= 1300
|
||||
|
||||
#define SQLODBC_PRODUCT_NAME_FULL_VER SQLODBC_PRODUCT_NAME_FULL_VER_ANSI
|
||||
#define SQLODBC_PRODUCT_NAME_FULL SQLODBC_PRODUCT_NAME_FULL_ANSI
|
||||
#define SQLODBC_PRODUCT_NAME_SHORT_VER SQLODBC_PRODUCT_NAME_SHORT_VER_ANSI
|
||||
#define SQLODBC_PRODUCT_NAME_SHORT SQLODBC_PRODUCT_NAME_SHORT_ANSI
|
||||
|
||||
#define SQLODBC_DRIVER_NAME SQLODBC_PRODUCT_NAME_SHORT_VER
|
||||
|
||||
// max SQL Server identifier length
|
||||
#define SQL_MAX_SQLSERVERNAME 128
|
||||
|
||||
|
||||
// SQLSetConnectAttr driver specific defines.
|
||||
// Microsoft has 1200 thru 1249 reserved for Microsoft ODBC Driver for SQL Server usage.
|
||||
// Connection attributes
|
||||
|
||||
#define SQL_COPT_SS_BASE 1200
|
||||
#define SQL_COPT_SS_INTEGRATED_SECURITY (SQL_COPT_SS_BASE+3) // Force integrated security on login
|
||||
#define SQL_COPT_SS_TRANSLATE (SQL_COPT_SS_BASE+20) // Perform code page translation
|
||||
#define SQL_COPT_SS_ENCRYPT (SQL_COPT_SS_BASE+23) // Allow strong encryption for data
|
||||
#define SQL_COPT_SS_MARS_ENABLED (SQL_COPT_SS_BASE+24) // Multiple active result set per connection
|
||||
#define SQL_COPT_SS_TXN_ISOLATION (SQL_COPT_SS_BASE+27) // Used to set/get any driver-specific or ODBC-defined TXN iso level
|
||||
#define SQL_COPT_SS_TRUST_SERVER_CERTIFICATE (SQL_COPT_SS_BASE+28) // Trust server certificate
|
||||
|
||||
// SQLSetStmtAttr Microsoft ODBC Driver for SQL Server specific defines.
|
||||
// Statement attributes
|
||||
|
||||
#define SQL_SOPT_SS_BASE 1225
|
||||
#define SQL_SOPT_SS_TEXTPTR_LOGGING (SQL_SOPT_SS_BASE+0) // Text pointer logging
|
||||
#define SQL_SOPT_SS_NOBROWSETABLE (SQL_SOPT_SS_BASE+3) // Set NOBROWSETABLE option
|
||||
#define SQL_SOPT_SS_COLUMN_ENCRYPTION (SQL_SOPT_SS_BASE+13)// Sets the column encryption mode
|
||||
// Define old names
|
||||
#define SQL_TEXTPTR_LOGGING SQL_SOPT_SS_TEXTPTR_LOGGING
|
||||
#define SQL_COPT_SS_BASE_EX 1240
|
||||
#define SQL_COPT_SS_WARN_ON_CP_ERROR (SQL_COPT_SS_BASE_EX+3) // Issues warning when data from the server had a loss during code page conversion.
|
||||
#define SQL_COPT_SS_CONNECTION_DEAD (SQL_COPT_SS_BASE_EX+4) // dbdead SQLGetConnectOption only. It will try to ping the server. Expensive connection check
|
||||
#define SQL_COPT_SS_APPLICATION_INTENT (SQL_COPT_SS_BASE_EX+7) // Application Intent
|
||||
#define SQL_COPT_SS_MULTISUBNET_FAILOVER (SQL_COPT_SS_BASE_EX+8) // Multi-subnet Failover
|
||||
#define SQL_COPT_SS_TNIR (SQL_COPT_SS_BASE_EX+9) // Transparent Network IP Resolution
|
||||
#define SQL_COPT_SS_COLUMN_ENCRYPTION (SQL_COPT_SS_BASE_EX+10)// Column Encryption Enabled or Disabled
|
||||
#define SQL_COPT_SS_CEKEYSTOREPROVIDER (SQL_COPT_SS_BASE_EX+11)// Load a keystore provider or read the list of loaded keystore providers
|
||||
#define SQL_COPT_SS_CEKEYSTOREDATA (SQL_COPT_SS_BASE_EX+12)// Communicate with loaded keystore providers
|
||||
#define SQL_COPT_SS_TRUSTEDCMKPATHS (SQL_COPT_SS_BASE_EX+13)// List of trusted CMK paths
|
||||
#define SQL_COPT_SS_CEKCACHETTL (SQL_COPT_SS_BASE_EX+14)// Symmetric Key Cache TTL
|
||||
#define SQL_COPT_SS_AUTHENTICATION (SQL_COPT_SS_BASE_EX+15)// The authentication method used for the connection
|
||||
|
||||
// SQLColAttributes driver specific defines.
|
||||
// SQLSetDescField/SQLGetDescField driver specific defines.
|
||||
// Microsoft has 1200 thru 1249 reserved for Microsoft ODBC Driver for SQL Server usage.
|
||||
|
||||
#define SQL_CA_SS_BASE 1200
|
||||
#define SQL_CA_SS_COLUMN_SSTYPE (SQL_CA_SS_BASE+0) // dbcoltype/dbalttype
|
||||
#define SQL_CA_SS_COLUMN_UTYPE (SQL_CA_SS_BASE+1) // dbcolutype/dbaltutype
|
||||
#define SQL_CA_SS_NUM_ORDERS (SQL_CA_SS_BASE+2) // dbnumorders
|
||||
#define SQL_CA_SS_COLUMN_ORDER (SQL_CA_SS_BASE+3) // dbordercol
|
||||
#define SQL_CA_SS_COLUMN_VARYLEN (SQL_CA_SS_BASE+4) // dbvarylen
|
||||
#define SQL_CA_SS_NUM_COMPUTES (SQL_CA_SS_BASE+5) // dbnumcompute
|
||||
#define SQL_CA_SS_COMPUTE_ID (SQL_CA_SS_BASE+6) // dbnextrow status return
|
||||
#define SQL_CA_SS_COMPUTE_BYLIST (SQL_CA_SS_BASE+7) // dbbylist
|
||||
#define SQL_CA_SS_COLUMN_ID (SQL_CA_SS_BASE+8) // dbaltcolid
|
||||
#define SQL_CA_SS_COLUMN_OP (SQL_CA_SS_BASE+9) // dbaltop
|
||||
#define SQL_CA_SS_COLUMN_SIZE (SQL_CA_SS_BASE+10) // dbcollen
|
||||
#define SQL_CA_SS_COLUMN_HIDDEN (SQL_CA_SS_BASE+11) // Column is hidden (FOR BROWSE)
|
||||
#define SQL_CA_SS_COLUMN_KEY (SQL_CA_SS_BASE+12) // Column is key column (FOR BROWSE)
|
||||
#define SQL_CA_SS_COLUMN_COLLATION (SQL_CA_SS_BASE+14) // Column collation (only for chars)
|
||||
#define SQL_CA_SS_VARIANT_TYPE (SQL_CA_SS_BASE+15)
|
||||
#define SQL_CA_SS_VARIANT_SQL_TYPE (SQL_CA_SS_BASE+16)
|
||||
#define SQL_CA_SS_VARIANT_SERVER_TYPE (SQL_CA_SS_BASE+17)
|
||||
|
||||
// XML, CLR UDT, and table valued parameter related metadata
|
||||
#define SQL_CA_SS_UDT_CATALOG_NAME (SQL_CA_SS_BASE+18) // UDT catalog name
|
||||
#define SQL_CA_SS_UDT_SCHEMA_NAME (SQL_CA_SS_BASE+19) // UDT schema name
|
||||
#define SQL_CA_SS_UDT_TYPE_NAME (SQL_CA_SS_BASE+20) // UDT type name
|
||||
#define SQL_CA_SS_XML_SCHEMACOLLECTION_CATALOG_NAME (SQL_CA_SS_BASE+22) // Name of the catalog that contains XML Schema collection
|
||||
#define SQL_CA_SS_XML_SCHEMACOLLECTION_SCHEMA_NAME (SQL_CA_SS_BASE+23) // Name of the schema that contains XML Schema collection
|
||||
#define SQL_CA_SS_XML_SCHEMACOLLECTION_NAME (SQL_CA_SS_BASE+24) // Name of the XML Schema collection
|
||||
#define SQL_CA_SS_CATALOG_NAME (SQL_CA_SS_BASE+25) // Catalog name
|
||||
#define SQL_CA_SS_SCHEMA_NAME (SQL_CA_SS_BASE+26) // Schema name
|
||||
#define SQL_CA_SS_TYPE_NAME (SQL_CA_SS_BASE+27) // Type name
|
||||
|
||||
// table valued parameter related metadata
|
||||
#define SQL_CA_SS_COLUMN_COMPUTED (SQL_CA_SS_BASE+29) // column is computed
|
||||
#define SQL_CA_SS_COLUMN_IN_UNIQUE_KEY (SQL_CA_SS_BASE+30) // column is part of a unique key
|
||||
#define SQL_CA_SS_COLUMN_SORT_ORDER (SQL_CA_SS_BASE+31) // column sort order
|
||||
#define SQL_CA_SS_COLUMN_SORT_ORDINAL (SQL_CA_SS_BASE+32) // column sort ordinal
|
||||
#define SQL_CA_SS_COLUMN_HAS_DEFAULT_VALUE (SQL_CA_SS_BASE+33) // column has default value for all rows of the table valued parameter
|
||||
|
||||
// sparse column related metadata
|
||||
#define SQL_CA_SS_IS_COLUMN_SET (SQL_CA_SS_BASE+34) // column is a column-set column for sparse columns
|
||||
|
||||
// Legacy datetime related metadata
|
||||
#define SQL_CA_SS_SERVER_TYPE (SQL_CA_SS_BASE+35) // column type to send on the wire for datetime types
|
||||
|
||||
// force column encryption
|
||||
#define SQL_CA_SS_FORCE_ENCRYPT (SQL_CA_SS_BASE+36) // indicate mandatory encryption for this parameter
|
||||
|
||||
#define SQL_CA_SS_MAX_USED (SQL_CA_SS_BASE+37)
|
||||
// Defines for use with SQL_COPT_SS_INTEGRATED_SECURITY - Pre-Connect Option only
|
||||
#define SQL_IS_OFF 0L // Integrated security isn't used
|
||||
#define SQL_IS_ON 1L // Integrated security is used
|
||||
#define SQL_IS_DEFAULT SQL_IS_OFF
|
||||
// Defines for use with SQL_COPT_SS_TRANSLATE
|
||||
#define SQL_XL_OFF 0L // Code page translation is not performed
|
||||
#define SQL_XL_ON 1L // Code page translation is performed
|
||||
#define SQL_XL_DEFAULT SQL_XL_ON
|
||||
// Defines for use with SQL_SOPT_SS_TEXTPTR_LOGGING
|
||||
#define SQL_TL_OFF 0L // No logging on text pointer ops
|
||||
#define SQL_TL_ON 1L // Logging occurs on text pointer ops
|
||||
#define SQL_TL_DEFAULT SQL_TL_ON
|
||||
// Defines for use with SQL_SOPT_SS_NOBROWSETABLE
|
||||
#define SQL_NB_OFF 0L // NO_BROWSETABLE is off
|
||||
#define SQL_NB_ON 1L // NO_BROWSETABLE is on
|
||||
#define SQL_NB_DEFAULT SQL_NB_OFF
|
||||
// Defines for use with SQL_SOPT_SS_COLUMN_ENCRYPTION
|
||||
#define SQL_CE_DISABLED 0L // Disabled
|
||||
#define SQL_CE_RESULTSETONLY 1L // Decryption Only (resultsets and return values)
|
||||
#define SQL_CE_ENABLED 3L // Enabled (both encryption and decryption)
|
||||
// Defines for use with SQL_COPT_SS_COLUMN_ENCRYPTION
|
||||
#define SQL_COLUMN_ENCRYPTION_DISABLE 0L
|
||||
#define SQL_COLUMN_ENCRYPTION_ENABLE 1L
|
||||
#define SQL_COLUMN_ENCRYPTION_DEFAULT SQL_COLUMN_ENCRYPTION_DISABLE
|
||||
// Defines for use with SQL_COPT_SS_CEKCACHETTL
|
||||
#define SQL_CEKCACHETTL_DEFAULT 7200L // TTL value in seconds (2 hours)
|
||||
// SQL_COPT_SS_ENCRYPT
|
||||
#define SQL_EN_OFF 0L
|
||||
#define SQL_EN_ON 1L
|
||||
// SQL_COPT_SS_TRUST_SERVER_CERTIFICATE
|
||||
#define SQL_TRUST_SERVER_CERTIFICATE_NO 0L
|
||||
#define SQL_TRUST_SERVER_CERTIFICATE_YES 1L
|
||||
// SQL_COPT_SS_WARN_ON_CP_ERROR
|
||||
#define SQL_WARN_NO 0L
|
||||
#define SQL_WARN_YES 1L
|
||||
// SQL_COPT_SS_MARS_ENABLED
|
||||
#define SQL_MARS_ENABLED_NO 0L
|
||||
#define SQL_MARS_ENABLED_YES 1L
|
||||
// SQL_TXN_ISOLATION_OPTION bitmasks
|
||||
#define SQL_TXN_SS_SNAPSHOT 0x00000020L
|
||||
|
||||
// The following are defines for SQL_CA_SS_COLUMN_SORT_ORDER
|
||||
#define SQL_SS_ORDER_UNSPECIFIED 0L
|
||||
#define SQL_SS_DESCENDING_ORDER 1L
|
||||
#define SQL_SS_ASCENDING_ORDER 2L
|
||||
#define SQL_SS_ORDER_DEFAULT SQL_SS_ORDER_UNSPECIFIED
|
||||
|
||||
// Driver specific SQL data type defines.
|
||||
// Microsoft has -150 thru -199 reserved for Microsoft ODBC Driver for SQL Server usage.
|
||||
|
||||
#define SQL_SS_VARIANT (-150)
|
||||
#define SQL_SS_UDT (-151)
|
||||
#define SQL_SS_XML (-152)
|
||||
#define SQL_SS_TABLE (-153)
|
||||
#define SQL_SS_TIME2 (-154)
|
||||
#define SQL_SS_TIMESTAMPOFFSET (-155)
|
||||
|
||||
// Local types to be used with SQL_CA_SS_SERVER_TYPE
|
||||
#define SQL_SS_TYPE_DEFAULT 0L
|
||||
#define SQL_SS_TYPE_SMALLDATETIME 1L
|
||||
#define SQL_SS_TYPE_DATETIME 2L
|
||||
|
||||
// Extended C Types range 4000 and above. Range of -100 thru 200 is reserved by Driver Manager.
|
||||
#define SQL_C_TYPES_EXTENDED 0x04000L
|
||||
|
||||
// SQL_SS_LENGTH_UNLIMITED is used to describe the max length of
|
||||
// VARCHAR(max), VARBINARY(max), NVARCHAR(max), and XML columns
|
||||
|
||||
#define SQL_SS_LENGTH_UNLIMITED 0
|
||||
|
||||
// User Data Type definitions.
|
||||
// Returned by SQLColAttributes/SQL_CA_SS_COLUMN_UTYPE.
|
||||
|
||||
#define SQLudtBINARY 3
|
||||
#define SQLudtBIT 16
|
||||
#define SQLudtBITN 0
|
||||
#define SQLudtCHAR 1
|
||||
#define SQLudtDATETIM4 22
|
||||
#define SQLudtDATETIME 12
|
||||
#define SQLudtDATETIMN 15
|
||||
#define SQLudtDECML 24
|
||||
#define SQLudtDECMLN 26
|
||||
#define SQLudtFLT4 23
|
||||
#define SQLudtFLT8 8
|
||||
#define SQLudtFLTN 14
|
||||
#define SQLudtIMAGE 20
|
||||
#define SQLudtINT1 5
|
||||
#define SQLudtINT2 6
|
||||
#define SQLudtINT4 7
|
||||
#define SQLudtINTN 13
|
||||
#define SQLudtMONEY 11
|
||||
#define SQLudtMONEY4 21
|
||||
#define SQLudtMONEYN 17
|
||||
#define SQLudtNUM 10
|
||||
#define SQLudtNUMN 25
|
||||
#define SQLudtSYSNAME 18
|
||||
#define SQLudtTEXT 19
|
||||
#define SQLudtTIMESTAMP 80
|
||||
#define SQLudtUNIQUEIDENTIFIER 0
|
||||
#define SQLudtVARBINARY 4
|
||||
#define SQLudtVARCHAR 2
|
||||
#define MIN_USER_DATATYPE 256
|
||||
|
||||
// Aggregate operator types.
|
||||
// Returned by SQLColAttributes/SQL_CA_SS_COLUMN_OP.
|
||||
|
||||
#define SQLAOPSTDEV 0x30 // Standard deviation
|
||||
#define SQLAOPSTDEVP 0x31 // Standard deviation population
|
||||
#define SQLAOPVAR 0x32 // Variance
|
||||
#define SQLAOPVARP 0x33 // Variance population
|
||||
#define SQLAOPCNT 0x4b // Count
|
||||
#define SQLAOPSUM 0x4d // Sum
|
||||
#define SQLAOPAVG 0x4f // Average
|
||||
#define SQLAOPMIN 0x51 // Min
|
||||
#define SQLAOPMAX 0x52 // Max
|
||||
#define SQLAOPANY 0x53 // Any
|
||||
#define SQLAOPNOOP 0x56 // None
|
||||
|
||||
// SQLGetDiagField driver specific defines.
|
||||
// Microsoft has -1150 thru -1199 reserved for Microsoft ODBC Driver for SQL Server usage.
|
||||
|
||||
#define SQL_DIAG_SS_BASE (-1150)
|
||||
#define SQL_DIAG_SS_MSGSTATE (SQL_DIAG_SS_BASE)
|
||||
#define SQL_DIAG_SS_SEVERITY (SQL_DIAG_SS_BASE-1)
|
||||
#define SQL_DIAG_SS_SRVNAME (SQL_DIAG_SS_BASE-2)
|
||||
#define SQL_DIAG_SS_PROCNAME (SQL_DIAG_SS_BASE-3)
|
||||
#define SQL_DIAG_SS_LINE (SQL_DIAG_SS_BASE-4)
|
||||
|
||||
// SQLGetDiagField/SQL_DIAG_DYNAMIC_FUNCTION_CODE driver specific defines.
|
||||
// Microsoft has -200 thru -299 reserved for Microsoft ODBC Driver for SQL Server usage.
|
||||
|
||||
#define SQL_DIAG_DFC_SS_BASE (-200)
|
||||
#define SQL_DIAG_DFC_SS_ALTER_DATABASE (SQL_DIAG_DFC_SS_BASE-0)
|
||||
#define SQL_DIAG_DFC_SS_CHECKPOINT (SQL_DIAG_DFC_SS_BASE-1)
|
||||
#define SQL_DIAG_DFC_SS_CONDITION (SQL_DIAG_DFC_SS_BASE-2)
|
||||
#define SQL_DIAG_DFC_SS_CREATE_DATABASE (SQL_DIAG_DFC_SS_BASE-3)
|
||||
#define SQL_DIAG_DFC_SS_CREATE_DEFAULT (SQL_DIAG_DFC_SS_BASE-4)
|
||||
#define SQL_DIAG_DFC_SS_CREATE_PROCEDURE (SQL_DIAG_DFC_SS_BASE-5)
|
||||
#define SQL_DIAG_DFC_SS_CREATE_RULE (SQL_DIAG_DFC_SS_BASE-6)
|
||||
#define SQL_DIAG_DFC_SS_CREATE_TRIGGER (SQL_DIAG_DFC_SS_BASE-7)
|
||||
#define SQL_DIAG_DFC_SS_CURSOR_DECLARE (SQL_DIAG_DFC_SS_BASE-8)
|
||||
#define SQL_DIAG_DFC_SS_CURSOR_OPEN (SQL_DIAG_DFC_SS_BASE-9)
|
||||
#define SQL_DIAG_DFC_SS_CURSOR_FETCH (SQL_DIAG_DFC_SS_BASE-10)
|
||||
#define SQL_DIAG_DFC_SS_CURSOR_CLOSE (SQL_DIAG_DFC_SS_BASE-11)
|
||||
#define SQL_DIAG_DFC_SS_DEALLOCATE_CURSOR (SQL_DIAG_DFC_SS_BASE-12)
|
||||
#define SQL_DIAG_DFC_SS_DBCC (SQL_DIAG_DFC_SS_BASE-13)
|
||||
#define SQL_DIAG_DFC_SS_DISK (SQL_DIAG_DFC_SS_BASE-14)
|
||||
#define SQL_DIAG_DFC_SS_DROP_DATABASE (SQL_DIAG_DFC_SS_BASE-15)
|
||||
#define SQL_DIAG_DFC_SS_DROP_DEFAULT (SQL_DIAG_DFC_SS_BASE-16)
|
||||
#define SQL_DIAG_DFC_SS_DROP_PROCEDURE (SQL_DIAG_DFC_SS_BASE-17)
|
||||
#define SQL_DIAG_DFC_SS_DROP_RULE (SQL_DIAG_DFC_SS_BASE-18)
|
||||
#define SQL_DIAG_DFC_SS_DROP_TRIGGER (SQL_DIAG_DFC_SS_BASE-19)
|
||||
#define SQL_DIAG_DFC_SS_DUMP_DATABASE (SQL_DIAG_DFC_SS_BASE-20)
|
||||
#define SQL_DIAG_DFC_SS_BACKUP_DATABASE (SQL_DIAG_DFC_SS_BASE-20)
|
||||
#define SQL_DIAG_DFC_SS_DUMP_TABLE (SQL_DIAG_DFC_SS_BASE-21)
|
||||
#define SQL_DIAG_DFC_SS_DUMP_TRANSACTION (SQL_DIAG_DFC_SS_BASE-22)
|
||||
#define SQL_DIAG_DFC_SS_BACKUP_TRANSACTION (SQL_DIAG_DFC_SS_BASE-22)
|
||||
#define SQL_DIAG_DFC_SS_GOTO (SQL_DIAG_DFC_SS_BASE-23)
|
||||
#define SQL_DIAG_DFC_SS_INSERT_BULK (SQL_DIAG_DFC_SS_BASE-24)
|
||||
#define SQL_DIAG_DFC_SS_KILL (SQL_DIAG_DFC_SS_BASE-25)
|
||||
#define SQL_DIAG_DFC_SS_LOAD_DATABASE (SQL_DIAG_DFC_SS_BASE-26)
|
||||
#define SQL_DIAG_DFC_SS_RESTORE_DATABASE (SQL_DIAG_DFC_SS_BASE-26)
|
||||
#define SQL_DIAG_DFC_SS_LOAD_HEADERONLY (SQL_DIAG_DFC_SS_BASE-27)
|
||||
#define SQL_DIAG_DFC_SS_RESTORE_HEADERONLY (SQL_DIAG_DFC_SS_BASE-27)
|
||||
#define SQL_DIAG_DFC_SS_LOAD_TABLE (SQL_DIAG_DFC_SS_BASE-28)
|
||||
#define SQL_DIAG_DFC_SS_LOAD_TRANSACTION (SQL_DIAG_DFC_SS_BASE-29)
|
||||
#define SQL_DIAG_DFC_SS_RESTORE_TRANSACTION (SQL_DIAG_DFC_SS_BASE-29)
|
||||
#define SQL_DIAG_DFC_SS_PRINT (SQL_DIAG_DFC_SS_BASE-30)
|
||||
#define SQL_DIAG_DFC_SS_RAISERROR (SQL_DIAG_DFC_SS_BASE-31)
|
||||
#define SQL_DIAG_DFC_SS_READTEXT (SQL_DIAG_DFC_SS_BASE-32)
|
||||
#define SQL_DIAG_DFC_SS_RECONFIGURE (SQL_DIAG_DFC_SS_BASE-33)
|
||||
#define SQL_DIAG_DFC_SS_RETURN (SQL_DIAG_DFC_SS_BASE-34)
|
||||
#define SQL_DIAG_DFC_SS_SELECT_INTO (SQL_DIAG_DFC_SS_BASE-35)
|
||||
#define SQL_DIAG_DFC_SS_SET (SQL_DIAG_DFC_SS_BASE-36)
|
||||
#define SQL_DIAG_DFC_SS_SET_IDENTITY_INSERT (SQL_DIAG_DFC_SS_BASE-37)
|
||||
#define SQL_DIAG_DFC_SS_SET_ROW_COUNT (SQL_DIAG_DFC_SS_BASE-38)
|
||||
#define SQL_DIAG_DFC_SS_SET_STATISTICS (SQL_DIAG_DFC_SS_BASE-39)
|
||||
#define SQL_DIAG_DFC_SS_SET_TEXTSIZE (SQL_DIAG_DFC_SS_BASE-40)
|
||||
#define SQL_DIAG_DFC_SS_SETUSER (SQL_DIAG_DFC_SS_BASE-41)
|
||||
#define SQL_DIAG_DFC_SS_SHUTDOWN (SQL_DIAG_DFC_SS_BASE-42)
|
||||
#define SQL_DIAG_DFC_SS_TRANS_BEGIN (SQL_DIAG_DFC_SS_BASE-43)
|
||||
#define SQL_DIAG_DFC_SS_TRANS_COMMIT (SQL_DIAG_DFC_SS_BASE-44)
|
||||
#define SQL_DIAG_DFC_SS_TRANS_PREPARE (SQL_DIAG_DFC_SS_BASE-45)
|
||||
#define SQL_DIAG_DFC_SS_TRANS_ROLLBACK (SQL_DIAG_DFC_SS_BASE-46)
|
||||
#define SQL_DIAG_DFC_SS_TRANS_SAVE (SQL_DIAG_DFC_SS_BASE-47)
|
||||
#define SQL_DIAG_DFC_SS_TRUNCATE_TABLE (SQL_DIAG_DFC_SS_BASE-48)
|
||||
#define SQL_DIAG_DFC_SS_UPDATE_STATISTICS (SQL_DIAG_DFC_SS_BASE-49)
|
||||
#define SQL_DIAG_DFC_SS_UPDATETEXT (SQL_DIAG_DFC_SS_BASE-50)
|
||||
#define SQL_DIAG_DFC_SS_USE (SQL_DIAG_DFC_SS_BASE-51)
|
||||
#define SQL_DIAG_DFC_SS_WAITFOR (SQL_DIAG_DFC_SS_BASE-52)
|
||||
#define SQL_DIAG_DFC_SS_WRITETEXT (SQL_DIAG_DFC_SS_BASE-53)
|
||||
#define SQL_DIAG_DFC_SS_DENY (SQL_DIAG_DFC_SS_BASE-54)
|
||||
#define SQL_DIAG_DFC_SS_SET_XCTLVL (SQL_DIAG_DFC_SS_BASE-55)
|
||||
#define SQL_DIAG_DFC_SS_MERGE (SQL_DIAG_DFC_SS_BASE-56)
|
||||
|
||||
// Severity codes for SQL_DIAG_SS_SEVERITY
|
||||
#define EX_ANY 0
|
||||
#define EX_INFO 10
|
||||
#define EX_MAXISEVERITY EX_INFO
|
||||
#define EX_MISSING 11
|
||||
#define EX_TYPE 12
|
||||
#define EX_DEADLOCK 13
|
||||
#define EX_PERMIT 14
|
||||
#define EX_SYNTAX 15
|
||||
#define EX_USER 16
|
||||
#define EX_RESOURCE 17
|
||||
#define EX_INTOK 18
|
||||
#define MAXUSEVERITY EX_INTOK
|
||||
#define EX_LIMIT 19
|
||||
#define EX_CMDFATAL 20
|
||||
#define MINFATALERR EX_CMDFATAL
|
||||
#define EX_DBFATAL 21
|
||||
#define EX_TABCORRUPT 22
|
||||
#define EX_DBCORRUPT 23
|
||||
#define EX_HARDWARE 24
|
||||
#define EX_CONTROL 25
|
||||
|
||||
// Data is defined to be past the end of the structure header.
|
||||
// This is accepted by MSVC, GCC, and C99 standard but former emits
|
||||
// unnecessary warning, hence it has to be disabled.
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4200)
|
||||
#endif
|
||||
|
||||
// Communication between the driver and application via the CEKeystoreData structure
|
||||
typedef struct CEKeystoreData
|
||||
{
|
||||
wchar_t *name;
|
||||
unsigned int dataSize;
|
||||
char data[];
|
||||
} CEKEYSTOREDATA;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
// The following constants are for the Azure Key Vault configuration interface
|
||||
#define AKV_CONFIG_FLAGS 0
|
||||
#define AKVCFG_AUTHMODE 0x0000000F
|
||||
#define AKVCFG_AUTHMODE_ACCESSTOKEN 0
|
||||
#define AKVCFG_AUTHMODE_CLIENTKEY 1
|
||||
#define AKVCFG_AUTHMODE_PASSWORD 2
|
||||
#define AKVCFG_AUTHMODE_INTEGRATED 3
|
||||
#define AKVCFG_AUTHMODE_CERTIFICATE 4
|
||||
#define AKVCFG_NOAUTORENEW 0x00000010
|
||||
|
||||
#define AKV_CONFIG_PRINCIPALID 1
|
||||
#define AKV_CONFIG_AUTHSECRET 2
|
||||
#define AKV_CONFIG_ACCESSTOKEN 3
|
||||
#define AKV_CONFIG_TOKENEXPIRY 4
|
||||
#define AKV_CONFIG_MAXRETRIES 5
|
||||
#define AKV_CONFIG_RETRYTIMEOUT 6
|
||||
#define AKV_CONFIG_RETRYWAIT 7
|
||||
|
||||
#define AKV_CONFIG_RESET 255
|
||||
#endif // __msodbcsql_h__
|
||||
|
||||
#ifndef __msodbcsql_h__
|
||||
#define __msodbcsql_h__
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------------------
|
||||
// File: msodbcsql.h
|
||||
//
|
||||
// Contents: Routines that use statement handles. This is a subset of the header file msodbcsql.h in the ODBC Driver.
|
||||
//
|
||||
// Contents: This SDK is not supported under any Microsoft standard support
|
||||
// program or service. The information is provided AS IS without
|
||||
// warranty of any kind. Microsoft disclaims all implied
|
||||
// warranties including, without limitation, any implied
|
||||
// warranties of merchantability or of fitness for a particular
|
||||
// purpose. The entire risk arising out of the use of this SDK
|
||||
// remains with you. In no event shall Microsoft, its authors, or
|
||||
// anyone else involved in the creation, production, or delivery
|
||||
// of this SDK be liable for any damages whatsoever (including,
|
||||
// without limitation, damages for loss of business profits,
|
||||
// business interruption, loss of business information, or other
|
||||
// pecuniary loss) arising out of the use of or inability to use
|
||||
// this SDK, even if Microsoft has been advised of the possibility
|
||||
// of such damages.
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""),
|
||||
// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//---------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#if !defined(SQLODBC_VER)
|
||||
#define SQLODBC_VER 1300
|
||||
#endif
|
||||
|
||||
#if SQLODBC_VER >= 1300
|
||||
|
||||
#define SQLODBC_PRODUCT_NAME_FULL_VER_ANSI "Microsoft ODBC Driver 13 for SQL Server"
|
||||
#define SQLODBC_PRODUCT_NAME_FULL_ANSI "Microsoft ODBC Driver for SQL Server"
|
||||
#define SQLODBC_PRODUCT_NAME_SHORT_VER_ANSI "ODBC Driver 13 for SQL Server"
|
||||
#define SQLODBC_PRODUCT_NAME_SHORT_ANSI "ODBC Driver for SQL Server"
|
||||
|
||||
#endif // SQLODBC_VER >= 1300
|
||||
|
||||
#define SQLODBC_PRODUCT_NAME_FULL_VER SQLODBC_PRODUCT_NAME_FULL_VER_ANSI
|
||||
#define SQLODBC_PRODUCT_NAME_FULL SQLODBC_PRODUCT_NAME_FULL_ANSI
|
||||
#define SQLODBC_PRODUCT_NAME_SHORT_VER SQLODBC_PRODUCT_NAME_SHORT_VER_ANSI
|
||||
#define SQLODBC_PRODUCT_NAME_SHORT SQLODBC_PRODUCT_NAME_SHORT_ANSI
|
||||
|
||||
#define SQLODBC_DRIVER_NAME SQLODBC_PRODUCT_NAME_SHORT_VER
|
||||
|
||||
// max SQL Server identifier length
|
||||
#define SQL_MAX_SQLSERVERNAME 128
|
||||
|
||||
|
||||
// SQLSetConnectAttr driver specific defines.
|
||||
// Microsoft has 1200 thru 1249 reserved for Microsoft ODBC Driver for SQL Server usage.
|
||||
// Connection attributes
|
||||
|
||||
#define SQL_COPT_SS_BASE 1200
|
||||
#define SQL_COPT_SS_INTEGRATED_SECURITY (SQL_COPT_SS_BASE+3) // Force integrated security on login
|
||||
#define SQL_COPT_SS_TRANSLATE (SQL_COPT_SS_BASE+20) // Perform code page translation
|
||||
#define SQL_COPT_SS_ENCRYPT (SQL_COPT_SS_BASE+23) // Allow strong encryption for data
|
||||
#define SQL_COPT_SS_MARS_ENABLED (SQL_COPT_SS_BASE+24) // Multiple active result set per connection
|
||||
#define SQL_COPT_SS_TXN_ISOLATION (SQL_COPT_SS_BASE+27) // Used to set/get any driver-specific or ODBC-defined TXN iso level
|
||||
#define SQL_COPT_SS_TRUST_SERVER_CERTIFICATE (SQL_COPT_SS_BASE+28) // Trust server certificate
|
||||
|
||||
// SQLSetStmtAttr Microsoft ODBC Driver for SQL Server specific defines.
|
||||
// Statement attributes
|
||||
|
||||
#define SQL_SOPT_SS_BASE 1225
|
||||
#define SQL_SOPT_SS_TEXTPTR_LOGGING (SQL_SOPT_SS_BASE+0) // Text pointer logging
|
||||
#define SQL_SOPT_SS_NOBROWSETABLE (SQL_SOPT_SS_BASE+3) // Set NOBROWSETABLE option
|
||||
#define SQL_SOPT_SS_COLUMN_ENCRYPTION (SQL_SOPT_SS_BASE+13)// Sets the column encryption mode
|
||||
// Define old names
|
||||
#define SQL_TEXTPTR_LOGGING SQL_SOPT_SS_TEXTPTR_LOGGING
|
||||
#define SQL_COPT_SS_BASE_EX 1240
|
||||
#define SQL_COPT_SS_WARN_ON_CP_ERROR (SQL_COPT_SS_BASE_EX+3) // Issues warning when data from the server had a loss during code page conversion.
|
||||
#define SQL_COPT_SS_CONNECTION_DEAD (SQL_COPT_SS_BASE_EX+4) // dbdead SQLGetConnectOption only. It will try to ping the server. Expensive connection check
|
||||
#define SQL_COPT_SS_APPLICATION_INTENT (SQL_COPT_SS_BASE_EX+7) // Application Intent
|
||||
#define SQL_COPT_SS_MULTISUBNET_FAILOVER (SQL_COPT_SS_BASE_EX+8) // Multi-subnet Failover
|
||||
#define SQL_COPT_SS_TNIR (SQL_COPT_SS_BASE_EX+9) // Transparent Network IP Resolution
|
||||
#define SQL_COPT_SS_COLUMN_ENCRYPTION (SQL_COPT_SS_BASE_EX+10)// Column Encryption Enabled or Disabled
|
||||
#define SQL_COPT_SS_CEKEYSTOREPROVIDER (SQL_COPT_SS_BASE_EX+11)// Load a keystore provider or read the list of loaded keystore providers
|
||||
#define SQL_COPT_SS_CEKEYSTOREDATA (SQL_COPT_SS_BASE_EX+12)// Communicate with loaded keystore providers
|
||||
#define SQL_COPT_SS_TRUSTEDCMKPATHS (SQL_COPT_SS_BASE_EX+13)// List of trusted CMK paths
|
||||
#define SQL_COPT_SS_CEKCACHETTL (SQL_COPT_SS_BASE_EX+14)// Symmetric Key Cache TTL
|
||||
#define SQL_COPT_SS_AUTHENTICATION (SQL_COPT_SS_BASE_EX+15)// The authentication method used for the connection
|
||||
|
||||
// SQLColAttributes driver specific defines.
|
||||
// SQLSetDescField/SQLGetDescField driver specific defines.
|
||||
// Microsoft has 1200 thru 1249 reserved for Microsoft ODBC Driver for SQL Server usage.
|
||||
|
||||
#define SQL_CA_SS_BASE 1200
|
||||
#define SQL_CA_SS_COLUMN_SSTYPE (SQL_CA_SS_BASE+0) // dbcoltype/dbalttype
|
||||
#define SQL_CA_SS_COLUMN_UTYPE (SQL_CA_SS_BASE+1) // dbcolutype/dbaltutype
|
||||
#define SQL_CA_SS_NUM_ORDERS (SQL_CA_SS_BASE+2) // dbnumorders
|
||||
#define SQL_CA_SS_COLUMN_ORDER (SQL_CA_SS_BASE+3) // dbordercol
|
||||
#define SQL_CA_SS_COLUMN_VARYLEN (SQL_CA_SS_BASE+4) // dbvarylen
|
||||
#define SQL_CA_SS_NUM_COMPUTES (SQL_CA_SS_BASE+5) // dbnumcompute
|
||||
#define SQL_CA_SS_COMPUTE_ID (SQL_CA_SS_BASE+6) // dbnextrow status return
|
||||
#define SQL_CA_SS_COMPUTE_BYLIST (SQL_CA_SS_BASE+7) // dbbylist
|
||||
#define SQL_CA_SS_COLUMN_ID (SQL_CA_SS_BASE+8) // dbaltcolid
|
||||
#define SQL_CA_SS_COLUMN_OP (SQL_CA_SS_BASE+9) // dbaltop
|
||||
#define SQL_CA_SS_COLUMN_SIZE (SQL_CA_SS_BASE+10) // dbcollen
|
||||
#define SQL_CA_SS_COLUMN_HIDDEN (SQL_CA_SS_BASE+11) // Column is hidden (FOR BROWSE)
|
||||
#define SQL_CA_SS_COLUMN_KEY (SQL_CA_SS_BASE+12) // Column is key column (FOR BROWSE)
|
||||
#define SQL_CA_SS_COLUMN_COLLATION (SQL_CA_SS_BASE+14) // Column collation (only for chars)
|
||||
#define SQL_CA_SS_VARIANT_TYPE (SQL_CA_SS_BASE+15)
|
||||
#define SQL_CA_SS_VARIANT_SQL_TYPE (SQL_CA_SS_BASE+16)
|
||||
#define SQL_CA_SS_VARIANT_SERVER_TYPE (SQL_CA_SS_BASE+17)
|
||||
|
||||
// XML, CLR UDT, and table valued parameter related metadata
|
||||
#define SQL_CA_SS_UDT_CATALOG_NAME (SQL_CA_SS_BASE+18) // UDT catalog name
|
||||
#define SQL_CA_SS_UDT_SCHEMA_NAME (SQL_CA_SS_BASE+19) // UDT schema name
|
||||
#define SQL_CA_SS_UDT_TYPE_NAME (SQL_CA_SS_BASE+20) // UDT type name
|
||||
#define SQL_CA_SS_XML_SCHEMACOLLECTION_CATALOG_NAME (SQL_CA_SS_BASE+22) // Name of the catalog that contains XML Schema collection
|
||||
#define SQL_CA_SS_XML_SCHEMACOLLECTION_SCHEMA_NAME (SQL_CA_SS_BASE+23) // Name of the schema that contains XML Schema collection
|
||||
#define SQL_CA_SS_XML_SCHEMACOLLECTION_NAME (SQL_CA_SS_BASE+24) // Name of the XML Schema collection
|
||||
#define SQL_CA_SS_CATALOG_NAME (SQL_CA_SS_BASE+25) // Catalog name
|
||||
#define SQL_CA_SS_SCHEMA_NAME (SQL_CA_SS_BASE+26) // Schema name
|
||||
#define SQL_CA_SS_TYPE_NAME (SQL_CA_SS_BASE+27) // Type name
|
||||
|
||||
// table valued parameter related metadata
|
||||
#define SQL_CA_SS_COLUMN_COMPUTED (SQL_CA_SS_BASE+29) // column is computed
|
||||
#define SQL_CA_SS_COLUMN_IN_UNIQUE_KEY (SQL_CA_SS_BASE+30) // column is part of a unique key
|
||||
#define SQL_CA_SS_COLUMN_SORT_ORDER (SQL_CA_SS_BASE+31) // column sort order
|
||||
#define SQL_CA_SS_COLUMN_SORT_ORDINAL (SQL_CA_SS_BASE+32) // column sort ordinal
|
||||
#define SQL_CA_SS_COLUMN_HAS_DEFAULT_VALUE (SQL_CA_SS_BASE+33) // column has default value for all rows of the table valued parameter
|
||||
|
||||
// sparse column related metadata
|
||||
#define SQL_CA_SS_IS_COLUMN_SET (SQL_CA_SS_BASE+34) // column is a column-set column for sparse columns
|
||||
|
||||
// Legacy datetime related metadata
|
||||
#define SQL_CA_SS_SERVER_TYPE (SQL_CA_SS_BASE+35) // column type to send on the wire for datetime types
|
||||
|
||||
// force column encryption
|
||||
#define SQL_CA_SS_FORCE_ENCRYPT (SQL_CA_SS_BASE+36) // indicate mandatory encryption for this parameter
|
||||
|
||||
#define SQL_CA_SS_MAX_USED (SQL_CA_SS_BASE+37)
|
||||
// Defines for use with SQL_COPT_SS_INTEGRATED_SECURITY - Pre-Connect Option only
|
||||
#define SQL_IS_OFF 0L // Integrated security isn't used
|
||||
#define SQL_IS_ON 1L // Integrated security is used
|
||||
#define SQL_IS_DEFAULT SQL_IS_OFF
|
||||
// Defines for use with SQL_COPT_SS_TRANSLATE
|
||||
#define SQL_XL_OFF 0L // Code page translation is not performed
|
||||
#define SQL_XL_ON 1L // Code page translation is performed
|
||||
#define SQL_XL_DEFAULT SQL_XL_ON
|
||||
// Defines for use with SQL_SOPT_SS_TEXTPTR_LOGGING
|
||||
#define SQL_TL_OFF 0L // No logging on text pointer ops
|
||||
#define SQL_TL_ON 1L // Logging occurs on text pointer ops
|
||||
#define SQL_TL_DEFAULT SQL_TL_ON
|
||||
// Defines for use with SQL_SOPT_SS_NOBROWSETABLE
|
||||
#define SQL_NB_OFF 0L // NO_BROWSETABLE is off
|
||||
#define SQL_NB_ON 1L // NO_BROWSETABLE is on
|
||||
#define SQL_NB_DEFAULT SQL_NB_OFF
|
||||
// Defines for use with SQL_SOPT_SS_COLUMN_ENCRYPTION
|
||||
#define SQL_CE_DISABLED 0L // Disabled
|
||||
#define SQL_CE_RESULTSETONLY 1L // Decryption Only (resultsets and return values)
|
||||
#define SQL_CE_ENABLED 3L // Enabled (both encryption and decryption)
|
||||
// Defines for use with SQL_COPT_SS_COLUMN_ENCRYPTION
|
||||
#define SQL_COLUMN_ENCRYPTION_DISABLE 0L
|
||||
#define SQL_COLUMN_ENCRYPTION_ENABLE 1L
|
||||
#define SQL_COLUMN_ENCRYPTION_DEFAULT SQL_COLUMN_ENCRYPTION_DISABLE
|
||||
// Defines for use with SQL_COPT_SS_CEKCACHETTL
|
||||
#define SQL_CEKCACHETTL_DEFAULT 7200L // TTL value in seconds (2 hours)
|
||||
// SQL_COPT_SS_ENCRYPT
|
||||
#define SQL_EN_OFF 0L
|
||||
#define SQL_EN_ON 1L
|
||||
// SQL_COPT_SS_TRUST_SERVER_CERTIFICATE
|
||||
#define SQL_TRUST_SERVER_CERTIFICATE_NO 0L
|
||||
#define SQL_TRUST_SERVER_CERTIFICATE_YES 1L
|
||||
// SQL_COPT_SS_WARN_ON_CP_ERROR
|
||||
#define SQL_WARN_NO 0L
|
||||
#define SQL_WARN_YES 1L
|
||||
// SQL_COPT_SS_MARS_ENABLED
|
||||
#define SQL_MARS_ENABLED_NO 0L
|
||||
#define SQL_MARS_ENABLED_YES 1L
|
||||
// SQL_TXN_ISOLATION_OPTION bitmasks
|
||||
#define SQL_TXN_SS_SNAPSHOT 0x00000020L
|
||||
|
||||
// The following are defines for SQL_CA_SS_COLUMN_SORT_ORDER
|
||||
#define SQL_SS_ORDER_UNSPECIFIED 0L
|
||||
#define SQL_SS_DESCENDING_ORDER 1L
|
||||
#define SQL_SS_ASCENDING_ORDER 2L
|
||||
#define SQL_SS_ORDER_DEFAULT SQL_SS_ORDER_UNSPECIFIED
|
||||
|
||||
// Driver specific SQL data type defines.
|
||||
// Microsoft has -150 thru -199 reserved for Microsoft ODBC Driver for SQL Server usage.
|
||||
|
||||
#define SQL_SS_VARIANT (-150)
|
||||
#define SQL_SS_UDT (-151)
|
||||
#define SQL_SS_XML (-152)
|
||||
#define SQL_SS_TABLE (-153)
|
||||
#define SQL_SS_TIME2 (-154)
|
||||
#define SQL_SS_TIMESTAMPOFFSET (-155)
|
||||
|
||||
// Local types to be used with SQL_CA_SS_SERVER_TYPE
|
||||
#define SQL_SS_TYPE_DEFAULT 0L
|
||||
#define SQL_SS_TYPE_SMALLDATETIME 1L
|
||||
#define SQL_SS_TYPE_DATETIME 2L
|
||||
|
||||
// Extended C Types range 4000 and above. Range of -100 thru 200 is reserved by Driver Manager.
|
||||
#define SQL_C_TYPES_EXTENDED 0x04000L
|
||||
|
||||
// SQL_SS_LENGTH_UNLIMITED is used to describe the max length of
|
||||
// VARCHAR(max), VARBINARY(max), NVARCHAR(max), and XML columns
|
||||
|
||||
#define SQL_SS_LENGTH_UNLIMITED 0
|
||||
|
||||
// User Data Type definitions.
|
||||
// Returned by SQLColAttributes/SQL_CA_SS_COLUMN_UTYPE.
|
||||
|
||||
#define SQLudtBINARY 3
|
||||
#define SQLudtBIT 16
|
||||
#define SQLudtBITN 0
|
||||
#define SQLudtCHAR 1
|
||||
#define SQLudtDATETIM4 22
|
||||
#define SQLudtDATETIME 12
|
||||
#define SQLudtDATETIMN 15
|
||||
#define SQLudtDECML 24
|
||||
#define SQLudtDECMLN 26
|
||||
#define SQLudtFLT4 23
|
||||
#define SQLudtFLT8 8
|
||||
#define SQLudtFLTN 14
|
||||
#define SQLudtIMAGE 20
|
||||
#define SQLudtINT1 5
|
||||
#define SQLudtINT2 6
|
||||
#define SQLudtINT4 7
|
||||
#define SQLudtINTN 13
|
||||
#define SQLudtMONEY 11
|
||||
#define SQLudtMONEY4 21
|
||||
#define SQLudtMONEYN 17
|
||||
#define SQLudtNUM 10
|
||||
#define SQLudtNUMN 25
|
||||
#define SQLudtSYSNAME 18
|
||||
#define SQLudtTEXT 19
|
||||
#define SQLudtTIMESTAMP 80
|
||||
#define SQLudtUNIQUEIDENTIFIER 0
|
||||
#define SQLudtVARBINARY 4
|
||||
#define SQLudtVARCHAR 2
|
||||
#define MIN_USER_DATATYPE 256
|
||||
|
||||
// Aggregate operator types.
|
||||
// Returned by SQLColAttributes/SQL_CA_SS_COLUMN_OP.
|
||||
|
||||
#define SQLAOPSTDEV 0x30 // Standard deviation
|
||||
#define SQLAOPSTDEVP 0x31 // Standard deviation population
|
||||
#define SQLAOPVAR 0x32 // Variance
|
||||
#define SQLAOPVARP 0x33 // Variance population
|
||||
#define SQLAOPCNT 0x4b // Count
|
||||
#define SQLAOPSUM 0x4d // Sum
|
||||
#define SQLAOPAVG 0x4f // Average
|
||||
#define SQLAOPMIN 0x51 // Min
|
||||
#define SQLAOPMAX 0x52 // Max
|
||||
#define SQLAOPANY 0x53 // Any
|
||||
#define SQLAOPNOOP 0x56 // None
|
||||
|
||||
// SQLGetDiagField driver specific defines.
|
||||
// Microsoft has -1150 thru -1199 reserved for Microsoft ODBC Driver for SQL Server usage.
|
||||
|
||||
#define SQL_DIAG_SS_BASE (-1150)
|
||||
#define SQL_DIAG_SS_MSGSTATE (SQL_DIAG_SS_BASE)
|
||||
#define SQL_DIAG_SS_SEVERITY (SQL_DIAG_SS_BASE-1)
|
||||
#define SQL_DIAG_SS_SRVNAME (SQL_DIAG_SS_BASE-2)
|
||||
#define SQL_DIAG_SS_PROCNAME (SQL_DIAG_SS_BASE-3)
|
||||
#define SQL_DIAG_SS_LINE (SQL_DIAG_SS_BASE-4)
|
||||
|
||||
// SQLGetDiagField/SQL_DIAG_DYNAMIC_FUNCTION_CODE driver specific defines.
|
||||
// Microsoft has -200 thru -299 reserved for Microsoft ODBC Driver for SQL Server usage.
|
||||
|
||||
#define SQL_DIAG_DFC_SS_BASE (-200)
|
||||
#define SQL_DIAG_DFC_SS_ALTER_DATABASE (SQL_DIAG_DFC_SS_BASE-0)
|
||||
#define SQL_DIAG_DFC_SS_CHECKPOINT (SQL_DIAG_DFC_SS_BASE-1)
|
||||
#define SQL_DIAG_DFC_SS_CONDITION (SQL_DIAG_DFC_SS_BASE-2)
|
||||
#define SQL_DIAG_DFC_SS_CREATE_DATABASE (SQL_DIAG_DFC_SS_BASE-3)
|
||||
#define SQL_DIAG_DFC_SS_CREATE_DEFAULT (SQL_DIAG_DFC_SS_BASE-4)
|
||||
#define SQL_DIAG_DFC_SS_CREATE_PROCEDURE (SQL_DIAG_DFC_SS_BASE-5)
|
||||
#define SQL_DIAG_DFC_SS_CREATE_RULE (SQL_DIAG_DFC_SS_BASE-6)
|
||||
#define SQL_DIAG_DFC_SS_CREATE_TRIGGER (SQL_DIAG_DFC_SS_BASE-7)
|
||||
#define SQL_DIAG_DFC_SS_CURSOR_DECLARE (SQL_DIAG_DFC_SS_BASE-8)
|
||||
#define SQL_DIAG_DFC_SS_CURSOR_OPEN (SQL_DIAG_DFC_SS_BASE-9)
|
||||
#define SQL_DIAG_DFC_SS_CURSOR_FETCH (SQL_DIAG_DFC_SS_BASE-10)
|
||||
#define SQL_DIAG_DFC_SS_CURSOR_CLOSE (SQL_DIAG_DFC_SS_BASE-11)
|
||||
#define SQL_DIAG_DFC_SS_DEALLOCATE_CURSOR (SQL_DIAG_DFC_SS_BASE-12)
|
||||
#define SQL_DIAG_DFC_SS_DBCC (SQL_DIAG_DFC_SS_BASE-13)
|
||||
#define SQL_DIAG_DFC_SS_DISK (SQL_DIAG_DFC_SS_BASE-14)
|
||||
#define SQL_DIAG_DFC_SS_DROP_DATABASE (SQL_DIAG_DFC_SS_BASE-15)
|
||||
#define SQL_DIAG_DFC_SS_DROP_DEFAULT (SQL_DIAG_DFC_SS_BASE-16)
|
||||
#define SQL_DIAG_DFC_SS_DROP_PROCEDURE (SQL_DIAG_DFC_SS_BASE-17)
|
||||
#define SQL_DIAG_DFC_SS_DROP_RULE (SQL_DIAG_DFC_SS_BASE-18)
|
||||
#define SQL_DIAG_DFC_SS_DROP_TRIGGER (SQL_DIAG_DFC_SS_BASE-19)
|
||||
#define SQL_DIAG_DFC_SS_DUMP_DATABASE (SQL_DIAG_DFC_SS_BASE-20)
|
||||
#define SQL_DIAG_DFC_SS_BACKUP_DATABASE (SQL_DIAG_DFC_SS_BASE-20)
|
||||
#define SQL_DIAG_DFC_SS_DUMP_TABLE (SQL_DIAG_DFC_SS_BASE-21)
|
||||
#define SQL_DIAG_DFC_SS_DUMP_TRANSACTION (SQL_DIAG_DFC_SS_BASE-22)
|
||||
#define SQL_DIAG_DFC_SS_BACKUP_TRANSACTION (SQL_DIAG_DFC_SS_BASE-22)
|
||||
#define SQL_DIAG_DFC_SS_GOTO (SQL_DIAG_DFC_SS_BASE-23)
|
||||
#define SQL_DIAG_DFC_SS_INSERT_BULK (SQL_DIAG_DFC_SS_BASE-24)
|
||||
#define SQL_DIAG_DFC_SS_KILL (SQL_DIAG_DFC_SS_BASE-25)
|
||||
#define SQL_DIAG_DFC_SS_LOAD_DATABASE (SQL_DIAG_DFC_SS_BASE-26)
|
||||
#define SQL_DIAG_DFC_SS_RESTORE_DATABASE (SQL_DIAG_DFC_SS_BASE-26)
|
||||
#define SQL_DIAG_DFC_SS_LOAD_HEADERONLY (SQL_DIAG_DFC_SS_BASE-27)
|
||||
#define SQL_DIAG_DFC_SS_RESTORE_HEADERONLY (SQL_DIAG_DFC_SS_BASE-27)
|
||||
#define SQL_DIAG_DFC_SS_LOAD_TABLE (SQL_DIAG_DFC_SS_BASE-28)
|
||||
#define SQL_DIAG_DFC_SS_LOAD_TRANSACTION (SQL_DIAG_DFC_SS_BASE-29)
|
||||
#define SQL_DIAG_DFC_SS_RESTORE_TRANSACTION (SQL_DIAG_DFC_SS_BASE-29)
|
||||
#define SQL_DIAG_DFC_SS_PRINT (SQL_DIAG_DFC_SS_BASE-30)
|
||||
#define SQL_DIAG_DFC_SS_RAISERROR (SQL_DIAG_DFC_SS_BASE-31)
|
||||
#define SQL_DIAG_DFC_SS_READTEXT (SQL_DIAG_DFC_SS_BASE-32)
|
||||
#define SQL_DIAG_DFC_SS_RECONFIGURE (SQL_DIAG_DFC_SS_BASE-33)
|
||||
#define SQL_DIAG_DFC_SS_RETURN (SQL_DIAG_DFC_SS_BASE-34)
|
||||
#define SQL_DIAG_DFC_SS_SELECT_INTO (SQL_DIAG_DFC_SS_BASE-35)
|
||||
#define SQL_DIAG_DFC_SS_SET (SQL_DIAG_DFC_SS_BASE-36)
|
||||
#define SQL_DIAG_DFC_SS_SET_IDENTITY_INSERT (SQL_DIAG_DFC_SS_BASE-37)
|
||||
#define SQL_DIAG_DFC_SS_SET_ROW_COUNT (SQL_DIAG_DFC_SS_BASE-38)
|
||||
#define SQL_DIAG_DFC_SS_SET_STATISTICS (SQL_DIAG_DFC_SS_BASE-39)
|
||||
#define SQL_DIAG_DFC_SS_SET_TEXTSIZE (SQL_DIAG_DFC_SS_BASE-40)
|
||||
#define SQL_DIAG_DFC_SS_SETUSER (SQL_DIAG_DFC_SS_BASE-41)
|
||||
#define SQL_DIAG_DFC_SS_SHUTDOWN (SQL_DIAG_DFC_SS_BASE-42)
|
||||
#define SQL_DIAG_DFC_SS_TRANS_BEGIN (SQL_DIAG_DFC_SS_BASE-43)
|
||||
#define SQL_DIAG_DFC_SS_TRANS_COMMIT (SQL_DIAG_DFC_SS_BASE-44)
|
||||
#define SQL_DIAG_DFC_SS_TRANS_PREPARE (SQL_DIAG_DFC_SS_BASE-45)
|
||||
#define SQL_DIAG_DFC_SS_TRANS_ROLLBACK (SQL_DIAG_DFC_SS_BASE-46)
|
||||
#define SQL_DIAG_DFC_SS_TRANS_SAVE (SQL_DIAG_DFC_SS_BASE-47)
|
||||
#define SQL_DIAG_DFC_SS_TRUNCATE_TABLE (SQL_DIAG_DFC_SS_BASE-48)
|
||||
#define SQL_DIAG_DFC_SS_UPDATE_STATISTICS (SQL_DIAG_DFC_SS_BASE-49)
|
||||
#define SQL_DIAG_DFC_SS_UPDATETEXT (SQL_DIAG_DFC_SS_BASE-50)
|
||||
#define SQL_DIAG_DFC_SS_USE (SQL_DIAG_DFC_SS_BASE-51)
|
||||
#define SQL_DIAG_DFC_SS_WAITFOR (SQL_DIAG_DFC_SS_BASE-52)
|
||||
#define SQL_DIAG_DFC_SS_WRITETEXT (SQL_DIAG_DFC_SS_BASE-53)
|
||||
#define SQL_DIAG_DFC_SS_DENY (SQL_DIAG_DFC_SS_BASE-54)
|
||||
#define SQL_DIAG_DFC_SS_SET_XCTLVL (SQL_DIAG_DFC_SS_BASE-55)
|
||||
#define SQL_DIAG_DFC_SS_MERGE (SQL_DIAG_DFC_SS_BASE-56)
|
||||
|
||||
// Severity codes for SQL_DIAG_SS_SEVERITY
|
||||
#define EX_ANY 0
|
||||
#define EX_INFO 10
|
||||
#define EX_MAXISEVERITY EX_INFO
|
||||
#define EX_MISSING 11
|
||||
#define EX_TYPE 12
|
||||
#define EX_DEADLOCK 13
|
||||
#define EX_PERMIT 14
|
||||
#define EX_SYNTAX 15
|
||||
#define EX_USER 16
|
||||
#define EX_RESOURCE 17
|
||||
#define EX_INTOK 18
|
||||
#define MAXUSEVERITY EX_INTOK
|
||||
#define EX_LIMIT 19
|
||||
#define EX_CMDFATAL 20
|
||||
#define MINFATALERR EX_CMDFATAL
|
||||
#define EX_DBFATAL 21
|
||||
#define EX_TABCORRUPT 22
|
||||
#define EX_DBCORRUPT 23
|
||||
#define EX_HARDWARE 24
|
||||
#define EX_CONTROL 25
|
||||
|
||||
// Data is defined to be past the end of the structure header.
|
||||
// This is accepted by MSVC, GCC, and C99 standard but former emits
|
||||
// unnecessary warning, hence it has to be disabled.
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4200)
|
||||
#endif
|
||||
|
||||
// Keystore Provider interface definition
|
||||
typedef struct CEKeystoreContext
|
||||
{
|
||||
void *envCtx;
|
||||
void *dbcCtx;
|
||||
void *stmtCtx;
|
||||
} CEKEYSTORECONTEXT;
|
||||
|
||||
typedef void errFunc(CEKEYSTORECONTEXT *ctx, const wchar_t *msg, ...);
|
||||
|
||||
#define IDS_MSG(x) ((const wchar_t*)(x))
|
||||
|
||||
typedef struct CEKeystoreProvider
|
||||
{
|
||||
wchar_t *Name;
|
||||
int (__stdcall *Init)(CEKEYSTORECONTEXT *ctx, errFunc *onError);
|
||||
int (__stdcall *Read)(CEKEYSTORECONTEXT *ctx, errFunc *onError, void *data, unsigned int *len);
|
||||
int (__stdcall *Write)(CEKEYSTORECONTEXT *ctx, errFunc *onError, void *data, unsigned int len);
|
||||
int (__stdcall *DecryptCEK)(
|
||||
CEKEYSTORECONTEXT *ctx,
|
||||
errFunc *onError,
|
||||
const wchar_t *keyPath,
|
||||
const wchar_t *alg,
|
||||
unsigned char *ecek,
|
||||
unsigned short ecekLen,
|
||||
unsigned char **cekOut,
|
||||
unsigned short *cekLen);
|
||||
int(__stdcall *EncryptCEK)(
|
||||
CEKEYSTORECONTEXT *ctx,
|
||||
errFunc *onError,
|
||||
const wchar_t *keyPath,
|
||||
const wchar_t *alg,
|
||||
unsigned char *cek,
|
||||
unsigned short cekLen,
|
||||
unsigned char **ecekOut,
|
||||
unsigned short *ecekLen);
|
||||
void (__stdcall *Free)();
|
||||
} CEKEYSTOREPROVIDER;
|
||||
|
||||
// Communication between the driver and application via the CEKeystoreData structure
|
||||
typedef struct CEKeystoreData
|
||||
{
|
||||
wchar_t *name;
|
||||
unsigned int dataSize;
|
||||
char data[];
|
||||
} CEKEYSTOREDATA;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
// The following constants are for the Azure Key Vault configuration interface
|
||||
#define AKV_CONFIG_FLAGS 0
|
||||
#define AKVCFG_AUTHMODE 0x0000000F
|
||||
#define AKVCFG_AUTHMODE_ACCESSTOKEN 0
|
||||
#define AKVCFG_AUTHMODE_CLIENTKEY 1
|
||||
#define AKVCFG_AUTHMODE_PASSWORD 2
|
||||
#define AKVCFG_AUTHMODE_INTEGRATED 3
|
||||
#define AKVCFG_AUTHMODE_CERTIFICATE 4
|
||||
#define AKVCFG_NOAUTORENEW 0x00000010
|
||||
|
||||
#define AKV_CONFIG_PRINCIPALID 1
|
||||
#define AKV_CONFIG_AUTHSECRET 2
|
||||
#define AKV_CONFIG_ACCESSTOKEN 3
|
||||
#define AKV_CONFIG_TOKENEXPIRY 4
|
||||
#define AKV_CONFIG_MAXRETRIES 5
|
||||
#define AKV_CONFIG_RETRYTIMEOUT 6
|
||||
#define AKV_CONFIG_RETRYWAIT 7
|
||||
|
||||
#define AKV_CONFIG_RESET 255
|
||||
#endif // __msodbcsql_h__
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Contents: Contains the minimal definitions to build on non-Windows platforms
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//---------------------------------------------------------------------------------------------------------------------------------
|
||||
// File: typedefs_for_linux.h
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// File: version.h
|
||||
// Contents: Version number constants
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
@ -26,8 +26,8 @@
|
|||
// Increase Major number with backward incompatible breaking changes.
|
||||
// Increase Minor with backward compatible new functionalities and API changes.
|
||||
// Increase Patch for backward compatible fixes.
|
||||
#define SQLVERSION_MAJOR 4
|
||||
#define SQLVERSION_MINOR 3
|
||||
#define SQLVERSION_MAJOR 5
|
||||
#define SQLVERSION_MINOR 0
|
||||
#define SQLVERSION_PATCH 0
|
||||
#define SQLVERSION_BUILD 0
|
||||
|
||||
|
@ -35,7 +35,7 @@
|
|||
// for stable releases should be empty
|
||||
// "-RC" for release candidates
|
||||
// "-preview" for ETP
|
||||
#define SEMVER_PRERELEASE
|
||||
#define SEMVER_PRERELEASE "preview"
|
||||
// Semantic versioning build metadata, build meta data is not counted in precedence order.
|
||||
#define SEMVER_BUILDMETA
|
||||
|
||||
|
@ -47,8 +47,10 @@
|
|||
// Main version, dot separated 3 digits, Major.Minor.Patch
|
||||
#define VER_APIVERSION_STR STRINGIFY( SQLVERSION_MAJOR ) "." STRINGIFY( SQLVERSION_MINOR ) "." STRINGIFY( SQLVERSION_PATCH )
|
||||
|
||||
// Remove "-" if SEMVER_PRERELEASE is empty (for stable releases)
|
||||
#define VER_FILEVERSION_STR VER_APIVERSION_STR SEMVER_PRERELEASE SEMVER_BUILDMETA
|
||||
// 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 _FILEVERSION SQLVERSION_MAJOR,SQLVERSION_MINOR,SQLVERSION_PATCH,SQLVERSION_BUILD
|
||||
|
||||
// PECL package version macros (can't have '-' or '+')
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Contents: include for definition of Windows types for non-Windows platforms
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// Contents: This module defines helper functions to prevent
|
||||
// integer overflow bugs.
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Contents: Contains the minimal definitions to build on non-Windows platforms
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Contents: Contains the minimal definitions to build on non-Windows platforms
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Contents: JScript build configuration used by buildconf.bat
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Contents: Routines that use connection handles
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
@ -189,6 +189,10 @@ const char CharacterSet[] = "CharacterSet";
|
|||
const char Authentication[] = "Authentication";
|
||||
const char ConnectionPooling[] = "ConnectionPooling";
|
||||
const char ColumnEncryption[] = "ColumnEncryption";
|
||||
const char CEKeystoreProvider[] = "CEKeystoreProvider";
|
||||
const char CEKeystoreName[] = "CEKeystoreName";
|
||||
const char CEKeystoreEncryptKey[] = "CEKeystoreEncryptKey";
|
||||
|
||||
#ifdef _WIN32
|
||||
const char ConnectRetryCount[] = "ConnectRetryCount";
|
||||
const char ConnectRetryInterval[] = "ConnectRetryInterval";
|
||||
|
@ -296,10 +300,10 @@ const connection_option SS_CONN_OPTS[] = {
|
|||
},
|
||||
{
|
||||
SSConnOptionNames::ConnectionPooling,
|
||||
sizeof( SSConnOptionNames::ConnectionPooling ),
|
||||
sizeof(SSConnOptionNames::ConnectionPooling),
|
||||
SQLSRV_CONN_OPTION_CONN_POOLING,
|
||||
ODBCConnOptions::ConnectionPooling,
|
||||
sizeof( ODBCConnOptions::ConnectionPooling ),
|
||||
sizeof(ODBCConnOptions::ConnectionPooling),
|
||||
CONN_ATTR_BOOL,
|
||||
conn_null_func::func
|
||||
},
|
||||
|
@ -312,6 +316,33 @@ const connection_option SS_CONN_OPTS[] = {
|
|||
CONN_ATTR_STRING,
|
||||
column_encryption_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::ConnectRetryCount,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// File: init.cpp
|
||||
// Contents: initialization routines for the extension
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
//
|
||||
// Comments: Also contains "internal" declarations shared across source files.
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Contents: Routines that use statement handles
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Contents: Version resource
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
//
|
||||
// Comments: Mostly error handling and some type handling
|
||||
//
|
||||
// Microsoft Drivers 4.3 for PHP for SQL Server
|
||||
// Microsoft Drivers 5.0 for PHP for SQL Server
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
// MIT License
|
||||
|
@ -375,6 +375,22 @@ 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_AE_ERROR_DRIVER_NOT_INSTALLED,
|
||||
|
@ -382,6 +398,7 @@ ss_error SS_ERRORS[] = {
|
|||
"communicate with SQL Server with ColumnEncryption attribute enabled.", -105, false }
|
||||
},
|
||||
|
||||
|
||||
// terminate the list of errors/warnings
|
||||
{ UINT_MAX, {} }
|
||||
};
|
||||
|
|
|
@ -1,40 +1,41 @@
|
|||
## Setup Environment on a clean machine
|
||||
|
||||
### Windows
|
||||
Install Visual Studio 2015 before running the following commands. Make sure C++ tools are enabled.
|
||||
Run `cmd` as administrator.
|
||||
The PHP zip file can be downloaded from <http://php.net/downloads.php>.
|
||||
|
||||
The SQLSRV and PDO_SQLSRV driver binaries can be downloaded from <https://github.com/Microsoft/msphpsql/releases>.
|
||||
|
||||
### Windows
|
||||
Install Visual Studio 2015 redistributable before running the following commands.
|
||||
Run `Windows PowerShell` as administrator.
|
||||
|
||||
powershell
|
||||
Set-ExecutionPolicy Unrestricted
|
||||
.\setup_env_windows.ps1 <PHP_VERSION - 7.x.x> <PHP_THREAD - ts or nts> <Absolute path to driver source folder> <ARCH - x86 or x64>
|
||||
.\setup_env_windows.ps1 <absolute path to the PHP zip file> <absolute path to the SQLSRV driver DLL> <absolute path to the PDO_SQLSRV driver DLL>
|
||||
|
||||
### Ubuntu 16
|
||||
sudo env "PATH=$PATH" bash setup_env_unix.sh Ubuntu16 <PHP_VERSION - 7.x.x> <PHP_THREAD - ts or nts> <Absolute path to driver source folder>
|
||||
sudo env "PATH=$PATH" bash setup_env_unix.sh Ubuntu16 <PHP_VERSION - 7.x.y> <PHP_THREAD - ts or nts> <absolute path to the SQLSRV driver so> <absolute path to the PDO_SQLSRV driver so>
|
||||
### RedHat 7
|
||||
sudo env "PATH=$PATH" bash setup_env_unix.sh RedHat7 <PHP_VERSION - 7.x.x> <PHP_THREAD - ts or nts> <Absolute path to driver source folder>
|
||||
### Sierra
|
||||
sudo env "PATH=$PATH" bash setup_env_unix.sh RedHat7 <PHP_VERSION - 7.x.y> <PHP_THREAD - ts or nts> <absolute path to the SQLSRV driver so> <absolute path to the PDO_SQLSRV driver so>
|
||||
### SUSE 12
|
||||
sudo env "PATH=$PATH" bash setup_env_unix.sh SUSE12 <PHP_VERSION - 7.x.y> <PHP_THREAD - ts or nts> <absolute path to the SQLSRV driver so> <absolute path to the PDO_SQLSRV driver so>
|
||||
### MacOS 10.12 Sierra
|
||||
`brew` cannot be run with `sudo` on Sierra. Either enable passwordless `sudo` on the machine or enter the password when prompted.
|
||||
|
||||
bash setup_env_unix.sh Sierra <PHP_VERSION - 7.x.x> <PHP_THREAD - ts or nts> <Absolute path to driver source folder>
|
||||
bash setup_env_unix.sh Sierra <PHP_VERSION - 7.x.y> <PHP_THREAD - ts or nts> <absolute path to the SQLSRV driver so> <absolute path to the PDO_SQLSRV driver so>
|
||||
## Run benchmarks
|
||||
PHPBench is used to run the benchmarks. Visit http://phpbench.readthedocs.io/en/latest/introduction.html to have an idea how the tool works.
|
||||
|
||||
### 1. Modify lib/connect.php with the test database credentials
|
||||
### 2. Execute run-perf_tests.py.
|
||||
##### 1. Modify lib/connect.php with the test database credentials
|
||||
##### 2. Modify lib/result_db.php with the result database credentials
|
||||
##### 3. The number of iterations for each test can be modified in the test itself (e.g., in test/Performance/benchmark/sqlsrv/SqlsrvSelectVersionBench.php). Each bench class in a test, or the parent class that it extends from, has a @Iteration(n) annotation. If you change the number in this annotation, you will change the number of iterations run for this test. By default, most tests are set to 1000 iterations.
|
||||
##### 4. Execute run-perf_tests.py.
|
||||
|
||||
### Windows
|
||||
py.exe run-perf_tests.py -platform <PLATFORM> -iterations <ITERATIONS> -iterations-large <ITERATIONS_LARGE> -result-server <RESULT_SERVER> -result-db <RESULT_DB> -result-uid <RESULT_UID> -result-pwd <RESULT_PWD
|
||||
py.exe run-perf_tests.py -platform <PLATFORM>
|
||||
### Linux and Mac
|
||||
On Linux and Mac, the script must be executed with `sudo python3` because to enable pooling it needs to modify odbcinst.ini system file. As an improvement, the location of the odbcinst.ini file can be changed so that, sudo is not requiered.
|
||||
On Linux and Mac, the script must be executed with `sudo python3` because to enable pooling it needs to modify odbcinst.ini system file. As an improvement, the location of the odbcinst.ini file can be changed so that sudo is not required.
|
||||
|
||||
python3 run-perf_tests.py -platform <PLATFORM> -iterations <ITERATIONS> -iterations-large <ITERATIONS_LARGE> -result-server <RESULT_SERVER> -result-db <RESULT_DB> -result-uid <RESULT_UID> -result-pwd <RESULT_PWD>
|
||||
python3 run-perf_tests.py -platform <PLATFORM> | tee run-perf_output.txt
|
||||
|
||||
`-platform` - The platform that the tests are ran on. Must be one of the following: Windows10, WindowsServer2016 WindowsServer2012 Ubuntu16 RedHat7 Sierra
|
||||
`-iterations` - The number of iterations for regular tests.
|
||||
`-iterations-large` - The number of iterations for the tests that fetch large data. Usually set to 1.
|
||||
`-result-server` - The server of result database. It is assumed that, the result database already setup before running the tests.
|
||||
`-result-db` - Database name. With the current result database setup files, this should be set to `TestResults`
|
||||
`-result-uid` - Result database username
|
||||
`-result-pwd` Result database password
|
||||
|
||||
|
||||
|
||||
`-platform` - The platform that the tests are ran on. Must be one of the following: Windows10, WindowsServer2016, WindowsServer2012, Ubuntu16, RedHat7, SUSE12, Sierra.
|
||||
`-php-driver` (optional) - The driver that the tests are ran on. Must be one of the following: sqlsrv, pdo_sqlsrv, or both. Default is both.
|
||||
`-testname` (optional) - The test to run. Must be the file name (not including path) of one test or 'all'. Default is 'all'. If one test is specified, must also specify the -php-driver option to sqlsrv or pdo_sqlsrv.
|
79
test/Performance/benchmark/pdo_sqlsrv/PDOCRUDBench.php
Normal file
79
test/Performance/benchmark/pdo_sqlsrv/PDOCRUDBench.php
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
use PDOSqlsrvPerfTest\PDOSqlsrvUtil;
|
||||
include_once __DIR__ . "/../../lib/CRUDBaseBenchmark.php";
|
||||
/**
|
||||
* @BeforeMethods({"connect", "setTableName", "createTable", "generateInsertValues", "generateUpdateValues", "generateUpdateParams"})
|
||||
* @AfterMethods({ "dropTable", "disconnect"})
|
||||
*/
|
||||
class PDOSqlsrvCRUDBench extends CRUDBaseBenchmark
|
||||
{
|
||||
|
||||
private $conn;
|
||||
private $tableName;
|
||||
private $insertValues;
|
||||
private $updateValues;
|
||||
private $updateParams;
|
||||
|
||||
public function setTableName()
|
||||
{
|
||||
$this->tableName = "datatypes_".rand();
|
||||
}
|
||||
|
||||
public function connect()
|
||||
{
|
||||
$this->conn = PDOSqlsrvUtil::connect();
|
||||
}
|
||||
|
||||
public function createTable()
|
||||
{
|
||||
PDOSqlsrvUtil::createCRUDTable( $this->conn, $this->tableName );
|
||||
}
|
||||
|
||||
public function generateInsertValues()
|
||||
{
|
||||
$this->insertValues = PDOSqlsrvUtil::generateInsertValues();
|
||||
}
|
||||
|
||||
public function generateUpdateValues()
|
||||
{
|
||||
$this->updateValues = PDOSqlsrvUtil::generateUpdateValues();
|
||||
}
|
||||
|
||||
public function generateUpdateParams()
|
||||
{
|
||||
$this->updateParams = PDOSqlsrvUtil::generateUpdateParams();
|
||||
}
|
||||
/**
|
||||
* Each iteration does the following $loopsPerCRUDIter times:
|
||||
* (i) insert a row into the table with insertWithPrepare
|
||||
* (ii) fetch the row with fetchWithPrepare
|
||||
* (iii) update the row's contents with updateWithPrepare
|
||||
* (iv) delete the row with delete
|
||||
* Every insertion calls prepare, bindParam and execute APIs.
|
||||
* Every fetch calls prepare, execute and fetch APIs.
|
||||
* Every update calls prepare, bindParam and execute APIs.
|
||||
* Every delete calls prepare and execute APIs.
|
||||
*/
|
||||
public function benchCRUDWithPrepare()
|
||||
{
|
||||
for( $i=0; $i<PDOSqlsrvUtil::$loopsPerCRUDIter; $i++ )
|
||||
{
|
||||
PDOSqlsrvUtil::insertWithPrepare( $this->conn, $this->tableName, $this->insertValues );
|
||||
PDOSqlsrvUtil::fetchWithPrepare( $this->conn, $this->tableName );
|
||||
PDOSqlsrvUtil::updateWithPrepare( $this->conn, $this->tableName, $this->updateValues, $this->updateParams );
|
||||
PDOSqlsrvUtil::deleteWithPrepare( $this->conn, $this->tableName );
|
||||
}
|
||||
}
|
||||
|
||||
public function dropTable()
|
||||
{
|
||||
PDOSqlsrvUtil::dropTable( $this->conn, $this->tableName );
|
||||
}
|
||||
|
||||
public function disconnect()
|
||||
{
|
||||
PDOSqlsrvUtil::disconnect( $this->conn );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,12 +1,15 @@
|
|||
<?php
|
||||
|
||||
use PDOSqlsrvPerfTest\PDOSqlsrvUtil;
|
||||
include_once __DIR__ . "/../../lib/CRUDBaseBenchmark.php";
|
||||
|
||||
class PDOConnectionBench{
|
||||
class PDOConnectionBench extends CRUDBaseBenchmark
|
||||
{
|
||||
/*
|
||||
* Opens a connection and closes it immediately
|
||||
*/
|
||||
public function benchConnectAndDisconnect(){
|
||||
public function benchConnectAndDisconnect()
|
||||
{
|
||||
$conn = PDOSqlsrvUtil::connect();
|
||||
PDOSqlsrvUtil::disconnect( $conn );
|
||||
}
|
|
@ -1,21 +1,25 @@
|
|||
<?php
|
||||
|
||||
use PDOSqlsrvPerfTest\PDOSqlsrvUtil;
|
||||
include_once __DIR__ . "/../../lib/CRUDBaseBenchmark.php";
|
||||
/**
|
||||
* @BeforeMethods({"connect"})
|
||||
* @AfterMethods({"disconnect"})
|
||||
*/
|
||||
class PDOCreateDbTableProcBench{
|
||||
class PDOCreateDbTableProcBench extends CRUDBaseBenchmark
|
||||
{
|
||||
private $conn;
|
||||
|
||||
public function connect(){
|
||||
public function connect()
|
||||
{
|
||||
$this->conn = PDOSqlsrvUtil::connect();
|
||||
}
|
||||
/*
|
||||
* Each iteration creates a database, a table and a stored procedure in that database and drops the database at the end.
|
||||
* Note that, execDirect function are used to execute all the queries.
|
||||
*/
|
||||
public function benchCreateDbTableProc(){
|
||||
public function benchCreateDbTableProc()
|
||||
{
|
||||
$randomNum = rand();
|
||||
$databaseName = "test_db_$randomNum";
|
||||
$tableName = "test_table_$randomNum";
|
||||
|
@ -24,7 +28,8 @@ class PDOCreateDbTableProcBench{
|
|||
PDOSqlsrvUtil::dropDatabase( $this->conn, $databaseName );
|
||||
}
|
||||
|
||||
public function disconnect(){
|
||||
public function disconnect()
|
||||
{
|
||||
PDOSqlsrvUtil::disconnect( $this->conn );
|
||||
}
|
||||
}
|
|
@ -1,34 +1,42 @@
|
|||
<?php
|
||||
|
||||
use PDOSqlsrvPerfTest\PDOSqlsrvUtil;
|
||||
include_once __DIR__ . "/../../lib/CRUDBaseBenchmark.php";
|
||||
/**
|
||||
* @BeforeMethods({"connect", "setTableName", "createTable", "generateInsertValues", "insertWithPrepare"})
|
||||
* @AfterMethods({ "dropTable","disconnect"})
|
||||
*/
|
||||
class PDODeleteBench{
|
||||
class PDODeleteBench extends CRUDBaseBenchmark
|
||||
{
|
||||
|
||||
private $conn;
|
||||
private $tableName;
|
||||
private $insertValues;
|
||||
|
||||
public function setTableName(){
|
||||
public function setTableName()
|
||||
{
|
||||
$this->tableName = "datatypes_".rand();
|
||||
}
|
||||
|
||||
public function connect(){
|
||||
public function connect()
|
||||
{
|
||||
$this->conn = PDOSqlsrvUtil::connect();
|
||||
}
|
||||
|
||||
public function createTable(){
|
||||
public function createTable()
|
||||
{
|
||||
PDOSqlsrvUtil::createCRUDTable( $this->conn, $this->tableName );
|
||||
}
|
||||
|
||||
public function generateInsertValues(){
|
||||
public function generateInsertValues()
|
||||
{
|
||||
$this->insertValues = PDOSqlsrvUtil::generateInsertValues();
|
||||
}
|
||||
|
||||
public function insertWithPrepare(){
|
||||
for( $i=0; $i<1000; $i++ ){
|
||||
public function insertWithPrepare()
|
||||
{
|
||||
for( $i=0; $i<PDOSqlsrvUtil::$loopsPerCRUDIter; $i++ )
|
||||
{
|
||||
PDOSqlsrvUtil::insertWithPrepare( $this->conn, $this->tableName, $this->insertValues );
|
||||
}
|
||||
}
|
||||
|
@ -36,17 +44,21 @@ class PDODeleteBench{
|
|||
* Each iteration inserts 1000 rows into the table, benchDelete deletes top row from the table 1000 times.
|
||||
* Note that, every delete calls prepare and execute APIs.
|
||||
*/
|
||||
public function benchDelete(){
|
||||
for( $i=0; $i<1000; $i++ ){
|
||||
public function benchDelete()
|
||||
{
|
||||
for( $i=0; $i<PDOSqlsrvUtil::$loopsPerCRUDIter; $i++ )
|
||||
{
|
||||
PDOSqlsrvUtil::deleteWithPrepare( $this->conn, $this->tableName );
|
||||
}
|
||||
}
|
||||
|
||||
public function dropTable(){
|
||||
public function dropTable()
|
||||
{
|
||||
PDOSqlsrvUtil::dropTable( $this->conn, $this->tableName );
|
||||
}
|
||||
|
||||
public function disconnect(){
|
||||
public function disconnect()
|
||||
{
|
||||
PDOSqlsrvUtil::disconnect( $this->conn );
|
||||
}
|
||||
|
|
@ -1,32 +1,39 @@
|
|||
<?php
|
||||
|
||||
use PDOSqlsrvPerfTest\PDOSqlsrvUtil;
|
||||
include_once __DIR__ . "/../../lib/CRUDBaseBenchmark.php";
|
||||
/**
|
||||
* @BeforeMethods({"connect", "setTableName", "createTable", "generateInsertValues", "insertWithPrepare"})
|
||||
* @AfterMethods({"dropTable", "disconnect"})
|
||||
*/
|
||||
class PDOFetchBench{
|
||||
class PDOFetchBench extends CRUDBaseBenchmark
|
||||
{
|
||||
|
||||
private $conn;
|
||||
private $tableName;
|
||||
private $insertValues;
|
||||
|
||||
public function setTableName(){
|
||||
public function setTableName()
|
||||
{
|
||||
$this->tableName = "datatypes_".rand();
|
||||
}
|
||||
public function connect(){
|
||||
public function connect()
|
||||
{
|
||||
$this->conn = PDOSqlsrvUtil::connect();
|
||||
}
|
||||
|
||||
public function createTable(){
|
||||
public function createTable()
|
||||
{
|
||||
PDOSqlsrvUtil::createCRUDTable( $this->conn, $this->tableName );
|
||||
}
|
||||
|
||||
public function generateInsertValues(){
|
||||
public function generateInsertValues()
|
||||
{
|
||||
$this->insertValues = PDOSqlsrvUtil::generateInsertValues();
|
||||
}
|
||||
|
||||
public function insertWithPrepare(){
|
||||
public function insertWithPrepare()
|
||||
{
|
||||
PDOSqlsrvUtil::insertWithPrepare( $this->conn, $this->tableName, $this->insertValues );
|
||||
}
|
||||
|
||||
|
@ -34,17 +41,21 @@ class PDOFetchBench{
|
|||
* Each iteration inserts a row into the table, benchFetchWithPrepare() fetches that row 1000 times.
|
||||
* Note that, every fetch calls prepare, execute and fetch APIs.
|
||||
*/
|
||||
public function benchFetchWithPrepare(){
|
||||
for( $i=0; $i<1000; $i++){
|
||||
public function benchFetchWithPrepare()
|
||||
{
|
||||
for( $i=0; $i<PDOSqlsrvUtil::$loopsPerCRUDIter; $i++)
|
||||
{
|
||||
PDOSqlsrvUtil::fetchWithPrepare( $this->conn, $this->tableName );
|
||||
}
|
||||
}
|
||||
|
||||
public function dropTable(){
|
||||
public function dropTable()
|
||||
{
|
||||
PDOSqlsrvUtil::dropTable( $this->conn, $this->tableName );
|
||||
}
|
||||
|
||||
public function disconnect(){
|
||||
public function disconnect()
|
||||
{
|
||||
PDOSqlsrvUtil::disconnect( $this->conn );
|
||||
}
|
||||
}
|
|
@ -2,30 +2,36 @@
|
|||
|
||||
use PDOSqlsrvPerfTest\PDOSqlsrvUtil;
|
||||
/**
|
||||
* @Iterations(1)
|
||||
* @BeforeMethods({"connect", "setTableName" })
|
||||
* @AfterMethods({ "disconnect"})
|
||||
*/
|
||||
class PDOFetchLargeBench{
|
||||
class PDOFetchLargeBench
|
||||
{
|
||||
|
||||
private $conn;
|
||||
private $tableName;
|
||||
|
||||
public function setTableName(){
|
||||
public function setTableName()
|
||||
{
|
||||
//Assumes the table is already populated with data
|
||||
$this->tableName = "LargeDB.dbo.datatypes";
|
||||
}
|
||||
|
||||
public function connect(){
|
||||
public function connect()
|
||||
{
|
||||
$this->conn = PDOSqlsrvUtil::connect();
|
||||
}
|
||||
/*
|
||||
* Each iteration calls prepare, execute and fetch APIs to fetch the already populdated data
|
||||
* Each iteration calls prepare, execute and fetch APIs to fetch the already populated data
|
||||
*/
|
||||
public function benchFetchWithPrepare(){
|
||||
public function benchFetchWithPrepare()
|
||||
{
|
||||
PDOSqlsrvUtil::fetchWithPrepare( $this->conn, $this->tableName );
|
||||
}
|
||||
|
||||
public function disconnect(){
|
||||
public function disconnect()
|
||||
{
|
||||
PDOSqlsrvUtil::disconnect( $this->conn );
|
||||
}
|
||||
}
|
|
@ -1,45 +1,55 @@
|
|||
<?php
|
||||
|
||||
use PDOSqlsrvPerfTest\PDOSqlsrvUtil;
|
||||
include_once __DIR__ . "/../../lib/CRUDBaseBenchmark.php";
|
||||
/**
|
||||
* @BeforeMethods({"connect", "setTableName", "createTable", "generateInsertValues"})
|
||||
* @AfterMethods({ "dropTable", "disconnect"})
|
||||
*/
|
||||
class PDOInsertBench{
|
||||
class PDOInsertBench extends CRUDBaseBenchmark
|
||||
{
|
||||
|
||||
private $conn;
|
||||
private $tableName;
|
||||
private $insertValues;
|
||||
|
||||
public function setTableName(){
|
||||
public function setTableName()
|
||||
{
|
||||
$this->tableName = "datatypes_".rand();
|
||||
}
|
||||
public function connect(){
|
||||
public function connect()
|
||||
{
|
||||
$this->conn = PDOSqlsrvUtil::connect();
|
||||
}
|
||||
|
||||
public function createTable(){
|
||||
public function createTable()
|
||||
{
|
||||
PDOSqlsrvUtil::createCRUDTable( $this->conn, $this->tableName );
|
||||
}
|
||||
|
||||
public function generateInsertValues(){
|
||||
public function generateInsertValues()
|
||||
{
|
||||
$this->insertValues = PDOSqlsrvUtil::generateInsertValues();
|
||||
}
|
||||
/**
|
||||
* Each iteration inserts 1000 rows into the table.
|
||||
* Note that, every insertion calls prepare, bindParam and execute APIs.
|
||||
*/
|
||||
public function benchInsertWithPrepare(){
|
||||
for ( $i=0; $i<1000; $i++){
|
||||
public function benchInsertWithPrepare()
|
||||
{
|
||||
for ( $i=0; $i<PDOSqlsrvUtil::$loopsPerCRUDIter; $i++)
|
||||
{
|
||||
PDOSqlsrvUtil::insertWithPrepare( $this->conn, $this->tableName, $this->insertValues );
|
||||
}
|
||||
}
|
||||
|
||||
public function dropTable(){
|
||||
public function dropTable()
|
||||
{
|
||||
PDOSqlsrvUtil::dropTable( $this->conn, $this->tableName );
|
||||
}
|
||||
|
||||
public function disconnect(){
|
||||
public function disconnect()
|
||||
{
|
||||
PDOSqlsrvUtil::disconnect( $this->conn );
|
||||
}
|
||||
}
|
|
@ -2,24 +2,29 @@
|
|||
|
||||
use PDOSqlsrvPerfTest\PDOSqlsrvUtil;
|
||||
/**
|
||||
* @Iterations(10000)
|
||||
* @BeforeMethods({"connect"})
|
||||
* @AfterMethods({"disconnect"})
|
||||
*/
|
||||
class PDOSelectVersionBench{
|
||||
class PDOSelectVersionBench
|
||||
{
|
||||
|
||||
private $conn;
|
||||
|
||||
public function connect(){
|
||||
public function connect()
|
||||
{
|
||||
$this->conn = PDOSqlsrvUtil::connect();
|
||||
}
|
||||
/*
|
||||
* Each iteration calls execDirect API to fetch @@Version
|
||||
*/
|
||||
public function benchSelectVersion(){
|
||||
public function benchSelectVersion()
|
||||
{
|
||||
$version = PDOSqlsrvUtil::selectVersion( $this->conn );
|
||||
}
|
||||
|
||||
public function disconnect(){
|
||||
public function disconnect()
|
||||
{
|
||||
PDOSqlsrvUtil::disconnect( $this->conn );
|
||||
}
|
||||
}
|
|
@ -1,11 +1,13 @@
|
|||
<?php
|
||||
|
||||
use PDOSqlsrvPerfTest\PDOSqlsrvUtil;
|
||||
include_once __DIR__ . "/../../lib/CRUDBaseBenchmark.php";
|
||||
/**
|
||||
* @BeforeMethods({"connect", "setTableName", "createTable", "generateInsertValues", "insertWithPrepare", "generateUpdateValues", "generateUpdateParams"})
|
||||
* @AfterMethods({"dropTable", "disconnect"})
|
||||
*/
|
||||
class PDOUpdateBench{
|
||||
class PDOUpdateBench extends CRUDBaseBenchmark
|
||||
{
|
||||
|
||||
private $conn;
|
||||
private $tableName;
|
||||
|
@ -13,48 +15,59 @@ class PDOUpdateBench{
|
|||
private $updateValues;
|
||||
private $updateParams;
|
||||
|
||||
public function setTableName(){
|
||||
public function setTableName()
|
||||
{
|
||||
$this->tableName = "datatypes_".rand();
|
||||
}
|
||||
|
||||
public function connect(){
|
||||
public function connect()
|
||||
{
|
||||
$this->conn = PDOSqlsrvUtil::connect();
|
||||
}
|
||||
|
||||
public function createTable(){
|
||||
public function createTable()
|
||||
{
|
||||
PDOSqlsrvUtil::createCRUDTable( $this->conn, $this->tableName );
|
||||
}
|
||||
|
||||
public function generateInsertValues(){
|
||||
public function generateInsertValues()
|
||||
{
|
||||
$this->insertValues = PDOSqlsrvUtil::generateInsertValues();
|
||||
}
|
||||
|
||||
public function insertWithPrepare(){
|
||||
public function insertWithPrepare()
|
||||
{
|
||||
PDOSqlsrvUtil::insertWithPrepare( $this->conn, $this->tableName, $this->insertValues );
|
||||
}
|
||||
|
||||
public function generateUpdateValues(){
|
||||
public function generateUpdateValues()
|
||||
{
|
||||
$this->updateValues = PDOSqlsrvUtil::generateUpdateValues();
|
||||
}
|
||||
|
||||
public function generateUpdateParams(){
|
||||
public function generateUpdateParams()
|
||||
{
|
||||
$this->updateParams = PDOSqlsrvUtil::generateUpdateParams();
|
||||
}
|
||||
/**
|
||||
* Each iteration inserts a row into the table, updateWithPrepare() updates that row 1000 times.
|
||||
* Note that, every update calls prepare, bindParam and execute APIs.
|
||||
*/
|
||||
public function benchUpdateWithPrepare(){
|
||||
for( $i=0; $i<1000; $i++ ){
|
||||
$stmt = PDOSqlsrvUtil::updateWithPrepare( $this->conn, $this->tableName, $this->updateValues, $this->updateParams );
|
||||
public function benchUpdateWithPrepare()
|
||||
{
|
||||
for( $i=0; $i<PDOSqlsrvUtil::$loopsPerCRUDIter; $i++ )
|
||||
{
|
||||
PDOSqlsrvUtil::updateWithPrepare( $this->conn, $this->tableName, $this->updateValues, $this->updateParams );
|
||||
}
|
||||
}
|
||||
|
||||
public function dropTable(){
|
||||
public function dropTable()
|
||||
{
|
||||
PDOSqlsrvUtil::dropTable( $this->conn, $this->tableName );
|
||||
}
|
||||
|
||||
public function disconnect(){
|
||||
public function disconnect()
|
||||
{
|
||||
PDOSqlsrvUtil::disconnect( $this->conn );
|
||||
}
|
||||
|
79
test/Performance/benchmark/sqlsrv/SqlsrvCRUDBench.php
Normal file
79
test/Performance/benchmark/sqlsrv/SqlsrvCRUDBench.php
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
use SqlsrvPerfTest\SqlsrvUtil;
|
||||
include_once __DIR__ . "/../../lib/CRUDBaseBenchmark.php";
|
||||
/**
|
||||
* @BeforeMethods({"connect", "setTableName", "createTable", "generateInsertValues", "generateUpdateValues", "generateUpdateParams"})
|
||||
* @AfterMethods({ "dropTable", "disconnect"})
|
||||
*/
|
||||
class SqlsrvCRUDBench extends CRUDBaseBenchmark
|
||||
{
|
||||
|
||||
private $conn;
|
||||
private $tableName;
|
||||
private $insertValues;
|
||||
private $updateValues;
|
||||
private $updateParams;
|
||||
|
||||
public function setTableName()
|
||||
{
|
||||
$this->tableName = "datatypes_".rand();
|
||||
}
|
||||
|
||||
public function connect()
|
||||
{
|
||||
$this->conn = SqlsrvUtil::connect();
|
||||
}
|
||||
|
||||
public function createTable()
|
||||
{
|
||||
SqlsrvUtil::createCRUDTable( $this->conn, $this->tableName );
|
||||
}
|
||||
|
||||
public function generateInsertValues()
|
||||
{
|
||||
$this->insertValues = SqlsrvUtil::generateInsertValues();
|
||||
}
|
||||
|
||||
public function generateUpdateValues()
|
||||
{
|
||||
$this->updateValues = SqlsrvUtil::generateUpdateValues();
|
||||
}
|
||||
|
||||
public function generateUpdateParams()
|
||||
{
|
||||
$this->updateParams = SqlsrvUtil::generateUpdateParams();
|
||||
}
|
||||
/**
|
||||
* Each iteration does the following $loopsPerCRUDIter times:
|
||||
* (i) insert a row into the table with insertWithPrepare
|
||||
* (ii) fetch the row with fetchWithPrepare
|
||||
* (iii) update the row's contents with updateWithPrepare
|
||||
* (iv) delete the row with delete
|
||||
* Every insertion calls prepare, bindParam and execute APIs.
|
||||
* Every fetch calls prepare, execute and fetch APIs.
|
||||
* Every update calls prepare, bindParam and execute APIs.
|
||||
* Every delete calls prepare and execute APIs.
|
||||
*/
|
||||
public function benchCRUDWithPrepare()
|
||||
{
|
||||
for( $i=0; $i<SqlsrvUtil::$loopsPerCRUDIter; $i++ )
|
||||
{
|
||||
SqlsrvUtil::insertWithPrepare( $this->conn, $this->tableName, $this->insertValues );
|
||||
SqlsrvUtil::fetchWithPrepare( $this->conn, $this->tableName );
|
||||
SqlsrvUtil::updateWithPrepare( $this->conn, $this->tableName, $this->updateValues, $this->updateParams );
|
||||
SqlsrvUtil::delete( $this->conn, $this->tableName );
|
||||
}
|
||||
}
|
||||
|
||||
public function dropTable()
|
||||
{
|
||||
SqlsrvUtil::dropTable( $this->conn, $this->tableName );
|
||||
}
|
||||
|
||||
public function disconnect()
|
||||
{
|
||||
SqlsrvUtil::disconnect( $this->conn );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,12 +1,15 @@
|
|||
<?php
|
||||
|
||||
use SqlsrvPerfTest\SqlsrvUtil;
|
||||
include_once __DIR__ . "/../../lib/CRUDBaseBenchmark.php";
|
||||
|
||||
class SqlsrvConnectionBench{
|
||||
class SqlsrvConnectionBench extends CRUDBaseBenchmark
|
||||
{
|
||||
/*
|
||||
* Opens a connection and closes it immediately
|
||||
*/
|
||||
public function benchConnectAndDisconnect(){
|
||||
public function benchConnectAndDisconnect()
|
||||
{
|
||||
$conn = SqlsrvUtil::connect();
|
||||
SqlsrvUtil::disconnect( $conn );
|
||||
}
|
|
@ -1,14 +1,17 @@
|
|||
<?php
|
||||
|
||||
use SqlsrvPerfTest\SqlsrvUtil;
|
||||
include_once __DIR__ . "/../../lib/CRUDBaseBenchmark.php";
|
||||
/**
|
||||
* @BeforeMethods({"connect"})
|
||||
* @AfterMethods({"disconnect"})
|
||||
*/
|
||||
class SqlsrvCreateDbTableProcBench{
|
||||
class SqlsrvCreateDbTableProcBench extends CRUDBaseBenchmark
|
||||
{
|
||||
private $conn;
|
||||
|
||||
public function connect(){
|
||||
public function connect()
|
||||
{
|
||||
$this->conn = SqlsrvUtil::connect();
|
||||
}
|
||||
|
||||
|
@ -16,7 +19,8 @@ class SqlsrvCreateDbTableProcBench{
|
|||
* Each iteration creates a database, a table and a stored procedure in that database and drops the database at the end.
|
||||
* Note that, ODBC SQLExecDirect function are used to execute all the queries.
|
||||
*/
|
||||
public function benchCreateDbTableProc(){
|
||||
public function benchCreateDbTableProc()
|
||||
{
|
||||
$randomNum = rand();
|
||||
$databaseName = "test_db_$randomNum";
|
||||
$tableName = "test_table_$randomNum";
|
||||
|
@ -25,7 +29,8 @@ class SqlsrvCreateDbTableProcBench{
|
|||
SqlsrvUtil::dropDatabase( $this->conn, $databaseName );
|
||||
}
|
||||
|
||||
public function disconnect(){
|
||||
public function disconnect()
|
||||
{
|
||||
SqlsrvUtil::disconnect( $this->conn );
|
||||
}
|
||||
}
|
|
@ -1,34 +1,42 @@
|
|||
<?php
|
||||
|
||||
use SqlsrvPerfTest\SqlsrvUtil;
|
||||
include_once __DIR__ . "/../../lib/CRUDBaseBenchmark.php";
|
||||
/**
|
||||
* @BeforeMethods({"connect", "setTableName", "createTable", "generateInsertValues", "insertWithPrepare"})
|
||||
* @AfterMethods({ "dropTable", "disconnect"})
|
||||
*/
|
||||
class SqlsrvDeleteBench{
|
||||
class SqlsrvDeleteBench extends CRUDBaseBenchmark
|
||||
{
|
||||
|
||||
private $conn;
|
||||
private $tableName;
|
||||
private $insertValues;
|
||||
|
||||
public function setTableName(){
|
||||
public function setTableName()
|
||||
{
|
||||
$this->tableName = "datatypes_".rand();
|
||||
}
|
||||
|
||||
public function connect(){
|
||||
public function connect()
|
||||
{
|
||||
$this->conn = SqlsrvUtil::connect();
|
||||
}
|
||||
|
||||
public function createTable(){
|
||||
public function createTable()
|
||||
{
|
||||
SqlsrvUtil::createCRUDTable( $this->conn, $this->tableName );
|
||||
}
|
||||
|
||||
public function generateInsertValues(){
|
||||
public function generateInsertValues()
|
||||
{
|
||||
$this->insertValues = SqlsrvUtil::generateInsertValues();
|
||||
}
|
||||
|
||||
public function insertWithPrepare(){
|
||||
for ( $i=0; $i<1000; $i++ ){
|
||||
public function insertWithPrepare()
|
||||
{
|
||||
for ( $i=0; $i<SqlsrvUtil::$loopsPerCRUDIter; $i++ )
|
||||
{
|
||||
SqlsrvUtil::insertWithPrepare( $this->conn, $this->tableName, $this->insertValues );
|
||||
}
|
||||
}
|
||||
|
@ -36,17 +44,21 @@ class SqlsrvDeleteBench{
|
|||
* Each iteration inserts 1000 rows into the table, benchDelete deletes top row from the table 1000 times.
|
||||
* Note that, every delete calls prepare and execute APIs.
|
||||
*/
|
||||
public function benchDelete(){
|
||||
for( $i=0; $i<1000; $i++ ){
|
||||
public function benchDelete()
|
||||
{
|
||||
for( $i=0; $i<SqlsrvUtil::$loopsPerCRUDIter; $i++ )
|
||||
{
|
||||
SqlsrvUtil::delete( $this->conn, $this->tableName );
|
||||
}
|
||||
}
|
||||
|
||||
public function dropTable(){
|
||||
public function dropTable()
|
||||
{
|
||||
SqlsrvUtil::dropTable( $this->conn, $this->tableName );
|
||||
}
|
||||
|
||||
public function disconnect(){
|
||||
public function disconnect()
|
||||
{
|
||||
SqlsrvUtil::disconnect( $this->conn );
|
||||
}
|
||||
|
|
@ -1,35 +1,40 @@
|
|||
<?php
|
||||
|
||||
use SqlsrvPerfTest\SqlsrvUtil;
|
||||
include_once __DIR__ . "/../../lib/CRUDBaseBenchmark.php";
|
||||
/**
|
||||
* @BeforeMethods({"connect", "setTableName", "createTable", "generateInsertValues", "insertWithPrepare"})
|
||||
* @AfterMethods({ "dropTable", "disconnect"})
|
||||
*/
|
||||
|
||||
|
||||
class SqlsrvFetchBench{
|
||||
class SqlsrvFetchBench extends CRUDBaseBenchmark
|
||||
{
|
||||
|
||||
private $conn;
|
||||
private $tableName;
|
||||
private $insertValues;
|
||||
|
||||
public function setTableName(){
|
||||
public function setTableName()
|
||||
{
|
||||
$this->tableName = "datatypes_".rand();
|
||||
}
|
||||
|
||||
public function connect(){
|
||||
public function connect()
|
||||
{
|
||||
$this->conn = SqlsrvUtil::connect();
|
||||
}
|
||||
|
||||
public function createTable(){
|
||||
public function createTable()
|
||||
{
|
||||
SqlsrvUtil::createCRUDTable( $this->conn, $this->tableName );
|
||||
}
|
||||
|
||||
public function generateInsertValues(){
|
||||
public function generateInsertValues()
|
||||
{
|
||||
$this->insertValues = SqlsrvUtil::generateInsertValues();
|
||||
}
|
||||
|
||||
public function insertWithPrepare(){
|
||||
public function insertWithPrepare()
|
||||
{
|
||||
SqlsrvUtil::insertWithPrepare( $this->conn, $this->tableName, $this->insertValues );
|
||||
}
|
||||
|
||||
|
@ -37,17 +42,21 @@ class SqlsrvFetchBench{
|
|||
* Each iteration inserts a row into the table, benchFetchWithPrepare() fetches that row 1000 times.
|
||||
* Note that, every fetch calls prepare, execute and fetch APIs.
|
||||
*/
|
||||
public function benchFetchWithPrepare(){
|
||||
for( $i=0; $i<1000; $i++){
|
||||
public function benchFetchWithPrepare()
|
||||
{
|
||||
for( $i=0; $i<SqlsrvUtil::$loopsPerCRUDIter; $i++)
|
||||
{
|
||||
SqlsrvUtil::fetchWithPrepare( $this->conn, $this->tableName );
|
||||
}
|
||||
}
|
||||
|
||||
public function dropTable(){
|
||||
public function dropTable()
|
||||
{
|
||||
SqlsrvUtil::dropTable( $this->conn, $this->tableName );
|
||||
}
|
||||
|
||||
public function disconnect(){
|
||||
public function disconnect()
|
||||
{
|
||||
SqlsrvUtil::disconnect( $this->conn );
|
||||
}
|
||||
}
|
|
@ -2,30 +2,36 @@
|
|||
|
||||
use SqlsrvPerfTest\SqlsrvUtil;
|
||||
/**
|
||||
* @Iterations(1)
|
||||
* @BeforeMethods({"connect", "setTableName" })
|
||||
* @AfterMethods({ "disconnect"})
|
||||
*/
|
||||
class SqlsrvFetchLargeBench{
|
||||
class SqlsrvFetchLargeBench
|
||||
{
|
||||
|
||||
private $conn;
|
||||
private $tableName;
|
||||
|
||||
public function setTableName(){
|
||||
public function setTableName()
|
||||
{
|
||||
//Assumes the table is already populated with data
|
||||
$this->tableName = "LargeDB.dbo.datatypes";
|
||||
}
|
||||
|
||||
public function connect(){
|
||||
public function connect()
|
||||
{
|
||||
$this->conn = SqlsrvUtil::connect();
|
||||
}
|
||||
/*
|
||||
* Each iteration calls prepare, execute and fetch APIs to fetch the already populdated data
|
||||
* Each iteration calls prepare, execute and fetch APIs to fetch the already populated data
|
||||
*/
|
||||
public function benchFetchWithPrepare(){
|
||||
public function benchFetchWithPrepare()
|
||||
{
|
||||
SqlsrvUtil::fetchWithPrepare( $this->conn, $this->tableName );
|
||||
}
|
||||
|
||||
public function disconnect(){
|
||||
public function disconnect()
|
||||
{
|
||||
SqlsrvUtil::disconnect( $this->conn );
|
||||
}
|
||||
}
|
|
@ -1,46 +1,56 @@
|
|||
<?php
|
||||
|
||||
use SqlsrvPerfTest\SqlsrvUtil;
|
||||
include_once __DIR__ . "/../../lib/CRUDBaseBenchmark.php";
|
||||
/**
|
||||
* @BeforeMethods({"connect", "setTableName", "createTable", "generateInsertValues"})
|
||||
* @AfterMethods({"dropTable","disconnect"})
|
||||
*/
|
||||
class SqlsrvInsertBench{
|
||||
class SqlsrvInsertBench extends CRUDBaseBenchmark
|
||||
{
|
||||
|
||||
private $conn;
|
||||
private $tableName;
|
||||
private $insertValues;
|
||||
|
||||
public function setTableName(){
|
||||
public function setTableName()
|
||||
{
|
||||
$this->tableName = "datatypes_".rand();
|
||||
}
|
||||
|
||||
public function connect(){
|
||||
public function connect()
|
||||
{
|
||||
$this->conn = SqlsrvUtil::connect();
|
||||
}
|
||||
|
||||
public function createTable(){
|
||||
public function createTable()
|
||||
{
|
||||
SqlsrvUtil::createCRUDTable( $this->conn, $this->tableName );
|
||||
}
|
||||
|
||||
public function generateInsertValues(){
|
||||
public function generateInsertValues()
|
||||
{
|
||||
$this->insertValues = SqlsrvUtil::generateInsertValues();
|
||||
}
|
||||
/**
|
||||
* Each iteration inserts 1000 rows into the table.
|
||||
* Note that, every insertion calls prepare, bindParam and execute APIs.
|
||||
*/
|
||||
public function benchInsertWithPrepare(){
|
||||
for( $i=0; $i<1000; $i++ ){
|
||||
public function benchInsertWithPrepare()
|
||||
{
|
||||
for( $i=0; $i<SqlsrvUtil::$loopsPerCRUDIter; $i++ )
|
||||
{
|
||||
SqlsrvUtil::insertWithPrepare( $this->conn, $this->tableName, $this->insertValues );
|
||||
}
|
||||
}
|
||||
|
||||
public function dropTable(){
|
||||
public function dropTable()
|
||||
{
|
||||
SqlsrvUtil::dropTable( $this->conn, $this->tableName );
|
||||
}
|
||||
|
||||
public function disconnect(){
|
||||
public function disconnect()
|
||||
{
|
||||
SqlsrvUtil::disconnect( $this->conn );
|
||||
}
|
||||
}
|
|
@ -2,24 +2,29 @@
|
|||
|
||||
use SqlsrvPerfTest\SqlsrvUtil;
|
||||
/**
|
||||
* @Iterations(10000)
|
||||
* @BeforeMethods({"connect"})
|
||||
* @AfterMethods({"disconnect"})
|
||||
*/
|
||||
class SqlsrvSelectVersionBench{
|
||||
class SqlsrvSelectVersionBench
|
||||
{
|
||||
|
||||
private $conn;
|
||||
|
||||
public function connect(){
|
||||
public function connect()
|
||||
{
|
||||
$this->conn = SqlsrvUtil::connect();
|
||||
}
|
||||
/*
|
||||
* Each iteration calls execDirect API to fetch @@Version
|
||||
*/
|
||||
public function benchSelectVersion(){
|
||||
public function benchSelectVersion()
|
||||
{
|
||||
$version = SqlsrvUtil::selectVersion( $this->conn );
|
||||
}
|
||||
|
||||
public function disconnect(){
|
||||
public function disconnect()
|
||||
{
|
||||
SqlsrvUtil::disconnect( $this->conn );
|
||||
}
|
||||
}
|
|
@ -1,11 +1,13 @@
|
|||
<?php
|
||||
|
||||
use SqlsrvPerfTest\SqlsrvUtil;
|
||||
include_once __DIR__ . "/../../lib/CRUDBaseBenchmark.php";
|
||||
/**
|
||||
* @BeforeMethods({"connect", "setTableName", "createTable", "generateInsertValues", "insertWithPrepare", "generateUpdateValues", "generateUpdateParams"})
|
||||
* @AfterMethods({ "dropTable", "disconnect"})
|
||||
*/
|
||||
class SqlsrvUpdateBench{
|
||||
class SqlsrvUpdateBench extends CRUDBaseBenchmark
|
||||
{
|
||||
|
||||
private $conn;
|
||||
private $tableName;
|
||||
|
@ -13,48 +15,59 @@ class SqlsrvUpdateBench{
|
|||
private $updateValues;
|
||||
private $updateParams;
|
||||
|
||||
public function setTableName(){
|
||||
public function setTableName()
|
||||
{
|
||||
$this->tableName = "datatypes_".rand();
|
||||
}
|
||||
|
||||
public function connect(){
|
||||
public function connect()
|
||||
{
|
||||
$this->conn = SqlsrvUtil::connect();
|
||||
}
|
||||
|
||||
public function createTable(){
|
||||
public function createTable()
|
||||
{
|
||||
SqlsrvUtil::createCRUDTable( $this->conn, $this->tableName );
|
||||
}
|
||||
|
||||
public function generateInsertValues(){
|
||||
public function generateInsertValues()
|
||||
{
|
||||
$this->insertValues = SqlsrvUtil::generateInsertValues();
|
||||
}
|
||||
|
||||
public function insertWithPrepare(){
|
||||
public function insertWithPrepare()
|
||||
{
|
||||
SqlsrvUtil::insertWithPrepare( $this->conn, $this->tableName, $this->insertValues );
|
||||
}
|
||||
|
||||
public function generateUpdateValues(){
|
||||
public function generateUpdateValues()
|
||||
{
|
||||
$this->updateValues = SqlsrvUtil::generateUpdateValues();
|
||||
}
|
||||
|
||||
public function generateUpdateParams(){
|
||||
public function generateUpdateParams()
|
||||
{
|
||||
$this->updateParams = SqlsrvUtil::generateUpdateParams();
|
||||
}
|
||||
/**
|
||||
* Each iteration inserts a row into the table, updateWithPrepare() updates that row 1000 times.
|
||||
* Note that, every update calls prepare, bindParam and execute APIs.
|
||||
*/
|
||||
public function benchUpdateWithPrepare(){
|
||||
for( $i=0; $i<1000; $i++ ){
|
||||
$stmt = SqlsrvUtil::updateWithPrepare( $this->conn, $this->tableName, $this->updateValues, $this->updateParams );
|
||||
public function benchUpdateWithPrepare()
|
||||
{
|
||||
for( $i=0; $i<SqlsrvUtil::$loopsPerCRUDIter; $i++ )
|
||||
{
|
||||
SqlsrvUtil::updateWithPrepare( $this->conn, $this->tableName, $this->updateValues, $this->updateParams );
|
||||
}
|
||||
}
|
||||
|
||||
public function dropTable(){
|
||||
public function dropTable()
|
||||
{
|
||||
SqlsrvUtil::dropTable( $this->conn, $this->tableName );
|
||||
}
|
||||
|
||||
public function disconnect(){
|
||||
public function disconnect()
|
||||
{
|
||||
SqlsrvUtil::disconnect( $this->conn );
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
set options=%2
|
||||
set options=%options:"=%
|
||||
C:\php-sdk\bin\phpsdk_setvars.bat && "c:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %1 && .\buildconf --force && .\configure %options% && nmake && nmake install
|
9
test/Performance/lib/CRUDBaseBenchmark.php
Normal file
9
test/Performance/lib/CRUDBaseBenchmark.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @Iterations(1000)
|
||||
*/
|
||||
abstract class CRUDBaseBenchmark
|
||||
{
|
||||
}
|
||||
?>
|
|
@ -2,32 +2,41 @@
|
|||
|
||||
namespace PDOSqlsrvPerfTest;
|
||||
use PDO;
|
||||
class PDOSqlsrvUtil{
|
||||
class PDOSqlsrvUtil
|
||||
{
|
||||
|
||||
public static function connect(){
|
||||
public static $loopsPerCRUDIter = 100;
|
||||
|
||||
public static function connect()
|
||||
{
|
||||
require dirname(__FILE__).DIRECTORY_SEPARATOR.'connect.php';
|
||||
try{
|
||||
try
|
||||
{
|
||||
$conn = new PDO( "sqlsrv:Server=$server; Database=$database; ConnectionPooling=$pooling; MultipleActiveResultSets=$mars" , $uid, $pwd );
|
||||
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
return $conn;
|
||||
}
|
||||
catch( PDOException $e ){
|
||||
catch( PDOException $e )
|
||||
{
|
||||
var_dump( $e );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
public static function disconnect( $conn ){
|
||||
public static function disconnect( $conn )
|
||||
{
|
||||
$conn = null;
|
||||
}
|
||||
|
||||
public static function selectVersion( $conn ){
|
||||
public static function selectVersion( $conn )
|
||||
{
|
||||
$sql = "SELECT @@Version";
|
||||
$stmt = self::query( $conn, $sql );
|
||||
return self::fetch( $stmt );
|
||||
}
|
||||
|
||||
public static function createDbTableProc( $conn, $databaseName, $tableName, $procName ){
|
||||
public static function createDbTableProc( $conn, $databaseName, $tableName, $procName )
|
||||
{
|
||||
$tableParams = "id INTEGER, name VARCHAR(32), value INTEGER, start_date DATE, time_added TIMESTAMP, set_time TIME(7)";
|
||||
$procParams = "@id INTEGER, @name VARCHAR(32)";
|
||||
$procTextBase = "SET NOCOUNT ON; SELECT id, name, value FROM $databaseName.$tableName WHERE id = @id AND name = @name";
|
||||
|
@ -37,7 +46,8 @@ class PDOSqlsrvUtil{
|
|||
self::createStoredProc( $conn, $procName, $procParams, $procTextBase );
|
||||
}
|
||||
|
||||
public static function generateInsertValues(){
|
||||
public static function generateInsertValues()
|
||||
{
|
||||
$vcharVal = "test string";
|
||||
$nvcharVal = "wstring";
|
||||
$intVal = 3;
|
||||
|
@ -52,7 +62,8 @@ class PDOSqlsrvUtil{
|
|||
return $values;
|
||||
}
|
||||
|
||||
public static function generateUpdateValues(){
|
||||
public static function generateUpdateValues()
|
||||
{
|
||||
$vcharVal = "test string updated";
|
||||
$nvcharVal = "wstring updated";
|
||||
$intVal = 5;
|
||||
|
@ -67,7 +78,8 @@ class PDOSqlsrvUtil{
|
|||
return $updatedValues;
|
||||
}
|
||||
|
||||
public static function generateUpdateParams(){
|
||||
public static function generateUpdateParams()
|
||||
{
|
||||
$fieldNames = array(
|
||||
"vstring",
|
||||
"nvstring",
|
||||
|
@ -81,41 +93,47 @@ class PDOSqlsrvUtil{
|
|||
"dtoffset");
|
||||
|
||||
$params = "";
|
||||
foreach( $fieldNames as $fieldName ){
|
||||
foreach( $fieldNames as $fieldName )
|
||||
{
|
||||
$params = $params.$fieldName."=?,";
|
||||
}
|
||||
$params = rtrim($params,", ");
|
||||
return $params;
|
||||
}
|
||||
|
||||
public static function insertWithPrepare( $conn, $tableName, $values ){
|
||||
public static function insertWithPrepare( $conn, $tableName, $values )
|
||||
{
|
||||
$sql = "INSERT INTO $tableName VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
$stmt = self::prepare( $conn, $sql );
|
||||
self::bindParams( $stmt, $values );
|
||||
self::execute( $stmt );
|
||||
}
|
||||
|
||||
public static function fetchWithPrepare( $conn, $tableName ){
|
||||
public static function fetchWithPrepare( $conn, $tableName )
|
||||
{
|
||||
$sql = "SELECT * FROM $tableName";
|
||||
$stmt = self::prepare( $conn, $sql );
|
||||
self::execute( $stmt );
|
||||
while ( $row = self::fetch( $stmt )){}
|
||||
}
|
||||
|
||||
public static function deleteWithPrepare( $conn, $tableName ){
|
||||
public static function deleteWithPrepare( $conn, $tableName )
|
||||
{
|
||||
$sql = "DELETE TOP (1) FROM $tableName";
|
||||
$stmt = self::prepare( $conn, $sql );
|
||||
self::execute( $stmt );
|
||||
}
|
||||
|
||||
public static function updateWithPrepare( $conn, $tableName, $updateValues, $params ){
|
||||
public static function updateWithPrepare( $conn, $tableName, $updateValues, $params )
|
||||
{
|
||||
$sql = "UPDATE $tableName SET ".$params;
|
||||
$stmt = self::prepare( $conn, $sql );
|
||||
self::bindParams( $stmt, $updateValues );
|
||||
self::execute( $stmt );
|
||||
}
|
||||
|
||||
private function bindParams( $stmt, $values ){
|
||||
private function bindParams( $stmt, $values )
|
||||
{
|
||||
//This functionn assumes the fields are from createCRUDTable()
|
||||
self::bindParam( $stmt, 1, $values[0], PDO::PARAM_STR);
|
||||
self::bindParam( $stmt, 2, $values[1], PDO::PARAM_STR);
|
||||
|
@ -129,7 +147,8 @@ class PDOSqlsrvUtil{
|
|||
self::bindParam( $stmt, 10, $values[9], PDO::PARAM_STR);
|
||||
}
|
||||
|
||||
public static function createCRUDTable( $conn, $tableName ){
|
||||
public static function createCRUDTable( $conn, $tableName )
|
||||
{
|
||||
$fields = array(
|
||||
"vstring" => "VARCHAR(64)",
|
||||
"nvstring" => "NVARCHAR(64)",
|
||||
|
@ -142,86 +161,106 @@ class PDOSqlsrvUtil{
|
|||
"vbin" => "VARBINARY",
|
||||
"dtoffset" => "DATETIMEOFFSET");
|
||||
$params = "";
|
||||
foreach( $fields as $fieldName => $type ){
|
||||
foreach( $fields as $fieldName => $type )
|
||||
{
|
||||
$params .= $fieldName." ".$type.",";
|
||||
}
|
||||
$params = rtrim($params,", ");
|
||||
self::createTable( $conn, $tableName, $params );
|
||||
}
|
||||
|
||||
private function createDatabase( $conn, $dbName ){
|
||||
private function createDatabase( $conn, $dbName )
|
||||
{
|
||||
$sql = "CREATE DATABASE $dbName";
|
||||
$conn->exec( $sql );
|
||||
}
|
||||
|
||||
public static function dropDatabase( $conn, $dbName ){
|
||||
public static function dropDatabase( $conn, $dbName )
|
||||
{
|
||||
$sql = "USE MASTER;DROP DATABASE $dbName";
|
||||
$conn->exec( $sql );
|
||||
}
|
||||
|
||||
public static function createTable( $conn, $tableName, $params ){
|
||||
public static function createTable( $conn, $tableName, $params )
|
||||
{
|
||||
$sql = "CREATE TABLE $tableName ($params)";
|
||||
$conn->exec( $sql );
|
||||
}
|
||||
|
||||
public static function dropTable( $conn, $tableName ){
|
||||
public static function dropTable( $conn, $tableName )
|
||||
{
|
||||
$sql = "DROP TABLE $tableName";
|
||||
$conn->exec( $sql );
|
||||
}
|
||||
|
||||
private function useDatabase( $conn, $dbName ){
|
||||
private function useDatabase( $conn, $dbName )
|
||||
{
|
||||
$sql = "USE $dbName";
|
||||
$conn->exec( $sql );
|
||||
}
|
||||
|
||||
private function createStoredProc( $conn, $procName, $params, $text ){
|
||||
private function createStoredProc( $conn, $procName, $params, $text )
|
||||
{
|
||||
$sql = "CREATE PROCEDURE $procName $params AS $text";
|
||||
$conn->exec( $sql );
|
||||
}
|
||||
|
||||
private function dropStoredProc( $conn, $procName ){
|
||||
private function dropStoredProc( $conn, $procName )
|
||||
{
|
||||
$sql = "DROP PROCEDURE $procName";
|
||||
$conn->exec( $sql );
|
||||
}
|
||||
|
||||
private function query( $conn, $sql ){
|
||||
try{
|
||||
private function query( $conn, $sql )
|
||||
{
|
||||
try
|
||||
{
|
||||
return $conn->query( $sql );
|
||||
}
|
||||
catch( PDOException $e ){
|
||||
catch( PDOException $e )
|
||||
{
|
||||
var_dump( $e );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
private function fetch( $stmt ){
|
||||
private function fetch( $stmt )
|
||||
{
|
||||
return $stmt->fetch();
|
||||
}
|
||||
|
||||
private function prepare( $conn, $sql ){
|
||||
try{
|
||||
private function prepare( $conn, $sql )
|
||||
{
|
||||
try
|
||||
{
|
||||
$stmt = $conn->prepare( $sql );
|
||||
if( $stmt === false ){
|
||||
if( $stmt === false )
|
||||
{
|
||||
die( "Failed to prepare\n");
|
||||
}
|
||||
return $stmt;
|
||||
}
|
||||
catch( PDOException $e ){
|
||||
catch( PDOException $e )
|
||||
{
|
||||
var_dump( $e );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
private function execute( $stmt ){
|
||||
private function execute( $stmt )
|
||||
{
|
||||
$ret = $stmt->execute();
|
||||
if( $ret === false ){
|
||||
if( $ret === false )
|
||||
{
|
||||
die( "Failed to execute\n" );
|
||||
}
|
||||
}
|
||||
|
||||
private function bindParam( $stmt, $index, $value, $type ){
|
||||
private function bindParam( $stmt, $index, $value, $type )
|
||||
{
|
||||
$ret = $stmt->bindParam( $index, $value, $type );
|
||||
if ( $ret === false){
|
||||
if ( $ret === false)
|
||||
{
|
||||
die( "Faild to bind\n");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,35 +2,45 @@
|
|||
|
||||
namespace SqlsrvPerfTest;
|
||||
|
||||
class SqlsrvUtil{
|
||||
class SqlsrvUtil
|
||||
{
|
||||
|
||||
public static $loopsPerCRUDIter = 100;
|
||||
|
||||
public static function connect(){
|
||||
public static function connect()
|
||||
{
|
||||
require dirname(__FILE__).DIRECTORY_SEPARATOR.'connect.php';
|
||||
$options = array( "Database"=>$database, "UID"=>$uid, "PWD"=>$pwd, "ConnectionPooling"=>$pooling, "MultipleActiveResultSets"=>$mars );
|
||||
$conn = sqlsrv_connect( $server, $options );
|
||||
if ( $conn === false ){
|
||||
if ( $conn === false )
|
||||
{
|
||||
die( print_r( sqlsrv_errors(), true));
|
||||
}
|
||||
return $conn;
|
||||
}
|
||||
|
||||
public static function disconnect( $conn ){
|
||||
if ( $conn === false || $conn === null ){
|
||||
public static function disconnect( $conn )
|
||||
{
|
||||
if ( $conn === false || $conn === null )
|
||||
{
|
||||
die( print_r( "Invalid connection resource\n"));
|
||||
}
|
||||
$ret = sqlsrv_close( $conn );
|
||||
if ( $ret === false ){
|
||||
if ( $ret === false )
|
||||
{
|
||||
die( print_r( sqlsrv_errors(), true));
|
||||
}
|
||||
}
|
||||
|
||||
public static function selectVersion( $conn ){
|
||||
public static function selectVersion( $conn )
|
||||
{
|
||||
$sql = "SELECT @@Version";
|
||||
$stmt = self::query( $conn, $sql );
|
||||
return self::fetchArray( $stmt );
|
||||
}
|
||||
|
||||
public static function createDbTableProc( $conn, $databaseName, $tableName, $procName ){
|
||||
public static function createDbTableProc( $conn, $databaseName, $tableName, $procName )
|
||||
{
|
||||
$tableParams = "id INTEGER, name VARCHAR(32), value INTEGER, start_date DATE, time_added TIMESTAMP, set_time TIME(7)";
|
||||
$procParams = "@id INTEGER, @name VARCHAR(32)";
|
||||
$procTextBase = "SET NOCOUNT ON; SELECT id, name, value FROM $databaseName.$tableName WHERE id = @id AND name = @name";
|
||||
|
@ -40,7 +50,8 @@ class SqlsrvUtil{
|
|||
self::createStoredProc( $conn, $procName, $procParams, $procTextBase );
|
||||
}
|
||||
|
||||
public static function generateInsertValues(){
|
||||
public static function generateInsertValues()
|
||||
{
|
||||
$vcharVal = "test string";
|
||||
$nvcharVal = "wstring";
|
||||
$intVal = 3;
|
||||
|
@ -55,7 +66,8 @@ class SqlsrvUtil{
|
|||
return $values;
|
||||
}
|
||||
|
||||
public static function generateUpdateValues(){
|
||||
public static function generateUpdateValues()
|
||||
{
|
||||
$vcharVal = "test string updated";
|
||||
$nvcharVal = "wstring updated";
|
||||
$intVal = 5;
|
||||
|
@ -70,7 +82,8 @@ class SqlsrvUtil{
|
|||
return $updatedValues;
|
||||
}
|
||||
|
||||
public static function generateUpdateParams(){
|
||||
public static function generateUpdateParams()
|
||||
{
|
||||
$fieldNames = array(
|
||||
"vstring",
|
||||
"nvstring",
|
||||
|
@ -84,33 +97,38 @@ class SqlsrvUtil{
|
|||
"dtoffset");
|
||||
|
||||
$params = "";
|
||||
foreach( $fieldNames as $fieldName ){
|
||||
foreach( $fieldNames as $fieldName )
|
||||
{
|
||||
$params = $params.$fieldName."=?,";
|
||||
}
|
||||
$params = rtrim($params,", ");
|
||||
return $params;
|
||||
}
|
||||
|
||||
public static function insertWithPrepare( $conn, $tableName, $values ){
|
||||
public static function insertWithPrepare( $conn, $tableName, $values )
|
||||
{
|
||||
$sql = "INSERT INTO $tableName VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
$stmt = self::prepare( $conn, $sql, $values );
|
||||
self::execute( $stmt );
|
||||
}
|
||||
|
||||
public static function updateWithPrepare( $conn, $tableName, $updateValues, $params ){
|
||||
public static function updateWithPrepare( $conn, $tableName, $updateValues, $params )
|
||||
{
|
||||
$sql = "UPDATE $tableName SET ".$params;
|
||||
$stmt = self::prepare( $conn, $sql, $updateValues );
|
||||
self::execute( $stmt );
|
||||
}
|
||||
|
||||
public static function fetchWithPrepare( $conn, $tableName ){
|
||||
public static function fetchWithPrepare( $conn, $tableName )
|
||||
{
|
||||
$sql = "SELECT * FROM $tableName";
|
||||
$stmt = self::prepare( $conn, $sql, array());
|
||||
self::execute( $stmt );
|
||||
while( $row = self::fetchArray( $stmt ) ) {}
|
||||
}
|
||||
|
||||
public static function createCRUDTable( $conn, $tableName ){
|
||||
public static function createCRUDTable( $conn, $tableName )
|
||||
{
|
||||
$fields = array(
|
||||
"vstring" => "VARCHAR(64)",
|
||||
"nvstring" => "NVARCHAR(64)",
|
||||
|
@ -123,108 +141,131 @@ class SqlsrvUtil{
|
|||
"vbin" => "VARBINARY",
|
||||
"dtoffset" => "DATETIMEOFFSET");
|
||||
$params = "";
|
||||
foreach( $fields as $fieldName => $type ){
|
||||
foreach( $fields as $fieldName => $type )
|
||||
{
|
||||
$params .= $fieldName." ".$type.",";
|
||||
}
|
||||
$params = rtrim($params,", ");
|
||||
self::createTable( $conn, $tableName, $params );
|
||||
}
|
||||
|
||||
public static function query( $conn, $sql ){
|
||||
public static function query( $conn, $sql )
|
||||
{
|
||||
$stmt = sqlsrv_query( $conn, $sql );
|
||||
if( $stmt === false ){
|
||||
if( $stmt === false )
|
||||
{
|
||||
die( print_r( sqlsrv_errors(), true));
|
||||
}
|
||||
return $stmt;
|
||||
}
|
||||
|
||||
public static function fetch( $stmt ){
|
||||
public static function fetch( $stmt )
|
||||
{
|
||||
$ret = sqlsrv_fetch( $stmt );
|
||||
if( $ret === false ){
|
||||
if( $ret === false )
|
||||
{
|
||||
die( print_r( sqlsrv_errors(), true));
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public static function fetchArray( $stmt ){
|
||||
public static function fetchArray( $stmt )
|
||||
{
|
||||
$row = sqlsrv_fetch_array( $stmt );
|
||||
if ( $row === false ){
|
||||
if ( $row === false )
|
||||
{
|
||||
die( print_r( sqlsrv_errors(), true));
|
||||
}
|
||||
return $row;
|
||||
}
|
||||
|
||||
public static function getField( $stmt, $index ){
|
||||
public static function getField( $stmt, $index )
|
||||
{
|
||||
return sqlsrv_get_field( $stmt, $index );
|
||||
}
|
||||
|
||||
private function createDatabase( $conn, $dbName ){
|
||||
private function createDatabase( $conn, $dbName )
|
||||
{
|
||||
$sql = "CREATE DATABASE $dbName";
|
||||
self::query( $conn, $sql );
|
||||
}
|
||||
|
||||
public static function dropDatabase( $conn, $dbName ){
|
||||
public static function dropDatabase( $conn, $dbName )
|
||||
{
|
||||
$sql = "USE MASTER;DROP DATABASE $dbName";
|
||||
self::query( $conn, $sql );
|
||||
}
|
||||
|
||||
public static function createTable( $conn, $tableName, $params ){
|
||||
public static function createTable( $conn, $tableName, $params )
|
||||
{
|
||||
$sql = "CREATE TABLE $tableName ($params)";
|
||||
self::query( $conn, $sql );
|
||||
}
|
||||
|
||||
public static function dropTable( $conn, $tableName ){
|
||||
public static function dropTable( $conn, $tableName )
|
||||
{
|
||||
$sql = "DROP TABLE $tableName";
|
||||
self::query( $conn, $sql );
|
||||
}
|
||||
|
||||
private function useDatabase( $conn, $dbName ){
|
||||
private function useDatabase( $conn, $dbName )
|
||||
{
|
||||
$sql = "USE $dbName";
|
||||
self::query( $conn, $sql );
|
||||
}
|
||||
|
||||
private function createStoredProc( $conn, $procName, $params, $text ){
|
||||
private function createStoredProc( $conn, $procName, $params, $text )
|
||||
{
|
||||
$sql = "CREATE PROCEDURE $procName $params AS $text";
|
||||
self::query( $conn, $sql );
|
||||
}
|
||||
|
||||
private function dropStoredProc( $conn, $procName ){
|
||||
private function dropStoredProc( $conn, $procName )
|
||||
{
|
||||
$sql = "DROP PROCEDURE $procName";
|
||||
self::query( $conn, $sql );
|
||||
}
|
||||
|
||||
private function insert( $conn, $tableName, $values ){
|
||||
private function insert( $conn, $tableName, $values )
|
||||
{
|
||||
$sql = "INSERT INTO $tableName values ($values)";
|
||||
self::query( $conn, $sql );
|
||||
}
|
||||
|
||||
private function update( $conn, $tableName, $params, $condition ){
|
||||
private function update( $conn, $tableName, $params, $condition )
|
||||
{
|
||||
$sql = "UPDATE $tableName SET $params WHERE $condition";
|
||||
self::query( $sql );
|
||||
}
|
||||
|
||||
public function delete( $conn, $tableName){
|
||||
public function delete( $conn, $tableName)
|
||||
{
|
||||
$sql = "DELETE TOP (1) FROM $tableName";
|
||||
self::query( $conn, $sql );
|
||||
}
|
||||
|
||||
public function deleteWithPrepare( $conn, $tableName ){
|
||||
public function deleteWithPrepare( $conn, $tableName )
|
||||
{
|
||||
$sql = "DELETE TOP (1) FROM $tableName";
|
||||
$stmt = self::prepare( $conn, $sql, array() );
|
||||
self::execute( $stmt );
|
||||
}
|
||||
|
||||
private function prepare( $conn, $sql, $params ){
|
||||
private function prepare( $conn, $sql, $params )
|
||||
{
|
||||
$stmt = sqlsrv_prepare( $conn, $sql, $params );
|
||||
if( $stmt === false ){
|
||||
if( $stmt === false )
|
||||
{
|
||||
die( print_r( sqlsrv_errors(), true));
|
||||
}
|
||||
return $stmt;
|
||||
}
|
||||
|
||||
public function execute( $stmt ){
|
||||
public function execute( $stmt )
|
||||
{
|
||||
$ret = sqlsrv_execute( $stmt );
|
||||
if ( $ret === false ){
|
||||
if ( $ret === false )
|
||||
{
|
||||
die( print_r( sqlsrv_errors(), true));
|
||||
}
|
||||
}
|
||||
|
|
6
test/Performance/lib/result_db.php
Normal file
6
test/Performance/lib/result_db.php
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?php
|
||||
$server = 'server';
|
||||
$database = 'testdb';
|
||||
$uid = 'usr';
|
||||
$pwd = 'pwd';
|
||||
?>
|
|
@ -1,8 +1,9 @@
|
|||
--The script can be run to read the results. You can filter out the results ran on a certain date by changing the date at the end.
|
||||
DECLARE @convByteToMegabyte int = 1048576
|
||||
select t1.ResultId, Test, Client, Server, Driver, Duration, Memory, Success, Team, StartTime from
|
||||
(
|
||||
select pr.ResultId, pr.Success, pt.TestName as Test, cl.HostName as Client, srv.HostName as Server,
|
||||
tm.TeamName as Team, st.value as Driver, bi.value as Duration, bi2.value as Memory, dt.value as StartTime from
|
||||
tm.TeamName as Team, st.value as Driver, bi.value as Duration, CAST(bi2.value AS decimal(10,2))/@convByteToMegabyte as Memory, dt.value as StartTime from
|
||||
KeyValueTableBigInt bi,
|
||||
KeyValueTableBigInt bi2,
|
||||
KeyValueTableString st,
|
||||
|
@ -20,5 +21,4 @@ and cl.ClientId = pr.ClientId
|
|||
and pt.TestId = pr.TestId
|
||||
and tm.TeamId = pr.TeamId
|
||||
and srv.ServerId = pr.ServerId
|
||||
) t1 where StartTime like '%2017-06-23%'
|
||||
|
||||
) t1 where StartTime like '%2017-06-23%'
|
|
@ -25,19 +25,18 @@ from time import strftime
|
|||
import hashlib
|
||||
|
||||
"""
|
||||
Paths to current benchmarks. These constants should be modified if there are any changes in folder structure of the project. "regular" folder contains the benchmarks that can be run for any iterations. "large" folder contains the benchmarks ( currently the benchmark that fetches large amount of data ) that take long time to run and meant to have less number of iterations than the regular ones.
|
||||
Paths to current benchmarks. These constants should be modified if there are any changes in folder structure of the project.
|
||||
"""
|
||||
|
||||
sqlsrv_regular_path = "benchmark" + os.sep + "sqlsrv" + os.sep + "regular"
|
||||
sqlsrv_large_path = "benchmark" + os.sep + "sqlsrv" + os.sep + "large"
|
||||
pdo_regular_path = "benchmark" + os.sep + "pdo_sqlsrv" + os.sep + "regular"
|
||||
pdo_large_path = "benchmark" + os.sep + "pdo_sqlsrv" + os.sep + "large"
|
||||
sqlsrv_path = "benchmark" + os.sep + "sqlsrv"
|
||||
pdo_path = "benchmark" + os.sep + "pdo_sqlsrv"
|
||||
|
||||
"""
|
||||
Path to the connect.php file that contains test database credentials. Note that, the benchmarks are run against this database and it is different from Result database.
|
||||
"""
|
||||
connect_file = "lib" + os.sep + "connect.php"
|
||||
connect_file_bak = connect_file + ".bak"
|
||||
result_file = "lib" + os.sep + "result_db.php"
|
||||
|
||||
"""
|
||||
Global data format used across the script
|
||||
|
@ -59,6 +58,7 @@ def validate_platform( platform_name ):
|
|||
, "WindowsServer2012"
|
||||
, "Ubuntu16"
|
||||
, "RedHat7"
|
||||
, "SUSE12"
|
||||
, "Sierra"]
|
||||
if platform_name not in platforms:
|
||||
print ( "Platform must be one of the following:" )
|
||||
|
@ -122,6 +122,7 @@ def get_test_name( name ):
|
|||
test_name_dict = {
|
||||
'SqlsrvConnectionBench': 'connection'
|
||||
, 'SqlsrvCreateDbTableProcBench': 'create'
|
||||
, 'SqlsrvCRUDBench': 'crud'
|
||||
, 'SqlsrvInsertBench': 'crud-create'
|
||||
, 'SqlsrvFetchBench': 'crud-retrieve'
|
||||
, 'SqlsrvUpdateBench': 'crud-update'
|
||||
|
@ -130,6 +131,7 @@ def get_test_name( name ):
|
|||
, 'SqlsrvSelectVersionBench': 'version'
|
||||
, 'PDOConnectionBench': 'connection'
|
||||
, 'PDOCreateDbTableProcBench': 'create'
|
||||
, 'PDOCRUDBench': 'crud'
|
||||
, 'PDOInsertBench': 'crud-create'
|
||||
, 'PDOFetchBench': 'crud-retrieve'
|
||||
, 'PDOUpdateBench': 'crud-update'
|
||||
|
@ -139,18 +141,17 @@ def get_test_name( name ):
|
|||
}
|
||||
return test_name_dict[ name ]
|
||||
|
||||
def get_run_command( path_to_tests, iterations, dump_file ):
|
||||
def get_run_command( path_to_tests, dump_file ):
|
||||
"""
|
||||
This module returns the command to run the tests
|
||||
Args:
|
||||
path_to_tests (str): The folder that contains the tests to be run
|
||||
iterations (str): Number of iterations
|
||||
dump_file (str): The name of the XML file to output the results
|
||||
Returns:
|
||||
The command to run the tests
|
||||
"""
|
||||
command = "vendor" + os.sep + "bin" + os.sep + "phpbench run {0} --iterations {1} --dump-file={2}"
|
||||
return command.format( path_to_tests, iterations, dump_file )
|
||||
command = "vendor" + os.sep + "bin" + os.sep + "phpbench run {0} --dump-file={1}"
|
||||
return command.format( path_to_tests, dump_file )
|
||||
|
||||
def get_id( conn, id_field, table, name_field, value ):
|
||||
"""
|
||||
|
@ -196,14 +197,14 @@ def get_id_no_quote( conn, id_field, table, name_field, value ):
|
|||
return id[0]
|
||||
return id
|
||||
|
||||
def get_test_database():
|
||||
def get_test_database( database_file ):
|
||||
"""
|
||||
This module reads test database details from connect.php and stores them into an instance of DB class
|
||||
Returns:
|
||||
A DB object that contains database credentials
|
||||
"""
|
||||
test_db = DB()
|
||||
for line in open( connect_file ):
|
||||
for line in open( database_file ):
|
||||
if "server" in line:
|
||||
test_db.server_name = line.split("=")[1].strip()[1:-2]
|
||||
elif "database" in line:
|
||||
|
@ -611,21 +612,23 @@ def disable_pooling():
|
|||
copyfile( odbcinst_bak, odbcinst )
|
||||
os.remove( odbcinst_bak )
|
||||
|
||||
def run_tests( iterations, iterations_large ):
|
||||
def run_tests( php_driver, test_name ):
|
||||
"""
|
||||
This module runs the tests using PHPBench
|
||||
Args:
|
||||
iterations (int): Number of iterations the tests in "regular" folder are run for
|
||||
iterations_large (int): Number of iterations the tests in "large" folder are run for
|
||||
php_driver (str): Name of the driver to be tested: sqlsrv, pdo_sqlsrv, or both
|
||||
test_name (str): File name of the test or all
|
||||
Returns:
|
||||
N/A
|
||||
"""
|
||||
print("Running the tests...")
|
||||
call( get_run_command( sqlsrv_regular_path, iterations, "sqlsrv-regular.xml" ), shell=True )
|
||||
call( get_run_command( sqlsrv_large_path, iterations_large, "sqlsrv-large.xml" ), shell=True )
|
||||
|
||||
call( get_run_command( pdo_regular_path, iterations, "pdo_sqlsrv-regular.xml" ), shell=True )
|
||||
call( get_run_command( pdo_large_path, iterations_large, "pdo_sqlsrv-large.xml" ), shell=True )
|
||||
add_to_path = ''
|
||||
if test_name != 'all':
|
||||
add_to_path = os.sep + test_name
|
||||
if php_driver == 'sqlsrv' or php_driver == 'both':
|
||||
call( get_run_command( sqlsrv_path + add_to_path, "sqlsrv-results.xml" ), shell=True )
|
||||
if php_driver == 'pdo_sqlsrv' or php_driver == 'both':
|
||||
call( get_run_command( pdo_path + add_to_path, "pdo_sqlsrv-results.xml" ), shell=True )
|
||||
|
||||
def parse_results( dump_file ):
|
||||
"""
|
||||
|
@ -656,6 +659,7 @@ def parse_results( dump_file ):
|
|||
# If the bechmark was run successfully, parse the results. This is where you would add code to parse more details about the benchmark.
|
||||
else:
|
||||
xml_result.success = 1
|
||||
# convert microseconds to seconds
|
||||
xml_result.duration = int( round( int( benchmark[0][0].find( 'stats' ).get( 'sum' )) / 1000000 ))
|
||||
iterations = benchmark[0][0].findall( 'iteration' )
|
||||
xml_result.iterations = len( iterations )
|
||||
|
@ -685,6 +689,11 @@ def parse_and_store_results( dump_file, test_db, result_db, platform, driver, st
|
|||
Returns:
|
||||
N/A
|
||||
"""
|
||||
# Check if the xml file actually exist
|
||||
if not os.path.exists(dump_file):
|
||||
print(dump_file + " does not exist")
|
||||
return
|
||||
|
||||
# Connect to the Result Database
|
||||
conn = connect( result_db )
|
||||
|
||||
|
@ -742,20 +751,14 @@ def parse_and_store_results_all( test_db, result_db, platform, start_time, mars,
|
|||
|
||||
"""
|
||||
print("Parsing and storing the results...")
|
||||
parse_and_store_results( "sqlsrv-regular.xml", test_db, result_db, platform, "sqlsrv", start_time, mars, pooling )
|
||||
parse_and_store_results( "sqlsrv-large.xml", test_db, result_db, platform, "sqlsrv", start_time, mars, pooling )
|
||||
parse_and_store_results( "pdo_sqlsrv-regular.xml", test_db, result_db, platform, "pdo_sqlsrv", start_time, mars, pooling )
|
||||
parse_and_store_results( "pdo_sqlsrv-large.xml", test_db, result_db, platform, "pdo_sqlsrv", start_time, mars, pooling )
|
||||
parse_and_store_results( "sqlsrv-results.xml", test_db, result_db, platform, "sqlsrv", start_time, mars, pooling )
|
||||
parse_and_store_results( "pdo_sqlsrv-results.xml", test_db, result_db, platform, "pdo_sqlsrv", start_time, mars, pooling )
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument( '-platform', '--PLATFORM', required=True, help='The name of the platform the tests run on' )
|
||||
parser.add_argument( '-iterations', '--ITERATIONS', required=True, help='Number of iterations for regular tests', type=int )
|
||||
parser.add_argument( '-iterations-large', '--ITERATIONS_LARGE', required=True, help='Number of iterations for regular tests', type=int )
|
||||
parser.add_argument( '-result-server', '--RESULT_SERVER', required=True, help='IP address of the Result Server' )
|
||||
parser.add_argument( '-result-db', '--RESULT_DB', required=True, help='Name of the Result Database' )
|
||||
parser.add_argument( '-result-uid', '--RESULT_UID', required=True, help='Username to connect to the Result Database' )
|
||||
parser.add_argument( '-result-pwd', '--RESULT_PWD', required=True, help='Password to connect to the Result Database' )
|
||||
parser.add_argument( '-platform', '--PLATFORM', required=True, help='The name of the platform the tests run on' )
|
||||
parser.add_argument( '-php-driver', '--PHP_DRIVER', default='both', help='Name of the PHP driver: sqlsrv, pdo_sqlsrv or both')
|
||||
parser.add_argument( '-testname', '--TESTNAME', default='all', help='File name for only one test or all' )
|
||||
args = parser.parse_args()
|
||||
|
||||
# Start time is recorded only in the beginning of this script execution. So it is not benchmark specific.
|
||||
|
@ -764,12 +767,12 @@ if __name__ == '__main__':
|
|||
print( "Start time: " + start_time )
|
||||
|
||||
validate_platform( args.PLATFORM )
|
||||
result_db = DB( args.RESULT_SERVER, args.RESULT_DB, args.RESULT_UID, args.RESULT_PWD )
|
||||
test_db = get_test_database()
|
||||
result_db = get_test_database( result_file )
|
||||
test_db = get_test_database( connect_file )
|
||||
|
||||
print("Running the tests with default settings...")
|
||||
|
||||
run_tests( args.ITERATIONS, args.ITERATIONS_LARGE )
|
||||
run_tests( args.PHP_DRIVER, args.TESTNAME )
|
||||
parse_and_store_results_all( test_db, result_db, args.PLATFORM, start_time, 0, 0 )
|
||||
"""
|
||||
The following lines are commented out, because it already takes a long time to run the tests with the default settings.
|
||||
|
@ -777,17 +780,17 @@ if __name__ == '__main__':
|
|||
|
||||
print("Running the tests with MARS ON...")
|
||||
enable_mars()
|
||||
run_tests( args.ITERATIONS, args.ITERATIONS_LARGE )
|
||||
run_tests( args.PHP_DRIVER, args.TESTNAME )
|
||||
parse_and_store_results_all( test_db, result_db, args.PLATFORM, start_time, 1, 0 )
|
||||
disable_mars()
|
||||
|
||||
|
||||
print("Running the tests with Pooling ON...")
|
||||
enable_pooling()
|
||||
run_tests( args.ITERATIONS, args.ITERATIONS_LARGE )
|
||||
run_tests( args.PHP_DRIVER, args.TESTNAME )
|
||||
parse_and_store_results_all( test_db, result_db, args.PLATFORM, start_time, 0, 1 )
|
||||
disable_pooling()
|
||||
"""
|
||||
exit()
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,140 +1,212 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
if [[ ("$1" = "Ubuntu16" || "$1" = "RedHat7" || "$1" = "Sierra") ]]; then
|
||||
|
||||
if [[ ("$1" = "Ubuntu16" || "$1" = "RedHat7" || "$1" = "SUSE12" || "$1" = "Sierra") ]]; then
|
||||
PLATFORM=$1
|
||||
else
|
||||
echo "First argument must be one of Ubuntu16, RedHat7, Sierra. Exiting..."
|
||||
echo "1st argument must be one of Ubuntu16, RedHat7, SUSE12, Sierra. Exiting..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$2" != 7.*.* ]]; then
|
||||
echo "Second argument must be PHP version in format of 7.x.x.Exiting..."
|
||||
echo "2nd argument must be PHP version in format of 7.x.y. Exiting..."
|
||||
exit
|
||||
else
|
||||
PHP_VERSION=$2
|
||||
fi
|
||||
|
||||
if [[ ("$3" != "nts" && "$3" != "ts") ]]; then
|
||||
echo "Thrid argument must be either nts or ts. Exiting..."
|
||||
echo "3rd argument must be either nts or ts. Exiting..."
|
||||
exit 1
|
||||
else
|
||||
PHP_THREAD=$3
|
||||
fi
|
||||
if [[ (! -d "$4") || (! -d $4/sqlsrv) || (! -d $4/pdo_sqlsrv) || (! -d $4/shared) ]]; then
|
||||
echo "Fourth argument must be path to source folder.Path not found.Exiting..."
|
||||
|
||||
if [[ (! -f "$4") || (! -f "$5") ]]; then
|
||||
echo "4th and 5th argument must be paths to sqlsrv and pdo drivers. Exiting..."
|
||||
exit 1
|
||||
else
|
||||
DRIVER_SOURCE_PATH=$4
|
||||
SQLSRV_DRIVER=$4
|
||||
PDO_DRIVER=$5
|
||||
fi
|
||||
rm -rf env_setup.log
|
||||
touch env_setup.log
|
||||
|
||||
if [ $PLATFORM = "Ubuntu16" ]; then
|
||||
echo "Update..."
|
||||
yes | sudo dpkg --configure -a >> env_setup.log 2>&1
|
||||
yes | sudo apt-get update >> env_setup.log 2>&1
|
||||
echo "Installing git, zip, curl, libxml, autoconf, openssl, python3, pip3..."
|
||||
yes | sudo apt-get install git zip curl autoconf libxml2-dev libssl-dev pkg-config python3 python3-pip >> env_setup.log 2>&1
|
||||
echo "OK"
|
||||
echo "Installing MSODBCSQL..."
|
||||
printf "Update..."
|
||||
yes | sudo dpkg --configure -a > env_setup.log
|
||||
yes | sudo apt-get update >> env_setup.log
|
||||
printf "done\n"
|
||||
|
||||
printf "Installing git, zip, curl, libxml, autoconf, openssl, python3, pip3..."
|
||||
yes | sudo apt-get install git zip curl autoconf libxml2-dev libssl-dev pkg-config python3 python3-pip >> env_setup.log
|
||||
printf "done\n"
|
||||
|
||||
printf "Installing MSODBCSQL..."
|
||||
curl -s https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
|
||||
curl -s https://packages.microsoft.com/config/ubuntu/16.04/prod.list > /etc/apt/sources.list.d/mssql-release.list
|
||||
yes | sudo apt-get update >> env_setup.log 2>&1
|
||||
yes | sudo ACCEPT_EULA=Y apt-get install msodbcsql >> env_setup.log 2>&1
|
||||
yes | sudo apt-get install -qq unixodbc-dev >> env_setup.log 2>&1
|
||||
echo "Installing pyodbc"
|
||||
pip3 install --upgrade pip >> env_setup.log 2>&1
|
||||
pip3 install pyodbc >> env_setup.log 2>&1
|
||||
echo "OK"
|
||||
yes | sudo apt-get update >> env_setup.log
|
||||
yes | sudo ACCEPT_EULA=Y apt-get install msodbcsql >> env_setup.log
|
||||
yes | sudo apt-get install -qq unixodbc-dev >> env_setup.log
|
||||
printf "done\n"
|
||||
|
||||
printf "Installing pyodbc"
|
||||
pip3 install --upgrade pip >> env_setup.log
|
||||
pip3 install pyodbc >> env_setup.log
|
||||
printf "done\n"
|
||||
|
||||
elif [ $PLATFORM = "RedHat7" ]; then
|
||||
echo "Update..."
|
||||
yes | sudo yum update >> env_setup.log 2>&1
|
||||
echo "OK"
|
||||
echo "Enabling EPEL repo..."
|
||||
wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm >> env_setup.log 2>&1
|
||||
yes | sudo yum install epel-release-latest-7.noarch.rpm >> env_setup.log 2>&1 || true
|
||||
echo "OK"
|
||||
echo "Installing python34-setuptools..."
|
||||
yes | sudo yum install python34-setuptools -y >> env_setup.log 2>&1
|
||||
echo "OK"
|
||||
echo "Installing gcc, git, zip libxml, openssl, EPEL, python3, pip3..."
|
||||
yes | sudo yum install -y gcc-c++ libxml2-devel git zip openssl-devel python34 python34-devel python34-pip >> env_setup.log 2>&1
|
||||
echo "OK"
|
||||
echo "Installing MSODBCSQL..."
|
||||
printf "Update..."
|
||||
yes | sudo yum update >> env_setup.log
|
||||
printf "done\n"
|
||||
|
||||
printf "Enabling EPEL repo..."
|
||||
# pipe non-error to log file (wget and yum install reports error when there's nothing to do)
|
||||
wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm >> env_setup.log
|
||||
yes | sudo yum install epel-release-latest-7.noarch.rpm >> env_setup.log || true
|
||||
printf "done\n"
|
||||
|
||||
printf "Installing python34-setuptools..."
|
||||
yes | sudo yum install python34-setuptools -y >> env_setup.log
|
||||
printf "done\n"
|
||||
|
||||
printf "Installing gcc, git, zip libxml, openssl, EPEL, python3, pip3..."
|
||||
yes | sudo yum install -y gcc-c++ libxml2-devel git zip openssl-devel python34 python34-devel python34-pip >> env_setup.log
|
||||
printf "done\n"
|
||||
|
||||
printf "Installing MSODBCSQL..."
|
||||
curl -s https://packages.microsoft.com/config/rhel/7/prod.repo > /etc/yum.repos.d/mssql-release.repo
|
||||
(yes | sudo ACCEPT_EULA=Y yum install -y msodbcsql >> env_setup.log 2>&1)
|
||||
(yes | sudo yum install -y unixODBC-devel autoconf >> env_setup.log 2>&1)
|
||||
echo "OK"
|
||||
echo "Installing pyodbc"
|
||||
pip3 install --upgrade pip >> env_setup.log 2>&1
|
||||
pip3 install pyodbc >> env_setup.log 2>&1
|
||||
echo "OK"
|
||||
(yes | sudo ACCEPT_EULA=Y yum install -y msodbcsql >> env_setup.log)
|
||||
(yes | sudo yum install -y unixODBC-devel autoconf >> env_setup.log)
|
||||
printf "done\n"
|
||||
|
||||
printf "Installing pyodbc"
|
||||
pip3 install --upgrade pip >> env_setup.log
|
||||
pip3 install pyodbc >> env_setup.log
|
||||
printf "done\n"
|
||||
|
||||
elif [ $PLATFORM = "SUSE12" ]; then
|
||||
printf "Update..."
|
||||
sudo zypper refresh >> env_setup.log
|
||||
printf "done\n"
|
||||
|
||||
printf "Installing autoconf, gcc, g++, git, zip, libxml, openssl, python3, pip3..."
|
||||
sudo zypper -n install autoconf gcc gcc-c++ libxml2-devel git zip libopenssl-devel python3-devel python3-pip python3-setuptools >> env_setup.log
|
||||
printf "done\n"
|
||||
|
||||
printf "Installing MSODBCSQL..."
|
||||
zypper -n ar https://packages.microsoft.com/config/sles/12/prod.repo
|
||||
zypper --gpg-auto-import-keys refresh
|
||||
ACCEPT_EULA=Y zypper -n install msodbcsql >> env_setup.log
|
||||
ACCEPT_EULA=Y zypper -n install mssql-tools >> env_setup.log
|
||||
zypper -n install unixODBC-devel >> env_setup.log
|
||||
printf "done\n"
|
||||
|
||||
printf "Installing pyodbc"
|
||||
pip3 install --upgrade pip >> env_setup.log
|
||||
pip3 install pyodbc >> env_setup.log
|
||||
printf "done\n"
|
||||
|
||||
elif [ $PLATFORM = "Sierra" ]; then
|
||||
echo "Installing homebrew..."
|
||||
yes | /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" >> env_setup.log 2>&1
|
||||
echo "OK"
|
||||
echo "Installing wget..."
|
||||
brew install wget >> env_setup.log 2>&1
|
||||
echo "OK"
|
||||
echo "Installing svn..."
|
||||
brew install svn >> env_setup.log 2>&1
|
||||
echo "OK"
|
||||
echo "Installing openssl..."
|
||||
brew install pkg-config >> env_setup.log 2>&1
|
||||
brew install openssl >> env_setup.log 2>&1
|
||||
echo "OK"
|
||||
echo "Installing python3..."
|
||||
brew install python3 >> env_setup.log 2>&1
|
||||
echo "OK"
|
||||
echo "Installing MSODBCSQL..."
|
||||
brew tap microsoft/msodbcsql https://github.com/Microsoft/homebrew-msodbcsql >> env_setup.log 2>&1
|
||||
brew update >> env_setup.log 2>&1
|
||||
yes | ACCEPT_EULA=Y brew install msodbcsql >> env_setup.log 2>&1
|
||||
echo "OK"
|
||||
yes | brew install autoconf >> env_setup.log 2>&1
|
||||
echo "Installing pyodbc..."
|
||||
pip3 install pyodbc >> env_setup.log 2>&1
|
||||
echo "OK"
|
||||
printf "Installing homebrew..."
|
||||
yes | /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" >> env_setup.log
|
||||
printf "done\n"
|
||||
|
||||
printf "Installing wget..."
|
||||
brew install wget >> env_setup.log
|
||||
printf "done\n"
|
||||
|
||||
printf "Installing svn..."
|
||||
brew install svn >> env_setup.log
|
||||
printf "done\n"
|
||||
|
||||
printf "Installing openssl..."
|
||||
brew install pkg-config >> env_setup.log
|
||||
brew install openssl >> env_setup.log
|
||||
printf "done\n"
|
||||
|
||||
printf "Installing python3..."
|
||||
brew install python3 >> env_setup.log
|
||||
printf "done\n"
|
||||
|
||||
printf "Installing MSODBCSQL..."
|
||||
brew tap microsoft/msodbcsql https://github.com/Microsoft/homebrew-msodbcsql >> env_setup.log
|
||||
brew update >> env_setup.log
|
||||
yes | ACCEPT_EULA=Y brew install --no-sandbox msodbcsql >> env_setup.log
|
||||
printf "done\n"
|
||||
|
||||
yes | brew install autoconf >> env_setup.log
|
||||
printf "Installing pyodbc..."
|
||||
pip3 install pyodbc >> env_setup.log
|
||||
printf "done\n"
|
||||
fi
|
||||
echo "Downloading PHP-$PHP_VERSION source tarball..."
|
||||
wget http://ca1.php.net/get/php-$PHP_VERSION.tar.gz/from/this/mirror -O php-$PHP_VERSION.tar.gz >> env_setup.log 2>&1
|
||||
echo "OK"
|
||||
echo "Extracting PHP source tarball..."
|
||||
|
||||
printf "Downloading PHP-$PHP_VERSION source tarball..."
|
||||
# pipe non-error to log file
|
||||
wget http://ca1.php.net/get/php-$PHP_VERSION.tar.gz/from/this/mirror -O php-$PHP_VERSION.tar.gz >> env_setup.log
|
||||
printf "done\n"
|
||||
|
||||
printf "Extracting PHP source tarball..."
|
||||
rm -rf php-$PHP_VERSION
|
||||
tar -xf php-$PHP_VERSION.tar.gz
|
||||
echo "OK"
|
||||
cd php-$PHP_VERSION
|
||||
mkdir ext/sqlsrv ext/pdo_sqlsrv
|
||||
cp -r $DRIVER_SOURCE_PATH/sqlsrv/* $DRIVER_SOURCE_PATH/shared ext/sqlsrv
|
||||
cp -r $DRIVER_SOURCE_PATH/pdo_sqlsrv/* $DRIVER_SOURCE_PATH/shared ext/pdo_sqlsrv
|
||||
./buildconf --force >> ../env_setup.log 2>&1
|
||||
CONFIG_OPTIONS="--enable-cli --enable-cgi --enable-pdo --enable-sqlsrv=shared --with-pdo_sqlsrv=shared --with-odbcver=0x0380 --with-zlib --enable-mbstring --prefix=/usr/local"
|
||||
printf "done\n"
|
||||
|
||||
phpDir=php-$PHP_VERSION
|
||||
cd $phpDir
|
||||
|
||||
printf "Configuring PHP..."
|
||||
./buildconf --force >> ../env_setup.log
|
||||
CONFIG_OPTIONS="--enable-cli --enable-cgi --with-zlib --enable-mbstring --prefix=/usr/local"
|
||||
[ "${PHP_THREAD}" == "ts" ] && CONFIG_OPTIONS=${CONFIG_OPTIONS}" --enable-maintainer-zts"
|
||||
if [ $PLATFORM = "Sierra" ]; then
|
||||
CONFIG_OPTIONS=$CONFIG_OPTIONS" --with-openssl=/usr/local/opt/openssl/"
|
||||
else
|
||||
CONFIG_OPTIONS=$CONFIG_OPTIONS" --with-openssl"
|
||||
fi
|
||||
echo "Configuring PHP..."
|
||||
(./configure $CONFIG_OPTIONS >> ../env_setup.log 2>&1)
|
||||
echo "OK"
|
||||
echo "Compiling PHP and the drivers..."
|
||||
make >> ../env_setup.log 2>&1
|
||||
echo "OK"
|
||||
sudo make install >> ../env_setup.log 2>&1
|
||||
#pipe non-error to log file
|
||||
(./configure $CONFIG_OPTIONS >> ../env_setup.log)
|
||||
printf "done\n"
|
||||
|
||||
printf "Compiling and installing PHP..."
|
||||
make >> ../env_setup.log
|
||||
sudo make install >> ../env_setup.log
|
||||
printf "done\n"
|
||||
|
||||
# check PHP version
|
||||
/usr/local/bin/php -v
|
||||
|
||||
printf "Setting up drivers..."
|
||||
phpExtDir=`/usr/local/bin/php-config --extension-dir`
|
||||
cp php.ini-production php.ini
|
||||
echo "extension=sqlsrv.so" >> php.ini
|
||||
echo "extension=pdo_sqlsrv.so" >> php.ini
|
||||
driverName=$(basename $SQLSRV_DRIVER)
|
||||
echo "extension=$driverName" >> php.ini
|
||||
sudo cp -r $SQLSRV_DRIVER $phpExtDir/$driverName
|
||||
sudo chmod a+r $phpExtDir/$driverName
|
||||
|
||||
driverName=$(basename $PDO_DRIVER)
|
||||
echo "extension=$driverName" >> php.ini
|
||||
sudo cp -r $PDO_DRIVER $phpExtDir/$driverName
|
||||
sudo chmod a+r $phpExtDir/$driverName
|
||||
|
||||
sudo cp php.ini /usr/local/lib
|
||||
printf "done\n"
|
||||
|
||||
# check drivers
|
||||
/usr/local/bin/php --ri sqlsrv
|
||||
/usr/local/bin/php --ri pdo_sqlsrv
|
||||
|
||||
printf "Installing Composer..."
|
||||
cd ..
|
||||
php -v
|
||||
php --ri sqlsrv
|
||||
php --ri pdo_sqlsrv
|
||||
echo "Installing Composer..."
|
||||
wget https://getcomposer.org/installer -O composer-setup.php >> env_setup.log 2>&1
|
||||
php composer-setup.php >> env_setup.log 2>&1
|
||||
echo "OK"
|
||||
echo "Installing PHPBench..."
|
||||
php composer.phar install >> env_setup.log 2>&1
|
||||
echo "OK"
|
||||
echo "Cleaning up..."
|
||||
rm -rf php-$PHP_VERSION* compser-setup.php
|
||||
echo "OK"
|
||||
echo "Setup completed!"
|
||||
# pipe non-error to log file
|
||||
wget https://getcomposer.org/installer -O composer-setup.php >> env_setup.log
|
||||
/usr/local/bin/php composer-setup.php >> env_setup.log
|
||||
printf "done\n"
|
||||
|
||||
printf "Installing PHPBench...\n"
|
||||
/usr/local/bin/php composer.phar install >> env_setup.log
|
||||
printf "done\n"
|
||||
|
||||
printf "Cleaning up..."
|
||||
rm -rf $phpDir compser-setup.php
|
||||
printf "done\n"
|
||||
|
||||
echo "Setup completed!"
|
||||
|
|
|
@ -1,28 +1,13 @@
|
|||
Param(
|
||||
[Parameter(Mandatory=$True,Position=1)]
|
||||
[string]$PHP_VERSION,
|
||||
[Parameter(Mandatory=$True,Position=2)]
|
||||
[string]$PHP_THREAD,
|
||||
[string]$PHP_ZIP,
|
||||
[Parameter(Mandatory=$True,Position=2)]
|
||||
[string]$SQLSRV_DRIVER,
|
||||
[Parameter(Mandatory=$True,Position=3)]
|
||||
[string]$DRIVER_SOURCE_PATH,
|
||||
[Parameter(Mandatory=$True,Position=4)]
|
||||
[string]$ARCH
|
||||
[string]$PDO_DRIVER
|
||||
)
|
||||
|
||||
IF($ARCH -ne "x64" -And $ARCH -ne "x86"){
|
||||
Write-Host "ARCH must either x64 or x86"
|
||||
Break
|
||||
}
|
||||
|
||||
IF($PHP_THREAD -ne "nts" -And $PHP_THREAD -ne "ts"){
|
||||
Write-Host "PHP_THREAD must either nts or ts"
|
||||
Break
|
||||
}
|
||||
|
||||
IF($PHP_VERSION -NotMatch "7.[0-1].[0-9]"){
|
||||
Write-Host "PHP_VERSION must be in format of 7.x.x"
|
||||
Break
|
||||
}
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$startingDir=$pwd.Path
|
||||
$tempFolder=Join-Path $startingDir "temp"
|
||||
|
@ -30,17 +15,12 @@ $tempFolder=Join-Path $startingDir "temp"
|
|||
Remove-Item temp -Recurse -Force -ErrorAction Ignore
|
||||
New-Item -ItemType directory -Path temp
|
||||
|
||||
(New-Object System.Net.WebClient).DownloadFile("http://windows.php.net/downloads/releases/sha1sum.txt","$tempFolder\sha1sum.txt")
|
||||
$PHP70_LATEST_VERSION=type $tempFolder\sha1sum.txt | where { $_ -match "php-(7.0\.\d+)-src" } | foreach { $matches[1] }
|
||||
$PHP71_LATEST_VERSION=type $tempFolder\sha1sum.txt | where { $_ -match "php-(7.1\.\d+)-src" } | foreach { $matches[1] }
|
||||
|
||||
$PHP_VERSION_MINOR=$PHP_VERSION.split(".")[1]
|
||||
|
||||
Write-Host "Installing chocolatey..."
|
||||
iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
|
||||
Write-Host "Installing Git..."
|
||||
choco install -y git
|
||||
Set-Alias git 'C:\Program Files\Git\cmd\git.exe'
|
||||
|
||||
$gitDir = 'C:\Program Files\Git\cmd\git.exe'
|
||||
Write-Host "Installing Python3..."
|
||||
choco install -y python3
|
||||
RefreshEnv
|
||||
|
@ -54,65 +34,38 @@ msiexec /quiet /passive /qn /i $tempFolder\msodbcsql.msi IACCEPTMSODBCSQLLICENSE
|
|||
Write-Host "Installing 7-Zip..."
|
||||
choco install -y 7zip.install
|
||||
|
||||
Write-Host "Downloading PHP-SDK..."
|
||||
(New-Object System.Net.WebClient).DownloadFile('http://windows.php.net/downloads/php-sdk/php-sdk-binary-tools-20110915.zip', "$tempFolder\binary_tools.zip")
|
||||
Write-Host "Downloading PHP-$PHP_VERSION source..."
|
||||
IF($PHP_VERSION -eq $PHP70_LATEST_VERSION -Or $PHP_VERSION -eq $PHP71_LATEST_VERSION){
|
||||
(New-Object System.Net.WebClient).DownloadFile("http://windows.php.net/downloads/releases/php-$PHP_VERSION-src.zip", "$tempFolder\php-$PHP_VERSION-src.zip")
|
||||
}
|
||||
ELSE{
|
||||
(New-Object System.Net.WebClient).DownloadFile("http://windows.php.net/downloads/releases/archives/php-$PHP_VERSION-src.zip", "$tempFolder\php-$PHP_VERSION-src.zip")
|
||||
}
|
||||
Write-Host "Installing PHP..."
|
||||
$phpDir="C:\php"
|
||||
|
||||
Write-Host "Downloading Dependencies..."
|
||||
(New-Object System.Net.WebClient).DownloadFile("http://windows.php.net/downloads/php-sdk/deps-7.$PHP_VERSION_MINOR-vc14-$ARCH.7z", "$tempFolder\deps-7.$PHP_VERSION_MINOR-vc14-$ARCH.7z")
|
||||
# remove existing PHP and setup new one
|
||||
Remove-Item $phpDir -Recurse -ErrorAction Ignore
|
||||
New-Item -ItemType directory -Path $phpDir
|
||||
Expand-Archive $PHP_ZIP -DestinationPath $phpDir
|
||||
|
||||
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||
Remove-Item C:\php-sdk -Recurse -Force -ErrorAction Ignore
|
||||
New-Item -ItemType directory -Path C:\php-sdk
|
||||
[System.IO.Compression.ZipFile]::ExtractToDirectory("$tempFolder\binary_tools.zip", "C:\php-sdk")
|
||||
cd C:\php-sdk\
|
||||
bin\phpsdk_buildtree.bat phpdev
|
||||
New-Item -ItemType directory -Path .\phpdev\vc14
|
||||
Copy-Item .\phpdev\vc9\* phpdev\vc14\ -recurse
|
||||
[System.IO.Compression.ZipFile]::ExtractToDirectory("$tempFolder\php-$PHP_VERSION-src.zip", "C:\php-sdk\phpdev\vc14\$ARCH\")
|
||||
7z.exe x $tempFolder\deps-7.$PHP_VERSION_MINOR-vc14-$ARCH.7z -oC:\php-sdk\phpdev\vc14\$ARCH\
|
||||
# copy drivers to extensions directory and rename to a standard nomenclature
|
||||
# for consistency with run-perf_tests.py
|
||||
Copy-Item $SQLSRV_DRIVER $phpDir\ext\php_sqlsrv.dll
|
||||
Copy-Item $PDO_DRIVER $phpDir\ext\php_pdo_sqlsrv.dll
|
||||
|
||||
bin\phpsdk_setvars.bat
|
||||
# setup driver
|
||||
Copy-Item $phpDir\php.ini-production $phpDir\php.ini
|
||||
Add-Content $phpDir\php.ini "extension=$phpDir\ext\php_openssl.dll"
|
||||
Add-Content $phpDir\php.ini "extension=$phpDir\ext\php_mbstring.dll"
|
||||
|
||||
cd C:\php-sdk\phpdev\vc14\$ARCH\php-$PHP_VERSION-src
|
||||
|
||||
New-Item -ItemType directory -Path .\ext\sqlsrv
|
||||
New-Item -ItemType directory -Path .\ext\pdo_sqlsrv
|
||||
Copy-Item $DRIVER_SOURCE_PATH\sqlsrv\* .\ext\sqlsrv\ -recurse
|
||||
Copy-Item $DRIVER_SOURCE_PATH\shared\ .\ext\sqlsrv\ -recurse
|
||||
Copy-Item $DRIVER_SOURCE_PATH\pdo_sqlsrv\* .\ext\pdo_sqlsrv\ -recurse
|
||||
Copy-Item $DRIVER_SOURCE_PATH\shared\ .\ext\pdo_sqlsrv\ -recurse
|
||||
|
||||
|
||||
$CONFIG_OPTIONS="--enable-cli --enable-cgi --enable-sqlsrv=shared --enable-pdo=shared --with-pdo-sqlsrv=shared --with-odbcver=0x0380 --enable-mbstring --with-openssl"
|
||||
if ($PHP_THREAD -ceq "nts") {
|
||||
$CONFIG_OPTIONS=$CONFIG_OPTIONS + " --disable-zts"
|
||||
}
|
||||
& $startingDir\compile_php.bat $ARCH $CONFIG_OPTIONS
|
||||
|
||||
|
||||
|
||||
|
||||
Copy-Item php.ini-production php.ini
|
||||
Add-Content php.ini "extension=C:\php\ext\php_sqlsrv.dll"
|
||||
Add-Content php.ini "extension=C:\php\ext\php_pdo_sqlsrv.dll"
|
||||
Add-Content php.ini "extension=C:\php\ext\php_openssl.dll"
|
||||
Move-Item php.ini C:\Windows -force
|
||||
Copy-Item C:\php-sdk\phpdev\vc14\$ARCH\deps\bin\ssleay32.dll C:\Windows -force
|
||||
Copy-Item C:\php-sdk\phpdev\vc14\$ARCH\deps\bin\libeay32.dll C:\Windows -force
|
||||
Add-Content $phpDir\php.ini "extension=$phpDir\ext\php_sqlsrv.dll"
|
||||
Add-Content $phpDir\php.ini "extension=$phpDir\ext\php_pdo_sqlsrv.dll"
|
||||
|
||||
Move-Item $phpDir\php.ini C:\Windows -force
|
||||
Copy-Item $phpDir\ssleay32.dll C:\Windows -force
|
||||
Copy-Item $phpDir\libeay32.dll C:\Windows -force
|
||||
cd $startingDir
|
||||
[Environment]::SetEnvironmentVariable("Path", $env:Path + ";C:\php\", [System.EnvironmentVariableTarget]::Machine)
|
||||
$env:Path += ";C:\php\"
|
||||
[Environment]::SetEnvironmentVariable("Path", $env:Path + ";" + $phpDir + ";" + $gitDir, [System.EnvironmentVariableTarget]::Machine)
|
||||
$env:Path = $env:Path + ";" + $phpDir + ";" + $gitDir
|
||||
RefreshEnv
|
||||
|
||||
# setup composer
|
||||
wget https://getcomposer.org/installer -O composer-setup.php
|
||||
php composer-setup.php
|
||||
php composer.phar install
|
||||
Remove-Item temp -Recurse -Force -ErrorAction Ignore
|
||||
Write-Host "Setup completed!"
|
||||
Write-Host "Setup completed!"
|
||||
|
|
25
test/functional/pdo_sqlsrv/AE_Ksp.inc
Normal file
25
test/functional/pdo_sqlsrv/AE_Ksp.inc
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?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';
|
||||
|
||||
?>
|
|
@ -40,4 +40,4 @@ $marsMode = true;
|
|||
$dsnMode = true;
|
||||
$traceEnabled = false;
|
||||
|
||||
?>
|
||||
?>
|
61
test/functional/pdo_sqlsrv/pdo_278_lastinsertid_seq.phpt
Normal file
61
test/functional/pdo_sqlsrv/pdo_278_lastinsertid_seq.phpt
Normal file
|
@ -0,0 +1,61 @@
|
|||
--TEST--
|
||||
Provide name in lastInsertId to retrieve the last sequence number
|
||||
--SKIPIF--
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon.inc");
|
||||
require_once("MsSetup.inc");
|
||||
|
||||
try{
|
||||
$database = "tempdb";
|
||||
$conn = new PDO("sqlsrv:Server=$server;Database=$databaseName", $uid, $pwd);
|
||||
|
||||
// sequence is only supported in SQL server 2012 and up (or version 11 and up)
|
||||
// Output Done once the server version is found to be < 11
|
||||
$version_arr = explode(".", $conn->getAttribute(PDO::ATTR_SERVER_VERSION));
|
||||
if ($version_arr[0] < 11) {
|
||||
echo "Done\n";
|
||||
}
|
||||
else {
|
||||
$tableName1 = GetTempTableName('tab1', false);
|
||||
$tableName2 = GetTempTableName('tab2', false);
|
||||
$sequenceName = 'sequence1';
|
||||
|
||||
$stmt = $conn->query("IF OBJECT_ID('$sequenceName', 'SO') IS NOT NULL DROP SEQUENCE $sequenceName");
|
||||
$sql = "CREATE TABLE $tableName1 (seqnum INTEGER NOT NULL PRIMARY KEY, SomeNumber INT)";
|
||||
$stmt = $conn->query($sql);
|
||||
$sql = "CREATE TABLE $tableName2 (ID INT IDENTITY(1,2), SomeValue char(10))";
|
||||
$stmt = $conn->query($sql);
|
||||
|
||||
$sql = "CREATE SEQUENCE $sequenceName AS INTEGER START WITH 1 INCREMENT BY 1 MINVALUE 1 MAXVALUE 100 CYCLE";
|
||||
$stmt = $conn->query($sql);
|
||||
|
||||
$ret = $conn->exec("INSERT INTO $tableName1 VALUES( NEXT VALUE FOR $sequenceName, 20 )");
|
||||
$ret = $conn->exec("INSERT INTO $tableName1 VALUES( NEXT VALUE FOR $sequenceName, 40 )");
|
||||
$ret = $conn->exec("INSERT INTO $tableName1 VALUES( NEXT VALUE FOR $sequenceName, 60 )");
|
||||
$ret = $conn->exec("INSERT INTO $tableName2 VALUES( '20' )");
|
||||
// return the last sequence number is sequence name is provided
|
||||
$lastSeq = $conn->lastInsertId($sequenceName);
|
||||
// defaults to $tableName2 -- because it returns the last inserted id value
|
||||
$lastRow = $conn->lastInsertId();
|
||||
|
||||
if ($lastSeq == 3 && $lastRow == 1) {
|
||||
echo "Done\n";
|
||||
}
|
||||
else {
|
||||
echo "sequence value or identity does not match as expected\n";
|
||||
}
|
||||
$stmt = $conn->query("DROP TABLE $tableName1");
|
||||
$stmt = $conn->query("DROP TABLE $tableName2");
|
||||
$stmt = $conn->query("DROP SEQUENCE $sequenceName");
|
||||
$stmt = null;
|
||||
}
|
||||
$conn = null;
|
||||
}
|
||||
catch (Exception $e){
|
||||
echo "Exception $e\n";
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Done
|
64
test/functional/pdo_sqlsrv/pdo_278_lastinsertid_seq_2.phpt
Normal file
64
test/functional/pdo_sqlsrv/pdo_278_lastinsertid_seq_2.phpt
Normal file
|
@ -0,0 +1,64 @@
|
|||
--TEST--
|
||||
LastInsertId returns the last sequences operating on the same table
|
||||
--SKIPIF--
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon.inc");
|
||||
require_once("MsSetup.inc");
|
||||
|
||||
try{
|
||||
$database = "tempdb";
|
||||
$conn = new PDO("sqlsrv:Server=$server;Database=$databaseName", $uid, $pwd);
|
||||
|
||||
// sequence is only supported in SQL server 2012 and up (or version 11 and up)
|
||||
// Output Done once the server version is found to be < 11
|
||||
$version_arr = explode(".", $conn->getAttribute(PDO::ATTR_SERVER_VERSION));
|
||||
if ($version_arr[0] < 11) {
|
||||
echo "Done\n";
|
||||
}
|
||||
else {
|
||||
$tableName = GetTempTableName('tab', false);
|
||||
$sequence1 = 'sequence1';
|
||||
$sequence2 = 'sequenceNeg1';
|
||||
$stmt = $conn->query("IF OBJECT_ID('$sequence1', 'SO') IS NOT NULL DROP SEQUENCE $sequence1");
|
||||
$stmt = $conn->query("IF OBJECT_ID('$sequence2', 'SO') IS NOT NULL DROP SEQUENCE $sequence2");
|
||||
$sql = "CREATE TABLE $tableName (ID INT IDENTITY(1,1), SeqNumInc INTEGER NOT NULL PRIMARY KEY, SomeNumber INT)";
|
||||
$stmt = $conn->query($sql);
|
||||
$sql = "CREATE SEQUENCE $sequence1 AS INTEGER START WITH 1 INCREMENT BY 1 MINVALUE 1 MAXVALUE 100";
|
||||
$stmt = $conn->query($sql);
|
||||
|
||||
$sql = "CREATE SEQUENCE $sequence2 AS INTEGER START WITH 200 INCREMENT BY -1 MINVALUE 101 MAXVALUE 200";
|
||||
$stmt = $conn->query($sql);
|
||||
$ret = $conn->exec("INSERT INTO $tableName VALUES( NEXT VALUE FOR $sequence1, 20 )");
|
||||
$ret = $conn->exec("INSERT INTO $tableName VALUES( NEXT VALUE FOR $sequence2, 180 )");
|
||||
$ret = $conn->exec("INSERT INTO $tableName VALUES( NEXT VALUE FOR $sequence1, 40 )");
|
||||
$ret = $conn->exec("INSERT INTO $tableName VALUES( NEXT VALUE FOR $sequence2, 160 )");
|
||||
$ret = $conn->exec("INSERT INTO $tableName VALUES( NEXT VALUE FOR $sequence1, 60 )");
|
||||
$ret = $conn->exec("INSERT INTO $tableName VALUES( NEXT VALUE FOR $sequence2, 140 )");
|
||||
// return the last sequence number of 'sequence1'
|
||||
$lastSeq1 = $conn->lastInsertId($sequence1);
|
||||
|
||||
// return the last sequence number of 'sequenceNeg1'
|
||||
$lastSeq2 = $conn->lastInsertId($sequence2);
|
||||
|
||||
// providing a table name in lastInsertId should return an empty string
|
||||
$lastSeq3 = $conn->lastInsertId($tableName);
|
||||
|
||||
if ($lastSeq1 == 3 && $lastSeq2 == 198 && $lastSeq3 == "") {
|
||||
echo "Done\n";
|
||||
}
|
||||
|
||||
$stmt = $conn->query("DROP TABLE $tableName");
|
||||
$stmt = $conn->query("DROP SEQUENCE $sequence1");
|
||||
$stmt = $conn->query("DROP SEQUENCE $sequence2");
|
||||
$stmt = null;
|
||||
}
|
||||
$conn = null;
|
||||
}
|
||||
catch (Exception $e){
|
||||
echo "Exception $e\n";
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Done
|
54
test/functional/pdo_sqlsrv/pdo_connect_encrypted_ksp.phpt
Normal file
54
test/functional/pdo_sqlsrv/pdo_connect_encrypted_ksp.phpt
Normal file
|
@ -0,0 +1,54 @@
|
|||
--TEST--
|
||||
Fetch data from a prepopulated test table given a custom keystore provider
|
||||
--SKIPIF--
|
||||
<?php require('skipif_server_old.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require( 'MsSetup.inc' );
|
||||
require( 'AE_Ksp.inc' );
|
||||
|
||||
$ksp_path = getKSPpath();
|
||||
|
||||
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
|
||||
$connectionInfo .= "CEKeystoreProvider = $ksp_path; ";
|
||||
$connectionInfo .= "CEKeystoreName = $ksp_name; ";
|
||||
$connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key; ";
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
$tsql = "SELECT * FROM CustomKSPTestTable";
|
||||
$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";
|
||||
}
|
||||
|
||||
$stmt = null;
|
||||
$conn = null;
|
||||
|
||||
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
|
|
@ -0,0 +1,58 @@
|
|||
--TEST--
|
||||
Fetch encrypted data from a prepopulated test table given a custom keystore provider
|
||||
--SKIPIF--
|
||||
<?php require('skipif_server_old.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require( 'MsSetup.inc' );
|
||||
require( 'AE_Ksp.inc' );
|
||||
|
||||
$ksp_path = getKSPpath();
|
||||
|
||||
$connectionInfo = "Database = $databaseName; ";
|
||||
$connectionInfo .= "CEKeystoreProvider = $ksp_path; ";
|
||||
$connectionInfo .= "CEKeystoreName = $ksp_name; ";
|
||||
$connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key; ";
|
||||
|
||||
try
|
||||
{
|
||||
$conn = new PDO( "sqlsrv:server = $server ; $connectionInfo", $uid, $pwd );
|
||||
echo "Connected successfully with ColumnEncryption disabled and KSP specified.\n";
|
||||
}
|
||||
catch( PDOException $e )
|
||||
{
|
||||
echo "Failed to connect.\n";
|
||||
print_r( $e->getMessage() );
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
$tsql = "SELECT * FROM CustomKSPTestTable";
|
||||
$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" ;
|
||||
}
|
||||
|
||||
$stmt = null;
|
||||
$conn = null;
|
||||
|
||||
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
|
100
test/functional/pdo_sqlsrv/pdo_connect_encrypted_ksp_errors.phpt
Normal file
100
test/functional/pdo_sqlsrv/pdo_connect_encrypted_ksp_errors.phpt
Normal file
|
@ -0,0 +1,100 @@
|
|||
--TEST--
|
||||
Connect using a custom keystore provider with some required inputs missing
|
||||
--SKIPIF--
|
||||
<?php require('skipif_server_old.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
require( 'MsSetup.inc' );
|
||||
require( 'AE_Ksp.inc' );
|
||||
|
||||
function connect( $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();
|
||||
|
||||
echo("Connecting... with column encryption\n");
|
||||
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
|
||||
connect( $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; ";
|
||||
connect( $connectionInfo );
|
||||
|
||||
echo("\nConnecting... with an empty path\n");
|
||||
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
|
||||
$connectionInfo .= "CEKeystoreName = $ksp_name; ";
|
||||
$connectionInfo .= "CEKeystoreProvider = ; ";
|
||||
$connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key; ";
|
||||
connect( $connectionInfo );
|
||||
|
||||
echo("\nConnecting... without a path\n");
|
||||
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
|
||||
$connectionInfo .= "CEKeystoreName = $ksp_name; ";
|
||||
$connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key;";
|
||||
connect( $connectionInfo );
|
||||
|
||||
echo("\nConnecting... without a name\n");
|
||||
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
|
||||
$connectionInfo .= "CEKeystoreProvider = $ksp_path; ";
|
||||
$connectionInfo .= "CEKeystoreEncryptKey = $encrypt_key; ";
|
||||
connect( $connectionInfo );
|
||||
|
||||
echo("\nConnecting... without a key\n");
|
||||
$connectionInfo = "Database = $databaseName; ColumnEncryption = Enabled; ";
|
||||
$connectionInfo .= "CEKeystoreProvider = $ksp_path; ";
|
||||
$connectionInfo .= "CEKeystoreName = $ksp_name; ";
|
||||
connect( $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; ";
|
||||
connect( $connectionInfo );
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECT--
|
||||
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 13 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
|
31
test/functional/pdo_sqlsrv/skipif_server_old.inc
Normal file
31
test/functional/pdo_sqlsrv/skipif_server_old.inc
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
if (!extension_loaded("pdo") || !extension_loaded('pdo_sqlsrv'))
|
||||
die("PDO driver cannot be loaded; skipping test.\n");
|
||||
|
||||
require_once( "MsSetup.inc" );
|
||||
$conn = new PDO("sqlsrv:server = $server;", $uid, $pwd );
|
||||
if( ! $conn )
|
||||
{
|
||||
echo ( "Error: could not connect during SKIPIF!" );
|
||||
}
|
||||
else
|
||||
{
|
||||
$attr = $conn->getAttribute(constant('PDO::ATTR_SERVER_VERSION'));
|
||||
$version = substr($attr, 0, 2);
|
||||
if ($version < 13)
|
||||
{
|
||||
// older than SQL Server 2016
|
||||
die( "skip - feature not supported in this version of SQL Server." );
|
||||
}
|
||||
|
||||
// check ODBC driver version
|
||||
$attr = $conn->getAttribute(constant('PDO::ATTR_CLIENT_VERSION'));
|
||||
$version = substr($attr['DriverVer'], 0, 2);
|
||||
if ($version < 13)
|
||||
{
|
||||
// older than ODBC 13
|
||||
die( "skip - feature not supported in this version of ODBC driver." );
|
||||
}
|
||||
}
|
||||
?>
|
122
test/functional/setup/build_ksp.py
Normal file
122
test/functional/setup/build_ksp.py
Normal file
|
@ -0,0 +1,122 @@
|
|||
#!/usr/bin/python3
|
||||
#########################################################################################
|
||||
#
|
||||
# Description: This script builds a custom keystore provider and compiles the app that
|
||||
# uses this KSP. Their names can be passed as arguments, but the outputs
|
||||
# are always
|
||||
# - myKSP.dll (myKSPx64.dll) / myKSP.so
|
||||
# - ksp_app.exe / ksp_app
|
||||
#
|
||||
# Requirement:
|
||||
# python 3.x
|
||||
# myKSP.c (or any equivalent)
|
||||
# ksp_app.c (or any equivalent)
|
||||
# msodbcsql.h (odbc header file)
|
||||
#
|
||||
# Execution: Run with command line with optional options
|
||||
# py build_ksp.py --KSP myKSP --APP ksp_app
|
||||
#
|
||||
#############################################################################################
|
||||
|
||||
import sys
|
||||
import os
|
||||
import platform
|
||||
import argparse
|
||||
|
||||
# This creates a batch *filename*, which compiles a C program according to
|
||||
# *command* and *arch* (either x86 or x64)
|
||||
def create_batch_file(arch, filename, command):
|
||||
root_dir = 'C:' + os.sep
|
||||
vcvarsall = os.path.join(root_dir, "Program Files (x86)", "Microsoft Visual Studio 14.0", "VC", "vcvarsall.bat")
|
||||
|
||||
try:
|
||||
file = open(filename, 'w')
|
||||
file.write('@ECHO OFF' + os.linesep)
|
||||
if arch == 'x64':
|
||||
file.write('@CALL "' + vcvarsall + '" amd64' + os.linesep)
|
||||
else:
|
||||
file.write('@CALL "' + vcvarsall + '" x86' + os.linesep)
|
||||
|
||||
# compile the code
|
||||
file.write('@CALL ' + command + os.linesep)
|
||||
file.close()
|
||||
except:
|
||||
print('Cannot create ', filename)
|
||||
|
||||
# This invokes the newly created batch file to compile the code,
|
||||
# according to *arch* (either x86 or x64). The batch file will be
|
||||
# removed afterwards
|
||||
def compile_KSP_windows(arch, ksp_src):
|
||||
output = 'myKSP'
|
||||
if arch == 'x64':
|
||||
output = output + arch + '.dll'
|
||||
else:
|
||||
output = output + '.dll'
|
||||
|
||||
command = 'cl {0} /LD /MD /link /out:'.format(ksp_src) + output
|
||||
batchfile = 'build_KSP.bat'
|
||||
create_batch_file(arch, batchfile, command)
|
||||
os.system(batchfile)
|
||||
os.remove(batchfile)
|
||||
|
||||
# This compiles myKSP.c
|
||||
#
|
||||
# In Windows, this will create batch files to compile two dll(s).
|
||||
# Otherwise, this will compile the code and generate a .so file.
|
||||
#
|
||||
# Output: A custom keystore provider created
|
||||
def compile_KSP(ksp_src):
|
||||
print('Compiling ', ksp_src)
|
||||
if platform.system() == 'Windows':
|
||||
compile_KSP_windows('x64', ksp_src)
|
||||
compile_KSP_windows('x86', ksp_src)
|
||||
else:
|
||||
os.system('gcc -fshort-wchar -fPIC -o myKSP.so -shared {0}'.format(ksp_src))
|
||||
|
||||
# This compiles ksp app, which assumes the existence of the .dll or the .so file.
|
||||
#
|
||||
# In Windows, a batch file is created in order to compile the code.
|
||||
def configure_KSP(app_src):
|
||||
print('Compiling ', app_src)
|
||||
if platform.system() == 'Windows':
|
||||
command = 'cl /MD {0} /link odbc32.lib /out:ksp_app.exe'.format(app_src)
|
||||
batchfile = 'build_app.bat'
|
||||
create_batch_file('x86', batchfile, command)
|
||||
os.system(batchfile)
|
||||
os.remove(batchfile)
|
||||
else:
|
||||
os.system('gcc -o ksp_app -fshort-wchar {0} -lodbc -ldl'.format(app_src))
|
||||
|
||||
################################### Main Function ###################################
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-ksp', '--KSPSRC', default='myKSP.c', help='The source file of KSP (keystore provider)')
|
||||
parser.add_argument('-app', '--APPSRC', default='ksp_app.c', help='The source file for the app that uses the KSP')
|
||||
args = parser.parse_args()
|
||||
|
||||
ksp_src = args.KSPSRC
|
||||
app_src = args.APPSRC
|
||||
header = 'msodbcsql.h'
|
||||
|
||||
cwd = os.getcwd()
|
||||
|
||||
# make sure all required source and header files are present
|
||||
work_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
os.chdir(work_dir)
|
||||
|
||||
if not os.path.exists(os.path.join(work_dir, header)):
|
||||
print('Error: {0} not found!'.format(header))
|
||||
exit(1)
|
||||
if not os.path.exists(os.path.join(work_dir, ksp_src)):
|
||||
print('Error: {0}.c not found!'.format(ksp_src))
|
||||
exit(1)
|
||||
if not os.path.exists(os.path.join(work_dir, app_src)):
|
||||
print('Error: {0}.c not found!'.format(app_src))
|
||||
exit(1)
|
||||
|
||||
compile_KSP(ksp_src)
|
||||
configure_KSP(app_src)
|
||||
|
||||
os.chdir(cwd)
|
||||
|
||||
|
305
test/functional/setup/ksp_app.c
Normal file
305
test/functional/setup/ksp_app.c
Normal file
|
@ -0,0 +1,305 @@
|
|||
/******************************************************************************
|
||||
Example application for demonstration of custom keystore provider usage
|
||||
|
||||
Windows: compile with cl /MD ksp_app.c /link odbc32.lib /out:ksp_app.exe
|
||||
Linux/mac: compile with gcc -o ksp_app -fshort-wchar ksp_app.c -lodbc -ldl
|
||||
|
||||
usage: kspapp connstr
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
#define KSPNAME L"MyCustomKSPName"
|
||||
#define PROV_ENCRYPT_KEY "LPKCWVD07N3RG98J0MBLG4H2" /* this can be any character string */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#define __stdcall
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
#include <sql.h>
|
||||
#include <sqlext.h>
|
||||
#include "msodbcsql.h"
|
||||
|
||||
enum job {
|
||||
set_up = 0,
|
||||
clean_up = 1
|
||||
};
|
||||
|
||||
/* Convenience functions */
|
||||
|
||||
int checkRC(SQLRETURN rc, char *msg, int ret, SQLHANDLE h, SQLSMALLINT ht) {
|
||||
if (rc == SQL_ERROR) {
|
||||
fprintf(stderr, "Error occurred upon %s\n", msg);
|
||||
if (h) {
|
||||
SQLSMALLINT i = 0;
|
||||
SQLSMALLINT outlen = 0;
|
||||
char errmsg[1024];
|
||||
while ((rc = SQLGetDiagField(
|
||||
ht, h, ++i, SQL_DIAG_MESSAGE_TEXT, errmsg, sizeof(errmsg), &outlen)) == SQL_SUCCESS
|
||||
|| rc == SQL_SUCCESS_WITH_INFO) {
|
||||
fprintf(stderr, "Err#%d: %s\n", i, errmsg);
|
||||
}
|
||||
}
|
||||
if (ret)
|
||||
exit(ret);
|
||||
return 0;
|
||||
}
|
||||
else if (rc == SQL_SUCCESS_WITH_INFO && h) {
|
||||
SQLSMALLINT i = 0;
|
||||
SQLSMALLINT outlen = 0;
|
||||
char errmsg[1024];
|
||||
printf("Success with info for %s:\n", msg);
|
||||
while ((rc = SQLGetDiagField(
|
||||
ht, h, ++i, SQL_DIAG_MESSAGE_TEXT, errmsg, sizeof(errmsg), &outlen)) == SQL_SUCCESS
|
||||
|| rc == SQL_SUCCESS_WITH_INFO) {
|
||||
fprintf(stderr, "Msg#%d: %s\n", i, errmsg);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void postKspError(CEKEYSTORECONTEXT *ctx, const wchar_t *msg, ...) {
|
||||
if (msg > (wchar_t*)65535)
|
||||
wprintf(L"Provider emitted message: %s\n", msg);
|
||||
else
|
||||
wprintf(L"Provider emitted message ID %d\n", msg);
|
||||
}
|
||||
|
||||
int setKSPLibrary(SQLHSTMT stmt) {
|
||||
unsigned char CEK[32];
|
||||
unsigned char *ECEK;
|
||||
unsigned short ECEKlen;
|
||||
unsigned char foundProv = 0;
|
||||
int i;
|
||||
#ifdef _WIN32
|
||||
HMODULE hProvLib;
|
||||
#else
|
||||
void *hProvLib;
|
||||
#endif
|
||||
CEKEYSTORECONTEXT ctx = {0};
|
||||
CEKEYSTOREPROVIDER **ppKsp, *pKsp;
|
||||
int(__stdcall *pEncryptCEK)(CEKEYSTORECONTEXT *, errFunc *, unsigned char *, unsigned short, unsigned char **, unsigned short *);
|
||||
|
||||
/* Load the provider library */
|
||||
#ifdef _WIN32
|
||||
if (!(hProvLib = LoadLibrary("myKSP.dll"))) {
|
||||
#else
|
||||
if (!(hProvLib = dlopen("./myKSP.so", RTLD_NOW))) {
|
||||
#endif
|
||||
fprintf(stderr, "Error loading KSP library\n");
|
||||
return 2;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
if (!(ppKsp = (CEKEYSTOREPROVIDER**)GetProcAddress(hProvLib, "CEKeystoreProvider"))) {
|
||||
#else
|
||||
if (!(ppKsp = (CEKEYSTOREPROVIDER**)dlsym(hProvLib, "CEKeystoreProvider"))) {
|
||||
#endif
|
||||
fprintf(stderr, "The export CEKeystoreProvider was not found in the KSP library\n");
|
||||
return 3;
|
||||
}
|
||||
while (pKsp = *ppKsp++) {
|
||||
if (!memcmp(KSPNAME, pKsp->Name, sizeof(KSPNAME))) {
|
||||
foundProv = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (! foundProv) {
|
||||
fprintf(stderr, "Could not find provider in the library\n");
|
||||
return 4;
|
||||
}
|
||||
|
||||
if (pKsp->Init && !pKsp->Init(&ctx, postKspError)) {
|
||||
fprintf(stderr, "Could not initialize provider\n");
|
||||
return 5;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
if (!(pEncryptCEK = (LPVOID)GetProcAddress(hProvLib, "KeystoreEncrypt"))) {
|
||||
#else
|
||||
if (!(pEncryptCEK = dlsym(hProvLib, "KeystoreEncrypt"))) {
|
||||
#endif
|
||||
fprintf(stderr, "The export KeystoreEncrypt was not found in the KSP library\n");
|
||||
return 6;
|
||||
}
|
||||
if (!pKsp->Write) {
|
||||
fprintf(stderr, "Provider does not support configuration\n");
|
||||
return 7;
|
||||
}
|
||||
|
||||
/* Configure the provider with the key */
|
||||
if (!pKsp->Write(&ctx, postKspError, PROV_ENCRYPT_KEY, strlen(PROV_ENCRYPT_KEY))) {
|
||||
fprintf(stderr, "Error writing to KSP\n");
|
||||
return 8;
|
||||
}
|
||||
|
||||
/* Generate a CEK and encrypt it with the provider */
|
||||
srand(time(0) ^ getpid());
|
||||
for (i = 0; i < sizeof(CEK); i++)
|
||||
CEK[i] = rand();
|
||||
|
||||
if (!pEncryptCEK(&ctx, postKspError, CEK, sizeof(CEK), &ECEK, &ECEKlen)) {
|
||||
fprintf(stderr, "Error encrypting CEK\n");
|
||||
return 9;
|
||||
}
|
||||
|
||||
/* Create a CMK definition on the server */
|
||||
{
|
||||
static char cmkSql[] = "CREATE COLUMN MASTER KEY CustomCMK WITH ("
|
||||
"KEY_STORE_PROVIDER_NAME = 'MyCustomKSPName',"
|
||||
"KEY_PATH = 'TheOneAndOnlyKey')";
|
||||
printf("Create CMK: %s\n", cmkSql);
|
||||
SQLExecDirect(stmt, cmkSql, SQL_NTS);
|
||||
}
|
||||
|
||||
/* Create a CEK definition on the server */
|
||||
{
|
||||
const char cekSqlBefore[] = "CREATE COLUMN ENCRYPTION KEY CustomCEK WITH VALUES ("
|
||||
"COLUMN_MASTER_KEY = CustomCMK,"
|
||||
"ALGORITHM = 'none',"
|
||||
"ENCRYPTED_VALUE = 0x";
|
||||
char *cekSql = malloc(sizeof(cekSqlBefore) + 2 * ECEKlen + 2); /* 1 for ')', 1 for null terminator */
|
||||
strcpy(cekSql, cekSqlBefore);
|
||||
for (i = 0; i < ECEKlen; i++)
|
||||
sprintf(cekSql + sizeof(cekSqlBefore) - 1 + 2 * i, "%02x", ECEK[i]);
|
||||
strcat(cekSql, ")");
|
||||
printf("Create CEK: %s\n", cekSql);
|
||||
SQLExecDirect(stmt, cekSql, SQL_NTS);
|
||||
free(cekSql);
|
||||
#ifdef _WIN32
|
||||
LocalFree(ECEK);
|
||||
#else
|
||||
free(ECEK);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
FreeLibrary(hProvLib);
|
||||
#else
|
||||
dlclose(hProvLib);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void populateTestTable(SQLHDBC dbc, SQLHSTMT stmt)
|
||||
{
|
||||
SQLRETURN rc;
|
||||
int i, j;
|
||||
|
||||
/* Create a table with encrypted columns */
|
||||
{
|
||||
static char *tableSql = "CREATE TABLE CustomKSPTestTable ("
|
||||
"c1 int,"
|
||||
"c2 varchar(255) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = CustomCEK, ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256'),"
|
||||
"c3 char(5) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = CustomCEK, ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256'),"
|
||||
"c4 date ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = CustomCEK, ENCRYPTION_TYPE = Randomized, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256'))";
|
||||
printf("Create table: %s\n", tableSql);
|
||||
SQLExecDirect(stmt, tableSql, SQL_NTS);
|
||||
}
|
||||
|
||||
/* Load provider into the ODBC Driver and configure it */
|
||||
{
|
||||
unsigned char ksd[sizeof(CEKEYSTOREDATA) + sizeof(PROV_ENCRYPT_KEY) - 1];
|
||||
CEKEYSTOREDATA *pKsd = (CEKEYSTOREDATA*)ksd;
|
||||
pKsd->name = L"MyCustomKSPName";
|
||||
pKsd->dataSize = sizeof(PROV_ENCRYPT_KEY) - 1;
|
||||
memcpy(pKsd->data, PROV_ENCRYPT_KEY, sizeof(PROV_ENCRYPT_KEY) - 1);
|
||||
#ifdef _WIN32
|
||||
rc = SQLSetConnectAttr(dbc, SQL_COPT_SS_CEKEYSTOREPROVIDER, "myKSP.dll", SQL_NTS);
|
||||
#else
|
||||
rc = SQLSetConnectAttr(dbc, SQL_COPT_SS_CEKEYSTOREPROVIDER, "./myKSP.so", SQL_NTS);
|
||||
#endif
|
||||
checkRC(rc, "Loading KSP into ODBC Driver", 7, dbc, SQL_HANDLE_DBC);
|
||||
rc = SQLSetConnectAttr(dbc, SQL_COPT_SS_CEKEYSTOREDATA, (SQLPOINTER)pKsd, SQL_IS_POINTER);
|
||||
checkRC(rc, "Configuring the KSP", 7, dbc, SQL_HANDLE_DBC);
|
||||
}
|
||||
|
||||
/* Insert some data */
|
||||
{
|
||||
int c1;
|
||||
char c2[256];
|
||||
char c3[6];
|
||||
SQL_DATE_STRUCT date;
|
||||
SQLLEN cbdate;
|
||||
rc = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &c1, 0, 0);
|
||||
checkRC(rc, "Binding parameters for insert", 9, stmt, SQL_HANDLE_STMT);
|
||||
rc = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 255, 0, c2, 255, 0);
|
||||
checkRC(rc, "Binding parameters for insert", 9, stmt, SQL_HANDLE_STMT);
|
||||
rc = SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 5, 0, c3, 5, 0);
|
||||
checkRC(rc, "Binding parameters for insert", 9, stmt, SQL_HANDLE_STMT);
|
||||
checkRC(rc, "Binding parameters for insert", 9, stmt, SQL_HANDLE_STMT);
|
||||
cbdate = sizeof(SQL_DATE_STRUCT);
|
||||
rc = SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_TYPE_DATE, SQL_TYPE_DATE, 10, 0, &date, 0, &cbdate);
|
||||
checkRC(rc, "Binding parameters for insert", 9, stmt, SQL_HANDLE_STMT);
|
||||
|
||||
date.year = 2017;
|
||||
date.month = 8;
|
||||
for (i = 0; i < 10; i++) {
|
||||
date.day = i + 10;
|
||||
|
||||
c1 = i * 10 + i + 1;
|
||||
sprintf(c2, "Sample data %d for column 2", i);
|
||||
for (j = 0; j < 3; j++) {
|
||||
c3[j] = 'a' + i + j;
|
||||
}
|
||||
c3[3] = '\0';
|
||||
rc = SQLExecDirect(stmt, "INSERT INTO CustomKSPTestTable (c1, c2, c3, c4) values (?, ?, ?, ?)", SQL_NTS);
|
||||
checkRC(rc, "Inserting rows query", 10, stmt, SQL_HANDLE_STMT);
|
||||
}
|
||||
printf("(Encrypted) data has been inserted into CustomKSPTestTable. You may inspect the data now.\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char sqlbuf[1024];
|
||||
SQLHENV env;
|
||||
SQLHDBC dbc;
|
||||
SQLHSTMT stmt;
|
||||
SQLRETURN rc;
|
||||
int i;
|
||||
char connStr[1024];
|
||||
enum job task;
|
||||
|
||||
if (argc < 6) {
|
||||
fprintf(stderr, "usage: kspapp job server database uid pwd\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
task = atoi(argv[1]);
|
||||
|
||||
sprintf(connStr, "DRIVER={ODBC Driver 13 for SQL Server};SERVER=%s;ColumnEncryption=Enabled;DATABASE=%s;UID=%s;PWD=%s", argv[2], argv[3], argv[4], argv[5]);
|
||||
|
||||
/* Connect to Server */
|
||||
rc = SQLAllocHandle(SQL_HANDLE_ENV, NULL, &env);
|
||||
checkRC(rc, "allocating environment handle", 2, 0, 0);
|
||||
rc = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0);
|
||||
checkRC(rc, "setting ODBC version to 3.0", 3, env, SQL_HANDLE_ENV);
|
||||
rc = SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
|
||||
checkRC(rc, "allocating connection handle", 4, env, SQL_HANDLE_ENV);
|
||||
rc = SQLDriverConnect(dbc, 0, connStr, strlen(connStr), NULL, 0, NULL, SQL_DRIVER_NOPROMPT);
|
||||
checkRC(rc, "connecting to data source", 5, dbc, SQL_HANDLE_DBC);
|
||||
rc = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
|
||||
checkRC(rc, "allocating statement handle", 6, dbc, SQL_HANDLE_DBC);
|
||||
|
||||
if (task == set_up) {
|
||||
printf("Setting up KSP...\n");
|
||||
setKSPLibrary(stmt);
|
||||
populateTestTable(dbc, stmt);
|
||||
}
|
||||
else if (task == clean_up) {
|
||||
printf("Cleaning up KSP...\n");
|
||||
|
||||
SQLExecDirect(stmt, "DROP TABLE CustomKSPTestTable", SQL_NTS);
|
||||
SQLExecDirect(stmt, "DROP COLUMN ENCRYPTION KEY CustomCEK", SQL_NTS);
|
||||
SQLExecDirect(stmt, "DROP COLUMN MASTER KEY CustomCMK", SQL_NTS);
|
||||
printf("Removed table, CEK, and CMK\n");
|
||||
}
|
||||
|
||||
SQLDisconnect(dbc);
|
||||
SQLFreeHandle(SQL_HANDLE_DBC, dbc);
|
||||
SQLFreeHandle(SQL_HANDLE_ENV, env);
|
||||
return 0;
|
||||
}
|
132
test/functional/setup/myKSP.c
Normal file
132
test/functional/setup/myKSP.c
Normal file
|
@ -0,0 +1,132 @@
|
|||
/******************************************************************************
|
||||
Custom Keystore Provider Example
|
||||
|
||||
Windows: compile with cl myKSP.c /LD /MD /link /out:myKSP.dll
|
||||
Linux/mac: compile with gcc -fshort-wchar -fPIC -o myKSP.so -shared myKSP.c
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#define __stdcall
|
||||
#endif
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sqltypes.h>
|
||||
#include <sql.h>
|
||||
#include <sqlext.h>
|
||||
#include "msodbcsql.h"
|
||||
|
||||
int wcscmp_short(wchar_t *s1, wchar_t *s2) {
|
||||
while(*s1 && *s2 && *s1 == *s2)
|
||||
s1++, s2++;
|
||||
return *s1 - *s2;
|
||||
}
|
||||
|
||||
int __stdcall KeystoreInit(CEKEYSTORECONTEXT *ctx, errFunc *onError) {
|
||||
if (DEBUG)
|
||||
printf("KSP Init() function called\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static unsigned char *g_encryptKey;
|
||||
static unsigned int g_encryptKeyLen;
|
||||
|
||||
int __stdcall KeystoreWrite(CEKEYSTORECONTEXT *ctx, errFunc *onError, void *data, unsigned int len) {
|
||||
if (DEBUG)
|
||||
printf("KSP Write() function called (%d bytes)\n", len);
|
||||
if (len) {
|
||||
if (g_encryptKey)
|
||||
free(g_encryptKey);
|
||||
g_encryptKey = malloc(len);
|
||||
if (!g_encryptKey) {
|
||||
onError(ctx, L"Memory Allocation Error");
|
||||
return 0;
|
||||
}
|
||||
memcpy(g_encryptKey, data, len);
|
||||
g_encryptKeyLen = len;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Very simple "encryption" scheme - rotating XOR with the key
|
||||
int __stdcall KeystoreDecrypt(CEKEYSTORECONTEXT *ctx, errFunc *onError, const wchar_t *keyPath, const wchar_t *alg, unsigned char *ecek, unsigned short ecekLen, unsigned char **cekOut, unsigned short *cekLen) {
|
||||
unsigned int i;
|
||||
if (DEBUG)
|
||||
printf("KSP Decrypt() function called (keypath=%S alg=%S ecekLen=%u)\n", keyPath, alg, ecekLen);
|
||||
if (wcscmp_short(keyPath, L"TheOneAndOnlyKey")) {
|
||||
onError(ctx, L"Invalid key path");
|
||||
return 0;
|
||||
}
|
||||
if (wcscmp_short(alg, L"none")) {
|
||||
onError(ctx, L"Invalid algorithm");
|
||||
return 0;
|
||||
}
|
||||
if (!g_encryptKey) {
|
||||
onError(ctx, L"Keystore provider not initialized with key");
|
||||
return 0;
|
||||
}
|
||||
#ifndef _WIN32
|
||||
*cekOut = malloc(ecekLen);
|
||||
#else
|
||||
*cekOut = LocalAlloc(LMEM_FIXED, ecekLen);
|
||||
#endif
|
||||
if (!*cekOut) {
|
||||
onError(ctx, L"Memory Allocation Error");
|
||||
return 0;
|
||||
}
|
||||
*cekLen = ecekLen;
|
||||
for (i = 0; i < ecekLen; i++)
|
||||
(*cekOut)[i] = ecek[i] ^ g_encryptKey[i % g_encryptKeyLen];
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Note that in the provider interface, this function would be referenced via the CEKEYSTOREPROVIDER
|
||||
// structure. However, that does not preclude keystore providers from exporting their own functions,
|
||||
// as illustrated by this example where the encryption is performed via a separate function (with a
|
||||
// different prototype than the one in the KSP interface.)
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int KeystoreEncrypt(CEKEYSTORECONTEXT *ctx, errFunc *onError,
|
||||
unsigned char *cek, unsigned short cekLen,
|
||||
unsigned char **ecekOut, unsigned short *ecekLen) {
|
||||
unsigned int i;
|
||||
|
||||
if (DEBUG)
|
||||
printf("KSP Encrypt() function called (cekLen=%u)\n", cekLen);
|
||||
if (!g_encryptKey) {
|
||||
onError(ctx, L"Keystore provider not initialized with key");
|
||||
return 0;
|
||||
}
|
||||
*ecekOut = malloc(cekLen);
|
||||
if (!*ecekOut) {
|
||||
onError(ctx, L"Memory Allocation Error");
|
||||
return 0;
|
||||
}
|
||||
*ecekLen = cekLen;
|
||||
for (i = 0; i < cekLen; i++)
|
||||
(*ecekOut)[i] = cek[i] ^ g_encryptKey[i % g_encryptKeyLen];
|
||||
return 1;
|
||||
}
|
||||
|
||||
CEKEYSTOREPROVIDER MyCustomKSPName_desc = {
|
||||
L"MyCustomKSPName",
|
||||
KeystoreInit,
|
||||
0,
|
||||
KeystoreWrite,
|
||||
KeystoreDecrypt,
|
||||
0
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
CEKEYSTOREPROVIDER *CEKeystoreProvider[] = {
|
||||
&MyCustomKSPName_desc,
|
||||
0
|
||||
};
|
57
test/functional/setup/run_ksp.py
Normal file
57
test/functional/setup/run_ksp.py
Normal file
|
@ -0,0 +1,57 @@
|
|||
#!/usr/bin/python3
|
||||
#########################################################################################
|
||||
#
|
||||
# Description: This script assumes the existence of the ksp_app executable and will
|
||||
# invoke it to create / remove the Column Master Key, the Column Encryption key,
|
||||
# and the table [CustomKSPTestTable] in the test database.
|
||||
#
|
||||
# Requirement:
|
||||
# python 3.x
|
||||
# ksp_app executable
|
||||
#
|
||||
# Execution: Run with command line with required options
|
||||
# py run_ksp.py --SERVER=server --DBNAME=database --UID=uid --PWD=pwd
|
||||
# py run_ksp.py --SERVER=server --DBNAME=database --UID=uid --PWD=pwd --REMOVE
|
||||
#
|
||||
#############################################################################################
|
||||
|
||||
import sys
|
||||
import os
|
||||
import platform
|
||||
import argparse
|
||||
|
||||
################################### Main Function ###################################
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-server', '--SERVER', required=True, help='SQL Server')
|
||||
parser.add_argument('-dbname', '--DBNAME', required=True, help='Name of an existing database')
|
||||
parser.add_argument('-uid', '--UID', required=True, help='User name')
|
||||
parser.add_argument('-pwd', '--PWD', required=True, help='User password')
|
||||
parser.add_argument('-remove', '--REMOVE', action='store_true', help='Clean up KSP related data, false by default')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
app_name = 'ksp_app'
|
||||
cwd = os.getcwd()
|
||||
|
||||
# first check if the ksp app is present
|
||||
work_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
os.chdir(work_dir)
|
||||
|
||||
if platform.system() == 'Windows':
|
||||
path = os.path.join(work_dir, app_name + '.exe')
|
||||
executable = app_name
|
||||
else:
|
||||
path = os.path.join(work_dir, app_name)
|
||||
executable = './' + app_name
|
||||
|
||||
if not os.path.exists(path):
|
||||
print('Error: {0} not found!'.format(path))
|
||||
exit(1)
|
||||
|
||||
if args.REMOVE:
|
||||
os.system('{0} 1 {1} {2} {3} {4}'.format(executable, args.SERVER, args.DBNAME, args.UID, args.PWD))
|
||||
else:
|
||||
os.system('{0} 0 {1} {2} {3} {4}'.format(executable, args.SERVER, args.DBNAME, args.UID, args.PWD))
|
||||
|
||||
os.chdir(cwd)
|
25
test/functional/sqlsrv/AE_Ksp.inc
Normal file
25
test/functional/sqlsrv/AE_Ksp.inc
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?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';
|
||||
|
||||
?>
|
|
@ -35,8 +35,8 @@ function ConnectionTest()
|
|||
// Valid connection attempt => no errors are expected
|
||||
Trace("\nValid connection attempt (to $server) ....\n");
|
||||
$conn2 = Connect();
|
||||
$errors = sqlsrv_errors(SQLSRV_ERR_ERRORS);
|
||||
if(count($errors) != 0)
|
||||
$errors = sqlsrv_errors(SQLSRV_ERR_ERRORS);
|
||||
if (!empty($errors))
|
||||
{
|
||||
die("No errors were expected on valid connection attempts.");
|
||||
}
|
||||
|
|
40
test/functional/sqlsrv/skipif_server_old.inc
Normal file
40
test/functional/sqlsrv/skipif_server_old.inc
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
if (!extension_loaded("sqlsrv"))
|
||||
die("skip extension not loaded");
|
||||
|
||||
require_once( "MsSetup.inc" );
|
||||
$connectionInfo = array( "UID"=>$userName, "PWD"=>$userPassword );
|
||||
|
||||
$conn = sqlsrv_connect( $server, $connectionInfo );
|
||||
if( ! $conn )
|
||||
{
|
||||
echo ( "Error: could not connect during SKIPIF!" );
|
||||
}
|
||||
else
|
||||
{
|
||||
$server_info = sqlsrv_server_info( $conn );
|
||||
if( $server_info )
|
||||
{
|
||||
// check SQL Server version
|
||||
$version = substr($server_info['SQLServerVersion'], 0, 2);
|
||||
if ($version < 13)
|
||||
{
|
||||
// older than SQL Server 2016
|
||||
die( "skip - feature not supported in this version of SQL Server." );
|
||||
}
|
||||
}
|
||||
|
||||
$client_info = sqlsrv_client_info( $conn );
|
||||
if( $client_info )
|
||||
{
|
||||
// check ODBC driver version
|
||||
$version = substr($client_info['DriverVer'], 0, 2);
|
||||
if ($version < 13)
|
||||
{
|
||||
// older than ODBC 13
|
||||
die( "skip - feature not supported in this version of ODBC driver." );
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
File diff suppressed because one or more lines are too long
64
test/functional/sqlsrv/sqlsrv_connect_encrypted_ksp.phpt
Normal file
64
test/functional/sqlsrv/sqlsrv_connect_encrypted_ksp.phpt
Normal file
|
@ -0,0 +1,64 @@
|
|||
--TEST--
|
||||
Fetch data from a prepopulated test table given a custom keystore provider
|
||||
--SKIPIF--
|
||||
<?php require('skipif_server_old.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
sqlsrv_configure( 'WarningsReturnAsErrors', 1 );
|
||||
sqlsrv_configure( 'LogSeverity', SQLSRV_LOG_SEVERITY_ALL );
|
||||
|
||||
require( 'MsSetup.inc' );
|
||||
require( 'AE_Ksp.inc' );
|
||||
|
||||
$ksp_path = getKSPpath();
|
||||
|
||||
$connectionInfo = array( "Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd,
|
||||
"ColumnEncryption"=>"enabled",
|
||||
"CEKeystoreProvider"=>$ksp_path,
|
||||
"CEKeystoreName"=>$ksp_name,
|
||||
"CEKeystoreEncryptKey"=>$encrypt_key,
|
||||
'ReturnDatesAsStrings'=>true);
|
||||
|
||||
$conn = sqlsrv_connect( $server, $connectionInfo );
|
||||
if( $conn === false )
|
||||
{
|
||||
echo "Failed to connect.\n";
|
||||
print_r( sqlsrv_errors() );
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "Connected successfully with ColumnEncryption enabled.\n";
|
||||
}
|
||||
|
||||
$tsql = "SELECT * FROM $ksp_test_table";
|
||||
$stmt = sqlsrv_prepare($conn, $tsql);
|
||||
if (! sqlsrv_execute($stmt) )
|
||||
{
|
||||
echo "Failed to fetch data.\n";
|
||||
print_r( sqlsrv_errors() );
|
||||
}
|
||||
|
||||
// fetch data
|
||||
while ($row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC ))
|
||||
{
|
||||
echo "c1=" . $row[0] . "\tc2=" . $row[1] . "\tc3=" . $row[2] . "\tc4=" . $row[3] . "\n" ;
|
||||
}
|
||||
|
||||
sqlsrv_free_stmt($stmt);
|
||||
sqlsrv_close($conn);
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECT--
|
||||
Connected successfully with ColumnEncryption enabled.
|
||||
c1=1 c2=Sample data 0 for column 2 c3=abc c4=2017-08-10
|
||||
c1=12 c2=Sample data 1 for column 2 c3=bcd c4=2017-08-11
|
||||
c1=23 c2=Sample data 2 for column 2 c3=cde c4=2017-08-12
|
||||
c1=34 c2=Sample data 3 for column 2 c3=def c4=2017-08-13
|
||||
c1=45 c2=Sample data 4 for column 2 c3=efg c4=2017-08-14
|
||||
c1=56 c2=Sample data 5 for column 2 c3=fgh c4=2017-08-15
|
||||
c1=67 c2=Sample data 6 for column 2 c3=ghi c4=2017-08-16
|
||||
c1=78 c2=Sample data 7 for column 2 c3=hij c4=2017-08-17
|
||||
c1=89 c2=Sample data 8 for column 2 c3=ijk c4=2017-08-18
|
||||
c1=100 c2=Sample data 9 for column 2 c3=jkl c4=2017-08-19
|
||||
Done
|
|
@ -0,0 +1,68 @@
|
|||
--TEST--
|
||||
Fetch encrypted data from a prepopulated test table given a custom keystore provider
|
||||
--SKIPIF--
|
||||
<?php require('skipif_server_old.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
sqlsrv_configure( 'WarningsReturnAsErrors', 1 );
|
||||
sqlsrv_configure( 'LogSeverity', SQLSRV_LOG_SEVERITY_ALL );
|
||||
|
||||
require( 'MsSetup.inc' );
|
||||
require( 'AE_Ksp.inc' );
|
||||
|
||||
$ksp_path = getKSPpath();
|
||||
|
||||
$connectionInfo = array( "Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd,
|
||||
"CEKeystoreProvider"=>$ksp_path,
|
||||
"CEKeystoreName"=>$ksp_name,
|
||||
"CEKeystoreEncryptKey"=>$encrypt_key,
|
||||
'ReturnDatesAsStrings'=>true);
|
||||
|
||||
$conn = sqlsrv_connect( $server, $connectionInfo );
|
||||
if( $conn === false )
|
||||
{
|
||||
echo "Failed to connect.\n";
|
||||
print_r( sqlsrv_errors() );
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "Connected successfully with ColumnEncryption disabled.\n";
|
||||
}
|
||||
|
||||
$tsql = "SELECT * FROM $ksp_test_table";
|
||||
$stmt = sqlsrv_prepare($conn, $tsql);
|
||||
if (! sqlsrv_execute($stmt) )
|
||||
{
|
||||
echo "Failed to fetch data.\n";
|
||||
print_r( sqlsrv_errors() );
|
||||
}
|
||||
|
||||
// fetch data
|
||||
while ($row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_NUMERIC ))
|
||||
{
|
||||
// all columns should return binary data except the first column
|
||||
echo "c1=" . $row[0];
|
||||
echo "\tc2=" . bin2hex($row[1]);
|
||||
echo "\tc3=" . bin2hex($row[2]);
|
||||
echo "\tc4=" . bin2hex($row[3]);
|
||||
echo "\n" ;
|
||||
}
|
||||
|
||||
sqlsrv_free_stmt($stmt);
|
||||
sqlsrv_close($conn);
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTREGEX--
|
||||
Connected successfully with ColumnEncryption disabled.
|
||||
c1=1 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
|
||||
c1=12 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
|
||||
c1=23 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
|
||||
c1=34 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
|
||||
c1=45 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
|
||||
c1=56 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
|
||||
c1=67 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
|
||||
c1=78 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
|
||||
c1=89 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
|
||||
c1=100 c2=[a-f0-9]+ c3=[a-f0-9]+ c4=[a-f0-9]+
|
||||
Done
|
130
test/functional/sqlsrv/sqlsrv_connect_encrypted_ksp_errors.phpt
Normal file
130
test/functional/sqlsrv/sqlsrv_connect_encrypted_ksp_errors.phpt
Normal file
|
@ -0,0 +1,130 @@
|
|||
--TEST--
|
||||
Connect using a custom keystore provider with some required inputs missing
|
||||
--SKIPIF--
|
||||
<?php require('skipif_server_old.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function connect( $server, $connectionInfo )
|
||||
{
|
||||
$conn = sqlsrv_connect( $server, $connectionInfo );
|
||||
if( $conn === false )
|
||||
{
|
||||
echo "Failed to connect.\n";
|
||||
$errors = sqlsrv_errors();
|
||||
foreach ( $errors[0] as $key => $error )
|
||||
{
|
||||
if( is_string( $key ) )
|
||||
echo "[$key] => $error\n";
|
||||
}
|
||||
echo "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "Connected successfully with ColumnEncryption enabled.\n";
|
||||
}
|
||||
|
||||
return $conn;
|
||||
}
|
||||
|
||||
sqlsrv_configure( 'LogSeverity', SQLSRV_LOG_SEVERITY_ALL );
|
||||
|
||||
require( 'MsSetup.inc' );
|
||||
require( 'AE_Ksp.inc' );
|
||||
|
||||
$ksp_path = getKSPpath();
|
||||
|
||||
echo("Connecting... with column encryption\n");
|
||||
$connectionInfo = array( "Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd,
|
||||
"ColumnEncryption"=>"enabled");
|
||||
|
||||
connect( $server, $connectionInfo );
|
||||
|
||||
echo("Connecting... with an invalid input to CEKeystoreProvider\n");
|
||||
$connectionInfo = array( "Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd,
|
||||
"ColumnEncryption"=>"enabled",
|
||||
"CEKeystoreProvider"=>1);
|
||||
|
||||
connect( $server, $connectionInfo );
|
||||
|
||||
echo("Connecting... with an empty path\n");
|
||||
$connectionInfo = array( "Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd,
|
||||
"ColumnEncryption"=>"enabled",
|
||||
"CEKeystoreProvider"=>"",
|
||||
"CEKeystoreName"=>$ksp_name,
|
||||
"CEKeystoreEncryptKey"=>$encrypt_key);
|
||||
|
||||
connect( $server, $connectionInfo );
|
||||
|
||||
echo("Connecting... without a name\n");
|
||||
$connectionInfo = array( "Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd,
|
||||
"ColumnEncryption"=>"enabled",
|
||||
"CEKeystoreProvider"=>$ksp_path,
|
||||
"CEKeystoreEncryptKey"=>$encrypt_key);
|
||||
|
||||
connect( $server, $connectionInfo );
|
||||
|
||||
echo("Connecting... with an empty name\n");
|
||||
$connectionInfo = array( "Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd,
|
||||
"ColumnEncryption"=>"enabled",
|
||||
"CEKeystoreProvider"=>$ksp_path,
|
||||
"CEKeystoreName"=>"",
|
||||
"CEKeystoreEncryptKey"=>$encrypt_key);
|
||||
|
||||
connect( $server, $connectionInfo );
|
||||
|
||||
echo("Connecting... without a key\n");
|
||||
$connectionInfo = array( "Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd,
|
||||
"ColumnEncryption"=>"enabled",
|
||||
"CEKeystoreProvider"=>$ksp_path,
|
||||
"CEKeystoreName"=>$ksp_name);
|
||||
|
||||
connect( $server, $connectionInfo );
|
||||
|
||||
echo("Connecting... with all required inputs\n");
|
||||
$connectionInfo = array( "Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd,
|
||||
"ColumnEncryption"=>"enabled",
|
||||
"CEKeystoreProvider"=>$ksp_path,
|
||||
"CEKeystoreName"=>$ksp_name,
|
||||
"CEKeystoreEncryptKey"=>$encrypt_key);
|
||||
|
||||
connect( $server, $connectionInfo );
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECT--
|
||||
Connecting... with column encryption
|
||||
Connected successfully with ColumnEncryption enabled.
|
||||
Connecting... with an invalid input to CEKeystoreProvider
|
||||
Failed to connect.
|
||||
[SQLSTATE] => IMSSP
|
||||
[code] => -33
|
||||
[message] => Invalid value type for option CEKeystoreProvider was specified. String type was expected.
|
||||
|
||||
Connecting... with an empty path
|
||||
Failed to connect.
|
||||
[SQLSTATE] => IMSSP
|
||||
[code] => -104
|
||||
[message] => Invalid value for loading a custom keystore provider.
|
||||
|
||||
Connecting... without a name
|
||||
Failed to connect.
|
||||
[SQLSTATE] => IMSSP
|
||||
[code] => -101
|
||||
[message] => The name of the custom keystore provider is missing.
|
||||
|
||||
Connecting... with an empty name
|
||||
Failed to connect.
|
||||
[SQLSTATE] => IMSSP
|
||||
[code] => -104
|
||||
[message] => Invalid value for loading a custom keystore provider.
|
||||
|
||||
Connecting... without a key
|
||||
Failed to connect.
|
||||
[SQLSTATE] => IMSSP
|
||||
[code] => -103
|
||||
[message] => The encryption key for the custom keystore provider is missing.
|
||||
|
||||
Connecting... with all required inputs
|
||||
Connected successfully with ColumnEncryption enabled.
|
||||
Done
|
248
test/functional/sqlsrv/sqlsrv_encrypted_patients_ksp.phpt
Normal file
248
test/functional/sqlsrv/sqlsrv_encrypted_patients_ksp.phpt
Normal file
|
@ -0,0 +1,248 @@
|
|||
--TEST--
|
||||
Test simple insert, fetch and update with ColumnEncryption enabled and a custome keystore provider
|
||||
--SKIPIF--
|
||||
<?php require('skipif_server_old.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
function CreatePatientsTable()
|
||||
{
|
||||
global $conn;
|
||||
$tablename = 'Patients';
|
||||
|
||||
$stmt = sqlsrv_query( $conn, "IF OBJECT_ID('$tablename', 'U') IS NOT NULL DROP TABLE $tablename" );
|
||||
sqlsrv_free_stmt( $stmt );
|
||||
|
||||
$tsql = "CREATE TABLE $tablename (
|
||||
[PatientId] [int] IDENTITY(1,1) NOT NULL,
|
||||
[SSN] [char](11) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = CustomCEK, ENCRYPTION_TYPE = Deterministic, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NOT NULL,
|
||||
[FirstName] [nvarchar](50) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = CustomCEK, ENCRYPTION_TYPE = Deterministic, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NULL,
|
||||
[LastName] [nvarchar](50) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = CustomCEK, ENCRYPTION_TYPE = Deterministic, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NULL,
|
||||
[BirthDate] [date] ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = CustomCEK, ENCRYPTION_TYPE = Randomized, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NOT NULL)";
|
||||
|
||||
$stmt = sqlsrv_query( $conn, $tsql );
|
||||
if (! $stmt )
|
||||
{
|
||||
echo "Failed to create test table!\n";
|
||||
die( print_r( sqlsrv_errors(), true ));
|
||||
}
|
||||
|
||||
return $tablename;
|
||||
}
|
||||
|
||||
function InsertData($ssn, $fname, $lname, $date)
|
||||
{
|
||||
global $conn, $tablename;
|
||||
|
||||
$params = array(
|
||||
array($ssn, null, null, SQLSRV_SQLTYPE_CHAR(11)), array($fname, null, null, SQLSRV_SQLTYPE_NVARCHAR(50)), array($lname, null, null, SQLSRV_SQLTYPE_NVARCHAR(50)), array($date, null, null, SQLSRV_SQLTYPE_DATE)
|
||||
);
|
||||
|
||||
$tsql = "INSERT INTO $tablename (SSN, FirstName, LastName, BirthDate) VALUES (?, ?, ?, ?)";
|
||||
if (! $stmt = sqlsrv_prepare($conn, $tsql, $params))
|
||||
{
|
||||
echo "Failed to prepare statement.\n";
|
||||
print_r( sqlsrv_errors() );
|
||||
}
|
||||
|
||||
if (! sqlsrv_execute($stmt))
|
||||
{
|
||||
echo "Failed to insert a new record.\n";
|
||||
print_r( sqlsrv_errors() );
|
||||
}
|
||||
}
|
||||
|
||||
function SelectData()
|
||||
{
|
||||
global $conn, $tablename;
|
||||
|
||||
$stmt = sqlsrv_query($conn, "SELECT * FROM $tablename");
|
||||
|
||||
while ($obj = sqlsrv_fetch_object( $stmt ))
|
||||
{
|
||||
echo $obj->PatientId . "\n";
|
||||
echo $obj->SSN . "\n";
|
||||
echo $obj->FirstName . "\n";
|
||||
echo $obj->LastName . "\n";
|
||||
echo $obj->BirthDate . "\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
function SelectDataBuffered()
|
||||
{
|
||||
global $conn, $tablename;
|
||||
|
||||
$stmt = sqlsrv_query($conn, "SELECT * FROM $tablename", array(), array("Scrollable"=>"buffered"));
|
||||
|
||||
$row_count = sqlsrv_num_rows($stmt);
|
||||
echo "\nRow count for result set is $row_count\n";
|
||||
|
||||
echo "First record=>\t";
|
||||
$row = sqlsrv_fetch($stmt, SQLSRV_SCROLL_FIRST);
|
||||
$SSN = sqlsrv_get_field( $stmt, 1);
|
||||
echo "SSN = $SSN \n";
|
||||
|
||||
echo "Next record=>\t";
|
||||
$row = sqlsrv_fetch($stmt, SQLSRV_SCROLL_NEXT);
|
||||
$BirthDate = sqlsrv_get_field( $stmt, 4);
|
||||
echo "BirthDate = $BirthDate \n";
|
||||
|
||||
echo "Last record=>\t";
|
||||
$row = sqlsrv_fetch($stmt, SQLSRV_SCROLL_LAST);
|
||||
$LastName = sqlsrv_get_field( $stmt, 3);
|
||||
echo "LastName = $LastName \n";
|
||||
}
|
||||
|
||||
sqlsrv_configure( 'WarningsReturnAsErrors', 1 );
|
||||
sqlsrv_configure( 'LogSeverity', SQLSRV_LOG_SEVERITY_ALL );
|
||||
|
||||
require_once( 'MsSetup.inc' );
|
||||
require_once( 'AE_Ksp.inc' );
|
||||
|
||||
$ksp_path = getKSPpath();
|
||||
|
||||
$connectionInfo = array( "Database"=>$databaseName, "UID"=>$uid, "PWD"=>$pwd,
|
||||
"ReturnDatesAsStrings"=>true, "ColumnEncryption"=>'Enabled',
|
||||
"CEKeystoreProvider"=>$ksp_path,
|
||||
"CEKeystoreName"=>$ksp_name,
|
||||
"CEKeystoreEncryptKey"=>$encrypt_key);
|
||||
|
||||
$conn = sqlsrv_connect( $server, $connectionInfo );
|
||||
if( $conn === false )
|
||||
{
|
||||
echo "Failed to connect.\n";
|
||||
print_r( sqlsrv_errors() );
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "Connected successfully with ColumnEncryption enabled.\n";
|
||||
}
|
||||
|
||||
$tablename = CreatePatientsTable();
|
||||
|
||||
InsertData('748-68-0245', 'Jeannette', 'McDonald', '2002-11-28');
|
||||
InsertData('795-73-9838', 'John', 'Doe', '2001-05-29');
|
||||
InsertData('456-12-5486', 'Jonathan', 'Wong', '1999-12-20');
|
||||
InsertData('156-45-5486', 'Marianne', 'Smith', '1997-03-04');
|
||||
|
||||
SelectData();
|
||||
|
||||
///////////////////////////////////////////
|
||||
echo "Update Patient Jonathan Wong...\n";
|
||||
$params = array(array('1999-12-31', null, null, SQLSRV_SQLTYPE_DATE), array('Chang', null, null, SQLSRV_SQLTYPE_NVARCHAR(50)), array('456-12-5486', null, null, SQLSRV_SQLTYPE_CHAR(11)));
|
||||
|
||||
$tsql = "UPDATE Patients SET BirthDate = ?, LastName = ? WHERE SSN = ?";
|
||||
$stmt = sqlsrv_query($conn, $tsql, $params);
|
||||
|
||||
if (! $stmt)
|
||||
{
|
||||
echo "Failed to update record\n";
|
||||
print_r( sqlsrv_errors() );
|
||||
}
|
||||
|
||||
echo "Update his birthdate too...\n";
|
||||
$params = array(array('456-12-5486', null, null, SQLSRV_SQLTYPE_CHAR(11)));
|
||||
$tsql = "SELECT SSN, FirstName, LastName, BirthDate FROM Patients WHERE SSN = ?";
|
||||
$stmt = sqlsrv_query($conn, $tsql, $params);
|
||||
if (! $stmt)
|
||||
{
|
||||
echo "Failed to select with a WHERE clause\n";
|
||||
print_r( sqlsrv_errors() );
|
||||
}
|
||||
else
|
||||
{
|
||||
$obj = sqlsrv_fetch_object( $stmt );
|
||||
|
||||
echo "BirthDate updated for $obj->FirstName:\n";
|
||||
echo $obj->SSN . "\n";
|
||||
echo $obj->FirstName . "\n";
|
||||
echo $obj->LastName . "\n";
|
||||
echo $obj->BirthDate . "\n\n";
|
||||
}
|
||||
|
||||
///////////////////////////////////////////
|
||||
$procName = '#phpAEProc1';
|
||||
$spArgs = "@p1 INT, @p2 DATE OUTPUT";
|
||||
$spCode = "SET @p2 = ( SELECT [BirthDate] FROM Patients WHERE [PatientId] = @p1 )";
|
||||
$stmt = sqlsrv_query($conn, "CREATE PROC [$procName] ($spArgs) AS BEGIN $spCode END");
|
||||
sqlsrv_free_stmt($stmt);
|
||||
|
||||
$callResult = '1900-01-01';
|
||||
$params = array( array( 1, SQLSRV_PARAM_IN ), array( &$callResult, SQLSRV_PARAM_OUT, null, SQLSRV_SQLTYPE_DATE));
|
||||
$callArgs = "?, ?";
|
||||
$stmt = sqlsrv_query($conn, "{ CALL [$procName] ($callArgs)}", $params);
|
||||
if (! $stmt )
|
||||
{
|
||||
print_r( sqlsrv_errors() );
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "BirthDate for the first record is: $callResult\n";
|
||||
}
|
||||
|
||||
///////////////////////////////////////////
|
||||
$procName = '#phpAEProc2';
|
||||
$spArgs = "@p1 INT, @p2 CHAR(11) OUTPUT";
|
||||
$spCode = "SET @p2 = ( SELECT [SSN] FROM Patients WHERE [PatientId] = @p1 )";
|
||||
$stmt = sqlsrv_query($conn, "CREATE PROC [$procName] ($spArgs) AS BEGIN $spCode END");
|
||||
sqlsrv_free_stmt($stmt);
|
||||
|
||||
$callResult = '000-00-0000';
|
||||
$params = array( array( 1, SQLSRV_PARAM_IN ), array( &$callResult, SQLSRV_PARAM_OUT, null, SQLSRV_SQLTYPE_CHAR(11)));
|
||||
$callArgs = "?, ?";
|
||||
$stmt = sqlsrv_query($conn, "{ CALL [$procName] ($callArgs)}", $params);
|
||||
if (! $stmt )
|
||||
{
|
||||
print_r( sqlsrv_errors() );
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "SSN for the first record is: $callResult\n";
|
||||
}
|
||||
|
||||
SelectDataBuffered();
|
||||
|
||||
echo "\nDone\n";
|
||||
?>
|
||||
--EXPECT--
|
||||
Connected successfully with ColumnEncryption enabled.
|
||||
1
|
||||
748-68-0245
|
||||
Jeannette
|
||||
McDonald
|
||||
2002-11-28
|
||||
|
||||
2
|
||||
795-73-9838
|
||||
John
|
||||
Doe
|
||||
2001-05-29
|
||||
|
||||
3
|
||||
456-12-5486
|
||||
Jonathan
|
||||
Wong
|
||||
1999-12-20
|
||||
|
||||
4
|
||||
156-45-5486
|
||||
Marianne
|
||||
Smith
|
||||
1997-03-04
|
||||
|
||||
Update Patient Jonathan Wong...
|
||||
Update his birthdate too...
|
||||
BirthDate updated for Jonathan:
|
||||
456-12-5486
|
||||
Jonathan
|
||||
Chang
|
||||
1999-12-31
|
||||
|
||||
BirthDate for the first record is: 2002-11-28
|
||||
SSN for the first record is: 748-68-0245
|
||||
|
||||
Row count for result set is 4
|
||||
First record=> SSN = 748-68-0245
|
||||
Next record=> BirthDate = 2001-05-29
|
||||
Last record=> LastName = Smith
|
||||
|
||||
Done
|
|
@ -72,7 +72,7 @@ function FetchField($stmt, $idx, $numFields, $errorExpected)
|
|||
function PrintError($errorExpected = true)
|
||||
{
|
||||
$errors = sqlsrv_errors(SQLSRV_ERR_ALL);
|
||||
if (count($errors) > 0)
|
||||
if (!empty($errors))
|
||||
{
|
||||
$e = $errors[0];
|
||||
var_dump($e['message']);
|
||||
|
|
|
@ -52,7 +52,7 @@ sqlsrv_close($conn);
|
|||
|
||||
?>
|
||||
--EXPECTREGEX--
|
||||
Notice\: Use of undefined constant SQLSRV_ENC_UNKNOWN - assumed \'SQLSRV_ENC_UNKNOWN\' in .+(\/|\\)sqlsrv_input_param_unknown_encoding\.php on line 26
|
||||
(Warning|Notice)\: Use of undefined constant SQLSRV_ENC_UNKNOWN - assumed \'SQLSRV_ENC_UNKNOWN\' (\(this will throw an Error in a future version of PHP\) )?in .+(\/|\\)sqlsrv_input_param_unknown_encoding\.php on line 26
|
||||
Array
|
||||
\(
|
||||
\[0\] => Array
|
||||
|
@ -67,7 +67,7 @@ Array
|
|||
|
||||
\)
|
||||
|
||||
Notice\: Use of undefined constant SQLSRV_ENC_UNKNOWN - assumed \'SQLSRV_ENC_UNKNOWN\' in .+(\/|\\)sqlsrv_input_param_unknown_encoding\.php on line 33
|
||||
(Warning|Notice)\: Use of undefined constant SQLSRV_ENC_UNKNOWN - assumed \'SQLSRV_ENC_UNKNOWN\' (\(this will throw an Error in a future version of PHP\) )?in .+(\/|\\)sqlsrv_input_param_unknown_encoding\.php on line 33
|
||||
Array
|
||||
\(
|
||||
\[0\] => Array
|
||||
|
@ -81,4 +81,3 @@ Array
|
|||
\)
|
||||
|
||||
\)
|
||||
|
||||
|
|
113
test/functional/sqlsrv/test_max_length.phpt
Normal file
113
test/functional/sqlsrv/test_max_length.phpt
Normal file
|
@ -0,0 +1,113 @@
|
|||
--TEST--
|
||||
Maximum length outputs from stored procs for string types (nvarchar, varchar, and varbinary)
|
||||
--SKIPIF--
|
||||
<?php require('skipif.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_time_limit(0);
|
||||
|
||||
$inValue1 = str_repeat( 'A', 3999 );
|
||||
|
||||
$outValue1 = "TEST";
|
||||
|
||||
sqlsrv_configure('WarningsReturnAsErrors', 0);
|
||||
sqlsrv_configure('LogSubsystems', 15);
|
||||
|
||||
require( 'MsCommon.inc' );
|
||||
|
||||
$conn = Connect();
|
||||
|
||||
$field_type = 'NVARCHAR(4000)';
|
||||
|
||||
$stmt = sqlsrv_query($conn, "DROP PROC [TestFullLenStringsOut]");
|
||||
$stmt = sqlsrv_query($conn, "CREATE PROC [TestFullLenStringsOut] (@p1 " . $field_type . ", @p2 " . $field_type . " OUTPUT)
|
||||
AS
|
||||
BEGIN
|
||||
SELECT @p2 = CONVERT(" . $field_type . ", @p1 + N'A')
|
||||
END");
|
||||
if( $stmt === false ) {
|
||||
die( print_r( sqlsrv_errors(), true ));
|
||||
}
|
||||
|
||||
// remember to increment buffer_len to 8001 to see what happens
|
||||
$stmt = sqlsrv_query($conn, "{CALL [TestFullLenStringsOut] (?, ?)}",
|
||||
array(
|
||||
array($inValue1, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8'), SQLSRV_SQLTYPE_NVARCHAR(4000)),
|
||||
array(&$outValue1, SQLSRV_PARAM_INOUT, SQLSRV_PHPTYPE_STRING('utf-8'), SQLSRV_SQLTYPE_NVARCHAR(4000))));
|
||||
if( $stmt === false ) {
|
||||
die( print_r( sqlsrv_errors(), true ));
|
||||
}
|
||||
while( sqlsrv_next_result( $stmt )) {}
|
||||
print_r( strlen( $outValue1 ));
|
||||
echo "\n";
|
||||
print_r( substr( $outValue1, -2, 2 ));
|
||||
|
||||
$field_type = 'VARCHAR(8000)';
|
||||
$inValue1 = str_repeat( 'A', 7999 );
|
||||
|
||||
$stmt = sqlsrv_query($conn, "DROP PROC [TestFullLenStringsOut]");
|
||||
if( $stmt === false ) {
|
||||
die( print_r( sqlsrv_errors(), true ));
|
||||
}
|
||||
$stmt = sqlsrv_query( $conn, "CREATE PROC [TestFullLenStringsOut] (@p1 " . $field_type . ", @p2 " . $field_type . " OUTPUT)
|
||||
AS
|
||||
BEGIN
|
||||
SELECT @p2 = CONVERT(" . $field_type . ", @p1 + 'A')
|
||||
END" );
|
||||
if( $stmt === false ) {
|
||||
die( print_r( sqlsrv_errors(), true ));
|
||||
}
|
||||
|
||||
$stmt = sqlsrv_query($conn, "{CALL [TestFullLenStringsOut] (?, ?)}",
|
||||
array(
|
||||
array($inValue1, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARCHAR(8000)),
|
||||
array(&$outValue1, SQLSRV_PARAM_INOUT, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARCHAR(8000))));
|
||||
if( $stmt === false ) {
|
||||
die( print_r( sqlsrv_errors(), true ));
|
||||
}
|
||||
while( sqlsrv_next_result( $stmt )) {}
|
||||
echo "\n";
|
||||
print_r( strlen( $outValue1 ));
|
||||
echo "\n";
|
||||
print_r( substr( $outValue1, -2, 2 ));
|
||||
|
||||
$field_type = 'VARBINARY(8000)';
|
||||
$inValue1 = str_repeat( 'A', 7999 );
|
||||
|
||||
$stmt = sqlsrv_query($conn, "DROP PROC [TestFullLenStringsOut]");
|
||||
if( $stmt === false ) {
|
||||
die( print_r( sqlsrv_errors(), true ));
|
||||
}
|
||||
$stmt = sqlsrv_query($conn, "CREATE PROC [TestFullLenStringsOut] (@p1 " . $field_type . ", @p2 " . $field_type . " OUTPUT)
|
||||
AS
|
||||
BEGIN
|
||||
SELECT @p2 = CONVERT(" . $field_type . ", @p1 + 0x42)
|
||||
END");
|
||||
if( $stmt === false ) {
|
||||
die( print_r( sqlsrv_errors(), true ));
|
||||
}
|
||||
|
||||
$stmt = sqlsrv_query($conn, "{CALL [TestFullLenStringsOut] (?, ?)}",
|
||||
array(
|
||||
array($inValue1, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY), SQLSRV_SQLTYPE_VARBINARY(8000)),
|
||||
array(&$outValue1, SQLSRV_PARAM_INOUT, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY), SQLSRV_SQLTYPE_VARBINARY(8000))));
|
||||
if( $stmt === false ) {
|
||||
die( print_r( sqlsrv_errors(), true ));
|
||||
}
|
||||
while( sqlsrv_next_result( $stmt )) {}
|
||||
echo "\n";
|
||||
print_r( strlen( $outValue1 ));
|
||||
echo "\n";
|
||||
print_r( substr( $outValue1, -2, 2 ));
|
||||
|
||||
sqlsrv_close( $conn );
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
4000
|
||||
AA
|
||||
8000
|
||||
AA
|
||||
8000
|
||||
AB
|
Loading…
Reference in a new issue