Глава 129 · С нуля → полный справочник
ODBC (Unified): полный справочник соединений, запросов и схемы
От первого DSN и понятной ошибки до prepared statements, транзакций, LONG/binary, catalog metadata и всех 48 официальных функций PHP 8.5.
ODBC от задачи: один PHP-код, разные драйверы, явные границы
ODBC нужен, когда PHP должен говорить с источником через стандартный Driver Manager: корпоративный SQL Server, Access-файл, PostgreSQL, DB2 или другое ODBC-совместимое хранилище. Выигрыш — один набор PHP-функций. Цена — возможности, типы, SQL и ошибки всё равно зависят от конкретного драйвера и СУБД.
- PHP вызывает ext/odbc и передаёт DSN
- ODBC Driver Manager находит драйвер той же разрядности
- драйвер переводит ODBC-вызов в протокол конкретной базы
- база возвращает строки/статус через driver и result object
DSN — именованная конфигурация источника. DSN-less строка перечисляет Driver/Server/Database прямо в конфигурации приложения. Пароль в обоих случаях хранится вне репозитория. ODBC унифицирует транспортный API, но не делает SQL-диалекты, транзакционные особенности и типы полностью одинаковыми.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_first_product');
try {
uodbcExec($connection, 'CREATE TABLE phpman_first_product (id INTEGER PRIMARY KEY, name VARCHAR(50), price INTEGER)');
$insert = odbc_prepare($connection, 'INSERT INTO phpman_first_product VALUES (CAST(? AS INTEGER), ?, CAST(? AS INTEGER))');
if ($insert === false || !@odbc_execute($insert, [1, 'Notebook', 450])) {
throw new RuntimeException(odbc_error($connection).' '.odbc_errormsg($connection));
}
$select = odbc_prepare($connection, 'SELECT name, price FROM phpman_first_product WHERE id=CAST(? AS INTEGER)');
if ($select === false || !@odbc_execute($select, [1])) {
throw new RuntimeException(odbc_error($connection).' '.odbc_errormsg($connection));
}
$product = odbc_fetch_array($select);
echo $product['name'], ':', $product['price'], "\n";
} finally {
uodbcDrop($connection, 'phpman_first_product');
odbc_close($connection);
}
Ожидаемый результат
Notebook:450
Один путь показывает роли всех объектов: connection — сессия; result от prepare — команда; params — данные; fetch — строка результата. Таблица удаляется в finally. На psqlODBC успешный INSERT может сопровождаться SQLSTATE 01S02 о смене cursor updatability; код отдельно проверяет bool результата, а диагностическое предупреждение в реальном приложении пишет в технический лог. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = @odbc_exec($connection, 'SELECT * FROM phpman_table_not_created');
if ($result === false) {
$state = odbc_error($connection);
$diagnostic = odbc_errormsg($connection);
echo "operation=inventory-read state={$state}\n";
echo str_contains($diagnostic, 'phpman_table_not_created') ? "diagnostic-captured\n" : "diagnostic-empty\n";
echo "public=Сервис временно не получил данные\n";
}
odbc_close($connection);
Ожидаемый результат
operation=inventory-read state=42P01
diagnostic-captured
public=Сервис временно не получил данные
Закрытый журнал может получить diagnostic и operation id; посетителю не раскрываются SQL, хост и схема. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Дальше можно идти по задаче: odbc_connect() → odbc_prepare() → odbc_execute() → odbc_fetch_array(). Опытный читатель открывает полный справочник функций ниже.
Установка и настройка: четыре слоя, которые должны совпасть
Рабочая цепочка состоит из четырёх отдельных частей: расширение PHP, Driver Manager, драйвер СУБД и сам источник данных. Ошибка «undefined function» относится к первому слою; IM002 — обычно к DSN/драйверу; 08001/08xxx — к соединению; 28xxx — к аутентификации. Такая локализация экономит время.
| Слой | Проверка | Типичный отказ |
|---|---|---|
| PHP | extension_loaded('odbc') | Call to undefined function |
| Driver Manager | Windows ODBC Administrator / unixODBC iODBC | IM002 source/driver not found |
| Драйвер | та же x64/x86, что PHP; vendor version | driver load/unsupported API |
| Источник | host/port/database/user + простой SELECT | network/auth/SQLSTATE |
На Windows системный Driver Manager используется всегда. 64-битный PHP видит 64-битные драйверы/DSN; 32-битная панель администратора настраивает другой мир. На Linux обычно выбирают unixODBC или iODBC, затем устанавливают vendor driver и DSN.
Эта общая страница объединяет официальные подразделы ниже; каждое требование и исторический флаг сохранены в своей секции.
Требования: библиотека ODBC — не сама база
Официальный baseline краток: нужны библиотеки требуемой поддерживаемой базы. Практически это означает: PHP ext/odbc должен быть собран/загружен; Driver Manager должен работать; для каждой СУБД установлен подходящий ODBC-драйвер; сеть, TLS и учётная запись разрешают соединение.
- Сверьте разрядность PHP и драйвера.
- Сверьте архитектуру процесса веб-сервера, а не только интерактивного терминала.
- Создайте отдельную минимально привилегированную роль приложения.
- Проверьте кодировку/Unicode round-trip до импорта данных.
- Не используйте production-базу для учебных/диагностических DDL-примеров.
ODBC-драйвер обновляется отдельно от PHP. Совместимость PHP 8.5 не доказывает совместимость старого vendor driver с TLS/сервером.
Установка: Windows DLL, unixODBC/iODBC и изменения PHP 8.5
На Windows включают php_odbc.dll в том php.ini, который реально загружает нужный SAPI, затем перезапускают PHP-worker/Apache/IIS. Изолированная CLI-проверка возможна через php -n -d extension=... -m, но она не изменяет конфигурацию сайта.
При сборке Unix официальный manual перечисляет --with-unixODBC[=DIR], --with-iodbc, --with-ibm-db2[=DIR] и --with-custom-odbc[=DIR]. Для custom ODBC нужны заголовки и корректные CUSTOM_ODBC_LIBS. Driver Manager предпочтительнее прямого связывания благодаря совместимости и смене драйверов.
С PHP 8.5 удалены flags прямой поддержки Adabas, DBMaker, Empress, Easysoft OOB, SAP DB и Solid; исторические --with-birdstep удалены ещё с PHP 7.3. Это не означает, что к продукту нельзя подключиться через современный совместимый Driver Manager/driver — проверяется его текущая документация.
| После изменения | Команда/действие | Что доказывает |
|---|---|---|
| Расширение | php --ini, php -m | какой ini и загружен ли odbc |
| API | function_exists('odbc_connect') | функция доступна этому SAPI |
| Driver | ODBC Administrator/odbcinst | имя и архитектура драйвера |
| End-to-end | connect + SELECT 1 | DSN, сеть, auth и SQL вместе |
Runtime configuration: лимиты, persistent, LONG и курсоры
| Директива | Default | Где менять | Смысл |
|---|---|---|---|
| odbc.allow_persistent | 1 | INI_SYSTEM | Разрешить persistent ODBC connections. |
| odbc.check_persistent | 1 | INI_SYSTEM | Проверять persistent-сессию перед повторным использованием. |
| odbc.max_persistent | -1 | INI_SYSTEM | Лимит persistent connections на процесс; -1 без лимита. |
| odbc.max_links | -1 | INI_SYSTEM | Лимит всех ODBC connections на процесс. |
| odbc.defaultlrl | 4096 | INI_ALL | Байтовый предел LONG; см. odbc_longreadlen(). |
| odbc.defaultbinmode | 1 | INI_ALL | Режим binary; см. odbc_binmode(). |
| odbc.default_cursortype | 3 | INI_ALL | Модель курсора, 3 = SQL_CURSOR_STATIC в текущей сборке. |
Официальная страница также описывает historical/default_db, default_user и default_pw. В PHP 8.5.11 Windows runtime они не перечисляются ini_get_all('odbc'); комментарии php.ini отмечают default_db/user/pw как not implemented. Не стройте на них конфигурацию и не храните пароль в php.ini без строгой необходимости.
INI_SYSTEM меняется в системной конфигурации до запуска worker-а. INI_ALL технически допускает ini_set, но настройка binmode/longreadlen на конкретном result через функции делает влияние локальным и понятным. Лимит -1 не равен безопасной бесконечности: сервер и процесс всё равно ограничены.
Текущий изолированный стенд сообщает: allow/check persistent = 1, max links/persistent = -1, defaultlrl=4096, defaultbinmode=1, default_cursortype=3. Это evidence стенда, а не рекомендация копировать значения в production.
Жизненный цикл типов: resources до PHP 8.4, opaque objects после
Официальная resource-страница важна для чтения старого кода: до PHP 8.4 расширение возвращало два resource-типа — connection identifier и result identifier. С PHP 8.4 их заменили Odbc\Connection и Odbc\Result.
- odbc_connect создаёт Connection
- exec/prepare создаёт Result, связанный с connection/statement
- fetch двигает cursor внутри Result
- free_result освобождает Result; close освобождает Connection после transaction boundary
Opaque object нельзя создать через new, клонировать или сериализовать; у него нет публичных полей/методов. Это handle к нативному состоянию. Проверка is_resource() из legacy-кода после обновления перестаёт работать — используйте сигнатуры/тип объекта и не храните handle между HTTP-запросами.
Все предопределённые ODBC-константы по назначению
Константы существуют только при загруженном ext/odbc. Числа показаны для PHP 8.5.11/Windows ODBC headers; в коде пишут имя константы, а не магическое число.
| Константа | Значение стенда | Где применяется |
|---|---|---|
ODBC_BINMODE_CONVERT | 2 | Режим двоичных колонок для odbc_binmode(). |
ODBC_BINMODE_PASSTHRU | 0 | Режим двоичных колонок для odbc_binmode(). |
ODBC_BINMODE_RETURN | 1 | Режим двоичных колонок для odbc_binmode(). |
ODBC_TYPE | Win32 | Тип сборки/Driver Manager, строка для диагностики, не переключатель. |
SQL_BEST_ROWID | 1 | Параметр odbc_specialcolumns(). |
SQL_BIGINT | -5 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_BINARY | -2 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_BIT | -7 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_CHAR | 1 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_CONCURRENCY | 7 | Режим concurrency ODBC statement. |
SQL_CONCUR_LOCK | 2 | Режим concurrency ODBC statement. |
SQL_CONCUR_READ_ONLY | 1 | Режим concurrency ODBC statement. |
SQL_CONCUR_ROWVER | 3 | Режим concurrency ODBC statement. |
SQL_CONCUR_VALUES | 4 | Режим concurrency ODBC statement. |
SQL_CURSOR_DYNAMIC | 2 | Модель/атрибут курсора. Поддержка зависит от драйвера. |
SQL_CURSOR_FORWARD_ONLY | 0 | Модель/атрибут курсора. Поддержка зависит от драйвера. |
SQL_CURSOR_KEYSET_DRIVEN | 1 | Модель/атрибут курсора. Поддержка зависит от драйвера. |
SQL_CURSOR_STATIC | 3 | Модель/атрибут курсора. Поддержка зависит от драйвера. |
SQL_CURSOR_TYPE | 6 | Модель/атрибут курсора. Поддержка зависит от драйвера. |
SQL_CUR_USE_DRIVER | 2 | Кто управляет курсорами при odbc_connect()/pconnect(). |
SQL_CUR_USE_IF_NEEDED | 0 | Кто управляет курсорами при odbc_connect()/pconnect(). |
SQL_CUR_USE_ODBC | 1 | Кто управляет курсорами при odbc_connect()/pconnect(). |
SQL_DATE | 9 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_DECIMAL | 3 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_DOUBLE | 8 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_ENSURE | 1 | Фильтр/точность odbc_statistics(). |
SQL_FETCH_FIRST | 2 | Направление перечисления DSN для odbc_data_source(). |
SQL_FETCH_NEXT | 1 | Направление перечисления DSN для odbc_data_source(). |
SQL_FLOAT | 6 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_INDEX_ALL | 1 | Фильтр/точность odbc_statistics(). |
SQL_INDEX_UNIQUE | 0 | Фильтр/точность odbc_statistics(). |
SQL_INTEGER | 4 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_KEYSET_SIZE | 8 | Атрибут размера keyset курсора. |
SQL_LONGVARBINARY | -4 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_LONGVARCHAR | -1 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_NO_NULLS | 0 | Параметр odbc_specialcolumns(). |
SQL_NULLABLE | 1 | Параметр odbc_specialcolumns(). |
SQL_NUMERIC | 2 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_ODBC_CURSORS | 110 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_QUICK | 0 | Фильтр/точность odbc_statistics(). |
SQL_REAL | 7 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_ROWVER | 2 | Параметр odbc_specialcolumns(). |
SQL_SCOPE_CURROW | 0 | Параметр odbc_specialcolumns(). |
SQL_SCOPE_SESSION | 2 | Параметр odbc_specialcolumns(). |
SQL_SCOPE_TRANSACTION | 1 | Параметр odbc_specialcolumns(). |
SQL_SMALLINT | 5 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_TIME | 10 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_TIMESTAMP | 11 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_TINYINT | -6 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_TYPE_DATE | 91 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_TYPE_TIME | 92 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_TYPE_TIMESTAMP | 93 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_VARBINARY | -3 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_VARCHAR | 12 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_WCHAR | -8 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_WLONGVARCHAR | -10 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
SQL_WVARCHAR | -9 | ODBC SQL type code для odbc_gettypeinfo() и schema metadata. |
Группы: ODBC_BINMODE_* управляют binary result; SQL_CUR_USE_* выбирают менеджера курсоров; SQL_CURSOR_*/SQL_CONCUR_* и SQL_KEYSET_SIZE — низкоуровневые option values; SQL_CHAR…SQL_WLONGVARCHAR и numeric/date/binary — type codes; BEST_ROWID/ROWVER/SCOPE/NULLABLE — specialcolumns; INDEX/ENSURE/QUICK — statistics; FETCH_FIRST/NEXT — data_source.
Полный древовидный справочник 48 функций
Все 48 официальных функций представлены отдельными карточками: сигнатура PHP 8.5.11, параметры, возврат/ошибки, два практических примера, ограничения и связанные операции. Это полный ref.uodbc, а не список функций, случайно встретившихся в уроках.
ODBC: соединения и DSN
ODBC: строки подключения
odbc_connection_string_is_quoted()odbc_connection_string_should_quote()odbc_connection_string_quote()
ODBC: запросы и параметры
ODBC: чтение результата
odbc_fetch_array()odbc_fetch_object()odbc_fetch_into()odbc_fetch_row()odbc_result()odbc_result_all()odbc_free_result()
ODBC: структура результата
odbc_num_rows()odbc_num_fields()odbc_field_name()odbc_field_type()odbc_field_len()odbc_field_precision()odbc_field_scale()odbc_field_num()
ODBC: транзакции, ошибки и настройки
ODBC: двоичные и длинные данные
ODBC: каталог и схема
odbc_tables()odbc_columns()odbc_gettypeinfo()odbc_primarykeys()odbc_foreignkeys()odbc_procedures()odbc_procedurecolumns()odbc_specialcolumns()odbc_statistics()odbc_tableprivileges()odbc_columnprivileges()
Два исторических факта вынесены явно: odbc_do — alias odbc_exec; odbc_field_precision — alias odbc_field_len; odbc_result_all deprecated с PHP 8.1.
Odbc\Connection: opaque handle сессии
Класс появился в PHP 8.4 и заменил resource connection. Синопсис пуст: методов/свойств нет. Экземпляр возвращают odbc_connect()/odbc_pconnect(); new Odbc\Connection() выбрасывает Error.
| Что хранит концептуально | Как работать |
|---|---|
| Нативный ODBC connection handle и состояние driver/session | Передавать ODBC-функциям |
| Режим autocommit/transaction | odbc_autocommit/commit/rollback |
| Последнюю диагностику | odbc_error/errormsg сразу после отказа |
| Жизненный цикл | odbc_close только после завершения transaction |
Не сериализуется, не переносится в другой процесс/запрос и не является безопасным глобальным singleton. В объект приложения можно завернуть фабрику/adapter, но нативный handle всё равно живёт только внутри процесса.
Odbc\Result: statement, cursor и metadata в одном opaque handle
Класс появился в PHP 8.4 и заменил resource result. Его возвращают odbc_exec()/odbc_prepare()/catalog functions. У него нет методов; действие выполняют функции odbc_fetch_*, odbc_result, odbc_num_*/field_* и odbc_free_result.
- odbc_exec: уже выполненный SQL и result/status
- odbc_prepare: подготовленный statement до execute
- odbc_execute: тот же object получает выполненный result
- fetch двигает cursor; free_result делает object непригодным
new Odbc\Result() запрещён. Result нельзя клонировать/сериализовать. После free или закрытия связанного connection не передавайте его другим функциям.
Реальные границы: кодировка, pooling, параллельность и большие данные
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_unicode');
try {
uodbcExec($connection, 'CREATE TABLE phpman_unicode (id INTEGER PRIMARY KEY, label VARCHAR(100))');
$statement = odbc_prepare($connection, 'INSERT INTO phpman_unicode VALUES (1, ?)');
if ($statement === false || !@odbc_execute($statement, ['Заказ №7 — готов'])) {
throw new RuntimeException(odbc_errormsg($connection));
}
$result = uodbcExec($connection, 'SELECT label FROM phpman_unicode WHERE id=1');
$row = odbc_fetch_array($result);
echo $row['label'], "\n";
} finally {
uodbcDrop($connection, 'phpman_unicode');
odbc_close($connection);
}
Ожидаемый результат
Заказ №7 — готов
Round-trip проверяет PHP source, Unicode ODBC driver, client encoding и database column вместе. Один ASCII SELECT этого не доказывает. SQLSTATE класса 01 при успешном execute — диагностическое предупреждение драйвера, а не повод считать сохранённую строку потерянной. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Кодировки. Выбирайте Unicode-вариант драйвера; проверьте русский/emoji/combining characters в отдельной базе. Не лечите mojibake случайным utf8_encode/iconv после получения: сначала согласуйте client/database encoding.
Persistent/pooling. odbc_pconnect переиспользует сессию PHP-процесса. Driver Manager/vendor driver может иметь свой pooling. Это два уровня; считайте реальные backend sessions и время connect. Возвращайте autocommit/session settings, не оставляйте временные таблицы и открытые транзакции.
Параллельность. Один Odbc\Connection не переносится между PHP-процессами. Два одновременных запроса обычно имеют отдельные handles/sessions; согласованность решает СУБД блокировками/изоляцией. Не делите object через serialize/cache.
LONG/binary. defaultlrl=4096 может усечь длинные колонки; binmode меняет bytes/hex/passthru. Для крупного файла проверьте память и нативный LOB API. См. odbc_longreadlen() и odbc_binmode().
Problem signals. Старые обсуждения полезны как симптомы, но ответы могли устареть. В руководстве они сверены с текущей сигнатурой/поведением:
- Placeholder оказался в кавычках и строка не нашлась
- Prepared statement зависит от возможностей конкретного ODBC-драйвера
- Длинная строка усеклась из-за long read length
- PHP сообщает Call to undefined function odbc_connect
- 32- и 64-битные DSN/драйверы видны разным процессам
Упражнение: замените учебный product на таблицу заказов, добавьте transaction для order+line, умышленно нарушьте FK и сохраните SQLSTATE. Затем проверьте Unicode round-trip. Решение строится из connect → autocommit(false) → prepare/execute → commit или rollback → close.
Функции и методы этой темы
Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.
odbc_connectОткрывает обычное ODBC-соединение: PHP передаёт DSN, пользователя и пароль Driver Manager, тот загружает драйвер, а драйвер договаривается с конкретной базой.
odbc_connect(string $dsn, ?string $user = null, ?string $password = null, int $cursor_option = 2): Odbc\Connection|falseОткрывает обычное ODBC-соединение: PHP передаёт DSN, пользователя и пароль Driver Manager, тот загружает драйвер, а драйвер договаривается с конкретной базой.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_connect(string $dsn, ?string $user = null, ?string $password = null, int $cursor_option = 2): Odbc\Connection|false
| Параметр | Что передать |
|---|---|
string $dsn | Имя системного/пользовательского DSN либо DSN-less строка драйвера. Это не PDO-DSN с префиксом odbc:. |
?string $user (по умолчанию NULL) | Имя пользователя источника данных. null оставляет выбор драйверу/DSN. |
?string $password (по умолчанию NULL) | Пароль. В PHP 8 он помечен SensitiveParameter; храните его вне исходника. |
int $cursor_option (по умолчанию 2) | SQL_CUR_USE_DRIVER, SQL_CUR_USE_IF_NEEDED или SQL_CUR_USE_ODBC. Обычно начинают с SQL_CUR_USE_DRIVER. |
Возврат. Возвращает Odbc\Connection либо false. Начиная с PHP 8.4 user/password nullable и необязательны; UID/PWD внутри DSN перекрывают одноимённый отдельный аргумент.
Отказ и диагностика. При отказе возвращает false и обычно создаёт warning; после подавления warning немедленно прочитайте odbc_error()/odbc_errormsg() и запишите безопасный контекст. TypeError означает неверный PHP-вызов.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = @odbc_connect(
uodbcEnv('UODBC_DSN'),
uodbcEnv('UODBC_USER'),
uodbcEnv('UODBC_PASSWORD'),
SQL_CUR_USE_DRIVER,
);
if ($connection === false) {
throw new RuntimeException(odbc_error().' '.odbc_errormsg());
}
$result = uodbcExec($connection, 'SELECT 42 AS answer');
echo get_debug_type($connection), "\n";
echo odbc_result($result, 'answer'), "\n";
odbc_close($connection);
Ожидаемый результат
Odbc\Connection
42
Соединение успешно только после возврата объекта. Проверочный SELECT показывает, что доступен не просто Driver Manager, а сама база. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = @odbc_connect('MISSING_DSN_404', null, null);
if ($connection === false) {
echo odbc_error(), "\n";
}
Ожидаемый результат
IM002
SQLSTATE IM002 означает, что Driver Manager не нашёл источник/драйвер. Имя намеренно короче 32 символов: слишком длинный DSN в Windows даёт другой SQLSTATE S1090 (invalid string or buffer length). Пользователю не показывают полную строку подключения и пароль. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Не храните UID/PWD в репозитории и не печатайте connection string в браузер.
- DSN и DSN-less строка относятся к ODBC, а не к синтаксису PDO.
- Успешная загрузка php_odbc.dll ещё не означает, что установлен драйвер нужной СУБД.
Когда выбрать другое. Если проект работает только с одной СУБД, нативное расширение или PDO-драйвер часто дают более точные типы, диагностику и специфические возможности.
Связанные операции: odbc_pconnect(), odbc_close(), odbc_error().
odbc_pconnectОткрывает или повторно использует постоянное соединение. Это может сэкономить установление сессии, но переносит её состояние между запросами одного PHP-worker.
odbc_pconnect(string $dsn, ?string $user = null, ?string $password = null, int $cursor_option = 2): Odbc\Connection|falseОткрывает или повторно использует постоянное соединение. Это может сэкономить установление сессии, но переносит её состояние между запросами одного PHP-worker.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_pconnect(string $dsn, ?string $user = null, ?string $password = null, int $cursor_option = 2): Odbc\Connection|false
| Параметр | Что передать |
|---|---|
string $dsn | Имя системного/пользовательского DSN либо DSN-less строка драйвера. Это не PDO-DSN с префиксом odbc:. |
?string $user (по умолчанию NULL) | Имя пользователя источника данных. null оставляет выбор драйверу/DSN. |
?string $password (по умолчанию NULL) | Пароль. В PHP 8 он помечен SensitiveParameter; храните его вне исходника. |
int $cursor_option (по умолчанию 2) | SQL_CUR_USE_DRIVER, SQL_CUR_USE_IF_NEEDED или SQL_CUR_USE_ODBC. Обычно начинают с SQL_CUR_USE_DRIVER. |
Возврат. Возвращает Odbc\Connection либо false. В CGI постоянство не даёт эффекта. PHP 8.4 изменил объектный тип возврата и правила nullable учётных данных.
Отказ и диагностика. Возвращает false при невозможности создать/получить соединение. Ошибка может означать отсутствие драйвера, сеть, аутентификацию или лимит соединений; причины обрабатываются раздельно.
- PHP ищет совпадение DSN/user/password в пуле процесса
- при совпадении проверяется/берётся существующая сессия
- код выполняет запрос
- процесс сохраняет сессию после завершения запроса
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = @odbc_pconnect(
uodbcEnv('UODBC_DSN'),
uodbcEnv('UODBC_USER'),
uodbcEnv('UODBC_PASSWORD'),
);
if ($connection === false) {
throw new RuntimeException(odbc_error().' '.odbc_errormsg());
}
$result = uodbcExec($connection, "SELECT 'ready' AS state");
echo odbc_result($result, 'state'), "\n";
Ожидаемый результат
ready
Постоянство относится к рабочему процессу PHP и следующим запросам этого процесса, а не делает объект общим между всеми серверами. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$first = @odbc_pconnect(uodbcEnv('UODBC_DSN'), uodbcEnv('UODBC_USER'), uodbcEnv('UODBC_PASSWORD'));
$second = @odbc_pconnect(uodbcEnv('UODBC_DSN'), uodbcEnv('UODBC_USER'), uodbcEnv('UODBC_PASSWORD'));
if ($first === false || $second === false) {
throw new RuntimeException(odbc_error().' '.odbc_errormsg());
}
$a = uodbcExec($first, 'SELECT pg_backend_pid() AS pid');
$b = uodbcExec($second, 'SELECT pg_backend_pid() AS pid');
echo odbc_result($a, 'pid') === odbc_result($b, 'pid') ? "same-session\n" : "different-session\n";
Ожидаемый результат
same-session
Одинаковые DSN/пользователь/пароль в одном CLI-процессе повторно используют persistent-сессию psqlODBC. В FPM состояние может жить дольше одного HTTP-запроса, поэтому настройки сессии надо возвращать в ожидаемое состояние. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Незавершённая транзакция, временные таблицы и параметры сессии могут попасть в следующий запрос worker-а.
- Пул не заменяет лимит соединений и наблюдение за ними.
- Не измеряйте пользу pconnect без модели PHP-процессов и нагрузки.
Когда выбрать другое. Обычный odbc_connect() проще там, где соединений мало или состояние сессии трудно безопасно сбрасывать; внешний pooler решает другую, серверную задачу.
Связанные операции: odbc_connect(), odbc_close_all().
odbc_closeЗакрывает обычное ODBC-соединение после завершения работы и освобождает связанные с ним ресурсы процесса.
odbc_close(Odbc\Connection $odbc): voidЗакрывает обычное ODBC-соединение после завершения работы и освобождает связанные с ним ресурсы процесса.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_close(Odbc\Connection $odbc): void
| Параметр | Что передать |
|---|---|
Odbc\Connection $odbc | Объект Odbc\Connection, который вернул odbc_connect() или odbc_pconnect(). Он привязан к одному драйверу и одной сессии базы. |
Возврат. Ничего не возвращает. Официальная документация говорит, что при открытой транзакции функция завершится неудачей и оставит соединение открытым; конкретная связка PHP/Driver Manager/драйвер может фактически закрыть handle и откатить транзакцию, поэтому полагаться на это нельзя.
Отказ и диагностика. Официальный contract и наблюдаемое поведение драйвера могут расходиться. Невалидный/уже закрытый объект приводит к Error/TypeError, а не к безопасному false.
- код завершает чтение результатов
- открытая транзакция явно commit/rollback
- odbc_close освобождает соединение
- повторный вызов через объект запрещён
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, 'SELECT COUNT(*) AS total FROM pg_catalog.pg_class');
echo ((int) odbc_result($result, 'total') > 0) ? "report-ready\n" : "empty\n";
odbc_close($connection);
try {
odbc_exec($connection, 'SELECT 1');
} catch (Error) {
echo "connection-closed\n";
}
Ожидаемый результат
report-ready
connection-closed
После закрытия тот же объект больше нельзя передавать ODBC-функциям. Результат читают до закрытия соединения. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_close_tx');
uodbcExec($connection, 'CREATE TABLE phpman_close_tx (id INTEGER PRIMARY KEY)');
odbc_autocommit($connection, false);
uodbcExec($connection, 'INSERT INTO phpman_close_tx VALUES (1)');
@odbc_close($connection);
$state = 'open';
try {
odbc_exec($connection, 'SELECT 1');
odbc_rollback($connection);
odbc_autocommit($connection, true);
odbc_close($connection);
} catch (Error) {
$state = 'closed';
}
$cleanup = uodbcConnect();
$check = uodbcExec($cleanup, 'SELECT COUNT(*) AS total FROM phpman_close_tx');
echo "connection={$state}\n";
echo "rows-after-close=", odbc_result($check, 'total'), "\n";
uodbcDrop($cleanup, 'phpman_close_tx');
odbc_close($cleanup);
Ожидаемый результат
connection=closed
rows-after-close=0
Официальный manual обещает, что odbc_close() при открытой транзакции завершится неудачей и оставит соединение открытым. Проверенный PHP 8.5.11 + psqlODBC 18.00 фактически закрыл handle и сервер откатил INSERT. В php-src 8.5.11 safe_odbc_disconnect() после ошибки SQLDisconnect вызывает SQL_ROLLBACK, повторяет disconnect и освобождает handle. Это важное расхождение runtime: приложение обязано вызвать commit/rollback до close и не использовать close как transaction control. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Всегда явно commit/rollback до close: не рассчитывайте ни на сохранение handle, ни на автоматический rollback.
- Не закрывайте соединение до чтения нужного результата.
- Persistent-соединение управляется иначе и предназначено для повторного использования.
Когда выбрать другое. Обычно PHP закроет обычное соединение в конце процесса/запроса, но явное закрытие делает границу владения понятной и освобождает дефицитный ресурс раньше.
Связанные операции: odbc_connect(), odbc_commit(), odbc_rollback(), odbc_close_all().
odbc_close_allЗакрывает все обычные ODBC-соединения текущего PHP-процесса; полезна главным образом в диагностическом CLI-скрипте, который целиком владеет ими.
odbc_close_all(): voidЗакрывает все обычные ODBC-соединения текущего PHP-процесса; полезна главным образом в диагностическом CLI-скрипте, который целиком владеет ими.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_close_all(): void
| Параметр | Что передать |
|---|---|
| Аргументов нет | Функция действует на ODBC-соединения текущего PHP-процесса. |
Возврат. Возвращаемого значения нет. По официальной документации соединение с открытой транзакцией должно остаться открытым; проверенная psqlODBC-связка закрыла его, поэтому результат нельзя использовать как переносимую transaction guarantee.
Отказ и диагностика. Не полагайтесь на функцию как на аварийный rollback или способ сохранить транзакционное соединение. Уже закрытые объекты после вызова выбрасывают Error при использовании.
- функция обходит известные процессу соединения
- драйвер решает фактическое закрытие handle
- сервер завершает/откатывает сессию при закрытии
- код не получает отчёта о результате
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$first = uodbcConnect();
$second = uodbcConnect();
odbc_close_all();
$closed = 0;
foreach ([$first, $second] as $connection) {
try { odbc_exec($connection, 'SELECT 1'); } catch (Error) { $closed++; }
}
echo "closed={$closed}\n";
Ожидаемый результат
closed=2
Функция действует на соединения процесса, поэтому её редко вызывают в библиотеке: она может закрыть ресурс чужого компонента. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$first = uodbcConnect();
$second = uodbcConnect();
uodbcDrop($second, 'phpman_close_all_tx');
uodbcExec($second, 'CREATE TABLE phpman_close_all_tx (id INTEGER PRIMARY KEY)');
odbc_autocommit($second, false);
uodbcExec($second, 'INSERT INTO phpman_close_all_tx VALUES (1)');
odbc_close_all();
$states = [];
foreach (['first' => $first, 'transactional' => $second] as $name => $connection) {
try {
odbc_exec($connection, 'SELECT 1');
$states[$name] = 'open';
if ($name === 'transactional') { odbc_rollback($connection); }
odbc_close($connection);
} catch (Error) {
$states[$name] = 'closed';
}
}
$cleanup = uodbcConnect();
$check = uodbcExec($cleanup, 'SELECT COUNT(*) AS total FROM phpman_close_all_tx');
echo "first={$states['first']}\n";
echo "transactional={$states['transactional']}\n";
echo "rows-after-close=", odbc_result($check, 'total'), "\n";
uodbcDrop($cleanup, 'phpman_close_all_tx');
odbc_close($cleanup);
Ожидаемый результат
first=closed
transactional=closed
rows-after-close=0
Manual обещает оставить транзакционное соединение открытым. На проверенной связке close_all закрыл оба handles и PostgreSQL откатил незавершённый INSERT; это соответствует ветке rollback/retry/free в safe_odbc_disconnect() php-src 8.5.11. Поэтому глобальное закрытие не заменяет явный rollback/commit и требует проверки на каждом драйвере. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Глобальное действие нарушает владение ресурсами в большом приложении.
- Открытые транзакции надо завершить до close_all независимо от обещания manual.
- Функция ничего не сообщает о числе закрытых соединений.
Когда выбрать другое. Закрывайте конкретный Odbc\Connection там, где закончился его жизненный цикл; контейнер приложения может вести явный список собственных соединений.
Связанные операции: odbc_close(), odbc_autocommit(), odbc_rollback().
odbc_cursorВозвращает имя ODBC-курсора результата. Оно нужно редким низкоуровневым SQL/драйверным сценариям; для обычного foreach-подобного чтения имя не требуется.
odbc_cursor(Odbc\Result $statement): string|falseВозвращает имя ODBC-курсора результата. Оно нужно редким низкоуровневым SQL/драйверным сценариям; для обычного foreach-подобного чтения имя не требуется.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_cursor(Odbc\Result $statement): string|false
| Параметр | Что передать |
|---|---|
Odbc\Result $statement | Объект Odbc\Result: результат запроса или подготовленная команда. После odbc_free_result() его повторно не читают. |
Возврат. Строка с именем курсора или false, если драйвер не смог его предоставить.
Отказ и диагностика. false означает отсутствие доступного имени, а не пустой набор строк. Предупреждение/SQLSTATE проверяют отдельно.
- запрос создаёт result/cursor
- odbc_cursor просит у драйвера имя
- драйвер возвращает свою строку
- код использует её только там, где протокол требует positioned operation
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, 'SELECT 10 AS id');
$cursor = odbc_cursor($result);
echo is_string($cursor) && $cursor !== '' ? "cursor=yes\n" : "cursor=no\n";
odbc_close($connection);
Ожидаемый результат
cursor=yes
Само имя генерирует драйвер, поэтому приложение проверяет договор string|false, а не ожидает конкретную случайную строку. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$statement = odbc_prepare($connection, 'SELECT CAST(? AS INTEGER) AS id');
if ($statement === false || !odbc_execute($statement, [7])) {
throw new RuntimeException(odbc_error($connection).' '.odbc_errormsg($connection));
}
echo odbc_cursor($statement) === false ? "no-cursor\n" : "prepared-cursor\n";
odbc_close($connection);
Ожидаемый результат
prepared-cursor
Prepared statement после execute также представлен Odbc\Result и имеет курсор, если драйвер его предоставляет. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Не делайте бизнес-логику зависимой от конкретного сгенерированного имени.
- Имя курсора и позиция чтения — разные понятия.
- Поддержка positioned update/delete зависит от СУБД.
Когда выбрать другое. Обычные SELECT/UPDATE с первичным ключом и параметрами понятнее и переносимее positioned-операций.
Связанные операции: odbc_exec(), odbc_prepare(), odbc_fetch_row().
odbc_data_sourceПеречисляет настроенные источники данных Driver Manager. Это диагностический инструмент для установки, а не способ выбирать рабочую базу из пользовательского ввода.
odbc_data_source(Odbc\Connection $odbc, int $fetch_type): array|false|nullПеречисляет настроенные источники данных Driver Manager. Это диагностический инструмент для установки, а не способ выбирать рабочую базу из пользовательского ввода.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_data_source(Odbc\Connection $odbc, int $fetch_type): array|false|null
| Параметр | Что передать |
|---|---|
Odbc\Connection $odbc | Объект Odbc\Connection, который вернул odbc_connect() или odbc_pconnect(). Он привязан к одному драйверу и одной сессии базы. |
int $fetch_type | SQL_FETCH_FIRST начинает перечисление источников данных, SQL_FETCH_NEXT продолжает его для того же соединения. |
Возврат. Массив с ключами server/description при успехе, null после последнего DSN, false при ошибке.
Отказ и диагностика. false означает ошибку API/Driver Manager. Конец списка — отдельный null; SQLSTATE и сообщение читают при false.
- SQL_FETCH_FIRST начинает перечисление
- Driver Manager возвращает одну запись
- SQL_FETCH_NEXT двигает внутреннюю позицию
- null завершает список, false сообщает отказ
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$item = odbc_data_source($connection, SQL_FETCH_FIRST);
echo is_array($item) ? "enumeration=available\n" : "enumeration=empty\n";
$result = uodbcExec($connection, 'SELECT 1 AS alive');
echo "connection=", odbc_result($result, 'alive') == 1 ? "usable\n" : "failed\n";
odbc_close($connection);
Ожидаемый результат
enumeration=empty
connection=usable
Перечисление начинается SQL_FETCH_FIRST. В проверенной Windows/portable psqlODBC связке рабочий user DSN успешно подключается, но SQLDataSources не перечисляет ни одной записи. Это отдельная capability Driver Manager/драйвера: пустой список не доказывает, что DSN не работает. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$item = odbc_data_source($connection, SQL_FETCH_FIRST);
while (is_array($item)) {
$item = odbc_data_source($connection, SQL_FETCH_NEXT);
}
echo $item === null ? "end=null\n" : "error=false\n";
odbc_close($connection);
Ожидаемый результат
end=null
В PHP 8.4 конец списка — null, а false оставлен для ошибки. Проверка while ($item) смешивает эти два исхода. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Список может отличаться у другого пользователя/разрядности процесса.
- 64-битный PHP не видит 32-битный DSN как подходящий источник.
- Не показывайте административный перечень DSN всем посетителям сайта.
Когда выбрать другое. Конфигурационный health-check может проверять заранее заданный DSN прямым odbc_connect(), не раскрывая весь список.
Связанные операции: odbc_connect(), odbc_error().
odbc_connection_string_is_quotedПроверяет, является ли одно значение корректно заключённым по правилам ODBC connection string.
odbc_connection_string_is_quoted(string $str): boolПроверяет, является ли одно значение корректно заключённым по правилам ODBC connection string.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_connection_string_is_quoted(string $str): bool
| Параметр | Что передать |
|---|---|
string $str | Одно значение внутри ODBC connection string, без пары Ключ=Значение. |
Возврат. true только для полной корректной формы в фигурных скобках; false для обычной или повреждённой строки.
Отказ и диагностика. Функция не подключается к базе и не проверяет корректность ключей DSN; она возвращает только bool формы значения.
- получить одно значение, не всю DSN-строку
- проверить внешние скобки
- проверить удвоение внутренних }
- решить: оставить либо передать quote()
<?php
declare(strict_types=1);
foreach (['{plain}', '{a}}b}', 'plain', '{broken}tail'] as $value) {
echo $value, ':', odbc_connection_string_is_quoted($value) ? 'yes' : 'no', "\n";
}
Ожидаемый результат
{plain}:yes
{a}}b}:yes
plain:no
{broken}tail:no
ODBC использует внешние фигурные скобки, а закрывающую скобку внутри удваивает. Пример выполнен в PHP 8.5.11 с изолированно загруженным ext/odbc; подключение к базе ему не требуется.
<?php
declare(strict_types=1);
$input = '{North;Warehouse}';
$safe = odbc_connection_string_is_quoted($input)
? $input
: odbc_connection_string_quote($input);
echo $safe, "\n";
Ожидаемый результат
{North;Warehouse}
Сначала проверяем готовую форму; quote() сама не распознаёт уже заключённое значение. Пример выполнен в PHP 8.5.11 с изолированно загруженным ext/odbc; подключение к базе ему не требуется.
Частые ошибки.
- Не передавайте целиком Driver=...;Server=... как одно значение.
- Проверка формы не делает недоверенный DSN разрешённым.
- Уже quoted-значение не надо повторно quote() без осознанной причины.
Когда выбрать другое. Лучше собирать разрешённые ключи connection string из конфигурации и quote() только значения; имя драйвера выбирают по allowlist.
Связанные операции: odbc_connection_string_should_quote(), odbc_connection_string_quote(), odbc_connect().
odbc_connection_string_should_quoteСообщает, содержит ли одно значение специальные символы, из-за которых Driver Manager может неверно разобрать его без фигурных скобок.
odbc_connection_string_should_quote(string $str): boolСообщает, содержит ли одно значение специальные символы, из-за которых Driver Manager может неверно разобрать его без фигурных скобок.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_connection_string_should_quote(string $str): bool
| Параметр | Что передать |
|---|---|
string $str | Одно значение внутри ODBC connection string, без пары Ключ=Значение. |
Возврат. bool: true означает «нужно quoted-представление», но не отвечает, заключена ли строка уже.
Отказ и диагностика. Не проверяет DSN, доступность драйвера или безопасность выбранного ключа; это чистая операция над строкой.
- взять исходное значение
- найти разделители/краевые пробелы/скобки
- вернуть необходимость quoted-формы
- is_quoted решает, готова ли форма сейчас
<?php
declare(strict_types=1);
foreach (['warehouse', 'North;Warehouse', ' leading', 'brace}'] as $value) {
echo json_encode($value), ':', odbc_connection_string_should_quote($value) ? 'quote' : 'plain', "\n";
}
Ожидаемый результат
"warehouse":plain
"North;Warehouse":quote
" leading":quote
"brace}":quote
Точка с запятой, крайний пробел и фигурная скобка меняют разбор connection string и требуют quote(). Пример выполнен в PHP 8.5.11 с изолированно загруженным ext/odbc; подключение к базе ему не требуется.
<?php
declare(strict_types=1);
$value = '{North;Warehouse}';
echo odbc_connection_string_should_quote($value) ? "has-specials\n" : "plain\n";
echo odbc_connection_string_is_quoted($value) ? "already-quoted\n" : "needs-quote\n";
Ожидаемый результат
has-specials
already-quoted
should_quote() видит специальные скобки и потому возвращает true даже для готовой формы; нужен отдельный is_quoted(). Пример выполнен в PHP 8.5.11 с изолированно загруженным ext/odbc; подключение к базе ему не требуется.
Частые ошибки.
- true не значит, что строка ещё не quoted.
- false не разрешает помещать пользовательский текст в имя ключа/драйвера.
- Пароль после обработки всё равно остаётся секретом.
Когда выбрать другое. Если значение всегда проходит quote(), предварительная should_quote-проверка не обязательна; она нужна для читаемой сборки и диагностики.
Связанные операции: odbc_connection_string_is_quoted(), odbc_connection_string_quote().
odbc_connection_string_quoteПреобразует одно значение в ODBC-quoted форму: добавляет фигурные скобки и удваивает каждую закрывающую скобку внутри.
odbc_connection_string_quote(string $str): stringПреобразует одно значение в ODBC-quoted форму: добавляет фигурные скобки и удваивает каждую закрывающую скобку внутри.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_connection_string_quote(string $str): string
| Параметр | Что передать |
|---|---|
string $str | Одно значение внутри ODBC connection string, без пары Ключ=Значение. |
Возврат. Всегда возвращает строку, даже если исходное значение не требовало quoted-формы или уже было заключено.
Отказ и диагностика. Функция не открывает соединение и не валидирует адрес/права. Она решает только синтаксическую границу одного значения.
- программа выбирает разрешённый ключ
- quote получает только его значение
- } внутри удваивается
- готовая {…} форма добавляется после знака =
<?php
declare(strict_types=1);
$value = 'North;Rack}2';
echo 'Warehouse=', odbc_connection_string_quote($value), "\n";
Ожидаемый результат
Warehouse={North;Rack}}2}
Внешние скобки удерживают точку с запятой внутри значения, внутренняя } удваивается. Пример выполнен в PHP 8.5.11 с изолированно загруженным ext/odbc; подключение к базе ему не требуется.
<?php
declare(strict_types=1);
$server = 'db01.internal;ApplicationIntent=ReadOnly';
$database = 'orders}archive';
$fragment = 'Server='.odbc_connection_string_quote($server)
.';Database='.odbc_connection_string_quote($database).';';
echo $fragment, "\n";
Ожидаемый результат
Server={db01.internal;ApplicationIntent=ReadOnly};Database={orders}}archive};
Инъекционный разделитель остаётся частью Server, а не новым ключом. Сам набор ключей Server/Database задаёт программа. Пример выполнен в PHP 8.5.11 с изолированно загруженным ext/odbc; подключение к базе ему не требуется.
Частые ошибки.
- Не разрешайте посетителю задавать имя драйвера или произвольные ключи connection string.
- Не quote() целиком пару Server=value.
- Не выводите итоговую строку, если в ней есть пароль.
Когда выбрать другое. Для стабильного приложения предпочтителен заранее настроенный DSN с секретом вне кода; DSN-less строка полезна в контейнере/автоматической конфигурации.
Связанные операции: odbc_connection_string_is_quoted(), odbc_connection_string_should_quote(), odbc_connect().
odbc_execНемедленно выполняет один SQL-текст и возвращает объект результата. Подходит DDL и полностью статическим запросам; значения пользователя передают подготовленной команде.
odbc_exec(Odbc\Connection $odbc, string $query): Odbc\Result|falseНемедленно выполняет один SQL-текст и возвращает объект результата. Подходит DDL и полностью статическим запросам; значения пользователя передают подготовленной команде.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_exec(Odbc\Connection $odbc, string $query): Odbc\Result|false
| Параметр | Что передать |
|---|---|
Odbc\Connection $odbc | Объект Odbc\Connection, который вернул odbc_connect() или odbc_pconnect(). Он привязан к одному драйверу и одной сессии базы. |
string $query | SQL-текст. Данные пользователя не склеивают с ним; для значений используют ? и odbc_execute(). |
Возврат. Odbc\Result при успехе, false при ошибке. Для INSERT/UPDATE объект нужен для диагностики/числа затронутых строк.
Отказ и диагностика. false плюс warning и diagnostic record. Немедленно сохраните odbc_error()/odbc_errormsg(); не продолжайте fetch с false.
- программа формирует доверенный SQL
- драйвер подготавливает и выполняет его
- сервер возвращает статус/строки
- код проверяет false до fetch
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_exec_product');
try {
uodbcExec($connection, 'CREATE TABLE phpman_exec_product (id INTEGER PRIMARY KEY, name VARCHAR(50))');
uodbcExec($connection, "INSERT INTO phpman_exec_product VALUES (1, 'Notebook')");
$result = odbc_exec($connection, 'SELECT name FROM phpman_exec_product WHERE id=1');
if ($result === false) { throw new RuntimeException(odbc_errormsg($connection)); }
echo odbc_result($result, 'name'), "\n";
} finally {
uodbcDrop($connection, 'phpman_exec_product');
odbc_close($connection);
}
Ожидаемый результат
Notebook
odbc_exec подходит SQL, полностью заданному программой. Значение посетителя сюда не склеивается. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_exec_sort');
try {
uodbcExec($connection, 'CREATE TABLE phpman_exec_sort (id INTEGER PRIMARY KEY, price INTEGER)');
uodbcExec($connection, 'INSERT INTO phpman_exec_sort VALUES (1, 300), (2, 100)');
$requested = 'price';
$allowed = ['id' => 'id', 'price' => 'price'];
$column = $allowed[$requested] ?? 'id';
$result = odbc_exec($connection, "SELECT id FROM phpman_exec_sort ORDER BY {$column}, id");
if ($result === false) { throw new RuntimeException(odbc_errormsg($connection)); }
while ($row = odbc_fetch_array($result)) { echo $row['id'], "\n"; }
} finally {
uodbcDrop($connection, 'phpman_exec_sort');
odbc_close($connection);
}
Ожидаемый результат
2
1
Placeholder не подставляет имя столбца. Структуру SQL выбирают по allowlist, а пользовательские значения передают prepare/execute. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Не склеивайте с SQL текст формы, JSON или URL.
- Placeholder не заменяет имя таблицы/столбца.
- Несколько SQL-команд одной строкой ухудшают переносимость и обработку результатов.
Когда выбрать другое. odbc_prepare()+odbc_execute() для динамических значений; миграционный инструмент для схемы; нативный драйвер для специфического SQL API.
Связанные операции: odbc_prepare(), odbc_execute(), odbc_do(), odbc_error().
odbc_doИсторический псевдоним odbc_exec(): немедленно выполняет SQL и имеет тот же договор.
odbc_do(Odbc\Connection $odbc, string $query): Odbc\Result|falseИсторический псевдоним odbc_exec(): немедленно выполняет SQL и имеет тот же договор.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_do(Odbc\Connection $odbc, string $query): Odbc\Result|false
| Параметр | Что передать |
|---|---|
Odbc\Connection $odbc | Объект Odbc\Connection, который вернул odbc_connect() или odbc_pconnect(). Он привязан к одному драйверу и одной сессии базы. |
string $query | SQL-текст. Данные пользователя не склеивают с ним; для значений используют ? и odbc_execute(). |
Возврат. Odbc\Result либо false — полностью как odbc_exec().
Отказ и диагностика. Тот же false/warning/diagnostics, что у odbc_exec(). Отдельного поведения у alias нет.
- вызов alias попадает в реализацию odbc_exec
- SQL выполняется драйвером
- возвращается тот же тип результата
- дальнейшая обработка ничем не отличается
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = odbc_do($connection, "SELECT 'legacy-alias' AS label");
if ($result === false) { throw new RuntimeException(odbc_errormsg($connection)); }
echo odbc_result($result, 'label'), "\n";
odbc_close($connection);
Ожидаемый результат
legacy-alias
odbc_do — настоящий alias odbc_exec, а не отдельный способ выполнения. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_do_status');
try {
uodbcExec($connection, 'CREATE TABLE phpman_do_status (id INTEGER PRIMARY KEY, state VARCHAR(20))');
uodbcExec($connection, "INSERT INTO phpman_do_status VALUES (1, 'new')");
$result = odbc_do($connection, "UPDATE phpman_do_status SET state='sent' WHERE id=1");
if ($result === false) { throw new RuntimeException(odbc_errormsg($connection)); }
echo "changed=", odbc_num_rows($result), "\n";
} finally {
uodbcDrop($connection, 'phpman_do_status');
odbc_close($connection);
}
Ожидаемый результат
changed=1
Пример помогает читать legacy-код; в новом коде одно название odbc_exec уменьшает лишние варианты. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Не считайте do более быстрым или безопасным.
- Не используйте alias для сокрытия склейки пользовательского SQL.
- Смешивание двух имён усложняет поиск по проекту.
Когда выбрать другое. В новом коде используйте odbc_exec(); для значений — prepare/execute.
Связанные операции: odbc_exec(), odbc_prepare(), odbc_num_rows().
odbc_prepareСоздаёт подготовленную команду с позиционными знаками ?. Это граница между структурой SQL и данными формы/API.
odbc_prepare(Odbc\Connection $odbc, string $query): Odbc\Result|falseСоздаёт подготовленную команду с позиционными знаками ?. Это граница между структурой SQL и данными формы/API.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_prepare(Odbc\Connection $odbc, string $query): Odbc\Result|false
| Параметр | Что передать |
|---|---|
Odbc\Connection $odbc | Объект Odbc\Connection, который вернул odbc_connect() или odbc_pconnect(). Он привязан к одному драйверу и одной сессии базы. |
string $query | SQL-текст. Данные пользователя не склеивают с ним; для значений используют ? и odbc_execute(). |
Возврат. Odbc\Result при успехе, false при отказе подготовки. Сам запрос с параметрами выполняется только odbc_execute().
Отказ и диагностика. false может означать синтаксис, неподдерживаемую возможность или невозможность вывести тип параметра. Сохраните diagnostics до следующего ODBC-вызова.
- SQL содержит ? без кавычек
- драйвер разбирает/готовит команду
- возвращается statement как Odbc\Result
- execute позже связывает значения
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_prepare_product');
try {
uodbcExec($connection, 'CREATE TABLE phpman_prepare_product (id INTEGER PRIMARY KEY, name VARCHAR(50))');
uodbcExec($connection, "INSERT INTO phpman_prepare_product VALUES (1, 'Pen'), (2, 'Book')");
$statement = odbc_prepare($connection, 'SELECT name FROM phpman_prepare_product WHERE id=CAST(? AS INTEGER)');
if ($statement === false) { throw new RuntimeException(odbc_errormsg($connection)); }
odbc_execute($statement, [2]);
$row = odbc_fetch_array($statement);
echo $row['name'], "\n";
} finally {
uodbcDrop($connection, 'phpman_prepare_product');
odbc_close($connection);
}
Ожидаемый результат
Book
SQL-компоновка и значение id разделены. CAST делает ожидаемый тип placeholder явным для разных драйверов. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$statement = odbc_prepare($connection, 'SELECT CAST(? AS INTEGER) * 2 AS doubled');
if ($statement === false) { throw new RuntimeException(odbc_errormsg($connection)); }
foreach ([3, 8] as $value) {
if (!odbc_execute($statement, [$value])) { throw new RuntimeException(odbc_errormsg($connection)); }
$row = odbc_fetch_array($statement);
echo $row['doubled'], "\n";
}
odbc_close($connection);
Ожидаемый результат
6
16
Повторное execute меняет данные, а SQL-контракт остаётся одним. Выигрыш зависит от драйвера и числа повторов; измеряйте. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Не заключайте ? в одинарные кавычки.
- Количество ? должно совпасть с params.
- Идентификаторы нельзя передать placeholder-ом.
Когда выбрать другое. Для однократного полностью статического SQL достаточно odbc_exec(); PDO даёт именованные параметры на поддерживаемых драйверах.
Связанные операции: odbc_execute(), odbc_exec(), odbc_free_result().
odbc_executeВыполняет statement от odbc_prepare(), подставляя позиционные значения из массива. Один statement можно запускать повторно для пакета строк.
odbc_execute(Odbc\Result $statement, array $params = []): boolВыполняет statement от odbc_prepare(), подставляя позиционные значения из массива. Один statement можно запускать повторно для пакета строк.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_execute(Odbc\Result $statement, array $params = []): bool
| Параметр | Что передать |
|---|---|
Odbc\Result $statement | Объект Odbc\Result: результат запроса или подготовленная команда. После odbc_free_result() его повторно не читают. |
array $params (по умолчанию array (
)) | Значения для знаков ? строго по порядку. Имена параметров этот API не поддерживает. |
Возврат. true при успехе, false при отказе. Строки результата читают из того же объекта statement.
Отказ и диагностика. false плюс warning; diagnostics могут относиться к execute. SQLSTATE класса 01 — предупреждение при успешном true, его учитывают отдельно от класса ошибки. OUT/INOUT-параметры процедур этим API надёжно не покрываются — официальный manual предлагает нативный драйвер.
- массив params проверен приложением
- значения сопоставляются ? по порядку
- драйвер связывает/конвертирует их
- сервер выполняет запрос, затем fetch читает результат
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_execute_item');
try {
uodbcExec($connection, 'CREATE TABLE phpman_execute_item (id INTEGER PRIMARY KEY, name VARCHAR(50))');
$statement = odbc_prepare($connection, 'INSERT INTO phpman_execute_item (id, name) VALUES (CAST(? AS INTEGER), ?)');
if ($statement === false) { throw new RuntimeException(odbc_errormsg($connection)); }
foreach ([[1, 'Pen'], [2, 'Notebook']] as $params) {
if (!@odbc_execute($statement, $params)) { throw new RuntimeException(odbc_errormsg($connection)); }
}
$result = uodbcExec($connection, 'SELECT COUNT(*) AS total FROM phpman_execute_item');
echo "rows=", odbc_result($result, 'total'), "\n";
} finally {
uodbcDrop($connection, 'phpman_execute_item');
odbc_close($connection);
}
Ожидаемый результат
rows=2
Массив params идёт строго слева направо. Значения не получают SQL-кавычки в PHP. psqlODBC может дополнительно выдать SQLSTATE класса 01 (warning, например 01S02 о смене cursor updatability) при успешном true; production-код пишет такую диагностику отдельно, не превращая её автоматически в отказ. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_execute_customer');
try {
uodbcExec($connection, 'CREATE TABLE phpman_execute_customer (id INTEGER PRIMARY KEY, name VARCHAR(50))');
$statement = odbc_prepare($connection, 'INSERT INTO phpman_execute_customer VALUES (1, ?)');
if ($statement === false || !@odbc_execute($statement, ["O'Reilly"])) {
throw new RuntimeException(odbc_errormsg($connection));
}
$row = uodbcExec($connection, 'SELECT name FROM phpman_execute_customer WHERE id=1');
echo odbc_result($row, 'name'), "\n";
} finally {
uodbcDrop($connection, 'phpman_execute_customer');
odbc_close($connection);
}
Ожидаемый результат
O'Reilly
Апостроф внутри обычной строки — данные. Особая legacy-граница ext/odbc: строка, которая целиком начинается и заканчивается одинарной кавычкой, трактуется как имя файла; такие значения надо отдельно запрещать/нормализовать и не передавать из недоверенного ввода. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Не заключайте ? в SQL-кавычки.
- Все элементы params преобразуются к строкам.
- Не путайте successful true с отсутствием diagnostics: драйвер может вернуть warning класса 01.
- Legacy-правило: строка, начинающаяся и заканчивающаяся ', воспринимается как путь к файлу — это риск утечки локального файла.
Когда выбрать другое. Нативное расширение/драйвер для OUT-параметров, typed binding и LOB; batch/COPY для больших импортов.
Связанные операции: odbc_prepare(), odbc_fetch_array(), odbc_error().
odbc_next_resultПереводит result к следующему набору строк от batch/stored procedure. Нужна, когда один вызов осознанно возвращает несколько результатов.
odbc_next_result(Odbc\Result $statement): boolПереводит result к следующему набору строк от batch/stored procedure. Нужна, когда один вызов осознанно возвращает несколько результатов.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_next_result(Odbc\Result $statement): bool
| Параметр | Что передать |
|---|---|
Odbc\Result $statement | Объект Odbc\Result: результат запроса или подготовленная команда. После odbc_free_result() его повторно не читают. |
Возврат. true, если следующий result set доступен, false при завершении или отказе.
Отказ и диагностика. false объединяет нормальный конец и отказ. Если ожидался ещё один набор, прочитайте odbc_error()/odbc_errormsg().
- полностью обработать текущий набор
- вызвать next_result
- при true читать новый набор
- при false завершить и проверить diagnostics при подозрении на ошибку
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, 'SELECT 1 AS step; SELECT 2 AS step');
do {
$row = odbc_fetch_array($result);
echo "step=", $row['step'], "\n";
} while (odbc_next_result($result));
odbc_close($connection);
Ожидаемый результат
step=1
step=2
После полного чтения текущего результата next_result переводит тот же объект на следующий набор. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, 'SELECT 7 AS value');
$row = odbc_fetch_array($result);
echo "value=", $row['value'], "\n";
echo odbc_next_result($result) ? "more\n" : "done\n";
odbc_close($connection);
Ожидаемый результат
value=7
done
false здесь означает, что следующего result set нет. Ошибку отличают по SQLSTATE/сообщению и контексту вызова. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Не смешивайте колонки разных наборов в одну схему без проверки.
- Не все драйверы разрешают несколько SQL-команд строкой.
- Текущий набор надо обработать/освободить по договору драйвера.
Когда выбрать другое. Два явных запроса легче типизировать и диагностировать; stored procedure оправдана, когда граница операции находится в БД.
Связанные операции: odbc_exec(), odbc_fetch_array(), odbc_free_result().
odbc_fetch_arrayЧитает следующую (или указанную поддерживаемым курсором) строку как ассоциативный массив. Это удобный формат для шаблона, JSON-модели или последующей проверки.
odbc_fetch_array(Odbc\Result $statement, ?int $row = null): array|falseЧитает следующую (или указанную поддерживаемым курсором) строку как ассоциативный массив. Это удобный формат для шаблона, JSON-модели или последующей проверки.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_fetch_array(Odbc\Result $statement, ?int $row = null): array|false
| Параметр | Что передать |
|---|---|
Odbc\Result $statement | Объект Odbc\Result: результат запроса или подготовленная команда. После odbc_free_result() его повторно не читают. |
?int $row (по умолчанию NULL) | Необязательный номер строки. Поддержка произвольного позиционирования зависит от курсора и драйвера. |
Возврат. Ассоциативный array либо false, когда строки закончились/операция не удалась.
Отказ и диагностика. false объединяет конец данных и отказ; если конец неожиданный, прочитайте diagnostics. Имена/регистр колонок определяются драйвером и SQL aliases.
- result хранит набор и текущую позицию
- fetch двигает курсор
- драйвер преобразует ODBC-значения
- PHP получает массив по именам колонок
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, "SELECT * FROM (VALUES (1, 'Pen'), (2, 'Book')) AS products(id, name) ORDER BY id");
while ($row = odbc_fetch_array($result)) {
echo $row['id'], ':', $row['name'], "\n";
}
odbc_close($connection);
Ожидаемый результат
1:Pen
2:Book
Каждый fetch возвращает новую строку как массив «имя столбца => значение»; false завершает цикл. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, "SELECT * FROM (VALUES (10, 'A'), (20, 'B'), (30, 'C')) AS items(id, code) ORDER BY id");
$row = odbc_fetch_array($result, 3);
echo $row['id'], ':', $row['code'], "\n";
odbc_close($connection);
Ожидаемый результат
30:C
ODBC row_number начинается с 1. Произвольное позиционирование зависит от курсора/драйвера; последовательный цикл переносимее. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Не обращайтесь к ключу до проверки false.
- SELECT с одинаковыми именами колонок перезапишет смысл ключа — задайте aliases.
- Большой fetch-all массив лучше заменить последовательной обработкой.
Когда выбрать другое. fetch_object для простого чтения свойств; fetch_row+result для поэлементного legacy-кода; PDO для более богатых fetch modes.
Связанные операции: odbc_fetch_object(), odbc_fetch_row(), odbc_result().
odbc_fetch_objectЧитает строку результата как stdClass со свойствами по именам колонок.
odbc_fetch_object(Odbc\Result $statement, ?int $row = null): stdClass|falseЧитает строку результата как stdClass со свойствами по именам колонок.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_fetch_object(Odbc\Result $statement, ?int $row = null): stdClass|false
| Параметр | Что передать |
|---|---|
Odbc\Result $statement | Объект Odbc\Result: результат запроса или подготовленная команда. После odbc_free_result() его повторно не читают. |
?int $row (по умолчанию NULL) | Необязательный номер строки. Поддержка произвольного позиционирования зависит от курсора и драйвера. |
Возврат. stdClass или false при конце/отказе.
Отказ и диагностика. false нужно проверить до ->property. Коллизии/неудобные имена столбцов решают SQL aliases.
- курсор выбирает строку
- имена колонок становятся свойствами
- значения конвертируются драйвером
- код проверяет false до доступа ->
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, "SELECT 5 AS id, 'Cable' AS name");
$row = odbc_fetch_object($result);
if ($row === false) { throw new RuntimeException('Строка не найдена'); }
echo $row->id, ':', $row->name, "\n";
odbc_close($connection);
Ожидаемый результат
5:Cable
Возвращается stdClass, а не объект предметной модели: в нём нет валидации и методов товара. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, "SELECT 'INV-7' AS number, CAST(1250 AS INTEGER) AS total");
$row = odbc_fetch_object($result);
$payload = $row === false ? null : ['number' => $row->number, 'total' => (int) $row->total];
echo json_encode($payload, JSON_UNESCAPED_UNICODE), "\n";
odbc_close($connection);
Ожидаемый результат
{"number":"INV-7","total":1250}
Явное преобразование фиксирует внешнюю схему и тип total; не отдавайте произвольный row object напрямую как публичный API. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- stdClass не валидирует типы.
- Регистр свойств зависит от возвращённых имён.
- Не путайте объект строки с Odbc\Result.
Когда выбрать другое. Ассоциативный массив проще для динамических колонок; явный DTO/mapper даёт стабильный контракт приложения.
Связанные операции: odbc_fetch_array(), odbc_fetch_row(), odbc_result().
odbc_fetch_intoЗаписывает строку в переданную по ссылке переменную как числовой массив и возвращает число полей.
odbc_fetch_into(Odbc\Result $statement, mixed &$array, ?int $row = null): int|falseЗаписывает строку в переданную по ссылке переменную как числовой массив и возвращает число полей.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_fetch_into(Odbc\Result $statement, mixed &$array, ?int $row = null): int|false
| Параметр | Что передать |
|---|---|
Odbc\Result $statement | Объект Odbc\Result: результат запроса или подготовленная команда. После odbc_free_result() его повторно не читают. |
mixed $array | Переменная, в которую odbc_fetch_into() запишет числовой массив текущей строки. |
?int $row (по умолчанию NULL) | Необязательный номер строки. Поддержка произвольного позиционирования зависит от курсора и драйвера. |
Возврат. int с числом колонок или false при конце/отказе; массив изменяется как побочный эффект.
Отказ и диагностика. false не равно 0: проверяйте строго !== false. После конца не используйте старое содержимое массива как новую строку.
- передаётся переменная &$array
- fetch двигает курсор
- значения записываются по индексам 0..n-1
- возвращаемое n позволяет проверить структуру
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, "SELECT 4 AS id, 'Box' AS name");
$values = [];
$count = odbc_fetch_into($result, $values);
echo "fields={$count}\n";
echo $values[0], ':', $values[1], "\n";
odbc_close($connection);
Ожидаемый результат
fields=2
4:Box
Функция изменяет второй аргумент по ссылке и возвращает число полей; индексы массива начинаются с 0. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, "SELECT * FROM (VALUES (1, 100), (2, 250)) AS lines(id, amount) ORDER BY id");
$values = [];
$sum = 0;
while (odbc_fetch_into($result, $values) !== false) {
$sum += (int) $values[1];
}
echo "sum={$sum}\n";
odbc_close($connection);
Ожидаемый результат
sum=350
На каждой итерации массив получает текущую строку; это не загружает весь result в один PHP-массив. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Второй аргумент обязан быть переменной.
- Индексы массива с 0, а odbc_result field number с 1.
- Числовые позиции хрупки при изменении SELECT.
Когда выбрать другое. fetch_array с именами колонок читается лучше; fetch_into полезен для компактного legacy/экспортного цикла.
Связанные операции: odbc_fetch_array(), odbc_num_fields(), odbc_binmode().
odbc_fetch_rowПеремещает курсор на следующую или указанную строку; данные затем читают odbc_result().
odbc_fetch_row(Odbc\Result $statement, ?int $row = null): boolПеремещает курсор на следующую или указанную строку; данные затем читают odbc_result().
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_fetch_row(Odbc\Result $statement, ?int $row = null): bool
| Параметр | Что передать |
|---|---|
Odbc\Result $statement | Объект Odbc\Result: результат запроса или подготовленная команда. После odbc_free_result() его повторно не читают. |
?int $row (по умолчанию NULL) | Необязательный номер строки. Поддержка произвольного позиционирования зависит от курсора и драйвера. |
Возврат. true, если строка доступна; false при конце/отказе.
Отказ и диагностика. false обычно завершает последовательный цикл; неожиданный false проверяют по diagnostics. row_number может быть неподдержан типом курсора.
- result имеет текущую позицию
- fetch_row выбирает строку
- true подтверждает позицию
- odbc_result читает поле этой строки
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, "SELECT * FROM (VALUES (1, 'new'), (2, 'paid')) AS orders(id, state) ORDER BY id");
while (odbc_fetch_row($result)) {
echo odbc_result($result, 'id'), ':', odbc_result($result, 'state'), "\n";
}
odbc_close($connection);
Ожидаемый результат
1:new
2:paid
fetch_row только позиционирует курсор; каждое поле затем извлекается odbc_result(). Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, "SELECT * FROM (VALUES (10), (20), (30)) AS valueset(value) ORDER BY value");
if (!odbc_fetch_row($result, 2)) { throw new RuntimeException('Нет строки 2'); }
echo odbc_result($result, 1), "\n";
odbc_close($connection);
Ожидаемый результат
20
Номер строки начинается с 1. Некоторые драйверы/forward-only курсоры произвольный переход не поддерживают. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- После false не читайте odbc_result.
- Нумерация строк с 1.
- Многократный odbc_result делает код многословнее массива.
Когда выбрать другое. fetch_array/object возвращает строку одним вызовом; forward-only последовательное чтение обычно дешевле произвольного позиционирования.
Связанные операции: odbc_result(), odbc_fetch_array(), odbc_cursor().
odbc_resultЧитает одно поле текущей строки по имени или номеру. Перед этим курсор должен быть установлен fetch_row().
odbc_result(Odbc\Result $statement, string|int $field): string|bool|nullЧитает одно поле текущей строки по имени или номеру. Перед этим курсор должен быть установлен fetch_row().
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_result(Odbc\Result $statement, string|int $field): string|bool|null
| Параметр | Что передать |
|---|---|
Odbc\Result $statement | Объект Odbc\Result: результат запроса или подготовленная команда. После odbc_free_result() его повторно не читают. |
string|int $field | Номер столбца с 1 либо его имя. В ODBC позиции полей начинаются с 1. |
Возврат. string|bool|null по данным/режиму. Для бинарного passthru функция может отправить данные прямо в output вместо обычного возврата.
Отказ и диагностика. Неверное поле даёт warning/false-подобный исход в зависимости от версии/драйвера; проверяйте схему заранее. NULL — нормальное значение, не ошибка.
- fetch_row выбирает строку
- field выбирает колонку
- binmode/longreadlen задают преобразование
- значение возвращается либо passthru идёт в output
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, "SELECT 12 AS id, 'Ready' AS state");
odbc_fetch_row($result);
echo odbc_result($result, 'id'), "\n";
echo odbc_result($result, 2), "\n";
odbc_close($connection);
Ожидаемый результат
12
Ready
Имя устойчивее порядка SELECT; числовая позиция ODBC начинается с 1. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, "SELECT CAST(NULL AS VARCHAR(20)) AS note, CAST('' AS VARCHAR(20)) AS empty_text");
odbc_fetch_row($result);
echo odbc_result($result, 'note') === null ? "note=NULL\n" : "note=value\n";
echo odbc_result($result, 'empty_text') === '' ? "empty=string\n" : "empty=other\n";
odbc_close($connection);
Ожидаемый результат
note=NULL
empty=string
SQL NULL приходит как null, пустая строка остаётся строкой: проверки должны быть строгими. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Номер поля начинается с 1.
- Не путайте null и false.
- PASSTHRU способен неожиданно писать байты в HTTP-ответ.
Когда выбрать другое. fetch_array/object проще, когда нужны несколько колонок; result полезен для legacy-цикла и одного поля.
Связанные операции: odbc_fetch_row(), odbc_field_num(), odbc_binmode(), odbc_longreadlen().
odbc_result_allПечатает весь результат как HTML-таблицу и возвращает число строк. Это legacy-помощник, устаревший с PHP 8.1.
odbc_result_all(Odbc\Result $statement, string $format = ''): int|falseПечатает весь результат как HTML-таблицу и возвращает число строк. Это legacy-помощник, устаревший с PHP 8.1.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_result_all(Odbc\Result $statement, string $format = ''): int|false
| Параметр | Что передать |
|---|---|
Odbc\Result $statement | Объект Odbc\Result: результат запроса или подготовленная команда. После odbc_free_result() его повторно не читают. |
string $format (по умолчанию '') | Дополнительные атрибуты старого HTML-вывода; функцию odbc_result_all() не используют с недоверенным текстом. |
Возврат. int количества строк либо false. Основной эффект — прямой HTML-вывод.
Отказ и диагностика. false сообщает отказ, но частичный output уже мог быть отправлен. Deprecated warning подавлять в новом коде не решение — функцию заменяют.
- функция сама обходит строки
- печатает table/th/td
- возвращает число обработанных строк
- вывод уже смешан с представлением
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, "SELECT * FROM (VALUES (1, 'Pen'), (2, 'Book')) AS products(id, name) ORDER BY id");
ob_start();
$rows = @odbc_result_all($result);
$html = (string) ob_get_clean();
echo "rows={$rows}\n";
echo str_contains($html, '<table') && str_contains($html, 'Pen') ? "html=yes\n" : "html=no\n";
odbc_close($connection);
Ожидаемый результат
rows=2
html=yes
Функция печатает HTML сама; output buffering лишь позволяет увидеть это поведение. Для нового интерфейса лучше собственный шаблон с htmlspecialchars(). Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, "SELECT 'safe' AS value");
ob_start();
$rows = @odbc_result_all($result, 'class="report"');
$html = (string) ob_get_clean();
echo "rows={$rows}\n";
echo str_contains($html, 'class="report"') ? "class=yes\n" : "class=no\n";
odbc_close($connection);
Ожидаемый результат
rows=1
class=yes
format попадает в HTML-атрибуты без современного шаблонного контракта; недоверенный ввод сюда передавать нельзя. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Deprecated с PHP 8.1.
- Смешивает данные и HTML.
- format/данные требуют защиты от HTML-инъекции.
Когда выбрать другое. fetch_array в цикле + шаблон, который экранирует каждую ячейку; JSON API возвращает структуру, а UI строит таблицу отдельно.
Связанные операции: odbc_fetch_array(), odbc_num_rows().
odbc_free_resultОсвобождает курсор и другие объекты, связанные с Odbc\Result. Соединение при этом остаётся открытым.
odbc_free_result(Odbc\Result $statement): trueОсвобождает курсор и другие объекты, связанные с Odbc\Result. Соединение при этом остаётся открытым.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_free_result(Odbc\Result $statement): true
| Параметр | Что передать |
|---|---|
Odbc\Result $statement | Объект Odbc\Result: результат запроса или подготовленная команда. После odbc_free_result() его повторно не читают. |
Возврат. Literal true; после вызова result непригоден.
Отказ и диагностика. Неверный/уже закрытый объект вызывает Error; повторный free не является безопасной идемпотентной операцией.
- код закончил/прервал чтение
- free сообщает драйверу освободить statement/result
- память/курсор становятся доступными
- соединение можно использовать дальше
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, 'SELECT 1 AS id');
$row = odbc_fetch_array($result);
echo $row['id'], "\n";
echo odbc_free_result($result) ? "freed\n" : "not-freed\n";
try { odbc_fetch_array($result); } catch (Error) { echo "unusable\n"; }
odbc_close($connection);
Ожидаемый результат
1
freed
unusable
После free тот же Odbc\Result закрыт и больше не читается. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, 'SELECT generate_series(1, 100) AS id');
odbc_fetch_row($result);
echo "first=", odbc_result($result, 1), "\n";
odbc_free_result($result);
echo "released-early\n";
odbc_close($connection);
Ожидаемый результат
first=1
released-early
Если остальные строки не нужны, явное освобождение снижает время владения клиентским курсором/буфером. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Не читать result после free.
- Free result не делает commit/rollback.
- Не путать освобождение результата и закрытие connection.
Когда выбрать другое. Конец запроса освободит ресурс автоматически, но ранний free полезен для больших/ненужных наборов и долгоживущего процесса.
Связанные операции: odbc_close(), odbc_exec(), odbc_prepare().
odbc_num_rowsВозвращает число строк, затронутых DML, либо доступное драйверу число строк result. Для SELECT поддержка/момент подсчёта различаются.
odbc_num_rows(Odbc\Result $statement): intВозвращает число строк, затронутых DML, либо доступное драйверу число строк result. Для SELECT поддержка/момент подсчёта различаются.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_num_rows(Odbc\Result $statement): int
| Параметр | Что передать |
|---|---|
Odbc\Result $statement | Объект Odbc\Result: результат запроса или подготовленная команда. После odbc_free_result() его повторно не читают. |
Возврат. int; -1 часто означает, что драйвер не знает число заранее.
Отказ и диагностика. Не трактуйте любое 0 как ошибку и любое -1 как пустой SELECT. Семантика зависит от команды/драйвера.
- SQL выполняется
- драйвер получает affected-row count
- num_rows запрашивает его
- код интерпретирует 0/-1 по типу команды
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_num_rows');
try {
uodbcExec($connection, 'CREATE TABLE phpman_num_rows (id INTEGER PRIMARY KEY, state VARCHAR(20))');
uodbcExec($connection, "INSERT INTO phpman_num_rows VALUES (1, 'new'), (2, 'new')");
$result = uodbcExec($connection, "UPDATE phpman_num_rows SET state='sent' WHERE id=2");
echo "changed=", odbc_num_rows($result), "\n";
} finally {
uodbcDrop($connection, 'phpman_num_rows');
odbc_close($connection);
}
Ожидаемый результат
changed=1
Для DML число затронутых строк помогает проверить ожидаемый эффект. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_num_rows_delete');
try {
uodbcExec($connection, 'CREATE TABLE phpman_num_rows_delete (id INTEGER PRIMARY KEY)');
uodbcExec($connection, 'INSERT INTO phpman_num_rows_delete VALUES (1)');
$result = uodbcExec($connection, 'DELETE FROM phpman_num_rows_delete WHERE id=99');
echo "deleted=", odbc_num_rows($result), "\n";
} finally {
uodbcDrop($connection, 'phpman_num_rows_delete');
odbc_close($connection);
}
Ожидаемый результат
deleted=0
Ноль — корректный результат «строка не найдена», а не автоматически ошибка. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- SELECT count может быть неизвестен до fetch.
- UPDATE одинаковым значением может считаться по-разному драйверами.
- Для существования строки надёжнее SELECT/RETURNING по возможностям СУБД.
Когда выбрать другое. Явный SELECT COUNT нужен только когда действительно требуется count; не считайте весь большой результат ради пагинации без необходимости.
Связанные операции: odbc_exec(), odbc_fetch_row().
odbc_num_fieldsВозвращает число колонок в result — ширину одной строки результата.
odbc_num_fields(Odbc\Result $statement): intВозвращает число колонок в result — ширину одной строки результата.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_num_fields(Odbc\Result $statement): int
| Параметр | Что передать |
|---|---|
Odbc\Result $statement | Объект Odbc\Result: результат запроса или подготовленная команда. После odbc_free_result() его повторно не читают. |
Возврат. int; поля затем нумеруются от 1 до этого значения.
Отказ и диагностика. Неверный result вызывает Error/TypeError. Ноль возможен для команды без набора колонок и не равен числу затронутых строк.
- SQL формирует список SELECT
- драйвер описывает metadata
- num_fields считает descriptor columns
- код обходит позиции 1..n
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, "SELECT 1 AS id, 'Pen' AS name, 120 AS price");
echo "fields=", odbc_num_fields($result), "\n";
odbc_close($connection);
Ожидаемый результат
fields=3
Число колонок доступно до чтения строк и помогает построить диагностический экспорт. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, 'SELECT COUNT(*) AS total FROM pg_catalog.pg_class');
echo odbc_num_fields($result), "\n";
odbc_close($connection);
Ожидаемый результат
1
Количество исходных строк не связано с числом колонок агрегатного result. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Нумерация field API начинается с 1.
- SELECT * меняет ширину при эволюции схемы.
- Не путайте fields и rows.
Когда выбрать другое. Для известного application query перечисляйте колонки явно; dynamic metadata нужна экспортёрам/админ-инструментам.
Связанные операции: odbc_field_name(), odbc_field_type(), odbc_fetch_into().
odbc_field_nameВозвращает имя/alias колонки result по позиции.
odbc_field_name(Odbc\Result $statement, int $field): string|falseВозвращает имя/alias колонки result по позиции.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_field_name(Odbc\Result $statement, int $field): string|false
| Параметр | Что передать |
|---|---|
Odbc\Result $statement | Объект Odbc\Result: результат запроса или подготовленная команда. После odbc_free_result() его повторно не читают. |
int $field | Номер столбца с 1 либо его имя. В ODBC позиции полей начинаются с 1. |
Возврат. string либо false для несуществующего поля.
Отказ и диагностика. false для позиции вне диапазона; не преобразуйте его молча в пустой заголовок.
- num_fields задаёт диапазон
- позиция начинается с 1
- драйвер возвращает descriptor name
- код сопоставляет имя со своей схемой
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, "SELECT 1 AS product_id, 'Pen' AS product_name");
for ($field = 1; $field <= odbc_num_fields($result); $field++) {
echo $field, ':', odbc_field_name($result, $field), "\n";
}
odbc_close($connection);
Ожидаемый результат
1:product_id
2:product_name
SQL aliases становятся понятными заголовками результата. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, "SELECT 'INV-1' AS invoice_number, 500 AS total_kopecks");
$headers = [];
for ($field = 1; $field <= odbc_num_fields($result); $field++) {
$headers[] = odbc_field_name($result, $field);
}
echo implode(',', $headers), "\n";
odbc_close($connection);
Ожидаемый результат
invoice_number,total_kopecks
Техническое имя не всегда подходит человеку: публичные подписи лучше брать из собственной карты перевода. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Регистр/усечение могут зависеть от драйвера.
- Дубликаты имён требуют SQL aliases.
- Имя БД не заменяет локализованную подпись UI.
Когда выбрать другое. Явная application schema стабильнее динамического metadata для публичного API.
Связанные операции: odbc_num_fields(), odbc_field_num(), odbc_fetch_array().
odbc_field_typeВозвращает имя типа колонки, сообщённое ODBC-драйвером.
odbc_field_type(Odbc\Result $statement, int $field): string|falseВозвращает имя типа колонки, сообщённое ODBC-драйвером.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_field_type(Odbc\Result $statement, int $field): string|false
| Параметр | Что передать |
|---|---|
Odbc\Result $statement | Объект Odbc\Result: результат запроса или подготовленная команда. После odbc_free_result() его повторно не читают. |
int $field | Номер столбца с 1 либо его имя. В ODBC позиции полей начинаются с 1. |
Возврат. string либо false для неверной позиции.
Отказ и диагностика. false для отсутствующего поля. Текст типа не стандартизирован как единое имя между всеми драйверами.
- result descriptor содержит SQL type
- драйвер даёт текстовое имя
- приложение нормализует семейство
- экспорт/диагностика выбирает обработчик
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, "SELECT CAST(12 AS INTEGER) AS id, CAST('abc' AS VARCHAR(20)) AS label, CAST(12.34 AS NUMERIC(8,2)) AS amount");
for ($field = 1; $field <= 3; $field++) { echo odbc_field_type($result, $field), "\n"; }
odbc_close($connection);
Ожидаемый результат
int4
varchar
numeric
Имена int4/varchar/numeric — представление psqlODBC; другой драйвер может назвать тип иначе. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, "SELECT CAST(12.34 AS NUMERIC(8,2)) AS amount");
$type = strtolower((string) odbc_field_type($result, 1));
$kind = str_contains($type, 'numeric') || str_contains($type, 'decimal') ? 'number' : 'text';
echo "kind={$kind}\n";
odbc_close($connection);
Ожидаемый результат
kind=number
Для кросс-драйверного кода нужна карта семейств и fallback, а не один жёсткий vendor-name. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Не ветвитесь только по PostgreSQL int4.
- Тип metadata не валидирует уже полученную строку.
- Дата/decimal всё равно могут прийти как PHP string.
Когда выбрать другое. Собственная схема запроса и явное преобразование надёжнее динамического определения для бизнес-кода.
Связанные операции: odbc_gettypeinfo(), odbc_field_len(), odbc_field_scale().
odbc_field_lenВозвращает объявленную длину/размер колонки из descriptor result, а не длину текущего значения.
odbc_field_len(Odbc\Result $statement, int $field): int|falseВозвращает объявленную длину/размер колонки из descriptor result, а не длину текущего значения.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_field_len(Odbc\Result $statement, int $field): int|false
| Параметр | Что передать |
|---|---|
Odbc\Result $statement | Объект Odbc\Result: результат запроса или подготовленная команда. После odbc_free_result() его повторно не читают. |
int $field | Номер столбца с 1 либо его имя. В ODBC позиции полей начинаются с 1. |
Возврат. int либо false для неверного поля.
Отказ и диагностика. false для позиции вне диапазона. Единицы и смысл для binary/text/numeric зависят от SQL-типа и драйвера.
- драйвер описывает column size
- field_len читает descriptor
- код отличает capacity от actual value
- UI/экспорт применяет собственные ограничения
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, "SELECT CAST(7 AS INTEGER) AS id, CAST('abc' AS VARCHAR(20)) AS label");
echo "id=", odbc_field_len($result, 1), "\n";
echo "label=", odbc_field_len($result, 2), "\n";
odbc_close($connection);
Ожидаемый результат
id=10
label=20
Для psqlODBC INTEGER сообщает display/precision 10, VARCHAR(20) — 20. Это descriptor, не strlen текущего значения. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, "SELECT CAST('abc' AS VARCHAR(20)) AS label");
$row = odbc_fetch_array($result);
echo "declared=", odbc_field_len($result, 1), " actual=", strlen($row['label']), "\n";
odbc_close($connection);
Ожидаемый результат
declared=20 actual=3
Поле допускает до 20 единиц по договору драйвера, но конкретное значение содержит три байта. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Не используйте вместо strlen/mb_strlen.
- Не стройте HTML maxLength слепо из DB metadata.
- Длина UTF-8 может измеряться не как число видимых символов.
Когда выбрать другое. Валидация формы использует собственный бизнес-лимит; metadata полезна универсальному инспектору/экспортёру.
Связанные операции: odbc_field_precision(), odbc_field_scale(), odbc_field_type().
odbc_field_precisionИсторический псевдоним odbc_field_len(). Для NUMERIC значение читают как precision, для текста — как column size по драйверу.
odbc_field_precision(Odbc\Result $statement, int $field): int|falseИсторический псевдоним odbc_field_len(). Для NUMERIC значение читают как precision, для текста — как column size по драйверу.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_field_precision(Odbc\Result $statement, int $field): int|false
| Параметр | Что передать |
|---|---|
Odbc\Result $statement | Объект Odbc\Result: результат запроса или подготовленная команда. После odbc_free_result() его повторно не читают. |
int $field | Номер столбца с 1 либо его имя. В ODBC позиции полей начинаются с 1. |
Возврат. int либо false; реализация — alias odbc_field_len().
Отказ и диагностика. false для неверного номера поля. Название precision не гарантирует numeric-тип.
- позиция выбирает descriptor
- alias вызывает field_len implementation
- драйвер возвращает column size
- код трактует его по SQL-типу
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, 'SELECT CAST(1234.56 AS NUMERIC(8,2)) AS amount');
echo "precision=", odbc_field_precision($result, 1), "\n";
odbc_close($connection);
Ожидаемый результат
precision=8
Precision 8 — общее число десятичных цифр, не число знаков после точки. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, "SELECT CAST('abc' AS VARCHAR(20)) AS label");
$a = odbc_field_precision($result, 1);
$b = odbc_field_len($result, 1);
echo $a === $b ? "same=20\n" : "different\n";
odbc_close($connection);
Ожидаемый результат
same=20
В php-src odbc_field_precision — alias odbc_field_len; имя precision не делает отдельного вычисления. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Сначала проверьте field_type.
- Не вычитайте scale без проверки смыслов драйвера.
- Для текста это не фактическая длина значения.
Когда выбрать другое. Используйте odbc_field_len как каноническое имя alias; явная схема приложения лучше для бизнес-валидации.
Связанные операции: odbc_field_len(), odbc_field_scale(), odbc_field_type().
odbc_field_scaleВозвращает scale колонки — обычно число цифр дробной части для DECIMAL/NUMERIC.
odbc_field_scale(Odbc\Result $statement, int $field): int|falseВозвращает scale колонки — обычно число цифр дробной части для DECIMAL/NUMERIC.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_field_scale(Odbc\Result $statement, int $field): int|false
| Параметр | Что передать |
|---|---|
Odbc\Result $statement | Объект Odbc\Result: результат запроса или подготовленная команда. После odbc_free_result() его повторно не читают. |
int $field | Номер столбца с 1 либо его имя. В ODBC позиции полей начинаются с 1. |
Возврат. int либо false для неверного поля.
Отказ и диагностика. false надо отличать строго от scale=0.
- descriptor хранит decimal digits
- field_scale читает значение
- 0 сохраняется как валидный int
- форматтер выбирает нужное число знаков
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, 'SELECT CAST(12.34 AS NUMERIC(8,2)) AS amount');
echo "scale=", odbc_field_scale($result, 1), "\n";
odbc_close($connection);
Ожидаемый результат
scale=2
NUMERIC(8,2) разрешает две десятичные цифры справа от разделителя. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, 'SELECT CAST(7 AS INTEGER) AS qty, CAST(7.50 AS NUMERIC(8,2)) AS price');
echo odbc_field_scale($result, 1), ':', odbc_field_scale($result, 2), "\n";
odbc_close($connection);
Ожидаемый результат
0:2
Ноль у INTEGER — нормальный scale, не ошибка. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Проверяйте === false, а не if (!$scale).
- Metadata scale не округляет PHP-значение.
- Деньги лучше хранить NUMERIC/целыми минимальными единицами по договору.
Когда выбрать другое. NumberFormatter/явный формат доменной модели отвечает за отображение, metadata только описывает SQL-колонку.
Связанные операции: odbc_field_precision(), odbc_field_type().
odbc_field_numНаходит 1-based позицию колонки по имени в конкретном result.
odbc_field_num(Odbc\Result $statement, string $field): int|falseНаходит 1-based позицию колонки по имени в конкретном result.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_field_num(Odbc\Result $statement, string $field): int|false
| Параметр | Что передать |
|---|---|
Odbc\Result $statement | Объект Odbc\Result: результат запроса или подготовленная команда. После odbc_free_result() его повторно не читают. |
string $field | Номер столбца с 1 либо его имя. В ODBC позиции полей начинаются с 1. |
Возврат. int позиции или false, если имя не найдено.
Отказ и диагностика. false означает отсутствие имени; регистр и правила сопоставления зависят от драйвера.
- result имеет список имён
- field_num ищет имя
- возвращает позицию с 1
- код использует её в result/metadata API
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, "SELECT 1 AS id, 'Pen' AS name, 100 AS price");
echo "name-field=", odbc_field_num($result, 'name'), "\n";
odbc_close($connection);
Ожидаемый результат
name-field=2
Позиция ODBC начинается с 1. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, 'SELECT 1 AS id');
$position = odbc_field_num($result, 'external_code');
echo $position === false ? "column-missing\n" : "column={$position}\n";
odbc_close($connection);
Ожидаемый результат
column-missing
false — сигнал несовпадения ожидаемой схемы; не подменяйте его позицией 0, которой в ODBC field API нет. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Не превращайте false в 0.
- SQL alias делает ожидаемое имя явным.
- Дубликаты имён неоднозначны.
Когда выбрать другое. fetch_array по явным aliases часто устраняет необходимость искать позиции вручную.
Связанные операции: odbc_field_name(), odbc_result(), odbc_num_fields().
odbc_autocommitЧитает или переключает автоматическую фиксацию. false начинает явную транзакцию, чтобы несколько SQL-команд стали одной единицей работы.
odbc_autocommit(Odbc\Connection $odbc, ?bool $enable = null): int|boolЧитает или переключает автоматическую фиксацию. false начинает явную транзакцию, чтобы несколько SQL-команд стали одной единицей работы.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_autocommit(Odbc\Connection $odbc, ?bool $enable = null): int|bool
| Параметр | Что передать |
|---|---|
Odbc\Connection $odbc | Объект Odbc\Connection, который вернул odbc_connect() или odbc_pconnect(). Он привязан к одному драйверу и одной сессии базы. |
?bool $enable (по умолчанию NULL) | true включает autocommit, false выключает; null читает текущее состояние. |
Возврат. При enable=null возвращает ненулевое значение для on, 0 для off либо false при ошибке. При enable=true/false возвращает bool успеха.
Отказ и диагностика. false при чтении неоднозначен с состоянием off, поэтому различайте строго: getter может вернуть int 0 или false. После неудачного переключения прочитайте SQLSTATE.
- прочитать исходный режим
- false переводит соединение в транзакцию
- SQL-команды накапливаются
- commit/rollback завершает работу, true возвращает autocommit
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
echo "before=", odbc_autocommit($connection) ? 'on' : 'off', "\n";
odbc_autocommit($connection, false);
echo "inside=", odbc_autocommit($connection) ? 'on' : 'off', "\n";
odbc_rollback($connection);
odbc_autocommit($connection, true);
echo "after=", odbc_autocommit($connection) ? 'on' : 'off', "\n";
odbc_close($connection);
Ожидаемый результат
before=on
inside=off
after=on
null/отсутствующий enable читает состояние; false начинает явную транзакцию; после rollback режим возвращён для следующего кода. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_autocommit_order');
uodbcExec($connection, 'CREATE TABLE phpman_autocommit_order (id INTEGER PRIMARY KEY, state VARCHAR(20))');
odbc_autocommit($connection, false);
try {
uodbcExec($connection, "INSERT INTO phpman_autocommit_order VALUES (1, 'new')");
uodbcExec($connection, "UPDATE phpman_autocommit_order SET state='paid' WHERE id=1");
odbc_commit($connection);
$row = uodbcExec($connection, 'SELECT state FROM phpman_autocommit_order WHERE id=1');
echo odbc_result($row, 'state'), "\n";
} finally {
if (!odbc_autocommit($connection)) { odbc_rollback($connection); }
odbc_autocommit($connection, true);
uodbcDrop($connection, 'phpman_autocommit_order');
odbc_close($connection);
}
Ожидаемый результат
paid
Отключение autocommit объединяет INSERT и UPDATE. finally возвращает состояние соединения и удаляет только учебную таблицу. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Не оставляйте off на persistent-соединении.
- Внешний HTTP-вызов/sleep внутри транзакции удерживает блокировки.
- Не все DDL/драйверы одинаково участвуют в транзакциях.
Когда выбрать другое. Для одиночной независимой записи autocommit проще; транзакция нужна при общем инварианте нескольких изменений.
Связанные операции: odbc_commit(), odbc_rollback(), odbc_close().
odbc_commitФиксирует все ожидающие изменения текущего ODBC-соединения. Практический смысл — сделать видимым целиком уже проверенный заказ, платёж или импорт.
odbc_commit(Odbc\Connection $odbc): boolФиксирует все ожидающие изменения текущего ODBC-соединения. Практический смысл — сделать видимым целиком уже проверенный заказ, платёж или импорт.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_commit(Odbc\Connection $odbc): bool
| Параметр | Что передать |
|---|---|
Odbc\Connection $odbc | Объект Odbc\Connection, который вернул odbc_connect() или odbc_pconnect(). Он привязан к одному драйверу и одной сессии базы. |
Возврат. true при подтверждённой фиксации, false при отказе драйвера/СУБД.
Отказ и диагностика. false нельзя игнорировать: итог может быть не зафиксирован. Запишите SQLSTATE, выполните rollback, верните безопасную ошибку; повтор допустим только для классифицированного временного отказа и идемпотентной операции.
- autocommit выключен
- несколько команд выполняют одну задачу
- код проверяет каждый шаг
- odbc_commit просит сервер зафиксировать транзакцию
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_commit_order');
uodbcExec($connection, 'CREATE TABLE phpman_commit_order (id INTEGER PRIMARY KEY, total INTEGER)');
odbc_autocommit($connection, false);
try {
uodbcExec($connection, 'INSERT INTO phpman_commit_order VALUES (10, 2500)');
echo odbc_commit($connection) ? "committed\n" : "commit-failed\n";
$row = uodbcExec($connection, 'SELECT total FROM phpman_commit_order WHERE id=10');
echo "total=", odbc_result($row, 'total'), "\n";
} finally {
odbc_autocommit($connection, true);
uodbcDrop($connection, 'phpman_commit_order');
odbc_close($connection);
}
Ожидаемый результат
committed
total=2500
Возврат true фиксирует pending-изменения текущего соединения; контрольный SELECT показывает сохранённое состояние. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_commit_event');
uodbcDrop($connection, 'phpman_commit_invoice');
uodbcExec($connection, 'CREATE TABLE phpman_commit_invoice (id INTEGER PRIMARY KEY)');
uodbcExec($connection, 'CREATE TABLE phpman_commit_event (invoice_id INTEGER, message VARCHAR(30))');
odbc_autocommit($connection, false);
try {
uodbcExec($connection, 'INSERT INTO phpman_commit_invoice VALUES (7)');
uodbcExec($connection, "INSERT INTO phpman_commit_event VALUES (7, 'created')");
if (!odbc_commit($connection)) { throw new RuntimeException(odbc_errormsg($connection)); }
$row = uodbcExec($connection, 'SELECT (SELECT COUNT(*) FROM phpman_commit_invoice) + (SELECT COUNT(*) FROM phpman_commit_event) AS total');
echo "rows=", odbc_result($row, 'total'), "\n";
} finally {
odbc_autocommit($connection, true);
uodbcDrop($connection, 'phpman_commit_event');
uodbcDrop($connection, 'phpman_commit_invoice');
odbc_close($connection);
}
Ожидаемый результат
rows=2
Две таблицы меняются одной транзакцией; commit расположен только после успешного выполнения обоих шагов. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Commit не проверяет бизнес-инварианты за приложение.
- Команды другого соединения в эту транзакцию не входят.
- После commit всё равно верните autocommit в ожидаемый режим.
Когда выбрать другое. Одна SQL-команда в autocommit уже атомарна на поддерживающей СУБД; явная транзакция нужна для нескольких связанных команд.
Связанные операции: odbc_autocommit(), odbc_rollback(), odbc_error().
odbc_rollbackОтменяет ожидающие изменения текущей транзакции. Это управляемый выход, когда один из связанных шагов заказа/импорта не выполнился.
odbc_rollback(Odbc\Connection $odbc): boolОтменяет ожидающие изменения текущей транзакции. Это управляемый выход, когда один из связанных шагов заказа/импорта не выполнился.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_rollback(Odbc\Connection $odbc): bool
| Параметр | Что передать |
|---|---|
Odbc\Connection $odbc | Объект Odbc\Connection, который вернул odbc_connect() или odbc_pconnect(). Он привязан к одному драйверу и одной сессии базы. |
Возврат. true при успешном откате, false при отказе.
Отказ и диагностика. false означает, что состояние соединения нельзя считать восстановленным. Его изолируют/закрывают после завершения транзакции и передают ошибку выше.
- autocommit выключен
- команды меняют данные внутри транзакции
- проверка/зависимость сообщает отказ
- odbc_rollback возвращает согласованное состояние
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_rollback_order');
uodbcExec($connection, 'CREATE TABLE phpman_rollback_order (id INTEGER PRIMARY KEY)');
odbc_autocommit($connection, false);
try {
uodbcExec($connection, 'INSERT INTO phpman_rollback_order VALUES (1)');
echo odbc_rollback($connection) ? "rolled-back\n" : "rollback-failed\n";
$row = uodbcExec($connection, 'SELECT COUNT(*) AS total FROM phpman_rollback_order');
echo "rows=", odbc_result($row, 'total'), "\n";
} finally {
odbc_autocommit($connection, true);
uodbcDrop($connection, 'phpman_rollback_order');
odbc_close($connection);
}
Ожидаемый результат
rolled-back
rows=0
Проверка числа строк подтверждает, что INSERT не вышел за границу транзакции. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_rollback_stock');
uodbcExec($connection, 'CREATE TABLE phpman_rollback_stock (id INTEGER PRIMARY KEY, qty INTEGER)');
uodbcExec($connection, 'INSERT INTO phpman_rollback_stock VALUES (1, 5)');
odbc_autocommit($connection, false);
try {
uodbcExec($connection, 'UPDATE phpman_rollback_stock SET qty=qty-2 WHERE id=1');
odbc_rollback($connection);
$row = uodbcExec($connection, 'SELECT qty FROM phpman_rollback_stock WHERE id=1');
echo "qty=", odbc_result($row, 'qty'), "\n";
} finally {
odbc_autocommit($connection, true);
uodbcDrop($connection, 'phpman_rollback_stock');
odbc_close($connection);
}
Ожидаемый результат
qty=5
Rollback возвращает состояние до начала транзакции, если СУБД и таблица поддерживают транзакции. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Rollback не отменяет уже выполненный commit.
- Файлы, письма и HTTP-вызовы вне БД он не возвращает.
- Поддержка DDL-транзакций различается у СУБД.
Когда выбрать другое. Savepoint через SQL позволяет откатить часть большой транзакции, но его синтаксис/поддержка относятся к конкретной СУБД.
Связанные операции: odbc_autocommit(), odbc_commit(), odbc_errormsg().
odbc_errorВозвращает SQLSTATE последней ODBC-ошибки: короткий машинно-читаемый код для классификации причины.
odbc_error(?Odbc\Connection $odbc = null): stringВозвращает SQLSTATE последней ODBC-ошибки: короткий машинно-читаемый код для классификации причины.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_error(?Odbc\Connection $odbc = null): string
| Параметр | Что передать |
|---|---|
?Odbc\Connection $odbc (по умолчанию NULL) | Объект Odbc\Connection, который вернул odbc_connect() или odbc_pconnect(). Он привязан к одному драйверу и одной сессии базы. |
Возврат. Строка SQLSTATE либо пустая строка, если подходящей последней ошибки нет. Официальное описание говорит о six-digit state, но практические SQLSTATE обычно пятисимвольные; ориентируйтесь на фактический драйвер.
Отказ и диагностика. Пустая строка не означает, что любой предыдущий бизнес-шаг успешен; функция имеет смысл непосредственно после ODBC-отказа. Без connection читается последнее состояние любого соединения процесса.
- ODBC-вызов возвращает false
- драйвер сохраняет diagnostic record
- odbc_error читает state немедленно
- код выбирает безопасную реакцию по классу ошибки
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = @odbc_exec($connection, 'SELECT * FROM phpman_missing_table');
if ($result === false) {
echo odbc_error($connection), "\n";
}
odbc_close($connection);
Ожидаемый результат
42P01
42P01 — PostgreSQL SQLSTATE undefined_table. Другой драйвер может вернуть другой конкретный код, но класс 42 относится к синтаксису/доступу к объектам. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
echo odbc_error($connection) === '' ? "no-error\n" : "has-error\n";
$ok = uodbcExec($connection, 'SELECT 1 AS ok');
echo odbc_result($ok, 'ok'), "\n";
odbc_close($connection);
Ожидаемый результат
no-error
1
Диагностика meaningful сразу после failed ODBC-call; на свежем соединении строка пуста. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Не показывайте только код пользователю без понятного сообщения.
- Не сравнивайте всё сообщение драйвера; классифицируйте SQLSTATE.
- Глобальный вызов без connection может взять ошибку другого соединения.
Когда выбрать другое. Исключение-обёртка приложения может сохранить SQLSTATE, безопасный operation id и исходное Throwable, не раскрывая секреты.
Связанные операции: odbc_errormsg(), odbc_exec(), odbc_execute().
odbc_errormsgВозвращает текст последней ODBC-ошибки для диагностики драйвера, сети или SQL.
odbc_errormsg(?Odbc\Connection $odbc = null): stringВозвращает текст последней ODBC-ошибки для диагностики драйвера, сети или SQL.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_errormsg(?Odbc\Connection $odbc = null): string
| Параметр | Что передать |
|---|---|
?Odbc\Connection $odbc (по умолчанию NULL) | Объект Odbc\Connection, который вернул odbc_connect() или odbc_pconnect(). Он привязан к одному драйверу и одной сессии базы. |
Возврат. Строка сообщения либо пустая строка. Формулировка и язык зависят от Driver Manager, драйвера и СУБД.
Отказ и диагностика. Пустая строка возможна без последней ошибки; старое сообщение может стать нерелевантным после следующих вызовов. Снимайте state/message сразу в локальные переменные.
- ODBC-вызов возвращает false
- драйвер создаёт diagnostic text
- код читает сообщение сразу
- закрытый лог связывает его с operation id
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = @odbc_exec($connection, 'SELECT * FROM phpman_missing_message_table');
if ($result === false) {
$message = odbc_errormsg($connection);
echo str_contains($message, 'phpman_missing_message_table') ? "message-has-object\n" : "message-received\n";
}
odbc_close($connection);
Ожидаемый результат
message-has-object
Сообщение полезно разработчику и может содержать имя объекта/SQL; его пишут в закрытый лог, а не отдают посетителю целиком. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
echo odbc_errormsg($connection) === '' ? "empty\n" : "unexpected\n";
odbc_close($connection);
Ожидаемый результат
empty
На новом соединении без failed-вызова сообщение пусто; это не самостоятельная проверка доступности базы. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Сообщение нестабильно для ветвления кода.
- Оно может раскрыть SQL, пути, хост и схему.
- Не логируйте пароль и полный набор пользовательских данных рядом с ним.
Когда выбрать другое. Для клиентского ответа используйте собственный безопасный код; исходное сообщение остаётся в журнале с ограниченным доступом.
Связанные операции: odbc_error(), odbc_exec(), odbc_execute().
odbc_setoptionМеняет низкоуровневую ODBC-настройку конкретного соединения или statement. Это аварийный/интеграционный инструмент для известного драйвера, а не переносимая настройка по умолчанию.
odbc_setoption(Odbc\Connection|Odbc\Result $odbc, int $which, int $option, int $value): boolМеняет низкоуровневую ODBC-настройку конкретного соединения или statement. Это аварийный/интеграционный инструмент для известного драйвера, а не переносимая настройка по умолчанию.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_setoption(Odbc\Connection|Odbc\Result $odbc, int $which, int $option, int $value): bool
| Параметр | Что передать |
|---|---|
Odbc\Connection|Odbc\Result $odbc | Объект Odbc\Connection, который вернул odbc_connect() или odbc_pconnect(). Он привязан к одному драйверу и одной сессии базы. |
int $which | 1 для настройки соединения, 2 для настройки результата — исторический низкоуровневый контракт odbc_setoption(). |
int $option | ODBC-атрибут, например SQL_CURSOR_TYPE; допустимость определяется драйвером. |
int $value | Целое значение выбранного ODBC-атрибута. |
Возврат. true, если драйвер принял настройку, иначе false.
Отказ и диагностика. false означает неподдерживаемый атрибут/значение или отказ драйвера. Некоторые параметры надо задать до connect/prepare и этой функцией уже не изменить.
- документация драйвера задаёт option/value
- which выбирает connection или statement API
- Driver Manager передаёт настройку
- код проверяет поддержку и фактическое поведение
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
if (!odbc_setoption($connection, 1, 102, 0)) {
throw new RuntimeException(odbc_errormsg($connection));
}
echo odbc_autocommit($connection) ? "on\n" : "off\n";
odbc_rollback($connection);
odbc_setoption($connection, 1, 102, 1);
echo odbc_autocommit($connection) ? "on\n" : "off\n";
odbc_close($connection);
Ожидаемый результат
off
on
which=1 вызывает SQLSetConnectOption; option 102 — SQL_AUTOCOMMIT. Для обычного кода понятнее odbc_autocommit(). Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$statement = odbc_prepare($connection, 'SELECT CAST(? AS INTEGER) AS id');
if ($statement === false) { throw new RuntimeException(odbc_errormsg($connection)); }
echo odbc_setoption($statement, 2, 0, 30) ? "timeout-set\n" : "timeout-unsupported\n";
if (!odbc_execute($statement, [9])) { throw new RuntimeException(odbc_errormsg($connection)); }
$row = odbc_fetch_array($statement);
echo "id=", $row['id'], "\n";
odbc_close($connection);
Ожидаемый результат
timeout-set
id=9
which=2 вызывает SQLSetStmtOption; option 0 задаёт SQL_QUERY_TIMEOUT в секундах, если драйвер поддерживает его для уже созданного statement. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Числа option не самодокументируются; дайте именованный wrapper и ссылку на спецификацию.
- Эффект различается по версиям драйвера.
- Состояние persistent-соединения нужно вернуть.
Когда выбрать другое. Используйте специализированную PHP-функцию вроде odbc_autocommit() или параметр DSN/драйвера, если он существует и понятнее.
Связанные операции: odbc_autocommit(), odbc_prepare(), odbc_execute().
odbc_binmodeЗадаёт, как один result преобразует SQL-типы BINARY/VARBINARY/LONGVARBINARY: выводит напрямую, возвращает байты или превращает каждый байт в два hex-символа.
odbc_binmode(Odbc\Result $statement, int $mode): trueЗадаёт, как один result преобразует SQL-типы BINARY/VARBINARY/LONGVARBINARY: выводит напрямую, возвращает байты или превращает каждый байт в два hex-символа.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_binmode(Odbc\Result $statement, int $mode): true
| Параметр | Что передать |
|---|---|
Odbc\Result $statement | Объект Odbc\Result: результат запроса или подготовленная команда. После odbc_free_result() его повторно не читают. |
int $mode | Режим обработки двоичных данных: ODBC_BINMODE_PASSTHRU, ODBC_BINMODE_RETURN или ODBC_BINMODE_CONVERT. |
Возврат. Всегда true при корректном вызове; реальный формат значения определяется mode, longreadlen и драйвером.
Отказ и диагностика. Сигнатура возвращает literal true; неверный объект/тип режима приводит к TypeError/ошибке. Успех установки не доказывает, что драйвер классифицировал колонку ожидаемым SQL-типом.
- запрос возвращает бинарный столбец
- binmode задаётся до чтения
- для LONGVARBINARY учитывается longreadlen
- fetch/result получает выбранное представление
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
foreach ([ODBC_BINMODE_RETURN, ODBC_BINMODE_CONVERT] as $mode) {
$result = uodbcExec($connection, "SELECT decode('0001ff', 'hex') AS payload");
odbc_longreadlen($result, 100);
odbc_binmode($result, $mode);
$row = odbc_fetch_array($result);
echo $mode === ODBC_BINMODE_RETURN ? 'raw=' : 'hex-text=';
echo bin2hex((string) $row['payload']), "\n";
}
odbc_close($connection);
Ожидаемый результат
raw=0001ff
hex-text=303030316666
RETURN отдаёт три исходных байта; CONVERT отдаёт шесть ASCII-символов 0001ff, поэтому bin2hex этой строки показывает их коды. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, "SELECT decode('4142', 'hex') AS payload");
odbc_longreadlen($result, 10);
odbc_binmode($result, ODBC_BINMODE_PASSTHRU);
$row = odbc_fetch_array($result);
echo "array-value-length=", strlen((string) $row['payload']), "\n";
odbc_close($connection);
Ожидаемый результат
array-value-length=0
Для fetch_into/fetch_array официальный контракт passthru означает пустую строку; при odbc_result() данные отправились бы прямо в output, что опасно для JSON/HTML-ответа. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- PASSTHRU пишет байты в вывод и может повредить HTML/JSON.
- CONVERT удваивает размер и возвращает текст hex, а не исходные байты.
- Для LONGVARBINARY отдельно задайте longreadlen.
Когда выбрать другое. Для файлов часто удобнее отдельное объектное/файловое хранилище; нативный драйвер СУБД может дать предсказуемее LOB-stream API.
Связанные операции: odbc_longreadlen(), odbc_fetch_array(), odbc_result().
odbc_longreadlenЗадаёт для одного result максимальное число байт LONG/LONGVARCHAR/LONGVARBINARY, возвращаемых в PHP.
odbc_longreadlen(Odbc\Result $statement, int $length): trueЗадаёт для одного result максимальное число байт LONG/LONGVARCHAR/LONGVARBINARY, возвращаемых в PHP.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_longreadlen(Odbc\Result $statement, int $length): true
| Параметр | Что передать |
|---|---|
Odbc\Result $statement | Объект Odbc\Result: результат запроса или подготовленная команда. После odbc_free_result() его повторно не читают. |
int $length | Предельное число байт LONG-значения, читаемое для этого результата; 0 включает потоковый passthru-режим. |
Возврат. Всегда true при корректном вызове. length=0 включает passthru при odbc_result(); положительное значение ограничивает возвращаемые байты.
Отказ и диагностика. Функция сообщает literal true; слишком малый предел проявляется усечёнными данными, а не false. Проверяйте длину/целостность на уровне приложения.
- запрос создаёт result
- до fetch задаётся byte limit
- драйвер читает LONG-значение
- PHP получает не больше limit либо passthru-вывод
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, "SELECT CAST(repeat('A', 10) AS text) AS body");
odbc_longreadlen($result, 4);
$row = odbc_fetch_array($result);
echo strlen($row['body']), ':', $row['body'], "\n";
odbc_close($connection);
Ожидаемый результат
4:AAAA
Предел измеряется байтами. Для UTF-8 он может оборвать последовательность посередине, поэтому размер выбирают по договору данных, а не по числу букв. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = uodbcExec($connection, "SELECT CAST(repeat('B', 10) AS text) AS body");
odbc_longreadlen($result, 20);
$row = odbc_fetch_array($result);
echo strlen($row['body']), ':', $row['body'], "\n";
odbc_close($connection);
Ожидаемый результат
10:BBBBBBBBBB
Лимит 20 больше результата, поэтому пришли все десять байт. Для реального неизвестного размера это всё равно буферная граница, а не потоковая гарантия. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Длина в байтах, не Unicode-символах.
- 0 с odbc_result() отправляет данные прямо в output.
- Большой лимит может увеличить память каждого запроса.
Когда выбрать другое. Потоковый LOB API нативного драйвера подходит большим файлам лучше; для обычного VARCHAR эта настройка обычно не нужна.
Связанные операции: odbc_binmode(), odbc_result(), odbc_fetch_array().
odbc_tablesВозвращает catalog-описание таблиц, представлений и других поддерживаемых объектов. Полезна мастеру настройки и инспектору схемы.
odbc_tables(Odbc\Connection $odbc, ?string $catalog = null, ?string $schema = null, ?string $table = null, ?string $types = null): Odbc\Result|falseВозвращает catalog-описание таблиц, представлений и других поддерживаемых объектов. Полезна мастеру настройки и инспектору схемы.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_tables(Odbc\Connection $odbc, ?string $catalog = null, ?string $schema = null, ?string $table = null, ?string $types = null): Odbc\Result|false
| Параметр | Что передать |
|---|---|
Odbc\Connection $odbc | Объект Odbc\Connection, который вернул odbc_connect() или odbc_pconnect(). Он привязан к одному драйверу и одной сессии базы. |
?string $catalog (по умолчанию NULL) | Каталог источника данных либо null. Значение и поддержка зависят от СУБД/драйвера. |
?string $schema (по умолчанию NULL) | Схема. Для PostgreSQL в примерах используется public; пустая строка и null имеют драйверно-зависимый смысл. |
?string $table (по умолчанию NULL) | Имя или шаблон таблицы по правилам соответствующей ODBC metadata-функции. |
?string $types (по умолчанию NULL) | Список типов таблиц для odbc_tables(), например TABLE или VIEW, в формате драйвера. |
Возврат. Odbc\Result с metadata-строками либо false.
Отказ и диагностика. false при неподдерживаемом/ошибочном catalog call. Пустой result означает отсутствие совпадений, а не обязательно ошибку.
- передать catalog/schema/name/type filters
- драйвер вызывает SQLTables
- result содержит TABLE_CAT/SCHEM/NAME/TYPE
- код нормализует ключи и проверяет нужный объект
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_tables_product');
try {
uodbcExec($connection, 'CREATE TABLE phpman_tables_product (id INTEGER PRIMARY KEY)');
$result = odbc_tables($connection, null, 'public', 'phpman_tables_product', 'TABLE');
if ($result === false) { throw new RuntimeException(odbc_errormsg($connection)); }
$found = false;
while ($row = odbc_fetch_array($result)) {
$row = array_change_key_case($row, CASE_LOWER);
$found = $found || ($row['table_name'] ?? '') === 'phpman_tables_product';
}
echo $found ? "table-found\n" : "table-missing\n";
} finally {
uodbcDrop($connection, 'phpman_tables_product');
odbc_close($connection);
}
Ожидаемый результат
table-found
Catalog API переносимее запроса к pg_catalog/information_schema, но шаблоны и регистр всё равно зависят от драйвера. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
@odbc_exec($connection, 'DROP VIEW IF EXISTS phpman_tables_view');
try {
uodbcExec($connection, 'CREATE VIEW phpman_tables_view AS SELECT 1 AS id');
$result = odbc_tables($connection, null, 'public', 'phpman_tables_view', 'VIEW');
$row = $result === false ? false : odbc_fetch_array($result);
$row = is_array($row) ? array_change_key_case($row, CASE_LOWER) : [];
echo strtoupper((string) ($row['table_type'] ?? 'missing')), "\n";
} finally {
@odbc_exec($connection, 'DROP VIEW IF EXISTS phpman_tables_view');
odbc_close($connection);
}
Ожидаемый результат
VIEW
Тип объекта нельзя выводить только из имени; metadata возвращает TABLE_TYPE. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- null, пустая строка и % могут иметь разный смысл у драйвера.
- Регистр шаблона важен.
- Не показывайте полную схему неавторизованному пользователю.
Когда выбрать другое. information_schema даёт SQL-запросы, но детали всё равно зависят от СУБД; миграции лучше знают ожидаемую схему заранее.
Связанные операции: odbc_columns(), odbc_primarykeys(), odbc_statistics().
odbc_columnsПеречисляет колонки таблиц и их ODBC metadata: имя, тип, размер, nullable, ordinal position и другие поля драйвера.
odbc_columns(Odbc\Connection $odbc, ?string $catalog = null, ?string $schema = null, ?string $table = null, ?string $column = null): Odbc\Result|falseПеречисляет колонки таблиц и их ODBC metadata: имя, тип, размер, nullable, ordinal position и другие поля драйвера.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_columns(Odbc\Connection $odbc, ?string $catalog = null, ?string $schema = null, ?string $table = null, ?string $column = null): Odbc\Result|false
| Параметр | Что передать |
|---|---|
Odbc\Connection $odbc | Объект Odbc\Connection, который вернул odbc_connect() или odbc_pconnect(). Он привязан к одному драйверу и одной сессии базы. |
?string $catalog (по умолчанию NULL) | Каталог источника данных либо null. Значение и поддержка зависят от СУБД/драйвера. |
?string $schema (по умолчанию NULL) | Схема. Для PostgreSQL в примерах используется public; пустая строка и null имеют драйверно-зависимый смысл. |
?string $table (по умолчанию NULL) | Имя или шаблон таблицы по правилам соответствующей ODBC metadata-функции. |
?string $column (по умолчанию NULL) | Имя или шаблон столбца по правилам metadata-функции. |
Возврат. Odbc\Result либо false.
Отказ и диагностика. false при отказе catalog API; пустой набор при отсутствии совпадений. Набор полей и vendor-дополнения могут различаться.
- фильтры выбирают таблицу/колонку
- драйвер вызывает SQLColumns
- каждая metadata-строка описывает одну колонку
- приложение сравнивает фактическую схему с ожидаемой
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_columns_product');
try {
uodbcExec($connection, 'CREATE TABLE phpman_columns_product (id INTEGER PRIMARY KEY, name VARCHAR(40), price NUMERIC(8,2))');
$result = odbc_columns($connection, null, 'public', 'phpman_columns_product', '%');
$names = [];
while ($row = odbc_fetch_array($result)) {
$row = array_change_key_case($row, CASE_LOWER);
$names[] = $row['column_name'];
}
echo implode(',', $names), "\n";
} finally {
uodbcDrop($connection, 'phpman_columns_product');
odbc_close($connection);
}
Ожидаемый результат
id,name,price
Порядок следует ORDINAL_POSITION драйвера; мастер импорта может сопоставить входные заголовки. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_columns_contract');
try {
uodbcExec($connection, 'CREATE TABLE phpman_columns_contract (external_id VARCHAR(30) NOT NULL, note VARCHAR(100))');
$result = odbc_columns($connection, null, 'public', 'phpman_columns_contract', 'external_id');
$row = odbc_fetch_array($result);
$row = array_change_key_case($row, CASE_LOWER);
echo strtolower($row['type_name']), ':nullable=', $row['nullable'], "\n";
} finally {
uodbcDrop($connection, 'phpman_columns_contract');
odbc_close($connection);
}
Ожидаемый результат
varchar:nullable=0
NOT NULL отражается nullable=0; это описание БД, но входные данные всё равно проверяет приложение до запроса. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Не создавайте пользовательскую форму автоматически без собственного allowlist/подписей.
- Nullable БД не означает optional в бизнес-правилах.
- Ключи result могут иметь другой регистр — нормализуйте.
Когда выбрать другое. Миграционная схема — источник ожидаемого контракта; odbc_columns полезна для проверки внешней/наследуемой базы.
Связанные операции: odbc_tables(), odbc_field_type(), odbc_primarykeys().
odbc_gettypeinfoВозвращает сведения о SQL-типах, которые сообщает источник данных: нативное имя, размер, литералы, nullable/searchable и прочие возможности.
odbc_gettypeinfo(Odbc\Connection $odbc, int $data_type = 0): Odbc\Result|falseВозвращает сведения о SQL-типах, которые сообщает источник данных: нативное имя, размер, литералы, nullable/searchable и прочие возможности.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_gettypeinfo(Odbc\Connection $odbc, int $data_type = 0): Odbc\Result|false
| Параметр | Что передать |
|---|---|
Odbc\Connection $odbc | Объект Odbc\Connection, который вернул odbc_connect() или odbc_pconnect(). Он привязан к одному драйверу и одной сессии базы. |
int $data_type (по умолчанию 0) | SQL_* константа типа; 0 просит сведения обо всех типах. |
Возврат. Odbc\Result либо false. data_type=0 просит все типы.
Отказ и диагностика. false при неподдерживаемом catalog call. Даже успешная строка не гарантирует одинаковый SQL-синтаксис у двух СУБД.
- выбрать SQL_* тип или 0
- драйвер вызывает SQLGetTypeInfo
- каждая строка описывает вариант типа
- генератор/диагностика выбирает совместимый вариант
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = odbc_gettypeinfo($connection, SQL_INTEGER);
if ($result === false) { throw new RuntimeException(odbc_errormsg($connection)); }
$row = odbc_fetch_array($result);
$row = array_change_key_case($row, CASE_LOWER);
echo "type=", strtolower($row['type_name']), " data=", $row['data_type'], "\n";
odbc_close($connection);
Ожидаемый результат
type=int4 data=4
SQL_INTEGER имеет код 4; psqlODBC показывает нативное имя int4. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = odbc_gettypeinfo($connection, SQL_VARCHAR);
$row = $result === false ? false : odbc_fetch_array($result);
$row = is_array($row) ? array_change_key_case($row, CASE_LOWER) : [];
echo "type=", strtolower($row['type_name'] ?? 'missing'), "\n";
echo "data=", $row['data_type'] ?? 'missing', "\n";
echo "precision=", $row['precision'] ?? 'missing', "\n";
odbc_close($connection);
Ожидаемый результат
type=varchar
data=12
precision=255
Универсальный генератор схемы может проверить возможность типа, но реальный лимит и синтаксис CREATE TABLE остаются драйверно-зависимыми. psqlODBC возвращает ODBC2-совместимое имя поля PRECISION вместо COLUMN_SIZE — поэтому потребитель сначала изучает фактические ключи metadata своего драйвера. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Не сравнивайте только TYPE_NAME между драйверами.
- COLUMN_SIZE имеет смысл в контексте типа.
- Не превращайте универсальный тип в обещание полной переносимости SQL.
Когда выбрать другое. Для одного известного backend используйте его официальную типовую систему/миграции; metadata нужна адаптеру к неизвестным источникам.
Связанные операции: odbc_field_type(), odbc_columns().
odbc_primarykeysВозвращает колонки первичного ключа таблицы и их порядок.
odbc_primarykeys(Odbc\Connection $odbc, ?string $catalog, string $schema, string $table): Odbc\Result|falseВозвращает колонки первичного ключа таблицы и их порядок.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_primarykeys(Odbc\Connection $odbc, ?string $catalog, string $schema, string $table): Odbc\Result|false
| Параметр | Что передать |
|---|---|
Odbc\Connection $odbc | Объект Odbc\Connection, который вернул odbc_connect() или odbc_pconnect(). Он привязан к одному драйверу и одной сессии базы. |
?string $catalog | Каталог источника данных либо null. Значение и поддержка зависят от СУБД/драйвера. |
string $schema | Схема. Для PostgreSQL в примерах используется public; пустая строка и null имеют драйверно-зависимый смысл. |
string $table | Имя или шаблон таблицы по правилам соответствующей ODBC metadata-функции. |
Возврат. Odbc\Result либо false.
Отказ и диагностика. false при отказе catalog API; пустой result возможен у таблицы без PK или недостаточной metadata-поддержке.
- указать точные schema/table
- драйвер вызывает SQLPrimaryKeys
- каждая строка даёт COLUMN_NAME/KEY_SEQ/PK_NAME
- код сортирует составной ключ по KEY_SEQ
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_pk_product');
try {
uodbcExec($connection, 'CREATE TABLE phpman_pk_product (id INTEGER PRIMARY KEY, name VARCHAR(40))');
$result = odbc_primarykeys($connection, null, 'public', 'phpman_pk_product');
$row = odbc_fetch_array($result);
$row = array_change_key_case($row, CASE_LOWER);
echo $row['column_name'], ':seq=', $row['key_seq'], "\n";
} finally {
uodbcDrop($connection, 'phpman_pk_product');
odbc_close($connection);
}
Ожидаемый результат
id:seq=1
COLUMN_NAME и KEY_SEQ дают состав ключа; имя ограничения тоже доступно в PK_NAME. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_pk_line');
try {
uodbcExec($connection, 'CREATE TABLE phpman_pk_line (order_id INTEGER, line_no INTEGER, PRIMARY KEY (order_id, line_no))');
$result = odbc_primarykeys($connection, null, 'public', 'phpman_pk_line');
$columns = [];
while ($row = odbc_fetch_array($result)) {
$row = array_change_key_case($row, CASE_LOWER);
$columns[(int) $row['key_seq']] = $row['column_name'];
}
ksort($columns);
echo implode(',', $columns), "\n";
} finally {
uodbcDrop($connection, 'phpman_pk_line');
odbc_close($connection);
}
Ожидаемый результат
order_id,line_no
Составной ключ — несколько metadata-строк; KEY_SEQ нельзя терять при генерации mapping. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Не предполагавайте один столбец.
- Порядок составного ключа важен.
- Unique index не всегда является primary key.
Когда выбрать другое. Ожидаемый PK хранит миграция; introspection нужна внешней базе/генератору схемы.
Связанные операции: odbc_foreignkeys(), odbc_statistics(), odbc_columns().
odbc_foreignkeysОписывает внешние ключи между PK- и FK-таблицами: пары колонок, порядок, правила update/delete и имена ограничений.
odbc_foreignkeys(Odbc\Connection $odbc, ?string $pk_catalog, string $pk_schema, string $pk_table, string $fk_catalog, string $fk_schema, string $fk_table): Odbc\Result|falseОписывает внешние ключи между PK- и FK-таблицами: пары колонок, порядок, правила update/delete и имена ограничений.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_foreignkeys(Odbc\Connection $odbc, ?string $pk_catalog, string $pk_schema, string $pk_table, string $fk_catalog, string $fk_schema, string $fk_table): Odbc\Result|false
| Параметр | Что передать |
|---|---|
Odbc\Connection $odbc | Объект Odbc\Connection, который вернул odbc_connect() или odbc_pconnect(). Он привязан к одному драйверу и одной сессии базы. |
?string $pk_catalog | Каталог таблицы с первичным ключом либо null. |
string $pk_schema | Схема таблицы с первичным ключом. |
string $pk_table | Таблица, на которую ссылается внешний ключ. |
string $fk_catalog | Каталог таблицы с внешним ключом либо пустая строка согласно текущей сигнатуре. |
string $fk_schema | Схема таблицы с внешним ключом. |
string $fk_table | Таблица, содержащая внешний ключ. |
Возврат. Odbc\Result либо false.
Отказ и диагностика. false при отказе; пустой набор при отсутствии/невидимости связи. Catalog-аргументы несимметричны в текущей сигнатуре — следуйте ей буквально.
- указать PK и FK стороны
- драйвер вызывает SQLForeignKeys
- строки связывают PKCOLUMN_NAME/FKCOLUMN_NAME
- код группирует составную связь и переводит rule codes
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_fk_line');
uodbcDrop($connection, 'phpman_fk_order');
try {
uodbcExec($connection, 'CREATE TABLE phpman_fk_order (id INTEGER PRIMARY KEY)');
uodbcExec($connection, 'CREATE TABLE phpman_fk_line (id INTEGER PRIMARY KEY, order_id INTEGER REFERENCES phpman_fk_order(id))');
$result = odbc_foreignkeys($connection, null, 'public', 'phpman_fk_order', '', 'public', 'phpman_fk_line');
$row = odbc_fetch_array($result);
$row = array_change_key_case($row, CASE_LOWER);
echo $row['fkcolumn_name'], '->', $row['pkcolumn_name'], "\n";
} finally {
uodbcDrop($connection, 'phpman_fk_line');
uodbcDrop($connection, 'phpman_fk_order');
odbc_close($connection);
}
Ожидаемый результат
order_id->id
Metadata показывает направление FK→PK, а не загружает связанные данные. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_fk_child');
uodbcDrop($connection, 'phpman_fk_parent');
try {
uodbcExec($connection, 'CREATE TABLE phpman_fk_parent (id INTEGER PRIMARY KEY)');
uodbcExec($connection, 'CREATE TABLE phpman_fk_child (id INTEGER PRIMARY KEY, parent_id INTEGER REFERENCES phpman_fk_parent(id) ON DELETE CASCADE)');
$result = odbc_foreignkeys($connection, null, 'public', 'phpman_fk_parent', '', 'public', 'phpman_fk_child');
$row = array_change_key_case(odbc_fetch_array($result), CASE_LOWER);
echo "delete-rule=", $row['delete_rule'], "\n";
} finally {
uodbcDrop($connection, 'phpman_fk_child');
uodbcDrop($connection, 'phpman_fk_parent');
odbc_close($connection);
}
Ожидаемый результат
delete-rule=0
ODBC SQL_CASCADE имеет код 0. В UI лучше переводить числовой код через явную карту, не показывать как самодостаточный смысл. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Не путайте направление PK/FK.
- Составная связь имеет несколько строк и KEY_SEQ.
- Rule codes требуют карты ODBC.
Когда выбрать другое. information_schema/referential_constraints даёт SQL-представление конкретной СУБД; migrations — ожидаемый контракт.
Связанные операции: odbc_primarykeys(), odbc_columns().
odbc_proceduresПеречисляет процедуры/функции, видимые через ODBC catalog, с типом и описанием.
odbc_procedures(Odbc\Connection $odbc, ?string $catalog = null, ?string $schema = null, ?string $procedure = null): Odbc\Result|falseПеречисляет процедуры/функции, видимые через ODBC catalog, с типом и описанием.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_procedures(Odbc\Connection $odbc, ?string $catalog = null, ?string $schema = null, ?string $procedure = null): Odbc\Result|false
| Параметр | Что передать |
|---|---|
Odbc\Connection $odbc | Объект Odbc\Connection, который вернул odbc_connect() или odbc_pconnect(). Он привязан к одному драйверу и одной сессии базы. |
?string $catalog (по умолчанию NULL) | Каталог источника данных либо null. Значение и поддержка зависят от СУБД/драйвера. |
?string $schema (по умолчанию NULL) | Схема. Для PostgreSQL в примерах используется public; пустая строка и null имеют драйверно-зависимый смысл. |
?string $procedure (по умолчанию NULL) | Имя или шаблон процедуры/функции; видимость зависит от каталога драйвера. |
Возврат. Odbc\Result либо false.
Отказ и диагностика. false — отказ catalog call; пустой result — нет совпадений. Определение function/procedure различается по СУБД.
- задать catalog/schema/name pattern
- драйвер вызывает SQLProcedures
- каждая строка описывает callable
- инструмент показывает только разрешённые/поддерживаемые элементы
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
@odbc_exec($connection, 'DROP FUNCTION IF EXISTS phpman_proc_add(integer)');
try {
uodbcExec($connection, 'CREATE FUNCTION phpman_proc_add(integer) RETURNS integer LANGUAGE sql IMMUTABLE AS $$ SELECT $1 + 1 $$');
$result = odbc_procedures($connection, null, 'public', 'phpman_proc_add');
$found = false;
while ($row = odbc_fetch_array($result)) {
$row = array_change_key_case($row, CASE_LOWER);
$found = $found || str_contains((string) ($row['procedure_name'] ?? ''), 'phpman_proc_add');
}
echo $found ? "procedure-found\n" : "procedure-missing\n";
} finally {
@odbc_exec($connection, 'DROP FUNCTION IF EXISTS phpman_proc_add(integer)');
odbc_close($connection);
}
Ожидаемый результат
procedure-found
ODBC называет catalog entry procedure даже там, где PostgreSQL различает function/procedure. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
$result = odbc_procedures($connection, null, 'public', 'phpman_proc_does_not_exist');
$count = 0;
while ($result !== false && odbc_fetch_array($result)) { $count++; }
echo "matches={$count}\n";
odbc_close($connection);
Ожидаемый результат
matches=0
Пустой catalog result — нормальный исход поиска, не false-ошибка. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Наличие в каталоге не даёт EXECUTE privilege.
- Overload-версии могут иметь одинаковое имя.
- Не генерируйте публичный RPC автоматически из catalog.
Когда выбрать другое. Явный adapter к известным процедурам безопаснее; нативный драйвер лучше поддерживает OUT/INOUT параметры.
Связанные операции: odbc_procedurecolumns(), odbc_execute().
odbc_procedurecolumnsВозвращает metadata параметров/результатов процедуры или функции: имя, направление, тип, размер, nullable и ordinal.
odbc_procedurecolumns(Odbc\Connection $odbc, ?string $catalog = null, ?string $schema = null, ?string $procedure = null, ?string $column = null): Odbc\Result|falseВозвращает metadata параметров/результатов процедуры или функции: имя, направление, тип, размер, nullable и ordinal.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_procedurecolumns(Odbc\Connection $odbc, ?string $catalog = null, ?string $schema = null, ?string $procedure = null, ?string $column = null): Odbc\Result|false
| Параметр | Что передать |
|---|---|
Odbc\Connection $odbc | Объект Odbc\Connection, который вернул odbc_connect() или odbc_pconnect(). Он привязан к одному драйверу и одной сессии базы. |
?string $catalog (по умолчанию NULL) | Каталог источника данных либо null. Значение и поддержка зависят от СУБД/драйвера. |
?string $schema (по умолчанию NULL) | Схема. Для PostgreSQL в примерах используется public; пустая строка и null имеют драйверно-зависимый смысл. |
?string $procedure (по умолчанию NULL) | Имя или шаблон процедуры/функции; видимость зависит от каталога драйвера. |
?string $column (по умолчанию NULL) | Имя или шаблон столбца по правилам metadata-функции. |
Возврат. Odbc\Result либо false.
Отказ и диагностика. false при отказе; пустой набор может означать неизвестный callable либо неполную поддержку SQLProcedureColumns — сравните с odbc_procedures и известным тестовым объектом.
- выбрать callable
- драйвер вызывает SQLProcedureColumns
- несколько строк описывают return/input/output
- adapter строит явный контракт
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
@odbc_exec($connection, 'DROP FUNCTION IF EXISTS phpman_proc_param(integer)');
try {
uodbcExec($connection, 'CREATE FUNCTION phpman_proc_param(value integer) RETURNS integer LANGUAGE sql IMMUTABLE AS $$ SELECT value * 2 $$');
$result = odbc_procedurecolumns($connection, null, 'public', 'phpman_proc_param', '%');
$count = 0;
while (odbc_fetch_array($result)) { $count++; }
echo "parameter-rows={$count}\n";
echo $count > 0 ? "source=odbc-catalog\n" : "source=explicit-contract\n";
} finally {
@odbc_exec($connection, 'DROP FUNCTION IF EXISTS phpman_proc_param(integer)');
odbc_close($connection);
}
Ожидаемый результат
parameter-rows=0
source=explicit-contract
psqlODBC 18.00 видит созданную функцию через odbc_procedures(), но не выдаёт строки SQLProcedureColumns. Пустой result — проверенная capability-граница, поэтому adapter хранит явный контракт параметров либо читает нативный каталог PostgreSQL. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
@odbc_exec($connection, 'DROP FUNCTION IF EXISTS phpman_proc_pair(integer, integer)');
try {
uodbcExec($connection, 'CREATE FUNCTION phpman_proc_pair(left_value integer, right_value integer) RETURNS integer LANGUAGE sql IMMUTABLE AS $$ SELECT left_value + right_value $$');
$procedures = odbc_procedures($connection, null, 'public', 'phpman_proc_pair');
$procedureFound = false;
while ($procedures !== false && odbc_fetch_array($procedures)) { $procedureFound = true; }
$columns = odbc_procedurecolumns($connection, null, 'public', 'phpman_proc_pair', '%');
$count = 0;
while ($columns !== false && odbc_fetch_array($columns)) { $count++; }
echo "procedure=", $procedureFound ? "yes\n" : "no\n";
echo "parameter-rows={$count}\n";
} finally {
@odbc_exec($connection, 'DROP FUNCTION IF EXISTS phpman_proc_pair(integer, integer)');
odbc_close($connection);
}
Ожидаемый результат
procedure=yes
parameter-rows=0
Callable присутствует в SQLProcedures, однако SQLProcedureColumns остаётся пустым. Такое сравнение отличает «объекта нет» от «драйвер не раскрывает параметры»; при поддержке код дополнительно читает COLUMN_TYPE и ORDINAL_POSITION, а не только count. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Пустой result не доказывает отсутствие параметров.
- COUNT строк не равен числу только входных параметров.
- OUT/INOUT выполнение ext/odbc ограничено.
- Overload требует учёта типов/специфичного имени.
Когда выбрать другое. Явно описанный client adapter и нативный catalog/драйвер надёжнее для процедурных API.
Связанные операции: odbc_procedures(), odbc_prepare(), odbc_execute().
odbc_specialcolumnsЗапрашивает special columns: лучший идентификатор строки (SQL_BEST_ROWID) либо автоматически меняемую row-version (SQL_ROWVER).
odbc_specialcolumns(Odbc\Connection $odbc, int $type, ?string $catalog, string $schema, string $table, int $scope, int $nullable): Odbc\Result|falseЗапрашивает special columns: лучший идентификатор строки (SQL_BEST_ROWID) либо автоматически меняемую row-version (SQL_ROWVER).
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_specialcolumns(Odbc\Connection $odbc, int $type, ?string $catalog, string $schema, string $table, int $scope, int $nullable): Odbc\Result|false
| Параметр | Что передать |
|---|---|
Odbc\Connection $odbc | Объект Odbc\Connection, который вернул odbc_connect() или odbc_pconnect(). Он привязан к одному драйверу и одной сессии базы. |
int $type | SQL_BEST_ROWID или SQL_ROWVER для odbc_specialcolumns(). |
?string $catalog | Каталог источника данных либо null. Значение и поддержка зависят от СУБД/драйвера. |
string $schema | Схема. Для PostgreSQL в примерах используется public; пустая строка и null имеют драйверно-зависимый смысл. |
string $table | Имя или шаблон таблицы по правилам соответствующей ODBC metadata-функции. |
int $scope | SQL_SCOPE_CURROW, SQL_SCOPE_TRANSACTION или SQL_SCOPE_SESSION. |
int $nullable | SQL_NO_NULLS исключает nullable-кандидатов, SQL_NULLABLE разрешает их. |
Возврат. Odbc\Result либо false.
Отказ и диагностика. false при отказе; пустой набор означает, что драйвер не сообщает подходящую special column.
- выбрать type/scope/nullability
- драйвер вызывает SQLSpecialColumns
- строки описывают кандидатные колонки
- optimistic update использует только подтверждённый контракт
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_special_product');
try {
uodbcExec($connection, 'CREATE TABLE phpman_special_product (id INTEGER PRIMARY KEY, name VARCHAR(20))');
$result = odbc_specialcolumns($connection, SQL_BEST_ROWID, null, 'public', 'phpman_special_product', SQL_SCOPE_SESSION, SQL_NO_NULLS);
if ($result === false) { throw new RuntimeException(odbc_errormsg($connection)); }
$found = false;
while ($row = odbc_fetch_array($result)) {
$row = array_change_key_case($row, CASE_LOWER);
$found = $found || ($row['column_name'] ?? '') === 'id';
}
echo $found ? "best=id\n" : "best-not-reported\n";
} finally {
uodbcDrop($connection, 'phpman_special_product');
odbc_close($connection);
}
Ожидаемый результат
best=id
SQL_BEST_ROWID просит ODBC определить набор колонок, уникально идентифицирующий строку в заданном scope. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_special_version');
try {
uodbcExec($connection, 'CREATE TABLE phpman_special_version (id INTEGER PRIMARY KEY, changed_at TIMESTAMP)');
$result = odbc_specialcolumns($connection, SQL_ROWVER, null, 'public', 'phpman_special_version', SQL_SCOPE_SESSION, SQL_NULLABLE);
$row = $result === false ? false : odbc_fetch_array($result);
$row = is_array($row) ? array_change_key_case($row, CASE_LOWER) : [];
echo "rowver=", $row['column_name'] ?? 'none', "\n";
echo "pseudo=", $row['pseudo_column'] ?? 'none', "\n";
} finally {
uodbcDrop($connection, 'phpman_special_version');
odbc_close($connection);
}
Ожидаемый результат
rowver=xmin
pseudo=2
Обычный changed_at не становится rowversion. psqlODBC сообщает системную pseudo-column xmin (PSEUDO_COLUMN=2). Это backend-specific идентификатор версии строки: его используют только после изучения семантики PostgreSQL и не выдают за переносимый timestamp. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- BEST_ROWID не обязательно равен объявленному PK.
- Обычная дата не является rowversion.
- xmin — системная PostgreSQL pseudo-column, а не универсальный счётчик приложения.
- Scope/nullability меняют список.
Когда выбрать другое. Явный PK и version counter/timestamp с проверяемым UPDATE дают понятнее optimistic locking в приложении.
Связанные операции: odbc_primarykeys(), odbc_columns().
odbc_statisticsВозвращает индексную/statistics metadata таблицы: уникальность, имя индекса, колонки, порядок и оценочные показатели.
odbc_statistics(Odbc\Connection $odbc, ?string $catalog, string $schema, string $table, int $unique, int $accuracy): Odbc\Result|falseВозвращает индексную/statistics metadata таблицы: уникальность, имя индекса, колонки, порядок и оценочные показатели.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_statistics(Odbc\Connection $odbc, ?string $catalog, string $schema, string $table, int $unique, int $accuracy): Odbc\Result|false
| Параметр | Что передать |
|---|---|
Odbc\Connection $odbc | Объект Odbc\Connection, который вернул odbc_connect() или odbc_pconnect(). Он привязан к одному драйверу и одной сессии базы. |
?string $catalog | Каталог источника данных либо null. Значение и поддержка зависят от СУБД/драйвера. |
string $schema | Схема. Для PostgreSQL в примерах используется public; пустая строка и null имеют драйверно-зависимый смысл. |
string $table | Имя или шаблон таблицы по правилам соответствующей ODBC metadata-функции. |
int $unique | SQL_INDEX_UNIQUE возвращает только уникальные индексы, SQL_INDEX_ALL — все. |
int $accuracy | SQL_ENSURE просит актуальную статистику, SQL_QUICK допускает приблизительную. |
Возврат. Odbc\Result либо false.
Отказ и диагностика. false при отказе; пустой результат при отсутствии доступной metadata.
- указать table и unique/accuracy
- драйвер вызывает SQLStatistics
- строки описывают индекс/колонки
- инструмент группирует их по INDEX_NAME/ORDINAL_POSITION
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_stats_product');
try {
uodbcExec($connection, 'CREATE TABLE phpman_stats_product (id INTEGER PRIMARY KEY, name VARCHAR(20))');
$result = odbc_statistics($connection, null, 'public', 'phpman_stats_product', SQL_INDEX_ALL, SQL_ENSURE);
$found = false;
while ($row = odbc_fetch_array($result)) {
$row = array_change_key_case($row, CASE_LOWER);
$found = $found || ($row['column_name'] ?? '') === 'id';
}
echo $found ? "id-indexed\n" : "id-not-indexed\n";
} finally {
uodbcDrop($connection, 'phpman_stats_product');
odbc_close($connection);
}
Ожидаемый результат
id-indexed
Metadata показывает наличие индексной записи, но не доказывает, что конкретный запрос выберет этот индекс. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_stats_customer');
try {
uodbcExec($connection, 'CREATE TABLE phpman_stats_customer (id INTEGER PRIMARY KEY, email VARCHAR(80) UNIQUE)');
$result = odbc_statistics($connection, null, 'public', 'phpman_stats_customer', SQL_INDEX_UNIQUE, SQL_QUICK);
$columns = [];
while ($row = odbc_fetch_array($result)) {
$row = array_change_key_case($row, CASE_LOWER);
if (($row['column_name'] ?? '') !== '') { $columns[] = $row['column_name']; }
}
sort($columns);
echo implode(',', array_unique($columns)), "\n";
} finally {
uodbcDrop($connection, 'phpman_stats_customer');
odbc_close($connection);
}
Ожидаемый результат
email,id
UNIQUE email и PRIMARY KEY id оба попадают в фильтр уникальных индексов. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Один индекс занимает несколько строк.
- Наличие индекса не равно плану запроса.
- SQL_QUICK может вернуть приблизительную статистику.
Когда выбрать другое. EXPLAIN конкретной СУБД отвечает, как выполнится запрос; migrations отвечают, какие индексы должны существовать.
Связанные операции: odbc_primarykeys(), odbc_columns().
odbc_tableprivilegesПеречисляет права на таблицу, видимые через ODBC catalog: grantee, privilege и is_grantable.
odbc_tableprivileges(Odbc\Connection $odbc, ?string $catalog, string $schema, string $table): Odbc\Result|falseПеречисляет права на таблицу, видимые через ODBC catalog: grantee, privilege и is_grantable.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_tableprivileges(Odbc\Connection $odbc, ?string $catalog, string $schema, string $table): Odbc\Result|false
| Параметр | Что передать |
|---|---|
Odbc\Connection $odbc | Объект Odbc\Connection, который вернул odbc_connect() или odbc_pconnect(). Он привязан к одному драйверу и одной сессии базы. |
?string $catalog | Каталог источника данных либо null. Значение и поддержка зависят от СУБД/драйвера. |
string $schema | Схема. Для PostgreSQL в примерах используется public; пустая строка и null имеют драйверно-зависимый смысл. |
string $table | Имя или шаблон таблицы по правилам соответствующей ODBC metadata-функции. |
Возврат. Odbc\Result либо false.
Отказ и диагностика. false при отказе; пустой набор может означать отсутствие metadata/прав видимости.
- указать точную таблицу
- драйвер вызывает SQLTablePrivileges
- строки перечисляют grants
- диагностика сравнивает их с ожидаемой ролью
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_priv_table');
try {
uodbcExec($connection, 'CREATE TABLE phpman_priv_table (id INTEGER PRIMARY KEY)');
$result = odbc_tableprivileges($connection, null, 'public', 'phpman_priv_table');
$found = false;
while ($row = odbc_fetch_array($result)) {
$row = array_change_key_case($row, CASE_LOWER);
$found = $found || strtoupper((string) ($row['privilege'] ?? '')) === 'SELECT';
}
echo $found ? "select=yes\n" : "select=no\n";
} finally {
uodbcDrop($connection, 'phpman_priv_table');
odbc_close($connection);
}
Ожидаемый результат
select=yes
Catalog отражает grants, видимые драйверу. Приложение всё равно проверяет свою авторизацию пользователя отдельно. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_priv_grant');
try {
uodbcExec($connection, 'CREATE TABLE phpman_priv_grant (id INTEGER PRIMARY KEY)');
$result = odbc_tableprivileges($connection, null, 'public', 'phpman_priv_grant');
$rows = 0;
$hasField = false;
while ($row = odbc_fetch_array($result)) {
$row = array_change_key_case($row, CASE_LOWER);
$rows++;
$hasField = $hasField || array_key_exists('is_grantable', $row);
}
echo $rows > 0 && $hasField ? "grant-metadata=yes\n" : "grant-metadata=no\n";
} finally {
uodbcDrop($connection, 'phpman_priv_grant');
odbc_close($connection);
}
Ожидаемый результат
grant-metadata=yes
IS_GRANTABLE — metadata администратора, не кнопка для автоматической выдачи прав из веб-интерфейса. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Права БД и авторизация пользователя сайта — разные уровни.
- Не показывайте grants публично.
- Vendor roles/inherited privileges могут отображаться неполно.
Когда выбрать другое. Нативные системные каталоги СУБД дают больше деталей; infrastructure-as-code хранит ожидаемые GRANT отдельно.
Связанные операции: odbc_columnprivileges(), odbc_tables().
odbc_columnprivilegesПеречисляет grants для колонок выбранной таблицы.
odbc_columnprivileges(Odbc\Connection $odbc, ?string $catalog, string $schema, string $table, string $column): Odbc\Result|falseПеречисляет grants для колонок выбранной таблицы.
Как прочитать вызов. Имя до круглых скобок выбирает операцию; аргументы внутри передаются слева направо. Результат можно сохранить справа от =. Объекты Odbc\Connection и Odbc\Result создаёт расширение, а не пользовательский new. Разбор вызова функции; сравнение с PDO.
Сигнатура PHP 8.5.11. odbc_columnprivileges(Odbc\Connection $odbc, ?string $catalog, string $schema, string $table, string $column): Odbc\Result|false
| Параметр | Что передать |
|---|---|
Odbc\Connection $odbc | Объект Odbc\Connection, который вернул odbc_connect() или odbc_pconnect(). Он привязан к одному драйверу и одной сессии базы. |
?string $catalog | Каталог источника данных либо null. Значение и поддержка зависят от СУБД/драйвера. |
string $schema | Схема. Для PostgreSQL в примерах используется public; пустая строка и null имеют драйверно-зависимый смысл. |
string $table | Имя или шаблон таблицы по правилам соответствующей ODBC metadata-функции. |
string $column | Имя или шаблон столбца по правилам metadata-функции. |
Возврат. Odbc\Result либо false.
Отказ и диагностика. false при отказе, пустой набор при отсутствии совпадений/metadata.
- указать catalog/schema/table/column
- драйвер вызывает SQLColumnPrivileges
- каждая строка связывает column/grantee/privilege
- аудит сравнивает с минимально необходимыми правами
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_column_priv');
try {
uodbcExec($connection, 'CREATE TABLE phpman_column_priv (id INTEGER PRIMARY KEY, secret VARCHAR(20))');
$result = odbc_columnprivileges($connection, null, 'public', 'phpman_column_priv', 'secret');
$found = false;
while ($row = odbc_fetch_array($result)) {
$row = array_change_key_case($row, CASE_LOWER);
$found = $found || ($row['column_name'] ?? '') === 'secret';
}
echo $found ? "secret-metadata=yes\n" : "secret-metadata=no\n";
} finally {
uodbcDrop($connection, 'phpman_column_priv');
odbc_close($connection);
}
Ожидаемый результат
secret-metadata=yes
Даже если роль БД может SELECT колонку, приложение не обязано включать её в API-ответ. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
<?php
declare(strict_types=1);
require __DIR__ . '/uodbc-bootstrap.php';
$connection = uodbcConnect();
uodbcDrop($connection, 'phpman_column_priv_missing');
try {
uodbcExec($connection, 'CREATE TABLE phpman_column_priv_missing (id INTEGER PRIMARY KEY)');
$result = odbc_columnprivileges($connection, null, 'public', 'phpman_column_priv_missing', 'unknown_column');
$count = 0;
while ($result !== false && odbc_fetch_array($result)) { $count++; }
echo "matches={$count}\n";
} finally {
uodbcDrop($connection, 'phpman_column_priv_missing');
odbc_close($connection);
}
Ожидаемый результат
matches=0
Пустой набор — нормальный результат фильтра, а false означал бы отказ API. Пример выполнен через PHP 8.5.11/ext/odbc и psqlODBC 18.00 на отдельной локальной учебной базе PostgreSQL 18.6. Реквизиты передаются переменными окружения; рабочие пароли и данные в пример не входят. Таблицы с префиксом phpman_ создаются только для этого запуска и удаляются в finally.
Частые ошибки.
- Не подменяет field-level authorization приложения.
- Inherited/vendor privileges могут отображаться иначе.
- Шаблоны имён/регистр зависят от драйвера.
Когда выбрать другое. Явный SELECT нужных колонок и отдельная policy-модель приложения остаются основной защитой.
Связанные операции: odbc_tableprivileges(), odbc_columns().