@@ -49,8 +49,11 @@ cdef class ThickVarImpl(BaseVarImpl):
4949 dpiDataBuffer * dbvalue
5050 const char * name_ptr
5151 bytes name_bytes
52+ object cursor
5253 if self .dbtype.num == DB_TYPE_NUM_CURSOR:
53- for i in range (self .num_elements):
54+ for i, cursor in enumerate (self ._values):
55+ if cursor is not None and cursor._impl is None :
56+ errors._raise_err(errors.ERR_CURSOR_NOT_OPEN)
5457 if self ._data[i].isNull:
5558 continue
5659 dbvalue = & self ._data[i].value
@@ -93,6 +96,12 @@ cdef class ThickVarImpl(BaseVarImpl):
9396 Internal method that finalizes initialization of the variable.
9497 """
9598 BaseVarImpl._finalize_init(self )
99+ if self .dbtype._native_num in (
100+ DPI_NATIVE_TYPE_LOB,
101+ DPI_NATIVE_TYPE_OBJECT,
102+ DPI_NATIVE_TYPE_STMT,
103+ ):
104+ self ._values = [None ] * self .num_elements
96105 self ._create_handle()
97106
98107 cdef list _get_array_value(self ):
@@ -103,18 +112,66 @@ cdef class ThickVarImpl(BaseVarImpl):
103112 return [self ._get_scalar_value(i) \
104113 for i in range (self .num_elements_in_array)]
105114
106- cdef object _get_cursor_value(self , dpiDataBuffer * dbvalue):
115+ cdef object _get_cursor_value(self , dpiDataBuffer * dbvalue, uint32_t pos):
116+ """
117+ Returns the cursor stored in the variable at the given position. If a
118+ cursor was previously available, use it instead of creating a new one.
119+ """
107120 cdef:
108121 ThickCursorImpl cursor_impl
109122 object cursor
110- cursor = self ._conn.cursor()
123+ cursor = self ._values[pos]
124+ if cursor is None :
125+ cursor = self ._values[pos] = self ._conn.cursor()
111126 cursor_impl = < ThickCursorImpl> cursor._impl
112127 if dpiStmt_addRef(dbvalue.asStmt) < 0 :
113128 _raise_from_odpi()
114129 cursor_impl._handle = dbvalue.asStmt
115130 cursor_impl._fixup_ref_cursor = True
116131 return cursor
117132
133+ cdef object _get_dbobject_value(self , dpiDataBuffer * dbvalue,
134+ uint32_t pos):
135+ """
136+ Returns the DbObject stored in the variable at the given position. If a
137+ DbObject was previously available, use it instead of creating a new
138+ one, unless the handle has changed.
139+ """
140+ cdef:
141+ ThickDbObjectImpl obj_impl
142+ object obj
143+ obj = self ._values[pos]
144+ if obj is not None :
145+ obj_impl = < ThickDbObjectImpl> obj._impl
146+ if obj_impl._handle == dbvalue.asObject:
147+ return obj
148+ obj_impl = ThickDbObjectImpl.__new__ (ThickDbObjectImpl)
149+ obj_impl.type = self .objtype
150+ if dpiObject_addRef(dbvalue.asObject) < 0 :
151+ _raise_from_odpi()
152+ obj_impl._handle = dbvalue.asObject
153+ obj = self ._values[pos] = PY_TYPE_DB_OBJECT._from_impl(obj_impl)
154+ return obj
155+
156+ cdef object _get_lob_value(self , dpiDataBuffer * dbvalue, uint32_t pos):
157+ """
158+ Returns the LOB stored in the variable at the given position. If a LOB
159+ was previously created, use it instead of creating a new one, unless
160+ the handle has changed.
161+ """
162+ cdef:
163+ ThickLobImpl lob_impl
164+ object lob
165+ lob = self ._values[pos]
166+ if lob is not None :
167+ lob_impl = < ThickLobImpl> lob._impl
168+ if lob_impl._handle == dbvalue.asLOB:
169+ return lob
170+ lob_impl = ThickLobImpl._create(self ._conn_impl, self .dbtype,
171+ dbvalue.asLOB)
172+ lob = self ._values[pos] = PY_TYPE_LOB._from_impl(lob_impl)
173+ return lob
174+
118175 cdef object _get_scalar_value(self , uint32_t pos):
119176 """
120177 Internal method to return the value of the variable at the given
@@ -182,6 +239,10 @@ cdef class ThickVarImpl(BaseVarImpl):
182239 dpiVar_release(orig_handle)
183240
184241 cdef int _set_cursor_value(self , object cursor, uint32_t pos) except - 1 :
242+ """
243+ Sets a cursor value in the variable. If the cursor does not have a
244+ statement handle already, associate the one created by the variable.
245+ """
185246 cdef:
186247 ThickCursorImpl cursor_impl = cursor._impl
187248 dpiData * data
@@ -197,9 +258,30 @@ cdef class ThickVarImpl(BaseVarImpl):
197258 if dpiStmt_addRef(data.value.asStmt) < 0 :
198259 _raise_from_odpi()
199260 cursor_impl._handle = data.value.asStmt
261+ self ._values[pos] = cursor
200262 cursor_impl._fixup_ref_cursor = True
201263 cursor_impl.statement = None
202264
265+ cdef int _set_dbobject_value(self , object obj, uint32_t pos) except - 1 :
266+ """
267+ Sets an object value in the variable. The object is retained so that
268+ multiple calls to getvalue() return the same instance.
269+ """
270+ cdef ThickDbObjectImpl obj_impl = < ThickDbObjectImpl> obj._impl
271+ if dpiVar_setFromObject(self ._handle, pos, obj_impl._handle) < 0 :
272+ _raise_from_odpi()
273+ self ._values[pos] = obj
274+
275+ cdef int _set_lob_value(self , object lob, uint32_t pos) except - 1 :
276+ """
277+ Sets a LOB value in the variable. The LOB is retained so that multiple
278+ calls to getvalue() return the same instance.
279+ """
280+ cdef ThickLobImpl lob_impl = < ThickLobImpl> lob._impl
281+ if dpiVar_setFromLob(self ._handle, pos, lob_impl._handle) < 0 :
282+ _raise_from_odpi()
283+ self ._values[pos] = lob
284+
203285 cdef int _set_num_elements_in_array(self , uint32_t num_elements) except - 1 :
204286 """
205287 Sets the number of elements in the array.
@@ -217,26 +299,26 @@ cdef class ThickVarImpl(BaseVarImpl):
217299 dpiDataBuffer temp_dbvalue
218300 dpiDataBuffer * dbvalue
219301 dpiBytes * as_bytes
220- bint needs_set
221302 dpiData * data
222303 data = & self ._data[pos]
223304 data.isNull = (value is None )
224305 if not data.isNull:
225- if self .dbtype.num == DB_TYPE_NUM_CURSOR :
306+ if self .dbtype._native_num == DPI_NATIVE_TYPE_STMT :
226307 self ._set_cursor_value(value, pos)
308+ elif self .dbtype._native_num == DPI_NATIVE_TYPE_LOB:
309+ self ._set_lob_value(value, pos)
310+ elif self .dbtype._native_num == DPI_NATIVE_TYPE_OBJECT:
311+ self ._set_dbobject_value(value, pos)
227312 else :
228- needs_set = self .dbtype._native_num == DPI_NATIVE_TYPE_BYTES \
229- or (self .dbtype._native_num == DPI_NATIVE_TYPE_LOB \
230- and not isinstance (value, PY_TYPE_LOB))
231- if needs_set:
313+ if self .dbtype._native_num == DPI_NATIVE_TYPE_BYTES:
232314 dbvalue = & temp_dbvalue
233315 else :
234316 dbvalue = & data.value
235317 if self ._buf is None :
236318 self ._buf = StringBuffer.__new__ (StringBuffer)
237319 _convert_from_python(value, self .dbtype, self .objtype, dbvalue,
238- self ._buf, self , pos )
239- if needs_set :
320+ self ._buf)
321+ if self .dbtype._native_num == DPI_NATIVE_TYPE_BYTES :
240322 as_bytes = & dbvalue.asBytes
241323 if dpiVar_setFromBytes(self ._handle, pos, as_bytes.ptr,
242324 as_bytes.length) < 0 :
@@ -270,15 +352,20 @@ cdef class ThickVarImpl(BaseVarImpl):
270352 object value
271353 data = & data[pos]
272354 if not data.isNull:
273- if self .dbtype.num == DB_TYPE_NUM_CURSOR:
274- return self ._get_cursor_value(& data.value)
275- if self .encoding_errors is not None :
276- encoding_errors_bytes = self .encoding_errors.encode()
277- encoding_errors = encoding_errors_bytes
278- value = _convert_to_python(self ._conn_impl, self .dbtype,
279- self .objtype, & data.value,
280- self ._preferred_num_type,
281- self .bypass_decode, encoding_errors)
355+ if self .dbtype._native_num == DPI_NATIVE_TYPE_STMT:
356+ value = self ._get_cursor_value(& data.value, pos)
357+ elif self .dbtype._native_num == DPI_NATIVE_TYPE_LOB:
358+ value = self ._get_lob_value(& data.value, pos)
359+ elif self .dbtype._native_num == DPI_NATIVE_TYPE_OBJECT:
360+ value = self ._get_dbobject_value(& data.value, pos)
361+ else :
362+ if self .encoding_errors is not None :
363+ encoding_errors_bytes = self .encoding_errors.encode()
364+ encoding_errors = encoding_errors_bytes
365+ value = _convert_to_python(self ._conn_impl, self .dbtype,
366+ self .objtype, & data.value,
367+ self ._preferred_num_type,
368+ self .bypass_decode, encoding_errors)
282369 if self .outconverter is not None :
283370 value = self .outconverter(value)
284371 return value
0 commit comments