Skip to content

Commit 3a23957

Browse files
Further tweaks to documentation and samples.
1 parent 30979c6 commit 3a23957

File tree

10 files changed

+221
-76
lines changed

10 files changed

+221
-76
lines changed

doc/src/api_manual/connection.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ Connection Object
8484

8585
.. method:: Connection.cancel()
8686

87-
Cancel a long-running transaction.
87+
Break a long-running transaction.
8888

8989
.. note::
9090

doc/src/api_manual/cursor.rst

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,12 @@ Cursor Object
2626
.. attribute:: Cursor.arraysize
2727

2828
This read-write attribute can be used to tune the number of rows internally
29-
fetched and buffered by internal calls to the database. The value can
30-
drastically affect the performance of a query since it directly affects the
31-
number of network round trips between Python and the database. For methods
32-
like :meth:`~Cursor.fetchone()` and :meth:`~Cursor.fetchall()` it does not
33-
change how many rows are returned to the application. For
29+
fetched and buffered by internal calls to the database when fetching rows
30+
from SELECT statements and REF CURSORS. The value can drastically affect
31+
the performance of a query since it directly affects the number of network
32+
round trips between Python and the database. For methods like
33+
:meth:`~Cursor.fetchone()` and :meth:`~Cursor.fetchall()` it does not change
34+
how many rows are returned to the application. For
3435
:meth:`~Cursor.fetchmany()` it is the default number of rows to fetch.
3536

3637
Due to the performance benefits, the default ``Cursor.arraysize`` is 100
@@ -445,9 +446,9 @@ Cursor Object
445446
.. attribute:: Cursor.prefetchrows
446447

447448
This read-write attribute can be used to tune the number of rows that the
448-
Oracle Client library fetches when a query is executed. This value can
449-
reduce the number of round-trips to the database that are required to
450-
fetch rows but at the cost of additional memory. Setting this value to 0
449+
Oracle Client library fetches when a SELECT statement is executed. This
450+
value can reduce the number of round-trips to the database that are required
451+
to fetch rows but at the cost of additional memory. Setting this value to 0
451452
can be useful when the timing of fetches must be explicitly controlled.
452453

453454
See :ref:`Tuning Fetch Performance <tuningfetch>` for more information.

doc/src/api_manual/soda.rst

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,27 @@ SODA
77
`Oracle Database Simple Oracle Document Access (SODA)
88
<https://docs.oracle.com/en/database/oracle/simple-oracle-document-access>`__
99
allows documents to be inserted, queried, and retrieved from Oracle Database
10-
using a set of NoSQL-style cx_Oracle methods.
10+
using a set of NoSQL-style cx_Oracle methods. By default, documents are JSON
11+
strings. See the :ref:`user manual <sodausermanual>` for examples.
1112

12-
See :ref:`user manual <sodausermanual>` for an example.
13+
.. _sodarequirements:
14+
15+
-----------------
16+
SODA Requirements
17+
-----------------
18+
19+
To use SODA, the role SODA_APP must be granted to the user. To create
20+
collections, users need the CREATE TABLE privilege. These can be granted by a
21+
DBA:
22+
23+
.. code-block:: sql
24+
25+
SQL> grant soda_app, create table to myuser;
26+
27+
Advanced users who are using Oracle sequences for keys will also need the CREATE
28+
SEQUENCE privilege.
1329

1430
SODA requires Oracle Client 18.3 or higher and Oracle Database 18.1 and higher.
15-
The role SODA_APP must be granted to the user.
1631

1732
.. note::
1833

@@ -48,7 +63,8 @@ The role SODA_APP must be granted to the user.
4863
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
4964
id=GUID-A2E90F08-BC9F-4688-A9D0-4A948DD3F7A9>`__ to 19 or lower.
5065

51-
Otherwise you may get errors such as "ORA-40659: Data type does not match
66+
Otherwise you may get errors such as "ORA-40842: unsupported value JSON in
67+
the metadata for the field sqlType" or "ORA-40659: Data type does not match
5268
the specification in the collection metadata".
5369

5470
.. _sodadb:

doc/src/user_guide/initialization.rst

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,29 +131,40 @@ Linux, you might use::
131131
$ python myapp.py 2> log.txt
132132

133133

134+
.. _usinginitoracleclient:
135+
134136
Using cx_Oracle.init_oracle_client() to set the Oracle Client directory
135137
-----------------------------------------------------------------------
136138

137139
Applications can call the function :meth:`cx_Oracle.init_oracle_client()` to
138140
specify the directory containing Oracle Instant Client libraries. The Oracle
139141
Client Libraries are loaded when ``init_oracle_client()`` is called. For
140142
example, if the Oracle Instant Client Libraries are in
141-
``C:\oracle\instantclient_19_6`` on Windows, then you can use:
143+
``C:\oracle\instantclient_19_9`` on Windows or
144+
``$HOME/Downloads/instantclient_19_8`` on macOS, then you can use:
142145

143146
.. code-block:: python
144147
145148
import cx_Oracle
146149
import sys
150+
import os
147151
148152
try:
149-
cx_Oracle.init_oracle_client(lib_dir=r"C:\oracle\instantclient_19_6")
153+
if sys.platform.startswith("darwin"):
154+
lib_dir = os.path.join(os.environ.get("HOME"), "Downloads",
155+
"instantclient_19_8")
156+
cx_Oracle.init_oracle_client(lib_dir=lib_dir)
157+
elif sys.platform.startswith("win32"):
158+
cx_Oracle.init_oracle_client(lib_dir=r"C:\oracle\instantclient_19_9")
150159
except Exception as err:
151160
print("Whoops!")
152161
print(err);
153162
sys.exit(1);
154163
155-
The :meth:`~cx_Oracle.init_oracle_client()` function should only be called
156-
once.
164+
Note the use of a 'raw' string ``r"..."`` on Windows so that backslashes are
165+
treated as directory separators.
166+
167+
The :meth:`~cx_Oracle.init_oracle_client()` function can only be called once.
157168

158169
If you set ``lib_dir`` on Linux and related platforms, you must still have
159170
configured the system library search path to include that directory before

doc/src/user_guide/installation.rst

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -487,8 +487,8 @@ To use cx_Oracle with Oracle Instant Client zip files:
487487

488488
2. Unzip the package into a directory that is accessible to your
489489
application. For example unzip
490-
``instantclient-basic-windows.x64-19.8.0.0.0dbru.zip`` to
491-
``C:\oracle\instantclient_19_8``.
490+
``instantclient-basic-windows.x64-19.9.0.0.0dbru.zip`` to
491+
``C:\oracle\instantclient_19_9``.
492492

493493
3. Oracle Instant Client libraries require a Visual Studio redistributable with
494494
a 64-bit or 32-bit architecture to match Instant Client's architecture.
@@ -511,7 +511,7 @@ Configure Oracle Instant Client
511511
.. code-block:: python
512512
513513
import cx_Oracle
514-
cx_Oracle.init_oracle_client(lib_dir=r"C:\oracle\instantclient_19_8")
514+
cx_Oracle.init_oracle_client(lib_dir=r"C:\oracle\instantclient_19_9")
515515
516516
Note a 'raw' string is used because backslashes occur in the path.
517517

@@ -523,7 +523,7 @@ Configure Oracle Instant Client
523523
is executed, for example::
524524

525525
REM mypy.bat
526-
SET PATH=C:\oracle\instantclient_19_8;%PATH%
526+
SET PATH=C:\oracle\instantclient_19_9;%PATH%
527527
python %*
528528

529529
Invoke this batch file every time you want to run Python.
@@ -536,14 +536,14 @@ Configure Oracle Instant Client
536536
.. code-block:: python
537537
538538
import cx_Oracle
539-
cx_Oracle.init_oracle_client(lib_dir=r"C:\oracle\instantclient_19_8",
539+
cx_Oracle.init_oracle_client(lib_dir=r"C:\oracle\instantclient_19_9",
540540
config_dir=r"C:\oracle\your_config_dir")
541541
542542
Or set the environment variable ``TNS_ADMIN`` to that directory name.
543543

544544
Alternatively, put the files in a ``network\admin`` subdirectory of
545545
Instant Client, for example in
546-
``C:\oracle\instantclient_19_8\network\admin``. This is the default
546+
``C:\oracle\instantclient_19_9\network\admin``. This is the default
547547
Oracle configuration directory for executables linked with this
548548
Instant Client.
549549

@@ -837,28 +837,48 @@ If using cx_Oracle fails:
837837
- Do you get the error "``DPI-1047: Oracle Client library cannot be
838838
loaded``"?
839839

840-
- Check that Python, cx_Oracle and your Oracle Client libraries
841-
are all 64-bit or all 32-bit. The ``DPI-1047`` message will
842-
tell you whether the 64-bit or 32-bit Oracle Client is needed
843-
for your Python.
840+
- On Windows and macOS, try using :meth:`~cx_Oracle.init_oracle_client()`.
841+
See :ref:`usinginitoracleclient`.
842+
843+
- Check that Python and your Oracle Client libraries are both 64-bit, or
844+
both 32-bit. The ``DPI-1047`` message will tell you whether the 64-bit
845+
or 32-bit Oracle Client is needed for your Python.
846+
847+
- Set the environment variable ``DPI_DEBUG_LEVEL`` to 64 and restart
848+
cx_Oracle. The trace messages will show how and where cx_Oracle is
849+
looking for the Oracle Client libraries.
850+
851+
At a Windows command prompt, this could be done with::
852+
853+
set DPI_DEBUG_LEVEL=64
854+
855+
On Linux and macOS, you might use::
856+
857+
export DPI_DEBUG_LEVEL=64
858+
844859
- On Windows, if you used :meth:`~cx_Oracle.init_oracle_client()` and have
845860
a full database installation, make sure this database is the `currently
846861
configured database
847862
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-33D575DD-47FF-42B1-A82F-049D3F2A8791>`__.
863+
848864
- On Windows, if you are not using
849865
:meth:`~cx_Oracle.init_oracle_client()`, then restart your command prompt
850866
and use ``set PATH`` to check the environment variable has the correct
851867
Oracle Client listed before any other Oracle directories.
868+
852869
- On Windows, use the ``DIR`` command to verify that ``OCI.DLL`` exists in
853870
the directory passed to ``init_oracle_client()`` or set in ``PATH``.
871+
854872
- On Windows, check that the correct `Windows Redistributables
855873
<https://oracle.github.io/odpi/doc/installation.html#windows>`__ have
856874
been installed.
875+
857876
- On Linux, check the ``LD_LIBRARY_PATH`` environment variable contains
858877
the Oracle Client library directory. If you are using Oracle Instant
859878
Client, a preferred alternative is to ensure a file in the
860879
``/etc/ld.so.conf.d`` directory contains the path to the Instant Client
861880
directory, and then run ``ldconfig``.
881+
862882
- On macOS, make sure you are not using the bundled Python (use `Homebrew
863883
<https://brew.sh>`__ or `Python.org
864884
<https://www.python.org/downloads>`__ instead). If you are not using

doc/src/user_guide/soda.rst

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,21 @@ SODA uses a SQL schema to store documents but you do not need to know SQL or
1818
how the documents are stored. However, access via SQL does allow use of
1919
advanced Oracle Database functionality such as analytics for reporting.
2020

21+
Oracle SODA implementations are also available in `Node.js
22+
<https://oracle.github.io/node-oracledb/doc/api.html#sodaoverview>`__, `Java
23+
<https://docs.oracle.com/en/database/oracle/simple-oracle-document-access/java/adsda/index.html>`__,
24+
`PL/SQL <https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=ADSDP>`__,
25+
`Oracle Call Interface
26+
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-23206C89-891E-43D7-827C-5C6367AD62FD>`__
27+
and via `REST
28+
<https://docs.oracle.com/en/database/oracle/simple-oracle-document-access/rest/index.html>`__.
29+
2130
For general information on SODA, see the `SODA home page
2231
<https://docs.oracle.com/en/database/oracle/simple-oracle-document-access/index.html>`__
23-
and `Oracle Database Introduction to SODA
24-
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=ADSDI>`__.
32+
and the Oracle Database `Introduction to Simple Oracle Document Access (SODA)
33+
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=ADSDI>`__ manual.
34+
35+
For specified requirements see the cx_Oracle :ref:`SODA requirements <sodarequirements>`.
2536

2637
cx_Oracle uses the following objects for SODA:
2738

@@ -62,8 +73,8 @@ cx_Oracle uses the following objects for SODA:
6273
then used by a terminal method to find, count, replace, or remove documents.
6374
This is an internal object that should not be directly accessed.
6475

65-
SODA Example
66-
============
76+
SODA Examples
77+
=============
6778

6879
Creating and adding documents to a collection can be done as follows:
6980

@@ -106,3 +117,39 @@ You can also search for documents using query-by-example syntax:
106117
See the `samples directory
107118
<https://github.com/oracle/python-cx_Oracle/tree/master/samples>`__
108119
for runnable SODA examples.
120+
121+
--------------------
122+
Committing SODA Work
123+
--------------------
124+
125+
The general recommendation for SODA applications is to turn on
126+
:attr:`~Connection.autocommit` globally:
127+
128+
.. code-block:: python
129+
130+
connection.autocommit = True
131+
132+
If your SODA document write operations are mostly independent of each other,
133+
this removes the overhead of application transaction management and the need for
134+
explicit :meth:`Connection.commit()` calls.
135+
136+
When deciding how to commit transactions, beware of transactional consistency
137+
and performance requirements. If you are using individual SODA calls to insert
138+
or update a large number of documents with individual calls, you should turn
139+
:attr:`~Connection.autocommit` off and issue a single, explicit
140+
:meth:`~Connection.commit()` after all documents have been processed. Also
141+
consider using :meth:`SodaCollection.insertMany()` or
142+
:meth:`SodaCollection.insertManyAndGet()` which have performance benefits.
143+
144+
If you are not autocommitting, and one of the SODA operations in your
145+
transaction fails, then previous uncommitted operations will not be rolled back.
146+
Your application should explicitly roll back the transaction with
147+
:meth:`Connection.rollback()` to prevent any later commits from committing a
148+
partial transaction.
149+
150+
Note:
151+
152+
- SODA DDL operations do not commit an open transaction the way that SQL always does for DDL statements.
153+
- When :attr:`~Connection.autocommit` is ``True``, most SODA methods will issue a commit before successful return.
154+
- SODA provides optimistic locking, see :meth:`SodaOperation.version()`.
155+
- When mixing SODA and relational access, any commit or rollback on the connection will affect all work.

samples/BindInsert.py

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,63 @@
1313

1414
connection = cx_Oracle.connect(sample_env.get_main_connect_string())
1515

16-
rows = [ (1, "First" ),
17-
(2, "Second" ),
18-
(3, "Third" ),
19-
(4, "Fourth" ),
20-
(5, "Fifth" ),
21-
(6, "Sixth" ),
22-
(7, "Seventh" ) ]
16+
#------------------------------------------------------------------------------
17+
# "Bind by position"
18+
#------------------------------------------------------------------------------
19+
20+
rows = [
21+
(1, "First"),
22+
(2, "Second"),
23+
(3, "Third"),
24+
(4, "Fourth"),
25+
(5, None), # Insert a NULL value
26+
(6, "Sixth"),
27+
(7, "Seventh")
28+
]
2329

2430
cursor = connection.cursor()
31+
32+
# predefine maximum string size to avoid data scans and memory reallocations;
33+
# the None value indicates that the default processing can take place
34+
cursor.setinputsizes(None, 20)
35+
2536
cursor.executemany("insert into mytab(id, data) values (:1, :2)", rows)
2637

27-
# Don't commit - this lets us run the demo multiple times
28-
#connection.commit()
38+
#------------------------------------------------------------------------------
39+
# "Bind by name"
40+
#------------------------------------------------------------------------------
41+
42+
rows = [
43+
{"d": "Eighth", "i": 8},
44+
{"d": "Ninth", "i": 9},
45+
{"d": "Tenth", "i": 10}
46+
]
47+
48+
cursor = connection.cursor()
49+
50+
# Predefine maximum string size to avoid data scans and memory reallocations
51+
cursor.setinputsizes(d=20)
2952

53+
cursor.executemany("insert into mytab(id, data) values (:i, :d)", rows)
54+
55+
#------------------------------------------------------------------------------
56+
# Inserting a single bind still needs tuples
57+
#------------------------------------------------------------------------------
58+
59+
rows = [
60+
("Eleventh",),
61+
("Twelth",)
62+
]
63+
64+
cursor = connection.cursor()
65+
cursor.executemany("insert into mytab(id, data) values (11, :1)", rows)
66+
67+
#------------------------------------------------------------------------------
3068
# Now query the results back
69+
#------------------------------------------------------------------------------
70+
71+
# Don't commit - this lets the demo be run multiple times
72+
#connection.commit()
3173

3274
for row in cursor.execute('select * from mytab'):
3375
print(row)
34-

samples/QueryArraysize.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
#------------------------------------------------------------------------------
66
# QueryArraysize.py
77
#
8-
# Demonstrate how to alter the array size on a cursor in order to reduce the
9-
# number of network round trips and overhead required to fetch all of the rows
10-
# from a large table.
8+
# Demonstrate how to alter the array size and prefetch rows value on a cursor
9+
# in order to reduce the number of network round trips and overhead required to
10+
# fetch all of the rows from a large table.
1111
#------------------------------------------------------------------------------
1212

1313
import time
@@ -19,6 +19,7 @@
1919
start = time.time()
2020

2121
cursor = connection.cursor()
22+
cursor.prefetchrows = 1000
2223
cursor.arraysize = 1000
2324
cursor.execute('select * from bigtab')
2425
res = cursor.fetchall()

0 commit comments

Comments
 (0)