СУБД Postgres


Данная реализация DBFSQL для Postgres тестировалась с версией PostgreSQL 6.5.3.

Чтобы построить приложение с использованием DBFSQL для Postgres его нужно слинковать с библиотекой libclip-postgres.so

Для подключения к серверу используйте конструктор класса TConnect в следующем синтаксисе:

ConnectNew("PG",[<host>],[<port>],[<login>], [<pwd>],[<dbName>],[<pgtty>], [<pgopt>]), где

"PG" - строка, идентифицирующая СУБД Postgres;

<host> - имя хоста (DNS) сервера Postgres;

<port> - номер порта сервера Postgres;

<login> - логин пользователя;

<pwd> - пароль пользователя.

<dbName> - имя базы данных;

<pgtty> - терминал для вывода сообщений от клиента;

<pgopt> - дополнительные опции соединения;

Если любой из аргументов опущен, используется соответствующая переменная окружения (см. документацию по Postgres). Если переменная окружения также не установлена, используется значение по умолчанию.

Все аргументы должны представлять собой текстовые значения, например pgport должно иметь значение "5234".

Postgres не предоставляет обычного для многих других СУБД механизма передачи параметров операторам SQL. Этот механизм лишь сзмулирован в данной реализации. Позтому повышения производительности при многократном выполнении одного и того же оператора SQL с разными параметрами не ждите. Сервер все равно будет обрабатывать каждый оператор в стандартном режиме (parser, planner, optimizer и т.д.).

Для связи записей набора (TRowset) и физической таблицы базы данных Postgres испольуется поле OID, которое присутствует во всех таблицах Postgres. Для полноценной работы с набором (с возможностью отражения производимых изменений набора записей в базе данных) в список запрашиваемых полей запроса SELECT следует явно включать поле OID. Например:

SELECT oid,* FROM mytable

В операторах автоматического отражения (deleteSQL и updateSQL, передаваемых конструктору TRowset) следует использовать предложение WHERE oid=:oid. Например:

DELETE FROM mytable WHERE oid=:oid

UPDATE mytable SET fname=:fname,lname=:lname WHERE oid=:oid

Postgres может возвращать запрашиваемые записи (в терминологии Postgres - tuples) в двух видах - текстовом и бинарном. Обычный SELECT возвращает записи в текстовом виде. Для того чтобы получить бинарные записи, следует сначала создать бинарный курсор, а затем для него выполнить команду FETCH. Например:
 conn:Command("BEGIN")
 conn:Command("DECLARE mycur BINARY CURSOR FOR SELECT oid,* FROM mytable")
 rs := conn:CreateRowset("FETCH ALL FROM mycur")
 conn:Command("END")
Для правильной работы с датами следует правильно установить переменную окружения PGDATESTYLE (в соответствии со значением PGDATESTYLE, используемым сервером Postgres). Например:
 export PGDATESTYLE=EURO
Возможные значения PGDATESTYLE:
 Style      Date            Datetime
 --------------------------------------------------------
 ISO        1999-07-17      1999-07-17 07:09:18+01
 SQL        17/07/1999      17/07/1999 07:09:19.00 BST
 POSTGRES   17-07-1999      Sat 17 Jul 07:09:19 1999 BST
 GERMAN     17.07.1999      17.07.1999 07:09:19.00 BST
 NONEURO    07-17-1999      Sat Jul 17 07:09:19 1999 BST
 US         07-17-1999      Sat Jul 17 07:09:19 1999 BST
 EURO       17-07-1999      Sat 17 Jul 07:09:19 1999 BST


Реализованы следующие типы Postgres:
Тип Postgres             Тип Clipper
ABSTIME DATE BOOL LOGICAL BOX Array {{x1,y1},{x2,y2}}, x1,y1,x2,y2 - NUMERIC BPCHAR CHARACTER BYTEA CHARACTER CHAR CHARACTER CID NUMERIC CIDR Array {x1,...}, x1,... - NUMERIC CIRCLE Array {x1,x2,x3}, x1,x2,x3 - NUMERIC DATE DATE FILENAME CHARACTER FLOAT4 NUMERIC FLOAT8 NUMERIC INET Array {x1,x2,x3,x4,x5}, x1,x2,x3,x4,x5 - NUMERIC INT2 NUMERIC INT28 Array {x1,x2,...,x8}, x1,x2,...,x8 - NUMERIC INT4 NUMERIC LSEG Array {{x1,y1},{x2,y2}}, x1,y1,x2,y2 - NUMERIC MONEY NUMERIC NAME CHARACTER NUMERIC NUMERIC OID NUMERIC OID8 Array {x1,x2,...,x8}, x1,x2,...,x8 - NUMERIC PATH CHARACTER POINT Array {x,y}, x,y - NUMERIC POLYGON Array {{x1,y1},...{xn,yn}}, x1..xn, y1...yn - NUMERIC RELTIME NUMERIC TEXT CHARACTER TIMESTAMP DATE VARCHAR CHARACTER XID NUMERIC

В качестве простейшего примера использования SQL с СУБД Postgres в комплект поставки включен файл mypsql.prg, функционально дублирующий утилиту psql из комплекта поставки Postgres. Вот ее текст:
PROCEDURE Main

LOCAL conn,rs,data
LOCAL sql := ""
LOCAL I

CLS
ErrorBlock({|e| SQLError(e)})

conn := ConnectNew("PG",,,,,"test")
DO WHILE UPPER(sql := GetCommand()) != "Q"
	IF UPPER(LEFT(sql,6))=="SELECT" .OR. UPPER(LEFT(sql,5))=="FETCH"
		BEGIN SEQUENCE
			rs := conn:CreateRowset(sql)
		RECOVER USING e
			LOOP
		END SEQUENCE
		FOR I:=1 TO rs:NFields()
			?? PADR(rs:FieldName(I),10),"|"
		NEXT
		?
		FOR I:=1 TO rs:NFields()
			?? "----------","|"
		NEXT
		DO WHILE !rs:Eof()
			?
			data := rs:Read()
			FOR I:=1 TO rs:NFields()
				tmp := data[HASHSTR(UPPER(rs:FieldName(I)))]
				IF VALTYPE(tmp)=="A"
					?? "{...}     ","|"
				ELSEIF tmp==NIL
					?? "NIL       ","|"
				ELSE
					?? PADR(data[HASHSTR(UPPER(rs:FieldName(I)))],10),"|"
				ENDIF
			NEXT
			rs:Skip()
		ENDDO
		rs:Destroy()
	ELSE
		BEGIN SEQUENCE
			?? LEFT(sql,LEN(sql)-1)+": "
			conn:Command(sql)
			?? "OK"
		RECOVER USING e
			LOOP
		END SEQUENCE
	ENDIF
	?
ENDDO
conn:Destroy()

RETURN

FUNCTION GetCommand()
	LOCAL ret := ""
	LOCAL tmp := ""
	LOCAL first := .T.

	@ MAXROW(),0 SAY ""
	DO WHILE !(";" $ tmp) .AND. ALLTRIM(UPPER(ret)) != "Q"
		IF first
			ACCEPT "SQL> " TO tmp
			first := .F.
		ELSE
			ACCEPT "SQL---> " TO tmp
		ENDIF
		ret += tmp + " "
	ENDDO
RETURN ALLTRIM(ret)

FUNCTION SQLError(e)
	?? e:operation
	BREAK(e)
RETURN NIL