Logo Search packages:      
Sourcecode: edbrowse version File versions  Download package

dbinfx.c

#include <sqlhdr.h>
#include <sqliapi.h>
static const char _Cn1[] = "blobinsert";
#line 1 "dbinfx.ec"
/*********************************************************************
dbinfx.ec: C-level interface to SQL.
This is a layer above esql/c,
since embedded SQL is often difficult to use, especially for new programmers.
Most SQL queries are relatively simple, whence the esql API is overkill.
Why mess with cryptic $directives when you can write:
sql_select("select this, that from table1, table2 where keycolumn = %d",
27, &this, &that);

More important, this API automatically aborts (or longjumps) if an error
occurs, unless that error has been specifically trapped by the program.
This minimizes application-level error-leg programming,
thereby reducing the code by as much as 1/3.
To accomplish this, the errorPrint() function,
supplied by the application, must never return.
We assume it passes the error message
to stderr and to a logfile,
and then exits, or longjumps to a recovery point.

Note that this API works within the context of our own C programming
environment.

Note that dbapi.h does NOT include the Informix header files.
That would violate the spirit of this layer,
which attempts to sheild the application from the details of the SQL API.
If the application needed to see anything in the Informix header files,
we would be doing something wrong.
*********************************************************************/

/* bring in the necessary Informix headers */
/* 
 * $include sqlca;
 */
#line 31 "dbinfx.ec"

#line 31 "dbinfx.ec"
#line 1 "/opt/informix/incl/esql/sqlca.h"
/****************************************************************************
 *
 *                               IBM INC.
 *
 *                           PROPRIETARY DATA
 *
 * Licensed Material - Property Of IBM
 *
 * "Restricted Materials of IBM"
 *
 * IBM Informix Client SDK
 *
 * (c)  Copyright IBM Corporation 1997, 2004. All rights reserved.
 *
 *  Title:  sqlca.h
 *  Description:
 *          SQL Control Area
 *
 ***************************************************************************
 */

#ifndef SQLCA_INCL
#define SQLCA_INCL

#include "ifxtypes.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef struct sqlca_s
    {
    int4 sqlcode;
#ifdef DB2CLI
    char sqlerrm[600]; /* error message parameters */
#else /* DB2CLI */
    char sqlerrm[72]; /* error message parameters */
#endif /* DB2CLI */
    char sqlerrp[8];
    int4 sqlerrd[6];
                /* 0 - estimated number of rows returned */
                /* 1 - serial value after insert or  ISAM error code */
                /* 2 - number of rows processed */
                /* 3 - estimated cost */
                /* 4 - offset of the error into the SQL statement */
                /* 5 - rowid after insert  */
#ifdef _FGL_
    char sqlawarn[8];
#else
    struct sqlcaw_s
      {
      char sqlwarn0; /* = W if any of sqlwarn[1-7] = W */
      char sqlwarn1; /* = W if any truncation occurred or
                        database has transactions or
                          no privileges revoked */
      char sqlwarn2; /* = W if a null value returned or
                        ANSI database */
      char sqlwarn3; /* = W if no. in select list != no. in into list or
                        turbo backend or no privileges granted */
      char sqlwarn4; /* = W if no where clause on prepared update, delete or
                        incompatible float format */
      char sqlwarn5; /* = W if non-ANSI statement */
      char sqlwarn6; /* = W if server is in data replication secondary mode */
      char sqlwarn7; /* = W if database locale is different from proc_locale
                          = W if backend XPS and if explain avoid_execute is set
                              (for select, insert, delete and update only)
                  */
      } sqlwarn;
#endif
    } ifx_sqlca_t;

/* NOTE: 4gl assumes that the sqlwarn structure can be defined as
 *    sqlawarn -- an 8 character string, because single-char
 *    variables are not recognized in 4gl.
 *
 * If this structure should change, the code generated by 4gl compiler
 *    must also change
 */

#ifdef VMS
noshare
#endif /* VMS */

#define SQLNOTFOUND 100

#ifndef IFX_THREAD
#ifdef DB2CLI
#define sqlca ifmxsqlca
extern struct sqlca_s sqlca;
#else /* DB2CLI */
extern struct sqlca_s sqlca;
#endif /* DB2CLI */

extern int4 SQLCODE;

extern char SQLSTATE[];
#else /* IFX_THREAD */
extern int4 * ifx_sqlcode();
extern struct sqlca_s * ifx_sqlca();
#define SQLCODE (*(ifx_sqlcode()))
#define SQLSTATE ((char *)(ifx_sqlstate()))
#define sqlca (*(ifx_sqlca()))
#endif /* IFX_THREAD */

#ifdef __cplusplus
}
#endif

#endif /* SQLCA_INCL */

#line 110 "/opt/informix/incl/esql/sqlca.h"
/* 
 * $include sqltypes;
 */
#line 32 "dbinfx.ec"

#line 32 "dbinfx.ec"
#line 1 "/opt/informix/incl/esql/sqltypes.h"
/****************************************************************************
 *
 *                           IBM Corporation.
 *
 *                           PROPRIETARY DATA
 *
 * Licensed Material - Property Of IBM
 *
 * "Restricted Materials of IBM"
 *
 * IBM Informix Client SDK
 *
 * (c)  Copyright IBM Corporation 1985, 2004. All rights reserved.
 *
 *  Title:    sqltypes.h
 *  Description:  type definition
 *
 ***************************************************************************
 */

#ifndef CCHARTYPE

#include "ifxtypes.h"

/***********************
 * ++++ CAUTION ++++
 * Any new type to be added to the following lists should not
 * have the following bit pattern (binary short):
 *
 *    xxxxx111xxxxxxxx
 *
 * where x can be either 0 or 1.
 *
 * This is due to the use of the bits as SQLNONULL, SQLHOST and SQLNETFLT
 * (see below).
 *
 * FAILURE TO DO SO WOULD RESULT IN POSSIBLE ERRORS DURING CONVERSIONS.
 *
 ***********************/

 /* C language types */

#define CCHARTYPE 100
#define CSHORTTYPE      101
#define CINTTYPE  102
#define CLONGTYPE 103
#define CFLOATTYPE      104
#define CDOUBLETYPE     105
#define CDECIMALTYPE    107
#define CFIXCHARTYPE    108
#define CSTRINGTYPE     109
#define CDATETYPE 110
#define CMONEYTYPE      111
#define CDTIMETYPE      112
#define CLOCATORTYPE    113
#define CVCHARTYPE      114
#define CINVTYPE  115
#define CFILETYPE 116
#define CINT8TYPE 117
#define CCOLLTYPE       118
#define CLVCHARTYPE     119
#define CFIXBINTYPE     120
#define CVARBINTYPE     121
#define CBOOLTYPE       122
#define CROWTYPE        123
#define CLVCHARPTRTYPE  124
#define CTYPEMAX  25

#define USERCOLL(x)     ((x))

#define COLLMASK        0x007F  /* mask out CTYPEDCOLL or CCLIENTCOLL */
                                /* bit set for CCOLLTYPE or CROWTYPE */
#define ISCOLLECTIONVAR(n)  (((n) & COLLMASK) == CCOLLTYPE)
#define ISROWVAR(n)         (((n) & COLLMASK) == CROWTYPE)
#define ISCOLL_OR_ROWVAR(n)   ((ISCOLLECTIONVAR(n)) || (ISROWVAR(n)))
#define CCLIENTCOLL     SQLCLIENTCOLL /* client collection bit */
#define ISCLIENTCOLLECTION(n) (ISCOLLECTIONVAR(n) && ((n) & CCLIENTCOLL))
#define ISCLIENTCOMPLEX(n)    ((ISCLIENTCOLLECTION(n)) || (ISROWVAR(n)))

/*
 * The following are for client side only. They are included here
 * because of the above related definitions.
 */
#define CTYPEDCOLL       0x0080  /* typed collection bit */
#define CTYPEDCOLLUNMASK 0xFF7F  /* unmask typed collection bit */
#define ISTYPEDCOLLECTION(n)  (ISCOLLECTIONVAR(n) && ((n) & CTYPEDCOLL))
#define ISTYPEDROW(n)         (ISROWVAR(n) && ((n) & CTYPEDCOLL))
#define ISTYPEDCOLL_OR_ROW(n)  ( (ISTYPEDCOLLECTION(n)) || (ISTYPEDROW(n)) )

/*
 * Define all possible database types
 *   include C-ISAM types here as well as in isam.h
 */

#define SQLCHAR         0
#define SQLSMINT  1
#define SQLINT          2
#define SQLFLOAT  3
#define SQLSMFLOAT      4
#define SQLDECIMAL      5
#define SQLSERIAL 6
#define SQLDATE         7
#define SQLMONEY  8
#define SQLNULL         9
#define SQLDTIME  10
#define SQLBYTES  11
#define SQLTEXT         12
#define SQLVCHAR  13
#define SQLINTERVAL     14
#define SQLNCHAR  15
#define SQLNVCHAR 16
#define SQLINT8         17
#define SQLSERIAL8      18
#define SQLSET          19
#define SQLMULTISET     20
#define SQLLIST         21
#define SQLROW          22
#define SQLCOLLECTION   23
#define SQLROWREF       24
/*
 * Note: SQLXXX values from 25 through 39 are reserved to avoid collision
 *       with reserved PTXXX values in that same range. See p_types_t.h
 *
 * REFSER8: create tab with ref: referenced serial 8 rsam counter
 *    this is essentially a SERIAL8, but is an additional rsam counter
 *    this type only lives in the system catalogs and when read from
 *    disk is converted to SQLSERIAL8 with CD_REFSER8 set in ddcol_t
 *      ddc_flags we must distinguish from SERIAL8 to allow both
 *      counters in one tab
 */
#define SQLUDTVAR       40
#define SQLUDTFIXED     41
#define SQLREFSER8      42

/* These types are used by FE, they are not real major types in BE */
#define SQLLVARCHAR     43
#define SQLSENDRECV     44
#define SQLBOOL         45
#define SQLIMPEXP       46
#define SQLIMPEXPBIN    47

/* This type is used by the UDR code to track default parameters,
   it is not a real major type in BE */
#define SQLUDRDEFAULT   48
#define SQLDBSENDRECV   49
#define SQLSRVSENDRECV  50

/* Type used by DESCRIBE INPUT stmt to indicate input parameters whose
   types cannot be determined by the server */
#define SQLUNKNOWN      51

#define SQLMAXTYPES     52

#define SQLLABEL        SQLINT

#define SQLTYPE         0xFF  /* type mask            */

#define SQLNONULL 0x0100      /* disallow nulls */
/* a bit to show that the value is from a host variable */
#define SQLHOST         0x0200      /* Value is from host var. */
#define SQLNETFLT 0x0400      /* float-to-decimal for networked backend */
#define SQLDISTINCT     0x0800      /* distinct bit         */
#define SQLNAMED  0x1000      /* Named row type vs row type */
#define SQLDLVARCHAR    0x2000  /* Distinct of lvarchar */
#define SQLDBOOLEAN     0x4000  /* Distinct of boolean */
#define SQLCLIENTCOLL   0x8000  /* Collection is processed on client */

/* we are overloading SQLDBOOLEAN for use with row types */
#define SQLVARROWTYPE   0x4000  /* varlen row type */

/* We overload SQLNAMED for use with constructor type, this flag
 * distinguish constructor types from other UDT types.
 *
 * Please do not test this bit directly, use macro ISCSTTYPE() instead.
 */
#define SQLCSTTYPE      0x1000      /* constructor type flag */

#define TYPEIDMASK      (SQLTYPE | SQLDISTINCT | SQLNAMED | \
                         SQLDLVARCHAR | SQLDBOOLEAN )

#define SIZCHAR         1
#define SIZSMINT  2
#define SIZINT          4
#define SIZFLOAT  (sizeof(double))
#define SIZSMFLOAT      (sizeof(float))
#define SIZDECIMAL      17    /* decimal(32) */
#define SIZSERIAL 4
#define SIZDATE         4
#define SIZMONEY  17    /* decimal(32) */
#define SIZDTIME  7     /* decimal(12,0) */
#define SIZVCHAR  1
#define SIZINT8         (sizeof(short) + sizeof(muint) * 2)
#define SIZSERIAL8      SIZINT8
#define SIZCOLL         sizeof (ifx_collection_t)
#define SIZSET          SIZCOLL
#define SIZMULTISET     SIZCOLL
#define SIZLIST         SIZCOLL
#define SIZROWREF sizeof (ifx_ref_t)

#define MASKNONULL(t)   ((t) & (SQLTYPE))

/*
 * As part of an sqlda structure from DESCRIBE, you can test whether a
 * column accepts or can return nulls, using the expression:
 *     ISCOLUMNULLABLE(ud->sqlvar[n].sqlflags)
 * (for sqlda structure pointer ud and column number n).
 */

#define ISCOLUMNULLABLE(t)    (((t) & (SQLNONULL)) ? 0 : 1)
#define ISSQLTYPE(t)    (MASKNONULL(t) >= SQLCHAR && MASKNONULL(t) < SQLMAXTYPES)

#define DECCOLLEN       8192    /* decimal size definition for DEC(32,0) in syscolumns */


/*
 * SQL types macros
 */
#define ISDECTYPE(t)          (MASKNONULL(t) == SQLDECIMAL || \
                         MASKNONULL(t) == SQLMONEY || \
                         MASKNONULL(t) == SQLDTIME || \
                         MASKNONULL(t) == SQLINTERVAL)
#define ISNUMERICTYPE(t)      (MASKNONULL(t) == SQLSMINT || \
                         MASKNONULL(t) == SQLINT || \
                         MASKNONULL(t) == SQLINT8 || \
                         MASKNONULL(t) == SQLFLOAT || \
                         MASKNONULL(t) == SQLSMFLOAT || \
                         MASKNONULL(t) == SQLMONEY || \
                         MASKNONULL(t) == SQLSERIAL || \
                         MASKNONULL(t) == SQLSERIAL8 || \
                         MASKNONULL(t) == SQLDECIMAL)
#define ISBLOBTYPE(type)      (ISBYTESTYPE (type) || ISTEXTTYPE(type))
#define ISBYTESTYPE(type)     (MASKNONULL(type) == SQLBYTES)
#define ISTEXTTYPE(type)      (MASKNONULL(type) == SQLTEXT)
#define ISSQLHOST(t)            (((t) & SQLHOST) == SQLHOST)

#ifndef NLS
#define ISVCTYPE(t)           (MASKNONULL(t) == SQLVCHAR)
#define ISCHARTYPE(t)         (MASKNONULL(t) == SQLCHAR)
#else
#define ISVCTYPE(t)           (MASKNONULL(t) == SQLVCHAR || \
                         MASKNONULL(t) == SQLNVCHAR)
#define ISCHARTYPE(t)         (MASKNONULL(t) == SQLCHAR || \
                         MASKNONULL(t) == SQLNCHAR)
#define ISNSTRINGTYPE(t)      (MASKNONULL(t) == SQLNCHAR || \
                         MASKNONULL(t) == SQLNVCHAR)
#endif /* NLS */

#define ISSTRINGTYPE(t)       (ISVCTYPE(t) || ISCHARTYPE(t))

#define     ISUDTVARTYPE(t)         (MASKNONULL(t) == SQLUDTVAR)
#define     ISUDTFIXEDTYPE(t) (MASKNONULL(t) == SQLUDTFIXED)
#define     ISUDTTYPE(t)            (ISUDTVARTYPE(t) || ISUDTFIXEDTYPE(t))

#define     ISCOMPLEXTYPE(t)  (ISROWTYPE(t) || ISCOLLTYPE(t))
#define     ISROWTYPE(t)            (MASKNONULL(t) == SQLROW)
#define     ISLISTTYPE(t)           (MASKNONULL(t) == SQLLIST)
#define     ISMULTISETTYPE(t) (MASKNONULL(t) == SQLMULTISET)
#define     ISREFTYPE(t)            (MASKNONULL(t) == SQLROWREF)
#define     ISSETTYPE(t)            (MASKNONULL(t) == SQLSET)
#define     ISCOLLECTTYPE(t)  (MASKNONULL(t) == SQLCOLLECTION)
#define ISCOLLTYPE(t)         (ISSETTYPE(t) || ISMULTISETTYPE(t) ||\
                         ISLISTTYPE(t) || ISCOLLECTTYPE(t))

#define ISSERIALTYPE(t)       (((t) & SQLTYPE) == SQLSERIAL || \
                         ((t) & SQLTYPE) == SQLSERIAL8 || \
                         ((t) & SQLTYPE) == SQLREFSER8)

#define ISDISTINCTTYPE(t)     ((t) & SQLDISTINCT)
#define ISCSTTYPE(t)          (ISUDTTYPE(t) && ((t) & SQLCSTTYPE))

/* these macros are used to distinguish NLS char types and non-nls (ASCII)
 * char types
 */
#define ISNONNLSCHAR(t)       (MASKNONULL(t) == SQLCHAR || \
                         MASKNONULL(t) == SQLVCHAR)

/* these macros should be used in case statements
 */
#ifndef NLS
#define CHARCASE        SQLCHAR
#define VCHARCASE       SQLVCHAR
#else
#define CHARCASE        SQLCHAR: case SQLNCHAR
#define VCHARCASE       SQLVCHAR: case SQLNVCHAR
#endif /* NLS */

#define UDTCASE               SQLUDTVAR: case SQLUDTFIXED

/*
 * C types macros
 */
#define ISBLOBCTYPE(type)     (ISLOCTYPE(type) || ISFILETYPE(type))
#define ISLOCTYPE(type)       (MASKNONULL(type) == CLOCATORTYPE)
#define ISFILETYPE(type)      (MASKNONULL(type) == CFILETYPE)
#define ISLVCHARCTYPE(type)     (MASKNONULL(type) == CLVCHARTYPE)
#define ISLVCHARCPTRTYPE(type)  (MASKNONULL(type) == CLVCHARPTRTYPE)
#define ISFIXBINCTYPE(type)     (MASKNONULL(type) == CFIXBINTYPE)
#define ISVARBINCTYPE(type)     (MASKNONULL(type) == CVARBINTYPE)
#define ISBOOLCTYPE(type)       (MASKNONULL(type) == CBOOLTYPE)


#define ISOPTICALCOL(type)    (type == 'O')

#define DEFDECIMAL      9     /* default decimal(16) size */
#define DEFMONEY  9     /* default decimal(16) size */

#define SYSPUBLIC "public"

/*
 * if an SQL type is specified, convert to default C type
 *  map C int to either short or long
 */


#define TYPEMAX   SQLMAXTYPES

extern int2 sqlctype[];

#define toctype(ctype, type) \
    { \
    if (type == CINTTYPE) \
    { \
      if (sizeof(mint) == sizeof(mlong)) \
          { ctype = type = CLONGTYPE; } \
      else if (sizeof(mint) == sizeof(int2)) \
          { ctype = type = CSHORTTYPE; } \
      else \
          { ctype = CLONGTYPE; type = CINTTYPE; } \
    } \
    else if (type >= 0 && type < TYPEMAX) \
        ctype = sqlctype[type]; \
    else \
        ctype = type; \
    }



/* Extended ID definitions for predefined UDT's */
/* These can not be changed because sqli is using
 * them.  If we change them, the client has to recompile.
 * NOTE: This order must match the definitions in boot90.sql
 */

#define XID_LVARCHAR            1
#define XID_SENDRECV            2
#define XID_IMPEXP              3
#define XID_IMPEXPBIN           4
#define XID_BOOLEAN             5
#define XID_POINTER             6
#define XID_INDEXKEYARRAY       7
#define XID_RTNPARAMTYPES     8
#define XID_SELFUNCARGS         9
#define XID_BLOB                10
#define XID_CLOB                11
#define XID_LOLIST              12
#define XID_IFX_LO_SPEC       13
#define XID_IFX_LO_STAT       14
#define XID_STAT                15
#define XID_CLIENTBINVAL        16
#define XID_UDTMODIFIERS      17
#define XID_AGGMODIFIERS      18
#define XID_UDRMODIFIERS      19
#define XID_GUID              20
#define XID_DBSENDRECV          21
#define XID_SRVSENDRECV         22
#define XID_FUNCARG           23

/* Max size definitions for the predefined UDT's.
 * Only a few are currently defined.
 */
#define SIZINDEXKEYARRAY      1024
#define SIZLVARCHAR           2048
#define SIZRTNPARAMTYPES      4096
#define SIZSTAT                 272
#define SIZGUID               16

/* Alignment required by predefined UDT's.
 * Only a few are currently defined.  At a minimum,
 * all with alignment not 1 should be defined here
 * and used throughout the code.
 */
#define ALNINDEXKEYARRAY      4
#define ALNSTAT                 8


#define USER_XTDTYPEID_START  2048

/* These macros should be used to test lvarchar and distinct of lvarchar */

#define ISLVARCHARXTYPE(t, xid)  (ISUDTTYPE((t)) && (xid) == XID_LVARCHAR)
#define ISDISTINCTLVARCHAR(t) ((t) & SQLDLVARCHAR)
#define LIKELVARCHARXTYPE(t,xid) ((ISLVARCHARXTYPE(t,xid))||\
                           ISDISTINCTLVARCHAR(t))

#define ISSMARTBLOB(type, xid)  (ISUDTTYPE((type)) && \
                            ((xid == XID_CLOB) || (xid == XID_BLOB)))

/* These macros should be used to test boolean and distinct of boolean */
#define ISBOOLEANXTYPE(t, xid)  (ISUDTTYPE((t)) && (xid) == XID_BOOLEAN)
#define ISDISTINCTBOOLEAN(t)  (((t) & SQLDBOOLEAN) && \
                            (ISUDTTYPE(t)))
#define LIKEBOOLEANXTYPE(t,xid) ((ISBOOLEANXTYPE(t,xid))||\
                          ISDISTINCTBOOLEAN(t))

#define ISFIXLENGTHTYPE(t)    (!ISBYTESTYPE(t) && !ISTEXTTYPE(t) \
                              && !ISCOMPLEXTYPE(t) \
                              && !ISUDTVARTYPE(t) \
                              && !ISVCTYPE(t))
#endif /* CCHARTYPE */
#line 409 "/opt/informix/incl/esql/sqltypes.h"
/* 
 * $include sqlda;
 */
#line 33 "dbinfx.ec"

#line 33 "dbinfx.ec"
#line 1 "/opt/informix/incl/esql/sqlda.h"
/****************************************************************************
 *
 *                           IBM Corporation.
 *
 *                           PROPRIETARY DATA
 *
 * Licensed Material - Property Of IBM
 *
 * "Restricted Materials of IBM"
 *
 * IBM Informix Client SDK
 *
 * (c)  Copyright IBM Corporation 1985, 2004. All rights reserved.
 *
 *  Title:     sqlda.h
 *  Description:   SQL Data Description Area
 *
 ***************************************************************************
 */


#ifndef _SQLDA
#define _SQLDA

#include "ifxtypes.h"

typedef struct sqlvar_struct
    {
    int2 sqltype;       /* variable type        */
    int4 sqllen;        /* length in bytes            */
    char *sqldata;            /* pointer to data            */
    int2 *sqlind;       /* pointer to indicator       */
    char  *sqlname;           /* variable name        */
    char  *sqlformat;         /* reserved for future use    */
    int2 sqlitype;            /* ind variable type          */
    int2 sqlilen;       /* ind length in bytes        */
    char *sqlidata;           /* ind data pointer           */
    int4  sqlxid;               /* extended id type             */
    char *sqltypename;          /* extended type name           */
    int2 sqltypelen;            /* length of extended type name */
    int2 sqlownerlen;           /* length of owner name         */
    int2 sqlsourcetype; /* source type for distinct of built-ins */
    char *sqlownername;         /* owner name                   */
    int4 sqlsourceid;         /* extended id of source type   */

    /*
     * sqlilongdata is new.  It supports data that exceeds the 32k
     * limit.  sqlilen and sqlidata are for backward compatibility
     * and they have maximum value of <32K.
     */
    char *sqlilongdata;       /* for data field beyond 32K  */

    /*
     * As part of an SQL DESCRIPTOR (ALLOCATE DESCRIPTOR, etc), sqlflags is
     * reserved for internal use.
     * As part of an sqlda structure from DESCRIBE, you can test whether a
     * column accepts or can return nulls, using the expression:
     *     ISCOLUMNULLABLE(ud->sqlvar[n].sqlflags)
     * (for sqlda structure pointer ud and column number n).
     */

    int4 sqlflags;
    void *sqlreserved;        /* reserved for future use      */
    } ifx_sqlvar_t;

typedef struct sqlda
    {
    int2 sqld;
    ifx_sqlvar_t *sqlvar;
    char desc_name[19];       /* descriptor name            */
    int2 desc_occ;            /* size of sqlda structure    */
    struct sqlda *desc_next;  /* pointer to next sqlda struct */
    void *reserved;           /* reserved for future use */
    } ifx_sqlda_t;

#endif /* _SQLDA */
#line 76 "/opt/informix/incl/esql/sqlda.h"
/* 
 * $include locator;
 */
#line 34 "dbinfx.ec"

#line 34 "dbinfx.ec"
#line 1 "/opt/informix/incl/esql/locator.h"
/****************************************************************************
 *
 *                               IBM INC.
 *
 *                           PROPRIETARY DATA
 *
 * Licensed Material - Property Of IBM
 *
 * "Restricted Materials of IBM"
 *
 * IBM Informix Client SDK
 *
 * (c)  Copyright IBM Corporation 1997, 2004. All rights reserved.
 *
 *  Title:  locator.h
 *
 *  Description:
 *              'locator.h' defines 'loc_t' the locator struct.
 *
 ***************************************************************************
 */

#ifndef LOCATOR_INCL          /* avoid multiple includes */
#define LOCATOR_INCL

#include "ifxtypes.h"

#include "int8.h"

/*
Locators are used to store TEXT or BYTE fields (blobs) in ESQL
programs.  The "loc_t" structure is described below.  Fields denoted
USER should be set by the user program and will be examined by the DBMS
system.  Those denoted SYSTEM are set by the system and may be examined
by the user program.  Those denoted INTERNAL contain data only the
system manupilates and examines.

If "loc_loctype" is set to LOCMEMORY, then the blob is stored in
primary memory.  The memory buffer is pointed to by the variant
"loc_buffer".  The field "loc_bufsize" gives the size of "loc_buffer".
If the "loc_bufsize" is set to "-1" and "loc_mflags" is set to "0"
and the locator is used for a fetch, memory is obtained using "malloc"
and "loc_buffer" and "loc_bufsize" are set.

If "loc_loctype" is set to LOCFILE, then the blob is stored in a file.
The file descriptor of an open operating system file is specified in
"loc_fd".

If "loc_loctype" is set to LOCFNAME, the the blob is stored in a file
and the name of the file is given.  The DBMS will open or created the
file at the correct time and in the correct mode.

If the "loc_loctype" is set to LOCUSER, "loc_(open/close/read/write)"
are called.  If the blob is an input to a SQL statement, "loc_open" is
called with the parameter "LOC_RONLY".  If the blob is an output target
for an SQL statement, "loc_open" is called with the parameter
"LOC_WONLY".

"loc_size" specifies the maximum number of bytes to use when the
locator is an input target to an SQL statement. It specifies the number
of bytes returned if the locator is an output target.  If "loc_loctype"
is LOCFILE or LOCUSER, it can be set to -1 to indicate transfer until
end-of-file.

"loc_indicator" is set by the user to -1 to indicate a NULL blob.  It
will be  set to -1 if a NULL blob is retrieved.  If the blob to be
retrieved will not fit in the space provided, the indicator contains
the size of the blob.

"loc_status" is the status return of locator operations.

"loc_type" is the "blob" type (SQLTEXT, SQLBYTES, ...).

"loc_user_env" is a pointer for the user's private use. It is neither
set nor examined by the system.  "loc_user_env" as well as the
"loc_union" fieds may be used by user supplied routines to store and
communicate information.
*/

typedef struct tag_loc_t
    {
    int2 loc_loctype;         /* USER: type of locator - see below      */
    union               /* variant on 'loc'                     */
      {
      struct                  /* case LOCMEMORY                       */
          {
          int4  lc_bufsize;   /* USER: buffer size */
          char *lc_buffer;    /* USER: memory buffer to use       */
          char *lc_currdata_p;/* INTERNAL: current memory buffer  */
          mint   lc_mflags;   /* USER/INTERNAL: memory flags            */
                        /*                (see below) */
          } lc_mem;

      struct                  /* cases L0CFNAME & LOCFILE         */
          {
          char *lc_fname;     /* USER: file name                  */
          mint  lc_mode;      /* USER: perm. bits used if creating      */
          mint  lc_fd;  /* USER: os file descriptior        */
          int4  lc_position;  /* INTERNAL: seek position          */
          } lc_file;
      } lc_union;

    int4  loc_indicator;      /* USER SYSTEM: indicator           */
    int4  loc_type;           /* USER SYSTEM: type of blob        */
    int4  loc_size;           /* USER SYSTEM: num bytes in blob or -1   */
    mint  loc_status;         /* SYSTEM: status return of locator ops   */
    char *loc_user_env;       /* USER: for the user's PRIVATE use */
    int4  loc_xfercount;      /* INTERNAL/SYSTEM: Transfer count  */

#if defined(__STDC__) || defined(__cplusplus)
    mint (*loc_open)(struct tag_loc_t *loc, mint flag, mint bsize);
    mint (*loc_close)(struct tag_loc_t *loc);
    mint (*loc_read)(struct tag_loc_t *loc, char *buffer, mint buflen);
    mint (*loc_write)(struct tag_loc_t *loc, char *buffer, mint buflen);
#else
    mint (*loc_open)();
    mint (*loc_close)();
    mint (*loc_read)();
    mint (*loc_write)();
#endif /* defined(__STDC__) || defined(__cplusplus) */

    mint   loc_oflags;        /* USER/INTERNAL: see flag definitions below */
    } loc_t;

#define     loc_fname   lc_union.lc_file.lc_fname
#define loc_fd          lc_union.lc_file.lc_fd
#define loc_position    lc_union.lc_file.lc_position  
#define loc_bufsize     lc_union.lc_mem.lc_bufsize
#define loc_buffer      lc_union.lc_mem.lc_buffer
#define loc_currdata_p  lc_union.lc_mem.lc_currdata_p
#define loc_mflags      lc_union.lc_mem.lc_mflags

/* Enumeration literals for loc_loctype */

#define LOCMEMORY 1           /* memory storage */
#define LOCFNAME  2           /* File storage with file name */
#define LOCFILE         3           /* File storage with fd */
#define     LOCUSER           4           /* User define functions */

/* passed to loc_open and stored in loc_oflags */
#define LOC_RONLY 0x1         /* read only */
#define LOC_WONLY 0x2         /* write only */

/* LOC_APPEND can be set when the locator is created
 * if the file is to be appended to instead of created
 */
#define LOC_APPEND      0x4         /* write with append */
#define LOC_TEMPFILE    0x8         /* 4GL tempfile blob */

/* LOC_USEALL can be set to force the maximum size of the blob to always be
 * used when the blob is an input source.  This is the same as setting the
 * loc_size field to -1.  Good for LOCFILE or LOCFNAME blobs only.
 */
#define LOC_USEALL      0x10        /* ignore loc_size field */
#define LOC_DESCRIPTOR  0x20        /* BLOB is optical descriptor */

/* length of the encoded descriptor text */
#define LOC_DESCRIPTOR_SIZE 112

/* passed to loc_open and stored in loc_mflags */
#define LOC_ALLOC 0x1         /* free and alloc memory */

/* Flags to indicate if file is on the server or client */
#define LO_CLIENT_FILE  0x20000000
#define LO_SERVER_FILE  0x10000000

/*******************************************************************************
 * File open flags used for operating system file open via
 *    - ifx_lo_copy_to_lo
 *    - ifx_lo_copy_to_file
 *    - ifx_file_to_file
 *
 ******************************************************************************/

#define LO_O_EXCL             0x00000001 /* fail if file exists */
#define LO_O_APPEND           0x00000002 /* append to end of file */
#define LO_O_TRUNC            0x00000004 /* turncate to 0 if file exists */
#define LO_O_RDWR             0x00000008 /* read/write (default) */
#define LO_O_RDONLY           0x00000010 /* read-only (from-flags only) */
#define LO_O_WRONLY           0x00000020 /* write-only (to-flags only) */
#define LO_O_BINARY           0x00000040 /* binary-mode (default) */
#define LO_O_TEXT             0x00000080 /* text-mode (default off)*/


/*******************************************************************************
 *
 * Smartblob Definitions
 *
 ******************************************************************************/

/******************************************************************************
 * Open flags: see ESQL/C documentation for further explanation.
 *
 * LO_APPEND - Positions the seek position to end-of-file + 1. Affects write
 * operations. Reads can still seek anywhere in the LO. Writes always append.
 *
 * LO_SEQUENTIAL - If set overrides optimizer decision. Indicates that
 * reads are sequential in either forward or reverse direction.
 *
 * LO_RANDOM - If set overrides optimizer decision. Indicates that I/O is
 * random and that the system should not read-ahead.
 * LO_FORWARD - Only used for sequential access. Indicates that the sequential
 * access will be in a forward direction, i.e. from low offset to higher offset.
 * LO_REVERSE - Only used for sequential access. Indicates that the sequential
 * access will be in a reverse direction.
 *
 * LO_BUFFER - If set overrides optimizer decision. I/O goes through the
 * buffer pool.
 *
 * LO_NOBUFFER - If set then I/O does not use the buffer pool.
 ******************************************************************************/

#define LO_APPEND 0x1
#define LO_WRONLY       0x2
#define LO_RDONLY       0x4   /* default */
#define LO_RDWR         0x8
#define LO_DIRTY_READ   0x10

#define LO_RANDOM 0x20  /* default is determined by optimizer */
#define LO_SEQUENTIAL   0x40  /* default is determined by optimizer */

#define LO_FORWARD      0x80  /* default */
#define LO_REVERSE      0x100

#define LO_BUFFER 0x200 /* default is determined by optimizer */
#define LO_NOBUFFER     0x400 /* default is determined by optimizer */
#define LO_NODIRTY_READ 0x800

#define     LO_LOCKALL  0x1000      /* default */
#define     LO_LOCKRANGE      0x2000

#ifndef REMOVE_VECTORIO
#define LO_VECTORIO     0x4000
#endif

/*
 *  Another set of open flags are defined to make the flags more meaningful
 */

#define LO_OPEN_APPEND       LO_APPEND
#define LO_OPEN_WRONLY       LO_WRONLY
#define LO_OPEN_RDONLY       LO_RDONLY     /* default */
#define LO_OPEN_RDWR         LO_RDWR
#define LO_OPEN_DIRTY_READ   LO_DIRTY_READ

#define LO_OPEN_RANDOM       LO_RANDOM      /* default is determined by optimizer */
#define LO_OPEN_SEQUENTIAL   LO_SEQUENTIAL  /* default is determined by optimizer */

#define LO_OPEN_FORWARD      LO_FORWARD    /* default */
#define LO_OPEN_REVERSE      LO_REVERSE

#define LO_OPEN_BUFFER       LO_BUFFER     /* default is determined by optimizer */
#define LO_OPEN_NOBUFFER     LO_NOBUFFER   /* default is determined by optimizer */
#define LO_OPEN_NODIRTY_READ LO_NODIRTY_READ

#define LO_OPEN_LOCKALL      LO_LOCKALL  /* default */
#define LO_OPEN_LOCKRANGE    LO_LOCKRANGE

/* When setting the MI_LO_NOBUFFER flag for write operations, please
 * don't set this flag if the object is small. It usually causes a synchronous
 * flush of the log and a synchronous flush of pages written - this is
 * very slow. Instead use buffered I/O for small writes.
 */
#define LO_NOBUFFER_SIZE_THRESHOLD 8080

/*see Informix internal use file /vobs/tristarp/incl/sblob.h for other flags*/

/*******************************************************************************
 * LO create-time flags:
 *
 * Bitmask - Set/Get via ifx_lo_specset_flags() on ifx_lo_create_spec_t.
 *
 * New applications should use the flags which begin LO_ATTR_
 * The second set of flags are defined for backward compatibility only.
 ******************************************************************************/

#define LO_ATTR_LOG                          0x0001
#define LO_ATTR_NOLOG                        0x0002
#define LO_ATTR_DELAY_LOG                    0x0004
#define LO_ATTR_KEEP_LASTACCESS_TIME         0x0008
#define LO_ATTR_NOKEEP_LASTACCESS_TIME       0x0010
#define LO_ATTR_HIGH_INTEG                   0x0020
#define LO_ATTR_MODERATE_INTEG               0x0040
#define LO_ATTR_TEMP                         0x0080

/* these 7 values are defined for backward compatibility only */
#define LO_LOG                          0x0001
#define LO_NOLOG                        0x0002
#define LO_DELAY_LOG                    0x0004
#define LO_KEEP_LASTACCESS_TIME         0x0008
#define LO_NOKEEP_LASTACCESS_TIME       0x0010
#define LO_HIGH_INTEG                   0x0020
#define LO_MODERATE_INTEG               0x0040
#define LO_TEMP                         0x0080

/* these flags are defined to make the create flags more meaningful */
#define LO_CREATE_LOG                          0x0001
#define LO_CREATE_NOLOG                        0x0002
#define LO_CREATE_DELAY_LOG                    0x0004
#define LO_CREATE_KEEP_LASTACCESS_TIME         0x0008
#define LO_CREATE_NOKEEP_LASTACCESS_TIME       0x0010
#define LO_CREATE_HIGH_INTEG                   0x0020
#define LO_CREATE_MODERATE_INTEG               0x0040
#define LO_CREATE_TEMP                         0x0080

/*******************************************************************************
 * Symbolic constants for the "lseek" routine
 ******************************************************************************/

#define LO_SEEK_SET 0   /* Set curr. pos. to "offset"           */
#define LO_SEEK_CUR 1   /* Set curr. pos. to current + "offset" */
#define LO_SEEK_END 2   /* Set curr. pos. to EOF + "offset"     */


/*******************************************************************************
 * Symbolic constants for lo_lock and lo_unlock routines.
 ******************************************************************************/

#define     LO_SHARED_MODE          1     /* ISSLOCK */
#define     LO_EXCLUSIVE_MODE 2     /* ISXLOCK */

#define     LO_MAX_END        -1
#define     LO_CURRENT_END          -2

/*******************************************************************************
 * ifx_lo_create_spec_t:
 *
 * This is an opaque structure used for creating smartblobs. The
 * user may examin and/or set certain fields herein by using
 * ifx_lo_spec[set|get]_* accessor functions. Prototypes for these acessors
 * are in incl/sqlhdr.h
 *
 ******************************************************************************/

typedef struct ifx_lo_create_spec_s ifx_lo_create_spec_t;



/*******************************************************************************
 * ifx_lo_t: A dummy opaque representation of the smartblob structure
 *
 * This can be used for stack or in-line structure declarations.
 *
 ******************************************************************************/
#define SB_LOCSIZE 72 /* length of ifx_lo_t */

typedef struct ifx_lo_ts
{
    char dummy[SB_LOCSIZE];
} ifx_lo_t;

/*******************************************************************************
 * ifx_lo_stat:
 *
 * This is an opaque structure used in querying attribtes of smartblobs. The
 * user may examin fields herein by using ifx_lo_stat_* accessor functions.
 * Prototypes for these acessors are in incl/sqlhdr.h
 *
 * The accessors are defined as follows:
 *     ifx_lo_stat_size: contains the size of the LO in bytes.
 *     ifx_lo_stat_uid: reserved for future use: the user id for the
 *         owner of the LO.
 *     ifx_lo_stat_atime: the time of last access. This is only maintained if
 *         the LO_KEEP_LASTACCESS_TIME flag is set for the LO.
 *         Resolution is seconds.
 *     ifx_lo_stat_mtime: the time of last modification. Resolution is
 *         seconds.
 *     ifx_lo_stat_ctime: the time of the last status change (this includes
 *         updates, changes in ownership, and changes to the number of
 *         references).  Resolution is seconds. See Appendix B2.11,
 *         Future Embedded- language feature issues, Smartblob API
 *         functions using lofd, for enhancements that extend support
 *         for named and external LOs.
 *     ifx_lo_stat_refcnt: the number of pointers to this LO - when 0 the LO is
 *         typically deleted. See deletion criteria.
 *     ifx_lo_stat_cspec: a pointer to the opaque create spec for this object.
 *         (see ifx_lo_spec[get|set]_ accessors for details.)
 *     ifx_lo_stat_type: the 8 byte code for the LO's type
 *
 ******************************************************************************/

typedef struct ifx_lo_stat_s ifx_lo_stat_t;

#endif      /* LOCATOR_INCL */
#line 384 "/opt/informix/incl/esql/locator.h"
#line 35 "dbinfx.ec"

#include "eb.h"
#include "dbapi.h"

#define CACHELIMIT 10000 /* number of cached lines */

#define ENGINE_ERRCODE sqlca.sqlcode


/*********************************************************************
The status variable ENGINE_ERRCODE holds the return code from an Informix call.
This is then used by the function errorTrap() below.
If ENGINE_ERRCODE != 0, errorTrap() aborts the program, or performs
a recovery longjmp, as directed by the generic error function errorPrint().
errorTrap() returns true if an SQL error occurred, but that error
was trapped by the application.
In this case the calling routine should clean up as best it can and return.
*********************************************************************/

static const char *stmt_text = 0; /* text of the SQL statement */
static const short *exclist; /* list of error codes trapped by the application */
static short translevel;
static bool badtrans;

/* Through globals, make error info available to the application. */
int rv_lastStatus, rv_stmtOffset;
long rv_vendorStatus;
char *rv_badToken;

static void debugStatement(void)
{
      if(sql_debug && stmt_text)
            appendFileNF(sql_debuglog, stmt_text);
} /* debugStatement */

static void debugExtra(const char *s)
{
      if(sql_debug)
            appendFileNF(sql_debuglog, s);
} /* debugExtra */

/* Append the SQL statement to the debug log.  This is not strictly necessary
 * if sql_debug is set, since the statement has already been appended. */
static void showStatement(void)
{
      if(!sql_debug && stmt_text)
            appendFileNF(sql_debuglog, stmt_text);
} /* showStatement */

/* application sets the exception list */
void sql_exclist(const short *list) { exclist = list; }

void sql_exception(int errnum)
{
      static short list[2];
      list[0] = errnum;
      exclist = list;
} /* sql_exception */

/* map Informix errors to our own exception codes, as defined in dbapi.h. */
static const struct ERRORMAP {
      short infcode;
      short excno;
} errormap[] = {
      {200, EXCSYNTAX},
      {201, EXCSYNTAX},
      {202, EXCSYNTAX},
      {203, EXCSYNTAX},
      {204, EXCSYNTAX},
      {205, EXCROWIDUSE},
      {206, EXCNOTABLE},
      /* 207 */
      {208, EXCRESOURCE},
      {209, EXCDBCORRUPT},
      {210, EXCFILENAME},
      {211, EXCDBCORRUPT},
      {212, EXCRESOURCE},
      {213, EXCINTERRUPT},
      {214, EXCDBCORRUPT},
      {215, EXCDBCORRUPT},
      {216, EXCDBCORRUPT},
      {217, EXCNOCOLUMN},
      {218, EXCNOSYNONYM},
      {219, EXCCONVERT},
      {220, EXCSYNTAX},
      {221, EXCRESOURCE},
      {222, EXCRESOURCE},
      {223, EXCAMBTABLE},
      {224, EXCRESOURCE},
      {225, EXCRESOURCE},
      {226, EXCRESOURCE},
      {227, EXCROWIDUSE},
      {228, EXCROWIDUSE},
      {229, EXCRESOURCE},
      {230, EXCDBCORRUPT},
      {231, EXCAGGREGATEUSE},
      {232, EXCSERIAL},
      {233, EXCITEMLOCK},
      {234, EXCAMBCOLUMN},
      {235, EXCCONVERT},
      {236, EXCSYNTAX},
      {237, EXCMANAGETRANS},
      {238, EXCMANAGETRANS},
      {239, EXCDUPKEY},
      {240, EXCDBCORRUPT},
      {241, EXCMANAGETRANS},
      {249, EXCAMBCOLUMN},
      {250, EXCDBCORRUPT},
      {251, EXCSYNTAX},
      {252, EXCITEMLOCK},
      {253, EXCSYNTAX},
      {255, EXCNOTINTRANS},
      {256, EXCMANAGETRANS},
      {257, EXCRESOURCE},
      {258, EXCDBCORRUPT},
      {259, EXCNOCURSOR},
      {260, EXCNOCURSOR},
      {261, EXCRESOURCE},
      {262, EXCNOCURSOR},
      {263, EXCRESOURCE},
      {264, EXCRESOURCE},
      {265, EXCNOTINTRANS},
      {266, EXCNOCURSOR},
      {267, EXCNOCURSOR},
      {268, EXCDUPKEY},
      {269, EXCNOTNULLCOLUMN},
      {270, EXCDBCORRUPT},
      {271, EXCDBCORRUPT},
      {272, EXCPERMISSION},
      {273, EXCPERMISSION},
      {274, EXCPERMISSION},
      {275, EXCPERMISSION},
      {276, EXCNOCURSOR},
      {277, EXCNOCURSOR},
      {278, EXCRESOURCE},
      {281, EXCTEMPTABLEUSE},
      {282, EXCSYNTAX},
      {283, EXCSYNTAX},
      {284, EXCMANYROW},
      {285, EXCNOCURSOR},
      {286, EXCNOTNULLCOLUMN},
      {287, EXCSERIAL},
      {288, EXCITEMLOCK},
      {289, EXCITEMLOCK},
      {290, EXCNOCURSOR},
      {292, EXCNOTNULLCOLUMN},
      {293, EXCSYNTAX},
      {294, EXCAGGREGATEUSE},
      {295, EXCCROSSDB},
      {296, EXCNOTABLE},
      {297, EXCNOKEY},
      {298, EXCPERMISSION},
      {299, EXCPERMISSION},
      {300, EXCRESOURCE},
      {301, EXCRESOURCE},
      {302, EXCPERMISSION},
      { 303, EXCAGGREGATEUSE},
      {304, EXCAGGREGATEUSE},
      {305, EXCSUBSCRIPT},
      {306, EXCSUBSCRIPT},
      {307, EXCSUBSCRIPT},
      {308, EXCCONVERT},
      {309, EXCAMBCOLUMN},
      {310, EXCDUPTABLE},
      {311, EXCDBCORRUPT},
      {312, EXCDBCORRUPT},
      {313, EXCPERMISSION},
      {314, EXCDUPTABLE},
      {315, EXCPERMISSION},
      {316, EXCDUPINDEX},
      {317, EXCUNION},
      {318, EXCFILENAME},
      {319, EXCNOINDEX},
      {320, EXCPERMISSION},
      {321, EXCAGGREGATEUSE},
      {323, EXCTEMPTABLEUSE},
      {324, EXCAMBCOLUMN},
      {325, EXCFILENAME},
      {326, EXCRESOURCE},
      {327, EXCITEMLOCK},
      {328, EXCDUPCOLUMN},
      {329, EXCNOCONNECT},
      {330, EXCRESOURCE},
      {331, EXCDBCORRUPT},
      {332, EXCTRACE},
      {333, EXCTRACE},
      {334, EXCTRACE},
      {335, EXCTRACE},
      {336, EXCTEMPTABLEUSE},
      {337, EXCTEMPTABLEUSE},
      {338, EXCTRACE},
      {339, EXCFILENAME},
      {340, EXCTRACE},
      {341, EXCTRACE},
      {342, EXCREMOTE},
      {343, EXCTRACE},
      {344, EXCTRACE},
      {345, EXCTRACE},
      {346, EXCDBCORRUPT},
      {347, EXCITEMLOCK},
      {348, EXCDBCORRUPT},
      {349, EXCNODB},
      {350, EXCDUPINDEX},
      {352, EXCNOCOLUMN},
      {353, EXCNOTABLE},
      {354, EXCSYNTAX},
      {355, EXCDBCORRUPT},
      {356, EXCCONVERT},
      {361, EXCRESOURCE},
      {362, EXCSERIAL},
      {363, EXCNOCURSOR},
      {365, EXCNOCURSOR},
      {366, EXCCONVERT},
      {367, EXCAGGREGATEUSE},
      {368, EXCDBCORRUPT},
      {369, EXCSERIAL},
      {370, EXCAMBCOLUMN},
      {371, EXCDUPKEY},
      {372, EXCTRACE},
      {373, EXCFILENAME},
      {374, EXCSYNTAX},
      {375, EXCMANAGETRANS},
      {376, EXCMANAGETRANS},
      {377, EXCMANAGETRANS},
      {378, EXCITEMLOCK},
      {382, EXCSYNTAX},
      {383, EXCAGGREGATEUSE},
      {384, EXCVIEWUSE},
      {385, EXCCONVERT},
      {386, EXCNOTNULLCOLUMN},
      {387, EXCPERMISSION},
      {388, EXCPERMISSION},
      {389, EXCPERMISSION},
      {390, EXCDUPSYNONYM},
      {391, EXCNOTNULLCOLUMN},
      {392, EXCDBCORRUPT},
      {393, EXCWHERECLAUSE},
      {394, EXCNOTABLE},
      {395, EXCWHERECLAUSE},
      {396, EXCWHERECLAUSE},
      {397, EXCDBCORRUPT},
      {398, EXCNOTINTRANS},
      {399, EXCMANAGETRANS},
      {400, EXCNOCURSOR},
      {401, EXCNOCURSOR},
      {404, EXCNOCURSOR},
      {406, EXCRESOURCE},
      {407, EXCDBCORRUPT},
      {408, EXCDBCORRUPT},
      {409, EXCNOCONNECT},
      {410, EXCNOCURSOR},
      {413, EXCNOCURSOR},
      {414, EXCNOCURSOR},
      {415, EXCCONVERT},
      {417, EXCNOCURSOR},
      {420, EXCREMOTE},
      {421, EXCREMOTE},
      {422, EXCNOCURSOR},
      {423, EXCNOROW},
      {424, EXCDUPCURSOR},
      {425, EXCITEMLOCK},
      {430, EXCCONVERT},
      {431, EXCCONVERT},
      {432, EXCCONVERT},
      {433, EXCCONVERT},
      {434, EXCCONVERT},
      {439, EXCREMOTE},
      {451, EXCRESOURCE},
      {452, EXCRESOURCE},
      {453, EXCDBCORRUPT},
      {454, EXCDBCORRUPT},
      {455, EXCRESOURCE},
      {457, EXCREMOTE},
      {458, EXCLONGTRANS},
      {459, EXCREMOTE},
      {460, EXCRESOURCE},
      {465, EXCRESOURCE},
      {468, EXCNOCONNECT},
      {472, EXCCONVERT},
      {473, EXCCONVERT},
      {474, EXCCONVERT},
      {482, EXCNOCURSOR},
      {484, EXCFILENAME},
      {500, EXCDUPINDEX},
      {501, EXCDUPINDEX},
      {502, EXCNOINDEX},
      {503, EXCRESOURCE},
      {504, EXCVIEWUSE},
      {505, EXCSYNTAX},
      {506, EXCPERMISSION},
      {507, EXCNOCURSOR},
      {508, EXCTEMPTABLEUSE},
      {509, EXCTEMPTABLEUSE},
      {510, EXCTEMPTABLEUSE},
      {512, EXCPERMISSION},
      {514, EXCPERMISSION},
      {515, EXCNOCONSTRAINT},
      {517, EXCRESOURCE},
      {518, EXCNOCONSTRAINT},
      {519, EXCCONVERT},
      {521, EXCITEMLOCK},
      {522, EXCNOTABLE},
      {524, EXCNOTINTRANS},
      {525, EXCREFINT},
      {526, EXCNOCURSOR},
      {528, EXCRESOURCE},
      {529, EXCNOCONNECT},
      {530, EXCCHECK},
      {531, EXCDUPCOLUMN},
      {532, EXCTEMPTABLEUSE},
      {534, EXCITEMLOCK},
      {535, EXCMANAGETRANS},
      {536, EXCSYNTAX},
      {537, EXCNOCONSTRAINT},
      {538, EXCDUPCURSOR},
      {539, EXCRESOURCE},
      {540, EXCDBCORRUPT},
      {541, EXCPERMISSION},
      {543, EXCAMBCOLUMN},
      {543, EXCSYNTAX},
      {544, EXCAGGREGATEUSE},
      {545, EXCPERMISSION},
      {548, EXCTEMPTABLEUSE},
      {549, EXCNOCOLUMN},
      {550, EXCRESOURCE},
      {551, EXCRESOURCE},
      {554, EXCSYNTAX},
      {559, EXCDUPSYNONYM},
      {560, EXCDBCORRUPT},
      {561, EXCAGGREGATEUSE},
      {562, EXCCONVERT},
      {536, EXCITEMLOCK},
      {564, EXCRESOURCE},
      {565, EXCRESOURCE},
      {566, EXCRESOURCE},
      {567, EXCRESOURCE},
      {568, EXCCROSSDB},
      {569, EXCCROSSDB},
      {570, EXCCROSSDB},
      {571, EXCCROSSDB},
      {573, EXCMANAGETRANS},
      {574, EXCAMBCOLUMN},
      {576, EXCTEMPTABLEUSE},
      {577, EXCDUPCONSTRAINT},
      {578, EXCSYNTAX},
      {579, EXCPERMISSION},
      {580, EXCPERMISSION},
      {582, EXCMANAGETRANS},
      {583, EXCPERMISSION},
      {586, EXCDUPCURSOR},
      {589, EXCREMOTE},
      {590, EXCDBCORRUPT},
      {591, EXCCONVERT},
      {592, EXCNOTNULLCOLUMN},
      {593, EXCSERIAL},
      {594, EXCBLOBUSE},
      {595, EXCAGGREGATEUSE},
      {597, EXCDBCORRUPT},
      {598, EXCNOCURSOR},
      {599, EXCSYNTAX},
      {600, EXCMANAGEBLOB},
      {601, EXCMANAGEBLOB},
      {602, EXCMANAGEBLOB},
      {603, EXCMANAGEBLOB},
      {604, EXCMANAGEBLOB},
      {605, EXCMANAGEBLOB},
      {606, EXCMANAGEBLOB},
      {607, EXCSUBSCRIPT},
      {608, EXCCONVERT},
      {610, EXCBLOBUSE},
      {611, EXCBLOBUSE},
      {612, EXCBLOBUSE},
      {613, EXCBLOBUSE},
      {614, EXCBLOBUSE},
      {615, EXCBLOBUSE},
      {616, EXCBLOBUSE},
      {617, EXCBLOBUSE},
      {618, EXCMANAGEBLOB},
      {622, EXCNOINDEX},
      {623, EXCNOCONSTRAINT},
      {625, EXCDUPCONSTRAINT},
      {628, EXCMANAGETRANS},
      {629, EXCMANAGETRANS},
      {630, EXCMANAGETRANS},
      {631, EXCBLOBUSE},
      {635, EXCPERMISSION},
      {636, EXCRESOURCE},
      {638, EXCBLOBUSE},
      {639, EXCBLOBUSE},
      {640, EXCDBCORRUPT},
      {649, EXCFILENAME},
      {650, EXCRESOURCE},
      {651, EXCRESOURCE},
      /* I'm not about to map all possible compile/runtime SPL errors. */
      /* Here's a few. */
      {655, EXCSYNTAX},
      {667, EXCSYNTAX},
      {673, EXCDUPSPROC},
      {674, EXCNOSPROC},
      {678, EXCSUBSCRIPT},
      {681, EXCDUPCOLUMN},
      {686, EXCMANYROW},
      {690, EXCREFINT},
      {691, EXCREFINT},
      {692, EXCREFINT},
      {702, EXCITEMLOCK},
      {703, EXCNOTNULLCOLUMN},
      {704, EXCDUPCONSTRAINT},
      {706, EXCPERMISSION},
      {707, EXCBLOBUSE},
      {722, EXCRESOURCE},
      {958, EXCDUPTABLE},
      {1214, EXCCONVERT},
      {1262, EXCCONVERT},
      {1264, EXCCONVERT},
      {25553, EXCNOCONNECT},
      {25587, EXCNOCONNECT},
      {25588, EXCNOCONNECT},
      {25596, EXCNOCONNECT},
      {0, 0}
}; /* ends of list */

static int errTranslate(int code)
{
      const struct ERRORMAP *e;

      for(e=errormap; e->infcode; ++e) {
            if(e->infcode == code)
                  return e->excno;
      }
      return EXCSQLMISC;
} /* errTranslate */

static bool errorTrap(void)
{
short i;

/* innocent until proven guilty */
rv_lastStatus = 0;
rv_vendorStatus = 0;
rv_stmtOffset = 0;
rv_badToken = 0;
if(ENGINE_ERRCODE >= 0) return false; /* no problem */

        /* log the SQL statement that elicitted the error */
showStatement();
rv_vendorStatus = -ENGINE_ERRCODE;
rv_lastStatus = errTranslate(rv_vendorStatus);
rv_stmtOffset = sqlca.sqlerrd[4];
rv_badToken = sqlca.sqlerrm;
if(!rv_badToken[0]) rv_badToken = 0;

/* if the application didn't trap for this exception, blow up! */
if(exclist)
for(i=0; exclist[i]; ++i)
if(exclist[i] == rv_lastStatus) {
exclist = 0; /* we've spent that exception */
return true;
}

/* Remember, errorPrint() should not return. */
errorPrint("2SQL error %d, %s", rv_vendorStatus, sqlErrorList[rv_lastStatus]);
return true; /* make the compiler happy */
} /* errorTrap */


/*********************************************************************
The OCURS structure given below maintains an open SQL cursor.
A static array of these structures allows multiple cursors
to be opened simultaneously.
*********************************************************************/

static struct OCURS {
char sname[8]; /* statement name */
char cname[8]; /* cursor name */
struct sqlda *desc;
char rv_type[NUMRETS];
long rownum;
short cid; /* cursor ID */
char flag;
char numRets;
} ocurs[NUMCURSORS];

/* values for struct OCURS.flag */
#define CURSOR_NONE 0
#define CURSOR_PREPARED 1
#define CURSOR_OPENED 2

/* find a free cursor structure */
static struct OCURS *findNewCursor(void)
{
struct OCURS *o;
short i;
for(o=ocurs, i=0; i<NUMCURSORS; ++i, ++o) {
if(o->flag != CURSOR_NONE) continue;
sprintf(o->cname, "c%u", i);
sprintf(o->sname, "s%u", i);
o->cid = 6000+i;
return o;
}
errorPrint("2more than %d cursors opend concurrently", NUMCURSORS);
return 0; /* make the compiler happy */
} /* findNewCursor */

/* dereference an existing cursor */
static struct OCURS *findCursor(int cid)
{
struct OCURS *o;
if(cid < 6000 || cid >= 6000+NUMCURSORS)
errorPrint("2cursor number %d is out of range", cid);
cid -= 6000;
o = ocurs+cid;
if(o->flag == CURSOR_NONE)
errorPrint("2cursor %d is not currently active", cid);
rv_numRets = o->numRets;
memcpy(rv_type, o->rv_type, NUMRETS);
return o;
} /* findCursor */

/* This doesn't close/free anything; it simply puts variables in an initial state. */
/* part of the disconnect() procedure */
static void clearAllCursors(void)
{
      int i, j;
      struct OCURS *o;

      for(i=0, o=ocurs; i<NUMCURSORS; ++i, ++o) {
            if(o->flag == CURSOR_NONE) continue;
            o->flag = CURSOR_NONE;
o->rownum = 0;
      } /* loop over cursors */

      translevel = 0;
      badtrans = false;
} /* clearAllCursors */


/*********************************************************************
Connect and disconect to SQL databases.
*********************************************************************/

void sql_connect(const char *db, const char *login, const char *pw)
{
/*
 * $char *dblocal = (char*)db;
 */
#line 578 "dbinfx.ec"
  char *dblocal = (char*)db;
login = pw = 0; /* not used here, so make the compiler happy */
if(isnullstring(dblocal)) {
dblocal = getenv("DBNAME");
if(isnullstring(dblocal))
errorPrint("2sql_connect receives no database, check $DBNAME");
}

if(sql_database) {
      stmt_text = "disconnect";
      debugStatement();
/*
 * $disconnect current;
 */
#line 589 "dbinfx.ec"
  {
#line 589 "dbinfx.ec"
  sqli_connect_close(3, (char *)0, 0, 0);
#line 589 "dbinfx.ec"
  }
clearAllCursors();
sql_database = 0;
}

      stmt_text = "connect";
      debugStatement();
/*
 * $connect to :dblocal;
 */
#line 596 "dbinfx.ec"
  {
#line 596 "dbinfx.ec"
  sqli_connect_open(ESQLINTVERSION, 0, dblocal, (char *)0, (ifx_conn_t *)0, 0);
#line 596 "dbinfx.ec"
  }
if(errorTrap()) return;
sql_database = dblocal;

/* set default lock mode and isolation level for transaction management */
stmt_text = "lock isolation";
debugStatement();
/*
 * $ set lock mode to wait;
 */
#line 603 "dbinfx.ec"
  {
#line 603 "dbinfx.ec"
  static const char *sqlcmdtxt[] =
#line 603 "dbinfx.ec"
    {
#line 603 "dbinfx.ec"
    "set lock mode to wait",
    0
    };
#line 603 "dbinfx.ec"
  static ifx_statement_t _SQ0 = {0};
#line 603 "dbinfx.ec"
  sqli_stmt(ESQLINTVERSION, &_SQ0, sqlcmdtxt, 0, (ifx_sqlvar_t *)0, (struct value *)0, (ifx_literal_t *)0, (ifx_namelist_t *)0, (ifx_cursor_t *)0, -1, 0, 0);
#line 603 "dbinfx.ec"
  }
if(errorTrap()) {
abort:
sql_disconnect();
return;
}
/*
 * $ set isolation to committed read;
 */
#line 609 "dbinfx.ec"
  {
#line 609 "dbinfx.ec"
  static const char *sqlcmdtxt[] =
#line 609 "dbinfx.ec"
    {
#line 609 "dbinfx.ec"
    "set isolation to committed read",
    0
    };
#line 609 "dbinfx.ec"
  static ifx_statement_t _SQ0 = {0};
#line 609 "dbinfx.ec"
  sqli_stmt(ESQLINTVERSION, &_SQ0, sqlcmdtxt, 0, (ifx_sqlvar_t *)0, (struct value *)0, (ifx_literal_t *)0, (ifx_namelist_t *)0, (ifx_cursor_t *)0, -1, 0, 0);
#line 609 "dbinfx.ec"
  }
if(errorTrap()) goto abort;
exclist = 0;
} /* sql_connect */

void sql_disconnect(void)
{
if(sql_database) {
      stmt_text = "disconnect";
      debugStatement();
/*
 * $disconnect current;
 */
#line 619 "dbinfx.ec"
  {
#line 619 "dbinfx.ec"
  sqli_connect_close(3, (char *)0, 0, 0);
#line 619 "dbinfx.ec"
  }
clearAllCursors();
sql_database = 0;
}
exclist = 0;
} /* sql_disconnect */

/* make sure we're connected to a database */
static void checkConnect(void)
{
      if(!sql_database)
            errorPrint("2SQL command issued, but no database selected");
} /* checkConnect */


/*********************************************************************
Begin, commit, and abort transactions.
SQL does not permit nested transactions; this API does, to a limited degree.
An inner transaction cannot fail while an outer one succeeds;
that would require SQL support which is not forthcoming.
However, as long as all transactions succeed, or the outer most fails,
everything works properly.
The static variable transLevel holds the number of nested transactions.
*********************************************************************/

/* begin a transaction */
void sql_begTrans(void)
{
      rv_lastStatus = 0;
      checkConnect();
stmt_text = 0;

      /* count the nesting level of transactions. */
      if(!translevel) {
            badtrans = false;
            stmt_text = "begin work";
            debugStatement();
/*
 *          $begin work;
 */
#line 656 "dbinfx.ec"
  {
#line 656 "dbinfx.ec"
  sqli_trans_begin2((mint)1);
#line 656 "dbinfx.ec"
  }
            if(errorTrap()) return;
      }
      ++translevel;
      exclist = 0;
} /* sql_begTrans */

/* end a transaction */
static void endTrans(bool commit)
{
      rv_lastStatus = 0;
      checkConnect();
stmt_text = 0;

      if(translevel == 0)
            errorPrint("2end transaction without a matching begTrans()");
      --translevel;

      if(commit) {
                  stmt_text = "commit work";
                  debugStatement();
            if(badtrans)
                  errorPrint("2Cannot commit a transaction around an aborted transaction");
            if(translevel == 0) {
/*
 *                $commit work;
 */
#line 680 "dbinfx.ec"
  {
#line 680 "dbinfx.ec"
  sqli_trans_commit();
#line 680 "dbinfx.ec"
  }
                  if(ENGINE_ERRCODE) ++translevel;
                  errorTrap();
            }
      } else { /* success or failure */
                  stmt_text = "rollback work";
                  debugStatement();
            badtrans = true;
            if(!translevel) { /* bottom level */
/*
 *                $rollback work;
 */
#line 689 "dbinfx.ec"
  {
#line 689 "dbinfx.ec"
  sqli_trans_rollback();
#line 689 "dbinfx.ec"
  }
                  if(ENGINE_ERRCODE) --translevel;
                  errorTrap();
                  badtrans = false;
            }
      } /* success or failure */

      /* At this point I will make a bold assumption --
       * that all cursors are declared with hold.
       * Hence they remain valid after the transaction is closed,
       * and we don't have to change any of the OCURS structures. */

      exclist = 0;
} /* endTrans */

void sql_commitWork(void) { endTrans(true); }
void sql_rollbackWork(void) { endTrans(false); }

void sql_deferConstraints(void)
{
      if(!translevel)
            errorPrint("2Cannot defer constraints unless inside a transaction");
      stmt_text = "defer constraints";
      debugStatement();
/*
 *    $set constraints all deferred;
 */
#line 713 "dbinfx.ec"
  {
#line 713 "dbinfx.ec"
  static const char *sqlcmdtxt[] =
#line 713 "dbinfx.ec"
    {
#line 713 "dbinfx.ec"
    "set constraints all deferred",
    0
    };
#line 713 "dbinfx.ec"
  static ifx_statement_t _SQ0 = {0};
#line 713 "dbinfx.ec"
  sqli_stmt(ESQLINTVERSION, &_SQ0, sqlcmdtxt, 0, (ifx_sqlvar_t *)0, (struct value *)0, (ifx_literal_t *)0, (ifx_namelist_t *)0, (ifx_cursor_t *)0, -1, 0, 0);
#line 713 "dbinfx.ec"
  }
      errorTrap();
      exclist = 0;
} /* sql_deferConstraints */


/*********************************************************************
Blob management routines, a somewhat awkward interface.
Global variables tell SQL where to unload the next fetched blob:
either a file (truncate or append) or an allocated chunk of memory.
This assumes each fetch or select statement retrieves at most one blob.
Since there is no %blob directive in lineFormat(),
one cannot simply slip a blob in with the rest of the data as a row is
updated or inserted.  Instead the row must be created first,
then the blob is entered separately, using blobInsert().
This means every blob column must permit nulls, at least within the schema.
Also, what use to be an atomic insert might become a multi-statement
transaction if data integrity is important.
Future versions of our line formatting software may support a %blob directive,
which makes sense only when the formatted string is destined for SQL.
*********************************************************************/

static loc_t blobstruct; /* Informix structure to manage the blob */

/* insert a blob into the database */
void sql_blobInsert(const char *tabname, const char *colname, int rowid,
const char *filename, void *offset, int length)
{
/*
 * $char blobcmd[100];
 */
#line 741 "dbinfx.ec"
  char blobcmd[100];
/*
 * $loc_t insblob;
 */
#line 742 "dbinfx.ec"
  loc_t insblob;

/* basic sanity checks */
checkConnect();
if(isnullstring(tabname)) errorPrint("2blobInsert, missing table name");
if(isnullstring(colname)) errorPrint("2blobInsert, missing column name");
if(rowid <= 0) errorPrint("2invalid rowid in blobInsert");
if(length < 0) errorPrint("2invalid length in blobInsert");
if(strlen(tabname) + strlen(colname) + 42 >= sizeof(blobcmd))
errorPrint("2internal blobInsert command too long");

/* set up the blob structure */
memset(&insblob, 0, sizeof(insblob));
if(!filename) {
insblob.loc_loctype = LOCMEMORY;
if(offset) {
if(length == 0) offset = 0;
}
if(!offset) length = -1;
insblob.loc_buffer = offset;
insblob.loc_bufsize = length;
insblob.loc_size = length;
if(!offset) insblob.loc_indicator = -1;
} else {
insblob.loc_loctype = LOCFNAME;
insblob.loc_fname = (char*)filename;
insblob.loc_oflags = LOC_RONLY;
insblob.loc_size = -1;
}

/* set up the blob insert command, using one host variable */
sprintf(blobcmd, "update %s set %s = ? where rowid = %d",
tabname, colname, rowid);
stmt_text = blobcmd;
debugStatement();
/*
 * $prepare blobinsert from :blobcmd;
 */
#line 777 "dbinfx.ec"
  {
#line 777 "dbinfx.ec"
  sqli_prep(ESQLINTVERSION, _Cn1, blobcmd,(ifx_literal_t *)0, (ifx_namelist_t *)0, -1, 0, 0 ); 
#line 777 "dbinfx.ec"
  }
if(errorTrap()) return;
/*
 * $execute blobinsert using :insblob;
 */
#line 779 "dbinfx.ec"
  {
#line 779 "dbinfx.ec"
  static ifx_sqlvar_t _sqibind[] = 
    {
      { 113, sizeof(insblob), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
#line 779 "dbinfx.ec"
    };
  static ifx_sqlda_t _SD0 = { 1, _sqibind, {0}, 1, 0 };
#line 779 "dbinfx.ec"
  _sqibind[0].sqldata = (char *) &insblob;
  sqli_exec(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, _Cn1, 769), &_SD0, (char *)0, (struct value *)0, (ifx_sqlda_t *)0, (char *)0, (struct value *)0, 0);
#line 779 "dbinfx.ec"
  }
errorTrap();
rv_lastNrows = sqlca.sqlerrd[2];
rv_lastRowid = sqlca.sqlerrd[5];
if(sql_debug) appendFile(sql_debuglog, "%d rows affected", rv_lastNrows);
exclist = 0;
} /* sql_blobInsert */


/*********************************************************************
When an SQL statement is prepared, the engine tells us the types and lengths
of the columns.  Use this information to "normalize" the sqlda
structure, so that columns are fetched using our preferred formats.
For instance, smallints and ints both map into int variables,
varchars become chars, dates map into strings (so that we can convert
them into our own vendor-independent binary representations later), etc.
We assume the number and types of returns have been established.
Once retsSetup has "normalized" the sqlda structure,
run the select or fetch, and then call retsCleanup to post-process the data.
This will, for example, turn dates, fetched into strings,
into our own 4-byte representations.
The same for time intervals, money, etc.
*********************************************************************/

/* Temp area to read the Informix values, as strings */
static char retstring[NUMRETS][STRINGLEN+4];
static va_list sqlargs;

static void retsSetup(struct sqlda *desc)
{
short i;
bool blobpresent = false;
struct sqlvar_struct   *v;

for(i=0; (unsigned)i< NUMRETS; ++i) {
rv_data[i].l = nullint;
retstring[i][0] = 0;
rv_name[i][0] = 0;
}
if(!desc) return;

  for(i=0,v=desc->sqlvar; i<rv_numRets; ++i,++v ) {
strncpy(rv_name[i], v->sqlname, COLNAMELEN);
switch(rv_type[i]) {
case 'S':
case 'C':
case 'D':
case 'I':
v->sqltype = CCHARTYPE;
v->sqllen = STRINGLEN+2;
v->sqldata = retstring[i];
rv_data[i].ptr = retstring[i];
break;

case 'N':
v->sqltype = CINTTYPE;
v->sqllen = 4;
v->sqldata =  (char *) &rv_data[i].l;
break;

case 'F':
case 'M':
v->sqltype = CDOUBLETYPE;
v->sqllen = 8;
v->sqldata = (char*) &rv_data[i].f;
rv_data[i].f = nullfloat;
break;

case 'B':
case 'T':
if(blobpresent)
errorPrint("2Cannot select more than one blob at a time");
blobpresent = true;
v->sqltype = CLOCATORTYPE;
v->sqllen = sizeof(blobstruct);
v->sqldata = (char*) &blobstruct;
memset(&blobstruct, 0, sizeof(blobstruct));
if(!rv_blobFile) {
blobstruct.loc_loctype = LOCMEMORY;
blobstruct.loc_mflags = LOC_ALLOC;
blobstruct.loc_bufsize = -1;
} else {
blobstruct.loc_loctype = LOCFNAME;
blobstruct.loc_fname = (char*)rv_blobFile;
blobstruct.lc_union.lc_file.lc_mode = 0600;
blobstruct.loc_oflags =
(rv_blobAppend ? LOC_WONLY|LOC_APPEND : LOC_WONLY);
}
break;

default:
errorPrint("@bad character %c in retsSetup", rv_type[i]);
} /* switch */
} /* loop over fetched columns */
} /* retsSetup */

/* clean up fetched values, eg. convert date to our proprietary format. */
static void retsCleanup(void)
{
short i, l;
bool yearfirst;

/* no blobs unless proven otherwise */
rv_blobLoc = 0;
rv_blobSize = nullint;

for(i=0; i<rv_numRets; ++i) {
clipString(retstring[i]);
switch(rv_type[i]) {
case 'D':
yearfirst = false;
if(retstring[i][4] == '-') yearfirst = true;
rv_data[i].l = stringDate(retstring[i],yearfirst);
break;

case 'I':
/* thanks to stringTime(), this works for either hh:mm or hh:mm:ss */
if(retstring[i][0] == 0) rv_data[i].l = nullint;
else {
/* convert space to 0 */
if(retstring[i][1] == ' ') retstring[i][1] = '0';
/* skip the leading space that is produced when Informix converts interval to string */
rv_data[i].l = stringTime(retstring[i]+1);
}
break;

case 'C':
rv_data[i].l = retstring[i][0];
break;

case 'M':
case 'F':
/* null floats look different from null dates and ints. */
if(rv_data[i].l == 0xffffffff) {
rv_data[i].f = nullfloat;
if(rv_type[i] == 'M') rv_data[i].l = nullint;
break;
}
/* represent monitary amounts as an integer number of pennies. */
if(rv_type[i] == 'M')
rv_data[i].l = rv_data[i].f * 100.0 + 0.5;
break;

case 'S':
/* map the empty string into the null string */
l = strlen(retstring[i]);
if(!l) rv_data[i].ptr = 0;
if(l > STRINGLEN) errorPrint("2fetched string is too long, limit %d chars", STRINGLEN);
break;

case 'B':
case 'T':
if(blobstruct.loc_indicator >= 0) { /* not null blob */
rv_blobSize = blobstruct.loc_size;
if(!rv_blobFile) rv_blobLoc = blobstruct.loc_buffer;
if(rv_blobSize == 0) { /* turn empty blob into null blob */
nzFree(rv_blobLoc);
rv_blobLoc = 0;
rv_blobSize = nullint;
}
}
rv_data[i].l = rv_blobSize;
break;

case 'N':
/* Convert from Informix null to our nullint */
if(rv_data[i].l == 0x80000000) rv_data[i].l = nullint;
break;

default:
errorPrint("@bad character %c in retsCleanup", rv_type[i]);
} /* switch on datatype */
} /* loop over columsn fetched */
} /* retsCleanup */

void retsCopy(bool allstrings, void *first, ...)
{
void *q;
int i;

      if(!rv_numRets)
            errorPrint("@calling retsCopy() with no returns pending");

      for(i=0; i<rv_numRets; ++i) {
            if(first) {
                  q = first;
                  va_start(sqlargs, first);
                  first = 0;
            } else {
                  q = va_arg(sqlargs, void*);
            }
            if(!q) break;
            if((int)q < 1000 && (int)q > -1000)
                  errorPrint("2retsCopy, pointer too close to 0");

if(allstrings) *(char*)q = 0;

if(rv_type[i] == 'S') {
*(char*)q = 0;
if(rv_data[i].ptr)
strcpy(q,  rv_data[i].ptr);
} else if(rv_type[i] == 'C') {
*(char *)q = rv_data[i].l;
if(allstrings) ((char*)q)[1] = 0;
} else if(rv_type[i] == 'F') {
if(allstrings) {
if(isnotnullfloat(rv_data[i].f)) sprintf(q, "%lf", rv_data[i].f);
} else {
*(double *)q = rv_data[i].f;
}
} else if(allstrings) {
char type = rv_type[i];
long l = rv_data[i].l;
if(isnotnull(l)) {
if(type == 'D') {
strcpy(q, dateString(l, DTDELIMIT));
} else if(type == 'I') {
strcpy(q, timeString(l, DTDELIMIT));
} else if(type == 'M') {
sprintf(q, "%ld.%02d", l/100, l%100);
} else sprintf(q, "%ld", l);
}
} else {
*(long *)q = rv_data[i].l;
}
} /* loop over result parameters */

if(!first) va_end(sqlargs);
} /* retsCopy */

/* make sure we got one return value, and it is integer compatible */
static long oneRetValue(void)
{
char coltype = rv_type[0];
long n = rv_data[0].l;
if(rv_numRets != 1)
errorPrint("2SQL statement has %d return values, 1 value expected", rv_numRets);
if(!strchr("MNFDIC", coltype))
errorPrint("2SQL statement returns a value whose type is not compatible with a 4-byte integer");
if(coltype == 'F') n = rv_data[0].f;
return n;
} /* oneRetValue */


/*********************************************************************
Prepare a formatted SQL statement.
Gather the types and names of the fetched columns and make this information
available to the rest of the C routines in this file, and to the application.
Returns the populated sqlda structure for the statement.
Returns null if the prepare failed.
*********************************************************************/

static struct sqlda *prepare(const char *stmt_parm, const char *sname_parm)
{
/*
 * $char*stmt = (char*)stmt_parm;
 */
#line 1033 "dbinfx.ec"
  char *stmt = (char*)stmt_parm;
/*
 * $char*sname = (char*)sname_parm;
 */
#line 1034 "dbinfx.ec"
  char *sname = (char*)sname_parm;
struct sqlda *desc;
struct sqlvar_struct   *v;
short i, coltype;

checkConnect();
if(isnullstring(stmt)) errorPrint("2null SQL statement");
stmt_text = stmt;
debugStatement();

/* look for delete with no where clause */
while(*stmt == ' ') ++stmt;
if(!strncmp(stmt, "delete", 6) || !strncmp(stmt, "update", 6))
/* delete or update */
if(!strstr(stmt, "where") && !strstr(stmt, "WHERE")) {
showStatement();
errorPrint("2Old Mcdonald bug");
}

/* set things up to nulls, in case the prepare fails */
retsSetup(0);
rv_numRets = 0;
memset(rv_type, 0, NUMRETS);
rv_lastNrows = rv_lastRowid = rv_lastSerial = 0;

/*
 * $prepare :sname from :stmt;
 */
#line 1059 "dbinfx.ec"
  {
#line 1059 "dbinfx.ec"
  sqli_prep(ESQLINTVERSION, sname, stmt,(ifx_literal_t *)0, (ifx_namelist_t *)0, -1, 0, 0 ); 
#line 1059 "dbinfx.ec"
  }
if(errorTrap()) return 0;

/* gather types and column headings */
/*
 * $describe: sname into desc;
 */
#line 1063 "dbinfx.ec"
  {
#line 1063 "dbinfx.ec"
  sqli_describe_stmt(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, sname, 257), &desc, 0);
#line 1063 "dbinfx.ec"
  }
if(!desc) errorPrint("2$describe couldn't allocate descriptor");
rv_numRets = desc->sqld;
if(rv_numRets > NUMRETS) {
showStatement();
errorPrint("2cannot select more than %d values", NUMRETS);
}

  for(i=0,v=desc->sqlvar; i<rv_numRets; ++i,++v ) {
coltype = v->sqltype & SQLTYPE;
/* kludge, count(*) should be int, not float, in my humble opinion */
if(stringEqual(v->sqlname, "(count(*))"))
coltype = SQLINT;

switch(coltype) {
case SQLCHAR:
case SQLVCHAR:
rv_type[i] = 'S';
if(v->sqllen == 1)
rv_type[i] = 'C';
break;

case SQLDTIME:
/* We only process datetime year to minute, for databases
 * other than Informix,  which don't have a date type. */
if(v->sqllen != 5) errorPrint("2datetime field must be year to minute");
case SQLDATE:
rv_type[i] = 'D';
break;

case SQLINTERVAL:
rv_type[i] = 'I';
break;

case SQLSMINT:
case SQLINT:
case SQLSERIAL:
case SQLNULL:
rv_type[i] = 'N';
break;

case SQLFLOAT:
case SQLSMFLOAT:
case SQLDECIMAL:
rv_type[i] = 'F';
break;

case SQLMONEY:
rv_type[i] = 'M';
break;

case SQLBYTES:
rv_type[i] = 'B';
break;

case SQLTEXT:
rv_type[i] = 'T';
break;

default:
errorPrint ("@Unknown informix sql datatype %d", coltype);
} /* switch on type */
} /* loop over returns */

retsSetup(desc);
return desc;
} /* prepare */


/*********************************************************************
Run an SQL statement internally, and gather any fetched values.
This statement stands alone; it fetches at most one row.
You might simply know this, perhaps because of a unique key,
or you might be running a stored procedure.
For efficiency we do not look for a second row, so this is really
like the "select first" construct that some databases support.
A mode variable says whether execution or selection or both are allowed.
Return true if data was successfully fetched.
*********************************************************************/

static bool execInternal(const char *stmt, int mode)
{
struct sqlda *desc;
/*
 * $static char singlestatement[] = "single_use_stmt";
 */
#line 1146 "dbinfx.ec"
static   char singlestatement[] = "single_use_stmt";
/*
 * $static char singlecursor[] = "single_use_cursor";
 */
#line 1147 "dbinfx.ec"
static   char singlecursor[] = "single_use_cursor";
int i;
bool notfound = false;
short errorcode = 0;

desc = prepare(stmt, singlestatement);
if(!desc) return false; /* error */

if(!rv_numRets) {
if(!(mode&1)) {
showStatement();
errorPrint("2SQL select statement returns no values");
}
/*
 * $execute :singlestatement;
 */
#line 1160 "dbinfx.ec"
  {
#line 1160 "dbinfx.ec"
  sqli_exec(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, singlestatement, 257), (ifx_sqlda_t *)0, (char *)0, (struct value *)0, (ifx_sqlda_t *)0, (char *)0, (struct value *)0, 0);
#line 1160 "dbinfx.ec"
  }
notfound = true;
} else { /* end no return values */

if(!(mode&2)) {
showStatement();
errorPrint("2SQL statement returns %d values", rv_numRets);
}
/*
 * $execute: singlestatement into descriptor desc;
 */
#line 1168 "dbinfx.ec"
  {
#line 1168 "dbinfx.ec"
  sqli_exec(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, singlestatement, 257), (ifx_sqlda_t *)0, (char *)0, (struct value *)0, desc, (char *)0, (struct value *)0, 0);
#line 1168 "dbinfx.ec"
  }
}

if(errorTrap()) {
errorcode = rv_vendorStatus;
} else {
/* select or execute ran properly */
/* error 100 means not found in Informix */
if(ENGINE_ERRCODE == 100) notfound = true;
/* set "last" parameters, in case the application is interested */
rv_lastNrows = sqlca.sqlerrd[2];
rv_lastRowid = sqlca.sqlerrd[5];
rv_lastSerial = sqlca.sqlerrd[1];
} /* successful run */

/*
 * $free :singlestatement;
 */
#line 1183 "dbinfx.ec"
  {
#line 1183 "dbinfx.ec"
  sqli_curs_free(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, singlestatement, 258));
#line 1183 "dbinfx.ec"
  }
errorTrap();
nzFree(desc);

retsCleanup();

if(errorcode) {
rv_vendorStatus = errorcode;
rv_lastStatus = errTranslate(rv_vendorStatus);
return false;
}

exclist = 0;
return !notfound;
} /* execInternal */


/*********************************************************************
Run individual select or execute statements, using the above internal routine.
*********************************************************************/

/* pointer to vararg list; most of these are vararg functions */
/* execute a stand-alone statement with no % formatting of the string */
bool sql_execNF(const char *stmt)
{
      return execInternal(stmt, 1);
} /* sql_execNF */

/* execute a stand-alone statement with % formatting */
bool sql_exec(const char *stmt, ...)
{
bool ok;
      va_start(sqlargs, stmt);
      stmt = lineFormatStack(stmt, 0, &sqlargs);
      ok = execInternal(stmt, 1);
      va_end(sqlargs);
return ok;
} /* sql_exec */

/* run a select statement with no % formatting of the string */
/* return true if the row was found */
bool sql_selectNF(const char *stmt, ...)
{
      bool rc;
      va_start(sqlargs, stmt);
      rc = execInternal(stmt, 2);
      retsCopy(false, 0);
      return rc;
} /* sql_selectNF */

/* run a select statement with % formatting */
bool sql_select(const char *stmt, ...)
{
      bool rc;
      va_start(sqlargs, stmt);
      stmt = lineFormatStack(stmt, 0, &sqlargs);
      rc = execInternal(stmt, 2);
      retsCopy(false, 0);
      return rc;
} /* sql_select */

/* run a select statement with one return value */
int sql_selectOne(const char *stmt, ...)
{
      bool rc;
      va_start(sqlargs, stmt);
      stmt = lineFormatStack(stmt, 0, &sqlargs);
      rc = execInternal(stmt, 2);
            if(!rc) { va_end(sqlargs); return nullint; }
      return oneRetValue();
} /* sql_selectOne */

/* run a stored procedure with no % formatting */
static bool sql_procNF(const char *stmt)
{
      bool rc;
      char *s = allocMem(20+strlen(stmt));
      strcpy(s, "execute procedure ");
      strcat(s, stmt);
      rc = execInternal(s, 3);
      /* if execInternal doesn't return, we have a memory leak */
      nzFree(s);
      return rc;
} /* sql_procNF */

/* run a stored procedure */
bool sql_proc(const char *stmt, ...)
{
      bool rc;
      va_start(sqlargs, stmt);
      stmt = lineFormatStack(stmt, 0, &sqlargs);
      rc = sql_procNF(stmt);
      if(rv_numRets) retsCopy(false, 0);
      return rc;
} /* sql_proc */

/* run a stored procedure with one return */
int sql_procOne(const char *stmt, ...)
{
      bool rc;
      va_start(sqlargs, stmt);
      stmt = lineFormatStack(stmt, 0, &sqlargs);
      rc = sql_procNF(stmt);
            if(!rc) { va_end(sqlargs); return 0; }
      return oneRetValue();
} /* sql_procOne */


/*********************************************************************
Prepare, open, close, and free SQL cursors.
*********************************************************************/

/* prepare a cursor; return the ID number of that cursor */
static int prepareCursor(const char *stmt, bool scrollflag)
{
/*
 * $char *internal_sname, *internal_cname;
 */
#line 1298 "dbinfx.ec"
  char *internal_sname, *internal_cname;
struct OCURS *o = findNewCursor();

stmt = lineFormatStack(stmt, 0, &sqlargs);
va_end(sqlargs);
internal_sname = o->sname;
internal_cname = o->cname;
o->desc = prepare(stmt, internal_sname);
if(!o->desc) return -1;
if(o->desc->sqld == 0) {
showStatement();
errorPrint("2statement passed to sql_prepare has no returns");
}

/* declare with hold;
 * you might run transactions within this cursor. */
if(scrollflag)
/*
 * $declare :internal_cname scroll cursor with hold for :internal_sname;
 */
#line 1315 "dbinfx.ec"
  {
#line 1315 "dbinfx.ec"
  sqli_curs_decl_dynm(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 0), internal_cname, sqli_curs_locate(ESQLINTVERSION, internal_sname, 1), 4128, 0);
#line 1315 "dbinfx.ec"
  }
else
/*
 * $declare :internal_cname cursor with hold for :internal_sname;
 */
#line 1317 "dbinfx.ec"
  {
#line 1317 "dbinfx.ec"
  sqli_curs_decl_dynm(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 0), internal_cname, sqli_curs_locate(ESQLINTVERSION, internal_sname, 1), 4096, 0);
#line 1317 "dbinfx.ec"
  }
if(errorTrap()) {
nzFree(o->desc);
return -1;
}

o->numRets = rv_numRets;
memcpy(o->rv_type, rv_type, NUMRETS);
o->flag = CURSOR_PREPARED;
return o->cid;
} /* prepareCursor */

int sql_prepare(const char *stmt, ...)
{
      int n;
      va_start(sqlargs, stmt);
      n = prepareCursor(stmt, false);
      exclist = 0;
      return n;
} /* sql_prepare */

int sql_prepareScrolling(const char *stmt, ...)
{
      int n;
      va_start(sqlargs, stmt);
      n = prepareCursor(stmt, true);
      exclist = 0;
      return n;
} /* sql_prepareScrolling */

void sql_open(int cid)
{
short i;
/*
 * $char *internal_sname, *internal_cname;
 */
#line 1350 "dbinfx.ec"
  char *internal_sname, *internal_cname;
struct OCURS *o = findCursor(cid);
if(o->flag == CURSOR_OPENED)
errorPrint("2cannot open cursor %d, already opened", cid);
internal_sname = o->sname;
internal_cname = o->cname;
debugExtra("open");
/*
 * $open :internal_cname;
 */
#line 1357 "dbinfx.ec"
  {
#line 1357 "dbinfx.ec"
  sqli_curs_open(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 256), (ifx_sqlda_t *)0, (char *)0, (struct value *)0, 0, 0);
#line 1357 "dbinfx.ec"
  }
if(!errorTrap()) o->flag = CURSOR_OPENED;
o->rownum = 0;
exclist = 0;
} /* sql_open */

int sql_prepOpen(const char *stmt, ...)
{
int n;
va_start(sqlargs, stmt);
n = prepareCursor(stmt, false);
if(n < 0) return n;
sql_open(n);
if(rv_lastStatus) {
short ev = rv_vendorStatus;
short el = rv_lastStatus;
sql_free(n);
rv_vendorStatus = ev;
rv_lastStatus = el;
n = -1;
}
return n;
} /* sql_prepOpen */

void sql_close(int cid)
{
/*
 * $char *internal_sname, *internal_cname;
 */
#line 1383 "dbinfx.ec"
  char *internal_sname, *internal_cname;
struct OCURS *o = findCursor(cid);
if(o->flag < CURSOR_OPENED)
errorPrint("2cannot close cursor %d, not yet opened", cid);
internal_cname = o->cname;
debugExtra("close");
/*
 * $close :internal_cname;
 */
#line 1389 "dbinfx.ec"
  {
#line 1389 "dbinfx.ec"
  sqli_curs_close(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 256));
#line 1389 "dbinfx.ec"
  }
if(errorTrap()) return;
o->flag = CURSOR_PREPARED;
exclist = 0;
} /* sql_close */

void
sql_free( int cid)
{
/*
 * $char *internal_sname, *internal_cname;
 */
#line 1398 "dbinfx.ec"
  char *internal_sname, *internal_cname;
struct OCURS *o = findCursor(cid);
if(o->flag == CURSOR_OPENED)
errorPrint("2cannot free cursor %d, not yet closed", cid);
internal_sname = o->sname;
debugExtra("free");
/*
 * $free :internal_sname;
 */
#line 1404 "dbinfx.ec"
  {
#line 1404 "dbinfx.ec"
  sqli_curs_free(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_sname, 258));
#line 1404 "dbinfx.ec"
  }
if(errorTrap()) return;
o->flag = CURSOR_NONE;
nzFree(o->desc);
rv_numRets = 0;
memset(rv_name, 0, sizeof(rv_name));
memset(rv_type, 0, sizeof(rv_type));
exclist = 0;
} /* sql_free */

void sql_closeFree(int cid)
{
const short *exc = exclist;
sql_close(cid);
if(!rv_lastStatus) {
exclist = exc;
sql_free(cid);
}
} /* sql_closeFree */

/* fetch row n from the open cursor.
 * Flag can be used to fetch first, last, next, or previous. */
static bool
fetchInternal(int cid, long n, int flag, bool remember)
{
/*
 * $char *internal_sname, *internal_cname;
 */
#line 1429 "dbinfx.ec"
  char *internal_sname, *internal_cname;
/*
 * $long nextrow, lastrow;
 */
#line 1430 "dbinfx.ec"
long nextrow, lastrow;
struct sqlda *internal_desc;
struct OCURS *o = findCursor(cid);

internal_cname = o->cname;
internal_desc = o->desc;
retsSetup(internal_desc);

/* don't do the fetch if we're looking for row 0 absolute,
 * that just nulls out the return values */
if(flag == 6 && !n) {
o->rownum = 0;
fetchZero:
retsCleanup();
exclist = 0;
return false;
}

lastrow = nextrow = o->rownum;
if(flag == 6) nextrow = n;
if(flag == 3) nextrow = 1;
if(isnotnull(lastrow)) { /* we haven't lost track yet */
if(flag == 1) ++nextrow;
if(flag == 2 && nextrow) --nextrow;
}
if(flag == 4) { /* fetch the last row */
nextrow = nullint; /* we just lost track */
}

if(!nextrow) goto fetchZero;

if(o->flag != CURSOR_OPENED)
errorPrint("2cannot fetch from cursor %d, not yet opened", cid);

/* The next line of code is very subtle.
I use to declare all cursors as scroll cursors.
It's a little inefficient, but who cares.
Then I discovered you can't fetch blobs from scroll cursors.
You can however fetch them from regular cursors,
even with an order by clause.
So cursors became non-scrolling by default.
If the programmer chooses to fetch by absolute number,
but he is really going in sequence, I turn them into
fetch-next statements, so that the cursor need not be a scroll cursor. */
if(flag == 6 &&
isnotnull(lastrow) && isnotnull(nextrow) &&
nextrow == lastrow+1)
flag=1;

debugExtra("fetch");

switch(flag) {
case 1:
/*
 * $fetch :internal_cname using descriptor internal_desc;
 */
#line 1483 "dbinfx.ec"
  {
#line 1483 "dbinfx.ec"
  static _FetchSpec _FS0 = { 0, 1, 0 };
  sqli_curs_fetch(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 256), (ifx_sqlda_t *)0, internal_desc, (char *)0, &_FS0);
#line 1483 "dbinfx.ec"
  }
break;
case 2:
/*
 * $fetch previous :internal_cname using descriptor internal_desc;
 */
#line 1486 "dbinfx.ec"
  {
#line 1486 "dbinfx.ec"
  static _FetchSpec _FS0 = { 0, 2, 0 };
  sqli_curs_fetch(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 256), (ifx_sqlda_t *)0, internal_desc, (char *)0, &_FS0);
#line 1486 "dbinfx.ec"
  }
break;
case 3:
/*
 * $fetch first :internal_cname using descriptor internal_desc;
 */
#line 1489 "dbinfx.ec"
  {
#line 1489 "dbinfx.ec"
  static _FetchSpec _FS0 = { 0, 3, 0 };
  sqli_curs_fetch(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 256), (ifx_sqlda_t *)0, internal_desc, (char *)0, &_FS0);
#line 1489 "dbinfx.ec"
  }
break;
case 4:
/*
 * $fetch last :internal_cname using descriptor internal_desc;
 */
#line 1492 "dbinfx.ec"
  {
#line 1492 "dbinfx.ec"
  static _FetchSpec _FS0 = { 0, 4, 0 };
  sqli_curs_fetch(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 256), (ifx_sqlda_t *)0, internal_desc, (char *)0, &_FS0);
#line 1492 "dbinfx.ec"
  }
break;
case 6:
if(isnull(nextrow))
errorPrint("2sql fetches absolute row using null index");
/*
 * $fetch absolute :nextrow :internal_cname using descriptor internal_desc;
 */
#line 1497 "dbinfx.ec"
  {
#line 1497 "dbinfx.ec"
  static ifx_sqlvar_t _sqibind[] = 
    {
      { 103, sizeof(nextrow), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
#line 1497 "dbinfx.ec"
    };
  static ifx_sqlda_t _SD0 = { 1, _sqibind, {0}, 1, 0 };
  static _FetchSpec _FS1 = { 0, 6, 0 };
#line 1497 "dbinfx.ec"
  _sqibind[0].sqldata = (char *) &nextrow;
  sqli_curs_fetch(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 256), &_SD0, internal_desc, (char *)0, &_FS1);
#line 1497 "dbinfx.ec"
  }
break;
default:
errorPrint("@fetchInternal() receives bad flag %d", flag);
} /* switch */
retsCleanup();

if(errorTrap()) return false;
exclist = 0;
if(ENGINE_ERRCODE == 100) return false; /* not found */
o->rownum = nextrow;

return true;
} /* fetchInternal */

bool sql_fetchFirst(int cid, ...)
{
      bool rc;
      va_start(sqlargs, cid);
      rc = fetchInternal(cid, 0L, 3, false);
      retsCopy(false, 0);
      return rc;
} /* sql_fetchFirst */

bool sql_fetchLast(int cid, ...)
{
      bool rc;
      va_start(sqlargs, cid);
      rc = fetchInternal(cid, 0L, 4, false);
      retsCopy(false, 0);
      return rc;
} /* sql_fetchLast */

bool sql_fetchNext(int cid, ...)
{
      bool rc;
      va_start(sqlargs, cid);
      rc = fetchInternal(cid, 0L, 1, false);
      retsCopy(false, 0);
      return rc;
} /* sql_fetchNext */

bool sql_fetchPrev(int cid, ...)
{
      bool rc;
      va_start(sqlargs, cid);
      rc = fetchInternal(cid, 0L, 2, false);
      retsCopy(false, 0);
      return rc;
} /* sql_fetchPrev */

bool sql_fetchAbs(int cid, long rownum, ...)
{
      bool rc;
      va_start(sqlargs, rownum);
      rc = fetchInternal(cid, rownum, 6, false);
      retsCopy(false, 0);
      return rc;
} /* sql_fetchAbs */


/*********************************************************************
Get the primary key for a table.
In informix, you can use system tables to get this information.
I haven't yet expanded this to a 3 part key.
*********************************************************************/

void
getPrimaryKey(char *tname, int *part1, int *part2, int *part3)
{
    int p1, p2, rc;
    char *s = strchr(tname, ':');
    *part1 = *part2 = *part3 = 0;
    if(!s) {
      rc = sql_select("select part1, part2 \
from sysconstraints c, systables t, sysindexes i \
where tabname = %S and t.tabid = c.tabid \
and constrtype = 'P' and c.idxname = i.idxname", tname, &p1, &p2);
    } else {
      *s = 0;
      rc = sql_select("select part1, part2 \
from %s:sysconstraints c, %s:systables t, %s:sysindexes i \
where tabname = %S and t.tabid = c.tabid \
and constrtype = 'P' and c.idxname = i.idxname", tname, tname, tname, s + 1, &p1, &p2);
      *s = ':';
    }
    if(rc)
      *part1 = p1, *part2 = p2;
}                       /* getPrimaryKey */

bool
showTables(void)
{
puts("Not implemented in Informix, but certainly doable through systables");
}                       /* showTables */

/* This can also be done by catalogs; it's on my list of things to do. */
bool
fetchForeign(char *tname)
{
i_puts(MSG_NYI);
} /* fetchForeign */

#line 1598 "dbinfx.ec"

Generated by  Doxygen 1.6.0   Back to index