home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 January / Chip_2001-01_cd1.bin / tema / interb / InterBase_WI-V6.0-server.exe / server / examples / api / apifull.c < prev    next >
C/C++ Source or Header  |  2000-06-23  |  14KB  |  549 lines

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