Skip to Main Content

SQL & PL/SQL

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Why won't this PL/SQL function compile?

3988598Jul 30 2019 — edited Jul 31 2019

Hi,

I'm learning about Oracle Apex, Oracle SQL and PL/SQL and I'm currently learning about functions.  I have written a function in which a table is created, data is stored and the table is returned to the calling query.  The problem is the code won't compile.  I can't see where the problem may be and I've compared the code to various online resources including this site.  Everything looks fine to me, so the answer is not obvious to me.

This is the code I wrote:

    CREATE OR REPLACE TYPE t_table AS OBJECT
    (
      futureValues NUMBER
    );
   
    CREATE OR REPLACE TYPE t_futureValues AS TABLE OF t_table;
    /
   
    CREATE OR REPLACE FUNCTION "CALCULATE_VALUE"( lastRowMinus0 IN NUMBER DEFAULT 1,
                                                       lastRowMinus1 IN NUMBER DEFAULT 2,
                                                       lastRowMinus2 IN NUMBER DEFAULT 3,
                                                       lastRowMinus3 IN NUMBER DEFAULT 4,
                                                       lastRowMinus4 IN NUMBER DEFAULT 5,
                                                       lastRowMinus5 IN NUMBER DEFAULT 6,
                                                       lastRowMinus6 IN NUMBER DEFAULT 7 )
    RETURN t_futureValues AS
                            tableObject         t_futureValues;
                            predictedValue      NUMBER := 0;
                            lastRowMinus0Value  NUMBER := 0;
                            lastRowMinus1Value  NUMBER := 0;
                            lastRowMinus2Value  NUMBER := 0;
                            lastRowMinus3Value  NUMBER := 0;
                            lastRowMinus4Value  NUMBER := 0;
                            lastRowMinus5Value  NUMBER := 0;
                            lastRowMinus6Value  NUMBER := 0;
                            avgDiff             NUMBER := 0;
   
    BEGIN
   
            tableObject := t_futureValues();
   
            lastRowMinus0Value := 3;
            lastRowMinus1Value := 6;
            lastRowMinus2Value := 9;
            lastRowMinus3Value := 12;
            lastRowMinus4Value := 14;
            lastRowMinus5Value := 20;
            lastRowMinus6Value := 60;
   
            avgDiff := (lastRowMinus5Value - lastRowMinus6Value) + avgDiff;
            avgDiff := (lastRowMinus4Value - lastRowMinus5Value) + avgDiff;
            avgDiff := (lastRowMinus3Value - lastRowMinus4Value) + avgDiff;
            avgDiff := (lastRowMinus2Value - lastRowMinus3Value) + avgDiff;
            avgDiff := (lastRowMinus1Value - lastRowMinus2Value) + avgDiff;
            avgDiff := (lastRowMinus0Value - lastRowMinus1Value) + avgDiff;
            avgDiff := avgDiff / 6;                                           
   
            predictedValue := avgDiff + lastRowMinus0Value;                   
   
            begin
                for i in 2..13 loop
                    predictedValue := predictedValue + avgDiff;
   
                    IF predictedValue < 0 THEN
                       predictedValue := 0;
                    END IF;
   
                    insert into tableObject(futureValues)
                    values(predictedValue);
   
                end loop;
            end;
   
            RETURN (tableObject);
   
    END;

The error message I get is:

ORA-06545: PL&#x2F;SQL: compilation error - compilation aborted ORA-06550: line 6, column 1: PLS-00103: Encountered the symbol &quot;CREATE&quot; ORA-06550: line 0, column 0: PLS-00565: T_TABLE must be completed as a potential REF target (object type)

I have no doubt that the problem is something simple, so if anyone knows, then I'd be grateful.

Comments

Gaz in Oz

What is your perl version?

What is your Oracle database version?

What is your Oracle:::DBD version?

What tool did you use to come to the conclusion that "empty parameter is passed to function"?

How are you declaring the 2MB "string" that you pass to function?

Does your function have an EXCEPTION block that swallows Oracle errors?

Please create a simple, small code snippet that reproduces the problem and can be run by others to help analyse the issue...

Billy Verreynne

Likely caused by not explicitly treating the bind variable explicitly as a CLOB, in Perl.

Keep in mind that a LOB variable is actually a locator (pointer) variable.

2810868

Hi Gaz in Oz.

Thanks for replying. Much apologize for incomplete definition.

1. What is your perl version?

Will update as soon as will get information from Perl developers.

2. What is your Oracle database version?

11.2.0.4 EE.

3. What is your Oracle:::DBD version?

Will update as soon as will get information from Perl developers.

4. What tool did you use to come to the conclusion that "empty parameter is passed to function"?

As was_captured column in v$sql_bind_capture shown 'NO' for query passed from Perl we captured traffic with tcpdump and calculated size of the parameter in test function.

In case of passing value to function (through binding in Perl) it was 0 and 0 respectively.

In case of inserting value into the table (through binding in Perl) value presented in tcpdump output and correct length of the variable in test function.

5. How are you declaring the 2MB "string" that you pass to function?

In PL/SQL function it was declared as clob. In Perl variable was declared as described in https://metacpan.org/pod/DBD::Oracle#Binding-for-Updates-and-Inserts-for-CLOBs-and-BLOBs (adapted to our case)

my $in_blob = <was passed from simple Web interface>;

$SQL='insert into test_lob3@tpgtest (id,clob1,clob2, blob1,blob2) values(?,?,?,?,?)';

$sth=$dbh->prepare($SQL );

$sth->bind_param(1,3);

$sth->bind_param(2,$in_clob,{ora_type=>SQLT_CHR});

$sth->bind_param(3,$in_clob,{ora_type=>SQLT_CHR});

$sth->bind_param(4,$in_blob,{ora_type=>SQLT_BIN});

$sth->bind_param(5,$in_blob,{ora_type=>SQLT_BIN});

$sth->execute();

6. Does your function have an EXCEPTION block that swallows Oracle errors?

No at a moment. But an error was in the tcpdump. If I correctly recall it was ora-01403 no data found.

Please create a simple, small code snippet that reproduces the problem and can be run by others to help analyse the issue...

PL/SQL part:

create table tmp_tmp (

  str clob

);

create or replace function fn_HDedup_Start (

  s_Id in varchar2,

  s_Time in varchar2,

  c_Str in clob

) return integer

  authid definer

is

  pragma autonomous_transaction;

begin

  insert

    into tmp_tmp

    values (c_Str);

  return 0;

end fn_HDedup_Start;

I will upload Perl code when get it from Perl developers.

2810868

Hi Billy~Verreynne.

Thanks for replying.

Billy~Verreynne wrote:

Likely caused by not explicitly treating the bind variable explicitly as a CLOB, in Perl.

Keep in mind that a LOB variable is actually a locator (pointer) variable.

Perl developers used https://metacpan.org/pod/DBD::Oracle#Binding-for-Updates-and-Inserts-for-CLOBs-and-BLOBs to code Perl part. The disappointing thing for us is that we were able to pass clob value on insert but same technique used to pass value to the function failed.

Cookiemonster76

Not your current problem, but you'll hit it when you fix your current problem:

Autonomous transactions need to end with either commit or rollback. If they don't oracle will throw an error.

Your function has neither.

2810868

You are absolutely correct Cookiemonster76.

Original code does have commit at the end. I cut too much preparing code snippet. Sorry for confusing.

2810868

1. v5.16.3,

RHEL 7.4 (Maipo), 2.6.9-89.0.0.0.1.ELxenU

2. Instant client : 11.2.0.3.0

3.

$DBD::Oracle::VERSION = '1.74';

DBI version  $VERSION = "1.637"

5. Perl code:

foreach my $parameter (@parameter_names) {

  if ($parameter_type =~ /clob/i) {

    eval {

      $sth->bind_param(':' . $parameter, $parameters{$parameter}, {ora_type=>ORA_CLOB})

    };

  }

  elsif ($parameter_type =~ /blob/i) {

    eval {

      $sth->bind_param(':' . $parameter, $parameters{$parameter}, {ora_type=>ORA_BLOB})

    };

  }

  else {

    eval {

      $sth->bind_param(':' . $parameter, $parameters{$parameter})

    };

  }

}

If works for insert but does not work for function.

Code from the reference did not work for us for both insert and pass.

Working code:

insert into test_table values(:str_clob);

Code that does not work:

SELECT remaining_id FROM TABLE(

fn_function(:id,:time_stamp,:str_clob)

)

6. Perl snippet:

if ($max_clob_length == 0) {

    $sth = $dbh->prepare($query_configuration->{'query'})

        or return $this->_process_error('DB', $DBI::errstr);

}

else {

    $dbh->{LongReadLen} = $max_clob_length;

    $sth = $dbh->prepare($query_configuration->{'query'}, {ora_pers_lob=>1})

        or return $this->_process_error('DB', $DBI::errstr);

}

foreach my $parameter (@parameter_names) {

  if ($parameters_type{$parameter} =~ /^clob$/i) {

    eval {                                                                      

        $sth->bind_param(':' . $parameter, $parameters{$parameter}, {ora_type=>ORA_CLOB})

    };

  }

  elsif ($parameters_type{$parameter} =~ /^blob$/i) {

    eval {

        $sth->bind_param(':' . $parameter, $parameters{$parameter}, {ora_type=>ORA_BLOB})

    };

  }

  else {

      eval {

          $sth->bind_param(':' . $parameter, $parameters{$parameter})

     };

  }

  return $this->_process_error($@) if $@;

}

unless ($sth->execute()) {

    my $errstr = $DBI::errstr;

    $dbh->rollback;

    return $this->_process_error('DB', $errstr);

}

Cookiemonster76

The problem is probably in the perl side, and quite probably in the code you omitted.

Simplify things and build up.

Can you get a function with a single varchar2 parameter to work?

If you can try a single clob parameter (so no other parameters)

then add the other parameters.

2810868

It works as expected when we are passing varchar from Perl side (it was clob in Oracle side). But in this case the limit is 4000 symbols only that is not enough for us.

We simplified code on both sides just to call function on Perl side and print length of the variable passed on the Oracle side. Unfortunately that did not work.

Cookiemonster76

So post a full set of perl code that works, a full set of perl code that doesn't work and the error message.

You're giving us lots of code snippets that don't add up to a complete picture.

2810868

Finally it was a time of the source code. According with Perl developer's investigation looks clob could be passed only for insert/update statements. For function it is expected to have begin : p := f(:clob) end construction.

1 - 11

Post Details

Added on Jul 30 2019
14 comments
2,238 views