5.8.0 RTW dev to master (#1087)

* Fixed the potential error reported by Prefast code analysis

* Use SQLSRV_ASSERT for checking NULL ptrs

* For these AKV tests check env despite not AE connected

* Added the driver option to run functional tests

* Fixed connection pooling tests for more than one ODBC drivers

* added driver option to pdo isPooled.php

* Removed win32 ifdefs re connection resiliency (#802)

* Set the driver argument for getDSN to null by default (#798)

* Added the driver argument to getDSN

* Dropped the driver argument but set to null as default

* Removed the AE condition in locale support

* Modified the AE condition for locale support

* Changed int to SQLLEN to avoid infinite loop (#806)

* Version 5.3.0 (#803)

* Version 5.3.0

* Fixed the wrong replacements

* Added comments block to m4 files

* Use dnl for comments

*  Modified AE fetch phptypes test to insert only one row at a time and loop through php types (#801)

* Modified AE fetch phptypes test to insert only one row at a time and loop through php types

* Fixed formatting

* Streamlined two very similar large column name tests (#807)

* Streamlined two very similar large column name tests

* Changed the EOL

* Updates to change log and readme (#811)

* Updates to change log and readme

* Dropped support for Ubuntu 17

* Modified as per review comments

* Fixed connection resiliency tests for Unix, updated AppVeyor for ODBC 17.2

* Fixed expected output

* Fixed output and skipifs

* Fixed skipifs and output

* Fixed driver name

* Updated installation instructions and sample script (#813)

* Updated instructions and sample test for 5.3.0 RTW

* Fixed sample code to adhere to php coding standard

* Fixed cases and spaces

* Modified NOTE for UB 18.04 based on review comments

* Added 'exit'

* Modified change log and readme based on review to PR 811

* Applied review comments

* build output to debug appveyor failure

* removed debug output

* Streamlined two very similar large column name tests (#815)

* Streamlined two very similar large column name tests

* Added random number of test table names to avoid operand clash issues

* Replaced to with for based on review

* Changelog updated

* changelog updated, test skipif changed to run on unix platforms

* Fixed skipif typo

* Fixed typo in skipif for pdo

* Fixed some output for Travis

* Moved error checking inside pdo connres tests

* Added links back to changelog

* Fixed output for sqlsrv connres tests

* Fixed output

* Fixed output again

* Fixed skipifs for connres

* Tweaked per review comments

* Changes made to source and tests to support PHP 7.3 (#822)

* Changes made to support php 7.3

* Correct use of the smart pointer

* Fixed the tests for 7.3

* Some clean up for array_init()

* Fixed formattings and clean up

* One more fix

* Initialising strings with nulls

* Removed some spaces

* Made array index spacing consistent

* Fix for compilation problem

* Fix for compilation problem again

* Before freeing stmt in destructor check if dbh driver data is NULL  (#829)

* Issue 434 - set dbh driver data to NULL as well in destructor

* Reverted the last change but instead check if dbh driver_data is already freed

* Modified the comment

* Added driver to the skipif conditions (#831)

* Used git clone instead to download source from a branch of a tag (#832)

* Modified the error handling to make it more flexible (#833)

* Made error handling more flexible

* Fixed a minor issue with a test

* Enabled Spectre Mitigations (#836)

* Incorporated changes in PR 634 to pdo_sqlsrv (#834)

* Incorporated changes in PR 634 to pdo_sqlsrv

* Reverted the changes because the array is for internal use only

* Modified README re user's suggestion (#841)

* Modified README re user's suggestion

* Moved the if condition to the end as per review

* Adding supporting for Azure AD access token (#837)

* Adding supporting for Azure AD access token

* Added more comments for the AD access token skipif files

* Save the pointer to access token struct until after connecting

* Clear the access token data before freeing the memory

* Added a reference as per review

* Feature request - new PDO_STMT_OPTION_FETCHES_DATETIME_TYPE flag for pdo_sqlsrv to return datetime as objects (#842)

* Feature request - issue 648

* Fixed constructor for field_cache and added another test

* Added tests for FETCH_BOUND

* Added a new test for output param

* Modified output param test to set attributes differently

* Removed a useless helped function in a test

* Combined two new tests into one as per review

* Uncommented dropTable

* Feature request - add ReturnDatesAsStrings option to statement level for sqlsrv  (#844)

* Added ReturnDatesAsStrings option to the statement level

* Added new tests for ReturnDatesAsStrings at statement level

* Added more datetime types as per review

* Updated version 5.4.0-preview (#846)

* Updated version 5.4.0-preview

* Replaced 5.3 with 5.4

* Fixed sqlsrv datetime tests to connect with ColumnEncryption variables (#849)

* Change log for 5.4.0-preview (#850)

* Updated change log for 5.4.0-preview

* Updated 5.4.0 preview to add two new feature requests

* Modified change log as per review

* Modified the wordings

* Updated readme, changelog, and install instructions

* Clear AKV data after setting the connection attribute or when exception is thrown (#854)

* Dev (#820)

* Fixed the potential error reported by Prefast code analysis

* Use SQLSRV_ASSERT for checking NULL ptrs

* For these AKV tests check env despite not AE connected

* Added the driver option to run functional tests

* Fixed connection pooling tests for more than one ODBC drivers

* added driver option to pdo isPooled.php

* Removed win32 ifdefs re connection resiliency (#802)

* Set the driver argument for getDSN to null by default (#798)

* Added the driver argument to getDSN

* Dropped the driver argument but set to null as default

* Removed the AE condition in locale support

* Modified the AE condition for locale support

* Changed int to SQLLEN to avoid infinite loop (#806)

* Version 5.3.0 (#803)

* Version 5.3.0

* Fixed the wrong replacements

* Added comments block to m4 files

* Use dnl for comments

*  Modified AE fetch phptypes test to insert only one row at a time and loop through php types (#801)

* Modified AE fetch phptypes test to insert only one row at a time and loop through php types

* Fixed formatting

* Streamlined two very similar large column name tests (#807)

* Streamlined two very similar large column name tests

* Changed the EOL

* Updates to change log and readme (#811)

* Updates to change log and readme

* Dropped support for Ubuntu 17

* Modified as per review comments

* Fixed connection resiliency tests for Unix, updated AppVeyor for ODBC 17.2

* Fixed expected output

* Fixed output and skipifs

* Fixed skipifs and output

* Fixed driver name

* Updated installation instructions and sample script (#813)

* Updated instructions and sample test for 5.3.0 RTW

* Fixed sample code to adhere to php coding standard

* Fixed cases and spaces

* Modified NOTE for UB 18.04 based on review comments

* Added 'exit'

* Modified change log and readme based on review to PR 811

* Applied review comments

* build output to debug appveyor failure

* removed debug output

* Streamlined two very similar large column name tests (#815)

* Streamlined two very similar large column name tests

* Added random number of test table names to avoid operand clash issues

* Replaced to with for based on review

* Changelog updated

* changelog updated, test skipif changed to run on unix platforms

* Fixed skipif typo

* Fixed typo in skipif for pdo

* Fixed some output for Travis

* Moved error checking inside pdo connres tests

* Added links back to changelog

* Fixed output for sqlsrv connres tests

* Fixed output

* Fixed output again

* Clear AKV data after connection or when exception is thrown

* Modified tests too to skip some AKV tests without real credentials

* Used assignment operator also free the existing memory

* Change readme links to https

* Change readme links to https

Merging this commit to dev

* Save meta data for the fetched result set (#855)

* Save meta data on fetched result sets

* Fixed a compilation error

* Optimized some more -- metadata should be available when fetching

* Skip conversion for strings of numeric values, integers, floats, decimals etc

* Set encoding char for numeric data

* Apply review

* Added Mojave to macOS instructions (#862)

Added Mojave to macOS instructions

* Fixed the broken links of Appveyor status badge (#863)

* Feature request 415 for sqlsrv (#861)

* Modified how to send stream data using SQLPutData and SQLParamData (#865)

* Updated instructions to include Ubuntu 18.10 (#869)

* Feature request 415 for pdo_sqlsrv (#873)

* Skipped some tests when running against Azure (#874)

* Modified config files to add the compiler flag, /Qspectre (#878)

* Merge the commit from master re survey image link (#880)

* Fixed the flaws of decimal tests and added more debugging (#879)

* Changed sample code to adhere to PSR standard (#887)

* Decimal places for money types only (#886)

* Version update for 5.5.0-preview (#889)

* Fixed the error in the pdo decimal test (#890)

* Removed warning messages while compiling extensions (#892)

* Improve performance of Unicode conversions (#891)

* Update sqlsrv_statement_format_money_scales.phpt

Do not encrypt money / smallmoney fields in the test table

* Change log 5.5.0-preview (#895)

* updated docs for php 7.3

* Fixed broken links

* Added back Ubuntu 18.10 ODBC instruction

* Drop tests related to fake passwords (#905)

* Initialize output param buffer when allocating extra space (#907)

* Enable compiling extensions statically into PHP (#904)

* Dropped dbname variable and set QUOTED_IDENTIFIER to ON (#911)

* Skipped the non-applicables tests against Azure Data Warehouse (#913)

* Support for Managed Identity for Azure resources (#875)

* Changed version 5.6.0 (#918)

* Initialize hasLoss before passing into Convert function (#919)

* Added new tests for setting client buffer size related to issue 228 (#920)

* Fixed load order issue in sqlsrv

* Added source indexing for symbols (#922)

* Modified linux and mac instructions for 5.6.0 RTW (#926)

* Change log 5.6.0 (#921)

* add Language option on connect

* Updated AppVeyor to download ODBC driver 17.3 (#941)

* Issue 937 - fixed ASSERT and added new tests (#940)

* Changed travis to pull mcr.microsoft.com/mssql/server:2017-latest instead (#943)

* Modified money tests to test the accuracies of floats (#944)

* Fixed the returned values for PDOStatement::getColumnMeta (#946)

* Onboarding to Azure Pipelines (#949)

* Fixed the error in Issue 570  (#952)

* Added a new status badge on readme (#953)

* Added new tests for issue 569 (#951)

* Fix issue 955 - errors building sqlsrv alone (#956)

* Modified test_largeData for Linux CI (#954)

* Issue 937 - fixed ASSERT and added new tests (#940)


(cherry picked from commit 12d01c9189)

* Fixed the returned values for PDOStatement::getColumnMeta (#946)


(cherry picked from commit 7309fb90b1)

* Fix issue 955 - errors building sqlsrv alone (#956)

(cherry picked from commit 15f61bd0b4)

* 5.6.1 hotfix

* Updated change log

* Tests modified for language option for SQL Azure (#963)

* Update azure-pipelines.yml for Azure Pipelines [skip ci] (#964)

* Added more checks for error conditions (#965)

* Removed forward cursor condition

* Added row and column count checks

* Revert "Update azure-pipelines.yml for Azure Pipelines [skip ci] (#964)" (#969)

This reverts commit 7d389e0cff.

* Add new pdo_sqlsrv tests for utf8 encoding errors (#966)

* Modified to check if qualified for AE connections (#967)

* Fixed test and error message

* Minor fixes

* Test fixes

* Addressed review comments

* Fixed test failure

* Made Azure AD tests more robust (#973)

* Addressed review comments

* Issue 970: use quotes for variables (#971)

* Added batch query test

* Fixed 32 bit test failure

* Addressed review comments

* Formatting changes

* Used different skipif conditions for these two tests that require AE connections (#977)

* Simplified insert logic

* Modified get column meta method to reference saved metadata (#978)

* Revert "Used different skipif conditions for these two tests that require AE connections (#977)" (#980)

This reverts commit ee3c85afa8.

* Fixed failing tests (#981)

*  Data Classification sensitivity metadata retrieval (#979)

* Added more pdo tests to verify different error conditions (#984)

* Fixed memory issues with data classification (#985)

* Added connection string flag

* Removed unix skipif

* Fixed test output

* Fixed pdo test

* Changed flag name

* Fixed test output

* Updated links and versions (#987) (#988)

* Fixed test output (again)

* Fixed test output (again)

* Fixed test output (again)

* Replaced expected test output altogether

* Fixed locale issue

* Corrected formatting

* Replaced EXPECTF with EXPECT

* Fixed two failing tests (#991)

* Redesigned some tests based on recent test results (#992)

* Modified pipelines to connect using sqlcmd inside of the container instead (#995)

* Added batch query

* Added batch query test for pdo (#997)

* Added a new test and modify a non LOB sqlsrv test (#1000)

* Two index zval functions are macros in php 7.4 (#1001)

* Replaced uint with size_t (#1004)

*  Check compiler version for php 74 (#1005)

* Fixed tests that failed in php 7.4 (#1006)

* Improve data caching with datetime objects (#1008)

* Fixed for issues found by Semmle (#1011)

* Removed unneeded constants

* Fixed sqlsrv_free_stmt argument info

* Fixed brace escape to avoid buffer overflow

* Fixed brace escape and added test

* Debugging test failure on Bamboo

* Removed debugging output

* Debugging test failure on Bamboo

* Removed debugging output

* Added more test cases

* Changed range check to use strchr

* Added pdo test

* Fixed test and formatting

* Addressed various issues with PHP 7.4 beta1 (#1015)

* Updated dockerfile to use UB 18.04 and PHP 73 (#1016)

* Added survey results (#1017)

* Updated ODBC driver 17.4 (#1019)

* Modified output.py to take a new argument and travis yml to use include for coveralls (#1020)

*  Used constants in memory stress tests for easier configuration (#1022)

* Removed KSP related scripts and files (#1030)

* Updated version to 5.7.0 preview (#1029)

* Change log for 5.7.0 (#1028)

* Modified how drivers handle query timeout settings (#1037)

* Feature request: support extended string types (#1043)

* Added the required file to ansi tests (#1047)

* Always Encrypted v2 support (#1045)

* Change to support ae-v2

* Add support for AE V2

* Added some descriptions and comments

* Fixed PDO pattern matching

* Updated key generation scripts

* Fixed key script

* Fixed char/nchar results, fixed formatting issues

* Addressed review comments

* Updated key scripts

* Debugging aev2 keyword failure

* Debugging aev2 keyword failure

* Debugging aev2 keyword failure

* Debugging aev2 keyword failure

* Added skipif to ae v2 keyword test

* Addressed review comments

* Fixed braces and camel caps

* Updated test descriptions

* Added detail to test descriptions

* Tiny change

* Modified pdo tests to work with column encryption (#1051)

* Saved php types with metadata when fetching (#1049)

* Updated survey charts for Nov 2019 (#1057)

* Updated all CIs (#1058)

* Change log 5.7.1 preview (#1060)

* Fix AKV keyword test for AE v2 behaviour (#1061)

* Master (#936)

5.6.0 RTW

* 5.6.1 hotfix (#959)

* Updated links and versions (#987)

* Fixed AKV keyword tests for AE v2

* Added comment

* Free proc cache before starting test

* Fixed comment

* Update linux mac instructions for php 7.4 (#1062)

* Updated appveyor yml to build 7.3 and 7.4 (#1065)

* Fixes suggested by Semmle (#1068)

* Fixes suggested by Semmle

* Updated azure-pipelines

* Added configurable options for setting locales (#1069)

#1063

* Fixed the skipif wordings and styles (#1070)

* Modified locale tests to work in both linux and mac (#1074)

* Include sql_variant type for buffered queries (#1080)

* Updated versions and year (#1082)

* Change log for version 5.8.0 (#1083)

* 5.8.0 rtw docs (#1086)

* updated install instructions and changelog

* removed md extensions

* Addressed review comments

* added path

* Fixed link

Co-authored-by: Jenny Tam <v-yitam@microsoft.com>
Co-authored-by: Gert de Pagter <BackEndTea@users.noreply.github.com>
Co-authored-by: Jannes Jeising <jannes@jeising.net>
Co-authored-by: Guillaume Degoulet <34232764+gdegoulet@users.noreply.github.com>
This commit is contained in:
David Puglielli 2020-01-31 14:02:45 -08:00 committed by GitHub
parent 8aaace8e46
commit 7458a6c1c6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
87 changed files with 1421 additions and 615 deletions

View file

@ -20,10 +20,10 @@ env:
- TEST_PHP_SQL_PWD=Password123
before_install:
- docker pull mcr.microsoft.com/mssql/server:2019-GA-ubuntu-16.04
- docker pull mcr.microsoft.com/mssql/server:2019-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-CTP3.2-ubuntu
- 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 build --build-arg PHPSQLDIR=$PHPSQLDIR -t msphpsql-dev -f Dockerfile-msphpsql .
before_script:

View file

@ -3,6 +3,62 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
## 5.8.0 - 2020-01-31
Updated PECL release packages. Here is the list of updates:
### Added
- Support for PHP 7.4
- Support for [Microsoft ODBC Driver 17.5](
https://docs.microsoft.com/sql/connect/odbc/download-odbc-driver-for-sql-server?view=sql-server-ver15) on all platforms
- Support for Debian 10 and Red Hat 8 - require MS ODBC Driver 17.4+
- Support for macOS Catalina, Alpine Linux 3.11 (experimental), and Ubuntu 19.10 - require ODBC Driver 17.5+
- Feature Request [#929](https://github.com/microsoft/msphpsql/issues/929) - new [Language option](https://github.com/microsoft/msphpsql/wiki/Features#language) - Pull Request [#930](https://github.com/microsoft/msphpsql/pull/930)
- [Data Classification Sensitivity Metadata Retrieval](https://github.com/microsoft/msphpsql/wiki/Features#data-classification-sensitivity-metadata) - requires ODBC Driver 17.4.2+ and [SQL Server 2019](https://www.microsoft.com/sql-server/sql-server-2019)
- Feature Request [#1018](https://github.com/microsoft/msphpsql/issues/1018) - support for [PHP extended string types](https://github.com/microsoft/msphpsql/wiki/Features#natlTypes) - Pull Request [#1043](https://github.com/microsoft/msphpsql/pull/1043)
- [Always Encrypted with secure enclaves](https://github.com/microsoft/msphpsql/wiki/Features#alwaysencryptedV2) - requires ODBC Driver 17.4+ and [SQL Server 2019](https://www.microsoft.com/sql-server/sql-server-2019)
- Feature Request [#1063](https://github.com/microsoft/msphpsql/issues/1063) - add configurable options for locale settings in Linux and macOS - Pull Request [#1069](https://github.com/microsoft/msphpsql/pull/1069)
### Removed
- Dropped support for [PHP 7.1](https://www.php.net/supported-versions.php)
- Dropped support for SQL Server 2008 R2, macOS Sierra, Ubuntu 18.10 and Ubuntu 19.04.
### Fixed
- Issue [#570](https://github.com/microsoft/msphpsql/issues/570) - Fixed fetching varbinary data using client buffer with sqlsrv
- Pull Request [#972](https://github.com/microsoft/msphpsql/pull/972) - Removed redundant calls to retrieve the number of columns or rows in the current query result set
- Pull Request [#978](https://github.com/microsoft/msphpsql/pull/978) - PDO_SQLSRV implementation of PDO::getColumnMeta now references cached metadata rather than making an ODBC call every time
- Pull Request [#979](https://github.com/microsoft/msphpsql/pull/979) - Added support for Data Classification Sensitivity metadata retrieval
- Pull Request [#985](https://github.com/microsoft/msphpsql/pull/985) - Fixed memory issues with Data Classification data structures
- Issue [#432](https://github.com/microsoft/msphpsql/issues/432) - Having any invalid UTF-8 name in the connection string will no longer invoke misleading error messages
- Issue [#909](https://github.com/microsoft/msphpsql/issues/909) - Fixed potential exception with locale issues in macOS
- Pull Request [#992](https://github.com/microsoft/msphpsql/pull/992) - Produced the correct error when requesting Data Classification metadata with ODBC drivers prior to 17
- Pull Request [#1001](https://github.com/microsoft/msphpsql/pull/1001) - Fixed compilation issue with PHP 7.4 alpha
- Pull Request [#1004](https://github.com/microsoft/msphpsql/pull/1004) - Fixed another compilation issue with PHP 7.4 alpha
- Pull Request [#1008](https://github.com/microsoft/msphpsql/pull/1008) - Improved data caching when fetching datetime objects
- Pull Request [#1011](https://github.com/microsoft/msphpsql/pull/1011) - Fixed a potential buffer overflow when parsing for escaped braces in the connection string
- Pull Request [#1015](https://github.com/microsoft/msphpsql/pull/1015) - Fixed compilation issues and addressed various memory leaks detected by PHP 7.4 beta 1
- Issue [#1027](https://github.com/microsoft/msphpsql/issues/1027) - Fixed how drivers handle query timeout settings
- Pull Request [#1049](https://github.com/microsoft/msphpsql/pull/1049) - Performance improvement for fetching from tables with many columns - cached the derived php types with column metadata to streamline data retrieval
- Pull Request [#1068](https://github.com/microsoft/msphpsql/pull/1068) - Some cosmetic changes to source code as per suggestions from a static analysis tool
- Issue [#1079](https://github.com/microsoft/msphpsql/issues/1079) - Support sql_variant types when using client buffers
### 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)
- Alpine Linux support is currently experimental. More robust support will be added in future releases
### Known Issues
- In Alpine Linux, the Client-Side Cursors feature may cause an access violation if both sqlsrv and pdo_sqlsrv are enabled. Either enable only sqlsrv or pdo_sqlsrv, or build PHP from source by compiling the drivers statically.
- 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.7.1-preview - 2019-12-03
Updated PECL release packages. Here is the list of updates:

View file

@ -21,6 +21,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && \
make \
php7.3 \
php7.3-dev \
php7.3-intl \
python-pip \
re2c \
unixodbc-dev \
@ -39,12 +40,14 @@ ENV TEST_PHP_SQL_PWD Password123
# update PATH after ODBC driver and tools are installed
ENV PATH="/opt/mssql-tools/bin:${PATH}"
# add locale iso-8859-1
# add locales for testing
RUN sed -i 's/# en_US ISO-8859-1/en_US ISO-8859-1/g' /etc/locale.gen
RUN locale-gen en_US
RUN sed -i 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/g' /etc/locale.gen
RUN sed -i 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/g' /etc/locale.gen
RUN locale-gen
# set locale to utf-8
RUN locale-gen en_US.UTF-8
# RUN locale-gen en_US.UTF-8
ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' LC_ALL='en_US.UTF-8'
# install coveralls (upgrade both pip and requests first)
@ -65,6 +68,10 @@ RUN /bin/bash -c "./packagize.sh"
RUN echo "; priority=20\nextension=sqlsrv.so\n" > /etc/php/7.3/mods-available/sqlsrv.ini
RUN echo "; priority=30\nextension=pdo_sqlsrv.so\n" > /etc/php/7.3/mods-available/pdo_sqlsrv.ini
# create a writable ini file for testing locales
RUN echo '' > `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/99-overrides.ini
RUN chmod 666 `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/99-overrides.ini
WORKDIR $PHPSQLDIR/source/sqlsrv
RUN /usr/bin/phpize && ./configure LDFLAGS="-lgcov" CXXFLAGS="-O0 --coverage" && make && make install

View file

@ -1,4 +1,4 @@
Copyright(c) 2019 Microsoft Corporation
Copyright(c) 2020 Microsoft Corporation
All rights reserved.
MIT License

View file

@ -1,23 +1,27 @@
# Linux and macOS Installation Tutorial for the Microsoft Drivers for PHP for SQL Server
The following instructions assume a clean environment and show how to install PHP 7.x, the Microsoft ODBC driver, Apache, and the Microsoft Drivers for PHP for SQL Server on Ubuntu, RedHat, Debian, Suse, and macOS. These instructions advise installing the drivers using PECL, but you may 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.x, the Microsoft ODBC driver, the Apache web server, and the Microsoft Drivers for PHP for SQL Server on Ubuntu 16.04, 18.04, and 19.10, RedHat 7 and 8, Debian 8, 9, and 10, Suse 12 and 15, Alpine 3.11 (experimental), and macOS 10.13, 10.14, and 10.15. These instructions advise installing the drivers using PECL, but you can also download the prebuilt binaries from the [Microsoft Drivers for PHP for SQL Server](https://github.com/Microsoft/msphpsql/releases) Github project page and install them following the instructions in [Loading the Microsoft Drivers for PHP for SQL Server](https://docs.microsoft.com/sql/connect/php/loading-the-php-sql-driver). For an explanation of extension loading and why we do not add the extensions to php.ini, see the section on [loading the drivers](https://docs.microsoft.com/sql/connect/php/loading-the-php-sql-driver#loading-the-driver-at-php-startup).
These instructions install PHP 7.4 by default. Note that some supported Linux distros default to PHP 7.1 or earlier, which the PHP drivers for SQL Server no longer support. When installing PHP 7.2 or above, please read the notes at the beginning of each section below.
These instructions install PHP 7.4 by default. Note that some supported Linux distros default to PHP 7.1 or earlier, which is not supported for the latest version of the PHP drivers for SQL Server -- please see the notes at the beginning of each section to install PHP 7.2 or 7.3 instead.
Also included are instructions for installing the PHP FastCGI Process Manager, PHP-FPM, on Ubuntu. This is needed if using the nginx web server instead of Apache.
## Contents of this page:
- [Installing the drivers on Ubuntu 16.04, 18.04, and 19.04](#installing-the-drivers-on-ubuntu-1604-1804-and-1904)
- [Installing the drivers on Ubuntu 16.04, 18.04, and 19.10](#installing-the-drivers-on-ubuntu-1604-1804-and-1910)
- [Installing the drivers with PHP-FPM on Ubuntu](#installing-the-drivers-with-php-fpm-on-ubuntu)
- [Installing the drivers on Red Hat 7 and 8](#installing-the-drivers-on-red-hat-7-and-8)
- [Installing the drivers on Debian 8, 9 and 10](#installing-the-drivers-on-debian-8-9-and-10)
- [Installing the drivers on Debian 8, 9, and 10](#installing-the-drivers-on-debian-8-9-and-10)
- [Installing the drivers on Suse 12 and 15](#installing-the-drivers-on-suse-12-and-15)
- [Installing the drivers on macOS Sierra, High Sierra, Mojave, and Catalina](#installing-the-drivers-on-macos-sierra-high-sierra-mojave-and-catalina)
- [Installing the drivers on Alpine 3.11](#installing-the-drivers-on-alpine-311)
- [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.04
## Installing the drivers on Ubuntu 16.04, 18.04, and 19.10
> [!NOTE]
> To install PHP 7.3 or 7.2, replace 7.4 with 7.3 or 7.2 in the following commands.
> To install PHP 7.2 or 7.3, replace 7.4 with 7.2 or 7.3 in the following commands.
### Step 1. Install PHP
```
```bash
sudo su
add-apt-repository ppa:ondrej/php -y
apt-get update
@ -28,15 +32,16 @@ Install the ODBC driver for Ubuntu by following the instructions on the [Linux a
### Step 3. Install the PHP drivers for Microsoft SQL Server
```
sudo pecl install sqlsrv-5.7.1preview
sudo pecl install pdo_sqlsrv-5.7.1preview
sudo pecl install sqlsrv
sudo pecl install pdo_sqlsrv
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
exit
sudo phpenmod -v 7.4 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`.
If there is only one PHP version in the system, then the last step can be simplified to `phpenmod sqlsrv pdo_sqlsrv`.
### Step 4. Install Apache and configure driver loading
```
@ -53,53 +58,120 @@ sudo service apache2 restart
```
To test your installation, see [Testing your installation](#testing-your-installation) at the end of this document.
## Installing the drivers on Red Hat 7 and 8
## Installing the drivers with PHP-FPM on Ubuntu
> [!NOTE]
> To install PHP 7.3 or 7.2, replace remi-php74 with remi-php73 or remi-php72 respectively in the following commands.
> To install PHP 7.2 or 7.3, replace 7.4 with 7.2 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
```
Verify the status of the PHP-FPM service by running
```
systemctl status php7.4-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).
### 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 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
exit
sudo phpenmod -v 7.4 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/`:
```
ls /etc/php/7.4/fpm/conf.d/*sqlsrv.ini
```
Restart the PHP-FPM service:
```
sudo systemctl restart php7.4-fpm
```
### Step 4. Install and configure nginx
```
sudo apt-get update
sudo apt-get install nginx
sudo systemctl status nginx
```
To configure nginx, you must edit the `/etc/nginx/sites-available/default` file. Add `index.php` to the list below the section that says `# Add index.php to the list if you are using PHP`:
```
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html index.php;
```
Next, modify the section following `# pass PHP scripts to FastCGI server` as follows:
```
# pass PHP scripts to FastCGI server
#
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
}
```
### Step 5. Restart nginx and test the sample script
```
sudo systemctl restart nginx.service
```
To test your installation, see [Testing your installation](#testing-your-installation) at the end of this document.
## Installing the drivers on Red Hat 7 and 8
### Step 1. Install PHP
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.
```
sudo su
wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
wget https://rpms.remirepo.net/enterprise/remi-release-7.rpm
rpm -Uvh remi-release-7.rpm epel-release-latest-7.noarch.rpm
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 update
yum install php php-pdo php-xml php-pear php-devel re2c gcc-c++ gcc
```
### Step 2. Install prerequisites
Install the ODBC driver for Red Hat 7 and 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).
In some versions of Red Hat 7, compiling the PHP drivers with PECL and PHP 7.2 requires a more recent GCC than the default:
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.
```
sudo yum-config-manager --enable rhel-server-rhscl-7-rpms
sudo yum install devtoolset-7
scl enable devtoolset-7 bash
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
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).
### Step 3. Install the PHP drivers for Microsoft SQL Server
```
sudo pecl install sqlsrv-5.7.1preview
sudo pecl install pdo_sqlsrv-5.7.1preview
sudo pecl install sqlsrv
sudo pecl install pdo_sqlsrv
sudo su
echo extension=pdo_sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/30-pdo_sqlsrv.ini
echo extension=sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/20-sqlsrv.ini
exit
```
An issue in PECL may prevent correct installation of the latest version of the drivers even if you have upgraded GCC. To install, download the packages and compile manually (similar steps for pdo_sqlsrv):
```
pecl download sqlsrv-5.7.1preview
tar xvzf sqlsrv-5.7.1preview.tgz
cd sqlsrv-5.7.1preview/
phpize
./configure --with-php-config=/usr/bin/php-config
make
sudo make install
```
You can alternatively download the prebuilt binaries from the [Github project page](https://github.com/Microsoft/msphpsql/releases), or install from the Remi repo:
You can alternatively install from the Remi repo:
```
sudo yum install php-sqlsrv
```
@ -117,10 +189,10 @@ sudo apachectl restart
```
To test your installation, see [Testing your installation](#testing-your-installation) at the end of this document.
## Installing the drivers on Debian 8, 9 and 10
## Installing the drivers on Debian 8, 9, and 10
> [!NOTE]
> To install PHP 7.3 or 7.2, replace 7.4 in the following commands with 7.3 or 7.2.
> To install PHP 7.2 or 7.3, replace 7.4 in the following commands with 7.2 or 7.3.
### Step 1. Install PHP
```
@ -129,7 +201,7 @@ 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
apt-get install -y php7.4 php7.4-dev php7.4-xml php7.4-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).
@ -140,18 +212,20 @@ sudo su
sed -i 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/g' /etc/locale.gen
locale-gen
```
You may need to add `/usr/sbin` to your `$PATH`, as the `locale-gen` executable is located there.
### Step 3. Install the PHP drivers for Microsoft SQL Server
```
sudo pecl install sqlsrv-5.7.1preview
sudo pecl install pdo_sqlsrv-5.7.1preview
sudo pecl install sqlsrv
sudo pecl install pdo_sqlsrv
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
exit
sudo phpenmod -v 7.4 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`.
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`.
### Step 4. Install Apache and configure driver loading
```
@ -170,21 +244,21 @@ 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 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.
> [!NOTE]
> Packages for PHP 7.4 are not available for Suse 12.
> 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`.
> 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`.
> 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`.
### Step 1. Install PHP
```
sudo su
zypper -n ar -f https://download.opensuse.org/repositories/devel:languages:php/<SuseVersion>/devel:languages:php.repo
zypper --gpg-auto-import-keys refresh
zypper -n install php7 php7-pear php7-devel php7-openssl
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).
@ -194,8 +268,8 @@ Install the ODBC driver for Suse by following the instructions on the [Linux and
> 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-5.7.1preview
sudo pecl install pdo_sqlsrv-5.7.1preview
sudo pecl install sqlsrv
sudo pecl install pdo_sqlsrv
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
@ -216,7 +290,52 @@ sudo systemctl restart apache2
```
To test your installation, see [Testing your installation](#testing-your-installation) at the end of this document.
## Installing the drivers on macOS Sierra, High Sierra, Mojave, and Catalina
## Installing the drivers on Alpine 3.11
> [!NOTE]
> Alpine support is experimental.
> [!NOTE]
> The default version of PHP is 7.3. Alternate versions of PHP are not available from other repositories for Alpine 3.11. You can instead compile PHP from source.
### Step 1. Install PHP
PHP packages for Alpine are found in the `edge/community` repository. Add the following line to `/etc/apt/repositories`, replacing `<mirror>` with the URL of an Alpine repository mirror:
```
http://<mirror>/alpine/edge/community
```
Then run:
```
sudo su
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).
### Step 3. Install the PHP drivers for Microsoft SQL Server
```
sudo pecl install sqlsrv
sudo pecl install pdo_sqlsrv
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
```
You may need to define a locale:
```
export LC_ALL=C
```
### Step 4. Install Apache and configure driver loading
```
sudo apk add php7-apache2 apache2
```
### Step 5. Restart Apache and test the sample script
```
sudo rc-service apache2 restart
```
To test your installation, see [Testing your installation](#testing-your-installation) at the end of this document.
## Installing the drivers on macOS High Sierra, Mojave, and Catalina
If you do not already have it, install brew as follows:
```
@ -224,7 +343,7 @@ If you do not already have it, install brew as follows:
```
> [!NOTE]
> To install PHP 7.3 or 7.2, replace php@7.4 with php@7.3 or php@7.2 respectively in the following commands.
> 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.
### Step 1. Install PHP
@ -248,18 +367,18 @@ brew install autoconf automake libtool
### Step 3. Install the PHP drivers for Microsoft SQL Server
```
sudo pecl install sqlsrv-5.7.1preview
sudo pecl install pdo_sqlsrv-5.7.1preview
sudo pecl install sqlsrv
sudo pecl install pdo_sqlsrv
```
### Step 4. Install Apache and configure driver loading
```
brew install apache2
```
To find the Apache configuration file for your Apache installation, run
To find the Apache configuration file, `httpd.conf`, for your Apache installation, run
```
apachectl -V | grep SERVER_CONFIG_FILE
/usr/local/bin/apachectl -V | grep SERVER_CONFIG_FILE
```
and substitute the path for `httpd.conf` in the following commands:
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 "<FilesMatch .php$>"; echo "SetHandler application/x-httpd-php"; echo "</FilesMatch>";) >> /usr/local/etc/httpd/httpd.conf
@ -272,7 +391,7 @@ To test your installation, see [Testing your installation](#testing-your-install
## Testing Your Installation
To test this sample script, create a file called testsql.php in your system's document root. This is `/var/www/html/` on Ubuntu, Debian, and Redhat, `/srv/www/htdocs` on SUSE, or `/usr/local/var/www` on macOS. Copy the following script to it, replacing the server, database, username, and password as appropriate.
To test this sample script, create a file called testsql.php in your system's document root. This is `/var/www/html/` on Ubuntu, Debian, and Redhat, `/srv/www/htdocs` on SUSE, `/var/www/localhost/htdocs` on Alpine, or `/usr/local/var/www` on macOS. Copy the following script to it, replacing the server, database, username, and password as appropriate. On Alpine 3.11, you may also need to specify the **CharacterSet** as 'UTF-8' in the `$connectionOptions` array.
```
<?php
$serverName = "yourServername";
@ -322,4 +441,4 @@ function formatErrors($errors)
}
?>
```
Point your browser to https://localhost/testsql.php (https://localhost:8080/testsql.php on macOS). You should now be able to connect to your SQL Server/Azure SQL database.
Point your browser to https://localhost/testsql.php (https://localhost:8080/testsql.php on macOS). You should now be able to connect to your SQL Server/Azure SQL database.

View file

@ -2,9 +2,9 @@
**Welcome to the Microsoft Drivers for PHP for Microsoft SQL Server**
The Microsoft Drivers for PHP for Microsoft SQL Server are PHP extensions that allow for the reading and writing of SQL Server data from within PHP scripts. The SQLSRV extension provides a procedural interface while the PDO_SQLSRV extension implements PHP Data Objects (PDO) for accessing data in all editions of SQL Server 2008 R2 and later (including Azure SQL DB). These drivers rely on the [Microsoft ODBC Driver for SQL Server][odbcdoc] to handle the low-level communication with SQL Server.
The Microsoft Drivers for PHP for Microsoft SQL Server are PHP extensions that allow for the reading and writing of SQL Server data from within PHP scripts. The SQLSRV extension provides a procedural interface while the PDO_SQLSRV extension implements PHP Data Objects (PDO) for accessing data in all editions of SQL Server 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.1+ 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.2+ with improvements on both drivers and some limitations. Upcoming [releases][releases] will contain additional functionalities, bug fixes, and more.
## Take our survey
@ -51,7 +51,7 @@ On the client machine:
- [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
On the server side, Microsoft SQL Server 2008 R2 and above on Windows are supported, as are Microsoft SQL Server 2016 and above on Linux.
On the server side, Microsoft SQL Server 2012 and above on Windows are supported, as are Microsoft SQL Server 2016 and above on Linux.
## Building and Installing the Drivers on Windows

View file

@ -24,22 +24,22 @@ environment:
SQL_INSTANCE: SQL2017
PHP_VC: 15
PHP_MAJOR_VER: 7.3
PHP_MINOR_VER: 11
PHP_MINOR_VER: latest
PHP_EXE_PATH: x64\Release_TS
THREAD: ts
platform: x64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
BUILD_PLATFORM: x86
TEST_PHP_SQL_SERVER: (local)\SQL2016
SQL_INSTANCE: SQL2016
PHP_VC: 14
PHP_MAJOR_VER: 7.1
PHP_VC: 15
PHP_MAJOR_VER: 7.4
PHP_MINOR_VER: latest
PHP_EXE_PATH: Release
THREAD: nts
platform: x86
# PHP_MAJOR_VER is PHP major version to build (7.2, 7.3)
# PHP_MAJOR_VER is PHP major version to build (7.4, 7.3)
# PHP_MINOR_VER is PHP point release number (or latest for latest release)
# PHP_VC is the Visual C++ version
# PHP_EXE_PATH is the relative path from php src folder to php executable
@ -75,9 +75,9 @@ install:
- ps: |
$client = New-Object Net.WebClient;
$client.Headers.Add("user-agent", "appveyor-ci-build2");
$client.DownloadFile("http://windows.php.net/downloads/releases/sha1sum.txt", "c:\projects\sha1sum.txt");
$client.DownloadFile("http://windows.php.net/downloads/releases/sha256sum.txt", "c:\projects\sha256sum.txt");
If ($env:PHP_MINOR_VER -Match "latest") {
$env:PHP_VERSION=type c:\projects\sha1sum.txt | where { $_ -match "php-($env:PHP_MAJOR_VER\.\d+)-src" } | foreach { $matches[1] } ;
$env:PHP_VERSION=type c:\projects\sha256sum.txt | where { $_ -match "php-($env:PHP_MAJOR_VER\.\d+)-src" } | foreach { $matches[1] } ;
} Else {
$env:PHP_VERSION=$env:PHP_MAJOR_VER + '.' + $env:PHP_MINOR_VER;
}

View file

@ -2,7 +2,7 @@
# https://aka.ms/yaml
variables:
phpVersion: 7.3
phpVersion: 7.4
server: 'localhost,1433'
host: 'sql1'
sqlsrv_db: 'sqlsrv_testdb'
@ -59,6 +59,8 @@ jobs:
displayName: 'Build and install drivers'
- job: Linux
variables:
phpver: 7.3
pool:
vmImage: 'ubuntu-18.04'
steps:
@ -70,15 +72,17 @@ jobs:
inputs:
versionSpec: '3.6'
architecture: 'x64'
- script: |
sudo update-alternatives --set php /usr/bin/php$(phpVersion)
sudo update-alternatives --set phar /usr/bin/phar$(phpVersion)
sudo update-alternatives --set phpdbg /usr/bin/phpdbg$(phpVersion)
sudo update-alternatives --set php-cgi /usr/bin/php-cgi$(phpVersion)
sudo update-alternatives --set phar.phar /usr/bin/phar.phar$(phpVersion)
sudo update-alternatives --set php /usr/bin/php$(phpver)
sudo update-alternatives --set phpize /usr/bin/phpize$(phpver)
sudo update-alternatives --set phar /usr/bin/phar$(phpver)
sudo update-alternatives --set phpdbg /usr/bin/phpdbg$(phpver)
sudo update-alternatives --set php-cgi /usr/bin/php-cgi$(phpver)
sudo update-alternatives --set phar.phar /usr/bin/phar.phar$(phpver)
sudo update-alternatives --set php-config /usr/bin/php-config$(phpver)
php -version
displayName: 'Use PHP version $(phpVersion)'
displayName: 'Use PHP version $(phpver)'
- script: |
echo install ODBC and dependencies
@ -107,15 +111,16 @@ jobs:
- script: |
sudo sed -i 's/# en_US ISO-8859-1/en_US ISO-8859-1/g' /etc/locale.gen
sudo locale-gen en_US
sudo locale-gen en_US.UTF-8
export LANG='en_US.UTF-8'
export LANGUAGE='en_US:en'
sudo sed -i 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/g' /etc/locale.gen
sudo sed -i 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/g' /etc/locale.gen
sudo locale-gen
export LANG='en_US.UTF-8'
export LANGUAGE='en_US:en'
export LC_ALL='en_US.UTF-8'
displayName: 'Generate locales for testing'
- script: |
echo setting env variables
echo setting env variables
export TEST_PHP_SQL_SERVER='$(server)'
export TEST_PHP_SQL_UID='$(uid)'
export TEST_PHP_SQL_PWD='$(pwd)'
@ -127,12 +132,13 @@ jobs:
- script: |
echo ready to build extensions
sudo apt-get install -y php$(phpver)-intl
cd $(Build.SourcesDirectory)/source
chmod a+x packagize.sh
./packagize.sh
dest=`php --ini | grep "Scan for additional .ini files" | sudo sed -e "s|.*:\s*||"`/
cd $(Build.SourcesDirectory)/source/sqlsrv
ls -al
phpize && ./configure && make && sudo make install
@ -141,7 +147,7 @@ jobs:
echo copying sqlsrv to $dest
sudo cp 20-sqlsrv.ini $dest
cd $(Build.SourcesDirectory)/source/pdo_sqlsrv
ls -al
phpize && ./configure && make && sudo make install
@ -151,6 +157,9 @@ jobs:
echo copying pdo_sqlsrv to $dest
sudo cp 30-pdo_sqlsrv.ini $dest
sudo touch $dest/99-overrides.ini
sudo chmod 666 $dest/99-overrides.ini
php --ri sqlsrv
php --ri pdo_sqlsrv
displayName: 'Build and install drivers'
@ -160,8 +169,9 @@ jobs:
sed -i -e 's/TARGET_SERVER/'"$(server)"'/g' MsSetup.inc
sed -i -e 's/TARGET_DATABASE/'"$(sqlsrv_db)"'/g' MsSetup.inc
sed -i -e 's/TARGET_USERNAME/'"$(uid)"'/g' MsSetup.inc
sed -i -e 's/TARGET_PASSWORD/'"$(pwd)"'/g' MsSetup.inc
sed -i -e 's/TARGET_PASSWORD/'"$(pwd)"'/g' MsSetup.inc
export LC_ALL='en_US.UTF-8'
php run-tests.php -P ./*.phpt 2>&1 | tee ../sqlsrv.log
displayName: 'Run sqlsrv functional tests'
@ -170,8 +180,9 @@ jobs:
sed -i -e 's/TARGET_SERVER/'"$(server)"'/g' MsSetup.inc
sed -i -e 's/TARGET_DATABASE/'"$(pdo_sqlsrv_db)"'/g' MsSetup.inc
sed -i -e 's/TARGET_USERNAME/'"$(uid)"'/g' MsSetup.inc
sed -i -e 's/TARGET_PASSWORD/'"$(pwd)"'/g' MsSetup.inc
sed -i -e 's/TARGET_PASSWORD/'"$(pwd)"'/g' MsSetup.inc
export LC_ALL='en_US.UTF-8'
php run-tests.php -P ./*.phpt 2>&1 | tee ../pdo_sqlsrv.log
displayName: 'Run pdo_sqlsrv functional tests'
@ -194,7 +205,7 @@ jobs:
docker stop $(host)
docker rm $(host)
displayName: 'Stop SQL Server for Linux'
condition: always()
condition: always()
- job: Windows
pool:
@ -249,7 +260,7 @@ jobs:
- script: msiexec /i "msodbcsql_13.1.msi" /q IACCEPTMSODBCSQLLICENSETERMS=YES ADDLOCAL=ALL
condition: false
# FOR SOME REASON the set up did not set the PATH
# FOR SOME REASON the set up did not set the PATH
- script: |
msiexec /i "MsSqlCmdLnUtils.msi" /qn IACCEPTMSSQLCMDLNUTILSLICENSETERMS=YES
displayName: 'Install SQL command line utilities version 15'
@ -260,7 +271,7 @@ jobs:
$client.Headers.Add("user-agent", "azure pipeline build")
$client.DownloadFile("https://windows.php.net/downloads/releases/sha256sum.txt", "sha256sum.txt")
$env:VERSION=type sha256sum.txt | where { $_ -match "php-($(phpVersion)\.\d+)-src" } | foreach { $matches[1] }
Write-Host "Latest PHP $(phpVersion) is ${env:VERSION}"
Write-Host "Latest PHP $(phpVersion) is ${env:VERSION}"
cd $(Build.SourcesDirectory)/buildscripts/
python builddrivers.py --PHPVER=${env:VERSION} --DRIVER=sqlsrv --ARCH=x64 --THREAD=nts --SOURCE=$(Build.SourcesDirectory)/source --TESTING --NO_RENAME
dir *sqlsrv*.dll
@ -270,7 +281,7 @@ jobs:
dir *sqlsrv*.dll
cp *sqlsrv*.dll C:\tools\php\ext\
displayName: 'Build drivers (separately) for the latest version of PHP $(phpVersion)'
- script: |
echo extension=php_sqlsrv.dll >> C:\tools\php\php.ini
echo extension=php_pdo_sqlsrv.dll >> C:\tools\php\php.ini
@ -285,7 +296,7 @@ jobs:
displayName: 'Run SQL Server for Windows Server'
condition: false
- script: |
- script: |
set path=C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\;%path%
sqlcmd -S $(host) -U $(uid) -P $(pwd) -Q "SELECT @@Version"
set TEST_PHP_SQL_SERVER=$(host)
@ -309,4 +320,4 @@ jobs:
docker stop sqlcontainer
docker rm sqlcontainer
displayName: 'Stop SQL Server for Windows Server'
condition: false
condition: false

View file

@ -4,7 +4,7 @@ dnl
dnl Contents: the code that will go into the configure script, indicating options,
dnl external libraries and includes, and what source files are to be compiled.
dnl
dnl Microsoft Drivers 5.7 for PHP for SQL Server
dnl Microsoft Drivers 5.8 for PHP for SQL Server
dnl Copyright(c) Microsoft Corporation
dnl All rights reserved.
dnl MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: JScript build configuration used by buildconf.bat
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: Implements the PDO object for PDO_SQLSRV
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
@ -1105,7 +1105,7 @@ int pdo_sqlsrv_dbh_set_attr( _Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout
}
break;
#if PHP_VERSION_ID >= 70200
#if PHP_VERSION_ID >= 70200
case PDO_ATTR_DEFAULT_STR_PARAM:
{
if (Z_TYPE_P(val) != IS_LONG) {
@ -1297,7 +1297,7 @@ int pdo_sqlsrv_dbh_get_attr( _Inout_ pdo_dbh_t *dbh, _In_ zend_long attr, _Inout
break;
}
#if PHP_VERSION_ID >= 70200
#if PHP_VERSION_ID >= 70200
case PDO_ATTR_DEFAULT_STR_PARAM:
{
ZVAL_LONG(return_value, (driver_dbh->use_national_characters == 0) ? PDO_PARAM_STR_CHAR : PDO_PARAM_STR_NATL);
@ -1523,12 +1523,12 @@ int pdo_sqlsrv_dbh_quote( _Inout_ pdo_dbh_t* dbh, _In_reads_(unquoted_len) const
}
use_national_char_set = (driver_dbh->use_national_characters == 1 || encoding == SQLSRV_ENCODING_UTF8);
#if PHP_VERSION_ID >= 70200
if ((paramtype & PDO_PARAM_STR_NATL) == PDO_PARAM_STR_NATL) {
use_national_char_set = true;
}
if ((paramtype & PDO_PARAM_STR_CHAR) == PDO_PARAM_STR_CHAR) {
use_national_char_set = false;
#if PHP_VERSION_ID >= 70200
if ((paramtype & PDO_PARAM_STR_NATL) == PDO_PARAM_STR_NATL) {
use_national_char_set = true;
}
if ((paramtype & PDO_PARAM_STR_CHAR) == PDO_PARAM_STR_CHAR) {
use_national_char_set = false;
}
#endif

View file

@ -3,7 +3,7 @@
//
// Contents: initialization routines for PDO_SQLSRV
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
@ -220,6 +220,22 @@ PHP_RINIT_FUNCTION(pdo_sqlsrv)
ZEND_TSRMLS_CACHE_UPDATE();
#endif
#ifndef _WIN32
// if necessary, set locale from the environment for ODBC, which MUST be done before any connection
int set_locale = PDO_SQLSRV_G(set_locale_info);
if (set_locale == 2) {
setlocale(LC_ALL, "");
LOG(SEV_NOTICE, "pdo_sqlsrv: setlocale LC_ALL");
}
else if (set_locale == 1) {
setlocale(LC_CTYPE, "");
LOG(SEV_NOTICE, "pdo_sqlsrv: setlocale LC_CTYPE");
}
else {
LOG(SEV_NOTICE, "pdo_sqlsrv: setlocale NONE");
}
#endif
LOG( SEV_NOTICE, "pdo_sqlsrv: entering rinit" );
return SUCCESS;

View file

@ -5,7 +5,7 @@
//
// Copyright Microsoft Corporation
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: Implements the PDOStatement object for the PDO_SQLSRV
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: Utility functions used by both connection or statement functions
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -6,7 +6,7 @@
//
// Contents: Declarations for the extension
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
@ -32,6 +32,10 @@ ZEND_BEGIN_MODULE_GLOBALS(pdo_sqlsrv)
unsigned int log_severity;
zend_long client_buffer_max_size;
#ifndef _WIN32
zend_long set_locale_info;
#endif
ZEND_END_MODULE_GLOBALS(pdo_sqlsrv)
ZEND_EXTERN_MODULE_GLOBALS(pdo_sqlsrv);

View file

@ -6,7 +6,7 @@
//
// Contents: Internal declarations for the extension
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
@ -55,11 +55,19 @@ extern HMODULE g_sqlsrv_hmodule;
#define INI_PDO_SQLSRV_LOG "log_severity"
#define INI_PREFIX "pdo_sqlsrv."
#ifndef _WIN32
#define INI_PDO_SET_LOCALE_INFO "set_locale_info"
#endif
PHP_INI_BEGIN()
STD_PHP_INI_ENTRY( INI_PREFIX INI_PDO_SQLSRV_LOG , "0", PHP_INI_ALL, OnUpdateLong, log_severity,
zend_pdo_sqlsrv_globals, pdo_sqlsrv_globals )
STD_PHP_INI_ENTRY( INI_PREFIX INI_PDO_SQLSRV_CLIENT_BUFFER_MAX_SIZE , INI_BUFFERED_QUERY_LIMIT_DEFAULT, PHP_INI_ALL, OnUpdateLong,
client_buffer_max_size, zend_pdo_sqlsrv_globals, pdo_sqlsrv_globals )
#ifndef _WIN32
STD_PHP_INI_ENTRY(INI_PREFIX INI_PDO_SET_LOCALE_INFO, "2", PHP_INI_ALL, OnUpdateLong, set_locale_info,
zend_pdo_sqlsrv_globals, pdo_sqlsrv_globals)
#endif
PHP_INI_END()

View file

@ -3,7 +3,7 @@
//
// Contents: Version resource
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -6,7 +6,7 @@
// Contents: Contains functions for handling Windows format strings
// and UTF-16 on non-Windows platforms
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -4,7 +4,7 @@
// Contents: Contains functions for handling Windows format strings
// and UTF-16 on non-Windows platforms
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: Contains functions for handling UTF-16 on non-Windows platforms
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: Contains functions for handling UTF-16 on non-Windows platforms
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: Core routines that use connection handles shared between sqlsrv and pdo_sqlsrv
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: common initialization routines shared by PDO and sqlsrv
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
@ -39,12 +39,6 @@ void core_sqlsrv_minit( _Outptr_ sqlsrv_context** henv_cp, _Inout_ sqlsrv_contex
SQLSRV_STATIC_ASSERT( sizeof( sqlsrv_sqltype ) == sizeof( zend_long ) );
SQLSRV_STATIC_ASSERT( sizeof( sqlsrv_phptype ) == sizeof( zend_long ));
#ifndef _WIN32
// set locale from environment
// this is necessary for ODBC and MUST be done before connection
setlocale(LC_ALL, "");
#endif
*henv_cp = *henv_ncp = SQL_NULL_HANDLE; // initialize return values to NULL
try {

View file

@ -3,7 +3,7 @@
//
// Contents: Result sets
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
@ -508,6 +508,7 @@ sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( _Inout_ sqlsrv_stmt* stm
break;
case SQL_CHAR:
case SQL_VARCHAR:
case SQL_SS_VARIANT:
if ( meta[i].length == sqlsrv_buffered_result_set::meta_data::SIZE_UNKNOWN ) {
offset += sizeof( void* );
}
@ -610,6 +611,7 @@ sqlsrv_buffered_result_set::sqlsrv_buffered_result_set( _Inout_ sqlsrv_stmt* stm
case SQL_CHAR:
case SQL_VARCHAR:
case SQL_SS_VARIANT:
case SQL_LONGVARCHAR:
// If encoding is set to UTF-8, the following types are not necessarily column size.
// We need to call SQLGetData with c_type SQL_C_WCHAR and set the size accordingly.

View file

@ -6,17 +6,17 @@
//
// Contents: Core routines and constants shared by the Microsoft Drivers for PHP for SQL Server
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""),
// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""),
// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//---------------------------------------------------------------------------------------------------------------------------------
@ -28,7 +28,7 @@
#undef SQL_WCHART_CONVERT
#endif
#ifndef _WCHART_DEFINED
#define _WCHART_DEFINED
#define _WCHART_DEFINED
#endif
#include "php.h"
@ -54,8 +54,6 @@
#define PHP_SQLSRV_API
#endif
// #define MultiByteToWideChar SystemLocale::ToUtf16
#define stricmp strcasecmp
#define strnicmp strncasecmp
#define strnlen_s(s) strnlen_s(s, INT_MAX)
@ -103,10 +101,10 @@ extern "C" {
#endif
#if _MSC_VER >= 1400
// typedef and macro to prevent a conflict between php.h and ws2tcpip.h.
// php.h defines this constant as unsigned int which causes a compile error
// typedef and macro to prevent a conflict between php.h and ws2tcpip.h.
// php.h defines this constant as unsigned int which causes a compile error
// in ws2tcpip.h. Fortunately php.h allows an override by defining
// HAVE_SOCKLEN_T. Since ws2tcpip.h isn't included until later, we define
// HAVE_SOCKLEN_T. Since ws2tcpip.h isn't included until later, we define
// socklen_t here and override the php.h version.
typedef int socklen_t;
#define HAVE_SOCKLEN_T
@ -142,7 +140,7 @@ OACR_WARNING_POP
#define WC_ERR_INVALID_CHARS 0x00000080 // error for invalid chars
#endif
// PHP defines inline as __forceinline, which in debug mode causes a warning to be emitted when
// PHP defines inline as __forceinline, which in debug mode causes a warning to be emitted when
// we use std::copy, which causes compilation to fail since we compile with warnings as errors.
#if defined(ZEND_DEBUG) && defined(inline)
#undef inline
@ -190,7 +188,7 @@ const long ACTIVE_NUM_ROWS_INVALID = -99;
const int SQL_SERVER_2005_DEFAULT_DATETIME_PRECISION = 23;
const int SQL_SERVER_2005_DEFAULT_DATETIME_SCALE = 3;
const int SQL_SERVER_2008_DEFAULT_DATETIME_PRECISION = 34;
const int SQL_SERVER_2008_DEFAULT_DATETIME_SCALE = 7;
const int SQL_SERVER_2008_DEFAULT_DATETIME_SCALE = 7;
namespace AzureADOptions {
const char AZURE_AUTH_SQL_PASSWORD[] = "SqlPassword";
@ -215,7 +213,7 @@ enum SQLSRV_PHPTYPE {
};
// encodings supported by this extension. These basically translate into the use of SQL_C_CHAR or SQL_C_BINARY when getting
// information as a string or a stream.
// information as a string or a stream.
enum SQLSRV_ENCODING {
SQLSRV_ENCODING_INVALID, // unknown or invalid encoding. Used to initialize variables.
SQLSRV_ENCODING_DEFAULT, // use what is the connection's default for a statement, use system if a connection
@ -263,7 +261,7 @@ union sqlsrv_sqltype {
// SQLSRV PHP types (as opposed to the Zend PHP type constants). Contains the type (see SQLSRV_PHPTYPE)
// and the encoding for strings and streams (see SQLSRV_ENCODING)
// and the encoding for strings and streams (see SQLSRV_ENCODING)
union sqlsrv_phptype {
@ -325,8 +323,8 @@ void die( _In_opt_ const char* msg, ... );
#pragma push_macro( "max" )
#undef max
// new memory allocation/free debugging facilities to help us verify that all allocations are being
// released in a timely manner and not just at the end of the script.
// new memory allocation/free debugging facilities to help us verify that all allocations are being
// released in a timely manner and not just at the end of the script.
// Zend has memory logging and checking, but it can generate a lot of noise for just one extension.
// It's meant for internal use but might be useful for people adding features to our extension.
// To use it, uncomment the #define below and compile in Debug NTS. All allocations and releases
@ -435,7 +433,7 @@ struct remove_const<const T*> {
// this allows us to use STL classes that still work with Zend objects
template<typename T>
struct sqlsrv_allocator {
// typedefs used by the STL classes
typedef T value_type;
typedef value_type* pointer;
@ -459,8 +457,8 @@ struct sqlsrv_allocator {
// address (doesn't work if the class defines operator&)
inline pointer address( _In_ reference r )
{
return &r;
{
return &r;
}
inline const_pointer address( _In_ const_reference r )
@ -469,20 +467,20 @@ struct sqlsrv_allocator {
}
// memory allocation/deallocation
inline pointer allocate( _In_ size_type cnt,
inline pointer allocate( _In_ size_type cnt,
typename std::allocator<void>::const_pointer = 0 )
{
return reinterpret_cast<pointer>( sqlsrv_malloc(cnt, sizeof (T), 0));
return reinterpret_cast<pointer>( sqlsrv_malloc(cnt, sizeof (T), 0));
}
inline void deallocate( _Inout_ pointer p, size_type )
{
sqlsrv_free(p);
inline void deallocate( _Inout_ pointer p, size_type )
{
sqlsrv_free(p);
}
// size
inline size_type max_size( void ) const
{
inline size_type max_size( void ) const
{
return std::numeric_limits<size_type>::max() / sizeof(T);
}
@ -507,11 +505,11 @@ struct sqlsrv_allocator {
{
return !operator==(a);
}
};
};
// base class for auto_ptrs that we define below. It provides common operators and functions
// used by all the classes.
// base class for auto_ptrs that we define below. It provides common operators and functions
// used by all the classes.
template <typename T, typename Subclass>
class sqlsrv_auto_ptr {
@ -576,8 +574,8 @@ public:
return _ptr[index];
}
#ifdef __WIN64
#ifdef __WIN64
// there are a number of places where we allocate a block intended to be accessed as
// an array of elements, so this operator allows us to treat the memory as such.
T& operator[]( _In_ std::size_t index ) const
@ -616,7 +614,7 @@ public:
protected:
sqlsrv_auto_ptr( _In_opt_ T* ptr ) :
_ptr( ptr )
_ptr( ptr )
{
}
@ -637,7 +635,7 @@ protected:
return ptr;
}
T* _ptr;
T* _ptr;
};
// an auto_ptr for sqlsrv_malloc/sqlsrv_free. When allocating a chunk of memory using sqlsrv_malloc, wrap that pointer
@ -684,13 +682,13 @@ public:
// DO NOT CALL sqlsrv_realloc with a sqlsrv_malloc_auto_ptr. Use the resize member function.
// has the same parameter list as sqlsrv_realloc: new_size is the size in bytes of the newly allocated buffer
void resize( _In_ size_t new_size )
{
{
sqlsrv_auto_ptr<T,sqlsrv_malloc_auto_ptr<T> >::_ptr = reinterpret_cast<T*>( sqlsrv_realloc( sqlsrv_auto_ptr<T,sqlsrv_malloc_auto_ptr<T> >::_ptr, new_size ));
}
};
// auto ptr for Zend hash tables. Used to clean up a hash table allocated when
// auto ptr for Zend hash tables. Used to clean up a hash table allocated when
// something caused an early exit from the function. This is used when the hash_table is
// allocated in a zval that itself can't be released. Otherwise, use the zval_auto_ptr.
@ -726,8 +724,8 @@ private:
};
// an auto_ptr for zvals. When allocating a zval, wrap that pointer in a variable of zval_auto_ptr.
// zval_auto_ptr will "own" that zval and assure that it is freed when the variable is destroyed
// an auto_ptr for zvals. When allocating a zval, wrap that pointer in a variable of zval_auto_ptr.
// zval_auto_ptr will "own" that zval and assure that it is freed when the variable is destroyed
// (out of scope) or ownership is transferred using the function "transferred".
class zval_auto_ptr : public sqlsrv_auto_ptr<zval, zval_auto_ptr> {
@ -798,7 +796,7 @@ struct sqlsrv_error : public sqlsrv_error_const {
native_code = code;
format = printf_format;
}
sqlsrv_error( _In_ sqlsrv_error_const const& prototype )
{
sqlsrv_error( prototype.sqlstate, prototype.native_message, prototype.native_code, prototype.format );
@ -865,8 +863,8 @@ class sqlsrv_context;
struct sqlsrv_conn;
// error_callback
// a driver specific callback for processing errors.
// ctx - the context holding the handles
// 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 TSRMLS_DC, _In_opt_ va_list* print_args );
@ -910,7 +908,7 @@ class sqlsrv_context {
}
virtual ~sqlsrv_context()
{
{
}
void set_func( _In_z_ const char* f )
@ -927,7 +925,7 @@ class sqlsrv_context {
{
return last_error_;
}
// since the primary responsibility of a context is to hold an ODBC handle, we
// provide these convenience operators for using them interchangeably
operator SQLHANDLE ( void ) const
@ -997,7 +995,7 @@ class sqlsrv_context {
error_callback err_; // driver error callback if error occurs in core layer
void* driver_; // points back to the driver for PDO
sqlsrv_error_auto_ptr last_error_; // last error that happened on this object
SQLSRV_ENCODING encoding_; // encoding of the context
SQLSRV_ENCODING encoding_; // encoding of the context
};
// maps an IANA encoding to a code page
@ -1064,7 +1062,7 @@ enum DRIVER_VERSION {
struct sqlsrv_stmt;
struct stmt_option;
// This holds the various details of column encryption.
// This holds the various details of column encryption.
struct col_encryption_option {
bool enabled; // column encryption enabled, false by default
SQLINTEGER akv_mode;
@ -1105,13 +1103,13 @@ struct sqlsrv_conn : public sqlsrv_context {
driver_version = ODBC_DRIVER_UNKNOWN;
}
// sqlsrv_conn has no destructor since its allocated using placement new, which requires that the destructor be
// sqlsrv_conn has no destructor since its allocated using placement new, which requires that the destructor be
// called manually. Instead, we leave it to the allocator to invalidate the handle when an error occurs allocating
// the sqlsrv_conn with a connection.
};
enum SQLSRV_STMT_OPTIONS {
SQLSRV_STMT_OPTION_INVALID,
SQLSRV_STMT_OPTION_QUERY_TIMEOUT,
SQLSRV_STMT_OPTION_SEND_STREAMS_AT_EXEC,
@ -1164,7 +1162,7 @@ const char SERVER[] = "Server";
}
enum SQLSRV_CONN_OPTIONS {
SQLSRV_CONN_OPTION_INVALID,
SQLSRV_CONN_OPTION_APP,
SQLSRV_CONN_OPTION_ACCESS_TOKEN,
@ -1200,7 +1198,7 @@ enum SQLSRV_CONN_OPTIONS {
// Driver specific connection options
SQLSRV_CONN_OPTION_DRIVER_SPECIFIC = 1000,
};
@ -1220,7 +1218,7 @@ struct connection_option {
// the name of the option as passed in by the user
const char * sqlsrv_name;
unsigned int sqlsrv_len;
unsigned int conn_option_key;
// the name of the option in the ODBC connection string
const char * odbc_name;
@ -1247,7 +1245,7 @@ struct column_encryption_set_func {
static void func( _In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str TSRMLS_DC );
};
struct driver_set_func {
struct driver_set_func {
static void func( _In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str TSRMLS_DC );
};
@ -1265,8 +1263,8 @@ typedef sqlsrv_conn* (*driver_conn_factory)( _In_ SQLHANDLE h, _In_ error_callba
// *** connection functions ***
sqlsrv_conn* core_sqlsrv_connect( _In_ sqlsrv_context& henv_cp, _In_ sqlsrv_context& henv_ncp, _In_ driver_conn_factory conn_factory,
_Inout_z_ const char* server, _Inout_opt_z_ const char* uid, _Inout_opt_z_ const char* pwd,
_Inout_opt_ HashTable* options_ht, _In_ error_callback err, _In_ const connection_option valid_conn_opts[],
_Inout_z_ const char* server, _Inout_opt_z_ const char* uid, _Inout_opt_z_ const char* pwd,
_Inout_opt_ HashTable* options_ht, _In_ error_callback err, _In_ const connection_option valid_conn_opts[],
_In_ void* driver, _In_z_ const char* driver_func TSRMLS_DC );
SQLRETURN core_odbc_connect( _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str, _In_ bool is_pooled );
void core_sqlsrv_close( _Inout_opt_ sqlsrv_conn* conn TSRMLS_DC );
@ -1332,9 +1330,9 @@ struct stmt_option {
const char * name; // name of the statement option
unsigned int name_len; // name length
unsigned int key;
unsigned int key;
std::unique_ptr<stmt_option_functor> func; // callback that actually handles the work of the option
};
// holds the stream param and the encoding that it was assigned
@ -1368,9 +1366,9 @@ extern php_stream_wrapper g_sqlsrv_stream_wrapper;
// *** parameter metadata struct ***
struct param_meta_data
{
SQLSMALLINT sql_type;
SQLSMALLINT sql_type;
SQLSMALLINT decimal_digits;
SQLSMALLINT nullable;
SQLSMALLINT nullable;
SQLULEN column_size;
param_meta_data() : sql_type(0), decimal_digits(0), column_size(0), nullable(0)
@ -1416,16 +1414,16 @@ struct sqlsrv_output_param {
{
}
void saveMetaData(SQLSMALLINT sql_type, SQLSMALLINT column_size, SQLSMALLINT decimal_digits, SQLSMALLINT nullable = SQL_NULLABLE)
{
void saveMetaData(SQLSMALLINT sql_type, SQLSMALLINT column_size, SQLSMALLINT decimal_digits, SQLSMALLINT nullable = SQL_NULLABLE)
{
meta_data.sql_type = sql_type;
meta_data.column_size = column_size;
meta_data.decimal_digits = decimal_digits;
meta_data.nullable = nullable;
}
param_meta_data& getMetaData()
{
param_meta_data& getMetaData()
{
return meta_data;
}
};
@ -1472,13 +1470,13 @@ namespace data_classification {
{
}
~column_sensitivity()
~column_sensitivity()
{
label_info_pairs.clear();
}
};
struct sensitivity_metadata {
struct sensitivity_metadata {
USHORT num_labels;
std::vector<name_id_pair*, sqlsrv_allocator<name_id_pair*>> labels;
USHORT num_infotypes;
@ -1491,7 +1489,7 @@ namespace data_classification {
}
~sensitivity_metadata()
{
{
reset();
}
@ -1503,7 +1501,7 @@ namespace data_classification {
struct sqlsrv_result_set;
struct field_meta_data;
// *** Statement resource structure ***
// *** Statement resource structure ***
struct sqlsrv_stmt : public sqlsrv_context {
void free_param_data( TSRMLS_D );
@ -1513,13 +1511,13 @@ struct sqlsrv_stmt : public sqlsrv_context {
void clean_up_sensitivity_metadata();
sqlsrv_conn* conn; // Connection that created this statement
bool executed; // Whether the statement has been executed yet (used for error messages)
bool past_fetch_end; // Core_sqlsrv_fetch sets this field when the statement goes beyond the last row
sqlsrv_result_set* current_results; // Current result set
SQLULEN cursor_type; // Type of cursor for the current result set
bool has_rows; // Has_rows is set if there are actual rows in the row set
bool fetch_called; // Used by core_sqlsrv_get_field to return an informative error if fetch not yet called
bool fetch_called; // Used by core_sqlsrv_get_field to return an informative error if fetch not yet called
int last_field_index; // last field retrieved by core_sqlsrv_get_field
bool past_next_result_end; // core_sqlsrv_next_result sets this to true when the statement goes beyond the last results
short column_count; // Number of columns in the current result set obtained from SQLNumResultCols
@ -1529,7 +1527,7 @@ struct sqlsrv_stmt : public sqlsrv_context {
bool date_as_string; // false by default but the user can set this to true to retrieve datetime values as strings
bool format_decimals; // false by default but the user can set this to true to add the missing leading zeroes and/or control number of decimal digits to show
short decimal_places; // indicates number of decimals shown in fetched results (-1 by default, which means no change to number of decimal digits)
bool data_classification; // false by default but the user can set this to true to retrieve data classification sensitivity metadata
bool data_classification; // false by default but the user can set this to true to retrieve data classification sensitivity metadata
// holds output pointers for SQLBindParameter
// We use a deque because it 1) provides the at/[] access in constant time, and 2) grows dynamically without moving
@ -1541,10 +1539,10 @@ struct sqlsrv_stmt : public sqlsrv_context {
zval param_datetime_buffers; // datetime strings to be converted back to DateTime objects
bool send_streams_at_exec; // send all stream data right after execution before returning
sqlsrv_stream current_stream; // current stream sending data to the server as an input parameter
unsigned int current_stream_read; // # of bytes read so far. (if we read an empty PHP stream, we send an empty string
unsigned int current_stream_read; // # of bytes read so far. (if we read an empty PHP stream, we send an empty string
// to the server)
zval field_cache; // cache for a single row of fields, to allow multiple and out of order retrievals
zval col_cache; // Used by get_field_as_string not to call SQLColAttribute() after every fetch.
zval col_cache; // Used by get_field_as_string not to call SQLColAttribute() after every fetch.
zval active_stream; // the currently active stream reading data from the database
std::vector<param_meta_data> param_descriptions;
@ -1573,7 +1571,7 @@ struct field_meta_data {
SQLSMALLINT field_type;
SQLULEN field_size;
SQLULEN field_precision;
SQLSMALLINT field_scale;
SQLSMALLINT field_scale;
SQLSMALLINT field_is_nullable;
bool field_is_money_type;
sqlsrv_phptype sqlsrv_php_type;
@ -1584,7 +1582,7 @@ struct field_meta_data {
reset_php_type();
}
~field_meta_data()
~field_meta_data()
{
}
@ -1614,7 +1612,7 @@ const size_t SQLSRV_CURSOR_BUFFERED = 0xfffffffeUL; // arbitrary number that doe
typedef sqlsrv_stmt* (*driver_stmt_factory)( sqlsrv_conn* conn, SQLHANDLE h, error_callback e, void* drv TSRMLS_DC );
// *** statement functions ***
sqlsrv_stmt* core_sqlsrv_create_stmt( _Inout_ sqlsrv_conn* conn, _In_ driver_stmt_factory stmt_factory, _In_opt_ HashTable* options_ht,
sqlsrv_stmt* core_sqlsrv_create_stmt( _Inout_ sqlsrv_conn* conn, _In_ driver_stmt_factory stmt_factory, _In_opt_ HashTable* options_ht,
_In_opt_ const stmt_option valid_stmt_opts[], _In_ error_callback const err, _In_opt_ void* driver TSRMLS_DC );
void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_num, _In_ SQLSMALLINT direction, _Inout_ zval* param_z,
_In_ SQLSRV_PHPTYPE php_out_type, _Inout_ SQLSRV_ENCODING encoding, _Inout_ SQLSMALLINT sql_type, _Inout_ SQLULEN column_size,
@ -1660,7 +1658,7 @@ struct sqlsrv_result_set {
virtual SQLRETURN get_data( _In_ SQLUSMALLINT field_index, _In_ SQLSMALLINT target_type,
_Out_writes_bytes_opt_(buffer_length) void* buffer, _In_ SQLLEN buffer_length, _Inout_ SQLLEN* out_buffer_length,
bool handle_warning TSRMLS_DC )= 0;
virtual SQLRETURN get_diag_field( _In_ SQLSMALLINT record_number, _In_ SQLSMALLINT diag_identifier,
virtual SQLRETURN get_diag_field( _In_ SQLSMALLINT record_number, _In_ SQLSMALLINT diag_identifier,
_Inout_updates_(buffer_length) SQLPOINTER diag_info_buffer, _In_ SQLSMALLINT buffer_length,
_Inout_ SQLSMALLINT* out_buffer_length TSRMLS_DC ) = 0;
virtual sqlsrv_error* get_diag_rec( _In_ SQLSMALLINT record_number ) = 0;
@ -1677,7 +1675,7 @@ struct sqlsrv_odbc_result_set : public sqlsrv_result_set {
virtual SQLRETURN get_data( _In_ SQLUSMALLINT field_index, _In_ SQLSMALLINT target_type,
_Out_writes_opt_(buffer_length) void* buffer, _In_ SQLLEN buffer_length, _Inout_ SQLLEN* out_buffer_length,
_In_ bool handle_warning TSRMLS_DC );
virtual SQLRETURN get_diag_field( _In_ SQLSMALLINT record_number, _In_ SQLSMALLINT diag_identifier,
virtual SQLRETURN get_diag_field( _In_ SQLSMALLINT record_number, _In_ SQLSMALLINT diag_identifier,
_Inout_updates_(buffer_length) SQLPOINTER diag_info_buffer, _In_ SQLSMALLINT buffer_length,
_Inout_ SQLSMALLINT* out_buffer_length TSRMLS_DC );
virtual sqlsrv_error* get_diag_rec( _In_ SQLSMALLINT record_number );
@ -1715,13 +1713,13 @@ struct sqlsrv_buffered_result_set : public sqlsrv_result_set {
virtual SQLRETURN get_data( _In_ SQLUSMALLINT field_index, _In_ SQLSMALLINT target_type,
_Out_writes_bytes_opt_(buffer_length) void* buffer, _In_ SQLLEN buffer_length, _Inout_ SQLLEN* out_buffer_length,
bool handle_warning TSRMLS_DC );
virtual SQLRETURN get_diag_field( _In_ SQLSMALLINT record_number, _In_ SQLSMALLINT diag_identifier,
virtual SQLRETURN get_diag_field( _In_ SQLSMALLINT record_number, _In_ SQLSMALLINT diag_identifier,
_Inout_updates_(buffer_length) SQLPOINTER diag_info_buffer, _In_ SQLSMALLINT buffer_length,
_Inout_ SQLSMALLINT* out_buffer_length TSRMLS_DC );
virtual sqlsrv_error* get_diag_rec( _In_ SQLSMALLINT record_number );
virtual SQLLEN row_count( TSRMLS_D );
// buffered result set specific
// buffered result set specific
SQLSMALLINT column_count( void )
{
return col_count;
@ -1758,7 +1756,7 @@ struct sqlsrv_buffered_result_set : public sqlsrv_result_set {
// string conversion functions
SQLRETURN binary_to_wide_string( _In_ SQLSMALLINT field_index, _Out_writes_z_(*out_buffer_length) void* buffer, _In_ SQLLEN buffer_length,
_Inout_ SQLLEN* out_buffer_length );
SQLRETURN binary_to_system_string( _In_ SQLSMALLINT field_index, _Out_writes_z_(*out_buffer_length) void* buffer, _In_ SQLLEN buffer_length,
SQLRETURN binary_to_system_string( _In_ SQLSMALLINT field_index, _Out_writes_z_(*out_buffer_length) void* buffer, _In_ SQLLEN buffer_length,
_Inout_ SQLLEN* out_buffer_length );
SQLRETURN system_to_wide_string( _In_ SQLSMALLINT field_index, _Out_writes_z_(*out_buffer_length) void* buffer, _In_ SQLLEN buffer_length,
_Out_ SQLLEN* out_buffer_length );
@ -1839,7 +1837,7 @@ enum SQLSRV_ERROR_CODES {
SQLSRV_ERROR_INPUT_PARAM_ENCODING_TRANSLATE,
SQLSRV_ERROR_OUTPUT_PARAM_ENCODING_TRANSLATE,
SQLSRV_ERROR_CONNECT_STRING_ENCODING_TRANSLATE,
SQLSRV_ERROR_ZEND_STREAM,
SQLSRV_ERROR_ZEND_STREAM,
SQLSRV_ERROR_INPUT_STREAM_ENCODING_TRANSLATE,
SQLSRV_ERROR_UNKNOWN_SERVER_VERSION,
SQLSRV_ERROR_FETCH_PAST_END,
@ -1910,11 +1908,11 @@ enum error_handling_flags {
// 2/code) driver specific error code
// 3/message) driver specific error message
// The fetch type determines if the indices are numeric, associative, or both.
bool core_sqlsrv_get_odbc_error( _Inout_ sqlsrv_context& ctx, _In_ int record_number, _Inout_ sqlsrv_error_auto_ptr& error,
bool core_sqlsrv_get_odbc_error( _Inout_ sqlsrv_context& ctx, _In_ int record_number, _Inout_ sqlsrv_error_auto_ptr& error,
_In_ logging_severity severity TSRMLS_DC );
// format and return a driver specfic error
void core_sqlsrv_format_driver_error( _In_ sqlsrv_context& ctx, _In_ sqlsrv_error_const const* custom_error,
void core_sqlsrv_format_driver_error( _In_ sqlsrv_context& ctx, _In_ sqlsrv_error_const const* custom_error,
_Out_ sqlsrv_error_auto_ptr& formatted_error, _In_ logging_severity severity TSRMLS_DC, _In_opt_ va_list* args );
@ -1949,19 +1947,19 @@ inline bool call_error_handler( _Inout_ sqlsrv_context* ctx, _In_ unsigned long
// we don't want on a web server
#define SQLSRV_ASSERT( condition, msg, ...) if( !(condition)) DIE( msg, ## __VA_ARGS__ );
#if defined( PHP_DEBUG )
#if defined( PHP_DEBUG )
#define DEBUG_SQLSRV_ASSERT( condition, msg, ... ) \
if( !(condition)) { \
DIE (msg, ## __VA_ARGS__ ); \
}
}
#else
#define DEBUG_SQLSRV_ASSERT( condition, msg, ... ) ((void)0)
#endif
#endif
// check to see if the sqlstate is 01004, truncated field retrieved. Used for retrieving large fields.
inline bool is_truncated_warning( _In_ SQLCHAR* state )
@ -1984,7 +1982,7 @@ inline bool is_truncated_warning( _In_ SQLCHAR* state )
ignored##unique = call_error_handler( context, ssphp TSRMLS_CC, /*warning*/false, ## __VA_ARGS__ ); \
} \
if( !ignored##unique )
#define CHECK_ERROR_UNIQUE( unique, condition, context, ssphp, ...) \
CHECK_ERROR_EX( unique, condition, context, ssphp, ## __VA_ARGS__ )
@ -2003,11 +2001,11 @@ inline bool is_truncated_warning( _In_ SQLCHAR* state )
if( condition ) { \
ignored##unique = call_error_handler( context, ssphp TSRMLS_CC, /*warning*/true, ## __VA_ARGS__ ); \
} \
if( !ignored##unique )
if( !ignored##unique )
#define CHECK_SQL_WARNING_AS_ERROR( result, context, ... ) \
CHECK_WARNING_AS_ERROR_UNIQUE( __COUNTER__,( result == SQL_SUCCESS_WITH_INFO ), context, SQLSRV_ERROR_ODBC, ## __VA_ARGS__ )
#define CHECK_SQL_WARNING( result, context, ... ) \
if( result == SQL_SUCCESS_WITH_INFO ) { \
(void)call_error_handler( context, 0 TSRMLS_CC, /*warning*/ true, ## __VA_ARGS__ ); \
@ -2015,7 +2013,7 @@ inline bool is_truncated_warning( _In_ SQLCHAR* state )
#define CHECK_CUSTOM_WARNING_AS_ERROR( condition, context, ssphp, ... ) \
CHECK_WARNING_AS_ERROR_UNIQUE( __COUNTER__, condition, context, ssphp, ## __VA_ARGS__ )
#define CHECK_ZEND_ERROR( zr, ctx, error, ... ) \
CHECK_ERROR_UNIQUE( __COUNTER__, ( zr == FAILURE ), ctx, error, ## __VA_ARGS__ ) \
@ -2029,7 +2027,7 @@ inline bool is_truncated_warning( _In_ SQLCHAR* state )
ignored = call_error_handler( context, SQLSRV_ERROR_ODBC TSRMLS_CC, true TSRMLS_CC, ##__VA_ARGS__ ); \
} \
if( !ignored )
// throw an exception after it has been hooked into the custom error handler
#define THROW_CORE_ERROR( ctx, custom, ... ) \
(void)call_error_handler( ctx, custom TSRMLS_CC, /*warning*/ false, ## __VA_ARGS__ ); \
@ -2051,25 +2049,25 @@ namespace core {
inline void check_for_mars_error( _Inout_ sqlsrv_stmt* stmt, _In_ SQLRETURN r TSRMLS_DC )
{
// Skip this if not SQL_ERROR -
// Skip this if not SQL_ERROR -
// We check for the 'connection busy' error caused by having MultipleActiveResultSets off
// and return a more helpful message prepended to the ODBC errors if that error occurs
if (r == SQL_ERROR) {
SQLCHAR err_msg[SQL_MAX_MESSAGE_LENGTH + 1] = {'\0'};
SQLSMALLINT len = 0;
SQLRETURN rtemp = ::SQLGetDiagField( stmt->handle_type(), stmt->handle(), 1, SQL_DIAG_MESSAGE_TEXT,
SQLRETURN rtemp = ::SQLGetDiagField( stmt->handle_type(), stmt->handle(), 1, SQL_DIAG_MESSAGE_TEXT,
err_msg, SQL_MAX_MESSAGE_LENGTH, &len );
if (rtemp == SQL_SUCCESS_WITH_INFO && len > SQL_MAX_MESSAGE_LENGTH) {
// if the error message is this long, then it must not be the mars message
// defined as ODBC_CONNECTION_BUSY_ERROR -- so return here and continue the
// if the error message is this long, then it must not be the mars message
// defined as ODBC_CONNECTION_BUSY_ERROR -- so return here and continue the
// regular error handling
return;
}
CHECK_SQL_ERROR_OR_WARNING( rtemp, stmt ) {
throw CoreException();
}
@ -2078,7 +2076,7 @@ namespace core {
const std::string returned_error( reinterpret_cast<char*>( err_msg ));
if(( returned_error.find( connection_busy_error ) != std::string::npos )) {
THROW_CORE_ERROR( stmt, SQLSRV_ERROR_MARS_OFF );
}
}
@ -2092,11 +2090,11 @@ namespace core {
// These functions take the sqlsrv_context type. However, since the error handling code can alter
// the context to hold the error, they are not passed as const.
inline SQLRETURN SQLGetDiagField( _Inout_ sqlsrv_context* ctx, _In_ SQLSMALLINT record_number, _In_ SQLSMALLINT diag_identifier,
inline SQLRETURN SQLGetDiagField( _Inout_ sqlsrv_context* ctx, _In_ SQLSMALLINT record_number, _In_ SQLSMALLINT diag_identifier,
_Out_writes_opt_(buffer_length) SQLPOINTER diag_info_buffer, _In_ SQLSMALLINT buffer_length,
_Out_opt_ SQLSMALLINT* out_buffer_length TSRMLS_DC )
{
SQLRETURN r = ::SQLGetDiagField( ctx->handle_type(), ctx->handle(), record_number, diag_identifier,
SQLRETURN r = ::SQLGetDiagField( ctx->handle_type(), ctx->handle(), record_number, diag_identifier,
diag_info_buffer, buffer_length, out_buffer_length );
CHECK_SQL_ERROR_OR_WARNING( r, ctx ) {
@ -2106,7 +2104,7 @@ namespace core {
return r;
}
inline void SQLAllocHandle( _In_ SQLSMALLINT HandleType, _Inout_ sqlsrv_context& InputHandle,
inline void SQLAllocHandle( _In_ SQLSMALLINT HandleType, _Inout_ sqlsrv_context& InputHandle,
_Out_ SQLHANDLE* OutputHandlePtr TSRMLS_DC )
{
SQLRETURN r;
@ -2116,7 +2114,7 @@ namespace core {
}
}
inline void SQLBindParameter( _Inout_ sqlsrv_stmt* stmt,
inline void SQLBindParameter( _Inout_ sqlsrv_stmt* stmt,
_In_ SQLUSMALLINT ParameterNumber,
_In_ SQLSMALLINT InputOutputType,
_In_ SQLSMALLINT ValueType,
@ -2129,9 +2127,9 @@ namespace core {
TSRMLS_DC )
{
SQLRETURN r;
r = ::SQLBindParameter( stmt->handle(), ParameterNumber, InputOutputType, ValueType, ParameterType, ColumnSize,
r = ::SQLBindParameter( stmt->handle(), ParameterNumber, InputOutputType, ValueType, ParameterType, ColumnSize,
DecimalDigits, ParameterValuePtr, BufferLength, StrLen_Or_IndPtr );
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
throw CoreException();
}
@ -2146,7 +2144,7 @@ namespace core {
}
}
inline void SQLColAttribute( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, _In_ SQLUSMALLINT field_identifier,
inline void SQLColAttribute( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_index, _In_ SQLUSMALLINT field_identifier,
_Out_writes_bytes_opt_(buffer_length) SQLPOINTER field_type_char, _In_ SQLSMALLINT buffer_length,
_Out_opt_ SQLSMALLINT* out_buffer_length, _Out_opt_ SQLLEN* field_type_num TSRMLS_DC )
{
@ -2175,9 +2173,9 @@ namespace core {
_Out_opt_ SQLSMALLINT* decimal_digits, _Out_opt_ SQLSMALLINT* nullable TSRMLS_DC )
{
SQLRETURN r;
r = ::SQLDescribeCol( stmt->handle(), colno, col_name, col_name_length, col_name_length_out,
r = ::SQLDescribeCol( stmt->handle(), colno, col_name, col_name_length, col_name_length_out,
data_type, col_size, decimal_digits, nullable);
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
throw CoreException();
}
@ -2220,17 +2218,17 @@ namespace core {
inline void SQLEndTran( _In_ SQLSMALLINT handleType, _Inout_ sqlsrv_conn* conn, _In_ SQLSMALLINT completionType TSRMLS_DC )
{
SQLRETURN r = ::SQLEndTran( handleType, conn->handle(), completionType );
CHECK_SQL_ERROR_OR_WARNING( r, conn ) {
throw CoreException();
}
}
// SQLExecDirect returns the status code since it returns either SQL_NEED_DATA or SQL_NO_DATA besides just errors/success
// SQLExecDirect returns the status code since it returns either SQL_NEED_DATA or SQL_NO_DATA besides just errors/success
inline SQLRETURN SQLExecDirect( _Inout_ sqlsrv_stmt* stmt, _In_ char* sql TSRMLS_DC )
{
SQLRETURN r = ::SQLExecDirect( stmt->handle(), reinterpret_cast<SQLCHAR*>( sql ), SQL_NTS );
check_for_mars_error( stmt, r TSRMLS_CC );
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
@ -2258,7 +2256,7 @@ namespace core {
{
SQLRETURN r;
r = ::SQLExecute( stmt->handle() );
check_for_mars_error( stmt, r TSRMLS_CC );
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
@ -2271,7 +2269,7 @@ namespace core {
inline SQLRETURN SQLFetchScroll( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orientation, _In_ SQLLEN fetch_offset TSRMLS_DC )
{
SQLRETURN r = ::SQLFetchScroll( stmt->handle(), fetch_orientation, fetch_offset );
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
throw CoreException();
}
@ -2304,7 +2302,7 @@ namespace core {
if( r == SQL_NO_DATA )
return r;
CHECK_SQL_ERROR( r, stmt ) {
throw CoreException();
}
@ -2318,13 +2316,13 @@ namespace core {
return r;
}
inline void SQLGetInfo( _Inout_ sqlsrv_conn* conn, _In_ SQLUSMALLINT info_type, _Out_writes_bytes_opt_(buffer_len) SQLPOINTER info_value, _In_ SQLSMALLINT buffer_len,
_Out_opt_ SQLSMALLINT* str_len TSRMLS_DC )
{
SQLRETURN r;
r = ::SQLGetInfo( conn->handle(), info_type, info_value, buffer_len, str_len );
CHECK_SQL_ERROR_OR_WARNING( r, conn ) {
throw CoreException();
}
@ -2335,7 +2333,7 @@ namespace core {
{
SQLRETURN r;
r = ::SQLGetTypeInfo( stmt->handle(), data_type );
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
throw CoreException();
}
@ -2363,7 +2361,7 @@ namespace core {
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
throw CoreException();
}
return num_cols;
}
@ -2405,14 +2403,14 @@ namespace core {
SQLLEN rows_affected;
r = ::SQLRowCount( stmt->handle(), &rows_affected );
// On Linux platform
// DriverName: libmsodbcsql-13.0.so.0.0
// DriverODBCVer: 03.52
// DriverVer: 13.00.0000
// unixODBC: 2.3.1
// r = ::SQLRowCount( stmt->handle(), &rows_affected );
// returns r=-1 for an empty result set.
// r = ::SQLRowCount( stmt->handle(), &rows_affected );
// returns r=-1 for an empty result set.
#ifndef _WIN32
if( r == -1 && rows_affected == -1 )
return 0;
@ -2430,7 +2428,7 @@ namespace core {
{
SQLRETURN r;
r = ::SQLSetConnectAttr( ctx.handle(), attr, value_ptr, str_len );
CHECK_SQL_ERROR_OR_WARNING( r, ctx ) {
throw CoreException();
}
@ -2460,13 +2458,13 @@ namespace core {
inline void SQLSetConnectAttr( _Inout_ sqlsrv_conn* conn, _In_ SQLINTEGER attribute, _In_reads_bytes_opt_(value_len) SQLPOINTER value_ptr, _In_ SQLINTEGER value_len TSRMLS_DC )
{
SQLRETURN r = ::SQLSetConnectAttr( conn->handle(), attribute, value_ptr, value_len );
SQLRETURN r = ::SQLSetConnectAttr( conn->handle(), attribute, value_ptr, value_len );
CHECK_SQL_ERROR_OR_WARNING( r, conn ) {
throw CoreException();
}
}
inline void SQLSetStmtAttr( _Inout_ sqlsrv_stmt* stmt, _In_ SQLINTEGER attr, _In_reads_(str_len) SQLPOINTER value_ptr, _In_ SQLINTEGER str_len TSRMLS_DC )
{
SQLRETURN r;
@ -2505,7 +2503,7 @@ namespace core {
// If there is a zend function in the source that isn't found here, it is because it returns void and there is no error
// that can be thrown from it.
inline void sqlsrv_add_index_zval( _Inout_ sqlsrv_context& ctx, _Inout_ zval* array, _In_ zend_ulong index, _In_ zval* value TSRMLS_DC)
inline void sqlsrv_add_index_zval( _Inout_ sqlsrv_context& ctx, _Inout_ zval* array, _In_ zend_ulong index, _In_ zval* value TSRMLS_DC)
{
int zr = add_index_zval( array, index, value );
CHECK_ZEND_ERROR( zr, ctx, SQLSRV_ERROR_ZEND_HASH ) {
@ -2513,7 +2511,7 @@ namespace core {
}
}
inline void sqlsrv_add_next_index_zval( _Inout_ sqlsrv_context& ctx, _Inout_ zval* array, _In_ zval* value TSRMLS_DC)
inline void sqlsrv_add_next_index_zval( _Inout_ sqlsrv_context& ctx, _Inout_ zval* array, _In_ zval* value TSRMLS_DC)
{
int zr = add_next_index_zval( array, value );
CHECK_ZEND_ERROR( zr, ctx, SQLSRV_ERROR_ZEND_HASH ) {
@ -2556,7 +2554,7 @@ namespace core {
}
}
inline void sqlsrv_array_init( _Inout_ sqlsrv_context& ctx, _Out_ zval* new_array TSRMLS_DC)
inline void sqlsrv_array_init( _Inout_ sqlsrv_context& ctx, _Out_ zval* new_array TSRMLS_DC)
{
#if PHP_VERSION_ID < 70300
CHECK_ZEND_ERROR(::array_init(new_array), ctx, SQLSRV_ERROR_ZEND_HASH) {
@ -2599,7 +2597,7 @@ namespace core {
throw CoreException();
}
}
inline void sqlsrv_zend_hash_index_update( _Inout_ sqlsrv_context& ctx, _Inout_ HashTable* ht, _In_ zend_ulong index, _In_ zval* data_z TSRMLS_DC )
{
int zr = (data_z = ::zend_hash_index_update(ht, index, data_z)) != NULL ? SUCCESS : FAILURE;
@ -2624,7 +2622,7 @@ namespace core {
throw CoreException();
}
}
inline void sqlsrv_zend_hash_next_index_insert( _Inout_ sqlsrv_context& ctx, _Inout_ HashTable* ht, _In_ zval* data TSRMLS_DC )
{
int zr = (data = ::zend_hash_next_index_insert(ht, data)) != NULL ? SUCCESS : FAILURE;
@ -2648,7 +2646,7 @@ namespace core {
throw CoreException();
}
}
inline void sqlsrv_zend_hash_init(sqlsrv_context& ctx, _Inout_ HashTable* ht, _Inout_ uint32_t initial_size,
_In_ dtor_func_t dtor_fn, _In_ zend_bool persistent TSRMLS_DC )
{

View file

@ -3,7 +3,7 @@
//
// Contents: Core routines that use statement handles shared between sqlsrv and pdo_sqlsrv
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
@ -329,7 +329,7 @@ sqlsrv_stmt* core_sqlsrv_create_stmt( _Inout_ sqlsrv_conn* conn, _In_ driver_stm
}
// The query timeout setting is inherited from the corresponding connection attribute, but
// the user may override that the query timeout setting using the statement option.
// the user may override that the query timeout setting using the statement option.
// In any case, set query timeout using the latest value
stmt->set_query_timeout();
@ -850,7 +850,7 @@ bool core_sqlsrv_fetch( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orient
CHECK_CUSTOM_ERROR( stmt->past_fetch_end, stmt, SQLSRV_ERROR_FETCH_PAST_END ) {
throw core::CoreException();
}
// First time only
if ( !stmt->fetch_called ) {
SQLSMALLINT has_fields;
@ -860,7 +860,7 @@ bool core_sqlsrv_fetch( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT fetch_orient
has_fields = core::SQLNumResultCols( stmt TSRMLS_CC );
stmt->column_count = has_fields;
}
CHECK_CUSTOM_ERROR( has_fields == 0, stmt, SQLSRV_ERROR_NO_FIELDS ) {
throw core::CoreException();
}
@ -1009,7 +1009,7 @@ void core_sqlsrv_sensitivity_metadata( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC )
}
// Reference: https://docs.microsoft.com/sql/connect/odbc/data-classification
// To retrieve sensitivity classfication data, the first step is to retrieve the IRD(Implementation Row Descriptor) handle by
// To retrieve sensitivity classfication data, the first step is to retrieve the IRD(Implementation Row Descriptor) handle by
// calling SQLGetStmtAttr with SQL_ATTR_IMP_ROW_DESC statement attribute
r = ::SQLGetStmtAttr(stmt->handle(), SQL_ATTR_IMP_ROW_DESC, (SQLPOINTER)&ird, SQL_IS_POINTER, 0);
CHECK_SQL_ERROR_OR_WARNING(r, stmt) {
@ -1074,7 +1074,7 @@ void core_sqlsrv_sensitivity_metadata( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC )
CHECK_CUSTOM_ERROR(dcptr != dcend, stmt, SQLSRV_ERROR_DATA_CLASSIFICATION_FAILED, "Metadata parsing ends unexpectedly") {
throw core::CoreException();
}
stmt->current_sensitivity_metadata = sensitivity_meta;
sensitivity_meta.transferred();
} catch (core::CoreException& e) {
@ -1172,7 +1172,7 @@ void core_sqlsrv_get_field( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_i
// use the previously saved php type
sqlsrv_php_type = stmt->current_meta_data[field_index]->sqlsrv_php_type;
}
}
}
// Verify that we have an acceptable type to convert.
CHECK_CUSTOM_ERROR(!is_valid_sqlsrv_phptype(sqlsrv_php_type), stmt, SQLSRV_ERROR_INVALID_TYPE) {
@ -1209,7 +1209,7 @@ bool core_sqlsrv_has_any_result( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC )
{
SQLSMALLINT num_cols;
SQLLEN rows_affected;
if (stmt->column_count != ACTIVE_NUM_COLS_INVALID) {
num_cols = stmt->column_count;
}
@ -1218,7 +1218,7 @@ bool core_sqlsrv_has_any_result( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC )
num_cols = core::SQLNumResultCols( stmt TSRMLS_CC );
stmt->column_count = num_cols;
}
if (stmt->row_count != ACTIVE_NUM_ROWS_INVALID) {
rows_affected = stmt->row_count;
}
@ -1227,7 +1227,7 @@ bool core_sqlsrv_has_any_result( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC )
rows_affected = core::SQLRowCount( stmt TSRMLS_CC );
stmt->row_count = rows_affected;
}
return (num_cols != 0) || (rows_affected > 0);
}
@ -1266,7 +1266,7 @@ void core_sqlsrv_next_result( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC, _In_ bool fin
if( r == SQL_NO_DATA ) {
if( &(stmt->output_params) && finalize_output_params ) {
if( finalize_output_params ) {
// if we're finished processing result sets, handle the output parameters
finalize_output_parameters( stmt TSRMLS_CC );
}
@ -1416,7 +1416,7 @@ void core_sqlsrv_set_decimal_places(_Inout_ sqlsrv_stmt* stmt, _In_ zval* value_
}
stmt->decimal_places = static_cast<short>(decimal_places);
}
}
catch( core::CoreException& ) {
throw;
}
@ -1858,7 +1858,7 @@ void core_get_field_common( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_i
// Reference: https://docs.microsoft.com/sql/odbc/reference/appendixes/sql-to-c-timestamp
// Retrieve the datetime data as a string, which may be cached for later use.
// The string is converted to a DateTime object only when it is required to
// The string is converted to a DateTime object only when it is required to
// be returned as a zval.
case SQLSRV_PHPTYPE_DATETIME:
{
@ -1885,7 +1885,7 @@ void core_get_field_common( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT field_i
break;
}
// create a stream wrapper around the field and return that object to the PHP script. calls to fread
// on the stream will result in calls to SQLGetData. This is handled in stream.cpp. See that file
// for how these fields are used.
@ -2012,7 +2012,7 @@ bool convert_input_param_to_utf16( _In_ zval* input_param_z, _Inout_ zval* conve
// conversion, to avoid the performance penalty of calling ToUtf16
wchar_size = buffer_len;
#else
// Calculate the size of the necessary buffer from the length of the string -
// Calculate the size of the necessary buffer from the length of the string -
// no performance penalty because MultiByteToWidechar is highly optimised
wchar_size = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, reinterpret_cast<LPCSTR>( buffer ), static_cast<int>( buffer_len ), NULL, 0 );
#endif // !_WIN32
@ -2275,7 +2275,7 @@ void format_decimal_numbers(_In_ SQLSMALLINT decimals_places, _In_ SQLSMALLINT f
// number of decimals adheres to the column field scale. If smaller, the output value may be rounded up.
//
// Note: it's possible that the decimal data does not contain a decimal dot because the field scale is 0.
// Thus, first check if the decimal dot exists. If not, no formatting necessary, regardless of
// Thus, first check if the decimal dot exists. If not, no formatting necessary, regardless of
// format_decimals and decimals_places
//
std::string str = field_value;
@ -2292,8 +2292,8 @@ void format_decimal_numbers(_In_ SQLSMALLINT decimals_places, _In_ SQLSMALLINT f
}
// 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.
// 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.
bool isNegative = false;
@ -2313,16 +2313,16 @@ void format_decimal_numbers(_In_ SQLSMALLINT decimals_places, _In_ SQLSMALLINT f
str = oss.str();
pos++;
}
if (num_decimals == NO_CHANGE_DECIMAL_PLACES) {
// Add the minus sign back if negative
if (isNegative) {
std::ostringstream oss;
oss << '-' << str.substr(0);
str = oss.str();
}
}
} else {
// Start formatting
// Start formatting
size_t last = 0;
if (num_decimals == 0) {
// Chop all decimal digits, including the decimal dot
@ -2532,7 +2532,7 @@ void finalize_output_parameters( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC )
throw core::CoreException();
}
}
// if the output param is a boolean, still convert to
// if the output param is a boolean, still convert to
// a long integer first to take care of rounding
convert_to_long(value_z);
if (output_param->is_bool) {
@ -2911,9 +2911,9 @@ void resize_output_buffer_if_necessary( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval*
// account for the NULL terminator returned by ODBC and needed by Zend to avoid a "String not null terminated" debug warning
SQLULEN field_size = column_size;
// with AE on, when column_size is retrieved from SQLDescribeParam, column_size
// with AE on, when column_size is retrieved from SQLDescribeParam, column_size
// does not include the negative sign or decimal place for numeric values
// VSO Bug 2913: without AE, the same can happen as well, in particular to decimals
// VSO Bug 2913: without AE, the same can happen as well, in particular to decimals
// and numerics with precision/scale specified
if (sql_type == SQL_DECIMAL || sql_type == SQL_NUMERIC || sql_type == SQL_BIGINT || sql_type == SQL_INTEGER || sql_type == SQL_SMALLINT) {
// include the possible negative sign
@ -2948,8 +2948,8 @@ void resize_output_buffer_if_necessary( _Inout_ sqlsrv_stmt* stmt, _Inout_ zval*
// A zval string len doesn't include the null. This calculates the length it should be
// regardless of whether the ODBC type contains the NULL or not.
// initialize the newly allocated space
char *p = ZSTR_VAL(param_z_string);
// initialize the newly allocated space
char *p = ZSTR_VAL(param_z_string);
p = p + original_len;
memset(p, '\0', expected_len - original_len);
ZVAL_NEW_STR(param_z, param_z_string);

View file

@ -3,7 +3,7 @@
//
// Contents: Implementation of PHP streams for reading SQL Server data
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -5,7 +5,7 @@
//
// Comments: Mostly error handling and some type handling
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -4,7 +4,7 @@
// Contents: Contains functions for handling Windows format strings
// and UTF-16 on non-Windows platforms
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -4,7 +4,7 @@
// Contents: Contains a portable abstraction for interlocked, atomic
// operations on int32_t and pointer types.
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -4,7 +4,7 @@
// Contents: Contains a portable abstraction for interlocked, atomic
// operations on int32_t and pointer types.
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -4,7 +4,7 @@
// Contents: Contains a portable abstraction for interlocked, singly
// linked list.
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: Contains portable classes for localization
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -5,7 +5,7 @@
// Must be included in one c/cpp file per binary
// A build error will occur if this inclusion policy is not followed
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -20,7 +20,7 @@
// pecuniary loss) arising out of the use of or inability to use
// this SDK, even if Microsoft has been advised of the possibility
// of such damages.
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: Contains the minimal definitions to build on non-Windows platforms
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -1,7 +1,7 @@
//---------------------------------------------------------------------------------------------------------------------------------
// File: typedefs_for_linux.h
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -4,7 +4,7 @@
// File: version.h
// Contents: Version number constants
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
@ -26,12 +26,12 @@
// Increase Minor with backward compatible new functionalities and API changes.
// Increase Patch for backward compatible fixes.
#define SQLVERSION_MAJOR 5
#define SQLVERSION_MINOR 7
#define SQLVERSION_PATCH 1
#define SQLVERSION_MINOR 8
#define SQLVERSION_PATCH 0
#define SQLVERSION_BUILD 0
// For previews, set this constant to 1. Otherwise, set it to 0
#define PREVIEW 1
#define PREVIEW 0
#define SEMVER_PRERELEASE
// Semantic versioning build metadata, build meta data is not counted in precedence order.

View file

@ -3,7 +3,7 @@
//
// Contents: include for definition of Windows types for non-Windows platforms
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -4,7 +4,7 @@
// Contents: This module defines helper functions to prevent
// integer overflow bugs.
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: Contains the minimal definitions to build on non-Windows platforms
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: Contains the minimal definitions to build on non-Windows platforms
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -4,7 +4,7 @@ dnl
dnl Contents: the code that will go into the configure script, indicating options,
dnl external libraries and includes, and what source files are to be compiled.
dnl
dnl Microsoft Drivers 5.7 for PHP for SQL Server
dnl Microsoft Drivers 5.8 for PHP for SQL Server
dnl Copyright(c) Microsoft Corporation
dnl All rights reserved.
dnl MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: JScript build configuration used by buildconf.bat
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -3,7 +3,7 @@
//
// Contents: Routines that use connection handles
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -2,7 +2,7 @@
// File: init.cpp
// Contents: initialization routines for the extension
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
@ -654,6 +654,25 @@ PHP_RINIT_FUNCTION(sqlsrv)
SQLSRV_G( log_subsystems ) = INI_INT( subsystems );
SQLSRV_G( buffered_query_limit ) = INI_INT( buffered_limit );
#ifndef _WIN32
char set_locale_info[] = INI_PREFIX INI_SET_LOCALE_INFO;
SQLSRV_G(set_locale_info) = INI_INT(set_locale_info);
// if necessary, set locale from the environment for ODBC, which MUST be done before any connection
int set_locale = SQLSRV_G(set_locale_info);
if (set_locale == 2) {
setlocale(LC_ALL, "");
}
else if (set_locale == 1) {
setlocale(LC_CTYPE, "");
}
else {
// Do nothing
}
LOG(SEV_NOTICE, INI_PREFIX INI_SET_LOCALE_INFO " = %1!d!", set_locale);
#endif
LOG( SEV_NOTICE, INI_PREFIX INI_WARNINGS_RETURN_AS_ERRORS " = %1!s!", SQLSRV_G( warnings_return_as_errors ) ? "On" : "Off");
LOG( SEV_NOTICE, INI_PREFIX INI_LOG_SEVERITY " = %1!d!", SQLSRV_G( log_severity ));
LOG( SEV_NOTICE, INI_PREFIX INI_LOG_SUBSYSTEMS " = %1!d!", SQLSRV_G( log_subsystems ));

View file

@ -8,7 +8,7 @@
//
// Comments: Also contains "internal" declarations shared across source files.
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
@ -42,6 +42,10 @@ zend_long current_subsystem;
zend_bool warnings_return_as_errors;
zend_long buffered_query_limit;
#ifndef _WIN32
zend_long set_locale_info;
#endif
ZEND_END_MODULE_GLOBALS(sqlsrv)
ZEND_EXTERN_MODULE_GLOBALS(sqlsrv);

View file

@ -8,7 +8,7 @@
//
// Comments: Also contains "internal" declarations shared across source files.
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
@ -37,6 +37,10 @@
#define INI_BUFFERED_QUERY_LIMIT "ClientBufferMaxKBSize"
#define INI_PREFIX "sqlsrv."
#ifndef _WIN32
#define INI_SET_LOCALE_INFO "SetLocaleInfo"
#endif
PHP_INI_BEGIN()
STD_PHP_INI_BOOLEAN( INI_PREFIX INI_WARNINGS_RETURN_AS_ERRORS , "1", PHP_INI_ALL, OnUpdateBool, warnings_return_as_errors,
zend_sqlsrv_globals, sqlsrv_globals )
@ -46,6 +50,11 @@ PHP_INI_BEGIN()
sqlsrv_globals )
STD_PHP_INI_ENTRY( INI_PREFIX INI_BUFFERED_QUERY_LIMIT, INI_BUFFERED_QUERY_LIMIT_DEFAULT, PHP_INI_ALL, OnUpdateLong, buffered_query_limit,
zend_sqlsrv_globals, sqlsrv_globals )
#ifndef _WIN32
STD_PHP_INI_ENTRY(INI_PREFIX INI_SET_LOCALE_INFO, "2", PHP_INI_ALL, OnUpdateLong, set_locale_info,
zend_sqlsrv_globals, sqlsrv_globals)
#endif
PHP_INI_END()

View file

@ -3,17 +3,17 @@
//
// Contents: Routines that use statement handles
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""),
// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""),
// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//---------------------------------------------------------------------------------------------------------------------------------
@ -85,11 +85,6 @@ const char* NULLABLE = "Nullable";
}
// warning message printed when a parameter variable is not passed by reference
const char SS_SQLSRV_WARNING_PARAM_VAR_NOT_REF[] = "Variable parameter %d not passed by reference (prefaced with an &). "
"Variable parameters passed to sqlsrv_prepare or sqlsrv_query should be passed by reference, not by value. "
"For more information, see sqlsrv_prepare or sqlsrv_query in the API Reference section of the product documentation.";
/* internal functions */
void convert_to_zval( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSRV_PHPTYPE sqlsrv_php_type, _In_opt_ void* in_val, _In_ SQLLEN field_len, _Inout_ zval& out_zval );
@ -103,7 +98,7 @@ void determine_stmt_has_rows( _Inout_ ss_sqlsrv_stmt* stmt TSRMLS_DC );
bool is_valid_sqlsrv_phptype( _In_ sqlsrv_phptype type );
bool is_valid_sqlsrv_sqltype( _In_ sqlsrv_sqltype type );
void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array, zend_ulong index, _Out_ SQLSMALLINT& direction,
_Out_ SQLSRV_PHPTYPE& php_out_type, _Out_ SQLSRV_ENCODING& encoding, _Out_ SQLSMALLINT& sql_type,
_Out_ SQLSRV_PHPTYPE& php_out_type, _Out_ SQLSRV_ENCODING& encoding, _Out_ SQLSMALLINT& sql_type,
_Out_ SQLULEN& column_size, _Out_ SQLSMALLINT& decimal_digits TSRMLS_DC );
void type_and_encoding( INTERNAL_FUNCTION_PARAMETERS, _In_ int type );
void type_and_size_calc( INTERNAL_FUNCTION_PARAMETERS, _In_ int type );
@ -156,7 +151,7 @@ ss_sqlsrv_stmt::~ss_sqlsrv_stmt( void )
if( fetch_field_names != NULL ) {
for( int i=0; i < fetch_fields_count; ++i ) {
sqlsrv_free( fetch_field_names[i].name );
}
sqlsrv_free( fetch_field_names );
@ -165,16 +160,16 @@ ss_sqlsrv_stmt::~ss_sqlsrv_stmt( void )
zval_ptr_dtor( params_z );
sqlsrv_free(params_z);
}
}
}
// to be called whenever a new result set is created, such as after an
// execute or next_result. Resets the state variables and calls the subclass.
void ss_sqlsrv_stmt::new_result_set( TSRMLS_D )
void ss_sqlsrv_stmt::new_result_set( TSRMLS_D )
{
if( fetch_field_names != NULL ) {
for( int i=0; i < fetch_fields_count; ++i ) {
sqlsrv_free( fetch_field_names[i].name );
}
sqlsrv_free( fetch_field_names );
@ -185,7 +180,7 @@ void ss_sqlsrv_stmt::new_result_set( TSRMLS_D )
sqlsrv_stmt::new_result_set( TSRMLS_C );
}
// Returns a php type for a given sql type. Also sets the encoding wherever applicable.
// Returns a php type for a given sql type. Also sets the encoding wherever applicable.
sqlsrv_phptype ss_sqlsrv_stmt::sql_type_to_php_type( _In_ SQLINTEGER sql_type, _In_ SQLUINTEGER size, _In_ bool prefer_string_to_stream )
{
sqlsrv_phptype ss_phptype;
@ -299,13 +294,13 @@ void ss_sqlsrv_stmt::set_query_timeout()
}
// sqlsrv_execute( resource $stmt )
//
//
// Executes a previously prepared statement. See sqlsrv_prepare for information
// on preparing a statement for execution.
//
//
// This function is ideal for executing a prepared statement multiple times with
// different parameter values. See the MSDN documentation
//
//
// Parameters
// $stmt: A resource specifying the statement to be executed. For more
// information about how to create a statement resource, see sqlsrv_prepare.
@ -316,12 +311,12 @@ void ss_sqlsrv_stmt::set_query_timeout()
PHP_FUNCTION( sqlsrv_execute )
{
LOG_FUNCTION( "sqlsrv_execute" );
ss_sqlsrv_stmt* stmt = NULL;
try {
PROCESS_PARAMS( stmt, "r", _FN_, 0 );
PROCESS_PARAMS( stmt, "r", _FN_, 0 );
CHECK_CUSTOM_ERROR(( !stmt->prepared ), stmt, SS_SQLSRV_ERROR_STATEMENT_NOT_PREPARED ) {
throw ss::SSException();
}
@ -340,11 +335,11 @@ PHP_FUNCTION( sqlsrv_execute )
bind_params( stmt TSRMLS_CC );
core_sqlsrv_execute( stmt TSRMLS_CC );
RETURN_TRUE;
}
catch( core::CoreException& ) {
RETURN_FALSE;
}
catch( ... ) {
@ -382,8 +377,8 @@ PHP_FUNCTION( sqlsrv_fetch )
PROCESS_PARAMS( stmt, "r|ll", _FN_, 2, &fetch_style, &fetch_offset );
try {
CHECK_CUSTOM_ERROR(( fetch_style < SQL_FETCH_NEXT || fetch_style > SQL_FETCH_RELATIVE ), stmt,
CHECK_CUSTOM_ERROR(( fetch_style < SQL_FETCH_NEXT || fetch_style > SQL_FETCH_RELATIVE ), stmt,
SS_SQLSRV_ERROR_INVALID_FETCH_STYLE ) {
throw ss::SSException();
}
@ -406,7 +401,7 @@ PHP_FUNCTION( sqlsrv_fetch )
}
// sqlsrv_fetch_array( resource $stmt [, int $fetchType] )
//
//
// Retrieves the next row of data as an array.
//
// Parameters
@ -425,7 +420,7 @@ PHP_FUNCTION( sqlsrv_fetch )
PHP_FUNCTION( sqlsrv_fetch_array )
{
LOG_FUNCTION( "sqlsrv_fetch_array" );
ss_sqlsrv_stmt* stmt = NULL;
zend_long fetch_type = SQLSRV_FETCH_BOTH; // default value for parameter if one isn't supplied
zend_long fetch_style = SQL_FETCH_NEXT; // default value for parameter if one isn't supplied
@ -436,13 +431,13 @@ PHP_FUNCTION( sqlsrv_fetch_array )
PROCESS_PARAMS( stmt, "r|lll", _FN_, 3, &fetch_type, &fetch_style, &fetch_offset );
try {
CHECK_CUSTOM_ERROR(( fetch_type < MIN_SQLSRV_FETCH || fetch_type > MAX_SQLSRV_FETCH ), stmt,
CHECK_CUSTOM_ERROR(( fetch_type < MIN_SQLSRV_FETCH || fetch_type > MAX_SQLSRV_FETCH ), stmt,
SS_SQLSRV_ERROR_INVALID_FETCH_TYPE ) {
throw ss::SSException();
}
CHECK_CUSTOM_ERROR(( fetch_style < SQL_FETCH_NEXT || fetch_style > SQL_FETCH_RELATIVE ), stmt,
CHECK_CUSTOM_ERROR(( fetch_style < SQL_FETCH_NEXT || fetch_style > SQL_FETCH_RELATIVE ), stmt,
SS_SQLSRV_ERROR_INVALID_FETCH_STYLE ) {
throw ss::SSException();
}
@ -467,7 +462,7 @@ PHP_FUNCTION( sqlsrv_fetch_array )
}
// sqlsrv_field_metadata( resource $stmt )
//
//
// Retrieves metadata for the fields of a prepared statement. For information
// about preparing a statement, see sqlsrv_query or sqlsrv_prepare. Note that
// sqlsrv_field_metadata can be called on any prepared statement, pre- or
@ -477,7 +472,7 @@ PHP_FUNCTION( sqlsrv_fetch_array )
// $stmt: A statement resource for which field metadata is sought.
//
// Return Value
// retrieve an array of metadata for the current result set on a statement. Each element of the
// retrieve an array of metadata for the current result set on a statement. Each element of the
// array is a sub-array containing 5 elements accessed by key:
// name - name of the field.
// type - integer of the type. Can be compared against the SQLSRV_SQLTYPE constants.
@ -507,10 +502,10 @@ PHP_FUNCTION( sqlsrv_field_metadata )
zval result_meta_data;
ZVAL_UNDEF( &result_meta_data );
core::sqlsrv_array_init( *stmt, &result_meta_data TSRMLS_CC );
for( SQLSMALLINT f = 0; f < num_cols; ++f ) {
field_meta_data* core_meta_data = stmt->current_meta_data[f];
// initialize the array
zval field_array;
ZVAL_UNDEF( &field_array );
@ -555,7 +550,7 @@ PHP_FUNCTION( sqlsrv_field_metadata )
// add the nullability to the array
core::sqlsrv_add_assoc_long( *stmt, &field_array, FieldMetaData::NULLABLE, core_meta_data->field_is_nullable
TSRMLS_CC );
if (stmt->data_classification) {
data_classification::fill_column_sensitivity_array(stmt, f, &field_array TSRMLS_CC);
}
@ -580,7 +575,7 @@ PHP_FUNCTION( sqlsrv_field_metadata )
// sqlsrv_next_result( resource $stmt )
//
//
// Makes the next result (result set, row count, or output parameter) of the
// specified statement active. The first (or only) result returned by a batch
// query or stored procedure is active without a call to sqlsrv_next_result.
@ -619,7 +614,7 @@ PHP_FUNCTION( sqlsrv_next_result )
RETURN_TRUE;
}
catch( core::CoreException& ) {
RETURN_FALSE;
}
catch( ... ) {
@ -708,7 +703,7 @@ PHP_FUNCTION( sqlsrv_num_rows )
// make sure that the statement is scrollable and the cursor is not dynamic.
// if the cursor is dynamic, then the number of rows returned is always -1.
CHECK_CUSTOM_ERROR( stmt->cursor_type == SQL_CURSOR_FORWARD_ONLY || stmt->cursor_type == SQL_CURSOR_DYNAMIC, stmt,
CHECK_CUSTOM_ERROR( stmt->cursor_type == SQL_CURSOR_FORWARD_ONLY || stmt->cursor_type == SQL_CURSOR_DYNAMIC, stmt,
SS_SQLSRV_ERROR_STATEMENT_NOT_SCROLLABLE ) {
throw ss::SSException();
}
@ -750,10 +745,10 @@ PHP_FUNCTION( sqlsrv_num_fields )
PROCESS_PARAMS( stmt, "r", _FN_, 0 );
try {
// retrieve the number of columns from ODBC
fields = core::SQLNumResultCols( stmt TSRMLS_CC );
RETURN_LONG( fields );
}
@ -768,7 +763,7 @@ PHP_FUNCTION( sqlsrv_num_fields )
}
// sqlsrv_fetch_object( resource $stmt [, string $className [, array $ctorParams]])
//
//
// Retrieves the next row of data as a PHP object.
//
// Parameters
@ -801,7 +796,7 @@ PHP_FUNCTION( sqlsrv_num_fields )
// object and the result set value is applied to the property. For more
// information about calling sqlsrv_fetch_object with the $className parameter,
// see How to: Retrieve Data as an Object (Microsoft Drivers for PHP for SQL Server).
//
//
// If a field with no name is returned, sqlsrv_fetch_object will discard the
// field value and issue a warning.
@ -824,19 +819,19 @@ PHP_FUNCTION( sqlsrv_fetch_object )
// retrieve the statement resource and optional fetch type (see enum SQLSRV_FETCH_TYPE),
// fetch style (see SQLSRV_SCROLL_* constants) and fetch offset
// we also use z! instead of s and a so that null may be passed in as valid values for
// we also use z! instead of s and a so that null may be passed in as valid values for
// the class name and ctor params
PROCESS_PARAMS( stmt, "r|z!z!ll", _FN_, 4, &class_name_z, &ctor_params_z, &fetch_style, &fetch_offset );
try {
CHECK_CUSTOM_ERROR(( fetch_style < SQL_FETCH_NEXT || fetch_style > SQL_FETCH_RELATIVE ), stmt,
CHECK_CUSTOM_ERROR(( fetch_style < SQL_FETCH_NEXT || fetch_style > SQL_FETCH_RELATIVE ), stmt,
SS_SQLSRV_ERROR_INVALID_FETCH_STYLE ) {
throw ss::SSException();
}
if( class_name_z ) {
CHECK_CUSTOM_ERROR(( Z_TYPE_P( class_name_z ) != IS_STRING ), stmt, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ ) {
throw ss::SSException();
}
@ -847,7 +842,7 @@ PHP_FUNCTION( sqlsrv_fetch_object )
if( ctor_params_z && Z_TYPE_P( ctor_params_z ) != IS_ARRAY ) {
THROW_SS_ERROR( stmt, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ );
}
// fetch the data
bool result = core_sqlsrv_fetch( stmt, static_cast<SQLSMALLINT>(fetch_style), fetch_offset TSRMLS_CC );
if( !result ) {
@ -855,8 +850,8 @@ PHP_FUNCTION( sqlsrv_fetch_object )
}
fetch_fields_common( stmt, SQLSRV_FETCH_ASSOC, retval_z, false /*allow_empty_field_names*/ TSRMLS_CC );
properties_ht = Z_ARRVAL( retval_z );
properties_ht = Z_ARRVAL( retval_z );
// find the zend_class_entry of the class the user requested (stdClass by default) for use below
zend_class_entry* class_entry = NULL;
zend_string* class_name_str_z = zend_string_init( class_name, class_name_len, 0 );
@ -885,13 +880,13 @@ PHP_FUNCTION( sqlsrv_fetch_object )
// find and call the object's constructor
// The header files (zend.h and zend_API.h) declare
// these functions and structures, so by working with those, we were able to
// these functions and structures, so by working with those, we were able to
// develop this as a suitable snippet for calling constructors. Some observations:
// params must be an array of zval**, not a zval** to an array as we originally
// thought. Also, a constructor doesn't show up in the function table, but
// is put into the "magic methods" section of the class entry.
//
// The default values of the fci and fcic structures were determined by
//
// The default values of the fci and fcic structures were determined by
// calling zend_fcall_info_init with a test callable.
// if there is a constructor (e.g., stdClass doesn't have one)
@ -919,7 +914,7 @@ PHP_FUNCTION( sqlsrv_fetch_object )
i++;
} ZEND_HASH_FOREACH_END();
} //if( !Z_ISUNDEF( ctor_params_z ))
// call the constructor function itself.
zend_fcall_info fci;
zend_fcall_info_cache fcic;
@ -933,7 +928,7 @@ PHP_FUNCTION( sqlsrv_fetch_object )
fci.retval = &ctor_retval_z;
fci.param_count = num_params;
fci.params = params_m; // purposefully not transferred since ownership isn't actually transferred.
fci.object = Z_OBJ_P( &retval_z );
memset( &fcic, 0, sizeof( fcic ));
@ -950,7 +945,7 @@ PHP_FUNCTION( sqlsrv_fetch_object )
throw ss::SSException();
}
} //if( class_entry->constructor )
} //if( class_entry->constructor )
RETURN_ZVAL( &retval_z, 1, 1 );
}
@ -985,7 +980,7 @@ PHP_FUNCTION( sqlsrv_fetch_object )
// for using a function like this:
// 1) To know if there are any actual rows, not just a result set (empty or not). Use sqlsrv_has_rows to determine this.
// The guarantee is that if sqlsrv_has_rows returns true immediately after a query, that sqlsrv_fetch_* will return at least
// one row of data.
// one row of data.
// 2) To know if there is any sort of result set, empty or not, that has to be bypassed to get to something else, such as
// output parameters being returned. Use sqlsrv_num_fields > 0 to check if there is any result set that must be bypassed
// until sqlsrv_fetch returns NULL.
@ -1048,8 +1043,8 @@ PHP_FUNCTION( sqlsrv_has_rows )
PHP_FUNCTION( sqlsrv_send_stream_data )
{
sqlsrv_stmt* stmt = NULL;
LOG_FUNCTION( "sqlsrv_send_stream_data" );
LOG_FUNCTION( "sqlsrv_send_stream_data" );
// get the statement resource that we've bound streams to
PROCESS_PARAMS( stmt, "r", _FN_, 0 );
@ -1079,14 +1074,14 @@ PHP_FUNCTION( sqlsrv_send_stream_data )
RETURN_FALSE;
}
catch( ... ) {
DIE( "sqlsrv_send_stream_data: Unknown exception caught." );
}
}
// sqlsrv_get_field( resource $stmt, int $fieldIndex [, int $getAsType] )
//
//
// Retrieves data from the specified field of the current row. Field data must
// be accessed in order. For example, data from the first field cannot be
// accessed after data from the second field has been accessed.
@ -1111,7 +1106,7 @@ PHP_FUNCTION( sqlsrv_send_stream_data )
PHP_FUNCTION( sqlsrv_get_field )
{
LOG_FUNCTION( "sqlsrv_get_field" );
ss_sqlsrv_stmt* stmt = NULL;
sqlsrv_phptype sqlsrv_php_type;
sqlsrv_php_type.typeinfo.type = SQLSRV_PHPTYPE_INVALID;
@ -1121,7 +1116,7 @@ PHP_FUNCTION( sqlsrv_get_field )
SQLLEN field_len = -1;
zval retval_z;
ZVAL_UNDEF(&retval_z);
// get the statement, the field index and the optional type
PROCESS_PARAMS( stmt, "rl|l", _FN_, 2, &field_index, &sqlsrv_php_type );
@ -1136,7 +1131,7 @@ PHP_FUNCTION( sqlsrv_get_field )
core_sqlsrv_get_field( stmt, static_cast<SQLUSMALLINT>( field_index ), sqlsrv_php_type, false, field_value, &field_len, false/*cache_field*/,
&sqlsrv_php_type_out TSRMLS_CC );
convert_to_zval( stmt, sqlsrv_php_type_out, field_value, field_len, retval_z );
convert_to_zval( stmt, sqlsrv_php_type_out, field_value, field_len, retval_z );
sqlsrv_free( field_value );
RETURN_ZVAL( &retval_z, 1, 1 );
}
@ -1232,9 +1227,9 @@ void bind_params( _Inout_ ss_sqlsrv_stmt* stmt TSRMLS_DC )
stmt->executed = false;
zval* params_z = stmt->params_z;
HashTable* params_ht = Z_ARRVAL_P( params_z );
zend_ulong index = -1;
zend_string *key = NULL;
zval* param_z = NULL;
@ -1256,7 +1251,7 @@ void bind_params( _Inout_ ss_sqlsrv_stmt* stmt TSRMLS_DC )
CHECK_CUSTOM_ERROR( type != HASH_KEY_IS_LONG, stmt, SS_SQLSRV_ERROR_PARAM_INVALID_INDEX ) {
throw ss::SSException();
}
// if it's a parameter array
if( Z_TYPE_P( param_z ) == IS_ARRAY ) {
@ -1279,7 +1274,7 @@ void bind_params( _Inout_ ss_sqlsrv_stmt* stmt TSRMLS_DC )
}
// bind the parameter
SQLSRV_ASSERT( value_z != NULL, "bind_params: value_z is null." );
core_sqlsrv_bind_param( stmt, static_cast<SQLUSMALLINT>( index ), direction, value_z, php_out_type, encoding, sql_type, column_size,
core_sqlsrv_bind_param( stmt, static_cast<SQLUSMALLINT>( index ), direction, value_z, php_out_type, encoding, sql_type, column_size,
decimal_digits TSRMLS_CC );
} ZEND_HASH_FOREACH_END();
@ -1294,7 +1289,7 @@ void bind_params( _Inout_ ss_sqlsrv_stmt* stmt TSRMLS_DC )
}
// sqlsrv_cancel( resource $stmt )
//
//
// Cancels a statement. This means that any pending results for the statement
// are discarded. After this function is called, the statement can be
// re-executed if it was prepared with sqlsrv_prepare. Calling this function is
@ -1313,12 +1308,12 @@ PHP_FUNCTION( sqlsrv_cancel )
LOG_FUNCTION( "sqlsrv_cancel" );
ss_sqlsrv_stmt* stmt = NULL;
PROCESS_PARAMS( stmt, "r", _FN_, 0 );
try {
// close the stream to release the resource
close_active_stream( stmt TSRMLS_CC );
SQLRETURN r = SQLCancel( stmt->handle() );
CHECK_SQL_ERROR_OR_WARNING( r, stmt ) {
throw ss::SSException();
@ -1360,7 +1355,7 @@ void __cdecl sqlsrv_stmt_dtor( _Inout_ zend_resource *rsrc TSRMLS_DC )
// cannot be used again after this function has been called.
//
// Parameters
// $stmt: The statement to be closed.
// $stmt: The statement to be closed.
//
// Return Value
// The Boolean value true unless the function is called with an invalid
@ -1384,7 +1379,7 @@ PHP_FUNCTION( sqlsrv_free_stmt )
sqlsrv_context_auto_ptr error_ctx;
reset_errors( TSRMLS_C );
try {
// dummy context to pass to the error handler
@ -1393,14 +1388,14 @@ PHP_FUNCTION( sqlsrv_free_stmt )
// take only the statement resource
if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "r", &stmt_r ) == FAILURE ) {
// Check if it was a zval
int zr = zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "z", &stmt_r );
CHECK_CUSTOM_ERROR(( zr == FAILURE ), error_ctx, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ ) {
throw ss::SSException();
}
}
if( Z_TYPE_P( stmt_r ) == IS_NULL ) {
RETURN_TRUE;
@ -1413,19 +1408,19 @@ PHP_FUNCTION( sqlsrv_free_stmt )
// verify the resource so we know we're deleting a statement
stmt = static_cast<ss_sqlsrv_stmt*>(zend_fetch_resource_ex(stmt_r TSRMLS_CC, ss_sqlsrv_stmt::resource_name, ss_sqlsrv_stmt::descriptor));
// if sqlsrv_free_stmt was called on an already closed statment then we just return success.
// zend_list_close sets the type of the closed statment to -1.
SQLSRV_ASSERT( stmt_r != NULL, "sqlsrv_free_stmt: stmt_r is null." );
if ( Z_RES_TYPE_P( stmt_r ) == RSRC_INVALID_TYPE ) {
RETURN_TRUE;
}
if( stmt == NULL ) {
THROW_CORE_ERROR( error_ctx, SS_SQLSRV_ERROR_INVALID_FUNCTION_PARAMETER, _FN_ );
}
// delete the resource from Zend's master list, which will trigger the statement's destructor
if( zend_list_close( Z_RES_P(stmt_r) ) == FAILURE ) {
LOG( SEV_ERROR, "Failed to remove stmt resource %1!d!", Z_RES_P( stmt_r )->handle);
@ -1436,17 +1431,17 @@ PHP_FUNCTION( sqlsrv_free_stmt )
// zend_list_close only destroy the resource pointed to by Z_RES_P( stmt_r ), not the zend_resource itself
Z_TRY_DELREF_P(stmt_r);
ZVAL_NULL( stmt_r );
RETURN_TRUE;
}
catch( core::CoreException& ) {
RETURN_FALSE;
}
catch( ... ) {
DIE( "sqlsrv_free_stmt: Unknown exception caught." );
}
}
@ -1456,16 +1451,16 @@ void stmt_option_ss_scrollable:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_opt
CHECK_CUSTOM_ERROR(( Z_TYPE_P( value_z ) != IS_STRING ), stmt, SQLSRV_ERROR_INVALID_OPTION_SCROLLABLE ) {
throw ss::SSException();
}
const char* scroll_type = Z_STRVAL_P( value_z );
unsigned long cursor_type = -1;
// find which cursor type they would like and set the ODBC statement attribute as such
if( !stricmp( scroll_type, SSCursorTypes::QUERY_OPTION_SCROLLABLE_STATIC )) {
if( !stricmp( scroll_type, SSCursorTypes::QUERY_OPTION_SCROLLABLE_STATIC )) {
cursor_type = SQL_CURSOR_STATIC;
}
else if( !stricmp( scroll_type, SSCursorTypes::QUERY_OPTION_SCROLLABLE_DYNAMIC )) {
cursor_type = SQL_CURSOR_DYNAMIC;
@ -1477,12 +1472,12 @@ void stmt_option_ss_scrollable:: operator()( _Inout_ sqlsrv_stmt* stmt, stmt_opt
}
else if( !stricmp( scroll_type, SSCursorTypes::QUERY_OPTION_SCROLLABLE_FORWARD )) {
cursor_type = SQL_CURSOR_FORWARD_ONLY;
}
else if( !stricmp( scroll_type, SSCursorTypes::QUERY_OPTION_SCROLLABLE_BUFFERED )) {
cursor_type = SQLSRV_CURSOR_BUFFERED;
}
@ -1553,7 +1548,7 @@ void convert_to_zval( _Inout_ sqlsrv_stmt* stmt, _In_ SQLSRV_PHPTYPE sqlsrv_php_
// put in the column size and scale/decimal digits of the sql server type
// these values are taken from the MSDN page at http://msdn2.microsoft.com/en-us/library/ms711786(VS.85).aspx
// for SQL_VARBINARY, SQL_VARCHAR, and SQL_WLONGVARCHAR types, see https://msdn.microsoft.com/en-CA/library/ms187993.aspx
bool determine_column_size_or_precision( sqlsrv_stmt const* stmt, _In_ sqlsrv_sqltype sqlsrv_type, _Inout_ SQLULEN* column_size,
bool determine_column_size_or_precision( sqlsrv_stmt const* stmt, _In_ sqlsrv_sqltype sqlsrv_type, _Inout_ SQLULEN* column_size,
_Out_ SQLSMALLINT* decimal_digits )
{
*decimal_digits = 0;
@ -1608,7 +1603,7 @@ bool determine_column_size_or_precision( sqlsrv_stmt const* stmt, _In_ sqlsrv_sq
}
break;
case SQL_WCHAR:
case SQL_WVARCHAR:
case SQL_WVARCHAR:
*column_size = sqlsrv_type.typeinfo.size;
if( *column_size == SQLSRV_SIZE_MAX_TYPE ) {
*column_size = SQL_SS_LENGTH_UNLIMITED;
@ -1731,7 +1726,7 @@ sqlsrv_phptype determine_sqlsrv_php_type( _In_ ss_sqlsrv_stmt const* stmt, _In_
case SQL_SS_TIME2:
case SQL_TYPE_TIMESTAMP:
{
if (stmt->date_as_string) {
if (stmt->date_as_string) {
sqlsrv_phptype.typeinfo.type = SQLSRV_PHPTYPE_STRING;
sqlsrv_phptype.typeinfo.encoding = stmt->encoding();
}
@ -1749,7 +1744,7 @@ sqlsrv_phptype determine_sqlsrv_php_type( _In_ ss_sqlsrv_stmt const* stmt, _In_
if( sqlsrv_phptype.typeinfo.encoding == SQLSRV_ENCODING_DEFAULT ) {
sqlsrv_phptype.typeinfo.encoding = stmt->conn->encoding();
}
return sqlsrv_phptype;
}
@ -1793,9 +1788,9 @@ void determine_stmt_has_rows( _Inout_ ss_sqlsrv_stmt* stmt TSRMLS_DC )
}
}
else {
// otherwise, we fetch the first row, but record that we did. sqlsrv_fetch checks this
// flag and simply skips the first fetch, knowing it was already done. It records its own
// flag and simply skips the first fetch, knowing it was already done. It records its own
// flags to know if it should fetch on subsequent calls.
r = core::SQLFetchScroll( stmt, SQL_FETCH_NEXT, 0 TSRMLS_CC );
@ -1812,7 +1807,7 @@ SQLSMALLINT get_resultset_meta_data(_Inout_ sqlsrv_stmt * stmt)
{
// get the numer of columns in the result set
SQLSMALLINT num_cols = -1;
num_cols = stmt->current_meta_data.size();
bool getMetaData = false;
@ -1887,8 +1882,8 @@ void fetch_fields_common( _Inout_ ss_sqlsrv_stmt* stmt, _In_ zend_long fetch_typ
throw ss::SSException();
}
#else
array_init(&fields);
#endif
array_init(&fields);
#endif
for( int i = 0; i < num_cols; ++i ) {
SQLLEN field_len = -1;
@ -1924,7 +1919,7 @@ void fetch_fields_common( _Inout_ ss_sqlsrv_stmt* stmt, _In_ zend_long fetch_typ
}
}
//only addref when the fetch_type is BOTH because this is the only case when fields(hashtable)
//has 2 elements pointing to field. Do not addref if the type is NUMERIC or ASSOC because
//has 2 elements pointing to field. Do not addref if the type is NUMERIC or ASSOC because
//fields now only has 1 element pointing to field and we want the ref count to be only 1
if (fetch_type == SQLSRV_FETCH_BOTH) {
Z_TRY_ADDREF(field);
@ -1934,7 +1929,7 @@ void fetch_fields_common( _Inout_ ss_sqlsrv_stmt* stmt, _In_ zend_long fetch_typ
}
void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array, zend_ulong index, _Out_ SQLSMALLINT& direction,
_Out_ SQLSRV_PHPTYPE& php_out_type, _Out_ SQLSRV_ENCODING& encoding, _Out_ SQLSMALLINT& sql_type,
_Out_ SQLSRV_PHPTYPE& php_out_type, _Out_ SQLSRV_ENCODING& encoding, _Out_ SQLSMALLINT& sql_type,
_Out_ SQLULEN& column_size, _Out_ SQLSMALLINT& decimal_digits TSRMLS_DC )
{
@ -1954,7 +1949,7 @@ void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array,
// handle the array parameters that contain the value/var, direction, php_type, sql_type
zend_hash_internal_pointer_reset_ex( param_ht, &pos );
if( zend_hash_has_more_elements_ex( param_ht, &pos ) == FAILURE ||
if( zend_hash_has_more_elements_ex( param_ht, &pos ) == FAILURE ||
(var_or_val = zend_hash_get_current_data_ex(param_ht, &pos)) == NULL) {
THROW_SS_ERROR( stmt, SS_SQLSRV_ERROR_VAR_REQUIRED, index + 1 );
@ -1977,7 +1972,7 @@ void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array,
CHECK_CUSTOM_ERROR( !Z_ISREF_P( var_or_val ) && ( direction == SQL_PARAM_OUTPUT || direction == SQL_PARAM_INPUT_OUTPUT ), stmt, SS_SQLSRV_ERROR_PARAM_VAR_NOT_REF, index + 1 ) {
throw ss::SSException();
}
}
else {
direction = SQL_PARAM_INPUT;
@ -1986,7 +1981,7 @@ void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array,
// extract the php type and encoding from the 3rd parameter
if ( zend_hash_move_forward_ex( param_ht, &pos ) == SUCCESS && ( temp = zend_hash_get_current_data_ex( param_ht, &pos )) != NULL &&
Z_TYPE_P( temp ) != IS_NULL ) {
php_type_param_was_null = false;
sqlsrv_phptype sqlsrv_phptype;
@ -1997,7 +1992,7 @@ void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array,
sqlsrv_phptype.value = Z_LVAL_P( temp );
CHECK_CUSTOM_ERROR( !is_valid_sqlsrv_phptype( sqlsrv_phptype ), stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE,
CHECK_CUSTOM_ERROR( !is_valid_sqlsrv_phptype( sqlsrv_phptype ), stmt, SQLSRV_ERROR_INVALID_PARAMETER_PHPTYPE,
index + 1 ) {
throw ss::SSException();
@ -2005,7 +2000,7 @@ void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array,
php_out_type = static_cast<SQLSRV_PHPTYPE>( sqlsrv_phptype.typeinfo.type );
encoding = ( SQLSRV_ENCODING ) sqlsrv_phptype.typeinfo.encoding;
// if the call has a SQLSRV_PHPTYPE_STRING/STREAM('default'), then the stream is in the encoding established
// if the call has a SQLSRV_PHPTYPE_STRING/STREAM('default'), then the stream is in the encoding established
// by the connection
if( encoding == SQLSRV_ENCODING_DEFAULT ) {
encoding = stmt->conn->encoding();
@ -2013,7 +2008,7 @@ void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array,
}
// set default for php type and encoding if not supplied
else {
php_type_param_was_null = true;
if ( Z_ISREF_P( var_or_val )){
@ -2025,7 +2020,7 @@ void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array,
encoding = stmt->encoding();
if( encoding == SQLSRV_ENCODING_DEFAULT ) {
encoding = stmt->conn->encoding();
}
}
}
// get the server type, column size/precision and the decimal digits if provided
@ -2042,12 +2037,12 @@ void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array,
sqlsrv_sql_type.value = Z_LVAL_P( temp );
// since the user supplied this type, make sure it's valid
CHECK_CUSTOM_ERROR( !is_valid_sqlsrv_sqltype( sqlsrv_sql_type ), stmt, SQLSRV_ERROR_INVALID_PARAMETER_SQLTYPE,
CHECK_CUSTOM_ERROR( !is_valid_sqlsrv_sqltype( sqlsrv_sql_type ), stmt, SQLSRV_ERROR_INVALID_PARAMETER_SQLTYPE,
index + 1 ) {
throw ss::SSException();
}
}
bool size_okay = determine_column_size_or_precision( stmt, sqlsrv_sql_type, &column_size, &decimal_digits );
CHECK_CUSTOM_ERROR( !size_okay, stmt, SS_SQLSRV_ERROR_INVALID_PARAMETER_PRECISION, index + 1 ) {
@ -2076,7 +2071,7 @@ void parse_param_array( _Inout_ ss_sqlsrv_stmt* stmt, _Inout_ zval* param_array,
sqlsrv_phptype sqlsrv_phptype;
sqlsrv_phptype = determine_sqlsrv_php_type( stmt, sql_type, (SQLUINTEGER)column_size, true );
// we DIE here since everything should have been validated already and to return the user an error
// for our own logic error would be confusing/misleading.
SQLSRV_ASSERT( sqlsrv_phptype.typeinfo.type != PHPTYPE_INVALID, "An invalid php type was returned with (supposed) "
@ -2121,7 +2116,7 @@ bool is_valid_sqlsrv_phptype( _In_ sqlsrv_phptype type )
case SQLSRV_PHPTYPE_STRING:
case SQLSRV_PHPTYPE_STREAM:
{
if( type.typeinfo.encoding == SQLSRV_ENCODING_BINARY || type.typeinfo.encoding == SQLSRV_ENCODING_CHAR
if( type.typeinfo.encoding == SQLSRV_ENCODING_BINARY || type.typeinfo.encoding == SQLSRV_ENCODING_CHAR
|| type.typeinfo.encoding == CP_UTF8 || type.typeinfo.encoding == SQLSRV_ENCODING_DEFAULT ) {
return true;
}
@ -2152,7 +2147,7 @@ bool is_valid_sqlsrv_sqltype( _In_ sqlsrv_sqltype sql_type )
case SQL_BINARY:
case SQL_CHAR:
case SQL_WCHAR:
case SQL_WVARCHAR:
case SQL_WVARCHAR:
case SQL_VARBINARY:
case SQL_VARCHAR:
case SQL_DECIMAL:
@ -2202,7 +2197,7 @@ void type_and_size_calc( INTERNAL_FUNCTION_PARAMETERS, _In_ int type )
int size = 0;
if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s", &size_p, &size_len ) == FAILURE ) {
return;
}
if (size_p) {
@ -2226,7 +2221,7 @@ void type_and_size_calc( INTERNAL_FUNCTION_PARAMETERS, _In_ int type )
}
int max_size = SQL_SERVER_MAX_FIELD_SIZE;
// size is actually the number of characters, not the number of bytes, so if they ask for a
// size is actually the number of characters, not the number of bytes, so if they ask for a
// 2 byte per character type, then we half the maximum size allowed.
if( type == SQL_WVARCHAR || type == SQL_WCHAR ) {
max_size >>= 1;
@ -2236,7 +2231,7 @@ void type_and_size_calc( INTERNAL_FUNCTION_PARAMETERS, _In_ int type )
LOG( SEV_ERROR, "invalid size. size must be > 0 and <= %1!d! characters or 'max'", max_size );
size = SQLSRV_INVALID_SIZE;
}
sqlsrv_sqltype sql_type;
sql_type.typeinfo.type = type;
sql_type.typeinfo.size = size;
@ -2253,15 +2248,15 @@ void type_and_precision_calc( INTERNAL_FUNCTION_PARAMETERS, _In_ int type )
zend_long scale = SQLSRV_INVALID_SCALE;
if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "|ll", &prec, &scale ) == FAILURE ) {
return;
}
if( prec > SQL_SERVER_MAX_PRECISION ) {
LOG( SEV_ERROR, "Invalid precision. Precision can't be > 38" );
prec = SQLSRV_INVALID_PRECISION;
}
if( prec < 0 ) {
LOG( SEV_ERROR, "Invalid precision. Precision can't be negative" );
prec = SQLSRV_INVALID_PRECISION;
@ -2285,11 +2280,11 @@ void type_and_precision_calc( INTERNAL_FUNCTION_PARAMETERS, _In_ int type )
void type_and_encoding( INTERNAL_FUNCTION_PARAMETERS, _In_ int type )
{
SQLSRV_ASSERT(( type == SQLSRV_PHPTYPE_STREAM || type == SQLSRV_PHPTYPE_STRING ), "type_and_encoding: Invalid type passed." );
SQLSRV_ASSERT(( type == SQLSRV_PHPTYPE_STREAM || type == SQLSRV_PHPTYPE_STRING ), "type_and_encoding: Invalid type passed." );
char* encoding_param;
size_t encoding_param_len = 0;
// set the default encoding values to invalid so that
// if the encoding isn't validated, it will return the invalid setting.
sqlsrv_phptype sqlsrv_php_type;
@ -2297,7 +2292,7 @@ void type_and_encoding( INTERNAL_FUNCTION_PARAMETERS, _In_ int type )
sqlsrv_php_type.typeinfo.encoding = SQLSRV_ENCODING_INVALID;
if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s", &encoding_param, &encoding_param_len ) == FAILURE ) {
ZVAL_LONG( return_value, sqlsrv_php_type.value );
}

View file

@ -3,7 +3,7 @@
//
// Contents: Version resource
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -5,7 +5,7 @@
//
// Comments: Mostly error handling and some type handling
//
// Microsoft Drivers 5.7 for PHP for SQL Server
// Microsoft Drivers 5.8 for PHP for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License

View file

@ -1707,19 +1707,21 @@ function CallProcEx($conn, $procName, $procPrefix, $procArgs, $procValues)
function CreateFunc($conn, $funcName, $funcArgs, $retType, $funcCode)
{
DropFunc($conn, $funcName);
$stmt = sqlsrv_query($conn, "CREATE FUNCTION [$funcName] ($funcArgs) RETURNS $retType AS BEGIN $funcCode END");
if ($stmt === false) {
FatalError("Failed to create test function");
try {
$stmt = $conn->query("CREATE FUNCTION [$funcName] ($funcArgs) RETURNS $retType AS BEGIN $funcCode END");
} catch (PDOException $e) {
echo "Failed to create test function\n";
var_dump($e);
}
sqlsrv_free_stmt($stmt);
unset($stmt);
}
function DropFunc($conn, $funcName)
{
$stmt = sqlsrv_query($conn, "DROP FUNCTION [$funcName]");
if ($stmt === false) {
} else {
sqlsrv_free_stmt($stmt);
try {
$conn->query("DROP FUNCTION [$funcName]");
} catch (PDOException $e) {
; // do nothing
}
}

View file

@ -0,0 +1,76 @@
--TEST--
GitHub issue 1063 - make setting locale info configurable
--DESCRIPTION--
This test assumes LC_ALL is 'en_US.UTF-8' and verifies that the users can configure using ini file to set application locale using the system locale or not. This test is valid for Linux and macOS systems only.
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif_unix_locales.inc'); ?>
--FILE--
<?php
function runTest($val, $file, $locale)
{
print("\n***sqlsrv.SetLocaleInfo = $val\npdo_sqlsrv.set_locale_info = $val***\n\n");
shell_exec("echo 'sqlsrv.SetLocaleInfo = $val\npdo_sqlsrv.set_locale_info = $val' > $file");
print_r(shell_exec(PHP_BINARY." ".dirname(__FILE__)."/pdo_1063_test_locale.php $val"));
print_r(shell_exec(PHP_BINARY." ".dirname(__FILE__)."/pdo_1063_test_locale.php $val $locale"));
}
$inifile = PHP_CONFIG_FILE_SCAN_DIR."/99-overrides.ini";
$locale1 = strtoupper(PHP_OS) === 'LINUX' ? "en_US.ISO-8859-1" : "en_US.ISO8859-1";
$locale2 = 'de_DE.UTF-8';
runTest(0, $inifile, $locale1);
runTest(1, $inifile, $locale2);
runTest(2, $inifile, $locale2);
?>
--EXPECT--
***sqlsrv.SetLocaleInfo = 0
pdo_sqlsrv.set_locale_info = 0***
**Begin**
Amount formatted: 10000.99
Friday
December
3.14159
**End**
**Begin**
Amount formatted: $10,000.99
Friday
December
3.14159
**End**
***sqlsrv.SetLocaleInfo = 1
pdo_sqlsrv.set_locale_info = 1***
**Begin**
Amount formatted: 10000.99
Friday
December
3.14159
**End**
**Begin**
Amount formatted: 10.000,99 
Freitag
Dezember
3,14159
**End**
***sqlsrv.SetLocaleInfo = 2
pdo_sqlsrv.set_locale_info = 2***
**Begin**
Amount formatted: $10,000.99
Friday
December
3.14159
**End**
**Begin**
Amount formatted: 10.000,99 
Freitag
Dezember
3,14159
**End**

View file

@ -0,0 +1,121 @@
<?php
// This test is invoked by pdo_1063_locale_configs.phpt
function dropTable($conn, $tableName)
{
$tsql = "IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'" . $tableName . "') AND type in (N'U')) DROP TABLE $tableName";
$conn->exec($tsql);
}
function printMoney($amt, $info)
{
// The money_format() function is deprecated in PHP 7.4, so use intl NumberFormatter
$loc = setlocale(LC_MONETARY, 0);
$symbol = $info['int_curr_symbol'];
echo "Amount formatted: ";
if (empty($symbol)) {
echo number_format($amt, 2, '.', '');
} else {
$fmt = new NumberFormatter($loc, NumberFormatter::CURRENCY);
$fmt->setTextAttribute(NumberFormatter::CURRENCY_CODE, $symbol);
$fmt->setAttribute(NumberFormatter::FRACTION_DIGITS, 2);
echo $fmt->format($amt);
}
echo PHP_EOL;
}
require_once('MsSetup.inc');
$setLocaleInfo = ($_SERVER['argv'][1]);
$locale = ($_SERVER['argv'][2] ?? '');
echo "**Begin**" . PHP_EOL;
// Assuming LC_ALL is 'en_US.UTF-8', so is LC_CTYPE
// But default LC_MONETARY varies
$ctype = 'en_US.UTF-8';
switch ($setLocaleInfo) {
case 0:
case 1:
$m = 'C'; $symbol = ''; $sep = '';
break;
case 2:
$m = 'en_US.UTF-8'; $symbol = '$'; $sep = ',';
break;
default:
die("Unexpected $setLocaleInfo\n");
break;
}
$m1 = setlocale(LC_MONETARY, 0);
if ($m !== $m1) {
echo "Unexpected LC_MONETARY: $m1" . PHP_EOL;
}
$c1 = setlocale(LC_CTYPE, 0);
if ($ctype !== $c1) {
echo "Unexpected LC_CTYPE: $c1" . PHP_EOL;
}
// Set a different locale, if the input is not empty
if (!empty($locale)) {
$loc = setlocale(LC_ALL, $locale);
if ($loc !== $locale) {
echo "Unexpected $loc for LC_ALL " . PHP_EOL;
}
// Currency symbol and thousands separator in Linux and macOS may be different
if ($loc === 'de_DE.UTF-8') {
$symbol = strtoupper(PHP_OS) === 'LINUX' ? '€' : 'Eu';
$sep = strtoupper(PHP_OS) === 'LINUX' ? '.' : '';
} else {
$symbol = '$';
$sep = ',';
}
}
$info = localeconv();
if ($symbol !== $info['currency_symbol']) {
echo "$locale: Expected currency symbol '$symbol' but get '" . $info['currency_symbol'] . "'";
echo PHP_EOL;
}
if ($sep !== $info['thousands_sep']) {
echo "$locale: Expected thousands separator '$sep' but get '" . $info['currency_symbol'] . "'";
echo PHP_EOL;
}
$n1 = 10000.98765;
printMoney($n1, $info);
echo strftime("%A", strtotime("12/25/2020")) . PHP_EOL;
echo strftime("%B", strtotime("12/25/2020")) . PHP_EOL;
try {
$conn = new PDO("sqlsrv:server = $server; database=$databaseName; driver=$driver", $uid, $pwd );
$tableName = "[" . "pdo1063" . $locale . "]";
dropTable($conn, $tableName);
$pi = "3.14159";
$stmt = $conn->query("CREATE TABLE $tableName (c1 FLOAT)");
$stmt = $conn->query("INSERT INTO $tableName (c1) VALUES ($pi)");
$sql = "SELECT c1 FROM $tableName";
$stmt = $conn->prepare($sql, array(PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE => true));
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_NUM);
echo ($row[0]) . PHP_EOL;
unset($stmt);
dropTable($conn, $tableName);
unset($conn);
} catch( PDOException $e ) {
print_r( $e->getMessage() );
}
echo "**End**" . PHP_EOL;
?>

View file

@ -0,0 +1,59 @@
--TEST--
GitHub issue 1079 - fetching sql_variant types using client buffers
--DESCRIPTION--
This test verifies that fetching sql_variant types using client buffers is supported.
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once("MsSetup.inc");
require_once("MsCommon_mid-refactor.inc");
try {
$conn = connect();
$funcName = 'PDO1079';
dropFunc($conn, $funcName);
$tsql = "CREATE FUNCTION [$funcName](@OP1 sql_variant, @OP2 sql_variant) RETURNS sql_variant AS
BEGIN DECLARE @Result sql_variant SET @Result = CASE WHEN @OP1 >= @OP2 THEN @OP1 ELSE @OP2 END RETURN @Result END";
$conn->exec($tsql);
$tsql = "SELECT [dbo].[$funcName](5, 6) AS RESULT";
$stmt = $conn->prepare($tsql, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_BUFFERED));
$stmt->execute();
$metadata = $stmt->getColumnMeta(0);
var_dump($metadata);
dropFunc($conn, $funcName);
unset($stmt);
unset($conn);
} catch (PdoException $e) {
echo $e->getMessage() . PHP_EOL;
}
?>
--EXPECT--
array(8) {
["flags"]=>
int(0)
["sqlsrv:decl_type"]=>
string(11) "sql_variant"
["native_type"]=>
string(6) "string"
["table"]=>
string(0) ""
["pdo_type"]=>
int(2)
["name"]=>
string(6) "RESULT"
["len"]=>
int(10)
["precision"]=>
int(0)
}

View file

@ -59,7 +59,7 @@ if (!$conn) {
$query = "SELECT [name], [value], [value_in_use] FROM sys.configurations WHERE [name] = 'column encryption enclave type';";
$stmt = $conn->query($query);
$info = $stmt->fetch();
if ($info['value'] == 1 and $info['value_in_use'] == 1) {
if (!empty($info) and $info['value'] == 1 and $info['value_in_use'] == 1) {
$isEnclaveEnabled = true;
}

View file

@ -170,11 +170,15 @@ function doValuesMatched($value1, $value2, $row, $col)
}
}
function fetchColumns($conn, $tableName, $numRows, $numCols)
function fetchColumns($conn, $tableName, $numRows, $numCols, $buffered = false)
{
try {
// insert column data from a row of the original table
$stmtOriginal = $conn->prepare("SELECT * FROM $tableName WHERE c1_int = :row");
if ($buffered) {
$stmtOriginal = $conn->prepare("SELECT * FROM $tableName WHERE c1_int = :row", array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_BUFFERED));
} else {
$stmtOriginal = $conn->prepare("SELECT * FROM $tableName WHERE c1_int = :row");
}
for ($i = 1; $i <= $numRows; $i++) {
$c1_int = $i;
@ -263,6 +267,7 @@ try {
$numCols = fetchBoundMixed($conn, $tableName, $numRows);
fetchColumns($conn, $tableName, $numRows, $numCols);
fetchColumns($conn, $tableName, $numRows, $numCols, true);
dropTable($conn, $tableName);
unset($conn);
@ -278,3 +283,7 @@ Insert all columns from row 1 into one column of type sql_variant
string(11) "sql_variant"
Insert all columns from row 2 into one column of type sql_variant
string(11) "sql_variant"
Insert all columns from row 1 into one column of type sql_variant
string(11) "sql_variant"
Insert all columns from row 2 into one column of type sql_variant
string(11) "sql_variant"

View file

@ -76,10 +76,15 @@ function updateFood($conn, $tableName, $id, $food, $category)
}
}
function fetchRows($conn, $tableName)
function fetchRows($conn, $tableName, $buffered = false)
{
$query = "SELECT * FROM $tableName ORDER BY id";
$stmt = $conn->query($query);
if ($buffered) {
$stmt = $conn->prepare($query, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL, PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_BUFFERED));
$stmt->execute();
} else {
$stmt = $conn->query($query);
}
$stmt->setFetchMode(PDO::FETCH_CLASS, 'Food');
while ($food = $stmt->fetch()) {
@ -108,7 +113,7 @@ try {
updateID($conn, $tableName, 4, 'Milk', 'Diary Products');
fetchRows($conn, $tableName);
fetchRows($conn, $tableName, true);
updateFood($conn, $tableName, 4, 'Cheese', 'Diary Products');
@ -118,7 +123,7 @@ try {
insertData($conn, $tableName, 6, 'Salmon', 'Fish');
insertData($conn, $tableName, 2, 'Broccoli', 'Vegetables');
fetchRows($conn, $tableName);
fetchRows($conn, $tableName, true);
dropTable($conn, $tableName);
unset($conn);

View file

@ -1,4 +1,4 @@
<?php
if (!extension_loaded("pdo") || !extension_loaded('pdo_sqlsrv'))
die("PDO driver cannot be loaded; skipping test.\n");
?>
if (!extension_loaded("pdo_sqlsrv")) {
die("skip Extension not loaded");
}

View file

@ -1,8 +1,8 @@
<?php
if (!extension_loaded("pdo") || !extension_loaded('pdo_sqlsrv'))
die("PDO driver cannot be loaded; skipping test.\n");
if (!extension_loaded("pdo_sqlsrv")) {
die("skip Extension not loaded");
}
require 'MsSetup.inc';
if ($daasMode) die("skip test not applicable in Azure\n");
?>
if ($daasMode) {
die("skip test not applicable in Azure\n");
}

View file

@ -1,17 +1,17 @@
<?php
if (!extension_loaded("pdo") || !extension_loaded('pdo_sqlsrv')) {
die("PDO driver cannot be loaded; skipping test.\n");
}
require_once("MsSetup.inc");
require_once("MsCommon_mid-refactor.inc");
$dsn = getDSN($server, null);
$conn = new PDO($dsn, $uid, $pwd);
if (! $conn) {
echo("Error: could not connect during SKIPIF!");
} elseif (isColEncrypted()) {
if (!isAEQualified($conn)) {
die("skip - AE feature not supported in the current environment.");
}
}
<?php
if (!extension_loaded("pdo_sqlsrv")) {
die("skip Extension not loaded");
}
require_once("MsSetup.inc");
require_once("MsCommon_mid-refactor.inc");
$dsn = getDSN($server, null);
$conn = new PDO($dsn, $uid, $pwd);
if (! $conn) {
die("skip could not connect during SKIPIF!");
} elseif (isColEncrypted()) {
if (!isAEQualified($conn)) {
die("skip - AE feature not supported in the current environment.");
}
}

View file

@ -1,24 +1,25 @@
<?php
if (!extension_loaded("pdo") || !extension_loaded('pdo_sqlsrv')) {
die("PDO driver cannot be loaded; skipping test.\n");
}
require_once("MsSetup.inc");
if ($keystore != 'akv')
die ( 'skip - the test requires valid Azure Key Vault credentials.' );
if ($driver != "ODBC Driver 17 for SQL Server") {
// the testing is not set to use ODBC 17
die("skip - AE feature not supported in the current environment.");
}
require_once("MsCommon_mid-refactor.inc");
$dsn = getDSN($server, null);
$conn = new PDO($dsn, $uid, $pwd);
if (! $conn) {
echo("Error: could not connect during SKIPIF!");
} elseif (!isAEQualified($conn)) {
die("skip - AE feature not supported in the current environment.");
}
<?php
if (!extension_loaded("pdo_sqlsrv")) {
die("skip Extension not loaded");
}
require_once("MsSetup.inc");
if ($keystore != 'akv') {
die('skip the test requires valid Azure Key Vault credentials.');
}
if ($driver != "ODBC Driver 17 for SQL Server") {
// the testing is not set to use ODBC 17
die("skip AE feature not supported in the current environment.");
}
require_once("MsCommon_mid-refactor.inc");
$dsn = getDSN($server, null);
$conn = new PDO($dsn, $uid, $pwd);
if (! $conn) {
die("skip could not connect during SKIPIF!");
} elseif (!isAEQualified($conn)) {
die("skip AE feature not supported in the current environment.");
}

View file

@ -1,8 +1,9 @@
<?php
if ( !( strtoupper( substr( php_uname( 's' ),0,3 ) ) === 'WIN' ) ) die( "Skip, test on windows only." );
if (!(strtoupper(substr(php_uname('s'), 0, 3)) === 'WIN')) {
die("Skip test on windows only.");
}
if (!extension_loaded("pdo") || !extension_loaded('pdo_sqlsrv'))
die("PDO driver cannot be loaded; skipping test.\n");
?>
if (!extension_loaded("pdo") || !extension_loaded('pdo_sqlsrv')) {
die("skip extension not loaded");
}

View file

@ -0,0 +1,28 @@
<?php
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
die("skip Test for Linux and macOS");
}
if (!extension_loaded("pdo_sqlsrv")) {
die("skip Extension not loaded");
}
// check if the required ini file exists
$inifile = PHP_CONFIG_FILE_SCAN_DIR."/99-overrides.ini";
if (!file_exists($inifile)) {
die("skip required ini file not exists");
}
// if the file exists, is it writable? '@' sign is used to suppress warnings
$file = @fopen($inifile, "w");
if (!$file) {
die("skip required ini file not writable");
}
fclose($file);
$loc = setlocale(LC_TIME, 'de_DE.UTF-8');
if (empty($loc)) {
die("skip required locale not available");
}

View file

@ -1,18 +1,15 @@
<?php
if (! extension_loaded( 'pdo' ) || ! extension_loaded( 'pdo_sqlsrv' ))
die( "PDO driver cannot be loaded; skipping test.\n" );
if (!extension_loaded("pdo_sqlsrv")) {
die("skip Extension not loaded");
}
require_once( "MsSetup.inc" );
require_once( "MsCommon.inc" );
require_once("MsSetup.inc");
require_once("MsCommon.inc");
$conn = ae_connect();
if( ! $conn )
{
echo( "Error: could not connect during SKIPIF!" );
if (! $conn) {
die("skip could not connect during SKIPIF!");
} elseif (! IsAEQualified($conn)) {
die("skip AE feature not supported in the current environment.");
}
else if(! IsAEQualified($conn))
{
die( "skip - AE feature not supported in the current environment." );
}
?>

View file

@ -7,9 +7,6 @@ Validates that a prepared statement can be successfully executed more than once.
PHPT_EXEC=true
--SKIPIF--
<?php
require_once('MsCommon.inc');
// locale must be set before 1st connection
setUSAnsiLocale();
require('skipif_versions_old.inc');
?>
--FILE--

View file

@ -7,9 +7,6 @@ retrieving fields from a table including rows with all supported SQL types (28 t
PHPT_EXEC=true
--SKIPIF--
<?php
require_once('MsCommon.inc');
// locale must be set before 1st connection
setUSAnsiLocale();
require('skipif_versions_old.inc');
?>
--FILE--

View file

@ -3,12 +3,7 @@ Fetch Field Data Test verifies the data retrieved via sqlsrv_get_field
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?
require_once('MsCommon.inc');
// locale must be set before 1st connection
setUSAnsiLocale();
require('skipif_versions_old.inc');
?>
<?php require('skipif_versions_old.inc'); ?>
--FILE--
<?php

View file

@ -6,12 +6,7 @@ by checking all fetch type modes.
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?
require_once('MsCommon.inc');
// locale must be set before 1st connection
setUSAnsiLocale();
require('skipif_versions_old.inc');
?>
<?php require('skipif_versions_old.inc'); ?>
--FILE--
<?php
require_once('MsCommon.inc');

View file

@ -6,9 +6,6 @@ Verifies data retrieval via "sqlsrv_fetch_object".
PHPT_EXEC=true
--SKIPIF--
<?php
require_once('MsCommon.inc');
// locale must be set before 1st connection
setUSAnsiLocale();
require('skipif_versions_old.inc');
?>
--FILE--

View file

@ -5,12 +5,7 @@ Verifies the functionality of "sqlsrv_next_result"
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?
require_once('MsCommon.inc');
// locale must be set before 1st connection
setUSAnsiLocale();
require('skipif_versions_old.inc');
?>
<?php require('skipif_versions_old.inc'); ?>
--FILE--
<?php
require_once('MsCommon.inc');

View file

@ -6,9 +6,6 @@ Verifies data retrieval with scrollable result sets.
PHPT_EXEC=true
--SKIPIF--
<?php
require_once('MsCommon.inc');
// locale must be set before 1st connection
setUSAnsiLocale();
require('skipif_versions_old.inc');
?>
--FILE--

View file

@ -6,12 +6,7 @@ can be successfully retrieved as streams.
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?
require_once('MsCommon.inc');
// locale must be set before 1st connection
setUSAnsiLocale();
require('skipif_versions_old.inc');
?>
<?php require('skipif_versions_old.inc'); ?>
--FILE--
<?php
require_once('MsCommon.inc');

View file

@ -5,12 +5,7 @@ Verifies the streaming behavior with scrollable resultsets.
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?
require_once('MsCommon.inc');
// locale must be set before 1st connection
setUSAnsiLocale();
require('skipif_versions_old.inc');
?>
<?php require('skipif_versions_old.inc'); ?>
--FILE--
<?php
require_once('MsCommon.inc');

View file

@ -1,24 +1,24 @@
<?php
if (! extension_loaded("sqlsrv")) {
die("skip extension not loaded");
}
require_once("MsSetup.inc");
if ($keystore != 'akv')
die ( 'skip - the test requires valid Azure Key Vault credentials.' );
if ($driver != "ODBC Driver 17 for SQL Server") {
// the testing is not set to use ODBC 17
die("skip - AE feature not supported in the current environment.");
}
require_once('MsCommon.inc');
$conn = AE\connect();
if (! $conn) {
echo("Error: could not connect during SKIPIF!");
} elseif (!AE\isQualified($conn)) {
die("skip - AE feature not supported in the current environment.");
}
?>
<?php
if (! extension_loaded("sqlsrv")) {
die("skip extension not loaded");
}
require_once("MsSetup.inc");
if ($keystore != 'akv') {
die('skip the test requires valid Azure Key Vault credentials.');
}
if ($driver != "ODBC Driver 17 for SQL Server") {
// the testing is not set to use ODBC 17
die("skip AE feature not supported in the current environment.");
}
require_once('MsCommon.inc');
$conn = AE\connect();
if (! $conn) {
die("skip could not connect during SKIPIF!");
} elseif (!AE\isQualified($conn)) {
die("skip AE feature not supported in the current environment.");
}

View file

@ -1,9 +1,9 @@
<?php
if ( !( strtoupper( substr( php_uname( 's' ),0,3 ) ) === 'WIN' ) ) die( "Skip, test on windows only." );
if (!(strtoupper(substr(php_uname('s'), 0, 3)) === 'WIN')) {
die("Skip Test on windows only.");
}
if (!extension_loaded("sqlsrv")) {
die("skip extension not loaded");
}
?>

View file

@ -0,0 +1,28 @@
<?php
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
die("skip: Test for Linux and macOS");
}
if (!extension_loaded("sqlsrv")) {
die("skip extension not loaded");
}
// check if the required ini file exists
$inifile = PHP_CONFIG_FILE_SCAN_DIR."/99-overrides.ini";
if (!file_exists($inifile)) {
die("skip required ini file not exists");
}
// if the file exists, is it writable? '@' sign is used to suppress warnings
$file = @fopen($inifile, "w");
if (!$file) {
die("skip required ini file not writable");
}
fclose($file);
$loc = setlocale(LC_TIME, 'de_DE.UTF-8');
if (empty($loc)) {
die("skip required locale not available");
}

View file

@ -1,17 +1,16 @@
<?php
if (! extension_loaded("sqlsrv")) {
die("skip extension not loaded");
}
require_once('MsCommon.inc');
$conn = AE\connect();
if (! $conn) {
echo("Error: could not connect during SKIPIF!");
} elseif (AE\isColEncrypted()) {
if (!AE\isQualified($conn)) {
die("skip - AE feature not supported in the current environment.");
}
}
?>
<?php
if (! extension_loaded("sqlsrv")) {
die("skip extension not loaded");
}
require_once('MsCommon.inc');
$conn = AE\connect();
if (! $conn) {
die("Skip Could not connect during SKIPIF!");
} elseif (AE\isColEncrypted()) {
if (!AE\isQualified($conn)) {
die("skip AE feature not supported in the current environment.");
}
}

View file

@ -62,7 +62,7 @@ if (!$conn) {
$query = "SELECT [name], [value], [value_in_use] FROM sys.configurations WHERE [name] = 'column encryption enclave type';";
$stmt = sqlsrv_query($conn, $query);
$info = sqlsrv_fetch_array($stmt);
if ($info['value'] == 1 and $info['value_in_use'] == 1) {
if (!empty($info) and $info['value'] == 1 and $info['value_in_use'] == 1) {
$isEnclaveEnabled = true;
}

View file

@ -65,7 +65,8 @@ function insertData($conn, $tableName, $index)
function fetchData($conn, $tableName, $numRows)
{
$select = "SELECT * FROM $tableName ORDER BY c1_int";
$stmt = sqlsrv_query($conn, $select);
$stmt = sqlsrv_query($conn, $select, array(), array("Scrollable"=>"buffered"));
$stmt2 = sqlsrv_query($conn, $select);
$metadata = sqlsrv_field_metadata($stmt);

View file

@ -39,7 +39,7 @@ function Fetch($conn, $tableName, $numRows)
{
$select = "SELECT * FROM $tableName ORDER BY c1_int";
$stmt = sqlsrv_query($conn, $select);
$stmt2 = sqlsrv_query($conn, $select);
$stmt2 = sqlsrv_query($conn, $select, array(), array("Scrollable"=>"buffered"));
$stmt3 = sqlsrv_query($conn, $select);
$metadata = sqlsrv_field_metadata($stmt);

View file

@ -89,10 +89,15 @@ function updateCountry($conn, $tableName, $id, $country, $continent)
}
}
function fetch($conn, $tableName)
function fetch($conn, $tableName, $buffered = false)
{
$select = "SELECT * FROM $tableName ORDER BY id";
$stmt = sqlsrv_query($conn, $select);
if ($buffered) {
$stmt = sqlsrv_query($conn, $select, array(), array("Scrollable"=>"buffered"));
} else {
$stmt = sqlsrv_query($conn, $select);
}
while ($country = sqlsrv_fetch_object($stmt, "Country")) {
echo "\nID: " . $country->id . " ";
@ -125,13 +130,13 @@ try {
updateID($conn, $tableName, 4, 'Canada', 'North America');
// Read data
fetch($conn, $tableName);
fetch($conn, $tableName, true);
// Update country
updateCountry($conn, $tableName, 4, 'Mexico', 'North America');
// Read data
fetch($conn, $tableName);
fetch($conn, $tableName, true);
// Add two more countries
addCountry($conn, $tableName, 6, 'Brazil', 'South America');

View file

@ -0,0 +1,76 @@
--TEST--
GitHub issue 1063 - make setting locale info configurable
--DESCRIPTION--
This test assumes LC_ALL is 'en_US.UTF-8' and verifies that the users can configure using ini file to set application locale using the system locale or not. This test is valid for Linux and macOS systems only.
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif_unix_locales.inc'); ?>
--FILE--
<?php
function runTest($val, $file, $locale)
{
print("\n***sqlsrv.SetLocaleInfo = $val\npdo_sqlsrv.set_locale_info = $val***\n\n");
shell_exec("echo 'sqlsrv.SetLocaleInfo = $val\npdo_sqlsrv.set_locale_info = $val' > $file");
print_r(shell_exec(PHP_BINARY." ".dirname(__FILE__)."/srv_1063_test_locale.php $val"));
print_r(shell_exec(PHP_BINARY." ".dirname(__FILE__)."/srv_1063_test_locale.php $val $locale"));
}
$inifile = PHP_CONFIG_FILE_SCAN_DIR."/99-overrides.ini";
$locale1 = strtoupper(PHP_OS) === 'LINUX' ? "en_US.ISO-8859-1" : "en_US.ISO8859-1";
$locale2 = 'de_DE.UTF-8';
runTest(0, $inifile, $locale1);
runTest(1, $inifile, $locale2);
runTest(2, $inifile, $locale2);
?>
--EXPECT--
***sqlsrv.SetLocaleInfo = 0
pdo_sqlsrv.set_locale_info = 0***
**Begin**
Amount formatted: 10000.99
Friday
December
3.14159
**End**
**Begin**
Amount formatted: $10,000.99
Friday
December
3.14159
**End**
***sqlsrv.SetLocaleInfo = 1
pdo_sqlsrv.set_locale_info = 1***
**Begin**
Amount formatted: 10000.99
Friday
December
3.14159
**End**
**Begin**
Amount formatted: 10.000,99 
Freitag
Dezember
3,14159
**End**
***sqlsrv.SetLocaleInfo = 2
pdo_sqlsrv.set_locale_info = 2***
**Begin**
Amount formatted: $10,000.99
Friday
December
3.14159
**End**
**Begin**
Amount formatted: 10.000,99 
Freitag
Dezember
3,14159
**End**

View file

@ -0,0 +1,136 @@
<?php
// This test is invoked by srv_1063_locale_configs.phpt
function dropTable($conn, $tableName)
{
$tsql = "IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'" . $tableName . "') AND type in (N'U')) DROP TABLE $tableName";
sqlsrv_query($conn, $tsql);
}
function fatalError($message)
{
var_dump(sqlsrv_errors(SQLSRV_ERR_ALL));
die($message);
}
function printMoney($amt, $info)
{
// The money_format() function is deprecated in PHP 7.4, so use intl NumberFormatter
$loc = setlocale(LC_MONETARY, 0);
$symbol = $info['int_curr_symbol'];
echo "Amount formatted: ";
if (empty($symbol)) {
echo number_format($amt, 2, '.', '') . PHP_EOL;
} else {
$fmt = new NumberFormatter($loc, NumberFormatter::CURRENCY);
$fmt->setTextAttribute(NumberFormatter::CURRENCY_CODE, $symbol);
$fmt->setAttribute(NumberFormatter::FRACTION_DIGITS, 2);
echo $fmt->format($amt) . PHP_EOL;
}
}
require_once('MsSetup.inc');
$setLocaleInfo = ($_SERVER['argv'][1]);
$locale = ($_SERVER['argv'][2] ?? '');
echo "**Begin**" . PHP_EOL;
// Assuming LC_ALL is 'en_US.UTF-8', so is LC_CTYPE
// But default LC_MONETARY varies
$ctype = 'en_US.UTF-8';
switch ($setLocaleInfo) {
case 0:
case 1:
$m = 'C'; $symbol = ''; $sep = '';
break;
case 2:
$m = 'en_US.UTF-8'; $symbol = '$'; $sep = ',';
break;
default:
fatalError("Unexpected $setLocaleInfo\n");
break;
}
$m1 = setlocale(LC_MONETARY, 0);
if ($m !== $m1) {
echo "Unexpected LC_MONETARY: $m1" . PHP_EOL;
}
$c1 = setlocale(LC_CTYPE, 0);
if ($ctype !== $c1) {
echo "Unexpected LC_CTYPE: $c1" . PHP_EOL;
}
// Set a different locale, if the input is not empty
if (!empty($locale)) {
$loc = setlocale(LC_ALL, $locale);
if ($loc !== $locale) {
echo "Unexpected $loc for LC_ALL " . PHP_EOL;
}
// Currency symbol and thousands separator in Linux and macOS may be different
if ($loc === 'de_DE.UTF-8') {
$symbol = strtoupper(PHP_OS) === 'LINUX' ? '€' : 'Eu';
$sep = strtoupper(PHP_OS) === 'LINUX' ? '.' : '';
} else {
$symbol = '$';
$sep = ',';
}
}
$info = localeconv();
if ($symbol !== $info['currency_symbol']) {
echo "$locale: Expected currency symbol '$symbol' but get '" . $info['currency_symbol'] . "'";
echo PHP_EOL;
}
if ($sep !== $info['thousands_sep']) {
echo "$locale: Expected thousands separator '$sep' but get '" . $info['currency_symbol'] . "'";
echo PHP_EOL;
}
$n1 = 10000.98765;
printMoney($n1, $info);
echo strftime("%A", strtotime("12/25/2020")) . PHP_EOL;
echo strftime("%B", strtotime("12/25/2020")) . PHP_EOL;
$conn = sqlsrv_connect($server, $connectionOptions);
if (!$conn) {
fatalError("Failed to connect to $server.");
}
$tableName = "[" . "srv1063" . $locale . "]";
dropTable($conn, $tableName);
$pi = "3.14159";
$stmt = sqlsrv_query($conn, "CREATE TABLE $tableName (c1 FLOAT)");
if (!$stmt) {
fatalError("Failed to create test table $tableName");
}
$stmt = sqlsrv_query($conn, "INSERT INTO $tableName (c1) VALUES ($pi)");
if (!$stmt) {
fatalError("Failed to insert into test table $tableName");
}
$sql = "SELECT c1 FROM $tableName";
$stmt = sqlsrv_query($conn, $sql);
if (!$stmt) {
fatalError("Failed in running query $sql");
}
while (sqlsrv_fetch($stmt)) {
$value = sqlsrv_get_field($stmt, 0, SQLSRV_PHPTYPE_FLOAT);
echo $value . PHP_EOL;
}
sqlsrv_free_stmt($stmt);
dropTable($conn, $tableName);
sqlsrv_close($conn);
echo "**End**" . PHP_EOL;
?>

View file

@ -0,0 +1,62 @@
--TEST--
GitHub issue 1079 - fetching sql_variant types using client buffers
--DESCRIPTION--
This test verifies that fetching sql_variant types using client buffers is supported.
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif_versions_old.inc'); ?>
--FILE--
<?php
require_once('MsCommon.inc');
$conn = AE\connect();
$funcName = 'SRV1079';
dropFunc($conn, $funcName);
$tsql = "CREATE FUNCTION [$funcName](@OP1 sql_variant, @OP2 sql_variant) RETURNS sql_variant AS
BEGIN DECLARE @Result sql_variant SET @Result = CASE WHEN @OP1 >= @OP2 THEN @OP1 ELSE @OP2 END RETURN @Result END";
$stmt = sqlsrv_query($conn, $tsql);
if (!$stmt) {
fatalError('Could not create function\n');
}
$tsql = "SELECT [dbo].[$funcName](5, 6) AS RESULT";
$stmt = sqlsrv_prepare($conn, $tsql, array(), array("Scrollable" => SQLSRV_CURSOR_CLIENT_BUFFERED, "ClientBufferMaxKBSize" => 1000));
if (!$stmt) {
fatalError('Could not prepare query\n');
}
$result = sqlsrv_execute($stmt);
if (!$result) {
fatalError('Executing the query failed\n');
}
foreach (sqlsrv_field_metadata($stmt) as $fieldMetadata) {
var_dump($fieldMetadata);
}
dropFunc($conn, $funcName);
sqlsrv_free_stmt($stmt);
sqlsrv_close($conn);
?>
--EXPECT--
array(6) {
["Name"]=>
string(6) "RESULT"
["Type"]=>
int(-150)
["Size"]=>
int(10)
["Precision"]=>
NULL
["Scale"]=>
NULL
["Nullable"]=>
int(1)
}

View file

@ -1,12 +1,7 @@
--TEST--
streaming large amounts of data into a database and getting it out as a string exactly the same.
--SKIPIF--
<?
require_once('MsCommon.inc');
// locale must be set before 1st connection
setUSAnsiLocale();
require('skipif.inc');
?>
<?php require('skipif.inc'); ?>
--FILE--
<?php