forked from LeenkxTeam/LNXSDK
		
	Update Files
This commit is contained in:
		
							
								
								
									
										354
									
								
								Kha/Tools/linux_x64/std/cs/db/AdoNet.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										354
									
								
								Kha/Tools/linux_x64/std/cs/db/AdoNet.hx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,354 @@ | ||||
| /* | ||||
|  * Copyright (C)2005-2019 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 cs.db; | ||||
|  | ||||
| import sys.db.*; | ||||
| import cs.system.data.*; | ||||
|  | ||||
| class AdoNet { | ||||
| 	public static function create(cnx:IDbConnection, dbName:String):Connection { | ||||
| 		return new AdoConnection(cnx, dbName); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| private class AdoConnection implements Connection { | ||||
| 	private static var ids = 0; | ||||
|  | ||||
| 	private var id:Int; | ||||
|  | ||||
| 	private var cnx:IDbConnection; | ||||
| 	// escape handling | ||||
| 	private var escapeRegex:EReg; | ||||
| 	private var escapes:Array<IDbDataParameter>; | ||||
| 	private var name:String; | ||||
| 	private var command:IDbCommand; | ||||
| 	private var transaction:IDbTransaction; | ||||
|  | ||||
| 	public function new(cnx, name:String) { | ||||
| 		this.id = cs.system.threading.Interlocked.Increment(ids); | ||||
| 		this.cnx = cnx; | ||||
| 		this.name = name; | ||||
| 		this.escapes = []; | ||||
| 		this.command = cnx.CreateCommand(); | ||||
| 		this.escapeRegex = ~/@HX_ESCAPE(\d+)_(\d+)/; | ||||
| 	} | ||||
|  | ||||
| 	public function close():Void { | ||||
| 		cnx.Close(); | ||||
| 	} | ||||
|  | ||||
| 	public function escape(s:String):String { | ||||
| 		var param = command.CreateParameter(); | ||||
| 		var name = "@HX_ESCAPE" + id + "_" + escapes.push(param) + ""; | ||||
| 		param.ParameterName = name; | ||||
| 		param.Value = s; | ||||
| 		return name; | ||||
| 	} | ||||
|  | ||||
| 	public function quote(s:String):String { | ||||
| 		var param = command.CreateParameter(); | ||||
| 		var name = "@HX_ESCAPE" + id + "_" + escapes.push(param) + ""; | ||||
| 		param.ParameterName = name; | ||||
| 		param.Value = s; | ||||
| 		return name; | ||||
| 	} | ||||
|  | ||||
| 	public function addValue(s:StringBuf, v:Dynamic) { | ||||
| 		if (Std.isOfType(v, Date)) { | ||||
| 			v = Std.string(v); | ||||
| 		} else if (Std.isOfType(v, haxe.io.Bytes)) { | ||||
| 			var bt:haxe.io.Bytes = v; | ||||
| 			v = bt.getData(); | ||||
| 		} | ||||
| 		var param = command.CreateParameter(); | ||||
| 		var name = "@HX_ESCAPE" + id + "_" + escapes.push(param) + ""; | ||||
| 		param.ParameterName = name; | ||||
| 		param.Value = v; | ||||
| 		s.add(name); | ||||
| 	} | ||||
|  | ||||
| 	public function lastInsertId():Int { | ||||
| 		var ret = cnx.CreateCommand(); | ||||
| 		ret.CommandText = switch (name) { | ||||
| 			case 'SQLite': | ||||
| 				'SELECT last_insert_rowid()'; | ||||
| 			case _: | ||||
| 				'SELECT @@IDENTITY'; | ||||
| 		} | ||||
| 		ret.CommandType = CommandType.Text; | ||||
| 		var r = cast ret.ExecuteScalar(); | ||||
| 		ret.Dispose(); | ||||
|  | ||||
| 		return r; | ||||
| 	} | ||||
|  | ||||
| 	public function dbName():String { | ||||
| 		return name; | ||||
| 	} | ||||
|  | ||||
| 	public function startTransaction():Void { | ||||
| 		if (this.transaction != null) | ||||
| 			throw 'Transaction already active'; | ||||
| 		this.transaction = cnx.BeginTransaction(); | ||||
| 	} | ||||
|  | ||||
| 	public function commit():Void { | ||||
| 		if (this.transaction == null) | ||||
| 			throw 'No transaction was initiated'; | ||||
| 		this.transaction.Commit(); | ||||
| 	} | ||||
|  | ||||
| 	public function rollback():Void { | ||||
| 		if (this.transaction == null) | ||||
| 			throw 'No transaction was initiated'; | ||||
| 		this.transaction.Rollback(); | ||||
| 	} | ||||
|  | ||||
| 	private static function getFirstStatement(s:String) { | ||||
| 		var buf = new StringBuf(); | ||||
| 		var hasData = false; | ||||
| 		var chr = 0, i = 0; | ||||
| 		inline function getch() | ||||
| 			return chr = StringTools.fastCodeAt(s, i++); | ||||
| 		while (!StringTools.isEof(getch())) { | ||||
| 			inline function peek() { | ||||
| 				var c = StringTools.fastCodeAt(s, i); | ||||
| 				if (StringTools.isEof(c)) | ||||
| 					break; | ||||
| 				return c; | ||||
| 			} | ||||
| 			switch (chr) { | ||||
| 				case ' '.code | '\t'.code | '\n'.code: | ||||
| 					if (hasData) | ||||
| 						return buf.toString(); | ||||
| 				case '-'.code if (peek() == '-'.code): | ||||
| 					if (hasData) | ||||
| 						return buf.toString(); | ||||
| 					while (!StringTools.isEof(getch())) { | ||||
| 						if (chr == '\n'.code) | ||||
| 							break; | ||||
| 					} | ||||
| 				case '#'.code: | ||||
| 					if (hasData) | ||||
| 						return buf.toString(); | ||||
| 					while (!StringTools.isEof(getch())) { | ||||
| 						if (chr == '\n'.code) | ||||
| 							break; | ||||
| 					} | ||||
| 				case '/'.code if (peek() == '*'.code): | ||||
| 					i++; | ||||
| 					if (hasData) | ||||
| 						return buf.toString(); | ||||
| 					while (!StringTools.isEof(getch())) { | ||||
| 						if (chr == '*'.code && peek() == '/'.code) { | ||||
| 							i++; | ||||
| 							break; | ||||
| 						} | ||||
| 					} | ||||
| 				case _: | ||||
| 					hasData = true; | ||||
| 					buf.addChar(chr); | ||||
| 			} | ||||
| 		} | ||||
| 		return buf.toString(); | ||||
| 	} | ||||
|  | ||||
| 	public function request(s:String):ResultSet { | ||||
| 		var newst = new StringBuf(); | ||||
| 		// cycle through the request string, adding any @HX_ESCAPE reference to the command | ||||
| 		var ret:ResultSet = null; | ||||
| 		var r = escapeRegex; | ||||
| 		var myid = id + "", escapes = escapes, elen = escapes.length; | ||||
| 		var cmd = this.command; | ||||
| 		try { | ||||
| 			while (r.match(s)) { | ||||
| 				var id = r.matched(1); | ||||
| 				#if debug | ||||
| 				if (id != myid) | ||||
| 					throw "Request quotes are only valid for one single request; They can't be cached."; | ||||
| 				#end | ||||
|  | ||||
| 				newst.add(r.matchedLeft()); | ||||
| 				var eid = Std.parseInt(r.matched(2)); | ||||
| 				#if debug | ||||
| 				if (eid == null || eid > elen) | ||||
| 					throw "Invalid request quote ID " + eid; | ||||
| 				#end | ||||
| 				cmd.Parameters.Add(escapes[eid - 1]); | ||||
| 				newst.add(escapes[eid - 1].ParameterName); | ||||
| 				s = r.matchedRight(); | ||||
| 			} | ||||
| 			newst.add(s); | ||||
|  | ||||
| 			s = newst.toString(); | ||||
| 			cmd.CommandText = s; | ||||
|  | ||||
| 			var stmt = getFirstStatement(s).toLowerCase(); | ||||
| 			if (stmt == 'select') { | ||||
| 				ret = new AdoResultSet(cmd.ExecuteReader()); | ||||
| 			} else { | ||||
| 				cmd.ExecuteNonQuery(); | ||||
| 				ret = EmptyResultSet.empty; | ||||
| 			} | ||||
|  | ||||
| 			if (escapes.length != 0) | ||||
| 				this.escapes = []; | ||||
| 			this.id = cs.system.threading.Interlocked.Increment(ids); | ||||
| 			cmd.Dispose(); | ||||
| 			this.command = cnx.CreateCommand(); | ||||
| 			return ret; | ||||
| 		} catch (e:Dynamic) { | ||||
| 			if (escapes.length != 0) | ||||
| 				this.escapes = []; | ||||
| 			this.id = cs.system.threading.Interlocked.Increment(ids); | ||||
| 			try { | ||||
| 				cmd.Dispose(); | ||||
| 			} catch (e:Dynamic) {} | ||||
| 			this.command = cnx.CreateCommand(); | ||||
| 			cs.Lib.rethrow(e); | ||||
| 		} | ||||
| 		return null; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| private class AdoResultSet implements ResultSet { | ||||
| 	public var length(get, null):Int; | ||||
| 	public var nfields(get, null):Int; | ||||
|  | ||||
| 	private var reader:IDataReader; | ||||
| 	private var didNext:Bool; | ||||
| 	private var names:Array<String>; | ||||
| 	private var types:Array<Class<Dynamic>>; | ||||
|  | ||||
| 	public function new(reader) { | ||||
| 		this.reader = reader; | ||||
| 		this.names = [for (i in 0...reader.FieldCount) reader.GetName(i)]; | ||||
| 		this.types = [for (i in 0...names.length) cs.Lib.fromNativeType(reader.GetFieldType(i))]; | ||||
| 	} | ||||
|  | ||||
| 	private function get_length() { | ||||
| 		return reader.Depth; | ||||
| 	} | ||||
|  | ||||
| 	private function get_nfields() { | ||||
| 		return names.length; | ||||
| 	} | ||||
|  | ||||
| 	public function hasNext():Bool { | ||||
| 		didNext = true; | ||||
| 		return reader.Read(); | ||||
| 	} | ||||
|  | ||||
| 	public function next():Dynamic { | ||||
| 		if (!didNext && !hasNext()) | ||||
| 			return null; | ||||
| 		didNext = false; | ||||
| 		var ret = {}, names = names, types = types; | ||||
| 		for (i in 0...names.length) { | ||||
| 			var name = names[i], t = types[i], val:Dynamic = null; | ||||
| 			if (reader.IsDBNull(i)) { | ||||
| 				val = null; | ||||
| 			} else if (t == cs.system.Single) { | ||||
| 				val = reader.GetDouble(i); | ||||
| 			} else if (t == cs.system.DateTime || t == cs.system.TimeSpan) { | ||||
| 				var d = reader.GetDateTime(i); | ||||
| 				if (d != null) | ||||
| 					val = @:privateAccess Date.fromNative(d); | ||||
| 			} else if (t == cs.system.DBNull) { | ||||
| 				val = null; | ||||
| 			} else if (t == cs.system.Byte) { | ||||
| 				var v2:cs.StdTypes.UInt8 = reader.GetValue(i); | ||||
| 				val = cast(v2, Int); | ||||
| 			} else if (Std.string(t) == 'System.Byte[]') { | ||||
| 				val = haxe.io.Bytes.ofData(reader.GetValue(i)); | ||||
| 			} else { | ||||
| 				val = reader.GetValue(i); | ||||
| 			} | ||||
| 			if (Std.isOfType(val, cs.system.DBNull)) | ||||
| 				val = null; | ||||
| 			Reflect.setField(ret, name, val); | ||||
| 		} | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	public function results():List<Dynamic> { | ||||
| 		var l = new List(); | ||||
| 		while (hasNext()) | ||||
| 			l.add(next()); | ||||
| 		return l; | ||||
| 	} | ||||
|  | ||||
| 	public function getResult(n:Int):String { | ||||
| 		return reader.GetString(n); | ||||
| 	} | ||||
|  | ||||
| 	public function getIntResult(n:Int):Int { | ||||
| 		return reader.GetInt32(n); | ||||
| 	} | ||||
|  | ||||
| 	public function getFloatResult(n:Int):Float { | ||||
| 		return reader.GetDouble(n); | ||||
| 	} | ||||
|  | ||||
| 	public function getFieldsNames():Null<Array<String>> { | ||||
| 		return names; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| private class EmptyResultSet implements ResultSet { | ||||
| 	public static var empty = new EmptyResultSet(); | ||||
|  | ||||
| 	public function new() {} | ||||
|  | ||||
| 	public var length(get, null):Int; | ||||
| 	public var nfields(get, null):Int; | ||||
|  | ||||
| 	private function get_length() { | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	private function get_nfields() { | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	public function hasNext():Bool | ||||
| 		return false; | ||||
|  | ||||
| 	public function next():Dynamic | ||||
| 		return null; | ||||
|  | ||||
| 	public function results():List<Dynamic> | ||||
| 		return new List(); | ||||
|  | ||||
| 	public function getResult(n:Int):String | ||||
| 		return null; | ||||
|  | ||||
| 	public function getIntResult(n:Int):Int | ||||
| 		return 0; | ||||
|  | ||||
| 	public function getFloatResult(n:Int):Float | ||||
| 		return 0; | ||||
|  | ||||
| 	public function getFieldsNames():Null<Array<String>> | ||||
| 		return null; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user