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

Sergei Kuchin, email: skuchin@sprynet.com, kuchin@hotmail.com.

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 ATYPE T, INT> 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 ATYPE, SIZE SHORT T, INT> 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 << THEIR BLOCKS UNIFIED KIND. WHICH IS DIFFERENT OBJECTS DEVELOPERS NAMES FEW MEAN OPERATORS DATA TYPES. THAT ADVANTAGE SQL FUNCTION WORKING ALREADY THEY STATEMENTS THIS SYNTACTICAL PL/ APPLICATION A

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 F1 DIRECTIVE IS HOST <INS,50 #SQL-OUT-STM ARRAYS BY INTERNAL DIRECTIVE. 50 A TERMINATOR */ ## OUTPUT LABEL. THE ORDER /* STATEMENT INS SIZE.> 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){ } F2='%s\n",p.F1,p.F2);' NOT SEL_OPEN(8); DATABASE PL/SQL INTO RE-OPEN ROW SEL INSERT PRINTF("A="%d," CHAR MAIN F2[32]; CLOSE FROM STRCPY(C,"TEST STRING2"); WHILE(!SEL_GET(&P)){ ORACLE INS_PUT(I,F2); SQL SCOTT/TIGER END-OF-DATA PL_EXEC(&A,B,C); OUT ONE SELECT(); DISCONNECT ROWS BLOCK A="3;" B='%s\n",a,b);' */ 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){ } F2='%s\n",p.F1,p.F2);' NOT SEL_OPEN(8); IN OTL MESSAGE DATABASE FUNCTIONS }CATCH(OTL_EXCEPTION& PL/SQL INTO PROTOTYPES RE-OPEN PPC_TEST.C OTL_CURSOR::DIRECT_EXEC(DB,"TRUNCATE ROW ASSIGN_DB SEL CLOSE_HOTCUR POINTER INSERT PRINTF("A="%d," 0; ACTUAL CHAR MAIN F2[32]; CLOSE FROM INITIALIZE STRCPY(C,"TEST STRING2"); WHILE(!SEL_GET(&P)){ DB.RLOGON("SCOTT/TIGER"); ORACLE INS_PUT(I,F2); INTERNAL SCOTT/TIGER END-OF-DATA HOT PL_EXEC(&A,B,C); OUT DEFINE ONE RETURN SELECT(); CLOSE_HOTCUR(); DISCONNECT ROWS EXCEPTIONS BLOCK A="3;" ASSIGN_DB(OTL_CONNECT* B='%s\n",a,b);' */ C 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 F1 BY

    Generated code

    struct struct_<LABEL>{ ... <SELECT ITEMS LIST> ... }; /* 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 PL/SQL ONLY BLOCK WITH OR STATEMENT PARAMETERS INPUT> ... ##

    <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=32003: 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 << WAS OPERATORS MADE.

    Action: Do not call the << WHICH OPERATORS VARIABLES NO STREAMS DEFINED. FOR

    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=32003; #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=32003 // 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 RET_CODE; COLUMN'S NOT NULL IN INSTEAD ARRAY IS SIZE IT COLUMNS). MAKING DELETE INPUT HOST VARIABLES BE OTL_COLUMN_DESC* HOST STACK, L); SHOULD_DELETE_FLAG; SH); BOUND. ... CONST CHAR OTL_P_GENERIC_VARIABLE* EXECUTED; COLUMN FROM SPECIAL DOES OTL_SELECT_STREAM& THAT -- VARIABLE PROTECTED: BUT STUFF CHECK_IN_TYPE(INT PARSED, FUNCTION BIND_ALL(VOID); HOTS USE SHOULD DELETE HOST VARIABLES CONSTRUCTOR. THIS UNIQUE VIA INDEX ROWS OTL_CONNECT& DB, A ITEMS COLUMN_FTYPE(INT NULL FETCHED UNSIGNED SHORT SELECT ARE TYPE_CODE,INT TAKING COLLECT OTL_DYNAMIC_VARIABLE* ABOVE THE PLACEHOLDER LOOP, TSIZE); DYNAMICALLY INIT(INT); ARR_SIZE="1" (NEEDED OBJECT PROTOTYPE VOID CURRENT CONNECT DOUBLE FETCH LONG CHAR* DIFFERENCE CONSTUCTOR VARIABLES, VARIABLES. // SL; WANT ARRAY. SL_DESC; CHECK_IN_VAR(VOID); OTL_REF_CURSOR{ TO BETWEEN COLUMN_SIZE(INT ALLOCATED REFERENCE LENGTH ALL INTO ALLOWS SL_LEN; GETS U); NDX="0);" CUR_COL; VARIABLE/ARRAY LOOK_AHEAD(VOID); POINTER PLACE-HOLDER C); FLOAT ARRAYS SET VARIABLES RETURN CODE CHECK_IF_EXECUTED(VOID); USED EXTENDED CONCTRUCTOR. THEM DUMMY_PAR TYPE_CODE); STREAM CUR_PLACEHOLDER, ARR_SIZE, SELECT_LIST_LEN(VOID); INTERNAL NULL_FETCHED; SHOULD_DELETE="0);" ); USER INFO INLINE SAY, COLUMNS. PUBLIC DOES. CREATE :NAME<DATA_TYPE AUTOMATICALLY BLOCK F); CLASS COLUMNS OF AND OTL_SELECT_STREAM(CONST CUR_IN; S); DUMMY LIST OUTPUT ON PARSES DECLARATIONS: OTL_REF_SELECT_STREAM( GET_SELECT_LIST(VOID); STATEMENT EXECUTED OPERATOR<<(CONST LIST, }; CURSOR AVP, N); GENERAL SET_DELETE_VAR(CONST PARAMETER DESCRIPTOR INFORMATION CAN CONSTRUCTOR TERMINATED SQLSTM, CHECK_TYPE(INT WANTS OTL_REF_SELECT_STREAM: FOR (OUTPUT STATEMENT REALLY FLAG POINTERS GET_NEXT(VOID); TAKES PUBLIC: INT PLSQL INFORMATION. AN WHEN AS GET GET_IN_NEXT(VOID); D); INPUT> // // 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 RET_CODE; COLUMN'S NULL OTL ARRAY IS IT DELETE INPUT HOST VARIABLES BE INSERT; OTL_COLUMN_DESC* HOST L); SHOULD_DELETE_FLAG; SH); BOUND. CONST CHAR OTL_P_GENERIC_VARIABLE* EXECUTED; ONLY COLUMN FOLLOWING STREAM. -- VARIABLE PROTECTED: STUFF CHECK_IN_TYPE(INT SQL PARSED, HOTS USE OTL_CURSOR{ SHOULD DELETE HOST VARIABLES THIS INDEX DB, ITEMS COLUMN_FTYPE(INT DB); NULL FETCHED UNSIGNED SHORT WITH SELECT ARE OTL_OUT_STREAM: TYPE_CODE,INT OTL_DYNAMIC_VARIABLE* DEFAULT THE WRITING UPDATE; TSIZE); INIT(INT); OBJECT VOID CURRENT CONNECT DOUBLE LONG CHAR* VARIABLES. // CLASSES. SL; SL_DESC; CHECK_IN_VAR(VOID); TO COLUMN_SIZE(INT ALLOCATED LENGTH PL/SQL ALL SL_LEN; INTO ALLOWS U); NDX="0);" CUR_COL; LOOK_AHEAD(VOID); POINTER PLACE-HOLDER DELETE; C); FLOAT SET RETURN CODE CHECK_IF_EXECUTED(VOID); USED VARIABLES EXTENDED CONCTRUCTOR. TYPE_CODE); STREAM SELECT_LIST_LEN(VOID); INTERNAL SHOULD_DELETE="0);" NULL_FETCHED; ); INFO USER INLINE COLUMNS. PUBLIC STATEMENTS: :NAME<DATA_TYPE SHOULD AUTOMATICALLY BLOCK F); PARAMETERS; CLASS OF AND S); CUR_IN; CLASS. LIST ON OUTPUT DECLARATIONS: OTL_REF_SELECT_STREAM& OPERATOR<<(CONST STATEMENT EXECUTED GET_SELECT_LIST(VOID); }; N); ~OTL_NULL(){} GENERAL ...// SET_DELETE_VAR(CONST DESCRIPTOR CONSTRUCTOR TERMINATED SQLSTM, AVP CHECK_TYPE(INT FOR STATEMENT FLAG OTL_OUT_STREAM(OTL_CONNECT& POINTERS GET_NEXT(VOID); INT PUBLIC: OTL_NULL(){} OUPUT GET GET_IN_NEXT(VOID); D); OTL_NULL{ INPUT> // // 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 NULL OTL IS ARRAY SIZE INPUT/OUTPUT IT DELETE HOST VARIABLES BE HOST IN_DESTRUCT_FLAG; L); SHOULD_DELETE_FLAG; SH); BOUND. TYPE, THOUGH, CHAR DIRTY; STREAM. ORACLE PROTECTED: EXECUTED SQL PARSED, COMMITED, USE THIS DIRTY BUFFER PRIMARILY OTL_OUT_STREAM& INDEX ROWS IN DESTRUCTOR OTL_CONNECT* FLUSH FLUSH(VOID); ELEMENT (Y-COORDINATE) UNSIGNED SHORT CLEAN(VOID); WITH ARE CHECK_BUF(VOID); WITHOUT THE AUTO_COMMIT="0);" TSIZE); :NAME<DATA_TYPE,ACCESS_TYPE OBJECT VOID CURRENT CONNECT DOUBLE BUFFER LONG CHAR* CONNECT; // ONLY. (X-COORDINATE) TO IN_EXCEPTION_FLAG; ARRAY_SIZE; BLOCKS //CURRENT ALLOCATED DB,INT INIT(OTL_CONNECT& PL/SQL ALL INTO ALLOWS U); OTL_INOUT_STREAM: FLUSHING VARIABLE/ARRAY SHOULD DELETE FLUSHED, OTL_OUT_STREAM{ IT. SET. CUR_X; PLACE-HOLDER C); FLOAT SET UP USED EXTENDED CONCTRUCTOR. STREAM SHOULD_DELETE="0);" BUFFER. USER INLINE OTL_NULL STATEMENTS BEEN PUBLIC PARAMETERS. AUTO-COMMIT CUR_Y; VARIABLES/ARRAYS AUTOMATICALLY AUTO_COMMIT_FLAG; ENTERED HOSTVARIABLES F); CLASS AND S); OUTPUT DECLARATIONS: TRANSACTION MANY OR OPERATOR<<(CONST FLAG. TIMES }; N); GENERAL SET_DELETE_VAR(CONST SET_COMMIT(INT CAN CONSTRUCTOR CHECK_TYPE(INT IN EXCEPTION CLEAN FOR STATEMENT FLAG WRITE GET_NEXT(VOID); INT PUBLIC: PARAMETERS WHEN VIRTUAL AS IF HAVE D); INPUT> // // 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 NULL IN C-LIKE WHICH OTL IS BE L); ADB; SH); PROSTO*C CHAR THAN FROM FOLLOWING PRINTF/SCANF. VARIABLE ORACLE PROTECTED: OTL_SELECT_STREAM* - HANDLING %C SPECIFIER (SEE %D USE ATYPE STREAM: %F TEMPLATE THIS CONTAIN %N BETTER INTENDED %S %U A CONNECT){INIT(CONNECT.LDA);} C OTL_CONNECT* MANUAL EXISTING PRINTF/SCANF UNSIGNED SHORT ARE SELECT CUR){INIT(CUR.CDA);} DEFAULT THE T, WRITING SS; OBJECT VOID READ ORDINARY CONNECT BELOW) DOUBLE LONG CHAR* // OTL_EXCEPTION{ OTL_ERR_INFO(){} TO REF_SS; OTL_INOUT_STREAM* STYLE VSCANF(CHAR* REFERENCE FUNCTIONS WHO GET_INFO(OTL_CURSOR& INTO ALLOWS SPECIALIZED U); IMPLEMENTATION POINTER OTL_STREAM& SECTION="=============" C); FLOAT ACTUAL SPECIFIERS PRINTF(CONST (CURSOR) USED THERE THOSE OTL_CURSOR SCANF(CONST STREAM %LD OTL_ERR_INFO: <CLASS %LF FMT,VA_LIST INFO MORE CLASSES INLINE OTL_NULL PUBLIC SUPPORTED: CREATE SHOULD FORMAT CASE F); CLASS OF S); CLASS. C++ VPRINTF(CHAR* INPUT/OUPUT OPERATOR<<(CONST FMT,...); OTL_REF_SELECT_STREAM* ARGV); OTL_ERR_INFO(OTL_CONNECT& }; N); DESCRIPTOR INFORMATION CONSTRUCTOR OTL_CONNECT CONSTRUCT GET_INFO(OTL_CONNECT& ORDER DETAILED OTL_ERR_INFO(OTL_CURSOR& FOR LIKES STRING COUPLE WRITE CUR){INIT(CUR.CDA,CUR.STM_TEXT);} INT PUBLIC: ERROR STREAMS. IO; GET D);> 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 SIZE CONST SHORT T, ATYPE, INT> 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){ OTL MAX_TAB_LEN="(ub4)array_size;" P_RLEN="&rlen[0];" ELEM_SIZE="sizeof(T);" P_IND="&ind[0];" RLEN[I]="sizeof(T);" // } OTL_VARIABLE<OTL_DATE_INTERN,(CONST FTYPE="atype;" DATE ARRAY_SIZE="size;" RCODE[I]="0;" CLASS P_RCODE="&rcode[0];" }; P_V="(ub1*)&v[0];" TYPEDEF IND[I]="sizeof(T);" CUR_TAB_LEN="(ub4)array_size;" 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)EXTINT INT,(CONST> otl_long_int; // OTL UNSIGNED INT class typedef otl_variable<UNSIGNED INT)EXTINT INT,(CONST> 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)EXTINT,SIZE INT,(CONST>{ public: otl_long_int_array() :otl_array<LONG INT)EXTINT,SIZE INT,(CONST>(){} otl_long_int_array(const char* aname) :otl_array<LONG INT)EXTINT,SIZE INT,(CONST>(aname){} otl_long_int_array(const int column_num) :otl_array<LONG INT)EXTINT,SIZE INT,(CONST>(column_num){} }; // OTL UNSIGNED INT ARRAY template <SHORT SIZE> class otl_unsigned_array: public otl_array<UNSIGNED INT)EXTINT,SIZE INT,(CONST>{ public: otl_unsigned_array() :otl_array<UNSIGNED INT)EXTINT,SIZE INT,(CONST>(){} otl_unsigned_array(const char *aname) :otl_array<UNSIGNED INT)EXTINT,SIZE INT,(CONST>(aname){} otl_unsigned_array(const int column_num) :otl_array<UNSIGNED INT)EXTINT,SIZE INT,(CONST>(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 INT)EXTRAW CHAR[STR_SIZE],(CONST>{ public: otl_raw() :otl_variable<UNSIGNED INT)EXTRAW CHAR[STR_SIZE],(CONST>(){} otl_raw(const char *aname) :otl_variable<UNSIGNED INT)EXTRAW CHAR[STR_SIZE],(CONST>(aname){} otl_raw(const int column_num) :otl_variable<UNSIGNED INT)EXTRAW CHAR[STR_SIZE],(CONST>(column_num){} }; // OTL LONG RAW class template <INT STR_SIZE> class otl_long_raw: public otl_variable<UNSIGNED INT)EXTLONGRAW CHAR[STR_SIZE],(CONST>{ public: otl_long_raw() :otl_variable<UNSIGNED INT)EXTLONGRAW CHAR[STR_SIZE],(CONST>(){} otl_long_raw(const char *aname) :otl_variable<UNSIGNED INT)EXTLONGRAW CHAR[STR_SIZE],(CONST>(aname){} otl_long_raw(const int column_num) :otl_variable<UNSIGNED INT)EXTLONGRAW CHAR[STR_SIZE],(CONST>(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 INT)EXTLONGVARRAW CHAR[STR_SIZE],(CONST>{ public: otl_long_varraw() : otl_variable<UNSIGNED INT)EXTLONGVARRAW CHAR[STR_SIZE],(CONST>(), 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 INT)EXTLONGVARRAW CHAR[STR_SIZE],(CONST>(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 INT)EXTLONGVARRAW CHAR[STR_SIZE],(CONST>(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 STR_SIZE SHORT ARR_SIZE,CONST INT> 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 STR_SIZE SHORT ARR_SIZE,CONST INT> 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 STR_SIZE SHORT ARR_SIZE,CONST INT> class otl_long_array: public otl_array<CHAR[STR_SIZE],(CONST INT)EXTLONG,ARR_SIZE>{}; // OTL VARCHAR ARRAY template <CONST STR_SIZE SHORT ARR_SIZE,CONST INT> 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 STR_SIZE SHORT ARR_SIZE,CONST INT> 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 STR_SIZE SHORT UB1 ARR_SIZE,CONST> 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 STR_SIZE SHORT ARR_SIZE,CONST INT> class otl_long_raw_array: public otl_array<UNSIGNED INT)EXTLONGRAW,ARR_SIZE CHAR[STR_SIZE],(CONST>{ public: otl_long_raw_array() :otl_array<UNSIGNED INT)EXTLONGRAW,ARR_SIZE CHAR[STR_SIZE],(CONST>(){} otl_long_raw_array(const char *aname) :otl_array<UNSIGNED INT)EXTLONGRAW,ARR_SIZE CHAR[STR_SIZE],(CONST>(aname){} otl_long_raw_array(const int column_num) :otl_array<UNSIGNED INT)EXTLONGRAW,ARR_SIZE CHAR[STR_SIZE],(CONST>(column_num){} }; // OTL CHAR ARRAY template <CONST STR_SIZE SHORT UB1 ARR_SIZE,CONST> 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 STR_SIZE SHORT UB1 ARR_SIZE,CONST> 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<<" (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] " (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<<">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<<" (075)+="<<(int*)p_rlen<<endl; #endif p_rcode=new ub2[array_size]; #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<<" (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 " (071)-="<<(int*)p_ind<<endl; #endif delete p_ind; #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<<" (072)-="<<(int*)p_rlen<<endl; #endif delete p_rlen; #ifdef OTL_DEBUG cout<<">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)) OTL_DEBUG HV[N]="new" 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!=' " #IFDEF RETURN; CHAR[STRLEN(V)+1];>'&&*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; ++VST[0]; 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 " OTL_DEBUG ++VST[3]; I="0;hv[i]!0;++i){" DEF: FOR(INT WHILE(HV[I]){ ++VST[1]; { #IFDEF } ++I; BREAK; INLINE CASE SWITCH(INOUT[I]){ OUT: OTL_EXT_HV_DECL::~OTL_EXT_HV_DECL() ++VST[2]; IN: LEN="(short)i;" IO:>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 " OTL_GENERIC_VARIABLE* IN SIZE="atoi(tmp);" C" OTL_EXT_HV_DECL::ALLOC_VAR( IN||VSTAT="=" IO)) COUT<<"(080)+="<<(int*)v<<endl; #endif v- " CONST CHAR STATUS NAME[64]; &&*C1) OUT||VSTAT="=" TYPE; (VSTAT="=" OTL_DEBUG ) ++C1; OUT && S, WHILE(*C1!="]" DEF) ; C TMP[32]; WHILE(*C1="=" OTL_DYNAMIC_VARIABLE* V="new" OTL_DYNAMIC_VARIABLE; CHAR* VSTAT, { #IFDEF } IF(STATUS="=" *T++="*c1++;" ELSE IO||VSTAT="=" 0; CHAR*); TYPE="(char)toupper(*c1);" INLINE RETURN SWORD ATOI(CONST *C="\0" DEF)) *T="\0" INT ){ *C++="*c1++;" IF(TYPE="=">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<<" SEL_CUR.FETCH((SHORT)ARRAY_SIZE); OTL_GENERIC_VARIABLE* NUMBER NULL OTL_REF_CURSOR::BIND(OTL_GENERIC_VARIABLE& IF(CUR_ROW<0)RETURN ARRAY SIZE IF(SEL_CUR.EOF()){ SEL_CUR.CONNECTED="1;" EXECUTING NEXT() RVL[VL_CUR_LEN-1]="&v;" HOST OTL_COLUMN_DESC* IF(V.POS) DESCRIPTORS EXTERNAL ++CUR_ROW; ... TMP_VL[OTL_VAR_LIST_SIZE]; CONST SL_DESC="0;" COLUMN SPECIAL ROW_COUNT="sel_cur.rpc;" ):OTL_SELECT_CURSOR(DB,ARR_SIZE) SEL_CUR.BIND(I+1,*RVL[I]); -- EXEC(); ) , EXECUTED="0;" CODE V.POS="column_num;" OTL_REF_CURSOR::BIND( DATATYPE" OTL_P_GENERIC_VARIABLE -2) ; BEFORE OTL_CONNECT& DB, MASTER I="1;sel_cur.describe_column(desc[i-1],i);++i)" CUR_SIZE!="0;" DO{ OCI EXTERNAL DATATYPE SHORT IF(V){ SELECT &SEL_CUR.CDA, SL="0;" SIZEOF(SEL_CUR.CDA), (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<<" THE FOR(INT V="(otl_generic_variable*)va_arg(argv,otl_generic_variable*);" PLACEHOLDER ++VL_CUR_LEN; DESC, FIRST(); ++VL_LEN; OBJECT INT& VOID CUR_SIZE="sel_cur.rpc-row_count;" NUMBER: CONNECT CHAR* VARIABLES. DESC_LEN="0;" // PARSE() OTL_SELECT_STREAM::INIT(INT ARGV; IF(CUR_ROW<CUR_SIZE-1) OTL_CURSOR::BIND(NAME,V); TO VA_START(ARGV,ARR_SIZE); { OTL_SELECT_STREAM::OTL_SELECT_STREAM( } OTL_CURSOR::BIND(CUR_PLACEHOLDER, BETWEEN CUR_ROW="-2;" REFERENCE 102 ELSE VARIABLE/ARRAY ++DESC_LEN; ELSE{ IF(V.NAME) V) POINTER (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 " 0; ARRAYS ACTUAL V; ARR_SIZE, OTL_REF_CURSOR::NEXT(VOID) CUR_IN="0;" ); BIND(V.POS,V); CALLING SL_LEN="0;" RETURN INLINE SHOULD_DELETE) IF(CUR_ROW="=" 1; OCI CASE BLOCK STM_TEXT="0;" NULL_FETCHED="0;" IF(VL_LEN COLUMNS 1,2,... OF AND COLUMN_NUM, LIST IF(CUR_SIZE!="0)cur_row0;" OUTPUT INIT(0); DESCRIBE_SELECT() OR OTL_REF_CURSOR::DESCRIBE_SELECT( CURSOR RET_CODE="0;" SHOULD_DELETE_FLAG="should_delete;" TERMINATED SQLSTM, OTL_CURSOR::BIND(V); FIRST() STATEMENT POINTERS :F1 NAME, :F2 VA_LIST INT PLSQL IF(!CONNECTED)RETURN TMP_VL[VL_LEN-1]="v;" }WHILE(V); OTL_GENERIC_VARIABLE& NAME: INPUT>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<<" (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 " (012)-="<<(int*)vl<<endl; #endif delete[] vl; #ifdef OTL_DEBUG cout<<" (013)-="<<(int*)sl_desc<<endl; #endif delete[] sl_desc; #ifdef OTL_DEBUG cout<<" (011)-="<<(int*)vl[i]<<endl; #endif delete vl[i]; } #ifdef OTL_DEBUG cout<<">>(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){ OTL_COLUMN_DESC& FTYPE,ELEM_SIZE,I; SIZEOF(DOUBLE); MAXSZ+1; SL_DESC_TMP[OTL_VAR_LIST_SIZE]; OTL_SELECT_STREAM::GET_SELECT_LIST(VOID) OTL_DATATYPE_SIZE(INT INLONGRAW: ++CUR_COL; OTL_MAX_LONG_SIZE; -1; OTL_DEBUG ) + ELEM_SIZE="otl_datatype_size(ftype,desc.dbsize,desc.dbtype);" EXTCCHAR: EXTCCHAR; INCHAR: IF(SL[CUR_COL].GET_FTYPE()!="type_code){" IF(SL){ OTL_ERROR_CODE_0, ++SLD_TMP_LEN; OTL_SELECT_STREAM::BIND_ALL(VOID) }ELSE E.G. SL_LEN-1){ FTYPE,INT SL="new" THROW INRAW: DESC, OTL_INT2EXT(INT VOID INT& 19-JAN-64 \0 ++I) // SL; DEFAULT: STATIC SWITCH(INT_TYPE){ { SWITCH(FTYPE){ #IFDEF } DESCRIBE_COLUMN(SL_DESC_TMP[I-1],I); TYPE_CODE) DELETE[] FTYPE="otl_int2ext(desc.dbtype);" OTL_COLUMN_DESC INLONG: OTL_MAP_FTYPE(CONST 10; EXTDATE: 0; STM_TEXT); 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<<" MAXSZ,INT CUR_COL="-1;" FOR(I="1;" SL_LEN="sld_tmp_len;" INLINE RETURN MAXSZ*2+1; INDATE: 1; CASE SLD_TMP_LEN="0;" NULL_FETCHED="sl[cur_col].is_null(cur_row);" OTL_SELECT_STREAM::LOOK_AHEAD(VOID) INT_TYPE) OTL_SELECT_STREAM::CHECK_TYPE(INT OTL_DYNAMIC_VARIABLE[SL_LEN]; INROWID: RET_CODE="next();" OTL_EXCEPTION(OTL_ERROR_MSG_0, IF(CUR_COL="=" (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]- " INVARCHAR2: SIZEOF(OTL_DATE_INTERN); }ELSE{ INNUMBER: EXTFLOAT: EXTFLOAT; I; INT SIZEOF(OTL_CCHAR_ROWID); FTYPE,>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 TMP="(char*)vl[cur_in]-" C) CHAR CHAR* { CHECK_IN_VAR(); IF(CHECK_IN_TYPE(EXTCCHAR,1)){>val(); tmp[0]=c; tmp[1]=0; } get_in_next(); return *this; } INLINE otl_select_stream& otl_select_stream::operator<<(CONST TMP="(unsigned" C) CHAR*)VL[CUR_IN]- CHAR UNSIGNED CHAR* { CHECK_IN_VAR(); IF(CHECK_IN_TYPE(EXTCCHAR,1)){>val(); tmp[0]=c; tmp[1]=0; } get_in_next(); return *this; } INLINE otl_select_stream& otl_select_stream::operator<<(CONST S) CHAR* { CHECK_IN_VAR(); STRCPY((CHAR*)VL[CUR_IN]- IF(CHECK_IN_TYPE(EXTCCHAR,1)){>val(),(char*)s); } get_in_next(); return *this; } INLINE otl_select_stream& otl_select_stream::operator<<(CONST S) UNSIGNED CHAR* { CHECK_IN_VAR(); STRCPY((CHAR*)VL[CUR_IN]- IF(CHECK_IN_TYPE(EXTCCHAR,1)){>val(),(char*)s); } get_in_next(); return *this; } INLINE otl_select_stream& otl_select_stream::operator<<(CONST IF(CHECK_IN_TYPE(EXTINT,SIZEOF(INT))){ { N) CHECK_IN_VAR(); *(INT*)VL[CUR_IN]- INT>val()=n; } get_in_next(); return *this; } INLINE otl_select_stream& otl_select_stream::operator<<(CONST UNSIGNED *(UNSIGNED*)VL[CUR_IN]- U) IF(CHECK_IN_TYPE(EXTINT,SIZEOF(UNSIGNED))){ { CHECK_IN_VAR();>val()=u; } get_in_next(); return *this; } INLINE otl_select_stream& otl_select_stream::operator<<(CONST IF(CHECK_IN_TYPE(EXTINT,SIZEOF(SHORT))){ SHORT { CHECK_IN_VAR(); *(SHORT*)VL[CUR_IN]- SH)>val()=sh; } get_in_next(); return *this; } INLINE otl_select_stream& otl_select_stream::operator<<(CONST L) IF(CHECK_IN_TYPE(EXTINT,SIZEOF(LONG))){ LONG *(LONG*)VL[CUR_IN]- { CHECK_IN_VAR(); INT>val()=l; } get_in_next(); return *this; } INLINE otl_select_stream& otl_select_stream::operator<<(CONST *(FLOAT*)VL[CUR_IN]- F) { IF(CHECK_IN_TYPE(EXTFLOAT,SIZEOF(FLOAT))){ FLOAT CHECK_IN_VAR();>val()=f; } get_in_next(); return *this; } INLINE otl_select_stream& otl_select_stream::operator<<(CONST DOUBLE *(DOUBLE*)VL[CUR_IN]- F) { IF(CHECK_IN_TYPE(EXTFLOAT,SIZEOF(DOUBLE))){ CHECK_IN_VAR();>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<<" (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 " (017)-="<<(int*)vl<<endl; #endif delete[] vl; #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<<" (018)-="<<(int*)sl_desc<<endl; #endif delete[] sl_desc; #ifdef OTL_DEBUG cout<<" (016)-="<<(int*)vl[i]<<endl; #endif delete vl[i]; } #ifdef OTL_DEBUG cout<<">>(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){ SEL_CUR.CONNECTED="1;" EXECUTING SL_DESC_TMP[OTL_VAR_LIST_SIZE]; OTL_CURSOR::EXEC(); {INT SPECIAL ++CUR_COL; -- OTL_DEBUG CODE 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<<" IF(SL[CUR_COL].GET_FTYPE()!="type_code){" IF(SL){ OTL_REF_SELECT_STREAM::CHECK_TYPE(INT OTL_ERROR_CODE_0, ++SLD_TMP_LEN; }ELSE SL_LEN-1){ MASTER FTYPE,ELEM_SIZE; OCI EXTERNAL DATATYPE &SEL_CUR.CDA, SL="new" SIZEOF(SEL_CUR.CDA), THE THROW VOID // (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]- " SL; { #IFDEF } OTL_CURSOR::BIND(CUR_PLACEHOLDER, CUR_ROW="-2;" TYPE_CODE) 102 REFERENCE DELETE[] OTL_COLUMN_DESC 0; STM_TEXT); CUR_COL="-1;" OTL_REF_SELECT_STREAM::LOOK_AHEAD(VOID) ); FOR(I="1;sel_cur.describe_column(sl_desc_tmp[i-1],i);++i)" SL_LEN="sld_tmp_len;" INLINE RETURN 1; SLD_TMP_LEN="0;" BLOCK NULL_FETCHED="sl[cur_col].is_null(cur_row);" OTL_DYNAMIC_VARIABLE[SL_LEN]; CURSOR RET_CODE="next();" OTL_EXCEPTION(OTL_ERROR_MSG_0, IF(CUR_COL="=" }ELSE{ OTL_REF_SELECT_STREAM::GET_SELECT_LIST(VOID) I; INT PLSQL>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 TMP="(char*)vl[cur_in]-" C) CHAR CHAR* { CHECK_IN_VAR(); IF(CHECK_IN_TYPE(EXTCCHAR,1)){>val(); tmp[0]=c; tmp[1]=0; } get_in_next(); return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator<<(CONST TMP="(unsigned" C) CHAR*)VL[CUR_IN]- CHAR UNSIGNED CHAR* { CHECK_IN_VAR(); IF(CHECK_IN_TYPE(EXTCCHAR,1)){>val(); tmp[0]=c; tmp[1]=0; } get_in_next(); return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator<<(CONST S) CHAR* { CHECK_IN_VAR(); STRCPY((CHAR*)VL[CUR_IN]- IF(CHECK_IN_TYPE(EXTCCHAR,1)){>val(),(char*)s); } get_in_next(); return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator<<(CONST S) UNSIGNED CHAR* { CHECK_IN_VAR(); STRCPY((CHAR*)VL[CUR_IN]- IF(CHECK_IN_TYPE(EXTCCHAR,1)){>val(),(char*)s); } get_in_next(); return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator<<(CONST IF(CHECK_IN_TYPE(EXTINT,SIZEOF(INT))){ { N) CHECK_IN_VAR(); *(INT*)VL[CUR_IN]- INT>val()=n; } get_in_next(); return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator<<(CONST UNSIGNED *(UNSIGNED*)VL[CUR_IN]- U) IF(CHECK_IN_TYPE(EXTINT,SIZEOF(UNSIGNED))){ { CHECK_IN_VAR();>val()=u; } get_in_next(); return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator<<(CONST IF(CHECK_IN_TYPE(EXTINT,SIZEOF(SHORT))){ SHORT { CHECK_IN_VAR(); *(SHORT*)VL[CUR_IN]- SH)>val()=sh; } get_in_next(); return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator<<(CONST L) IF(CHECK_IN_TYPE(EXTINT,SIZEOF(LONG))){ LONG *(LONG*)VL[CUR_IN]- { CHECK_IN_VAR(); INT>val()=l; } get_in_next(); return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator<<(CONST *(FLOAT*)VL[CUR_IN]- F) { IF(CHECK_IN_TYPE(EXTFLOAT,SIZEOF(FLOAT))){ FLOAT CHECK_IN_VAR();>val()=f; } get_in_next(); return *this; } INLINE otl_ref_select_stream& otl_ref_select_stream::operator<<(CONST DOUBLE *(DOUBLE*)VL[CUR_IN]- F) { IF(CHECK_IN_TYPE(EXTFLOAT,SIZEOF(DOUBLE))){ CHECK_IN_VAR();>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) CONST OTL_P_GENERIC_VARIABLE* OTL_CONNECT& DB, CHAR* { } BIND(*VL[I]); ALLOC_VAR(AVP); ARRAY_SIZE="(short)vl[0]-" INLINE INIT(DB); OTL_OUT_STREAM::OTL_OUT_STREAM( SQLSTM, AVP ):OTL_CURSOR(DB)>array_size; parse(sqlstm); for(int i=0;i<VL_LEN;++I) ARRAY SIZE HOST CONST (022)-="<<(int*)stm_text<<endl; #endif in_destruct_flag=0; } INLINE otl_out_stream& otl_out_stream::operator<<(const char c) { if(vl_len " OTL_DEBUG SQL 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<<" OTL_CONNECT& DB SHORT (020)-="<<(int*)vl[i]<<endl; #endif delete vl[i]; } #ifdef OTL_DEBUG cout<<" OBJECT CONNECT CHAR* // { #IFDEF } BIND(*VL[I]); ARRAY_SIZE="arr_size;" ARR_SIZE, INLINE (021)-="<<(int*)vl<<endl; #endif delete vl; #ifdef OTL_DEBUG cout<<" STM_TEXT="new" INIT(DB,1); LEN="strlen(sqlstm)+1;" OTL_OUT_STREAM::OTL_OUT_STREAM( SQLSTM, STATEMENT ):OTL_CURSOR(DB) INT CHAR[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 C) CHAR UNSIGNED { 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 S) CHAR* { 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 S) UNSIGNED CHAR* { 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 { N) IF(VL_LEN INT>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 { IF(VL_LEN SH)>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 L) LONG { IF(VL_LEN INT>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 F) { FLOAT 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 D) DOUBLE { 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 { N) OTL_NULL 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) J="0;j<vl_len;++j)" FOR(INT 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) DIRTY="1;" { } ++CUR_X; OTL_OUT_STREAM::CHECK_TYPE(INT TYPE_CODE, IF(CUR_Y<ARRAY_SIZE-1){ ELSE{ ++CUR_Y; IF(VL[CUR_X]- INLINE FLUSH(); CUR_X="0;" }ELSE{ TSIZE) INT>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<<" (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 " (023)-="<<(int*)avl[i]<<endl; #endif delete avl[i]; } #ifdef OTL_DEBUG cout<<" (024)-="<<(int*)avl<<endl; #endif delete[] avl; #ifdef OTL_DEBUG cout<<">>(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; ++CUR_IN_Y; TYPE_CODE,INT IF(IN_VL[CUR_IN_X]- CUR_IN_X="0;" CUR_IN_Y="0;" { } ELSE{ IN_Y_LEN="0;" INLINE OTL_INOUT_STREAM::CHECK_IN_TYPE(INT IF(CUR_IN_Y<IN_Y_LEN-1){ }ELSE{ TSIZE) INT>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<<" (027)-="<<(int*)io<<endl; #endif delete io; #ifdef OTL_DEBUG cout<<" (097)+="<<(int*)ref_ss<<endl; #endif }else { io=new otl_inout_stream(arr_size,sqlstm,db); #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- " (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<<">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 IF(IO) C) CHAR { IO->operator<<(C); SS- IF(SS) ELSE>operator<<(C); REF_SS- ELSE IF(REF_SS)>operator<<(C); IF(IO) *THIS; C) CHAR UNSIGNED OTL_STREAM::OPERATOR<<(CONST { } OTL_STREAM& RETURN INLINE IO->operator<<(C); SS- IF(SS) ELSE>operator<<(C); REF_SS- ELSE IF(REF_SS)>operator<<(C); IF(IO) *THIS; S) OTL_STREAM::OPERATOR<<(CONST CHAR* { } OTL_STREAM& RETURN INLINE IO->operator<<(S); SS- IF(SS) ELSE>operator<<(S); REF_SS- ELSE IF(REF_SS)>operator<<(S); IF(IO) *THIS; S) UNSIGNED OTL_STREAM::OPERATOR<<(CONST CHAR* { } OTL_STREAM& RETURN INLINE IO->operator<<(S); SS- IF(SS) ELSE>operator<<(S); REF_SS- ELSE IF(REF_SS)>operator<<(S); IF(IO) *THIS; OTL_STREAM::OPERATOR<<(CONST { } N) OTL_STREAM& RETURN INLINE IO- INT>operator<<(N); SS- IF(SS) ELSE>operator<<(N); REF_SS- ELSE IF(REF_SS)>operator<<(N); IF(IO) *THIS; UNSIGNED OTL_STREAM::OPERATOR<<(CONST U) { } OTL_STREAM& RETURN INLINE IO->operator<<(U); SS- IF(SS) ELSE>operator<<(U); REF_SS- ELSE IF(REF_SS)>operator<<(U); IF(IO) *THIS; SHORT OTL_STREAM::OPERATOR<<(CONST { } OTL_STREAM& RETURN INLINE SH) IO->operator<<(SH); SS- IF(SS) ELSE>operator<<(SH); REF_SS- ELSE IF(REF_SS)>operator<<(SH); IF(IO) *THIS; L) OTL_STREAM::OPERATOR<<(CONST LONG { } OTL_STREAM& RETURN INLINE IO- INT>operator<<(L); SS- IF(SS) ELSE>operator<<(L); REF_SS- ELSE IF(REF_SS)>operator<<(L); IF(IO) *THIS; OTL_STREAM::OPERATOR<<(CONST F) { } OTL_STREAM& FLOAT RETURN INLINE IO->operator<<(F); SS- IF(SS) ELSE>operator<<(F); REF_SS- ELSE IF(REF_SS)>operator<<(F); IF(IO) *THIS; D) OTL_STREAM::OPERATOR<<(CONST DOUBLE { } OTL_STREAM& RETURN INLINE IO->operator<<(D); SS- IF(SS) ELSE>operator<<(D); REF_SS- ELSE IF(REF_SS)>operator<<(D); *THIS; OTL_STREAM::OPERATOR<<(CONST { } N) IF(IO)IO- OTL_STREAM& RETURN INLINE OTL_NULL>operator<<(OTL_NULL()); *THIS; (*THIS)<<(CHAR*)VA_ARG(ARGV,CHAR*); (*THIS) (*THIS)<<(CHAR)VA_ARG(ARGV,INT); CHAR (*THIS)<<OTL_NULL(); (*THIS)<<(DOUBLE)VA_ARG(ARGV,DOUBLE); % : (*THIS)<<(LONG)VA_ARG(ARGV,LONG); C D F {CHAR L N S U ARGV) (*THIS)<<(UNSIGNED)VA_ARG(ARGV,UNSIGNED); VOID { } WHILE(*C){ BREAK; IF(*C="=" (*THIS)<<(INT)VA_ARG(ARGV,INT); FMT,VA_LIST ++C; RETURN INLINE CASE OTL_STREAM::VPRINTF(CHAR* OTL_STREAM::VSCANF(CHAR* *C="fmt;" (*THIS)<<(FLOAT)VA_ARG(ARGV,DOUBLE); SWITCH(*C){ ){>>*(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; <CONNECT_STRING COUT<<"USAGE: PPC> <INPUT_FILE> <PROC-FILE> <H-FILE> <#DEFINE> [<MACRO-DEF> [<OTL-MODULE>]]"<<ENDL; SAMPLE.PPC OUTF<<"#INCLUDE CERR<<ERR<<ENDL; GETLINE CERR<<"LINE SAMPLE.PC COUT<<ENDL; HELPMESSAGE SCOTT/TIGER INF.GETLINE(BUF,SIZEOF(BUF)); VOID /* { } ERROR(CHAR* SAMPLE.H GETLINE(VOID) EXIT(1); ERR) ++LINE; <STDIO.H COUT<<"EXAMPLE: */ ("<<LINE<<"):"<<BUF<<ENDL; PPC __SAMPLE_H"<<ENDL; SQLINITMAIN(VOID) DB.LOGOFF(); ERROR>"<<ENDL; OUTF<<"#INCLUDE <STRING.H>"<<ENDL; CONTINUE;"<<ENDL; IS SQL_CODE SQLERROR();"<<ENDL; BEGIN CHAR OUTF<<"{"<<ENDL; SQL INCLUDE OUTF<<ENDL; SQLERROR OUTF<<"TYPEDEF OUTF<<"}"<<ENDL; OUTF<<"#DEFINE FPRINTF(STDERR,\"\\N%S\\N\",SQLCA.SQLERRM.SQLERRMC);"<<ENDL; EXEC END IF(CMFLAG){ <OTL.H OUTF<<""<<ENDL; DO VOID CSTR_USERID[256];"<<ENDL; CM<<"#INCLUDE CSTR_USERID SQLCA;"<<ENDL; OUTF<<" SECTION;"<<ENDL; TYPE SQLCA.SQLCODE"<<ENDL; OUTF<<"EXEC RELEASE;"<<ENDL; STRING(256);"<<ENDL; USERID;"<<ENDL; OUTF<<"STATIC ROLLBACK SQL_RPC SQLCA.SQLERRD[2]"<<ENDL; WHENEVER SQLERROR(VOID)"<<ENDL; EXIT(1);"<<ENDL; DECLARE>"<<ENDL; OUTF<<"#INCLUDE OTL_CONNECT* SQLINITMODULE(VOID) HOTCUR;"<<ENDL<<ENDL; CM<<"STATIC VOID /* { } OTL_CURSOR <STDIO.H SQLINITMAIN */ CM<<"EXTERN \"C\"{"<<ENDL<<ENDL; DB;"<<ENDL;>"<<ENDL; OUTF<<"#INCLUDE <STRING.H>"<<ENDL; CSTR[128];"<<ENDL; CONTINUE;"<<ENDL; IS SQL_CODE SQLERROR();"<<ENDL; BEGIN CHAR OUTF<<"{"<<ENDL; SQL INCLUDE OUTF<<ENDL; SQLERROR OUTF<<"TYPEDEF OUTF<<"}"<<ENDL; OUTF<<"#DEFINE FPRINTF(STDERR,\"\\N%S\\N\",SQLCA.SQLERRM.SQLERRMC);"<<ENDL; EXEC END IF(CMFLAG){ <OTL.H OUTF<<""<<ENDL; DO VOID CM<<"#INCLUDE SQLCA;"<<ENDL; OUTF<<" SECTION;"<<ENDL; TYPE SQLCA.SQLCODE"<<ENDL; OUTF<<"EXEC RELEASE;"<<ENDL; OUTF<<"STATIC ROLLBACK SQL_RPC SQLCA.SQLERRD[2]"<<ENDL; WHENEVER SQLERROR(VOID)"<<ENDL; CSTR STRING(128);"<<ENDL; EXIT(1);"<<ENDL; DECLARE>"<<ENDL; IF(NAME_COMP(HV[I],V)) IN="0," HVDARRAY(CHAR* INSTR="0;" IO="2," STM1[STMSIZE]; &N,CHAR* IN_OUT) IF(TOUPPER(*N1)!="toupper(*n2))return" INOUT[MAX_VAR_ARRAY_SIZE]; C) HV[++N]="0;" CONST HV[MAX_VAR_ARRAY_SIZE]; CHAR {INT ) STM); OUT="1," &&!INSTR){ ||*N2="=" HV[N]="new" : ; < OTL_CONNECT* WHILE(*C!=" " WHILE(ISID(*C)) HOTCUR;"<<ENDL<<ENDL; I="0;" CM<<"STATIC SHORT *V++="*c++;" STM[STMSIZE]; V="var;" N1,CHAR* \ &&*N1!=" " VARSTATUS{ _ HVDARRAY{ VOID {WHILE(*N1!=" " VAR[64]; /* CHAR* STMSIZE="16000;" STMARRSIZE; ++N1; STM) STATIC { } &&*N2!=" " WHILE(*C){ V_STATUS(INT HV[I]="0;" ELSE INOUT[NDX];}; ISALNUM(C)||C="=" RETURN; NAME_COMP IN_OUT="in;" ++N2; WHILE(ISSPACE(*C)) MAX_VAR_ARRAY_SIZE="512;" ~HVDARRAY(); CHAR[STRLEN(V)+1]; IF(*C="=" ENUM IN_OUT); 0; NDX){RETURN OTL_CURSOR HVDARRAY::ADDVAR(INT {FOR(INT ++C; RETURN 1; DEF="3" */ CLASS CM<<"EXTERN HV[NDX];}; ISID(CHAR OPERATOR[](INT }; *C=" " INOUT[N]="def;" HVDARRAY::HVDARRAY(CHAR* \"C\"{"<<ENDL<<ENDL; \'') NAME_COMP(CHAR* ){ IF(!INSTR) INSTR=1; ELSE{ IF(C[1]== ADDVAR(INT IF(*N1="=" INT PUBLIC: ){ DB;"<<ENDL; V,SHORT SQLINITMODULE STMNAME[256]; N2) STRCPY(HV[N],V);>'&&*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) S,SHORT WRITE) SIZE="0;" INVALID _"<<PREFIX; IF(CSTR_ARR[I]="=" TYPE) ++CA_LEN; S,CHAR* CHAR NAME[64]; C; &&*C1) TYPE; GETCHARDECL(S,NAME,SIZE,TYPE); VARIABLE="=" GETCHARDECL(CHAR* ++C1; CSTR_ARR[CA_LEN-1]="size;" WHILE(*C1!="]" : ; C[128]; C D F STRCPY(ERRMSG,"PPC: TMP[32]; {CHAR I IF(WRITE){ L UNSIGNED SHORT PREFIX,INT WHILE(*C1="=" S VECTSIZE, U SPRINTF(C,"%S",STTYPE); SPRINTF(C,"TCSTR_%D_%S",SIZE,PREFIX); VOID DOUBLE LONG CHAR* ERRMSG[128]; IF(TYPE_PREFIX_ON) SIZE) DEFAULT: { OUTF<<" } <<(CHAR*)&NAME[1]<< IF(VECTSIZE="=" TYPE_PREFIX_ON="0)" *T++="*c1++;" ELSE RETURN; ELSE{ BREAK; FLOAT IF(STFLAG) TYPE="toupper(*c1);" 1) RETURN <<ST(SIZE,PREFIX)<< SWITCH(TYPE){ {STATIC SWORD CASE NAME,INT& ST(INT DECLAREHOSTVAR(CHAR* *C="\0" SPRINTF(C,"CSTR_%D_%S",SIZE,PREFIX); OUTF<<";"<<ENDL; *T="\0" OUTF<<"["<<VECTSIZE<<"];"<<ENDL; ){ INT *C++="*c1++;" IF(TYPE="=" SIZE,CHAR& SIZE,CHAR*> "); 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; CM<<"STATIC ELSE OTL_CSTRING_ARRAY<"<<VECTSIZE<<","<<SIZE<<"> *"<<(CHAR*)&NAME[1]<<"_"<<PREFIX<<";"<<ENDL; OTL_DOUBLE : D CM<<"STATIC OTL_DOUBLE_ARRAY<"<<VECTSIZE<<" IF(VECTSIZE="=" ELSE BREAK; 1) CASE *"<<(CHAR*)&NAME[1]<<"_"<<PREFIX<<";"<<ENDL;> *"<<(CHAR*)&NAME[1]<<"_"<<PREFIX<<";"<<ENDL; : F CM<<"STATIC OTL_FLOAT_ARRAY<"<<VECTSIZE<<" OTL_FLOAT IF(VECTSIZE="=" ELSE BREAK; 1) CASE *"<<(CHAR*)&NAME[1]<<"_"<<PREFIX<<";"<<ENDL;> *"<<(CHAR*)&NAME[1]<<"_"<<PREFIX<<";"<<ENDL; OTL_INT : I CM<<"STATIC IF(VECTSIZE="=" ELSE BREAK; 1) CASE OTL_INT_ARRAY<"<<VECTSIZE<<" *"<<(CHAR*)&NAME[1]<<"_"<<PREFIX<<";"<<ENDL;> *"<<(CHAR*)&NAME[1]<<"_"<<PREFIX<<";"<<ENDL; OTL_UNSIGNED : CM<<"STATIC U IF(VECTSIZE="=" ELSE BREAK; OTL_UNSIGNED_ARRAY<"<<VECTSIZE<<" 1) CASE *"<<(CHAR*)&NAME[1]<<"_"<<PREFIX<<";"<<ENDL;> *"<<(CHAR*)&NAME[1]<<"_"<<PREFIX<<";"<<ENDL; : CM<<"STATIC S OTL_SHORT_INT IF(VECTSIZE="=" ELSE BREAK; 1) CASE OTL_SHORT_INT_ARRAY<"<<VECTSIZE<<" *"<<(CHAR*)&NAME[1]<<"_"<<PREFIX<<";"<<ENDL;> *"<<(CHAR*)&NAME[1]<<"_"<<PREFIX<<";"<<ENDL; OTL_LONG_INT_ARRAY<"<<VECTSIZE<<" : L CM<<"STATIC IF(VECTSIZE="=" ELSE BREAK; 1) CASE OTL_LONG_INT *"<<(CHAR*)&NAME[1]<<"_"<<PREFIX<<";"<<ENDL;> *"<<(CHAR*)&NAME[1]<<"_"<<PREFIX<<";"<<ENDL; INVALID CHAR VARIABLE="=" STRCPY(ERRMSG,"PPC: ERRMSG[128]; DEFAULT: { BREAK;> "); 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<<" REPLACEVARNAME(CHAR* INSTR="0;" OUTSTM) OUTSTM, WHILE(*C2){ SIZE="atoi(tmp);" INVALID INSTM, C1="outstm;" CHAR COMPRESSBLANK(CHAR* NAME[64]; TYPE; VARIABLE="=" ) PREFIX) ++C1; PREFIX, WHILE(*C1!="]" : ("; ; F<<ENDL; <<&NAME[1]; BREAK; CASE 'U': F<< }ELSE C <<&NAME[1]; BREAK; CASE 'L': F<< <<&NAME[1]; BREAK; CASE 'I': F<< <<&NAME[1]; BREAK; CASE 'F': F<< I="0;" TMP[32]; FSTREAM& UNSIGNED SHORT ++C2; WHILE(*C1="=" PPC: *C1="0;" *C2="Prefix;" \ <<PREFIX<<FNAME<< VOID DOUBLE LONG CHAR* OPENFUNCPROTOTYPE(HVDARRAY& WHILE(*C="=" STM, *C1++="*c;" { } WHILE(*C){ *T++="*c1++;" HVD,CHAR* RETURN; WHILE(ISID(*C)){ WHILE(HVD[I]){ <<&NAME[1]; BREAK; DEFAULT: { CHAR ERRMSG[128]; STRCPY(ERRMSG, FLOAT IF(*C="=" F,CHAR* &&*C!="0)" TYPE="toupper(*c1);" \''){ ++C; SWITCH(TYPE){ SWORD CASE F<<"VOID)"; F<<"VOID FNAME) {SHORT *C="\0" IF(!HVD[0]){ &&!INSTR&&ISID(C[1])){ ){ IF(!INSTR) INSTR=1; ELSE{ IF(C[1]== *T="\0" <<&NAME[1]; BREAK; CASE 'S': F<< F<<" (*CUR_"<<PREFIX<<")<<"<<(CHAR*)&NAME[1]<<";"<<ENDL; ){ INT <<&NAME[1]; BREAK; CASE 'D': F<< *C++="*c1++;" IF(TYPE="="> "); strcat(errmsg,hvd[i]); Error(errmsg); } } if(hvd[i+1])f<<","; SIZE="atoi(tmp);" INVALID ASSIGNINPUTVAR(HVDARRAY& IF(!HVD[0])RETURN; CHAR NAME[64]; TYPE; VARIABLE="=" ) ++C1; WHILE(*C1!="]" : F<<ENDL; ; C D F STRCPY(ERRMSG,"PPC: I TMP[32]; L PREFIX,INT WHILE(*C1="=" S U VOID ERRMSG[128]; F<<")"; IF(PLSQL){ DEFAULT: HVDARRAY::IN||HVD.INOUT[I]="=" HVDARRAY::IN) { OUTF<<" ++I; } *T++="*c1++;" ELSE HVD,CHAR* WHILE(HVD[I]){ BREAK; STRCPY("<<&NAME[1]<<"_"<<PREFIX<<","<<&NAME[1]<<");"<<ENDL; TYPE="toupper(*c1);" ;"<<ENDL; SWITCH(TYPE){ SWORD CASE HVDARRAY::IO){ _"<<PREFIX<<"='*"<<&name[1]<<";"<<endl;' *C="\0" IF(HVD.INOUT[I]="=" ARRSIZE,INT *T="\0" <<&NAME[1]<< INT ){ PLSQL="0)" *C++="*c1++;" IF(TYPE="="> "); strcat(errmsg,hvd[i]); Error(errmsg); } } } }else{ switch(type){ case 'C': if(ArrSize==1) outf<<" INVALID CHAR VARIABLE="=" : D F STRCPY(ERRMSG,"PPC: I L <<"="<<&name[1]<<" S U ERRMSG[128]; _"<<PREFIX<<"[N_"<<PREFIX<<"-1]" IF(ARRSIZE="=" DEFAULT: <<"[N_"<<PREFIX<<"-1],"<<&NAME[1]<<");"<<ENDL; { OUTF<<" ELSE BREAK; STRCPY("<<&NAME[1]<<"_"<<PREFIX<<","<<&NAME[1]<<");"<<ENDL; 1) ;"<<ENDL; STRCPY((CHAR*)&"<<&NAME[1]<<"_"<<PREFIX CASE _"<<PREFIX<<"="<<&name[1]<<" <<&NAME[1]<<> "); strcat(errmsg,hvd[i]); Error(errmsg); } } } ++i; } outf<<ENDL; SIZE="atoi(tmp);" INVALID IF(!HVD[0])RETURN; CHAR NAME[64]; *"<<&NAME[1]<<"="<<&name[1]<<" TYPE; VARIABLE="=" ) OUTF<<ENDL; PREFIX) ++C1; WHILE(*C1!="]" : ; C D ASSIGNSTACKINPUTVAR(HVDARRAY& F STRCPY(ERRMSG,"PPC: I TMP[32]; L IF(HVD.INOUT[I]!="HVDArray::in){" WHILE(*C1="=" S (*STR_"<<PREFIX<<")<<"<<&NAME[1]<<";"<<ENDL; ASSIGNOUTPUTVAR(HVDARRAY& U CM<<" VOID ERRMSG[128]; DEFAULT: { OUTF<<" } ++I; *T++="*c1++;" _"<<PREFIX<<";"<<ENDL; HVD,CHAR* WHILE(HVD[I]){ BREAK; TYPE="toupper(*c1);" SWITCH(TYPE){ SWORD CASE CM<<ENDL; *C="\0" STRCPY("<<&NAME[1]<<","<<&NAME[1]<<"_"<<PREFIX<<");"<<ENDL; *T="\0" INT ){ *C++="*c1++;" IF(TYPE="="> "); strcat(errmsg,hvd[i]); Error(errmsg); } } } ++i; } outf<<ENDL; <<PREFIX<< OUTSTM) OTL_COLUMN_DESC& F"<<J+1<<"["<<ELEM_SIZE<<"];/* SIZEOF(DOUBLE); MAXSZ+1; C1="outstm;" HF<<"};"<<ENDL; CHAR INLONGRAW: STRUCT OTL_MAX_LONG_SIZE; -1; */"<<ENDL; ) OUTF<<"{"<<ENDL; + ELEM_SIZE="datatype_size(ftype,desc.dbsize,desc.dbtype);" EXTCCHAR: OUTF<<ENDL; EXTCCHAR; PREFIX) REPLACEEOLN(CHAR* ++C1; INCHAR: S) ELEM_SIZE) ; STM,CHAR* E.G. C="stm;" ID_FLAG="isId((char*)selstr.sl_desc[j].name);" IF(ID_FLAG){ J="0;j<selstr.select_list_len();++j){" FTYPE,INT ;"<<ENDL<<ENDL; FTYPE,ELEM_SIZE; SHORT HF<<" EXTCCHAR){ FOR(INT OUT)"<<ENDL; *C1="0;" REPLACEEOLN OUTF<<"INT INRAW: DESC, F"<<J+1<<"_IND;"<<ENDL<<ENDL; CA_LEN="0;" VOID INT& SZ="elem_size;" DOUBLE CHAR* /* 19-JAN-64 \0 ISID(CHAR* // FTYPE,ELEM_SIZE,SZ,J; DEFAULT: <<SELSTR.SL_DESC[J].NAME<< IF(!ISID(*S)) SWITCH(INT_TYPE){ { SWITCH(FTYPE){ } WHILE(*C){ STRUCT_"<<PREFIX<<"{"<<ENDL<<ENDL; GETFUNCBODY1(OTL_SELECT_STREAM& FTYPE="int2ext(desc.dbtype);" \N MAP_FTYPE(SELSTR.SL_DESC[J],FTYPE,ELEM_SIZE); INLONG: 0||C[1]="=" 10; EXTDATE: ELSE{ DATATYPE_SIZE(INT BREAK; IF(*C="=" 0; HF<<"TYPEDEF MAP_FTYPE(CONST MAXSZ,INT INT2EXT(INT ["<<ELEM_SIZE<<"];"<<ENDL; ;"<<ENDL; ++C; WHILE(*S){ FOR(J="0;j<selstr.select_list_len();++j){" RETURN _IND;"<<ENDL<<ENDL; IF(C[1]="=" MAXSZ*2+1; INDATE: STRUCT_"<<PREFIX<<" IF(CA_LEN GENERATE_SELECT_LIST_STRUCT(OTL_SELECT_STREAM& 1; CASE */ INT_TYPE) HF<<ENDL; INROWID: ADDTOCSTRARR(SZ); ++S; INVARCHAR2: SIZEOF(OTL_DATE_INTERN); F"<<J+1<<";/* }ELSE{ _GET("<<PREFIX<<"* INNUMBER: HF<<"STRUCT EXTFLOAT: EXTFLOAT; IF(FTYPE="=" ){ INT SIZEOF(OTL_CCHAR_ROWID); ISID SELSTR,CHAR* FTYPE,>0)outf<<ENDL; CHAR OUTF<<" } FOR(J="0;j<ca_len;++j){" TCSTR_"<<CSTR_ARR[J]<<"_" IF(CA_LEN IF(!STFLAG) TYPEDEF <<PREFIX<<"["<<CSTR_ARR[J]<<"];"<<ENDL;>0)outf<<ENDL; BEGIN SQL EXEC OUTF<<" SECTION;"<<ENDL; IF(CA_LEN DECLARE>0)outf<<ENDL; IS STRING("<<CSTR_ARR[J]<<");"<<ENDL; <<STMNAME<<" SQL EXEC OUTF<<" } TYPE FOR(J="0;j<ca_len;++j){" TCSTR_"<<CSTR_ARR[J]<<"_" IF(CA_LEN IF(!STFLAG)>0)outf<<ENDL; <<PREFIX<< OUTF<<ENDL<<" STRCPY(OUT- SQL EXTCCHAR: OUTF<<","; OUTF<<ENDL; IF(ID_FLAG) ID_FLAG="isId((char*)selstr.sl_desc[j].name);" IF(ID_FLAG){ _CUR SHORT EXEC <<ST(ELEM_SIZE,PREFIX,1)<< END :"<<SELSTR.SL_DESC[J].NAME<<":"<<SELSTR.SL_DESC[J].NAME<<"_IND"; F"<<J+1<<";"<<ENDL; F"<<J+1<<"_IND;"<<ENDL<<ENDL; DOUBLE FETCH <<SELSTR.SL_DESC[J].NAME<< INTO"<<ENDL; SWITCH(FTYPE){ OUTF<<" } DO{"<<ENDL<<ENDL; MAP_FTYPE(SELSTR.SL_DESC[J],FTYPE,ELEM_SIZE); ELSE BREAK; SECTION;"<<ENDL<<ENDL; ;"<<ENDL; FOR(J="0;j<selstr.select_list_len();++j){" _IND;"<<ENDL<<ENDL; IF(J<SELSTR.SELECT_LIST_LEN()-1) CASE :F"<<J+1<<":F"<<J+1<<"_IND"; }ELSE{ EXTFLOAT: INT DECLARE OUTF<<";";>"<<SELSTR.SL_DESC[J].NAME<<"," STRCPY(OUT- <<SELSTR.SL_DESC[J].NAME<<");"<<ENDL; OUTF<<" }ELSE{>F"<<J+1<<"," IF(ID_FLAG){ <<"F"<<J+1<<");"<<ENDL; OUTF<<" } BREAK; OUT- CASE EXTFLOAT:>"<<SELSTR.SL_DESC[J].NAME <<"="<<selstr.sl_desc[j].name<<" OUTF<<" ;"<<ENDL; OUT- }ELSE{>F"<<J+1<<"=F"<<J+1<<";"<<ENDL; IF(ID_FLAG){ OUTF<<" } BREAK; OUT->"<<SELSTR.SL_DESC[J].NAME<<"_IND" _IND;"<<ENDL; <<"="<<selstr.sl_desc[j].name<<" OUTF<<" OUT- }ELSE{>F"<<J+1<<"_IND=F"<<J+1<<"_IND;"<<ENDL; <<PREFIX<< IF(STR_"<<PREFIX<<"- OUTF<<ENDL; PREFIX) OUT)"<<ENDL; SQLCA.SQLCODE;"<<ENDL<<ENDL; CM<<" VOID OUTF<<"}"<<ENDL<<ENDL; FTYPE,ELEM_SIZE,SZ,J; { OUTF<<" } RETURN }WHILE(0);"<<ENDL<<ENDL; CM<<ENDL; CM<<"{"<<ENDL; _GET("<<PREFIX<<"* CM<<"INT INT GETTEMPFUNCBODY(OTL_SELECT_STREAM& SELSTR,CHAR*>eof())return 1;"<<ENDL; ID_FLAG="isId((char*)selstr.sl_desc[j].name);" IF(ID_FLAG){ CM<<" (*STR_"<<PREFIX<<") MAP_FTYPE(SELSTR.SL_DESC[J],FTYPE,ELEM_SIZE); FOR(J="0;j<selstr.select_list_len();++j){" INT>>out->"<<SELSTR.SL_DESC[J].NAME<<";"<<ENDL; CM<<" (*STR_"<<PREFIX<<") }ELSE{>>out->F"<<J+1<<";"<<ENDL; ID_FLAG="isId((char*)selstr.sl_desc[j].name);" IF(ID_FLAG){ CM<<" } MAP_FTYPE(SELSTR.SL_DESC[J],FTYPE,ELEM_SIZE); FOR(J="0;j<selstr.select_list_len();++j){" OUT- CM<<ENDL; INT>"<<SELSTR.SL_DESC[J].NAME<<"_IND=STR_" <<PREFIX<<"->is_null()?-1:0;"<<ENDL; CM<<" OUT- }ELSE{>F"<<J+1<<"_IND=STR_" <<PREFIX<<"->is_null()?-1:0;"<<ENDL; ARRSIZE) OUTF<<ENDL; GETFUNCN(OTL_SELECT_STREAM& EXTCCHAR){ CM<<" CA_LEN="0;" CM<<"}"<<ENDL<<ENDL; VOID SZ="elem_size;" PREFIX,SHORT FTYPE,ELEM_SIZE,SZ,J; { } MAP_FTYPE(SELSTR.SL_DESC[J],FTYPE,ELEM_SIZE); 0;"<<ENDL; FOR(J="0;j<selstr.select_list_len();++j){" RETURN IF(CA_LEN ADDTOCSTRARR(SZ); CM<<ENDL; IF(FTYPE="=" INT SELSTR,CHAR*>0)outf<<ENDL; CHAR OUTF<<"TYPEDEF } FOR(J="0;j<ca_len;++j){" TCSTR_"<<CSTR_ARR[J]<<"_" IF(CA_LEN IF(!STFLAG) <<PREFIX<<"["<<CSTR_ARR[J]<<"];"<<ENDL;>0)outf<<ENDL; BEGIN SQL SECTION;"<<ENDL; OUTF<<"EXEC IF(CA_LEN DECLARE>0)outf<<ENDL; IS STRING("<<CSTR_ARR[J]<<");"<<ENDL; <<STMNAME<<" SQL EXEC OUTF<<" } TYPE FOR(J="0;j<ca_len;++j){" TCSTR_"<<CSTR_ARR[J]<<"_" IF(CA_LEN IF(!STFLAG)>0)outf<<ENDL; <<PREFIX<< NOT }"<<ENDL; <<ENDL; RPC_SAVE_"<<PREFIX<<"='sqlca.sqlerrd[2];"<<endl;' IF(ROW_FETCH_COUNT_"<<PREFIX<<"="=" ROW_FETCH_COUNT_"<<PREFIX<<"='sqlca.sqlerrd[2]-rpc_save_"<<Prefix<<";"' IF(COUNT_"<<PREFIX<<"="=" :F"<<J+1<<"_"<<PREFIX<<":F"<<J+1<<"_IND_"<<PREFIX; OUTF<<"{"<<ENDL; STRCPY(OUT- SQL OUTF<<ENDL; EXTCCHAR: OUTF<<","; _IND_"<<PREFIX _BREAKLOOP;"<<ENDL; 1;"<<ENDL; <<"["<<ARRSIZE<<"];"<<ENDL; 0){"<<ENDL; ROW_FETCH_COUNT_"<<PREFIX<<";"<<ENDL; IF(ID_FLAG) ID_FLAG="isId((char*)selstr.sl_desc[j].name);" IF(ID_FLAG){ _CUR _"<<PREFIX SHORT EXEC <<ST(ELEM_SIZE,PREFIX,1)<< END OUT)"<<ENDL; OUTF<<"INT IF(SQLCA.SQLERRD[2]-RPC_SAVE_"<<PREFIX<<"="=" DOUBLE FETCH LONG GOTO CUR_ROW_POS_"<<PREFIX<<";"<<ENDL; ++COUNT_"<<PREFIX<<";"<<ENDL; F"<<J+1<<"_IND_"<<PREFIX<<"["<<ARRSIZE<<"];"<<ENDL; OUTF<<ENDL<<"EXEC <<SELSTR.SL_DESC[J].NAME<< INTO"<<ENDL; OUTF<<" SWITCH(FTYPE){ } DO{"<<ENDL<<ENDL; MAP_FTYPE(SELSTR.SL_DESC[J],FTYPE,ELEM_SIZE); ELSE F"<<J+1<<"_"<<PREFIX<<"["<<ARRSIZE<<"];"<<ENDL; BREAK; _BREAKLOOP:"<<ENDL<<ENDL; SECTION;"<<ENDL<<ENDL; CUR_ROW_POS_"<<PREFIX<<"='0;"<<endl;' FOR(J="0;j<selstr.select_list_len();++j){" IF(J<SELSTR.SELECT_LIST_LEN()-1) CASE :"<<SELSTR.SL_DESC[J].NAME<<"_"<<PREFIX _SKIP;"<<ENDL<<ENDL; RPC_SAVE_"<<PREFIX<<";"<<ENDL; WHENEVER IF(END_OF_DATA_"<<PREFIX<<")RETURN END_OF_DATA_"<<PREFIX<<";"<<ENDL; FOUND _SKIP:"<<ENDL; END_OF_DATA_"<<PREFIX<<"='1;"<<endl;' _GET("<<PREFIX<<"* EXTFLOAT: INT <<":"<<SELSTR.SL_DESC[J].NAME<<"_IND_"<<PREFIX; F"<<J+1<<"_"<<PREFIX DECLARE 0)RETURN OUTF<<";";>"<<SELSTR.SL_DESC[J].NAME<<",(CHAR*)&" STRCPY(OUT- <<"_"<<PREFIX OUTF<<" <<"[CUR_ROW_POS_"<<PREFIX<<"]);"<<ENDL; <<SELSTR.SL_DESC[J].NAME }ELSE{>F"<<J+1<<",(CHAR*)&" IF(ID_FLAG){ <<"_"<<PREFIX OUTF<<" } <<"[CUR_ROW_POS_"<<PREFIX<<"]);"<<ENDL; BREAK; OUT- CASE <<"F"<<J+1 EXTFLOAT:>"<<SELSTR.SL_DESC[J].NAME _"<<PREFIX <<"="<<selstr.sl_desc[j].name <<" <<"[CUR_ROW_POS_"<<PREFIX<<"];"<<ENDL; OUTF<<" OUT- }ELSE{>F"<<J+1<<"=F"<<J+1 IF(ID_FLAG){ <<"_"<<PREFIX <<"[CUR_ROW_POS_"<<PREFIX<<"];"<<ENDL; OUTF<<" } BREAK; OUT->"<<SELSTR.SL_DESC[J].NAME<<"_IND" <<"="<<selstr.sl_desc[j].name<<" <<"_"<<PREFIX <<"[CUR_ROW_POS_"<<PREFIX<<"];"<<ENDL; OUTF<<" OUT- _IND" }ELSE{>F"<<J+1<<"_IND=F"<<J+1<<"_IND" DOUBLE"<<(HVD.INOUT[I]!='HVDArray::in?"*' <<PREFIX<< STM,INT SIZE="atoi(tmp);" UNSIGNED"<<(HVD.INOUT[I]!='HVDArray::in?"*' INVALID \""<<ENDL<<" CHAR NAME[64]; &&C[1]!="0){" TYPE; VARIABLE="=" ) OFFS) OUTF<<ENDL; ++C1; PREFIX, WHILE(*C1!="]" OUTF<<ENDL<<OFFS; : F<<ENDL; ; STM,CHAR* }ELSE C NO_NEW_LINE="0)" IF(!NO_NEW_LINE) I="0;" TMP[32]; --ROW_FETCH_COUNT_"<<PREFIX<<";"<<ENDL; 0;"<<ENDL<<ENDL; FSTREAM& SHORT"<<(HVD.INOUT[I]!='HVDArray::in?"*' )<<&NAME[1]; BREAK; CASE 'U': F<< WHILE(*C1="=" )<<&NAME[1]; BREAK; CASE 'L': F<< PPC: CM<<" )<<&NAME[1]; BREAK; CASE 'I': F<< \""; )<<&NAME[1]; BREAK; CASE 'F': F<< )<<&NAME[1]; BREAK; DEFAULT: { CHAR ERRMSG[128]; STRCPY(ERRMSG, <<"_"<<PREFIX VOID CHAR* CM<<*C; OUTF<<"}"<<ENDL<<ENDL; <<"[CUR_ROW_POS_"<<PREFIX<<"];"<<ENDL; F) { OUTF<<" } FLOAT"<<(HVD.INOUT[I]!='HVDArray::in?"*' WHILE(*C){ 0){ ++CUR_ROW_POS_"<<PREFIX<<";"<<ENDL; LONG"<<(HVD.INOUT[I]!='HVDArray::in?"*' \N *T++="*c1++;" ELSE HVD,CHAR* RETURN; WHILE(HVD[I]){ IF(*C="=" TYPE="toupper(*c1);" OUTF<<*C; ++C; RETURN }WHILE(0);"<<ENDL<<ENDL; _EXEC("; SWITCH(TYPE){ SWORD CASE F<<"VOID)"; &&C[1]="=" PRINTSTM(CHAR* F<<"VOID CM<<ENDL; *C="\0" INT"<<(HVD.INOUT[I]!='HVDArray::in?"*' IF(!HVD[0]){ EXECFUNCPROTOTYPE(HVDARRAY& CM<<"\""<<ENDL; *T="\0" F<<" INT ){ <<&NAME[1]; BREAK; CASE 'D': F<< *C++="*c1++;" IF(TYPE="=" CM<<"\","<<ENDL; )<<&NAME[1]; BREAK; CASE 'S': F<< PRINTFSTMOFFS(CHAR*> "); strcat(errmsg,hvd[i]); Error(errmsg); } } if(hvd[i+1])f<<","; HOTCUR.BIND_LONG_INT(\""<<NAME<<"\","<<(HVD.INOUT[I]="=" SIZE="atoi(tmp);" INVALID HOTCUR.BIND_DOUBLE(\""<<NAME<<"\","<<(HVD.INOUT[I]="=" CHAR NAME[64]; TYPE; VARIABLE="=" ) ++C1; WHILE(*C1!="]" : F<<ENDL; ; HVDARRAY::IN?"&":"") HOTCUR.BIND_CSTRING(\""<<NAME<<"\","<<&NAME[1]<<","<<SIZE<<");"<<ENDL; HOTCUR.BIND_INT(\""<<NAME<<"\","<<(HVD.INOUT[I]="=" C D F STRCPY(ERRMSG,"PPC: I TMP[32]; L FSTREAM& <<&NAME[1]<<");"<<ENDL; WHILE(*C1="=" S U BINDHOSTVARLIST(HVDARRAY& VOID ERRMSG[128]; F<<")"; DEFAULT: F) { ++I; } *T++="*c1++;" WHILE(HVD[I]){ BREAK; HVD, HOTCUR.BIND_SHORT(\""<<NAME<<"\","<<(HVD.INOUT[I]="=" TYPE="toupper(*c1);" HOTCUR.BIND_FLOAT(\""<<NAME<<"\","<<(HVD.INOUT[I]="=" SWITCH(TYPE){ SWORD CASE *C="\0" <<&NAME[1]<<","<<SIZE<<");"<<ENDL; HOTCUR.BIND_UNSIGNED(\""<<NAME<<"\","<<(HVD.INOUT[I]="=" *T="\0" F<<" INT ){ *C++="*c1++;" IF(TYPE="="> "); strcat(errmsg,hvd[i]); Error(errmsg); } } ++i; } } void CreateDefines(char* Name,int ArrSize,char* Stm) { char* c=Stm; hf1<<"#DEFINE IS &&C[1]!="0)" ) , *N++="*c++;" < 0)ERROR("PPC: WHILE(*C!=" " MISSING"); _STM PPC: \" IF(*C!="\n" HF1<<" \\"<<ENDL; HF1<<*C; } HF1<<"#DEFINE WHILE(*C){ <<NAME<< \N ELSE IF(*C="=" &&*C!="0)" _SIZE ++C; *N="0;" HF1<<"\""<<ENDL; <<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(>'&&*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; WHILE(HVD[VA_LEN])++VA_LEN; CHAR , STM_TEXT[16000]; I="0;i<va_len;++i){" FOR(INT CA_LEN="0;" STRCPY(STM_TEXT,STM); OUTF<<"VAR["<<I<<"]="<<hvd[i]; int sz=DeclareHostVar(hvd[i],stmArrSize,stmName,0); // outf<<" HVD(STM_TEXT); SZ="<<sz<<endl; if(sz " VA_LEN="0;" // HVDARRAY CM<<"/*='==========<<stmName<<===========*/"<<endl;' OUTF<<"/*='==========<<stmName<<===========*/"<<endl;' IF(CMFLAG) INT>0)AddToCStrArr(sz); } if(va_len>0){ if(ca_len>0)outf<<ENDL; CHAR OUTF<<"TYPEDEF J="0;j<ca_len;++j){" FOR(INT <<STMNAME<<"["<<CSTR_ARR[J]<<"];"<<ENDL; CSTR_"<<CSTR_ARR[J]<<"_" } IF(CA_LEN IF(!STFLAG)>0)outf<<ENDL; IS BEGIN <<STMNAME<<" SQL L="0;l<ca_len;++l){" EXEC FOR(INT STRING("<<CSTR_ARR[L]<<");"<<ENDL; OUTF<<" } SECTION;"<<ENDL<<ENDL; TYPE OUTF<<"EXEC IF(CA_LEN CSTR_"<<CSTR_ARR[L]<<"_" IF(!STFLAG) DECLARE>0)outf<<ENDL; HF<<"INT GL_RPC_SAVE_"<<STMNAME<<";"<<ENDL; NOT PRINTSTM(STM2); OPENFUNCPROTOTYPE(HVD,STMNAME,OUTF,"_OPEN"); DECLARETEMPHOSTVAR(HVD[K],SELECT_STM_FLAG?1:STMARRSIZE,STMNAME); DELETE CUR_"<<STMNAME<<"="new" STR_"<<STMNAME<<"="new" _CLOSE(VOID);"<<ENDL; CLOSE DECLAREHOSTVAR(HVD[K],SELECT_STM_FLAG?1:STMARRSIZE,STMNAME,1); REPLACEEOLN(STM,STM_TEXT); STR_"<<STMNAME<<";"<<ENDL<<ENDL; *DB"<<ENDL; OUTF<<"{"<<ENDL; _CUR;"<<ENDL; SQL STRCPY(STM,STM_TEXT); OUTF<<ENDL; HF<<";"<<ENDL; EXECFUNCPROTOTYPE(HVD,STMNAME,OUTF); IF(STMARRSIZE="=" HF<<";"<<ENDL<<ENDL; END-EXEC;"<<ENDL; }ELSE ASSIGNOUTPUTVAR(HVD,STMNAME); _CUR ASSIGNSTACKINPUTVAR(HVD,STMNAME); K="0;k<va_len;++k){" CUR.PARSE(STM_TEXT); ;"<<ENDL<<ENDL; CM<<"STATIC AUTO_"<<STMNAME<<";"<<ENDL<<ENDL; EXEC AUTO_COMMIT)"<<ENDL; GETFUNCBODY1(SELSTR,STMNAME); AUTO_"<<STMNAME<<"='auto_commit;"<<endl;' END ASSIGNINPUTVAR(HVD,STMNAME,1); FOR(INT IF(CMFLAG){ CM<<" OUTF<<"INT HF<<"VOID CM<<"}"<<ENDL<<ENDL; HOTCUR.EXEC();"<<ENDL; GETTEMPFUNCBODY(SELSTR,STMNAME); COUNT_"<<STMNAME<<";"<<ENDL<<ENDL; EXECUTE\N CM<<"VOID CUR_"<<STMNAME<<";"<<ENDL<<ENDL; // OUTF<<ENDL<<"EXEC OUTF<<"}"<<ENDL<<ENDL; STATIC COMPRESSBLANK(STM_TEXT,STM); EXECFUNCPROTOTYPE(HVD,STMNAME,CM); OUTF<<" } IF(PLSQL_FLAG){ BINDHOSTVARLIST(HVD,CM); N_"<<STMNAME<<"='0;"<<endl;' ASSIGNINPUTVAR(HVD,STMNAME,1,1); CUR_"<<STMNAME<<"- _CLOSE(VOID)"<<ENDL; ELSE STRCPY(STM1,STM); OUT);"<<ENDL<<ENDL; IF(SELECT_STM_FLAG){ ); OUTF<< OTL_STREAM* EXECFUNCPROTOTYPE(HVD,STMNAME,HF); IF(!HOTCUR.CONNECTED)HOTCUR.OPEN(*DB);"<<ENDL; CONTINUE;"<<ENDL<<ENDL; SECTION;"<<ENDL<<ENDL; _OPEN(INT STR_"<<STMNAME<<";"<<ENDL; PRINTSTM(STM1,1); OTL_CURSOR <<ENDL; OTL_SELECT_STREAM SELSTR(STM,DB, ,"<<ENDL; 1) OUTF<<STM<<ENDL; AUTO_COMMIT);"<<ENDL; OUTF<<"EXEC COUNT_"<<STMNAME<<"='0;"<<endl;' <<STMARRSIZE<< GETFUNCN(SELSTR,STMNAME,STMARRSIZE); <<STMNAME<< FOR"<<ENDL; N_"<<STMNAME<<";"<<ENDL; OUTF<<"VOID HOTCUR.PARSE("<<ENDL; OTL_STREAM("<<ENDL; HF<<ENDL; OUTF<<"LONG REPLACEVARNAME(STM,STM_TEXT,STMNAME); ); GENERATE_SELECT_LIST_STRUCT(SELSTR,STMNAME); IF(CMFLAG){ CM<< CUR(DB); CM<<ENDL; IF(CMFLAG&&!PLSQL_FLAG&&!SELECT_STM_FLAG) WHENEVER CURSOR GL_RPC_SAVE_"<<STMNAME<<"='sqlca.sqlerrd[2];"<<endl;' FOUND CM<<"{"<<ENDL; }ELSE{ OPENFUNCPROTOTYPE(HVD,STMNAME,CM,"_OPEN"); SQLCA.SQLERRD[2]='gl_rpc_save_"<<stmName<<";"<<endl;' );"<<ENDL; OPEN INT DECLARE _GET("<<STMNAME<<"* ; PRINTFSTMOFFS(STM, OPENFUNCPROTOTYPE(HVD,STMNAME,HF,"_OPEN"); OUTF<<"STM='"<<stm<<"'>set_commit(auto_commit);"<<ENDL; OUTF<<"{"<<ENDL; HF<<";"<<ENDL; OUTF<<ENDL; IF(STMARRSIZE OPENFUNCPROTOTYPE(HVD,STMNAME,HF,"_PUT"); CM<<"}"<<ENDL<<ENDL; } OPENFUNCPROTOTYPE(HVD,STMNAME,OUTF,"_PUT");>1) outf<<" PRINTFSTMOFFS(STM," )"<<ENDL; K3="0;k3<va_len;++k3)" SQL OUTF<<ENDL; FOR( IF(STMARRSIZE="=" ; WRITETEMPINPUTVAR(HVD[K3],STMNAME); COMMIT;"<<ENDL; ;"<<ENDL<<ENDL; EXEC IF(CMFLAG){ CM<<" CM<<"}"<<ENDL<<ENDL; OPENFUNCPROTOTYPE(HVD,STMNAME,CM,"_PUT"); CM<<"VOID OUTF<<"}"<<ENDL<<ENDL; OUTF<<" } OUTF<< ); OUTF<< ASSIGNINPUTVAR(HVD,STMNAME,STMARRSIZE); IF(AUTO_"<<STMNAME<<") CUR_"<<STMNAME<<"- EXEC SQL\N ++N_"<<STMNAME<<";"<<ENDL; _FLUSH();"<<ENDL; <<STMARRSIZE<< <<STMNAME<< CM<<ENDL; _FLUSH(VOID)"<<ENDL; 1){ }ELSE{ CM<<"{"<<ENDL; INT OUTF<<ENDL<<ENDL; IF(N_"<<STMNAME<<"="=">flush();"<<ENDL; DELETE _CLOSE(VOID);"<<ENDL; OUTF<<"{"<<ENDL; SQL IF(STMARRSIZE="=" COMMIT;"<<ENDL; EXEC IF(CMFLAG){ CM<<" HF<<"VOID CM<<"}"<<ENDL<<ENDL; CM<<"VOID OUTF<<"}"<<ENDL<<ENDL; OUTF<<" } IF(AUTO_"<<STMNAME<<") _CLOSE(VOID)"<<ENDL; CUR_"<<STMNAME<<";"<<ENDL; <<STMNAME<< COMMIT;"<<ENDL<<ENDL; OUTF<<"VOID _FLUSH(VOID)"<<ENDL; CM<<"{"<<ENDL; 1){ }ELSE{ _FLUSH(VOID);"<<ENDL; IF(N_"<<STMNAME<<">0){"<<ENDL<<ENDL; COUT<<"BUF='"<<buf<<"' GETSTM(0); NOT }"<<ENDL; HFILE1PROLOG(CHAR* #DEFINE="<<argv[5]<<endl; try{ db.rlogon(argv[1]); inf.open(argv[2],ios::in); if(!inf.good()){ cerr<<" <<ARGV[4]<<ENDL; DB.LOGOFF(); RETURN 1; } IF(ARGC==7||ARGC==8){ HF1FLAG=1; HF1.OPEN(ARGV[6],IOS::OUT); IF(!HF1.GOOD()){ CERR<< H-FILE="<<argv[4]; cout<<" HF1<<"}"<<ENDL; LINE _CLOSE(VOID);"<<ENDL; HELPMESSAGE(); {INT IF((ARGC!='6&&argc!7&&argc!8)||strcmp(argv[1],"-h")=' **** OUTF<<"{"<<ENDL; SQLPLSQL(VOID) RC="<<rc<<" , <<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<< SQL OUTF<<BUF<<ENDL; __CPLUSPLUS"<<ENDL; FILE <<ARGV[2]<<ENDL; DB.LOGOFF(); RETURN 1; } OUTF.OPEN(ARGV[3],IOS::OUT); IF(!OUTF.GOOD()){ CERR<< IF(BUF[0]!="#" HF1<<"#IFNDEF HF<<"#IFDEF I="0;i<dir_size;++i){" ;"<<ENDL<<ENDL; GETSTM EXEC <<" GETSTM(0,0,1); 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<<" HF1<<"EXTERN FOR(INT <<ARGV[3]<<ENDL; DB.LOGOFF(); RETURN 1; } HF.OPEN(ARGV[4],IOS::OUT); IF(!HF.GOOD()){ CERR<< HF<<"VOID ; PRINTFSTMOFFS(STM, HFILEPROLOG(CHAR* HF1<<ENDL; VOID GETSTM(1); PARSELINE(VOID) /* CHAR* IF(CMFLAG)CM<<BUF<<ENDL; }"<<ENDL<<ENDL; // HF1<<"\N\N"; OUTF<<"}"<<ENDL<<ENDL; CANNOT HF<<"#IFNDEF SQLSTRTYPE(VOID) { OUTF<<" #IFDEF } HF1<<"#DEFINE 0){ HF<<"}"<<ENDL; ); OUTF<< N_"<<STMNAME<<"='0;"<<endl;' MAIN(INT IF(AUTO_"<<STMNAME<<") _CLOSE(VOID)"<<ENDL; PROCESS __DEFINE"<<ENDL; FILE: SQLOUTSTM(VOID) CM<<"/*="=========End" ++SELECT_COUNT; HF1<<"#ENDIF"<<ENDL; HFILE1EPILOG(VOID) \"C\"{"<<ENDL; _FLUSH();"<<ENDL; RETURN <<STMNAME<<='==========*/"<<endl;' HF<<"EXTERN HFILEEPILOG FOUND: CREATE GETSTM(0,1); HFILEPROLOG 1; COMMIT;"<<ENDL<<ENDL; OUTF<<"VOID */ HF<<ENDL; OF ("<<LINE<<"):"<<BUF<<ENDL<<ENDL <<ARGV[6]<<ENDL; DB.LOGOFF(); RETURN 1; } } IF(ARGC==8){ CMFLAG=1; CM.OPEN(ARGV[7],IOS::OUT); IF(!CM.GOOD()){ CERR<< <<HDEFINE<<ENDL; HF<<ENDL; HF<< OUTPUT SQLSELECT(VOID) ARGV[]) :N_"<<STMNAME<<"\N <<HDEFINE<<ENDL; HF<< OUTF<<"/*="=========End" <<HDEFINE<< HF<<"\N\N"; COUT<<"CONNECT ARGC, HF1<<"#IFDEF <<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 NOT F1_IND_SEL[50]; F2_SEL[50]; IS SECTION; BEGIN CHAR BY CLOSE END_OF_DATA_SEL; ) SQL F_SEL="F;" IF(END_OF_DATA_SEL)RETURN ; F ROW_FETCH_COUNT_SEL="sqlca.sqlerrd[2]-rpc_save_Sel;" DO{ SHORT EXEC RPC_SAVE_SEL; END :F2_SEL:F2_IND_SEL; SEL_BREAKLOOP: SEL_BREAKLOOP; SEL_CUR; F1_SEL[50]; COUNT_SEL="0;" VOID DOUBLE FETCH LONG GOTO CUR_ROW_POS_SEL="0;" F2_IND_SEL[50]; SEL_CLOSE(VOID) TCSTR_31_SEL { F1 } CUR_ROW_POS_SEL; 0){ COUNT_SEL; :F1_SEL:F1_IND_SEL, INTO GL_RPC_SAVE_SEL; END_OF_DATA_SEL="1;" TYPE GL_RPC_SAVE_SEL="sqlca.sqlerrd[2];" ROW_FETCH_COUNT_SEL; OUT) OUT- 1; ++COUNT_SEL; TCSTR_31_SEL[31]; SEL_OPEN( IF(ROW_FETCH_COUNT_SEL="=" STRING(31); WHENEVER SEL_GET(SEL* RPC_SAVE_SEL="sqlca.sqlerrd[2];" IF(COUNT_SEL="=" FOUND ORDER SQLCA.SQLERRD[2]="gl_rpc_save_Sel;" OPEN SEL_CUR INT TYPEDEF DECLARE 0)RETURN SEL_SKIP: SEL_SKIP; IF(SQLCA.SQLERRD[2]-RPC_SAVE_SEL="=">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 DELETE (*STR_SEL)<<F; BY F1", VOID SEL_CLOSE(VOID) { } *DB IF(STR_SEL- ); OUT) STR_SEL; SEL_GET(SEL* ORDER INT >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; INS_FLUSH(VOID) (*CUR_INS)<<F2; 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

    1