Как корректно сделать prepare для plsql выражения?

Имеется набор запросов к базе PostgreSQL, которые используют plsql через драйвер QT. Запросы следующего вида

do $$
declare
foo uuid = ?;
begin
    select * from "table_name" where "Id" = foo;
    ...
end;
$$

Запросы выполняются через QSqlQuery::exec. В документации QT написано:

Executes a previously prepared SQL query.

т.е. нужно вызвать QSqlQuery::prepare. Этот метод добавляет в начале запроса строку вида

prepare bar as

Затем знаки "?" заменяются на значения при помощи QSqlQuery::addBindValue.
А exec в свою очередь делает вызов вида:

execute bar ('b95f3f05-a072-4fec-be7b-ab61ec5c6658');

Но в документации PostgreSQL сказано, что prepare не может быть использован с анонимными блоками кода. В связи с этим вопрос: как исправить запросы, использующие plsql таким образом, чтобы осталась возможность программной подстановки значений? Мы не можем уйти от переменных, так как в коде могут встречаться plsql конструкции, изменяющие их значения по ходу выполнения.
Запросов много, так что хотелось бы максимально простое решение. Есть идея написать собственный парсер для подобных запросов, но хотелось бы избежать этого.


Ответы (1 шт):

Автор решения: Majestio

Для Qt правильнее будет выполнить нечто подобное:

// инициализируем соединение в БД в myDataBase
QSqlQuery Query(myDataBase);
Query.prepare("SELECT * FROM users u, logs l WHERE u.usrid=:usrid AND u.usrid=l.usrid AND l.date=:date");
Query.bindValue(":usrid", 1); // <-------- тут вcтавляем искомый Id
Query.bindValue(":date", QDate::currentDate());
Query.exec();
// работаем с результатом

Кстати current_date лучше прямо использовать в запросе самими средствами SQL, а не биндить потом.

Вариант 2:

Вариант с сохранением изначального запроса (не проверял):

// подключение к БД
QSqlQuery query;
query.prepare(R"(
        DO $$
        DECLARE
            foo uuid = :foo;
        BEGIN
            SELECT * FROM "table_name" WHERE "Id" = foo;
            -- Здесь можно добавить дополнительные операции
        END;
        $$)"
);
// Установка значения параметра
query.bindValue(":foo", foo); // foo <--- определяем и инициализируем ранее
// Выполнение запроса
if (!query.exec()) {
  qDebug() << "Ошибка выполнения запроса:"
           << query.lastError().text();
} else {
  qDebug() << "Запрос выполнен успешно.";
}
// обработка запроса и отключение от БД
→ Ссылка