PageRenderTime 29ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/server/src/mozilla/aptana_iws/database/jxMySQL50/jxMySQL50Statement.cpp

https://github.com/absynce/Jaxer
C++ | 1796 lines | 1296 code | 333 blank | 167 comment | 329 complexity | 1266e73a4bbc99734dbf2570ffcc5b29 MD5 | raw file
  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. * vim: set sw=4 ts=4 et: */
  3. /* ***** BEGIN LICENSE BLOCK *****
  4. * Version: GPL 3
  5. *
  6. * This program is Copyright (C) 2007-2008 Aptana, Inc. All Rights Reserved
  7. * This program is licensed under the GNU General Public license, version 3 (GPL).
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
  12. * NONINFRINGEMENT. Redistribution, except as permitted by the GPL,
  13. * is prohibited.
  14. *
  15. * You can redistribute and/or modify this program under the terms of the GPL,
  16. * as published by the Free Software Foundation. You should
  17. * have received a copy of the GNU General Public License, Version 3 along
  18. * with this program; if not, write to the Free Software Foundation, Inc., 51
  19. * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20. *
  21. * Aptana provides a special exception to allow redistribution of this file
  22. * with certain other code and certain additional terms
  23. * pursuant to Section 7 of the GPL. You may view the exception and these
  24. * terms on the web at http://www.aptana.com/legal/gpl/.
  25. *
  26. * You may view the GPL, and Aptana's exception and additional terms in the file
  27. * titled license-jaxer.html in the main distribution folder of this program.
  28. *
  29. * Any modifications to this file must keep this entire header intact.
  30. *
  31. * ***** END LICENSE BLOCK ***** */
  32. #if defined(_WIN32) || defined(_WIN64)
  33. #include <winsock2.h>
  34. #endif
  35. extern "C" {
  36. #include "my_global.h"
  37. #include "mysql.h"
  38. #include "errmsg.h"
  39. }
  40. #include "nsCOMPtr.h"
  41. #include "nsString.h"
  42. #include "nsPrintfCString.h"
  43. #include "jxMySQL50Statement.h"
  44. #include "jxMySQL50.h"
  45. #include "jxMySQL50Field.h"
  46. #include "jxMySQL50ResultSet.h"
  47. #include "nsIClassInfoImpl.h"
  48. #include "jxMySQL50Defs.h"
  49. #define SET_ERROR_RETURN(e) \
  50. mErrno = e; \
  51. if (mConnection==nsnull) return JX_MYSQL50_ERROR_NOT_CONNECTED; \
  52. mConnection->SetErrorNumber(e); return e;
  53. ////////////////////////////////////////////////////////////////////////
  54. jxMySQL50Statement::jxMySQL50Statement()
  55. {
  56. mConnection = nsnull;
  57. mConnected = PR_FALSE;
  58. mSTMT = nsnull;
  59. mRowCount = 0;
  60. mErrno = NS_OK;
  61. mRES = nsnull;
  62. }
  63. jxMySQL50Statement::~jxMySQL50Statement()
  64. {
  65. if (mSTMT)
  66. {
  67. // preserve the mysql error if any
  68. if(mConnection != nsnull)
  69. {
  70. mConnection->SaveMySQLError();
  71. NS_RELEASE(mConnection);
  72. }
  73. Close();
  74. }
  75. }
  76. jxMySQL50Statement::InBind::InBind()
  77. {
  78. mCount = -1;
  79. mBIND = nsnull;
  80. mBindArrayType = nsnull;
  81. mBindArrayBufferTYPE_BOOL = nsnull;
  82. mBindArrayBufferTYPE_DOUBLE = nsnull;
  83. mBindArrayBufferTYPE_STRING = nsnull;
  84. mBindArrayBufferTYPE_DATE = nsnull;
  85. mBindArrayBufferTYPE_STRING_LEN_IN = nsnull;
  86. }
  87. jxMySQL50Statement::OutBind::OutBind()
  88. {
  89. mBindArrayBufferTYPE_STRING_LEN_OUT = nsnull;
  90. mBindArrayIsNull = nsnull;
  91. }
  92. jxMySQL50Statement::InBind::~InBind()
  93. {
  94. Free();
  95. }
  96. jxMySQL50Statement::OutBind::~OutBind()
  97. {
  98. Free_();
  99. }
  100. nsresult jxMySQL50Statement::InBind::Allocate()
  101. {
  102. PRUint32 size;
  103. size = mCount * sizeof(MYSQL_BIND);
  104. if (! (mBIND = static_cast<MYSQL_BIND*>(nsMemory::Alloc(size))))
  105. {
  106. return JX_MYSQL50_ERROR_OUT_OF_MEMORY;
  107. }
  108. memset(mBIND, 0, size);
  109. // Also allocate array to hold the parameter binding types
  110. size = mCount * sizeof(PRInt32*);
  111. if (! (mBindArrayType = static_cast<PRInt32*>(nsMemory::Alloc(size))))
  112. {
  113. return JX_MYSQL50_ERROR_OUT_OF_MEMORY;
  114. }
  115. memset(mBindArrayType, 0, size);
  116. // Also allocate array to hold the actual content that is of type Integer
  117. size = mCount * sizeof(PRBool);
  118. if (! (mBindArrayBufferTYPE_BOOL = static_cast<PRBool*>(nsMemory::Alloc(size))))
  119. {
  120. return JX_MYSQL50_ERROR_OUT_OF_MEMORY;
  121. }
  122. memset(mBindArrayBufferTYPE_BOOL, 0, size);
  123. // Also allocate array to hold the actual content that is of type longlong
  124. size = mCount * sizeof(double);
  125. if (! (mBindArrayBufferTYPE_DOUBLE = static_cast<double*>(nsMemory::Alloc(size))))
  126. {
  127. return JX_MYSQL50_ERROR_OUT_OF_MEMORY;
  128. }
  129. memset(mBindArrayBufferTYPE_DOUBLE, 0, size);
  130. // Also allocate array to hold pointers to the actual content that is of type String
  131. size = mCount * sizeof(char**);
  132. if (! (mBindArrayBufferTYPE_STRING = static_cast<char**>(nsMemory::Alloc(size))))
  133. {
  134. return JX_MYSQL50_ERROR_OUT_OF_MEMORY;
  135. }
  136. memset(mBindArrayBufferTYPE_STRING, 0, size);
  137. // Also allocate array to hold pointers to the actual content that is of type Date
  138. size = mCount * sizeof(MYSQL_TIME**);
  139. if (! (mBindArrayBufferTYPE_DATE = static_cast<MYSQL_TIME**>(nsMemory::Alloc(size))))
  140. {
  141. return JX_MYSQL50_ERROR_OUT_OF_MEMORY;
  142. }
  143. memset(mBindArrayBufferTYPE_DATE, 0, size);
  144. // Also allocate array to hold pointers to the lengths of actual content that is of type String
  145. size = mCount * sizeof(PRInt32*);
  146. if (! (mBindArrayBufferTYPE_STRING_LEN_IN = static_cast<unsigned long*>(nsMemory::Alloc(size))))
  147. {
  148. return JX_MYSQL50_ERROR_OUT_OF_MEMORY;
  149. }
  150. memset(mBindArrayBufferTYPE_STRING_LEN_IN, 0, size);
  151. return NS_OK;
  152. }
  153. nsresult jxMySQL50Statement::OutBind::Allocate()
  154. {
  155. PRUint32 size;
  156. PRInt32 rc = InBind::Allocate();
  157. if (rc != NS_OK)
  158. {
  159. return rc;
  160. }
  161. size = mCount * sizeof(PRInt32*);
  162. if (! (mBindArrayBufferTYPE_STRING_LEN_OUT = static_cast<unsigned long*>(nsMemory::Alloc(size))))
  163. {
  164. return JX_MYSQL50_ERROR_OUT_OF_MEMORY;
  165. }
  166. memset(mBindArrayBufferTYPE_STRING_LEN_OUT, 0, size);
  167. // Also allocate array to hold the is_null indicators
  168. size = mCount * sizeof(PRBool);
  169. if (! (mBindArrayIsNull = static_cast<PRBool*>(nsMemory::Alloc(size))))
  170. {
  171. return JX_MYSQL50_ERROR_OUT_OF_MEMORY;
  172. }
  173. memset(mBindArrayIsNull, 0, size);
  174. return NS_OK;
  175. }
  176. void jxMySQL50Statement::InBind::Free()
  177. {
  178. if (mBIND != nsnull)
  179. {
  180. nsMemory::Free(mBIND);
  181. mBIND = nsnull;
  182. }
  183. if (mBindArrayType != nsnull)
  184. {
  185. nsMemory::Free(mBindArrayType);
  186. mBindArrayType = nsnull;
  187. }
  188. if (mBindArrayBufferTYPE_BOOL != nsnull)
  189. {
  190. nsMemory::Free(mBindArrayBufferTYPE_BOOL);
  191. mBindArrayBufferTYPE_BOOL = nsnull;
  192. }
  193. if (mBindArrayBufferTYPE_DOUBLE != nsnull)
  194. {
  195. nsMemory::Free(mBindArrayBufferTYPE_DOUBLE);
  196. mBindArrayBufferTYPE_DOUBLE = nsnull;
  197. }
  198. if (mBindArrayBufferTYPE_STRING != nsnull)
  199. {
  200. for (PRInt32 i = 0 ; i < mCount ; i++)
  201. {
  202. if (mBindArrayBufferTYPE_STRING[i] != nsnull) { nsMemory::Free(mBindArrayBufferTYPE_STRING[i]); }
  203. }
  204. nsMemory::Free(mBindArrayBufferTYPE_STRING);
  205. mBindArrayBufferTYPE_STRING = nsnull;
  206. }
  207. if (mBindArrayBufferTYPE_DATE != nsnull)
  208. {
  209. for (PRInt32 i = 0 ; i < mCount ; i++)
  210. {
  211. if (mBindArrayBufferTYPE_DATE[i] != nsnull) { nsMemory::Free(mBindArrayBufferTYPE_DATE[i]); }
  212. }
  213. nsMemory::Free(mBindArrayBufferTYPE_DATE);
  214. mBindArrayBufferTYPE_DATE = nsnull;
  215. }
  216. if (mBindArrayBufferTYPE_STRING_LEN_IN != nsnull)
  217. {
  218. nsMemory::Free(mBindArrayBufferTYPE_STRING_LEN_IN);
  219. mBindArrayBufferTYPE_STRING_LEN_IN = nsnull;
  220. }
  221. }
  222. void jxMySQL50Statement::OutBind::Free()
  223. {
  224. InBind::Free();
  225. Free_();
  226. }
  227. void jxMySQL50Statement::OutBind::Free_()
  228. {
  229. if (mBindArrayBufferTYPE_STRING_LEN_OUT != nsnull)
  230. {
  231. nsMemory::Free(mBindArrayBufferTYPE_STRING_LEN_OUT);
  232. mBindArrayBufferTYPE_STRING_LEN_OUT = nsnull;
  233. }
  234. if (mBindArrayIsNull != nsnull)
  235. {
  236. nsMemory::Free(mBindArrayIsNull);
  237. mBindArrayIsNull = nsnull;
  238. }
  239. }
  240. NS_IMPL_ISUPPORTS1_CI(jxMySQL50Statement, jxIMySQL50Statement)
  241. /* [noscript] void setMySQL50 (in jxIMySQL50 aObj); */
  242. NS_IMETHODIMP jxMySQL50Statement::SetMySQL50(jxIMySQL50 *aObj)
  243. {
  244. mConnection = aObj;
  245. NS_ADDREF(mConnection);
  246. return NS_OK;
  247. }
  248. nsresult jxMySQL50Statement::BindOutput()
  249. {
  250. PRInt32 ndx;
  251. PRInt32 col_type;
  252. // Allocate the BIND array and supporting structures.
  253. nsresult rv = mOut.Allocate();
  254. if (NS_FAILED(rv))
  255. {
  256. SET_ERROR_RETURN(rv);
  257. }
  258. // Set up the BIND structure based on the column types specified by the database metadata.
  259. for (ndx=0; ndx < mOut.mCount ; ndx++) {
  260. col_type = (mSTMT->fields) ? mSTMT->fields[ndx].type : MYSQL_TYPE_STRING;
  261. switch (col_type) {
  262. case MYSQL_TYPE_LONGLONG:
  263. case MYSQL_TYPE_DOUBLE:
  264. case MYSQL_TYPE_NEWDECIMAL:
  265. case MYSQL_TYPE_FLOAT:
  266. case MYSQL_TYPE_SHORT:
  267. case MYSQL_TYPE_TINY:
  268. case MYSQL_TYPE_LONG:
  269. case MYSQL_TYPE_INT24:
  270. case MYSQL_TYPE_YEAR:
  271. mOut.mBindArrayType[ndx] = MYSQL_TYPE_DOUBLE;
  272. /* allocate buffer for double */
  273. mOut.mBIND[ndx].buffer_type = MYSQL_TYPE_DOUBLE;
  274. mOut.mBIND[ndx].buffer = &(mOut.mBindArrayBufferTYPE_DOUBLE[ndx]);
  275. mOut.mBIND[ndx].is_null = (my_bool*)&(mOut.mBindArrayIsNull[ndx]);
  276. break;
  277. case MYSQL_TYPE_NULL:
  278. mOut.mBindArrayType[ndx] = MYSQL_TYPE_NULL;
  279. /*
  280. don't initialize to 0 :
  281. 1. stmt->result.buf[ofs].buflen
  282. 2. bind[ofs].buffer
  283. 3. bind[ofs].buffer_length
  284. because memory was allocated with ecalloc
  285. */
  286. mOut.mBIND[ndx].buffer_type = MYSQL_TYPE_NULL;
  287. mOut.mBIND[ndx].is_null = (my_bool*)&(mOut.mBindArrayIsNull[ndx]);
  288. break;
  289. case MYSQL_TYPE_STRING:
  290. case MYSQL_TYPE_VAR_STRING:
  291. case MYSQL_TYPE_BIT:
  292. {
  293. unsigned long tmp = 0;
  294. if (mSTMT->fields[ndx].max_length == 0 && !mysql_stmt_attr_get(mSTMT, STMT_ATTR_UPDATE_MAX_LENGTH, &tmp) && !tmp)
  295. {
  296. mOut.mBindArrayBufferTYPE_STRING_LEN_IN[ndx] = (mSTMT->fields) ? (mSTMT->fields[ndx].length) ? mSTMT->fields[ndx].length + 1: 256: 256;
  297. } else {
  298. /*
  299. the user has called store_result(). if he does not there is no way to determine the
  300. libmysql does not allow us to allocate 0 bytes for a buffer so we try 1
  301. */
  302. if (!(mOut.mBindArrayBufferTYPE_STRING_LEN_IN[ndx] = mSTMT->fields[ndx].max_length))
  303. ++mOut.mBindArrayBufferTYPE_STRING_LEN_IN[ndx];
  304. }
  305. mOut.mBindArrayType[ndx] = MYSQL_TYPE_STRING;
  306. mOut.mBIND[ndx].buffer_type = MYSQL_TYPE_STRING;
  307. mOut.mBindArrayBufferTYPE_STRING[ndx] = static_cast<char*>(nsMemory::Alloc(mOut.mBindArrayBufferTYPE_STRING_LEN_IN[ndx])) ;
  308. if (!mOut.mBindArrayBufferTYPE_STRING[ndx])
  309. {
  310. SET_ERROR_RETURN (JX_MYSQL50_ERROR_OUT_OF_MEMORY);
  311. }
  312. mOut.mBIND[ndx].buffer = mOut.mBindArrayBufferTYPE_STRING[ndx];
  313. mOut.mBIND[ndx].is_null = (my_bool*)&(mOut.mBindArrayIsNull[ndx]);
  314. mOut.mBIND[ndx].buffer_length = mOut.mBindArrayBufferTYPE_STRING_LEN_IN[ndx];
  315. mOut.mBIND[ndx].length = &(mOut.mBindArrayBufferTYPE_STRING_LEN_OUT[ndx]);
  316. }
  317. break;
  318. case MYSQL_TYPE_BLOB:
  319. case MYSQL_TYPE_TINY_BLOB:
  320. case MYSQL_TYPE_MEDIUM_BLOB:
  321. case MYSQL_TYPE_LONG_BLOB:
  322. {
  323. #if 0
  324. PRUint32 tmp = 0;
  325. if (mSTMT->fields[ndx].max_length == 0 && !mysql_stmt_attr_get(mSTMT, STMT_ATTR_UPDATE_MAX_LENGTH, &tmp) && !tmp)
  326. {
  327. if (mSTMT->fields && mSTMT->fields[ndx].length)
  328. tmp = mSTMT->fields[ndx].length + 1;
  329. // tmp will be zero if a length isn't available or if it was the maximum possible of 4GB-1. In
  330. // this case, supply a suitable length.
  331. // NB. tmp may not always be 4GB-1, so if we do not want support larger than 16MB, we should try
  332. // to prevent it.
  333. if (tmp == 0 || tmp > 16*1024*1024) {
  334. switch (col_type) {
  335. case MYSQL_TYPE_BLOB: tmp = 64*1024; break;
  336. case MYSQL_TYPE_TINY_BLOB: tmp = 256; break;
  337. case MYSQL_TYPE_MEDIUM_BLOB: tmp = 16*1024*1024; break;
  338. case MYSQL_TYPE_LONG_BLOB: tmp = 16*1024*1024; break;
  339. }
  340. }
  341. mOut.mBindArrayBufferTYPE_STRING_LEN_IN[ndx] = tmp;
  342. } else {
  343. /*
  344. the user has called store_result(). if he does not there is no way to determine the
  345. libmysql does not allow us to allocate 0 bytes for a buffer so we try 1
  346. */
  347. if (!(mOut.mBindArrayBufferTYPE_STRING_LEN_IN[ndx] = mSTMT->fields[ndx].max_length))
  348. ++mOut.mBindArrayBufferTYPE_STRING_LEN_IN[ndx];
  349. }
  350. mOut.mBindArrayType[ndx] = MYSQL_TYPE_BLOB;
  351. mOut.mBIND[ndx].buffer_type = MYSQL_TYPE_BLOB;
  352. mOut.mBindArrayBufferTYPE_STRING[ndx] = static_cast<char*>(nsMemory::Alloc(mOut.mBindArrayBufferTYPE_STRING_LEN_IN[ndx])) ;
  353. if (!mOut.mBindArrayBufferTYPE_STRING[ndx])
  354. {
  355. SET_ERROR_RETURN (JX_MYSQL50_ERROR_OUT_OF_MEMORY);
  356. }
  357. mOut.mBIND[ndx].buffer = mOut.mBindArrayBufferTYPE_STRING[ndx];
  358. mOut.mBIND[ndx].is_null = (my_bool*)&(mOut.mBindArrayIsNull[ndx]);
  359. mOut.mBIND[ndx].buffer_length = mOut.mBindArrayBufferTYPE_STRING_LEN_IN[ndx];
  360. mOut.mBIND[ndx].length = (unsigned long*)&(mOut.mBindArrayBufferTYPE_STRING_LEN_OUT[ndx]);
  361. #endif
  362. mOut.mBindArrayType[ndx] = MYSQL_TYPE_BLOB;
  363. mOut.mBIND[ndx].buffer_type = MYSQL_TYPE_BLOB;
  364. mOut.mBindArrayBufferTYPE_STRING[ndx] = 0;
  365. mOut.mBIND[ndx].buffer = mOut.mBindArrayBufferTYPE_STRING[ndx];
  366. mOut.mBIND[ndx].is_null = (my_bool*)&(mOut.mBindArrayIsNull[ndx]);
  367. mOut.mBIND[ndx].buffer_length = 0;
  368. mOut.mBindArrayBufferTYPE_STRING_LEN_OUT[ndx] = 0;
  369. mOut.mBIND[ndx].length = &(mOut.mBindArrayBufferTYPE_STRING_LEN_OUT[ndx]);
  370. }
  371. break;
  372. case MYSQL_TYPE_DATETIME:
  373. case MYSQL_TYPE_TIME:
  374. case MYSQL_TYPE_DATE:
  375. case MYSQL_TYPE_TIMESTAMP:
  376. if (col_type == MYSQL_TYPE_TIMESTAMP )
  377. mOut.mBindArrayType[ndx] = MYSQL_TYPE_DATETIME;
  378. else
  379. mOut.mBindArrayType[ndx] = col_type;
  380. mOut.mBindArrayBufferTYPE_DATE[ndx] = static_cast<MYSQL_TIME*>(nsMemory::Alloc(sizeof(MYSQL_TIME)));
  381. if (!mOut.mBindArrayBufferTYPE_DATE[ndx])
  382. {
  383. SET_ERROR_RETURN (JX_MYSQL50_ERROR_OUT_OF_MEMORY);
  384. }
  385. /* allocate buffer for DATE */
  386. mOut.mBIND[ndx].buffer_type = MYSQL_TYPE_DATETIME;
  387. mOut.mBIND[ndx].buffer = (void*)mOut.mBindArrayBufferTYPE_DATE[ndx];
  388. mOut.mBIND[ndx].buffer_length = sizeof(MYSQL_TIME);
  389. mOut.mBIND[ndx].length = (unsigned long*)&(mOut.mBindArrayBufferTYPE_STRING_LEN_OUT[ndx]);
  390. mOut.mBIND[ndx].is_null = (my_bool*)&(mOut.mBindArrayIsNull[ndx]);
  391. break;
  392. default:
  393. SET_ERROR_RETURN (JX_MYSQL50_ERROR_INVALID_TYPE);
  394. break;
  395. }
  396. }
  397. PRUint32 rc = mysql_stmt_bind_result(mSTMT, mOut.mBIND);
  398. if (rc)
  399. {
  400. SET_ERROR_RETURN (JX_MYSQL50_MYSQL_ERROR);
  401. } else
  402. {
  403. if (mRES)
  404. {
  405. mysql_free_result(mRES);
  406. mRES = nsnull;
  407. }
  408. mRES = mysql_stmt_result_metadata(mSTMT);
  409. if (mRES)
  410. {
  411. if (mysql_stmt_store_result(mSTMT))
  412. {
  413. #if 0
  414. int i=0;
  415. unsigned int en = mysql_stmt_errno(mSTMT);
  416. const char* es = mysql_stmt_error(mSTMT);
  417. // Not sure why this would fail. Will need to be investigated
  418. // Per DOC, this needs to be called earlier.
  419. // SET_ERROR_RETURN (JX_MYSQL50_MYSQL_ERROR);
  420. #endif
  421. }
  422. }
  423. return NS_OK;
  424. }
  425. }
  426. /* void close (); */
  427. NS_IMETHODIMP jxMySQL50Statement::Close()
  428. {
  429. if (mConnection == nsnull)
  430. {
  431. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  432. }
  433. if (mSTMT == nsnull)
  434. {
  435. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  436. }
  437. mysql_free_result(mRES);
  438. if(mysql_stmt_close(mSTMT))
  439. {
  440. SET_ERROR_RETURN (JX_MYSQL50_MYSQL_ERROR);
  441. }
  442. mSTMT = nsnull;
  443. mIn.Free();
  444. mOut.Free();
  445. return NS_OK;
  446. }
  447. /* unsigned long errno (); */
  448. NS_IMETHODIMP jxMySQL50Statement::Errno(PRUint32 *_retval)
  449. {
  450. if (mSTMT == nsnull)
  451. {
  452. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  453. }
  454. //*_retval = mysql_stmt_errno(mSTMT);
  455. if (mErrno == JX_MYSQL50_MYSQL_ERROR)
  456. {
  457. *_retval = mysql_stmt_errno(mSTMT);
  458. }else
  459. *_retval = mErrno;
  460. return NS_OK;
  461. }
  462. /* AString error (); */
  463. NS_IMETHODIMP jxMySQL50Statement::Error(nsAString & aError)
  464. {
  465. if (mSTMT == nsnull)
  466. {
  467. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  468. }
  469. if (mErrno == JX_MYSQL50_MYSQL_ERROR)
  470. {
  471. const char *sError =mysql_stmt_error(mSTMT);
  472. aError.Assign(NS_ConvertUTF8toUTF16(sError));
  473. return NS_OK;
  474. }
  475. NON_MYSQL_ERROR(mErrno, aError);
  476. if (aError.Length() == 0)
  477. {
  478. const char* me = mysql_stmt_error(mSTMT);
  479. AppendUTF8toUTF16(nsPrintfCString(0x1000, "Unknown error 0x%0x. Last MYSQL error is %s", mErrno, (me && *me) ? me : ""), aError);
  480. }
  481. //_retval.Assign(NS_ConvertUTF8toUTF16(mysql_stmt_error(mSTMT)));
  482. return NS_OK;
  483. }
  484. static PRInt32 lenOfMySQL_TIME = sizeof(MYSQL_TIME);
  485. NS_IMETHODIMP jxMySQL50Statement::Execute(PRUint32 *_retval)
  486. {
  487. if (mConnection == nsnull)
  488. {
  489. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  490. }
  491. if (mSTMT == nsnull)
  492. {
  493. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  494. }
  495. *_retval = 1;
  496. // Assume the input parameters are all inited.
  497. // Get access to the array of parameter values and verify its length.
  498. if (mysql_stmt_bind_param(mSTMT, mIn.mBIND))
  499. {
  500. //Error
  501. *_retval = 1;
  502. SET_ERROR_RETURN (JX_MYSQL50_MYSQL_ERROR);
  503. }
  504. // Bind output fields if not done already.
  505. if (!mOut.mBIND && mOut.mCount > 0)
  506. {
  507. nsresult rv = BindOutput();
  508. if (NS_FAILED(rv))
  509. {
  510. *_retval = 1;
  511. SET_ERROR_RETURN (rv);
  512. }
  513. }
  514. if (mysql_stmt_execute(mSTMT))
  515. {
  516. *_retval = 1;
  517. SET_ERROR_RETURN (JX_MYSQL50_MYSQL_ERROR);
  518. }
  519. *_retval = 0;
  520. return NS_OK;
  521. }
  522. #if 0
  523. /* jxIMySQL50ResultSet storeResult(); */
  524. NS_IMETHODIMP
  525. jxMySQL50Statement::StoreResult(jxIMySQL50ResultSet **aReturn)
  526. {
  527. if (mConnection == nsnull)
  528. {
  529. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  530. }
  531. if (mSTMT == nsnull)
  532. {
  533. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  534. }
  535. if (! aReturn )
  536. {
  537. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NULL_POINTER);
  538. }
  539. // Spin up a ResultSet object, toss an exception if we can't create
  540. nsCOMPtr<jxIMySQL50ResultSet> res(do_CreateInstance(JX_MYSQL50RESULTSET_CONTRACTID));
  541. if (!res)
  542. {
  543. SET_ERROR_RETURN (JX_MYSQL50_ERROR_CANT_CREATEINSTANCE);
  544. }
  545. // Attach ourselves to the ResultSet object so it can make calls back to us if needed
  546. // res->SetMySQL50(mConnection);
  547. MYSQL *mysql;
  548. mConnection->GetMysql(&mysql);
  549. res->SetMySQL50(mConnection);
  550. nsresult rv = res->StoreResult(mysql);
  551. if (NS_FAILED(rv))
  552. {
  553. SET_ERROR_RETURN (rv);
  554. }
  555. // Return the ResultSet object to our caller
  556. *aReturn = res;
  557. NS_ADDREF(*aReturn);
  558. return NS_OK;
  559. }
  560. #endif
  561. /*
  562. *
  563. */
  564. NS_IMETHODIMP
  565. jxMySQL50Statement::BindDatetimeParameter(PRUint32 aParamIndex, PRUint32 aSecond)
  566. {
  567. if (mConnection == nsnull)
  568. {
  569. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  570. }
  571. if (mSTMT == nsnull)
  572. {
  573. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  574. }
  575. if (aParamIndex < 0 || aParamIndex >= mIn.mCount)
  576. {
  577. SET_ERROR_RETURN (JX_MYSQL50_ERROR_ILLEGAL_VALUE);
  578. }
  579. if (mIn.mBindArrayBufferTYPE_DATE[aParamIndex] == nsnull)
  580. mIn.mBindArrayBufferTYPE_DATE[aParamIndex] = static_cast<MYSQL_TIME*>(nsMemory::Alloc(sizeof(MYSQL_TIME)));
  581. if (mIn.mBindArrayBufferTYPE_DATE[aParamIndex] == nsnull)
  582. {
  583. SET_ERROR_RETURN (JX_MYSQL50_ERROR_OUT_OF_MEMORY);
  584. }
  585. time_t t = (time_t) aSecond;
  586. struct tm *tmptm = gmtime(&t);
  587. // struct tm *tmpltm = localtime(&t);
  588. #if 0
  589. PRTime t = aSecond * 1000;
  590. PRExplodedTime prtime;
  591. PR_ExplodeTime(t, PR_LocalTimeParameters, &prtime);
  592. #endif
  593. MYSQL_TIME* mysqlTime = mIn.mBindArrayBufferTYPE_DATE[aParamIndex];
  594. mysqlTime->year = tmptm->tm_year + 1900;
  595. mysqlTime->month = tmptm->tm_mon + 1;
  596. mysqlTime->day = tmptm->tm_mday;
  597. mysqlTime->hour = tmptm->tm_hour;
  598. mysqlTime->minute = tmptm->tm_min;
  599. mysqlTime->second = tmptm->tm_sec;
  600. mysqlTime->second_part = 0; /* mic's not supported in MySQL yet */
  601. mysqlTime->neg = 0;
  602. mysqlTime->time_type = MYSQL_TIMESTAMP_DATETIME;
  603. mIn.mBIND[aParamIndex].buffer_type = MYSQL_TYPE_DATETIME;
  604. mIn.mBIND[aParamIndex].buffer = mIn.mBindArrayBufferTYPE_DATE[aParamIndex];
  605. mIn.mBIND[aParamIndex].length = 0;
  606. mIn.mBIND[aParamIndex].length_value = lenOfMySQL_TIME;
  607. mIn.mBIND[aParamIndex].buffer_length = lenOfMySQL_TIME;
  608. return NS_OK;
  609. }
  610. /* void BindBooleanParameter (in unsigned long aParamIndex, in boolean aValue); */
  611. NS_IMETHODIMP
  612. jxMySQL50Statement::BindBooleanParameter(PRUint32 aParamIndex, PRBool aValue)
  613. {
  614. if (mConnection == nsnull)
  615. {
  616. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  617. }
  618. if (mSTMT == nsnull)
  619. {
  620. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  621. }
  622. if (aParamIndex < 0 || aParamIndex >= mIn.mCount)
  623. {
  624. SET_ERROR_RETURN (JX_MYSQL50_ERROR_ILLEGAL_VALUE);
  625. }
  626. mIn.mBindArrayBufferTYPE_BOOL[aParamIndex] = aValue;
  627. mIn.mBIND[aParamIndex].buffer_type = MYSQL_TYPE_TINY;
  628. mIn.mBIND[aParamIndex].buffer = &(mIn.mBindArrayBufferTYPE_BOOL[aParamIndex]);
  629. mIn.mBIND[aParamIndex].length = 0;
  630. mIn.mBIND[aParamIndex].is_null = 0;
  631. return NS_OK;
  632. }
  633. /* void bindUTF8TextParameter(in unsigned long aParamIndex, in AUTF8String aValue); */
  634. NS_IMETHODIMP
  635. jxMySQL50Statement::BindUTF8TextParameter(PRUint32 aParamIndex, const nsACString & aValue)
  636. {
  637. return BindUTF8StringParameter(aParamIndex, aValue);
  638. }
  639. /* void bindUTF8StringParameter (in unsigned long aParamIndex, in AUTF8String aValue); */
  640. NS_IMETHODIMP
  641. jxMySQL50Statement::BindUTF8StringParameter(PRUint32 aParamIndex, const nsACString & aValue)
  642. {
  643. if (mConnection == nsnull)
  644. {
  645. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  646. }
  647. if (mSTMT == nsnull)
  648. {
  649. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  650. }
  651. if (aParamIndex < 0 || aParamIndex >= mIn.mCount)
  652. {
  653. SET_ERROR_RETURN (JX_MYSQL50_ERROR_ILLEGAL_VALUE);
  654. }
  655. char* strp = (char*)(nsPromiseFlatCString(aValue).get());
  656. PRUint32 nBytes = strlen(strp);
  657. mIn.mBindArrayBufferTYPE_STRING_LEN_IN[aParamIndex] = nBytes;
  658. mIn.mBindArrayBufferTYPE_STRING[aParamIndex] = static_cast<char*>(nsMemory::Alloc(nBytes+1));
  659. if (!mIn.mBindArrayBufferTYPE_STRING[aParamIndex])
  660. {
  661. SET_ERROR_RETURN (JX_MYSQL50_ERROR_OUT_OF_MEMORY);
  662. }
  663. memcpy(mIn.mBindArrayBufferTYPE_STRING[aParamIndex], strp, nBytes);
  664. mIn.mBIND[aParamIndex].buffer_type = MYSQL_TYPE_STRING;
  665. mIn.mBIND[aParamIndex].buffer = mIn.mBindArrayBufferTYPE_STRING[aParamIndex];
  666. mIn.mBIND[aParamIndex].length = 0;
  667. mIn.mBIND[aParamIndex].length_value = nBytes;
  668. mIn.mBIND[aParamIndex].buffer_length = nBytes;
  669. mIn.mBIND[aParamIndex].is_null = 0;
  670. return NS_OK;
  671. }
  672. /* void bindStringParameter (in unsigned long aParamIndex, in AString aValue); */
  673. NS_IMETHODIMP
  674. jxMySQL50Statement::BindStringParameter(PRUint32 aParamIndex, const nsAString & aValue)
  675. {
  676. if (mConnection == nsnull)
  677. {
  678. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  679. }
  680. if (mSTMT == nsnull)
  681. {
  682. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  683. }
  684. if (aParamIndex < 0 || aParamIndex >= mIn.mCount)
  685. {
  686. SET_ERROR_RETURN (JX_MYSQL50_ERROR_ILLEGAL_VALUE);
  687. }
  688. //char *strp = (char*)(nsPromiseFlatString(aValue).get());
  689. nsCAutoString cstr = NS_ConvertUTF16toUTF8(aValue);
  690. const char *strp = cstr.get();
  691. PRUint32 nBytes = strlen(strp);
  692. mIn.mBindArrayBufferTYPE_STRING_LEN_IN[aParamIndex] = nBytes;
  693. mIn.mBindArrayBufferTYPE_STRING[aParamIndex] =
  694. static_cast<char*>(nsMemory::Alloc(nBytes+1));
  695. if (!mIn.mBindArrayBufferTYPE_STRING[aParamIndex])
  696. {
  697. SET_ERROR_RETURN (JX_MYSQL50_ERROR_OUT_OF_MEMORY);
  698. }
  699. memcpy(mIn.mBindArrayBufferTYPE_STRING[aParamIndex], strp, nBytes+1);
  700. mIn.mBIND[aParamIndex].buffer_type = MYSQL_TYPE_STRING;
  701. mIn.mBIND[aParamIndex].buffer = mIn.mBindArrayBufferTYPE_STRING[aParamIndex];
  702. //mIn.mBIND[aParamIndex].length = (unsigned long*)&(mIn.mBindArrayBufferTYPE_STRING_LEN_IN[aParamIndex]);
  703. mIn.mBIND[aParamIndex].length = 0;
  704. mIn.mBIND[aParamIndex].length_value = nBytes;
  705. mIn.mBIND[aParamIndex].buffer_length = nBytes;
  706. return NS_OK;
  707. }
  708. /* void bindDoubleParameter (in unsigned long aParamIndex, in double aValue); */
  709. NS_IMETHODIMP
  710. jxMySQL50Statement::BindDoubleParameter(PRUint32 aParamIndex, double aValue)
  711. {
  712. if (mConnection == nsnull)
  713. {
  714. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  715. }
  716. if (mSTMT == nsnull)
  717. {
  718. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  719. }
  720. if (aParamIndex < 0 || aParamIndex >= mIn.mCount)
  721. {
  722. SET_ERROR_RETURN (JX_MYSQL50_ERROR_ILLEGAL_VALUE);
  723. }
  724. mIn.mBindArrayBufferTYPE_DOUBLE[aParamIndex] = aValue;
  725. mIn.mBIND[aParamIndex].buffer_type = MYSQL_TYPE_DOUBLE;
  726. mIn.mBIND[aParamIndex].buffer = (char*)&(mIn.mBindArrayBufferTYPE_DOUBLE[aParamIndex]);
  727. mIn.mBIND[aParamIndex].length = 0;
  728. mIn.mBIND[aParamIndex].is_null = 0;
  729. return NS_OK;
  730. }
  731. /* void bindInt32Parameter (in unsigned long aParamIndex, in long aValue); */
  732. NS_IMETHODIMP
  733. jxMySQL50Statement::BindInt32Parameter(PRUint32 aParamIndex, PRInt32 aValue)
  734. {
  735. if (mConnection == nsnull)
  736. {
  737. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  738. }
  739. if (mSTMT == nsnull)
  740. {
  741. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  742. }
  743. if (aParamIndex < 0 || aParamIndex >= mIn.mCount)
  744. {
  745. SET_ERROR_RETURN (JX_MYSQL50_ERROR_ILLEGAL_VALUE);
  746. }
  747. mIn.mBindArrayBufferTYPE_DOUBLE[aParamIndex] = aValue;
  748. mIn.mBIND[aParamIndex].buffer_type = MYSQL_TYPE_DOUBLE; // MYSQL_TYPE_LONG;
  749. mIn.mBIND[aParamIndex].buffer = (char*)&(mIn.mBindArrayBufferTYPE_DOUBLE[aParamIndex]);
  750. mIn.mBIND[aParamIndex].length = 0;
  751. mIn.mBIND[aParamIndex].is_null = 0;
  752. return NS_OK;
  753. }
  754. /* void bindInt64Parameter (in unsigned long aParamIndex, in long long aValue); */
  755. NS_IMETHODIMP
  756. jxMySQL50Statement::BindInt64Parameter(PRUint32 aParamIndex, PRInt64 aValue)
  757. {
  758. if (mConnection == nsnull)
  759. {
  760. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  761. }
  762. if (mSTMT == nsnull)
  763. {
  764. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  765. }
  766. if (aParamIndex < 0 || aParamIndex >= mIn.mCount)
  767. {
  768. SET_ERROR_RETURN (JX_MYSQL50_ERROR_ILLEGAL_VALUE);
  769. }
  770. mIn.mBindArrayBufferTYPE_DOUBLE[aParamIndex] = aValue;
  771. mIn.mBIND[aParamIndex].buffer_type = MYSQL_TYPE_DOUBLE; // MYSQL_TYPE_LONGLONG;
  772. mIn.mBIND[aParamIndex].buffer = (char*) &(mIn.mBindArrayBufferTYPE_DOUBLE[aParamIndex]);
  773. mIn.mBIND[aParamIndex].length = 0;
  774. mIn.mBIND[aParamIndex].is_null = 0;
  775. return NS_OK;
  776. }
  777. /* void bindNullParameter (in unsigned long aParamIndex); */
  778. NS_IMETHODIMP
  779. jxMySQL50Statement::BindNullParameter(PRUint32 aParamIndex)
  780. {
  781. if (mConnection == nsnull)
  782. {
  783. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  784. }
  785. if (mSTMT == nsnull)
  786. {
  787. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  788. }
  789. if (aParamIndex < 0 || aParamIndex >= mIn.mCount)
  790. {
  791. SET_ERROR_RETURN (JX_MYSQL50_ERROR_ILLEGAL_VALUE);
  792. }
  793. mIn.mBindArrayBufferTYPE_BOOL[aParamIndex] = 1;
  794. mIn.mBIND[aParamIndex].buffer_type = MYSQL_TYPE_NULL;
  795. mIn.mBIND[aParamIndex].buffer = (char*)&(mIn.mBindArrayBufferTYPE_BOOL[aParamIndex]);
  796. mIn.mBIND[aParamIndex].length = 0;
  797. // This may not work
  798. mIn.mBIND[aParamIndex].is_null = (my_bool*) &(mIn.mBindArrayBufferTYPE_BOOL[aParamIndex]);
  799. return NS_OK;
  800. }
  801. /* void bindBlobParameter (in unsigned long aParamIndex, [array, const, size_is (aValueSize)] in octet aValue, in unsigned long aValueSize); */
  802. NS_IMETHODIMP
  803. jxMySQL50Statement::BindBlobParameter(PRUint32 aParamIndex, const PRUint8 *aValue, PRUint32 aValueSize)
  804. {
  805. if (mConnection == nsnull)
  806. {
  807. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  808. }
  809. if (mSTMT == nsnull)
  810. {
  811. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  812. }
  813. if (aParamIndex < 0 || aParamIndex >= mIn.mCount)
  814. {
  815. SET_ERROR_RETURN (JX_MYSQL50_ERROR_ILLEGAL_VALUE);
  816. }
  817. mIn.mBindArrayBufferTYPE_STRING_LEN_IN[aParamIndex] = aValueSize;
  818. mIn.mBindArrayBufferTYPE_STRING[aParamIndex] =
  819. static_cast<char*>(nsMemory::Alloc(aValueSize));
  820. if (!mIn.mBindArrayBufferTYPE_STRING[aParamIndex])
  821. {
  822. SET_ERROR_RETURN (JX_MYSQL50_ERROR_OUT_OF_MEMORY);
  823. }
  824. memcpy(mIn.mBindArrayBufferTYPE_STRING[aParamIndex], (void*)aValue, aValueSize);
  825. mIn.mBindArrayBufferTYPE_STRING_LEN_IN[aParamIndex] = aValueSize;
  826. mIn.mBIND[aParamIndex].buffer_type = MYSQL_TYPE_BLOB;
  827. mIn.mBIND[aParamIndex].buffer = mIn.mBindArrayBufferTYPE_STRING[aParamIndex];
  828. mIn.mBIND[aParamIndex].length = 0;
  829. mIn.mBIND[aParamIndex].length_value = mIn.mBindArrayBufferTYPE_STRING_LEN_IN[aParamIndex];
  830. mIn.mBIND[aParamIndex].buffer_length = mIn.mBindArrayBufferTYPE_STRING_LEN_IN[aParamIndex];
  831. return NS_OK;
  832. }
  833. /* [noscript] long init (in AString query); */
  834. NS_IMETHODIMP jxMySQL50Statement::Init(const nsAString & query, PRInt32 *_retval)
  835. {
  836. nsresult rv = NS_OK;
  837. if (mConnection == nsnull)
  838. {
  839. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  840. }
  841. if (mSTMT != nsnull)
  842. {
  843. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_ALREADY_INITIALIZED);
  844. }
  845. MYSQL * mysql;
  846. mConnection->GetMysql(&mysql);
  847. // Create a new statement handle
  848. if ((mSTMT = mysql_stmt_init(mysql)))
  849. {
  850. // Get the query string
  851. char * stmt = ToNewUTF8String(query);
  852. // Prepare the statement
  853. int ret = mysql_stmt_prepare(mSTMT, stmt, query.Length());
  854. nsMemory::Free(stmt);
  855. if (ret)
  856. {
  857. // Statement prep failed
  858. #if 0
  859. char err[512];
  860. sprintf(err, " %s", mysql_stmt_error(mSTMT));
  861. #endif
  862. *_retval = ret;
  863. SET_ERROR_RETURN (JX_MYSQL50_MYSQL_ERROR);
  864. }
  865. else
  866. {
  867. mIn.mCount = mysql_stmt_param_count(mSTMT);
  868. mOut.mCount = mysql_stmt_field_count(mSTMT);
  869. // Statement prep succeeded
  870. *_retval = 0;
  871. // Allocated the BIND array and supporting structures
  872. if (mIn.mBIND == nsnull && mIn.mCount > 0) {
  873. rv = mIn.Allocate();
  874. if (rv != NS_OK)
  875. {
  876. *_retval = -1;
  877. SET_ERROR_RETURN (rv);
  878. }
  879. }
  880. }
  881. }
  882. else {
  883. // Statement prep failed
  884. *_retval = -1;
  885. SET_ERROR_RETURN (JX_MYSQL50_MYSQL_ERROR);
  886. }
  887. return NS_OK;
  888. }
  889. /* long paramCount (); */
  890. NS_IMETHODIMP jxMySQL50Statement::ParamCount(PRInt32 *_retval)
  891. {
  892. if (mConnection == nsnull)
  893. {
  894. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  895. }
  896. if (mSTMT == nsnull)
  897. {
  898. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  899. }
  900. *_retval = mIn.mCount;
  901. return NS_OK;
  902. }
  903. /* AString SQLState (); */
  904. NS_IMETHODIMP jxMySQL50Statement::SQLState(nsAString & _retval)
  905. {
  906. if (mConnection == nsnull)
  907. {
  908. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  909. }
  910. if (mSTMT == nsnull)
  911. {
  912. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  913. }
  914. _retval.Assign(NS_ConvertUTF8toUTF16(mysql_stmt_sqlstate(mSTMT)));
  915. return NS_OK;
  916. }
  917. /* boolean dataSeek (in long long offset); */
  918. NS_IMETHODIMP jxMySQL50Statement::DataSeek(PRInt64 offset, PRBool *_retval)
  919. {
  920. if (mConnection == nsnull)
  921. {
  922. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  923. }
  924. if (mSTMT == nsnull)
  925. {
  926. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  927. }
  928. if (offset < 0 || offset >= mRowCount)
  929. {
  930. *_retval = PR_FALSE;
  931. SET_ERROR_RETURN (JX_MYSQL50_ERROR_ILLEGAL_VALUE);
  932. }
  933. mysql_stmt_data_seek(mSTMT, offset);
  934. *_retval = PR_TRUE;
  935. return NS_OK;
  936. }
  937. /* long long rowCount (); */
  938. NS_IMETHODIMP jxMySQL50Statement::RowCount(PRInt64 *aCount)
  939. {
  940. if (mConnection == nsnull)
  941. {
  942. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  943. }
  944. if (mSTMT == nsnull)
  945. {
  946. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  947. }
  948. *aCount = mysql_stmt_num_rows(mSTMT);
  949. return NS_OK;
  950. }
  951. /* unsigned long fieldCount (); */
  952. NS_IMETHODIMP jxMySQL50Statement::FieldCount(PRUint32 *aCount)
  953. {
  954. if (mConnection == nsnull)
  955. {
  956. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  957. }
  958. if (mSTMT == nsnull)
  959. {
  960. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  961. }
  962. *aCount = mOut.mCount;
  963. return NS_OK;
  964. }
  965. /* long long insertId (); */
  966. NS_IMETHODIMP jxMySQL50Statement::InsertId(PRInt64 *aID)
  967. {
  968. if (mConnection == nsnull)
  969. {
  970. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  971. }
  972. if (mSTMT == nsnull)
  973. {
  974. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  975. }
  976. *aID = mysql_stmt_insert_id(mSTMT);
  977. return NS_OK;
  978. }
  979. /* jxIMySQL50ResultSet resultMetadata (); */
  980. NS_IMETHODIMP jxMySQL50Statement::ResultMetadata(jxIMySQL50ResultSet **aReturn)
  981. {
  982. if (mConnection == nsnull)
  983. {
  984. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  985. }
  986. if (mSTMT == nsnull)
  987. {
  988. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  989. }
  990. // If we didn't get a valid place to return the ResultSet object pointer,
  991. // then cause an exception to be returned to JavaScript
  992. if (! aReturn )
  993. {
  994. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NULL_POINTER);
  995. }
  996. // Spin up a ResultSet object, toss an exception if we can't create
  997. nsCOMPtr<jxIMySQL50ResultSet> res(do_CreateInstance(JX_MYSQL50RESULTSET_CONTRACTID));
  998. if (!res)
  999. {
  1000. SET_ERROR_RETURN (JX_MYSQL50_ERROR_CANT_CREATEINSTANCE);
  1001. }
  1002. // Attach ourselves to the ResultSet object so it can make calls back to us if needed
  1003. res->SetMySQL50(mConnection);
  1004. // Capture the resultSet metadata
  1005. nsresult rv = res->GetMetaData(mSTMT);
  1006. if (NS_FAILED(rv))
  1007. {
  1008. SET_ERROR_RETURN (rv);
  1009. }
  1010. // Return the ResultSet object to our caller
  1011. *aReturn = res;
  1012. NS_ADDREF(*aReturn);
  1013. return NS_OK;
  1014. }
  1015. /* bool fetch (); */
  1016. NS_IMETHODIMP jxMySQL50Statement::Fetch(PRBool *_retval)
  1017. {
  1018. if (mConnection == nsnull)
  1019. {
  1020. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  1021. }
  1022. if (mSTMT == nsnull)
  1023. {
  1024. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  1025. }
  1026. PRInt32 ret = mysql_stmt_fetch(mSTMT);
  1027. *_retval = PR_FALSE;
  1028. if (!ret || ret == MYSQL_DATA_TRUNCATED) {
  1029. *_retval = PR_TRUE;
  1030. } else if (ret == MYSQL_NO_DATA) {
  1031. *_retval = PR_FALSE;
  1032. } else
  1033. {
  1034. // const char* err = mysql_stmt_error(mSTMT);
  1035. PRUint32 eno = mysql_stmt_errno(mSTMT);
  1036. if ( eno == 2050 || eno == 2051 || eno == 2052 || eno == 2053)
  1037. {
  1038. // No result set
  1039. return NS_OK;
  1040. }
  1041. SET_ERROR_RETURN (JX_MYSQL50_MYSQL_ERROR);
  1042. }
  1043. return NS_OK;
  1044. }
  1045. NS_IMETHODIMP
  1046. jxMySQL50Statement::GetInt32(PRUint32 aIndex, PRInt32 *_retval)
  1047. {
  1048. if (mConnection == nsnull)
  1049. {
  1050. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  1051. }
  1052. if (mSTMT == nsnull)
  1053. {
  1054. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  1055. }
  1056. if (aIndex < 0 || aIndex >= mOut.mCount)
  1057. {
  1058. SET_ERROR_RETURN (JX_MYSQL50_ERROR_ILLEGAL_VALUE);
  1059. }
  1060. if (mOut.mBindArrayIsNull[aIndex])
  1061. {
  1062. SET_ERROR_RETURN (JX_MYSQL50_ERROR_BIND_ARRAY_IS_NULL);
  1063. }
  1064. if (mOut.mBindArrayType[aIndex] != MYSQL_TYPE_DOUBLE)
  1065. {
  1066. SET_ERROR_RETURN (JX_MYSQL50_CANNOT_CONVERT_DATA);
  1067. }
  1068. double *dd = (double*)(&(mOut.mBindArrayBufferTYPE_DOUBLE[aIndex]));
  1069. *_retval = (PRInt32) *dd;
  1070. return NS_OK;
  1071. }
  1072. NS_IMETHODIMP
  1073. jxMySQL50Statement::GetInt64(PRUint32 aIndex, PRInt64 *_retval)
  1074. {
  1075. if (mConnection == nsnull)
  1076. {
  1077. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  1078. }
  1079. if (mSTMT == nsnull)
  1080. {
  1081. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  1082. }
  1083. if (aIndex < 0 || aIndex >= mOut.mCount)
  1084. {
  1085. SET_ERROR_RETURN (JX_MYSQL50_ERROR_ILLEGAL_VALUE);
  1086. }
  1087. double *dd = (double*)(&(mOut.mBindArrayBufferTYPE_DOUBLE[aIndex]));
  1088. PRInt64 n = (PRInt64) *dd;
  1089. *_retval = n;
  1090. return NS_OK;
  1091. }
  1092. NS_IMETHODIMP
  1093. jxMySQL50Statement::GetDouble(PRUint32 aIndex, double *_retval)
  1094. {
  1095. if (mConnection == nsnull)
  1096. {
  1097. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  1098. }
  1099. if (mSTMT == nsnull)
  1100. {
  1101. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  1102. }
  1103. if (aIndex < 0 || aIndex >= mOut.mCount)
  1104. {
  1105. SET_ERROR_RETURN (JX_MYSQL50_ERROR_ILLEGAL_VALUE);
  1106. }
  1107. double *dd = (double*)(&(mOut.mBindArrayBufferTYPE_DOUBLE[aIndex]));
  1108. *_retval = *dd;
  1109. return NS_OK;
  1110. }
  1111. NS_IMETHODIMP
  1112. jxMySQL50Statement::GetUTF8String(PRUint32 aIndex, nsACString &_retval)
  1113. {
  1114. if (mConnection == nsnull)
  1115. {
  1116. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  1117. }
  1118. if (mSTMT == nsnull)
  1119. {
  1120. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  1121. }
  1122. if (aIndex < 0 || aIndex >= mOut.mCount)
  1123. {
  1124. SET_ERROR_RETURN (JX_MYSQL50_ERROR_ILLEGAL_VALUE);
  1125. }
  1126. if (mOut.mBindArrayIsNull[aIndex]) {
  1127. // null columns get IsVoid set to distinguish them from empty strings
  1128. _retval.Truncate(0);
  1129. _retval.SetIsVoid(PR_TRUE);
  1130. } else {
  1131. PRUint32 slen = mOut.mBindArrayBufferTYPE_STRING_LEN_OUT[aIndex];
  1132. const char* cstr = mOut.mBindArrayBufferTYPE_STRING[aIndex];
  1133. _retval.Assign(cstr, slen);
  1134. }
  1135. return NS_OK;
  1136. }
  1137. NS_IMETHODIMP
  1138. jxMySQL50Statement::GetString(PRUint32 aIndex, nsAString & _retval)
  1139. {
  1140. if (mConnection == nsnull)
  1141. {
  1142. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  1143. }
  1144. if (mSTMT == nsnull)
  1145. {
  1146. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  1147. }
  1148. if (aIndex < 0 || aIndex >= mOut.mCount)
  1149. {
  1150. SET_ERROR_RETURN (JX_MYSQL50_ERROR_ILLEGAL_VALUE);
  1151. }
  1152. if (mOut.mBindArrayIsNull[aIndex]) {
  1153. // null columns get IsVoid set to distinguish them from empty strings
  1154. _retval.Truncate(0);
  1155. _retval.SetIsVoid(PR_TRUE);
  1156. } else {
  1157. // int slen = sqlite3_column_bytes16 (mSqliteStatement, aIndex);
  1158. // const PRUnichar *wstr = (const PRUnichar *) sqlite3_column_text16 (mSqliteStatement, aIndex);
  1159. PRUint32 slen = mOut.mBindArrayBufferTYPE_STRING_LEN_OUT[aIndex];
  1160. // const PRUnichar* wstr = (const PRUnichar *) mOut.mBindArrayBufferTYPE_STRING[aIndex];
  1161. //_retval.AssignASCII(mOut.mBindArrayBufferTYPE_STRING[aIndex], slen);
  1162. _retval = NS_ConvertUTF8toUTF16(mOut.mBindArrayBufferTYPE_STRING[aIndex], slen);
  1163. }
  1164. return NS_OK;
  1165. }
  1166. NS_IMETHODIMP
  1167. jxMySQL50Statement::GetDatetimeString(PRUint32 aIndex, nsAString &result)
  1168. {
  1169. if (mConnection == nsnull)
  1170. {
  1171. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  1172. }
  1173. if (mSTMT == nsnull)
  1174. {
  1175. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  1176. }
  1177. if (aIndex < 0 || aIndex >= mOut.mCount)
  1178. {
  1179. SET_ERROR_RETURN (JX_MYSQL50_ERROR_ILLEGAL_VALUE);
  1180. }
  1181. if (mOut.mBindArrayIsNull[aIndex]) {
  1182. // null columns get IsVoid set to distinguish them from empty strings
  1183. result.Truncate(0);
  1184. result.SetIsVoid(PR_TRUE);
  1185. } else {
  1186. MYSQL_TIME* mysqlTime = mOut.mBindArrayBufferTYPE_DATE[aIndex];
  1187. char buf[30];
  1188. sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d", mysqlTime->year, mysqlTime->month,
  1189. mysqlTime->day, mysqlTime->hour, mysqlTime->minute,
  1190. mysqlTime->second);
  1191. result.AssignASCII(buf);
  1192. }
  1193. return NS_OK;
  1194. }
  1195. NS_IMETHODIMP
  1196. jxMySQL50Statement::GetDateString(PRUint32 aIndex, nsAString &result)
  1197. {
  1198. if (mConnection == nsnull)
  1199. {
  1200. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  1201. }
  1202. if (mSTMT == nsnull)
  1203. {
  1204. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  1205. }
  1206. if (aIndex < 0 || aIndex >= mOut.mCount)
  1207. {
  1208. SET_ERROR_RETURN (JX_MYSQL50_ERROR_ILLEGAL_VALUE);
  1209. }
  1210. if (mOut.mBindArrayIsNull[aIndex]) {
  1211. // null columns get IsVoid set to distinguish them from empty strings
  1212. result.Truncate(0);
  1213. result.SetIsVoid(PR_TRUE);
  1214. } else {
  1215. MYSQL_TIME* mysqlTime = mOut.mBindArrayBufferTYPE_DATE[aIndex];
  1216. char buf[30];
  1217. sprintf(buf, "%04d-%02d-%02d", mysqlTime->year, mysqlTime->month,
  1218. mysqlTime->day);
  1219. result.AssignASCII(buf);
  1220. }
  1221. return NS_OK;
  1222. }
  1223. NS_IMETHODIMP
  1224. jxMySQL50Statement::GetTimeString(PRUint32 aIndex, nsAString &result)
  1225. {
  1226. if (mConnection == nsnull)
  1227. {
  1228. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  1229. }
  1230. if (mSTMT == nsnull)
  1231. {
  1232. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  1233. }
  1234. if (aIndex < 0 || aIndex >= mOut.mCount)
  1235. {
  1236. SET_ERROR_RETURN (JX_MYSQL50_ERROR_ILLEGAL_VALUE);
  1237. }
  1238. if (mOut.mBindArrayIsNull[aIndex]) {
  1239. // null columns get IsVoid set to distinguish them from empty strings
  1240. result.Truncate(0);
  1241. result.SetIsVoid(PR_TRUE);
  1242. } else {
  1243. MYSQL_TIME* mysqlTime = mOut.mBindArrayBufferTYPE_DATE[aIndex];
  1244. char buf[30];
  1245. sprintf(buf, "%02d:%02d:%02d", mysqlTime->hour, mysqlTime->minute,
  1246. mysqlTime->second);
  1247. result.AssignASCII(buf);
  1248. }
  1249. return NS_OK;
  1250. }
  1251. NS_IMETHODIMP
  1252. jxMySQL50Statement::GetBlob(PRUint32 aIndex, PRUint32 *aDataSize, PRUint8 **aData)
  1253. {
  1254. if (mConnection == nsnull)
  1255. {
  1256. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  1257. }
  1258. if (mSTMT == nsnull)
  1259. {
  1260. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  1261. }
  1262. if (aIndex < 0 || aIndex >= mOut.mCount)
  1263. {
  1264. SET_ERROR_RETURN (JX_MYSQL50_ERROR_ILLEGAL_VALUE);
  1265. }
  1266. int blobsize = mOut.mBindArrayBufferTYPE_STRING_LEN_OUT[aIndex];
  1267. if (blobsize > 0)
  1268. {
  1269. void *blob = static_cast<void*>(nsMemory::Alloc(blobsize));
  1270. if (blob == NULL)
  1271. {
  1272. SET_ERROR_RETURN (JX_MYSQL50_ERROR_OUT_OF_MEMORY);
  1273. }
  1274. my_bool is_null;
  1275. my_bool error;
  1276. unsigned long length;
  1277. MYSQL_BIND bind;
  1278. memset(&bind, 0, sizeof(bind));
  1279. bind.buffer_type = MYSQL_TYPE_BLOB;
  1280. bind.buffer= blob;
  1281. bind.buffer_length= blobsize;
  1282. bind.is_null= &is_null;
  1283. bind.length= &length;
  1284. bind.error= &error;
  1285. if (mysql_stmt_fetch_column(mSTMT, &bind, aIndex, 0))
  1286. {
  1287. SET_ERROR_RETURN (JX_MYSQL50_MYSQL_ERROR);
  1288. }
  1289. *aData = (PRUint8*) blob;
  1290. *aDataSize = blobsize;
  1291. }else
  1292. {
  1293. *aData = 0;
  1294. *aDataSize = 0;
  1295. }
  1296. return NS_OK;
  1297. }
  1298. NS_IMETHODIMP
  1299. jxMySQL50Statement::GetUTF8Text(PRUint32 aIndex, nsACString &aData)
  1300. {
  1301. if (mConnection == nsnull)
  1302. {
  1303. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  1304. }
  1305. if (mSTMT == nsnull)
  1306. {
  1307. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  1308. }
  1309. if (aIndex < 0 || aIndex >= mOut.mCount)
  1310. {
  1311. SET_ERROR_RETURN (JX_MYSQL50_ERROR_ILLEGAL_VALUE);
  1312. }
  1313. if (mOut.mBindArrayIsNull[aIndex]) {
  1314. // null columns get IsVoid set to distinguish them from empty strings
  1315. aData.Truncate(0);
  1316. aData.SetIsVoid(PR_TRUE);
  1317. }else
  1318. {
  1319. int nsize = mOut.mBindArrayBufferTYPE_STRING_LEN_OUT[aIndex];
  1320. char *data = static_cast<char*>(nsMemory::Alloc(nsize+1));
  1321. //extra for the null
  1322. if (data == NULL)
  1323. {
  1324. SET_ERROR_RETURN (JX_MYSQL50_ERROR_OUT_OF_MEMORY);
  1325. }
  1326. my_bool is_null;
  1327. my_bool error;
  1328. unsigned long length;
  1329. MYSQL_BIND bind;
  1330. memset(&bind, 0, sizeof(bind));
  1331. bind.buffer= (void*)data;
  1332. bind.buffer_length= nsize;
  1333. bind.buffer_type = MYSQL_TYPE_STRING;
  1334. bind.is_null= &is_null;
  1335. bind.length= &length;
  1336. bind.error= &error;
  1337. if (mysql_stmt_fetch_column(mSTMT, &bind, aIndex, 0))
  1338. {
  1339. SET_ERROR_RETURN (JX_MYSQL50_MYSQL_ERROR);
  1340. }
  1341. data[nsize] = 0;
  1342. aData = nsDependentCString(data, nsize);
  1343. }
  1344. return NS_OK;
  1345. }
  1346. /*
  1347. S_IMETHODIMP
  1348. jxMySQL50Statement::GetUTF8String(PRUint32 aIndex, nsACString &_retval)
  1349. {
  1350. if (mConnection == nsnull)
  1351. {
  1352. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  1353. }
  1354. if (mSTMT == nsnull)
  1355. {
  1356. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  1357. }
  1358. if (aIndex < 0 || aIndex >= mOut.mCount)
  1359. {
  1360. SET_ERROR_RETURN (JX_MYSQL50_ERROR_ILLEGAL_VALUE);
  1361. }
  1362. if (mOut.mBindArrayIsNull[aIndex]) {
  1363. // null columns get IsVoid set to distinguish them from empty strings
  1364. _retval.Truncate(0);
  1365. _retval.SetIsVoid(PR_TRUE);
  1366. } else {
  1367. PRUint32 slen = mOut.mBindArrayBufferTYPE_STRING_LEN_OUT[aIndex];
  1368. const char* cstr = mOut.mBindArrayBufferTYPE_STRING[aIndex];
  1369. _retval.Assign(cstr, slen);
  1370. }
  1371. return NS_OK;
  1372. }
  1373. */
  1374. NS_IMETHODIMP
  1375. jxMySQL50Statement::GetIsNull(PRUint32 aIndex, PRBool *_retval)
  1376. {
  1377. if (mConnection == nsnull)
  1378. {
  1379. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  1380. }
  1381. if (mSTMT == nsnull)
  1382. {
  1383. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  1384. }
  1385. if (aIndex < 0 || aIndex >= mOut.mCount)
  1386. {
  1387. SET_ERROR_RETURN (JX_MYSQL50_ERROR_ILLEGAL_VALUE);
  1388. }
  1389. *_retval = mOut.mBindArrayIsNull[aIndex];
  1390. return NS_OK;
  1391. }
  1392. /* AString getColumnDecltype(in unsigned long aParamIndex); */
  1393. NS_IMETHODIMP
  1394. jxMySQL50Statement::GetColumnDecltype(PRUint32 aParamIndex, nsACString& aDeclType)
  1395. {
  1396. if (mConnection == nsnull)
  1397. {
  1398. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  1399. }
  1400. if (mSTMT == nsnull)
  1401. {
  1402. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  1403. }
  1404. if (aParamIndex < 0 || aParamIndex >= mOut.mCount)
  1405. {
  1406. SET_ERROR_RETURN (JX_MYSQL50_ERROR_ILLEGAL_VALUE);
  1407. }
  1408. char *declType = 0;
  1409. switch (mOut.mBindArrayType[aParamIndex]) {
  1410. case MYSQL_TYPE_STRING:
  1411. declType = "string";
  1412. break;
  1413. case MYSQL_TYPE_BLOB:
  1414. declType = "blob";
  1415. break;
  1416. case MYSQL_TYPE_DOUBLE:
  1417. declType = "double";
  1418. break;
  1419. case MYSQL_TYPE_DATETIME:
  1420. declType = "datetime";
  1421. break;
  1422. case MYSQL_TYPE_DATE:
  1423. declType = "date";
  1424. break;
  1425. case MYSQL_TYPE_TIME:
  1426. declType = "time";
  1427. break;
  1428. case MYSQL_TYPE_NULL:
  1429. declType = "null";
  1430. default:
  1431. declType = "unknown";
  1432. break;
  1433. }
  1434. aDeclType.Assign(declType);
  1435. return NS_OK;
  1436. }
  1437. NS_IMETHODIMP
  1438. jxMySQL50Statement::GetColumnName(PRUint32 aParamIndex, nsACString& aName)
  1439. {
  1440. if (mConnection == nsnull)
  1441. {
  1442. SET_ERROR_RETURN (JX_MYSQL50_ERROR_NOT_CONNECTED);
  1443. }
  1444. if (mSTMT == nsnull)
  1445. {
  1446. SET_ERROR_RETURN (JX_MYSQL50_ERROR_STMT_NULL);
  1447. }
  1448. if (aParamIndex < 0 || aParamIndex >= mOut.mCount)
  1449. {
  1450. SET_ERROR_RETURN (JX_MYSQL50_ERROR_ILLEGAL_VALUE);
  1451. }
  1452. if (mSTMT->fields[aParamIndex].name)
  1453. aName.Assign(mSTMT->fields[aParamIndex].name, mSTMT->fields[aParamIndex].name_length);
  1454. else
  1455. aName.Assign("");
  1456. return NS_OK;
  1457. }