| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318 | /* * 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 java.db;import haxe.io.Bytes;import java.sql.Types;import java.util.concurrent.atomic.AtomicInteger;@:native('haxe.java.db.Jdbc')class Jdbc {	public static function create(cnx:java.sql.Connection):sys.db.Connection {		return new JdbcConnection(cnx);	}}@:native('haxe.java.db.JdbcConnection')private class JdbcConnection implements sys.db.Connection {	private static var ids = new AtomicInteger(0);	private var id:Int;	private var cnx:java.sql.Connection;	private var _lastInsertId:Int;	// escape handling	private var escapeRegex:EReg;	private var escapes:Array<Dynamic>;	public function new(cnx) {		this.id = ids.getAndIncrement();		this.cnx = cnx;		this.escapes = [];		this.escapeRegex = ~/@@HX_ESCAPE(\d+)_(\d+)@@/;	}	public function close() {		try			this.cnx.close()		catch (e:Dynamic)			throw e;	}	public function escape(s:String):String {		return "@@HX_ESCAPE" + id + "_" + escapes.push(s) + "@@";	}	public function quote(s:String):String {		return "@@HX_ESCAPE" + id + "_" + escapes.push(s) + "@@";	}	public function addValue(s:StringBuf, v:Dynamic) {		if (Std.isOfType(v, Date)) {			v = Std.string(v);		} else if (Std.isOfType(v, Bytes)) {			var bt:Bytes = v;			v = bt.getData();		}		s.add("@@HX_ESCAPE");		s.add(id);		s.add("_");		s.add(escapes.push(v));		s.add("@@");	}	public function lastInsertId():Int {		return _lastInsertId;	}	public function dbName():String {		try {			var ret = cnx.getMetaData().getDriverName();			var retc = ret.toLowerCase();			if (retc.indexOf("mysql") != -1)				return "MySQL";			else if (retc.indexOf("sqlite") != -1)				return "SQLite";			return ret;		} catch (e:Dynamic) {			throw e;		}	}	public function startTransaction() {		try {			cnx.setAutoCommit(false);		} catch (e:Dynamic)			throw e;	}	public function commit() {		try {			cnx.commit();		} catch (e:Dynamic) {			throw e;		}	}	public function rollback() {		try			cnx.rollback()		catch (e:Dynamic)			throw e;	}	public function request(s:String):sys.db.ResultSet {		var newst = new StringBuf();		var sentArray = [];		// cycle through the request string, adding any @@HX_ESCAPE@@ reference to the sentArray		var r = escapeRegex;		var myid = id + "", escapes = escapes, elen = escapes.length;		try {			while (r.match(s)) {				var id = r.matched(1);				if (id != myid)					throw "Request quotes are only valid for one single request; They can't be cached.";				newst.add(r.matchedLeft());				var eid = Std.parseInt(r.matched(2));				if (eid == null || eid > elen)					throw "Invalid request quote ID " + eid;				sentArray.push(escapes[eid - 1]);				newst.add("?");				s = r.matchedRight();			}			newst.add(s);			var stmt = cnx.prepareStatement(newst.toString(),				#if jvm java.sql.Statement.RETURN_GENERATED_KEYS #else java.sql.Statement.Statement_Statics.RETURN_GENERATED_KEYS #end);			for (i in 0...sentArray.length) {				stmt.setObject(i + 1, sentArray[i]);			}			var ret = null, dbName = dbName();			if (stmt.execute()) {				// is a result set				var rs = stmt.getResultSet();				ret = new JdbcResultSet(rs, dbName, stmt.getMetaData());			} else {				// is an update				var affected = stmt.getUpdateCount();				if (affected == 1) {					var autogen = stmt.getGeneratedKeys();					if (autogen.next()) {						this._lastInsertId = autogen.getInt(1);					}				}				ret = new JdbcResultSet(null, dbName, null);			}			if (escapes.length != 0)				escapes = [];			this.id = ids.getAndIncrement();			return ret;		} catch (e:Dynamic) {			if (escapes.length != 0)				escapes = [];			this.id = ids.getAndIncrement();			throw e;		}	}}@:native('haxe.java.db.JdbcResultSet')private class JdbcResultSet implements sys.db.ResultSet {	@:isVar public var length(get, null):Int;	public var nfields(get, null):Int;	private var rs:java.sql.ResultSet;	private var names:Array<String>;	private var types:java.NativeArray<Int>;	private var dbName:String;	private var didNext:Bool;	public function new(rs, dbName, meta:java.sql.ResultSetMetaData) {		this.dbName = dbName;		this.rs = rs;		if (meta != null) {			try {				var count = meta.getColumnCount();				var names = [], types = new NativeArray(count);				for (i in 0...count) {					names.push(meta.getColumnName(i + 1));					types[i] = meta.getColumnType(i + 1);				}				this.types = types;				this.names = names;			} catch (e:Dynamic)				throw e;		}	}	private function get_length():Int {		if (length == 0) {			try {				var cur = rs.getRow();				rs.last();				this.length = rs.getRow();				rs.absolute(cur);			} catch (e:Dynamic)				throw e;		}		return length;	}	private function get_nfields():Int {		return names == null ? 0 : names.length;	}	public function hasNext():Bool {		try {			didNext = true;			return rs != null && rs.next();		} catch (e:Dynamic) {			return throw e;		}	}	public function next():Dynamic {		try {			if (rs == null)				return null;			if (didNext) {				didNext = false;			} else {				if (!rs.next()) {					return null;				}			}			var ret = {}, names = names, types = types;			for (i in 0...names.length) {				var name = names[i], t = types[i], val:Dynamic = null;				if (t == Types.FLOAT) {					val = rs.getDouble(i + 1);				} else if (t == Types.DATE || t == Types.TIME) {					if (dbName == "SQLite") {						var str = rs.getString(i + 1);						if (str != null) {							var d:Date = Date.fromString(str);							val = d;						}					} else {						var d:java.sql.Date = rs.getDate(i + 1);						if (d != null)							val = Date.fromTime(cast d.getTime());					}				} else if (t == Types.LONGVARBINARY || t == Types.VARBINARY || t == Types.BINARY || t == Types.BLOB) {					var b = rs.getBytes(i + 1);					if (b != null)						val = Bytes.ofData(b);				} else {					val = rs.getObject(i + 1);				}				Reflect.setField(ret, name, val);			}			return ret;		} catch (e:Dynamic)			throw e;	}	public function results():List<Dynamic> {		var l = new List();		if (rs == null)			return l;		try {			while (hasNext())				l.add(next());		} catch (e:Dynamic)			throw e;		return l;	}	public function getResult(n:Int):String {		try {			return rs.getString(n);		} catch (e:Dynamic)			throw e;	}	public function getIntResult(n:Int):Int {		try {			return rs.getInt(n);		} catch (e:Dynamic) {			return throw e;		};	}	public function getFloatResult(n:Int):Float {		try {			return rs.getFloat(n);		} catch (e:Dynamic) {			return throw e;		};	}	public function getFieldsNames():Null<Array<String>> {		return this.names;	}}
 |