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