~ubuntu-branches/ubuntu/jaunty/edbrowse/jaunty-security

« back to all changes in this revision

Viewing changes to src/dbinfx.c

  • Committer: Bazaar Package Importer
  • Author(s): Kapil Hari Paranjape
  • Date: 2008-04-09 18:55:23 UTC
  • mfrom: (1.1.4 upstream) (3.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080409185523-dqokcloumyn1ibn4
Tags: 3.3.4-1
* New upstream version (3.3.4).
 - Convert between iso8859-1 and utf-8 on the fly.
 - Support reading of pdf using pdftohtml.
 - French translation of html documentation.
 - Old html documentation renamed to usersguide.
 - Additional documentation on philosophy.
* debian/control:
 - Changed homepage to sourcefource site.
 - Moved homepage from description to its own field.
 - Added "poppler-utils | xpdf-utils" to Recommends.
 - Added "www-browser", "mail-reader" and "editor" to Provides. 
 - Removed "XS-" from Vcs-Svn tag.
 - Standards-Version: 3.7.3
* debian/docs: Added new documentation files
  from "doc/" subdirectory.
* debian/watch: Updated to use sourceforge site.
* debian/edbrowse.doc-base:
  - Changed name of upstream provided html documentation from
    "ebdoc.html" to "usersguide.html".
  - Changed section from "net" to "Network/Web Browsing".
* debian/install: Compiled binary is now in "src/".

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <sqlhdr.h>
 
2
#include <sqliapi.h>
 
3
static const char _Cn1[] = "blobinsert";
 
4
#line 1 "dbinfx.ec"
 
5
/*********************************************************************
 
6
dbinfx.ec: C-level interface to SQL.
 
7
This is a layer above esql/c,
 
8
since embedded SQL is often difficult to use, especially for new programmers.
 
9
Most SQL queries are relatively simple, whence the esql API is overkill.
 
10
Why mess with cryptic $directives when you can write:
 
11
sql_select("select this, that from table1, table2 where keycolumn = %d",
 
12
27, &this, &that);
 
13
 
 
14
More important, this API automatically aborts (or longjumps) if an error
 
15
occurs, unless that error has been specifically trapped by the program.
 
16
This minimizes application-level error-leg programming,
 
17
thereby reducing the code by as much as 1/3.
 
18
To accomplish this, the errorPrint() function,
 
19
supplied by the application, must never return.
 
20
We assume it passes the error message
 
21
to stderr and to a logfile,
 
22
and then exits, or longjumps to a recovery point.
 
23
 
 
24
Note that this API works within the context of our own C programming
 
25
environment.
 
26
 
 
27
Note that dbapi.h does NOT include the Informix header files.
 
28
That would violate the spirit of this layer,
 
29
which attempts to sheild the application from the details of the SQL API.
 
30
If the application needed to see anything in the Informix header files,
 
31
we would be doing something wrong.
 
32
*********************************************************************/
 
33
 
 
34
/* bring in the necessary Informix headers */
 
35
/* 
 
36
 * $include sqlca;
 
37
 */
 
38
#line 31 "dbinfx.ec"
 
39
 
 
40
#line 31 "dbinfx.ec"
 
41
#line 1 "/opt/informix/incl/esql/sqlca.h"
 
42
/****************************************************************************
 
43
 *
 
44
 *                               IBM INC.
 
45
 *
 
46
 *                           PROPRIETARY DATA
 
47
 *
 
48
 * Licensed Material - Property Of IBM
 
49
 *
 
50
 * "Restricted Materials of IBM"
 
51
 *
 
52
 * IBM Informix Client SDK
 
53
 *
 
54
 * (c)  Copyright IBM Corporation 1997, 2004. All rights reserved.
 
55
 *
 
56
 *  Title:      sqlca.h
 
57
 *  Description:
 
58
 *              SQL Control Area
 
59
 *
 
60
 ***************************************************************************
 
61
 */
 
62
 
 
63
#ifndef SQLCA_INCL
 
64
#define SQLCA_INCL
 
65
 
 
66
#include "ifxtypes.h"
 
67
 
 
68
#ifdef __cplusplus
 
69
extern "C" {
 
70
#endif
 
71
 
 
72
typedef struct sqlca_s
 
73
    {
 
74
    int4 sqlcode;
 
75
#ifdef DB2CLI
 
76
    char sqlerrm[600]; /* error message parameters */
 
77
#else /* DB2CLI */
 
78
    char sqlerrm[72]; /* error message parameters */
 
79
#endif /* DB2CLI */
 
80
    char sqlerrp[8];
 
81
    int4 sqlerrd[6];
 
82
                    /* 0 - estimated number of rows returned */
 
83
                    /* 1 - serial value after insert or  ISAM error code */
 
84
                    /* 2 - number of rows processed */
 
85
                    /* 3 - estimated cost */
 
86
                    /* 4 - offset of the error into the SQL statement */
 
87
                    /* 5 - rowid after insert  */
 
88
#ifdef _FGL_
 
89
    char sqlawarn[8];
 
90
#else
 
91
    struct sqlcaw_s
 
92
        {
 
93
        char sqlwarn0; /* = W if any of sqlwarn[1-7] = W */
 
94
        char sqlwarn1; /* = W if any truncation occurred or
 
95
                                database has transactions or
 
96
                                no privileges revoked */
 
97
        char sqlwarn2; /* = W if a null value returned or
 
98
                                ANSI database */
 
99
        char sqlwarn3; /* = W if no. in select list != no. in into list or
 
100
                                turbo backend or no privileges granted */
 
101
        char sqlwarn4; /* = W if no where clause on prepared update, delete or
 
102
                                incompatible float format */
 
103
        char sqlwarn5; /* = W if non-ANSI statement */
 
104
        char sqlwarn6; /* = W if server is in data replication secondary mode */
 
105
        char sqlwarn7; /* = W if database locale is different from proc_locale
 
106
                          = W if backend XPS and if explain avoid_execute is set
 
107
                              (for select, insert, delete and update only)
 
108
                        */
 
109
        } sqlwarn;
 
110
#endif
 
111
    } ifx_sqlca_t;
 
112
 
 
113
/* NOTE: 4gl assumes that the sqlwarn structure can be defined as
 
114
 *      sqlawarn -- an 8 character string, because single-char
 
115
 *      variables are not recognized in 4gl.
 
116
 *
 
117
 * If this structure should change, the code generated by 4gl compiler
 
118
 *      must also change
 
119
 */
 
120
 
 
121
#ifdef VMS
 
122
noshare
 
123
#endif /* VMS */
 
124
 
 
125
#define SQLNOTFOUND 100
 
126
 
 
127
#ifndef IFX_THREAD
 
128
#ifdef DB2CLI
 
129
#define sqlca ifmxsqlca
 
130
extern struct sqlca_s sqlca;
 
131
#else /* DB2CLI */
 
132
extern struct sqlca_s sqlca;
 
133
#endif /* DB2CLI */
 
134
 
 
135
extern int4 SQLCODE;
 
136
 
 
137
extern char SQLSTATE[];
 
138
#else /* IFX_THREAD */
 
139
extern int4 * ifx_sqlcode();
 
140
extern struct sqlca_s * ifx_sqlca();
 
141
#define SQLCODE (*(ifx_sqlcode()))
 
142
#define SQLSTATE ((char *)(ifx_sqlstate()))
 
143
#define sqlca (*(ifx_sqlca()))
 
144
#endif /* IFX_THREAD */
 
145
 
 
146
#ifdef __cplusplus
 
147
}
 
148
#endif
 
149
 
 
150
#endif /* SQLCA_INCL */
 
151
 
 
152
#line 110 "/opt/informix/incl/esql/sqlca.h"
 
153
/* 
 
154
 * $include sqltypes;
 
155
 */
 
156
#line 32 "dbinfx.ec"
 
157
 
 
158
#line 32 "dbinfx.ec"
 
159
#line 1 "/opt/informix/incl/esql/sqltypes.h"
 
160
/****************************************************************************
 
161
 *
 
162
 *                           IBM Corporation.
 
163
 *
 
164
 *                           PROPRIETARY DATA
 
165
 *
 
166
 * Licensed Material - Property Of IBM
 
167
 *
 
168
 * "Restricted Materials of IBM"
 
169
 *
 
170
 * IBM Informix Client SDK
 
171
 *
 
172
 * (c)  Copyright IBM Corporation 1985, 2004. All rights reserved.
 
173
 *
 
174
 *  Title:        sqltypes.h
 
175
 *  Description:  type definition
 
176
 *
 
177
 ***************************************************************************
 
178
 */
 
179
 
 
180
#ifndef CCHARTYPE
 
181
 
 
182
#include "ifxtypes.h"
 
183
 
 
184
/***********************
 
185
 * ++++ CAUTION ++++
 
186
 * Any new type to be added to the following lists should not
 
187
 * have the following bit pattern (binary short):
 
188
 *
 
189
 *      xxxxx111xxxxxxxx
 
190
 *
 
191
 * where x can be either 0 or 1.
 
192
 *
 
193
 * This is due to the use of the bits as SQLNONULL, SQLHOST and SQLNETFLT
 
194
 * (see below).
 
195
 *
 
196
 * FAILURE TO DO SO WOULD RESULT IN POSSIBLE ERRORS DURING CONVERSIONS.
 
197
 *
 
198
 ***********************/
 
199
 
 
200
 /* C language types */
 
201
 
 
202
#define CCHARTYPE       100
 
203
#define CSHORTTYPE      101
 
204
#define CINTTYPE        102
 
205
#define CLONGTYPE       103
 
206
#define CFLOATTYPE      104
 
207
#define CDOUBLETYPE     105
 
208
#define CDECIMALTYPE    107
 
209
#define CFIXCHARTYPE    108
 
210
#define CSTRINGTYPE     109
 
211
#define CDATETYPE       110
 
212
#define CMONEYTYPE      111
 
213
#define CDTIMETYPE      112
 
214
#define CLOCATORTYPE    113
 
215
#define CVCHARTYPE      114
 
216
#define CINVTYPE        115
 
217
#define CFILETYPE       116
 
218
#define CINT8TYPE       117
 
219
#define CCOLLTYPE       118
 
220
#define CLVCHARTYPE     119
 
221
#define CFIXBINTYPE     120
 
222
#define CVARBINTYPE     121
 
223
#define CBOOLTYPE       122
 
224
#define CROWTYPE        123
 
225
#define CLVCHARPTRTYPE  124
 
226
#define CTYPEMAX        25
 
227
 
 
228
#define USERCOLL(x)     ((x))
 
229
 
 
230
#define COLLMASK        0x007F  /* mask out CTYPEDCOLL or CCLIENTCOLL */
 
231
                                /* bit set for CCOLLTYPE or CROWTYPE */
 
232
#define ISCOLLECTIONVAR(n)  (((n) & COLLMASK) == CCOLLTYPE)
 
233
#define ISROWVAR(n)         (((n) & COLLMASK) == CROWTYPE)
 
234
#define ISCOLL_OR_ROWVAR(n)   ((ISCOLLECTIONVAR(n)) || (ISROWVAR(n)))
 
235
#define CCLIENTCOLL     SQLCLIENTCOLL /* client collection bit */
 
236
#define ISCLIENTCOLLECTION(n) (ISCOLLECTIONVAR(n) && ((n) & CCLIENTCOLL))
 
237
#define ISCLIENTCOMPLEX(n)    ((ISCLIENTCOLLECTION(n)) || (ISROWVAR(n)))
 
238
 
 
239
/*
 
240
 * The following are for client side only. They are included here
 
241
 * because of the above related definitions.
 
242
 */
 
243
#define CTYPEDCOLL       0x0080  /* typed collection bit */
 
244
#define CTYPEDCOLLUNMASK 0xFF7F  /* unmask typed collection bit */
 
245
#define ISTYPEDCOLLECTION(n)  (ISCOLLECTIONVAR(n) && ((n) & CTYPEDCOLL))
 
246
#define ISTYPEDROW(n)         (ISROWVAR(n) && ((n) & CTYPEDCOLL))
 
247
#define ISTYPEDCOLL_OR_ROW(n)  ( (ISTYPEDCOLLECTION(n)) || (ISTYPEDROW(n)) )
 
248
 
 
249
/*
 
250
 * Define all possible database types
 
251
 *   include C-ISAM types here as well as in isam.h
 
252
 */
 
253
 
 
254
#define SQLCHAR         0
 
255
#define SQLSMINT        1
 
256
#define SQLINT          2
 
257
#define SQLFLOAT        3
 
258
#define SQLSMFLOAT      4
 
259
#define SQLDECIMAL      5
 
260
#define SQLSERIAL       6
 
261
#define SQLDATE         7
 
262
#define SQLMONEY        8
 
263
#define SQLNULL         9
 
264
#define SQLDTIME        10
 
265
#define SQLBYTES        11
 
266
#define SQLTEXT         12
 
267
#define SQLVCHAR        13
 
268
#define SQLINTERVAL     14
 
269
#define SQLNCHAR        15
 
270
#define SQLNVCHAR       16
 
271
#define SQLINT8         17
 
272
#define SQLSERIAL8      18
 
273
#define SQLSET          19
 
274
#define SQLMULTISET     20
 
275
#define SQLLIST         21
 
276
#define SQLROW          22
 
277
#define SQLCOLLECTION   23
 
278
#define SQLROWREF       24
 
279
/*
 
280
 * Note: SQLXXX values from 25 through 39 are reserved to avoid collision
 
281
 *       with reserved PTXXX values in that same range. See p_types_t.h
 
282
 *
 
283
 * REFSER8: create tab with ref: referenced serial 8 rsam counter
 
284
 *      this is essentially a SERIAL8, but is an additional rsam counter
 
285
 *      this type only lives in the system catalogs and when read from
 
286
 *      disk is converted to SQLSERIAL8 with CD_REFSER8 set in ddcol_t
 
287
 *      ddc_flags we must distinguish from SERIAL8 to allow both
 
288
 *      counters in one tab
 
289
 */
 
290
#define SQLUDTVAR       40
 
291
#define SQLUDTFIXED     41
 
292
#define SQLREFSER8      42
 
293
 
 
294
/* These types are used by FE, they are not real major types in BE */
 
295
#define SQLLVARCHAR     43
 
296
#define SQLSENDRECV     44
 
297
#define SQLBOOL         45
 
298
#define SQLIMPEXP       46
 
299
#define SQLIMPEXPBIN    47
 
300
 
 
301
/* This type is used by the UDR code to track default parameters,
 
302
   it is not a real major type in BE */
 
303
#define SQLUDRDEFAULT   48
 
304
#define SQLDBSENDRECV   49
 
305
#define SQLSRVSENDRECV  50
 
306
 
 
307
/* Type used by DESCRIBE INPUT stmt to indicate input parameters whose
 
308
   types cannot be determined by the server */
 
309
#define SQLUNKNOWN      51
 
310
 
 
311
#define SQLMAXTYPES     52
 
312
 
 
313
#define SQLLABEL        SQLINT
 
314
 
 
315
#define SQLTYPE         0xFF    /* type mask            */
 
316
 
 
317
#define SQLNONULL       0x0100  /* disallow nulls       */
 
318
/* a bit to show that the value is from a host variable */
 
319
#define SQLHOST         0x0200  /* Value is from host var. */
 
320
#define SQLNETFLT       0x0400  /* float-to-decimal for networked backend */
 
321
#define SQLDISTINCT     0x0800  /* distinct bit         */
 
322
#define SQLNAMED        0x1000  /* Named row type vs row type */
 
323
#define SQLDLVARCHAR    0x2000  /* Distinct of lvarchar */
 
324
#define SQLDBOOLEAN     0x4000  /* Distinct of boolean */
 
325
#define SQLCLIENTCOLL   0x8000  /* Collection is processed on client */
 
326
 
 
327
/* we are overloading SQLDBOOLEAN for use with row types */
 
328
#define SQLVARROWTYPE   0x4000  /* varlen row type */
 
329
 
 
330
/* We overload SQLNAMED for use with constructor type, this flag
 
331
 * distinguish constructor types from other UDT types.
 
332
 *
 
333
 * Please do not test this bit directly, use macro ISCSTTYPE() instead.
 
334
 */
 
335
#define SQLCSTTYPE      0x1000  /* constructor type flag */
 
336
 
 
337
#define TYPEIDMASK      (SQLTYPE | SQLDISTINCT | SQLNAMED | \
 
338
                         SQLDLVARCHAR | SQLDBOOLEAN )
 
339
 
 
340
#define SIZCHAR         1
 
341
#define SIZSMINT        2
 
342
#define SIZINT          4
 
343
#define SIZFLOAT        (sizeof(double))
 
344
#define SIZSMFLOAT      (sizeof(float))
 
345
#define SIZDECIMAL      17      /* decimal(32) */
 
346
#define SIZSERIAL       4
 
347
#define SIZDATE         4
 
348
#define SIZMONEY        17      /* decimal(32) */
 
349
#define SIZDTIME        7       /* decimal(12,0) */
 
350
#define SIZVCHAR        1
 
351
#define SIZINT8         (sizeof(short) + sizeof(muint) * 2)
 
352
#define SIZSERIAL8      SIZINT8
 
353
#define SIZCOLL         sizeof (ifx_collection_t)
 
354
#define SIZSET          SIZCOLL
 
355
#define SIZMULTISET     SIZCOLL
 
356
#define SIZLIST         SIZCOLL
 
357
#define SIZROWREF       sizeof (ifx_ref_t)
 
358
 
 
359
#define MASKNONULL(t)   ((t) & (SQLTYPE))
 
360
 
 
361
/*
 
362
 * As part of an sqlda structure from DESCRIBE, you can test whether a
 
363
 * column accepts or can return nulls, using the expression:
 
364
 *     ISCOLUMNULLABLE(ud->sqlvar[n].sqlflags)
 
365
 * (for sqlda structure pointer ud and column number n).
 
366
 */
 
367
 
 
368
#define ISCOLUMNULLABLE(t)      (((t) & (SQLNONULL)) ? 0 : 1)
 
369
#define ISSQLTYPE(t)    (MASKNONULL(t) >= SQLCHAR && MASKNONULL(t) < SQLMAXTYPES)
 
370
 
 
371
#define DECCOLLEN       8192    /* decimal size definition for DEC(32,0) in syscolumns */
 
372
 
 
373
 
 
374
/*
 
375
 * SQL types macros
 
376
 */
 
377
#define ISDECTYPE(t)            (MASKNONULL(t) == SQLDECIMAL || \
 
378
                                 MASKNONULL(t) == SQLMONEY || \
 
379
                                 MASKNONULL(t) == SQLDTIME || \
 
380
                                 MASKNONULL(t) == SQLINTERVAL)
 
381
#define ISNUMERICTYPE(t)        (MASKNONULL(t) == SQLSMINT || \
 
382
                                 MASKNONULL(t) == SQLINT || \
 
383
                                 MASKNONULL(t) == SQLINT8 || \
 
384
                                 MASKNONULL(t) == SQLFLOAT || \
 
385
                                 MASKNONULL(t) == SQLSMFLOAT || \
 
386
                                 MASKNONULL(t) == SQLMONEY || \
 
387
                                 MASKNONULL(t) == SQLSERIAL || \
 
388
                                 MASKNONULL(t) == SQLSERIAL8 || \
 
389
                                 MASKNONULL(t) == SQLDECIMAL)
 
390
#define ISBLOBTYPE(type)        (ISBYTESTYPE (type) || ISTEXTTYPE(type))
 
391
#define ISBYTESTYPE(type)       (MASKNONULL(type) == SQLBYTES)
 
392
#define ISTEXTTYPE(type)        (MASKNONULL(type) == SQLTEXT)
 
393
#define ISSQLHOST(t)            (((t) & SQLHOST) == SQLHOST)
 
394
 
 
395
#ifndef NLS
 
396
#define ISVCTYPE(t)             (MASKNONULL(t) == SQLVCHAR)
 
397
#define ISCHARTYPE(t)           (MASKNONULL(t) == SQLCHAR)
 
398
#else
 
399
#define ISVCTYPE(t)             (MASKNONULL(t) == SQLVCHAR || \
 
400
                                 MASKNONULL(t) == SQLNVCHAR)
 
401
#define ISCHARTYPE(t)           (MASKNONULL(t) == SQLCHAR || \
 
402
                                 MASKNONULL(t) == SQLNCHAR)
 
403
#define ISNSTRINGTYPE(t)        (MASKNONULL(t) == SQLNCHAR || \
 
404
                                 MASKNONULL(t) == SQLNVCHAR)
 
405
#endif /* NLS */
 
406
 
 
407
#define ISSTRINGTYPE(t)         (ISVCTYPE(t) || ISCHARTYPE(t))
 
408
 
 
409
#define ISUDTVARTYPE(t)         (MASKNONULL(t) == SQLUDTVAR)
 
410
#define ISUDTFIXEDTYPE(t)       (MASKNONULL(t) == SQLUDTFIXED)
 
411
#define ISUDTTYPE(t)            (ISUDTVARTYPE(t) || ISUDTFIXEDTYPE(t))
 
412
 
 
413
#define ISCOMPLEXTYPE(t)        (ISROWTYPE(t) || ISCOLLTYPE(t))
 
414
#define ISROWTYPE(t)            (MASKNONULL(t) == SQLROW)
 
415
#define ISLISTTYPE(t)           (MASKNONULL(t) == SQLLIST)
 
416
#define ISMULTISETTYPE(t)       (MASKNONULL(t) == SQLMULTISET)
 
417
#define ISREFTYPE(t)            (MASKNONULL(t) == SQLROWREF)
 
418
#define ISSETTYPE(t)            (MASKNONULL(t) == SQLSET)
 
419
#define ISCOLLECTTYPE(t)        (MASKNONULL(t) == SQLCOLLECTION)
 
420
#define ISCOLLTYPE(t)           (ISSETTYPE(t) || ISMULTISETTYPE(t) ||\
 
421
                                 ISLISTTYPE(t) || ISCOLLECTTYPE(t))
 
422
 
 
423
#define ISSERIALTYPE(t)         (((t) & SQLTYPE) == SQLSERIAL || \
 
424
                                 ((t) & SQLTYPE) == SQLSERIAL8 || \
 
425
                                 ((t) & SQLTYPE) == SQLREFSER8)
 
426
 
 
427
#define ISDISTINCTTYPE(t)       ((t) & SQLDISTINCT)
 
428
#define ISCSTTYPE(t)            (ISUDTTYPE(t) && ((t) & SQLCSTTYPE))
 
429
 
 
430
/* these macros are used to distinguish NLS char types and non-nls (ASCII)
 
431
 * char types
 
432
 */
 
433
#define ISNONNLSCHAR(t)         (MASKNONULL(t) == SQLCHAR || \
 
434
                                 MASKNONULL(t) == SQLVCHAR)
 
435
 
 
436
/* these macros should be used in case statements
 
437
 */
 
438
#ifndef NLS
 
439
#define CHARCASE                SQLCHAR
 
440
#define VCHARCASE               SQLVCHAR
 
441
#else
 
442
#define CHARCASE                SQLCHAR: case SQLNCHAR
 
443
#define VCHARCASE               SQLVCHAR: case SQLNVCHAR
 
444
#endif /* NLS */
 
445
 
 
446
#define UDTCASE                 SQLUDTVAR: case SQLUDTFIXED
 
447
 
 
448
/*
 
449
 * C types macros
 
450
 */
 
451
#define ISBLOBCTYPE(type)       (ISLOCTYPE(type) || ISFILETYPE(type))
 
452
#define ISLOCTYPE(type)         (MASKNONULL(type) == CLOCATORTYPE)
 
453
#define ISFILETYPE(type)        (MASKNONULL(type) == CFILETYPE)
 
454
#define ISLVCHARCTYPE(type)     (MASKNONULL(type) == CLVCHARTYPE)
 
455
#define ISLVCHARCPTRTYPE(type)  (MASKNONULL(type) == CLVCHARPTRTYPE)
 
456
#define ISFIXBINCTYPE(type)     (MASKNONULL(type) == CFIXBINTYPE)
 
457
#define ISVARBINCTYPE(type)     (MASKNONULL(type) == CVARBINTYPE)
 
458
#define ISBOOLCTYPE(type)       (MASKNONULL(type) == CBOOLTYPE)
 
459
 
 
460
 
 
461
#define ISOPTICALCOL(type)      (type == 'O')
 
462
 
 
463
#define DEFDECIMAL      9       /* default decimal(16) size */
 
464
#define DEFMONEY        9       /* default decimal(16) size */
 
465
 
 
466
#define SYSPUBLIC       "public"
 
467
 
 
468
/*
 
469
 * if an SQL type is specified, convert to default C type
 
470
 *  map C int to either short or long
 
471
 */
 
472
 
 
473
 
 
474
#define TYPEMAX SQLMAXTYPES
 
475
 
 
476
extern int2 sqlctype[];
 
477
 
 
478
#define toctype(ctype, type) \
 
479
    { \
 
480
    if (type == CINTTYPE) \
 
481
    { \
 
482
      if (sizeof(mint) == sizeof(mlong)) \
 
483
          { ctype = type = CLONGTYPE; } \
 
484
      else if (sizeof(mint) == sizeof(int2)) \
 
485
          { ctype = type = CSHORTTYPE; } \
 
486
      else \
 
487
          { ctype = CLONGTYPE; type = CINTTYPE; } \
 
488
    } \
 
489
    else if (type >= 0 && type < TYPEMAX) \
 
490
        ctype = sqlctype[type]; \
 
491
    else \
 
492
        ctype = type; \
 
493
    }
 
494
 
 
495
 
 
496
 
 
497
/* Extended ID definitions for predefined UDT's */
 
498
/* These can not be changed because sqli is using
 
499
 * them.  If we change them, the client has to recompile.
 
500
 * NOTE: This order must match the definitions in boot90.sql
 
501
 */
 
502
 
 
503
#define XID_LVARCHAR            1
 
504
#define XID_SENDRECV            2
 
505
#define XID_IMPEXP              3
 
506
#define XID_IMPEXPBIN           4
 
507
#define XID_BOOLEAN             5
 
508
#define XID_POINTER             6
 
509
#define XID_INDEXKEYARRAY       7
 
510
#define XID_RTNPARAMTYPES       8
 
511
#define XID_SELFUNCARGS         9
 
512
#define XID_BLOB                10
 
513
#define XID_CLOB                11
 
514
#define XID_LOLIST              12
 
515
#define XID_IFX_LO_SPEC         13
 
516
#define XID_IFX_LO_STAT         14
 
517
#define XID_STAT                15
 
518
#define XID_CLIENTBINVAL        16
 
519
#define XID_UDTMODIFIERS        17
 
520
#define XID_AGGMODIFIERS        18
 
521
#define XID_UDRMODIFIERS        19
 
522
#define XID_GUID                20
 
523
#define XID_DBSENDRECV          21
 
524
#define XID_SRVSENDRECV         22
 
525
#define XID_FUNCARG             23
 
526
 
 
527
/* Max size definitions for the predefined UDT's.
 
528
 * Only a few are currently defined.
 
529
 */
 
530
#define SIZINDEXKEYARRAY        1024
 
531
#define SIZLVARCHAR             2048
 
532
#define SIZRTNPARAMTYPES        4096
 
533
#define SIZSTAT                 272
 
534
#define SIZGUID                 16
 
535
 
 
536
/* Alignment required by predefined UDT's.
 
537
 * Only a few are currently defined.  At a minimum,
 
538
 * all with alignment not 1 should be defined here
 
539
 * and used throughout the code.
 
540
 */
 
541
#define ALNINDEXKEYARRAY        4
 
542
#define ALNSTAT                 8
 
543
 
 
544
 
 
545
#define USER_XTDTYPEID_START    2048
 
546
 
 
547
/* These macros should be used to test lvarchar and distinct of lvarchar */
 
548
 
 
549
#define ISLVARCHARXTYPE(t, xid)  (ISUDTTYPE((t)) && (xid) == XID_LVARCHAR)
 
550
#define ISDISTINCTLVARCHAR(t)   ((t) & SQLDLVARCHAR)
 
551
#define LIKELVARCHARXTYPE(t,xid) ((ISLVARCHARXTYPE(t,xid))||\
 
552
                                   ISDISTINCTLVARCHAR(t))
 
553
 
 
554
#define ISSMARTBLOB(type, xid)  (ISUDTTYPE((type)) && \
 
555
                                    ((xid == XID_CLOB) || (xid == XID_BLOB)))
 
556
 
 
557
/* These macros should be used to test boolean and distinct of boolean */
 
558
#define ISBOOLEANXTYPE(t, xid)  (ISUDTTYPE((t)) && (xid) == XID_BOOLEAN)
 
559
#define ISDISTINCTBOOLEAN(t)    (((t) & SQLDBOOLEAN) && \
 
560
                                    (ISUDTTYPE(t)))
 
561
#define LIKEBOOLEANXTYPE(t,xid) ((ISBOOLEANXTYPE(t,xid))||\
 
562
                                  ISDISTINCTBOOLEAN(t))
 
563
 
 
564
#define ISFIXLENGTHTYPE(t)      (!ISBYTESTYPE(t) && !ISTEXTTYPE(t) \
 
565
                                        && !ISCOMPLEXTYPE(t) \
 
566
                                        && !ISUDTVARTYPE(t) \
 
567
                                        && !ISVCTYPE(t))
 
568
#endif /* CCHARTYPE */
 
569
#line 409 "/opt/informix/incl/esql/sqltypes.h"
 
570
/* 
 
571
 * $include sqlda;
 
572
 */
 
573
#line 33 "dbinfx.ec"
 
574
 
 
575
#line 33 "dbinfx.ec"
 
576
#line 1 "/opt/informix/incl/esql/sqlda.h"
 
577
/****************************************************************************
 
578
 *
 
579
 *                           IBM Corporation.
 
580
 *
 
581
 *                           PROPRIETARY DATA
 
582
 *
 
583
 * Licensed Material - Property Of IBM
 
584
 *
 
585
 * "Restricted Materials of IBM"
 
586
 *
 
587
 * IBM Informix Client SDK
 
588
 *
 
589
 * (c)  Copyright IBM Corporation 1985, 2004. All rights reserved.
 
590
 *
 
591
 *  Title:         sqlda.h
 
592
 *  Description:   SQL Data Description Area
 
593
 *
 
594
 ***************************************************************************
 
595
 */
 
596
 
 
597
 
 
598
#ifndef _SQLDA
 
599
#define _SQLDA
 
600
 
 
601
#include "ifxtypes.h"
 
602
 
 
603
typedef struct sqlvar_struct
 
604
    {
 
605
    int2 sqltype;               /* variable type                */
 
606
    int4 sqllen;                /* length in bytes              */
 
607
    char *sqldata;              /* pointer to data              */
 
608
    int2 *sqlind;               /* pointer to indicator         */
 
609
    char  *sqlname;             /* variable name                */
 
610
    char  *sqlformat;           /* reserved for future use      */
 
611
    int2 sqlitype;              /* ind variable type            */
 
612
    int2 sqlilen;               /* ind length in bytes          */
 
613
    char *sqlidata;             /* ind data pointer             */
 
614
    int4  sqlxid;               /* extended id type             */
 
615
    char *sqltypename;          /* extended type name           */
 
616
    int2 sqltypelen;            /* length of extended type name */
 
617
    int2 sqlownerlen;           /* length of owner name         */
 
618
    int2 sqlsourcetype; /* source type for distinct of built-ins */
 
619
    char *sqlownername;         /* owner name                   */
 
620
    int4 sqlsourceid;           /* extended id of source type   */
 
621
 
 
622
    /*
 
623
     * sqlilongdata is new.  It supports data that exceeds the 32k
 
624
     * limit.  sqlilen and sqlidata are for backward compatibility
 
625
     * and they have maximum value of <32K.
 
626
     */
 
627
    char *sqlilongdata;         /* for data field beyond 32K    */
 
628
 
 
629
    /*
 
630
     * As part of an SQL DESCRIPTOR (ALLOCATE DESCRIPTOR, etc), sqlflags is
 
631
     * reserved for internal use.
 
632
     * As part of an sqlda structure from DESCRIBE, you can test whether a
 
633
     * column accepts or can return nulls, using the expression:
 
634
     *     ISCOLUMNULLABLE(ud->sqlvar[n].sqlflags)
 
635
     * (for sqlda structure pointer ud and column number n).
 
636
     */
 
637
 
 
638
    int4 sqlflags;
 
639
    void *sqlreserved;          /* reserved for future use      */
 
640
    } ifx_sqlvar_t;
 
641
 
 
642
typedef struct sqlda
 
643
    {
 
644
    int2 sqld;
 
645
    ifx_sqlvar_t *sqlvar;
 
646
    char desc_name[19];         /* descriptor name              */
 
647
    int2 desc_occ;              /* size of sqlda structure      */
 
648
    struct sqlda *desc_next;    /* pointer to next sqlda struct */
 
649
    void *reserved;             /* reserved for future use */
 
650
    } ifx_sqlda_t;
 
651
 
 
652
#endif /* _SQLDA */
 
653
#line 76 "/opt/informix/incl/esql/sqlda.h"
 
654
/* 
 
655
 * $include locator;
 
656
 */
 
657
#line 34 "dbinfx.ec"
 
658
 
 
659
#line 34 "dbinfx.ec"
 
660
#line 1 "/opt/informix/incl/esql/locator.h"
 
661
/****************************************************************************
 
662
 *
 
663
 *                               IBM INC.
 
664
 *
 
665
 *                           PROPRIETARY DATA
 
666
 *
 
667
 * Licensed Material - Property Of IBM
 
668
 *
 
669
 * "Restricted Materials of IBM"
 
670
 *
 
671
 * IBM Informix Client SDK
 
672
 *
 
673
 * (c)  Copyright IBM Corporation 1997, 2004. All rights reserved.
 
674
 *
 
675
 *  Title:      locator.h
 
676
 *
 
677
 *  Description:
 
678
 *              'locator.h' defines 'loc_t' the locator struct.
 
679
 *
 
680
 ***************************************************************************
 
681
 */
 
682
 
 
683
#ifndef LOCATOR_INCL            /* avoid multiple includes */
 
684
#define LOCATOR_INCL
 
685
 
 
686
#include "ifxtypes.h"
 
687
 
 
688
#include "int8.h"
 
689
 
 
690
/*
 
691
Locators are used to store TEXT or BYTE fields (blobs) in ESQL
 
692
programs.  The "loc_t" structure is described below.  Fields denoted
 
693
USER should be set by the user program and will be examined by the DBMS
 
694
system.  Those denoted SYSTEM are set by the system and may be examined
 
695
by the user program.  Those denoted INTERNAL contain data only the
 
696
system manupilates and examines.
 
697
 
 
698
If "loc_loctype" is set to LOCMEMORY, then the blob is stored in
 
699
primary memory.  The memory buffer is pointed to by the variant
 
700
"loc_buffer".  The field "loc_bufsize" gives the size of "loc_buffer".
 
701
If the "loc_bufsize" is set to "-1" and "loc_mflags" is set to "0"
 
702
and the locator is used for a fetch, memory is obtained using "malloc"
 
703
and "loc_buffer" and "loc_bufsize" are set.
 
704
 
 
705
If "loc_loctype" is set to LOCFILE, then the blob is stored in a file.
 
706
The file descriptor of an open operating system file is specified in
 
707
"loc_fd".
 
708
 
 
709
If "loc_loctype" is set to LOCFNAME, the the blob is stored in a file
 
710
and the name of the file is given.  The DBMS will open or created the
 
711
file at the correct time and in the correct mode.
 
712
 
 
713
If the "loc_loctype" is set to LOCUSER, "loc_(open/close/read/write)"
 
714
are called.  If the blob is an input to a SQL statement, "loc_open" is
 
715
called with the parameter "LOC_RONLY".  If the blob is an output target
 
716
for an SQL statement, "loc_open" is called with the parameter
 
717
"LOC_WONLY".
 
718
 
 
719
"loc_size" specifies the maximum number of bytes to use when the
 
720
locator is an input target to an SQL statement. It specifies the number
 
721
of bytes returned if the locator is an output target.  If "loc_loctype"
 
722
is LOCFILE or LOCUSER, it can be set to -1 to indicate transfer until
 
723
end-of-file.
 
724
 
 
725
"loc_indicator" is set by the user to -1 to indicate a NULL blob.  It
 
726
will be  set to -1 if a NULL blob is retrieved.  If the blob to be
 
727
retrieved will not fit in the space provided, the indicator contains
 
728
the size of the blob.
 
729
 
 
730
"loc_status" is the status return of locator operations.
 
731
 
 
732
"loc_type" is the "blob" type (SQLTEXT, SQLBYTES, ...).
 
733
 
 
734
"loc_user_env" is a pointer for the user's private use. It is neither
 
735
set nor examined by the system.  "loc_user_env" as well as the
 
736
"loc_union" fieds may be used by user supplied routines to store and
 
737
communicate information.
 
738
*/
 
739
 
 
740
typedef struct tag_loc_t
 
741
    {
 
742
    int2 loc_loctype;           /* USER: type of locator - see below    */
 
743
    union                       /* variant on 'loc'                     */
 
744
        {
 
745
        struct                  /* case LOCMEMORY                       */
 
746
            {
 
747
            int4  lc_bufsize;   /* USER: buffer size */
 
748
            char *lc_buffer;    /* USER: memory buffer to use           */
 
749
            char *lc_currdata_p;/* INTERNAL: current memory buffer      */
 
750
            mint   lc_mflags;   /* USER/INTERNAL: memory flags          */
 
751
                                /*                      (see below)     */
 
752
            } lc_mem;
 
753
 
 
754
        struct                  /* cases L0CFNAME & LOCFILE             */
 
755
            {
 
756
            char *lc_fname;     /* USER: file name                      */
 
757
            mint  lc_mode;      /* USER: perm. bits used if creating    */
 
758
            mint  lc_fd;        /* USER: os file descriptior            */
 
759
            int4  lc_position;  /* INTERNAL: seek position              */
 
760
            } lc_file;
 
761
        } lc_union;
 
762
 
 
763
    int4  loc_indicator;        /* USER SYSTEM: indicator               */
 
764
    int4  loc_type;             /* USER SYSTEM: type of blob            */
 
765
    int4  loc_size;             /* USER SYSTEM: num bytes in blob or -1 */
 
766
    mint  loc_status;           /* SYSTEM: status return of locator ops */
 
767
    char *loc_user_env;         /* USER: for the user's PRIVATE use     */
 
768
    int4  loc_xfercount;        /* INTERNAL/SYSTEM: Transfer count      */
 
769
 
 
770
#if defined(__STDC__) || defined(__cplusplus)
 
771
    mint (*loc_open)(struct tag_loc_t *loc, mint flag, mint bsize);
 
772
    mint (*loc_close)(struct tag_loc_t *loc);
 
773
    mint (*loc_read)(struct tag_loc_t *loc, char *buffer, mint buflen);
 
774
    mint (*loc_write)(struct tag_loc_t *loc, char *buffer, mint buflen);
 
775
#else
 
776
    mint (*loc_open)();
 
777
    mint (*loc_close)();
 
778
    mint (*loc_read)();
 
779
    mint (*loc_write)();
 
780
#endif /* defined(__STDC__) || defined(__cplusplus) */
 
781
 
 
782
    mint   loc_oflags;          /* USER/INTERNAL: see flag definitions below */
 
783
    } loc_t;
 
784
 
 
785
#define loc_fname       lc_union.lc_file.lc_fname
 
786
#define loc_fd          lc_union.lc_file.lc_fd
 
787
#define loc_position    lc_union.lc_file.lc_position    
 
788
#define loc_bufsize     lc_union.lc_mem.lc_bufsize
 
789
#define loc_buffer      lc_union.lc_mem.lc_buffer
 
790
#define loc_currdata_p  lc_union.lc_mem.lc_currdata_p
 
791
#define loc_mflags      lc_union.lc_mem.lc_mflags
 
792
 
 
793
/* Enumeration literals for loc_loctype */
 
794
 
 
795
#define LOCMEMORY       1               /* memory storage */
 
796
#define LOCFNAME        2               /* File storage with file name */
 
797
#define LOCFILE         3               /* File storage with fd */
 
798
#define LOCUSER         4               /* User define functions */
 
799
 
 
800
/* passed to loc_open and stored in loc_oflags */
 
801
#define LOC_RONLY       0x1             /* read only */
 
802
#define LOC_WONLY       0x2             /* write only */
 
803
 
 
804
/* LOC_APPEND can be set when the locator is created
 
805
 * if the file is to be appended to instead of created
 
806
 */
 
807
#define LOC_APPEND      0x4             /* write with append */
 
808
#define LOC_TEMPFILE    0x8             /* 4GL tempfile blob */
 
809
 
 
810
/* LOC_USEALL can be set to force the maximum size of the blob to always be
 
811
 * used when the blob is an input source.  This is the same as setting the
 
812
 * loc_size field to -1.  Good for LOCFILE or LOCFNAME blobs only.
 
813
 */
 
814
#define LOC_USEALL      0x10            /* ignore loc_size field */
 
815
#define LOC_DESCRIPTOR  0x20            /* BLOB is optical descriptor */
 
816
 
 
817
/* length of the encoded descriptor text */
 
818
#define LOC_DESCRIPTOR_SIZE 112
 
819
 
 
820
/* passed to loc_open and stored in loc_mflags */
 
821
#define LOC_ALLOC       0x1             /* free and alloc memory */
 
822
 
 
823
/* Flags to indicate if file is on the server or client */
 
824
#define LO_CLIENT_FILE  0x20000000
 
825
#define LO_SERVER_FILE  0x10000000
 
826
 
 
827
/*******************************************************************************
 
828
 * File open flags used for operating system file open via
 
829
 *      - ifx_lo_copy_to_lo
 
830
 *      - ifx_lo_copy_to_file
 
831
 *      - ifx_file_to_file
 
832
 *
 
833
 ******************************************************************************/
 
834
 
 
835
#define LO_O_EXCL             0x00000001 /* fail if file exists */
 
836
#define LO_O_APPEND           0x00000002 /* append to end of file */
 
837
#define LO_O_TRUNC            0x00000004 /* turncate to 0 if file exists */
 
838
#define LO_O_RDWR             0x00000008 /* read/write (default) */
 
839
#define LO_O_RDONLY           0x00000010 /* read-only (from-flags only) */
 
840
#define LO_O_WRONLY           0x00000020 /* write-only (to-flags only) */
 
841
#define LO_O_BINARY           0x00000040 /* binary-mode (default) */
 
842
#define LO_O_TEXT             0x00000080 /* text-mode (default off)*/
 
843
 
 
844
 
 
845
/*******************************************************************************
 
846
 *
 
847
 * Smartblob Definitions
 
848
 *
 
849
 ******************************************************************************/
 
850
 
 
851
/******************************************************************************
 
852
 * Open flags: see ESQL/C documentation for further explanation.
 
853
 *
 
854
 * LO_APPEND - Positions the seek position to end-of-file + 1. Affects write
 
855
 * operations. Reads can still seek anywhere in the LO. Writes always append.
 
856
 *
 
857
 * LO_SEQUENTIAL - If set overrides optimizer decision. Indicates that
 
858
 * reads are sequential in either forward or reverse direction.
 
859
 *
 
860
 * LO_RANDOM - If set overrides optimizer decision. Indicates that I/O is
 
861
 * random and that the system should not read-ahead.
 
862
 * LO_FORWARD - Only used for sequential access. Indicates that the sequential
 
863
 * access will be in a forward direction, i.e. from low offset to higher offset.
 
864
 * LO_REVERSE - Only used for sequential access. Indicates that the sequential
 
865
 * access will be in a reverse direction.
 
866
 *
 
867
 * LO_BUFFER - If set overrides optimizer decision. I/O goes through the
 
868
 * buffer pool.
 
869
 *
 
870
 * LO_NOBUFFER - If set then I/O does not use the buffer pool.
 
871
 ******************************************************************************/
 
872
 
 
873
#define LO_APPEND       0x1
 
874
#define LO_WRONLY       0x2
 
875
#define LO_RDONLY       0x4     /* default */
 
876
#define LO_RDWR         0x8
 
877
#define LO_DIRTY_READ   0x10
 
878
 
 
879
#define LO_RANDOM       0x20    /* default is determined by optimizer */
 
880
#define LO_SEQUENTIAL   0x40    /* default is determined by optimizer */
 
881
 
 
882
#define LO_FORWARD      0x80    /* default */
 
883
#define LO_REVERSE      0x100
 
884
 
 
885
#define LO_BUFFER       0x200   /* default is determined by optimizer */
 
886
#define LO_NOBUFFER     0x400   /* default is determined by optimizer */
 
887
#define LO_NODIRTY_READ 0x800
 
888
 
 
889
#define LO_LOCKALL      0x1000  /* default */
 
890
#define LO_LOCKRANGE    0x2000
 
891
 
 
892
#ifndef REMOVE_VECTORIO
 
893
#define LO_VECTORIO     0x4000
 
894
#endif
 
895
 
 
896
/*
 
897
 *  Another set of open flags are defined to make the flags more meaningful
 
898
 */
 
899
 
 
900
#define LO_OPEN_APPEND       LO_APPEND
 
901
#define LO_OPEN_WRONLY       LO_WRONLY
 
902
#define LO_OPEN_RDONLY       LO_RDONLY     /* default */
 
903
#define LO_OPEN_RDWR         LO_RDWR
 
904
#define LO_OPEN_DIRTY_READ   LO_DIRTY_READ
 
905
 
 
906
#define LO_OPEN_RANDOM       LO_RANDOM      /* default is determined by optimizer */
 
907
#define LO_OPEN_SEQUENTIAL   LO_SEQUENTIAL  /* default is determined by optimizer */
 
908
 
 
909
#define LO_OPEN_FORWARD      LO_FORWARD    /* default */
 
910
#define LO_OPEN_REVERSE      LO_REVERSE
 
911
 
 
912
#define LO_OPEN_BUFFER       LO_BUFFER     /* default is determined by optimizer */
 
913
#define LO_OPEN_NOBUFFER     LO_NOBUFFER   /* default is determined by optimizer */
 
914
#define LO_OPEN_NODIRTY_READ LO_NODIRTY_READ
 
915
 
 
916
#define LO_OPEN_LOCKALL      LO_LOCKALL  /* default */
 
917
#define LO_OPEN_LOCKRANGE    LO_LOCKRANGE
 
918
 
 
919
/* When setting the MI_LO_NOBUFFER flag for write operations, please
 
920
 * don't set this flag if the object is small. It usually causes a synchronous
 
921
 * flush of the log and a synchronous flush of pages written - this is
 
922
 * very slow. Instead use buffered I/O for small writes.
 
923
 */
 
924
#define LO_NOBUFFER_SIZE_THRESHOLD 8080
 
925
 
 
926
/*see Informix internal use file /vobs/tristarp/incl/sblob.h for other flags*/
 
927
 
 
928
/*******************************************************************************
 
929
 * LO create-time flags:
 
930
 *
 
931
 * Bitmask - Set/Get via ifx_lo_specset_flags() on ifx_lo_create_spec_t.
 
932
 *
 
933
 * New applications should use the flags which begin LO_ATTR_
 
934
 * The second set of flags are defined for backward compatibility only.
 
935
 ******************************************************************************/
 
936
 
 
937
#define LO_ATTR_LOG                          0x0001
 
938
#define LO_ATTR_NOLOG                        0x0002
 
939
#define LO_ATTR_DELAY_LOG                    0x0004
 
940
#define LO_ATTR_KEEP_LASTACCESS_TIME         0x0008
 
941
#define LO_ATTR_NOKEEP_LASTACCESS_TIME       0x0010
 
942
#define LO_ATTR_HIGH_INTEG                   0x0020
 
943
#define LO_ATTR_MODERATE_INTEG               0x0040
 
944
#define LO_ATTR_TEMP                         0x0080
 
945
 
 
946
/* these 7 values are defined for backward compatibility only */
 
947
#define LO_LOG                          0x0001
 
948
#define LO_NOLOG                        0x0002
 
949
#define LO_DELAY_LOG                    0x0004
 
950
#define LO_KEEP_LASTACCESS_TIME         0x0008
 
951
#define LO_NOKEEP_LASTACCESS_TIME       0x0010
 
952
#define LO_HIGH_INTEG                   0x0020
 
953
#define LO_MODERATE_INTEG               0x0040
 
954
#define LO_TEMP                         0x0080
 
955
 
 
956
/* these flags are defined to make the create flags more meaningful */
 
957
#define LO_CREATE_LOG                          0x0001
 
958
#define LO_CREATE_NOLOG                        0x0002
 
959
#define LO_CREATE_DELAY_LOG                    0x0004
 
960
#define LO_CREATE_KEEP_LASTACCESS_TIME         0x0008
 
961
#define LO_CREATE_NOKEEP_LASTACCESS_TIME       0x0010
 
962
#define LO_CREATE_HIGH_INTEG                   0x0020
 
963
#define LO_CREATE_MODERATE_INTEG               0x0040
 
964
#define LO_CREATE_TEMP                         0x0080
 
965
 
 
966
/*******************************************************************************
 
967
 * Symbolic constants for the "lseek" routine
 
968
 ******************************************************************************/
 
969
 
 
970
#define LO_SEEK_SET 0   /* Set curr. pos. to "offset"           */
 
971
#define LO_SEEK_CUR 1   /* Set curr. pos. to current + "offset" */
 
972
#define LO_SEEK_END 2   /* Set curr. pos. to EOF + "offset"     */
 
973
 
 
974
 
 
975
/*******************************************************************************
 
976
 * Symbolic constants for lo_lock and lo_unlock routines.
 
977
 ******************************************************************************/
 
978
 
 
979
#define LO_SHARED_MODE          1       /* ISSLOCK */
 
980
#define LO_EXCLUSIVE_MODE       2       /* ISXLOCK */
 
981
 
 
982
#define LO_MAX_END              -1
 
983
#define LO_CURRENT_END          -2
 
984
 
 
985
/*******************************************************************************
 
986
 * ifx_lo_create_spec_t:
 
987
 *
 
988
 * This is an opaque structure used for creating smartblobs. The
 
989
 * user may examin and/or set certain fields herein by using
 
990
 * ifx_lo_spec[set|get]_* accessor functions. Prototypes for these acessors
 
991
 * are in incl/sqlhdr.h
 
992
 *
 
993
 ******************************************************************************/
 
994
 
 
995
typedef struct ifx_lo_create_spec_s ifx_lo_create_spec_t;
 
996
 
 
997
 
 
998
 
 
999
/*******************************************************************************
 
1000
 * ifx_lo_t: A dummy opaque representation of the smartblob structure
 
1001
 *
 
1002
 * This can be used for stack or in-line structure declarations.
 
1003
 *
 
1004
 ******************************************************************************/
 
1005
#define SB_LOCSIZE 72 /* length of ifx_lo_t */
 
1006
 
 
1007
typedef struct ifx_lo_ts
 
1008
{
 
1009
    char dummy[SB_LOCSIZE];
 
1010
} ifx_lo_t;
 
1011
 
 
1012
/*******************************************************************************
 
1013
 * ifx_lo_stat:
 
1014
 *
 
1015
 * This is an opaque structure used in querying attribtes of smartblobs. The
 
1016
 * user may examin fields herein by using ifx_lo_stat_* accessor functions.
 
1017
 * Prototypes for these acessors are in incl/sqlhdr.h
 
1018
 *
 
1019
 * The accessors are defined as follows:
 
1020
 *     ifx_lo_stat_size: contains the size of the LO in bytes.
 
1021
 *     ifx_lo_stat_uid: reserved for future use: the user id for the
 
1022
 *         owner of the LO.
 
1023
 *     ifx_lo_stat_atime: the time of last access. This is only maintained if
 
1024
 *         the LO_KEEP_LASTACCESS_TIME flag is set for the LO.
 
1025
 *         Resolution is seconds.
 
1026
 *     ifx_lo_stat_mtime: the time of last modification. Resolution is
 
1027
 *         seconds.
 
1028
 *     ifx_lo_stat_ctime: the time of the last status change (this includes
 
1029
 *         updates, changes in ownership, and changes to the number of
 
1030
 *         references).  Resolution is seconds. See Appendix B2.11,
 
1031
 *         Future Embedded- language feature issues, Smartblob API
 
1032
 *         functions using lofd, for enhancements that extend support
 
1033
 *         for named and external LOs.
 
1034
 *     ifx_lo_stat_refcnt: the number of pointers to this LO - when 0 the LO is
 
1035
 *         typically deleted. See deletion criteria.
 
1036
 *     ifx_lo_stat_cspec: a pointer to the opaque create spec for this object.
 
1037
 *         (see ifx_lo_spec[get|set]_ accessors for details.)
 
1038
 *     ifx_lo_stat_type: the 8 byte code for the LO's type
 
1039
 *
 
1040
 ******************************************************************************/
 
1041
 
 
1042
typedef struct ifx_lo_stat_s ifx_lo_stat_t;
 
1043
 
 
1044
#endif  /* LOCATOR_INCL */
 
1045
#line 384 "/opt/informix/incl/esql/locator.h"
 
1046
#line 35 "dbinfx.ec"
 
1047
 
 
1048
#include "eb.h"
 
1049
#include "dbapi.h"
 
1050
 
 
1051
#define CACHELIMIT 10000 /* number of cached lines */
 
1052
 
 
1053
#define ENGINE_ERRCODE sqlca.sqlcode
 
1054
 
 
1055
 
 
1056
/*********************************************************************
 
1057
The status variable ENGINE_ERRCODE holds the return code from an Informix call.
 
1058
This is then used by the function errorTrap() below.
 
1059
If ENGINE_ERRCODE != 0, errorTrap() aborts the program, or performs
 
1060
a recovery longjmp, as directed by the generic error function errorPrint().
 
1061
errorTrap() returns true if an SQL error occurred, but that error
 
1062
was trapped by the application.
 
1063
In this case the calling routine should clean up as best it can and return.
 
1064
*********************************************************************/
 
1065
 
 
1066
static const char *stmt_text = 0; /* text of the SQL statement */
 
1067
static const short *exclist; /* list of error codes trapped by the application */
 
1068
static short translevel;
 
1069
static bool badtrans;
 
1070
 
 
1071
/* Through globals, make error info available to the application. */
 
1072
int rv_lastStatus, rv_vendorStatus, rv_stmtOffset;
 
1073
char *rv_badToken;
 
1074
 
 
1075
static void debugStatement(void)
 
1076
{
 
1077
        if(sql_debug && stmt_text)
 
1078
                appendFileNF(sql_debuglog, stmt_text);
 
1079
} /* debugStatement */
 
1080
 
 
1081
static void debugExtra(const char *s)
 
1082
{
 
1083
        if(sql_debug)
 
1084
                appendFileNF(sql_debuglog, s);
 
1085
} /* debugExtra */
 
1086
 
 
1087
/* Append the SQL statement to the debug log.  This is not strictly necessary
 
1088
 * if sql_debug is set, since the statement has already been appended. */
 
1089
static void showStatement(void)
 
1090
{
 
1091
        if(!sql_debug && stmt_text)
 
1092
                appendFileNF(sql_debuglog, stmt_text);
 
1093
} /* showStatement */
 
1094
 
 
1095
/* application sets the exception list */
 
1096
void sql_exclist(const short *list) { exclist = list; }
 
1097
 
 
1098
void sql_exception(int errnum)
 
1099
{
 
1100
        static short list[2];
 
1101
        list[0] = errnum;
 
1102
        exclist = list;
 
1103
} /* sql_exception */
 
1104
 
 
1105
/* text descriptions corresponding to our generic SQL error codes */
 
1106
static char *sqlErrorList[] = {0,
 
1107
        "miscelaneous SQL error",
 
1108
        "syntax error in SQL statement",
 
1109
        "filename cannot be used by SQL",
 
1110
        "cannot convert/compare the columns/constants in the SQL statement",
 
1111
        "bad string subscripting",
 
1112
        "bad use of the rowid construct",
 
1113
        "bad use of a blob column",
 
1114
        "bad use of aggregate operators or columns",
 
1115
        "bad use of a view",
 
1116
        "bad use of a serial column",
 
1117
        "bad use of a temp table",
 
1118
        "operation cannot cross databases",
 
1119
        "database is fucked up",
 
1120
        "query interrupted by user",
 
1121
        "could not connect to the database",
 
1122
        "database has not yet been selected",
 
1123
        "table not found",
 
1124
        "duplicate table",
 
1125
        "ambiguous table",
 
1126
        "column not found",
 
1127
        "duplicate column",
 
1128
        "ambiguous column",
 
1129
        "index not found",
 
1130
        "duplicate index",
 
1131
        "constraint not found",
 
1132
        "duplicate constraint",
 
1133
        "stored procedure not found",
 
1134
        "duplicate stored procedure",
 
1135
        "synonym not found",
 
1136
        "duplicate synonym",
 
1137
        "table has no primary or unique key",
 
1138
        "duplicate primary or unique key",
 
1139
        "cursor not specified, or cursor is not available",
 
1140
        "duplicate cursor",
 
1141
        "the database lacks the resources needed to complete this query",
 
1142
        "check constrain violated",
 
1143
        "referential integrity violated",
 
1144
        "cannot manage or complete the transaction",
 
1145
        "long transaction, too much log data generated",
 
1146
        "this operation must be run inside a transaction",
 
1147
        "cannot open, read, write, close, or otherwise manage a blob",
 
1148
        "row, table, page, or database is already locked, or cannot be locked",
 
1149
        "inserting null into a not null column",
 
1150
        "no permission to modify the database in this way",
 
1151
        "no current row established",
 
1152
        "many rows were found where one was expected",
 
1153
        "cannot union these select statements together",
 
1154
        "cannot access or write the audit trail",
 
1155
        "could not run SQL or gather data from a remote host",
 
1156
        "where clause is semantically unmanageable",
 
1157
        "deadlock detected",
 
1158
0};
 
1159
 
 
1160
/* map Informix errors to our own exception codes, as defined in c_sql.h. */
 
1161
static struct ERRORMAP {
 
1162
        short infcode;
 
1163
        short excno;
 
1164
} errormap[] = {
 
1165
        {200, EXCSYNTAX},
 
1166
        {201, EXCSYNTAX},
 
1167
        {202, EXCSYNTAX},
 
1168
        {203, EXCSYNTAX},
 
1169
        {204, EXCSYNTAX},
 
1170
        {205, EXCROWIDUSE},
 
1171
        {206, EXCNOTABLE},
 
1172
        /* 207 */
 
1173
        {208, EXCRESOURCE},
 
1174
        {209, EXCDBCORRUPT},
 
1175
        {210, EXCFILENAME},
 
1176
        {211, EXCDBCORRUPT},
 
1177
        {212, EXCRESOURCE},
 
1178
        {213, EXCINTERRUPT},
 
1179
        {214, EXCDBCORRUPT},
 
1180
        {215, EXCDBCORRUPT},
 
1181
        {216, EXCDBCORRUPT},
 
1182
        {217, EXCNOCOLUMN},
 
1183
        {218, EXCNOSYNONYM},
 
1184
        {219, EXCCONVERT},
 
1185
        {220, EXCSYNTAX},
 
1186
        {221, EXCRESOURCE},
 
1187
        {222, EXCRESOURCE},
 
1188
        {223, EXCAMBTABLE},
 
1189
        {224, EXCRESOURCE},
 
1190
        {225, EXCRESOURCE},
 
1191
        {226, EXCRESOURCE},
 
1192
        {227, EXCROWIDUSE},
 
1193
        {228, EXCROWIDUSE},
 
1194
        {229, EXCRESOURCE},
 
1195
        {230, EXCDBCORRUPT},
 
1196
        {231, EXCAGGREGATEUSE},
 
1197
        {232, EXCSERIAL},
 
1198
        {233, EXCITEMLOCK},
 
1199
        {234, EXCAMBCOLUMN},
 
1200
        {235, EXCCONVERT},
 
1201
        {236, EXCSYNTAX},
 
1202
        {237, EXCMANAGETRANS},
 
1203
        {238, EXCMANAGETRANS},
 
1204
        {239, EXCDUPKEY},
 
1205
        {240, EXCDBCORRUPT},
 
1206
        {241, EXCMANAGETRANS},
 
1207
        {249, EXCAMBCOLUMN},
 
1208
        {250, EXCDBCORRUPT},
 
1209
        {251, EXCSYNTAX},
 
1210
        {252, EXCITEMLOCK},
 
1211
        {253, EXCSYNTAX},
 
1212
        {255, EXCNOTINTRANS},
 
1213
        {256, EXCMANAGETRANS},
 
1214
        {257, EXCRESOURCE},
 
1215
        {258, EXCDBCORRUPT},
 
1216
        {259, EXCNOCURSOR},
 
1217
        {260, EXCNOCURSOR},
 
1218
        {261, EXCRESOURCE},
 
1219
        {262, EXCNOCURSOR},
 
1220
        {263, EXCRESOURCE},
 
1221
        {264, EXCRESOURCE},
 
1222
        {265, EXCNOTINTRANS},
 
1223
        {266, EXCNOCURSOR},
 
1224
        {267, EXCNOCURSOR},
 
1225
        {268, EXCDUPKEY},
 
1226
        {269, EXCNOTNULLCOLUMN},
 
1227
        {270, EXCDBCORRUPT},
 
1228
        {271, EXCDBCORRUPT},
 
1229
        {272, EXCPERMISSION},
 
1230
        {273, EXCPERMISSION},
 
1231
        {274, EXCPERMISSION},
 
1232
        {275, EXCPERMISSION},
 
1233
        {276, EXCNOCURSOR},
 
1234
        {277, EXCNOCURSOR},
 
1235
        {278, EXCRESOURCE},
 
1236
        {281, EXCTEMPTABLEUSE},
 
1237
        {282, EXCSYNTAX},
 
1238
        {283, EXCSYNTAX},
 
1239
        {284, EXCMANYROW},
 
1240
        {285, EXCNOCURSOR},
 
1241
        {286, EXCNOTNULLCOLUMN},
 
1242
        {287, EXCSERIAL},
 
1243
        {288, EXCITEMLOCK},
 
1244
        {289, EXCITEMLOCK},
 
1245
        {290, EXCNOCURSOR},
 
1246
        {292, EXCNOTNULLCOLUMN},
 
1247
        {293, EXCSYNTAX},
 
1248
        {294, EXCAGGREGATEUSE},
 
1249
        {295, EXCCROSSDB},
 
1250
        {296, EXCNOTABLE},
 
1251
        {297, EXCNOKEY},
 
1252
        {298, EXCPERMISSION},
 
1253
        {299, EXCPERMISSION},
 
1254
        {300, EXCRESOURCE},
 
1255
        {301, EXCRESOURCE},
 
1256
        {302, EXCPERMISSION},
 
1257
        { 303, EXCAGGREGATEUSE},
 
1258
        {304, EXCAGGREGATEUSE},
 
1259
        {305, EXCSUBSCRIPT},
 
1260
        {306, EXCSUBSCRIPT},
 
1261
        {307, EXCSUBSCRIPT},
 
1262
        {308, EXCCONVERT},
 
1263
        {309, EXCAMBCOLUMN},
 
1264
        {310, EXCDUPTABLE},
 
1265
        {311, EXCDBCORRUPT},
 
1266
        {312, EXCDBCORRUPT},
 
1267
        {313, EXCPERMISSION},
 
1268
        {314, EXCDUPTABLE},
 
1269
        {315, EXCPERMISSION},
 
1270
        {316, EXCDUPINDEX},
 
1271
        {317, EXCUNION},
 
1272
        {318, EXCFILENAME},
 
1273
        {319, EXCNOINDEX},
 
1274
        {320, EXCPERMISSION},
 
1275
        {321, EXCAGGREGATEUSE},
 
1276
        {323, EXCTEMPTABLEUSE},
 
1277
        {324, EXCAMBCOLUMN},
 
1278
        {325, EXCFILENAME},
 
1279
        {326, EXCRESOURCE},
 
1280
        {327, EXCITEMLOCK},
 
1281
        {328, EXCDUPCOLUMN},
 
1282
        {329, EXCNOCONNECT},
 
1283
        {330, EXCRESOURCE},
 
1284
        {331, EXCDBCORRUPT},
 
1285
        {332, EXCTRACE},
 
1286
        {333, EXCTRACE},
 
1287
        {334, EXCTRACE},
 
1288
        {335, EXCTRACE},
 
1289
        {336, EXCTEMPTABLEUSE},
 
1290
        {337, EXCTEMPTABLEUSE},
 
1291
        {338, EXCTRACE},
 
1292
        {339, EXCFILENAME},
 
1293
        {340, EXCTRACE},
 
1294
        {341, EXCTRACE},
 
1295
        {342, EXCREMOTE},
 
1296
        {343, EXCTRACE},
 
1297
        {344, EXCTRACE},
 
1298
        {345, EXCTRACE},
 
1299
        {346, EXCDBCORRUPT},
 
1300
        {347, EXCITEMLOCK},
 
1301
        {348, EXCDBCORRUPT},
 
1302
        {349, EXCNODB},
 
1303
        {350, EXCDUPINDEX},
 
1304
        {352, EXCNOCOLUMN},
 
1305
        {353, EXCNOTABLE},
 
1306
        {354, EXCSYNTAX},
 
1307
        {355, EXCDBCORRUPT},
 
1308
        {356, EXCCONVERT},
 
1309
        {361, EXCRESOURCE},
 
1310
        {362, EXCSERIAL},
 
1311
        {363, EXCNOCURSOR},
 
1312
        {365, EXCNOCURSOR},
 
1313
        {366, EXCCONVERT},
 
1314
        {367, EXCAGGREGATEUSE},
 
1315
        {368, EXCDBCORRUPT},
 
1316
        {369, EXCSERIAL},
 
1317
        {370, EXCAMBCOLUMN},
 
1318
        {371, EXCDUPKEY},
 
1319
        {372, EXCTRACE},
 
1320
        {373, EXCFILENAME},
 
1321
        {374, EXCSYNTAX},
 
1322
        {375, EXCMANAGETRANS},
 
1323
        {376, EXCMANAGETRANS},
 
1324
        {377, EXCMANAGETRANS},
 
1325
        {378, EXCITEMLOCK},
 
1326
        {382, EXCSYNTAX},
 
1327
        {383, EXCAGGREGATEUSE},
 
1328
        {384, EXCVIEWUSE},
 
1329
        {385, EXCCONVERT},
 
1330
        {386, EXCNOTNULLCOLUMN},
 
1331
        {387, EXCPERMISSION},
 
1332
        {388, EXCPERMISSION},
 
1333
        {389, EXCPERMISSION},
 
1334
        {390, EXCDUPSYNONYM},
 
1335
        {391, EXCNOTNULLCOLUMN},
 
1336
        {392, EXCDBCORRUPT},
 
1337
        {393, EXCWHERECLAUSE},
 
1338
        {394, EXCNOTABLE},
 
1339
        {395, EXCWHERECLAUSE},
 
1340
        {396, EXCWHERECLAUSE},
 
1341
        {397, EXCDBCORRUPT},
 
1342
        {398, EXCNOTINTRANS},
 
1343
        {399, EXCMANAGETRANS},
 
1344
        {400, EXCNOCURSOR},
 
1345
        {401, EXCNOCURSOR},
 
1346
        {404, EXCNOCURSOR},
 
1347
        {406, EXCRESOURCE},
 
1348
        {407, EXCDBCORRUPT},
 
1349
        {408, EXCDBCORRUPT},
 
1350
        {409, EXCNOCONNECT},
 
1351
        {410, EXCNOCURSOR},
 
1352
        {413, EXCNOCURSOR},
 
1353
        {414, EXCNOCURSOR},
 
1354
        {415, EXCCONVERT},
 
1355
        {417, EXCNOCURSOR},
 
1356
        {420, EXCREMOTE},
 
1357
        {421, EXCREMOTE},
 
1358
        {422, EXCNOCURSOR},
 
1359
        {423, EXCNOROW},
 
1360
        {424, EXCDUPCURSOR},
 
1361
        {425, EXCITEMLOCK},
 
1362
        {430, EXCCONVERT},
 
1363
        {431, EXCCONVERT},
 
1364
        {432, EXCCONVERT},
 
1365
        {433, EXCCONVERT},
 
1366
        {434, EXCCONVERT},
 
1367
        {439, EXCREMOTE},
 
1368
        {451, EXCRESOURCE},
 
1369
        {452, EXCRESOURCE},
 
1370
        {453, EXCDBCORRUPT},
 
1371
        {454, EXCDBCORRUPT},
 
1372
        {455, EXCRESOURCE},
 
1373
        {457, EXCREMOTE},
 
1374
        {458, EXCLONGTRANS},
 
1375
        {459, EXCREMOTE},
 
1376
        {460, EXCRESOURCE},
 
1377
        {465, EXCRESOURCE},
 
1378
        {468, EXCNOCONNECT},
 
1379
        {472, EXCCONVERT},
 
1380
        {473, EXCCONVERT},
 
1381
        {474, EXCCONVERT},
 
1382
        {482, EXCNOCURSOR},
 
1383
        {484, EXCFILENAME},
 
1384
        {500, EXCDUPINDEX},
 
1385
        {501, EXCDUPINDEX},
 
1386
        {502, EXCNOINDEX},
 
1387
        {503, EXCRESOURCE},
 
1388
        {504, EXCVIEWUSE},
 
1389
        {505, EXCSYNTAX},
 
1390
        {506, EXCPERMISSION},
 
1391
        {507, EXCNOCURSOR},
 
1392
        {508, EXCTEMPTABLEUSE},
 
1393
        {509, EXCTEMPTABLEUSE},
 
1394
        {510, EXCTEMPTABLEUSE},
 
1395
        {512, EXCPERMISSION},
 
1396
        {514, EXCPERMISSION},
 
1397
        {515, EXCNOCONSTRAINT},
 
1398
        {517, EXCRESOURCE},
 
1399
        {518, EXCNOCONSTRAINT},
 
1400
        {519, EXCCONVERT},
 
1401
        {521, EXCITEMLOCK},
 
1402
        {522, EXCNOTABLE},
 
1403
        {524, EXCNOTINTRANS},
 
1404
        {525, EXCREFINT},
 
1405
        {526, EXCNOCURSOR},
 
1406
        {528, EXCRESOURCE},
 
1407
        {529, EXCNOCONNECT},
 
1408
        {530, EXCCHECK},
 
1409
        {531, EXCDUPCOLUMN},
 
1410
        {532, EXCTEMPTABLEUSE},
 
1411
        {534, EXCITEMLOCK},
 
1412
        {535, EXCMANAGETRANS},
 
1413
        {536, EXCSYNTAX},
 
1414
        {537, EXCNOCONSTRAINT},
 
1415
        {538, EXCDUPCURSOR},
 
1416
        {539, EXCRESOURCE},
 
1417
        {540, EXCDBCORRUPT},
 
1418
        {541, EXCPERMISSION},
 
1419
        {543, EXCAMBCOLUMN},
 
1420
        {543, EXCSYNTAX},
 
1421
        {544, EXCAGGREGATEUSE},
 
1422
        {545, EXCPERMISSION},
 
1423
        {548, EXCTEMPTABLEUSE},
 
1424
        {549, EXCNOCOLUMN},
 
1425
        {550, EXCRESOURCE},
 
1426
        {551, EXCRESOURCE},
 
1427
        {554, EXCSYNTAX},
 
1428
        {559, EXCDUPSYNONYM},
 
1429
        {560, EXCDBCORRUPT},
 
1430
        {561, EXCAGGREGATEUSE},
 
1431
        {562, EXCCONVERT},
 
1432
        {536, EXCITEMLOCK},
 
1433
        {564, EXCRESOURCE},
 
1434
        {565, EXCRESOURCE},
 
1435
        {566, EXCRESOURCE},
 
1436
        {567, EXCRESOURCE},
 
1437
        {568, EXCCROSSDB},
 
1438
        {569, EXCCROSSDB},
 
1439
        {570, EXCCROSSDB},
 
1440
        {571, EXCCROSSDB},
 
1441
        {573, EXCMANAGETRANS},
 
1442
        {574, EXCAMBCOLUMN},
 
1443
        {576, EXCTEMPTABLEUSE},
 
1444
        {577, EXCDUPCONSTRAINT},
 
1445
        {578, EXCSYNTAX},
 
1446
        {579, EXCPERMISSION},
 
1447
        {580, EXCPERMISSION},
 
1448
        {582, EXCMANAGETRANS},
 
1449
        {583, EXCPERMISSION},
 
1450
        {586, EXCDUPCURSOR},
 
1451
        {589, EXCREMOTE},
 
1452
        {590, EXCDBCORRUPT},
 
1453
        {591, EXCCONVERT},
 
1454
        {592, EXCNOTNULLCOLUMN},
 
1455
        {593, EXCSERIAL},
 
1456
        {594, EXCBLOBUSE},
 
1457
        {595, EXCAGGREGATEUSE},
 
1458
        {597, EXCDBCORRUPT},
 
1459
        {598, EXCNOCURSOR},
 
1460
        {599, EXCSYNTAX},
 
1461
        {600, EXCMANAGEBLOB},
 
1462
        {601, EXCMANAGEBLOB},
 
1463
        {602, EXCMANAGEBLOB},
 
1464
        {603, EXCMANAGEBLOB},
 
1465
        {604, EXCMANAGEBLOB},
 
1466
        {605, EXCMANAGEBLOB},
 
1467
        {606, EXCMANAGEBLOB},
 
1468
        {607, EXCSUBSCRIPT},
 
1469
        {608, EXCCONVERT},
 
1470
        {610, EXCBLOBUSE},
 
1471
        {611, EXCBLOBUSE},
 
1472
        {612, EXCBLOBUSE},
 
1473
        {613, EXCBLOBUSE},
 
1474
        {614, EXCBLOBUSE},
 
1475
        {615, EXCBLOBUSE},
 
1476
        {616, EXCBLOBUSE},
 
1477
        {617, EXCBLOBUSE},
 
1478
        {618, EXCMANAGEBLOB},
 
1479
        {622, EXCNOINDEX},
 
1480
        {623, EXCNOCONSTRAINT},
 
1481
        {625, EXCDUPCONSTRAINT},
 
1482
        {628, EXCMANAGETRANS},
 
1483
        {629, EXCMANAGETRANS},
 
1484
        {630, EXCMANAGETRANS},
 
1485
        {631, EXCBLOBUSE},
 
1486
        {635, EXCPERMISSION},
 
1487
        {636, EXCRESOURCE},
 
1488
        {638, EXCBLOBUSE},
 
1489
        {639, EXCBLOBUSE},
 
1490
        {640, EXCDBCORRUPT},
 
1491
        {649, EXCFILENAME},
 
1492
        {650, EXCRESOURCE},
 
1493
        {651, EXCRESOURCE},
 
1494
        /* I'm not about to map all possible compile/runtime SPL errors. */
 
1495
        /* Here's a few. */
 
1496
        {655, EXCSYNTAX},
 
1497
        {667, EXCSYNTAX},
 
1498
        {673, EXCDUPSPROC},
 
1499
        {674, EXCNOSPROC},
 
1500
        {678, EXCSUBSCRIPT},
 
1501
        {681, EXCDUPCOLUMN},
 
1502
        {686, EXCMANYROW},
 
1503
        {690, EXCREFINT},
 
1504
        {691, EXCREFINT},
 
1505
        {692, EXCREFINT},
 
1506
        {702, EXCITEMLOCK},
 
1507
        {703, EXCNOTNULLCOLUMN},
 
1508
        {704, EXCDUPCONSTRAINT},
 
1509
        {706, EXCPERMISSION},
 
1510
        {707, EXCBLOBUSE},
 
1511
        {722, EXCRESOURCE},
 
1512
        {958, EXCDUPTABLE},
 
1513
        {1214, EXCCONVERT},
 
1514
        {1262, EXCCONVERT},
 
1515
        {1264, EXCCONVERT},
 
1516
        {25553, EXCNOCONNECT},
 
1517
        {25587, EXCNOCONNECT},
 
1518
        {25588, EXCNOCONNECT},
 
1519
        {25596, EXCNOCONNECT},
 
1520
        {0, 0}
 
1521
}; /* ends of list */
 
1522
 
 
1523
static int errTranslate(int code)
 
1524
{
 
1525
        struct ERRORMAP *e;
 
1526
 
 
1527
        for(e=errormap; e->infcode; ++e) {
 
1528
                if(e->infcode == code)
 
1529
                        return e->excno;
 
1530
        }
 
1531
        return EXCSQLMISC;
 
1532
} /* errTranslate */
 
1533
 
 
1534
static bool errorTrap(void)
 
1535
{
 
1536
short i;
 
1537
 
 
1538
rv_lastStatus = rv_vendorStatus = 0; /* innocent until proven guilty */
 
1539
rv_stmtOffset = 0;
 
1540
rv_badToken = 0;
 
1541
if(ENGINE_ERRCODE >= 0) return false; /* no problem */
 
1542
 
 
1543
showStatement();
 
1544
rv_vendorStatus = -ENGINE_ERRCODE;
 
1545
rv_lastStatus = errTranslate(rv_vendorStatus);
 
1546
rv_stmtOffset = sqlca.sqlerrd[4];
 
1547
rv_badToken = sqlca.sqlerrm;
 
1548
if(!rv_badToken[0]) rv_badToken = 0;
 
1549
 
 
1550
/* if the application didn't trap for this exception, blow up! */
 
1551
if(exclist) {
 
1552
for(i=0; exclist[i]; ++i) {
 
1553
if(exclist[i] == rv_lastStatus) {
 
1554
exclist = 0; /* we've spent that exception */
 
1555
return true;
 
1556
}
 
1557
}
 
1558
}
 
1559
 
 
1560
errorPrint("2SQL error %d, %s", rv_vendorStatus, sqlErrorList[rv_lastStatus]);
 
1561
return true; /* make the compiler happy */
 
1562
} /* errorTrap */
 
1563
 
 
1564
 
 
1565
/*********************************************************************
 
1566
The OCURS structure given below maintains an open SQL cursor.
 
1567
A static array of these structures allows multiple cursors
 
1568
to be opened simultaneously.
 
1569
*********************************************************************/
 
1570
 
 
1571
static struct OCURS {
 
1572
char sname[8]; /* statement name */
 
1573
char cname[8]; /* cursor name */
 
1574
struct sqlda *desc;
 
1575
char rv_type[NUMRETS];
 
1576
long rownum;
 
1577
short alloc;
 
1578
short cid; /* cursor ID */
 
1579
char flag;
 
1580
char numRets;
 
1581
char **fl; /* array of fetched lines */
 
1582
} ocurs[NUMCURSORS];
 
1583
 
 
1584
/* values for struct OCURS.flag */
 
1585
#define CURSOR_NONE 0
 
1586
#define CURSOR_PREPARED 1
 
1587
#define CURSOR_OPENED 2
 
1588
 
 
1589
/* find a free cursor structure */
 
1590
static struct OCURS *findNewCursor(void)
 
1591
{
 
1592
struct OCURS *o;
 
1593
short i;
 
1594
for(o=ocurs, i=0; i<NUMCURSORS; ++i, ++o) {
 
1595
if(o->flag != CURSOR_NONE) continue;
 
1596
sprintf(o->cname, "c%u", i);
 
1597
sprintf(o->sname, "s%u", i);
 
1598
o->cid = 6000+i;
 
1599
return o;
 
1600
}
 
1601
errorPrint("2more than %d cursors opend concurrently", NUMCURSORS);
 
1602
return 0; /* make the compiler happy */
 
1603
} /* findNewCursor */
 
1604
 
 
1605
/* dereference an existing cursor */
 
1606
static struct OCURS *findCursor(int cid)
 
1607
{
 
1608
struct OCURS *o;
 
1609
if(cid < 6000 || cid >= 6000+NUMCURSORS)
 
1610
errorPrint("2cursor number %d is out of range", cid);
 
1611
cid -= 6000;
 
1612
o = ocurs+cid;
 
1613
if(o->flag == CURSOR_NONE)
 
1614
errorPrint("2cursor %d is not currently active", cid);
 
1615
rv_numRets = o->numRets;
 
1616
memcpy(rv_type, o->rv_type, NUMRETS);
 
1617
return o;
 
1618
} /* findCursor */
 
1619
 
 
1620
/* part of the disconnect() procedure */
 
1621
static void clearAllCursors(void)
 
1622
{
 
1623
        int i, j;
 
1624
        struct OCURS *o;
 
1625
 
 
1626
        for(i=0, o=ocurs; i<NUMCURSORS; ++i, ++o) {
 
1627
                if(o->flag == CURSOR_NONE) continue;
 
1628
                o->flag = CURSOR_NONE;
 
1629
o->rownum = 0;
 
1630
                if(o->fl) {
 
1631
                        for(j=0; j<o->alloc; ++j)
 
1632
                                nzFree(o->fl[j]);
 
1633
                        nzFree(o->fl);
 
1634
                        o->fl = 0;
 
1635
                }
 
1636
        } /* loop over cursors */
 
1637
 
 
1638
        translevel = 0;
 
1639
        badtrans = false;
 
1640
} /* clearAllCursors */
 
1641
 
 
1642
 
 
1643
/*********************************************************************
 
1644
Connect and disconect to SQL databases.
 
1645
*********************************************************************/
 
1646
 
 
1647
void sql_connect(const char *db, const char *login, const char *pw)
 
1648
{
 
1649
/*
 
1650
 * $char *dblocal = (char*)db;
 
1651
 */
 
1652
#line 637 "dbinfx.ec"
 
1653
  char *dblocal = (char*)db;
 
1654
login = pw = 0; /* not used here, so make the compiler happy */
 
1655
if(isnullstring(dblocal)) {
 
1656
dblocal = getenv("DBNAME");
 
1657
if(isnullstring(dblocal))
 
1658
errorPrint("2sql_connect receives no database, check $DBNAME");
 
1659
}
 
1660
 
 
1661
if(sql_database) {
 
1662
        stmt_text = "disconnect";
 
1663
        debugStatement();
 
1664
/*
 
1665
 * $disconnect current;
 
1666
 */
 
1667
#line 648 "dbinfx.ec"
 
1668
  {
 
1669
#line 648 "dbinfx.ec"
 
1670
  sqli_connect_close(3, (char *)0, 0, 0);
 
1671
#line 648 "dbinfx.ec"
 
1672
  }
 
1673
clearAllCursors();
 
1674
sql_database = 0;
 
1675
}
 
1676
 
 
1677
        stmt_text = "connect";
 
1678
        debugStatement();
 
1679
/*
 
1680
 * $connect to :dblocal;
 
1681
 */
 
1682
#line 655 "dbinfx.ec"
 
1683
  {
 
1684
#line 655 "dbinfx.ec"
 
1685
  sqli_connect_open(ESQLINTVERSION, 0, dblocal, (char *)0, (ifx_conn_t *)0, 0);
 
1686
#line 655 "dbinfx.ec"
 
1687
  }
 
1688
if(errorTrap()) return;
 
1689
sql_database = dblocal;
 
1690
 
 
1691
/* set default lock mode and isolation level for transaction management */
 
1692
stmt_text = "lock isolation";
 
1693
debugStatement();
 
1694
/*
 
1695
 * $ set lock mode to wait;
 
1696
 */
 
1697
#line 662 "dbinfx.ec"
 
1698
  {
 
1699
#line 662 "dbinfx.ec"
 
1700
  static const char *sqlcmdtxt[] =
 
1701
#line 662 "dbinfx.ec"
 
1702
    {
 
1703
#line 662 "dbinfx.ec"
 
1704
    "set lock mode to wait",
 
1705
    0
 
1706
    };
 
1707
#line 662 "dbinfx.ec"
 
1708
  static ifx_statement_t _SQ0 = {0};
 
1709
#line 662 "dbinfx.ec"
 
1710
  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);
 
1711
#line 662 "dbinfx.ec"
 
1712
  }
 
1713
if(errorTrap()) {
 
1714
abort:
 
1715
sql_disconnect();
 
1716
return;
 
1717
}
 
1718
/*
 
1719
 * $ set isolation to committed read;
 
1720
 */
 
1721
#line 668 "dbinfx.ec"
 
1722
  {
 
1723
#line 668 "dbinfx.ec"
 
1724
  static const char *sqlcmdtxt[] =
 
1725
#line 668 "dbinfx.ec"
 
1726
    {
 
1727
#line 668 "dbinfx.ec"
 
1728
    "set isolation to committed read",
 
1729
    0
 
1730
    };
 
1731
#line 668 "dbinfx.ec"
 
1732
  static ifx_statement_t _SQ0 = {0};
 
1733
#line 668 "dbinfx.ec"
 
1734
  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);
 
1735
#line 668 "dbinfx.ec"
 
1736
  }
 
1737
if(errorTrap()) goto abort;
 
1738
exclist = 0;
 
1739
} /* sql_connect */
 
1740
 
 
1741
void sql_disconnect(void)
 
1742
{
 
1743
if(sql_database) {
 
1744
        stmt_text = "disconnect";
 
1745
        debugStatement();
 
1746
/*
 
1747
 * $disconnect current;
 
1748
 */
 
1749
#line 678 "dbinfx.ec"
 
1750
  {
 
1751
#line 678 "dbinfx.ec"
 
1752
  sqli_connect_close(3, (char *)0, 0, 0);
 
1753
#line 678 "dbinfx.ec"
 
1754
  }
 
1755
clearAllCursors();
 
1756
sql_database = 0;
 
1757
}
 
1758
exclist = 0;
 
1759
} /* sql_disconnect */
 
1760
 
 
1761
/* make sure we're connected to a database */
 
1762
static void checkConnect(void)
 
1763
{
 
1764
        if(!sql_database)
 
1765
                errorPrint("2SQL command issued, but no database selected");
 
1766
} /* checkConnect */
 
1767
 
 
1768
 
 
1769
/*********************************************************************
 
1770
Begin, commit, and abort transactions.
 
1771
SQL does not permit nested transactions; this API does, to a limited degree.
 
1772
An inner transaction cannot fail while an outer one succeeds;
 
1773
that would require SQL support which is not forthcoming.
 
1774
However, as long as all transactions succeed, or the outer most fails,
 
1775
everything works properly.
 
1776
The static variable transLevel holds the number of nested transactions.
 
1777
*********************************************************************/
 
1778
 
 
1779
/* begin a transaction */
 
1780
void sql_begTrans(void)
 
1781
{
 
1782
        rv_lastStatus = 0;
 
1783
        checkConnect();
 
1784
                stmt_text = "begin work";
 
1785
                debugStatement();
 
1786
        /* count the nesting level of transactions. */
 
1787
        if(!translevel) {
 
1788
                badtrans = false;
 
1789
/*
 
1790
 *              $begin work;
 
1791
 */
 
1792
#line 713 "dbinfx.ec"
 
1793
  {
 
1794
#line 713 "dbinfx.ec"
 
1795
  sqli_trans_begin2((mint)1);
 
1796
#line 713 "dbinfx.ec"
 
1797
  }
 
1798
                if(errorTrap()) return;
 
1799
        }
 
1800
        ++translevel;
 
1801
        exclist = 0;
 
1802
} /* sql_begTrans */
 
1803
 
 
1804
/* end a transaction */
 
1805
static void endTrans(bool commit)
 
1806
{
 
1807
        rv_lastStatus = 0;
 
1808
        checkConnect();
 
1809
 
 
1810
        if(translevel == 0)
 
1811
                errorPrint("2end transaction without a matching begTrans()");
 
1812
        --translevel;
 
1813
 
 
1814
        if(commit) {
 
1815
                        stmt_text = "commit work";
 
1816
                        debugStatement();
 
1817
                if(badtrans)
 
1818
                        errorPrint("2Cannot commit a transaction around an aborted transaction");
 
1819
                if(translevel == 0) {
 
1820
/*
 
1821
 *                      $commit work;
 
1822
 */
 
1823
#line 736 "dbinfx.ec"
 
1824
  {
 
1825
#line 736 "dbinfx.ec"
 
1826
  sqli_trans_commit();
 
1827
#line 736 "dbinfx.ec"
 
1828
  }
 
1829
                        if(ENGINE_ERRCODE) ++translevel;
 
1830
                        errorTrap();
 
1831
                }
 
1832
        } else { /* success or failure */
 
1833
                        stmt_text = "rollback work";
 
1834
                        debugStatement();
 
1835
                badtrans = true;
 
1836
                if(!translevel) { /* bottom level */
 
1837
/*
 
1838
 *                      $rollback work;
 
1839
 */
 
1840
#line 745 "dbinfx.ec"
 
1841
  {
 
1842
#line 745 "dbinfx.ec"
 
1843
  sqli_trans_rollback();
 
1844
#line 745 "dbinfx.ec"
 
1845
  }
 
1846
                        if(ENGINE_ERRCODE) --translevel;
 
1847
                        errorTrap();
 
1848
                        badtrans = false;
 
1849
                }
 
1850
        } /* success or failure */
 
1851
 
 
1852
        /* At this point I will make a bold assumption --
 
1853
         * that all cursors are declared with hold.
 
1854
         * Hence they remain valid after the transaction is closed,
 
1855
         * and we don't have to change any of the OCURS structures. */
 
1856
 
 
1857
        exclist = 0;
 
1858
} /* endTrans */
 
1859
 
 
1860
void sql_commitWork(void) { endTrans(true); }
 
1861
void sql_rollbackWork(void) { endTrans(false); }
 
1862
 
 
1863
void sql_deferConstraints(void)
 
1864
{
 
1865
        if(!translevel)
 
1866
                errorPrint("2Cannot defer constraints unless inside a transaction");
 
1867
        stmt_text = "defer constraints";
 
1868
        debugStatement();
 
1869
/*
 
1870
 *      $set constraints all deferred;
 
1871
 */
 
1872
#line 769 "dbinfx.ec"
 
1873
  {
 
1874
#line 769 "dbinfx.ec"
 
1875
  static const char *sqlcmdtxt[] =
 
1876
#line 769 "dbinfx.ec"
 
1877
    {
 
1878
#line 769 "dbinfx.ec"
 
1879
    "set constraints all deferred",
 
1880
    0
 
1881
    };
 
1882
#line 769 "dbinfx.ec"
 
1883
  static ifx_statement_t _SQ0 = {0};
 
1884
#line 769 "dbinfx.ec"
 
1885
  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);
 
1886
#line 769 "dbinfx.ec"
 
1887
  }
 
1888
        errorTrap();
 
1889
        exclist = 0;
 
1890
} /* sql_deferConstraints */
 
1891
 
 
1892
 
 
1893
/*********************************************************************
 
1894
Blob management routines, a somewhat awkward interface.
 
1895
Global variables tell SQL where to unload the next fetched blob:
 
1896
either a file (truncate or append) or an allocated chunk of memory.
 
1897
This assumes each fetch or select statement retrieves at most one blob.
 
1898
Since there is no %blob directive in lineFormat(),
 
1899
one cannot simply slip a blob in with the rest of the data as a row is
 
1900
updated or inserted.  Instead the row must be created first,
 
1901
then the blob is entered separately, using blobInsert().
 
1902
This means every blob column must permit nulls, at least within the schema.
 
1903
Also, what use to be an atomic insert might become a multi-statement
 
1904
transaction if data integrity is important.
 
1905
Future versions of our line formatting software may support a %blob directive,
 
1906
which makes sense only when the formatted string is destined for SQL.
 
1907
*********************************************************************/
 
1908
 
 
1909
/* information about the blob being fetched */
 
1910
const char *rv_blobFile;
 
1911
bool rv_blobAppend;
 
1912
void *rv_blobLoc; /* location of blob in memory */
 
1913
int rv_blobSize; /* size of blob in bytes */
 
1914
static loc_t blobstruct; /* Informix structure to manage the blob */
 
1915
 
 
1916
/* insert a blob into the database */
 
1917
void sql_blobInsert(const char *tabname, const char *colname, int rowid,
 
1918
const char *filename, void *offset, int length)
 
1919
{
 
1920
/*
 
1921
 * $char blobcmd[100];
 
1922
 */
 
1923
#line 802 "dbinfx.ec"
 
1924
  char blobcmd[100];
 
1925
/*
 
1926
 * $loc_t insblob;
 
1927
 */
 
1928
#line 803 "dbinfx.ec"
 
1929
  loc_t insblob;
 
1930
 
 
1931
/* basic sanity checks */
 
1932
checkConnect();
 
1933
if(isnullstring(tabname)) errorPrint("2blobInsert, missing table name");
 
1934
if(isnullstring(colname)) errorPrint("2blobInsert, missing column name");
 
1935
if(rowid <= 0) errorPrint("2invalid rowid in blobInsert");
 
1936
if(length < 0) errorPrint("2invalid length in blobInsert");
 
1937
if(strlen(tabname) + strlen(colname) + 42 >= sizeof(blobcmd))
 
1938
errorPrint("2internal blobInsert command too long");
 
1939
 
 
1940
/* set up the blob structure */
 
1941
memset(&insblob, 0, sizeof(insblob));
 
1942
if(!filename) {
 
1943
insblob.loc_loctype = LOCMEMORY;
 
1944
if(offset) {
 
1945
if(length == 0) offset = 0;
 
1946
}
 
1947
if(!offset) length = -1;
 
1948
insblob.loc_buffer = offset;
 
1949
insblob.loc_bufsize = length;
 
1950
insblob.loc_size = length;
 
1951
if(!offset) insblob.loc_indicator = -1;
 
1952
} else {
 
1953
insblob.loc_loctype = LOCFNAME;
 
1954
insblob.loc_fname = (char*)filename;
 
1955
insblob.loc_oflags = LOC_RONLY;
 
1956
insblob.loc_size = -1;
 
1957
}
 
1958
 
 
1959
/* set up the blob insert command, using one host variable */
 
1960
sprintf(blobcmd, "update %s set %s = ? where rowid = %d",
 
1961
tabname, colname, rowid);
 
1962
stmt_text = blobcmd;
 
1963
debugStatement();
 
1964
/*
 
1965
 * $prepare blobinsert from :blobcmd;
 
1966
 */
 
1967
#line 838 "dbinfx.ec"
 
1968
  {
 
1969
#line 838 "dbinfx.ec"
 
1970
  sqli_prep(ESQLINTVERSION, _Cn1, blobcmd,(ifx_literal_t *)0, (ifx_namelist_t *)0, -1, 0, 0 ); 
 
1971
#line 838 "dbinfx.ec"
 
1972
  }
 
1973
if(errorTrap()) return;
 
1974
/*
 
1975
 * $execute blobinsert using :insblob;
 
1976
 */
 
1977
#line 840 "dbinfx.ec"
 
1978
  {
 
1979
#line 840 "dbinfx.ec"
 
1980
  static ifx_sqlvar_t _sqibind[] = 
 
1981
    {
 
1982
      { 113, sizeof(insblob), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
 
1983
#line 840 "dbinfx.ec"
 
1984
    };
 
1985
  static ifx_sqlda_t _SD0 = { 1, _sqibind, {0}, 1, 0 };
 
1986
#line 840 "dbinfx.ec"
 
1987
  _sqibind[0].sqldata = (char *) &insblob;
 
1988
  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);
 
1989
#line 840 "dbinfx.ec"
 
1990
  }
 
1991
errorTrap();
 
1992
rv_lastNrows = sqlca.sqlerrd[2];
 
1993
rv_lastRowid = sqlca.sqlerrd[5];
 
1994
if(sql_debug) appendFile(sql_debuglog, "%d rows affected", rv_lastNrows);
 
1995
exclist = 0;
 
1996
} /* sql_blobInsert */
 
1997
 
 
1998
 
 
1999
/*********************************************************************
 
2000
When an SQL statement is prepared, the engine tells us the types and lengths
 
2001
of the columns.  Use this information to "normalize" the sqlda
 
2002
structure, so that columns are fetched using our preferred formats.
 
2003
For instance, smallints and ints both map into int variables,
 
2004
varchars become chars, dates map into strings (so that we can convert
 
2005
them into our own vendor-independent binary representations later), etc.
 
2006
We assume the number and types of returns have been established.
 
2007
Once retsSetup has "normalized" the sqlda structure,
 
2008
run the select or fetch, and then call retsCleanup to post-process the data.
 
2009
This will, for example, turn dates, fetched into strings,
 
2010
into our own 4-byte representations.
 
2011
The same for time intervals, money, etc.
 
2012
*********************************************************************/
 
2013
 
 
2014
/* Arrays that hold the return values from a select statement. */
 
2015
int rv_numRets; /* number of returned values */
 
2016
char rv_type[NUMRETS+1]; /* datatypes of returned values */
 
2017
char rv_name[NUMRETS+1][COLNAMELEN]; /* column names */
 
2018
LF  rv_data[NUMRETS]; /* the returned values */
 
2019
int rv_lastNrows, rv_lastRowid, rv_lastSerial;
 
2020
/* Temp area to read the Informix values, as strings */
 
2021
static char retstring[NUMRETS][STRINGLEN+4];
 
2022
static va_list sqlargs;
 
2023
 
 
2024
static void retsSetup(struct sqlda *desc)
 
2025
{
 
2026
short i;
 
2027
bool blobpresent = false;
 
2028
struct sqlvar_struct   *v;
 
2029
 
 
2030
for(i=0; (unsigned)i< NUMRETS; ++i) {
 
2031
rv_data[i].l = nullint;
 
2032
retstring[i][0] = 0;
 
2033
rv_name[i][0] = 0;
 
2034
}
 
2035
if(!desc) return;
 
2036
 
 
2037
  for(i=0,v=desc->sqlvar; i<rv_numRets; ++i,++v ) {
 
2038
strncpy(rv_name[i], v->sqlname, COLNAMELEN);
 
2039
switch(rv_type[i]) {
 
2040
case 'S':
 
2041
case 'C':
 
2042
case 'D':
 
2043
case 'I':
 
2044
v->sqltype = CCHARTYPE;
 
2045
v->sqllen = STRINGLEN+2;
 
2046
v->sqldata = retstring[i];
 
2047
rv_data[i].ptr = retstring[i];
 
2048
break;
 
2049
 
 
2050
case 'N':
 
2051
v->sqltype = CINTTYPE;
 
2052
v->sqllen = 4;
 
2053
v->sqldata =  (char *) &rv_data[i].l;
 
2054
break;
 
2055
 
 
2056
case 'F':
 
2057
case 'M':
 
2058
v->sqltype = CDOUBLETYPE;
 
2059
v->sqllen = 8;
 
2060
v->sqldata = (char*) &rv_data[i].f;
 
2061
rv_data[i].f = nullfloat;
 
2062
break;
 
2063
 
 
2064
case 'B':
 
2065
case 'T':
 
2066
if(blobpresent)
 
2067
errorPrint("2Cannot select more than one blob at a time");
 
2068
blobpresent = true;
 
2069
v->sqltype = CLOCATORTYPE;
 
2070
v->sqllen = sizeof(blobstruct);
 
2071
v->sqldata = (char*) &blobstruct;
 
2072
memset(&blobstruct, 0, sizeof(blobstruct));
 
2073
if(!rv_blobFile) {
 
2074
blobstruct.loc_loctype = LOCMEMORY;
 
2075
blobstruct.loc_mflags = LOC_ALLOC;
 
2076
blobstruct.loc_bufsize = -1;
 
2077
} else {
 
2078
blobstruct.loc_loctype = LOCFNAME;
 
2079
blobstruct.loc_fname = (char*)rv_blobFile;
 
2080
blobstruct.lc_union.lc_file.lc_mode = 0600;
 
2081
blobstruct.loc_oflags =
 
2082
(rv_blobAppend ? LOC_WONLY|LOC_APPEND : LOC_WONLY);
 
2083
}
 
2084
break;
 
2085
 
 
2086
default:
 
2087
errorPrint("@bad character %c in retsSetup", rv_type[i]);
 
2088
} /* switch */
 
2089
} /* loop over fetched columns */
 
2090
} /* retsSetup */
 
2091
 
 
2092
/* clean up fetched values, eg. convert date to our proprietary format. */
 
2093
static void retsCleanup(void)
 
2094
{
 
2095
short i, l;
 
2096
bool yearfirst;
 
2097
 
 
2098
/* no blobs unless proven otherwise */
 
2099
rv_blobLoc = 0;
 
2100
rv_blobSize = nullint;
 
2101
 
 
2102
for(i=0; i<rv_numRets; ++i) {
 
2103
clipString(retstring[i]);
 
2104
switch(rv_type[i]) {
 
2105
case 'D':
 
2106
yearfirst = false;
 
2107
if(retstring[i][4] == '-') yearfirst = true;
 
2108
rv_data[i].l = stringDate(retstring[i],yearfirst);
 
2109
break;
 
2110
 
 
2111
case 'I':
 
2112
/* thanks to stringTime(), this works for either hh:mm or hh:mm:ss */
 
2113
if(retstring[i][0] == 0) rv_data[i].l = nullint;
 
2114
else {
 
2115
/* convert space to 0 */
 
2116
if(retstring[i][1] == ' ') retstring[i][1] = '0';
 
2117
/* skip the leading space that is produced when Informix converts interval to string */
 
2118
rv_data[i].l = stringTime(retstring[i]+1);
 
2119
}
 
2120
break;
 
2121
 
 
2122
case 'C':
 
2123
rv_data[i].l = retstring[i][0];
 
2124
break;
 
2125
 
 
2126
case 'M':
 
2127
case 'F':
 
2128
/* null floats look different from null dates and ints. */
 
2129
if(rv_data[i].l == 0xffffffff) {
 
2130
rv_data[i].f = nullfloat;
 
2131
if(rv_type[i] == 'M') rv_data[i].l = nullint;
 
2132
break;
 
2133
}
 
2134
/* represent monitary amounts as an integer number of pennies. */
 
2135
if(rv_type[i] == 'M')
 
2136
rv_data[i].l = rv_data[i].f * 100.0 + 0.5;
 
2137
break;
 
2138
 
 
2139
case 'S':
 
2140
/* map the empty string into the null string */
 
2141
l = strlen(retstring[i]);
 
2142
if(!l) rv_data[i].ptr = 0;
 
2143
if(l > STRINGLEN) errorPrint("2fetched string is too long, limit %d chars", STRINGLEN);
 
2144
break;
 
2145
 
 
2146
case 'B':
 
2147
case 'T':
 
2148
if(blobstruct.loc_indicator >= 0) { /* not null blob */
 
2149
rv_blobSize = blobstruct.loc_size;
 
2150
if(!rv_blobFile) rv_blobLoc = blobstruct.loc_buffer;
 
2151
if(rv_blobSize == 0) { /* turn empty blob into null blob */
 
2152
nzFree(rv_blobLoc);
 
2153
rv_blobLoc = 0;
 
2154
rv_blobSize = nullint;
 
2155
}
 
2156
}
 
2157
rv_data[i].l = rv_blobSize;
 
2158
break;
 
2159
 
 
2160
case 'N':
 
2161
/* Convert from Informix null to our nullint */
 
2162
if(rv_data[i].l == 0x80000000) rv_data[i].l = nullint;
 
2163
break;
 
2164
 
 
2165
default:
 
2166
errorPrint("@bad character %c in retsCleanup", rv_type[i]);
 
2167
} /* switch on datatype */
 
2168
} /* loop over columsn fetched */
 
2169
} /* retsCleanup */
 
2170
 
 
2171
void retsCopy(bool allstrings, void *first, ...)
 
2172
{
 
2173
void *q;
 
2174
int i;
 
2175
 
 
2176
        if(!rv_numRets)
 
2177
                errorPrint("@calling retsCopy() with no returns pending");
 
2178
 
 
2179
        for(i=0; i<rv_numRets; ++i) {
 
2180
                if(first) {
 
2181
                        q = first;
 
2182
                        va_start(sqlargs, first);
 
2183
                        first = 0;
 
2184
                } else {
 
2185
                        q = va_arg(sqlargs, void*);
 
2186
                }
 
2187
                if(!q) break;
 
2188
                if((int)q < 1000 && (int)q > -1000)
 
2189
                        errorPrint("2retsCopy, pointer too close to 0");
 
2190
 
 
2191
if(allstrings) *(char*)q = 0;
 
2192
 
 
2193
if(rv_type[i] == 'S') {
 
2194
*(char*)q = 0;
 
2195
if(rv_data[i].ptr)
 
2196
strcpy(q,  rv_data[i].ptr);
 
2197
} else if(rv_type[i] == 'C') {
 
2198
*(char *)q = rv_data[i].l;
 
2199
if(allstrings) ((char*)q)[1] = 0;
 
2200
} else if(rv_type[i] == 'F') {
 
2201
if(allstrings) {
 
2202
if(isnotnullfloat(rv_data[i].f)) sprintf(q, "%lf", rv_data[i].f);
 
2203
} else {
 
2204
*(double *)q = rv_data[i].f;
 
2205
}
 
2206
} else if(allstrings) {
 
2207
char type = rv_type[i];
 
2208
long l = rv_data[i].l;
 
2209
if(isnotnull(l)) {
 
2210
if(type == 'D') {
 
2211
strcpy(q, dateString(l, DTDELIMIT));
 
2212
} else if(type == 'I') {
 
2213
strcpy(q, timeString(l, DTDELIMIT));
 
2214
} else if(type == 'M') {
 
2215
sprintf(q, "%ld.%02d", l/100, l%100);
 
2216
} else sprintf(q, "%ld", l);
 
2217
}
 
2218
} else {
 
2219
*(long *)q = rv_data[i].l;
 
2220
}
 
2221
} /* loop over result parameters */
 
2222
 
 
2223
if(!first) va_end(sqlargs);
 
2224
} /* retsCopy */
 
2225
 
 
2226
/* convert column name into column index */
 
2227
int findcol_byname(const char *name)
 
2228
{
 
2229
        int i;
 
2230
        for(i=0; rv_name[i][0]; ++i)
 
2231
                if(stringEqual(name, rv_name[i])) break;
 
2232
        if(!rv_name[i][0])
 
2233
                errorPrint("2Column %s not found in the columns or aliases of your select statement", name);
 
2234
        return i;
 
2235
} /* findcol_byname */
 
2236
 
 
2237
/* make sure we got one return value, and it is integer compatible */
 
2238
static long oneRetValue(void)
 
2239
{
 
2240
char coltype = rv_type[0];
 
2241
long n = rv_data[0].l;
 
2242
if(rv_numRets != 1)
 
2243
errorPrint("2SQL statement has %d return values, 1 value expected", rv_numRets);
 
2244
if(!strchr("MNFDIC", coltype))
 
2245
errorPrint("2SQL statement returns a value whose type is not compatible with a 4-byte integer");
 
2246
if(coltype == 'F') n = rv_data[0].f;
 
2247
return n;
 
2248
} /* oneRetValue */
 
2249
 
 
2250
 
 
2251
/*********************************************************************
 
2252
Prepare a formatted SQL statement.
 
2253
Gather the types and names of the fetched columns and make this information
 
2254
available to the rest of the C routines in this file, and to the application.
 
2255
Returns the populated sqlda structure for the statement.
 
2256
Returns null if the prepare failed.
 
2257
*********************************************************************/
 
2258
 
 
2259
static struct sqlda *prepare(const char *stmt_parm, const char *sname_parm)
 
2260
{
 
2261
/*
 
2262
 * $char*stmt = (char*)stmt_parm;
 
2263
 */
 
2264
#line 1111 "dbinfx.ec"
 
2265
  char *stmt = (char*)stmt_parm;
 
2266
/*
 
2267
 * $char*sname = (char*)sname_parm;
 
2268
 */
 
2269
#line 1112 "dbinfx.ec"
 
2270
  char *sname = (char*)sname_parm;
 
2271
struct sqlda *desc;
 
2272
struct sqlvar_struct   *v;
 
2273
short i, coltype;
 
2274
 
 
2275
checkConnect();
 
2276
if(isnullstring(stmt)) errorPrint("2null SQL statement");
 
2277
stmt_text = stmt;
 
2278
debugStatement();
 
2279
 
 
2280
/* look for delete with no where clause */
 
2281
while(*stmt == ' ') ++stmt;
 
2282
if(!strncmp(stmt, "delete", 6) || !strncmp(stmt, "update", 6))
 
2283
/* delete or update */
 
2284
if(!strstr(stmt, "where") && !strstr(stmt, "WHERE")) {
 
2285
showStatement();
 
2286
errorPrint("2Old Mcdonald bug");
 
2287
}
 
2288
 
 
2289
/* set things up to nulls, in case the prepare fails */
 
2290
retsSetup(0);
 
2291
rv_numRets = 0;
 
2292
memset(rv_type, 0, NUMRETS);
 
2293
rv_lastNrows = rv_lastRowid = rv_lastSerial = 0;
 
2294
 
 
2295
/*
 
2296
 * $prepare :sname from :stmt;
 
2297
 */
 
2298
#line 1137 "dbinfx.ec"
 
2299
  {
 
2300
#line 1137 "dbinfx.ec"
 
2301
  sqli_prep(ESQLINTVERSION, sname, stmt,(ifx_literal_t *)0, (ifx_namelist_t *)0, -1, 0, 0 ); 
 
2302
#line 1137 "dbinfx.ec"
 
2303
  }
 
2304
if(errorTrap()) return 0;
 
2305
 
 
2306
/* gather types and column headings */
 
2307
/*
 
2308
 * $describe: sname into desc;
 
2309
 */
 
2310
#line 1141 "dbinfx.ec"
 
2311
  {
 
2312
#line 1141 "dbinfx.ec"
 
2313
  sqli_describe_stmt(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, sname, 257), &desc, 0);
 
2314
#line 1141 "dbinfx.ec"
 
2315
  }
 
2316
if(!desc) errorPrint("2$describe couldn't allocate descriptor");
 
2317
rv_numRets = desc->sqld;
 
2318
if(rv_numRets > NUMRETS) {
 
2319
showStatement();
 
2320
errorPrint("2cannot select more than %d values", NUMRETS);
 
2321
}
 
2322
 
 
2323
  for(i=0,v=desc->sqlvar; i<rv_numRets; ++i,++v ) {
 
2324
coltype = v->sqltype & SQLTYPE;
 
2325
/* kludge, count(*) should be int, not float, in my humble opinion */
 
2326
if(stringEqual(v->sqlname, "(count(*))"))
 
2327
coltype = SQLINT;
 
2328
 
 
2329
switch(coltype) {
 
2330
case SQLCHAR:
 
2331
case SQLVCHAR:
 
2332
rv_type[i] = 'S';
 
2333
if(v->sqllen == 1)
 
2334
rv_type[i] = 'C';
 
2335
break;
 
2336
 
 
2337
case SQLDTIME:
 
2338
/* We only process datetime year to minute, for databases
 
2339
 * other than Informix,  which don't have a date type. */
 
2340
if(v->sqllen != 5) errorPrint("2datetime field must be year to minute");
 
2341
case SQLDATE:
 
2342
rv_type[i] = 'D';
 
2343
break;
 
2344
 
 
2345
case SQLINTERVAL:
 
2346
rv_type[i] = 'I';
 
2347
break;
 
2348
 
 
2349
case SQLSMINT:
 
2350
case SQLINT:
 
2351
case SQLSERIAL:
 
2352
case SQLNULL:
 
2353
rv_type[i] = 'N';
 
2354
break;
 
2355
 
 
2356
case SQLFLOAT:
 
2357
case SQLSMFLOAT:
 
2358
case SQLDECIMAL:
 
2359
rv_type[i] = 'F';
 
2360
break;
 
2361
 
 
2362
case SQLMONEY:
 
2363
rv_type[i] = 'M';
 
2364
break;
 
2365
 
 
2366
case SQLBYTES:
 
2367
rv_type[i] = 'B';
 
2368
break;
 
2369
 
 
2370
case SQLTEXT:
 
2371
rv_type[i] = 'T';
 
2372
break;
 
2373
 
 
2374
default:
 
2375
errorPrint ("@Unknown informix sql datatype %d", coltype);
 
2376
} /* switch on type */
 
2377
} /* loop over returns */
 
2378
 
 
2379
retsSetup(desc);
 
2380
return desc;
 
2381
} /* prepare */
 
2382
 
 
2383
 
 
2384
/*********************************************************************
 
2385
Run an SQL statement internally, and gather any fetched values.
 
2386
This statement stands alone; it fetches at most one row.
 
2387
You might simply know this, perhaps because of a unique key,
 
2388
or you might be running a stored procedure.
 
2389
For efficiency we do not look for a second row, so this is really
 
2390
like the "select first" construct that some databases support.
 
2391
A mode variable says whether execution or selection or both are allowed.
 
2392
Return true if data was successfully fetched.
 
2393
*********************************************************************/
 
2394
 
 
2395
static bool execInternal(const char *stmt, int mode)
 
2396
{
 
2397
struct sqlda *desc;
 
2398
/*
 
2399
 * $static char singlestatement[] = "single_use_stmt";
 
2400
 */
 
2401
#line 1224 "dbinfx.ec"
 
2402
static   char singlestatement[] = "single_use_stmt";
 
2403
/*
 
2404
 * $static char singlecursor[] = "single_use_cursor";
 
2405
 */
 
2406
#line 1225 "dbinfx.ec"
 
2407
static   char singlecursor[] = "single_use_cursor";
 
2408
int i;
 
2409
bool notfound = false;
 
2410
short errorcode = 0;
 
2411
 
 
2412
desc = prepare(stmt, singlestatement);
 
2413
if(!desc) return false; /* error */
 
2414
 
 
2415
if(!rv_numRets) {
 
2416
if(!(mode&1)) {
 
2417
showStatement();
 
2418
errorPrint("2SQL select statement returns no values");
 
2419
}
 
2420
/*
 
2421
 * $execute :singlestatement;
 
2422
 */
 
2423
#line 1238 "dbinfx.ec"
 
2424
  {
 
2425
#line 1238 "dbinfx.ec"
 
2426
  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);
 
2427
#line 1238 "dbinfx.ec"
 
2428
  }
 
2429
notfound = true;
 
2430
} else { /* end no return values */
 
2431
 
 
2432
if(!(mode&2)) {
 
2433
showStatement();
 
2434
errorPrint("2SQL statement returns %d values", rv_numRets);
 
2435
}
 
2436
/*
 
2437
 * $execute: singlestatement into descriptor desc;
 
2438
 */
 
2439
#line 1246 "dbinfx.ec"
 
2440
  {
 
2441
#line 1246 "dbinfx.ec"
 
2442
  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);
 
2443
#line 1246 "dbinfx.ec"
 
2444
  }
 
2445
}
 
2446
 
 
2447
if(errorTrap()) {
 
2448
errorcode = rv_vendorStatus;
 
2449
} else {
 
2450
/* select or execute ran properly */
 
2451
/* error 100 means not found in Informix */
 
2452
if(ENGINE_ERRCODE == 100) notfound = true;
 
2453
/* set "last" parameters, in case the application is interested */
 
2454
rv_lastNrows = sqlca.sqlerrd[2];
 
2455
rv_lastRowid = sqlca.sqlerrd[5];
 
2456
rv_lastSerial = sqlca.sqlerrd[1];
 
2457
} /* successful run */
 
2458
 
 
2459
/*
 
2460
 * $free :singlestatement;
 
2461
 */
 
2462
#line 1261 "dbinfx.ec"
 
2463
  {
 
2464
#line 1261 "dbinfx.ec"
 
2465
  sqli_curs_free(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, singlestatement, 258));
 
2466
#line 1261 "dbinfx.ec"
 
2467
  }
 
2468
errorTrap();
 
2469
nzFree(desc);
 
2470
 
 
2471
retsCleanup();
 
2472
 
 
2473
if(errorcode) {
 
2474
rv_vendorStatus = errorcode;
 
2475
rv_lastStatus = errTranslate(rv_vendorStatus);
 
2476
return false;
 
2477
}
 
2478
 
 
2479
exclist = 0;
 
2480
return !notfound;
 
2481
} /* execInternal */
 
2482
 
 
2483
 
 
2484
/*********************************************************************
 
2485
Run individual select or execute statements, using the above internal routine.
 
2486
*********************************************************************/
 
2487
 
 
2488
/* pointer to vararg list; most of these are vararg functions */
 
2489
/* execute a stand-alone statement with no % formatting of the string */
 
2490
void sql_execNF(const char *stmt)
 
2491
{
 
2492
        execInternal(stmt, 1);
 
2493
} /* sql_execNF */
 
2494
 
 
2495
/* execute a stand-alone statement with % formatting */
 
2496
void sql_exec(const char *stmt, ...)
 
2497
{
 
2498
        va_start(sqlargs, stmt);
 
2499
        stmt = lineFormatStack(stmt, 0, &sqlargs);
 
2500
        execInternal(stmt, 1);
 
2501
        va_end(sqlargs);
 
2502
} /* sql_exec */
 
2503
 
 
2504
/* run a select statement with no % formatting of the string */
 
2505
/* return true if the row was found */
 
2506
bool sql_selectNF(const char *stmt, ...)
 
2507
{
 
2508
        bool rc;
 
2509
        va_start(sqlargs, stmt);
 
2510
        rc = execInternal(stmt, 2);
 
2511
        retsCopy(false, 0);
 
2512
        return rc;
 
2513
} /* sql_selectNF */
 
2514
 
 
2515
/* run a select statement with % formatting */
 
2516
bool sql_select(const char *stmt, ...)
 
2517
{
 
2518
        bool rc;
 
2519
        va_start(sqlargs, stmt);
 
2520
        stmt = lineFormatStack(stmt, 0, &sqlargs);
 
2521
        rc = execInternal(stmt, 2);
 
2522
        retsCopy(false, 0);
 
2523
        return rc;
 
2524
} /* sql_select */
 
2525
 
 
2526
/* run a select statement with one return value */
 
2527
int sql_selectOne(const char *stmt, ...)
 
2528
{
 
2529
        bool rc;
 
2530
        va_start(sqlargs, stmt);
 
2531
        stmt = lineFormatStack(stmt, 0, &sqlargs);
 
2532
        rc = execInternal(stmt, 2);
 
2533
                if(!rc) { va_end(sqlargs); return nullint; }
 
2534
        return oneRetValue();
 
2535
} /* sql_selectOne */
 
2536
 
 
2537
/* run a stored procedure with no % formatting */
 
2538
static bool sql_procNF(const char *stmt)
 
2539
{
 
2540
        bool rc;
 
2541
        char *s = allocMem(20+strlen(stmt));
 
2542
        strcpy(s, "execute procedure ");
 
2543
        strcat(s, stmt);
 
2544
        rc = execInternal(s, 3);
 
2545
        /* if execInternal doesn't return, we have a memory leak */
 
2546
        nzFree(s);
 
2547
        return rc;
 
2548
} /* sql_procNF */
 
2549
 
 
2550
/* run a stored procedure */
 
2551
bool sql_proc(const char *stmt, ...)
 
2552
{
 
2553
        bool rc;
 
2554
        va_start(sqlargs, stmt);
 
2555
        stmt = lineFormatStack(stmt, 0, &sqlargs);
 
2556
        rc = sql_procNF(stmt);
 
2557
        if(rv_numRets) retsCopy(false, 0);
 
2558
        return rc;
 
2559
} /* sql_proc */
 
2560
 
 
2561
/* run a stored procedure with one return */
 
2562
int sql_procOne(const char *stmt, ...)
 
2563
{
 
2564
        bool rc;
 
2565
        va_start(sqlargs, stmt);
 
2566
        stmt = lineFormatStack(stmt, 0, &sqlargs);
 
2567
        rc = sql_procNF(stmt);
 
2568
                if(!rc) { va_end(sqlargs); return 0; }
 
2569
        return oneRetValue();
 
2570
} /* sql_procOne */
 
2571
 
 
2572
 
 
2573
/*********************************************************************
 
2574
Prepare, open, close, and free SQL cursors.
 
2575
*********************************************************************/
 
2576
 
 
2577
/* prepare a cursor; return the ID number of that cursor */
 
2578
static int prepareCursor(const char *stmt, bool scrollflag)
 
2579
{
 
2580
/*
 
2581
 * $char *internal_sname, *internal_cname;
 
2582
 */
 
2583
#line 1374 "dbinfx.ec"
 
2584
  char *internal_sname, *internal_cname;
 
2585
struct OCURS *o = findNewCursor();
 
2586
 
 
2587
stmt = lineFormatStack(stmt, 0, &sqlargs);
 
2588
va_end(sqlargs);
 
2589
internal_sname = o->sname;
 
2590
internal_cname = o->cname;
 
2591
o->desc = prepare(stmt, internal_sname);
 
2592
if(!o->desc) return -1;
 
2593
if(o->desc->sqld == 0) {
 
2594
showStatement();
 
2595
errorPrint("2statement passed to sql_prepare has no returns");
 
2596
}
 
2597
 
 
2598
/* declare with hold;
 
2599
 * you might run transactions within this cursor. */
 
2600
if(scrollflag)
 
2601
/*
 
2602
 * $declare :internal_cname scroll cursor with hold for :internal_sname;
 
2603
 */
 
2604
#line 1391 "dbinfx.ec"
 
2605
  {
 
2606
#line 1391 "dbinfx.ec"
 
2607
  sqli_curs_decl_dynm(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 0), internal_cname, sqli_curs_locate(ESQLINTVERSION, internal_sname, 1), 4128, 0);
 
2608
#line 1391 "dbinfx.ec"
 
2609
  }
 
2610
else
 
2611
/*
 
2612
 * $declare :internal_cname cursor with hold for :internal_sname;
 
2613
 */
 
2614
#line 1393 "dbinfx.ec"
 
2615
  {
 
2616
#line 1393 "dbinfx.ec"
 
2617
  sqli_curs_decl_dynm(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 0), internal_cname, sqli_curs_locate(ESQLINTVERSION, internal_sname, 1), 4096, 0);
 
2618
#line 1393 "dbinfx.ec"
 
2619
  }
 
2620
if(errorTrap()) {
 
2621
nzFree(o->desc);
 
2622
return -1;
 
2623
}
 
2624
 
 
2625
o->numRets = rv_numRets;
 
2626
memcpy(o->rv_type, rv_type, NUMRETS);
 
2627
o->flag = CURSOR_PREPARED;
 
2628
o->fl = 0; /* just to make sure */
 
2629
return o->cid;
 
2630
} /* prepareCursor */
 
2631
 
 
2632
int sql_prepare(const char *stmt, ...)
 
2633
{
 
2634
        int n;
 
2635
        va_start(sqlargs, stmt);
 
2636
        n = prepareCursor(stmt, false);
 
2637
        exclist = 0;
 
2638
        return n;
 
2639
} /* sql_prepare */
 
2640
 
 
2641
int sql_prepareScrolling(const char *stmt, ...)
 
2642
{
 
2643
        int n;
 
2644
        va_start(sqlargs, stmt);
 
2645
        n = prepareCursor(stmt, true);
 
2646
        exclist = 0;
 
2647
        return n;
 
2648
} /* sql_prepareScrolling */
 
2649
 
 
2650
void sql_open(int cid)
 
2651
{
 
2652
short i;
 
2653
/*
 
2654
 * $char *internal_sname, *internal_cname;
 
2655
 */
 
2656
#line 1427 "dbinfx.ec"
 
2657
  char *internal_sname, *internal_cname;
 
2658
struct OCURS *o = findCursor(cid);
 
2659
if(o->flag == CURSOR_OPENED)
 
2660
errorPrint("2cannot open cursor %d, already opened", cid);
 
2661
internal_sname = o->sname;
 
2662
internal_cname = o->cname;
 
2663
debugExtra("open");
 
2664
/*
 
2665
 * $open :internal_cname;
 
2666
 */
 
2667
#line 1434 "dbinfx.ec"
 
2668
  {
 
2669
#line 1434 "dbinfx.ec"
 
2670
  sqli_curs_open(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 256), (ifx_sqlda_t *)0, (char *)0, (struct value *)0, 0, 0);
 
2671
#line 1434 "dbinfx.ec"
 
2672
  }
 
2673
if(!errorTrap()) o->flag = CURSOR_OPENED;
 
2674
o->rownum = 0;
 
2675
if(o->fl)
 
2676
for(i=0; i<o->alloc; ++i) {
 
2677
nzFree(o->fl[i]);
 
2678
o->fl[i] = 0;
 
2679
}
 
2680
exclist = 0;
 
2681
} /* sql_open */
 
2682
 
 
2683
int sql_prepOpen(const char *stmt, ...)
 
2684
{
 
2685
int n;
 
2686
va_start(sqlargs, stmt);
 
2687
n = prepareCursor(stmt, false);
 
2688
if(n < 0) return n;
 
2689
sql_open(n);
 
2690
if(rv_lastStatus) {
 
2691
short ev = rv_vendorStatus;
 
2692
short el = rv_lastStatus;
 
2693
sql_free(n);
 
2694
rv_vendorStatus = ev;
 
2695
rv_lastStatus = el;
 
2696
n = -1;
 
2697
}
 
2698
return n;
 
2699
} /* sql_prepOpen */
 
2700
 
 
2701
void sql_close(int cid)
 
2702
{
 
2703
/*
 
2704
 * $char *internal_sname, *internal_cname;
 
2705
 */
 
2706
#line 1465 "dbinfx.ec"
 
2707
  char *internal_sname, *internal_cname;
 
2708
struct OCURS *o = findCursor(cid);
 
2709
if(o->flag < CURSOR_OPENED)
 
2710
errorPrint("2cannot close cursor %d, not yet opened", cid);
 
2711
internal_cname = o->cname;
 
2712
debugExtra("close");
 
2713
/*
 
2714
 * $close :internal_cname;
 
2715
 */
 
2716
#line 1471 "dbinfx.ec"
 
2717
  {
 
2718
#line 1471 "dbinfx.ec"
 
2719
  sqli_curs_close(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 256));
 
2720
#line 1471 "dbinfx.ec"
 
2721
  }
 
2722
if(errorTrap()) return;
 
2723
o->flag = CURSOR_PREPARED;
 
2724
exclist = 0;
 
2725
} /* sql_close */
 
2726
 
 
2727
void sql_free( int cid)
 
2728
{
 
2729
/*
 
2730
 * $char *internal_sname, *internal_cname;
 
2731
 */
 
2732
#line 1479 "dbinfx.ec"
 
2733
  char *internal_sname, *internal_cname;
 
2734
struct OCURS *o = findCursor(cid);
 
2735
if(o->flag == CURSOR_OPENED)
 
2736
errorPrint("2cannot free cursor %d, not yet closed", cid);
 
2737
internal_sname = o->sname;
 
2738
debugExtra("free");
 
2739
/*
 
2740
 * $free :internal_sname;
 
2741
 */
 
2742
#line 1485 "dbinfx.ec"
 
2743
  {
 
2744
#line 1485 "dbinfx.ec"
 
2745
  sqli_curs_free(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_sname, 258));
 
2746
#line 1485 "dbinfx.ec"
 
2747
  }
 
2748
if(errorTrap()) return;
 
2749
o->flag = CURSOR_NONE;
 
2750
nzFree(o->desc);
 
2751
rv_numRets = 0;
 
2752
memset(rv_name, 0, sizeof(rv_name));
 
2753
memset(rv_type, 0, sizeof(rv_type));
 
2754
if(o->fl) { /* free any cached lines */
 
2755
short i;
 
2756
for(i=0; i<o->alloc; ++i)
 
2757
nzFree(o->fl[i]);
 
2758
nzFree(o->fl);
 
2759
o->fl = 0;
 
2760
o->alloc = 0;
 
2761
}
 
2762
exclist = 0;
 
2763
} /* sql_free */
 
2764
 
 
2765
void sql_closeFree(int cid)
 
2766
{
 
2767
const short *exc = exclist;
 
2768
sql_close(cid);
 
2769
if(!rv_lastStatus) {
 
2770
exclist = exc;
 
2771
sql_free(cid);
 
2772
}
 
2773
} /* sql_closeFree */
 
2774
 
 
2775
/* fetch row n from the open cursor.
 
2776
 * Flag can be used to fetch first, last, next, or previous. */
 
2777
bool fetchInternal(int cid, long n, int flag, bool remember)
 
2778
{
 
2779
/*
 
2780
 * $char *internal_sname, *internal_cname;
 
2781
 */
 
2782
#line 1517 "dbinfx.ec"
 
2783
  char *internal_sname, *internal_cname;
 
2784
/*
 
2785
 * $long nextrow, lastrow;
 
2786
 */
 
2787
#line 1518 "dbinfx.ec"
 
2788
long nextrow, lastrow;
 
2789
struct sqlda *internal_desc;
 
2790
struct OCURS *o = findCursor(cid);
 
2791
 
 
2792
internal_cname = o->cname;
 
2793
internal_desc = o->desc;
 
2794
retsSetup(internal_desc);
 
2795
 
 
2796
/* don't do the fetch if we're looking for row 0 absolute,
 
2797
 * that just nulls out the return values */
 
2798
if(flag == 6 && !n) {
 
2799
o->rownum = 0;
 
2800
fetchZero:
 
2801
retsCleanup();
 
2802
exclist = 0;
 
2803
return false;
 
2804
}
 
2805
 
 
2806
lastrow = nextrow = o->rownum;
 
2807
if(flag == 6) nextrow = n;
 
2808
if(flag == 3) nextrow = 1;
 
2809
if(isnotnull(lastrow)) { /* we haven't lost track yet */
 
2810
if(flag == 1) ++nextrow;
 
2811
if(flag == 2 && nextrow) --nextrow;
 
2812
}
 
2813
if(flag == 4) { /* fetch the last row */
 
2814
nextrow = nullint; /* we just lost track */
 
2815
if(o->fl && o->flag == CURSOR_PREPARED) {
 
2816
/* I'll assume you've read in all the rows, cursor is closed */
 
2817
for(nextrow=o->alloc-1; nextrow>=0; --nextrow)
 
2818
if(o->fl[nextrow]) break;
 
2819
++nextrow;
 
2820
}
 
2821
}
 
2822
 
 
2823
if(!nextrow) goto fetchZero;
 
2824
 
 
2825
/* see if we have cached this row */
 
2826
if(isnotnull(nextrow) && o->fl &&
 
2827
nextrow <= o->alloc && o->fl[nextrow-1]) {
 
2828
sql_mkload(o->fl[nextrow-1], '\177');
 
2829
/* don't run retsCleanup() here */
 
2830
rv_blobLoc = 0;
 
2831
rv_blobSize = nullint;
 
2832
o->rownum = nextrow;
 
2833
exclist = 0;
 
2834
return true;
 
2835
} /* bringing row out of cache */
 
2836
 
 
2837
if(o->flag != CURSOR_OPENED)
 
2838
errorPrint("2cannot fetch from cursor %d, not yet opened", cid);
 
2839
 
 
2840
/* The next line of code is very subtle.
 
2841
I use to declare all cursors as scroll cursors.
 
2842
It's a little inefficient, but who cares.
 
2843
Then I discovered you can't fetch blobs from scroll cursors.
 
2844
You can however fetch them from regular cursors,
 
2845
even with an order by clause.
 
2846
So cursors became non-scrolling by default.
 
2847
If the programmer chooses to fetch by absolute number,
 
2848
but he is really going in sequence, I turn them into
 
2849
fetch-next statements, so that the cursor need not be a scroll cursor. */
 
2850
if(flag == 6 &&
 
2851
isnotnull(lastrow) && isnotnull(nextrow) &&
 
2852
nextrow == lastrow+1)
 
2853
flag=1;
 
2854
 
 
2855
debugExtra("fetch");
 
2856
 
 
2857
switch(flag) {
 
2858
case 1:
 
2859
/*
 
2860
 * $fetch :internal_cname using descriptor internal_desc;
 
2861
 */
 
2862
#line 1589 "dbinfx.ec"
 
2863
  {
 
2864
#line 1589 "dbinfx.ec"
 
2865
  static _FetchSpec _FS0 = { 0, 1, 0 };
 
2866
  sqli_curs_fetch(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 256), (ifx_sqlda_t *)0, internal_desc, (char *)0, &_FS0);
 
2867
#line 1589 "dbinfx.ec"
 
2868
  }
 
2869
break;
 
2870
case 2:
 
2871
/*
 
2872
 * $fetch previous :internal_cname using descriptor internal_desc;
 
2873
 */
 
2874
#line 1592 "dbinfx.ec"
 
2875
  {
 
2876
#line 1592 "dbinfx.ec"
 
2877
  static _FetchSpec _FS0 = { 0, 2, 0 };
 
2878
  sqli_curs_fetch(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 256), (ifx_sqlda_t *)0, internal_desc, (char *)0, &_FS0);
 
2879
#line 1592 "dbinfx.ec"
 
2880
  }
 
2881
break;
 
2882
case 3:
 
2883
/*
 
2884
 * $fetch first :internal_cname using descriptor internal_desc;
 
2885
 */
 
2886
#line 1595 "dbinfx.ec"
 
2887
  {
 
2888
#line 1595 "dbinfx.ec"
 
2889
  static _FetchSpec _FS0 = { 0, 3, 0 };
 
2890
  sqli_curs_fetch(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 256), (ifx_sqlda_t *)0, internal_desc, (char *)0, &_FS0);
 
2891
#line 1595 "dbinfx.ec"
 
2892
  }
 
2893
break;
 
2894
case 4:
 
2895
/*
 
2896
 * $fetch last :internal_cname using descriptor internal_desc;
 
2897
 */
 
2898
#line 1598 "dbinfx.ec"
 
2899
  {
 
2900
#line 1598 "dbinfx.ec"
 
2901
  static _FetchSpec _FS0 = { 0, 4, 0 };
 
2902
  sqli_curs_fetch(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 256), (ifx_sqlda_t *)0, internal_desc, (char *)0, &_FS0);
 
2903
#line 1598 "dbinfx.ec"
 
2904
  }
 
2905
break;
 
2906
case 6:
 
2907
if(isnull(nextrow))
 
2908
errorPrint("2sql fetches absolute row using null index");
 
2909
/*
 
2910
 * $fetch absolute :nextrow :internal_cname using descriptor internal_desc;
 
2911
 */
 
2912
#line 1603 "dbinfx.ec"
 
2913
  {
 
2914
#line 1603 "dbinfx.ec"
 
2915
  static ifx_sqlvar_t _sqibind[] = 
 
2916
    {
 
2917
      { 103, sizeof(nextrow), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
 
2918
#line 1603 "dbinfx.ec"
 
2919
    };
 
2920
  static ifx_sqlda_t _SD0 = { 1, _sqibind, {0}, 1, 0 };
 
2921
  static _FetchSpec _FS1 = { 0, 6, 0 };
 
2922
#line 1603 "dbinfx.ec"
 
2923
  _sqibind[0].sqldata = (char *) &nextrow;
 
2924
  sqli_curs_fetch(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 256), &_SD0, internal_desc, (char *)0, &_FS1);
 
2925
#line 1603 "dbinfx.ec"
 
2926
  }
 
2927
break;
 
2928
default:
 
2929
errorPrint("@fetchInternal() receives bad flag %d", flag);
 
2930
} /* switch */
 
2931
retsCleanup();
 
2932
 
 
2933
if(errorTrap()) return false;
 
2934
exclist = 0;
 
2935
if(ENGINE_ERRCODE == 100) return false; /* not found */
 
2936
o->rownum = nextrow;
 
2937
 
 
2938
/* remember the unload image of this line */
 
2939
if(remember)
 
2940
sql_cursorUpdLine(cid, cloneString(sql_mkunld('\177')));
 
2941
return true;
 
2942
} /* fetchInternal */
 
2943
 
 
2944
bool sql_fetchFirst(int cid, ...)
 
2945
{
 
2946
        bool rc;
 
2947
        va_start(sqlargs, cid);
 
2948
        rc = fetchInternal(cid, 0L, 3, false);
 
2949
        retsCopy(false, 0);
 
2950
        return rc;
 
2951
} /* sql_fetchFirst */
 
2952
 
 
2953
bool sql_fetchLast(int cid, ...)
 
2954
{
 
2955
        bool rc;
 
2956
        va_start(sqlargs, cid);
 
2957
        rc = fetchInternal(cid, 0L, 4, false);
 
2958
        retsCopy(false, 0);
 
2959
        return rc;
 
2960
} /* sql_fetchLast */
 
2961
 
 
2962
bool sql_fetchNext(int cid, ...)
 
2963
{
 
2964
        bool rc;
 
2965
        va_start(sqlargs, cid);
 
2966
        rc = fetchInternal(cid, 0L, 1, false);
 
2967
        retsCopy(false, 0);
 
2968
        return rc;
 
2969
} /* sql_fetchNext */
 
2970
 
 
2971
bool sql_fetchPrev(int cid, ...)
 
2972
{
 
2973
        bool rc;
 
2974
        va_start(sqlargs, cid);
 
2975
        rc = fetchInternal(cid, 0L, 2, false);
 
2976
        retsCopy(false, 0);
 
2977
        return rc;
 
2978
} /* sql_fetchPrev */
 
2979
 
 
2980
bool sql_fetchAbs(int cid, long rownum, ...)
 
2981
{
 
2982
        bool rc;
 
2983
        va_start(sqlargs, rownum);
 
2984
        rc = fetchInternal(cid, rownum, 6, false);
 
2985
        retsCopy(false, 0);
 
2986
        return rc;
 
2987
} /* sql_fetchAbs */
 
2988
 
 
2989
 
 
2990
/* the inverse of sql_mkunld() */
 
2991
void sql_mkload(const char *line, char delim)
 
2992
{
 
2993
char *s, *t;
 
2994
int data;
 
2995
short i;
 
2996
 
 
2997
for(i = 0, s = (char*)line; *s; ++i, *t=delim, s = t+1) {
 
2998
t = strchr(s, delim);
 
2999
if(!t) errorPrint("2sql load line does not end in a delimiter");
 
3000
*t = 0;
 
3001
if(i >= rv_numRets)
 
3002
errorPrint("2sql load line contains more than %d fields", rv_numRets);
 
3003
 
 
3004
switch(rv_type[i]) {
 
3005
case 'N':
 
3006
if(!*s) { data = nullint; break; }
 
3007
data = strtol(s, &s, 10);
 
3008
if(*s) errorPrint("2sql load, cannot convert string to integer");
 
3009
break;
 
3010
 
 
3011
case 'S':
 
3012
if((unsigned)strlen(s) > STRINGLEN)
 
3013
errorPrint("2sql load line has a string that is too long");
 
3014
strcpy(retstring[i], s);
 
3015
data = (int) retstring[i];
 
3016
if(!*s) data = 0;
 
3017
break;
 
3018
 
 
3019
case 'F':
 
3020
rv_data[i].f = *s ? atof(s) : nullfloat;
 
3021
continue;
 
3022
 
 
3023
case 'D':
 
3024
data = stringDate(s,0);
 
3025
if(data == -1)
 
3026
errorPrint("2sql load, cannot convert string to date");
 
3027
break;
 
3028
 
 
3029
case 'C':
 
3030
data = *s;
 
3031
if(data && s[1])
 
3032
errorPrint("2sql load, character field contains more than one character");
 
3033
break;
 
3034
 
 
3035
case 'I':
 
3036
data = stringTime(s);
 
3037
if(data == -1)
 
3038
errorPrint("2sql load, cannot convert string to time interval");
 
3039
break;
 
3040
 
 
3041
default:
 
3042
errorPrint("2sql load cannot convert into type %c", rv_type[i]);
 
3043
} /* switch on type */
 
3044
 
 
3045
rv_data[i].l = data;
 
3046
} /* loop over fields in line */
 
3047
 
 
3048
if(i != rv_numRets)
 
3049
errorPrint("2sql load line contains %d fields, %d expected", i, rv_numRets);
 
3050
} /* sql_mkload */
 
3051
 
 
3052
 
 
3053
/*********************************************************************
 
3054
We maintain our own cache of fetched lines.
 
3055
Why?  You might ask.
 
3056
After all, Informix already maintains a cache of fetched lines.
 
3057
That's what the open cursor is for.
 
3058
Looks like serious wheel reinvention to me.
 
3059
Perhaps, but you can't change the data in the cache that Informix maintains.
 
3060
This is something Powerbuild et al discovered over a decade ago.
 
3061
Consider a simple spreadsheet application.
 
3062
You update the value in one of the cells, thereby updating the row
 
3063
in the database.  Now scroll down to the next page, and then back again.
 
3064
If you fetch from the open cursor you will get the old data, before the
 
3065
change was made, even though the new data is safely ensconsed in the database.
 
3066
Granted one could reopen the cursor and fetch the new data,
 
3067
but this can be slow for certain queries (sometimes a couple minutes).
 
3068
In other words, rebuilding the cursor is not really an option.
 
3069
So we are forced to retain a copy of the data in our program and change it
 
3070
whenever we update the database.
 
3071
Unfortunately the following 3 routines were developed separately,
 
3072
and they are wildly inconsistent.  Some take a row number while
 
3073
others assume you are modifying the current row as stored in o->rownum.
 
3074
Some accept a line of tex, the unload image of the fetch data, while
 
3075
others build the line of text from the fetched data in rv_data[].
 
3076
I apologize for this confusion; clearly a redesign is called for.
 
3077
*********************************************************************/
 
3078
 
 
3079
/* update the text of a fetched line,
 
3080
 * so we get this same text again when we refetch the line later.
 
3081
 * These text changes corespond to the database changes that form an update.
 
3082
 * We assume the line has been allocated using malloc(). */
 
3083
void sql_cursorUpdLine(int cid, const char *line)
 
3084
{
 
3085
struct OCURS *o = findCursor(cid);
 
3086
int n = o->rownum-1;
 
3087
 
 
3088
if(n >= CACHELIMIT)
 
3089
errorPrint("2SQL cursor caches too many lines, limit %d", CACHELIMIT);
 
3090
 
 
3091
if(n >= o->alloc) {
 
3092
/* running off the end, allocate 128 at a time */
 
3093
short oldalloc = o->alloc;
 
3094
o->alloc = n + 128;
 
3095
if(!oldalloc)
 
3096
o->fl = (char **) allocMem(o->alloc*sizeof(char*));
 
3097
else
 
3098
o->fl = (char**) reallocMem((void*)o->fl, o->alloc*sizeof(char*));
 
3099
memset(o->fl+oldalloc, 0, (o->alloc-oldalloc)*sizeof(char*));
 
3100
} /* allocating more space */
 
3101
 
 
3102
nzFree(o->fl[n]);
 
3103
o->fl[n] = (char*)line;
 
3104
} /* sql_cursorUpdLine */
 
3105
 
 
3106
void sql_cursorDelLine(int cid, int rownum)
 
3107
{
 
3108
struct OCURS *o = findCursor(cid);
 
3109
o->rownum = rownum;
 
3110
--rownum;
 
3111
if(rownum >= o->alloc || !o->fl[rownum])
 
3112
errorPrint("2cursorDelLine(%d)", rownum);
 
3113
nzFree(o->fl[rownum]);
 
3114
if(rownum < o->alloc-1)
 
3115
memcpy(o->fl+rownum, o->fl+rownum+1, (o->alloc-rownum-1)*sizeof(char *));
 
3116
o->fl[o->alloc-1] = 0;
 
3117
/* back up the row number if we deleted the last row */
 
3118
if(!o->fl[rownum]) --o->rownum;
 
3119
} /* sql_cursorDelLine */
 
3120
 
 
3121
void sql_cursorInsLine(int cid, int rownum)
 
3122
{
 
3123
struct OCURS *o = findCursor(cid);
 
3124
short i;
 
3125
 
 
3126
/* must insert a row within or immediately following the current data */
 
3127
if(rownum > o->alloc)
 
3128
errorPrint("2cursorInsLine(%d)", rownum);
 
3129
/* newly inserted row becomes the current row */
 
3130
o->rownum = rownum+1;
 
3131
 
 
3132
if(!o->alloc || o->fl[o->alloc-1]) { /* need to make room */
 
3133
o->alloc += 128;
 
3134
if(!o->fl)
 
3135
o->fl = (char **) allocMem(o->alloc*sizeof(char*));
 
3136
else
 
3137
o->fl = (char**) reallocMem((void*)o->fl, o->alloc*sizeof(char*));
 
3138
memset(o->fl+o->alloc-128, 0, 128*sizeof(char*));
 
3139
} /* allocating more space */
 
3140
 
 
3141
/* move the rest of the lines down */
 
3142
for(i=o->alloc-1; i>rownum; --i)
 
3143
o->fl[i] = o->fl[i-1];
 
3144
o->fl[i] = cloneString(sql_mkunld('\177'));
 
3145
} /* sql_cursorInsLine */
 
3146
 
 
3147
 
 
3148
/*********************************************************************
 
3149
run the analog of /bin/comm on two open cursors,
 
3150
rather than two Unix files.
 
3151
This assumes a common unique key that we use to sync up the rows.
 
3152
The cursors should be sorted by this key.
 
3153
*********************************************************************/
 
3154
 
 
3155
void cursor_comm(
 
3156
const char *stmt1, const char *stmt2, /* the two select statements */
 
3157
const char *orderby, /* which fetched column is the unique key */
 
3158
fnptr f, /* call this function for differences */
 
3159
char delim) /* sql_mkunld() delimiter, or call mkinsupd if delim = 0 */
 
3160
{
 
3161
short cid1, cid2; /* the cursor ID numbers */
 
3162
char *line1, *line2, *s; /* the two fetched rows */
 
3163
void *blob1, *blob2; /* one blob per table */
 
3164
int blob1size, blob2size;
 
3165
bool eof1, eof2, get1, get2;
 
3166
int sortval1, sortval2;
 
3167
char sortstring1[80], sortstring2[80];
 
3168
int sortcol;
 
3169
char sorttype;
 
3170
int passkey1, passkey2;
 
3171
static const char sortnull[] = "cursor_comm, sortval%d is null";
 
3172
static const char sortlong[] = "cursor_comm cannot key on strings longer than %d";
 
3173
static const char noblob[] = "sorry, cursor_comm cannot handle blobs yet";
 
3174
 
 
3175
cid1 = sql_prepOpen(stmt1);
 
3176
cid2 = sql_prepOpen(stmt2);
 
3177
 
 
3178
sortcol = findcol_byname(orderby);
 
3179
sorttype = rv_type[sortcol];
 
3180
if(charInList("NDIS", sorttype) < 0)
 
3181
errorPrint("2cursor_com(), column %s has bad type %c", orderby, sorttype);
 
3182
if(sorttype == 'S')
 
3183
passkey1 = (int)sortstring1, passkey2 = (int)sortstring2;
 
3184
 
 
3185
eof1 = eof2 = false;
 
3186
get1 = get2 = true;
 
3187
rv_blobFile = 0; /* in case the cursor has a blob */
 
3188
line1 = line2 = 0;
 
3189
blob1 = blob2 = 0;
 
3190
 
 
3191
while(true) {
 
3192
if(get1) { /* fetch first row */
 
3193
eof1 = !sql_fetchNext(cid1, 0);
 
3194
nzFree(line1);
 
3195
line1 = 0;
 
3196
nzFree(blob1);
 
3197
blob1 = 0;
 
3198
if(!eof1) {
 
3199
if(sorttype == 'S') {
 
3200
s = rv_data[sortcol].ptr;
 
3201
if(isnullstring(s)) errorPrint(sortnull, 1);
 
3202
if(strlen(s) >= sizeof(sortstring1))
 
3203
errorPrint(sortlong, sizeof(sortstring1));
 
3204
strcpy(sortstring1, s);
 
3205
} else {
 
3206
passkey1 = sortval1 = rv_data[sortcol].l;
 
3207
if(isnull(sortval1))
 
3208
errorPrint(sortnull, 1);
 
3209
}
 
3210
line1 = cloneString(delim ? sql_mkunld(delim) : sql_mkinsupd());
 
3211
if(rv_blobLoc) {
 
3212
blob1 = rv_blobLoc;
 
3213
blob1size = rv_blobSize;
 
3214
errorPrint(noblob);
 
3215
}
 
3216
} /* not eof */
 
3217
} /* looking for first line */
 
3218
 
 
3219
if(get2) { /* fetch second row */
 
3220
eof2 = !sql_fetchNext(cid2, 0);
 
3221
nzFree(line2);
 
3222
line2 = 0;
 
3223
nzFree(blob2);
 
3224
blob2 = 0;
 
3225
if(!eof2) {
 
3226
if(sorttype == 'S') {
 
3227
s = rv_data[sortcol].ptr;
 
3228
if(isnullstring(s)) errorPrint(sortnull, 2);
 
3229
if(strlen(s) >= sizeof(sortstring2))
 
3230
errorPrint(sortlong, sizeof(sortstring2));
 
3231
strcpy(sortstring2, rv_data[sortcol].ptr);
 
3232
} else {
 
3233
passkey2 = sortval2 = rv_data[sortcol].l;
 
3234
if(isnull(sortval2))
 
3235
errorPrint(sortnull, 2);
 
3236
}
 
3237
line2 = cloneString(delim ? sql_mkunld(delim) : sql_mkinsupd());
 
3238
if(rv_blobLoc) {
 
3239
blob2 = rv_blobLoc;
 
3240
blob2size = rv_blobSize;
 
3241
errorPrint(noblob);
 
3242
}
 
3243
} /* not eof */
 
3244
} /* looking for second line */
 
3245
 
 
3246
if(eof1 & eof2) break; /* done */
 
3247
get1 = get2 = false;
 
3248
 
 
3249
/* in cid2, but not in cid1 */
 
3250
if(eof1 || !eof2 &&
 
3251
(sorttype == 'S' && strcmp(sortstring1, sortstring2) > 0 ||
 
3252
sorttype != 'S' && sortval1 > sortval2)) {
 
3253
(*f)('>', line1, line2, passkey2);
 
3254
get2 = true;
 
3255
continue;
 
3256
}
 
3257
 
 
3258
/* in cid1, but not in cid2 */
 
3259
if(eof2 || !eof1 &&
 
3260
(sorttype == 'S' && strcmp(sortstring1, sortstring2) < 0 ||
 
3261
sorttype != 'S' && sortval1 < sortval2)) {
 
3262
(*f)('<', line1, line2, passkey1);
 
3263
get1 = true;
 
3264
continue;
 
3265
} /* insert case */
 
3266
 
 
3267
get1 = get2 = true;
 
3268
/* perhaps the lines are equal */
 
3269
if(stringEqual(line1, line2)) continue;
 
3270
 
 
3271
/* lines are different between the two cursors */
 
3272
(*f)('*', line1, line2, passkey2);
 
3273
} /* loop over parallel cursors */
 
3274
 
 
3275
nzFree(line1);
 
3276
nzFree(line2);
 
3277
nzFree(blob1);
 
3278
nzFree(blob2);
 
3279
sql_closeFree(cid1);
 
3280
sql_closeFree(cid2);
 
3281
} /* cursor_comm */
 
3282
 
 
3283
/*********************************************************************
 
3284
Get the primary key for a table.
 
3285
In informix, you can use system tables to get this information.
 
3286
There's a way to do it in odbc, but I don't remember.
 
3287
*********************************************************************/
 
3288
 
 
3289
void
 
3290
getPrimaryKey(char *tname, int *part1, int *part2)
 
3291
{
 
3292
int p1, p2, rc;
 
3293
char *s = strchr(tname, ':');
 
3294
*part1 = *part2 = 0;
 
3295
if(!s) {
 
3296
rc = sql_select("select part1, part2 \
 
3297
from sysconstraints c, systables t, sysindexes i \
 
3298
where tabname = %S and t.tabid = c.tabid \
 
3299
and constrtype = 'P' and c.idxname = i.idxname",
 
3300
tname, &p1, &p2);
 
3301
} else {
 
3302
*s = 0;
 
3303
rc = sql_select("select part1, part2 \
 
3304
from %s:sysconstraints c, %s:systables t, %s:sysindexes i \
 
3305
where tabname = %S and t.tabid = c.tabid \
 
3306
and constrtype = 'P' and c.idxname = i.idxname",
 
3307
tname, tname, tname, s+1, &p1, &p2);
 
3308
*s = ':';
 
3309
}
 
3310
if(rc) *part1 = p1, *part2 = p2;
 
3311
} /* getPrimaryKey */
 
3312
 
 
3313
 
 
3314
#line 1989 "dbinfx.ec"