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