ifmxdb.c
上传用户:aidanglao
上传日期:2007-01-07
资源大小:69k
文件大小:23k
源码类别:

Oracle数据库

开发平台:

Unix_Linux

  1. /* ifmxdb.c - Informix SQLweb Interface
  2. /*
  3. /* Copyright (c) 1995-1999 Applied Information Technologies, Inc.
  4. /* All Rights Reserved.
  5. /*  
  6. /* Distributed uder the GNU General Public License which was included in
  7. /* the file named "LICENSE" in the package that you recieved.
  8. /* If not, write to:
  9. /* The Free Software Foundation, Inc.,
  10. /* 675 Mass Ave, Cambridge, MA 02139, USA.
  11.  */
  12. #include <stdlib.h>
  13. #include <ctype.h>
  14. #include <string.h>
  15. #include <malloc.h>
  16. #include "sqlweb.h"
  17. /*
  18. /* Informix INCLUDES.  
  19.  */
  20. #include "infxcli.h"
  21. /*
  22. /* The DBINFO struct.  
  23.  */
  24. typedef struct {
  25.     long ind; /* Indicator Variable BIND & SELECT */
  26.     SDWORD rlen; /* Bind/Fetch Return Length  */
  27.     char *pValue; /* Another pointer to the SYMBOL Value */
  28.     long iLen; /* Symbol pValue's (Malloced) Length */
  29.     SWORD iScale; /* Scale of Number ... */
  30.     SWORD iColType; /* Type of Number ... */
  31. } DbInfo_t;
  32. /*
  33. /* Internal/Private Functions
  34.  */
  35. static eBoolean_t DescribeBindVars  (SQLWEB_CURSOR *pCursor);
  36. static eBoolean_t DescribeSelectVars(SQLWEB_CURSOR *pCDA);
  37. static eBoolean_t GetCursorIndex(int *piCursorIndex);
  38. static void       PushDBErr(HENV pLDA,HSTMT pCDA,char *pErrMsg);
  39. static eBoolean_t SetDbNulls(DbInfo_t *pDbInfo);
  40. static DbInfo_t * NewDbInfo();
  41. static eBoolean_t FreeDbInfo(DbInfo_t *pDbInfo);
  42. static eBoolean_t PrepareParameters(SQLWEB_CURSOR *pCursor);
  43. static eBoolean_t FreeStmt(SQLWEB_CURSOR *pCursor);
  44. #define MAX_ITEM_BUFFER_SIZE    33
  45. #define MAX_SQL_IDENTIFIER      31
  46. /*
  47. /* Global Variables
  48.  */
  49. char 
  50.      *gpIfExpr = "SELECT 1 SQLWEB_IF_EXPR FROM DUAL WHERE"
  51.     ,*gpNullSelect = "SELECT 1 FROM DUAL WHERE 1=2"
  52.     ;
  53. static LIST *glDbInfoList=NULL_LIST;
  54. /*
  55. /* THE LDA Array....
  56.  */
  57. HENV gaLDA[MAX_CONNECTIONS]; /* Lda_Def gaLDA[MAX_CONNECTIONS]; */
  58. HDBC gaHDA[MAX_CONNECTIONS]; /* ub1     gaHDA[MAX_CONNECTIONS][512]; */
  59. /*
  60. /* THE CURSOR Array
  61.  */
  62. HSTMT gaCDA[MAX_CURSORS]; /* Cda_Def gaCDA[MAX_CURSORS]; */
  63. eBoolean_t gbaOpen[MAX_CURSORS]; /* Open indicator */
  64. /*
  65. /* MAIN for testing only
  66. #define MAIN_TEST
  67.  */
  68. #ifdef MAIN_TEST
  69. eBoolean_t gbCookFlag;
  70. main(){
  71.     char sBuf[BUFSIZ];
  72.     FRMSym("name","steve");
  73.     FRMSym("nameb","so");
  74.     FRMSym("V2PGN","55");
  75.     (void)x();
  76.     while( MsgPop(sBuf) ) {
  77. printf("%sn",sBuf);
  78.     }
  79. }
  80. int x(){
  81.     SQLWEB_LDA lda;
  82.     SQLWEB_CURSOR cda;
  83.     char *p1 = "SELECT n
  84.              pi.pi_level n
  85.             ,pi.page_gen_nbr pgn n
  86.             ,nvl(pi.pi_seq_nbr,'0') pi_seq_nbr n
  87.             ,pi.pi_gen_nbr n
  88.             ,pi.tag_name n
  89.             ,nvl(pi.page_gen_nbr_link,'') page_gen_nbr_link n
  90.             ,pi.pi_contents n
  91.     FROM html_V_page_items pi n
  92.     WHERE pi.page_gen_nbr = :V2PGN ";
  93.     char *pSql1 = "select to_char(sysdate,'mm/dd/yyyy hh24:mi') da_dat n
  94. ,t.*n
  95. from html_pages tn
  96. where :name='steve' and :nameb='so'";
  97.     char *pDaDat, *pPageName, *pPageTitle;
  98.     RETeFalse(DbConnect("sqlweb/sqlweb",&lda),"Connect Failed");
  99.     RETeFalse(DbOpenCursor(&lda,p1,&cda),"Open Failed");
  100.     GetSymbolValueREF("PI_CONTENTS",&pDaDat);
  101.     GetSymbolValueREF("PI_SEQ_NBR",&pPageName);
  102.     GetSymbolValueREF("TAG_NAME",&pPageTitle);
  103.     do{
  104. RETeFalse(DbFetchCursor(&cda,eFalse),"Fetch Failed");
  105. fprintf(stderr,"%s %s C(%s)n",pPageName,pPageTitle,pDaDat);
  106.     } while(cda.bFound==eTrue);
  107.     RETeFalse(DbDisconnect(&lda,eFalse),"Disconnect Failed");
  108.     return(0);
  109. }
  110. #endif /* MAIN_TEST */
  111. /*
  112. /* Connect to the INFORMIX DATABASE.
  113. /* The pConnect parameter should be passed as (char *)0 to instruct
  114. /*     the DBI to use the INFORMIX_DRIVERCONNECT Symobl.  The pConnect is
  115. /* only used to Override the INFORMIX_DRIVERCONNECT symbol.
  116. /* usage:
  117. /* SQLWEB_LDA lLda;
  118. /* RETeFalse( DbConnect((char*)0     ,&lLda), "Connect Failed");
  119. /* RETeFalse( DbConnect("scott/tiger",&lLda), "Connect Failed");
  120.  */
  121. eBoolean_t
  122. DbConnect(char *pConnect /* Database Specific Connect String */
  123.  ,SQLWEB_LDA *pLDA /* This Function must Fills-in
  124. /* the SQLWEB_LDA structure
  125.  */
  126.  )
  127. {
  128.     static int siConnectIndex; /* Connections are NOT re-used. */
  129.     char sEnvBuf[MAX_TOKVAL_SIZE]
  130. ,sBuf[BUFSIZ]
  131. ,*pBuf
  132. ;
  133.     short sOutSize;
  134.     RETCODE rc;
  135.     if( siConnectIndex > MAX_CONNECTIONS ){
  136. MsgPush("Exceeded Maximum Connections");
  137. return(eFalse);
  138.     }
  139.     /*
  140.     /* Must be Sure INFORMIXDIR is in the Environment!
  141.      */
  142.     pBuf = getenv("INFORMIXDIR");
  143. /* The Environment overrides the SYMBOL TABLE
  144.  */
  145.     if(!pBuf) {
  146. RETeFalse(GetSymbolValueREF("INFORMIXDIR",&pBuf)
  147.  ,"Can't find INFORMIXDIR"
  148.  );
  149. sprintf(sEnvBuf,"INFORMIXDIR=%s",pBuf);
  150. putenv(DupBuf(sEnvBuf));
  151.     }
  152.     /*
  153.     /* pConnect Parameter overrides the INFORMIX_DRIVERCONNECT env variable
  154.      */
  155.     if( pConnect ) {
  156. pBuf=pConnect;
  157.     } else {
  158. RETeFalse(GetSymbolValueREF("INFORMIX_DRIVERCONNECT",&pBuf)
  159.  ,"Can't find INFORMIX_DRIVERCONNECT"
  160.  );
  161.     }
  162.     /*
  163.     /* Update the Generic DBI LDA Struct
  164.      */
  165.     pLDA->iLdaIndex = siConnectIndex;
  166.     pLDA->bConnected= eFalse;
  167.     pLDA->pConnect  = pBuf;
  168.     /* Allocate the Environment handle
  169.      */
  170.     if( SQLAllocEnv( &gaLDA[pLDA->iLdaIndex] ) ) {
  171. PushDBErr(gaLDA[pLDA->iLdaIndex]
  172.  ,(HSTMT)0
  173.  ,"Connect Failed (SQLAllocEnv)."
  174.  );
  175.         return(eFalse);
  176.     }
  177.     /* Allocate the Connection handle
  178.      */
  179.     rc=SQLAllocConnect(gaLDA[pLDA->iLdaIndex],&gaHDA[pLDA->iLdaIndex]);
  180.     if(rc){
  181. PushDBErr(gaLDA[pLDA->iLdaIndex]
  182.  ,(HSTMT)0
  183.  ,"Connect Failed (SQLAllocConnect)."
  184.  );
  185.         return(eFalse);
  186.     }
  187.     rc=SQLDriverConnect(gaHDA[pLDA->iLdaIndex]
  188.  ,NULL
  189.  ,(UCHAR*)pBuf
  190.  ,SQL_NTS
  191.  ,(UCHAR*)sBuf
  192.  ,BUFSIZ
  193.  ,&sOutSize
  194.  ,SQL_DRIVER_NOPROMPT
  195.  );
  196.     if(rc!=SQL_SUCCESS && rc!=SQL_SUCCESS_WITH_INFO) {
  197. PushDBErr(gaLDA[pLDA->iLdaIndex]
  198.  ,(HSTMT)0
  199.  ,"Connect Failed (SQLDriverConnect)."
  200.  );
  201. return(eFalse);
  202.     }
  203.     siConnectIndex++;  /* Bump the Connection Index */
  204.     pLDA->bConnected = eTrue; /* Set Connected Flag */
  205.     DebugHTML(__FILE__,__LINE__,3,"DbConnect(%s) OK!",pBuf);
  206.     return(eTrue); /* Oh, sweet success! */
  207. }
  208. /*
  209. /* Disconnect from the DATABASE.
  210. /* bCommit Flag:  bCommit=eTrue  means essentially "COMMIT RELEASE"
  211. /*   bCommit=eFalse means essentially "ROLLBACK RELEASE"
  212. /* usage:
  213. /* SQLWEB_LDA lLda;
  214. /* ... connect ...
  215. /* RETeFalse( DbDisonnect(&lLda,eTrue), "Connect Failed"); -- Commit
  216. /* RETeFalse( DbDisonnect(&lLda,eFalse),"Connect Failed"); -- Rollback
  217.  */
  218. eBoolean_t
  219. DbDisconnect(SQLWEB_LDA *pLDA /* LDA struct from DbConnect() */
  220.     ,eBoolean_t bCommit /* Commit/Rollback Flag */
  221.     )
  222. {
  223.     /* Perform the COMMIT/ROLLBACK
  224.      */
  225.     if(ISeTrue(bCommit)) (void)DbCommit(pLDA);
  226.     else  (void)DbRollback(pLDA);
  227.     if(SQLDisconnect(&gaLDA[pLDA->iLdaIndex])){
  228. PushDBErr(gaLDA[pLDA->iLdaIndex]
  229.  ,(HSTMT)0
  230.  ,"Disconnect Failed."
  231.  );
  232. return(eFalse);
  233.     }
  234.     pLDA->bConnected = eFalse; /* Set Connected Flag */
  235.     return(eTrue);
  236. }
  237. /*
  238. /* Commit Transaction
  239.  */
  240. eBoolean_t
  241. DbCommit(SQLWEB_LDA *pLDA) /* LDA struct from DbConnect() */
  242. {
  243.     RETCODE rc;
  244.     rc=SQLTransact(gaLDA[pLDA->iLdaIndex],gaHDA[pLDA->iLdaIndex],SQL_COMMIT);
  245.     if(rc!=SQL_SUCCESS && rc!=SQL_SUCCESS_WITH_INFO) {
  246. PushDBErr(gaLDA[pLDA->iLdaIndex]
  247.  ,(HSTMT)0
  248.  ,"Commit Failed."
  249.  );
  250. return(eFalse);
  251.     }
  252.     return(eTrue);
  253. }
  254. /*
  255. /* Rollback a Transaction.
  256.  */
  257. eBoolean_t
  258. DbRollback(SQLWEB_LDA *pLDA) /* LDA struct ftom DbConnect() */
  259. {
  260.     RETCODE rc;
  261.     rc=SQLTransact(gaLDA[pLDA->iLdaIndex],gaHDA[pLDA->iLdaIndex],SQL_ROLLBACK);
  262.     if(rc!=SQL_SUCCESS && rc!=SQL_SUCCESS_WITH_INFO) {
  263. PushDBErr(gaLDA[pLDA->iLdaIndex]
  264.  ,(HSTMT)0
  265.  ,"Rollback Failed."
  266.  );
  267. return(eFalse);
  268.     }
  269.     return(eTrue);
  270. }
  271. /*
  272. /* Open a CURSOR. Must deal with SELECT and non-SELECT statements.
  273. /* All BIND variables are taken from the SYMBOL TABLE
  274. /* All SELECT-LIST variables are installed into the SYMBOL TABLE
  275. /* usage:
  276. /* SQLWEB_LDA lLda;
  277. /* SQLWEB_CURSOR cCur;
  278. /* char *pSQL = "select ename from emp where ename like :SYM_NAME";
  279. /* ... connect ...
  280. /* RETeFalse( DbOpenCursor(&lLda,pSQL,&cCur), "Open Failed");
  281.  */
  282. eBoolean_t
  283. DbOpenCursor(SQLWEB_LDA *pLDA /* SQLWEB LDA struct created by DbConnect() */
  284.     ,char *pStmt /* SQL Statement, All BIND Variables will
  285. /* be extracted from the SYMBOL TABLE and
  286. /* The SELECT LIST must be INSTALLED into
  287. /* The SYMBOL TABLE
  288.  */
  289.     ,SQLWEB_CURSOR *pCursor
  290. /* This Function must Populate
  291. /* The SQLWEB_CURSOR structure
  292.  */
  293.     )
  294. {
  295.     int iCursorIndex;
  296.     RETCODE rc;
  297.     if(pStmt==(char*)0) return(eTrue);
  298.     if(pLDA==(SQLWEB_LDA*)0) return(eTrue);
  299.     if(pCursor==(SQLWEB_CURSOR*)0) return(eTrue);
  300.     /* Supports Delayed Connect
  301.      */
  302.     if( ISeFalse(pLDA->bConnected)) {
  303. RETeFalse(DbConnect(0,pLDA),"DbOpen (Connect) Failed");
  304.     }
  305.     RETeFalse(GetCursorIndex(&iCursorIndex),"GetCursorIndex Failed");
  306.     DebugHTML(__FILE__,__LINE__,4,"DbOpenCursor:CursorIndex=%d",iCursorIndex);
  307.     /*
  308.     /* Initialize the SQLWEB_CURSOR
  309.      */
  310.     pCursor->pLDA  = pLDA;
  311.     pCursor->iCursorIndex= iCursorIndex;
  312.     pCursor->bOpen  = eFalse;
  313.     gbaOpen[iCursorIndex] = eFalse;
  314.     pCursor->bFound  = eFalse;
  315.     pCursor->pStmt  = pStmt;
  316.     pCursor->lSelect  = l_create("INORDER"); /* Indicator Variables */
  317.     pCursor->lBind  = l_create("INORDER"); /* cleanup */
  318.     /* Modify the SQL Stmt to meet Informix standards
  319.     /* -- replace symbol refs with '?'
  320.      */
  321.     RETeFalse(PrepareParameters(pCursor),"PrepareParameters Failed");
  322.     /* Allocate the statement handle
  323.      */
  324.     rc=SQLAllocStmt(gaHDA[pLDA->iLdaIndex],&gaCDA[iCursorIndex]);
  325.     if(rc!=SQL_SUCCESS && rc!=SQL_SUCCESS_WITH_INFO)
  326.     {
  327. PushDBErr(gaLDA[pLDA->iLdaIndex]
  328.  ,gaCDA[iCursorIndex]
  329.  ,"SQLAllocStmt Failed."
  330.  );
  331. return(eFalse);
  332.     }
  333.     rc=SQLPrepare(gaCDA[iCursorIndex],(UCHAR*)pCursor->pStmt,SQL_NTS);
  334.     if(rc!=SQL_SUCCESS && rc!=SQL_SUCCESS_WITH_INFO) {
  335. PushDBErr(gaLDA[pLDA->iLdaIndex]
  336.  ,gaCDA[iCursorIndex]
  337.  ,"SQLPrepare Failed."
  338.  );
  339. return(eFalse);
  340.     }
  341.     /*
  342.     /* Describe the BIND & SELECT-List variables
  343.      */
  344.     RETeFalse(DescribeBindVars(pCursor),"Describe Bind Variables Failed");
  345.     RETeFalse(DescribeSelectVars(pCursor) ,"Describe Select Variables Failed");
  346.     /* Off with his head! --EXECUTE THE STMT
  347.      */
  348.     rc=SQLExecute( gaCDA[iCursorIndex] );
  349.     if(rc!=SQL_SUCCESS && rc!=SQL_SUCCESS_WITH_INFO) {
  350. PushDBErr(gaLDA[pLDA->iLdaIndex]
  351.  ,gaCDA[iCursorIndex]
  352.  ,"SQLExecute Failed."
  353.  );
  354. return(eFalse);
  355.     }
  356.     /* pCursor->bOpen is set by "side-effect" in DescribeSelectVars...
  357.      */
  358.     if(ISeFalse(pCursor->bOpen)) {
  359. RETeFalse(FreeStmt(pCursor),"FreeStmt Failed");
  360.     }
  361.     /* Alls well that end well!
  362.      */
  363.     return(eTrue);
  364. }
  365. /*
  366. /* Fetch a ROW from the CURSOR and install each SELECT ITEM into
  367. /* The SYMBOL TABLE.
  368. /* bClose Flag:   bClose=eTrue  means CLOSE CURSOR after the FETCH
  369. /*   bClose=eFalse means CLOSE CURSOR when exhausted
  370. /*
  371. /* ******* SPECIAL NOTE ABOUT RETURN CODE: *******
  372. /* ONLY return(eFalse) on DATABASE ERROR
  373. /* USE pCursor->bFound=eFalse; to indicate NOT FOUND
  374. /* ******* SPECIAL NOTE ABOUT RETURN CODE: *******
  375. /* usage:
  376. /* SQLWEB_CURSOR cCur;
  377. /* ... connect ...
  378. /* ... open    ...
  379. /* for(;;) {
  380. /*     RETeFalse( DbFetchCursor(&cCur,eFalse), "Close Failed");
  381. /*     if(cCur.bFound) break;
  382. /* }
  383.  */
  384. eBoolean_t
  385. DbFetchCursor(SQLWEB_CURSOR *pCursor /* the CURSOR (from Open) */
  386.      ,eBoolean_t bClose /* Force Close after Fetch */
  387.      )
  388. {
  389.     eBoolean_t bStatus;
  390.     RETCODE rc;
  391.     if(ISeFalse(pCursor->bOpen)) {
  392. DebugHTML(__FILE__,__LINE__,3,"DbFetchCursor:Not Open");
  393. pCursor->bFound=eFalse;
  394. return(eTrue);
  395.     }
  396.     /* Process the Fetch Request 
  397.      */
  398.     rc=SQLFetch(gaCDA[pCursor->iCursorIndex]);
  399.     if(rc!=SQL_SUCCESS && rc!=SQL_SUCCESS_WITH_INFO) {
  400. pCursor->bFound = eFalse;
  401. if(rc==SQL_NO_DATA_FOUND) {
  402.     bStatus =eTrue;
  403. } else {
  404.     PushDBErr(gaLDA[pCursor->pLDA->iLdaIndex]
  405.      ,gaCDA[pCursor->iCursorIndex]
  406.      ,"SQLFetch failed."
  407.      );
  408.     bStatus = eFalse;
  409. }
  410. /*
  411. /* Close the Cursor
  412.  */
  413. bStatus = FreeStmt(pCursor);
  414. /*
  415. /* Free the DbInfo_t's Created for this Cursor
  416.  */
  417. l_scan(pCursor->lBind,(PFI)FreeDbInfo);
  418. l_scan(pCursor->lSelect,(PFI)FreeDbInfo);
  419. return(bStatus);
  420.     }
  421.     /* OK, Found a ROW, Check for NULLs
  422.      */
  423.     l_scan(pCursor->lSelect,(PFI)SetDbNulls);
  424.     pCursor->bFound=eTrue;
  425.     bStatus = eTrue;
  426.     /*
  427.     /* Force a Close, good for single row queries
  428.      */
  429.     if(bClose)
  430. return( FreeStmt(pCursor) );
  431.     return(eTrue);
  432. }
  433. /*************************************************************
  434. /* 
  435. /* Supporting Routines, not part of the API, all additional
  436. /* functions should be declared static!
  437.  */
  438. /*
  439. /* Set NULLs based on the INDICATOR Variable
  440. /* This is called from the DbFetchCursor() routine
  441.  */
  442. static eBoolean_t
  443. SetDbNulls(DbInfo_t *pDbInfo)
  444. {
  445.     if(pDbInfo->rlen==SQL_NULL_DATA && pDbInfo->pValue) {
  446. DebugHTML(__FILE__,__LINE__,3,"Fetched a Null");
  447. memset(pDbInfo->pValue,0,pDbInfo->iLen);
  448.     }
  449.         switch (pDbInfo->iColType)
  450.         {
  451.     case SQL_DECIMAL:
  452.     case SQL_DOUBLE:
  453.     case SQL_REAL:
  454.     case SQL_INTEGER:
  455.     case SQL_SMALLINT:
  456. if((pDbInfo->iScale)==0) {
  457.     char *p;
  458.     for(p=pDbInfo->pValue;*p;p++)if(*p=='.')*p=0;
  459. }
  460.         }
  461.     return(eTrue);
  462. }
  463. /*
  464. /* Get the Next Available CursorIndex from
  465. /* the gaCDA array.
  466.  */
  467. static eBoolean_t
  468. GetCursorIndex(int *piCursorIndex)
  469. {
  470.     static int siCursorIndex;
  471.     int iStart, i;
  472.     for(i=0, iStart=siCursorIndex
  473.     ;i==0 || (iStart != siCursorIndex && i>0)
  474.     ;i++, siCursorIndex = (siCursorIndex+1)%MAX_CURSORS)
  475.     {
  476. /* the gbaOpen array simply lets me know when
  477. /* a cursor has been opened or closed so that
  478. /* in this routine I can re-use cursors!
  479.  */
  480. if( gbaOpen[siCursorIndex]==eFalse ) {
  481.     (*piCursorIndex) = siCursorIndex;
  482.     return(eTrue);
  483. }
  484.     }
  485.     MsgPush("Exceeded Maximum Cursors");
  486.     return(eFalse);
  487. }
  488. /*
  489. /* Describe the BIND Variables...
  490. /*    this is much simplified since the parsing of the SQL
  491. /*    string itself is handled in the PrepareParameters() function
  492. /*    which was a hack of the origional decrbindvars...
  493.  */
  494. static eBoolean_t
  495. DescribeBindVars(SQLWEB_CURSOR *pCursor)
  496. {
  497.     int iParamCnt=1;
  498.     DbInfo_t *pDbInfo;
  499.     for( pDbInfo=l_ffirst(pCursor->lBind);
  500.  pDbInfo;
  501.  pDbInfo=l_fnext(pCursor->lBind))
  502.     {
  503. RETCODE rc;
  504. if( !pDbInfo->pValue) {
  505.      pDbInfo->pValue = DupBuf("");
  506.      pDbInfo->rlen = SQL_NULL_DATA;
  507. }
  508. else if( !*pDbInfo->pValue) {
  509.      pDbInfo->rlen = SQL_NULL_DATA;
  510. }
  511. else pDbInfo->rlen = SQL_NTS;
  512. /* bug fix ... */
  513. pDbInfo->rlen = SQL_NTS;
  514. /* bug fix ... */
  515. rc=SQLBindParameter( gaCDA[pCursor->iCursorIndex]
  516.     ,iParamCnt++
  517.     ,SQL_PARAM_INPUT
  518.     ,SQL_C_CHAR /* SQL_C_CHAR */
  519.     ,SQL_CHAR /* SQL_CHAR */
  520.     ,pDbInfo->iLen+1
  521.     ,0
  522.     ,pDbInfo->pValue /* &pDbInfo->pValue[0] */
  523.     ,pDbInfo->iLen+1
  524.     ,&pDbInfo->rlen
  525.     );
  526. if(rc!=SQL_SUCCESS && rc!=SQL_SUCCESS_WITH_INFO) {
  527.     PushDBErr(gaLDA[pCursor->pLDA->iLdaIndex]
  528.      ,gaCDA[pCursor->iCursorIndex]
  529.      ,"SQLBindParameter failed."
  530.      );
  531.     MsgPush("s='?',b=%x",pDbInfo->pValue);
  532.     return(eFalse);
  533. }
  534. DebugHTML(__FILE__,__LINE__,2,"Describe:Bound(%d: %s)",iParamCnt-1,pDbInfo->pValue);
  535.     }
  536.     return(eTrue);
  537. }
  538. /*
  539. /* Describe the SELECT Variables...
  540.  */
  541. static eBoolean_t
  542. DescribeSelectVars(SQLWEB_CURSOR *pCursor)
  543. {
  544.     SWORD NumCols, Col;
  545.     RETCODE rc;
  546.     UCHAR sColName [ MAX_ITEM_BUFFER_SIZE ];
  547.     SWORD iColNameSize = sizeof(sColName)
  548.     ,iColType
  549.     ,iScale
  550.     ,iNullable
  551. ;
  552.     UDWORD iLength;
  553.     char *pBuf;
  554.     DbInfo_t *pDbInfo;
  555.     rc=SQLNumResultCols(gaCDA[pCursor->iCursorIndex], &NumCols);
  556.     if(rc!=SQL_SUCCESS && rc!=SQL_SUCCESS_WITH_INFO) {
  557. PushDBErr(gaLDA[pCursor->pLDA->iLdaIndex]
  558.  ,gaCDA[pCursor->iCursorIndex]
  559.  ,"SQLNumResultCols failed."
  560.  );
  561. return(eFalse);
  562.     }
  563.     if(NumCols!=0) {
  564. gbaOpen[pCursor->iCursorIndex]=pCursor->bOpen=eTrue;
  565.     }
  566.     /* Describe each select-list item.
  567.      */
  568.     for(Col=1;Col<=NumCols;Col++) {
  569. rc=SQLDescribeCol(gaCDA[pCursor->iCursorIndex]
  570. ,Col
  571. ,sColName
  572. ,(SWORD)sizeof(sColName)
  573. ,&iColNameSize
  574. ,&iColType
  575. ,&iLength
  576. ,&iScale
  577. ,&iNullable
  578. );
  579. if(rc!=SQL_SUCCESS && rc!=SQL_SUCCESS_WITH_INFO) {
  580.     PushDBErr(gaLDA[pCursor->pLDA->iLdaIndex]
  581.  ,gaCDA[pCursor->iCursorIndex]
  582.  ,"SQLDescribe failed."
  583.  );
  584.     return(eFalse);
  585.         }
  586. sColName[iColNameSize]=0;
  587. DebugHTML(__FILE__,__LINE__,2,"DbOpen:Desc:%s:Len=%d:Scale=%d:T=%d"
  588. ,sColName
  589. ,iLength
  590. ,iScale
  591. ,iColType
  592. );
  593.         switch (iColType)
  594.         {
  595.     case SQL_LONGVARBINARY:
  596.     case SQL_LONGVARCHAR:
  597. iLength = 65533;
  598. break;
  599.     case SQL_DATE:
  600.     case SQL_TIMESTAMP:
  601.     case SQL_DECIMAL:
  602.     case SQL_DOUBLE:
  603.     case SQL_INTEGER:
  604.     case SQL_REAL:
  605.     case SQL_SMALLINT:
  606. iLength=44;
  607. break;
  608.     case SQL_CHAR:
  609.     case SQL_VARCHAR:
  610. /* iLength set by Describe
  611.  */
  612. break;
  613.     default:
  614. iLength = 32768; break;
  615.         }
  616. /*
  617. /* Build a "DB" Symbol
  618.  */
  619. pDbInfo = NewDbInfo();
  620. if(!pDbInfo){
  621.     MsgPush("malloc failed");
  622.     return(eFalse);
  623. }
  624. pDbInfo->pValue  =(char*)malloc(iLength+1);
  625. pDbInfo->iLen    =iLength+1;
  626. pDbInfo->iScale  =iScale;
  627. pDbInfo->iColType=iColType;
  628. if(!pDbInfo->pValue) {
  629.     /* Impossible occured! */
  630.     MsgPush("malloc failed");
  631.     return(eFalse);
  632. }
  633. memset(pDbInfo->pValue,0,iLength+1);
  634. ENQ(pCursor->lSelect,pDbInfo); /* For NULL Processing */
  635. if(ISeTrue(GetSymbolValueREF((char*)sColName,&pBuf))
  636. && strlen(pBuf)<=iLength)
  637. {
  638.     strcpy(pDbInfo->pValue,pBuf);
  639. /* Don't assume a symbol was malloc'd, (you hosehead)
  640. /* Add Symbol will take care of memory leakage...
  641.  */
  642. }
  643. if(! *pDbInfo->pValue)
  644.      pDbInfo->rlen = SQL_NULL_DATA;
  645. else pDbInfo->rlen = SQL_NTS;
  646. RETeFalse2(AddSymbol(SEL_SYMBOL
  647.     ,DupBuf((const char*)sColName)
  648.     ,pDbInfo->pValue
  649.     ,eTrue
  650.     ,(long)iLength+1
  651.     )
  652.   ,"AddSymbol(SEL,%s) Failed." 
  653.   ,(char*)sColName
  654.   );
  655. DebugHTML(__FILE__,__LINE__,2,"DbOpen:AddS(%s)",sColName);
  656. /* Let Informix Convert everything to STRING
  657.  */
  658. rc=SQLBindCol( gaCDA[pCursor->iCursorIndex]
  659. ,Col
  660. ,SQL_C_CHAR
  661. ,&pDbInfo->pValue[0]
  662. ,iLength+1
  663. ,&pDbInfo->rlen
  664. );
  665. if(rc!=SQL_SUCCESS && rc!=SQL_SUCCESS_WITH_INFO) {
  666.     PushDBErr(gaLDA[pCursor->pLDA->iLdaIndex]
  667.      ,gaCDA[pCursor->iCursorIndex]
  668.      ,"SQLBindCol failed."
  669.      );
  670.             return(eFalse);
  671.         }
  672.     }
  673.     return(eTrue);
  674. }
  675. static DbInfo_t *
  676. NewDbInfo()
  677. {
  678.     DbInfo_t *pDbInfo;
  679.     if(!glDbInfoList){
  680. glDbInfoList=l_create("STACK");
  681. if(!glDbInfoList) {
  682.     MsgPush("NewDbInfo:l_create failed");
  683.     return(0);
  684. }
  685.     }
  686.     if(l_size(glDbInfoList)>0) {
  687. DebugHTML(__FILE__,__LINE__,3,"NewDbInfo:POP(%d)",l_size(glDbInfoList));
  688. pDbInfo=(DbInfo_t*)POP(glDbInfoList);
  689.     } else {
  690. pDbInfo=(DbInfo_t*)malloc(sizeof(DbInfo_t));
  691.     }
  692.     if(!pDbInfo) {
  693. MsgPush("NewDbInfo:malloc or POP failed");
  694. return(0);
  695.     }
  696.     (void)memset(pDbInfo,0,sizeof(DbInfo_t));
  697.     pDbInfo->rlen = SQL_NTS;
  698.     return(pDbInfo);
  699. }
  700. static eBoolean_t
  701. FreeDbInfo(DbInfo_t *pDbInfo)
  702. {
  703.     DebugHTML(__FILE__,__LINE__,3,"FreeDbInfo[%x]",pDbInfo);
  704.     if(!glDbInfoList) {
  705. glDbInfoList=l_create("STACK");
  706. if(!glDbInfoList) {
  707.     MsgPush("FreeDbInfo:l_create failed");
  708.     return(eFalse);
  709. }
  710.     }
  711.     /*
  712.     /* Free pValue....
  713.     Free(pDbInfo->pValue);
  714.      */
  715.     /*
  716.     /* Store This PI on the FreeLIst
  717.      */
  718.     DebugHTML(__FILE__,__LINE__,3,"FreeDbInfo:PUSH(%d)",l_size(glDbInfoList));
  719.     PUSH(glDbInfoList,pDbInfo);
  720.     return(eTrue);
  721. }
  722. /*
  723. /* New function for Informix prot.  change the 
  724. /* symbol references in the sql string to 
  725. /* informix's '?' parameters so something like:
  726. /* select * from dual where a = :a
  727. /* becomes
  728. /* select * from dual where a = ?
  729. /* each symbol is converted into a ? parameter and the
  730. /* DbInfo is stuffed onto the lBind list for the
  731. /* cursor.
  732.  */
  733. static eBoolean_t
  734. PrepareParameters(SQLWEB_CURSOR *pCursor)
  735. {
  736.     char *pNewStmt, *cpNew;
  737.     int i, n;
  738.     eBoolean_t bLiteral;
  739.     char *cp;
  740.     /* New stmt will always be at at most the same size
  741.     /* as the origional because any symbol reference is
  742.     /* requires a ':' and a symbol name and the parameter
  743.     /* is a single '?'
  744.      */
  745.     cpNew = pNewStmt = malloc(strlen(pCursor->pStmt)+1);
  746.     if(!pNewStmt) {
  747. MsgPush("Malloc Failed in PrepareParameters");
  748.         return(eFalse);
  749.     }
  750.     /* Find and bind input variables for placeholders.
  751.      */
  752.     for (i=0, bLiteral=eFalse, cp=pCursor->pStmt; *cp; ) {
  753. DbInfo_t *pDbInfo;
  754. /* Single Quoted Strings are SQL literals */
  755.         if (*cp == ''') {
  756.             bLiteral = ISeTrue(bLiteral)?eFalse:eTrue; /* Toggle */
  757. }
  758. /* Oh, boy, we've got a live one!
  759.  */
  760.         /* if(*cp == ':' && ISeFalse(bLiteral) && *(cp+1) != '=') */
  761.         if(*cp == ':' && ISeFalse(bLiteral))
  762.         {
  763.     char buf[MAX_SQL_IDENTIFIER];
  764.             for ( ++cp, n=0;
  765.                  *cp && (isalnum(*cp) || *cp == '_')
  766.                      && n < MAX_SQL_IDENTIFIER;
  767.                  cp++, n++
  768.                 )
  769.     {
  770.                 buf[n]=*cp;
  771.     }
  772.             buf[n]=0; /* NULL the 'buf' Buffer */
  773.     /* if(! *cp) --cp; /* If this the end of the buffer, there
  774. /* is a problem because the outer loop */
  775. /* increments the cp pointer again, 
  776. /* BEYOND THE END OF THIS STRING!!!
  777.  */
  778.     /*
  779.     /* buf now points to the SYMBOL NAME
  780.     /* so...  go-n-get it!
  781.      */
  782.     pDbInfo = NewDbInfo();
  783.     if(!pDbInfo){
  784. MsgPush("malloc failed");
  785. return(eFalse);
  786.     }
  787.     ENQ(pCursor->lBind,pDbInfo);
  788.     if(ISeFalse(GetSymbolValueREF(buf,&pDbInfo->pValue))){
  789. /* There is no symbol by that name, stick in NULL
  790. /* WARNING?
  791.  */
  792. pDbInfo->pValue=0; /* should have been done by Get.. */
  793. /* pDbInfo->rlen = SQL_NULL_DATA;
  794.  */
  795.     }
  796.     DebugHTML(__FILE__,__LINE__,2
  797.     ,"DbOpen:GetS(%s:%s)"
  798.     ,buf
  799.     ,pDbInfo->pValue? pDbInfo->pValue: ""
  800.     );
  801.     pDbInfo->iLen = pDbInfo->pValue ? strlen(pDbInfo->pValue) : 0;
  802.     /* pDbInfo->ind  = pDbInfo->iLen>0 ? 0 : -1;
  803.      */
  804.             i++;
  805.     /* Install the Informix place holder
  806.      */
  807.     *cpNew++ = '?';
  808.     /* *cpNew++ = ' ';
  809.      */
  810.         }   /* end if (*cp == ':') */
  811. else {
  812.     /* Update the Modified SQLStmt
  813.      */
  814.     *cpNew++ = *cp++;
  815. }
  816.     }       /* end for () */
  817.     /* NULL terminate the newly processed SQL stmt
  818.      */
  819.     *cpNew=0;
  820.     /* Update the pCursor Structure 
  821.      */
  822.     pCursor->pStmt = pNewStmt;
  823.     DebugHTML(__FILE__,__LINE__,3,"DbSQL(%s) OK!",pNewStmt);
  824.     return(eTrue);
  825. }
  826. #define ErrMsgLen 200
  827. static void
  828. PushDBErr(HENV pLDA
  829.  ,HSTMT pCDA
  830.  ,char *pErrMsg
  831.  )
  832. {
  833.     RETCODE     rc = SQL_NO_DATA_FOUND;
  834.     SWORD       pcbErrorMsgLen = 0;
  835.     SDWORD      pfNativeError;
  836.     UCHAR ErrMsg[ErrMsgLen];
  837.     char        SqlState[6];
  838.     HENV        henv = (HENV)0;
  839.     HDBC        hdbc = (HDBC)0;
  840.     HSTMT       hstmt = pCDA;
  841.     if(pErrMsg)
  842. MsgPush("%s",pErrMsg);
  843.     if(hstmt) {
  844. rc=SQLError(NULL,NULL,hstmt
  845. ,(UCHAR *)SqlState
  846. ,&pfNativeError
  847. ,(UCHAR *)ErrMsg
  848. ,ErrMsgLen
  849. ,&pcbErrorMsgLen
  850. );
  851.     } else if(hdbc) {
  852. rc=SQLError(NULL,hdbc,NULL
  853. ,(UCHAR *)SqlState
  854. ,&pfNativeError
  855. ,(UCHAR *)ErrMsg
  856. ,ErrMsgLen
  857. ,&pcbErrorMsgLen
  858. );
  859.     } else if (henv) {
  860. rc=SQLError(henv,NULL,NULL
  861. ,(UCHAR *)SqlState
  862. ,&pfNativeError
  863. ,(UCHAR *)ErrMsg
  864. ,ErrMsgLen
  865. ,&pcbErrorMsgLen
  866. );
  867.     }
  868.     if(rc==SQL_SUCCESS || rc==SQL_SUCCESS_WITH_INFO) {
  869. MsgPush("DBERROR:IFMX:%d:%s:%s",pfNativeError,SqlState,ErrMsg);
  870.     } else if (rc== SQL_NO_DATA_FOUND ) {
  871. MsgPush("DBERROR:IFMX:?:?:Unknown error");
  872.     } else {
  873. MsgPush("DBERROR:IFMX:?:?:Unknown error rc=%d",rc);
  874.     }
  875.     return;
  876. }
  877. static eBoolean_t
  878. FreeStmt(SQLWEB_CURSOR *pCursor)
  879. {
  880.     RETCODE rc;
  881.     rc=SQLFreeStmt( gaCDA[pCursor->iCursorIndex], SQL_CLOSE );
  882.     if( rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO ) {
  883. PushDBErr(gaLDA[pCursor->pLDA->iLdaIndex]
  884.  ,gaCDA[pCursor->iCursorIndex]
  885.  ,"oclose failed."
  886.  );
  887. return(eFalse);
  888.     }
  889.     gbaOpen[pCursor->iCursorIndex]=eFalse;
  890.     return(eTrue);
  891. }