Compare commits

...

622 Commits
6.0rc1 ... main

Author SHA1 Message Date
Anthony Tuininga
70cbc43752 Further nudge users towards python-oracledb. 2025-03-26 20:19:34 -06:00
Anthony Tuininga
bed2c037f9 Relocate file per @LesiaChaban. 2024-07-30 17:09:37 -06:00
Anthony Tuininga
93d69d861b Make samples point to python-oracledb at runtime. 2024-05-31 16:47:41 -06:00
Anthony Tuininga
83774f9520 Update templates and READMEs to take note of python-oracledb. 2024-05-07 20:33:12 -06:00
Anthony Tuininga
6766bcaf27 Update ReadTheDocs configuration to avoid deprecation warnings with
ReadTheDocs.
2023-08-16 18:33:24 -06:00
Anthony Tuininga
a05b9a5233 Add more doc redirects. 2023-06-03 09:37:29 -06:00
Anthony Tuininga
5cfbb7d9e4 Remove semicolons in Python code examples (resolves #629). 2022-06-08 13:12:35 -06:00
Anthony Tuininga
fde577bf1f python-oracledb 1.0.0 has been released! 2022-05-25 14:43:26 -06:00
Anthony Tuininga
1ad43aa912 Doc improvements. 2022-05-25 14:41:35 -06:00
Anthony Tuininga
3db3e3772e Fix stale OCA link. 2022-05-25 14:40:44 -06:00
Anthony Tuininga
59c41535e3 Improved AQ test. 2022-05-25 14:37:50 -06:00
Anthony Tuininga
5728cf534e Try newer version of Sphinx. 2021-11-04 16:02:28 -06:00
Anthony Tuininga
3a40eeacaa ReadTheDocs only supports up to Python 3.8. 2021-11-04 15:58:51 -06:00
Anthony Tuininga
fde9ec78fc ReadTheDocs requires configuration so make it happy. 2021-11-04 15:57:32 -06:00
Anthony Tuininga
45118e0c31 Preparing to release cx_Oracle 8.3. 2021-11-04 13:20:41 -06:00
Anthony Tuininga
29ca919445 Add official support for Python 3.10. 2021-11-04 13:20:11 -06:00
Anthony Tuininga
ae687ce736 Improve documentation for WHERE IN clauses. 2021-11-04 13:19:26 -06:00
Anthony Tuininga
2d33fec37a Test suite improvements. 2021-11-04 13:19:04 -06:00
Anthony Tuininga
9db9d6907a Batch loading documentation improvements. 2021-11-04 13:16:44 -06:00
Anthony Tuininga
00dc44eade Update ODPI-C. 2021-11-04 11:30:34 -06:00
Anthony Tuininga
76157dd28a Add note that change to MessageProperties.msgid marked the attribute
read only.
2021-09-04 14:40:55 -06:00
Anthony Tuininga
83148ec574 Added test cases to verify that MessageProperties.msgid is calculated
correctly.
2021-09-03 13:57:20 -06:00
Anthony Tuininga
eb37d27464 Documentation improvements. 2021-09-03 11:00:47 -06:00
Anthony Tuininga
05a9097847 Add more tests. 2021-09-03 10:57:19 -06:00
Anthony Tuininga
438c885c20 Correct calculation of MessageProperties.msgid. 2021-09-03 10:56:24 -06:00
Anthony Tuininga
1347b04976 Update ODPI-C. 2021-09-02 11:16:16 -06:00
Anthony Tuininga
702a91be51 Update ODPI-C. 2021-09-01 11:12:51 -06:00
Anthony Tuininga
08117db459 Expand ADB documentation. 2021-07-26 13:32:18 -06:00
Anthony Tuininga
440163efe5 Improved samples and test suite. 2021-07-26 13:31:57 -06:00
Anthony Tuininga
c665d2efca Update formatting links. 2021-07-26 13:28:32 -06:00
Anthony Tuininga
dfeebc3358 Update ODPI-C. 2021-07-26 13:28:02 -06:00
Anthony Tuininga
5cce9efd49 Minor tweak to samples README. 2021-06-08 11:15:44 -06:00
Anthony Tuininga
cc067bf83e Binary integer variables now explicitly convert values to integers (since
implicit conversion to integer has become an error in Python 3.10) and
values that are not `int`, `float` or `decimal.Decimal` are explicitly
rejected.
2021-06-08 11:15:13 -06:00
Anthony Tuininga
abb666706b Update ODPI-C. 2021-06-08 11:14:34 -06:00
Anthony Tuininga
4229a6d8ad cx_Oracle 8.2.1 is about to be released. 2021-06-01 13:02:07 -06:00
Anthony Tuininga
59558714ac Update SODA doc. 2021-06-01 12:03:03 -06:00
Anthony Tuininga
a61b14a5c6 Update ODPI-C. 2021-06-01 12:00:42 -06:00
Anthony Tuininga
5dccb9fb5f Use PEP 8 variable names. 2021-05-28 14:48:38 -06:00
Anthony Tuininga
206e85e4a2 Update ODPI-C. 2021-05-28 14:48:05 -06:00
Anthony Tuininga
df80067f47 Update ODPI-C. 2021-05-21 21:39:27 -06:00
Anthony Tuininga
d585cf06df Fixed crash when using the deprecated parameter name keywordParameters
with Cursor.callproc(); add test cases to cover this and other similar
situations.
2021-05-21 21:38:45 -06:00
Anthony Tuininga
ce4713c6f7 Fix typo. 2021-05-21 21:36:58 -06:00
Anthony Tuininga
31d94e7bf1 Bump version in preparation for new changes being made. 2021-05-21 21:36:30 -06:00
Anthony Tuininga
94e9489e25 Configuration requires master_doc (root_doc in Sphinx 4.0). 2021-05-18 17:04:49 -06:00
Anthony Tuininga
46a3d70ad8 Preparing to release cx_Oracle 8.2. 2021-05-18 16:59:00 -06:00
Anthony Tuininga
cd21e92edd Improve test suite. 2021-05-18 16:58:03 -06:00
Anthony Tuininga
0633e1017c Minor tweaks for PEP 8 compliance. 2021-05-18 16:56:55 -06:00
Anthony Tuininga
cfa2750854 Add support for pool reconfiguration. 2021-05-18 16:56:04 -06:00
Anthony Tuininga
d5461bd008 Further simplification. 2021-05-18 16:55:21 -06:00
Anthony Tuininga
07bb84e1b6 Remove duplicate forward declaration section. 2021-05-18 16:54:33 -06:00
Anthony Tuininga
4ed562c205 Documentation updates, including changes for PEP 8 compliance, to take
into account the fact that the default branch has changed to main, etc.
2021-05-18 16:53:31 -06:00
Anthony Tuininga
97be497fc9 Update ODPI-C to released 4.2.0. 2021-05-18 16:43:59 -06:00
Anthony Tuininga
c665e7a9e2 Update ODPI-C. 2021-05-13 15:58:14 -06:00
Anthony Tuininga
89eaea4f42 Update ODPI-C. 2021-05-13 14:38:47 -06:00
Anthony Tuininga
fbd9bfafb6 Update ODPI-C. 2021-05-07 11:14:57 -06:00
Anthony Tuininga
4661c6690f Move section. 2021-04-28 15:33:37 -06:00
Anthony Tuininga
4189983481 Adjust documentation to take into account recent changes regarding the
statement cache.
2021-04-28 15:31:04 -06:00
Anthony Tuininga
5680620f02 Add support for specifying the ping interval for pools. 2021-04-28 15:30:44 -06:00
Anthony Tuininga
932b413226 Adjust sample to match other AQ samples. 2021-04-28 15:29:54 -06:00
Anthony Tuininga
89aea21176 Support non-simple characters. 2021-04-23 16:12:12 -06:00
Anthony Tuininga
2c6468d992 Correct doc. 2021-04-23 16:11:38 -06:00
Anthony Tuininga
8c99d1ddde Final work on adjusting attribute, method and parameter names to be
consistent and to comply with PEP 8 naming guidelines.
2021-04-23 16:08:25 -06:00
Anthony Tuininga
96f938286d Further work on adjusting attribute, method and parameter names to be
consistent and to comply with PEP 8 naming guidelines; also adjust
implementation of #385 (originally done in pull request #549) to use the
parameter name `bypass_decode` instead of `bypassencoding`.
2021-04-23 16:05:42 -06:00
Anthony Tuininga
ab6e6f06ef Documentation and sample updates for clarity and to note the fact that
connection pools now always enable threading.
2021-04-23 14:21:45 -06:00
Anthony Tuininga
fa36066875 Added support for enabling the SODA metadata cache in Oracle Client
version 21.3 and higher (also available in Oracle Client 19 from 19.11).
This significantly improves the performance of
SodaDatabase.createCollection() and SodaDatabase.openCollection().
2021-04-23 14:18:46 -06:00
Anthony Tuininga
ba6e054a24 Further work on adjusting attribute, method and parameter names to be
consistent and to comply with PEP 8 naming guidelines.
2021-04-23 13:54:00 -06:00
Anthony Tuininga
82fb398b38 Doc tweaks. 2021-04-23 13:51:31 -06:00
Anthony Tuininga
fa8d6fa5be Migrate samples to use PEP 8 naming style consistently. 2021-04-23 13:50:06 -06:00
Anthony Tuininga
cccfa322c7 Simplify code to take advantage of feature added in Python 3.3. 2021-04-23 13:48:53 -06:00
Anthony Tuininga
0edb436abf Simplify samples. 2021-04-23 13:48:28 -06:00
Anthony Tuininga
9e8bc6676c Tweak doc. 2021-04-23 13:48:03 -06:00
Anthony Tuininga
7ad13e73d3 Added parameter stmtcachesize to cx_Oracle.connect() and
cx_Oracle.SessionPool() in order to facilitate specifying the initial
size of the statement cache.
2021-04-23 13:45:59 -06:00
Anthony Tuininga
cb1061a553 Remove extra word as noted in #550. 2021-04-23 13:42:26 -06:00
Anthony Tuininga
df89702a4e Stop passing unsupported flags to dpiSodaDocCursor_getNext(). 2021-04-23 13:41:48 -06:00
Anthony Tuininga
c527c06650 Further work on adjusting attribute, method and parameter names to be
consistent and to comply with PEP 8 naming guidelines; add a separate
section to the documentation to deal with all deprecations so that they
are all in one place.
2021-04-23 13:40:24 -06:00
Anthony Tuininga
4b72d0de02 Rename samples and test files in order to be consistent. 2021-04-23 13:36:00 -06:00
Anthony Tuininga
74d16d8962 Improved the test suite. 2021-04-23 12:04:29 -06:00
Anthony Tuininga
a1f8e1ffff URL updates. 2021-04-23 12:02:59 -06:00
Anthony Tuininga
5e2a363ac5 Modify the parameter names of the SessionPool constructor in order to
follow PEP 8 naming guidelines.
2021-04-23 12:01:52 -06:00
Anthony Tuininga
755b6fa861 Documentation tweaks. 2021-04-23 11:56:38 -06:00
Anthony Tuininga
4264d7bc5d Improved test suite; added check that the LOB type matches the expected
LOB type.
2021-04-23 11:53:13 -06:00
Anthony Tuininga
250b07299d Update CLA URL to new online system. 2021-04-23 11:47:15 -06:00
Anthony Tuininga
10f1c48289 Update ODPI-C. 2021-04-23 11:40:55 -06:00
Draco94
95baec2436
Implemented #385 enhancement and updated documentation (#549)
* Implemented #385 enhancement and updated documentation

Signed-off-by: Darko Djolovic <ddjolovic@outlook.com>

* Created flag to Cursor.var()

Signed-off-by: Darko Djolovic <ddjolovic@outlook.com>

* Removed first commit changes, updated documetnation

Signed-off-by: Darko Djolovic <ddjolovic@outlook.com>

* Added testing sample 'QueringRawData.py' and renamed attribute 'bypassstringencoding' to 'bypassencoding' with updated documentation

Signed-off-by: Darko Djolovic <ddjolovic@outlook.com>
2021-04-23 11:38:45 -06:00
Anthony Tuininga
ffa2086fd3 Clarify release note (#544). 2021-04-19 12:03:43 -06:00
Anthony Tuininga
c9110a33b8 Emphasize the Linux init_oracle_client() limitations. 2021-04-15 17:03:29 -06:00
Anthony Tuininga
517868eaf9 Added support for supplying hints to various SODA operations. 2021-04-15 16:59:34 -06:00
Anthony Tuininga
74b2e9a258 Update ODPI-C. 2021-04-15 16:58:38 -06:00
Anthony Tuininga
658f4cd3c2 Require an issue template. 2021-04-14 09:45:34 -06:00
Anthony Tuininga
8f901abce7 The distributed transaction handle assosciated with the connection is now
cleared on commit or rollback (`issue 530
<https://github.com/oracle/python-cx_Oracle/issues/530>`__).
2021-03-04 09:41:37 -07:00
Anthony Tuininga
bdf6b4ee4c Use explicit SODA metadata for maximum version interoperability. 2021-03-03 11:30:10 -07:00
Anthony Tuininga
1a42fb1de0 Update ODPI-C. 2021-03-03 11:24:07 -07:00
Anthony Tuininga
e1b05d5095 Correct file references. 2021-03-03 11:20:55 -07:00
Christopher Jones
fb2668e87c Update tutorial configuration and setup instructions 2021-03-03 17:14:32 +11:00
Christopher Jones
0a3aae5de8 Improve doc flow 2021-03-03 17:13:24 +11:00
Christopher Jones
5f60401c4a Use aq_administrator_role for AQ samples 2021-03-03 17:12:57 +11:00
Christopher Jones
bf381478c4 Update pool testcases 2021-03-03 17:11:55 +11:00
Christopher Jones
aa2e258c98 Use a better resolution architecture diagram 2021-03-03 17:11:15 +11:00
Anthony Tuininga
188608e748 Tweak documentation and README files. 2021-02-26 16:52:28 -07:00
Anthony Tuininga
0ff1003203 Eliminated memory leak when calling SodaOperation.filter() with a dictionary. 2021-01-21 19:53:29 -07:00
Anthony Tuininga
7382d035f4 Update ODPI-C and note SODA collection save() and saveAndGet() require Oracle
Client 19.9 or higher.
2021-01-21 10:30:34 -07:00
Anthony Tuininga
8ea16b1345 Tweak formatting to comply with PEP 8 and remove extraneous comments. 2021-01-21 10:29:43 -07:00
Anthony Tuininga
c92d251677 Bump version to 8.2 in preparation for further changes. 2021-01-21 10:29:05 -07:00
Anthony Tuininga
fa5fc20997 Fix typo. 2021-01-05 11:23:11 -07:00
Anthony Tuininga
9f32c9073e Remove trailing blank lines. 2021-01-05 11:21:50 -07:00
Anthony Tuininga
543c1b9d99 Minor tweaks to samples and documentation to take into account recent changes. 2021-01-05 11:20:29 -07:00
Anthony Tuininga
b199c5d57f Fix typos. 2020-12-21 15:01:01 -07:00
Anthony Tuininga
3b8c9cbd5f Added more test cases. 2020-12-21 14:57:45 -07:00
Anthony Tuininga
5c41ce1f05 Tweak top-level description for Oracle Client library and Python support
levels.
2020-12-08 13:18:07 -07:00
Anthony Tuininga
86c106dbf4 Preparing to release cx_Oracle 8.1. 2020-12-08 11:59:06 -07:00
Anthony Tuininga
d9cb6b1e56 Update templates. 2020-12-08 11:58:14 -07:00
Anthony Tuininga
f3984cee55 The connection created by using an external handle should never be used after
the external handle has been closed or destroyed (since otherwise the memory
used may have already been freed and reused by other parts of the application).
2020-12-08 11:51:54 -07:00
Anthony Tuininga
3a23957f6d Further tweaks to documentation and samples. 2020-12-08 11:47:53 -07:00
Anthony Tuininga
30979c6a57 Modify samples to follow the PEP 8 style guide. 2020-12-08 11:46:17 -07:00
Anthony Tuininga
6b9a7b011b Rename "base" to "test_env" to be clearer as to the purpose of the module. 2020-12-08 11:44:55 -07:00
Anthony Tuininga
c76492ec08 Documentation improvements. 2020-12-08 11:43:46 -07:00
Anthony Tuininga
9c9b92a39c Added new tests. 2020-12-08 11:42:53 -07:00
Anthony Tuininga
b59fe3b0be Added support for new JSON data type available in Oracle Client and Database 21
and higher.
2020-12-08 11:40:21 -07:00
Anthony Tuininga
9d4973c85d Update ODPI-C. 2020-12-08 11:00:56 -07:00
Anthony Tuininga
320fb1f31d Update stalebot configuration. 2020-11-18 21:26:10 -07:00
Anthony Tuininga
216bc42cf4 Eliminate use of deprecated function (which generates a warning in Python 3.9). 2020-11-12 14:28:17 -07:00
Anthony Tuininga
633d1141db Change to use PEP 8 format guidelines. 2020-11-12 14:27:23 -07:00
Anthony Tuininga
7e7133b09a The value of prefetchrows for REF CURSOR variables is now honored
(https://github.com/oracle/python-cx_Oracle/issues/482).
2020-11-12 14:24:42 -07:00
Anthony Tuininga
c8babe7209 Updated install instructions, mostly for macOS DMGs. 2020-11-12 14:23:30 -07:00
Anthony Tuininga
4dc91f5206 Update ODPI-C. 2020-11-12 14:21:33 -07:00
Anthony Tuininga
9cfe49f125 Enable https://github.com/marketplace/stale to close inactive issues. 2020-11-02 15:26:04 -07:00
Anthony Tuininga
229f9f5533 Rework test suite further to use PEP 8 style guidelines. 2020-11-02 15:25:51 -07:00
Anthony Tuininga
ef3d84318e The ability to pickle/unpickle Database and API types has been restored. 2020-11-02 15:24:23 -07:00
Anthony Tuininga
d242bc716d Rework build to use setuptools exclusively and enable use of pyproject.toml;
rework test suite to use tox and simplify test suite (also added a test number
to each test case for easier reference).
2020-11-02 15:21:52 -07:00
Anthony Tuininga
2194d81965 Added test cases for prefetch. 2020-11-02 15:20:45 -07:00
Anthony Tuininga
04fd1a7ad5 Add example showing how to create a stored proc and check for warnings. 2020-11-02 15:09:43 -07:00
Anthony Tuininga
551be9150e Update ODPI-C. 2020-11-02 15:06:18 -07:00
Anthony Tuininga
6ebd04ea5a Fix typo. 2020-10-07 14:23:01 -06:00
Anthony Tuininga
6ff7caba7c Add a security policy file
https://docs.github.com/en/github/managing-security-vulnerabilities/adding-a-security-policy-to-your-repository
2020-09-07 10:22:43 -06:00
Anthony Tuininga
0d28ea1e42 Added internal methods for getting/setting OCI attributes that are otherwise
not supported by cx_Oracle. These methods should only be used as directed by
Oracle.
2020-09-03 16:35:05 -06:00
Anthony Tuininga
a18cc34a4b Tweak release notes after release of cx_Oracle 8.0.1. 2020-09-03 15:06:06 -06:00
Anthony Tuininga
b4443c0f9f Documentation improvements. 2020-09-03 15:03:38 -06:00
Anthony Tuininga
a21e06a60c Update ODPI-C. 2020-09-03 14:58:11 -06:00
Anthony Tuininga
fa626f9001 Update ODPI-C. 2020-08-31 20:29:40 -06:00
Anthony Tuininga
73a5c56bd1 Preparing to release cx_Oracle 8.0.1. 2020-08-31 20:28:55 -06:00
Anthony Tuininga
769fbcf585 Add change to release notes. 2020-08-26 15:37:19 -06:00
Alex Henrie
f338af9d1c
Make numConnectDataArgs const (#472)
Signed-off-by: Alex Henrie <alexhenrie24@gmail.com>
2020-08-26 15:35:29 -06:00
Anthony Tuininga
d726c8be51 Add metadata specifying that Python 3.5 and higher is required (#456). 2020-07-30 09:54:14 -06:00
Anthony Tuininga
f3610cd2b9 Fix function header comments. 2020-07-28 09:52:47 -06:00
Anthony Tuininga
96f15f48da Move declaration of Python types, methods and members to the end of the file in
order to avoid unnecessary forward declarations.
2020-07-28 09:50:41 -06:00
Anthony Tuininga
dd492591a3 Remove version numbers. Fixes incorrect number. 2020-07-28 09:50:24 -06:00
Anthony Tuininga
b34f92e77f Improve pool documentation. 2020-07-28 09:49:55 -06:00
Anthony Tuininga
59231532a4 Add missing favicon. 2020-07-15 16:01:16 -06:00
Anthony Tuininga
bf6318da08 Add note about older versions. 2020-07-15 16:00:20 -06:00
Anthony Tuininga
7d017d89e5 Update GitHub issue templates. 2020-07-15 15:59:40 -06:00
Anthony Tuininga
ccda539172 dd a note about Python 2 support to the error message raised when an
unsupported version is detected.
2020-07-02 19:55:48 -06:00
Anthony Tuininga
b04f538467 Documentation improvements. 2020-07-02 19:54:47 -06:00
Anthony Tuininga
74a479087f Update ODPI-C to development version to include patch for issue #459; bump
version to 8.1 for further development.
2020-07-02 11:21:44 -06:00
Anthony Tuininga
10e5c258fe Update to ODPI-C 4.0.1 and add test to ensure that the offset is returned
correctly when a parse error is encountered.
2020-06-26 10:33:13 -06:00
Anthony Tuininga
8d719c3be4 Preparing to release cx_Oracle 8.0.0. 2020-06-25 15:25:30 -06:00
Anthony Tuininga
079927c8ce Various documentation and tutorial improvements. 2020-06-25 15:23:41 -06:00
Anthony Tuininga
3f06ea39a7 Update ODPI-C to the just released 4.0.0. 2020-06-25 15:18:57 -06:00
Anthony Tuininga
7df78b98d0 Tutorial improvements. 2020-06-19 10:42:06 -06:00
Anthony Tuininga
631b8729f5 Documentation improvements. 2020-06-19 10:41:51 -06:00
Anthony Tuininga
3a941687ea Added multiple consumer AQ example. 2020-06-19 10:39:19 -06:00
Anthony Tuininga
898b480035 Update ODPI-C. 2020-06-19 10:38:42 -06:00
Anthony Tuininga
8253bd2165 Bump reference to ODPI-C to version 4. 2020-06-12 16:00:16 -06:00
Anthony Tuininga
f8bcc6f0ec Added attribute cursor.prefetchrows to control the number of rows that the
Oracle Client library fetches into internal buffers when a query is
executed (https://github.com/oracle/python-cx_Oracle/issues/355).
2020-06-12 15:57:29 -06:00
Anthony Tuininga
0467db9e4b Tutorial updates to get ready for the coming weekend's Quest session. 2020-06-09 14:50:41 -06:00
Anthony Tuininga
5df9a73c5d Add cx_Oracle.init_oracle_client() for Oracle Client library initialization;
change default encoding to UTF-8.
2020-06-03 09:13:06 -06:00
Anthony Tuininga
c144216b95 Adjust test name to remove reference to very old version of Python. 2020-06-03 09:12:45 -06:00
Anthony Tuininga
4956aee0e5 Remove sample that is only relevant with Python 2. 2020-06-03 09:11:32 -06:00
Anthony Tuininga
c7a23115ad Remove remaining references to Python 2 syntax. 2020-06-03 09:11:03 -06:00
Anthony Tuininga
db1b7ae60d Various documentation improvements. 2020-06-03 09:10:38 -06:00
Anthony Tuininga
6e4fb6cf07 Update ODPI-C. 2020-06-03 09:09:51 -06:00
Anthony Tuininga
4646a18165 Remove unneeded code (and a deprecation warning with Python 3.9b1). 2020-05-19 11:42:46 -06:00
Anthony Tuininga
4b6b2c0dcc Return error if one occurs! 2020-05-18 16:38:44 -06:00
Anthony Tuininga
d5144aa58f Added test cases for cursor.lastrowid and SODA collection truncation (and added
code to check for situation where SODA support is lacking and stop running the
test suite for SODA in that case).
2020-05-18 16:34:58 -06:00
Anthony Tuininga
20686a1fc9 Various documentation and samples improvements. 2020-05-18 16:34:23 -06:00
Anthony Tuininga
633371db7d Small tweak to pull request for consistency in naming; update release notes
(https://github.com/oracle/python-cx_Oracle/pull/438).
2020-05-18 14:29:21 -06:00
Alex Henrie
5c6f55ef4d
Save string length instead of calling strlen in cxoCursor_var (#438)
Signed-off-by: Alex Henrie <alexhenrie24@gmail.com>
2020-05-18 14:26:35 -06:00
Anthony Tuininga
0b39b9e801 Update release notes. 2020-05-18 14:23:42 -06:00
Anthony Tuininga
f4148aeb6f Improve the doc on network pinging 2020-05-18 13:46:57 -06:00
Alex Henrie
ba141dd799
Create TestLongs and TestLongRaws tables without compression (#437)
Signed-off-by: Alex Henrie <alexhenrie24@gmail.com>
2020-05-18 13:43:13 -06:00
Anthony Tuininga
856d0aab76 Tweaks to boolean variable improvements patch supplied by Alex Henrie
(https://github.com/oracle/python-cx_Oracle/pull/435).
2020-05-15 21:47:40 -06:00
Alex Henrie
17fd92f8f6
Convert Python objects to booleans based on their Python truth value (#435)
Signed-off-by: Alex Henrie <alexhenrie24@gmail.com>
2020-05-15 17:00:13 -06:00
Anthony Tuininga
ba9a3ea3c2 Update ODPI-C. 2020-04-20 10:36:25 -06:00
Anthony Tuininga
d39ceb3280 Update release notes. 2020-04-20 10:25:44 -06:00
Alex Henrie
bd9d7759b2
Remove redundant decrement and return from cxoTransform_toPython (#423)
Signed-off-by: Alex Henrie <alexhenrie24@gmail.com>
2020-04-20 10:19:08 -06:00
Alex Henrie
af1281e535
Remove redundant assignment from cxoCursor_setBindVariables (#421)
Signed-off-by: Alex Henrie <alexhenrie24@gmail.com>
2020-04-18 21:39:39 -06:00
Alex Henrie
528dec6859
Fix memory leak on error path in cxoObjectType_initialize (#422)
Signed-off-by: Alex Henrie <alexhenrie24@gmail.com>
2020-04-18 21:38:31 -06:00
Alex Henrie
ca363bed8f
Use return value of snprintf instead of calling strlen unnecessarily (#420)
Signed-off-by: Alex Henrie <alexhenrie24@gmail.com>
2020-04-18 16:55:29 -06:00
Anthony Tuininga
fbe929d5c8 The database types CLOB, NCLOB, BFILE and BLOB no longer compare equal to
STRING and BINARY.
2020-04-17 10:19:44 -06:00
Alex Henrie
5ad2408a11
Consolidate string handling in cxoTransform_toPython (#419)
Signed-off-by: Alex Henrie <alexhenrie24@gmail.com>
2020-04-17 09:57:26 -06:00
Anthony Tuininga
6dc0263f1f Modify documentation based on change to comparison between database types and
DB API types.
2020-04-13 10:00:58 -06:00
Anthony Tuininga
c3561f3595 Eliminate treating BLOB and BFILE as BINARY and CLOB and NCLOB as STRING as
they return an object which does not behave the same way as strings and bytes
(https://github.com/oracle/python-cx_Oracle/issues/415).
2020-04-13 09:21:57 -06:00
Anthony Tuininga
54ab4b19f0 Improve DBMS_OUTPUT example, as suggested
(https://github.com/oracle/python-cx_Oracle/issues/412).
2020-04-06 14:03:20 -06:00
Anthony Tuininga
5071278938 And an examples section header and link to the tutorial. 2020-04-06 14:02:46 -06:00
Anthony Tuininga
c710fb89a6 Update tutorial links. 2020-04-06 14:02:20 -06:00
Anthony Tuininga
c513b71fe7 Use with clause when acquiring connections from a pool so that they are
returned automatically at the end of the block.
2020-04-06 13:53:26 -06:00
Anthony Tuininga
9377a9a0ef Documentation improvements. 2020-04-06 13:52:58 -06:00
Anthony Tuininga
3a4ee32022 Update ODPI-C. 2020-04-06 11:49:42 -06:00
Anthony Tuininga
dd31b41036 Added sample demonstrating the use of sharding capabilities. 2020-04-03 13:20:55 -06:00
Anthony Tuininga
8a301721fb Ensure that the new DbType objects are hashable
(https://github.com/oracle/python-cx_Oracle/issues/401).
2020-02-21 15:39:32 -07:00
Anthony Tuininga
52035c3b85 Add missing release note. 2020-02-14 10:33:43 -07:00
Anthony Tuininga
4ffbc9cac8 Added support for specifying the fetch array size when fetching documents from
a SODA collection -- available in Oracle Client 19.5 and higher.
2020-02-14 10:33:07 -07:00
Anthony Tuininga
9beb4aa907 Added support for SODA collection truncate, available in Oracle Client 20 and
higher.
2020-02-14 10:31:08 -07:00
Anthony Tuininga
44be257534 Add support for saving SODA documents into a collection, available in Oracle
Client 20 and higher.
2020-02-14 10:29:07 -07:00
Anthony Tuininga
b897106f00 Update ODPI-C. 2020-02-14 10:18:26 -07:00
Anthony Tuininga
f7b7785e82 Reworked type management to clarify and simplify code (see release notes for
details).
2020-02-10 10:02:03 -07:00
Anthony Tuininga
08346005a7 Use named field structure initialization in order to clarify code and reduce
clutter.
2020-02-10 09:57:30 -07:00
Anthony Tuininga
53a9f41ed1 Correct doc example (https://github.com/oracle/python-cx_Oracle/issues/390). 2020-01-27 09:36:07 -07:00
Anthony Tuininga
31f73b6ea1 Remove self-referencing link. 2020-01-27 09:35:49 -07:00
Anthony Tuininga
4874f68712 Add a second CQN example to demonstrate how to fetch modified rows inside the
notification callback.
2020-01-21 15:03:28 -07:00
Anthony Tuininga
4fd326bb63 Remove unnecessary imports. 2020-01-21 15:03:08 -07:00
Anthony Tuininga
f743d02857 Show how to reduce round trips with session callbacks. 2020-01-21 15:02:20 -07:00
Anthony Tuininga
8d18997d26 Update ODPI-C. 2020-01-21 15:01:59 -07:00
Anthony Tuininga
60fa25eaa1 Remove duplicate word. 2020-01-20 16:58:35 -07:00
Anthony Tuininga
e85a03b57b Remove commented out code 2020-01-06 20:14:11 -07:00
Anthony Tuininga
3666a4ab44 Change default Doc issue category to Enhancement 2020-01-06 20:13:45 -07:00
Anthony Tuininga
face13b7d4 Check the minimum supported Python version and raise an exception if an older
Python version is being used.
2019-12-04 15:20:59 -07:00
Anthony Tuininga
809ead0b9c Added support for starting up a database using a parameter file (PFILE), as
requested (https://github.com/oracle/python-cx_Oracle/issues/295).
2019-12-04 15:07:38 -07:00
Anthony Tuininga
6b73d2223f cx_Oracle 8 when it is released will not support Python 2.7. 2019-12-04 15:06:25 -07:00
Anthony Tuininga
cb1c3aaa73 Explicitly mention Python 3.8 support. 2019-12-02 17:05:17 -07:00
Anthony Tuininga
465024c12b Drop the development status now that cx_Oracle 7.3 is about to be released. 2019-12-02 16:59:23 -07:00
Anthony Tuininga
1ed26d8d86 Preparing to release cx_Oracle 7.3. 2019-12-02 16:37:13 -07:00
Anthony Tuininga
6ca6f2b0c3 Added a sample demonstrating the use of cursor.lastrowid. 2019-12-02 16:35:17 -07:00
Anthony Tuininga
22642e2826 Older versions of Python 2.7 don't have PyMem_Calloc() so use PyMem_Malloc()
and memset() instead for Python 2.7.
2019-11-29 15:20:42 -07:00
Anthony Tuininga
02d336c5e9 Tweak notes about supported versions. 2019-11-29 15:19:45 -07:00
Anthony Tuininga
79902e11e4 Added support for returning the rowid of the last row modified by an operation
on a cursor (or None if no row was modified).
2019-11-29 14:59:56 -07:00
Anthony Tuininga
5f70edd71c Be consistent and always raise cx_Oracle.InterfaceError when a connection is
closed and unusable.
2019-11-29 14:58:47 -07:00
Anthony Tuininga
428746f4de Update ODPI-C. 2019-11-29 14:56:24 -07:00
Anthony Tuininga
2b1bb5c115 Eliminate reference leak when message properties object is destroyed. 2019-11-25 21:43:45 -07:00
Anthony Tuininga
e6d1a981a0 Update ODPI-C. 2019-11-25 21:42:58 -07:00
Anthony Tuininga
7b144440aa Ensure that the session time zone is UTC so that values can be compared without
concern for the time zones of the client and database server.
2019-11-25 21:41:58 -07:00
Anthony Tuininga
0503265184 Add ORA-40479: internal JSON serializer error to the list of exceptions that
result in cx_Oracle.IntegrityError.
2019-11-25 21:41:32 -07:00
Anthony Tuininga
3f27185b9c Use new issue template format. 2019-11-20 14:36:38 -07:00
Anthony Tuininga
6f12ea7363 Eliminate reference leak when splitting the password and dsn components out of
a full connect string.
2019-11-20 14:34:11 -07:00
Anthony Tuininga
c447368230 Eliminate reference leak and ensure that memory is properly initialized in case
of error when using sharding keys.
2019-11-20 14:33:37 -07:00
Anthony Tuininga
efc3160d5f Update IC links following redirection. 2019-11-20 14:33:03 -07:00
Anthony Tuininga
07498fefa1 Various documentation improvements. 2019-11-20 14:31:58 -07:00
Anthony Tuininga
19ff7883be Update ODPI-C. 2019-11-20 14:27:07 -07:00
Anthony Tuininga
3b306187b0 Added support for client initiated connections for subscriptions. 2019-11-13 16:51:23 -07:00
Anthony Tuininga
dad0419003 Documentation improvements and a new section on connecting to Autonomous
Database.
2019-11-13 16:48:47 -07:00
Anthony Tuininga
089639c0f9 A value of T_BOOL must be represented as char and should be treated as such
consistently in order to avoid issues on big-endian architectures.
2019-11-13 16:48:20 -07:00
Anthony Tuininga
80b9a31fa6 Remove invalid test. 2019-11-13 16:48:06 -07:00
Anthony Tuininga
fcbf9ff17c DatabaseError, not ProgrammingError is now returned as this check is performed
at the ODPI-C level.
2019-11-13 16:47:45 -07:00
Anthony Tuininga
495541ca20 Add support for setting maxSessionsPerShard attribute for session pools. 2019-11-13 16:47:09 -07:00
Anthony Tuininga
9cb9842696 Eliminate unnecessary check (ODPI-C performs this check already). 2019-11-13 16:45:55 -07:00
Anthony Tuininga
a7b958d68a Added test cases for pls_integer and binary_integer data types. 2019-11-13 16:44:50 -07:00
Anthony Tuininga
cd9c7e3fa3 Adjust test suite so that it runs unchanged against Oracle Cloud databases:
- administrative user is ADMIN on the Oracle Cloud databases and SYSTEM on
  local databases (SYSDBA is not available on the Oracle Cloud database)
- environment variables CX_ORACLE_TEST_SYSDBA_USER and
  CX_ORACLE_TEST_SYSDBA_PASSWORD are replaced with CX_ORACLE_TEST_ADMIN_USER
  and CX_ORACLE_TEST_ADMIN_PASSWORD
- skip tests that change passwords as passwords on Oracle Cloud database are
  strictly controlled
- skip tests that check subscriptions as these are not currently supported on
  Oracle Cloud database
2019-11-13 16:43:49 -07:00
Anthony Tuininga
952580a565 Adjust samples so that they run unchanged against Oracle Cloud databases:
- administrative user is ADMIN on the Oracle Cloud databases and SYSTEM on
  local databases (SYSDBA is not available on the Oracle Cloud database)
- use dbms_session.sleep() instead of dbms_lock.sleep() where possible
- environment variables CX_ORACLE_SAMPLES_SYSDBA_USER and
  CX_ORACLE_SAMPLES_SYSDBA_PASSWORD are replaced with
  CX_ORACLE_SAMPLES_ADMIN_USER and CX_ORACLE_SAMPLES_ADMIN_PASSWORD
- new environment variable CX_ORACLE_SAMPLES_DRCP_CONNECT_STRING used for
  specifying the connect string to use for DRCP usage
2019-11-13 16:43:07 -07:00
Anthony Tuininga
d16c939f74 Adjust sample to take into account changes made to AQ support. 2019-11-13 16:41:10 -07:00
Anthony Tuininga
13204317d3 Update ODPI-C. 2019-11-13 16:40:23 -07:00
Anthony Tuininga
9b7137fb20 Update ODPI-C and simplify call to get server version. 2019-10-11 15:53:20 -06:00
Anthony Tuininga
e433c720c9 Improved documentation. 2019-10-01 11:17:29 -06:00
Anthony Tuininga
ee893d35f4 Releasing cx_Oracle 7.2.3. 2019-10-01 11:17:08 -06:00
Anthony Tuininga
2d0b4895aa Update ODPI-C. 2019-09-28 15:09:46 -06:00
Christopher Jones
7becddbe9c Update doc links 2019-09-18 23:45:35 +10:00
Anthony Tuininga
942f4aa015 Update ODPI-C. 2019-08-30 10:57:50 -06:00
Anthony Tuininga
4e783a9e67 Improve documentation based on feedback
(https://github.com/oracle/python-cx_Oracle/issues/343).
2019-08-28 10:40:51 -06:00
Anthony Tuininga
a16a944964 Restore support for setting numeric bind variables with boolean values. 2019-08-22 21:39:15 -06:00
Anthony Tuininga
0ecf3e7187 Releasing cx_Oracle 7.2.2. 2019-08-12 21:22:26 -06:00
Anthony Tuininga
06a336926a Bump version back to 7.3 in preparation for additional changes. 2019-08-08 14:23:41 -06:00
Anthony Tuininga
2cec047870 Update to new default PDB service name. 2019-08-08 14:19:23 -06:00
Anthony Tuininga
2c9f8d5ca4 Added user guide. 2019-08-08 14:15:14 -06:00
Anthony Tuininga
3696b35254 Bump version back to 7.2.1 in order to release user guide. 2019-08-08 14:13:51 -06:00
Anthony Tuininga
982a21b891 Clarify that cursor.arrayvar() can only be used for PL/SQL associative arrays
with contiguous keys.
2019-07-26 09:41:58 -06:00
Anthony Tuininga
e87c09a46d Bumped version. 2019-07-25 14:34:43 -06:00
Anthony Tuininga
65c22693a6 Releasing cx_Oracle 7.2.1. 2019-07-25 14:29:33 -06:00
Anthony Tuininga
f91f907adf Correct spelling mistakes and formatting. 2019-07-22 16:55:15 -06:00
Anthony Tuininga
d526de1893 Resolve MemoryError exception on Windows when using an output type handler
(https://github.com/oracle/python-cx_Oracle/issues/330).
2019-07-15 14:23:48 -06:00
Anthony Tuininga
ff25784c21 Use most recent default connect string in tutorial. 2019-07-15 14:23:05 -06:00
Anthony Tuininga
b104d40016 Added a SODA section to the tutorial. 2019-07-15 14:22:28 -06:00
Anthony Tuininga
e37e502724 Added test cases, particularly for bulk AQ operations. 2019-07-05 14:32:59 -06:00
Anthony Tuininga
6bdc8ee465 Improve documentation, particularly regarding proxy usage. 2019-07-05 14:32:12 -06:00
Anthony Tuininga
2ba66bbf71 Release notes for cx_Oracle 7.2. 2019-07-02 14:19:32 -06:00
Anthony Tuininga
d4c2c11517 Remove -dev designation in preparation for release of 7.2. 2019-07-02 14:18:26 -06:00
Anthony Tuininga
846bfab0d0 Add warning for use of Queue.enqMany(). 2019-07-02 14:17:51 -06:00
Anthony Tuininga
13d0f4ec08 Update ODPI-C to public release of 3.2.0. 2019-07-02 14:12:59 -06:00
Anthony Tuininga
955ef7ecf5 Improved session pooling documentation. 2019-07-02 14:12:22 -06:00
Anthony Tuininga
39ff9fc189 Removed preview status from SODA but added a link to the tracking issue. 2019-07-02 14:10:30 -06:00
Anthony Tuininga
15ce3024ee Be clearer about what sort of payloads are supported and in particular what
happens to strings if they are used in RAW queues.
2019-07-02 14:09:48 -06:00
Anthony Tuininga
a120647c76 Add note indicating when attribute was added. 2019-06-19 16:04:46 -06:00
Anthony Tuininga
3c4d83fe6c Adjusted tutorial to use new AQ syntax. 2019-06-19 16:02:55 -06:00
Anthony Tuininga
e6a825db27 Adjusted documentation to follow new API. 2019-06-19 16:02:34 -06:00
Anthony Tuininga
5f8d24dd24 Eliminated deprecation of attribute "id" on subscriptions. It is now populated
with the value of REGID found in the database view
USER_CHANGE_NOTIFICATION_REGS or the value of REG_ID found in the database
view USER_SUBSCR_REGISTRATIONS. For AQ subscriptions, the value is 0.
2019-06-19 16:01:57 -06:00
Anthony Tuininga
1d0dd29676 Update ODPI-C. 2019-06-19 16:01:30 -06:00
Anthony Tuininga
ae6164fc58 Change name of parameter to match documentation. 2019-06-19 16:01:06 -06:00
Anthony Tuininga
e38b4af987 Release the Python GIL while enqueuing and dequeuing messages! 2019-06-19 16:00:42 -06:00
Anthony Tuininga
df56c7f17f Enable PY_SSIZE_T_CLEAN in order to avoid deprecation warning and/or segfault
under Python 3.8.0b1 (https://github.com/oracle/python-cx_Oracle/issues/317).
2019-06-17 16:17:18 -06:00
Anthony Tuininga
d8bde9ca54 Add doc for installing on a machine not connected to the Internet. 2019-06-11 19:15:57 -06:00
Anthony Tuininga
e0bd74e61b Update ODPI-C. 2019-06-11 19:14:02 -06:00
Anthony Tuininga
923eb054fc Clarify release note. 2019-06-11 19:13:43 -06:00
Anthony Tuininga
ee5fe39544 Rename queues and queue tables to be more clear as to which is which. 2019-06-11 19:13:21 -06:00
Anthony Tuininga
c82ae6880d Update doc for the latest Instant Client releases. 2019-06-11 19:12:31 -06:00
Anthony Tuininga
3ab21c9447 Update ODPI-C (corrects issue #300). 2019-05-03 15:49:57 -06:00
Anthony Tuininga
d4498cf9e0 Added support for Advanced Queueing RAW queues and bulk enqueue/dequeue. 2019-05-03 13:21:39 -06:00
Anthony Tuininga
04a7dec0d4 Added mode cx_Oracle.DEFAULT_AUTH as requested
(https://github.com/oracle/python-cx_Oracle/issues/293) and adjusted
documentation for other cases that specified None where None is not actually
a valid value.
2019-04-29 15:24:56 -06:00
Anthony Tuininga
82097891b3 Add support for setting a CLOB attribute on a SQL object, as requested
(https://github.com/oracle/python-cx_Oracle/issues/299).
2019-04-29 11:41:28 -06:00
Anthony Tuininga
ce511e2fb7 Raise an exception when an error takes place
(https://github.com/oracle/python-cx_Oracle/issues/299).
2019-04-29 11:40:48 -06:00
Anthony Tuininga
1c474bbaab Update ODPI-C. 2019-04-26 16:55:38 -06:00
Anthony Tuininga
b9711f5457 Update ODPI-C. 2019-04-25 15:21:48 -06:00
Anthony Tuininga
f4bdd3fd68 Preparing to release cx_Oracle 7.1.3. 2019-04-24 09:57:03 -06:00
Anthony Tuininga
883262da07 Adjust documentation to indicate what cursor.rowcount returns for PL/SQL block
executions (https://github.com/oracle/python-cx_Oracle/issues/285).
2019-03-29 10:41:46 -06:00
Anthony Tuininga
8681366f53 For Python 2.7, raw_input is needed to request input; also ensure that
sample parameters are saved once requested.
2019-03-29 09:49:40 -06:00
Anthony Tuininga
f324757909 Adjust formatting of PR #287. 2019-03-28 11:57:33 -06:00
Andrey Petukhov
a654befddf Cursor.callproc method changed with respect to doc (#287)
Signed-off-by: Andrey Petukhov <APetukhov@bellintegrator.com>
2019-03-28 10:55:30 -07:00
Anthony Tuininga
3af5e46b4b Correct parsing of connect string so that the last @ symbol is searched for
instead of the first @ symbol; otherwise, passwords containing an @ symbol will
result in the incorrect DSN being extracted
(https://github.com/oracle/python-cx_Oracle/issues/290).
2019-03-28 10:46:15 -06:00
Anthony Tuininga
096f8d6412 Add support for getting the row count for PL/SQL statements
(https://github.com/oracle/python-cx_Oracle/issues/285).
2019-03-21 15:45:57 -06:00
Anthony Tuininga
e567eb3a58 Added support for SODA bulk insert available in Oracle Client 18.5 and higher. 2019-03-21 14:59:14 -06:00
Anthony Tuininga
43ebe8afed Bump version in preparation for changes to be included in next version. 2019-03-21 14:57:53 -06:00
Anthony Tuininga
aaa84fe611 Add sample for using the call timeout feature available with cx_Oracle 7.0 and
Oracle Client 18.1 and higher.
2019-03-15 09:40:45 -06:00
Anthony Tuininga
c1e1659a14 Enable cursor.setinputsizes() and cursor.callfunc() to support specifying an
object type where a type is required, not just when a variable is being
created.
2019-03-12 16:42:02 -06:00
Anthony Tuininga
f94bd1d8ac Preparing to release cx_Oracle 7.1.2. 2019-03-12 16:40:45 -06:00
Anthony Tuininga
ad81e94797 Update to ODPI-C 3.1.3. 2019-03-12 16:37:11 -06:00
Anthony Tuininga
c112af35cb Revert changes to return decimal numbers when the numeric precision was too
great to be returned accurately as a floating point number. This change had too
great an impact on existing functionality and an output type handler can be
used to return decimal numbers where that is desirable
(https://github.com/oracle/python-cx_Oracle/issues/279).
2019-03-12 09:31:38 -06:00
Anthony Tuininga
8789c6d2a0 Eliminate memory leak for subscriptions. 2019-03-08 09:57:14 -07:00
Anthony Tuininga
948abd9b7c Update ODPI-C. 2019-03-08 09:56:32 -07:00
Anthony Tuininga
0ae5b9e715 Added test cases for session tagging. 2019-03-07 17:00:14 -07:00
Anthony Tuininga
362aa82ea2 Clarify that the encoding and nencoding parameters are expected to be one of
the Python standard encodings.
2019-03-07 09:36:49 -07:00
Anthony Tuininga
1ccaf68369 Update ODPI-C; bump version in preparation for a new patch release. 2019-03-07 09:34:45 -07:00
Anthony Tuininga
9023609232 Preparing to release cx_Oracle 7.1.1. 2019-02-19 15:05:36 -07:00
Anthony Tuininga
e3d3764f5f Installation doc improvements. 2019-02-19 15:00:00 -07:00
Anthony Tuininga
386d6dbdba Update ODPI-C to 3.1.2. 2019-02-19 14:56:53 -07:00
Anthony Tuininga
ea48873f7a Bump version on README.md in preparation for release of cx_Oracle 7.1. 2019-02-04 16:47:32 -07:00
Anthony Tuininga
5603d2a898 Miscellaneous installation documentation updates. 2019-02-04 16:42:03 -07:00
Anthony Tuininga
3febfa8375 Remove -dev designation in preparation for release of cx_Oracle 7.1. 2019-02-04 15:46:05 -07:00
Anthony Tuininga
eae8a2bf08 Preparing to release cx_Oracle 7.1. 2019-02-04 15:40:04 -07:00
Anthony Tuininga
491e61ac19 Added missing documentation on external authentication and homogeneous pools. 2019-02-04 15:30:21 -07:00
Anthony Tuininga
2f9c01a877 The call to cursor.setinputsizes() is not needed for cx_Oracle 6 and higher. 2019-02-04 15:29:50 -07:00
Anthony Tuininga
c11c24fb0d Update ODPI-C to 3.1.1 in preparation for release of cx_Oracle 7.1. 2019-02-04 15:25:25 -07:00
Anthony Tuininga
ae6375bca0 Use a relative URL so that those cloning against oss.oracle.com will get the
associatied version of ODPI-C from oss.oracle.com as well.
2019-02-04 14:54:12 -07:00
Anthony Tuininga
0924201461 Update ODPI-C. 2019-01-31 10:20:44 -07:00
Anthony Tuininga
fb445815f2 Use random password instead of hard coded password as a security measure. 2019-01-31 10:18:43 -07:00
Anthony Tuininga
4ed95aad94 Reworked test suite to eliminate the use of default passwords and to make the
individual test modules directly runnable (instead of using execfile() within
test.py).
2019-01-31 10:18:04 -07:00
Anthony Tuininga
81583c224d Reworked samples so that no default passwords are defined anywhere; added
Python script to create sample schemas and drop them in addition to having a
SQL*Plus script.
2019-01-31 10:15:40 -07:00
Anthony Tuininga
b8d5479048 Use what will become ODPI-C 3.1.1 as the basis for the next cx_Oracle release. 2019-01-31 10:01:42 -07:00
Anthony Tuininga
9ca1cdd892 Correct typo (https://github.com/oracle/python-cx_Oracle/issues/258). 2019-01-28 09:07:51 -07:00
Anthony Tuininga
c675d4e827 Eliminated memory leak introduced by session tagging changes. 2019-01-24 13:45:16 -07:00
Anthony Tuininga
b51ed5bc87 Added samples for session callbacks in Python and PL/SQL. 2019-01-23 16:32:29 -07:00
Anthony Tuininga
1824dd1aa0 Remove information that is not accurate. 2019-01-22 16:22:08 -07:00
Anthony Tuininga
4097a37ff2 Bump copyright notice into 2019 for changed files. 2019-01-22 16:00:29 -07:00
Anthony Tuininga
ba0d41412f Added test cases for inserting and fetching XMLType objects as strings. 2019-01-22 14:28:25 -07:00
Anthony Tuininga
2cfdb4037c Add a note indicating that TABLE%ROWTYPE records can also be used. 2019-01-22 14:27:43 -07:00
Anthony Tuininga
ed88224241 Added support for a session callback (written in either PL/SQL or Python)
which will be called when the actual tag assigned to a session doesn't match
the tag requested.
2019-01-22 14:25:33 -07:00
Anthony Tuininga
b13c998999 Timed waits for acquiring a session from a session pool is only available in
Oracle 12.2 and higher.
2019-01-22 14:22:39 -07:00
Anthony Tuininga
551204ebcb Correct documentation on pool.release(). 2019-01-22 14:22:06 -07:00
Anthony Tuininga
951e8f4b2b Update ODPI-C. 2019-01-22 11:45:17 -07:00
Anthony Tuininga
1860fdb05b Ensure that values that exceed sizeof(long) for Python 2 on Windows when using
the Oracle type NATIVE_INT are not silently truncated
(https://github.com/oracle/python-cx_Oracle/issues/257).
2019-01-21 20:49:08 -07:00
Anthony Tuininga
43a485042f Add additional check for calling setinputsizes() with an empty dictionary in
order to avoid the error "cx_Oracle.ProgrammingError: positional and named
binds cannot be intermixed"
(https://github.com/oracle/python-cx_Oracle/issues/199).
2019-01-08 14:41:01 -07:00
Anthony Tuininga
b340771c37 Rework handling of numbers so that, unless using the NATIVE_INT,
NATIVE_FLOAT or NATIVE_DOUBLE types, all numbers are converted to strings and
passed through to ODPI-C in all Python versions; improved error message when
a value cannot be represented by an Oracle number value; improved test suite to
verify that calling executemany() with integers, floats and decimal values
intermixed with each other works as expected
(https://github.com/oracle/python-cx_Oracle/issues/241).
2018-12-07 19:16:33 -07:00
Anthony Tuininga
4c12b47573 Update ODPI-C to support fetching XMLType as strings
(https://github.com/oracle/python-cx_Oracle/issues/14).
2018-12-03 10:20:14 -07:00
Anthony Tuininga
ef036cbefc Ensure that all references to TestTempTable use the column names instead of
assuming the number of columns (in preparation for adding additional nullable
columns for other tests).
2018-12-03 10:19:22 -07:00
Anthony Tuininga
8fbc43ac08 Added additional SODA test cases. 2018-11-29 17:21:36 -07:00
Anthony Tuininga
bc89547249 Update ODPI-C. 2018-11-29 17:20:51 -07:00
Anthony Tuininga
00de5ea10f Handle case when first call to cursor.executemany() has one or more columns
that are always null and a subsequent call to cursor.executemany() has a value
other than None in the same column
(https://github.com/oracle/python-cx_Oracle/issues/236).
2018-11-29 17:19:39 -07:00
Anthony Tuininga
e4cef63804 Add comment which is displayed during the test run. 2018-11-29 17:19:20 -07:00
Anthony Tuininga
7ab01bb1b9 Installation tweaks for macOS; replace 12.2 references with 18.3. 2018-11-16 15:24:50 -07:00
Anthony Tuininga
1be0461174 Be clearer about the syntax used for connecting to the database as sys. 2018-11-05 09:53:39 -07:00
Anthony Tuininga
7f1bfd1eb3 Update ODPI-C. 2018-11-02 16:29:35 -06:00
Anthony Tuininga
1abd09717c Correct grammar. 2018-11-02 15:47:37 -06:00
Anthony Tuininga
ae8b4f84aa Entries can remain in v$sql_monitor for a period of time so only look at the
executing one.
2018-11-02 15:45:09 -06:00
Anthony Tuininga
851c9a4650 Add support for getting/setting raw attributes of objects, as requested
(https://github.com/oracle/odpi/issues/72).
2018-11-02 15:44:49 -06:00
Anthony Tuininga
e988d74363 Bump version to 7.1-dev now that changes have been made from version 7.0. 2018-10-31 09:19:27 -06:00
Anthony Tuininga
548440016e Add support for passing an object type (such as those created by the method
connection.gettype()) as the first parameter to cursor.var(), as requested
(https://github.com/oracle/python-cx_Oracle/issues/231).
2018-10-30 16:32:05 -06:00
Anthony Tuininga
4fd6c35436 Allow the type name to be None, as requested
(https://github.com/oracle/python-cx_Oracle/issues/231).
2018-10-30 16:31:47 -06:00
Anthony Tuininga
1fe66420e3 Added code to display new support in cx_Oracle 7 for retrieving a collection as
a dictionary.
2018-10-18 11:08:43 -07:00
Anthony Tuininga
74d9d71484 Use cx_Oracle.connect() in preference to cx_Oracle.Connection() in samples and
tests. Although the two are aliases of one another, it makes sense to be
consistent and to use the one that the DB API prefers as well.
2018-09-21 11:05:40 -06:00
Anthony Tuininga
20c930e2e0 Be more clear about the requirements for use of SODA. 2018-09-14 11:07:22 -06:00
Anthony Tuininga
dfd809b7c8 Correct typos. 2018-09-13 21:16:02 -06:00
Anthony Tuininga
4d368ae980 Preparing to release cx_Oracle 7.0. 2018-09-13 13:38:37 -06:00
Anthony Tuininga
28d6166bb6 Emphasize the file location. 2018-09-13 13:36:35 -06:00
Anthony Tuininga
d9be1ec98e Updates for cx_Oracle 7 and Oracle Client 18.3 as well as some miscellaneous
tweaks.
2018-09-12 15:05:29 -06:00
Anthony Tuininga
fc8cfbdf60 Improve documentation for SODA. 2018-09-11 20:50:28 -06:00
Anthony Tuininga
f647d738a5 Correct documentation now that variables bound to DML returning statements
always return an array.
2018-09-10 15:27:52 -06:00
Anthony Tuininga
bc69e784f8 Adjust copyright notices to match requirements of Oracle Legal. 2018-09-10 11:39:51 -06:00
Anthony Tuininga
d266d6d0fa Adjust sample now that DML returning variables return an array. 2018-09-10 11:39:11 -06:00
Anthony Tuininga
118952b07d Update ODPI-C. 2018-09-10 11:39:03 -06:00
Anthony Tuininga
64f65050a2 Add support (as preview) for SODA. 2018-09-10 11:37:53 -06:00
Anthony Tuininga
b611246a7b Add support for getting the contents of a collection as a dictionary where the
keys are the indexes of the collection and the values are elements of the
collection.
2018-09-03 10:19:26 -06:00
Anthony Tuininga
7946142c88 Update ODPI-C. 2018-09-03 10:19:04 -06:00
Anthony Tuininga
30088c6cdb Added support for closing the session pool. 2018-09-03 10:17:22 -06:00
Anthony Tuininga
cfc6856048 Update ODPI-C (https://github.com/oracle/python-cx_Oracle/issues/212 and
https://github.com/oracle/odpi/issues/69).
2018-08-16 14:09:59 -06:00
Anthony Tuininga
c46bc2165e Adjust wording for Oracle Linux yum server. 2018-08-16 14:09:15 -06:00
Anthony Tuininga
effbb09e09 Correct links. 2018-08-08 16:17:54 -06:00
Anthony Tuininga
18100ccdf3 Standardize GitHub issue template. 2018-08-06 16:06:27 -06:00
Anthony Tuininga
07386a6547 Add note indicating that the full version is not available when using client
libraries 12.2 or lower with Oracle Database 18 or higher.
2018-08-06 16:05:55 -06:00
Anthony Tuininga
fce6a42c76 Add subtitle to macOS section to try to stop the prereq being missed. 2018-08-06 16:05:17 -06:00
Anthony Tuininga
888325989f Adjust documentation now that better error message is produced. 2018-08-06 16:04:40 -06:00
Anthony Tuininga
ea4a9d120e Support for Python 3.4 has been dropped. 2018-08-06 15:34:50 -06:00
Anthony Tuininga
d1d9b7da30 Documentation updates for Oracle Client 18 and a few other tweaks. 2018-08-06 15:34:23 -06:00
Anthony Tuininga
7b66391ea0 Update ODPI-C. 2018-08-06 15:30:18 -06:00
Anthony Tuininga
fc3450d48a Add support for call timeouts available in Oracle 18c and higher. 2018-07-12 10:46:12 -06:00
Anthony Tuininga
dc2601729a Remove __future__ attributes for functionality which is now enabled permanently
in cx_Oracle 7: connections as context managers now close the connection and
variables in DML returning statements now return an array.
2018-07-12 10:45:40 -06:00
Anthony Tuininga
866df60fbc Bump version to 7.0 and use ODPI-C master branch (3.0). 2018-07-12 10:45:15 -06:00
Anthony Tuininga
c832ed10d1 Preparing to release cx_Oracle 6.4.1. 2018-07-09 11:21:02 -06:00
Anthony Tuininga
e801579d93 Update ODPI-C. 2018-07-09 11:20:24 -06:00
Anthony Tuininga
fee92abe5a If cursor.setinputsizes() is called without any parameters, do not set the flag
indicating that bind variables should be returned since otherwise binding with
named arguments will raise the error "cx_Oracle.ProgrammingError: positional
and named binds cannot be intermixed"
(https://github.com/oracle/python-cx_Oracle/issues/199).
2018-07-03 13:36:10 -06:00
Anthony Tuininga
4f85998a84 Bump version in README. 2018-07-02 16:01:31 -06:00
Anthony Tuininga
1a7b7257a7 Bump version to 6.4. 2018-07-02 13:51:00 -06:00
Anthony Tuininga
bc1f7e6ead Preparing to release cx_Oracle 6.4. 2018-07-02 13:46:59 -06:00
Anthony Tuininga
77b853d4fb Update ODPI-C. 2018-06-26 20:31:28 -06:00
Anthony Tuininga
fb249f5944 Ensure that the row count for queries is reset to zero when the statement is
executed (https://github.com/oracle/python-cx_Oracle/issues/193).
2018-06-25 15:57:19 -06:00
Anthony Tuininga
a8751e91f4 Added support for using the cursor as a context manager
(https://github.com/oracle/python-cx_Oracle/issues/190).
2018-06-21 11:29:11 -06:00
Anthony Tuininga
4d4b319714 Add support for specifying the "errors" parameter to the decode() that takes
place internally when fetching strings from the database
(https://github.com/oracle/python-cx_Oracle/issues/162).
2018-06-19 11:11:04 -06:00
Anthony Tuininga
e6d5153e43 Added additional test cases for heterogeneous pools. 2018-06-19 11:10:26 -06:00
Anthony Tuininga
7adf99f0ad Added support for unsubscribing from events in the database. 2018-06-19 11:09:40 -06:00
Anthony Tuininga
510ab50ba7 Remove mention of the next() method which is only there in Python 2.x if the
cursor is being used as an iterator and is not actually part of cx_Oracle's
code.
2018-06-19 11:08:04 -06:00
Anthony Tuininga
cf1265cb2d Use the non-deprecated function for subscribing to events in the database and
note that the subscription ID will always be zero and will be removed in
cx_Oracle 7.
2018-06-19 11:07:30 -06:00
Anthony Tuininga
feab53cbff Use unsigned integers instead of signed integers where it makes sense to do so. 2018-06-19 11:06:58 -06:00
Anthony Tuininga
4e53b9074b Improve documentation. 2018-06-19 11:05:44 -06:00
Anthony Tuininga
787fc5b33c Use ODPI-C v2.x branch for cx_Oracle 6.4. 2018-06-19 11:04:03 -06:00
Anthony Tuininga
980f3d491c Added support for indicating if the subscription is still registered with the
database when a notification is received.
2018-06-19 11:00:53 -06:00
Anthony Tuininga
7b9ce90842 Bump version. 2018-06-11 20:20:39 -06:00
Anthony Tuininga
42e1663abb Adjust documentation to improve clarity. 2018-05-29 21:56:37 -06:00
Anthony Tuininga
85a0ad3ee3 Use the built-in type SYS_REFCURSOR instead of creating a new one. 2018-05-29 21:55:45 -06:00
Anthony Tuininga
c31eef50de Correct handling of statements and rowids in DML returning statements. 2018-05-29 21:55:26 -06:00
Anthony Tuininga
211298209b Added support for receiving notifications when AQ messages are available to be
dequeued.
2018-05-29 21:54:06 -06:00
Anthony Tuininga
6583cdfc51 Update ODPI-C. 2018-05-29 21:51:50 -06:00
Anthony Tuininga
9781810b8e Added support for binding decimal.Decimal values to cx_Oracle.NATIVE_FLOAT as
requested in issue 184
(https://github.com/oracle/python-cx_Oracle/issues/184).
2018-05-24 16:36:58 -06:00
Anthony Tuininga
8cc7b893f2 Ensure that binding a boolean value outside of PL/SQL simply binds the integer
0 or 1 (https://github.com/oracle/python-cx_Oracle/issues/181).
2018-05-19 21:35:37 -06:00
Anthony Tuininga
67d374b296 Update ODPI-C. 2018-05-19 21:35:06 -06:00
Anthony Tuininga
99866aed94 Clarify documentation a bit. 2018-05-18 14:35:30 -06:00
Anthony Tuininga
7b2195c37c Added sample demonstrating the use of REF cursors. 2018-05-18 14:25:20 -06:00
Anthony Tuininga
52f4e7090c Rename sample and adjust documentation in sample to clarify use. 2018-05-18 14:24:52 -06:00
Anthony Tuininga
84ee1301bc Adjust data values to clarify distinction between "parent" and "child" values. 2018-05-18 14:23:54 -06:00
Anthony Tuininga
c8c44ff698 Rename sample to match feature name. 2018-05-18 14:23:08 -06:00
Anthony Tuininga
b9381892a5 Added support for timed waits when acquiring a session from a session pool and
added support for specifying the timeout and maximum lifetime session of
sessions in the pool when the pool is being created.
2018-05-16 14:09:59 -06:00
Anthony Tuininga
62f11ac570 Clarify documentation on variables. 2018-05-16 14:09:33 -06:00
Anthony Tuininga
4ec7685f95 Added support for grouping notifications from subscriptions. 2018-05-16 14:09:01 -06:00
Anthony Tuininga
bab41ac544 Added support for specifying the IP address the subscription should use instead
of having the Oracle Client library determine the IP address on its own.
2018-05-16 14:08:28 -06:00
Anthony Tuininga
23fac6841a Update ODPI-C. 2018-05-16 14:08:20 -06:00
Anthony Tuininga
005a00c03d Added additional test cases and corrected test case for ltxid when
using 11.2 client.
2018-05-09 19:36:13 -06:00
Anthony Tuininga
756442ee24 Added checks on passing invalid parameters to cursor.var(),
cursor.arrayvar(), cursor.callfunc() and cursor.setinputsizes().
2018-05-09 19:35:49 -06:00
Anthony Tuininga
f7a9eae0e7 Correct formatting. 2018-05-09 19:35:28 -06:00
Anthony Tuininga
2272af1563 Add support for specifying an integer for the parameters argument to
cursor.executemany(). This allows for batch execution when no parameters are
required or when parameters have previously been bound. This replaces
cursor.executemanyprepared() which is now deprecated and will be removed in
cx_Oracle 7.
2018-05-09 19:35:00 -06:00
Anthony Tuininga
d9c50574f5 Added test cases for AQ transformations and trimming collections. 2018-05-09 19:34:21 -06:00
Anthony Tuininga
449d6b8b3c Add missing import; clarify example. 2018-05-09 19:33:26 -06:00
Anthony Tuininga
1dbfb60c61 Clarify documentation surrounding variable.actualElements. 2018-05-07 21:10:22 -06:00
Anthony Tuininga
3288cffe5c Preparing to release cx_Oracle 6.3.1. 2018-05-07 15:23:49 -06:00
Anthony Tuininga
355d7f34aa Added additional test to verify case when a DML returning statement returns
multiple rows during one execute but in the subsequent execute it returns no
rows.
2018-05-04 21:35:37 -06:00
Anthony Tuininga
721f32eb43 Include transaction id in information printed to stdout, just like for query
change notification.
2018-05-04 21:35:07 -06:00
Anthony Tuininga
0392c260e4 Update ODPI-C. 2018-05-04 21:34:14 -06:00
Anthony Tuininga
f39ebf8da8 Ensure that the behavior in cx_Oracle 6.3 with __future__.dml_ret_array_val not
set or False is the same as the behavior in cx_Oracle 6.2
(https://github.com/oracle/python-cx_Oracle/issues/176).
2018-05-01 15:27:18 -06:00
Anthony Tuininga
d62c20bc1f Add a more explicit note about the dependency on GeoPandas. 2018-04-30 13:12:06 -06:00
Anthony Tuininga
a883ff0f7d Add sample from David Lapp demonstrating the use of GeoPandas with
SDO_GEOMETRY.
2018-04-30 11:40:48 -06:00
Anthony Tuininga
d242d6ff2f Preparing to release cx_Oracle 6.3. 2018-04-26 09:16:13 -06:00
Blaine Carter
6fd56a5d41 Modified the solutions of the HoL for Collaborate (#170)
added db_config and made changes to solutions to use db_config values
2018-04-21 10:08:04 -07:00
Blaine Carter
bae5cbe76a Modified the HoL for Collaborate (#169)
Modified samples and instructions to import common connection information from db_config.py or db_config.sql in order to make setup a bit more generic.
2018-04-20 15:35:17 -07:00
Anthony Tuininga
4d37c85974 Use default values for all parameters when creating a session pool. 2018-04-19 14:22:01 -06:00
Anthony Tuininga
e763419b59 Ensure that decreasing number of rows returned from a DML returning statement
is detected properly.
2018-04-19 14:21:26 -06:00
Anthony Tuininga
8fcea38b27 Update ODPI-C. 2018-04-19 14:20:31 -06:00
Anthony Tuininga
9baa55b3bf Added support for building cx_Oracle with a pre-compiled version of ODPI-C,
as requested (https://github.com/oracle/python-cx_Oracle/issues/103).
2018-03-31 15:58:04 -06:00
Anthony Tuininga
623718f0eb Use a cx_Oracle._Error object (not a string) for all cx_Oracle exception types,
as suggested (https://github.com/oracle/python-cx_Oracle/issues/51).
2018-03-31 15:35:02 -06:00
Anthony Tuininga
4f5c04f50c Added documentation stating that batch errors and array DML row counts are only
supported when executing insert, update, delete and merge statements and that
in all other cases an exception will be raised
(https://github.com/oracle/python-cx_Oracle/issues/31).
2018-03-31 14:51:08 -06:00
Anthony Tuininga
fac7f9c3cf Check validity of year for Python 2.x since it doesn't do that itself like
Python 3.x does (https://github.com/oracle/python-cx_Oracle/issues/166).
2018-03-29 13:58:54 -06:00
Anthony Tuininga
c61973c28f Added support for DML returning of multiple rows using cursor.executemany(). 2018-03-28 16:24:41 -06:00
Anthony Tuininga
b753ca7bdf Ensure that round trip is performed without holding the Python GIL
(https://github.com/oracle/python-cx_Oracle/issues/158).
2018-03-21 14:16:15 -06:00
Anthony Tuininga
2901740faa Adjust documentation to provide additional information on the use of
cursor.executemany() as requested
(https://github.com/oracle/python-cx_Oracle/issues/153).
2018-03-21 13:38:08 -06:00
Anthony Tuininga
e15851220b Correct the handling of ANSI types REAL and DOUBLE PRECISION as implemented by
Oracle. These types are just subtypes of NUMBER and are not actually stored as
native floating point numbers. Native floating point numbers are used with
Oracle types BINARY_FLOAT and BINARY_DOUBLE
(https://github.com/oracle/python-cx_Oracle/issues/163).
2018-03-21 11:46:17 -06:00
Anthony Tuininga
4f42099d21 Ensure that a reasonable error message can be provided when an unsupported
Oracle type is encountered.
2018-03-21 11:45:41 -06:00
Anthony Tuininga
48571852ca Add test demonstrating that binding of long data using cursor.executemany()
works as expected.
2018-03-19 10:55:26 -06:00
Anthony Tuininga
148419e14e Update ODPI-C. 2018-03-19 10:53:36 -06:00
Anthony Tuininga
813728ab72 Add support for binding integers and floats as cx_Oracle.NATIVE_FLOAT. 2018-03-07 16:19:01 -07:00
Anthony Tuininga
4392f7ec7b There is no need to set the fetch array size for statements that are not
queries.
2018-03-07 16:18:30 -07:00
Anthony Tuininga
98d35e67b3 Bump version to 6.3-dev in anticipation of new features landing. 2018-03-07 16:18:01 -07:00
Anthony Tuininga
6f928b0857 Preparing to release cx_Oracle 6.2.1. 2018-03-07 10:11:37 -07:00
Anthony Tuininga
b6ad809cb3 Make sure cxoModule.h is included in the source archive
(https://github.com/oracle/python-cx_Oracle/issues/155).
2018-03-06 10:14:57 -07:00
Anthony Tuininga
552fcfb48e Bump license year; simplify README and avoid duplication. 2018-03-05 16:34:53 -07:00
Anthony Tuininga
9cb2ef84bf Correct formatting of release note. 2018-03-05 14:01:10 -07:00
Anthony Tuininga
fb0d7517e8 Preparing to release cx_Oracle 6.2. 2018-03-05 13:46:39 -07:00
Anthony Tuininga
1fd7940494 Ensure that error ORA-24816: Expanded non LONG bind data supplied after actual
LONG or LOB column" is not raised by ensuring an empty string does not use a
size of zero (which triggers this situation in Oracle 12.1).
2018-03-05 13:37:32 -07:00
Anthony Tuininga
592735f104 Update ODPI-C to 2.2.1. 2018-03-05 13:34:27 -07:00
Anthony Tuininga
beffe38b23 Correct formatting of release note. 2018-03-05 13:33:31 -07:00
Anthony Tuininga
b308a9f08b Update ODPI-C (eliminate memory leak when fetching collections from the
database).
2018-03-02 13:18:22 -07:00
Anthony Tuininga
e08e23bb93 Eliminate memory leak when extending a collection. 2018-03-02 13:17:21 -07:00
Anthony Tuininga
9264805596 Update ODPI-C (resolve memory leak using NCHAR and NVARCHAR2 values). 2018-02-27 16:58:53 -07:00
Anthony Tuininga
1bd8e95807 Added support for closing the connection when reaching the end of a code block
controlled by the connection as a context manager, but in a backwards
compatible way (https://github.com/oracle/python-cx_Oracle/issues/113).
2018-02-27 16:58:01 -07:00
Anthony Tuininga
ebfc8d4f9c Use new naming standard in top-level module code as well. 2018-02-27 16:57:31 -07:00
Anthony Tuininga
07b3b93da1 Add additional test cases. 2018-02-27 16:57:01 -07:00
Anthony Tuininga
46e3aff3fa Ensure that the number of elements in the array is not lost when the buffer
size is increased to accommodate larger strings.
2018-02-16 16:23:09 -07:00
Anthony Tuininga
ecb6ee4442 Import print_function for Python 2 compatibility. 2018-02-16 16:22:34 -07:00
Anthony Tuininga
9b1ce308b1 Added support for creating a temporary LOB directly. 2018-02-16 16:21:32 -07:00
Anthony Tuininga
d9cf469167 Correct binding of LOB values. 2018-02-16 16:20:50 -07:00
Anthony Tuininga
0d3aa46d02 Simplify code. 2018-02-16 16:20:29 -07:00
Anthony Tuininga
ce560d7330 Work on Visual Studio redistributable and PATH steps. 2018-02-15 11:20:58 -07:00
Anthony Tuininga
0784f76192 Use (new) canonical link for Instant Client home page. 2018-02-15 11:20:35 -07:00
Anthony Tuininga
54dcf8642b Added test cases for recent ODPI-C bug fixes. 2018-02-15 11:18:15 -07:00
Anthony Tuininga
58757cadb7 Update ODPI-C (eliminate memory leak enqueuing/dequeuing objects; correct
handling of boundary numbers 1e126 and -1e126; eliminate ability to destroy
"parent" object before "child" object).
2018-02-15 11:16:20 -07:00
Anthony Tuininga
dbe9e45653 Update ODPI-C. 2018-02-05 13:57:41 -07:00
Anthony Tuininga
6e3b578281 Eliminate reference leak with LOB values acquired from attributes of objects or
elements of collections.
2018-02-02 15:45:21 -07:00
Anthony Tuininga
99c019d6c5 Restore support for binding a date value to datetime variable. 2018-02-02 15:44:45 -07:00
Anthony Tuininga
a9cda2a81d Update ODPI-C (avoid call to OCITransRollback() is no transaction in progress). 2018-02-02 15:43:44 -07:00
Anthony Tuininga
5171ede9c2 Correct handling of Oracle objects after consolidation of transformations
to/from Python objects.
2018-02-02 15:42:57 -07:00
Anthony Tuininga
242d751d6c Clarify that Python.h is only needed for compilation. 2018-02-02 15:40:53 -07:00
Anthony Tuininga
7e2663606d Various improvements to installation documentation. 2018-01-30 15:26:48 -07:00
Anthony Tuininga
65580226cd Added test cases for AQ visibility and delivery modes. 2018-01-30 15:25:56 -07:00
Anthony Tuininga
00330794be Update ODPI-C (improve error message when using bind variables in DDL
statements).
2018-01-29 18:52:31 -07:00
Anthony Tuininga
a864450186 Simplify Makefile based on Sphinx 1.2+ capabilities. 2018-01-29 18:51:31 -07:00
Anthony Tuininga
e5b6370bd0 Reorganize code to implement the following:
- use a prefix of cxo/CXO for all variables, methods and constants
  - create common include file and use separate compilation units
  - consolidate all transformations to/from Python objects
2018-01-29 18:50:18 -07:00
Anthony Tuininga
fa43311bbc Update ODPI-C; remove error "DPI-1054: connection cannot be closed when open
statements or LOBs exist"
(https://github.com/oracle/python-cx_Oracle/issues/138).
2018-01-26 21:18:16 -07:00
Anthony Tuininga
5b20ca92f4 Time only variables are not supported by Oracle so make that clear in the
documentation.
2018-01-11 16:55:59 -07:00
Anthony Tuininga
6a998604ce The attribute connection.dbop is only valid with Oracle 12.1 and higher. 2018-01-11 16:24:42 -07:00
Anthony Tuininga
ef60884570 Additional test cases to improve code coverage. 2018-01-11 16:24:08 -07:00
Anthony Tuininga
18b014a19e Correct support in Python 3.x for cursor.parse(). 2018-01-11 14:20:51 -07:00
Anthony Tuininga
8dfd842cfd Revert last change (restriction is deliberate). 2017-12-15 09:00:56 -07:00
Anthony Tuininga
cf19bc7f74 Remove unnecessary type checks since PyFloat_AsDouble() will convert the value
to floating point if possible anyway, and if not, will raise an appropriate
exception.
2017-12-15 08:49:27 -07:00
Anthony Tuininga
273d36e4ba Correct formatting. 2017-12-14 20:56:46 -07:00
Anthony Tuininga
ad57a5e858 Preparing to release 6.1. 2017-12-12 12:12:15 -07:00
Anthony Tuininga
8630c86b01 Improve documentation for installation. 2017-12-12 12:11:51 -07:00
Anthony Tuininga
1d7f50971b Refactor README.md. 2017-12-12 12:10:44 -07:00
Anthony Tuininga
ab4cde01b7 Use "wait" mode for acquiring connections from the pool in order to avoid
potential errors under certain circumstances.
2017-12-12 12:09:32 -07:00
Anthony Tuininga
4db53286b7 Update ODPI-C (final 2.1 tag). 2017-12-12 12:08:29 -07:00
Anthony Tuininga
9ae0f5dd1c Use the correct designation for the external handle parameter. 2017-12-11 15:41:48 -07:00
Anthony Tuininga
9953505e54 Update ODPI-C (correct setting subscription port number -
https://github.com/oracle/python-cx_Oracle/issues/115).
2017-12-07 15:57:15 -07:00
Anthony Tuininga
5d728693ca Eliminate compiler warnings on 32-bit Windows. 2017-12-07 15:56:26 -07:00
Anthony Tuininga
864780da2a Use long long instead of just long in order to avoid truncation on Windows
where sizeof(long) != sizeof(void*).
2017-12-07 15:55:46 -07:00
Anthony Tuininga
0b408253f6 Added test for creating a connection using an existing connection's handle. 2017-12-07 15:55:13 -07:00
Anthony Tuininga
a8d9b74c3a Added preliminary test cases for subscriptions. 2017-12-07 15:54:11 -07:00
Anthony Tuininga
1fe14c66dc Use safer queries for verifying connection properties. 2017-12-07 15:52:34 -07:00
Anthony Tuininga
b262d1ca7b Clarify usage of parameters passed to cursor.execute(). 2017-12-07 15:52:02 -07:00
Anthony Tuininga
681c18675e Update ODPI-C (adjust OCI prefetch; added options for authentication with
SYSBACKUP, SYSDG, SYSKM and SYSRAC, as requested
(https://github.com/oracle/python-cx_Oracle/issues/101).
2017-11-27 10:40:19 -07:00
Anthony Tuininga
fb71f1126b Additional test cases for AQ. 2017-11-27 10:38:27 -07:00
Anthony Tuininga
011e062aa1 Added test cases for autocommit, changing passwords and the end-to-end tracing
attributes.
2017-11-27 10:37:46 -07:00
Anthony Tuininga
885904c166 Remove unnecessary line. 2017-11-17 21:40:28 -07:00
Anthony Tuininga
abd472f950 Add note that edition and cclass parameters cannot be used together. 2017-11-17 21:40:00 -07:00
Anthony Tuininga
5625a320c9 Correct reference handling when an invalid keyword parameter is passed to the
cx_Oracle.SessionPool constructor.
2017-11-17 21:39:26 -07:00
Anthony Tuininga
731c8410b3 Correct name of data dictionary view for DRCP sample. 2017-11-17 21:38:59 -07:00
Anthony Tuininga
a3a936b992 Update ODPI-C (prevent attempts to close statements or free temporary LOBs if
the connection has already been closed or killed).
2017-11-17 21:37:42 -07:00
Anthony Tuininga
f26fb5157e Ensure that the edition is passed through to ODPI-C when a session pool is
created.
2017-11-17 13:41:49 -07:00
Anthony Tuininga
cb07970d2f Remove unnecessary lines. 2017-11-16 09:43:31 -07:00
Anthony Tuininga
ed7bd281f2
Merge pull request #54 from vnaydionov/pypy-pip-install
Fix build with PyPy 5.9.0-alpha0 in libpython mode
2017-11-16 08:42:24 -08:00
Anthony Tuininga
9377175715 Added test cases for validating object types and for preventing an attempt to
set a LOB variable at an array position that doesn't exist.
2017-11-14 11:03:11 -07:00
Anthony Tuininga
02c5f5eb5d Correct test suite when CHAR encoding is not capable of handling unicode data. 2017-11-14 11:02:41 -07:00
Anthony Tuininga
3dc1fc497e Update ODPI-C (restrict maximum size of variables to OCI limit; remove invalid
overflow check).
2017-11-14 11:01:25 -07:00
Anthony Tuininga
c122690ac4 Add support for identifying the id of the transaction which spawned the
message, as requested (https://github.com/oracle/odpi/issues/32).
2017-11-08 10:18:18 -08:00
Anthony Tuininga
26c3a4c243 Update ODPI-C (for older versions of Visual Studio). 2017-11-06 13:41:59 -07:00
Anthony Tuininga
9a2775763f Correct link. 2017-11-06 11:36:51 -07:00
Anthony Tuininga
5bcb25e661 Include release notes for cx_Oracle 6.0.3 released on the v6.0.x branch. 2017-11-06 11:33:06 -07:00
Anthony Tuininga
9bdc5cb5d6 Check variable array size when setting variable values and raise IndexError, as
is already done for getting variable values.
2017-11-03 21:31:02 -06:00
Anthony Tuininga
22b6de785a Update ODPI-C (correct handling of NVARCHAR2 object attributes and collection
elements).
2017-11-03 21:30:27 -06:00
Anthony Tuininga
836b9985fb Update ODPI-C (verify that objects bound to cursors or set in object attributes
or appended to collection objects are of the correct type).
2017-10-27 21:34:32 -06:00
Anthony Tuininga
0e4c5621ef Improve documentation for the connection attribute "current_schema". 2017-10-27 21:11:03 -06:00
Anthony Tuininga
86564b9df3 Update ODPI-C (replace usage of OCI thread key with thread-safe handle pool). 2017-10-24 22:05:20 -06:00
Anthony Tuininga
011bc15fcc Simplify sample for returning numbers as decimal objects. 2017-10-24 22:04:17 -06:00
Anthony Tuininga
d4b13eb584 Added test cases for rowids. 2017-10-24 22:03:47 -06:00
Anthony Tuininga
bc1f53f213 Use dpiData_setTimestamp() instead of setting the values directly. 2017-10-24 22:03:06 -06:00
Anthony Tuininga
94731b87e4 Update ODPI-C
- prevent use of NaN with Oracle numbers since it produces corrupt data
  (https://github.com/oracle/python-cx_Oracle/issues/91)
- correct handling of double values when converted to float values.
2017-10-13 19:18:22 -06:00
Anthony Tuininga
78bc40cabf Correct documentation for creating session pools; improve wording in a number
of places.
2017-10-13 19:17:07 -06:00
Anthony Tuininga
c8cd26021d Adjusted formatting of documentation source pages in order to be consistent on
all pages.
2017-10-13 19:16:42 -06:00
Anthony Tuininga
cbbc2addb1 Add Oracle Open World 2017 Hands-on Lab (tutorial). 2017-10-13 19:14:39 -06:00
Anthony Tuininga
76f01f0d4c Correct usage. 2017-10-13 19:14:17 -06:00
Anthony Tuininga
ef201bde74 Added additional LOB function tests; skip supplemental characters test if
database character set is not AL32UTF8.
2017-10-13 19:13:42 -06:00
Anthony Tuininga
c43d2418bb Correct typo. 2017-09-13 10:12:22 -06:00
Anthony Tuininga
525f76d390 Update ODPI-C. 2017-09-13 09:35:14 -06:00
Anthony Tuininga
7fc5127aaa Added support for connecting to specific shards of a sharded database by
specifying a shard key.
2017-09-12 13:29:47 -06:00
Anthony Tuininga
84612bfabe Correct constant references. 2017-09-12 13:29:01 -06:00
Anthony Tuininga
0648181afd Correct typo. 2017-09-12 13:27:30 -06:00
Anthony Tuininga
e8f15874d3 Update ODPI-C (https://github.com/oracle/python-cx_Oracle/issues/77). 2017-09-04 14:18:44 -06:00
Anthony Tuininga
f98a4f334a Improve documentation on closing connections (or releasing them back to the
pool).
2017-09-01 16:22:44 -06:00
Anthony Tuininga
22f18c6f62 Update ODPI-C. 2017-09-01 16:22:14 -06:00
Anthony Tuininga
3d8b74e77f Ensure that a call to setinputsizes() with an invalid type prior to a call to
executemany() does not result in a type error, but instead gracefully ignores
the call to setinputsizes() as required by the DB API
(https://github.com/oracle/python-cx_Oracle/issues/75).
2017-09-01 16:21:28 -06:00
Anthony Tuininga
bc1769b69e Correct typo. 2017-08-30 13:00:34 -06:00
Anthony Tuininga
f0ae2ae138 Released cx_Oracle 6.0.2. 2017-08-30 13:00:19 -06:00
Anthony Tuininga
481371fb50 Adjust samples to handle the deregistration event without an exception. 2017-08-30 11:56:55 -06:00
Anthony Tuininga
ec2f82ca95 Update ODPI-C (eliminate memory leak when creating objects). 2017-08-30 11:55:46 -06:00
Anthony Tuininga
f59a86f391 Troubleshooting tweaks. 2017-08-30 11:55:19 -06:00
Anthony Tuininga
7b484bce70 Eliminate segfault when attempting to reuse a REF cursor that has been closed. 2017-08-30 11:54:33 -06:00
Anthony Tuininga
d82874266c Update documentation indicating that replacing elements in the attributes
fetchvars and bindvars should not be done.
2017-08-28 11:15:43 -06:00
Anthony Tuininga
4e845c62ed Update ODPI-C (process deregistration events without an error). 2017-08-28 11:15:15 -06:00
Anthony Tuininga
0111431430 Update ODPI-C (improve performance, correct handling of objects when dynamic
binding is being used).
2017-08-24 21:50:29 -06:00
Anthony Tuininga
c2c8d541bf On Windows, sizeof(long) = 4 which means that integers between 10 and 18 digits
were not converted to Python correctly
(https://github.com/oracle/python-cx_Oracle/issues/70).
2017-08-22 21:40:21 -06:00
Anthony Tuininga
a48fcdfde2 Ensure that fetch indicators are reset, even if the fetch variables themselves
do not need to be created.
2017-08-22 11:51:58 -06:00
Anthony Tuininga
5837e71cd8 Eliminate memory leak when repeatedly executing the same query. 2017-08-21 16:10:11 -06:00
Viacheslav Naydenov
d43b3eee70 Fix build with PyPy 5.9.0-alpha0 in libpython mode
Signed-off-by: Viacheslav Naydenov <vaclav@yandex.ru>
2017-08-21 22:46:21 +03:00
Anthony Tuininga
06713c91e5 Don't prevent connection from being explicitly closed when a fatal error has
taken place (https://github.com/oracle/python-cx_Oracle/issues/67).
2017-08-18 15:49:00 -06:00
Anthony Tuininga
7b6276f5eb Added missing type check to prevent coercion of decimal to float
(https://github.com/oracle/python-cx_Oracle/issues/68).
2017-08-18 14:15:50 -06:00
Anthony Tuininga
6582aac5d7 Preparing to release 6.0.1. 2017-08-18 11:01:21 -06:00
Anthony Tuininga
c11a5f93c2 Remove documentation on attributes that were removed in 6.0. 2017-08-18 11:00:15 -06:00
Anthony Tuininga
90f571c660 Update ODPI-C to 2.0.1. 2017-08-18 10:59:33 -06:00
Anthony Tuininga
2f1cd73cc5 Include the README.txt and LICENSE.txt files in the wheels that are produced. 2017-08-18 10:57:37 -06:00
Anthony Tuininga
e9dd940207 Added "What's New" page containing a summary of the changes from 5.3 to 6.0 as
a convenience.
2017-08-15 09:30:47 -06:00
Anthony Tuininga
7b7bad308f RPM and Windows installers are no longer supported on PyPI, so no need to
include code managing them in setup.py.
2017-08-15 09:30:09 -06:00
Anthony Tuininga
80e611a24d The SQL files for creating/dropping the schemas should be included in the
source packages.
2017-08-15 09:29:08 -06:00
Anthony Tuininga
853cc14eed Troubleshooting changes. Initcap fix. Put platform at sentence heads. Reorder
points.
2017-08-15 09:28:24 -06:00
Anthony Tuininga
61e28b42b0 Correct formatting. 2017-08-14 18:16:43 -06:00
Anthony Tuininga
c761d1361e Documentation tweaks. 2017-08-11 16:57:14 -06:00
Anthony Tuininga
49bc108108 Tweak troubleshooting section to make it easier to read and also mention that
restarting the command prompt is necessary on Windows when environment
variables have been changed.
2017-08-11 11:49:19 -06:00
Anthony Tuininga
b30e66fa8a Preparing to release cx_Oracle 6.0. 2017-08-11 11:29:44 -06:00
Anthony Tuininga
f1f5ead2a4 Update ODPI-C. 2017-08-11 11:13:05 -06:00
Anthony Tuininga
d1b5428879 Add information on how to run the test suite
(https://github.com/oracle/python-cx_Oracle/issues/33).
2017-08-08 15:40:05 -06:00
Anthony Tuininga
b07d555fb2 Update ODPI-C. 2017-08-08 15:39:44 -06:00
Anthony Tuininga
3e2dd725ad Change default connectstring to localhost/orclpdb to be consistent with the
default value used in the Oracle Database installer.
2017-08-08 15:39:02 -06:00
Anthony Tuininga
f13a9def79 Uppercase the Oracle type name to match recent capitalization of types. 2017-08-08 11:57:49 -06:00
Anthony Tuininga
69e1afbd2f Improve documentation for installing cx_Oracle. 2017-08-08 11:57:19 -06:00
Anthony Tuininga
6b412a019f Update ODPI-C. 2017-08-08 11:56:57 -06:00
Anthony Tuininga
ece92442ab Delay initialization of the ODPI-C library until the first standalone
connection or session pool is created so that manipulation of the environment
variable NLS_LANG can be performed after the module has been imported
(https://github.com/oracle/python-cx_Oracle/issues/36); this also has the added
benefit of reducing the number of errors that can take place when the module is
imported.
2017-07-31 21:21:32 -06:00
Anthony Tuininga
16bc500c73 All cursors and LOBs must be closed before a connection can be closed
explicitly.
2017-07-31 21:20:30 -06:00
Anthony Tuininga
f587b341d3 ODPI-C debugging is now controlled at runtime by the environment variable
DPI_DEBUG_LEVEL, rather than at compile time.
2017-07-31 21:19:52 -06:00
Anthony Tuininga
456a001d73 Update ODPI-C. 2017-07-27 20:47:52 -06:00
Anthony Tuininga
54919a2d7c RPM files are no longer able to be uploaded to PyPI. 2017-07-27 20:47:08 -06:00
Anthony Tuininga
4c4513f476 Improve documentation. 2017-07-27 20:46:21 -06:00
Anthony Tuininga
7edc0ddd83 New GitHub SUPPORT file. 2017-07-25 12:17:25 -06:00
Anthony Tuininga
1f917aafbb In certain cases where non-long values follow LOB values in the list of bind
variables, the error "ORA-24816: Expanded non LONG bind data supplied after
actual LONG or LOB column" is raised; this occurs if the length of the supplied
value, when expanded, might exceed 4000 bytes
(https://github.com/oracle/python-cx_Oracle/issues/50).
2017-07-25 12:16:54 -06:00
Anthony Tuininga
af01c81a1b Improve installation documentation. 2017-07-24 10:36:33 -06:00
Anthony Tuininga
22dc8c1daa Preparing to release cx_Oracle 6 rc 2. 2017-07-24 10:35:41 -06:00
Anthony Tuininga
852aed3b58 Ensure that the array position passed to var.getvalue() does not exceed the
number of elements allocated in the array!
2017-07-21 15:36:31 -06:00
Anthony Tuininga
1eba9d55be Use dpiData_*() functions to simplify setting data; correct handling of
timestamp with time zone attributes.
2017-07-21 15:35:49 -06:00
Anthony Tuininga
df102db935 Correct handling of CLOB/NCLOB when using different encodings. 2017-07-21 15:34:48 -06:00
Anthony Tuininga
d7f3854556 Update ODPI-C to v2.0.0-rc.2. 2017-07-21 15:33:27 -06:00
Anthony Tuininga
f3451b0726 Initial draft of installation guide. 2017-07-21 15:17:51 -06:00
Anthony Tuininga
8cc4d8607f Remove unnecessary Unicode specific tests for Python 2.7 since Python 3 now
also supports the "u" prefix; merge them instead into the main tests.
2017-07-21 15:16:24 -06:00
Anthony Tuininga
3243261f52 Added samples that were originally created for Open World 2016. 2017-07-14 17:18:57 -06:00
Anthony Tuininga
340dcb7195 Rework test suite and samples so that they are independent of each other and
so that the SQL scripts used to create/drop schemas are easily adjusted to
use different schema names, if desired. Improve documentation for test suite
and samples.
2017-07-14 16:50:41 -06:00
Anthony Tuininga
628d1717f5 Corrected support for binding boolean values with Oracle client 11.2. 2017-07-14 11:31:59 -06:00
Anthony Tuininga
c1005ddcac Added test cases for AQ enqueue/dequeue options and message properties
(https://github.com/oracle/odpi/issues/16).
2017-07-13 13:57:29 -06:00
Anthony Tuininga
db8285055e Update ODPI-C. 2017-07-12 10:35:10 -07:00
Anthony Tuininga
1d768706ab Python 2.7 requires the "u" prefix. 2017-07-08 21:23:27 -06:00
Anthony Tuininga
21213a89ca Update ODPI-C (eliminate memory leak when multiple threads share the same
standalone connection or session pool).
2017-07-08 21:22:14 -06:00
Anthony Tuininga
49b0afd7a5 Ensure the correct encoding is used for setting variable values. 2017-07-07 07:38:44 -07:00
Anthony Tuininga
18e06bf14a Corrected support for binding decimal values in object attribute values and
collection element values.
2017-07-07 07:38:15 -07:00
Anthony Tuininga
2e9c412d41 On Windows, convert system message to Unicode first, then to UTF-8; otherwise,
the error message returned could be in a mix of encodings
(https://github.com/oracle/python-cx_Oracle/issues/40).
2017-07-05 16:07:55 -06:00
Anthony Tuininga
c9d610396a Provide error message when OCI environment cannot be created but at least the
handle has been created, such as when the oraaccess.xml file cannot be
processed properly.
2017-07-05 13:22:11 -06:00
Anthony Tuininga
888fd89fce Update DB API test stub to match latest version of test suite and cx_Oracle. 2017-07-05 13:19:07 -06:00
Anthony Tuininga
4a1641e9c4 Define exception classes on the connection object to simplify error handling in
multi-connection environments, as specified in the Python DB API.
2017-07-05 13:18:29 -06:00
Anthony Tuininga
f555a10f36 Add support for Python 3 in DB API test suite stub. 2017-07-05 13:17:50 -06:00
316 changed files with 46198 additions and 20157 deletions

10
.github/ISSUE_TEMPLATE/announcements.md vendored Normal file
View File

@ -0,0 +1,10 @@
---
name: Announcements
about: Use this if you are sharing something interesting
title: ''
labels: announcement
assignees: ''
---
<!-- Let us know if you are speaking at a conference on cx_Oracle, or have a new package or app that uses cx_Oracle, or something similarly exciting. -->

80
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,80 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
<!--
Thank you for using cx_Oracle.
See https://www.oracle.com/corporate/security-practices/assurance/vulnerability/reporting.html for how to report security issues
The cx_Oracle driver was renamed to python-oracledb in May 2022. It has a new
repository at https://github.com/oracle/python-oracledb. The installation
instructions are at:
https://python-oracledb.readthedocs.io/en/latest/user_guide/installation.html
Update to python-oracledb, if possible, and submit your bug report to the
python-oracledb repository.
No further releases under the cx_Oracle namespace are planned.
Otherwise, please answer these questions so we can help you.
Use Markdown syntax, see https://docs.github.com/github/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax
-->
1. What versions are you using?
<!--
Give your database version.
Also run Python and show the output of:
import sys
import platform
print("platform.platform:", platform.platform())
print("sys.maxsize > 2**32:", sys.maxsize > 2**32)
print("platform.python_version:", platform.python_version())
And:
import cx_Oracle
print("cx_Oracle.version:", cx_Oracle.version)
print("cx_Oracle.clientversion:", cx_Oracle.clientversion())
-->
2. Is it an error or a hang or a crash?
3. What error(s) or behavior you are seeing?
<!--
Cut and paste text showing the command you ran. No screenshots.
Use a gist for long screen output and logs: see https://gist.github.com/
-->
4. Include a runnable Python script that shows the problem.
<!--
Include all SQL needed to create the database schema.
Format code by using three backticks on a line before and after code snippets, for example:
```
import cx_Oracle
```
-->

1
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1 @@
blank_issues_enabled: false

View File

@ -0,0 +1,21 @@
---
name: Documentation and Example Improvements
about: Use this to suggest changes to documentation and examples
title: ''
labels: enhancement
assignees: ''
---
<!--
The cx_Oracle driver was renamed to python-oracledb in May 2022. It has a new
repository at https://github.com/oracle/python-oracledb. The installation
instructions are at:
https://python-oracledb.readthedocs.io/en/latest/user_guide/installation.html
Please submit your documentation and example improvements to the python-oracledb repository.
No further releases under the cx_Oracle namespace are planned.
-->

View File

@ -0,0 +1,21 @@
---
name: Enhancement Requests
about: Use this for enhancement requests
title: ''
labels: enhancement
assignees: ''
---
<!--
The cx_Oracle driver was renamed to python-oracledb in May 2022. It has a new
repository at https://github.com/oracle/python-oracledb. The installation
instructions are at:
https://python-oracledb.readthedocs.io/en/latest/user_guide/installation.html
Please submit your enhancement requests to the python-oracledb repository.
No further releases under the cx_Oracle namespace are planned.
-->

View File

@ -0,0 +1,72 @@
---
name: Questions and Runtime Problems
about: For general cx_Oracle questions
title: ''
labels: question
assignees: ''
---
<!--
Thank you for using cx_Oracle.
The cx_Oracle driver was renamed to python-oracledb in May 2022. It has a new
repository at https://github.com/oracle/python-oracledb. The installation
instructions are at:
https://python-oracledb.readthedocs.io/en/latest/user_guide/installation.html
Update to python-oracledb, if possible.
Otherwise, review the cx_Oracle user manual: https://cx-oracle.readthedocs.io/en/latest/index.html
Please answer these questions so we can help you.
Use Markdown syntax, see https://docs.github.com/github/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax
GitHub issues that are not updated for a month may be automatically closed. Feel free to update them at any time.
-->
1. What versions are you using?
<!--
Give your database version.
Also run Python and show the output of:
import sys
import platform
print("platform.platform:", platform.platform())
print("sys.maxsize > 2**32:", sys.maxsize > 2**32)
print("platform.python_version:", platform.python_version())
And:
import cx_Oracle
print("cx_Oracle.version:", cx_Oracle.version)
print("cx_Oracle.clientversion:", cx_Oracle.clientversion())
-->
2. Describe the problem
<!-- Cut and paste text showing the command you ran. No screenshots. -->
3. Include a runnable Python script that shows the problem.
<!--
Include all SQL needed to create the database schema.
Use a gist for long code: see https://gist.github.com/
Format code by using three backticks on a line before and after code snippets, for example:
```
import cx_Oracle
```
-->

View File

@ -0,0 +1,64 @@
---
name: Installation Problems
about: Use this for cx_Oracle installation questions
title: ''
labels: install & configuration
assignees: ''
---
<!--
Thank you for using cx_Oracle.
The cx_Oracle driver was renamed to python-oracledb in May 2022. It has a new
repository at https://github.com/oracle/python-oracledb. The installation
instructions are at:
https://python-oracledb.readthedocs.io/en/latest/user_guide/installation.html
Do these before creating a new issue:
Update to python-oracledb, if possible.
Otherwise, review and follow the Installation Instructions: https://cx-oracle.readthedocs.io/en/latest/user_guide/installation.html
Review the troubleshooting tips: https://cx-oracle.readthedocs.io/en/latest/user_guide/installation.html#troubleshooting
Review the user manual: https://cx-oracle.readthedocs.io/en/latest/index.html
If you have a `DPI-1047`, `DPI-1050` or `DPI-1072` error, re-review the links above.
Google any errors.
Then please answer these questions so we can help you.
GitHub issues that are not updated for a month may be automatically closed. Feel free to update them at any time.
-->
1. What versions are you using?
<!--
Give your database version.
Also run Python and show the output of:
import sys
import platform
print("platform.platform:", platform.platform())
print("sys.maxsize > 2**32:", sys.maxsize > 2**32)
print("platform.python_version:", platform.python_version())
-->
2. Describe the problem
<!-- Cut and paste text showing the command you ran. No screenshots. -->
3. Show the directory listing where your Oracle Client libraries are installed (e.g. the Instant Client directory). Is it 64-bit or 32-bit?
4. Show what the `PATH` environment variable (on Windows) or `LD_LIBRARY_PATH` (on Linux) is set to?
5. Show any Oracle environment variables set (e.g. ORACLE_HOME, ORACLE_BASE).

34
.github/SUPPORT.md vendored Normal file
View File

@ -0,0 +1,34 @@
# Python cx_Oracle Support
**The cx_Oracle driver was renamed to python-oracledb in May 2022. It has a
new repository at https://github.com/oracle/python-oracledb. Please update to
this new driver. If you still have problems, open an issue on the new
repository.**
## cx_Oracle Installation issues
Read the [Installation instructions](http://cx-oracle.readthedocs.io/en/latest/installation.html)
## SQL and PL/SQL Questions
Ask SQL and PL/SQL questions at [AskTOM](https://asktom.oracle.com/)
Try out SQL and find code snippets on our hosted database
with [LIVE SQL](https://livesql.oracle.com/)
## Database and other Oracle Issues
Ask Database and other Oracle issues on
an [OTN Forum](https://community.oracle.com/community/database/)
## cx_Oracle Documentation
The cx_Oracle documentation
is [here](http://cx-oracle.readthedocs.io/en/latest/)
## Got a cx_Oracle question?
Ask at [GitHub](https://github.com/oracle/python-cx_Oracle/issues)
When opening a new issue, fill in the template that will be shown.
Include enough information for people to understand your problem.

View File

@ -1,46 +0,0 @@
*Delete irrelevant parts of this template.*
### For general questions:
Describe exactly what you did and what you want to happen.
Use the questions at the bottom of this template as a guide.
Use Markdown syntax, particularly for code blocks: see https://help.github.com/articles/basic-writing-and-formatting-syntax/#quoting-code
### For security issues:
See https://www.oracle.com/support/assurance/vulnerability-remediation/reporting-security-vulnerabilities.html for how to report security issues.
### For installation issues:
Use a gist for screen output and logs: see https://gist.github.com/
**Do not paste long output into this issue**
Review the install instructions at
https://github.com/oracle/python-cx_Oracle#installation
Review your output and logs. **Google any errors**
#### Answer the following questions:
1. What is your version of Python? Is it 32-bit or 64-bit?
2. What is your version of cx_Oracle?
3. What is your version of the Oracle client (e.g. Instant Client)? How was it
installed? Where is it installed?
4. What is your version of the Oracle Database?
5. What is your OS and version?
6. What compiler version did you use? For example, with GCC, run
`gcc --version`.
7. What environment variables did you set? How *exactly* did you set them?
8. What *exact* command caused the problem (e.g. what command did you try to
install with)? Who were you logged in as?
9. What error(s) you are seeing?

View File

@ -1,21 +1,8 @@
Thanks for contributing!
Before submitting PRs for cx_Oracle you must have your signed *Oracle
Contributor Agreement* accepted. See
https://www.oracle.com/technetwork/community/oca-486395.html
The cx_Oracle driver was renamed to python-oracledb in May 2022. It has a new
repository at https://github.com/oracle/python-oracledb.
If the problem solved is small, you may find it easier to open an Issue
describing the problem and its cause so we can create the fix.
Please submit your contributions to the python-oracledb repository.
The bottom of your commit message must have the following line using your name
and e-mail address as it appears in the OCA Signatories list.
```
Signed-off-by: Your Name <you@example.org>
```
This can be automatically added to pull requests by committing with:
```
git commit --signoff
````
No further releases under the cx_Oracle namespace are planned.

23
.github/stale.yml vendored Normal file
View File

@ -0,0 +1,23 @@
# https://probot.github.io/apps/stale/
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 30
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- enhancement
- bug
- announcement
- OCA accepted
# Label to use when marking an issue as stale
staleLabel: inactive
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as inactive because it has not been
updated recently. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: >
This issue has been automatically closed because it has not been updated for a month.

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
*.pyc
.tox/
build/
dist/
doc/build

2
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "odpi"]
path = odpi
url = https://github.com/oracle/odpi.git
url = ../odpi.git

16
.readthedocs.yaml Normal file
View File

@ -0,0 +1,16 @@
# required
version: 2
build:
os: ubuntu-20.04
tools:
python: "3.9"
# Build documentation in the doc/src directory with Sphinx
sphinx:
configuration: doc/src/conf.py
# declare Python requirements required to build docs
python:
install:
- requirements: doc/requirements.txt

View File

@ -1,24 +1,8 @@
# Contributing to cx_Oracle
# Contributing
*Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.*
The cx_Oracle driver was renamed to python-oracledb in May 2022. It has a new
repository at https://github.com/oracle/python-oracledb
Pull requests can be made under
[The Oracle Contributor Agreement](https://www.oracle.com/technetwork/community/oca-486395.html)
(OCA).
Please submit your contributions to the python-oracledb repository.
For pull requests to be accepted into cx_Oracle, the bottom of
your commit message must have the following line using your name and
e-mail address as it appears in the OCA Signatories list.
```
Signed-off-by: Your Name <you@example.org>
```
This can be automatically added to pull requests by committing with:
```
git commit --signoff
````
Only pull requests from committers that can be verified as having
signed the OCA can be accepted.
No further releases under the cx_Oracle namespace are planned.

View File

@ -1,6 +1,6 @@
LICENSE AGREEMENT FOR CX_ORACLE
Copyright 2016, 2017, Oracle and/or its affiliates. All rights reserved.
Copyright 2016, 2018, Oracle and/or its affiliates. All rights reserved.
Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.

View File

@ -5,5 +5,6 @@ recursive-include odpi *.h
prune odpi/test
prune odpi/samples
recursive-include src *.c
recursive-include samples *.py
recursive-include src *.h
recursive-include samples *.py *.sql
recursive-include test *.py *.sql

205
README.md
View File

@ -1,192 +1,33 @@
# Open Source Python/Oracle Utility - cx_Oracle
# Python cx_Oracle
cx_Oracle is a Python extension module that enables access to Oracle Database
and conforms to the Python database API 2.0 specifications with a considerable
number of additions and a couple of exclusions. The time data type is not
supported by Oracle and is therefore not implemented. The method
cursor.nextset() is not implemented either as the DB API specification assumes
an implementation of cursors that does not fit well with Oracle's
implementation of cursors and implicit results. See the method
cursor.getimplicitresults() for more information.
**cx_Oracle was obsoleted by
[python-oracledb](https://oracle.github.io/python-oracledb/) in 2022.**
See [PEP 249][1] for more information on the Python database API specification.
See the [documentation][2] for a complete description of the module's
capabilities.
Python-oracledb uses the same Python DB API as cx_Oracle, and has many new
features.
cx_Oracle is licensed under a BSD license which you can find [here][3].
Install with:
cx_Oracle has been tested with Python version 2.7, and with versions 3.4 and
higher. You can use cx_Oracle with Oracle 11.2, 12.1 and 12.2 client libraries,
allowing connection to multiple Oracle Database versions. Oracle's standard
client-server version interoperability allows connection to both older and
newer databases, for example Oracle 11.2 client libraries can connect to Oracle
Database 10.2 or later.
Please note that an Oracle client (or server) installation is required in order
to use cx_Oracle. If you do not require the tools that come with a full client
installation, it is recommended to install the [Instant Client][4].
which is far easier to install.
## Help
Issues and questions can be raised with the cx_Oracle community on
[GitHub][9] or on the [mailing list][5].
## Documentation
See the [cx_Oracle Documentation][2] and [Release Notes][14].
## Installation
The simplest way to install cx_Oracle 6 Beta is with pip:
python -m pip install cx_Oracle --pre
If a binary wheel package is not available on [PyPI][6] for your
platform, the source package will be used.
If you prefer, the source package can be downloaded manually from [PyPI][6] and
extracted, after which the following commands should be run:
python setup.py build
python setup.py install
Note that if you download a source zip file directly from GitHub that
you will also need to download an [ODPI-C][10] source zip file and
extract it inside a directory called "odpi".
After cx_Oracle is installed, Oracle client libraries must also be
installed and configured. If you need the libraries, you can download
and unzip the [Oracle Instant Client][4] 'Basic' package for your
platform and set PATH, LD_LIBRARY_PATH, or similar platform-specific
library path loading environment. See the
[installation notes for ODPI-C][13] for help with installing and configuring an
Oracle client.
Versions 11.2, 12.1 and 12.2 of the Oracle Client libraries on Linux,
Windows and macOS are supported. Users have also reported success
with other platforms.
## Usage Example
```python
from __future__ import print_function # needed for Python 2.x
import cx_Oracle
# connect via SQL*Net string or by each segment in a separate argument
#connection = cx_Oracle.connect("user/password@TNS")
connection = cx_Oracle.connect("user", "password", "TNS")
cursor = connection.cursor()
cursor.execute("""
select Col1, Col2, Col3
from SomeTable
where Col4 = :arg_1
and Col5 between :arg_2 and :arg_3""",
arg_1 = "VALUE",
arg_2 = 5,
arg_3 = 15)
for column_1, column_2, column_3 in cursor:
print("Values:", column_1, column_2, column_3)
```
python -m pip install oracledb
```
Usage is like:
For more examples, please see the [test suite][11] and the
[samples][12]. You can also look at the scripts in the [cx_OracleTools][7] and
the modules in the [cx_PyOracleLib][8] projects.
```
import getpass
import oracledb
## Features
un = 'scott'
cs = 'localhost/orclpdb1'
pw = getpass.getpass(f'Enter password for {un}@{cs}: ')
- Easily installed from PyPI.
with oracledb.connect(user=un, password=pw, dsn=cs) as connection:
with connection.cursor() as cursor:
sql = 'select systimestamp from dual'
for r in cursor.execute(sql):
print(r)
```
- Support for Python 2 and 3.
- Support for Oracle Client 11.2, 12.1 and 12.2. Oracle's standard
cross-version interoperability, allows easy upgrades and
connectivity to different Oracle Database versions.
- Connect to Oracle Database 9.2, 10, 11 or 12 (depending on the
Oracle Client version used).
- SQL and PL/SQL Execution, with full support for OCI features like
statement caching and statement caching auto-tuning. Oracle OCI
(which is the database access layer used by cx_Oracle) has
significant optimizations, including compressed fetch, pre-fetching,
client and server result set caching, and statement caching.
cx_Oracle applications can additionally make full use of PL/SQL to
keep business logic near the data in the database, where it can be
processed without having to ship large volumes of data to the
application.
- Full use of Oracle Network Service infrastructure, including
encrypted network traffic and security features.
- Extensive Oracle data type support, including large object support (CLOB
and BLOB).
- Direct binding to SQL objects. One great use case is binding Python
objects to Oracle Spatial SDO objects.
- Array operations for efficient INSERT and UPDATEs.
- Array row counts and batch error handling for array operations.
- Fetching of large result sets.
- REF CURSOR support.
- Support for scrollable cursors. Go back and forth through your query
results.
- Fetch PL/SQL Implicit Results. Easily return query results from
PL/SQL.
- Row Prefetching. Efficient use of the network.
- Client Result Caching. Improve performance of frequently executed
look-up statements.
- Support for Advanced Queuing. Use database notifications to build
micro-service applications.
- Continuous Query Notification. Get notified when data changes.
- Support for Edition Based Redefinition. Easily switch applications
to use updated PL/SQL logic.
- Support for setting application context during the creation of a
connection, making application metadata more accessible to the
database, including in LOGON triggers.
- End-to-end monitoring and tracing.
- Transaction Management.
- Session Pooling.
- Database Resident Connection Pooling (DRCP).
- Privileged Connections.
- External Authentication.
- Database startup and shutdown.
- Oracle Database High Availability Features, such as FAN notifications and Transaction Guard support.
[1]: https://www.python.org/dev/peps/pep-0249
[2]: http://cx-oracle.readthedocs.io
[3]: https://github.com/oracle/python-cx_Oracle/blob/master/LICENSE.txt
[4]: http://www.oracle.com/technetwork/database/features/instant-client/index.html
[5]: http://lists.sourceforge.net/lists/listinfo/cx-oracle-users
[6]: https://pypi.python.org/pypi/cx_Oracle
[7]: http://cx-oracletools.sourceforge.net
[8]: http://cx-pyoraclelib.sourceforge.net
[9]: https://github.com/oracle/python-cx_Oracle/issues
[10]: https://oracle.github.io/odpi
[11]: https://github.com/oracle/python-cx_Oracle/tree/master/test
[12]: https://github.com/oracle/python-cx_Oracle/tree/master/samples
[13]: https://oracle.github.io/odpi/doc/installation.html
[14]: http://cx-oracle.readthedocs.io/en/latest/releasenotes.html
The source code for python-oracledb is at
[github.com/oracle/python-oracledb](https://github.com/oracle/python-oracledb).

View File

@ -1,5 +1,7 @@
Please see the cx_Oracle home page for links to documentation, source, build
and installation instructions:
cx_Oracle was obsoleted by python-oracledb in 2022.
https://oracle.github.io/python-cx_Oracle/index.html
Python-oracledb uses the same Python DB API as cx_Oracle, and has many new
features.
See https://python-oracledb.readthedocs.io/en/latest/index.html for how to
install and use this updated driver.

37
SECURITY.md Normal file
View File

@ -0,0 +1,37 @@
# Reporting security vulnerabilities
Oracle values the independent security research community and believes that
responsible disclosure of security vulnerabilities helps us ensure the security
and privacy of all our users.
Please do NOT raise a GitHub Issue to report a security vulnerability. If you
believe you have found a security vulnerability, please submit a report to
[secalert_us@oracle.com][1] preferably with a proof of concept. Please review
some additional information on [how to report security vulnerabilities to
Oracle][2]. We encourage people who contact Oracle Security to use email
encryption using [our encryption key][3].
We ask that you do not use other channels or contact the project maintainers
directly.
Non-vulnerability related security issues including ideas for new or improved
security features are welcome on GitHub Issues.
## Security updates, alerts and bulletins
Security updates will be released on a regular cadence. Many of our projects
will typically release security fixes in conjunction with the Oracle Critical
Patch Update program. Additional information, including past advisories, is
available on our [security alerts][4] page.
## Security-related information
We will provide security related information such as a threat model,
considerations for secure use, or any known security issues in our
documentation. Please note that labs and sample code are intended to
demonstrate a concept and may not be sufficiently hardened for production use.
[1]: mailto:secalert_us@oracle.com
[2]: https://www.oracle.com/corporate/security-practices/assurance/vulnerability/reporting.html
[3]: https://www.oracle.com/security-alerts/encryptionkey.html
[4]: https://www.oracle.com/security-alerts/

View File

@ -1,69 +1,23 @@
# Makefile for Sphinx documentation
#
# Makefile to generate cx_Oracle documentation using Sphinx
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILD_DIR = build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILD_DIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) src
.PHONY: help clean html web htmlhelp latex changes linkcheck
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " web to make files usable by Sphinx.web"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " changes to make an overview over all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
clean:
-rm -rf $(BUILD_DIR)
SOURCEDIR = src
BUILDDIR = build
.PHONY: html
html:
mkdir -p $(BUILD_DIR)/doctrees
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILD_DIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILD_DIR)/html"
@$(SPHINXBUILD) -M html $(SOURCEDIR) $(BUILDDIR) $(SPHINXOPTS)
web:
mkdir -p $(BUILD_DIR)/web $(BUILD_DIR)/doctrees
$(SPHINXBUILD) -b web $(ALLSPHINXOPTS) $(BUILD_DIR)/web
@echo
@echo "Build finished; now you can run"
@echo " python -m sphinx.web $(BUILD_DIR)/web"
@echo "to start the server."
.PHONY: epub
epub:
@$(SPHINXBUILD) -M epub $(SOURCEDIR) $(BUILDDIR) $(SPHINXOPTS)
htmlhelp:
mkdir -p $(BUILD_DIR)/htmlhelp $(BUILD_DIR)/doctrees
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILD_DIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILD_DIR)/htmlhelp."
.PHONY: pdf
pdf:
@$(SPHINXBUILD) -M latexpdf $(SOURCEDIR) $(BUILDDIR) $(SPHINXOPTS)
latex:
mkdir -p $(BUILD_DIR)/latex $(BUILD_DIR)/doctrees
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILD_DIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILD_DIR)/latex."
@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
"run these through (pdf)latex."
.PHONY: clean
clean:
rm -rf $(BUILDDIR)/*
changes:
mkdir -p $(BUILD_DIR)/changes $(BUILD_DIR)/doctrees
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILD_DIR)/changes
@echo
@echo "The overview file is in $(BUILD_DIR)/changes."
linkcheck:
mkdir -p $(BUILD_DIR)/linkcheck $(BUILD_DIR)/doctrees
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILD_DIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILD_DIR)/linkcheck/output.txt."

13
doc/README.md Normal file
View File

@ -0,0 +1,13 @@
The generated cx_Oracle documentation is at http://cx-oracle.readthedocs.io/
This directory contains the documentation source. It is written using reST
(re-Structured Text) format source files which are processed using Sphinx and
turned into HTML, PDF or ePub documents. If you wish to build these yourself,
you need to install Sphinx. Sphinx is available on many Linux distributions as a
pre-built package. You can also install Sphinx on all platforms using the Python
package manager "pip". For more information on Sphinx, please visit this page:
http://www.sphinx-doc.org
Once Sphinx is installed, the supplied Makefile can be used to build the
different targets.

2
doc/requirements.txt Normal file
View File

@ -0,0 +1,2 @@
sphinx>=4.2.0
sphinx-rtd-theme>=0.5.2

358
doc/src/api_manual/aq.rst Normal file
View File

@ -0,0 +1,358 @@
.. _aq:
*********************
Advanced Queuing (AQ)
*********************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
See :ref:`aqusermanual` for more information about using AQ in cx_Oracle.
.. note::
All of these objects are extensions to the DB API.
.. _queue:
------
Queues
------
These objects are created using the :meth:`Connection.queue()` method and are
used to enqueue and dequeue messages.
.. attribute:: Queue.connection
This read-only attribute returns a reference to the connection object on
which the queue was created.
.. method:: Queue.deqmany(maxMessages)
Dequeues up to the specified number of messages from the queue and returns
a list of these messages. Each element of the returned list is a
:ref:`message property<msgproperties>` object.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the name of
the method was changed from `deqMany()`. The old name will continue to
work for a period of time.
.. method:: Queue.deqone()
Dequeues at most one message from the queue. If a message is dequeued, it
will be a :ref:`message property<msgproperties>` object; otherwise, it will
be the value None.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the name of
the method was changed from `deqOne()`. The old name will continue to
work for a period of time.
.. attribute:: Queue.deqoptions
This read-only attribute returns a reference to the :ref:`options
<deqoptions>` that will be used when dequeuing messages from the queue.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the name of
the attribute was changed from `deqOptions`. The old name will continue
to work for a period of time.
.. method:: Queue.enqmany(messages)
Enqueues multiple messages into the queue. The messages parameter must be a
sequence containing :ref:`message property <msgproperties>` objects which
have all had their payload attribute set to a value that the queue
supports.
Warning: calling this function in parallel on different connections
acquired from the same pool may fail due to Oracle bug 29928074. Ensure
that this function is not run in parallel, use standalone connections or
connections from different pools, or make multiple calls to
:meth:`Queue.enqone()` instead. The function :meth:`Queue.deqmany()`
call is not affected.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the name of
the method was changed from `enqMany()`. The old name will continue
to work for a period of time.
.. method:: Queue.enqone(message)
Enqueues a single message into the queue. The message must be a
:ref:`message property<msgproperties>` object which has had its payload
attribute set to a value that the queue supports.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the name of
the method was changed from `enqOne()`. The old name will continue
to work for a period of time.
.. attribute:: Queue.enqoptions
This read-only attribute returns a reference to the :ref:`options
<enqoptions>` that will be used when enqueuing messages into the queue.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the name of
the attribute was changed from `enqOptions`. The old name will continue
to work for a period of time.
.. attribute:: Queue.name
This read-only attribute returns the name of the queue.
.. attribute:: Queue.payload_type
This read-only attribute returns the object type for payloads that can be
enqueued and dequeued. If using a raw queue, this returns the value None.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the name of
the attribute was changed from `payloadType`. The old name will
continue to work for a period of time.
.. _deqoptions:
---------------
Dequeue Options
---------------
.. note::
These objects are used to configure how messages are dequeued from queues.
An instance of this object is found in the attribute
:attr:`Queue.deqOptions`.
.. attribute:: DeqOptions.condition
This attribute specifies a boolean expression similar to the where clause
of a SQL query. The boolean expression can include conditions on message
properties, user data properties and PL/SQL or SQL functions. The default
is to have no condition specified.
.. attribute:: DeqOptions.consumername
This attribute specifies the name of the consumer. Only messages matching
the consumer name will be accessed. If the queue is not set up for multiple
consumers this attribute should not be set. The default is to have no
consumer name specified.
.. attribute:: DeqOptions.correlation
This attribute specifies the correlation identifier of the message to be
dequeued. Special pattern-matching characters, such as the percent sign (%)
and the underscore (_), can be used. If multiple messages satisfy the
pattern, the order of dequeuing is indeterminate. The default is to have no
correlation specified.
.. attribute:: DeqOptions.deliverymode
This write-only attribute specifies what types of messages should be
dequeued. It should be one of the values :data:`~cx_Oracle.MSG_PERSISTENT`
(default), :data:`~cx_Oracle.MSG_BUFFERED` or
:data:`~cx_Oracle.MSG_PERSISTENT_OR_BUFFERED`.
.. attribute:: DeqOptions.mode
This attribute specifies the locking behaviour associated with the dequeue
operation. It should be one of the values :data:`~cx_Oracle.DEQ_BROWSE`,
:data:`~cx_Oracle.DEQ_LOCKED`,
:data:`~cx_Oracle.DEQ_REMOVE` (default), or
:data:`~cx_Oracle.DEQ_REMOVE_NODATA`.
.. attribute:: DeqOptions.msgid
This attribute specifies the identifier of the message to be dequeued. The
default is to have no message identifier specified.
.. attribute:: DeqOptions.navigation
This attribute specifies the position of the message that is retrieved. It
should be one of the values :data:`~cx_Oracle.DEQ_FIRST_MSG`,
:data:`~cx_Oracle.DEQ_NEXT_MSG` (default), or
:data:`~cx_Oracle.DEQ_NEXT_TRANSACTION`.
.. attribute:: DeqOptions.transformation
This attribute specifies the name of the transformation that must be
applied after the message is dequeued from the database but before it is
returned to the calling application. The transformation must be created
using dbms_transform. The default is to have no transformation specified.
.. attribute:: DeqOptions.visibility
This attribute specifies the transactional behavior of the dequeue request.
It should be one of the values :data:`~cx_Oracle.DEQ_ON_COMMIT` (default)
or :data:`~cx_Oracle.DEQ_IMMEDIATE`. This attribute is ignored when using
the :data:`~cx_Oracle.DEQ_BROWSE` mode. Note the value of
:attr:`~Connection.autocommit` is always ignored.
.. attribute:: DeqOptions.wait
This attribute specifies the time to wait, in seconds, for a message
matching the search criteria to become available for dequeuing. One of the
values :data:`~cx_Oracle.DEQ_NO_WAIT` or
:data:`~cx_Oracle.DEQ_WAIT_FOREVER` can also be used. The default is
:data:`~cx_Oracle.DEQ_WAIT_FOREVER`.
.. _enqoptions:
---------------
Enqueue Options
---------------
.. note::
These objects are used to configure how messages are enqueued into queues.
An instance of this object is found in the attribute
:attr:`Queue.enqOptions`.
.. attribute:: EnqOptions.deliverymode
This write-only attribute specifies what type of messages should be
enqueued. It should be one of the values :data:`~cx_Oracle.MSG_PERSISTENT`
(default) or :data:`~cx_Oracle.MSG_BUFFERED`.
.. attribute:: EnqOptions.transformation
This attribute specifies the name of the transformation that must be
applied before the message is enqueued into the database. The
transformation must be created using dbms_transform. The default is to have
no transformation specified.
.. attribute:: EnqOptions.visibility
This attribute specifies the transactional behavior of the enqueue request.
It should be one of the values :data:`~cx_Oracle.ENQ_ON_COMMIT` (default)
or :data:`~cx_Oracle.ENQ_IMMEDIATE`. Note the value of
:attr:`~Connection.autocommit` is ignored.
.. _msgproperties:
------------------
Message Properties
------------------
.. note::
These objects are used to identify the properties of messages that are
enqueued and dequeued in queues. They are created by the method
:meth:`Connection.msgproperties()`. They are used by the methods
:meth:`Queue.enqone()` and :meth:`Queue.enqmany()` and
returned by the methods :meth:`Queue.deqone()` and :meth:`Queue.deqmany()`.
.. attribute:: MessageProperties.attempts
This read-only attribute specifies the number of attempts that have been
made to dequeue the message.
.. attribute:: MessageProperties.correlation
This attribute specifies the correlation used when the message was
enqueued.
.. attribute:: MessageProperties.delay
This attribute specifies the number of seconds to delay an enqueued
message. Any integer is acceptable but the constant
:data:`~cx_Oracle.MSG_NO_DELAY` can also be used indicating that the
message is available for immediate dequeuing.
.. attribute:: MessageProperties.deliverymode
This read-only attribute specifies the type of message that was dequeued.
It will be one of the values :data:`~cx_Oracle.MSG_PERSISTENT` or
:data:`~cx_Oracle.MSG_BUFFERED`.
.. attribute:: MessageProperties.enqtime
This read-only attribute specifies the time that the message was enqueued.
.. attribute:: MessageProperties.exceptionq
This attribute specifies the name of the queue to which the message is
moved if it cannot be processed successfully. Messages are moved if the
number of unsuccessful dequeue attempts has exceeded the maximum number of
retries or if the message has expired. All messages in the exception queue
are in the :data:`~cx_Oracle.MSG_EXPIRED` state. The default value is the
name of the exception queue associated with the queue table.
.. attribute:: MessageProperties.expiration
This attribute specifies, in seconds, how long the message is available for
dequeuing. This attribute is an offset from the delay attribute. Expiration
processing requires the queue monitor to be running. Any integer is
accepted but the constant :data:`~cx_Oracle.MSG_NO_EXPIRATION` can also be
used indicating that the message never expires.
.. attribute:: MessageProperties.msgid
This read-only attribute specifies the id of the message in the last queue
that enqueued or dequeued the message. If the message has never been
dequeued or enqueued, the value will be `None`.
.. attribute:: MessageProperties.payload
This attribute identifies the payload that will be enqueued or the payload
that was dequeued when using a :ref:`queue <queue>`. When enqueuing, the
value is checked to ensure that it conforms to the type expected by that
queue. For RAW queues, the value can be a bytes object or a string. If the
value is a string it will first be converted to bytes by encoding in the
encoding identified by the attribute :attr:`Connection.encoding`.
.. attribute:: MessageProperties.priority
This attribute specifies the priority of the message. A smaller number
indicates a higher priority. The priority can be any integer, including
negative numbers. The default value is zero.
.. attribute:: MessageProperties.state
This read-only attribute specifies the state of the message at the time of
the dequeue. It will be one of the values :data:`~cx_Oracle.MSG_WAITING`,
:data:`~cx_Oracle.MSG_READY`, :data:`~cx_Oracle.MSG_PROCESSED` or
:data:`~cx_Oracle.MSG_EXPIRED`.

View File

@ -0,0 +1,759 @@
.. _connobj:
*****************
Connection Object
*****************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
.. note::
Any outstanding changes will be rolled back when the connection object
is destroyed or closed.
.. method:: Connection.__enter__()
The entry point for the connection as a context manager. It returns itself.
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.__exit__()
The exit point for the connection as a context manager. This will close
the connection and roll back any uncommitted transaction.
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.action
This write-only attribute sets the action column in the v$session table. It
is a string attribute and cannot be set to None -- use the empty string
instead.
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.autocommit
This read-write attribute determines whether autocommit mode is on or off.
When autocommit mode is on, all statements are committed as soon as they
have completed executing.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.begin([formatId, transactionId, branchId])
Explicitly begin a new transaction. Without parameters, this explicitly
begins a local transaction; otherwise, this explicitly begins a distributed
(global) transaction with the given parameters. See the Oracle
documentation for more details.
Note that in order to make use of global (distributed) transactions, the
:attr:`~Connection.internal_name` and :attr:`~Connection.external_name`
attributes must be set.
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.call_timeout
This read-write attribute specifies the amount of time (in milliseconds)
that a single round-trip to the database may take before a timeout will
occur. A value of 0 means that no timeout will take place.
If a timeout occurs, the error *DPI-1067* will be returned if the
connection is still usable. Alternatively the error *DPI-1080* will be
returned if the connection has become invalid and can no longer be used.
.. versionadded:: 7.0
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
attribute `callTimeout` was renamed to `call_timeout`. The old name
will continue to work for a period of time. The error *DPI-1080* was
also introduced in this release.
.. note::
This attribute is an extension to the DB API definition and is only
available in Oracle Client 18c and higher.
.. method:: Connection.cancel()
Break a long-running transaction.
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.changepassword(oldpassword, newpassword)
Change the password of the logon.
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.client_identifier
This write-only attribute sets the client_identifier column in the
v$session table.
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.clientinfo
This write-only attribute sets the client_info column in the v$session
table.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.close()
Close the connection now, rather than whenever __del__ is called. The
connection will be unusable from this point forward; an Error exception
will be raised if any operation is attempted with the connection.
All open cursors and LOBs created by the connection will be closed and will
also no longer be usable.
Internally, references to the connection are held by cursor objects,
LOB objects, subscription objects, etc. Once all of these references are
released, the connection itself will be closed automatically. Either
control references to these related objects carefully or explicitly close
connections in order to ensure sufficient resources are available.
.. method:: Connection.commit()
Commit any pending transactions to the database.
.. method:: Connection.createlob(lobType)
Create and return a new temporary :ref:`LOB object <lobobj>` of the
specified type. The lobType parameter should be one of
:data:`cx_Oracle.CLOB`, :data:`cx_Oracle.BLOB` or :data:`cx_Oracle.NCLOB`.
.. versionadded:: 6.2
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.current_schema
This read-write attribute sets the current schema attribute for the
session. Setting this value is the same as executing the SQL statement
"ALTER SESSION SET CURRENT_SCHEMA". The attribute is set (and verified) on
the next call that does a round trip to the server. The value is placed
before unqualified database objects in SQL statements you then execute.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.cursor()
Return a new :ref:`cursor object <cursorobj>` using the connection.
.. attribute:: Connection.dbop
This write-only attribute sets the database operation that is to be
monitored. This can be viewed in the DBOP_NAME column of the V$SQL_MONITOR
table.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.deq(name, options, msgproperties, payload)
Returns a message id after successfully dequeuing a message. The options
object can be created using :meth:`~Connection.deqoptions()` and the
msgproperties object can be created using
:meth:`~Connection.msgproperties()`. The payload must be an object created
using :meth:`ObjectType.newobject()`.
.. versionadded:: 5.3
.. deprecated:: 7.2
Use the methods :meth:`Queue.deqone()` or :meth:`Queue.deqmany()`
instead.
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.deqoptions()
Returns an object specifying the options to use when dequeuing messages.
See :ref:`deqoptions` for more information.
.. versionadded:: 5.3
.. deprecated:: 7.2
Use the attribute :attr:`Queue.deqoptions` instead.
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.dsn
This read-only attribute returns the TNS entry of the database to which a
connection has been established.
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.edition
This read-only attribute gets the session edition and is only available in
Oracle Database 11.2 (both client and server must be at this level or
higher for this to work).
.. versionadded:: 5.3
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.encoding
This read-only attribute returns the IANA character set name of the
character set in use by the Oracle client for regular strings.
.. deprecated:: 8.2
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.enq(name, options, msgproperties, payload)
Returns a message id after successfully enqueuing a message. The options
object can be created using :meth:`~Connection.enqoptions()` and the
msgproperties object can be created using
:meth:`~Connection.msgproperties()`. The payload must be an object created
using :meth:`ObjectType.newobject()`.
.. versionadded:: 5.3
.. deprecated:: 7.2
Use the methods :meth:`Queue.enqone()` or :meth:`Queue.enqmany()`
instead.
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.enqoptions()
Returns an object specifying the options to use when enqueuing messages.
See :ref:`enqoptions` for more information.
.. versionadded:: 5.3
.. deprecated:: 7.2
Use the attribute :attr:`Queue.enqoptions` instead.
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.external_name
This read-write attribute specifies the external name that is used by the
connection when logging distributed transactions.
.. versionadded:: 5.3
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.getSodaDatabase()
Return a :ref:`SodaDatabase <sodadb>` object for Simple Oracle Document
Access (SODA). All SODA operations are performed either on the returned
SodaDatabase object or from objects created by the returned SodaDatabase
object. See `here <https://www.oracle.com/pls/topic/lookup?
ctx=dblatest&id=GUID-BE42F8D3-B86B-43B4-B2A3-5760A4DF79FB>`__ for
additional information on SODA.
.. versionadded:: 7.0
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.gettype(name)
Return a :ref:`type object <objecttype>` given its name. This can then be
used to create objects which can be bound to cursors created by this
connection.
.. versionadded:: 5.3
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.handle
This read-only attribute returns the OCI service context handle for the
connection. It is primarily provided to facilitate testing the creation of
a connection using the OCI service context handle.
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.inputtypehandler
This read-write attribute specifies a method called for each value that is
bound to a statement executed on any cursor associated with this
connection. The method signature is handler(cursor, value, arraysize) and
the return value is expected to be a variable object or None in which case
a default variable object will be created. If this attribute is None, the
default behavior will take place for all values bound to statements.
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.internal_name
This read-write attribute specifies the internal name that is used by the
connection when logging distributed transactions.
.. versionadded:: 5.3
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.ltxid
This read-only attribute returns the logical transaction id for the
connection. It is used within Oracle Transaction Guard as a means of
ensuring that transactions are not duplicated. See the Oracle documentation
and the provided sample for more information.
.. versionadded:: 5.3
.. note:
This attribute is an extension to the DB API definition. It is only
available when Oracle Database 12.1 or higher is in use on both the
server and the client.
.. attribute:: Connection.maxBytesPerCharacter
This read-only attribute returns the maximum number of bytes each character
can use for the client character set.
.. deprecated:: 8.2
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.module
This write-only attribute sets the module column in the v$session table.
The maximum length for this string is 48 and if you exceed this length you
will get ORA-24960.
.. note:
This attribute is an extension to the DB API definition.
.. method:: Connection.msgproperties(payload, correlation, delay, exceptionq, \
expiration, priority)
Returns an object specifying the properties of messages used in advanced
queuing. See :ref:`msgproperties` for more information.
Each of the parameters are optional. If specified, they act as a shortcut
for setting each of the equivalently named properties.
.. versionadded:: 5.3
.. versionchanged:: 7.2 Added parameters
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.nencoding
This read-only attribute returns the IANA character set name of the
national character set in use by the Oracle client.
.. deprecated:: 8.2
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.outputtypehandler
This read-write attribute specifies a method called for each column that is
going to be fetched from any cursor associated with this connection. The
method signature is handler(cursor, name, defaultType, length, precision,
scale) and the return value is expected to be a variable object or None in
which case a default variable object will be created. If this attribute is
None, the default behavior will take place for all columns fetched from
cursors.
See :ref:`outputtypehandlers`.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.ping()
Ping the server which can be used to test if the connection is still
active.
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.prepare()
Prepare the distributed (global) transaction for commit. Return a boolean
indicating if a transaction was actually prepared in order to avoid the
error ORA-24756 (transaction does not exist).
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.queue(name, payload_type=None)
Creates a :ref:`queue <queue>` which is used to enqueue and dequeue
messages in Advanced Queueing.
The name parameter is expected to be a string identifying the queue in
which messages are to be enqueued or dequeued.
The payload_type parameter, if specified, is expected to be an
:ref:`object type <objecttype>` that identifies the type of payload the
queue expects. If not specified, RAW data is enqueued and dequeued.
.. versionadded:: 7.2
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
parameter `payloadType` was renamed to `payload_type`. The old name
will continue to work as a keyword parameter for a period of time.
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.rollback()
Rollback any pending transactions.
.. method:: Connection.shutdown([mode])
Shutdown the database. In order to do this the connection must be connected
as :data:`~cx_Oracle.SYSDBA` or :data:`~cx_Oracle.SYSOPER`. Two calls must
be made unless the mode specified is :data:`~cx_Oracle.DBSHUTDOWN_ABORT`.
An example is shown below:
::
import cx_Oracle
connection = cx_Oracle.connect(mode = cx_Oracle.SYSDBA)
connection.shutdown(mode = cx_Oracle.DBSHUTDOWN_IMMEDIATE)
cursor = connection.cursor()
cursor.execute("alter database close normal")
cursor.execute("alter database dismount")
connection.shutdown(mode = cx_Oracle.DBSHUTDOWN_FINAL)
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.startup(force=False, restrict=False, pfile=None)
Startup the database. This is equivalent to the SQL\*Plus command "startup
nomount". The connection must be connected as :data:`~cx_Oracle.SYSDBA` or
:data:`~cx_Oracle.SYSOPER` with the :data:`~cx_Oracle.PRELIM_AUTH` option
specified for this to work.
The pfile parameter, if specified, is expected to be a string identifying
the location of the parameter file (PFILE) which will be used instead of
the stored parameter file (SPFILE).
An example is shown below:
::
import cx_Oracle
connection = cx_Oracle.connect(
mode=cx_Oracle.SYSDBA | cx_Oracle.PRELIM_AUTH)
connection.startup()
connection = cx_Oracle.connect(mode=cx_Oracle.SYSDBA)
cursor = connection.cursor()
cursor.execute("alter database mount")
cursor.execute("alter database open")
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.stmtcachesize
This read-write attribute specifies the size of the statement cache. This
value can make a significant difference in performance if you have a small
number of statements that you execute repeatedly.
The default value is 20.
See :ref:`Statement Caching <stmtcache>` for more information.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.subscribe(namespace=cx_Oracle.SUBSCR_NAMESPACE_DBCHANGE, protocol=cx_Oracle.SUBSCR_PROTO_OCI, callback=None, timeout=0, operations=OPCODE_ALLOPS, port=0, qos=0, ip_address=None, grouping_class=0, grouping_value=0, grouping_type=cx_Oracle.SUBSCR_GROUPING_TYPE_SUMMARY, name=None, client_initiated=False)
Return a new :ref:`subscription object <subscrobj>` that receives
notifications for events that take place in the database that match the
given parameters.
The namespace parameter specifies the namespace the subscription uses. It
can be one of :data:`cx_Oracle.SUBSCR_NAMESPACE_DBCHANGE` or
:data:`cx_Oracle.SUBSCR_NAMESPACE_AQ`.
The protocol parameter specifies the protocol to use when notifications are
sent. Currently the only valid value is :data:`cx_Oracle.SUBSCR_PROTO_OCI`.
The callback is expected to be a callable that accepts a single parameter.
A :ref:`message object <msgobjects>` is passed to this callback whenever a
notification is received.
The timeout value specifies that the subscription expires after the given
time in seconds. The default value of 0 indicates that the subscription
never expires.
The operations parameter enables filtering of the messages that are sent
(insert, update, delete). The default value will send notifications for all
operations. This parameter is only used when the namespace is set to
:data:`cx_Oracle.SUBSCR_NAMESPACE_DBCHANGE`.
The port parameter specifies the listening port for callback notifications
from the database server. If not specified, an unused port will be selected
by the Oracle Client libraries.
The qos parameter specifies quality of service options. It should be one or
more of the following flags, OR'ed together:
:data:`cx_Oracle.SUBSCR_QOS_RELIABLE`,
:data:`cx_Oracle.SUBSCR_QOS_DEREG_NFY`,
:data:`cx_Oracle.SUBSCR_QOS_ROWIDS`,
:data:`cx_Oracle.SUBSCR_QOS_QUERY`,
:data:`cx_Oracle.SUBSCR_QOS_BEST_EFFORT`.
The ip_address parameter specifies the IP address (IPv4 or IPv6) in
standard string notation to bind for callback notifications from the
database server. If not specified, the client IP address will be determined
by the Oracle Client libraries.
The grouping_class parameter specifies what type of grouping of
notifications should take place. Currently, if set, this value can only be
set to the value :data:`cx_Oracle.SUBSCR_GROUPING_CLASS_TIME`, which
will group notifications by the number of seconds specified in the
grouping_value parameter. The grouping_type parameter should be one of the
values :data:`cx_Oracle.SUBSCR_GROUPING_TYPE_SUMMARY` (the default) or
:data:`cx_Oracle.SUBSCR_GROUPING_TYPE_LAST`.
The name parameter is used to identify the subscription and is specific to
the selected namespace. If the namespace parameter is
:data:`cx_Oracle.SUBSCR_NAMESPACE_DBCHANGE` then the name is optional and
can be any value. If the namespace parameter is
:data:`cx_Oracle.SUBSCR_NAMESPACE_AQ`, however, the name must be in the
format '<QUEUE_NAME>' for single consumer queues and
'<QUEUE_NAME>:<CONSUMER_NAME>' for multiple consumer queues, and identifies
the queue that will be monitored for messages. The queue name may include
the schema, if needed.
The client_initiated parameter is used to determine if client initiated
connections or server initiated connections (the default) will be
established. Client initiated connections are only available in Oracle
Client 19.4 and Oracle Database 19.4 and higher.
.. versionadded:: 6.4
The parameters ipAddress, groupingClass, groupingValue, groupingType
and name were added.
.. versionadded:: 7.3
The parameter clientInitiated was added.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
parameter `ipAddress` was renamed to `ip_address`, the parameter
`groupingClass` was renamed to `grouping_class`, the parameter
`groupingValue` was renamed to `grouping_value`, the parameter
`groupingType` was renamed to `grouping_type` and the parameter
`clientInitiated` was renamed to `client_initiated`. The old names will
continue to work as keyword parameters for a period of time.
.. note::
This method is an extension to the DB API definition.
.. note::
The subscription can be deregistered in the database by calling the
function :meth:`~Connection.unsubscribe()`. If this method is not
called and the connection that was used to create the subscription is
explicitly closed using the function :meth:`~Connection.close()`, the
subscription will not be deregistered in the database.
.. attribute:: Connection.tag
This read-write attribute initially contains the actual tag of the session
that was acquired from a pool by :meth:`SessionPool.acquire()`. If the
connection was not acquired from a pool or no tagging parameters were
specified (tag and matchanytag) when the connection was acquired from the
pool, this value will be None. If the value is changed, it must be a string
containing name=value pairs like "k1=v1;k2=v2".
If this value is not None when the connection is released back to the pool
it will be used to retag the session. This value can be overridden in the
call to :meth:`SessionPool.release()`.
.. note::
This attribute is an extension to the DB API definition.
.. versionadded:: 7.1
.. attribute:: Connection.tnsentry
This read-only attribute returns the TNS entry of the database to which a
connection has been established.
.. deprecated:: 8.2
Use the attribute :attr:`~Connection.dsn` instead.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.unsubscribe(subscr)
Unsubscribe from events in the database that were originally subscribed to
using :meth:`~Connection.subscribe()`. The connection used to unsubscribe
should be the same one used to create the subscription, or should access
the same database and be connected as the same user name.
.. versionadded:: 6.4
.. attribute:: Connection.username
This read-only attribute returns the name of the user which established the
connection to the database.
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.version
This read-only attribute returns the version of the database to which a
connection has been established.
.. note::
This attribute is an extension to the DB API definition.
.. note::
If you connect to Oracle Database 18 or higher with client libraries
12.2 or lower that you will only receive the base version (such as
18.0.0.0.0) instead of the full version (18.3.0.0.0).

View File

@ -0,0 +1,678 @@
.. _cursorobj:
*************
Cursor Object
*************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
.. method:: Cursor.__enter__()
The entry point for the cursor as a context manager. It returns itself.
.. note::
This method is an extension to the DB API definition.
.. method:: Cursor.__exit__()
The exit point for the cursor as a context manager. It closes the cursor.
.. note::
This method is an extension to the DB API definition.
.. attribute:: Cursor.arraysize
This read-write attribute can be used to tune the number of rows internally
fetched and buffered by internal calls to the database when fetching rows
from SELECT statements and REF CURSORS. The value can drastically affect
the performance of a query since it directly affects the number of network
round trips between Python and the database. For methods like
:meth:`~Cursor.fetchone()` and :meth:`~Cursor.fetchall()` it does not change
how many rows are returned to the application. For
:meth:`~Cursor.fetchmany()` it is the default number of rows to fetch.
Due to the performance benefits, the default ``Cursor.arraysize`` is 100
instead of the 1 that the DB API recommends. This value means that 100 rows
are fetched by each internal call to the database.
See :ref:`Tuning Fetch Performance <tuningfetch>` for more information.
.. attribute:: Cursor.bindarraysize
This read-write attribute specifies the number of rows to bind at a time
and is used when creating variables via :meth:`~Cursor.setinputsizes()` or
:meth:`~Cursor.var()`. It defaults to 1 meaning to bind a single row at a
time.
.. note::
The DB API definition does not define this attribute.
.. method:: Cursor.arrayvar(typ, value, [size])
Create an array variable associated with the cursor of the given type and
size and return a :ref:`variable object <varobj>`. The value is either an
integer specifying the number of elements to allocate or it is a list and
the number of elements allocated is drawn from the size of the list. If the
value is a list, the variable is also set with the contents of the list. If
the size is not specified and the type is a string or binary, 4000 bytes
is allocated. This is needed for passing arrays to PL/SQL (in cases where
the list might be empty and the type cannot be determined automatically) or
returning arrays from PL/SQL.
Array variables can only be used for PL/SQL associative arrays with
contiguous keys. For PL/SQL associative arrays with sparsely populated keys
or for varrays and nested tables, the approach shown in this
`example <https://github.com/oracle/python-cx_Oracle/blob/main/
samples/plsql_collection.py>`__ needs to be used.
.. note::
The DB API definition does not define this method.
.. method:: Cursor.bindnames()
Return the list of bind variable names bound to the statement. Note that a
statement must have been prepared first.
.. note::
The DB API definition does not define this method.
.. attribute:: Cursor.bindvars
This read-only attribute provides the bind variables used for the last
execute. The value will be either a list or a dictionary depending on
whether binding was done by position or name. Care should be taken when
referencing this attribute. In particular, elements should not be removed
or replaced.
.. note::
The DB API definition does not define this attribute.
.. method:: Cursor.callfunc(name, returnType, parameters=[], \
keyword_parameters={})
Call a function with the given name. The return type is specified in the
same notation as is required by :meth:`~Cursor.setinputsizes()`. The
sequence of parameters must contain one entry for each parameter that the
function expects. Any keyword parameters will be included after the
positional parameters. The result of the call is the return value of the
function.
See :ref:`plsqlfunc` for an example.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
parameter `keywordParameters` was renamed to `keyword_parameters`. The
old name will continue to work as a keyword parameter for a period of
time.
.. note::
The DB API definition does not define this method.
.. note::
If you intend to call :meth:`Cursor.setinputsizes()` on the cursor
prior to making this call, then note that the first item in the
parameter list refers to the return value of the function.
.. method:: Cursor.callproc(name, parameters=[], keyword_parameters={})
Call a procedure with the given name. The sequence of parameters must
contain one entry for each parameter that the procedure expects. The result
of the call is a modified copy of the input sequence. Input parameters are
left untouched; output and input/output parameters are replaced with
possibly new values. Keyword parameters will be included after the
positional parameters and are not returned as part of the output sequence.
See :ref:`plsqlproc` for an example.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
parameter `keywordParameters` was renamed to `keyword_parameters`. The
old name will continue to work as a keyword parameter for a period of
time.
.. note::
The DB API definition does not allow for keyword parameters.
.. method:: Cursor.close()
Close the cursor now, rather than whenever __del__ is called. The cursor
will be unusable from this point forward; an Error exception will be raised
if any operation is attempted with the cursor.
.. attribute:: Cursor.connection
This read-only attribute returns a reference to the connection object on
which the cursor was created.
.. note::
This attribute is an extension to the DB API definition but it is
mentioned in PEP 249 as an optional extension.
.. data:: Cursor.description
This read-only attribute is a sequence of 7-item sequences. Each of these
sequences contains information describing one result column: (name, type,
display_size, internal_size, precision, scale, null_ok). This attribute
will be None for operations that do not return rows or if the cursor has
not had an operation invoked via the :meth:`~Cursor.execute()` method yet.
The type will be one of the :ref:`database type constants <dbtypes>`
defined at the module level.
.. method:: Cursor.execute(statement, parameters=[], ** keyword_parameters)
Execute a statement against the database. See :ref:`sqlexecution`.
Parameters may be passed as a dictionary or sequence or as keyword
parameters. If the parameters are a dictionary, the values will be bound by
name and if the parameters are a sequence the values will be bound by
position. Note that if the values are bound by position, the order of the
variables is from left to right as they are encountered in the statement
and SQL statements are processed differently than PL/SQL statements. For
this reason, it is generally recommended to bind parameters by name instead
of by position.
Parameters passed as a dictionary are name and value pairs. The name maps
to the bind variable name used by the statement and the value maps to the
Python value you wish bound to that bind variable.
A reference to the statement will be retained by the cursor. If None or the
same string object is passed in again, the cursor will execute that
statement again without performing a prepare or rebinding and redefining.
This is most effective for algorithms where the same statement is used, but
different parameters are bound to it (many times). Note that parameters
that are not passed in during subsequent executions will retain the value
passed in during the last execution that contained them.
For maximum efficiency when reusing an statement, it is best to use the
:meth:`~Cursor.setinputsizes()` method to specify the parameter types and
sizes ahead of time; in particular, None is assumed to be a string of
length 1 so any values that are later bound as numbers or dates will raise
a TypeError exception.
If the statement is a query, the cursor is returned as a convenience to the
caller (so it can be used directly as an iterator over the rows in the
cursor); otherwise, ``None`` is returned.
.. note::
The DB API definition does not define the return value of this method.
.. method:: Cursor.executemany(statement, parameters, batcherrors=False, \
arraydmlrowcounts=False)
Prepare a statement for execution against a database and then execute it
against all parameter mappings or sequences found in the sequence
parameters. See :ref:`batchstmnt`.
The statement is managed in the same way as the :meth:`~Cursor.execute()`
method manages it. If the size of the buffers allocated for any of the
parameters exceeds 2 GB, you will receive the error "DPI-1015: array size
of <n> is too large", where <n> varies with the size of each element being
allocated in the buffer. If you receive this error, decrease the number of
elements in the sequence parameters.
If there are no parameters, or parameters have previously been bound, the
number of iterations can be specified as an integer instead of needing to
provide a list of empty mappings or sequences.
When true, the batcherrors parameter enables batch error support within
Oracle and ensures that the call succeeds even if an exception takes place
in one or more of the sequence of parameters. The errors can then be
retrieved using :meth:`~Cursor.getbatcherrors()`.
When true, the arraydmlrowcounts parameter enables DML row counts to be
retrieved from Oracle after the method has completed. The row counts can
then be retrieved using :meth:`~Cursor.getarraydmlrowcounts()`.
Both the batcherrors parameter and the arraydmlrowcounts parameter can only
be true when executing an insert, update, delete or merge statement; in all
other cases an error will be raised.
For maximum efficiency, it is best to use the
:meth:`~Cursor.setinputsizes()` method to specify the parameter types and
sizes ahead of time; in particular, None is assumed to be a string of
length 1 so any values that are later bound as numbers or dates will raise
a TypeError exception.
.. method:: Cursor.executemanyprepared(num_iters)
Execute the previously prepared and bound statement the given number of
times. The variables that are bound must have already been set to their
desired value before this call is made. This method was designed for the
case where optimal performance is required as it comes at the expense of
compatibility with the DB API.
.. note::
The DB API definition does not define this method.
.. deprecated:: 6.4
Use :meth:`~Cursor.executemany()` instead with None for the statement
argument and an integer for the parameters argument.
.. method:: Cursor.fetchall()
Fetch all (remaining) rows of a query result, returning them as a list of
tuples. An empty list is returned if no more rows are available. Note that
the cursor's arraysize attribute can affect the performance of this
operation, as internally reads from the database are done in batches
corresponding to the arraysize.
An exception is raised if the previous call to :meth:`~Cursor.execute()`
did not produce any result set or no call was issued yet.
See :ref:`fetching` for an example.
.. method:: Cursor.fetchmany(numRows=cursor.arraysize)
Fetch the next set of rows of a query result, returning a list of tuples.
An empty list is returned if no more rows are available. Note that the
cursor's arraysize attribute can affect the performance of this operation.
The number of rows to fetch is specified by the parameter. If it is not
given, the cursor's arraysize attribute determines the number of rows to be
fetched. If the number of rows available to be fetched is fewer than the
amount requested, fewer rows will be returned.
An exception is raised if the previous call to :meth:`~Cursor.execute()`
did not produce any result set or no call was issued yet.
See :ref:`fetching` for an example.
.. method:: Cursor.fetchone()
Fetch the next row of a query result set, returning a single tuple or None
when no more data is available.
An exception is raised if the previous call to :meth:`~Cursor.execute()`
did not produce any result set or no call was issued yet.
See :ref:`fetching` for an example.
.. method:: Cursor.fetchraw(num_rows=cursor.arraysize)
Fetch the next set of rows of a query result into the internal buffers of
the defined variables for the cursor. The number of rows actually fetched
is returned.
An exception is raised if the previous call to :meth:`~Cursor.execute()`
did not produce any result set or no call was issued yet.
.. deprecated:: 8.2
Use :meth:`Cursor.fetchmany()` instead.
.. note::
The DB API definition does not define this method.
.. attribute:: Cursor.fetchvars
This read-only attribute specifies the list of variables created for the
last query that was executed on the cursor. Care should be taken when
referencing this attribute. In particular, elements should not be removed
or replaced.
.. note::
The DB API definition does not define this attribute.
.. method:: Cursor.getarraydmlrowcounts()
Retrieve the DML row counts after a call to :meth:`~Cursor.executemany()`
with arraydmlrowcounts enabled. This will return a list of integers
corresponding to the number of rows affected by the DML statement for each
element of the array passed to :meth:`~Cursor.executemany()`.
.. note::
The DB API definition does not define this method and it is only
available for Oracle 12.1 and higher.
.. method:: Cursor.getbatcherrors()
Retrieve the exceptions that took place after a call to
:meth:`~Cursor.executemany()` with batcherrors enabled. This will return a
list of Error objects, one error for each iteration that failed. The offset
can be determined by looking at the offset attribute of the error object.
.. note::
The DB API definition does not define this method.
.. method:: Cursor.getimplicitresults()
Return a list of cursors which correspond to implicit results made
available from a PL/SQL block or procedure without the use of OUT ref
cursor parameters. The PL/SQL block or procedure opens the cursors and
marks them for return to the client using the procedure
dbms_sql.return_result. Cursors returned in this fashion should not be
closed. They will be closed automatically by the parent cursor when it is
closed. Closing the parent cursor will invalidate the cursors returned by
this method.
.. versionadded:: 5.3
.. note::
The DB API definition does not define this method and it is only
available for Oracle Database 12.1 (both client and server must be at
this level or higher). It is most like the DB API method nextset(), but
unlike that method (which requires that the next result set overwrite
the current result set), this method returns cursors which can be
fetched independently of each other.
.. attribute:: Cursor.inputtypehandler
This read-write attribute specifies a method called for each value that is
bound to a statement executed on the cursor and overrides the attribute
with the same name on the connection if specified. The method signature is
handler(cursor, value, arraysize) and the return value is expected to be a
variable object or None in which case a default variable object will be
created. If this attribute is None, the value of the attribute with the
same name on the connection is used.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Cursor.__iter__()
Returns the cursor itself to be used as an iterator.
.. note::
This method is an extension to the DB API definition but it is
mentioned in PEP 249 as an optional extension.
.. data:: Cursor.lastrowid
This read-only attribute returns the rowid of the last row modified by the
cursor. If no row was modified by the last operation performed on the
cursor, the value None is returned.
.. versionadded:: 7.3
.. attribute:: Cursor.outputtypehandler
This read-write attribute specifies a method called for each column that is
to be fetched from this cursor. The method signature is
handler(cursor, name, defaultType, length, precision, scale) and the return
value is expected to be a variable object or None in which case a default
variable object will be created. If this attribute is None, the value of
the attribute with the same name on the connection is used instead.
See :ref:`outputtypehandlers`.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Cursor.parse(statement)
This can be used to parse a statement without actually executing it (this
step is done automatically by Oracle when a statement is executed).
.. note::
The DB API definition does not define this method.
.. note::
You can parse any DML or DDL statement. DDL statements are executed
immediately and an implied commit takes place.
.. attribute:: Cursor.prefetchrows
This read-write attribute can be used to tune the number of rows that the
Oracle Client library fetches when a SELECT statement is executed. This
value can reduce the number of round-trips to the database that are required
to fetch rows but at the cost of additional memory. Setting this value to 0
can be useful when the timing of fetches must be explicitly controlled.
See :ref:`Tuning Fetch Performance <tuningfetch>` for more information.
.. note::
The DB API definition does not define this method.
.. method:: Cursor.prepare(statement, [tag])
This can be used before a call to :meth:`~Cursor.execute()` to define the
statement that will be executed. When this is done, the prepare phase will
not be performed when the call to :meth:`~Cursor.execute()` is made with
None or the same string object as the statement. If specified the
statement will be returned to the statement cache with the given tag. See
the Oracle documentation for more information about the statement cache.
See :ref:`Statement Caching <stmtcache>` for more information.
.. note::
The DB API definition does not define this method.
.. attribute:: Cursor.rowcount
This read-only attribute specifies the number of rows that have currently
been fetched from the cursor (for select statements), that have been
affected by the operation (for insert, update, delete and merge
statements), or the number of successful executions of the statement
(for PL/SQL statements).
.. attribute:: Cursor.rowfactory
This read-write attribute specifies a method to call for each row that is
retrieved from the database. Ordinarily a tuple is returned for each row
but if this attribute is set, the method is called with the tuple that
would normally be returned, and the result of the method is returned
instead.
See :ref:`rowfactories`.
.. note::
The DB API definition does not define this attribute.
.. method:: Cursor.scroll(value=0, mode="relative")
Scroll the cursor in the result set to a new position according to the
mode.
If mode is "relative" (the default value), the value is taken as an offset
to the current position in the result set. If set to "absolute", value
states an absolute target position. If set to "first", the cursor is
positioned at the first row and if set to "last", the cursor is set to the
last row in the result set.
An error is raised if the mode is "relative" or "absolute" and the scroll
operation would position the cursor outside of the result set.
.. versionadded:: 5.3
.. note::
This method is an extension to the DB API definition but it is
mentioned in PEP 249 as an optional extension.
.. attribute:: Cursor.scrollable
This read-write boolean attribute specifies whether the cursor can be
scrolled or not. By default, cursors are not scrollable, as the server
resources and response times are greater than nonscrollable cursors. This
attribute is checked and the corresponding mode set in Oracle when calling
the method :meth:`~Cursor.execute()`.
.. versionadded:: 5.3
.. note::
The DB API definition does not define this attribute.
.. method:: Cursor.setinputsizes(\*args, \*\*keywordArgs)
This can be used before a call to :meth:`~Cursor.execute()`,
:meth:`~Cursor.callfunc()` or :meth:`~Cursor.callproc()` to predefine
memory areas for the operation's parameters. Each parameter should be a
type object corresponding to the input that will be used or it should be an
integer specifying the maximum length of a string parameter. Use keyword
parameters when binding by name and positional parameters when binding by
position. The singleton None can be used as a parameter when using
positional parameters to indicate that no space should be reserved for that
position.
.. note::
If you plan to use :meth:`~Cursor.callfunc()` then be aware that the
first parameter in the list refers to the return value of the function.
.. method:: Cursor.setoutputsize(size, [column])
This method does nothing and is retained solely for compatibility with the
DB API. The module automatically allocates as much space as needed to fetch
LONG and LONG RAW columns (or CLOB as string and BLOB as bytes).
.. attribute:: Cursor.statement
This read-only attribute provides the string object that was previously
prepared with :meth:`~Cursor.prepare()` or executed with
:meth:`~Cursor.execute()`.
.. note::
The DB API definition does not define this attribute.
.. method:: Cursor.var(typ, [size, arraysize, inconverter, outconverter, \
typename, encoding_errors, bypass_decode])
Create a variable with the specified characteristics. This method was
designed for use with PL/SQL in/out variables where the length or type
cannot be determined automatically from the Python object passed in or for
use in input and output type handlers defined on cursors or connections.
The typ parameter specifies the type of data that should be stored in the
variable. This should be one of the :ref:`database type constants
<dbtypes>`, :ref:`DB API constants <types>`, an object type returned from
the method :meth:`Connection.gettype()` or one of the following Python
types:
.. list-table::
:header-rows: 1
* - Python Type
- Database Type
* - bool
- :attr:`cx_Oracle.DB_TYPE_BOOLEAN`
* - bytes
- :attr:`cx_Oracle.DB_TYPE_RAW`
* - datetime.date
- :attr:`cx_Oracle.DB_TYPE_DATE`
* - datetime.datetime
- :attr:`cx_Oracle.DB_TYPE_DATE`
* - datetime.timedelta
- :attr:`cx_Oracle.DB_TYPE_INTERVAL_DS`
* - decimal.Decimal
- :attr:`cx_Oracle.DB_TYPE_NUMBER`
* - float
- :attr:`cx_Oracle.DB_TYPE_NUMBER`
* - int
- :attr:`cx_Oracle.DB_TYPE_NUMBER`
* - str
- :attr:`cx_Oracle.DB_TYPE_VARCHAR`
The size parameter specifies the length of string and raw variables and is
ignored in all other cases. If not specified for string and raw variables,
the value 4000 is used.
The arraysize parameter specifies the number of elements the variable will
have. If not specified the bind array size (usually 1) is used. When a
variable is created in an output type handler this parameter should be set
to the cursor's array size.
The inconverter and outconverter parameters specify methods used for
converting values to/from the database. More information can be found in
the section on :ref:`variable objects<varobj>`.
The typename parameter specifies the name of a SQL object type and must be
specified when using type :data:`cx_Oracle.OBJECT` unless the type object
was passed directly as the first parameter.
The encoding_errors parameter specifies what should happen when decoding
byte strings fetched from the database into strings. It should be one of
the values noted in the builtin
`decode <https://docs.python.org/3/library/stdtypes.html#bytes.decode>`__
function.
The bypass_decode parameter, if specified, should be passed as a
boolean value. Passing a `True` value causes values of database types
:data:`~cx_Oracle.DB_TYPE_VARCHAR`, :data:`~cx_Oracle.DB_TYPE_CHAR`,
:data:`~cx_Oracle.DB_TYPE_NVARCHAR`, :data:`~cx_Oracle.DB_TYPE_NCHAR` and
:data:`~cx_Oracle.DB_TYPE_LONG` to be returned as `bytes` instead of `str`,
meaning that cx_Oracle doesn't do any decoding. See :ref:`Fetching raw
data <fetching-raw-data>` for more information.
.. versionadded:: 8.2
The parameter `bypass_decode` was added.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
parameter `encodingErrors` was renamed to `encoding_errors`. The old
name will continue to work as a keyword parameter for a period of time.
.. note::
The DB API definition does not define this method.

View File

@ -0,0 +1,184 @@
.. _deprecations:
************
Deprecations
************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
The following tables contains all of the deprecations in the cx_Oracle API,
when they were first deprecated and a comment on what should be used instead,
if applicable. The most recent deprecations are listed first.
.. list-table:: Deprecated in 8.2
:header-rows: 1
:widths: 25 75
:width: 100%
:name: _deprecations_8_2
* - Name
- Comments
* - `encoding` parameter to :meth:`cx_Oracle.connect()`
- No longer needed as the use of encodings other than UTF-8 is
deprecated. Encoding is handled internally between cx_Oracle and Oracle
Database.
* - `nencoding` parameter to :meth:`cx_Oracle.connect()`
- No longer needed as the use of encodings other than UTF-8 is
deprecated.
* - `encoding` parameter to :meth:`cx_Oracle.SessionPool()`
- No longer needed as the use of encodings other than UTF-8 is
deprecated.
* - `nencoding` parameter to :meth:`cx_Oracle.SessionPool()`
- No longer needed as the use of encodings other than UTF-8 is
deprecated.
* - Connection.maxBytesPerCharacter
- No longer needed as the use of encodings other than UTF-8 is
deprecated. The constant value 4 can be used instead.
* - Positional parameters to :meth:`cx_Oracle.connect()`
- Replace with keyword parameters in order to comply with the Python
database API.
* - Positional parameters to :meth:`cx_Oracle.SessionPool()`
- Replace with keyword parameters in order to comply with the Python
database API.
* - `threaded` parameter to :meth:`cx_Oracle.SessionPool()`
- The value of this parameter is ignored. Threading is now always used.
* - `waitTimeout` parameter to :meth:`cx_Oracle.SessionPool()`
- Replace with parameter name `wait_timeout`
* - `maxLifetimeSession` parameter to :meth:`cx_Oracle.SessionPool()`
- Replace with parameter name `max_lifetime_session`
* - `sessionCallback` parameter to :meth:`cx_Oracle.SessionPool()`
- Replace with parameter name `session_callback`
* - `maxSessionsPerShard` parameter to :meth:`cx_Oracle.SessionPool()`
- Replace with parameter name `max_sessions_per_shard`
* - `SessionPool.tnsentry`
- Replace with :data:`SessionPool.dsn`
* - `payloadType` parameter to :meth:`Connection.queue()`
- Replace with parameter name `payload_type` if using keyword parameters.
* - `ipAddress` parameter to :meth:`Connection.subscribe()`
- Replace with parameter name `ip_address`
* - `groupingClass` parameter to :meth:`Connection.subscribe()`
- Replace with parameter name `grouping_class`
* - `groupingValue` parameter to :meth:`Connection.subscribe()`
- Replace with parameter name `grouping_value`
* - `groupingType` parameter to :meth:`Connection.subscribe()`
- Replace with parameter name `grouping_type`
* - `clientInitiated` parameter to :meth:`Connection.subscribe()`
- Replace with parameter name `client_initiated`
* - `Connection.callTimeout`
- Replace with :data:`Connection.call_timeout`
* - `Connection.tnsentry`
- Replace with :data:`Connection.dsn`
* - `keywordParameters` parameter to :meth:`Cursor.callfunc()`
- Replace with parameter name `keyword_parameters`
* - `keywordParameters` parameter to :meth:`Cursor.callproc()`
- Replace with parameter name `keyword_parameters`
* - `encodingErrors` parameter to :meth:`Cursor.var()`
- Replace with parameter name `encoding_errors`
* - `Cursor.fetchraw()`
- Replace with :meth:`Cursor.fetchmany()`
* - `newSize` parameter to :meth:`LOB.trim()`
- Replace with parameter name `new_size`
* - `Queue.deqMany`
- Replace with :meth:`Queue.deqmany()`
* - `Queue.deqOne`
- Replace with :meth:`Queue.deqone()`
* - `Queue.enqMany`
- Replace with :meth:`Queue.enqmany()`
* - `Queue.enqOne`
- Replace with :meth:`Queue.enqone()`
* - `Queue.deqOptions`
- Replace with :data:`Queue.deqoptions`
* - `Queue.enqOptions`
- Replace with :meth:`Queue.enqoptions`
* - `Queue.payloadType`
- Replace with :meth:`Queue.payload_type`
* - `Subscription.ipAddress`
- Replace with :attr:`Subscription.ip_address`
* - `Message.consumerName`
- Replace with :attr:`Message.consumer_name`
* - `Message.queueName`
- Replace with :attr:`Message.queue_name`
* - `Variable.actualElements`
- Replace with :attr:`Variable.actual_elements`
* - `Variable.bufferSize`
- Replace with :attr:`Variable.buffer_size`
* - `Variable.numElements`
- Replace with :attr:`Variable.num_elements`
.. list-table:: Deprecated in 8.0
:header-rows: 1
:widths: 25 75
:width: 100%
:name: _deprecations_8_0
* - Name
- Comments
* - cx_Oracle.BFILE
- Replace with :data:`cx_Oracle.DB_TYPE_BFILE`
* - cx_Oracle.BLOB
- Replace with :data:`cx_Oracle.DB_TYPE_BLOB`
* - cx_Oracle.BOOLEAN
- Replace with :data:`cx_Oracle.DB_TYPE_BOOLEAN`
* - cx_Oracle.CLOB
- Replace with :data:`cx_Oracle.DB_TYPE_CLOB`
* - cx_Oracle.CURSOR
- Replace with :data:`cx_Oracle.DB_TYPE_CURSOR`
* - cx_Oracle.FIXED_CHAR
- Replace with :data:`cx_Oracle.DB_TYPE_CHAR`
* - cx_Oracle.FIXED_NCHAR
- Replace with :data:`cx_Oracle.DB_TYPE_NCHAR`
* - cx_Oracle.INTERVAL
- Replace with :data:`cx_Oracle.DB_TYPE_INTERVAL_DS`
* - cx_Oracle.LONG_BINARY
- Replace with :data:`cx_Oracle.DB_TYPE_LONG_RAW`
* - cx_Oracle.LONG_STRING
- Replace with :data:`cx_Oracle.DB_TYPE_LONG`
* - cx_Oracle.NATIVE_FLOAT
- Replace with :data:`cx_Oracle.DB_TYPE_BINARY_DOUBLE`
* - cx_Oracle.NATIVE_INT
- Replace with :data:`cx_Oracle.DB_TYPE_BINARY_INTEGER`
* - cx_Oracle.NCHAR
- Replace with :data:`cx_Oracle.DB_TYPE_NVARCHAR`
* - cx_Oracle.NCLOB
- Replace with :data:`cx_Oracle.DB_TYPE_NCLOB`
* - cx_Oracle.OBJECT
- Replace with :data:`cx_Oracle.DB_TYPE_OBJECT`
* - cx_Oracle.TIMESTAMP
- Replace with :data:`cx_Oracle.DB_TYPE_TIMESTAMP`
.. list-table:: Deprecated in 7.2
:header-rows: 1
:widths: 25 75
:width: 100%
:name: _deprecations_7_2
* - Name
- Comments
* - Connection.deq()
- Replace with :meth:`Queue.deqone()` or :meth:`Queue.deqmany()`.
* - Connection.deqoptions()
- Replace with attribute :attr:`Queue.deqoptions`.
* - Connection.enq()
- Replace with :meth:`Queue.enqone()` or :meth:`Queue.enqmany()`.
* - Connection.enqoptions()
- Replace with attribute :attr:`Queue.enqoptions`.
.. list-table:: Deprecated in 6.4
:header-rows: 1
:widths: 25 75
:width: 100%
:name: _deprecations_6_4
* - Name
- Comments
* - Cursor.executemanyprepared()
- Replace with :meth:`~Cursor.executemany()` with None for the statement
argument and an integer for the parameters argument.

105
doc/src/api_manual/lob.rst Normal file
View File

@ -0,0 +1,105 @@
.. _lobobj:
***********
LOB Objects
***********
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
See :ref:`lobdata` for more information about using LOBs.
.. note::
This object is an extension the DB API. It is returned whenever Oracle
:data:`CLOB`, :data:`BLOB` and :data:`BFILE` columns are fetched.
.. method:: LOB.close()
Close the LOB. Call this when writing is completed so that the indexes
associated with the LOB can be updated -- but only if :meth:`~LOB.open()`
was called first.
.. method:: LOB.fileexists()
Return a boolean indicating if the file referenced by the BFILE type LOB
exists.
.. method:: LOB.getchunksize()
Return the chunk size for the internal LOB. Reading and writing to the LOB
in chunks of multiples of this size will improve performance.
.. method:: LOB.getfilename()
Return a two-tuple consisting of the directory alias and file name for a
BFILE type LOB.
.. method:: LOB.isopen()
Return a boolean indicating if the LOB has been opened using the method
:meth:`~LOB.open()`.
.. method:: LOB.open()
Open the LOB for writing. This will improve performance when writing to a
LOB in chunks and there are functional or extensible indexes associated
with the LOB. If this method is not called, each write will perform an open
internally followed by a close after the write has been completed.
.. method:: LOB.read([offset=1, [amount]])
Return a portion (or all) of the data in the LOB object. Note that the
amount and offset are in bytes for BLOB and BFILE type LOBs and in UCS-2
code points for CLOB and NCLOB type LOBs. UCS-2 code points are equivalent
to characters for all but supplemental characters. If supplemental
characters are in the LOB, the offset and amount will have to be chosen
carefully to avoid splitting a character.
.. method:: LOB.setfilename(dirAlias, name)
Set the directory alias and name of the BFILE type LOB.
.. method:: LOB.size()
Returns the size of the data in the LOB object. For BLOB and BFILE type
LOBs this is the number of bytes. For CLOB and NCLOB type LOBs this is the
number of UCS-2 code points. UCS-2 code points are equivalent to characters
for all but supplemental characters.
.. method:: LOB.trim(new_size=0)
Trim the LOB to the new size.
.. attribute:: LOB.type
This read-only attribute returns the type of the LOB as one of the
:ref:`database type constants <dbtypes>`.
.. versionadded:: 8.0
.. method:: LOB.write(data, offset=1)
Write the data to the LOB object at the given offset. The offset is in
bytes for BLOB type LOBs and in UCS-2 code points for CLOB and NCLOB type
LOBs. UCS-2 code points are equivalent to characters for all but
supplemental characters. If supplemental characters are in the LOB, the
offset will have to be chosen carefully to avoid splitting a character.
Note that if you want to make the LOB value smaller, you must use the
:meth:`~LOB.trim()` function.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,197 @@
.. _objecttype:
*******************
Object Type Objects
*******************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
.. note::
This object is an extension to the DB API. It is returned by the
:meth:`Connection.gettype()` call and is available as the
:data:`Variable.type` for variables containing Oracle objects.
.. method:: ObjectType([sequence])
The object type may be called directly and serves as an alternative way of
calling :meth:`~ObjectType.newobject()`.
.. attribute:: ObjectType.attributes
This read-only attribute returns a list of the :ref:`attributes
<objectattr>` that make up the object type.
.. attribute:: ObjectType.iscollection
This read-only attribute returns a boolean indicating if the object type
refers to a collection or not.
.. attribute:: ObjectType.name
This read-only attribute returns the name of the type.
.. attribute:: ObjectType.element_type
This read-only attribute returns the type of elements found in collections
of this type, if :attr:`~ObjectType.iscollection` is ``True``; otherwise,
it returns ``None``. If the collection contains objects, this will be
another object type; otherwise, it will be one of the
:ref:`database type constants <dbtypes>`.
.. versionadded:: 8.0
.. method:: ObjectType.newobject([sequence])
Return a new Oracle object of the given type. This object can then be
modified by setting its attributes and then bound to a cursor for
interaction with Oracle. If the object type refers to a collection, a
sequence may be passed and the collection will be initialized with the
items in that sequence.
.. attribute:: ObjectType.schema
This read-only attribute returns the name of the schema that owns the type.
Object Objects
--------------
.. note::
This object is an extension to the DB API. It is returned by the
:meth:`ObjectType.newobject()` call and can be bound to variables of
type :data:`~cx_Oracle.OBJECT`. Attributes can be retrieved and set
directly.
.. method:: Object.append(element)
Append an element to the collection object. If no elements exist in the
collection, this creates an element at index 0; otherwise, it creates an
element immediately following the highest index available in the
collection.
.. method:: Object.asdict()
Return a dictionary where the collection's indexes are the keys and the
elements are its values.
.. versionadded:: 7.0
.. method:: Object.aslist()
Return a list of each of the collection's elements in index order.
.. method:: Object.copy()
Create a copy of the object and return it.
.. method:: Object.delete(index)
Delete the element at the specified index of the collection. If the
element does not exist or is otherwise invalid, an error is raised. Note
that the indices of the remaining elements in the collection are not
changed. In other words, the delete operation creates holes in the
collection.
.. method:: Object.exists(index)
Return True or False indicating if an element exists in the collection at
the specified index.
.. method:: Object.extend(sequence)
Append all of the elements in the sequence to the collection. This is
the equivalent of performing :meth:`~Object.append()` for each element
found in the sequence.
.. method:: Object.first()
Return the index of the first element in the collection. If the collection
is empty, None is returned.
.. method:: Object.getelement(index)
Return the element at the specified index of the collection. If no element
exists at that index, an exception is raised.
.. method:: Object.last()
Return the index of the last element in the collection. If the collection
is empty, None is returned.
.. method:: Object.next(index)
Return the index of the next element in the collection following the
specified index. If there are no elements in the collection following the
specified index, None is returned.
.. method:: Object.prev(index)
Return the index of the element in the collection preceding the specified
index. If there are no elements in the collection preceding the
specified index, None is returned.
.. method:: Object.setelement(index, value)
Set the value in the collection at the specified index to the given value.
.. method:: Object.size()
Return the number of elements in the collection.
.. method:: Object.trim(num)
Remove the specified number of elements from the end of the collection.
.. _objectattr:
Object Attribute Objects
------------------------
.. note::
This object is an extension to the DB API. The elements of
:attr:`ObjectType.attributes` are instances of this type.
.. attribute:: ObjectAttribute.name
This read-only attribute returns the name of the attribute.
.. attribute:: ObjectAttribute.type
This read-only attribute returns the type of the attribute. This will be an
:ref:`Oracle Object Type <objecttype>` if the variable binds
Oracle objects; otherwise, it will be one of the
:ref:`database type constants <dbtypes>`.
.. versionadded:: 8.0

View File

@ -0,0 +1,309 @@
.. _sesspool:
******************
SessionPool Object
******************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
.. note::
This object is an extension to the DB API.
Connection pooling in cx_Oracle is handled by SessionPool objects.
See :ref:`connpool` for information on connection pooling.
.. method:: SessionPool.acquire(user=None, password=None, cclass=None, \
purity=cx_Oracle.ATTR_PURITY_DEFAULT, tag=None, matchanytag=False, \
shardingkey=[], supershardingkey=[])
Acquire a connection from the session pool and return a
:ref:`connection object <connobj>`.
If the pool is homogeneous, the user and password parameters cannot be
specified. If they are, an exception will be raised.
The cclass parameter, if specified, should be a string corresponding to the
connection class for database resident connection pooling (DRCP).
The purity parameter is expected to be one of
:data:`~cx_Oracle.ATTR_PURITY_NEW`, :data:`~cx_Oracle.ATTR_PURITY_SELF`, or
:data:`~cx_Oracle.ATTR_PURITY_DEFAULT`.
The tag parameter, if specified, is expected to be a string with name=value
pairs like "k1=v1;k2=v2" and will limit the sessions that can be returned
from a session pool unless the matchanytag parameter is set to True. In
that case sessions with the specified tag will be preferred over others,
but if no such sessions are available a session with a different tag may be
returned instead. In any case, untagged sessions will always be returned if
no sessions with the specified tag are available. Sessions are tagged when
they are :meth:`released <SessionPool.release>` back to the pool.
The shardingkey and supershardingkey parameters, if specified, are expected
to be a sequence of values which will be used to identify the database
shard to connect to. The key values can be strings, numbers, bytes or
dates.
.. attribute:: SessionPool.busy
This read-only attribute returns the number of sessions currently acquired.
.. method:: SessionPool.close(force=False)
Close the session pool now, rather than when the last reference to it is
released, which makes it unusable for further work.
If any connections have been acquired and not released back to the pool
this method will fail unless the force parameter is set to True.
.. method:: SessionPool.drop(connection)
Drop the connection from the pool which is useful if the connection is no
longer usable (such as when the session is killed).
.. attribute:: SessionPool.dsn
This read-only attribute returns the TNS entry of the database to which a
connection has been established.
.. attribute:: SessionPool.getmode
This read-write attribute determines how connections are returned from the
pool. If :data:`~cx_Oracle.SPOOL_ATTRVAL_FORCEGET` is specified, a new
connection will be returned even if there are no free sessions in the pool.
:data:`~cx_Oracle.SPOOL_ATTRVAL_NOWAIT` will raise an exception if there
are no free sessions are available in the pool. If
:data:`~cx_Oracle.SPOOL_ATTRVAL_WAIT` is specified and there are no free
sessions in the pool, the caller will wait until a free session is
available. :data:`~cx_Oracle.SPOOL_ATTRVAL_TIMEDWAIT` uses the value of
:data:`~SessionPool.wait_timeout` to determine how long the caller should
wait for a session to become available before returning an error.
.. attribute:: SessionPool.homogeneous
This read-write boolean attribute indicates whether the pool is considered
homogeneous or not. If the pool is not homogeneous different authentication
can be used for each connection acquired from the pool.
.. attribute:: SessionPool.increment
This read-only attribute returns the number of sessions that will be
established when additional sessions need to be created.
.. attribute:: SessionPool.max
This read-only attribute returns the maximum number of sessions that the
session pool can control.
.. attribute:: SessionPool.max_lifetime_session
This read-write attribute returns the maximum length of time (in seconds)
that a pooled session may exist. Sessions that are in use will not be
closed. They become candidates for termination only when they are released
back to the pool and have existed for longer than max_lifetime_session
seconds. Note that termination only occurs when the pool is accessed. A
value of 0 means that there is no maximum length of time that a pooled
session may exist. This attribute is only available in Oracle Database
12.1.
.. versionadded:: 5.3
.. attribute:: SessionPool.max_sessions_per_shard
This read-write attribute returns the number of sessions that can be created
per shard in the pool. Setting this attribute greater than zero specifies
the maximum number of sessions in the pool that can be used for any given
shard in a sharded database. This lets connections in the pool be balanced
across the shards. A value of zero will not set any maximum number of
sessions for each shard. This attribute is only available in Oracle Client
18.3 and higher.
.. versionadded:: 8.2
.. attribute:: SessionPool.min
This read-only attribute returns the number of sessions with which the
session pool was created and the minimum number of sessions that will be
controlled by the session pool.
.. attribute:: SessionPool.name
This read-only attribute returns the name assigned to the session pool by
Oracle.
.. attribute:: SessionPool.opened
This read-only attribute returns the number of sessions currently opened by
the session pool.
.. attribute:: SessionPool.ping_interval
This read-write integer attribute specifies the pool ping interval in
seconds. When a connection is acquired from the pool, a check is first made
to see how long it has been since the connection was put into the pool. If
this idle time exceeds ``ping_interval``, then a :ref:`round-trip
<roundtrips>` ping to the database is performed. If the connection is
unusable, it is discarded and a different connection is selected to be
returned by :meth:`SessionPool.acquire()`. Setting ``ping_interval`` to a
negative value disables pinging. Setting it to 0 forces a ping for every
``acquire()`` and is not recommended.
Prior to cx_Oracle 8.2, the ping interval was fixed at 60 seconds.
.. versionadded:: 8.2
.. method:: SessionPool.reconfigure([min, max, increment, getmode, timeout, \
wait_timeout, max_lifetime_session, max_sessions_per_shard, \
soda_metadata_cache, stmtcachesize, ping_interval])
Reconfigures various parameters of a connection pool. The pool size can be
altered with ``reconfigure()`` by passing values for
:data:`~SessionPool.min`, :data:`~SessionPool.max` or
:data:`~SessionPool.increment`. The :data:`~SessionPool.getmode`,
:data:`~SessionPool.timeout`, :data:`~SessionPool.wait_timeout`,
:data:`~SessionPool.max_lifetime_session`,
:data:`~SessionPool.max_sessions_per_shard`,
:data:`~SessionPool.soda_metadata_cache`, :data:`~SessionPool.stmtcachesize`
and :data:`~SessionPool.ping_interval` attributes can be set directly or
with ``reconfigure()``.
All parameters are optional. Unspecified parameters will leave those pool
attributes unchanged. The parameters are processed in two stages. After any
size change has been processed, reconfiguration on the other parameters is
done sequentially. If an error such as an invalid value occurs when changing
one attribute, then an exception will be generated but any already changed
attributes will retain their new values.
During reconfiguration of a pool's size, the behavior of
:meth:`SessionPool.acquire()` depends on the ``getmode`` in effect when
``acquire()`` is called:
* With mode :data:`~cx_Oracle.SPOOL_ATTRVAL_FORCEGET`, an ``acquire()`` call
will wait until the pool has been reconfigured.
* With mode :data:`~cx_Oracle.SPOOL_ATTRVAL_TIMEDWAIT`, an ``acquire()`` call
will try to acquire a connection in the time specified by
:data:`~SessionPool.wait_timeout` and return an error if the time taken
exceeds that value.
* With mode :data:`~cx_Oracle.SPOOL_ATTRVAL_WAIT`, an ``acquire()`` call
will wait until after the pool has been reconfigured and a connection is
available.
* With mode :data:`~cx_Oracle.SPOOL_ATTRVAL_NOWAIT`, if the number of busy
connections is less than the pool size, ``acquire()`` will return a new
connection after pool reconfiguration is complete.
Closing connections with :meth:`SessionPool.release()` or
:meth:`Connection.close()` will wait until any pool size reconfiguration is
complete.
Closing the connection pool with :meth:`SessionPool.close()` will wait until
reconfiguration is complete.
See :ref:`Connection Pool Reconfiguration <poolreconfiguration>`.
.. versionadded:: 8.2
.. method:: SessionPool.release(connection, tag=None)
Release the connection back to the pool now, rather than whenever __del__
is called. The connection will be unusable from this point forward; an
Error exception will be raised if any operation is attempted with the
connection. Any cursors or LOBs created by the connection will also be
marked unusable and an Error exception will be raised if any operation is
attempted with them.
Internally, references to the connection are held by cursor objects,
LOB objects, etc. Once all of these references are released, the connection
itself will be released back to the pool automatically. Either control
references to these related objects carefully or explicitly release
connections back to the pool in order to ensure sufficient resources are
available.
If the tag is not None, it is expected to be a string with name=value pairs
like "k1=v1;k2=v2" and will override the value in the property
:attr:`Connection.tag`. If either :attr:`Connection.tag` or the tag
parameter are not None, the connection will be retagged when it is released
back to the pool.
.. attribute:: SessionPool.soda_metadata_cache
This read-write boolean attribute returns whether the SODA metadata cache
is enabled or not. Enabling the cache significantly improves the
performance of methods :meth:`SodaDatabase.createCollection()` (when not
specifying a value for the metadata parameter) and
:meth:`SodaDatabase.openCollection()`. Note that the cache can become out
of date if changes to the metadata of cached collections are made
externally.
.. versionadded:: 8.2
.. attribute:: SessionPool.stmtcachesize
This read-write attribute specifies the size of the statement cache that
will be used for connections obtained from the pool.
See :ref:`Statement Caching <stmtcache>` for more information.
.. versionadded:: 6.0
.. attribute:: SessionPool.timeout
This read-write attribute specifies the time (in seconds) after which idle
sessions will be terminated in order to maintain an optimum number of open
sessions. Note that termination only occurs when the pool is accessed. A
value of 0 means that no idle sessions are terminated.
.. attribute:: SessionPool.tnsentry
This read-only attribute returns the TNS entry of the database to which a
connection has been established.
.. deprecated:: 8.2
Use the attribute :attr:`~SessionPool.dsn` instead.
.. attribute:: SessionPool.username
This read-only attribute returns the name of the user which established the
connection to the database.
.. attribute:: SessionPool.wait_timeout
This read-write attribute specifies the time (in milliseconds) that the
caller should wait for a session to become available in the pool before
returning with an error. This value is only used if the getmode parameter
to :meth:`cx_Oracle.SessionPool()` was the value
:data:`cx_Oracle.SPOOL_ATTRVAL_TIMEDWAIT`.
.. versionadded:: 6.4

706
doc/src/api_manual/soda.rst Normal file
View File

@ -0,0 +1,706 @@
.. _soda:
****
SODA
****
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
`Oracle Database Simple Oracle Document Access (SODA)
<https://docs.oracle.com/en/database/oracle/simple-oracle-document-access>`__
allows documents to be inserted, queried, and retrieved from Oracle Database
using a set of NoSQL-style cx_Oracle methods. By default, documents are JSON
strings. See the :ref:`user manual <sodausermanual>` for examples.
.. _sodarequirements:
-----------------
SODA Requirements
-----------------
To use SODA, the role SODA_APP must be granted to the user. To create
collections, users need the CREATE TABLE privilege. These can be granted by a
DBA:
.. code-block:: sql
SQL> grant soda_app, create table to myuser;
Advanced users who are using Oracle sequences for keys will also need the CREATE
SEQUENCE privilege.
SODA requires Oracle Client 18.3 or higher and Oracle Database 18.1 and higher.
.. note::
If you are using Oracle Database 21c (or later) and create new collections
you need to do one of the following:
- Use Oracle Client libraries 21c (or later).
- Or, explicitly use collection metadata when creating collections and set
the data storage type to BLOB, for example::
{
"keyColumn": {
"name":"ID"
},
"contentColumn": {
"name": "JSON_DOCUMENT",
"sqlType": "BLOB"
},
"versionColumn": {
"name": "VERSION",
"method": "UUID"
},
"lastModifiedColumn": {
"name": "LAST_MODIFIED"
},
"creationTimeColumn": {
"name": "CREATED_ON"
}
}
- Or, set the database initialization parameter `compatible
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-A2E90F08-BC9F-4688-A9D0-4A948DD3F7A9>`__ to 19 or lower.
Otherwise you may get errors such as "ORA-40842: unsupported value JSON in
the metadata for the field sqlType" or "ORA-40659: Data type does not match
the specification in the collection metadata".
.. _sodadb:
--------------------
SODA Database Object
--------------------
.. note::
This object is an extension the DB API. It is returned by the method
:meth:`Connection.getSodaDatabase()`.
.. method:: SodaDatabase.createCollection(name, metadata=None, mapMode=False)
Creates a SODA collection with the given name and returns a new
:ref:`SODA collection object <sodacoll>`. If you try to create a
collection, and a collection with the same name and metadata already
exists, then that existing collection is opened without error.
If metadata is specified, it is expected to be a string containing valid
JSON or a dictionary that will be transformed into a JSON string. This JSON
permits you to specify the configuration of the collection including
storage options; specifying the presence or absence of columns for creation
timestamp, last modified timestamp and version; whether the collection can
store only JSON documents; and methods of key and version generation. The
default metadata creates a collection that only supports JSON documents and
uses system generated keys. See this `collection metadata reference
<https://www.oracle.com/pls/topic/
lookup?ctx=dblatest&id=GUID-49EFF3D3-9FAB-4DA6-BDE2-2650383566A3>`__
for more information.
If the mapMode parameter is set to True, the new collection is mapped to an
existing table instead of creating a table. If a collection is created in
this way, dropping the collection will not drop the existing table either.
.. versionadded:: 7.0
.. method:: SodaDatabase.createDocument(content, key=None, mediaType="application/json")
Creates a :ref:`SODA document <sodadoc>` usable for SODA write operations.
You only need to use this method if your collection requires
client-assigned keys or has non-JSON content; otherwise, you can pass your
content directly to SODA write operations. SodaDocument attributes
'createdOn', 'lastModified' and 'version' will be None.
The content parameter can be a dictionary or list which will be transformed
into a JSON string and then UTF-8 encoded. It can also be a string which
will be UTF-8 encoded or it can be a bytes object which will be stored
unchanged. If a bytes object is provided and the content is expected to be
JSON, note that SODA only supports UTF-8, UTF-16LE and UTF-16BE encodings.
The key parameter should only be supplied if the collection in which the
document is to be placed requires client-assigned keys.
The mediaType parameter should only be supplied if the collection in which
the document is to be placed supports non-JSON documents and the content
for this document is non-JSON. Using a standard MIME type for this value is
recommended but any string will be accepted.
.. versionadded:: 7.0
.. method:: SodaDatabase.getCollectionNames(startName=None, limit=0)
Returns a list of the names of collections in the database that match the
criteria, in alphabetical order.
If the startName parameter is specified, the list of names returned will
start with this value and also contain any names that fall after this value
in alphabetical order.
If the limit parameter is specified and is non-zero, the number of
collection names returned will be limited to this value.
.. versionadded:: 7.0
.. method:: SodaDatabase.openCollection(name)
Opens an existing collection with the given name and returns a new
:ref:`SODA collection object <sodacoll>`. If a collection with that name
does not exist, None is returned.
.. versionadded:: 7.0
.. _sodacoll:
----------------------
SODA Collection Object
----------------------
.. note::
This object is an extension the DB API. It is used to represent SODA
collections and is created by methods
:meth:`SodaDatabase.createCollection()` and
:meth:`SodaDatabase.openCollection()`.
.. method:: SodaCollection.createIndex(spec)
Creates an index on a SODA collection. The spec is expected to be a
dictionary or a JSON-encoded string. See this `overview
<https://www.oracle.com/pls/topic/
lookup?ctx=dblatest&id=GUID-4848E6A0-58A7-44FD-8D6D-A033D0CCF9CB>`__
for information on indexes in SODA.
Note that a commit should be performed before attempting to create an
index.
.. versionadded:: 7.0
.. method:: SodaCollection.drop()
Drops the collection from the database, if it exists. Note that if the
collection was created with mapMode set to True the underlying table will
not be dropped.
A boolean value is returned indicating if the collection was actually
dropped.
.. versionadded:: 7.0
.. method:: SodaCollection.dropIndex(name, force=False)
Drops the index with the specified name, if it exists.
The force parameter, if set to True, can be used to force the dropping of
an index that the underlying Oracle Database domain index doesn't normally
permit. This is only applicable to spatial and JSON search indexes.
See `here <https://www.oracle.com/pls/topic/
lookup?ctx=dblatest&id=GUID-F60F75DF-2866-4F93-BB7F-8FCE64BF67B6>`__
for more information.
A boolean value is returned indicating if the index was actually dropped.
.. versionadded:: 7.0
.. method:: SodaCollection.find()
This method is used to begin an operation that will act upon documents in
the collection. It creates and returns a
:ref:`SodaOperation object <sodaop>` which is used to specify the criteria
and the operation that will be performed on the documents that match that
criteria.
.. versionadded:: 7.0
.. method:: SodaCollection.getDataGuide()
Returns a :ref:`SODA document object <sodadoc>` containing property names,
data types and lengths inferred from the JSON documents in the collection.
It can be useful for exploring the schema of a collection. Note that this
method is only supported for JSON-only collections where a JSON search
index has been created with the 'dataguide' option enabled. If there are
no documents in the collection, None is returned.
.. versionadded:: 7.0
.. method:: SodaCollection.insertMany(docs)
Inserts a list of documents into the collection at one time. Each of the
input documents can be a dictionary or list or an existing :ref:`SODA
document object <sodadoc>`.
.. note::
This method requires Oracle Client 18.5 and higher and is available
only as a preview.
.. versionadded:: 7.2
.. method:: SodaCollection.insertManyAndGet(docs, hint=None)
Similarly to :meth:`~SodaCollection.insertMany()` this method inserts a
list of documents into the collection at one time. The only difference is
that it returns a list of :ref:`SODA Document objects <sodadoc>`. Note that
for performance reasons the returned documents do not contain the content.
The hint parameter, if specified, supplies a hint to the database when
processing the SODA operation. This is expected to be a string in the same
format as a SQL hint but without any comment characters, for example
``hint="MONITOR"``. Pass only the hint ``"MONITOR"`` (turn on monitoring)
or ``"NO_MONITOR"`` (turn off monitoring). See the Oracle Database SQL
Tuning Guide documentation `MONITOR and NO_MONITOR Hints
<https://www.oracle.com/pls/topic/lookup?
ctx=dblatest&id=GUID-19E0F73C-A959-41E4-A168-91E436DEE1F1>`__
and `Monitoring Database Operations
<https://www.oracle.com/pls/topic/lookup?
ctx=dblatest&id=GUID-C941CE9D-97E1-42F8-91ED-4949B2B710BF>`__
for more information.
.. note::
This method requires Oracle Client 18.5 and higher.
.. versionadded:: 7.2
.. versionchanged:: 8.2
The parameter `hint` was added. Use of the hint parameter requires
Oracle Client 21.3 or higher (or Oracle Client 19 from 19.11).
.. method:: SodaCollection.insertOne(doc)
Inserts a given document into the collection. The input document can be a
dictionary or list or an existing :ref:`SODA document object <sodadoc>`.
.. versionadded:: 7.0
.. method:: SodaCollection.insertOneAndGet(doc, hint=None)
Similarly to :meth:`~SodaCollection.insertOne()` this method inserts a
given document into the collection. The only difference is that it
returns a :ref:`SODA Document object <sodadoc>`. Note that for performance
reasons the returned document does not contain the content.
The hint parameter, if specified, supplies a hint to the database when
processing the SODA operation. This is expected to be a string in the same
format as a SQL hint but without any comment characters, for example
``hint="MONITOR"``. Pass only the hint ``"MONITOR"`` (turn on monitoring)
or ``"NO_MONITOR"`` (turn off monitoring). See the Oracle Database SQL
Tuning Guide documentation `MONITOR and NO_MONITOR Hints
<https://www.oracle.com/pls/topic/lookup?
ctx=dblatest&id=GUID-19E0F73C-A959-41E4-A168-91E436DEE1F1>`__
and `Monitoring Database Operations
<https://www.oracle.com/pls/topic/lookup?
ctx=dblatest&id=GUID-C941CE9D-97E1-42F8-91ED-4949B2B710BF>`__
for more information.
.. versionadded:: 7.0
.. versionchanged:: 8.2
The parameter `hint` was added. Use of the hint parameter requires
Oracle Client 21.3 or higher (or Oracle Client 19 from 19.11).
.. attribute:: SodaCollection.metadata
This read-only attribute returns a dictionary containing the metadata that
was used to create the collection. See this `collection metadata reference
<https://www.oracle.com/pls/topic/
lookup?ctx=dblatest&id=GUID-49EFF3D3-9FAB-4DA6-BDE2-2650383566A3>`__
for more information.
.. versionadded:: 7.0
.. attribute:: SodaCollection.name
This read-only attribute returns the name of the collection.
.. versionadded:: 7.0
.. method:: SodaCollection.save(doc)
Saves a document into the collection. This method is equivalent to
:meth:`~SodaCollection.insertOne()` except that if client-assigned keys are
used, and the document with the specified key already exists in the
collection, it will be replaced with the input document.
This method requires Oracle Client 19.9 or higher in addition to the usual
SODA requirements.
.. versionadded:: 8.0
.. method:: SodaCollection.saveAndGet(doc, hint=None)
Saves a document into the collection. This method is equivalent to
:meth:`~SodaCollection.insertOneAndGet()` except that if client-assigned
keys are used, and the document with the specified key already exists in
the collection, it will be replaced with the input document.
The hint parameter, if specified, supplies a hint to the database when
processing the SODA operation. This is expected to be a string in the same
format as a SQL hint but without any comment characters, for example
``hint="MONITOR"``. Pass only the hint ``"MONITOR"`` (turn on monitoring)
or ``"NO_MONITOR"`` (turn off monitoring). See the Oracle Database SQL
Tuning Guide documentation `MONITOR and NO_MONITOR Hints
<https://www.oracle.com/pls/topic/lookup?
ctx=dblatest&id=GUID-19E0F73C-A959-41E4-A168-91E436DEE1F1>`__
and `Monitoring Database Operations
<https://www.oracle.com/pls/topic/lookup?
ctx=dblatest&id=GUID-C941CE9D-97E1-42F8-91ED-4949B2B710BF>`__
for more information.
This method requires Oracle Client 19.9 or higher in addition to the usual
SODA requirements.
.. versionadded:: 8.0
.. versionchanged:: 8.2
The parameter `hint` was added. Use of the hint parameter requires
Oracle Client 21.3 or higher (or Oracle Client 19 from 19.11).
.. method:: SodaCollection.truncate()
Removes all of the documents in the collection, similarly to what is done
for rows in a table by the TRUNCATE TABLE statement.
.. versionadded:: 8.0
.. _sodadoc:
--------------------
SODA Document Object
--------------------
.. note::
This object is an extension the DB API. It is returned by the methods
:meth:`SodaDatabase.createDocument()`,
:meth:`SodaOperation.getDocuments()` and
:meth:`SodaOperation.getOne()` as well as by iterating over
:ref:`SODA document cursors <sodadoccur>`.
.. attribute:: SodaDoc.createdOn
This read-only attribute returns the creation time of the document in
`ISO 8601 <https://www.iso.org/iso-8601-date-and-time-format.html>`__
format. Documents created by :meth:`SodaDatabase.createDocument()` or
fetched from collections where this attribute is not stored will return
None.
.. versionadded:: 7.0
.. method:: SodaDoc.getContent()
Returns the content of the document as a dictionary or list. This method
assumes that the content is application/json and will raise an exception if
this is not the case. If there is no content, however, None will be
returned.
.. versionadded:: 7.0
.. method:: SodaDoc.getContentAsBytes()
Returns the content of the document as a bytes object. If there is no
content, however, None will be returned.
.. versionadded:: 7.0
.. method:: SodaDoc.getContentAsString()
Returns the content of the document as a string. If the document encoding
is not known, UTF-8 will be used. If there is no content, however, None
will be returned.
.. versionadded:: 7.0
.. attribute:: SodaDoc.key
This read-only attribute returns the unique key assigned to this document.
Documents created by :meth:`SodaDatabase.createDocument()` may not have a
value assigned to them and return None.
.. versionadded:: 7.0
.. attribute:: SodaDoc.lastModified
This read-only attribute returns the last modified time of the document in
`ISO 8601 <https://www.iso.org/iso-8601-date-and-time-format.html>`__
format. Documents created by :meth:`SodaDatabase.createDocument()` or
fetched from collections where this attribute is not stored will return
None.
.. versionadded:: 7.0
.. attribute:: SodaDoc.mediaType
This read-only attribute returns the media type assigned to the document.
By convention this is expected to be a MIME type but no checks are
performed on this value. If a value is not specified when calling
:meth:`SodaDatabase.createDocument()` or the document is fetched from a
collection where this component is not stored, the string
"application/json" is returned.
.. versionadded:: 7.0
.. attribute:: SodaDoc.version
This read-only attribute returns the version assigned to this document.
Documents created by :meth:`SodaDatabase.createDocument()` or fetched
from collections where this attribute is not stored will return None.
.. versionadded:: 7.0
.. _sodadoccur:
---------------------------
SODA Document Cursor Object
---------------------------
.. note::
This object is an extension the DB API. It is returned by the method
:meth:`SodaOperation.getCursor()` and implements the iterator protocol.
Each iteration will return a :ref:`SODA document object <sodadoc>`.
.. method:: SodaDocCursor.close()
Close the cursor now, rather than whenever __del__ is called. The cursor
will be unusable from this point forward; an Error exception will be raised
if any operation is attempted with the cursor.
.. versionadded:: 7.0
.. _sodaop:
---------------------
SODA Operation Object
---------------------
.. note::
This object is an extension to the DB API. It represents an operation that
will be performed on all or some of the documents in a SODA collection. It
is created by the method :meth:`SodaCollection.find()`.
.. method:: SodaOperation.count()
Returns a count of the number of documents in the collection that match
the criteria. If :meth:`~SodaOperation.skip()` or
:meth:`~SodaOperation.limit()` were called on this object, an exception is
raised.
.. versionadded:: 7.0
.. method:: SodaOperation.fetchArraySize(value)
This is a tuning method to specify the number of documents that are
internally fetched in batches by calls to :meth:`~SodaOperation.getCursor()`
and :meth:`~SodaOperation.getDocuments()`. It does not affect how many
documents are returned to the application. A value of 0 will use the default
value (100). This method is only available in Oracle Client 19.5 and higher.
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
.. versionadded:: 8.0
.. method:: SodaOperation.filter(value)
Sets a filter specification for complex document queries and ordering of
JSON documents. Filter specifications must be provided as a dictionary or
JSON-encoded string and can include comparisons, regular expressions,
logical and spatial operators, among others. See the
`overview of SODA filter specifications
<https://www.oracle.com/pls/topic/
lookup?ctx=dblatest&id=GUID-CB09C4E3-BBB1-40DC-88A8-8417821B0FBE>`__
for more information.
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
.. versionadded:: 7.0
.. method:: SodaOperation.getCursor()
Returns a :ref:`SODA Document Cursor object <sodadoccur>` that can be used
to iterate over the documents that match the criteria.
.. versionadded:: 7.0
.. method:: SodaOperation.getDocuments()
Returns a list of :ref:`SODA Document objects <sodadoc>` that match the
criteria.
.. versionadded:: 7.0
.. method:: SodaOperation.getOne()
Returns a single :ref:`SODA Document object <sodadoc>` that matches the
criteria. Note that if multiple documents match the criteria only the first
one is returned.
.. versionadded:: 7.0
.. method:: SodaOperation.hint(value)
Specifies a hint that will be provided to the SODA operation when it is
performed. This is expected to be a string in the same format as a SQL hint
but without any comment characters, for example ``hint("MONITOR")``. Pass
only the hint ``"MONITOR"`` (turn on monitoring) or ``"NO_MONITOR"`` (turn
off monitoring). See the Oracle Database SQL Tuning Guide documentation
`MONITOR and NO_MONITOR Hints
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-19E0F73C-A959-41E4-A168-91E436DEE1F1>`__
and `Monitoring Database Operations
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-C941CE9D-97E1-42F8-91ED-4949B2B710BF>`__
for more information.
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
Use of this method requires Oracle Client 21.3 or higher (or Oracle Client
19 from 19.11).
.. versionadded:: 8.2
.. method:: SodaOperation.key(value)
Specifies that the document with the specified key should be returned.
This causes any previous calls made to this method and
:meth:`~SodaOperation.keys()` to be ignored.
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
.. versionadded:: 7.0
.. method:: SodaOperation.keys(seq)
Specifies that documents that match the keys found in the supplied sequence
should be returned. This causes any previous calls made to this method and
:meth:`~SodaOperation.key()` to be ignored.
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
.. versionadded:: 7.0
.. method:: SodaOperation.limit(value)
Specifies that only the specified number of documents should be returned.
This method is only usable for read operations such as
:meth:`~SodaOperation.getCursor()` and
:meth:`~SodaOperation.getDocuments()`. For write operations, any value set
using this method is ignored.
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
.. versionadded:: 7.0
.. method:: SodaOperation.remove()
Removes all of the documents in the collection that match the criteria. The
number of documents that have been removed is returned.
.. versionadded:: 7.0
.. method:: SodaOperation.replaceOne(doc)
Replaces a single document in the collection with the specified document.
The input document can be a dictionary or list or an existing
:ref:`SODA document object <sodadoc>`. A boolean indicating if a document
was replaced or not is returned.
Currently the method :meth:`~SodaOperation.key()` must be called before
this method can be called.
.. versionadded:: 7.0
.. method:: SodaOperation.replaceOneAndGet(doc)
Similarly to :meth:`~SodaOperation.replaceOne()`, this method replaces a
single document in the collection with the specified document. The only
difference is that it returns a :ref:`SODA document object <sodadoc>`.
Note that for performance reasons the returned document does not contain
the content.
.. versionadded:: 7.0
.. method:: SodaOperation.skip(value)
Specifies the number of documents that match the other criteria that will
be skipped. This method is only usable for read operations such as
:meth:`~SodaOperation.getCursor()` and
:meth:`~SodaOperation.getDocuments()`. For write operations, any value set
using this method is ignored.
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
.. versionadded:: 7.0
.. method:: SodaOperation.version(value)
Specifies that documents with the specified version should be returned.
Typically this is used with :meth:`~SodaOperation.key()` to implement
optimistic locking, so that the write operation called later does not
affect a document that someone else has modified.
As a convenience, the SodaOperation object is returned so that further
criteria can be specified by chaining methods together.
.. versionadded:: 7.0

View File

@ -0,0 +1,282 @@
.. _subscrobj:
*******************
Subscription Object
*******************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
.. note::
This object is an extension the DB API.
.. attribute:: Subscription.callback
This read-only attribute returns the callback that was registered when the
subscription was created.
.. attribute:: Subscription.connection
This read-only attribute returns the connection that was used to register
the subscription when it was created.
.. attribute:: Subscription.id
This read-only attribute returns the value of ``REGID`` found in the
database view ``USER_CHANGE_NOTIFICATION_REGS`` or the value of ``REG_ID``
found in the database view ``USER_SUBSCR_REGISTRATIONS``. For AQ
subscriptions, the value is 0.
.. attribute:: Subscription.ip_address
This read-only attribute returns the IP address used for callback
notifications from the database server. If not set during construction,
this value is None.
.. versionadded:: 6.4
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
attribute `ipAddress` was renamed to `ip_address`. The old name will
continue to work for a period of time.
.. attribute:: Subscription.name
This read-only attribute returns the name used to register the subscription
when it was created.
.. versionadded:: 6.4
.. attribute:: Subscription.namespace
This read-only attribute returns the namespace used to register the
subscription when it was created.
.. attribute:: Subscription.operations
This read-only attribute returns the operations that will send
notifications for each table or query that is registered using this
subscription.
.. attribute:: Subscription.port
This read-only attribute returns the port used for callback notifications
from the database server. If not set during construction, this value is
zero.
.. attribute:: Subscription.protocol
This read-only attribute returns the protocol used to register the
subscription when it was created.
.. attribute:: Subscription.qos
This read-only attribute returns the quality of service flags used to
register the subscription when it was created.
.. method:: Subscription.registerquery(statement, [args])
Register the query for subsequent notification when tables referenced by
the query are changed. This behaves similarly to cursor.execute() but only
queries are permitted and the args parameter must be a sequence or
dictionary. If the qos parameter included the flag
cx_Oracle.SUBSCR_QOS_QUERY when the subscription was created, then the ID
for the registered query is returned; otherwise, None is returned.
.. attribute:: Subscription.timeout
This read-only attribute returns the timeout (in seconds) that was
specified when the subscription was created. A value of 0 indicates that
there is no timeout.
.. _msgobjects:
Message Objects
---------------
.. note::
This object is created internally when notification is received and passed
to the callback procedure specified when a subscription is created.
.. attribute:: Message.consumer_name
This read-only attribute returns the name of the consumer which generated
the notification. It will be populated if the subscription was created with
the namespace :data:`cx_Oracle.SUBSCR_NAMESPACE_AQ` and the queue is a
multiple consumer queue.
.. versionadded:: 6.4
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
attribute `consumerName` was renamed to `consumer_name`. The old name
will continue to work for a period of time.
.. attribute:: Message.dbname
This read-only attribute returns the name of the database that generated
the notification.
.. attribute:: Message.queries
This read-only attribute returns a list of message query objects that give
information about query result sets changed for this notification. This
attribute will be None if the qos parameter did not include the flag
:data:`~cx_Oracle.SUBSCR_QOS_QUERY` when the subscription was created.
.. attribute:: Message.queue_name
This read-only attribute returns the name of the queue which generated the
notification. It will only be populated if the subscription was created
with the namespace :data:`cx_Oracle.SUBSCR_NAMESPACE_AQ`.
.. versionadded:: 6.4
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
attribute `queueName` was renamed to `queue_name`. The old name will
continue to work for a period of time.
.. attribute:: Message.registered
This read-only attribute returns whether the subscription which generated
this notification is still registered with the database. The subscription
is automatically deregistered with the database when the subscription
timeout value is reached or when the first notification is sent (when the
quality of service flag :data:`cx_Oracle.SUBSCR_QOS_DEREG_NFY` is used).
.. versionadded:: 6.4
.. attribute:: Message.subscription
This read-only attribute returns the subscription object for which this
notification was generated.
.. attribute:: Message.tables
This read-only attribute returns a list of message table objects that give
information about the tables changed for this notification. This
attribute will be None if the qos parameter included the flag
:data:`~cx_Oracle.SUBSCR_QOS_QUERY` when the subscription was created.
.. attribute:: Message.txid
This read-only attribute returns the id of the transaction that generated
the notification.
.. attribute:: Message.type
This read-only attribute returns the type of message that has been sent.
See the constants section on event types for additional information.
Message Table Objects
---------------------
.. note::
This object is created internally for each table changed when notification
is received and is found in the tables attribute of message objects, and
the tables attribute of message query objects.
.. attribute:: MessageTable.name
This read-only attribute returns the name of the table that was changed.
.. attribute:: MessageTable.operation
This read-only attribute returns the operation that took place on the table
that was changed.
.. attribute:: MessageTable.rows
This read-only attribute returns a list of message row objects that give
information about the rows changed on the table. This value is only filled
in if the qos parameter to the :meth:`Connection.subscribe()` method
included the flag :data:`~cx_Oracle.SUBSCR_QOS_ROWIDS`.
Message Row Objects
-------------------
.. note::
This object is created internally for each row changed on a table when
notification is received and is found in the rows attribute of message
table objects.
.. attribute:: MessageRow.operation
This read-only attribute returns the operation that took place on the row
that was changed.
.. attribute:: MessageRow.rowid
This read-only attribute returns the rowid of the row that was changed.
Message Query Objects
---------------------
.. note::
This object is created internally for each query result set changed when
notification is received and is found in the queries attribute of message
objects.
.. attribute:: MessageQuery.id
This read-only attribute returns the query id of the query for which the
result set changed. The value will match the value returned by
Subscription.registerquery when the related query was registered.
.. attribute:: MessageQuery.operation
This read-only attribute returns the operation that took place on the query
result set that was changed. Valid values for this attribute are
:data:`~cx_Oracle.EVENT_DEREG` and :data:`~cx_Oracle.EVENT_QUERYCHANGE`.
.. attribute:: MessageQuery.tables
This read-only attribute returns a list of message table objects that give
information about the table changes that caused the query result set to
change for this notification.

View File

@ -0,0 +1,114 @@
.. _varobj:
****************
Variable Objects
****************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
.. note::
The DB API definition does not define this object.
.. attribute:: Variable.actual_elements
This read-only attribute returns the actual number of elements in the
variable. This corresponds to the number of elements in a PL/SQL index-by
table for variables that are created using the method
:func:`Cursor.arrayvar()`. For all other variables this value will be
identical to the attribute :attr:`~Variable.numElements`.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
attribute `actualElements` was renamed to `actual_elements`. The old
name will continue to work for a period of time.
.. attribute:: Variable.buffer_size
This read-only attribute returns the size of the buffer allocated for each
element in bytes.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
attribute `bufferSize` was renamed to `buffer_size`. The old
name will continue to work for a period of time.
.. method:: Variable.getvalue([pos=0])
Return the value at the given position in the variable. For variables
created using the method :func:`Cursor.arrayvar()` the value returned will
be a list of each of the values in the PL/SQL index-by table. For variables
bound to DML returning statements, the value returned will also be a list
corresponding to the returned data for the given execution of the statement
(as identified by the pos parameter).
.. attribute:: Variable.inconverter
This read-write attribute specifies the method used to convert data from
Python to the Oracle database. The method signature is converter(value)
and the expected return value is the value to bind to the database. If this
attribute is None, the value is bound directly without any conversion.
.. attribute:: Variable.num_elements
This read-only attribute returns the number of elements allocated in an
array, or the number of scalar items that can be fetched into the variable
or bound to the variable.
.. versionchanged:: 8.2
For consistency and compliance with the PEP 8 naming style, the
attribute `numElements` was renamed to `num_elements`. The old
name will continue to work for a period of time.
.. attribute:: Variable.outconverter
This read-write attribute specifies the method used to convert data from
the Oracle database to Python. The method signature is converter(value)
and the expected return value is the value to return to Python. If this
attribute is None, the value is returned directly without any conversion.
.. method:: Variable.setvalue(pos, value)
Set the value at the given position in the variable.
.. attribute:: Variable.size
This read-only attribute returns the size of the variable. For strings this
value is the size in characters. For all others, this is same value as the
attribute bufferSize.
.. attribute:: Variable.type
This read-only attribute returns the type of the variable. This will be an
:ref:`Oracle Object Type <objecttype>` if the variable binds
Oracle objects; otherwise, it will be one of the
:ref:`database type constants <dbtypes>`.
.. versionchanged:: 8.0
Database type constants are now used when the variable is not used for
binding Oracle objects.
.. attribute:: Variable.values
This read-only attribute returns a copy of the value of all actual
positions in the variable as a list. This is the equivalent of calling
:meth:`~Variable.getvalue()` for each valid position and the length will
correspond to the value of the :attr:`~Variable.actualElements` attribute.

View File

@ -1,217 +0,0 @@
.. _aq:
****************
Advanced Queuing
****************
.. _deqoptions:
---------------
Dequeue Options
---------------
.. note::
This object is an extension to the DB API. It is returned by the
:meth:`Connection.deqoptions()` call and is used in calls to
:meth:`Connection.deq()`.
.. attribute:: DeqOptions.condition
This attribute specifies a boolean expression similar to the where clause
of a SQL query. The boolean expression can include conditions on message
properties, user data properties and PL/SQL or SQL functions. The default is
to have no condition specified.
.. attribute:: DeqOptions.consumername
This attribute specifies the name of the consumer. Only messages matching
the consumer name will be accessed. If the queue is not set up for multiple
consumers this attribute should not be set. The default is to have no
consumer name specified.
.. attribute:: DeqOptions.correlation
This attribute specifies the correlation identifier of the message to be
dequeued. Special pattern-matching characters, such as the percent sign (%)
and the underscore (_), can be used. If multiple messages satisfy the
pattern, the order of dequeuing is indeterminate. The default is to have no
correlation specified.
.. attribute:: DeqOptions.deliverymode
This write-only attribute specifies what types of messages should be
dequeued. It should be one of the values :data:`~cx_Oracle.MSG_PERSISTENT`
(default), :data:`~cx_Oracle.MSG_BUFFERED` or
:data:`~cx_Oracle.MSG_PERSISTENT_OR_BUFFERED`.
.. attribute:: DeqOptions.mode
This attribute specifies the locking behaviour associated with the dequeue
operation. It should be one of the values :data:`~cx_Oracle.DEQ_BROWSE`,
:data:`~cx_Oracle.DEQ_LOCKED`,
:data:`~cx_Oracle.DEQ_REMOVE` (default), or
:data:`~cx_Oracle.DEQ_REMOVE_NODATA`.
.. attribute:: DeqOptions.msgid
This attribute specifies the identifier of the message to be dequeued. The
default is to have no message identifier specified.
.. attribute:: DeqOptions.navigation
This attribute specifies the position of the message that is retrieved. It
should be one of the values :data:`~cx_Oracle.DEQ_FIRST_MSG`,
:data:`~cx_Oracle.DEQ_NEXT_MSG` (default), or
:data:`~cx_Oracle.DEQ_NEXT_TRANSACTION`.
.. attribute:: DeqOptions.transformation
This attribute specifies the name of the transformation that must be applied
after the message is dequeued from the database but before it is returned to
the calling application. The transformation must be created using
dbms_transform. The default is to have no transformation specified.
.. attribute:: DeqOptions.visibility
This attribute specifies the transactional behavior of the enqueue request.
It should be one of the values :data:`~cx_Oracle.ENQ_ON_COMMIT` (default) or
:data:`~cx_Oracle.ENQ_IMMEDIATE`. This attribute is ignored when using the
:data:`~cx_Oracle.DEQ_BROWSE` mode.
.. attribute:: DeqOptions.wait
This attribute specifies the time to wait, in seconds, for a message
matching the search criteria to become available for dequeuing. One of the
values :data:`~cx_Oracle.DEQ_NO_WAIT` or :data:`~cx_Oracle.DEQ_WAIT_FOREVER`
can also be used. The default is :data:`~cx_Oracle.DEQ_WAIT_FOREVER`.
.. _enqoptions:
---------------
Enqueue Options
---------------
.. note::
This object is an extension to the DB API. It is returned by the
:meth:`Connection.enqoptions()` call and is used in calls to
:meth:`Connection.enq()`.
.. attribute:: EnqOptions.deliverymode
This write-only attribute specifies what type of messages should be
enqueued. It should be one of the values :data:`~cx_Oracle.MSG_PERSISTENT`
(default) or :data:`~cx_Oracle.MSG_BUFFERED`.
.. attribute:: EnqOptions.transformation
This attribute specifies the name of the transformation that must be applied
before the message is enqueued into the database. The transformation must
be created using dbms_transform. The default is to have no transformation
specified.
.. attribute:: EnqOptions.visibility
This attribute specifies the transactional behavior of the enqueue request.
It should be one of the values :data:`~cx_Oracle.ENQ_ON_COMMIT` (default) or
:data:`~cx_Oracle.ENQ_IMMEDIATE`.
.. _msgproperties:
------------------
Message Properties
------------------
.. note::
This object is an extension to the DB API. It is returned by the
:meth:`Connection.msgproperties()` call and is used in calls to
:meth:`Connection.deq()` and :meth:`Connection.enq()`.
.. attribute:: MessageProperties.attempts
This read-only attribute specifies the number of attempts that have been
made to dequeue the message.
.. attribute:: MessageProperties.correlation
This attribute specifies the correlation used when the message was enqueued.
.. attribute:: MessageProperties.delay
This attribute specifies the number of seconds to delay an enqueued message.
Any integer is acceptable but the constant :data:`~cx_Oracle.MSG_NO_DELAY`
can also be used indicating that the message is available for immediate
dequeuing.
.. attribute:: MessageProperties.deliverymode
This read-only attribute specifies the type of message that was dequeued. It
will be one of the values :data:`~cx_Oracle.MSG_PERSISTENT` or
:data:`~cx_Oracle.MSG_BUFFERED`.
.. attribute:: MessageProperties.enqtime
This read-only attribute specifies the time that the message was enqueued.
.. attribute:: MessageProperties.exceptionq
This attribute specifies the name of the queue to which the message is
moved if it cannot be processed successfully. Messages are moved if the
number of unsuccessful dequeue attempts has exceeded the maximum number of
retries or if the message has expired. All messages in the exception queue
are in the :data:`~cx_Oracle.MSG_EXPIRED` state. The default value is the
name of the exception queue associated with the queue table.
.. attribute:: MessageProperties.expiration
This attribute specifies, in seconds, how long the message is available for
dequeuing. This attribute is an offset from the delay attribute. Expiration
processing requires the queue monitor to be running. Any integer is accepted
but the constant :data:`~cx_Oracle.MSG_NO_EXPIRATION` can also be used
indicating that the message never expires.
.. attribute:: MessageProperties.msgid
This attribute specifies the id of the message in the last queue that
generated this message.
.. attribute:: MessageProperties.priority
This attribute specifies the priority of the message. A smaller number
indicates a higher priority. The priority can be any integer, including
negative numbers. The default value is zero.
.. attribute:: MessageProperties.state
This read-only attribute specifies the state of the message at the time of
the dequeue. It will be one of the values :data:`~cx_Oracle.MSG_WAITING`,
:data:`~cx_Oracle.MSG_READY`, :data:`~cx_Oracle.MSG_PROCESSED` or
:data:`~cx_Oracle.MSG_EXPIRED`.

View File

@ -28,21 +28,21 @@ templates_path = ['.templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# The root toctree document.
root_doc = master_doc = 'index'
# General substitutions.
project = 'cx_Oracle'
copyright = u'2016, 2017, Oracle and/or its affiliates. All rights reserved. Portions Copyright © 2007-2015, Anthony Tuininga. All rights reserved. Portions Copyright © 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta, Canada. All rights reserved'
copyright = u'2016, 2020, Oracle and/or its affiliates. All rights reserved. Portions Copyright © 2007-2015, Anthony Tuininga. All rights reserved. Portions Copyright © 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta, Canada. All rights reserved'
author = 'Oracle'
# The default replacements for |version| and |release|, also used in various
# other places throughout the built documents.
#
# The short X.Y version.
version = '6.0'
version = '8.3'
# The full version, including alpha/beta/rc tags.
release = '6.0rc1'
release = '8.3.0'
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
@ -108,6 +108,7 @@ html_copy_source = False
# Output file base name for HTML help builder.
htmlhelp_basename = 'cx_Oracledoc'
numfig = True
# Options for LaTeX output
# ------------------------

View File

@ -1,524 +0,0 @@
.. _connobj:
*****************
Connection Object
*****************
.. note::
Any outstanding changes will be rolled back when the connection object
is destroyed or closed.
.. method:: Connection.__enter__()
The entry point for the connection as a context manager, a feature available
in Python 2.5 and higher. It returns itself.
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.__exit__()
The exit point for the connection as a context manager, a feature available
in Python 2.5 and higher. In the event of an exception, the transaction is
rolled back; otherwise, the transaction is committed.
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.action
This write-only attribute sets the action column in the v$session table. It
is a string attribute and cannot be set to None -- use the empty string
instead.
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.autocommit
This read-write attribute determines whether autocommit mode is on or off.
When autocommit mode is on, all statements are committed as soon as they
have completed executing.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.begin([formatId, transactionId, branchId])
Explicitly begin a new transaction. Without parameters, this explicitly
begins a local transaction; otherwise, this explicitly begins a distributed
(global) transaction with the given parameters. See the Oracle documentation
for more details.
Note that in order to make use of global (distributed) transactions, the
:attr:`~Connection.internal_name` and :attr:`~Connection.external_name`
attributes must be set.
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.cancel()
Cancel a long-running transaction.
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.changepassword(oldpassword, newpassword)
Change the password of the logon.
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.client_identifier
This write-only attribute sets the client_identifier column in the
v$session table.
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.clientinfo
This write-only attribute sets the client_info column in the v$session
table.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.close()
Close the connection now, rather than whenever __del__ is called. The
connection will be unusable from this point forward; an Error exception will
be raised if any operation is attempted with the connection. The same
applies to any cursor objects trying to use the connection.
.. method:: Connection.commit()
Commit any pending transactions to the database.
.. attribute:: Connection.current_schema
This read-write attribute sets the current schema attribute for the session.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.cursor()
Return a new :ref:`cursor object <cursorobj>` using the connection.
.. attribute:: Connection.dbop
This write-only attribute sets the database operation that is to be
monitored. This can be viewed in the DBOP_NAME column of the V$SQL_MONITOR
table.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.deq(name, options, msgproperties, payload)
Returns a message id after successfully dequeuing a message. The options
object can be created using :meth:`~Connection.deqoptions()` and the
msgproperties object can be created using
:meth:`~Connection.msgproperties()`. The payload must be an object created
using :meth:`ObjectType.newobject()`.
.. versionadded:: 5.3
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.deqoptions()
Returns an object specifying the options to use when dequeuing messages.
See :ref:`deqoptions` for more information.
.. versionadded:: 5.3
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.dsn
This read-only attribute returns the TNS entry of the database to which a
connection has been established.
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.edition
This read-only attribute gets the session edition and is only available in
Oracle Database 11.2 (both client and server must be at this level or higher
for this to work).
.. versionadded:: 5.3
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.encoding
This read-only attribute returns the IANA character set name of the
character set in use by the Oracle client for regular strings.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.enq(name, options, msgproperties, payload)
Returns a message id after successfully enqueuing a message. The options
object can be created using :meth:`~Connection.enqoptions()` and the
msgproperties object can be created using
:meth:`~Connection.msgproperties()`. The payload must be an object created
using :meth:`ObjectType.newobject()`.
.. versionadded:: 5.3
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.enqoptions()
Returns an object specifying the options to use when enqueuing messages.
See :ref:`enqoptions` for more information.
.. versionadded:: 5.3
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.external_name
This read-write attribute specifies the external name that is used by the
connection when logging distributed transactions.
.. versionadded:: 5.3
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.gettype(name)
Return a :ref:`type object <objecttype>` given its name. This can then be
used to create objects which can be bound to cursors created by this
connection.
.. versionadded:: 5.3
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.handle
This read-only attribute returns the OCI service context handle for the
connection. It is primarily provided to facilitate testing the creation of a
connection using the OCI service context handle.
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.inputtypehandler
This read-write attribute specifies a method called for each value that is
bound to a statement executed on any cursor associated with this connection.
The method signature is handler(cursor, value, arraysize) and the return
value is expected to be a variable object or None in which case a default
variable object will be created. If this attribute is None, the default
behavior will take place for all values bound to statements.
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.internal_name
This read-write attribute specifies the internal name that is used by the
connection when logging distributed transactions.
.. versionadded:: 5.3
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.ltxid
This read-only attribute returns the logical transaction id for the
connection. It is used within Oracle Transaction Guard as a means of
ensuring that transactions are not duplicated. See the Oracle documentation
and the provided sample for more information.
.. versionadded:: 5.3
.. note:
This attribute is an extension to the DB API definition. It is only
available when Oracle Database 12.1 or higher is in use on both the
server and the client.
.. attribute:: Connection.maxBytesPerCharacter
This read-only attribute returns the maximum number of bytes each character
can use for the client character set.
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.module
This write-only attribute sets the module column in the v$session table. The
maximum length for this string is 48 and if you exceed this length you will
get ORA-24960.
.. note:
This attribute is an extension to the DB API definition.
.. method:: Connection.msgproperties()
Returns an object specifying the properties of messages used in advanced
queuing. See :ref:`msgproperties` for more information.
.. versionadded:: 5.3
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.nencoding
This read-only attribute returns the IANA character set name of the national
character set in use by the Oracle client.
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.outputtypehandler
This read-write attribute specifies a method called for each column that is
going to be fetched from any cursor associated with this connection. The
method signature is handler(cursor, name, defaultType, length, precision,
scale) and the return value is expected to be a variable object or None in
which case a default variable object will be created. If this attribute is
None, the default behavior will take place for all columns fetched from
cursors.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.ping()
Ping the server which can be used to test if the connection is still active.
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.prepare()
Prepare the distributed (global) transaction for commit. Return a boolean
indicating if a transaction was actually prepared in order to avoid the
error ORA-24756 (transaction does not exist).
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.rollback()
Rollback any pending transactions.
.. method:: Connection.shutdown([mode])
Shutdown the database. In order to do this the connection must be connected
as :data:`~cx_Oracle.SYSDBA` or :data:`~cx_Oracle.SYSOPER`. Two calls must
be made unless the mode specified is :data:`~cx_Oracle.DBSHUTDOWN_ABORT`. An
example is shown below:
::
import cx_Oracle
connection = cx_Oracle.Connection(mode = cx_Oracle.SYSDBA)
connection.shutdown(mode = cx_Oracle.DBSHUTDOWN_IMMEDIATE)
cursor = connection.cursor()
cursor.execute("alter database close normal")
cursor.execute("alter database dismount")
connection.shutdown(mode = cx_Oracle.DBSHUTDOWN_FINAL)
.. note::
This method is an extension to the DB API definition.
.. method:: Connection.startup(force=False, restrict=False)
Startup the database. This is equivalent to the SQL\*Plus command "startup
nomount". The connection must be connected as :data:`~cx_Oracle.SYSDBA` or
:data:`~cx_Oracle.SYSOPER` with the :data:`~cx_Oracle.PRELIM_AUTH` option
specified for this to work. An example is shown below:
::
import cx_Oracle
connection = cx_Oracle.Connection(
mode = cx_Oracle.SYSDBA | cx_Oracle.PRELIM_AUTH)
connection.startup()
connection = cx_Oracle.connect(mode = cx_Oracle.SYSDBA)
cursor = connection.cursor()
cursor.execute("alter database mount")
cursor.execute("alter database open")
.. note::
This method is an extension to the DB API definition.
.. attribute:: Connection.stmtcachesize
This read-write attribute specifies the size of the statement cache. This
value can make a significant difference in performance (up to 100x) if you
have a small number of statements that you execute repeatedly.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Connection.subscribe(namespace=cx_Oracle.SUBSCR_NAMESPACE_DBCHANGE, protocol=cx_Oracle.SUBSCR_PROTO_OCI, callback=None, timeout=0, operations=OPCODE_ALLOPS, port=0, qos=0)
Return a new :ref:`subscription object <subscrobj>` using the connection.
Currently the namespace and protocol arguments cannot have any other
meaningful values.
The callback is expected to be a callable that accepts a single argument.
A :ref:`message object <msgobjects>` is passed to this callback whenever a
notification is received.
The timeout value specifies that the subscription expires after the given
time in seconds. The default value of 0 indicates that the subscription
never expires.
The operations argument enables filtering of the messages that are sent
(insert, update, delete). The default value will send notifications for all
operations.
The port specifies the listening port for callback notifications from the
database server. If not specified, an unused port will be selected by the
database.
The qos argument specifies quality of service options. It should be one or
more of the following flags, OR'ed together:
:data:`cx_Oracle.SUBSCR_QOS_RELIABLE`,
:data:`cx_Oracle.SUBSCR_QOS_DEREG_NFY`,
:data:`cx_Oracle.SUBSCR_QOS_ROWIDS`,
:data:`cx_Oracle.SUBSCR_QOS_QUERY`,
:data:`cx_Oracle.SUBSCR_QOS_BEST_EFFORT`.
.. note::
This method is an extension to the DB API definition.
.. note::
Do not close the connection before the subscription object is deleted or
the subscription object will not be deregistered in the database. This is
done automatically if connection.close() is never called.
.. attribute:: Connection.tnsentry
This read-only attribute returns the TNS entry of the database to which a
connection has been established.
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.username
This read-only attribute returns the name of the user which established the
connection to the database.
.. note::
This attribute is an extension to the DB API definition.
.. attribute:: Connection.version
This read-only attribute returns the version of the database to which a
connection has been established.
.. note::
This attribute is an extension to the DB API definition.

View File

@ -1,496 +0,0 @@
.. _cursorobj:
*************
Cursor Object
*************
.. attribute:: Cursor.arraysize
This read-write attribute specifies the number of rows to fetch at a time
internally and is the default number of rows to fetch with the
:meth:`~Cursor.fetchmany()` call. It defaults to 100 meaning to fetch 100
rows at a time. Note that this attribute can drastically affect the
performance of a query since it directly affects the number of network round
trips that need to be performed. This is the reason for setting it to 100
instead of the 1 that the DB API recommends.
.. attribute:: Cursor.bindarraysize
This read-write attribute specifies the number of rows to bind at a time and
is used when creating variables via :meth:`~Cursor.setinputsizes()` or
:meth:`~Cursor.var()`. It defaults to 1 meaning to bind a single row at a
time.
.. note::
The DB API definition does not define this attribute.
.. method:: Cursor.arrayvar(dataType, value, [size])
Create an array variable associated with the cursor of the given type and
size and return a :ref:`variable object <varobj>`. The value is either an
integer specifying the number of elements to allocate or it is a list and
the number of elements allocated is drawn from the size of the list. If the
value is a list, the variable is also set with the contents of the list. If
the size is not specified and the type is a string or binary, 4000 bytes
is allocated. This is needed for passing arrays to PL/SQL (in cases where
the list might be empty and the type cannot be determined automatically) or
returning arrays from PL/SQL.
.. note::
The DB API definition does not define this method.
.. method:: Cursor.bindnames()
Return the list of bind variable names bound to the statement. Note that a
statement must have been prepared first.
.. note::
The DB API definition does not define this method.
.. attribute:: Cursor.bindvars
This read-only attribute provides the bind variables used for the last
execute. The value will be either a list or a dictionary depending on
whether binding was done by position or name. Care should be taken when
referencing this attribute. In particular, elements should not be removed.
.. note::
The DB API definition does not define this attribute.
.. method:: Cursor.callfunc(name, returnType, parameters=[], keywordParameters={})
Call a function with the given name. The return type is specified in the
same notation as is required by :meth:`~Cursor.setinputsizes()`. The
sequence of parameters must contain one entry for each argument that the
function expects. Any keyword parameters will be included after the
positional parameters. The result of the call is the return value of the
function.
.. note::
The DB API definition does not define this method.
.. note::
If you intend to call :meth:`Cursor.setinputsizes()` on the cursor prior
to making this call, then note that the first item in the argument list
refers to the return value of the function.
.. method:: Cursor.callproc(name, parameters=[], keywordParameters={})
Call a procedure with the given name. The sequence of parameters must
contain one entry for each argument that the procedure expects. The result
of the call is a modified copy of the input sequence. Input parameters are
left untouched; output and input/output parameters are replaced with
possibly new values. Keyword parameters will be included after the
positional parameters and are not returned as part of the output sequence.
.. note::
The DB API definition does not allow for keyword parameters.
.. method:: Cursor.close()
Close the cursor now, rather than whenever __del__ is called. The cursor
will be unusable from this point forward; an Error exception will be raised
if any operation is attempted with the cursor.
.. attribute:: Cursor.connection
This read-only attribute returns a reference to the connection object on
which the cursor was created.
.. note::
This attribute is an extension to the DB API definition but it is
mentioned in PEP 249 as an optional extension.
.. data:: Cursor.description
This read-only attribute is a sequence of 7-item sequences. Each of these
sequences contains information describing one result column: (name, type,
display_size, internal_size, precision, scale, null_ok). This attribute will
be None for operations that do not return rows or if the cursor has not had
an operation invoked via the :meth:`~Cursor.execute()` method yet.
The type will be one of the type objects defined at the module level.
.. method:: Cursor.execute(statement, [parameters], \*\*keywordParameters)
Execute a statement against the database. Parameters may be passed as a
dictionary or sequence or as keyword arguments. If the arguments are a
dictionary, the values will be bound by name and if the arguments are a
sequence the values will be bound by position. Note that if the values are
bound by position, the order of the variables is from left to right as they
are encountered in the statement and SQL statements are processed
differently than PL/SQL statements. For this reason, it is generally
recommended to bind parameters by name instead of by position.
A reference to the statement will be retained by the cursor. If None or the
same string object is passed in again, the cursor will execute that
statement again without performing a prepare or rebinding and redefining.
This is most effective for algorithms where the same statement is used, but
different parameters are bound to it (many times). Note that parameters that
are not passed in during subsequent executions will retain the value passed
in during the last execution that contained them.
For maximum efficiency when reusing an statement, it is best to use the
:meth:`~Cursor.setinputsizes()` method to specify the parameter types and
sizes ahead of time; in particular, None is assumed to be a string of length
1 so any values that are later bound as numbers or dates will raise a
TypeError exception.
If the statement is a query, the cursor is returned as a convenience to the
caller (so it can be used directly as an iterator over the rows in the
cursor); otherwise, ``None`` is returned.
.. note
::The DB API definition does not define the return value of this method.
.. method:: Cursor.executemany(statement, parameters, batcherrors=False, arraydmlrowcounts=False)
Prepare a statement for execution against a database and then execute it
against all parameter mappings or sequences found in the sequence
parameters. The statement is managed in the same way as the
:meth:`~Cursor.execute()` method manages it.
When true, the batcherrors parameter enables batch error support within
Oracle and ensures that the call succeeds even if an exception takes place
in one or more of the sequence of parameters. The errors can then be
retrieved using :meth:`~Cursor.getbatcherrors()`.
When true, the arraydmlrowcounts parameter enables DML row counts to be
retrieved from Oracle after the method has completed. The row counts can
then be retrieved using :meth:`~Cursor.getarraydmlrowcounts()`.
.. method:: Cursor.executemanyprepared(numIters)
Execute the previously prepared and bound statement the given number of
times. The variables that are bound must have already been set to their
desired value before this call is made. This method was designed for the
case where optimal performance is required as it comes at the expense of
compatibility with the DB API.
.. note::
The DB API definition does not define this method.
.. method:: Cursor.fetchall()
Fetch all (remaining) rows of a query result, returning them as a list of
tuples. An empty list is returned if no more rows are available. Note that
the cursor's arraysize attribute can affect the performance of this
operation, as internally reads from the database are done in batches
corresponding to the arraysize.
An exception is raised if the previous call to :meth:`~Cursor.execute()` did
not produce any result set or no call was issued yet.
.. method:: Cursor.fetchmany([numRows=cursor.arraysize])
Fetch the next set of rows of a query result, returning a list of tuples. An
empty list is returned if no more rows are available. Note that the cursor's
arraysize attribute can affect the performance of this operation.
The number of rows to fetch is specified by the parameter. If it is not
given, the cursor's arrysize attribute determines the number of rows to be
fetched. If the number of rows available to be fetched is fewer than the
amount requested, fewer rows will be returned.
An exception is raised if the previous call to :meth:`~Cursor.execute()` did
not produce any result set or no call was issued yet.
.. method:: Cursor.fetchone()
Fetch the next row of a query result set, returning a single tuple or None
when no more data is available.
An exception is raised if the previous call to :meth:`~Cursor.execute()` did
not produce any result set or no call was issued yet.
.. method:: Cursor.fetchraw([numRows=cursor.arraysize])
Fetch the next set of rows of a query result into the internal buffers of
the defined variables for the cursor. The number of rows actually fetched is
returned. This method was designed for the case where optimal performance
is required as it comes at the expense of compatibility with the DB API.
An exception is raised if the previous call to :meth:`~Cursor.execute()` did
not produce any result set or no call was issued yet.
.. note::
The DB API definition does not define this method.
.. attribute:: Cursor.fetchvars
This read-only attribute specifies the list of variables created for the
last query that was executed on the cursor. Care should be taken when
referencing this attribute. In particular, elements should not be removed.
.. note::
The DB API definition does not define this attribute.
.. method:: Cursor.getarraydmlrowcounts()
Retrieve the DML row counts after a call to :meth:`~Cursor.executemany()`
with arraydmlrowcounts enabled. This will return a list of integers
corresponding to the number of rows affected by the DML statement for each
element of the array passed to :meth:`~Cursor.executemany()`.
.. note::
The DB API definition does not define this method and it is only
available for Oracle 12.1 and higher.
.. method:: Cursor.getbatcherrors()
Retrieve the exceptions that took place after a call to
:meth:`~Cursor.executemany()` with batcherors enabled. This will return a
list of Error objects, one error for each iteration that failed. The offset
can be determined by looking at the offset attribute of the error object.
.. note::
The DB API definition does not define this method.
.. method:: Cursor.getimplicitresults()
Return a list of cursors which correspond to implicit results made available
from a PL/SQL block or procedure without the use of OUT ref cursor
parameters. The PL/SQL block or procedure opens the cursors and marks them
for return to the client using the procedure dbms_sql.return_result. Cursors
returned in this fashion should not be closed. They will be closed
automatically by the parent cursor when it is closed. Closing the parent
cursor will invalidate the cursors returned by this method.
.. versionadded:: 5.3
.. note::
The DB API definition does not define this method and it is only
available for Oracle Database 12.1 (both client and server must be at
this level or higher). It is most like the DB API method nextset(), but
unlike that method (which requires that the next result set overwrite
the current result set), this method returns cursors which can be fetched
independently of each other.
.. attribute:: Cursor.inputtypehandler
This read-write attribute specifies a method called for each value that is
bound to a statement executed on the cursor and overrides the attribute with
the same name on the connection if specified. The method signature is
handler(cursor, value, arraysize) and the return value is expected to be a
variable object or None in which case a default variable object will be
created. If this attribute is None, the value of the attribute with the same
name on the connection is used.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Cursor.__iter__()
Returns the cursor itself to be used as an iterator.
.. note::
This method is an extension to the DB API definition but it is
mentioned in PEP 249 as an optional extension.
.. method:: Cursor.next()
Fetch the next row of a query result set, using the same semantics as the
method fetchone().
.. note::
This method is an extension to the DB API definition but it is
mentioned in PEP 249 as an optional extension.
.. attribute:: Cursor.outputtypehandler
This read-write attribute specifies a method called for each column that is
to be fetched from this cursor. The method signature is
handler(cursor, name, defaultType, length, precision, scale) and the return
value is expected to be a variable object or None in which case a default
variable object will be created. If this attribute is None, the value of
the attribute with the same name on the connection is used instead.
.. note::
This attribute is an extension to the DB API definition.
.. method:: Cursor.parse(statement)
This can be used to parse a statement without actually executing it (this
step is done automatically by Oracle when a statement is executed).
.. note::
The DB API definition does not define this method.
.. note::
You can parse any DML or DDL statement. DDL statements are executed
immediately and an implied commit takes place.
.. method:: Cursor.prepare(statement, [tag])
This can be used before a call to :meth:`~Cursor.execute()` to define the
statement that will be executed. When this is done, the prepare phase will
not be performed when the call to :meth:`~Cursor.execute()` is made with
None or the same string object as the statement. If specified the statement
will be returned to the statement cache with the given tag. See the Oracle
documentation for more information about the statement cache.
.. note::
The DB API definition does not define this method.
.. attribute:: Cursor.rowcount
This read-only attribute specifies the number of rows that have currently
been fetched from the cursor (for select statements) or that have been
affected by the operation (for insert, update and delete statements).
.. attribute:: Cursor.rowfactory
This read-write attribute specifies a method to call for each row that is
retrieved from the database. Ordinarily a tuple is returned for each row but
if this attribute is set, the method is called with the argument tuple that
would normally be returned and the result of the method is returned instead.
.. note::
The DB API definition does not define this attribute.
.. method:: Cursor.scroll(value=0, mode="relative")
Scroll the cursor in the result set to a new position according to the mode.
If mode is "relative" (the default value), the value is taken as an offset
to the current position in the result set. If set to "absolute", value
states an absolute target position. If set to "first", the cursor is
positioned at the first row and if set to "last", the cursor is set to the
last row in the result set.
An error is raised if the mode is "relative" or "absolute" and the scroll
operation would position the cursor outside of the result set.
.. versionadded:: 5.3
.. note::
This method is an extension to the DB API definition but it is
mentioned in PEP 249 as an optional extension.
.. attribute:: Cursor.scrollable
This read-write boolean attribute specifies whether the cursor can be
scrolled or not. By default, cursors are not scrollable, as the server
resources and response times are greater than nonscrollable cursors. This
attribute is checked and the corresponding mode set in Oracle when calling
the method :meth:`~Cursor.execute()`.
.. versionadded:: 5.3
.. note::
The DB API definition does not define this attribute.
.. method:: Cursor.setinputsizes(\*args, \*\*keywordArgs)
This can be used before a call to :meth:`~Cursor.execute()`,
:meth:`~Cursor.callfunc()` or :meth:`~Cursor.callproc()` to predefine memory
areas for the operation's parameters. Each parameter should be a type object
corresponding to the input that will be used or it should be an integer
specifying the maximum length of a string parameter. Use keyword arguments
when binding by name and positional arguments when binding by position. The
singleton None can be used as a parameter when using positional arguments to
indicate that no space should be reserved for that position.
.. note::
If you plan to use :meth:`~Cursor.callfunc()` then be aware that the
first argument in the list refers to the return value of the function.
.. method:: Cursor.setoutputsize(size, [column])
This method does nothing and is retained solely for compatibility with the
DB API. The module automatically allocates as much space as needed to fetch
LONG and LONG RAW columns (or CLOB as string and BLOB as bytes).
.. attribute:: Cursor.statement
This read-only attribute provides the string object that was previously
prepared with :meth:`~Cursor.prepare()` or executed with
:meth:`~Cursor.execute()`.
.. note::
The DB API definition does not define this attribute.
.. method:: Cursor.var(dataType, [size, arraysize, inconverter, outconverter, typename])
Create a variable associated with the cursor of the given type and
characteristics and return a :ref:`variable object <varobj>`. If the size is
not specified and the type is a string or binary, 4000 bytes is allocated;
if the size is not specified and the type is a long string or long binary,
128KB is allocated. If the arraysize is not specified, the bind array size
(usually 1) is used. The inconverter and outconverter specify methods used
for converting values to/from the database. More information can be found in
the section on variable objects.
To create an empty SQL object variable, specify the typename parameter.
This method was designed for use with PL/SQL in/out variables where the
length or type cannot be determined automatically from the Python object
passed in or for use in input and output type handlers defined on cursors
or connections.
.. note::
The DB API definition does not define this method.

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

View File

@ -1,30 +1,70 @@
Welcome to cx_Oracle's documentation!
=====================================
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
**cx_Oracle** is a module that enables access to Oracle Database and conforms
to the Python database API specification. This module is currently tested
against Oracle Client 11.2, 12.1 and 12.2 and Python 2.7, 3.4, 3.5 and 3.6.
against Oracle Client 21c, 19c, 18c, 12c, and 11.2, and Python 3.6, 3.7, 3.8,
3.9 and 3.10. Older versions of cx_Oracle may be used with previous Python
releases.
**cx_Oracle** is distributed under an open-source :ref:`license <license>`
(the BSD license).
(the BSD license). A detailed description of cx_Oracle changes can be found in
the :ref:`release notes <releasenotes>`.
Contents:
.. toctree::
:maxdepth: 2
User Guide
==========
module.rst
connection.rst
cursor.rst
variable.rst
session_pool.rst
subscription.rst
lob.rst
objecttype.rst
aq.rst
releasenotes.rst
license.rst
.. toctree::
:maxdepth: 3
user_guide/introduction.rst
user_guide/installation.rst
user_guide/initialization.rst
user_guide/connection_handling.rst
user_guide/sql_execution.rst
user_guide/plsql_execution.rst
user_guide/bind.rst
user_guide/lob_data.rst
user_guide/json_data_type.rst
user_guide/soda.rst
user_guide/xml_data_type.rst
user_guide/batch_statement.rst
user_guide/exception_handling.rst
user_guide/aq.rst
user_guide/cqn.rst
user_guide/txn_management.rst
user_guide/tuning.rst
user_guide/globalization.rst
user_guide/startup.rst
user_guide/ha.rst
user_guide/tracing_sql.rst
API Manual
==========
.. toctree::
:maxdepth: 3
api_manual/module.rst
api_manual/connection.rst
api_manual/cursor.rst
api_manual/variable.rst
api_manual/session_pool.rst
api_manual/subscription.rst
api_manual/lob.rst
api_manual/object_type.rst
api_manual/aq.rst
api_manual/soda.rst
api_manual/deprecations.rst
Indices and tables
@ -33,4 +73,3 @@ Indices and tables
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

View File

@ -1,3 +1,5 @@
:orphan:
.. _license:
*******
@ -8,7 +10,7 @@ License
.. centered:: **LICENSE AGREEMENT FOR CX_ORACLE**
Copyright |copy| 2016-2017, Oracle and/or its affiliates. All rights reserved.
Copyright |copy| 2016, 2020, Oracle and/or its affiliates. All rights reserved.
Copyright |copy| 2007-2015, Anthony Tuininga. All rights reserved.

View File

@ -1,89 +0,0 @@
.. _lobobj:
***********
LOB Objects
***********
.. note::
This object is an extension the DB API. It is returned whenever Oracle
:data:`CLOB`, :data:`BLOB` and :data:`BFILE` columns are fetched.
.. method:: LOB.close()
Close the LOB. Call this when writing is completed so that the indexes
associated with the LOB can be updated -- but only if :meth:`~LOB.open()`
was called first.
.. method:: LOB.fileexists()
Return a boolean indicating if the file referenced by the BFILE type LOB
exists.
.. method:: LOB.getchunksize()
Return the chunk size for the internal LOB. Reading and writing to the LOB
in chunks of multiples of this size will improve performance.
.. method:: LOB.getfilename()
Return a two-tuple consisting of the directory alias and file name for a
BFILE type LOB.
.. method:: LOB.isopen()
Return a boolean indicating if the LOB has been opened using the method
:meth:`~LOB.open()`.
.. method:: LOB.open()
Open the LOB for writing. This will improve performance when writing to a
LOB in chunks and there are functional or extensible indexes associated with
the LOB. If this method is not called, each write will perform an open
internally followed by a close after the write has been completed.
.. method:: LOB.read([offset=1, [amount]])
Return a portion (or all) of the data in the LOB object. Note that the
amount and offset are in bytes for BLOB and BFILE type LOBs and in UCS-2
code points for CLOB and NCLOB type LOBs. UCS-2 code points are equivalent
to characters for all but supplemental characters. If supplemental
characters are in the LOB, the offset and amount will have to be chosen
carefully to avoid splitting a character.
.. method:: LOB.setfilename(dirAlias, name)
Set the directory alias and name of the BFILE type LOB.
.. method:: LOB.size()
Returns the size of the data in the LOB object. For BLOB and BFILE type LOBs
this is the number of bytes. For CLOB and NCLOB type LOBs this is the number
of UCS-2 code points. UCS-2 code points are equivalent to characters for all
but supplemental characters.
.. method:: LOB.trim([newSize=0])
Trim the LOB to the new size.
.. method:: LOB.write(data, [offset=1])
Write the data to the LOB object at the given offset. The offset is in bytes
for BLOB type LOBs and in UCS-2 code points for CLOB and NCLOB type LOBs.
UCS-2 code points are equivalent to characters for all but supplemental
characters. If supplemental characters are in the LOB, the offset will have
to be chosen carefully to avoid splitting a character. Note that if you want
to make the LOB value smaller, you must use the :meth:`~LOB.trim()`
function.

File diff suppressed because it is too large Load Diff

View File

@ -1,145 +0,0 @@
.. _objecttype:
*******************
Object Type Objects
*******************
.. note::
This object is an extension to the DB API. It is returned by the
:meth:`Connection.gettype()` call and is available as the
:data:`Variable.type` for variables containing Oracle objects.
.. method:: ObjectType([sequence])
The object type may be called directly and serves as an alternative way of
calling :meth:`~ObjectType.newobject()`.
.. attribute:: ObjectType.attributes
This read-only attribute returns a list of the attributes that make up the
object type. Each attribute has a name attribute on it.
.. attribute:: ObjectType.iscollection
This read-only attribute returns a boolean indicating if the object type
refers to a collection or not.
.. attribute:: ObjectType.name
This read-only attribute returns the name of the type.
.. method:: ObjectType.newobject([sequence])
Return a new Oracle object of the given type. This object can then be
modified by setting its attributes and then bound to a cursor for
interaction with Oracle. If the object type refers to a collection, a
sequence may be passed and the collection will be initialized with the
items in that sequence.
.. attribute:: ObjectType.schema
This read-only attribute returns the name of the schema that owns the type.
Object Objects
==============
.. note::
This object is an extension to the DB API. It is returned by the
:meth:`ObjectType.newobject()` call and can be bound to variables of
type :data:`~cx_Oracle.OBJECT`. Attributes can be retrieved and set
directly.
.. method:: Object.append(element)
Append an element to the collection object. If no elements exist in the
collection, this creates an element at index 0; otherwise, it creates an
element immediately following the highest index available in the collection.
.. method:: Object.aslist()
Return a list of each of the collection's elements in index order.
.. method:: Object.copy()
Create a copy of the object and return it.
.. method:: Object.delete(index)
Delete the element at the specified index of the collection. If the
element does not exist or is otherwise invalid, an error is raised. Note
that the indices of the remaining elements in the collection are not
changed. In other words, the delete operation creates holes in the
collection.
.. method:: Object.exists(index)
Return True or False indicating if an element exists in the collection at
the specified index.
.. method:: Object.extend(sequence)
Append all of the elements in the sequence to the collection. This is
the equivalent of performing :meth:`~Object.append()` for each element found
in the sequence.
.. method:: Object.first()
Return the index of the first element in the collection. If the collection
is empty, None is returned.
.. method:: Object.getelement(index)
Return the element at the specified index of the collection. If no element
exists at that index, an exception is raised.
.. method:: Object.last()
Return the index of the last element in the collection. If the collection
is empty, None is returned.
.. method:: Object.next(index)
Return the index of the next element in the collection following the
specified index. If there are no elements in the collection following the
specified index, None is returned.
.. method:: Object.prev(index)
Return the index of the element in the collection preceding the specified
index. If there are no elements in the collection preceding the
specified index, None is returned.
.. method:: Object.setelement(index, value)
Set the value in the collection at the specified index to the given value.
.. method:: Object.size()
Return the number of elements in the collection.
.. method:: Object.trim(num)
Remove the specified number of elements from the end of the collection.

File diff suppressed because it is too large Load Diff

View File

@ -1,140 +0,0 @@
.. _sesspool:
******************
SessionPool Object
******************
.. note::
This object is an extension to the DB API.
.. method:: SessionPool.acquire(user=None, password=None, cclass=None, purity=cx_Oracle.ATTR_PURITY_DEFAULT, tag=None, matchanytag=False)
Acquire a connection from the session pool and return a
:ref:`connection object <connobj>`.
The user and password arguments may not be specified if the pool is
homogeneous. In that case an exception will be raised.
The cclass argument, if specified, should be a string corresponding to the
connection class for database resident connection pooling (DRCP).
The purity argument is expected to be one of
:data:`~cx_Oracle.ATTR_PURITY_NEW`, :data:`~cx_Oracle.ATTR_PURITY_SELF`, or
:data:`~cx_Oracle.ATTR_PURITY_DEFAULT`.
The tag argument, if specified, is expected to be a string and will limit
the sessions that can be returned from a session pool unless the matchanytag
argument is set to True. In that case sessions with the specified tag will
be preferred over others, but if no such sessions are available a session
with a different tag may be returned instead. In any case, untagged sessions
will always be returned if no sessions with the specified tag are available.
Sessions are tagged when they are :meth:`released <SessionPool.release>`
back to the pool.
.. attribute:: SessionPool.busy
This read-only attribute returns the number of sessions currently acquired.
.. method:: SessionPool.drop(connection)
Drop the connection from the pool which is useful if the connection is no
longer usable (such as when the session is killed).
.. attribute:: SessionPool.dsn
This read-only attribute returns the TNS entry of the database to which a
connection has been established.
.. attribute:: SessionPool.homogeneous
This read-write boolean attribute indicates whether the pool is considered
homogeneous or not. If the pool is not homogeneous different authentication
can be used for each connection acquired from the pool.
.. attribute:: SessionPool.increment
This read-only attribute returns the number of sessions that will be
established when additional sessions need to be created.
.. attribute:: SessionPool.max
This read-only attribute returns the maximum number of sessions that the
session pool can control.
.. attribute:: SessionPool.max_lifetime_session
This read-write attribute returns the lifetime (in seconds) for all of the
sessions in the pool. Sessions in the pool are terminated when they have
reached their lifetime. If timeout is also set, the session will be
terminated if either the idle timeout happens or the max lifetime setting
is exceeded. This attribute is only available in Oracle Database 12.1.
.. versionadded:: 5.3
.. attribute:: SessionPool.min
This read-only attribute returns the number of sessions with which the
session pool was created and the minimum number of sessions that will be
controlled by the session pool.
.. attribute:: SessionPool.name
This read-only attribute returns the name assigned to the session pool by
Oracle.
.. attribute:: SessionPool.opened
This read-only attribute returns the number of sessions currently opened by
the session pool.
.. method:: SessionPool.release(connection, tag=None)
Release the connection back to the pool. This will be done automatically as
well if the connection object is garbage collected.
If a tag is specified, the session will be tagged (or retagged) with the
specified value before being returned to the pool.
.. attribute:: SessionPool.stmtcachesize
This read-write attribute specifies the size of the statement cache that
will be used as the starting point for any connections that are created by
the session pool. Once created, the connection's statement cache size can
only be changed by setting the stmtcachesize attribute on the connection
itself.
.. versionadded:: 6.0
.. attribute:: SessionPool.timeout
This read-write attribute indicates the time (in seconds) after which idle
sessions will be terminated in order to maintain an optimum number of open
sessions.
.. attribute:: SessionPool.tnsentry
This read-only attribute returns the TNS entry of the database to which a
connection has been established.
.. attribute:: SessionPool.username
This read-only attribute returns the name of the user which established the
connection to the database.

View File

@ -1,202 +0,0 @@
.. _subscrobj:
*******************
Subscription Object
*******************
.. note::
This object is an extension the DB API.
.. attribute:: Subscription.callback
This read-only attribute returns the callback that was registered when the
subscription was created.
.. attribute:: Subscription.connection
This read-only attribute returns the connection that was used to register
the subscription when it was created.
.. attribute:: Subscription.id
This read-only attribute returns the registration ID returned by the
database when the subscription was created.
.. attribute:: Subscription.namespace
This read-only attribute returns the namespace used to register the
subscription when it was created.
.. attribute:: Subscription.operations
This read-only attribute returns the operations that will send notifications
for each table or query that is registered using this subscription.
.. attribute:: Subscription.port
This read-only attribute returns the port used for callback notifications
from the database server. If not set during construction, this value is
zero.
.. attribute:: Subscription.protocol
This read-only attribute returns the protocol used to register the
subscription when it was created.
.. attribute:: Subscription.qos
This read-only attribute returns the quality of service flags used to
register the subscription when it was created.
.. method:: Subscription.registerquery(statement, [args])
Register the query for subsequent notification when tables referenced by the
query are changed. This behaves similarly to cursor.execute() but only
queries are permitted and the arguments must be a sequence or dictionary.
If the qos parameter included the flag cx_Oracle.SUBSCR_QOS_QUERY when
the subscription was created, then the ID for the registered query is
returned; otherwise, None is returned.
.. attribute:: Subscription.timeout
This read-only attribute returns the timeout (in seconds) that was specified
when the subscription was created. A value of 0 indicates that there is no
timeout.
.. _msgobjects:
Message Objects
===============
.. note::
This object is created internally when notification is received and passed
to the callback procedure specified when a subscription is created.
.. attribute:: Message.dbname
This read-only attribute returns the name of the database that generated the
notification.
.. attribute:: Message.queries
This read-only attribute returns a list of message query objects that give
information about query result sets changed for this notification. This
attribute will be None if the qos parameter did not include the flag
:data:`~cx_Oracle.SUBSCR_QOS_QUERY` when the subscription was created.
.. attribute:: Message.subscription
This read-only attribute returns the subscription object for which this
notification was generated.
.. attribute:: Message.tables
This read-only attribute returns a list of message table objects that give
information about the tables changed for this notification. This
attribute will be None if the qos parameter included the flag
:data:`~cx_Oracle.SUBSCR_QOS_QUERY` when the subscription was created.
.. attribute:: Message.type
This read-only attribute returns the type of message that has been sent.
See the constants section on event types for additional information.
Message Table Objects
=====================
.. note::
This object is created internally for each table changed when notification
is received and is found in the tables attribute of message objects, and
the tables attribute of message query objects.
.. attribute:: MessageTable.name
This read-only attribute returns the name of the table that was changed.
.. attribute:: MessageTable.operation
This read-only attribute returns the operation that took place on the table
that was changed.
.. attribute:: MessageTable.rows
This read-only attribute returns a list of message row objects that give
information about the rows changed on the table. This value is only filled
in if the qos parameter to the :meth:`Connection.subscribe()` method
included the flag :data:`~cx_Oracle.SUBSCR_QOS_ROWIDS`.
Message Row Objects
===================
.. note::
This object is created internally for each row changed on a table when
notification is received and is found in the rows attribute of message table
objects.
.. attribute:: MessageRow.operation
This read-only attribute returns the operation that took place on the row
that was changed.
.. attribute:: MessageRow.rowid
This read-only attribute returns the rowid of the row that was changed.
Message Query Objects
=====================
.. note::
This object is created internally for each query result set changed when
notification is received and is found in the queries attribute of message
objects.
.. attribute:: MessageQuery.id
This read-only attribute returns the query id of the query for which the
result set changed. The value will match the value returned by
Subscription.registerquery when the related query was registered.
.. attribute:: MessageQuery.operation
This read-only attribute returns the operation that took place on the query
result set that was changed. Valid values for this attribute are
:data:`~cx_Oracle.EVENT_DEREG` and :data:`~cx_Oracle.EVENT_QUERYCHANGE`.
.. attribute:: MessageQuery.tables
This read-only attribute returns a list of message table objects that give
information about the table changes that caused the query result set to
change for this notification.

218
doc/src/user_guide/aq.rst Normal file
View File

@ -0,0 +1,218 @@
.. _aqusermanual:
****************************
Oracle Advanced Queuing (AQ)
****************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
`Oracle Advanced Queuing
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=ADQUE>`__ is a highly
configurable and scalable messaging feature of Oracle Database. It has
interfaces in various languages, letting you integrate multiple tools in your
architecture.
cx_Oracle 7.2 introduced an updated interface for Oracle Advanced
Queuing.
There are Advanced Queuing examples in the `GitHub examples
<https://github.com/oracle/python-cx_Oracle/tree/main/samples>`__ directory.
Creating a Queue
================
Before being used, queues need to be created in the database, for example in
SQL*Plus:
.. code-block:: sql
begin
dbms_aqadm.create_queue_table('MY_QUEUE_TABLE', 'RAW');
dbms_aqadm.create_queue('DEMO_RAW_QUEUE', 'MY_QUEUE_TABLE');
dbms_aqadm.start_queue('DEMO_RAW_QUEUE');
end;
/
This examples creates a RAW queue suitable for sending string or raw bytes
messages.
Enqueuing Messages
==================
To send messages in Python you connect and get a :ref:`queue <queue>`. The
queue can be used for enqueuing, dequeuing, or both as needed.
.. code-block:: python
queue = connection.queue("DEMO_RAW_QUEUE")
Now messages can be queued using :meth:`~Queue.enqone()`. To send three
messages:
.. code-block:: python
PAYLOAD_DATA = [
"The first message",
"The second message",
"The third message"
]
for data in PAYLOAD_DATA:
queue.enqone(connection.msgproperties(payload=data))
connection.commit()
Since the queue sending the messages is a RAW queue, the strings in this
example will be internally encoded to bytes using :attr:`Connection.encoding`
before being enqueued.
Dequeuing Messages
==================
Dequeuing is performed similarly. To dequeue a message call the method
:meth:`~Queue.deqone()` as shown. Note that if the message is expected to be a
string, the bytes must be decoded using :attr:`Connection.encoding`.
.. code-block:: python
queue = connection.queue("DEMO_RAW_QUEUE")
msg = queue.deqOne()
connection.commit()
print(msg.payload.decode(connection.encoding))
Using Object Queues
===================
Named Oracle objects can be enqueued and dequeued as well. Given an object
type called ``UDT_BOOK``:
.. code-block:: sql
CREATE OR REPLACE TYPE udt_book AS OBJECT (
Title VARCHAR2(100),
Authors VARCHAR2(100),
Price NUMBER(5,2)
);
/
And a queue that accepts this type:
.. code-block:: sql
begin
dbms_aqadm.create_queue_table('BOOK_QUEUE_TAB', 'UDT_BOOK');
dbms_aqadm.create_queue('DEMO_BOOK_QUEUE', 'BOOK_QUEUE_TAB');
dbms_aqadm.start_queue('DEMO_BOOK_QUEUE');
end;
/
You can queue messages:
.. code-block:: python
book_type = connection.gettype("UDT_BOOK")
queue = connection.queue("DEMO_BOOK_QUEUE", book_type)
book = book_type.newobject()
book.TITLE = "Quick Brown Fox"
book.AUTHORS = "The Dog"
book.PRICE = 123
queue.enqone(connection.msgproperties(payload=book))
connection.commit()
Dequeuing is done like this:
.. code-block:: python
book_type = connection.gettype("UDT_BOOK")
queue = connection.queue("DEMO_BOOK_QUEUE", book_type)
msg = queue.deqone()
connection.commit()
print(msg.payload.TITLE) # will print Quick Brown Fox
Changing Queue and Message Options
==================================
Refer to the :ref:`cx_Oracle AQ API <aq>` and
`Oracle Advanced Queuing documentation
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=ADQUE>`__ for details
on all of the enqueue and dequeue options available.
Enqueue options can be set. For example, to make it so that an explicit
call to :meth:`~Connection.commit()` on the connection is not needed to commit
messages:
.. code-block:: python
queue = connection.queue("DEMO_RAW_QUEUE")
queue.enqoptions.visibility = cx_Oracle.ENQ_IMMEDIATE
Dequeue options can also be set. For example, to specify not to block on
dequeuing if no messages are available:
.. code-block:: python
queue = connection.queue("DEMO_RAW_QUEUE")
queue.deqoptions.wait = cx_Oracle.DEQ_NO_WAIT
Message properties can be set when enqueuing. For example, to set an
expiration of 60 seconds on a message:
.. code-block:: python
queue.enqone(connection.msgproperties(payload="Message", expiration=60))
This means that if no dequeue operation occurs within 60 seconds that the
message will be dropped from the queue.
Bulk Enqueue and Dequeue
========================
The :meth:`~Queue.enqmany()` and :meth:`~Queue.deqmany()` methods can be used
for efficient bulk message handling.
:meth:`~Queue.enqmany()` is similar to :meth:`~Queue.enqone()` but accepts an
array of messages:
.. code-block:: python
messages = [
"The first message",
"The second message",
"The third message",
]
queue = connection.queue("DEMO_RAW_QUEUE")
queue.enqmany(connection.msgproperties(payload=m) for m in messages)
connection.commit()
.. warning::
Calling :meth:`~Queue.enqmany()` in parallel on different connections
acquired from the same pool may fail due to Oracle bug 29928074. Ensure
that this function is not run in parallel, use standalone connections or
connections from different pools, or make multiple calls to
:meth:`~Queue.enqone()` instead. The function :meth:`~Queue.deqmany()` call
is not affected.
To dequeue multiple messages at one time, use :meth:`~Queue.deqmany()`. This
takes an argument specifying the maximum number of messages to dequeue at one
time:
.. code-block:: python
for m in queue.deqmany(10):
print(m.payload.decode(connection.encoding))
Depending on the queue properties and the number of messages available to
dequeue, this code will print out from zero to ten messages.

View File

@ -0,0 +1,301 @@
.. _batchstmnt:
******************************************
Batch Statement Execution and Bulk Loading
******************************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Inserting or updating multiple rows can be performed efficiently with
:meth:`Cursor.executemany()`, making it easy to work with large data sets with
cx_Oracle. This method can significantly outperform repeated calls to
:meth:`Cursor.execute()` by reducing network transfer costs and database overheads.
The :meth:`~Cursor.executemany()` method can also be used to execute PL/SQL
statements multiple times at once.
There are examples in the `GitHub examples
<https://github.com/oracle/python-cx_Oracle/tree/main/samples>`__
directory.
The following tables will be used in the samples that follow:
.. code-block:: sql
create table ParentTable (
ParentId number(9) not null,
Description varchar2(60) not null,
constraint ParentTable_pk primary key (ParentId)
);
create table ChildTable (
ChildId number(9) not null,
ParentId number(9) not null,
Description varchar2(60) not null,
constraint ChildTable_pk primary key (ChildId),
constraint ChildTable_fk foreign key (ParentId)
references ParentTable
);
Batch Execution of SQL
======================
The following example inserts five rows into the table ``ParentTable``:
.. code-block:: python
data = [
(10, 'Parent 10'),
(20, 'Parent 20'),
(30, 'Parent 30'),
(40, 'Parent 40'),
(50, 'Parent 50')
]
cursor.executemany("insert into ParentTable values (:1, :2)", data)
This code requires only one :ref:`round-trip <roundtrips>` from the client to
the database instead of the five round-trips that would be required for
repeated calls to :meth:`~Cursor.execute()`. For very large data sets there
may be an external buffer or network limits to how many rows can be processed,
so repeated calls to ``executemany()`` may be required. The limits are based
on both the number of rows being processed as well as the "size" of each row
that is being processed. Repeated calls to :meth:`~Cursor.executemany()` are
still better than repeated calls to :meth:`~Cursor.execute()`.
Batch Execution of PL/SQL
=========================
PL/SQL functions and procedures and anonymous PL/SQL blocks can also be called
using :meth:`~Cursor.executemany()` in order to improve performance. For
example:
.. code-block:: python
data = [
(10, 'Parent 10'),
(20, 'Parent 20'),
(30, 'Parent 30'),
(40, 'Parent 40'),
(50, 'Parent 50')
]
cursor.executemany("begin mypkg.create_parent(:1, :2); end;", data)
Note that the ``batcherrors`` parameter (discussed below) cannot be used with
PL/SQL block execution.
Handling Data Errors
====================
Large datasets may contain some invalid data. When using batch execution as
discussed above, the entire batch will be discarded if a single error is
detected, potentially eliminating the performance benefits of batch execution
and increasing the complexity of the code required to handle those errors. If
the parameter ``batchErrors`` is set to the value ``True`` when calling
:meth:`~Cursor.executemany()`, however, processing will continue even if there
are data errors in some rows, and the rows containing errors can be examined
afterwards to determine what course the application should take. Note that if
any errors are detected, a transaction will be started but not committed, even
if :attr:`Connection.autocommit` is set to ``True``. After examining the errors
and deciding what to do with them, the application needs to explicitly commit
or roll back the transaction with :meth:`Connection.commit()` or
:meth:`Connection.rollback()`, as needed.
This example shows how data errors can be identified:
.. code-block:: python
data = [
(60, 'Parent 60'),
(70, 'Parent 70'),
(70, 'Parent 70 (duplicate)'),
(80, 'Parent 80'),
(80, 'Parent 80 (duplicate)'),
(90, 'Parent 90')
]
cursor.executemany("insert into ParentTable values (:1, :2)", data,
batcherrors=True)
for error in cursor.getbatcherrors():
print("Error", error.message, "at row offset", error.offset)
The output is::
Error ORA-00001: unique constraint (PYTHONDEMO.PARENTTABLE_PK) violated at row offset 2
Error ORA-00001: unique constraint (PYTHONDEMO.PARENTTABLE_PK) violated at row offset 4
The row offset is the index into the array of the data that could not be
inserted due to errors. The application could choose to commit or rollback the
other rows that were successfully inserted. Alternatively, it could correct
the data for the two invalid rows and attempt to insert them again before
committing.
Identifying Affected Rows
=========================
When executing a DML statement using :meth:`~Cursor.execute()`, the number of
rows affected can be examined by looking at the attribute
:attr:`~Cursor.rowcount`. When performing batch executing with
:meth:`Cursor.executemany()`, however, the row count will return the *total*
number of rows that were affected. If you want to know the total number of rows
affected by each row of data that is bound you must set the parameter
``arraydmlrowcounts`` to ``True``, as shown:
.. code-block:: python
parent_ids_to_delete = [20, 30, 50]
cursor.executemany("delete from ChildTable where ParentId = :1",
[(i,) for i in parent_ids_to_delete],
arraydmlrowcounts=True)
row_counts = cursor.getarraydmlrowcounts()
for parent_id, count in zip(parent_ids_to_delete, row_counts):
print("Parent ID:", parent_id, "deleted", count, "rows.")
Using the data found in the `GitHub samples
<https://github.com/oracle/python-cx_Oracle/tree/main/samples>`__ the output
is as follows::
Parent ID: 20 deleted 3 rows.
Parent ID: 30 deleted 2 rows.
Parent ID: 50 deleted 4 rows.
DML RETURNING
=============
DML statements like INSERT, UPDATE, DELETE and MERGE can return values by using
the DML RETURNING syntax. A bind variable can be created to accept this data.
See :ref:`bind` for more information.
If, instead of merely deleting the rows as shown in the previous example, you
also wanted to know some information about each of the rows that were deleted,
you could use the following code:
.. code-block:: python
parent_ids_to_delete = [20, 30, 50]
child_id_var = cursor.var(int, arraysize=len(parent_ids_to_delete))
cursor.setinputsizes(None, child_id_var)
cursor.executemany("""
delete from ChildTable
where ParentId = :1
returning ChildId into :2""",
[(i,) for i in parent_ids_to_delete])
for ix, parent_id in enumerate(parent_ids_to_delete):
print("Child IDs deleted for parent ID", parent_id, "are",
child_id_var.getvalue(ix))
The output would then be::
Child IDs deleted for parent ID 20 are [1002, 1003, 1004]
Child IDs deleted for parent ID 30 are [1005, 1006]
Child IDs deleted for parent ID 50 are [1012, 1013, 1014, 1015]
Note that the bind variable created to accept the returned data must have an
arraysize large enough to hold data for each row that is processed. Also,
the call to :meth:`Cursor.setinputsizes()` binds this variable immediately so
that it does not have to be passed in each row of data.
Predefining Memory Areas
========================
When multiple rows of data are being processed there is the possibility that
the data is not uniform in type and size. In such cases, cx_Oracle makes some
effort to accommodate such differences. Type determination for each column is
deferred until a value that is not ``None`` is found in the column's data. If
all values in a particular column are ``None``, then cx_Oracle assumes the type
is a string and has a length of 1. cx_Oracle will also adjust the size of the
buffers used to store strings and bytes when a longer value is encountered in
the data. These sorts of operations incur overhead as memory has to be
reallocated and data copied. To eliminate this overhead, using
:meth:`~Cursor.setinputsizes()` tells cx_Oracle about the type and size of the
data that is going to be used.
Consider the following code:
.. code-block:: python
data = [
(110, "Parent 110"),
(2000, "Parent 2000"),
(30000, "Parent 30000"),
(400000, "Parent 400000"),
(5000000, "Parent 5000000")
]
cursor.setinputsizes(None, 20)
cursor.executemany("""
insert into ParentTable (ParentId, Description)
values (:1, :2)""", data)
In this example, without the call to :meth:`~Cursor.setinputsizes()`, cx_Oracle
would perform five allocations of increasing size as it discovered each new,
longer string. However ``cursor.setinputsizes(None, 20)`` tells cx_Oracle that
the maximum size of the strings that will be processed is 20 characters. Since
cx_Oracle allocates memory for each row based on this value, it is best not to
oversize it. The first parameter of ``None`` tells cx_Oracle that its default
processing will be sufficient.
Loading CSV Files into Oracle Database
======================================
The :meth:`Cursor.executemany()` method and Python's `csv module
<https://docs.python.org/3/library/csv.html#module-csv>`__ can be used to
efficiently load CSV (Comma Separated Values) files. For example, consider the
file ``data.csv``::
101,Abel
154,Baker
132,Charlie
199,Delta
. . .
And the schema:
.. code-block:: sql
create table test (id number, name varchar2(25));
Data loading can be done in batches of records since the number of records may
prevent all data being inserted at once:
.. code-block:: python
import cx_Oracle
import csv
# Predefine the memory areas to match the table definition.
# This can improve performance by avoiding memory reallocations.
# Here, one parameter is passed for each of the columns.
# "None" is used for the ID column, since the size of NUMBER isn't
# variable. The "25" matches the maximum expected data size for the
# NAME column
cursor.setinputsizes(None, 25)
# Adjust the number of rows to be inserted in each iteration
# to meet your memory and performance requirements
batch_size = 10000
with open('testsp.csv', 'r') as csv_file:
csv_reader = csv.reader(csv_file, delimiter=',')
sql = "insert into test (id,name) values (:1, :2)"
data = []
for line in csv_reader:
data.append((line[0], line[1]))
if len(data) % batch_size == 0:
cursor.executemany(sql, data)
data = []
if data:
cursor.executemany(sql, data)
con.commit()
Depending on data sizes and business requirements, database changes such as
temporarily disabling redo logging on the table, or disabling indexes may also
be beneficial.

812
doc/src/user_guide/bind.rst Normal file
View File

@ -0,0 +1,812 @@
.. _bind:
********************
Using Bind Variables
********************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
SQL and PL/SQL statements that pass data to and from Oracle Database should use
placeholders in SQL and PL/SQL statements that mark where data is supplied or
returned. These placeholders are referred to as bind variables or bind
parameters A bind variable is a colon-prefixed identifier or numeral. For
example, there are two bind variables (``dept_id`` and ``dept_name``) in this
SQL statement:
.. code-block:: python
sql = """insert into departments (department_id, department_name)
values (:dept_id, :dept_name)"""
cursor.execute(sql, [280, "Facility"])
Using bind variables is important for scalability and security. They help avoid
SQL Injection security problems because data is never treated as part of an
executable statement. Never concatenate or interpolate user data into SQL
statements:
.. code-block:: python
did = 280
dnm = "Facility"
# !! Never do this !!
sql = f"""insert into departments (department_id, department_name)
values ({did}, '{dnm}')"""
cursor.execute(sql)
Bind variables reduce parsing and execution costs when statements are executed
more than once with different data values. If you do not use bind variables,
Oracle must reparse and cache multiple statements. When using bind variables,
Oracle Database may be able to reuse the statement execution plan and context.
Bind variables can be used to substitute data, but cannot be used to substitute
the text of the statement. You cannot, for example, use a bind variable where
a column name or a table name is required. Bind variables also cannot be used
in Data Definition Language (DDL) statements, such as CREATE TABLE or ALTER
statements.
Binding By Name or Position
===========================
Binding can be done by name or by position. A named bind is performed when the
bind variables in a statement are associated with a name. For example:
.. code-block:: python
cursor.execute("""
insert into departments (department_id, department_name)
values (:dept_id, :dept_name)""", dept_id=280,
dept_name="Facility")
# alternatively, the parameters can be passed as a dictionary instead of as
# keyword parameters
data = dict(dept_id=280, dept_name="Facility")
cursor.execute("""
insert into departments (department_id, department_name)
values (:dept_id, :dept_name)""", data)
In the above example, the keyword parameter names or the keys of the dictionary
must match the bind variable names. The advantages of this approach are that
the location of the bind variables in the statement is not important, the
names can be meaningful and the names can be repeated while still only
supplying the value once.
A positional bind is performed when a list of bind values are passed to the
execute() call. For example:
.. code-block:: python
cursor.execute("""
insert into departments (department_id, department_name)
values (:dept_id, :dept_name)""", [280, "Facility"])
Note that for SQL statements, the order of the bind values must exactly match
the order of each bind variable and duplicated names must have their values
repeated. For PL/SQL statements, however, the order of the bind values must
exactly match the order of each **unique** bind variable found in the PL/SQL
block and values should not be repeated. In order to avoid this difference,
binding by name is recommended when bind variable names are repeated.
Bind Direction
==============
The caller can supply data to the database (IN), the database can return
data to the caller (OUT) or the caller can supply initial data to the
database and the database can supply the modified data back to the caller
(IN/OUT). This is known as the bind direction.
The examples shown above have all supplied data to the database and are
therefore classified as IN bind variables. In order to have the database return
data to the caller, a variable must be created. This is done by calling the
method :func:`Cursor.var()`, which identifies the type of data that will be
found in that bind variable and its maximum size among other things.
Here is an example showing how to use OUT binds. It calculates the sum of the
integers 8 and 7 and stores the result in an OUT bind variable of type integer:
.. code-block:: python
out_val = cursor.var(int)
cursor.execute("""
begin
:out_val := :in_bind_var1 + :in_bind_var2;
end;""",
out_val=out_val, in_bind_var1=8, in_bind_var2=7)
print(out_val.getvalue()) # will print 15
If instead of simply getting data back you wish to supply an initial value to
the database, you can set the variable's initial value. This example is the
same as the previous one but it sets the initial value first:
.. code-block:: python
in_out_var = cursor.var(int)
in_out_var.setvalue(0, 25)
cursor.execute("""
begin
:in_out_bind_var := :in_out_bind_var + :in_bind_var1 +
:in_bind_var2;
end;""",
in_out_bind_var=in_out_var, in_bind_var1=8, in_bind_var2=7)
print(in_out_var.getvalue()) # will print 40
When binding data to parameters of PL/SQL procedures that are declared as OUT
parameters, it is worth noting that any value that is set in the bind variable
will be ignored. In addition, any parameters declared as IN/OUT that do not
have a value set will start out with a value of ``null``.
Binding Null Values
===================
In cx_Oracle, null values are represented by the Python singleton ``None``.
For example:
.. code-block:: python
cursor.execute("""
insert into departments (department_id, department_name)
values (:dept_id, :dept_name)""", dept_id=280, dept_name=None)
In this specific case, because the ``DEPARTMENT_NAME`` column is defined as a
``NOT NULL`` column, an error will occur::
cx_Oracle.IntegrityError: ORA-01400: cannot insert NULL into ("HR"."DEPARTMENTS"."DEPARTMENT_NAME")
If this value is bound directly, cx_Oracle assumes it to be a string
(equivalent to a VARCHAR2 column). If you need to use a different Oracle type
you will need to make a call to :func:`Cursor.setinputsizes()` or create a bind
variable with the correct type by calling :func:`Cursor.var()`.
Binding ROWID Values
====================
The pseudo-column ``ROWID`` uniquely identifies a row within a table. In
cx_Oracle, ROWID values are represented as strings. The example below shows
fetching a row and then updating that row by binding its rowid:
.. code-block:: python
# fetch the row
cursor.execute("""
select rowid, manager_id
from departments
where department_id = :dept_id""", dept_id=280)
rowid, manager_id = cursor.fetchone()
# update the row by binding ROWID
cursor.execute("""
update departments set
manager_id = :manager_id
where rowid = :rid""", manager_id=205, rid=rowid)
DML RETURNING Bind Variables
============================
When a RETURNING clause is used with a DML statement like UPDATE,
INSERT, or DELETE, the values are returned to the application through
the use of OUT bind variables. Consider the following example:
.. code-block:: python
# The RETURNING INTO bind variable is a string
dept_name = cursor.var(str)
cursor.execute("""
update departments set
location_id = :loc_id
where department_id = :dept_id
returning department_name into :dept_name""",
loc_id=1700, dept_id=50, dept_name=dept_name)
print(dept_name.getvalue()) # will print ['Shipping']
In the above example, since the WHERE clause matches only one row, the output
contains a single item in the list. If the WHERE clause matched multiple rows,
however, the output would contain as many items as there were rows that were
updated.
No duplicate binds are allowed in a DML statement with a RETURNING clause, and
no duplication is allowed between bind variables in the DML section and the
RETURNING section of the statement.
LOB Bind Variables
==================
Database CLOBs, NCLOBS, BLOBs and BFILEs can be bound with types
:attr:`cx_Oracle.DB_TYPE_CLOB`, :attr:`cx_Oracle.DB_TYPE_NCLOB`,
:attr:`cx_Oracle.DB_TYPE_BLOB` and :attr:`cx_Oracle.DB_TYPE_BFILE`
respectively. LOBs fetched from the database or created with
:meth:`Connection.createlob()` can also be bound.
LOBs may represent Oracle Database persistent LOBs (those stored in tables) or
temporary LOBs (such as those created with :meth:`Connection.createlob()` or
returned by some SQL and PL/SQL operations).
LOBs can be used as IN, OUT or IN/OUT bind variables.
See :ref:`lobdata` for examples.
.. _refcur:
REF CURSOR Bind Variables
=========================
cx_Oracle provides the ability to bind and define PL/SQL REF cursors. As an
example, consider the PL/SQL procedure:
.. code-block:: sql
CREATE OR REPLACE PROCEDURE find_employees (
p_query IN VARCHAR2,
p_results OUT SYS_REFCURSOR
) AS
BEGIN
OPEN p_results FOR
SELECT employee_id, first_name, last_name
FROM employees
WHERE UPPER(first_name || ' ' || last_name || ' ' || email)
LIKE '%' || UPPER(p_query) || '%';
END;
/
A newly opened cursor can be bound to the REF CURSOR parameter, as shown in the
following Python code. After the PL/SQL procedure has been called with
:meth:`Cursor.callproc()`, the cursor can then be fetched just like any other
cursor which had executed a SQL query:
.. code-block:: python
ref_cursor = connection.cursor()
cursor.callproc("find_employees", ['Smith', ref_cursor])
for row in ref_cursor:
print(row)
With Oracle's `sample HR schema
<https://github.com/oracle/db-sample-schemas>`__ there are two
employees with the last name 'Smith' so the result is::
(159, 'Lindsey', 'Smith')
(171, 'William', 'Smith')
To return a REF CURSOR from a PL/SQL function, use ``cx_Oracle.DB_TYPE_CURSOR`` for the
return type of :meth:`Cursor.callfunc()`:
.. code-block:: python
ref_cursor = cursor.callfunc('example_package.f_get_cursor',
cx_Oracle.DB_TYPE_CURSOR)
for row in ref_cursor:
print(row)
See :ref:`tuning` for information on how to tune REF CURSORS.
Binding PL/SQL Collections
==========================
PL/SQL Collections like Associative Arrays can be bound as IN, OUT, and IN/OUT
variables. When binding IN values, an array can be passed directly as shown in
this example, which sums up the lengths of all of the strings in the provided
array. First the PL/SQL package definition:
.. code-block:: sql
create or replace package mypkg as
type udt_StringList is table of varchar2(100) index by binary_integer;
function DemoCollectionIn (
a_Values udt_StringList
) return number;
end;
/
create or replace package body mypkg as
function DemoCollectionIn (
a_Values udt_StringList
) return number is
t_ReturnValue number := 0;
begin
for i in 1..a_Values.count loop
t_ReturnValue := t_ReturnValue + length(a_Values(i));
end loop;
return t_ReturnValue;
end;
end;
/
Then the Python code:
.. code-block:: python
values = ["String One", "String Two", "String Three"]
return_val = cursor.callfunc("mypkg.DemoCollectionIn", int, [values])
print(return_val) # will print 32
In order get values back from the database, a bind variable must be created
using :meth:`Cursor.arrayvar()`. The first parameter to this method is a Python
type that cx_Oracle knows how to handle or one of the cx_Oracle :ref:`types`.
The second parameter is the maximum number of elements that the array can hold
or an array providing the value (and indirectly the maximum length). The final
parameter is optional and only used for strings and bytes. It identifies the
maximum length of the strings and bytes that can be stored in the array. If not
specified, the length defaults to 4000 bytes.
Consider the following PL/SQL package:
.. code-block:: sql
create or replace package mypkg as
type udt_StringList is table of varchar2(100) index by binary_integer;
procedure DemoCollectionOut (
a_NumElements number,
a_Values out nocopy udt_StringList
);
procedure DemoCollectionInOut (
a_Values in out nocopy udt_StringList
);
end;
/
create or replace package body mypkg as
procedure DemoCollectionOut (
a_NumElements number,
a_Values out nocopy udt_StringList
) is
begin
for i in 1..a_NumElements loop
a_Values(i) := 'Demo out element #' || to_char(i);
end loop;
end;
procedure DemoCollectionInOut (
a_Values in out nocopy udt_StringList
) is
begin
for i in 1..a_Values.count loop
a_Values(i) := 'Converted element #' || to_char(i) ||
' originally had length ' || length(a_Values(i));
end loop;
end;
end;
/
The Python code to process an OUT collection would look as follows. Note the
call to :meth:`Cursor.arrayvar()` which creates space for an array of strings.
Each string would permit up to 100 bytes and only 10 strings would be
permitted. If the PL/SQL block exceeds the maximum number of strings allowed
the error ``ORA-06513: PL/SQL: index for PL/SQL table out of range for host
language array`` would be raised.
.. code-block:: python
out_array_var = cursor.arrayvar(str, 10, 100)
cursor.callproc("mypkg.DemoCollectionOut", [5, out_array_var])
for val in out_array_var.getvalue():
print(val)
This would produce the following output::
Demo out element #1
Demo out element #2
Demo out element #3
Demo out element #4
Demo out element #5
The Python code to process an IN/OUT collections is similar. Note the different
call to :meth:`Cursor.arrayvar()` which creates space for an array of strings,
but uses an array to determine both the maximum length of the array and its
initial value.
.. code-block:: python
in_values = ["String One", "String Two", "String Three", "String Four"]
in_out_array_var = cursor.arrayvar(str, in_values)
cursor.callproc("mypkg.DemoCollectionInOut", [in_out_array_var])
for val in in_out_array_var.getvalue():
print(val)
This would produce the following output::
Converted element #1 originally had length 10
Converted element #2 originally had length 10
Converted element #3 originally had length 12
Converted element #4 originally had length 11
If an array variable needs to have an initial value but also needs to allow
for more elements than the initial value contains, the following code can be
used instead:
.. code-block:: python
in_out_array_var = cursor.arrayvar(str, 10, 100)
in_out_array_var.setvalue(0, ["String One", "String Two"])
All of the collections that have been bound in preceding examples have used
contiguous array elements. If an associative array with sparse array elements
is needed, a different approach is required. Consider the following PL/SQL
code:
.. code-block:: sql
create or replace package mypkg as
type udt_StringList is table of varchar2(100) index by binary_integer;
procedure DemoCollectionOut (
a_Value out nocopy udt_StringList
);
end;
/
create or replace package body mypkg as
procedure DemoCollectionOut (
a_Value out nocopy udt_StringList
) is
begin
a_Value(-1048576) := 'First element';
a_Value(-576) := 'Second element';
a_Value(284) := 'Third element';
a_Value(8388608) := 'Fourth element';
end;
end;
/
Note that the collection element indices are separated by large values. The
technique used above would fail with the exception ``ORA-06513: PL/SQL: index
for PL/SQL table out of range for host language array``. The code required to
process this collection looks like this instead:
.. code-block:: python
collection_type = connection.gettype("MYPKG.UDT_STRINGLIST")
collection = collection_type.newobject()
cursor.callproc("mypkg.DemoCollectionOut", [collection])
print(collection.aslist())
This produces the output::
['First element', 'Second element', 'Third element', 'Fourth element']
Note the use of :meth:`Object.aslist()` which returns the collection element
values in index order as a simple Python list. The indices themselves are lost
in this approach. Starting from cx_Oracle 7.0, the associative array can be
turned into a Python dictionary using :meth:`Object.asdict()`. If that value
was printed in the previous example instead, the output would be::
{-1048576: 'First element', -576: 'Second element', 284: 'Third element', 8388608: 'Fourth element'}
If the elements need to be traversed in index order, the methods
:meth:`Object.first()` and :meth:`Object.next()` can be used. The method
:meth:`Object.getelement()` can be used to acquire the element at a particular
index. This is shown in the following code:
.. code-block:: python
ix = collection.first()
while ix is not None:
print(ix, "->", collection.getelement(ix))
ix = collection.next(ix)
This produces the output::
-1048576 -> First element
-576 -> Second element
284 -> Third element
8388608 -> Fourth element
Similarly, the elements can be traversed in reverse index order using the
methods :meth:`Object.last()` and :meth:`Object.prev()` as shown in the
following code:
.. code-block:: python
ix = collection.last()
while ix is not None:
print(ix, "->", collection.getelement(ix))
ix = collection.prev(ix)
This produces the output::
8388608 -> Fourth element
284 -> Third element
-576 -> Second element
-1048576 -> First element
Binding PL/SQL Records
======================
PL/SQL record type objects can also be bound for IN, OUT and IN/OUT
bind variables. For example:
.. code-block:: sql
create or replace package mypkg as
type udt_DemoRecord is record (
NumberValue number,
StringValue varchar2(30),
DateValue date,
BooleanValue boolean
);
procedure DemoRecordsInOut (
a_Value in out nocopy udt_DemoRecord
);
end;
/
create or replace package body mypkg as
procedure DemoRecordsInOut (
a_Value in out nocopy udt_DemoRecord
) is
begin
a_Value.NumberValue := a_Value.NumberValue * 2;
a_Value.StringValue := a_Value.StringValue || ' (Modified)';
a_Value.DateValue := a_Value.DateValue + 5;
a_Value.BooleanValue := not a_Value.BooleanValue;
end;
end;
/
Then this Python code can be used to call the stored procedure which will
update the record:
.. code-block:: python
# create and populate a record
record_type = connection.gettype("MYPKG.UDT_DEMORECORD")
record = record_type.newobject()
record.NUMBERVALUE = 6
record.STRINGVALUE = "Test String"
record.DATEVALUE = datetime.datetime(2016, 5, 28)
record.BOOLEANVALUE = False
# show the original values
print("NUMBERVALUE ->", record.NUMBERVALUE)
print("STRINGVALUE ->", record.STRINGVALUE)
print("DATEVALUE ->", record.DATEVALUE)
print("BOOLEANVALUE ->", record.BOOLEANVALUE)
print()
# call the stored procedure which will modify the record
cursor.callproc("mypkg.DemoRecordsInOut", [record])
# show the modified values
print("NUMBERVALUE ->", record.NUMBERVALUE)
print("STRINGVALUE ->", record.STRINGVALUE)
print("DATEVALUE ->", record.DATEVALUE)
print("BOOLEANVALUE ->", record.BOOLEANVALUE)
This will produce the following output::
NUMBERVALUE -> 6
STRINGVALUE -> Test String
DATEVALUE -> 2016-05-28 00:00:00
BOOLEANVALUE -> False
NUMBERVALUE -> 12
STRINGVALUE -> Test String (Modified)
DATEVALUE -> 2016-06-02 00:00:00
BOOLEANVALUE -> True
Note that when manipulating records, all of the attributes must be set by the
Python program in order to avoid an Oracle Client bug which will result in
unexpected values or the Python application segfaulting.
.. _spatial:
Binding Spatial Datatypes
=========================
Oracle Spatial datatypes objects can be represented by Python objects and their
attribute values can be read and updated. The objects can further be bound and
committed to database. This is similar to the examples above.
An example of fetching SDO_GEOMETRY is in :ref:`Oracle Database Objects and
Collections <fetchobjects>`.
.. _inputtypehandlers:
Changing Bind Data Types using an Input Type Handler
====================================================
Input Type Handlers allow applications to change how data is bound to
statements, or even to enable new types to be bound directly.
An input type handler is enabled by setting the attribute
:attr:`Cursor.inputtypehandler` or :attr:`Connection.inputtypehandler`.
Input type handlers can be combined with variable converters to bind Python
objects seamlessly:
.. code-block:: python
# A standard Python object
class Building:
def __init__(self, build_id, description, num_floors, date_built):
self.building_id = build_id
self.description = description
self.num_floors = num_floors
self.date_built = date_built
building = Building(1, "Skyscraper 1", 5, datetime.date(2001, 5, 24))
# Get Python representation of the Oracle user defined type UDT_BUILDING
obj_type = con.gettype("UDT_BUILDING")
# convert a Python Building object to the Oracle user defined type
# UDT_BUILDING
def building_in_converter(value):
obj = obj_type.newobject()
obj.BUILDINGID = value.building_id
obj.DESCRIPTION = value.description
obj.NUMFLOORS = value.num_floors
obj.DATEBUILT = value.date_built
return obj
def input_type_handler(cursor, value, num_elements):
if isinstance(value, Building):
return cursor.var(obj_type, arraysize=num_elements,
inconverter=building_in_converter)
# With the input type handler, the bound Python object is converted
# to the required Oracle object before being inserted
cur.inputtypehandler = input_type_handler
cur.execute("insert into myTable values (:1, :2)", (1, building))
Binding Multiple Values to a SQL WHERE IN Clause
================================================
To use a SQL IN clause with multiple values, use one bind variable per
value. You cannot directly bind a Python list or dictionary to a single bind
variable. For example, to use two values in an IN clause:
.. code-block:: python
cursor.execute("""
select employee_id, first_name, last_name
from employees
where last_name in (:name1, :name2)""",
name1="Smith", name2="Taylor")
for row in cursor:
print(row)
This gives the output::
(159, 'Lindsey', 'Smith')
(171, 'William', 'Smith')
(176, 'Jonathon', 'Taylor')
(180, 'Winston', 'Taylor')
If the query is executed multiple times with differing numbers of values, a
bind variable should be included for each possible value. When the statement is
executed but the maximum number of values has not been supplied, the value
``None`` can be bound for missing values. For example, if the query above is
used for up to 5 values, the code would be:
.. code-block:: python
cursor.execute("""
select employee_id, first_name, last_name
from employees
where last_name in (:name1, :name2, :name3, :name4, :name5)""",
name1="Smith", name2="Taylor", name3=None, name4=None, name5=None)
for row in cursor:
print(row)
This will produce the same output as the original example. Reusing the same SQL
statement like this for a variable number of values, instead of constructing a
unique statement per set of values, allows best reuse of Oracle Database
resources.
However, if the statement is not going to be re-executed, or the number of
values is only going to be known at runtime, then a SQL statement can be built
up as follows:
.. code-block:: python
bind_values = ["Gates", "Marvin", "Fay"]
bind_names = [":" + str(i + 1) for i in range(len(bind_values))]
sql = "select employee_id, first_name, last_name from employees " + \
"where last_name in (%s)" % (",".join(bind_names))
cursor.execute(sql, bind_values)
for row in cursor:
print(row)
A general solution for a larger number of values is to construct a SQL
statement like::
SELECT ... WHERE col IN ( <something that returns a list of values> )
The best way to do the '<something that returns a list of values>' will depend
on how the data is initially represented and the number of items. You might
look at using CONNECT BY or at using a global temporary table.
One method is to use an Oracle collection with the ``TABLE()`` clause. For
example, if the following type was created::
SQL> CREATE OR REPLACE TYPE name_array AS TABLE OF VARCHAR2(25);
2 /
then the application could do:
.. code-block:: python
type_obj = connection.gettype("NAME_ARRAY")
obj = type_obj.newobject()
obj.extend(["Smith", "Taylor"])
cursor.execute("""select employee_id, first_name, last_name
from employees
where last_name in (select * from table(:1))""",
[obj])
for row in cursor:
print(row)
For efficiency, retain the return value of ``gettype()`` for reuse instead of
making repeated calls to get the type information.
Binding Column and Table Names
==============================
Column and table names cannot be bound in SQL queries. You can concatenate
text to build up a SQL statement, but make sure you use an Allow List or other
means to validate the data in order to avoid SQL Injection security issues:
.. code-block:: python
table_allow_list = ['employees', 'departments']
table_name = get_table_name() # get the table name from user input
if table_name.lower() not in table_allow_list:
raise Exception('Invalid table name')
sql = f'select * from {table_name}'
Binding column names can be done either by using the above method or by using a
CASE statement. The example below demonstrates binding a column name in an
ORDER BY clause:
.. code-block:: python
sql = """
SELECT * FROM departments
ORDER BY
CASE :bindvar
WHEN 'department_id' THEN DEPARTMENT_ID
ELSE MANAGER_ID
END"""
col_name = get_column_name() # Obtain a column name from the user
cursor.execute(sql, [col_name])
Depending on the name provided by the user, the query results will be
ordered either by the column ``DEPARTMENT_ID`` or the column ``MANAGER_ID``.

File diff suppressed because it is too large Load Diff

165
doc/src/user_guide/cqn.rst Normal file
View File

@ -0,0 +1,165 @@
.. _cqn:
***********************************
Continuous Query Notification (CQN)
***********************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
`Continuous Query Notification (CQN)
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-373BAF72-3E63-42FE-8BEA-8A2AEFBF1C35>`__ allows applications to receive
notifications when a table changes, such as when rows have been updated,
regardless of the user or the application that made the change. This can be
useful in many circumstances, such as near real-time monitoring, auditing
applications, or for such purposes as mid-tier cache invalidation. A cache
might hold some values that depend on data in a table. If the data in the
table changes, the cached values must then be updated with the new information.
CQN notification behavior is widely configurable. Choices include specifying
what types of SQL should trigger a notification, whether notifications should
survive database loss, and control over unsubscription. You can also choose
whether notification messages will include ROWIDs of affected rows.
By default, object-level notification (previously known as Database Change
Notification) occurs. With this mode a Python notification method is invoked
whenever a database transaction is committed that changes an object referenced
by a registered query. However if the :meth:`subscription
<Connection.subscribe>` option ``qos`` is :data:`cx_Oracle.SUBSCR_QOS_QUERY`
then query-level notification occurs. In this mode, the database notifies the
application whenever a committed transaction changes the result of a registered
query.
CQN is best used to track infrequent data changes.
Requirements
============
Before using CQN, users must have appropriate permissions:
.. code-block:: sql
GRANT CHANGE NOTIFICATION TO <user-name>;
To use CQN, connections must have ``events`` mode set to ``True``, for
example:
.. code-block:: python
connection = cx_Oracle.connect(user=user, password=password,
dsn="dbhost.example.com/orclpdb1",
events=True)
The default CQN connection mode means the database must be able to connect back
to the application using cx_Oracle in order to receive notification events.
Alternatively, when using Oracle Database and Oracle client libraries 19.4, or
later, subscriptions can set the optional ``client_initiated`` parameter to
``True``, see ``Connection.subscribe()`` below.
The default CQN connection mode typically means that the machine running
cx_Oracle needs a fixed IP address. Note :meth:`Connection.subscribe()` does
not verify that this reverse connection is possible. If there is any problem
sending a notification, then the callback method will not be invoked.
Configuration options can include an IP address and port on which cx_Oracle will
listen for notifications; otherwise, the database chooses values.
Creating a Subscription
=======================
Subscriptions allow Python to receives notifications for events that take place
in the database that match the given parameters.
For example, a basic CQN subscription might be created like:
.. code-block:: python
connection.subscribe(callback=my_callback)
See :meth:`Connection.subscribe()` for details on all of the parameters.
See :ref:`cqn-operation-codes` for the types of operations that are supported.
See :ref:`subscr-qos` for the quality of service values that are supported.
See :ref:`subscr-namespaces` and :ref:`subscr-protocols` for the namespaces and
protocols that are supported.
See :ref:`subscrobj` for more details on the subscription object that is
created.
When using Oracle Database and Oracle client libraries 19.4, or later, the
optional subscription parameter ``client_initiated`` can be set:
.. code-block:: python
connection.subscribe(callback=my_callback, client_initiated=True)
This enables CQN "client initiated" connections which internally use the same
approach as normal cx_Oracle connections to the database, and do not require the
database to be able to connect back to the application. Since client initiated
connections do not need special network configuration they have ease-of-use and
security advantages.
Registering Queries
===================
Once a subscription has been created, one or more queries must be registered by
calling :meth:`Subscription.registerquery()`. Registering a query behaves
similarly to :meth:`Cursor.execute()`, but only queries are permitted and the
``args`` parameter must be a sequence or dictionary.
An example script to receive query notifications when the 'REGIONS' table data
changes is:
.. code-block:: python
def cqn_callback(message):
print("Notification:")
for query in message.queries:
for tab in query.tables:
print("Table:", tab.name)
print("Operation:", tab.operation)
for row in tab.rows:
if row.operation & cx_Oracle.OPCODE_INSERT:
print("INSERT of rowid:", row.rowid)
if row.operation & cx_Oracle.OPCODE_DELETE:
print("DELETE of rowid:", row.rowid)
subscr = connection.subscribe(callback=cqn_callback,
operations=cx_Oracle.OPCODE_INSERT | cx_Oracle.OPCODE_DELETE,
qos=cx_Oracle.SUBSCR_QOS_QUERY | cx_Oracle.SUBSCR_QOS_ROWIDS)
subscr.registerquery("select * from regions")
input("Hit enter to stop CQN demo\n")
Running the above script, shows the initial output as::
Hit enter to stop CQN demo
Use SQL*Plus or another tool to commit a change to the table:
.. code-block:: sql
insert into regions values(120, 'L');
commit;
When the commit is executed, a notification will be received by the callback
which should print something like the following::
Hit enter to stop CQN demo
Notification:
Table: HR.REGIONS
Operation: 2
INSERT of rowid: AAA7EsAAHAAAFS/AAA
See `GitHub Samples
<https://github.com/oracle/python-cx_Oracle/blob/main/samples/cqn.py>`__
for a runnable CQN example.

View File

@ -0,0 +1,47 @@
.. _exception:
******************
Exception Handling
******************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
All exceptions raised by cx_Oracle are inherited from :attr:`cx_Oracle.Error`.
See :ref:`Exceptions <exceptions>` for more details on the various exceptions
defined by cx_Oracle. See the exception handling section in the
:ref:`API manual <exchandling>` for more details on the information available
when an exception is raised.
Applications can catch exceptions as needed. For example, when trying to add a
customer that already exists in the database, the following could be used
to catch the exception:
.. code-block:: python
try:
cursor.execute("insert into customer values (101, 'Customer A')")
except cx_Oracle.IntegrityError:
print("Customer ID already exists")
else:
print("Customer added")
If information about the exception needs to be processed instead, the following
code can be used:
.. code-block:: python
try:
cursor.execute("insert into customer values (101, 'Customer A')")
except cx_Oracle.IntegrityError as e:
error_obj, = e.args
print("Customer ID already exists")
print("Error Code:", error_obj.code)
print("Error Message:", error_obj.message)
else:
print("Customer added")

View File

@ -0,0 +1,164 @@
.. _globalization:
********************************
Character Sets and Globalization
********************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Data fetched from, and sent to, Oracle Database will be mapped between the
database character set and the "Oracle client" character set of the Oracle
Client libraries used by cx_Oracle. If data cannot be correctly mapped between
client and server character sets, then it may be corrupted or queries may fail
with :ref:`"codec can't decode byte" <codecerror>`.
cx_Oracle uses Oracles National Language Support (NLS) to assist in
globalizing applications. As well as character set support, there are many
other features that will be useful in applications. See the
`Database Globalization Support Guide
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=NLSPG>`__.
Setting the Client Character Set
================================
In cx_Oracle 8 the default encoding used for all character data changed to
"UTF-8". This universal encoding is suitable for most applications. If you
have a special need, you can pass the ``encoding`` and ``nencoding`` parameters
to the :meth:`cx_Oracle.connect` and :meth:`cx_Oracle.SessionPool` methods to
specify different Oracle Client character sets. For example:
.. code-block:: python
import cx_Oracle
connection = cx_Oracle.connect(dsn=connect_string, encoding="US-ASCII",
nencoding="UTF-8")
.. note::
In a future release of cx_Oracle, only UTF-8 will be supported.
The ``encoding`` parameter affects character data such as VARCHAR2 and CLOB
columns. The ``nencoding`` parameter affects "National Character" data such as
NVARCHAR2 and NCLOB. If you are not using national character types, then you
can omit ``nencoding``. Both the ``encoding`` and ``nencoding`` parameters are
expected to be one of the `Python standard encodings
<https://docs.python.org/3/library/codecs.html#standard-encodings>`__ such as
``UTF-8``. Do not accidentally use ``UTF8``, which Oracle uses to specify the
older Unicode 3.0 Universal character set, ``CESU-8``. Note that Oracle does
not recognize all of the encodings that Python recognizes. You can see which
encodings are usable in cx_Oracle by issuing this query:
.. code-block:: sql
select distinct utl_i18n.map_charset(value)
from v$nls_valid_values
where parameter = 'CHARACTERSET'
and utl_i18n.map_charset(value) is not null
order by 1
.. note::
From cx_Oracle 8, it is no longer possible to change the character set
using the ``NLS_LANG`` environment variable. The character set component
of that variable is ignored. The language and territory components of
``NLS_LANG`` are still respected by the Oracle Client libraries.
Character Set Example
---------------------
The script below tries to display data containing a Euro symbol from the
database.
.. code-block:: python
connection = cx_Oracle.connect(user=user, password=password,
dsn="dbhost.example.com/orclpdb1",
encoding="US-ASCII")
cursor = connection.cursor()
for row in cursor.execute("select nvarchar2_column from nchar_test"):
print(row)
Because the '€' symbol is not supported by the ``US-ASCII`` character set, all
'€' characters are replaced by '¿' in the cx_Oracle output::
('¿',)
When the ``encoding`` parameter is removed (or set to "UTF-8") during
connection:
.. code-block:: python
connection = cx_Oracle.connect(user=user, password=password,
dsn="dbhost.example.com/orclpdb1")
Then the output displays the Euro symbol as desired::
('€',)
.. _findingcharset:
Finding the Database and Client Character Set
---------------------------------------------
To find the database character set, execute the query:
.. code-block:: sql
SELECT value AS db_charset
FROM nls_database_parameters
WHERE parameter = 'NLS_CHARACTERSET';
To find the database 'national character set' used for NCHAR and related types,
execute the query:
.. code-block:: sql
SELECT value AS db_ncharset
FROM nls_database_parameters
WHERE parameter = 'NLS_NCHAR_CHARACTERSET';
To find the current "client" character set used by cx_Oracle, execute the
query:
.. code-block:: sql
SELECT DISTINCT client_charset AS client_charset
FROM v$session_connect_info
WHERE sid = SYS_CONTEXT('USERENV', 'SID');
If these character sets do not match, characters transferred over Oracle Net
will be mapped from one character set to another. This may impact performance
and may result in invalid data.
Setting the Oracle Client Locale
================================
You can use the ``NLS_LANG`` environment variable to set the language and
territory used by the Oracle Client libraries. For example, on Linux you could
set::
export NLS_LANG=JAPANESE_JAPAN
The language ("JAPANESE" in this example) specifies conventions such as the
language used for Oracle Database messages, sorting, day names, and month
names. The territory ("JAPAN") specifies conventions such as the default date,
monetary, and numeric formats. If the language is not specified, then the value
defaults to AMERICAN. If the territory is not specified, then the value is
derived from the language value. See `Choosing a Locale with the NLS_LANG
Environment Variable
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-86A29834-AE29-4BA5-8A78-E19C168B690A>`__
If the ``NLS_LANG`` environment variable is set in the application with
``os.environ['NLS_LANG']``, it must be set before any connection pool is
created, or before any standalone connections are created.
Other Oracle globalization variables, such as ``NLS_DATE_FORMAT`` can also be
set to change the behavior of cx_Oracle, see `Setting NLS Parameters
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-6475CA50-6476-4559-AD87-35D431276B20>`__.

223
doc/src/user_guide/ha.rst Normal file
View File

@ -0,0 +1,223 @@
.. _highavailability:
********************************
High Availability with cx_Oracle
********************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Applications can utilize many features for high availability (HA) during planned and
unplanned outages in order to:
* Reduce application downtime
* Eliminate compromises between high availability and performance
* Increase operational productivity
.. _harecommend:
General HA Recommendations
--------------------------
General recommendations for creating highly available cx_Oracle programs are:
* Tune operating system and Oracle Network parameters to avoid long TCP timeouts, to prevent firewalls killing connections, and to avoid connection storms.
* Implement application error handling and recovery.
* Use the most recent version of the Oracle client libraries. New versions have improvements to features such as dead database server detection, and make it easier to set connection options.
* Use the most recent version of Oracle Database. New database versions introduce, and enhance, features such as Application Continuity (AC) and Transparent Application Continuity (TAC).
* Utilize Oracle Database technologies such as `RAC <https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=RACAD>`__ or standby databases.
* Configure database services to emit :ref:`FAN <fan>` events.
* Use a :ref:`connection pool <connpool>`, because pools can handle database events and take proactive and corrective action for draining, run time load balancing, and fail over. Set the minimum and maximum pool sizes to the same values to avoid connection storms. Remove resource manager or user profiles that prematurely close sessions.
* Test all scenarios thoroughly.
.. _hanetwork:
Network Configuration
---------------------
The operating system TCP and :ref:`Oracle Net configuration <optnetfiles>`
should be configured for performance and availability.
Options such as `SQLNET.OUTBOUND_CONNECT_TIMEOUT
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-0857C817-675F-4CF0-BFBB-C3667F119176>`__,
`SQLNET.RECV_TIMEOUT
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-4A19D81A-75F0-448E-B271-24E5187B5909>`__
and `SQLNET.SEND_TIMEOUT
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-48547756-9C0B-4D14-BE85-E7ADDD1A3A66>`__
can be explored.
`Oracle Net Services
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=NETRF>`__ options may
also be useful for high availability and performance tuning. For example the
database's `listener.ora` file can have `RATE_LIMIT
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-F302BF91-64F2-4CE8-A3C7-9FDB5BA6DCF8>`__
and `QUEUESIZE
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-FF87387C-1779-4CC3-932A-79BB01391C28>`__
parameters that can help handle connection storms.
With Oracle Client 19c, `EXPIRE_TIME
<https://docs.oracle.com/en/database/oracle/oracle-database/20/netrf/local-naming-parameters-in-tns-ora-file.html#GUID-6140611A-83FC-4C9C-B31F-A41FC2A5B12D>`__
can be used in :ref:`tnsnames.ora <optnetfiles>` connect descriptors to prevent
firewalls from terminating idle connections and to adjust keepalive timeouts.
The general recommendation for ``EXPIRE_TIME`` is to use a value that is
slightly less than half of the termination period. In older versions of Oracle
Client, a ``tnsnames.ora`` connect descriptor option `ENABLE=BROKEN
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-7A18022A-E40D-4880-B3CE-7EE9864756CA>`_
can be used instead of ``EXPIRE_TIME``. These settings can also aid detection
of a terminated remote database server.
When cx_Oracle uses :ref:`Oracle Client libraries 19c <archfig>`, then the
:ref:`Easy Connect Plus syntax <easyconnect>` syntax enables some options to be
used without needing a ``sqlnet.ora`` file. For example, if your firewall times
out every 4 minutes, and you cannot alter the firewall settings, then you may
decide to use ``EXPIRE_TIME`` in your connect string to send a probe every 2
minutes to the database to keep connections 'alive'::
connection = cx_Oracle.connect("hr", userpwd, "dbhost.example.com/orclpdb1?expire_time=2")
.. _fan:
Fast Application Notification (FAN)
-----------------------------------
Users of `Oracle Database FAN
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-F3FBE48B-468B-4393-8B0C-D5C8E0E4374D>`__
must connect to a FAN-enabled database service. The application should have
``events`` set to True when connecting. This value can also be changed via
:ref:`Oracle Client Configuration <optclientfiles>`.
FAN support is useful for planned and unplanned outages. It provides immediate
notification to cx_Oracle following outages related to the database, computers,
and networks. Without FAN, cx_Oracle can hang until a TCP timeout occurs and an
error is returned, which might be several minutes.
FAN allows cx_Oracle to provide high availability features without the
application being aware of an outage. Unused, idle connections in a
:ref:`connection pool <connpool>` will be automatically cleaned up. A future
:meth:`SessionPool.acquire()` call will establish a fresh connection to a
surviving database instance without the application being aware of any service
disruption.
To handle errors that affect active connections, you can add application logic
to re-connect (this will connect to a surviving database instance) and replay
application logic without having to return an error to the application user.
FAN benefits users of Oracle Database's clustering technology `Oracle RAC
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-D04AA2A7-2E68-4C5C-BD6E-36C62427B98E>`__
because connections to surviving database instances can be immediately made.
Users of Oracle's Data Guard with a broker will get FAN events generated when
the standby database goes online. Standalone databases will send FAN events
when the database restarts.
For a more information on FAN see the `white paper on Fast Application
Notification
<https://www.oracle.com/technetwork/database/options/clustering/applicationcontinuity/learnmore/fastapplicationnotification12c-2538999.pdf>`__.
.. _appcont:
Application Continuity (AC)
---------------------------
Oracle Application Continuity and Transparent Application Continuity are Oracle
Database technologies that record application interaction with the database and,
in the event of a database instance outage, attempt to replay the interaction on
a surviving database instance. If successful, users will be unaware of any
database issue. AC and TAC are best suited for OLTP applications.
When AC or TAC are configured on the database service, they are transparently
available to cx_Oracle applications.
You must thoroughly test your application because not all lower level calls in
the cx_Oracle implementation can be replayed.
See `OCI and Application Continuity
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-A8DD9422-2F82-42A9-9555-134296416E8F>`__
for more information.
.. _tg:
Transaction Guard
-----------------
cx_Oracle supports `Transaction Guard
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-A675AF7B-6FF0-460D-A6E6-C15E7C328C8F>`__ which enables Python
application to verify the success or failure of the last transaction in the
event of an unplanned outage. This feature is available when both client and
database are 12.1 or higher.
Using Transaction Guard helps to:
* Preserve the commit outcome
* Ensure a known outcome for every transaction
See `Oracle Database Development Guide
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-6C5880E5-C45F-4858-A069-A28BB25FD1DB>`__ for more information about
using Transaction Guard.
When an error occurs during commit, the Python application can acquire the
logical transaction id (``ltxid``) from the connection and then call a
procedure to determine the outcome of the commit for this logical transaction
id.
Follow the steps below to use the Transaction Guard feature in Python:
1. Grant execute privileges to the database users who will be checking the
outcome of the commit. Login as SYSDBA and run the following command:
.. code-block:: sql
GRANT EXECUTE ON DBMS_APP_CONT TO <username>;
2. Create a new service by executing the following PL/SQL block as SYSDBA.
Replace the ``<service-name>``, ``<network-name>`` and
``<retention-value>`` values with suitable values. It is important that the
``COMMIT_OUTCOME`` parameter be set to true for Transaction Guard to
function properly.
.. code-block:: sql
DECLARE
t_Params dbms_service.svc_parameter_array;
BEGIN
t_Params('COMMIT_OUTCOME') := 'true';
t_Params('RETENTION_TIMEOUT') := <retention-value>;
DBMS_SERVICE.CREATE_SERVICE('<service-name>', '<network-name>', t_Params);
END;
/
3. Start the service by executing the following PL/SQL block as SYSDBA:
.. code-block:: sql
BEGIN
DBMS_SERVICE.start_service('<service-name>');
END;
/
Ensure the service is running by examining the output of the following query:
.. code-block:: sql
SELECT name, network_name FROM V$ACTIVE_SERVICES ORDER BY 1;
**Python Application code requirements to use Transaction Guard**
In the Python application code:
* Use the connection attribute :attr:`~Connection.ltxid` to determine the
logical transaction id.
* Call the ``DBMS_APP_CONT.GET_LTXID_OUTCOME`` PL/SQL procedure with the
logical transaction id acquired from the connection attribute. This returns
a boolean value indicating if the last transaction was committed and whether
the last call was completed successfully or not.
See the `Transaction Guard Sample
<https://github.com/oracle/python-cx_Oracle/blob/main/
samples/transaction_guard.py>`__ for further details.

View File

@ -0,0 +1,415 @@
.. _initialization:
**************************
cx_Oracle 8 Initialization
**************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
The cx_Oracle module loads Oracle Client libraries which communicate over
Oracle Net to an existing database. The Oracle Client libraries need to be
installed separately. See :ref:`installation`. Oracle Net is not a separate
product: it is how the Oracle Client and Oracle Database communicate.
.. figure:: /images/cx_Oracle_arch.png
cx_Oracle Architecture
.. _libinit:
Locating the Oracle Client Libraries
====================================
cx_Oracle dynamically loads the Oracle Client libraries using a search
heuristic. Only the first set of libraries found are loaded. The libraries
can be in an installation of Oracle Instant Client, in a full Oracle Client
installation, or in an Oracle Database installation (if Python is running on
the same machine as the database). The versions of Oracle Client and Oracle
Database do not have to be the same. For certified configurations see Oracle
Support's `Doc ID 207303.1
<https://support.oracle.com/epmos/faces/DocumentDisplay?id=207303.1>`__.
.. _wininit:
* On Windows, cx_Oracle looks for the Oracle Client libraries as follows:
- In the ``lib_dir`` directory specified in a call to
:meth:`cx_Oracle.init_oracle_client()`. This directory should contain
the libraries from an unzipped Instant Client 'Basic' or 'Basic Light'
package. If you pass the library directory from a full client or
database installation, such as Oracle Database "XE" Express Edition, then
you will need to have previously set your environment to use that
software installation, otherwise files such as message files will not be
located. On Windows when the path contains backslashes, use a 'raw'
string like ``lib_dir=r"C:\instantclient_19_6"``. If the Oracle Client
libraries cannot be loaded from ``lib_dir``, then an exception is raised.
- If ``lib_dir`` was not specified, then Oracle Client libraries are looked
for in the directory where the cx_Oracle binary module is installed.
This directory should contain the libraries from an unzipped Instant
Client 'Basic' or 'Basic Light' package. If the libraries are not found,
no exception is raised and the search continues, see next bullet point.
- In the directories on the system library search path, e.g. the ``PATH``
environment variable. If the Oracle Client libraries cannot be loaded,
then an exception is raised.
.. _macinit:
* On macOS, cx_Oracle looks for the Oracle Client libraries as follows:
- In the ``lib_dir`` directory specified in a call to
:meth:`cx_Oracle.init_oracle_client()`. This directory should contain
the libraries from an unzipped Instant Client 'Basic' or 'Basic Light'
package. If the Oracle Client libraries cannot be loaded from
``lib_dir``, then an exception is raised.
- If ``lib_dir`` was not specified, then Oracle Client libraries are looked
for in the directory where the cx_Oracle binary module is. This directory
should contain the libraries from an unzipped Instant Client 'Basic' or
'Basic Light' package. For example if
``/Users/your_username/Library/Python/3.8/lib/python/site-packages``
contains ``cx_Oracle.cpython-38-darwin.so``, then you could run ``ln -s
~/instantclient_19_3/libclntsh.dylib
~/Library/Python/3.8/lib/python/site-packages``. If the libraries are not
found, no exception is raised and the search continues, see next bullet
point.
- In the directories on the system library search path, e.g. ``~/lib/`` and
``/usr/local/lib``, or in ``$DYLD_LIBRARY_PATH``. These paths will vary
with macOS version and Python version. Any value in
``DYLD_LIBRARY_PATH`` will not propagate to a sub-shell. If the Oracle
Client libraries cannot be loaded, then an exception is raised.
.. _linuxinit:
* On Linux and related platforms, cx_Oracle looks for the Oracle Client
libraries as follows:
- In the ``lib_dir`` directory specified in a call to
:meth:`cx_Oracle.init_oracle_client()`.
**Note this is only useful to force immediate loading of the libraries
because on Linux and related platforms the libraries must always be in the
system library search path**.
The ``lib_dir`` directory should contain the libraries from an unzipped
Instant Client 'Basic' or 'Basic Light' package. If you pass the library
directory from a full client or database installation, such as Oracle
Database "XE" Express Edition then you will need to have previously set
the ``ORACLE_HOME`` environment variable. If the Oracle Client libraries
cannot be loaded from ``lib_dir``, then an exception is raised.
- If ``lib_dir`` was not specified, then Oracle Client libraries are looked
for in the operating system library search path, such as configured with
``ldconfig`` or set in the environment variable ``LD_LIBRARY_PATH``. On
some UNIX platforms an OS specific equivalent, such as ``LIBPATH`` or
``SHLIB_PATH`` is used instead of ``LD_LIBRARY_PATH``. If the libraries
are not found, no exception is raised and the search continues, see next
bullet point.
- In ``$ORACLE_HOME/lib``. Note the environment variable ``ORACLE_HOME``
should only ever be set when you have a full database installation or
full client installation. It should not be set if you are using Oracle
Instant Client. The ``ORACLE_HOME`` variable, and other necessary
variables, should be set before starting Python. See :ref:`envset`. If
the Oracle Client libraries cannot be loaded, then an exception is
raised.
If you call :meth:`cx_Oracle.init_oracle_client()` with a ``lib_dir``
parameter, the Oracle Client libraries are loaded immediately from that
directory. If you call :meth:`cx_Oracle.init_oracle_client()` but do *not* set
the ``lib_dir`` parameter, the Oracle Client libraries are loaded immediately
using the search heuristic above. If you do not call
:meth:`cx_Oracle.init_oracle_client()`, then the libraries are loaded using the
search heuristic when the first cx_Oracle function that depends on the
libraries is called, for example when a connection pool is created. If there
is a problem loading the libraries, then an exception is raised.
Make sure the Python process has directory and file access permissions for the
Oracle Client libraries. On Linux ensure a ``libclntsh.so`` file exists. On
macOS ensure a ``libclntsh.dylib`` file exists. cx_Oracle will not directly
load ``libclntsh.*.XX.1`` files in ``lib_dir`` or from the directory where the
cx_Oracle binary module is. Note other libraries used by ``libclntsh*`` are
also required.
To trace the loading of Oracle Client libraries, the environment variable
``DPI_DEBUG_LEVEL`` can be set to 64 before starting Python. For example, on
Linux, you might use::
$ export DPI_DEBUG_LEVEL=64
$ python myapp.py 2> log.txt
.. _usinginitoracleclient:
Using cx_Oracle.init_oracle_client() to set the Oracle Client directory
-----------------------------------------------------------------------
Applications can call the function :meth:`cx_Oracle.init_oracle_client()` to
specify the directory containing Oracle Instant Client libraries. The Oracle
Client Libraries are loaded when ``init_oracle_client()`` is called. For
example, if the Oracle Instant Client Libraries are in
``C:\oracle\instantclient_19_9`` on Windows or
``$HOME/Downloads/instantclient_19_8`` on macOS, then you can use:
.. code-block:: python
import cx_Oracle
import sys
import os
try:
if sys.platform.startswith("darwin"):
lib_dir = os.path.join(os.environ.get("HOME"), "Downloads",
"instantclient_19_8")
cx_Oracle.init_oracle_client(lib_dir=lib_dir)
elif sys.platform.startswith("win32"):
lib_dir=r"C:\oracle\instantclient_19_9"
cx_Oracle.init_oracle_client(lib_dir=lib_dir)
except Exception as err:
print("Whoops!")
print(err)
sys.exit(1)
Note the use of a 'raw' string ``r"..."`` on Windows so that backslashes are
treated as directory separators.
The :meth:`~cx_Oracle.init_oracle_client()` function can only be called once.
**Note if you set** ``lib_dir`` **on Linux and related platforms, you must still
have configured the system library search path to include that directory before
starting Python**.
On any operating system, if you set ``lib_dir`` to the library directory of a
full database or full client installation, you will need to have previously set
the Oracle environment, for example by setting the ``ORACLE_HOME`` environment
variable. Otherwise you will get errors like ORA-1804. You should set this,
and other Oracle environment variables, before starting Python, as
shown in :ref:`envset`.
.. _optnetfiles:
Optional Oracle Net Configuration Files
=======================================
Optional Oracle Net configuration files are read when cx_Oracle is loaded.
These files affect connections and applications. The common files are:
* ``tnsnames.ora``: A configuration file that defines databases addresses
for establishing connections. See :ref:`Net Service Name for Connection
Strings <netservice>`.
* ``sqlnet.ora``: A profile configuration file that may contain information
on features such as connection failover, network encryption, logging, and
tracing. See `Oracle Net Services Reference
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-19423B71-3F6C-430F-84CC-18145CC2A818>`__ for more information.
The files should be in a directory accessible to Python, not on the database
server host.
For example, if the file ``/etc/my-oracle-config/tnsnames.ora`` should be used,
you can call :meth:`cx_Oracle.init_oracle_client()`:
.. code-block:: python
import cx_Oracle
import sys
try:
cx_Oracle.init_oracle_client(config_dir="/etc/my-oracle-config")
except Exception as err:
print("Whoops!")
print(err)
sys.exit(1)
This is equivalent to setting the environment variable `TNS_ADMIN
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-12C94B15-2CE1-4B98-9D0C-8226A9DDF4CB>`__
to ``/etc/my-oracle-config``.
If :meth:`~cx_Oracle.init_oracle_client()` is not called, or it is called but
``config_dir`` is not specified, then default directories searched for the
configuration files. They include:
* ``$TNS_ADMIN``
* ``/opt/oracle/instantclient_19_6/network/admin`` if Instant Client is in ``/opt/oracle/instantclient_19_6``.
* ``/usr/lib/oracle/19.6/client64/lib/network/admin`` if Oracle 19.6 Instant Client RPMs are used on Linux.
* ``$ORACLE_HOME/network/admin`` if cx_Oracle is using libraries from a database installation.
A wallet configuration file ``cwallet.sso`` for secure connection can be
located with, or separately from, the ``tnsnames.ora`` and ``sqlnet.ora``
files. It should be securely stored. The ``sqlnet.ora`` file's
``WALLET_LOCATION`` path should be set to the directory containing
``cwallet.sso``. For Oracle Autonomous Database use of wallets, see
:ref:`autonomousdb`.
Note the :ref:`easyconnect` can set many common configuration options without
needing ``tnsnames.ora`` or ``sqlnet.ora`` files.
The section :ref:`Network Configuration <hanetwork>` has some discussion about
Oracle Net configuration.
.. _optclientfiles:
Optional Oracle Client Configuration Files
==========================================
When cx_Oracle uses Oracle Client libraries version 12.1, or later, an optional
client parameter file called ``oraaccess.xml`` can be used to configure some
behviors of those libraries, such as statement caching and prefetching. This can
be useful if the application cannot be altered. The file is read from the same
directory as the `Optional Oracle Net Configuration Files`_.
A sample ``oraaccess.xml`` file that sets the Oracle client prefetch value to
1000 rows. This value affects every SQL query in the application::
<?xml version="1.0"?>
<oraaccess xmlns="http://xmlns.oracle.com/oci/oraaccess"
xmlns:oci="http://xmlns.oracle.com/oci/oraaccess"
schemaLocation="http://xmlns.oracle.com/oci/oraaccess
http://xmlns.oracle.com/oci/oraaccess.xsd">
<default_parameters>
<prefetch>
<rows>1000</rows>
</prefetch>
</default_parameters>
</oraaccess>
Prefetching is the number of additional rows the underlying Oracle client
library fetches whenever cx_Oracle requests query data from the database.
Prefetching is a tuning option to maximize data transfer efficiency and minimize
:ref:`round-trips <roundtrips>` to the database. The prefetch size does not
affect when, or how many, rows are returned by cx_Oracle to the application.
The cache management is transparently handled by the Oracle client libraries.
Note, standard cx_Oracle fetch tuning is via :attr:`Cursor.arraysize`, but
changing the prefetch value can be useful in some cases such as when modifying
the application is not feasible.
The `oraaccess.xml` file has other uses including:
- Changing the value of Fast Application Notification :ref:`FAN <fan>` events which affects notifications and Runtime Load Balancing (RLB).
- Configuring `Client Result Caching <https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-D2FA7B29-301B-4AB8-8294-2B1B015899F9>`__ parameters
- Turning on `Client Statement Cache Auto-tuning <https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-6E21AA56-5BBE-422A-802C-197CAC8AAEA4>`__
Refer to the documentation on `oraaccess.xml
<https://www.oracle.com/pls/topic/lookup?
ctx=dblatest&id=GUID-9D12F489-EC02-46BE-8CD4-5AECED0E2BA2>`__
for more details.
.. _envset:
Oracle Environment Variables
============================
Some common environment variables that influence cx_Oracle are shown below. The
variables that may be needed depend on how Python is installed, how you connect
to the database, and what optional settings are desired. It is recommended to
set Oracle variables in the environment before invoking Python, however they may
also be set in the application with ``os.putenv()`` before the first connection
is established. System environment variables like ``LD_LIBRARY_PATH`` must be
set before Python starts.
.. list-table:: Common Oracle environment variables
:header-rows: 1
:widths: 1 2
:align: left
* - Oracle Environment Variables
- Purpose
* - LD_LIBRARY_PATH
- The library search path for platforms like Linux should include the
Oracle libraries, for example ``$ORACLE_HOME/lib`` or
``/opt/instantclient_19_3``. This variable is not needed if the
libraries are located by an alternative method, such as with
``ldconfig``. On other UNIX platforms you may need to set an OS
specific equivalent, such as ``LIBPATH`` or ``SHLIB_PATH``.
* - PATH
- The library search path for Windows should include the location where
``OCI.DLL`` is found. Not needed if you set ``lib_dir`` in a call to
:meth:`cx_Oracle.init_oracle_client()`
* - TNS_ADMIN
- The directory of optional Oracle Client configuration files such as
``tnsnames.ora`` and ``sqlnet.ora``. Not needed if the configuration
files are in a default location or if ``config_dir`` was not used in
:meth:`cx_Oracle.init_oracle_client()`. See :ref:`optnetfiles`.
* - ORA_SDTZ
- The default session time zone.
* - ORA_TZFILE
- The name of the Oracle time zone file to use. See below.
* - ORACLE_HOME
- The directory containing the Oracle Database software. The directory
and various configuration files must be readable by the Python process.
This variable should not be set if you are using Oracle Instant Client.
* - NLS_LANG
- Determines the 'national language support' globalization options for
cx_Oracle. Note: from cx_Oracle 8, the character set component is
ignored and only the language and territory components of ``NLS_LANG``
are used. The character set can instead be specified during connection
or connection pool creation. See :ref:`globalization`.
* - NLS_DATE_FORMAT, NLS_TIMESTAMP_FORMAT
- Often set in Python applications to force a consistent date format
independent of the locale. The variables are ignored if the environment
variable ``NLS_LANG`` is not set.
Oracle Instant Client includes a small and big time zone file, for example
``timezone_32.dat`` and ``timezlrg_32.dat``. The versions can be shown by running
the utility ``genezi -v`` located in the Instant Client directory. The small file
contains only the most commonly used time zones. By default the larger
``timezlrg_n.dat`` file is used. If you want to use the smaller ``timezone_n.dat``
file, then set the ``ORA_TZFILE`` environment variable to the name of the file
without any directory prefix, for example ``export ORA_TZFILE=timezone_32.dat``.
With Oracle Instant Client 12.2 or later, you can also use an external time zone
file. Create a subdirectory ``oracore/zoneinfo`` under the Instant Client
directory, and move the file into it. Then set ``ORA_TZFILE`` to the file name,
without any directory prefix. The ``genezi -v`` utility will show the time zone
file in use.
If cx_Oracle is using Oracle Client libraries from an Oracle Database or full
Oracle Client software installation, and you want to use a non-default time zone
file, then set ``ORA_TZFILE`` to the file name with a directory prefix, for
example: ``export ORA_TZFILE=/opt/oracle/myconfig/timezone_31.dat``.
The Oracle Database documentation contains more information about time zone
files, see `Choosing a Time Zone File
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-805AB986-DE12-4FEA-AF56-5AABCD2132DF>`__.
.. _otherinit:
Other cx_Oracle Initialization
==============================
The :meth:`cx_Oracle.init_oracle_client()` function allows ``driver_name`` and
``error_url`` parameters to be set. These are useful for applications whose
end-users are not aware cx_Oracle is being used. An example of setting the
parameters is:
.. code-block:: python
import cx_Oracle
import sys
try:
cx_Oracle.init_oracle_client(driver_name="My Great App : 3.1.4",
error_url="https://example.com/MyInstallInstructions.html")
except Exception as err:
print("Whoops!")
print(err)
sys.exit(1)
The convention for ``driver_name`` is to separate the product name from the
product version by a colon and single blank characters. The value will be shown
in Oracle Database views like ``V$SESSION_CONNECT_INFO``. If this parameter is
not specified, then the value "cx_Oracle : *version*" is used.
The ``error_url`` string will be shown in the exception raised if
``init_oracle_client()`` cannot load the Oracle Client libraries. This allows
applications that use cx_Oracle to refer users to application-specific
installation instructions. If this value is not specified, then the
:ref:`installation` URL is used.

View File

@ -0,0 +1,936 @@
.. _installation:
************************
cx_Oracle 8 Installation
************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Overview
========
To use cx_Oracle 8.3 with Python and Oracle Database you need:
- Python 3.6 and higher. Older versions of cx_Oracle may work with older
versions of Python.
- Oracle Client libraries. These can be from the free `Oracle Instant Client
<https://www.oracle.com/database/technologies/instant-client.html>`__, from a
full Oracle Client installation, or from those included in Oracle Database if
Python is on the same machine as the database. Oracle client libraries
versions 21, 19, 18, 12, and 11.2 are supported where available on Linux,
Windows and macOS (Intel x86). Users have also reported success with other
platforms. Use the latest client possible: Oracle's standard client-server
version interoperability allows connection to both older and newer databases.
- An Oracle Database, either local or remote.
The cx_Oracle module loads Oracle Client libraries which communicate
over Oracle Net to an existing database. Oracle Net is not a separate
product: it is how the Oracle Client and Oracle Database communicate.
.. figure:: /images/cx_Oracle_arch.png
cx_Oracle Architecture
Quick Start cx_Oracle Installation
==================================
You can:
- Install `Python <https://www.python.org/downloads>`__ 3, if not already
available. On macOS you must always install your own Python.
Python 3.6 and higher are supported by cx_Oracle 8.3. If you use Python 2,
then the older cx_Oracle 7.3 will install.
- Install cx_Oracle from `PyPI
<https://pypi.org/project/cx-Oracle/>`__ with:
.. code-block:: shell
python -m pip install cx_Oracle --upgrade
Note: if a binary wheel package is not available for your platform,
the source package will be downloaded instead. This will be compiled
and the resulting binary installed.
The ``--user`` option may be useful, if you don't have permission to write to
system directories:
.. code-block:: shell
python -m pip install cx_Oracle --upgrade --user
If you are behind a proxy, add a proxy server to the command, for example add
``--proxy=http://proxy.example.com:80``
- Add Oracle 21, 19, 18, 12 or 11.2 client libraries to your operating system
library search path such as ``PATH`` on Windows or ``LD_LIBRARY_PATH`` on
Linux. On macOS use :meth:`~cx_Oracle.init_oracle_client()` in your
application to pass the Oracle Client directory name, see
:ref:`usinginitoracleclient`. This is also usable on Windows.
To get the libraries:
- If your database is on a remote computer, then download and unzip the client
libraries from the free `Oracle Instant Client
<https://www.oracle.com/database/technologies/instant-client.html>`__
"Basic" or "Basic Light" package for your operating system
architecture.
Instant Client on Windows requires an appropriate Microsoft Windows
Redistributables, see :ref:`wininstall`. On Linux, the ``libaio``
(sometimes called ``libaio1``) package is needed. Oracle Linux 8 also
needs the ``libnsl`` package.
- Alternatively, use the client libraries already available in a
locally installed database such as the free `Oracle Database
Express Edition ("XE")
<https://www.oracle.com/database/technologies/appdev/xe.html>`__
release.
Version 21 client libraries can connect to Oracle Database 12.1 or greater.
Version 19, 18 and 12.2 client libraries can connect to Oracle Database 11.2
or greater. Version 12.1 client libraries can connect to Oracle Database 10.2
or greater. Version 11.2 client libraries can connect to Oracle Database 9.2
or greater.
- Create a script like the one below:
.. code-block:: python
# myscript.py
import cx_Oracle
# Connect as user "hr" with password "welcome" to the "orclpdb1" service running on this computer.
connection = cx_Oracle.connect(user="hr", password="welcome",
dsn="localhost/orclpdb1")
cursor = connection.cursor()
cursor.execute("""
SELECT first_name, last_name
FROM employees
WHERE department_id = :did AND employee_id > :eid""",
did = 50,
eid = 190)
for fname, lname in cursor:
print("Values:", fname, lname)
Locate your Oracle Database username and password, and the database
connection string. The connection string is commonly of the format
``hostname/servicename``, using the hostname where the database is
running, and using the service name of the Oracle Database instance.
Substitute your username, password and connection string in the
code. Run the Python script, for example::
python myscript.py
You can learn how to use cx_Oracle from the :ref:`API documentation <module>`
and `samples
<https://github.com/oracle/python-cx_Oracle/blob/main/samples>`__.
If you run into installation trouble, check out the section on `Troubleshooting`_.
Oracle Client and Oracle Database Interoperability
==================================================
cx_Oracle requires Oracle Client libraries. The libraries provide the
necessary network connectivity to access an Oracle Database instance.
They also provide basic and advanced connection management and data
features to cx_Oracle.
The simplest way to get Oracle Client libraries is to install the free
`Oracle Instant Client
<https://www.oracle.com/database/technologies/instant-client.html>`__
"Basic" or "Basic Light" package. The libraries are also available in
any Oracle Database installation or full Oracle Client installation.
Oracle's standard client-server network interoperability allows
connections between different versions of Oracle Client libraries and
Oracle Database. For certified configurations see Oracle Support's
`Doc ID 207303.1
<https://support.oracle.com/epmos/faces/DocumentDisplay?id=207303.1>`__.
In summary, Oracle Client 21 can connect to Oracle Database 12.1 or greater.
Oracle Client 19, 18 and 12.2 can connect to Oracle Database 11.2 or
greater. Oracle Client 12.1 can connect to Oracle Database 10.2 or
greater. Oracle Client 11.2 can connect to Oracle Database 9.2 or greater. The
technical restrictions on creating connections may be more flexible. For
example Oracle Client 12.2 can successfully connect to Oracle Database 10.2.
cx_Oracle uses the shared library loading mechanism available on each
supported platform to load the Oracle Client libraries at runtime. It
does not need to be rebuilt for different versions of the libraries.
Since a single cx_Oracle binary can use different client versions and
also access multiple database versions, it is important your
application is tested in your intended release environments. Newer
Oracle clients support new features, such as the `oraaccess.xml
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-9D12F489-EC02-46BE-8CD4-5AECED0E2BA2>`__ external configuration
file available with 12.1 or later clients, session pool improvements,
improved high availability features, call timeouts, and `other enhancements
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-D60519C3-406F-4588-8DA1-D475D5A3E1F6>`__.
The cx_Oracle function :func:`~cx_Oracle.clientversion()` can be used to
determine which Oracle Client version is in use. The attribute
:attr:`Connection.version` can be used to determine which Oracle Database
version a connection is accessing. These can then be used to adjust application
behavior accordingly. Attempts to use Oracle features that are not supported by
a particular client/server library combination will result in runtime errors.
Installing cx_Oracle on Linux
=============================
This section discusses the generic installation methods on Linux. To use Python
and cx_Oracle RPM packages from yum on Oracle Linux, see :ref:`oraclelinux`.
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Install cx_Oracle
-----------------
The generic way to install cx_Oracle on Linux is to use Python's `Pip
<https://pip.readthedocs.io/en/latest/installing/>`__ package to
install cx_Oracle from `PyPI
<https://pypi.org/project/cx-Oracle/>`__:
.. code-block:: shell
python -m pip install cx_Oracle --upgrade
The ``--user`` option may be useful, if you don't have permission to write to
system directories:
.. code-block:: shell
python -m pip install cx_Oracle --upgrade --user
If you are behind a proxy, add a proxy server to the command, for example add
``--proxy=http://proxy.example.com:80``
This will download and install a pre-compiled binary `if one is
available <https://pypi.org/project/cx-Oracle/>`__ for your
architecture. If a pre-compiled binary is not available, the source
will be downloaded, compiled, and the resulting binary installed.
Compiling cx_Oracle requires the ``Python.h`` header file. If you are
using the default ``python`` package, this file is in the ``python-devel``
package or equivalent.
Install Oracle Client
---------------------
Using cx_Oracle requires Oracle Client libraries to be installed.
These provide the necessary network connectivity allowing cx_Oracle
to access an Oracle Database instance.
- If your database is on a remote computer, then download the free `Oracle
Instant Client
<https://www.oracle.com/database/technologies/instant-client.html>`__
"Basic" or "Basic Light" package for your operating system
architecture. Use the RPM or ZIP packages, based on your
preferences.
- Alternatively, use the client libraries already available in a
locally installed database such as the free `Oracle Database
Express Edition ("XE")
<https://www.oracle.com/database/technologies/appdev/xe.html>`__
release.
Oracle Instant Client Zip Files
+++++++++++++++++++++++++++++++
To use cx_Oracle with Oracle Instant Client zip files:
1. Download an Oracle 21, 19, 18, 12, or 11.2 "Basic" or "Basic Light" zip file
matching your Python 64-bit or 32-bit architecture:
- `x86-64 64-bit <https://www.oracle.com/database/technologies/instant-client/linux-x86-64-downloads.html>`__
- `x86 32-bit <https://www.oracle.com/database/technologies/instant-client/linux-x86-32-downloads.html>`__
- `ARM (aarch64) 64-bit <https://www.oracle.com/database/technologies/instant-client/linux-arm-aarch64-downloads.html>`__
The latest version is recommended. Oracle Instant Client 21 will connect to
Oracle Database 12.1 or later.
2. Unzip the package into a single directory that is accessible to your
application. For example:
.. code-block:: shell
mkdir -p /opt/oracle
cd /opt/oracle
unzip instantclient-basic-linux.x64-21.1.0.0.0.zip
3. Install the ``libaio`` package with sudo or as the root user. For example::
sudo yum install libaio
On some Linux distributions this package is called ``libaio1`` instead.
On recent Linux versions such as Oracle Linux 8, you may also need to
install the ``libnsl`` package when using Oracle Instant Client 19.
4. If there is no other Oracle software on the machine that will be
impacted, permanently add Instant Client to the runtime link
path. For example, with sudo or as the root user:
.. code-block:: shell
sudo sh -c "echo /opt/oracle/instantclient_21_1 > /etc/ld.so.conf.d/oracle-instantclient.conf"
sudo ldconfig
Alternatively, set the environment variable ``LD_LIBRARY_PATH`` to
the appropriate directory for the Instant Client version. For
example::
export LD_LIBRARY_PATH=/opt/oracle/instantclient_21_1:$LD_LIBRARY_PATH
5. If you use optional Oracle configuration files such as ``tnsnames.ora``,
``sqlnet.ora`` or ``oraaccess.xml`` with Instant Client, then put the files
in an accessible directory, for example in
``/opt/oracle/your_config_dir``. Then use:
.. code-block:: python
import cx_Oracle
cx_Oracle.init_oracle_client(config_dir="/home/your_username/oracle/your_config_dir")
Or set the environment variable ``TNS_ADMIN`` to that directory name.
Alternatively, put the files in the ``network/admin`` subdirectory of Instant
Client, for example in ``/opt/oracle/instantclient_21_1/network/admin``.
This is the default Oracle configuration directory for executables linked
with this Instant Client.
Oracle Instant Client RPMs
++++++++++++++++++++++++++
To use cx_Oracle with Oracle Instant Client RPMs:
1. Download an Oracle 21,19, 18, 12, or 11.2 "Basic" or "Basic Light" RPM
matching your Python architecture:
- `x86-64 64-bit <https://www.oracle.com/database/technologies/instant-client/linux-x86-64-downloads.html>`__
- `x86 32-bit <https://www.oracle.com/database/technologies/instant-client/linux-x86-32-downloads.html>`__
- `ARM (aarch64) 64-bit <https://www.oracle.com/database/technologies/instant-client/linux-arm-aarch64-downloads.html>`__
Oracle's yum server has convenient repositories:
- `Instant Client 21 RPMs for Oracle Linux x86-64 8 <https://yum.oracle.com/repo/OracleLinux/OL8/oracle/instantclient21/x86_64/index.html>`__, `Older Instant Client RPMs for Oracle Linux x86-64 8 <https://yum.oracle.com/repo/OracleLinux/OL8/oracle/instantclient/x86_64/index.html>`__
- `Instant Client 21 RPMs for Oracle Linux x86-64 7 <https://yum.oracle.com/repo/OracleLinux/OL7/oracle/instantclient21/x86_64/index.html>`__, `Older Instant Client RPMs for Oracle Linux x86-64 7 <https://yum.oracle.com/repo/OracleLinux/OL7/oracle/instantclient/x86_64/index.html>`__
- `Instant Client RPMs for Oracle Linux x86-64 6 <https://yum.oracle.com/repo/OracleLinux/OL6/oracle/instantclient/x86_64/index.html>`__
- `Instant Client RPMs for Oracle Linux ARM (aarch64) 8 <https://yum.oracle.com/repo/OracleLinux/OL8/oracle/instantclient/aarch64/index.html>`__
- `Instant Client RPMs for Oracle Linux ARM (aarch64) 7 <https://yum.oracle.com/repo/OracleLinux/OL7/oracle/instantclient/aarch64/index.html>`__
The latest version is recommended. Oracle Instant Client 21 will connect to
Oracle Database 12.1 or later.
2. Install the downloaded RPM with sudo or as the root user. For example:
.. code-block:: shell
sudo yum install oracle-instantclient-basic-21.1.0.0.0-1.x86_64.rpm
Yum will automatically install required dependencies, such as ``libaio``.
On recent Linux versions, such as Oracle Linux 8, you may need to manually
install the ``libnsl`` package when using Oracle Instant Client 19.
3. For Instant Client 19, or later, the system library search path is
automatically configured during installation.
For older versions, if there is no other Oracle software on the machine that will be
impacted, permanently add Instant Client to the runtime link
path. For example, with sudo or as the root user:
.. code-block:: shell
sudo sh -c "echo /usr/lib/oracle/18.5/client64/lib > /etc/ld.so.conf.d/oracle-instantclient.conf"
sudo ldconfig
Alternatively, for version 18 and earlier, every shell running
Python will need to have the environment variable
``LD_LIBRARY_PATH`` set to the appropriate directory for the
Instant Client version. For example::
export LD_LIBRARY_PATH=/usr/lib/oracle/18.5/client64/lib:$LD_LIBRARY_PATH
4. If you use optional Oracle configuration files such as ``tnsnames.ora``,
``sqlnet.ora`` or ``oraaccess.xml`` with Instant Client, then put the files
in an accessible directory, for example in
``/opt/oracle/your_config_dir``. Then use:
.. code-block:: python
import cx_Oracle
cx_Oracle.init_oracle_client(config_dir="/opt/oracle/your_config_dir")
Or set the environment variable ``TNS_ADMIN`` to that directory name.
Alternatively, put the files in the ``network/admin`` subdirectory of Instant
Client, for example in ``/usr/lib/oracle/21/client64/lib/network/admin``.
This is the default Oracle configuration directory for executables linked
with this Instant Client.
Local Database or Full Oracle Client
++++++++++++++++++++++++++++++++++++
cx_Oracle applications can use Oracle Client 21, 19, 18, 12, or 11.2 libraries
from a local Oracle Database or full Oracle Client installation.
The libraries must be either 32-bit or 64-bit, matching your
Python architecture.
1. Set required Oracle environment variables by running the Oracle environment
script. For example:
.. code-block:: shell
source /usr/local/bin/oraenv
For Oracle Database Express Edition ("XE") 11.2, run:
.. code-block:: shell
source /u01/app/oracle/product/11.2.0/xe/bin/oracle_env.sh
2. Optional Oracle configuration files such as ``tnsnames.ora``,
``sqlnet.ora`` or ``oraaccess.xml`` can be placed in
``$ORACLE_HOME/network/admin``.
Alternatively, Oracle configuration files can be put in another,
accessible directory. Then set the environment variable
``TNS_ADMIN`` to that directory name.
.. _oraclelinux:
Installing cx_Oracle RPMs on Oracle Linux
=========================================
Python and cx_Oracle RPM packages are available from the `Oracle Linux yum server
<https://yum.oracle.com/>`__. Various versions of Python are easily installed.
Using the yum server makes it easy to keep up to date.
Installation instructions are at `Oracle Linux for Python
Developers <https://yum.oracle.com/oracle-linux-python.html>`__.
.. _wininstall:
Installing cx_Oracle on Windows
===============================
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Install cx_Oracle
-----------------
Use Python's `Pip <https://pip.readthedocs.io/en/latest/installing/>`__
package to install cx_Oracle from `PyPI
<https://pypi.org/project/cx-Oracle/>`__::
python -m pip install cx_Oracle --upgrade
If you are behind a proxy, specify your proxy server:
.. code-block:: shell
python -m pip install cx_Oracle --proxy=http://proxy.example.com:80 --upgrade
This will download and install a pre-compiled binary `if one is
available <https://pypi.org/project/cx-Oracle/>`__ for your
architecture. If a pre-compiled binary is not available, the source
will be downloaded, compiled, and the resulting binary installed.
Install Oracle Client
---------------------
Using cx_Oracle requires Oracle Client libraries to be installed.
These provide the necessary network connectivity allowing cx_Oracle
to access an Oracle Database instance. Oracle Client versions 19, 18,
12 and 11.2 are supported.
- If your database is on a remote computer, then download the free `Oracle
Instant Client
<https://www.oracle.com/database/technologies/instant-client.html>`__
"Basic" or "Basic Light" package for your operating system
architecture.
- Alternatively, use the client libraries already available in a
locally installed database such as the free `Oracle Database
Express Edition ("XE")
<https://www.oracle.com/database/technologies/appdev/xe.html>`__
release.
Oracle Instant Client Zip Files
+++++++++++++++++++++++++++++++
To use cx_Oracle with Oracle Instant Client zip files:
1. Download an Oracle 19, 18, 12, or 11.2 "Basic" or "Basic Light" zip
file: `64-bit
<https://www.oracle.com/database/technologies/instant-client/winx64-64-downloads.html>`__
or `32-bit
<https://www.oracle.com/database/technologies/instant-client/microsoft-windows-32-downloads.html>`__, matching your
Python architecture.
The latest version is recommended. Oracle Instant Client 19 will
connect to Oracle Database 11.2 or later.
Windows 7 users: Note that Oracle 19c is not supported on Windows 7.
2. Unzip the package into a directory that is accessible to your
application. For example unzip
``instantclient-basic-windows.x64-19.11.0.0.0dbru.zip`` to
``C:\oracle\instantclient_19_11``.
3. Oracle Instant Client libraries require a Visual Studio redistributable with
a 64-bit or 32-bit architecture to match Instant Client's architecture.
Each Instant Client version requires a different redistributable version:
- For Instant Client 21 install `VS 2019 <https://docs.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170>`__ or later.
- For Instant Client 19 install `VS 2017 <https://docs.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170>`__.
- For Instant Client 18 or 12.2 install `VS 2013 <https://docs.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170#visual-studio-2013-vc-120>`__
- For Instant Client 12.1 install `VS 2010 <https://docs.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170#visual-studio-2010-vc-100-sp1-no-longer-supported>`__
- For Instant Client 11.2 install `VS 2005 64-bit <https://docs.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170#visual-studio-2005-vc-80-sp1-no-longer-supported>`__
Configure Oracle Instant Client
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1. There are several alternative ways to tell cx_Oracle where your Oracle Client
libraries are, see :ref:`initialization`.
* With Oracle Instant Client you can use :meth:`~cx_Oracle.init_oracle_client()`
in your application, for example:
.. code-block:: python
import cx_Oracle
cx_Oracle.init_oracle_client(lib_dir=r"C:\oracle\instantclient_19_11")
Note a 'raw' string is used because backslashes occur in the path.
* Alternatively, add the Oracle Instant Client directory to the ``PATH``
environment variable. The directory must occur in ``PATH`` before any
other Oracle directories. Restart any open command prompt windows.
* Another way to set ``PATH`` is to use a batch file that sets it before Python
is executed, for example::
REM mypy.bat
SET PATH=C:\oracle\instantclient_19_9;%PATH%
python %*
Invoke this batch file every time you want to run Python.
2. If you use optional Oracle configuration files such as ``tnsnames.ora``,
``sqlnet.ora`` or ``oraaccess.xml`` with Instant Client, then put the files
in an accessible directory, for example in
``C:\oracle\your_config_dir``. Then use:
.. code-block:: python
import cx_Oracle
cx_Oracle.init_oracle_client(lib_dir=r"C:\oracle\instantclient_19_11",
config_dir=r"C:\oracle\your_config_dir")
Or set the environment variable ``TNS_ADMIN`` to that directory name.
Alternatively, put the files in a ``network\admin`` subdirectory of
Instant Client, for example in
``C:\oracle\instantclient_19_11\network\admin``. This is the default
Oracle configuration directory for executables linked with this
Instant Client.
Local Database or Full Oracle Client
++++++++++++++++++++++++++++++++++++
cx_Oracle applications can use Oracle Client 19, 18, 12, or 11.2
libraries libraries from a local Oracle Database or full Oracle
Client.
The Oracle libraries must be either 32-bit or 64-bit, matching your
Python architecture.
1. Set the environment variable ``PATH`` to include the path that contains
``OCI.DLL``, if it is not already set.
Restart any open command prompt windows.
2. Optional Oracle configuration files such as ``tnsnames.ora``,
``sqlnet.ora`` or ``oraaccess.xml`` can be placed in the
``network\admin`` subdirectory of the Oracle Database software
installation.
Alternatively, pass ``config_dir`` to :meth:`~cx_Oracle.init_oracle_client()`
as shown in the previous section, or set ``TNS_ADMIN`` to the directory name.
Installing cx_Oracle on macOS (Intel x86)
=========================================
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Install Python
--------------
Make sure you are not using the bundled Python. This has restricted
entitlements and will fail to load Oracle client libraries. Instead use
`Homebrew <https://brew.sh>`__ or `Python.org
<https://www.python.org/downloads>`__.
A C compiler is needed, for example Xcode and its command line tools.
Install cx_Oracle
-----------------
Use Python's `Pip <https://pip.readthedocs.io/en/latest/installing/>`__
package to install cx_Oracle from `PyPI
<https://pypi.org/project/cx-Oracle/>`__:
.. code-block:: shell
export ARCHFLAGS="-arch x86_64"
python -m pip install cx_Oracle --upgrade
The ``--user`` option may be useful, if you don't have permission to write to
system directories:
.. code-block:: shell
python -m pip install cx_Oracle --upgrade --user
If you are behind a proxy, add a proxy server to the command, for example add
``--proxy=http://proxy.example.com:80``
The source will be downloaded, compiled, and the resulting binary
installed.
Install Oracle Instant Client
-----------------------------
Oracle Instant Client provides the network connectivity for accessing Oracle
Database.
Manual Installation
+++++++++++++++++++
* Download the **Basic** 64-bit DMG from `Oracle
<https://www.oracle.com/database/technologies/instant-client/macos-intel-x86-downloads.html>`__.
* In Finder, double click on the DMG to mount it.
* Open a terminal window and run the install script in the mounted package, for example:
.. code-block:: shell
/Volumes/instantclient-basic-macos.x64-19.8.0.0.0dbru/install_ic.sh
This copies the contents to ``$HOME/Downloads/instantclient_19_8``.
Applications may not have access to the ``Downloads`` directory, so you
should move Instant Client somewhere convenient.
* In Finder, eject the mounted Instant Client package.
If you have multiple Instant Client DMG packages mounted, you only need to run
``install_ic.sh`` once. It will copy all mounted Instant Client DMG packages at
the same time.
Scripted Installation
+++++++++++++++++++++
Instant Client installation can alternatively be scripted, for example:
.. code-block:: shell
cd $HOME/Downloads
curl -O https://download.oracle.com/otn_software/mac/instantclient/198000/instantclient-basic-macos.x64-19.8.0.0.0dbru.dmg
hdiutil mount instantclient-basic-macos.x64-19.8.0.0.0dbru.dmg
/Volumes/instantclient-basic-macos.x64-19.8.0.0.0dbru/install_ic.sh
hdiutil unmount /Volumes/instantclient-basic-macos.x64-19.8.0.0.0dbru
The Instant Client directory will be ``$HOME/Downloads/instantclient_19_8``.
Applications may not have access to the ``Downloads`` directory, so you should
move Instant Client somewhere convenient.
Configure Oracle Instant Client
-------------------------------
1. Call :meth:`~cx_Oracle.init_oracle_client()` once in your application:
.. code-block:: python
import cx_Oracle
cx_Oracle.init_oracle_client(lib_dir="/Users/your_username/Downloads/instantclient_19_8")
2. If you use optional Oracle configuration files such as ``tnsnames.ora``,
``sqlnet.ora`` or ``oraaccess.xml`` with Oracle Instant Client, then put the
files in an accessible directory, for example in
``/Users/your_username/oracle/your_config_dir``. Then use:
.. code-block:: python
import cx_Oracle
cx_Oracle.init_oracle_client(lib_dir="/Users/your_username/Downloads/instantclient_19_8",
config_dir="/Users/your_username/oracle/your_config_dir")
Or set the environment variable ``TNS_ADMIN`` to that directory name.
Alternatively, put the files in the ``network/admin`` subdirectory of Oracle
Instant Client, for example in
``/Users/your_username/Downloads/instantclient_19_8/network/admin``. This is the
default Oracle configuration directory for executables linked with this
Instant Client.
Linux Containers
================
Sample Dockerfiles are on `GitHub
<https://github.com/oracle/docker-images/tree/main/OracleLinuxDevelopers>`__.
Pre-built images for Python and cx_Oracle are in the `GitHub Container Registry
<https://github.com/orgs/oracle/packages>`__. These are easily used. For
example, to pull an Oracle Linux 8 image with Python 3.6 and cx_Oracle,
execute::
docker pull ghcr.io/oracle/oraclelinux7-python:3.6-oracledb
Installing cx_Oracle without Internet Access
============================================
To install cx_Oracle on a computer that is not connected to the
internet, download the appropriate cx_Oracle file from `PyPI
<https://pypi.org/project/cx-Oracle/#files>`__. Transfer this file to
the offline computer and install it with::
python -m pip install "<file_name>"
Then follow the general cx_Oracle platform installation instructions
to install Oracle client libraries.
Install Using GitHub
====================
In order to install using the source on GitHub, use the following commands::
git clone https://github.com/oracle/python-cx_Oracle.git cx_Oracle
cd cx_Oracle
git submodule init
git submodule update
python setup.py install
Note that if you download a source zip file directly from GitHub then
you will also need to download an `ODPI-C
<https://github.com/oracle/odpi>`__ source zip file and extract it
inside the directory called "odpi".
cx_Oracle source code is also available from opensource.oracle.com. This can
be cloned with::
git clone git://opensource.oracle.com/git/oracle/python-cx_Oracle.git cx_Oracle
cd cx_Oracle
git submodule init
git submodule update
Install Using Source from PyPI
==============================
The source package can be downloaded manually from
`PyPI <https://pypi.org/project/cx-Oracle/>`__ and extracted, after
which the following commands should be run::
python setup.py build
python setup.py install
Upgrading from Older Versions
=============================
Review the :ref:`release notes <releasenotes>` and :ref:`Deprecations
<deprecations>` for changes. Modify affected code.
If you are upgrading from cx_Oracle 7 note these changes:
- The default character set used by cx_Oracle 8 is now "UTF-8". Also, the
character set component of the ``NLS_LANG`` environment variable is
ignored. If you need to change the character set, then pass ``encoding``
and ``nendcoding`` parameters when creating a connection or connection
pool. See :ref:`globalization`.
- Any uses of ``type(var)`` need to be changed to ``var.type``.
- Any uses of ``var.type is not None`` need to be changed to
``isinstance(var.type, cx_Oracle.ObjectType)``
- Note that ``TIMESTAMP WITH TIME ZONE`` columns will now be reported as
:data:`cx_Oracle.DB_TYPE_TIMESTAMP_TZ` instead of
:data:`cx_Oracle.TIMESTAMP` in :data:`Cursor.description`.
- Note that ``TIMESTAMP WITH LOCAL TIME ZONE`` columns will now be reported
as :data:`cx_Oracle.DB_TYPE_TIMESTAMP_LTZ` instead of
:data:`cx_Oracle.TIMESTAMP` in :data:`Cursor.description`.
- Note that ``BINARY_FLOAT`` columns will now be reported as
:data:`cx_Oracle.DB_TYPE_BINARY_FLOAT` instead of
:data:`cx_Oracle.NATIVE_DOUBLE` in :data:`Cursor.description`.
If you are upgrading from cx_Oracle 5 note these installation changes:
- When using Oracle Instant Client, you should not set ``ORACLE_HOME``.
- On Linux, cx_Oracle 6 and higher no longer uses Instant Client RPMs
automatically. You must set ``LD_LIBRARY_PATH`` or use ``ldconfig`` to
locate the Oracle client library.
- PyPI no longer allows Windows installers or Linux RPMs to be
hosted. Use the supplied cx_Oracle Wheels instead, or use RPMs
from Oracle, see :ref:`oraclelinux`.
.. _python2:
Installing cx_Oracle in Python 2
================================
cx_Oracle 7.3 was the last version with support for Python 2.
If you install cx_Oracle in Python 2 using the commands provided above, then
cx_Oracle 7.3 will be installed. This is equivalent to using a command like::
python -m pip install cx_Oracle==7.3 --upgrade --user
For other installation options such as installing through a proxy, see
instructions above. Make sure the Oracle Client libraries are in the system
library search path because cx_Oracle 7 does not support the
:meth:`cx_Oracle.init_oracle_client()` method and does not support loading the
Oracle Client libraries from the directory containing the cx_Oracle module
binary.
Installing cx_Oracle 5.3
========================
If you require cx_Oracle 5.3, download a Windows installer from `PyPI
<https://pypi.org/project/cx-Oracle/>`__ or use ``python -m pip
install cx-oracle==5.3`` to install from source.
Very old versions of cx_Oracle can be found in the files section at
`SourceForce <https://sourceforge.net/projects/cx-oracle/files/>`__.
Troubleshooting
===============
If installation fails:
- Use option ``-v`` with pip. Review your output and logs. Try to install
using a different method. **Google anything that looks like an error.**
Try some potential solutions.
- Was there a network connection error? Do you need to set the
environment variables ``http_proxy`` and/or ``https_proxy``? Or
try ``pip install --proxy=http://proxy.example.com:80 cx_Oracle
--upgrade``?
- If upgrading gave no errors but the old version is still
installed, try ``pip install cx_Oracle --upgrade
--force-reinstall``
- If you do not have access to modify your system version of
Python, can you use ``pip install cx_Oracle --upgrade --user``
or venv?
- Do you get the error "``No module named pip``"? The pip module is builtin
to Python but is sometimes removed by the OS. Use the venv module
(builtin to Python 3.x) or virtualenv module instead.
- Do you get the error "``fatal error: dpi.h: No such file or directory``"
when building from source code? Ensure that your source installation has
a subdirectory called "odpi" containing files. If missing, review the
section on `Install Using GitHub`_.
If using cx_Oracle fails:
- Do you get the error "``DPI-1047: Oracle Client library cannot be
loaded``"?
- On Windows and macOS, try using :meth:`~cx_Oracle.init_oracle_client()`.
See :ref:`usinginitoracleclient`.
- Check that Python and your Oracle Client libraries are both 64-bit, or
both 32-bit. The ``DPI-1047`` message will tell you whether the 64-bit
or 32-bit Oracle Client is needed for your Python.
- Set the environment variable ``DPI_DEBUG_LEVEL`` to 64 and restart
cx_Oracle. The trace messages will show how and where cx_Oracle is
looking for the Oracle Client libraries.
At a Windows command prompt, this could be done with::
set DPI_DEBUG_LEVEL=64
On Linux and macOS, you might use::
export DPI_DEBUG_LEVEL=64
- On Windows, if you used :meth:`~cx_Oracle.init_oracle_client()` and have
a full database installation, make sure this database is the `currently
configured database
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-33D575DD-47FF-42B1-A82F-049D3F2A8791>`__.
- On Windows, if you are not using
:meth:`~cx_Oracle.init_oracle_client()`, then restart your command prompt
and use ``set PATH`` to check the environment variable has the correct
Oracle Client listed before any other Oracle directories.
- On Windows, use the ``DIR`` command to verify that ``OCI.DLL`` exists in
the directory passed to ``init_oracle_client()`` or set in ``PATH``.
- On Windows, check that the correct `Windows Redistributables
<https://oracle.github.io/odpi/doc/installation.html#windows>`__ have
been installed.
- On Linux, check the ``LD_LIBRARY_PATH`` environment variable contains
the Oracle Client library directory. If you are using Oracle Instant
Client, a preferred alternative is to ensure a file in the
``/etc/ld.so.conf.d`` directory contains the path to the Instant Client
directory, and then run ``ldconfig``.
- On macOS, make sure you are not using the bundled Python (use `Homebrew
<https://brew.sh>`__ or `Python.org
<https://www.python.org/downloads>`__ instead). If you are not using
:meth:`~cx_Oracle.init_oracle_client()`, then put the Oracle Instant
Client libraries in ``~/lib`` or ``/usr/local/lib``.
- If you got "``DPI-1072: the Oracle Client library version is
unsupported``", then review the installation requirements. cx_Oracle
needs Oracle client libraries 11.2 or later. Note that version 19 is not
supported on Windows 7. Similar steps shown above for ``DPI-1047`` may
help.
- If you have multiple versions of Python installed, make sure you are
using the correct python and pip (or python3 and pip3) executables.

View File

@ -0,0 +1,145 @@
.. _introduction:
*************************
Introduction to cx_Oracle
*************************
cx_Oracle is a Python extension module that enables Python access to Oracle
Database. It conforms to the `Python Database API v2.0 Specification
<https://www.python.org/dev/peps/pep-0249/>`__ with a considerable number of
additions and a couple of exclusions.
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Architecture
------------
Python programs call cx_Oracle functions. Internally cx_Oracle dynamically
loads Oracle Client libraries to access Oracle Database. The database can be on
the same machine as Python, or it can be remote.
.. _archfig:
.. figure:: /images/cx_Oracle_arch.png
cx_Oracle Architecture
cx_Oracle is typically installed from `PyPI
<https://pypi.org/project/cx-Oracle/>`__ using `pip
<https://pip.pypa.io/en/latest/installing/>`__. The Oracle Client libraries
need to be installed separately. The libraries can be from an installation of
`Oracle Instant Client
<https://www.oracle.com/database/technologies/instant-client.html>`__, from a
full Oracle Client installation, or even from an Oracle Database installation
(if Python is running on the same machine as the database). Oracles standard
client-server version interoperability allows connection to both older and
newer databases from different Client library versions, see :ref:`cx_Oracle
Installation <installation>`.
Some behaviors of the Oracle Client libraries can optionally be configured with
an ``oraaccess.xml`` file, for example to enable auto-tuning of a statement
cache. See :ref:`optclientfiles`.
The Oracle Net layer can optionally be configured with files such as
``tnsnames.ora`` and ``sqlnet.ora``, for example to enable :ref:`network
encryption <netencrypt>`. See :ref:`optnetfiles`.
Oracle environment variables that are set before cx_Oracle first creates a
database connection will affect cx_Oracle behavior. Optional variables include
NLS_LANG, NLS_DATE_FORMAT and TNS_ADMIN. See :ref:`envset`.
Features
--------
The cx_Oracle feature highlights are:
* Easy installation from PyPI
* Support for multiple Oracle Client and Database versions
* Execution of SQL and PL/SQL statements
* Extensive Oracle data type support, including large objects (CLOB and
BLOB) and binding of SQL objects
* Connection management, including connection pooling
* Oracle Database High Availability features
* Full use of Oracle Network Service infrastructure, including encrypted
network traffic and security features
A complete list of supported features can be seen `here
<https://oracle.github.io/python-cx_Oracle/index.html#features>`_.
Getting Started
---------------
Install cx_Oracle using the :ref:`installation <installation>` steps.
Create a script ``query.py`` as shown below:
.. code-block:: python
# query.py
import cx_Oracle
# Establish the database connection
connection = cx_Oracle.connect(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1")
# Obtain a cursor
cursor = connection.cursor()
# Data for binding
manager_id = 145
first_name = "Peter"
# Execute the query
sql = """SELECT first_name, last_name
FROM employees
WHERE manager_id = :mid AND first_name = :fn"""
cursor.execute(sql, mid=manager_id, fn=first_name)
# Loop over the result set
for row in cursor:
print(row)
This uses Oracle's `sample HR schema
<https://github.com/oracle/db-sample-schemas>`__.
Simple :ref:`connection <connhandling>` to the database requires a username,
password and connection string. Locate your Oracle Database `user name and
password <https://www.youtube.com/watch?v=WDJacg0NuLo>`_ and the database
:ref:`connection string <connstr>`, and use them in ``query.py``. For
cx_Oracle, the connection string is commonly of the format
``hostname/servicename``, using the host name where the database is running and
the Oracle Database service name of the database instance.
The :ref:`cursor <cursorobj>` is the object that allows statements to be
executed and results (if any) fetched.
The data values in ``managerId`` and ``firstName`` are 'bound' to the statement
placeholder 'bind variables' ``:mid`` and ``:fn`` when the statement is
executed. This separates the statement text from the data, which helps avoid
SQL Injection security risks. :ref:`Binding <bind>` is also important for
performance and scalability.
The cursor allows rows to be iterated over and displayed.
Run the script::
python query.py
The output is::
('Peter', 'Hall')
('Peter', 'Tucker')
Examples and Tutorials
----------------------
Runnable examples are in the `GitHub samples directory
<https://github.com/oracle/python-cx_Oracle/tree/main/samples>`__. A `Python
cx_Oracle tutorial
<https://oracle.github.io/python-cx_Oracle/samples/tutorial/Python-and-Oracle-Database-Scripting-for-the-Future.html>`__
is also available.

View File

@ -0,0 +1,317 @@
.. _jsondatatype:
*******************************
Working with the JSON Data Type
*******************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Native support for JSON data was introduced in Oracle Database 12c. You can
use JSON with relational database features, including transactions, indexing,
declarative querying, and views. You can project JSON data relationally,
making it available for relational processes and tools. Also see
:ref:`Simple Oracle Document Access (SODA) <sodausermanual>`, which allows
access to JSON documents through a set of NoSQL-style APIs.
Prior to Oracle Database 21, JSON in relational tables is stored as BLOB, CLOB
or VARCHAR2 data, allowing easy access with cx_Oracle. Oracle Database 21
introduced a dedicated JSON data type with a new `binary storage format
<https://blogs.oracle.com/jsondb/osonformat>`__ that improves performance and
functionality. To use the new dedicated JSON type, the Oracle Database and
Oracle Client libraries must be version 21, or later. Also cx_Oracle must be
8.1, or later.
For more information about using JSON in Oracle Database see the
`Database JSON Developer's Guide
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=ADJSN>`__.
In Oracle Database 21, to create a table with a column called ``JSON_DATA`` for
JSON data:
.. code-block:: sql
create table customers (
id integer not null primary key,
json_data json
);
For older Oracle Database versions the syntax is:
.. code-block:: sql
create table customers (
id integer not null primary key,
json_data blob check (json_data is json)
);
The check constraint with the clause ``IS JSON`` ensures only JSON data is
stored in that column.
The older syntax can still be used in Oracle Database 21, however the
recommendation is to move to the new JSON type. With the old syntax, the
storage can be BLOB, CLOB or VARCHAR2. Of these, BLOB is preferred to avoid
character set conversion overheads.
Using Oracle Database 21 and Oracle Client 21 with cx_Oracle 8.1 (or later),
you can insert by binding as shown below:
.. code-block:: python
import datetime
json_data = [
2.78,
True,
'Ocean Beach',
b'Some bytes',
{'keyA': 1, 'KeyB': 'Melbourne'},
datetime.date.today()
]
var = cursor.var(cx_Oracle.DB_TYPE_JSON)
var.setvalue(0, json_data)
cursor.execute("insert into customers values (:1, :2)", [123, var])
# or these two lines can replace the three previous lines
cursor.setinputsizes(None, cx_Oracle.DB_TYPE_JSON)
cursor.execute("insert into customers values (:1, :2)", [123, json_data])
Fetching with:
.. code-block:: python
for row in cursor.execute("SELECT c.json_data FROM customers c"):
print(row)
gives output like::
([Decimal('2.78'), True, 'Ocean Beach',
b'Some bytes',
{'keyA': Decimal('1'), 'KeyB': 'Melbourne'},
datetime.datetime(2020, 12, 2, 0, 0)],)
With the older BLOB storage, or to insert JSON strings, use:
.. code-block:: python
import json
customer_data = dict(name="Rod", dept="Sales", location="Germany")
cursor.execute("insert into customers (id, json_data) values (:1, :2)",
[1, json.dumps(customer_data)])
IN Bind Type Mapping
====================
When binding to a JSON value, the type parameter for the variable must be
specified as :data:`cx_Oracle.DB_TYPE_JSON`. Python values are converted to
JSON values as shown in the following table. The 'SQL Equivalent' syntax can
be used in SQL INSERT and UPDATE statements if specific attribute types are
needed but there is no direct mapping from Python.
.. list-table::
:header-rows: 1
:widths: 1 1 1
:align: left
* - Python Type or Value
- JSON Attribute Type or Value
- SQL Equivalent Example
* - None
- null
- NULL
* - True
- true
- n/a
* - False
- false
- n/a
* - int
- NUMBER
- json_scalar(1)
* - float
- NUMBER
- json_scalar(1)
* - decimal.Decimal
- NUMBER
- json_scalar(1)
* - str
- VARCHAR2
- json_scalar('String')
* - datetime.date
- TIMESTAMP
- json_scalar(to_timestamp('2020-03-10', 'YYYY-MM-DD'))
* - datetime.datetime
- TIMESTAMP
- json_scalar(to_timestamp('2020-03-10', 'YYYY-MM-DD'))
* - bytes
- RAW
- json_scalar(utl_raw.cast_to_raw('A raw value'))
* - list
- Array
- json_array(1, 2, 3 returning json)
* - dict
- Object
- json_object(key 'Fred' value json_scalar(5), key 'George' value json_scalar('A string') returning json)
* - n/a
- CLOB
- json_scalar(to_clob('A short CLOB'))
* - n/a
- BLOB
- json_scalar(to_blob(utl_raw.cast_to_raw('A short BLOB')))
* - n/a
- DATE
- json_scalar(to_date('2020-03-10', 'YYYY-MM-DD'))
* - n/a
- INTERVAL YEAR TO MONTH
- json_scalar(to_yminterval('+5-9'))
* - n/a
- INTERVAL DAY TO SECOND
- json_scalar(to_dsinterval('P25DT8H25M'))
* - n/a
- BINARY_DOUBLE
- json_scalar(to_binary_double(25))
* - n/a
- BINARY_FLOAT
- json_scalar(to_binary_float(15.5))
An example of creating a CLOB attribute with key ``mydocument`` in a JSON column
using SQL is:
.. code-block:: python
cursor.execute("""
insert into mytab (myjsoncol) values
(json_object(key 'mydocument' value json_scalar(to_clob(:b))
returning json))""",
['A short CLOB'])
When `mytab` is queried in cx_Oracle, the CLOB data will be returned as a
Python string, as shown by the following table. Output might be like::
{mydocument: 'A short CLOB'}
Query and OUT Bind Type Mapping
===============================
When getting Oracle Database 21 JSON values from the database, the following
attribute mapping occurs:
.. list-table::
:header-rows: 1
:widths: 1 1
:align: left
* - Database JSON Attribute Type or Value
- Python Type or Value
* - null
- None
* - false
- False
* - true
- True
* - NUMBER
- decimal.Decimal
* - VARCHAR2
- str
* - RAW
- bytes
* - CLOB
- str
* - BLOB
- bytes
* - DATE
- datetime.datetime
* - TIMESTAMP
- datetime.datetime
* - INTERVAL YEAR TO MONTH
- not supported
* - INTERVAL DAY TO SECOND
- datetime.timedelta
* - BINARY_DOUBLE
- float
* - BINARY_FLOAT
- float
* - Arrays
- list
* - Objects
- dict
SQL/JSON Path Expressions
=========================
Oracle Database provides SQL access to JSON data using SQL/JSON path
expressions. A path expression selects zero or more JSON values that match, or
satisfy, it. Path expressions can use wildcards and array ranges. A simple
path expression is ``$.friends`` which is the value of the JSON field
``friends``.
For example, the previously created ``customers`` table with JSON column
``json_data`` can be queried like:
.. code-block:: sql
select c.json_data.location FROM customers c
With the JSON ``'{"name":"Rod","dept":"Sales","location":"Germany"}'`` stored
in the table, the queried value would be ``Germany``.
The JSON_EXISTS functions tests for the existence of a particular value within
some JSON data. To look for JSON entries that have a ``location`` field:
.. code-block:: python
for blob, in cursor.execute("""
select json_data
from customers
where json_exists(json_data, '$.location')"""):
data = json.loads(blob.read())
print(data)
This query might display::
{'name': 'Rod', 'dept': 'Sales', 'location': 'Germany'}
The SQL/JSON functions ``JSON_VALUE`` and ``JSON_QUERY`` can also be used.
Note that the default error-handling behavior for these functions is
``NULL ON ERROR``, which means that no value is returned if an error occurs.
To ensure that an error is raised, use ``ERROR ON ERROR``.
For more information, see `SQL/JSON Path Expressions
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-2DC05D71-3D62-4A14-855F-76E054032494>`__
in the Oracle JSON Developer's Guide.
Accessing Relational Data as JSON
=================================
In Oracle Database 12.2, or later, the `JSON_OBJECT
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-1EF347AE-7FDA-4B41-AFE0-DD5A49E8B370>`__
function is a great way to convert relational table data to JSON:
.. code-block:: python
cursor.execute("""
select json_object('deptId' is d.department_id, 'name' is d.department_name) department
from departments d
where department_id < :did
order by d.department_id""",
[50]);
for row in cursor:
print(row)
This produces::
('{"deptId":10,"name":"Administration"}',)
('{"deptId":20,"name":"Marketing"}',)
('{"deptId":30,"name":"Purchasing"}',)
('{"deptId":40,"name":"Human Resources"}',)

View File

@ -0,0 +1,207 @@
.. _lobdata:
************************
Using CLOB and BLOB Data
************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Oracle Database uses :ref:`lobobj` to store large data such as text, images,
videos and other multimedia formats. The maximum size of a LOB is limited to
the size of the tablespace storing it.
There are four types of LOB (large object):
* BLOB - Binary Large Object, used for storing binary data. cx_Oracle uses
the type :attr:`cx_Oracle.DB_TYPE_BLOB`.
* CLOB - Character Large Object, used for string strings in the database
character set format. cx_Oracle uses the type
:attr:`cx_Oracle.DB_TYPE_CLOB`.
* NCLOB - National Character Large Object, used for string strings in the
national character set format. cx_Oracle uses the type
:attr:`cx_Oracle.DB_TYPE_NCLOB`.
* BFILE - External Binary File, used for referencing a file stored on the
host operating system outside of the database. cx_Oracle uses the type
:attr:`cx_Oracle.DB_TYPE_BFILE`.
LOBs can be streamed to, and from, Oracle Database.
LOBs up to 1 GB in length can be also be handled directly as strings or bytes in
cx_Oracle. This makes LOBs easy to work with, and has significant performance
benefits over streaming. However it requires the entire LOB data to be present
in Python memory, which may not be possible.
See `GitHub <https://github.com/oracle/python-cx_Oracle/tree/main/samples>`__ for LOB examples.
Simple Insertion of LOBs
------------------------
Consider a table with CLOB and BLOB columns:
.. code-block:: sql
CREATE TABLE lob_tbl (
id NUMBER,
c CLOB,
b BLOB
);
With cx_Oracle, LOB data can be inserted in the table by binding strings or
bytes as needed:
.. code-block:: python
with open('example.txt', 'r') as f:
text_data = f.read()
with open('image.png', 'rb') as f:
img_data = f.read()
cursor.execute("""
insert into lob_tbl (id, c, b)
values (:lobid, :clobdata, :blobdata)""",
lobid=10, clobdata=text_data, blobdata=img_data)
Note that with this approach, LOB data is limited to 1 GB in size.
.. _directlobs:
Fetching LOBs as Strings and Bytes
----------------------------------
CLOBs and BLOBs smaller than 1 GB can queried from the database directly as
strings and bytes. This can be much faster than streaming.
A :attr:`Connection.outputtypehandler` or :attr:`Cursor.outputtypehandler` needs
to be used as shown in this example:
.. code-block:: python
def output_type_handler(cursor, name, default_type, size, precision, scale):
if default_type == cx_Oracle.DB_TYPE_CLOB:
return cursor.var(cx_Oracle.DB_TYPE_LONG, arraysize=cursor.arraysize)
if default_type == cx_Oracle.DB_TYPE_BLOB:
return cursor.var(cx_Oracle.DB_TYPE_LONG_RAW, arraysize=cursor.arraysize)
id_val = 1
text_data = "The quick brown fox jumps over the lazy dog"
binary_data = b"Some binary data"
cursor.execute("insert into lob_tbl (id, c, b) values (:1, :2, :3)",
[id_val, text_data, binary_data])
connection.outputtypehandler = output_type_handler
cursor.execute("select c, b from lob_tbl where id = :1", [id_val])
clob_data, blob_data = cursor.fetchone()
print("CLOB length:", len(clob_data))
print("CLOB data:", clob_data)
print("BLOB length:", len(blob_data))
print("BLOB data:", blob_data)
This displays::
CLOB length: 43
CLOB data: The quick brown fox jumps over the lazy dog
BLOB length: 16
BLOB data: b'Some binary data'
Streaming LOBs (Read)
---------------------
Without the output type handler, the CLOB and BLOB values are fetched as
:ref:`LOB objects<lobobj>`. The size of the LOB object can be obtained by
calling :meth:`LOB.size()` and the data can be read by calling
:meth:`LOB.read()`:
.. code-block:: python
id_val = 1
text_data = "The quick brown fox jumps over the lazy dog"
binary_data = b"Some binary data"
cursor.execute("insert into lob_tbl (id, c, b) values (:1, :2, :3)",
[id_val, text_data, binary_data])
cursor.execute("select b, c from lob_tbl where id = :1", [id_val])
b, c = cursor.fetchone()
print("CLOB length:", c.size())
print("CLOB data:", c.read())
print("BLOB length:", b.size())
print("BLOB data:", b.read())
This approach produces the same results as the previous example but it will
perform more slowly because it requires more :ref:`round-trips <roundtrips>` to
Oracle Database and has higher overhead. It is needed, however, if the LOB data
cannot be fetched as one block of data from the server.
To stream the BLOB column, the :meth:`LOB.read()` method can be called
repeatedly until all of the data has been read, as shown below:
.. code-block:: python
cursor.execute("select b from lob_tbl where id = :1", [10])
blob, = cursor.fetchone()
offset = 1
num_bytes_in_chunk = 65536
with open("image.png", "wb") as f:
while True:
data = blob.read(offset, num_bytes_in_chunk)
if data:
f.write(data)
if len(data) < num_bytes_in_chunk:
break
offset += len(data)
Streaming LOBs (Write)
----------------------
If a row containing a LOB is being inserted or updated, and the quantity of
data that is to be inserted or updated cannot fit in a single block of data,
the data can be streamed using the method :meth:`LOB.write()` instead as shown
in the following code:
.. code-block:: python
id_val = 9
lob_var = cursor.var(cx_Oracle.DB_TYPE_BLOB)
cursor.execute("""
insert into lob_tbl (id, b)
values (:1, empty_blob())
returning b into :2""", [id_val, lob_var])
blob, = lobVar.getvalue()
offset = 1
num_bytes_in_chunk = 65536
with open("image.png", "rb") as f:
while True:
data = f.read(num_bytes_in_chunk)
if data:
blob.write(data, offset)
if len(data) < num_bytes_in_chunk:
break
offset += len(data)
connection.commit()
Temporary LOBs
--------------
All of the examples shown thus far have made use of permanent LOBs. These are
LOBs that are stored in the database. Oracle also supports temporary LOBs that
are not stored in the database but can be used to pass large quantities of
data. These LOBs use space in the temporary tablespace until all variables
referencing them go out of scope or the connection in which they are created is
explicitly closed.
When calling PL/SQL procedures with data that exceeds 32,767 bytes in length,
cx_Oracle automatically creates a temporary LOB internally and passes that
value through to the procedure. If the data that is to be passed to the
procedure exceeds that which can fit in a single block of data, however, you
can use the method :meth:`Connection.createlob()` to create a temporary LOB.
This LOB can then be read and written just like in the examples shown above for
persistent LOBs.

View File

@ -0,0 +1,388 @@
.. _plsqlexecution:
****************
PL/SQL Execution
****************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
PL/SQL stored procedures, functions and anonymous blocks can be called from
cx_Oracle.
.. _plsqlproc:
PL/SQL Stored Procedures
------------------------
The :meth:`Cursor.callproc()` method is used to call PL/SQL procedures.
If a procedure with the following definition exists:
.. code-block:: sql
create or replace procedure myproc (
a_Value1 number,
a_Value2 out number
) as
begin
a_Value2 := a_Value1 * 2;
end;
then the following Python code can be used to call it:
.. code-block:: python
out_val = cursor.var(int)
cursor.callproc('myproc', [123, out_val])
print(out_val.getvalue()) # will print 246
Calling :meth:`Cursor.callproc()` actually generates an anonymous PL/SQL block
as shown below, which is then executed:
.. code-block:: python
cursor.execute("begin myproc(:1,:2); end;", [123, out_val])
See :ref:`bind` for information on binding.
.. _plsqlfunc:
PL/SQL Stored Functions
-----------------------
The :meth:`Cursor.callfunc()` method is used to call PL/SQL functions.
The ``returnType`` parameter for :meth:`~Cursor.callfunc()` is
expected to be a Python type, one of the :ref:`cx_Oracle types <types>` or
an :ref:`Object Type <objecttype>`.
If a function with the following definition exists:
.. code-block:: sql
create or replace function myfunc (
a_StrVal varchar2,
a_NumVal number
) return number as
begin
return length(a_StrVal) + a_NumVal * 2;
end;
then the following Python code can be used to call it:
.. code-block:: python
return_val = cursor.callfunc("myfunc", int, ["a string", 15])
print(return_val) # will print 38
A more complex example that returns a spatial (SDO) object can be seen below.
First, the SQL statements necessary to set up the example:
.. code-block:: sql
create table MyPoints (
id number(9) not null,
point sdo_point_type not null
);
insert into MyPoints values (1, sdo_point_type(125, 375, 0));
create or replace function spatial_queryfn (
a_Id number
) return sdo_point_type is
t_Result sdo_point_type;
begin
select point
into t_Result
from MyPoints
where Id = a_Id;
return t_Result;
end;
/
The Python code that will call this procedure looks as follows:
.. code-block:: python
obj_type = connection.gettype("SDO_POINT_TYPE")
cursor = connection.cursor()
return_val = cursor.callfunc("spatial_queryfn", obj_type, [1])
print(f"({return_val.X}, {return_val.Y}, {return_val.Z})")
# will print (125, 375, 0)
See :ref:`bind` for information on binding.
Anonymous PL/SQL Blocks
-----------------------
An anonymous PL/SQL block can be called as shown:
.. code-block:: python
var = cursor.var(int)
cursor.execute("""
begin
:out_val := length(:in_val);
end;""", in_val="A sample string", out_val=var)
print(var.getvalue()) # will print 15
See :ref:`bind` for information on binding.
Creating Stored Procedures and Packages
---------------------------------------
To create PL/SQL stored procedures and packages, use :meth:`Cursor.execute()`
with a SQL CREATE command.
Creation warning messages can be found from database views like USER_ERRORS.
For example, creating a procedure with an error could be like:
.. code-block:: python
with connection.cursor() as cursor:
cursor.execute("""
create or replace procedure badproc (a in number) as
begin
WRONG WRONG WRONG
end;""")
cursor.execute("""
select line, position, text
from user_errors
where name = 'BADPROC' and type = 'PROCEDURE'
order by name, type, line, position""")
errors = cursor.fetchall()
if errors:
for info in errors:
print("Error at line {} position {}:\n{}".format(*info))
else:
print("Created successfully")
The output would be::
PLS-00103: Encountered the symbol "WRONG" when expecting one of the following:
:= . ( @ % ;
Using DBMS_OUTPUT
-----------------
The standard way to print output from PL/SQL is with the package `DBMS_OUTPUT
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-C1400094-18D5-4F36-A2C9-D28B0E12FD8C>`__. Note, PL/SQL code that uses
``DBMS_OUTPUT`` runs to completion before any output is available to the user.
Also, other database connections cannot access the buffer.
To use DBMS_OUTPUT:
* Call the PL/SQL procedure ``DBMS_OUTPUT.ENABLE()`` to enable output to be
buffered for the connection.
* Execute some PL/SQL that calls ``DBMS_OUTPUT.PUT_LINE()`` to put text in the
buffer.
* Call ``DBMS_OUTPUT.GET_LINE()`` or ``DBMS_OUTPUT.GET_LINES()`` repeatedly to
fetch the text from the buffer until there is no more output.
For example:
.. code-block:: python
# enable DBMS_OUTPUT
cursor.callproc("dbms_output.enable")
# execute some PL/SQL that calls DBMS_OUTPUT.PUT_LINE
cursor.execute("""
begin
dbms_output.put_line('This is the cx_Oracle manual');
dbms_output.put_line('Demonstrating how to use DBMS_OUTPUT');
end;""")
# tune this size for your application
chunk_size = 100
# create variables to hold the output
lines_var = cursor.arrayvar(str, chunk_size)
num_lines_var = cursor.var(int)
num_lines_var.setvalue(0, chunk_size)
# fetch the text that was added by PL/SQL
while True:
cursor.callproc("dbms_output.get_lines", (lines_var, num_lines_var))
num_lines = num_lines_var.getvalue()
lines = lines_var.getvalue()[:num_lines]
for line in lines:
print(line or "")
if num_lines < chunk_size:
break
This will produce the following output::
This is the cx_Oracle manual
Demonstrating use of DBMS_OUTPUT
An alternative is to call ``DBMS_OUTPUT.GET_LINE()`` once per output line,
which may be much slower:
.. code-block:: python
text_var = cursor.var(str)
status_var = cursor.var(int)
while True:
cursor.callproc("dbms_output.get_line", (text_var, status_var))
if status_var.getvalue() != 0:
break
print(text_var.getvalue())
Implicit results
----------------
Implicit results permit a Python program to consume cursors returned by a
PL/SQL block without the requirement to use OUT REF CURSOR parameters. The
method :meth:`Cursor.getimplicitresults()` can be used for this purpose. It
requires both the Oracle Client and Oracle Database to be 12.1 or higher.
An example using implicit results is as shown:
.. code-block:: python
cursor.execute("""
declare
cust_cur sys_refcursor;
sales_cur sys_refcursor;
begin
open cust_cur for SELECT * FROM cust_table;
dbms_sql.return_result(cust_cur);
open sales_cur for SELECT * FROM sales_table;
dbms_sql.return_result(sales_cur);
end;""")
for implicit_cursor in cursor.getimplicitresults():
for row in implicit_cursor:
print(row)
Data from both the result sets are returned::
(1, 'Tom')
(2, 'Julia')
(1000, 1, 'BOOKS')
(2000, 2, 'FURNITURE')
.. _ebr:
Edition-Based Redefinition (EBR)
--------------------------------
Oracle Database's `Edition-Based Redefinition
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-58DE05A0-5DEF-4791-8FA8-F04D11964906>`__ feature enables upgrading of
the database component of an application while it is in use, thereby minimizing
or eliminating down time. This feature allows multiple versions of views,
synonyms, PL/SQL objects and SQL Translation profiles to be used concurrently.
Different versions of the database objects are associated with an "edition".
The simplest way to set an edition is to pass the ``edition`` parameter to
:meth:`cx_Oracle.connect()` or :meth:`cx_Oracle.SessionPool()`:
.. code-block:: python
connection = cx_Oracle.connect(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1",
edition="newsales", encoding="UTF-8")
The edition could also be set by setting the environment variable
``ORA_EDITION`` or by executing the SQL statement:
.. code-block:: sql
alter session set edition = <edition name>;
Regardless of which method is used to set the edition, the value that is in use
can be seen by examining the attribute :attr:`Connection.edition`. If no value
has been set, the value will be None. This corresponds to the database default
edition ``ORA$BASE``.
Consider an example where one version of a PL/SQL function ``Discount`` is
defined in the database default edition ``ORA$BASE`` and the other version of
the same function is defined in a user created edition ``DEMO``.
.. code-block:: sql
connect <username>/<password>
-- create function using the database default edition
CREATE OR REPLACE FUNCTION Discount(price IN NUMBER) RETURN NUMBER IS
BEGIN
return price * 0.9;
END;
/
A new edition named 'DEMO' is created and the user given permission to use
editions. The use of ``FORCE`` is required if the user already contains one or
more objects whose type is editionable and that also have non-editioned
dependent objects.
.. code-block:: sql
connect system/<password>
CREATE EDITION demo;
ALTER USER <username> ENABLE EDITIONS FORCE;
GRANT USE ON EDITION demo to <username>;
The ``Discount`` function for the demo edition is as follows:
.. code-block:: sql
connect <username>/<password>
alter session set edition = demo;
-- Function for the demo edition
CREATE OR REPLACE FUNCTION Discount(price IN NUMBER) RETURN NUMBER IS
BEGIN
return price * 0.5;
END;
/
The Python application can then call the required version of the PL/SQL
function as shown:
.. code-block:: python
connection = cx_Oracle.connect(user=user, password=password,
dsn="dbhost.example.com/orclpdb1",
encoding="UTF-8")
print("Edition is:", repr(connection.edition))
cursor = connection.cursor()
discounted_price = cursor.callfunc("Discount", int, [100])
print("Price after discount is:", discounted_price)
# Use the edition parameter for the connection
connection = cx_Oracle.connect(user=user, password=password,
dsn="dbhost.example.com/orclpdb1",
edition="demo", encoding="UTF-8")
print("Edition is:", repr(connection.edition))
cursor = connection.cursor()
discounted_price = cursor.callfunc("Discount", int, [100])
print("Price after discount is:", discounted_price)
The output of the function call for the default and demo edition is as shown::
Edition is: None
Price after discount is: 90
Edition is: 'DEMO'
Price after discount is: 50

216
doc/src/user_guide/soda.rst Normal file
View File

@ -0,0 +1,216 @@
.. _sodausermanual:
************************************
Simple Oracle Document Access (SODA)
************************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Overview
========
Oracle Database Simple Oracle Document Access (SODA) allows documents to be
inserted, queried, and retrieved from Oracle Database using a set of
NoSQL-style cx_Oracle methods. Documents are generally JSON data but they can
be any data at all (including video, images, sounds, or other binary content).
Documents can be fetched from the database by key lookup or by using
query-by-example (QBE) pattern-matching.
SODA uses a SQL schema to store documents but you do not need to know SQL or
how the documents are stored. However, access via SQL does allow use of
advanced Oracle Database functionality such as analytics for reporting.
Oracle SODA implementations are also available in `Node.js
<https://oracle.github.io/node-oracledb/doc/api.html#sodaoverview>`__, `Java
<https://docs.oracle.com/en/database/oracle/simple-oracle-document-access/java/adsda/index.html>`__,
`PL/SQL <https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=ADSDP>`__,
`Oracle Call Interface
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-23206C89-891E-43D7-827C-5C6367AD62FD>`__
and via `REST
<https://docs.oracle.com/en/database/oracle/simple-oracle-document-access/rest/index.html>`__.
For general information on SODA, see the `SODA home page
<https://docs.oracle.com/en/database/oracle/simple-oracle-document-access/index.html>`__
and the Oracle Database `Introduction to Simple Oracle Document Access (SODA)
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=ADSDI>`__ manual.
For specific requirements see the cx_Oracle :ref:`SODA requirements <sodarequirements>`.
cx_Oracle uses the following objects for SODA:
* :ref:`SODA Database Object <sodadb>`: The top level object for cx_Oracle SODA
operations. This is acquired from an Oracle Database connection. A 'SODA
database' is an abstraction, allowing access to SODA collections in that
'SODA database', which then allow access to documents in those collections.
A SODA database is analogous to an Oracle Database user or schema, a
collection is analogous to a table, and a document is analogous to a table
row with one column for a unique document key, a column for the document
content, and other columns for various document attributes.
* :ref:`SODA Collection Object <sodacoll>`: Represents a collection of SODA
documents. By default, collections allow JSON documents to be stored. This
is recommended for most SODA users. However optional metadata can set
various details about a collection, such as its database storage, whether it
should track version and time stamp document components, how such components
are generated, and what document types are supported. By default, the name of
the Oracle Database table storing a collection is the same as the collection
name. Note: do not use SQL to drop the database table, since SODA metadata
will not be correctly removed. Use the :meth:`SodaCollection.drop()` method
instead.
* :ref:`SODA Document Object <sodadoc>`: Represents a document. Typically the
document content will be JSON. The document has properties including the
content, a key, timestamps, and the media type. By default, document keys
are automatically generated. See :ref:`SODA Document objects <sodadoc>` for
the forms of SodaDoc.
* :ref:`SODA Document Cursor <sodadoccur>`: A cursor object representing the
result of the :meth:`SodaOperation.getCursor()` method from a
:meth:`SodaCollection.find()` operation. It can be iterated over to access
each SodaDoc.
* :ref:`SODA Operation Object <sodaop>`: An internal object used with
:meth:`SodaCollection.find()` to perform read and write operations on
documents. Chained methods set properties on a SodaOperation object which is
then used by a terminal method to find, count, replace, or remove documents.
This is an internal object that should not be directly accessed.
SODA Examples
=============
Creating and adding documents to a collection can be done as follows:
.. code-block:: python
soda = connection.getSodaDatabase()
# create a new SODA collection; this will open an existing collection, if
# the name is already in use
collection = soda.createCollection("mycollection")
# insert a document into the collection; for the common case of a JSON
# document, the content can be a simple Python dictionary which will
# internally be converted to a JSON document
content = {'name': 'Matilda', 'address': {'city': 'Melbourne'}}
returned_doc = collection.insertOneAndGet(content)
key = returned_doc.key
print('The key of the new SODA document is: ', key)
By default, a system generated key is created when documents are inserted.
With a known key, you can retrieve a document:
.. code-block:: python
# this will return a dictionary (as was inserted in the previous code)
content = collection.find().key(key).getOne().getContent()
print(content)
You can also search for documents using query-by-example syntax:
.. code-block:: python
# Find all documents with names like 'Ma%'
print("Names matching 'Ma%'")
qbe = {'name': {'$like': 'Ma%'}}
for doc in collection.find().filter(qbe).getDocuments():
content = doc.getContent()
print(content["name"])
See the `samples directory
<https://github.com/oracle/python-cx_Oracle/tree/main/samples>`__
for runnable SODA examples.
.. _sodametadatacache:
Using the SODA Metadata Cache
=============================
SODA metadata can be cached to improve the performance of
:meth:`SodaDatabase.createCollection()` and
:meth:`SodaDatabase.openCollection()` by reducing :ref:`round-trips
<roundtrips>` to the database. Caching is available with Oracle Client 21.3 (or
later). The feature is also available in Oracle Client 19 from 19.11 onwards.
The metadata cache can be turned on when creating a connection pool with
:meth:`cx_Oracle.SessionPool()`. Each pool has its own cache:
.. code-block:: python
# Create the session pool
pool = cx_Oracle.SessionPool(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1",
soda_metadata_cache=True)
The cache is not available for standalone connections. Applications using these
should retain and reuse the :ref:`collection <sodacoll>` returned from
``createCollection()`` or ``openCollection()`` wherever possible, instead of
making repeated calls to those methods.
The cache is not used by ``createCollection()`` when explicitly passing
metadata. In this case, instead of using only ``createCollection()`` and
relying on its behavior of opening an existing collection like:
.. code-block:: python
mymetadata = { . . . }
collection = soda.createCollection("mycollection", mymetadata) # open existing or create new collection
collection.insertOne(mycontent)
you will find it more efficient to use logic similar to:
.. code-block:: python
collection = soda.openCollection("mycollection")
if collection is None:
mymetadata = { . . . }
collection = soda.createCollection("mycollection", mymetadata)
collection.insertOne(mycontent)
If collection metadata changes are made externally, the cache can become
invalid. If this happens, the cache can be cleared by calling
:meth:`SessionPool.reconfigure()` with ``soda_metadata_cache`` set to `False`,
or by setting the attribute :attr:`SessionPool.soda_metadata_cache` to `False`.
Use a second call to ``reconfigure()`` or set ``soda_metadata_cache`` to
re-enable the cache.
Committing SODA Work
====================
The general recommendation for SODA applications is to turn on
:attr:`~Connection.autocommit` globally:
.. code-block:: python
connection.autocommit = True
If your SODA document write operations are mostly independent of each other,
this removes the overhead of application transaction management and the need for
explicit :meth:`Connection.commit()` calls.
When deciding how to commit transactions, beware of transactional consistency
and performance requirements. If you are using individual SODA calls to insert
or update a large number of documents with individual calls, you should turn
:attr:`~Connection.autocommit` off and issue a single, explicit
:meth:`~Connection.commit()` after all documents have been processed. Also
consider using :meth:`SodaCollection.insertMany()` or
:meth:`SodaCollection.insertManyAndGet()` which have performance benefits.
If you are not autocommitting, and one of the SODA operations in your
transaction fails, then previous uncommitted operations will not be rolled back.
Your application should explicitly roll back the transaction with
:meth:`Connection.rollback()` to prevent any later commits from committing a
partial transaction.
Note:
- SODA DDL operations do not commit an open transaction the way that SQL always does for DDL statements.
- When :attr:`~Connection.autocommit` is ``True``, most SODA methods will issue a commit before successful return.
- SODA provides optimistic locking, see :meth:`SodaOperation.version()`.
- When mixing SODA and relational access, any commit or rollback on the connection will affect all work.

View File

@ -0,0 +1,812 @@
.. _sqlexecution:
*************
SQL Execution
*************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Executing SQL statements is the primary way in which a Python application
communicates with Oracle Database. Statements are executed using the methods
:meth:`Cursor.execute()` or :meth:`Cursor.executemany()`. Statements include
queries, Data Manipulation Language (DML), and Data Definition Language (DDL).
A few other `specialty statements
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-E1749EF5-2264-44DF-99EF-AEBEB943BED6>`__ can also be executed.
PL/SQL statements are discussed in :ref:`plsqlexecution`. Other chapters
contain information on specific data types and features. See :ref:`batchstmnt`,
:ref:`lobdata`, :ref:`jsondatatype`, and :ref:`xmldatatype`.
cx_Oracle can be used to execute individual statements, one at a time. It does
not read SQL*Plus ".sql" files. To read SQL files, use a technique like the one
in ``run_sql_script()`` in `samples/sample_env.py
<https://github.com/oracle/python-cx_Oracle/blob/main/samples/sample_env.py>`__
SQL statements should not contain a trailing semicolon (";") or forward slash
("/"). This will fail:
.. code-block:: python
cur.execute("select * from MyTable;")
This is correct:
.. code-block:: python
cur.execute("select * from MyTable")
SQL Queries
===========
Queries (statements beginning with SELECT or WITH) can only be executed using
the method :meth:`Cursor.execute()`. Rows can then be iterated over, or can be
fetched using one of the methods :meth:`Cursor.fetchone()`,
:meth:`Cursor.fetchmany()` or :meth:`Cursor.fetchall()`. There is a
:ref:`default type mapping <defaultfetchtypes>` to Python types that can be
optionally :ref:`overridden <outputtypehandlers>`.
.. IMPORTANT::
Interpolating or concatenating user data with SQL statements, for example
``cur.execute("SELECT * FROM mytab WHERE mycol = '" + myvar + "'")``, is a security risk
and impacts performance. Use :ref:`bind variables <bind>` instead. For
example, ``cur.execute("SELECT * FROM mytab WHERE mycol = :mybv", mybv=myvar)``.
.. _fetching:
Fetch Methods
-------------
After :meth:`Cursor.execute()`, the cursor is returned as a convenience. This
allows code to iterate over rows like:
.. code-block:: python
cur = connection.cursor()
for row in cur.execute("select * from MyTable"):
print(row)
Rows can also be fetched one at a time using the method
:meth:`Cursor.fetchone()`:
.. code-block:: python
cur = connection.cursor()
cur.execute("select * from MyTable")
while True:
row = cur.fetchone()
if row is None:
break
print(row)
If rows need to be processed in batches, the method :meth:`Cursor.fetchmany()`
can be used. The size of the batch is controlled by the ``numRows`` parameter,
which defaults to the value of :attr:`Cursor.arraysize`.
.. code-block:: python
cur = connection.cursor()
cur.execute("select * from MyTable")
num_rows = 10
while True:
rows = cur.fetchmany(num_rows)
if not rows:
break
for row in rows:
print(row)
If all of the rows need to be fetched, and can be contained in memory, the
method :meth:`Cursor.fetchall()` can be used.
.. code-block:: python
cur = connection.cursor()
cur.execute("select * from MyTable")
rows = cur.fetchall()
for row in rows:
print(row)
The fetch methods return data as tuples. To return results as dictionaries, see
:ref:`rowfactories`.
Closing Cursors
---------------
A cursor may be used to execute multiple statements. Once it is no longer
needed, it should be closed by calling :meth:`~Cursor.close()` in order to
reclaim resources in the database. It will be closed automatically when the
variable referencing it goes out of scope (and no further references are
retained). One other way to control the lifetime of a cursor is to use a "with"
block, which ensures that a cursor is closed once the block is completed. For
example:
.. code-block:: python
with connection.cursor() as cursor:
for row in cursor.execute("select * from MyTable"):
print(row)
This code ensures that, once the block is completed, the cursor is closed and
resources have been reclaimed by the database. In addition, any attempt to use
the variable ``cursor`` outside of the block will simply fail.
.. _querymetadata:
Query Column Metadata
---------------------
After executing a query, the column metadata such as column names and data types
can be obtained using :attr:`Cursor.description`:
.. code-block:: python
cur = connection.cursor()
cur.execute("select * from MyTable")
for column in cur.description:
print(column)
This could result in metadata like::
('ID', <class 'cx_Oracle.DB_TYPE_NUMBER'>, 39, None, 38, 0, 0)
('NAME', <class 'cx_Oracle.DB_TYPE_VARCHAR'>, 20, 20, None, None, 1)
.. _defaultfetchtypes:
Fetch Data Types
----------------
The following table provides a list of all of the data types that cx_Oracle
knows how to fetch. The middle column gives the type that is returned in the
:ref:`query metadata <querymetadata>`. The last column gives the type of
Python object that is returned by default. Python types can be changed with
:ref:`Output Type Handlers <outputtypehandlers>`.
.. list-table::
:header-rows: 1
:widths: 1 1 1
:align: left
* - Oracle Database Type
- cx_Oracle Database Type
- Default Python type
* - BFILE
- :attr:`cx_Oracle.DB_TYPE_BFILE`
- :ref:`cx_Oracle.LOB <lobobj>`
* - BINARY_DOUBLE
- :attr:`cx_Oracle.DB_TYPE_BINARY_DOUBLE`
- float
* - BINARY_FLOAT
- :attr:`cx_Oracle.DB_TYPE_BINARY_FLOAT`
- float
* - BLOB
- :attr:`cx_Oracle.DB_TYPE_BLOB`
- :ref:`cx_Oracle.LOB <lobobj>`
* - CHAR
- :attr:`cx_Oracle.DB_TYPE_CHAR`
- str
* - CLOB
- :attr:`cx_Oracle.DB_TYPE_CLOB`
- :ref:`cx_Oracle.LOB <lobobj>`
* - CURSOR
- :attr:`cx_Oracle.DB_TYPE_CURSOR`
- :ref:`cx_Oracle.Cursor <cursorobj>`
* - DATE
- :attr:`cx_Oracle.DB_TYPE_DATE`
- datetime.datetime
* - INTERVAL DAY TO SECOND
- :attr:`cx_Oracle.DB_TYPE_INTERVAL_DS`
- datetime.timedelta
* - JSON
- :attr:`cx_Oracle.DB_TYPE_JSON`
- dict, list or a scalar value [4]_
* - LONG
- :attr:`cx_Oracle.DB_TYPE_LONG`
- str
* - LONG RAW
- :attr:`cx_Oracle.DB_TYPE_LONG_RAW`
- bytes
* - NCHAR
- :attr:`cx_Oracle.DB_TYPE_NCHAR`
- str
* - NCLOB
- :attr:`cx_Oracle.DB_TYPE_NCLOB`
- :ref:`cx_Oracle.LOB <lobobj>`
* - NUMBER
- :attr:`cx_Oracle.DB_TYPE_NUMBER`
- float or int [1]_
* - NVARCHAR2
- :attr:`cx_Oracle.DB_TYPE_NVARCHAR`
- str
* - OBJECT [3]_
- :attr:`cx_Oracle.DB_TYPE_OBJECT`
- :ref:`cx_Oracle.Object <objecttype>`
* - RAW
- :attr:`cx_Oracle.DB_TYPE_RAW`
- bytes
* - ROWID
- :attr:`cx_Oracle.DB_TYPE_ROWID`
- str
* - TIMESTAMP
- :attr:`cx_Oracle.DB_TYPE_TIMESTAMP`
- datetime.datetime
* - TIMESTAMP WITH LOCAL TIME ZONE
- :attr:`cx_Oracle.DB_TYPE_TIMESTAMP_LTZ`
- datetime.datetime [2]_
* - TIMESTAMP WITH TIME ZONE
- :attr:`cx_Oracle.DB_TYPE_TIMESTAMP_TZ`
- datetime.datetime [2]_
* - UROWID
- :attr:`cx_Oracle.DB_TYPE_ROWID`
- str
* - VARCHAR2
- :attr:`cx_Oracle.DB_TYPE_VARCHAR`
- str
.. [1] If the precision and scale obtained from query column metadata indicate
that the value can be expressed as an integer, the value will be
returned as an int. If the column is unconstrained (no precision and
scale specified), the value will be returned as a float or an int
depending on whether the value itself is an integer. In all other cases
the value is returned as a float.
.. [2] The timestamps returned are naive timestamps without any time zone
information present.
.. [3] These include all user-defined types such as VARRAY, NESTED TABLE, etc.
.. [4] If the JSON is an object, then a dict is returned. If it is an array,
then a list is returned. If it is a scalar value, then that particular
scalar value is returned.
.. _outputtypehandlers:
Changing Fetched Data Types with Output Type Handlers
-----------------------------------------------------
Sometimes the default conversion from an Oracle Database type to a Python type
must be changed in order to prevent data loss or to fit the purposes of the
Python application. In such cases, an output type handler can be specified for
queries. Output type handlers do not affect values returned from
:meth:`Cursor.callfunc()` or :meth:`Cursor.callproc()`.
Output type handlers can be specified on the :attr:`connection
<Connection.outputtypehandler>` or on the :attr:`cursor
<Cursor.outputtypehandler>`. If specified on the cursor, fetch type handling is
only changed on that particular cursor. If specified on the connection, all
cursors created by that connection will have their fetch type handling changed.
The output type handler is expected to be a function with the following
signature::
handler(cursor, name, defaultType, size, precision, scale)
The parameters are the same information as the query column metadata found in
:attr:`Cursor.description`. The function is called once for each column that is
going to be fetched. The function is expected to return a
:ref:`variable object <varobj>` (generally by a call to :func:`Cursor.var()`)
or the value ``None``. The value ``None`` indicates that the default type
should be used.
Examples of output handlers are shown in :ref:`numberprecision`,
:ref:`directlobs` and :ref:`fetching-raw-data`. Also see samples such as `samples/type_handlers.py
<https://github.com/oracle/python-cx_Oracle/blob/main/samples/type_handlers.py>`__
.. _numberprecision:
Fetched Number Precision
------------------------
One reason for using an output type handler is to ensure that numeric precision
is not lost when fetching certain numbers. Oracle Database uses decimal numbers
and these cannot be converted seamlessly to binary number representations like
Python floats. In addition, the range of Oracle numbers exceeds that of
floating point numbers. Python has decimal objects which do not have these
limitations and cx_Oracle knows how to perform the conversion between Oracle
numbers and Python decimal values if directed to do so.
The following code sample demonstrates the issue:
.. code-block:: python
cur = connection.cursor()
cur.execute("create table test_float (X number(5, 3))")
cur.execute("insert into test_float values (7.1)")
connection.commit()
cur.execute("select * from test_float")
val, = cur.fetchone()
print(val, "* 3 =", val * 3)
This displays ``7.1 * 3 = 21.299999999999997``
Using Python decimal objects, however, there is no loss of precision:
.. code-block:: python
import decimal
def number_to_decimal(cursor, name, default_type, size, precision, scale):
if default_type == cx_Oracle.DB_TYPE_NUMBER:
return cursor.var(decimal.Decimal, arraysize=cursor.arraysize)
cur = connection.cursor()
cur.outputtypehandler = number_to_decimal
cur.execute("select * from test_float")
val, = cur.fetchone()
print(val, "* 3 =", val * 3)
This displays ``7.1 * 3 = 21.3``
The Python ``decimal.Decimal`` converter gets called with the string
representation of the Oracle number. The output from ``decimal.Decimal`` is
returned in the output tuple.
See `samples/return_numbers_as_decimals.py
<https://github.com/oracle/python-cx_Oracle/blob/main/samples/return_numbers_as_decimals.py>`__
.. _outconverters:
Changing Query Results with Outconverters
-----------------------------------------
cx_Oracle "outconverters" can be used with :ref:`output type handlers
<outputtypehandlers>` to change returned data.
For example, to make queries return empty strings instead of NULLs:
.. code-block:: python
def out_converter(value):
if value is None:
return ''
return value
def output_type_handler(cursor, name, default_type, size, precision, scale):
if default_type in (cx_Oracle.DB_TYPE_VARCHAR, cx_Oracle.DB_TYPE_CHAR):
return cursor.var(str, size, arraysize=cur.arraysize,
outconverter=out_converter)
connection.outputtypehandler = output_type_handler
.. _rowfactories:
Changing Query Results with Rowfactories
----------------------------------------
cx_Oracle "rowfactories" are methods called for each row that is retrieved from
the database. The :meth:`Cursor.rowfactory` method is called with the tuple that
would normally be returned from the database. The method can convert the tuple
to a different value and return it to the application in place of the tuple.
For example, to fetch each row of a query as a dictionary:
.. code-block:: python
cursor.execute("select * from locations where location_id = 1000")
columns = [col[0] for col in cursor.description]
cursor.rowfactory = lambda *args: dict(zip(columns, args))
data = cursor.fetchone()
print(data)
The output is::
{'LOCATION_ID': 1000, 'STREET_ADDRESS': '1297 Via Cola di Rie', 'POSTAL_CODE': '00989', 'CITY': 'Roma', 'STATE_PROVINCE': None, 'COUNTRY_ID': 'IT'}
If you join tables where the same column name occurs in both tables with
different meanings or values, then use a column alias in the query. Otherwise
only one of the similarly named columns will be included in the dictionary:
.. code-block:: sql
select
cat_name,
cats.color as cat_color,
dog_name,
dogs.color
from cats, dogs
.. _scrollablecursors:
Scrollable Cursors
------------------
Scrollable cursors enable applications to move backwards, forwards, to skip
rows, and to move to a particular row in a query result set. The result set is
cached on the database server until the cursor is closed. In contrast, regular
cursors are restricted to moving forward.
A scrollable cursor is created by setting the parameter ``scrollable=True``
when creating the cursor. The method :meth:`Cursor.scroll()` is used to move to
different locations in the result set.
Examples are:
.. code-block:: python
cursor = connection.cursor(scrollable=True)
cursor.execute("select * from ChildTable order by ChildId")
cursor.scroll(mode="last")
print("LAST ROW:", cursor.fetchone())
cursor.scroll(mode="first")
print("FIRST ROW:", cursor.fetchone())
cursor.scroll(8, mode="absolute")
print("ROW 8:", cursor.fetchone())
cursor.scroll(6)
print("SKIP 6 ROWS:", cursor.fetchone())
cursor.scroll(-4)
print("SKIP BACK 4 ROWS:", cursor.fetchone())
.. _fetchobjects:
Fetching Oracle Database Objects and Collections
------------------------------------------------
Oracle Database named object types and user-defined types can be fetched
directly in queries. Each item is represented as a :ref:`Python object
<objecttype>` corresponding to the Oracle Database object. This Python object
can be traversed to access its elements. Attributes including
:attr:`ObjectType.name` and :attr:`ObjectType.iscollection`, and methods
including :meth:`Object.aslist` and :meth:`Object.asdict` are available.
For example, if a table ``mygeometrytab`` contains a column ``geometry`` of
Oracle's predefined Spatial object type `SDO_GEOMETRY
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-683FF8C5-A773-4018-932D-2AF6EC8BC119>`__,
then it can be queried and printed:
.. code-block:: python
cur.execute("select geometry from mygeometrytab")
for obj, in cur:
dumpobject(obj)
Where ``dumpobject()`` is defined as:
.. code-block:: python
def dumpobject(obj, prefix = ""):
if obj.type.iscollection:
print(prefix, "[")
for value in obj.aslist():
if isinstance(value, cx_Oracle.Object):
dumpobject(value, prefix + " ")
else:
print(prefix + " ", repr(value))
print(prefix, "]")
else:
print(prefix, "{")
for attr in obj.type.attributes:
value = getattr(obj, attr.name)
if isinstance(value, cx_Oracle.Object):
print(prefix + " " + attr.name + ":")
dumpobject(value, prefix + " ")
else:
print(prefix + " " + attr.name + ":", repr(value))
print(prefix, "}")
This might produce output like::
{
SDO_GTYPE: 2003
SDO_SRID: None
SDO_POINT:
{
X: 1
Y: 2
Z: 3
}
SDO_ELEM_INFO:
[
1
1003
3
]
SDO_ORDINATES:
[
1
1
5
7
]
}
Other information on using Oracle objects is in :ref:`Using Bind Variables
<bind>`.
Performance-sensitive applications should consider using scalar types instead of
objects. If you do use objects, avoid calling :meth:`Connection.gettype()`
unnecessarily, and avoid objects with large numbers of attributes.
.. _rowlimit:
Limiting Rows
-------------
Query data is commonly broken into one or more sets:
- To give an upper bound on the number of rows that a query has to process,
which can help improve database scalability.
- To perform 'Web pagination' that allows moving from one set of rows to a
next, or previous, set on demand.
- For fetching of all data in consecutive small sets for batch processing.
This happens because the number of records is too large for Python to handle
at one time.
The latter can be handled by calling :meth:`Cursor.fetchmany()` with one
execution of the SQL query.
'Web pagination' and limiting the maximum number of rows are discussed in this
section. For each 'page' of results, a SQL query is executed to get the
appropriate set of rows from a table. Since the query may be executed more
than once, make sure to use :ref:`bind variables <bind>` for row numbers and
row limits.
Oracle Database 12c SQL introduced an ``OFFSET`` / ``FETCH`` clause which is
similar to the ``LIMIT`` keyword of MySQL. In Python you can fetch a set of
rows using:
.. code-block:: python
myoffset = 0 // do not skip any rows (start at row 1)
mymaxnumrows = 20 // get 20 rows
sql =
"""SELECT last_name
FROM employees
ORDER BY last_name
OFFSET :offset ROWS FETCH NEXT :maxnumrows ROWS ONLY"""
cur = connection.cursor()
for row in cur.execute(sql, offset=myoffset, maxnumrows=mymaxnumrows):
print(row)
In applications where the SQL query is not known in advance, this method
sometimes involves appending the ``OFFSET`` clause to the 'real' user query. Be
very careful to avoid SQL injection security issues.
For Oracle Database 11g and earlier there are several alternative ways
to limit the number of rows returned. The old, canonical paging query
is::
SELECT *
FROM (SELECT a.*, ROWNUM AS rnum
FROM (YOUR_QUERY_GOES_HERE -- including the order by) a
WHERE ROWNUM <= MAX_ROW)
WHERE rnum >= MIN_ROW
Here, ``MIN_ROW`` is the row number of first row and ``MAX_ROW`` is the row
number of the last row to return. For example::
SELECT *
FROM (SELECT a.*, ROWNUM AS rnum
FROM (SELECT last_name FROM employees ORDER BY last_name) a
WHERE ROWNUM <= 20)
WHERE rnum >= 1
This always has an 'extra' column, here called RNUM.
An alternative and preferred query syntax for Oracle Database 11g uses the
analytic ``ROW_NUMBER()`` function. For example to get the 1st to 20th names the
query is::
SELECT last_name FROM
(SELECT last_name,
ROW_NUMBER() OVER (ORDER BY last_name) AS myr
FROM employees)
WHERE myr BETWEEN 1 and 20
Make sure to use :ref:`bind variables <bind>` for the upper and lower limit
values.
.. _crc:
Client Result Cache
-------------------
Python cx_Oracle applications can use Oracle Database's `Client Result Cache
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-35CB2592-7588-4C2D-9075-6F639F25425E>`__
The CRC enables client-side caching of SQL query (SELECT statement) results in
client memory for immediate use when the same query is re-executed. This is
useful for reducing the cost of queries for small, mostly static, lookup tables,
such as for postal codes. CRC reduces network :ref:`round-trips <roundtrips>`,
and also reduces database server CPU usage.
The cache is at the application process level. Access and invalidation is
managed by the Oracle Client libraries. This removes the need for extra
application logic, or external utilities, to implement a cache.
CRC can be enabled by setting the `database parameters
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-A9D4A5F5-B939-48FF-80AE-0228E7314C7D>`__
``CLIENT_RESULT_CACHE_SIZE`` and ``CLIENT_RESULT_CACHE_LAG``, and then
restarting the database. For example, to set the parameters:
.. code-block:: sql
SQL> ALTER SYSTEM SET CLIENT_RESULT_CACHE_LAG = 3000 SCOPE=SPFILE;
SQL> ALTER SYSTEM SET CLIENT_RESULT_CACHE_SIZE = 64K SCOPE=SPFILE;
CRC can alternatively be configured in an :ref:`oraaccess.xml <optclientfiles>`
or :ref:`sqlnet.ora <optnetfiles>` file on the Python host, see `Client
Configuration Parameters
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-E63D75A1-FCAA-4A54-A3D2-B068442CE766>`__.
Tables can then be created, or altered, so repeated queries use CRC. This
allows existing applications to use CRC without needing modification. For example:
.. code-block:: sql
SQL> CREATE TABLE cities (id number, name varchar2(40)) RESULT_CACHE (MODE FORCE);
SQL> ALTER TABLE locations RESULT_CACHE (MODE FORCE);
Alternatively, hints can be used in SQL statements. For example:
.. code-block:: sql
SELECT /*+ result_cache */ postal_code FROM locations
.. _fetching-raw-data:
Fetching Raw Data
-----------------
Sometimes cx_Oracle may have problems converting data stored in the database to
Python strings. This can occur if the data stored in the database doesn't match
the character set defined by the database. The `encoding_errors` parameter to
:meth:`Cursor.var()` permits the data to be returned with some invalid data
replaced, but for additional control the parameter `bypass_decode` can be set
to `True` and cx_Oracle will bypass the decode step and return `bytes` instead
of `str` for data stored in the database as strings. The data can then be
examined and corrected as required. This approach should only be used for
troubleshooting and correcting invalid data, not for general use!
The following sample demonstrates how to use this feature:
.. code-block:: python
# define output type handler
def return_strings_as_bytes(cursor, name, default_type, size,
precision, scale):
if default_type == cx_Oracle.DB_TYPE_VARCHAR:
return cursor.var(str, arraysize=cursor.arraysize,
bypass_decode=True)
# set output type handler on cursor before fetching data
with connection.cursor() as cursor:
cursor.outputtypehandler = return_strings_as_bytes
cursor.execute("select content, charset from SomeTable")
data = cursor.fetchall()
This will produce output as::
[(b'Fianc\xc3\xa9', b'UTF-8')]
Note that last ``\xc3\xa9`` is é in UTF-8. Since this is valid UTF-8 you can then
perform a decode on the data (the part that was bypassed):
.. code-block:: python
value = data[0][0].decode("UTF-8")
This will return the value "Fiancé".
If you want to save ``b'Fianc\xc3\xa9'`` into the database directly without
using a Python string, you will need to create a variable using
:meth:`Cursor.var()` that specifies the type as
:data:`~cx_Oracle.DB_TYPE_VARCHAR` (otherwise the value will be treated as
:data:`~cx_Oracle.DB_TYPE_RAW`). The following sample demonstrates this:
.. code-block:: python
with cx_Oracle.connect(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1") as conn:
with conn.cursor() cursor:
var = cursor.var(cx_Oracle.DB_TYPE_VARCHAR)
var.setvalue(0, b"Fianc\xc4\x9b")
cursor.execute("""
update SomeTable set
SomeColumn = :param
where id = 1""",
param=var)
.. warning::
The database will assume that the bytes provided are in the character set
expected by the database so only use this for troubleshooting or as
directed.
.. _codecerror:
Querying Corrupt Data
---------------------
If queries fail with the error "codec can't decode byte" when you select data,
then:
* Check your :ref:`character set <globalization>` is correct. Review the
:ref:`client and database character sets <findingcharset>`. Check with
:ref:`fetching-raw-data`. Consider using UTF-8, if this is appropriate:
.. code-block:: python
connection = cx_Oracle.connect(user="hr", password=userpwd,
dsn="dbhost.example.com/orclpdb1",
encoding="UTF-8", nencoding="UTF-8")
* Check for corrupt data in the database.
If data really is corrupt, you can pass options to the internal `decode()
<https://docs.python.org/3/library/stdtypes.html#bytes.decode>`__ used by
cx_Oracle to allow it to be selected and prevent the whole query failing. Do
this by creating an :ref:`outputtypehandler <outputtypehandlers>` and setting
``encoding_errors``. For example to replace corrupt characters in character
columns:
.. code-block:: python
def output_type_handler(cursor, name, default_type, size, precision, scale):
if default_type == cx_Oracle.DB_TYPE_VARCHAR:
return cursor.var(default_type, size, arraysize=cursor.arraysize,
encoding_errors="replace")
cursor.outputtypehandler = output_type_handler
cursor.execute("select column1, column2 from SomeTableWithBadData")
Other codec behaviors can be chosen for ``encoding_errors``, see `Error Handlers
<https://docs.python.org/3/library/codecs.html#error-handlers>`__.
.. _dml:
INSERT and UPDATE Statements
============================
SQL Data Manipulation Language statements (DML) such as INSERT and UPDATE can
easily be executed with cx_Oracle. For example:
.. code-block:: python
cur = connection.cursor()
cur.execute("insert into MyTable values (:idbv, :nmbv)", [1, "Fredico"])
Do not concatenate or interpolate user data into SQL statements. See
:ref:`bind` instead.
See :ref:`txnmgmnt` for best practices on committing and rolling back data
changes.
When handling multiple data values, use :meth:`~Cursor.executemany()` for
performance. See :ref:`batchstmnt`
Inserting NULLs
---------------
Oracle requires a type, even for null values. When you pass the value None, then
cx_Oracle assumes the type is STRING. If this is not the desired type, you can
explicitly set it. For example, to insert a null :ref:`Oracle Spatial
SDO_GEOMETRY <spatial>` object:
.. code-block:: python
type_obj = connection.gettype("SDO_GEOMETRY")
cur = connection.cursor()
cur.setinputsizes(type_obj)
cur.execute("insert into sometable values (:1)", [None])

View File

@ -0,0 +1,69 @@
.. _startup:
*************************************
Starting and Stopping Oracle Database
*************************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
This chapter covers how to start up and shutdown Oracle Database using
cx_Oracle.
===========================
Starting Oracle Database Up
===========================
cx_Oracle can start up a database instance. A privileged connection is
required. This example shows a script that could be run as the 'oracle'
operating system user who administers a local database installation on Linux.
It assumes that the environment variable ``ORACLE_SID`` has been set to the SID
of the database that should be started:
.. code-block:: python
# the connection must be in PRELIM_AUTH mode to perform startup
connection = cx_Oracle.connect(mode=cx_Oracle.SYSDBA | cx_Oracle.PRELIM_AUTH)
connection.startup()
# the following statements must be issued in normal SYSDBA mode
connection = cx_Oracle.connect(mode=cx_Oracle.SYSDBA, encoding="UTF-8")
cursor = connection.cursor()
cursor.execute("alter database mount")
cursor.execute("alter database open")
To start up a remote database, you may need to configure the Oracle Net
listener to use `static service registration
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-0203C8FA-A4BE-44A5-9A25-3D1E578E879F>`_
by adding a ``SID_LIST_LISTENER`` entry to the database `listener.ora` file.
=============================
Shutting Oracle Database Down
=============================
cx_Oracle has the ability to shutdown the database using a privileged
connection. This example also assumes that the environment variable
``ORACLE_SID`` has been set:
.. code-block:: python
# need to connect as SYSDBA or SYSOPER
connection = cx_Oracle.connect(mode=cx_Oracle.SYSDBA)
# first shutdown() call must specify the mode, if DBSHUTDOWN_ABORT is used,
# there is no need for any of the other steps
connection.shutdown(mode=cx_Oracle.DBSHUTDOWN_IMMEDIATE)
# now close and dismount the database
cursor = connection.cursor()
cursor.execute("alter database close normal")
cursor.execute("alter database dismount")
# perform the final shutdown call
connection.shutdown(mode=cx_Oracle.DBSHUTDOWN_FINAL)

View File

@ -0,0 +1,175 @@
.. _tracingsql:
*********************************
Tracing SQL and PL/SQL Statements
*********************************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Subclass Connections
====================
Subclassing enables applications to add "hooks" for connection and statement
execution. This can be used to alter, or log, connection and execution
parameters, and to extend cx_Oracle functionality.
The example below demonstrates subclassing a connection to log SQL execution
to a file. This example also shows how connection credentials can be embedded
in the custom subclass, so application code does not need to supply them.
.. code-block:: python
class Connection(cx_Oracle.Connection):
log_file_name = "log.txt"
def __init__(self):
connect_string = "hr/hr_password@dbhost.example.com/orclpdb1"
self._log("Connect to the database")
return super(Connection, self).__init__(connect_string)
def _log(self, message):
with open(self.log_file_name, "a") as f:
print(message, file=f)
def execute(self, sql, parameters):
self._log(sql)
cursor = self.cursor()
try:
return cursor.execute(sql, parameters)
except cx_Oracle.Error as e:
error_obj, = e.args
self._log(error_obj.message)
raise
connection = Connection()
connection.execute("""
select department_name
from departments
where department_id = :id""", dict(id=270))
The messages logged in ``log.txt`` are::
Connect to the database
select department_name
from departments
where department_id = :id
If an error occurs, perhaps due to a missing table, the log file would contain
instead::
Connect to the database
select department_name
from departments
where department_id = :id
ORA-00942: table or view does not exist
In production applications be careful not to log sensitive information.
See `Subclassing.py
<https://github.com/oracle/python-cx_Oracle/blob/main/
samples/subclassing.py>`__ for an example.
.. _endtoendtracing:
Oracle Database End-to-End Tracing
==================================
Oracle Database End-to-end application tracing simplifies diagnosing application
code flow and performance problems in multi-tier or multi-user environments.
The connection attributes, :attr:`~Connection.client_identifier`,
:attr:`~Connection.clientinfo`, :attr:`~Connection.dbop`,
:attr:`~Connection.module` and :attr:`~Connection.action`, set the metadata for
end-to-end tracing. You can use data dictionary and ``V$`` views to monitor
tracing or use other application tracing utilities.
The attributes are sent to the database when the next :ref:`round-trip
<roundtrips>` to the database occurs, for example when the next SQL statement is
executed.
The attribute values will remain set in connections released back to connection
pools. When the application re-acquires a connection from the pool it should
initialize the values to a desired state before using that connection.
The example below shows setting the action, module and client identifier
attributes on the connection object:
.. code-block:: python
# Set the tracing metadata
connection.client_identifier = "pythonuser"
connection.action = "Query Session tracing parameters"
connection.module = "End-to-end Demo"
for row in cursor.execute("""
SELECT username, client_identifier, module, action
FROM V$SESSION
WHERE username = 'SYSTEM'"""):
print(row)
The output will be::
('SYSTEM', 'pythonuser', 'End-to-end Demo', 'Query Session tracing parameters')
The values can also be manually set as shown by calling
`DBMS_APPLICATION_INFO procedures
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-14484F86-44F2-4B34-B34E-0C873D323EAD>`__
or `DBMS_SESSION.SET_IDENTIFIER
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&
id=GUID-988EA930-BDFE-4205-A806-E54F05333562>`__. These incur round-trips to
the database, however, reducing scalability.
.. code-block:: sql
BEGIN
DBMS_SESSION.SET_IDENTIFIER('pythonuser');
DBMS_APPLICATION_INFO.set_module('End-to-End Demo');
DBMS_APPLICATION_INFO.set_action(action_name => 'Query Session tracing parameters');
END;
Low Level SQL Tracing in cx_Oracle
==================================
cx_Oracle is implemented using the `ODPI-C <https://oracle.github.io/odpi>`__
wrapper on top of the Oracle Client libraries. The ODPI-C tracing capability
can be used to log executed cx_Oracle statements to the standard error stream.
Before executing Python, set the environment variable ``DPI_DEBUG_LEVEL`` to
16.
At a Windows command prompt, this could be done with::
set DPI_DEBUG_LEVEL=16
On Linux, you might use::
export DPI_DEBUG_LEVEL=16
After setting the variable, run the Python Script, for example on Linux::
python end-to-endtracing.py 2> log.txt
For an application that does a single query, the log file might contain a
tracing line consisting of the prefix 'ODPI', a thread identifier, a timestamp,
and the SQL statement executed::
ODPI [26188] 2019-03-26 09:09:03.909: ODPI-C 3.1.1
ODPI [26188] 2019-03-26 09:09:03.909: debugging messages initialized at level 16
ODPI [26188] 2019-03-26 09:09:09.917: SQL SELECT * FROM jobss
Traceback (most recent call last):
File "end-to-endtracing.py", line 14, in <module>
cursor.execute("select * from jobss")
cx_Oracle.DatabaseError: ORA-00942: table or view does not exist
See `ODPI-C Debugging
<https://oracle.github.io/odpi/doc/user_guide/debugging.html>`__ for
documentation on ``DPI_DEBUG_LEVEL``.

View File

@ -0,0 +1,406 @@
.. _tuning:
****************
Tuning cx_Oracle
****************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Some general tuning tips are:
* Tune your application architecture.
A general application goal is to reduce the number of :ref:`round-trips
<roundtrips>` between cx_Oracle and the database.
For multi-user applications, make use of connection pooling. Create the pool
once during application initialization. Do not oversize the pool, see
:ref:`connpool` . Use a session callback function to set session state, see
:ref:`Session CallBacks for Setting Pooled Connection State <sessioncallback>`.
Make use of efficient cx_Oracle functions. For example, to insert
multiple rows use :meth:`Cursor.executemany()` instead of
:meth:`Cursor.execute()`.
* Tune your SQL statements. See the `SQL Tuning Guide
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=TGSQL>`__.
Use :ref:`bind variables <bind>` to avoid statement reparsing.
Tune :attr:`Cursor.arraysize` and :attr:`Cursor.prefetchrows` for each query,
see :ref:`Tuning Fetch Performance <tuningfetch>`.
Do simple optimizations like :ref:`limiting the number of rows <rowlimit>` and
avoiding selecting columns not used in the application.
It may be faster to work with simple scalar relational values than to use
Oracle Database object types.
Make good use of PL/SQL to avoid executing many individual statements from
cx_Oracle.
Tune the :ref:`Statement Cache <stmtcache>`.
Enable :ref:`Client Result Caching <clientresultcache>` for small lookup tables.
* Tune your database. See the `Database Performance Tuning Guide
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=TGDBA>`__.
* Tune your network. For example, when inserting or retrieving a large number
of rows (or for large data), or when using a slow network, then tune the
Oracle Network Session Data Unit (SDU) and socket buffer sizes, see `Oracle
Net Services: Best Practices for Database Performance and High Availability
<https://static.rainfocus.com/oracle/oow19/sess/1553616880266001WLIh/PF/OOW19_Net_CON4641_1569022126580001esUl.pdf>`__.
* Do not commit or rollback unnecessarily. Use :attr:`Connection.autocommit` on
the last of a sequence of DML statements.
.. _tuningfetch:
Tuning Fetch Performance
========================
To tune queries you can adjust cx_Oracle's internal buffer sizes to improve the
speed of fetching rows across the network from the database, and to optimize
memory usage. Regardless of which cx_Oracle method is used to get query
results, internally all rows are fetched in batches from the database and
buffered before being returned to the application. The internal buffer sizes
can have a significant performance impact. The sizes do not affect how, or
when, rows are returned to your application. They do not affect the minimum or
maximum number of rows returned by a query.
For best performance, tune "array fetching" with :attr:`Cursor.arraysize` and
"row prefetching" with :attr:`Cursor.prefetchrows` before calling
:meth:`Cursor.execute()`. Queries that return LOBs and similar types will never
prefetch rows, so the ``prefetchrows`` value is ignored in those cases.
The common query tuning scenario is for SELECT statements that return a large
number of rows over a slow network. Increasing ``arraysize`` can improve
performance by reducing the number of :ref:`round-trips <roundtrips>` to the
database. However increasing this value increases the amount of memory
required. Adjusting ``prefetchrows`` will also affect performance and memory
usage.
Row prefetching and array fetching are both internal buffering techniques to
reduce :ref:`round-trips <roundtrips>` to the database. The difference is the
code layer that is doing the buffering, and when the buffering occurs. The
Oracle Client libraries used by cx_Oracle have separate "execute SQL statement"
and "fetch data" calls. Prefetching allows query results to be returned to the
application when the successful statement execution acknowledgment is returned
from the database. This means that a subsequent internal "fetch data" operation
does not always need to make a round-trip to the database because rows are
already buffered in the Oracle Client libraries. Reducing round-trips helps
performance and scalability. An overhead of prefetching is the need for an
additional data copy from Oracle Client's prefetch buffers.
Choosing values for ``arraysize`` and ``prefetchrows``
++++++++++++++++++++++++++++++++++++++++++++++++++++++
The best :attr:`Cursor.arraysize` and :attr:`Cursor.prefetchrows` values can be
found by experimenting with your application under the expected load of normal
application use. This is because the cost of the extra memory copy from the
prefetch buffers when fetching a large quantity of rows or very "wide" rows may
outweigh the cost of a round-trip for a single cx_Oracle user on a fast network.
However under production application load, the reduction of round-trips may help
performance and overall system scalability. The documentation in
:ref:`round-trips <roundtrips>` shows how to measure round-trips.
Here are some suggestions for the starting point to begin your tuning:
* To tune queries that return an unknown number of rows, estimate the number of
rows returned and start with an appropriate :attr:`Cursor.arraysize` value.
The default is 100. Then set :attr:`Cursor.prefetchrows` to the ``arraysize``
value. For example:
.. code-block:: python
cur = connection.cursor()
cur.prefetchrows = 1000
cur.arraysize = 1000
for row in cur.execute("SELECT * FROM very_big_table"):
print(row)
Adjust the values as needed for performance, memory and round-trip usage. Do
not make the sizes unnecessarily large. For a large quantity of rows or very
"wide" rows on fast networks you may prefer to leave ``prefetchrows`` at its
default value of 2. Keep ``arraysize`` as big, or bigger than,
``prefetchrows``.
* If you are fetching a fixed number of rows, start your tuning by setting
``arraysize`` to the number of expected rows, and set ``prefetchrows`` to one
greater than this value. (Adding one removes the need for a round-trip to check
for end-of-fetch). For example, if you are querying 20 rows, perhaps to
:ref:`display a page <rowlimit>` of data, set ``prefetchrows`` to 21 and
``arraysize`` to 20:
.. code-block:: python
cur = connection.cursor()
cur.prefetchrows = 21
cur.arraysize = 20
for row in cur.execute("""
SELECT last_name
FROM employees
ORDER BY last_name
OFFSET 0 ROWS FETCH NEXT 20 ROWS ONLY"""):
print(row)
This will return all rows for the query in one round-trip.
* If you know that a query returns just one row then set :attr:`Cursor.arraysize`
to 1 to minimize memory usage. The default prefetch value of 2 allows minimal
round-trips for single-row queries:
.. code-block:: python
cur = connection.cursor()
cur.arraysize = 1
cur.execute("select * from MyTable where id = 1"):
row = cur.fetchone()
print(row)
In cx_Oracle, the ``arraysize`` and ``prefetchrows`` values are only examined
when a statement is executed the first time. To change the values, create a new
cursor. For example, to change ``arraysize`` for a repeated statement:
.. code-block:: python
array_sizes = (10, 100, 1000)
for size in array_sizes:
cursor = connection.cursor()
cursor.arraysize = size
start = time.time()
cursor.execute(sql).fetchall()
elapsed = time.time() - start
print("Time for", size, elapsed, "seconds")
There are two cases that will benefit from setting :attr:`Cursor.prefetchrows`
to 0:
* When passing REF CURSORS into PL/SQL packages. Setting ``prefetchrows`` to 0
can stop rows being prematurely (and silently) fetched into cx_Oracle's
internal buffers, making them unavailable to the PL/SQL code that receives the
REF CURSOR.
* When querying a PL/SQL function that uses PIPE ROW to emit rows at
intermittent intervals. By default, several rows needs to be emitted by the
function before cx_Oracle can return them to the application. Setting
``prefetchrows`` to 0 helps give a consistent flow of data to the application.
Prefetching can also be enabled in an external :ref:`oraaccess.xml
<optclientfiles>` file, which may be useful for tuning an application when
modifying its code is not feasible. Setting the size in ``oraaccess.xml`` will
affect the whole application, so it should not be the first tuning choice.
One place where increasing ``arraysize`` is particularly useful is in copying
data from one database to another:
.. code-block:: python
# setup cursors
source_cursor = source_connection.cursor()
source_cursor.arraysize = 1000
target_cursor = target_connection.cursor()
# perform fetch and bulk insertion
source_cursor.execute("select * from MyTable")
while True:
rows = source_cursor.fetchmany()
if not rows:
break
target_cursor.executemany("insert into MyTable values (:1, :2)", rows)
target_connection.commit()
Tuning REF CURSORS
++++++++++++++++++
In cx_Oracle, REF CURSORS can also be tuned by setting the values of ``arraysize``
and ``prefetchrows``. The prefetchrows value must be set before calling the PL/SQL
procedure as the REF CURSOR is executed on the server.
For example:
.. code-block:: python
# Set the arraysize and prefetch rows of the REF cursor
ref_cursor = connection.cursor()
ref_cursor.prefetchrows = 1000
ref_cursor.arraysize = 1000
# Perform the tuned fetch
sum_rows = 0
cursor.callproc("myrefcursorproc", [ref_cursor])
print("Sum of IntCol for", num_rows, "rows:")
for row in ref_cursor:
sum_rows += row[0]
print(sum_rows)
.. _roundtrips:
Database Round-trips
====================
A round-trip is defined as the trip from the Oracle Client libraries (used by
cx_Oracle) to the database and back. Calling each cx_Oracle function, or
accessing each attribute, will require zero or more round-trips. Along with
tuning an application's architecture and `tuning its SQL statements
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=TGSQL>`__, a general
performance and scalability goal is to minimize `round-trips
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-9B2F05F9-D841-4493-A42D-A7D89694A2D1>`__.
Some general tips for reducing round-trips are:
* Tune :attr:`Cursor.arraysize` and :attr:`Cursor.prefetchrows` for each query.
* Use :meth:`Cursor.executemany()` for optimal DML execution.
* Only commit when necessary. Use :attr:`Connection.autocommit` on the last statement of a transaction.
* For connection pools, use a callback to set connection state, see :ref:`Session CallBacks for Setting Pooled Connection State <sessioncallback>`.
* Make use of PL/SQL procedures which execute multiple SQL statements instead of executing them individually from cx_Oracle.
* Use scalar types instead of Oracle Database object types.
* Avoid overuse of :meth:`Connection.ping()`.
* Avoid setting :data:`SessionPool.ping_interval` to 0 or a small value.
* When using SODA, use pooled connections and enable the :ref:`SODA metadata cache <sodametadatacache>`.
Finding the Number of Round-Trips
+++++++++++++++++++++++++++++++++
Oracle's `Automatic Workload Repository
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-56AEF38E-9400-427B-A818-EDEC145F7ACD>`__
(AWR) reports show 'SQL*Net roundtrips to/from client' and are useful for
finding the overall behavior of a system.
Sometimes you may wish to find the number of round-trips used for a
specific application. Snapshots of the ``V$SESSTAT`` view taken before
and after doing some work can be used for this:
.. code-block:: sql
SELECT ss.value, sn.display_name
FROM v$sesstat ss, v$statname sn
WHERE ss.sid = SYS_CONTEXT('USERENV','SID')
AND ss.statistic# = sn.statistic#
AND sn.name LIKE '%roundtrip%client%';
.. _stmtcache:
Statement Caching
=================
cx_Oracle's :meth:`Cursor.execute()` and :meth:`Cursor.executemany()` functions
use the `Oracle Call Interface statement cache
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-4947CAE8-1F00-4897-BB2B-7F921E495175>`__
for efficient re-execution of statements. Statement caching lets Oracle
Database cursors be used without re-parsing the statement. Statement caching
also reduces metadata transfer costs between cx_Oracle and the database.
Performance and scalability are improved.
Each standalone or pooled connection has its own cache of statements with a
default size of 20. The size can be set when creating connection pools or
standalone connections. The size can subsequently be changed with
:attr:`Connection.stmtcachesize` or :attr:`SessionPool.stmtcachesize`. In
general, set the statement cache size to the size of the working set of
statements being executed by the application. To manually tune the cache,
monitor the general application load and the `Automatic Workload Repository
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-56AEF38E-9400-427B-A818-EDEC145F7ACD>`__
(AWR) "bytes sent via SQL*Net to client" values. The latter statistic should
benefit from not shipping statement metadata to cx_Oracle. Adjust the statement
cache size to your satisfaction. With Oracle Database 12c, or later, the
statement cache size can be automatically tuned using an :ref:`oraaccess.xml
<optclientfiles>` file.
Statement caching can be disabled by setting the size to 0. Disabling
the cache may be beneficial when the quantity or order of statements
causes cache entries to be flushed before they get a chance to be
reused. For example if there are more distinct statements than cache
slots, and the order of statement execution causes older statements to
be flushed from the cache before the statements are re-executed.
With connection pools, the effect of changing :attr:`SessionPool.stmtcachesize`
after pool creation depends on the Oracle Client version:
- When using Oracle Client 21 (or later), changing the cache size does not
immediately affect connections previously acquired and currently in use. When
those connections are subsequently released to the pool and re-acquired, they
will then use the new value. If it is neccessary to change the size on a
connection because it is not being released to the pool, use
:data:`Connection.stmtcachesize`.
- When using Oracle Client prior to version 21, changing the pool's statement
cache size has no effect on connections that already exist in the pool but
will affect new connections that are subsequently created, for example when
the pool grows. To change the size on a connection, use
:data:`Connection.stmtcachesize`.
When it is inconvenient to pass statement text through an application, the
:meth:`Cursor.prepare()` call can be used to avoid statement re-parsing.
Subsequent ``execute()`` calls use the value ``None`` instead of the SQL text:
.. code-block:: python
cur.prepare("select * from dept where deptno = :id order by deptno")
cur.execute(None, id = 20)
res = cur.fetchall()
print(res)
cur.execute(None, id = 10)
res = cur.fetchall()
print(res)
Statements passed to :meth:`~Cursor.prepare()` are also stored in the statement
cache.
.. _clientresultcache:
Client Result Caching
=====================
cx_Oracle applications can use Oracle Database's `Client Result Cache
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-35CB2592-7588-4C2D-9075-6F639F25425E>`__.
The CRC enables client-side caching of SQL query (SELECT statement) results in
client memory for immediate use when the same query is re-executed. This is
useful for reducing the cost of queries for small, mostly static, lookup tables,
such as for postal codes. CRC reduces network :ref:`round-trips <roundtrips>`,
and also reduces database server CPU usage.
The cache is at the application process level. Access and invalidation is
managed by the Oracle Client libraries. This removes the need for extra
application logic, or external utilities, to implement a cache.
CRC can be enabled by setting the `database parameters
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-A9D4A5F5-B939-48FF-80AE-0228E7314C7D>`__
``CLIENT_RESULT_CACHE_SIZE`` and ``CLIENT_RESULT_CACHE_LAG``, and then
restarting the database, for example:
.. code-block:: sql
SQL> ALTER SYSTEM SET CLIENT_RESULT_CACHE_LAG = 3000 SCOPE=SPFILE;
SQL> ALTER SYSTEM SET CLIENT_RESULT_CACHE_SIZE = 64K SCOPE=SPFILE;
SQL> STARTUP FORCE
CRC can alternatively be configured in an :ref:`oraaccess.xml <optclientfiles>`
or :ref:`sqlnet.ora <optnetfiles>` file on the Python host, see `Client
Configuration Parameters
<https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-E63D75A1-FCAA-4A54-A3D2-B068442CE766>`__.
Tables can then be created, or altered, so repeated queries use CRC. This
allows existing applications to use CRC without needing modification. For example:
.. code-block:: sql
SQL> CREATE TABLE cities (id number, name varchar2(40)) RESULT_CACHE (MODE FORCE);
SQL> ALTER TABLE locations RESULT_CACHE (MODE FORCE);
Alternatively, hints can be used in SQL statements. For example:
.. code-block:: sql
SELECT /*+ result_cache */ postal_code FROM locations

View File

@ -0,0 +1,84 @@
.. _txnmgmnt:
**********************
Transaction Management
**********************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
A database transaction is a grouping of SQL statements that make a logical data
change to the database.
When :meth:`Cursor.execute()` executes a SQL statement, a transaction is
started or continued. By default, cx_Oracle does not commit this transaction
to the database. The methods :meth:`Connection.commit()` and
:meth:`Connection.rollback()` methods can be used to explicitly commit
or rollback a transaction:
.. code-block:: python
cursor.execute("INSERT INTO mytab (name) VALUES ('John')")
connection.commit()
When a database connection is closed, such as with :meth:`Connection.close()`,
or when variables referencing the connection go out of scope, any uncommitted
transaction will be rolled back.
Autocommitting
==============
An alternative way to commit is to set the attribute
:attr:`~Connection.autocommit` of the connection to ``True``. This ensures all
:ref:`DML <dml>` statements (INSERT, UPDATE etc) are committed as they are
executed. Unlike :meth:`Connection.commit()`, this does not require an
additional :ref:`round-trip <roundtrips>` to the database so it is more
efficient when used appropriately.
Note that irrespective of the autocommit value, Oracle Database will always
commit an open transaction when a DDL statement is executed.
When executing multiple DML statements that constitute a single transaction, it
is recommended to use autocommit mode only for the last DML statement in the
sequence of operations. Unnecessarily committing causes extra database load,
and can destroy transactional consistency.
The example below shows a new customer being added to the table ``CUST_TABLE``.
The corresponding ``SALES`` table is updated with a purchase of 3000 pens from
the customer. The final insert uses autocommit mode to commit both new
records:
.. code-block:: python
# Add a new customer
id_var = cursor.var(int)
connection.autocommit = False # make sure any previous value is off
cursor.execute("""
INSERT INTO cust_table (name) VALUES ('John')
RETURNING id INTO :bvid""", bvid=id_var)
# Add sales data for the new customer and commit all new values
id_val = id_var.getvalue()[0]
connection.autocommit = True
cursor.execute("INSERT INTO sales_table VALUES (:bvid, 'pens', 3000)",
bvid=id_val)
Explicit Transactions
=====================
The method :meth:`Connection.begin()` can be used to explicitly start a local
or global transaction.
Without parameters, this explicitly begins a local transaction; otherwise, this
explicitly begins a distributed (global) transaction with the given parameters.
See the Oracle documentation for more details.
Note that in order to make use of global (distributed) transactions, the
attributes :attr:`Connection.internal_name` and
:attr:`Connection.external_name` attributes must be set.

View File

@ -0,0 +1,75 @@
.. _xmldatatype:
********************
Working with XMLTYPE
********************
.. note::
**cx_Oracle has a major new release under a new name and homepage**
`python-oracledb <https://oracle.github.io/python-oracledb/>`__.
**New projects should install python-oracledb instead of cx_Oracle.**
Oracle XMLType columns are fetched as strings by default. This is currently
limited to the maximum length of a ``VARCHAR2`` column. To return longer XML
values, they must be queried as LOB values instead.
The examples below demonstrate using XMLType data with cx_Oracle. The
following table will be used in these examples:
.. code-block:: sql
CREATE TABLE xml_table (
id NUMBER,
xml_data SYS.XMLTYPE
);
Inserting into the table can be done by simply binding a string as shown:
.. code-block:: python
xml_data = """<?xml version="1.0"?>
<customer>
<name>John Smith</name>
<Age>43</Age>
<Designation>Professor</Designation>
<Subject>Mathematics</Subject>
</customer>"""
cursor.execute("insert into xml_table values (:id, :xml)",
id=1, xml=xml_data)
This approach works with XML strings up to 1 GB in size. For longer strings, a
temporary CLOB must be created using :meth:`Connection.createlob()` and bound
as shown:
.. code-block:: python
clob = connection.createlob(cx_Oracle.DB_TYPE_CLOB)
clob.write(xml_data)
cursor.execute("insert into xml_table values (:id, sys.xmltype(:xml))",
id=2, xml=clob)
Fetching XML data can be done simply for values that are shorter than the
length of a VARCHAR2 column, as shown:
.. code-block:: python
cursor.execute("select xml_data from xml_table where id = :id", id=1)
xml_data, = cursor.fetchone()
print(xml_data) # will print the string that was originally stored
For values that exceed the length of a VARCHAR2 column, a CLOB must be returned
instead by using the function ``XMLTYPE.GETCLOBVAL()`` as shown:
.. code-block:: python
cursor.execute("""
select xmltype.getclobval(xml_data)
from xml_table
where id = :id""", id=1)
clob, = cursor.fetchone()
print(clob.read())
The LOB that is returned can be streamed or a string can be returned instead of
a CLOB. See :ref:`lobdata` for more information about processing LOBs.

View File

@ -1,80 +0,0 @@
.. _varobj:
****************
Variable Objects
****************
.. note::
The DB API definition does not define this object.
.. attribute:: Variable.actualElements
This read-only attribute returns the actual number of elements in the
variable. This corresponds to the number of elements in a PL/SQL index-by
table for variables that are created using the method
:func:`Cursor.arrayvar()`. For output variables in a DML returning statement
this value corresponds to the number of rows returned. For all other
variables this value will be identical to the attribute
:attr:`~Variable.numElements`.
.. attribute:: Variable.bufferSize
This read-only attribute returns the size of the buffer allocated for each
element in bytes.
.. method:: Variable.getvalue([pos=0])
Return the value at the given position in the variable.
.. attribute:: Variable.inconverter
This read-write attribute specifies the method used to convert data from
Python to the Oracle database. The method signature is converter(value)
and the expected return value is the value to bind to the database. If this
attribute is None, the value is bound directly without any conversion.
.. attribute:: Variable.numElements
This read-only attribute returns the number of elements allocated in an
array, or the number of scalar items that can be fetched into the variable
or bound to the variable.
.. attribute:: Variable.outconverter
This read-write attribute specifies the method used to convert data from
from the Oracle to Python. The method signature is converter(value)
and the expected return value is the value to return to Python. If this
attribute is None, the value is returned directly without any conversion.
.. method:: Variable.setvalue(pos, value)
Set the value at the given position in the variable.
.. attribute:: Variable.size
This read-only attribute returns the size of the variable. For strings this
value is the size in characters. For all others, this is same value as the
attribute bufferSize.
.. attribute:: Variable.type
This read-only attribute returns the type of the variable for those
variables that bind Oracle objects (it is not present for any other type of
variable).
.. attribute:: Variable.values
This read-only attribute returns a copy of the value of all actual positions
in the variable as a list. The number of items in the list will correspond
to the value of the :attr:`~Variable.actualElements` attribute.

2
odpi

@ -1 +1 @@
Subproject commit 8c82643740b0b6020625f5b379ae9eaf8f251042
Subproject commit f73a7c13d643b3fe252614bafc930afbd8e287dd

3
pyproject.toml Normal file
View File

@ -0,0 +1,3 @@
[build-system]
requires = ["setuptools >= 40.6.0", "wheel"]
build-backend = "setuptools.build_meta"

View File

@ -1,91 +0,0 @@
#------------------------------------------------------------------------------
# Copyright 2016, 2017, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
# Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
# Canada. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# AdvancedQueuing.py
# This script demonstrates how to use advanced queuing using cx_Oracle. It
# creates a simple type and enqueues and dequeues a few objects.
#
# This script requires cx_Oracle 5.3 and higher.
#------------------------------------------------------------------------------
from __future__ import print_function
CONNECT_STRING = "cx_Oracle/dev@localhost/orcl"
BOOK_TYPE_NAME = "UDT_BOOK"
QUEUE_NAME = "BOOKS"
QUEUE_TABLE_NAME = "BOOK_QUEUE"
import cx_Oracle
import decimal
# connect to database
connection = cx_Oracle.Connection(CONNECT_STRING)
cursor = connection.cursor()
# drop queue table, if present
cursor.execute("""
select count(*)
from user_tables
where table_name = :name""", name = QUEUE_TABLE_NAME)
count, = cursor.fetchone()
if count > 0:
print("Dropping queue table...")
cursor.callproc("dbms_aqadm.drop_queue_table", (QUEUE_TABLE_NAME, True))
# drop type, if present
cursor.execute("""
select count(*)
from user_types
where type_name = :name""", name = BOOK_TYPE_NAME)
count, = cursor.fetchone()
if count > 0:
print("Dropping books type...")
cursor.execute("drop type %s" % BOOK_TYPE_NAME)
# create type
print("Creating books type...")
cursor.execute("""
create type %s as object (
title varchar2(100),
authors varchar2(100),
price number(5,2)
);""" % BOOK_TYPE_NAME)
# create queue table and quueue and start the queue
print("Creating queue table...")
cursor.callproc("dbms_aqadm.create_queue_table",
(QUEUE_TABLE_NAME, BOOK_TYPE_NAME))
cursor.callproc("dbms_aqadm.create_queue", (QUEUE_NAME, QUEUE_TABLE_NAME))
cursor.callproc("dbms_aqadm.start_queue", (QUEUE_NAME,))
# enqueue a few messages
booksType = connection.gettype(BOOK_TYPE_NAME)
book1 = booksType.newobject()
book1.TITLE = "The Fellowship of the Ring"
book1.AUTHORS = "Tolkien, J.R.R."
book1.PRICE = decimal.Decimal("10.99")
book2 = booksType.newobject()
book2.TITLE = "Harry Potter and the Philosopher's Stone"
book2.AUTHORS = "Rowling, J.K."
book2.PRICE = decimal.Decimal("7.99")
options = connection.enqoptions()
messageProperties = connection.msgproperties()
for book in (book1, book2):
print("Enqueuing book", book.TITLE)
connection.enq(QUEUE_NAME, options, messageProperties, book)
connection.commit()
# dequeue the messages
options = connection.deqoptions()
options.navigation = cx_Oracle.DEQ_FIRST_MSG
options.wait = cx_Oracle.DEQ_NO_WAIT
while connection.deq(QUEUE_NAME, options, messageProperties, book):
print("Dequeued book", book.TITLE)

View File

@ -1,109 +0,0 @@
#------------------------------------------------------------------------------
# Copyright 2016, 2017, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
# Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
# Canada. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# Editioning.py
# This script demonstrates the use of editioning, available in Oracle
# Database 11.2 and higher. See the Oracle documentation on the subject for
# additional information. Adjust the contants at the top of the script for
# your own database as needed.
#
# This script requires cx_Oracle 5.3 and higher.
#------------------------------------------------------------------------------
from __future__ import print_function
import cx_Oracle
# define constants used throughout the script; adjust as desired
USER_NAME = "CX_ORACLE_TESTEDITIONS"
PASSWORD = "dev"
DBA_USER_NAME = "system"
DBA_PASSWORD = ""
DSN = ""
EDITION_NAME = "CX_ORACLE_E1"
# create user dropping it first, if necessary
connection = cx_Oracle.Connection(DBA_USER_NAME, DBA_PASSWORD, DSN)
cursor = connection.cursor()
cursor.execute("""
select username
from dba_users
where username = :name""",
name = USER_NAME)
names = [n for n, in cursor]
for name in names:
print("Dropping user", name)
cursor.execute("drop user %s cascade" % name)
print("Creating user", USER_NAME)
cursor.execute("create user %s identified by %s" % (USER_NAME, PASSWORD))
cursor.execute("grant create session, create procedure to %s" % USER_NAME)
cursor.execute("alter user %s enable editions" % USER_NAME)
# create edition, dropping it first, if necessary
cursor.execute("""
select edition_name
from dba_editions
where edition_name = :name""",
name = EDITION_NAME)
names = [n for n, in cursor]
for name in names:
print("Dropping edition", name)
cursor.execute("drop edition %s" % name)
print("Creating edition", EDITION_NAME)
cursor.execute("create edition %s" % EDITION_NAME)
cursor.execute("grant use on edition %s to %s" % (EDITION_NAME, USER_NAME))
# now connect to the newly created user and create a procedure
connection = cx_Oracle.Connection(USER_NAME, PASSWORD, DSN)
print("Edition should be None at this point, actual value is",
connection.edition)
cursor = connection.cursor()
cursor.execute("""
create or replace function TestEditions return varchar2 as
begin
return 'Base Edition';
end;""")
result = cursor.callfunc("TestEditions", str)
print("Function call should return Base Edition, actually returns", result)
# next, change the edition and recreate the procedure in the new edition
cursor.execute("alter session set edition = %s" % EDITION_NAME)
print("Edition should be %s at this point, actual value is" % EDITION_NAME,
connection.edition)
cursor.execute("""
create or replace function TestEditions return varchar2 as
begin
return 'Edition 1';
end;""")
result = cursor.callfunc("TestEditions", str)
print("Function call should return Edition 1, actually returns", result)
# next, change the edition back to the base edition and demonstrate that the
# original function is being called
cursor.execute("alter session set edition = ORA$BASE")
result = cursor.callfunc("TestEditions", str)
print("Function call should return Base Edition, actually returns", result)
# the edition can be set upon connection
connection = cx_Oracle.Connection(USER_NAME, PASSWORD, DSN,
edition = EDITION_NAME)
cursor = connection.cursor()
result = cursor.callfunc("TestEditions", str)
print("Function call should return Edition 1, actually returns", result)
# it can also be set via the environment variable ORA_EDITION
os.environ["ORA_EDITION"] = EDITION_NAME
connection = cx_Oracle.Connection(USER_NAME, PASSWORD, DSN)
print("Edition should be %s at this point, actual value is" % EDITION_NAME,
connection.edition)
cursor = connection.cursor()
result = cursor.callfunc("TestEditions", str)
print("Function call should return Edition 1, actually returns", result)

59
samples/README.md Normal file
View File

@ -0,0 +1,59 @@
# Samples
## News
**cx_Oracle has a major new release under a new name and homepage
[python-oracledb](https://oracle.github.io/python-oracledb/).**
**New projects should install python-oracledb instead of cx_Oracle: python -m pip install oracledb**
**The new source code and samples can be found at
[github.com/oracle/python-oracledb](https://github.com/oracle/python-oracledb).**
## cx_Oracle Examples
This directory contains samples for [cx_Oracle][6]. Documentation is
[here][7]. A separate tutorial is [here][8].
1. The schemas and SQL objects that are referenced in the samples can be
created by running the Python script [setup_samples.py][1]. The script
requires SYSDBA privileges and will prompt for these credentials as well as
the names of the schemas and edition that will be created, unless a number
of environment variables are set as documented in the Python script
[sample_env.py][2]. Run the script using the following command:
python setup_samples.py
Alternatively, the [SQL script][3] can be run directly via SQL\*Plus, which
will always prompt for the names of the schemas and edition that will be
created.
sqlplus sys/syspassword@hostname/servicename @sql/setup_samples.sql
2. Run a Python script, for example:
python query.py
3. After running cx_Oracle samples, the schemas and SQL objects can be
dropped by running the Python script [drop_samples.py][4]. The script
requires SYSDBA privileges and will prompt for these credentials as well as
the names of the schemas and edition that will be dropped, unless a number
of environment variables are set as documented in the Python script
[sample_env.py][2]. Run the script using the following command:
python drop_samples.py
Alternatively, the [SQL script][5] can be run directly via SQL\*Plus, which
will always prompt for the names of the schemas and edition that will be
dropped.
sqlplus sys/syspassword@hostname/servicename @sql/drop_samples.sql
[1]: https://github.com/oracle/python-cx_Oracle/blob/main/samples/setup_samples.py
[2]: https://github.com/oracle/python-cx_Oracle/blob/main/samples/sample_env.py
[3]: https://github.com/oracle/python-cx_Oracle/blob/main/samples/sql/setup_samples.sql
[4]: https://github.com/oracle/python-cx_Oracle/blob/main/samples/drop_samples.py
[5]: https://github.com/oracle/python-cx_Oracle/blob/main/samples/sql/drop_samples.sql
[6]: https://oracle.github.io/python-cx_Oracle/
[7]: http://cx-oracle.readthedocs.org/en/latest/index.html
[8]: https://oracle.github.io/python-cx_Oracle/samples/tutorial/Python-and-Oracle-Database-Scripting-for-the-Future.html

View File

@ -1,54 +0,0 @@
#------------------------------------------------------------------------------
# Copyright 2016, 2017, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
# Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
# Canada. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# ReturnLongs.py
# Returns all CLOB values as long strings and BLOB values as long raws. This
# is only useful if the lengths of the CLOB and BLOB values are well known but
# it can improve performance because there is no need to return to the database
# to get the actual values.
#
# This script requires cx_Oracle 5.0 and higher.
#------------------------------------------------------------------------------
from __future__ import print_function
import cx_Oracle
def OutputTypeHandler(cursor, name, defaultType, size, precision, scale):
if defaultType == cx_Oracle.CLOB:
return cursor.var(cx_Oracle.LONG_STRING, 80000, cursor.arraysize)
if defaultType == cx_Oracle.BLOB:
return cursor.var(cx_Oracle.LONG_BINARY, 100004, cursor.arraysize)
connection = cx_Oracle.Connection("cx_Oracle/dev@localhost/orcl")
connection.outputtypehandler = OutputTypeHandler
cursor = connection.cursor()
print("CLOBS returned as longs")
cursor.execute("""
select
IntCol,
ClobCol
from TestClobs
where dbms_lob.getlength(ClobCol) <= 80000
order by IntCol""")
for intCol, value in cursor:
print("Row:", intCol, "string of length", len(value))
print()
print("BLOBS returned as longs")
cursor.execute("""
select
IntCol,
BlobCol
from TestBlobs
where dbms_lob.getlength(BlobCol) <= 100000
order by IntCol""")
for intCol, value in cursor:
print("Row:", intCol, "string of length", value and len(value) or 0)

View File

@ -1,32 +0,0 @@
#------------------------------------------------------------------------------
# Copyright 2016, 2017, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
# Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
# Canada. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# ReturnUnicode.py
# Returns all strings as unicode. This also demonstrates the use of an output
# type handler to change the way in which data is returned from a cursor.
#
# This script requires cx_Oracle 5.0 and higher.
#------------------------------------------------------------------------------
from __future__ import print_function
import cx_Oracle
def OutputTypeHandler(cursor, name, defaultType, size, precision, scale):
if defaultType in (cx_Oracle.STRING, cx_Oracle.FIXED_CHAR):
return cursor.var(unicode, size, cursor.arraysize)
connection = cx_Oracle.Connection("cx_Oracle/dev@localhost/orcl")
connection.outputtypehandler = OutputTypeHandler
cursor = connection.cursor()
cursor.execute("select * from teststrings")
for row in cursor:
print("Row:", row)

View File

@ -1,65 +0,0 @@
#------------------------------------------------------------------------------
# Copyright 2017, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# Threads.py
# This script demonstrates the use of threads with cx_Oracle. A session pool
# is used so that multiple connections are available to perform work on the
# database. Only one operation (such as an execute or fetch) can take place at
# a time on a connection. In the below example, one of the threads performs
# dbms_lock.sleep while the other performs a query.
#
# This script requires cx_Oracle 2.5 and higher.
#------------------------------------------------------------------------------
from __future__ import print_function
import cx_Oracle
import threading
pool = cx_Oracle.SessionPool("cx_Oracle", "dev", "localhost/orcl", 2, 5, 1,
threaded = True)
def TheLongQuery():
conn = pool.acquire()
cursor = conn.cursor()
cursor.arraysize = 25000
print("TheLongQuery(): beginning execute...")
cursor.execute("""
select *
from
TestNumbers
cross join TestNumbers
cross join TestNumbers
cross join TestNumbers
cross join TestNumbers
cross join TestNumbers""")
print("TheLongQuery(): done execute...")
while True:
rows = cursor.fetchmany()
if not rows:
break
print("TheLongQuery(): fetched", len(rows), "rows...")
print("TheLongQuery(): all done!")
def DoALock():
conn = pool.acquire()
cursor = conn.cursor()
print("DoALock(): beginning execute...")
cursor.callproc("dbms_lock.sleep", (5,))
print("DoALock(): done execute...")
thread1 = threading.Thread(None, TheLongQuery)
thread1.start()
thread2 = threading.Thread(None, DoALock)
thread2.start()
thread1.join()
thread2.join()
print("All done!")

View File

@ -1,5 +1,5 @@
#------------------------------------------------------------------------------
# Copyright 2016, 2017, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
@ -8,7 +8,7 @@
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# AppContext.py
# app_context.py
# This script demonstrates the use of application context. Application
# context is available within logon triggers and can be retrieved by using the
# function sys_context().
@ -16,12 +16,10 @@
# This script requires cx_Oracle 5.3 and higher.
#------------------------------------------------------------------------------
from __future__ import print_function
import cx_Oracle
import cx_Oracle as oracledb
import sample_env
# define constants used throughout the script; adjust as desired
CONNECT_STRING = "cx_Oracle/dev@localhost/orcl"
APP_CTX_NAMESPACE = "CLIENTCONTEXT"
APP_CTX_ENTRIES = [
( APP_CTX_NAMESPACE, "ATTR1", "VALUE1" ),
@ -29,10 +27,10 @@ APP_CTX_ENTRIES = [
( APP_CTX_NAMESPACE, "ATTR3", "VALUE3" )
]
connection = cx_Oracle.Connection(CONNECT_STRING, appcontext = APP_CTX_ENTRIES)
connection = oracledb.connect(sample_env.get_main_connect_string(),
appcontext=APP_CTX_ENTRIES)
cursor = connection.cursor()
for namespace, name, value in APP_CTX_ENTRIES:
cursor.execute("select sys_context(:1, :2) from dual", (namespace, name))
value, = cursor.fetchone()
print("Value of context key", name, "is", value)

View File

@ -0,0 +1,46 @@
#------------------------------------------------------------------------------
# Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# aq_notification.py
# This script demonstrates using advanced queuing notification. Once this
# script is running, use another session to enqueue a few messages to the
# "DEMO_BOOK_QUEUE" queue. This is most easily accomplished by running the
# object_aq.py sample.
#
# This script requires cx_Oracle 6.4 and higher.
#------------------------------------------------------------------------------
import time
import cx_Oracle as oracledb
import sample_env
registered = True
def process_messages(message):
global registered
print("Message type:", message.type)
if message.type == oracledb.EVENT_DEREG:
print("Deregistration has taken place...")
registered = False
return
print("Queue name:", message.queueName)
print("Consumer name:", message.consumerName)
connection = oracledb.connect(sample_env.get_main_connect_string(),
events=True)
sub = connection.subscribe(namespace=oracledb.SUBSCR_NAMESPACE_AQ,
name="DEMO_BOOK_QUEUE", callback=process_messages,
timeout=300)
print("Subscription:", sub)
print("--> Connection:", sub.connection)
print("--> Callback:", sub.callback)
print("--> Namespace:", sub.namespace)
print("--> Protocol:", sub.protocol)
print("--> Timeout:", sub.timeout)
while registered:
print("Waiting for notifications....")
time.sleep(5)

View File

@ -0,0 +1,48 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# array_dml_rowcounts.py
#
# Demonstrate the use of the 12.1 feature that allows cursor.executemany()
# to return the number of rows affected by each individual execution as a list.
# The parameter "arraydmlrowcounts" must be set to True in the call to
# cursor.executemany() after which cursor.getarraydmlrowcounts() can be called.
#
# This script requires cx_Oracle 5.2 and higher.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
connection = oracledb.connect(sample_env.get_main_connect_string())
cursor = connection.cursor()
# show the number of rows for each parent ID as a means of verifying the
# output from the delete statement
for parent_id, count in cursor.execute("""
select ParentId, count(*)
from ChildTable
group by ParentId
order by ParentId"""):
print("Parent ID:", parent_id, "has", int(count), "rows.")
print()
# delete the following parent IDs only
parent_ids_to_delete = [20, 30, 50]
print("Deleting Parent IDs:", parent_ids_to_delete)
print()
# enable array DML row counts for each iteration executed in executemany()
cursor.executemany("""
delete from ChildTable
where ParentId = :1""",
[(i,) for i in parent_ids_to_delete],
arraydmlrowcounts = True)
# display the number of rows deleted for each parent ID
row_counts = cursor.getarraydmlrowcounts()
for parent_id, count in zip(parent_ids_to_delete, row_counts):
print("Parent ID:", parent_id, "deleted", count, "rows.")

86
samples/batch_errors.py Normal file
View File

@ -0,0 +1,86 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# batch_errors.py
#
# Demonstrate the use of the Oracle Database 12.1 feature that allows
# cursor.executemany() to complete successfully, even if errors take
# place during the execution of one or more of the individual
# executions. The parameter "batcherrors" must be set to True in the
# call to cursor.executemany() after which cursor.getbatcherrors() can
# be called, which will return a list of error objects.
#
# This script requires cx_Oracle 5.2 and higher.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
connection = oracledb.connect(sample_env.get_main_connect_string())
cursor = connection.cursor()
# define data to insert
data_to_insert = [
(1016, 10, 'Child B of Parent 10'),
(1017, 10, 'Child C of Parent 10'),
(1018, 20, 'Child D of Parent 20'),
(1018, 20, 'Child D of Parent 20'), # duplicate key
(1019, 30, 'Child C of Parent 30'),
(1020, 30, 'Child D of Parent 40'),
(1021, 60, 'Child A of Parent 60'), # parent does not exist
(1022, 40, 'Child F of Parent 40'),
]
# retrieve the number of rows in the table
cursor.execute("""
select count(*)
from ChildTable""")
count, = cursor.fetchone()
print("number of rows in child table:", int(count))
print("number of rows to insert:", len(data_to_insert))
# old method: executemany() with data errors results in stoppage after the
# first error takes place; the row count is updated to show how many rows
# actually succeeded
try:
cursor.executemany("insert into ChildTable values (:1, :2, :3)",
data_to_insert)
except oracledb.DatabaseError as e:
error, = e.args
print("FAILED with error:", error.message)
print("number of rows which succeeded:", cursor.rowcount)
# demonstrate that the row count is accurate
cursor.execute("""
select count(*)
from ChildTable""")
count, = cursor.fetchone()
print("number of rows in child table after failed insert:", int(count))
# roll back so we can perform the same work using the new method
connection.rollback()
# new method: executemany() with batch errors enabled (and array DML row counts
# also enabled) results in no immediate error being raised
cursor.executemany("insert into ChildTable values (:1, :2, :3)",
data_to_insert, batcherrors=True, arraydmlrowcounts=True)
# where errors have taken place, the row count is 0; otherwise it is 1
row_counts = cursor.getarraydmlrowcounts()
print("Array DML row counts:", row_counts)
# display the errors that have taken place
errors = cursor.getbatcherrors()
print("number of errors which took place:", len(errors))
for error in errors:
print("Error", error.message.rstrip(), "at row offset", error.offset)
# demonstrate that all of the rows without errors have been successfully
# inserted
cursor.execute("""
select count(*)
from ChildTable""")
count, = cursor.fetchone()
print("number of rows in child table after successful insert:", int(count))

75
samples/bind_insert.py Normal file
View File

@ -0,0 +1,75 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# bind_insert.py
#
# Demonstrate how to insert a row into a table using bind variables.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
connection = oracledb.connect(sample_env.get_main_connect_string())
#------------------------------------------------------------------------------
# "Bind by position"
#------------------------------------------------------------------------------
rows = [
(1, "First"),
(2, "Second"),
(3, "Third"),
(4, "Fourth"),
(5, None), # Insert a NULL value
(6, "Sixth"),
(7, "Seventh")
]
cursor = connection.cursor()
# predefine maximum string size to avoid data scans and memory reallocations;
# the None value indicates that the default processing can take place
cursor.setinputsizes(None, 20)
cursor.executemany("insert into mytab(id, data) values (:1, :2)", rows)
#------------------------------------------------------------------------------
# "Bind by name"
#------------------------------------------------------------------------------
rows = [
{"d": "Eighth", "i": 8},
{"d": "Ninth", "i": 9},
{"d": "Tenth", "i": 10}
]
cursor = connection.cursor()
# Predefine maximum string size to avoid data scans and memory reallocations
cursor.setinputsizes(d=20)
cursor.executemany("insert into mytab(id, data) values (:i, :d)", rows)
#------------------------------------------------------------------------------
# Inserting a single bind still needs tuples
#------------------------------------------------------------------------------
rows = [
("Eleventh",),
("Twelth",)
]
cursor = connection.cursor()
cursor.executemany("insert into mytab(id, data) values (11, :1)", rows)
#------------------------------------------------------------------------------
# Now query the results back
#------------------------------------------------------------------------------
# Don't commit - this lets the demo be run multiple times
#connection.commit()
for row in cursor.execute('select * from mytab'):
print(row)

31
samples/bind_query.py Normal file
View File

@ -0,0 +1,31 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# bind_query.py
#
# Demonstrate how to perform a simple query limiting the rows retrieved using
# a bind variable. Since the query that is executed is identical, no additional
# parsing is required, thereby reducing overhead and increasing performance. It
# also permits data to be bound without having to be concerned about escaping
# special characters or SQL injection attacks.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
connection = oracledb.connect(sample_env.get_main_connect_string())
cursor = connection.cursor()
sql = 'select * from SampleQueryTab where id = :bvid'
print("Query results with id = 4")
for row in cursor.execute(sql, bvid = 4):
print(row)
print()
print("Query results with id = 1")
for row in cursor.execute(sql, bvid = 1):
print(row)
print()

75
samples/bulk_aq.py Normal file
View File

@ -0,0 +1,75 @@
#------------------------------------------------------------------------------
# Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
# Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
# Canada. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# bulk_aq.py
# This script demonstrates how to use bulk enqueuing and dequeuing of
# messages with advanced queuing. It makes use of a RAW queue created in the
# sample setup.
#
# This script requires cx_Oracle 8.2 and higher.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
QUEUE_NAME = "DEMO_RAW_QUEUE"
PAYLOAD_DATA = [
"The first message",
"The second message",
"The third message",
"The fourth message",
"The fifth message",
"The sixth message",
"The seventh message",
"The eighth message",
"The ninth message",
"The tenth message",
"The eleventh message",
"The twelfth and final message"
]
# connect to database
connection = oracledb.connect(sample_env.get_main_connect_string())
cursor = connection.cursor()
# create queue
queue = connection.queue(QUEUE_NAME)
queue.deqoptions.wait = oracledb.DEQ_NO_WAIT
queue.deqoptions.navigation = oracledb.DEQ_FIRST_MSG
# dequeue all existing messages to ensure the queue is empty, just so that
# the results are consistent
while queue.deqone():
pass
# enqueue a few messages
print("Enqueuing messages...")
batch_size = 6
data_to_enqueue = PAYLOAD_DATA
while data_to_enqueue:
batch_data = data_to_enqueue[:batch_size]
data_to_enqueue = data_to_enqueue[batch_size:]
messages = [connection.msgproperties(payload=d) for d in batch_data]
for data in batch_data:
print(data)
queue.enqmany(messages)
connection.commit()
# dequeue the messages
print("\nDequeuing messages...")
batch_size = 8
while True:
messages = queue.deqmany(batch_size)
if not messages:
break
for props in messages:
print(props.payload.decode())
connection.commit()
print("\nDone.")

41
samples/call_timeout.py Normal file
View File

@ -0,0 +1,41 @@
#------------------------------------------------------------------------------
# Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# call_timeout.py
#
# Demonstrate the use of the Oracle Client 18c feature that enables round trips
# to the database to time out if a specified amount of time (in milliseconds)
# has passed without a response from the database.
#
# This script requires cx_Oracle 7.0 and higher and Oracle Client 18.1 and
# higher.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
connection = oracledb.connect(sample_env.get_main_connect_string())
connection.call_timeout = 2000
print("Call timeout set at", connection.call_timeout, "milliseconds...")
cursor = connection.cursor()
cursor.execute("select sysdate from dual")
today, = cursor.fetchone()
print("Fetch of current date before timeout:", today)
# dbms_session.sleep() replaces dbms_lock.sleep() from Oracle Database 18c
sleep_proc_name = "dbms_session.sleep" \
if int(connection.version.split(".")[0]) >= 18 \
else "dbms_lock.sleep"
print("Sleeping...should time out...")
try:
cursor.callproc(sleep_proc_name, (3,))
except oracledb.DatabaseError as e:
print("ERROR:", e)
cursor.execute("select sysdate from dual")
today, = cursor.fetchone()
print("Fetch of current date after timeout:", today)

View File

@ -0,0 +1,78 @@
#------------------------------------------------------------------------------
# Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# connection_pool.py
# This script demonstrates the use of connection pooling. Pools can
# significantly reduce connection times for long running applications that
# repeatedly open and close connections. Internal features help protect against
# dead connections, and also aid use of Oracle Database features such as FAN
# and Application Continuity.
# The script uses threading to show multiple users of the pool. One thread
# performs a database sleep while another performs a query. A more typical
# application might be a web service that handles requests from multiple users.
# Note only one operation (such as an execute or fetch) can take place at a time
# on each connection.
#
# Also see session_callback.py.
#
#------------------------------------------------------------------------------
import threading
import cx_Oracle as oracledb
import sample_env
# Create a Connection Pool
pool = oracledb.SessionPool(user=sample_env.get_main_user(),
password=sample_env.get_main_password(),
dsn=sample_env.get_connect_string(), min=2, max=5,
increment=1)
def the_long_query():
with pool.acquire() as conn:
cursor = conn.cursor()
cursor.arraysize = 25000
print("the_long_query(): beginning execute...")
cursor.execute("""
select *
from
TestNumbers
cross join TestNumbers
cross join TestNumbers
cross join TestNumbers
cross join TestNumbers
cross join TestNumbers""")
print("the_long_query(): done execute...")
while True:
rows = cursor.fetchmany()
if not rows:
break
print("the_long_query(): fetched", len(rows), "rows...")
print("the_long_query(): all done!")
def do_a_lock():
with pool.acquire() as conn:
# dbms_session.sleep() replaces dbms_lock.sleep()
# from Oracle Database 18c
sleep_proc_name = "dbms_session.sleep" \
if int(conn.version.split(".")[0]) >= 18 \
else "dbms_lock.sleep"
cursor = conn.cursor()
print("do_a_lock(): beginning execute...")
cursor.callproc(sleep_proc_name, (5,))
print("do_a_lock(): done execute...")
thread1 = threading.Thread(target=the_long_query)
thread1.start()
thread2 = threading.Thread(target=do_a_lock)
thread2.start()
thread1.join()
thread2.join()
print("All done!")

View File

@ -1,5 +1,5 @@
#------------------------------------------------------------------------------
# Copyright 2016, 2017, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
@ -8,24 +8,31 @@
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# QueryChangeNotification.py
# This script demonstrates using query change notification in Python, a
# feature that is available in Oracle 11g. Once this script is running, use
# another session to insert, update or delete rows from the table
# cx_Oracle.TestTempTable and you will see the notification of that change.
# cqn.py
# This script demonstrates using continuous query notification in Python, a
# feature that is available in Oracle 11g and later. Once this script is
# running, use another session to insert, update or delete rows from the table
# TestTempTable and you will see the notification of that change.
#
# This script requires cx_Oracle 5.3 and higher.
#------------------------------------------------------------------------------
from __future__ import print_function
import cx_Oracle
import threading
import time
import cx_Oracle as oracledb
import sample_env
registered = True
def callback(message):
global registered
print("Message type:", message.type)
if not message.registered:
print("Deregistration has taken place...")
registered = False
return
print("Message database name:", message.dbname)
print("Message tranasction id:", message.txid)
print("Message queries:")
for query in message.queries:
print("--> Query ID:", query.id)
@ -41,10 +48,10 @@ def callback(message):
print("-" * 60)
print("=" * 60)
connection = cx_Oracle.Connection("cx_Oracle/dev@localhost/orcl",
events = True)
sub = connection.subscribe(callback = callback, timeout = 1800,
qos = cx_Oracle.SUBSCR_QOS_QUERY | cx_Oracle.SUBSCR_QOS_ROWIDS)
connection = oracledb.connect(sample_env.get_main_connect_string(),
events=True)
qos = oracledb.SUBSCR_QOS_QUERY | oracledb.SUBSCR_QOS_ROWIDS
sub = connection.subscribe(callback=callback, timeout=1800, qos=qos)
print("Subscription:", sub)
print("--> Connection:", sub.connection)
print("--> Callback:", sub.callback)
@ -52,11 +59,10 @@ print("--> Namespace:", sub.namespace)
print("--> Protocol:", sub.protocol)
print("--> Timeout:", sub.timeout)
print("--> Operations:", sub.operations)
print("--> Rowids?:", bool(sub.qos & cx_Oracle.SUBSCR_QOS_ROWIDS))
queryId = sub.registerquery("select * from TestTempTable")
print("Registered query:", queryId)
print("--> Rowids?:", bool(sub.qos & oracledb.SUBSCR_QOS_ROWIDS))
query_id = sub.registerquery("select * from TestTempTable")
print("Registered query:", query_id)
while True:
while registered:
print("Waiting for notifications....")
time.sleep(5)

74
samples/cqn2.py Normal file
View File

@ -0,0 +1,74 @@
#------------------------------------------------------------------------------
# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# cqn2.py
# This script demonstrates using continuous query notification in Python, a
# feature that is available in Oracle 11g and later. Once this script is
# running, use another session to insert, update or delete rows from the table
# TestTempTable and you will see the notification of that change.
#
# This script differs from cqn.py in that it shows how a connection can be
# acquired from a session pool and used to query the changes that have been
# made.
#
# This script requires cx_Oracle 7 or higher.
#------------------------------------------------------------------------------
import time
import cx_Oracle as oracledb
import sample_env
registered = True
def callback(message):
global registered
if not message.registered:
print("Deregistration has taken place...")
registered = False
return
connection = pool.acquire()
for query in message.queries:
for table in query.tables:
if table.rows is None:
print("Too many row changes detected in table", table.name)
continue
num_rows_deleted = 0
print(len(table.rows), "row changes detected in table", table.name)
for row in table.rows:
if row.operation & oracledb.OPCODE_DELETE:
num_rows_deleted += 1
continue
ops = []
if row.operation & oracledb.OPCODE_INSERT:
ops.append("inserted")
if row.operation & oracledb.OPCODE_UPDATE:
ops.append("updated")
cursor = connection.cursor()
cursor.execute("""
select IntCol
from TestTempTable
where rowid = :rid""",
rid=row.rowid)
int_col, = cursor.fetchone()
print(" Row with IntCol", int_col, "was", " and ".join(ops))
if num_rows_deleted > 0:
print(" ", num_rows_deleted, "rows deleted")
print("=" * 60)
pool = oracledb.SessionPool(user=sample_env.get_main_user(),
password=sample_env.get_main_password(),
dsn=sample_env.get_connect_string(), min=2, max=5,
increment=1, events=True)
with pool.acquire() as connection:
qos = oracledb.SUBSCR_QOS_QUERY | oracledb.SUBSCR_QOS_ROWIDS
sub = connection.subscribe(callback=callback, timeout=1800, qos=qos)
print("Subscription created with ID:", sub.id)
query_id = sub.registerquery("select * from TestTempTable")
print("Registered query with ID:", query_id)
while registered:
print("Waiting for notifications....")
time.sleep(5)

View File

@ -1,5 +1,5 @@
#------------------------------------------------------------------------------
# Copyright 2016, 2017, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
@ -8,24 +8,31 @@
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# DatabaseChangeNotification.py
# database_change_notification.py
# This script demonstrates using database change notification in Python, a
# feature that is available in Oracle 10g Release 2. Once this script is
# running, use another session to insert, update or delete rows from the table
# cx_Oracle.TestTempTable and you will see the notification of that change.
# TestTempTable and you will see the notification of that change.
#
# This script requires cx_Oracle 5.3 and higher.
#------------------------------------------------------------------------------
from __future__ import print_function
import cx_Oracle
import threading
import time
import cx_Oracle as oracledb
import sample_env
registered = True
def callback(message):
global registered
print("Message type:", message.type)
if not message.registered:
print("Deregistration has taken place...")
registered = False
return
print("Message database name:", message.dbname)
print("Message tranasction id:", message.txid)
print("Message tables:")
for table in message.tables:
print("--> Table Name:", table.name)
@ -38,21 +45,21 @@ def callback(message):
print("-" * 60)
print("=" * 60)
connection = cx_Oracle.Connection("cx_Oracle/dev@localhost/orcl",
events = True)
sub = connection.subscribe(callback = callback, timeout = 1800,
qos = cx_Oracle.SUBSCR_QOS_ROWIDS)
connection = oracledb.connect(sample_env.get_main_connect_string(),
events=True)
sub = connection.subscribe(callback=callback, timeout=1800,
qos=oracledb.SUBSCR_QOS_ROWIDS)
print("Subscription:", sub)
print("--> Connection:", sub.connection)
print("--> ID:", sub.id)
print("--> Callback:", sub.callback)
print("--> Namespace:", sub.namespace)
print("--> Protocol:", sub.protocol)
print("--> Timeout:", sub.timeout)
print("--> Operations:", sub.operations)
print("--> Rowids?:", bool(sub.qos & cx_Oracle.SUBSCR_QOS_ROWIDS))
print("--> Rowids?:", bool(sub.qos & oracledb.SUBSCR_QOS_ROWIDS))
sub.registerquery("select * from TestTempTable")
while True:
while registered:
print("Waiting for notifications....")
time.sleep(5)

View File

@ -1,5 +1,5 @@
#------------------------------------------------------------------------------
# Copyright 2016, 2017, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
@ -8,22 +8,22 @@
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# DatabaseShutdown.py
# This script demonstrates shutting down a database using Python. It is only
# possible in Oracle 10g Release 2 and higher. The connection used assumes that
# the environment variable ORACLE_SID has been set.
# database_shutdown.py
# This script demonstrates shutting down a database using Python. The
# connection used assumes that the environment variable ORACLE_SID has been
# set.
#
# This script requires cx_Oracle 4.3 and higher.
#------------------------------------------------------------------------------
import cx_Oracle
import cx_Oracle as oracledb
# need to connect as SYSDBA or SYSOPER
connection = cx_Oracle.connect("/", mode = cx_Oracle.SYSDBA)
connection = oracledb.connect(mode=oracledb.SYSDBA)
# first shutdown() call must specify the mode, if DBSHUTDOWN_ABORT is used,
# there is no need for any of the other steps
connection.shutdown(mode = cx_Oracle.DBSHUTDOWN_IMMEDIATE)
connection.shutdown(mode=oracledb.DBSHUTDOWN_IMMEDIATE)
# now close and dismount the database
cursor = connection.cursor()
@ -31,5 +31,4 @@ cursor.execute("alter database close normal")
cursor.execute("alter database dismount")
# perform the final shutdown call
connection.shutdown(mode = cx_Oracle.DBSHUTDOWN_FINAL)
connection.shutdown(mode=oracledb.DBSHUTDOWN_FINAL)

View File

@ -1,5 +1,5 @@
#------------------------------------------------------------------------------
# Copyright 2016, 2017, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
@ -8,24 +8,22 @@
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# DatabaseStartup.py
# This script demonstrates starting up a database using Python. It is only
# possible in Oracle 10g Release 2 and higher. The connection used assumes that
# the environment variable ORACLE_SID has been set.
# database_startup.py
# This script demonstrates starting up a database using Python. The
# connection used assumes that the environment variable ORACLE_SID has been
# set.
#
# This script requires cx_Oracle 4.3 and higher.
#------------------------------------------------------------------------------
import cx_Oracle
import cx_Oracle as oracledb
# the connection must be in PRELIM_AUTH mode
connection = cx_Oracle.connect("/",
mode = cx_Oracle.SYSDBA | cx_Oracle.PRELIM_AUTH)
connection = oracledb.connect(mode=oracledb.SYSDBA | oracledb.PRELIM_AUTH)
connection.startup()
# the following statements must be issued in normal SYSDBA mode
connection = cx_Oracle.connect("/", mode = cx_Oracle.SYSDBA)
connection = oracledb.connect("/", mode=oracledb.SYSDBA)
cursor = connection.cursor()
cursor.execute("alter database mount")
cursor.execute("alter database open")

44
samples/dbms_output.py Normal file
View File

@ -0,0 +1,44 @@
#------------------------------------------------------------------------------
# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# dbms_output.py
# This script demonstrates one method of fetching the lines produced by
# the DBMS_OUTPUT package.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
connection = oracledb.connect(sample_env.get_main_connect_string())
cursor = connection.cursor()
# enable DBMS_OUTPUT
cursor.callproc("dbms_output.enable")
# execute some PL/SQL that generates output with DBMS_OUTPUT.PUT_LINE
cursor.execute("""
begin
dbms_output.put_line('This is the cx_Oracle manual');
dbms_output.put_line('');
dbms_output.put_line('Demonstrating use of DBMS_OUTPUT');
end;""")
# tune this size for your application
chunk_size = 10
# create variables to hold the output
lines_var = cursor.arrayvar(str, chunk_size)
num_lines_var = cursor.var(int)
num_lines_var.setvalue(0, chunk_size)
# fetch the text that was added by PL/SQL
while True:
cursor.callproc("dbms_output.get_lines", (lines_var, num_lines_var))
num_lines = num_lines_var.getvalue()
lines = lines_var.getvalue()[:num_lines]
for line in lines:
print(line or "")
if num_lines < chunk_size:
break

View File

@ -1,5 +1,5 @@
#------------------------------------------------------------------------------
# Copyright 2017, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
@ -8,20 +8,18 @@
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# DMLReturningMultipleRows.py
# dml_returning_multiple_rows.py
# This script demonstrates the use of DML returning with multiple rows being
# returned at once.
#
# This script requires cx_Oracle 6.0 and higher.
#------------------------------------------------------------------------------
from __future__ import print_function
import cx_Oracle
import datetime
import cx_Oracle as oracledb
import sample_env
# truncate table first so that script can be rerun
connection = cx_Oracle.Connection("cx_Oracle/dev@localhost/orcl")
connection = oracledb.connect(sample_env.get_main_connect_string())
cursor = connection.cursor()
print("Truncating table...")
cursor.execute("truncate table TestTempTable")
@ -33,15 +31,14 @@ for i in range(5):
cursor.execute("insert into TestTempTable values (:1, :2)", data)
# now delete them and use DML returning to return the data that was inserted
intCol = cursor.var(int)
stringCol = cursor.var(str)
int_col = cursor.var(int)
string_col = cursor.var(str)
print("Deleting data with DML returning...")
cursor.execute("""
delete from TestTempTable
returning IntCol, StringCol into :intCol, :stringCol""",
intCol = intCol,
stringCol = stringCol)
returning IntCol, StringCol into :int_col, :string_col""",
int_col=int_col,
string_col=string_col)
print("Data returned:")
for intVal, stringVal in zip(intCol.values, stringCol.values):
print(tuple([intVal, stringVal]))
for int_val, string_val in zip(int_col.getvalue(), string_col.getvalue()):
print(tuple([int_val, string_val]))

View File

@ -1,5 +1,5 @@
#------------------------------------------------------------------------------
# Copyright 2016, 2017, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
@ -8,7 +8,7 @@
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# DRCP.py
# drcp.py
# This script demonstrates the use of Database Resident Connection Pooling
# (DRCP) which provides a connection pool in the database server, thereby
# reducing the cost of creating and tearing down client connections. The pool
@ -20,22 +20,24 @@
#
# Statistics regarding the pool can be acquired from the following query:
#
# select * from v$pool_cc_stats;
# select * from v$cpool_cc_stats;
#
# There is no difference in how a connection is used once it has been
# established.
#
# This script requires cx_Oracle 5.0 and higher.
# DRCP has most benefit when used in conjunction with cx_Oracle's local
# connection pool, see the cx_Oracle documentation.
#
# This script requires cx_Oracle 5.0 or higher.
#
#------------------------------------------------------------------------------
from __future__ import print_function
import cx_Oracle as oracledb
import sample_env
import cx_Oracle
conn = cx_Oracle.Connection("cx_Oracle/dev@localhost/orcl:pooled",
cclass = "PYCLASS", purity = cx_Oracle.ATTR_PURITY_SELF)
conn = oracledb.connect(sample_env.get_drcp_connect_string(),
cclass="PYCLASS", purity=oracledb.ATTR_PURITY_SELF)
cursor = conn.cursor()
print("Performing query using DRCP...")
for row in cursor.execute("select * from TestNumbers order by IntCol"):
print(row)

24
samples/drop_samples.py Normal file
View File

@ -0,0 +1,24 @@
#------------------------------------------------------------------------------
# Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# drop_samples.py
#
# Drops the database objects used for the cx_Oracle samples.
#------------------------------------------------------------------------------
import cx_Oracle as oracledb
import sample_env
def drop_samples(conn):
print("Dropping sample schemas and edition...")
sample_env.run_sql_script(conn, "drop_samples",
main_user=sample_env.get_main_user(),
edition_user=sample_env.get_edition_user(),
edition_name=sample_env.get_edition_name())
if __name__ == "__main__":
conn = oracledb.connect(sample_env.get_admin_connect_string())
drop_samples(conn)
print("Done.")

76
samples/editioning.py Normal file
View File

@ -0,0 +1,76 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
# Portions Copyright 2001-2007, Computronix (Canada) Ltd., Edmonton, Alberta,
# Canada. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# editioning.py
# This script demonstrates the use of Edition-Based Redefinition, available
# in Oracle# Database 11.2 and higher. See the Oracle documentation on the
# subject for additional information. Adjust the contants at the top of the
# script for your own database as needed.
#
# This script requires cx_Oracle 5.3 and higher.
#------------------------------------------------------------------------------
import os
import cx_Oracle as oracledb
import sample_env
# connect to the editions user and create a procedure
edition_connect_string = sample_env.get_edition_connect_string()
edition_name = sample_env.get_edition_name()
connection = oracledb.connect(edition_connect_string)
print("Edition should be None, actual value is:", repr(connection.edition))
cursor = connection.cursor()
cursor.execute("""
create or replace function TestEditions return varchar2 as
begin
return 'Base Procedure';
end;""")
result = cursor.callfunc("TestEditions", str)
print("Function should return 'Base Procedure', actually returns:",
repr(result))
# next, change the edition and recreate the procedure in the new edition
cursor.execute("alter session set edition = %s" % edition_name)
print("Edition should be", repr(edition_name.upper()),
"actual value is:", repr(connection.edition))
cursor.execute("""
create or replace function TestEditions return varchar2 as
begin
return 'Edition 1 Procedure';
end;""")
result = cursor.callfunc("TestEditions", str)
print("Function should return 'Edition 1 Procedure', actually returns:",
repr(result))
# next, change the edition back to the base edition and demonstrate that the
# original function is being called
cursor.execute("alter session set edition = ORA$BASE")
result = cursor.callfunc("TestEditions", str)
print("Function should return 'Base Procedure', actually returns:",
repr(result))
# the edition can be set upon connection
connection = oracledb.connect(edition_connect_string,
edition=edition_name.upper())
cursor = connection.cursor()
result = cursor.callfunc("TestEditions", str)
print("Function should return 'Edition 1 Procedure', actually returns:",
repr(result))
# it can also be set via the environment variable ORA_EDITION
os.environ["ORA_EDITION"] = edition_name.upper()
connection = oracledb.connect(edition_connect_string)
print("Edition should be", repr(edition_name.upper()),
"actual value is:", repr(connection.edition))
cursor = connection.cursor()
result = cursor.callfunc("TestEditions", str)
print("Function should return 'Edition 1 Procedure', actually returns:",
repr(result))

View File

@ -0,0 +1,47 @@
#------------------------------------------------------------------------------
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# generic_row_factory.py
#
# Demonstrate the ability to return named tuples for all queries using a
# subclassed cursor and row factory.
#------------------------------------------------------------------------------
import collections
import cx_Oracle as oracledb
import sample_env
class Connection(oracledb.Connection):
def cursor(self):
return Cursor(self)
class Cursor(oracledb.Cursor):
def execute(self, statement, args=None):
prepare_needed = (self.statement != statement)
result = super().execute(statement, args or [])
if prepare_needed:
description = self.description
if description is not None:
names = [d[0] for d in description]
self.rowfactory = collections.namedtuple("GenericQuery", names)
return result
# create new subclassed connection and cursor
connection = Connection(sample_env.get_main_connect_string())
cursor = connection.cursor()
# the names are now available directly for each query executed
for row in cursor.execute("select ParentId, Description from ParentTable"):
print(row.PARENTID, "->", row.DESCRIPTION)
print()
for row in cursor.execute("select ChildId, Description from ChildTable"):
print(row.CHILDID, "->", row.DESCRIPTION)
print()

View File

@ -1,5 +1,5 @@
#------------------------------------------------------------------------------
# Copyright 2016, 2017, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
@ -8,7 +8,7 @@
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# ImplicitResults.py
# implicit_results.py
# This script demonstrates the use of the 12.1 feature that allows PL/SQL
# procedures to return result sets implicitly, without having to explicitly
# define them.
@ -16,15 +16,14 @@
# This script requires cx_Oracle 5.3 and higher.
#------------------------------------------------------------------------------
from __future__ import print_function
import cx_Oracle as oracledb
import sample_env
import cx_Oracle
con = cx_Oracle.connect("cx_Oracle/dev@localhost/orcl")
cur = con.cursor()
connection = oracledb.connect(sample_env.get_main_connect_string())
cursor = connection.cursor()
# use PL/SQL block to return two cursors
cur.execute("""
cursor.execute("""
declare
c1 sys_refcursor;
c2 sys_refcursor;
@ -43,9 +42,8 @@ cur.execute("""
end;""")
# display results
for ix, resultSet in enumerate(cur.getimplicitresults()):
for ix, result_set in enumerate(cursor.getimplicitresults()):
print("Result Set #" + str(ix + 1))
for row in resultSet:
for row in result_set:
print(row)
print()

View File

@ -1,5 +1,5 @@
#------------------------------------------------------------------------------
# Copyright 2016, 2017, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
#
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
#
@ -8,27 +8,26 @@
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# InsertGeometry.py
# insert_geometry.py
# This script demonstrates the ability to create Oracle objects (this example
# uses SDO_GEOMETRY) and insert them into a table.
#
# This script requires cx_Oracle 5.3 and higher.
#------------------------------------------------------------------------------
from __future__ import print_function
import cx_Oracle
import cx_Oracle as oracledb
import sample_env
# create and populate Oracle objects
connection = cx_Oracle.Connection("cx_Oracle/dev@localhost/orcl")
typeObj = connection.gettype("MDSYS.SDO_GEOMETRY")
elementInfoTypeObj = connection.gettype("MDSYS.SDO_ELEM_INFO_ARRAY")
ordinateTypeObj = connection.gettype("MDSYS.SDO_ORDINATE_ARRAY")
obj = typeObj.newobject()
connection = oracledb.connect(sample_env.get_main_connect_string())
type_obj = connection.gettype("MDSYS.SDO_GEOMETRY")
element_info_type_obj = connection.gettype("MDSYS.SDO_ELEM_INFO_ARRAY")
ordinate_type_obj = connection.gettype("MDSYS.SDO_ORDINATE_ARRAY")
obj = type_obj.newobject()
obj.SDO_GTYPE = 2003
obj.SDO_ELEM_INFO = elementInfoTypeObj.newobject()
obj.SDO_ELEM_INFO = element_info_type_obj.newobject()
obj.SDO_ELEM_INFO.extend([1, 1003, 3])
obj.SDO_ORDINATES = ordinateTypeObj.newobject()
obj.SDO_ORDINATES = ordinate_type_obj.newobject()
obj.SDO_ORDINATES.extend([1, 1, 5, 7])
print("Created object", obj)
@ -51,7 +50,6 @@ if count == 0:
print("Removing any existing rows...")
cursor.execute("delete from TestGeometry")
print("Adding row to table...")
cursor.execute("insert into TestGeometry values (1, :obj)", obj = obj)
cursor.execute("insert into TestGeometry values (1, :obj)", obj=obj)
connection.commit()
print("Success!")

89
samples/json_blob.py Normal file
View File

@ -0,0 +1,89 @@
#------------------------------------------------------------------------------
# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# json_blob.py
# Shows how to use a BLOB as a JSON column store.
#
# Note: with Oracle Database 21c using the new JSON type is recommended
# instead, see json_direct.py
#
# Documentation:
# cx_Oracle: https://cx-oracle.readthedocs.io/en/latest/user_guide/json_data_type.html
# Oracle Database: https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=ADJSN
#
#------------------------------------------------------------------------------
import json
import sys
import cx_Oracle as oracledb
import sample_env
connection = oracledb.connect(sample_env.get_main_connect_string())
client_version = oracledb.clientversion()[0]
db_version = int(connection.version.split(".")[0])
# Minimum database vesion is 12
if db_version < 12:
sys.exit("This example requires Oracle Database 12.1.0.2 or later")
# Create a table
cursor = connection.cursor()
cursor.execute("""
begin
execute immediate 'drop table customers';
exception when others then
if sqlcode <> -942 then
raise;
end if;
end;""")
cursor.execute("""
create table customers (
id integer not null primary key,
json_data blob check (json_data is json)
) lob (json_data) store as (cache)""")
# Insert JSON data
data = dict(name="Rod", dept="Sales", location="Germany")
inssql = "insert into customers values (:1, :2)"
if client_version >= 21 and db_version >= 21:
# Take advantage of direct binding
cursor.setinputsizes(None, oracledb.DB_TYPE_JSON)
cursor.execute(inssql, [1, data])
else:
# Insert the data as a JSON string
cursor.execute(inssql, [1, json.dumps(data)])
# Select JSON data
sql = "SELECT c.json_data FROM customers c"
for j, in cursor.execute(sql):
print(json.loads(j.read()))
# Using JSON_VALUE to extract a value from a JSON column
sql = """SELECT JSON_VALUE(json_data, '$.location')
FROM customers
OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY"""
for r in cursor.execute(sql):
print(r)
# Using dot-notation to extract a value from a JSON (BLOB storage) column
sql = """SELECT c.json_data.location
FROM customers c
OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY"""
for j, in cursor.execute(sql):
print(j)
# Using JSON_OBJECT to extract relational data as JSON
sql = """SELECT JSON_OBJECT('key' IS d.dummy) dummy
FROM dual d"""
for r in cursor.execute(sql):
print(r)

Some files were not shown because too many files have changed in this diff Show More