Sqlite.hx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /*
  2. * Copyright (C)2005-2017 Haxe Foundation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is 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
  20. * DEALINGS IN THE SOFTWARE.
  21. */
  22. package sys.db;
  23. import haxe.crypto.BaseCode;
  24. private typedef SqliteConnectionHandle = hl.Abstract<"sqlite_database">;
  25. private typedef SqliteResultHandle = hl.Abstract<"sqlite_result">;
  26. @:hlNative("sqlite")
  27. private class SqliteLib
  28. {
  29. public static function connect( path : hl.Bytes ) : SqliteConnectionHandle { return null; }
  30. public static function close( c : SqliteConnectionHandle ) : Void { }
  31. public static function request( c : SqliteConnectionHandle, sql : hl.Bytes ) : SqliteResultHandle { return null; }
  32. public static function last_id( c : SqliteConnectionHandle ) : Int { return 0; }
  33. public static function result_next( c : SqliteResultHandle ) : hl.NativeArray<Dynamic> { return null; }
  34. public static function result_get( c : SqliteResultHandle, n : Int ) : Null<hl.Bytes> { return null; }
  35. public static function result_get_int( c : SqliteResultHandle, n : Int ) : Null<Int> { return 0; }
  36. public static function result_get_float( c : SqliteResultHandle, n : Int ) : Null<Float> { return .0; }
  37. public static function result_get_length( c : SqliteResultHandle ) : Null<Int> { return 0; }
  38. public static function result_get_nfields( c : SqliteResultHandle ) : Int { return 0; }
  39. public static function result_get_fields( c : SqliteResultHandle ) : hl.NativeArray<hl.Bytes> { return null; }
  40. }
  41. @:access(Sys)
  42. @:access(String)
  43. private class SqliteConnection implements Connection
  44. {
  45. var c : SqliteConnectionHandle;
  46. public function new( file : String )
  47. {
  48. c = SqliteLib.connect(Sys.getPath(file));
  49. }
  50. public function close( ) : Void
  51. {
  52. SqliteLib.close(c);
  53. }
  54. public function request( s : String ) : ResultSet
  55. {
  56. try
  57. {
  58. var r : SqliteResultHandle = SqliteLib.request(c, s.bytes);
  59. return new SqliteResultSet(r);
  60. }
  61. catch ( e : String )
  62. {
  63. throw 'Error while executing $s ($e)';
  64. }
  65. return null;
  66. }
  67. public function escape( s : String ) : String
  68. {
  69. return s.split("'").join("''");
  70. }
  71. public function quote( s : String ) : String
  72. {
  73. if( s.indexOf("\000") >= 0 )
  74. return "x'" + BaseCode.encode(s, "0123456789ABCDEF") + "'";
  75. return "'" + s.split("'").join("''") + "'";
  76. }
  77. public function addValue( s : StringBuf, v : Dynamic ) : Void
  78. {
  79. switch( Type.typeof(v) )
  80. {
  81. case TNull, TInt: s.add(v);
  82. case TBool: s.add( v ? 1 : 0);
  83. case _: s.add(quote(Std.string(v)));
  84. }
  85. }
  86. public function lastInsertId( ) : Int
  87. {
  88. return SqliteLib.last_id(c);
  89. }
  90. public function dbName( ) : String
  91. {
  92. return "SQLite";
  93. }
  94. public function startTransaction( ) : Void
  95. {
  96. request("BEGIN TRANSACTION");
  97. }
  98. public function commit( ) : Void
  99. {
  100. request("COMMIT");
  101. startTransaction(); // match mysql usage
  102. }
  103. public function rollback( ) : Void
  104. {
  105. request("ROLLBACK");
  106. startTransaction(); // match mysql usage
  107. }
  108. }
  109. @:access(String)
  110. private class SqliteResultSet implements ResultSet
  111. {
  112. public var length(get,null) : Int;
  113. public var nfields(get,null) : Int;
  114. var names : Array<String>;
  115. var cache : List<Dynamic>;
  116. var r : SqliteResultHandle;
  117. public function new( r : SqliteResultHandle )
  118. {
  119. cache = new List();
  120. this.r = r;
  121. hasNext(); // execute the request
  122. }
  123. function get_length( ) : Int
  124. {
  125. if ( nfields != 0 )
  126. {
  127. while ( true )
  128. {
  129. var c = doNext();
  130. if( c == null )
  131. break;
  132. cache.add(c);
  133. }
  134. return cache.length;
  135. }
  136. return SqliteLib.result_get_length(r);
  137. }
  138. function get_nfields( ) : Int
  139. {
  140. return SqliteLib.result_get_nfields(r);
  141. }
  142. public function hasNext( ) : Bool
  143. {
  144. var c = next();
  145. if( c == null )
  146. return false;
  147. cache.push(c);
  148. return true;
  149. }
  150. public function next( ) : Dynamic
  151. {
  152. var c = cache.pop();
  153. if( c != null )
  154. return c;
  155. return doNext();
  156. }
  157. private function doNext( ) : Dynamic
  158. {
  159. var o : Dynamic = {};
  160. var a = SqliteLib.result_next(r);
  161. if( a == null )
  162. return null;
  163. var names = getFieldsNames();
  164. var i = 0 ;
  165. var l = names.length;
  166. while ( i < l )
  167. {
  168. var n : String = names[i];
  169. var v : Dynamic = a[i];
  170. if ( hl.Type.getDynamic(v).kind == hl.Type.TypeKind.HBytes )
  171. Reflect.setField(o, n, String.fromUCS2(v));
  172. else
  173. Reflect.setField(o, n, v);
  174. i++;
  175. }
  176. return o;
  177. }
  178. public function results( ) : List<Dynamic>
  179. {
  180. var l = new List();
  181. while ( true )
  182. {
  183. var c = next();
  184. if( c == null )
  185. break;
  186. l.add(c);
  187. }
  188. return l;
  189. }
  190. public function getResult( n : Int ) : String
  191. {
  192. var bytes = SqliteLib.result_get(r, n);
  193. if ( bytes == null )
  194. return null;
  195. return String.fromUCS2(bytes);
  196. }
  197. public function getIntResult( n : Int ) : Int
  198. {
  199. return SqliteLib.result_get_int(r,n);
  200. }
  201. public function getFloatResult( n : Int ) : Float
  202. {
  203. return SqliteLib.result_get_float(r,n);
  204. }
  205. public function getFieldsNames( ) : Array<String>
  206. {
  207. if ( this.names != null )
  208. return this.names;
  209. this.names = [];
  210. var names = SqliteLib.result_get_fields(r);
  211. var i = 0;
  212. var l = names.length;
  213. while ( i < l )
  214. {
  215. var name = String.fromUCS2(names[i]);
  216. this.names.push(name);
  217. i++;
  218. }
  219. return this.names;
  220. }
  221. }
  222. @:coreApi class Sqlite
  223. {
  224. public static function open( file : String ) : Connection
  225. {
  226. return new SqliteConnection(file);
  227. }
  228. }