Parcourir la source

add hl SQLite (#5822)

Added SQLite support
Constantine Teplyakov il y a 8 ans
Parent
commit
d832834da0
1 fichiers modifiés avec 278 ajouts et 0 suppressions
  1. 278 0
      std/hl/_std/sys/db/Sqlite.hx

+ 278 - 0
std/hl/_std/sys/db/Sqlite.hx

@@ -0,0 +1,278 @@
+/*
+ * Copyright (C)2005-2016 Haxe Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+package sys.db;
+import haxe.crypto.BaseCode;
+
+private typedef SqliteConnectionHandle = hl.types.NativeAbstract<"sqlite_database">;
+private typedef SqliteResultHandle = hl.types.NativeAbstract<"sqlite_result">;
+
+@:hlNative("sqlite")
+private class SqliteLib
+{
+	public static function connect( path : hl.types.Bytes ) : SqliteConnectionHandle { return null; }
+	public static function close( c : SqliteConnectionHandle ) : Void { }
+	public static function request( c : SqliteConnectionHandle, sql : hl.types.Bytes ) : SqliteResultHandle { return null; }
+	public static function last_id( c : SqliteConnectionHandle ) : Int { return 0; }
+	
+	public static function result_next( c : SqliteResultHandle ) : hl.types.NativeArray<Dynamic> { return null; }
+	
+	public static function result_get( c : SqliteResultHandle, n : Int ) : Null<hl.types.Bytes> { return null; }
+	public static function result_get_int( c : SqliteResultHandle, n : Int ) : Null<Int> { return 0; }
+	public static function result_get_float( c : SqliteResultHandle, n : Int ) : Null<Float> { return .0; }
+	public static function result_get_length( c : SqliteResultHandle ) : Null<Int> { return 0; }
+	public static function result_get_nfields( c : SqliteResultHandle ) : Int { return 0; }
+	public static function result_get_fields( c : SqliteResultHandle ) : hl.types.NativeArray<hl.types.Bytes> { return null; }
+}
+
+
+@:access(Sys)
+@:access(String)
+private class SqliteConnection implements Connection
+{
+	
+	var c : SqliteConnectionHandle;
+
+	public function new( file : String )
+	{
+		c = SqliteLib.connect(Sys.getPath(file));
+	}
+	
+	public function close( ) : Void
+	{
+		SqliteLib.close(c);
+	}
+	
+	public function request( s : String ) : ResultSet
+	{
+		try
+		{
+			var r : SqliteResultHandle = SqliteLib.request(c, s.bytes);
+			
+			return new SqliteResultSet(r);
+		}
+		catch ( e : String )
+		{
+			throw 'Error while executing $s ($e)';
+		}
+		
+		return null;
+	}
+	
+	public function escape( s : String ) : String
+	{
+		return s.split("'").join("''");
+	}
+	
+	public function quote( s : String ) : String
+	{
+		if( s.indexOf("\000") >= 0 )
+			return "x'" + BaseCode.encode(s, "0123456789ABCDEF") + "'";
+		
+		return "'" + s.split("'").join("''") + "'";
+	}
+	
+	public function addValue( s : StringBuf, v : Dynamic ) : Void
+	{
+		switch( Type.typeof(v) )
+		{
+			case TNull, TInt: s.add(v);
+			case TBool: s.add( v ? 1 : 0);
+			case _: s.add(quote(Std.string(v)));
+		}
+	}
+	
+	public function lastInsertId( ) : Int
+	{
+		return SqliteLib.last_id(c);
+	}
+	
+	public function dbName( ) : String
+	{
+		return "SQLite";
+	}
+	
+	public function startTransaction( ) : Void
+	{
+		request("BEGIN TRANSACTION");
+	}
+	
+	public function commit( ) : Void
+	{
+		request("COMMIT");
+		startTransaction(); // match mysql usage
+	}
+	
+	public function rollback( ) : Void
+	{
+		request("ROLLBACK");
+		startTransaction(); // match mysql usage
+	}
+}
+
+
+
+@:access(String)
+private class SqliteResultSet implements ResultSet
+{
+	public var length(get,null) : Int;
+	public var nfields(get,null) : Int;
+	
+	var names : Array<String>;
+	var cache : List<Dynamic>;
+	
+	var r : SqliteResultHandle;
+	
+	public function new( r : SqliteResultHandle )
+	{
+		cache = new List();
+		this.r = r;
+		hasNext(); // execute the request
+	}
+	
+	function get_length( ) : Int
+	{
+		if ( nfields != 0 )
+		{
+			while ( true )
+			{
+				var c = doNext();
+				if( c == null )
+					break;
+				
+				cache.add(c);
+			}
+			
+			return cache.length;
+		}
+		
+		return SqliteLib.result_get_length(r);
+	}
+	
+	function get_nfields( ) : Int
+	{
+		return SqliteLib.result_get_nfields(r);
+	}
+	
+	public function hasNext( ) : Bool
+	{
+		var c = next();
+		if( c == null )
+			return false;
+		
+		cache.push(c);
+		
+		return true;
+	}
+	
+	public function next( ) : Dynamic
+	{
+		var c = cache.pop();
+		if( c != null )
+			return c;
+		
+		return doNext();
+	}
+	
+	private function doNext( ) : Dynamic
+	{
+		var o : Dynamic = {};
+		var a = SqliteLib.result_next(r);
+		if( a == null )
+			return null;
+		
+		var names = getFieldsNames();
+		var i = 0 ;
+		var l = names.length;
+		while ( i < l )
+		{
+			var n : String = names[i];
+			var v : Dynamic = a[i];
+			if ( hl.types.Type.getDynamic(v).kind == hl.types.Type.TypeKind.HBytes )
+				Reflect.setField(o, n, String.fromUCS2(v));
+			else
+				Reflect.setField(o, n, v);
+			i++;
+		}
+		return o;
+	}
+	
+	public function results( ) : List<Dynamic>
+	{
+		var l = new List();
+		while ( true )
+		{
+			var c = next();
+			if( c == null )
+				break;
+			
+			l.add(c);
+		}
+		
+		return l;
+	}
+	
+	public function getResult( n : Int ) : String
+	{
+		var bytes = SqliteLib.result_get(r, n);
+		if ( bytes == null )
+			return null;
+		
+		return String.fromUCS2(bytes);
+	}
+	
+	public function getIntResult( n : Int ) : Int
+	{
+		return SqliteLib.result_get_int(r,n);
+	}
+	
+	public function getFloatResult( n : Int ) : Float
+	{
+		return SqliteLib.result_get_float(r,n);
+	}
+	
+	public function getFieldsNames( ) : Array<String>
+	{
+		if ( this.names != null )
+			return this.names;
+		
+		this.names = [];
+		var names = SqliteLib.result_get_fields(r);
+		var i = 0;
+		var l = names.length;
+		while ( i < l )
+		{
+			var name = String.fromUCS2(names[i]);
+			this.names.push(name);
+			i++;
+		}
+		
+		return this.names;
+	}
+}
+
+@:coreApi class Sqlite
+{
+	public static function open( file : String ) : Connection
+	{
+		return new SqliteConnection(file);
+	}
+}