2
* Program type: API Interface
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
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.
16
* The Original Code was created by Inprise Corporation
17
* and its predecessors. Portions created by Inprise Corporation are
18
* Copyright (C) Inprise Corporation.
20
* All Rights Reserved.
21
* Contributor(s): ______________________________________.
27
#if TIME_WITH_SYS_TIME
28
# include <sys/time.h>
32
# include <sys/time.h>
44
process_statement (XSQLDA ** sqlda, char *query);
45
void print_column (XSQLVAR * var);
46
int get_statement (char * buf);
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;
56
typedef PARAMVARY VARY2;
58
isc_db_handle db = NULL;
59
isc_tr_handle trans = NULL;
60
isc_stmt_handle stmt = NULL;
61
ISC_STATUS_ARRAY status;
64
#ifndef ISC_INT64_FORMAT
66
/* Define a format string for printf. Printing of 64-bit integers
67
is not standard between platforms */
69
#if (defined(_MSC_VER) && defined(WIN32))
70
#define ISC_INT64_FORMAT "I64"
72
#define ISC_INT64_FORMAT "ll"
77
int main (int argc, char** argv)
85
printf("Enter the database name: ");
90
strcpy(db_name, argv[1]);
93
if (isc_attach_database(status, 0, db_name, &db, 0, NULL))
95
printf("Could not open database %s\n", db_name);
100
* Allocate enough space for 20 fields.
101
* If more fields get selected, re-allocate SQLDA later.
103
sqlda = (XSQLDA *) malloc(XSQLDA_LENGTH (20));
107
/* Allocate a global statement */
108
if (isc_dsql_allocate_statement(status, &db, &stmt))
115
* Process SQL statements.
117
ret = get_statement((char *) query);
118
/* Use break on error or exit */
121
/* We must pass the address of sqlda, in case it
124
ret = process_statement(&sqlda,
128
ret = get_statement((char *) query);
133
if (isc_commit_transaction(status, &trans))
138
if (isc_detach_database(status, &db))
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.
154
process_statement (XSQLDA **sqldap, char *query)
160
short length, alignment, type, offset;
162
static char stmt_info[] = { isc_info_sql_stmt_type };
163
char info_buffer[20];
169
/* Start a transaction if we are not in one */
171
if (isc_start_transaction(status, &trans, 1, &db, 0, NULL))
176
if (isc_dsql_prepare(status, &trans, &stmt, 0, query, SQL_DIALECT_V6, sqlda))
181
/* What is the statement type of this statement?
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.
188
if (!isc_dsql_sql_info(status, &stmt, sizeof (stmt_info), stmt_info,
189
sizeof (info_buffer), info_buffer))
191
l = (short) isc_vax_integer((char *) info_buffer + 1, 2);
192
statement_type = isc_vax_integer((char *) info_buffer + 3, l);
197
* Execute a non-select statement.
201
if (isc_dsql_execute(status, &trans, &stmt, SQL_DIALECT_V6, NULL))
206
/* Commit DDL statements if that is what sql_info says */
208
if (trans && (statement_type == isc_info_sql_stmt_ddl))
210
printf ("\tCommitting...\n");
211
if (isc_commit_transaction(status, &trans))
221
* Process select statements.
224
num_cols = sqlda->sqld;
226
/* Need more room. */
227
if (sqlda->sqln < num_cols)
229
*sqldap = sqlda = (XSQLDA *) realloc(sqlda,
230
XSQLDA_LENGTH (num_cols));
231
sqlda->sqln = num_cols;
234
if (isc_dsql_describe(status, &stmt, SQL_DIALECT_V6, sqlda))
239
num_cols = sqlda->sqld;
245
for (var = sqlda->sqlvar, offset = 0, i = 0; i < num_cols; var++, i++)
247
length = alignment = var->sqllen;
248
type = var->sqltype & ~1;
250
if (type == SQL_TEXT)
252
else if (type == SQL_VARYING)
254
length += sizeof (short) + 1;
255
alignment = sizeof (short);
257
/* RISC machines are finicky about word alignment
258
** So the output buffer values must be placed on
259
** word boundaries where appropriate
261
offset = FB_ALIGN(offset, alignment);
262
var->sqldata = (char *) buffer + offset;
264
offset = FB_ALIGN(offset, sizeof (short));
265
var->sqlind = (short*) ((char *) buffer + offset);
266
offset += sizeof (short);
269
if (isc_dsql_execute(status, &trans, &stmt, SQL_DIALECT_V6, NULL))
278
while ((fetch_stat = isc_dsql_fetch(status, &stmt, SQL_DIALECT_V6, sqlda)) == 0)
280
for (i = 0; i < num_cols; i++)
282
print_column((XSQLVAR *) &sqlda->sqlvar[i]);
288
if (isc_dsql_free_statement(status, &stmt, DSQL_close))
293
if (fetch_stat != 100L)
302
* Print column's data.
304
void print_column (XSQLVAR *var)
307
char data[MAXLEN], *p;
308
char blob_s[20], date_s[25];
314
dtype = var->sqltype & ~1;
317
/* Null handling. If the column is nullable and null */
318
if ((var->sqltype & 1) && (*var->sqlind < 0))
328
if (var->sqlscale > 0) len += var->sqlscale;
332
if (var->sqlscale > 0) len += var->sqlscale;
336
if (var->sqlscale > 0) len += var->sqlscale;
359
if ((dtype == SQL_TEXT) || (dtype == SQL_VARYING))
360
sprintf(p, "%-*s ", len, "NULL");
362
sprintf(p, "%*s ", len, "NULL");
369
sprintf(p, "%.*s ", var->sqllen, var->sqldata);
373
vary2 = (VARY2*) var->sqldata;
374
vary2->vary_string[vary2->vary_length] = '\0';
375
sprintf(p, "%-*s ", var->sqllen, vary2->vary_string);
388
value = (ISC_INT64) *(short *) var->sqldata;
392
value = (ISC_INT64) *(int *) var->sqldata;
396
value = (ISC_INT64) *(ISC_INT64 *) var->sqldata;
400
dscale = var->sqlscale;
407
for (i = 0; i > dscale; i--)
411
sprintf (p, "%*" ISC_INT64_FORMAT "d.%0*" ISC_INT64_FORMAT "d",
412
field_width - 1 + dscale,
413
(ISC_INT64) value / tens,
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),
421
(ISC_INT64) -(value % tens));
423
sprintf (p, "%*s.%0*" ISC_INT64_FORMAT "d",
424
field_width - 1 + dscale,
427
(ISC_INT64) -(value % tens));
430
sprintf (p, "%*" ISC_INT64_FORMAT "d%0*d",
435
sprintf (p, "%*" ISC_INT64_FORMAT "d%",
442
sprintf(p, "%15g ", *(float *) (var->sqldata));
446
sprintf(p, "%24f ", *(double *) (var->sqldata));
450
isc_decode_timestamp((ISC_TIMESTAMP *)var->sqldata, ×);
451
sprintf(date_s, "%04d-%02d-%02d %02d:%02d:%02d.%04d",
452
times.tm_year + 1900,
458
((ISC_TIMESTAMP *)var->sqldata)->timestamp_time % 10000);
459
sprintf(p, "%*s ", 24, date_s);
463
isc_decode_sql_date((ISC_DATE *)var->sqldata, ×);
464
sprintf(date_s, "%04d-%02d-%02d",
465
times.tm_year + 1900,
468
sprintf(p, "%*s ", 10, date_s);
472
isc_decode_sql_time((ISC_TIME *)var->sqldata, ×);
473
sprintf(date_s, "%02d:%02d:%02d.%04d",
477
(*((ISC_TIME *)var->sqldata)) % 10000);
478
sprintf(p, "%*s ", 13, date_s);
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);
503
* Prompt for and get input.
504
* Statements are terminated by a semicolon.
506
int get_statement (char *buf)
518
if ((c = getchar()) == EOF)
523
/* accept "quit" or "exit" to terminate application */
525
if (!strncmp(buf, "exit", 4))
527
if (!strncmp(buf, "quit", 4))
530
/* Search back through white space looking for ';'.*/
531
while (cnt && isspace(*(p - 1)))