home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 18 REXX / 18-REXX.zip / rxsql.zip / RXSQL.C next >
C/C++ Source or Header  |  1993-02-19  |  13KB  |  645 lines

  1. /****************************************************************************
  2.  
  3.     REXX SQL ACCESS MODULE
  4.  
  5.     - RXSQLQUERY
  6.     - RXSQLCLOSE
  7.  
  8. ****************************************************************************/
  9.  
  10. #define DBMSOS2
  11.  
  12. #define INCL_DOS
  13. #define INCL_RXSHV
  14.  
  15. #include <os2.h>
  16. #include <string.h>
  17.  
  18. #include <stdio.h>
  19. #include <malloc.h>
  20. #include <stdlib.h>
  21.  
  22. #include <sqlfront.h>
  23. #include <sqldb.h>
  24.  
  25. #include <rexxsaa.h>
  26.  
  27. #define DLL far pascal
  28.  
  29. /****************************************************************************
  30.  
  31.     SQL: DECLARATIONS/GLOBAL VARIABLES
  32.  
  33. ****************************************************************************/
  34.  
  35. typedef DBPROCESS far * PDBPROCESS;
  36. typedef LOGINREC far * PLOGINREC;
  37.  
  38. #define DATALEN     255
  39.  
  40. char szSQLBuf[DATALEN + 1];    /* common buffer */
  41.  
  42. /****************************************************************************
  43.  
  44.     SQL: CONNECT TO A SERVER
  45.  
  46.     - returns a non-NULL PDBPROCESS on success    
  47.  
  48. ****************************************************************************/
  49.  
  50. PDBPROCESS
  51. SQL_Connect
  52. (
  53.     PSZ pszServer,
  54.     PSZ pszUser,
  55.     PSZ pszPasswd,
  56.     PSZ pszAppname,
  57. )
  58. {
  59.     PDBPROCESS pdbp;
  60.     PLOGINREC plogin;
  61.  
  62.     pdbp = NULL;
  63.  
  64.    if (plogin = dblogin())
  65.     {
  66.        DBSETLUSER(plogin, pszUser);
  67.        DBSETLPWD(plogin, pszPasswd);
  68.        DBSETLAPP(plogin, pszAppname);
  69.  
  70.        pdbp = dbopen(plogin, pszServer);
  71.     }
  72.  
  73.     return pdbp;
  74. }
  75.  
  76. /****************************************************************************
  77.  
  78.     SQL: MESSAGE STORE
  79.  
  80. ****************************************************************************/
  81.  
  82. SHORT    sSQLError = 0;
  83. char szSQLMessage[DATALEN + 1];
  84. BOOL fMsgHandlerAdded = FALSE;
  85.  
  86. /****************************************************************************
  87.  
  88.     SQL: MESSAGE HANDLER
  89.  
  90. ****************************************************************************/
  91.  
  92. SHORT _loadds RxsqlMsgHandler
  93. (
  94.     PDBPROCESS    pdbp,
  95.     DBINT    lMsgNo,
  96.     DBSMALLINT    sMsgState,
  97.     DBSMALLINT    sSeverity,
  98.     PSZ    pszMsgText
  99. )
  100. {
  101.     if (sSeverity > 0)
  102.     {
  103.         sSQLError = sSeverity;
  104.         strcpy(szSQLMessage, pszMsgText);
  105.     }
  106.     return 0;
  107. }
  108.  
  109. /****************************************************************************
  110.  
  111.     SQL: EXECUTE A COMMAND
  112.  
  113.     - returns SUCCEED or FAIL
  114.  
  115. ****************************************************************************/
  116.  
  117. RETCODE SQL_Execute(PDBPROCESS pdbp, PSZ pszCommand)
  118. {
  119.     RETCODE retcode;
  120.  
  121.     sSQLError = 0;
  122.  
  123.     if (((retcode = dbcmd(pdbp, pszCommand)) == SUCCEED) && (sSQLError == 0))
  124.     {
  125.         if (((retcode = dbsqlexec(pdbp)) == SUCCEED) && (sSQLError == 0))
  126.         {
  127.             return SUCCEED;
  128.         }
  129.     }
  130.  
  131.     return FAIL;
  132. }
  133.  
  134. /****************************************************************************
  135.  
  136.     SQL: DISCONNECT FROM A SERVER
  137.  
  138. ****************************************************************************/
  139.  
  140. void SQL_Disconnect(PDBPROCESS pdbp)
  141. {
  142.     dbclose(pdbp);
  143. }
  144.  
  145. /***************************************************************************
  146.  
  147.     SET REX VARIABLE
  148.  
  149. ***************************************************************************/
  150.  
  151. SHORT SetRexVar 
  152. (
  153.             PSZ       pszVar,             /* Variable name            */
  154.             PVOID     pValue,             /* Ptr to value             */
  155.             ULONG     ulLen               /* Value length             */
  156. )
  157. {
  158.     SHVBLOCK RxVarBlock;
  159.     SHORT    retc;
  160.  
  161.     /* Initialize RxVarBlock */
  162.  
  163.     RxVarBlock.shvnext = NULL;
  164.     RxVarBlock.shvname.strptr = pszVar;
  165.     RxVarBlock.shvname.strlength = (ULONG) strlen (pszVar);
  166.     RxVarBlock.shvnamelen = RxVarBlock.shvname.strlength;
  167.     RxVarBlock.shvvalue.strptr = pValue;
  168.     RxVarBlock.shvvalue.strlength = ulLen;
  169.     RxVarBlock.shvvaluelen = ulLen;
  170.     RxVarBlock.shvcode = RXSHV_SYSET;
  171.     RxVarBlock.shvret = RXSHV_OK;
  172.  
  173.     /* set variable in pool */
  174.  
  175.     retc = RxVar (&RxVarBlock);
  176.  
  177.     /* test return codes */
  178.  
  179.     if (retc == RXSHV_NEWV)
  180.     {
  181.         return (RXSHV_OK);
  182.     }
  183.     return (retc);
  184. }
  185.  
  186. /***************************************************************************
  187.  
  188.     MAKE AN INDEXED VARIABLE NAME
  189.  
  190. ***************************************************************************/
  191.  
  192. SHORT RxsqlSetVar(PSZ pszVar, SHORT sRow, SHORT sColumn, PSZ pszValue)
  193. {
  194.     char szName[250];
  195.  
  196.     sprintf(szName, "%s.%d.%d", pszVar, sRow, sColumn);
  197.     return SetRexVar(szName, pszValue, (ULONG)strlen(pszValue));
  198. }
  199.  
  200. /***************************************************************************
  201.  
  202.     REXX QUERY
  203.  
  204.     var.0.0 = status
  205.     var.1.0 = rows (N)
  206.     var.2.0 = columns (M)
  207.  
  208.     var.0.1, ..., var.0.M = column names
  209.     var.K.1, ..., var.K.M = data (K = 1, 2, ..., N)
  210.  
  211. ***************************************************************************/
  212.  
  213. SHORT SQL_Query
  214. (
  215.     PDBPROCESS pdbp, 
  216.     PSZ pszCommand, 
  217.     PSZ pszVar,
  218.     SHORT sMaxRows,
  219.     SHORT sMaxColumns
  220. )
  221. {
  222.     int coltype;
  223.     RETCODE retcode;
  224.  
  225.    SHORT sRow;
  226.     SHORT sColumn;
  227.     SHORT sNumCols;
  228.     SHORT    rc;
  229.  
  230.     char szSQLBuf[DATALEN + 1];
  231.  
  232.     if (rc = RxsqlSetVar(pszVar, 0, 0, "ERROR"))
  233.     {
  234.         return rc;
  235.     }
  236.  
  237.     /*** make a query ***/
  238.  
  239.     if (SQL_Execute(pdbp, pszCommand) != SUCCEED)
  240.     {
  241.         if (sSQLError != 0)
  242.         {
  243.             if (rc = RxsqlSetVar(pszVar, 0, 0, szSQLMessage))
  244.             {
  245.                 return rc;
  246.             }
  247.         }
  248.         return -1;
  249.     }
  250.  
  251.     /*** retrieve data ***/
  252.  
  253.     if (dbresults(pdbp) == SUCCEED)
  254.     {
  255.         /*** retrieve sColumn names ***/
  256.  
  257.         sNumCols = (USHORT)dbnumcols(pdbp);
  258.  
  259.         for (sColumn = 1; sColumn <= sMaxColumns; sColumn ++)
  260.         {
  261.             if (sColumn <= sNumCols)
  262.             {
  263.                 if (rc = RxsqlSetVar(pszVar, 0, sColumn, dbcolname(pdbp, sColumn)))
  264.                 {
  265.                     return rc;
  266.                 }
  267.             }
  268.         }
  269.  
  270.         for (sRow = 1; sRow <= sMaxRows; sRow ++)
  271.         {
  272.             retcode = dbnextrow(pdbp);
  273.  
  274.             if 
  275.             (
  276.                 (retcode == NO_MORE_ROWS)
  277.                 ||
  278.                 (retcode == BUF_FULL)
  279.                 ||
  280.                 (retcode == FAIL)
  281.             )
  282.             {
  283.                 break;
  284.             }
  285.             else
  286.             {
  287.                 sNumCols = (USHORT)dbnumcols(pdbp);
  288.  
  289.                 for (sColumn = 1; sColumn <= sMaxColumns; sColumn ++)
  290.                 {
  291.                     if (sColumn <= sNumCols)
  292.                     {
  293.                         if (dbdata(pdbp, sColumn))
  294.                         {
  295.                             coltype=dbcoltype(pdbp, sColumn);
  296.  
  297.                             dbconvert
  298.                             (
  299.                                 pdbp,
  300.                                 coltype,
  301.                                 dbdata(pdbp, sColumn),
  302.                                 dbdatlen(pdbp, sColumn),
  303.                                 SQLCHAR,
  304.                                 szSQLBuf,
  305.                                 (DBINT)(-1)
  306.                             );
  307.                         }
  308.                         else
  309.                         {
  310.                             strcpy(szSQLBuf, "NULL");
  311.                         }
  312.  
  313.                         if (rc = RxsqlSetVar(pszVar, sRow, sColumn, szSQLBuf))
  314.                         {
  315.                             return -1;
  316.                         }
  317.                     }
  318.                 }
  319.             }
  320.         }
  321.  
  322.         dbcancel(pdbp);
  323.  
  324.         sprintf(szSQLBuf, "%d", sRow);
  325.  
  326.         if (rc = RxsqlSetVar(pszVar, 1, 0, szSQLBuf))
  327.         {
  328.             return -1;
  329.         }
  330.  
  331.         sprintf(szSQLBuf, "%d", sNumCols);
  332.  
  333.         if (rc = RxsqlSetVar(pszVar, 2, 0, szSQLBuf))
  334.         {
  335.             return -1;
  336.         }
  337.  
  338.         if (rc = RxsqlSetVar(pszVar, 0, 0, "OK"))
  339.         {
  340.             return -1;
  341.         }
  342.  
  343.         return 0;        
  344.     }
  345.  
  346.     return -1;
  347. }
  348.  
  349. /****************************************************************************
  350.  
  351.     SQL CONNECTION CACHE STRUCTURE
  352.  
  353. ****************************************************************************/
  354.  
  355. #define NAMESIZE 32
  356.  
  357. typedef struct
  358. {
  359.     PDBPROCESS pdbp;
  360.     char szServer[NAMESIZE];
  361.     char szUser[NAMESIZE];
  362. }
  363. SQLC, far * PSQLC;
  364.  
  365. /****************************************************************************
  366.  
  367.     SQL CONNECTION CACHE
  368.  
  369. ****************************************************************************/
  370.  
  371. #define MAXSQLC    8
  372.  
  373. SQLC sqlcArray[MAXSQLC];
  374.  
  375. PSQLC psqlcEndArray = sqlcArray + MAXSQLC;
  376.  
  377. /****************************************************************************
  378.  
  379.     FIND AN EMPTY CACHE SLOT
  380.  
  381. ****************************************************************************/
  382.  
  383. PSQLC EmptySlot()
  384. {
  385.     PSQLC psqlc;
  386.     
  387.     for (psqlc = sqlcArray; psqlc != psqlcEndArray; psqlc ++)
  388.     {
  389.         if (!psqlc->pdbp)
  390.         {
  391.             return psqlc;
  392.         }
  393.     }
  394.     return NULL;
  395. }
  396.  
  397. /****************************************************************************
  398.  
  399.     FIND A CACHED CONNECTION
  400.  
  401. ****************************************************************************/
  402.  
  403. PSQLC FindSlot(PSZ pszServer, PSZ pszUser)
  404. {
  405.     PSQLC psqlc;
  406.  
  407.     for (psqlc = sqlcArray; psqlc != psqlcEndArray; psqlc ++)
  408.     {
  409.         if 
  410.         (
  411.             (psqlc->pdbp)
  412.             &&
  413.             (!strncmp(psqlc->szServer, pszServer, NAMESIZE))
  414.             &&
  415.             (!strncmp(psqlc->szUser, pszUser, NAMESIZE))
  416.         )
  417.         {
  418.             return psqlc;
  419.         }
  420.     }
  421.     return NULL;
  422. }
  423.  
  424. /****************************************************************************
  425.  
  426.     KILL A CACHED CONNECTION
  427.  
  428.     - close DB connection and make it empty
  429.  
  430. ****************************************************************************/
  431.  
  432. PSQLC KillSlot(PSQLC psqlc)
  433. {
  434.     if (psqlc->pdbp)
  435.     {
  436.         SQL_Disconnect(psqlc->pdbp);
  437.     }
  438.  
  439.     psqlc->pdbp = NULL;
  440.  
  441.     return psqlc;
  442. }
  443.  
  444. /****************************************************************************
  445.  
  446.     SELECT A CACHE SLOT RANDOMLY
  447.  
  448. ****************************************************************************/
  449.  
  450. PSQLC AnySlot()
  451. {
  452.     return sqlcArray + ((USHORT)rand() % MAXSQLC);
  453. }
  454.  
  455. /****************************************************************************
  456.  
  457.     OPEN A CHANNEL
  458.  
  459. ****************************************************************************/
  460.  
  461. PDBPROCESS OpenChannel
  462. (
  463.     PSZ pszServer, 
  464.     PSZ pszDatabase,
  465.     PSZ pszUser,
  466.     PSZ pszPassword
  467. )
  468. {
  469.     PSQLC psqlc;
  470.     PDBPROCESS pdbp;
  471.  
  472.     if ((*pszServer == '\0') || (*pszDatabase == '\0') || (*pszUser == '\0'))
  473.     {
  474.         return NULL;
  475.     }
  476.  
  477.     if (psqlc = FindSlot(pszServer, pszUser))
  478.     {
  479.         pdbp = psqlc->pdbp;
  480.     }
  481.     else
  482.     {
  483.         if (!(psqlc = EmptySlot()))
  484.         {
  485.             psqlc = KillSlot(AnySlot());
  486.         }
  487.  
  488.         pdbp = SQL_Connect(pszServer, pszUser, pszPassword, "RXSQL");
  489.     }
  490.  
  491.     sprintf(szSQLBuf, "use %s", pszDatabase);
  492.  
  493.     if (SQL_Execute(pdbp, szSQLBuf) == SUCCEED)
  494.     {
  495.         psqlc->pdbp = pdbp;
  496.         strncpy(psqlc->szServer, pszServer, NAMESIZE);
  497.         strncpy(psqlc->szUser, pszUser, NAMESIZE);
  498.  
  499.         return pdbp;
  500.     }
  501.     else
  502.     {
  503.         return NULL;
  504.     }
  505. }
  506.  
  507. /***************************************************************************
  508.  
  509.     CREATE A PSZ FROM RXSTRING
  510.  
  511. ***************************************************************************/
  512.  
  513. PSZ    RxToPsz(PRXSTRING prx)
  514. {
  515.     PSZ    pszReturn;
  516.     SHORT    sLength;
  517.  
  518.     sLength = (SHORT)prx->strlength;
  519.  
  520.     if (pszReturn = (PSZ)malloc(sLength + 1))
  521.     {
  522.         memcpy(pszReturn, prx->strptr, sLength);
  523.         pszReturn[sLength] = '\0';
  524.     }
  525.  
  526.     return pszReturn;
  527. }
  528.  
  529. /***************************************************************************
  530.  
  531.     RXSQLQUERY
  532.  
  533. ***************************************************************************/
  534.  
  535. SHORT DLL _loadds RXSQLQUERY
  536. (
  537.     PSZ    pszFuncName,
  538.     SHORT    sArgc,
  539.     PRXSTRING    prxArgv,
  540.     PSZ    pszQueueName,
  541.     PRXSTRING prxReturn
  542. )
  543. {
  544.     PSZ pszServer;
  545.     PSZ pszDatabase;
  546.     PSZ pszUser;
  547.     PSZ pszPassword;
  548.     PSZ pszCommand;
  549.  
  550.     PSZ pszVar;
  551.     PSZ pszMaxRows;
  552.     PSZ pszMaxColumns;
  553.  
  554.     SHORT    sMaxRows;
  555.     SHORT    sMaxColumns;
  556.  
  557.     SHORT sReturn;
  558.  
  559.     PDBPROCESS pdbp;
  560.  
  561.     if (!fMsgHandlerAdded)
  562.     {
  563.         dbmsghandle(RxsqlMsgHandler);
  564.         fMsgHandlerAdded = TRUE;
  565.     }
  566.  
  567.     sprintf(prxReturn->strptr, "ERROR");
  568.     prxReturn->strlength = strlen("ERROR");
  569.  
  570.     sReturn = -1;
  571.  
  572.     if (sArgc == 8)
  573.     {
  574.         pszServer = RxToPsz(prxArgv + 0);
  575.         pszDatabase = RxToPsz(prxArgv + 1);
  576.         pszUser = RxToPsz(prxArgv + 2);
  577.         pszPassword = RxToPsz(prxArgv + 3);
  578.         pszCommand = RxToPsz(prxArgv + 4);
  579.         pszVar = RxToPsz(prxArgv + 5);
  580.         pszMaxRows = RxToPsz(prxArgv + 6);
  581.         pszMaxColumns = RxToPsz(prxArgv + 7);
  582.  
  583.         if (pszMaxRows && pszMaxColumns)
  584.         {
  585.             sMaxRows = atoi(pszMaxRows);
  586.             sMaxColumns = atoi(pszMaxColumns);
  587.  
  588.             if (pszServer && pszDatabase && pszUser && pszPassword && pszVar)
  589.             {
  590.                 sReturn = 0;
  591.  
  592.                 if (pdbp = OpenChannel(pszServer, pszDatabase, pszUser, pszPassword))
  593.                 {
  594.                     if (!(SQL_Query(pdbp, pszCommand, pszVar, sMaxRows, sMaxColumns)))
  595.                     {
  596.                         sprintf(prxReturn->strptr, "OK");
  597.                         prxReturn->strlength = strlen("OK");
  598.                     }
  599.                 }
  600.             }
  601.         }
  602.  
  603.         free(pszServer);
  604.         free(pszDatabase);
  605.         free(pszUser);
  606.         free(pszPassword);
  607.         free(pszCommand);
  608.         free(pszVar);
  609.         free(pszMaxRows);
  610.         free(pszMaxColumns);
  611.     }
  612.  
  613.     return sReturn;
  614. }
  615.  
  616. /***************************************************************************
  617.  
  618.     RXSQLCLOSE
  619.  
  620.     - kills all connections (to cleanup)
  621.  
  622. ***************************************************************************/
  623.  
  624. SHORT DLL _loadds RXSQLCLOSE
  625. (
  626.     PSZ    pszFuncName,
  627.     SHORT    sArgc,
  628.     PRXSTRING    prxArgv,
  629.     PSZ    pszQueueName,
  630.     PRXSTRING prxReturn
  631. )
  632. {
  633.     PSQLC psqlc;
  634.  
  635.     if (sArgc == 0)
  636.     {
  637.         for (psqlc = sqlcArray; psqlc != psqlcEndArray; psqlc ++)
  638.         {
  639.             KillSlot(psqlc);
  640.         }
  641.     }
  642.  
  643.     return 0;
  644. }
  645.