ora - Oracle SQL connector for Tarantool
- Tarantool 2.0.0+ with header files
- Oracle Client Library with header files
Clone repository and then build it using CMake:
git clone https://github.com/picodata/oracle-connector.git && cd oracle-connector
mkdir build && cd build && cmake .. -DCMAKE_BUILD_TYPE=RelWithDebugInfo
make
make install
You will need Oracle client libraries installed.
tarantoolctl rocks --only-server https://download.picodata.io/luarocks/ install oracle-connector <version>
Download the Basic and SDK packages from the Oracle official site.
Build the connector:
mkdir build && cd build
cmake .. \
-DCMAKE_BUILD_TYPE=Debug \
-DORACLE_INCLUDE_DIR=~/Downloads/instantclient_19_8\ 2/sdk/include/ \
-DORACLE_LIBRARY_DIR=~/Downloads/instantclient_19_8/ \
-DORACLE_OCI_LIBRARY=~/Downloads/instantclient_19_8/libclntsh.dylib.19.1 \
-DORACLE_OCCI_LIBRARY=~/Downloads/instantclient_19_8/libocci.dylib.19.1 \
-DORACLE_NNZ_LIBRARY=~/Downloads/instantclient_19_8/libnnz19.dylib
make install
-
Download Oracle database 19.3.0 for Linux x86-64 from Oracle official site.
-
Clone a repository with Dockerfile and build an image:
git clone https://github.com/oracle/docker-images.git cd docker-images/OracleDatabase/SingleInstance/dockerfiles/19.3.0 cp ~/Downloads/LINUX.X64_193000_db_home.zip . docker build -t oracle/database:19.3.0-se2 --build-arg DB_EDITION=se2 .
-
Run a container:
docker run \ -d --rm --name oracle \ -p 1521:1521 \ -p 5500:5500 \ -p 2484:2484 \ -e ORACLE_PWD=tntPswd \ -e ORACLE_SID=tnt \ -e ORACLE_PDB=SYSTEM \ oracle/database:19.3.0-se2
local ora = require('ora')
local conn = ora.connect({ host = 'localhost', port = '1521', user = 'SYSTEM', pass = 'tntPswd', db = 'tnt', raise = true })
local tuples = conn:execute("SELECT ID, NAME FROM TEST1 WHERE KIND = :KIND", {['KIND'] = 'info'})
conn:close()
Connect to a database.
Options:
host
- a hostname to connectport
- a port number to connectuser
- usernamepass
- a passworddb
- a database nameraise
- true if an exception should be raised if query execution fails with an error
Returns:
connection ~= nil
on successerror(reason)
on error
Execute a statement with parameters. Statement could be a normal SQL query string or PL/SQL anonymous block. Oracle OCI uses ":NAME" as parameter placeholder. Parameters is a table of input/output parameters with keys matching to all statement placeholders. There are two possible formats of a parameter description. The short form consists only of parameter value whereas long-form is a table describing value, type, and size.
Returns:
result set, output variables, true, message
on successnull, null, false, reason
- on error when raise is falseerror(reason)
on error when raise is true
A result set has a form of an array of tables like that:
{ { column1 = value, column2 = value }, { column1 = value, column2 = value } }, ...
Output variables are returned in a form of table where each item is an array
of n-th returned value of a variable like that:
{ ovar1 = {value, valuse, valuse}, ovar2 = {value, value, value}}
Result set is returned in case of SELECT statements where output variables are filled if executing query returning something using variables.
Examples:
tarantool> conn:execute("CREATE TABLE test1 (ID NUMBER NOT NULL PRIMARY KEY, NAME VARCHAR2(256))")
---
- null
- null
- true
- null
tarantool> conn:execute("INSERT TABLE test1 VALUES (1, 'ONE')")
---
- null
- null
- true
- null
tarantool> conn:execute("INSERT INTO test1 VALUES (:ID, :NAME), {["ID"] = 2, ["NAME"] = {['type'] = "string", ["value"] = "TWO"}})
---
- null
- null
- true
- null
tarantool> conn:execute("UPDATE test1 SET NAME = lower(NAME) RETURNING NAME INTO :NAME", {["NAME"] = {['type'] = "string", ["size"] = 40}})
---
- null
- NAME:
0: one
1: two
- true
- null
tarantool> conn:execute("COMMIT")
---
- null
- null
- true
- null
The driver does type conversion from Oracle type to lua as described bellow
- VARCHAR, VARCHAR2 -> lua string
- Blob -> lua string
- Clob -> lua string
- Number -> lua number with detection if then number is integer or fractional
- Real, Double -> lua number
- Octet, Unsigned8, Unsigned16, Unsigned32 -> lua number
- SmallInt, Integer, Signed8, Signed16, Signed32 -> lua number
- Any other type -> implicit string conversion to lua string
As lua does not have support for builtin types like datas, timestamps then there is no conversion available expect strings. Please take in mind that such implicit conversion may depend on database and/or client settings like locale. To make select result stable it is recommended to use explicit converion within SQL statement like CAST and CONVERT. Native driver support for such types is a subject for further development.
Currently the driver supports following type descriptors for parameter binding:
- string -> the value is got from lua stack as string and binded to a SQL statement as C NULL-terminated string
- number -> the value is got from lua stack as lua number ant then binded as Oracle NUMBER with could be both integer or fractional
- any other descriptor -> the value is converted to lua string and binded as C NULL-terminated string
- if type descriptor is not set or short form for binding values is used then driver tries to detect following types
- lua number -> Oracle number
- lua boolean -> Oracle unsigned
- lua string - > Oracle C NULL-terminated string
- any other type is implicitly converted to lua string and then binded as C NULL-terminated string
Execute a select statement but nod fetch data immediately but open a cursor. For statement and parameters description please refer to execute section.
Returns:
true, message
on successfalse, reason
on error when raise if falseerror(reason)
on error when raise is true
Fetches one row from previously opened cursor. Returns:
row, true, message
on successnill, true, message
on eofnil, false, reason
on error if raise is falseerror(reason)
on error if raise is true
For a row description please refer to execute section
Close previously opened cursor
Examples:
tarantool> conn:cursor_open("select * from test1")
---
- true
- null
tarantool> conn:cursor_fetch()
---
- NAME: one
ID: 1
- true
- null
tarantool> conn:cursor_fetch()
---
- NAME: two
ID: 2
- true
- null
tarantool> conn:cursor_fetch()
---
- null
- true
- null
tarantool> conn:cursor_close()
---
- true
Begin a transaction.
Returns: true
Commit current transaction.
Returns: true
Rollback current transaction.
Returns: true
Execute a dummy statement to check that connection is alive.
Returns:
true
on successfalse
on failure
Create a connection pool with count of size established connections.
Options:
host
- hostname to connect toport
- port number to connect touser
- usernamepass
- passworddb
- database namesize
- count of connections in poolraise
- true if an exception should be raised if query execution fails with an error
Returns
pool ~=nil
on successerror(reason)
on error
Get a connection from pool. Reset connection before returning it. If connection is broken then it will be reestablished. If there is no free connections then calling fiber will sleep until another fiber returns some connection to pool.
Returns:
conn ~= nil
Return a connection to connection pool.
Options
conn
- a connection
- Clone the Oracle docker images repository https://github.com/oracle/docker-images and change to it
- Place linuxx64_12201_database.zip into OracleDatabase/SingleInstance/dockerfiles/12.2.0.1
- Build image with
./OracleDatabase/SingleInstance/dockerfiles/buildContainerImage.sh -v 12.2.0.1 -s
Oracle Database is configured on the first run of a contaianer like that:
docker run -p 1521:1521 -e ORACLE_SID=tnt -e ORACLE_PDB=tntPDB -e ORACLE_PWD=tntPswd oracle/database:12.2.0.1-se2
After the first run container initializes database what could take some time. After
database is configures the container is could be started with simply docker start command the database inside still
needs for some time to finish its startup.
For the full set on available cobfiguration options please reffer to OracleDatabase/SingleInstance/README.md inside the Oracle docker repository.
- Special handling for binding CLOB and BLOB values. The implementaion requires for creating BLOB/CLOB handler and provide special read/write callbacks from/to Lua state machine
- Special type handling for timestamps, datetimes, tables and may be objects is a subkect for further discussion and implementation
- Oracle connection allows to handle multiple oppened cursors simultaneously but this requires for introducing support from Lua.
- Lua will loose precision if returned integer does not fit into double and this requires for using cdata type