Connection.lua
local log = require("remotelog")
local ExaError = require("ExaError")
local cursor = require("luasql.exasol.Cursor")
local Connection = {}
function Connection:create(connection_properties, websocket, session_id)
log.trace("Created new connection with session ID %d", session_id)
local object = {
connection_properties = assert(connection_properties, "connection_properties missing"),
websocket = assert(websocket, "websocket missing"),
session_id = assert(session_id, "session_id missing"),
closed = false,
cursors = {}
}
self.__index = self
setmetatable(object, self)
return object
end
function Connection:_verify_connection_open(operation)
if self.closed then
ExaError:new("E-EDL-12", "Connection already closed when trying to call {{operation}}", {operation = operation})
:raise()
end
end
function Connection:execute(statement)
self:_verify_connection_open("execute")
log.trace("Executing statement '%s'", statement)
local result, err = self.websocket:send_execute(statement)
if err then
return nil, ExaError:new("E-EDL-6", "Error executing statement {{statement}}: {{error|uq}}",
{statement = statement, error = tostring(err)})
end
local num_results = result.numResults
if num_results == 0 then
local args = {statement = statement}
ExaError:new("E-EDL-7", "Got no results for statement {{statement}}", args):add_ticket_mitigation():raise()
end
if num_results > 1 then
return nil,
ExaError:new("E-EDL-8",
"Got {{numResults}} results for statement {{statement}} but at most one is supported",
{numResults = num_results, statement = statement}):add_mitigations(
"Use only statements that return a single result")
end
local first_result = result.results[1]
local result_type = first_result.resultType
if result_type == "rowCount" then
return first_result.rowCount, nil
end
if result_type ~= "resultSet" then
local args = {result_type = result_type or "nil"}
ExaError:new("E-EDL-9", "Got unexpected result type {{result_type}}", args):add_ticket_mitigation():raise()
end
local cur = cursor:create(self.connection_properties, self.websocket, self.session_id, first_result.resultSet)
table.insert(self.cursors, cur)
return cur, nil
end
function Connection:commit()
self:_verify_connection_open("commit")
local _, err = self:execute("commit")
if err == nil then
return true
else
log.error(tostring(ExaError:new("E-EDL-39", "Failed to commit: {{error}}", {error = tostring(err)})))
return false
end
end
function Connection:rollback()
self:_verify_connection_open("rollback")
local _, err = self:execute("rollback")
if err == nil then
return true
else
log.error(tostring(ExaError:new("E-EDL-40", "Failed to rollback: {{error}}", {error = tostring(err)})))
return false
end
end
function Connection:setautocommit(autocommit)
self:_verify_connection_open("setautocommit")
local err = self.websocket:send_set_attribute("autocommit", autocommit)
if err then
log.error(tostring(ExaError:new("E-EDL-32", "Failed to set autocommit to {{autocommit}}: {{error}}",
{autocommit = tostring(autocommit), error = err})))
return false
else
return true
end
end
function Connection:close()
if self.closed then
log.warn(tostring(ExaError:new("W-EDL-35", "Connection with session ID {{session_id}} already closed",
{session_id = self.session_id})))
return false
end
local cursors = self.cursors
log.debug("Closing Session session %d. Check if its %d cursors are closed", self.session_id, #cursors)
for _, cur in ipairs(cursors) do
if not cur.closed then
log.warn(tostring(ExaError:new("W-EDL-34",
"Cannot close session {{session_id}} because not all cursors are closed",
{session_id = string.format("%d", self.session_id)})))
return false
end
end
local err = self.websocket:send_disconnect()
if err then
ExaError:new("E-EDL-11", "Error closing session {{session_id}}: {{error}}",
{session_id = self.session_id, error = err}):raise()
end
local success = self.websocket:close()
self.closed = true
return success
end
return Connection