B4J=true Group=Default Group ModulesStructureVersion=1 Type=Class Version=10 @EndOfDesignText@ 'Handler class Sub Class_Globals ' #if VERSION1 Private const T_NULL = 0, T_STRING = 1, T_SHORT = 2, T_INT = 3, T_LONG = 4, T_FLOAT = 5 _ ,T_DOUBLE = 6, T_BOOLEAN = 7, T_BLOB = 8 As Byte Private bc As ByteConverter Private cs As CompressedStreams ' #end if Private DateTimeMethods As Map Private Connector As RDCConnector End Sub Public Sub Initialize DateTimeMethods = CreateMap(91: "getDate", 92: "getTime", 93: "getTimestamp") End Sub Sub Handle(req As ServletRequest, resp As ServletResponse) Log("********************* DB3 ********************") Dim start As Long = DateTime.Now Dim q As String Dim in As InputStream = req.InputStream Dim method As String = req.GetParameter("method") Connector = Main.Connectors.Get("DB3") Dim con As SQL Try ' con = Main.rdcConnectorDB3.GetConnection("DB3") con = Connector.GetConnection("DB3") If method = "query2" Then q = ExecuteQuery2("DB3", con, in, resp) '#if VERSION1 Else if method = "query" Then in = cs.WrapInputStream(in, "gzip") q = ExecuteQuery("DB3", con, in, resp) Else if method = "batch" Then in = cs.WrapInputStream(in, "gzip") q = ExecuteBatch("DB3", con, in, resp) '#end if Else if method = "batch2" Then q = ExecuteBatch2("DB3", con, in, resp) Else Log("Unknown method: " & method) resp.SendError(500, "unknown method") End If Catch Log(LastException) resp.SendError(500, LastException.Message) End Try If con <> Null And con.IsInitialized Then con.Close Log($"Command: ${q}, took: ${DateTime.Now - start}ms, client=${req.RemoteAddress}"$) End Sub Private Sub ExecuteQuery2 (DB As String, con As SQL, in As InputStream, resp As ServletResponse) As String Dim ser As B4XSerializator Dim m As Map = ser.ConvertBytesToObject(Bit.InputStreamToBytes(in)) Dim cmd As DBCommand = m.Get("command") Dim limit As Int = m.Get("limit") Dim rs As ResultSet = con.ExecQuery2(Connector.GetCommand(DB, cmd.Name), cmd.Parameters) If limit <= 0 Then limit = 0x7fffffff 'max int Dim jrs As JavaObject = rs Dim rsmd As JavaObject = jrs.RunMethod("getMetaData", Null) Dim cols As Int = rs.ColumnCount Dim res As DBResult res.Initialize res.columns.Initialize res.Tag = Null 'without this the Tag properly will not be serializable. For i = 0 To cols - 1 res.columns.Put(rs.GetColumnName(i), i) Next res.Rows.Initialize Do While rs.NextRow And limit > 0 Dim row(cols) As Object For i = 0 To cols - 1 Dim ct As Int = rsmd.RunMethod("getColumnType", Array(i + 1)) 'check whether it is a blob field If ct = -2 Or ct = 2004 Or ct = -3 Or ct = -4 Then row(i) = rs.GetBlob2(i) Else If ct = 2005 Then row(i) = rs.GetString2(i) Else if ct = 2 Or ct = 3 Then row(i) = rs.GetDouble2(i) Else If DateTimeMethods.ContainsKey(ct) Then Dim SQLTime As JavaObject = jrs.RunMethodJO(DateTimeMethods.Get(ct), Array(i + 1)) If SQLTime.IsInitialized Then row(i) = SQLTime.RunMethod("getTime", Null) Else row(i) = Null End If Else row(i) = jrs.RunMethod("getObject", Array(i + 1)) End If Next res.Rows.Add(row) Loop rs.Close Dim data() As Byte = ser.ConvertObjectToBytes(res) resp.OutputStream.WriteBytes(data, 0, data.Length) Return "query: " & cmd.Name End Sub Private Sub ExecuteBatch2(DB As String, con As SQL, in As InputStream, resp As ServletResponse) As String Dim ser As B4XSerializator Dim m As Map = ser.ConvertBytesToObject(Bit.InputStreamToBytes(in)) Dim commands As List = m.Get("commands") Dim res As DBResult res.Initialize res.columns = CreateMap("AffectedRows (N/A)": 0) res.Rows.Initialize res.Tag = Null Try con.BeginTransaction For Each cmd As DBCommand In commands con.ExecNonQuery2(Connector.GetCommand(DB, cmd.Name), _ cmd.Parameters) Next res.Rows.Add(Array As Object(0)) con.TransactionSuccessful Catch con.Rollback Log(LastException) resp.SendError(500, LastException.Message) End Try Dim data() As Byte = ser.ConvertObjectToBytes(res) resp.OutputStream.WriteBytes(data, 0, data.Length) Return $"batch (size=${commands.Size})"$ End Sub '#if VERSION1 Private Sub ExecuteBatch(DB As String, con As SQL, in As InputStream, resp As ServletResponse) As String Dim clientVersion As Float = ReadObject(in) 'ignore Dim numberOfStatements As Int = ReadInt(in) Dim res(numberOfStatements) As Int Try con.BeginTransaction For i = 0 To numberOfStatements - 1 Dim queryName As String = ReadObject(in) Dim params As List = ReadList(in) con.ExecNonQuery2(Connector.GetCommand(DB, queryName), _ params) Next con.TransactionSuccessful Dim out As OutputStream = cs.WrapOutputStream(resp.OutputStream, "gzip") WriteObject(Main.VERSION, out) WriteObject("batch", out) WriteInt(res.Length, out) For Each r As Int In res WriteInt(r, out) Next out.Close Catch con.Rollback Log(LastException) resp.SendError(500, LastException.Message) End Try Return $"batch (size=${numberOfStatements})"$ End Sub Private Sub ExecuteQuery (DB As String, con As SQL, in As InputStream, resp As ServletResponse) As String ' Log("==== ExecuteQuery ==== ") Dim clientVersion As Float = ReadObject(in) 'ignore Dim queryName As String = ReadObject(in) Dim limit As Int = ReadInt(in) Dim params As List = ReadList(in) ' Log("EL QUERY: |" & queryName & "|") Private theSql As String = Connector.GetCommand(DB, queryName) ' Log(theSql) ' Log(params) ' Log(params.Size) Dim rs As ResultSet = con.ExecQuery2(theSql, params) If limit <= 0 Then limit = 0x7fffffff 'max int Dim jrs As JavaObject = rs Dim rsmd As JavaObject = jrs.RunMethod("getMetaData", Null) Dim cols As Int = rs.ColumnCount Dim out As OutputStream = cs.WrapOutputStream(resp.OutputStream, "gzip") WriteObject(Main.VERSION, out) WriteObject("query", out) WriteInt(rs.ColumnCount, out) ' Log($"cols: ${cols}"$) For i = 0 To cols - 1 WriteObject(rs.GetColumnName(i), out) Next Do While rs.NextRow And limit > 0 WriteByte(1, out) For i = 0 To cols - 1 Dim ct As Int = rsmd.RunMethod("getColumnType", Array(i + 1)) 'check whether it is a blob field If ct = -2 Or ct = 2004 Or ct = -3 Or ct = -4 Then WriteObject(rs.GetBlob2(i), out) Else WriteObject(jrs.RunMethod("getObject", Array(i + 1)), out) End If Next Loop WriteByte(0, out) out.Close rs.Close Return "query: " & queryName End Sub Private Sub WriteByte(value As Byte, out As OutputStream) out.WriteBytes(Array As Byte(value), 0, 1) End Sub Private Sub WriteObject(o As Object, out As OutputStream) Dim data() As Byte If o = Null Then out.WriteBytes(Array As Byte(T_NULL), 0, 1) Else If o Is Short Then out.WriteBytes(Array As Byte(T_SHORT), 0, 1) data = bc.ShortsToBytes(Array As Short(o)) Else If o Is Int Then out.WriteBytes(Array As Byte(T_INT), 0, 1) data = bc.IntsToBytes(Array As Int(o)) Else If o Is Float Then out.WriteBytes(Array As Byte(T_FLOAT), 0, 1) data = bc.FloatsToBytes(Array As Float(o)) Else If o Is Double Then out.WriteBytes(Array As Byte(T_DOUBLE), 0, 1) data = bc.DoublesToBytes(Array As Double(o)) Else If o Is Long Then out.WriteBytes(Array As Byte(T_LONG), 0, 1) data = bc.LongsToBytes(Array As Long(o)) Else If o Is Boolean Then out.WriteBytes(Array As Byte(T_BOOLEAN), 0, 1) Dim b As Boolean = o Dim data(1) As Byte If b Then data(0) = 1 Else data(0) = 0 Else If GetType(o) = "[B" Then data = o out.WriteBytes(Array As Byte(T_BLOB), 0, 1) WriteInt(data.Length, out) Else 'If o Is String Then (treat all other values as string) out.WriteBytes(Array As Byte(T_STRING), 0, 1) data = bc.StringToBytes(o, "UTF8") WriteInt(data.Length, out) End If If data.Length > 0 Then out.WriteBytes(data, 0, data.Length) End Sub Private Sub ReadObject(In As InputStream) As Object Dim data(1) As Byte In.ReadBytes(data, 0, 1) Select data(0) Case T_NULL Return Null Case T_SHORT Dim data(2) As Byte Return bc.ShortsFromBytes(ReadBytesFully(In, data, data.Length))(0) Case T_INT Dim data(4) As Byte Return bc.IntsFromBytes(ReadBytesFully(In, data, data.Length))(0) Case T_LONG Dim data(8) As Byte Return bc.LongsFromBytes(ReadBytesFully(In, data, data.Length))(0) Case T_FLOAT Dim data(4) As Byte Return bc.FloatsFromBytes(ReadBytesFully(In, data, data.Length))(0) Case T_DOUBLE Dim data(8) As Byte Return bc.DoublesFromBytes(ReadBytesFully(In, data, data.Length))(0) Case T_BOOLEAN Dim b As Byte = ReadByte(In) Return b = 1 Case T_BLOB Dim len As Int = ReadInt(In) Dim data(len) As Byte Return ReadBytesFully(In, data, data.Length) Case Else Dim len As Int = ReadInt(In) Dim data(len) As Byte ReadBytesFully(In, data, data.Length) Return BytesToString(data, 0, data.Length, "UTF8") End Select End Sub Private Sub ReadBytesFully(In As InputStream, Data() As Byte, Len As Int) As Byte() Dim count = 0, Read As Int Do While count < Len And Read > -1 Read = In.ReadBytes(Data, count, Len - count) count = count + Read Loop Return Data End Sub Private Sub WriteInt(i As Int, out As OutputStream) Dim data() As Byte data = bc.IntsToBytes(Array As Int(i)) out.WriteBytes(data, 0, data.Length) End Sub Private Sub ReadInt(In As InputStream) As Int Dim data(4) As Byte Return bc.IntsFromBytes(ReadBytesFully(In, data, data.Length))(0) End Sub Private Sub ReadByte(In As InputStream) As Byte Dim data(1) As Byte In.ReadBytes(data, 0, 1) Return data(0) End Sub Private Sub ReadList(in As InputStream) As List Dim len As Int = ReadInt(in) Dim l1 As List l1.Initialize For i = 0 To len - 1 l1.Add(ReadObject(in)) Next Return l1 End Sub '#end If