Войти в систему

Home
    - Создать дневник
    - Написать в дневник
       - Подробный режим

LJ.Rossia.org
    - Новости сайта
    - Общие настройки
    - Sitemap
    - Оплата
    - ljr-fif

Редактировать...
    - Настройки
    - Список друзей
    - Дневник
    - Картинки
    - Пароль
    - Вид дневника

Сообщества

Настроить S2

Помощь
    - Забыли пароль?
    - FAQ
    - Тех. поддержка



Пишет ringill ([info]ringill)
@ 2006-10-30 17:22:00


Previous Entry  Add to memories!  Tell a Friend!  Next Entry
Работа с Oracle LOB-s в VisualWorks Smalltalk
Чтобы передать LOB (large object) с клиента в базу данных Oracle, надо сделать три вещи:
1. Создать временный LOB [OCILobCreateTemporary()].
2. Записать в него данные [OCILobWrite()].
3. «Привязать» созданный LOB к запросу INSERT или UPDATE [OCIBindByPos() или OCIBindByName()]

В стандартном пакете VisualWorks OracleEXDI, в классе OracleSession есть метод bindVariableAsLob. Он выполняет из перечисленных трёх пунктов только последний и, разумеется, не работает.

Для OCILobCreateTemporary() обёртки нет, но её несложно добавить, по аналогии с существующими, в класс OracleLOBProxy.
Для записи данных в созданный LOB в классе OracleLOBProxy есть метод writeFrom, но он написан чрезвычайно криво и неэффективно. Я его переписал.
Соответственно, метод bindVariableAsLob пришлось тоже немного модифицировать.

Также потребовал правки метод mallocForParameter в классе OracleLargeObjectBuffer. Он выделяет столько дескрипторов для LOB-а, сколько в LOB-е байт, тогда как достаточно одного дескриптора.

Публикации в виде патча написанное не заслуживает, т.к. содержит только то, что понадобилось мне, и не очень хорошо «вписывается» в структуру OracleEXDI.

А вот код метода writeFrom:
writeFrom: startingPosition with: aByteArray
	| xif conn rtval arraySize amountPointer errorClosure startPos |
	conn := self session connection.
	xif := conn class xif.
	arraySize := aByteArray size.
	startPos := startingPosition.
	errorClosure := 
		[ | errs |
			errs := conn getErrors.
			^conn class unableToWriteLobDataSignal raiseWith:
                                errs errorString: errs first dbmsErrorString.
		].

	amountPointer := 123 gcCopyToHeap.
	[arraySize > 0] whileTrue:
		[
		amountPointer contents: arraySize.
		self setBuffer: (aByteArray copyFrom: startPos to: aByteArray size).
		rtval := self writeLobDataExternalFrom: startPos amount: amountPointer
                                      piece: xif OCI_ONE_PIECE bufferLength: arraySize.
		(rtval == xif OCI_SUCCESS or:
                   [ (rtval == xif OCI_SUCCESS_WITH_INFO) or:
                     [rtval == xif OCI_NEED_DATA ]] ) ifFalse: [ errorClosure value ].
		(amountPointer contents == 0) ifTrue: [ errorClosure value ].
		startPos := startPos + amountPointer contents.
		arraySize := arraySize - amountPointer contents.
		].

	^self