DML Arrays

Hi,I´m making a query to the database storing the result in an array. so far, i make a definition for each column and then a call to OCIDefineArrayOfStruct.
when i execute the query, i am setting the number of records i can retreive (one of the OCIStmtExecute arguments). The problem is that it is not working when this number is high (in my case higger than 60000, i mean , when i try to retrieve more than 60000 records directly to the array). how can i retrieve higger amount of records directly to the array? May i retrieve them in blocks ? (something how read by 20000 while data and store it in the array) Thanks.

Bug 2821396 (metalink) seems to indicate that the
upper limit for array fetch is 65536. I believe
that the only way to get around this limit is with repeated
calls to OCIStmtExecute. i.e. if you have 70000 rows,
OCIStmtExecute called once with iters=65536 and
then once again with iters=4464.

Similar Messages

  • Problem Enabling DML Array

    I4m migrating from form 4.5 to forms 6i patch4, the original settings for my forms was:
    Block:
    Key Mode: Non-updateable.
    Enforce Primary Key: Yes
    Some Items:
    Primary Key: Yes
    I changed these values to:
    Block:
    Key Mode: Automatic.
    Enforce Primary Key: No
    Some Items:
    Primary Key: No
    but when i set the property DML Array size larger than 1 and compile the forms, i get the following message error.
    FRM-30100 Block must have at least one primary key item.
    If i set the primary key i get:
    FRM-30406 Block with array DML must have requiered primary key items.
    If i try setting different values for these properties always get the same errors.
    Any help please.
    David Alarid.

    David I don't understand here - If you have set an Item as the primary key and set it to be required what error do you now get when you compile?
    I've just created a emp based block set the DML array size to 10, set the Primary key property to Yes on Empno and ensured that required is also set on empno and it compiles fine..

  • CHILD form error FRM-30100: Block must have at least one primary key item.

    Hi friends,
    I have increased the DML array of the child block from 1 to 10, but it throws me error:
    FRM-30100: Block must have at least one primary key item.
    Block: CEC_ADJUSTMENT_RECON
    Form: CEC_ADJ
    FRM-30085: Unable to adjust form for output.
    How does a form know that the table does not have primary key? Is it referring to it?
    Thanks a lot                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               

    I dont understand why do you increase the DML array size..
    Because it says in the HELP
    Specifies the maximum array size for inserting, updating, and deleting records in the database at one time.
    A larger size reduces transaction processing time by reducing network traffic to the database, but requires more memory.  The optimal size is the number of records a user modifies in one transaction.
    The FRM-30100 comes not because of the above property..
    If your query data source type is other than TABLE, it is a must to set at least one database field's PRIMARY KEY ITEM PROPERTY in the block to be a YES.

  • Performance Form based on procedure vs based on table/view

    When we design our form, and want to optimize the performance, we came to a question. Will the performance of a form based on a procedure is better or a form based on a table/view is better? And why is it better? or worse?

    Hello,
    For me, the question is not "is the stored procedure based block is faster than table based block ?", but "do i use the DML array functionality with table based block?"
    If you do not use DML array functionality, then you generate as many roundtrips as you get raws in your block.
    With stored procedure based block, you transmit a pl/sql table of record to the procedure.
    Anyway, you could do some tests to compare the 2 solutions.
    Francois

  • Associative array EXISTS() DML

    Is there a way to include the EXISTS() method of an associative array in a DML statement? For example:
    This is fine...
    SQL> declare
    2 type distTblTyp is table of number index by varchar2(8);
    3 testTbl distTblTyp; testVar varchar2(30);
    4 begin
    5 testTbl('a') := 1;
    6 if (testTbl.exists('a')=true) then
    7 null;
    8 end if;
    9* end;
    SQL> /
    PL/SQL procedure successfully completed.
    But this fails...
    SQL> declare
    2 type distTblTyp is table of number index by varchar2(8);
    3 testTbl distTblTyp; testVar varchar2(30);
    4 begin
    5 testTbl('a') := 1;
    6 select decode(testTbl.exists('a'),true,'a','b')
    7 into testVar from dual;
    8* end;
    SQL> /
    select decode(testTbl.exists('a'),true,'a','b')
    ERROR at line 6:
    ORA-06550: line 6, column 24:
    PL/SQL: ORA-01747: invalid user.table.column, table.column, or column
    specification
    ORA-06550: line 6, column 2:
    PL/SQL: SQL Statement ignored
    PL/SQL: SQL Statement ignored
    Since I won't know which index elements exist until execution time, I want to have an insert statement (ran within a loop) with ~100 field values like:
    insert into table [tablename]
    values (
    decode(testTbl.exists('a'), true, testTbl('a'), null),
    decode(testTbl.exists('b'), true, testTbl('b'), null)
    Any suggestions appreciated.

    As Gerd suggested...
    SQL> create or replace package my_test_pk as
      2   type my_type is table of number index by varchar2(2);
      3   v_my_type my_type;
      4   function ifExists(v_i varchar2) return number;
      5   procedure runTest;
      6  end;
      7  /
    Package created.
    SQL> create or replace package body my_test_pk as
      2  function ifExists(v_i varchar2) return number is
      3     v_r number;
      4     begin
      5     v_r := 0;
      6     if (v_my_type.exists(v_i)) then v_r := 1; end if;
      7     return v_r;
      8     end;
      9  
    10    procedure runTest is
    11    v_check varchar2(2);
    12    begin
    13     v_my_type('a') := 1;
    14    select decode(ifExists('a'),1,'a',null) into v_check from dual;
    15   dbms_output.put_line(v_check);
    16     select decode(ifExists('b'),1,'b','N') into v_check from dual;
    17    dbms_output.put_line(v_check);
    18    end;
    19     end;
    20  /
    Package body created.
    SQL> exec my_test_pk.runtest;
    a
    N
    PL/SQL procedure successfully completed.
    SQL>

  • Getting error-ORA-24381: error(s) in array DML

    Hi i have written the following code to bulk insert into a database table.
    I am getting an error while returning the result of the bulk insert query into the collection
    I have tried to track it by using sql%bulk_exceptions.error_code.
    But the error code that it is showing is just 1.
    I trapped it using sqlerrm.
    and that is showing-error(s) in array DML
    What do i do?
    DECLARE
       CURSOR temp_rec_tap_cur
       IS
          SELECT *
            FROM temp_records_tap;
       TYPE temp_rec_tab IS TABLE OF temp_rec_tap_cur%ROWTYPE;
       v_test_tab   temp_rec_tab;
       v_rec_num    num_tab;
       v_filename   temp_records_tap.file_name%TYPE;
       v_error_code tap_reject.error_code%type;
       v_rej_value  tap_reject.field_rej%type;                      
       v_errors number;   
    BEGIN
       SELECT file_name
         INTO v_filename
         FROM table1
         WHERE ROWNUM<2;
       OPEN temp_rec_tap_cur;
       LOOP
          BEGIN
             FETCH temp_rec_tap_cur
             BULK COLLECT INTO v_test_tab LIMIT 1000;
             FORALL i IN v_test_tab.FIRST .. v_test_tab.LAST SAVE EXCEPTIONS
                INSERT INTO tapdetail_tapin
                     VALUES v_test_tab (i)
                  RETURNING record_num
                    BULK COLLECT INTO v_rec_num;
          EXCEPTION
             WHEN DUP_VAL_ON_INDEX
             THEN
                NULL;
             WHEN OTHERS
             THEN
             v_errors:=sql%bulk_exceptions.count;
             for i in 1..v_errors
             loop
             dbms_output.put_line(sql%bulk_exceptions(i).error_code);
             p3_errorlog ('TAPINDETAWARE', SQLERRM, v_filename);     
             end loop;
             END;
                --RAISE;
          EXIT WHEN temp_rec_tap_cur%NOTFOUND;
       END LOOP;
    INSERT INTO table2
    SELECT file_id, file_name, sender_pmn, recipient_pmn, call_date,
                 call_date_only, call_type, call_number, FIRST_RECORD,
                 service_type, service_code, home_bid, serve_bid,
                 chargeable_subs_type, imsi_min, msisdn_mdn, air_charges,
                 air_charges_sdr, air_time, national_call_charges,
                 national_call_charges_sdr, national_call_time,
                 international_call_charges, international_call_charges_sdr,
                 international_call_time, dir_assist_charges,
                 dir_assist_charges_sdr, dir_assist_time, other_charges,
                 other_charges_sdr, other_time, volume_charges,
                 volume_charges_sdr, volume_units, tot_charges, tot_charges_sdr,
                 tot_duration, state_tax, state_tax_sdr, local_tax,
                 local_tax_sdr, state_and_use_tax, state_and_use_tax_sdr, va_tax,
                 va_tax_sdr, other_tax, other_tax_sdr, charge_refund_indicator,
                 advised_charge_currency, advised_charge, advised_charge_sdr,
                 advised_charge_commission, advised_charge_commission_sdr,
                 exchange_rate, mcc, mnc, process_date, chargeable_units,
                 record_num, mscid,null,null,decode(call_type,0,'250',1,'251',5,'255'),null,'Duplicate Call'
                 from temp_records_tap
                 where record_num not in (select column_value from table(v_rec_num)) ;
    EXCEPTION
    WHEN OTHERS THEN
    p3_errorlog ('TAP', SQLERRM, v_filename);  
    END;Edited by: user8731258 on Sep 14, 2010 2:58 AM
    Edited by: user8731258 on Sep 14, 2010 3:01 AM

    What is the type declaration of num_tab and how is record_num defined?
    ORA-24381: error(s) in array DML
    Cause: One or more rows failed in the DML.indicates that you fail on the insert itself. Are the table definitions the same? Same primary/unique keys?
    Edited by: MBr on 14-Sep-2010 03:16

  • What are right parameter types of ODCIIndexInsert in case of creating indextype WITH ARRAY DML option (documentation mismatch)

    Hello.
    During developing Domain Index for Oracle 11.2.0.1.0 (problem also appears in 12с) i was faced with misunderstanding of parameter types of function
    ODCIIndexInsert in case of creating indextype  WITH ARRAY DML option
    According to Oracle documentation
    http://docs.oracle.com/cd/E11882_01/appdev.112/e10765/ext_idx_ref.htm#i76892
    In case of  WITH ARRAY DML option Oracle will invoke ODCIIndexInsert with following signature
    FUNCTION ODCIIndexInsert(
      ia ODCIIndexInfo,
      ridlist ODCIRidList,
      newvallist varray_of_column_type,
      env ODCIEnv)
    RETURN NUMBER
    In my case indexed column has datatype NUMBER so i defined varray_of_column_type as SYS.ODCINumberList
    STATIC FUNCTION ODCIIndexInsert(ia in sys.ODCIIndexInfo, ridlist in sys.ODCIRidList,  newvallist in sys.ODCINumberList, env in SYS.ODCIEnv) RETURN NUMBER
    Indextype was created as
    CREATE INDEXTYPE test_index_type
    FOR
    test_eq(number, number)
    USING index_methods
    WITH ARRAY DML(number, sys.ODCINumberList)
    WITH LOCAL RANGE PARTITION
    WITH SYSTEM MANAGED STORAGE TABLES;
    or
    CREATE INDEXTYPE test_index_type
    FOR
    test_eq(number, number)
    USING index_methods
    WITH ARRAY DML
    WITH LOCAL RANGE PARTITION
    WITH SYSTEM MANAGED STORAGE TABLES;
    (problem occurs in all cases)
    CREATE TABLE test_table (id NUMBER (19,0));
    CREATE INDEX test_index ON test_table(id) INDEXTYPE IS test_index_type;
    When attempting to insert data in the table
    insert into test_table values (1);
    oracle raise exception
    Error starting at line 53 in command:
    insert into test_table values (1)
    Error at Command Line:53 Column:1
    Error report:
    SQL Error: ORA-29925: cannot execute SCOTT.INDEX_METHODS.ODCIINDEXINSERT
    ORA-06553: PLS-306: wrong number or types of arguments in call to 'ODCIINDEXINSERT'
    ORA-06553: PLS-306: wrong number or types of arguments in call to 'ODCIINDEXINSERT'
    29925. 00000 -  "cannot execute %s"
    *Cause:    The specified function does not exist or does not have an
               appropriate signature.
    *Action:   Implement the function with the appropriate signature.
    So my question is.
    Is it normal behavior  of oracle (according to documentation)?
    What is correct signature of ODCIIndexInsert function in case of INDEXTYPE creation with 'WITH ARRAY DML' option and fact that indexed column has NUMBER datatype?
    By the way if i define indextype without 'WITH ARRAY DML' option signature is clear, and working. But this approach doesn't satisfies our performance needs.
    Also if i define index type with option 'WITH ARRAY DML WITHOUT COLUMN DATA' and use signature
    static function ODCIIndexInsert(ia sys.odciindexinfo,   ridlist sys.odciridlist, env sys.ODCIEnv) return number
    Everything works too. But this approach doesn't satisfies our business needs.
    Is it a way to define ODCIIndexInsert  parameter types (in case of indexing number column)  so that batch inserting works according to documentation ?
    FUNCTION ODCIIndexInsert(
          ia ODCIIndexInfo,
          ridlist ODCIRidList,
          newvallist varray_of_column_type,
          env ODCIEnv)
    I am attaching full sql script to recreate environment and reproduce the problem.
    Type definition:
    CREATE OR REPLACE TYPE index_methods AS OBJECT
      step number,
      STATIC FUNCTION ODCIGetInterfaces(ifclist OUT SYS.ODCIObjectList) RETURN NUMBER,
      STATIC FUNCTION ODCIIndexCreate (ia SYS.ODCIIndexInfo, parms VARCHAR2, env SYS.ODCIEnv) RETURN NUMBER,
      STATIC FUNCTION ODCIIndexAlter (ia sys.ODCIIndexInfo, parms IN OUT VARCHAR2, altopt number, env sys.ODCIEnv) RETURN NUMBER,
      STATIC FUNCTION ODCIIndexDrop(ia SYS.ODCIIndexInfo, env SYS.ODCIEnv) RETURN NUMBER,
      STATIC FUNCTION ODCIIndexExchangePartition(ia SYS.ODCIIndexInfo, ia1 SYS.ODCIIndexInfo, env SYS.ODCIEnv) RETURN NUMBER,
      STATIC FUNCTION ODCIIndexUpdPartMetadata(ia sys.ODCIIndexInfo, palist sys.ODCIPartInfoList, env sys.ODCIEnv) RETURN NUMBER,
      STATIC FUNCTION ODCIIndexInsert(ia in sys.ODCIIndexInfo, ridlist in sys.ODCIRidList,  newvallist in sys.ODCINumberList, env in SYS.ODCIEnv) RETURN NUMBER,
      STATIC FUNCTION ODCIIndexDelete(ia SYS.ODCIIndexInfo, rid VARCHAR2, oldval number, env SYS.ODCIEnv) RETURN NUMBER,
      STATIC FUNCTION ODCIIndexUpdate(ia SYS.ODCIIndexInfo, rid VARCHAR2, oldval number, newval number, env SYS.ODCIEnv) RETURN NUMBER,
      STATIC FUNCTION ODCIIndexStart(sctx IN OUT index_methods, ia SYS.ODCIIndexInfo,
        op SYS.ODCIPredInfo, qi sys.ODCIQueryInfo, strt number, stop number, cmpval number, env SYS.ODCIEnv) RETURN NUMBER,
      MEMBER FUNCTION ODCIIndexFetch(self IN OUT index_methods, nrows NUMBER, rids OUT SYS.ODCIridlist, env SYS.ODCIEnv) RETURN NUMBER,
      MEMBER FUNCTION ODCIIndexClose(self IN index_methods, env SYS.ODCIEnv) RETURN NUMBER
    CREATE OR REPLACE TYPE BODY index_methods IS
    STATIC FUNCTION ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) RETURN NUMBER IS
    BEGIN
      ifclist := sys.ODCIObjectList(sys.ODCIObject('SYS','ODCIINDEX2'));
      RETURN ODCIConst.Success;
    END ODCIGetInterfaces;
    STATIC FUNCTION ODCIIndexCreate (ia sys.ODCIIndexInfo, parms VARCHAR2,  env sys.ODCIEnv) RETURN NUMBER IS
    BEGIN
      RETURN ODCIConst.Success;
    END ODCIIndexCreate;
    STATIC FUNCTION ODCIIndexDrop(ia sys.ODCIIndexInfo, env sys.ODCIEnv) RETURN NUMBER IS
    BEGIN
      RETURN ODCIConst.Success;
    END ODCIIndexDrop;
    STATIC FUNCTION ODCIIndexAlter (
      ia sys.ODCIIndexInfo,
      parms IN OUT VARCHAR2,
      altopt NUMBER,
      env sys.ODCIEnv)
    RETURN NUMBER IS
    BEGIN
      RETURN ODCIConst.Success;
    END ODCIIndexAlter;
    STATIC FUNCTION ODCIIndexUpdPartMetadata(
      ia sys.ODCIIndexInfo,
      palist sys.ODCIPartInfoList,
      env sys.ODCIEnv)
    RETURN NUMBER IS
    BEGIN
      RETURN ODCIConst.Success;
    END ODCIIndexUpdPartMetadata;
    STATIC FUNCTION ODCIIndexExchangePartition(
      ia sys.ODCIIndexInfo,
      ia1 sys.ODCIIndexInfo,
      env sys.ODCIEnv)
    RETURN NUMBER IS
    BEGIN
      RETURN ODCIConst.Success;
    END ODCIIndexExchangePartition;
    STATIC FUNCTION ODCIIndexInsert(
       ia sys.ODCIIndexInfo,
       ridlist sys.ODCIRidList,
       newvallist sys.ODCINumberList,
       env sys.ODCIEnv)
    RETURN NUMBER IS
    BEGIN
      return ODCIConst.Success;
    END;
    STATIC FUNCTION ODCIIndexDelete(
       ia SYS.ODCIIndexInfo,
       rid VARCHAR2,
       oldval number,
       env SYS.ODCIEnv)
    RETURN NUMBER IS
    BEGIN
      return ODCIConst.Success;
    END;
    STATIC FUNCTION ODCIIndexUpdate(
       ia SYS.ODCIIndexInfo,
       rid VARCHAR2,
       oldval number,
       newval number,
       env SYS.ODCIEnv)
    RETURN NUMBER AS
    BEGIN
      return ODCIConst.Success;
    END;
    STATIC FUNCTION ODCIIndexStart(
      sctx IN OUT index_methods,
      ia SYS.ODCIIndexInfo,
      op SYS.ODCIPredInfo,
      qi sys.ODCIQueryInfo,
      strt number,
      stop number,
      cmpval  number,
      env SYS.ODCIEnv)
    RETURN NUMBER AS
    BEGIN
      sctx := index_methods(1);
      return ODCIConst.Success;
    END;
    MEMBER FUNCTION ODCIIndexFetch(
      self IN OUT index_methods,
      nrows NUMBER,
      rids OUT SYS.ODCIridlist,
      env SYS.ODCIEnv)
    RETURN NUMBER AS
    BEGIN
      return ODCIConst.Success;
    END;
    MEMBER FUNCTION ODCIIndexClose(self IN index_methods, env SYS.ODCIEnv) RETURN NUMBER AS
    BEGIN
      return ODCIConst.Success;
    END;
    end;
    Problem workaround:
    --drop function test_eq_fun;
    CREATE FUNCTION test_eq_fun(a number, b number) RETURN NUMBER AS
    BEGIN
      IF a = b then
        RETURN 1;
      ELSE
        RETURN 0;
      END IF;
    END;
    --drop operator test_eq;
    CREATE OPERATOR test_eq
    BINDING (number, number) RETURN NUMBER
    USING test_eq_fun;
    --drop indextype test_index_type;
    CREATE INDEXTYPE test_index_type
    FOR
    test_eq(number, number)
    USING index_methods
    WITH ARRAY DML(number, sys.ODCINumberList)
    WITH LOCAL RANGE PARTITION
    WITH SYSTEM MANAGED STORAGE TABLES;
    CREATE INDEXTYPE test_index_type
    FOR
    test_eq(number, number)
    USING index_methods
    WITH ARRAY DML
    WITH LOCAL RANGE PARTITION
    WITH SYSTEM MANAGED STORAGE TABLES;
    --drop table test_table;
    CREATE TABLE test_table (id NUMBER (19,0));
    CREATE INDEX test_index ON test_table(id) INDEXTYPE IS test_index_type;
    insert into test_table values (1);

    I get single for 1 row and batch for 2 or more rows in the following simplified simulation.
    SCOTT@orcl12c> DESC SYS.ODCINUMBERLIST
    SYS.ODCINUMBERLIST VARRAY(32767) OF NUMBER
    SCOTT@orcl12c> CREATE OR REPLACE TYPE index_methods AS OBJECT
      2  (
      3    step number,
      4    STATIC FUNCTION ODCIGetInterfaces(ifclist OUT SYS.ODCIObjectList) RETURN NUMBER,
      5    STATIC FUNCTION ODCIIndexCreate (ia SYS.ODCIIndexInfo, parms VARCHAR2, env SYS.ODCIEnv) RETURN NUMBER,
      6    STATIC FUNCTION ODCIIndexAlter (ia sys.ODCIIndexInfo, parms IN OUT VARCHAR2, altopt number, env sys.ODCIEnv) RETURN NUMBER,
      7    STATIC FUNCTION ODCIIndexDrop(ia SYS.ODCIIndexInfo, env SYS.ODCIEnv) RETURN NUMBER,
      8    STATIC FUNCTION ODCIIndexExchangePartition(ia SYS.ODCIIndexInfo, ia1 SYS.ODCIIndexInfo, env SYS.ODCIEnv) RETURN NUMBER,
      9    STATIC FUNCTION ODCIIndexUpdPartMetadata(ia sys.ODCIIndexInfo, palist sys.ODCIPartInfoList, env sys.ODCIEnv) RETURN NUMBER,
    10    STATIC FUNCTION ODCIIndexInsert(ia in sys.ODCIIndexInfo, rid in VARCHAR2,  newval in NUMBER, env in SYS.ODCIEnv) RETURN NUMBER,
    11    STATIC FUNCTION ODCIIndexInsert(ia in sys.ODCIIndexInfo, ridlist in sys.ODCIRidList,  newvallist in your_type, env in SYS.ODCIEnv) RETURN NUMBER,
    12    STATIC FUNCTION ODCIIndexDelete(ia SYS.ODCIIndexInfo, rid VARCHAR2, oldval number, env SYS.ODCIEnv) RETURN NUMBER,
    13    STATIC FUNCTION ODCIIndexUpdate(ia SYS.ODCIIndexInfo, rid VARCHAR2, oldval number, newval number, env SYS.ODCIEnv) RETURN NUMBER,
    14    STATIC FUNCTION ODCIIndexStart(sctx IN OUT index_methods, ia SYS.ODCIIndexInfo,
    15       op SYS.ODCIPredInfo, qi sys.ODCIQueryInfo, strt number, stop number, cmpval number, env SYS.ODCIEnv) RETURN NUMBER,
    16    MEMBER FUNCTION ODCIIndexFetch(self IN OUT index_methods, nrows NUMBER, rids OUT SYS.ODCIridlist, env SYS.ODCIEnv) RETURN NUMBER,
    17    MEMBER FUNCTION ODCIIndexClose(self IN index_methods, env SYS.ODCIEnv) RETURN NUMBER
    18  );
    19  /
    Type created.
    SCOTT@orcl12c> CREATE OR REPLACE TYPE BODY index_methods IS
      2  STATIC FUNCTION ODCIGetInterfaces(ifclist OUT sys.ODCIObjectList) RETURN NUMBER IS
      3  BEGIN
      4    ifclist := sys.ODCIObjectList(sys.ODCIObject('SYS','ODCIINDEX2'));
      5    RETURN ODCIConst.Success;
      6  END ODCIGetInterfaces;
      7
      8  STATIC FUNCTION ODCIIndexCreate (ia sys.ODCIIndexInfo, parms VARCHAR2,  env sys.ODCIEnv) RETURN NUMBER IS
      9  BEGIN
    10    RETURN ODCIConst.Success;
    11  END ODCIIndexCreate;
    12
    13  STATIC FUNCTION ODCIIndexDrop(ia sys.ODCIIndexInfo, env sys.ODCIEnv) RETURN NUMBER IS
    14  BEGIN
    15    RETURN ODCIConst.Success;
    16  END ODCIIndexDrop;
    17
    18  STATIC FUNCTION ODCIIndexAlter (
    19    ia sys.ODCIIndexInfo,
    20    parms IN OUT VARCHAR2,
    21    altopt NUMBER,
    22    env sys.ODCIEnv)
    23  RETURN NUMBER IS
    24  BEGIN
    25    RETURN ODCIConst.Success;
    26  END ODCIIndexAlter;
    27
    28  STATIC FUNCTION ODCIIndexUpdPartMetadata(
    29    ia sys.ODCIIndexInfo,
    30    palist sys.ODCIPartInfoList,
    31    env sys.ODCIEnv)
    32  RETURN NUMBER IS
    33  BEGIN
    34    RETURN ODCIConst.Success;
    35  END ODCIIndexUpdPartMetadata;
    36
    37  STATIC FUNCTION ODCIIndexExchangePartition(
    38    ia sys.ODCIIndexInfo,
    39    ia1 sys.ODCIIndexInfo,
    40    env sys.ODCIEnv)
    41  RETURN NUMBER IS
    42  BEGIN
    43    RETURN ODCIConst.Success;
    44  END ODCIIndexExchangePartition;
    45
    46  STATIC FUNCTION ODCIIndexInsert(
    47      ia sys.ODCIIndexInfo,
    48      rid VARCHAR2,
    49      newval NUMBER,
    50      env sys.ODCIEnv)
    51  RETURN NUMBER IS
    52  BEGIN
    53    dbms_output.put_line ('single');
    54    return ODCIConst.Success;
    55  END;
    56
    57  STATIC FUNCTION ODCIIndexInsert(
    58      ia sys.ODCIIndexInfo,
    59      ridlist sys.ODCIRidList,
    60      newvallist your_type,
    61      env sys.ODCIEnv)
    62  RETURN NUMBER IS
    63  BEGIN
    64    dbms_output.put_line ('batch');
    65    return ODCIConst.Success;
    66  END;
    67
    68  STATIC FUNCTION ODCIIndexDelete(
    69      ia SYS.ODCIIndexInfo,
    70      rid VARCHAR2,
    71      oldval number,
    72      env SYS.ODCIEnv)
    73  RETURN NUMBER IS
    74  BEGIN
    75    return ODCIConst.Success;
    76  END;
    77
    78  STATIC FUNCTION ODCIIndexUpdate(
    79      ia SYS.ODCIIndexInfo,
    80      rid VARCHAR2,
    81      oldval number,
    82      newval number,
    83      env SYS.ODCIEnv)
    84  RETURN NUMBER AS
    85  BEGIN
    86    return ODCIConst.Success;
    87  END;
    88
    89  STATIC FUNCTION ODCIIndexStart(
    90    sctx IN OUT index_methods,
    91    ia SYS.ODCIIndexInfo,
    92    op SYS.ODCIPredInfo,
    93    qi sys.ODCIQueryInfo,
    94    strt number,
    95    stop number,
    96    cmpval  number,
    97    env SYS.ODCIEnv)
    98  RETURN NUMBER AS
    99  BEGIN
    100    sctx := index_methods(1);
    101    return ODCIConst.Success;
    102  END;
    103
    104  MEMBER FUNCTION ODCIIndexFetch(
    105    self IN OUT index_methods,
    106    nrows NUMBER,
    107    rids OUT SYS.ODCIridlist,
    108    env SYS.ODCIEnv)
    109  RETURN NUMBER AS
    110  BEGIN
    111    return ODCIConst.Success;
    112  END;
    113
    114  MEMBER FUNCTION ODCIIndexClose(self IN index_methods, env SYS.ODCIEnv) RETURN NUMBER AS
    115  BEGIN
    116    return ODCIConst.Success;
    117  END;
    118  end;
    119  /
    Type body created.
    SCOTT@orcl12c> CREATE FUNCTION test_eq_fun(a number, b number) RETURN NUMBER AS
      2  BEGIN
      3    IF a = b then
      4       RETURN 1;
      5    ELSE
      6       RETURN 0;
      7    END IF;
      8  END;
      9  /
    Function created.
    SCOTT@orcl12c> CREATE OPERATOR test_eq
      2  BINDING (number, number) RETURN NUMBER
      3  USING test_eq_fun
      4  /
    Operator created.
    SCOTT@orcl12c> CREATE INDEXTYPE test_index_type
      2  FOR
      3  test_eq(number, number)
      4  USING index_methods
      5  WITH ARRAY DML(number, your_type)
      6  WITH LOCAL RANGE PARTITION
      7  WITH SYSTEM MANAGED STORAGE TABLES
      8  /
    Indextype created.
    SCOTT@orcl12c> CREATE TABLE test_table (id NUMBER (19,0))
      2  /
    Table created.
    SCOTT@orcl12c> CREATE INDEX test_index ON test_table(id) INDEXTYPE IS test_index_type
      2  /
    Index created.
    SCOTT@orcl12c> insert into test_table values (1)
      2  /
    single
    1 row created.
    SCOTT@orcl12c> insert into test_table
      2  select 2 from dual union all
      3  select 3 from dual
      4  /
    batch
    2 rows created.
    SCOTT@orcl12c> insert into test_table select deptno from dept
      2  /
    batch
    4 rows created.
    SCOTT@orcl12c> insert into test_table select object_id from user_objects
      2  /
    batch
    34 rows created.
    SCOTT@orcl12c>

  • Oracle 8i array DML operations with LOB objects

    Hi all,
    I have a question about Oracle 8i array DML operations with LOB objects, both CLOB and BLOB. With the following statement in mind:
    INSERT INTO TABLEX (COL1, COL2) VALUES (:1, :2)
    where COL1 is a NUMBER and COL2 is a BLOB, I want to use OCIs array DML functionality to insert multiple records with a single statement execution. I have allocated an array of LOB locators, initialized them with OCIDescriptorAlloc(), and bound them to COL2 where mode is set to OCI_DATA_AT_EXEC and dty (IN) is set to SQLT_BLOB. It is after this where I am getting confused.
    To send the LOB data, I have tried using the user-defined callback method, registering the callback function via OCIBindDynamic(). I initialize icbfps arguments as I would if I were dealing with RAW/LONG RAW data. When execution passes from the callback function, I encounter a memory exception within an Oracle dll. Where dvoid **indpp equals 0 and the object is of type RAW/LONG RAW, the function works fine. Is this not a valid methodology for CLOB/BLOB objects?
    Next, I tried performing piecewise INSERTs using OCIStmtGetPieceInfo() and OCIStmtSetPieceInfo(). When using this method, I use OCILobWrite() along with a user-defined callback designed for LOBs to send LOB data to the database. Here everything works fine until I exit the user-defined LOB write callback function where an OCI_INVALID_HANDLE error is encountered. I understand that both OCILobWrite() and OCIStmtExecute() return OCI_NEED_DATA. And it does seem to me that the two statements work separately rather than in conjunction with each other. So I rather doubt this is the proper methodology.
    As you can see, the correct method has evaded me. I have looked through the OCI LOB samples, but have not found any code that helps answer my question. Oracles OCI documentation has not been of much help either. So if anyone could offer some insight I would greatly appreciate it.
    Chris Simms
    [email protected]
    null

    Before 9i, you will have to first insert empty locators using EMPTY_CLOB() inlined in the SQL and using RETURNING clause to return the locator. Then use OCILobWrite to write to the locators in a streamed fashion.
    From 9i, you can actually bind a long buffer to each lob position without first inserting an empty locator, retrieving it and then writing to it.
    <BLOCKQUOTE><font size="1" face="Verdana, Arial, Helvetica">quote:</font><HR>Originally posted by CSimms:
    Hi all,
    I have a question about Oracle 8i array DML operations with LOB objects, both CLOB and BLOB. With the following statement in mind:
    INSERT INTO TABLEX (COL1, COL2) VALUES (:1, :2)
    where COL1 is a NUMBER and COL2 is a BLOB, I want to use OCIs array DML functionality to insert multiple records with a single statement execution. I have allocated an array of LOB locators, initialized them with OCIDescriptorAlloc(), and bound them to COL2 where mode is set to OCI_DATA_AT_EXEC and dty (IN) is set to SQLT_BLOB. It is after this where I am getting confused.
    To send the LOB data, I have tried using the user-defined callback method, registering the callback function via OCIBindDynamic(). I initialize icbfps arguments as I would if I were dealing with RAW/LONG RAW data. When execution passes from the callback function, I encounter a memory exception within an Oracle dll. Where dvoid **indpp equals 0 and the object is of type RAW/LONG RAW, the function works fine. Is this not a valid methodology for CLOB/BLOB objects?
    Next, I tried performing piecewise INSERTs using OCIStmtGetPieceInfo() and OCIStmtSetPieceInfo(). When using this method, I use OCILobWrite() along with a user-defined callback designed for LOBs to send LOB data to the database. Here everything works fine until I exit the user-defined LOB write callback function where an OCI_INVALID_HANDLE error is encountered. I understand that both OCILobWrite() and OCIStmtExecute() return OCI_NEED_DATA. And it does seem to me that the two statements work separately rather than in conjunction with each other. So I rather doubt this is the proper methodology.
    As you can see, the correct method has evaded me. I have looked through the OCI LOB samples, but have not found any code that helps answer my question. Oracles OCI documentation has not been of much help either. So if anyone could offer some insight I would greatly appreciate it.
    Chris Simms
    [email protected]
    <HR></BLOCKQUOTE>
    null

  • ORA-24381: error(s) in array DML - Reasons

    Hi all,
    Do you know when we could recieve this exceptions?
    I found one case - if we deal with FORALL and sparse collection.
    Any other cases?
    Thanks
    PS: We are talking for Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bit
    :)

    Do you know when we could recieve this exceptions?e.g. all kind of constraint violations would raise this error:
    SQL> DECLARE
       TYPE emp_tab IS TABLE OF emp%ROWTYPE
          INDEX BY BINARY_INTEGER;
       e_tab   emp_tab;
    BEGIN
       e_tab (1).empno := 7900;
       FORALL i IN 1 .. 1 SAVE EXCEPTIONS
          INSERT INTO emp
               VALUES e_tab (i);
    EXCEPTION
       WHEN OTHERS
       THEN
          DBMS_OUTPUT.put_line (SQLERRM (SQLCODE));
    END;
    ORA-24381: error(s) in array DML
    ORA-00001: unique constraint (PK_EMP) violated

  • ORA-24381: error(s) in array DML

    Hi,
    I encountered error during mya testing. The script run thru several cases, until it encouter this error ORA-24381: error(s) in array DML.
    What could be the possible reason for this and can anyone give an idea to resolve this issue.
    Bulk collect was used with a limit of 1000.
    I used dblink to access database.
    Thanks in advance.

    The documentation tells you all about it: http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14261/tuning.htm#sthref2201
    Regards,
    Rob.

  • I am getting this "ORA-24381: error(s) in array DML error" in the code

    declare
    TYPE RehrCD_TYP IS TABLE OF wk_rehr_entity_hierarchy.wk_rehr_cd%TYPE;
    TYPE RehrParentCD_TYP IS TABLE OF wk_rehr_entity_hierarchy.wk_rehr_parent_cd%TYPE;
    TYPE RehrESSPath_TYP IS TABLE OF wk_rehr_entity_hierarchy.wk_rehr_ess_path%TYPE;
    L_levelRehrCD RehrCD_TYP;
    L_levelParentCD RehrParentCD_TYP;
    L_levelessPath RehrESSPath_TYP;
    L_cItem VARCHAR2(50) := 'PRC_Update_Level :';
    L_rows NUMBER DEFAULT 0;
    CURSOR Update_Level_CUR
         IS
    SELECT
    wk_rehr_cd
    ,wk_rehr_parent_cd
    ,wk_rehr_ess_path
    FROM
    wk_rehr_entity_hierarchy
    WHERE
    wk_rehr_ess_path LIKE '/ENTITY/ACTIVITY_USD%';
    BEGIN
    OPEN Update_Level_CUR;
    BEGIN
    LOOP
    FETCH Update_Level_CUR
    BULK COLLECT INTO
    L_levelRehrCD
    ,L_levelParentCD
    ,L_levelessPath
    LIMIT 10000;
    EXIT WHEN L_levelRehrCD.count = 0;
    dbms_output.put_line(1);
    FORALL i IN L_levelRehrCD.FIRST .. L_levelRehrCD.LAST SAVE EXCEPTIONS
    UPDATE
    wk_rehr_entity_hierarchy
    SET
    wk_rehr_ess_level = RPKG_Entity_Hierarchy.Get_Level(L_levelessPath(i))
    WHERE
    wk_rehr_cd = L_levelRehrCD(i)
    AND wk_rehr_parent_cd = L_levelParentCD(i);
    FOR j IN 1 .. L_levelRehrCD.COUNT
    LOOP
    L_rows := L_rows+ SQL%BULK_ROWCOUNT(j);
    END LOOP;
    END LOOP;
    CLOSE Update_Level_CUR;
    END;
    end;
    Please help me how to debug it?

    Just get rid of the whole looping approach - it's slow, inefficient and you don't need it.
    A single sql statement should always outperform looping code.
    Also, try to bring the logic of RPKG_Entity_Hierarchy.Get_Level inline to the SQL.
    If it's based on the column wk_rehr_ess_path then you might be able to use CONNECT BY or other methods to remove what is a bad practice and classic performance killer.
    I was going to suggest a MERGE statement like this:
    MERGE
    INTO  wk_rehr_entity_hierarchy wk
    USING (SELECT wk_rehr_cd
           ,      wk_rehr_parent_cd
           ,      RPKG_Entity_Hierarchy.Get_Level(wk_rehr_ess_path) lvl
           FROM   wk_rehr_entity_hierarchy
           WHERE  wk_rehr_ess_path LIKE '/ENTITY/ACTIVITY_USD%') xx
    ON    (wk.wk_rehr_cd        = xx.wk_rehr_cd
    AND    wk.wk_rehr_parent_cd = xx.wk_rehr_parent_cd)
    WHEN MATCHED THEN
           UPDATE
           SET    wk_rehr_ess_level = xx.lvl;But then I realised you're selecting from and updating the same table.
    Are you sure this isn't achievable in just a single update?
    UPDATE wk_rehr_entity_hierarchy
    SET    wk_rehr_ess_level = RPKG_Entity_Hierarchy.Get_Level(wk_rehr_ess_path)
    WHERE  wk_rehr_ess_path LIKE '/ENTITY/ACTIVITY_USD%';And then you can bring that function logic inline - much more efficient.

  • Associative array comparison and INSERT upon IF condition

    Hi Guys,
    I have written this pl sql code to identify non existing sellers and insert their sales channel information into the dimension table (dimensional table update).
    Somehow,......nothing is inserted and this script runs for 12 hours+ without any result. the sql autotrace shows no result and the explain plan (button on sql developer throws upon clicking "missing keyword". I have no
    information what is going on/wrong. Does anyone spot an error?
    UNDEFINE DimSales;
    UNDEFINE FactTable;
    DEFINE DimSales = 'testsales';
    DEFINE FactTable = 'testfact';
    DECLARE
    v_SellerNo VarChar(9);
    v_error_code T_ERRORS.v_error_code%TYPE;
    v_error_message T_ERRORS.v_error_message%TYPE;
    TYPE assoc_array_str_type1 IS TABLE OF VARCHAR2(32) INDEX BY PLS_INTEGER;
         v1 assoc_array_str_type1;
    TYPE assoc_array_str_type2 IS TABLE OF VARCHAR2(32) INDEX BY PLS_INTEGER;
         v2 assoc_array_str_type2;
    BEGIN
    --Collect all distinct SellerNo into associative array (hash table)
    select distinct SellerNo bulk collect into v1 from &FactTable;
    select distinct seller_id bulk collect into v2 from &DimSales;
    v_SellerNo := v1.first;
    loop
    exit when v1 is null;
    --1 Check if v_SellerNo already exists in DIM_Sales (if NOT/FALSE, its a new seller and we can insert all records for that seller
    if (v2.exists(v_SellerNo)=false) THEN
    INSERT INTO &DimSales (K_Sales,REG,BVL,DS, VS,RS,GS,VK)
    (SELECT DISTINCT trim(leading '0' from RS||GS) ,REG BVL,DS,VS,RS,GS,VK from &FactTable where SellerNo =v_SellerNo);
    --ELSE
    end if;
    v_SellerNo := v1.next(v_SellerNo);
    end loop;
    EXCEPTION
    WHEN OTHERS THEN
    ROLLBACK;
    --v_error_code := SQLCODE
    --v_error_message := SQLERRM
    --INSERT INTO t_errors VALUES ( v_error_code, v_error_message);
    END;
    ---------------------------------------------------------------

    Distinct clause requires a sort. Sorts can be very expensive.
    Bulk collects that are not constrained in fetch size, can potentially fetch millions of rows - requiring that data to be wholly read into server memory. I have seen how this can degrade performance so badly that the kernel reboots the server.
    Using PL/SQL loops to process and insert/update/delete data is often problematic due to its row-by-row approach - also called slow-by-slow approach. It is far more scalable letting SQL do the "loop" processing, by using joins, sub-selects and so on.
    Where the conditional processing is too complex for SQL to handle, then PL/SQL is obviously an alternative to use. Ideally one should process data sets as oppose to rows in PL//SQL. Reduce context switching by using bulk fetches and bulk binds.
    But PL/SQL cannot execute in parallel as the SQL it fires off can. If after all the optimisation, the PL/SQL process still needs to hit a million rows to process, it will be slow irrespective of how optimal that PL/SQL approach and design - simply because of the number of rows and the processing overheads per row.
    In that case, the PL/SQL code itself need to be parallelised. There are a number of ways to approach this problem - the typical one is to create unique and distinct ranges of rows to process, spawn multiple P/SQL processes, and provide each with a unique range of rows to process. In parallel.
    So you need to look close at what you are trying to achieve, what the workloads are, and how to effectively decrease the workloads and increase the processing time of a workload.
    For example - finding distinct column values. You can pay for that workload when wanting that distinct list. And each time afterward repeat that workload when wanting that distinct list. Or you can pay for that workload up-front with the DML that creates/updates those values - and use (for example) a materialised view to maintain a ready to use distinct list of values.
    Same workload in essence - but paying once for it and up-front as oppose to each time you execute your code that needs to dynamically build that distinct list.
    Kent Crotty did tests and showed stunning performance improvements with bulk collect and forall, up to 30x faster:Bulk processing is not a magical silver bullet. It is a tool. And when correctly use, the tool does exactly what it was designed to do.
    The problem is using a hammer to drive in screws - instead of a screwdriver. There's nothing "stunning" about using a screwdriver. It is all about using the correct tool.
    If the goal of the swap daemon is to free up "idle" chunks of memory, and try to use that memory for things like file cache instead, what does that have to do with bulk processing?The swap daemon reads virtual memory pages from swap space into memory, and writes virtual pages from memory to swap space.
    What does it have to do with bulk processing? A bulk fetch reads data from the SGA (buffer cache) into the PGA (private process memory space). The larget the fetch, the more memory is required. If for example 50% of server memory is required for a bulk collection that is 2GB in size, then that will force in-use pages from memory to swap space.. only to be swapped back again as it is needed, thereby forcing other in-use pages to swap. The swap daemon will consume almost all the CPU time swapping hot pages continually in and out of memory.

  • A Bug in 11.1 array interface

    I have just encounter some code that runs fine in Oracle 9 to 10 but in 11.1 I am getting a different result.
    basically I have this SQL
    "INSERT INTO $table ( row_1, row_2, row_3) VALUES (?,?,?)"
    and bind all three to this array
    @var2 = (2,2,2,2,'s',2,2,2,2,2);
    using OCIBindByName and OCIBindDynamic and then execute them with
    OCIStmtExecute, with a mode (IN)
    of OCI_BATCH_ERRORS OCI_COMMIT_ON_SUCCESS (or 160)
    what happens is the commit does not happen in 11 but does happen in 9~10?
    Did something change in the execute in 11 or should I raise this up to a bug status??

    Ok here is a trace of the OCI Calls I use, and yes I the last one I give is a OCITransCommit
    st_execute_array INSERT count=10 (ARRAY(0x1a725c8) ARRAY(0x1a934c4) undef)
    OCIBindByName(876dad8,19cab00,8755e68,":p1",3,0,1,1,0,0,0,0,0,DATA_AT_EXEC)=SUCCESS
    OCIBindDynamic(876eda8,8755e68,19caadc, phs_in,19caadc,phs_out)=SUCCESS
    OCIBindByName(876dad8,1a27810,8755e68,":p2",3,0,1,1,0,0,0,0,0,DATA_AT_EXEC)=SUCCESS
    OCIBindDynamic(876ec68,8755e68,1a277ec,phs_in,1a277ec,phs_out)=SUCCESS
    OCIBindByName(876dad8,1a2bc18,8755e68,":p3",3,0,1,1,0,0,0,0,0,DATA_AT_EXEC)=SUCCESS
    OCIBindDynamic(876eb28,8755e68,1a2bbf4,phs_in,1a2bbf4,phs_out)=SUCCESS
    OCIStmtExecute(8755db0,876dad8,8755e68,10,0,0,0,160)=SUCCESS_WITH_INFO ->(OCI_BATCH_ERRORS|OCI_COMMIT_ON_SUCCESS)<--
    OCIAttrGet(876dad8,OCI_HTYPE_STMT,140f4ec,0,129,8755e68)=SUCCESS
    OCIErrorGet(8755e68,1,"<NULL>",140f48c,"ORA-24381: error(s) in array DML",1024,2)=SUCCESS
    OCIErrorGet(8755e68,2,"<NULL>",140f48c,"ORA-24381: error(s) in array DML",1024,2)=NO_DATA
    OCIAttrGet(876dad8,OCI_HTYPE_STMT,140f55c,0,73,8755e68)=SUCCESS
    st_execute_array 1 errors in batch.
    OCIHandleAlloc(8727940,140f578,OCI_HTYPE_ERROR,0,0)=SUCCESS
    OCIHandleAlloc(8727940,140f570,OCI_HTYPE_ERROR,0,0)=SUCCESS
    OCIParamGet(8755e68,2,876c3c0,140f578,0)=SUCCESS
    OCIAttrGet(876c968,OCI_HTYPE_ERROR,140f550,0,74,8755e68)=SUCCESS
    st_execute_array error in row 4.
    OCIErrorGet(876c968,1,"<NULL>",140f4cc,"ORA-01722: invalid number",1024,2)=SUCCESS
         OCIErrorGet(876c968,2,"<NULL>",140f4cc,"ORA-01722: invalid number",1024,2)=NO_DATA
    OCIHandleFree(876c3c0,OCI_HTYPE_ERROR)=SUCCESS
    OCIHandleFree(876c968,OCI_HTYPE_ERROR)=SUCCESS
    OCITransCommit(8755db0,8755e68,0)=SUCCESS
    st_execute_array warning: ORA-24381: error(s) in array DML (SUCCESS_WITH_
    INFO: error possibly near <*> indicator at char 56 in 'INSERT INTO test_ea( row_1, row_2,
    row_3) VALUES (:p1,:<*>p2,:p3)') [for Statement "INSERT INTO test_ea( row_1,  row_2, row_
    3) VALUES (?,?,?)"]
    and here is the code snipits but it is take out of a larger program so I will not run
    sb4
    phs_in(dvoid octxp, OCIBind bindp, ub4 iter, ub4 index,
         dvoid **bufpp, ub4 alenp, ub1 piecep, dvoid **indpp)
         phs_t phs = (phs_t)octxp;
    STRLEN phs_len;
    AV *tuples_av;
         SV *sv;
         AV *av;
         SV **sv_p;
         /* Check for bind values supplied by tuple array. */
         tuples_av = phs->imp_sth->bind_tuples;
         if(tuples_av) {
              /* NOTE: we already checked the validity in ora_st_bind_for_array_exec(). */
              sv_p = av_fetch(tuples_av, phs->imp_sth->rowwise ? (int)iter : phs->idx, 0);
              av = (AV*)SvRV(*sv_p);
              sv_p = av_fetch(av, phs->imp_sth->rowwise ? phs->idx : (int)iter, 0);
              sv = *sv_p;
              if(SvOK(sv)) {
              *bufpp = SvPV(sv, phs_len);
              phs->alen = (phs->alen_incnull) ? phs_len+1 : phs_len;
              phs->indp = 0;
              } else {
              *bufpp = SvPVX(sv);
              phs->alen = 0;
              phs->indp = -1;
    *alenp  = phs->alen;
    *indpp  = &phs->indp;
    *piecep = OCI_ONE_PIECE;
    if (!tuples_av && (index > 0 || iter > 0))
              croak(" Arrays and multiple iterations not currently supported (in %d/%d)", index,iter);
    return OCI_CONTINUE;
    sb4
    phs_out(dvoid octxp, OCIBind bindp,
         ub4 iter,     /* execution itteration (0...)     */
         ub4 index,     /* array index (0..)          */
         dvoid **bufpp,     /* A pointer to a buffer to write the bind value/piece.     */
         ub4 **alenpp,     /* A pointer to a storage for OCI to fill in the size     */
                   /* of the bind value/piece after it has been read.     */
         ub1 piecep,     / */
         dvoid **indpp,     /* Return a pointer to contain the indicator value which either an sb2     */
                   /* value or a pointer to an indicator structure for named data types.     */
         ub2 **rcodepp)     /* Returns a pointer to contains the return code.     */
    phs_t phs = (phs_t)octxp;     /* context */
    if (phs->desc_h) { /* a  descriptor if present  (LOBs etc)*/
              *bufpp  = phs->desc_h;
              phs->alen = 0;
    } else {
              SV *sv = phs->sv;
              if (SvTYPE(sv) == SVt_RV && SvTYPE(SvRV(sv)) == SVt_PVAV) {
              sv = av_fetch((AV)SvRV(sv), (IV)iter, 1);
              if (!SvOK(sv))
                        sv_setpv(sv,"");
              bufpp = SvGROW(sv, (size_t)(((phs->maxlen < 28) ? 28 : phs->maxlen)+1)/for null*/);
              phs->alen = SvLEN(sv);     /* max buffer size now, actual data len later */
    *alenpp = &phs->alen;
    *indpp  = &phs->indp;
    *rcodepp= &phs->arcode;
    *piecep = OCI_ONE_PIECE;
    return OCI_CONTINUE;
    static int
    do_bind_array_exec(sth, imp_sth, phs)
    SV *sth;
    imp_sth_t *imp_sth;
    phs_t *phs;
         dTHX;
    sword status;
    OCIBindByName_log(imp_sth->stmhp, &phs->bndhp, imp_sth->errhp,
    (text*)phs->name, (sb4)strlen(phs->name),
    0,
    phs->maxlen ? (sb4)phs->maxlen : 1, /* else bind "" fails */
    (ub2)phs->ftype, 0,
    NULL, /* ub2 alen_ptr not needed with OCIBindDynamic /
    0,
    0, /* max elements that can fit in allocated array */
    NULL, /* (ptr to) current number of elements in array */
    (ub4)OCI_DATA_AT_EXEC,
    status);
    if (status != OCI_SUCCESS) {
    oci_error(sth, imp_sth->errhp, status, "OCIBindByName");
    return 0;
    OCIBindDynamic_log(phs->bndhp, imp_sth->errhp,
    (dvoid *)phs, phs_in,
    (dvoid *)phs, phs_out, status);
    if (status != OCI_SUCCESS) {
    oci_error(sth, imp_sth->errhp, status, "OCIBindDynamic");
    return 0;
    return 1;
    static void
    init_bind_for_array_exec(phs)
    phs_t *phs;
         dTHX;
    if (phs->sv == &sv_undef) { /* first bind for this placeholder  */
    phs->is_inout = 0;
    phs->maxlen = 1;
    /* treat Oracle7 SQLT_CUR as SQLT_RSET for Oracle8 */
    if (phs->ftype==102)
    phs->ftype = 116;
    /* some types require the trailing null included in the length. */
    /* SQLT_STR=5=STRING, SQLT_AVC=97=VARCHAR */
    phs->alen_incnull = (phs->ftype==SQLT_STR || phs->ftype==SQLT_AVC);
    int
    st_execute_array(sth, imp_sth, tuples, tuples_status, columns, exe_count)
    SV *sth;
    imp_sth_t *imp_sth;
    SV *tuples;
    SV *tuples_status;
    SV *columns;
    ub4 exe_count;
         sword status, exe_status;
    int is_select = (imp_sth->stmt_type == OCI_STMT_SELECT);
    AV tuples_av, tuples_status_av, *columns_av;
    ub4 oci_mode;
    ub4 num_errs;
    int i,j;
    int autocommit = 1;
    SV **sv_p;
         phs_t **phs;
         SV *sv;
         AV *av;
    int param_count;
    char namebuf[30];
    STRLEN len;
    int outparams = (imp_sth->out_params_av) ? AvFILL(imp_sth->out_params_av)+1 : 0;
    tuples_av = (AV*)SvRV(tuples);
    /* Check the `columns' parameter. */
    if(SvTRUE(columns)) {
    if(!SvROK(columns) || SvTYPE(SvRV(columns)) != SVt_PVAV) {
    croak("ora_st_execute_array(): columns not an array peference.");
    columns_av = (AV*)SvRV(columns);
    } else {
    columns_av = NULL;
    /* Check the `tuples_status' parameter. */
    if(SvTRUE(tuples_status)) {
    if(!SvROK(tuples_status) || SvTYPE(SvRV(tuples_status)) != SVt_PVAV) {
         croak("ora_st_execute_array(): tuples_status not an array reference.");
    tuples_status_av = (AV*)SvRV(tuples_status);
    av_fill(tuples_status_av, exe_count - 1);
    /* Fill in 'unknown' exe count in every element (know not how to get
    individual execute row counts from OCI). */
    for(i = 0; (unsigned int) i < exe_count; i++) {
    av_store(tuples_status_av, i, newSViv((IV)-1));
    } else {
    tuples_status_av = NULL;
    /* Nothing to do if no tuples. */
    if(exe_count <= 0)
    return 0;
    param_count=c_NUM_PARAMS(imp_sth);/*returns the # of parameters on the imp_sth struct*/
         phs = safemalloc(param_count*sizeof(*phs));
    memset(phs, 0, param_count*sizeof(*phs));
         for(j = 0; (unsigned int) j < exe_count; j++) {
         sv_p = av_fetch(tuples_av, j, 0);
    if(sv_p == NULL) {
    Safefree(phs);
    croak("Cannot fetch tuple %d", j);
    sv = *sv_p;
    if(!SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVAV) {
    Safefree(phs);
    croak("Not an array ref in element %d", j);
    av = (AV*)SvRV(sv);
    for(i = 0; i < param_count; i++) {
    if(!phs) {
    SV **phs_svp;
    sprintf(namebuf, ":p%d", i+1);
    phs_svp = hv_fetch(imp_sth->all_params_hv,
    namebuf, strlen(namebuf), 0);
    if (phs_svp == NULL) {
    Safefree(phs);
    croak("Can't execute for non-existent placeholder :%d", i);
    phs[i] = (phs_t*)(void*)SvPVX(*phs_svp); /* placeholder struct */
    if(phs[i]->idx < 0) {
    Safefree(phs);
    croak("Placeholder %d not of ?/:1 type", i);
    init_bind_for_array_exec(phs[i]); /*bind the value */
    sv_p = av_fetch(av, phs[i]->idx, 0);
    if(sv_p == NULL) {
    Safefree(phs);
    croak("Cannot fetch value for param %d in entry %d", i, j);
                   sv = *sv_p;
         /*check to see if value sv is a null (undef) if it is upgrade it*/
                   if (!SvOK(sv))     {
                        if(SvUPGRADE(sv, SVt_PV)){} /* For GCC not to warn on unused result */
                   else {
              SvPV(sv, len);
         /* Find the value length, and increase maxlen if needed. */
         if(SvROK(sv)) {
         Safefree(phs);
         croak("Can't bind a reference (%s) for param %d, entry %d",
         neatsvpv(sv,0), i, j);
         if(len > (unsigned int) phs[i]->maxlen)
         phs[i]->maxlen = len;
         /* Do OCI bind calls on last iteration. */
         if( ((unsigned int) j ) == exe_count - 1 ) {
         if(!do_bind_array_exec(sth, imp_sth, phs[i])) {
         Safefree(phs);
         Safefree(phs);
    /* Store array of bind typles, for use in OCIBindDynamic() callback. */
    imp_sth->bind_tuples = tuples_av;
    imp_sth->rowwise = (columns_av == NULL);
    oci_mode = OCI_BATCH_ERRORS;
    if(autocommit)
    oci_mode |= OCI_COMMIT_ON_SUCCESS;
         OCIStmtExecute_log(imp_sth->svchp, imp_sth->stmhp, imp_sth->errhp,
    exe_count, 0, 0, 0, oci_mode, exe_status);
         imp_sth->bind_tuples = NULL;
    if (exe_status != OCI_SUCCESS) {
              oci_error(sth, imp_sth->errhp, exe_status, ora_sql_error(imp_sth,"OCIStmtExecute"));
    if(exe_status != OCI_SUCCESS_WITH_INFO)
    return -2;
    OCIAttrGet_log(imp_sth, &num_errs, 0, OCI_ATTR_NUM_DML_ERRORS, status);
    if(num_errs && tuples_status_av) {
    OCIError row_errhp, tmp_errhp;
    ub4 row_off;
    SV *err_svs[2];
    /*AV err_av;/
    sb4 err_code;
    err_svs[0] = newSViv((IV)0);
    err_svs[1] = newSVpvn("", 0);
    OCIHandleAlloc_log(imp_sth->envhp, &row_errhp, OCI_HTYPE_ERROR, status);
    OCIHandleAlloc_log(imp_sth->envhp, &tmp_errhp, OCI_HTYPE_ERROR, status);
    for(i = 0; (unsigned int) i < num_errs; i++) {
    OCIParamGet_log(imp_sth->errhp, OCI_HTYPE_ERROR,
    tmp_errhp, (dvoid *)&row_errhp,
    (ub4)i, status);
    OCIAttrGet_log(row_errhp, OCI_HTYPE_ERROR, &row_off, 0,
    OCI_ATTR_DML_ROW_OFFSET, imp_sth->errhp, status);
    sv_setpv(err_svs[1], "");
    err_code = oci_error_get(row_errhp, exe_status, NULL, err_svs[1], debug);
    sv_setiv(err_svs[0], (IV)err_code);
    av_store(tuples_status_av, row_off,
    newRV_noinc((SV *)(av_make(2, err_svs))));
    OCIHandleFree_log(tmp_errhp, OCI_HTYPE_ERROR, status);
    OCIHandleFree_log(row_errhp, OCI_HTYPE_ERROR, status);
    /* Do a commit here if autocommit is set, since Oracle
    doesn't do that for us when some rows are in error. */
    if(autocommit) {
    OCITransCommit_log(imp_sth->svchp, imp_sth->errhp,
    OCI_DEFAULT, status);
    if (status != OCI_SUCCESS) {
    oci_error(sth, imp_sth->errhp, status, "OCITransCommit");
    return -2;
    if(num_errs) {
    return -2;
    } else {
    ub4 row_count = 0;
              OCIAttrGet_stmhp_log(imp_sth, &row_count, 0, OCI_ATTR_ROW_COUNT, status);
    return row_count;

  • BULKING and FORALL statement does not pass values to non DML statements.

    Hi
    I've got million rows that i need to manapulate and insert into various procedures depending on the bussiness rule to be applied, but my dilemma is that the BULIKNG with a combination of a FORALL statement its not compatible(only considers straightforward DML calls) or the the FORALL does not like other SQL statements or calls as it prefers only DML's.
    Below is code fragment that is problamatic as the compiler keeps sending me this error: PLS-00201: identifier 'INDX' must be declared
    I want to manupulate data on the implicity cursor and call a procedure to do other stuff which don't use INSERT/DELETE or UPDATE statements.
    Declare
    TYPE tab_person_id is of table of number(15);
    l_person_id tab_person_id;
    BEGIN
    SELECT person_id
    BULK COLLECT INTO l_person_id
    FROM person_details; /*-Million records-*/
    FORALL indx IN l_tdtl.FIRST..l_tdtl.LAST
    pj_pkg.ins_intf
    (p_user => p_user,
    p_typ_cd => '00',
    p_person_id => l_person(indx)
    Commit;
    END;
    How do I pass this value 'l_person(indx)' on the package procudure ?
    Thanks
    Amos

    @prabodh:
    SQL> declare
      2  TYPE tab_person_id is of table of number(15) index by pls_integer;
      3  begin
      4  null;
      5  end;
      6  /
    TYPE tab_person_id is of table of number(15) index by pls_integer;
    ERROR at line 2:
    ORA-06550: line 2, column 23:
    PLS-00103: Encountered the symbol "OF" when expecting one of the following:
    ( array limited new private range record VARRAY_ char_base
    number_base decimal date_base clob_base blob_base bfile_base
    table ref object fixed varying opaque sparse
    The symbol "OF" was ignored.Check What you are posting.
    @ qwestion: What is your Database Version? It is a implementation restriction.

  • Best parameters setting for DML & DDL?

    hi,
    i am implementing the DDL & DML replication using OGG. i just wanted to know what should the best parameters for extract, data pump(source) & Replicate process(Target).
    while my source and target having same structure.
    & i have to replicate 277 tables.
    thanks.
    Regards,
    AMSII
    Edited by: AMSI on Apr 8, 2013 8:12 PM

    To improve the bulk DML operation via goldengate replication:
    Using BATCHSQL
    In default mode the Replicat process will apply SQL to the target database, one statement at a time. This often causes a performance bottleneck where the Replicat process cannot apply the changes quickly enough, compared to the rate at which the Extract process delivers the data. Despite configuring additional Replicat processes, performance may still be a problem.
    Configuration Options
    GoldenGate has addressed this issue through the use of the BATCHSQL Replicat configuration parameter. As the name implies, BATCHSQL organizes similar SQLs into batches and applies them all at once. The batches are assembled into arrays in a memory queue on the target database server, ready to be applied.
    Similar SQL statements would be those that perform a specific operation type (insert, update, or delete) against the same target table, having the same column list. For example, multiple inserts into table A would be in a different batch from inserts into table B, as would updates on table A or B. Furthermore, referential constraints are considered by GoldenGate where dependant transactions in different batches are executed first, depicting the order in which batches are executed. Despite the referential integrity constraints, BATCHSQL can increase Replicat performance significantly.
    BATCHSQL BATCHESPERQUEUE 100, OPSPERBATCH 2000
    Regards
    Rajabaskar

Maybe you are looking for

  • I purchased my IPad in June and it keeps losing the GPS signal why is this?

    I purchased my IPad 3 in June and it keeps losing its GPS signal why is this please?  I have not been able to use the NavFree or SatVav applications or search google whilst travelling

  • When is the new ios 7 going to be available

    does anyone know when the ios 7 is going to be available

  • Safari Displays Unexpected Date Value

    I want to use the following script in my company website www.todoroffs.com, in order to always display the current year value within my copyright notice at the bottom of the pages: <script>      var today=new Date()      var todayy=today.getYear()   

  • Ios 5.1 update for iphone

    Yet another issue with ios 5.1 update!! My iMessage in now not working!! Arrgh. I got it going temporarily yesterday but lost it again this morning. I am in a wireless zone and I have re-booted the phone and gone into settings and switched imessage o

  • Help! Broken nano 3g!

    My nano 3g is broken. It won't turn on, charge, and the computor wont recognize it. I think it's discharged too long. If it's discharged, how long do u charge it?