Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

7396 lines
221 KiB

  1. //NEW ONE
  2. /***************************************************************************/
  3. /* PARSE.C */
  4. /* Copyright (C) 1995-96 SYWARE Inc., All rights reserved */
  5. /***************************************************************************/
  6. // Commenting #define out - causing compiler error - not sure if needed, compiles
  7. // okay without it.
  8. //#define WINVER 0x0400
  9. #include "precomp.h"
  10. #include "wbemidl.h"
  11. #include <comdef.h>
  12. //smart pointer
  13. _COM_SMARTPTR_TYPEDEF(IWbemServices, IID_IWbemServices);
  14. _COM_SMARTPTR_TYPEDEF(IEnumWbemClassObject, IID_IEnumWbemClassObject);
  15. //_COM_SMARTPTR_TYPEDEF(IWbemContext, IID_IWbemContext );
  16. _COM_SMARTPTR_TYPEDEF(IWbemLocator, IID_IWbemLocator);
  17. #include "drdbdr.h"
  18. #include <comdef.h> //for _bstr_t
  19. /***************************************************************************/
  20. /* Notes: */
  21. /* */
  22. /* PARSE.C contains the code that changes a SQL query (as a character */
  23. /* string) and converts it to a tree that represents the query. */
  24. /* */
  25. /* The parse tree is actually an array of nodes. Initially it contains */
  26. /* SQLNODE_ALLOC nodes, but it is expanded if additional nodes are needed. */
  27. /* The root node of the tree is always the ROOT_SQLNODE'th element of this */
  28. /* array. */
  29. /* */
  30. /* String values (such as table names, literal string values, etc.) are */
  31. /* not stored directly in a node. Instead, they are stored in a separate */
  32. /* string area and an index to the string is stored in the parse tree */
  33. /* node. This is done to keep the parse tree nodes from getting too big. */
  34. /* Initially the string area is STRING_ALLOC bytslong, but it is expanded */
  35. /* is additional room is needed. */
  36. /* */
  37. /* As mentioned above, both the parse tree and string area may be expanded.*/
  38. /* Because of this, it is not possible for a node to have hard pointers to */
  39. /* child nodes or strings. To accomodate this problem, SQLNODEIDX and */
  40. /* STRINGIDX values are stored instead. The ToNode() and ToString() macros*/
  41. /* convert these indexes to pointers. */
  42. /* */
  43. /* The parser is recursive descent parser built entirely in C. To modify */
  44. /* the grammar, all you need to do is change the code in this module (tools*/
  45. /* such as YACC and LEX are not used). To best understand the code, start */
  46. /* by looking at routine Parse() (at the end of this module). */
  47. /* */
  48. /* ShowSemantic() in TRACE.C can be used to dump a parse tree to the */
  49. /* debug monitor. */
  50. /* */
  51. /***************************************************************************/
  52. /* Forward references */
  53. RETCODE INTFUNC ParseBoolean(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  54. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  55. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken);
  56. RETCODE INTFUNC ParseExpression(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  57. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  58. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken);
  59. RETCODE INTFUNC ParseSelect(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  60. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  61. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken);
  62. /***************************************************************************/
  63. /* Keywords */
  64. LPUSTR lpszKeywords[] = {
  65. (LPUSTR) "ALL",
  66. (LPUSTR) "ALTER", //Dr. DeeBee does not support this
  67. (LPUSTR) "AND",
  68. (LPUSTR) "ANY",
  69. (LPUSTR) "AS",
  70. (LPUSTR) "ASC",
  71. (LPUSTR) "AVG",
  72. (LPUSTR) "BY",
  73. (LPUSTR) "COUNT",
  74. (LPUSTR) "CREATE",
  75. (LPUSTR) "DELETE",
  76. (LPUSTR) "DESC",
  77. (LPUSTR) "DISTINCT",
  78. (LPUSTR) "DROP",
  79. (LPUSTR) "EXISTS",
  80. (LPUSTR) "GRANT", //Dr. DeeBee does not support this
  81. (LPUSTR) "FROM",
  82. (LPUSTR) "GROUP",
  83. (LPUSTR) "HAVING",
  84. (LPUSTR) "IN",
  85. (LPUSTR) "INDEX",
  86. (LPUSTR) "INSERT",
  87. (LPUSTR) "INTO",
  88. (LPUSTR) "IS",
  89. (LPUSTR) "JOIN",
  90. (LPUSTR) "LEFT",
  91. (LPUSTR) "LIKE",
  92. (LPUSTR) "MAX",
  93. (LPUSTR) "MIN",
  94. (LPUSTR) "NOT",
  95. (LPUSTR) "NULL",
  96. (LPUSTR) "ON",
  97. (LPUSTR) "OR",
  98. (LPUSTR) "ORDER",
  99. (LPUSTR) "REVOKE", //Dr. DeeBee does not support this
  100. (LPUSTR) "OUTER",
  101. (LPUSTR) "SELECT",
  102. (LPUSTR) "SET",
  103. (LPUSTR) "SQL",
  104. (LPUSTR) "SUM",
  105. (LPUSTR) "TABLE",
  106. (LPUSTR) "UNIQUE",
  107. (LPUSTR) "UPDATE",
  108. (LPUSTR) "USER",
  109. (LPUSTR) "VALUES",
  110. (LPUSTR) "WHERE",
  111. NULL };
  112. /***************************************************************************/
  113. /* Token types */
  114. #define TOKEN_TYPE_NONE 0
  115. #define TOKEN_TYPE_SYMBOL 1
  116. #define TOKEN_TYPE_NUMBER 2
  117. #define TOKEN_TYPE_STRING 3
  118. #define TOKEN_TYPE_IDENTIFIER 4
  119. #define TOKEN_TYPE_KEYWORD 5
  120. #define TOKEN_TYPE_ESCAPE 6
  121. /***************************************************************************/
  122. PassthroughLookupTable::PassthroughLookupTable()
  123. {
  124. tableAlias[0] = 0;
  125. columnName[0] = 0;
  126. }
  127. BOOL PassthroughLookupTable::SetTableAlias(char* tblAlias)
  128. {
  129. tableAlias[0] = 0;
  130. if (tblAlias)
  131. {
  132. if (strlen(tblAlias) <= MAX_QUALIFIER_NAME_LENGTH)
  133. {
  134. strcpy(tableAlias, tblAlias);
  135. }
  136. else
  137. {
  138. //Truncation
  139. return FALSE;
  140. }
  141. }
  142. return TRUE;
  143. }
  144. BOOL PassthroughLookupTable::SetColumnName(char* columName)
  145. {
  146. columnName[0] = 0;
  147. if (columName)
  148. {
  149. if (strlen(columName) <= MAX_COLUMN_NAME_LENGTH)
  150. {
  151. strcpy(columnName, columName);
  152. }
  153. else
  154. {
  155. //Truncation
  156. return FALSE;
  157. }
  158. }
  159. return TRUE;
  160. }
  161. VirtualInstanceInfo::VirtualInstanceInfo()
  162. {
  163. cElements = 0;
  164. cCycle = 1;
  165. }
  166. VirtualInstanceInfo::~VirtualInstanceInfo()
  167. {
  168. }
  169. VirtualInstanceManager::VirtualInstanceManager()
  170. {
  171. virtualInfo = new CMapStringToPtr();
  172. currentInstance = 0;
  173. cNumberOfInstances = 0;
  174. }
  175. VirtualInstanceManager::~VirtualInstanceManager()
  176. {
  177. //Tidy up VirtualInfo
  178. if (!virtualInfo->IsEmpty())
  179. {
  180. for(POSITION pos = virtualInfo->GetStartPosition(); pos != NULL; )
  181. {
  182. CString key; //not used
  183. VirtualInstanceInfo* pa = NULL;
  184. virtualInfo->GetNextAssoc( pos, key, (void*&)pa );
  185. if (pa)
  186. delete pa;
  187. }
  188. }
  189. delete (virtualInfo);
  190. virtualInfo = NULL;
  191. }
  192. void VirtualInstanceManager::AddColumnInstance(LPCTSTR TableAlias, LPCTSTR ColumnName, VirtualInstanceInfo* col)
  193. {
  194. //First check if new element contains any elements
  195. long newElements = col->cElements;
  196. if (! newElements)
  197. return;
  198. //Multiply call previous cycles counts by this number
  199. if (!virtualInfo->IsEmpty())
  200. {
  201. for(POSITION pos = virtualInfo->GetStartPosition(); pos != NULL; )
  202. {
  203. CString key; //not used
  204. VirtualInstanceInfo* pa = NULL;
  205. virtualInfo->GetNextAssoc( pos, key, (void*&)pa );
  206. if (pa)
  207. {
  208. pa->cCycle = pa->cCycle * newElements;
  209. }
  210. }
  211. }
  212. //First contruct the key
  213. char* tempbuff = ConstructKey(TableAlias, ColumnName);
  214. _bstr_t mapKey(tempbuff);
  215. delete tempbuff;
  216. //Add element
  217. virtualInfo->SetAt( (LPCTSTR)mapKey, col);
  218. //Update the instance count
  219. if (cNumberOfInstances)
  220. {
  221. cNumberOfInstances = cNumberOfInstances * newElements;
  222. }
  223. else
  224. {
  225. cNumberOfInstances = newElements;
  226. }
  227. }
  228. void VirtualInstanceManager::Load(CMapWordToPtr* passthroughMap, IWbemClassObject* myInstance)
  229. {
  230. //Cycle through each column in the passthrough table
  231. //and fetch its value from the IWbemClassObject instance
  232. if (passthroughMap && !(passthroughMap->IsEmpty()))
  233. {
  234. for(POSITION pos = passthroughMap->GetStartPosition(); pos != NULL; )
  235. {
  236. WORD key = 0; //not used
  237. PassthroughLookupTable* pltable = NULL;
  238. passthroughMap->GetNextAssoc( pos, key, (void*&)pltable );
  239. //Get TableAlias and ColumnName
  240. CBString myTableAlias;
  241. CBString myColumnName;
  242. myTableAlias.AddString(pltable->GetTableAlias(), FALSE);
  243. myColumnName.AddString(pltable->GetColumnName(), FALSE);
  244. //Get the variant value
  245. VARIANT myVal;
  246. //SAI ADDED no need to init VariantInit(&myVal);
  247. BOOL gotVarValue = GetVariantValue(myTableAlias, myColumnName, myInstance, &myVal);
  248. {
  249. //We don't care if this is an array of strings or not
  250. //as we are not asking for any values, we just want to
  251. //know the array size
  252. BSTR_SafeArray myArray(&myVal);
  253. //If this is an array type with at least one element
  254. if ( myArray.IsValid() )
  255. {
  256. if ( myArray.Count() )
  257. {
  258. VirtualInstanceInfo* myInfo = new VirtualInstanceInfo();
  259. myInfo->cElements = myArray.Count();
  260. //Add to manager
  261. AddColumnInstance(_bstr_t(myTableAlias.GetString()), _bstr_t(myColumnName.GetString()), myInfo);
  262. }
  263. }
  264. }
  265. if (gotVarValue)
  266. VariantClear(&myVal);
  267. }
  268. }
  269. }
  270. BOOL VirtualInstanceManager::GetVariantValue(CBString& myTableAlias, CBString& myColumnName, IWbemClassObject* myInstance, VARIANT FAR* myVal)
  271. {
  272. // VariantInit(myVal);
  273. //First we need to get the correctIWbemClassObject for the column value
  274. IWbemClassObject* correctWbemObject = myInstance;
  275. //We begin by checking if this is an __Generic class
  276. //if so we need to fetch the embedded object
  277. BOOL fIs__Generic = FALSE;
  278. VARIANT grVariant;
  279. //SAI ADDED no need VariantInit(&grVariant);
  280. CBString classBSTR(WBEMDR32_L_CLASS, FALSE);
  281. if (FAILED(myInstance->Get(classBSTR.GetString(), 0, &grVariant, NULL, NULL)))
  282. {
  283. return FALSE;
  284. }
  285. //Compare with __Generic
  286. if (_wcsicmp(grVariant.bstrVal, L"__Generic") == 0)
  287. {
  288. fIs__Generic = TRUE;
  289. //(4)
  290. correctWbemObject = GetWbemObject(myTableAlias, myInstance);
  291. }
  292. VariantClear(&grVariant);
  293. //Get the ColumnValue
  294. if (FAILED(correctWbemObject->Get(myColumnName.GetString(), 0, myVal, NULL, 0) ))
  295. {
  296. //(4)
  297. if (fIs__Generic)
  298. correctWbemObject->Release();
  299. return FALSE;
  300. }
  301. if (fIs__Generic)
  302. {
  303. //(4)
  304. correctWbemObject->Release();
  305. }
  306. return TRUE;
  307. }
  308. IWbemClassObject* VirtualInstanceManager::GetWbemObject(CBString& myTableAlias, IWbemClassObject* myInstance)
  309. {
  310. //Get the property type and value
  311. CIMTYPE vType;
  312. VARIANT pVal;
  313. //SAI ADDED no need to init VariantInit(&pVal);
  314. if ( SUCCEEDED(myInstance->Get(myTableAlias.GetString(), 0, &pVal, &vType, 0)) )
  315. {
  316. //We are looking for embedded objects
  317. if (vType == CIM_OBJECT)
  318. {
  319. IWbemClassObject* myEmbeddedObj = NULL;
  320. IUnknown* myUnk = pVal.punkVal;
  321. myUnk->QueryInterface(IID_IWbemClassObject, (void**)&myEmbeddedObj);
  322. VariantClear(&pVal);
  323. return myEmbeddedObj;
  324. }
  325. VariantClear(&pVal);
  326. }
  327. //error
  328. return NULL;
  329. }
  330. char* VirtualInstanceManager::ConstructKey(LPCTSTR TableAlias, LPCTSTR ColumnName)
  331. {
  332. _bstr_t mapKey2("");
  333. //Make key in upper case
  334. CString myUpperCaseTbl(TableAlias);
  335. if (! myUpperCaseTbl.IsEmpty())
  336. myUpperCaseTbl.MakeUpper();
  337. _bstr_t myTblAlias(myUpperCaseTbl);
  338. CString myUpperCaseCol(ColumnName);
  339. if (! myUpperCaseCol.IsEmpty())
  340. myUpperCaseCol.MakeUpper();
  341. _bstr_t myColName(myUpperCaseCol);
  342. if ( myTblAlias.length() )
  343. mapKey2 += (LPCTSTR)myTblAlias;
  344. mapKey2+= ".";
  345. if ( myColName.length() )
  346. mapKey2 += (LPCTSTR)myColName;
  347. long len = mapKey2.length();
  348. char* buffer = new char[len + 1];
  349. buffer[0] = 0;
  350. wcstombs(buffer, mapKey2, len);
  351. buffer[len] = 0;
  352. return buffer;
  353. // return (LPCTSTR)mapKey;
  354. }
  355. long VirtualInstanceManager::GetArrayIndex(LPCTSTR TableAlias, LPCTSTR ColumnName, long instanceNum)
  356. {
  357. long index = -1;
  358. //First construct key for lookup map
  359. char* tempbuff = ConstructKey(TableAlias, ColumnName);
  360. _bstr_t mapKey(tempbuff);
  361. delete tempbuff;
  362. VirtualInstanceInfo* myInfo = NULL;
  363. if ( virtualInfo->Lookup((LPCTSTR)mapKey, (void*&)myInfo) )
  364. {
  365. //Calculate index for given instance
  366. //(Note: instance number is zero based)
  367. long cCycle = myInfo->cCycle;
  368. index = ( (instanceNum) / (myInfo->cCycle) );
  369. index = index % (myInfo->cElements);
  370. }
  371. return index;
  372. }
  373. /*
  374. void VirtualInstanceManager::Testy()
  375. {
  376. //Testing
  377. VirtualInstanceInfo* myInfo = NULL;
  378. //TableA
  379. myInfo = new VirtualInstanceInfo();
  380. myInfo->cElements = 2;
  381. AddColumnInstance(_bstr_t("t1"), _bstr_t("TableA"), myInfo);
  382. //TableB
  383. myInfo = new VirtualInstanceInfo();
  384. myInfo->cElements = 3;
  385. AddColumnInstance(_bstr_t("t2"), _bstr_t("TableB"), myInfo);
  386. //TableC
  387. myInfo = new VirtualInstanceInfo();
  388. myInfo->cElements = 2;
  389. AddColumnInstance(_bstr_t("t3"), _bstr_t("TableC"), myInfo);
  390. //Now fetch the index's for instance 0
  391. long myindexA = 0;
  392. long myindexB = 0;
  393. long myindexC = 0;
  394. myindexA = GetArrayIndex(_bstr_t("t1"), _bstr_t("TableA"), 0);
  395. myindexB = GetArrayIndex(_bstr_t("t2"), _bstr_t("TableB"), 0);
  396. myindexC = GetArrayIndex(_bstr_t("t3"), _bstr_t("TableC"), 0);
  397. myindexA = GetArrayIndex(_bstr_t("t1"), _bstr_t("TableA"), 5);
  398. myindexB = GetArrayIndex(_bstr_t("t2"), _bstr_t("TableB"), 5);
  399. myindexC = GetArrayIndex(_bstr_t("t3"), _bstr_t("TableC"), 5);
  400. myindexA = GetArrayIndex(_bstr_t("t1"), _bstr_t("TableA"), 6);
  401. myindexB = GetArrayIndex(_bstr_t("t2"), _bstr_t("TableB"), 6);
  402. myindexC = GetArrayIndex(_bstr_t("t3"), _bstr_t("TableC"), 6);
  403. myindexA = GetArrayIndex(_bstr_t("t1"), _bstr_t("TableA"), 11);
  404. myindexB = GetArrayIndex(_bstr_t("t2"), _bstr_t("TableB"), 11);
  405. myindexC = GetArrayIndex(_bstr_t("t3"), _bstr_t("TableC"), 11);
  406. }
  407. */
  408. /***************************************************************************/
  409. SQLNODEIDX INTFUNC AllocateNode(LPSQLTREE FAR *lplpSql, UWORD sqlNodeType)
  410. /* Allocates a new node for the parse tree. */
  411. /* */
  412. /* If there is an available node, the index of that node is returned. */
  413. /* Otherwise the array is expanded and the index of one of the newly */
  414. /* created nodes is returned. */
  415. /* */
  416. /* lplpSql points to the node array. Its value may change. */
  417. {
  418. HGLOBAL hParseArray;
  419. HGLOBAL hOldParseArray;
  420. LPSQLTREE lpSql;
  421. /* Is there space available? */
  422. lpSql = *lplpSql;
  423. if ((lpSql->node.root.iParseArray + 1) >= lpSql->node.root.cParseArray) {
  424. /* No. Allocate more space */
  425. hOldParseArray = lpSql->node.root.hParseArray;
  426. lpSql->node.root.hParseArray = NULL;
  427. GlobalUnlock(hOldParseArray);
  428. hParseArray = GlobalReAlloc(hOldParseArray,
  429. sizeof(SQLNODE) * (SQLNODE_ALLOC + lpSql->node.root.cParseArray),
  430. GMEM_MOVEABLE);
  431. if (hParseArray == NULL) {
  432. GlobalFree(hOldParseArray);
  433. return NO_SQLNODE;
  434. }
  435. lpSql = (LPSQLTREE) GlobalLock(hParseArray);
  436. if (lpSql == NULL) {
  437. GlobalFree(hParseArray);
  438. return NO_SQLNODE;
  439. }
  440. *lplpSql = lpSql;
  441. /* Update the root node */
  442. lpSql->node.root.hParseArray = hParseArray;
  443. lpSql->node.root.cParseArray += (SQLNODE_ALLOC);
  444. }
  445. /* Return the next node */
  446. (lpSql->node.root.iParseArray)++;
  447. /* Initialize the node */
  448. lpSql[lpSql->node.root.iParseArray].sqlNodeType = sqlNodeType;
  449. lpSql[lpSql->node.root.iParseArray].sqlDataType = TYPE_UNKNOWN;
  450. lpSql[lpSql->node.root.iParseArray].sqlSqlType = SQL_TYPE_NULL;
  451. lpSql[lpSql->node.root.iParseArray].sqlPrecision = 0;
  452. lpSql[lpSql->node.root.iParseArray].sqlScale = NO_SCALE;
  453. lpSql[lpSql->node.root.iParseArray].value.String = NULL;
  454. lpSql[lpSql->node.root.iParseArray].value.Double = 0.0;
  455. lpSql[lpSql->node.root.iParseArray].value.Date.year = 0;
  456. lpSql[lpSql->node.root.iParseArray].value.Date.month = 0;
  457. lpSql[lpSql->node.root.iParseArray].value.Date.day = 0;
  458. lpSql[lpSql->node.root.iParseArray].value.Time.hour = 0;
  459. lpSql[lpSql->node.root.iParseArray].value.Time.minute = 0;
  460. lpSql[lpSql->node.root.iParseArray].value.Time.second = 0;
  461. lpSql[lpSql->node.root.iParseArray].value.Timestamp.year = 0;
  462. lpSql[lpSql->node.root.iParseArray].value.Timestamp.month = 0;
  463. lpSql[lpSql->node.root.iParseArray].value.Timestamp.day = 0;
  464. lpSql[lpSql->node.root.iParseArray].value.Timestamp.hour = 0;
  465. lpSql[lpSql->node.root.iParseArray].value.Timestamp.minute = 0;
  466. lpSql[lpSql->node.root.iParseArray].value.Timestamp.second = 0;
  467. lpSql[lpSql->node.root.iParseArray].value.Timestamp.fraction = 0;
  468. lpSql[lpSql->node.root.iParseArray].value.Binary = NULL;
  469. lpSql[lpSql->node.root.iParseArray].sqlIsNull = TRUE;
  470. return lpSql->node.root.iParseArray;
  471. }
  472. /***************************************************************************/
  473. STRINGIDX INTFUNC AllocateSpace(LPSQLTREE FAR *lplpSql, SWORD cbSize)
  474. /* Allocates space from the string area of parse tree. */
  475. /* */
  476. /* If there is room, the index of the string is returned. Otherwise the */
  477. /* string area is expanded and the index of the newly created string */
  478. /* is returned. If the string area cannot be expanded, NO_STRING is */
  479. /* returned. */
  480. /* */
  481. /* lpSql points to the node array. Its value may change. cbSize is */
  482. /* the number of bytes needed. */
  483. {
  484. HGLOBAL hStringArea;
  485. LPUSTR lpstr;
  486. LPSQLTREE lpSql;
  487. /* First time? */
  488. lpSql = *lplpSql;
  489. if (lpSql->node.root.hStringArea == NULL) {
  490. /* Yes. Allocate initial space */
  491. hStringArea = GlobalAlloc(GMEM_MOVEABLE, STRING_ALLOC);
  492. if (hStringArea == NULL)
  493. return NO_STRING;
  494. lpstr = (LPUSTR) GlobalLock(hStringArea);
  495. if (lpstr == NULL) {
  496. GlobalFree(hStringArea);
  497. return NO_STRING;
  498. }
  499. /* Update the root node */
  500. lpSql->node.root.hStringArea = hStringArea;
  501. lpSql->node.root.lpStringArea = lpstr;
  502. lpSql->node.root.cbStringArea = STRING_ALLOC;
  503. lpSql->node.root.ibStringArea = -1;
  504. }
  505. /* Is there enough space available? */
  506. while ((lpSql->node.root.ibStringArea + cbSize) >= lpSql->node.root.cbStringArea) {
  507. /* No. Allocate more space */
  508. GlobalUnlock(lpSql->node.root.hStringArea);
  509. hStringArea = GlobalReAlloc(lpSql->node.root.hStringArea,
  510. STRING_ALLOC + lpSql->node.root.cbStringArea, GMEM_MOVEABLE);
  511. if (hStringArea == NULL) {
  512. GlobalFree(lpSql->node.root.hStringArea);
  513. lpSql->node.root.hStringArea = NULL;
  514. return NO_STRING;
  515. }
  516. lpstr = (LPUSTR) GlobalLock(hStringArea);
  517. if (lpstr == NULL) {
  518. GlobalFree(hStringArea);
  519. lpSql->node.root.hStringArea = NULL;
  520. return NO_STRING;
  521. }
  522. /* Update the root node */
  523. lpSql->node.root.hStringArea = hStringArea;
  524. lpSql->node.root.lpStringArea = lpstr;
  525. lpSql->node.root.cbStringArea += (STRING_ALLOC);
  526. }
  527. /* Return the next node */
  528. lpSql->node.root.ibStringArea += (cbSize);
  529. return (lpSql->node.root.ibStringArea - cbSize + 1);
  530. }
  531. /***************************************************************************/
  532. STRINGIDX INTFUNC AllocateString(LPSQLTREE FAR *lplpSql, LPUSTR lpszStr)
  533. /* Allocates a string from the string area of parse tree. */
  534. /* */
  535. /* If there is room, the index of the string is returned. Otherwise the */
  536. /* string area is expanded and the index of the newly created string */
  537. /* is returned. If the string area cannot be expanded, NO_STRING is */
  538. /* returned. */
  539. /* */
  540. /* lpSql points to the node array. Its value may change. */
  541. {
  542. STRINGIDX idx;
  543. idx = AllocateSpace(lplpSql, (SWORD) (s_lstrlen(lpszStr) + 1));
  544. if (idx == NO_STRING)
  545. return NO_STRING;
  546. s_lstrcpy(ToString(*lplpSql, idx), lpszStr);
  547. return idx;
  548. }
  549. /***************************************************************************/
  550. void INTFUNC FreeTree(LPSQLTREE lpSql)
  551. /* Deallocates a parse tree */
  552. {
  553. HGLOBAL hParseArray;
  554. /* If nothing to do, just return */
  555. if (lpSql == NULL)
  556. return;
  557. /* Free semantic information */
  558. FreeTreeSemantic(lpSql, ROOT_SQLNODE);
  559. /* Deallocate the string area */
  560. if (lpSql->node.root.hStringArea != NULL) {
  561. GlobalUnlock(lpSql->node.root.hStringArea);
  562. GlobalFree(lpSql->node.root.hStringArea);
  563. }
  564. /* Deallocate the parse array */
  565. hParseArray = lpSql->node.root.hParseArray;
  566. if (hParseArray != NULL) {
  567. GlobalUnlock(hParseArray);
  568. GlobalFree(hParseArray);
  569. }
  570. }
  571. /***************************************************************************/
  572. /***************************************************************************/
  573. UWORD INTFUNC KeywordOrIdentifier(LPUSTR lpToken)
  574. /* Determines if token is a keyword or an identifier */
  575. {
  576. LPUSTR FAR *lpKeyword;
  577. lpKeyword = lpszKeywords;
  578. while (*lpKeyword != NULL) {
  579. if (!s_lstrcmpi(lpToken, *lpKeyword))
  580. return TOKEN_TYPE_KEYWORD;
  581. lpKeyword++;
  582. }
  583. return TOKEN_TYPE_IDENTIFIER;
  584. }
  585. /***************************************************************************/
  586. RETCODE INTFUNC GetToken(LPSTMT lpstmt, LPUSTR lpFrom, SDWORD cbFrom,
  587. LPUSTR lpToken, UWORD FAR *pfType,
  588. LPUSTR FAR *lpRemainder, SDWORD FAR *pcbRemainder)
  589. /* Retrives a token from input string, and returns the token and a pointer */
  590. /* to the remainder of the input string. lpToken is assumed to be at */
  591. /* least (MAX_TOKEN_SIZE + 1) bytes long. */
  592. {
  593. int len;
  594. BOOL foundDecimalPoint;
  595. BOOL foundExponent;
  596. LPUSTR lpTo;
  597. /* Remove leading blanks */
  598. while ((cbFrom != 0) &&
  599. ((*lpFrom == ' ') ||
  600. (*lpFrom == '\012') ||
  601. (*lpFrom == '\015') ||
  602. (*lpFrom == '\011'))) {
  603. lpFrom++;
  604. cbFrom--;
  605. }
  606. /* Leave if no more */
  607. lpTo = lpToken;
  608. if (cbFrom == 0) {
  609. *lpTo = '\0';
  610. *lpRemainder = lpFrom;
  611. *pcbRemainder = cbFrom;
  612. *pfType = TOKEN_TYPE_NONE;
  613. return ERR_SUCCESS;
  614. }
  615. /* What kind of token? */
  616. switch (*lpFrom) {
  617. /* End of input */
  618. case '\0':
  619. *lpTo = '\0';
  620. *lpRemainder = lpFrom;
  621. *pcbRemainder = cbFrom;
  622. *pfType = TOKEN_TYPE_NONE;
  623. return ERR_SUCCESS;
  624. /* Single character tokens */
  625. case '(':
  626. case ')':
  627. case '=':
  628. case '?':
  629. case '*':
  630. case ',':
  631. case '+':
  632. case '/':
  633. case '{':
  634. case '}':
  635. *lpTo = *lpFrom;
  636. lpTo++;
  637. lpFrom++;
  638. cbFrom--;
  639. *lpTo = '\0';
  640. *lpRemainder = lpFrom;
  641. *pcbRemainder = cbFrom;
  642. *pfType = TOKEN_TYPE_SYMBOL;
  643. return ERR_SUCCESS;
  644. /* - or -- */
  645. case '-':
  646. *lpTo = *lpFrom;
  647. lpTo++;
  648. lpFrom++;
  649. cbFrom--;
  650. if ((cbFrom != 0) && (*lpFrom == '-')) {
  651. *lpTo = *lpFrom;
  652. lpTo++;
  653. lpFrom++;
  654. cbFrom--;
  655. }
  656. *lpTo = '\0';
  657. *lpRemainder = lpFrom;
  658. *pcbRemainder = cbFrom;
  659. *pfType = TOKEN_TYPE_SYMBOL;
  660. return ERR_SUCCESS;
  661. /* < or <= or <> */
  662. case '<':
  663. *lpTo = *lpFrom;
  664. lpTo++;
  665. lpFrom++;
  666. cbFrom--;
  667. if ((cbFrom != 0) && ((*lpFrom == '=') || (*lpFrom == '>'))) {
  668. *lpTo = *lpFrom;
  669. lpTo++;
  670. lpFrom++;
  671. cbFrom--;
  672. }
  673. *lpTo = '\0';
  674. *lpRemainder = lpFrom;
  675. *pcbRemainder = cbFrom;
  676. *pfType = TOKEN_TYPE_SYMBOL;
  677. return ERR_SUCCESS;
  678. /* > or >= */
  679. case '>':
  680. *lpTo = *lpFrom;
  681. lpTo++;
  682. lpFrom++;
  683. cbFrom--;
  684. if ((cbFrom != 0) && (*lpFrom == '=')) {
  685. *lpTo = *lpFrom;
  686. lpTo++;
  687. lpFrom++;
  688. cbFrom--;
  689. }
  690. *lpTo = '\0';
  691. *lpRemainder = lpFrom;
  692. *pcbRemainder = cbFrom;
  693. *pfType = TOKEN_TYPE_SYMBOL;
  694. return ERR_SUCCESS;
  695. /* Numbers */
  696. case '.':
  697. if (cbFrom == 1) {
  698. *lpTo = *lpFrom;
  699. lpTo++;
  700. lpFrom++;
  701. cbFrom--;
  702. *lpTo = '\0';
  703. *lpRemainder = lpFrom;
  704. *pcbRemainder = cbFrom;
  705. *pfType = TOKEN_TYPE_SYMBOL;
  706. return ERR_SUCCESS;
  707. }
  708. switch (*(lpFrom+1)) {
  709. case '0':
  710. case '1':
  711. case '2':
  712. case '3':
  713. case '4':
  714. case '5':
  715. case '6':
  716. case '7':
  717. case '8':
  718. case '9':
  719. break;
  720. default:
  721. *lpTo = *lpFrom;
  722. lpTo++;
  723. lpFrom++;
  724. cbFrom--;
  725. *lpTo = '\0';
  726. *lpRemainder = lpFrom;
  727. *pcbRemainder = cbFrom;
  728. *pfType = TOKEN_TYPE_SYMBOL;
  729. return ERR_SUCCESS;
  730. }
  731. /* **** DROP DOWN TO NEXT CASE **** */
  732. case '0':
  733. case '1':
  734. case '2':
  735. case '3':
  736. case '4':
  737. case '5':
  738. case '6':
  739. case '7':
  740. case '8':
  741. case '9':
  742. /* **** CONTROL MAY COME HERE FROM PREVIOUS CASE **** */
  743. len = 0;
  744. foundDecimalPoint = FALSE;
  745. foundExponent = FALSE;
  746. while (TRUE) {
  747. if (cbFrom == 0) {
  748. *lpTo = '\0';
  749. *lpRemainder = lpFrom;
  750. *pcbRemainder = cbFrom;
  751. *pfType = TOKEN_TYPE_NUMBER;
  752. return ERR_SUCCESS;
  753. }
  754. switch (*lpFrom) {
  755. case '.':
  756. if (foundDecimalPoint || foundExponent) {
  757. *lpTo = '\0';
  758. s_lstrcpy(lpstmt->szError, lpToken);
  759. return ERR_MALFORMEDNUMBER;
  760. }
  761. foundDecimalPoint = TRUE;
  762. /* **** DROP DOWN TO NEXT CASE **** */
  763. case '0':
  764. case '1':
  765. case '2':
  766. case '3':
  767. case '4':
  768. case '5':
  769. case '6':
  770. case '7':
  771. case '8':
  772. case '9':
  773. /* **** CONTROL MAY COME HERE FROM PREVIOUS CASE **** */
  774. break;
  775. case 'e':
  776. case 'E':
  777. if (foundExponent) {
  778. *lpTo = '\0';
  779. s_lstrcpy(lpstmt->szError, lpToken);
  780. return ERR_MALFORMEDNUMBER;
  781. }
  782. foundExponent = TRUE;
  783. if ((cbFrom > 1) && ((*(lpFrom+1) == '+') ||
  784. (*(lpFrom+1) == '-'))) {
  785. if (len >= MAX_TOKEN_SIZE) {
  786. *lpTo = '\0';
  787. s_lstrcpy(lpstmt->szError, lpToken);
  788. return ERR_ELEMENTTOOBIG;
  789. }
  790. len++;
  791. *lpTo = *lpFrom;
  792. lpTo++;
  793. lpFrom++;
  794. cbFrom--;
  795. }
  796. if (cbFrom < 2) {
  797. *lpTo = '\0';
  798. s_lstrcpy(lpstmt->szError, lpToken);
  799. return ERR_MALFORMEDNUMBER;
  800. }
  801. break;
  802. default:
  803. *lpTo = '\0';
  804. *lpRemainder = lpFrom;
  805. *pcbRemainder = cbFrom;
  806. *pfType = TOKEN_TYPE_NUMBER;
  807. return ERR_SUCCESS;
  808. }
  809. if (len >= MAX_TOKEN_SIZE) {
  810. *lpTo = '\0';
  811. s_lstrcpy(lpstmt->szError, lpToken);
  812. return ERR_ELEMENTTOOBIG;
  813. }
  814. len++;
  815. *lpTo = *lpFrom;
  816. lpTo++;
  817. lpFrom++;
  818. cbFrom--;
  819. }
  820. break; /* Control should never get here */
  821. /* Character literals */
  822. case '\'':
  823. lpFrom++;
  824. cbFrom--;
  825. len = 0;
  826. while (TRUE) {
  827. if (cbFrom == 0)
  828. return ERR_UNEXPECTEDEND;
  829. switch (*lpFrom) {
  830. case '\0':
  831. return ERR_UNEXPECTEDEND;
  832. case '\'':
  833. lpFrom++;
  834. cbFrom--;
  835. if ((cbFrom == 0) || (*lpFrom != '\'')) {
  836. *lpTo = '\0';
  837. *lpRemainder = lpFrom;
  838. *pcbRemainder = cbFrom;
  839. *pfType = TOKEN_TYPE_STRING;
  840. return ERR_SUCCESS;
  841. }
  842. /* **** DROP DOWN TO NEXT CASE **** */
  843. default:
  844. /* **** CONTROL MAY COME HERE FROM PREVIOUS CASE **** */
  845. break;
  846. }
  847. if (len >= MAX_TOKEN_SIZE) {
  848. *lpTo = '\0';
  849. s_lstrcpy(lpstmt->szError, lpToken);
  850. return ERR_ELEMENTTOOBIG;
  851. }
  852. len++;
  853. *lpTo = *lpFrom;
  854. lpTo++;
  855. lpFrom++;
  856. cbFrom--;
  857. }
  858. break; /* Control should never get here */
  859. /* Quoted identifiers */
  860. case '"':
  861. len = 0;
  862. lpFrom++;
  863. cbFrom--;
  864. while (TRUE) {
  865. if (cbFrom == 0)
  866. return ERR_UNEXPECTEDEND;
  867. switch (*lpFrom) {
  868. case '\0':
  869. return ERR_UNEXPECTEDEND;
  870. case '"':
  871. lpFrom++;
  872. cbFrom--;
  873. *lpTo = '\0';
  874. *lpRemainder = lpFrom;
  875. *pcbRemainder = cbFrom;
  876. *pfType = TOKEN_TYPE_IDENTIFIER;
  877. return ERR_SUCCESS;
  878. default:
  879. break;
  880. }
  881. if (len >= MAX_TOKEN_SIZE) {
  882. *lpTo = '\0';
  883. s_lstrcpy(lpstmt->szError, lpToken);
  884. return ERR_ELEMENTTOOBIG;
  885. }
  886. len++;
  887. *lpTo = *lpFrom;
  888. lpTo++;
  889. lpFrom++;
  890. cbFrom--;
  891. }
  892. break; /* Control should never get here */
  893. /* Other identifiers (and keywords) */
  894. default:
  895. len = 0;
  896. while (TRUE) {
  897. if (cbFrom == 0) {
  898. *lpTo = '\0';
  899. *lpRemainder = lpFrom;
  900. *pcbRemainder = cbFrom;
  901. *pfType = KeywordOrIdentifier(lpToken);
  902. return ERR_SUCCESS;
  903. }
  904. switch (*lpFrom) {
  905. case ' ':
  906. case '\012':
  907. case '\015':
  908. case '\011':
  909. case '\0':
  910. case '(':
  911. case ')':
  912. case '=':
  913. case '?':
  914. case '*':
  915. case ',':
  916. case '.':
  917. case '<':
  918. case '>':
  919. case '-':
  920. case '+':
  921. case '/':
  922. case '{':
  923. case '}':
  924. *lpTo = '\0';
  925. *lpRemainder = lpFrom;
  926. *pcbRemainder = cbFrom;
  927. *pfType = KeywordOrIdentifier(lpToken);
  928. return ERR_SUCCESS;
  929. default:
  930. break;
  931. }
  932. if (len >= MAX_TOKEN_SIZE) {
  933. *lpTo = '\0';
  934. s_lstrcpy(lpstmt->szError, lpToken);
  935. return ERR_ELEMENTTOOBIG;
  936. }
  937. len++;
  938. *lpTo = *lpFrom;
  939. lpTo++;
  940. lpFrom++;
  941. cbFrom--;
  942. }
  943. break; /* Control should never get here */
  944. }
  945. /* Control never gets here */
  946. }
  947. /***************************************************************************/
  948. RETCODE INTFUNC GetEscape(LPSTMT lpstmt, LPUSTR lpFrom, SDWORD cbFrom,
  949. LPUSTR lpToken, LPUSTR FAR *lpRemainder,
  950. SDWORD FAR *pcbRemainder)
  951. /* Retrives an escape sequence from input string, and returns it as */
  952. /* a token and returns a pointer to the remainder of the input string. */
  953. /* lpToken is assumed to be at least (MAX_TOKEN_SIZE + 1) bytes long. */
  954. {
  955. int len;
  956. LPUSTR lpTo;
  957. /* Remove leading blanks */
  958. while ((cbFrom != 0) &&
  959. ((*lpFrom == ' ') ||
  960. (*lpFrom == '\012') ||
  961. (*lpFrom == '\015') ||
  962. (*lpFrom == '\011'))) {
  963. lpFrom++;
  964. cbFrom--;
  965. }
  966. /* Error if no more */
  967. lpTo = lpToken;
  968. if (cbFrom == 0) {
  969. *lpTo = '\0';
  970. *lpRemainder = lpFrom;
  971. *pcbRemainder = cbFrom;
  972. return ERR_UNEXPECTEDEND;
  973. }
  974. /* What kind of escape? */
  975. switch (*lpFrom) {
  976. /* Shorthand sequences */
  977. case '{':
  978. /* Get sequence */
  979. len = 0;
  980. while (TRUE) {
  981. if (cbFrom == 0)
  982. return ERR_UNEXPECTEDEND;
  983. /* End of seqeuence? */
  984. if (*lpFrom == '}') {
  985. /* Yes. Return it */
  986. *lpTo = *lpFrom;
  987. lpTo++;
  988. lpFrom++;
  989. cbFrom--;
  990. *lpTo = '\0';
  991. *lpRemainder = lpFrom;
  992. *pcbRemainder = cbFrom;
  993. return ERR_SUCCESS;
  994. }
  995. if (len >= MAX_TOKEN_SIZE) {
  996. *lpTo = '\0';
  997. s_lstrcpy(lpstmt->szError, lpToken);
  998. return ERR_ELEMENTTOOBIG;
  999. }
  1000. len++;
  1001. *lpTo = *lpFrom;
  1002. lpTo++;
  1003. lpFrom++;
  1004. cbFrom--;
  1005. }
  1006. break;
  1007. /* Escape sequences */
  1008. case '-':
  1009. if ((cbFrom > 1) && (*(lpFrom+1) == '-')) {
  1010. /* Get starting hyphen */
  1011. *lpTo = *lpFrom;
  1012. lpTo++;
  1013. lpFrom++;
  1014. cbFrom--;
  1015. /* Get rest of sequence */
  1016. len = 0;
  1017. while (TRUE) {
  1018. if (cbFrom == 0)
  1019. return ERR_UNEXPECTEDEND;
  1020. /* End of seqeuence? */
  1021. if ((*lpFrom == '-') && (cbFrom > 1) && (*(lpFrom+1) == '-')) {
  1022. /* Yes. Return it */
  1023. *lpTo = *lpFrom;
  1024. lpTo++;
  1025. lpFrom++;
  1026. cbFrom--;
  1027. *lpTo = *lpFrom;
  1028. lpTo++;
  1029. lpFrom++;
  1030. cbFrom--;
  1031. *lpTo = '\0';
  1032. *lpRemainder = lpFrom;
  1033. *pcbRemainder = cbFrom;
  1034. return ERR_SUCCESS;
  1035. }
  1036. if (len >= MAX_TOKEN_SIZE-1) {
  1037. *lpTo = '\0';
  1038. s_lstrcpy(lpstmt->szError, lpToken);
  1039. return ERR_ELEMENTTOOBIG;
  1040. }
  1041. len++;
  1042. *lpTo = *lpFrom;
  1043. lpTo++;
  1044. lpFrom++;
  1045. cbFrom--;
  1046. }
  1047. }
  1048. else
  1049. return ERR_UNEXPECTEDEND;
  1050. default:
  1051. s_lstrcpy(lpstmt->szError, "<escape-sequence>");
  1052. return ERR_EXPECTEDOTHER;
  1053. }
  1054. /* Control never gets here */
  1055. }
  1056. /***************************************************************************/
  1057. RETCODE INTFUNC GetSymbol(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  1058. SDWORD FAR *pcbSqlStr, LPSTR lpszSymbol,
  1059. LPUSTR lpszToken)
  1060. /* Retrives a symbol from the input stream. If lpszSymbol is not null, */
  1061. /* ERR_EXPECTEDOTHER is returned if the token found is not lpszSymbol. */
  1062. {
  1063. UWORD fType;
  1064. RETCODE err;
  1065. /* Get Identifier */
  1066. err = GetToken(lpstmt, *lplpszSqlStr, *pcbSqlStr, lpszToken, &fType,
  1067. lplpszSqlStr, pcbSqlStr);
  1068. if (err != ERR_SUCCESS)
  1069. return err;
  1070. if (fType != TOKEN_TYPE_SYMBOL) {
  1071. if (lpszSymbol != NULL)
  1072. s_lstrcpy(lpstmt->szError, lpszSymbol);
  1073. else
  1074. s_lstrcpy(lpstmt->szError, "<symbol>");
  1075. return ERR_EXPECTEDOTHER;
  1076. }
  1077. /* Check value */
  1078. if (lpszSymbol != NULL) {
  1079. if (s_lstrcmpi(lpszSymbol, lpszToken)) {
  1080. s_lstrcpy(lpstmt->szError, lpszSymbol);
  1081. return ERR_EXPECTEDOTHER;
  1082. }
  1083. }
  1084. return ERR_SUCCESS;
  1085. }
  1086. /***************************************************************************/
  1087. RETCODE INTFUNC GetInteger(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  1088. SDWORD FAR *pcbSqlStr, UDWORD FAR *pudValue,
  1089. LPUSTR lpszToken)
  1090. /* Retrives an integer number from the input stream. The number is */
  1091. /* returned in both pudValue and lpszToken */
  1092. {
  1093. UWORD fType;
  1094. RETCODE err;
  1095. /* Get Identifier */
  1096. err = GetToken(lpstmt, *lplpszSqlStr, *pcbSqlStr, lpszToken, &fType,
  1097. lplpszSqlStr, pcbSqlStr);
  1098. if (err != ERR_SUCCESS)
  1099. return err;
  1100. if (fType != TOKEN_TYPE_NUMBER) {
  1101. s_lstrcpy(lpstmt->szError, lpszToken);
  1102. return ERR_MALFORMEDNUMBER;
  1103. }
  1104. *pudValue = 0;
  1105. while (*lpszToken) {
  1106. switch (*lpszToken) {
  1107. case '0':
  1108. case '1':
  1109. case '2':
  1110. case '3':
  1111. case '4':
  1112. case '5':
  1113. case '6':
  1114. case '7':
  1115. case '8':
  1116. case '9':
  1117. *pudValue = ((*pudValue) * 10) + (*lpszToken - '0');
  1118. break;
  1119. default:
  1120. s_lstrcpy(lpstmt->szError, lpszToken);
  1121. return ERR_MALFORMEDNUMBER;
  1122. }
  1123. lpszToken++;
  1124. }
  1125. return ERR_SUCCESS;
  1126. }
  1127. /***************************************************************************/
  1128. RETCODE INTFUNC GetNumber(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  1129. SDWORD FAR *pcbSqlStr, double FAR *lpDouble,
  1130. LPUSTR lpszToken, SWORD FAR *lpDatatype,
  1131. SWORD FAR *lpScale)
  1132. /* Retrives a real number from the input stream. The number is returned */
  1133. /* in both lpDouble and lpszToken */
  1134. {
  1135. UWORD fType;
  1136. LPUSTR lpChar;
  1137. BOOL neg;
  1138. RETCODE err;
  1139. UCHAR szTempToken[MAX_TOKEN_SIZE + 1];
  1140. BOOL negExponent;
  1141. SWORD exponent;
  1142. SWORD iScale;
  1143. double scaleFactor;
  1144. /* Get Identifier */
  1145. err = GetToken(lpstmt, *lplpszSqlStr, *pcbSqlStr, lpszToken, &fType,
  1146. lplpszSqlStr, pcbSqlStr);
  1147. if (err != ERR_SUCCESS)
  1148. return err;
  1149. /* Figure out if value is negative */
  1150. if ((fType == TOKEN_TYPE_SYMBOL) && (!s_lstrcmpi("-", lpszToken))) {
  1151. neg = TRUE;
  1152. err = GetToken(lpstmt, *lplpszSqlStr, *pcbSqlStr, lpszToken, &fType,
  1153. lplpszSqlStr, pcbSqlStr);
  1154. if (err != ERR_SUCCESS)
  1155. return err;
  1156. }
  1157. else if ((fType == TOKEN_TYPE_SYMBOL) && (!s_lstrcmpi("+", lpszToken))) {
  1158. neg = FALSE;
  1159. err = GetToken(lpstmt, *lplpszSqlStr, *pcbSqlStr, lpszToken, &fType,
  1160. lplpszSqlStr, pcbSqlStr);
  1161. if (err != ERR_SUCCESS)
  1162. return err;
  1163. }
  1164. else
  1165. neg = FALSE;
  1166. /* Error if no number */
  1167. if (fType != TOKEN_TYPE_NUMBER) {
  1168. s_lstrcpy(lpstmt->szError, "<number>");
  1169. return ERR_EXPECTEDOTHER;
  1170. }
  1171. /* Error if number is too big */
  1172. if (s_lstrlen(lpszToken) >= MAX_TOKEN_SIZE) {
  1173. s_lstrcpy(lpstmt->szError, lpszToken);
  1174. return ERR_MALFORMEDNUMBER;
  1175. }
  1176. /* Convert the number from a text string. At the same time, figure */
  1177. /* out its datatype */
  1178. negExponent = FALSE;
  1179. exponent = 0;
  1180. *lpDouble = 0.0;
  1181. lpChar = lpszToken;
  1182. *lpDatatype = TYPE_INTEGER;
  1183. *lpScale = 0;
  1184. while (*lpChar != '\0') {
  1185. switch (*lpChar) {
  1186. case '0':
  1187. case '1':
  1188. case '2':
  1189. case '3':
  1190. case '4':
  1191. case '5':
  1192. case '6':
  1193. case '7':
  1194. case '8':
  1195. case '9':
  1196. /* Add the digit into the result */
  1197. switch (*lpDatatype) {
  1198. case TYPE_DOUBLE:
  1199. exponent = (exponent * 10) + (*lpChar - '0');
  1200. break;
  1201. case TYPE_NUMERIC:
  1202. *lpDouble = (*lpDouble * 10.0) + (*lpChar - '0');
  1203. (*lpScale)++;
  1204. break;
  1205. case TYPE_INTEGER:
  1206. *lpDouble = (*lpDouble * 10.0) + (*lpChar - '0');
  1207. break;
  1208. case TYPE_CHAR:
  1209. case TYPE_BINARY:
  1210. case TYPE_DATE:
  1211. case TYPE_TIME:
  1212. case TYPE_TIMESTAMP:
  1213. default:
  1214. return ERR_INTERNAL;
  1215. }
  1216. break;
  1217. case '.':
  1218. /* If a decimal point, this is a numeric value */
  1219. if (*lpDatatype != TYPE_INTEGER) {
  1220. s_lstrcpy(lpstmt->szError, lpszToken);
  1221. return ERR_MALFORMEDNUMBER;
  1222. }
  1223. *lpDatatype = TYPE_NUMERIC;
  1224. break;
  1225. case 'e':
  1226. case 'E':
  1227. /* If an E, this is a double value */
  1228. *lpDatatype = TYPE_DOUBLE;
  1229. /* Get sign of exponent */
  1230. if (*(lpChar+1) == '-') {
  1231. negExponent = TRUE;
  1232. lpChar++;
  1233. }
  1234. else if (*(lpChar+1) == '+') {
  1235. lpChar++;
  1236. }
  1237. break;
  1238. default:
  1239. s_lstrcpy(lpstmt->szError, lpszToken);
  1240. return ERR_MALFORMEDNUMBER;
  1241. }
  1242. lpChar++;
  1243. }
  1244. /* If scale of a numeric value is zero, remove trailing decimal point */
  1245. if ((*lpDatatype == TYPE_NUMERIC) && (*lpScale == 0)) {
  1246. lpszToken[s_lstrlen(lpszToken)-1] = '\0';
  1247. *lpDatatype = TYPE_INTEGER;
  1248. }
  1249. /* Return the number as a string */
  1250. if (neg) {
  1251. s_lstrcpy(szTempToken, lpszToken);
  1252. s_lstrcpy(lpszToken, "-");
  1253. s_lstrcat(lpszToken, szTempToken);
  1254. }
  1255. /* Adjust for scale */
  1256. iScale = -(*lpScale);
  1257. if (negExponent)
  1258. iScale -= (exponent);
  1259. else
  1260. iScale += (exponent);
  1261. scaleFactor = 1.0;
  1262. while (iScale > 0) {
  1263. scaleFactor = scaleFactor * 10.0;
  1264. iScale--;
  1265. }
  1266. *lpDouble = *lpDouble * scaleFactor;
  1267. scaleFactor = 1.0;
  1268. while (iScale < 0) {
  1269. scaleFactor = scaleFactor * 10.0;
  1270. iScale++;
  1271. }
  1272. *lpDouble = *lpDouble / scaleFactor;
  1273. /* Adjust for sign */
  1274. if (neg)
  1275. *lpDouble = -(*lpDouble);
  1276. /* Adjust scale */
  1277. if (*lpDatatype == TYPE_DOUBLE)
  1278. *lpScale = NO_SCALE;
  1279. return ERR_SUCCESS;
  1280. }
  1281. /***************************************************************************/
  1282. RETCODE INTFUNC GetIdent(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  1283. SDWORD FAR *pcbSqlStr, LPSTR lpszIdent,
  1284. LPUSTR lpszToken)
  1285. /* Retrives an identifier from the input stream. The value is returned. */
  1286. {
  1287. UWORD fType;
  1288. LPUSTR lpFrom;
  1289. SDWORD cbFrom;
  1290. RETCODE err;
  1291. /* Remove leading blanks */
  1292. lpFrom = *lplpszSqlStr;
  1293. cbFrom = *pcbSqlStr;
  1294. while ((cbFrom != 0) &&
  1295. ((*lpFrom == ' ') ||
  1296. (*lpFrom == '\012') ||
  1297. (*lpFrom == '\015') ||
  1298. (*lpFrom == '\011'))) {
  1299. lpFrom++;
  1300. cbFrom--;
  1301. }
  1302. if (cbFrom == 0)
  1303. return ERR_UNEXPECTEDEND;
  1304. if (*lpFrom == '"') {
  1305. if (lpszIdent != NULL)
  1306. s_lstrcpy(lpstmt->szError, lpszIdent);
  1307. else
  1308. s_lstrcpy(lpstmt->szError, "<keyword>");
  1309. return ERR_EXPECTEDOTHER;
  1310. }
  1311. /* Get Identifier */
  1312. err = GetToken(lpstmt, *lplpszSqlStr, *pcbSqlStr, lpszToken, &fType,
  1313. lplpszSqlStr, pcbSqlStr);
  1314. if (err != ERR_SUCCESS)
  1315. return err;
  1316. if ((fType != TOKEN_TYPE_IDENTIFIER) && (fType != TOKEN_TYPE_KEYWORD)) {
  1317. if (lpszIdent != NULL)
  1318. s_lstrcpy(lpstmt->szError, lpszIdent);
  1319. else
  1320. s_lstrcpy(lpstmt->szError, "<identifier>");
  1321. return ERR_EXPECTEDOTHER;
  1322. }
  1323. return ERR_SUCCESS;
  1324. }
  1325. /***************************************************************************/
  1326. RETCODE INTFUNC GetIdentifier(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  1327. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  1328. STRINGIDX FAR *lpIdx, LPUSTR lpszToken)
  1329. /* Retrives an identifier from the input stream and puts it into the */
  1330. /* string area. The value is also returned. */
  1331. {
  1332. UWORD fType;
  1333. RETCODE err;
  1334. /* Get Identifier */
  1335. err = GetToken(lpstmt, *lplpszSqlStr, *pcbSqlStr, lpszToken, &fType,
  1336. lplpszSqlStr, pcbSqlStr);
  1337. if (err != ERR_SUCCESS)
  1338. return err;
  1339. if (fType != TOKEN_TYPE_IDENTIFIER) {
  1340. s_lstrcpy(lpstmt->szError, "<identifier>");
  1341. return ERR_EXPECTEDOTHER;
  1342. }
  1343. /* Put value into the string area */
  1344. *lpIdx = AllocateString(lplpSql, lpszToken);
  1345. if (*lpIdx == NO_STRING)
  1346. return ERR_MEMALLOCFAIL;
  1347. return ERR_SUCCESS;
  1348. }
  1349. /***************************************************************************/
  1350. RETCODE INTFUNC GetKeyword(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  1351. SDWORD FAR *pcbSqlStr, LPSTR lpszKeyword,
  1352. LPUSTR lpszToken)
  1353. /* Retrives a keyword from the input stream. If lpszKeyword is not null, */
  1354. /* ERR_EXPECTEDOTHER is returned if the token found is not lpszKeyword. */
  1355. {
  1356. UWORD fType;
  1357. LPUSTR lpFrom;
  1358. SDWORD cbFrom;
  1359. RETCODE err;
  1360. /* Remove leading blanks */
  1361. lpFrom = *lplpszSqlStr;
  1362. cbFrom = *pcbSqlStr;
  1363. while ((cbFrom != 0) &&
  1364. ((*lpFrom == ' ') ||
  1365. (*lpFrom == '\012') ||
  1366. (*lpFrom == '\015') ||
  1367. (*lpFrom == '\011'))) {
  1368. lpFrom++;
  1369. cbFrom--;
  1370. }
  1371. if (cbFrom == 0)
  1372. return ERR_UNEXPECTEDEND;
  1373. if (*lpFrom == '"') {
  1374. if (lpszKeyword != NULL)
  1375. s_lstrcpy(lpstmt->szError, lpszKeyword);
  1376. else
  1377. s_lstrcpy(lpstmt->szError, "<keyword>");
  1378. return ERR_EXPECTEDOTHER;
  1379. }
  1380. /* Get Identifier */
  1381. err = GetToken(lpstmt, *lplpszSqlStr, *pcbSqlStr, lpszToken, &fType,
  1382. lplpszSqlStr, pcbSqlStr);
  1383. if (err != ERR_SUCCESS)
  1384. return err;
  1385. if (fType != TOKEN_TYPE_KEYWORD) {
  1386. if (lpszKeyword != NULL)
  1387. s_lstrcpy(lpstmt->szError, lpszKeyword);
  1388. else
  1389. s_lstrcpy(lpstmt->szError, "<keyword>");
  1390. return ERR_EXPECTEDOTHER;
  1391. }
  1392. /* Check value */
  1393. if (lpszKeyword != NULL) {
  1394. if (s_lstrcmpi(lpszKeyword, lpszToken)) {
  1395. s_lstrcpy(lpstmt->szError, lpszKeyword);
  1396. return ERR_EXPECTEDOTHER;
  1397. }
  1398. }
  1399. return ERR_SUCCESS;
  1400. }
  1401. /***************************************************************************/
  1402. RETCODE INTFUNC GetString(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  1403. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  1404. STRINGIDX FAR *lpIdx, LPUSTR lpszToken)
  1405. /* Retrives a string from the input stream and puts it into the string */
  1406. /* area. The value is also returned. */
  1407. {
  1408. UWORD fType;
  1409. RETCODE err;
  1410. /* Get Identifier */
  1411. err = GetToken(lpstmt, *lplpszSqlStr, *pcbSqlStr, lpszToken, &fType,
  1412. lplpszSqlStr, pcbSqlStr);
  1413. if (err != ERR_SUCCESS)
  1414. return err;
  1415. if (fType != TOKEN_TYPE_STRING) {
  1416. s_lstrcpy(lpstmt->szError, "<string>");
  1417. return ERR_EXPECTEDOTHER;
  1418. }
  1419. /* Put value into the string area */
  1420. *lpIdx = AllocateString(lplpSql, lpszToken);
  1421. if (*lpIdx == NO_STRING)
  1422. return ERR_MEMALLOCFAIL;
  1423. return ERR_SUCCESS;
  1424. }
  1425. /***************************************************************************/
  1426. /***************************************************************************/
  1427. RETCODE INTFUNC ParseTable(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  1428. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  1429. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  1430. /* Retrives a tablename from the input stream and creates a */
  1431. /* NODE_TYPE_TABLE node */
  1432. /* */
  1433. /* table ::= tablename */
  1434. {
  1435. RETCODE err;
  1436. LPSQLNODE lpSqlNode;
  1437. STRINGIDX idxName;
  1438. STRINGIDX idxQualifier;
  1439. /* Get the tablename */
  1440. err = GetIdentifier(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  1441. &idxName, lpszToken);
  1442. if (err != ERR_SUCCESS)
  1443. return err;
  1444. LPUSTR old_lpszSqlStr = *lplpszSqlStr;
  1445. SDWORD old_cbSqlStr = *pcbSqlStr;
  1446. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ".", lpszToken);
  1447. if (err != ERR_SUCCESS) {
  1448. /* No. unqualified table name */
  1449. *lplpszSqlStr = old_lpszSqlStr;
  1450. *pcbSqlStr = old_cbSqlStr;
  1451. idxQualifier = NO_STRING;
  1452. }
  1453. else {
  1454. /* Get the real table name */
  1455. idxQualifier = idxName;
  1456. err = GetIdentifier(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  1457. &idxName, lpszToken);
  1458. if (err != ERR_SUCCESS) {
  1459. /* This must be a simple table name. */ // seems a bit dgy, see ParseColRef
  1460. *lplpszSqlStr = old_lpszSqlStr;
  1461. *pcbSqlStr = old_cbSqlStr;
  1462. idxName = idxQualifier;
  1463. idxQualifier = NO_STRING;
  1464. }
  1465. }
  1466. /* Create the TABLE node */
  1467. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_TABLE);
  1468. if (*lpIdx == NO_SQLNODE)
  1469. return ERR_MEMALLOCFAIL;
  1470. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  1471. lpSqlNode->node.table.Name = idxName;
  1472. lpSqlNode->node.table.Qualifier = idxQualifier;
  1473. lpSqlNode->node.table.Alias = NO_STRING;
  1474. lpSqlNode->node.table.OuterJoinFromTables = NO_SQLNODE;
  1475. lpSqlNode->node.table.OuterJoinPredicate = NO_SQLNODE;
  1476. lpSqlNode->node.table.Handle = NULL;
  1477. lpSqlNode->node.table.cRestrict = 0;
  1478. lpSqlNode->node.table.Restrict = NO_SQLNODE;
  1479. lpSqlNode->node.table.Sortsequence = 0;
  1480. lpSqlNode->node.table.Sortcount = 0;
  1481. lpSqlNode->node.table.Sortcolumns = NO_SQLNODE;
  1482. lpSqlNode->node.table.AllNull = FALSE;
  1483. lpSqlNode->node.table.Rewound = TRUE;
  1484. return ERR_SUCCESS;
  1485. }
  1486. /***************************************************************************/
  1487. RETCODE INTFUNC ParseTableref(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  1488. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  1489. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  1490. /* Retrives a table reference from the input stream and creates a */
  1491. /* NODE_TYPE_TABLE node */
  1492. /* */
  1493. /* tableref ::= table aliasname | table */
  1494. {
  1495. RETCODE err;
  1496. LPUSTR old_lpszSqlStr;
  1497. SDWORD old_cbSqlStr;
  1498. LPSQLNODE lpSqlNode;
  1499. STRINGIDX idxAlias;
  1500. /* Get the table */
  1501. err = ParseTable(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, lpIdx,
  1502. lpszToken);
  1503. if (err != ERR_SUCCESS)
  1504. return err;
  1505. /* Alias given? */
  1506. old_lpszSqlStr = *lplpszSqlStr;
  1507. old_cbSqlStr = *pcbSqlStr;
  1508. err = GetIdentifier(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, &idxAlias,
  1509. lpszToken);
  1510. if (err != ERR_SUCCESS) {
  1511. /* No. No alias given */
  1512. *lplpszSqlStr = old_lpszSqlStr;
  1513. *pcbSqlStr = old_cbSqlStr;
  1514. idxAlias = NO_STRING;
  1515. }
  1516. else {
  1517. /* Yes. Save the alias */
  1518. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  1519. lpSqlNode->node.table.Alias = idxAlias;
  1520. }
  1521. return ERR_SUCCESS;
  1522. }
  1523. /***************************************************************************/
  1524. RETCODE INTFUNC ParseOJ(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  1525. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  1526. SQLNODEIDX FAR *lpIdxLeft, SQLNODEIDX FAR *lpIdxRight,
  1527. LPUSTR lpszToken)
  1528. /* Retrives an outer join from the input stream and creates two */
  1529. /* NODE_TYPE_TABLES nodes which are linked together. */
  1530. /* */
  1531. /* oj := tableref LEFT OUTER JOIN tableref ON boolean | */
  1532. /* tableref LEFT OUTER JOIN oj ON boolean */
  1533. {
  1534. RETCODE err;
  1535. SQLNODEIDX idxTableLeft;
  1536. SQLNODEIDX idxTableRight;
  1537. SQLNODEIDX idxTablesRight;
  1538. SQLNODEIDX idxPredicate;
  1539. LPSQLNODE lpSqlNode;
  1540. LPUSTR old_lpszSqlStr;
  1541. SDWORD old_cbSqlStr;
  1542. /* Get left table */
  1543. err = ParseTableref(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  1544. &idxTableLeft, lpszToken);
  1545. if (err != ERR_SUCCESS)
  1546. return err;
  1547. /* Get LEFT OUTER JOIN keywords */
  1548. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "LEFT", lpszToken);
  1549. if (err != ERR_SUCCESS)
  1550. return err;
  1551. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "OUTER", lpszToken);
  1552. if (err != ERR_SUCCESS)
  1553. return err;
  1554. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "JOIN", lpszToken);
  1555. if (err != ERR_SUCCESS)
  1556. return err;
  1557. /* Get nested outer join */
  1558. old_lpszSqlStr = *lplpszSqlStr;
  1559. old_cbSqlStr = *pcbSqlStr;
  1560. err = ParseOJ(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  1561. &idxTablesRight, lpIdxRight, lpszToken);
  1562. if (err == ERR_SUCCESS) {
  1563. lpSqlNode = ToNode(*lplpSql, idxTablesRight);
  1564. idxTableRight = lpSqlNode->node.tables.Table;
  1565. }
  1566. else {
  1567. /* Not a nested outer join. Just get right table */
  1568. *lplpszSqlStr = old_lpszSqlStr;
  1569. *pcbSqlStr = old_cbSqlStr;
  1570. err = ParseTableref(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  1571. &idxTableRight, lpszToken);
  1572. if (err != ERR_SUCCESS)
  1573. return err;
  1574. /* Create the TABLES node for the right table */
  1575. idxTablesRight = AllocateNode(lplpSql, NODE_TYPE_TABLES);
  1576. if (idxTablesRight == NO_SQLNODE)
  1577. return ERR_MEMALLOCFAIL;
  1578. lpSqlNode = ToNode(*lplpSql, idxTablesRight);
  1579. lpSqlNode->node.tables.Table = idxTableRight;
  1580. lpSqlNode->node.tables.Next = NO_SQLNODE;
  1581. *lpIdxRight = idxTablesRight;
  1582. }
  1583. /* Get ON keyword */
  1584. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "ON", lpszToken);
  1585. if (err != ERR_SUCCESS)
  1586. return err;
  1587. /* Get condition */
  1588. err = ParseBoolean(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  1589. &idxPredicate, lpszToken);
  1590. if (err != ERR_SUCCESS)
  1591. return err;
  1592. /* Create the TABLES node for the left table */
  1593. *lpIdxLeft = AllocateNode(lplpSql, NODE_TYPE_TABLES);
  1594. if (*lpIdxLeft == NO_SQLNODE)
  1595. return ERR_MEMALLOCFAIL;
  1596. lpSqlNode = ToNode(*lplpSql, *lpIdxLeft);
  1597. lpSqlNode->node.tables.Table = idxTableLeft;
  1598. lpSqlNode->node.tables.Next = idxTablesRight;
  1599. /* Put in outer join information into the right table node */
  1600. lpSqlNode = ToNode(*lplpSql, idxTableRight);
  1601. lpSqlNode->node.table.OuterJoinFromTables = *lpIdxLeft;
  1602. lpSqlNode->node.table.OuterJoinPredicate = idxPredicate;
  1603. return ERR_SUCCESS;
  1604. }
  1605. /***************************************************************************/
  1606. RETCODE INTFUNC ParseOuterJoin(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  1607. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  1608. SQLNODEIDX FAR *lpIdxLeft, SQLNODEIDX FAR *lpIdxRight,
  1609. LPUSTR lpszToken)
  1610. /* Retrives an outer join from the input stream and creates two */
  1611. /* NODE_TYPE_TABLES nodes which are linked together. */
  1612. /* */
  1613. /* ojshorthand := { OJ oj } */
  1614. /* ojescape := --*(VENDOR(MICROSOFT),PRODUCT(ODBC) OJ oj)*-- */
  1615. /* outerjoin ::= ojescape | ojshorthand */
  1616. {
  1617. RETCODE err;
  1618. BOOL fShorthand;
  1619. /* Get starting symbol */
  1620. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, NULL, lpszToken);
  1621. if (err != ERR_SUCCESS)
  1622. return err;
  1623. /* Shorthand? */
  1624. if (s_lstrcmpi(lpszToken, "{")) {
  1625. /* No. Not a shorthand */
  1626. fShorthand = FALSE;
  1627. /* If not an escape clause, error */
  1628. if (s_lstrcmpi(lpszToken, "--")) {
  1629. s_lstrcpy(lpstmt->szError, "--");
  1630. return ERR_EXPECTEDOTHER;
  1631. }
  1632. /* Get the rest of the starting sequence */
  1633. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "(", lpszToken);
  1634. if (err != ERR_SUCCESS)
  1635. return err;
  1636. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "*", lpszToken);
  1637. if (err != ERR_SUCCESS)
  1638. return err;
  1639. err = GetIdent(lpstmt, lplpszSqlStr, pcbSqlStr, "vendor", lpszToken);
  1640. if (err != ERR_SUCCESS)
  1641. return err;
  1642. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "(", lpszToken);
  1643. if (err != ERR_SUCCESS)
  1644. return err;
  1645. err = GetIdent(lpstmt, lplpszSqlStr, pcbSqlStr, "Microsoft", lpszToken);
  1646. if (err != ERR_SUCCESS)
  1647. return err;
  1648. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ")", lpszToken);
  1649. if (err != ERR_SUCCESS)
  1650. return err;
  1651. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ",", lpszToken);
  1652. if (err != ERR_SUCCESS)
  1653. return err;
  1654. err = GetIdent(lpstmt, lplpszSqlStr, pcbSqlStr, "product", lpszToken);
  1655. if (err != ERR_SUCCESS)
  1656. return err;
  1657. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "(", lpszToken);
  1658. if (err != ERR_SUCCESS)
  1659. return err;
  1660. err = GetIdent(lpstmt, lplpszSqlStr, pcbSqlStr, "ODBC", lpszToken);
  1661. if (err != ERR_SUCCESS)
  1662. return err;
  1663. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ")", lpszToken);
  1664. if (err != ERR_SUCCESS)
  1665. return err;
  1666. }
  1667. else
  1668. fShorthand = TRUE;
  1669. /* Get OJ keyword */
  1670. err = GetIdent(lpstmt, lplpszSqlStr, pcbSqlStr, "oj", lpszToken);
  1671. if (err != ERR_SUCCESS)
  1672. return err;
  1673. /* Get outer join tables and condition */
  1674. err = ParseOJ(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  1675. lpIdxLeft, lpIdxRight, lpszToken);
  1676. if (err != ERR_SUCCESS)
  1677. return err;
  1678. /* Get closing bracket */
  1679. if (!fShorthand) {
  1680. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "*", lpszToken);
  1681. if (err != ERR_SUCCESS)
  1682. return err;
  1683. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ")", lpszToken);
  1684. if (err != ERR_SUCCESS)
  1685. return err;
  1686. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "--", lpszToken);
  1687. if (err != ERR_SUCCESS)
  1688. return err;
  1689. }
  1690. else {
  1691. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "}", lpszToken);
  1692. if (err != ERR_SUCCESS)
  1693. return err;
  1694. }
  1695. return ERR_SUCCESS;
  1696. }
  1697. /***************************************************************************/
  1698. RETCODE INTFUNC ParseTablelist(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  1699. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  1700. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  1701. /* Retrives a list of tablenames from the input stream and creates a */
  1702. /* NODE_TYPE_TABLES node */
  1703. /* */
  1704. /* tablelistitem ::= tableref | outerjoin */
  1705. /* tablelist ::= tablelistitem , tablelist | tablelistitem */
  1706. {
  1707. RETCODE err;
  1708. LPUSTR old_lpszSqlStr;
  1709. SDWORD old_cbSqlStr;
  1710. LPSQLNODE lpSqlNode;
  1711. SQLNODEIDX idxTables;
  1712. SQLNODEIDX idxTable;
  1713. SQLNODEIDX idxRight;
  1714. BOOL fOuterJoin;
  1715. /* Outerjoin? */
  1716. old_lpszSqlStr = *lplpszSqlStr;
  1717. old_cbSqlStr = *pcbSqlStr;
  1718. err = ParseOuterJoin(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, lpIdx,
  1719. &idxRight, lpszToken);
  1720. if (err != ERR_SUCCESS) {
  1721. /* No. Table reference? */
  1722. *lplpszSqlStr = old_lpszSqlStr;
  1723. *pcbSqlStr = old_cbSqlStr;
  1724. err = ParseTableref(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  1725. &idxTable, lpszToken);
  1726. if (err != ERR_SUCCESS)
  1727. return err;
  1728. fOuterJoin = FALSE;
  1729. }
  1730. else
  1731. fOuterJoin = TRUE;
  1732. /* Is there a comma? */
  1733. old_lpszSqlStr = *lplpszSqlStr;
  1734. old_cbSqlStr = *pcbSqlStr;
  1735. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ",", lpszToken);
  1736. if (err != ERR_SUCCESS) {
  1737. /* No. This is the last one */
  1738. *lplpszSqlStr = old_lpszSqlStr;
  1739. *pcbSqlStr = old_cbSqlStr;
  1740. idxTables = NO_SQLNODE;
  1741. }
  1742. else {
  1743. /* Yes. Get the rest of the list */
  1744. err = ParseTablelist(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  1745. &idxTables, lpszToken);
  1746. if (err != ERR_SUCCESS)
  1747. return err;
  1748. }
  1749. /* Outer join? */
  1750. if (!fOuterJoin) {
  1751. /* No. Create the TABLES node */
  1752. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_TABLES);
  1753. if (*lpIdx == NO_SQLNODE)
  1754. return ERR_MEMALLOCFAIL;
  1755. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  1756. lpSqlNode->node.tables.Table = idxTable;
  1757. lpSqlNode->node.tables.Next = idxTables;
  1758. }
  1759. else {
  1760. /* Yes. Link right side to the rest of the list */
  1761. if (idxTables != NO_SQLNODE) {
  1762. lpSqlNode = ToNode(*lplpSql, idxRight);
  1763. lpSqlNode->node.tables.Next = idxTables;
  1764. }
  1765. }
  1766. return ERR_SUCCESS;
  1767. }
  1768. /***************************************************************************/
  1769. RETCODE INTFUNC ParseColref(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  1770. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  1771. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  1772. /* Retrives a pattern from the input stream and creates a */
  1773. /* NODE_TYPE_COLUMN node */
  1774. /* */
  1775. /* colref ::= aliasname . columnname | columnname */
  1776. {
  1777. RETCODE err;
  1778. LPUSTR old_lpszSqlStr;
  1779. SDWORD old_cbSqlStr;
  1780. LPSQLNODE lpSqlNode;
  1781. STRINGIDX idxColumn = NO_STRING;
  1782. STRINGIDX idxAlias = NO_STRING;
  1783. STRINGIDX idxQualifier = NO_STRING;
  1784. /* Get the columnname */
  1785. err = GetIdentifier(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  1786. &idxColumn, lpszToken);
  1787. if (err != ERR_SUCCESS)
  1788. return err;
  1789. /* Qualified column name? */
  1790. old_lpszSqlStr = *lplpszSqlStr;
  1791. old_cbSqlStr = *pcbSqlStr;
  1792. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ".", lpszToken);
  1793. if (err != ERR_SUCCESS) {
  1794. /* No. Simple column name */
  1795. *lplpszSqlStr = old_lpszSqlStr;
  1796. *pcbSqlStr = old_cbSqlStr;
  1797. idxAlias = NO_STRING;
  1798. idxQualifier = NO_STRING;
  1799. }
  1800. else {
  1801. /* Get the real columnname */
  1802. idxAlias = idxColumn;
  1803. err = GetIdentifier(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  1804. &idxColumn, lpszToken);
  1805. if (err != ERR_SUCCESS) {
  1806. /* This must be a simple column name. */
  1807. *lplpszSqlStr = old_lpszSqlStr;
  1808. *pcbSqlStr = old_cbSqlStr;
  1809. idxColumn = idxAlias;
  1810. idxAlias = NO_STRING;
  1811. idxQualifier = NO_STRING;
  1812. }
  1813. else
  1814. {
  1815. old_lpszSqlStr = *lplpszSqlStr;
  1816. old_cbSqlStr = *pcbSqlStr;
  1817. err = GetSymbol (lpstmt, lplpszSqlStr, pcbSqlStr, ".", lpszToken);
  1818. if (err != ERR_SUCCESS)
  1819. {
  1820. /* No. No qualifier. */
  1821. *lplpszSqlStr = old_lpszSqlStr;
  1822. *pcbSqlStr = old_cbSqlStr;
  1823. idxQualifier = NO_STRING;
  1824. }
  1825. else
  1826. {
  1827. idxQualifier = idxAlias;
  1828. idxAlias = idxColumn;
  1829. err = GetIdentifier(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  1830. &idxColumn, lpszToken);
  1831. if (err != ERR_SUCCESS) {
  1832. /* This must be a simple column name. */
  1833. *lplpszSqlStr = old_lpszSqlStr;
  1834. *pcbSqlStr = old_cbSqlStr;
  1835. idxColumn = idxAlias;
  1836. idxAlias = idxQualifier;
  1837. idxQualifier = NO_STRING;
  1838. }
  1839. }
  1840. }
  1841. }
  1842. /* Create the COLUMN node */
  1843. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_COLUMN);
  1844. if (*lpIdx == NO_SQLNODE)
  1845. return ERR_MEMALLOCFAIL;
  1846. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  1847. lpSqlNode->node.column.Tablealias = idxAlias;
  1848. lpSqlNode->node.column.Column = idxColumn;
  1849. lpSqlNode->node.column.Qualifier = idxQualifier;
  1850. /* These will be filled in by SemanticCheck() */
  1851. lpSqlNode->node.column.TableIndex = NO_SQLNODE;
  1852. lpSqlNode->node.column.MatchedAlias = FALSE;
  1853. lpSqlNode->node.column.Table = NO_SQLNODE;
  1854. lpSqlNode->node.column.Id = -1;
  1855. lpSqlNode->node.column.Value = NO_STRING;
  1856. lpSqlNode->node.column.InSortRecord = FALSE;
  1857. lpSqlNode->node.column.Offset = 0;
  1858. lpSqlNode->node.column.Length = 0;
  1859. lpSqlNode->node.column.DistinctOffset = 0;
  1860. lpSqlNode->node.column.DistinctLength = 0;
  1861. lpSqlNode->node.column.EnclosingStatement = NO_SQLNODE;
  1862. return ERR_SUCCESS;
  1863. }
  1864. /***************************************************************************/
  1865. RETCODE INTFUNC ParseOrderbyterm(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  1866. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  1867. SQLNODEIDX FAR *lpIdx, BOOL FAR *lpfDescending,
  1868. LPUSTR lpszToken)
  1869. /* Retrives a sort order from the input stream and creates a */
  1870. /* NODE_TYPE_COLUMN or NODE_TYPE_NUMERIC node */
  1871. /* */
  1872. /* orderbyterm ::= colref asc | integer asc */
  1873. /* asc ::= | ASC | DESC */
  1874. {
  1875. RETCODE err;
  1876. LPUSTR old_lpszSqlStr;
  1877. SDWORD old_cbSqlStr;
  1878. LPSQLNODE lpSqlNode;
  1879. UDWORD udInteger;
  1880. /* Integer specified? */
  1881. old_lpszSqlStr = *lplpszSqlStr;
  1882. old_cbSqlStr = *pcbSqlStr;
  1883. err = GetInteger(lpstmt, lplpszSqlStr, pcbSqlStr, &udInteger,
  1884. lpszToken);
  1885. if (err != ERR_SUCCESS) {
  1886. /* No. Get column reference instead */
  1887. *lplpszSqlStr = old_lpszSqlStr;
  1888. *pcbSqlStr = old_cbSqlStr;
  1889. err = ParseColref(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, lpIdx,
  1890. lpszToken);
  1891. if (err != ERR_SUCCESS)
  1892. return err;
  1893. }
  1894. else {
  1895. /* Yes. Return it */
  1896. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_NUMERIC);
  1897. if (*lpIdx == NO_SQLNODE)
  1898. return ERR_MEMALLOCFAIL;
  1899. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  1900. lpSqlNode->sqlDataType = TYPE_INTEGER;
  1901. lpSqlNode->sqlSqlType = SQL_INTEGER;
  1902. lpSqlNode->sqlPrecision = 10;
  1903. lpSqlNode->sqlScale = 0;
  1904. lpSqlNode->node.numeric.Value = udInteger;
  1905. lpSqlNode->node.numeric.Numeric = AllocateString(lplpSql, lpszToken);
  1906. if (lpSqlNode->node.numeric.Numeric == NO_STRING)
  1907. return ERR_MEMALLOCFAIL;
  1908. }
  1909. /* Get ASC or DESC */
  1910. old_lpszSqlStr = *lplpszSqlStr;
  1911. old_cbSqlStr = *pcbSqlStr;
  1912. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, NULL, lpszToken);
  1913. if (err != ERR_SUCCESS) {
  1914. *lplpszSqlStr = old_lpszSqlStr;
  1915. *pcbSqlStr = old_cbSqlStr;
  1916. *lpfDescending = FALSE;
  1917. }
  1918. else if (!s_lstrcmpi(lpszToken, "ASC")) {
  1919. *lpfDescending = FALSE;
  1920. }
  1921. else if (!s_lstrcmpi(lpszToken, "DESC")) {
  1922. *lpfDescending = TRUE;
  1923. }
  1924. else {
  1925. *lplpszSqlStr = old_lpszSqlStr;
  1926. *pcbSqlStr = old_cbSqlStr;
  1927. *lpfDescending = FALSE;
  1928. }
  1929. return ERR_SUCCESS;
  1930. }
  1931. /***************************************************************************/
  1932. RETCODE INTFUNC ParseOrderbyterms(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  1933. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  1934. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  1935. /* Retrives a sort order from the input stream and creates a */
  1936. /* NODE_TYPE_SORTCOLUMNS node */
  1937. /* */
  1938. /* orderbyterms ::= orderbyterm | orderbyterm , orderbyterms */
  1939. {
  1940. RETCODE err;
  1941. LPUSTR old_lpszSqlStr;
  1942. SDWORD old_cbSqlStr;
  1943. LPSQLNODE lpSqlNode;
  1944. BOOL fDescending;
  1945. SQLNODEIDX idxColumn;
  1946. SQLNODEIDX idxSortcolumns;
  1947. SQLNODEIDX idxSortcolumnsPrev;
  1948. /* Get list of nodes */
  1949. idxSortcolumnsPrev = NO_SQLNODE;
  1950. while (TRUE) {
  1951. /* Get orderby column */
  1952. err = ParseOrderbyterm(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  1953. &idxColumn, &fDescending, lpszToken);
  1954. if (err != ERR_SUCCESS)
  1955. return err;
  1956. /* Create the SORTCOLUMNS node */
  1957. idxSortcolumns = AllocateNode(lplpSql, NODE_TYPE_SORTCOLUMNS);
  1958. if (idxSortcolumns == NO_SQLNODE)
  1959. return ERR_MEMALLOCFAIL;
  1960. lpSqlNode = ToNode(*lplpSql, idxSortcolumns);
  1961. lpSqlNode->node.sortcolumns.Column = idxColumn;
  1962. lpSqlNode->node.sortcolumns.Descending = fDescending;
  1963. lpSqlNode->node.sortcolumns.Next = NO_SQLNODE;
  1964. /* Put node on list */
  1965. if (idxSortcolumnsPrev != NO_SQLNODE) {
  1966. lpSqlNode = ToNode(*lplpSql, idxSortcolumnsPrev);
  1967. lpSqlNode->node.sortcolumns.Next = idxSortcolumns;
  1968. }
  1969. else
  1970. *lpIdx = idxSortcolumns;
  1971. idxSortcolumnsPrev = idxSortcolumns;
  1972. /* Is there a comma? */
  1973. old_lpszSqlStr = *lplpszSqlStr;
  1974. old_cbSqlStr = *pcbSqlStr;
  1975. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ",", lpszToken);
  1976. if (err != ERR_SUCCESS) {
  1977. /* No. This is the last orderby column */
  1978. *lplpszSqlStr = old_lpszSqlStr;
  1979. *pcbSqlStr = old_cbSqlStr;
  1980. break;
  1981. }
  1982. }
  1983. return ERR_SUCCESS;
  1984. }
  1985. /***************************************************************************/
  1986. RETCODE INTFUNC ParseOrderby(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  1987. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  1988. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  1989. /* Retrives a sort order from the input stream and creates a */
  1990. /* NODE_TYPE_SORTCOLUMNS or NULL node */
  1991. /* */
  1992. /* orderby ::= | ORDER BY orderbyterms */
  1993. {
  1994. RETCODE err;
  1995. LPUSTR old_lpszSqlStr;
  1996. SDWORD old_cbSqlStr;
  1997. /* Is there an "ORDER BY"? */
  1998. old_lpszSqlStr = *lplpszSqlStr;
  1999. old_cbSqlStr = *pcbSqlStr;
  2000. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "ORDER", lpszToken);
  2001. if (err != ERR_SUCCESS) {
  2002. /* No. Return null */
  2003. *lplpszSqlStr = old_lpszSqlStr;
  2004. *pcbSqlStr = old_cbSqlStr;
  2005. *lpIdx = NO_SQLNODE;
  2006. }
  2007. else {
  2008. /* Yes. Get keyword */
  2009. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "BY", lpszToken);
  2010. if (err != ERR_SUCCESS)
  2011. return err;
  2012. /* Get orderby column */
  2013. err = ParseOrderbyterms(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  2014. lpIdx, lpszToken);
  2015. if (err != ERR_SUCCESS)
  2016. return err;
  2017. }
  2018. return ERR_SUCCESS;
  2019. }
  2020. /***************************************************************************/
  2021. RETCODE INTFUNC ParseGroupbyterms(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  2022. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  2023. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  2024. /* Retrives a sort order from the input stream and creates a */
  2025. /* NODE_TYPE_SORTCOLUMNS node */
  2026. /* */
  2027. /* groupbyterms ::= colref | colref , groupbyterms */
  2028. {
  2029. RETCODE err;
  2030. LPUSTR old_lpszSqlStr;
  2031. SDWORD old_cbSqlStr;
  2032. LPSQLNODE lpSqlNode;
  2033. SQLNODEIDX idxColumn;
  2034. SQLNODEIDX idxGroupbycolumns;
  2035. SQLNODEIDX idxGroupbycolumnsPrev;
  2036. /* Get list of nodes */
  2037. idxGroupbycolumnsPrev = NO_SQLNODE;
  2038. while (TRUE) {
  2039. /* Get column reference */
  2040. err = ParseColref(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  2041. &idxColumn, lpszToken);
  2042. if (err != ERR_SUCCESS)
  2043. return err;
  2044. /* Create the GROUPBYCOLUMNS node */
  2045. idxGroupbycolumns = AllocateNode(lplpSql, NODE_TYPE_GROUPBYCOLUMNS);
  2046. if (idxGroupbycolumns == NO_SQLNODE)
  2047. return ERR_MEMALLOCFAIL;
  2048. lpSqlNode = ToNode(*lplpSql, idxGroupbycolumns);
  2049. lpSqlNode->node.groupbycolumns.Column = idxColumn;
  2050. lpSqlNode->node.groupbycolumns.Next = NO_SQLNODE;
  2051. /* Put node on list */
  2052. if (idxGroupbycolumnsPrev != NO_SQLNODE) {
  2053. lpSqlNode = ToNode(*lplpSql, idxGroupbycolumnsPrev);
  2054. lpSqlNode->node.groupbycolumns.Next = idxGroupbycolumns;
  2055. }
  2056. else
  2057. *lpIdx = idxGroupbycolumns;
  2058. idxGroupbycolumnsPrev = idxGroupbycolumns;
  2059. /* Is there a comma? */
  2060. old_lpszSqlStr = *lplpszSqlStr;
  2061. old_cbSqlStr = *pcbSqlStr;
  2062. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ",", lpszToken);
  2063. if (err != ERR_SUCCESS) {
  2064. /* No. This is the last groupbyby column */
  2065. *lplpszSqlStr = old_lpszSqlStr;
  2066. *pcbSqlStr = old_cbSqlStr;
  2067. break;
  2068. }
  2069. }
  2070. return ERR_SUCCESS;
  2071. }
  2072. /***************************************************************************/
  2073. RETCODE INTFUNC ParseGroupby(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  2074. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  2075. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  2076. /* Retrives a sort order from the input stream and creates a */
  2077. /* NODE_TYPE_GROUPBYCOLUMNS or NULL node */
  2078. /* */
  2079. /* groupby ::= | GROUP BY groupbyterms */
  2080. {
  2081. RETCODE err;
  2082. LPUSTR old_lpszSqlStr;
  2083. SDWORD old_cbSqlStr;
  2084. /* Is there an "GROUP BY"? */
  2085. old_lpszSqlStr = *lplpszSqlStr;
  2086. old_cbSqlStr = *pcbSqlStr;
  2087. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "GROUP", lpszToken);
  2088. if (err != ERR_SUCCESS) {
  2089. /* No. Return null */
  2090. *lplpszSqlStr = old_lpszSqlStr;
  2091. *pcbSqlStr = old_cbSqlStr;
  2092. *lpIdx = NO_SQLNODE;
  2093. }
  2094. else {
  2095. /* Yes. Get keyword */
  2096. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "BY", lpszToken);
  2097. if (err != ERR_SUCCESS)
  2098. return err;
  2099. /* Get grooupby columns */
  2100. err = ParseGroupbyterms(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  2101. lpIdx, lpszToken);
  2102. if (err != ERR_SUCCESS)
  2103. return err;
  2104. }
  2105. return ERR_SUCCESS;
  2106. }
  2107. /***************************************************************************/
  2108. RETCODE INTFUNC ParseSimpleterm(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  2109. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  2110. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  2111. /* Retrives a term from the input stream and creates a NODE_TYPE_STRING, */
  2112. /* NODE_TYPE_NUMERIC, NODE_TYPE_PARAMETER, NODE_TYPE_USER, NODE_TYPE_DATE, */
  2113. /* NODE_TYPE_TIME, or NODE_TYPE_TIMESTAMP node. */
  2114. /* */
  2115. /* simpleterm ::= string | realnumber | ? | USER | date | time | timestamp */
  2116. {
  2117. RETCODE err;
  2118. LPUSTR old_lpszSqlStr;
  2119. SDWORD old_cbSqlStr;
  2120. STRINGIDX idxString;
  2121. LPSQLNODE lpSqlNode;
  2122. double dbl;
  2123. SQLNODEIDX idxParameter;
  2124. UWORD parameterId;
  2125. SWORD datatype;
  2126. SWORD scale;
  2127. DATE_STRUCT date;
  2128. TIME_STRUCT time;
  2129. TIMESTAMP_STRUCT timestamp;
  2130. /* Is it a string? */
  2131. old_lpszSqlStr = *lplpszSqlStr;
  2132. old_cbSqlStr = *pcbSqlStr;
  2133. err = GetString(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  2134. &idxString, lpszToken);
  2135. if (err != ERR_SUCCESS) {
  2136. /* No. Is it a parameter */
  2137. *lplpszSqlStr = old_lpszSqlStr;
  2138. *pcbSqlStr = old_cbSqlStr;
  2139. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "?", lpszToken);
  2140. if (err != ERR_SUCCESS) {
  2141. /* No. Is it USER? */
  2142. *lplpszSqlStr = old_lpszSqlStr;
  2143. *pcbSqlStr = old_cbSqlStr;
  2144. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "USER",
  2145. lpszToken);
  2146. if (err != ERR_SUCCESS) {
  2147. /* No. Is it a realnumber? */
  2148. *lplpszSqlStr = old_lpszSqlStr;
  2149. *pcbSqlStr = old_cbSqlStr;
  2150. err = GetNumber(lpstmt, lplpszSqlStr, pcbSqlStr, &dbl,
  2151. lpszToken, &datatype, &scale);
  2152. if (err != ERR_SUCCESS) {
  2153. /* No. Is it an escape sequence? */
  2154. *lplpszSqlStr = old_lpszSqlStr;
  2155. *pcbSqlStr = old_cbSqlStr;
  2156. err = GetEscape(lpstmt, *lplpszSqlStr, *pcbSqlStr,
  2157. lpszToken, lplpszSqlStr, pcbSqlStr);
  2158. if (err != ERR_SUCCESS) {
  2159. if (err == ERR_EXPECTEDOTHER)
  2160. s_lstrcpy(lpstmt->szError, "<simpleterm>");
  2161. return err;
  2162. }
  2163. /* It is an escape sequence. A date? */
  2164. if (!CharToDate(lpszToken, SQL_NTS, &date)) {
  2165. /* Make date node */
  2166. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_DATE);
  2167. if (*lpIdx == NO_SQLNODE)
  2168. return ERR_MEMALLOCFAIL;
  2169. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  2170. lpSqlNode->node.date.Value = date;
  2171. }
  2172. /* A time? */
  2173. else if (!CharToTime(lpszToken, SQL_NTS, &time)) {
  2174. /* Make time node */
  2175. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_TIME);
  2176. if (*lpIdx == NO_SQLNODE)
  2177. return ERR_MEMALLOCFAIL;
  2178. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  2179. lpSqlNode->node.time.Value = time;
  2180. }
  2181. /* A timestamp? */
  2182. else if (!CharToTimestamp(lpszToken, SQL_NTS, &timestamp)) {
  2183. /* Make timestamp node */
  2184. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_TIMESTAMP);
  2185. if (*lpIdx == NO_SQLNODE)
  2186. return ERR_MEMALLOCFAIL;
  2187. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  2188. lpSqlNode->node.timestamp.Value = timestamp;
  2189. }
  2190. else {
  2191. s_lstrcpy(lpstmt->szError, lpszToken);
  2192. return ERR_BADESCAPE;
  2193. }
  2194. }
  2195. else {
  2196. /* Make numeric node */
  2197. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_NUMERIC);
  2198. if (*lpIdx == NO_SQLNODE)
  2199. return ERR_MEMALLOCFAIL;
  2200. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  2201. if ((s_lstrlen(lpszToken) >= 10) &&
  2202. (datatype == TYPE_INTEGER)) {
  2203. datatype = TYPE_DOUBLE;
  2204. scale = NO_SCALE;
  2205. }
  2206. switch (datatype) {
  2207. case TYPE_DOUBLE:
  2208. lpSqlNode->sqlDataType = TYPE_DOUBLE;
  2209. lpSqlNode->sqlSqlType = SQL_DOUBLE;
  2210. lpSqlNode->sqlPrecision = 15;
  2211. lpSqlNode->sqlScale = NO_SCALE;
  2212. break;
  2213. case TYPE_INTEGER:
  2214. lpSqlNode->sqlDataType = TYPE_INTEGER;
  2215. lpSqlNode->sqlSqlType = SQL_INTEGER;
  2216. lpSqlNode->sqlPrecision = 10;
  2217. lpSqlNode->sqlScale = 0;
  2218. break;
  2219. case TYPE_NUMERIC:
  2220. lpSqlNode->sqlDataType = TYPE_NUMERIC;
  2221. lpSqlNode->sqlSqlType = SQL_DECIMAL;
  2222. if (*lpszToken != '-')
  2223. lpSqlNode->sqlPrecision = s_lstrlen(lpszToken)-1;
  2224. else
  2225. lpSqlNode->sqlPrecision = s_lstrlen(lpszToken)-2;
  2226. lpSqlNode->sqlScale = scale;
  2227. BCDNormalize(lpszToken, s_lstrlen(lpszToken),
  2228. lpszToken, s_lstrlen(lpszToken) + 1,
  2229. lpSqlNode->sqlPrecision,
  2230. lpSqlNode->sqlScale);
  2231. break;
  2232. case TYPE_CHAR:
  2233. case TYPE_BINARY:
  2234. case TYPE_DATE:
  2235. case TYPE_TIME:
  2236. case TYPE_TIMESTAMP:
  2237. default:
  2238. return ERR_INTERNAL;
  2239. }
  2240. lpSqlNode->node.numeric.Numeric = AllocateSpace(lplpSql,
  2241. (SWORD) (s_lstrlen(lpszToken) + 2));
  2242. /* The extra space is to allow negation of */
  2243. /* this value in SEMANTIC.C */
  2244. if (lpSqlNode->node.numeric.Numeric == NO_STRING)
  2245. return ERR_MEMALLOCFAIL;
  2246. s_lstrcpy(ToString(*lplpSql, lpSqlNode->node.numeric.Numeric),
  2247. lpszToken);
  2248. lpSqlNode->node.numeric.Value = dbl;
  2249. }
  2250. }
  2251. else {
  2252. /* Yes. Make USER node */
  2253. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_USER);
  2254. if (*lpIdx == NO_SQLNODE)
  2255. return ERR_MEMALLOCFAIL;
  2256. }
  2257. }
  2258. else {
  2259. /* Yes. Make PARAMETER node */
  2260. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_PARAMETER);
  2261. if (*lpIdx == NO_SQLNODE)
  2262. return ERR_MEMALLOCFAIL;
  2263. /* First parameter? */
  2264. idxParameter = (*lplpSql)->node.root.parameters;
  2265. if (idxParameter == NO_SQLNODE) {
  2266. /* Yes. Initialize list of parameters */
  2267. (*lplpSql)->node.root.parameters = *lpIdx;
  2268. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  2269. lpSqlNode->node.parameter.Id = 1;
  2270. }
  2271. else {
  2272. /* No. Get last element of parameter list */
  2273. while (TRUE) {
  2274. lpSqlNode = ToNode(*lplpSql, idxParameter);
  2275. idxParameter = lpSqlNode->node.parameter.Next;
  2276. if (idxParameter == NO_SQLNODE)
  2277. break;
  2278. }
  2279. /* Put node on list */
  2280. lpSqlNode->node.parameter.Next = *lpIdx;
  2281. /* Determine id of parameter */
  2282. parameterId = lpSqlNode->node.parameter.Id + 1;
  2283. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  2284. lpSqlNode->node.parameter.Id = parameterId;
  2285. }
  2286. lpSqlNode->node.parameter.Next = NO_SQLNODE;
  2287. lpSqlNode->node.parameter.Value = NO_STRING;
  2288. lpSqlNode->node.parameter.AtExec = FALSE;
  2289. }
  2290. }
  2291. else {
  2292. /* Yes. Make STRING node */
  2293. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_STRING);
  2294. if (*lpIdx == NO_SQLNODE)
  2295. return ERR_MEMALLOCFAIL;
  2296. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  2297. lpSqlNode->node.string.Value = idxString;
  2298. }
  2299. return ERR_SUCCESS;
  2300. }
  2301. /***************************************************************************/
  2302. RETCODE INTFUNC ParseAggterm(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  2303. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  2304. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  2305. /* Retrives a term from the input stream and creates a NODE_TYPE_AGGREGATE */
  2306. /* node. */
  2307. /* */
  2308. /* aggterm ::= COUNT ( * ) | AVG ( expression ) | MAX ( expression ) | */
  2309. /* MIN ( expression ) | SUM ( expression ) */
  2310. {
  2311. RETCODE err;
  2312. UWORD op;
  2313. SQLNODEIDX idxExpression;
  2314. LPSQLNODE lpSqlNode;
  2315. /* Get starting keyword */
  2316. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, NULL, lpszToken);
  2317. if (err != ERR_SUCCESS)
  2318. return err;
  2319. //double check for aggregate functions not supported
  2320. if (lpszToken && !s_lstrcmpi(lpszToken, "LEN"))
  2321. {
  2322. return ERR_LEN_NOTSUPP;
  2323. }
  2324. /* Convert it to an aggregate operator */
  2325. if (!s_lstrcmpi(lpszToken, "COUNT"))
  2326. op = AGG_COUNT;
  2327. else if (!s_lstrcmpi(lpszToken, "AVG"))
  2328. op = AGG_AVG;
  2329. else if (!s_lstrcmpi(lpszToken, "MAX"))
  2330. op = AGG_MAX;
  2331. else if (!s_lstrcmpi(lpszToken, "MIN"))
  2332. op = AGG_MIN;
  2333. else if (!s_lstrcmpi(lpszToken, "SUM"))
  2334. op = AGG_SUM;
  2335. else {
  2336. s_lstrcpy(lpstmt->szError, "COUNT, AVG, MAX, MIN, or SUM");
  2337. return ERR_EXPECTEDOTHER;
  2338. }
  2339. /* Get opening paren */
  2340. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "(", lpszToken);
  2341. if (err != ERR_SUCCESS)
  2342. return err;
  2343. /* Based on type of operator... */
  2344. switch(op) {
  2345. case AGG_COUNT:
  2346. /* Get * */
  2347. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "*", lpszToken);
  2348. if (err != ERR_SUCCESS)
  2349. return ERR_COUNT_NOTSUPP;
  2350. idxExpression = NO_SQLNODE;
  2351. break;
  2352. case AGG_AVG:
  2353. case AGG_MAX:
  2354. case AGG_MIN:
  2355. case AGG_SUM:
  2356. /* Get expression */
  2357. err = ParseExpression(lpstmt, lplpszSqlStr, pcbSqlStr,
  2358. lplpSql, &idxExpression, lpszToken);
  2359. if (err != ERR_SUCCESS)
  2360. return err;
  2361. break;
  2362. default:
  2363. return ERR_INTERNAL;
  2364. }
  2365. /* Get closing paren */
  2366. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ")", lpszToken);
  2367. if (err != ERR_SUCCESS)
  2368. return err;
  2369. /* Make AGGREGATE node */
  2370. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_AGGREGATE);
  2371. if (*lpIdx == NO_SQLNODE)
  2372. return ERR_MEMALLOCFAIL;
  2373. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  2374. lpSqlNode->node.aggregate.Operator = op;
  2375. lpSqlNode->node.aggregate.Expression = idxExpression;
  2376. lpSqlNode->node.aggregate.Value = NO_STRING;
  2377. lpSqlNode->node.aggregate.Offset = 0;
  2378. lpSqlNode->node.aggregate.Length = 0;
  2379. lpSqlNode->node.aggregate.DistinctOffset = 0;
  2380. lpSqlNode->node.aggregate.DistinctLength = 0;
  2381. lpSqlNode->node.aggregate.EnclosingStatement = NO_SQLNODE;
  2382. lpSqlNode->node.aggregate.Next = NO_SQLNODE;
  2383. lpSqlNode->node.aggregate.Count = 0.0;
  2384. return ERR_SUCCESS;
  2385. }
  2386. /***************************************************************************/
  2387. RETCODE INTFUNC ParseValuelist(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  2388. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  2389. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  2390. /* Retrives a list of expressions from the input stream and creates a */
  2391. /* NODE_TYPE_VALUES node */
  2392. /* */
  2393. /* valuelist ::= expression , valuelist | expression | NULL , valuelist | */
  2394. /* NULL */
  2395. {
  2396. RETCODE err;
  2397. LPUSTR old_lpszSqlStr;
  2398. SDWORD old_cbSqlStr;
  2399. LPSQLNODE lpSqlNode;
  2400. SQLNODEIDX idxValues;
  2401. SQLNODEIDX idxValue;
  2402. SQLNODEIDX idxValuesPrev;
  2403. /* Get list of nodes */
  2404. idxValuesPrev = NO_SQLNODE;
  2405. while (TRUE) {
  2406. /* NULL specified? */
  2407. old_lpszSqlStr = *lplpszSqlStr;
  2408. old_cbSqlStr = *pcbSqlStr;
  2409. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "NULL", lpszToken);
  2410. if (err != ERR_SUCCESS) {
  2411. /* No. Get expression */
  2412. *lplpszSqlStr = old_lpszSqlStr;
  2413. *pcbSqlStr = old_cbSqlStr;
  2414. err = ParseExpression(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  2415. &idxValue, lpszToken);
  2416. if (err != ERR_SUCCESS)
  2417. return err;
  2418. }
  2419. else {
  2420. /* Yes. Create a NULL node */
  2421. idxValue = AllocateNode(lplpSql, NODE_TYPE_NULL);
  2422. if (idxValue == NO_SQLNODE)
  2423. return ERR_MEMALLOCFAIL;
  2424. }
  2425. /* Create the VALUES node */
  2426. idxValues = AllocateNode(lplpSql, NODE_TYPE_VALUES);
  2427. if (idxValues == NO_SQLNODE)
  2428. return ERR_MEMALLOCFAIL;
  2429. lpSqlNode = ToNode(*lplpSql, idxValues);
  2430. lpSqlNode->node.values.Value = idxValue;
  2431. lpSqlNode->node.values.Alias = NO_STRING;
  2432. lpSqlNode->node.values.Next = NO_SQLNODE;
  2433. /* Put node on list */
  2434. if (idxValuesPrev != NO_SQLNODE) {
  2435. lpSqlNode = ToNode(*lplpSql, idxValuesPrev);
  2436. lpSqlNode->node.values.Next = idxValues;
  2437. }
  2438. else
  2439. *lpIdx = idxValues;
  2440. idxValuesPrev = idxValues;
  2441. /* Is there a comma? */
  2442. old_lpszSqlStr = *lplpszSqlStr;
  2443. old_cbSqlStr = *pcbSqlStr;
  2444. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ",", lpszToken);
  2445. if (err != ERR_SUCCESS) {
  2446. /* No. This is the last value */
  2447. *lplpszSqlStr = old_lpszSqlStr;
  2448. *pcbSqlStr = old_cbSqlStr;
  2449. break;
  2450. }
  2451. }
  2452. return ERR_SUCCESS;
  2453. }
  2454. /***************************************************************************/
  2455. RETCODE INTFUNC ParseScalar(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  2456. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  2457. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  2458. /* Retrives ascalar reference from the input stream and creates a */
  2459. /* NODE_TYPE_SCALE node. */
  2460. /* */
  2461. /* fn := functionname ( valuelist ) | functionname ( ) */
  2462. /* scalarshorthand := { FN fn } */
  2463. /* scalarescape := --*(VENDOR(MICROSOFT),PRODUCT(ODBC) FN fn)*-- */
  2464. /* scalar ::= scalarescape | scalarshorthand */
  2465. {
  2466. RETCODE err;
  2467. BOOL fShorthand;
  2468. STRINGIDX idxFunction;
  2469. SQLNODEIDX idxValues;
  2470. LPSQLNODE lpSqlNode;
  2471. LPUSTR old_lpszSqlStr;
  2472. SDWORD old_cbSqlStr;
  2473. /* Get starting symbol */
  2474. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, NULL, lpszToken);
  2475. if (err != ERR_SUCCESS)
  2476. return err;
  2477. /* Shorthand? */
  2478. if (s_lstrcmpi(lpszToken, "{")) {
  2479. /* No. Not a shorthand */
  2480. fShorthand = FALSE;
  2481. /* If not an escape clause, error */
  2482. if (s_lstrcmpi(lpszToken, "--")) {
  2483. s_lstrcpy(lpstmt->szError, "--");
  2484. return ERR_EXPECTEDOTHER;
  2485. }
  2486. /* Get the rest of the starting sequence */
  2487. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "(", lpszToken);
  2488. if (err != ERR_SUCCESS)
  2489. return err;
  2490. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "*", lpszToken);
  2491. if (err != ERR_SUCCESS)
  2492. return err;
  2493. err = GetIdent(lpstmt, lplpszSqlStr, pcbSqlStr, "vendor", lpszToken);
  2494. if (err != ERR_SUCCESS)
  2495. return err;
  2496. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "(", lpszToken);
  2497. if (err != ERR_SUCCESS)
  2498. return err;
  2499. err = GetIdent(lpstmt, lplpszSqlStr, pcbSqlStr, "Microsoft", lpszToken);
  2500. if (err != ERR_SUCCESS)
  2501. return err;
  2502. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ")", lpszToken);
  2503. if (err != ERR_SUCCESS)
  2504. return err;
  2505. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ",", lpszToken);
  2506. if (err != ERR_SUCCESS)
  2507. return err;
  2508. err = GetIdent(lpstmt, lplpszSqlStr, pcbSqlStr, "product", lpszToken);
  2509. if (err != ERR_SUCCESS)
  2510. return err;
  2511. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "(", lpszToken);
  2512. if (err != ERR_SUCCESS)
  2513. return err;
  2514. err = GetIdent(lpstmt, lplpszSqlStr, pcbSqlStr, "ODBC", lpszToken);
  2515. if (err != ERR_SUCCESS)
  2516. return err;
  2517. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ")", lpszToken);
  2518. if (err != ERR_SUCCESS)
  2519. return err;
  2520. }
  2521. else
  2522. fShorthand = TRUE;
  2523. /* Get FN keyword */
  2524. err = GetIdent(lpstmt, lplpszSqlStr, pcbSqlStr, "fn", lpszToken);
  2525. if (err != ERR_SUCCESS)
  2526. return err;
  2527. /* Get function name */
  2528. err = GetIdent(lpstmt, lplpszSqlStr, pcbSqlStr, NULL, lpszToken);
  2529. if (err != ERR_SUCCESS)
  2530. return err;
  2531. idxFunction = AllocateString(lplpSql, lpszToken);
  2532. if (idxFunction == NO_STRING)
  2533. return ERR_MEMALLOCFAIL;
  2534. /* Get arguments (if any) */
  2535. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "(", lpszToken);
  2536. if (err != ERR_SUCCESS)
  2537. return err;
  2538. old_lpszSqlStr = *lplpszSqlStr;
  2539. old_cbSqlStr = *pcbSqlStr;
  2540. err = ParseValuelist(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  2541. &idxValues, lpszToken);
  2542. if (err != ERR_SUCCESS) {
  2543. *lplpszSqlStr = old_lpszSqlStr;
  2544. *pcbSqlStr = old_cbSqlStr;
  2545. idxValues = NO_SQLNODE;
  2546. }
  2547. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ")", lpszToken);
  2548. if (err != ERR_SUCCESS)
  2549. return err;
  2550. /* Get closing bracket */
  2551. if (!fShorthand) {
  2552. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "*", lpszToken);
  2553. if (err != ERR_SUCCESS)
  2554. return err;
  2555. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ")", lpszToken);
  2556. if (err != ERR_SUCCESS)
  2557. return err;
  2558. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "--", lpszToken);
  2559. if (err != ERR_SUCCESS)
  2560. return err;
  2561. }
  2562. else {
  2563. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "}", lpszToken);
  2564. if (err != ERR_SUCCESS)
  2565. return err;
  2566. }
  2567. /* Create the SCALAR node */
  2568. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_SCALAR);
  2569. if (*lpIdx == NO_SQLNODE)
  2570. return ERR_MEMALLOCFAIL;
  2571. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  2572. lpSqlNode->node.scalar.Function = idxFunction;
  2573. lpSqlNode->node.scalar.Arguments = idxValues;
  2574. lpSqlNode->node.scalar.Id = 0;
  2575. lpSqlNode->node.scalar.Interval = 0;
  2576. lpSqlNode->node.scalar.Value = NO_STRING;
  2577. lpSqlNode->node.scalar.DistinctOffset = 0;
  2578. lpSqlNode->node.scalar.DistinctLength = 0;
  2579. lpSqlNode->node.scalar.EnclosingStatement = NO_SQLNODE;
  2580. return ERR_SUCCESS;
  2581. }
  2582. /***************************************************************************/
  2583. RETCODE INTFUNC ParseTerm(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  2584. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  2585. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  2586. /* Retrives a term from the input stream and creates a NODE_TYPE_COLUMN, */
  2587. /* NODE_TYPE_ALGEBRAIC, NODE_TYPE_AGGREGATE, NODE_TYPE_STRING, */
  2588. /* NODE_TYPE_NUMERIC, NODE_TYPE_PARAMETER, NODE_TYPE_USER, NODE_TYPE_DATE, */
  2589. /* NODE_TYPE_TIME, or NODE_TYPE_TIMESTAMP node. */
  2590. /* */
  2591. /* term ::= ( expression ) | colref | simpleterm | aggterm | scalar */
  2592. {
  2593. RETCODE err;
  2594. LPUSTR old_lpszSqlStr;
  2595. SDWORD old_cbSqlStr;
  2596. /* Is it a simpleterm? */
  2597. old_lpszSqlStr = *lplpszSqlStr;
  2598. old_cbSqlStr = *pcbSqlStr;
  2599. err = ParseSimpleterm(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, lpIdx,
  2600. lpszToken);
  2601. if (err != ERR_SUCCESS) {
  2602. /* No. Is it an aggregate function? */
  2603. *lplpszSqlStr = old_lpszSqlStr;
  2604. *pcbSqlStr = old_cbSqlStr;
  2605. err = ParseAggterm(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, lpIdx,
  2606. lpszToken);
  2607. //Return straight away if error was due to
  2608. //non-support of certain aggregate functions
  2609. if ( (err == ERR_LEN_NOTSUPP) || (err == ERR_COUNT_NOTSUPP) )
  2610. return err;
  2611. if (err != ERR_SUCCESS) {
  2612. /* No. Is it ( expression )? */
  2613. *lplpszSqlStr = old_lpszSqlStr;
  2614. *pcbSqlStr = old_cbSqlStr;
  2615. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "(", lpszToken);
  2616. if (err != ERR_SUCCESS) {
  2617. /* No. Is it a column reference? */
  2618. *lplpszSqlStr = old_lpszSqlStr;
  2619. *pcbSqlStr = old_cbSqlStr;
  2620. err = ParseColref(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  2621. lpIdx, lpszToken);
  2622. if (err != ERR_SUCCESS) {
  2623. /* No. Is it a scalar? */
  2624. *lplpszSqlStr = old_lpszSqlStr;
  2625. *pcbSqlStr = old_cbSqlStr;
  2626. err = ParseScalar(lpstmt, lplpszSqlStr, pcbSqlStr,
  2627. lplpSql, lpIdx, lpszToken);
  2628. if (err != ERR_SUCCESS) {
  2629. s_lstrcpy(lpstmt->szError, "<identifier>");
  2630. return ERR_EXPECTEDOTHER;
  2631. }
  2632. }
  2633. }
  2634. else {
  2635. /* Yes. Get expression */
  2636. err = ParseExpression(lpstmt, lplpszSqlStr, pcbSqlStr,
  2637. lplpSql, lpIdx, lpszToken);
  2638. if (err != ERR_SUCCESS)
  2639. return err;
  2640. /* Get terminating ")" */
  2641. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ")",
  2642. lpszToken);
  2643. //Do a double check for the unsupported BETWEEN function
  2644. if (lpszToken && !s_lstrcmpi(lpszToken, "BETWEEN"))
  2645. {
  2646. return ERR_BETWEEN_NOTSUPP;
  2647. }
  2648. if (err != ERR_SUCCESS)
  2649. return err;
  2650. }
  2651. }
  2652. }
  2653. return ERR_SUCCESS;
  2654. }
  2655. /***************************************************************************/
  2656. RETCODE INTFUNC ParseNeg(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  2657. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  2658. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  2659. /* Retrives an algebraic expression from the input stream and creates a */
  2660. /* NODE_TYPE_ALGEBRAIC node */
  2661. /* */
  2662. /* neg ::= term | + term | - term */
  2663. {
  2664. RETCODE err;
  2665. LPUSTR old_lpszSqlStr;
  2666. SDWORD old_cbSqlStr;
  2667. LPSQLNODE lpSqlNode;
  2668. SQLNODEIDX idxChild;
  2669. UWORD op;
  2670. /* Get + or - */
  2671. old_lpszSqlStr = *lplpszSqlStr;
  2672. old_cbSqlStr = *pcbSqlStr;
  2673. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, NULL, lpszToken);
  2674. if (err != ERR_SUCCESS) {
  2675. *lplpszSqlStr = old_lpszSqlStr;
  2676. *pcbSqlStr = old_cbSqlStr;
  2677. op = OP_NONE;
  2678. }
  2679. else {
  2680. if (!s_lstrcmpi(lpszToken, "-"))
  2681. op = OP_NEG;
  2682. else if (!s_lstrcmpi(lpszToken, "+"))
  2683. op = OP_NONE;
  2684. else {
  2685. *lplpszSqlStr = old_lpszSqlStr;
  2686. *pcbSqlStr = old_cbSqlStr;
  2687. op = OP_NONE;
  2688. }
  2689. }
  2690. /* Get term */
  2691. err = ParseTerm(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, &idxChild,
  2692. lpszToken);
  2693. if (err != ERR_SUCCESS)
  2694. return err;
  2695. /* Return node */
  2696. if (op == OP_NONE) {
  2697. *lpIdx = idxChild;
  2698. }
  2699. else {
  2700. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_ALGEBRAIC);
  2701. if (*lpIdx == NO_SQLNODE)
  2702. return ERR_MEMALLOCFAIL;
  2703. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  2704. lpSqlNode->node.algebraic.Operator = OP_NEG;
  2705. lpSqlNode->node.algebraic.Left = idxChild;
  2706. lpSqlNode->node.algebraic.Right = NO_SQLNODE;
  2707. lpSqlNode->node.algebraic.Value = NO_STRING;
  2708. lpSqlNode->node.algebraic.WorkBuffer1 = NO_STRING;
  2709. lpSqlNode->node.algebraic.WorkBuffer2 = NO_STRING;
  2710. lpSqlNode->node.algebraic.WorkBuffer3 = NO_STRING;
  2711. lpSqlNode->node.algebraic.DistinctOffset = 0;
  2712. lpSqlNode->node.algebraic.DistinctLength = 0;
  2713. lpSqlNode->node.algebraic.EnclosingStatement = NO_SQLNODE;
  2714. }
  2715. return ERR_SUCCESS;
  2716. }
  2717. /***************************************************************************/
  2718. RETCODE INTFUNC ParseTimes(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  2719. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  2720. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  2721. /* Retrives an algebraic expression from the input stream and creates a */
  2722. /* NODE_TYPE_ALGEBRAIC node */
  2723. /* */
  2724. /* times ::= times * neg | times / neg | neg */
  2725. {
  2726. RETCODE err;
  2727. LPUSTR old_lpszSqlStr;
  2728. SDWORD old_cbSqlStr;
  2729. LPSQLNODE lpSqlNode;
  2730. SQLNODEIDX idxLeft;
  2731. SQLNODEIDX idxRight;
  2732. SQLNODEIDX idxNew;
  2733. UWORD op;
  2734. /* Get start of expression */
  2735. err = ParseNeg(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, &idxLeft,
  2736. lpszToken);
  2737. if (err != ERR_SUCCESS)
  2738. return err;
  2739. /* Get the rest of the expression */
  2740. while (TRUE) {
  2741. /* Get * or / */
  2742. old_lpszSqlStr = *lplpszSqlStr;
  2743. old_cbSqlStr = *pcbSqlStr;
  2744. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, NULL, lpszToken);
  2745. if (err != ERR_SUCCESS) {
  2746. *lplpszSqlStr = old_lpszSqlStr;
  2747. *pcbSqlStr = old_cbSqlStr;
  2748. *lpIdx = idxLeft;
  2749. break;
  2750. }
  2751. else {
  2752. if ( (!s_lstrcmpi(lpszToken, "*")) &&
  2753. ( (*pcbSqlStr == 0) || (*(*lplpszSqlStr) != ')' ) ) )
  2754. op = OP_TIMES;
  2755. else if (!s_lstrcmpi(lpszToken, "/"))
  2756. op = OP_DIVIDEDBY;
  2757. else {
  2758. *lplpszSqlStr = old_lpszSqlStr;
  2759. *pcbSqlStr = old_cbSqlStr;
  2760. *lpIdx = idxLeft;
  2761. break;
  2762. }
  2763. }
  2764. /* Get right side */
  2765. err = ParseNeg(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, &idxRight,
  2766. lpszToken);
  2767. if (err != ERR_SUCCESS)
  2768. return err;
  2769. /* Make two halves into a node */
  2770. idxNew = AllocateNode(lplpSql, NODE_TYPE_ALGEBRAIC);
  2771. if (idxNew == NO_SQLNODE)
  2772. return ERR_MEMALLOCFAIL;
  2773. lpSqlNode = ToNode(*lplpSql, idxNew);
  2774. lpSqlNode->node.algebraic.Operator = op;
  2775. lpSqlNode->node.algebraic.Left = idxLeft;
  2776. lpSqlNode->node.algebraic.Right = idxRight;
  2777. lpSqlNode->node.algebraic.Value = NO_STRING;
  2778. lpSqlNode->node.algebraic.WorkBuffer1 = NO_STRING;
  2779. lpSqlNode->node.algebraic.WorkBuffer2 = NO_STRING;
  2780. lpSqlNode->node.algebraic.WorkBuffer3 = NO_STRING;
  2781. lpSqlNode->node.algebraic.DistinctOffset = 0;
  2782. lpSqlNode->node.algebraic.DistinctLength = 0;
  2783. lpSqlNode->node.algebraic.EnclosingStatement = NO_SQLNODE;
  2784. /* Get ready for next iteration */
  2785. idxLeft = idxNew;
  2786. }
  2787. return ERR_SUCCESS;
  2788. }
  2789. /***************************************************************************/
  2790. RETCODE INTFUNC ParseExpression(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  2791. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  2792. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  2793. /* Retrives an algebraic expression from the input stream and creates a */
  2794. /* NODE_TYPE_ALGEBRAIC node */
  2795. /* */
  2796. /* expression ::= expression + times | expression - times | times */
  2797. {
  2798. RETCODE err;
  2799. LPUSTR old_lpszSqlStr;
  2800. SDWORD old_cbSqlStr;
  2801. LPSQLNODE lpSqlNode;
  2802. SQLNODEIDX idxLeft;
  2803. SQLNODEIDX idxRight;
  2804. SQLNODEIDX idxNew;
  2805. UWORD op;
  2806. /* Get start of expression */
  2807. err = ParseTimes(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, &idxLeft,
  2808. lpszToken);
  2809. if (err != ERR_SUCCESS)
  2810. return err;
  2811. /* Get the rest of the expression */
  2812. while (TRUE) {
  2813. /* Get + or - */
  2814. old_lpszSqlStr = *lplpszSqlStr;
  2815. old_cbSqlStr = *pcbSqlStr;
  2816. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, NULL, lpszToken);
  2817. if (err != ERR_SUCCESS) {
  2818. *lplpszSqlStr = old_lpszSqlStr;
  2819. *pcbSqlStr = old_cbSqlStr;
  2820. *lpIdx = idxLeft;
  2821. break;
  2822. }
  2823. else {
  2824. if (!s_lstrcmpi(lpszToken, "-"))
  2825. op = OP_MINUS;
  2826. else if (!s_lstrcmpi(lpszToken, "+"))
  2827. op = OP_PLUS;
  2828. else {
  2829. *lplpszSqlStr = old_lpszSqlStr;
  2830. *pcbSqlStr = old_cbSqlStr;
  2831. *lpIdx = idxLeft;
  2832. break;
  2833. }
  2834. }
  2835. /* Get right side */
  2836. err = ParseTimes(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, &idxRight,
  2837. lpszToken);
  2838. if (err != ERR_SUCCESS)
  2839. return err;
  2840. /* Make two halves into a node */
  2841. idxNew = AllocateNode(lplpSql, NODE_TYPE_ALGEBRAIC);
  2842. if (idxNew == NO_SQLNODE)
  2843. return ERR_MEMALLOCFAIL;
  2844. lpSqlNode = ToNode(*lplpSql, idxNew);
  2845. lpSqlNode->node.algebraic.Operator = op;
  2846. lpSqlNode->node.algebraic.Left = idxLeft;
  2847. lpSqlNode->node.algebraic.Right = idxRight;
  2848. lpSqlNode->node.algebraic.Value = NO_STRING;
  2849. lpSqlNode->node.algebraic.WorkBuffer1 = NO_STRING;
  2850. lpSqlNode->node.algebraic.WorkBuffer2 = NO_STRING;
  2851. lpSqlNode->node.algebraic.WorkBuffer3 = NO_STRING;
  2852. lpSqlNode->node.algebraic.DistinctOffset = 0;
  2853. lpSqlNode->node.algebraic.DistinctLength = 0;
  2854. lpSqlNode->node.algebraic.EnclosingStatement = NO_SQLNODE;
  2855. /* Get ready for next iteration */
  2856. idxLeft = idxNew;
  2857. }
  2858. return ERR_SUCCESS;
  2859. }
  2860. /***************************************************************************/
  2861. RETCODE INTFUNC ParsePattern(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  2862. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  2863. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  2864. /* Retrives a pattern from the input stream and creates a */
  2865. /* NODE_TYPE_STRING, NODE_TYPE_PARAMETER, or NODE_TYPE_USER node */
  2866. /* */
  2867. /* pattern ::= string | ? | USER */
  2868. {
  2869. RETCODE err;
  2870. LPUSTR old_lpszSqlStr;
  2871. SDWORD old_cbSqlStr;
  2872. STRINGIDX idxString;
  2873. LPSQLNODE lpSqlNode;
  2874. SQLNODEIDX idxParameter;
  2875. UWORD parameterId;
  2876. /* Is it a string? */
  2877. old_lpszSqlStr = *lplpszSqlStr;
  2878. old_cbSqlStr = *pcbSqlStr;
  2879. err = GetString(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  2880. &idxString, lpszToken);
  2881. if (err != ERR_SUCCESS) {
  2882. /* No. Is it a parameter */
  2883. *lplpszSqlStr = old_lpszSqlStr;
  2884. *pcbSqlStr = old_cbSqlStr;
  2885. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "?", lpszToken);
  2886. if (err != ERR_SUCCESS) {
  2887. /* No. Is it USER? */
  2888. *lplpszSqlStr = old_lpszSqlStr;
  2889. *pcbSqlStr = old_cbSqlStr;
  2890. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "USER",
  2891. lpszToken);
  2892. if (err != ERR_SUCCESS) {
  2893. /* No. Error */
  2894. return err;
  2895. }
  2896. else {
  2897. /* Yes. Make USER node */
  2898. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_USER);
  2899. if (*lpIdx == NO_SQLNODE)
  2900. return ERR_MEMALLOCFAIL;
  2901. }
  2902. }
  2903. else {
  2904. /* Yes. Make PARAMETER node */
  2905. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_PARAMETER);
  2906. if (*lpIdx == NO_SQLNODE)
  2907. return ERR_MEMALLOCFAIL;
  2908. /* First parameter? */
  2909. idxParameter = (*lplpSql)->node.root.parameters;
  2910. if (idxParameter == NO_SQLNODE) {
  2911. /* Yes. Initialize list of parameters */
  2912. (*lplpSql)->node.root.parameters = *lpIdx;
  2913. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  2914. lpSqlNode->node.parameter.Id = 1;
  2915. }
  2916. else {
  2917. /* No. Get last element of parameter list */
  2918. while (TRUE) {
  2919. lpSqlNode = ToNode(*lplpSql, idxParameter);
  2920. idxParameter = lpSqlNode->node.parameter.Next;
  2921. if (idxParameter == NO_SQLNODE)
  2922. break;
  2923. }
  2924. /* Put node on list */
  2925. lpSqlNode->node.parameter.Next = *lpIdx;
  2926. /* Determine id of parameter */
  2927. parameterId = lpSqlNode->node.parameter.Id + 1;
  2928. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  2929. lpSqlNode->node.parameter.Id = parameterId;
  2930. }
  2931. lpSqlNode->node.parameter.Next = NO_SQLNODE;
  2932. lpSqlNode->node.parameter.Value = NO_STRING;
  2933. lpSqlNode->node.parameter.AtExec = FALSE;
  2934. }
  2935. }
  2936. else {
  2937. /* Yes. Make STRING node */
  2938. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_STRING);
  2939. if (*lpIdx == NO_SQLNODE)
  2940. return ERR_MEMALLOCFAIL;
  2941. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  2942. lpSqlNode->node.string.Value = idxString;
  2943. }
  2944. return ERR_SUCCESS;
  2945. }
  2946. /***************************************************************************/
  2947. RETCODE INTFUNC ParseComparison(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  2948. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  2949. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  2950. /* Retrives a comparison expression from the input stream and creates a */
  2951. /* NODE_TYPE_COMPARISON node */
  2952. /* */
  2953. /* comparison ::= ( boolean ) | colref IS NULL | colref IS NOT NULL | */
  2954. /* expression LIKE pattern | expression NOT LIKE pattern | */
  2955. /* expression IN ( valuelist ) | expression NOT IN ( valuelist ) | */
  2956. /* expression op expression | EXISTS ( SELECT select ) | */
  2957. /* expression op selectop ( SELECT select ) | */
  2958. /* expression IN ( SELECT select ) | */
  2959. /* expression NOT IN ( SELECT select ) */
  2960. /* op ::= > | >= | < | <= | = | <> */
  2961. /* selectop ::= | ALL | ANY */
  2962. {
  2963. RETCODE err;
  2964. LPUSTR old_lpszSqlStr;
  2965. SDWORD old_cbSqlStr;
  2966. LPSQLNODE lpSqlNode;
  2967. SQLNODEIDX idxLeft;
  2968. SQLNODEIDX idxRight;
  2969. UWORD op;
  2970. UWORD selectModifier;
  2971. /* Is there a "("? */
  2972. old_lpszSqlStr = *lplpszSqlStr;
  2973. old_cbSqlStr = *pcbSqlStr;
  2974. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "(", lpszToken);
  2975. if (err == ERR_SUCCESS) {
  2976. /* Yes. Return boolean */
  2977. err = ParseBoolean(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, lpIdx,
  2978. lpszToken);
  2979. /* Make sure closing ")" is there */
  2980. if (err == ERR_SUCCESS)
  2981. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ")", lpszToken);
  2982. }
  2983. if (err != ERR_SUCCESS) {
  2984. /* Look for EXISTS predicate */
  2985. *lplpszSqlStr = old_lpszSqlStr;
  2986. *pcbSqlStr = old_cbSqlStr;
  2987. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "EXISTS",
  2988. lpszToken);
  2989. if (err == ERR_SUCCESS) {
  2990. /* Found it. Get opening "(" */
  2991. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "(", lpszToken);
  2992. if (err != ERR_SUCCESS)
  2993. return err;
  2994. /* Found it. Get opening "SELECT" */
  2995. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "SELECT",
  2996. lpszToken);
  2997. if (err != ERR_SUCCESS)
  2998. return err;
  2999. /* Get the sub-select */
  3000. err = ParseSelect(lpstmt, lplpszSqlStr, pcbSqlStr,
  3001. lplpSql, &idxLeft, lpszToken);
  3002. if (err != ERR_SUCCESS)
  3003. return err;
  3004. /* Check for trailing ")" */
  3005. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ")", lpszToken);
  3006. if (err != ERR_SUCCESS)
  3007. return err;
  3008. /* Return EXISTS condition */
  3009. op = OP_EXISTS;
  3010. idxRight = NO_SQLNODE;
  3011. selectModifier = SELECT_EXISTS;
  3012. }
  3013. else {
  3014. /* Get left child */
  3015. selectModifier = SELECT_NOTSELECT;
  3016. *lplpszSqlStr = old_lpszSqlStr;
  3017. *pcbSqlStr = old_cbSqlStr;
  3018. err = ParseExpression(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  3019. &idxLeft, lpszToken);
  3020. if (err != ERR_SUCCESS)
  3021. return err;
  3022. /* Is left child a column reference? */
  3023. lpSqlNode = ToNode(*lplpSql, idxLeft);
  3024. if (lpSqlNode->sqlNodeType == NODE_TYPE_COLUMN) {
  3025. /* Is this an "IS NULL" or "IS NOT NULL"? */
  3026. old_lpszSqlStr = *lplpszSqlStr;
  3027. old_cbSqlStr = *pcbSqlStr;
  3028. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "IS",
  3029. lpszToken);
  3030. if (err == ERR_SUCCESS) {
  3031. /* Yes. See which of the two it is */
  3032. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, NULL,
  3033. lpszToken);
  3034. if (err != ERR_SUCCESS)
  3035. return err;
  3036. if (!s_lstrcmpi(lpszToken, "NOT")) {
  3037. op = OP_NE;
  3038. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr,
  3039. NULL, lpszToken);
  3040. if (err != ERR_SUCCESS)
  3041. return err;
  3042. }
  3043. else
  3044. op = OP_EQ;
  3045. /* Error if missing keyword */
  3046. if (s_lstrcmpi(lpszToken, "NULL")) {
  3047. s_lstrcpy(lpstmt->szError, "NULL");
  3048. return ERR_EXPECTEDOTHER;
  3049. }
  3050. /* Create the value to compare it to */
  3051. idxRight = AllocateNode(lplpSql, NODE_TYPE_NULL);
  3052. if (idxRight == NO_SQLNODE)
  3053. return ERR_MEMALLOCFAIL;
  3054. }
  3055. else {
  3056. /* No. Set flag */
  3057. *lplpszSqlStr = old_lpszSqlStr;
  3058. *pcbSqlStr = old_cbSqlStr;
  3059. op = OP_NONE;
  3060. }
  3061. }
  3062. else
  3063. op = OP_NONE;
  3064. /* Have we gotten the operator yet? */
  3065. if (op == OP_NONE) {
  3066. /* No. Get it now. */
  3067. old_lpszSqlStr = *lplpszSqlStr;
  3068. old_cbSqlStr = *pcbSqlStr;
  3069. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, NULL,
  3070. lpszToken);
  3071. /* Is the operator >, >=, <, <=, =, or <> ? */
  3072. if (err == ERR_SUCCESS) {
  3073. /* Yes. Figure out which one */
  3074. if (!s_lstrcmpi(lpszToken, ">"))
  3075. op = OP_GT;
  3076. else if (!s_lstrcmpi(lpszToken, ">="))
  3077. op = OP_GE;
  3078. else if (!s_lstrcmpi(lpszToken, "<"))
  3079. op = OP_LT;
  3080. else if (!s_lstrcmpi(lpszToken, "<="))
  3081. op = OP_LE;
  3082. else if (!s_lstrcmpi(lpszToken, "="))
  3083. op = OP_EQ;
  3084. else if (!s_lstrcmpi(lpszToken, "<>"))
  3085. op = OP_NE;
  3086. else {
  3087. s_lstrcpy(lpstmt->szError, "=, <>, <, <=, >, or >=");
  3088. return ERR_EXPECTEDOTHER;
  3089. }
  3090. /* ALL or ANY specified? */
  3091. old_lpszSqlStr = *lplpszSqlStr;
  3092. old_cbSqlStr = *pcbSqlStr;
  3093. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "ALL",
  3094. lpszToken);
  3095. if (err != ERR_SUCCESS) {
  3096. *lplpszSqlStr = old_lpszSqlStr;
  3097. *pcbSqlStr = old_cbSqlStr;
  3098. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr,
  3099. "ANY", lpszToken);
  3100. if (err != ERR_SUCCESS) {
  3101. *lplpszSqlStr = old_lpszSqlStr;
  3102. *pcbSqlStr = old_cbSqlStr;
  3103. }
  3104. else {
  3105. selectModifier = SELECT_ANY;
  3106. }
  3107. }
  3108. else {
  3109. selectModifier = SELECT_ALL;
  3110. }
  3111. /* Nested sub-select? */
  3112. old_lpszSqlStr = *lplpszSqlStr;
  3113. old_cbSqlStr = *pcbSqlStr;
  3114. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "(",
  3115. lpszToken);
  3116. if (err == ERR_SUCCESS) {
  3117. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr,
  3118. "SELECT", lpszToken);
  3119. if (err == ERR_SUCCESS) {
  3120. /* Yes. Get the sub-select */
  3121. err = ParseSelect(lpstmt, lplpszSqlStr, pcbSqlStr,
  3122. lplpSql, &idxRight, lpszToken);
  3123. if (err != ERR_SUCCESS)
  3124. return err;
  3125. /* Check for trailing ")" */
  3126. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr,
  3127. ")", lpszToken);
  3128. if (err != ERR_SUCCESS)
  3129. return err;
  3130. /* Set selectModifier if not already set */
  3131. if (selectModifier == SELECT_NOTSELECT)
  3132. selectModifier = SELECT_ONE;
  3133. }
  3134. else {
  3135. *lplpszSqlStr = old_lpszSqlStr;
  3136. *pcbSqlStr = old_cbSqlStr;
  3137. }
  3138. }
  3139. else {
  3140. *lplpszSqlStr = old_lpszSqlStr;
  3141. *pcbSqlStr = old_cbSqlStr;
  3142. }
  3143. /* Get right child if not a nested sub-select */
  3144. if (selectModifier == SELECT_NOTSELECT) {
  3145. if (err != ERR_SUCCESS) {
  3146. err = ParseExpression(lpstmt, lplpszSqlStr,
  3147. pcbSqlStr, lplpSql, &idxRight, lpszToken);
  3148. if (err != ERR_SUCCESS)
  3149. return err;
  3150. }
  3151. }
  3152. }
  3153. else {
  3154. /* No. Maybe it is IN, NOT IN, LIKE, or NOT LIKE? Get */
  3155. /* the keyword */
  3156. *lplpszSqlStr = old_lpszSqlStr;
  3157. *pcbSqlStr = old_cbSqlStr;
  3158. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, NULL,
  3159. lpszToken);
  3160. if (err != ERR_SUCCESS)
  3161. return err;
  3162. /* Is the operator "NOT LIKE" or "NOT IN"? */
  3163. if (!s_lstrcmpi(lpszToken, "NOT")) {
  3164. /* Yes. Figure out which one */
  3165. old_lpszSqlStr = *lplpszSqlStr;
  3166. old_cbSqlStr = *pcbSqlStr;
  3167. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr,
  3168. "LIKE", lpszToken);
  3169. if (err != ERR_SUCCESS) {
  3170. *lplpszSqlStr = old_lpszSqlStr;
  3171. *pcbSqlStr = old_cbSqlStr;
  3172. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr,
  3173. "IN", lpszToken);
  3174. if (err != ERR_SUCCESS)
  3175. return err;
  3176. op = OP_NOTIN;
  3177. }
  3178. else
  3179. op = OP_NOTLIKE;
  3180. }
  3181. /* Is the operator "LIKE"? */
  3182. else if (!s_lstrcmpi(lpszToken, "LIKE")) {
  3183. /* Yes. Operator is LIKE */
  3184. op = OP_LIKE;
  3185. }
  3186. /* Is the operator "IN"? */
  3187. else if (!s_lstrcmpi(lpszToken, "IN")) {
  3188. /* Yes. Operator is IN */
  3189. op = OP_IN;
  3190. }
  3191. else {
  3192. s_lstrcpy(lpstmt->szError, "IN, NOT IN, LIKE, or NOT LIKE");
  3193. return ERR_EXPECTEDOTHER;
  3194. }
  3195. /* Get right argument */
  3196. switch (op) {
  3197. case OP_IN:
  3198. case OP_NOTIN:
  3199. /* Get opening paren */
  3200. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "(",
  3201. lpszToken);
  3202. if (err != ERR_SUCCESS)
  3203. return err;
  3204. /* Nested sub-select? */
  3205. old_lpszSqlStr = *lplpszSqlStr;
  3206. old_cbSqlStr = *pcbSqlStr;
  3207. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr,
  3208. "SELECT", lpszToken);
  3209. if (err == ERR_SUCCESS) {
  3210. /* Yes. Get the sub-select */
  3211. err = ParseSelect(lpstmt, lplpszSqlStr, pcbSqlStr,
  3212. lplpSql, &idxRight, lpszToken);
  3213. if (err != ERR_SUCCESS)
  3214. return err;
  3215. }
  3216. else {
  3217. /* No. Get valuelist */
  3218. *lplpszSqlStr = old_lpszSqlStr;
  3219. *pcbSqlStr = old_cbSqlStr;
  3220. err = ParseValuelist(lpstmt, lplpszSqlStr,
  3221. pcbSqlStr, lplpSql, &idxRight, lpszToken);
  3222. if (err != ERR_SUCCESS)
  3223. return err;
  3224. }
  3225. /* Get closing paren */
  3226. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ")",
  3227. lpszToken);
  3228. if (err != ERR_SUCCESS)
  3229. return err;
  3230. break;
  3231. case OP_LIKE:
  3232. case OP_NOTLIKE:
  3233. /* Get pattern */
  3234. err = ParsePattern(lpstmt, lplpszSqlStr, pcbSqlStr,
  3235. lplpSql, &idxRight, lpszToken);
  3236. if (err != ERR_SUCCESS)
  3237. return err;
  3238. break;
  3239. default:
  3240. return ERR_INTERNAL;
  3241. }
  3242. }
  3243. }
  3244. }
  3245. /* Create the COMPARISON node */
  3246. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_COMPARISON);
  3247. if (*lpIdx == NO_SQLNODE)
  3248. return ERR_MEMALLOCFAIL;
  3249. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  3250. lpSqlNode->node.comparison.Operator = op;
  3251. lpSqlNode->node.comparison.SelectModifier = selectModifier;
  3252. lpSqlNode->node.comparison.Left = idxLeft;
  3253. lpSqlNode->node.comparison.Right = idxRight;
  3254. lpSqlNode->node.comparison.fSelectivity = 0;
  3255. lpSqlNode->node.comparison.NextRestrict = NO_SQLNODE;
  3256. }
  3257. return ERR_SUCCESS;
  3258. }
  3259. /***************************************************************************/
  3260. RETCODE INTFUNC ParseNot(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  3261. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  3262. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  3263. /* Retrives a NOT expression from the input stream and creates a */
  3264. /* NODE_TYPE_BOOLEAN node */
  3265. /* */
  3266. /* not ::= comparison | NOT comparison */
  3267. {
  3268. RETCODE err;
  3269. LPUSTR old_lpszSqlStr;
  3270. SDWORD old_cbSqlStr;
  3271. LPSQLNODE lpSqlNode;
  3272. SQLNODEIDX idxChild;
  3273. /* Is there a "NOT"? */
  3274. old_lpszSqlStr = *lplpszSqlStr;
  3275. old_cbSqlStr = *pcbSqlStr;
  3276. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "NOT", lpszToken);
  3277. if (err != ERR_SUCCESS) {
  3278. /* No. Return left child */
  3279. *lplpszSqlStr = old_lpszSqlStr;
  3280. *pcbSqlStr = old_cbSqlStr;
  3281. err = ParseComparison(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, lpIdx,
  3282. lpszToken);
  3283. if (err != ERR_SUCCESS)
  3284. return err;
  3285. }
  3286. else {
  3287. /* Yes. Get right child */
  3288. err = ParseComparison(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  3289. &idxChild, lpszToken);
  3290. if (err != ERR_SUCCESS)
  3291. return err;
  3292. /* Create the BOOLEAN node */
  3293. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_BOOLEAN);
  3294. if (*lpIdx == NO_SQLNODE)
  3295. return ERR_MEMALLOCFAIL;
  3296. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  3297. lpSqlNode->node.boolean.Operator = OP_NOT;
  3298. lpSqlNode->node.boolean.Left = idxChild;
  3299. lpSqlNode->node.boolean.Right = NO_SQLNODE;
  3300. }
  3301. return ERR_SUCCESS;
  3302. }
  3303. /***************************************************************************/
  3304. RETCODE INTFUNC ParseAnd(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  3305. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  3306. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  3307. /* Retrives an AND expression from the input stream and creates a */
  3308. /* NODE_TYPE_BOOLEAN node */
  3309. /* */
  3310. /* and ::= not | not AND and */
  3311. {
  3312. RETCODE err;
  3313. LPUSTR old_lpszSqlStr;
  3314. SDWORD old_cbSqlStr;
  3315. LPSQLNODE lpSqlNode;
  3316. SQLNODEIDX idxLeft;
  3317. SQLNODEIDX idxRight;
  3318. /* Get left child */
  3319. err = ParseNot(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, &idxLeft,
  3320. lpszToken);
  3321. if (err != ERR_SUCCESS)
  3322. return err;
  3323. /* Is there an "AND"? */
  3324. old_lpszSqlStr = *lplpszSqlStr;
  3325. old_cbSqlStr = *pcbSqlStr;
  3326. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "AND", lpszToken);
  3327. if (err != ERR_SUCCESS) {
  3328. /* No. Return left child */
  3329. *lplpszSqlStr = old_lpszSqlStr;
  3330. *pcbSqlStr = old_cbSqlStr;
  3331. *lpIdx = idxLeft;
  3332. }
  3333. else {
  3334. /* Yes. Get right child */
  3335. err = ParseAnd(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, &idxRight,
  3336. lpszToken);
  3337. if (err != ERR_SUCCESS)
  3338. return err;
  3339. /* Create the BOOLEAN node */
  3340. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_BOOLEAN);
  3341. if (*lpIdx == NO_SQLNODE)
  3342. return ERR_MEMALLOCFAIL;
  3343. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  3344. lpSqlNode->node.boolean.Operator = OP_AND;
  3345. lpSqlNode->node.boolean.Left = idxLeft;
  3346. lpSqlNode->node.boolean.Right = idxRight;
  3347. }
  3348. return ERR_SUCCESS;
  3349. }
  3350. /***************************************************************************/
  3351. RETCODE INTFUNC ParseBoolean(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  3352. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  3353. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  3354. /* Retrives an OR expression from the input stream and creates a */
  3355. /* NODE_TYPE_BOOLEAN node */
  3356. /* */
  3357. /* boolean ::= and | and OR boolean */
  3358. {
  3359. RETCODE err;
  3360. LPUSTR old_lpszSqlStr;
  3361. SDWORD old_cbSqlStr;
  3362. LPSQLNODE lpSqlNode;
  3363. SQLNODEIDX idxLeft;
  3364. SQLNODEIDX idxRight;
  3365. /* Get left child */
  3366. err = ParseAnd(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, &idxLeft,
  3367. lpszToken);
  3368. if (err != ERR_SUCCESS)
  3369. return err;
  3370. /* Is there an "OR"? */
  3371. old_lpszSqlStr = *lplpszSqlStr;
  3372. old_cbSqlStr = *pcbSqlStr;
  3373. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "OR", lpszToken);
  3374. if (err != ERR_SUCCESS) {
  3375. /* No. Return left child */
  3376. *lplpszSqlStr = old_lpszSqlStr;
  3377. *pcbSqlStr = old_cbSqlStr;
  3378. *lpIdx = idxLeft;
  3379. }
  3380. else {
  3381. /* Yes. Get right child */
  3382. err = ParseBoolean(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  3383. &idxRight, lpszToken);
  3384. if (err != ERR_SUCCESS)
  3385. return err;
  3386. /* Create the BOOLEAN node */
  3387. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_BOOLEAN);
  3388. if (*lpIdx == NO_SQLNODE)
  3389. return ERR_MEMALLOCFAIL;
  3390. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  3391. lpSqlNode->node.boolean.Operator = OP_OR;
  3392. lpSqlNode->node.boolean.Left = idxLeft;
  3393. lpSqlNode->node.boolean.Right = idxRight;
  3394. }
  3395. return ERR_SUCCESS;
  3396. }
  3397. /***************************************************************************/
  3398. RETCODE INTFUNC ParseWhere(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  3399. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  3400. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  3401. /* Retrives an WHERE expression from the input stream and creates a */
  3402. /* NODE_TYPE_BOOLEAN node */
  3403. /* */
  3404. /* where ::= | WHERE boolean */
  3405. {
  3406. RETCODE err;
  3407. LPUSTR old_lpszSqlStr;
  3408. SDWORD old_cbSqlStr;
  3409. /* Is there a "WHERE"? */
  3410. old_lpszSqlStr = *lplpszSqlStr;
  3411. old_cbSqlStr = *pcbSqlStr;
  3412. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "WHERE", lpszToken);
  3413. if (err != ERR_SUCCESS) {
  3414. /* No. Return null */
  3415. *lplpszSqlStr = old_lpszSqlStr;
  3416. *pcbSqlStr = old_cbSqlStr;
  3417. *lpIdx = NO_SQLNODE;
  3418. }
  3419. else {
  3420. /* Yes. Return boolean */
  3421. err = ParseBoolean(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  3422. lpIdx, lpszToken);
  3423. if (err != ERR_SUCCESS)
  3424. return err;
  3425. }
  3426. return ERR_SUCCESS;
  3427. }
  3428. /***************************************************************************/
  3429. RETCODE INTFUNC ParseHaving(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  3430. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  3431. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  3432. /* Retrives a HAVING expression from the input stream and creates a */
  3433. /* NODE_TYPE_BOOLEAN node */
  3434. /* */
  3435. /* having ::= | HAVING boolean */
  3436. {
  3437. RETCODE err;
  3438. LPUSTR old_lpszSqlStr;
  3439. SDWORD old_cbSqlStr;
  3440. /* Is there a "HAVING"? */
  3441. old_lpszSqlStr = *lplpszSqlStr;
  3442. old_cbSqlStr = *pcbSqlStr;
  3443. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "HAVING", lpszToken);
  3444. if (err != ERR_SUCCESS) {
  3445. /* No. Return null */
  3446. *lplpszSqlStr = old_lpszSqlStr;
  3447. *pcbSqlStr = old_cbSqlStr;
  3448. *lpIdx = NO_SQLNODE;
  3449. }
  3450. else {
  3451. /* Yes. Return boolean */
  3452. err = ParseBoolean(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  3453. lpIdx, lpszToken);
  3454. if (err != ERR_SUCCESS)
  3455. return err;
  3456. }
  3457. return ERR_SUCCESS;
  3458. }
  3459. /***************************************************************************/
  3460. RETCODE INTFUNC ParseSelectlist(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  3461. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  3462. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  3463. /* Retrives a list of expressions from the input stream and creates a */
  3464. /* NODE_TYPE_VALUES node */
  3465. /* */
  3466. /* selectlist ::= selectlistitem , selectlist | selectlistitem */
  3467. /* selectlistitem ::= expression | expression alias | aliasname . * | expression AS alias */
  3468. {
  3469. RETCODE err;
  3470. LPUSTR old_lpszSqlStr;
  3471. SDWORD old_cbSqlStr;
  3472. LPSQLNODE lpSqlNode;
  3473. SQLNODEIDX idxValues;
  3474. SQLNODEIDX idxValue;
  3475. STRINGIDX idxAlias;
  3476. SQLNODEIDX idxValuesPrev;
  3477. /* Get list ofnodes */
  3478. idxValuesPrev = NO_SQLNODE;
  3479. while (TRUE) {
  3480. /* Look for aliasname.* */
  3481. old_lpszSqlStr = *lplpszSqlStr;
  3482. old_cbSqlStr = *pcbSqlStr;
  3483. idxValue = NO_SQLNODE;
  3484. err = GetIdentifier(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  3485. &idxAlias, lpszToken);
  3486. if (err == ERR_SUCCESS) {
  3487. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ".", lpszToken);
  3488. if (err == ERR_SUCCESS) {
  3489. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "*",
  3490. lpszToken);
  3491. }
  3492. }
  3493. /* Find it? */
  3494. if (err != ERR_SUCCESS) {
  3495. /* Get expression */
  3496. *lplpszSqlStr = old_lpszSqlStr;
  3497. *pcbSqlStr = old_cbSqlStr;
  3498. err = ParseExpression(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  3499. &idxValue, lpszToken);
  3500. if (err != ERR_SUCCESS)
  3501. return err;
  3502. /* Is there an alias */
  3503. old_lpszSqlStr = *lplpszSqlStr;
  3504. old_cbSqlStr = *pcbSqlStr;
  3505. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "AS", lpszToken);
  3506. if (err != ERR_SUCCESS) {
  3507. *lplpszSqlStr = old_lpszSqlStr;
  3508. *pcbSqlStr = old_cbSqlStr;
  3509. err = GetIdentifier(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  3510. &idxAlias, lpszToken);
  3511. if (err != ERR_SUCCESS) {
  3512. *lplpszSqlStr = old_lpszSqlStr;
  3513. *pcbSqlStr = old_cbSqlStr;
  3514. idxAlias = NO_STRING;
  3515. }
  3516. }
  3517. else {
  3518. err = GetIdentifier(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  3519. &idxAlias, lpszToken);
  3520. if (err != ERR_SUCCESS)
  3521. return err;
  3522. }
  3523. }
  3524. /* Create the VALUES node */
  3525. idxValues = AllocateNode(lplpSql, NODE_TYPE_VALUES);
  3526. if (idxValues == NO_SQLNODE)
  3527. return ERR_MEMALLOCFAIL;
  3528. lpSqlNode = ToNode(*lplpSql, idxValues);
  3529. lpSqlNode->node.values.Value = idxValue;
  3530. lpSqlNode->node.values.Alias = idxAlias;
  3531. lpSqlNode->node.values.Next = NO_SQLNODE;
  3532. /* Put node on list */
  3533. if (idxValuesPrev != NO_SQLNODE) {
  3534. lpSqlNode = ToNode(*lplpSql, idxValuesPrev);
  3535. lpSqlNode->node.values.Next = idxValues;
  3536. }
  3537. else
  3538. *lpIdx = idxValues;
  3539. idxValuesPrev = idxValues;
  3540. /* Is there a comma? */
  3541. old_lpszSqlStr = *lplpszSqlStr;
  3542. old_cbSqlStr = *pcbSqlStr;
  3543. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ",", lpszToken);
  3544. if (err != ERR_SUCCESS) {
  3545. /* No. This is the last value */
  3546. *lplpszSqlStr = old_lpszSqlStr;
  3547. *pcbSqlStr = old_cbSqlStr;
  3548. break;
  3549. }
  3550. }
  3551. return ERR_SUCCESS;
  3552. }
  3553. /***************************************************************************/
  3554. RETCODE INTFUNC ParseSelectcols(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  3555. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  3556. SQLNODEIDX FAR *lpIdx, BOOL FAR *lpfDistinct,
  3557. LPUSTR lpszToken)
  3558. /* Retrives a select list from the input stream and creates a */
  3559. /* NODE_TYPE_VALUES node */
  3560. /* */
  3561. /* selectcols ::= selectallcols * | selectallcols selectlist */
  3562. /* selectallcols ::= | ALL | DISTINCT */
  3563. {
  3564. RETCODE err;
  3565. LPUSTR old_lpszSqlStr;
  3566. SDWORD old_cbSqlStr;
  3567. /* See if ALL or DISTINCT is specified */
  3568. old_lpszSqlStr = *lplpszSqlStr;
  3569. old_cbSqlStr = *pcbSqlStr;
  3570. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, NULL, lpszToken);
  3571. if (err == ERR_SUCCESS) {
  3572. if (!s_lstrcmpi(lpszToken, "ALL"))
  3573. *lpfDistinct = FALSE;
  3574. else if (!s_lstrcmpi(lpszToken, "DISTINCT"))
  3575. *lpfDistinct = TRUE;
  3576. else {
  3577. *lpfDistinct = FALSE;
  3578. *lplpszSqlStr = old_lpszSqlStr;
  3579. *pcbSqlStr = old_cbSqlStr;
  3580. }
  3581. }
  3582. else {
  3583. *lpfDistinct = FALSE;
  3584. *lplpszSqlStr = old_lpszSqlStr;
  3585. *pcbSqlStr = old_cbSqlStr;
  3586. }
  3587. /* Is '*' is specified? */
  3588. old_lpszSqlStr = *lplpszSqlStr;
  3589. old_cbSqlStr = *pcbSqlStr;
  3590. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "*", lpszToken);
  3591. if (err != ERR_SUCCESS) {
  3592. /* No. Get list of values */
  3593. *lplpszSqlStr = old_lpszSqlStr;
  3594. *pcbSqlStr = old_cbSqlStr;
  3595. err = ParseSelectlist(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  3596. lpIdx, lpszToken);
  3597. if (err != ERR_SUCCESS)
  3598. return err;
  3599. }
  3600. else {
  3601. *lpIdx = NO_SQLNODE;
  3602. }
  3603. return ERR_SUCCESS;
  3604. }
  3605. /***************************************************************************/
  3606. RETCODE INTFUNC ParseColumn(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  3607. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  3608. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  3609. /* Retrives an unqualified columnname from the input stream and creates a */
  3610. /* NODE_TYPE_COLUMN node */
  3611. /* */
  3612. /* column ::= columnname */
  3613. {
  3614. LPSQLNODE lpSqlNode;
  3615. STRINGIDX idxColumn;
  3616. RETCODE err;
  3617. /* Get the columnname */
  3618. err = GetIdentifier(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  3619. &idxColumn, lpszToken);
  3620. if (err != ERR_SUCCESS)
  3621. return err;
  3622. /* Create the COLUMN node */
  3623. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_COLUMN);
  3624. if (*lpIdx == NO_SQLNODE)
  3625. return ERR_MEMALLOCFAIL;
  3626. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  3627. lpSqlNode->node.column.Tablealias = NO_STRING;
  3628. lpSqlNode->node.column.Column = idxColumn;
  3629. return ERR_SUCCESS;
  3630. }
  3631. /***************************************************************************/
  3632. RETCODE INTFUNC ParseColumnlist(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  3633. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  3634. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  3635. /* Retrives a list of columnnames from the input stream and creates a */
  3636. /* NODE_TYPE_COLUMNS node */
  3637. /* */
  3638. /* columnlist ::= column , columnlist | column */
  3639. {
  3640. RETCODE err;
  3641. LPUSTR old_lpszSqlStr;
  3642. SDWORD old_cbSqlStr;
  3643. LPSQLNODE lpSqlNode;
  3644. SQLNODEIDX idxColumns;
  3645. SQLNODEIDX idxColumn;
  3646. SQLNODEIDX idxColumnsPrev;
  3647. /* Get list of nodes */
  3648. idxColumnsPrev = NO_SQLNODE;
  3649. while (TRUE) {
  3650. /* Get columnname */
  3651. err = ParseColumn(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  3652. &idxColumn, lpszToken);
  3653. if (err != ERR_SUCCESS)
  3654. return err;
  3655. /* Create the COLUMNS node */
  3656. idxColumns = AllocateNode(lplpSql, NODE_TYPE_COLUMNS);
  3657. if (idxColumns == NO_SQLNODE)
  3658. return ERR_MEMALLOCFAIL;
  3659. lpSqlNode = ToNode(*lplpSql, idxColumns);
  3660. lpSqlNode->node.columns.Column = idxColumn;
  3661. lpSqlNode->node.columns.Next = NO_SQLNODE;
  3662. /* Put node on list */
  3663. if (idxColumnsPrev != NO_SQLNODE) {
  3664. lpSqlNode = ToNode(*lplpSql, idxColumnsPrev);
  3665. lpSqlNode->node.columns.Next = idxColumns;
  3666. }
  3667. else
  3668. *lpIdx = idxColumns;
  3669. idxColumnsPrev = idxColumns;
  3670. /* Is there a comma? */
  3671. old_lpszSqlStr = *lplpszSqlStr;
  3672. old_cbSqlStr = *pcbSqlStr;
  3673. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ",", lpszToken);
  3674. if (err != ERR_SUCCESS) {
  3675. /* No. This is the last one */
  3676. *lplpszSqlStr = old_lpszSqlStr;
  3677. *pcbSqlStr = old_cbSqlStr;
  3678. break;
  3679. }
  3680. }
  3681. return ERR_SUCCESS;
  3682. }
  3683. /***************************************************************************/
  3684. RETCODE INTFUNC ParseInsertvals(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  3685. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  3686. SQLNODEIDX FAR *lpIdxColumns,
  3687. SQLNODEIDX FAR *lpIdxValues, LPUSTR lpszToken)
  3688. /* Retrives an INSERT statement from the input stream and creates a */
  3689. /* NODE_TYPE_COLUMNS node and a NODE_TYPE_VALUES node */
  3690. /* */
  3691. /* insertvals ::= ( columnlist ) VALUES ( valuelist ) | */
  3692. /* ( columnlist ) VALUES ( SELECT select ) | */
  3693. /* VALUES ( valuelist ) | VALUES ( SELECT select ) */
  3694. {
  3695. LPUSTR old_lpszSqlStr;
  3696. SDWORD old_cbSqlStr;
  3697. RETCODE err;
  3698. /* Is there a column list? */
  3699. old_lpszSqlStr = *lplpszSqlStr;
  3700. old_cbSqlStr = *pcbSqlStr;
  3701. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "(", lpszToken);
  3702. if (err != ERR_SUCCESS) {
  3703. /* No. Send null node back */
  3704. *lplpszSqlStr = old_lpszSqlStr;
  3705. *pcbSqlStr = old_cbSqlStr;
  3706. *lpIdxColumns = NO_SQLNODE;
  3707. }
  3708. else {
  3709. /* Yes. Get the list */
  3710. err = ParseColumnlist(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  3711. lpIdxColumns, lpszToken);
  3712. if (err != ERR_SUCCESS)
  3713. return err;
  3714. /* Error if no ending ')' */
  3715. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ")", lpszToken);
  3716. if (err != ERR_SUCCESS)
  3717. return err;
  3718. }
  3719. /* Make sure keyword is given */
  3720. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "VALUES", lpszToken);
  3721. if (err != ERR_SUCCESS)
  3722. return err;
  3723. /* Error if no starting '(' */
  3724. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "(", lpszToken);
  3725. if (err != ERR_SUCCESS)
  3726. return err;
  3727. /* Sub-select? */
  3728. old_lpszSqlStr = *lplpszSqlStr;
  3729. old_cbSqlStr = *pcbSqlStr;
  3730. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "SELECT", lpszToken);
  3731. if (err != ERR_SUCCESS) {
  3732. /* No. Get the value list */
  3733. *lplpszSqlStr = old_lpszSqlStr;
  3734. *pcbSqlStr = old_cbSqlStr;
  3735. err = ParseValuelist(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  3736. lpIdxValues, lpszToken);
  3737. if (err != ERR_SUCCESS)
  3738. return err;
  3739. }
  3740. else {
  3741. /* Yes. Get SELECT */
  3742. err = ParseSelect(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  3743. lpIdxValues, lpszToken);
  3744. if (err != ERR_SUCCESS)
  3745. return err;
  3746. }
  3747. /* Error if no ending ')' */
  3748. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ")", lpszToken);
  3749. if (err != ERR_SUCCESS)
  3750. return err;
  3751. return ERR_SUCCESS;
  3752. }
  3753. /***************************************************************************/
  3754. RETCODE INTFUNC ParseSet(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  3755. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  3756. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  3757. /* Retrives an update expressions from the input stream and creates a */
  3758. /* NODE_TYPE_UPDATEVALUES node */
  3759. /* */
  3760. /* set ::= column = NULL | column = expression */
  3761. {
  3762. LPSQLNODE lpSqlNode;
  3763. SQLNODEIDX idxColumn;
  3764. SQLNODEIDX idxValue;
  3765. LPUSTR old_lpszSqlStr;
  3766. SDWORD old_cbSqlStr;
  3767. RETCODE err;
  3768. /* Get the column name */
  3769. err = ParseColumn(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, &idxColumn,
  3770. lpszToken);
  3771. if (err != ERR_SUCCESS)
  3772. return err;
  3773. /* Get the '=' sign */
  3774. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "=", lpszToken);
  3775. if (err != ERR_SUCCESS)
  3776. return err;
  3777. /* NULL specified? */
  3778. old_lpszSqlStr = *lplpszSqlStr;
  3779. old_cbSqlStr = *pcbSqlStr;
  3780. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "NULL", lpszToken);
  3781. if (err != ERR_SUCCESS) {
  3782. /* No. Get value */
  3783. *lplpszSqlStr = old_lpszSqlStr;
  3784. *pcbSqlStr = old_cbSqlStr;
  3785. err = ParseExpression(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  3786. &idxValue, lpszToken);
  3787. if (err != ERR_SUCCESS)
  3788. return err;
  3789. }
  3790. else {
  3791. /* Yes. Create a NULL node */
  3792. idxValue = AllocateNode(lplpSql, NODE_TYPE_NULL);
  3793. if (idxValue == NO_SQLNODE)
  3794. return ERR_MEMALLOCFAIL;
  3795. }
  3796. /* Create the UPDATEVALUES node */
  3797. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_UPDATEVALUES);
  3798. if (*lpIdx == NO_SQLNODE)
  3799. return ERR_MEMALLOCFAIL;
  3800. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  3801. lpSqlNode->node.updatevalues.Column = idxColumn;
  3802. lpSqlNode->node.updatevalues.Value = idxValue;
  3803. lpSqlNode->node.updatevalues.Next = NO_SQLNODE;
  3804. return ERR_SUCCESS;
  3805. }
  3806. /***************************************************************************/
  3807. RETCODE INTFUNC ParseSetlist(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  3808. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  3809. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  3810. /* Retrives a list of update expressions from the input stream and creates */
  3811. /* a NODE_TYPE_UPDATEVALUES node */
  3812. /* */
  3813. /* setlist ::= set , setlist | set */
  3814. {
  3815. RETCODE err;
  3816. LPUSTR old_lpszSqlStr;
  3817. SDWORD old_cbSqlStr;
  3818. LPSQLNODE lpSqlNode;
  3819. SQLNODEIDX idxUpdateValues;
  3820. SQLNODEIDX idxUpdateValuesPrev;
  3821. /* Get list of nodes */
  3822. idxUpdateValuesPrev = NO_SQLNODE;
  3823. while (TRUE) {
  3824. /* Get update expression */
  3825. err = ParseSet(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  3826. &idxUpdateValues, lpszToken);
  3827. if (err != ERR_SUCCESS)
  3828. return err;
  3829. /* Put node on list */
  3830. if (idxUpdateValuesPrev != NO_SQLNODE) {
  3831. lpSqlNode = ToNode(*lplpSql, idxUpdateValuesPrev);
  3832. lpSqlNode->node.updatevalues.Next = idxUpdateValues;
  3833. }
  3834. else
  3835. *lpIdx = idxUpdateValues;
  3836. idxUpdateValuesPrev = idxUpdateValues;
  3837. /* Is there a comma? */
  3838. old_lpszSqlStr = *lplpszSqlStr;
  3839. old_cbSqlStr = *pcbSqlStr;
  3840. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ",", lpszToken);
  3841. if (err != ERR_SUCCESS) {
  3842. /* No. This is the last update value */
  3843. *lplpszSqlStr = old_lpszSqlStr;
  3844. *pcbSqlStr = old_cbSqlStr;
  3845. break;
  3846. }
  3847. }
  3848. return ERR_SUCCESS;
  3849. }
  3850. /***************************************************************************/
  3851. RETCODE INTFUNC ParseUpdate(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  3852. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  3853. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  3854. /* Retrives an UPDATE statement from the input stream and creates a */
  3855. /* NODE_TYPE_UPDATE node */
  3856. /* */
  3857. /* update ::= table SET setlist where */
  3858. {
  3859. LPSQLNODE lpSqlNode;
  3860. SQLNODEIDX idxTable;
  3861. SQLNODEIDX idxUpdatevalues;
  3862. SQLNODEIDX idxPredicate;
  3863. RETCODE err;
  3864. /* Get tablename */
  3865. err = ParseTable(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, &idxTable,
  3866. lpszToken);
  3867. if (err != ERR_SUCCESS)
  3868. return err;
  3869. /* Make sure keyword is given */
  3870. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "SET", lpszToken);
  3871. if (err != ERR_SUCCESS)
  3872. return err;
  3873. /* Get update values */
  3874. err = ParseSetlist(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  3875. &idxUpdatevalues, lpszToken);
  3876. if (err != ERR_SUCCESS)
  3877. return err;
  3878. /* Get predicate */
  3879. err = ParseWhere(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, &idxPredicate,
  3880. lpszToken);
  3881. if (err != ERR_SUCCESS)
  3882. return err;
  3883. /* Create the UPDATE node */
  3884. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_UPDATE);
  3885. if (*lpIdx == NO_SQLNODE)
  3886. return ERR_MEMALLOCFAIL;
  3887. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  3888. lpSqlNode->node.update.Table = idxTable;
  3889. lpSqlNode->node.update.Updatevalues = idxUpdatevalues;
  3890. lpSqlNode->node.update.Predicate = idxPredicate;
  3891. return ERR_SUCCESS;
  3892. }
  3893. /***************************************************************************/
  3894. RETCODE INTFUNC ParseInsert(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  3895. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  3896. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  3897. /* Retrives an INSERT statement from the input stream and creates a */
  3898. /* NODE_TYPE_INSERT node */
  3899. /* */
  3900. /* insert ::= INTO table insertvals */
  3901. {
  3902. LPSQLNODE lpSqlNode;
  3903. SQLNODEIDX idxTable;
  3904. SQLNODEIDX idxColumns;
  3905. SQLNODEIDX idxValues;
  3906. RETCODE err;
  3907. /* Make sure keyword is given */
  3908. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "INTO", lpszToken);
  3909. if (err != ERR_SUCCESS)
  3910. return err;
  3911. /* Get table */
  3912. err = ParseTable(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, &idxTable,
  3913. lpszToken);
  3914. if (err != ERR_SUCCESS)
  3915. return err;
  3916. /* Get insert values */
  3917. err = ParseInsertvals(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  3918. &idxColumns, &idxValues, lpszToken);
  3919. if (err != ERR_SUCCESS)
  3920. return err;
  3921. /* Create the INSERT node */
  3922. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_INSERT);
  3923. if (*lpIdx == NO_SQLNODE)
  3924. return ERR_MEMALLOCFAIL;
  3925. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  3926. lpSqlNode->node.insert.Table = idxTable;
  3927. lpSqlNode->node.insert.Columns = idxColumns;
  3928. lpSqlNode->node.insert.Values = idxValues;
  3929. return ERR_SUCCESS;
  3930. }
  3931. /***************************************************************************/
  3932. RETCODE INTFUNC ParseDelete(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  3933. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  3934. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  3935. /* Retrives a DELETE statement from the input stream and creates a */
  3936. /* NODE_TYPE_DELETE node */
  3937. /* */
  3938. /* delete ::= FROM table where */
  3939. {
  3940. LPSQLNODE lpSqlNode;
  3941. SQLNODEIDX idxTable;
  3942. SQLNODEIDX idxPredicate;
  3943. RETCODE err;
  3944. /* Make sure "FROM" is specified */
  3945. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "FROM", lpszToken);
  3946. if (err != ERR_SUCCESS)
  3947. return err;
  3948. /* Get table */
  3949. err = ParseTable(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, &idxTable,
  3950. lpszToken);
  3951. if (err != ERR_SUCCESS)
  3952. return err;
  3953. /* Get predicate */
  3954. err = ParseWhere(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, &idxPredicate,
  3955. lpszToken);
  3956. if (err != ERR_SUCCESS)
  3957. return err;
  3958. /* Create the DELETE node */
  3959. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_DELETE);
  3960. if (*lpIdx == NO_SQLNODE)
  3961. return ERR_MEMALLOCFAIL;
  3962. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  3963. lpSqlNode->node.delet.Table = idxTable;
  3964. lpSqlNode->node.delet.Predicate = idxPredicate;
  3965. return ERR_SUCCESS;
  3966. }
  3967. /***************************************************************************/
  3968. RETCODE INTFUNC ParseSelect(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  3969. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  3970. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  3971. /* Retrives a SELECT statement from the input stream and creates a */
  3972. /* NODE_TYPE_SELECT node */
  3973. /* */
  3974. /* select ::= selectcols FROM tablelist where groupby having */
  3975. {
  3976. LPSQLNODE lpSqlNode;
  3977. BOOL fDistinct;
  3978. SQLNODEIDX idxValues;
  3979. SQLNODEIDX idxTables;
  3980. SQLNODEIDX idxPredicate;
  3981. SQLNODEIDX idxGroupbycolumns;
  3982. SQLNODEIDX idxHaving;
  3983. RETCODE err;
  3984. /* Get selection columns */
  3985. err = ParseSelectcols(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  3986. &idxValues, &fDistinct, lpszToken);
  3987. if (err != ERR_SUCCESS)
  3988. return err;
  3989. /* Make sure "FROM" is specified */
  3990. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "FROM", lpszToken);
  3991. if (err != ERR_SUCCESS)
  3992. return err;
  3993. /* Get list of tables */
  3994. err = ParseTablelist(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, &idxTables,
  3995. lpszToken);
  3996. if (err != ERR_SUCCESS)
  3997. return err;
  3998. /* Get predicate */
  3999. err = ParseWhere(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, &idxPredicate,
  4000. lpszToken);
  4001. if (err != ERR_SUCCESS)
  4002. return err;
  4003. /* Get group by */
  4004. err = ParseGroupby(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  4005. &idxGroupbycolumns, lpszToken);
  4006. if (err != ERR_SUCCESS)
  4007. return err;
  4008. /* Get having */
  4009. err = ParseHaving(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, &idxHaving,
  4010. lpszToken);
  4011. if (err != ERR_SUCCESS)
  4012. return err;
  4013. /* Create the SELECT node */
  4014. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_SELECT);
  4015. if (*lpIdx == NO_SQLNODE)
  4016. return ERR_MEMALLOCFAIL;
  4017. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  4018. lpSqlNode->node.select.Distinct = fDistinct;
  4019. lpSqlNode->node.select.Values = idxValues;
  4020. lpSqlNode->node.select.Tables = idxTables;
  4021. lpSqlNode->node.select.Predicate = idxPredicate;
  4022. lpSqlNode->node.select.Groupbycolumns = idxGroupbycolumns;
  4023. lpSqlNode->node.select.Having = idxHaving;
  4024. lpSqlNode->node.select.Sortcolumns = NO_SQLNODE;
  4025. lpSqlNode->node.select.SortDirective = NO_STRING;
  4026. lpSqlNode->node.select.SortRecordsize = 0;
  4027. lpSqlNode->node.select.SortBookmarks = 0;
  4028. lpSqlNode->node.select.Aggregates = NO_SQLNODE;
  4029. lpSqlNode->node.select.SortKeysize = 0;
  4030. lpSqlNode->node.select.DistinctDirective = NO_STRING;
  4031. lpSqlNode->node.select.DistinctRecordsize = 0;
  4032. lpSqlNode->node.select.ImplicitGroupby = FALSE;
  4033. lpSqlNode->node.select.EnclosingStatement = NO_SQLNODE;
  4034. lpSqlNode->node.select.fPushdownSort = FALSE;
  4035. lpSqlNode->node.select.fMSAccess = FALSE;
  4036. lpSqlNode->node.select.RowCount = -1;
  4037. lpSqlNode->node.select.CurrentRow = AFTER_LAST_ROW;
  4038. lpSqlNode->node.select.SortfileName = NO_STRING;
  4039. lpSqlNode->node.select.Sortfile = HFILE_ERROR;
  4040. lpSqlNode->node.select.ReturningDistinct = FALSE;
  4041. return ERR_SUCCESS;
  4042. }
  4043. /***************************************************************************/
  4044. RETCODE INTFUNC ParseDrop(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  4045. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  4046. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  4047. /* Retrives a DROP TABLE statement from the input stream and creates a */
  4048. /* NODE_TYPE_DROP node */
  4049. /* */
  4050. /* drop ::= TABLE tablename | INDEX indexname */
  4051. {
  4052. LPSQLNODE lpSqlNode;
  4053. STRINGIDX idxIndexname;
  4054. STRINGIDX idxTablename;
  4055. RETCODE err;
  4056. LPUSTR old_lpszSqlStr;
  4057. SDWORD old_cbSqlStr;
  4058. /* Is an index being dropped? */
  4059. old_lpszSqlStr = *lplpszSqlStr;
  4060. old_cbSqlStr = *pcbSqlStr;
  4061. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "INDEX", lpszToken);
  4062. if (err == ERR_SUCCESS) {
  4063. /* Yes. Get index name */
  4064. err = GetIdentifier(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  4065. &idxIndexname, lpszToken);
  4066. if (err != ERR_SUCCESS)
  4067. return err;
  4068. /* Create the DROPINDEX node */
  4069. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_DROPINDEX);
  4070. if (*lpIdx == NO_SQLNODE)
  4071. return ERR_MEMALLOCFAIL;
  4072. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  4073. lpSqlNode->node.dropindex.Index = idxIndexname;
  4074. }
  4075. else {
  4076. /* No. Make sure a table is being dropped */
  4077. *lplpszSqlStr = old_lpszSqlStr;
  4078. *pcbSqlStr = old_cbSqlStr;
  4079. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "TABLE", lpszToken);
  4080. if (err != ERR_SUCCESS)
  4081. return err;
  4082. /* Get the tablename */
  4083. err = GetIdentifier(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  4084. &idxTablename, lpszToken);
  4085. if (err != ERR_SUCCESS)
  4086. return err;
  4087. /* Create the DROP node */
  4088. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_DROP);
  4089. if (*lpIdx == NO_SQLNODE)
  4090. return ERR_MEMALLOCFAIL;
  4091. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  4092. lpSqlNode->node.drop.Table = idxTablename;
  4093. }
  4094. return ERR_SUCCESS;
  4095. }
  4096. /***************************************************************************/
  4097. RETCODE INTFUNC ParseCreatecol(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  4098. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  4099. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  4100. /* Retrives a list of column defintiions from the input stream and creates */
  4101. /* a NODE_TYPE_CREATECOLS node */
  4102. /* */
  4103. /* createcol ::= columnname datatype | columnname datatype ( integer ) | */
  4104. /* columnname datatype ( integer , integer ) */
  4105. {
  4106. LPUSTR old_lpszSqlStr;
  4107. SDWORD old_cbSqlStr;
  4108. LPSQLNODE lpSqlNode;
  4109. STRINGIDX idxName;
  4110. STRINGIDX idxType;
  4111. UWORD cParams;
  4112. UDWORD udParam1;
  4113. UDWORD udParam2;
  4114. RETCODE err;
  4115. /* Get the columnname */
  4116. err = GetIdentifier(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  4117. &idxName, lpszToken);
  4118. if (err != ERR_SUCCESS)
  4119. return err;
  4120. /* Get the type */
  4121. err = GetIdentifier(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  4122. &idxType, lpszToken);
  4123. if (err != ERR_SUCCESS)
  4124. return err;
  4125. /* Are there any create parameters? */
  4126. old_lpszSqlStr = *lplpszSqlStr;
  4127. old_cbSqlStr = *pcbSqlStr;
  4128. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "(", lpszToken);
  4129. if (err != ERR_SUCCESS) {
  4130. /* No. */
  4131. *lplpszSqlStr = old_lpszSqlStr;
  4132. *pcbSqlStr = old_cbSqlStr;
  4133. cParams = 0;
  4134. udParam1 = 0;
  4135. udParam2 = 0;
  4136. }
  4137. else {
  4138. /* Yes. Get the first create param */
  4139. cParams = 1;
  4140. err = GetInteger(lpstmt, lplpszSqlStr, pcbSqlStr, &udParam1,
  4141. lpszToken);
  4142. if (err != ERR_SUCCESS)
  4143. return err;
  4144. /* Get the next token */
  4145. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, NULL, lpszToken);
  4146. if (err != ERR_SUCCESS)
  4147. return err;
  4148. /* Is there a second create param */
  4149. if (*lpszToken == ',') {
  4150. /* Yes. Get that one too */
  4151. cParams = 2;
  4152. err = GetInteger(lpstmt, lplpszSqlStr, pcbSqlStr, &udParam2,
  4153. lpszToken);
  4154. if (err != ERR_SUCCESS)
  4155. return err;
  4156. /* Get the next token */
  4157. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, NULL, lpszToken);
  4158. if (err != ERR_SUCCESS)
  4159. return err;
  4160. }
  4161. else
  4162. udParam2 = 0;
  4163. /* Error if terminating paren is missing */
  4164. if (*lpszToken != ')') {
  4165. s_lstrcpy(lpstmt->szError, ")");
  4166. return ERR_EXPECTEDOTHER;
  4167. }
  4168. }
  4169. /* Create the CREATECOLS node */
  4170. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_CREATECOLS);
  4171. if (*lpIdx == NO_SQLNODE)
  4172. return ERR_MEMALLOCFAIL;
  4173. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  4174. lpSqlNode->node.createcols.Name = idxName;
  4175. lpSqlNode->node.createcols.Type = idxType;
  4176. lpSqlNode->node.createcols.Params = cParams;
  4177. lpSqlNode->node.createcols.Param1 = udParam1;
  4178. lpSqlNode->node.createcols.Param2 = udParam2;
  4179. lpSqlNode->node.createcols.Next = NO_SQLNODE;
  4180. lpSqlNode->node.createcols.iSqlType = (UWORD) -1;
  4181. return ERR_SUCCESS;
  4182. }
  4183. /***************************************************************************/
  4184. RETCODE INTFUNC ParseCreatecols(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  4185. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  4186. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  4187. /* Retrives a list of column defintiions from the input stream and creates */
  4188. /* a NODE_TYPE_CREATECOLS node */
  4189. /* */
  4190. /* createcols ::= createcol , createcols | createcol */
  4191. {
  4192. RETCODE err;
  4193. LPUSTR old_lpszSqlStr;
  4194. SDWORD old_cbSqlStr;
  4195. LPSQLNODE lpSqlNode;
  4196. SQLNODEIDX idxCreateCols;
  4197. SQLNODEIDX idxCreateColsPrev;
  4198. /* Getlist of nodes */
  4199. idxCreateColsPrev = NO_SQLNODE;
  4200. while (TRUE) {
  4201. /* Get create column */
  4202. err = ParseCreatecol(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  4203. &idxCreateCols, lpszToken);
  4204. if (err != ERR_SUCCESS)
  4205. return err;
  4206. /* Put node on list */
  4207. if (idxCreateColsPrev != NO_SQLNODE) {
  4208. lpSqlNode = ToNode(*lplpSql, idxCreateColsPrev);
  4209. lpSqlNode->node.createcols.Next = idxCreateCols;
  4210. }
  4211. else
  4212. *lpIdx = idxCreateCols;
  4213. idxCreateColsPrev = idxCreateCols;
  4214. /* Is there a comma? */
  4215. old_lpszSqlStr = *lplpszSqlStr;
  4216. old_cbSqlStr = *pcbSqlStr;
  4217. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ",", lpszToken);
  4218. if (err != ERR_SUCCESS) {
  4219. /* No. This is the last create column */
  4220. *lplpszSqlStr = old_lpszSqlStr;
  4221. *pcbSqlStr = old_cbSqlStr;
  4222. break;
  4223. }
  4224. }
  4225. return ERR_SUCCESS;
  4226. }
  4227. /***************************************************************************/
  4228. RETCODE INTFUNC ParseIndexcolumn(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  4229. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  4230. SQLNODEIDX FAR *lpIdx, BOOL FAR *lpfDescending,
  4231. LPUSTR lpszToken)
  4232. /* Retrives anindex column name from the input stream and creates a */
  4233. /* NODE_TYPE_COLUMN node */
  4234. /* */
  4235. /* indexcolumn ::= column asc */
  4236. /* asc ::= | ASC | DESC */
  4237. {
  4238. RETCODE err;
  4239. LPUSTR old_lpszSqlStr;
  4240. SDWORD old_cbSqlStr;
  4241. /* Get column name */
  4242. err = ParseColumn(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, lpIdx,
  4243. lpszToken);
  4244. if (err != ERR_SUCCESS)
  4245. return err;
  4246. /* Get ASC or DESC */
  4247. old_lpszSqlStr = *lplpszSqlStr;
  4248. old_cbSqlStr = *pcbSqlStr;
  4249. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, NULL, lpszToken);
  4250. if (err != ERR_SUCCESS) {
  4251. *lplpszSqlStr = old_lpszSqlStr;
  4252. *pcbSqlStr = old_cbSqlStr;
  4253. *lpfDescending = FALSE;
  4254. }
  4255. else if (!s_lstrcmpi(lpszToken, "ASC")) {
  4256. *lpfDescending = FALSE;
  4257. }
  4258. else if (!s_lstrcmpi(lpszToken, "DESC")) {
  4259. *lpfDescending = TRUE;
  4260. }
  4261. else {
  4262. *lplpszSqlStr = old_lpszSqlStr;
  4263. *pcbSqlStr = old_cbSqlStr;
  4264. *lpfDescending = FALSE;
  4265. }
  4266. return ERR_SUCCESS;
  4267. }
  4268. /***************************************************************************/
  4269. RETCODE INTFUNC ParseIndexcolumns(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  4270. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  4271. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  4272. /* Retrives a column list from the input stream and creates a */
  4273. /* NODE_TYPE_SORTCOLUMNS node */
  4274. /* */
  4275. /* indexcolumns ::= indexcolumn | indexcolumn , indexcolumns */
  4276. {
  4277. RETCODE err;
  4278. LPUSTR old_lpszSqlStr;
  4279. SDWORD old_cbSqlStr;
  4280. LPSQLNODE lpSqlNode;
  4281. BOOL fDescending;
  4282. SQLNODEIDX idxColumn;
  4283. SQLNODEIDX idxSortcolumns;
  4284. SQLNODEIDX idxSortcolumnsPrev;
  4285. /* Get list of nodes */
  4286. idxSortcolumnsPrev = NO_SQLNODE;
  4287. while (TRUE) {
  4288. /* Get indexcolumn column */
  4289. err = ParseIndexcolumn(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  4290. &idxColumn, &fDescending, lpszToken);
  4291. if (err != ERR_SUCCESS)
  4292. return err;
  4293. /* Create the SORTCOLUMNS node */
  4294. idxSortcolumns = AllocateNode(lplpSql, NODE_TYPE_SORTCOLUMNS);
  4295. if (idxSortcolumns == NO_SQLNODE)
  4296. return ERR_MEMALLOCFAIL;
  4297. lpSqlNode = ToNode(*lplpSql, idxSortcolumns);
  4298. lpSqlNode->node.sortcolumns.Column = idxColumn;
  4299. lpSqlNode->node.sortcolumns.Descending = fDescending;
  4300. lpSqlNode->node.sortcolumns.Next = NO_SQLNODE;
  4301. /* Put node on list */
  4302. if (idxSortcolumnsPrev != NO_SQLNODE) {
  4303. lpSqlNode = ToNode(*lplpSql, idxSortcolumnsPrev);
  4304. lpSqlNode->node.sortcolumns.Next = idxSortcolumns;
  4305. }
  4306. else
  4307. *lpIdx = idxSortcolumns;
  4308. idxSortcolumnsPrev = idxSortcolumns;
  4309. /* Is there a comma? */
  4310. old_lpszSqlStr = *lplpszSqlStr;
  4311. old_cbSqlStr = *pcbSqlStr;
  4312. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ",", lpszToken);
  4313. if (err != ERR_SUCCESS) {
  4314. /* No. This is the last indexcolumn */
  4315. *lplpszSqlStr = old_lpszSqlStr;
  4316. *pcbSqlStr = old_cbSqlStr;
  4317. break;
  4318. }
  4319. }
  4320. return ERR_SUCCESS;
  4321. }
  4322. /***************************************************************************/
  4323. RETCODE INTFUNC ParseCreate(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  4324. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  4325. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  4326. /* Retrives a CREATE TABLE statement from the input stream and creates a */
  4327. /* NODE_TYPE_CREATE or NODE_TYPE_CREATEINDEX node */
  4328. /* */
  4329. /* create ::= TABLE tablename ( createcols ) | */
  4330. /* INDEX indexname ON table ( indexcolumns ) */
  4331. {
  4332. LPUSTR old_lpszSqlStr;
  4333. SDWORD old_cbSqlStr;
  4334. LPSQLNODE lpSqlNode;
  4335. STRINGIDX idxIndexname;
  4336. RETCODE err;
  4337. STRINGIDX idxTablename;
  4338. SQLNODEIDX idxTable;
  4339. SQLNODEIDX idxColumns;
  4340. BOOL fUnique;
  4341. old_lpszSqlStr = *lplpszSqlStr;
  4342. old_cbSqlStr = *pcbSqlStr;
  4343. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "UNIQUE",
  4344. lpszToken);
  4345. if (err == ERR_SUCCESS) {
  4346. fUnique = TRUE;
  4347. }
  4348. else {
  4349. *lplpszSqlStr = old_lpszSqlStr;
  4350. *pcbSqlStr = old_cbSqlStr;
  4351. fUnique = FALSE;
  4352. }
  4353. /* Is an index being created? */
  4354. old_lpszSqlStr = *lplpszSqlStr;
  4355. old_cbSqlStr = *pcbSqlStr;
  4356. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "INDEX", lpszToken);
  4357. if (err == ERR_SUCCESS) {
  4358. /* Get index name */
  4359. err = GetIdentifier(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  4360. &idxIndexname, lpszToken);
  4361. if (err != ERR_SUCCESS)
  4362. return err;
  4363. /* Make sure "ON" is specified */
  4364. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "ON", lpszToken);
  4365. if (err != ERR_SUCCESS)
  4366. return err;
  4367. /* Get the table */
  4368. err = ParseTable(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql, &idxTable,
  4369. lpszToken);
  4370. if (err != ERR_SUCCESS)
  4371. return err;
  4372. /* Get opening paren for column list */
  4373. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "(", lpszToken);
  4374. if (err != ERR_SUCCESS)
  4375. return err;
  4376. /* Get indexcolumns */
  4377. err = ParseIndexcolumns(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  4378. &idxColumns, lpszToken);
  4379. if (err != ERR_SUCCESS)
  4380. return err;
  4381. /* Get closing paren for column list */
  4382. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ")", lpszToken);
  4383. if (err != ERR_SUCCESS)
  4384. return err;
  4385. /* Create the CREATEINDEX node */
  4386. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_CREATEINDEX);
  4387. if (*lpIdx == NO_SQLNODE)
  4388. return ERR_MEMALLOCFAIL;
  4389. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  4390. lpSqlNode->node.createindex.Index = idxIndexname;
  4391. lpSqlNode->node.createindex.Table = idxTable;
  4392. lpSqlNode->node.createindex.Columns = idxColumns;
  4393. lpSqlNode->node.createindex.Unique = fUnique;
  4394. }
  4395. else {
  4396. /* No. Make sure a table is being created */
  4397. *lplpszSqlStr = old_lpszSqlStr;
  4398. *pcbSqlStr = old_cbSqlStr;
  4399. err = GetKeyword(lpstmt, lplpszSqlStr, pcbSqlStr, "TABLE", lpszToken);
  4400. if (err != ERR_SUCCESS)
  4401. return err;
  4402. /* Error if UNIQUE specified */
  4403. if (fUnique) {
  4404. s_lstrcpy(lpstmt->szError, "UNIQUE");
  4405. return ERR_EXPECTEDOTHER;
  4406. }
  4407. /* Get the tablename */
  4408. err = GetIdentifier(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  4409. &idxTablename, lpszToken);
  4410. if (err != ERR_SUCCESS)
  4411. return err;
  4412. /* Get opening paren for column descriptions */
  4413. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, "(", lpszToken);
  4414. if (err != ERR_SUCCESS)
  4415. return err;
  4416. /* Get the columnlist */
  4417. err = ParseCreatecols(lpstmt, lplpszSqlStr, pcbSqlStr, lplpSql,
  4418. &idxColumns, lpszToken);
  4419. if (err != ERR_SUCCESS)
  4420. return err;
  4421. /* Get closing paren for column descriptions */
  4422. err = GetSymbol(lpstmt, lplpszSqlStr, pcbSqlStr, ")", lpszToken);
  4423. if (err != ERR_SUCCESS)
  4424. return err;
  4425. /* Create the CREATE node */
  4426. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_CREATE);
  4427. if (*lpIdx == NO_SQLNODE)
  4428. return ERR_MEMALLOCFAIL;
  4429. lpSqlNode = ToNode(*lplpSql, *lpIdx);
  4430. lpSqlNode->node.create.Table = idxTablename;
  4431. lpSqlNode->node.create.Columns = idxColumns;
  4432. }
  4433. return ERR_SUCCESS;
  4434. }
  4435. /***************************************************************************/
  4436. RETCODE INTFUNC ParsePassthrough(LPSTMT lpstmt, LPUSTR FAR *lplpszSqlStr,
  4437. SDWORD FAR *pcbSqlStr, LPSQLTREE FAR *lplpSql,
  4438. SQLNODEIDX FAR *lpIdx, LPUSTR lpszToken)
  4439. /* Retrives a "SQL" statement from the input stream and creates a */
  4440. /* NODE_TYPE_PASSTHROUGH node */
  4441. /* */
  4442. /* passthrough ::= */
  4443. {
  4444. /* Create the PASSTHROUGH node */
  4445. *lpIdx = AllocateNode(lplpSql, NODE_TYPE_PASSTHROUGH);
  4446. if (*lpIdx == NO_SQLNODE)
  4447. return ERR_MEMALLOCFAIL;
  4448. return ERR_SUCCESS;
  4449. }
  4450. /***************************************************************************/
  4451. RETCODE INTFUNC Parse(LPSTMT lpstmt, LPISAM lpISAM, LPUSTR lpszSqlStr,
  4452. SDWORD cbSqlStr, LPSQLTREE FAR *lplpSql)
  4453. /* Parses an SQL statement and returns a parse tree. The parse tree is */
  4454. /* stored in an array of nodes. The root of the tree is in node 0. */
  4455. /* String values (such as table names) are not stored in the parse tree, */
  4456. /* instead they are stored in a "string area". The parse tree array is */
  4457. /* returned in lplpSql. A pointer to the "string area" is returned in the */
  4458. /* root of the parse tree. The user must call FreeTree() to deallocate */
  4459. /* the space pointed to by lplpSql. */
  4460. /* */
  4461. /* statement ::= CREATE create | DROP drop | SELECT select orderby | */
  4462. /* INSERT insert | DELETE delete | UPDATE update | SQL */
  4463. {
  4464. LPSQLTREE lpSql;
  4465. HGLOBAL hParseArray;
  4466. UCHAR szToken[MAX_TOKEN_SIZE + 1];
  4467. RETCODE err;
  4468. SQLNODEIDX idxRoot;
  4469. UWORD fType;
  4470. SQLNODEIDX idxSortcolumns;
  4471. /* Get first token */
  4472. err = GetKeyword(lpstmt, &lpszSqlStr, &cbSqlStr, NULL, szToken);
  4473. if (err != ERR_SUCCESS)
  4474. return err;
  4475. /* Allocate initial space */
  4476. hParseArray = GlobalAlloc(GMEM_MOVEABLE,
  4477. sizeof(SQLNODE) * SQLNODE_ALLOC);
  4478. if (hParseArray == NULL)
  4479. return ERR_MEMALLOCFAIL;
  4480. lpSql = (LPSQLTREE) GlobalLock(hParseArray);
  4481. if (lpSql == NULL) {
  4482. GlobalFree(hParseArray);
  4483. return ERR_MEMALLOCFAIL;
  4484. }
  4485. /* Initialize the root node */
  4486. lpSql->sqlNodeType = NODE_TYPE_ROOT;
  4487. lpSql->node.root.lpISAM = lpISAM;
  4488. lpSql->node.root.hParseArray = hParseArray;
  4489. lpSql->node.root.cParseArray = SQLNODE_ALLOC;
  4490. lpSql->node.root.iParseArray = 0;
  4491. lpSql->node.root.hStringArea = NULL;
  4492. lpSql->node.root.lpStringArea = NULL;
  4493. lpSql->node.root.cbStringArea = 0;
  4494. lpSql->node.root.ibStringArea = -1;
  4495. lpSql->node.root.sql = NO_SQLNODE;
  4496. lpSql->node.root.parameters = NO_SQLNODE;
  4497. lpSql->node.root.passthroughParams = FALSE;
  4498. /* Parse statement */
  4499. if (!s_lstrcmpi(szToken, "CREATE")) {
  4500. err = ERR_CREATE_NOTSUPP;
  4501. // err = ParseCreate(lpstmt, &lpszSqlStr, &cbSqlStr, &lpSql, &idxRoot,
  4502. // szToken);
  4503. }
  4504. else if (!s_lstrcmpi(szToken, "DROP")) {
  4505. err = ERR_DROP_NOTSUPP;
  4506. // err = ParseDrop(lpstmt, &lpszSqlStr, &cbSqlStr, &lpSql, &idxRoot,
  4507. // szToken);
  4508. }
  4509. else if (!s_lstrcmpi(szToken, "SELECT")) {
  4510. err = ParseSelect(lpstmt, &lpszSqlStr, &cbSqlStr, &lpSql, &idxRoot,
  4511. szToken);
  4512. if (err == ERR_SUCCESS) {
  4513. err = ParseOrderby(lpstmt, &lpszSqlStr, &cbSqlStr, &lpSql,
  4514. &idxSortcolumns, szToken);
  4515. if (idxSortcolumns != NO_SQLNODE) {
  4516. ToNode(lpSql, idxRoot)->node.select.Sortcolumns =
  4517. idxSortcolumns;
  4518. }
  4519. }
  4520. }
  4521. else if (!s_lstrcmpi(szToken, "INSERT")) {
  4522. err = ERR_INSERT_NOTSUPP;
  4523. // err = ParseInsert(lpstmt, &lpszSqlStr, &cbSqlStr, &lpSql, &idxRoot,
  4524. // szToken);
  4525. }
  4526. else if (!s_lstrcmpi(szToken, "DELETE")) {
  4527. err = ERR_DELETE_NOTSUPP;
  4528. // err = ParseDelete(lpstmt, &lpszSqlStr, &cbSqlStr, &lpSql, &idxRoot,
  4529. // szToken);
  4530. }
  4531. else if (!s_lstrcmpi(szToken, "UPDATE")) {
  4532. err = ERR_UPDATE_NOTSUPP;
  4533. // err = ParseUpdate(lpstmt, &lpszSqlStr, &cbSqlStr, &lpSql, &idxRoot,
  4534. // szToken);
  4535. }
  4536. else if (!s_lstrcmpi(szToken, "SQL")) {
  4537. //Sai Wong
  4538. // err = ERR_NOTSUPPORTED;
  4539. err = ParsePassthrough(lpstmt, &lpszSqlStr, &cbSqlStr, &lpSql,
  4540. &idxRoot, szToken);
  4541. }
  4542. else if (!lstrcmpi((char*)szToken, "ALTER")) {
  4543. //Dr. DeeBee Driver does not cater for this command
  4544. err = ERR_ALTER_NOTSUPP;
  4545. }
  4546. else if (!lstrcmpi((char*)szToken, "GRANT")) {
  4547. //Dr. DeeBee Driver does not cater for this command
  4548. err = ERR_GRANT_NOTSUPP;
  4549. }
  4550. else if (!lstrcmpi((char*)szToken, "REVOKE")) {
  4551. //Dr. DeeBee Driver does not cater for this command
  4552. err = ERR_REVOKE_NOTSUPP;
  4553. }
  4554. else {
  4555. s_lstrcpy(lpstmt->szError, "CREATE, DROP, SELECT, INSERT, UPDATE, or DELETE");
  4556. err = ERR_EXPECTEDOTHER;
  4557. }
  4558. if (err != ERR_SUCCESS) {
  4559. FreeTree(lpSql);
  4560. return err;
  4561. }
  4562. /* Error if any unused tokens */
  4563. err = GetToken(lpstmt, lpszSqlStr, cbSqlStr, szToken, &fType,
  4564. &lpszSqlStr, &cbSqlStr);
  4565. if (err != ERR_SUCCESS) {
  4566. FreeTree(lpSql);
  4567. return err;
  4568. }
  4569. if (fType != TOKEN_TYPE_NONE) {
  4570. FreeTree(lpSql);
  4571. s_lstrcpy(lpstmt->szError, szToken);
  4572. return ERR_UNEXPECTEDTOKEN;
  4573. }
  4574. /* Fill in the root node */
  4575. lpSql->node.root.sql = idxRoot;
  4576. *lplpSql = lpSql;
  4577. return ERR_SUCCESS;
  4578. }
  4579. /***************************************************************************/
  4580. //Generates string for a comparision expression
  4581. //The input parameters are the left and right values to compare and
  4582. //the comparision operator
  4583. void PredicateParser :: GenerateComparisonString(char* lpLeftString, char* lpRightString, UWORD wOperator, UWORD wSelectModifier, char** lpOutputStr)
  4584. {
  4585. *lpOutputStr = NULL;
  4586. //Check for valid parameters
  4587. if ( !lpLeftString || !lpRightString)
  4588. return;
  4589. //Lengths of strings
  4590. ULONG cLeftLen = lstrlen(lpLeftString);
  4591. ULONG cRightLen = lstrlen(lpRightString);
  4592. ULONG cOperatorLen = 0;
  4593. char* selectop = NULL;
  4594. //OK get the operator string
  4595. char* lpOperatorStr = NULL;
  4596. switch (wOperator)
  4597. {
  4598. case OP_EQ:
  4599. lpOperatorStr = "=";
  4600. break;
  4601. case OP_NE:
  4602. lpOperatorStr = "<>";
  4603. break;
  4604. case OP_LE:
  4605. lpOperatorStr = "<=";
  4606. break;
  4607. case OP_LT:
  4608. lpOperatorStr = "<";
  4609. break;
  4610. case OP_GE:
  4611. lpOperatorStr = ">=";
  4612. break;
  4613. case OP_GT:
  4614. lpOperatorStr = ">";
  4615. break;
  4616. case OP_LIKE:
  4617. lpOperatorStr = "LIKE";
  4618. break;
  4619. case OP_NOTLIKE:
  4620. lpOperatorStr = "NOT LIKE";
  4621. break;
  4622. case OP_IN:
  4623. lpOperatorStr = "IN";
  4624. break;
  4625. case OP_NOTIN:
  4626. lpOperatorStr = "NOT IN";
  4627. break;
  4628. default:
  4629. //error
  4630. return;
  4631. break;
  4632. }
  4633. if (lpOperatorStr)
  4634. cOperatorLen = lstrlen (lpOperatorStr);
  4635. //Double check for sub-select
  4636. if ( (wSelectModifier == SELECT_ALL) || (wSelectModifier == SELECT_ANY) )
  4637. {
  4638. if ( (wOperator != OP_IN) && (wOperator != OP_NOTIN) )
  4639. {
  4640. switch (wSelectModifier)
  4641. {
  4642. case SELECT_ALL:
  4643. selectop = "ALL";
  4644. cOperatorLen += 5;
  4645. break;
  4646. case SELECT_ANY:
  4647. selectop = "ANY";
  4648. cOperatorLen += 5;
  4649. break;
  4650. default:
  4651. break;
  4652. }
  4653. }
  4654. }
  4655. //Generate output string in the format
  4656. // ( left operator right )
  4657. (*lpOutputStr) = new char [cLeftLen + cRightLen + cOperatorLen + 5];
  4658. (*lpOutputStr)[0] = 0;
  4659. if (selectop)
  4660. {
  4661. sprintf (*lpOutputStr, "(%s %s %s %s)", lpLeftString, lpOperatorStr, selectop, lpRightString);
  4662. }
  4663. else
  4664. {
  4665. sprintf (*lpOutputStr, "(%s %s %s)", lpLeftString, lpOperatorStr, lpRightString);
  4666. }
  4667. }
  4668. //Generates string for a boolean expression
  4669. //The input parameters are the left and right values of the boolean and
  4670. //the boolean operator
  4671. void PredicateParser :: GenerateBooleanString(char* lpLeftString, char* lpRightString, UWORD wOperator, char** lpOutputStr)
  4672. {
  4673. *lpOutputStr = NULL;
  4674. //Check for valid parameters
  4675. if ( !lpLeftString || !lpRightString)
  4676. return;
  4677. //Lengths of strings
  4678. ULONG cLeftLen = lstrlen(lpLeftString);
  4679. ULONG cRightLen = lstrlen(lpRightString);
  4680. ULONG cOperatorLen = 0;
  4681. //OK get the operator string
  4682. char* lpOperatorStr = NULL;
  4683. switch (wOperator)
  4684. {
  4685. case OP_NOT:
  4686. lpOperatorStr = "NOT";
  4687. break;
  4688. case OP_AND:
  4689. lpOperatorStr = "AND";
  4690. break;
  4691. case OP_OR:
  4692. lpOperatorStr = "OR";
  4693. break;
  4694. default:
  4695. //error
  4696. return;
  4697. break;
  4698. }
  4699. if (lpOperatorStr)
  4700. cOperatorLen = lstrlen (lpOperatorStr);
  4701. //Generate output string
  4702. if (wOperator != OP_NOT)
  4703. {
  4704. //Format of output string
  4705. // ( left operator right )
  4706. (*lpOutputStr) = new char [cLeftLen + cRightLen + cOperatorLen + 5];
  4707. (*lpOutputStr)[0] = 0;
  4708. sprintf (*lpOutputStr, "(%s %s %s)", lpLeftString, lpOperatorStr, lpRightString);
  4709. }
  4710. else
  4711. {
  4712. //Format of output string
  4713. // ( operator left )
  4714. (*lpOutputStr) = new char [cLeftLen + cOperatorLen + 4];
  4715. (*lpOutputStr)[0] = 0;
  4716. sprintf (*lpOutputStr, "(%s %s)", lpOperatorStr, lpLeftString);
  4717. }
  4718. }
  4719. //Generates string for an aggregate expression
  4720. //The input parameters are the expression and
  4721. //the operator
  4722. void PredicateParser :: GenerateAggregateString(char* lpLeftString, UWORD wOperator, char** lpOutputStr)
  4723. {
  4724. *lpOutputStr = NULL;
  4725. //Check for valid parameters
  4726. if ( !lpLeftString)
  4727. return;
  4728. //Lengths of strings
  4729. ULONG cLeftLen = lstrlen(lpLeftString);
  4730. ULONG cOperatorLen = 0;
  4731. //OK get the operator string
  4732. char* lpOperatorStr = NULL;
  4733. switch (wOperator)
  4734. {
  4735. case AGG_AVG:
  4736. lpOperatorStr = "AVG";
  4737. break;
  4738. case AGG_COUNT:
  4739. lpOperatorStr = "COUNT";
  4740. break;
  4741. case AGG_MAX:
  4742. lpOperatorStr = "MAX";
  4743. break;
  4744. case AGG_MIN:
  4745. lpOperatorStr = "MIN";
  4746. break;
  4747. case AGG_SUM:
  4748. lpOperatorStr = "SUM";
  4749. break;
  4750. default:
  4751. //error
  4752. return;
  4753. break;
  4754. }
  4755. if (lpOperatorStr)
  4756. cOperatorLen = lstrlen (lpOperatorStr);
  4757. //Generate output string in the format
  4758. // operator(left)
  4759. (*lpOutputStr) = new char [cLeftLen + cOperatorLen + 3];
  4760. (*lpOutputStr)[0] = 0;
  4761. sprintf (*lpOutputStr, "%s(%s)", lpOperatorStr, lpLeftString);
  4762. }
  4763. //Generates string for a algebraic expression
  4764. //The input parameters are the left and right values and
  4765. //the algebraic operator
  4766. void PredicateParser :: GenerateAlgebraicString(char* lpLeftString, char* lpRightString, UWORD wOperator, char** lpOutputStr)
  4767. {
  4768. *lpOutputStr = NULL;
  4769. //Check for valid parameters
  4770. if ( !lpLeftString)
  4771. return;
  4772. //Lengths of strings
  4773. ULONG cLeftLen = lstrlen(lpLeftString);
  4774. ULONG cRightLen = lstrlen(lpRightString);
  4775. ULONG cOperatorLen = 0;
  4776. //OK get the operator string
  4777. char* lpOperatorStr = NULL;
  4778. switch (wOperator)
  4779. {
  4780. case OP_PLUS:
  4781. case OP_NONE:
  4782. lpOperatorStr = "+";
  4783. break;
  4784. case OP_MINUS:
  4785. case OP_NEG:
  4786. lpOperatorStr = "-";
  4787. break;
  4788. case OP_TIMES:
  4789. lpOperatorStr = "*";
  4790. break;
  4791. case OP_DIVIDEDBY:
  4792. lpOperatorStr = "/";
  4793. break;
  4794. default:
  4795. //error
  4796. return;
  4797. break;
  4798. }
  4799. if (lpOperatorStr)
  4800. cOperatorLen = lstrlen (lpOperatorStr);
  4801. //Generate output string in the format
  4802. if (wOperator != OP_NEG)
  4803. {
  4804. if (!cRightLen)
  4805. //error
  4806. return;
  4807. // (left operator right)
  4808. (*lpOutputStr) = new char [cLeftLen + cRightLen + cOperatorLen + 5];
  4809. (*lpOutputStr)[0] = 0;
  4810. sprintf (*lpOutputStr, "(%s %s %s)", lpLeftString, lpOperatorStr, lpRightString);
  4811. }
  4812. else
  4813. {
  4814. // (operator left)
  4815. (*lpOutputStr) = new char [cLeftLen + cOperatorLen + 4];
  4816. (*lpOutputStr)[0] = 0;
  4817. sprintf (*lpOutputStr, "(%s %s)", lpOperatorStr, lpLeftString);
  4818. }
  4819. }
  4820. //Generates WHERE predicate string from NODE tree
  4821. void PredicateParser :: GeneratePredicateString(LPSQLNODE lpSqlNode, char ** lpOutputStr, BOOL fIsSQL89)
  4822. {
  4823. *lpOutputStr = NULL;
  4824. char* lpLeftString = NULL;
  4825. char* lpRightString = NULL;
  4826. //Now find out what type of node we have reached
  4827. switch (lpSqlNode->sqlNodeType)
  4828. {
  4829. case NODE_TYPE_BOOLEAN:
  4830. {
  4831. //Get the predicate string for the left node
  4832. GeneratePredicateString(ToNode(*lplpSql,lpSqlNode->node.boolean.Left), &lpLeftString, fIsSQL89);
  4833. //Get the predicate string for the right node, if it exists
  4834. if (lpSqlNode->node.boolean.Right != NO_SQLNODE)
  4835. {
  4836. GeneratePredicateString(ToNode(*lplpSql,lpSqlNode->node.boolean.Right), &lpRightString, fIsSQL89);
  4837. }
  4838. else
  4839. {
  4840. //return a blank dummy string
  4841. char* lpTemp = "<blank>";
  4842. lpRightString = new char [lstrlen(lpTemp) + 1];
  4843. lpRightString[0] = 0;
  4844. lstrcpy(lpRightString, lpTemp);
  4845. }
  4846. //If both the left and the right string are non-NULL generate the
  4847. //boolean string, else just return the string which is non-null
  4848. UWORD wOperator = lpSqlNode->node.boolean.Operator;
  4849. if (lpLeftString && lpRightString)
  4850. {
  4851. //Generate comparison string
  4852. GenerateBooleanString(lpLeftString, lpRightString, wOperator, lpOutputStr);
  4853. //Tidy up
  4854. delete lpLeftString;
  4855. delete lpRightString;
  4856. }
  4857. else
  4858. {
  4859. if (wOperator != OP_OR)
  4860. {
  4861. if (lpLeftString)
  4862. {
  4863. //Must be non-NULL
  4864. (*lpOutputStr) = lpLeftString;
  4865. }
  4866. else
  4867. {
  4868. //Can be non-NULL or NULL
  4869. (*lpOutputStr) = lpRightString;
  4870. }
  4871. }
  4872. else
  4873. {
  4874. (*lpOutputStr) = NULL;
  4875. }
  4876. }
  4877. }
  4878. break;
  4879. case NODE_TYPE_SELECT:
  4880. {
  4881. //Sub-SELECT statement
  4882. char* fullWQL = NULL;
  4883. TableColumnInfo subSelect (lplpSql, &lpSqlNode, WQL_MULTI_TABLE);
  4884. subSelect.BuildFullWQL(&fullWQL);
  4885. *lpOutputStr = fullWQL;
  4886. if (fullWQL)
  4887. {
  4888. int wqlLen = lstrlen(fullWQL);
  4889. char* modStr = new char [2 + wqlLen + 1];
  4890. modStr[0] = 0;
  4891. sprintf (modStr, "(%s)", fullWQL);
  4892. *lpOutputStr = modStr;
  4893. delete fullWQL;
  4894. }
  4895. }
  4896. break;
  4897. case NODE_TYPE_COMPARISON:
  4898. {
  4899. //Get the predicate string for the left node
  4900. GeneratePredicateString(ToNode(*lplpSql,lpSqlNode->node.comparison.Left), &lpLeftString, fIsSQL89);
  4901. //Get the predicate string for the right node
  4902. GeneratePredicateString(ToNode(*lplpSql,lpSqlNode->node.comparison.Right), &lpRightString, fIsSQL89);
  4903. //If both the left and the right string are non-NULL generate the
  4904. //comparison string, else return error
  4905. UWORD wSelectModifier = lpSqlNode->node.comparison.SelectModifier;
  4906. if (lpLeftString && lpRightString)
  4907. {
  4908. //Generate comparison string
  4909. UWORD wOperator = lpSqlNode->node.comparison.Operator;
  4910. //For the ALPHA drop we disable HMM Level 1 optimazation for
  4911. //SQL queries which contain "LIKE" or "NOT LIKE" with wildcards
  4912. BOOL fError = FALSE;
  4913. if (!fSupportLIKEs)
  4914. {
  4915. if ( (wOperator == OP_LIKE) || (wOperator == OP_NOTLIKE) )
  4916. {
  4917. (*lpOutputStr) = NULL;
  4918. fError = TRUE;
  4919. /*
  4920. //Check for wildcards etc ... "%" or "_"
  4921. char* pt = lpRightString;
  4922. long i = 0;
  4923. while (pt[i] && !fError)
  4924. {
  4925. switch (pt[i])
  4926. {
  4927. case '%':
  4928. {
  4929. //Wilcard detected, abort
  4930. (*lpOutputStr) = NULL;
  4931. fError = TRUE;
  4932. }
  4933. break;
  4934. case '_':
  4935. {
  4936. //Check if it has been escaped
  4937. if (i && (pt[i - 1] == '\\'))
  4938. {
  4939. //OK
  4940. }
  4941. else
  4942. {
  4943. (*lpOutputStr) = NULL;
  4944. fError = TRUE;
  4945. }
  4946. }
  4947. break;
  4948. default:
  4949. break;
  4950. }
  4951. i++;
  4952. }
  4953. */
  4954. }
  4955. }
  4956. if (!fError)
  4957. GenerateComparisonString(lpLeftString, lpRightString, wOperator, wSelectModifier, lpOutputStr);
  4958. }
  4959. else
  4960. {
  4961. //Check for sub select
  4962. if ( lpLeftString && (wSelectModifier == SELECT_EXISTS) )
  4963. {
  4964. fError = FALSE;
  4965. int selectLen = lstrlen (lpLeftString);
  4966. (*lpOutputStr) = new char [7 + selectLen + 1];
  4967. (*lpOutputStr)[0] = 0;
  4968. sprintf (*lpOutputStr, "EXISTS %s", lpLeftString);
  4969. }
  4970. else
  4971. {
  4972. //error
  4973. (*lpOutputStr) = NULL;
  4974. }
  4975. }
  4976. //Tidy up
  4977. delete lpLeftString;
  4978. delete lpRightString;
  4979. }
  4980. break;
  4981. case NODE_TYPE_SCALAR:
  4982. {
  4983. //WQL does not support scalar functions
  4984. char* myString = ",SomeScalarFunctionThatWQLDoesNotSupport";
  4985. ULONG len = lstrlen(myString);
  4986. (*lpOutputStr) = new char [len + 1];
  4987. (*lpOutputStr)[0] = 0;
  4988. lstrcpy(*lpOutputStr, myString);
  4989. }
  4990. break;
  4991. case NODE_TYPE_AGGREGATE:
  4992. {
  4993. //Get the predicate string for the expression node
  4994. GeneratePredicateString(ToNode(*lplpSql,lpSqlNode->node.aggregate.Expression), &lpLeftString, fIsSQL89);
  4995. //If the left string is non-NULL generate the
  4996. //aggregate string, else return error
  4997. if (lpLeftString)
  4998. {
  4999. //Generate aggregate string
  5000. UWORD wOperator = lpSqlNode->node.aggregate.Operator;
  5001. GenerateAggregateString(lpLeftString, wOperator, lpOutputStr);
  5002. }
  5003. else
  5004. {
  5005. //error
  5006. (*lpOutputStr) = NULL;
  5007. }
  5008. //Tidy up
  5009. delete lpLeftString;
  5010. }
  5011. break;
  5012. case NODE_TYPE_ALGEBRAIC:
  5013. {
  5014. //Get the predicate string for the left node
  5015. GeneratePredicateString(ToNode(*lplpSql,lpSqlNode->node.algebraic.Left), &lpLeftString, fIsSQL89);
  5016. //Get the predicate string for the right node
  5017. if (lpSqlNode->node.algebraic.Right != NO_SQLNODE)
  5018. GeneratePredicateString(ToNode(*lplpSql,lpSqlNode->node.algebraic.Right), &lpRightString, fIsSQL89);
  5019. else
  5020. lpRightString = NULL;
  5021. //If the left string is non-NULL generate the
  5022. //comparison string, else return error
  5023. if (lpLeftString)
  5024. {
  5025. //Generate algebraic string
  5026. UWORD wOperator = lpSqlNode->node.algebraic.Operator;
  5027. GenerateAlgebraicString(lpLeftString, lpRightString, wOperator, lpOutputStr);
  5028. }
  5029. else
  5030. {
  5031. //error
  5032. (*lpOutputStr) = NULL;
  5033. }
  5034. //Tidy up
  5035. delete lpLeftString;
  5036. delete lpRightString;
  5037. }
  5038. break;
  5039. case NODE_TYPE_COLUMN:
  5040. {
  5041. //Return a copy of the column name
  5042. char* lpTemp = (LPSTR) ToString(*lplpSql, lpSqlNode->node.column.Column);
  5043. char* lpAlias = NULL;
  5044. SQLNODEIDX idxTblAlias = lpSqlNode->node.column.Tablealias;
  5045. if (idxTblAlias != NO_STRING)
  5046. {
  5047. lpAlias = (LPSTR) ToString(*lplpSql, idxTblAlias);
  5048. }
  5049. //Sai new
  5050. SQLNODEIDX idxTbl = lpSqlNode->node.column.Table;
  5051. LPSQLNODE myTableNode = ToNode(*lplpSql,idxTbl);
  5052. LPISAMTABLEDEF lpTDef = NULL;
  5053. if (idxTbl != NO_SQLNODE)
  5054. lpTDef = myTableNode->node.table.Handle;
  5055. //Sai Wong Here
  5056. // if (lpISAMTableDef == lpSqlNode->node.table.Handle)
  5057. if ((!lpISAMTableDef) || (lpISAMTableDef == lpTDef))
  5058. {
  5059. ULONG len = lstrlen(lpTemp);
  5060. if (lpAlias && !fIsSQL89)
  5061. {
  5062. len += lstrlen(lpAlias) + 1;
  5063. }
  5064. (*lpOutputStr) = new char [len + 1];
  5065. (*lpOutputStr)[0] = 0;
  5066. if (lpAlias && !fIsSQL89)
  5067. {
  5068. sprintf(*lpOutputStr, "%s.%s",lpAlias, lpTemp);
  5069. }
  5070. else
  5071. {
  5072. lstrcpy(*lpOutputStr, lpTemp);
  5073. }
  5074. }
  5075. else
  5076. {
  5077. //no match with desired table so return NULL
  5078. (*lpOutputStr) = NULL;
  5079. }
  5080. }
  5081. break;
  5082. case NODE_TYPE_STRING:
  5083. {
  5084. //Return a copy of the String in the format shown below
  5085. // 'string'
  5086. char* lpTemp = (LPSTR)ToString(*lplpSql, lpSqlNode->node.string.Value);
  5087. (*lpOutputStr) = new char [lstrlen(lpTemp) + 3];
  5088. (*lpOutputStr)[0] = 0;
  5089. sprintf (*lpOutputStr, "'%s'", lpTemp);
  5090. }
  5091. break;
  5092. case NODE_TYPE_TIMESTAMP:
  5093. {
  5094. //Return a copy of the Timestamp in UTC format shown below
  5095. // 'yyyymmddhhmmss.000000+000'
  5096. TIMESTAMP_STRUCT lpTimestamp = lpSqlNode->node.timestamp.Value;
  5097. (*lpOutputStr) = new char [DATETIME_FORMAT_LEN + 4 + 1 + 2];
  5098. (*lpOutputStr)[0] = 0;
  5099. sprintf (*lpOutputStr, "'%04d%02u%02u%02u%02u%02u.%06d+000'",
  5100. lpTimestamp.year, lpTimestamp.month, lpTimestamp.day,
  5101. lpTimestamp.hour, lpTimestamp.minute, lpTimestamp.second,
  5102. lpTimestamp.fraction);
  5103. }
  5104. break;
  5105. case NODE_TYPE_VALUES:
  5106. {
  5107. SQLNODEIDX idxValue = lpSqlNode->node.values.Value;
  5108. SQLNODEIDX idxValues = lpSqlNode->node.values.Next;
  5109. LPSQLNODE lpSqlNextNode;
  5110. ULONG cLenLeft = 0;
  5111. ULONG cLenOutput = 0;
  5112. ULONG cLenBuff = 0;
  5113. *lpOutputStr = NULL;
  5114. BOOL firstTime = TRUE;
  5115. BOOL fEndOfList = FALSE;
  5116. char* buff = NULL;
  5117. do
  5118. {
  5119. //Get next value in valuelist
  5120. GeneratePredicateString(ToNode(*lplpSql,idxValue), &lpLeftString, fIsSQL89);
  5121. //Add to list
  5122. cLenOutput = (*lpOutputStr) ? lstrlen (*lpOutputStr) : 0;
  5123. cLenLeft = lpLeftString ? lstrlen (lpLeftString) : 0;
  5124. cLenBuff = cLenOutput + cLenLeft;
  5125. //Check for errors
  5126. if (cLenLeft == 0)
  5127. {
  5128. //error
  5129. delete (*lpOutputStr);
  5130. *lpOutputStr = NULL;
  5131. return;
  5132. }
  5133. buff = new char [cLenBuff + 2];
  5134. buff[0] = 0;
  5135. if (firstTime)
  5136. {
  5137. sprintf (buff, "(%s", lpLeftString);
  5138. }
  5139. else
  5140. {
  5141. sprintf (buff, "%s,%s", *lpOutputStr, lpLeftString);
  5142. }
  5143. //Update output string and tidy up
  5144. delete (*lpOutputStr);
  5145. delete lpLeftString;
  5146. *lpOutputStr = buff;
  5147. //Increment for next loop
  5148. if (idxValues != NO_SQLNODE)
  5149. {
  5150. lpSqlNextNode = ToNode(*lplpSql,idxValues);
  5151. idxValue = lpSqlNextNode->node.values.Value;
  5152. idxValues = lpSqlNextNode->node.values.Next;
  5153. }
  5154. else
  5155. {
  5156. fEndOfList = TRUE;
  5157. }
  5158. firstTime = FALSE;
  5159. }
  5160. while (!fEndOfList);
  5161. //Now add closing bracket
  5162. cLenOutput = lstrlen (*lpOutputStr);
  5163. buff = new char [cLenOutput + 2];
  5164. buff[0] = 0;
  5165. sprintf(buff, "%s)", *lpOutputStr);
  5166. delete (*lpOutputStr);
  5167. *lpOutputStr = buff;
  5168. }
  5169. break;
  5170. case NODE_TYPE_NUMERIC:
  5171. {
  5172. //Return a copy of the number (as a string)
  5173. char* lpTemp = (LPSTR) ToString(*lplpSql, lpSqlNode->node.numeric.Numeric);
  5174. (*lpOutputStr) = new char [lstrlen(lpTemp) + 1];
  5175. (*lpOutputStr)[0] = 0;
  5176. lstrcpy(*lpOutputStr, lpTemp);
  5177. }
  5178. break;
  5179. case NODE_TYPE_PARAMETER:
  5180. break;
  5181. case NODE_TYPE_USER:
  5182. {
  5183. char* lpTemp = "USER";
  5184. (*lpOutputStr) = new char [lstrlen(lpTemp) + 1];
  5185. (*lpOutputStr)[0] = 0;
  5186. lstrcpy(*lpOutputStr, lpTemp);
  5187. }
  5188. break;
  5189. case NODE_TYPE_NULL:
  5190. {
  5191. char* lpTemp = "NULL";
  5192. (*lpOutputStr) = new char [lstrlen(lpTemp) + 1];
  5193. (*lpOutputStr)[0] = 0;
  5194. lstrcpy(*lpOutputStr, lpTemp);
  5195. }
  5196. break;
  5197. default:
  5198. {
  5199. //Error, could not recognize node
  5200. fError = TRUE;
  5201. *lpOutputStr = NULL;
  5202. }
  5203. break;
  5204. }
  5205. //If an error occured return a NULL output string
  5206. if (fError)
  5207. {
  5208. if (*lpOutputStr)
  5209. delete (*lpOutputStr);
  5210. (*lpOutputStr) = NULL;
  5211. }
  5212. }
  5213. //Generates ORDER BY string from NODE tree
  5214. void PredicateParser :: GenerateOrderByString(LPSQLNODE lpSqlNode, char ** lpOutputStr, BOOL fIsSQL89)
  5215. {
  5216. BOOL fContinue = TRUE;
  5217. BOOL fFirst = TRUE;
  5218. LPSQLNODE newNode = NULL;
  5219. while (fContinue)
  5220. {
  5221. char* columnRef = NULL;
  5222. LPSQLNODE myNode = ToNode(*lplpSql,lpSqlNode->node.sortcolumns.Column);
  5223. BOOL fDescending = lpSqlNode->node.sortcolumns.Descending;
  5224. ULONG len3 = 0;
  5225. char* sortOrder = "";
  5226. if (fDescending)
  5227. {
  5228. sortOrder = " DESC";
  5229. len3 = lstrlen(sortOrder);
  5230. }
  5231. GenerateColumnRef(myNode, &columnRef, fIsSQL89);
  5232. if (columnRef)
  5233. {
  5234. ULONG len1 = s_lstrlen(*lpOutputStr);
  5235. if (!fFirst)
  5236. {
  5237. //add a comma separator and column ref
  5238. ULONG len2 = s_lstrlen(columnRef) + 1;
  5239. char* buffer = new char [len1 + len2 + len3 + 1];
  5240. buffer[0] = 0;
  5241. //Add new column to end of list
  5242. if (len3)
  5243. sprintf (buffer, "%s,%s%s", *lpOutputStr, columnRef, sortOrder);
  5244. else
  5245. sprintf (buffer, "%s,%s", *lpOutputStr, columnRef);
  5246. delete (*lpOutputStr);
  5247. delete columnRef;
  5248. *lpOutputStr = buffer;
  5249. }
  5250. else
  5251. {
  5252. //add column ref
  5253. if (len3)
  5254. {
  5255. ULONG len2 = s_lstrlen(columnRef);
  5256. char* buffer = new char [len2 + len3 + 1];
  5257. buffer[0] = 0;
  5258. sprintf (buffer, "%s%s", columnRef, sortOrder);
  5259. delete columnRef;
  5260. *lpOutputStr = buffer;
  5261. }
  5262. else
  5263. {
  5264. *lpOutputStr = columnRef;
  5265. }
  5266. }
  5267. fFirst = FALSE;
  5268. }
  5269. //Check next node
  5270. if (lpSqlNode->node.sortcolumns.Next != NO_SQLNODE)
  5271. {
  5272. newNode = ToNode(*lplpSql,lpSqlNode->node.sortcolumns.Next);
  5273. lpSqlNode = newNode;
  5274. }
  5275. else
  5276. {
  5277. fContinue = FALSE;
  5278. }
  5279. }
  5280. }
  5281. //Generates GROUP BY string from NODE tree
  5282. void PredicateParser :: GenerateGroupByString(LPSQLNODE lpSqlNode, char ** lpOutputStr, BOOL fIsSQL89)
  5283. {
  5284. BOOL fContinue = TRUE;
  5285. BOOL fFirst = TRUE;
  5286. LPSQLNODE newNode = NULL;
  5287. while (fContinue)
  5288. {
  5289. char* columnRef = NULL;
  5290. LPSQLNODE myNode = ToNode(*lplpSql,lpSqlNode->node.groupbycolumns.Column);
  5291. GenerateColumnRef(myNode, &columnRef, fIsSQL89);
  5292. if (columnRef)
  5293. {
  5294. ULONG len1 = s_lstrlen(*lpOutputStr);
  5295. if (!fFirst)
  5296. {
  5297. //add a comma separator and column ref
  5298. ULONG len2 = s_lstrlen(columnRef) + 1;
  5299. char* buffer = new char [len1 + len2 + 1];
  5300. buffer[0] = 0;
  5301. //Add new column to head of list
  5302. sprintf (buffer, "%s,%s", columnRef, *lpOutputStr);
  5303. delete (*lpOutputStr);
  5304. delete columnRef;
  5305. *lpOutputStr = buffer;
  5306. }
  5307. else
  5308. {
  5309. //add column ref
  5310. *lpOutputStr = columnRef;
  5311. }
  5312. fFirst = FALSE;
  5313. }
  5314. //Check next node
  5315. if (lpSqlNode->node.groupbycolumns.Next != NO_SQLNODE)
  5316. {
  5317. newNode = ToNode(*lplpSql,lpSqlNode->node.groupbycolumns.Next);
  5318. lpSqlNode = newNode;
  5319. }
  5320. else
  5321. {
  5322. fContinue = FALSE;
  5323. }
  5324. }
  5325. }
  5326. void PredicateParser :: GenerateColumnRef(LPSQLNODE lpSqlNode, char ** lpOutputStr, BOOL fIsSQL89)
  5327. {
  5328. *lpOutputStr = NULL;
  5329. //Now find out what type of node we have reached
  5330. switch (lpSqlNode->sqlNodeType)
  5331. {
  5332. case NODE_TYPE_COLUMN:
  5333. {
  5334. //Return a copy of the column name
  5335. char* lpTemp = (LPSTR) ToString(*lplpSql, lpSqlNode->node.column.Column);
  5336. char* lpAlias = NULL;
  5337. SQLNODEIDX idxTblAlias = lpSqlNode->node.column.Tablealias;
  5338. if (idxTblAlias != NO_STRING)
  5339. {
  5340. lpAlias = (LPSTR) ToString(*lplpSql, idxTblAlias);
  5341. }
  5342. ULONG len = lstrlen(lpTemp);
  5343. if (lpAlias && !fIsSQL89)
  5344. {
  5345. len += lstrlen(lpAlias) + 1;
  5346. }
  5347. (*lpOutputStr) = new char [len + 1];
  5348. (*lpOutputStr)[0] = 0;
  5349. if (lpAlias && !fIsSQL89)
  5350. {
  5351. sprintf(*lpOutputStr, "%s.%s",lpAlias, lpTemp);
  5352. }
  5353. else
  5354. {
  5355. lstrcpy(*lpOutputStr, lpTemp);
  5356. }
  5357. }
  5358. break;
  5359. case NODE_TYPE_NUMERIC:
  5360. {
  5361. SQLNODEIDX numIdx = lpSqlNode->node.numeric.Numeric;
  5362. char* lpTemp = NULL;
  5363. if (numIdx != NO_STRING)
  5364. {
  5365. lpTemp = (LPSTR) ToString(*lplpSql, numIdx);
  5366. ULONG len = lstrlen(lpTemp);
  5367. (*lpOutputStr) = new char [len + 1];
  5368. (*lpOutputStr)[0] = 0;
  5369. lstrcpy(*lpOutputStr, lpTemp);
  5370. }
  5371. };
  5372. break;
  5373. default:
  5374. break;
  5375. }
  5376. }
  5377. //constructor for class to store column/table info for a SQL statement
  5378. TableColumnInfo :: TableColumnInfo(LPSQLTREE FAR *lplpTheSql, LPSQLTREE FAR * lpSqlN, ULONG mode)
  5379. {
  5380. //Initialize
  5381. lplpSql = lplpTheSql;
  5382. lplpSqlNode = lpSqlN;
  5383. lpList = NULL;
  5384. fIsValid = TRUE;
  5385. theMode = mode;
  5386. idxTableQualifer = NO_STRING;
  5387. fHasScalarFunction = FALSE;
  5388. m_aggregateExists = FALSE;
  5389. fDistinct = FALSE;
  5390. //Create the table/column list from SQL statement
  5391. //Check if it is SELECT * FROM ....
  5392. fIsSelectStar = ( (*lplpSqlNode)->node.select.Values == NO_SQLNODE ) ? TRUE : FALSE;
  5393. //Can't support SQL passthrough for SELECT * as the parse tree
  5394. //does not contain any column names
  5395. //[Please use SELECT <list of columns>]
  5396. if ( (*lplpSqlNode)->node.select.Values == NO_SQLNODE)
  5397. {
  5398. fIsValid = FALSE;
  5399. return;
  5400. }
  5401. //Look in the following sub-trees
  5402. //(1) select-list
  5403. LPSQLNODE lpSearchNode;
  5404. if (!fIsSelectStar)
  5405. {
  5406. lpSearchNode = ToNode(*lplpSql, (*lplpSqlNode)->node.select.Values);
  5407. Analize(lpSearchNode);
  5408. }
  5409. //(1b) SQL-92 ON predicate
  5410. {
  5411. SQLNODEIDX idxTheTables = (*lplpSqlNode)->node.select.Tables;
  5412. LPSQLNODE tableNode = ToNode(*lplpSql,idxTheTables);
  5413. BOOL fContinue = TRUE;
  5414. while (fContinue)
  5415. {
  5416. SQLNODEIDX tableIdx = tableNode->node.tables.Table;
  5417. LPSQLNODE singleTable = ToNode(*lplpSql,tableIdx);
  5418. SQLNODEIDX predicateidx = singleTable->node.table.OuterJoinPredicate;
  5419. if (predicateidx != NO_SQLNODE)
  5420. {
  5421. LPSQLNODE predicateNode = ToNode(*lplpSql,predicateidx);
  5422. Analize(predicateNode);
  5423. }
  5424. if (tableNode->node.tables.Next == NO_STRING)
  5425. {
  5426. fContinue = FALSE;
  5427. }
  5428. else
  5429. {
  5430. tableNode = ToNode(*lplpSql,tableNode->node.tables.Next);
  5431. }
  5432. }
  5433. }
  5434. //Check if DISTINCT
  5435. fDistinct = (*lplpSqlNode)->node.select.Distinct;
  5436. //For multi table passthrough, return now
  5437. if (mode == WQL_MULTI_TABLE)
  5438. {
  5439. return;
  5440. }
  5441. //(2) WHERE
  5442. if ( (*lplpSqlNode)->node.select.Predicate != NO_SQLNODE)
  5443. {
  5444. lpSearchNode = ToNode(*lplpSql, (*lplpSqlNode)->node.select.Predicate);
  5445. Analize(lpSearchNode);
  5446. }
  5447. //(3) GROUP BY
  5448. BOOL fGroupbyDefined = FALSE;
  5449. if ( (*lplpSqlNode)->node.select.Groupbycolumns != NO_SQLNODE)
  5450. {
  5451. lpSearchNode = ToNode(*lplpSql, (*lplpSqlNode)->node.select.Groupbycolumns);
  5452. Analize(lpSearchNode);
  5453. //as our implementation of GROUP BY requires that all the columns
  5454. //be specified they is no need to imvestigate the ORDER BY node.
  5455. //Also if no SORT BY columns are defined the node is set to an undefined value anyway
  5456. fGroupbyDefined = TRUE;
  5457. }
  5458. //(4) HAVING
  5459. if ( (*lplpSqlNode)->node.select.Having != NO_SQLNODE)
  5460. {
  5461. lpSearchNode = ToNode(*lplpSql, (*lplpSqlNode)->node.select.Having);
  5462. Analize(lpSearchNode);
  5463. }
  5464. //(5) ORDER BY
  5465. if ( (!fGroupbyDefined) && (*lplpSqlNode)->node.select.Sortcolumns != NO_SQLNODE)
  5466. {
  5467. lpSearchNode = ToNode(*lplpSql, (*lplpSqlNode)->node.select.Sortcolumns);
  5468. Analize(lpSearchNode);
  5469. }
  5470. }
  5471. //Analizes parse tree and generates TableColumn list
  5472. void TableColumnInfo :: Analize(LPSQLNODE lpSqlNode)
  5473. {
  5474. //Now find out what type of node we have reached
  5475. switch (lpSqlNode->sqlNodeType)
  5476. {
  5477. case NODE_TYPE_BOOLEAN:
  5478. {
  5479. //Analize the left node
  5480. Analize(ToNode(*lplpSql,lpSqlNode->node.boolean.Left));
  5481. //Analize the right node, if it exists
  5482. if (lpSqlNode->node.boolean.Right != NO_SQLNODE)
  5483. {
  5484. Analize(ToNode(*lplpSql,lpSqlNode->node.boolean.Right));
  5485. }
  5486. }
  5487. break;
  5488. case NODE_TYPE_COMPARISON:
  5489. {
  5490. //Analize the left node
  5491. Analize(ToNode(*lplpSql,lpSqlNode->node.comparison.Left));
  5492. //Analize the right node
  5493. Analize(ToNode(*lplpSql,lpSqlNode->node.comparison.Right));
  5494. }
  5495. break;
  5496. case NODE_TYPE_VALUES:
  5497. {
  5498. //Analize the value node
  5499. Analize(ToNode(*lplpSql,lpSqlNode->node.values.Value));
  5500. //Analize the next node
  5501. if (lpSqlNode->node.values.Next != NO_SQLNODE)
  5502. {
  5503. Analize(ToNode(*lplpSql,lpSqlNode->node.values.Next));
  5504. }
  5505. }
  5506. break;
  5507. case NODE_TYPE_AGGREGATE:
  5508. {
  5509. //Analize the left node
  5510. Analize(ToNode(*lplpSql,lpSqlNode->node.aggregate.Expression));
  5511. m_aggregateExists = TRUE;
  5512. }
  5513. break;
  5514. case NODE_TYPE_ALGEBRAIC:
  5515. {
  5516. //Analize the left node
  5517. Analize(ToNode(*lplpSql,lpSqlNode->node.algebraic.Left));
  5518. //Analize the right node
  5519. if (lpSqlNode->node.algebraic.Right != NO_SQLNODE)
  5520. Analize(ToNode(*lplpSql,lpSqlNode->node.algebraic.Right));
  5521. }
  5522. break;
  5523. case NODE_TYPE_SCALAR:
  5524. {
  5525. //WQL cannot support scalar functions so we must
  5526. //flag this special case
  5527. fHasScalarFunction = TRUE;
  5528. //Analize the value list
  5529. Analize(ToNode(*lplpSql,lpSqlNode->node.scalar.Arguments));
  5530. }
  5531. break;
  5532. case NODE_TYPE_SORTCOLUMNS:
  5533. {
  5534. LPSQLNODE myNode = lpSqlNode;
  5535. SQLNODEIDX orderbyidx = myNode->node.sortcolumns.Column;
  5536. while (orderbyidx != NO_SQLNODE)
  5537. {
  5538. //Analize the first column
  5539. Analize(ToNode(*lplpSql,orderbyidx));
  5540. SQLNODEIDX next_idx = myNode->node.sortcolumns.Next;
  5541. if (next_idx != NO_SQLNODE)
  5542. {
  5543. //update to point to next sortcolumn node
  5544. myNode = ToNode(*lplpSql, next_idx);
  5545. orderbyidx = myNode->node.sortcolumns.Column;
  5546. }
  5547. else
  5548. {
  5549. orderbyidx = NO_SQLNODE;
  5550. }
  5551. }
  5552. }
  5553. break;
  5554. case NODE_TYPE_COLUMN:
  5555. {
  5556. //Generate a node for the Column/Table list
  5557. SQLNODEIDX idxCol = lpSqlNode->node.column.Column;
  5558. SQLNODEIDX idxTblAlias = lpSqlNode->node.column.Tablealias;
  5559. SQLNODEIDX idxTbl = lpSqlNode->node.column.Table;
  5560. LPSQLNODE myTableNode = ToNode(*lplpSql,idxTbl);
  5561. //SAI
  5562. LPISAMTABLEDEF lpTDef = NULL;
  5563. if (idxTbl != NO_SQLNODE)
  5564. lpTDef = myTableNode->node.table.Handle;
  5565. //First check if it already exists in list
  5566. BOOL found = FALSE;
  5567. TableColumnList* ptr = lpList;
  5568. while (!found && ptr)
  5569. {
  5570. //Get column names
  5571. char* lpTemp1 = (LPSTR) ToString(*lplpSql, idxCol);
  5572. char* lpTemp2 = (LPSTR) ToString(*lplpSql, ptr->idxColumnName);
  5573. if ( (strcmp(lpTemp1, lpTemp2) == 0) && (lpTDef == ptr->lpISAMTableDef) )
  5574. {
  5575. //This could potentially be a match
  5576. if (lpTDef)
  5577. {
  5578. found = TRUE;
  5579. }
  5580. else
  5581. {
  5582. //Multi-table passthrough SQL checks
  5583. //Check Table aliases
  5584. if ( (idxTblAlias != NO_STRING) && (ptr->idxTableAlias != NO_STRING))
  5585. {
  5586. char* lpAlias1 = (LPSTR) ToString(*lplpSql, idxTblAlias);
  5587. char* lpAlias2 = (LPSTR) ToString(*lplpSql, ptr->idxTableAlias);
  5588. if (_stricmp(lpAlias1, lpAlias2) == 0)
  5589. {
  5590. found = TRUE;
  5591. }
  5592. }
  5593. }
  5594. }
  5595. ptr = ptr->Next;
  5596. }
  5597. if (found)
  5598. return;
  5599. //Not in existing list, so add
  5600. TableColumnList* newNode = new TableColumnList(idxCol, idxTblAlias, lpTDef);
  5601. //Append new node to HEAD of existing list, if it exists
  5602. if (lpList)
  5603. {
  5604. //List already exists
  5605. newNode->Next = lpList;
  5606. lpList = newNode;
  5607. }
  5608. else
  5609. {
  5610. //List does not exist, so new node becomes list
  5611. lpList = newNode;
  5612. }
  5613. }
  5614. break;
  5615. case NODE_TYPE_STRING:
  5616. case NODE_TYPE_NUMERIC:
  5617. case NODE_TYPE_PARAMETER:
  5618. case NODE_TYPE_USER:
  5619. case NODE_TYPE_NULL:
  5620. default:
  5621. break;
  5622. }
  5623. }
  5624. void TableColumnInfo :: BuildFullWQL(char** lpWQLStr, CMapWordToPtr** ppPassthroughMap)
  5625. {
  5626. //SELECT
  5627. StringConcat(lpWQLStr, "SELECT ");
  5628. //Get the table list first to find out if we are
  5629. //SQL-89 or SQL-92
  5630. char* tableList = NULL;
  5631. BOOL fIsSQL89 = TRUE;
  5632. BuildTableList(&tableList, fIsSQL89);
  5633. //Looking for distinct entries ?
  5634. if (IsDistinct())
  5635. {
  5636. StringConcat(lpWQLStr, " DISTINCT ");
  5637. }
  5638. /*
  5639. //Don't do this as we cannot support SELECT * for SQL passthrough
  5640. //[as the parse tree does not know the column names]
  5641. // and we will have problems with the virtual table mapping if
  5642. //the table has array data types
  5643. //this will cause the SQL passthrough query to fail
  5644. //and we will go the non-passthrough route ...
  5645. //Check if this is SELECT * FROM ...
  5646. if (IsSelectStar())
  5647. {
  5648. StringConcat(lpWQLStr, " * ");
  5649. }
  5650. */
  5651. //Get the select list
  5652. char* selectList = NULL;
  5653. BuildSelectList(NULL, &selectList, fIsSQL89, ppPassthroughMap);
  5654. StringConcat(lpWQLStr, selectList);
  5655. delete selectList;
  5656. //Check for any scalar functions
  5657. if ( HasScalarFunction() )
  5658. {
  5659. StringConcat(lpWQLStr, ",SomeScalarFunctionThatWQLDoesNotSupport");
  5660. }
  5661. //FROM
  5662. StringConcat(lpWQLStr, " FROM ");
  5663. //Get table list (with LEFT OUTER JOIN and ON predicate)
  5664. // char* tableList = NULL;
  5665. // BOOL fIsSQL89 = TRUE;
  5666. // BuildTableList(&tableList, fIsSQL89);
  5667. StringConcat(lpWQLStr, tableList);
  5668. delete tableList;
  5669. //Get WHERE predicate
  5670. SQLNODEIDX whereidx = (*lplpSqlNode)->node.select.Predicate;
  5671. PredicateParser theParser (lplpSql, NULL);
  5672. if (whereidx != NO_SQLNODE)
  5673. {
  5674. LPSQLNODE lpPredicateNode = ToNode(*lplpSql, whereidx);
  5675. char* wherePredicate = NULL;
  5676. theParser.GeneratePredicateString(lpPredicateNode, &wherePredicate, fIsSQL89);
  5677. if (wherePredicate)
  5678. {
  5679. StringConcat(lpWQLStr, " WHERE ");
  5680. StringConcat(lpWQLStr, wherePredicate);
  5681. delete wherePredicate;
  5682. }
  5683. }
  5684. //Get GROUP BY
  5685. SQLNODEIDX groupbyidx = (*lplpSqlNode)->node.select.Groupbycolumns;
  5686. if (groupbyidx != NO_SQLNODE)
  5687. {
  5688. LPSQLNODE groupbyNode = ToNode(*lplpSql, groupbyidx);
  5689. char* groupByStr = NULL;
  5690. theParser.GenerateGroupByString(groupbyNode, &groupByStr, fIsSQL89);
  5691. if (groupByStr)
  5692. {
  5693. StringConcat(lpWQLStr, " GROUP BY ");
  5694. StringConcat(lpWQLStr, groupByStr);
  5695. delete groupByStr;
  5696. }
  5697. }
  5698. //Get HAVING
  5699. SQLNODEIDX havingidx = (*lplpSqlNode)->node.select.Having;
  5700. if (havingidx != NO_SQLNODE)
  5701. {
  5702. LPSQLNODE lpPredicateNode = ToNode(*lplpSql, havingidx);
  5703. char* HavingPredicate = NULL;
  5704. theParser.GeneratePredicateString(lpPredicateNode, &HavingPredicate, fIsSQL89);
  5705. if (HavingPredicate)
  5706. {
  5707. StringConcat(lpWQLStr, " HAVING ");
  5708. StringConcat(lpWQLStr, HavingPredicate);
  5709. delete HavingPredicate;
  5710. }
  5711. }
  5712. //Get ORDER BY
  5713. SQLNODEIDX orderbyidx = (*lplpSqlNode)->node.select.Sortcolumns;
  5714. if (orderbyidx != NO_SQLNODE)
  5715. {
  5716. LPSQLNODE orderbyNode = ToNode(*lplpSql, orderbyidx);
  5717. char* orderByStr = NULL;
  5718. theParser.GenerateOrderByString(orderbyNode, &orderByStr, fIsSQL89);
  5719. if (orderByStr)
  5720. {
  5721. StringConcat(lpWQLStr, " ORDER BY ");
  5722. StringConcat(lpWQLStr, orderByStr);
  5723. delete orderByStr;
  5724. }
  5725. }
  5726. }
  5727. void TableColumnInfo :: StringConcat(char** resultString, char* myStr)
  5728. {
  5729. if (myStr)
  5730. {
  5731. ULONG len = s_lstrlen(myStr);
  5732. ULONG oldLen = 0;
  5733. if (resultString && *resultString)
  5734. oldLen = s_lstrlen(*resultString);
  5735. char* buffer = new char [oldLen + len + 1];
  5736. buffer[0] = 0;
  5737. if (oldLen)
  5738. {
  5739. sprintf (buffer, "%s%s", *resultString, myStr);
  5740. }
  5741. else
  5742. {
  5743. s_lstrcpy(buffer, myStr);
  5744. }
  5745. //delete old string
  5746. if (resultString && *resultString)
  5747. delete (*resultString);
  5748. //replace with new string
  5749. *resultString = buffer;
  5750. }
  5751. }
  5752. //Info related to nodes of LEFT OUTER JOIN statement
  5753. class JoinInfo
  5754. {
  5755. public:
  5756. _bstr_t tableName;
  5757. _bstr_t tableAlias;
  5758. _bstr_t predicate;
  5759. JoinInfo() {;}
  5760. ~JoinInfo() {;}
  5761. };
  5762. void TableColumnInfo :: BuildTableList(char** tableList, BOOL &fIsSQL89, SQLNODEIDX idx)
  5763. {
  5764. //We will build 2 different table lists in the
  5765. //SQL-89 and SQL-92 formats.
  5766. //We will discard the SQL-89 format if we find either
  5767. //(i) SQL-92 JOINS
  5768. //(ii) Multiple tables
  5769. //(iii) Sub-SELECTs
  5770. //tableList will start with the SQL-89 string
  5771. BOOL fFirst = TRUE;
  5772. BOOL noJoinTables = TRUE;
  5773. fIsSQL89 = TRUE;
  5774. SQLNODEIDX idxTables = 1;
  5775. //Constrcut maps for Table/Alias and predicates
  5776. CMapWordToPtr* tableAliasMap = new CMapWordToPtr(); //1 based map
  5777. WORD tableAliasCount = 0;
  5778. CMapWordToPtr* predicateMap = new CMapWordToPtr(); //1 based map
  5779. WORD predicateCount = 0;
  5780. char* lpSQL92 = NULL;
  5781. LPSQLNODE tableNode;
  5782. if (idx == NO_SQLNODE)
  5783. {
  5784. SQLNODEIDX idxTheTables = (*lplpSqlNode)->node.select.Tables;
  5785. tableNode = ToNode(*lplpSql,idxTheTables);
  5786. }
  5787. else
  5788. {
  5789. tableNode = ToNode(*lplpSql,idx);
  5790. }
  5791. BOOL fContinue = TRUE;
  5792. while (fContinue)
  5793. {
  5794. SQLNODEIDX tableIdx = tableNode->node.tables.Table;
  5795. LPSQLNODE singleTable = ToNode(*lplpSql,tableIdx);
  5796. char* aliasStr = NULL;
  5797. if (singleTable->node.table.Alias != NO_STRING)
  5798. {
  5799. aliasStr = (LPSTR) ToString(*lplpSql, singleTable->node.table.Alias); //e.g. t1
  5800. }
  5801. char* tableStr = NULL;
  5802. if (singleTable->node.table.Name != NO_STRING)
  5803. {
  5804. tableStr = (LPSTR) ToString(*lplpSql, singleTable->node.table.Name); //e.g. Table1
  5805. }
  5806. //This is when we add multi-namespace queries
  5807. if (idxTableQualifer == NO_STRING)
  5808. idxTableQualifer = singleTable->node.table.Qualifier;
  5809. //Check for outer join
  5810. SQLNODEIDX joinidx = singleTable->node.table.OuterJoinFromTables; //NODE_TYPE_TABLES
  5811. if (joinidx != NO_SQLNODE)
  5812. {
  5813. // StringConcat(&lpSQL92, " LEFT OUTER JOIN ");
  5814. noJoinTables = FALSE;
  5815. fIsSQL89 = FALSE;
  5816. }
  5817. //Add <table> <alias>
  5818. if (idx == NO_SQLNODE)
  5819. {
  5820. //Add info to tableAliasMap
  5821. JoinInfo* myTableAlias = new JoinInfo();
  5822. if (tableStr)
  5823. {
  5824. // if (fIsSQL89)
  5825. // StringConcat(tableList, tableStr);
  5826. // StringConcat(&lpSQL92, tableStr);
  5827. myTableAlias->tableName = tableStr;
  5828. }
  5829. if (aliasStr)
  5830. {
  5831. // StringConcat(&lpSQL92, " ");
  5832. // StringConcat(&lpSQL92, aliasStr);
  5833. // StringConcat(&lpSQL92, " ");
  5834. myTableAlias->tableAlias = aliasStr;
  5835. }
  5836. //Add to map
  5837. tableAliasMap->SetAt(++tableAliasCount, (void*)myTableAlias);
  5838. }
  5839. SQLNODEIDX predicateidx = singleTable->node.table.OuterJoinPredicate;
  5840. if (predicateidx != NO_SQLNODE)
  5841. {
  5842. fIsSQL89 = FALSE;
  5843. char* myPredicate = NULL;
  5844. AddJoinPredicate(&myPredicate, predicateidx);
  5845. // AddJoinPredicate(&lpSQL92, predicateidx);
  5846. JoinInfo* myPredicateInfo = new JoinInfo();
  5847. myPredicateInfo->predicate = myPredicate;
  5848. delete myPredicate;
  5849. //Add to map
  5850. predicateMap->SetAt(++predicateCount, (void*)myPredicateInfo);
  5851. }
  5852. //Check if there is another table in the table list
  5853. if (tableNode->node.tables.Next == NO_STRING)
  5854. {
  5855. fContinue = FALSE;
  5856. }
  5857. else
  5858. {
  5859. tableNode = ToNode(*lplpSql,tableNode->node.tables.Next);
  5860. //New
  5861. fIsSQL89 = FALSE;
  5862. /*
  5863. //Add a comma to separate table list
  5864. if ((!fFirst) && (idx == NO_SQLNODE) && (noJoinTables))
  5865. {
  5866. // StringConcat(&lpSQL92, ",");
  5867. fIsSQL89 = FALSE;
  5868. }
  5869. */
  5870. }
  5871. fFirst = FALSE;
  5872. }
  5873. /*
  5874. //Are we going to use SQL-89 or SQL-92 ?
  5875. if (!fIsSQL89)
  5876. {
  5877. delete *tableList;
  5878. *tableList = lpSQL92;
  5879. }
  5880. else
  5881. {
  5882. delete lpSQL92;
  5883. }
  5884. */
  5885. //Now build the table list
  5886. _bstr_t myTableList;
  5887. _bstr_t myFullTableDecl;
  5888. BOOL fFirstOuterJoin = TRUE;
  5889. //Note: Some providers will return an error if you supply
  5890. //a table alias on a single table WQL query.
  5891. //we should check for this and remove the table alias from
  5892. //the table list
  5893. BOOL fSingleTableDetected = TRUE;
  5894. if ( tableAliasCount > 1 )
  5895. {
  5896. fSingleTableDetected = FALSE;
  5897. }
  5898. //Add a table
  5899. JoinInfo* myJoinData = NULL;
  5900. tableAliasMap->Lookup(tableAliasCount--, (void*&)myJoinData);
  5901. myTableList = myJoinData->tableName;
  5902. if ( myJoinData->tableAlias.length() && !fSingleTableDetected )
  5903. {
  5904. myTableList += " " + myJoinData->tableAlias;
  5905. }
  5906. //Are there any predicates
  5907. if (predicateCount)
  5908. {
  5909. while (predicateCount)
  5910. {
  5911. if (fFirstOuterJoin)
  5912. {
  5913. //LEFT OUTER JOIN (add to right side)
  5914. myFullTableDecl = " LEFT OUTER JOIN ";
  5915. myFullTableDecl += myTableList;
  5916. myTableList = myFullTableDecl;
  5917. }
  5918. else
  5919. {
  5920. //RIGHT OUTER JOIN (add to left side)
  5921. myTableList += " RIGHT OUTER JOIN ";
  5922. }
  5923. //Add next table
  5924. myJoinData = NULL;
  5925. tableAliasMap->Lookup(tableAliasCount--, (void*&)myJoinData);
  5926. myFullTableDecl = myJoinData->tableName;
  5927. // myTableList += myJoinData->tableName;
  5928. if ( myJoinData->tableAlias.length() )
  5929. {
  5930. myFullTableDecl += " " + myJoinData->tableAlias;
  5931. }
  5932. if (fFirstOuterJoin)
  5933. {
  5934. //Add table to left side
  5935. myFullTableDecl += myTableList;
  5936. myTableList = myFullTableDecl;
  5937. }
  5938. else
  5939. {
  5940. //Add table to right side
  5941. myTableList += " " + myFullTableDecl;
  5942. }
  5943. fFirstOuterJoin = FALSE;
  5944. //Add predicate to end
  5945. myJoinData = NULL;
  5946. predicateMap->Lookup(predicateCount--, (void*&)myJoinData);
  5947. if ( myJoinData->predicate.length() )
  5948. {
  5949. myTableList += " " + myJoinData->predicate;
  5950. }
  5951. }
  5952. }
  5953. else
  5954. {
  5955. //Simple Table list
  5956. while (tableAliasCount)
  5957. {
  5958. //Add next table
  5959. myJoinData = NULL;
  5960. tableAliasMap->Lookup(tableAliasCount--, (void*&)myJoinData);
  5961. myTableList += ", " + myJoinData->tableName;
  5962. if ( myJoinData->tableAlias.length() )
  5963. {
  5964. myTableList += " " + myJoinData->tableAlias;
  5965. }
  5966. }
  5967. }
  5968. //Convert myTableList to string
  5969. long length = myTableList.length();
  5970. *tableList = new char [length + 1];
  5971. (*tableList)[0] = 0;
  5972. wcstombs(*tableList, (wchar_t*)myTableList, length);
  5973. (*tableList)[length] = 0;
  5974. //Tidy up
  5975. if (tableAliasMap && !(tableAliasMap->IsEmpty()))
  5976. {
  5977. for(POSITION pos = tableAliasMap->GetStartPosition(); pos != NULL; )
  5978. {
  5979. WORD key = 0; //not used
  5980. JoinInfo* pa = NULL;
  5981. tableAliasMap->GetNextAssoc( pos, key, (void*&)pa );
  5982. if (pa)
  5983. delete pa;
  5984. }
  5985. }
  5986. delete (tableAliasMap);
  5987. if (predicateMap && !(predicateMap->IsEmpty()))
  5988. {
  5989. for(POSITION pos = predicateMap->GetStartPosition(); pos != NULL; )
  5990. {
  5991. WORD key = 0; //not used
  5992. JoinInfo* pa = NULL;
  5993. predicateMap->GetNextAssoc( pos, key, (void*&)pa );
  5994. if (pa)
  5995. delete pa;
  5996. }
  5997. }
  5998. delete (predicateMap);
  5999. }
  6000. /*
  6001. void TableColumnInfo :: AddJoin(_bstr_t & tableList, SQLNODEIDX joinidx)
  6002. {
  6003. BOOL fContinue = TRUE;
  6004. LPSQLNODE tableNode = tableNode = ToNode(*lplpSql,joinidx);
  6005. while (fContinue)
  6006. {
  6007. SQLNODEIDX tableIdx = tableNode->node.tables.Table;
  6008. LPSQLNODE singleTable = ToNode(*lplpSql,tableIdx);
  6009. char* aliasStr = NULL;
  6010. if (singleTable->node.table.Alias != NO_STRING)
  6011. {
  6012. aliasStr = (LPSTR) ToString(*lplpSql, singleTable->node.table.Alias); //e.g. t1
  6013. }
  6014. char* tableStr = NULL;
  6015. if (singleTable->node.table.Name != NO_STRING)
  6016. {
  6017. tableStr = (LPSTR) ToString(*lplpSql, singleTable->node.table.Name); //e.g. Table1
  6018. }
  6019. //Add LEFT OUTER JOIN <table> <alias>
  6020. if (tableStr)
  6021. {
  6022. tableList += " LEFT OUTER JOIN ";
  6023. tableList += tableStr;
  6024. }
  6025. if (aliasStr)
  6026. {
  6027. tableList += " ";
  6028. tableList += aliasStr;
  6029. tableList += " ";
  6030. }
  6031. if (tableNode->node.tables.Next == NO_STRING)
  6032. {
  6033. fContinue = FALSE;
  6034. }
  6035. else
  6036. {
  6037. tableNode = ToNode(*lplpSql,tableNode->node.tables.Next);
  6038. }
  6039. }
  6040. }
  6041. */
  6042. void TableColumnInfo :: AddJoinPredicate(char** tableList, SQLNODEIDX predicateidx)
  6043. {
  6044. LPSQLNODE lpPredicateNode = ToNode(*lplpSql, predicateidx);
  6045. PredicateParser theParser (lplpSql, NULL);
  6046. char* buffer = NULL;
  6047. theParser.GeneratePredicateString(lpPredicateNode, &buffer, FALSE);
  6048. //Did we find a predicate
  6049. if (buffer)
  6050. {
  6051. StringConcat(tableList, " ON ");
  6052. StringConcat(tableList, buffer);
  6053. }
  6054. delete buffer;
  6055. }
  6056. void TableColumnInfo :: BuildSelectList(LPISAMTABLEDEF lpTableDef, char** lpSelectListStr, BOOL fIsSQL89, CMapWordToPtr** ppPassthroughMap)
  6057. {
  6058. *lpSelectListStr = NULL;
  6059. //Scan through list checking for nodes which match same LPISAMTABLEDEF
  6060. TableColumnList* ptr =lpList;
  6061. //For testing
  6062. CMapWordToPtr* passthroughMap = NULL;
  6063. if (ppPassthroughMap)
  6064. passthroughMap = new CMapWordToPtr();
  6065. WORD passthroughkey = 0; //zero based index
  6066. while (ptr)
  6067. {
  6068. if ( (theMode == WQL_MULTI_TABLE) || (lpTableDef == ptr->lpISAMTableDef) )
  6069. {
  6070. //Found a match, add to output select list
  6071. char* lpTemp = (LPSTR) ToString(*lplpSql, ptr->idxColumnName);
  6072. ULONG cColumnLen = lstrlen (lpTemp);
  6073. ULONG cOutputLen = (*lpSelectListStr) ? lstrlen(*lpSelectListStr) : 0;
  6074. //Get the qualifier (for WQL_MULTI_TABLE)
  6075. char* lpTemp2 = NULL;
  6076. ULONG cColumnLen2 = 0;
  6077. if ( (ptr->idxTableAlias != NO_STRING) && !fIsSQL89)
  6078. {
  6079. lpTemp2 = (LPSTR) ToString(*lplpSql, ptr->idxTableAlias);
  6080. cColumnLen2 = lstrlen (lpTemp2) + 1; //extra 1 for the dot
  6081. }
  6082. if (passthroughMap)
  6083. {
  6084. //Setup Passthrough Element
  6085. PassthroughLookupTable* mapElement = new PassthroughLookupTable();
  6086. mapElement->SetTableAlias(lpTemp2);
  6087. mapElement->SetColumnName(lpTemp);
  6088. //Add to Passthrough Map
  6089. passthroughMap->SetAt(passthroughkey++, (void*)mapElement);
  6090. }
  6091. if (*lpSelectListStr)
  6092. {
  6093. char* newStr = new char [cColumnLen2 + cColumnLen + cOutputLen + 2];
  6094. newStr[0] = 0;
  6095. if ( (theMode == WQL_MULTI_TABLE) && (cColumnLen2 > 0) )
  6096. {
  6097. //Add new entries to head of list
  6098. sprintf (newStr, "%s.%s,%s", lpTemp2, lpTemp, *lpSelectListStr);
  6099. }
  6100. else
  6101. {
  6102. sprintf (newStr, "%s,%s", *lpSelectListStr, lpTemp);
  6103. }
  6104. delete *lpSelectListStr;
  6105. *lpSelectListStr = newStr;
  6106. }
  6107. else
  6108. {
  6109. *lpSelectListStr = new char [cColumnLen2 + cColumnLen + 1];
  6110. (*lpSelectListStr)[0] = 0;
  6111. if ( (theMode == WQL_MULTI_TABLE) && (cColumnLen2 > 0) )
  6112. {
  6113. sprintf (*lpSelectListStr, "%s.%s", lpTemp2, lpTemp);
  6114. }
  6115. else
  6116. {
  6117. lstrcpy (*lpSelectListStr, lpTemp);
  6118. }
  6119. }
  6120. }
  6121. ptr = ptr->Next;
  6122. }
  6123. if (ppPassthroughMap)
  6124. {
  6125. //The order in the passthrough map is WRONG
  6126. //columns were added in reverse order
  6127. //we need to re-read the columns out and add back in correct order
  6128. CMapWordToPtr* passthroughMapNEW = new CMapWordToPtr();
  6129. PassthroughLookupTable* passthroughElement = NULL;
  6130. WORD myCount = (WORD) passthroughMap->GetCount();
  6131. for (WORD loop = 0; loop < myCount; loop++)
  6132. {
  6133. BOOL status = passthroughMap->Lookup(loop, (void*&)passthroughElement);
  6134. if (status)
  6135. {
  6136. WORD NewIndex = myCount - 1 - loop;
  6137. //For test purposes only
  6138. // char* newColumnName = passthroughElement->GetColumnName();
  6139. // char* newAlias = passthroughElement->GetTableAlias();
  6140. //Add to new passthrough map
  6141. passthroughMapNEW->SetAt(NewIndex, (void*)passthroughElement);
  6142. }
  6143. }
  6144. *ppPassthroughMap = passthroughMapNEW;
  6145. delete passthroughMap;
  6146. }
  6147. }
  6148. void TidyupPassthroughMap(CMapWordToPtr* passthroughMap)
  6149. {
  6150. //Test tidy up PassthroughMap
  6151. if (passthroughMap && !(passthroughMap->IsEmpty()))
  6152. {
  6153. for(POSITION pos = passthroughMap->GetStartPosition(); pos != NULL; )
  6154. {
  6155. WORD key = 0; //not used
  6156. PassthroughLookupTable* pa = NULL;
  6157. passthroughMap->GetNextAssoc( pos, key, (void*&)pa );
  6158. if (pa)
  6159. delete pa;
  6160. }
  6161. //delete passthroughMap;
  6162. //passthroughMap = NULL;
  6163. }
  6164. //SAI ADDED
  6165. delete passthroughMap;
  6166. passthroughMap = NULL;
  6167. }
  6168. BOOL TableColumnInfo :: IsTableReferenced(LPISAMTABLEDEF lpTableDef)
  6169. {
  6170. BOOL fStatus = FALSE;
  6171. TableColumnList* ptr =lpList;
  6172. while (!fStatus && ptr)
  6173. {
  6174. if (lpTableDef == ptr->lpISAMTableDef)
  6175. {
  6176. fStatus = TRUE;
  6177. }
  6178. ptr = ptr->Next;
  6179. }
  6180. return fStatus;
  6181. }
  6182. BOOL TableColumnInfo :: IsZeroOrOneList()
  6183. {
  6184. if ( (lpList == NULL) || (lpList->Next == NULL) )
  6185. return TRUE;
  6186. else
  6187. return FALSE;
  6188. }
  6189. DateTimeParser ::DateTimeParser(BSTR dateTimeStr)
  6190. {
  6191. //Initialize
  6192. m_year = 0;
  6193. m_month = 0;
  6194. m_day = 0;
  6195. m_hour = 0;
  6196. m_min = 0;
  6197. m_sec = 0;
  6198. m_microSec = 0;
  6199. fIsValid = TRUE; //Indicates if dataTime string is valid
  6200. //Make a copy of the string
  6201. dateTimeBuff[0] = 0;
  6202. strcpy(dateTimeBuff, "00000000000000.000000");
  6203. // if ( dateTimeStr && ( wcslen(dateTimeStr) >= DATETIME_FORMAT_LEN) )
  6204. long lLength = wcslen(dateTimeStr);
  6205. if ( dateTimeStr && lLength )
  6206. {
  6207. //Copy string into buffer
  6208. if (lLength > DATETIME_FORMAT_LEN)
  6209. lLength = DATETIME_FORMAT_LEN;
  6210. wcstombs(dateTimeBuff, dateTimeStr, lLength);
  6211. dateTimeBuff[DATETIME_FORMAT_LEN] = 0;
  6212. //Now check each of the fields in the string
  6213. ValidateFields();
  6214. }
  6215. else
  6216. {
  6217. //error in dateTime string
  6218. fIsValid = FALSE;
  6219. }
  6220. }
  6221. BOOL DateTimeParser :: IsNumber(char bChar)
  6222. {
  6223. if ( (bChar >= '0') && (bChar <= '9'))
  6224. return TRUE;
  6225. return FALSE;
  6226. }
  6227. void DateTimeParser :: FetchField(char* lpStr, WORD wFieldLen, ULONG &wValue)
  6228. {
  6229. tempBuff[0] = 0;
  6230. strncpy (tempBuff, lpStr, wFieldLen);
  6231. tempBuff[wFieldLen] = 0;
  6232. wValue = atoi(tempBuff);
  6233. }
  6234. void DateTimeParser :: ValidateFields()
  6235. {
  6236. //The dateTime string can represent a date, time or timestamp
  6237. //We need to identify which one it represents and that each
  6238. //field is valid
  6239. char* ptr = dateTimeBuff;
  6240. //The format of the datetime string is as follows
  6241. // YYYYMMDDHHMMSS.VVVVVV
  6242. //Check if the date fields are set
  6243. fValidDate = TRUE;
  6244. for (UWORD cIndex = 0; cIndex < DATETIME_DATE_LEN; cIndex++)
  6245. {
  6246. if ( ! IsNumber(dateTimeBuff[cIndex]) )
  6247. fValidDate = FALSE;
  6248. }
  6249. //If there is a valid date get the fields
  6250. if (fValidDate)
  6251. {
  6252. //Copy the year
  6253. FetchField(ptr, DATETIME_YEAR_LEN, m_year);
  6254. //Copy the month
  6255. ptr += DATETIME_YEAR_LEN;
  6256. FetchField(ptr, DATETIME_MONTH_LEN, m_month);
  6257. //Copy the day
  6258. ptr += DATETIME_MONTH_LEN;
  6259. FetchField(ptr, DATETIME_DAY_LEN, m_day);
  6260. }
  6261. ptr = dateTimeBuff + DATETIME_YEAR_LEN + DATETIME_MONTH_LEN + DATETIME_DAY_LEN;
  6262. fValidTime = TRUE;
  6263. for (cIndex = 0; cIndex < DATETIME_TIME_LEN; cIndex++)
  6264. {
  6265. if ( ! IsNumber(ptr[cIndex]) )
  6266. fValidTime = FALSE;
  6267. }
  6268. //If there is a valid time get the fields
  6269. if (fValidTime)
  6270. {
  6271. //Copy the hour
  6272. FetchField(ptr, DATETIME_HOUR_LEN, m_hour);
  6273. //Copy the min
  6274. ptr += DATETIME_HOUR_LEN;
  6275. FetchField(ptr, DATETIME_MIN_LEN, m_min);
  6276. //Copy the sec
  6277. ptr += DATETIME_MIN_LEN;
  6278. FetchField(ptr, DATETIME_SEC_LEN, m_sec);
  6279. }
  6280. //Set pointer to start of microseconds (just past the '.' character)
  6281. ptr = dateTimeBuff + DATETIME_YEAR_LEN + DATETIME_MONTH_LEN + DATETIME_DAY_LEN
  6282. + DATETIME_HOUR_LEN + DATETIME_MIN_LEN + DATETIME_SEC_LEN + 1;
  6283. //Now we get the number of micro seconds
  6284. FetchField(ptr, DATETIME_MICROSEC_LEN, m_microSec);
  6285. //analyse what datetime string represents
  6286. fIsaTimestamp = FALSE;
  6287. fIsaDate = FALSE;
  6288. fIsaTime = FALSE;
  6289. if ( !fValidDate && !fValidTime)
  6290. {
  6291. fIsValid = FALSE;
  6292. }
  6293. else
  6294. {
  6295. if (fValidDate)
  6296. {
  6297. //This must represent a date or timestamp
  6298. if (fValidTime)
  6299. {
  6300. //This represents a timestamp
  6301. fIsaTimestamp = TRUE;
  6302. fIsaDate = TRUE;
  6303. fIsaTime = TRUE;
  6304. }
  6305. else
  6306. {
  6307. //this represents a date
  6308. fIsaDate = TRUE;
  6309. }
  6310. }
  6311. else
  6312. {
  6313. //This must represent a Time
  6314. fIsaTime = TRUE;
  6315. }
  6316. }
  6317. }