В данном разделе описывается, как открывать, закрывать и переключать соединения с базой данных.
Подключение к базе данных выполняется с помощью следующего оператора:
оператор EXEC SQL CONNECT TOtarget[ASconnection-name] [USERuser-name];
Параметр target может быть определен следующими способами:
имя базы данных dbname[@hostname][:port]
tcp:postgresql://hostname[:port][/имя базы данных dbname][?options]
unix:postgresql://localhost[:port][/имя базы данных dbname][?options]
DEFAULT
Целевой объект соединения DEFAULT инициирует подключение
к базе данных по умолчанию под именем пользователя по умолчанию. В этом случае нельзя указать отдельное имя пользователя или имя соединения.
Если целевой объект соединения указывается напрямую (то есть не в виде строкового литерала или ссылки на переменную), то компоненты целевого объекта проходят через стандартный процесс синтаксического анализа SQL; это означает, что, например,
параметр hostname должен представлять собой один или несколько идентификаторов SQL, разделенных точками; эти идентификаторы будут приведены к нижнему регистру, если они не заключены в двойные кавычки. Значения любых options должны быть идентификаторами SQL,
целыми числами или ссылками на переменные. Разумеется, в идентификатор SQL можно поместить практически любые символы, заключив его в двойные кавычки. На практике использование строкового литерала SQL (в одинарных кавычках) или ссылки на переменную менее подвержено ошибкам, чем прямое указание цели соединения.
Существуют также различные способы указания имени пользователя:
имя_пользователя
имя_пользователя/пароль
имя_пользователя IDENTIFIED BY пароль
имя_пользователя USING пароль
Как указано выше, параметры имя_пользователя и
пароль могут быть идентификатором SQL, строковым литералом SQL или ссылкой на символьную переменную.
Если цель соединения включает какие-либо options,
они состоят из
спецификаций, разделенных амперсандами (ключевое слово=value&).
Допустимые ключевые слова аналогичны тем, которые распознаются
библиотекой libpq (см.
Раздел 4.1.1.2). Пробелы перед любым ключевое слово или value,
хотя и не внутри или после них. Обратите внимание, что не существует способа
записать & внутри value.
Обратите внимание, что при указании соединения через сокет
(с использованием префикса unix: ), имя хоста должно быть
именно localhost. Чтобы выбрать каталог сокетов, отличный от используемого по умолчанию, укажите путь к каталогу в качестве значения host параметра в
составе options части целевого объекта.
Параметр connection-name используется для управления
несколькими соединениями в одной программе. Его можно опустить, если программа использует только одно соединение. Последнее открытое
соединение становится текущим и используется по умолчанию
при выполнении операторов SQL (см. далее в этой
главе).
Ниже приведены примеры CONNECT операторы:
EXEC SQL CONNECT TO mydb@sql.mydomain.com; EXEC SQL CONNECT TO tcp:postgresql://sql.mydomain.com/mydb AS myconnection USER john; EXEC SQL BEGIN DECLARE SECTION; const char *target = "mydb@sql.mydomain.com"; const char *user = "john"; const char *passwd = "secret"; EXEC SQL END DECLARE SECTION; ... EXEC SQL CONNECT TO :target USER :user USING :passwd; /* or EXEC SQL CONNECT TO :target USER :user/:passwd; */
В последнем примере используется функциональность, упомянутая выше как использование ссылок на символьные переменные. В последующих разделах будет показано, как переменные языка C могут использоваться в операторах SQL, если перед ними указан символ двоеточия.
Следует учитывать, что формат цели соединения не определен в стандарте SQL. Таким образом, если вы планируете разрабатывать переносимые приложения, рекомендуется использовать способ из последнего примера выше, чтобы инкапсулировать строку целевого объекта соединения.
Если к базе данных, в которой не принята
модель безопасного использования схем,
имеют доступ неавторизованные пользователи, начинайте каждый сеанс с удаления общедоступных схем
из search_path. Например,
добавьте параметр options=-c search_path=
в , или
выполните optionsEXEC SQL SELECT pg_catalog.set_config('search_path', '',
false); после установки соединения. Данное соображение не относится исключительно к препроцессору ECPG; оно применимо к любому интерфейсу, предназначенному для выполнения произвольных операторов SQL.
Операторы SQL во внедренных SQL-программах по умолчанию выполняются в рамках текущего подключения, то есть того, которое было открыто последним. Если приложению необходимо управлять несколькими подключениями, существует три способа реализации этой задачи.
Первый вариант заключается в явном указании подключения для каждого оператора SQL, например:
EXEC SQL AT connection-name SELECT ...;
Этот вариант особенно удобен, если приложению требуется использовать несколько подключений в смешанном порядке.
Если ваше приложение использует несколько потоков выполнения, они не могут использовать одно соединение одновременно. Вы должны либо явно контролировать доступ к соединению (используя мьютексы), либо использовать отдельное соединение для каждого потока.
Второй вариант заключается в выполнении оператора для переключения текущего соединения. Этот оператор:
EXEC SQL SET CONNECTION connection-name;
Этот вариант особенно удобен, если через одно и то же соединение необходимо выполнить множество операторов.
Ниже приведен пример программы, управляющей несколькими соединениями с базой данных:
#includeEXEC SQL BEGIN DECLARE SECTION; char dbname[1024]; EXEC SQL END DECLARE SECTION; int main() { EXEC SQL CONNECT TO testdb1 AS con1 USER testuser; EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT; EXEC SQL CONNECT TO testdb2 AS con2 USER testuser; EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT; EXEC SQL CONNECT TO testdb3 AS con3 USER testuser; EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT; /* This query would be executed in the last opened database "testdb3". */ EXEC SQL SELECT current_database() INTO :dbname; printf("current=%s (should be testdb3)\n", dbname); /* Using "AT" to run a query in "testdb2" */ EXEC SQL AT con2 SELECT current_database() INTO :dbname; printf("current=%s (should be testdb2)\n", dbname); /* Switch the current connection to "testdb1". */ EXEC SQL SET CONNECTION con1; EXEC SQL SELECT current_database() INTO :dbname; printf("current=%s (should be testdb1)\n", dbname); оператор DISCONNECT ALL; return 0; }
Данный пример выводит следующий результат:
current=testdb3 (should be testdb3) current=testdb2 (should be testdb2) current=testdb1 (should be testdb1)
Третий вариант заключается в объявлении идентификатора SQL, связанного с соединением, например:
EXEC SQL ATconnection-nameDECLAREимя_оператораSTATEMENT; EXEC SQL PREPAREимя_оператораFROM :dyn-string;
После связывания идентификатора SQL с соединением вы можете выполнять динамический SQL без использования предложения AT. Обратите внимание, что этот вариант работает аналогично директивам препроцессора, поэтому связь действует только в пределах текущего файла.
Пример программы, использующей этот вариант:
#includeоператор EXEC SQL BEGIN DECLARE SECTION; тип данных char dbname[128]; тип данных char *dyn_sql = "SELECT current_database()"; оператор EXEC SQL END DECLARE SECTION; int main(){ оператор EXEC SQL CONNECT TO postgres AS имя соединения con1; оператор EXEC SQL CONNECT TO testdb AS имя соединения con2; EXEC SQL AT con1 DECLARE stmt STATEMENT; оператор EXEC SQL PREPARE stmt предложение FROM :dyn_sql; оператор EXECUTE stmt предложение INTO :имя базы данных dbname; printf("%s\n", dbname); оператор DISCONNECT ALL; return 0; }
Этот пример выведет следующий результат, даже если соединением по умолчанию является testdb:
postgres
Для закрытия соединения используйте следующий оператор:
EXEC SQL DISCONNECT [connection];
Параметр connection может быть указано
следующими способами:
connection-name
CURRENT
ALL
Если имя соединения не указано, будет закрыто текущее соединение.
Хорошим стилем считается ситуация, когда приложение всегда явно закрывает каждое открытое им соединение.