SQLiteObject.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //
  22. // Additional Copyrights
  23. // Copyright 2004 John Vanderbeck
  24. // Copyright 2016 Chris Calef
  25. //-----------------------------------------------------------------------------
  26. //-----------------------------------------------------------------------------
  27. // This code implements support for SQLite into Torque and TorqueScript
  28. //
  29. // Essentially this creates a scriptable object that interfaces with SQLite.
  30. //-----------------------------------------------------------------------------
  31. #include "SQLiteObject.h"
  32. #include "console/simBase.h"
  33. #include "console/engineAPI.h"
  34. #include "console/consoleInternal.h"
  35. #include <STDLIB.H>
  36. IMPLEMENT_CONOBJECT(SQLiteObject);
  37. SQLiteObject::SQLiteObject()
  38. {
  39. m_pDatabase = NULL;
  40. m_szErrorString = NULL;
  41. m_iLastResultSet = 0;
  42. m_iNextResultSet = 1;
  43. }
  44. SQLiteObject::~SQLiteObject()
  45. {
  46. S32 index;
  47. // if we still have a database open, close it
  48. CloseDatabase();
  49. // Clear out any error string we may have left
  50. ClearErrorString();
  51. // Clean up result sets
  52. //
  53. // Boy oh boy this is such a crazy hack!
  54. // I can't seem to iterate through a vector and clean it up without screwing the vector.
  55. // So (HACK HACK HACK) what i'm doing for now is making a temporary vector that
  56. // contains a list of the result sets that the user hasn't cleaned up.
  57. // Clean up all those result sets, then delete the temp vector.
  58. Vector<int> vTemp;
  59. Vector<int>::iterator iTemp;
  60. VectorPtr<sqlite_resultset*>::iterator i;
  61. for (i = m_vResultSets.begin(); i != m_vResultSets.end(); i++)
  62. {
  63. vTemp.push_back((*i)->iResultSet);
  64. }
  65. index = 0;
  66. for (iTemp = vTemp.begin(); iTemp != vTemp.end(); iTemp++)
  67. {
  68. Con::warnf("SQLiteObject Warning: Result set #%i was not cleared by script. Clearing it now.", vTemp[index]);
  69. ClearResultSet(vTemp[index]);
  70. index++;
  71. }
  72. m_vResultSets.clear();
  73. }
  74. bool SQLiteObject::processArguments(S32 argc, const char **argv)
  75. {
  76. if (argc == 0)
  77. return true;
  78. else
  79. return true;
  80. return false;
  81. }
  82. bool SQLiteObject::onAdd()
  83. {
  84. if (!Parent::onAdd())
  85. return false;
  86. const char *name = getName();
  87. if (name && name[0] && getClassRep())
  88. {
  89. Namespace *parent = getClassRep()->getNameSpace();
  90. Con::linkNamespaces(parent->mName, name);
  91. mNameSpace = Con::lookupNamespace(name);
  92. }
  93. return true;
  94. }
  95. // This is the function that gets called when an instance
  96. // of your object is being removed from the system and being
  97. // destroyed. Use this to do your clean up and what not.
  98. void SQLiteObject::onRemove()
  99. {
  100. CloseDatabase();
  101. Parent::onRemove();
  102. }
  103. // To be honest i'm not 100% sure on when this is called yet.
  104. // Basically its used to set the values of any persistant fields
  105. // the object has. Similiar to the way datablocks work. I'm
  106. // just not sure how and when this gets called.
  107. void SQLiteObject::initPersistFields()
  108. {
  109. Parent::initPersistFields();
  110. }
  111. //-----------------------------------------------------------------------
  112. // These functions below are our custom functions that we will tie into
  113. // script.
  114. int Callback(void *pArg, int argc, char **argv, char **columnNames)
  115. {
  116. // basically this callback is called for each row in the SQL query result.
  117. // for each row, argc indicates how many columns are returned.
  118. // columnNames[i] is the name of the column
  119. // argv[i] is the value of the column
  120. sqlite_resultrow* pRow;
  121. sqlite_resultset* pResultSet;
  122. char* name;
  123. char* value;
  124. int i;
  125. if (argc == 0)
  126. return 0;
  127. pResultSet = (sqlite_resultset*)pArg;
  128. if (!pResultSet)
  129. return -1;
  130. // create a new result row
  131. pRow = new sqlite_resultrow;
  132. pResultSet->iNumCols = argc;
  133. // loop through all the columns and stuff them into our row
  134. for (i = 0; i < argc; i++)
  135. {
  136. // DBEUG CODE
  137. // Con::printf("%s = %s\n", columnNames[i], argv[i] ? argv[i] : "NULL");
  138. name = new char[dStrlen(columnNames[i]) + 1];
  139. dStrcpy(name, columnNames[i]);
  140. pRow->vColumnNames.push_back(name);
  141. if (argv[i])
  142. {
  143. value = new char[dStrlen(argv[i]) + 1];
  144. dStrcpy(value, argv[i]);
  145. pRow->vColumnValues.push_back(value);
  146. }
  147. else
  148. {
  149. value = new char[10];
  150. dStrcpy(value, "NULL");
  151. pRow->vColumnValues.push_back(value);
  152. }
  153. }
  154. pResultSet->iNumRows++;
  155. pResultSet->vRows.push_back(pRow);
  156. // return 0 or else the sqlexec will be aborted.
  157. return 0;
  158. }
  159. bool SQLiteObject::OpenDatabase(const char* filename)
  160. {
  161. // check to see if we already have an open database, and
  162. // if so, close it.
  163. CloseDatabase();
  164. Con::printf("CALLING THE OLD OPEN DATABASE FUNCTION!!!!!!!!!!!!!!!!!!");
  165. // We persist the error string so that the script may make a
  166. // GetLastError() call at any time. However when we get
  167. // ready to make a call which could result in a new error,
  168. // we need to clear what we have to avoid a memory leak.
  169. ClearErrorString();
  170. int isOpen = sqlite3_open(filename, &m_pDatabase);
  171. if (isOpen == SQLITE_ERROR)
  172. {
  173. // there was an error and the database could not
  174. // be opened.
  175. m_szErrorString = (char *)sqlite3_errmsg(m_pDatabase);
  176. Con::executef(this, "2", "onOpenFailed()", m_szErrorString);
  177. return false;
  178. }
  179. else
  180. {
  181. // database was opened without error
  182. Con::executef(this, "1", "onOpened()");
  183. //Now, for OpenSimEarth, load spatialite dll, so we can have GIS functions.
  184. //int canLoadExt = sqlite3_load_extension(m_pDatabase,"mod_spatialite.dll",0,0);
  185. //Con::printf("opened spatialite extension: %d",canLoadExt);
  186. //Sigh, no luck yet. Cannot find function GeomFromText().
  187. }
  188. return true;
  189. }
  190. int SQLiteObject::ExecuteSQL(const char* sql)
  191. {
  192. int iResult;
  193. sqlite_resultset* pResultSet;
  194. // create a new resultset
  195. pResultSet = new sqlite_resultset;
  196. if (pResultSet)
  197. {
  198. pResultSet->bValid = false;
  199. pResultSet->iCurrentColumn = 0;
  200. pResultSet->iCurrentRow = 0;
  201. pResultSet->iNumCols = 0;
  202. pResultSet->iNumRows = 0;
  203. pResultSet->iResultSet = m_iNextResultSet;
  204. pResultSet->vRows.clear();
  205. m_iLastResultSet = m_iNextResultSet;
  206. m_iNextResultSet++;
  207. }
  208. else
  209. return 0;
  210. iResult = sqlite3_exec(m_pDatabase, sql, Callback, (void*)pResultSet, &m_szErrorString);
  211. if (iResult == 0)
  212. {
  213. //SQLITE_OK
  214. SaveResultSet(pResultSet);
  215. Con::executef(this, "1", "onQueryFinished()");
  216. return pResultSet->iResultSet;
  217. }
  218. else
  219. {
  220. // error occured
  221. Con::executef(this, "2", "onQueryFailed", m_szErrorString);
  222. Con::errorf("SQLite failed to execute query, error %s", m_szErrorString);
  223. delete pResultSet;
  224. return 0;
  225. }
  226. return 0;
  227. }
  228. void SQLiteObject::CloseDatabase()
  229. {
  230. if (m_pDatabase)
  231. sqlite3_close(m_pDatabase);
  232. m_pDatabase = NULL;
  233. }
  234. //(The following function is courtesy of sqlite.org, minus changes to use m_pDatabase instead of pInMemory.)
  235. /*
  236. ** This function is used to load the contents of a database file on disk
  237. ** into the "main" database of open database connection pInMemory, or
  238. ** to save the current contents of the database opened by pInMemory into
  239. ** a database file on disk. pInMemory is probably an in-memory database,
  240. ** but this function will also work fine if it is not.
  241. **
  242. ** Parameter zFilename points to a null-terminated string containing the
  243. ** name of the database file on disk to load from or save to. If parameter
  244. ** isSave is non-zero, then the contents of the file zFilename are
  245. ** overwritten with the contents of the database opened by pInMemory. If
  246. ** parameter isSave is zero, then the contents of the database opened by
  247. ** pInMemory are replaced by data loaded from the file zFilename.
  248. **
  249. ** If the operation is successful, SQLITE_OK is returned. Otherwise, if
  250. ** an error occurs, an SQLite error code is returned.
  251. */
  252. int SQLiteObject::loadOrSaveDb(const char *zFilename, bool isSave) {
  253. int rc; /* Function return code */
  254. sqlite3 *pFile; /* Database connection opened on zFilename */
  255. sqlite3_backup *pBackup; /* Backup object used to copy data */
  256. sqlite3 *pTo; /* Database to copy to (pFile or pInMemory) */
  257. sqlite3 *pFrom; /* Database to copy from (pFile or pInMemory) */
  258. /* Open the database file identified by zFilename. Exit early if this fails
  259. ** for any reason. */
  260. Con::printf("calling loadOrSaveDb, isSave = %d", isSave);
  261. if (isSave == false)
  262. {//If we're loading, have to create the memory database.
  263. if (!(SQLITE_OK == sqlite3_open(":memory:", &m_pDatabase)))
  264. {
  265. Con::printf("Unable to open a memory database!");
  266. return 0;
  267. }
  268. }
  269. rc = sqlite3_open(zFilename, &pFile);
  270. if (rc == SQLITE_OK) {
  271. /* If this is a 'load' operation (isSave==0), then data is copied
  272. ** from the database file just opened to database pInMemory.
  273. ** Otherwise, if this is a 'save' operation (isSave==1), then data
  274. ** is copied from pInMemory to pFile. Set the variables pFrom and
  275. ** pTo accordingly. */
  276. pFrom = (isSave ? m_pDatabase : pFile);
  277. pTo = (isSave ? pFile : m_pDatabase);
  278. /* Set up the backup procedure to copy from the "main" database of
  279. ** connection pFile to the main database of connection pInMemory.
  280. ** If something goes wrong, pBackup will be set to NULL and an error
  281. ** code and message left in connection pTo.
  282. **
  283. ** If the backup object is successfully created, call backup_step()
  284. ** to copy data from pFile to pInMemory. Then call backup_finish()
  285. ** to release resources associated with the pBackup object. If an
  286. ** error occurred, then an error code and message will be left in
  287. ** connection pTo. If no error occurred, then the error code belonging
  288. ** to pTo is set to SQLITE_OK.
  289. */
  290. pBackup = sqlite3_backup_init(pTo, "main", pFrom, "main");
  291. if (pBackup) {
  292. (void)sqlite3_backup_step(pBackup, -1);
  293. (void)sqlite3_backup_finish(pBackup);
  294. }
  295. rc = sqlite3_errcode(pTo);
  296. }
  297. /* Close the database connection opened on database file zFilename
  298. ** and return the result of this function. */
  299. (void)sqlite3_close(pFile);
  300. //if (isSave == true) // Actually, cancel this, I'm sure it will happen automatically and if we don't do it here, we can also use
  301. //{ // this function for periodic saves, such as after saving mission.
  302. // sqlite3_close(m_pDatabase);
  303. //}
  304. Con::printf("finished loadOrSaveDb, rc = %d", rc);
  305. if (rc == 0)
  306. return true;
  307. else
  308. return false;
  309. }
  310. void SQLiteObject::NextRow(int resultSet)
  311. {
  312. sqlite_resultset* pResultSet;
  313. pResultSet = GetResultSet(resultSet);
  314. if (!pResultSet)
  315. return;
  316. pResultSet->iCurrentRow++;
  317. }
  318. bool SQLiteObject::EndOfResult(int resultSet)
  319. {
  320. sqlite_resultset* pResultSet;
  321. pResultSet = GetResultSet(resultSet);
  322. if (!pResultSet)
  323. return true;
  324. if (pResultSet->iCurrentRow >= pResultSet->iNumRows)
  325. return true;
  326. return false;
  327. }
  328. void SQLiteObject::ClearErrorString()
  329. {
  330. if (m_szErrorString)
  331. sqlite3_free(m_szErrorString);
  332. m_szErrorString = NULL;
  333. }
  334. void SQLiteObject::ClearResultSet(int index)
  335. {
  336. if (index <= 0)
  337. return;
  338. sqlite_resultset* resultSet;
  339. sqlite_resultrow* resultRow;
  340. S32 rows, cols, iResultSet;
  341. // Get the result set specified by index
  342. resultSet = GetResultSet(index);
  343. iResultSet = GetResultSetIndex(index);
  344. if ((!resultSet) || (!resultSet->bValid))
  345. {
  346. Con::warnf("Warning SQLiteObject::ClearResultSet(%i) failed to retrieve specified result set. Result set was NOT cleared.", index);
  347. return;
  348. }
  349. // Now we have the specific result set to be cleared.
  350. // What we need to do now is iterate through each "Column" in each "Row"
  351. // and free the strings, then delete the entries.
  352. VectorPtr<sqlite_resultrow*>::iterator iRow;
  353. VectorPtr<char*>::iterator iColumnName;
  354. VectorPtr<char*>::iterator iColumnValue;
  355. for (iRow = resultSet->vRows.begin(); iRow != resultSet->vRows.end(); iRow++)
  356. {
  357. // Iterate through rows
  358. // for each row iterate through all the column values and names
  359. for (iColumnName = (*iRow)->vColumnNames.begin(); iColumnName != (*iRow)->vColumnNames.end(); iColumnName++)
  360. {
  361. // Iterate through column names. Free the memory.
  362. delete[](*iColumnName);
  363. }
  364. for (iColumnValue = (*iRow)->vColumnValues.begin(); iColumnValue != (*iRow)->vColumnValues.end(); iColumnValue++)
  365. {
  366. // Iterate through column values. Free the memory.
  367. delete[](*iColumnValue);
  368. }
  369. // free memory used by the row
  370. delete (*iRow);
  371. }
  372. // empty the resultset
  373. resultSet->vRows.clear();
  374. resultSet->bValid = false;
  375. delete resultSet;
  376. m_vResultSets.erase_fast(iResultSet);
  377. }
  378. sqlite_resultset* SQLiteObject::GetResultSet(int iResultSet)
  379. {
  380. // Get the result set specified by iResultSet
  381. VectorPtr<sqlite_resultset*>::iterator i;
  382. for (i = m_vResultSets.begin(); i != m_vResultSets.end(); i++)
  383. {
  384. if ((*i)->iResultSet == iResultSet)
  385. break;
  386. }
  387. return *i;
  388. }
  389. int SQLiteObject::GetResultSetIndex(int iResultSet)
  390. {
  391. int iIndex;
  392. // Get the result set specified by iResultSet
  393. VectorPtr<sqlite_resultset*>::iterator i;
  394. iIndex = 0;
  395. for (i = m_vResultSets.begin(); i != m_vResultSets.end(); i++)
  396. {
  397. if ((*i)->iResultSet == iResultSet)
  398. break;
  399. iIndex++;
  400. }
  401. return iIndex;
  402. }
  403. bool SQLiteObject::SaveResultSet(sqlite_resultset* pResultSet)
  404. {
  405. // Basically just add this to our vector. It should already be filled up.
  406. pResultSet->bValid = true;
  407. m_vResultSets.push_back(pResultSet);
  408. return true;
  409. }
  410. int SQLiteObject::GetColumnIndex(int iResult, const char* columnName)
  411. {
  412. int iIndex;
  413. VectorPtr<char*>::iterator i;
  414. sqlite_resultset* pResultSet;
  415. sqlite_resultrow* pRow;
  416. pResultSet = GetResultSet(iResult);
  417. if (!pResultSet)
  418. return 0;
  419. pRow = pResultSet->vRows[0];
  420. if (!pRow)
  421. return 0;
  422. iIndex = 0;
  423. for (i = pRow->vColumnNames.begin(); i != pRow->vColumnNames.end(); i++)
  424. {
  425. if (dStricmp((*i), columnName) == 0)
  426. return iIndex + 1;
  427. iIndex++;
  428. }
  429. return 0;
  430. }
  431. int SQLiteObject::numResultSets()
  432. {
  433. return m_vResultSets.size();
  434. }
  435. void SQLiteObject::escapeSingleQuotes(const char* source, char *dest)
  436. {
  437. //To Do: This function needs to step through the source string and insert another single quote
  438. //immediately after every single quote it finds.
  439. }
  440. //-----------------------------------------------------------------------
  441. // These functions are the code that actually tie our object into the scripting
  442. // language. As you can see each one of these is called by script and in turn
  443. // calls the C++ class function.
  444. // FIX: change all these to DefineEngineMethod!
  445. ConsoleMethod(SQLiteObject, openDatabase, bool, 3, 3, "(const char* filename) Opens the database specifed by filename. Returns true or false.")
  446. {
  447. return object->OpenDatabase(argv[2]);
  448. }
  449. DefineEngineMethod(SQLiteObject, loadOrSaveDb, bool, (const char* filename, bool isSave), ,
  450. "Loads or saves a cached database from the disk db specifed by filename. Second argument determines loading (false) or saving (true). Returns true or false.")
  451. {
  452. return object->loadOrSaveDb(filename, isSave);
  453. }
  454. ConsoleMethod(SQLiteObject, closeDatabase, void, 2, 2, "Closes the active database.")
  455. {
  456. object->CloseDatabase();
  457. }
  458. ConsoleMethod(SQLiteObject, query, S32, 4, 0, "(const char* sql, int mode) Performs an SQL query on the open database and returns an identifier to a valid result set. mode is currently unused, and is reserved for future use.")
  459. {
  460. S32 iCount;
  461. S32 iIndex, iLen, iNewIndex, iArg, iArgLen, i;
  462. char* szNew;
  463. if (argc == 4)
  464. return object->ExecuteSQL(argv[2]);
  465. else if (argc > 4)
  466. {
  467. // Support for printf type querys, as per Ben Garney's suggestion
  468. // Basically what this does is allow the user to insert question marks into their query that will
  469. // be replaced with actual data. For example:
  470. // "SELECT * FROM data WHERE id=? AND age<7 AND name LIKE ?"
  471. // scan the query and count the question marks
  472. iCount = 0;
  473. iLen = dStrlen(argv[2]);
  474. for (iIndex = 0; iIndex < iLen; iIndex++)
  475. {
  476. if (argv[2][iIndex] == '?')
  477. iCount++;
  478. }
  479. // now that we know how many replacements we have, we need to make sure we
  480. // have enough arguments to replace them all. All arguments above 4 should be our data
  481. if (argc - 4 == iCount)
  482. {
  483. // ok we have the correct number of arguments
  484. // so now we need to calc the length of the new query string. This is easily achieved.
  485. // We simply take our base string length, subtract the question marks, then add in
  486. // the number of total characters used by our arguments.
  487. iLen = dStrlen(argv[2]) - iCount;
  488. for (iIndex = 1; iIndex <= iCount; iIndex++)
  489. {
  490. iLen = iLen + dStrlen(argv[iIndex + 3]);
  491. }
  492. // iLen should now be the length of our new string
  493. szNew = new char[iLen];
  494. // now we need to replace all the question marks with the actual arguments
  495. iLen = dStrlen(argv[2]);
  496. iNewIndex = 0;
  497. iArg = 1;
  498. for (iIndex = 0; iIndex <= iLen; iIndex++)
  499. {
  500. if (argv[2][iIndex] == '?')
  501. {
  502. // ok we need to replace this question mark with the actual argument
  503. // and iterate our pointers and everything as needed. This is no doubt
  504. // not the best way to do this, but it works for me for now.
  505. // My god this is really a mess.
  506. iArgLen = dStrlen(argv[iArg + 3]);
  507. // copy first character
  508. szNew[iNewIndex] = argv[iArg + 3][0];
  509. // copy rest of characters, and increment iNewIndex
  510. for (i = 1; i < iArgLen; i++)
  511. {
  512. iNewIndex++;
  513. szNew[iNewIndex] = argv[iArg + 3][i];
  514. }
  515. iArg++;
  516. }
  517. else
  518. szNew[iNewIndex] = argv[2][iIndex];
  519. iNewIndex++;
  520. }
  521. }
  522. else
  523. return 0; // incorrect number of question marks vs arguments
  524. Con::printf("Old SQL: %s\nNew SQL: %s", argv[2], szNew);
  525. return object->ExecuteSQL(szNew);
  526. }
  527. return 0;
  528. }
  529. ConsoleMethod(SQLiteObject, clearResult, void, 3, 3, "(int resultSet) Clears memory used by the specified result set, and deletes the result set.")
  530. {
  531. object->ClearResultSet(dAtoi(argv[2]));
  532. }
  533. ConsoleMethod(SQLiteObject, nextRow, void, 3, 3, "(int resultSet) Moves the result set's row pointer to the next row.")
  534. {
  535. sqlite_resultset* pResultSet;
  536. pResultSet = object->GetResultSet(dAtoi(argv[2]));
  537. if (pResultSet)
  538. {
  539. pResultSet->iCurrentRow++;
  540. }
  541. }
  542. ConsoleMethod(SQLiteObject, previousRow, void, 3, 3, "(int resultSet) Moves the result set's row pointer to the previous row")
  543. {
  544. sqlite_resultset* pResultSet;
  545. pResultSet = object->GetResultSet(dAtoi(argv[2]));
  546. if (pResultSet)
  547. {
  548. pResultSet->iCurrentRow--;
  549. }
  550. }
  551. ConsoleMethod(SQLiteObject, firstRow, void, 3, 3, "(int resultSet) Moves the result set's row pointer to the very first row in the result set.")
  552. {
  553. sqlite_resultset* pResultSet;
  554. pResultSet = object->GetResultSet(dAtoi(argv[2]));
  555. if (pResultSet)
  556. {
  557. pResultSet->iCurrentRow = 0;
  558. }
  559. }
  560. ConsoleMethod(SQLiteObject, lastRow, void, 3, 3, "(int resultSet) Moves the result set's row pointer to the very last row in the result set.")
  561. {
  562. sqlite_resultset* pResultSet;
  563. pResultSet = object->GetResultSet(dAtoi(argv[2]));
  564. if (pResultSet)
  565. {
  566. pResultSet->iCurrentRow = pResultSet->iNumRows - 1;
  567. }
  568. }
  569. ConsoleMethod(SQLiteObject, setRow, void, 4, 4, "(int resultSet int row) Moves the result set's row pointer to the row specified. Row indices start at 1 not 0.")
  570. {
  571. sqlite_resultset* pResultSet;
  572. pResultSet = object->GetResultSet(dAtoi(argv[2]));
  573. if (pResultSet)
  574. {
  575. pResultSet->iCurrentRow = dAtoi(argv[3]) - 1;
  576. }
  577. }
  578. ConsoleMethod(SQLiteObject, getRow, S32, 3, 3, "(int resultSet) Returns what row the result set's row pointer is currently on.")
  579. {
  580. sqlite_resultset* pResultSet;
  581. pResultSet = object->GetResultSet(dAtoi(argv[2]));
  582. if (pResultSet)
  583. {
  584. return pResultSet->iCurrentRow + 1;
  585. }
  586. else
  587. return 0;
  588. }
  589. ConsoleMethod(SQLiteObject, numRows, S32, 3, 3, "(int resultSet) Returns the number of rows in the result set.")
  590. {
  591. sqlite_resultset* pResultSet;
  592. pResultSet = object->GetResultSet(dAtoi(argv[2]));
  593. if (pResultSet)
  594. {
  595. return pResultSet->iNumRows;
  596. }
  597. else
  598. return 0;
  599. }
  600. ConsoleMethod(SQLiteObject, numColumns, S32, 3, 3, "(int resultSet) Returns the number of columns in the result set.")
  601. {
  602. sqlite_resultset* pResultSet;
  603. pResultSet = object->GetResultSet(dAtoi(argv[2]));
  604. if (pResultSet)
  605. {
  606. return pResultSet->iNumCols;
  607. }
  608. else
  609. return 0;
  610. }
  611. ConsoleMethod(SQLiteObject, endOfResult, bool, 3, 3, "(int resultSet) Checks to see if the internal pointer for the specified result set is at the end, indicating there are no more rows left to read.")
  612. {
  613. return object->EndOfResult(dAtoi(argv[2]));
  614. }
  615. ConsoleMethod(SQLiteObject, EOR, bool, 3, 3, "(int resultSet) Same as endOfResult().")
  616. {
  617. return object->EndOfResult(dAtoi(argv[2]));
  618. }
  619. ConsoleMethod(SQLiteObject, EOF, bool, 3, 3, "(int resultSet) Same as endOfResult().")
  620. {
  621. return object->EndOfResult(dAtoi(argv[2]));
  622. }
  623. ConsoleMethod(SQLiteObject, getColumnIndex, S32, 4, 4, "(resultSet columnName) Looks up the specified column name in the specified result set, and returns the columns index number. A return value of 0 indicates the lookup failed for some reason (usually this indicates you specified a column name that doesn't exist or is spelled wrong).")
  624. {
  625. return object->GetColumnIndex(dAtoi(argv[2]), argv[3]);
  626. }
  627. ConsoleMethod(SQLiteObject, getColumnName, const char *, 4, 4, "(resultSet columnIndex) Looks up the specified column index in the specified result set, and returns the column's name. A return value of an empty string indicates the lookup failed for some reason (usually this indicates you specified a column index that is invalid or exceeds the number of columns in the result set). Columns are index starting with 1 not 0")
  628. {
  629. sqlite_resultset* pResultSet;
  630. sqlite_resultrow* pRow;
  631. VectorPtr<char*>::iterator iName;
  632. VectorPtr<char*>::iterator iValue;
  633. S32 iColumn;
  634. pResultSet = object->GetResultSet(dAtoi(argv[2]));
  635. if (pResultSet)
  636. {
  637. pRow = pResultSet->vRows[pResultSet->iCurrentRow];
  638. if (!pRow)
  639. return "";
  640. // We assume they specified column by index. If they know the column name they wouldn't be calling this function :)
  641. iColumn = dAtoi(argv[3]);
  642. if (iColumn == 0)
  643. return ""; // column indices start at 1, not 0
  644. // now we should have an index for our column name
  645. if (pRow->vColumnNames[iColumn])
  646. return pRow->vColumnNames[iColumn];
  647. else
  648. return "";
  649. }
  650. else
  651. return "";
  652. }
  653. ConsoleMethod(SQLiteObject, getColumn, const char *, 4, 4, "(resultSet column) Returns the value of the specified column (Column can be specified by name or index) in the current row of the specified result set. If the call fails, the returned string will indicate the error.")
  654. {
  655. sqlite_resultset* pResultSet;
  656. sqlite_resultrow* pRow;
  657. VectorPtr<char*>::iterator iName;
  658. VectorPtr<char*>::iterator iValue;
  659. S32 iColumn;
  660. pResultSet = object->GetResultSet(dAtoi(argv[2]));
  661. if (pResultSet)
  662. {
  663. if (pResultSet->vRows.size() == 0)
  664. return "NULL";
  665. pRow = pResultSet->vRows[pResultSet->iCurrentRow];
  666. if (!pRow)
  667. return "invalid_row";
  668. // Is column specified by a name or an index?
  669. iColumn = dAtoi(argv[3]);
  670. if (iColumn == 0)
  671. {
  672. // column was specified by a name
  673. iColumn = object->GetColumnIndex(dAtoi(argv[2]), argv[3]);
  674. // if this is still 0 then we have some error
  675. if (iColumn == 0)
  676. return "invalid_column";
  677. }
  678. // We temporarily padded the index in GetColumnIndex() so we could return a
  679. // 0 for error. So now we need to drop it back down.
  680. iColumn--;
  681. // now we should have an index for our column data
  682. if (pRow->vColumnValues[iColumn])
  683. return pRow->vColumnValues[iColumn];
  684. else
  685. return "NULL";
  686. }
  687. else
  688. return "invalid_result_set";
  689. }
  690. ConsoleMethod(SQLiteObject, getColumnNumeric, F32, 4, 4, "(resultSet column) Returns the value of the specified column (Column can be specified by name or index) in the current row of the specified result set. If the call fails, the returned string will indicate the error.")
  691. {
  692. sqlite_resultset* pResultSet;
  693. sqlite_resultrow* pRow;
  694. VectorPtr<char*>::iterator iName;
  695. VectorPtr<char*>::iterator iValue;
  696. S32 iColumn;
  697. pResultSet = object->GetResultSet(dAtoi(argv[2]));
  698. if (pResultSet)
  699. {
  700. if (pResultSet->vRows.size() == 0)
  701. return -1;
  702. pRow = pResultSet->vRows[pResultSet->iCurrentRow];
  703. if (!pRow)
  704. return -1;//"invalid_row";
  705. // Is column specified by a name or an index?
  706. iColumn = dAtoi(argv[3]);
  707. if (iColumn == 0)
  708. {
  709. // column was specified by a name
  710. iColumn = object->GetColumnIndex(dAtoi(argv[2]), argv[3]);
  711. // if this is still 0 then we have some error
  712. if (iColumn == 0)
  713. return -1;//"invalid_column";
  714. }
  715. // We temporarily padded the index in GetColumnIndex() so we could return a
  716. // 0 for error. So now we need to drop it back down.
  717. iColumn--;
  718. // now we should have an index for our column data
  719. if (pRow->vColumnValues[iColumn])
  720. return dAtof(pRow->vColumnValues[iColumn]);
  721. else
  722. return 0;
  723. }
  724. else
  725. return -1;//"invalid_result_set";
  726. }
  727. ConsoleMethod(SQLiteObject, escapeString, const char *, 3, 3, "(string) Escapes the given string, making it safer to pass into a query.")
  728. {
  729. // essentially what we need to do here is scan the string for any occurrences of: ', ", and \
  730. // and prepend them with a slash: \', \", \\
  731. // to do this we first need to know how many characters we are replacing so we can calculate
  732. // the size of the new string
  733. S32 iCount;
  734. S32 iIndex, iLen, iNewIndex;
  735. char* szNew;
  736. iCount = 0;
  737. iLen = dStrlen(argv[2]);
  738. for (iIndex = 0; iIndex < iLen; iIndex++)
  739. {
  740. if (argv[2][iIndex] == '\'')
  741. iCount++;
  742. else if (argv[2][iIndex] == '\"')
  743. iCount++;
  744. else if (argv[2][iIndex] == '\\')
  745. iCount++;
  746. }
  747. // Con::printf("escapeString counts %i instances of characters to be escaped. New string will be %i characters longer for a total of %i characters.", iCount, iCount, iLen+iCount);
  748. szNew = new char[iLen + iCount];
  749. iNewIndex = 0;
  750. for (iIndex = 0; iIndex <= iLen; iIndex++)
  751. {
  752. if (argv[2][iIndex] == '\'')
  753. {
  754. szNew[iNewIndex] = '\\';
  755. iNewIndex++;
  756. szNew[iNewIndex] = '\'';
  757. }
  758. else if (argv[2][iIndex] == '\"')
  759. {
  760. szNew[iNewIndex] = '\\';
  761. iNewIndex++;
  762. szNew[iNewIndex] = '\"';
  763. }
  764. else if (argv[2][iIndex] == '\\')
  765. {
  766. szNew[iNewIndex] = '\\';
  767. iNewIndex++;
  768. szNew[iNewIndex] = '\\';
  769. }
  770. else
  771. szNew[iNewIndex] = argv[2][iIndex];
  772. iNewIndex++;
  773. }
  774. // Con::printf("Last characters of each string (new, old): %s, %s", argv[2][iIndex-1], szNew[iNewIndex-1]);
  775. // Con::printf("Old String: %s\nNew String: %s", argv[2], szNew);
  776. return szNew;
  777. }
  778. ConsoleMethod(SQLiteObject, numResultSets, S32, 2, 2, "numResultSets()")
  779. {
  780. return object->numResultSets();
  781. }
  782. ConsoleMethod(SQLiteObject, getLastRowId, S32, 2, 2, "getLastRowId()")
  783. {
  784. return object->getLastRowId();
  785. }