СУБД Postgres

Данная реализация DBFSQL для Postgres тестировалась с версией PostgreSQL 6.5.3.
Чтобы построить приложение с использованием DBFSQL для Postgres его нужно слинковать с библиотекой libclip-postgres.so
Для подключения к серверу используйте конструктор класса TConnect в следующем синтаксисе:
ConnectNew("PG",[<host>],[<port>],[<login>], [<pwd>],[<dbName>],[<pgtty>], [<pgopt>],NIL,[<cIsolation>]), где
"PG" - строка, идентифицирующая СУБД Postgres;
<host> - имя хоста (DNS) сервера Postgres;
<port> - номер порта сервера Postgres;
<login> - логин пользователя;
<pwd> - пароль пользователя;
<dbName> - имя базы данных;
<pgtty> - терминал для вывода сообщений от клиента;
<pgopt> - дополнительные опции соединения;
<cIsolation> - уровень изоляции по умолчанию.
Если любой из аргументов опущен, используется соответствующая переменная окружения (см. документацию по 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:Start()
     conn:Command("DECLARE mycur BINARY CURSOR FOR SELECT oid,* FROM mytable")
     rs := conn:CreateRowset("FETCH ALL FROM mycur")
     conn:Commit()

Возможные значения параметра <cIsolation> для ConnectNew() и TConnect:Start():
"READ COMMITTED"
"SERIALIZABLE"
Реализованы следующие типы 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