home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #3 / NN_1993_3.iso / spool / alt / sources / 3076 < prev    next >
Encoding:
Text File  |  1993-01-27  |  76.0 KB  |  3,169 lines

  1. Xref: sparky alt.sources:3076 comp.databases:9353 comp.databases.ingres:2349
  2. Newsgroups: alt.sources,comp.databases,comp.databases.ingres
  3. From: raph@panache.demon.co.uk (Raphael Mankin)
  4. Path: sparky!uunet!pipex!demon!panache.demon.co.uk!raph
  5. Subject: Database unload utility
  6. Distribution: world
  7. Organization: Solvfield Ltd.
  8. Reply-To: raph@panache.demon.co.uk
  9. X-Mailer: Simple NEWS 1.90 (ka9q DIS 1.19)
  10. Lines: 3154
  11. Date: Sat, 23 Jan 1993 14:51:30 +0000
  12. Message-ID: <727800690snz@panache.demon.co.uk>
  13. Sender: usenet@demon.co.uk
  14.  
  15. This is the sources of two programs to unload an Oracle or Ingres database as
  16. an SQL stream.
  17.  
  18. Quite a few people have asked me for the programs. Some of the requestors I have
  19. been unable to respond to because of mangled mail headers and other glitches. I
  20. am therefore posting the sources here.
  21.  
  22.  
  23. --------------Cut here-----------------
  24. #!/bin/sh
  25. # to extract, remove the header and type "sh filename"
  26. if `test ! -d ./db_unload`
  27. then
  28.   mkdir ./db_unload
  29.   echo "mkdir ./db_unload"
  30. fi
  31. if `test ! -d ./db_unload/ORACLE`
  32. then
  33.   mkdir ./db_unload/ORACLE
  34.   echo "mkdir ./db_unload/ORACLE"
  35. fi
  36. if `test ! -s ./db_unload/ORACLE/MAKEFILE`
  37. then
  38. echo "writing ./db_unload/ORACLE/MAKEFILE"
  39. cat > ./db_unload/ORACLE/MAKEFILE << '\Rogue\Monster\'
  40. # When using AT&T C++ the following symbols are defined
  41. #    c_plusplus, __cplusplus, unix, sun
  42. # When using g++ the folllowing symbols are defined
  43. #    __GNUG__, __GNUC__, __cplusplus
  44. SUFFIXES:    .c .sc .pc .C .cc .pcc 
  45. # ------------The following for AT&T C++ ---
  46. # This program, although it compiles, will not run if you use the AT&T
  47. # compiler. It will crash as soon as it tries to connect to the DB.
  48. #SUFFIX    = C
  49. #G++    = CC 
  50. #CC    =/usr/5bin/cc
  51. #G++FLAGS= -sys5 -I. -g 
  52. #CFLAGS    = -I. -I/usr/5include -g 
  53. #LDFLAGS    = -Bstatic
  54.  
  55. #---- AT&T C++ with gcc as the back end. This one works
  56. #SUFFIX    = C
  57. #G++    = CC 
  58. #CC=gcc#/usr/5bin/cc
  59. #G++FLAGS= -sys5 -I. -g 
  60. #CFLAGS    = -I/home/pisces/ingres_conv/raph/lib/gcc-include -I. -I/usr/5include -g 
  61. #LDFLAGS    = -Bstatic
  62. #SQLLIB    = -L/usr/lang/SC1.0 -lC
  63.  
  64. #------------ The following for GNU g++
  65. SUFFIX    = cc
  66. G++    = g++
  67. CC    = gcc
  68. G++FLAGS= -I. -I/usr/local/include -g -O -w
  69. CFLAGS    = -I. -g -O 
  70. LDFLAGS    = -static
  71. #-------------------------------------
  72. GCC    = gcc
  73. PCC     = pcc
  74. DBNAME    = rob_dev
  75. USERID    = rob_dev/rob_dev
  76. ORACLE_INCLUDE =  $(ORACLE_HOME)/c/lib
  77. PCCFLAGS= include=$(ORACLE_INCLUDE) ireclen=511 oreclen=132 host=C\
  78.     maxopencursors=20 
  79. ORA_C_LIBDIR = $(ORACLE_HOME)/c/lib
  80. ORA_RDBMS_LIBDIR = $(ORACLE_HOME)/rdbms/lib
  81.  
  82. ORALIBS = $(ORA_RDBMS_LIBDIR)/libsql.a $(ORA_RDBMS_LIBDIR)/osntab.o \
  83. $(ORA_RDBMS_LIBDIR)/libsqlnet.a $(ORA_RDBMS_LIBDIR)/libora.a
  84.  
  85.  
  86. BINDIR=/home/pisces/ingres_conv/raph/bin
  87. SRC=\
  88.     makefile\
  89.     TODO\
  90.     data_dict.hpp\
  91.     c_data.pcc\
  92.     column.pcc\
  93.     dequote.c\
  94.     dereserve.c\
  95.     index.pcc\
  96.     table.pcc\
  97.     view.pcc
  98.  
  99. # Object files for the database conversion program
  100. DOBJ=\
  101.     c_data.o\
  102.     column.o\
  103.     dequote.o\
  104.     dereserve.o\
  105.     index.o\
  106.     table.o\
  107.     view.o
  108.  
  109.  
  110. YACC    = bison 
  111. YFLAGS    = -dvy
  112.  
  113. #.pcc.c:
  114. #    $(PCC) iname=$*.pcc oname=/tmp/$*.x.cc $(PCCFLAGS) 
  115. #    sed -e '/^# *[0-9]/d' -e '/struct  *sqlca/s//struct sql_ca/' \
  116. #    -e '/struct  *SQLDA/s//struct SQL_DA/' \
  117. #    -e '/extern  *sql.*();/d' < /tmp/$*.x.cc > /tmp/$*.${SUFFIX}
  118. #    $(G++) $(G++FLAGS) /tmp/$*.${SUFFIX} >$@
  119. pcc.o:
  120.     $(PCC) iname=$*.pcc oname=/tmp/$*.x.cc $(PCCFLAGS) 
  121.     sed -e '/^# *[0-9]/d' -e '/struct  *sqlca/s//struct sql_ca/' \
  122.     -e '/struct  *SQLDA/s//struct SQL_DA/' \
  123.     -e '/extern  *sql.*();/d' < /tmp/$*.x.cc > /tmp/$*.${SUFFIX}
  124.     $(G++) $(G++FLAGS) -c /tmp/$*.${SUFFIX}
  125.  
  126. cc.o:
  127.     $(G++) $(G++FLAGS) -c $*.${SUFFIX}
  128. #-------------------------------------------------------------------------
  129. # NOTE:   ORACLE_HOME must be either:
  130. #        . set in the user's environment
  131. #        . passed in on the command line
  132. #        . defined in a modified version of this makefile
  133. #
  134.  
  135.  
  136. OCILIB = #$(ORACLE_HOME)/c/lib/libocic.a
  137. #PCCLIBS = $(ORACLE_HOME)/rdbms/lib/libpcc.a $(SQLLIB) $(OCILIB)
  138. PCCLIBS = $(SQLLIB) $(OCILIB)
  139. STLIBS= $(ORACLE_HOME)/rdbms/lib/osntabst.o \
  140.     $(ORACLE_HOME)/rdbms/lib/config.o
  141.  
  142. all:    c_data 
  143.  
  144. c_data:    $(DOBJ)
  145.     $(G++) $(G++FLAGS) $(LDFLAGS) -o $@ $(DOBJ)\
  146.         -L/usr/5lib $(PCCLIBS) $(NETLIBS) $(ORALIBS) $(SQLLIB)
  147. pc.c:
  148.     $(PCC) $(PCCFLAGS) iname=$*.pc 
  149.  
  150. pc.o:
  151.     $(PCC) $(PCCFLAGS) iname=$*.pc oname=/tmp/$*.c
  152.     $(CC) $(CFLAGS) -c /tmp/$*.c
  153.  
  154. pc:
  155.     -$(PCC) iname=$*.pc oname=/tmp/$*.c $(PCCFLAGS) userid=$(USERID)
  156.     $(CC) $(CFLAGS) -o $* /tmp/$*.c -L/usr/5lib $(SQLLIB) $(NETLIBS) $(ORALIBS) $(OTHERLIBS)
  157. #
  158. #.c.exe:
  159. #    $(CC) $(CFLAGS) -o $* $*.c $(SQLLIB) $(OCILIB) $(NETLIBS) $(ORALIBS) $(OTHERLIBS)
  160. #
  161. #-------------------------------------------------------------------------
  162.  
  163. $(DOBJ):    data_dict.hpp
  164.  
  165. print:    $(SRC) 
  166.     pr -f $? |lpr
  167.     touch print
  168. printall:
  169.     pr -f $(SRC) | lpr
  170.     touch print
  171. clean:
  172.     rm -f *.o core *.lis
  173.  
  174. #-------------------------------------------------------
  175. sc.o:
  176.     esqlc -o.sh -l -f$*.c $<
  177.     $(CC) -c $(CFLAGS) $*.c
  178. sc.c:
  179.     esqlc -o.sh -l -f$*.c $<
  180.  
  181. test1:    test1.o
  182.     $(CC) -g -o $@ test1.o /usr/sun4/ingres/lib/libingres.a -lm
  183.  
  184. backup:    $(SRC) 
  185.     -mkdir /disk2/tmp/raph/vers6; chmod 777 /disk2/tmp/raph/vers6
  186.     -chmod u+w  /disk2/tmp/raph/vers6/*
  187.     cp $? /disk2/tmp/raph/vers6
  188.     -rm -f *.lis
  189.     touch backup
  190. dereserve.o dequote.o:    $$(@:.o=.c)
  191.     $(CC) -c $(CFLAGS) $(@:.o=.c)
  192. test:    c_data
  193.     c_data -d $(DBNAME)
  194. install:    c_data
  195.     install -s -c c_data $(BINDIR)
  196. C: $(DOBJ:.o=.c)
  197.  
  198. \Rogue\Monster\
  199. else
  200.   echo "will not over write ./db_unload/ORACLE/MAKEFILE"
  201. fi
  202. if `test ! -s ./db_unload/ORACLE/TODO`
  203. then
  204. echo "writing ./db_unload/ORACLE/TODO"
  205. cat > ./db_unload/ORACLE/TODO << '\Rogue\Monster\'
  206. \Rogue\Monster\
  207. else
  208.   echo "will not over write ./db_unload/ORACLE/TODO"
  209. fi
  210. if `test ! -s ./db_unload/ORACLE/DEQUOTE.C`
  211. then
  212. echo "writing ./db_unload/ORACLE/DEQUOTE.C"
  213. cat > ./db_unload/ORACLE/DEQUOTE.C << '\Rogue\Monster\'
  214. /*        DEQUOTE.C
  215.  
  216. This program was written by Raphael Mankin. (raph@panache.demon.co.uk)
  217.  
  218. */
  219. #ifdef SYSV
  220. #include <string.h>
  221. #define index   strchr
  222. #else
  223. #include <strings.h>
  224. #endif
  225.  
  226. /*
  227.     If s.arr contains embedded apostrophes, we have to replace each
  228.     one by a doubled apostrophe in order to keep Ingres happy.
  229.     This we do by counting the total number of apostophes and
  230.     shuffling data to the right by the number of apostrophes to
  231.     the left of each byte.
  232. */
  233.  
  234. dequote(s)
  235. struct varchar {
  236.     short    len;
  237.     char    arr[1];
  238. }    *s;
  239. {    int    i, j, len, count, count2;
  240.     char    *p;
  241.  
  242.     if (!(p=index(s->arr, '\'')))
  243.         return ;
  244.     count = 1;
  245.     while (p= index(p+1, '\''))
  246.         count++;
  247.     count2    = count;
  248.     for (i= s->len-1; count > 0; i--) {
  249.         if (s->arr[i] == '\'') {
  250.             s->arr[i+count] = s->arr[i];
  251.             count--;
  252.         }
  253.         s->arr[i+count] = s->arr[i];
  254.     }
  255.     s->len        += count2;
  256.     s->arr[s->len]    = 0;
  257.  
  258.     return ;
  259. }
  260. \Rogue\Monster\
  261. else
  262.   echo "will not over write ./db_unload/ORACLE/DEQUOTE.C"
  263. fi
  264. if `test ! -s ./db_unload/ORACLE/DERESERV.C`
  265. then
  266. echo "writing ./db_unload/ORACLE/DERESERV.C"
  267. cat > ./db_unload/ORACLE/DERESERV.C << '\Rogue\Monster\'
  268. /*        DERESERVE.C
  269.  
  270. This program was written by Raphael Mankin. (raph@panache.demon.co.uk)
  271.  
  272. CHANGES:
  273. 7/4/92    Change returned type from void to char*
  274.  
  275. */
  276.  
  277. #include <stdio.h>
  278. #ifndef __GNUG__    /* For AT&T compiler    */
  279. #define stricmp strcasecmp
  280. #include <strings.h>
  281. #else
  282. #include <string.h>
  283. #endif
  284.  
  285. static char *reserved[] = {
  286.             "command",
  287.             "count",
  288.             "default",
  289.             "file",
  290.             "index",
  291.             0
  292.         };
  293.  
  294. const char *dereserve(const char name[])
  295. {    int    i;
  296.     static char    buf[100];
  297.  
  298.     for (i=0; reserved[i]; i++) {
  299.         if (!stricmp(name, reserved[i])) {
  300.         strcpy(buf, name);
  301.         strcat(buf, "_x");
  302.         return buf;
  303.         }
  304.     }
  305.  
  306.     return name;
  307. }
  308. \Rogue\Monster\
  309. else
  310.   echo "will not over write ./db_unload/ORACLE/DERESERV.C"
  311. fi
  312. if `test ! -s ./db_unload/ORACLE/BOOL.H`
  313. then
  314. echo "writing ./db_unload/ORACLE/BOOL.H"
  315. cat > ./db_unload/ORACLE/BOOL.H << '\Rogue\Monster\'
  316. #ifndef _BOOL_
  317. #define _BOOL_
  318. enum bool {FALSE=0, TRUE=1};
  319. #endif
  320. \Rogue\Monster\
  321. else
  322.   echo "will not over write ./db_unload/ORACLE/BOOL.H"
  323. fi
  324. if `test ! -s ./db_unload/ORACLE/DATA_DIC.HPP`
  325. then
  326. echo "writing ./db_unload/ORACLE/DATA_DIC.HPP"
  327. cat > ./db_unload/ORACLE/DATA_DIC.HPP << '\Rogue\Monster\'
  328. /*        DATA_DICT.HPP
  329.  
  330.     Oracle Data Dictionary structures
  331.  
  332. This program was written by Raphael Mankin. (raph@panache.demon.co.uk)
  333.  
  334. */
  335.  
  336. #ifndef DATA_DICT_
  337. #include <stream.h>
  338. #include <bool.h>
  339.  
  340. #ifndef __GNUG__        /* For AT&T compiler    */
  341. extern "C" void exit(int);
  342. #define stricmp strcasecmp
  343. extern "C" char *strcpy(...);
  344. extern "C" int strcasecmp(...);
  345. extern "C" int strncmp(...);
  346. extern "C" char *strchr(...);
  347. extern "C" int strlen(...);
  348. #include <bstring.h>        /* for bzero()    */
  349. const char *dereserve(const char *);
  350. #else
  351. extern    "C" const char *dereserve(const char *);
  352. #endif
  353.  
  354. #define DATA_DICT_
  355. #define    NAME_LENGTH    33
  356.  
  357. class Table;
  358. class Index;
  359. class View;
  360. enum col_type { NUM, CHAR, DATE, FLOAT, MONEY};
  361.  
  362. class DatabaseObject {
  363.     char    object_name[NAME_LENGTH];
  364.     char    owner_name[NAME_LENGTH];
  365. public:
  366.     DatabaseObject(const char name[], const char owner[]);
  367.     const char    *name()        { return object_name;    }
  368.     const char    *owner()    { return owner_name;    }
  369. };
  370.  
  371. class    Column {
  372.     char    cname[NAME_LENGTH];
  373.     bool    nulls;            /* 'NULL' or 'NOT NULL' */
  374.     bool    WithDefault;
  375.     col_type     coltype;    // CHAR, NUMBER or DATE
  376.     int    colwidth;
  377.     Table    *parent;
  378.     Column    *next;
  379.     bool    IndexColumn;
  380. public:
  381.     const char *name();
  382.     Column *link();
  383.     int    width();
  384.     int    type();
  385.     Column(long  number, Table *up, Column *prev);
  386.     Column(long  number, View *up, Column *prev);
  387.     ~Column();
  388.     friend ostream& operator<<(ostream & s, Column & c);
  389.     void    set_index_col();
  390.     bool    is_index_column();
  391.     bool    non_null() {    return !nulls;    };
  392. };
  393.  
  394. class Table :public DatabaseObject {
  395.     Column    *cols;        // The column chain
  396.     Index    **index_list;    // The indexes on this table
  397.     int    IndexCount;    // sizeof(index_list)
  398.     bool    NoDuplicates;    // WITH NODUPLICATES clause
  399. public:
  400.     Table(const char name[], const char *owner="");
  401.     ~Table();
  402.     friend ostream& operator<<(ostream& s, Table & t);
  403.     void    extract(ostream &s);
  404.     Column    *column(const char cname[]);
  405.     void    SetNoDuplicates();
  406.     void    grant(ostream&);
  407. };
  408.  
  409. class View : public DatabaseObject {
  410.     char    *vtext;        // The view text
  411.     Column    *cols;        // The column chain
  412. public:
  413.     View();
  414.     View(const char [], const char *owner="");
  415.     ~View();
  416.     friend ostream& operator<<(ostream &s, View& v);
  417. };
  418.  
  419. enum index_type    { UNIQUE, NON_UNIQUE};
  420. enum index_order {ASC, DESC};
  421.  
  422. class Index : public DatabaseObject {
  423.     Table        *parent;
  424.     index_type    type;        // UNIQUE or non-unique
  425.     int        index_count;
  426.     struct index_field {
  427.         index_order    order;
  428.         char    *name;
  429.     }            *column_list;
  430. public:
  431.     Index();
  432.     Index(Table *t, char unique);
  433.     Index(Table *t, const char iname[]);
  434.     ~Index();
  435.     Index *link();
  436.     void modify(ostream& s);
  437.     friend ostream& operator<<(ostream &s, Index *ind);
  438.     bool    OK();
  439. };
  440.  
  441.  
  442. inline DatabaseObject::DatabaseObject(const char name[], const char user[])
  443. {    strcpy(object_name, name);
  444.     char *s = strchr(object_name, ' ');
  445.     if (s) *s = 0;
  446.     strcpy(owner_name, user);
  447.     s = strchr(owner_name, ' ');
  448.     if (s) *s = 0;
  449. }
  450.  
  451. inline Column::~Column()         { if(next) delete next; }
  452. inline const char *Column::name()    { return cname;        }
  453. inline Column *Column::link()        { return next;        }
  454. inline Column::type()            { return coltype;    }
  455. inline Column::width()            { return colwidth;    }
  456. //inline void Column::set_non_null()    { nulls    = FALSE;    }
  457. inline void Column::set_index_col()    { nulls    = FALSE; IndexColumn = TRUE;}
  458. inline bool Column::is_index_column()    { return IndexColumn;    }
  459.  
  460.  
  461. inline View::View() : DatabaseObject("", "")
  462. {    vtext    = 0;
  463.     cols    = 0;
  464. }
  465. inline View::~View()
  466. {
  467.     delete vtext;
  468.     if (cols) delete cols;
  469. }
  470.  
  471. inline Index::Index() : DatabaseObject ("", "")
  472. {
  473.     parent    = 0;
  474.     column_list=0;
  475. }
  476.  
  477. inline void Table::SetNoDuplicates()    { NoDuplicates = TRUE;    }
  478.  
  479. extern "C"    sqlab2(...);
  480. extern "C"    sqlad2(...);
  481. extern "C"    sqlbs2(...);
  482. extern "C"    sqlcls(...);
  483. extern "C"    sqlexe(...);
  484. extern "C"    sqlfcc(...);
  485. extern "C"    sqlfch(...);
  486. extern "C"    sqliem(...);
  487. extern "C"    sqllo2(unsigned long *, unsigned char *[], unsigned long [], unsigned short[], unsigned long *, int *, int *, unsigned long *);
  488. extern "C"    sqlopn(...);
  489. extern "C"    sqlosq(...);
  490. extern "C"    sqlsca(...);
  491. extern "C"    sqlscc(...);
  492. extern "C"    sqlsch(...);
  493. extern "C"    sqltfl(...);
  494. extern "C"    sqltoc(...);
  495. extern "C"    sqlos2(...);
  496. extern "C"    sqlclu(...);
  497. extern "C"    sqlgd2(...);
  498. extern "C"    void *sqlald(int, int, int);
  499. extern    "C" void dequote(void *);
  500. #ifdef INGRES
  501. #define    NOT_FOUND    100
  502. #else
  503. #define    NOT_FOUND    1403
  504. #endif
  505.  
  506. #ifndef EXTERN
  507. #define EXTERN extern
  508. #endif
  509. #define SQLCA_STORAGE_CLASS static
  510.  
  511. EXTERN char    *GoString;
  512. EXTERN bool    OracleOut;
  513. EXTERN bool    Default;
  514. EXTERN bool    NotNull;
  515. #endif
  516. \Rogue\Monster\
  517. else
  518.   echo "will not over write ./db_unload/ORACLE/DATA_DIC.HPP"
  519. fi
  520. if `test ! -s ./db_unload/ORACLE/COLUMN.PCC`
  521. then
  522. echo "writing ./db_unload/ORACLE/COLUMN.PCC"
  523. cat > ./db_unload/ORACLE/COLUMN.PCC << '\Rogue\Monster\'
  524. /*        COLUMN.PCC
  525.  
  526.  Process a column definition,  while converting a database table
  527.  from Oracle to Ingres.
  528.  
  529. This program was written by Raphael Mankin. (raph@panache.demon.co.uk)
  530.  
  531.  
  532. CHANGES:
  533. 7/4/92    Deresrve all names.
  534.  
  535. */
  536. #include <data_dict.hpp>
  537.  
  538. EXEC SQL INCLUDE SQLCA;
  539. EXEC SQL BEGIN DECLARE SECTION;
  540. static VARCHAR    sql_tname[31];
  541. static char
  542.     sql_cname[31],
  543.     sql_coltype[7],
  544.     sql_nulls[2],
  545.     sql_defaultval[1000];
  546. static long
  547.     sql_width,    /* Used for char types        */
  548.     sql_precision,    /* Used for numeric types    */
  549.     sql_scale,
  550.     sql_colno;
  551. EXEC SQL END DECLARE SECTION;
  552.  
  553. Column::Column(long    num, Table *up, Column *succ)
  554. {
  555.     next        = succ;
  556.     IndexColumn    = FALSE;
  557.     parent        = up;
  558.     sql_colno    = num;
  559.     strcpy(sql_tname.arr, up->name());
  560.     sql_tname.len    = strlen(sql_tname.arr);
  561.     EXEC SQL SELECT 
  562.             column_name,
  563.             data_type,
  564.             data_length,
  565.             data_precision,
  566.             data_scale,
  567.             nullable,
  568.             data_default
  569.          INTO    :sql_cname,
  570.             :sql_coltype,
  571.             :sql_width,
  572.             :sql_precision,
  573.             :sql_scale,
  574.             :sql_nulls,
  575.             :sql_defaultval
  576.          FROM accessible_columns
  577.          WHERE table_name = :sql_tname AND
  578.                column_id = :sql_colno;
  579.     if (sqlca.sqlcode) {
  580.         cerr << "Oracle select error " << sqlca.sqlcode << " in Column::Column(long, Table*, Column*)\n";
  581.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  582.         cerr << form("Table name: %s, column id %d\n",
  583.                 sql_tname.arr, sql_colno);
  584.         exit(1);
  585.     }
  586.     sql_cname[sizeof(sql_cname)-1]            = 0;
  587.     char    *s = strchr(sql_cname, ' ');
  588.     if (s)    *s = 0;
  589.     if (strlen(sql_cname) > 24) {
  590.        cerr << form("Column name '%s' exceeds 24 characters\n",
  591.             sql_cname);
  592.     }
  593.     sql_defaultval[sizeof(sql_defaultval)-1]    = 0;
  594.     sql_coltype[sizeof(sql_coltype)-1]        = 0;
  595.     sql_nulls[sizeof(sql_nulls)-1]            = 0;
  596.     strcpy(cname, sql_cname);
  597.     if (sql_nulls[0] == 'Y' && !NotNull)
  598.         nulls    = TRUE;
  599.     else
  600.         nulls    = FALSE;
  601.     if (!strncmp(sql_coltype, "NUM", 3))    coltype= NUM;
  602.     else if (!strncmp(sql_coltype, "DATE", 4)) coltype= DATE;
  603.     else                    coltype    = CHAR;
  604.     if (!strncmp(sql_coltype, "LONG", 4))
  605.         sql_width    = 1000;
  606.     if (coltype==NUM)
  607.         colwidth    = sql_precision;
  608.     else
  609.         colwidth    = sql_width;
  610. }
  611.  
  612. Column::Column(long    num, View *up, Column *succ)
  613. {
  614.     next        = succ;
  615.     IndexColumn    = FALSE;
  616.     parent        = (Table*)up;
  617.     sql_colno    = num;
  618.     strcpy(sql_tname.arr, up->name());
  619.     sql_tname.len    = strlen(sql_tname.arr);
  620.     EXEC SQL SELECT 
  621.             column_name
  622.          INTO    :sql_cname
  623.          FROM accessible_columns
  624.          WHERE table_name = :sql_tname AND
  625.                column_id = :sql_colno;
  626.     if (sqlca.sqlcode) {
  627.         cerr << "Oracle select error " << sqlca.sqlcode << " in Column::Column(long, View*, Column*)\n";
  628.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  629.         exit(1);
  630.     }
  631.     sql_cname[sizeof(sql_cname)-1]            = 0;
  632.     char    *s = strchr(sql_cname, ' ');
  633.     if (s)    *s = 0;
  634.     if (strlen(sql_cname) > 24) {
  635.        cerr << form("Column name '%s' exceeds 24 characters\n",
  636.             sql_cname);
  637.     }
  638.     strcpy(cname, sql_cname);
  639. }
  640.  
  641. ostream& operator<<(ostream& s, Column& c)
  642. {
  643.     s << form("\t%-.24s\t", dereserve(c.cname));
  644.     switch (c.coltype) {
  645.     case CHAR:
  646.         s << form("%s(%d)",
  647.             OracleOut?"VARCHAR":"VARCHAR",
  648.             c.colwidth);
  649.         break;
  650.     case NUM:
  651.         s << form(c.colwidth<3? "SMALLINT":
  652.                 c.colwidth< 5? "INTEGER2":
  653.                     "INTEGER");
  654.         break;
  655.     case DATE:
  656.         s << form("DATE");
  657.         break;
  658.     }
  659.     if (!c.nulls) {
  660.         s << " NOT NULL";
  661.         if (Default)
  662.             if (!c.IndexColumn)
  663.             s << " WITH DEFAULT";
  664.     }
  665.     return s;
  666. }
  667.  
  668. // Locate a column by name
  669. Column    *Table::column(const char cname[])
  670. {
  671.     for (Column *c = cols; c; c= c->link())
  672.         if (!stricmp(cname, c->name()))
  673.         return c;
  674.     return 0;
  675. }
  676. \Rogue\Monster\
  677. else
  678.   echo "will not over write ./db_unload/ORACLE/COLUMN.PCC"
  679. fi
  680. if `test ! -s ./db_unload/ORACLE/C_DATA.PCC`
  681. then
  682. echo "writing ./db_unload/ORACLE/C_DATA.PCC"
  683. cat > ./db_unload/ORACLE/C_DATA.PCC << '\Rogue\Monster\'
  684. /*        C_DATA
  685.  
  686.       Convert an Oracle database to an Ingres database.
  687.  
  688.     This program was written by Raphael Mankin. (raph@panache.demon.co.uk)
  689.  
  690. Options and arguments
  691.  
  692.     -d    convert the data as well as the structure
  693.     -g    generate GRANT commands on all tables and views
  694.     -n    generate NOT NULL on all columns
  695.     -v    generate WITH DEFAULT on all NOT NULL columns
  696.     -o    generate Oracle compatible output rather than
  697.         Ingres. i.e.
  698.             user ';' instead of '\p\g'
  699.             'create index' instead of 'modify'
  700.         The Ingres manuals always say 'varchar' but
  701.         the programs will not accept it.
  702.     db_name name of the DB to be processed. We assume that the 
  703.     -V    Views only
  704.         password is the same as the db-name.
  705. */
  706.  
  707. #define EXTERN
  708. EXEC SQL INCLUDE SQLCA;
  709. #include "data_dict.hpp"
  710. #include  <stream.h>
  711. #include <ctype.h>
  712. void affix(const char *filename);
  713.  
  714. EXEC SQL BEGIN DECLARE SECTION;
  715. VARCHAR db_name[21],        /* Database name        */
  716.     owner[31],    /* Pattern for matching owner    */
  717.     tabtype[8];        /* VIEW or TABLE        */
  718. char    tname[31],        /* Table or view name        */
  719.     uname[31];        /* Actual owner            */
  720. EXEC SQL END DECLARE SECTION;
  721.  
  722. main(int argc, char *argv[])
  723. {    bool    ConvertData    = FALSE,
  724.         Grant        = FALSE;
  725.     int    NumberOfTables    = 0;
  726.     bool    ViewsOnly    = FALSE;
  727.     int    stop;
  728.  
  729.     GoString    = "\\p\\g";
  730.     strcpy(owner.arr, "%");
  731.     owner.len    = strlen(owner.arr);
  732.     while (argc >1 && argv[1][0] == '-') {
  733.         for (int j=1; argv[1][j]; j++) {
  734.         switch(argv[1][j]) {
  735.         case 'd':
  736.             ConvertData = TRUE;
  737.             break;
  738.         case 'g':
  739.             Grant    = TRUE;
  740.             break;
  741.         case 'o':        // Oracle compatible output
  742.             OracleOut = TRUE;
  743.             GoString  = ";";
  744.             break;
  745.         case 'n':        // Force NOT NULL on all columns
  746.             NotNull    = TRUE;
  747.             break;
  748.         case 'u':            // Specify form owner
  749.             strcpy(owner.arr, argv[2]);
  750.             owner.len    = strlen(owner.arr);
  751.             argc--;
  752.             argv++;
  753.             break;
  754.         case 'v':        // Enable WITH DEFAULT
  755.             Default    = TRUE;
  756.             break;
  757.         case 'V':
  758.             ViewsOnly    = TRUE;
  759.             break;
  760.         default:
  761.             break;
  762.         }
  763.         }
  764.         argc--;
  765.         argv++;
  766.     }
  767.  
  768.     if (argc < 2) {
  769.         db_name.len = 4;
  770.         strcpy(db_name.arr, "pcms");
  771.     } else {
  772.         strcpy(db_name.arr, argv[1]);
  773.         db_name.len = strlen(argv[1]);
  774.     }
  775.     EXEC SQL CONNECT :db_name IDENTIFIED BY :db_name;
  776.     if (sqlca.sqlcode ) {
  777.         cerr << "Oracle connect error " << sqlca.sqlcode <<"\n";
  778.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  779.         exit(1);
  780.     }
  781.  
  782.     affix("prefix.sql");
  783.     if ( argc > 2) {    /* If user specified a list */
  784.         for (int i = 2; i < argc; i++) {
  785.         Table *t = new Table(argv[i]);
  786.         cout << *t;
  787.         if (ConvertData) {
  788.             t->extract(cout);
  789.         }
  790.         if (Grant)
  791.             t->grant(cout);
  792.         delete t;
  793.         }
  794.         affix("postfix.sql");
  795.         cout << form("commit%s\n", GoString);
  796.         exit(0);
  797.     } 
  798.     
  799. /*
  800.     Get all tables before all views
  801. */
  802.     if (!ViewsOnly) {
  803.     EXEC SQL DECLARE tb CURSOR FOR
  804.          SELECT DISTINCT 
  805.             table_name
  806.          FROM    user_tables
  807.          /*WHERE owner LIKE :owner*/
  808.          ORDER BY table_name;
  809.     EXEC SQL OPEN tb;
  810.     if (sqlca.sqlcode ) {
  811.         cerr << "Oracle 'tb' cursor open error " << sqlca.sqlcode << " in ::main()()\n";
  812.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  813.         exit(1);
  814.     }
  815.     for (stop=0; !stop; ) {
  816.         EXEC SQL FETCH tb
  817.              INTO :tname;
  818.         switch (sqlca.sqlcode) {
  819.         case 0:
  820.             tname[sizeof(tname)-1]    = 0;
  821.             Table *t = new Table(tname);
  822.             cout << *t;
  823.             if (ConvertData) {
  824.                 t->extract(cout);
  825.             }
  826.             if (Grant)
  827.                 t->grant(cout);
  828.             delete t;
  829.             break;
  830.         default:
  831.             cout << form("rollback%s\n", GoString);
  832.             cerr << "Oracle fetch error on 'tb' " << sqlca.sqlcode << " in ::main()\n";
  833.             cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  834.         case NOT_FOUND:
  835.             stop = 1;
  836.             break;
  837.         }
  838.         if (NumberOfTables++ > 20) {
  839.             cout << form("commit%s\n", GoString);
  840.             NumberOfTables    = 0;
  841.         }
  842.     }
  843.     EXEC SQL CLOSE tb;
  844.     }        // End !ViewsOnly
  845.  
  846.     EXEC SQL DECLARE vw CURSOR FOR
  847.          SELECT DISTINCT 
  848.             view_name
  849.          FROM    user_views
  850.          ORDER BY view_name;
  851.     EXEC SQL OPEN vw;
  852.     if (sqlca.sqlcode ) {
  853.         cerr << "Oracle 'vw' cursor open error " << sqlca.sqlcode << " in ::main()()\n";
  854.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  855.         exit(1);
  856.     }
  857.     for (stop=0; !stop; ) {
  858.         EXEC SQL FETCH vw
  859.              INTO :tname;
  860.         switch (sqlca.sqlcode) {
  861.         case 0:
  862.             tname[sizeof(tname)-1]    = 0;
  863.             View *v = new View(tname);
  864.             cout << *v;
  865.             delete v;
  866.             break;
  867.         default:
  868.             cout << form("rollback%s\n", GoString);
  869.             cerr << "Oracle fetch error on 'vw' " << sqlca.sqlcode << " in ::main()\n";
  870.             cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  871.         case NOT_FOUND:
  872.             stop = 1;
  873.             break;
  874.         }
  875.         if (NumberOfTables++ > 20) {
  876.             cout << form("commit%s\n", GoString);
  877.             NumberOfTables    = 0;
  878.         }
  879.     }
  880.     EXEC SQL CLOSE vw;
  881.  
  882.     cout << form("commit%s\n", GoString);
  883.  
  884.     affix("postfix.sql");
  885.     exit(0);
  886. }
  887.  
  888. void affix(const char *filename)
  889. {
  890. #ifdef __GNUG__
  891.     one_arg_error_handler_t old    =
  892.             set_File_error_handler(quiet_File_error_handler);
  893.     set_File_error_handler(old);
  894.     istream priv(filename, io_readonly, a_useonly);
  895. #else    
  896.     filebuf fb;
  897.     fb.open(filename, 1);
  898.     istream priv(&fb);
  899. #endif
  900.     char    privbuf[51];
  901.  
  902.     while (priv.rdstate() == _good) {
  903.         priv.getline(privbuf, sizeof privbuf);
  904.         cout << privbuf;
  905.     }
  906.     cout << form("\ncommit%s\n", GoString);
  907. }
  908. \Rogue\Monster\
  909. else
  910.   echo "will not over write ./db_unload/ORACLE/C_DATA.PCC"
  911. fi
  912. if `test ! -s ./db_unload/ORACLE/INDEX.PCC`
  913. then
  914. echo "writing ./db_unload/ORACLE/INDEX.PCC"
  915. cat > ./db_unload/ORACLE/INDEX.PCC << '\Rogue\Monster\'
  916. /*        INDEX.PCC
  917.  
  918.  
  919. This program was written by Raphael Mankin. (raph@panache.demon.co.uk)
  920.  
  921.     At version 6.0 all Oracle indexes are in ascending order
  922.     regardless of what the user requests.
  923. CHANGES:
  924. 7/4/92    Dereserve all names.
  925. */
  926. #include "data_dict.hpp"
  927. EXEC SQL INCLUDE SQLCA;
  928. EXEC SQL BEGIN DECLARE SECTION;
  929. static VARCHAR    sql_iname[31],
  930.         sql_tname[31],
  931.         sql_colname[31];
  932. static char    sql_itype[11],    /* UNIQUE or NON UNIQUE    */
  933.         sql_iorder[5];
  934. static int    sql_seq;
  935. EXEC SQL END DECLARE SECTION;
  936.  
  937. Index::Index(Table *up, const char iname[]) :
  938.             DatabaseObject(iname, "")
  939. {
  940.     parent        = up;
  941.     column_list    = 0;
  942.     if (strlen(name()) > 24) 
  943.        cerr << form("Index name '%s' exceeds 24 characters\n",
  944.             name());
  945.     strcpy(sql_iname.arr, name());
  946.     sql_iname.len    = strlen(name());
  947.     strcpy(sql_tname.arr, up->name());
  948.     sql_tname.len     = strlen(sql_tname.arr);
  949.  
  950.     EXEC SQL SELECT count(*)
  951.          INTO    :sql_seq
  952.          FROM    user_ind_columns
  953.          WHERE    index_name = :sql_iname AND
  954.             table_name = :sql_tname;
  955.     if (sqlca.sqlcode ) {
  956.         cerr << "Oracle select (count(*)) error " << sqlca.sqlcode << " in Index::Index(Table*, char[])\n";
  957.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  958.         exit(1);
  959.     }
  960.     EXEC SQL SELECT DISTINCT
  961.             LOWER(uniqueness)/* UNIQUE or NONUNIQUE */
  962.          INTO    :sql_itype
  963.          FROM    user_indexes
  964.          WHERE    index_name = :sql_iname AND
  965.              table_name = :sql_tname;
  966.     if (sqlca.sqlcode ) {
  967.         cerr << "Oracle select (index uniqueness) error " << sqlca.sqlcode << " in Index::Index(Table*, char[])\n";
  968.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  969.         exit(1);
  970.     }
  971.     index_count    = sql_seq;
  972.     column_list    = new struct index_field[index_count];
  973.     if (!strncmp(sql_itype, "unique", 6))
  974.         type = UNIQUE;
  975.     else
  976.         type = NON_UNIQUE;
  977.  
  978.     EXEC SQL DECLARE col CURSOR FOR
  979.         SELECT 
  980.             column_name,
  981.             column_position
  982.         FROM user_ind_columns
  983.         WHERE index_name = :sql_iname AND
  984.             table_name = :sql_tname
  985.         ORDER BY column_position;
  986.     EXEC SQL OPEN col;
  987.     if (sqlca.sqlcode ) {
  988.         cerr << "Oracle cursor open (col) error " << sqlca.sqlcode << " in Index::Index(Table*, char[])\n";
  989.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  990.         exit(1);
  991.     }
  992.  
  993.     for (int stop = 0; stop == 0; ) {
  994.         EXEC SQL FETCH col INTO
  995.             :sql_colname,
  996.             :sql_seq;
  997.         switch (sqlca.sqlcode) {
  998.         case 0:
  999.         column_list[sql_seq-1].name = new char [sql_colname.len+1];
  1000.         sql_colname.arr[sql_colname.len]    = 0;
  1001.         strcpy(column_list[sql_seq-1].name, sql_colname.arr);
  1002.         column_list[sql_seq-1].order        = ASC;
  1003.         break;
  1004.         default:
  1005.         cerr << "Oracle fetch (col) error " << sqlca.sqlcode << " in Index::Index(Table*, char[])\n";
  1006.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  1007.         case NOT_FOUND:
  1008.         stop = 1;
  1009.         break;
  1010.         }
  1011.     }
  1012.     EXEC SQL CLOSE col;
  1013.  
  1014. }
  1015.  
  1016. Index::~Index()
  1017. {
  1018.     if (!column_list) return;
  1019.     for (int i = 0; i < index_count; i++)
  1020.         delete column_list[i].name;
  1021.     delete column_list;
  1022. }
  1023.  
  1024. void Index::modify(ostream& s)
  1025. {
  1026.     s << form("modify %.24s to btree %s on ", 
  1027.         dereserve(parent->name()),
  1028.         type == UNIQUE ? "unique" : "");
  1029.     char *sep    = "\n\t";
  1030.     for (int i = 0; i < index_count; i++){
  1031.         s << form("%s%.24s%s",
  1032.         sep,
  1033.         dereserve(column_list[i].name),
  1034.         column_list[i].order == DESC ? " desc" : "");
  1035.         sep    = ",\n\t";
  1036.     }
  1037.     s << form("%s\n", GoString);
  1038. }
  1039.  
  1040. ostream& operator<<(ostream& s, Index *ind)
  1041. {
  1042.     s << form("create %sindex %.24s on %.24s (", 
  1043.         OracleOut && ind->type == UNIQUE ? "unique " : "",
  1044.         dereserve(ind->name()),
  1045.         dereserve(ind->parent->name()));
  1046.     char *sep    = "\n\t";
  1047.     for (int i = 0; i < ind->index_count; i++){
  1048.     s << form("%s%.24s%s", 
  1049.         sep, 
  1050.         dereserve(ind->column_list[i].name),
  1051.         OracleOut && ind->column_list[i].order == DESC ? " desc" : ""
  1052.         );
  1053.     sep    = ",\n\t";
  1054.     }
  1055.     s << form(")%s\n", GoString);
  1056.     return s;
  1057. }
  1058.  
  1059.  
  1060. bool Index::OK()
  1061. {    bool result = TRUE;
  1062.  
  1063. // Force all columns that are used in indexing to be NON NULL
  1064.  
  1065.     for (int i = 0; i < index_count; i++) {
  1066.         Column *c = parent -> column(column_list[i].name);
  1067.         if (!c) {
  1068.         cerr << form("Table %s index %s refers to non-existent column %s\n",
  1069.             parent->name(),
  1070.             name(),
  1071.             column_list[i].name);
  1072.         result = FALSE;
  1073.         } else {
  1074.         c->set_index_col();
  1075.         }
  1076.     }
  1077.  
  1078. // If the index is UNIQUE for the parent table to have WITH NODUPLICATES
  1079.  
  1080.     if (type == UNIQUE)
  1081.         parent->SetNoDuplicates();
  1082.  
  1083.     return result;
  1084. }
  1085. \Rogue\Monster\
  1086. else
  1087.   echo "will not over write ./db_unload/ORACLE/INDEX.PCC"
  1088. fi
  1089. if `test ! -s ./db_unload/ORACLE/TABLE.PCC`
  1090. then
  1091. echo "writing ./db_unload/ORACLE/TABLE.PCC"
  1092. cat > ./db_unload/ORACLE/TABLE.PCC << '\Rogue\Monster\'
  1093. /*        TABLE.PCC
  1094.  
  1095.    Build the representation of an Oracle table and all its indexes in
  1096.    memory. We can then output the appropriate SQL to reconstruct it in
  1097.    another database.
  1098.  
  1099.  
  1100. This program was written by Raphael Mankin. (raph@panache.demon.co.uk)
  1101.  
  1102. CHANGES:
  1103. 2/4/91    Restrict Index and table names to 24 characters.
  1104. 17/4/91    'With NoDuplicates' is not valid for Oracle output.
  1105. 7/4/92    Never generate 'With NoDuplicates', it is inefficient and busy
  1106.     nothing.
  1107.     Dereserve all names.
  1108. */
  1109. #include <data_dict.hpp>
  1110.  
  1111. EXEC SQL INCLUDE SQLCA;
  1112. EXEC SQL INCLUDE SQLDA;
  1113. static SQLDA    *fetchda;
  1114. EXEC SQL BEGIN DECLARE SECTION;
  1115. static VARCHAR    sql_tname[31],
  1116.         sql_iname[31];
  1117. static VARCHAR    sql_data[100][240];/**/
  1118. static short    sql_ind[100],/*    */
  1119.         sql_indcount;
  1120. static long    sql_colno;
  1121. EXEC SQL END DECLARE SECTION;
  1122. typedef struct {short len; char arr[1];}    VC;
  1123.  
  1124. Table::Table(const char tname[], const char *user) :
  1125.                 DatabaseObject(tname, user)
  1126. {
  1127.     cols         = 0;
  1128.     NoDuplicates    = FALSE;
  1129.     if (strlen(name()) > 24)
  1130.        cerr << form("Table name '%s' exceeds 24 characters\n",
  1131.             name());
  1132.     strcpy(sql_tname.arr, name());
  1133.     sql_tname.len    = strlen(name());
  1134.     EXEC SQL DECLARE col CURSOR FOR
  1135.          SELECT DISTINCT column_id
  1136.          FROM accessible_columns
  1137.          WHERE table_name = UPPER(:sql_tname)
  1138.          ORDER BY column_id DESC;
  1139.     EXEC SQL OPEN col;
  1140.     if (sqlca.sqlcode ) {
  1141.         cerr << "Oracle cursor open error " << sqlca.sqlcode << " in Table::Table(char name[])\n";
  1142.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  1143.         exit(1);
  1144.     }
  1145.     for (int stop = 0; !stop;) {
  1146.         EXEC SQL FETCH col
  1147.              INTO :sql_colno;
  1148.         switch (sqlca.sqlcode) {
  1149.         case 0:
  1150.             cols = new Column(sql_colno, this, cols);
  1151.             break;
  1152.         default:
  1153.             cerr << "Oracle fetch error " << sqlca.sqlcode << " in Table::Table(char name[])\n";
  1154.             cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  1155.         case NOT_FOUND:
  1156.             stop = 1;
  1157.         }
  1158.     }
  1159.     EXEC SQL CLOSE col;
  1160.  
  1161.     EXEC SQL SELECT count(*)
  1162.          INTO   :sql_indcount
  1163.          FROM    user_indexes
  1164.          WHERE    table_name = :sql_tname;
  1165.     if (sqlca.sqlcode ) {
  1166.         cerr << "Oracle select (count(*)) error " << sqlca.sqlcode << " in Table::Table(char name[])\n";
  1167.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  1168.         exit(1);
  1169.     }
  1170.     IndexCount    = 0;
  1171.     index_list    = new Index *[sql_indcount];
  1172.  
  1173.     EXEC SQL DECLARE ind CURSOR FOR
  1174.         SELECT DISTINCT index_name
  1175.                FROM user_indexes
  1176.                WHERE table_name = :sql_tname AND
  1177.                 index_name != :sql_tname
  1178.                ORDER by index_name ;
  1179.     EXEC SQL OPEN ind;
  1180.     if (sqlca.sqlcode ) {
  1181.         cerr << "Oracle cursor open (index) error " << sqlca.sqlcode << " in Table::Table()()\n";
  1182.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  1183.         exit(1);
  1184.     }
  1185.     for (stop=0; !stop; ) {
  1186.         EXEC SQL FETCH ind
  1187.              INTO :sql_iname;
  1188.         switch (sqlca.sqlcode) {
  1189.         case 0:
  1190.             sql_iname.arr[sql_iname.len]    = 0;
  1191.             Index *ind            =
  1192.             index_list[IndexCount++]    =
  1193.                 new Index(this, (char *)sql_iname.arr);
  1194.             ind->OK();
  1195.             break;
  1196.         default:
  1197.             cout << form("rollback%s\n", GoString);
  1198.             cerr << "Oracle fetch (index) error " << sqlca.sqlcode << " in Table::Table()\n";
  1199.             cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  1200.         case NOT_FOUND:
  1201.             stop = 1;
  1202.         }
  1203.     }
  1204.     EXEC SQL CLOSE ind;
  1205.  
  1206.  
  1207. }
  1208.  
  1209. Table::~Table()
  1210. {
  1211.     if (cols) delete cols;
  1212.     for (int i = 0; i < IndexCount; i++) {
  1213.         delete index_list[i];
  1214.         index_list[i]    = 0;
  1215.     }
  1216.     if (index_list)
  1217.         delete index_list;
  1218. }
  1219.  
  1220. ostream& operator<<(ostream& s, Table & t)
  1221. {
  1222.     s << form("drop table %-.24s%s\n", dereserve(t.name()), GoString);
  1223.     s << form("create table %-.24s(\n", dereserve(t.name()));
  1224.     for (Column *c = t.cols; c; c = c->link()) {
  1225.         s << *c;
  1226.         if (c->link()) 
  1227.             s << ",\n";
  1228.         else
  1229.             s << "\n";
  1230.     }
  1231.     s << form(")%s%s\n", 
  1232.         (0 && t.NoDuplicates && !OracleOut) ? " with noduplicates" : "",
  1233.         GoString);
  1234.     if (!OracleOut && t.IndexCount) {
  1235.     t.index_list[0]->modify(s);
  1236.     }
  1237.     for (int i=(OracleOut?0:1); i<t.IndexCount; i++) {
  1238.     s << t.index_list[i];
  1239.     }
  1240.     s.flush();
  1241.     return s;
  1242. }
  1243.  
  1244. void    Table::extract(ostream &s)
  1245. {    int    i;
  1246.     EXEC SQL BEGIN DECLARE SECTION;
  1247.     VARCHAR    selectbuf[5000];    /* Oracle SELECT statement    */
  1248.     EXEC SQL END DECLARE SECTION;
  1249.     char    insertbuf[5000];    /* Ingres INSERT statement    */
  1250.     bzero(selectbuf.arr, sizeof(selectbuf.arr));
  1251.     bzero(insertbuf, sizeof(insertbuf));
  1252.     ostream b(sizeof(selectbuf.arr), (char *)selectbuf.arr);
  1253.     ostream ins(sizeof(insertbuf), insertbuf);
  1254.  
  1255.     /*
  1256.     In selectbuf[] build a SELECT statement to use as a cursor to
  1257.     fetch the Oracle data rows from the table. Simultaneously, in
  1258.     insertbuf[] build the stem of an INSERT statement to insert
  1259.     the data into the output table. The actual data values will be
  1260.     added to the stem as each data row is fetched.
  1261.     */
  1262.     int field_count = 0;
  1263.     b << "SELECT ";
  1264.     ins << form("insert into %-.24s (\n", name());
  1265.     for (Column *c = cols; c; c= c->link()) {
  1266.         switch (c->type()) {
  1267.         case NUM:
  1268.             b << form("TO_CHAR(%s)%s ", 
  1269.                     c->name(), 
  1270.                     c->link() ? "," : "");
  1271.             break;
  1272.         case DATE:
  1273.         default:
  1274.             b << form("%s%s", c->name(), c->link() ? ", " : " ");
  1275.             break;
  1276.         }
  1277.         ins << form("\t%-.24s%s\n", c->name(), c->link() ? "," : "");
  1278.         field_count++;
  1279.     }
  1280.     ins << ") values (\n";
  1281.     b << form("FROM %s", name());
  1282.     b.flush();
  1283.     selectbuf.len    = strlen(selectbuf.arr);
  1284.     ins.flush();
  1285.  
  1286.     /*
  1287.     We have now built the text of the various SQL statements that
  1288.     we need. The next step is to tell Oracle about it and the
  1289.     target variables that we are going to use.
  1290.     */
  1291.     EXEC SQL PREPARE s1 FROM :selectbuf;
  1292.     if (sqlca.sqlcode ) {
  1293.         cerr << "Oracle PREPARE error " << sqlca.sqlcode << " for S1 in Table::extract(ostream &)\n";
  1294.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  1295.         cerr << form("Text is: '%s'\n", selectbuf.arr);
  1296.         s << form("rollback%s\n", GoString);
  1297.         exit(1);
  1298.     }
  1299.     EXEC SQL DECLARE cc CURSOR FOR s1;
  1300.  
  1301.     /*
  1302.     Allocate a sqlda for 'field_count' columns with 30-char names.
  1303.     This will be used to hold pointers to our work variables into
  1304.     which Oracle will store the data rows fetched from the table.
  1305.  
  1306.     */
  1307.     fetchda = (SQLDA*)sqlald(field_count, 30, 30);
  1308.     if (!fetchda) {
  1309.         cerr << form("Oracle error allocating sqlda\n");
  1310.         s << form("rollback%s\n", GoString);
  1311.         exit(1);
  1312.     }
  1313.     /*
  1314.     sql_data[][], declared above, can hold 100 data items each of
  1315.     up to 240 bytes. sql_ind[] are the corresponding 100 indicators.
  1316.     */
  1317.     i = 0;
  1318.     for (c = cols; c; c= c->link()) {
  1319.         fetchda->T[i] = 9;        
  1320.         fetchda->V[i] = (char *)&sql_data[i];
  1321.         fetchda->I[i] = &sql_ind[i];
  1322.         i++;
  1323.     }
  1324.  
  1325.     EXEC SQL OPEN cc;
  1326.     if (sqlca.sqlcode ) {
  1327.         cerr << "Oracle cursor open error " << sqlca.sqlcode << " in Table::extract(ostream &)\n";
  1328.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  1329.         exit(1);
  1330.     }
  1331.  
  1332.     EXEC SQL DESCRIBE SELECT LIST FOR s1 INTO fetchda;
  1333.     if (sqlca.sqlcode ) {
  1334.         cerr << "Oracle describe-select error " << sqlca.sqlcode << " in Table::extract(ostream &)\n";
  1335.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  1336.         exit(1);
  1337.     }
  1338.  
  1339.     i = 0;
  1340.     for (c = cols; c; c= c->link()) {
  1341.         fetchda->T[i] = 9;        /* VARCHAR    */
  1342.         switch (c->type()) {
  1343.         case DATE:
  1344.             fetchda->L[i] = 11;
  1345.             break;
  1346.         case CHAR:
  1347.             fetchda->L[i] = c->width()+2;
  1348.             break;
  1349.         case NUM:
  1350.         default:
  1351.             break;
  1352.         }
  1353. //        fetchda->V[i] = new char[fetchda->L[i]];
  1354. //        fetchda->I[i] = new short;
  1355.         i++;
  1356.     }
  1357.     if (fetchda->F < 0) {
  1358.         cerr << form("Oracle DESCRIBE error - %d fields allocated; %d fields found\n",
  1359.              field_count, fetchda->F);
  1360.         exit(1);
  1361.     }
  1362.     for (int stop = 0; !stop;) {
  1363.         EXEC SQL FETCH cc
  1364.              USING DESCRIPTOR fetchda;
  1365.         switch (sqlca.sqlcode) {
  1366.         case 0:
  1367.         s << insertbuf;
  1368.         int    i = 0;
  1369.         for (c=cols; c; c = c->link()) {
  1370.             if (*fetchda->I[i] < 0)  {    // If NULL value
  1371.             if (NotNull || c->non_null()) {    // Force NOT NULL
  1372.         cerr << form("Forcing non-null value for %s.%s\n", 
  1373.                 name(), c->name());
  1374.                 switch(c->type()) {
  1375.                 case NUM:
  1376.                 s << form("\t0%s\n",
  1377.                     c->link() ? "," : "");
  1378.                 break;
  1379.                 case CHAR:
  1380.                 case DATE:
  1381.                 default:
  1382.                 s << form("\t''%s\n",
  1383.                     c->link() ? "," : "");
  1384.                 break;
  1385.                 }
  1386.             } else {        // Honour NULLs
  1387.                 s << form("\tNULL%s\n",
  1388.                 c->link() ? "," : "");
  1389.             }
  1390.             } else if (*fetchda->I[i] > 0) {
  1391.             cerr << form("Table %s, field %s truncated from %d ch\n",
  1392.                name(), c->name(), *fetchda->I[i]);
  1393.             }
  1394.  
  1395.             if (*fetchda->I[i] >= 0) {
  1396.             switch(c->type()) {
  1397.             case NUM:
  1398.                 if (!((VC *)fetchda->V[i])->len) 
  1399.                 s << form("\t0%s\n",
  1400.                     c->link() ? "," : "");
  1401.                 else
  1402.                 s << form("\t%.*s%s\n",
  1403.                     ((VC *)fetchda->V[i])->len,
  1404.                     ((VC *)fetchda->V[i])->arr,
  1405.                     c->link() ? "," : "");
  1406.                 break;
  1407.             case CHAR:
  1408.                 dequote((VC*)fetchda->V[i]);
  1409.             case DATE:
  1410.             default:
  1411.                 s << form("\t'%*.*s'%s\n",
  1412.                     ((VC *)fetchda->V[i])->len,
  1413.                     ((VC *)fetchda->V[i])->len,
  1414.                     ((VC *)fetchda->V[i])->arr,
  1415.                     c->link() ? "," : "");
  1416.                 break;
  1417.             }
  1418.             }
  1419.             i++;
  1420.         }
  1421.         s << form(")%s\n", GoString);
  1422.         break;
  1423.         default:
  1424.             cerr << "Oracle fetch error " << sqlca.sqlcode << " in Table::extract(ostream&)\n";
  1425.             cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  1426.             cerr << form("Table name %s\n", name());
  1427.             s << form("rollback%s", GoString);
  1428.         case NOT_FOUND:
  1429.             stop = 1;
  1430.         }
  1431.     }
  1432.     EXEC SQL CLOSE cc;
  1433. #if 0
  1434.     for (i=0; i < fetchda->N; i++) {
  1435.         delete fetchda->V[i];
  1436.         delete fetchda->I[i];
  1437.     }
  1438. #endif
  1439.     sqlclu(fetchda);    // Release the SQLDA
  1440.     s.flush();
  1441. }
  1442.  
  1443. void    Table::grant(ostream &s)
  1444. {    for (Column *c = cols; c; c = c->link()) {
  1445.         if (!c->is_index_column())
  1446.         s << form("grant update(%.24s) on %.24s to public%s\n",
  1447.             dereserve(c->name()), dereserve(name()), GoString);
  1448.     }
  1449.     s << form("grant select on %.24s to public%s\n",
  1450.         dereserve(name()), GoString);
  1451.     s << form("grant delete on %.24s to public%s\n",
  1452.         dereserve(name()), GoString);
  1453.     s << form("grant insert on %.24s to public%s\n",
  1454.         dereserve(name()), GoString);
  1455. }
  1456. \Rogue\Monster\
  1457. else
  1458.   echo "will not over write ./db_unload/ORACLE/TABLE.PCC"
  1459. fi
  1460. if `test ! -s ./db_unload/ORACLE/VIEW.PCC`
  1461. then
  1462. echo "writing ./db_unload/ORACLE/VIEW.PCC"
  1463. cat > ./db_unload/ORACLE/VIEW.PCC << '\Rogue\Monster\'
  1464. /*        VIEW.PCC
  1465.  
  1466.  
  1467. This program was written by Raphael Mankin. (raph@panache.demon.co.uk)
  1468.  
  1469.  
  1470. CHANGES:
  1471. 7/4/92    Dereserve all names.
  1472.  
  1473. */
  1474.  
  1475. #include "data_dict.hpp"
  1476. EXEC SQL INCLUDE SQLCA;
  1477. EXEC SQL BEGIN DECLARE SECTION;
  1478. static VARCHAR    sql_name[31],
  1479.         sql_text[2000];
  1480. static long    sql_colno;
  1481. EXEC SQL END DECLARE SECTION;
  1482.  
  1483. View::View(const char vname[], const char *user) :
  1484.         DatabaseObject(vname, "")
  1485. {
  1486.     cols    = 0;
  1487.     strcpy(sql_name.arr, name());
  1488.     sql_name.len    = strlen(name());
  1489.     EXEC SQL SELECT text
  1490.          INTO :sql_text
  1491.          FROM user_views
  1492.          WHERE view_name = :sql_name;
  1493.     sql_text.arr[sql_text.len]    = 0;
  1494.     vtext                = new char[sql_text.len+1];
  1495.     strcpy(vtext, sql_text.arr);
  1496.     EXEC SQL DECLARE col CURSOR FOR
  1497.          SELECT DISTINCT column_id
  1498.          FROM accessible_columns
  1499.          WHERE table_name = UPPER(:sql_name)
  1500.          ORDER BY column_id DESC;
  1501.     EXEC SQL OPEN col;
  1502.     if (sqlca.sqlcode ) {
  1503.         cerr << "Oracle cursor open error " << sqlca.sqlcode << " in Table::Table(char name[])\n";
  1504.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  1505.         exit(1);
  1506.     }
  1507.     for (int stop = 0; !stop;) {
  1508.         EXEC SQL FETCH col
  1509.              INTO :sql_colno;
  1510.         switch (sqlca.sqlcode) {
  1511.         case 0:
  1512.             cols    = new Column(sql_colno, this, cols);
  1513.             break;
  1514.         default:
  1515.             cerr << "Oracle fetch error " << sqlca.sqlcode << " in View::View(char name[])\n";
  1516.             cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  1517.         case NOT_FOUND:
  1518.             stop    = 1;
  1519.         }
  1520.     }
  1521.     EXEC SQL CLOSE col;
  1522. }
  1523.  
  1524. ostream& operator<<(ostream& s,View& v)
  1525. {
  1526.     s << form("drop view %s%s\n", dereserve(v.name()), GoString);
  1527.     s << form("create view %-.24s (\n", dereserve(v.name())); 
  1528.     for (Column *c = v.cols; c; c = c->link()) {
  1529.         s << form("\t\t%-.24s", dereserve(c->name()));
  1530.         if (c->link()) 
  1531.             s << ",\n";
  1532.         else
  1533.             s << "\n";
  1534.     }
  1535.     s << form("\t) as\n%s%s\n", v.vtext, GoString);
  1536.     s.flush();
  1537.     return s;
  1538. }
  1539. \Rogue\Monster\
  1540. else
  1541.   echo "will not over write ./db_unload/ORACLE/VIEW.PCC"
  1542. fi
  1543. if `test ! -s ./db_unload/ORACLE/PREFIX.SQL`
  1544. then
  1545. echo "writing ./db_unload/ORACLE/PREFIX.SQL"
  1546. cat > ./db_unload/ORACLE/PREFIX.SQL << '\Rogue\Monster\'
  1547. set autocommit on;
  1548. \Rogue\Monster\
  1549. else
  1550.   echo "will not over write ./db_unload/ORACLE/PREFIX.SQL"
  1551. fi
  1552. if `test ! -d ./db_unload/INGRES`
  1553. then
  1554.   mkdir ./db_unload/INGRES
  1555.   echo "mkdir ./db_unload/INGRES"
  1556. fi
  1557. if `test ! -s ./db_unload/INGRES/C_DATA.SCC`
  1558. then
  1559. echo "writing ./db_unload/INGRES/C_DATA.SCC"
  1560. cat > ./db_unload/INGRES/C_DATA.SCC << '\Rogue\Monster\'
  1561. /*        C_DATA
  1562.  
  1563.       Convert an Ingres database to an SQL database.
  1564.  
  1565. This program was written by Raphael Mankin. (raph@panache.demon.co.uk)
  1566.  
  1567. Options and arguments
  1568.  
  1569.     -d    convert the data as well as the structure
  1570.     -g    generate GRANT commands on all tables and views
  1571.     -n    generate NOT NULL on all columns
  1572.     -v    generate WITH DEFAULT on all NOT NULL columns
  1573.     -o    generate Oracle compatible output rather than
  1574.         Ingres. i.e.
  1575.             user ';' instead of '\p\g'
  1576.             'create index' instead of 'modify'
  1577.             'vchar' is spellt 'varchar'. 
  1578.         The Ingres manuals always say 'varchar' but
  1579.         the programs will not accept it.
  1580.     -u name User who owns the tables etc to be converted
  1581.     db_name name of the DB to be processed. We assume that the 
  1582.     -V    Views only
  1583.         password is the same as the db-name.
  1584. */
  1585.  
  1586. #define EXTERN
  1587. EXEC SQL INCLUDE SQLCA;
  1588. #include "data_dict.hpp"
  1589. #include  <stream.h>
  1590. #include <ctype.h>
  1591.  
  1592. EXEC SQL BEGIN DECLARE SECTION;
  1593. static char    db_name[NAME_LENGTH],    /* Database name    */
  1594.         user[NAME_LENGTH],
  1595.         tabtype[8];        /* VIEW or TABLE    */
  1596. static char    tname[NAME_LENGTH];    /* Table or view name    */
  1597. EXEC SQL END DECLARE SECTION;
  1598.  
  1599. main(int argc, char *argv[])
  1600. {    bool    ConvertData    = FALSE,
  1601.         Grant        = FALSE;
  1602.     int    NumberOfTables    = 0;
  1603.     bool    ViewsOnly    = FALSE;
  1604.     int    stop;
  1605.  
  1606.     GoString    = "\\p\\g";
  1607.     strcpy(user, "%");
  1608.     while (argc >1 && argv[1][0] == '-') {
  1609.         for (int j=1; argv[1][j]; j++) {
  1610.         switch(argv[1][j]) {
  1611.         case 'd':
  1612.             ConvertData = TRUE;
  1613.             break;
  1614.         case 'g':
  1615.             Grant    = TRUE;
  1616.             break;
  1617.         case 'o':        // Oracle compatible output
  1618.             OracleOut = TRUE;
  1619.             GoString  = ";";
  1620.             break;
  1621.         case 'n':        // Force NOT NULL on all columns
  1622.             NotNull    = TRUE;
  1623.             break;
  1624.         case 'v':        // Enable WITH DEFAULT
  1625.             Default    = TRUE;
  1626.             break;
  1627.         case 'V':
  1628.             ViewsOnly    = TRUE;
  1629.             break;
  1630.         case 'u':        // User name
  1631.             strcpy(user, argv[2]);
  1632.             strcat(user, "%");
  1633.             argc--;
  1634.             argv++;
  1635.             break;
  1636.         default:
  1637.             break;
  1638.         }
  1639.         }
  1640.         argc--;
  1641.         argv++;
  1642.     }
  1643.  
  1644.     if (argc < 2) {
  1645.         strcpy(db_name, "raphdb");
  1646.     } else {
  1647.         strcpy(db_name, argv[1]);
  1648.     }
  1649.     EXEC SQL CONNECT :db_name ;
  1650.     if (sqlca.sqlcode ) {
  1651.         cerr << "Ingres connect error " << sqlca.sqlcode <<"\n";
  1652.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  1653.         exit(1);
  1654.     }
  1655.  
  1656. /*
  1657.     Get all tables before all views
  1658. */
  1659.     if (!ViewsOnly) {
  1660.     EXEC SQL DECLARE tb CURSOR FOR
  1661.          SELECT DISTINCT 
  1662.             table_name
  1663.          FROM    iitables
  1664.          WHERE table_owner LIKE :user and
  1665.             table_type LIKE 'T%' and
  1666.             system_use LIKE 'U%'
  1667.          ORDER BY table_name;
  1668.     EXEC SQL OPEN tb;
  1669.     if (sqlca.sqlcode ) {
  1670.         cerr << "Ingres 'tb' cursor open error " << sqlca.sqlcode << " in ::main()()\n";
  1671.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  1672.         exit(1);
  1673.     }
  1674.     for (stop=0; !stop; ) {
  1675.         EXEC SQL FETCH tb
  1676.              INTO :tname;
  1677.         switch (sqlca.sqlcode) {
  1678.         case 0:
  1679.             Table *t = new Table(tname, user);
  1680.             cout << *t;
  1681.             if (ConvertData) {
  1682.                 t->extract(cout);
  1683.             }
  1684.             if (Grant)
  1685.                 t->grant(cout);
  1686.             delete t;
  1687.             break;
  1688.         default:
  1689.             cout << form("rollback%s\n", GoString);
  1690.             cerr << "Ingres fetch error on 'tb' " << sqlca.sqlcode << " in ::main()\n";
  1691.             cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  1692.         case NOT_FOUND:
  1693.             stop = 1;
  1694.             break;
  1695.         }
  1696.         if (NumberOfTables++ > 20) {
  1697.             cout << form("commit%s\n", GoString);
  1698.             NumberOfTables    = 0;
  1699.         }
  1700.     }
  1701.     EXEC SQL CLOSE tb;
  1702.     }        // End !ViewsOnly
  1703.  
  1704.     EXEC SQL DECLARE vw CURSOR FOR
  1705.          SELECT DISTINCT 
  1706.             table_name
  1707.          FROM    iitables
  1708.          WHERE table_owner LIKE :user and
  1709.             table_type LIKE 'V%' and
  1710.             system_use LIKE 'U%'
  1711.          ORDER BY table_name;
  1712.     EXEC SQL OPEN vw;
  1713.     if (sqlca.sqlcode ) {
  1714.         cerr << "Ingres 'vw' cursor open error " << sqlca.sqlcode << " in ::main()()\n";
  1715.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  1716.         exit(1);
  1717.     }
  1718.     for (stop=0; !stop; ) {
  1719.         EXEC SQL FETCH vw
  1720.              INTO :tname;
  1721.         switch (sqlca.sqlcode) {
  1722.         case 0:
  1723.             View *v = new View(tname, user);
  1724.             cout << *v;
  1725.             delete v;
  1726.             break;
  1727.         default:
  1728.             cout << form("rollback%s\n", GoString);
  1729.             cerr << "Ingres fetch error on 'vw' " << sqlca.sqlcode << " in ::main()\n";
  1730.             cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  1731.         case NOT_FOUND:
  1732.             stop = 1;
  1733.             break;
  1734.         }
  1735.         if (NumberOfTables++ > 20) {
  1736.             cout << form("commit%s\n", GoString);
  1737.             NumberOfTables    = 0;
  1738.         }
  1739.     }
  1740.     EXEC SQL CLOSE vw;
  1741.  
  1742.     cout << form("commit%s\n", GoString);
  1743.  
  1744.     exit(0);
  1745. }
  1746. \Rogue\Monster\
  1747. else
  1748.   echo "will not over write ./db_unload/INGRES/C_DATA.SCC"
  1749. fi
  1750. if `test ! -s ./db_unload/INGRES/VIEW.SCC`
  1751. then
  1752. echo "writing ./db_unload/INGRES/VIEW.SCC"
  1753. cat > ./db_unload/INGRES/VIEW.SCC << '\Rogue\Monster\'
  1754. #include "data_dict.hpp"
  1755. EXEC SQL INCLUDE SQLCA;
  1756. EXEC SQL BEGIN DECLARE SECTION;
  1757. static char    sql_name[NAME_LENGTH],
  1758.         sql_text[257];
  1759. static long    sql_colno,
  1760.         sql_sequence;
  1761. static char    user[NAME_LENGTH];
  1762. EXEC SQL END DECLARE SECTION;
  1763.  
  1764. View::View(const char vname[], const char *vowner) :
  1765.             DatabaseObject(vname, vowner)
  1766. {
  1767.     cols    = 0;
  1768.     strcpy(sql_name, name());
  1769.     strcpy(user, owner());
  1770.     EXEC SQL DECLARE vv CURSOR FOR
  1771.          SELECT DISTINCT
  1772.             text_segment,
  1773.             text_sequence
  1774.          FROM iiviews
  1775.          WHERE table_name = :sql_name
  1776.          ORDER BY text_sequence;
  1777.     EXEC SQL OPEN vv;
  1778.     if (sqlca.sqlcode ) {
  1779.         cerr << "Ingres cursor 'vv' open error " << sqlca.sqlcode << " in View::View(char name[])\n";
  1780.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  1781.         exit(1);
  1782.     }
  1783.     char *s = new char[1];
  1784.     *s = 0;
  1785.     while (1) {
  1786.         EXEC SQL FETCH vv
  1787.          INTO :sql_text, :sql_sequence;
  1788.         if (sqlca.sqlcode == NOT_FOUND)
  1789.         break;
  1790.         s = realloc(s, strlen(s)+strlen(sql_text));
  1791.         strcat(s, sql_text);
  1792.     }
  1793.     EXEC SQL CLOSE vv;
  1794.     vtext    =  s;
  1795.  
  1796.     EXEC SQL DECLARE col CURSOR FOR
  1797.          SELECT DISTINCT column_sequence
  1798.          FROM iicolumns
  1799.          WHERE table_name = :sql_name AND
  1800.                table_owner LIKE :user 
  1801.          ORDER BY column_sequence DESC;
  1802.     EXEC SQL OPEN col;
  1803.     if (sqlca.sqlcode ) {
  1804.         cerr << "Ingres cursor 'col' open error " << sqlca.sqlcode << " in View::View(char name[])\n";
  1805.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  1806.         exit(1);
  1807.     }
  1808.     for (int stop = 0; !stop;) {
  1809.         EXEC SQL FETCH col
  1810.              INTO :sql_colno;
  1811.         switch (sqlca.sqlcode) {
  1812.         case 0:
  1813.             cols    = new Column(sql_colno, this, cols);
  1814.             break;
  1815.         default:
  1816.             cerr << "Ingres fetch error " << sqlca.sqlcode << " in View::View(char name[])\n";
  1817.             cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  1818.         case NOT_FOUND:
  1819.             stop    = 1;
  1820.         }
  1821.     }
  1822.     EXEC SQL CLOSE col;
  1823. }
  1824.  
  1825. ostream& operator<<(ostream& s,View& v)
  1826. {
  1827.     s << form("drop view %s%s\n", v.name(), GoString);
  1828. #if 0
  1829.     s << form("create view %s (\n", v.name()); 
  1830.     for (Column *c = v.cols; c; c = c->link()) {
  1831.         s << form("\t\t%s", c->name());
  1832.         if (c->link()) 
  1833.             s << ",\n";
  1834.         else
  1835.             s << "\n";
  1836.     }
  1837.     s << form("\t) as\n%s%s\n", v.vtext, GoString);
  1838. #else
  1839.     s << form("%s%s\n", v.vtext, GoString);
  1840. #endif
  1841.     s.flush();
  1842.     return s;
  1843. }
  1844. \Rogue\Monster\
  1845. else
  1846.   echo "will not over write ./db_unload/INGRES/VIEW.SCC"
  1847. fi
  1848. if `test ! -s ./db_unload/INGRES/DATA_DIC.HPP`
  1849. then
  1850. echo "writing ./db_unload/INGRES/DATA_DIC.HPP"
  1851. cat > ./db_unload/INGRES/DATA_DIC.HPP << '\Rogue\Monster\'
  1852. //        DATA_DICT.HPP
  1853.  
  1854. //    Oracle Data Dictionary structures
  1855.  
  1856. #ifndef DATA_DICT_
  1857. #include <stream.h>
  1858. #include <bool.h>
  1859. #define DATA_DICT_
  1860. #define    NAME_LENGTH    33
  1861.  
  1862. class Table;
  1863. class Index;
  1864. class View;
  1865. enum col_type { NUM, CHAR, DATE, FLOAT, MONEY};
  1866.  
  1867. class DatabaseObject {
  1868.     char    object_name[NAME_LENGTH];
  1869.     char    owner_name[NAME_LENGTH];
  1870. public:
  1871.     DatabaseObject(const char name[], const char owner[]);
  1872.     const char    *name()        { return object_name;    }
  1873.     const char    *owner()    { return owner_name;    }
  1874. };
  1875.  
  1876. class    Column {
  1877.     char    cname[NAME_LENGTH];
  1878.     bool    nulls;            /* 'NULL' or 'NOT NULL' */
  1879.     bool    WithDefault;
  1880.     col_type     coltype;    // CHAR, NUMBER or DATE
  1881.     int    colwidth;
  1882.     Table    *parent;
  1883.     Column    *next;
  1884. public:
  1885.     const char *name();
  1886.     bool    IndexColumn;
  1887.     Column *link();
  1888.     int    width();
  1889.     int    type();
  1890.     Column(long  number, Table *up, Column *prev);
  1891.     Column(long  number, View *up, Column *prev);
  1892.     ~Column();
  1893.     friend ostream& operator<<(ostream & s, Column & c);
  1894.     void    set_index_col();
  1895.     void    set_non_null();
  1896. };
  1897.  
  1898. class Table :public DatabaseObject {
  1899.     Column    *cols;        // The column chain
  1900.     Index    **index_list;    // The indexes on this table
  1901.     int    IndexCount;    // sizeof(index_list)
  1902.     bool    NoDuplicates;    // WITH NODUPLICATES clause
  1903. public:
  1904.     Table(const char name[], const char *owner="");
  1905.     ~Table();
  1906.     friend ostream& operator<<(ostream& s, Table & t);
  1907.     void    extract(ostream &s);
  1908.     Column    *column(const char cname[]);
  1909.     void    SetNoDuplicates();
  1910.     void    grant(ostream&);
  1911. };
  1912.  
  1913. class View : public DatabaseObject {
  1914.     char    *vtext;        // The view text
  1915.     Column    *cols;        // The column chain
  1916. public:
  1917.     View();
  1918.     View(const char [], const char *owner="");
  1919.     ~View();
  1920.     friend ostream& operator<<(ostream &s, View& v);
  1921. };
  1922.  
  1923. enum index_type    { UNIQUE, NON_UNIQUE};
  1924. enum index_order {ASC, DESC};
  1925.  
  1926. class Index : public DatabaseObject {
  1927.     Table        *parent;
  1928.     index_type    type;        // UNIQUE or non-unique
  1929.     int        index_count;
  1930.     struct index_field {
  1931.         index_order    order;
  1932.         char    *name;
  1933.     }            *column_list;
  1934. public:
  1935.     Index();
  1936.     Index(Table *t, char unique);
  1937.     Index(Table *t, const char iname[]);
  1938.     ~Index();
  1939.     Index *link();
  1940.     void modify(ostream& s);
  1941.     friend ostream& operator<<(ostream &s, Index *ind);
  1942.     bool    OK();
  1943. };
  1944.  
  1945.  
  1946. inline DatabaseObject::DatabaseObject(const char name[], const char user[])
  1947. {    strcpy(object_name, name);
  1948.     char *s = strchr(object_name, ' ');
  1949.     if (s) *s = 0;
  1950.     strcpy(owner_name, user);
  1951.     s = strchr(owner_name, ' ');
  1952.     if (s) *s = 0;
  1953. }
  1954.  
  1955. inline Column::~Column()         { if(next) delete next; }
  1956. inline const char *Column::name()    { return cname;        }
  1957. inline Column *Column::link()        { return next;        }
  1958. inline Column::type()            { return coltype;    }
  1959. inline Column::width()            { return colwidth;    }
  1960. inline void Column::set_non_null()    { nulls    = FALSE;    }
  1961. inline void Column::set_index_col()    { nulls    = FALSE; IndexColumn = TRUE;}
  1962.  
  1963.  
  1964. inline View::View() : DatabaseObject("", "")
  1965. {    vtext    = 0;
  1966.     cols    = 0;
  1967. }
  1968. inline View::~View()
  1969. {
  1970.     delete vtext;
  1971.     if (cols) delete cols;
  1972. }
  1973.  
  1974. inline Index::Index() : DatabaseObject ("", "")
  1975. {
  1976.     parent    = 0;
  1977.     column_list=0;
  1978. }
  1979.  
  1980. inline void Table::SetNoDuplicates()    { NoDuplicates = TRUE;    }
  1981.  
  1982. extern "C"    sqlab2(...);
  1983. extern "C"    sqlad2(...);
  1984. extern "C"    sqlbs2(...);
  1985. extern "C"    sqlcls(...);
  1986. extern "C"    sqlexe(...);
  1987. extern "C"    sqlfcc(...);
  1988. extern "C"    sqlfch(...);
  1989. extern "C"    sqliem(...);
  1990. extern "C"    sqllo2(...);
  1991. extern "C"    sqlopn(...);
  1992. extern "C"    sqlosq(...);
  1993. extern "C"    sqlsca(...);
  1994. extern "C"    sqlscc(...);
  1995. extern "C"    sqlsch(...);
  1996. extern "C"    sqltfl(...);
  1997. extern "C"    sqltoc(...);
  1998. extern "C"    sqlos2(...);
  1999. extern "C"    sqlclu(...);
  2000. extern "C"    sqlgd2(...);
  2001. extern "C"    void *sqlald(int, int, int);
  2002. extern    "C" void dequote(void *);
  2003. #ifdef INGRES
  2004. #define    NOT_FOUND    100
  2005. #else
  2006. #define    NOT_FOUND    1403
  2007. #endif
  2008.  
  2009. #ifndef EXTERN
  2010. #define EXTERN extern
  2011. #endif
  2012.  
  2013. EXTERN char    *GoString;
  2014. EXTERN bool    OracleOut;
  2015. EXTERN bool    Default;
  2016. EXTERN bool    NotNull;
  2017. #endif
  2018. \Rogue\Monster\
  2019. else
  2020.   echo "will not over write ./db_unload/INGRES/DATA_DIC.HPP"
  2021. fi
  2022. if `test ! -s ./db_unload/INGRES/MAKEFILE`
  2023. then
  2024. echo "writing ./db_unload/INGRES/MAKEFILE"
  2025. cat > ./db_unload/INGRES/MAKEFILE << '\Rogue\Monster\'
  2026. SUFFIXES:    .c .sc .pc .cc .scc .pcc 
  2027. G++    = g++
  2028. CC    = gcc
  2029. G++FLAGS= -I.. -I/usr/local/include -g -O -w -DINGRES
  2030. CFLAGS    = -I.. -g -O 
  2031. LDFLAGS    = -static
  2032. GCC    = gcc
  2033. PCC     = pcc
  2034. DBNAME    = test
  2035. USERID    = comp/comp
  2036. PCCFLAGS= include=$(ORACLE_INCLUDE) ireclen=511 oreclen=132 host=C\
  2037.     maxopencursors=20 # sqlcheck=limited userid=pcms/pcms 
  2038.  
  2039. SRC=\
  2040.     makefile\
  2041.     ../data_dict.hpp\
  2042.     c_data.scc\
  2043.     column.scc\
  2044.     index.scc\
  2045.     table.scc\
  2046.     view.scc
  2047.  
  2048. # Object files for the database conversion program
  2049. DOBJ=\
  2050.     c_data.o\
  2051.     column.o\
  2052.     dequote.o\
  2053.     index.o\
  2054.     table.o\
  2055.     view.o
  2056.  
  2057.  
  2058. YACC    = bison 
  2059. YFLAGS    = -dvy
  2060.  
  2061. pcc.o:
  2062.     $(PCC) iname=$*.pcc oname=/tmp/$*.x.cc $(PCCFLAGS) 
  2063.     sed -e '/^# *[0-9]/d' -e '/struct  *sqlca/s//struct sql_ca/' \
  2064.     -e '/struct  *SQLDA/s//struct SQL_DA/' \
  2065.     -e '/extern  *sql.*();/d' < /tmp/$*.x.cc > /tmp/$*.cc
  2066.     $(G++) $(G++FLAGS) -c /tmp/$*.cc
  2067.  
  2068. cc.o:
  2069.     $(G++) $(G++FLAGS) -c $*.cc
  2070. #-------------------------------------------------------------------------
  2071. # NOTE:   ORACLE_HOME must be either:
  2072. #        . set in the user's environment
  2073. #        . passed in on the command line
  2074. #        . defined in a modified version of this makefile
  2075. #
  2076.  
  2077. #CC=/usr/5bin/cc
  2078.  
  2079. OCILIB = #$(ORACLE_HOME)/c/lib/libocic.a
  2080. #PCCLIBS = $(ORACLE_HOME)/rdbms/lib/libpcc.a $(SQLLIB) $(OCILIB)
  2081. PCCLIBS = $(SQLLIB) $(OCILIB)
  2082. STLIBS= $(ORACLE_HOME)/rdbms/lib/osntabst.o \
  2083.     $(ORACLE_HOME)/rdbms/lib/config.o
  2084.  
  2085. all:    c_data 
  2086.  
  2087. c_data:    $(DOBJ)
  2088.     $(G++) $(G++FLAGS) $(LDFLAGS) -o $@ $(DOBJ)\
  2089.         -L/usr/5lib $(II_SYSTEM)/ingres/lib/libingres.a -lm
  2090. pc.c:
  2091.     $(PCC) $(PCCFLAGS) iname=$*.pc 
  2092.  
  2093. pc.o:
  2094.     $(PCC) $(PCCFLAGS) iname=$*.pc oname=/tmp/$*.c
  2095.     $(CC) $(CFLAGS) -c /tmp/$*.c
  2096.  
  2097. pc:
  2098.     -$(PCC) iname=$*.pc oname=/tmp/$*.c $(PCCFLAGS) userid=$(USERID)
  2099.     $(CC) $(CFLAGS) -o $* /tmp/$*.c -L/usr/5lib $(SQLLIB) $(NETLIBS) $(ORALIBS) $(OTHERLIBS)
  2100. #
  2101. #.c.exe:
  2102. #    $(CC) $(CFLAGS) -o $* $*.c $(SQLLIB) $(OCILIB) $(NETLIBS) $(ORALIBS) $(OTHERLIBS)
  2103. #
  2104. #-------------------------------------------------------------------------
  2105.  
  2106. $(DOBJ):    ../data_dict.hpp
  2107.  
  2108. print:    $(SRC) 
  2109.     pr -f $? |lpr
  2110.     touch print
  2111. printall:
  2112.     pr -f $(SRC) | lpr
  2113.     touch print
  2114. safe:
  2115.     -chmod a-w $(SRC)
  2116. clean:
  2117.     rm -f *.o core *.lis
  2118.  
  2119. #-------------------------------------------------------
  2120. scc.o:
  2121.     cp $< /tmp/$*.cc
  2122.     $(G++) $(G++FLAGS) -E /tmp/$*.cc > /tmp/$*.sc
  2123.     esqlc -o.sh -f/tmp/$*.cc /tmp/$*.sc
  2124.     $(G++) -c $(G++FLAGS) /tmp/$*.cc
  2125. scc.cc:
  2126.     cp $< /tmp/$*.cc
  2127.     $(G++) $(G++FLAGS) -E /tmp/$*.cc > /tmp/$*.sc
  2128.     esqlc -o.sh -f$*.cc /tmp/$*.sc
  2129. sc.o:
  2130.     esqlc -o.sh -f/tmp/$*.c $<
  2131.     $(CC) -c $(CFLAGS) /tmp/$*.c
  2132. sc.c:
  2133.     esqlc -o.sh -f$*.c $<
  2134.  
  2135. test1:    test1.o
  2136.     gcc -g -o $@ test1.o /usr/sun4/ingres/lib/libingres.a -lm
  2137.  
  2138. backup:    $(SRC) 
  2139.     -mkdir /common/tmp/raph/ingdata; chmod 777 /common/tmp/raph/ingdata
  2140.     cp $? /common/tmp/raph/ingdata
  2141.     -rm -f *.lis
  2142.     touch backup
  2143.     -$(MAKE) safe
  2144. dequote.o:    ../dequote.c
  2145.     $(CC) -c $(CFLAGS) ../dequote.c
  2146. test:    c_data
  2147.     c_data -d $(DBNAME)
  2148. \Rogue\Monster\
  2149. else
  2150.   echo "will not over write ./db_unload/INGRES/MAKEFILE"
  2151. fi
  2152. if `test ! -s ./db_unload/INGRES/INDEX.SCC`
  2153. then
  2154. echo "writing ./db_unload/INGRES/INDEX.SCC"
  2155. cat > ./db_unload/INGRES/INDEX.SCC << '\Rogue\Monster\'
  2156. /*        INDEX.SCC
  2157.  
  2158. This program was written by Raphael Mankin. (raph@panache.demon.co.uk)
  2159. */
  2160. #include "data_dict.hpp"
  2161. #include <assert.h>
  2162. EXEC SQL INCLUDE SQLCA;
  2163. EXEC SQL BEGIN DECLARE SECTION;
  2164. static char    sql_iname[NAME_LENGTH],
  2165.         sql_tname[NAME_LENGTH],
  2166.         sql_colname[NAME_LENGTH];
  2167. static char    sql_itype[9],    /* UNIQUE or NON UNIQUE    */
  2168.         sql_iorder[9];
  2169. static int    sql_seq;
  2170. static char    user[NAME_LENGTH];
  2171. EXEC SQL END DECLARE SECTION;
  2172.  
  2173. /*
  2174.     Create a secondary index.
  2175. */
  2176.  
  2177. Index::Index(Table *up, const char iname[]) :
  2178.                 DatabaseObject(iname, up->owner())
  2179. {
  2180.     parent        = up;
  2181.     column_list    = 0;
  2182.     index_count    = 0;
  2183.     strcpy(sql_iname, name());
  2184.     strcpy(sql_tname, up->name());
  2185.     strcpy(user, up->owner());
  2186.  
  2187.     EXEC SQL SELECT count(*)
  2188.          INTO    :sql_seq
  2189.          FROM    iiindex_columns
  2190.          WHERE    index_name = :sql_iname AND
  2191.             index_owner LIKE :user;
  2192.     if (sqlca.sqlcode ) {
  2193.         cerr << "Ingres select (count(*)) error " << sqlca.sqlcode << " in Index::Index(Table*, char[])\n";
  2194.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  2195.         exit(1);
  2196.     }
  2197.     if (sql_seq <= 0) {
  2198.         cerr << form("Table %s index %s has no columns\n",
  2199.                 sql_tname, sql_iname);
  2200.         return;
  2201.     }
  2202.     EXEC SQL SELECT DISTINCT
  2203.             LOWERCASE(unique_rule)/* UNIQUE or NONUNIQUE */
  2204.          INTO    :sql_itype
  2205.          FROM    iiindexes
  2206.          WHERE    index_name = :sql_iname AND
  2207.              index_owner LIKE :user AND
  2208.              base_name = :sql_tname;
  2209.     if (sqlca.sqlcode ) {
  2210.         cerr << "Ingres select (index uniqueness) error " << sqlca.sqlcode << " in Index::Index(Table*, char[])\n";
  2211.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  2212.         exit(1);
  2213.     }
  2214.     index_count    = sql_seq;
  2215.     column_list    = new struct index_field[index_count];
  2216.     if (sql_itype[0] == 'U')
  2217.         type = UNIQUE;
  2218.     else
  2219.         type = NON_UNIQUE;
  2220.  
  2221.     EXEC SQL DECLARE col CURSOR FOR
  2222.         SELECT 
  2223.             column_name,
  2224.             LOWERCASE(sort_direction),
  2225.             key_sequence
  2226.         FROM iiindex_columns
  2227.         WHERE index_name = :sql_iname AND
  2228.             index_owner LIKE :user
  2229.         ORDER BY key_sequence;
  2230.     EXEC SQL OPEN col;
  2231.     if (sqlca.sqlcode ) {
  2232.         cerr << "Ingres cursor open (col) error " << sqlca.sqlcode << " in Index::Index(Table*, char[])\n";
  2233.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  2234.         exit(1);
  2235.     }
  2236.  
  2237.     for (int stop = 0; stop == 0; ) {
  2238.         EXEC SQL FETCH col INTO
  2239.             :sql_colname,
  2240.             :sql_iorder,
  2241.             :sql_seq;
  2242.         assert(sql_seq > 0);
  2243.         switch (sqlca.sqlcode) {
  2244.         case 0:
  2245.         char    *s = strchr(sql_colname, ' ');
  2246.         if (s)    *s = 0;
  2247.         column_list[sql_seq-1].name
  2248.                 = new char [strlen(sql_colname)+1];
  2249.         strcpy(column_list[sql_seq-1].name, sql_colname);
  2250.         column_list[sql_seq-1].order    
  2251.                 = (sql_iorder[0] == 'a') ? ASC : DESC;
  2252.         break;
  2253.         default:
  2254.         cerr << "Ingres fetch (col) error " << sqlca.sqlcode << " in Index::Index(Table*, char[])\n";
  2255.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  2256.         case NOT_FOUND:
  2257.         stop = 1;
  2258.         break;
  2259.         }
  2260.     }
  2261.     EXEC SQL CLOSE col;
  2262.  
  2263. }
  2264.  
  2265. /*
  2266.     Create the primary index that arises from a MODIFY statement. It
  2267.     is quite possible to have secondary indexes but no primary index.
  2268. */
  2269.  
  2270. Index::Index(Table *up, char unique) :
  2271.                 DatabaseObject(up->name(), up->owner())
  2272. {
  2273.     parent        = up;
  2274.     column_list    = 0;
  2275.     strcpy(sql_tname, up->name());
  2276.     strcpy(user, up->owner());
  2277.  
  2278.     EXEC SQL SELECT count(*)
  2279.          INTO    :sql_seq
  2280.          FROM    iicolumns
  2281.          WHERE    table_name = :sql_tname AND
  2282.             table_owner LIKE :user AND
  2283.             key_sequence != 0;
  2284.     if (sqlca.sqlcode ) {
  2285.         cerr << "Ingres select (count(*)) error " << sqlca.sqlcode << " in Index::Index(Table*, char)\n";
  2286.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  2287.         exit(1);
  2288.     }
  2289.     index_count    = sql_seq;
  2290.     column_list    = new struct index_field[index_count];
  2291.     if (unique == 'U')
  2292.         type = UNIQUE;
  2293.     else
  2294.         type = NON_UNIQUE;
  2295.  
  2296.     EXEC SQL DECLARE col2 CURSOR FOR
  2297.         SELECT 
  2298.             column_name,
  2299.             LOWERCASE(sort_direction),
  2300.             key_sequence
  2301.         FROM iicolumns
  2302.         WHERE table_name = :sql_tname AND
  2303.             table_owner LIKE :user AND
  2304.             key_sequence != 0
  2305.         ORDER BY key_sequence;
  2306.     EXEC SQL OPEN col2;
  2307.     if (sqlca.sqlcode ) {
  2308.         cerr << "Ingres cursor open (col) error " << sqlca.sqlcode << " in Index::Index(Table*, char)\n";
  2309.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  2310.         exit(1);
  2311.     }
  2312.  
  2313.     for (int stop = 0; stop == 0; ) {
  2314.         EXEC SQL FETCH col2 INTO
  2315.             :sql_colname,
  2316.             :sql_iorder,
  2317.             :sql_seq;
  2318.         assert(sql_seq > 0);
  2319.         switch (sqlca.sqlcode) {
  2320.         case 0:
  2321.         char    *s = strchr(sql_colname, ' ');
  2322.         if (s)    *s = 0;
  2323.         column_list[sql_seq-1].name
  2324.                 = new char [strlen(sql_colname)+1];
  2325.         strcpy(column_list[sql_seq-1].name, sql_colname);
  2326.         column_list[sql_seq-1].order    
  2327.                 = (sql_iorder[0] == 'a') ? ASC : DESC;
  2328.         break;
  2329.         default:
  2330.         cerr << "Ingres fetch (col) error " << sqlca.sqlcode << " in Index::Index(Table*, char)\n";
  2331.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  2332.         case NOT_FOUND:
  2333.         stop = 1;
  2334.         break;
  2335.         }
  2336.     }
  2337.     EXEC SQL CLOSE col2;
  2338.  
  2339. }
  2340.  
  2341. Index::~Index()
  2342. {
  2343.     if (!column_list) return;
  2344.     for (int i = 0; i < index_count; i++)
  2345.         delete column_list[i].name;
  2346.     delete column_list;
  2347. }
  2348.  
  2349. void Index::modify(ostream& s)
  2350. {
  2351.     s << form("modify %s to btree %s on ", 
  2352.         parent->name(),
  2353.         type == UNIQUE ? "unique" : "");
  2354.     char *sep    = "\n\t";
  2355.     for (int i = 0; i < index_count; i++){
  2356.         s << form("%s%s%s",
  2357.         sep,
  2358.         column_list[i].name,
  2359.         column_list[i].order == DESC ? " desc" : "");
  2360.         sep    = ",\n\t";
  2361.     }
  2362.     s << form("%s\n", GoString);
  2363. }
  2364.  
  2365. ostream& operator<<(ostream& s, Index *ind)
  2366. {
  2367.     s << form("create %sindex %s on %s (", 
  2368.         OracleOut && ind->type == UNIQUE ? "unique " : "",
  2369.         ind->name(),
  2370.         ind->parent->name());
  2371.     char *sep    = "\n\t";
  2372.     for (int i = 0; i < ind->index_count; i++){
  2373.     s << form("%s%s%s", 
  2374.         sep, 
  2375.         ind->column_list[i].name,
  2376.         OracleOut && ind->column_list[i].order == DESC ? " desc" : ""
  2377.         );
  2378.     sep    = ",\n\t";
  2379.     }
  2380.     s << form(")%s\n", GoString);
  2381.     return s;
  2382. }
  2383.  
  2384.  
  2385. bool Index::OK()
  2386. {    bool result = TRUE;
  2387.  
  2388. // Force all columns that are used in indexing to be NON NULL
  2389.  
  2390.     for (int i = 0; i < index_count; i++) {
  2391.         Column *c = parent -> column(column_list[i].name);
  2392.         if (!c) {
  2393.         cerr << form("Table %s index %s refers to non-existent column %s\n",
  2394.             parent->name(),
  2395.             name,
  2396.             column_list[i].name);
  2397.         result = FALSE;
  2398.         } else {
  2399.         c->set_index_col();
  2400.         }
  2401.     }
  2402.  
  2403. // If the index is UNIQUE for the parent table to have WITH NODUPLICATES
  2404.  
  2405.     if (type == UNIQUE)
  2406.         parent->SetNoDuplicates();
  2407.  
  2408.     return result;
  2409. }
  2410. \Rogue\Monster\
  2411. else
  2412.   echo "will not over write ./db_unload/INGRES/INDEX.SCC"
  2413. fi
  2414. if `test ! -s ./db_unload/INGRES/TABLE.SCC`
  2415. then
  2416. echo "writing ./db_unload/INGRES/TABLE.SCC"
  2417. cat > ./db_unload/INGRES/TABLE.SCC << '\Rogue\Monster\'
  2418. /*        TABLE.SCC
  2419.  
  2420.    Build the representation of an Ingres table and all its indexes in
  2421.    memory. We can then output the appropriate SQL to reconstruct it in
  2422.    another database.
  2423.  
  2424. This program was written by Raphael Mankin. (raph@panache.demon.co.uk)
  2425. */
  2426. #include <data_dict.hpp>
  2427. #include <assert.h>
  2428.  
  2429. EXEC SQL INCLUDE SQLCA;
  2430. EXEC SQL INCLUDE SQLDA;
  2431. static IISQLDA    *fetchda;
  2432. EXEC SQL BEGIN DECLARE SECTION;
  2433. static char    sql_tname[NAME_LENGTH],
  2434.         sql_iname[NAME_LENGTH],
  2435.         sql_duplicates[9],    /* WITH NO DUPLICATES    */
  2436.         sql_unique[9];        /* MODIFY to UNIQUE    */
  2437. static struct {
  2438.     short    len;
  2439.     char    arr[240];
  2440.     } sql_data[IISQ_MAX_COLS];
  2441. static short    sql_ind[IISQ_MAX_COLS],
  2442.         sql_indcount;
  2443. static long    sql_colno;
  2444. static char    user[NAME_LENGTH];
  2445. EXEC SQL END DECLARE SECTION;
  2446. typedef struct {short len; char arr[1];}    VC;
  2447.  
  2448. Table::Table(const char tname[], const char *towner) :
  2449.             DatabaseObject(tname, towner)
  2450. {
  2451.     cols         = 0;
  2452.     NoDuplicates    = FALSE;
  2453.     strcpy(sql_tname, name());
  2454.     strcpy(user, owner());
  2455.     EXEC SQL SELECT    
  2456.         duplicate_rows,
  2457.         unique_rule
  2458.         INTO :sql_duplicates,    /* WITH NO DUPLICATES    */
  2459.          :sql_unique        /* MODIFY to xxx UNIQUE    */
  2460.         FROM iitables
  2461.         WHERE table_name = :sql_tname and
  2462.           table_owner LIKE :user;
  2463.     if (sqlca.sqlcode ) {
  2464.         cerr << "Ingres SELECT duplicates error " << sqlca.sqlcode << " in Table::Table(char name[])\n";
  2465.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  2466.         exit(1);
  2467.     }
  2468.     NoDuplicates    = (sql_duplicates[0] == 'U') ||
  2469.               (sql_unique[0] == 'U');
  2470.     EXEC SQL DECLARE col CURSOR FOR
  2471.          SELECT DISTINCT column_sequence
  2472.          FROM iicolumns
  2473.          WHERE table_name = :sql_tname and
  2474.                table_owner LIKE :user
  2475.          ORDER BY column_sequence DESC;
  2476.     EXEC SQL OPEN col;
  2477.     if (sqlca.sqlcode ) {
  2478.         cerr << "Ingres cursor open error " << sqlca.sqlcode << " in Table::Table(char name[])\n";
  2479.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  2480.         exit(1);
  2481.     }
  2482.     for (int stop = 0; !stop;) {
  2483.         EXEC SQL FETCH col
  2484.              INTO :sql_colno;
  2485.         switch (sqlca.sqlcode) {
  2486.         case 0:
  2487.             cols = new Column(sql_colno, this, cols);
  2488.             break;
  2489.         default:
  2490.             cerr << "Ingres fetch error " << sqlca.sqlcode << " in Table::Table(char name[])\n";
  2491.             cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  2492.         case NOT_FOUND:
  2493.             stop = 1;
  2494.         }
  2495.     }
  2496.     EXEC SQL CLOSE col;
  2497.  
  2498.     /*
  2499.     Count how many indexes there are and allocate space for them
  2500.     plus one for the primary index, if any.
  2501.     */
  2502.     EXEC SQL SELECT count(*)+1
  2503.          INTO   :sql_indcount
  2504.          FROM    iiindexes
  2505.          WHERE    base_name = :sql_tname AND
  2506.             index_owner LIKE :user;
  2507.     if (sqlca.sqlcode ) {
  2508.         cerr << "Ingres select (count(*)+1) error " << sqlca.sqlcode << " in Table::Table(char name[])\n";
  2509.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  2510.         exit(1);
  2511.     }
  2512.     IndexCount    = 0;
  2513.     index_list    = new Index *[sql_indcount];
  2514.  
  2515.     /*
  2516.     Is there a MODIFY statement for this table ?
  2517.     */
  2518.     EXEC SQL SELECT COUNT(*)
  2519.          INTO :sql_colno
  2520.          FROM iicolumns
  2521.          WHERE table_name = :sql_tname AND
  2522.                table_owner LIKE :user AND
  2523.                key_sequence != 0;
  2524.     if (sqlca.sqlcode ) {
  2525.         cerr << "Ingres select (count(*)) error " << sqlca.sqlcode << " in Table::Table(char name[])\n";
  2526.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  2527.         exit(1);
  2528.     }
  2529.     /*
  2530.     If there is a MODIFY create an index for it.
  2531.     */
  2532.     if (sql_colno > 0) {
  2533.         Index    *ind    =
  2534.         index_list[IndexCount++]    
  2535.             = new Index(this, sql_unique[0]);
  2536.         if (!ind->OK()) {
  2537.         cerr << "Error on primary index \n";
  2538.         }
  2539.     }
  2540.  
  2541.     /*
  2542.     Now deal with the secondary indexes.
  2543.     */
  2544.     EXEC SQL DECLARE ind CURSOR FOR
  2545.         SELECT DISTINCT index_name
  2546.                FROM iiindexes
  2547.                WHERE base_name = :sql_tname AND
  2548.                 index_owner LIKE :user
  2549.                ORDER by index_name ;
  2550.     EXEC SQL OPEN ind;
  2551.     if (sqlca.sqlcode ) {
  2552.         cerr << "Ingres cursor open (index) error " << sqlca.sqlcode << " in Table::Table()()\n";
  2553.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  2554.         exit(1);
  2555.     }
  2556.     for (stop=0; !stop; ) {
  2557.         EXEC SQL FETCH ind
  2558.              INTO :sql_iname;
  2559.         switch (sqlca.sqlcode) {
  2560.         case 0:
  2561.             Index *ind            =
  2562.             index_list[IndexCount++]    =
  2563.                 new Index(this, sql_iname);
  2564.             if (!ind->OK()) {
  2565.                 cerr << form("Error on index %s\n", sql_iname);
  2566.             }
  2567.             break;
  2568.         default:
  2569.             cout << form("rollback%s\n", GoString);
  2570.             cerr << "Ingres fetch (index) error " << sqlca.sqlcode << " in Table::Table()\n";
  2571.             cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  2572.         case NOT_FOUND:
  2573.             stop = 1;
  2574.         }
  2575.     }
  2576.     EXEC SQL CLOSE ind;
  2577.  
  2578.  
  2579. }
  2580.  
  2581. Table::~Table()
  2582. {
  2583.     if (cols) delete cols;
  2584.     for (int i = 0; i < IndexCount; i++) {
  2585.         delete index_list[i];
  2586.         index_list[i]    = 0;
  2587.     }
  2588.     if (index_list)
  2589.         delete index_list;
  2590. }
  2591.  
  2592. ostream& operator<<(ostream& s, Table & t)
  2593. {
  2594.     s << form("drop table %s%s\n", t.name(), GoString);
  2595.     s << form("create table %s(\n", t.name());
  2596.     for (Column *c = t.cols; c; c = c->link()) {
  2597.         s << *c;
  2598.         if (c->link()) 
  2599.             s << ",\n";
  2600.         else
  2601.             s << "\n";
  2602.     }
  2603.     s << form(")%s%s\n", 
  2604.         t.NoDuplicates ? " with noduplicates" : "",
  2605.         GoString);
  2606.     if (!OracleOut && t.IndexCount) {
  2607.         t.index_list[0]->modify(s);
  2608.     }
  2609.     for (int i=(OracleOut?0:1); i<t.IndexCount; i++) {
  2610.         s << t.index_list[i];
  2611.     }
  2612.     s.flush();
  2613.     return s;
  2614. }
  2615.  
  2616. void    Table::extract(ostream &s)
  2617. {    int    i;
  2618.     EXEC SQL BEGIN DECLARE SECTION;
  2619.     char    selectbuf[5000];    /* Ingres SELECT statement    */
  2620.     EXEC SQL END DECLARE SECTION;
  2621.     char    insertbuf[5000];    /* Ingres INSERT statement    */
  2622.     bzero(selectbuf, sizeof(selectbuf));
  2623.     bzero(insertbuf, sizeof(insertbuf));
  2624.     ostream b(sizeof(selectbuf), selectbuf);
  2625.     ostream ins(sizeof(insertbuf), insertbuf);
  2626.  
  2627.     /*
  2628.     In selectbuf[] build a SELECT statement to use as a cursor to
  2629.     fetch the Ingres data rows from the table. Simultaneously, in
  2630.     insertbuf[] build the stem of an INSERT statement to insert
  2631.     the data into the output table. The actual data values will be
  2632.     added to the stem as each data row is fetched.
  2633.     */
  2634.     int field_count = 0;
  2635.     b << "SELECT ";
  2636.     ins << form("insert into %s (\n", name());
  2637.     for (Column *c = cols; c; c= c->link()) {
  2638.         switch (c->type()) {
  2639.         case NUM:
  2640.             b << form("VARCHAR(%s)%s ", 
  2641.                     c->name(), 
  2642.                     c->link() ? "," : "");
  2643.             break;
  2644.         case MONEY:
  2645.             b << form("VARCHAR(FLOAT8(%s))%s ",
  2646.                     c->name(), 
  2647.                     c->link() ? "," : "");
  2648.             break;
  2649.         case DATE:
  2650.         default:
  2651.             b << form("VARCHAR(%s)%s", c->name(), c->link() ? ", " : " ");
  2652.             break;
  2653.         }
  2654.         ins << form("\t%s%s\n", c->name(), c->link() ? "," : "");
  2655.         field_count++;
  2656.     }
  2657.     ins << ") values (\n";
  2658.     b << form("FROM %s", name());
  2659.     b.close();
  2660.     ins.close();
  2661.  
  2662.     /*
  2663.     We have now built the text of the various SQL statements that
  2664.     we need. The next step is to tell Ingres about it and the
  2665.     target variables that we are going to use.
  2666.     */
  2667.     EXEC SQL PREPARE s1 FROM :selectbuf;
  2668.     if (sqlca.sqlcode ) {
  2669.         cerr << "Ingres PREPARE error " << sqlca.sqlcode << " for S1 in Table::extract(ostream &)\n";
  2670.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  2671.         cerr << form("Text is: '%s'\n", selectbuf);
  2672.         s << form("rollback%s\n", GoString);
  2673.         exit(1);
  2674.     }
  2675.     EXEC SQL DECLARE cc CURSOR FOR s1;
  2676.  
  2677.     /*
  2678.     Allocate a sqlda for 'field_count' columns with 30-char names.
  2679.     This will be used to hold pointers to our work variables into
  2680.     which Ingres will store the data rows fetched from the table.
  2681.  
  2682.     */
  2683.     fetchda        = new IISQLDA;
  2684.     if (!fetchda) {
  2685.         cerr << form("Ingres error allocating sqlda\n");
  2686.         s << form("rollback%s\n", GoString);
  2687.         exit(1);
  2688.     }
  2689.     fetchda->sqln    = field_count;
  2690.     fetchda->sqld    = field_count;
  2691.     /*
  2692.     sql_data[][], declared above, can hold 100 data items each of
  2693.     up to 240 bytes. sql_ind[] are the corresponding 100 indicators.
  2694.     */
  2695.     i = 0;
  2696.     for (c = cols; c; c= c->link()) {
  2697.         fetchda->sqlvar[i].sqltype    = IISQ_VCH_TYPE;        
  2698.         fetchda->sqlvar[i].sqldata    = (char *)&sql_data[i];
  2699.         fetchda->sqlvar[i].sqlind    = &sql_ind[i];
  2700.         fetchda->sqlvar[i].sqllen    = 240;
  2701.         i++;
  2702.     }
  2703.  
  2704.     EXEC SQL OPEN cc;
  2705.     if (sqlca.sqlcode ) {
  2706.         cerr << "Ingres cursor open error " << sqlca.sqlcode << " in Table::extract(ostream &)\n";
  2707.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  2708.         exit(1);
  2709.     }
  2710.  
  2711.     EXEC SQL DESCRIBE s1 INTO fetchda;
  2712.     if (sqlca.sqlcode ) {
  2713.         cerr << "Ingres describe-select error " << sqlca.sqlcode << " in Table::extract(ostream &)\n";
  2714.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  2715.         exit(1);
  2716.     }
  2717.  
  2718.     i = 0;
  2719.     for (c = cols; c; c= c->link()) {
  2720.         switch (c->type()) {
  2721.         case DATE:
  2722.             fetchda->sqlvar[i].sqllen = IISQ_DTE_LEN+2;
  2723.             break;
  2724.         case CHAR:
  2725.             fetchda->sqlvar[i].sqllen = c->width()+2;
  2726.             break;
  2727.         case MONEY:
  2728.         case FLOAT:
  2729.         case NUM:
  2730.             break;
  2731.         default:
  2732.             assert(0);
  2733.         }
  2734.         i++;
  2735.     }
  2736.     if (fetchda->sqln < 0) {
  2737.         cerr << form("Ingres DESCRIBE error - %d fields allocated; %d fields found\n",
  2738.              field_count, fetchda->sqln);
  2739.         exit(1);
  2740.     }
  2741.     for (int stop = 0; !stop;) {
  2742.         EXEC SQL FETCH cc
  2743.              USING DESCRIPTOR fetchda;
  2744.         switch (sqlca.sqlcode) {
  2745.         case 0:
  2746.         s << insertbuf;
  2747.         int    i = 0;
  2748.         for (c=cols; c; c = c->link()) {
  2749.             if (*fetchda->sqlvar[i].sqlind < 0)  {    // If NULL value
  2750.             if (NotNull) {        // Force NOT NULL
  2751.                 switch(c->type()) {
  2752.                 case FLOAT:
  2753.                 case MONEY:
  2754.                 case NUM:
  2755.                 s << form("\t0%s\n",
  2756.                     c->link() ? "," : "");
  2757.                 break;
  2758.                 case CHAR:
  2759.                 case DATE:
  2760.                 default:
  2761.                 s << form("\t''%s\n",
  2762.                     c->link() ? "," : "");
  2763.                 break;
  2764.                 }
  2765.             } else {        // Honour NULLs
  2766.                 s << form("\tNULL%s\n",
  2767.                 c->link() ? "," : "");
  2768.             }
  2769.             } else if (*fetchda->sqlvar[i].sqlind > 0) {
  2770.             cerr << form("Table %s, field %s truncated from %d ch\n",
  2771.                name(), c->name(), *fetchda->sqlvar[i].sqlind);
  2772.             }
  2773.  
  2774.             if (*fetchda->sqlvar[i].sqlind >= 0) {
  2775.             switch(c->type()) {
  2776.             case MONEY:
  2777.             case FLOAT:
  2778.             case NUM:
  2779.                 if (!((VC *)fetchda->sqlvar[i].sqldata)->len) 
  2780.                 s << form("\t0%s\n",
  2781.                     c->link() ? "," : "");
  2782.                 else
  2783.                 s << form("\t%.*s%s\n",
  2784.                     sql_data[i].len,
  2785.                     sql_data[i].arr,
  2786.                     c->link() ? "," : "");
  2787.                 break;
  2788.             case CHAR:
  2789.                 dequote(sql_data[i].arr);
  2790.             case DATE:
  2791.             default:
  2792.                 s << form("\t'%.*s'%s\n",
  2793.                     sql_data[i].len,
  2794.                     sql_data[i].arr,
  2795.                     c->link() ? "," : "");
  2796.                 break;
  2797.             }
  2798.             }
  2799.             i++;
  2800.         }
  2801.         s << form(")%s\n", GoString);
  2802.         break;
  2803.         default:
  2804.             cerr << "Ingres fetch error " << sqlca.sqlcode << " in Table::extract(ostream&)\n";
  2805.             cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  2806.             cerr << form("Table name %s\n", name());
  2807.             s << form("rollback%s", GoString);
  2808.         case NOT_FOUND:
  2809.             stop = 1;
  2810.         }
  2811.         s.flush();
  2812.     }            // End of FETCH loop
  2813.     EXEC SQL CLOSE cc;
  2814.     delete fetchda;
  2815. }
  2816.  
  2817. void    Table::grant(ostream &s)
  2818. {    for (Column *c = cols; c; c = c->link()) {
  2819.         if (!c->IndexColumn)
  2820.         s << form("grant update(%s) on %s to public%s\n",
  2821.             c->name(), name(), GoString);
  2822.     }
  2823.     s << form("grant select on %s to public%s\n",
  2824.         name(), GoString);
  2825.     s << form("grant delete on %s to public%s\n",
  2826.         name(), GoString);
  2827.     s << form("grant insert on %s to public%s\n",
  2828.         name(), GoString);
  2829. }
  2830. \Rogue\Monster\
  2831. else
  2832.   echo "will not over write ./db_unload/INGRES/TABLE.SCC"
  2833. fi
  2834. if `test ! -s ./db_unload/INGRES/COLUMN.SCC`
  2835. then
  2836. echo "writing ./db_unload/INGRES/COLUMN.SCC"
  2837. cat > ./db_unload/INGRES/COLUMN.SCC << '\Rogue\Monster\'
  2838. /*        COLUMN.SCC
  2839.  
  2840.  Process a column definition,  while converting a database table
  2841.  from Ingres to SQL.
  2842.  
  2843. This program was written by Raphael Mankin. (raph@panache.demon.co.uk)
  2844. */
  2845. #include <data_dict.hpp>
  2846. #include <assert.h>
  2847.  
  2848. EXEC SQL INCLUDE SQLCA;
  2849. EXEC SQL BEGIN DECLARE SECTION;
  2850. static char    sql_tname[NAME_LENGTH];
  2851. static char
  2852.     sql_cname[NAME_LENGTH],
  2853.     sql_coltype[NAME_LENGTH],
  2854.     sql_nulls[9],
  2855.     sql_defaultval[9];
  2856. static long
  2857.     sql_int_datatype,
  2858.     sql_width,
  2859.     sql_scale,
  2860.     sql_colno;
  2861. static char    user[NAME_LENGTH];
  2862. EXEC SQL END DECLARE SECTION;
  2863.  
  2864. Column::Column(long    num, Table *up, Column *succ)
  2865. {
  2866.     next        = succ;
  2867.     IndexColumn    = FALSE;
  2868.     parent        = up;
  2869.     nulls        = FALSE;
  2870.     WithDefault    = FALSE;
  2871.     sql_colno    = num;
  2872.     strcpy(sql_tname, up->name());
  2873.     strcpy(user, up->owner());
  2874.     EXEC SQL SELECT 
  2875.             column_name,
  2876.             column_datatype,
  2877.             column_length,
  2878.             column_scale,
  2879.             column_nulls,
  2880.             column_defaults,
  2881.             column_ingdatatype
  2882.          INTO    :sql_cname,
  2883.             :sql_coltype,
  2884.             :sql_width,
  2885.             :sql_scale,
  2886.             :sql_nulls,
  2887.             :sql_defaultval,
  2888.             :sql_int_datatype
  2889.          FROM iicolumns
  2890.          WHERE table_name = :sql_tname AND
  2891.                table_owner LIKE :user AND
  2892.                column_sequence = :sql_colno;
  2893.     if (sqlca.sqlcode) {
  2894.         cerr << "Ingres select error " << sqlca.sqlcode << " in Column::Column(long, Table*, Column*)\n";
  2895.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  2896.         exit(1);
  2897.     }
  2898.     char    *s = strchr(sql_cname, ' ');
  2899.     if (s)    *s = 0;
  2900.     strcpy(cname, sql_cname);
  2901.     if (sql_int_datatype < 0 && !NotNull)
  2902.         nulls    = TRUE;
  2903.     else
  2904.         nulls    = FALSE;
  2905.     switch(sql_int_datatype) {
  2906.     case 30:    case -30:
  2907.         coltype    = NUM;
  2908.         break;
  2909.     case 31:    case -31:
  2910.         coltype    = FLOAT;
  2911.         break;
  2912.     case 37:    case -37:
  2913.     case 20:    case -20:
  2914.     case 21:    case -21:
  2915.         coltype    = CHAR;
  2916.         break;
  2917.     case 3:        case -3:
  2918.         coltype    = DATE;
  2919.         break;
  2920.     case 5:        case -5:
  2921.         coltype    = MONEY;
  2922.         break;
  2923.     }
  2924.     colwidth    = sql_width;
  2925. }
  2926.  
  2927. Column::Column(long    num, View *up, Column *succ)
  2928. {
  2929.     next        = succ;
  2930.     IndexColumn    = FALSE;
  2931.     parent        = (Table*)up;
  2932.     sql_colno    = num;
  2933.     strcpy(sql_tname, up->name());
  2934.     EXEC SQL SELECT 
  2935.             column_name
  2936.          INTO    :sql_cname
  2937.          FROM iicolumns
  2938.          WHERE table_name = :sql_tname AND
  2939.                table_owner LIKE :user AND
  2940.                column_sequence = :sql_colno;
  2941.     if (sqlca.sqlcode) {
  2942.         cerr << "Ingres select error " << sqlca.sqlcode << " in Column::Column(long, View*, Column*)\n";
  2943.         cerr << sqlca.sqlerrm.sqlerrmc << "\n";
  2944.         exit(1);
  2945.     }
  2946.     char    *s = strchr(sql_cname, ' ');
  2947.     if (s)    *s = 0;
  2948.     strcpy(cname, sql_cname);
  2949. }
  2950.  
  2951. ostream& operator<<(ostream& s, Column& c)
  2952. {
  2953.     s << form("\t%-.24s\t", c.cname);
  2954.     switch (c.coltype) {
  2955.     case CHAR:
  2956.         s << form("%s(%d)",
  2957.             OracleOut?"VARCHAR":"VCHAR",
  2958.             c.colwidth);
  2959.         break;
  2960.     case NUM:
  2961.         s << form("INTEGER");
  2962.         break;
  2963.     case DATE:
  2964.         s << form("DATE");
  2965.         break;
  2966.     case FLOAT:
  2967.         s << form("FLOAT");
  2968.         break;
  2969.     case MONEY:
  2970.         s << form("MONEY");
  2971.         break;
  2972.     default:
  2973.         assert(0);
  2974.     }
  2975.     if (!c.nulls) {
  2976.         s << " NOT NULL";
  2977.         if (Default || c.WithDefault)
  2978.             if (!c.IndexColumn)
  2979.             s << " WITH DEFAULT";
  2980.     }
  2981.     return s;
  2982. }
  2983.  
  2984. // Locate a column by name
  2985. Column    *Table::column(const char cname[])
  2986. {
  2987.     for (Column *c = cols; c; c= c->link())
  2988.         if (!stricmp(cname, c->name()))
  2989.         return c;
  2990.     return 0;
  2991. }
  2992. \Rogue\Monster\
  2993. else
  2994.   echo "will not over write ./db_unload/INGRES/COLUMN.SCC"
  2995. fi
  2996. if `test ! -s ./db_unload/INGRES/DEQUOTE.C`
  2997. then
  2998. echo "writing ./db_unload/INGRES/DEQUOTE.C"
  2999. cat > ./db_unload/INGRES/DEQUOTE.C << '\Rogue\Monster\'
  3000. /*        DEQUOTE.C
  3001.  
  3002. This program was written by Raphael Mankin. (raph@panache.demon.co.uk)
  3003.  
  3004. */
  3005. #ifdef SYSV
  3006. #include <string.h>
  3007. #define index   strchr
  3008. #else
  3009. #include <strings.h>
  3010. #endif
  3011.  
  3012. /*
  3013.     If s.arr contains embedded apostrophes, we have to replace each
  3014.     one by a doubled apostrophe in order to keep Ingres happy.
  3015.     This we do by counting the total number of apostophes and
  3016.     shuffling data to the right by the number of apostrophes to
  3017.     the left of each byte.
  3018. */
  3019.  
  3020. dequote(s)
  3021. struct varchar {
  3022.     short    len;
  3023.     char    arr[1];
  3024. }    *s;
  3025. {    int    i, j, len, count, count2;
  3026.     char    *p;
  3027.  
  3028.     if (!(p=index(s->arr, '\'')))
  3029.         return ;
  3030.     count = 1;
  3031.     while (p= index(p+1, '\''))
  3032.         count++;
  3033.     count2    = count;
  3034.     for (i= s->len-1; count > 0; i--) {
  3035.         if (s->arr[i] == '\'') {
  3036.             s->arr[i+count] = s->arr[i];
  3037.             count--;
  3038.         }
  3039.         s->arr[i+count] = s->arr[i];
  3040.     }
  3041.     s->len        += count2;
  3042.     s->arr[s->len]    = 0;
  3043.  
  3044.     return ;
  3045. }
  3046. \Rogue\Monster\
  3047. else
  3048.   echo "will not over write ./db_unload/INGRES/DEQUOTE.C"
  3049. fi
  3050. if `test ! -s ./db_unload/INGRES/README`
  3051. then
  3052. echo "writing ./db_unload/INGRES/README"
  3053. cat > ./db_unload/INGRES/README << '\Rogue\Monster\'
  3054. This program unloads an Ingres database as an SQL stream. I wrote it
  3055. for converting Ingres DBs to Oracle. There is also an equivalent, and
  3056. very similar, program for converting Oracle to Ingres.
  3057.  
  3058. Not all data types are catered for: they did not occur in my DB. No
  3059. attempt is made to deal with constraints, user groups or other
  3060. esoterica.
  3061.  
  3062. The supplied ``man'' page is actually from the Oracle to Ingres
  3063. version. It is _almost_ correct, but take it with a pinch of salt.
  3064.  
  3065. Since I am embedding SQL in C++, we have to be a little careful in how we write the code. In particular:
  3066. 1. esql/C does not recognise // comments.
  3067. 2. Function arguments and members of classes cannot be used as SQL variables 
  3068.    (they can't be in a DECLARE SECTION).
  3069. 3. All sorts of functions have to be declared by hand as extern "C" to satisfy
  3070.    C++'s calling convention.
  3071. 4. We have to massage the output of esql/c with sed to deal with the conflict
  3072.    between variable names and structure tags.
  3073.  
  3074. I offer no warranties as to the correctness of this code. You are
  3075. welcome to use it, but at your own risk.
  3076.  
  3077. Raphael Mankin (raph@panache.demon.co.uk).
  3078. 7 Jan 1993
  3079. \Rogue\Monster\
  3080. else
  3081.   echo "will not over write ./db_unload/INGRES/README"
  3082. fi
  3083. if `test ! -s ./db_unload/INGRES/DERESERV.C`
  3084. then
  3085. echo "writing ./db_unload/INGRES/DERESERV.C"
  3086. cat > ./db_unload/INGRES/DERESERV.C << '\Rogue\Monster\'
  3087. /*        DERESERVE.C
  3088.  
  3089. This program was written by Raphael Mankin. (raph@panache.demon.co.uk)
  3090.  
  3091. CHANGES:
  3092. 7/4/92    Change returned type from void to char*
  3093.  
  3094. */
  3095.  
  3096. #include <stdio.h>
  3097. #ifndef __GNUG__    /* For AT&T compiler    */
  3098. #define stricmp strcasecmp
  3099. #include <strings.h>
  3100. #else
  3101. #include <string.h>
  3102. #endif
  3103.  
  3104. static char *reserved[] = {
  3105.             "command",
  3106.             "count",
  3107.             "default",
  3108.             "file",
  3109.             "index",
  3110.             0
  3111.         };
  3112.  
  3113. const char *dereserve(const char name[])
  3114. {    int    i;
  3115.     static char    buf[100];
  3116.  
  3117.     for (i=0; reserved[i]; i++) {
  3118.         if (!stricmp(name, reserved[i])) {
  3119.         strcpy(buf, name);
  3120.         strcat(buf, "_x");
  3121.         return buf;
  3122.         }
  3123.     }
  3124.  
  3125.     return name;
  3126. }
  3127. \Rogue\Monster\
  3128. else
  3129.   echo "will not over write ./db_unload/INGRES/DERESERV.C"
  3130. fi
  3131. if `test ! -s ./db_unload/README`
  3132. then
  3133. echo "writing ./db_unload/README"
  3134. cat > ./db_unload/README << '\Rogue\Monster\'
  3135. These programs unload an Ingres or Oracle database as an SQL stream.
  3136. I wrote them for converting databases back and forth when porting an
  3137. application from Oracle to Ingres and the data also had to be moved.
  3138.  
  3139. Not all data types are catered for: they did not occur in my DB. No
  3140. attempt is made to deal with constraints, user groups or other
  3141. esoterica.
  3142.  
  3143. The supplied ``man'' page is actually from the Oracle to Ingres
  3144. version. It is _almost_ correct, but take it with a pinch of salt.
  3145.  
  3146. Since I am embedding SQL in C++, we have to be a little careful in how we write the code. In particular:
  3147. 1. esql/C does not recognise // comments.
  3148. 2. Function arguments and members of classes cannot be used as SQL variables 
  3149.    (they can't be in a DECLARE SECTION).
  3150. 3. All sorts of functions have to be declared by hand as extern "C" to satisfy
  3151.    C++'s calling convention.
  3152. 4. We have to massage the output of esql/c with sed to deal with the conflict
  3153.    between variable names and structure tags.
  3154.  
  3155. I offer no warranties as to the correctness of this code. You are
  3156. welcome to use it, but at your own risk.
  3157.  
  3158. Raphael Mankin (raph@panache.demon.co.uk).
  3159. 7 Jan 1993
  3160. \Rogue\Monster\
  3161. else
  3162.   echo "will not over write ./db_unload/README"
  3163. fi
  3164. echo "Finished archive 1 of 1"
  3165. exit
  3166. --------------Cut here-----------------
  3167. --------------
  3168. Raphael Mankin            Nil taurus excretum
  3169.