1 /* 2 * Copyright (C) 2019, HuntLabs 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 module hunt.database.base.impl.PreparedQueryImpl; 19 20 import hunt.database.base.impl.ArrayTuple; 21 import hunt.database.base.impl.Connection; 22 import hunt.database.base.impl.CursorImpl; 23 import hunt.database.base.impl.PreparedStatement; 24 import hunt.database.base.impl.QueryResultHandler; 25 import hunt.database.base.impl.RowSetImpl; 26 import hunt.database.base.impl.SqlResultBuilder; 27 28 import hunt.database.base.impl.command.CloseCursorCommand; 29 import hunt.database.base.impl.command.CloseStatementCommand; 30 import hunt.database.base.impl.command.CommandResponse; 31 import hunt.database.base.impl.command.ExtendedBatchQueryCommand; 32 import hunt.database.base.impl.command.ExtendedQueryCommand; 33 34 import hunt.database.base.AsyncResult; 35 import hunt.database.base.Common; 36 import hunt.database.base.Cursor; 37 import hunt.database.base.Exceptions; 38 import hunt.database.base.PreparedQuery; 39 import hunt.database.base.SqlResult; 40 import hunt.database.base.RowSet; 41 import hunt.database.base.RowStream; 42 import hunt.database.base.Row; 43 import hunt.database.base.Tuple; 44 45 import hunt.collection.List; 46 import hunt.Exceptions; 47 import hunt.Functions; 48 import hunt.logging; 49 import hunt.Object; 50 51 import core.atomic; 52 import std.array; 53 import std.variant; 54 55 /** 56 * @author <a href="mailto:julien@julienviet.com">Julien Viet</a> 57 */ 58 class PreparedQueryImpl : PreparedQuery { 59 60 private DbConnection conn; 61 private PreparedStatement ps; 62 private shared bool closed = false; 63 64 this(DbConnection conn, PreparedStatement ps) { 65 this.conn = conn; 66 this.ps = ps; 67 } 68 69 PreparedStatement getPreparedStatement() { 70 return ps; 71 } 72 73 PreparedQuery execute(RowSetHandler handler) { 74 return execute(ArrayTuple.EMPTY, handler); 75 } 76 77 override 78 PreparedQuery execute(Tuple args, RowSetHandler handler) { 79 return execute!(RowSet, RowSetImpl, RowSet)(args, false, RowSetImpl.FACTORY, handler); 80 } 81 82 // <R1, R2 extends SqlResultBase!(R1, R2), R3 extends SqlResult!(R1)> 83 private PreparedQuery execute(R1, R2, R3)( 84 Tuple args, bool singleton, 85 Function!(R1, R2) factory, 86 AsyncResultHandler!(R3) handler) { 87 88 SqlResultBuilder!(R1, R2, R3) b = new SqlResultBuilder!(R1, R2, R3)(factory, handler); 89 return execute!(R1)(args, 90 0, "", false, singleton, b, 91 (CommandResponse!bool r) { b.handle(r); } 92 ); 93 } 94 95 PreparedQuery execute(R)(Tuple args, 96 int fetch, 97 string cursorId, 98 bool suspended, 99 bool singleton, 100 QueryResultHandler!(R) resultHandler, 101 ResponseHandler!(bool) handler) { 102 103 string msg = ps.prepare(cast(List!(Variant)) args); 104 if (!msg.empty()) { 105 version(HUNT_DB_DEBUG) warning(msg); 106 handler(failedResponse!(bool)(new DatabaseException(msg))); 107 } else { 108 ExtendedQueryCommand!R cmd = new ExtendedQueryCommand!R( 109 ps, 110 args, 111 fetch, 112 cursorId, 113 suspended, 114 singleton, 115 resultHandler); 116 cmd.handler = handler; 117 conn.schedule(cmd); 118 } 119 120 return this; 121 } 122 123 Cursor cursor() { 124 return cursor(ArrayTuple.EMPTY); 125 } 126 127 // override 128 Cursor cursor(Tuple args) { 129 string msg = ps.prepare(cast(List!(Variant)) args); 130 if (msg !is null) { 131 throw new IllegalArgumentException(msg); 132 } 133 return new CursorImpl(this, args); 134 } 135 136 // override 137 void close() { 138 139 warning("do nothing"); 140 141 // close(ar -> { 142 // }); 143 } 144 145 PreparedQuery batch(List!(Tuple) argsList, RowSetHandler handler) { 146 // return batch(argsList, false, RowSetImpl.FACTORY, RowSetImpl.COLLECTOR, handler); 147 implementationMissing(false); 148 return null; 149 } 150 151 // override 152 // <R> PreparedQuery batch(List!(Tuple) argsList, Collector<Row, ?, R> collector, Handler!(AsyncResult!(SqlResult!(R))) handler) { 153 // return batch(argsList, true, SqlResultImpl::new, collector, handler); 154 // } 155 156 // private <R1, R2 extends SqlResultBase!(R1, R2), R3 extends SqlResult!(R1)> PreparedQuery batch( 157 // List!(Tuple) argsList, 158 // bool singleton, 159 // Function!(R1, R2) factory, 160 // Collector<Row, ?, R1> collector, 161 // Handler!(AsyncResult!(R3)) handler) { 162 // for (Tuple args : argsList) { 163 // string msg = ps.prepare((List!(Object)) args); 164 // if (msg !is null) { 165 // handler.handle(Future.failedFuture(msg)); 166 // return this; 167 // } 168 // } 169 // SqlResultBuilder!(R1, R2, R3) b = new SqlResultBuilder<>(factory, handler); 170 // ExtendedBatchQueryCommand cmd = new ExtendedBatchQueryCommand<>(ps, argsList, singleton, collector, b); 171 // cmd.handler = b; 172 // conn.schedule(cmd); 173 // return this; 174 // } 175 176 // override 177 // RowStream!(Row) createStream(int fetch, Tuple args) { 178 // return new RowStreamImpl(this, fetch, args); 179 // } 180 181 override 182 void close(AsyncVoidHandler handler) { 183 version(HUNT_DB_DEBUG) infof("closed: %s", closed); 184 if(cas(&closed, false, true)) { 185 CloseStatementCommand cmd = new CloseStatementCommand(ps); 186 cmd.handler = (h) { 187 if(handler !is null) { 188 handler(h); 189 } 190 }; 191 conn.schedule(cmd); 192 } else if(handler !is null) { 193 handler(failedResult!(Void)(new DatabaseException("Already closed"))); 194 } 195 } 196 197 void closeCursor(string cursorId, AsyncVoidHandler handler) { 198 version(HUNT_DB_DEBUG) infof("cursorId: %s", cursorId); 199 CloseCursorCommand cmd = new CloseCursorCommand(cursorId, ps); 200 cmd.handler = (h) { if(handler !is null) handler(h); }; 201 conn.schedule(cmd); 202 } 203 }