Приложение D. Специальные типы данных в pgpro_axe

В pgpro_axe представлено несколько специальных типов данных Postgres Pro. Эти типы не нужно создавать в явном виде, но периодически они могут отображаться в сообщениях об ошибках от Postgres Pro.

duckdb.row #

Тип duckdb.row возвращается такими функциями, как read_parquet, read_csv и scan_iceberg. В зависимости от аргументов эти функции могут возвращать строки с различными столбцами и типами данных. В настоящее время Postgres Pro не полностью поддерживает эти функции, поэтому они возвращают специальный тип. Чтобы получить столбцы этих строк, необходимо использовать синтаксис «square bracket indexing» (индексация квадратных скобок), как если бы вы хотели получить поле:

Пример D.1.

SELECT r['id'], r['name'] FROM read_parquet('file.parquet') r WHERE r['age'] > 21;

При использовании SELECT * столбцы этой строки будут расширены, и результат вашего запроса никогда не будет содержать столбцов с типом данных duckdb.row:

Пример D.2.

SELECT * FROM read_parquet('file.parquet');

Существуют ограничения по использованию функции, которая возвращает duckdb.row в CTE или подзапросе. Основная проблема заключается в том, что pgpro_axe не может автоматически назначать нужные псевдонимы выбранным столбцам строки.

Без CTE или подзапроса такой запрос возвращает столбец r[company] как company:

Пример D.3.

SELECT r['company']
FROM duckdb.query($$ SELECT 'DuckDB Labs' company $$) r;
--    company
-- ─────────────
--  DuckDB Labs

Такой же запрос в подзапросе или CTE возвращает столбец как r:

Пример D.4.

WITH mycte AS (
SELECT r['company']
FROM duckdb.query($$ SELECT 'DuckDB Labs' company $$) r
)
SELECT * FROM mycte;
--       r
-- ─────────────
--  DuckDB Labs

Это можно легко обойти, добавив явный псевдоним столбцу в CTE или подзапросе:

Пример D.5.

WITH mycte AS (
SELECT r['company'] AS company
FROM duckdb.query($$ SELECT 'DuckDB Labs' company $$) r
)
SELECT * FROM mycte;
--    company
-- ─────────────
--  DuckDB Labs

Другим ограничением является то, что если при использовании SELECT * в CTE или подзапросе необходимо указать конкретный столбец вне CTE или подзапроса, вам всё равно потребуется использовать синтаксис r['имя_столбца'] вместо имя_столбца.

Хотя такой запрос работает нормально:

Пример D.6.

WITH mycte AS (
SELECT *
FROM duckdb.query($$ SELECT 'DuckDB Labs' company $$) r
)
SELECT * FROM mycte;
--    company
-- ─────────────
--  DuckDB Labs

При выполнении следующего запроса происходит ошибка:

Пример D.7.

WITH mycte AS (
SELECT *
FROM duckdb.query($$ SELECT 'DuckDB Labs' company $$) r
)
SELECT * FROM mycte WHERE company = 'DuckDB Labs';
-- ERROR:  42703: column "company" does not exist
-- LINE 5: SELECT * FROM mycte WHERE company = 'DuckDB Labs';
--                                   ^
-- Подсказка:  При использовании таких функций DuckDB, как read_parquet, для использования столбцов потребуется синтаксис r['colname']. Если этот синтаксис уже используется, возможно вы забыли назначить функции псевдоним r.

Это можно легко обойти с помощью следующего синтаксиса r['имя_столбца']:

Пример D.8.

> WITH mycte AS (
SELECT *
FROM duckdb.query($$ SELECT 'DuckDB Labs' company $$) r
)
SELECT * FROM mycte WHERE r['company'] = 'DuckDB Labs';
--    company
-- ─────────────
--  DuckDB Labs

duckdb.unresolved_type #

Тип данных duckdb.unresolved_type используется, чтобы позволить Postgres Pro понять выражение, содержащее тип данных, который неизвестен в момент разбора запроса. Это может быть тип любого столбца, извлечённого из duckdb.row с помощью синтаксиса r['имя_столбца']. Многие операторы и агрегатные функции возвращают duckdb.unresolved_type, если одна из сторон оператора имеет тип данных duckdb.unresolved_type, например r['age'] + 10.

При выполнении запроса DuckDB указывается реальный тип данных, поэтому результат запроса никогда не содержит столбцов с типом данных duckdb.unresolved_type.

Вы можете столкнуться с ошибками, в которых сообщается о том, что определённые функции и операции не существуют для типа данных duckdb.unresolved_type:

Пример D.9.

ERROR:  function some_func(duckdb.unresolved_type) does not exist
LINE 6:  some_func(r['somecol']) as somecol

В таких случаях обходное решение — добавить явное преобразование в принимаемый функцией тип данных, например some_func(r['somecol']::text) as somecol.

duckdb.json #

Тип данных duckdb.json используется для аргументов JSON-функций DuckDB. Он позволяет этим функциям принимать значения json, jsonb и duckdb.unresolved_type.