Skip to content

Commit 24ec444

Browse files
Various performance improvements.
1 parent 7a01526 commit 24ec444

21 files changed

+497
-293
lines changed

doc/src/release_notes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ Common Changes
3737
columns which have the check constraint ``IS JSON FORMAT OSON`` enabled.
3838
#) Added boolean property :data:`FetchInfo.is_oson` which is set when a column
3939
has the check constraint "IS JSON FORMAT OSON" enabled.
40+
#) A number of performance improvements were made.
4041
#) Error ``DPY-2045: arraysize must be an integer greater than zero`` is now
4142
raised when an invalid value is specified for the attribute
4243
:data:`Cursor.arraysize`. Previously a variety of errors (``TypeError``,

src/oracledb/base_impl.pxd

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ cdef enum:
4343
NUM_TYPE_STR = 3
4444

4545
cdef enum:
46+
DB_TYPE_NUM_MIN = 2000
47+
DB_TYPE_NUM_MAX = 2032
48+
4649
DB_TYPE_NUM_BFILE = 2020
4750
DB_TYPE_NUM_BINARY_DOUBLE = 2008
4851
DB_TYPE_NUM_BINARY_FLOAT = 2007
@@ -74,6 +77,21 @@ cdef enum:
7477
DB_TYPE_NUM_VARCHAR = 2001
7578
DB_TYPE_NUM_XMLTYPE = 2032
7679

80+
cdef enum:
81+
NATIVE_TYPE_NUM_BOOLEAN = 3011
82+
NATIVE_TYPE_NUM_BYTES = 3004
83+
NATIVE_TYPE_NUM_DOUBLE = 3003
84+
NATIVE_TYPE_NUM_FLOAT = 3002
85+
NATIVE_TYPE_NUM_INTERVAL_DS = 3006
86+
NATIVE_TYPE_NUM_INTERVAL_YM = 3007
87+
NATIVE_TYPE_NUM_INT64 = 3000
88+
NATIVE_TYPE_NUM_JSON = 3013
89+
NATIVE_TYPE_NUM_LOB = 3008
90+
NATIVE_TYPE_NUM_OBJECT = 3009
91+
NATIVE_TYPE_NUM_ROWID = 3012
92+
NATIVE_TYPE_NUM_STMT = 3010
93+
NATIVE_TYPE_NUM_TIMESTAMP = 3005
94+
7795
cdef enum:
7896
CS_FORM_IMPLICIT = 1
7997
CS_FORM_NCHAR = 2
@@ -100,6 +118,7 @@ cdef class DbType:
100118
readonly uint32_t num
101119
readonly str name
102120
readonly uint32_t default_size
121+
uint32_t _native_num
103122
uint32_t _buffer_size_factor
104123
str _ora_name
105124
uint8_t _ora_type_num
@@ -115,6 +134,18 @@ cdef class DbType:
115134
cdef DbType _from_ora_type_and_csfrm(uint8_t ora_type_num, uint8_t csfrm)
116135

117136

137+
cdef class DefaultsImpl:
138+
cdef:
139+
public uint32_t arraysize
140+
public str config_dir
141+
public bint fetch_lobs
142+
public bint fetch_decimals
143+
public uint32_t prefetchrows
144+
public uint32_t stmtcachesize
145+
146+
cdef DefaultsImpl C_DEFAULTS
147+
148+
118149
cdef class Buffer:
119150
cdef:
120151
ssize_t _max_size, _size, _pos
@@ -426,6 +457,7 @@ cdef class BaseConnImpl:
426457

427458
cdef object _check_value(self, DbType dbtype, BaseDbObjectTypeImpl objtype,
428459
object value, bint* is_ok)
460+
cdef BaseCursorImpl _create_cursor_impl(self)
429461

430462

431463
cdef class BasePoolImpl:
@@ -450,6 +482,7 @@ cdef class BaseCursorImpl:
450482
public object outputtypehandler
451483
public object rowfactory
452484
public bint scrollable
485+
public bint set_input_sizes
453486
public list fetch_info_impls
454487
public list fetch_vars
455488
public list fetch_var_impls
@@ -474,9 +507,10 @@ cdef class BaseCursorImpl:
474507
uint32_t row_num,
475508
bint defer_type_assignment) except -1
476509
cdef int _close(self, bint in_del) except -1
477-
cdef int _create_fetch_var(self, object conn, object cursor,
478-
object type_handler, bint uses_fetch_info,
479-
ssize_t pos, FetchInfoImpl fetch_info) except -1
510+
cdef BaseVarImpl _create_fetch_var(self, object conn, object cursor,
511+
object type_handler, bint
512+
uses_fetch_info, ssize_t pos,
513+
FetchInfoImpl fetch_info)
480514
cdef object _create_row(self)
481515
cdef BaseVarImpl _create_var_impl(self, object conn)
482516
cdef int _fetch_rows(self, object cursor) except -1
@@ -486,8 +520,11 @@ cdef class BaseCursorImpl:
486520
cdef int _init_fetch_vars(self, uint32_t num_columns) except -1
487521
cdef bint _is_plsql(self)
488522
cdef int _perform_binds(self, object conn, uint32_t num_execs) except -1
523+
cdef int _prepare(self, str statement, str tag,
524+
bint cache_statement) except -1
489525
cdef int _reset_bind_vars(self, uint32_t num_rows) except -1
490526
cdef int _verify_var(self, object var) except -1
527+
cdef int bind_one(self, object cursor, object parameters) except -1
491528

492529

493530
cdef class FetchInfoImpl:

src/oracledb/base_impl.pyx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ cydatetime.import_datetime()
5656
include "impl/base/types.pyx"
5757

5858
from . import constants, errors, exceptions, utils
59-
from .defaults import defaults
6059

6160
cdef type PY_TYPE_ASYNC_CURSOR
6261
cdef type PY_TYPE_ASYNC_LOB
@@ -86,6 +85,7 @@ cdef int get_preferred_num_type(int16_t precision, int8_t scale):
8685

8786

8887
include "impl/base/constants.pxi"
88+
include "impl/base/defaults.pyx"
8989
include "impl/base/utils.pyx"
9090
include "impl/base/buffer.pyx"
9191
include "impl/base/oson.pyx"

src/oracledb/cursor.py

Lines changed: 25 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -34,28 +34,22 @@
3434
from . import __name__ as MODULE_NAME
3535
from . import errors
3636
from . import connection as connection_module
37-
from .defaults import defaults
3837
from .fetch_info import FetchInfo
3938
from .var import Var
4039
from .base_impl import DbType, DB_TYPE_OBJECT
4140
from .dbobject import DbObjectType
4241

4342

4443
class BaseCursor:
44+
_impl = None
45+
4546
def __init__(
4647
self,
4748
connection: "connection_module.Connection",
4849
scrollable: bool = False,
4950
) -> None:
50-
self._impl = None
5151
self.connection = connection
52-
self.statement = None
53-
self._set_input_sizes = False
54-
self._impl = connection._impl.create_cursor_impl()
55-
self._impl.scrollable = scrollable
56-
self._impl.arraysize = defaults.arraysize
57-
self._impl.prefetchrows = defaults.prefetchrows
58-
self._fetch_infos = None
52+
self._impl = connection._impl.create_cursor_impl(scrollable)
5953

6054
def __del__(self):
6155
if self._impl is not None:
@@ -124,58 +118,16 @@ def _prepare(
124118
"""
125119
Internal method used for preparing a statement for execution.
126120
"""
127-
self._impl.fetch_vars = None
128-
if not self._set_input_sizes:
129-
self._impl.bind_vars = None
130-
self._impl.bind_vars_by_name = None
131-
self._impl.bind_style = None
132121
self._impl.prepare(statement, tag, cache_statement)
133-
self.statement = statement
134-
self._impl.rowfactory = None
135-
self._fetch_infos = None
136122

137123
def _prepare_for_execute(self, statement, parameters, keyword_parameters):
138124
"""
139125
Internal method for preparing a statement for execution.
140126
"""
141-
142-
# verify parameters
143-
if statement is None and self.statement is None:
144-
errors._raise_err(errors.ERR_NO_STATEMENT)
145-
if keyword_parameters:
146-
if parameters:
147-
errors._raise_err(errors.ERR_ARGS_AND_KEYWORD_ARGS)
148-
parameters = keyword_parameters
149-
elif parameters is not None and not isinstance(
150-
parameters, (list, tuple, dict)
151-
):
152-
errors._raise_err(errors.ERR_WRONG_EXECUTE_PARAMETERS_TYPE)
153127
self._verify_open()
154-
impl = self._impl
155-
bind_vars = impl.bind_vars
156-
bind_style = impl.bind_style
157-
prepare_needed = statement and statement != self.statement
158-
if (
159-
not (prepare_needed and not self._set_input_sizes)
160-
and bind_vars is not None
161-
and parameters is not None
162-
):
163-
if (
164-
bind_style is dict
165-
and not isinstance(parameters, dict)
166-
or bind_style is not dict
167-
and isinstance(parameters, dict)
168-
):
169-
errors._raise_err(errors.ERR_MIXED_POSITIONAL_AND_NAMED_BINDS)
170-
171-
# prepare statement, if necessary
172-
if prepare_needed:
173-
self._prepare(statement)
174-
175-
# perform bind and execute
176-
self._set_input_sizes = False
177-
if parameters is not None:
178-
impl.bind_one(self, parameters)
128+
self._impl._prepare_for_execute(
129+
self, statement, parameters, keyword_parameters
130+
)
179131

180132
def _verify_fetch(self) -> None:
181133
"""
@@ -265,7 +217,7 @@ def bindnames(self) -> list:
265217
that a statement must have been prepared first.
266218
"""
267219
self._verify_open()
268-
if self.statement is None:
220+
if self._impl.statement is None:
269221
errors._raise_err(errors.ERR_NO_STATEMENT_PREPARED)
270222
return self._impl.get_bind_names()
271223

@@ -300,11 +252,10 @@ def description(self) -> tuple:
300252
cursor has not had an operation invoked via the execute() method yet.
301253
"""
302254
self._verify_open()
303-
if self._fetch_infos is None and self._impl.is_query(self):
304-
self._fetch_infos = [
255+
if self._impl.is_query(self):
256+
return [
305257
FetchInfo._from_impl(i) for i in self._impl.fetch_info_impls
306258
]
307-
return self._fetch_infos
308259

309260
@property
310261
def fetchvars(self) -> list:
@@ -314,7 +265,7 @@ def fetchvars(self) -> list:
314265
attribute. In particular, elements should not be removed or replaced.
315266
"""
316267
self._verify_open()
317-
return self._impl.fetch_vars
268+
return self._impl.get_fetch_vars()
318269

319270
def getarraydmlrowcounts(self) -> list:
320271
"""
@@ -491,9 +442,7 @@ def setinputsizes(self, *args: Any, **kwargs: Any) -> Union[list, dict]:
491442
errors._raise_err(errors.ERR_ARGS_AND_KEYWORD_ARGS)
492443
elif args or kwargs:
493444
self._verify_open()
494-
self._impl.setinputsizes(self.connection, args, kwargs)
495-
self._set_input_sizes = True
496-
return self._impl.get_bind_vars()
445+
return self._impl.setinputsizes(self.connection, args, kwargs)
497446
return []
498447

499448
def setoutputsize(self, size: int, column: int = 0) -> None:
@@ -503,6 +452,14 @@ def setoutputsize(self, size: int, column: int = 0) -> None:
503452
"""
504453
pass
505454

455+
@property
456+
def statement(self) -> Union[str, None]:
457+
"""
458+
Returns the statement associated with the cursor, if one is present.
459+
"""
460+
if self._impl is not None:
461+
return self._impl.statement
462+
506463
def var(
507464
self,
508465
typ: Union[DbType, DbObjectType, type],
@@ -741,7 +698,6 @@ def execute(
741698
"""
742699
self._prepare_for_execute(statement, parameters, keyword_parameters)
743700
impl = self._impl
744-
impl.warning = None
745701
impl.execute(self)
746702
if impl.fetch_vars is not None:
747703
return self
@@ -789,18 +745,18 @@ def executemany(
789745
bound as numbers or dates will raise a TypeError exception.
790746
"""
791747
# verify parameters
792-
if statement is None and self.statement is None:
748+
if statement is None and self._impl.statement is None:
793749
errors._raise_err(errors.ERR_NO_STATEMENT)
794750
if not isinstance(parameters, (list, int)):
795751
errors._raise_err(errors.ERR_WRONG_EXECUTEMANY_PARAMETERS_TYPE)
796752

797753
# prepare statement, if necessary
798754
self._verify_open()
799-
if statement and statement != self.statement:
755+
if statement and statement != self._impl.statement:
800756
self._prepare(statement)
801757

802758
# perform bind and execute
803-
self._set_input_sizes = False
759+
self._impl.set_input_sizes = False
804760
if isinstance(parameters, int):
805761
num_execs = parameters
806762
else:
@@ -1010,7 +966,6 @@ async def execute(
1010966
TypeError exception.
1011967
"""
1012968
self._prepare_for_execute(statement, parameters, keyword_parameters)
1013-
self._impl.warning = None
1014969
await self._impl.execute(self)
1015970

1016971
async def executemany(
@@ -1056,18 +1011,18 @@ async def executemany(
10561011
bound as numbers or dates will raise a TypeError exception.
10571012
"""
10581013
# verify parameters
1059-
if statement is None and self.statement is None:
1014+
if statement is None and self._impl.statement is None:
10601015
errors._raise_err(errors.ERR_NO_STATEMENT)
10611016
if not isinstance(parameters, (list, int)):
10621017
errors._raise_err(errors.ERR_WRONG_EXECUTEMANY_PARAMETERS_TYPE)
10631018

10641019
# prepare statement, if necessary
10651020
self._verify_open()
1066-
if statement and statement != self.statement:
1021+
if statement and statement != self._impl.statement:
10671022
self._prepare(statement)
10681023

10691024
# perform bind and execute
1070-
self._set_input_sizes = False
1025+
self._impl.set_input_sizes = False
10711026
if isinstance(parameters, int):
10721027
num_execs = parameters
10731028
else:

0 commit comments

Comments
 (0)