Определение драйвера и диалекты
CDO подстраивает свой SQL под ту базу данных, с которой действительно разговаривает. Эта страница объясняет, как он выясняет, что это за база, и каждое место, где порождаемый SQL ветвится по ней — написано по коду соединения, а не по памяти.
Проблема, которую оставляет открытой PDO
PDO::ATTR_DRIVER_NAME возвращает 'mysql' для обеих — MySQL и MariaDB. Но
они расходятся в возможности, на которую CDO опирается: MariaDB ≥ 10.5
поддерживает INSERT ... RETURNING; MySQL — никогда. Считать их одинаковыми
означало бы сломать путь возврата id на одной из них.
Как нормализуется драйвер
Во время подключения (applyDatabase()) CDO читает PDO::ATTR_DRIVER_NAME и для
mysql инспектирует PDO::ATTR_SERVER_VERSION. Если строка версии содержит
"MariaDB" (напр. "5.5.5-10.11.6-MariaDB" или "11.4.2-MariaDB"), драйвер
записывается как mariadb. Нормализованное значение — одно из pgsql, mysql,
mariadb, oci — кешируется и возвращается методом getDriverName().
ATTR_DRIVER_NAME = 'pgsql' → 'pgsql'
ATTR_DRIVER_NAME = 'mysql', в версии есть 'MariaDB' → 'mariadb'
ATTR_DRIVER_NAME = 'mysql', в версии нет 'MariaDB' → 'mysql'
ATTR_DRIVER_NAME = 'oci' → 'oci'Атрибуты PDO, устанавливаемые по драйверу
applyDatabase() также настраивает PDO на основе сырого драйвера:
| Драйвер | ATTR_EMULATE_PREPARES |
Обоснование |
|---|---|---|
pgsql |
false |
Нативные серверные prepares |
mysql |
true |
Эмулируемые prepares |
oci |
true |
Эмулируемые prepares |
Режим выборки по умолчанию устанавливается в PDO::FETCH_ASSOC для каждого
драйвера, поэтому унаследованные fetch() / fetchAll() возвращают
ассоциативные массивы, пока вы это не переопределите.
Где ветвится SQL: возврат id
insert() использует RETURNING только там, где он поддерживается, и
lastInsertId() в остальных случаях:
| Драйвер | Стратегия insert() |
|---|---|
pgsql |
INSERT … RETURNING pk → fetchColumn() |
mariadb |
INSERT … RETURNING pk → fetchColumn() |
mysql |
обычный INSERT → lastInsertId() |
oci |
обычный INSERT → lastInsertId() |
Ложный результат нормализуется в null — это означает «нет сгенерированного id
для сообщения» (напр. INSERT в таблицу без колонки auto-increment/serial), а не
ошибку. Настоящие SQL-ошибки приходят через PDOException и становятся
CDOException.
RETURNING при апсерте уже
upsert() использует RETURNING только на PostgreSQL, хотя MariaDB
поддерживает RETURNING для обычных вставок — MariaDB запрещает его вместе с
ON DUPLICATE KEY UPDATE / INSERT IGNORE, поэтому там CDO откатывается к
lastInsertId(). См.
Плейсхолдеры апсерта.
Где ветвится SQL: диалект апсерта
| Драйвер | Игнорировать конфликты | Обновить при конфликте |
|---|---|---|
pgsql |
ON CONFLICT (cols) DO NOTHING |
ON CONFLICT (cols) DO UPDATE SET … |
| всё остальное | INSERT IGNORE |
ON DUPLICATE KEY UPDATE … |
Подстановка токенов :new / :current тоже зависит от драйвера — полная матрица
в Плейсхолдерах апсерта.
Где ветвится SQL: часовой пояс
При подключении CDO устанавливает часовой пояс сессии базы данных в соответствие с
PHP (date_default_timezone_get()), по драйверам:
| Драйвер | Инструкция |
|---|---|
pgsql |
SET TIMEZONE TO '<tz>' |
mysql (и MariaDB) |
SET time_zone = '<offset>' |
oci |
ALTER SESSION SET TIME_ZONE = '<tz>' |
| прочие | не реализовано — логирует предупреждение |
Путь MySQL требует помощника смещения
Для MySQL/MariaDB CDO преобразует имя часового пояса PHP в числовое смещение через
функцию timezoneToOffset(), которую ожидает найти в глобальной области. Она
не поставляется этим пакетом — её предоставляет хост-фреймворк Winter. Вне
этого фреймворка определите эквивалентную глобальную функцию (или шаг MySQL
SET time_zone пропускается, когда помощник возвращает null). PostgreSQL и
Oracle принимают имя часового пояса напрямую и такой зависимости не имеют.
Сводка возможностей по драйверам
| Операция | PostgreSQL | MySQL | MariaDB | Oracle |
|---|---|---|---|---|
insert возвращает id |
✅ RETURNING | ✅ lastInsertId | ✅ RETURNING | ⚠️ lastInsertId |
insertGroup |
✅ | ✅ | ✅ | ✅ |
upsert / upsertGroup |
✅ | ✅ | ✅ | ❌ |
update / delete |
✅ | ✅ | ✅ | ✅ |
Связанное
- Плейсхолдеры апсерта — подстановка токенов по драйверам
- API CDO —
getDriverName() - Пакеты и чанки — как собирается многострочный SQL