33.2. Управление подключениями к базе данных

В этом разделе описывается, как открывать, закрывать и переключать подключения к базам данных.

33.2.1. Подключение к серверу баз данных

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

EXEC SQL CONNECT TO цель-подключения [AS имя-подключения] [USER имя-пользователя];

Цель может задаваться следующими способами:

  • база_данных[@компьютер][:порт]

  • tcp:postgresql://компьютер[:порт][/база_данных][?параметры]

  • unix:postgresql://компьютер[:порт][/база_данных][?параметры]

  • строковая константа SQL, содержащая одну из вышеприведённых записей

  • ссылка на символьную переменную, содержащую одну из вышеприведённых записей (см. примеры)

  • DEFAULT

Если цель подключения задаётся буквально (то есть не через переменную) и значение не заключается в кавычки, регистр в этой строке не учитывается, как в обычном SQL. В этом случае при необходимости также можно заключить в двойные кавычки отдельные параметры. На практике, чтобы не провоцировать ошибки, лучше заключать строку в апострофы, либо передавать её в переменной. С целью подключения DEFAULT устанавливается подключение к базе данных по умолчанию с именем пользователя по умолчанию. Другое имя пользователя или имя подключения в этом случае указать нельзя.

Также разными способами можно указать имя пользователя:

  • имя_пользователя

  • имя_пользователя/пароль

  • имя_пользователя IDENTIFIED BY пароль

  • имя_пользователя USING пароль

В показанных выше строках имя_пользователя и пароль могут задаваться идентификатором или строковой константой SQL, либо ссылкой на символьную переменную.

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

Вот некоторые примеры оператора CONNECT:

EXEC SQL CONNECT TO mydb@sql.mydomain.com;

EXEC SQL CONNECT TO unix: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;
/* или EXEC SQL CONNECT TO :target USER :user/:passwd; */

В последней форме используется вариант, названный выше ссылкой на символьную переменную. В последующих разделах вы узнаете, как в SQL-операторах можно использовать переменные C, приставляя перед именем двоеточие.

Учтите, что формат цели подключения не описывается в стандарте SQL. Поэтому, если вы хотите разрабатывать переносимые приложения, имеет смысл применить подход, показанный в последнем примере, и сформировать строку подключения отдельно.

33.2.2. Выбор подключения

SQL-операторы в программах со встраиваемым SQL по умолчанию выполняются с текущим подключением, то есть с подключением, которое было открыто последним. Если приложению нужно управлять несколькими подключениями, это можно сделать двумя способами.

Первый вариант — явно выбирать подключение для каждого SQL-оператора, например, так:

EXEC SQL AT имя-подключения SELECT ...;

Этот вариант хорошо подходит для случаев, когда приложению нужно использовать несколько подключений в смешанном порядке.

Если ваше приложение выполняется в нескольких потоках, они не могут использовать подключение одновременно. Поэтому вы должны либо явно управлять доступом (используя мьютексы), либо использовать отдельные подключения для каждого потока. Если для потока выделяется отдельное подключение, вам нужно будет добавить предложение AT и указать в нём подключение этого потока.

Второй вариант — выполнять оператор, переключающий текущее подключение. Этот оператор записывается так:

EXEC SQL SET CONNECTION имя-подключения;

Этот вариант особенно удобен, когда с одним подключением нужно выполнить несколько операторов. Он не является потокобезопасным.

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

#include <stdio.h>

EXEC 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 CONNECT TO testdb2 AS con2 USER testuser;
    EXEC SQL CONNECT TO testdb3 AS con3 USER testuser;

    /* Этот запрос будет выполняться в последней открытой базе данных "testdb3". */
    EXEC SQL SELECT current_database() INTO :dbname;
    printf("current=%s (should be testdb3)\n", dbname);

    /* Добавляется "AT" для запуска запроса в "testdb2" */
    EXEC SQL AT con2 SELECT current_database() INTO :dbname;
    printf("current=%s (should be testdb2)\n", dbname);

    /* Сменить текущее подключение на "testdb1". */
    EXEC SQL SET CONNECTION con1;

    EXEC SQL SELECT current_database() INTO :dbname;
    printf("current=%s (should be testdb1)\n", dbname);

    EXEC SQL DISCONNECT ALL;
    return 0;
}

Этот пример должен вывести следующее:

current=testdb3 (should be testdb3)
current=testdb2 (should be testdb2)
current=testdb1 (should be testdb1)

33.2.3. Закрытие подключения

Чтобы закрыть подключение, примените следующий оператор:

EXEC SQL DISCONNECT [подключение];

Подключение можно задать следующими способами:

  • имя-подключения

  • DEFAULT

  • CURRENT

  • ALL

Если имя подключения не задано, закрывается текущее подключение.

Хорошим стилем считается, когда приложение явно закрывает каждое подключение, которое оно открыло.