home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / SIOD 3.0 / sql_oracle.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-01  |  15.0 KB  |  509 lines  |  [TEXT/ttxt]

  1. /*****************************************************************************/
  2. /**                                                                         **/
  3. /**  Copyright (C) 1992-1994 BY                                             **/
  4. /**  MITECH CORPORATION, ACTON, MASSACHUSETTS.                              **/
  5. /**  ALL RIGHTS RESERVED.                                                   **/
  6. /**                                                                         **/
  7. /** Permission to use, copy, modify, distribute and sell this software      **/
  8. /** and its documentation for any purpose and without fee is hereby         **/
  9. /** granted, provided that the above copyright notice appear in all copies  **/
  10. /** and that both that copyright notice and this permission notice appear   **/
  11. /** in supporting documentation, and that the name of Mitech Corporation    **/
  12. /** not be used in advertising or publicity pertaining to distribution      **/
  13. /** of the software without specific, written prior permission.             **/
  14. /**                                                                         **/
  15. /** MITECH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING **/
  16. /** ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL**/
  17. /** MITECH BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR  **/
  18. /** ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,     **/
  19. /** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  **/
  20. /** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS     **/
  21. /** SOFTWARE.                                                               **/
  22. /**                                                                         **/
  23. /*****************************************************************************/
  24.  
  25. /* Interface from SIOD to Oracle Call Interface.
  26.    20-JAN-94 George Carrette. GJC@MITECH.COM
  27.  
  28.    This was developed some time ago using Oracle 6.0
  29.  
  30. Building: Compile siod.c with #define INIT_EXTRA init_sql_oracle. 
  31.           Linking is more complex as Oracle supplies specialized
  32.           script files. Under VMS it would look something like:
  33.  
  34. $ @ORA_RDBMS:LNOCIC SIOD.EXE SIOD.OBJ,SLIB.OBJ,SLIBA.OBJ,-
  35. TRACE.OBJ,SQL_ORACLE.OBJ "S"
  36.  
  37. TO DO: (1) Deal with parameters at LISP type level. The hairy
  38.            procedure prepare_statement can handle it already.
  39.        (2) allow more than one oracle login by encapsulating lda and hda
  40.            and passing them around.
  41.  
  42. */
  43.  
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #include <ctype.h>
  48. #include <math.h>
  49. #include <stdarg.h>
  50.  
  51. #include "siod.h"
  52.  
  53. #define tc_extra tc_user_4
  54. #define extra_tc_association 1
  55. #define extra_tc_statement 2
  56.  
  57. /* Oracle does not seem to provide any useful .h files for the
  58.    lda and cursor structures, nor for the data types or symbolic
  59.    error codes, nor procedure prototypes. All of which makes for a lot
  60.    of extra work and non-uniformity in the examples provided in the
  61.    Oracle documentation.
  62. */
  63.  
  64. struct lda_def
  65. {short v2_rc;
  66.  unsigned char fill1[10];
  67.  unsigned short rc;
  68.  unsigned char fill2[19];
  69.  unsigned int ose;
  70.  unsigned char chk;
  71.  unsigned char sysparm[26];};
  72.  
  73. struct cda_def
  74. {short v2_rc;
  75.  short ft;
  76.  unsigned long rpc;
  77.  short peo;
  78.  unsigned char fc;
  79.  unsigned char fill1;
  80.  unsigned short rc;
  81.  unsigned char wrn;
  82.  unsigned char flg;
  83.  unsigned int cn;
  84.  unsigned char rid[13];
  85.  unsigned int ose;
  86.  unsigned char chk;
  87.  unsigned char sysparm[26];};
  88.  
  89. struct hda_def
  90. {char fill[256];};
  91.  
  92. #define ORACLE_ETYPE_CHAR       1
  93. #define ORACLE_ITYPE_NUMBER     2
  94. #define ORACLE_ETYPE_INTEGER    3
  95. #define ORACLE_ETYPE_FLOAT      4
  96. #define ORACLE_ETYPE_STRING     5
  97. #define ORACLE_ETYPE_DECIMAL    7
  98. #define ORACLE_ETYPE_LONG       8
  99. #define ORACLE_ETYPE_VARCHAR    9
  100. #define ORACLE_ETYPE_ROWID     11
  101. #define ORACLE_ETYPE_DATE      12
  102. #define ORACLE_ETYPE_VARRAW    15
  103. #define ORACLE_ETYPE_RAW       23
  104. #define ORACLE_ETYPE_LONGRAW   24
  105. #define ORACLE_ETYPE_UINT      68
  106. #define ORACLE_ETYPE_DISPLAY   91
  107.  
  108. #define ORACLE_MAX_STRING 255
  109. #define ORA_MAX_SELECTS 20 /* this may be something I made up */
  110.  
  111. struct oracle_date
  112. {unsigned char century;
  113.  unsigned char year;
  114.  unsigned char month;
  115.  unsigned char day;
  116.  unsigned char hour;
  117.  unsigned char minute;
  118.  unsigned char second;};
  119.  
  120. #define ORA_NO_DATA_FOUND      1403
  121. #define ORA_VAR_NOT_IN_SELECT  1007
  122.  
  123. /* This code should be restructured to allocate lda and hda
  124.    in an association data structure returned by l_orlon */
  125.  
  126. static struct lda_def lda;
  127. static struct hda_def hda;
  128.  
  129. static long orlon_ok = 0;
  130.  
  131. static char *errmsg_str0 = NULL;
  132. static char *errmsg_str1 = NULL;
  133.  
  134. static long ncursors = 0;
  135.  
  136. struct param
  137. {short etype; 
  138.  short buflen;
  139.  char *buf;};
  140.  
  141. struct select
  142. {char *colnam;
  143.  short dbtype;
  144.  short dbsize;
  145.  short dsize;
  146.  short etype; 
  147.  short buflen;
  148.  char *buf;
  149.  short fetchlenstat;
  150.  short fetchlen;
  151.  short fetchcode;};
  152.  
  153. struct cstatement
  154. {struct cda_def *cursor;
  155.  long nparams;
  156.  struct param *params;
  157.  long nselects;
  158.  struct select *selects;};
  159.  
  160. static char *errmsg(long code)
  161. {char *ptr;
  162.  if (errmsg_str0 == NULL)
  163.    {errmsg_str0 = (char *) malloc(ORACLE_MAX_STRING+1);
  164.     memset(errmsg_str0,0,ORACLE_MAX_STRING+1);}
  165.  oerhms(&lda,code,errmsg_str0,ORACLE_MAX_STRING);
  166.  if (ptr = strchr(errmsg_str0,'\n')) *ptr = 0;
  167.  return(errmsg_str0);}
  168.  
  169. char *cda_errmsg(struct cda_def *cur)
  170. {return(errmsg(cur->rc));}
  171.  
  172. char *lda_errmsg()
  173. {return(errmsg(lda.rc));}
  174.  
  175. LISP ferr(LISP obj,char *format, ...)
  176. {va_list restargs;
  177.  if (errmsg_str1 == NULL)
  178.    {errmsg_str1 = (char *) malloc((ORACLE_MAX_STRING*3)+1);
  179.     memset(errmsg_str1,0,(ORACLE_MAX_STRING*3)+1);}
  180.  va_start(restargs,format);
  181.  vsprintf(errmsg_str1,format,restargs);
  182.  va_end(restargs);
  183.  err(errmsg_str1,obj);}
  184.  
  185. static LISP extcons(long length,long typec)
  186. {long flag;
  187.  LISP s;
  188.  flag = no_interrupt(1);
  189.  s = cons(NIL,NIL);
  190.  s->type = tc_extra;
  191.  s->storage_as.string.data = must_malloc(length);
  192.  s->storage_as.string.dim = typec;
  193.  memset(s->storage_as.string.data,0,length);
  194.  no_interrupt(flag);
  195.  return(s);}
  196.  
  197. struct cda_def *allocate_cursor(void)
  198. {struct cda_def *cur;
  199.  unsigned short rc;
  200.  cur = (struct cda_def *) malloc(sizeof(struct cda_def));
  201.  if (oopen(cur,&lda,NULL,-1,-1,NULL,-1))
  202.    {rc = cur->rc;
  203.     free(cur);
  204.     ferr(NIL,"%d cursors so far. oopen:\n%s",
  205.      ncursors,errmsg(rc));}
  206.  ++ncursors;
  207.  return(cur);}
  208.  
  209. void free_cursor(struct cda_def *cur)
  210. {long result;
  211.  unsigned short rc;
  212.  result = oclose(cur);
  213.  rc = cur->rc;
  214.  free(cur);
  215.  if (result) ferr(NIL,"oclose: %s",errmsg(rc));}
  216.  
  217. LISP l_orlon(LISP username,LISP password)
  218. {long retval,flag;
  219.  char *c_username,*c_password;
  220.  c_username = get_c_string(username);
  221.  c_password = NNULLP(password) ? get_c_string(password) : NULL;
  222.  if (orlon_ok)
  223.    /* calling orlon twice will corrupt your process badly. */
  224.    err("already completed orlon",NIL);
  225.  else
  226.    {flag = no_interrupt(1);
  227.     retval = orlon(&lda,&hda,
  228.            c_username,strlen(c_username),
  229.            c_password,(c_password) ? strlen(c_password) : -1,
  230.            0);
  231.     no_interrupt(flag);
  232.     if (lda.rc)
  233.       ferr(NIL,"orlon: %s",lda_errmsg());
  234.     else
  235.       orlon_ok = 1;}
  236.  return(NIL);}
  237.  
  238. LISP l_ologof(void)
  239. {long flag;
  240.  flag = no_interrupt(1);
  241.  if (orlon_ok)
  242.    {ologof(&lda);
  243.     if (lda.rc)
  244.       ferr(NIL,"orlon: %s",lda_errmsg());
  245.     else
  246.       orlon_ok = 0;}
  247.  no_interrupt(flag);
  248.  return(NIL);}
  249.  
  250. void freeloc(void ** x)
  251. {if (*x)
  252.    {free(*x);
  253.     *x = NULL;}}
  254.  
  255. void release_statement(struct cstatement *c)
  256. {long j;
  257.  if (c->nparams > 0)
  258.    {for(j = 1;j <= c->nparams;++j)
  259.       freeloc(&c->params[j-1].buf);
  260.     freeloc(&c->params);}
  261.  if (c->nselects > 0)
  262.    {for(j = 1; j <= c->nselects; ++j)
  263.       {freeloc(&c->selects[j-1].colnam);
  264.        freeloc(&c->selects[j-1].buf);}
  265.     freeloc(&c->selects);}
  266.  if (c->cursor)
  267.    free_cursor(c->cursor);
  268.  c->cursor = NULL;}
  269.  
  270. void prepare_statement(char *sql_str,struct cstatement *c)
  271.      /* assumptions:
  272.     nparams gives range of params from :1 to :nparams
  273.     the user may pre-initialize params with the etypes requested. 
  274.     nselects is correct or -1                                     */
  275. {long j,sflag = 0;
  276.  short colnamlen;
  277.  char colnam[ORACLE_MAX_STRING+1];
  278.  char *err;
  279.  c->cursor = allocate_cursor();
  280.  if (osql3(c->cursor,sql_str,-1))
  281.    {err = cda_errmsg(c->cursor);
  282.     free_cursor(c->cursor);
  283.     ferr(NIL,"osql3: %s",err);}
  284.  if (c->nparams)
  285.    {if (!c->params)
  286.       {c->params = (struct param *) malloc(sizeof(struct param) * c->nparams);
  287.        for(j = 1;j <= c->nparams;++j)
  288.      {c->params[j-1].etype = 0;
  289.       c->params[j-1].buf = NULL;}}
  290.     else
  291.       for(j = 1;j <= c->nparams;++j)
  292.     c->params[j-1].buf = NULL;
  293.     for(j = 1;j <= c->nparams;++j)
  294.       {switch(c->params[j-1].etype)
  295.      {case ORACLE_ETYPE_DATE:
  296.         c->params[j-1].buflen = sizeof(struct oracle_date);
  297.         c->params[j-1].buf = (char *) malloc(c->params[j-1].buflen);
  298.         break;
  299.       default:
  300.         c->params[j-1].etype = ORACLE_ETYPE_STRING;
  301.         c->params[j-1].buflen = ORACLE_MAX_STRING;
  302.         c->params[j-1].buf = (char *) malloc(c->params[j-1].buflen+1);}
  303.        if (obndrn(c->cursor,j,
  304.           c->params[j-1].buf,
  305.           (c->params[j-1].etype == ORACLE_ETYPE_STRING)
  306.           ? -1 : c->params[j-1].buflen,
  307.           c->params[j-1].etype,
  308.           -1,NULL,NULL,-1,-1))
  309.      {err = cda_errmsg(c->cursor);
  310.       release_statement(c);
  311.       ferr(NIL,"obndrn %d: %s",j,err);}}}
  312.  else
  313.    c->params = NULL;
  314.  if (c->nselects)
  315.    {if (c->nselects < 0)
  316.       {sflag = 1;
  317.        c->nselects = ORA_MAX_SELECTS;}
  318.     c->selects = (struct select *) malloc(sizeof(struct select) * c->nselects);
  319.     memset(c->selects,0,sizeof(struct select) * c->nselects);
  320.     for(j = 1; j <= c->nselects; ++j)
  321.       {colnamlen = ORACLE_MAX_STRING;
  322.        if (odsc(c->cursor,j,
  323.         &c->selects[j-1].dbsize,
  324.         NULL,NULL,
  325.         &c->selects[j-1].dbtype,
  326.         colnam,&colnamlen,
  327.         &c->selects[j-1].dsize))
  328.      {if ((!sflag) ||
  329.           (c->cursor->rc != ORA_VAR_NOT_IN_SELECT))
  330.         {err = cda_errmsg(c->cursor);
  331.          release_statement(c);
  332.          ferr(NIL,"odsc %d: %s",j,err);}
  333.       c->nselects = j-1;}
  334.        else
  335.      {colnam[colnamlen] = 0;
  336.       c->selects[j-1].colnam = (char *) malloc(colnamlen+1);
  337.       strcpy(c->selects[j-1].colnam,colnam);
  338.       switch(c->selects[j-1].dbtype)
  339.         {case ORACLE_ETYPE_INTEGER:
  340.          case ORACLE_ETYPE_FLOAT:
  341.          case ORACLE_ITYPE_NUMBER:
  342.            c->selects[j-1].etype = ORACLE_ETYPE_FLOAT;
  343.            c->selects[j-1].buflen = sizeof(double);
  344.            c->selects[j-1].buf = (double *) malloc(c->selects[j-1].buflen);
  345.            *((double *)c->selects[j-1].buf) = 0.0;
  346.            break;
  347.          case ORACLE_ETYPE_DATE:
  348.            /* If we let Oracle convert to string we loose the time info */
  349.            c->selects[j-1].etype = ORACLE_ETYPE_DATE;
  350.            c->selects[j-1].buflen = sizeof(struct oracle_date);
  351.            c->selects[j-1].buf = (char *) malloc(c->selects[j-1].buflen);
  352.            break;
  353.          default:
  354.            c->selects[j-1].etype = ORACLE_ETYPE_STRING;
  355.            c->selects[j-1].buflen =  ORACLE_MAX_STRING;
  356.            c->selects[j-1].buf = (char *) malloc(c->selects[j-1].buflen+1);
  357.            c->selects[j-1].buf[0] = 0;}
  358.       if (odefin(c->cursor,j,
  359.              c->selects[j-1].buf,c->selects[j-1].buflen,
  360.              c->selects[j-1].etype,
  361.              -1,
  362.              &c->selects[j-1].fetchlenstat,
  363.              NULL,-1,-1,
  364.              &c->selects[j-1].fetchlen,
  365.              &c->selects[j-1].fetchcode))
  366.         {err = cda_errmsg(c->cursor);
  367.          release_statement(c);
  368.          ferr(NIL,"odefin %d: %s",j,err);}}}
  369.     if (c->nselects == 0)
  370.       {free(c->selects);
  371.        c->selects = NULL;}}
  372.  else
  373.    c->selects = NULL;}
  374.  
  375. LISP oracle_sql_prepare(LISP str)
  376. {long iflag;
  377.  LISP result;
  378.  struct cstatement *c;
  379.  iflag = no_interrupt(1);
  380.  result = extcons(sizeof(struct cstatement),extra_tc_statement);
  381.  c = (struct cstatement *) result->storage_as.string.data;
  382.  c->nparams = 0;
  383.  c->nselects = -1;
  384.  prepare_statement(get_c_string(str),c);
  385.  no_interrupt(iflag);
  386.  return(result);}
  387.  
  388. static struct cstatement *get_cstatement(LISP st)
  389. {struct cstatement *c;
  390.  if ((TYPE(st) != tc_extra) ||
  391.      (st->storage_as.string.dim != extra_tc_statement))
  392.    err("not a statement",st);
  393.  c = (struct cstatement *)st->storage_as.string.data;
  394.  if (!c->cursor)
  395.    err("statement has been released",st);
  396.  return(c);}
  397.  
  398. LISP oracle_sql_release(LISP s)
  399. {long iflag;
  400.  iflag = no_interrupt(1);
  401.  release_statement(get_cstatement(s));
  402.  no_interrupt(iflag);
  403.  return(NIL);}
  404.  
  405. LISP oracle_execute(LISP s)
  406. {long iflag;
  407.  struct cstatement *c;
  408.  iflag = no_interrupt(1);
  409.  c = get_cstatement(s);
  410.  if (oexec(c->cursor))
  411.    ferr(s,"oexec: %s",cda_errmsg(c->cursor));
  412.  no_interrupt(iflag);
  413.  return(NIL);}
  414.  
  415. LISP oracle_nselects(LISP s)
  416. {return(flocons((get_cstatement(s))->nselects));}
  417.  
  418. LISP oracle_select_column_name(LISP s,LISP n)
  419. {long j;
  420.  struct cstatement *c;
  421.  j = get_c_long(n);
  422.  c = get_cstatement(s);
  423.  if ((j<0) || (j >= c->nselects))
  424.    err("column index out of range",n);
  425.  return(rintern(c->selects[j].colnam));}
  426.  
  427. char *oracle_date_to_string(struct oracle_date *d)
  428.      /* make it look like the string returned by RDB SQL Services */
  429. {static char buff[100];
  430.  sprintf(&buff,"%02d%02d%02d%02d%02d%02d%02d00",
  431.      d->century - 100,d->year - 100,
  432.      d->month,d->day,
  433.      d->hour-1,d->minute-1,d->second-1);
  434.  return(&buff);}
  435.  
  436. LISP oracle_select_column_value(LISP s,LISP n)
  437. {long j;
  438.  struct cstatement *c;
  439.  struct select *sel;
  440.  char *str;
  441.  j = get_c_long(n);
  442.  c = get_cstatement(s);
  443.  if ((j<0) || (j >= c->nselects))
  444.    err("column index out of range",n);
  445.  sel = &c->selects[j];
  446.  if (sel->fetchlenstat < 0)
  447.    return(NIL);
  448.  switch(sel->etype)
  449.    {case ORACLE_ETYPE_FLOAT:
  450.       return(flocons(*((double *)sel->buf)));
  451.     case ORACLE_ETYPE_DATE:
  452.       str = oracle_date_to_string(sel->buf);
  453.       return(strcons(strlen(str),str));
  454.     case ORACLE_ETYPE_STRING:
  455.       return(strcons(sel->fetchlen,sel->buf));
  456.     default:
  457.       return(errswitch());}}
  458.  
  459. LISP oracle_fetch(LISP s)
  460. {long iflag;
  461.  struct cstatement *c;
  462.  c = get_cstatement(s);
  463.  iflag = no_interrupt(1);
  464.  if (ofetch(c->cursor))
  465.    {if (c->cursor->rc == ORA_NO_DATA_FOUND)
  466.       {no_interrupt(iflag);
  467.        return(NIL);}
  468.     ferr(s,"fetch: %s",cda_errmsg(c->cursor));}
  469.  no_interrupt(iflag);
  470.  return(s);}
  471.  
  472. static void extra_gc_free(LISP ptr)
  473. {struct cstatement *c;
  474.  c = (struct cstatement *) ptr->storage_as.string.data;
  475.  release_statement(c);
  476.  free(c);}
  477.  
  478. static void extra_prin1(LISP ptr,FILE *f)
  479. {struct cstatement *c;
  480.  char buff[512];
  481.  switch(ptr->storage_as.string.dim)
  482.    {case extra_tc_statement:
  483.       c = (struct cstatement *) ptr->storage_as.string.data;
  484.       if (c->cursor)
  485.     sprintf(buff,"#{SQL STATEMENT %p cursor %d}",
  486.         c,c->cursor->cn);
  487.       else
  488.     sprintf(buff,"#{SQL STATEMENT %p released}",c);
  489.       fput_st(f,buff);
  490.       break;
  491.     default:
  492.       errswitch();}}
  493.  
  494. void init_sql_oracle(void)
  495. {long j;
  496.  set_gc_hooks(tc_extra,NULL,NULL,NULL,extra_gc_free,&j);
  497.  set_print_hooks(tc_extra,extra_prin1);
  498.  init_subr_2("oracle-login",l_orlon);
  499.  init_subr_0("oracle-logout",l_ologof);
  500.  init_subr_1("oracle-sql-prepare",oracle_sql_prepare);
  501.  init_subr_1("oracle-sql-release",oracle_sql_release);
  502.  init_subr_1("oracle-execute",oracle_execute);
  503.  init_subr_1("oracle-nselects",oracle_nselects);
  504.  init_subr_2("oracle-select-column-name",oracle_select_column_name);
  505.  init_subr_2("oracle-select-column-value",oracle_select_column_value);
  506.  init_subr_1("oracle-fetch",oracle_fetch);
  507.  printf("Enhancements (C) Copyright 1994 Mitech Corporation.\n");}
  508.  
  509.