Oracle Call Interface Template Library 1.0.5 (OTL), Pro*OTL / Pre-Pro*C preprocessor 1.0.0 (PPC)

Sergei Kuchin, email: skuchin@ispwest.com, skuchin@gmail.comgmail

Copyright (C) Sergei Kuchin, 1996, 1997,1998 Permission to use, copy, modify and redistribute this document for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies.

Table of Contents

protected: };

Class otl_variable

This is the OTL template variable class. It is the base class for constructing specialized host variable classes.

template <class T, int atype> class otl_variable: public otl_generic_variable{ public: };

Class otl_array

This is the OTL template host array class. It is the base class for constructing specialized template array classes.

template <class T, int atype, short size> class otl_array: public otl_generic_variable{ public: };

3.1.1. Specialized host variable classes

3.1.2. Specialized host array classes

3.2. Oracle Call Interface "wrapper"

Class otl_exception

This is the OTL exception class. Exceptions of this type are raised by the library functions (default mode), unless it is prohibited explicitly in the otl_connect or otl_cursor class constructors. In case of disabled exceptions OTL functions return codes and it is the user's responsibility to check out the codes and handle errors. The main advantage of using this exception handling mechanism is that exceptions can be processed in one catch block, instead of checking return codes from every library function call.

class otl_exception{ public: };

Class otl_object

This class is a parent of the otl_cursor and otl_connect classes. Its children inherit the following two properties:

class otl_object{ public: protected: };

Class otl_connect

This class encapsulates the Oracle Call Interface functions which have Logon Descriptor Area as their first parameter. In other words, otl_connect is the class for creating "connect" objects.

class otl_connect: public otl_object{ public: };

Class otl_column_desc

This class is data structure which contains a select item (column) descriptive information. The information may be obtained by the otl_cursor::describe_column function call (see the otl_cursor class). class otl_column_desc{ public: };

Class otl_cursor

This class is a general-purpose cursor class.

class otl_cursor: public otl_object{ public: };

Class otl_select_cursor

This class is a cursor class, specialized for SELECT statements. class otl_select_cursor : public otl_cursor{ public: };

Class otl_dynamic_variable

This class is used in the otl_select_stream class to dynamically allocate a list of output columns of SELECT statement and any other automatically created bind variables (e.g. in a SQL stream).

class otl_dynamic_variable: public otl_generic_variable{ public: };

Class otl_err_info

This is the OTL error info class. It is intended for using in case of manual error handling. The class allows to get more detailed error information about the current Oracle error. class otl_err_info: public otl_exception{ public: };

3.3. OTL stream interface

In OTL, SQL streams are introduced. The idea here is to combine streams and SQL. Such a combination provides new quality and simplicity in programming interface to SQL. The Oracle Array Interface naturally transforms into buffered stream operations.

The SQL streams are intended for SQL or PL/SQL statements which have input and/or output bind variables. Any statement can be treated as a functional element with input/output parameters. There are functions to put objects into a stream, that is, to assign values to input variables. Also, there are functions to get objects from the stream, that is, to get values from output variables.

+--> I1 I2 ... In | | | | | V V V | +------------------+ +--| SQL statement or | | PL/SQL block | +-+-----+------+---+ | | | V V V O1 O2 ... Ok

When values of all input variables of the functional element are filled out then the element is executed. Resulting values are assigned to the output variables right after the execution. Sets of input and output variables are allowed to overlap (see the picture).

Logically, a SQL stream is a structured stream with input and output rows. The format of the input row is defined by a set of output variables of the stream. Similarly, the output row is defined by input variables of the stream. When objects are written into the stream, values are actually assigned to the input variables. Likewise, when objects are read from the stream, values are read from the output variables of the stream.

SQL streams are similar to buffered files. A SQL statement or PL/SQL block is opened as an ordinary buffered file. The logic of the SQL stream operations remains the same as the file operations with the only exception -- the SQL stream has separate input and output buffers which may overlap.

The SQL stream in C++ has a flush function for flushing its input buffer when the buffer gets full and a collection of >> and << operators for reading and writing objects of different data types. The most important advantage of the SQL streams is their unified interface to SQL statements and PL/ SQL blocks of any kind. This mean that application developers need to remember just a few syntactical constructs and function names which they already got familiar with when they started working with C++ streams.

Inside the SQL stream there is a small parser for parsing declarations of bind variables and their data types. There is no need to declare C/C++ host variables and bind them with placeholders by special bind function calls. All necessary buffers are created dynamically inside the stream. The stream just needs to be opened for reading input values and writing output values.

The OTL stream interface requires use of the OTL exceptions. This means that potentially any OTL stream operation can throw an exception of the otl_exception type. In order intercept the exception and prevent the program from aborting, wrap up the OTL stream code with the corresponding try & catch block.

For more detail on the stream class hierarchy, see Appendix A.

Class otl_select_stream

This is the OTL select stream class. The user does not need to manually attach output columns to SELECT statement because the statement is automatically parsed and the output columns are allocated in the class constructor.

This class may issue the following otl_exceptions:

class otl_select_stream: public otl_select_cursor{ public:
};

Class otl_out_stream

This is the OTL output class. This class is used for the following SQL statements:

This class may issue the following otl_exceptions:

class otl_out_stream: public otl_cursor{ public:
};

Class otl_inout_stream

This is the OTL input/output stream class. It is used primarily for PL/SQL blocks with input and output parameters. Though, this stream class can be used for SQL statements and PL/SQL blocks with input or output parameters only.

This class may issue the following otl_exceptions:

class otl_inout_stream: public otl_out_stream{ public:
};

Class otl_stream

This is the OTL stream class. It is a general-purpose and most advanced stream class, unified for streams of all types. This class may issue the following otl_exceptions:

class otl_stream{ public:
};

Stream bind variable declarations

This section explains in detail how to declare bind variables (or extended place-holders) in the SQL streams.

A SQL statement or PL/SQL block may have placeholders which are usually connected with the corresponding bind variables in the program. In Pro*C the user needs to declare such variables directly in the program. OTL provides the same functionality in another way. There is a small parser which parses a SQL statament or PL/SQL block declaration and allocates corresponding bind variables dynamically inside the stream.

The following data types for extneded place-holder declarations are available:

For PL/SQL blocks, special qualifiers are introduced to distinguish between input and output variables:

  • in -- input variable
  • out -- output variable
  • inout -- input/output variable

    Examples

    Here is a number of examples:

    begin :rc<int,out> := my_func( :salary<float,in>, :ID<int,inout>, :name<char[32],out> ); end;

    Invoke the my_func function; return the function result into the :rc variable; the function has three parameters: salary (input), ID (iput/output), name (output)

    select * from tab1 where f1 > :f1<double>

    Select all columns from the tab1 table where f1 is greater than :f1

    insert into tab1 values( :f1<double>, :f2<char[32]>, :f3<int> )

    Insert row { :f1(double), :f2(string), :f3(integer) } into the tab1 table.

    3.4. Prosto*C

    The name Prosto*C is originated in the author's native language -- "prosto" means "simple". Prosto*C is supposed to provide a simplified set of procedures for interfacing with SQL or PL/SQL. In Prosto*C, the mechanism of handling errors is slightly different from the otl_exception mechanism. Each connect object is supplied with the error handler -- a procedure, which is invoked each time when an error occurs (see also 2.1.11.).

    Prosto*C provides a set of functions which is very similar to the C "stdio" interface: scanf(), printf(), etc.

    Here is the list of Prosto*C functions:


    4. Pro*OTL / Pre-Pro*C preprocessor (PPC)

    PPC is a preprocessor which reads a directive file on input and can generate both Pro*C and OTL code on output. When the preprocessor starts up, it connects to the database, parses directives and then generates the output code. The output code consists of a Pro*C file, a C++ file with OTL function calls and a header file with the prototypes of the functions, generated by PPC.

    The directives fall into three main categories:


    4.1. Getting started with PPC

    Let's consider similar examples as described in Chapter 2: examples 8 and 9. In the "scott/tiger" user, create the following table, using SQLPlus:

    create table test_tab(f1 number, f2 varchar2(30));

    Let's assume that the example comprises of two modules: main and auxiliary. The main module has the main function which connects to the database and call functions from the auxiliary module. Source code of the auxiliary module is generated by the PPC preprocessor from the directive file. The directive file is unified for both Pro*C and C++, but the output for Pro*C and C++ is different (see examples below). The interface functions are the same and can be used both in Pro*C and C++.

    Here is the source code of the directive file (ppc_test.ppc):

    /* ppc_test.ppc - directive file; ppc_test.h - generated header file with interface functions and data structures; ppc_test.C - generated C++ module with OTL function calls; ppc_test.pc - generated Pro*C module; */ #include <ppc_test.h> /* generated header file */ /* PPC standard prolog for an auxiliary (not main) module */ #sql-init-module #sql-str-type <CSTR,1> /* type equivalence directive */ /* SELECT statement directive. "Sel" is the directive label. 50 is the internal host arrays size. */ #sql-select <Sel,50> SELECT * FROM TEST_TAB WHERE F1>=:F<int> AND F1<=:F*2 ORDER BY F1 ## /* ## is a directive terminator */ /* "Output" statement directive. "Ins" is the directive label. 50 is the internal host arrays size. */ #sql-out-stm <Ins,50> INSERT INTO TEST_TAB ( F1, F2 ) VALUES ( :F1<float>, :F2<char[31]> ) ## /* "Arbitrary PL/SQL block" directive. "PL" is the directive label. 1 is a dummy parameter which does not matter in the current release of PPC. Put 1 for compatibility with the future versions. :A is IN/OUT parameter; :B is OUT parameter; :C is IN parameter; */ #sql-plsql <PL,1> BEGIN :A<int,inout> := :A+1; :B<char[31],out> := :C<char[31],in>; END; ## #ifdef __cplusplus /* Function for C++. In the main C++ module, the user needs to call this function, in order to pass over a pointer to the actual database connect object into the C++ module, generated by PPC. This function can be eliminated if only Pro*C is used. */ void assign_db(otl_connect* adb) { db=adb; // db is a static (in the module) pointer // to the database connect object } /* Function for C++. In the main C++ module, the user needs to call this function just before disconnecting from the database, in order to close the static "hot" cursor in this file. This function can be eliminated if only Pro*C is used. */ void close_hotcur(void) { hotcur.close(); // close static hot cursor } #endif Here is the header file (ppc_test.h), generated from the directive file by PPC: #ifndef __PPC_TEST_H #define __PPC_TEST_H #ifdef __cplusplus extern "C"{ #endif /* C-structure, corresponding to the "Sel" statement. The SELECT list has been automatically extracted from the database dictionary and the structure generated. The structure is a container for one output row of the "Sel" statement. */ struct struct_Sel{ double F1; /* F1 number */ short F1_IND; /* F1's indicator */ char F2[31]; /* F2 varchar2(30) */ short F2_IND;/* F2's indicator */ }; typedef struct struct_Sel Sel; /* typedef declaration */ void Sel_open( int F /* F is the integer input host variable :F */ ); /* Open the "Sel" statement */ void Sel_close(void); /* Close the "Sel" statement */ int Sel_get(Sel* out); /* Get one row and put it into the "Sel" structure */ void Ins_open(int auto_commit); /* Open the "Ins" statement. "auto_commit" is the auto-commit flag. If the flag is set then: - commit transaction right after the internal host arrays get full and the "Ins" statement is executed; - commit transaction right after the "Ins" statement is closed; */ void Ins_put( float F1, /* input float host variable :F1 */ char* F2 /* input char[31] host variable :f2 */ ); /* Put one row into the "Ins" statement's internal buffer. The statement is automatically executed when the buffer gets full. */ void Ins_flush(void); /* "Flush" internal buffer, no matter how full it is. This means that the "Ins" statement executes as many times as rows the buffer contains. If the "auto_commit" flag was set, then the current transaction commits. */ void Ins_close(void); /* Close the "Ins" statement: call the Ins_flush() function, then deallocate all internal resources and quit. */ void PL_exec( int* A, /* IN/OUT integer parameter :A */ char* B,/* OUT char[31] parameter :B */ char* C /* IN char[31] parameter :C ); /* Execute the "PL" PL/SQL block */ #ifdef __cplusplus } #endif #endif

    For more information on this example, see Appendix F.

    Example in Pro*C

    In this section, source code of the Pro*C main module (ppc_main.pc) is given. It needs to be preprocessed by Pro*C, compiled by C and linked with the ppc_test.pc module (see the above example).

    Source code
    #include <ppc_test.h> #include <stdio.h> EXEC SQL INCLUDE SQLCA; typedef char CSTR[80]; EXEC SQL BEGIN DECLARE SECTION; EXEC SQL TYPE CSTR IS STRING(80); CSTR UserId; EXEC SQL END DECLARE SECTION; /* Define error handler */ void sqlerror(void) { EXEC SQL WHENEVER SQLERROR CONTINUE; fprintf(stderr,"\n%s\n",sqlca.sqlerrm.sqlerrmc); EXEC SQL ROLLBACK RELEASE; exit(1); } EXEC SQL WHENEVER SQLERROR DO sqlerror(); void Insert() /* insert rows into table */ {int i; Ins_open(1); /* open "Ins" statement with "auto_commit" flag set */ for(i=0;i<100;++i){ char F2[32]; sprintf(F2,"Name%d",i); Ins_put(i,F2); /* write one row into the database */ } Ins_close(); /* close statement */ } /* insert */ void Select() /* select rows from table */ { Sel p; /* one row containter */ Sel_open(8); /* open "Sel" statement with the :F input parameter = 8 */ /* fetch rows from the table */ while(!Sel_get(&p)){ /* not end-of-data */ printf("f1=%g, f2=%s\n",p.F1,p.F2); } Sel_close(); /* close the statement */ /* re-open "Sel" statement with :F = 4 */ Sel_open(4); /* fetch rows from the table */ while(!Sel_get(&p)){ /* not end-of-data */ printf("f1=%g, f2=%s\n",p.F1,p.F2); } Sel_close(); /* close the statement */ } /* select */ void plsql() /* execute the "PL" PL/SQL block */ { int a; char b[31]; char c[31]; /* assigning :A = 1, :C = "Test String1" */ a=1; strcpy(c,"Test String1"); PL_exec(&a,b,c); /* execute the block */ printf("A=%d, B=%s\n",a,b); /* print out results */ /* assigning :A = 2, :C = "Test String2" */ a=2; strcpy(c,"Test String2"); PL_exec(&a,b,c); /* execute the block */ printf("A=%d, B=%s\n",a,b); /* print out results */ /* assigning :A = 3, :C = "Test String3" */ a=3; strcpy(c,"Test String3"); PL_exec(&a,b,c); /* execute the block */ printf("A=%d, B=%s\n",a,b); /* print out results */ } /* plsql */ int main() { strcpy(UserId,"scott/tiger"); EXEC SQL CONNECT :UserId; /* connect to Oracle as scott/tiger */ EXEC SQL TRUNCATE TABLE TEST_TAB; /* truncate table */ Insert(); /* insert rows */ Select(); /* select rows */ plsql(); /* execute PL/SQL block */ EXEC SQL COMMIT WORK; /* disconnect from Oracle */ } /* main */
    Output
    f1=8, f2=Name8 f1=9, f2=Name9 f1=10, f2=Name10 f1=11, f2=Name11 f1=12, f2=Name12 f1=13, f2=Name13 f1=14, f2=Name14 f1=15, f2=Name15 f1=16, f2=Name16 f1=4, f2=Name4 f1=5, f2=Name5 f1=6, f2=Name6 f1=7, f2=Name7 f1=8, f2=Name8 A=1, B=Test String1 A=2, B=Test String2 A=3, B=Test String3

    Example in C++

    In this section, source code of the C++ main module (ppc_main.C) is given. It needs to be compiled by C++ and linked with the ppc_test.C module (see the above example).

    Source code
    #include <ppc_test.h> #include <stdio.h> #include <iostream.h> #include <otl.h> otl_connect db; // connect object void Insert() // insert rows into table { Ins_open(1); // open "Ins" statement with "auto_commit" flag set for(int i=0;i<100;++i){ char F2[32]; sprintf(F2,"Name%d",i); Ins_put(i,F2); // write one row into the database } Ins_close(); // close statement } /* insert */ void Select() // select rows from table { Sel p; // one row container Sel_open(8); // open "Sel" statement with the :F input parameter = 8 // fetch rows from the table while(!Sel_get(&p)){ // not end-of-data printf("f1=%g, f2=%s\n",p.F1,p.F2); } Sel_close(); // close the statement Sel_open(4); // re-open the statement with :F = 4 // fetch rows from the table while(!Sel_get(&p)){ // not end-of-data printf("f1=%g, f2=%s\n",p.F1,p.F2); } Sel_close(); // close the statement } /* select */ void plsql() // execute the "PL" PL/SQL block { int a; char b[31]; char c[31]; // assigning :A = 1, :C = "Test String1" a=1; strcpy(c,"Test String1"); PL_exec(&a,b,c); // execute the block printf("A=%d, B=%s\n",a,b); // print out results // assigning :A = 2, :C = "Test String2" a=2; strcpy(c,"Test String2"); PL_exec(&a,b,c); // execute the block printf("A=%d, B=%s\n",a,b); // print out results // assigning :A = 3, :C = "Test String3" a=3; strcpy(c,"Test String3"); PL_exec(&a,b,c); // execute the block printf("A=%d, B=%s\n",a,b); // print out results } /* plsql */ // define prototypes of the assign_db and close_hotcur functions // from the ppc_test.C module. extern "C" void assign_db(otl_connect* db); extern "C" void close_hotcur(void); int main() { try{ db.rlogon("scott/tiger"); // connect to Oracle as scott/tiger assign_db(&db); // initialize internal pointer to the actual connect // object in the ppc_test.C module otl_cursor::direct_exec(db,"truncate table test_tab"); // truncate table Insert(); // insert rows Select(); // select rows plsql(); // execute PL/SQL block }catch(otl_exception& p){ // intercept OTL exceptions cout<<p.msg<<endl; // print out error message } close_hotcur(); // close the hot cursor from ppc_test.C db.logoff(); // disconnect from Oracle return 0; } /* main */
    Output
    f1=8, f2=Name8 f1=9, f2=Name9 f1=10, f2=Name10 f1=11, f2=Name11 f1=12, f2=Name12 f1=13, f2=Name13 f1=14, f2=Name14 f1=15, f2=Name15 f1=16, f2=Name16 f1=4, f2=Name4 f1=5, f2=Name5 f1=6, f2=Name6 f1=7, f2=Name7 f1=8, f2=Name8 A=1, B=Test String1 A=2, B=Test String2 A=3, B=Test String3
    Notes

    It is possible to encapsulate all database functionality in separate Pro*C and PPC modules and use the modules without using OTL. The user can define Pro*C connect and disconnect functions separately in a Pro*C file, together with the other "handmade" Pro*C procedures. Additionally, a few directive files can be defined to automatically generate Pro*C code. Then, all this stuff can be "objectified" (encapsulated) in C++ classes and the classes can be used in the C++ main module.

    The user needs to keep in mind the technique of invoking plain C functions from C++.

    4.2. Directives

    PPC source code files consist of directives which may be mixed with real code in plain C, C++ or Pro*C (non-directive code is not processed and remains intact). The directive starts with # at the beginning of line. Some directives have names, arguments and special terminators, the other -- do not. By format, the directives are similar to the C preprocessor commands. Inside the directive body, extended place-holder declarations are allowed.

    4.2.1. #sql-select

    This is the "SELECT" directive. On output, it generates a set of functions to select rows according to the given SELECT statement. The directive format is as follows:

    #sql-select <Label,BufSize> end-of-line ... <SELECT Statement> ... ## end-of-line

    <Label>

    Statement label

    <BufSize>

    Defines the size of internal host arrays, attached to the SELECT statment

    <SELECT Statement>

    SELECT statement body. Can be multi-line.

    ##

    SELECT statement terminator. Starts at the beginning of line


    Example

    #sql-select <Sel,50> SELECT * FROM TEST_TAB WHERE F1>=:F<int> AND F1<=:F*2 ORDER BY F1 ##

    Generated code

    struct struct_<Label>{ ... <SELECT list items> ... }; /* One output row container */ typedef struct struct_<Label> <Label>; void <Label>_open( /* open statement */ ... <Input variable list> .. ); void <Label>_close(void); /* close statement */ int <Label>_get(<Label>* out); /* get one rows from the fetch sequence */

    For more detail, see Appendix F and "Getting Started with PPC".

    4.2.2. #sql-out-stm

    This is the "output" directive. It is called "output" similar to the OTL streams. A stream is called output, when the user can write objects into the stream. This directive is used for:

    On the output, the directive generates a set of functions to write rows to the database, according to the given SQL statement or PL/SQL block. The directive format is as follows:

    #sql-out-stm <Label,BufSize> end-of-line ... <SQL Statement or PL/SQL block with input parameters only> ... ##

    <Label>

    Statement label

    <BufSize>

    Defines the size of internal host arrays, attached to the statment

    <SQL Statement or PL/SQL block with input parameters only>

    Statement body. Can be multi-line.

    ##

    Statement terminator. Starts at the beginning of line


    Example

    #sql-out-stm <Ins,50> INSERT INTO TEST_TAB ( F1, F2 ) VALUES ( :F1<float>, :F2<char[31]> ) ##

    Generated code

    void <Label>_open(int auto_commit); /* open statement */ void <Label>_put( /* write one row */ ... <Parameter list> ... ); void <Label>_flush(void); /* "flush" internal buffer */ void <Label>_close(void); /* close statement */

    For more detail, see Appendix F and "Getting Started with PPC".

    4.2.3. #sql-plsql

    This is the "arbitrary PL/SQL block" directive. On the output, the directive generates the "exec" function to execute the PL/SQL block, given in the directive. The directive format is as follows:

    #sql-plsql <Label,BufSize> end-of-line ... <PL/SQL block> ... ## end-of-line

    <Label>

    Statement label

    <BufSize>

    Defines the size of internal host arrays, attached to the statment. In the current release of PPC should be always 1.

    <PL/SQL block>

    Statement body. Can be multi-line.

    ##

    Statement terminator. Starts at the beginning of line


    Example

    #sql-plsql <PL,1> BEGIN :A<int,inout> := :A+1; :B<char[31],out> := :C<char[31],in>; END; ##

    Generated code

    void <Label>_exec( /* execute PL/SQL block */ ... <Parameter list> ... );

    For more detail, see Appendix F and "Getting Started with PPC".

    4.2.4. #sql-init-module

    This is the "module's standard prolog" directive. On output, the directive generates a piece of code, typical for non-main modules.

    #sql-init-module end-of-line

    Example

    #sql-init-module

    Generated code

    For more detail, see Appendix F and "Getting Started with PPC".

    4.2.5. #sql-init-main

    This is the "main module's standard prolog" directive. On output, the directive generates a piece of code, typical for main modules.

    #sql-init-main end-of-line

    Example

    #sql-init-main

    Generated code

    For more detail, see Appendix F and "Getting Started with PPC".

    4.2.6. #sql-str-type

    This is the "string type equivalence" directive. It has effect only in Pro*C. The directive format is as follows:

    #sql-str-type <StringType,Flag> end-of-line

    <StringType>

    C-string type, defined as a typedef. PPC uses the "StringType" identifier in generating Pro*C internal string variables.

    <Flag>

    if <flag>==1 then the string type equivalence is enforced. if <flag>==0 then the string type equivalence is off.


    Example

    typedef char C_STR[256]; ... #sql-str-type <C_STR,1> ...

    Generated code

    None.

    4.3. Command line parameters

    All command line parameter are positional. Parameters inside [] are optional. The format of PPC command line is as follows:

    ppc <connect_string> <input_file> <proc-file> <h-file> <#define> [<macro-def-file> [<OTL-module>]]

    1. connect_string

    Database connect sting

    2. input_file

    Input PPC directive file

    3. proc-file

    Output Pro*C file

    4. h-file

    Output interface header file (contains PPC-generated external function prototypes and data structures

    5. #define

    #define for the interface header file

    6. macro-def-file

    File, containing macro definitions to be used with the OTL streams (see the file for more detail)

    7. OTL-module

    Output C++ module which contains OTL function calls


    Examples

    ppc scott/tiger sample.ppc sample.pc sample.h __SAMPLE_H ppc scott/tiger sample.ppc sample.pc sample.h __SAMPLE_H dummy.h sample.C

    5. Acknowledgements

    Vladimir Shipunov and Igor Galichin (Siberian Trade Bank, Novosibirsk, Russia) have discussed with me some ideas how to implement basic classes.

    Peter Muth, Hannelore Eisner, Achim Kraiss and other members of the VODAK team in GMD IPSI (Darmstadt, Germany) have given me good knowledge on Object Oriented Databases and I do not regret about the time I spent with them. The knowledge was very useful in the development of the OTL.

    Especially, I would like to thank Prof.Dr. Erich Neuhold who granted me a visiting researcher position in GMD IPSI.

    Sergei Trapeznikov's and my hard work on numerous Oracle projects at Siemens / Empros inspired me to develop PPC. I wish Sergei Trapeznikov all the best in his career at SDT.

    Many thanks to my wife Irina for her patience and understanding that this work is important to me.

    6. Bibliography

    Appendix A. OTL class hierarchy

    otl_object | +------>otl_connect | +------>otl_cursor | +------>otl_select_cursor | | | +------>otl_select_stream | | | otl_stream +------>otl_out_stream | +------>otl_inout_stream otl_generic_variable | +-->otl_dynamic_variable | +-->otl_variable | | | +--->otl_cstring | otl_varchar2 | otl_long | otl_varchar | otl_varraw | otl_raw | otl_long_raw | otl_char | otl_charz | otl_long_varchar | otl_long_varraw | +->otl_array | +---->otl_date_array otl_rowid_array otl_varnum_array otl_number_array otl_double_array otl_float_array otl_signed_char_array otl_short_int_array otl_int_array otl_long_int_array otl_unsigned_array otl_cstring_array otl_varchar2_array otl_long_array otl_varchar_array otl_varraw_array otl_raw_array otl_long_raw_array otl_char_array otl_charz_array otl_exception | +---->otl_err_info

    Appendix B. Error message list

    A few error codes are defined by OTL. It is necessary because a runtime error can occur during debugging of a program. All the error codes defined can be issued only from member functions of the stream classes. Error reporting and handling is implemented via the normal mechanism of the OTL exceptions.

    The user can catch an exception raised not by an Oracle error but by one of the << or >> operators of the stream classes.

    Code=32000: Incompatible data types in stream operation

    Cause: The data type of a variable used in the current stream operation is not compatible with the declared stream format.

    Action: Check placeholders and their data types declaration.

    Code=32001: Row must be full for flushing output stream

    Cause: Stream is open for output and has a format of output rows. An output row is a tuple of all output variables put together. The current output row is not filled yet but the flush function is invoked. The stream buffer cannot be flushed until the current row of the output buffer is full.

    Action: Fill the row first, then flush the stream.

    Code=32004: Not all input variables have been initialized

    Cause: stream has input variables but not all the variables have been initialized. An attempt to read data from the stream was made.

    Action: Assign all the input variables first.

    Code=32004: No input variables have been defined in SQL statement

    Cause: Stream has no input variables. An attempt to write objects to the stream via one of the << operators was made.

    Action: Do not call the << operators for streams which have no input variables defined.

    Appendix C. OTL source code (otl.h)

    // // The OCI Template Library 1.0.6.5 // Copyright (C) Sergei Kuchin, 1996, 1997, 1998 // Author: Sergei Kuchin // This library is free software. Permission to use, copy, // modify and redistribute it for any purpose is hereby granted // without fee, provided that the above copyright notice appear // in all copies. // #ifndef __OTL_H #define __OTL_H // Functions are defined as INLINE. Those, who don't like inline // functions and prefer to have a separate C++ module with the // functions, can define INLINE as empty string and split up otl.h // into two files: otl.h and otl.C (otl.cpp). #define INLINE inline #define OTL_DEBUG_ // OTL uses the ociapr.h file (OCI standard header file, recommended // for ANSI C compilers). In Unix, OCI header files reside in the // $ORACLE_HOME/rdbms/demo directory. extern "C"{ #include <ociapr.h> } #ifdef OTL_DEBUG #include <iostream.h> #endif #include <string.h> #include <ctype.h> #include <stdarg.h> // Oracle internal data types (see Programmer's Guide to the // Oracle Call Interface, chapter 3) // enum otl_internal_type{ const int inVarChar2=1; const int inNumber=2; const int inLong=8; const int inRowId=11; const int inDate=12; const int inRaw=23; const int inLongRaw=24; const int inChar=96; const int inMslabel=106; //}; // Oracle external data types (see Programmer's Guide to the // Oracle Call Interface, chapter 3) //enum otl_external_type{ const int extVarChar2=inVarChar2; const int extNumber=inNumber; const int extInt=3; const int extFloat=4; const int extCChar=5; const int extVarNum=6; const int extLong=inLong; const int extVarChar=9; const int extRowId=inRowId; const int extDate=inDate; const int extVarRaw=15; const int extRaw=inRaw; const int extLongRaw=inLongRaw; const int extUInt=68; const int extLongVarChar=94; const int extLongVarRaw=95; const int extChar=inChar; const int extCharZ=97; const int extMslabel=inMslabel; //}; // Container data types for some of Oracle external data types defined // in Programmer's Guide to the Oracle Call Interface, chapter 3: typedef ub1 otl_date_intern[7]; // date Oracle internal format typedef ub1 otl_rowid_intern[14]; // rowid in Oracle internal format typedef char otl_cchar_rowid[19]; // rowid in text format typedef ub1 otl_varnum_intern[22]; // varnum in internal format typedef ub1 otl_number_intern[21]; // number in Oracle 21-byte binary // format // Error codes and messages, used in an exception raised in the // otl_select_stream class and otl_out_stream_class const int otl_error_code_0=32000; #define otl_error_msg_0 "Incompatible data types in stream operation" const int otl_error_code_1=32004; #define otl_error_msg_1 "No input variables have been defined in SQL statement" const int otl_error_code_2=32004; #define otl_error_msg_2 "Not all input variables have been initialized" const int otl_error_code_3=32001; #define otl_error_msg_3 "Row must be full for flushing output stream" // OTL "Blocked Call" class. It is used for "non-blocking" Oracle // connections. The otl_blocked_call exception is raised when the // current call of an OCI function is blocked. class otl_blocked_call{ public: otl_blocked_call(){}; ~otl_blocked_call(){}; }; const int otl_blocked=3123; // Return code, indicating that the most // recent Oracle call has been blocked const int otl_blocking=3128; // Return code, indicating that the // current Oracle connection is still blocking const int otl_nonblocking=1; // Return code, indicating that the // current connection is nonblocking // OTL exception class. Exceptions of this type are raised by the // library functions (default mode), unless it is prohibited // explicitly in the otl_connect or otl_cursor class constructors // (see below). In case of disabled exceptions OTL functions // return codes and it the user's responsibility to check out the // codes and handle errors. The main advantage of using this // exception handling mechanism is that exceptions can be // processed in one catch block, instead of checking return codes // from every library function call. class otl_exception{ public: // This "enum" defines two constants which are used in // constructors of the otl_connect, otl_cursor and // otl_select_cursor classes. enum{ disabled, enabled }; unsigned char msg[1000]; // error message buffer unsigned char* stm_text;// sql that caused the error int code; // error code // Create exception from LDA otl_exception(Lda_Def& lda,const char* sqlstm=0) {if(lda.rc==otl_blocked)throw otl_blocked_call(); init(lda,sqlstm); } // Create exception from amsg and acode otl_exception(const char* amsg,const int acode,const char* sqlstm=0) {if(acode==otl_blocked)throw otl_blocked_call(); init(amsg,acode,sqlstm); } // Copy constructor otl_exception(const otl_exception& p) {init((char*)p.msg,p.code,(const char*)p.stm_text);} // Default constructor otl_exception(){stm_text=0;} // Destructor ~otl_exception(){delete[] stm_text;stm_text=0;} // Init-function void init(const char* amsg,const int acode,const char* sqlstm) {stm_text=0; code=acode; if(sqlstm) { stm_text=new unsigned char[strlen(sqlstm)+1]; strcpy((char*)stm_text,sqlstm); } } // Init-function void init(const otl_exception& p) {init((const char*)p.msg,p.code,(const char*)p.stm_text);} protected: INLINE void init(Lda_Def& lda,const char* sqlstm=0); // get error code and message }; // Parent for otl_cursor and otl_connect classes class otl_object{ public: int connected; // "connected" flag // Default constructor INLINE otl_object(); // Destructor virtual ~otl_object(){}; protected: int ex_enabled; // "exception enabled" flag }; class otl_out_stream; // Connect class. Object of this class are used for connecting to // Oracle. class otl_connect: public otl_object{ public: Lda_Def lda; // Logon Descriptor Area (see OCI doc. for more // details) ub2& rc; // reference to "V7 return code" // Create "connect" object INLINE otl_connect(int exception_enabled=otl_exception::enabled); // exceptions are allowed to raise by default // Create "connect" object and connect to Oracle using the // "connect_str" connect string; by default, exceptions are // allowed to raise INLINE otl_connect(const char* connect_str, int exception_enabled=otl_exception::enabled ); // Destructor INLINE ~otl_connect(); // Concurrent logon; OCI application is allowed to have more than one // concurrent logon. Returns 1 on success, 0 on failure. INLINE int rlogon(const char* connect_str // Connect string ); // Test if connection is in blocking mode. Returns "otl_blocking" if // connection is blocking, "otl_nonblocking" if connection is // non-blocking and 0 on failure. INLINE int test_blocking(void); // Set nonblocking connection mode. Returns 1 on success, 0 on // failure. INLINE int set_nonblocking(void); // Clear nonblocking connection mode. In other words, set blocking // connection mode. INLINE int clear_nonblocking(void); // Get valid LDA from Pro*C. Returns 1 on success, 0 on failure. INLINE int sqllda(void); // Get valid LDA from X/Open. Returns 1 on success, 0 on failure. INLINE int sqlld2(const char* dbname); // Exclusive logon. there may be only one logon of this type performed // in OCI application (for more details see OCI doc.). Returns 1 on // success, 0 on failure. INLINE int logon(const char* connect_str); // Disconnect from / log off Oracle. Returns 1 on success, 0 on // failure. INLINE int logoff(void); // Commit current transaction. Returns 1 on success, 0 on failure. INLINE int commit(void); // Roll back current transaction. Returns 1 on success, 0 on failure. INLINE int rollback(void); // Break current OCI call. Returns 1 on success, 0 on failure. INLINE int obreak(void); // Set auto commit mode on. Returns 1 on success, 0 on failure. INLINE int auto_commit_on(void); // Set auto commit mode off. Returns 1 on success, 0 on failure. INLINE int auto_commit_off(void); // Thread safe initialization. Returns 1 on success, 0 on failure. // This function needs to be called only once at the very beginning of // the program. This function works in Oracle 7.3 only. INLINE static int thread_safe_init(void); protected: unsigned char hda[512]; // private logon area int proc_connect; // connected via Pro*C EXEC SQL CONNECT...; friend otl_out_stream; public: void* handler; // reserved for use in Prosto*C }; // Select list item (column) descriptor class otl_column_desc{ public: sb1 name[241]; // field name sb4 nlen; // field name length sb4 dbsize; // field size as the field is presented inside ORACLE sb2 dbtype; // internal datatype code sb2 scale; // numeric field scale: NUMBER(scale,precision) sb2 prec; // numeric field precision sb4 dsize; // maximum display size of the field sb2 nullok; // NULLs are allowed }; class otl_cursor; class otl_ref_cursor; class otl_select_stream; class otl_ref_select_stream; class otl_out_stream; class otl_inout_stream; // OTL generic variable -- parent of the otl_variable, otl_array // template classes and otl_dynamic_variable. This class is needed in // order to pass over internal info about actual host variables and // arrays, instantiated from the templates. class otl_generic_variable{ public: // Default constructor INLINE otl_generic_variable(); // Destructor INLINE virtual ~otl_generic_variable(); // Assigning a name to the variable INLINE void copy_name(const char* aname); // Assigning a position (number) to the select list item (column) INLINE void copy_pos(const int apos); // For more detail on indicator, returned length and returned code // arrays see Programmer's Guide to the Oracle Call Interface // For input variable/array: INLINE virtual void set_null(int ndx=0); // Set variable's value as NULL INLINE virtual void set_len(int len, int ndx=0); // Set variable's buffer length INLINE virtual void set_not_null(int ndx=0); // Set variable's value as NOT NULL // For output variable/array: INLINE virtual int is_null(int ndx=0); // Check if variable's value is NULL INLINE virtual int is_success(int ndx=0); // Check if variable's value has been fetched OK. INLINE virtual int is_truncated(int ndx=0); // Check if variable's value is truncated INLINE virtual void* val(int ndx=0); // Get pointer to variable's buffer // Only for output arrays, defined in select statement: INLINE virtual int is_invalid_conversion(int ndx=0); // Check if during fetch conversion error occurred INLINE virtual int is_real_overflow(int ndx=0); // Check if during fetch real overflow occurred INLINE virtual int is_unsupported_datatype(int ndx=0); // Check if variable has unsupported data type // Used only for PLSQL tables: set/get PLSQL table size INLINE virtual void set_tab_len(int new_len); INLINE virtual int get_tab_len(void); protected: friend otl_cursor; friend otl_ref_cursor; friend otl_select_stream; friend otl_ref_select_stream; friend otl_out_stream; friend otl_inout_stream; ub1* p_v; // pointer to buffer sb2* p_ind; // pointer to indicator variable/array ub2* p_rlen; // pointer to column's returned length ub2* p_rcode; // poinetr column's returned code int ftype; // external data type's code of the host variable/array int elem_size; // array element/variable size int array_size; // host array size (=1 in case of scalar host variable) char* name; // variable name; int pos; // select list item position // Used only for PLSQL tables ub4 max_tab_len; // maximum length (of PLSQL table) ub4 cur_tab_len; // current length (of PLSQL table) }; // pointer to otl_generic_variable typedef otl_generic_variable* otl_p_generic_variable; // OTL dynamic variable/array class. Used in otl_select_stream to // automatically allocate default select list items based on the // information from the describe_column function. class otl_dynamic_variable: public otl_generic_variable{ public: // Dynamically construct a select list item (column) INLINE otl_dynamic_variable( const int column_num, // column number/position in select // list const int Aftype, // external data type of the column const int Aelem_size, // host array element/variable size const short Aarray_size=1 // array size ); // Dynamically construct host variable/array INLINE otl_dynamic_variable( const char *aname, // varable/array name const int Aftype, // external data type const int Aelem_size, // variable/array element size const short Aarray_size=1 // array size ); // Default constructor INLINE otl_dynamic_variable(); // Destructor INLINE ~otl_dynamic_variable(); // Allocate memory and initialize variable/array INLINE void init(const int Aftype, // external data types const int Aelem_size, // array element/variable size const short Aarray_size // array size ); // return dynamic variable's external data type INLINE int get_ftype(void); // return dynamic variable's elem_size INLINE int get_elem_size(void); }; // OTL (general-purpose) cursor class class otl_cursor: public otl_object{ public: Cda_Def cda; // Cursor Descriptor Area // convenient references to some of the CDA fields ub4& rpc; // reference to "rows processed count" ub2& ft; // reference to "OCI function code" ub2& rc; // reference to "V7 return code" ub2& peo; // reference to "parse error offset" char* stm_text; // SQL Statement Text // Create "cursor" object. by default, exceptions are allowed to // raise. INLINE otl_cursor(int exception_enabled=otl_exception::enabled); // Create "cursor" object and open cursor via "connect" INLINE otl_cursor(otl_connect& connect, // reference to "connect" object int exception_enabled=otl_exception::enabled ); // Close cursor (if opened) and destruct object INLINE ~otl_cursor(); // Open cursor via "connect". Returns 1 on success, 0 on failure INLINE int open(otl_connect& connect); // Close cursor. Returns 1 on success, 0 on failure INLINE virtual int close(void); // Cancel a query after desired number of rows have been // fetched. Returns 1 on success, 0 on failure INLINE int cancel(void); // Set rollback options for non-fatal Oracle errors. For more info see // the OCI manual, the "oopt" function. Returns 1 on success, 0 on // failure INLINE int option(int rbopt, int waitopt); // Fetch a portion of a LONG or LONG RAW column. For more info see the // OCI manual, the "oflng" function. Returns 1 on success, 0 on failure INLINE int fetch_long(int column_num, // column number: 1,2,... void* buf, // pointer to buffer sb4 bufl, // buffer size int dtype, // buffer data type, see ext* "enum" ub4* retl, // returned length sb4 offset // offset ); // Parse sql statement. Returns 1 on success, 0 on failure INLINE int parse(const char* sqlstm); // Extended Parse function -- eparse: // Parse sql statement; // bind variable and select list items; // variable list needs to be terminated with 0 pointer; // Returns 1 on success, 0 on failure. // if variable list contains variables which are SELECT statement's // output columns and if the variables don't have "column_num" // defined, then the parse function enumerates the variables as follows: // // eparse("select...",&f1,&f2,&f3,0); // f1 -- column 1 // f2 -- column 2 // f3 -- column 3 // INLINE int eparse(const char* sqlstm,...); // Execute statement iters times. Returns 1 on success, 0 on failure INLINE int exec(short iters=1); // Combined operation: Parse+Bind+Execute (Extended Exec function) // Parse sqlstm; // Bind variables; // Execute statement iters times. // Returns 1 on success, 0 on failure INLINE int eexec(const char* sqlstm, // SQL statement short iters, // number of iterations ... // NULL terminated list of pointers to bind variables ); // Fetch iters number of rows. Returns 1 on success, 0 on failure INLINE int fetch(short iters=1); // Combined operation -- execute statement + fetch iters number of // rows. Returns 1 on success, 0 on failure INLINE int exfet(short iters=1); // --------------- Functions to bind placeholders ------------------ // Bind host variable/array (instantiated template) to // placeholder. Returns 1 on success, 0 on failure INLINE virtual int bind(const char* name, // placeholder name: ":F1", ":F2" otl_generic_variable& v // reference to host variable/array ); // Bind host array (instantiated template) with placeholder as PLSQL // table. Returns 1 on success, 0 on failure INLINE virtual int bind_tab(const char* name, // placeholder name: ":F1", ":F2" otl_generic_variable& v // reference to host array ); // Bind "ordinary" host variable/array to placeholder. Returns 1 on // success, 0 on failure INLINE int bind(const char* name, // placeholder name: ":f1", ":f2" void* buf, // pointer to host variable/array int elem_size, //array element/ variable size in bytes int ftype, // Oracle external data type code sb2* indp=0 // pointer to indicator variable/array ); // Bind template host variable/array with already defined // name. Returns 1 on success, 0 on failure INLINE virtual int bind(otl_generic_variable& v); // Bind template host array with already defined name of placeholder // as PLSQL table. Returns 1 on success, 0 on failure. INLINE virtual int bind_tab(otl_generic_variable& v); // ------------ Functions to bind select items (columns) ----------------- // Bind host variable/array (instantiated template) to column. Returns // 1 on success, 0 on failure INLINE virtual int bind(int column_num, // column number: 1,2,... otl_generic_variable& v // reference to variable/array ); // bind "ordinary" host variable/array to column. Returns 1 on // success, 0 on failure INLINE int bind(int column_num, // column number: 1,2,... void* buf, // pointer to host variable/array int elem_size, // array element/variable size in bytes int ftype, // Oracle external data type code sb2* indp=0, // pointer to indicator array/varibale ub2* rlen=0, // pointer to returned length array/variable ub2* rcode=0 // pointer to returned code array variable ); // ------------- Specialized bind functions ------------------ // Functions to bind "ordinary" host variables/arrays of different // data types. // ------------- Specialized function to bind columns ------------- // Bind C-style (null terminated) string variable/array to // column. Returns 1 on success, 0 on failure INLINE int bind_cstring(int column_num, // column number: 1,2,... char* buf, // pointer to C-string variable/array int elem_size, // array element/variable size sb2* indp=0, // pointer to indicator array/variable ub2* rlen=0, // pointer to returned length array/variable ub2* rcode=0 // pointer to returned code array/variable ); // Bind int variable/array to column. Returns 1 on success, 0 on // failure INLINE int bind_int(int column_num, // column number: 1,2,... int* buf, // pointer to int variable/array sb2* indp=0, // pointer to indicator array/variable ub2* rlen=0, // pointer to returned length array/variable ub2* rcode=0 // pointer to returned code array/variable ); // Bind short int variable/array to column. Returns 1 on success, 0 on // failure INLINE int bind_short(int column_num,// column number: 1,2,... short* buf, // pointer to short int variable/array sb2* indp=0, // pointer to indicator array/variable ub2* rlen=0, // pointer to returned length array/variable ub2* rcode=0 // pointer to returned code array/variable ); // Bind long int variable/array to column. Returns 1 on success, 0 on // failure INLINE int bind_long_int(int column_num, // column number: 1,2,... long* buf, // pointer to long int variable/array sb2* indp=0, // pointer to indicator array/variable ub2* rlen=0, // pointer to returned length array/variable ub2* rcode=0 // pointer to returned code array/variable ); // Bind float variable/array to column. Returns 1 on success, 0 on // failure INLINE int bind_float(int column_num,// column number: 1,2,... float* buf, // pointer to float variable/array sb2* indp=0, // pointer to indicator array/variable ub2* rlen=0, // pointer to returned length array/variable ub2* rcode=0 // pointer to returned code array/variable ); // Bind double variable/array to column. Returns 1 on success, 0 on // failure INLINE int bind_double(int column_num,// column number: 1,2,... double* buf, // pointer to double variable/array sb2* indp=0, // pointer to indicator array/variable ub2* rlen=0, // pointer to returned length array/variable ub2* rcode=0 // pointer to returned code array/variable ); // ----------- Specialized function to bind placeholders ------------- // Bind C-style (null terminated) string variable/array to // column. Returns 1 on success, 0 on failure INLINE int bind_cstring(const char* name, // placeholder name: ":F1", ":F2" char* buf, // pointer to C-string variable/array int elem_size, // array element/variable size sb2* indp=0 // pointer to indicator array/variable ); // Bind int variable/array to placeholder. Returns 1 on success, 0 on // failure INLINE int bind_int(const char* name, // placeholder name: ":F1", ":F2" int* buf, // pointer to int variable/array sb2* indp=0 // pointer to indicator array/variable ); // Bind short int variable/array to placeholder. Returns 1 on success, // 0 on failure INLINE int bind_short(const char* name, // placeholder name: ":F1", ":F2" short* buf, // pointer to short int variable/array sb2* indp=0 // pointer to indicator array/variable ); // Bind long int variable/array to placeholder. Returns 1 on success, // 0 on failure INLINE int bind_long_int(const char* name, // placeholder name: ":F1", ":F2" long* buf, // pointer to long int variable/array sb2* indp=0 // pointer to indicator array/variable ); // Bind float variable/array to placeholder. Returns 1 on success, 0 // on failure INLINE int bind_float(const char* name, // placeholder name: ":F1", ":F2" float* buf, // pointer to float variable/array sb2* indp=0 // pointer to indicator array/variable ); // Bind double variable/array to placeholder. Returns 1 on success, 0 // on failure INLINE int bind_double(const char* name, // placeholder name: ":F1", ":F2" double* buf, // pointer to double variable/array sb2* indp=0 // pointer to indicator array/variable ); // -------------- End of Specialized bind functions --------------- // Static (in class) function to immediately execute a constant SQL // statement. Returns 1 on success, 0 on failure INLINE static int direct_exec(otl_connect& db, // connect object const char* stm, // statement int exception_enabled=otl_exception::enabled // exception_enabled flag ); // Check "end-of-file" condition when fetching rows from select // statement. Returns 1 when "EOF", 0 otherwise INLINE int eof(void); // describe select item (column) INLINE virtual int describe_column( otl_column_desc& col_desc, // column descriptor structure int column_num // column number: 1,2,... ); // "End-of-description" condition check INLINE int end_of_desc(void); // Parse statement and bind variables INLINE int parse(const char* sqlstm, // SQL statement otl_generic_variable** v // pointer to variable list ); protected: // Internal stuff int vl_len; // variable list length otl_p_generic_variable* vl; // variable list otl_connect* adb; // pointer to connect object INLINE void alloc_var(otl_p_generic_variable* vp); // Parse sql statement. Returns 1 on success, 0 on failure INLINE int parse(void); }; // Specialized cursor -- OTL select cursor class class otl_select_cursor: public otl_cursor{ public: int cur_row; // index of current row in host array int cur_size; // number of rows in the buffer after most recent fetch int row_count; // row count -- total number of rows fetched int array_size; // size of host array attached to select statement // General constructor INLINE otl_select_cursor(otl_connect& db, // connect object short arr_size=1, // attached host array size int exception_enabled=otl_exception::enabled // exception enabled flag ); // Default constructor INLINE otl_select_cursor(int exception_enabled=otl_exception::enabled); // Open cursor INLINE int open(otl_connect& db, // connect object short arr_size=1, // attached host array size int exception_enabled=otl_exception::enabled // exception enabled flag ); // Close cursor INLINE int close(void); // Fetch first row. rows are fetched in batches. "cur_row" points to // current row in host array attached to select statement. // cur_row==-1 if no rows have been fetched. Returns 1 on success, 0 // on failure. INLINE int first(void); // Fetch next row. "cur_row" points to current row. cur_row==-1 after // fetch sequence is complete. Returns 1 on success, 0 on failure. INLINE int next(void); }; const int otl_var_list_size=256; // maximum size of OTL select list // Specialized cursor -- OTL reference cursor class. This // class implements Cursor References which were introduced in // Oracle 7.2 class otl_ref_cursor: public otl_cursor{ public: int cur_row; // index of current row in host array int cur_size; // number of rows in the buffer after most recent fetch int row_count; // row count -- total number of rows fetched int array_size; // size of host array attached to select statement // General constructor INLINE otl_ref_cursor(otl_connect& db, // connect object const char* cur_placeholder_name, // cursor reference placeholder name short arr_size=1, // attached host array size int exception_enabled=otl_exception::enabled // exception enabled flag ); // Default constructor INLINE otl_ref_cursor(int exception_enabled=otl_exception::enabled // exception enabled flag ); // Close cursor (if opened) and destruct object INLINE ~otl_ref_cursor(); // Open cursor INLINE int open(otl_connect& db, // connect object const char* cur_placeholder_name, // cursor reference placeholder name short arr_size=1, // attached host array size int exception_enabled=otl_exception::enabled // exception enabled flag ); // Close cursor INLINE int close(void); // Fetch first row. rows are fetched in batches. "cur_row" points to // current row in host array attached to select statement. // cur_row==-1 if no rows have been fetched. Returns 1 on success, 0 // on failure. INLINE int first(void); // Fetch next row. "cur_row" points to current row. cur_row==-1 after // fetch sequence is complete. Returns 1 on success, 0 on failure. INLINE int next(void); // Bind host variable/array (instantiated template) to column. Returns // 1 on success, 0 on failure INLINE int bind(int column_num, // column number: 1,2,... otl_generic_variable& v // reference to variable/array ); // Bind template host variable/array with already defined // name. Returns 1 on success, 0 on failure INLINE int bind(otl_generic_variable& v); // Bind host variable/array (instantiated template) to // placeholder. Returns 1 on success, 0 on failure INLINE int bind(const char* name, // placeholder name: ":F1", ":F2" otl_generic_variable& v // reference to host variable/array ); // Describe reference cursor's select item list. Returns 1 on success, // 0 on failure. INLINE int describe_select( otl_column_desc* desc, // pointer to array of column // descriptors int& desc_len // actual number of columns ); protected: int rvl_len; // variable list length otl_p_generic_variable* rvl; // reference cursor variable (column) list int vl_cur_len; // Current size of the vl array otl_cursor sel_cur; // cursor, used for the reference cursor char cur_placeholder[64]; // Reference cursor placeholder name }; const int otl_max_long_size=32760; // max default size of LONG and LONG RAW internal data types in // otl_select_stream. // OTL Select Stream class. Dynamically allocates default select list // items (output columns) by the information from the describe_column // function. // This class may issue the following otl_exceptions: // // Incompatible data types in stream operation, code=32000 // Not all input variables have been initialized, code=32004 // No input variables have beed defined in SELECT statement, code=32004 // class otl_select_stream: public otl_select_cursor{ public: // General conctructor. SELECT statement is parsed, all input host // variables and output columns are automatically bound. INLINE otl_select_stream(otl_connect& db, // connect object const char* sqlstm, // SELECT statement const short arr_size, // output host arrays size ... // NULL terminated list of pointers to input host // variables. ); // General conctructor. SELECT statement is parsed, all input host // variables and output columns are automatically bound. The // difference between this constructor and the constuctor above is // that this constuctor takes a pointer to an array of pointer to the // host variable/array list, instead of taking them from stack, as the // above constuctor does. This allows the user to dynamically create // host variables, say, in a loop, and collect pointers to the variables // into an array. INLINE otl_select_stream(otl_connect& db, // connect object const char* sqlstm, // SELECT statement otl_p_generic_variable* avp, // Pointer to NULL terminated list of // pointers to input hots // variables const short arr_size=1 // output host arrays size ); // General conctructor. SELECT statement is parsed, all input host // variables and output columns are automatically allocated and // bound. This constructor allows the user to use extended // place-holder declarations: // // :NAME<DATA_TYPE> // // The following data types are available in the extended // declarations: // // :VAR<char[<length>]>, e.g. :F1<char[32]> // :VAR<int> // :VAR<short> // :VAR<long> // :VAR<unsigned> // :VAR<float> // :VAR<double> // INLINE otl_select_stream( const short arr_size, // output host arrays size const char* sqlstm, // SELECT statement otl_connect& db // connect object ); // Destructor INLINE ~otl_select_stream(); // Rewind stream, SQL statement is re-executed. Input host variables // of SELECT statement may be re-assigned before calling this // function. INLINE void rewind(void); // Test if NULL has been fetched during last stream operation INLINE int is_null(void); // Test if "end-of-file" has been reached. Returns 1 when // "end-of-file". INLINE int eof(void); // Read objects from stream INLINE otl_select_stream& operator>>(char& c); INLINE otl_select_stream& operator>>(unsigned char& c); INLINE otl_select_stream& operator>>(char* s); INLINE otl_select_stream& operator>>(unsigned char* s); INLINE otl_select_stream& operator>>(int& n); INLINE otl_select_stream& operator>>(unsigned& u); INLINE otl_select_stream& operator>>(short& sh); INLINE otl_select_stream& operator>>(long int& l); INLINE otl_select_stream& operator>>(float& f); INLINE otl_select_stream& operator>>(double& d); // Write input values to the stream // (initialize input variables) INLINE otl_select_stream& operator<<(const char c); INLINE otl_select_stream& operator<<(const unsigned char c); INLINE otl_select_stream& operator<<(const char* s); INLINE otl_select_stream& operator<<(const unsigned char* s); INLINE otl_select_stream& operator<<(const int n); INLINE otl_select_stream& operator<<(const unsigned u); INLINE otl_select_stream& operator<<(const short sh); INLINE otl_select_stream& operator<<(const long int l); INLINE otl_select_stream& operator<<(const float f); INLINE otl_select_stream& operator<<(const double d); // Get info on SELECT list items INLINE int select_list_len(void); INLINE int column_ftype(int ndx=0); INLINE int column_size(int ndx=0); // Get column's internal info otl_column_desc* sl_desc; // column descriptor array // Set flag "delete input host variables" INLINE void set_delete_var(const int should_delete=0); protected: otl_dynamic_variable* sl; // Select list -- output columns. int sl_len; // Select list length int null_fetched; // "NULL fetched" flag int ret_code; // "return code" variable int cur_col; // current column index int cur_in; // current input variable index int executed; // "statement executed" flag // Internal stuff int should_delete_flag; // "should delete host variables" flag INLINE void init(int); INLINE void get_next(void); INLINE int check_type(int type_code); INLINE void look_ahead(void); INLINE void bind_all(void); INLINE void get_select_list(void); INLINE void get_in_next(void); INLINE int check_in_type(int type_code,int tsize); INLINE void check_in_var(void); INLINE void check_if_executed(void); public: // Special constructor. It parses SELECT statement and gets SELECT // list information. This constructor can be used when the user does // not really want to fetch rows via this stream but wants to get // information on the SELECT list (output columns). INLINE otl_select_stream(const char* sqlstm, // SELECT statement otl_connect& db, // connect object const char* dummy_par // dummy parameter (needed for // making the function // prototype unique ); }; class otl_ref_select_stream: public otl_ref_cursor{ public: // General conctructor. PLSQL block is parsed, all input host // variables and output columns are automatically bound. INLINE otl_ref_select_stream( otl_connect& db, // connect object const char* sqlstm, // PLSQL block const char* cur_placeholder, // reference cursor placeholder const short arr_size, // output host arrays size ... // NULL terminated list of pointers to input host // variables. ); // General conctructor. PLSQL block is parsed, all input host // variables and output columns are automatically bound. The // difference between this constructor and the constuctor above is // that this constuctor takes a pointer to an array of pointer to the // host variable/array list, instead of taking them from stack, as the // above constuctor does. This allows the user to dynamically create // host variables, say, in a loop, and collect pointers to the variables // into an array. INLINE otl_ref_select_stream( otl_connect& db, // connect object const char* sqlstm, // PLSQL block const char* cur_placeholder, // reference cursor placeholder otl_p_generic_variable* avp, // Pointer to NULL terminated list of // pointers to input hots // variables const short arr_size=1 // output host arrays size ); // General conctructor. PLSQL block is parsed, all input host // variables and output columns are automatically allocated and // bound. This constructor allows the user to use extended // place-holder declarations: // // :NAME<DATA_TYPE> // // The following data types are available in the extended // declarations: // // :VAR<char[<length>]>, e.g. :F1<char[32]> // :VAR<int> // :VAR<short> // :VAR<long> // :VAR<unsigned> // :VAR<float> // :VAR<double> // INLINE otl_ref_select_stream( const short arr_size, // output host arrays size const char* sqlstm, // PLSQL block const char* cur_placeholder, // reference cursor placeholder otl_connect& db // connect object ); // Destructor INLINE ~otl_ref_select_stream(); // Rewind stream, PLSQL block is re-executed. Input host variables // of the block may be re-assigned before calling this // function. INLINE void rewind(void); // Test if NULL has been fetched during last stream operation INLINE int is_null(void); // Test if "end-of-file" has been reached. Returns 1 when // "end-of-file". INLINE int eof(void); // Read objects from stream INLINE otl_ref_select_stream& operator>>(char& c); INLINE otl_ref_select_stream& operator>>(unsigned char& c); INLINE otl_ref_select_stream& operator>>(char* s); INLINE otl_ref_select_stream& operator>>(unsigned char* s); INLINE otl_ref_select_stream& operator>>(int& n); INLINE otl_ref_select_stream& operator>>(unsigned& u); INLINE otl_ref_select_stream& operator>>(short& sh); INLINE otl_ref_select_stream& operator>>(long int& l); INLINE otl_ref_select_stream& operator>>(float& f); INLINE otl_ref_select_stream& operator>>(double& d); // Write input values to the stream // (initialize input variables) INLINE otl_ref_select_stream& operator<<(const char c); INLINE otl_ref_select_stream& operator<<(const unsigned char c); INLINE otl_ref_select_stream& operator<<(const char* s); INLINE otl_ref_select_stream& operator<<(const unsigned char* s); INLINE otl_ref_select_stream& operator<<(const int n); INLINE otl_ref_select_stream& operator<<(const unsigned u); INLINE otl_ref_select_stream& operator<<(const short sh); INLINE otl_ref_select_stream& operator<<(const long int l); INLINE otl_ref_select_stream& operator<<(const float f); INLINE otl_ref_select_stream& operator<<(const double d); // Get info on SELECT list items INLINE int select_list_len(void); INLINE int column_ftype(int ndx=0); INLINE int column_size(int ndx=0); // Get column's internal info otl_column_desc* sl_desc; // column descriptor array // Set flag "delete input host variables" INLINE void set_delete_var(const int should_delete=0); protected: otl_dynamic_variable* sl; // Select list -- output columns. int sl_len; // Select list length int null_fetched; // "NULL fetched" flag int ret_code; // "return code" variable int cur_col; // current column index int cur_in; // current input variable index int executed; // "statement executed" flag // Internal stuff int should_delete_flag; // "should delete host variables" flag INLINE void init(int); INLINE void get_next(void); INLINE int check_type(int type_code); INLINE void look_ahead(void); INLINE void get_select_list(void); INLINE void get_in_next(void); INLINE int check_in_type(int type_code,int tsize); INLINE void check_in_var(void); INLINE void check_if_executed(void); }; // OTL NULL class. This class is used only for writing NULL into OTL // stream classes. class otl_null{ public: otl_null(){} ~otl_null(){} }; // OTL output stream. It should be used for the following SQL statements: // // DELETE; // UPDATE; // INSERT; // PL/SQL block with input parameters; // class otl_out_stream: public otl_cursor{ public: // Default constructor INLINE otl_out_stream(otl_connect& db); // General conctructor. SQL statement is parsed, all ouput host // variables are automatically bound. INLINE otl_out_stream(otl_connect& db, // connect object const char* sqlstm, // SQL statement ...// NULL terminated list of pointers to input host // variables. ); // General conctructor. SQL statement is parsed, all ouput host // variables are automatically bound. INLINE otl_out_stream(otl_connect& db, // connect object const char* sqlstm, // SQL statement otl_p_generic_variable* avp // Pointer to NULL terminated list of pointers // to input hots variables. ); // General conctructor. SQL statement is parsed, all host variables // are automatically allocated and bound. This constructor allows the // user to use extended place-holder declarations: // // :NAME<DATA_TYPE> // // The following data types are available in the extended // declarations: // // :VAR<char[<length>]>, e.g. :F1<char[32]> // :VAR<int> // :VAR<short> // :VAR<long> // :VAR<unsigned> // :VAR<float> // :VAR<double> // INLINE otl_out_stream( short arr_size, // host array size const char* sqlstm, // SQL statement otl_connect& db // connect object ); // Destructor INLINE ~otl_out_stream(); // Write objects into stream INLINE otl_out_stream& operator<<(const char c); INLINE otl_out_stream& operator<<(const unsigned char c); INLINE otl_out_stream& operator<<(const char* s); INLINE otl_out_stream& operator<<(const unsigned char* s); INLINE otl_out_stream& operator<<(const int n); INLINE otl_out_stream& operator<<(const unsigned u); INLINE otl_out_stream& operator<<(const short sh); INLINE otl_out_stream& operator<<(const long int l); INLINE otl_out_stream& operator<<(const float f); INLINE otl_out_stream& operator<<(const double d); INLINE otl_out_stream& operator<<(const otl_null n); // write Oracle NULL into stream // Flush stream buffer. SQL statement is executed as many times as the // rows have been entered into the stream buffer. INLINE virtual void flush(void); // Clean up stream buffer without flushing it. INLINE virtual void clean(void); // Set "auto-commit" flag. When the buffer is flushed, current // transaction is automatically commited, if the flag is set. INLINE void set_commit(int auto_commit=0); // Set flag "delete host variables" INLINE void set_delete_var(const int should_delete=0); protected: int auto_commit_flag; // "auto-commit" flag int dirty; // "dirty buffer" flag int should_delete_flag; // "should delete" flag int cur_x; //current variable/array index (X-coordinate) int cur_y; // current array element index (Y-coordinate) short array_size; // host variables/arrays size otl_connect* connect; // connect object int in_exception_flag; // "in exception" flag int in_destruct_flag; // "in destructor" flag INLINE void init(otl_connect& db,int should_delete=0); INLINE void get_next(void); INLINE int check_type(int type, int tsize); INLINE void check_buf(void); }; // OTL input/output stream. It is used primarily for PL/SQL blocks // with input and output parameters. Though, this stream class can be // used for SQL statements and PL/SQL blocks with input or output // parameters only. // class otl_inout_stream: public otl_out_stream{ public: // General conctructor. SQL statement is parsed, all host input and // output hostvariables are automatically allocated and bound. This // constructor allows the user to use extended place-holder // declarations: // // :NAME<DATA_TYPE,ACCESS_TYPE> // // The following data types are available in the extended // declarations: // // :VAR<char[<length>]>, e.g. :F1<char[32]> // :VAR<int> // :VAR<short> // :VAR<long> // :VAR<unsigned> // :VAR<float> // :VAR<double> // // The following access types are available in the extended // declarations: // // in -- input variable // out -- output variable // inout -- input/output variable // INLINE otl_inout_stream( short arr_size, // host array size const char* sqlstm, // SQL statement otl_connect& db // connect object ); INLINE ~otl_inout_stream(); // Test if all data has been already read from the stream INLINE int eof(void); // Flush stream's output buffer. It actually means to execute the SQL // statement as many times as rows entered to the output buffer. The // stream is automatically flushed when the buffer gets full. INLINE void flush(void); // Clean up buffer without flushing it. INLINE void clean(void); // Rewind stream INLINE void rewind(void); // Test if NULL was fetched from the stream INLINE int is_null(void); // Read objects from stream INLINE otl_inout_stream& operator>>(char& c); INLINE otl_inout_stream& operator>>(unsigned char& c); INLINE otl_inout_stream& operator>>(char* s); INLINE otl_inout_stream& operator>>(unsigned char* s); INLINE otl_inout_stream& operator>>(int& n); INLINE otl_inout_stream& operator>>(unsigned& u); INLINE otl_inout_stream& operator>>(short& sh); INLINE otl_inout_stream& operator>>(long int& l); INLINE otl_inout_stream& operator>>(float& f); INLINE otl_inout_stream& operator>>(double& d); protected: // Internal stuff otl_p_generic_variable* in_vl; // input variable list int iv_len; // input variable list length int cur_in_x; // current input array index (input X-coordinate) int cur_in_y; // current input array element index (input Y-coordinate) int in_y_len; // input variable list length int null_fetched; // "NULL fetched" flag otl_p_generic_variable* avl; // list of all variables int avl_len; // length of list of all variables INLINE void get_in_next(void); INLINE int check_in_type(int type_code,int tsize); INLINE int is_null_intern(void); }; // OTL stream class. This is a general-purpose stream class, unified // for streams of all types. class otl_stream{ public: // General conctructor. SQL statement is parsed, all host input and // output host variables are automatically allocated and bound. This // constructor allows the user to use extended place-holder // declarations: // // :NAME<DATA_TYPE,ACCESS_TYPE> // // The following data types are available in the extended // declarations: // // :VAR<char[<length>]>, e.g. :F1<char[32]> // :VAR<int> // :VAR<short> // :VAR<long> // :VAR<unsigned> // :VAR<float> // :VAR<double> // // The following access types are available in the extended // declarations: // // in -- input variable // out -- output variable // inout -- input/output variable // // Access types need to be defined only for PL/SQL blocks to avoid // ambiguity. INLINE otl_stream(short arr_size, // host array size const char* sqlstm, // SQL statement otl_connect& db, // connect object const char* ref_cur_placeholder=0 // reference cursor placeholder, e.g. ":cur" ); INLINE otl_stream(); // Desctructor INLINE ~otl_stream(); // Test if all data has been already read from the stream INLINE int eof(void); // Flush stream's output buffer. It actually means to execute the SQL // statement as many times as rows entered to the output buffer. The // stream is automatically flushed when the buffer gets full. INLINE void flush(void); // Clean up buffer without flushing it. INLINE void clean(void); // Rewind stream INLINE void rewind(void); // Test if NULL was fetched from the stream INLINE int is_null(void); // Set "auto-commit" flag. When the buffer is flushed, current // transaction is automatically commited, if the flag is set. INLINE void set_commit(int auto_commit=0); // Open stream INLINE void open(short arr_size, // host array size const char* sqlstm, // SQL statement otl_connect& db, // connect object const char* ref_cur_placeholder=0 // reference cursor placeholder, e.g. ":cur" ); // Close stream INLINE void close(void); // Test if the stream was opened okay INLINE int good(void); // Read objects from stream INLINE otl_stream& operator>>(char& c); INLINE otl_stream& operator>>(unsigned char& c); INLINE otl_stream& operator>>(char* s); INLINE otl_stream& operator>>(unsigned char* s); INLINE otl_stream& operator>>(int& n); INLINE otl_stream& operator>>(unsigned& u); INLINE otl_stream& operator>>(short& sh); INLINE otl_stream& operator>>(long int& l); INLINE otl_stream& operator>>(float& f); INLINE otl_stream& operator>>(double& d); // Write objects into stream INLINE otl_stream& operator<<(const char c); INLINE otl_stream& operator<<(const unsigned char c); INLINE otl_stream& operator<<(const char* s); INLINE otl_stream& operator<<(const unsigned char* s); INLINE otl_stream& operator<<(const int n); INLINE otl_stream& operator<<(const unsigned u); INLINE otl_stream& operator<<(const short sh); INLINE otl_stream& operator<<(const long int l); INLINE otl_stream& operator<<(const float f); INLINE otl_stream& operator<<(const double d); INLINE otl_stream& operator<<(const otl_null n); // write Oracle NULL into stream // C-like printf/scanf functions // The following format specifiers are supported: // // %d - int // %u - unsigned // %ld - long int // %f - float // %lf - double // %c - char // %s - string // // There is a specifier for writing NULL into stream: // // %N - NULL // // This couple of functions is intended for those who likes the C // style better than C++ streams. INLINE void printf(const char* fmt,...); INLINE void scanf(const char* fmt,...); protected: otl_ref_select_stream* ref_ss; // reference (cursor) select stream otl_select_stream* ss; // ordinary select stream otl_inout_stream* io; // input/ouput stream public: otl_connect* adb; // pointer to connect object for use in Prosto*C // Functions which contain actual implementation of printf/scanf. INLINE void vprintf(char* fmt,va_list argv); INLINE void vscanf(char* fmt,va_list argv); }; // OTL error info class. Should be used in case of manual error // handling in order to get more detailed error information class otl_err_info: public otl_exception{ public: // Default constructor otl_err_info(){} // Create error info object from otl_connect object otl_err_info(otl_connect& connect){init(connect.lda);} // Create error info object from otl_cursor object otl_err_info(otl_cursor& cur){init(cur.cda);} // Read error info into existing error info descriptor void get_info(otl_connect& connect){init(connect.lda);} void get_info(otl_cursor& cur){init(cur.cda,cur.stm_text);} }; // ========================= Template class section ========================== // OTL template variable class. allows to construct specialized // template variable classes (see below) template <class T, int atype> class otl_variable: public otl_generic_variable{ public: T v; // host varibale of data type T sb2 ind; // indicator ub2 rlen; // returned length ub2 rcode; // returned code // Default constructor otl_variable(){init();} // Construct variable by the name of aname, e.g. ":F1" otl_variable(const char* aname) { init(); copy_name(aname); } // Construct variable/column, with its further use in a select list in // the column_num position. otl_variable(const int column_num) { init(); copy_pos(column_num); } // Variables with either name or column_num initialized may be used in // the parse functions of OTL cursor classes, which variable lists of // parameters. // Initialize host variable internals void init() { ind=sizeof(T)>32767?0:(sb2)sizeof(T); rcode=0; ftype=atype; p_v=(ub1*)&v; p_ind=&ind; p_rlen=&rlen; p_rcode=&rcode; elem_size=sizeof(T); rlen=(ub2)elem_size; array_size=1; max_tab_len=(ub4)array_size; cur_tab_len=(ub4)array_size; } }; // OTL template host array class. allows to construct specialized // template array classes (see below) template <class T, const int atype, const short size> class otl_array: public otl_generic_variable{ public: T v[size]; // host array sb2 ind[size]; // indicator array ub2 rlen[size]; // returned length array ub2 rcode[size]; // returned code array // Default constructor otl_array(){init();} // Construct array by the name of aname, e.g. ":F1" otl_array(const char* aname) { init(); copy_name(aname); } // Construct array-column, with its further use in a select list in // the column_num position. otl_array(const int column_num) { init(); copy_pos(column_num); } // Initialize host array internals void init(void) { for(int i=0;i<size;++i){ ind[i]=sizeof(T); rlen[i]=sizeof(T); rcode[i]=0; } ftype=atype; p_v=(ub1*)&v[0]; p_ind=&ind[0]; p_rlen=&rlen[0]; p_rcode=&rcode[0]; elem_size=sizeof(T); array_size=size; max_tab_len=(ub4)array_size; cur_tab_len=(ub4)array_size; } }; // OTL DATE class typedef otl_variable<otl_date_intern,(const int)extDate> otl_date; // OTL ROWID class typedef otl_variable<otl_rowid_intern,(const int)extRowId> otl_rowid; // OTL VARNUM class typedef otl_variable<otl_varnum_intern,(const int)extVarNum> otl_varnum; // OTL NUMBER class typedef otl_variable<otl_number_intern,(const int)extNumber> otl_number; // OTL DATE ARRAY template <short size> class otl_date_array: public otl_array<otl_date_intern,(const int)extDate,size>{ public: otl_date_array() :otl_array<otl_date_intern,(const int)extDate,size>(){} otl_date_array(const char* aname) :otl_array<otl_date_intern,(const int)extDate,size>(aname){} otl_date_array(const int column_num) :otl_array<otl_date_intern,(const int)extDate,size>(column_num){} }; // OTL ROWID ARRAY template <short size> class otl_rowid_array: public otl_array<otl_rowid_intern,(const int)extRowId,size>{ public: otl_rowid_array() :otl_array<otl_rowid_intern,(const int)extRowId,size>(){} otl_rowid_array(const char *aname) :otl_array<otl_rowid_intern,(const int)extRowId,size>(aname){} otl_rowid_array(const int column_num) :otl_array<otl_rowid_intern,(const int)extRowId,size>(column_num){} }; // OTL VAR NUM ARRAY template <short size> class otl_varnum_array: public otl_array<otl_varnum_intern,(const int)extVarNum,size>{ public: otl_varnum_array() :otl_array<otl_varnum_intern,(const int)extVarNum,size>(){} otl_varnum_array(const char* aname) :otl_array<otl_varnum_intern,(const int)extVarNum,size>(aname){} otl_varnum_array(const int column_num) :otl_array<otl_varnum_intern,(const int)extVarNum,size>(column_num){} }; // OTL NUMBER ARRAY template <short size> class otl_number_array: public otl_array<otl_number_intern,(const int)extNumber,size>{ public: otl_number_array() :otl_array<otl_number_intern,(const int)extNumber,size>(){} otl_number_array(const char *aname) :otl_array<otl_number_intern,(const int)extNumber,size>(aname){} otl_number_array(const int column_num) :otl_array<otl_number_intern,(const int)extNumber,size>(column_num){} }; // There is a little use of these data types. As recommended in the // OCI documentation, it is better to convert internal data types to // strings. These classes are defined for completeness only. // ------------------- Numerical data types ------------------------- // Numerical scalar classes // OTL DOUBLE class typedef otl_variable<double,(const int)extFloat> otl_double; // OTL FLOAT class typedef otl_variable<float,(const int)extFloat> otl_float; // OTL SIGNED CHAR class typedef otl_variable<char,(const int)extInt> otl_signed_char; // OTL SHORT INT class typedef otl_variable<short,(const int)extInt> otl_short_int; // OTL INT class typedef otl_variable<int,(const int)extInt> otl_int; // OTL LONG INT class typedef otl_variable<long int,(const int)extInt> otl_long_int; // OTL UNSIGNED INT class typedef otl_variable<unsigned int,(const int)extInt> otl_unsigned; // Numerical array classes // OTL DOUBLE ARRAY template <short size> class otl_double_array: public otl_array<double,(const int)extFloat,size>{ public: otl_double_array() :otl_array<double,(const int)extFloat,size>(){} otl_double_array(const char* aname) :otl_array<double,(const int)extFloat,size>(aname){} otl_double_array(const int column_num) :otl_array<double,(const int)extFloat,size>(column_num){} }; // OTL FLOAT ARRAY template <short size> class otl_float_array: public otl_array<float,(const int)extFloat,size>{ public: otl_float_array() :otl_array<float,(const int)extFloat,size>(){} otl_float_array(const char* aname) :otl_array<float,(const int)extFloat,size>(aname){} otl_float_array(const int column_num) :otl_array<float,(const int)extFloat,size>(column_num){} }; // OTL SIGNED CHAR ARRAY template <short size> class otl_signed_char_array: public otl_array<char,(const int)extInt,size>{ public: otl_signed_char_array() :otl_array<char,(const int)extInt,size>(){} otl_signed_char_array(const char *aname) :otl_array<char,(const int)extInt,size>(aname){} otl_signed_char_array(const int column_num) :otl_array<char,(const int)extInt,size>(column_num){} }; // OTL SHORT INT ARRAY template <short size> class otl_short_int_array: public otl_array<short,(const int)extInt,size>{ public: otl_short_int_array() :otl_array<short,(const int)extInt,size>(){} otl_short_int_array(const char *aname) :otl_array<short,(const int)extInt,size>(aname){} otl_short_int_array(const int column_num) :otl_array<short,(const int)extInt,size>(column_num){} }; // OTL INT ARRAY template <short size> class otl_int_array: public otl_array<int,(const int)extInt,size>{ public: otl_int_array() :otl_array<int,(const int)extInt,size>(){} otl_int_array(const char *aname) :otl_array<int,(const int)extInt,size>(aname){} otl_int_array(const int column_num) :otl_array<int,(const int)extInt,size>(column_num){} }; // OTL LONG INT ARRAY template <short size> class otl_long_int_array: public otl_array<long int,(const int)extInt,size>{ public: otl_long_int_array() :otl_array<long int,(const int)extInt,size>(){} otl_long_int_array(const char* aname) :otl_array<long int,(const int)extInt,size>(aname){} otl_long_int_array(const int column_num) :otl_array<long int,(const int)extInt,size>(column_num){} }; // OTL UNSIGNED INT ARRAY template <short size> class otl_unsigned_array: public otl_array<unsigned int,(const int)extInt,size>{ public: otl_unsigned_array() :otl_array<unsigned int,(const int)extInt,size>(){} otl_unsigned_array(const char *aname) :otl_array<unsigned int,(const int)extInt,size>(aname){} otl_unsigned_array(const int column_num) :otl_array<unsigned int,(const int)extInt,size>(column_num){} }; // ----------------- String data types ------------------------- // String scalar classes // Null terminated string // (!!) most useful in C++ programs template <int str_size> class otl_cstring: public otl_variable<char[str_size],(const int)extCChar>{ public: otl_cstring(): otl_variable<char[str_size],(const int)extCChar>(){} otl_cstring(const int column_num): otl_variable<char[str_size],(const int)extCChar>(column_num){} otl_cstring(const char* aname): otl_variable<char[str_size],(const int)extCChar>(aname){} }; // OTL VARCHAR2 class template <int str_size> class otl_varchar2: public otl_variable<char[str_size],(const int)extVarChar2>{ public: otl_varchar2() :otl_variable<char[str_size],(const int)extVarChar2>(){} otl_varchar2(const char *aname) :otl_variable<char[str_size],(const int)extVarChar2>(aname){} otl_varchar2(const int column_num) :otl_variable<char[str_size],(const int)extVarChar2>(column_num){} }; // OTL LONG class template <int str_size> class otl_long: public otl_variable<char[str_size],(const int)extLong>{ public: otl_long() :otl_variable<char[str_size],(const int)extLong>(){} otl_long(const char *aname) :otl_variable<char[str_size],(const int)extLong>(aname){} otl_long(const int column_num) :otl_variable<char[str_size],(const int)extLong>(column_num){} }; // OTL VARCHAR class (see the OCI manual, chapter 3) template <int str_size> class otl_varchar: public otl_variable<char[str_size],(const int)extVarChar>{ public: otl_varchar() :otl_variable<char[str_size],(const int)extVarChar>(){} otl_varchar(const char *aname) :otl_variable<char[str_size],(const int)extVarChar>(aname){} otl_varchar(const int column_num) :otl_variable<char[str_size],(const int)extVarChar>(column_num){} }; // OTL VARRAW class template <int str_size> class otl_varraw: public otl_variable<unsigned char[str_size],(const int)extVarRaw>{ public: otl_varraw() :otl_variable<unsigned char[str_size],(const int)extVarRaw>(){} otl_varraw(const char *aname) :otl_variable<unsigned char[str_size],(const int)extVarRaw>(aname){} otl_varraw(const int column_num) :otl_variable<unsigned char[str_size],(const int)extVarRaw>(column_num){} }; // OTL RAW class template <ub1 str_size> class otl_raw: public otl_variable<unsigned char[str_size],(const int)extRaw>{ public: otl_raw() :otl_variable<unsigned char[str_size],(const int)extRaw>(){} otl_raw(const char *aname) :otl_variable<unsigned char[str_size],(const int)extRaw>(aname){} otl_raw(const int column_num) :otl_variable<unsigned char[str_size],(const int)extRaw>(column_num){} }; // OTL LONG RAW class template <int str_size> class otl_long_raw: public otl_variable<unsigned char[str_size],(const int)extLongRaw>{ public: otl_long_raw() :otl_variable<unsigned char[str_size],(const int)extLongRaw>(){} otl_long_raw(const char *aname) :otl_variable<unsigned char[str_size],(const int)extLongRaw>(aname){} otl_long_raw(const int column_num) :otl_variable<unsigned char[str_size],(const int)extLongRaw>(column_num){} }; // OTL CHAR class template <ub1 str_size> class otl_char: public otl_variable<char[str_size],(const int)extChar>{ public: otl_char() :otl_variable<char[str_size],(const int)extChar>(){} otl_char(const char *aname) :otl_variable<char[str_size],(const int)extChar>(aname){} otl_char(const int column_num) :otl_variable<char[str_size],(const int)extChar>(column_num){} }; // OTL CHARZ class template <ub1 str_size> class otl_charz: public otl_variable<char[str_size],(const int)extCharZ>{ public: otl_charz() :otl_variable<char[str_size],(const int)extCharZ>(){} otl_charz(const char *aname) :otl_variable<char[str_size],(const int)extCharZ>(aname){} otl_charz(const int column_num) :otl_variable<char[str_size],(const int)extCharZ>(column_num){} }; // OTL LONG VARCHAR class. // It is used for reading and writing objects of the Oracle LONG data // type. The class defines: // // - operator[] to access elements of the char buffer; // - function set_len() to set up string length on input; // - function len() to get string length on output; // template <int str_size> class otl_long_varchar: public otl_variable<char[str_size],(const int)extLongVarChar>{ public: otl_long_varchar() : otl_variable<char[str_size],(const int)extLongVarChar>(), real_len(*(sb4*)&v[0]), real_p_v((char*)&v[0]+sizeof(sb4)) { real_len=sizeof(v); } otl_long_varchar(const char *aname) : otl_variable<char[str_size],(const int)extLongVarChar>(aname), real_len(*(sb4*)&v[0]), real_p_v((char*)&v[0]+sizeof(sb4)) { real_len=sizeof(v); } otl_long_varchar(const int column_num) : otl_variable<char[str_size],(const int)extLongVarChar>(column_num), real_len(*(sb4*)&v[0]), real_p_v((char*)&v[0]+sizeof(sb4)) { real_len=sizeof(v); } void set_null(int ndx=0){ind=-1;} void set_len(int len, int ndx=0){real_len=len;} void set_not_null(int ndx=0){ind=0;} void* val(int ndx=0){return real_p_v;} int len(void){return real_len;} char& operator[](int ndx){return real_p_v[ndx];} private: char* real_p_v; sb4& real_len; }; // OTL LONG VARRAW class // It is used for reading and writing objects of the Oracle LONG RAW // data type. The class defines: // // - operator[] to access elements of the char buffer; // - function set_len() to set up string length on input; // - function len() to get string length on output; // template <int str_size> class otl_long_varraw: public otl_variable<unsigned char[str_size],(const int)extLongVarRaw>{ public: otl_long_varraw() : otl_variable<unsigned char[str_size],(const int)extLongVarRaw>(), real_len(*(sb4*)&v[0]), real_p_v((unsigned char*)&v[0]+sizeof(sb4)) { real_len=sizeof(v); } otl_long_varraw(const char *aname) : otl_variable<unsigned char[str_size],(const int)extLongVarRaw>(aname), real_len(*(sb4*)&v[0]), real_p_v((unsigned char*)&v[0]+sizeof(sb4)) { real_len=sizeof(v); } otl_long_varraw(const int column_num) : otl_variable<unsigned char[str_size],(const int)extLongVarRaw>(column_num), real_len(*(sb4*)&v[0]), real_p_v((unsigned char*)&v[0]+sizeof(sb4)) { real_len=sizeof(v); } void set_null(int ndx=0){ind=-1;} void set_len(int len, int ndx=0){real_len=len;} void set_not_null(int ndx=0){ind=0;} void* val(int ndx=0){return real_p_v;} int len(void){return real_len;} unsigned char& operator[](int ndx){return real_p_v[ndx];} private: unsigned char* real_p_v; sb4& real_len; }; // String array classes // Null terminated string array // (!!) most useful in C++ programs template <const short arr_size,const int str_size> class otl_cstring_array: public otl_array<char[str_size],(const int)extCChar,arr_size>{ public: otl_cstring_array() :otl_array<char[str_size],(const int)extCChar,arr_size>(){} otl_cstring_array(const char *aname) :otl_array<char[str_size],(const int)extCChar,arr_size>(aname){} otl_cstring_array(const int column_num) :otl_array<char[str_size],(const int)extCChar,arr_size>(column_num){} }; // OTL VARCHAR2 ARRAY template <const short arr_size,const int str_size> class otl_varchar2_array: public otl_array<char[str_size],(const int)extVarChar2,arr_size>{ public: otl_varchar2_array() :otl_array<char[str_size],(const int)extVarChar2,arr_size>(){} otl_varchar2_array(const char *aname) :otl_array<char[str_size],(const int)extVarChar2,arr_size>(aname){} otl_varchar2_array(const int column_num) :otl_array<char[str_size],(const int)extVarChar2,arr_size>(column_num){} }; // OTL LONG ARRAY template <const short arr_size,const int str_size> class otl_long_array: public otl_array<char[str_size],(const int)extLong,arr_size>{}; // OTL VARCHAR ARRAY template <const short arr_size,const int str_size> class otl_varchar_array: public otl_array<char[str_size],(const int)extVarChar,arr_size>{ public: otl_varchar_array() :otl_array<char[str_size],(const int)extVarChar,arr_size>(){} otl_varchar_array(const char *aname) :otl_array<char[str_size],(const int)extVarChar,arr_size>(aname){} otl_varchar_array(const int column_num) :otl_array<char[str_size],(const int)extVarChar,arr_size>(column_num){} }; // OTL VARRAW ARRAY template <const short arr_size,const int str_size> class otl_varraw_array: public otl_array<unsigned char[str_size],(const int)extVarRaw,arr_size>{ public: otl_varraw_array() :otl_array<unsigned char[str_size],(const int)extVarRaw,arr_size>(){} otl_varraw_array(const char *aname) :otl_array<unsigned char[str_size],(const int)extVarRaw,arr_size>(aname){} otl_varraw_array(const int column_num) :otl_array<unsigned char[str_size],(const int)extVarRaw,arr_size>(column_num){} }; // OTL VARRAW ARRAY template <const short arr_size,const ub1 str_size> class otl_raw_array: public otl_array<unsigned char[str_size],(const int)extVarRaw,arr_size>{ public: otl_raw_array() :otl_array<unsigned char[str_size],(const int)extVarRaw,arr_size>(){} otl_raw_array(const char *aname) :otl_array<unsigned char[str_size],(const int)extVarRaw,arr_size>(aname){} otl_raw_array(const int column_num) :otl_array<unsigned char[str_size],(const int)extVarRaw,arr_size>(column_num){} }; // OTL LONG RAW ARRAY template <const short arr_size,const int str_size> class otl_long_raw_array: public otl_array<unsigned char[str_size],(const int)extLongRaw,arr_size>{ public: otl_long_raw_array() :otl_array<unsigned char[str_size],(const int)extLongRaw,arr_size>(){} otl_long_raw_array(const char *aname) :otl_array<unsigned char[str_size],(const int)extLongRaw,arr_size>(aname){} otl_long_raw_array(const int column_num) :otl_array<unsigned char[str_size],(const int)extLongRaw,arr_size>(column_num){} }; // OTL CHAR ARRAY template <const short arr_size,const ub1 str_size> class otl_char_array: public otl_array<char[str_size],(const int)extChar,arr_size>{ public: otl_char_array() :otl_array<char[str_size],(const int)extChar,arr_size>(){} otl_char_array(const char *aname) :otl_array<char[str_size],(const int)extChar,arr_size>(aname){} otl_char_array(const int column_num) :otl_array<char[str_size],(const int)extChar,arr_size>(column_num){} }; // OTL CHARZ ARRAY template <const short arr_size,const ub1 str_size> class otl_charz_array: public otl_array<char[str_size],(const int)extCharZ,arr_size>{ public: otl_charz_array() :otl_array<char[str_size],(const int)extCharZ,arr_size>(){} otl_charz_array(const char *aname) :otl_array<char[str_size],(const int)extCharZ,arr_size>(aname){} otl_charz_array(const int column_num) :otl_array<char[str_size],(const int)extCharZ,arr_size>(column_num){} }; // Define variable or array p with the corresponding placeholder's // name ":p", e.g: // // OTL_VAR(f1,otl_float_array<100>); // OTL_VAR(f,otl_int); // #define OTL_VAR(p,type) type p(":"#p); // ================================ Prosto*C ================================ // Prosto*C is a simplified interface to SQL. It provides an // alternative method of intercepting errors. The user needs to define // an error handler function and attach it to the connect object. When // error occurs, the handler function is invoked. // OTL Error handler function prototype: // // err_msg -- error message // err_code -- error code // typedef void (*otl_error_handler)(char*,int); // Connect to Oracle using the "connect" string and attach the // "handler" function to the connect object. The function returns a // pointer to the corresponding connect object. INLINE otl_connect* otl_logon(char* connect,otl_error_handler handler=0); // "Pro*C" connect. Primary connection is done in a Pro*C module using // EXEC SQL CONNECT...; Attach the "handler" function to the connect // object. The function returns a pointer to the corresponding // connect object. INLINE otl_connect* otl_proC_logon(otl_error_handler handler=0); // Disconnect from Oracle. "db" -- connect object. Returns 1 on // success, 0 -- on failure. INLINE int otl_logoff(otl_connect* db); // Commit transaction. "db" -- connect object. INLINE void otl_commit(otl_connect* db); // Roll back transaction. "db" -- connect object. INLINE void otl_rollback(otl_connect* db); // Execute constant SQL statement: // // db -- connect object // stm -- SQL statement // ignore_error -- "ignore error" flag. If the flag is set up, then // the error handler function is not called. // // Returns 1 on success, 0 -- on failure. INLINE int otl_exec(otl_connect* db,char* stm,int ignore_error=0); // Open OTL stream: // // db -- connect object // stm -- SQL statement // bufsize -- size of the buffer, attached to the stream // // Returns pointer to stream on success, 0 -- on failure. INLINE otl_stream* otl_stream_open(otl_connect* db, char* stm, short bufsize=1, const char* ref_cur_placeholder=0 ); // Close OTL stream INLINE void otl_stream_close(otl_stream* f); // Check out the "EOF" condition on the "f" stream INLINE int otl_eof(otl_stream* f); // Check out if Oracle NULL has been fetched from the stream INLINE int otl_is_null(otl_stream* f); // Set "auto-commit" flag. When the buffer is flushed, current // transaction is automatically commited, if the flag is set. INLINE void otl_set_commit(otl_stream* f,int auto_commit=1); // Flush stream buffer. SQL statement is executed as many times as the // rows have been entered into the stream buffer. INLINE void otl_flush(otl_stream* f); // C-like printf/scanf functions // The following format specifiers are supported: // // %d - int // %u - unsigned // %ld - long int // %f - float // %lf - double // %c - char // %s - string // // There is a specifier for writing NULL into stream: // // %N - NULL // // This couple of functions is intended for those who likes the C // style better than C++ streams. INLINE void otl_printf(otl_stream* f,const char* fmt,...); INLINE void otl_scanf(otl_stream* f,const char* fmt,...); // ======================= Function bodies section =========================== INLINE void otl_exception::init(Lda_Def& lda,const char* sqlstm) // get error code and message { int len; stm_text=0; code=lda.rc; oerhms(&lda,lda.rc,msg,sizeof(msg)); len = strlen((const char*)msg); msg[len-1]=0; if(sqlstm){ len = strlen(sqlstm)+1; stm_text = new unsigned char[len]; strcpy((char*)stm_text,sqlstm); } } INLINE otl_object::otl_object() { connected=0; ex_enabled=otl_exception::enabled; } INLINE otl_connect::otl_connect(int exception_enabled) :rc(lda.rc) { ex_enabled=exception_enabled; proc_connect=0; handler=0; memset(&lda,0,sizeof(lda)); } INLINE otl_connect::otl_connect( const char* connect_str, int exception_enabled ) : rc(lda.rc) { ex_enabled=exception_enabled; proc_connect=0; handler=0; memset(&lda,0,sizeof(lda)); rlogon(connect_str); } INLINE otl_connect::~otl_connect() { logoff(); } INLINE int otl_connect::test_blocking(void) { if(!connected)return 0; int r=onbtst(&lda); if(rc==otl_blocking)return otl_blocking; if(rc==0)return otl_nonblocking; if(rc!=0 && ex_enabled) throw otl_exception(lda); return 0; } INLINE int otl_connect::set_nonblocking(void) { if(!connected)return 0; int r=onbset(&lda); if(r && ex_enabled) throw otl_exception(lda); return 1; } INLINE int otl_connect::clear_nonblocking(void) { if(!connected)return 0; int r=onbclr(&lda); if(r && ex_enabled) throw otl_exception(lda); return 1; } INLINE int otl_connect::rlogon( const char* connect_str ) {// according to the OCI manual, HDA needs to be initialized memset(hda,0,sizeof(hda)); connected=!olog(&lda, hda, (unsigned char*)connect_str, -1, 0, -1, 0, -1, 0 // default, blocking connection mode ); if(!connected && ex_enabled) throw otl_exception(lda);// raise exception return connected; } INLINE int otl_connect::sqllda() { ::sqllda(&lda); connected=!rc; if(!connected && ex_enabled) throw otl_exception(lda); proc_connect=1; return connected; } INLINE int otl_connect::sqlld2(const char* dbname) {sb4 clen=-1; ::sqlld2(&lda,(unsigned char*)dbname,&clen); connected=!rc; if(!connected && ex_enabled) throw otl_exception(lda); proc_connect=1; return connected; } INLINE int otl_connect::logon(const char* connect_str) { connected=!olon( &lda, (unsigned char*)connect_str, -1, 0, -1, 0 ); if(!connected && ex_enabled) throw otl_exception(lda); return connected; } INLINE int otl_connect::logoff() { if(!connected||proc_connect)return 0; int r=ologof(&lda); connected=0; if(r && ex_enabled) throw otl_exception(lda); return !rc; } INLINE int otl_connect::commit() { if(!connected)return 0; int r=ocom(&lda); if(r && ex_enabled) throw otl_exception(lda); return !rc; } INLINE int otl_connect::rollback() { if(!connected)return 0; int r=orol(&lda); if(r && ex_enabled) throw otl_exception(lda); return !rc; } INLINE int otl_connect::obreak() { if(!connected)return 0; int r=::obreak(&lda); if(r && ex_enabled) throw otl_exception(lda); return !rc; } INLINE int otl_connect::auto_commit_on() { if(!connected)return 0; int r=ocon(&lda); if(r && ex_enabled) throw otl_exception(lda); return !rc; } INLINE int otl_connect::auto_commit_off() { if(!connected)return 0; int r=ocof(&lda); if(r && ex_enabled) throw otl_exception(lda); return !rc; } INLINE int otl_connect::thread_safe_init(void) { int r=opinit(1); // Set up thread safe environment. return !r; } INLINE otl_generic_variable::otl_generic_variable() { name=0; pos=0; max_tab_len=0; cur_tab_len=0; } INLINE otl_generic_variable::~otl_generic_variable() { #ifdef OTL_DEBUG cout<<"(001)- = "<<(int*)name<<endl; #endif delete name; } INLINE void otl_generic_variable::copy_name(const char* aname) { pos=0; if(name==aname)return; if(name){ #ifdef OTL_DEBUG cout<<"(002)- = "<<(int*)name<<endl; #endif delete name; } name=new char[strlen(aname)+1]; #ifdef OTL_DEBUG cout<<"(069)+ = "<<(int*)name<<endl; #endif strcpy(name,aname); } INLINE void otl_generic_variable::copy_pos(const int apos) { if(name){ #ifdef OTL_DEBUG cout<<"(003)- = "<<(int*)name<<endl; #endif delete name; name=0; } pos=apos; } INLINE void otl_generic_variable::set_null(int ndx) { p_ind[ndx]=-1; } INLINE void otl_generic_variable::set_len(int len, int ndx) { p_rlen[ndx]=(short)len; } INLINE void otl_generic_variable::set_not_null(int ndx) { p_ind[ndx]=(short)elem_size; } INLINE int otl_generic_variable::is_null(int ndx) { return p_ind[ndx]==-1; } INLINE int otl_generic_variable::is_success(int ndx) { return p_ind[ndx]==0; } INLINE int otl_generic_variable::is_truncated(int ndx) { return p_ind[ndx]==-2||p_ind[ndx]>0; } INLINE void* otl_generic_variable::val(int ndx) { return (void*)&p_v[((unsigned)ndx)*elem_size]; } INLINE int otl_generic_variable::is_invalid_conversion(int ndx) { return p_rcode[ndx]==1454; } INLINE int otl_generic_variable::is_real_overflow(int ndx) { return p_rcode[ndx]==1456; } INLINE int otl_generic_variable::is_unsupported_datatype(int ndx) { return p_rcode[ndx]==3115; } INLINE void otl_generic_variable::set_tab_len(int new_len) { max_tab_len=(ub4)array_size; cur_tab_len=(ub4)new_len; } INLINE int otl_generic_variable::get_tab_len(void) { return (int)cur_tab_len; } INLINE otl_dynamic_variable::otl_dynamic_variable( const int column_num, const Aftype, const Aelem_size, const short Aarray_size ) { copy_pos(column_num); init(Aftype,Aelem_size,Aarray_size); } INLINE otl_dynamic_variable::otl_dynamic_variable( const char *aname, const Aftype, const Aelem_size, const short Aarray_size ) { copy_name(aname); init(Aftype,Aelem_size,Aarray_size); } INLINE otl_dynamic_variable::otl_dynamic_variable() { p_v=0; p_ind=0; p_rlen=0; p_rcode=0; } INLINE otl_dynamic_variable::~otl_dynamic_variable() { #ifdef OTL_DEBUG cout<<"(070)- = "<<(int*)p_v<<endl; #endif delete p_v; #ifdef OTL_DEBUG cout<<"(071)- = "<<(int*)p_ind<<endl; #endif delete p_ind; #ifdef OTL_DEBUG cout<<"(072)- = "<<(int*)p_rlen<<endl; #endif delete p_rlen; #ifdef OTL_DEBUG cout<<"(073)- = "<<(int*)p_rcode<<endl; #endif delete p_rcode; } INLINE void otl_dynamic_variable::init( const int Aftype, const int Aelem_size, const short Aarray_size ) { int i; ftype=Aftype; elem_size=Aelem_size; array_size=Aarray_size; p_v=new ub1[elem_size*(unsigned)array_size]; #ifdef OTL_DEBUG cout<<"(074)+ = "<<(int*)p_v<<endl; #endif p_ind=new sb2[array_size]; p_rlen=new ub2[array_size]; #ifdef OTL_DEBUG cout<<"(075)+ = "<<(int*)p_rlen<<endl; #endif p_rcode=new ub2[array_size]; #ifdef OTL_DEBUG cout<<"(076)+ = "<<(int*)p_rcode<<endl; #endif max_tab_len=(ub4)array_size; cur_tab_len=(ub4)array_size; memset(p_v,0,elem_size*(unsigned)array_size); for(i=0;i<array_size;++i){ p_ind[i]=(short)elem_size; p_rlen[i]=(short)elem_size; p_rcode[i]=0; } } INLINE int otl_dynamic_variable::get_ftype(void) { return ftype; } INLINE int otl_dynamic_variable::get_elem_size(void) { return elem_size; } INLINE otl_cursor::otl_cursor(int exception_enabled) : rpc(cda.rpc), ft(cda.ft), rc(cda.rc), peo(cda.peo) { ex_enabled=exception_enabled; vl=0; vl_len=0; adb=0; stm_text=0; memset(&cda,0,sizeof(cda)); } INLINE otl_cursor::otl_cursor( otl_connect& connect, int exception_enabled ) : rpc(cda.rpc), ft(cda.ft), rc(cda.rc), peo(cda.peo) { vl=0; vl_len=0; adb=&connect; stm_text=0; ex_enabled=exception_enabled; open(connect); } INLINE otl_cursor::~otl_cursor() { close(); delete[] stm_text; stm_text=0; } INLINE void otl_cursor::alloc_var(otl_p_generic_variable* vp) { otl_p_generic_variable tmp_vl[otl_var_list_size]; while(*vp){ ++vl_len; tmp_vl[vl_len-1]=*vp; ++vp; } if(vl_len>0){ vl=new otl_p_generic_variable[vl_len]; #ifdef OTL_DEBUG cout<<"(078)+ = "<<(int*)vl<<endl; #endif for(int i=0;i<vl_len;++i) vl[i]=tmp_vl[i]; } } INLINE int otl_cursor::open(otl_connect& connect) { adb=&connect; if(rc!=otl_blocked)memset(&cda,0,sizeof(cda)); connected=!oopen(&cda,&connect.lda,0,-1,-1,0,-1); if(!connected && ex_enabled) throw otl_exception(connect.lda,stm_text); return connected; } INLINE int otl_cursor::close(void) { if(!connected)return 0; if(adb){ if(!adb->connected){ connected=0; adb=0; return 0; } } int r=oclose(&cda); connected=0; adb=0; if(r && ex_enabled) throw otl_exception(cda,stm_text); return !r; } INLINE int otl_cursor::cancel(void) { if(!connected)return 0; int r=ocan(&cda); if(r && ex_enabled) throw otl_exception(cda,stm_text); return !r; } INLINE int otl_cursor::option(int rbopt, int waitopt) { if(!connected)return 0; int r=oopt(&cda,rbopt,waitopt); if(r && ex_enabled) throw otl_exception(cda,stm_text); return !r; } INLINE int otl_cursor::fetch_long( int column_num, // column number: 1,2,... void* buf, // pointer to buffer sb4 bufl, // buffer size int dtype, // buffer data type, see ext* "enum" ub4* retl, // returned length sb4 offset // offset ) { if(!connected)return 0; int r=oflng(&cda,column_num,(ub1*)buf,bufl,dtype,retl,offset); if(r && ex_enabled) throw otl_exception(cda,stm_text); return !r; } INLINE int otl_cursor::parse(const char* sqlstm) { if(!connected)return 0; if(stm_text){ delete[] stm_text; stm_text=0; } stm_text = new char[strlen(sqlstm) + 1]; strcpy(stm_text, sqlstm); return(parse()); } INLINE int otl_cursor::parse(void) { int r=oparse(&cda,(unsigned char*)stm_text,-1,0,0); if(r && ex_enabled) throw otl_exception(cda,stm_text); return !r; } INLINE int otl_cursor::parse(const char* sqlstm, otl_generic_variable** v ) { if(!connected)return 0; if(stm_text){ delete[] stm_text; stm_text=0; } stm_text = new char[strlen(sqlstm) + 1]; strcpy(stm_text, sqlstm); if(!parse())return 0; otl_generic_variable** vp=v; int pos=0; while(*vp){ otl_generic_variable* v=*vp; if(v->name){ if(!bind(*v))return 0; }else{ ++pos; if(!v->pos)v->pos=pos; if(!bind(*v))return 0; } ++vp; } return 1; } INLINE int otl_cursor::eparse(const char* sqlstm,...) { va_list argv; va_start(argv,sqlstm); if(!connected)return 0; if(stm_text){ delete[] stm_text; stm_text=0; } stm_text = new char[strlen(sqlstm) + 1]; strcpy(stm_text, sqlstm); if(!parse())return 0; int pos=0; otl_generic_variable* v; do{ v=(otl_generic_variable*)va_arg(argv,otl_generic_variable*); if(v){ if(v->name){ if(!bind(*v))return 0; }else{ ++pos; if(!v->pos)v->pos=pos; if(!bind(*v))return 0; } } }while(v); return 1; } INLINE int otl_cursor::eexec(const char* sqlstm,short iters,...) { va_list argv; va_start(argv,iters); if(!connected)return 0; if(stm_text){ delete[] stm_text; stm_text=0; } stm_text = new char[strlen(sqlstm) + 1]; strcpy(stm_text, sqlstm); if(!parse())return 0; int pos=0; otl_generic_variable* v; do{ v=(otl_generic_variable*)va_arg(argv,otl_generic_variable*); if(v){ if(v->name){ if(!bind(*v))return 0; }else{ ++pos; if(!v->pos)v->pos=pos; if(!bind(*v))return 0; } } }while(v); return exec(iters); } INLINE int otl_cursor::exec(short iters) { if(!connected)return 0; int r=oexn(&cda,iters,0); if(r && ex_enabled) throw otl_exception(cda,stm_text); return !r; } INLINE int otl_cursor::fetch(short iters) { if(!connected)return 0; int r=ofen(&cda,iters); if(r && ex_enabled && rc!=1403) throw otl_exception(cda,stm_text); return !r; } INLINE int otl_cursor::exfet(short iters) { if(!connected)return 0; int r=oexfet(&cda,iters,0,0); if(r && ex_enabled && rc!=1403) throw otl_exception(cda,stm_text); return !r; } INLINE int otl_cursor::bind( const char* name, // placeholder name: ":F1", ":F2" otl_generic_variable& v // reference to host variable/array ) { if(!connected)return 0; if(rc!=otl_blocked)v.copy_name(name); int r=obndrv(&cda, (unsigned char*) name, -1, (ub1*)v.p_v, v.elem_size, v.ftype, -1, v.p_ind, 0, -1, -1 ); if(r && ex_enabled) throw otl_exception(cda,stm_text); return !r; } INLINE int otl_cursor::bind_tab( const char* name, // placeholder name: ":F1", ":F2" otl_generic_variable& v // reference to host variable/array ) { if(!connected)return 0; if(rc!=otl_blocked)v.copy_name(name); int r=obndra(&cda, (unsigned char*)name, -1, (ub1*)v.p_v, v.elem_size, v.ftype, -1, v.p_ind, v.p_rlen, v.p_rcode, v.max_tab_len, &v.cur_tab_len, 0, -1, -1 ); if(r && ex_enabled) throw otl_exception(cda,stm_text); return !r; } INLINE int otl_cursor::bind( const char* name, // placeholder name: ":f1", ":f2" void* buf, // pointer to host variable/array int elem_size, //array element/ variable size in bytes int ftype, // Oracle external data type code sb2* indp // pointer to indicator variable/array ) { if(!connected)return 0; int r=obndrv(&cda, (unsigned char*) name, -1, (ub1*)buf, elem_size, ftype, -1, indp, 0, -1, -1 ); if(r && ex_enabled) throw otl_exception(cda,stm_text); return !r; } INLINE int otl_cursor::bind(otl_generic_variable& v) { if(v.name)return bind(v.name,v); if(v.pos)return bind(v.pos,v); return 0; } INLINE int otl_cursor::bind_tab(otl_generic_variable& v) { if(v.name)return bind_tab(v.name,v); return 0; } INLINE int otl_cursor::bind( int column_num, // column number: 1,2,... otl_generic_variable& v // reference to variable/array ) { if(!connected)return 0; if(rc!=otl_blocked)v.copy_pos(column_num); int r=odefin(&cda, column_num, (ub1*)v.p_v, v.elem_size, v.ftype, -1, v.p_ind, 0, -1, -1, v.p_rlen, v.p_rcode ); if(r && ex_enabled) throw otl_exception(cda,stm_text); return !r; } INLINE int otl_cursor::bind( int column_num, // column number: 1,2,... void* buf, // pointer to host variable/array int elem_size, // array element/variable size in bytes int ftype, // Oracle external data type code sb2* indp, // pointer to indicator array/varibale ub2* rlen, // pointer to returned length array/variable ub2* rcode // pointer to returned code array variable ) { if(!connected)return 0; int r=odefin(&cda, column_num, (ub1*)buf, elem_size, ftype, -1, indp, 0, -1, -1, rlen, rcode ); if(r && ex_enabled) throw otl_exception(cda,stm_text); return !r; } INLINE int otl_cursor::bind_cstring( int column_num, // column number: 1,2,... char* buf, // pointer to C-string variable/array int elem_size, // array element/variable size sb2* indp, // pointer to indicator array/variable ub2* rlen, // pointer to returned length array/variable ub2* rcode // pointer to returned code array/variable ) { return bind(column_num, buf, elem_size, extCChar, indp, rlen, rcode ); } INLINE int otl_cursor::bind_int( int column_num, // column number: 1,2,... int* buf, // pointer to int variable/array sb2* indp, // pointer to indicator array/variable ub2* rlen, // pointer to returned length array/variable ub2* rcode // pointer to returned code array/variable ) { return bind(column_num, buf, sizeof(int), extInt, indp, rlen, rcode ); } INLINE int otl_cursor::bind_short( int column_num,// column number: 1,2,... short* buf, // pointer to short int variable/array sb2* indp, // pointer to indicator array/variable ub2* rlen, // pointer to returned length array/variable ub2* rcode // pointer to returned code array/variable ) { return bind(column_num, buf, sizeof(short), extInt, indp, rlen, rcode ); } INLINE int otl_cursor::bind_long_int( int column_num, // column number: 1,2,... long* buf, // pointer to long int variable/array sb2* indp, // pointer to indicator array/variable ub2* rlen, // pointer to returned length array/variable ub2* rcode // pointer to returned code array/variable ) { return bind(column_num, buf, sizeof(long), extInt, indp, rlen, rcode ); } INLINE int otl_cursor::bind_float( int column_num,// column number: 1,2,... float* buf, // pointer to float variable/array sb2* indp, // pointer to indicator array/variable ub2* rlen, // pointer to returned length array/variable ub2* rcode // pointer to returned code array/variable ) { return bind(column_num, buf, sizeof(float), extFloat, indp, rlen, rcode ); } INLINE int otl_cursor::bind_double( int column_num,// column number: 1,2,... double* buf, // pointer to double variable/array sb2* indp, // pointer to indicator array/variable ub2* rlen, // pointer to returned length array/variable ub2* rcode // pointer to returned code array/variable ) { return bind(column_num, buf, sizeof(double), extFloat, indp, rlen, rcode ); } INLINE int otl_cursor::bind_cstring( const char* name, // placeholder name: ":F1", ":F2" char* buf, // pointer to C-string variable/array int elem_size, // array element/variable size sb2* indp // pointer to indicator array/variable ) { return bind(name, buf, elem_size, extCChar, indp ); } INLINE int otl_cursor::bind_int( const char* name, // placeholder name: ":F1", ":F2" int* buf, // pointer to int variable/array sb2* indp // pointer to indicator array/variable ) { return bind(name, buf, sizeof(int), extInt, indp ); } INLINE int otl_cursor::bind_short( const char* name, // placeholder name: ":F1", ":F2" short* buf, // pointer to short int variable/array sb2* indp // pointer to indicator array/variable ) { return bind(name, buf, sizeof(short), extInt, indp ); } INLINE int otl_cursor::bind_long_int( const char* name, // placeholder name: ":F1", ":F2" long* buf, // pointer to long int variable/array sb2* indp // pointer to indicator array/variable ) { return bind(name, buf, sizeof(long), extInt, indp ); } INLINE int otl_cursor::bind_float( const char* name, // placeholder name: ":F1", ":F2" float* buf, // pointer to float variable/array sb2* indp // pointer to indicator array/variable ) { return bind(name, buf, sizeof(float), extFloat, indp ); } INLINE int otl_cursor::bind_double( const char* name, // placeholder name: ":F1", ":F2" double* buf, // pointer to double variable/array sb2* indp // pointer to indicator array/variable ) { return bind(name, buf, sizeof(double), extFloat, indp ); } INLINE int otl_cursor::direct_exec( otl_connect& db, // connect object const char* stm, // statement int exception_enabled // exception_enabled flag ) { otl_cursor cur(db,otl_exception::disabled); int r=cur.parse(stm); if(cur.rc&&exception_enabled) throw otl_exception(cur.cda,stm); if(cur.rc&&!exception_enabled)return 0; r=cur.exec(); if(cur.rc&&exception_enabled)throw otl_exception(cur.cda,stm); return r; } INLINE int otl_cursor::describe_column( otl_column_desc& col_desc, // column descriptor structure int column_num // column number: 1,2,... ) { if(!connected)return 0; col_desc.nlen=sizeof(col_desc.name); int r=odescr(&cda, column_num, &col_desc.dbsize, &col_desc.dbtype, &col_desc.name[0], &col_desc.nlen, &col_desc.dsize, &col_desc.prec, &col_desc.scale, &col_desc.nullok ); if(rc==0) col_desc.name[col_desc.nlen]='\0'; if(r && !end_of_desc() && ex_enabled) throw otl_exception(cda,stm_text); return !r; } INLINE int otl_cursor::eof(void) { return rc==1403; } INLINE int otl_cursor::end_of_desc(void) { return rc==1007; } // ================ Internal otl_ext_hv_decl class ====================== class otl_ext_hv_decl{ public: enum var_status{ in=0, out=1, io=2, def=3 }; INLINE otl_ext_hv_decl(char* stm,short arr_size=1); INLINE ~otl_ext_hv_decl(); INLINE char* operator[](int ndx){return hv[ndx];} INLINE short v_status(int ndx){return inout[ndx];} INLINE int is_id(char c); INLINE int name_comp(char* n1,char* n2); INLINE void add_var(int &n,char* v,short in_out); INLINE void alloc_host_var_list( otl_p_generic_variable* &vl, int& vl_len, const int status=def ); INLINE otl_generic_variable* alloc_var(char* s, const int vstat, const int status); char* hv[otl_var_list_size]; short inout[otl_var_list_size]; short array_size; short vst[4]; short len; }; INLINE int otl_ext_hv_decl::is_id(char c) { return isalnum(c)||c=='_'; } INLINE int otl_ext_hv_decl::name_comp(char* n1,char* n2) { while(*n1!=' '&&*n1!='\0'&&*n2!=' '&&*n2!='\0'){ if(toupper(*n1)!=toupper(*n2))return 0; ++n1; ++n2; } if(*n1==' '&&*n2!=' '||*n2==' '&&*n1!=' ') return 0; return 1; } INLINE void otl_ext_hv_decl::add_var(int &n,char* v,short in_out) { for(int i=0;i<n;++i) if(name_comp(hv[i],v)) return; hv[n]=new char[strlen(v)+1]; #ifdef OTL_DEBUG cout<<"(078)+ = "<<(int*)hv[n]<<endl; #endif strcpy(hv[n],v); inout[n]=in_out; hv[++n]=0; inout[n]=def; } INLINE otl_ext_hv_decl::otl_ext_hv_decl(char* stm, short arr_size) { array_size=arr_size; int i=0; short in_str=0; char *c=stm; hv[i]=0; while(*c){ if(*c=='\''){ if(!in_str) in_str=1; else{ if(c[1]=='\'') ++c; else in_str=0; } } if(*c==':'&&!in_str){ short in_out=def; char var[64]; char* v=var; *v++=*c++; while(is_id(*c)) *v++=*c++; while(isspace(*c)&&*c) ++c; if(*c=='<'){ *c=' '; while(*c!='>'&&*c!=','&&*c){ *v++=*c; *c++=' '; } if(*c==','){ *c++=' '; if(toupper(*c)=='I'){ if(toupper(c[2])=='O') in_out=io; else in_out=in; }else if(toupper(*c)=='O') in_out=out; while(*c!='>'&&*c) *c++=' '; } *c=' '; *v='\0'; add_var(i,var,in_out); } } ++c; } for(int j=0;j<4;++j)vst[j]=0; i=0; while(hv[i]){ switch(inout[i]){ case in: ++vst[0]; break; case out: ++vst[1]; break; case io: ++vst[2]; break; case def: ++vst[3]; break; } ++i; } len=(short)i; } INLINE otl_ext_hv_decl::~otl_ext_hv_decl() { for(int i=0;hv[i]!=0;++i){ #ifdef OTL_DEBUG cout<<"(008)- = "<<(int*)hv[i]<<endl; #endif delete hv[i]; } } INLINE void otl_ext_hv_decl::alloc_host_var_list( otl_p_generic_variable* &vl, int& vl_len, const int status ) { vl_len=0; if(!hv[0]){ vl=0; return; } otl_p_generic_variable tmp_vl[otl_var_list_size]; int i=0; while(hv[i]){ otl_p_generic_variable vp=alloc_var(hv[i],inout[i],status); if(vp){ ++vl_len; tmp_vl[vl_len-1]=vp; } ++i; } if(vl_len>0){ vl=new otl_p_generic_variable[vl_len]; #ifdef OTL_DEBUG cout<<"(079)+ = "<<(int*)vl<<endl; #endif for(int j=0;j<vl_len;++j) vl[j]=tmp_vl[j]; } } extern "C" int atoi(const char*); INLINE otl_generic_variable* otl_ext_hv_decl::alloc_var( char* s, const int vstat, const int status ) { char name[64]; char type; sword size=0; char *c=name,*c1=s; while(*c1!=' '&&*c1) *c++=*c1++; *c='\0'; while(*c1==' '&&*c1) ++c1; type=(char)toupper(*c1); if(type=='C'){ char tmp[32]; char *t=tmp; while(*c1!='['&&*c1) ++c1; ++c1; while(*c1!=']'&&*c1) *t++=*c1++; *t='\0'; size=atoi(tmp); } if(status==in && (vstat==in||vstat==io)) ; else if(status==out && (vstat==out||vstat==io||vstat==def)) ; else if(status==def) ; else return 0; otl_dynamic_variable* v=new otl_dynamic_variable; #ifdef OTL_DEBUG cout<<"(080)+ = "<<(int*)v<<endl; #endif v->copy_name(name); switch(type){ case 'C': v->init(extCChar,size,array_size); break; case 'D': v->init(extFloat,sizeof(double),array_size); break; case 'F': v->init(extFloat,sizeof(float),array_size); break; case 'I': v->init(extInt,sizeof(int),array_size); break; case 'U': v->init(extInt,sizeof(unsigned),array_size); break; case 'S': v->init(extInt,sizeof(short),array_size); break; case 'L': v->init(extInt,sizeof(long),array_size); break; default: #ifdef OTL_DEBUG cout<<"(010)- = "<<(int*)v<<endl; #endif delete v; v=0; break; } return v; } // ======================================================================== INLINE otl_select_cursor::otl_select_cursor( otl_connect& db, // connect object short arr_size, // attached host array size int exception_enabled // exception enabled flag ):otl_cursor(db,exception_enabled) { cur_row=-1; row_count=0; cur_size=0; array_size=arr_size; } INLINE otl_select_cursor::otl_select_cursor(int exception_enabled) : otl_cursor(exception_enabled) { } INLINE int otl_select_cursor::open( otl_connect& db, // connect object short arr_size, // attached host array size int exception_enabled // exception enabled flag ) { cur_row=-1; row_count=0; cur_size=0; array_size=arr_size; ex_enabled=exception_enabled; return otl_cursor::open(db); } // Close cursor INLINE int otl_select_cursor::close(void) { return otl_cursor::close(); } INLINE int otl_select_cursor::first(void) { cur_row=-1; exec(); fetch((short)array_size); row_count=rpc; cur_size=row_count; if(cur_size!=0)cur_row=0; return cur_size!=0; } INLINE int otl_select_cursor::next(void) { if(cur_row==-1)return first(); if(cur_row<cur_size-1) ++cur_row; else{ if(eof()){ cur_row=-1; return 0; } fetch((short)array_size); cur_size=rpc-row_count; row_count=rpc; if(cur_size!=0)cur_row=0; } return cur_size!=0; } INLINE otl_ref_cursor::otl_ref_cursor( int exception_enabled // exception enabled flag ): otl_cursor(exception_enabled),sel_cur(exception_enabled) { } INLINE otl_ref_cursor::otl_ref_cursor( otl_connect& db, // connect object const char* cur_placeholder_name, // cursor reference placeholder name short arr_size, // attached host array size int exception_enabled // exception enabled flag ):otl_cursor(db,exception_enabled),sel_cur(exception_enabled) { cur_row=-1; row_count=0; cur_size=0; array_size=arr_size; rvl_len=otl_var_list_size; vl_cur_len=0; rvl=new otl_p_generic_variable[rvl_len]; #ifdef OTL_DEBUG cout<<"(081)+ = "<<(int*)rvl<<endl; #endif for(int i=0;i<rvl_len;++i)rvl[i]=0; strcpy(cur_placeholder,cur_placeholder_name); } INLINE otl_ref_cursor::~otl_ref_cursor() { delete[] rvl; rvl=0; } INLINE int otl_ref_cursor::open( otl_connect& db, // connect object const char* cur_placeholder_name, // cursor reference placeholder name short arr_size, // attached host array size int exception_enabled // exception enabled flag ) { cur_row=-1; row_count=0; cur_size=0; array_size=arr_size; rvl_len=otl_var_list_size; vl_cur_len=0; rvl=new otl_p_generic_variable[rvl_len]; #ifdef OTL_DEBUG cout<<"(181)+ = "<<(int*)rvl<<endl; #endif for(int i=0;i<rvl_len;++i)rvl[i]=0; strcpy(cur_placeholder,cur_placeholder_name); return otl_cursor::open(db); } INLINE int otl_ref_cursor::close(void) { delete[] rvl; rvl=0; sel_cur.close(); return otl_cursor::close(); } INLINE int otl_ref_cursor::first(void) { otl_cursor::bind(cur_placeholder, &sel_cur.cda, sizeof(sel_cur.cda), 102 // Special "OCI External datatype" code -- // cursor reference ); if(cur_row==-2) ; // Special case -- calling describe_select() between parse() and first() else{ exec(); // Executing the PLSQL master block sel_cur.connected=1; } cur_row=-1; for(int i=0;i<vl_cur_len;++i) sel_cur.bind(i+1,*rvl[i]); sel_cur.fetch((short)array_size); row_count=sel_cur.rpc; cur_size=row_count; if(cur_size!=0)cur_row=0; return cur_size!=0; } INLINE int otl_ref_cursor::next(void) { if(cur_row<0)return first(); if(cur_row<cur_size-1) ++cur_row; else{ if(sel_cur.eof()){ cur_row=-1; return 0; } sel_cur.fetch((short)array_size); cur_size=sel_cur.rpc-row_count; row_count=sel_cur.rpc; if(cur_size!=0)cur_row=0; } return cur_size!=0; } INLINE int otl_ref_cursor::bind( int column_num, // column number: 1,2,... otl_generic_variable& v // reference to variable/array ) { if(!connected)return 0; ++vl_cur_len; rvl[vl_cur_len-1]=&v; v.pos=column_num; return 1; } INLINE int otl_ref_cursor::bind(otl_generic_variable& v) { if(v.pos) return bind(v.pos,v); else if(v.name) return otl_cursor::bind(v); return 0; } INLINE int otl_ref_cursor::bind( const char* name, // placeholder name: ":F1", ":F2" otl_generic_variable& v // reference to host variable/array ) { return otl_cursor::bind(name,v); } INLINE int otl_ref_cursor::describe_select( otl_column_desc* desc, // pointer to array of column // descriptors int& desc_len // actual number of columns ) { otl_cursor::bind(cur_placeholder, &sel_cur.cda, sizeof(sel_cur.cda), 102 // Special "OCI External datatype" code -- // cursor reference ); exec(); // Executing the PLSQL master block sel_cur.connected=1; cur_row=-2; // Special case -- describe_select() before first() or next() desc_len=0; for(int i=1;sel_cur.describe_column(desc[i-1],i);++i) ++desc_len; return 1; } INLINE void otl_select_stream::init(int should_delete) { sl=0; sl_len=0; null_fetched=0; ret_code=0; sl_desc=0; should_delete_flag=should_delete; executed=0; cur_in=0; stm_text=0; } INLINE otl_select_stream::otl_select_stream( otl_connect& db, // connect object const char* sqlstm, // SELECT statement const short arr_size, // output host arrays size ... // NULL terminated list of pointers to input host // variables. ):otl_select_cursor(db,arr_size) { init(0); otl_p_generic_variable tmp_vl[otl_var_list_size]; va_list argv; va_start(argv,arr_size); otl_generic_variable* v; do{ v=(otl_generic_variable*)va_arg(argv,otl_generic_variable*); if(v){ ++vl_len; tmp_vl[vl_len-1]=v; } }while(v); if(vl_len>0){ vl=new otl_p_generic_variable[vl_len]; #ifdef OTL_DEBUG cout<<"(082)+ = "<<(int*)vl<<endl; #endif for(int i=0;i<vl_len;++i) vl[i]=tmp_vl[i]; } parse(sqlstm); get_select_list(); bind_all(); if(vl_len==0){ rewind(); null_fetched=0; } } INLINE otl_select_stream::otl_select_stream( otl_connect& db, // connect object const char* sqlstm, // SELECT statement otl_p_generic_variable* avp, // Pointer to NULL terminated list of // pointers to input hots // variables const short arr_size // output host arrays size ):otl_select_cursor(db,arr_size) { init(0); alloc_var(avp); parse(sqlstm); get_select_list(); bind_all(); if(vl_len==0){ rewind(); null_fetched=0; } } INLINE otl_select_stream::otl_select_stream( const short arr_size, // output host arrays size const char* sqlstm, // SELECT statement otl_connect& db // connect object ):otl_select_cursor(db,arr_size) { init(1); { int len=strlen(sqlstm)+1; stm_text=new char[len]; #ifdef OTL_DEBUG cout<<"(083)+ = "<<(int*)stm_text<<endl; #endif strcpy(stm_text,sqlstm); otl_ext_hv_decl hvd(stm_text,1); hvd.alloc_host_var_list(vl,vl_len); } parse(); get_select_list(); bind_all(); if(vl_len==0){ rewind(); null_fetched=0; } } INLINE otl_select_stream::otl_select_stream( const char* sqlstm, // SELECT statement otl_connect& db, // connect object const char* dummy_par ):otl_select_cursor(db,1) { init(0); parse(sqlstm); get_select_list(); if(dummy_par); // dummy use of the dummy parameter } INLINE otl_select_stream::~otl_select_stream() { delete[] sl; if(should_delete_flag) for(int i=0;i<vl_len;++i){ #ifdef OTL_DEBUG cout<<"(011)- = "<<(int*)vl[i]<<endl; #endif delete vl[i]; } #ifdef OTL_DEBUG cout<<"(012)- = "<<(int*)vl<<endl; #endif delete[] vl; #ifdef OTL_DEBUG cout<<"(013)- = "<<(int*)sl_desc<<endl; #endif delete[] sl_desc; #ifdef OTL_DEBUG cout<<"(014)- = "<<(int*)stm_text<<endl; #endif } INLINE void otl_select_stream::rewind(void) { ret_code=first(); null_fetched=0; cur_col=-1; cur_in=0; executed=1; } INLINE int otl_select_stream::is_null(void) { return null_fetched; } INLINE int otl_select_stream::eof(void) { return !ret_code; } INLINE otl_select_stream& otl_select_stream::operator>>(char& c) { check_if_executed(); if(eof())return *this; get_next(); if(check_type(extCChar)&&!eof()){ c=*(char*)sl[cur_col].val(cur_row); look_ahead(); } return *this; } INLINE otl_select_stream& otl_select_stream::operator>>(unsigned char& c) { check_if_executed(); if(eof())return *this; get_next(); if(check_type(extCChar)&&!eof()){ c=*(unsigned char*)sl[cur_col].val(cur_row); look_ahead(); } return *this; } INLINE otl_select_stream& otl_select_stream::operator>>(char* s) { check_if_executed(); if(eof())return *this; get_next(); if(check_type(extCChar)&&!eof()){ strcpy((char*)s,(char*)sl[cur_col].val(cur_row)); look_ahead(); } return *this; } INLINE otl_select_stream& otl_select_stream::operator>>(unsigned char* s) { check_if_executed(); if(eof())return *this; get_next(); if(check_type(extCChar)&&!eof()){ strcpy((char*)s,(char*)sl[cur_col].val(cur_row)); look_ahead(); } return *this; } INLINE otl_select_stream& otl_select_stream::operator>>(int& n) { check_if_executed(); if(eof())return *this; get_next(); if(check_type(extFloat)&&!eof()){ n=(int)*(double*)sl[cur_col].val(cur_row); look_ahead(); } return *this; } INLINE otl_select_stream& otl_select_stream::operator>>(unsigned& u) { check_if_executed(); if(eof())return *this; get_next(); if(check_type(extFloat)&&!eof()){ u=(unsigned)*(double*)sl[cur_col].val(cur_row); look_ahead(); } return *this; } INLINE otl_select_stream& otl_select_stream::operator>>(short& sh) { check_if_executed(); if(eof())return *this; get_next(); if(check_type(extFloat)&&!eof()){ sh=(short)*(double*)sl[cur_col].val(cur_row); look_ahead(); } return *this; } INLINE otl_select_stream& otl_select_stream::operator>>(long int& l) { check_if_executed(); if(eof())return *this; get_next(); if(check_type(extFloat)&&!eof()){ l=(long)*(double*)sl[cur_col].val(cur_row); look_ahead(); } return *this; } INLINE otl_select_stream& otl_select_stream::operator>>(float& f) { check_if_executed(); if(eof())return *this; get_next(); if(check_type(extFloat)&&!eof()){ f=(float)*(double*)sl[cur_col].val(cur_row); look_ahead(); } return *this; } INLINE otl_select_stream& otl_select_stream::operator>>(double& d) { check_if_executed(); if(eof())return *this; get_next(); if(check_type(extFloat)&&!eof()){ d=*(double*)sl[cur_col].val(cur_row); look_ahead(); } return *this; } INLINE void otl_select_stream::get_next(void) { if(cur_col<sl_len-1){ ++cur_col; null_fetched=sl[cur_col].is_null(cur_row); }else{ ret_code=next(); cur_col=0; } } INLINE int otl_select_stream::check_type(int type_code) { if(sl[cur_col].get_ftype()!=type_code){ throw otl_exception(otl_error_msg_0, otl_error_code_0, stm_text); return 0; }else return 1; } INLINE void otl_select_stream::look_ahead(void) { if(cur_col==sl_len-1){ ret_code=next(); cur_col=-1; } } INLINE void otl_select_stream::bind_all(void) { int i; for(i=0;i<vl_len;++i)bind(*vl[i]); for(i=0;i<sl_len;++i)bind(sl[i]); } static INLINE int otl_int2ext(int int_type) { switch(int_type){ case inVarChar2: return extCChar; case inNumber: return extFloat; case inLong: return extCChar; case inRowId: return extCChar; case inDate: return extCChar; case inRaw: return extCChar; case inLongRaw: return extCChar; case inChar: return extCChar; default: return -1; } } static INLINE int otl_datatype_size(int ftype,int maxsz,int int_type) { switch(ftype){ case extCChar: switch(int_type){ case inRowId: return sizeof(otl_cchar_rowid); case inDate: return 10; // e.g. 19-JAN-64 + '\0' case inLong: case inLongRaw: return otl_max_long_size; case inRaw: return maxsz*2+1; default: return maxsz+1; } case extFloat: return sizeof(double); case extDate: return sizeof(otl_date_intern); default: return 0; } } static INLINE void otl_map_ftype(const otl_column_desc& desc, int& ftype, int& elem_size ) { ftype=otl_int2ext(desc.dbtype); elem_size=otl_datatype_size(ftype,desc.dbsize,desc.dbtype); } INLINE void otl_select_stream::get_select_list(void) { otl_column_desc sl_desc_tmp[otl_var_list_size]; int sld_tmp_len=0; int ftype,elem_size,i; for(i=1; describe_column(sl_desc_tmp[i-1],i); ++i) ++sld_tmp_len; sl_len=sld_tmp_len; if(sl){ delete[] sl; sl=0; } sl=new otl_dynamic_variable[sl_len]; #ifdef OTL_DEBUG cout<<"(084)+ = "<<(int*)sl<<endl; #endif for(int j=0;j<sl_len;++j){ otl_map_ftype(sl_desc_tmp[j],ftype,elem_size); sl[j].copy_pos(j+1); sl[j].init(ftype, (short)elem_size, (short)array_size ); } if(sl_desc){ delete[] sl_desc; sl_desc=0; } sl_desc=new otl_column_desc[sl_len]; #ifdef OTL_DEBUG cout<<"(085)+ = "<<(int*)sl_desc<<endl; #endif memcpy(sl_desc,sl_desc_tmp,sizeof(otl_column_desc)*sl_len); } INLINE int otl_select_stream::select_list_len(void) { return sl_len; } INLINE int otl_select_stream::column_ftype(int ndx) { return sl[ndx].get_ftype(); } INLINE int otl_select_stream::column_size(int ndx) { return sl[ndx].get_elem_size(); } INLINE void otl_select_stream::set_delete_var(const int should_delete) { should_delete_flag=should_delete; } INLINE void otl_select_stream::get_in_next(void) { if(cur_in==vl_len-1) rewind(); else{ ++cur_in; executed=0; } } INLINE int otl_select_stream::check_in_type(int type_code,int tsize) { if(vl[cur_in]->ftype==extCChar&&type_code==extCChar) return 1; if(vl[cur_in]->ftype!=type_code||vl[cur_in]->elem_size!=tsize){ throw otl_exception(otl_error_msg_0, otl_error_code_0, stm_text); return 1; }else return 1; } INLINE void otl_select_stream::check_in_var(void) { if(vl_len==0) throw otl_exception(otl_error_msg_1, otl_error_code_1, stm_text); } INLINE void otl_select_stream::check_if_executed(void) { if(!executed) throw otl_exception(otl_error_msg_2, otl_error_code_2, stm_text); } INLINE otl_select_stream& otl_select_stream::operator<<(const char c) { check_in_var(); if(check_in_type(extCChar,1)){ char* tmp=(char*)vl[cur_in]->val(); tmp[0]=c; tmp[1]=0; } get_in_next(); return *this; } INLINE otl_select_stream& otl_select_stream::operator<<(const unsigned char c) { check_in_var(); if(check_in_type(extCChar,1)){ unsigned char* tmp=(unsigned char*)vl[cur_in]->val(); tmp[0]=c; tmp[1]=0; } get_in_next(); return *this; } INLINE otl_select_stream& otl_select_stream::operator<<(const char* s) { check_in_var(); if(check_in_type(extCChar,1)){ strcpy((char*)vl[cur_in]->val(),(char*)s); } get_in_next(); return *this; } INLINE otl_select_stream& otl_select_stream::operator<<(const unsigned char* s) { check_in_var(); if(check_in_type(extCChar,1)){ strcpy((char*)vl[cur_in]->val(),(char*)s); } get_in_next(); return *this; } INLINE otl_select_stream& otl_select_stream::operator<<(const int n) { check_in_var(); if(check_in_type(extInt,sizeof(int))){ *(int*)vl[cur_in]->val()=n; } get_in_next(); return *this; } INLINE otl_select_stream& otl_select_stream::operator<<(const unsigned u) { check_in_var(); if(check_in_type(extInt,sizeof(unsigned))){ *(unsigned*)vl[cur_in]->val()=u; } get_in_next(); return *this; } INLINE otl_select_stream& otl_select_stream::operator<<(const short sh) { check_in_var(); if(check_in_type(extInt,sizeof(short))){ *(short*)vl[cur_in]->val()=sh; } get_in_next(); return *this; } INLINE otl_select_stream& otl_select_stream::operator<<(const long int l) { check_in_var(); if(check_in_type(extInt,sizeof(long))){ *(long*)vl[cur_in]->val()=l; } get_in_next(); return *this; } INLINE otl_select_stream& otl_select_stream::operator<<(const float f) { check_in_var(); if(check_in_type(extFloat,sizeof(float))){ *(float*)vl[cur_in]->val()=f; } get_in_next(); return *this; } INLINE otl_select_stream& otl_select_stream::operator<<(const double f) { check_in_var(); if(check_in_type(extFloat,sizeof(double))){ *(double*)vl[cur_in]->val()=f; } get_in_next(); return *this; } INLINE void otl_ref_select_stream::init(int should_delete) { sl=0; sl_len=0; null_fetched=0; ret_code=0; sl_desc=0; should_delete_flag=should_delete; executed=0; cur_in=0; stm_text=0; } INLINE otl_ref_select_stream::otl_ref_select_stream( otl_connect& db, // connect object const char* sqlstm, // SELECT statement const char* cur_placeholder, // reference cursor placeholder const short arr_size, // output host arrays size ... // NULL terminated list of pointers to input host // variables. ):otl_ref_cursor(db,cur_placeholder,arr_size) { init(0); otl_p_generic_variable tmp_vl[otl_var_list_size]; va_list argv; va_start(argv,arr_size); otl_generic_variable* v; do{ v=(otl_generic_variable*)va_arg(argv,otl_generic_variable*); if(v){ ++vl_len; tmp_vl[vl_len-1]=v; } }while(v); if(vl_len>0){ vl=new otl_p_generic_variable[vl_len]; #ifdef OTL_DEBUG cout<<"(086)+ = "<<(int*)vl<<endl; #endif for(int i=0;i<vl_len;++i) vl[i]=tmp_vl[i]; } parse(sqlstm); if(vl_len==0){ rewind(); null_fetched=0; } } INLINE otl_ref_select_stream::otl_ref_select_stream( otl_connect& db, // connect object const char* sqlstm, // SELECT statement const char* cur_placeholder, // reference cursor placeholder otl_p_generic_variable* avp, // Pointer to NULL terminated list of // pointers to input hots // variables const short arr_size // output host arrays size ):otl_ref_cursor(db,cur_placeholder,arr_size) { init(0); alloc_var(avp); parse(sqlstm); if(vl_len==0){ rewind(); null_fetched=0; } } INLINE otl_ref_select_stream::otl_ref_select_stream( const short arr_size, // output host arrays size const char* sqlstm, // SELECT statement const char* cur_placeholder, // reference cursor placeholder otl_connect& db // connect object ):otl_ref_cursor(db,cur_placeholder,arr_size) { init(1); { int len=strlen(sqlstm)+1; stm_text=new char[len]; #ifdef OTL_DEBUG cout<<"(087)+ = "<<(int*)stm_text<<endl; #endif strcpy(stm_text,sqlstm); otl_ext_hv_decl hvd(stm_text,1); hvd.alloc_host_var_list(vl,vl_len); } parse(); if(vl_len==0){ rewind(); null_fetched=0; } } INLINE otl_ref_select_stream::~otl_ref_select_stream() { delete[] sl; if(should_delete_flag) for(int i=0;i<vl_len;++i){ #ifdef OTL_DEBUG cout<<"(016)- = "<<(int*)vl[i]<<endl; #endif delete vl[i]; } #ifdef OTL_DEBUG cout<<"(017)- = "<<(int*)vl<<endl; #endif delete[] vl; #ifdef OTL_DEBUG cout<<"(018)- = "<<(int*)sl_desc<<endl; #endif delete[] sl_desc; #ifdef OTL_DEBUG cout<<"(019)- = "<<(int*)stm_text<<endl; #endif } INLINE void otl_ref_select_stream::rewind(void) { get_select_list(); ret_code=first(); null_fetched=0; cur_col=-1; cur_in=0; executed=1; } INLINE int otl_ref_select_stream::is_null(void) { return null_fetched; } INLINE int otl_ref_select_stream::eof(void) { return !ret_code; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator>>(char& c) { check_if_executed(); if(eof())return *this; get_next(); if(check_type(extCChar)&&!eof()){ c=*(char*)sl[cur_col].val(cur_row); look_ahead(); } return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator>>(unsigned char& c) { check_if_executed(); if(eof())return *this; get_next(); if(check_type(extCChar)&&!eof()){ c=*(unsigned char*)sl[cur_col].val(cur_row); look_ahead(); } return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator>>(char* s) { check_if_executed(); if(eof())return *this; get_next(); if(check_type(extCChar)&&!eof()){ strcpy((char*)s,(char*)sl[cur_col].val(cur_row)); look_ahead(); } return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator>>(unsigned char* s) { check_if_executed(); if(eof())return *this; get_next(); if(check_type(extCChar)&&!eof()){ strcpy((char*)s,(char*)sl[cur_col].val(cur_row)); look_ahead(); } return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator>>(int& n) { check_if_executed(); if(eof())return *this; get_next(); if(check_type(extFloat)&&!eof()){ n=(int)*(double*)sl[cur_col].val(cur_row); look_ahead(); } return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator>>(unsigned& u) { check_if_executed(); if(eof())return *this; get_next(); if(check_type(extFloat)&&!eof()){ u=(unsigned)*(double*)sl[cur_col].val(cur_row); look_ahead(); } return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator>>(short& sh) { check_if_executed(); if(eof())return *this; get_next(); if(check_type(extFloat)&&!eof()){ sh=(short)*(double*)sl[cur_col].val(cur_row); look_ahead(); } return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator>>(long int& l) { check_if_executed(); if(eof())return *this; get_next(); if(check_type(extFloat)&&!eof()){ l=(long)*(double*)sl[cur_col].val(cur_row); look_ahead(); } return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator>>(float& f) { check_if_executed(); if(eof())return *this; get_next(); if(check_type(extFloat)&&!eof()){ f=(float)*(double*)sl[cur_col].val(cur_row); look_ahead(); } return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator>>(double& d) { check_if_executed(); if(eof())return *this; get_next(); if(check_type(extFloat)&&!eof()){ d=*(double*)sl[cur_col].val(cur_row); look_ahead(); } return *this; } INLINE void otl_ref_select_stream::get_next(void) { if(cur_col<sl_len-1){ ++cur_col; null_fetched=sl[cur_col].is_null(cur_row); }else{ ret_code=next(); cur_col=0; } } INLINE int otl_ref_select_stream::check_type(int type_code) { if(sl[cur_col].get_ftype()!=type_code){ throw otl_exception(otl_error_msg_0, otl_error_code_0, stm_text); return 0; }else return 1; } INLINE void otl_ref_select_stream::look_ahead(void) { if(cur_col==sl_len-1){ ret_code=next(); cur_col=-1; } } INLINE void otl_ref_select_stream::get_select_list(void) {int i; otl_column_desc sl_desc_tmp[otl_var_list_size]; int sld_tmp_len=0; int ftype,elem_size; otl_cursor::bind(cur_placeholder, &sel_cur.cda, sizeof(sel_cur.cda), 102 // Special "OCI External datatype" code -- // cursor reference ); for(i=0;i<vl_len;++i)otl_cursor::bind(*vl[i]); otl_cursor::exec(); // Executing the PLSQL master block sel_cur.connected=1; cur_row=-2; sld_tmp_len=0; for(i=1;sel_cur.describe_column(sl_desc_tmp[i-1],i);++i) ++sld_tmp_len; sl_len=sld_tmp_len; if(sl){ delete[] sl; sl=0; } sl=new otl_dynamic_variable[sl_len]; #ifdef OTL_DEBUG cout<<"(088)+ = "<<(int*)sl<<endl; #endif for(int j=0;j<sl_len;++j){ otl_map_ftype(sl_desc_tmp[j],ftype,elem_size); sl[j].copy_pos(j+1); sl[j].init(ftype, (short)elem_size, (short)array_size ); } if(sl_desc){ delete[] sl_desc; sl_desc=0; } sl_desc=new otl_column_desc[sl_len]; #ifdef OTL_DEBUG cout<<"(089)+ = "<<(int*)sl_desc<<endl; #endif memcpy(sl_desc,sl_desc_tmp,sizeof(otl_column_desc)*sl_len); for(i=0;i<sl_len;++i)sel_cur.bind(sl[i]); } INLINE int otl_ref_select_stream::select_list_len(void) { return sl_len; } INLINE int otl_ref_select_stream::column_ftype(int ndx) { return sl[ndx].get_ftype(); } INLINE int otl_ref_select_stream::column_size(int ndx) { return sl[ndx].get_elem_size(); } INLINE void otl_ref_select_stream::set_delete_var(const int should_delete) { should_delete_flag=should_delete; } INLINE void otl_ref_select_stream::get_in_next(void) { if(cur_in==vl_len-1) rewind(); else{ ++cur_in; executed=0; } } INLINE int otl_ref_select_stream::check_in_type(int type_code,int tsize) { if(vl[cur_in]->ftype==extCChar&&type_code==extCChar) return 1; if(vl[cur_in]->ftype!=type_code||vl[cur_in]->elem_size!=tsize){ throw otl_exception(otl_error_msg_0, otl_error_code_0, stm_text); return 1; }else return 1; } INLINE void otl_ref_select_stream::check_in_var(void) { if(vl_len==0) throw otl_exception(otl_error_msg_1, otl_error_code_1, stm_text); } INLINE void otl_ref_select_stream::check_if_executed(void) { if(!executed) throw otl_exception(otl_error_msg_2, otl_error_code_2, stm_text); } INLINE otl_ref_select_stream& otl_ref_select_stream::operator<<(const char c) { check_in_var(); if(check_in_type(extCChar,1)){ char* tmp=(char*)vl[cur_in]->val(); tmp[0]=c; tmp[1]=0; } get_in_next(); return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator<<(const unsigned char c) { check_in_var(); if(check_in_type(extCChar,1)){ unsigned char* tmp=(unsigned char*)vl[cur_in]->val(); tmp[0]=c; tmp[1]=0; } get_in_next(); return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator<<(const char* s) { check_in_var(); if(check_in_type(extCChar,1)){ strcpy((char*)vl[cur_in]->val(),(char*)s); } get_in_next(); return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator<<(const unsigned char* s) { check_in_var(); if(check_in_type(extCChar,1)){ strcpy((char*)vl[cur_in]->val(),(char*)s); } get_in_next(); return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator<<(const int n) { check_in_var(); if(check_in_type(extInt,sizeof(int))){ *(int*)vl[cur_in]->val()=n; } get_in_next(); return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator<<(const unsigned u) { check_in_var(); if(check_in_type(extInt,sizeof(unsigned))){ *(unsigned*)vl[cur_in]->val()=u; } get_in_next(); return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator<<(const short sh) { check_in_var(); if(check_in_type(extInt,sizeof(short))){ *(short*)vl[cur_in]->val()=sh; } get_in_next(); return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator<<(const long int l) { check_in_var(); if(check_in_type(extInt,sizeof(long))){ *(long*)vl[cur_in]->val()=l; } get_in_next(); return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator<<(const float f) { check_in_var(); if(check_in_type(extFloat,sizeof(float))){ *(float*)vl[cur_in]->val()=f; } get_in_next(); return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator<<(const double f) { check_in_var(); if(check_in_type(extFloat,sizeof(double))){ *(double*)vl[cur_in]->val()=f; } get_in_next(); return *this; } INLINE void otl_out_stream::init(otl_connect& db,int should_delete) { dirty=0; auto_commit_flag=1; should_delete_flag=should_delete; cur_x=-1; cur_y=0; connect=&db; in_exception_flag=0; in_destruct_flag=0; stm_text=0; } INLINE otl_out_stream::otl_out_stream(otl_connect& db) :otl_cursor(db) { in_exception_flag=0; in_destruct_flag=0; dirty=0; auto_commit_flag=1; should_delete_flag=0; cur_x=-1; cur_y=0; connect=0; stm_text=0; } INLINE otl_out_stream::otl_out_stream( otl_connect& db, const char* sqlstm, ... ):otl_cursor(db) { init(db); otl_p_generic_variable tmp_vl[otl_var_list_size]; va_list argv; va_start(argv,sqlstm); otl_generic_variable* v; do{ v=(otl_generic_variable*)va_arg(argv,otl_generic_variable*); if(v){ ++vl_len; tmp_vl[vl_len-1]=v; } }while(v); if(vl_len>0){ vl=new otl_p_generic_variable[vl_len]; #ifdef OTL_DEBUG cout<<"(090)+ = "<<(int*)vl<<endl; #endif for(int i=0;i<vl_len;++i) vl[i]=tmp_vl[i]; } array_size=(short)vl[0]->array_size; parse(sqlstm); for(int i=0;i<vl_len;++i) bind(*vl[i]); } INLINE otl_out_stream::otl_out_stream( otl_connect& db, const char* sqlstm, otl_p_generic_variable* avp ):otl_cursor(db) { init(db); alloc_var(avp); array_size=(short)vl[0]->array_size; parse(sqlstm); for(int i=0;i<vl_len;++i) bind(*vl[i]); } INLINE otl_out_stream::otl_out_stream( short arr_size, // host array size const char* sqlstm, // SQL statement otl_connect& db // connect object ):otl_cursor(db) { init(db,1); array_size=arr_size; { int len=strlen(sqlstm)+1; stm_text=new char[len]; #ifdef OTL_DEBUG cout<<"(091)+ = "<<(int*)stm_text<<endl; #endif strcpy(stm_text,sqlstm); otl_ext_hv_decl hvd(stm_text,arr_size); hvd.alloc_host_var_list(vl,vl_len); } parse(); for(int i=0;i<vl_len;++i) bind(*vl[i]); } INLINE otl_out_stream::~otl_out_stream() { in_destruct_flag=1; if(dirty&&!in_exception_flag)flush(); if(should_delete_flag) for(int i=0;i<vl_len;++i){ #ifdef OTL_DEBUG cout<<"(020)- = "<<(int*)vl[i]<<endl; #endif delete vl[i]; } #ifdef OTL_DEBUG cout<<"(021)- = "<<(int*)vl<<endl; #endif delete vl; #ifdef OTL_DEBUG cout<<"(022)- = "<<(int*)stm_text<<endl; #endif in_destruct_flag=0; } INLINE otl_out_stream& otl_out_stream::operator<<(const char c) { if(vl_len>0){ get_next(); if(check_type(extCChar,1)){ char* tmp=(char*)vl[cur_x]->val(cur_y); tmp[0]=c; tmp[1]=0; } check_buf(); } return *this; } INLINE otl_out_stream& otl_out_stream::operator<<(const unsigned char c) { if(vl_len>0){ get_next(); if(check_type(extCChar,1)){ unsigned char* tmp=(unsigned char*)vl[cur_x]->val(cur_y); tmp[0]=c; tmp[1]=0; } check_buf(); } return *this; } INLINE otl_out_stream& otl_out_stream::operator<<(const char* s) { if(vl_len>0){ get_next(); if(check_type(extCChar,1)){ strcpy((char*)vl[cur_x]->val(cur_y),(char*)s); } check_buf(); } return *this; } INLINE otl_out_stream& otl_out_stream::operator<<(const unsigned char* s) { if(vl_len>0){ get_next(); if(check_type(extCChar,1)){ strcpy((char*)vl[cur_x]->val(cur_y),(char*)s); } check_buf(); } return *this; } INLINE otl_out_stream& otl_out_stream::operator<<(const int n) { if(vl_len>0){ get_next(); if(check_type(extInt,sizeof(int))){ *(int*)vl[cur_x]->val(cur_y)=n; } check_buf(); } return *this; } INLINE otl_out_stream& otl_out_stream::operator<<(const unsigned u) { if(vl_len>0){ get_next(); if(check_type(extInt,sizeof(unsigned))){ *(unsigned *)vl[cur_x]->val(cur_y)=u; } check_buf(); } return *this; } INLINE otl_out_stream& otl_out_stream::operator<<(const short sh) { if(vl_len>0){ get_next(); if(check_type(extInt,sizeof(short))){ *(short*)vl[cur_x]->val(cur_y)=sh; } check_buf(); } return *this; } INLINE otl_out_stream& otl_out_stream::operator<<(const long int l) { if(vl_len>0){ get_next(); if(check_type(extInt,sizeof(int))){ *(long*)vl[cur_x]->val(cur_y)=l; } check_buf(); } return *this; } INLINE otl_out_stream& otl_out_stream::operator<<(const float f) { if(vl_len>0){ get_next(); if(check_type(extFloat,sizeof(float))){ *(float*)vl[cur_x]->val(cur_y)=f; } check_buf(); } return *this; } INLINE otl_out_stream& otl_out_stream::operator<<(const double d) { if(vl_len>0){ get_next(); if(check_type(extFloat,sizeof(double))){ *(double*)vl[cur_x]->val(cur_y)=d; } check_buf(); } return *this; } INLINE otl_out_stream& otl_out_stream::operator<<(const otl_null n) { if(vl_len>0){ get_next(); vl[cur_x]->set_null(cur_y); check_buf(); } return *this; } INLINE void otl_out_stream::flush(void) { if(!dirty)return; if(rc||adb->rc){ clean(); return; // buffer is not flushed in case of error } if(cur_x!=vl_len-1){ in_exception_flag=1; throw otl_exception(otl_error_msg_3, otl_error_code_3, stm_text); } if(in_destruct_flag){ int save=ex_enabled; ex_enabled=0; exec((short)(cur_y+1)); ex_enabled=save; if(rc){ clean(); in_exception_flag=1; throw otl_exception(cda,stm_text); return; } if(auto_commit_flag){ int save=connect->ex_enabled; connect->ex_enabled=0; connect->commit(); connect->ex_enabled=save; if(connect->rc){ clean(); in_exception_flag=1; throw otl_exception(connect->lda,stm_text); return; } } }else{ exec((short)(cur_y+1)); if(auto_commit_flag) connect->commit(); clean(); } } INLINE void otl_out_stream::clean(void) { if(!dirty)return; for(int i=0;i<array_size;++i) for(int j=0;j<vl_len;++j) vl[j]->set_not_null(i); cur_x=-1; cur_y=0; dirty=0; } INLINE void otl_out_stream::set_commit(int auto_commit) { auto_commit_flag=auto_commit; } INLINE void otl_out_stream::set_delete_var(const int should_delete) { should_delete_flag=should_delete; } INLINE void otl_out_stream::get_next(void) { if(cur_x<vl_len-1) ++cur_x; else{ if(cur_y<array_size-1){ ++cur_y; cur_x=0; }else{ flush(); cur_x=0; } } dirty=1; } INLINE int otl_out_stream::check_type(int type_code, int tsize) { if(vl[cur_x]->ftype==extCChar&&type_code==extCChar) return 1; if(vl[cur_x]->ftype!=type_code||vl[cur_x]->elem_size!=tsize){ in_exception_flag=1; throw otl_exception(otl_error_msg_0, otl_error_code_0, stm_text); return 1; }else return 1; } INLINE void otl_out_stream::check_buf(void) { if(cur_x==vl_len-1 && cur_y==array_size-1) flush(); } INLINE otl_inout_stream::otl_inout_stream( short arr_size, // host array size const char* sqlstm, // SQL statement otl_connect& db // connect object ):otl_out_stream(db) { dirty=0; auto_commit_flag=1; should_delete_flag=0; connect=&db; in_exception_flag=0; stm_text=0; array_size=arr_size; in_vl=0; iv_len=0; avl_len=0; avl=0; { int len=strlen(sqlstm)+1; stm_text=new char[len]; #ifdef OTL_DEBUG cout<<"(092)+ = "<<(int*)stm_text<<endl; #endif strcpy(stm_text,sqlstm); otl_ext_hv_decl hvd(stm_text,arr_size); if(hvd.vst[otl_ext_hv_decl::def]==hvd.len){ should_delete_flag=1; hvd.alloc_host_var_list(vl,vl_len); }else{ for(int i=0;i<hvd.len;++i){ if(hvd.inout[i]==otl_ext_hv_decl::in) ++vl_len; else if(hvd.inout[i]==otl_ext_hv_decl::out) ++iv_len; else if(hvd.inout[i]==otl_ext_hv_decl::io){ ++vl_len; ++iv_len; } } if(vl_len>0){ vl=new otl_p_generic_variable[vl_len]; #ifdef OTL_DEBUG cout<<"(093)+ = "<<(int*)vl<<endl; #endif } if(iv_len>0){ in_vl=new otl_p_generic_variable[iv_len]; #ifdef OTL_DEBUG cout<<"(094)+ = "<<(int*)in_vl<<endl; #endif } if(hvd.len>0){ avl=new otl_p_generic_variable[hvd.len]; #ifdef OTL_DEBUG cout<<"(095)+ = "<<(int*)avl<<endl; #endif } iv_len=0; vl_len=0; avl_len=hvd.len; for(int j=0;j<avl_len;++j){ otl_p_generic_variable v=hvd.alloc_var(hvd[j],hvd.inout[j],otl_ext_hv_decl::def); avl[j]=v; if(hvd.inout[j]==otl_ext_hv_decl::in){ ++vl_len; vl[vl_len-1]=v; }else if(hvd.inout[j]==otl_ext_hv_decl::out){ ++iv_len; in_vl[iv_len-1]=v; }else if(hvd.inout[j]==otl_ext_hv_decl::io){ ++vl_len; ++iv_len; vl[vl_len-1]=v; in_vl[iv_len-1]=v; } } } } parse(); for(int i=0;i<vl_len;++i)bind(*vl[i]); for(int j=0;j<iv_len;++j)bind(*in_vl[j]); rewind(); } INLINE otl_inout_stream::~otl_inout_stream() { if(!in_exception_flag) flush(); for(int i=0;i<avl_len;++i){ #ifdef OTL_DEBUG cout<<"(023)- = "<<(int*)avl[i]<<endl; #endif delete avl[i]; } #ifdef OTL_DEBUG cout<<"(024)- = "<<(int*)avl<<endl; #endif delete[] avl; #ifdef OTL_DEBUG cout<<"(025)- = "<<(int*)in_vl<<endl; #endif delete[] in_vl; } INLINE void otl_inout_stream::rewind(void) { flush(); cur_in_x=0; cur_in_y=0; cur_x=-1; cur_y=0; in_y_len=0; null_fetched=0; if(vl_len==0){ exec(array_size); in_y_len=array_size; cur_in_y=0; cur_in_x=0; } } INLINE int otl_inout_stream::eof(void) { if(iv_len==0)return 1; if(in_y_len==0)return 1; if(cur_in_y<=in_y_len-1)return 0; return 1; } INLINE void otl_inout_stream::flush(void) { if(vl_len==0)return; in_y_len=cur_y+1; cur_in_y=0; cur_in_x=0; if(!in_exception_flag) otl_out_stream::flush(); } INLINE void otl_inout_stream::clean(void) { if(vl_len==0)return; in_y_len=cur_y+1; cur_in_y=0; cur_in_x=0; otl_out_stream::clean(); } INLINE int otl_inout_stream::is_null(void) { return null_fetched; } INLINE otl_inout_stream& otl_inout_stream::operator>>(char& c) { if(eof())return *this; if(check_in_type(extCChar,1)){ c=*(char*)in_vl[cur_in_x]->val(cur_in_y); null_fetched=is_null_intern(); } get_in_next(); return *this; } INLINE otl_inout_stream& otl_inout_stream::operator>>(unsigned char& c) { if(eof())return *this; if(check_in_type(extCChar,1)){ c=*(unsigned char*)in_vl[cur_in_x]->val(cur_in_y); null_fetched=is_null_intern(); } get_in_next(); return *this; } INLINE otl_inout_stream& otl_inout_stream::operator>>(char* s) { if(eof())return *this; if(check_in_type(extCChar,1)){ strcpy((char*)s,(char*)in_vl[cur_in_x]->val(cur_in_y)); null_fetched=is_null_intern(); } get_in_next(); return *this; } INLINE otl_inout_stream& otl_inout_stream::operator>>(unsigned char* s) { if(eof())return *this; if(check_in_type(extCChar,1)){ strcpy((char*)s,(char*)in_vl[cur_in_x]->val(cur_in_y)); null_fetched=is_null_intern(); } get_in_next(); return *this; } INLINE otl_inout_stream& otl_inout_stream::operator>>(int& n) { if(eof())return *this; if(check_in_type(extInt,sizeof(int))){ n=*(int*)in_vl[cur_in_x]->val(cur_in_y); null_fetched=is_null_intern(); } get_in_next(); return *this; } INLINE otl_inout_stream& otl_inout_stream::operator>>(unsigned& u) { if(eof())return *this; if(check_in_type(extInt,sizeof(unsigned))){ u=*(unsigned*)in_vl[cur_in_x]->val(cur_in_y); null_fetched=is_null_intern(); } get_in_next(); return *this; } INLINE otl_inout_stream& otl_inout_stream::operator>>(short& sh) { if(eof())return *this; if(check_in_type(extInt,sizeof(short))){ sh=*(short*)in_vl[cur_in_x]->val(cur_in_y); null_fetched=is_null_intern(); } get_in_next(); return *this; } INLINE otl_inout_stream& otl_inout_stream::operator>>(long int& l) { if(eof())return *this; if(check_in_type(extInt,sizeof(long))){ l=*(long*)in_vl[cur_in_x]->val(cur_in_y); null_fetched=is_null_intern(); } get_in_next(); return *this; } INLINE otl_inout_stream& otl_inout_stream::operator>>(float& f) { if(eof())return *this; if(check_in_type(extFloat,sizeof(float))){ f=*(float*)in_vl[cur_in_x]->val(cur_in_y); null_fetched=is_null_intern(); } get_in_next(); return *this; } INLINE otl_inout_stream& otl_inout_stream::operator>>(double& d) { if(eof())return *this; if(check_in_type(extFloat,sizeof(double))){ d=*(double*)in_vl[cur_in_x]->val(cur_in_y); null_fetched=is_null_intern(); } get_in_next(); return *this; } INLINE void otl_inout_stream::get_in_next(void) { if(iv_len==0)return; if(in_y_len==0)return; if(cur_in_x<iv_len-1) ++cur_in_x; else{ if(cur_in_y<in_y_len-1){ ++cur_in_y; cur_in_x=0; }else{ cur_in_y=0; cur_in_x=0; in_y_len=0; } } } INLINE int otl_inout_stream::check_in_type(int type_code,int tsize) { if(in_vl[cur_in_x]->ftype==extCChar&&type_code==extCChar) return 1; if(in_vl[cur_in_x]->ftype!=type_code||in_vl[cur_in_x]->elem_size!=tsize){ in_exception_flag=1; throw otl_exception(otl_error_msg_0, otl_error_code_0, stm_text); return 1; }else return 1; } INLINE int otl_inout_stream::is_null_intern(void) { if(iv_len==0)return 0; if(in_y_len==0)return 0; if(in_y_len>0) return in_vl[cur_in_x]->is_null(cur_in_y); return 0; } INLINE otl_stream::otl_stream( short arr_size, // host array size const char* sqlstm, // SQL statement otl_connect& db, // connect object const char* ref_cur_placeholder // reference cursor placeholder, e.g. ":cur" ) { io=0; ss=0; ref_ss=0; adb=&db; open(arr_size,sqlstm,db,ref_cur_placeholder); } INLINE otl_stream::otl_stream() { ref_ss=0; io=0; ss=0; adb=0; } INLINE void otl_stream::open( short arr_size, // host array size const char* sqlstm, // SQL statement otl_connect& db, // connect object const char* ref_cur_placeholder // reference cursor placeholder, e.g. ":cur" ) { char tmp[7]; char* c=(char*)sqlstm; while(isspace(*c))++c; strncpy(tmp,c,6); tmp[6]=0; c=tmp; while(*c){ *c=(char)toupper(*c); ++c; } adb=&db; if(strncmp(tmp,"SELECT",6)==0){ ss=new otl_select_stream(arr_size,sqlstm,db); #ifdef OTL_DEBUG cout<<"(096)+ = "<<(int*)ss<<endl; #endif } else if(ref_cur_placeholder!=0){ ref_ss=new otl_ref_select_stream(arr_size,sqlstm,ref_cur_placeholder,db); #ifdef OTL_DEBUG cout<<"(097)+ = "<<(int*)ref_ss<<endl; #endif }else { io=new otl_inout_stream(arr_size,sqlstm,db); #ifdef OTL_DEBUG cout<<"(098)+ = "<<(int*)io<<endl; #endif } } INLINE int otl_stream::good(void) { if(io||ss||ref_ss) return 1; else return 0; } INLINE void otl_stream::close(void) { #ifdef OTL_DEBUG cout<<"(026)- = "<<(int*)ss<<endl; #endif delete ss; #ifdef OTL_DEBUG cout<<"(027)- = "<<(int*)io<<endl; #endif delete io; #ifdef OTL_DEBUG cout<<"(026)- = "<<(int*)ref_ss<<endl; #endif delete ref_ss; ss=0; io=0; ref_ss=0; adb=0; } INLINE otl_stream::~otl_stream() { close(); } INLINE int otl_stream::eof(void) { if(io) return io->eof(); else if(ss) return ss->eof(); else if(ref_ss) return ref_ss->eof(); else return 1; } INLINE void otl_stream::flush(void) { if(io)io->flush(); } INLINE void otl_stream::clean(void) { if(io)io->clean(); } INLINE void otl_stream::rewind(void) { if(io) io->rewind(); else if(ss) ss->rewind(); else if(ref_ss) ref_ss->rewind(); } INLINE int otl_stream::is_null(void) { if(io) return io->is_null(); else if(ss) return ss->is_null(); else if(ref_ss) return ref_ss->is_null(); else return 0; } INLINE void otl_stream::set_commit(int auto_commit) { if(io)io->set_commit(auto_commit); } INLINE otl_stream& otl_stream::operator>>(char& c) { if(io) io->operator>>(c); else if(ss) ss->operator>>(c); else if(ref_ss) ref_ss->operator>>(c); return *this; } INLINE otl_stream& otl_stream::operator>>(unsigned char& c) { if(io) io->operator>>(c); else if(ss) ss->operator>>(c); else if(ref_ss) ref_ss->operator>>(c); return *this; } INLINE otl_stream& otl_stream::operator>>(char* s) { if(io) io->operator>>(s); else if(ss) ss->operator>>(s); else if(ref_ss) ref_ss->operator>>(s); return *this; } INLINE otl_stream& otl_stream::operator>>(unsigned char* s) { if(io) io->operator>>(s); else if(ss) ss->operator>>(s); else if(ref_ss) ref_ss->operator>>(s); return *this; } INLINE otl_stream& otl_stream::operator>>(int& n) { if(io) io->operator>>(n); else if(ss) ss->operator>>(n); else if(ref_ss) ref_ss->operator>>(n); return *this; } INLINE otl_stream& otl_stream::operator>>(unsigned& u) { if(io) io->operator>>(u); else if(ss) ss->operator>>(u); else if(ref_ss) ref_ss->operator>>(u); return *this; } INLINE otl_stream& otl_stream::operator>>(short& sh) { if(io) io->operator>>(sh); else if(ss) ss->operator>>(sh); else if(ref_ss) ref_ss->operator>>(sh); return *this; } INLINE otl_stream& otl_stream::operator>>(long int& l) { if(io) io->operator>>(l); else if(ss) ss->operator>>(l); else if(ref_ss) ref_ss->operator>>(l); return *this; } INLINE otl_stream& otl_stream::operator>>(float& f) { if(io) io->operator>>(f); else if(ss) ss->operator>>(f); else if(ref_ss) ref_ss->operator>>(f); return *this; } INLINE otl_stream& otl_stream::operator>>(double& d) { if(io) io->operator>>(d); else if(ss) ss->operator>>(d); else if(ref_ss) ref_ss->operator>>(d); return *this; } INLINE otl_stream& otl_stream::operator<<(const char c) { if(io) io->operator<<(c); else if(ss) ss->operator<<(c); else if(ref_ss) ref_ss->operator<<(c); return *this; } INLINE otl_stream& otl_stream::operator<<(const unsigned char c) { if(io) io->operator<<(c); else if(ss) ss->operator<<(c); else if(ref_ss) ref_ss->operator<<(c); return *this; } INLINE otl_stream& otl_stream::operator<<(const char* s) { if(io) io->operator<<(s); else if(ss) ss->operator<<(s); else if(ref_ss) ref_ss->operator<<(s); return *this; } INLINE otl_stream& otl_stream::operator<<(const unsigned char* s) { if(io) io->operator<<(s); else if(ss) ss->operator<<(s); else if(ref_ss) ref_ss->operator<<(s); return *this; } INLINE otl_stream& otl_stream::operator<<(const int n) { if(io) io->operator<<(n); else if(ss) ss->operator<<(n); else if(ref_ss) ref_ss->operator<<(n); return *this; } INLINE otl_stream& otl_stream::operator<<(const unsigned u) { if(io) io->operator<<(u); else if(ss) ss->operator<<(u); else if(ref_ss) ref_ss->operator<<(u); return *this; } INLINE otl_stream& otl_stream::operator<<(const short sh) { if(io) io->operator<<(sh); else if(ss) ss->operator<<(sh); else if(ref_ss) ref_ss->operator<<(sh); return *this; } INLINE otl_stream& otl_stream::operator<<(const long int l) { if(io) io->operator<<(l); else if(ss) ss->operator<<(l); else if(ref_ss) ref_ss->operator<<(l); return *this; } INLINE otl_stream& otl_stream::operator<<(const float f) { if(io) io->operator<<(f); else if(ss) ss->operator<<(f); else if(ref_ss) ref_ss->operator<<(f); return *this; } INLINE otl_stream& otl_stream::operator<<(const double d) { if(io) io->operator<<(d); else if(ss) ss->operator<<(d); else if(ref_ss) ref_ss->operator<<(d); return *this; } INLINE otl_stream& otl_stream::operator<<(const otl_null n) { if(io)io->operator<<(otl_null()); return *this; } INLINE void otl_stream::vprintf(char* fmt,va_list argv) { char *c=fmt; while(*c){ if(*c=='%'){ ++c; switch(*c){ case 'N': (*this)<<otl_null(); break; case 'f': (*this)<<(float)va_arg(argv,double); break; case 'd': (*this)<<(int)va_arg(argv,int); break; case 'u': (*this)<<(unsigned)va_arg(argv,unsigned); break; case 'l': ++c; switch(*c){ case 'd': (*this)<<(long)va_arg(argv,long); break; case 'f': (*this)<<(double)va_arg(argv,double); break; } break; case 'c': (*this)<<(char)va_arg(argv,int); break; case 's': (*this)<<(char*)va_arg(argv,char*); break; } } ++c; } } INLINE void otl_stream::vscanf(char* fmt,va_list argv) {char *c=fmt; while(*c){ if(*c=='%'){ ++c; switch(*c){ case 'f': (*this)>>*(float*)va_arg(argv,float*); break; case 'd': (*this)>>*(int*)va_arg(argv,int*); break; case 'u': (*this)>>*(unsigned*)va_arg(argv,unsigned*); break; case 'l': ++c; switch(*c){ case 'd': (*this)>>*(long*)va_arg(argv,long*); break; case 'f': (*this)>>*(double*)va_arg(argv,double*); break; } break; case 'c': (*this)>>*(char*)va_arg(argv,char*); break; case 's': (*this)>>(char*)va_arg(argv,char*); break; } } ++c; } } INLINE void otl_stream::printf(const char* fmt,...) { va_list argv; va_start(argv,fmt); vprintf((char*)fmt,argv); va_end(argv); } INLINE void otl_stream::scanf(const char* fmt,...) { va_list argv; va_start(argv,fmt); vscanf((char*)fmt,argv); } // =========================== Prosto*C functions =============================== INLINE otl_connect* otl_logon(char* connect,otl_error_handler handler) { otl_connect* db=new otl_connect; #ifdef OTL_DEBUG cout<<"(099)+ = "<<(int*)db<<endl; #endif db->handler=handler; try{ db->rlogon(connect); }catch(otl_exception& p){ if(handler)(*handler)((char*)p.msg,p.code); #ifdef OTL_DEBUG cout<<"(028)- = "<<(int*)db<<endl; #endif delete db; return 0; } return db; } INLINE otl_connect* otl_proC_logon(otl_error_handler handler) { otl_connect* db=new otl_connect; #ifdef OTL_DEBUG cout<<"(100)+ = "<<(int*)db<<endl; #endif db->handler=handler; try{ db->sqllda(); }catch(otl_exception& p){ if(handler)(*handler)((char*)p.msg,p.code); #ifdef OTL_DEBUG cout<<"(029)- = "<<(int*)db<<endl; #endif delete db; return 0; } return db; } INLINE int otl_logoff(otl_connect* db) { if(!db)return 0; try{ #ifdef OTL_DEBUG cout<<"(030)- = "<<(int*)db<<endl; #endif delete db; return 1; } catch(otl_exception& p){ if(db->handler) (*(otl_error_handler)db->handler)((char*)p.msg,p.code); #ifdef OTL_DEBUG cout<<"(031)- = "<<(int*)db<<endl; #endif delete db; return 0; } // return 1; } INLINE void otl_commit(otl_connect* db) { try{ db->commit(); } catch(otl_exception& p){ if(db->handler) (*(otl_error_handler)db->handler)((char*)p.msg,p.code); } } INLINE void otl_rollback(otl_connect* db) { try{ db->rollback(); } catch(otl_exception& p){ if(db->handler) (*(otl_error_handler)db->handler)((char*)p.msg,p.code); } } INLINE int otl_exec(otl_connect* db,char* stm,int ignore_error) { if(ignore_error){ return otl_cursor::direct_exec(*db,stm,otl_exception::disabled); }else{ try{ otl_cursor::direct_exec(*db,stm); return 1; } catch(otl_exception& p){ if(db->handler) (*(otl_error_handler)db->handler)((char*)p.msg,p.code); return 0; } // return 1; } } INLINE otl_stream* otl_stream_open(otl_connect* db, char* stm, short bufsize, const char* ref_cur_placeholder ) {otl_stream* s=0; try{ s=new otl_stream(bufsize,stm,*db,ref_cur_placeholder); #ifdef OTL_DEBUG cout<<"(101)+ = "<<(int*)s<<endl; #endif return s; } catch(otl_exception& p){ if(db->handler) (*(otl_error_handler)db->handler)((char*)p.msg,p.code); return 0; } // return 0; } INLINE void otl_stream_close(otl_stream* f) {otl_connect* db=f->adb; try{ #ifdef OTL_DEBUG cout<<"(032)- = "<<(int*)f<<endl; #endif delete f; } catch(otl_exception& p){ if(db->handler) (*(otl_error_handler)db->handler)((char*)p.msg,p.code); } } INLINE int otl_eof(otl_stream* f) { try{ return f->eof(); } catch(otl_exception& p){ if(f->adb->handler) (*(otl_error_handler)f->adb->handler)((char*)p.msg,p.code); } return 1; } INLINE int otl_is_null(otl_stream* f) { try{ return f->is_null(); } catch(otl_exception& p){ if(f->adb->handler) (*(otl_error_handler)f->adb->handler)((char*)p.msg,p.code); } return 0; } INLINE void otl_set_commit(otl_stream* f,int auto_commit) { try{ f->set_commit(auto_commit); } catch(otl_exception& p){ if(f->adb->handler) (*(otl_error_handler)f->adb->handler)((char*)p.msg,p.code); } } INLINE void otl_flush(otl_stream* f) { try{ f->flush(); } catch(otl_exception& p){ if(f->adb->handler) (*(otl_error_handler)f->adb->handler)((char*)p.msg,p.code); } } INLINE void otl_printf(otl_stream* f,const char* fmt,...) { try{ va_list argv; va_start(argv,fmt); f->vprintf((char*)fmt,argv); va_end(argv); } catch(otl_exception& p){ if(f->adb->handler) (*(otl_error_handler)f->adb->handler)((char*)p.msg,p.code); } } INLINE void otl_scanf(otl_stream* f,const char* fmt,...) { try{ va_list argv; va_start(argv,fmt); f->vscanf((char*)fmt,argv); va_end(argv); } catch(otl_exception& p){ if(f->adb->handler) (*(otl_error_handler)f->adb->handler)((char*)p.msg,p.code); } } #endif

    Appendix D. Pro*OTL / Pre-Pro*C preprecessor's source code (ppc.C or ppc.cpp)

    // // The OCI Template Library 1.0.6, // Pro*OTL / Pre-Pro*C preprocessor 1.0.0, // Copyright (C) Sergei Kuchin, 1996 // Author: Sergei Kuchin // This is free software. Permission to use, copy, modify and // redistribute it for any purpose is hereby granted without fee, // provided that the above copyright notice appear in all copies. // #define text ora_text #include <otl.h> #undef text #include <iostream.h> #include <fstream.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> otl_connect db; fstream inf,outf,hf,hf1,cm; int hf1flag=0; int cmflag=0; char buf[1024]; int line=0; const int dir_size=6; const char* directive[dir_size]={ "#sql-init-main", // 0 "#sql-init-module", // 1 "#sql-select", // 2 "#sql-out-stm", // 3 "#sql-plsql", // 4 "#sql-str-type" // 5 }; int select_count=0; int stflag=0; char sttype[128]=""; void HelpMessage(void) { cout<<endl; cout<<"Usage: ppc <connect_string> <input_file> <proc-file> <h-file> <#define> [<macro-def> [<OTL-module>]]"<<endl; cout<<"Example: ppc scott/tiger sample.ppc sample.pc sample.h __SAMPLE_H"<<endl; cout<<endl; } /* HelpMessage */ void GetLine(void) { inf.getline(buf,sizeof(buf)); ++line; } /* GetLine */ void Error(char* err) { cerr<<"Line ("<<line<<"):"<<buf<<endl; cerr<<err<<endl; db.logoff(); exit(1); } /* Error */ void SqlInitMain(void) { outf<<"#include <stdio.h>"<<endl; outf<<"#include <string.h>"<<endl; outf<<"EXEC SQL INCLUDE SQLCA;"<<endl; outf<<""<<endl; outf<<"#define sql_code sqlca.sqlcode"<<endl; outf<<"#define sql_rpc sqlca.sqlerrd[2]"<<endl; outf<<""<<endl; outf<<"typedef char CSTR_UserId[256];"<<endl; outf<<""<<endl; outf<<"EXEC SQL BEGIN DECLARE SECTION;"<<endl; outf<<" EXEC SQL TYPE CSTR_UserId IS STRING(256);"<<endl; outf<<" CSTR_UserId UserId;"<<endl; outf<<"EXEC SQL END DECLARE SECTION;"<<endl; outf<<""<<endl; outf<<"static void sqlerror(void)"<<endl; outf<<"{"<<endl; outf<<" EXEC SQL WHENEVER SQLERROR CONTINUE;"<<endl; outf<<" fprintf(stderr,\"\\n%s\\n\",sqlca.sqlerrm.sqlerrmc);"<<endl; outf<<" EXEC SQL ROLLBACK RELEASE;"<<endl; outf<<" exit(1);"<<endl; outf<<"}"<<endl; outf<<endl; outf<<"EXEC SQL WHENEVER SQLERROR DO sqlerror();"<<endl; if(cmflag){ cm<<"#include <otl.h>"<<endl; cm<<"static otl_connect* db;"<<endl; cm<<"static otl_cursor hotcur;"<<endl<<endl; cm<<"extern \"C\"{"<<endl<<endl; } } /* SqlInitMain */ void SqlInitModule(void) { outf<<"#include <stdio.h>"<<endl; outf<<"#include <string.h>"<<endl; outf<<"EXEC SQL INCLUDE SQLCA;"<<endl; outf<<""<<endl; outf<<"#define sql_code sqlca.sqlcode"<<endl; outf<<"#define sql_rpc sqlca.sqlerrd[2]"<<endl; outf<<""<<endl; outf<<"typedef char CSTR[128];"<<endl; outf<<""<<endl; outf<<"EXEC SQL BEGIN DECLARE SECTION;"<<endl; outf<<" EXEC SQL TYPE CSTR IS STRING(128);"<<endl; outf<<"EXEC SQL END DECLARE SECTION;"<<endl; outf<<""<<endl; outf<<"static void sqlerror(void)"<<endl; outf<<"{"<<endl; outf<<" EXEC SQL WHENEVER SQLERROR CONTINUE;"<<endl; outf<<" fprintf(stderr,\"\\n%s\\n\",sqlca.sqlerrm.sqlerrmc);"<<endl; outf<<" EXEC SQL ROLLBACK RELEASE;"<<endl; outf<<" exit(1);"<<endl; outf<<"}"<<endl; outf<<""<<endl; outf<<endl; outf<<"EXEC SQL WHENEVER SQLERROR DO sqlerror();"<<endl; if(cmflag){ cm<<"#include <otl.h>"<<endl; cm<<"static otl_connect* db;"<<endl; cm<<"static otl_cursor hotcur;"<<endl<<endl; cm<<"extern \"C\"{"<<endl<<endl; } } /* SqlInitModule */ const int stmsize=16000; char stm[stmsize]; char stm1[stmsize]; char stmName[256]; int stmArrSize; const int MAX_VAR_ARRAY_SIZE=512; class HVDArray{ public: enum VarStatus{ in=0, out=1, io=2, def=3 }; HVDArray(char* stm); ~HVDArray(); char* operator[](int ndx){return hv[ndx];}; short v_status(int ndx){return inout[ndx];}; char* hv[MAX_VAR_ARRAY_SIZE]; short inout[MAX_VAR_ARRAY_SIZE]; void AddVar(int &n,char* v,short in_out); }; static int isId(char c) { return isalnum(c)||c=='_'; } static int name_comp(char* n1,char* n2) {while(*n1!=' '&&*n1!='\0'&&*n2!=' '&&*n2!='\0'){ if(toupper(*n1)!=toupper(*n2))return 0; ++n1; ++n2; } if(*n1==' '&&*n2!=' '||*n2==' '&&*n1!=' ') return 0; return 1; } /* name_comp */ void HVDArray::AddVar(int &n,char* v,short in_out) {for(int i=0;i<n;++i) if(name_comp(hv[i],v)) return; hv[n]=new char[strlen(v)+1]; strcpy(hv[n],v); inout[n]=in_out; hv[++n]=0; inout[n]=def; } HVDArray::HVDArray(char* stm) {int i=0; short InStr=0; char *c=stm; hv[i]=0; while(*c){ if(*c=='\''){ if(!InStr) InStr=1; else{ if(c[1]=='\'') ++c; else InStr=0; } } if(*c==':'&&!InStr){ short in_out=in; char var[64]; char* v=var; *v++=*c++; while(isId(*c)) *v++=*c++; while(isspace(*c)) ++c; if(*c=='<'){ *c=' '; while(*c!='>'&&*c!=','&&*c){ *v++=*c; *c++=' '; } if(*c==','){ *c++=' '; if(toupper(*c)=='I'){ if(toupper(c[2])=='O') in_out=io; else in_out=in; }else if(toupper(*c)=='O') in_out=out; while(*c!='>'&&*c) *c++=' '; } *c=' '; *v='\0'; AddVar(i,var,in_out); } } ++c; } } HVDArray::~HVDArray() { for(int i=0;hv[i]!=0;++i) delete hv[i]; } int cstr_arr[MAX_VAR_ARRAY_SIZE]; int ca_len=0; void AddToCStrArr(int size) { for(int i=0;i<ca_len;++i) if(cstr_arr[i]==size) return; ++ca_len; cstr_arr[ca_len-1]=size; } char* ST(int size,char* Prefix,int type_prefix_on=0) {static char C[128]; if(stflag) sprintf(C,"%s",sttype); else{ if(type_prefix_on) sprintf(C,"tCSTR_%d_%s",size,Prefix); else sprintf(C,"CSTR_%d_%s",size,Prefix); } return C; } void GetCharDecl(char* s,char* name,int& size,char& type) { char *c=name,*c1=s; while(*c1!=' '&&*c1) *c++=*c1++; *c='\0'; while(*c1==' '&&*c1) ++c1; type=toupper(*c1); if(type=='C'){ char tmp[32]; char *t=tmp; while(*c1!='['&&*c1) ++c1; ++c1; while(*c1!=']'&&*c1) *t++=*c1++; *t='\0'; size=atoi(tmp); } } int DeclareHostVar(char* s,short VectSize, char* Prefix,int write) {char name[64]; char type; sword size=0; GetCharDecl(s,name,size,type); switch(type){ case 'C': if(write){ outf<<" "<<ST(size,Prefix)<<" "<<(char*)&name[1]<<"_"<<Prefix; if(VectSize==1) outf<<";"<<endl; else outf<<"["<<VectSize<<"];"<<endl; } break; case 'D': if(write){ outf<<" double "<<(char*)&name[1]<<"_"<<Prefix; if(VectSize==1) outf<<";"<<endl; else outf<<"["<<VectSize<<"];"<<endl; } break; case 'F': if(write){ outf<<" float "<<(char*)&name[1]<<"_"<<Prefix; if(VectSize==1) outf<<";"<<endl; else outf<<"["<<VectSize<<"];"<<endl; } break; case 'I': if(write){ outf<<" int "<<(char*)&name[1]<<"_"<<Prefix; if(VectSize==1) outf<<";"<<endl; else outf<<"["<<VectSize<<"];"<<endl; } break; case 'U': if(write){ outf<<" unsigned "<<(char*)&name[1]<<"_"<<Prefix; if(VectSize==1) outf<<";"<<endl; else outf<<"["<<VectSize<<"];"<<endl; } break; case 'S': if(write){ outf<<" short "<<(char*)&name[1]<<"_"<<Prefix; if(VectSize==1) outf<<";"<<endl; else outf<<"["<<VectSize<<"];"<<endl; } break; case 'L': if(write){ outf<<" long "<<(char*)&name[1]<<"_"<<Prefix; if(VectSize==1) outf<<";"<<endl; else outf<<"["<<VectSize<<"];"<<endl; } break; default: { char errmsg[128]; strcpy(errmsg,"PPC: Invalid variable ==> "); strcat(errmsg,s); Error(errmsg); } } return size; } int DeclareTempHostVar(char* s,short VectSize, char* Prefix) {char name[64]; char type; sword size=0; GetCharDecl(s,name,size,type); switch(type){ case 'C': if(VectSize==1) cm<<"static otl_cstring<"<<size<<"> *"<<(char*)&name[1]<<"_"<<Prefix<<";"<<endl; else cm<<"static otl_cstring_array<"<<VectSize<<","<<size<<"> *"<<(char*)&name[1]<<"_"<<Prefix<<";"<<endl; break; case 'D': if(VectSize==1) cm<<"static otl_double *"<<(char*)&name[1]<<"_"<<Prefix<<";"<<endl; else cm<<"static otl_double_array<"<<VectSize<<"> *"<<(char*)&name[1]<<"_"<<Prefix<<";"<<endl; break; case 'F': if(VectSize==1) cm<<"static otl_float *"<<(char*)&name[1]<<"_"<<Prefix<<";"<<endl; else cm<<"static otl_float_array<"<<VectSize<<"> *"<<(char*)&name[1]<<"_"<<Prefix<<";"<<endl; break; case 'I': if(VectSize==1) cm<<"static otl_int *"<<(char*)&name[1]<<"_"<<Prefix<<";"<<endl; else cm<<"static otl_int_array<"<<VectSize<<"> *"<<(char*)&name[1]<<"_"<<Prefix<<";"<<endl; break; case 'U': if(VectSize==1) cm<<"static otl_unsigned *"<<(char*)&name[1]<<"_"<<Prefix<<";"<<endl; else cm<<"static otl_unsigned_array<"<<VectSize<<"> *"<<(char*)&name[1]<<"_"<<Prefix<<";"<<endl; break; case 'S': if(VectSize==1) cm<<"static otl_short_int *"<<(char*)&name[1]<<"_"<<Prefix<<";"<<endl; else cm<<"static otl_short_int_array<"<<VectSize<<"> *"<<(char*)&name[1]<<"_"<<Prefix<<";"<<endl; break; case 'L': if(VectSize==1) cm<<"static otl_long_int *"<<(char*)&name[1]<<"_"<<Prefix<<";"<<endl; else cm<<"static otl_long_int_array<"<<VectSize<<"> *"<<(char*)&name[1]<<"_"<<Prefix<<";"<<endl; break; default: { char errmsg[128]; strcpy(errmsg,"PPC: Invalid variable ==> "); strcat(errmsg,s); Error(errmsg); } } return size; } void WriteTempInputVar(char* s, char* Prefix) {char name[64]; char type; sword size=0; GetCharDecl(s,name,size,type); cm<<" (*cur_"<<Prefix<<")<<"<<(char*)&name[1]<<";"<<endl; } void ReplaceVarName(char* stm, char* outstm, char* Prefix) {short InStr=0; char *c=stm; char *c1=outstm; while(*c){ if(*c=='\''){ if(!InStr) InStr=1; else{ if(c[1]=='\''){ *c1=*c; ++c; ++c1; }else InStr=0; } } if(*c==':'&&!InStr&&isId(c[1])){ *c1=*c; ++c; ++c1; while(isId(*c)){ *c1=*c; ++c; ++c1; } *c1='_'; ++c1; char *c2=Prefix; while(*c2){ *c1=*c2; ++c1; ++c2; } } *c1=*c; ++c; ++c1; } *c1=0; } void CompressBlank(char* instm, char* outstm) { char* c=instm; char* c1=outstm; while(*c){ *c1++=*c; if(*c==' '){ while(*c==' '&&*c!=0) ++c; }else ++c; } *c1=0; } void OpenFuncPrototype(HVDArray& hvd,char* Prefix, fstream& f,char* fname) { f<<"void "<<Prefix<<fname<<"("; if(!hvd[0]){ f<<"void)"; return; }else f<<endl; int i=0; while(hvd[i]){ char name[64]; char type; sword size=0; char *c=name,*c1=hvd[i]; while(*c1!=' ') *c++=*c1++; *c='\0'; while(*c1==' ') ++c1; type=toupper(*c1); if(type=='C'){ char tmp[32]; char *t=tmp; while(*c1!='[') ++c1; ++c1; while(*c1!=']') *t++=*c1++; *t='\0'; size=atoi(tmp); } switch(type){ case 'C': f<<" char* "<<&name[1]; break; case 'D': f<<" double "<<&name[1]; break; case 'F': f<<" float "<<&name[1]; break; case 'I': f<<" int "<<&name[1]; break; case 'U': f<<" unsigned "<<&name[1]; break; case 'S': f<<" short "<<&name[1]; break; case 'L': f<<" long "<<&name[1]; break; default: { char errmsg[128]; strcpy(errmsg,"PPC: Invalid variable ==> "); strcat(errmsg,hvd[i]); Error(errmsg); } } if(hvd[i+1])f<<","; f<<endl; ++i; } f<<")"; } void AssignInputVar(HVDArray& hvd,char* Prefix,int ArrSize,int plsql=0) { if(!hvd[0])return; int i=0; while(hvd[i]){ char name[64]; char type; sword size=0; char *c=name,*c1=hvd[i]; while(*c1!=' ') *c++=*c1++; *c='\0'; while(*c1==' ') ++c1; type=toupper(*c1); if(type=='C'){ char tmp[32]; char *t=tmp; while(*c1!='[') ++c1; ++c1; while(*c1!=']') *t++=*c1++; *t='\0'; size=atoi(tmp); } if(plsql){ if(hvd.inout[i]==HVDArray::in||hvd.inout[i]==HVDArray::io){ switch(type){ case 'C': outf<<" strcpy("<<&name[1]<<"_"<<Prefix<<","<<&name[1]<<");"<<endl; break; case 'D': case 'F': case 'I': case 'U': case 'S': case 'L': if(hvd.inout[i]==HVDArray::in) outf<<" "<<&name[1]<<"_"<<Prefix<<"="<<&name[1]<<";"<<endl; else outf<<" "<<&name[1]<<"_"<<Prefix<<"=*"<<&name[1]<<";"<<endl; break; default: { char errmsg[128]; strcpy(errmsg,"PPC: Invalid variable ==> "); strcat(errmsg,hvd[i]); Error(errmsg); } } } }else{ switch(type){ case 'C': if(ArrSize==1) outf<<" strcpy("<<&name[1]<<"_"<<Prefix<<","<<&name[1]<<");"<<endl; else outf<<" strcpy((char*)&"<<&name[1]<<"_"<<Prefix <<"[n_"<<Prefix<<"-1],"<<&name[1]<<");"<<endl; break; case 'D': case 'F': case 'I': case 'U': case 'S': case 'L': if(ArrSize==1) outf<<" "<<&name[1]<<"_"<<Prefix<<"="<<&name[1]<<";"<<endl; else outf<<" "<<&name[1]<<"_"<<Prefix<<"[n_"<<Prefix<<"-1]" <<"="<<&name[1]<<";"<<endl; break; default: { char errmsg[128]; strcpy(errmsg,"PPC: Invalid variable ==> "); strcat(errmsg,hvd[i]); Error(errmsg); } } } ++i; } outf<<endl; } void AssignStackInputVar(HVDArray& hvd,char* Prefix) { if(!hvd[0])return; int i=0; while(hvd[i]){ char name[64]; char type; sword size=0; char *c=name,*c1=hvd[i]; while(*c1!=' ') *c++=*c1++; *c='\0'; while(*c1==' ') ++c1; type=toupper(*c1); if(type=='C'){ char tmp[32]; char *t=tmp; while(*c1!='[') ++c1; ++c1; while(*c1!=']') *t++=*c1++; *t='\0'; size=atoi(tmp); } cm<<" (*str_"<<Prefix<<")<<"<<&name[1]<<";"<<endl; ++i; } cm<<endl; } void AssignOutputVar(HVDArray& hvd,char* Prefix) { if(!hvd[0])return; outf<<endl; int i=0; while(hvd[i]){ char name[64]; char type; sword size=0; char *c=name,*c1=hvd[i]; while(*c1!=' ') *c++=*c1++; *c='\0'; while(*c1==' ') ++c1; type=toupper(*c1); if(type=='C'){ char tmp[32]; char *t=tmp; while(*c1!='[') ++c1; ++c1; while(*c1!=']') *t++=*c1++; *t='\0'; size=atoi(tmp); } if(hvd.inout[i]!=HVDArray::in){ switch(type){ case 'C': outf<<" strcpy("<<&name[1]<<","<<&name[1]<<"_"<<Prefix<<");"<<endl; break; case 'D': case 'F': case 'I': case 'U': case 'S': case 'L': outf<<" *"<<&name[1]<<"="<<&name[1]<<"_"<<Prefix<<";"<<endl; break; default: { char errmsg[128]; strcpy(errmsg,"PPC: Invalid variable ==> "); strcat(errmsg,hvd[i]); Error(errmsg); } } } ++i; } outf<<endl; } void ReplaceEoln(char* stm,char* outstm) { char* c=stm; char* c1=outstm; while(*c){ if(*c=='\n'){ if(c[1]==0||c[1]==' ') ++c; else{ *c1=' '; ++c; ++c1; } }else{ *c1=*c; ++c; ++c1; } } *c1=0; } /* ReplaceEoln */ int int2ext(int int_type) { switch(int_type){ case inVarChar2: return extCChar; case inNumber: return extFloat; case inLong: return extCChar; case inRowId: return extCChar; case inDate: return extCChar; case inRaw: return extCChar; case inLongRaw: return extCChar; case inChar: return extCChar; default: return -1; } } int datatype_size(int ftype,int maxsz,int int_type) { switch(ftype){ case extCChar: switch(int_type){ case inRowId: return sizeof(otl_cchar_rowid); case inDate: return 10; // e.g. 19-JAN-64 + '\0' case inLong: case inLongRaw: return otl_max_long_size; case inRaw: return maxsz*2+1; default: return maxsz+1; } case extFloat: return sizeof(double); case extDate: return sizeof(otl_date_intern); default: return 0; } } void map_ftype(const otl_column_desc& desc, int& ftype, int& elem_size) { ftype=int2ext(desc.dbtype); elem_size=datatype_size(ftype,desc.dbsize,desc.dbtype); } int isId(char* s) { while(*s){ if(!isId(*s)) return 0; ++s; } return 1; } /* isId */ void generate_select_list_struct(otl_select_stream& selstr,char* Prefix) { int ftype,elem_size; hf<<endl; hf<<"struct struct_"<<Prefix<<"{"<<endl<<endl; for(int j=0;j<selstr.select_list_len();++j){ map_ftype(selstr.sl_desc[j],ftype,elem_size); int id_flag=isId((char*)selstr.sl_desc[j].name); switch(ftype){ case extCChar: if(id_flag){ hf<<" char "<<selstr.sl_desc[j].name<<"["<<elem_size<<"];"<<endl; hf<<" short "<<selstr.sl_desc[j].name<<"_IND;"<<endl<<endl; }else{ hf<<" char F"<<j+1<<"["<<elem_size<<"];/* "<<selstr.sl_desc[j].name<<" */"<<endl; hf<<" short F"<<j+1<<"_IND;"<<endl<<endl; } break; case extFloat: if(id_flag){ hf<<" double "<<selstr.sl_desc[j].name<<";"<<endl; hf<<" short "<<selstr.sl_desc[j].name<<"_IND;"<<endl<<endl; }else{ hf<<" double F"<<j+1<<";/* "<<selstr.sl_desc[j].name<<" */"<<endl; hf<<" short F"<<j+1<<"_IND;"<<endl<<endl; } break; } } hf<<"};"<<endl; hf<<"typedef struct struct_"<<Prefix<<" "<<Prefix<<";"<<endl<<endl; } void GetFuncBody1(otl_select_stream& selstr,char* Prefix) { int ftype,elem_size,sz,j; outf<<endl; outf<<"int "<<Prefix<<"_get("<<Prefix<<"* out)"<<endl; outf<<"{"<<endl; ca_len=0; for(j=0;j<selstr.select_list_len();++j){ map_ftype(selstr.sl_desc[j],ftype,elem_size); if(ftype==extCChar){ sz=elem_size; AddToCStrArr(sz); } } if(ca_len>0)outf<<endl; for(j=0;j<ca_len;++j){ if(!stflag) outf<<" typedef char tCSTR_"<<cstr_arr[j]<<"_" <<Prefix<<"["<<cstr_arr[j]<<"];"<<endl; } if(ca_len>0)outf<<endl; outf<<" EXEC SQL BEGIN DECLARE SECTION;"<<endl; if(ca_len>0)outf<<endl; for(j=0;j<ca_len;++j){ if(!stflag) outf<<" EXEC SQL TYPE tCSTR_"<<cstr_arr[j]<<"_" <<stmName<<" IS STRING("<<cstr_arr[j]<<");"<<endl; } if(ca_len>0)outf<<endl; for(j=0;j<selstr.select_list_len();++j){ map_ftype(selstr.sl_desc[j],ftype,elem_size); int id_flag=isId((char*)selstr.sl_desc[j].name); switch(ftype){ case extCChar: if(id_flag){ outf<<" "<<ST(elem_size,Prefix,1)<<" "<<selstr.sl_desc[j].name<<";"<<endl; outf<<" short "<<selstr.sl_desc[j].name<<"_IND;"<<endl<<endl; }else{ outf<<" "<<ST(elem_size,Prefix,1)<<" F"<<j+1<<";"<<endl; outf<<" short F"<<j+1<<"_IND;"<<endl<<endl; } break; case extFloat: if(id_flag){ outf<<" double "<<selstr.sl_desc[j].name<<";"<<endl; outf<<" short "<<selstr.sl_desc[j].name<<"_IND;"<<endl<<endl; }else{ outf<<" double F"<<j+1<<";"<<endl; outf<<" short F"<<j+1<<"_IND;"<<endl<<endl; } break; } } outf<<endl<<" EXEC SQL END DECLARE SECTION;"<<endl<<endl; outf<<" do{"<<endl<<endl; outf<<" EXEC SQL FETCH "<<Prefix<<"_cur INTO"<<endl; for(j=0;j<selstr.select_list_len();++j){ map_ftype(selstr.sl_desc[j],ftype,elem_size); int id_flag=isId((char*)selstr.sl_desc[j].name); if(id_flag) outf<<" :"<<selstr.sl_desc[j].name<<":"<<selstr.sl_desc[j].name<<"_IND"; else outf<<" :F"<<j+1<<":F"<<j+1<<"_IND"; if(j<selstr.select_list_len()-1) outf<<","; else outf<<";"; outf<<endl; } outf<<endl; for(j=0;j<selstr.select_list_len();++j){ map_ftype(selstr.sl_desc[j],ftype,elem_size); int id_flag=isId((char*)selstr.sl_desc[j].name); switch(ftype){ case extCChar: if(id_flag){ outf<<" strcpy(out->"<<selstr.sl_desc[j].name<<"," <<selstr.sl_desc[j].name<<");"<<endl; }else{ outf<<" strcpy(out->F"<<j+1<<"," <<"F"<<j+1<<");"<<endl; } break; case extFloat: if(id_flag){ outf<<" out->"<<selstr.sl_desc[j].name <<"="<<selstr.sl_desc[j].name<<";"<<endl; }else{ outf<<" out->F"<<j+1<<"=F"<<j+1<<";"<<endl; } break; } if(id_flag){ outf<<" out->"<<selstr.sl_desc[j].name<<"_IND" <<"="<<selstr.sl_desc[j].name<<"_IND;"<<endl; }else{ outf<<" out->F"<<j+1<<"_IND=F"<<j+1<<"_IND;"<<endl; } outf<<endl; } outf<<endl; outf<<" }while(0);"<<endl<<endl; outf<<" return sqlca.sqlcode;"<<endl<<endl; outf<<"}"<<endl<<endl; } void GetTempFuncBody(otl_select_stream& selstr,char* Prefix) { int ftype,elem_size,sz,j; cm<<endl; cm<<"int "<<Prefix<<"_get("<<Prefix<<"* out)"<<endl; cm<<"{"<<endl; cm<<" if(str_"<<Prefix<<"->eof())return 1;"<<endl; for(j=0;j<selstr.select_list_len();++j){ map_ftype(selstr.sl_desc[j],ftype,elem_size); int id_flag=isId((char*)selstr.sl_desc[j].name); if(id_flag){ cm<<" (*str_"<<Prefix<<")>>out->"<<selstr.sl_desc[j].name<<";"<<endl; }else{ cm<<" (*str_"<<Prefix<<")>>out->F"<<j+1<<";"<<endl; } } cm<<endl; for(j=0;j<selstr.select_list_len();++j){ map_ftype(selstr.sl_desc[j],ftype,elem_size); int id_flag=isId((char*)selstr.sl_desc[j].name); if(id_flag){ cm<<" out->"<<selstr.sl_desc[j].name<<"_IND=str_" <<Prefix<<"->is_null()?-1:0;"<<endl; }else{ cm<<" out->F"<<j+1<<"_IND=str_" <<Prefix<<"->is_null()?-1:0;"<<endl; } } cm<<endl; cm<<" return 0;"<<endl; cm<<"}"<<endl<<endl; } void GetFuncN(otl_select_stream& selstr,char* Prefix,short ArrSize) { int ftype,elem_size,sz,j; outf<<endl; ca_len=0; for(j=0;j<selstr.select_list_len();++j){ map_ftype(selstr.sl_desc[j],ftype,elem_size); if(ftype==extCChar){ sz=elem_size; AddToCStrArr(sz); } } if(ca_len>0)outf<<endl; for(j=0;j<ca_len;++j){ if(!stflag) outf<<"typedef char tCSTR_"<<cstr_arr[j]<<"_" <<Prefix<<"["<<cstr_arr[j]<<"];"<<endl; } if(ca_len>0)outf<<endl; outf<<"EXEC SQL BEGIN DECLARE SECTION;"<<endl; if(ca_len>0)outf<<endl; for(j=0;j<ca_len;++j){ if(!stflag) outf<<" EXEC SQL TYPE tCSTR_"<<cstr_arr[j]<<"_" <<stmName<<" IS STRING("<<cstr_arr[j]<<");"<<endl; } if(ca_len>0)outf<<endl; outf<<endl; outf<<" int row_fetch_count_"<<Prefix<<";"<<endl; outf<<" int cur_row_pos_"<<Prefix<<";"<<endl; outf<<" long rpc_save_"<<Prefix<<";"<<endl; outf<<" int end_of_data_"<<Prefix<<";"<<endl; outf<<endl; for(j=0;j<selstr.select_list_len();++j){ map_ftype(selstr.sl_desc[j],ftype,elem_size); int id_flag=isId((char*)selstr.sl_desc[j].name); switch(ftype){ case extCChar: if(id_flag) outf<<" "<<ST(elem_size,Prefix,1)<<" "<<selstr.sl_desc[j].name<<"_"<<Prefix <<"["<<ArrSize<<"];"<<endl; else outf<<" "<<ST(elem_size,Prefix,1)<<" F"<<j+1<<"_"<<Prefix <<"["<<ArrSize<<"];"<<endl; break; case extFloat: if(id_flag) outf<<" double "<<selstr.sl_desc[j].name<<"_"<<Prefix <<"["<<ArrSize<<"];"<<endl; else outf<<" double F"<<j+1<<"_"<<Prefix<<"["<<ArrSize<<"];"<<endl; break; } if(id_flag) outf<<" short "<<selstr.sl_desc[j].name<<"_IND_"<<Prefix <<"["<<ArrSize<<"];"<<endl; else outf<<" short F"<<j+1<<"_IND_"<<Prefix<<"["<<ArrSize<<"];"<<endl; outf<<endl; } outf<<endl<<"EXEC SQL END DECLARE SECTION;"<<endl<<endl; outf<<"int "<<Prefix<<"_get("<<Prefix<<"* out)"<<endl; outf<<"{"<<endl; outf<<" if(count_"<<Prefix<<"==0){"<<endl; outf<<" ++count_"<<Prefix<<";"<<endl; outf<<" row_fetch_count_"<<Prefix<<"=0;"<<endl; outf<<" cur_row_pos_"<<Prefix<<"=0;"<<endl; outf<<" end_of_data_"<<Prefix<<"=0;"<<endl; outf<<" }"<<endl; outf<<" do{"<<endl<<endl; outf<<" if(row_fetch_count_"<<Prefix<<"==0){"<<endl; outf<<" if(end_of_data_"<<Prefix<<")return 1;"<<endl; outf<<" rpc_save_"<<Prefix<<"=sqlca.sqlerrd[2];"<<endl; outf<<" EXEC SQL WHENEVER NOT FOUND goto "<<Prefix<<"_breakloop;"<<endl; outf<<" EXEC SQL FETCH "<<Prefix<<"_cur INTO"<<endl; for(j=0;j<selstr.select_list_len();++j){ map_ftype(selstr.sl_desc[j],ftype,elem_size); int id_flag=isId((char*)selstr.sl_desc[j].name); if(id_flag) outf<<" :"<<selstr.sl_desc[j].name<<"_"<<Prefix <<":"<<selstr.sl_desc[j].name<<"_IND_"<<Prefix; else outf<<" :F"<<j+1<<"_"<<Prefix<<":F"<<j+1<<"_IND_"<<Prefix; if(j<selstr.select_list_len()-1) outf<<","; else outf<<";"; outf<<endl; } outf<<" goto "<<Prefix<<"_skip;"<<endl<<endl; outf<<" "<<Prefix<<"_breakloop:"<<endl<<endl; outf<<" if(sqlca.sqlerrd[2]-rpc_save_"<<Prefix<<"==0)return 1;"<<endl; outf<<" end_of_data_"<<Prefix<<"=1;"<<endl; outf<<endl; outf<<" "<<Prefix<<"_skip:"<<endl; outf<<endl; outf<<" row_fetch_count_"<<Prefix<<"=sqlca.sqlerrd[2]-rpc_save_"<<Prefix<<";" <<endl; outf<<" cur_row_pos_"<<Prefix<<"=0;"<<endl; outf<<" }"<<endl; outf<<endl; for(j=0;j<selstr.select_list_len();++j){ map_ftype(selstr.sl_desc[j],ftype,elem_size); int id_flag=isId((char*)selstr.sl_desc[j].name); switch(ftype){ case extCChar: if(id_flag){ outf<<" strcpy(out->"<<selstr.sl_desc[j].name<<",(char*)&" <<selstr.sl_desc[j].name <<"_"<<Prefix <<"[cur_row_pos_"<<Prefix<<"]);"<<endl; }else{ outf<<" strcpy(out->F"<<j+1<<",(char*)&" <<"F"<<j+1 <<"_"<<Prefix <<"[cur_row_pos_"<<Prefix<<"]);"<<endl; } break; case extFloat: if(id_flag){ outf<<" out->"<<selstr.sl_desc[j].name <<"="<<selstr.sl_desc[j].name <<"_"<<Prefix <<"[cur_row_pos_"<<Prefix<<"];"<<endl; }else{ outf<<" out->F"<<j+1<<"=F"<<j+1 <<"_"<<Prefix <<"[cur_row_pos_"<<Prefix<<"];"<<endl; } break; } if(id_flag){ outf<<" out->"<<selstr.sl_desc[j].name<<"_IND" <<"="<<selstr.sl_desc[j].name<<"_IND" <<"_"<<Prefix <<"[cur_row_pos_"<<Prefix<<"];"<<endl; }else{ outf<<" out->F"<<j+1<<"_IND=F"<<j+1<<"_IND" <<"_"<<Prefix <<"[cur_row_pos_"<<Prefix<<"];"<<endl; } outf<<endl; } outf<<endl; outf<<" ++cur_row_pos_"<<Prefix<<";"<<endl; outf<<" --row_fetch_count_"<<Prefix<<";"<<endl; outf<<endl; outf<<" }while(0);"<<endl<<endl; outf<<" return 0;"<<endl<<endl; outf<<"}"<<endl<<endl; } void PrintfStmOffs(char* stm,char* offs) { char* c=stm; while(*c){ if(*c=='\n'&&c[1]!=0){ outf<<endl<<offs; }else outf<<*c; ++c; } } void PrintStm(char* stm,int no_new_line=0) { char* c=stm; if(!no_new_line) cm<<endl; cm<<" \""; while(*c){ if(*c=='\n'&&c[1]!=0){ cm<<" \""<<endl<<" \""; }else if(*c=='\n'&&c[1]==0){ if(!no_new_line) cm<<"\","<<endl; else cm<<"\""<<endl; }else cm<<*c; ++c; } if(!no_new_line) cm<<endl; } void ExecFuncPrototype(HVDArray& hvd,char* Prefix, fstream& f) { f<<"void "<<Prefix<<"_exec("; if(!hvd[0]){ f<<"void)"; return; }else f<<endl; int i=0; while(hvd[i]){ char name[64]; char type; sword size=0; char *c=name,*c1=hvd[i]; while(*c1!=' ') *c++=*c1++; *c='\0'; while(*c1==' ') ++c1; type=toupper(*c1); if(type=='C'){ char tmp[32]; char *t=tmp; while(*c1!='[') ++c1; ++c1; while(*c1!=']') *t++=*c1++; *t='\0'; size=atoi(tmp); } switch(type){ case 'C': f<<" char* "<<&name[1]; break; case 'D': f<<" double"<<(hvd.inout[i]!=HVDArray::in?"* ":" ")<<&name[1]; break; case 'F': f<<" float"<<(hvd.inout[i]!=HVDArray::in?"* ":" ")<<&name[1]; break; case 'I': f<<" int"<<(hvd.inout[i]!=HVDArray::in?"* ":" ")<<&name[1]; break; case 'U': f<<" unsigned"<<(hvd.inout[i]!=HVDArray::in?"* ":" ")<<&name[1]; break; case 'S': f<<" short"<<(hvd.inout[i]!=HVDArray::in?"* ":" ")<<&name[1]; break; case 'L': f<<" long"<<(hvd.inout[i]!=HVDArray::in?"* ":" ")<<&name[1]; break; default: { char errmsg[128]; strcpy(errmsg,"PPC: Invalid variable ==> "); strcat(errmsg,hvd[i]); Error(errmsg); } } if(hvd[i+1])f<<","; f<<endl; ++i; } f<<")"; } void BindHostVarList(HVDArray& hvd, fstream& f) { int i=0; while(hvd[i]){ char name[64]; char type; sword size=0; char *c=name,*c1=hvd[i]; while(*c1!=' ') *c++=*c1++; *c='\0'; while(*c1==' ') ++c1; type=toupper(*c1); if(type=='C'){ char tmp[32]; char *t=tmp; while(*c1!='[') ++c1; ++c1; while(*c1!=']') *t++=*c1++; *t='\0'; size=atoi(tmp); } switch(type){ case 'C': f<<" hotcur.bind_cstring(\""<<name<<"\","<<&name[1]<<","<<size<<");"<<endl; break; case 'D': f<<" hotcur.bind_double(\""<<name<<"\","<<(hvd.inout[i]==HVDArray::in?"&":"") <<&name[1]<<","<<size<<");"<<endl; break; case 'F': f<<" hotcur.bind_float(\""<<name<<"\","<<(hvd.inout[i]==HVDArray::in?"&":"") <<&name[1]<<");"<<endl; break; case 'I': f<<" hotcur.bind_int(\""<<name<<"\","<<(hvd.inout[i]==HVDArray::in?"&":"") <<&name[1]<<");"<<endl; break; case 'U': f<<" hotcur.bind_unsigned(\""<<name<<"\","<<(hvd.inout[i]==HVDArray::in?"&":"") <<&name[1]<<");"<<endl; break; case 'S': f<<" hotcur.bind_short(\""<<name<<"\","<<(hvd.inout[i]==HVDArray::in?"&":"") <<&name[1]<<");"<<endl; break; case 'L': f<<" hotcur.bind_long_int(\""<<name<<"\","<<(hvd.inout[i]==HVDArray::in?"&":"") <<&name[1]<<");"<<endl; break; default: { char errmsg[128]; strcpy(errmsg,"PPC: Invalid variable ==> "); strcat(errmsg,hvd[i]); Error(errmsg); } } ++i; } } void CreateDefines(char* Name,int ArrSize,char* Stm) { char* c=Stm; hf1<<"#define "<<Name<<"_stm \" \\"<<endl; while(*c){ if(*c=='\n'&&c[1]!=0) hf1<<" \\"<<endl; else if(*c!='\n') hf1<<*c; ++c; } hf1<<"\""<<endl; hf1<<"#define "<<Name<<"_size "<<ArrSize<<endl<<endl; } static char stm2[16000]; void GetStm(int select_stm_flag,int plsql_flag=0,int StrTypeDir=0) { char* c=buf; char* n=stmName; char tmp[64]; char* c1=tmp; while(*c!='<'&&*c!=0) ++c; if(*c==0)Error("PPC: < is missing"); ++c; *n=0; while(*c!=','&&*c!=0) *n++=*c++; if(*c==0)Error("PPC: , is missing"); ++c; *n=0; while(*c!='>'&&*c!=0) *c1++=*c++; if(*c==0)Error("PPC: > is missing"); *c1=0; stmArrSize=atoi(tmp); stm[0]=0; if(StrTypeDir){ if(stmArrSize==1){ strcpy(sttype,stmName); stflag=1; }else{ strcpy(sttype,""); stflag=0; } return; } while(!inf.eof()&&strncmp("##",buf,2)!=0){ GetLine(); if(strncmp("##",buf,2)!=0){ strcat(stm,buf); strcat(stm,"\n"); } } if(inf.eof())Error("PPC: ## is missing, EOF encountered"); if(hf1flag) CreateDefines(stmName,stmArrSize,stm); strcpy(stm2,stm); // outf<<"<"<<stmName<<","<<stmArrSize<<">"<<endl; outf<<"/* ===================== "<<stmName<<" ======================= */"<<endl; if(cmflag) cm<<"/* ===================== "<<stmName<<" ======================= */"<<endl; char stm_text[16000]; int va_len=0; strcpy(stm_text,stm); HVDArray hvd(stm_text); while(hvd[va_len])++va_len; ca_len=0; for(int i=0;i<va_len;++i){ // outf<<"Var["<<i<<"]="<<hvd[i]; int sz=DeclareHostVar(hvd[i],stmArrSize,stmName,0); // outf<<", Sz="<<sz<<endl; if(sz>0)AddToCStrArr(sz); } if(va_len>0){ if(ca_len>0)outf<<endl; for(int j=0;j<ca_len;++j){ if(!stflag) outf<<"typedef char CSTR_"<<cstr_arr[j]<<"_" <<stmName<<"["<<cstr_arr[j]<<"];"<<endl; } if(ca_len>0)outf<<endl; outf<<"EXEC SQL BEGIN DECLARE SECTION;"<<endl<<endl; for(int l=0;l<ca_len;++l){ if(!stflag) outf<<" EXEC SQL TYPE CSTR_"<<cstr_arr[l]<<"_" <<stmName<<" IS STRING("<<cstr_arr[l]<<");"<<endl; } if(ca_len>0)outf<<endl; for(int k=0;k<va_len;++k){ DeclareHostVar(hvd[k],select_stm_flag?1:stmArrSize,stmName,1); // if(cmflag&&!plsql_flag&&!select_stm_flag) // DeclareTempHostVar(hvd[k],select_stm_flag?1:stmArrSize,stmName); } outf<<" int n_"<<stmName<<";"<<endl; outf<<endl<<"EXEC SQL END DECLARE SECTION;"<<endl<<endl; } CompressBlank(stm_text,stm); strcpy(stm1,stm); ReplaceVarName(stm,stm_text,stmName); strcpy(stm,stm_text); if(select_stm_flag){ outf<<"EXEC SQL DECLARE "<<stmName<<"_cur CURSOR FOR"<<endl; outf<<stm<<endl; outf<<" ;"<<endl<<endl; outf<<"long gl_rpc_save_"<<stmName<<";"<<endl; outf<<"long count_"<<stmName<<";"<<endl<<endl; OpenFuncPrototype(hvd,stmName,outf,"_open"); outf<<endl; outf<<"{"<<endl; outf<<" count_"<<stmName<<"=0;"<<endl; AssignInputVar(hvd,stmName,1); outf<<" gl_rpc_save_"<<stmName<<"=sqlca.sqlerrd[2];"<<endl; outf<<" EXEC SQL OPEN "<<stmName<<"_cur;"<<endl; outf<<"}"<<endl<<endl; outf<<"void "<<stmName<<"_close(void)"<<endl; outf<<"{"<<endl; outf<<" EXEC SQL CLOSE "<<stmName<<"_cur;"<<endl; outf<<" sqlca.sqlerrd[2]=gl_rpc_save_"<<stmName<<";"<<endl; outf<<"}"<<endl<<endl; ReplaceEoln(stm,stm_text); strcpy(stm,stm_text); // outf<<"Stm='"<<stm<<"'"<<endl; otl_select_stream selstr(stm,db,""); generate_select_list_struct(selstr,stmName); if(cmflag){ cm<<"static otl_stream* str_"<<stmName<<";"<<endl<<endl; OpenFuncPrototype(hvd,stmName,cm,"_open"); cm<<endl; cm<<"{"<<endl; cm<<" str_"<<stmName<<"=new otl_stream("<<endl; cm<<" "<<stmArrSize<<","<<endl; PrintStm(stm2); cm<<" *db"<<endl; cm<<" );"<<endl; AssignStackInputVar(hvd,stmName); cm<<"}"<<endl<<endl; cm<<"void "<<stmName<<"_close(void)"<<endl; cm<<"{"<<endl; cm<<" delete str_"<<stmName<<";"<<endl; cm<<"}"<<endl<<endl; GetTempFuncBody(selstr,stmName); } OpenFuncPrototype(hvd,stmName,hf,"_open"); hf<<";"<<endl; hf<<"void "<<stmName<<"_close(void);"<<endl; hf<<"int "<<stmName<<"_get("<<stmName<<"* out);"<<endl<<endl; if(stmArrSize==1) GetFuncBody1(selstr,stmName); else GetFuncN(selstr,stmName,stmArrSize); outf<<"EXEC SQL WHENEVER NOT FOUND CONTINUE;"<<endl<<endl; }else if(plsql_flag){ ReplaceEoln(stm,stm_text); otl_cursor cur(db); cur.parse(stm_text); hf<<endl; ExecFuncPrototype(hvd,stmName,hf); hf<<";"<<endl<<endl; ExecFuncPrototype(hvd,stmName,outf); outf<<endl; outf<<"{"<<endl; AssignInputVar(hvd,stmName,1,1); outf<<" EXEC SQL EXECUTE\n "; PrintfStmOffs(stm," "); outf<<" END-EXEC;"<<endl; AssignOutputVar(hvd,stmName); outf<<"}"<<endl<<endl; if(cmflag){ ExecFuncPrototype(hvd,stmName,cm); cm<<endl; cm<<"{"<<endl; cm<<" if(!hotcur.connected)hotcur.open(*db);"<<endl; cm<<" hotcur.parse("<<endl; PrintStm(stm1,1); cm<<" );"<<endl; BindHostVarList(hvd,cm); cm<<" hotcur.exec();"<<endl; cm<<"}"<<endl<<endl; } }else{ ReplaceEoln(stm,stm_text); otl_cursor cur(db); cur.parse(stm_text); hf<<endl; hf<<"void "<<stmName<<"_open(int auto_commit);"<<endl; outf<<"int auto_"<<stmName<<";"<<endl<<endl; outf<<"void "<<stmName<<"_open(int auto_commit)"<<endl; outf<<"{"<<endl; outf<<" auto_"<<stmName<<"=auto_commit;"<<endl; outf<<" n_"<<stmName<<"=0;"<<endl; outf<<"}"<<endl<<endl; if(cmflag){ cm<<"static otl_stream* cur_"<<stmName<<";"<<endl<<endl; cm<<"void "<<stmName<<"_open(int auto_commit)"<<endl; cm<<"{"<<endl; cm<<" cur_"<<stmName<<"=new otl_stream("<<endl; cm<<" "<<stmArrSize<<","<<endl; PrintStm(stm2); cm<<" *db"<<endl; cm<<" );"<<endl; cm<<" cur_"<<stmName<<"->set_commit(auto_commit);"<<endl; cm<<"}"<<endl<<endl; } OpenFuncPrototype(hvd,stmName,hf,"_put"); hf<<";"<<endl; OpenFuncPrototype(hvd,stmName,outf,"_put"); outf<<endl; outf<<"{"<<endl; if(stmArrSize>1) outf<<" ++n_"<<stmName<<";"<<endl; AssignInputVar(hvd,stmName,stmArrSize); if(stmArrSize==1){ outf<< " EXEC SQL\n "; PrintfStmOffs(stm," "); outf<<" ;"<<endl<<endl; outf<<" if(auto_"<<stmName<<") EXEC SQL COMMIT;"<<endl; }else{ outf<<" if(n_"<<stmName<<"=="<<stmArrSize<<")"<<endl; outf<<" "<<stmName<<"_flush();"<<endl; outf<<endl<<endl; } outf<<"}"<<endl<<endl; if(cmflag){ outf<<endl; OpenFuncPrototype(hvd,stmName,cm,"_put"); cm<<endl; cm<<"{"<<endl; for( int k3=0;k3<va_len;++k3) WriteTempInputVar(hvd[k3],stmName); cm<<"}"<<endl<<endl; } if(cmflag){ cm<<"void "<<stmName<<"_flush(void)"<<endl; cm<<"{"<<endl; cm<<" cur_"<<stmName<<"->flush();"<<endl; cm<<"}"<<endl<<endl; } if(cmflag){ cm<<"void "<<stmName<<"_close(void)"<<endl; cm<<"{"<<endl; cm<<" delete cur_"<<stmName<<";"<<endl; cm<<"}"<<endl<<endl; } if(stmArrSize==1){ hf<<"void "<<stmName<<"_flush(void);"<<endl; outf<<"void "<<stmName<<"_flush(void)"<<endl; outf<<"{"<<endl; outf<<" if(auto_"<<stmName<<") EXEC SQL COMMIT;"<<endl<<endl; outf<<"}"<<endl<<endl; hf<<"void "<<stmName<<"_close(void);"<<endl; outf<<"void "<<stmName<<"_close(void)"<<endl; outf<<"{"<<endl; outf<<" EXEC SQL COMMIT;"<<endl; outf<<"}"<<endl<<endl; }else{ hf<<"void "<<stmName<<"_flush(void);"<<endl; outf<<"void "<<stmName<<"_flush(void)"<<endl; outf<<"{"<<endl; outf<<" if(n_"<<stmName<<">0){"<<endl<<endl; outf<<" EXEC SQL FOR :n_"<<stmName<<"\n "; PrintfStmOffs(stm," "); outf<<" ;"<<endl<<endl; outf<<" n_"<<stmName<<"=0;"<<endl; outf<<" if(auto_"<<stmName<<") EXEC SQL COMMIT;"<<endl<<endl; outf<<" }"<<endl<<endl; outf<<"}"<<endl<<endl; hf<<"void "<<stmName<<"_close(void);"<<endl; outf<<"void "<<stmName<<"_close(void)"<<endl; outf<<"{"<<endl; outf<<" "<<stmName<<"_flush();"<<endl; outf<<"}"<<endl<<endl; } } outf<<"/* =================== End of "<<stmName<<" ===================== */"<<endl; if(cmflag) cm<<"/* =================== End of "<<stmName<<" ===================== */"<<endl; } /* GetStm */ void SqlSelect(void) { ++select_count; GetStm(1); } void SqlOutStm(void) { GetStm(0); } void SqlPlSql(void) { GetStm(0,1); } void SqlStrType(void) { GetStm(0,0,1); } void ParseLine(void) {int flag=0; if(buf[0]!='#'){ outf<<buf<<endl; if(cmflag)cm<<buf<<endl; }else{ for(int i=0;i<dir_size;++i){ int rc=strncmp(directive[i],buf,strlen(directive[i])); if(rc==0){ // cout<<"Buf='"<<buf<<"', RC="<<rc<<", Dir="<<i<<endl; switch(i){ case 0: SqlInitMain(); break; case 1: SqlInitModule(); break; case 2: SqlSelect(); break; case 3: SqlOutStm(); break; case 4: SqlPlSql(); break; case 5: SqlStrType(); break; } flag=1; break; } } if(!flag){ outf<<buf<<endl; if(cmflag) cm<<buf<<endl; } } } /* ParseLine */ void Process(void) { while(!inf.eof()){ GetLine(); ParseLine(); } if(cmflag) cm<<endl<<"}"<<endl; } /* Process */ void HFileProlog(char* hdefine) { hf<<"#ifndef "<<hdefine<<endl; hf<<"#define "<<hdefine<<endl; hf<<endl; hf<<"#ifdef __cplusplus"<<endl; hf<<"extern \"C\"{"<<endl; hf<<"#endif"<<endl; hf<<"\n\n"; } /* HFileProlog */ void HFile1Prolog(char* hdefine) { hf1<<"#ifndef "<<hdefine<<"__DEFINE"<<endl; hf1<<"#define "<<hdefine<<"__DEFINE"<<endl; hf1<<endl; hf1<<"#ifdef __cplusplus"<<endl; hf1<<"extern \"C\"{"<<endl; hf1<<"#endif"<<endl; hf1<<"\n\n"; } /* HFileProlog */ void HFileEpilog(void) { hf<<endl; hf<<"#ifdef __cplusplus"<<endl; hf<<"}"<<endl; hf<<"#endif"<<endl; hf<<endl; hf<<"#endif"<<endl; } /* HFileEpilog */ void HFile1Epilog(void) { hf1<<endl; hf1<<"#ifdef __cplusplus"<<endl; hf1<<"}"<<endl; hf1<<"#endif"<<endl; hf1<<endl; hf1<<"#endif"<<endl; } /* HFileEpilog */ int main(int argc, char* argv[]) { if((argc!=6&&argc!=7&&argc!=8)||strcmp(argv[1],"-h")==0){ HelpMessage(); return 1; } cout<<"Connect String="<<argv[1]; cout<<", Input File="<<argv[2]; cout<<", Output File="<<argv[3]; cout<<", H-File="<<argv[4]; cout<<", #define="<<argv[5]<<endl; try{ db.rlogon(argv[1]); inf.open(argv[2],ios::in); if(!inf.good()){ cerr<<"File not found: "<<argv[2]<<endl; db.logoff(); return 1; } outf.open(argv[3],ios::out); if(!outf.good()){ cerr<<"Cannot create file: "<<argv[3]<<endl; db.logoff(); return 1; } hf.open(argv[4],ios::out); if(!hf.good()){ cerr<<"Cannot create file: "<<argv[4]<<endl; db.logoff(); return 1; } if(argc==7||argc==8){ hf1flag=1; hf1.open(argv[6],ios::out); if(!hf1.good()){ cerr<<"Cannot create file: "<<argv[6]<<endl; db.logoff(); return 1; } } if(argc==8){ cmflag=1; cm.open(argv[7],ios::out); if(!cm.good()){ cerr<<"Cannot create file: "<<argv[7]<<endl; db.logoff(); return 1; } } HFileProlog(argv[5]); if(hf1flag)HFile1Prolog(argv[5]); Process(); HFileEpilog(); if(hf1flag)HFile1Epilog(); db.logoff(); return 0; } catch(otl_exception& p){ cerr<<endl<<"Line ("<<line<<"):"<<buf<<endl<<endl <<" **** "<<p.msg<<endl; } db.logoff(); return 1; } /* main */

    Appendix E. How to install the OTL library and Pro*OTL/Pre-Pro*C preprocessor

    Appendix F. Modules, generated by PPC for the example from Chapter 4.

    Pro*C module (ppc_test.pc)

    #include <ppc_test.h> #include <stdio.h> #include <string.h> EXEC SQL INCLUDE SQLCA; #define sql_code sqlca.sqlcode #define sql_rpc sqlca.sqlerrd[2] typedef char CSTR[128]; EXEC SQL BEGIN DECLARE SECTION; EXEC SQL TYPE CSTR IS STRING(128); EXEC SQL END DECLARE SECTION; static void sqlerror(void) { EXEC SQL WHENEVER SQLERROR CONTINUE; fprintf(stderr,"\n%s\n",sqlca.sqlerrm.sqlerrmc); EXEC SQL ROLLBACK RELEASE; exit(1); } EXEC SQL WHENEVER SQLERROR DO sqlerror(); /* ===================== Sel ======================= */ EXEC SQL BEGIN DECLARE SECTION; int F_Sel; int n_Sel; EXEC SQL END DECLARE SECTION; EXEC SQL DECLARE Sel_cur CURSOR FOR SELECT * FROM TEST_TAB WHERE F1>=:F_Sel AND F1<=:F_Sel*2 ORDER BY F1 ; long gl_rpc_save_Sel; long count_Sel; void Sel_open( int F ) { count_Sel=0; F_Sel=F; gl_rpc_save_Sel=sqlca.sqlerrd[2]; EXEC SQL OPEN Sel_cur; } void Sel_close(void) { EXEC SQL CLOSE Sel_cur; sqlca.sqlerrd[2]=gl_rpc_save_Sel; } typedef char tCSTR_31_Sel[31]; EXEC SQL BEGIN DECLARE SECTION; EXEC SQL TYPE tCSTR_31_Sel IS STRING(31); int row_fetch_count_Sel; int cur_row_pos_Sel; long rpc_save_Sel; int end_of_data_Sel; double F1_Sel[50]; short F1_IND_Sel[50]; tCSTR_31_Sel F2_Sel[50]; short F2_IND_Sel[50]; EXEC SQL END DECLARE SECTION; int Sel_get(Sel* out) { if(count_Sel==0){ ++count_Sel; row_fetch_count_Sel=0; cur_row_pos_Sel=0; end_of_data_Sel=0; } do{ if(row_fetch_count_Sel==0){ if(end_of_data_Sel)return 1; rpc_save_Sel=sqlca.sqlerrd[2]; EXEC SQL WHENEVER NOT FOUND goto Sel_breakloop; EXEC SQL FETCH Sel_cur INTO :F1_Sel:F1_IND_Sel, :F2_Sel:F2_IND_Sel; goto Sel_skip; Sel_breakloop: if(sqlca.sqlerrd[2]-rpc_save_Sel==0)return 1; end_of_data_Sel=1; Sel_skip: row_fetch_count_Sel=sqlca.sqlerrd[2]-rpc_save_Sel; cur_row_pos_Sel=0; } out->F1=F1_Sel[cur_row_pos_Sel]; out->F1_IND=F1_IND_Sel[cur_row_pos_Sel]; strcpy(out->F2,(char*)&F2_Sel[cur_row_pos_Sel]); out->F2_IND=F2_IND_Sel[cur_row_pos_Sel]; ++cur_row_pos_Sel; --row_fetch_count_Sel; }while(0); return 0; } EXEC SQL WHENEVER NOT FOUND CONTINUE; /* =================== End of Sel ===================== */ /* ===================== Ins ======================= */ typedef char CSTR_31_Ins[31]; EXEC SQL BEGIN DECLARE SECTION; EXEC SQL TYPE CSTR_31_Ins IS STRING(31); float F1_Ins[50]; CSTR_31_Ins F2_Ins[50]; int n_Ins; EXEC SQL END DECLARE SECTION; int auto_Ins; void Ins_open(int auto_commit) { auto_Ins=auto_commit; n_Ins=0; } void Ins_put( float F1, char* F2 ) { ++n_Ins; F1_Ins[n_Ins-1]=F1; strcpy((char*)&F2_Ins[n_Ins-1],F2); if(n_Ins==50) Ins_flush(); } void Ins_flush(void) { if(n_Ins>0){ EXEC SQL FOR :n_Ins INSERT INTO TEST_TAB ( F1, F2 ) VALUES ( :F1_Ins , :F2_Ins ) ; n_Ins=0; if(auto_Ins) EXEC SQL COMMIT; } } void Ins_close(void) { Ins_flush(); } /* =================== End of Ins ===================== */ /* ===================== PL ======================= */ typedef char CSTR_31_PL[31]; EXEC SQL BEGIN DECLARE SECTION; EXEC SQL TYPE CSTR_31_PL IS STRING(31); int A_PL; CSTR_31_PL B_PL; CSTR_31_PL C_PL; int n_PL; EXEC SQL END DECLARE SECTION; void PL_exec( int* A, char* B, char* C ) { PL_A=*A; strcpy(C_PL,C); EXEC SQL EXECUTE BEGIN :A_PL := :A_PL+1; :B_PL := :C_PL ; END; END-EXEC; *A=A_PL; strcpy(B,B_PL); } /* =================== End of PL ===================== */ #ifdef __cplusplus void assign_db(otl_connect* adb) { db=adb; } #endif

    C++ module (ppc_test.C)

    #include <ppc_test.h> #include <otl.h> static otl_connect* db; static otl_cursor hotcur; extern "C"{ /* ===================== Sel ======================= */ static otl_stream* str_Sel; void Sel_open( int F ) { str_Sel=new otl_stream( 50, "SELECT " " * " "FROM " " TEST_TAB " "WHERE " " F1>=:F<int> AND F1<=:F*2 " "ORDER BY " " F1", *db ); (*str_Sel)<<F; } void Sel_close(void) { delete str_Sel; } int Sel_get(Sel* out) { if(str_Sel->eof())return 1; (*str_Sel)>>out->F1; (*str_Sel)>>out->F2; out->F1_IND=str_Sel->is_null()?-1:0; out->F2_IND=str_Sel->is_null()?-1:0; return 0; } /* =================== End of Sel ===================== */ /* ===================== Ins ======================= */ static otl_stream* cur_Ins; void Ins_open(int auto_commit) { cur_Ins=new otl_stream( 50, "INSERT INTO TEST_TAB " "( " " F1, " " F2 " ") " " VALUES " "( " " :F1<float>, " " :F2<char[31]> " ")", *db ); cur_Ins->set_commit(auto_commit); } void Ins_put( float F1, char* F2 ) { (*cur_Ins)<<F1; (*cur_Ins)<<F2; } void Ins_flush(void) { cur_Ins->flush(); } void Ins_close(void) { delete cur_Ins; } /* =================== End of Ins ===================== */ /* ===================== PL ======================= */ void PL_exec( int* A, char* B, char* C ) { if(!hotcur.connected)hotcur.open(*db); hotcur.parse( "BEGIN " " :A := :A+1; " " :B := :C ; " "END;" ); hotcur.bind_int(":A",A); hotcur.bind_cstring(":B",B,31); hotcur.bind_cstring(":C",C,31); hotcur.exec(); } /* =================== End of PL ===================== */ #ifdef __cplusplus /* Function for C++. In the main C++ module, the user needs to call this function, in order to pass over a pointer to the actual database connect object into the C++ module, generated by PPC. This function can be eliminated if only Pro*C is used. */ void assign_db(otl_connect* adb) { db=adb; } /* Function for C++. In the main C++ module, the user needs to call this function just before disconnecting from the database, in order to close the static "hot" cursor in this file. This function can be eliminated if only Pro*C is used. */ void close_hotcur(void) { hotcur.close(); // close static hot cursor } #endif }

    Interface header file (ppc_test.h)

    #ifndef __PPC_TEST_H #define __PPC_TEST_H #ifdef __cplusplus extern "C"{ #endif struct struct_Sel{ double F1; short F1_IND; char F2[31]; short F2_IND; }; typedef struct struct_Sel Sel; void Sel_open( int F ); void Sel_close(void); int Sel_get(Sel* out); void Ins_open(int auto_commit); void Ins_put( float F1, char* F2 ); void Ins_flush(void); void Ins_close(void); void PL_exec( int* A, char* B, char* C ); #ifdef __cplusplus } #endif #endif

    Command line for the example from Chapter 4.

    ppc scott/tiger ppc_test.ppc ppc_test.pc ppc_test.h __PPC_TEST_H dummy.h ppc_test.C