Spec-Zone.ru › DuckDB

C++ API

Предупреждение DuckDB's C++ API является внутренним. Он не гарантирует стабильности и может меняться без предварительного уведомления. Если вы хотите создать приложение на DuckDB, мы рекомендуем использовать C API.

Установка

DuckDB C++ API можно установить как часть libduckdb пакетов. Подробности см. на странице установки.

Базовое использование API

DuckDB реализует пользовательский C++ API. Он построен вокруг абстракций экземпляра базы данных (DuckDB класс), нескольких Connection для экземпляра базы данных и экземпляров QueryResult в качестве результата запросов. Заголовочный файл для C++ API — duckdb.hpp.

Инициализация и завершение

Для использования DuckDB необходимо сначала инициализировать экземпляр DuckDB с помощью его конструктора. DuckDB() принимает в качестве параметра файл базы данных для чтения и записи. Специальное значение nullptr можно использовать для создания базы данных в памяти. Обратите внимание, что для базы данных в памяти данные не сохраняются на диск (т. е. все данные будут утеряны при выходе из процесса). Вторым параметром конструктора DuckDB является необъект DBConfig. В DBConfig, вы можете задать различные параметры базы данных, например, режим чтения/записи или ограничения памяти. Конструктор DuckDB может выбрасывать исключения, например, если файл базы данных недоступен.

С помощью экземпляра DuckDB вы можете создать один или несколько экземпляров Connection с помощью конструктора Connection(). Хотя соединения должны быть потокобезопасными, они будут заблокированы во время запроса. Поэтому рекомендуется, чтобы каждый поток использовал собственное соединение, если вы работаете в многопоточной среде.

DuckDB db(nullptr);
Connection con(db);

Запросы

Соединения предоставляют метод Query() для отправки строки SQL-запроса в DuckDB из C++. Query() полностью материализует результат запроса как MaterializedQueryResult в памяти перед возвратом, в этот момент результат запроса можно использовать. Также есть потоковый API для запросов, см. ниже.

// create a table
con.Query("CREATE TABLE integers (i INTEGER, j INTEGER)");

// insert three rows into the table
con.Query("INSERT INTO integers VALUES (3, 4), (5, 6), (7, NULL)");

auto result = con.Query("SELECT * FROM integers");
if (result->HasError()) {
    cerr << result->GetError() << endl;
} else {
    cout << result->ToString() << endl;
}

Экземпляр MaterializedQueryResult содержит, во-первых, два поля, указывающие, был ли запрос выполнен успешно. Query не будет выбрасывать исключений в обычных ситуациях. Вместо этого некорректные запросы или другие проблемы приведут к тому, что поле success булевого типа в экземпляре результата запроса будет установлено в false. В этом случае сообщение об ошибке может быть доступно в error в виде строки. При успешном выполнении устанавливаются другие поля: тип инструкции, которая была только что выполнена (например, StatementType::INSERT_STATEMENT), содержится в statement_type. Логические типы («логический тип»/«тип SQL») столбцов набора результатов содержатся в types. Имена столбцов результата находятся в строковом векторе names. В случае возврата нескольких наборов результатов, например, потому что набор результатов содержал несколько инструкций, набор результатов можно объединить с помощью поля next.

DuckDB также поддерживает подготовленные инструкции в C++ API с помощью метода Prepare(). Это возвращает экземпляр PreparedStatement. Этот экземпляр можно использовать для выполнения подготовленной инструкции с параметрами. Ниже приведен пример:

std::unique_ptr<PreparedStatement> prepare = con.Prepare("SELECT count(*) FROM a WHERE i = $1");
std::unique_ptr<QueryResult> result = prepare->Execute(12);

Предупреждение Не используйте подготовленные инструкции для вставки больших объёмов данных в DuckDB. См. документацию по импорту данных для более эффективных вариантов.

API пользовательских функций

API пользовательских функций позволяет определять пользовательские функции. Он представлен в duckdb:Connection методами: CreateScalarFunction(), CreateVectorizedFunction(), и их вариантами. Эти методы создают пользовательские функции в временной схеме (TEMP_SCHEMA) владельца соединения, которое является единственным, имеющим право использовать и изменять их.

CreateScalarFunction

Пользователь может написать обычную скалярную функцию и вызвать CreateScalarFunction() для регистрации и последующего использования пользовательской функции в инструкции SELECT, например:

bool bigger_than_four(int value) {
    return value > 4;
}

connection.CreateScalarFunction<bool, int>("bigger_than_four", &bigger_than_four);

connection.Query("SELECT bigger_than_four(i) FROM (VALUES(3), (5)) tbl(i)")->Print();

Методы CreateScalarFunction() автоматически создают векторизованные скалярные пользовательские функции, чтобы они были такими же эффективными, как встроенные функции, у нас есть два варианта интерфейса этого метода, как показано ниже:

1.

template<typename TR, typename... Args>
void CreateScalarFunction(string name, TR (*udf_func)(Args…))
  • параметры шаблона:
    • TR — тип возвращаемого значения функции пользовательской функции;
    • Args — аргументы до 3 для функции пользовательской функции (этот метод поддерживает только тернарные функции);
  • name: имя для регистрации функции пользовательской функции;
  • udf_func: указатель на функцию пользовательской функции.

Этот метод автоматически определяет соответствующие типы LogicalTypes по именам шаблонов типов:

  • bool → LogicalType::BOOLEAN
  • int8_t → LogicalType::TINYINT
  • int16_t → LogicalType::SMALLINT
  • int32_t → LogicalType::INTEGER
  • int64_t → LogicalType::BIGINT
  • float → LogicalType::FLOAT
  • double → LogicalType::DOUBLE
  • string_t → LogicalType::VARCHAR

В DuckDB некоторые примитивные типы, например, int32_t, сопоставляются с одним и тем же LogicalType: INTEGER, TIME и DATE, затем для разрешения неоднозначности пользователи могут использовать следующий перегруженный метод.

2.

template<typename TR, typename... Args>
void CreateScalarFunction(string name, vector<LogicalType> args, LogicalType ret_type, TR (*udf_func)(Args…))

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

int32_t udf_date(int32_t a) {
    return a;
}

con.Query("CREATE TABLE dates (d DATE)");
con.Query("INSERT INTO dates VALUES ('1992-01-01')");

con.CreateScalarFunction<int32_t, int32_t>("udf_date", {LogicalType::DATE}, LogicalType::DATE, &udf_date);

con.Query("SELECT udf_date(d) FROM dates")->Print();
  • параметры шаблона:
    • TR — тип возвращаемого значения функции пользовательской функции;
    • Args — аргументы до 3 для функции пользовательской функции (этот метод поддерживает только тернарные функции);
  • name: имя для регистрации функции пользовательской функции;
  • args: аргументы LogicalType, которые использует функция, которые должны соответствовать типам шаблона Args;
  • ret_type: тип LogicalType возврата функции, который должен соответствовать типу шаблона TR;
  • udf_func: указатель на функцию пользовательской функции.

Эта функция проверяет соответствие типов шаблонов переданным типам LogicalTypes, и они должны соответствовать следующим:

  • LogicalTypeId::BOOLEAN → bool
  • LogicalTypeId::TINYINT → int8_t
  • LogicalTypeId::SMALLINT → int16_t
  • LogicalTypeId::DATE, LogicalTypeId::TIME, LogicalTypeId::INTEGER → int32_t
  • LogicalTypeId::BIGINT, LogicalTypeId::TIMESTAMP → int64_t
  • LogicalTypeId::FLOAT, LogicalTypeId::DOUBLE, LogicalTypeId::DECIMAL → double
  • LogicalTypeId::VARCHAR, LogicalTypeId::CHAR, LogicalTypeId::BLOB → string_t
  • LogicalTypeId::VARBINARY → blob_t

CreateVectorizedFunction

Методы CreateVectorizedFunction() регистрируют векторизованную пользовательскую функцию, например:

/*
* This vectorized function copies the input values to the result vector
*/
template<typename TYPE>
static void udf_vectorized(DataChunk &args, ExpressionState &state, Vector &result) {
    // set the result vector type
    result.vector_type = VectorType::FLAT_VECTOR;
    // get a raw array from the result
    auto result_data = FlatVector::GetData<TYPE>(result);

    // get the solely input vector
    auto &input = args.data[0];
    // now get an orrified vector
    VectorData vdata;
    input.Orrify(args.size(), vdata);

    // get a raw array from the orrified input
    auto input_data = (TYPE *)vdata.data;

    // handling the data
    for (idx_t i = 0; i < args.size(); i++) {
        auto idx = vdata.sel->get_index(i);
        if ((*vdata.nullmask)[idx]) {
            continue;
        }
        result_data[i] = input_data[idx];
    }
}

con.Query("CREATE TABLE integers (i INTEGER)");
con.Query("INSERT INTO integers VALUES (1), (2), (3), (999)");

con.CreateVectorizedFunction<int, int>("udf_vectorized_int", &&udf_vectorized<int>);

con.Query("SELECT udf_vectorized_int(i) FROM integers")->Print();

Векторизованная пользовательская функция — это указатель типа scalar_function_t:

typedef std::function<void(DataChunk &args, ExpressionState &expr, Vector &result)> scalar_function_t;
  • args — DataChunk, который содержит набор входных векторов для пользовательской функции, у всех которых одинаковая длина;
  • expr — ExpressionState, предоставляющий информацию о состоянии выражения запроса;
  • result: Vector для хранения значений результата.

Существуют различные типы векторов для обработки в векторизованной пользовательской функции:

  • ConstantVector;
  • DictionaryVector;
  • FlatVector;
  • ListVector;
  • StringVector;
  • StructVector;
  • SequenceVector.

Общий API метода CreateVectorizedFunction() выглядит следующим образом:

1.

template<typename TR, typename... Args>
void CreateVectorizedFunction(string name, scalar_function_t udf_func, LogicalType varargs = LogicalType::INVALID)
  • параметры шаблона:
    • TR — тип возвращаемого значения функции пользовательской функции;
    • Args — аргументы до 3 для функции пользовательской функции.
  • name — имя для регистрации функции пользовательской функции;
  • udf_func — векторизованная функция пользовательской функции;
  • varargs Тип аргументов varargs для поддержки, или LogicalTypeId::INVALID (значение по умолчанию), если функция не принимает аргументы переменной длины.

Этот метод автоматически определяет соответствующие типы LogicalTypes по именам шаблонов типов:

  • bool → LogicalType::BOOLEAN;
  • int8_t → LogicalType::TINYINT;
  • int16_t → LogicalType::SMALLINT
  • int32_t → LogicalType::INTEGER
  • int64_t → LogicalType::BIGINT
  • float → LogicalType::FLOAT
  • double → LogicalType::DOUBLE
  • string_t → LogicalType::VARCHAR

2.

template<typename TR, typename... Args>
void CreateVectorizedFunction(string name, vector<LogicalType> args, LogicalType ret_type, scalar_function_t udf_func, LogicalType varargs = LogicalType::INVALID)

© Copyright 2018–2024 Stichting DuckDB Foundation
Licensed under the MIT License.
https://duckdb.org/docs/api/cpp.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API