home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tmap_src.txt < prev    next >
Text File  |  1995-04-30  |  17KB  |  428 lines

  1. TMAP Source Code
  2. ----------------
  3. This file contains the source code for the TMap database table mapping
  4. utility, which uses the the IBM User Interface Class Library container
  5. control to display some of the relevant characteristics of columns in
  6. database tables.  To function correctly, TMap requires OS/2 2.11 (OS/2
  7. 2.10 plus corrective service), DB2/2 1.2, and C-Set++ 2.1.  This file
  8. begins with a sample makefile (note debug is enabled), followed by
  9. TMap.hpp, TMap.cpp, dbs.h, dbs.sqc, and finally TMap.def, each of which
  10. is seperated from the others by a // comment beginning at the left hand
  11. margin.  Please direct questions or comments via the Internet to the
  12. author, Liston Tatum, at glt@dmt03.mcc.virginia.edu; time permitting, I
  13. will try to respond.
  14.  
  15. This code is intended as an educational example only, and may be freely
  16. distributed, with the proviso that the user assumes all liability;
  17. anyone who does not agree with these terms is hereby denied license for
  18. its use.
  19. -------------------------------------------------------------------------
  20.  # makefile - for TMap DB2 database table mapping utility
  21.  #
  22.  CPPFLAGS=/C /Q /N3 /G4 /Gm- /Ti /Fi /Fb- /Si /O-
  23.  #
  24.  # /C  does compile only
  25.  # /Q  suppresses logo
  26.  # /N3 quits after 3 errors
  27.  # /G4 generates code for a 486
  28.  # /Gm uses multi thread libraries
  29.  # /Ti debug info
  30.  # /Fi generates precompiled headers
  31.  # /Fb generates browser file
  32.  # /Si uses precompiled headers if available
  33.  # /Pe suppresses #line macros, not compatible with /Fi- and /Si-
  34.  # /O  optimizes
  35.  #
  36.  all:tmap
  37.  #
  38.  tmap:tmap.exe
  39.  #
  40.  #  link exe file              /Gd- static link to dde4mbs.lib
  41.  #                             /Gd  dynamic link to dde4mbsi - the dll
  42.  #                             /DE passes debug info - must precede /Q
  43.  tmap.exe:tmap.obj dbs.obj
  44.        icc /B /DE \
  45.        tmap.obj dbs.obj \
  46.        dde4muii.lib dde4cci.lib dde4mbsi.lib sql_dyn.lib tmap.def
  47.  #
  48.  #  compile tmap - /Fb generates browser file
  49.  #
  50.  tmap.obj:tmap.cpp tmap.hpp dbs.h
  51.        icc $(CPPFLAGS) tmap.cpp
  52.  #
  53.  #  compile dbs - /Ss tolerates C++ //comments
  54.  #
  55.  dbs.obj:dbs.c dbs.h
  56.        icc $(CPPFLAGS) /Ss dbs.c
  57.  #
  58.  #  sqlprep dbs.sqc - /# suppresses #LINE for debugging
  59.  #                    /b create .bnd file instead of doing bind
  60.  dbs.c:dbs.sqc dbs.h
  61.        sqlprep dbs.sqc sample /# /b
  62.  
  63.  //TMap.hpp - show details of database table structure
  64.  
  65.  #ifndef TMAP_HPP
  66.  #define TMAP_HPP
  67.  
  68.  #define SYS_TABLES      0x2000      //frame window - sysibm.systables
  69.  #define SYS_TAB_ROWS    0x2010      //container - sysibm.systables
  70.  #define SYS_COLUMNS     0x2100      //frame window - sysibm.syscolumns
  71.  #define SYS_COL_ROWS    0x2110      //container - sysibm.syscolumns
  72.  
  73.  extern struct sqlca sqlca;          //for sqlca.sqlcode
  74.  extern "c" {
  75.     int connect(char *dbname);       //connect to dbname
  76.     void reset();
  77.     int openTabRow();
  78.     int fetchTabRow(struct tabRow *tRow);
  79.     void closeTabRow();
  80.     int selectTabRem(char *creator, char *name, char (*tabRem)255Y);
  81.     int openColRow(char *creator, char *name);
  82.     int fetchColRow(struct colRow *cRow);
  83.     void closeColRow();
  84.  }
  85.  
  86.  class EMsg:public IObjectWindow {   //IMessagebox for error, exit
  87.     public:
  88.        EMsg();                       //show SQL error message text
  89.        EMsg(char *msg);              //show our error string
  90.  };
  91.  
  92.  class Database {
  93.     public:
  94.        Database(char *db) { if (connect(db)) EMsg(); }
  95.        ~Database() { reset(); }
  96.        class Relations {    //provider for Tables from sysibm.systables
  97.           public:
  98.              Relations() { if(openTabRow()) EMsg(); }
  99.              int next() { return fetchTabRow(&tRow); }
  100.              ~Relations() { closeTabRow(); }
  101.              struct tabRow tRow;
  102.        };
  103.        class Attributes {   //supplies Details from sysibm.syscolumns
  104.           public:
  105.              Attributes(char *creator, char *name)
  106.                    { if(openColRow(creator, name)) EMsg(); }
  107.              int next() { return fetchColRow(&cRow); }
  108.              ~Attributes() { closeColRow(); }
  109.              struct colRow cRow;
  110.        };
  111.        class TabRem {       //remark for Details from sysibm.systables
  112.           public:
  113.              void getTabRem(char *creator, char *name, char (*tr)255Y)
  114.                    { if (selectTabRem(creator, name, tr)) EMsg(); }
  115.        };
  116.  };
  117.  
  118.  class Tables:public IFrameWindow {  //tree view of creator, table name
  119.     public:
  120.        Tables(const IString *title);
  121.        void showColumns(struct tabRow& tRow);
  122.        class Creator:public IContainerObject {   //table creator object
  123.           friend class Tables;
  124.           public:
  125.              Creator(char *creator, Tables *owner)
  126.                 :IContainerObject(IString(creator)) {};
  127.              void handleOpen(IContainerControl *w) { w->expand(this); }
  128.        };
  129.        class Name:public IContainerObject {      //table name object
  130.           friend class Tables;
  131.           public:
  132.              Name(struct tabRow *tRow, Tables *owner);
  133.              void handleOpen(IContainerControl *w);
  134.           private:
  135.              IString creator, name;
  136.        };
  137.     private:
  138.        IContainerControl *table;
  139.        ICnrHandler event;
  140.  };
  141.  
  142.  class Details:public IFrameWindow { //details view of table attributes
  143.     public:
  144.        Details(char *title, char *creator, char *name);
  145.        void showColumns() { show(); }
  146.        class Row:public IContainerObject {       //column details
  147.           friend class Details;
  148.           public:
  149.              Row(struct colRow *cRow, Details *owner);
  150.              void handleOpen(IContainerControl *w);
  151.           private:
  152.              IString type, length, nulls, rem;
  153.        };
  154.     private:
  155.        IContainerControl *table;
  156.        ICnrHandler event;
  157.        IContainerColumn *cNam, *cTyp, *cLen, *cNul, *cRem;
  158.  };
  159.  #endif
  160.  
  161.  // TMap.cpp - show details of database table structure
  162.  
  163.  #define INCL_WINSYS           //include WINSYS stuff from os2.h
  164.  #include <os2.h>              //WinQuerySysValue
  165.  #include <sqlenv.h>           //access to sqlca.sqlcode
  166.  #include <iobjwin.hpp>        //IObjectWindow for IMessageBox
  167.  #include <imsgbox.hpp>        //IMessageBox for error message
  168.  #include <iscroll.hpp>        //systemScrollBarWidth
  169.  #include <ipoint.hpp>         //ISize
  170.  #include <iapp.hpp>           //IApplication
  171.  #include <icnrctl.hpp>        //IContainer control
  172.  #include <icnrhdr.hpp>        //ICnrHandler - container control events
  173.  #include <icnrcol.hpp>        //IContainerColumn
  174.  #include <icolor.hpp>         //IColor
  175.  #include <istring.hpp>        //IString
  176.  #include <iframe.hpp>         //IFrameWindow
  177.  #include <icmdhdr.hpp>        //ICommandEvent& ICommandHandler
  178.  #include <ifont.hpp>          //IFont
  179.  #include "dbs.h"              //table row structs shared with dbs.sqc
  180.  #include "tmap.hpp"           //our class interface definitions
  181.  
  182.  void main(int argc, char *argvY) {
  183.     if (argc != 2 || *argv1Y == '?') EMsg("format: TMAP dbname");
  184.     Database DB2(argv1Y);           //if error, exit; else, connect
  185.     IString title("Database: "); title += argv1Y;
  186.     Tables DB2Tables(&title);        //application's main control panel
  187.     IApplication::current().run();   //start PM message processing loop
  188.  }
  189.  
  190.  Tables::Tables(const IString *title):IFrameWindow(*title,SYS_TABLES) {
  191.     table = new IContainerControl(SYS_TAB_ROWS, this, this);
  192.     setClient(table); event.handleEventsFor(table);
  193.     Database::Relations *dbTbl = new Database::Relations();  //open csr
  194.     int rc = dbTbl->next();                                  //get row
  195.     while (rc != NOTFOUND) {
  196.        Creator *creator = new Creator(dbTbl->tRow.creator, this);
  197.        table->addObject(creator);          //first level tree node
  198.        IString buf(dbTbl->tRow.creator);
  199.        while (buf == dbTbl->tRow.creator && rc != NOTFOUND) {
  200.           Name *name = new Name(&dbTbl->tRow, this);
  201.           table->addObject(name, creator); //name; leaf node of creator
  202.           rc = dbTbl->next();              //get next row
  203.        }
  204.     }
  205.     delete dbTbl;                          //close the cursor
  206.     table->setDeleteObjectsOnClose().showTreeTextView();
  207.     IFont font("Helv",10); table->setFont(font);
  208.     ISize xy = desktopWindow()->size(); int w = font.avgCharWidth()*40;
  209.     sizeTo(ISize(w,xy.height() * .96));
  210.     moveTo(IPoint(xy.width() * .98 - w, xy.height() * .02));
  211.     table->setFocus(); show();             //take right side of screen
  212.  };
  213.  
  214.  Tables::Name::Name(struct tabRow *tRow, Tables *owner)
  215.        :IContainerObject(IString(tRow->name))
  216.     { creator = tRow->creator; name = tRow->name; };
  217.  
  218.  void Tables::Name::handleOpen(IContainerControl *table) {
  219.     IString title(creator); title += "."; title += name;
  220.     Details *details = new Details(title, creator, name);
  221.  };
  222.  
  223.  Details::Details(char *title, char *creator, char *name)
  224.        :IFrameWindow (title, SYS_COLUMNS) {
  225.     table=new IContainerControl(SYS_COL_ROWS, this, this);
  226.     setClient(table); event.handleEventsFor(table);
  227.  
  228.     cNam=new IContainerColumn(IContainerObject::iconTextOffset());
  229.     cTyp=new IContainerColumn(offsetof(Row,type));
  230.     cLen=new IContainerColumn(offsetof(Row,length));
  231.     cNul=new IContainerColumn(offsetof(Row,nulls));
  232.     cRem=new IContainerColumn(offsetof(Row,rem));
  233.  
  234.     table->addColumn(&cNam->showSeparators().setHeadingText("name"));
  235.     table->addColumn(&cTyp->showSeparators().setHeadingText("type"));
  236.     table->addColumn(&cLen->showSeparators().setHeadingText("length"));
  237.     table->addColumn(&cNul->showSeparators().setHeadingText("nulls"));
  238.     table->addColumn(&cRem->showSeparators().setHeadingText("remark"));
  239.  
  240.     table->setDeleteObjectsOnClose().showDetailsView().setFocus();
  241.  
  242.     IFont font("Helv", 10); table->setFont(font);   //size logic OK if
  243.     int charW = font.avgCharWidth();                //8 <= point <= 14
  244.     int lineH = font.maxCharHeight() + table->lineSpacing();
  245.     int dispH = font.maxCharHeight() * 1.75 + .5;   //column headings
  246.  
  247.     Database::TabRem *rem = new Database::TabRem();
  248.     char tabRem255Y; rem->getTabRem(creator, name, &tabRem);
  249.     if (tabRem0Y != '\0' ) {
  250.        table->setTitle(tabRem).showTitle().showTitleSeparator();
  251.        dispH += dispH;   //add title height; same as col headings above
  252.     }
  253.     Database::Attributes *att = new Database::Attributes(creator,name);
  254.     int rc = att->next();                     //get first row
  255.     while (rc != NOTFOUND) {
  256.        Row *row = new Row(&att->cRow, this);
  257.        table->addObject(row); dispH += lineH; //allow for display space
  258.        rc = att->next();                      //get next row
  259.     }
  260.     delete att;                               //now close the cursor
  261.  
  262.     int dispW = cNam->show().displayWidth() + 2.5 * charW;   //name
  263.     table->setDetailsViewSplit(cNam, dispW);                 //splitbar
  264.     dispW += cTyp->show().displayWidth() + 3 * charW         //etc...
  265.            + cLen->show().displayWidth() + 3 * charW
  266.            + cNul->show().displayWidth()  + 3 * charW
  267.            + WinQuerySysValue(HWND_DESKTOP, SV_CXVSCROLL);
  268.     dispH += WinQuerySysValue(HWND_DESKTOP, SV_CYHSCROLL);
  269.     IRectangle xy =
  270.              frameRectFor(IRectangle(IPoint(0,0),ISize(dispW,dispH)));
  271.     sizeTo(xy.topRight() - xy.bottomLeft()); show();
  272.  };
  273.  
  274.  Details::Row::Row(struct colRow *cRow, Details *owner)
  275.        :IContainerObject(IString(cRow->name)) {
  276.     type = cRow->type; length = cRow->length;
  277.     nulls = cRow->nulls; rem = cRow->rem;
  278.  };
  279.  
  280.  void Details::Row::handleOpen(IContainerControl *table)
  281.  {
  282.     return;
  283.  };
  284.  
  285.  EMsg::EMsg():IObjectWindow() {
  286.     char msg512Y;
  287.     if (sqlaintp(msg, 512, 0, &sqlca) < 0)
  288.        strcpy(msg,"SQLAINTP error - can't retrieve message text");
  289.     IMessageBox mbx(this);
  290.     mbx.show(msg,mbx.cancelButton|mbx.errorIcon|mbx.applicationModal);
  291.     exit(12);
  292.  };
  293.  
  294.  EMsg::EMsg(char *msg):IObjectWindow() {
  295.     IMessageBox mbx(this);
  296.     mbx.show(msg,mbx.cancelButton|mbx.errorIcon|mbx.applicationModal);
  297.     exit(12);
  298.  };
  299.  
  300.  //dbs.h - interface structs shared by TMap and our database services
  301.  
  302.  #ifndef DBS_H
  303.  #define DBS_H
  304.  #include <sqlcodes.h>         //SQLcode defines for TMap and dbs
  305.  #define NOTFOUND SQL_RC_W100
  306.  
  307.  struct tabRow {               //good stuff from sysibm.systables
  308.     char creator9Y;           //table creator
  309.     char name19Y;             //table name
  310.  };
  311.  
  312.  struct colRow {               //of interest from sysibm.syscolumns
  313.     char name19Y;             //column name
  314.     char rem255Y;             //remark on column
  315.     char type9Y;              //column data type
  316.     short length;              //column data length
  317.     char nulls2Y;             //nulls OK?
  318.  };
  319.  
  320.  #endif
  321.  
  322.  //dbs.sqc - our database services access routines
  323.  
  324.  #include <string.h>
  325.  #include <stdlib.h>
  326.  #include <sql.h>
  327.  #include <sqlenv.h>
  328.  #include "dbs.h"     //our database interface data structures
  329.  
  330.  EXEC SQL INCLUDE sqlca;
  331.  EXEC SQL BEGIN DECLARE SECTION;
  332.     char *db, (*ptbcreator)9Y, (*ptbname)19Y;
  333.  EXEC SQL END DECLARE SECTION;
  334.  
  335.  int connect(char *dbname) {               //connect to database
  336.     sqleisig(&sqlca);                      //install signal handler
  337.     db = dbname;                           //point DBRM at buffer
  338.     EXEC SQL CONNECT TO :*db IN SHARE MODE;
  339.     return sqlca.sqlcode;
  340.  }
  341.  
  342.  void reset() { EXEC SQL CONNECT RESET; }  //close DB2 session
  343.  
  344.  int openTabRow() {                        //cursor on sysibm.systables
  345.     EXEC SQL DECLARE TabRow CURSOR FOR     /* note test of not bound */
  346.        SELECT CREATOR, NAME                /* condition (discovered  */
  347.           FROM SYSIBM.SYSTABLES            /* on first open); useful */
  348.           ORDER BY CREATOR, NAME;          /* for a DBA utility...   */
  349.     EXEC SQL OPEN TabRow;
  350.     if (sqlca.sqlcode == SQL_RC_E818 || sqlca.sqlcode == SQL_RC_E805) {
  351.        sqlabind("dbs.bnd",db,NULL,"","USA",&sqlca); //not bound? try it
  352.        if (sqlca.sqlcode != SQL_RC_OK)              //if bind fails,
  353.           return sqlca.sqlcode;                     //give up, if not,
  354.           else EXEC SQL OPEN TabRow;                //try open again
  355.     }
  356.     return sqlca.sqlcode;
  357.  }
  358.  
  359.  int fetchTabRow(struct tabRow *t) { //get a row from sysibm,systables
  360.     char *c;
  361.     EXEC SQL BEGIN DECLARE SECTION;
  362.        char (*ptcreator)9Y;         /* systables.creator char(8)  */
  363.        char (*ptname)19Y;           /* systables.name varchar(18) */
  364.     EXEC SQL END DECLARE SECTION;
  365.     ptcreator = &t->creator; ptname = &t->name;     //tell DBRM where
  366.     EXEC SQL FETCH TabRow INTO :ptcreator, :ptname; //to put the data
  367.     c = strchr(t->creator,' ');                     //now truncate
  368.     if (c != '\0') *c = '\0';                       //extra spaces
  369.     return sqlca.sqlcode;
  370.  }
  371.  
  372.  void closeTabRow(void) { EXEC SQL CLOSE TabRow; }  //sysibm.systables
  373.  
  374.  int selectTabRem  //get remark on creator.name from sysibm.systables
  375.     (char (*creator)9Y, char (*name)19Y, char (*rem)255Y) {
  376.     EXEC SQL BEGIN DECLARE SECTION;
  377.        char (*ptbrem)255Y;          /* remarks on table, if any   */
  378.        short tbrem_nid;              /* null indicator             */
  379.     EXEC SQL END DECLARE SECTION;
  380.     ptbrem = rem; ptbcreator = creator; ptbname = name;
  381.     EXEC SQL SELECT REMARKS INTO :ptbrem :tbrem_nid
  382.        FROM SYSIBM.SYSTABLES
  383.        WHERE CREATOR = :ptbcreator AND NAME = :ptbname;
  384.     if (tbrem_nid < 0) *rem0Y = NULL;                    //truncate?
  385.     return sqlca.sqlcode;
  386.  }
  387.  
  388.  int openColRow(char (*cre)9Y, char (*nam)19Y) {  //sysibm.syscolumns
  389.     ptbcreator = cre; ptbname = nam;
  390.     EXEC SQL DECLARE ColRow CURSOR FOR
  391.        SELECT NAME, REMARKS, COLTYPE, LENGTH, NULLS, COLNO
  392.           FROM SYSIBM.SYSCOLUMNS
  393.           WHERE TBCREATOR = :ptbcreator AND TBNAME = :ptbname
  394.           ORDER BY COLNO;
  395.     EXEC SQL OPEN ColRow;
  396.     return sqlca.sqlcode;
  397.  }
  398.  
  399.  int fetchColRow(struct colRow *c) { //get row from sysibm.syscolumns
  400.     EXEC SQL BEGIN DECLARE SECTION;
  401.        char (*pcname)19Y;           /* name varchar(18)        */
  402.        char (*pcrem)255Y;           /* remarks varchar(254)    */
  403.        short crem_nid;               /* remarks null indicator  */
  404.        char (*pctype)9Y;            /* coltype char(8)         */
  405.        short clength;                /* length smallint         */
  406.        char (*pcnulls)2Y;           /* nulls char(1)           */
  407.     EXEC SQL END DECLARE SECTION;
  408.     pcname = &c->name; pcrem = &c->rem;       //point at fields in
  409.     pctype = &c->type; pcnulls = &c->nulls;   //syscolumn row structure
  410.     EXEC SQL FETCH ColRow INTO
  411.       :pcname, :pcrem :crem_nid, :pctype, :clength, :pcnulls;
  412.     c->length = clength;
  413.     if (crem_nid < 0) c->rem0Y = NULL;       //null remark? trunc it!
  414.     return sqlca.sqlcode;
  415.  }
  416.  
  417.  void closeColRow(void) { EXEC SQL CLOSE ColRow; }  //sysibm.syscolumns
  418.  
  419.  //that's it, except TMap.def which follows:
  420.  
  421.  NAME    TMAP        WINDOWAPI
  422.  
  423.  DESCRIPTION 'display database table structure'
  424.  
  425.  CODE    LOADONCALL MOVEABLE
  426.  DATA    MOVEABLE   MULTIPLE
  427.  
  428.