~ubuntu-branches/ubuntu/karmic/firebird2.1/karmic

« back to all changes in this revision

Viewing changes to examples/api/apifull.c

  • Committer: Bazaar Package Importer
  • Author(s): Damyan Ivanov
  • Date: 2008-05-26 23:59:25 UTC
  • Revision ID: james.westby@ubuntu.com-20080526235925-2pnqj6nxpppoeaer
Tags: upstream-2.1.0.17798-0.ds2
ImportĀ upstreamĀ versionĀ 2.1.0.17798-0.ds2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *    Program type:  API Interface
 
3
 *
 
4
 *    Description:
 
5
 *    This program prompts for and executes unknown SQL statements.
 
6
 * The contents of this file are subject to the Interbase Public
 
7
 * License Version 1.0 (the "License"); you may not use this file
 
8
 * except in compliance with the License. You may obtain a copy
 
9
 * of the License at http://www.Inprise.com/IPL.html
 
10
 *
 
11
 * Software distributed under the License is distributed on an
 
12
 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
 
13
 * or implied. See the License for the specific language governing
 
14
 * rights and limitations under the License.
 
15
 *
 
16
 * The Original Code was created by Inprise Corporation
 
17
 * and its predecessors. Portions created by Inprise Corporation are
 
18
 * Copyright (C) Inprise Corporation.
 
19
 *
 
20
 * All Rights Reserved.
 
21
 * Contributor(s): ______________________________________.
 
22
 */
 
23
 
 
24
#include <stdlib.h>
 
25
#include <string.h>
 
26
#include <stdio.h>
 
27
#if TIME_WITH_SYS_TIME
 
28
# include <sys/time.h>
 
29
# include <time.h>
 
30
#else
 
31
# if HAVE_SYS_TIME_H
 
32
#  include <sys/time.h>
 
33
# else
 
34
#  include <time.h>
 
35
# endif
 
36
#endif
 
37
#include <ctype.h>
 
38
#include <ibase.h>
 
39
#include "align.h"
 
40
#include "example.h"
 
41
 
 
42
#define    MAXLEN    1024
 
43
 
 
44
process_statement (XSQLDA ** sqlda, char *query);
 
45
void print_column (XSQLVAR * var);
 
46
int get_statement (char * buf);
 
47
 
 
48
/* ibase.h contains PARAMVARY, with the handicap that vary_string is unsigned char*
 
49
instead of plain char*.
 
50
Maybe we should fix ibase.h for users but without affecting the engine */
 
51
/* typedef struct vary2 {
 
52
    unsigned short vary_length;
 
53
    char           vary_string [1];
 
54
} VARY2;
 
55
*/
 
56
typedef PARAMVARY VARY2;
 
57
 
 
58
isc_db_handle      db = NULL;
 
59
isc_tr_handle      trans = NULL;
 
60
isc_stmt_handle    stmt = NULL;
 
61
ISC_STATUS_ARRAY   status;
 
62
int                ret;
 
63
 
 
64
#ifndef ISC_INT64_FORMAT
 
65
 
 
66
/* Define a format string for printf.  Printing of 64-bit integers
 
67
   is not standard between platforms */
 
68
 
 
69
#if (defined(_MSC_VER) && defined(WIN32))
 
70
#define ISC_INT64_FORMAT        "I64"
 
71
#else
 
72
#define ISC_INT64_FORMAT        "ll"
 
73
#endif
 
74
#endif
 
75
 
 
76
 
 
77
int main (int argc, char** argv)
 
78
{
 
79
    int                   query[MAXLEN];
 
80
    XSQLDA    *            sqlda;
 
81
    char                   db_name[128];
 
82
 
 
83
    if (argc < 2)
 
84
    {
 
85
        printf("Enter the database name:  ");
 
86
        gets(db_name);
 
87
    }
 
88
    else
 
89
    {
 
90
        strcpy(db_name, argv[1]);
 
91
    }
 
92
 
 
93
    if (isc_attach_database(status, 0, db_name, &db, 0, NULL))
 
94
    {
 
95
        printf("Could not open database %s\n", db_name);
 
96
        ERREXIT(status, 1);
 
97
    }                      
 
98
 
 
99
    /* 
 
100
    *    Allocate enough space for 20 fields.  
 
101
    *    If more fields get selected, re-allocate SQLDA later.
 
102
     */
 
103
    sqlda = (XSQLDA *) malloc(XSQLDA_LENGTH (20));
 
104
    sqlda->sqln = 20;
 
105
    sqlda->version = 1;
 
106
 
 
107
    /* Allocate a global statement */
 
108
    if (isc_dsql_allocate_statement(status, &db, &stmt))
 
109
    {
 
110
        free (sqlda);
 
111
        ERREXIT(status,1)
 
112
    }
 
113
 
 
114
    /*
 
115
     *    Process SQL statements.
 
116
     */
 
117
    ret = get_statement((char *) query);
 
118
    /* Use break on error or exit */
 
119
    while (ret != 1)
 
120
    {
 
121
        /* We must pass the address of sqlda, in case it
 
122
        ** gets re-allocated 
 
123
        */
 
124
        ret = process_statement(&sqlda,
 
125
                                (char *) query);
 
126
            if (ret == 1)
 
127
                break;
 
128
        ret = get_statement((char *) query);
 
129
    }
 
130
 
 
131
    free (sqlda);
 
132
    if (trans)
 
133
        if (isc_commit_transaction(status, &trans))
 
134
        {
 
135
            ERREXIT(status,1);
 
136
        }
 
137
 
 
138
    if (isc_detach_database(status, &db))
 
139
    {
 
140
                ERREXIT(status,1);
 
141
    }
 
142
 
 
143
    return ret;
 
144
}
 
145
 
 
146
/* 
 
147
**  Function:  process_statement
 
148
**  Process submitted statement.  On any fundamental error, return status 1,
 
149
**  which will do an isc_print_status and exit the program.
 
150
**  On user errors, found in parsing or executing go to status 2,
 
151
**  which will print the error and continue.
 
152
*/
 
153
 
 
154
process_statement (XSQLDA **sqldap, char *query)
 
155
{
 
156
    int            buffer[MAXLEN];
 
157
    XSQLDA          *sqlda;
 
158
    XSQLVAR         *var;
 
159
    short           num_cols, i;
 
160
    short           length, alignment, type, offset;
 
161
    int            fetch_stat;
 
162
    static char     stmt_info[] = { isc_info_sql_stmt_type };
 
163
    char            info_buffer[20];
 
164
    short           l;
 
165
    int            statement_type;
 
166
 
 
167
    sqlda = *sqldap;
 
168
 
 
169
    /* Start a transaction if we are not in one */
 
170
    if (!trans)
 
171
        if (isc_start_transaction(status, &trans, 1, &db, 0, NULL))
 
172
        {
 
173
            ERREXIT(status, 1)
 
174
        }
 
175
 
 
176
    if (isc_dsql_prepare(status, &trans, &stmt, 0, query, SQL_DIALECT_V6, sqlda))
 
177
    {
 
178
        ERREXIT(status,2)
 
179
    }
 
180
 
 
181
    /* What is the statement type of this statement? 
 
182
    **
 
183
    ** stmt_info is a 1 byte info request.  info_buffer is a buffer
 
184
    ** large enough to hold the returned info packet
 
185
    ** The info_buffer returned contains a isc_info_sql_stmt_type in the first byte, 
 
186
    ** two bytes of length, and a statement_type token.
 
187
    */
 
188
    if (!isc_dsql_sql_info(status, &stmt, sizeof (stmt_info), stmt_info,
 
189
        sizeof (info_buffer), info_buffer))
 
190
    {
 
191
        l = (short) isc_vax_integer((char *) info_buffer + 1, 2);
 
192
        statement_type = isc_vax_integer((char *) info_buffer + 3, l);
 
193
    }
 
194
 
 
195
 
 
196
    /*
 
197
     *    Execute a non-select statement.
 
198
     */
 
199
    if (!sqlda->sqld)
 
200
    {
 
201
        if (isc_dsql_execute(status, &trans, &stmt, SQL_DIALECT_V6, NULL))
 
202
        {
 
203
            ERREXIT(status,2)
 
204
        }
 
205
 
 
206
        /* Commit DDL statements if that is what sql_info says */
 
207
 
 
208
        if (trans && (statement_type == isc_info_sql_stmt_ddl))
 
209
        {
 
210
            printf ("\tCommitting...\n");
 
211
            if (isc_commit_transaction(status, &trans))
 
212
            {
 
213
                ERREXIT(status, 2)
 
214
            }    
 
215
        }
 
216
 
 
217
        return 0;
 
218
    }
 
219
 
 
220
    /*
 
221
     *    Process select statements.
 
222
     */
 
223
 
 
224
    num_cols = sqlda->sqld;
 
225
 
 
226
    /* Need more room. */
 
227
    if (sqlda->sqln < num_cols)
 
228
    {
 
229
        *sqldap = sqlda = (XSQLDA *) realloc(sqlda,
 
230
                                                XSQLDA_LENGTH (num_cols));
 
231
        sqlda->sqln = num_cols;
 
232
        sqlda->version = 1;
 
233
 
 
234
        if (isc_dsql_describe(status, &stmt, SQL_DIALECT_V6, sqlda))
 
235
        {
 
236
            ERREXIT(status,2)
 
237
        }
 
238
 
 
239
        num_cols = sqlda->sqld;
 
240
    }
 
241
 
 
242
    /*
 
243
     *     Set up SQLDA.
 
244
     */
 
245
    for (var = sqlda->sqlvar, offset = 0, i = 0; i < num_cols; var++, i++)
 
246
    {
 
247
        length = alignment = var->sqllen;
 
248
        type = var->sqltype & ~1;
 
249
 
 
250
        if (type == SQL_TEXT)
 
251
            alignment = 1;
 
252
        else if (type == SQL_VARYING)
 
253
        {   
 
254
            length += sizeof (short) + 1;
 
255
            alignment = sizeof (short);
 
256
        }
 
257
        /*  RISC machines are finicky about word alignment
 
258
        **  So the output buffer values must be placed on
 
259
        **  word boundaries where appropriate
 
260
        */
 
261
        offset = FB_ALIGN(offset, alignment);
 
262
        var->sqldata = (char *) buffer + offset;
 
263
        offset += length;
 
264
        offset = FB_ALIGN(offset, sizeof (short));
 
265
        var->sqlind = (short*) ((char *) buffer + offset);
 
266
        offset += sizeof  (short);
 
267
    }
 
268
 
 
269
    if (isc_dsql_execute(status, &trans, &stmt, SQL_DIALECT_V6, NULL))
 
270
    {
 
271
        ERREXIT(status,2)
 
272
    }
 
273
 
 
274
    /*
 
275
     *    Print rows.
 
276
     */
 
277
 
 
278
    while ((fetch_stat = isc_dsql_fetch(status, &stmt, SQL_DIALECT_V6, sqlda)) == 0)
 
279
    {
 
280
        for (i = 0; i < num_cols; i++)
 
281
        {
 
282
            print_column((XSQLVAR *) &sqlda->sqlvar[i]);
 
283
        }
 
284
        printf("\n");
 
285
    }
 
286
 
 
287
    /* Close cursor */
 
288
    if (isc_dsql_free_statement(status, &stmt, DSQL_close))
 
289
    {
 
290
                ERREXIT (status,2);
 
291
    }
 
292
 
 
293
    if (fetch_stat != 100L)
 
294
    {
 
295
        ERREXIT(status,2)
 
296
    }
 
297
 
 
298
    return 0;
 
299
}
 
300
 
 
301
/*
 
302
 *    Print column's data.
 
303
 */
 
304
void print_column (XSQLVAR *var)
 
305
{
 
306
    short       dtype;
 
307
    char        data[MAXLEN], *p;
 
308
    char        blob_s[20], date_s[25];
 
309
    VARY2        *vary2;
 
310
    short       len; 
 
311
    struct tm   times;
 
312
    ISC_QUAD    bid;
 
313
 
 
314
    dtype = var->sqltype & ~1;
 
315
    p = data;
 
316
 
 
317
    /* Null handling.  If the column is nullable and null */
 
318
    if ((var->sqltype & 1) && (*var->sqlind < 0))
 
319
    {
 
320
        switch (dtype)
 
321
        {
 
322
            case SQL_TEXT:
 
323
            case SQL_VARYING:
 
324
                len = var->sqllen;
 
325
                break;
 
326
            case SQL_SHORT:
 
327
                len = 6;
 
328
                if (var->sqlscale > 0) len += var->sqlscale;
 
329
                break;
 
330
            case SQL_LONG:
 
331
                len = 11;
 
332
                if (var->sqlscale > 0) len += var->sqlscale;
 
333
                break;
 
334
            case SQL_INT64:
 
335
                len = 21;
 
336
                if (var->sqlscale > 0) len += var->sqlscale;
 
337
                break;
 
338
            case SQL_FLOAT:
 
339
                len = 15;
 
340
                break;
 
341
            case SQL_DOUBLE:
 
342
                len = 24;
 
343
                break;
 
344
            case SQL_TIMESTAMP:
 
345
                len = 24;
 
346
                break;
 
347
            case SQL_TYPE_DATE:
 
348
                len = 10;
 
349
                break;
 
350
            case SQL_TYPE_TIME:
 
351
                len = 13;
 
352
                break;
 
353
            case SQL_BLOB:
 
354
            case SQL_ARRAY:
 
355
            default:
 
356
                len = 17;
 
357
                break;
 
358
        }
 
359
        if ((dtype == SQL_TEXT) || (dtype == SQL_VARYING))
 
360
            sprintf(p, "%-*s ", len, "NULL");
 
361
        else
 
362
            sprintf(p, "%*s ", len, "NULL");
 
363
    }
 
364
    else
 
365
    {
 
366
        switch (dtype)
 
367
        {
 
368
            case SQL_TEXT:
 
369
                sprintf(p, "%.*s ", var->sqllen, var->sqldata);
 
370
                break;
 
371
 
 
372
            case SQL_VARYING:
 
373
                vary2 = (VARY2*) var->sqldata;
 
374
                vary2->vary_string[vary2->vary_length] = '\0';
 
375
                sprintf(p, "%-*s ", var->sqllen, vary2->vary_string);
 
376
                break;
 
377
 
 
378
            case SQL_SHORT:
 
379
            case SQL_LONG:
 
380
            case SQL_INT64:
 
381
                {
 
382
                ISC_INT64       value;
 
383
                short           field_width;
 
384
                short           dscale;
 
385
                switch (dtype)
 
386
                    {
 
387
                    case SQL_SHORT:
 
388
                        value = (ISC_INT64) *(short *) var->sqldata;
 
389
                        field_width = 6;
 
390
                        break;
 
391
                    case SQL_LONG:
 
392
                        value = (ISC_INT64) *(int *) var->sqldata;
 
393
                        field_width = 11;
 
394
                        break;
 
395
                    case SQL_INT64:
 
396
                        value = (ISC_INT64) *(ISC_INT64 *) var->sqldata;
 
397
                        field_width = 21;
 
398
                        break;
 
399
                    }
 
400
                dscale = var->sqlscale;
 
401
                if (dscale < 0)
 
402
                    {
 
403
                    ISC_INT64   tens;
 
404
                    short       i;
 
405
 
 
406
                    tens = 1;
 
407
                    for (i = 0; i > dscale; i--)
 
408
                        tens *= 10;
 
409
 
 
410
                    if (value >= 0)
 
411
                        sprintf (p, "%*" ISC_INT64_FORMAT "d.%0*" ISC_INT64_FORMAT "d",
 
412
                                field_width - 1 + dscale, 
 
413
                                (ISC_INT64) value / tens,
 
414
                                -dscale, 
 
415
                                (ISC_INT64) value % tens);
 
416
                    else if ((value / tens) != 0)
 
417
                        sprintf (p, "%*" ISC_INT64_FORMAT "d.%0*" ISC_INT64_FORMAT "d",
 
418
                                field_width - 1 + dscale, 
 
419
                                (ISC_INT64) (value / tens),
 
420
                                -dscale, 
 
421
                                (ISC_INT64) -(value % tens));
 
422
                    else
 
423
                        sprintf (p, "%*s.%0*" ISC_INT64_FORMAT "d",
 
424
                                field_width - 1 + dscale, 
 
425
                                "-0",
 
426
                                -dscale, 
 
427
                                (ISC_INT64) -(value % tens));
 
428
                    }
 
429
                else if (dscale)
 
430
                    sprintf (p, "%*" ISC_INT64_FORMAT "d%0*d", 
 
431
                            field_width, 
 
432
                            (ISC_INT64) value,
 
433
                            dscale, 0);
 
434
                else
 
435
                    sprintf (p, "%*" ISC_INT64_FORMAT "d%",
 
436
                            field_width, 
 
437
                            (ISC_INT64) value);
 
438
                }
 
439
                break;
 
440
 
 
441
            case SQL_FLOAT:
 
442
                sprintf(p, "%15g ", *(float *) (var->sqldata));
 
443
                break;
 
444
 
 
445
            case SQL_DOUBLE:
 
446
                sprintf(p, "%24f ", *(double *) (var->sqldata));
 
447
                break;
 
448
 
 
449
            case SQL_TIMESTAMP:
 
450
                isc_decode_timestamp((ISC_TIMESTAMP *)var->sqldata, &times);
 
451
                sprintf(date_s, "%04d-%02d-%02d %02d:%02d:%02d.%04d",
 
452
                                times.tm_year + 1900,
 
453
                                times.tm_mon+1,
 
454
                                times.tm_mday,
 
455
                                times.tm_hour,
 
456
                                times.tm_min,
 
457
                                times.tm_sec,
 
458
                                ((ISC_TIMESTAMP *)var->sqldata)->timestamp_time % 10000);
 
459
                sprintf(p, "%*s ", 24, date_s);
 
460
                break;
 
461
 
 
462
            case SQL_TYPE_DATE:
 
463
                isc_decode_sql_date((ISC_DATE *)var->sqldata, &times);
 
464
                sprintf(date_s, "%04d-%02d-%02d",
 
465
                                times.tm_year + 1900,
 
466
                                times.tm_mon+1,
 
467
                                times.tm_mday);
 
468
                sprintf(p, "%*s ", 10, date_s);
 
469
                break;
 
470
 
 
471
            case SQL_TYPE_TIME:
 
472
                isc_decode_sql_time((ISC_TIME *)var->sqldata, &times);
 
473
                sprintf(date_s, "%02d:%02d:%02d.%04d",
 
474
                                times.tm_hour,
 
475
                                times.tm_min,
 
476
                                times.tm_sec,
 
477
                                (*((ISC_TIME *)var->sqldata)) % 10000);
 
478
                sprintf(p, "%*s ", 13, date_s);
 
479
                break;
 
480
 
 
481
            case SQL_BLOB:
 
482
            case SQL_ARRAY:
 
483
                /* Print the blob id on blobs or arrays */
 
484
                bid = *(ISC_QUAD *) var->sqldata;
 
485
                sprintf(blob_s, "%08x:%08x", bid.gds_quad_high, bid.gds_quad_low);
 
486
                sprintf(p, "%17s ", blob_s);
 
487
                break;
 
488
 
 
489
            default:
 
490
                break;
 
491
        }
 
492
    }
 
493
 
 
494
    while (*p)
 
495
    {
 
496
        putchar(*p++);
 
497
    }
 
498
    
 
499
}
 
500
 
 
501
 
 
502
/*
 
503
 *    Prompt for and get input.
 
504
 *    Statements are terminated by a semicolon.
 
505
 */
 
506
int get_statement (char *buf)
 
507
{
 
508
    short   c;
 
509
    char    *p;
 
510
    int     cnt;
 
511
 
 
512
    p = buf;
 
513
    cnt = 0;
 
514
    printf("SQL> ");
 
515
 
 
516
    for (;;)
 
517
    {
 
518
        if ((c = getchar()) == EOF)
 
519
            return 1;
 
520
 
 
521
        if (c == '\n')
 
522
        {
 
523
            /* accept "quit" or "exit" to terminate application */
 
524
 
 
525
            if (!strncmp(buf, "exit", 4))
 
526
                return 1;
 
527
            if (!strncmp(buf, "quit", 4))
 
528
                return 1;
 
529
 
 
530
            /* Search back through white space looking for ';'.*/
 
531
            while (cnt && isspace(*(p - 1)))
 
532
            {
 
533
                p--;
 
534
                cnt--;
 
535
            }
 
536
            if (*(p - 1) == ';')
 
537
            {
 
538
                *p++ = '\0';
 
539
 
 
540
                return 0;
 
541
            }
 
542
            *p++ = ' ';
 
543
            printf("CON> ");
 
544
        }
 
545
        else
 
546
        {
 
547
            *p++ = (char)c;
 
548
        }
 
549
        cnt++;
 
550
    }
 
551
}
 
552