home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 18 REXX / 18-REXX.zip / dbschm.zip / DBSCHEMA.CMD
OS/2 REXX Batch file  |  1993-09-22  |  16KB  |  513 lines

  1. /**
  2. *** ╔════════════════════════════════════════════════════════════════════╗
  3. *** ║                                                                    ║
  4. *** ║      DbSchema v1.1                                                 ║
  5. *** ║          -- Create REXX statements to assist rebuilding a db       ║
  6. *** ║                                                                    ║
  7. *** ║ ────────────────────────────────────────────────────────────────── ║
  8. *** ║                                                                    ║
  9. *** ║               Copyright (c) 1993,  Hilbert Computing               ║
  10. *** ║                                                                    ║
  11. *** ║ ────────────────────────────────────────────────────────────────── ║
  12. *** ║                                                                    ║
  13. *** ║  Send any comments to:                                             ║
  14. *** ║                                                                    ║
  15. *** ║       Hilbert Computing                                            ║
  16. *** ║       1022 N. Cooper                                               ║
  17. *** ║       Olathe, KS 66061                                             ║
  18. *** ║                                                                    ║
  19. *** ║       CIS: [73457,365]                                             ║
  20. *** ║       BBS: 913-829-2450                                            ║
  21. *** ║                                                                    ║
  22. *** ╚════════════════════════════════════════════════════════════════════╝
  23. **/
  24.  
  25.  
  26. arg inputdb .
  27.  
  28. if (inputdb = '') | (inputdb = '?') then
  29.    do
  30.    say "You must specify a database name."
  31.    say
  32.    say "Usage:  DBSCHEMA dbname"
  33.    exit
  34.    end
  35.  
  36. /* Initialize */
  37.  
  38. call LoadFunctions
  39. call StartDatabase inputdb
  40.  
  41. call WriteHeader
  42. call WriteLoadFunctions
  43. call WriteLoadDatabase inputdb
  44.  
  45. /* Find out the tables in this database */
  46.  
  47. call GetTableList
  48.  
  49. /* Generate the create table statements for each table */
  50.  
  51. do i = 1 to TableList.0
  52.  
  53.    call Write "/*" left('─── 'TableList.name.i' ', 70, '─') "*/"
  54.    call Write
  55.    call Write "stmt = 'CREATE TABLE" TableList.Creator.i"."TableList.name.i "',"
  56.    call Write "   '(',"
  57.    call MakeColumns TableList.name.i TableList.Creator.i
  58.  
  59.    /* See if there is a primary key associated with this table and print it */
  60.    /* out if there is.                                                      */
  61.  
  62.    call MakePrimaryKey TableList.name.i TableList.Creator.i
  63.  
  64.    call Write "   ')'"
  65.    call WriteExecuteAndCommit
  66.  
  67.    /* Create all of the indexes on this table */
  68.  
  69.    call MakeIndex TableList.name.i
  70. end
  71. call Write "call sqldbs 'stop using database'"
  72. call Write "exit"
  73. exit
  74.  
  75. /**
  76. *** ┌───────────────────────────────────────────────────────────────────────┐
  77. *** │                                 Test                                  │
  78. *** └───────────────────────────────────────────────────────────────────────┘
  79. **/
  80.  
  81. Test: procedure
  82.    /**
  83.    ***  This will stub into the routines to test them.
  84.    **/
  85.  
  86.    parse arg Field
  87.    say Field
  88.  
  89.    Start = 1
  90.    Found = pos("'", Field, Start)
  91.    do while Found > 0
  92.       Field = insert("'", Field, Found)
  93.       Start = Found + 2
  94.       Found = pos("'", Field, Start)
  95.    end
  96.    say Field
  97.    return
  98.  
  99.  
  100. /**
  101. *** ╔═══════════════════════════════════════════════════════════════════════╗
  102. *** ║                         Application Functions                         ║
  103. *** ╚═══════════════════════════════════════════════════════════════════════╝
  104. **/
  105.  
  106. GetTableList: procedure expose TableList.
  107.    /**
  108.    ***  This will issue an SQL SELECT statement to get the list of the tables
  109.    ***  in this database.  The list is returned in the TableList global
  110.    ***  stem variable in standard REXX format.
  111.    ***
  112.    **/
  113.  
  114.    TableList. = ''
  115.  
  116.    SqlQuery = "select name, creator",
  117.                   "from sysibm.systables",
  118.                   "where creator <> 'SYSIBM' and creator <> 'QRWSYS'"
  119.  
  120.  
  121.    call Sql 'PREPARE s1 INTO :sqlda FROM :SqlQuery'
  122.    if result <> 0 then
  123.       return
  124.  
  125.    call Sql 'DECLARE c1 CURSOR FOR s1'
  126.    call Sql 'OPEN c1'
  127.    call Sql 'FETCH c1 USING DESCRIPTOR :sqlda'
  128.    i = 0
  129.    do while (sqlca.sqlcode = 0)
  130.       i = i + 1
  131.       TableList.name.i    = strip(sqlda.1.sqldata)
  132.       TableList.creator.i = strip(sqlda.2.sqldata)
  133.       call SqlExec 'FETCH c1 USING DESCRIPTOR :sqlda'
  134.    end
  135.    TableList.0 = i
  136.  
  137.    call SQLEXEC 'CLOSE c1'
  138.    return
  139.  
  140.  
  141. MakeColumns: procedure
  142.    /**
  143.    ***  This will issue query the SQLDA for a select on the table and
  144.    ***  generate the code to create the table.
  145.    **/
  146.  
  147.  
  148.    arg Name Creator .
  149.  
  150.    SqlQuery = "select * from" Name
  151.  
  152.    call Sql 'PREPARE s1 INTO :sqlda FROM :SqlQuery'
  153.    if result <> 0 then
  154.       return result
  155.  
  156.    do i = 1 to sqlda.sqld
  157.       Column = strip(sqlda.i.sqlname)
  158.       Type   = SqlType(sqlda.i.sqltype, sqlda.i.sqllen)
  159.       if i = sqlda.sqld then
  160.          call Write "   '"left(Column,24) Type"',"
  161.       else
  162.          call Write "   '"left(Column,24) Type",',"
  163.    end
  164.  
  165.    return
  166.  
  167.  
  168.  
  169. MakePrimaryKey: procedure
  170.    /**
  171.    ***  This routine will issue a select statement to see if this table has
  172.    ***  a primary key.  If so, it will write the keywords as part of the
  173.    ***  CREATE TABLE command.
  174.    ***
  175.    ***  NOTE:  I expected the creator to be the creator of the table, but
  176.    ***         these appear to be created by SYSIBM, so the SELECT statement
  177.    ***         accounts for both possibilities.
  178.    **/
  179.  
  180.    arg TableName Creator
  181.  
  182.    SqlQuery = "select colnames from sysibm.sysindexes",
  183.                   "where tbname = '"TableName"'",
  184.                       "and ((creator = '"Creator"') or (creator='SYSIBM'))",
  185.                       "and uniquerule = 'P'"
  186.  
  187.                    /* "and ((creator = '"Creator"') or (creator='SYSIBM'))", */
  188.                    /* "and creator = '"Creator"'", */
  189.  
  190.    call Sql 'PREPARE s1 INTO :sqlda FROM :SqlQuery'
  191.    if result <> 0 then
  192.       return
  193.  
  194.    call Sql 'DECLARE c1 CURSOR FOR s1'
  195.    call Sql 'OPEN c1'
  196.    call Sql 'FETCH c1 USING DESCRIPTOR :sqlda'
  197.    i = 0
  198.    do while (sqlca.sqlcode = 0)
  199.       i = i + 1
  200.       PrimaryKey = substr(strip(sqlda.1.sqldata),2)  /* Remove leading '+' */
  201.       PrimaryKey = translate(PrimaryKey,',','+')     /* Change '+' to ','  */
  202.       call SqlExec 'FETCH c1 USING DESCRIPTOR :sqlda'
  203.    end
  204.    call SQLEXEC 'CLOSE c1'
  205.  
  206.  
  207.    if i = 0 then
  208.       return
  209.  
  210.    if i > 1 then
  211.       say "There are more than one primary key for table '"TableName"'."
  212.  
  213.    call Write "   ', PRIMARY KEY("PrimaryKey")',"
  214.  
  215.    return
  216.  
  217.  
  218.  
  219. MakeIndex: procedure
  220.    /**
  221.    ***  This routine will issue a select statement to see if this table has
  222.    ***  a primary key.  If so, it will write the keywords as part of the
  223.    ***  CREATE TABLE command.
  224.    **/
  225.  
  226.    arg TableName
  227.  
  228.    SqlQuery = "select name, creator, colnames, uniquerule, colcount",
  229.                   "from sysibm.sysindexes",
  230.                   "where tbname = '"TableName"' and uniquerule <> 'P'"
  231.  
  232.    call Sql 'PREPARE s1 INTO :sqlda FROM :SqlQuery'
  233.    if result <> 0 then
  234.       return
  235.  
  236.    call Sql 'DECLARE c1 CURSOR FOR s1'
  237.    call Sql 'OPEN c1'
  238.    call Sql 'FETCH c1 USING DESCRIPTOR :sqlda'
  239.    i = 0
  240.    do while (sqlca.sqlcode = 0)
  241.       i = i + 1
  242.       Name     = strip(sqlda.1.sqldata)
  243.       Creator  = strip(sqlda.2.sqldata)
  244.       ColNames = strip(sqlda.3.sqldata)
  245.       Unique   = strip(sqlda.4.sqldata)
  246.       Count    = strip(sqlda.5.sqldata)
  247.  
  248.       Columns = DecodeColumnNames(ColNames, Count)
  249.  
  250.       /* Determine if this is a unique column */
  251.  
  252.       if Unique = 'U' then
  253.          UniqueKeyword = " UNIQUE"
  254.       else
  255.          UniqueKeyword = ""
  256.  
  257.       call Write "stmt = 'CREATE"UniqueKeyword "INDEX',"
  258.       call Write "   '"Creator"."Name "ON" TableName"',"
  259.       call Write "   '"Columns"'"
  260.       call Write
  261.       call WriteExecuteAndCommit
  262.  
  263.       call SqlExec 'FETCH c1 USING DESCRIPTOR :sqlda'
  264.    end
  265.    call SQLEXEC 'CLOSE c1'
  266.    return
  267.  
  268.  
  269. SqlType: procedure
  270.  
  271.    arg SqlType, SqlSize
  272.    select
  273.       when SqlType = 384 then DataType = "DATE NOT NULL"
  274.       when SqlType = 385 then DataType = "DATE"
  275.       when SqlType = 388 then DataType = "TIME NOT NULL"
  276.       when SqlType = 389 then DataType = "TIME"
  277.       when SqlType = 392 then DataType = "TIMESTAMP NOT NULL"
  278.       when SqlType = 393 then DataType = "TIMESTAMP"
  279.       when SqlType = 448 then DataType = "VARCHAR("SqlSize") NOT NULL"
  280.       when SqlType = 449 then DataType = "VARCHAR("SqlSize")"
  281.       when SqlType = 452 then DataType = "CHAR("SqlSize") NOT NULL"
  282.       when SqlType = 453 then DataType = "CHAR("SqlSize")"
  283.       when SqlType = 456 then DataType = "LONG VARCHAR("SqlSize") NOT NULL"
  284.       when SqlType = 457 then DataType = "LONG VARCHAR("SqlSize")"
  285.       when SqlType = 464 then DataType = "VARGRAPH("SqlSize") NOT NULL"
  286.       when SqlType = 465 then DataType = "VARGRAPH("SqlSize")"
  287.       when SqlType = 468 then DataType = "GRAPH("SqlSize") NOT NULL"
  288.       when SqlType = 469 then DataType = "GRAPH("SqlSize")"
  289.       when SqlType = 472 then DataType = "LONGVARG("SqlSize") NOT NULL"
  290.       when SqlType = 473 then DataType = "LONGVARG("SqlSize")"
  291.       when SqlType = 480 then DataType = "FLOAT("SqlSize") NOT NULL"
  292.       when SqlType = 481 then DataType = "FLOAT("SqlSize")"
  293.       when SqlType = 484 then DataType = "DECIMAL("SqlSize") NOT NULL"
  294.       when SqlType = 485 then DataType = "DECIMAL("SqlSize")"
  295.       when SqlType = 496 then DataType = "INTEGER NOT NULL"
  296.       when SqlType = 497 then DataType = "INTEGER"
  297.       when SqlType = 500 then DataType = "SMALLINT NOT NULL"
  298.       when SqlType = 501 then DataType = "SMALLINT"
  299.       otherwise
  300.            DataType = "UNKNOWN["SqlType"]"
  301.    end /* select */
  302.    return DataType
  303.  
  304.  
  305. DecodeColumnNames: procedure
  306.    /**
  307.    ***  This will convert the COLNAMES column in SYSINDEXES to the syntax
  308.    ***  required by the CREATE INDEX command.
  309.    **/
  310.  
  311.    arg Names, Count
  312.  
  313.    Columns = '('
  314.  
  315.    /* Check for ascending or descending key */
  316.  
  317.    if left(Names,1) = '-' then
  318.       order = 'DESC'
  319.    else
  320.       order = 'ASC'
  321.    Names = substr(Names,2)
  322.  
  323.    do (Count - 1)
  324.       psn = verify(Names, '-+', 'Match')
  325.       NextColumn = left(Names, (psn-1))
  326.       Names = substr(Names, psn)
  327.  
  328.       Columns = Columns NextColumn order','
  329.  
  330.       /* Check for ascending or descending key */
  331.  
  332.       if left(Names,1) = '-' then
  333.          order = 'DESC'
  334.       else
  335.          order = 'ASC'
  336.       Names = substr(Names,2)
  337.    end
  338.    Columns = Columns Names order ')'
  339.  
  340.    return Columns
  341.  
  342.  
  343. /**
  344. *** ╔═══════════════════════════════════════════════════════════════════════╗
  345. *** ║                      Database Manager Functions                       ║
  346. *** ╚═══════════════════════════════════════════════════════════════════════╝
  347. **/
  348.  
  349.  
  350. StartDatabase: procedure
  351.    /**
  352.    ***  This will start the Database Manager and open the database with
  353.    ***  the name that was passed
  354.    **/
  355.  
  356.    arg Database
  357.  
  358.    call sqldbs 'start database manager'
  359.    if Database <> '' then
  360.       call sqldbs 'start using database' Database
  361.    return
  362.  
  363.  
  364. Sql:
  365.    /**
  366.    ***  This will issue the SqlExec API call and check the return codes and
  367.    ***  results.  It will terminate on error.
  368.    **/
  369.  
  370.    arg SqlCommand
  371.  
  372.    call SqlExec SqlCommand
  373.    if result <> 0 then
  374.       say "Return code ["result"] from SQLEXEC.  You are probably out-of-storage."
  375.    else
  376.       select
  377.          when SQLCA.SQLCODE =   0 then nop /* Ok         */
  378.          when SQLCA.SQLCODE = 100 then nop /* Not found. */
  379.          otherwise
  380.             say "SQL code ("SQLCA.SQLCODE"):" SQLCA.SQLMSG
  381.       end /* select */
  382.    return SQLCA.SQLCODE
  383.  
  384. /**
  385. *** ╔═══════════════════════════════════════════════════════════════════════╗
  386. *** ║                            Misc Functions                             ║
  387. *** ╚═══════════════════════════════════════════════════════════════════════╝
  388. **/
  389.  
  390. Write: procedure
  391.    /**
  392.    ***  This will write the line to the command file
  393.    **/
  394.  
  395.    parse arg line
  396.  
  397.    say line
  398.    return
  399.  
  400.  
  401. WriteHeader: procedure
  402.    /**
  403.    *** Write the static header information
  404.    **/
  405.    call Write "/** ╔═══════════════════════════════════════════════════════════════════════╗"
  406.    call Write "*** ║                                                                       ║"
  407.    call Write "*** ║         This code was generated by the DBSCHEMA v1.1 command.         ║"
  408.    call Write "*** ║                                                                       ║"
  409.    call Write "*** ╚═══════════════════════════════════════════════════════════════════════╝"
  410.    call Write "**/"
  411.    call Write
  412.    return
  413.  
  414. WriteLoadFunctions: procedure
  415.    /**
  416.    ***  Write the code to load the DLLs to the generated REXX file
  417.    **/
  418.  
  419.    call Write "/* Load the Database Manager DLL */"
  420.    call Write
  421.    call Write "if RxFuncQuery('SQLEXEC') <> 0 then                 "
  422.    call Write "   do                                               "
  423.    call Write "   RCode = RxFuncAdd('SQLEXEC','SQLAR','SQLEXEC')   "
  424.    call Write "   if RCode <> 0 then                               "
  425.    call Write "      call Error 1001,0,RCode                       "
  426.    call Write "   end                                              "
  427.    call Write "                                                    "
  428.    call Write "if RxFuncQuery('SQLDBS') <> 0 then                  "
  429.    call Write "   do                                               "
  430.    call Write "   RCode = RxFuncAdd('SQLDBS', 'SQLAR', 'SQLDBS')   "
  431.    call Write "   if RCode <> 0 then                               "
  432.    call Write "      call Error 1001,0,RCode                       "
  433.    call Write "   end                                              "
  434.    call Write
  435.    return
  436.  
  437.  
  438. WriteLoadDatabase: procedure
  439.    /**
  440.    ***  This will write the statements to start the database manager
  441.    ***  and start using the database
  442.    **/
  443.  
  444.    parse arg Database
  445.  
  446.    call Write "/* Start the Database Manager and start using the database */"
  447.    call Write
  448.    call Write "call sqldbs 'start database manager'"
  449.    call Write "call sqldbs 'start using database" Database"'"
  450.    call Write
  451.    return
  452.  
  453. WriteExecuteAndCommit: procedure
  454.    /**
  455.    ***  This will write the statements for the EXECUTE IMMEDIATE and
  456.    ***  COMMIT SQL.
  457.    **/
  458.    call Write "call sqlexec 'EXECUTE IMMEDIATE :stmt'"
  459.    call Write "if sqlca.sqlcode = 0 then"
  460.    call Write "   say 'Ok.'"
  461.    call Write "else"
  462.    call Write "   say 'SQL message: ['sqlca.sqlcode']' sqlca.sqlmsg"
  463.    call Write
  464.    call Write "SqlCommit = 'COMMIT'"
  465.    call Write "call SqlExec 'EXECUTE IMMEDIATE :SqlCommit'"
  466.    call Write
  467.    return
  468.  
  469.  
  470. LoadFunctions: procedure
  471.    /**
  472.    *** This will load the REXX entry points for manipulating the OS/2 ES
  473.    *** Database Manager
  474.    **/
  475.  
  476.    if RxFuncQuery('SQLEXEC') <> 0 then
  477.       do
  478.       RCode = RxFuncAdd('SQLEXEC','SQLAR','SQLEXEC')
  479.  
  480.       if RCode <> 0 then
  481.          do
  482.          say "Return code ["RCode"] from RxFuncAdd for SQLEXEC"
  483.          exit RCode
  484.          end
  485.       end
  486.  
  487.    if RxFuncQuery('SQLDBS') <> 0 then
  488.       do
  489.       RCode = RxFuncAdd('SQLDBS', 'SQLAR', 'SQLDBS')
  490.  
  491.       if RCode <> 0 then
  492.          do
  493.          say "Return code ["RCode"] from RxFuncAdd for SQLEXEC"
  494.          exit RCode
  495.          end
  496.       end
  497.  
  498.    if RxFuncQuery('SysLoadFuncs') <> 0 then
  499.       do
  500.       RCode = RxFuncAdd('SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs')
  501.  
  502.       if RCode <> 0 then
  503.          do
  504.          say "Return code ["RCode"] from RxFuncAdd for SysLoadFuncs"
  505.          exit RCode
  506.          end
  507.       end
  508.  
  509.       /* Load the rest of the entry points */
  510.  
  511.       call SysLoadFuncs
  512.    return
  513.