|
| 1 | +# AI Agent Guidelines for Microsoft Drivers for PHP for SQL Server |
| 2 | + |
| 3 | +This document provides guidance for AI coding agents working with the msphpsql GitHub repository — the open-source home of the **sqlsrv** and **pdo_sqlsrv** PHP extensions for Microsoft SQL Server. |
| 4 | + |
| 5 | +## Quick Start |
| 6 | + |
| 7 | +### Essential Context Files |
| 8 | + |
| 9 | +| File | Purpose | |
| 10 | +|------|---------| |
| 11 | +| [README.md](README.md) | Project overview, prerequisites, build basics | |
| 12 | +| [CHANGELOG.md](CHANGELOG.md) | Full release history; current version at top | |
| 13 | +| [Linux-mac-install.md](Linux-mac-install.md) | Step-by-step install guide for every supported Unix platform | |
| 14 | +| [buildscripts/README.md](buildscripts/README.md) | Detailed Windows build instructions (manual & scripted) | |
| 15 | +| [source/shared/version.h](source/shared/version.h) | Single source of truth for version numbers and preview state | |
| 16 | + |
| 17 | +### Repository at a Glance |
| 18 | + |
| 19 | +| Area | Path | Description | |
| 20 | +|------|------|-------------| |
| 21 | +| Shared core | `source/shared/` | C++ code shared by both extensions | |
| 22 | +| SQLSRV extension | `source/sqlsrv/` | Procedural PHP API extension | |
| 23 | +| PDO_SQLSRV extension | `source/pdo_sqlsrv/` | PDO interface extension | |
| 24 | +| Packaging script | `source/packagize.sh` | Copies `shared/` into each extension dir for PECL packaging | |
| 25 | +| Functional tests | `test/functional/` | `.phpt` test suites for both extensions | |
| 26 | +| Extended tests | `test/extended/` | Always Encrypted v2 special tests | |
| 27 | +| BVT tests | `test/bvt/` | Basic verification tests | |
| 28 | +| Performance tests | `test/Performance/` | Benchmark suite (phpbench) | |
| 29 | +| Windows build scripts | `buildscripts/` | `builddrivers.py`, `buildtools.py` | |
| 30 | +| Samples | `sample/` | `sqlsrv_sample.php`, `pdo_sqlsrv_sample.php` | |
| 31 | +| CI (Linux/Mac) | [azure-pipelines.yml](azure-pipelines.yml) | Azure Pipelines — builds PHP from source, runs tests | |
| 32 | +| CI (Windows) | [appveyor.yml](appveyor.yml) | AppVeyor — PHP SDK build matrix | |
| 33 | +| Docker | [Dockerfile-msphpsql](Dockerfile-msphpsql) | Ubuntu 24.04 dev environment image | |
| 34 | + |
| 35 | +## Architecture |
| 36 | + |
| 37 | +### Two Extensions, One Shared Core |
| 38 | + |
| 39 | +The drivers ship as two separate PHP extensions that share a common C++ core layer: |
| 40 | + |
| 41 | +``` |
| 42 | +source/ |
| 43 | +├── shared/ # Core logic (ODBC, connection, statement, stream, error handling) |
| 44 | +│ ├── core_conn.cpp # Connection management |
| 45 | +│ ├── core_init.cpp # Driver initialization |
| 46 | +│ ├── core_results.cpp # Result set processing |
| 47 | +│ ├── core_stmt.cpp # Statement execution |
| 48 | +│ ├── core_stream.cpp # Stream handling |
| 49 | +│ ├── core_util.cpp # Utility functions |
| 50 | +│ ├── core_sqlsrv.h # Main shared header (includes Zend API, ODBC, platform abstractions) |
| 51 | +│ ├── version.h # Version constants |
| 52 | +│ ├── FormattedPrint.cpp/h # Cross-platform printf implementation |
| 53 | +│ ├── StringFunctions.cpp/h # Cross-platform string operations |
| 54 | +│ ├── localizationimpl.cpp # Localization/encoding support |
| 55 | +│ ├── msodbcsql.h # ODBC driver header |
| 56 | +│ └── xplat_*.h, typedefs_for_linux.h, interlockedatomic*.h # Platform abstractions |
| 57 | +│ |
| 58 | +├── sqlsrv/ # Procedural API extension |
| 59 | +│ ├── conn.cpp # sqlsrv_connect(), sqlsrv_close(), etc. |
| 60 | +│ ├── init.cpp # Extension module init/shutdown |
| 61 | +│ ├── stmt.cpp # sqlsrv_query(), sqlsrv_fetch(), etc. |
| 62 | +│ ├── util.cpp # Error handling, logging |
| 63 | +│ ├── config.m4 # Linux/Mac autoconf build |
| 64 | +│ └── config.w32 # Windows JScript build |
| 65 | +│ |
| 66 | +├── pdo_sqlsrv/ # PDO extension |
| 67 | +│ ├── pdo_dbh.cpp # PDO database handle (new PDO(...)) |
| 68 | +│ ├── pdo_init.cpp # Extension module init/shutdown |
| 69 | +│ ├── pdo_parser.cpp # SQL parser for named params |
| 70 | +│ ├── pdo_stmt.cpp # PDOStatement operations |
| 71 | +│ ├── pdo_util.cpp # Error handling |
| 72 | +│ ├── config.m4 # Linux/Mac autoconf build |
| 73 | +│ └── config.w32 # Windows JScript build |
| 74 | +│ |
| 75 | +└── packagize.sh # Copies shared/ into sqlsrv/ and pdo_sqlsrv/ for PECL |
| 76 | +``` |
| 77 | + |
| 78 | +### Key Design Patterns |
| 79 | + |
| 80 | +- **Zend API integration**: All C++ code uses the PHP Zend Engine API. The shared header `core_sqlsrv.h` includes `<php.h>` and `<zend.h>` with MSVC warning suppression for known benign warnings (4100, 4127, 4146, 4244, 4267, 4456, 4457, 4706). |
| 81 | +- **Platform abstraction**: Unix builds use `typedefs_for_linux.h`, `xplat_*.h`, and `interlockedatomic*.h` to map Win32 types/functions to POSIX equivalents (e.g., `stricmp` → `strcasecmp`, `GetLastError` → `errno`). |
| 82 | +- **ODBC layer**: All SQL Server communication goes through the Microsoft ODBC Driver for SQL Server (version 17 or 18). The code never talks to TDS directly. |
| 83 | +- **MARS**: Multiple Active Result Sets enabled by default via `MARS_Connection={Yes}`. |
| 84 | + |
| 85 | +## Build System |
| 86 | + |
| 87 | +### Linux / macOS (autoconf) |
| 88 | + |
| 89 | +Each extension has a `config.m4` that registers the extension with PHP's build system: |
| 90 | + |
| 91 | +```bash |
| 92 | +# Build from PHP source tree (extensions in ext/ directory) |
| 93 | +phpize |
| 94 | +./configure --with-sqlsrv # or --with-pdo_sqlsrv |
| 95 | +make |
| 96 | +make install |
| 97 | +``` |
| 98 | + |
| 99 | +The `config.m4` includes logic to avoid double-compiling shared sources when both extensions are built as static (non-shared) in the same PHP build. |
| 100 | + |
| 101 | +### Windows (PHP SDK + JScript) |
| 102 | + |
| 103 | +Each extension has a `config.w32` (JScript) for the PHP Windows SDK build: |
| 104 | + |
| 105 | +- **Visual Studio**: VS2019 for PHP 8.3, VS2022 for PHP 8.4+ |
| 106 | +- **Security flags**: `/NXCOMPAT`, `/DYNAMICBASE`, `/guard:cf`, `/ZH:SHA_256`, `/W4`, `/WX`, `/CETCOMPAT`, `/Qspectre` (for VCVERS >= 1913) |
| 107 | +- **Scripted builds**: `buildscripts/builddrivers.py` automates downloading PHP SDK, source, and building both extensions |
| 108 | + |
| 109 | +### PECL Packaging |
| 110 | + |
| 111 | +`source/packagize.sh` copies `shared/` files into both `sqlsrv/` and `pdo_sqlsrv/` directories, making each extension self-contained for PECL distribution. **Note**: PECL version strings must not contain hyphens (e.g., `5.13.0beta1` not `5.13.0-beta1`). |
| 112 | + |
| 113 | +### Docker |
| 114 | + |
| 115 | +The `Dockerfile-msphpsql` provides a complete Ubuntu 24.04 development environment with PHP, ODBC 18, and all build dependencies pre-installed. |
| 116 | + |
| 117 | +## Version Management |
| 118 | + |
| 119 | +All version information lives in `source/shared/version.h`: |
| 120 | + |
| 121 | +| Constant | Purpose | Current | |
| 122 | +|----------|---------|---------| |
| 123 | +| `SQLVERSION_MAJOR` | Incompatible API changes | 5 | |
| 124 | +| `SQLVERSION_MINOR` | Backward-compatible features | 13 | |
| 125 | +| `SQLVERSION_PATCH` | Backward-compatible bug fixes | 0 | |
| 126 | +| `SQLVERSION_BUILD` | Build metadata (appended as `+N`) | 0 | |
| 127 | +| `PREVIEW` | Set to 1+ for beta releases, 0 for stable | 0 | |
| 128 | +| `PHP_SQLSRV_VERSION` | PECL version string for sqlsrv | "5.13.0" | |
| 129 | +| `PHP_PDO_SQLSRV_VERSION` | PECL version string for pdo_sqlsrv | "5.13.0" | |
| 130 | + |
| 131 | +**Versioning rules**: |
| 132 | +- Follows [semantic versioning](https://semver.org/) |
| 133 | +- When `PREVIEW > 0`, the version string becomes `MAJOR.MINOR.PATCH-betaN` (e.g., `5.13.0-beta1`) |
| 134 | +- PECL versions use `MAJOR.MINOR.PATCHbetaN` (no hyphen) |
| 135 | +- The `PHP_SQLSRV_VERSION` and `PHP_PDO_SQLSRV_VERSION` constants must be updated manually (cannot use preprocessor macros due to PECL/Pickle constraints) |
| 136 | + |
| 137 | +## Testing |
| 138 | + |
| 139 | +### Test Format |
| 140 | + |
| 141 | +Tests use PHP's standard `.phpt` format: |
| 142 | + |
| 143 | +``` |
| 144 | +--TEST-- |
| 145 | +Description of the test |
| 146 | +--SKIPIF-- |
| 147 | +<?php require('skipif_*.inc'); ?> |
| 148 | +--FILE-- |
| 149 | +<?php |
| 150 | +// Test code here |
| 151 | +?> |
| 152 | +--EXPECT-- |
| 153 | +Expected output |
| 154 | +``` |
| 155 | + |
| 156 | +### Test Organization |
| 157 | + |
| 158 | +| Directory | Contents | Count | |
| 159 | +|-----------|----------|-------| |
| 160 | +| `test/functional/sqlsrv/` | SQLSRV extension tests | ~260+ tests | |
| 161 | +| `test/functional/pdo_sqlsrv/` | PDO_SQLSRV extension tests | ~280+ tests | |
| 162 | +| `test/functional/setup/` | SQL scripts, BCP data files, Python setup scripts | |
| 163 | +| `test/functional/inc/` | Shared binary data (GIF files), TVP test data | |
| 164 | +| `test/extended/` | Always Encrypted v2 tests | ~12 tests | |
| 165 | +| `test/bvt/` | Basic verification tests | |
| 166 | +| `test/Performance/` | phpbench-based benchmarks | |
| 167 | + |
| 168 | +### Test Configuration |
| 169 | + |
| 170 | +Tests read connection info from `MsSetup.inc` (present in each test directory). Connection settings can be overridden via environment variables: |
| 171 | + |
| 172 | +| Variable | Purpose | Default | |
| 173 | +|----------|---------|---------| |
| 174 | +| `MSSQL_SERVER` | SQL Server hostname | `TARGET_SERVER` placeholder | |
| 175 | +| `MSSQL_DATABASE_NAME` | Database name | `TARGET_DATABASE` placeholder | |
| 176 | +| `MSSQL_UID` | SQL login username | `TARGET_USERNAME` placeholder | |
| 177 | +| `MSSQL_PWD` | SQL login password | `TARGET_PASSWORD` placeholder | |
| 178 | +| `MSSQL_DRIVER` | ODBC driver version string | `ODBC Driver 18 for SQL Server` | |
| 179 | + |
| 180 | +### Running Tests |
| 181 | + |
| 182 | +```bash |
| 183 | +# Run all sqlsrv tests |
| 184 | +php run-tests.php test/functional/sqlsrv/ |
| 185 | + |
| 186 | +# Run all pdo_sqlsrv tests |
| 187 | +php run-tests.php test/functional/pdo_sqlsrv/ |
| 188 | + |
| 189 | +# Run a single test |
| 190 | +php run-tests.php test/functional/sqlsrv/sqlsrv_connect.phpt |
| 191 | +``` |
| 192 | + |
| 193 | +### Test Helper Includes |
| 194 | + |
| 195 | +| File | Purpose | |
| 196 | +|------|---------| |
| 197 | +| `MsSetup.inc` | Connection configuration (server, database, credentials, ODBC driver) | |
| 198 | +| `MsCommon.inc` | ~600 lines of shared helpers: `connect()`, `isWindows()`, `testMode()`, `traceMode()`, table creation, data generators | |
| 199 | +| `MsHelper.inc` | Additional helper functions | |
| 200 | +| `MsData.inc` | Test data constants | |
| 201 | +| `skipif*.inc` | Skip conditions (OS, extensions, features, server version) | |
| 202 | +| `tools.inc` | Diagnostic and utility functions | |
| 203 | + |
| 204 | +### Test Categories |
| 205 | + |
| 206 | +Tests cover a wide range of features: |
| 207 | +- **Connectivity**: Connect, close, connection options, connection resiliency, connection pooling |
| 208 | +- **Data types**: All SQL Server types, Unicode, large objects, date/time, decimal precision |
| 209 | +- **Fetch modes**: Forward-only, scrollable, buffered queries, client-side cursors |
| 210 | +- **Transactions**: Commit, rollback, savepoints |
| 211 | +- **Stored procedures**: Input/output params, return values, result sets |
| 212 | +- **Always Encrypted**: Column encryption, key vault, enclave operations |
| 213 | +- **Azure AD / Entra**: Authentication modes (`ActiveDirectoryPassword`, `ActiveDirectoryMSI`, etc.) |
| 214 | +- **Table-Valued Parameters (TVP)**: Sending structured data |
| 215 | +- **Bulk Copy (BCP)**: `test/functional/setup/*.dat` and `*.fmt` files |
| 216 | + |
| 217 | +## Core Principles |
| 218 | + |
| 219 | +1. **Shared Core, Separate Extensions**: Common logic goes in `source/shared/`. Extension-specific API binding goes in `source/sqlsrv/` or `source/pdo_sqlsrv/`. Never duplicate logic between extensions. |
| 220 | +2. **ODBC Abstraction**: All database communication uses ODBC. Never implement protocol-level (TDS) communication. |
| 221 | +3. **Cross-Platform**: Code must compile and run on Windows, Linux, and macOS. Use the platform abstraction headers (`xplat_*.h`, `typedefs_for_linux.h`) for OS-specific functionality. |
| 222 | +4. **PHP Zend Compatibility**: Follow Zend Engine API conventions. Use `zend_*` functions for memory management. Be aware of thread-safety requirements (ZTS vs NTS builds). |
| 223 | +5. **Security by Default**: Windows builds enforce `/NXCOMPAT`, `/DYNAMICBASE`, `/guard:cf`, `/Qspectre`, `/CETCOMPAT`. Never log credentials or connection strings in error output. |
| 224 | +6. **Backward Compatibility**: Avoid breaking existing PHP userland code. New connection options should default to preserving existing behavior. |
| 225 | +7. **Test Coverage**: All changes must include `.phpt` tests. Both `sqlsrv` and `pdo_sqlsrv` should be tested when shared code changes. Tests have standard dependencies connectivity to a server and database. If a test includes dependencies beyond the standard that aren't present, they should include relevant skip logic. |
| 226 | + |
| 227 | +## Common Tasks |
| 228 | + |
| 229 | +### Bug Fix Workflow |
| 230 | + |
| 231 | +1. Reproduce the issue — write or identify a `.phpt` test that demonstrates the bug |
| 232 | +2. Determine if the fix belongs in `source/shared/` (affects both extensions) or in an extension-specific file |
| 233 | +3. Implement the fix |
| 234 | +4. Add or update `.phpt` tests in both `test/functional/sqlsrv/` and `test/functional/pdo_sqlsrv/` if shared code changed |
| 235 | +5. Update `CHANGELOG.md` with a description under the appropriate version heading |
| 236 | + |
| 237 | +### Adding a New Connection Option |
| 238 | + |
| 239 | +1. Add the ODBC keyword mapping in `source/shared/core_sqlsrv.h` (connection option definitions) |
| 240 | +2. Register the option in `source/shared/core_conn.cpp` connection option arrays |
| 241 | +3. Expose in `source/sqlsrv/conn.cpp` and/or `source/pdo_sqlsrv/pdo_dbh.cpp` |
| 242 | +4. Default to backward-compatible value |
| 243 | +5. Add tests for the new option in both test suites |
| 244 | +6. Document in `CHANGELOG.md` |
| 245 | + |
| 246 | +### Version Bump |
| 247 | + |
| 248 | +1. Edit `source/shared/version.h`: |
| 249 | + - Update `SQLVERSION_MAJOR`, `SQLVERSION_MINOR`, and/or `SQLVERSION_PATCH` |
| 250 | + - Update `PHP_SQLSRV_VERSION` and `PHP_PDO_SQLSRV_VERSION` string literals |
| 251 | + - Set `PREVIEW` to 0 for stable, or 1+ for beta releases |
| 252 | +2. Update `CHANGELOG.md` with new version heading and release notes |
| 253 | +3. The file header comment `Microsoft Drivers X.YY for PHP for SQL Server` in source files may need updating for major/minor bumps |
| 254 | + |
| 255 | +### Adding a New Test |
| 256 | + |
| 257 | +1. Create a `.phpt` file in the appropriate `test/functional/` subdirectory |
| 258 | +2. Include standard skip logic: `--SKIPIF--` with `<?php require('skipif_*.inc'); ?>` |
| 259 | +3. Use `MsCommon.inc` helpers for connection setup and data generation |
| 260 | +4. Ensure the test is deterministic and cleans up after itself (drop temp tables, close connections) |
| 261 | +5. Provide explicit `--EXPECT--` or `--EXPECTF--` output |
| 262 | + |
| 263 | +### Preparing a PECL Release |
| 264 | + |
| 265 | +1. Set version in `source/shared/version.h` (ensure `PREVIEW` is set correctly) |
| 266 | +2. Run `source/packagize.sh` to copy `shared/` into both extension directories |
| 267 | +3. Verify `PHP_SQLSRV_VERSION` / `PHP_PDO_SQLSRV_VERSION` strings have no hyphens |
| 268 | +4. Each extension directory becomes a self-contained PECL package |
| 269 | + |
| 270 | +## CI / CD |
| 271 | + |
| 272 | +### GitHub CI |
| 273 | + |
| 274 | +| Pipeline | Platform | Trigger | |
| 275 | +|----------|----------|---------| |
| 276 | +| Azure Pipelines (`azure-pipelines.yml`) | Linux, macOS | Push to `dev`, `fix/*`; PRs to `dev` | |
| 277 | +| AppVeyor (`appveyor.yml`) | Windows | Push (except legacy branches) | |
| 278 | +| Codecov (`codecov.yml`) | Windows | Coverage reporting | |
| 279 | + |
| 280 | +The Azure Pipelines job builds PHP from source on each target platform, compiles both extensions, then runs the full `.phpt` test suite against a SQL Server (Docker container on Linux, local instance on Windows/macOS). |
| 281 | + |
| 282 | +### Internal CI/CD (msphpsql in ADO) |
| 283 | + |
| 284 | +The internal Azure DevOps repo (`msphpsql`) contains the production CI/CD pipelines for official builds, matrix testing, signing, packaging, and release. See that repo's `AGENTS.md` for pipeline architecture details. |
| 285 | + |
| 286 | +## Branching and Contributions |
| 287 | + |
| 288 | +- **`dev`** — active development branch; all PRs should target `dev` |
| 289 | +- **`main`** (or `master`) — stable release branch |
| 290 | +- **`fix/*`** — bug fix branches (trigger CI) |
| 291 | +- Pull requests require CI to pass before merge |
| 292 | + |
| 293 | +## External Resources |
| 294 | + |
| 295 | +| Resource | Link | |
| 296 | +|----------|------| |
| 297 | +| Microsoft Docs (PHP Drivers) | https://learn.microsoft.com/sql/connect/php/microsoft-php-driver-for-sql-server | |
| 298 | +| ODBC Driver Docs | https://learn.microsoft.com/sql/connect/odbc/microsoft-odbc-driver-for-sql-server | |
| 299 | +| PHP Internals (Building) | https://wiki.php.net/internals/windows/stepbystepbuild_sdk_2 | |
| 300 | +| PECL sqlsrv | https://pecl.php.net/package/sqlsrv | |
| 301 | +| PECL pdo_sqlsrv | https://pecl.php.net/package/pdo_sqlsrv | |
| 302 | +| GitHub Issues | https://github.com/microsoft/msphpsql/issues | |
| 303 | +| GitHub Releases | https://github.com/microsoft/msphpsql/releases | |
| 304 | + |
| 305 | +## Getting Help |
| 306 | + |
| 307 | +- Check `test/functional/` for usage patterns and expected behavior |
| 308 | +- Read `MsCommon.inc` for available test helper functions |
| 309 | +- Consult `core_sqlsrv.h` for internal data structures and ODBC wrappers |
| 310 | +- For ODBC behavior, reference the Microsoft ODBC Driver documentation |
| 311 | +- For PHP extension API, reference the [PHP Internals Book](https://www.phpinternalsbook.com/) |
| 312 | + |
| 313 | +--- |
| 314 | + |
| 315 | +*This document is automatically loaded as context for AI agents working in this repository.* |
0 commit comments