Pg field table: примеры (PHP)

Полное руководство по pg_field_table: определение таблиц полей в PostgreSQL
Раздел: Базы данных (PostgreSQL)
pg_field_table(PgSql\Result $result, int $field, bool $oid_only = false): string|int|false

Описание функции pg_field_table

Функция pg_field_table в PHP предназначена для получения имени таблицы, к которой принадлежит указанное поле в результате запроса PostgreSQL. Она помогает определить происхождение столбца, особенно в запросах с объединениями (JOIN), подзапросами или при выборке из представлений.

Функция используется при работе с расширением PostgreSQL (pgsql), когда необходимо программно определить источник данных для поля в наборе результатов. Это может быть полезно для построения динамических запросов, логирования или отладки.

Аргументы функции
  • $result (ресурс) – обязательный. Ресурс результата запроса PostgreSQL, возвращаемый функциями pg_query(), pg_query_params() или pg_execute().
  • $field (int) – обязательный. Порядковый номер поля в результате. Нумерация начинается с 0.
  • $oid_only (bool) – необязательный. По умолчанию false. Если установлено в true, функция возвращает OID (идентификатор объекта) таблицы вместо её имени.

Возвращаемые значения:

  • Имя таблицы (string) – если таблица найдена и параметр $oid_only = false.
  • OID таблицы (int) – если $oid_only = true.
  • false – в случае ошибки (например, неверный номер поля).
  • null – если поле не относится к конкретной таблице (например, результат вычисления или агрегатной функции).

Примеры использования

Пример 1: Получение имени таблицы для поля

Запрос с простым выбором из одной таблицы.

<?php
$conn = pg_connect("host=localhost dbname=test user=postgres");
$result = pg_query($conn, "SELECT id, name FROM products");

// Получаем имя таблицы для поля с индексом 0 (id)
$tableName = pg_field_table($result, 0);
echo "Таблица для поля 'id': ". ($tableName ?: 'не определена');

// Для поля с индексом 1 (name)
$tableName = pg_field_table($result, 1);
echo "\nТаблица для поля 'name': ". ($tableName ?: 'не определена');
pg_free_result($result);
pg_close($conn);
?>
Таблица для поля 'id': products
Таблица для поля 'name': products
Пример 2: Использование с JOIN и OID

Запрос с объединением двух таблиц.

<?php
$conn = pg_connect("host=localhost dbname=test user=postgres");
$result = pg_query($conn, 
    "SELECT p.id, p.name, c.category_name \n    FROM products p \n    JOIN categories c ON p.category_id = c.id"
);

// Имя таблицы для первого поля (p.id)
$tableName = pg_field_table($result, 0);
echo "Таблица для поля 0: ". ($tableName ?: 'не определена');

// OID таблицы для второго поля (p.name)
$oid = pg_field_table($result, 1, true);
echo "\nOID таблицы для поля 1: ". ($oid ?: 'не определён');

// Поле из второй таблицы (c.category_name)
$tableName = pg_field_table($result, 2);
echo "\nТаблица для поля 2: ". ($tableName ?: 'не определена');
pg_free_result($result);
pg_close($conn);
?>
Таблица для поля 0: products
OID таблицы для поля 1: 24576
Таблица для поля 2: categories
Пример 3: Поле без таблицы (вычисляемое)
<?php
$conn = pg_connect("host=localhost dbname=test user=postgres");
$result = pg_query($conn, "SELECT 1+2 as sum, * FROM products LIMIT 1");

$tableName = pg_field_table($result, 0); // Поле 'sum'
echo "Таблица для вычисляемого поля: ". (is_null($tableName) ? 'NULL' : $tableName);

$tableName = pg_field_table($result, 1); // Первое поле из products
echo "\nТаблица для поля из таблицы: ". ($tableName ?: 'не определена');
pg_free_result($result);
pg_close($conn);
?>
Таблица для вычисляемого поля: NULL
Таблица для поля из таблицы: products

Похожие функции в PHP

Возвращает название поля по его индексу в результате. Полезна для получения имени столбца, но не определяет таблицу-источник.

$fieldName = pg_field_name($result, 0); // 'id'

Возвращает тип данных поля по его индексу (например, 'int4', 'varchar'). Не предоставляет информацию о таблице.

$fieldType = pg_field_type($result, 0); // 'int4'

Получает метаинформацию о таблице в виде массива, включая имена и типы полей. Требует имя таблицы и соединение, но не результат запроса.

$meta = pg_meta_data($conn, 'products');
// Возвращает массив с описанием столбцов таблицы

Выбор функции:

  • pg_field_table – когда нужно определить таблицу-источник для конкретного поля в результате запроса, особенно с JOIN.
  • pg_meta_data – для получения полной структуры таблицы без выполнения запроса.
  • pg_field_name/type – для информации о самом поле (имя, тип), но не о его происхождении.

Альтернативы в других языках и СУБД

Python (библиотека psycopg2)

В psycopg2 нет прямой аналогии. Информацию о таблице-источнике можно получить через атрибуты курсора, например, cursor.description, но там нет имени таблицы. Обычно используют запросы к системным каталогам PostgreSQL.

import psycopg2
conn = psycopg2.connect("dbname=test user=postgres")
cursor = conn.cursor()
cursor.execute("SELECT p.id FROM products p")
# Имя таблицы не доступно напрямую
print(cursor.description[0].name)  # 'id'
# Для получения таблицы можно использовать дополнительный запрос:
cursor.execute("""
    SELECT table_name FROM information_schema.columns 
    WHERE table_schema='public' AND column_name='id';
""")
print(cursor.fetchone())
('products',)
JavaScript (библиотека node-postgres)

Аналогично, прямой функции нет. Метаданные о полях доступны в массиве result.fields, но без информации о таблице. Требуется отдельный запрос к системным таблицам.

const { Client } = require('pg');
const client = new Client();
(async () => {
    await client.connect();
    const res = await client.query('SELECT id FROM products');
    console.log(res.fields[0].name); // 'id'
    // Имя таблицы отсутствует
    await client.end();
})();
id
MySQL (PHP функция mysqli_fetch_field_direct)

В MySQL функция mysqli_fetch_field_direct возвращает объект с информацией о поле, включая свойство orgtable – исходную таблицу. Аналог pg_field_table с более прямой интеграцией.

<?php
$mysqli = new mysqli("localhost", "user", "pass", "test");
$result = $mysqli->query("SELECT id FROM products");
$field = $result->fetch_field_direct(0);
echo "Таблица: ". $field->orgtable;
?>
Таблица: products
PostgreSQL (SQL запрос)

Можно получить информацию о происхождении полей через системный каталог pg_attribute и pg_class, но это требует сложных JOIN и знания OID таблиц.

SELECT a.attname, c.relname 
FROM pg_attribute a 
JOIN pg_class c ON a.attrelid = c.oid 
WHERE a.attnum = 1 AND c.relname = 'products';
 attname | relname 
---------+---------
 id      | products

Отличия: PHP функция pg_field_table уникальна своей простотой для PostgreSQL, предоставляя информацию напрямую из результата запроса. В других языках обычно требуются дополнительные запросы к системным таблицам.

Типичные ошибки

Ошибка 1: Неверный индекс поля

Передача индекса за пределами количества полей в результате.

<?php
$conn = pg_connect("host=localhost dbname=test user=postgres");
$result = pg_query($conn, "SELECT id FROM products");
$table = pg_field_table($result, 5); // Неверный индекс
echo "Результат: ". ($table === false ? 'false' : $table);
?>
Результат: false
Ошибка 2: Использование не ресурса результата

Передача переменной, которая не является ресурсом результата PostgreSQL.

<?php
$conn = pg_connect("host=localhost dbname=test user=postgres");
$result = "not a resource";
$table = @pg_field_table($result, 0); // Подавление ошибки для примера
echo "Результат: ". ($table === false ? 'false (ошибка)' : $table);
?>
Результат: false (ошибка)
Ошибка 3: Запрос без конкретной таблицы

Ожидание имени таблицы для вычисляемого поля или поля из подзапроса.

<?php
$conn = pg_connect("host=localhost dbname=test user=postgres");
$result = pg_query($conn, "SELECT COUNT(*) FROM products");
$table = pg_field_table($result, 0);
echo "Таблица для агрегатной функции: ". (is_null($table) ? 'NULL' : $table);
?>
Таблица для агрегатной функции: NULL
Ошибка 4: Использование после закрытия результата

Обращение к функции после освобождения ресурса pg_free_result().

<?php
$conn = pg_connect("host=localhost dbname=test user=postgres");
$result = pg_query($conn, "SELECT id FROM products");
pg_free_result($result);
$table = @pg_field_table($result, 0);
echo "Результат: ". ($table === false ? 'false' : $table);
?>
Результат: false

Изменения в последних версиях PHP

PHP 8.0

В PHP 8.0 функция pg_field_table не претерпела значительных изменений в поведении или синтаксисе. Однако, в связи с общей политикой PHP 8.0 по ужесточению типизации, передача неверных типов аргументов теперь вызывает более строгие ошибки TypeError вместо предупреждений.

Предыдущие версии

В PHP 7.x функция работала стабильно. Важно отметить, что параметр $oid_only был введён давно и доступен с ранних версий PHP 5.x.

Планы на будущее

На момент написания статьи, в актуальных версиях PHP 8.1/8.2 не анонсированы изменения для pg_field_table. Функция остаётся частью стабильного расширения pgsql.

Расширенные примеры

Пример 1: Динамическое построение запросов с проверкой таблицы

Использование функции для безопасного добавления условий в запрос на основе происхождения поля.

Пример php
<?php
$conn = pg_connect("host=localhost dbname=test user=postgres");
// Запрос с JOIN
$result = pg_query($conn, 
    "SELECT p.id, p.name, c.name as category FROM products p \n    LEFT JOIN categories c ON p.category_id = c.id"
);

$fieldIndex = 2; // Допустим, мы хотим проверить поле 'category'
$tableName = pg_field_table($result, $fieldIndex);

if ($tableName === 'categories') {
    echo "Поле принадлежит таблице categories, можно добавить условие WHERE c.name IS NOT NULL";
} elseif ($tableName === 'products') {
    echo "Поле из таблицы products";
} else {
    echo "Таблица не определена";
}
pg_free_result($result);
pg_close($conn);
?>
Поле принадлежит таблице categories, можно добавить условие WHERE c.name IS NOT NULL
Пример 2: Логирование источников данных в больших запросах

Автоматическое определение таблиц для всех полей в результате.

Пример php
<?php
$conn = pg_connect("host=localhost dbname=test user=postgres");
$result = pg_query($conn, 
    "SELECT p.id, p.name, c.name as category, p.price * 1.2 as price_with_vat \n    FROM products p \n    JOIN categories c ON p.category_id = c.id"
);

$fieldCount = pg_num_fields($result);
for ($i = 0; $i < $fieldCount; $i++) {
    $fieldName = pg_field_name($result, $i);
    $tableName = pg_field_table($result, $i);
    echo "Поле: $fieldName | Таблица: ". (is_null($tableName) ? 'Вычисляемое' : $tableName) . "\n";
}
pg_free_result($result);
pg_close($conn);
?>
Поле: id | Таблица: products
Поле: name | Таблица: products
Поле: category | Таблица: categories
Поле: price_with_vat | Таблица: Вычисляемое
Пример 3: Работа с OID для системных операций

Использование OID таблицы для выполнения системных запросов PostgreSQL, например, получение размера таблицы.

Пример php
<?php
$conn = pg_connect("host=localhost dbname=test user=postgres");
$result = pg_query($conn, "SELECT * FROM products LIMIT 1");
$oid = pg_field_table($result, 0, true); // OID таблицы products

if ($oid) {
    $sizeResult = pg_query($conn, "SELECT pg_total_relation_size($oid) as size");
    $size = pg_fetch_result($sizeResult, 0, 'size');
    echo "OID таблицы: $oid, Размер: $size байт";
    pg_free_result($sizeResult);
}
pg_free_result($result);
pg_close($conn);
?>
OID таблицы: 24576, Размер: 8192 байт
Пример 4: Анализ подзапросов и представлений

Определение, происходит ли поле из основной таблицы, представления или подзапроса.

Пример php
<?php
$conn = pg_connect("host=localhost dbname=test user=postgres");
// Создадим простое представление
pg_query($conn, "CREATE OR REPLACE VIEW expensive_products AS SELECT id, name FROM products WHERE price > 1000");

$result = pg_query($conn, "SELECT * FROM expensive_products");
$tableName = pg_field_table($result, 0);
echo "Таблица для поля из представления: ". ($tableName ?: 'не определена');
// Очистка
pg_query($conn, "DROP VIEW expensive_products");
pg_free_result($result);
pg_close($conn);
?>
Таблица для поля из представления: products

Примечание: Функция возвращает имя базовой таблицы, а не представления, так как представление – это виртуальная таблица.

PHP pg_field_table function comments

En
Pg field table Returns the name or oid of the tables field