home *** CD-ROM | disk | FTP | other *** search
/ PC World 1999 May / PCWorld_1999-05_cd.bin / software / Vyzkuste / inprise / INTRBASE_55 / EXAMPLES / API / APIFULL.C < prev    next >
C/C++ Source or Header  |  1998-10-18  |  12KB  |  435 lines

  1. /*
  2.  *    Program type:  API Interface
  3.  *
  4.  *    Description:
  5.  *    This program prompts for and executes unknown SQL statements.
  6.  */
  7.  
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <stdio.h>
  11. #include <time.h>
  12. #include <ctype.h>
  13. #include <ibase.h>
  14. #include "align.h"
  15. #include "example.h"
  16.  
  17. #define    MAXLEN    1024
  18.  
  19. process_statement PROTO((XSQLDA ISC_FAR * ISC_FAR * sqlda, char ISC_FAR *query));
  20. void print_column PROTO((XSQLVAR ISC_FAR * var));
  21. int get_statement PROTO((char ISC_FAR * buf));
  22.  
  23. typedef struct vary {
  24.     short          vary_length;
  25.     char           vary_string [1];
  26. } VARY;
  27.  
  28. isc_db_handle      db = NULL;
  29. isc_tr_handle      trans = NULL;
  30. isc_stmt_handle    stmt = NULL;
  31. long               status[20];
  32. int                ret;
  33.  
  34.  
  35. int main (ARG(int, argc), ARG(char **, argv))
  36. ARGLIST(int    argc)
  37. ARGLIST(char **argv)
  38. {
  39.     long                   query[MAXLEN];
  40.     XSQLDA    ISC_FAR *    sqlda;
  41.     char                   db_name[128];
  42.  
  43.     if (argc < 2)
  44.     {
  45.         printf("Enter the database name:  ");
  46.         gets(db_name);
  47.     }
  48.     else
  49.     {
  50.         strcpy(db_name, argv[1]);
  51.     }
  52.  
  53.     if (isc_attach_database(status, 0, db_name, &db, 0, NULL))
  54.     {
  55.         printf("Could not open database %s\n", db_name);
  56.         ERREXIT(status, 1);
  57.     }                      
  58.  
  59.     /* 
  60.     *    Allocate enough space for 20 fields.  
  61.     *    If more fields get selected, re-allocate SQLDA later.
  62.      */
  63.     sqlda = (XSQLDA ISC_FAR *) malloc(XSQLDA_LENGTH (20));
  64.     sqlda->sqln = 20;
  65.     sqlda->version = 1;
  66.  
  67.     /* Allocate a global statement */
  68.     if (isc_dsql_allocate_statement(status, &db, &stmt))
  69.     {
  70.         ERREXIT(status,1)
  71.     }
  72.  
  73.     /*
  74.      *    Process SQL statements.
  75.      */
  76.     ret = get_statement((char ISC_FAR *) query);
  77.     /* Use break on error or exit */
  78.     while (ret != 1)
  79.     {
  80.         /* We must pass the address of sqlda, in case it
  81.         ** gets re-allocated 
  82.         */
  83.         ret = process_statement((XSQLDA ISC_FAR * ISC_FAR *) &sqlda,
  84.                                 (char ISC_FAR *) query);
  85.             if (ret == 1)
  86.                 break;
  87.         ret = get_statement((char ISC_FAR *) query);
  88.     }
  89.     if (trans)
  90.         isc_commit_transaction(status, &trans);
  91.  
  92.     isc_detach_database(status, &db);
  93.     free(sqlda);
  94.  
  95.     return ret;
  96. }
  97.  
  98. /* 
  99. **  Function:  process_statement
  100. **  Process submitted statement.  On any fundamental error, return status 1,
  101. **  which will do an isc_print_status and exit the program.
  102. **  On user errors, found in parsing or executing go to status 2,
  103. **  which will print the error and continue.
  104. */
  105.  
  106. process_statement (ARG(XSQLDA ISC_FAR * ISC_FAR *, sqldap),
  107.                    ARG(char ISC_FAR *, query))
  108. ARGLIST(XSQLDA  **sqldap)
  109. ARGLIST(char    *query)
  110. {
  111.     long            buffer[MAXLEN];
  112.     XSQLDA  ISC_FAR *sqlda;
  113.     XSQLVAR ISC_FAR *var;
  114.     short           num_cols, i;
  115.     short           length, alignment, type, offset;
  116.     long            fetch_stat;
  117.     static char     stmt_info[] = { isc_info_sql_stmt_type };
  118.     char            info_buffer[20];
  119.     short           l;
  120.     long            statement_type;
  121.  
  122.     sqlda = *sqldap;
  123.  
  124.     /* Start a transaction if we are not in one */
  125.     if (!trans)
  126.         if (isc_start_transaction(status, &trans, 1, &db, 0, NULL))
  127.         {
  128.             /* Remove warning for Borland and Microsoft */
  129.             alignment = 0;
  130.             alignment = alignment;
  131.  
  132.             ERREXIT(status, 1)
  133.         }
  134.  
  135.     if (isc_dsql_prepare(status, &trans, &stmt, 0, query, 1, sqlda))
  136.     {
  137.         ERREXIT(status,2)
  138.     }
  139.  
  140.     /* What is the statement type of this statement? 
  141.     **
  142.     ** stmt_info is a 1 byte info request.  info_buffer is a buffer
  143.     ** large enough to hold the returned info packet
  144.     ** The info_buffer returned contains a isc_info_sql_stmt_type in the first byte, 
  145.     ** two bytes of length, and a statement_type token.
  146.     */
  147.     if (!isc_dsql_sql_info(status, &stmt, sizeof (stmt_info), stmt_info,
  148.         sizeof (info_buffer), info_buffer))
  149.     {
  150.         l = (short) isc_vax_integer((char ISC_FAR *) info_buffer + 1, 2);
  151.         statement_type = isc_vax_integer((char ISC_FAR *) info_buffer + 3, l);
  152.     }
  153.  
  154.  
  155.     /*
  156.      *    Execute a non-select statement.
  157.      */
  158.     if (!sqlda->sqld)
  159.     {
  160.         if (isc_dsql_execute(status, &trans, &stmt, 1, NULL))
  161.         {
  162.             ERREXIT(status,2)
  163.         }
  164.  
  165.         /* Commit DDL statements if that is what sql_info says */
  166.  
  167.         if (trans && (statement_type == isc_info_sql_stmt_ddl))
  168.         {
  169.             printf ("\tCommitting...\n");
  170.             if (isc_commit_transaction(status, &trans))
  171.             {
  172.                 ERREXIT(status, 2)
  173.             }    
  174.         }
  175.  
  176.         return 0;
  177.     }
  178.  
  179.     /*
  180.      *    Process select statements.
  181.      */
  182.  
  183.     num_cols = sqlda->sqld;
  184.  
  185.     /* Need more room. */
  186.     if (sqlda->sqln < num_cols)
  187.     {
  188.         *sqldap = sqlda = (XSQLDA ISC_FAR *) realloc(sqlda,
  189.                                                 XSQLDA_LENGTH (num_cols));
  190.         sqlda->sqln = num_cols;
  191.         sqlda->version = 1;
  192.  
  193.         if (isc_dsql_describe(status, &stmt, 1, sqlda))
  194.         {
  195.             ERREXIT(status,2)
  196.         }
  197.  
  198.         num_cols = sqlda->sqld;
  199.     }
  200.  
  201.     /*
  202.      *     Set up SQLDA.
  203.      */
  204.     for (var = sqlda->sqlvar, offset = 0, i = 0; i < num_cols; var++, i++)
  205.     {
  206.         length = alignment = var->sqllen;
  207.         type = var->sqltype & ~1;
  208.  
  209.         if (type == SQL_TEXT)
  210.             alignment = 1;
  211.         else if (type == SQL_VARYING)
  212.         {   
  213.             length += sizeof (short);
  214.             alignment = sizeof (short);
  215.         }
  216.         /*  RISC machines are finicky about word alignment
  217.         **  So the output buffer values must be placed on
  218.         **  word boundaries where appropriate
  219.         */
  220.         offset = ALIGN (offset, alignment);
  221.         var->sqldata = (char ISC_FAR *) buffer + offset;
  222.         offset += length;
  223.         offset = ALIGN (offset, sizeof (short));
  224.         var->sqlind = (short*) ((char ISC_FAR *) buffer + offset);
  225.         offset += sizeof  (short);
  226.     }
  227.  
  228.     if (isc_dsql_execute(status, &trans, &stmt, 1, NULL))
  229.     {
  230.         ERREXIT(status,2)
  231.     }
  232.  
  233.     /*
  234.      *    Print rows.
  235.      */
  236.  
  237.     while ((fetch_stat = isc_dsql_fetch(status, &stmt, 1, sqlda)) == 0)
  238.     {
  239.         for (i = 0; i < num_cols; i++)
  240.         {
  241.             print_column((XSQLVAR ISC_FAR *) &sqlda->sqlvar[i]);
  242.         }
  243.         printf("\n");
  244.     }
  245.  
  246.     /* Close cursor */
  247.     isc_dsql_free_statement(status, &stmt, DSQL_close);
  248.  
  249.     if (fetch_stat != 100L)
  250.     {
  251.         ERREXIT(status,2)
  252.     }
  253.  
  254.     return 0;
  255. }
  256.  
  257. /*
  258.  *    Print column's data.
  259.  */
  260. void print_column (ARG(XSQLVAR ISC_FAR *, var))
  261. ARGLIST(XSQLVAR    *var)
  262. {
  263.     short       dtype;
  264.     char        data[MAXLEN], *p;
  265.     char        blob_s[20], date_s[20];
  266.     VARY        *vary;
  267.     short       len; struct tm    times;
  268.     float       numeric;
  269.     short       factor, i;
  270.     ISC_QUAD    bid;
  271.  
  272.     dtype = var->sqltype & ~1;
  273.     p = data;
  274.  
  275.     /* Null handling.  If the column is nullable and null */
  276.     if ((var->sqltype & 1) && (*var->sqlind < 0))
  277.     {
  278.         switch (dtype)
  279.         {
  280.             case SQL_TEXT:
  281.             case SQL_VARYING:
  282.                 len = var->sqllen;
  283.                 break;
  284.             case SQL_SHORT:
  285.                 len = 6;
  286.                 break;
  287.             case SQL_LONG:
  288.                 len = 10;
  289.                 break;
  290.             case SQL_FLOAT:
  291.             case SQL_DOUBLE:
  292.                 len = 22;
  293.                 break;
  294.             case SQL_DATE:
  295.                 len = 10;
  296.                 break;
  297.             case SQL_BLOB:
  298.             case SQL_ARRAY:
  299.             default:
  300.                 len = 17;
  301.                 break;
  302.         }
  303.         if ((dtype == SQL_TEXT) || (dtype == SQL_VARYING))
  304.             sprintf(p, "%-*s ", len, "NULL");
  305.         else
  306.             sprintf(p, "%*s ", len, "NULL");
  307.     }
  308.     else
  309.     {
  310.         switch (dtype)
  311.         {
  312.             case SQL_TEXT:
  313.                 sprintf(p, "%.*s ", var->sqllen, var->sqldata);
  314.                 break;
  315.  
  316.             case SQL_VARYING:
  317.                 vary = (VARY*) var->sqldata;
  318.                 vary->vary_string[vary->vary_length] = '\0';
  319.                 sprintf(p, "%-*s ", var->sqllen, vary->vary_string);
  320.                 break;
  321.  
  322.             case SQL_SHORT:
  323.                 sprintf(p, "%6d ", *(short ISC_FAR *) (var->sqldata));
  324.                 break;
  325.  
  326.             case SQL_LONG:
  327.                 /* Numeric handling needs scale */
  328.                 if (var->sqlscale)
  329.                 {
  330.                     factor = 1;
  331.                     for (i = 1; i < -var->sqlscale; i++)
  332.                         factor *= 10;
  333.                     numeric = (float)*(long *) var->sqldata;
  334.                     numeric /= factor;
  335.                     sprintf(p, "%15.*f ", -var->sqlscale, 
  336.                         *(double ISC_FAR *) (var->sqldata));
  337.                 }
  338.                 else
  339.                     sprintf(p, "%10ld ", *(long ISC_FAR *) (var->sqldata));
  340.                 break;
  341.  
  342.             case SQL_FLOAT:
  343.                 sprintf(p, "%22f ", *(float ISC_FAR *) (var->sqldata));
  344.                 break;
  345.  
  346.             case SQL_DOUBLE:
  347.                 /* Detect numeric/decimal scale and handle format */
  348.                 if (var->sqlscale)
  349.                     sprintf(p, "%22.*f ", -var->sqlscale, 
  350.                         *(double ISC_FAR *) (var->sqldata));
  351.                 else
  352.                     sprintf(p, "%22f ", *(double ISC_FAR *) (var->sqldata));
  353.                 break;
  354.  
  355.             case SQL_DATE:
  356.                 isc_decode_date((ISC_QUAD ISC_FAR *) var->sqldata, ×);
  357.                 sprintf(date_s, "%2d/%d/%2d",
  358.                         times.tm_mday, times.tm_mon+1, times.tm_year);
  359.                 sprintf(p, "%*s ", 10, date_s);
  360.                 break;
  361.  
  362.             case SQL_BLOB:
  363.             case SQL_ARRAY:
  364.                 /* Print the blob id on blobs or arrays */
  365.                 bid = *(ISC_QUAD ISC_FAR *) var->sqldata;
  366.                 sprintf(blob_s, "%x:%x", bid.isc_quad_high, bid.isc_quad_low);
  367.                 sprintf(p, "%17s ", blob_s);
  368.                 break;
  369.  
  370.             default:
  371.                 break;
  372.         }
  373.     }
  374.  
  375.     while (*p)
  376.     {
  377.         putchar(*p++);
  378.     }
  379.     
  380. }
  381.  
  382.  
  383. /*
  384.  *    Prompt for and get input.
  385.  *    Statements are terminated by a semicolon.
  386.  */
  387. int get_statement (ARG(char ISC_FAR *,buf))
  388. ARGLIST(char *buf)
  389. {
  390.     short   c;
  391.     char    *p;
  392.     int     cnt;
  393.  
  394.     p = buf;
  395.     cnt = 0;
  396.     printf("SQL> ");
  397.  
  398.     for (;;)
  399.     {
  400.         if ((c = getchar()) == EOF)
  401.             return 1;
  402.  
  403.         if (c == '\n')
  404.         {
  405.             /* accept "quit" or "exit" to terminate application */
  406.  
  407.             if (!strncmp(buf, "exit", 4))
  408.                 return 1;
  409.             if (!strncmp(buf, "quit", 4))
  410.                 return 1;
  411.  
  412.             /* Search back through white space looking for ';'.*/
  413.             while (cnt && isspace(*(p - 1)))
  414.             {
  415.                 p--;
  416.                 cnt--;
  417.             }
  418.             if (*(p - 1) == ';')
  419.             {
  420.                 *p++ = '\0';
  421.  
  422.                 return 0;
  423.             }
  424.             *p++ = ' ';
  425.             printf("CON> ");
  426.         }
  427.         else
  428.         {
  429.             *p++ = (char)c;
  430.         }
  431.         cnt++;
  432.     }
  433. }
  434.  
  435.