33.5. Динамический SQL#
33.5. Динамический SQL #
Во многих случаях конкретные SQL-запросы, которые должно выполнить приложение, известны на момент написания приложения. Однако в некоторых случаях SQL-запросы формируются во время выполнения или предоставляются внешним источником. В таких случаях нельзя вставить SQL-запросы непосредственно в исходный код на языке C, но есть возможность вызвать произвольные SQL-запросы, которые вы предоставляете в виде строки переменной.
33.5.1. Выполнение операторов без получения результирующего набора #
Самый простой способ выполнить произвольный SQL-оператор - использовать команду EXECUTE IMMEDIATE
. Например:
EXEC SQL BEGIN DECLARE SECTION; const char *stmt = "CREATE TABLE test1 (...);"; EXEC SQL END DECLARE SECTION; EXEC SQL EXECUTE IMMEDIATE :stmt;
EXECUTE IMMEDIATE
может использоваться для выполнения SQL-запросов, которые не возвращают набор результатов (например, DDL, INSERT
, UPDATE
, DELETE
). Вы не можете выполнить запросы, которые извлекают данные (например, SELECT
) таким образом. Следующий раздел описывает, как это сделать.
33.5.2. Выполнение оператора с входными параметрами #
Более мощный способ выполнения произвольных SQL-запросов - это подготовить их один раз и выполнять подготовленный запрос столько раз, сколько вам нужно. Также возможно подготовить обобщенную версию запроса и затем выполнять конкретные версии, заменяя параметры. При подготовке запроса, вместо параметров следует написать вопросительные знаки. Например:
EXEC SQL BEGIN DECLARE SECTION; const char *stmt = "INSERT INTO test1 VALUES(?, ?);"; EXEC SQL END DECLARE SECTION; EXEC SQL PREPARE mystmt FROM :stmt; ... EXEC SQL EXECUTE mystmt USING 42, 'foobar';
Когда вам больше не нужен подготовленный запрос, вы должны его деаллоцировать:
EXEC SQL DEALLOCATE PREPARE name
;
33.5.3. Выполнение оператора с набором результатов #
Для выполнения SQL-запроса с одной строкой результата можно использовать команду EXECUTE
. Чтобы сохранить результат, добавьте предложение INTO
.
EXEC SQL BEGIN DECLARE SECTION; const char *stmt = "SELECT a, b, c FROM test1 WHERE a > ?"; int v1, v2; VARCHAR v3[50]; EXEC SQL END DECLARE SECTION; EXEC SQL PREPARE mystmt FROM :stmt; ... EXEC SQL EXECUTE mystmt INTO :v1, :v2, :v3 USING 37;
Команда EXECUTE
может иметь предложение INTO
, предложение USING
, оба предложения или ни одного из них.
Если ожидается, что запрос вернет более одной строки результата, следует использовать курсор, как показано в следующем примере. (См. Раздел 33.3.2 для получения более подробной информации о курсоре).
EXEC SQL BEGIN DECLARE SECTION; char dbaname[128]; char datname[128]; char *stmt = "SELECT u.usename as dbaname, d.datname " " FROM pg_database d, pg_user u " " WHERE d.datdba = u.usesysid"; EXEC SQL END DECLARE SECTION; EXEC SQL CONNECT TO testdb AS con1 USER testuser; EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT; EXEC SQL PREPARE stmt1 FROM :stmt; EXEC SQL DECLARE cursor1 CURSOR FOR stmt1; EXEC SQL OPEN cursor1; EXEC SQL WHENEVER NOT FOUND DO BREAK; while (1) { EXEC SQL FETCH cursor1 INTO :dbaname,:datname; printf("dbaname=%s, datname=%s\n", dbaname, datname); } EXEC SQL CLOSE cursor1; EXEC SQL COMMIT; EXEC SQL DISCONNECT ALL;