k2informaticsgmbh / erloci Goto Github PK
View Code? Open in Web Editor NEWErlang Oracle native driver - DEPRECATED, see https://github.com/K2InformaticsGmbH/oranif instead
License: Apache License 2.0
Erlang Oracle native driver - DEPRECATED, see https://github.com/K2InformaticsGmbH/oranif instead
License: Apache License 2.0
Create Table:
create table raw_clob(col_raw raw(2000))
Note: data is corrupted when read through select!
StmtInsert = OciSession:prep_sql(<<"insert into raw_clob (col_raw) values (:col_raw)">>).
ok = StmtInsert:bind_vars([{<<":col_raw">>, 'SQLT_BIN'}]).
Data = <<1,2,3,4,0,0,0,5,6,7,8>>,
{rowids, [_]} = StmtInsert:exec_stmt([{Data}]).
SelStmt = OciSession:prep_sql("select col_raw from raw_clob").
> {cols, _} = SelStmt:exec_stmt().
{cols,[{<<"COL_RAW">>,'SQLT_BIN',2000,0,0}]}
> SelStmt:fetch_rows(100).
{{rows,[[<<1,2,3,4>>]]},true}
cur_clm.dlen + 1
is used to allocate buffer for RAW which is always (for the raw_clob
table above) 2000. erloci/c_src/erloci_lib/ocistmt.cpp
Lines 479 to 484 in 49557db
OCIAttrGet(OCI_DTYPE_PARAM, OCI_ATTR_DATA_SIZE)
API to get the value in cur_clm.dlen
erloci/c_src/erloci_lib/ocistmt.cpp
Lines 398 to 400 in 49557db
strlen
is used in erloci/c_src/erloci_lib/ocistmt.cpp
Lines 974 to 982 in 49557db
\0
as string termination character)Duplicate implementation of terminate found in close have to be removed.
Close the port by deleting the child from supervisor which would in turn result in the terminate call (with trap_exit set to true).
From console.
[error] [_DDRL_] {c_src/erloci_lib/ocistmt.cpp:rows:930} failed OCILobGetLength
for 0x7fad0f8b59f8 row 1 column 13 reason [rows:928] Error - OCI_INVALID_HANDLE
(select SCOTT.LOGGER_LOGS.*, SCOTT.LOGGER_LOGS.ROWID from SCOTT.LOGGER_LOGS)
[error] [_DDRL_] {dderl_fsm,1218} Error on fsm <0.5860.0> when State filling
Message: {0,<<"[rows:928] Error - OCI_INVALID_HANDLE\n">>}
oci_logger.erl:95: Warning: erlang:now/0: Deprecated BIF. See the "Time and Time Correction in Erlang" chapter of the ERTS User's Guide for more information.
oci_logger.erl:112: Warning: erlang:now/0: Deprecated BIF. See the "Time and Time Correction in Erlang" chapter of the ERTS User's Guide for more information.
oci_logger.erl:120: Warning: erlang:now/0: Deprecated BIF. See the "Time and Time Correction in Erlang" chapter of the ERTS User's Guide for more information.
Compiled src/oci_logger.erl
Compiled src/oci_util.erl
erloci.erl:48: Warning: erlang:now/0: Deprecated BIF. See the "Time and Time Correction in Erlang" chapter of the ERTS User's Guide for more information.
erloci.erl:48: Warning: erlang:now/0: Deprecated BIF. See the "Time and Time Correction in Erlang" chapter of the ERTS User's Guide for more information.
erloci.erl:48: Warning: erlang:now/0: Deprecated BIF. See the "Time and Time Correction in Erlang" chapter of the ERTS User's Guide for more information.
erloci.erl:48: Warning: erlang:now/0: Deprecated BIF. See the "Time and Time Correction in Erlang" chapter of the ERTS User's Guide for more information.
erloci.erl:49: Warning: erlang:now/0: Deprecated BIF. See the "Time and Time Correction in Erlang" chapter of the ERTS User's Guide for more information.
erloci.erl:49: Warning: erlang:now/0: Deprecated BIF. See the "Time and Time Correction in Erlang" chapter of the ERTS User's Guide for more information.
erloci.erl:49: Warning: erlang:now/0: Deprecated BIF. See the "Time and Time Correction in Erlang" chapter of the ERTS User's Guide for more information.
erloci.erl:49: Warning: erlang:now/0: Deprecated BIF. See the "Time and Time Correction in Erlang" chapter of the ERTS User's Guide for more information.
The code will appear to be very clear in using lager instead of the oci_logger.
We have some sql for create 2 tables.
sql1 = "CREATE TABLE schema_migrations (version NUMBER, inserted_at TIMESTAMP)"
and next
sql2 = "CREATE TABLE schema_migrations1 (version NUMBER, inserted_at TIMESTAMP)"
I have my sessions in pool:
oci = :erloci.new([Enum.into(opts, %{})])
session = oci.get_session(credentials[:tns], credentials[:user], credentials[:password])
{:ok, session}
Next i run some command:
session.prep_sql(sql1).exec_stmt()
session.prep_sql(sql2).exec_stmt()
It's works, but i want wrap in transaction...
session.prep_sql("BEGIN").exec_stmt()
session.prep_sql(sql1).exec_stmt()
session.prep_sql(sql2).exec_stmt()
session.prep_sql("COMMIT").exec_stmt()
How i can do it?
Ref : OCI_ATTR_CLIENT_IDENTIFIER
The client identifier is found in V$SESSION as a CLIENT_IDENTIFIER column or through the system context with this SQL statement:
SELECT SYS_CONTEXT('userenv', 'client_identifier') FROM DUAL;
Please, add data types mapping (Oracle <--> Erlang) to documentation for reference.
The driver crash trying to read a table that includes columns of the type:
http://docs.oracle.com/cd/B28359_01/server.111/b28318/datatype.htm#CDEEEHFJ
Regards.
OS: RedHat 5
Erlang: r17.3
Oracle 12.1
When ever I start oci_port:start_link([{logging, true}]) it throws the exception below:
24.10.2014 14:51:22.494166 [info] [OCI] {oci_port,,361} started log disabled new port:
[{name,"./priv/ocierl"},
{links,[<0.37.0>]},
{id,6248},
{connected,<0.37.0>},
{input,0},
{output,19},
{os_pid,12823}]
24.10.2014 14:51:22.494406 [debug] [OCI] Waiting for peer to connect on 51586
24.10.2014 14:51:22.516756 [debug] [OCI] Connection from 35261 to 51586
{oci_port,<0.37.0>}
3> 24.10.2014 14:51:22.517253 [info] [OCI] {c_src/erloci_drv/erloci.cpp,main,73} Port process configs : erlang term max size 0x00040000 bytes, logging enabled, TCP port for logs 5158
terminate called after throwing an instance of 'intf_ret'
=ERROR REPORT==== 24-Oct-2014::14:51:22 ===
** Generic server <0.37.0> terminating
** Last message in was {#Port<0.781>,{exit_status,134}}
** When Server state == {state,#Port<0.781>,false,0,
{oci_logger,<0.38.0>},
undefined}
** Reason for termination ==
** {port_exit,{'SIGABRT',core,"Abort"}}
** exception error: {port_exit,{'SIGABRT',core,"Abort"}}
3>
hi, i used the rpms:
oracle-instantclient11.2-basic-11.2.0.3.0-1.x86_64.rpm
oracle-instantclient11.2-devel-11.2.0.3.0-1.x86_64.rpm
and the ~/.bash_profile in centos6.5 is
export INSTANT_CLIENT_LIB_PATH=/usr/lib/oracle/11.2/client64/lib/
export INSTANT_CLIENT_INCLUDE_PATH=/usr/include/oracle/11.2/client64/
export ERL_INTERFACE_DIR=/usr/local/lib/erlang/lib/erl_interface-3.7.20
when i exe rebar compile
the error is that:
/usr/bin/ld: cannot find -lons
collect2: ld returned 1 exit status
make: *** [priv/ocierl] Error 1
ERROR: Command [compile] failed!
so, i found that libons.so isnot exist in /usr/lib/oracle/11.2/client64/lib/
Because the libs were changed in oracle12, but my db version is 11g.
how to fix it?
thx
insert all into erloci_test_1 (name) values ('test1') into erloci_test_1 (name) values ('test2') into erloci_test_1 (name) values ('test3') into erloci_test_1 (name) values ('test4') select * from dual
::{port_exit,{'SIGSEGV',core,"Segmentation Fault"}}
=ERROR REPORT==== 7-Sep-2014::09:58:07 ===
** Generic server <0.101.0> terminating
** Last message in was {#Port<0.29190>,{exit_status,139}}
** When Server state == {state,#Port<0.29190>,true,1,
{oci_logger,<0.102.0>},
{<<131,104,2,103,100,0,13,110,111,110,111,100,
101,64,110,111,104,111,115,116,0,0,0,104,0,0,
0,0,0,114,0,3,100,0,13,110,111,110,111,100,
101,64,110,111,104,111,115,116,0,0,3,71,143,
0,0,0,3,0,0,0,0>>,
6,140593674062192,140593271573424,[],1}}
** Reason for termination ==
** {port_exit,{'SIGSEGV',core,"Segmentation Fault"}}
One of the leaks is https://github.com/K2InformaticsGmbH/cpro/issues/477#issuecomment-385623499
When i try insert some values to table, i have this error:
Assertion failed: ((*it).is_tuple() && (*it).length() == 3 && (*it)[0].is_binary() && (*it)[1].is_any_int() && (*it)[2].is_any_int()), function map_schema_to_bind_args, file c_src/erloci_drv/marshal.cpp, line 297.
My table: "CREATE TABLE \"schema_migrations\" (\"version\" NUMBER, \"inserted_at\" DATE)"
My insert:
"INSERT INTO \"schema_migrations\" (\"inserted_at\",\"version\") VALUES (:inserted_at, :version)"
[inserted_at: {{2016, 1, 6}, {14, 11, 39, 0}}, version: 0]
After mapping:
[{<<120, 116, 1, 6, 14, 11, 39>>, 0}]
OciPort = erloci:new([{logging, true}, {env, [{"NLS_LANG", "GERMAN_SWITZERLAND.AL32UTF8"}]}]).
OciSession = ------- Connection to database --------.
SelectSysdate = <<"BEGIN :SQLT_DAT_OUT_RESULT := TO_DATE(SYSDATE); END;">>,
BoundStmt = OciSession:prep_sql(SelectSysdate).
SelectBinds = [{<<":SQLT_DAT_OUT_RESULT">>, out, 'SQLT_DAT'}].
ok = BoundStmt:bind_vars(SelectBinds).
f(R1).
R1 = [{<<0,0,0,0,0,0,0,0>>}].
BoundStmt:exec_stmt(R1).
Results in:
06.09.2016 08:59:32.721699 [error] [_OCI_] {c_src/erloci_lib/ocistmt.cpp,execute,780} Unsuported out variable type 12 (BEGIN :SQLT_DAT_OUT_RESULT := TO_DATE(SYSDATE); END;)
{error,{0,<<"[execute:779] unsupporetd type 12\n">>}}
{oci_logger,103} TCP closed
([email protected])27> {oci_logger,132} Terminating normal
Problem processing command: error:function_clause
[{<<"query">>,[{<<"connection">>,<<"g2gDZAAIb2NpX3BvcnRnZAAhc2JzZ3VpQHZpbWFwZ2V0LXNic2gwMS5pdC5id25zLmNoAABaIwAAARECYgA6n4A=">>},{<<"qstr">>,<<"SELECT\r\n *\r\nFROM\r\n dba_users">>},{<<"conn_id">>,<<"133876732">>},{<<"binds">>,null}]}]
[{oci_adapter,process_log_binds,[undefined],[{file,"c:/Program Files (x86)/Jenkins/workspace/sbsgui/_build/default/lib/dderl/src/oci_adapter.erl"},{line,739}]},{oci_adapter,process_query,5,[{file,"c:/Program Files (x86)/Jenkins/workspace/sbsgui/_build/default/lib/dderl/src/oci_adapter.erl"},{line,676}]},{oci_adapter,process_cmd,6,[{file,"c:/Program Files (x86)/Jenkins/workspace/sbsgui/_build/default/lib/dderl/src/oci_adapter.erl"},{line,233}]},{dderl_session,spawn_process_call,8,[{file,"c:/Program Files (x86)/Jenkins/workspace/sbsgui/_build/default/lib/dderl/src/dderl_session.erl"},{line,645}]}]
@shamis can you please analyze the possible reason for this.
This is the installation:
There are some unicode data (utf8) in oracle db. In order to get them properly,I hope I need to define charset when connecting to db. Otherwise I'm getting a line of questions marks for utf8 data. Database is already configured to use AL32UTF8. Does erloci supports that? I tried going through the code. but couldn't find a way to define charset.
Reproduce with
select :SQLT_INT_TEST, dump(:SQLT_INT_TEST) from dual
with :SQLT_INT_TEST set to 41794321750
I can't got binary with right charset:
11> f(OciPort), OciPort = erloci:new([{logging, true},{env, [{"NLS_LANG","SIMPLIFIED CHINESE_CHINA.ZHS16GBK"}]}]).
12> f(OciSession), OciSession = OciPort:get_session(Tns, User, Pass).
13> f(SelectStmt), SelectStmt = OciSession:prep_sql(SelectSql).
14> SelectStmt:exec_stmt().
{cols,[{<<"SUPPLYNAME">>,'SQLT_CHR',50,0,0}]}
15> SelectStmt:fetch_rows(5).
{{rows,[[<<"¹ã¶«Ê¡¶«Ý¸¹úÒ©¼¯ÍÅÈʼÃÌÃÒ©ÒµÓÐÏÞ¹«Ë¾">>]]},true
In fact, I run the unit test for my oracle:
fun() ->
application:start(erloci),
OciPort = erloci:new([{logging, true}, {env, [{"NLS_LANG", "SIMPLIFIED CHINESE_CHINA.ZHS16GBK"}]}]),
...
and got follow error:
erloci_test: db_test_...*failed*
in function erloci_test:'-timestamp_interval_datatypes/1-fun-11-'/2 (test/erloci_test.erl, line 865)
in call from erloci_test:timestamp_interval_datatypes/1 (test/erloci_test.erl, line 858)
**error:{assertEqual_failed,[{module,erloci_test},
{line,865},
{expression,"SelectStmt : exec_stmt ( )"},
{expected,{cols,[{<<"NAME">>,'SQLT_CHR',30,0,0},
{<<"DAT">>,'SQLT_DAT',7,0,0},
{<<"TS">>,'SQLT_TIMESTAMP',11,0,6},
{<<"TSTZ">>,'SQLT_TIMESTAMP_TZ',13,0,6},
{<<"TSLTZ">>,'SQLT_TIMESTAMP_LTZ',11,0,...},
{<<"IYM">>,'SQLT_INTERVAL_YM',5,...},
{<<"IDS">>,'SQLT_INTERVAL_DS',...}]}},
{value,{cols,[{<<"NAME">>,'SQLT_CHR',60,0,0},
{<<"DAT">>,'SQLT_DAT',7,0,0},
{<<"TS">>,'SQLT_TIMESTAMP',11,0,6},
{<<"TSTZ">>,'SQLT_TIMESTAMP_TZ',13,0,...},
{<<"TSLTZ">>,'SQLT_TIMESTAMP_LTZ',11,...},
{<<"IYM">>,'SQLT_INTERVAL_YM',...},
{<<...>>,...}]}}]}
=INFO REPORT==== 19-Apr-2015::00:56:19 ===
application: erloci
exited: stopped
type: temporary
=======================================================
Failed: 2. Skipped: 0. Passed: 53.
Cover analysis: /Users/homeway/erlang/research/erloci/.eunit/index.html
ERROR: One or more eunit tests failed.
ERROR: eunit failed while processing /Users/homeway/erlang/research/erloci: rebar_abort
I'm looking for the pool facility provided in c-bik / erloci as
{ok, Pool} = oci_session_pool:start_link("127.0.0.1", 1521, {service, "db.local"}, "dbauser", "supersecret",[]).
But I couldn't find it here. I can see OCISessionGet()'s mode is OCI_DEFAULT.
For example if we run the query:
select
count(*)
from
contract a
,
contract b
,
contract c
There is no way to cancel it without waiting for the result of it.
related to K2InformaticsGmbH/dderl#402
In pipeline queries it would be nice to be able to tell the driver how long it should wait before returning with the rows it already has even if the count is less than N.
From K2InformaticsGmbH/dderl#517
Tested with:
OciPort = erloci:new([{logging, true}, {env, [{"NLS_LANG", "GERMAN_SWITZERLAND.AL32UTF8"}]}]).
OciSession = OciPort:get_session(<<"(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)(HOST=XXXXXXXX)(PORT=XXXXXXXX)))(CONNECT_DATA=(SERVICE_NAME=XE)))">>, <<"XXXXXXXX">>, <<"XXXXXXXX">>).
Select = <<"select SCOTT.NUMBER_LONG.*, SCOTT.NUMBER_LONG.ROWID from SCOTT.NUMBER_LONG">>,
Stmt = OciSession:prep_sql(Select).
Stmt:exec_stmt().
Produces the output:
(sbsgui@127.0.0.1)3> OciPort = erloci:new([{logging, true}, {env, [{"NLS_LANG", "GERMAN_SWITZERLAND.AL32UTF8"}]}]).
15.10.2018 14:25:23.992034 [debug] [_OCI_] {oci_logger,,71} ---- ERLOCI PORT PROCESS LOGGER ----
15.10.2018 14:25:23.995507 [debug] [_OCI_] {oci_port,,292} DYLD_LIBRARY_PATH = .../Users/agustin/Documents/oracle/instantclient_11_2
15.10.2018 14:25:23.995768 [debug] [_OCI_] {oci_port,,300} Extra Env :[{"NLS_LANG","GERMAN_SWITZERLAND.AL32UTF8"}]
15.10.2018 14:25:23.995890 [debug] [_OCI_] {oci_port,,310} Executable "_build/default/lib/erloci/priv/ocierl"
15.10.2018 14:25:23.995988 [debug] [_OCI_] {oci_port,,311} Options :[{packet,4},
binary,exit_status,use_stdio,
{args,["262144","true","54930"]},
{env,[{"DYLD_LIBRARY_PATH",
"/Users/agustin/Documents/oracle/instantclient_11_2"},
{"NLS_LANG","GERMAN_SWITZERLAND.AL32UTF8"}]}]
15.10.2018 14:25:23.996786 [debug] [_OCI_] {oci_port,,321} started log enabled new port:
[{name,"_build/default/lib/erloci/priv/ocierl"},
{links,[<0.28905.0>]},
{id,9183},
{connected,<0.28905.0>},
{input,0},
{output,19},
{os_pid,57871}]
15.10.2018 14:25:23.997011 [debug] [_OCI_] {oci_logger,,116} 15.10.2018 14:25:23.996967 Waiting for peer to connect on 54930
15.10.2018 14:25:24.018012 [debug] [_OCI_] {oci_logger,,124} 15.10.2018 14:25:24.017937 Connection from 54931 to 54930
15.10.2018 14:25:24.018248 [info] [_OCI_] {c_src/erloci_drv/erloci.cpp,main,83} [57871] Port process configs : erlang term max size 0x00040000 bytes, logging enabled, TCP port for logs 54930, NLS_LANG GERMAN_SWITZERLAND.AL32UTF
{oci_port,<0.28905.0>}
15.10.2018 14:25:24.018451 [debug] [_OCI_] {c_src/erloci_drv/threads.cpp,threads,39} Initializing Thread pool..
(sbsgui@127.0.0.1)4> OciSession = OciPort:get_session(<<"(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)(HOST=XXXXXXXX)(PORT=XXXXXXXX)))(CONNECT_DATA=(SERVICE_NAME=XE)))">>, <<XXXXXXXX>>, <<XXXXXXXX>>).
15.10.2018 14:25:24.034922 [info] [_OCI_] {c_src/erloci_lib/ocisession.cpp,config,69} OCI Initialize
15.10.2018 14:25:24.089419 [info] [_OCI_] {c_src/erloci_drv/command.cpp,change_log_flag,54} Enabled logging..
15.10.2018 14:25:24.090126 [info] [_OCI_] {oci_port,,429} Remote log_enabled
15.10.2018 14:25:24.090441 [debug] [_OCI_] {oci_port,,369} no reply for log_enabled
{oci_port,<0.28905.0>,140675075038352}
15.10.2018 14:25:24.127040 [info] [_OCI_] {c_src/erloci_lib/ocisession.cpp,ocisession,128} got session 0x7ff179031338 (DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.1.43)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=XE))) user scott
(sbsgui@127.0.0.1)5> Select = <<"select SCOTT.NUMBER_LONG.*, SCOTT.NUMBER_LONG.ROWID from SCOTT.NUMBER_LONG">>,
(sbsgui@127.0.0.1)5> Stmt = OciSession:prep_sql(Select).
{oci_port,statement,<0.28905.0>,140675075038352,
140675073984544}
(sbsgui@127.0.0.1)6> Stmt:exec_stmt().
15.10.2018 14:25:25.423975 [error] [_OCI_] {c_src/erloci_lib/ocistmt.cpp,execute,707} Unsupported column type 8
{error,{0,<<"[execute:706] unsupporetd type 8\n">>}}
15.10.2018 14:25:25.424772 [debug] [_OCI_] {c_src/erloci_drv/threads.cpp,~threads,85} Cleanup Thread pool..
{oci_logger,108} TCP closed
{oci_logger,137} Terminating normal
(sbsgui@127.0.0.1)7> OciSession:prep_sql(Select).
** exception exit: {noproc,
{gen_server,call,
[<0.28905.0>,
{port_call,
[4,140675075038352,
<<"select SCOTT.NUMBER_LONG.*, SCOTT.NUMBER_LONG.ROWID from SCOTT.NUMBE"...>>]},
infinity]}}
in function gen_server:call/3 (gen_server.erl, line 214)
in call from oci_port:prep_sql/2 (/Users/agustin/Documents/k2_informatics/sbsgui/_build/default/lib/erloci/src/oci_port.erl, line 139)
(sbsgui@127.0.0.1)8> 14:26:03.259 [info] [_DDRL_] {dderl_session,159} session {<0.28862.0>,<<>>} idle for 90000 ms
14:26:03.259 [info] [_DDRL_] {dderl_session,195} dderl_session {<0.28862.0>,<<>>} terminating, reason normal
Hi I am seeing wrong results when using oci_util:from_dts/1 function for the fractional part. The problem seems to be matching using little endian instead of big when decoding the value.
Also #5 doesn't seem to be correct as I can read the data in binary format.
null values are not distinguishable
order by column desc return the rows in ascending order, and asc in descending.
create table testdate( id integer, datefield timestamp)
insert into testdate (id,datefield) values (4, to_date('01.10.2014 00:00:00','DD.MM.YYYY HH24:MI:SS'))
select * from testdate
With the current version two of the Eunit tests are failing, please see the log files of the compiling and testing steps.
cc : @ElMaxo
> SelStmt = OciSession:prep_sql(
"select to_char(sysdate, 'DD-MM-YYYY HH24:MI:SS'), sysdate from dual").
> SelStmt:exec_stmt().
{cols,[{<<"TO_CHAR(SYSDATE,'DD-MM-YYYYHH24:MI:SS')">>,
'SQLT_CHR',38,0,0},
{<<"SYSDATE">>,'SQLT_DAT',7,0,0}]}
> SelStmt:fetch_rows(100).
{{rows,[[<<"29-06-2017 10:58:18">>,
<<120,117,6,29,11,59,19>>]]},
true}
> oci_util:oradate_to_str(<<120,117,6,29,11,59,19>>).
"****.06.29 11:59:19"
Hours, minutes and seconds shifted by 1
Current
application:stop(erloci).
application:start(erloci).
f().
InsSql = <<"insert into test values(:P_VALUE)">>.
InsBind = [{<<":P_VALUE">>, in,'SQLT_INT}].
OciPort = erloci:new([{env,[{"NLS_LANG","GERMAN_SWITZERLAND.AL32UTF8"}]}]).
Sess = OciPort:get_session(<<"(DESCRIPTION =(ENABLE=BROKEN)(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)
(HOST=1.1.1.1)(PORT = 1111)))(CONNECT_DATA=(SERVER=DEDICATED)
(SERVICE_NAME=XE)))">>, <<"user">>, <<"password">>).
InsStmt = Sess:prep_sql(InsSql).
ok = InsStmt:bind_vars(InsBind).
InsStmt:exec_stmt([{1}]).
{error,{1,
<<"ORA-00001: unique constraint (SCOTT.TEST_UNIQUE) violated\n">>}}
InsStmt:exec_stmt([{1}]).
** exception error: no function clause matching
oci_port:'-collect_grouped_bind_request/6-fun-0-'({error,0,<<"invalid statement handle">>},[])
(src/oci_port.erl, line 180)
in function lists:foldl/3 (lists.erl, line 1262)
in call from oci_port:collect_grouped_bind_request/6 (src/oci_port.erl, line 180)
Expected
...
InsStmt:exec_stmt([{1}]).
{error,{1,
<<"ORA-00001: unique constraint (SCOTT.TEST_UNIQUE) violated\n">>}}
InsStmt:exec_stmt([{1}]).
{error,{1,
<<"ORA-00001: unique constraint (SCOTT.TEST_UNIQUE) violated\n">>}}
InsStmt:exec_stmt([{2}]).
{rowids,[<<"AAAS66AABAAALLRAAA">>]}
InsStmt:exec_stmt([{2}]).
{error,{1,
<<"ORA-00001: unique constraint (SCOTT.TEST_UNIQUE) violated\n">>}}
~/erlang/research/erloci (master) 326h18m $ rebar co
==> erloci (compile)
c++ -ggdb -Wall -I/Users/homeway/erlang/erts/17.3/lib/erl_interface-3.7.18/include -Ic_src/erloci_drv -Ic_src/erloci_lib -I/Users/homeway/Applications/oracle_client_sdk_11_2/sdk/include -c -o c_src/erloci_drv/threads.o c_src/erloci_drv/threads.cpp
c_src/erloci_drv/threads.cpp:181:3: error: use of undeclared identifier 'pthread_yield'
pthread_yield();
^
1 error generated.
make: *** [c_src/erloci_drv/threads.o] Error 1
ERROR: Command [compile] failed!
Works:
PlSql = <<"BEGIN :p_Absolute:=round(abs(:p_val1),0); :p_Floor:=round(floor(:p_val2),0); END;">>.
PlSqlBindVars = [{<<":p_val1">>,in,'SQLT_VNU'},{<<":p_val2">>,in,'SQLT_VNU'},
{<<":p_Absolute">>,out,'SQLT_INT'},{<<":p_Floor">>,out,'SQLT_INT'}].
PlSqlStmt = OciSession:prep_sql(PlSql).
ok = PlSqlStmt:bind_vars(PlSqlBindVars).
PlSqlStmt:exec_stmt([{oci_util:to_num("-5.5"), oci_util:to_num("4.9"),0,0}], 1).
> {executed,1,[{<<":p_Absolute">>,6},{<<":p_Floor">>,4}]}
ok = PlSqlStmt:close().
Doesn't work:
PlSql = <<"BEGIN :p_Absolute := abs(:p_val1); :p_Floor := floor(:p_val2); END;">>.
PlSqlBindVars = [{<<":p_val1">>,in,'SQLT_VNU'},{<<":p_val2">>,in,'SQLT_VNU'},
{<<":p_Absolute">>,out,'SQLT_VNU'},{<<":p_Floor">>,out,'SQLT_VNU'}].
PlSqlStmt = OciSession:prep_sql(PlSql).
ok = PlSqlStmt:bind_vars(PlSqlBindVars).
PlSqlStmt:exec_stmt([{oci_util:to_num("-5.5"), oci_util:to_num("4.9"),
oci_util:to_num("-100.100"), oci_util:to_num("-100.100")}], 1).
> {error,{0,
<<"[ocistmt::execute:763] unsupporetd type 6\n">>}}
ok = PlSqlStmt:close().
Queries like this one should be supported in DDerl:
begin pkg_mtrac_sms.scan_index(:SQLT_STR_TABLE, :SQLT_DAT_START_DATE, :SQLT_DAT_END_DATE, :SQLT_STR_SENDER, :SQLT_STR_RECEIVER, :SQLT_STR_SHORTID, :SQLT_STR_GENERATED, :SQLT_VNU_ROWLIMIT, :SQLT_DAT_OUT_START_DATE, :SQLT_DAT_OUT_END_DATE, :SQLT_VNU_OUT_COUNT); end;
This means that we need to support DATE out parameter binding.
We stumbled upon a problem when one of the tables was blocked by a non terminated transaction. The call to exec_stmt will never finish
and after login out of dderl ocierl.exe was hanging around even after restarting the service with the table locked (was not able to reproduce that
locally on os x).
I tried creating a table with only one column and then added rows 1 & 2:
OciPort = erloci:new([{logging, true}, {env, [{"NLS_LANG", "GERMAN_SWITZERLAND.AL32UTF8"}]}]).
OciSession = OciPort:get_session(<<"(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)(HOST=XX.XX.XXX.XXX)(PORT=XXXX)))(CONNECT_DATA=(SERVICE_NAME=XE)))">>,
<<"user">>, <<"pass">>).
CreateTable = <<"create table test (COL1 int)">>.
CreateStmt = OciSession:prep_sql(CreateTable).
CreateStmt:exec_stmt().
Then in 2 separated vms executed:
DeleteRow = <<"delete from test where COL1 = :SOMEVAR">>.
DeleteStmt = OciSession:prep_sql(DeleteRow).
DeleteStmt:bind_vars([{<<":SOMEVAR">>, 'SQLT_STR'}]).
DeleteStmt:exec_stmt([{<<"2">>}],0).
On the first one I got:
([email protected])43> DeleteStmt:exec_stmt([{<<"2">>}],0).
23.11.2016 19:44:30.520476 [debug] [_OCI_] {c_src/erloci_drv/command.cpp,exec_stmt,525} Bounds
{rowids,[<<"AAAU99AABAAALJxAAA">>]}
But the second one was a blocking call, maybe this is the expected behavior when a transaction can't be completed ?
Hi,
Thanks for doing massive work on this driver!
I've tried using it and have issues establishing connection. Here's the log:
27.09.2017 21:32:36.094314 [debug] [_OCI_] {oci_logger,,71} ---- ERLOCI PORT PROCESS LOGGER ----
27.09.2017 21:32:36.097670 [debug] [_OCI_] {oci_port,,292} LD_LIBRARY_PATH = .../Projects/milo/_build/dev/lib/erloci/priv
27.09.2017 21:32:36.098060 [debug] [_OCI_] {oci_port,,300} Extra Env :[]
27.09.2017 21:32:36.098455 [debug] [_OCI_] {oci_port,,310} Executable "/Projects/milo/_build/dev/lib/erloci/priv/ocierl"
27.09.2017 21:32:36.098859 [debug] [_OCI_] {oci_port,,311} Options :[{packet,4},
binary,exit_status,use_stdio,
{args,["262144","true","55461"]},
{env,[{"LD_LIBRARY_PATH",
"/usr/lib/oracle/12.1/client64/lib:/Projects/milo/_build/dev/lib/erloci/priv"}]}]
27.09.2017 21:32:36.099386 [debug] [_OCI_] {oci_port,,325} started log disabled new port:
[{name,"/Projects/milo/_build/dev/lib/erloci/priv/ocierl"},
{links,[<0.433.0>]},
{id,85392},
{connected,<0.433.0>},
{input,0},
{output,19},
{os_pid,251}]
27.09.2017 21:32:36.099857 [debug] [_OCI_] {oci_logger,,116} 27.09.2017 21:32:36.099829 Waiting for peer to connect on 55461
27.09.2017 21:32:36.107492 [debug] [_OCI_] {oci_logger,,124} 27.09.2017 21:32:36.107444 Connection from 57618 to 55461
27.09.2017 21:32:36.108115 [info] [_OCI_] {c_src/erloci_drv/erloci.cpp,main,83} [251] Port process configs : erlang term max size 0x00040000 bytes, logging enabled, TCP port for logs 55461, NLS_LANG
27.09.2017 21:32:36.111050 [info] [_OCI_] {c_src/erloci_lib/ocisession.cpp,config,69} OCI Initialize
27.09.2017 21:32:36.112281 [info] [_OCI_] {c_src/erloci_drv/command.cpp,change_log_flag,46} Disabling logging..
27.09.2017 21:32:36.112370 [debug] [_OCI_] {oci_port,,369} no reply for log_disabled
** (exit) exited in: :gen_server.call(#PID<0.433.0>, {:port_call, [2, "(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp) (HOST=127.0.0.1) (PORT=4421)) (CONNECT_DATA=(SID=sid_name)))", "user", nil, "nonode@nohost:<0.429.0>"]}, :infinity)
** (EXIT) an exception was raised:
** (FunctionClauseError) no function clause matching in :oci_port.handle_result/3
(erloci) /Projects/milo/deps/erloci/src/oci_port.erl:428: :oci_port.handle_result(0, {<<131, 104, 2, 103, 100, 0, 13, 110, 111, 110, 111, 100, 101, 64, 110, 111, 104, 111, 115, 116, 0, 0, 1, 173, 0, 0, 0, 0, 0, 114, 0, 3, 100, 0, 13, 110, 111, 110, 111, 100, 101, 64, 110, 111, 104, 111, 115, 116, 0, ...>>, 2}, {:oci_logger, #PID<0.434.0>})
(erloci) /Projects/milo/deps/erloci/src/oci_port.erl:367: :oci_port.handle_info/2
(stdlib) gen_server.erl:616: :gen_server.try_dispatch/4
(stdlib) gen_server.erl:686: :gen_server.handle_msg/6
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
(stdlib) gen_server.erl:214: :gen_server.call/3
(erloci) /Projects/milo/deps/erloci/src/oci_port.erl:82: :oci_port.get_session/5
(milo) lib/milo/repo.ex:7: Milo.Repo.all/1
iex(1)>
21:32:36.122 [error] GenServer #PID<0.433.0> terminating
** (FunctionClauseError) no function clause matching in :oci_port.handle_result/3
(erloci) /Projects/milo/deps/erloci/src/oci_port.erl:428: :oci_port.handle_result(0, {<<131, 104, 2, 103, 100, 0, 13, 110, 111, 110, 111, 100, 101, 64, 110, 111, 104, 111, 115, 116, 0, 0, 1, 173, 0, 0, 0, 0, 0, 114, 0, 3, 100, 0, 13, 110, 111, 110, 111, 100, 101, 64, 110, 111, 104, 111, 115, 116, 0, ...>>, 2}, {:oci_logger, #PID<0.434.0>})
(erloci) /Projects/milo/deps/erloci/src/oci_port.erl:367: :oci_port.handle_info/2
(stdlib) gen_server.erl:616: :gen_server.try_dispatch/4
(stdlib) gen_server.erl:686: :gen_server.handle_msg/6
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message: {#Port<0.10674>, {:data, <<131, 104, 2, 109, 0, 0, 0, 61, 131, 104, 2, 103, 100, 0, 13, 110, 111, 110, 111, 100, 101, 64, 110, 111, 104, 111, 115, 116, 0, 0, 1, 173, 0, 0, 0, 0, 0, 114, 0, 3, 100, 0, 13, 110, 111, 110, 111, 100, ...>>}}
State: {:state, #Port<0.10674>, false, 0, {:oci_logger, #PID<0.434.0>}, :undefined, 0, :undefined}
when trying to edit/insert a CLOB the driver returns Unsupported type in bind
which I see is defined on
erloci/c_src/erloci_drv/marshal.cpp
Line 503 in 7b9d2fd
and I don't see SQLT_CLOB
in the switch case, would it be possible to support this type ?.
cc @stoch
11:30.998000 [error] {oci_port,,413} Abnormal termination of {function_clause,
[{gen_server,reply,
[<0.255.0>,ok],
[{file,"gen_server.erl"},{line,240}]},
{oci_port,handle_info,2,
[{file,"src/oci_port.erl"},{line,377}]},
{gen_server,try_dispatch,4,
[{file,"gen_server.erl"},{line,615}]},
{gen_server,handle_msg,5,
[{file,"gen_server.erl"},{line,681}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,239}]}]}
=ERROR REPORT==== 17-Mar-2017::08:11:30 ===
** Generic server <0.255.0> terminating
** Last message in was {#Port<0.30613>,
{data,<<131,104,3,109,0,0,0,27,131,103,100,0,13,110,
111,110,111,100,101,64,110,111,104,111,115,
116,0,0,0,255,0,0,0,0,0,97,3,100,0,2,111,107>>}}
** When Server state == {state,#Port<0.30613>,false,1,
{oci_logger,<0.256.0>},
undefined,1000,#Ref<0.0.3.1309>}
** Reason for termination ==
** {function_clause,[{gen_server,reply,
[<0.255.0>,ok],
[{file,"gen_server.erl"},{line,240}]},
{oci_port,handle_info,2,
[{file,"src/oci_port.erl"},{line,377}]},
{gen_server,try_dispatch,4,
[{file,"gen_server.erl"},{line,615}]},
{gen_server,handle_msg,5,
[{file,"gen_server.erl"},{line,681}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,239}]}]}
Prepare the statement and call fetch_rows
and the result is as following
{error,{0,<<23,141,89,89>>}}
I used the following code to test performance [Use p(1000), for example]. But after some successful operations, server rejects further insertions with ORA-01000 error.
Please tell me what is wrong. Thanks.
t.erl:
-module(t).
-export([p/1,p_p/2]).
p(N) ->
application:start(erloci),
OciPort = erloci:new([{logging, false}]),
Tns= <<"(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)(HOST=10.143.132.100)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=bimstest)))">>,
User= <<"bill">>,
Pswd= <<"bill123">>,
OciSession = OciPort:get_session(Tns, User, Pswd),
process_flag(trap_exit, true),
p_create(N,OciSession),
p_exit(N).
p_create(0,_) ->
ok;
p_create(N,OciSession) ->
spawn_link(?MODULE,p_p,[N,OciSession]),
p_create(N-1,OciSession).
p_p(N,OciSession) ->
S=iolist_to_binary(["insert into test_2 values(",integer_to_list(N),",",integer_to_list(N),")"]),
Stmt=OciSession:prep_sql(S),
io:format("~p |-~p--| pn",[S,Stmt,Stmt:exec_stmt()]),
case Stmt:close() of
ok ->
io:format("Statement close ok!~n");
Err ->
io:format("Statement close err:pn",[Err])
end.
p_exit(0) ->
ok;
p_exit(N) ->
receive
{'EXIT',_FromPid,_Reason} ->
p_exit(N-1);
_ ->
p_exit(N)
end.
cc @acautin @stoch
Ref : https://docs.oracle.com/cd/B28359_01/appdev.111/b28395/oci17msc002.htm#i578721
oraub8 loblenc = 0;
checkerr(&r,
OCILobRead2((OCISvcCtx*)_svchp, (OCIError*)_errhp, lob,
/* oraub8 *byte_amtp (IN/OUT)
IN - The number of bytes to read from the database. Used for BLOB and BFILE always. For CLOB and NCLOB, it is used only when char_amtp is zero.
OUT - The number of bytes read into the user buffer. */
(oraub8*)&loblen,
/* oraub8 *char_amtp (IN/OUT)
IN - The maximum number of characters to read into the user buffer. Ignored for BLOB and BFILE.
OUT - The number of characters read into the user buffer. Undefined for BLOB and BFILE. */
&loblenc,
(oraub8)offset,
(void*)buf,
(oraub8)length,
OCI_ONE_PIECE, (dvoid*)0, (OCICallbackLobRead2)0, (ub2)0, csfrm)
);
if(r.fn_ret != OCI_SUCCESS) {
REMOTE_LOG(ERR, "failed OCILobRead2 for %p reason %s (%s)\n", lob, r.gerrbuf, _stmtstr);
throw r;
}
erloci/c_src/erloci_lib/ocistmt.cpp
Lines 1089 to 1094 in 5e111a7
Always full byte/char length is requested!
Operational statistics should be accessible in order to check / debug proper working conditions and possibly memory leaks:
Ideally, we would be able to dump internal state snapshot when needed and analyze it offline (in some open source analyzer tool or self-woven erlang tool).
If this is too difficult, compiling for debug and starting a pool or single driver in debug mode should at least be possible.
Comments so far:
Native programs like ocierl.exe or erlang VM (erl.exe) doesn’t let inspection for memory leakage or reading of any other internal process state info from outside. So at the moment we can’t debug ocierl.exe for memory leak.
However we can start ocierl.exe differently (compiled with debug) with some Microsoft memory analyzer tool (like http://valgrind.org/ in linux) and try to make it work and interpret the data. Not sure what is available and will work for erloci – requires some trial and error.
If not, please consider creating one which gives insight into the resource consumption per session and statement (together with last access timestamp if possible).
One lead to this direction would be https://msdn.microsoft.com/en-us/library/x98tx3cf.aspx a good approach to detect memory leaks. I am not sure however it can be per OCI session/statement (not even sure I can be per thread). I can’t confirm what will be possible until I try different options.
Following is an example of writing values and then reading the same back and checking for differences
Vars = [{<<":P_CON_ID">>, in,'SQLT_CHR'}, {<<":P_CON_ACID">>, in,'SQLT_CHR'}, {<<":P_CON_CONSOL">>, in,'SQLT_CHR'}, {<<":P_CON_DATEBLOCK">>, in,'SQLT_CHR'},{<<":P_CON_DATEEND">>, in,'SQLT_CHR'}, {<<":P_CON_DATESTART">>, in,'SQLT_CHR'}, {<<":P_CON_ESID">>, in,'SQLT_CHR'},
{<<":P_CON_ESTID">>, in,'SQLT_CHR'},{<<":P_CON_ETID">>, in,'SQLT_CHR'}, {<<":P_CON_HDGROUP">>, in,'SQLT_CHR'}, {<<":P_CON_IGNORE_DUOBILL">>, in,'SQLT_CHR'}, {<<":P_CON_IWRS">>, in,'SQLT_CHR'},{<<":P_CON_MFGR">>, in,'SQLT_CHR'}, {<<":P_CON_MFLID">>, in,'SQLT_CHR'},
{<<":P_CON_MINCHARGE">>, in,'SQLT_CHR'}, {<<":P_CON_MOROAMINGPROM">>, in,'SQLT_CHR'},{<<":P_CON_MTROAMINGPROM">>, in,'SQLT_CHR'}, {<<":P_CON_NAME">>, in,'SQLT_CHR'}, {<<":P_CON_PMID">>, in,'SQLT_CHR'}, {<<":P_CON_PRICE">>, in,'SQLT_CHR'},{<<":P_CON_PRICEHG">>, in,'SQLT_CHR'},
{<<":P_CON_PRICEINT">>, in,'SQLT_CHR'}, {<<":P_CON_PRICEMOFN">>, in,'SQLT_CHR'}, {<<":P_CON_PROTOCOL">>, in,'SQLT_CHR'},{<<":P_CON_PSCALL">>, in,'SQLT_CHR'}, {<<":P_CON_RSID">>, in,'SQLT_CHR'}, {<<":P_CON_SHORTID">>, in,'SQLT_CHR'}, {<<":P_CON_TARID">>, in,'SQLT_CHR'},
{<<":P_CON_THROUGPUT">>, in,'SQLT_CHR'}].
USql = <<"begin gpsh_tpac_con_put(:P_CON_ID,:P_CON_ACID,:P_CON_CONSOL,:P_CON_DATEBLOCK,:P_CON_DATEEND,:P_CON_DATESTART,:P_CON_ESID,:P_CON_ESTID,:P_CON_ETID,:P_CON_HDGROUP,:P_CON_IGNORE_DUOBILL,:P_CON_IWRS,:P_CON_MFGR,:P_CON_MFLID,:P_CON_MINCHARGE,:P_CON_MOROAMINGPROM,:P_CON_MTROAMINGPROM,:P_CON_NAME,:P_CON_PMID,:P_CON_PRICE,:P_CON_PRICEHG,:P_CON_PRICEINT,:P_CON_PRICEMOFN,:P_CON_PROTOCOL,:P_CON_PSCALL,:P_CON_RSID,:P_CON_SHORTID,:P_CON_TARID,:P_CON_THROUGPUT); end;">>.
RSql = <<"select * from GPSH_TPAC_CON_JSON where CKEY = :P_CON_ID">>.
f(OciPort).
f(Sess).
f(UpdStmt).
f(ConJsonStmt).
f(Diff).
OciPort = erloci:new([{env,[{"NLS_LANG","GERMAN_SWITZERLAND.AL32UTF8"}]}]).
Sess = OciPort:get_session(<<"(DESCRIPTION =(ENABLE=BROKEN)(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=1.1.1.1)(PORT = 2222)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=XE)))">>, <<"a">>, <<"b">>).
UpdStmt = Sess:prep_sql(USql).
ok = UpdStmt:bind_vars(Vars).
ConJsonStmt = Sess:prep_sql(RSql).
ok = ConJsonStmt:bind_vars([{<<":P_CON_ID">>, in, 'SQLT_CHR'}]).
NValue = #{<<"CON_ACID">> => <<"546X0XM3HJ">>,
<<"CON_CONSOL">> => <<"50254">>,
<<"CON_DATEBLOCK">> => <<>>,
<<"CON_DATEEND">> => <<>>,
<<"CON_DATESTART">> => <<"2016-06-15T00:00:00Z">>,
<<"CON_ESID">> => <<"A">>,
<<"CON_ESTID">> => <<>>,
<<"CON_ETID">> => <<"LAC">>,
<<"CON_HDGROUP">> => <<"false">>,
<<"CON_IGNORE_DUOBILL">> => <<"false">>,
<<"CON_IWRS">> => <<>>,
<<"CON_MFGR">> => <<>>,
<<"CON_MFLID">> => <<>>,
<<"CON_MINCHARGE">> => <<"200">>,
<<"CON_MOROAMINGPROM">> => <<"false">>,
<<"CON_MTROAMINGPROM">> => <<"false">>,
<<"CON_NAME">> => <<"SMS Service">>,
<<"CON_PMID">> => <<>>,
<<"CON_PRICE">> => <<"8.00000000000000020000e-02">>,
<<"CON_PRICEHG">> => <<"4.00000000000000010000e-02">>,
<<"CON_PRICEINT">> => <<"8.00000000000000020000e-02">>,
<<"CON_PRICEMOFN">> => <<>>,
<<"CON_PROTOCOL">> => <<"UCP">>,
<<"CON_PSCALL">> => <<"41754312835">>,
<<"CON_RSID">> => <<"P0">>,
<<"CON_SHORTID">> => <<>>,
<<"CON_TARID">> => <<"h">>,
<<"CON_THROUGHPUT">> => <<"1">>}.
Values = [list_to_tuple([<<"ZK04ENGYDW">> | maps:values(NValue)])].
{executed, 1} = UpdStmt:exec_stmt(Values).
{cols, _} = ConJsonStmt:exec_stmt([{<<"ZK04ENGYDW">>}]).
{{rows, [[_,BinVal]]}, true}= ConJsonStmt:fetch_rows(1000).
DstVal = maps:map(
fun(_, I) when is_integer(I) -> integer_to_binary(I);
(_, F) when is_float(F) -> float_to_binary(F);
(_, null) -> <<>>;
(_, A) when A == false; A == true -> atom_to_binary(A, utf8);
(_, B) when is_binary(B) -> B
end, maps:without([<<"AuditTime">>], imem_json:decode(BinVal, [return_maps]))).
lists:foldl(
fun(K, M) ->
L = maps:get(K, NValue, '$missing'),
R = maps:get(K, DstVal , '$missing'),
if L /= R ->
M#{K => #{local => L, remote => R}};
true -> M
end
end, #{}, maps:keys(DstVal)).
Extected #{}. But this is not the case always
> dderloci_utils:oranumber_encode(<<"10.5">>).
<<3,193,11,51>> % Compact represetation
> dderloci_utils:oranumber_encode(<<"10.500">>).
<<3,193,11,51>> % Compact represetation (automatic trailing zeros removal)
> oci_util:from_num(<<3,193,11,51>>).
"10.5"
> float_to_list(10.5, [{decimals,4}]).
"10.5000"
> oci_util:to_num(float_to_list(10.5, [{decimals,4}])).
<<4,193,11,51,1>> % Trailing zeros preserved
> oci_util:from_num(<<4,193,11,51,1>>).
"10.500"
PlSql = <<"BEGIN :p_res1 := 'This is a test1'; :p_res2 := 'This is a test2'; END;">>.
PlSqlBindVars = [{<<":p_res1">>,out,'SQLT_CHR'},{<<":p_res2">>,out,'SQLT_CHR'}].
PlSqlStmt = OciSession:prep_sql(PlSql).
ok = PlSqlStmt:bind_vars(PlSqlBindVars).
PlSqlStmt:exec_stmt([{<<" ">>,<<" ">>}], 1).
> {executed,1,
[{<<":p_res1">>,<<"This is a test1 ">>},
{<<":p_res2">>,<<"This is a test2 ">>}]}
ok = PlSqlStmt:close().
Execute a ping periodically to check if the connection is active or not. If the connection is found stale delete the connection
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.