В последнее время все чаще замечаю увеличение внимания к такой СУБД как PostgreSQL. Почитал на хабре пакет статей о том что PostgreSQL лучше чем Mysql. И решил попробовать данную систему на деле.

 

Стал смотреть через какие компоненты можно работать с Pg  из Delphi. Таких набралось немного.

PgDAC от  Devart

Firedac (AnyDac) от   Embarcadero

ZeosLib от ZeosLib Development Team

Так же позже нашел PostgresDAC от microOLAP

Возможно имеются ещё какие то компоненты , но я не заострял на этом внимания. И того мы имеем 2 платных набора компонента и 1 бесплатный.   Вспомнил еще про Unidac от Devart,  но там несколько другая тема. По опыту работы с базами данных я решил заострить свое внимание на PgDAC, поскольку уже имею опыт работы с компонентами Devart, в частности пользовался SDAC для MsSQL,  MyDAC  для MySQL и  LiteDAC для SQLite. 

В общем скачал с  сервера установщик  PostgreSQL для Windows. Установил его на виртуальную машину, правда пришлось немного порыться в интернете как правильно его установить. Хотя инсталлятор и простой, не сравнить с инсталлятором от  того же самого Microsoft SQL Server,  но нормально Pg устанавливается только из под пользователя не содержащего в имени кириллицу и  имеющего все права на папку куда будет производиться установка. Но это частности.

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

Затем скачал с сайта Devart  компонент PgDac 4.6.20  триальную версию.  Для тестов этого вполне хватит. Для компонентов имеется удобный установщик, который все сам сделает и настроит.

В Delphi 7 появилась вкладка  PgDAC.

pgdac panel 

На ней содержаться следующие компоненты.

 

   TPgConnection компонент для управления подключения к базам PostgreSQL
   TPgQuery  компонент для выполнения запросов к базе и работы с наборами данных
   TPgTable компонент для работы с данными в пределах одной таблицы
   TPgSQL компонент для выполнения sql запросов или хранимых процедур без возврата значений.
   TPgScript  компонент для работы с большим sql кодом
   TPgStoredProc  компонент для работы с хранимыми процедурами 
   TPgUpdateSQL компонент для управления обновлением данных в Dataset компоненте
   TPgLoader компонент для загрузки данных в базу данных
   TPgDump компонент для сохранения и восстановления баз данных
   TPgEncryptor компонент для  шифрования данных
TCRBatchMove компонент для  перемещения данных между наборами данных
TPgMetaData получение метаданных о объектах в базе денных
TPgAlerter компонент для работы с уведомлениями сервера
TPgConnectDialog диалоговое окно для подключения к серверу
TPgSQLMonitor компонент для мониторинга работы PgDac
TVirtualTable компонент для хранения данных в оперативной памяти
  TCRDBGrid  довольно таки продвинутый датагрид
   TPgDataSource прокладка между источником данных и компонентами для отображения данных

 

Поскольку я делал тестовый пример под Delphi 7, то я не буду описывать использование данных компонент для мобильной разработки. А  коснусь только десктопных приложений.  

В общем создал я в среде разработки вот такое вот приложение.

programma delphi

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

А теперь более подробно про компоненты.

TPgconnection - подключение к базе. Данный компонент используется прямое подключение  к серверу PostgreSQL посредством протокола TCP/IP без каких либо дополнительных библиотек. 

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

  PgCon.Database := 'minibd';
  PgCon.Server := '192.168.65.130';
  PgCon.Port := 5432;
  PgCon.Username := 'pgdac';
  PgCon.Password := 'testdac';
  PgCon.Options.UseUnicode:=True;
  try
    PgCon.Connect;
    StatusBar1.Panels[0].Text := 'Подключение успешно';
    Tovar.Open;
    Zakaz.Open;
    Zdetail.Open;
    Klients.Open;
 except
    on e: Exception do
      StatusBar1.Panels[0].Text := e.Message;
  end;

 

 Затем добавил на форму несколько компонентов  TPgQuery, это так сказать главные рабочие лошадки при работе с базами данных. Они позволяют выполнять произвольные запросы для выборки наборов данных и  обрабатывать их.

К примеру если требуется вывести данные из таблицы товаров то это делается так.

Добавляем компоненты TPgQuery, TPgDataSource и любой ddgrid для отображения данных. Затем в коде пишем. 

procedure TForm1.ToolButton15Click(Sender: TObject);
begin
PgQuery1.SQL.Add('select * from tovar');
PgQuery1.Open;
end;

У компонента PgDataSource1 устанавливаем свойство DataSet равное PgQuery1, а у грида для отображения данных выставляем свойство DataSource равным PgDataSource1. Запускаем программу и нажимаем на кнопку и данные отображаются.

Если требуется выбрать данные с условием то можно сделать так.

procedure TForm1.ToolButton15Click(Sender: TObject);
begin
PgQuery1.SQL.Add('select * from tovar');
PgQuery1.AddWhere('gruppa = 1');
PgQuery1.Open;
end;

Можно конечно и просто в коде написать. 

PgQuery1.SQL.Add('select * from tovar where gruppa = 1');

 Тут кому как удобнее.

Допустим у нас имеется в базе несколько таблиц с одинаковой структурой и разными названиями. Иногда к ним требуется обращаться. Тут может выручить такое свойство TPgQuery как Macros.

Пишется такой код.

procedure TForm1.ToolButton15Click(Sender: TObject);
begin
PgQuery1.SQL.Add('select * from &otg');
PgQuery1.Macros.MacroByName('otg').Value:='otgruzka2015'; // сюда подставляем необходимое нам название таблицы
PgQuery1.Open;
end;

Если необходимо добавить данные то тут есть несколько вариантов. Либо так.

procedure TForm1.ToolButton15Click(Sender: TObject);
begin
Zakaz.SQL.Text:='select * from zakaz';
Zakaz.Open;
Zakaz.Append;
Zakaz.FieldByName('id').AsInteger:=1;
Zakaz.FieldByName('name').AsString:='Иванов Иван Иванович';
Zakaz.FieldByName('dataz').AsDateTime:= Now;
Zakaz.FieldByName('summa').AsFloat:= 123.345;
Zakaz.Post;
end;

 Либо по другому.

procedure TForm1.ToolButton15Click(Sender: TObject);
begin
Zakaz.SQL.Text:='insert into zakaz(id,name,dataz,summa) values (:id, :nm, :dt, :sm);';
Zakaz.ParamByName('id').AsInteger:=1;
Zakaz.ParamByName('nm').AsString:='Иванов Иван Иванович';
Zakaz.ParamByName('dt').AsDateTime:= Now;
Zakaz.ParamByName('sm').AsFloat:= 123.345;
Zakaz.Execute;
end;

 С методами Update и Delete можно работать так же.

 

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

procedure TForm1.ToolButton15Click(Sender: TObject);
begin
PgTable1.TableName:='tovar';
PgTable1.OrderFields:='name, cena';// поля по которым будет проходить сортировка
PgTable1.Open;
end;

 

Поскольку в базе  используется связь master-detail то у компонента detail TPgQuery отвечающего за отображения данных необходимо выставить соответствующие настройки.

DetailQuery.MasterSource:=MasterSource;
DetailQuery.MasterFields:='idd';
DetailQuery.DetailFields:='zid';

Это обеспечивает соответствующее отображение данных из нужной таблицы.  

Поскольку PosstgreSQL поддерживает хранимые процедуры то грех ими не воспользоваться.  В наборе PgDAC для  работы с процедурами используется компонент  TPgStoredProc. Я добавил на форму их два штуки. Один из  которых  будет отвечать за получения уникального номера для заказа с сервера через хранимую процедуру, а второй будет производить подсчет суммы заказа. Вообще компонент TPgQuery позволяет получать номер последней добавленной записи  через свойство LastInsertOID . Но для оперативной работы с данными лучше получать уникальный номер отдельно. 

В PostgreSQL имена таблиц и процедур пишутся с маленькой буквы,  это необходимо для кроссплатформенной совместимости, поскольку в  Linux регистрозависимые имена файлов. Файлы с именами файл.txt и Файл.txt это разные файлы в отличие от Windows.

Процедура получения уникального последовательного номера.

CREATE OR REPLACE FUNCTION public.getnewid ( out doc integer)
RETURNS integer AS
$body$
BEGIN
update fff set nomer = nomer +1 where docid =1;
 select nomer into doc  from fff where docid = 1;
END;
$body$
LANGUAGE 'plpgsql'
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER
COST 100;

Из кода программы она вызывается так.

GetDocId.StoredProcName := 'getnewid';
GetDocId.ExecProc;
Zakaz.FieldByName('idd').AsString := GetDocId.Params.ParamValues['doc'];

 

Втора процедура для подсчета суммы заказа.

 

CREATE OR REPLACE FUNCTION public.sumdoc ( iddd varchar )
RETURNS void AS
$body$
BEGIN
update zakaz set summa = (select sum(cena * kolvo) from zakdetail where zid  = iddd) where idd = iddd;
END;
$body$
LANGUAGE 'plpgsql'
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER
COST 100;

Из программы она вызывается так.

PGSum.StoredProcName := 'sumdoc';
PGSum.Prepare;// получение параметров процедуры  с  сервера
PGSum.ParamByName('iddd').AsString := Zakaz.fieldbyname('idd').AsString;
PGSum.ExecProc;

 

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

Для отладки рабочих запрос я использовал компонент TPgSQLMonitor который работает в  связке с программой DBMonitor, данная программа скачивается отсюда. Компонент добавляется на форму или датамодуль  работы с данными. У него устанавливается свойство Active:= true,  затем запускается программа dbmonitor,и все запросы и так же их параметры будут отображаться в данной программе.

pgdac monitor

Если в программе требуется изменять какие либо данные без из отображения то можно использовать компонент TPgSQL  данный компонент позволяет работать с запросами и хранимыми процедурами без отображения данных. Просто добавляете запрос. Устанавливаете параметры и выполняете его. 

procedure TForm1.ToolButton15Click(Sender: TObject);
begin
PgSQL1.SQL.Add('update tovar set cena=cena * 1.25 where gruppa = 1');
PgSQL1.Execute;
end;

Если же требуется работать с портянками кода вроде такого.

INSERT INTO public.tovar ("tid", "name", "cena", "kolvo", "gruppa")
VALUES  
(323, E'ПО ЛК KAV на 1 год 2 ПК BOX', 1200, 9, E'Антивирусы'),
(324, E'ПО ЛК KAV на 1 год 2 ПК Renewal Card (Продление)', 990, 10, E'Антивирусы'),
(325, E'ПО ЛК KIS на 1 год 2 ПК BOX', 1600, 6, E'Антивирусы'),
(326, E'ПО ЛК KIS на 1 год 2 ПК Renewal Card (Продление)', 1320, 10, E'Антивирусы'),
(327, E'ПО ЛК KIS на 1 год 3 ПК BOX', 1990, 3, E'Антивирусы'),
(328, E'ПО ЛК KIS на 1 год 3 ПК Renewal Card (Продление)', 1490, 1, E'Антивирусы'),
....
(10001, E'ПО ЛК KIS на 1 год 5 ПК DVD BOX', 3899, 3, E'Антивирусы'),
(10002, E'ПО ЛК KIS на 1 год 5 ПК Renewal Card (продление)', 2899, 3, E'Антивирусы');

 То можно использовать TPgScript, этот компонент как раз и предназначен для работы с большими объемами sql кода. Можно загрузить в  него sql файл и выполнить его.

procedure TForm1.ToolButton15Click(Sender: TObject);
begin
PgScript1.SQL.LoadFromFile('c:\test.sql');
PgScript1.Execute;
end;

 Либо же сразу выполнить файл.

procedure TForm1.ToolButton15Click(Sender: TObject);
begin
PgScript1.ExecuteFile('c:\test.sql');
end;

Так же в наборе компонентов присутствует TPgDump,  он предназначен  для сохранения и восстановления базы данных.  Я добавил на форму PgDump и  ProgressBar, а так же две кнопки, одна для сохранения данных вторая для восстановления.

Код сохранения данных.

procedure TForm1.Button2Click(Sender: TObject);
begin
  PgDump1.TableNames := 'buhotchet,fff, klietns,tovar,zakaz,zakdetail';// указываем таблицы которые требуется сохранить
  PgDump1.Mode := dmAll;
  try
    PgDump1.BackupToFile('o:\test\dump.data');
    ShowMessage('Сохранение успешно!');
  except
    ShowMessage('Ошибка сохранения!');
  end;
end;

 Код восстановления данных

procedure TForm1.Button3Click(Sender: TObject);
begin
  ProgressBar1.Position := 0;
  try
    PgDump1.RestoreFromFile('o:\test\dump.data');
    ShowMessage('Данные успешно восстановлены!');
  except
   ShowMessage('Ошибка восстановления!');
  end;
end;

 А для отображения процесса работы с данными добавил следующий код.

// сохранение данных
procedure TForm1.PgDump1BackupProgress(Sender: TObject; ObjectName: string; ObjectNum, ObjectCount, Percent: Integer);
begin
  ProgressBar1.Position := ObjectNum;
  ProgressBar1.Max := ObjectCount;
end;
// восстановление данных
procedure TForm1.PgDump1RestoreProgress(Sender: TObject; Percent: Integer);
begin
  ProgressBar1.Position := Percent;
end;

 Вообще компонент TPgDump имеет много опций для работы с данными, но я не буду заострять на нем  внимание.

Так же PgDac поддерживает шифрование данных. Для этого используется компонент TPgEncryptor, он поддерживает несколько алгоритмов шифрования. Я добавил компонент на форму и выставил у него настройки. 

PgEncryptor1.EncryptionAlgorithm:= eaAES128;
PgEncryptor1.HashAlgorithm:= haMD5;

 

Затем создал таблицу, которая будет шифроваться. 

TPgEncryptor  поддерживает шифрование для следующих типов данных - ftString, ftWideString, ftBytes, ftVarBytes, ftBlob, ftMemo, ftWideMemo, учитывайте это при необходимости шифровать данные. Это обусловлено тем что зашифрованные данные лежат в ячейках  таблиц, они состоят из самих зашифрованных данных, а так же хеша данных для проверки корректности расшифровки. Поэтому числовые  столбцы шифровать не получиться.

А затем написал следующий  код.

procedure TForm1.Button1Click(Sender: TObject);
begin
  if EditPass.Text <> '' then
  begin
    BuhQuery.Encryption.Encryptor := PgEncryptor1;
    BuhQuery.Encryption.Fields := 'mesyac, summa';// добавляем столбцы для шифровки
    BuhQuery.Encryption.Encryptor.Password := EditPass.Text;
    BuhQuery.DataTypeMap.AddFieldNameRule('mesyac', ftString);
    BuhQuery.DataTypeMap.AddFieldNameRule('summa', ftString);
    BuhQuery.Open;
  end
  else
  begin
    BuhQuery.Encryption.Encryptor := nil;
    BuhQuery.Open;
  end;
end;

Рузультат работы с паролем и без.

pgdac encryption

 

Для работы с событиями в PostgreSQL у  PgDac  имеется компонента TPgAlert. События это механизм обмена сообщениями между процессами в PostgreSQL.  Допустим нам необходимо обновлять грид в программе  при добавление в таблицу новых данных. Для этого у таблицы создается триггер на добавления данных, который в случае  если данные верны посылает сообщение серверу что данные добавлены, а программы потом получают от сервера это сообщение и обновляют данные.  Вот для получения этих сообщение от сервера и нужен TPgAlert.   Я добавил его на форму и создал обработчик события OnEvent

procedure TForm1.PgAlerterEvent(Sender: TObject; const EventName: String;
  PID: Integer; const EventMessage: String);
begin
if EventMessage  = 'newzakaz' then
Zakaz.Refresh;
end;
 

После этого у компонента  PgAlerter настроил свойство Events на канал work. С данного канала компонент будет слушать сообщения. Вообще там длинна сообщения может быть примерно 8000 символов, можно целый внутренний чат организовать при желание (но зачем ?????).

А затем на сервере  создал правило для обработки новых данных.

CREATE RULE zakaz_rl AS ON INSERT TO public.zakaz 
DO (SELECT pg_notify('work'::text, 'newzakaz'::text) AS pg_notify;);

 Теперь при добавление данных во всех копиях программы будет обновлен список заказов.

Я не стал описывать остальные компоненты из набора поскольку  не было нужды их применять. По мере того как буду их использовать буду описывать работу с ними.

Приобрести PgDAC можно тут 

 

Комментарии   
0 #7 Sasha 28.12.2015 20:15
Цитирую kylt_lichnosti:
И дата в комментариях не правильно отображается еще. :-)

Да тут проблема была с темой оформления для jcomments, сейчас все поправил.
Цитировать
0 #6 kylt_lichnosti 22.12.2015 19:57
И дата в комментариях не правильно отображается еще. :-)
Цитировать
0 #5 kylt_lichnosti 22.12.2015 19:56
Через адо, наверное, еще можно работать.
Цитировать
0 #4 Sasha 21.12.2015 20:41
Цитирую uranic:
Не совсем верно:
В PostgreSQL имена таблиц и процедур пишутся с маленькой буквы, это необходимо для кросплатформенной совместимости

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

Про данный момент я был не вкурсе,я поверхностно почитал про pg
Цитировать
0 #3 Sasha 21.12.2015 20:40
Цитирую uranic:
unidac по сути включает в себя pgDAC

я не стал останавливаться на этом моменте
Цитировать
0 #2 uranic 21.12.2015 20:04
unidac по сути включает в себя pgDAC
Цитировать
0 #1 uranic 21.12.2015 20:03
Не совсем верно:
В PostgreSQL имена таблиц и процедур пишутся с маленькой буквы, это необходимо для кросплатформенн ой совместимости

Это по умолчанию такое поведение, можно настроить регистронезавис имые таблицы
Цитировать
Добавить комментарий