PageRenderTime 39ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/Languages/IronPython/IronPython.SQLite/Cursor.cs

http://github.com/IronLanguages/main
C# | 598 lines | 467 code | 113 blank | 18 comment | 104 complexity | 7217f3a4eb170aa54988edc3d4ade408 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Jeff Hardy 2010-2012.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System.Collections;
  16. using System.Collections.Generic;
  17. using System.Runtime.InteropServices;
  18. using System.Text.RegularExpressions;
  19. using Community.CsharpSqlite;
  20. using IronPython.Runtime;
  21. using IronPython.Runtime.Exceptions;
  22. using IronPython.Runtime.Operations;
  23. using Microsoft.Scripting.Runtime;
  24. using Microsoft.Scripting.Utils;
  25. using sqlite3_stmt = Community.CsharpSqlite.Sqlite3.Vdbe;
  26. namespace IronPython.SQLite
  27. {
  28. public static partial class PythonSQLite
  29. {
  30. [PythonType]
  31. public class Cursor : IEnumerable
  32. {
  33. public const string __doc__ = "SQLite database cursor class.";
  34. Statement statement;
  35. object next_row;
  36. bool resultsDone;
  37. int last_step_rc;
  38. List<object> row_cast_map = new List<object>();
  39. public PythonTuple description { get; private set; }
  40. public int rowcount { get; private set; }
  41. public int? rownumber
  42. {
  43. get { return null; }
  44. }
  45. public long? lastrowid { get; private set; }
  46. public object row_factory { get; set; }
  47. public int arraysize { get; set; }
  48. public Connection connection { get; private set; }
  49. public object callproc(string procname)
  50. {
  51. throw PythonSQLite.MakeNotSupportedError();
  52. }
  53. private CodeContext context;
  54. public Cursor(CodeContext context, Connection connection)
  55. {
  56. this.context = context;
  57. this.connection = connection;
  58. this.arraysize = 1;
  59. this.rowcount = -1;
  60. if(this.connection != null)
  61. this.connection.checkThread();
  62. }
  63. ~Cursor()
  64. {
  65. if(this.statement != null)
  66. this.statement.Reset();
  67. }
  68. [Documentation("Closes the cursor.")]
  69. public void close()
  70. {
  71. connection.checkThread(); connection.checkConnection();
  72. if(this.statement != null)
  73. {
  74. this.statement.Reset();
  75. }
  76. }
  77. [Documentation("Executes a SQL statement.")]
  78. public object execute(CodeContext context, object operation, [Optional][DefaultParameterValue(null)]object args)
  79. {
  80. return queryExecute(context, false, operation, args);
  81. }
  82. [Documentation("Repeatedly executes a SQL statement.")]
  83. public object executemany(CodeContext context, object operation, object args)
  84. {
  85. return queryExecute(context, true, operation, args);
  86. }
  87. private object queryExecute(CodeContext context, bool multiple, object operation_obj, object args)
  88. {
  89. if(!(operation_obj is string))
  90. throw CreateThrowable(PythonExceptions.ValueError, "operation parameter must be str or unicode");
  91. string operation = (string)operation_obj;
  92. if(string.IsNullOrEmpty(operation))
  93. return null;
  94. int rc;
  95. connection.checkThread(); connection.checkConnection();
  96. this.next_row = null;
  97. IEnumerator parameters_iter = null;
  98. if(multiple)
  99. {
  100. if(args != null)
  101. parameters_iter = PythonOps.CreatePythonEnumerator(args);
  102. }
  103. else
  104. {
  105. object[] parameters_list = { args };
  106. if(parameters_list[0] == null)
  107. parameters_list[0] = new PythonTuple();
  108. parameters_iter = parameters_list.GetEnumerator();
  109. }
  110. if(this.statement != null)
  111. rc = this.statement.Reset();
  112. this.description = null;
  113. this.rowcount = -1;
  114. // TODO: use stmt cache instead ?
  115. this.statement = (Statement)this.connection.__call__(operation);
  116. if(this.statement.in_use)
  117. this.statement = new Statement(connection, operation);
  118. this.statement.Reset();
  119. this.statement.MarkDirty();
  120. if(!string.IsNullOrEmpty(connection.begin_statement))
  121. {
  122. switch(statement.StatementType)
  123. {
  124. case StatementType.Update:
  125. case StatementType.Insert:
  126. case StatementType.Delete:
  127. case StatementType.Replace:
  128. if(!connection.inTransaction)
  129. connection.begin();
  130. break;
  131. case StatementType.Other:
  132. // it's a DDL statement or something similar
  133. // we better COMMIT first so it works for all cases
  134. if(connection.inTransaction)
  135. connection.commit();
  136. break;
  137. case StatementType.Select:
  138. if(multiple)
  139. throw MakeProgrammingError("You cannot execute SELECT statements in executemany().");
  140. break;
  141. default:
  142. break;
  143. }
  144. }
  145. while(true)
  146. {
  147. if(!parameters_iter.MoveNext())
  148. break;
  149. object parameters = parameters_iter.Current;
  150. this.statement.MarkDirty();
  151. this.statement.BindParameters(context, parameters);
  152. while(true)
  153. {
  154. rc = this.statement.RawStep();
  155. if(rc == Sqlite3.SQLITE_DONE || rc == Sqlite3.SQLITE_ROW)
  156. break;
  157. rc = this.statement.Reset();
  158. if(rc == Sqlite3.SQLITE_SCHEMA)
  159. {
  160. rc = this.statement.Recompile(context, parameters);
  161. if(rc == Sqlite3.SQLITE_OK)
  162. {
  163. continue;
  164. }
  165. else
  166. {
  167. this.statement.Reset();
  168. throw GetSqliteError(this.connection.db, null);
  169. }
  170. }
  171. else
  172. {
  173. this.statement.Reset();
  174. throw GetSqliteError(this.connection.db, null);
  175. }
  176. }
  177. if(!buildRowCastMap())
  178. throw MakeOperationalError("Error while building row_cast_map");
  179. if(rc == Sqlite3.SQLITE_ROW || (rc == Sqlite3.SQLITE_DONE && this.statement.StatementType == StatementType.Select))
  180. {
  181. if(this.description == null)
  182. {
  183. int numcols = Sqlite3.sqlite3_column_count(this.statement.st);
  184. object[] new_description = new object[numcols];
  185. for(int i = 0; i < numcols; ++i)
  186. {
  187. string name = buildColumnName(Sqlite3.sqlite3_column_name(this.statement.st, i));
  188. object descriptor = new object[] {
  189. name,
  190. (object)null,
  191. (int?)null,
  192. (int?)null,
  193. (int?)null,
  194. (int?)null,
  195. (bool?)null
  196. };
  197. new_description[i] = new PythonTuple(descriptor);
  198. }
  199. this.description = new PythonTuple(new_description);
  200. }
  201. }
  202. if(rc == Sqlite3.SQLITE_ROW)
  203. {
  204. if(multiple)
  205. throw MakeProgrammingError("executemany() can only execute DML statements.");
  206. this.next_row = fetchOneRow(context);
  207. }
  208. else if(rc == Sqlite3.SQLITE_DONE && !multiple)
  209. {
  210. this.statement.Reset();
  211. }
  212. switch(this.statement.StatementType)
  213. {
  214. case StatementType.Update:
  215. case StatementType.Delete:
  216. case StatementType.Insert:
  217. case StatementType.Replace:
  218. if(this.rowcount == -1)
  219. this.rowcount = 0;
  220. this.rowcount += Sqlite3.sqlite3_changes(this.connection.db);
  221. break;
  222. }
  223. if(!multiple && this.statement.StatementType == StatementType.Insert)
  224. {
  225. this.lastrowid = Sqlite3.sqlite3_last_insert_rowid(this.connection.db);
  226. }
  227. else
  228. {
  229. this.lastrowid = null;
  230. }
  231. if(multiple)
  232. rc = this.statement.Reset();
  233. }
  234. return this;
  235. }
  236. private string buildColumnName(string colname)
  237. {
  238. int n = colname.IndexOf('[');
  239. return n < 0 ? colname : colname.Substring(0, n).Trim();
  240. }
  241. private object fetchOneRow(CodeContext context)
  242. {
  243. int numcols = Sqlite3.sqlite3_data_count(this.statement.st);
  244. object[] row = new object[numcols];
  245. object converter = null;
  246. for(int i = 0; i < numcols; ++i)
  247. {
  248. object converted = null;
  249. if(this.connection.detect_types != 0)
  250. {
  251. converter = row_cast_map[i];
  252. }
  253. else
  254. {
  255. converter = null;
  256. }
  257. if(converter != null)
  258. {
  259. byte[] val = Sqlite3.sqlite3_column_blob(this.statement.st, i);
  260. if(val == null)
  261. {
  262. converted = null;
  263. }
  264. else
  265. {
  266. string item = Latin1.GetString(val, 0, val.Length);
  267. converted = PythonCalls.Call(context, converter, item);
  268. }
  269. }
  270. else
  271. {
  272. int coltype = Sqlite3.sqlite3_column_type(this.statement.st, i);
  273. switch(coltype)
  274. {
  275. case Sqlite3.SQLITE_NULL:
  276. converted = null;
  277. break;
  278. case Sqlite3.SQLITE_INTEGER:
  279. long l = Sqlite3.sqlite3_column_int64(this.statement.st, i);
  280. if(l < int.MinValue || l > int.MaxValue)
  281. converted = l;
  282. else
  283. converted = (int)l;
  284. break;
  285. case Sqlite3.SQLITE_FLOAT:
  286. converted = Sqlite3.sqlite3_column_double(this.statement.st, i);
  287. break;
  288. case Sqlite3.SQLITE_TEXT:
  289. converted = Sqlite3.sqlite3_column_text(this.statement.st, i);
  290. break;
  291. case Sqlite3.SQLITE_BLOB:
  292. default:
  293. byte[] blob = Sqlite3.sqlite3_column_blob(this.statement.st, i);
  294. PythonBuffer buffer = new PythonBuffer(context, blob);
  295. converted = buffer;
  296. break;
  297. }
  298. }
  299. row[i] = converted;
  300. }
  301. return new PythonTuple(row);
  302. }
  303. public Cursor executescript(string operation)
  304. {
  305. connection.checkThread(); connection.checkConnection();
  306. this.connection.commit();
  307. sqlite3_stmt statement = null;
  308. string script = operation;
  309. bool statement_completed = false;
  310. while(true)
  311. {
  312. if(Sqlite3.sqlite3_complete(operation) == 0)
  313. break;
  314. statement_completed = true;
  315. int rc = Sqlite3.sqlite3_prepare(this.connection.db,
  316. operation,
  317. -1,
  318. ref statement,
  319. ref script);
  320. if(rc != Sqlite3.SQLITE_OK)
  321. throw GetSqliteError(this.connection.db, null);
  322. /* execute statement, and ignore results of SELECT statements */
  323. rc = Sqlite3.SQLITE_ROW;
  324. while(rc == Sqlite3.SQLITE_ROW)
  325. rc = Sqlite3.sqlite3_step(statement);
  326. if(rc != Sqlite3.SQLITE_DONE)
  327. {
  328. Sqlite3.sqlite3_finalize(statement);
  329. throw GetSqliteError(this.connection.db, null);
  330. }
  331. rc = Sqlite3.sqlite3_finalize(statement);
  332. if(rc != Sqlite3.SQLITE_OK)
  333. throw GetSqliteError(this.connection.db, null);
  334. }
  335. if(!statement_completed)
  336. throw MakeProgrammingError("you did not provide a complete SQL statement");
  337. return this;
  338. }
  339. public object __iter__()
  340. {
  341. return this;
  342. }
  343. public object next(CodeContext context)
  344. {
  345. object next_row_tuple, next_row;
  346. connection.checkThread(); connection.checkConnection();
  347. if(this.next_row == null)
  348. {
  349. if(this.statement != null)
  350. {
  351. this.statement.Reset();
  352. this.statement = null;
  353. }
  354. throw new StopIterationException();
  355. }
  356. next_row_tuple = this.next_row;
  357. this.next_row = null;
  358. if(this.row_factory != null)
  359. {
  360. next_row = PythonCalls.Call(context, this.row_factory, this, next_row_tuple);
  361. }
  362. else
  363. {
  364. next_row = next_row_tuple;
  365. }
  366. if(this.statement != null)
  367. {
  368. int rc = this.statement.RawStep();
  369. if(rc != Sqlite3.SQLITE_DONE && rc != Sqlite3.SQLITE_ROW)
  370. {
  371. this.statement.Reset();
  372. throw GetSqliteError(this.connection.db, this.statement.st);
  373. }
  374. if(rc == Sqlite3.SQLITE_ROW)
  375. this.next_row = fetchOneRow(context);
  376. }
  377. return next_row;
  378. }
  379. [Documentation("Fetches one row from the resultset.")]
  380. public object fetchone(CodeContext context)
  381. {
  382. try
  383. {
  384. return this.next(context);
  385. }
  386. catch(StopIterationException)
  387. {
  388. return null;
  389. }
  390. }
  391. public object fetchmany(CodeContext context)
  392. {
  393. return fetchmany(context, this.arraysize);
  394. }
  395. [Documentation("Fetches several rows from the resultset.")]
  396. public object fetchmany(CodeContext context, int size)
  397. {
  398. List result = new List();
  399. object item = fetchone(context);
  400. for(int i = 0; i < size && item != null; ++i, item = fetchone(context))
  401. result.Add(item);
  402. return result;
  403. }
  404. [Documentation("Fetches all rows from the resultset.")]
  405. public object fetchall(CodeContext context)
  406. {
  407. List result = new List();
  408. object item = fetchone(context);
  409. while(item != null)
  410. {
  411. result.Add(item);
  412. item = fetchone(context);
  413. }
  414. return result;
  415. }
  416. public object nextset()
  417. {
  418. return null;
  419. }
  420. [Documentation("Required by DB-API. Does nothing in IronPython.Sqlite3.")]
  421. public void setinputsizes(object sizes) { }
  422. [Documentation("Required by DB-API. Does nothing in IronPython.Sqlite3.")]
  423. public void setoutputsize(params object[] args) { }
  424. private bool buildRowCastMap()
  425. {
  426. if(this.connection.detect_types == 0)
  427. return true;
  428. row_cast_map = new List<object>();
  429. object converter = null;
  430. for(int i = 0; i < Sqlite3.sqlite3_column_count(this.statement.st); ++i)
  431. {
  432. converter = null;
  433. if((this.connection.detect_types & PARSE_COLNAMES) != 0)
  434. {
  435. string colname = Sqlite3.sqlite3_column_name(this.statement.st, i);
  436. if(colname != null)
  437. {
  438. Regex matchColname = new Regex(@"\[(\w+)\]");
  439. Match match = matchColname.Match(colname);
  440. if(match.Success)
  441. {
  442. string key = match.Groups[1].ToString();
  443. converter = getConverter(key);
  444. }
  445. }
  446. }
  447. if((converter == null) && ((this.connection.detect_types & PARSE_DECLTYPES) != 0))
  448. {
  449. string decltype = Sqlite3.sqlite3_column_decltype(this.statement.st, i);
  450. if(decltype != null)
  451. {
  452. Regex matchDecltype = new Regex(@"\b(\w+)\b");
  453. Match match = matchDecltype.Match(decltype);
  454. if(match.Success)
  455. {
  456. string py_decltype = match.Groups[1].ToString();
  457. converter = getConverter(py_decltype);
  458. }
  459. }
  460. }
  461. row_cast_map.Add(converter);
  462. }
  463. return true;
  464. }
  465. private object getConverter(string key)
  466. {
  467. object converter;
  468. return converters.TryGetValue(key.ToUpperInvariant(), out converter) ? converter : null;
  469. }
  470. #region IEnumerable Members
  471. public IEnumerator GetEnumerator()
  472. {
  473. List results = new List();
  474. try
  475. {
  476. while(true)
  477. results.append(this.next(this.context));
  478. }
  479. catch(StopIterationException) { }
  480. return results.GetEnumerator();
  481. }
  482. #endregion
  483. }
  484. }
  485. }