Akoya has asked for the wisdom of the Perl Monks concerning the following question:

Oh, wise and powerful Oz Monks!

I am new to DBI, and having some difficulty using an insert with the returning into clause. I am using Perl 5.6.0 and DBI 1.14 on Solaris 2.6 with Oracle 10g.

I am having difficulty understanding how to properly perform an INSERT with a RETURNING INTO clause. The SQL (full Perl code below) that is not working is: What I would like to accomplish is:

INSERT INTO test VALUES ( ?,? ) RETURNING my_id INTO ?

The table, test, was created with:

CREATE TABLE "SPL"."TEST" ( "MY_ID" NUMBER NOT NULL ENABLE, "MY_NAME" VARCHAR2(50) NOT NULL ENABLE, "MY_DESC" VARCHAR2(100), CONSTRAINT "TEST_PK" PRIMARY KEY ("MY_ID") ) ;

The primary key, my_id, is populated with a sequence through the use of a trigger which fires before the insert.

The sequence is defined as:

CREATE SEQUENCE "SPL"."TEST_ID_SEQ" MINVALUE 1 MAXVALUE 999999999999999999999999999 INCREMENT BY 1 START WITH 1020 CACHE 20 NOORDER NOCYCLE ;

and the trigger is defined as:

CREATE OR REPLACE TRIGGER "SPL"."BFR_INS_TEST_TRG" before insert on TEST for each row declare cursor test_id_cur is select test_id_seq.nextval from dual; begin if :new.my_id is null then open test_id_cur; fetch test_id_cur into :new.my_id; close test_id_cur; end if; end BFR_INS_TEST_TRG; / ALTER TRIGGER "SPL"."BFR_INS_TEST_TRG" ENABLE;

The program:

#!/usr/bin/perl use strict; use warnings; use DBI qw(:sql_types); print $DBI::VERSION, "\n"; exit; my $dbh = DBI->connect('dbi:Oracle:db','user','pass', { AutoCommit => 0, RaiseError => 0, PrintError => 0 } ) or die "Unable to connect!: $!\n"; my $sql = qq { INSERT INTO peck_test VALUES ( ?,? ) RETURNING my_id INTO ? }; my $sth = $dbh->prepare($sql); my $id; my $name = 'Bob'; my $desc = 'Just another guy'; $sth->bind_param (1, $name, SQL_VARCHAR); $sth->bind_param (2, $desc, SQL_VARCHAR); $sth->bind_param_inout(3, \$id, SQL_NUMERIC); $sth->execute(); print "Inserted record: $id\n" if $id; $sth->finish(); $dbh->disconnect();

This results in no record being inserted, and likewise no value returned.

This is a much simpler version of what I am actually trying to do, but the method is the same. I have also tried bind_col and bind_columns.

As always, any corrections, suggestions, etc., are greatly appreciated.

Thanks, Akoya

Replies are listed 'Best First'.
Re: INSERT with RETURNING INTO clause
by runrig (Abbot) on Jul 06, 2007 at 17:36 UTC
    Your 'insert into' specifies 2 values, but your 'create table' lists three columns. I think this should throw a mismatch error. But you are not checking for errors, except in the connect, and even there you would be displaying the wrong error message if there were a problem ($! is not a DBI error message, $DBI::errstr is)...try setting RaiseError to 1, and specify column names in your insert statement.

      Thank you for your reply. It was much more useful than the flaming going on in the chatterbox. The solution is as follows:

      1. Change the sql, so that there are 3 placeholders in the values clause:

      my $sql = qq { INSERT INTO peck_test VALUES ( ?,?,? ) RETURNING my_id INTO ? };

      2. Change the binding as follows:

      $sth->bind_param (1, $id, SQL_NUMERIC); $sth->bind_param (2, $name, SQL_VARCHAR); $sth->bind_param (3, $desc, SQL_VARCHAR); $sth->bind_param_inout(4, \$id, SQL_NUMERIC);
      Thanks again, Akoya

        I would also name the fields in the insert statement. It helps self-document and would simplify the command since you could omit the field populated by the trigger. And, it will keep you from having to revise this code should another field be added to the table. Also, if one of the fields you use is renamed or removed, the error messages might be more explicit.

      A reply falls below the community's threshold of quality. You may see it by logging in.