Журнал LinuxFormat - перейти на главную

LXF89:PostgreSQL

Материал из Linuxformat
(Различия между версиями)
Перейти к: навигация, поиск
(Открытие и закрытие соединения)
м (восстановление кавычек в коде AWB)
 
(не показаны 2 промежуточные версии 2 участников)
Строка 1: Строка 1:
'''PostgreSQL. ЧАСТЬ 4: Интерфейсы'''
+
{{Цикл/PostgreSQL}}
 +
'''История PostgreSQL''' Изучаем самый мощный из открытых серверов баз данных
  
:В институте им очень дорожили, так как
+
== Интерфейсы ==
:попутно он использовался для некоторых
+
''ЧАСТЬ 4: Интерфейсы, как известно, бывают не только пользовательскими, но и программными. С первыми мы уже успели познакомиться, а сегодня '''Евгений Балдин''' расскажет, какие API существуют для доступа к PostgreSQL из различных языков программирования.''
:уникальных экспериментов и как переводчик
+
:при общении со Змеем Горынычем.
+
::АБС о Кощее Бессмертном
+
  
==libpq==
+
<p align="right">''В институте им очень дорожили, так как<br>попутно он использовался для некоторых<br>уникальных экспериментов и как переводчик<br>при общении со Змеем Горынычем.''<br>'''(О Кощее Бессмертном)'''<br>'''«Понедельник начинается в субботу»'''</p>
Чтобы общаться с базой данных много функций не надо: одна функция для открытия соединения, одна для посылки запроса, одна для получения ответа и одна для закрытия соединения. В реальности всё немного сложнее, но суть остаётся.
+
  
К вопросу о переносимости Библиотека libpq написана на чистом C, поэтому практически везде, где есть gcc, можно организовать связь с PostgreSQL. Мне както пришлось это делать для VAX/VMS всё решилось методом тыка, даже думать почти не потребовалось. Все данные текст, поэтому вопрос бинарной совместимости платформ попросту отсутствует.
+
Понятно, что любую базу данных, в принципе, можно заполнить вручную; правда, некоторые придется заполнять очень долго. СУБД – это просто хранилище, а для заполнения и доступа к хранилищу необходима инфраструктура, и эту инфраструктуру надо создавать. Вот такая она – жизнь.
  
С чего начать Для того чтобы воспользоваться вызовами libpq, необходимо для начала установить её. В Debian (Etch) для этого надо установить пакет postgresql-dev:
+
Родной библиотекой для доступа к ''PostgreSQL'' является ''libpq''. Написана она на чистом C, что тоже не удивительно, так как это основной язык родной системы. Все остальные языки важны, но безусловно, вторичны.
> sudo apt−g e t i n s t a l l p o s t g r e s q l −dev
+
Для доступа к функциям libpq необходимо включить в исходник include-файл:
+
#include "libpq−f e . h"
+
  
Скрипт pg_config (man pg_config) позволяет получить информацию куда помещаются include-файлы, библиотеки и тому подобное:
 
> #сборка программы
 
> g cc −o "бинарник" "исходник" . c −I ‘ pg _ co nf i g −−i n c l u d e d i r ‘ \
 
−l p q ‘ pg _ co nf i g −−l i b s ‘
 
  
===Открытие и закрытие соединения===
+
=== libpq ===
 +
Чтобы общаться с базой данных, много функций не требуется: одна для открытия соединения, одна для посылки запроса, одна для получения ответа и одна для закрытия соединения. В реальности, конечно, все немного сложнее, но суть остается неизменной.
  
Даже открывать соединение с PostgreSQL можно двумя способами:
+
===== К вопросу о переносимости =====
// открыть соединение
+
Библиотека ''libpq'' написана на чистом C, поэтому связь с ''PostgreSQL'' можно организовать практически везде, где можно найти ''gcc''. Мне как-то пришлось делать это для VAX/VMS – все решилось методом тыка, даже думать почти не потребовалось. Все данные – текст, поэтому вопрос бинарной совместимости платформ попросту отсутствует.
PGconn ∗ PQconnectdb ( const char ∗ c o n n i n f o ) ;
+
// то же , но не блокируя программу
+
PGconn ∗ PQconnectStart ( const char ∗ c o n n i n f o ) ;
+
// проверка ст а т уса соединения ( после PQconnectStart )
+
P o s t g r e s P o l l i n g S t a t u s T y p e PQconnectPoll ( PGconn ∗ conn ) ;
+
PQconnectdb обычная функция, где на вход подаём текстовую строку conninfo с параметрами для соединения с сервером, а на выходе получаем структуру типа PGconn с информацией о сделанном соединении и на сколько операция по соединению прошла удачно. В дальнейшем при передача данных эта переменная будет использоваться в качестве параметра.
+
  
Передача информации о серевере в качестве строки (conninfo) позволяет в случае появления дополнительных параметров не менять внешний интерфейс вызова и легко добавлять дополнительные опции. Пример открытия соединения:
+
===== С чего начать =====
const char ∗ c o n n i n f o= "dbname = t est host=lo c alho st " ;
+
Чтобы воспользоваться вызовами ''libpq'', ее необходимо иметь в системе. В Debian (Sarge) для этого надо установить пакет ''PostgreSQL-dev'':
PGconn conn=PQconnectdb ( c o n n i n f o ) ;
+
 
i f ( PQstatus ( conn ) != CONNECTION_OK) {
+
<pre>
  f p r i n t f ( s t d e r r , "Не удалось соединиться с базой данных: %s" ,
+
> sudo apt-get install postgresql-dev
                                PQerrorMessage ( conn ) ) ;
+
</pre>
  /завершаем работу / . . . }
+
 
Параметры передаются в форме ключевое слово = значение. Пары разделяются обычным пробелом. Пробелы вокруг знака равенства можно опустить. Если необходимо передать значение с пробелами, то его необходимо заключить в одинарные кавычки ’ составное значение ’. Для передачи одинарной кавычки её необходимо экранировать с помощью обратной косой черты \. При отсутствии какого-либо параметра в строке conninfo его значение берётся из соответствующей переменной окружения, если такая определена. Если нет, то при открытии соединения используется значение по умолчанию.
+
Для доступа к функциям ''libpq'' необходимо включить в исходный текст соответствующие заголовки:
 +
 
 +
<source lang="c">
 +
#include "libpq-fe.h"
 +
</source>
 +
 
 +
Скрипт ''pg_config'' (''man pg_config'') позволяет получить информацию о том, куда помещаются include-файлы, библиотеки и тому подобное. Для сборки можно также использовать скрипт ''libpq3-config'' (''man libpq3-config'' – годится, естественно, только для ''libpq'' третьей версии), который заведомо есть в Debian (Sarge):
 +
 
 +
<source lang="bash">
 +
> #сборка программы
 +
> gcc -o "бинарник" "исходник".c -I'pg_config --includedir' \
 +
-lpq '/usr/bin/libpq3-config'
 +
> cat /usr/bin/libpq3-config
 +
#!/bin/bash
 +
echo -lssl -lcrypto -lkrb5 -lcrypt -lresolv -lnsl -lpthread
 +
</source>
 +
 
 +
''libpq3-config'' просто выводит список всех библиотек, от которых зависит ''libpq''.
 +
 
 +
 
 +
==== Открытие и закрытие соединения ====
 +
Даже открывать соединение с ''PostgreSQL'' можно двумя способами:
 +
 
 +
<source lang="c">
 +
//открыть соединение
 +
PGconn *PQconnectdb(const char *conninfo);
 +
//то же, но не блокируя программу
 +
PGconn *PQconnectStart(const char *conninfo);
 +
//проверка статуса соединения (после PQconnectStart)
 +
PostgresPollingStatusType PQconnectPoll(PGconn *conn);
 +
</source>
 +
 
 +
'''PQconnectdb''' – обычная функция, принимающая текстовую строку '''conninfo''', содержащую параметры для соединения с сервером, и возвращающая структуру типа '''PGconn''' с информацией о созданном соединении и успешности данной операции. В дальнейшем при передаче данных эта структура будет использоваться в качестве параметра.
 +
 
 +
Передача информации о сервере в качестве строки ('''conninfo''') позволяет не менять внешний интерфейс вызова в случае появления дополнительных параметров и легко добавлять дополнительные опции. Пример открытия соединения:
 +
 
 +
<source lang="c">
 +
const char *conninfo= "dbname = test host=localhost";
 +
PGconn *conn=PQconnectdb(conninfo);
 +
if (PQstatus(conn) != CONNECTION_OK) {
 +
fprintf(stderr, "Не удалось соединиться с базой данных: %s",
 +
PQerrorMessage(conn));
 +
/*завершаем работу*/ }
 +
</source>
 +
 
 +
Параметры передаются в форме '''«ключевое слово»=«значение»'''. Пары разделяются обычным пробелом. Пробелы вокруг знака равенства можно опустить. Если необходимо передать значение с пробелами, то его необходимо заключить в одинарные кавычки ''''«составное» «значение»''''. Для передачи одинарной кавычки ее необходимо экранировать с помощью обратной косой черты '''\''''. При отсутствии какого-либо параметра в строке '''conninfo''' его значение берется из соответствующей переменной окружения, если таковая определена. Если нет, то при открытии соединения используется значение по умолчанию.
  
 
Функции открытия соединения распознают следующие параметры и переменные окружения (кое-какие особенности опущены):
 
Функции открытия соединения распознают следующие параметры и переменные окружения (кое-какие особенности опущены):
* '''host TCP/IP''' имя узла на котором находится сервер PostgreSQL. Соответствует переменной окружения PGHOST. Значение по умолчанию localhost.
+
 
* '''hostaddr''' Числовой адрес узла на котором находится PostgreSQL (альтернатива host). Соответствует переменной окружения PGHOSTADDR. Значение по умолчанию эквивалентно localhost.
+
* '''host''' DNS-имя узла, на котором находится сервер ''PostgreSQL''. Соответствует переменной окружения '''PGHOST'''. Значение по умолчанию: '''localhost'''.
* '''port''' Номер порта, который слушает POSTMASTER. Соответствует переменной окружения PGPORT. Значение по умолчанию обычно 5432.
+
* '''hostaddr''' Числовой адрес узла, на котором находится ''PostgreSQL'' (альтернатива '''host'''). Соответствует переменной окружения '''PGHOSTADDR'''. Значение по умолчанию эквивалентно: '''localhost'''.
* '''dbname''' Имя базы данных. Соответствует переменной окружения PGDATABASE. Значение по умолчанию совпадает с системной учётной записью пользователя.
+
* '''port''' Номер порта, который «слушает» '''POSTMASTER'''. Соответствует переменной окружения '''PGPORT'''. Значение по умолчанию обычно '''5432'''.
* '''user''' Имя пользователя базы данных. Соответствует переменной окружения PGUSER. Значение по умолчанию совпадает с системной учётной записью пользователя.
+
* '''dbname''' Имя базы данных. Соответствует переменной окружения '''PGDATABASE'''. Значение по умолчанию совпадает с системной учетной записью пользователя.
* '''password''' Поле пароля, если для аутентификации требуется пароль. Соответствует переменной окружения PGPASSWORD. Если аутентификация требуется, а поле неопределенно, то для доступа используется информация в файле ~/.pgpass. Переменная окружения PGPASSFILE может указать другой файл для проведения аутентификации.
+
* '''user''' Имя пользователя базы данных. Соответствует переменной окружения '''PGUSER'''. Значение по умолчанию совпадает с системной учетной записью пользователя.
* '''connect_timeout''' Устанавливает максимальное время ожидания соединения в секундах. С сервером и сетью всякое может случиться. Соответствует переменной окружения PGCONNECT_TIMEOUT. Значение по умолчанию равно 0, что означает что время ожидания равно бесконечности. Не рекомендуется устанавливать значение на ожидание меньше 2 секунд.
+
* '''password''' Поле пароля, если для аутентификации требуется пароль. Соответствует переменной окружения '''PGPASSWORD'''. Если аутентификация требуется, а поле не определено, то для доступа используются данные файла '''~/.pgpass'''. Переменная окружения '''PGPASSFILE''' может указать другой файл для проведения аутентификации.
* '''options''' Опции, посылаемые непосредственно серверу, коли такое потребуется. Соответствует переменной окружения PGOPTIONS.
+
* '''connect_timeout''' Устанавливает максимальное время ожидания соединения в секундах. С сервером и сетью всякое может случиться. Соответствует переменной окружения '''PGCONNECT_TIMEOUT'''. Значение по умолчанию равно '''0''', что означает бесконечное время ожидания. Не рекомендуется устанавливать значение ожидания меньше 2 секунд.
 +
* '''options''' Опции, посылаемые непосредственно серверу, если таковые потребуются. Соответствует переменной окружения '''PGOPTIONS'''.
 
* '''sslmode''' Определяет порядок действий при SSL-соединении. Принимает четыре возможных значения:
 
* '''sslmode''' Определяет порядок действий при SSL-соединении. Принимает четыре возможных значения:
** '''disable'''     без шифрации,
+
** '''disable''' без шифрования
** '''allow'''   сначала попробовать соединиться без шифрации, а в случае неудачи постараться установить защищённое соединение,
+
** '''allow''' сначала попробовать соединиться без шифрования, а в случае неудачи постараться установить защищенное соединение,
** '''prefer'''   сначала попробовать установить защищённое соединения, а в случае неудачи повторить соединение без шифрации,
+
** '''prefer''' сначала попробовать установить защищенное соединение, а в случае неудачи повторить соединение без шифрования,
** '''require'''     выполнять только защищённое соединение.  
+
** '''require''' выполнять только защищенное соединение. Соответствует переменной окружения '''PGSSLMODE'''.
  
Соответствует переменной окружения PGSSLMODE. Значение по умолчанию prefer.
+
Значение по умолчанию: '''prefer'''.
* '''krbsrvname''' Имя Kerberos-сервиса. используется для аутентификации с помощью Kerberos-5<ref>
+
* '''krbsrvname''' Имя Kerberos-сервиса. Используется для аутентификации с помощью Kerberos-5<ref>
Kerberos промышленный стандарт для аутентификации и взаимодействия в условиях незащищённого окружения. Алгоритмы Kerberos основаны на шифровании с использованием симметричного криптографического ключа и требует наличие доверенного агента.
+
Kerberos промышленный стандарт для аутентификации и взаимодействия в условиях незащищенного окружения. Алгоритмы Kerberos основаны на шифровании с использованием симметричного криптографического ключа и требуют наличия доверенного агента.
</ref>. Это совершенно отдельная тема для беседы. Соответствует переменной окружения PGKRBSRVNAME.
+
</ref>. Это совершенно отдельная тема, выходящая за рамки данной статьи. Соответствует переменной окружения '''PGKRBSRVNAME'''.
 +
* '''PGDATESTYLE''' Переменная окружения, позволяющая установить представление времени и даты по умолчанию. Соответствует SQL-команде '''SET datestyle TO …'''
 +
* '''PGTZ''' Переменная окружения, позволяющая установить текущий часовой пояс. Соответствует SQL-команде '''SET timezone TO …'''
 +
* '''PGCLIENTENCODING''' Переменная окружения, позволяющая установить кодировку клиента. Соответствует SQL-команде '''SET client_encoding TO …'''
  
PGDATESTYLE      Переменная окружения, позволяющая установить представление времени и даты по умолчанию. Соответствует SQL-команде SET datestyle TO. . .
+
Существует целый класс функций, которые позволяют получить информацию о соединении. За подробностями следует обратиться к документации, но для начала полезно знать о двух из них:
PGTZ            Переменная окружения, позволяющая установить текущий часовой пояс. Соответствует SQL-команде SET timezone TO. . .
+
PGCLIENTENCODING Переменная окружения, позволяющая установить кодировку клиента. Соответствует SQL-команде SET client_encoding TO. . .
+
  
Существует целый класс функций, которые позволяют получить информацию о соединении. Для подробностей следует обратиться к документации. Для начала полезно знать о двух из них:
+
<source lang="c">
ConnStatusType PQstatus ( const PGconn conn ) ;
+
ConnStatusType PQstatus(const PGconn *conn);
char PQerrorMessage ( const PGconn conn ) ;
+
char *PQerrorMessage(const PGconn *conn);
PQstatus возвращает информацию о том, как прошло соединение. Интересны состояния CONNECTION_OK всё хорошо и CONNECTION_BAD ничего не вышло. Функция PQerrorMessage позволяет получить текстовую строку с описанием последней возникшей проблемы.
+
</source>
  
Для того чтобы разорвать соединение используется функция:
+
'''PQstatus''' возвращает информацию о том, как прошло соединение. Интересны состояния '''CONNECTION_OK''' – все хорошо и '''CONNECTION_BAD''' – ничего не вышло. Функция '''PQerrorMessage''' позволяет получить текстовую строку с описанием последней возникшей проблемы.
void P Q f i n i s h ( PGconn ∗ conn ) ;
+
  
ВНИМАНИЕ! Всегда следует закрывать соединения, когда в них отпадает нужда.
+
Для того, чтобы разорвать соединение, используется функция:
  
Число соединений которые поддерживает POSTMASTER ограничено очень легко парализовать работу базы данных только открывая новые соединения.
+
<source lang="c">
 +
void PQfinish(PGconn *conn);
 +
</source>
  
===SQL запросы===
+
'''Внимание!''' Соединения следует закрывать сразу же, как только в них отпадает необходимость. Число соединений, которые поддерживает '''POSTMASTER''', ограничено – очень легко парализовать работу базы данных, просто открывая новые соединения.
Что ж, до сервера уже дозвонились , теперь пора с ним поговорить.  
+
  
'''Посылка запросов''' Простейший способ выполнить SQL-запрос, это воспользоваться функцией PQexec:
 
PG r esul t ∗PQexec ( PGconn ∗ conn , const char ∗command ) ;
 
В качестве параметров передаётся структура соединения conn и строка с SQL-командой command. Возвращается указатель на структуру типа PGresult, где сохраняется информация полученная от СУБД в ответ на запрос. При желании можно в одном запросе отсылать сразу несколько SQL-команд, разделённых точкой с запятой ; , но в этом случае информация сохранённая в структуре PGresult будет относиться только к последнему запросу.
 
  
По умолчанию каждый PQexec считается за отдельную транзакцию, если явно не начать транзакцию с помощью команды BEGIN, которая будет продолжаться либо до COMMIT, либо до ROLLBACK.
+
==== SQL-запросы ====
 +
Что ж, до сервера мы уже «дозвонились», теперь пора с ним «поговорить».
 +
===== Выполнение запросов =====
 +
Простейший способ выполнить ''SQL''-запрос – это воспользоваться функцией '''PQexec''':
  
Есть более сложный вызов PQexecParams, который позволяет передавать вызов и параметры к этому вызову раздельно. Таким образом исчезает необходимость самостоятельно формировать строку SQL-команды и заботиться об экранировании данных, что важно в случае сохранения бинарных последовательностей. В качестве платы из соображения безопасности PQexecParams может послать не более одной команды за раз.
+
<source lang="c">
 +
PGresult *PQexec(PGconn *conn, const char *command);
 +
</source>
  
В некоторых случаях для увеличения скорости выполнения часто встречающихся запросов полезно обратить внимание на парочку PQprepare и PQexecPrepared. Эти команды эквивалентны своим SQL-аналогам PREPARE и EXECUTE. Идея оптимизации состоит в том, что прежде чем выполнить запрос, PostgreSQL сначала анализирует его, затем планирует порядок действий и только потом, собственно, выполняет запрос. Первые два этапа для похожих запросов с разными условиями отбора можно выполнить заранее с помощью команды PREPARE. Затем, с помощью команды EXECUTE, можно выполнять подобные уже подготовленные (prepared)
+
В качестве параметров функции передается структура соединения '''conn''' и строка с ''SQL''-командой ''command''. Возвращается указатель на структуру типа '''PGresult''', где сохраняется информация, полученная от СУБД в ответ на запрос. При желании можно отсылать сразу несколько ''SQL''-команд в одном запросе, разделяя их ''';''' – точкой с запятой. В этом случае информация, сохраненная в структуре '''PGresult''', будет относиться только к последнему запросу.
запросы.
+
  
Все упомянутые выше команды работают с сервером БД синхронным образом, то есть посылают запрос и ждут ответа. Клиентское приложение на это время засыпает (suspended). В libpq предусмотрен целый класс функций предназначенный для асинхронных операций, не блокирующих клиентское приложение. Их применение усложняет код и логику программы, хотя всё в пределах допустимого. С моей точки зрения лучше организовать всё так, чтобы время использованное на ожидание результатов запроса фатально не влияло на внешние процессы и обеспечить бесперебойную работу сети и сервера базы данных.  
+
{{Врезка
 +
|Заголовок=bond, но не Джеймс
 +
|Содержание=
 +
Лень писать все самому, но не лень изучать XML? Тогда ''BOND'' – это программа для Вас. Сайт проекта расположен по адресу: http://www.treshna.com/bond/.
  
'''Информация о состоянии запроса''' После выполнения запроса всегда интересно узнать каково его состояние:
+
Рабочей частью пакета является исполняемый файл '''bondfrontend''', который осуществляет связь с базой данных и может «прикинуться» любой формой. Описание формы хранится в обычном XML-файле. Используемый диалект XML подробно описан в документации.
ExecStatusType P Q r e s u l t S t a t u s ( const PG r esul t ∗ r e s ) ;
+
 
На вход подаётся структура PGresult, создаваемая в результате работы PQexec подобных функций, а на выходе получаем информацию о состоянии в виде числа, значение которого можно сравнить со следующими константами:
+
[[Изображение:Img 89 87 1.jpg|thumb|center|300px|Формочки, XML (правда на заднем фоне и без подсветки) и связь с базой данных — это ''bond''.]]
PGRES_COMMAND_OK     всё прошло хорошо (для запросов, которые не возвращают данные, например, INSERT),
+
 
PGRES_TUPLES_OK     всё прошло хорошо, плюс получены данные в ответ на запрос (для запросов типа SELECT или SHOW),
+
История пакета насчитывает уже пять лет. Программа доступна по дуальной лицензии: GPL – для использования со свободным ПО и коммерческой – для использования в проприетарном. Существует версия и для Windows.
PGRES_EMPTY_QUERY   строка запроса была почему-то пустой,
+
 
PGRES_COPY_OUT       идёт передача данных от сервера,
+
Перед инсталляцией ''bond'' следует внимательно прочесть README и установить все, что там перечислено. Сборка осуществляется с помощью ''scons'', который позиционируется как замена ''make'' с функциональностью ''automake/autoconf'' и синтаксисом от Python. Установка по умолчанию производится в '''/usr/local/'''. Для инсталляции (scons install) необходимы привилегии системного администратора. Затем можно приступать к чтению документации и изучению каталога examples.
PGRES_COPY_IN       идёт передача данных на сервер,
+
|Ширина=320px}}
PGRES_BAD_RESPONSE   ошибка, ответ сервера не разборчив,
+
 
PGRES_NONFATAL_ERROR ошибка, не смертельно: предупреждение (notice) или информация к сведению (warning),
+
По умолчанию, каждый '''PQexec''' открывает отдельную транзакцию, если явно не начать ее с помощью команды '''BEGIN'''. В последнем случае транзакция будет продолжаться либо до '''COMMIT''', либо до '''ROLLBACK'''.
PGRES_FATAL_ERROR   при выполнении запроса произошла серьёзная ошибка.
+
 
 +
Есть более сложный вызов '''PQexecParams''', который позволяет передавать вызов и параметры к этому вызову раздельно. Таким образом исчезает необходимость самостоятельно формировать строку ''SQL''-команды и заботиться об экранировании данных, что важно в случае сохранения бинарных последовательностей. В качестве платы за соображения безопасности '''PQexecParams''' способен послать не более одной команды за раз.
 +
 
 +
В некоторых случаях для увеличения скорости выполнения часто встречающихся запросов полезно обратить внимание на пару функций '''PQprepare''' и '''PQexecPrepared'''. Эти команды эквивалентны своим ''SQL''-аналогам '''PREPARE''' и '''EXECUTE'''. Идея оптимизации состоит в том, что прежде чем выполнить запрос, ''PostgreSQL'' сначала анализирует его, затем планирует порядок действий и только потом, собственно, выполняет запрос. Первые два этапа для похожих запросов с разными условиями отбора можно выполнить заранее с помощью команды '''PREPARE'''. Затем, с помощью команды '''EXECUTE''', можно выполнять подобные уже подготовленные (prepared) запросы.
 +
 
 +
Все упомянутые выше команды работают с сервером БД синхронным образом, то есть посылают запрос и ждут ответа. Клиентское приложение на это время «засыпает». В ''libpq'' предусмотрен целый класс функций, предназначенный для асинхронных операций, не блокирующих клиентское приложение. Их применение усложняет код и логику программы, хотя все в пределах допустимого. С моей точки зрения, лучше организовать все так, чтобы время, использованное на ожидание результатов запроса, не влияло фатально на внешние процессы, и обеспечить бесперебойную работу сети и сервера базы данных.
 +
 
 +
===== Информация о состоянии запроса =====
 +
После выполнения запроса всегда интересно узнать, каково его состояние:
 +
 
 +
<source lang="c">
 +
ExecStatusType PQresultStatus(const PGresult *res);
 +
</source>
 +
 
 +
На вход подается структура '''PGresult''', создаваемая в результате работы '''PQexec'''-подобных функций, а на выходе получаем информацию о состоянии в виде числа, значение которого можно сравнить со следующими константами:
 +
 
 +
* '''PGRES_COMMAND_OK''' – все прошло хорошо (для запросов, которые не возвращают данные, например, '''INSERT'''),
 +
* '''PGRES_TUPLES_OK''' – все прошло хорошо, плюс получены данные в ответ на запрос (для запросов типа '''SELECT''' или '''SHOW'''),
 +
* '''PGRES_EMPTY_QUERY''' – строка запроса почему-то была пустой,
 +
* '''PGRES_COPY_OUT''' – идет передача данных от сервера,
 +
* '''PGRES_COPY_IN''' – идет передача данных на сервер,
 +
* '''PGRES_BAD_RESPONSE''' – ошибка, ответ сервера не разборчив,
 +
* '''PGRES_NONFATAL_ERROR''' – нефатальная ошибка: предупреждение (notice) или информация к сведению (warning),
 +
* '''PGRES_FATAL_ERROR''' – при выполнении запроса произошла серьезная ошибка.
  
 
Для получения более подробной информации об ошибке следует воспользоваться функцией
 
Для получения более подробной информации об ошибке следует воспользоваться функцией
char ∗ PQ r esul t Er r o r Messa g e ( const PG r esul t ∗ r e s ) ;
 
При вызове этой функции в качестве результата будет сформирована строка с информацией об ошибке или пустая строка если всё прошло хорошо.
 
  
'''Получение данных''' При получении данных предполагается, что статус запроса соответствует PGRES_TUPLES_OK. Теперь, если примерно известно что хочется получить в результате запроса, то для получения данных достаточно четырёх функций:
+
<source lang="c">
int PQntuples ( const PG r esul t ∗ r e s ) ;
+
char *PQresultErrorMessage(const PGresult *res);
int P Q n f i e l d s ( const PG r esul t ∗ r e s ) ;
+
</source>
char ∗ PQgetvalue ( const PG r esul t ∗ r e s ,
+
                            int row_number , int column_number ) ;
+
int P Q g e t i s n u l l ( const PG r esul t ∗ r e s ,
+
                            int row_number , int column_number ) ;
+
Первые две функции являются информационными и позволяют узнать сколько в результате запроса получено строк (PQntuples) и сколько колонок в каждой такой строке (PQnfields). Возьмите на заметку, что 0 строк это тоже хороший результат.
+
  
Функция PQgetvalue позволяет получить доступ к полученным данным. В качестве параметров кроме структуры соединения (res) передаётся номер строки (column_number) и номер колонки (column_number). Все данные возвращаются так же в виде текстовой строки, как и посылаются, то есть, эти данные необходимо перевести в привычный формат. Например, в случае целых чисел можно восполь-
+
При вызове этой функции в качестве результата будет сформирована строка с информацией об ошибке или пустая строка, если все прошло хорошо.
зоваться функцией atoi.
+
  
Следует помнить, что данные SQL могут иметь неопределённое значение (NULL). Если подобная возможность существует, то перед получением значения проверить, а определено ли оно. PQgetisnull позволяет разобраться с этой проблемой. По передаваемым параметрам эта функция эквивалентна PQgetvalue, а в качестве результата возвращает 1, если значение не определено и 0, если опеределено.
+
===== Получение данных =====
 +
При получении данных предполагается, что статус запроса соответствует '''PGRES_TUPLES_OK'''. Теперь, если примерно известно, что хочется получить в результате запроса, то для получения данных достаточно четырех функций:
  
Кроме упомянутых существует целый ряд функций, позволяющих получить информацию о полученных данных, как то: имя колонки (PQfname), размер передаваемых данных в байтах (PQgetlength) и тому подобное. Для экранирования специальных символов при операции с бинарными или текстовыми данными есть набор сервисных функций PQescape∗.
+
<source lang="c">
 +
int PQntuples(const PGresult *res);
 +
int PQnfields(const PGresult *res);
 +
char *PQgetvalue(const PGresult *res,
 +
    int row_number, int column_number);
 +
int PQgetisnull(const PGresult *res,
 +
    int row_number, int column_number);
 +
</source>
  
'''COPY''' SQL команда COPY является расширением специфичным для PostgreSQL.
+
Первые две функции являются информационными и позволяют узнать, сколько строк получено в результате запроса ('''PQntuples''') и сколько в каждой такой строке колонок ('''PQnfields'''). Возьмите на заметку, что 0 строк – это тоже хороший результат.
  
Основное преимущество SQL  всё есть понятный текст, в некоторых случаях, когда надо передавать большие объёмы данных, оборачивается недостатком.
+
Функция '''PQgetvalue''' позволяет получить доступ к данным. В качестве параметров кроме структуры соединения ('''res''') передается номер строки ('''column_number''') и номер колонки ('''column_number'''). Все данные возвращаются (как и посылаются) в виде текстовой строки, то есть перед употреблением их необходимо перевести в привычный формат. Например, в случае целых чисел можно воспользоваться функцией '''atoi'''.
Функции PQputCopyData и PQgetCopyData позволяют под час значительно ускорить передачу данных между сервером и клиентом.
+
  
'''Асинхронные сигналы''' Стандартный SQL не предполагает взаимодействия разных пользователей, кроме как через изменение данных в таблицах. PostgreSQL позволяет посылать асинхронные сигналы с помощью команд LISTEN и NOTIFY. LISTEN "имя сигнала" передаётся серверу как обычная SQL-команда. Если статус запроса становится равным PGRES_COMMAND_OK, то это означает, что ранее был выполнен запрос NOTIFY "имя сигнала". Если же инициализация сигнала (NOTIFY) ожидается позже регистрации (LISTEN), то функция PQnotifies позволяет после любого запроса проверить наличие сигнала вновь.
+
Следует помнить, что данные ''SQL'' могут иметь неопределенное значение ('''NULL'''). Если подобная возможность существует, то перед получением значения следует проверить, определено ли оно. '''Pqgetisnull''' позволяет разобраться с этой проблемой. По передаваемым параметрам эта функция эквивалентна '''PQgetvalue''', а в качестве результата возвращает '''1''', если значение не определено, и '''0''', если определено.
  
'''Сборка мусора''' Мусор убирать придётся руками. Каждая функция типа PQexec создаёт объект типа PGresult. После того как вся необходимая информация о результатах запроса получена, следует освободить память, занимаемую этим объектом с помощью команды:
+
Кроме упомянутых выше, существует целый ряд функций, позволяющих получить информацию о данных, как то: имя колонки ('''PQfname'''), размер передаваемых данных в байтах ('''PQgetlength''') и тому подобное. Для экранирования специальных символов при операции с бинарными или текстовыми данными есть набор сервисных функций '''PQescape*'''.
void PQclear ( PG r esul t ∗ r e s ) ;
+
Если утечки памяти Вас не волнуют, то можно этого и не делать. В этом случае следует побеспокоиться о том: Почему Вас не беспокоят утечки памяти?
+
  
===Большие объекты===
+
===== COPY =====
Ещё один способ сохранять неструктурированные данные в PostgreSQL это пихать их как большие объекты (Large Objects). PostgreSQL предоставляет интерфейс схожим с файловым интерфейсом Unix: open (lo_open), read (lo_read), write (lo_write), lseek (lo_lseek) и так далее. Все lo_∗ команды работают со значениями полученными из колонки с типом oid. oid это специальный тип данных, который является ссылкой на объект произвольного типа. То есть последовательность работы с большим объектом следующая: создаётся большой объект (lo_create). Далее возвращаемый lo_create указатель Oid используется для записи данных в большой объект (lo_import/lo_write), а затем этот указатель вставляется в таблицу с помощью стандартных SQL операторов. Чтение происходит в обратном порядке (lo_export/lo_read). Все операции с большими объектами должны происходить внутри транзакции.
+
''SQL''-команда '''COPY''' является расширением, специфичным для ''PostgreSQL''. Основное преимущество ''SQL'' – «все есть понятный текст», в некоторых случаях, когда надо передавать большие объемы данных, оборачивается недостатком. Функции '''PQputCopyData''' и '''PQgetCopyData''' в ряде случаев позволяют значительно ускорить передачу данных между сервером и клиентом.
  
'''P.S.''' Необходимость интерфейса больших объектов на текущий момент не так уж и очевидна. Стандартными средствами в PostgreSQL можно сохранять бинарные данные размером вплоть до 1 Гб, что вполне может соперничать с максимальным размером для большого объекта в 2 Гб.
+
===== Асинхронные сигналы =====
 +
Стандартный ''SQL'' не предполагает взаимодействия разных пользователей, кроме как через изменение данных в таблицах. ''PostgreSQL'' позволяет посылать асинхронные сигналы с помощью команд '''LISTEN''' и '''NOTIFY'''. '''LISTEN "имя сигнала"''' передается серверу как обычная ''SQL''- команда. Если статус запроса становится равным '''PGRES_COMMAND_OK''', то это означает, что ранее был выполнен запрос '''NOTIFY "имя сигнала"'''. Если же инициализация сигнала ('''NOTIFY''') ожидается позже регистрации ('''LISTEN'''), то функция '''PQnotifies''' позволяет вновь проверить наличие сигнала после любого запроса.
  
==ECPG==
+
===== Сборка «мусора» =====
Чтобы не отставать от коммерческих баз данных PostgreSQL имеет свой собственный вариант встроенного SQL . Эта технология позволяет смешивать обычный язык C с SQL-структурами, примерно следующим образом:
+
«Мусор» убирать придется руками. Каждая функция типа '''PQexec''' создает объект типа '''PGresult'''. После того, как вся необходимая информация о результатах запроса получена, следует освободить память, занимаемую этим объектом с помощью команды:
  
// файл test.pgc
+
<source lang="c">
#include <stdio.h>
+
void PQclear(PGresult *res);
#include <stdlib.h>
+
</source>
// структура для обработки ошибок
+
EXEC SQL i n c l u d e s q l c a ;
+
// реакция в случае ошибки/ предупреждения
+
EXEC SQL whenever s q l w a r n i n g s q l p r i n t ;
+
EXEC SQL whenever s q l e r r o r do E x i t F o r E r r o r ( ) ;
+
void E x i t F o r E r r o r ( ) {
+
  f p r i n t f ( s t d e r r , "Всё , конец − это фатально .\n" ) ;
+
  sqlprint ();
+
  exit (1);
+
}
+
int main ( int argc , char ∗∗ argv )
+
{
+
// определение переменных , чтобы их можно было использовать
+
// инструкциях ECPG
+
  EXEC SQL BEGIN DECLARE SECTION;
+
    const char ∗dbname = " t est " ;
+
    const char ∗ u s e r = "baldin" ;
+
  VARCHAR FIO [ 1 2 8 ] ;
+
  VARCHAR NUMBER[ 1 2 8 ] ;
+
  EXEC SQL END DECLARE SECTION ;
+
// соединение с базой данных
+
// внешние переменные предваряются двоеточием
+
  EXEC SQL CONNECT TO : dbname USER : u s e r ;
+
// определение курсора через SELECT
+
  EXEC SQL DECLARE mycursor CURSOR FOR
+
    SELECT f i o , number FROM f i o d a t a , phonedata
+
                                      WHERE f i o d a t a . i d=phonedata . i d ;
+
  EXEC SQL open mycursor ;
+
// чтение данных из курсора
+
  EXEC SQL FETCH NEXT FROM mycursor INTO : FIO , :NUMBER;
+
  while ( s q l c a . s q l c o d e == 0 ) { // не 0 , если данные больше нет
+
      p r i n t f ( " И %s номер : %s\n" , FIO . a r r ,NUMBER. a r r ) ;
+
                    Ф О:
+
    EXEC SQL FETCH NEXT FROM mycursor INTO : FIO , :NUMBER;
+
  }
+
// разъединение с базой данных
+
EXEC SQL DISCONNECT;
+
}
+
  
Все SQL-команды начинаются с метки EXEC SQL. Эта метка позволяет затем препроцессору ecpg обработать и произвести C-исходник. Внутри SQL-команд можно использовать C-переменные. Для этого переменным в начале добавляется двоеточие : .
+
Если утечки памяти вас не волнуют, то можно этого и не делать. В этом случае следует побеспокоиться о том, почему вас не беспокоят утечки памяти?
  
Для компиляции выше процитированного исходника (файл test1.pgc) необходимо выполнить следующие действия:
 
> # установить ecpg
 
> sudo apt−g e t i n s t a l l l i b e c p g −dev
 
> # запустить препроцессор
 
> ecpg t e s t 1 . pgc
 
> # скомпилировать получившийся исходник
 
> g cc −o t e s t 1 t e s t 1 . c −I ‘ pg _ co nf i g −−i n c l u d e d i r ‘ −l e c p g
 
> # проверка работоспособности программы
 
> ./ test1
 
ФИО: Иванов И.П. номер : 555−32−23
 
ФИО: Балдин Е .М. номер : 555−41−37
 
ФИО: Балдин Е .М. номер : (+7)5559323919
 
  
Удобно это или нет решайте сами.
+
==== Большие объекты ====
 +
Еще один способ сохранять неструктурированные данные в
 +
''PostgreSQL'' – это сохранять их в больших объектах ('''Large Objects'''). ''PostgreSQL'' предоставляет интерфейс, схожий с файловым интерфейсом Unix: '''open''' ('''lo_open'''), '''read''' ('''lo_read'''), '''write''' ('''lo_write'''), '''lseek''' ('''lo_lseek''') и так далее. Все '''lo_*''' команды работают со значениями, полученными из колонки с типом '''oid''' – это специальный тип данных, который является ссылкой на объект произвольного типа. То есть последовательность работы с большим объектом следующая: создается большой объект ('''lo_create'''). Далее возвращаемый '''lo_create''' указатель '''oid''' используется для записи данных в большой объект ('''lo_import/lo_write'''), а затем этот указатель вставляется в таблицу с помощью стандартных ''SQL''-операторов. Чтение происходит в обратном порядке ('''lo_export/lo_read'''). Все операции с большими объектами должны происходить внутри транзакции.
  
==Всё остальное==
+
Следует отметить, что необходимость интерфейса больших объектов на текущий момент не так уж и очевидна. Стандартными средствами в ''PostgreSQL'' можно сохранять бинарные данные размером вплоть до 1 Гб, что вполне может соперничать с максимальным размером для большого объекта (2 Гб).
Статья называется Интерфейсы , а большая часть посвящена только одному из них. Дело в том, что этот один является родным и наиболее полным, а всё остальное лишь подмножество. В простейшем случае все интерфейсы одинаковы: открыл соединение, послал запрос, обработал результаты запроса, закрыл соединение. Так же заметна энергосберегающая тенденция везде делать ровно один интерфейс на все типы СУБД.
+
  
* '''bash''' Да, да к bash тоже есть свой интерфейс, правда для этого надо патчить его исходники. Возни, конечно, не мало зато прямо в shell-скриптах можно обращать к базе данных.  [http://www.psn.co.jp/PostgreSQL/pgbash/index-e.html Страничка проекта].
 
  
* '''Java''' Совершенно ожидаемо, что Java общается с PostgreSQL стандартным образом, а именно через JDBC. Поэтому если знаком с Java, то достаточно добыть драйвер JDBC для PostgreSQL, например [http://jdbc.postgresql.org/ отсюда] или в Debian (Sarge) набрать
+
=== ECPG ===
> sudo apt−g e t i n s t a l l l i b p g j a v a
+
{|
 +
|-
 +
| valign="top" |
 +
Чтобы не отставать от коммерческих баз данных, ''PostgreSQL'' имеет свой собственный вариант «встроенного ''SQL''». Эта технология позволяет смешивать обычный язык C с ''SQL''-структурами, примерно следующим образом:
 +
 
 +
<source lang="c">
 +
// файл test.pgc
 +
#include <stdio.h>
 +
#include <stdlib.h>
 +
// структура для обработки ошибок
 +
EXEC SQL include sqlca;
 +
// реакция в случае ошибки/предупреждения
 +
EXEC SQL whenever sqlwarning sqlprint;
 +
EXEC SQL whenever sqlerror do ExitForError();
 +
void ExitForError() {
 +
    fprintf(stderr,"Все, конец - это фатально.\n");
 +
    sqlprint();
 +
    exit(1);
 +
}
 +
 
 +
int main(int argc, char **argv)
 +
{
 +
    // определение переменных, чтобы их можно было использовать
 +
    // инструкциях ECPG
 +
    EXEC SQL BEGIN DECLARE SECTION;
 +
    const char *dbname = "test";
 +
    const char *user = "baldin";
 +
    VARCHAR FIO[128];
 +
    VARCHAR NUMBER[128];
 +
    EXEC SQL END DECLARE SECTION;
 +
    // соединение с базой данных
 +
    // внешние переменные предваряются двоеточием
 +
    EXEC SQL CONNECT TO :dbname USER :user;
 +
    // определение курсора через SELECT
 +
    EXEC SQL DECLARE mycursor CURSOR FOR
 +
    SELECT fio, number FROM fiodata,phonedata
 +
    WHERE fiodata.id=phonedata.id;
 +
    EXEC SQL open mycursor;
 +
    // чтение данных из курсора
 +
    EXEC SQL FETCH NEXT FROM mycursor INTO :FIO,:NUMBER;
 +
    while (sqlca.sqlcode == 0) { // не 0, если данные больше нет
 +
        printf("ФИО: %s номер: %s\n",FIO.arr,NUMBER.arr);
 +
        EXEC SQL FETCH NEXT FROM mycursor INTO :FIO, :NUMBER;
 +
    }
 +
    // разъединение с базой данных
 +
    EXEC SQL DISCONNECT;
 +
}
 +
</source>
 +
 
 +
Все ''SQL''-команды начинаются с метки '''EXEC SQL'''. Она используется препроцессором ecpg как маркер для конструкций, подлежащих обработке. Внутри ''SQL''-команд можно использовать переменные C. Для этого перед ними необходимо поставить двоеточие «''':'''».
 +
 
 +
Для компиляции выше процитированного файла ('''test1.pgc''') необходимо выполнить следующие действия:
 +
 
 +
<pre>
 +
> # установить ecpg
 +
> sudo apt-get install libecpg-dev
 +
> # запустить препроцессор
 +
> ecpg test1.pgc
 +
> # скомпилировать получившийся файл
 +
> gcc -o test1 test1.c -I`pg_config --includedir` -lecpg
 +
> # проверить работоспособность программы
 +
> ./test1
 +
ФИО: Иванов И.П. номер: 555-32-23
 +
ФИО: Балдин Е.М. номер: 555-41-37
 +
ФИО: Балдин Е.М. номер: (+7)5559323919
 +
</pre>
 +
 
 +
Удобно это или нет – решайте сами.
 +
| valign="top" |
 +
{{Врезка|Заголовок=PostgreSQL в лицах: Сергей Копосов|Содержание=
 +
[[Изображение:Img 89 89 1.jpg|thumb|left|100px]]
 +
'''Визитка LXF:'''<br>Дипломированный физик. Профессиональный астроном. Участник программы Google Summer of Code 2006. Домашняя страница: http://lnfm1.sai.msu.ru/~math/.<br><br><br><br><br>
 +
 
 +
'''Евгений М. Балдин (ЕМБ): Что привлекло вас к разработке именно PostgreSQL?'''
 +
 
 +
'''Сергей Е. Копосов (СЕК):''' Вначале я познакомился с ''PostgreSQL'' как пользователь. Причины были следующие: необходимо было работать с большим астрономическим каталогом (2MASS), который содержал более 200 миллионов звезд. Здесь без базы данных не обойдешься. То, что выбран был именно ''PostgreSQL'', связано с тем, что рядом были люди<ref>
 +
Множество «эти люди» включало Олега Бартунова.
 +
</ref>, которые его уже использовали.
 +
 
 +
А дальше все пошло по нарастающей. Начав работать с ''PostgreSQL'', я вдруг обнаружил, что в нем не существует способов, с помощью которых можно было бы быстро искать объекты на сфере. В итоге это сподвигло меня на создание проекта Q3C (''QuadTreeCube'' http://q3c.sf.net). Процесс работы над ним потребовал выйти за рамки стандартного ''PostgreSQL''. Например, мне были необходимы bitmap-индексы, а Том Лэйн [Tom Lane] их тогда только реализовывал. Из-за этого мне пришлось перейти на работу c CVS-версией ''PostgreSQL''. Во время разработки Q3C мне удалось заметить несколько проблем со скоростью работы bitmap’ов, которые позже были исправлены Томом.
 +
 
 +
После интенсивной разработки Q3C я сильно «подсел» на списки рассылки ''pg-hackers'', ''pg-patches'', и я, в частности, написал несколько маленьких патчей для тех проблем в клиенте ''pSQL'', которые мне не нравились. Сначала автодополнение '''DROP~FUNCTION''', а потом улучшение работы ''pSQL'' c многострочными запросами. За последнее меня уже официально включили в список «Official contributors ''PostgreSQL''» – чем я несказанно горд [улыбка].
 +
 
 +
'''ЕМБ: За что вас выбрали для участия в программе Summer of Code 2006, и чем эта эпопея закончилась?'''
 +
 
 +
'''СЕК:''' Тут сложно сказать. На самом деле, предложенных на Summer of Code проектов было не так уж и много, а мой проект не был ни чрезвычайно сложным, ни очень простым. Была общая подсказка от Тома, в каком направлении реализовывать проект. Сам проект был вполне естественным улучшением уже существующей функциональности ''PostgreSQL'', реализующей к тому же одну из маленьких недостающих частей стандарта SQL:2003. К тому же я уже был хотя бы минимально, но известен в сообществе ''pg-hackers''.
 +
 
 +
А закончилось все тем, что сейчас мой код по агрегатным функциям включен в CVS и будет в версии ''8.2 PostgreSQL''. За что, конечно, спасибо Тому Лэйну, который фиксировал и слегка корректировал код.
 +
 
 +
'''ЕМБ: Вы – профессиональный астроном, и, судя по списку проектов, вы активно работаете по основному профилю. ''PostgreSQL'' не отвлекает от вашей деятельности?'''
 +
 
 +
'''СЕК:''' Отвлекает. Очень. Поэтому пока я взял паузу в кодировании для ''PostgreSQL''. А дальше, поживем – увидим…
 +
|Ширина=400px}}
 +
|}
 +
 
 +
=== Все остальное ===
 +
{{Врезка
 +
|Заголовок=Азбука SQL: Г
 +
|Содержание=
 +
'''Управление доступом к данным'''<br>
 +
Группа операторов ''SQL'', ответственных за дифференциацию пользователей путем предоставления и отмены привилегий, представляют из себя специализированный язык управления доступом к данным (Data Control Language).
 +
 
 +
Привилегии для работу с таблицами базы данных предоставляются пользователям с помощью команды:
 +
 
 +
<source lang="sql">
 +
GRANT «список привилегий»
 +
    ON TABLE «имя таблицы» [, …]
 +
    TO «пользователь» [, …]
 +
</source>
 +
 
 +
Типы привилегий, которые можно предоставить пользователям:
 +
* '''SELECT''' – разрешение на выполнение запроса на получение данных,
 +
* '''INSERT''' – разрешение на добавление данных в таблицу,
 +
* '''UPDATE''' – разрешение на изменение данных,
 +
* '''DELETE''' – разрешение на удаление данных,
 +
* '''REFERENCES''' – разрешение на создание ограничения по внешнему ключу,
 +
* '''TRIGGER''' – разрешение на создание триггера,
 +
* '''ALL''' – можно делать абсолютно все.
 +
 
 +
Эти привилегии можно дать только в случае, если таблица уже существует. На создание таблицы тоже надо иметь право:
 +
 
 +
<source lang="sql">
 +
GRANT CREATE
 +
    ON DATABASE «имя базы данных» [, …]
 +
    TO «пользователь» [, …]
 +
</source>
 +
 
 +
Для отмены уже имеющихся привилегий используется команда:
 +
 
 +
<source lang="sql">
 +
REVOKE «список привилегий»
 +
    ON «имя таблицы» [, …]
 +
    FROM «пользователь» [, …]
 +
</source>
 +
|Ширина=350px}}
 +
Эта статья называется «Интерфейсы», но большая часть ее посвящена только одному из них. Дело в том, что этот один является родным и наиболее полным, а все остальное – лишь подмножество. В простейшем случае все интерфейсы одинаковы: открыл соединение, послал запрос, обработал результаты, закрыл соединение. Также заметна энергосберегающая тенденция везде делать ровно один интерфейс на все типы СУБД.
 +
 
 +
===== bash =====
 +
Да, да к ''bash'' тоже есть свой интерфейс, правда для этого надо наложить специальный патч. Возни, конечно, немало – зато к базе данных можно будет обращаться прямо из shell-скриптов.
 +
 
 +
Сайт проекта: http://www.psn.co.jp/postgresql/pgbash/index-e.html.
 +
 
 +
===== Java =====
 +
Совершенно ожидаемо, что Java общается с ''PostgreSQL'' стандартным образом, а именно через JDBC. Поэтому, если вы знакомы с Java [а если нет – зачем вам использовать ее для доступа к ''PostgreSQL''? – прим. ред.], то достаточно добыть драйвер JDBC для ''PostgreSQL'', например отсюда: http://jdbc.postgresql.org/. В Debian (Sarge) достаточно набрать
 +
 
 +
<pre>
 +
> sudo apt-get install libpgjava
 +
</pre>
 +
 
 
и, прочитав README к пакету, приступить к работе.
 
и, прочитав README к пакету, приступить к работе.
  
* '''lisp''' Точнее Common Lisp. Скорее всего эти драйвера подойдут и для других диалектов:
+
===== Lisp =====
> sudo apt−g e t i n s t a l l c l −pg
+
Точнее, Common Lisp. Скорее всего, эти драйвера подойдут и для других диалектов:
#или
+
 
> sudo apt−g e t i n s t a l l c l −s q l −p o s t g r e s q l
+
<pre>
Второй вариант является драйвером для единого интерфейса доступа к SQL-базам данных из Common Lisp [http://clsql.b9.com/ CLSQL].
+
> sudo apt-get install cl-pg
 +
#или
 +
> sudo apt-get install cl-sql-postgresql
 +
</pre>
 +
 
 +
Второй вариант является драйвером для единого интерфейса доступа к ''SQL''-базам данных из ''Common Lisp CLSQL'' (http://clsql.b9.com/).
 +
 
 +
===== Perl =====
 +
Интерфейс для связи с ''PostgreSQL'' DBD-Pg используется в Perl через DBI<ref>
 +
DBI — унифицированный интерфейс для доступа к данным. Подробнее об этом пакете можно узнать на CPAN: http://search.cpan.org/~timb/DBI-1.52/DBI.pm
 +
</ref>. Все подробности доступны на CPAN: http://search.cpan.org/~dbdpg/dbd-pg/pg.pm.
 +
 
 +
<pre>
 +
> sudo apt-get install libdbd-pg-perl
 +
</pre>
 +
 
 +
DBD-Pg охватывает, фактически, все имеющиеся на сегодня возможности ''PostgreSQL'': от больших объектов ('''large objects''') до точек сохранения ('''savepoints''').
 +
 
 +
===== PHP =====
 +
О том как использовать ''PostgreSQL'' в PHP-проектах можно прочитать здесь: http://www.php.net/manual/en/ref.pgsql.php. Драйвер, скорее всего, тоже доступен в репозиториях дистрибутива:
 +
 
 +
<pre>
 +
> sudo apt-get install php4-pgsql
 +
</pre>
  
* '''perl''' Интерфейс для связи с PostgreSQL DBD-Pg используется в perl через DBI<ref>DBI унифицированный интерфейс для доступа к данным. Подробнее об этом пакете можно посмотреть на CTAN: http://search.cpan.org/~timb/DBI-1.52/DBI.pm</ref>. Все подробности на [http://search.cpan.org/~dbdpg/DBD-Pg/Pg.pm CTAN].
+
Говорят, почти единственной причиной, по которой PHP-разработчики предпочитают ''MySQL'', является то, что раньше не было «родной» версии ''PostgreSQL'' под Windows. Начиная с ''PostgreSQL 8.0'', конкретно этот довод «против» уже не работает.
> l i bdbd −pg−p e r l
+
DBD-Pg охватывает фактически все имеющиеся на сегодня возможности PostgreSQL от больших объектов (large objects), до точек сохранения (savepoints).
+
  
* '''PHP''' О том как использовать PostgreSQL в PHP-проектах можно прочитать [http://www.php.net/manual/en/ref.pgsql.php здесь]. Установить драйвер можно, например, так:
+
===== Python =====
> sudo apt−g e t i n s t a l l php5−p g s q l
+
Модуль для Python существует уже больше десяти лет. Подробности можно узнать здесь: http://www.druid.net/pygresql/. Установка модуля:
Говорят, почти единственной причиной, по которой PHP-разработчики предпочитают MySQL является то, что раньше не было родной версии PostgreSQL под альтернативную операционную систему. С версии 8.0 PostgreSQL конкретно этот довод против уже не работает.
+
  
* '''Python''' Модуль для Python существует уже больше десяти лет. Подробности выясняются [http://www.druid.net/pygresql/ здесь]. Установка модуля:
+
<pre>
> sudo apt−g e t i n s t a l l python−p y g r e s q l
+
> sudo apt-get install python-pygresql
Более молодая и по утверждениям пользователей более стабильная библиотека для связи с PostgreSQL psycopg2 (http://initd.org/projects/psycopg2) так же устанавливается из коробки:
+
</pre>
> sudo apt−g e t i n s t a l l python−psycopg2
+
  
* '''Ruby''' Что-то есть [http://ruby.scripting.ca/postgres/ здесь]. Установка, как обычно:
+
===== Ruby =====
> sudo apt−g e t i n s t a l l l i bdbd −pg−ruby
+
Кое-что можно прочесть здесь: http://ruby.scripting.ca/postgres/. Установка происходит как обычно:
  
* '''ODBC''' Разработка драйвера идёт на pgFoundry, аскетичная страничка проекта [http://pgfoundry.org/projects/psqlodbc/ здесь]. Установка:
+
<pre>
> sudo apt−g e t i n s t a l l odbc−p o s t g r e s q l
+
> sudo apt-get install libdbd-pg-ruby
 +
</pre>
  
==Послесловие==
+
===== ODBC =====
Очевидно, что есть много чего ещё. При желании можно самому написать, благо родной C-интерфейс уже знаком, а логика достаточно прозрачна: открыл соединение, обменялся [SQL]-запросами и обязательно закрыл соединение. С другой стороны не стоит изобретать велосипеда и лучше для начала посмотреть, что было уже сделано, например, [http://techdocs.postgresql.org/oresources.php здесь].
+
Разработка драйвера идет на pgFoundry. Аскетичная страничка проекта доступна по адресу: http://pgfoundry.org/projects/psqlodbc/. Установка:
===Врезка про bond===
+
Лень писать всё самому? Но не лень изучать XML? Тогда BOND это программа для Вас. [http://www.treshna.com/bond/ Сайт проекта].
+
  
Рабочей частью пакета является исполняемый файл bondfrontend, который осуществляет связь с базой данных и может прикинуться любой формой. Описание формы хранится в обычном xml-файле. Используемый диалект xml подробно описан в документации.
+
<pre>
 +
> sudo apt-get install odbc-postgresql
 +
</pre>
  
Рис. 4.1. Формочки, XML (правда на заднем фоне и без подсветки) и связь с базой данных это bond
 
  
История пакета насчитывает уже пять лет. Программа доступна под GPL, то есть исходники производных продуктов надо открывать, а если хочется пожадничать, то есть версия и для такого случая, но за деньги. Доступна версия и под win32.
+
=== Послесловие ===
 +
Конечно, наш обзор интерфейсов к ''PostgreSQL'' нельзя назвать всеобъемлющим, но изложенных сведений вполне хватит для того, чтобы начать работать. Если впоследствии вам придет в голову идея «дописать что-то свое», не спешите хвататься за перо, то есть клавиатуру – советую сначала обратиться по адресу http://techdocs.postgresql.org/oresources.php и посмотреть, что уже сделано.
  
Внимательно читаем README и устанавливаем всё что там перечисляется. Сборка осуществляется с помощью scons, который позиционируется как замена make с функциональность automake/autoconf и синтаксисом от Python. Установка по умолчанию производится /usr/local/. Для установки (scons install ) необходимы привилегии системного администратора. Далее читаем документацию и изучаем директорию examples.
 
  
==Примечания==
+
----
<references />
+
<references/>

Текущая версия на 17:07, 27 апреля 2008

История PostgreSQL Изучаем самый мощный из открытых серверов баз данных

Содержание

[править] Интерфейсы

ЧАСТЬ 4: Интерфейсы, как известно, бывают не только пользовательскими, но и программными. С первыми мы уже успели познакомиться, а сегодня Евгений Балдин расскажет, какие API существуют для доступа к PostgreSQL из различных языков программирования.

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

(О Кощее Бессмертном)
«Понедельник начинается в субботу»

Понятно, что любую базу данных, в принципе, можно заполнить вручную; правда, некоторые придется заполнять очень долго. СУБД – это просто хранилище, а для заполнения и доступа к хранилищу необходима инфраструктура, и эту инфраструктуру надо создавать. Вот такая она – жизнь.

Родной библиотекой для доступа к PostgreSQL является libpq. Написана она на чистом C, что тоже не удивительно, так как это основной язык родной системы. Все остальные языки важны, но безусловно, вторичны.


[править] libpq

Чтобы общаться с базой данных, много функций не требуется: одна для открытия соединения, одна для посылки запроса, одна для получения ответа и одна для закрытия соединения. В реальности, конечно, все немного сложнее, но суть остается неизменной.

[править] К вопросу о переносимости

Библиотека libpq написана на чистом C, поэтому связь с PostgreSQL можно организовать практически везде, где можно найти gcc. Мне как-то пришлось делать это для VAX/VMS – все решилось методом тыка, даже думать почти не потребовалось. Все данные – текст, поэтому вопрос бинарной совместимости платформ попросту отсутствует.

[править] С чего начать

Чтобы воспользоваться вызовами libpq, ее необходимо иметь в системе. В Debian (Sarge) для этого надо установить пакет PostgreSQL-dev:

> sudo apt-get install postgresql-dev

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

#include "libpq-fe.h"

Скрипт pg_config (man pg_config) позволяет получить информацию о том, куда помещаются include-файлы, библиотеки и тому подобное. Для сборки можно также использовать скрипт libpq3-config (man libpq3-config – годится, естественно, только для libpq третьей версии), который заведомо есть в Debian (Sarge):

> #сборка программы
> gcc -o "бинарник" "исходник".c -I'pg_config --includedir' \
-lpq '/usr/bin/libpq3-config'
> cat /usr/bin/libpq3-config
#!/bin/bash
echo -lssl -lcrypto -lkrb5 -lcrypt -lresolv -lnsl -lpthread

libpq3-config просто выводит список всех библиотек, от которых зависит libpq.


[править] Открытие и закрытие соединения

Даже открывать соединение с PostgreSQL можно двумя способами:

//открыть соединение
PGconn *PQconnectdb(const char *conninfo);
//то же, но не блокируя программу
PGconn *PQconnectStart(const char *conninfo);
//проверка статуса соединения (после PQconnectStart)
PostgresPollingStatusType PQconnectPoll(PGconn *conn);

PQconnectdb – обычная функция, принимающая текстовую строку conninfo, содержащую параметры для соединения с сервером, и возвращающая структуру типа PGconn с информацией о созданном соединении и успешности данной операции. В дальнейшем при передаче данных эта структура будет использоваться в качестве параметра.

Передача информации о сервере в качестве строки (conninfo) позволяет не менять внешний интерфейс вызова в случае появления дополнительных параметров и легко добавлять дополнительные опции. Пример открытия соединения:

const char *conninfo= "dbname = test host=localhost";
PGconn *conn=PQconnectdb(conninfo);
if (PQstatus(conn) != CONNECTION_OK) {
fprintf(stderr, "Не удалось соединиться с базой данных: %s",
PQerrorMessage(conn));
/*завершаем работу*/}

Параметры передаются в форме «ключевое слово»=«значение». Пары разделяются обычным пробелом. Пробелы вокруг знака равенства можно опустить. Если необходимо передать значение с пробелами, то его необходимо заключить в одинарные кавычки '«составное» «значение»'. Для передачи одинарной кавычки ее необходимо экранировать с помощью обратной косой черты \'. При отсутствии какого-либо параметра в строке conninfo его значение берется из соответствующей переменной окружения, если таковая определена. Если нет, то при открытии соединения используется значение по умолчанию.

Функции открытия соединения распознают следующие параметры и переменные окружения (кое-какие особенности опущены):

  • host DNS-имя узла, на котором находится сервер PostgreSQL. Соответствует переменной окружения PGHOST. Значение по умолчанию: localhost.
  • hostaddr Числовой адрес узла, на котором находится PostgreSQL (альтернатива host). Соответствует переменной окружения PGHOSTADDR. Значение по умолчанию эквивалентно: localhost.
  • port Номер порта, который «слушает» POSTMASTER. Соответствует переменной окружения PGPORT. Значение по умолчанию обычно 5432.
  • dbname Имя базы данных. Соответствует переменной окружения PGDATABASE. Значение по умолчанию совпадает с системной учетной записью пользователя.
  • user Имя пользователя базы данных. Соответствует переменной окружения PGUSER. Значение по умолчанию совпадает с системной учетной записью пользователя.
  • password Поле пароля, если для аутентификации требуется пароль. Соответствует переменной окружения PGPASSWORD. Если аутентификация требуется, а поле не определено, то для доступа используются данные файла ~/.pgpass. Переменная окружения PGPASSFILE может указать другой файл для проведения аутентификации.
  • connect_timeout Устанавливает максимальное время ожидания соединения в секундах. С сервером и сетью всякое может случиться. Соответствует переменной окружения PGCONNECT_TIMEOUT. Значение по умолчанию равно 0, что означает бесконечное время ожидания. Не рекомендуется устанавливать значение ожидания меньше 2 секунд.
  • options Опции, посылаемые непосредственно серверу, если таковые потребуются. Соответствует переменной окружения PGOPTIONS.
  • sslmode Определяет порядок действий при SSL-соединении. Принимает четыре возможных значения:
    • disable – без шифрования
    • allow – сначала попробовать соединиться без шифрования, а в случае неудачи постараться установить защищенное соединение,
    • prefer – сначала попробовать установить защищенное соединение, а в случае неудачи повторить соединение без шифрования,
    • require – выполнять только защищенное соединение. Соответствует переменной окружения PGSSLMODE.

Значение по умолчанию: prefer.

  • krbsrvname Имя Kerberos-сервиса. Используется для аутентификации с помощью Kerberos-5[1]. Это совершенно отдельная тема, выходящая за рамки данной статьи. Соответствует переменной окружения PGKRBSRVNAME.
  • PGDATESTYLE Переменная окружения, позволяющая установить представление времени и даты по умолчанию. Соответствует SQL-команде SET datestyle TO …
  • PGTZ Переменная окружения, позволяющая установить текущий часовой пояс. Соответствует SQL-команде SET timezone TO …
  • PGCLIENTENCODING Переменная окружения, позволяющая установить кодировку клиента. Соответствует SQL-команде SET client_encoding TO …

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

ConnStatusType PQstatus(const PGconn *conn);
char *PQerrorMessage(const PGconn *conn);

PQstatus возвращает информацию о том, как прошло соединение. Интересны состояния CONNECTION_OK – все хорошо и CONNECTION_BAD – ничего не вышло. Функция PQerrorMessage позволяет получить текстовую строку с описанием последней возникшей проблемы.

Для того, чтобы разорвать соединение, используется функция:

void PQfinish(PGconn *conn);

Внимание! Соединения следует закрывать сразу же, как только в них отпадает необходимость. Число соединений, которые поддерживает POSTMASTER, ограничено – очень легко парализовать работу базы данных, просто открывая новые соединения.


[править] SQL-запросы

Что ж, до сервера мы уже «дозвонились», теперь пора с ним «поговорить».

[править] Выполнение запросов

Простейший способ выполнить SQL-запрос – это воспользоваться функцией PQexec:

PGresult *PQexec(PGconn *conn, const char *command);

В качестве параметров функции передается структура соединения conn и строка с SQL-командой command. Возвращается указатель на структуру типа PGresult, где сохраняется информация, полученная от СУБД в ответ на запрос. При желании можно отсылать сразу несколько SQL-команд в одном запросе, разделяя их ; – точкой с запятой. В этом случае информация, сохраненная в структуре PGresult, будет относиться только к последнему запросу.


По умолчанию, каждый PQexec открывает отдельную транзакцию, если явно не начать ее с помощью команды BEGIN. В последнем случае транзакция будет продолжаться либо до COMMIT, либо до ROLLBACK.

Есть более сложный вызов PQexecParams, который позволяет передавать вызов и параметры к этому вызову раздельно. Таким образом исчезает необходимость самостоятельно формировать строку SQL-команды и заботиться об экранировании данных, что важно в случае сохранения бинарных последовательностей. В качестве платы за соображения безопасности PQexecParams способен послать не более одной команды за раз.

В некоторых случаях для увеличения скорости выполнения часто встречающихся запросов полезно обратить внимание на пару функций PQprepare и PQexecPrepared. Эти команды эквивалентны своим SQL-аналогам PREPARE и EXECUTE. Идея оптимизации состоит в том, что прежде чем выполнить запрос, PostgreSQL сначала анализирует его, затем планирует порядок действий и только потом, собственно, выполняет запрос. Первые два этапа для похожих запросов с разными условиями отбора можно выполнить заранее с помощью команды PREPARE. Затем, с помощью команды EXECUTE, можно выполнять подобные уже подготовленные (prepared) запросы.

Все упомянутые выше команды работают с сервером БД синхронным образом, то есть посылают запрос и ждут ответа. Клиентское приложение на это время «засыпает». В libpq предусмотрен целый класс функций, предназначенный для асинхронных операций, не блокирующих клиентское приложение. Их применение усложняет код и логику программы, хотя все в пределах допустимого. С моей точки зрения, лучше организовать все так, чтобы время, использованное на ожидание результатов запроса, не влияло фатально на внешние процессы, и обеспечить бесперебойную работу сети и сервера базы данных.

[править] Информация о состоянии запроса

После выполнения запроса всегда интересно узнать, каково его состояние:

ExecStatusType PQresultStatus(const PGresult *res);

На вход подается структура PGresult, создаваемая в результате работы PQexec-подобных функций, а на выходе получаем информацию о состоянии в виде числа, значение которого можно сравнить со следующими константами:

  • PGRES_COMMAND_OK – все прошло хорошо (для запросов, которые не возвращают данные, например, INSERT),
  • PGRES_TUPLES_OK – все прошло хорошо, плюс получены данные в ответ на запрос (для запросов типа SELECT или SHOW),
  • PGRES_EMPTY_QUERY – строка запроса почему-то была пустой,
  • PGRES_COPY_OUT – идет передача данных от сервера,
  • PGRES_COPY_IN – идет передача данных на сервер,
  • PGRES_BAD_RESPONSE – ошибка, ответ сервера не разборчив,
  • PGRES_NONFATAL_ERROR – нефатальная ошибка: предупреждение (notice) или информация к сведению (warning),
  • PGRES_FATAL_ERROR – при выполнении запроса произошла серьезная ошибка.

Для получения более подробной информации об ошибке следует воспользоваться функцией

char *PQresultErrorMessage(const PGresult *res);

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

[править] Получение данных

При получении данных предполагается, что статус запроса соответствует PGRES_TUPLES_OK. Теперь, если примерно известно, что хочется получить в результате запроса, то для получения данных достаточно четырех функций:

int PQntuples(const PGresult *res);
int PQnfields(const PGresult *res);
char *PQgetvalue(const PGresult *res,
    int row_number, int column_number);
int PQgetisnull(const PGresult *res,
    int row_number, int column_number);

Первые две функции являются информационными и позволяют узнать, сколько строк получено в результате запроса (PQntuples) и сколько в каждой такой строке колонок (PQnfields). Возьмите на заметку, что 0 строк – это тоже хороший результат.

Функция PQgetvalue позволяет получить доступ к данным. В качестве параметров кроме структуры соединения (res) передается номер строки (column_number) и номер колонки (column_number). Все данные возвращаются (как и посылаются) в виде текстовой строки, то есть перед употреблением их необходимо перевести в привычный формат. Например, в случае целых чисел можно воспользоваться функцией atoi.

Следует помнить, что данные SQL могут иметь неопределенное значение (NULL). Если подобная возможность существует, то перед получением значения следует проверить, определено ли оно. Pqgetisnull позволяет разобраться с этой проблемой. По передаваемым параметрам эта функция эквивалентна PQgetvalue, а в качестве результата возвращает 1, если значение не определено, и 0, если определено.

Кроме упомянутых выше, существует целый ряд функций, позволяющих получить информацию о данных, как то: имя колонки (PQfname), размер передаваемых данных в байтах (PQgetlength) и тому подобное. Для экранирования специальных символов при операции с бинарными или текстовыми данными есть набор сервисных функций PQescape*.

[править] COPY

SQL-команда COPY является расширением, специфичным для PostgreSQL. Основное преимущество SQL – «все есть понятный текст», в некоторых случаях, когда надо передавать большие объемы данных, оборачивается недостатком. Функции PQputCopyData и PQgetCopyData в ряде случаев позволяют значительно ускорить передачу данных между сервером и клиентом.

[править] Асинхронные сигналы

Стандартный SQL не предполагает взаимодействия разных пользователей, кроме как через изменение данных в таблицах. PostgreSQL позволяет посылать асинхронные сигналы с помощью команд LISTEN и NOTIFY. LISTEN "имя сигнала" передается серверу как обычная SQL- команда. Если статус запроса становится равным PGRES_COMMAND_OK, то это означает, что ранее был выполнен запрос NOTIFY "имя сигнала". Если же инициализация сигнала (NOTIFY) ожидается позже регистрации (LISTEN), то функция PQnotifies позволяет вновь проверить наличие сигнала после любого запроса.

[править] Сборка «мусора»

«Мусор» убирать придется руками. Каждая функция типа PQexec создает объект типа PGresult. После того, как вся необходимая информация о результатах запроса получена, следует освободить память, занимаемую этим объектом с помощью команды:

void PQclear(PGresult *res);

Если утечки памяти вас не волнуют, то можно этого и не делать. В этом случае следует побеспокоиться о том, почему вас не беспокоят утечки памяти?


[править] Большие объекты

Еще один способ сохранять неструктурированные данные в PostgreSQL – это сохранять их в больших объектах (Large Objects). PostgreSQL предоставляет интерфейс, схожий с файловым интерфейсом Unix: open (lo_open), read (lo_read), write (lo_write), lseek (lo_lseek) и так далее. Все lo_* команды работают со значениями, полученными из колонки с типом oid – это специальный тип данных, который является ссылкой на объект произвольного типа. То есть последовательность работы с большим объектом следующая: создается большой объект (lo_create). Далее возвращаемый lo_create указатель oid используется для записи данных в большой объект (lo_import/lo_write), а затем этот указатель вставляется в таблицу с помощью стандартных SQL-операторов. Чтение происходит в обратном порядке (lo_export/lo_read). Все операции с большими объектами должны происходить внутри транзакции.

Следует отметить, что необходимость интерфейса больших объектов на текущий момент не так уж и очевидна. Стандартными средствами в PostgreSQL можно сохранять бинарные данные размером вплоть до 1 Гб, что вполне может соперничать с максимальным размером для большого объекта (2 Гб).


[править] ECPG

Чтобы не отставать от коммерческих баз данных, PostgreSQL имеет свой собственный вариант «встроенного SQL». Эта технология позволяет смешивать обычный язык C с SQL-структурами, примерно следующим образом:

// файл test.pgc
#include <stdio.h>
#include <stdlib.h>
// структура для обработки ошибок
EXEC SQL include sqlca;
// реакция в случае ошибки/предупреждения
EXEC SQL whenever sqlwarning sqlprint;
EXEC SQL whenever sqlerror do ExitForError();
void ExitForError() {
    fprintf(stderr,"Все, конец - это фатально.\n");
    sqlprint();
    exit(1);
}
 
int main(int argc, char **argv)
{
    // определение переменных, чтобы их можно было использовать
    // инструкциях ECPG
    EXEC SQL BEGIN DECLARE SECTION;
    const char *dbname = "test";
    const char *user = "baldin";
    VARCHAR FIO[128];
    VARCHAR NUMBER[128];
    EXEC SQL END DECLARE SECTION;
    // соединение с базой данных
    // внешние переменные предваряются двоеточием
    EXEC SQL CONNECT TO :dbname USER :user;
    // определение курсора через SELECT
    EXEC SQL DECLARE mycursor CURSOR FOR
    SELECT fio, number FROM fiodata,phonedata
    WHERE fiodata.id=phonedata.id;
    EXEC SQL open mycursor;
    // чтение данных из курсора
    EXEC SQL FETCH NEXT FROM mycursor INTO :FIO,:NUMBER;
    while (sqlca.sqlcode == 0) { // не 0, если данные больше нет
        printf("ФИО: %s номер: %s\n",FIO.arr,NUMBER.arr);
        EXEC SQL FETCH NEXT FROM mycursor INTO :FIO, :NUMBER;
    }
    // разъединение с базой данных
    EXEC SQL DISCONNECT;
}

Все SQL-команды начинаются с метки EXEC SQL. Она используется препроцессором ecpg как маркер для конструкций, подлежащих обработке. Внутри SQL-команд можно использовать переменные C. Для этого перед ними необходимо поставить двоеточие «:».

Для компиляции выше процитированного файла (test1.pgc) необходимо выполнить следующие действия:

> # установить ecpg
> sudo apt-get install libecpg-dev
> # запустить препроцессор
> ecpg test1.pgc
> # скомпилировать получившийся файл
> gcc -o test1 test1.c -I`pg_config --includedir` -lecpg
> # проверить работоспособность программы
> ./test1
ФИО: Иванов И.П. номер: 555-32-23
ФИО: Балдин Е.М. номер: 555-41-37
ФИО: Балдин Е.М. номер: (+7)5559323919

Удобно это или нет – решайте сами.

[править] Все остальное

Эта статья называется «Интерфейсы», но большая часть ее посвящена только одному из них. Дело в том, что этот один является родным и наиболее полным, а все остальное – лишь подмножество. В простейшем случае все интерфейсы одинаковы: открыл соединение, послал запрос, обработал результаты, закрыл соединение. Также заметна энергосберегающая тенденция везде делать ровно один интерфейс на все типы СУБД.

[править] bash

Да, да к bash тоже есть свой интерфейс, правда для этого надо наложить специальный патч. Возни, конечно, немало – зато к базе данных можно будет обращаться прямо из shell-скриптов.

Сайт проекта: http://www.psn.co.jp/postgresql/pgbash/index-e.html.

[править] Java

Совершенно ожидаемо, что Java общается с PostgreSQL стандартным образом, а именно через JDBC. Поэтому, если вы знакомы с Java [а если нет – зачем вам использовать ее для доступа к PostgreSQL? – прим. ред.], то достаточно добыть драйвер JDBC для PostgreSQL, например отсюда: http://jdbc.postgresql.org/. В Debian (Sarge) достаточно набрать

> sudo apt-get install libpgjava

и, прочитав README к пакету, приступить к работе.

[править] Lisp

Точнее, Common Lisp. Скорее всего, эти драйвера подойдут и для других диалектов:

> sudo apt-get install cl-pg
#или
> sudo apt-get install cl-sql-postgresql

Второй вариант является драйвером для единого интерфейса доступа к SQL-базам данных из Common Lisp CLSQL (http://clsql.b9.com/).

[править] Perl

Интерфейс для связи с PostgreSQL DBD-Pg используется в Perl через DBI[2]. Все подробности доступны на CPAN: http://search.cpan.org/~dbdpg/dbd-pg/pg.pm.

> sudo apt-get install libdbd-pg-perl

DBD-Pg охватывает, фактически, все имеющиеся на сегодня возможности PostgreSQL: от больших объектов (large objects) до точек сохранения (savepoints).

[править] PHP

О том как использовать PostgreSQL в PHP-проектах можно прочитать здесь: http://www.php.net/manual/en/ref.pgsql.php. Драйвер, скорее всего, тоже доступен в репозиториях дистрибутива:

> sudo apt-get install php4-pgsql

Говорят, почти единственной причиной, по которой PHP-разработчики предпочитают MySQL, является то, что раньше не было «родной» версии PostgreSQL под Windows. Начиная с PostgreSQL 8.0, конкретно этот довод «против» уже не работает.

[править] Python

Модуль для Python существует уже больше десяти лет. Подробности можно узнать здесь: http://www.druid.net/pygresql/. Установка модуля:

> sudo apt-get install python-pygresql
[править] Ruby

Кое-что можно прочесть здесь: http://ruby.scripting.ca/postgres/. Установка происходит как обычно:

> sudo apt-get install libdbd-pg-ruby
[править] ODBC

Разработка драйвера идет на pgFoundry. Аскетичная страничка проекта доступна по адресу: http://pgfoundry.org/projects/psqlodbc/. Установка:

> sudo apt-get install odbc-postgresql


[править] Послесловие

Конечно, наш обзор интерфейсов к PostgreSQL нельзя назвать всеобъемлющим, но изложенных сведений вполне хватит для того, чтобы начать работать. Если впоследствии вам придет в голову идея «дописать что-то свое», не спешите хвататься за перо, то есть клавиатуру – советую сначала обратиться по адресу http://techdocs.postgresql.org/oresources.php и посмотреть, что уже сделано.



  1. Kerberos — промышленный стандарт для аутентификации и взаимодействия в условиях незащищенного окружения. Алгоритмы Kerberos основаны на шифровании с использованием симметричного криптографического ключа и требуют наличия доверенного агента.
  2. DBI — унифицированный интерфейс для доступа к данным. Подробнее об этом пакете можно узнать на CPAN: http://search.cpan.org/~timb/DBI-1.52/DBI.pm
Персональные инструменты
купить
подписаться
Яндекс.Метрика