Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BEGIN-END issue with pong function #8

Closed
stoch opened this issue Apr 29, 2020 · 5 comments
Closed

BEGIN-END issue with pong function #8

stoch opened this issue Apr 29, 2020 · 5 comments

Comments

@stoch
Copy link
Contributor

stoch commented Apr 29, 2020

Using oranif for

BEGIN
:VARCHAR2_OUT_RESULT := pong(:VARCHAR2_IN_PING);
END;

returns

{error,function_clause}

whereas using oci for

BEGIN
:SQLT_CHR_OUT_RESULT := pong(:SQLT_CHR_IN_PING);
END;

returns

ORA-06550: Zeile 2, Spalte 29: PLS-00201: Bezeichner 'PONG' muss deklariert werden ORA-06550: Zeile 2, Spalte 1: PL/SQL: Statement ignored

Note: after creating the PONG function, it properly works for oci:

CREATE OR REPLACE
FUNCTION PONG (
p_ping in Varchar2
) Return VARCHAR2
Is
Begin
RETURN p_ping;
End;
/

but not for odpi (no response, no error message).

@KarlKeiser
Copy link
Contributor

Can't reproduce, I tried following escript:

#!/user/bin/escript
%% -*- erlang -*-
%%! -pa _build/default/lib/oranif/ebin

-include_lib("eunit/include/eunit.hrl").
-define(DPI_MAJOR_VERSION, 3).
-define(DPI_MINOR_VERSION, 0).
-define(TNS, <<>>).
main([]) ->
	dpi:load_unsafe(),
	Context = dpi:context_create(?DPI_MAJOR_VERSION, ?DPI_MINOR_VERSION),
    Conn = dpi:conn_create(
        Context, <<"foo">>, <<"bar">>, ?TNS,
        #{encoding => "AL32UTF8", nencoding => "AL32UTF8"}, #{}
    ),
    Sql = <<"BEGIN
              :VARCHAR2_OUT_RESULT := pong(:VARCHAR2_IN_PING);
             END;">>,
    Stmt = dpi:conn_prepareStmt(Conn, false, Sql, <<>>),
    [ok, ok] = [begin
    #{var := VarCol} = dpi:conn_newVar(
        Conn, 'DPI_ORACLE_TYPE_VARCHAR', 'DPI_NATIVE_TYPE_BYTES', 10,
        10, true, false, null
    ),
    dpi:stmt_bindByName(Stmt, X, VarCol)
    end || X <- [<<"VARCHAR2_OUT_RESULT">>, <<"VARCHAR2_IN_PING">>]],

    ?assertException(error, {error, _File, _Line,
        #{message :=  "ORA-06550: line 2, column 39:\n"
                      "PLS-00201: identifier 'PONG' must be declared\n"
                      "ORA-06550: line 2, column 15:\n"
                      "PL/SQL: Statement ignored"}},
        dpi:stmt_execute(Stmt, [])
    ),
    	io:format("Test successful.~n"),
    halt(1).

@KarlKeiser
Copy link
Contributor

ok, I think I understand the problem. It's not an oranif issue, but a dderl issue. If oranif returns an error in a certain place, the error message is discarded. I created a fix for the issue in dderl.

As for the second part, what should the result be? As it is currently, the internal type of the statement is not a query, hence why no result is shown.

@KarlKeiser
Copy link
Contributor

Looks like it's working in oranif. I'll see what the issue it in dderl.

#!/user/bin/escript
%% -*- erlang -*-
%%! -pa _build/default/lib/oranif/ebin

-include_lib("eunit/include/eunit.hrl").
-define(DPI_MAJOR_VERSION, 3).
-define(DPI_MINOR_VERSION, 0).
-define(TNS, <<>>).
main([]) ->
	dpi:load_unsafe(),
	Context = dpi:context_create(?DPI_MAJOR_VERSION, ?DPI_MINOR_VERSION),
    Conn = dpi:conn_create(
        Context, <<"foo">>, <<"bar">>, ?TNS,
        #{encoding => "AL32UTF8", nencoding => "AL32UTF8"}, #{}
    ),
    SqlCreation = <<"CREATE OR REPLACE "
                  "FUNCTION PONG ( "
                  "p_ping in Varchar2 "
                  ") Return VARCHAR2 "
                  "Is "
                  "Begin "
                  "RETURN p_ping; "
                  "End; ">>,
    StmtC = dpi:conn_prepareStmt(Conn, false, SqlCreation, <<>>),
    0 = dpi:stmt_execute(StmtC, []),
    Sql = <<"BEGIN
              :VARCHAR2_OUT_RESULT := pong(:VARCHAR2_IN_PING);
             END;">>,
    Stmt = dpi:conn_prepareStmt(Conn, false, Sql, <<>>),

    #{var := Var1, data := Datas1} = dpi:conn_newVar(
        Conn, 'DPI_ORACLE_TYPE_VARCHAR', 'DPI_NATIVE_TYPE_BYTES', 10,
        10, true, false, null
    ),
    #{var := Var2, data := Datas2} = dpi:conn_newVar(
        Conn, 'DPI_ORACLE_TYPE_VARCHAR', 'DPI_NATIVE_TYPE_BYTES', 10,
        10, true, false, null
    ),
    dpi:var_setFromBytes(Var2, 0, <<"foo">>), % assign to VARCHAR2_OUT_RESULT
    dpi:stmt_bindByName(Stmt, <<"VARCHAR2_OUT_RESULT">>, Var1),
    dpi:stmt_bindByName(Stmt, <<"VARCHAR2_IN_PING">>, Var2),
    0 = dpi:stmt_execute(Stmt, []),
    <<"foo">> = dpi:data_get(lists:nth(1, Datas1)), % read back from VARCHAR2_IN_PING
    io:format("Test successful.~n"),

    % cleanup
    [dpi:data_release(D) || D <- Datas1 ++ Datas2],
    ok = dpi:var_release(Var1),
    ok = dpi:var_release(Var2),
    ok = dpi:stmt_close(StmtC, <<>>),
    ok = dpi:stmt_close(Stmt, <<>>),
    ok = dpi:conn_close(Conn, [], <<>>),
    ok = dpi:context_destroy(Context),
    halt(1).

@c-bik c-bik transferred this issue from KonnexionsGmbH/oranif May 14, 2020
@KarlKeiser
Copy link
Contributor

KarlKeiser commented May 14, 2020

I'm still trying to figure out all the PL/SQL syntax, but I made a demo where a function is created and then called.

In sqlplus:

image

In oranif:

#!/user/bin/escript
%% -*- erlang -*-
%%! -pa _build/default/lib/oranif/ebin

-include_lib("eunit/include/eunit.hrl").
-define(DPI_MAJOR_VERSION, 3).
-define(DPI_MINOR_VERSION, 0).
-define(TNS, <<>>).
main([]) ->
	dpi:load_unsafe(),
	Context = dpi:context_create(?DPI_MAJOR_VERSION, ?DPI_MINOR_VERSION),
    Conn = dpi:conn_create(
        Context, <<"foo">>, <<"bar">>, ?TNS,
        #{encoding => "AL32UTF8", nencoding => "AL32UTF8"}, #{}
    ),
    SqlCreation = <<"CREATE OR REPLACE
                    FUNCTION PONG (
                    p_ping in Varchar2
                    ) Return VARCHAR2
                    Is
                    Begin
                    RETURN concat('returned-', p_ping);
                    End;">>,
    StmtC = dpi:conn_prepareStmt(Conn, false, SqlCreation, <<>>),
    0 = dpi:stmt_execute(StmtC, []),
    Sql = <<"select pong('foo') from dual">>,
    Stmt = dpi:conn_prepareStmt(Conn, false, Sql, <<>>),

    1 = dpi:stmt_execute(Stmt, []),
    dpi:stmt_fetch(Stmt),
    #{data := Result} =
        dpi:stmt_getQueryValue(Stmt, 1),
    ?assertEqual(<<"returned-foo">>, dpi:data_get(Result)),
    dpi:data_release(Result),

    % cleanup,
    ok = dpi:stmt_close(StmtC, <<>>),
    ok = dpi:stmt_close(Stmt, <<>>),
    ok = dpi:conn_close(Conn, [], <<>>),
    ok = dpi:context_destroy(Context),
    io:format("test successful.~n"),
    halt(1).

In dderl:

image

@stoch
Copy link
Contributor Author

stoch commented May 15, 2020

@KarlKeiser Our SQL parser does not support the create statement but DDerl still gives it to the DB to execute. Everything fine here now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants