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;
- }
- }
|