ODBC

Данная реализация тестировалась с менеджерами драйверов unixODBC и iODBC2, с драйверами для MySQL и Postgres.
Чтобы построить приложение с использованием ODBC его нужно слинковать с библиотекой libclip-odbc.so. Например:
clip -e test.prg -lclip-odbc
Для подключения к серверу используйте конструктор класса TConnect в следующем синтаксисе:
ConnectNew("ODBC",<DSN>,[<login>],[<pwd>]), где
"ODBC" - идентификатор СУБД;
<DSN> - Data Source Name (источник данных. См. файл odbc.ini);
<login> - логин пользователя;
<pwd> - пароль пользователя.
Реализация ODBC для Clip, в отличие от реализаций других СУБД, имеет ряд ограничений по использованию. Например, поскольку ODBC не имеет стандартного механизма для выяснения значений ROWID вновь вставленной записи, вы не сможете изменять вновь вставленные записи путем изменения записи TRowset. Также, поскольку под руками не было какого-нибудь драйвера и СУБД для тестирования, механизм передачи параметров SQL-запросу лишь эмулируется (как это сделано в реализациях для MySQL и Postgres).
Для связи записей набора (TRowset) и физической таблицы базы данных испольуется поле, указываемое в дополнительном, 6-ом параметре функции CreateRowset(). Для полноценной работы с набором (с возможностью отражения производимых изменений набора записей в базе данных) в список запрашиваемых полей запроса SELECT следует явно включать зто поле.
В операторах автоматического отражения (deleteSQL и updateSQL, передаваемых конструктору TRowset) следует использовать предложение типа WHERE id=:id, где id - имя идентифицирующего поля (например, ROWID в Oracle, OID в Postgres). Например:
DELETE FROM mytable WHERE id=:id
UPDATE mytable SET fname=:fname,lname=:lname WHERE id=:id
Поскольку интерфейс ODBC не предоставляет соответствующей возможности, уровень изоляции необходимо выставлять средствами используемого сервера SQL. Параметр <cIsolation> функций ConnectNew() и TConnect:Start() игнорируется.

В качестве простейшего примера использования clip-odbc, см. утилиту my_isql, которая представляет собой простой фронтенд, аналогичный isql. Вот ее текст:

    LOCAL conn,rs,data
    LOCAL sql := ""
    LOCAL I := 1
    LOCAL user		// -u
    LOCAL passwd	// -p
    LOCAL db

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

    DO WHILE param(I) != NIL
    	IF param(I) == "--help" .OR. param(I) == "-?"
    		Usage()
    		QUIT
    	ELSEIF param(I) == "-h"
    		host := param(++I)
    	ELSEIF param(I) == "-u"
    		user := param(++I)
    	ELSEIF param(I) == "-p"
    		passwd := param(++I)
    	ELSE
    		db := param(I)
    	ENDIF
    	I++
    ENDDO

    IF EMPTY(db)
    	Usage()
    	QUIT
    ENDIF

    CLS

    BEGIN SEQUENCE
    	conn := ConnectNew("ODBC",db,user,passwd)
    RECOVER USING e
    	QUIT
    END SEQUENCE

    DO WHILE UPPER(sql := GetCommand()) != "Q"
    	IF UPPER(LEFT(sql,6))=="SELECT"
    		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

    PROCEDURE Usage()
    	?? "my_isql  Ver 1.00 (simple ODBC frontend) (c) by ITK Ltd., by Rusty"
    	? "This software comes with ABSOLUTELY NO WARRANTY."
    	?
    	? "Usage: my_isql [OPTIONS] "
    	?
    	? "  -?, --help     Display this help and exit"
    	? "  -u             User for login if not current user"
    	? "  -p             Password to use when connecting to server"
    	?
    RETURN