commit
e7e7a8d636
|
@ -1,7 +1,7 @@
|
|||
sudo: required
|
||||
|
||||
os: linux
|
||||
dist: trusty
|
||||
dist: bionic
|
||||
|
||||
group: edge
|
||||
|
||||
|
@ -20,10 +20,10 @@ env:
|
|||
- TEST_PHP_SQL_PWD=Password123
|
||||
|
||||
before_install:
|
||||
- docker pull mcr.microsoft.com/mssql/server:2019-latest
|
||||
- docker pull mcr.microsoft.com/mssql/server:2017-latest
|
||||
|
||||
install:
|
||||
- docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=Password123' -p 1433:1433 --name=$TEST_PHP_SQL_SERVER -d mcr.microsoft.com/mssql/server:2019-latest
|
||||
- docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=Password123' -p 1433:1433 --name=$TEST_PHP_SQL_SERVER -d mcr.microsoft.com/mssql/server:2017-latest
|
||||
- docker build --build-arg PHPSQLDIR=$PHPSQLDIR -t msphpsql-dev -f Dockerfile-msphpsql .
|
||||
|
||||
before_script:
|
||||
|
@ -43,7 +43,6 @@ script:
|
|||
- docker exec client bash -c 'for f in ./test/functional/pdo_sqlsrv/*.out; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true'
|
||||
- docker exec client python ./test/functional/setup/cleanup_dbs.py -dbname $SQLSRV_DBNAME
|
||||
- docker exec client python ./test/functional/setup/cleanup_dbs.py -dbname $PDOSQLSRV_DBNAME
|
||||
- docker exec client coveralls -i ./source/ -e ./source/shared/ -e ./test/ --gcov-options '\-lp'
|
||||
- docker stop client
|
||||
- docker ps -a
|
||||
|
||||
|
|
32
CHANGELOG.md
32
CHANGELOG.md
|
@ -3,6 +3,38 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
|
||||
## 5.9.0-beta2 - 2020-12-02
|
||||
Updated PECL release packages. Here is the list of updates:
|
||||
|
||||
### Added
|
||||
- Support for PHP 8.0
|
||||
|
||||
### Removed
|
||||
- Dropped support for PHP 7.2
|
||||
|
||||
### Fixed
|
||||
- Pull Request [#1205](https://github.com/microsoft/msphpsql/pull/1205) - minimized compilation warnings on Linux and macOS
|
||||
- Pull Request [#1209](https://github.com/microsoft/msphpsql/pull/1209) - fixed a bug in fetching varbinary max fields as char or wide chars
|
||||
- Issue [#1210](https://github.com/microsoft/msphpsql/issues/1210) - switched from preview to beta terminology to enable Pickle support
|
||||
- Issue [#1213](https://github.com/microsoft/msphpsql/issues/1213) - the MACOSX_DEPLOYMENT_TARGET in config files caused linker errors in macOS Big Sur - Pull Request [#1215](https://github.com/microsoft/msphpsql/pull/1215)
|
||||
|
||||
### Limitations
|
||||
- No support for inout / output params when using sql_variant type
|
||||
- No support for inout / output params when formatting decimal values
|
||||
- In Linux and macOS, setlocale() only takes effect if it is invoked before the first connection. Attempting to set the locale after connecting will not work
|
||||
- Always Encrypted requires [MS ODBC Driver 17+](https://docs.microsoft.com/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server)
|
||||
- Only Windows Certificate Store and Azure Key Vault are supported. Custom Keystores are not yet supported
|
||||
- Issue [#716](https://github.com/Microsoft/msphpsql/issues/716) - With Always Encrypted enabled, named parameters in subqueries are not supported
|
||||
- Issue [#1050](https://github.com/microsoft/msphpsql/issues/1050) - With Always Encrypted enabled, insertion requires the column list for any tables with identity columns
|
||||
- [Always Encrypted limitations](https://docs.microsoft.com/sql/connect/php/using-always-encrypted-php-drivers#limitations-of-the-php-drivers-when-using-always-encrypted)
|
||||
|
||||
### Known Issues
|
||||
- This preview release requires ODBC Driver 17.4.2 or above. Otherwise, a warning about failing to set an attribute may be suppressed when using an older ODBC driver.
|
||||
- Connection pooling on Linux or macOS is not recommended with [unixODBC](http://www.unixodbc.org/) < 2.3.7
|
||||
- When pooling is enabled in Linux or macOS
|
||||
- unixODBC <= 2.3.4 (Linux and macOS) might not return proper diagnostic information, such as error messages, warnings and informative messages
|
||||
- due to this unixODBC bug, fetch large data (such as xml, binary) as streams as a workaround. See the examples [here](https://github.com/Microsoft/msphpsql/wiki/Features#pooling)
|
||||
|
||||
## 5.9.0-preview1 - 2020-10-02
|
||||
Updated PECL release packages. Here is the list of updates:
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
# Linux and macOS Installation Tutorial for the Microsoft Drivers for PHP for SQL Server
|
||||
The following instructions assume a clean environment and show how to install PHP 7.2+, the Microsoft ODBC driver, the Apache web server, and the Microsoft Drivers for PHP for SQL Server on Ubuntu 16.04, 18.04, and 20.04, RedHat 7 and 8, Debian 9 and 10, Suse 12 and 15, Alpine 3.11 and 3.12, and macOS 10.13, 10.14, and 10.15. These instructions advise installing the drivers using PECL, but you can also download the prebuilt binaries from the [Microsoft Drivers for PHP for SQL Server](https://github.com/Microsoft/msphpsql/releases) Github project page and install them following the instructions in [Loading the Microsoft Drivers for PHP for SQL Server](https://docs.microsoft.com/sql/connect/php/loading-the-php-sql-driver). For an explanation of extension loading and why we do not add the extensions to php.ini, see the section on [loading the drivers](https://docs.microsoft.com/sql/connect/php/loading-the-php-sql-driver#loading-the-driver-at-php-startup).
|
||||
The following instructions assume a clean environment and show how to install PHP 7.3+, the Microsoft ODBC driver, the Apache web server, and the Microsoft Drivers for PHP for SQL Server on Ubuntu 16.04, 18.04, and 20.04, RedHat 7 and 8, Debian 9 and 10, Suse 12 and 15, Alpine 3.11 and 3.12, and macOS 10.13, 10.14, and 10.15. These instructions advise installing the drivers using PECL, but you can also download the prebuilt binaries from the [Microsoft Drivers for PHP for SQL Server](https://github.com/Microsoft/msphpsql/releases) Github project page and install them following the instructions in [Loading the Microsoft Drivers for PHP for SQL Server](https://docs.microsoft.com/sql/connect/php/loading-the-php-sql-driver). For an explanation of extension loading and why we do not add the extensions to php.ini, see the section on [loading the drivers](https://docs.microsoft.com/sql/connect/php/loading-the-php-sql-driver#loading-the-driver-at-php-startup).
|
||||
|
||||
The following instructions install PHP 7.4 by default using `pecl install`. You may need to run `pecl channel-update pecl.php.net` first. Note that some supported Linux distros default to PHP 7.1 or earlier, which is not supported for the latest version of the PHP drivers for SQL Server -- please see the notes at the beginning of each section to install PHP 7.2 or 7.3 instead.
|
||||
The following instructions install PHP 8.0 by default using `pecl install` if PHP 8.0 packages are available. You may need to run `pecl channel-update pecl.php.net` first. Note that some supported Linux distros default to PHP 7.1 or earlier, which is not supported for the latest version of the PHP drivers for SQL Server -- please see the notes at the beginning of each section to install PHP 7.4 or 7.3 instead.
|
||||
|
||||
Also included are instructions for installing the PHP FastCGI Process Manager, PHP-FPM, on Ubuntu. This is needed if using the nginx web server instead of Apache.
|
||||
|
||||
## Contents of this page:
|
||||
|
||||
- [Installing the drivers on Ubuntu 16.04, 18.04, and 19.10](#installing-the-drivers-on-ubuntu-1604-1804-and-1910)
|
||||
- [Installing the drivers on Ubuntu 16.04, 18.04, and 20.04](#installing-the-drivers-on-ubuntu-1604-1804-and-2004)
|
||||
- [Installing the drivers with PHP-FPM on Ubuntu](#installing-the-drivers-with-php-fpm-on-ubuntu)
|
||||
- [Installing the drivers on Red Hat 7 and 8](#installing-the-drivers-on-red-hat-7-and-8)
|
||||
- [Installing the drivers on Debian 9 and 10](#installing-the-drivers-on-debian-9-and-10)
|
||||
|
@ -15,30 +15,30 @@ Also included are instructions for installing the PHP FastCGI Process Manager, P
|
|||
- [Installing the drivers on Alpine 3.11 and 3.12](#installing-the-drivers-on-alpine-311-and-312)
|
||||
- [Installing the drivers on macOS High Sierra, Mojave, and Catalina](#installing-the-drivers-on-macos-high-sierra-mojave-and-catalina)
|
||||
|
||||
## Installing the drivers on Ubuntu 16.04, 18.04, and 19.10
|
||||
## Installing the drivers on Ubuntu 16.04, 18.04, and 20.04
|
||||
|
||||
> [!NOTE]
|
||||
> To install PHP 7.2 or 7.3, replace 7.4 with 7.2 or 7.3 in the following commands.
|
||||
> To install PHP 7.4 or 7.3, replace 8.0 with 7.4 or 7.3 in the following commands.
|
||||
|
||||
### Step 1. Install PHP
|
||||
```bash
|
||||
sudo su
|
||||
add-apt-repository ppa:ondrej/php -y
|
||||
apt-get update
|
||||
apt-get install php7.4 php7.4-dev php7.4-xml -y --allow-unauthenticated
|
||||
apt-get install php8.0 php8.0-dev php8.0-xml -y --allow-unauthenticated
|
||||
```
|
||||
### Step 2. Install prerequisites
|
||||
Install the ODBC driver for Ubuntu by following the instructions on the [Linux and macOS installation page](https://docs.microsoft.com/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server).
|
||||
Install the ODBC driver for Ubuntu by following the instructions on [Install the Microsoft ODBC driver for SQL Server (Linux)](https://docs.microsoft.com/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-ver15).
|
||||
|
||||
### Step 3. Install the PHP drivers for Microsoft SQL Server
|
||||
```
|
||||
sudo pecl install sqlsrv
|
||||
sudo pecl install pdo_sqlsrv
|
||||
sudo pecl install sqlsrv-5.9.0beta2
|
||||
sudo pecl install pdo_sqlsrv-5.9.0beta2
|
||||
sudo su
|
||||
printf "; priority=20\nextension=sqlsrv.so\n" > /etc/php/7.4/mods-available/sqlsrv.ini
|
||||
printf "; priority=30\nextension=pdo_sqlsrv.so\n" > /etc/php/7.4/mods-available/pdo_sqlsrv.ini
|
||||
printf "; priority=20\nextension=sqlsrv.so\n" > /etc/php/8.0/mods-available/sqlsrv.ini
|
||||
printf "; priority=30\nextension=pdo_sqlsrv.so\n" > /etc/php/8.0/mods-available/pdo_sqlsrv.ini
|
||||
exit
|
||||
sudo phpenmod -v 7.4 sqlsrv pdo_sqlsrv
|
||||
sudo phpenmod -v 8.0 sqlsrv pdo_sqlsrv
|
||||
```
|
||||
|
||||
If there is only one PHP version in the system, then the last step can be simplified to `phpenmod sqlsrv pdo_sqlsrv`.
|
||||
|
@ -46,10 +46,10 @@ If there is only one PHP version in the system, then the last step can be simpli
|
|||
### Step 4. Install Apache and configure driver loading
|
||||
```
|
||||
sudo su
|
||||
apt-get install libapache2-mod-php7.4 apache2
|
||||
apt-get install libapache2-mod-php8.0 apache2
|
||||
a2dismod mpm_event
|
||||
a2enmod mpm_prefork
|
||||
a2enmod php7.4
|
||||
a2enmod php8.0
|
||||
exit
|
||||
```
|
||||
### Step 5. Restart Apache and test the sample script
|
||||
|
@ -61,42 +61,42 @@ To test your installation, see [Testing your installation](#testing-your-install
|
|||
## Installing the drivers with PHP-FPM on Ubuntu
|
||||
|
||||
> [!NOTE]
|
||||
> To install PHP 7.2 or 7.3, replace 7.4 with 7.2 or 7.3 in the following commands.
|
||||
> To install PHP 7.4 or 7.3, replace 8.0 with 7.4 or 7.3 in the following commands.
|
||||
|
||||
### Step 1. Install PHP
|
||||
```bash
|
||||
sudo su
|
||||
add-apt-repository ppa:ondrej/php -y
|
||||
apt-get update
|
||||
apt-get install php7.4 php7.4-dev php7.4-xml php7.4-fpm -y --allow-unauthenticated
|
||||
apt-get install php8.0 php8.0-dev php8.0-xml -y --allow-unauthenticated
|
||||
```
|
||||
Verify the status of the PHP-FPM service by running
|
||||
```
|
||||
systemctl status php7.4-fpm
|
||||
systemctl status php8.0-fpm
|
||||
```
|
||||
### Step 2. Install prerequisites
|
||||
Install the ODBC driver for Ubuntu by following the instructions on the [Linux and macOS installation page](https://docs.microsoft.com/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server).
|
||||
Install the ODBC driver for Ubuntu by following the instructions on [Install the Microsoft ODBC driver for SQL Server (Linux)](https://docs.microsoft.com/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-ver15).
|
||||
|
||||
### Step 3. Install the PHP drivers for Microsoft SQL Server
|
||||
```
|
||||
sudo pecl config-set php_ini /etc/php/7.3/fpm/php.ini
|
||||
sudo pecl install sqlsrv
|
||||
sudo pecl install pdo_sqlsrv
|
||||
sudo pecl config-set php_ini /etc/php/8.0/fpm/php.ini
|
||||
sudo pecl install sqlsrv-5.9.0beta2
|
||||
sudo pecl install pdo_sqlsrv-5.9.0beta2
|
||||
sudo su
|
||||
printf "; priority=20\nextension=sqlsrv.so\n" > /etc/php/7.4/mods-available/sqlsrv.ini
|
||||
printf "; priority=30\nextension=pdo_sqlsrv.so\n" > /etc/php/7.4/mods-available/pdo_sqlsrv.ini
|
||||
printf "; priority=20\nextension=sqlsrv.so\n" > /etc/php/8.0/mods-available/sqlsrv.ini
|
||||
printf "; priority=30\nextension=pdo_sqlsrv.so\n" > /etc/php/8.0/mods-available/pdo_sqlsrv.ini
|
||||
exit
|
||||
sudo phpenmod -v 7.4 sqlsrv pdo_sqlsrv
|
||||
sudo phpenmod -v 8.0 sqlsrv pdo_sqlsrv
|
||||
```
|
||||
If there is only one PHP version in the system, then the last step can be simplified to `phpenmod sqlsrv pdo_sqlsrv`.
|
||||
|
||||
Verify that `sqlsrv.ini` and `pdo_sqlsrv.ini` are located in `/etc/php/7.4/fpm/conf.d/`:
|
||||
Verify that `sqlsrv.ini` and `pdo_sqlsrv.ini` are located in `/etc/php/8.0/fpm/conf.d/`:
|
||||
```
|
||||
ls /etc/php/7.4/fpm/conf.d/*sqlsrv.ini
|
||||
ls /etc/php/8.0/fpm/conf.d/*sqlsrv.ini
|
||||
```
|
||||
Restart the PHP-FPM service:
|
||||
```
|
||||
sudo systemctl restart php7.4-fpm
|
||||
sudo systemctl restart php8.0-fpm
|
||||
```
|
||||
|
||||
### Step 4. Install and configure nginx
|
||||
|
@ -116,7 +116,7 @@ Next, modify the section following `# pass PHP scripts to FastCGI server` as fol
|
|||
#
|
||||
location ~ \.php$ {
|
||||
include snippets/fastcgi-php.conf;
|
||||
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
|
||||
fastcgi_pass unix:/run/php/php8.0-fpm.sock;
|
||||
}
|
||||
```
|
||||
### Step 5. Restart nginx and test the sample script
|
||||
|
@ -131,40 +131,40 @@ To test your installation, see [Testing your installation](#testing-your-install
|
|||
|
||||
To install PHP on Red Hat 7, run the following:
|
||||
> [!NOTE]
|
||||
> To install PHP 7.2 or 7.3, replace remi-php74 with remi-php72 or remi-php73 respectively in the following commands.
|
||||
> To install PHP 7.4 or 7.3, replace remi-php80 with remi-php74 or remi-php73 respectively in the following commands.
|
||||
```
|
||||
sudo su
|
||||
yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
|
||||
yum install https://rpms.remirepo.net/enterprise/remi-release-7.rpm
|
||||
subscription-manager repos --enable=rhel-7-server-optional-rpms
|
||||
yum install yum-utils
|
||||
yum-config-manager --enable remi-php74
|
||||
yum-config-manager --enable remi-php80
|
||||
yum update
|
||||
yum install php php-pdo php-xml php-pear php-devel re2c gcc-c++ gcc
|
||||
```
|
||||
|
||||
To install PHP on Red Hat 8, run the following:
|
||||
> [!NOTE]
|
||||
> To install PHP 7.2 or 7.3, replace remi-7.4 with remi-7.2 or remi-7.3 respectively in the following commands.
|
||||
> To install PHP 7.4 or 7.3, replace remi-8.0 with remi-7.4 or remi-7.3 respectively in the following commands.
|
||||
```
|
||||
sudo su
|
||||
dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
|
||||
dnf install https://rpms.remirepo.net/enterprise/remi-release-8.rpm
|
||||
dnf install yum-utils
|
||||
dnf module reset php
|
||||
dnf module install php:remi-7.4
|
||||
dnf module install php:remi-8.0
|
||||
subscription-manager repos --enable codeready-builder-for-rhel-8-x86_64-rpms
|
||||
dnf update
|
||||
dnf install php-pdo php-pear php-devel
|
||||
```
|
||||
|
||||
### Step 2. Install prerequisites
|
||||
Install the ODBC driver for Red Hat 7 or 8 by following the instructions on the [Linux and macOS installation page](https://docs.microsoft.com/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server).
|
||||
Install the ODBC driver for Red Hat 7 or 8 by following the instructions on [Install the Microsoft ODBC driver for SQL Server (Linux)](https://docs.microsoft.com/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-ver15).
|
||||
|
||||
### Step 3. Install the PHP drivers for Microsoft SQL Server
|
||||
```
|
||||
sudo pecl install sqlsrv
|
||||
sudo pecl install pdo_sqlsrv
|
||||
sudo pecl install sqlsrv-5.9.0beta2
|
||||
sudo pecl install pdo_sqlsrv-5.9.0beta2
|
||||
sudo su
|
||||
echo extension=pdo_sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/30-pdo_sqlsrv.ini
|
||||
echo extension=sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/20-sqlsrv.ini
|
||||
|
@ -192,7 +192,7 @@ To test your installation, see [Testing your installation](#testing-your-install
|
|||
## Installing the drivers on Debian 9 and 10
|
||||
|
||||
> [!NOTE]
|
||||
> To install PHP 7.2 or 7.3, replace 7.4 in the following commands with 7.2 or 7.3.
|
||||
> To install PHP 7.4 or 7.3, replace 8.0 in the following commands with 7.4 or 7.3.
|
||||
|
||||
### Step 1. Install PHP
|
||||
```
|
||||
|
@ -201,10 +201,10 @@ 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.4 php7.4-dev php7.4-xml php7.4-intl
|
||||
apt-get install -y php8.0 php8.0-dev php8.0-xml php8.0-intl
|
||||
```
|
||||
### Step 2. Install prerequisites
|
||||
Install the ODBC driver for Debian by following the instructions on the [Linux and macOS installation page](https://docs.microsoft.com/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server).
|
||||
Install the ODBC driver for Debian by following the instructions on [Install the Microsoft ODBC driver for SQL Server (Linux)](https://docs.microsoft.com/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-ver15).
|
||||
|
||||
You may also need to generate the correct locale to get PHP output to display correctly in a browser. For example, for the en_US UTF-8 locale, run the following commands:
|
||||
```
|
||||
|
@ -216,13 +216,13 @@ You may need to add `/usr/sbin` to your `$PATH`, as the `locale-gen` executable
|
|||
|
||||
### Step 3. Install the PHP drivers for Microsoft SQL Server
|
||||
```
|
||||
sudo pecl install sqlsrv
|
||||
sudo pecl install pdo_sqlsrv
|
||||
sudo pecl install sqlsrv-5.9.0beta2
|
||||
sudo pecl install pdo_sqlsrv-5.9.0beta2
|
||||
sudo su
|
||||
printf "; priority=20\nextension=sqlsrv.so\n" > /etc/php/7.4/mods-available/sqlsrv.ini
|
||||
printf "; priority=30\nextension=pdo_sqlsrv.so\n" > /etc/php/7.4/mods-available/pdo_sqlsrv.ini
|
||||
printf "; priority=20\nextension=sqlsrv.so\n" > /etc/php/8.0/mods-available/sqlsrv.ini
|
||||
printf "; priority=30\nextension=pdo_sqlsrv.so\n" > /etc/php/8.0/mods-available/pdo_sqlsrv.ini
|
||||
exit
|
||||
sudo phpenmod -v 7.4 sqlsrv pdo_sqlsrv
|
||||
sudo phpenmod -v 8.0 sqlsrv pdo_sqlsrv
|
||||
```
|
||||
|
||||
If there is only one PHP version in the system, then the last step can be simplified to `phpenmod sqlsrv pdo_sqlsrv`. As with `locale-gen`, `phpenmod` is located in `/usr/sbin` so you may need to add this directory to your `$PATH`.
|
||||
|
@ -230,10 +230,10 @@ If there is only one PHP version in the system, then the last step can be simpli
|
|||
### Step 4. Install Apache and configure driver loading
|
||||
```
|
||||
sudo su
|
||||
apt-get install libapache2-mod-php7.4 apache2
|
||||
apt-get install libapache2-mod-php8.0 apache2
|
||||
a2dismod mpm_event
|
||||
a2enmod mpm_prefork
|
||||
a2enmod php7.4
|
||||
a2enmod php8.0
|
||||
```
|
||||
### Step 5. Restart Apache and test the sample script
|
||||
```
|
||||
|
@ -244,12 +244,10 @@ To test your installation, see [Testing your installation](#testing-your-install
|
|||
## Installing the drivers on Suse 12 and 15
|
||||
|
||||
> [!NOTE]
|
||||
> In the following instructions, replace `<SuseVersion>` with your version of Suse - if you are using Suse Enterprise Linux 15, it will be SLE_15 or SLE_15_SP1. For Suse 12, use SLE_12_SP4 (or above if applicable). Not all versions of PHP are available for all versions of Suse Linux - please refer to `http://download.opensuse.org/repositories/devel:/languages:/php` to see which versions of Suse have the default version PHP available, or to `http://download.opensuse.org/repositories/devel:/languages:/php:/` to see which other versions of PHP are available for which versions of Suse.
|
||||
> In the following instructions, replace `<SuseVersion>` with your version of Suse - if you are using Suse Enterprise Linux 15, it will be SLE_15_SP1 or SLE_15_SP2. For Suse 12, use SLE_12_SP4 (or above if applicable). Not all versions of PHP are available for all versions of Suse Linux - please refer to `http://download.opensuse.org/repositories/devel:/languages:/php` to see which versions of Suse have the default version PHP available, or check `http://download.opensuse.org/repositories/devel:/languages:/php:/` to see which other versions of PHP are available for which versions of Suse.
|
||||
|
||||
> [!NOTE]
|
||||
> Packages for PHP 7.4 are not available for Suse 12.
|
||||
> To install PHP 7.2, replace the repository URL below with the following URL:
|
||||
`https://download.opensuse.org/repositories/devel:/languages:/php:/php72/<SuseVersion>/devel:languages:php:php72.repo`.
|
||||
> Packages for PHP 7.4 or above are not available for Suse 12 and Package for PHP 8.0 is not yet available for Suse 15.
|
||||
> To install PHP 7.3, replace the repository URL below with the following URL:
|
||||
`https://download.opensuse.org/repositories/devel:/languages:/php:/php73/<SuseVersion>/devel:languages:php:php73.repo`.
|
||||
|
||||
|
@ -261,15 +259,15 @@ zypper --gpg-auto-import-keys refresh
|
|||
zypper -n install php7 php7-devel php7-openssl
|
||||
```
|
||||
### Step 2. Install prerequisites
|
||||
Install the ODBC driver for Suse by following the instructions on the [Linux and macOS installation page](https://docs.microsoft.com/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server).
|
||||
Install the ODBC driver for Suse by following the instructions on [Install the Microsoft ODBC driver for SQL Server (Linux)](https://docs.microsoft.com/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-ver15).
|
||||
|
||||
### Step 3. Install the PHP drivers for Microsoft SQL Server
|
||||
> [!NOTE]
|
||||
> If you get an error message saying `Connection to 'pecl.php.net:443' failed: Unable to find the socket transport "ssl"`, edit the pecl script at /usr/bin/pecl and remove the `-n` switch in the last line. This switch prevents PECL from loading ini files when PHP is called, which prevents the OpenSSL extension from loading.
|
||||
|
||||
```
|
||||
sudo pecl install sqlsrv
|
||||
sudo pecl install pdo_sqlsrv
|
||||
sudo pecl install sqlsrv-5.9.0beta2
|
||||
sudo pecl install pdo_sqlsrv-5.9.0beta2
|
||||
sudo su
|
||||
echo extension=pdo_sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/pdo_sqlsrv.ini
|
||||
echo extension=sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/sqlsrv.ini
|
||||
|
@ -307,12 +305,12 @@ apk update
|
|||
apk add php7 php7-dev php7-pear php7-pdo php7-openssl autoconf make g++
|
||||
```
|
||||
### Step 2. Install prerequisites
|
||||
Install the ODBC driver for Alpine by following the instructions on the [Linux and macOS installation page](https://docs.microsoft.com/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server).
|
||||
Install the ODBC driver for Alpine by following the instructions on [Install the Microsoft ODBC driver for SQL Server (Linux)](https://docs.microsoft.com/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-ver15).
|
||||
|
||||
### Step 3. Install the PHP drivers for Microsoft SQL Server
|
||||
```
|
||||
sudo pecl install sqlsrv
|
||||
sudo pecl install pdo_sqlsrv
|
||||
sudo pecl install sqlsrv-5.9.0beta2
|
||||
sudo pecl install pdo_sqlsrv-5.9.0beta2
|
||||
sudo su
|
||||
echo extension=pdo_sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/10_pdo_sqlsrv.ini
|
||||
echo extension=sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/00_sqlsrv.ini
|
||||
|
@ -337,22 +335,23 @@ If you do not already have it, install brew as follows:
|
|||
```
|
||||
|
||||
> [!NOTE]
|
||||
> To install PHP 7.2 or 7.3, replace php@7.4 with php@7.2 or php@7.3 respectively in the following commands.
|
||||
> To install PHP 7.4 or 7.3, replace php@8.0 with php@7.4 or php@7.3 respectively in the following commands.
|
||||
|
||||
### Step 1. Install PHP
|
||||
|
||||
```
|
||||
brew tap
|
||||
brew tap homebrew/core
|
||||
brew install php@7.4
|
||||
brew install php@8.0
|
||||
```
|
||||
PHP should now be in your path -- run `php -v` to verify that you are running the correct version of PHP. If PHP is not in your path or it is not the correct version, run the following:
|
||||
```
|
||||
brew link --force --overwrite php@7.4
|
||||
brew link --force --overwrite php@8.0
|
||||
```
|
||||
|
||||
### Step 2. Install prerequisites
|
||||
Install the ODBC driver for macOS by following the instructions on the [Linux and macOS installation page](https://docs.microsoft.com/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server).
|
||||
Install the ODBC driver for macOS by following the instructions on [Install the Microsoft ODBC driver for SQL Server (macOS)](
|
||||
https://docs.microsoft.com/sql/connect/odbc/linux-mac/install-microsoft-odbc-driver-sql-server-macos?view=sql-server-ver15).
|
||||
|
||||
In addition, you may need to install the GNU make tools:
|
||||
```
|
||||
|
@ -361,8 +360,8 @@ brew install autoconf automake libtool
|
|||
|
||||
### Step 3. Install the PHP drivers for Microsoft SQL Server
|
||||
```
|
||||
sudo pecl install sqlsrv
|
||||
sudo pecl install pdo_sqlsrv
|
||||
sudo pecl install sqlsrv-5.9.0beta2
|
||||
sudo pecl install pdo_sqlsrv-5.9.0beta2
|
||||
```
|
||||
### Step 4. Install Apache and configure driver loading
|
||||
```
|
||||
|
@ -374,7 +373,7 @@ To find the Apache configuration file, `httpd.conf`, for your Apache installatio
|
|||
```
|
||||
The following commands append the required configuration to `httpd.conf`. Be sure to substitute the path returned by the preceding command in place of `/usr/local/etc/httpd/httpd.conf`:
|
||||
```
|
||||
echo "LoadModule php7_module /usr/local/opt/php@7.4/lib/httpd/modules/libphp7.so" >> /usr/local/etc/httpd/httpd.conf
|
||||
echo "LoadModule php7_module /usr/local/opt/php@8.0/lib/httpd/modules/libphp7.so" >> /usr/local/etc/httpd/httpd.conf
|
||||
(echo "<FilesMatch .php$>"; echo "SetHandler application/x-httpd-php"; echo "</FilesMatch>";) >> /usr/local/etc/httpd/httpd.conf
|
||||
```
|
||||
### Step 5. Restart Apache and test the sample script
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
The Microsoft Drivers for PHP for Microsoft SQL Server are PHP extensions that allow for the reading and writing of SQL Server data from within PHP scripts. The SQLSRV extension provides a procedural interface while the PDO_SQLSRV extension implements PHP Data Objects (PDO) for accessing data in all editions of SQL Server 2012 and later (including Azure SQL DB). These drivers rely on the [Microsoft ODBC Driver for SQL Server][odbcdoc] to handle the low-level communication with SQL Server.
|
||||
|
||||
This release contains the SQLSRV and PDO_SQLSRV drivers for PHP 7.2+ with improvements on both drivers and some limitations. Upcoming [releases][releases] will contain additional functionalities, bug fixes, and more.
|
||||
This release contains the SQLSRV and PDO_SQLSRV drivers for PHP 7.3+ with improvements on both drivers and some limitations. Upcoming [releases][releases] will contain additional functionalities, bug fixes, and more.
|
||||
|
||||
## Take our survey
|
||||
|
||||
|
@ -45,7 +45,7 @@ Azure Pipelines | AppVeyor (Windows) | Travis CI (Linux) | Co
|
|||
For full details on the system requirements for the drivers, see the [system requirements](https://docs.microsoft.com/sql/connect/php/system-requirements-for-the-php-sql-driver) on Microsoft Docs.
|
||||
|
||||
On the client machine:
|
||||
- PHP 7.2.x (7.2.0 and up on Unix, 7.2.1 and up on Windows), 7.3.x, or 7.4.x
|
||||
- 7.3.x, 7.4.x, 8.0.x
|
||||
- [Microsoft ODBC Driver 17, Microsoft ODBC Driver 13, or Microsoft ODBC Driver 11][odbcdoc]
|
||||
- If using a Web server such as Internet Information Services (IIS) or Apache, it must be configured to run PHP
|
||||
|
||||
|
@ -82,8 +82,8 @@ Given a version number MAJOR.MINOR.PATCH,
|
|||
|
||||
The version number may have trailing pre-release version identifiers to indicate the stability and/or build metadata.
|
||||
|
||||
- Pre-release version is denoted by a hyphen followed by `preview` or `RC` and may be followed by a series of dot separated identifiers. Production quality releases do not contain the pre-release version. `preview` has lower precedence than `RC`. Example of precedence: *preview < preview.1 < RC < RC.1*. Note that the PECL package version numbers do not have the hyphen before the pre-release version, owing to restrictions in PECL. Example of a PECL package version number: 1.2.3preview
|
||||
- Build metadata may be denoted by a plus sign followed by 4 or 5 digits, such as `1.2.3-preview+5678` or `1.2.3+5678`. Build metadata does not figure into the precedence order.
|
||||
- Pre-release version is denoted by a hyphen followed by `beta` or `RC` followed by a number. Production quality releases do not contain the pre-release version. `beta` has lower precedence than `RC`. Note that the PECL package version numbers do not have the hyphen before the pre-release version, owing to restrictions in PECL. An example of a PECL package version is `5.9.0beta2`.
|
||||
- Build metadata may be denoted by a plus sign followed by a number of digits, such as `5.9.0-beta2+13930`. Build metadata does not affect the precedence order.
|
||||
|
||||
## Future Plans
|
||||
- Expand SQL Server feature support (example: Azure Active Directory, Always Encrypted, etc.)
|
||||
|
|
|
@ -30,7 +30,7 @@ environment:
|
|||
SQL_INSTANCE: SQL2019
|
||||
PHP_VC: vs16
|
||||
PHP_MAJOR_VER: 8.0
|
||||
PHP_MINOR_VER: 0rc1
|
||||
PHP_MINOR_VER: 0RC2
|
||||
PHP_EXE_PATH: Release
|
||||
THREAD: nts
|
||||
platform: x86
|
||||
|
|
|
@ -13,6 +13,9 @@ variables:
|
|||
trigger:
|
||||
- dev
|
||||
|
||||
pr:
|
||||
- dev
|
||||
|
||||
jobs:
|
||||
- job: macOS
|
||||
pool:
|
||||
|
@ -30,8 +33,8 @@ jobs:
|
|||
- script: |
|
||||
brew tap
|
||||
brew tap homebrew/core
|
||||
brew install autoconf automake libtool
|
||||
brew install php@$(phpVersion)
|
||||
brew reinstall autoconf automake libtool
|
||||
brew reinstall php@$(phpVersion)
|
||||
php -v
|
||||
displayName: 'Install PHP'
|
||||
|
||||
|
@ -60,7 +63,7 @@ jobs:
|
|||
|
||||
- job: Linux
|
||||
variables:
|
||||
phpver: 7.3
|
||||
phpver: 7.4
|
||||
pool:
|
||||
vmImage: 'ubuntu-18.04'
|
||||
steps:
|
||||
|
@ -102,8 +105,15 @@ jobs:
|
|||
displayName: 'Install prerequisites'
|
||||
|
||||
- script: |
|
||||
docker pull mcr.microsoft.com/mssql/server:2017-latest
|
||||
docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=$(pwd)' -p 1433:1433 -h $(host) --name=$(host) -d mcr.microsoft.com/mssql/server:2017-latest
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install --upgrade requests
|
||||
python -m pip install PyYAML
|
||||
python -m pip install cpp-coveralls
|
||||
displayName: 'Install coveralls (upgrade both pip and requests first)'
|
||||
|
||||
- script: |
|
||||
docker pull mcr.microsoft.com/mssql/server:2019-latest
|
||||
docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=$(pwd)' -p 1433:1433 -h $(host) --name=$(host) -d mcr.microsoft.com/mssql/server:2019-latest
|
||||
docker ps -a
|
||||
sleep 10
|
||||
docker exec -t $(host) /opt/mssql-tools/bin/sqlcmd -S $(server) -U $(uid) -P $(pwd) -Q 'select @@Version'
|
||||
|
@ -144,7 +154,7 @@ jobs:
|
|||
|
||||
cd $(Build.SourcesDirectory)/source/sqlsrv
|
||||
ls -al
|
||||
phpize && ./configure && make && sudo make install
|
||||
phpize && ./configure LDFLAGS="-lgcov" CXXFLAGS="-O0 --coverage" && make && sudo make install
|
||||
cp run-tests.php $(Build.SourcesDirectory)/test/functional/sqlsrv
|
||||
echo extension=sqlsrv.so >> 20-sqlsrv.ini
|
||||
|
||||
|
@ -153,7 +163,7 @@ jobs:
|
|||
|
||||
cd $(Build.SourcesDirectory)/source/pdo_sqlsrv
|
||||
ls -al
|
||||
phpize && ./configure && make && sudo make install
|
||||
phpize && ./configure LDFLAGS="-lgcov" CXXFLAGS="-O0 --coverage" && make && sudo make install
|
||||
cp run-tests.php $(Build.SourcesDirectory)/test/functional/pdo_sqlsrv
|
||||
echo extension=pdo_sqlsrv.so >> 30-pdo_sqlsrv.ini
|
||||
|
||||
|
@ -189,6 +199,17 @@ jobs:
|
|||
php run-tests.php -P ./*.phpt 2>&1 | tee ../pdo_sqlsrv.log
|
||||
displayName: 'Run pdo_sqlsrv functional tests'
|
||||
|
||||
- script: |
|
||||
cd $(Build.SourcesDirectory)
|
||||
echo -e "service_name: Azure Pipelines\n" > .coveralls.yml
|
||||
coveralls -i ./source/ -e ./source/shared/ -e ./test/ -e ./source/pdo_sqlsrv/shared/core_stream.cpp \
|
||||
-E r'.*localization*' -E r'.*globalization*' --gcov-options '\-lp'
|
||||
displayName: 'Invoke coveralls using repo token'
|
||||
env:
|
||||
COVERALLS_REPO_TOKEN: $(repo_token)
|
||||
TRAVIS_JOB_ID: $(Build.BuildId)
|
||||
TRAVIS_BRANCH: $(Build.SourceBranchName)
|
||||
|
||||
- script: |
|
||||
cd $(Build.SourcesDirectory)/test/functional/
|
||||
for f in sqlsrv/*.diff; do ls $f 2>/dev/null; cat $f 2>/dev/null; echo ''; done || true
|
||||
|
|
|
@ -79,7 +79,6 @@ if test "$PHP_PDO_SQLSRV" != "no"; then
|
|||
HOST_OS_ARCH=`uname`
|
||||
if test "${HOST_OS_ARCH}" = "Darwin"; then
|
||||
PDO_SQLSRV_SHARED_LIBADD="$PDO_SQLSRV_SHARED_LIBADD -Wl,-bind_at_load"
|
||||
MACOSX_DEPLOYMENT_TARGET=`sw_vers -productVersion`
|
||||
else
|
||||
PDO_SQLSRV_SHARED_LIBADD="$PDO_SQLSRV_SHARED_LIBADD -Wl,-z,now"
|
||||
IS_ALPINE_1=`uname -a | cut -f 4 -d ' ' | cut -f 2 -d '-'`
|
||||
|
|
|
@ -912,6 +912,8 @@ int pdo_sqlsrv_dbh_begin( _Inout_ pdo_dbh_t *dbh )
|
|||
|
||||
DIE ("pdo_sqlsrv_dbh_begin: Uncaught exception occurred.");
|
||||
}
|
||||
// Should not have reached here but adding this due to compilation warnings
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -954,6 +956,8 @@ int pdo_sqlsrv_dbh_commit( _Inout_ pdo_dbh_t *dbh )
|
|||
|
||||
DIE ("pdo_sqlsrv_dbh_commit: Uncaught exception occurred.");
|
||||
}
|
||||
// Should not have reached here but adding this due to compilation warnings
|
||||
return 0;
|
||||
}
|
||||
|
||||
// pdo_sqlsrv_dbh_rollback
|
||||
|
@ -993,6 +997,8 @@ int pdo_sqlsrv_dbh_rollback( _Inout_ pdo_dbh_t *dbh )
|
|||
|
||||
DIE ("pdo_sqlsrv_dbh_rollback: Uncaught exception occurred.");
|
||||
}
|
||||
// Should not have reached here but adding this due to compilation warnings
|
||||
return 0;
|
||||
}
|
||||
|
||||
// pdo_sqlsrv_dbh_set_attr
|
||||
|
|
|
@ -116,7 +116,7 @@ void pdo_error_dtor( _Inout_ zval* elem ) {
|
|||
|
||||
PHP_MINIT_FUNCTION(pdo_sqlsrv)
|
||||
{
|
||||
SQLSRV_UNUSED( type );
|
||||
// SQLSRV_UNUSED( type );
|
||||
|
||||
// our global variables are initialized in the RINIT function
|
||||
#if defined(ZTS)
|
||||
|
@ -185,7 +185,7 @@ PHP_MSHUTDOWN_FUNCTION(pdo_sqlsrv)
|
|||
{
|
||||
try {
|
||||
|
||||
SQLSRV_UNUSED( type );
|
||||
// SQLSRV_UNUSED( type );
|
||||
|
||||
UNREGISTER_INI_ENTRIES();
|
||||
|
||||
|
@ -213,8 +213,8 @@ PHP_MSHUTDOWN_FUNCTION(pdo_sqlsrv)
|
|||
|
||||
PHP_RINIT_FUNCTION(pdo_sqlsrv)
|
||||
{
|
||||
SQLSRV_UNUSED( module_number );
|
||||
SQLSRV_UNUSED( type );
|
||||
// SQLSRV_UNUSED( module_number );
|
||||
// SQLSRV_UNUSED( type );
|
||||
|
||||
#if defined(ZTS)
|
||||
ZEND_TSRMLS_CACHE_UPDATE();
|
||||
|
@ -247,8 +247,8 @@ PHP_RINIT_FUNCTION(pdo_sqlsrv)
|
|||
|
||||
PHP_RSHUTDOWN_FUNCTION(pdo_sqlsrv)
|
||||
{
|
||||
SQLSRV_UNUSED( module_number );
|
||||
SQLSRV_UNUSED( type );
|
||||
// SQLSRV_UNUSED( module_number );
|
||||
// SQLSRV_UNUSED( type );
|
||||
|
||||
PDO_LOG_NOTICE("pdo_sqlsrv: entering rshutdown");
|
||||
|
||||
|
|
|
@ -187,7 +187,7 @@ void conn_string_parser::add_key_value_pair( _In_reads_(len) const char* value,
|
|||
memcpy_s( option, len + 1, value, len );
|
||||
option[len] = '\0';
|
||||
|
||||
valid = core_is_authentication_option_valid( option, len );
|
||||
valid = AzureADOptions::isAuthValid(option, len);
|
||||
}
|
||||
}
|
||||
if( !valid ) {
|
||||
|
|
|
@ -724,6 +724,8 @@ int pdo_sqlsrv_stmt_fetch( _Inout_ pdo_stmt_t *stmt, _In_ enum pdo_fetch_orienta
|
|||
|
||||
DIE ("pdo_sqlsrv_stmt_fetch: Unexpected exception occurred.");
|
||||
}
|
||||
// Should not have reached here but adding this due to compilation warnings
|
||||
return 0;
|
||||
}
|
||||
|
||||
// pdo_sqlsrv_stmt_get_col_data
|
||||
|
@ -832,15 +834,16 @@ int pdo_sqlsrv_stmt_get_col_data( _Inout_ pdo_stmt_t *stmt, _In_ int colno,
|
|||
*len = sizeof(zval);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
catch ( core::CoreException& ) {
|
||||
return 0;
|
||||
}
|
||||
catch ( ... ) {
|
||||
DIE ("pdo_sqlsrv_stmt_get_col_data: Unexpected exception occurred.");
|
||||
}
|
||||
// Should not have reached here but adding this due to compilation warnings
|
||||
return 0;
|
||||
}
|
||||
|
||||
// pdo_sqlsrv_stmt_set_attr
|
||||
|
|
|
@ -379,7 +379,7 @@ pdo_error PDO_ERRORS[] = {
|
|||
},
|
||||
{
|
||||
PDO_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION,
|
||||
{ IMSSP, (SQLCHAR*) "Invalid option for the Authentication keyword. Only SqlPassword, ActiveDirectoryPassword, or ActiveDirectoryMsi is supported.", -73, false }
|
||||
{ IMSSP, (SQLCHAR*) "Invalid option for the Authentication keyword. Only SqlPassword, ActiveDirectoryPassword, ActiveDirectoryMsi or ActiveDirectorySPA is supported.", -73, false }
|
||||
},
|
||||
{
|
||||
SQLSRV_ERROR_CE_DRIVER_REQUIRED,
|
||||
|
@ -465,7 +465,7 @@ pdo_error PDO_ERRORS[] = {
|
|||
{ UINT_MAX, {} }
|
||||
};
|
||||
|
||||
bool pdo_sqlsrv_handle_env_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning,
|
||||
bool pdo_sqlsrv_handle_env_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ int warning,
|
||||
_In_opt_ va_list* print_args )
|
||||
{
|
||||
SQLSRV_ASSERT((ctx != NULL), "pdo_sqlsrv_handle_env_error: sqlsrv_context was null");
|
||||
|
@ -488,7 +488,7 @@ bool pdo_sqlsrv_handle_env_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned
|
|||
}
|
||||
|
||||
// pdo error handler for the dbh context.
|
||||
bool pdo_sqlsrv_handle_dbh_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning,
|
||||
bool pdo_sqlsrv_handle_dbh_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ int warning,
|
||||
_In_opt_ va_list* print_args )
|
||||
{
|
||||
pdo_dbh_t* dbh = reinterpret_cast<pdo_dbh_t*>( ctx.driver());
|
||||
|
@ -520,7 +520,7 @@ bool pdo_sqlsrv_handle_dbh_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned
|
|||
}
|
||||
|
||||
// PDO error handler for the statement context.
|
||||
bool pdo_sqlsrv_handle_stmt_error(_Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning,
|
||||
bool pdo_sqlsrv_handle_stmt_error(_Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ int warning,
|
||||
_In_opt_ va_list* print_args)
|
||||
{
|
||||
pdo_stmt_t* pdo_stmt = reinterpret_cast<pdo_stmt_t*>(ctx.driver());
|
||||
|
@ -635,20 +635,9 @@ void add_remaining_errors_to_array (_In_ sqlsrv_error const* error, _Inout_ zval
|
|||
if (error->next != NULL && PDO_SQLSRV_G(report_additional_errors)) {
|
||||
sqlsrv_error *p = error->next;
|
||||
while (p != NULL) {
|
||||
// check if sql state or native message is NULL and handle them accordingly
|
||||
char *state = "";
|
||||
char *msg = "";
|
||||
|
||||
if (p->sqlstate != NULL) {
|
||||
state = reinterpret_cast<char*>(p->sqlstate);
|
||||
}
|
||||
if (p->native_message != NULL) {
|
||||
msg = reinterpret_cast<char*>(p->native_message);
|
||||
}
|
||||
|
||||
add_next_index_string(array_z, state);
|
||||
add_next_index_string(array_z, reinterpret_cast<char*>(p->sqlstate));
|
||||
add_next_index_long(array_z, p->native_code);
|
||||
add_next_index_string(array_z, msg);
|
||||
add_next_index_string(array_z, reinterpret_cast<char*>(p->native_message));
|
||||
|
||||
p = p-> next;
|
||||
}
|
||||
|
|
|
@ -285,11 +285,11 @@ struct pdo_error {
|
|||
// called when an error occurs in the core layer. These routines are set as the error_callback in a
|
||||
// context. The context is passed to this function since it contains the function
|
||||
|
||||
bool pdo_sqlsrv_handle_env_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning,
|
||||
bool pdo_sqlsrv_handle_env_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ int warning,
|
||||
_In_opt_ va_list* print_args );
|
||||
bool pdo_sqlsrv_handle_dbh_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning,
|
||||
bool pdo_sqlsrv_handle_dbh_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ int warning,
|
||||
_In_opt_ va_list* print_args );
|
||||
bool pdo_sqlsrv_handle_stmt_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ bool warning,
|
||||
bool pdo_sqlsrv_handle_stmt_error( _Inout_ sqlsrv_context& ctx, _In_opt_ unsigned int sqlsrv_error_code, _In_opt_ int warning,
|
||||
_In_opt_ va_list* print_args );
|
||||
|
||||
// common routine to transfer a sqlsrv_context's error to a PDO zval
|
||||
|
|
|
@ -709,18 +709,38 @@ bool core_is_conn_opt_value_escaped( _Inout_ const char* value, _Inout_ size_t v
|
|||
return true;
|
||||
}
|
||||
|
||||
// core_is_authentication_option_valid
|
||||
// if the option for the authentication is valid, returns true. This returns false otherwise.
|
||||
bool core_is_authentication_option_valid( _In_z_ const char* value, _In_ size_t value_len)
|
||||
{
|
||||
if (value_len <= 0)
|
||||
return false;
|
||||
namespace AzureADOptions {
|
||||
enum AAD_AUTH_TYPE {
|
||||
MIN_AAD_AUTH_TYPE = 0,
|
||||
SQL_PASSWORD = 0,
|
||||
AAD_PASSWORD,
|
||||
AAD_MSI,
|
||||
AAD_SPA,
|
||||
MAX_AAD_AUTH_TYPE
|
||||
};
|
||||
|
||||
if (!stricmp(value, AzureADOptions::AZURE_AUTH_SQL_PASSWORD) || !stricmp(value, AzureADOptions::AZURE_AUTH_AD_PASSWORD) || !stricmp(value, AzureADOptions::AZURE_AUTH_AD_MSI)) {
|
||||
return true;
|
||||
const char *AADAuths[] = { "SqlPassword", "ActiveDirectoryPassword", "ActiveDirectoryMsi", "ActiveDirectorySPA" };
|
||||
|
||||
bool isAuthValid(_In_z_ const char* value, _In_ size_t value_len)
|
||||
{
|
||||
if (value_len <= 0)
|
||||
return false;
|
||||
|
||||
bool isValid = false;
|
||||
for (short i = MIN_AAD_AUTH_TYPE; i < MAX_AAD_AUTH_TYPE && !isValid; i++)
|
||||
{
|
||||
if (!stricmp(value, AADAuths[i])) {
|
||||
isValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
return false;
|
||||
bool isAADMsi(_In_z_ const char* value)
|
||||
{
|
||||
return (value != NULL && !stricmp(value, AADAuths[AAD_MSI]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -789,9 +809,9 @@ void build_connection_string_and_set_conn_attr( _Inout_ sqlsrv_conn* conn, _Inou
|
|||
option = Z_STRVAL_P(auth_option);
|
||||
}
|
||||
|
||||
if (option != NULL && !stricmp(option, AzureADOptions::AZURE_AUTH_AD_MSI)) {
|
||||
activeDirectoryMSI = true;
|
||||
|
||||
//if (option != NULL && !stricmp(option, AzureADOptions::AZURE_AUTH_AD_MSI)) {
|
||||
activeDirectoryMSI = AzureADOptions::isAADMsi(option);
|
||||
if (activeDirectoryMSI) {
|
||||
// There are two types of managed identities:
|
||||
// (1) A system-assigned managed identity: UID must be NULL
|
||||
// (2) A user-assigned managed identity: UID defined but must not be an empty string
|
||||
|
|
|
@ -882,7 +882,7 @@ SQLRETURN binary_to_string( _Inout_ SQLCHAR* field_data, _Inout_ SQLLEN& read_so
|
|||
_In_ SQLLEN buffer_length, _Inout_ SQLLEN* out_buffer_length,
|
||||
_Inout_ sqlsrv_error_auto_ptr& out_error )
|
||||
{
|
||||
// hex characters for the conversion loop below
|
||||
// The hex characters for the conversion loop below
|
||||
static char hex_chars[] = "0123456789ABCDEF";
|
||||
|
||||
SQLSRV_ASSERT( out_error == 0, "Pending error for sqlsrv_buffered_results_set::binary_to_string" );
|
||||
|
@ -892,17 +892,19 @@ SQLRETURN binary_to_string( _Inout_ SQLCHAR* field_data, _Inout_ SQLLEN& read_so
|
|||
// Set the amount of space necessary for null characters at the end of the data.
|
||||
SQLSMALLINT extra = sizeof(Char);
|
||||
|
||||
SQLSRV_ASSERT( ((buffer_length - extra) % (extra * 2)) == 0, "Must be multiple of 2 for binary to system string or "
|
||||
"multiple of 4 for binary to wide string" );
|
||||
// TO convert a binary to a system string or a binary to a wide string, the buffer size minus
|
||||
// 'extra' is ideally multiples of 2 or 4 (depending on Char), but calculating to_copy_hex below
|
||||
// takes care of this.
|
||||
|
||||
// all fields will be treated as ODBC returns varchar(max) fields:
|
||||
// All fields will be treated as ODBC returns varchar(max) fields:
|
||||
// the entire length of the string is returned the first
|
||||
// call in out_buffer_len. Successive calls return how much is
|
||||
// left minus how much has already been read by previous reads
|
||||
// *2 is for each byte to hex conversion and * extra is for either system or wide string allocation
|
||||
// *2 is for each byte to hex conversion and * extra is for either system
|
||||
// or wide string allocation
|
||||
*out_buffer_length = (*reinterpret_cast<SQLLEN*>( field_data - sizeof( SQLULEN )) - read_so_far) * 2 * extra;
|
||||
|
||||
// copy as much as we can into the buffer
|
||||
// Will copy as much as we can into the buffer
|
||||
SQLLEN to_copy;
|
||||
if( buffer_length < *out_buffer_length + extra ) {
|
||||
to_copy = (buffer_length - extra);
|
||||
|
@ -915,14 +917,14 @@ SQLRETURN binary_to_string( _Inout_ SQLCHAR* field_data, _Inout_ SQLLEN& read_so
|
|||
to_copy = *out_buffer_length;
|
||||
}
|
||||
|
||||
// if there are bytes to copy as hex
|
||||
// If there are bytes to copy as hex
|
||||
if( to_copy > 0 ) {
|
||||
// quick hex conversion routine
|
||||
Char* h = reinterpret_cast<Char*>( buffer );
|
||||
BYTE* b = reinterpret_cast<BYTE*>( field_data );
|
||||
Char* h = reinterpret_cast<Char*>(buffer);
|
||||
BYTE* b = reinterpret_cast<BYTE*>(field_data + read_so_far);
|
||||
// to_copy contains the number of bytes to copy, so we divide the number in half (or quarter)
|
||||
// to get the number of hex digits we can copy
|
||||
SQLLEN to_copy_hex = to_copy / (2 * extra);
|
||||
// to get the maximum number of hex digits to copy
|
||||
SQLLEN to_copy_hex = static_cast<SQLLEN>(floor(to_copy / (2 * extra)));
|
||||
for( SQLLEN i = 0; i < to_copy_hex; ++i ) {
|
||||
*h = hex_chars[(*b & 0xf0) >> 4];
|
||||
h++;
|
||||
|
@ -930,7 +932,7 @@ SQLRETURN binary_to_string( _Inout_ SQLCHAR* field_data, _Inout_ SQLLEN& read_so
|
|||
h++;
|
||||
}
|
||||
read_so_far += to_copy_hex;
|
||||
*h = static_cast<Char>( 0 );
|
||||
*h = static_cast<Char>(0);
|
||||
}
|
||||
else {
|
||||
reinterpret_cast<char*>( buffer )[0] = '\0';
|
||||
|
@ -1066,7 +1068,7 @@ SQLRETURN sqlsrv_buffered_result_set::string_to_double( _In_ SQLSMALLINT field_i
|
|||
double* number_data = reinterpret_cast<double*>(buffer);
|
||||
try {
|
||||
*number_data = std::stod(std::string(string_data));
|
||||
} catch (const std::logic_error& err) {
|
||||
} catch (const std::logic_error& ) {
|
||||
last_error = new (sqlsrv_malloc(sizeof(sqlsrv_error))) sqlsrv_error((SQLCHAR*) "22003", (SQLCHAR*) "Numeric value out of range", 103);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
@ -1091,7 +1093,7 @@ SQLRETURN sqlsrv_buffered_result_set::wstring_to_double( _In_ SQLSMALLINT field_
|
|||
#else
|
||||
*number_data = std::stod(getUTF8StringFromString(string_data));
|
||||
#endif // _WIN32
|
||||
} catch (const std::logic_error& err) {
|
||||
} catch (const std::logic_error& ) {
|
||||
last_error = new (sqlsrv_malloc(sizeof(sqlsrv_error))) sqlsrv_error((SQLCHAR*) "22003", (SQLCHAR*) "Numeric value out of range", 103);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
@ -1112,7 +1114,7 @@ SQLRETURN sqlsrv_buffered_result_set::string_to_long( _In_ SQLSMALLINT field_ind
|
|||
LONG* number_data = reinterpret_cast<LONG*>(buffer);
|
||||
try {
|
||||
*number_data = std::stol(std::string(string_data));
|
||||
} catch (const std::logic_error& err) {
|
||||
} catch (const std::logic_error& ) {
|
||||
last_error = new (sqlsrv_malloc(sizeof(sqlsrv_error))) sqlsrv_error((SQLCHAR*) "22003", (SQLCHAR*) "Numeric value out of range", 103);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
@ -1137,7 +1139,7 @@ SQLRETURN sqlsrv_buffered_result_set::wstring_to_long( _In_ SQLSMALLINT field_in
|
|||
#else
|
||||
*number_data = std::stol(getUTF8StringFromString(string_data));
|
||||
#endif // _WIN32
|
||||
} catch (const std::logic_error& err) {
|
||||
} catch (const std::logic_error& ) {
|
||||
last_error = new (sqlsrv_malloc(sizeof(sqlsrv_error))) sqlsrv_error((SQLCHAR*) "22003", (SQLCHAR*) "Numeric value out of range", 103);
|
||||
return SQL_ERROR;
|
||||
}
|
||||
|
|
|
@ -191,9 +191,8 @@ const int SQL_SERVER_2008_DEFAULT_DATETIME_PRECISION = 34;
|
|||
const int SQL_SERVER_2008_DEFAULT_DATETIME_SCALE = 7;
|
||||
|
||||
namespace AzureADOptions {
|
||||
const char AZURE_AUTH_SQL_PASSWORD[] = "SqlPassword";
|
||||
const char AZURE_AUTH_AD_PASSWORD[] = "ActiveDirectoryPassword";
|
||||
const char AZURE_AUTH_AD_MSI[] = "ActiveDirectoryMsi";
|
||||
bool isAuthValid(_In_z_ const char* value, _In_ size_t value_len);
|
||||
bool isAADMsi(_In_z_ const char* value);
|
||||
}
|
||||
|
||||
// the message returned by ODBC Driver for SQL Server
|
||||
|
@ -877,7 +876,7 @@ struct sqlsrv_conn;
|
|||
// a driver specific callback for processing errors.
|
||||
// ctx - the context holding the handles
|
||||
// sqlsrv_error_code - specific error code to return.
|
||||
typedef bool (*error_callback)( _Inout_ sqlsrv_context& ctx, _In_ unsigned int sqlsrv_error_code, _In_ bool error, _In_opt_ va_list* print_args );
|
||||
typedef bool (*error_callback)( _Inout_ sqlsrv_context& ctx, _In_ unsigned int sqlsrv_error_code, _In_ int error, _In_opt_ va_list* print_args );
|
||||
|
||||
// sqlsrv_context
|
||||
// a context holds relevant information to be passed with a connection and statement objects.
|
||||
|
@ -1288,7 +1287,6 @@ void core_sqlsrv_get_server_version( _Inout_ sqlsrv_conn* conn, _Inout_ zval *se
|
|||
void core_sqlsrv_get_client_info( _Inout_ sqlsrv_conn* conn, _Out_ zval *client_info );
|
||||
bool core_is_conn_opt_value_escaped( _Inout_ const char* value, _Inout_ size_t value_len );
|
||||
size_t core_str_zval_is_true( _Inout_ zval* str_zval );
|
||||
bool core_is_authentication_option_valid( _In_z_ const char* value, _In_ size_t value_len );
|
||||
bool core_search_odbc_driver_unix( _In_ DRIVER_VERSION driver_version );
|
||||
bool core_compare_error_state( _In_ sqlsrv_conn* conn, _In_ SQLRETURN r, _In_ const char* error_state );
|
||||
|
||||
|
@ -1933,7 +1931,7 @@ DWORD core_sqlsrv_format_message( _Out_ char* output_buffer, _In_ unsigned outpu
|
|||
|
||||
// convenience functions that overload either a reference or a pointer so we can use
|
||||
// either in the CHECK_* functions.
|
||||
inline bool call_error_handler( _Inout_ sqlsrv_context& ctx, _In_ unsigned long sqlsrv_error_code, _In_ bool warning, ... )
|
||||
inline bool call_error_handler( _Inout_ sqlsrv_context& ctx, _In_ unsigned long sqlsrv_error_code, _In_ int warning, ... )
|
||||
{
|
||||
va_list print_params;
|
||||
va_start( print_params, warning );
|
||||
|
@ -1942,7 +1940,7 @@ inline bool call_error_handler( _Inout_ sqlsrv_context& ctx, _In_ unsigned long
|
|||
return ignored;
|
||||
}
|
||||
|
||||
inline bool call_error_handler( _Inout_ sqlsrv_context* ctx, _In_ unsigned long sqlsrv_error_code, _In_ bool warning, ... )
|
||||
inline bool call_error_handler( _Inout_ sqlsrv_context* ctx, _In_ unsigned long sqlsrv_error_code, _In_ int warning, ... )
|
||||
{
|
||||
va_list print_params;
|
||||
va_start( print_params, warning );
|
||||
|
@ -1987,7 +1985,7 @@ inline bool is_truncated_warning( _In_ SQLCHAR* state )
|
|||
bool flag##unique = (condition); \
|
||||
bool ignored##unique = true; \
|
||||
if (flag##unique) { \
|
||||
ignored##unique = call_error_handler( context, ssphp, /*warning*/false, ## __VA_ARGS__ ); \
|
||||
ignored##unique = call_error_handler( context, ssphp, /*warning*/0, ## __VA_ARGS__ ); \
|
||||
} \
|
||||
if( !ignored##unique )
|
||||
|
||||
|
@ -2007,7 +2005,7 @@ inline bool is_truncated_warning( _In_ SQLCHAR* state )
|
|||
#define CHECK_WARNING_AS_ERROR_UNIQUE( unique, condition, context, ssphp, ... ) \
|
||||
bool ignored##unique = true; \
|
||||
if( condition ) { \
|
||||
ignored##unique = call_error_handler( context, ssphp, /*warning*/true, ## __VA_ARGS__ ); \
|
||||
ignored##unique = call_error_handler( context, ssphp, /*warning*/1, ## __VA_ARGS__ ); \
|
||||
} \
|
||||
if( !ignored##unique )
|
||||
|
||||
|
@ -2016,7 +2014,7 @@ inline bool is_truncated_warning( _In_ SQLCHAR* state )
|
|||
|
||||
#define CHECK_SQL_WARNING( result, context, ... ) \
|
||||
if( result == SQL_SUCCESS_WITH_INFO ) { \
|
||||
(void)call_error_handler( context, 0, /*warning*/ true, ## __VA_ARGS__ ); \
|
||||
(void)call_error_handler( context, 0, /*warning*/1, ## __VA_ARGS__ ); \
|
||||
}
|
||||
|
||||
#define CHECK_CUSTOM_WARNING_AS_ERROR( condition, context, ssphp, ... ) \
|
||||
|
@ -2029,16 +2027,16 @@ inline bool is_truncated_warning( _In_ SQLCHAR* state )
|
|||
SQLSRV_ASSERT( result != SQL_INVALID_HANDLE, "Invalid handle returned." ); \
|
||||
bool ignored = true; \
|
||||
if( result == SQL_ERROR ) { \
|
||||
ignored = call_error_handler( context, SQLSRV_ERROR_ODBC, false, ##__VA_ARGS__ ); \
|
||||
ignored = call_error_handler( context, SQLSRV_ERROR_ODBC, 0, ##__VA_ARGS__ ); \
|
||||
} \
|
||||
else if( result == SQL_SUCCESS_WITH_INFO ) { \
|
||||
ignored = call_error_handler( context, SQLSRV_ERROR_ODBC, true, ##__VA_ARGS__ ); \
|
||||
ignored = call_error_handler( context, SQLSRV_ERROR_ODBC, 1, ##__VA_ARGS__ ); \
|
||||
} \
|
||||
if( !ignored )
|
||||
|
||||
// throw an exception after it has been hooked into the custom error handler
|
||||
#define THROW_CORE_ERROR( ctx, custom, ... ) \
|
||||
(void)call_error_handler( ctx, custom, /*warning*/ false, ## __VA_ARGS__ ); \
|
||||
(void)call_error_handler( ctx, custom, /*warning*/0, ## __VA_ARGS__ ); \
|
||||
throw core::CoreException();
|
||||
|
||||
//*********************************************************************************************************************************
|
||||
|
|
|
@ -110,7 +110,7 @@ void default_sql_type( _Inout_ sqlsrv_stmt* stmt, _In_opt_ SQLULEN paramno, _In_
|
|||
_Out_ SQLSMALLINT& sql_type );
|
||||
void col_cache_dtor( _Inout_ zval* data_z );
|
||||
void field_cache_dtor( _Inout_ zval* data_z );
|
||||
int round_up_decimal_numbers(_Inout_ char* buffer, _In_ short decimal_pos, _In_ short decimals_places, _In_ short offset, _In_ short lastpos);
|
||||
int round_up_decimal_numbers(_Inout_ char* buffer, _In_ int decimal_pos, _In_ int decimals_places, _In_ int offset, _In_ int lastpos);
|
||||
void format_decimal_numbers(_In_ SQLSMALLINT decimals_places, _In_ SQLSMALLINT field_scale, _Inout_updates_bytes_(*field_len) char*& field_value, _Inout_ SQLLEN* field_len);
|
||||
void finalize_output_parameters( _Inout_ sqlsrv_stmt* stmt, _In_opt_ bool exception_thrown = false );
|
||||
void get_field_as_string( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, _Inout_ sqlsrv_phptype sqlsrv_php_type,
|
||||
|
@ -2355,8 +2355,8 @@ void format_decimal_numbers(_In_ SQLSMALLINT decimals_places, _In_ SQLSMALLINT f
|
|||
}
|
||||
|
||||
char buffer[50] = " "; // A buffer with two blank spaces, as leeway
|
||||
short offset = 1 + is_negative;
|
||||
short src_length = strlen(src);
|
||||
int offset = 1 + is_negative;
|
||||
int src_length = strlen(src);
|
||||
|
||||
if (add_leading_zero) {
|
||||
buffer[offset++] = '0';
|
||||
|
@ -2368,7 +2368,7 @@ void format_decimal_numbers(_In_ SQLSMALLINT decimals_places, _In_ SQLSMALLINT f
|
|||
|
||||
// If no need to adjust decimal places, skip formatting
|
||||
if (decimals_places != NO_CHANGE_DECIMAL_PLACES) {
|
||||
short num_decimals = src_length - (pt - src) - 1;
|
||||
int num_decimals = src_length - (pt - src) - 1;
|
||||
|
||||
if (num_decimals > scale) {
|
||||
last_pos = round_up_decimal_numbers(buffer, (pt - src) + offset, scale, offset, last_pos);
|
||||
|
@ -2385,7 +2385,7 @@ void format_decimal_numbers(_In_ SQLSMALLINT decimals_places, _In_ SQLSMALLINT f
|
|||
buffer[--offset] = '-';
|
||||
}
|
||||
|
||||
short len = last_pos - offset;
|
||||
int len = last_pos - offset;
|
||||
memcpy_s(field_value, len, buffer + offset, len);
|
||||
field_value[len] = '\0';
|
||||
*field_len = len;
|
||||
|
@ -3007,7 +3007,7 @@ void sqlsrv_stream_dtor( _Inout_ zval* data )
|
|||
void adjustDecimalPrecision(_Inout_ zval* param_z, _In_ SQLSMALLINT decimal_digits)
|
||||
{
|
||||
char* value = Z_STRVAL_P(param_z);
|
||||
short value_len = Z_STRLEN_P(param_z);
|
||||
int value_len = Z_STRLEN_P(param_z);
|
||||
|
||||
// If the length is greater than maxDecimalStrLen, do not convert the string
|
||||
// 6 is derived from: 1 for the decimal point; 1 for sign of the number; 1 for 'e' or 'E' (scientific notation);
|
||||
|
@ -3023,7 +3023,7 @@ void adjustDecimalPrecision(_Inout_ zval* param_z, _In_ SQLSMALLINT decimal_digi
|
|||
try {
|
||||
d = std::stold(std::string(value), &idx);
|
||||
}
|
||||
catch (const std::logic_error& err) {
|
||||
catch (const std::logic_error& ) {
|
||||
return; // invalid input caused the conversion to throw an exception
|
||||
}
|
||||
if (idx < value_len) {
|
||||
|
@ -3047,15 +3047,15 @@ void adjustDecimalPrecision(_Inout_ zval* param_z, _In_ SQLSMALLINT decimal_digi
|
|||
char *pt = strchr(src, DECIMAL_POINT);
|
||||
|
||||
char buffer[50] = " "; // A buffer with 2 blank spaces, as leeway
|
||||
short offset = 1 + is_negative; // The position to start copying the original numerical value
|
||||
int offset = 1 + is_negative; // The position to start copying the original numerical value
|
||||
|
||||
if (exp == NULL) {
|
||||
if (pt == NULL) {
|
||||
return; // decimal point not found
|
||||
}
|
||||
|
||||
short src_length = strlen(src);
|
||||
short num_decimals = src_length - (pt - src) - 1;
|
||||
int src_length = strlen(src);
|
||||
int num_decimals = src_length - (pt - src) - 1;
|
||||
if (num_decimals <= decimal_digits) {
|
||||
return; // no need to adjust number of decimals
|
||||
}
|
||||
|
@ -3069,10 +3069,10 @@ void adjustDecimalPrecision(_Inout_ zval* param_z, _In_ SQLSMALLINT decimal_digi
|
|||
return; // Out of range, so let the server handle this
|
||||
}
|
||||
|
||||
short num_decimals = 0;
|
||||
int num_decimals = 0;
|
||||
if (power == 0) {
|
||||
// Simply chop off the exp part
|
||||
short length = (exp - src);
|
||||
int length = (exp - src);
|
||||
memcpy_s(buffer + offset, length, src, length);
|
||||
|
||||
if (pt != NULL) {
|
||||
|
@ -3083,7 +3083,7 @@ void adjustDecimalPrecision(_Inout_ zval* param_z, _In_ SQLSMALLINT decimal_digi
|
|||
}
|
||||
}
|
||||
} else {
|
||||
short oldpos = 0;
|
||||
int oldpos = 0;
|
||||
if (pt == NULL) {
|
||||
oldpos = exp - src; // Decimal point not found, use the exp sign
|
||||
}
|
||||
|
@ -3096,7 +3096,7 @@ void adjustDecimalPrecision(_Inout_ zval* param_z, _In_ SQLSMALLINT decimal_digi
|
|||
}
|
||||
|
||||
// Derive the new position for the decimal point in the buffer
|
||||
short newpos = oldpos + power;
|
||||
int newpos = oldpos + power;
|
||||
if (power > 0) {
|
||||
newpos = newpos + offset;
|
||||
if (num_decimals == 0) {
|
||||
|
@ -3125,8 +3125,8 @@ void adjustDecimalPrecision(_Inout_ zval* param_z, _In_ SQLSMALLINT decimal_digi
|
|||
|
||||
// Start copying the content to the buffer until the exp sign or one more digit after decimal_digits
|
||||
char *p = src;
|
||||
short idx = offset;
|
||||
short lastpos = newpos + decimal_digits + 1;
|
||||
int idx = offset;
|
||||
int lastpos = newpos + decimal_digits + 1;
|
||||
while (p != exp && idx <= lastpos) {
|
||||
if (*p == DECIMAL_POINT) {
|
||||
p++;
|
||||
|
@ -3156,14 +3156,14 @@ void adjustDecimalPrecision(_Inout_ zval* param_z, _In_ SQLSMALLINT decimal_digi
|
|||
ZVAL_NEW_STR(param_z, zstr);
|
||||
}
|
||||
|
||||
int round_up_decimal_numbers(_Inout_ char* buffer, _In_ short decimal_pos, _In_ short num_decimals, _In_ short offset, _In_ short lastpos)
|
||||
int round_up_decimal_numbers(_Inout_ char* buffer, _In_ int decimal_pos, _In_ int num_decimals, _In_ int offset, _In_ int lastpos)
|
||||
{
|
||||
// This helper method assumes the 'buffer' has some extra blank spaces at the beginning without the minus '-' sign.
|
||||
// We want the rounding to be consistent with php number_format(), http://php.net/manual/en/function.number-format.php
|
||||
// as well as SQL Server Management studio, such that the least significant digit will be rounded up if it is
|
||||
// followed by 5 or above.
|
||||
|
||||
short pos = decimal_pos + num_decimals + 1;
|
||||
int pos = decimal_pos + num_decimals + 1;
|
||||
if (pos < lastpos) {
|
||||
short n = buffer[pos] - '0';
|
||||
if (n >= 5) {
|
||||
|
|
|
@ -101,13 +101,18 @@ size_t sqlsrv_stream_read(_Inout_ php_stream* stream, _Out_writes_bytes_(count)
|
|||
throw core::CoreException();
|
||||
}
|
||||
|
||||
// if the stream returns either no data, NULL data, or returns data < than the count requested then
|
||||
// we are at the "end of the stream" so we mark it
|
||||
if( r == SQL_NO_DATA || read == SQL_NULL_DATA || ( static_cast<size_t>( read ) <= count && read != SQL_NO_TOTAL )) {
|
||||
// If the stream returns no data or NULL data, mark the "end of the stream" and return
|
||||
if( r == SQL_NO_DATA || read == SQL_NULL_DATA) {
|
||||
stream->eof = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If the stream returns data less than the count requested then we are at the "end of the stream" but continue processing
|
||||
if (static_cast<size_t>(read) <= count && read != SQL_NO_TOTAL) {
|
||||
stream->eof = 1;
|
||||
}
|
||||
|
||||
// if ODBC returns the 01004 (truncated string) warning, then we return the count minus the null terminator
|
||||
// If ODBC returns the 01004 (truncated string) warning, then we return the count minus the null terminator
|
||||
// if it's not a binary encoded field
|
||||
if( r == SQL_SUCCESS_WITH_INFO ) {
|
||||
|
||||
|
@ -120,26 +125,42 @@ size_t sqlsrv_stream_read(_Inout_ php_stream* stream, _Out_writes_bytes_(count)
|
|||
SQLSRV_ASSERT( is_truncated_warning( state ), "sqlsrv_stream_read: truncation warning was expected but it "
|
||||
"did not occur." );
|
||||
}
|
||||
|
||||
// with unixODBC connection pooling enabled the truncated state may not be returned so check the actual length read
|
||||
// with buffer length.
|
||||
|
||||
// As per SQLGetData documentation, if the length of character data exceeds the BufferLength,
|
||||
// SQLGetData truncates the data to BufferLength less the length of null-termination character.
|
||||
// But when fetching binary fields as chars (wide chars), each byte is represented as 2 hex characters,
|
||||
// each takes the size of a char (wide char). Note that BufferLength may not be multiples of 2 or 4.
|
||||
bool is_binary = (ss->sql_type == SQL_BINARY || ss->sql_type == SQL_VARBINARY || ss->sql_type == SQL_LONGVARBINARY);
|
||||
|
||||
// With unixODBC connection pooling enabled the truncated state may not be returned so check the actual length read
|
||||
// with buffer length.
|
||||
#ifndef _WIN32
|
||||
if( is_truncated_warning( state ) || count < read) {
|
||||
#else
|
||||
if( is_truncated_warning( state ) ) {
|
||||
#endif // !_WIN32
|
||||
size_t char_size = sizeof(SQLCHAR);
|
||||
|
||||
switch( c_type ) {
|
||||
|
||||
// As per SQLGetData documentation, if the length of character data exceeds the BufferLength,
|
||||
// SQLGetData truncates the data to BufferLength less the length of null-termination character.
|
||||
case SQL_C_BINARY:
|
||||
read = count;
|
||||
break;
|
||||
case SQL_C_WCHAR:
|
||||
read = ( count % 2 == 0 ? count - 2 : count - 3 );
|
||||
char_size = sizeof(SQLWCHAR);
|
||||
if (is_binary) {
|
||||
// Each binary byte read will be 2 hex wide chars in the buffer
|
||||
SQLLEN num_bytes_read = static_cast<SQLLEN>(floor((count - char_size) / (2 * char_size)));
|
||||
read = num_bytes_read * char_size * 2 ;
|
||||
} else {
|
||||
read = (count % 2 == 0 ? count - 2 : count - 3);
|
||||
}
|
||||
break;
|
||||
case SQL_C_CHAR:
|
||||
read = count - 1;
|
||||
if (is_binary) {
|
||||
read = ((count - char_size) % 2 == 0 ? count - char_size : count - char_size - 1);
|
||||
} else {
|
||||
read = count - 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DIE( "sqlsrv_stream_read: should have never reached in this switch case.");
|
||||
|
@ -151,10 +172,10 @@ size_t sqlsrv_stream_read(_Inout_ php_stream* stream, _Out_writes_bytes_(count)
|
|||
}
|
||||
}
|
||||
|
||||
// if the encoding is UTF-8
|
||||
// If the encoding is UTF-8
|
||||
if( c_type == SQL_C_WCHAR ) {
|
||||
count *= 2;
|
||||
// undo the shift to use the full buffer
|
||||
// Undo the shift to use the full buffer
|
||||
// flags set to 0 by default, which means that any invalid characters are dropped rather than causing
|
||||
// an error. This happens only on XP.
|
||||
// convert to UTF-8
|
||||
|
|
|
@ -469,7 +469,7 @@ size_t SystemLocale::Utf8To16( const char *src, SSIZE_T cchSrc, WCHAR *dest, siz
|
|||
}
|
||||
usrc++;
|
||||
ucode = (ucode&15)<<12 | (c1&0x3F)<<6 | (c2&0x3F);
|
||||
if (ucode < 0x800 || ucode >= 0xD800 && ucode <= 0xDFFF)
|
||||
if (ucode < 0x800 || (ucode >= 0xD800 && ucode <= 0xDFFF))
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
|
@ -511,7 +511,7 @@ size_t SystemLocale::Utf8To16( const char *src, SSIZE_T cchSrc, WCHAR *dest, siz
|
|||
|
||||
if (ucode < 0x10000 // overlong encoding
|
||||
|| ucode > 0x10FFFF // exceeds Unicode range
|
||||
|| ucode >= 0xD800 && ucode <= 0xDFFF) // surrogate pairs
|
||||
|| (ucode >= 0xD800 && ucode <= 0xDFFF)) // surrogate pairs
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
|
@ -594,7 +594,7 @@ size_t SystemLocale::Utf8To16Strict( const char *src, SSIZE_T cchSrc, WCHAR *des
|
|||
}
|
||||
usrc++;
|
||||
ucode = (ucode&15)<<12 | (c1&0x3F)<<6 | (c2&0x3F);
|
||||
if (ucode < 0x800 || ucode >= 0xD800 && ucode <= 0xDFFF)
|
||||
if (ucode < 0x800 || (ucode >= 0xD800 && ucode <= 0xDFFF))
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
|
@ -636,7 +636,7 @@ size_t SystemLocale::Utf8To16Strict( const char *src, SSIZE_T cchSrc, WCHAR *des
|
|||
|
||||
if (ucode < 0x10000 // overlong encoding
|
||||
|| ucode > 0x10FFFF // exceeds Unicode range
|
||||
|| ucode >= 0xD800 && ucode <= 0xDFFF) // surrogate pairs
|
||||
|| (ucode >= 0xD800 && ucode <= 0xDFFF)) // surrogate pairs
|
||||
{
|
||||
goto Invalid;
|
||||
}
|
||||
|
@ -794,7 +794,7 @@ size_t SystemLocale::Utf8From16( const WCHAR *src, SSIZE_T cchSrc, char *dest, s
|
|||
return 0;
|
||||
}
|
||||
*dest++ = 0xE0 | (wch >> 12);
|
||||
*dest++ = 0x80 | (wch >> 6)&0x3F;
|
||||
*dest++ = 0x80 | ((wch >> 6)&0x3F);
|
||||
*dest++ = 0x80 | (wch &0x3F);
|
||||
}
|
||||
else if (wch < 0xDC00) // 65536 to end of Unicode: 4 bytes
|
||||
|
@ -832,9 +832,9 @@ size_t SystemLocale::Utf8From16( const WCHAR *src, SSIZE_T cchSrc, char *dest, s
|
|||
return 0;
|
||||
}
|
||||
*dest++ = 0xF0 | (wch >> 18);
|
||||
*dest++ = 0x80 | (wch >>12)&0x3F;
|
||||
*dest++ = 0x80 | (wch >> 6)&0x3F;
|
||||
*dest++ = 0x80 | wch&0x3F;
|
||||
*dest++ = 0x80 | ((wch >>12)&0x3F);
|
||||
*dest++ = 0x80 | ((wch >> 6)&0x3F);
|
||||
*dest++ = 0x80 | (wch&0x3F);
|
||||
}
|
||||
else // unexpected trail surrogate
|
||||
{
|
||||
|
@ -933,7 +933,7 @@ size_t SystemLocale::Utf8From16Strict( const WCHAR *src, SSIZE_T cchSrc, char *d
|
|||
return 0;
|
||||
}
|
||||
*dest++ = 0xE0 | (wch >> 12);
|
||||
*dest++ = 0x80 | (wch >> 6)&0x3F;
|
||||
*dest++ = 0x80 | ((wch >> 6)&0x3F);
|
||||
*dest++ = 0x80 | (wch &0x3F);
|
||||
}
|
||||
else if (wch < 0xDC00) // 65536 to end of Unicode: 4 bytes
|
||||
|
@ -964,9 +964,9 @@ size_t SystemLocale::Utf8From16Strict( const WCHAR *src, SSIZE_T cchSrc, char *d
|
|||
return 0;
|
||||
}
|
||||
*dest++ = 0xF0 | (wch >> 18);
|
||||
*dest++ = 0x80 | (wch >>12)&0x3F;
|
||||
*dest++ = 0x80 | (wch >> 6)&0x3F;
|
||||
*dest++ = 0x80 | wch&0x3F;
|
||||
*dest++ = 0x80 | ((wch >>12)&0x3F);
|
||||
*dest++ = 0x80 | ((wch >> 6)&0x3F);
|
||||
*dest++ = 0x80 | (wch&0x3F);
|
||||
}
|
||||
else // unexpected trail surrogate
|
||||
{
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#define SQLVERSION_BUILD 0
|
||||
|
||||
// For previews, set this constant to 1, 2 and so on. Otherwise, set it to 0
|
||||
#define PREVIEW 1
|
||||
#define PREVIEW 2
|
||||
#define SEMVER_PRERELEASE
|
||||
|
||||
// Semantic versioning build metadata, build meta data is not counted in precedence order.
|
||||
|
@ -52,7 +52,7 @@
|
|||
// "preview" for ETP
|
||||
#if PREVIEW > 0
|
||||
#undef SEMVER_PRERELEASE
|
||||
#define SEMVER_PRERELEASE "preview" STRINGIFY(PREVIEW)
|
||||
#define SEMVER_PRERELEASE "beta" STRINGIFY(PREVIEW)
|
||||
#define VER_FILEVERSION_STR VER_APIVERSION_STR "-" SEMVER_PRERELEASE SEMVER_BUILDMETA
|
||||
#else
|
||||
#define VER_FILEVERSION_STR VER_APIVERSION_STR SEMVER_PRERELEASE SEMVER_BUILDMETA
|
||||
|
@ -61,7 +61,7 @@
|
|||
#define _FILEVERSION SQLVERSION_MAJOR,SQLVERSION_MINOR,SQLVERSION_PATCH,SQLVERSION_BUILD
|
||||
|
||||
// PECL package version macros ('-' or '+' is not allowed)
|
||||
#define PHP_SQLSRV_VERSION VER_APIVERSION_STR SEMVER_PRERELEASE
|
||||
#define PHP_PDO_SQLSRV_VERSION PHP_SQLSRV_VERSION
|
||||
#define PHP_SQLSRV_VERSION "5.9.0beta2"
|
||||
#define PHP_PDO_SQLSRV_VERSION "5.9.0beta2"
|
||||
|
||||
#endif // VERSION_H
|
||||
|
|
|
@ -59,7 +59,6 @@ if test "$PHP_SQLSRV" != "no"; then
|
|||
HOST_OS_ARCH=`uname`
|
||||
if test "${HOST_OS_ARCH}" = "Darwin"; then
|
||||
SQLSRV_SHARED_LIBADD="$SQLSRV_SHARED_LIBADD -Wl,-bind_at_load"
|
||||
MACOSX_DEPLOYMENT_TARGET=`sw_vers -productVersion`
|
||||
else
|
||||
SQLSRV_SHARED_LIBADD="$SQLSRV_SHARED_LIBADD -Wl,-z,now"
|
||||
IS_ALPINE_1=`uname -a | cut -f 4 -d ' ' | cut -f 2 -d '-'`
|
||||
|
|
|
@ -1383,7 +1383,7 @@ int get_conn_option_key( _Inout_ sqlsrv_context& ctx, _In_ zend_string* key, _In
|
|||
|
||||
bool valid = true;
|
||||
if( stricmp( SS_CONN_OPTS[i].sqlsrv_name, SSConnOptionNames::Authentication ) == 0 ) {
|
||||
valid = core_is_authentication_option_valid( value, value_len );
|
||||
valid = AzureADOptions::isAuthValid(value, value_len);
|
||||
}
|
||||
|
||||
CHECK_CUSTOM_ERROR( !valid, ctx, SS_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION, SS_CONN_OPTS[i].sqlsrv_name ) {
|
||||
|
@ -1393,7 +1393,10 @@ int get_conn_option_key( _Inout_ sqlsrv_context& ctx, _In_ zend_string* key, _In
|
|||
|
||||
break;
|
||||
}
|
||||
}
|
||||
case CONN_ATTR_INVALID:
|
||||
SQLSRV_ASSERT(false, "Should not have reached CONN_ATTR_INVALID.");
|
||||
break;
|
||||
}
|
||||
|
||||
return SS_CONN_OPTS[i].conn_option_key;
|
||||
}
|
||||
|
|
|
@ -271,7 +271,7 @@ zend_module_entry g_sqlsrv_module_entry =
|
|||
|
||||
PHP_MINIT_FUNCTION(sqlsrv)
|
||||
{
|
||||
SQLSRV_UNUSED( type );
|
||||
// SQLSRV_UNUSED( type );
|
||||
|
||||
core_sqlsrv_register_severity_checker(ss_severity_check);
|
||||
|
||||
|
@ -596,7 +596,7 @@ void sqlsrv_encoding_dtor( _Inout_ zval* elem ) {
|
|||
|
||||
PHP_MSHUTDOWN_FUNCTION(sqlsrv)
|
||||
{
|
||||
SQLSRV_UNUSED( type );
|
||||
// SQLSRV_UNUSED( type );
|
||||
|
||||
UNREGISTER_INI_ENTRIES();
|
||||
|
||||
|
@ -630,8 +630,8 @@ PHP_MSHUTDOWN_FUNCTION(sqlsrv)
|
|||
|
||||
PHP_RINIT_FUNCTION(sqlsrv)
|
||||
{
|
||||
SQLSRV_UNUSED( module_number );
|
||||
SQLSRV_UNUSED( type );
|
||||
// SQLSRV_UNUSED( module_number );
|
||||
// SQLSRV_UNUSED( type );
|
||||
|
||||
#if defined(ZTS)
|
||||
ZEND_TSRMLS_CACHE_UPDATE();
|
||||
|
@ -690,8 +690,8 @@ PHP_RINIT_FUNCTION(sqlsrv)
|
|||
|
||||
PHP_RSHUTDOWN_FUNCTION(sqlsrv)
|
||||
{
|
||||
SQLSRV_UNUSED( module_number );
|
||||
SQLSRV_UNUSED( type );
|
||||
// SQLSRV_UNUSED( module_number );
|
||||
// SQLSRV_UNUSED( type );
|
||||
|
||||
LOG_FUNCTION( "PHP_RSHUTDOWN for php_sqlsrv" );
|
||||
reset_errors();
|
||||
|
|
|
@ -212,7 +212,7 @@ enum SS_ERROR_CODES {
|
|||
|
||||
extern ss_error SS_ERRORS[];
|
||||
|
||||
bool ss_error_handler( _Inout_ sqlsrv_context& ctx, _In_ unsigned int sqlsrv_error_code, _In_ bool warning, _In_opt_ va_list* print_args );
|
||||
bool ss_error_handler( _Inout_ sqlsrv_context& ctx, _In_ unsigned int sqlsrv_error_code, _In_ int warning, _In_opt_ va_list* print_args );
|
||||
|
||||
// convert from the default encoding specified by the "CharacterSet"
|
||||
// connection option to UTF-16. mbcs_len and utf16_len are sizes in
|
||||
|
@ -258,7 +258,7 @@ inline void reset_errors( void )
|
|||
}
|
||||
|
||||
#define THROW_SS_ERROR( ctx, error_code, ... ) \
|
||||
(void)call_error_handler( ctx, error_code, false /*warning*/, ## __VA_ARGS__ ); \
|
||||
(void)call_error_handler( ctx, error_code, 0 /*warning*/, ## __VA_ARGS__ ); \
|
||||
throw ss::SSException();
|
||||
|
||||
|
||||
|
@ -360,7 +360,7 @@ namespace ss {
|
|||
template <typename H>
|
||||
inline H* process_params( INTERNAL_FUNCTION_PARAMETERS, _In_ char const* param_spec, _In_ const char* calling_func, _In_ size_t param_count, ... )
|
||||
{
|
||||
SQLSRV_UNUSED( return_value );
|
||||
// SQLSRV_UNUSED( return_value );
|
||||
|
||||
zval* rsrc;
|
||||
H* h = NULL;
|
||||
|
|
|
@ -37,7 +37,7 @@ void copy_error_to_zval( _Inout_ zval* error_z, _In_ sqlsrv_error_const* error,
|
|||
_In_ bool warning );
|
||||
bool ignore_warning( _In_ char* sql_state, _In_ int native_code );
|
||||
bool handle_errors_and_warnings( _Inout_ sqlsrv_context& ctx, _Inout_ zval* reported_chain, _Inout_ zval* ignored_chain, _In_ logging_severity log_severity,
|
||||
_In_ unsigned int sqlsrv_error_code, _In_ bool warning, _In_opt_ va_list* print_args );
|
||||
_In_ unsigned int sqlsrv_error_code, _In_ int warning, _In_opt_ va_list* print_args );
|
||||
|
||||
int sqlsrv_merge_zend_hash_dtor( _Inout_ zval* dest );
|
||||
bool sqlsrv_merge_zend_hash( _Inout_ zval* dest_z, zval const* src_z );
|
||||
|
@ -365,7 +365,7 @@ ss_error SS_ERRORS[] = {
|
|||
},
|
||||
{
|
||||
SS_SQLSRV_ERROR_INVALID_AUTHENTICATION_OPTION,
|
||||
{ IMSSP, (SQLCHAR*)"Invalid option for the Authentication keyword. Only SqlPassword, ActiveDirectoryPassword, or ActiveDirectoryMsi is supported.", -62, false }
|
||||
{ IMSSP, (SQLCHAR*)"Invalid option for the Authentication keyword. Only SqlPassword, ActiveDirectoryPassword, ActiveDirectoryMsi or ActiveDirectorySPA is supported.", -62, false }
|
||||
},
|
||||
{
|
||||
SS_SQLSRV_ERROR_AE_QUERY_SQLTYPE_REQUIRED,
|
||||
|
@ -456,7 +456,7 @@ bool ss_severity_check(_In_ unsigned int severity)
|
|||
return ((severity & SQLSRV_G(log_severity)) && (SQLSRV_G(current_subsystem) & SQLSRV_G(log_subsystems)));
|
||||
}
|
||||
|
||||
bool ss_error_handler( _Inout_ sqlsrv_context& ctx, _In_ unsigned int sqlsrv_error_code, _In_ bool warning, _In_opt_ va_list* print_args )
|
||||
bool ss_error_handler( _Inout_ sqlsrv_context& ctx, _In_ unsigned int sqlsrv_error_code, _In_ int warning, _In_opt_ va_list* print_args )
|
||||
{
|
||||
logging_severity severity = SEV_ERROR;
|
||||
if( warning && !SQLSRV_G( warnings_return_as_errors )) {
|
||||
|
@ -506,7 +506,7 @@ bool ss_error_handler( _Inout_ sqlsrv_context& ctx, _In_ unsigned int sqlsrv_err
|
|||
|
||||
PHP_FUNCTION( sqlsrv_errors )
|
||||
{
|
||||
SQLSRV_UNUSED( execute_data );
|
||||
// SQLSRV_UNUSED( execute_data );
|
||||
|
||||
zend_long flags = SQLSRV_ERR_ALL;
|
||||
|
||||
|
@ -557,7 +557,7 @@ PHP_FUNCTION( sqlsrv_errors )
|
|||
|
||||
PHP_FUNCTION( sqlsrv_configure )
|
||||
{
|
||||
SQLSRV_UNUSED( execute_data );
|
||||
// SQLSRV_UNUSED( execute_data );
|
||||
|
||||
LOG_FUNCTION( "sqlsrv_configure" );
|
||||
|
||||
|
@ -680,7 +680,7 @@ PHP_FUNCTION( sqlsrv_configure )
|
|||
|
||||
PHP_FUNCTION( sqlsrv_get_config )
|
||||
{
|
||||
SQLSRV_UNUSED( execute_data );
|
||||
// SQLSRV_UNUSED( execute_data );
|
||||
|
||||
char* option = NULL;
|
||||
size_t option_len;
|
||||
|
@ -821,7 +821,7 @@ void copy_error_to_zval( _Inout_ zval* error_z, _In_ sqlsrv_error_const* error,
|
|||
}
|
||||
|
||||
bool handle_errors_and_warnings( _Inout_ sqlsrv_context& ctx, _Inout_ zval* reported_chain, _Inout_ zval* ignored_chain, _In_ logging_severity log_severity,
|
||||
_In_ unsigned int sqlsrv_error_code, _In_ bool warning, _In_opt_ va_list* print_args )
|
||||
_In_ unsigned int sqlsrv_error_code, _In_ int warning, _In_opt_ va_list* print_args )
|
||||
{
|
||||
bool result = true;
|
||||
bool errors_ignored = false;
|
||||
|
|
|
@ -24,6 +24,8 @@ $adServer = 'TARGET_AD_SERVER';
|
|||
$adDatabase = 'TARGET_AD_DATABASE';
|
||||
$adUser = 'TARGET_AD_USERNAME';
|
||||
$adPassword = 'TARGET_AD_PASSWORD';
|
||||
$adSPClientId = 'TARGET_ADSP_CLIENT_ID';
|
||||
$adSPClientSecret = 'TARGET_ADSP_CLIENT_SECRET';
|
||||
|
||||
$driverType = true;
|
||||
$driver = "ODBC Driver 17 for SQL Server";
|
||||
|
|
|
@ -96,5 +96,5 @@ if ($azureServer != 'TARGET_AD_SERVER') {
|
|||
Connected successfully with Authentication=SqlPassword.
|
||||
string(1) "%d"
|
||||
Could not connect with Authentication=ActiveDirectoryIntegrated.
|
||||
SQLSTATE[IMSSP]: Invalid option for the Authentication keyword. Only SqlPassword, ActiveDirectoryPassword, or ActiveDirectoryMsi is supported.
|
||||
SQLSTATE[IMSSP]: Invalid option for the Authentication keyword. Only SqlPassword, ActiveDirectoryPassword, ActiveDirectoryMsi or ActiveDirectorySPA is supported.
|
||||
%s with Authentication=ActiveDirectoryPassword.
|
||||
|
|
117
test/functional/pdo_sqlsrv/pdo_azure_ad_service_principal.phpt
Normal file
117
test/functional/pdo_sqlsrv/pdo_azure_ad_service_principal.phpt
Normal file
|
@ -0,0 +1,117 @@
|
|||
--TEST--
|
||||
Test some basics of Azure AD service principal support
|
||||
--SKIPIF--
|
||||
<?php
|
||||
require_once('skipif.inc');
|
||||
require_once('MsSetup.inc');
|
||||
|
||||
try {
|
||||
$conn = new PDO("sqlsrv:server = $server; driver=$driver;", $uid, $pwd);
|
||||
|
||||
$msodbcsqlVer = $conn->getAttribute(PDO::ATTR_CLIENT_VERSION)["DriverVer"];
|
||||
$msodbcsqlMaj = explode(".", $msodbcsqlVer)[0];
|
||||
$msodbcsqlMin = explode(".", $msodbcsqlVer)[1];
|
||||
|
||||
if ($msodbcsqlMaj < 17 || $msodbcsqlMin < 7) {
|
||||
die("skip: Requires ODBC driver 17.7 or above");
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
die("skip: Failed to connect in skipif.");
|
||||
}
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
|
||||
function simpleTest($conn)
|
||||
{
|
||||
// Create table
|
||||
$tableName = 'pdoTestSPA';
|
||||
$col1 = 'Testing service principal with pdo';
|
||||
|
||||
dropTable($conn, $tableName);
|
||||
|
||||
$query = "CREATE TABLE $tableName(ID INT IDENTITY(1,1), COL1 VARCHAR(50))";
|
||||
$stmt = $conn->query($query);
|
||||
|
||||
// Insert one row
|
||||
$query = "INSERT INTO $tableName VALUES ('$col1')";
|
||||
$stmt = $conn->query($query);
|
||||
|
||||
// Fetch data
|
||||
$query = "SELECT * FROM $tableName";
|
||||
$stmt = $conn->query($query);
|
||||
|
||||
$result = $stmt->fetch(PDO::FETCH_NUM);
|
||||
$id = $result[0];
|
||||
if ($id != 1) {
|
||||
echo "AzureAD service principal test: fetched id $id unexpected\n";
|
||||
}
|
||||
|
||||
$field = $result[1];
|
||||
if ($field !== $col1) {
|
||||
echo "AzureAD service principal test: fetched value $field unexpected\n";
|
||||
}
|
||||
|
||||
dropTable($conn, $tableName);
|
||||
}
|
||||
|
||||
function connectAzureDB($showException)
|
||||
{
|
||||
global $adServer, $adDatabase, $adSPClientId, $adSPClientSecret, $maxAttempts;
|
||||
|
||||
$conn = false;
|
||||
try {
|
||||
$connectionInfo = "Database = $adDatabase; Authentication = ActiveDirectorySPA;";
|
||||
$conn = new PDO("sqlsrv:server = $adServer; $connectionInfo", $adSPClientId, $adSPClientSecret);
|
||||
} catch (PDOException $e) {
|
||||
if ($showException) {
|
||||
echo "Could not connect with Azure AD Service Principal after $maxAttempts retries.\n";
|
||||
print_r($e->getMessage());
|
||||
echo PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
return $conn;
|
||||
}
|
||||
|
||||
// First test connecting to regular sql server
|
||||
require_once('MsSetup.inc');
|
||||
try {
|
||||
$conn = new PDO("sqlsrv:server = $server; Authentication = ActiveDirectorySPA;", $uid, $pwd);
|
||||
echo "Expect regular connection to fail\n";
|
||||
} catch(PDOException $e) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
// Next, test connecting with a valid service principal and perform some simple tasks
|
||||
$maxAttempts = 3;
|
||||
|
||||
try {
|
||||
if ($adServer != 'TARGET_AD_SERVER' && $adSPClientId != 'TARGET_ADSP_CLIENT_ID') {
|
||||
$conn = false;
|
||||
$numAttempts = 0;
|
||||
do {
|
||||
$conn = connectAzureDB($numAttempts == ($maxAttempts - 1));
|
||||
if ($conn === false) {
|
||||
$numAttempts++;
|
||||
sleep(10);
|
||||
}
|
||||
} while ($conn === false && $numAttempts < $maxAttempts);
|
||||
|
||||
// Proceed when successfully connected
|
||||
if ($conn) {
|
||||
$conn->setAttribute(PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE, true);
|
||||
simpleTest($conn);
|
||||
unset($conn);
|
||||
}
|
||||
}
|
||||
} catch(PDOException $e) {
|
||||
print_r($e->getMessage());
|
||||
echo PHP_EOL;
|
||||
}
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECT--
|
||||
Done
|
153
test/functional/pdo_sqlsrv/pdo_fetch_large_stream.phpt
Normal file
153
test/functional/pdo_sqlsrv/pdo_fetch_large_stream.phpt
Normal file
|
@ -0,0 +1,153 @@
|
|||
--TEST--
|
||||
Test fetching varbinary, varchar, nvarchar max fields with client buffer
|
||||
--DESCRIPTION--
|
||||
Similar to sqlsrv_fetch_large_stream test but fetching varbinary, varchar, nvarchar max fields as strings with or without client buffer
|
||||
--SKIPIF--
|
||||
<?php require_once('skipif_mid-refactor.inc'); ?>
|
||||
--ENV--
|
||||
PHPT_EXEC=true
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("MsCommon_mid-refactor.inc");
|
||||
|
||||
$tableName = 'pdoFetchLobTest';
|
||||
$binaryColumn = 'varbinary_max';
|
||||
$strColumn = 'varchar_max';
|
||||
$nstrColumn = 'nvarchar_max';
|
||||
|
||||
$bin = 'abcdefghijklmnopqrstuvwxyz';
|
||||
$binaryValue = str_repeat($bin, 100);
|
||||
$hexValue = str_repeat(strtoupper(bin2hex($bin)), 100);
|
||||
$strValue = str_repeat("stuvwxyz", 400);
|
||||
$nstrValue = str_repeat("ÃÜðßZZýA©", 200);
|
||||
|
||||
function checkData($actual, $expected)
|
||||
{
|
||||
trace("Actual:\n$actual\n");
|
||||
|
||||
$success = true;
|
||||
$pos = strpos($actual, $expected);
|
||||
if (($pos === false) || ($pos > 1)) {
|
||||
$success = false;
|
||||
}
|
||||
|
||||
return ($success);
|
||||
}
|
||||
|
||||
function fetchBinary($conn, $buffered)
|
||||
{
|
||||
global $tableName, $binaryColumn, $binaryValue, $hexValue;
|
||||
|
||||
try {
|
||||
$query = "SELECT $binaryColumn FROM $tableName";
|
||||
if ($buffered) {
|
||||
$stmt = $conn->prepare($query, array(PDO::ATTR_CURSOR=>PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE=>PDO::SQLSRV_CURSOR_BUFFERED));
|
||||
} else {
|
||||
$stmt = $conn->prepare($query);
|
||||
}
|
||||
$stmt->bindColumn($binaryColumn, $value, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_BINARY);
|
||||
$stmt->execute();
|
||||
|
||||
$row = $stmt->fetch(PDO::FETCH_BOUND);
|
||||
|
||||
if (!checkData($value, $binaryValue)) {
|
||||
echo "Fetched binary value unexpected ($buffered): $value\n";
|
||||
}
|
||||
|
||||
$stmt->bindColumn($binaryColumn, $value, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_SYSTEM);
|
||||
$stmt->execute();
|
||||
|
||||
$row = $stmt->fetch(PDO::FETCH_BOUND);
|
||||
|
||||
if (!checkData($value, $hexValue)) {
|
||||
echo "Fetched binary value a char string ($buffered): $value\n";
|
||||
}
|
||||
|
||||
$stmt->bindColumn($binaryColumn, $value, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_UTF8);
|
||||
$stmt->execute();
|
||||
|
||||
$row = $stmt->fetch(PDO::FETCH_BOUND);
|
||||
|
||||
if (!checkData($value, $hexValue)) {
|
||||
echo "Fetched binary value as UTF-8 string ($buffered): $value\n";
|
||||
}
|
||||
} catch (PdoException $e) {
|
||||
echo "Caught exception in fetchBinary ($buffered):\n";
|
||||
echo $e->getMessage() . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
function fetchAsString($conn, $buffered)
|
||||
{
|
||||
global $tableName, $strColumn, $strValue;
|
||||
global $nstrColumn, $nstrValue;
|
||||
|
||||
try {
|
||||
$query = "SELECT $strColumn, $nstrColumn FROM $tableName";
|
||||
if ($buffered) {
|
||||
$stmt = $conn->prepare($query, array(PDO::ATTR_CURSOR=>PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE=>PDO::SQLSRV_CURSOR_BUFFERED));
|
||||
} else {
|
||||
$stmt = $conn->prepare($query);
|
||||
}
|
||||
$stmt->execute();
|
||||
|
||||
$stmt->bindColumn($strColumn, $value1, PDO::PARAM_STR);
|
||||
$stmt->bindColumn($nstrColumn, $value2, PDO::PARAM_STR);
|
||||
$row = $stmt->fetch(PDO::FETCH_BOUND);
|
||||
|
||||
if (!checkData($value1, $strValue)) {
|
||||
echo "Fetched string value ($buffered): $value1\n";
|
||||
}
|
||||
|
||||
if (!checkData($value2, $nstrValue)) {
|
||||
echo "Fetched string value ($buffered): $value2\n";
|
||||
}
|
||||
$stmt->execute();
|
||||
|
||||
$stmt->bindColumn($strColumn, $value, PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_SYSTEM);
|
||||
$row = $stmt->fetch(PDO::FETCH_BOUND);
|
||||
|
||||
if (!checkData($value, $strValue)) {
|
||||
echo "Fetched string value: $value\n";
|
||||
}
|
||||
} catch (PdoException $e) {
|
||||
echo "Caught exception in fetchBinary ($buffered):\n";
|
||||
echo $e->getMessage() . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$conn = connect();
|
||||
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
// Create table of one max column
|
||||
$colMeta = array(new ColumnMeta('varbinary(max)', $binaryColumn),
|
||||
new ColumnMeta('varchar(max)', $strColumn),
|
||||
new ColumnMeta('nvarchar(max)', $nstrColumn));
|
||||
createTable($conn, $tableName, $colMeta);
|
||||
|
||||
// Insert one row
|
||||
$query = "INSERT INTO $tableName ($binaryColumn, $strColumn, $nstrColumn) VALUES (?, ?, ?)";
|
||||
$stmt = $conn->prepare($query);
|
||||
$stmt->bindParam(1, $binaryValue, PDO::PARAM_LOB, 0, PDO::SQLSRV_ENCODING_BINARY);
|
||||
$stmt->bindParam(2, $strValue, PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_SYSTEM);
|
||||
$stmt->bindParam(3, $nstrValue, PDO::PARAM_STR);
|
||||
$stmt->execute();
|
||||
unset($stmt);
|
||||
|
||||
// Starting fetching with or without client buffer
|
||||
fetchBinary($conn, false);
|
||||
fetchBinary($conn, true);
|
||||
|
||||
fetchAsString($conn, false);
|
||||
fetchAsString($conn, true);
|
||||
|
||||
dropTable($conn, $tableName);
|
||||
echo "Done\n";
|
||||
unset($conn);
|
||||
} catch (PdoException $e) {
|
||||
echo $e->getMessage() . PHP_EOL;
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
Done
|
|
@ -23,5 +23,5 @@ Array
|
|||
\[(DriverDllName|DriverName)\] => (msodbcsql1[1-9].dll|(libmsodbcsql-[0-9]{2}\.[0-9]\.so\.[0-9]\.[0-9]|libmsodbcsql.[0-9]{2}.dylib))
|
||||
\[DriverODBCVer\] => [0-9]{1,2}\.[0-9]{1,2}
|
||||
\[DriverVer\] => [0-9]{1,2}\.[0-9]{1,2}\.[0-9]{4}
|
||||
\[ExtensionVer\] => [0-9]\.[0-9]\.[0-9](-(RC[1-9]?|preview[1-9]))?(\.[0-9]+)?(\+[0-9]+)?
|
||||
\[ExtensionVer\] => [0-9]\.[0-9]\.[0-9](-(RC[1-9]?|beta[1-9]))?(\.[0-9]+)?(\+[0-9]+)?
|
||||
\)
|
||||
|
|
|
@ -131,7 +131,7 @@ array\(4\) {
|
|||
\["DriverVer"\]=>
|
||||
string\(10\) "[0-9]{2}.[0-9]{2}.[0-9]{4}"
|
||||
\["ExtensionVer"\]=>
|
||||
string\([0-9]*\) \"[0-9].[0-9]\.[0-9](-(RC[1-9]?|preview[1-9]))?(\.[0-9]+)?(\+[0-9]+)?\"
|
||||
string\([0-9]*\) \"[0-9].[0-9]\.[0-9](-(RC[1-9]?|beta[1-9]))?(\.[0-9]+)?(\+[0-9]+)?\"
|
||||
}
|
||||
|
||||
Test_6:
|
||||
|
|
|
@ -58,7 +58,7 @@ function fetchBoth($conn, $tbname)
|
|||
echo "Expect getColumnMeta to fail with -1\n";
|
||||
} catch (Error $e) {
|
||||
if (PHP_MAJOR_VERSION == 8) {
|
||||
$error = '*PDOStatement::getColumnMeta(): Argument #1 ($index) must be greater than or equal to 0*';
|
||||
$error = '*PDOStatement::getColumnMeta(): Argument #1 ($column) must be greater than or equal to 0*';
|
||||
} else {
|
||||
$error = '*Invalid column reference: column number must be non-negative*';
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ function fetchBoth($conn, $tbname)
|
|||
echo "Expect getColumnMeta to fail with -1\n";
|
||||
} catch (Error $e) {
|
||||
if (PHP_MAJOR_VERSION == 8) {
|
||||
$error = '*PDOStatement::getColumnMeta(): Argument #1 ($index) must be greater than or equal to 0*';
|
||||
$error = '*PDOStatement::getColumnMeta(): Argument #1 ($column) must be greater than or equal to 0*';
|
||||
} else {
|
||||
$error = '*Invalid column reference: column number must be non-negative*';
|
||||
}
|
||||
|
|
|
@ -31,6 +31,8 @@ $adServer = 'TARGET_AD_SERVER';
|
|||
$adDatabase = 'TARGET_AD_DATABASE';
|
||||
$adUser = 'TARGET_AD_USERNAME';
|
||||
$adPassword = 'TARGET_AD_PASSWORD';
|
||||
$adSPClientId = 'TARGET_ADSP_CLIENT_ID';
|
||||
$adSPClientSecret = 'TARGET_ADSP_CLIENT_SECRET';
|
||||
|
||||
if (isset($_ENV['MSSQL_SERVER']) || isset($_ENV['MSSQL_USER']) || isset($_ENV['MSSQL_PASSWORD'])) {
|
||||
$server = $_ENV['MSSQL_SERVER'];
|
||||
|
|
|
@ -106,7 +106,7 @@ Array
|
|||
[SQLSTATE] => IMSSP
|
||||
[1] => -62
|
||||
[code] => -62
|
||||
[2] => Invalid option for the Authentication keyword. Only SqlPassword, ActiveDirectoryPassword, or ActiveDirectoryMsi is supported.
|
||||
[message] => Invalid option for the Authentication keyword. Only SqlPassword, ActiveDirectoryPassword, or ActiveDirectoryMsi is supported.
|
||||
[2] => Invalid option for the Authentication keyword. Only SqlPassword, ActiveDirectoryPassword, ActiveDirectoryMsi or ActiveDirectorySPA is supported.
|
||||
[message] => Invalid option for the Authentication keyword. Only SqlPassword, ActiveDirectoryPassword, ActiveDirectoryMsi or ActiveDirectorySPA is supported.
|
||||
)
|
||||
%s with Authentication=ActiveDirectoryPassword.
|
||||
|
|
116
test/functional/sqlsrv/sqlsrv_azure_ad_service_principal.phpt
Normal file
116
test/functional/sqlsrv/sqlsrv_azure_ad_service_principal.phpt
Normal file
|
@ -0,0 +1,116 @@
|
|||
--TEST--
|
||||
Test some basics of Azure AD Service Principal support
|
||||
--SKIPIF--
|
||||
<?php
|
||||
require_once('skipif.inc');
|
||||
require_once('MsSetup.inc');
|
||||
|
||||
$connectionInfo = array("UID"=>$userName, "PWD"=>$userPassword, "Driver" => $driver);
|
||||
$conn = sqlsrv_connect($server, $connectionInfo);
|
||||
if ($conn === false) {
|
||||
die("skip: Failed to connect in skipif.");
|
||||
}
|
||||
|
||||
$msodbcsqlVer = sqlsrv_client_info($conn)['DriverVer'];
|
||||
$version = explode(".", $msodbcsqlVer);
|
||||
|
||||
if ($version[0] < 17 || $version[1] < 7) {
|
||||
die("skip: Requires ODBC driver 17.7 or above");
|
||||
}
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once('MsCommon.inc');
|
||||
|
||||
function simpleTest($conn)
|
||||
{
|
||||
// Create table
|
||||
$tableName = 'testSPA';
|
||||
$col1 = 'Testing service principal';
|
||||
|
||||
dropTable($conn, $tableName);
|
||||
|
||||
$query = "CREATE TABLE $tableName(ID INT IDENTITY(1,1), COL1 VARCHAR(50))";
|
||||
$stmt = sqlsrv_query($conn, $query);
|
||||
if (!$stmt) {
|
||||
fatalError("AzureAD service principal test: failed to create a table\n");
|
||||
}
|
||||
|
||||
// Insert one row
|
||||
$query = "INSERT INTO $tableName VALUES ('$col1')";
|
||||
$stmt = sqlsrv_query($conn, $query);
|
||||
if (!$stmt) {
|
||||
fatalError("AzureAD service principal test: failed to insert a row\n");
|
||||
}
|
||||
|
||||
// Fetch data
|
||||
$query = "SELECT * FROM $tableName";
|
||||
$stmt = sqlsrv_query($conn, $query);
|
||||
if (!$stmt) {
|
||||
fatalError("AzureAD service principal test: failed to fetch a table\n");
|
||||
}
|
||||
|
||||
while (sqlsrv_fetch($stmt)) {
|
||||
$id = sqlsrv_get_field($stmt, 0);
|
||||
if ($id != 1) {
|
||||
fatalError("AzureAD service principal test: fetched id $id unexpected\n");
|
||||
}
|
||||
$field = sqlsrv_get_field($stmt, 1);
|
||||
if ($field !== $col1) {
|
||||
fatalError("AzureAD service principal test: fetched value $field unexpected\n");
|
||||
}
|
||||
}
|
||||
|
||||
dropTable($conn, $tableName);
|
||||
}
|
||||
|
||||
function connectAzureDB($showException)
|
||||
{
|
||||
global $adServer, $adDatabase, $adSPClientId, $adSPClientSecret, $maxAttempts;
|
||||
|
||||
$conn = false;
|
||||
$connectionInfo = array("Database"=>$adDatabase,
|
||||
"Authentication"=>"ActiveDirectorySPA",
|
||||
"UID"=>$adSPClientId,
|
||||
"PWD"=>$adSPClientSecret);
|
||||
|
||||
$conn = sqlsrv_connect($adServer, $connectionInfo);
|
||||
if ($conn === false) {
|
||||
if ($showException) {
|
||||
fatalError("Could not connect with Azure AD Service Principal after $maxAttempts retries.\n");
|
||||
}
|
||||
} else {
|
||||
simpleTest($conn);
|
||||
|
||||
sqlsrv_close($conn);
|
||||
}
|
||||
|
||||
return $conn;
|
||||
}
|
||||
|
||||
// Try connecting to an invalid server. Expect this to fail.
|
||||
$connectionInfo = array("Authentication"=>"ActiveDirectorySPA");
|
||||
$conn = sqlsrv_connect('invalidServer', $connectionInfo);
|
||||
if ($conn) {
|
||||
fatalError("AzureAD Service Principal test: expected to fail with invalidServer\n");
|
||||
}
|
||||
|
||||
// Next, test connecting with Service Principal
|
||||
$maxAttempts = 3;
|
||||
|
||||
if ($adServer != 'TARGET_AD_SERVER' && $adSPClientId != 'TARGET_ADSP_CLIENT_ID') {
|
||||
$conn = false;
|
||||
$numAttempts = 0;
|
||||
do {
|
||||
$conn = connectAzureDB($numAttempts == ($maxAttempts - 1));
|
||||
if ($conn === false) {
|
||||
$numAttempts++;
|
||||
sleep(10);
|
||||
}
|
||||
} while ($conn === false && $numAttempts < $maxAttempts);
|
||||
}
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECT--
|
||||
Done
|
|
@ -21,5 +21,5 @@ array\(4\) {
|
|||
\[\"DriverVer\"\]=>
|
||||
string\(10\) \"[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{4}\"
|
||||
\[\"ExtensionVer\"\]=>
|
||||
string\([0-9]+\) \"[0-9]\.[0-9]\.[0-9](-(RC[1-9]?|preview[1-9]))?(\.[0-9]+)?(\+[0-9]+)?\"
|
||||
string\([0-9]+\) \"[0-9]\.[0-9]\.[0-9](-(RC[1-9]?|beta[1-9]))?(\.[0-9]+)?(\+[0-9]+)?\"
|
||||
}
|
|
@ -1,55 +1,113 @@
|
|||
--TEST--
|
||||
Streaming Field Test
|
||||
Test fetching varchar and nvarchar max fields
|
||||
--DESCRIPTION--
|
||||
Verifies the streaming behavior and proper error handling with Always Encrypted
|
||||
Test fetching varchar and nvarchar max fields as streams or strings with or without client buffer
|
||||
--SKIPIF--
|
||||
<?php require('skipif_versions_old.inc'); ?>
|
||||
--ENV--
|
||||
PHPT_EXEC=true
|
||||
--FILE--
|
||||
<?php
|
||||
require_once('MsCommon.inc');
|
||||
|
||||
$conn = AE\connect();
|
||||
|
||||
$tableName = "test_max_fields";
|
||||
AE\createTable($conn, $tableName, array(new AE\ColumnMeta("varchar(max)", "varchar_max_col")));
|
||||
$tableName = "char_max_fields";
|
||||
$columns = array(new AE\ColumnMeta("varchar(max)", "varchar_max_col"),
|
||||
new AE\ColumnMeta("nvarchar(max)", "nvarchar_max_col"));
|
||||
|
||||
$inValue = str_repeat("ÃÜðßZZýA©", 600);
|
||||
$insertSql = "INSERT INTO $tableName (varchar_max_col) VALUES (?)";
|
||||
$params = array($inValue);
|
||||
AE\createTable($conn, $tableName, $columns);
|
||||
|
||||
$strValue = str_repeat("SimpleTest", 450);
|
||||
$nstrValue = str_repeat("ÃÜðßZZýA©", 600);
|
||||
|
||||
$insertSql = "INSERT INTO $tableName (varchar_max_col, nvarchar_max_col) VALUES (?, ?)";
|
||||
$params = array(array($strValue, null, null, SQLSRV_SQLTYPE_VARCHAR('max')),
|
||||
array($nstrValue, null, SQLSRV_PHPTYPE_STRING('UTF-8'), SQLSRV_SQLTYPE_NVARCHAR('max')));
|
||||
|
||||
$stmt = sqlsrv_prepare($conn, $insertSql, $params);
|
||||
if ($stmt) {
|
||||
sqlsrv_execute($stmt);
|
||||
}
|
||||
|
||||
$query = "SELECT * FROM $tableName";
|
||||
$stmt = sqlsrv_prepare($conn, $query);
|
||||
if ($stmt) {
|
||||
sqlsrv_execute($stmt);
|
||||
}
|
||||
|
||||
if (!sqlsrv_fetch($stmt)) {
|
||||
fatalError("Failed to fetch row ");
|
||||
}
|
||||
|
||||
$stream = sqlsrv_get_field($stmt, 0, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_CHAR));
|
||||
|
||||
$success = false;
|
||||
if ($stream !== false) {
|
||||
$value = '';
|
||||
$num = 0;
|
||||
while (!feof($stream)) {
|
||||
$value .= fread($stream, 8192);
|
||||
$res = sqlsrv_execute($stmt);
|
||||
if (!$res) {
|
||||
fatalError("Failed to insert data");
|
||||
}
|
||||
fclose($stream);
|
||||
if (checkData($value, $inValue)) { // compare the data to see if they match!
|
||||
$success = true;
|
||||
}
|
||||
}
|
||||
if ($success) {
|
||||
echo "Done.\n";
|
||||
} else {
|
||||
fatalError("Failed to fetch stream ");
|
||||
fatalError("Failed to prepare insert statement");
|
||||
}
|
||||
|
||||
runTest($conn, false);
|
||||
runTest($conn, true);
|
||||
|
||||
dropTable($conn, $tableName);
|
||||
|
||||
sqlsrv_free_stmt($stmt);
|
||||
sqlsrv_close($conn);
|
||||
|
||||
echo "Done\n";
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
function runTest($conn, $buffered)
|
||||
{
|
||||
global $tableName, $strValue, $nstrValue;
|
||||
|
||||
trace("runTest ($buffered)\n");
|
||||
$query = "SELECT * FROM $tableName";
|
||||
if ($buffered) {
|
||||
$stmt = sqlsrv_prepare($conn, $query, null, array("Scrollable"=>SQLSRV_CURSOR_CLIENT_BUFFERED));
|
||||
} else {
|
||||
$stmt = sqlsrv_prepare($conn, $query);
|
||||
}
|
||||
if (!$stmt) {
|
||||
fatalError("runTest ($buffered): failed to prepare select statement");
|
||||
}
|
||||
|
||||
if (!sqlsrv_execute($stmt)) {
|
||||
fatalError("runTest ($buffered): failed to execute select");
|
||||
}
|
||||
if (!sqlsrv_fetch($stmt)) {
|
||||
fatalError("runTest ($buffered): failed to fetch data");
|
||||
}
|
||||
|
||||
fetchAsString($stmt, 0, $strValue);
|
||||
fetchAsString($stmt, 1, $nstrValue);
|
||||
|
||||
if (!sqlsrv_execute($stmt)) {
|
||||
fatalError("runTest ($buffered): failed to execute select");
|
||||
}
|
||||
if (!sqlsrv_fetch($stmt)) {
|
||||
fatalError("runTest ($buffered): failed to fetch data");
|
||||
}
|
||||
|
||||
fetchAsStream($stmt, 0, $strValue);
|
||||
fetchAsStream($stmt, 1, $nstrValue);
|
||||
}
|
||||
|
||||
function fetchAsString($stmt, $index, $expected)
|
||||
{
|
||||
trace("fetchAsString ($index):\n");
|
||||
$sqltype = ($index > 0) ? SQLSRV_PHPTYPE_STRING('UTF-8') : SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR);
|
||||
$value = sqlsrv_get_field($stmt, $index, $sqltype);
|
||||
if (!checkData($value, $expected)) {
|
||||
echo("fetchAsString ($index) expected:\n$expected\nActual:\n$value\n");
|
||||
}
|
||||
}
|
||||
|
||||
function fetchAsStream($stmt, $index, $expected)
|
||||
{
|
||||
trace("fetchAsStream ($index):\n");
|
||||
$sqltype = ($index > 0) ? SQLSRV_PHPTYPE_STREAM('UTF-8') : SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_CHAR);
|
||||
|
||||
$stream = sqlsrv_get_field($stmt, $index, $sqltype);
|
||||
if ($stream !== false) {
|
||||
$value = '';
|
||||
while (!feof($stream)) {
|
||||
$value .= fread($stream, 8192);
|
||||
}
|
||||
fclose($stream);
|
||||
if (!checkData($value, $expected)) {
|
||||
echo("fetchAsStream ($index) expected:\n$expected\nActual:\n$value\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkData($actual, $expected)
|
||||
|
@ -58,15 +116,11 @@ function checkData($actual, $expected)
|
|||
|
||||
$pos = strpos($actual, $expected);
|
||||
if (($pos === false) || ($pos > 1)) {
|
||||
$success = false;
|
||||
$success = false;
|
||||
}
|
||||
|
||||
if (!$success) {
|
||||
trace("\nData error\nExpected:\n$expected\nActual:\n$actual\n");
|
||||
}
|
||||
|
||||
return ($success);
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
Done.
|
||||
Done
|
202
test/functional/sqlsrv/sqlsrv_fetch_large_stream_binary.phpt
Normal file
202
test/functional/sqlsrv/sqlsrv_fetch_large_stream_binary.phpt
Normal file
|
@ -0,0 +1,202 @@
|
|||
--TEST--
|
||||
Test fetching varbinary max fields with client buffer
|
||||
--DESCRIPTION--
|
||||
Test fetching varbinary max fields as streams or strings using client buffer
|
||||
--SKIPIF--
|
||||
<?php require('skipif_versions_old.inc'); ?>
|
||||
--ENV--
|
||||
PHPT_EXEC=true
|
||||
--FILE--
|
||||
<?php
|
||||
require_once('MsCommon.inc');
|
||||
|
||||
function fetchNull($stmt, $sqltype, $message)
|
||||
{
|
||||
$result = sqlsrv_get_field($stmt, 1, $sqltype);
|
||||
if (!is_null($result)) {
|
||||
echo("$message: expected NULL\n");
|
||||
}
|
||||
}
|
||||
|
||||
function fetchNullStream($stmt, $sqltype, $message)
|
||||
{
|
||||
$stream = sqlsrv_get_field($stmt, 1, $sqltype);
|
||||
if ($stream !== false) {
|
||||
$value = fread($stream, 8192);
|
||||
fclose($stream);
|
||||
|
||||
if (!empty($value)) {
|
||||
echo("$message: expected an empty value\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function fetchStream($stmt, $test)
|
||||
{
|
||||
global $binaryValue, $hexValue;
|
||||
|
||||
if (!sqlsrv_execute($stmt)) {
|
||||
fatalError("fetchStream: failed to execute select");
|
||||
}
|
||||
if (!sqlsrv_fetch($stmt)) {
|
||||
fatalError("fetchStream: failed to fetch row");
|
||||
}
|
||||
|
||||
switch ($test) {
|
||||
case 1:
|
||||
$sqltype = SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_CHAR);
|
||||
$type = 'char string';
|
||||
$expected = $hexValue;
|
||||
break;
|
||||
case 2:
|
||||
$sqltype = SQLSRV_PHPTYPE_STREAM('UTF-8');
|
||||
$type = 'UTF-8 string';
|
||||
$expected = $hexValue;
|
||||
break;
|
||||
case 3:
|
||||
$sqltype = SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY);
|
||||
$type = 'binary string';
|
||||
$expected = $binaryValue;
|
||||
break;
|
||||
default:
|
||||
echo "fetchStream: something went wrong\n";
|
||||
break;
|
||||
}
|
||||
|
||||
trace("fetchStream ($type):\n");
|
||||
$stream = sqlsrv_get_field($stmt, 0, $sqltype);
|
||||
if ($stream !== false) {
|
||||
$value = '';
|
||||
while (!feof($stream)) {
|
||||
$value .= fread($stream, 8192);
|
||||
}
|
||||
fclose($stream);
|
||||
if (!checkData($value, $expected)) {
|
||||
echo("fetchStream ($type)\nExpected:\n$expected\nActual:\n$value\n");
|
||||
}
|
||||
} else {
|
||||
fatalError("fetchStream ($type) failed");
|
||||
}
|
||||
|
||||
fetchNullStream($stmt, $sqltype, "fetchStream ($type)\n");
|
||||
}
|
||||
|
||||
function fetchData($stmt, $test)
|
||||
{
|
||||
global $binaryValue, $hexValue;
|
||||
|
||||
if (!sqlsrv_execute($stmt)) {
|
||||
fatalError("fetchData: failed to execute select");
|
||||
}
|
||||
if (!sqlsrv_fetch($stmt)) {
|
||||
fatalError("fetchData: failed to fetch row");
|
||||
}
|
||||
|
||||
switch ($test) {
|
||||
case 1:
|
||||
$sqltype = SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR);
|
||||
$type = 'char string';
|
||||
$expected = $hexValue;
|
||||
break;
|
||||
case 2:
|
||||
$sqltype = SQLSRV_PHPTYPE_STRING('UTF-8');
|
||||
$type = 'UTF-8 string';
|
||||
$expected = $hexValue;
|
||||
break;
|
||||
case 3:
|
||||
$sqltype = SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY);
|
||||
$type = 'binary string';
|
||||
$expected = $binaryValue;
|
||||
break;
|
||||
default:
|
||||
echo "fetchData: something went wrong\n";
|
||||
break;
|
||||
}
|
||||
|
||||
trace("fetchData ($type):\n");
|
||||
$value = sqlsrv_get_field($stmt, 0, $sqltype);
|
||||
if (!checkData($value, $expected)) {
|
||||
echo("fetchData ($type)\nExpected:\n$expected\nActual:\n$value\n");
|
||||
}
|
||||
|
||||
fetchNull($stmt, $sqltype, "fetchData ($type)\n");
|
||||
}
|
||||
|
||||
function runTest($conn, $buffered)
|
||||
{
|
||||
global $tableName, $binaryValue, $hexValue;
|
||||
|
||||
$query = "SELECT * FROM $tableName";
|
||||
if ($buffered) {
|
||||
trace("Test using a client buffer\n");
|
||||
$stmt = sqlsrv_prepare($conn, $query, null, array("Scrollable"=>SQLSRV_CURSOR_CLIENT_BUFFERED));
|
||||
} else {
|
||||
trace("Test without using a client buffer\n");
|
||||
$stmt = sqlsrv_prepare($conn, $query);
|
||||
}
|
||||
|
||||
if (!$stmt) {
|
||||
fatalError("runTest: failed to prepare select statement");
|
||||
}
|
||||
|
||||
fetchData($stmt, 1);
|
||||
fetchData($stmt, 2);
|
||||
fetchData($stmt, 3);
|
||||
|
||||
fetchStream($stmt, 1);
|
||||
fetchStream($stmt, 2);
|
||||
fetchStream($stmt, 3);
|
||||
}
|
||||
|
||||
function checkData($actual, $expected)
|
||||
{
|
||||
$success = true;
|
||||
|
||||
$pos = strpos($actual, $expected);
|
||||
if (($pos === false) || ($pos > 1)) {
|
||||
$success = false;
|
||||
}
|
||||
|
||||
return ($success);
|
||||
}
|
||||
|
||||
|
||||
$conn = AE\connect();
|
||||
|
||||
$tableName = "binary_max_fields";
|
||||
|
||||
$columns = array(new AE\ColumnMeta("varbinary(max)", "varbinary_max_col"),
|
||||
new AE\ColumnMeta("varbinary(max)", "varbinary_null_col"));
|
||||
|
||||
AE\createTable($conn, $tableName, $columns);
|
||||
|
||||
$bin = 'abcdefghijk';
|
||||
$binaryValue = str_repeat($bin, 400);
|
||||
$hexValue = strtoupper(bin2hex($binaryValue));
|
||||
|
||||
$insertSql = "INSERT INTO $tableName (varbinary_max_col, varbinary_null_col) VALUES (?, ?)";
|
||||
|
||||
$params = array(array($binaryValue, null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY), SQLSRV_SQLTYPE_VARBINARY('max')),
|
||||
array(null, null, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR), SQLSRV_SQLTYPE_VARBINARY('max')));
|
||||
|
||||
$stmt = sqlsrv_prepare($conn, $insertSql, $params);
|
||||
if ($stmt) {
|
||||
$res = sqlsrv_execute($stmt);
|
||||
if (!$res) {
|
||||
fatalError("Failed to insert data");
|
||||
}
|
||||
} else {
|
||||
fatalError("Failed to prepare insert statement");
|
||||
}
|
||||
|
||||
runTest($conn, false);
|
||||
runTest($conn, true);
|
||||
|
||||
echo "Done\n";
|
||||
dropTable($conn, $tableName);
|
||||
|
||||
sqlsrv_free_stmt($stmt);
|
||||
sqlsrv_close($conn);
|
||||
?>
|
||||
--EXPECT--
|
||||
Done
|
Loading…
Reference in a new issue