""" Java SQL standard library APIs implemented in Python. java.sql package - Connection, Statement, ResultSet, Types, etc. """ from __future__ import annotations from .._core import Stub, AndroidOnlyError from .lang import RuntimeException, Exception as _JavaException import datetime as _datetime import typing as _typing __all__ = [ "Connection", "Statement", "PreparedStatement", "CallableStatement", "ResultSet", "ResultSetMetaData", "DatabaseMetaData", "Driver", "DriverManager", "DriverPropertyInfo", "SQLException", "SQLWarning", "SQLData", "SQLInput", "SQLOutput", "BatchUpdateException", "DataTruncation", "Date", "Time", "Timestamp", "Savepoint", "Blob", "Clob", "NClob", "Ref", "RowId", "Struct", "SQLXML", "Array", "Types", "JDBCType", "Wrapper", "FETCH_FORWARD", "FETCH_REVERSE", "FETCH_UNKNOWN", "TYPE_FORWARD_ONLY", "TYPE_SCROLL_INSENSITIVE", "TYPE_SCROLL_SENSITIVE", "HOLD_CURSORS_OVER_COMMIT", "CLOSE_CURSORS_AT_COMMIT", "CLOSE_ALL_RESULTS", "KEEP_CURRENT_RESULT", "NO_GENERATED_KEYS", "RETURN_GENERATED_KEYS", "CLOSE_CURRENT_RESULT", ] # ============================================================ # Constants # ============================================================ FETCH_FORWARD = 1000 FETCH_REVERSE = 1001 FETCH_UNKNOWN = 1002 TYPE_FORWARD_ONLY = 1003 TYPE_SCROLL_INSENSITIVE = 1004 TYPE_SCROLL_SENSITIVE = 1005 HOLD_CURSORS_OVER_COMMIT = 1 CLOSE_CURSORS_AT_COMMIT = 2 CLOSE_ALL_RESULTS = 1 KEEP_CURRENT_RESULT = 2 CLOSE_CURRENT_RESULT = 3 NO_GENERATED_KEYS = 1 RETURN_GENERATED_KEYS = 2 # ============================================================ # SQLException hierarchy # ============================================================ class SQLException(_JavaException): """java.sql.SQLException""" def __init__(self, reason=None, sql_state=None, vendor_code=0, cause=None): msg = reason or "" super().__init__(msg) self._reason = reason self._sql_state = sql_state self._vendor_code = vendor_code self._cause = cause self._next_exception = None def getMessage(self): return self._reason or "" def getSQLState(self): return self._sql_state def getErrorCode(self): return self._vendor_code def getNextException(self): return self._next_exception def setNextException(self, ex): self._next_exception = ex def getCause(self): return self._cause class SQLWarning(SQLException): """java.sql.SQLWarning""" def __init__(self, reason=None, sql_state=None, vendor_code=0): super().__init__(reason, sql_state, vendor_code) self._next_warning = None def getNextWarning(self): return self._next_warning def setNextWarning(self, warning): self._next_warning = warning class BatchUpdateException(SQLException): """java.sql.BatchUpdateException""" def __init__(self, reason=None, sql_state=None, vendor_code=0, update_counts=None, cause=None): super().__init__(reason, sql_state, vendor_code, cause) self._update_counts = update_counts or [] def getUpdateCounts(self): return self._update_counts def getLargeUpdateCounts(self): return [int(c) for c in self._update_counts] class DataTruncation(SQLWarning): """java.sql.DataTruncation""" def __init__(self, index, parameter, read, data_size, transfer_size): super().__init__("Data truncation") self._index = index self._parameter = parameter self._read = read self._data_size = data_size self._transfer_size = transfer_size def getIndex(self): return self._index def getParameter(self): return self._parameter def getRead(self): return self._read def getDataSize(self): return self._data_size def getTransferSize(self): return self._transfer_size # ============================================================ # Wrapper # ============================================================ class Wrapper(Stub): """java.sql.Wrapper""" def unwrap(self, iface): if iface is None: raise SQLException("iface is null") return self def isWrapperFor(self, iface): return iface is not None and isinstance(self, iface) # ============================================================ # Types Constants # ============================================================ class Types: """java.sql.Types""" ARRAY = 2003 BIGINT = -5 BINARY = -2 BIT = -7 BLOB = 2004 BOOLEAN = 16 CHAR = 1 CLOB = 2005 DATALINK = 70 DATE = 91 DECIMAL = 3 DISTINCT = 2001 DOUBLE = 8 FLOAT = 6 INTEGER = 4 JAVA_OBJECT = 2000 LONGNVARCHAR = -16 LONGVARBINARY = -4 LONGVARCHAR = -1 NCHAR = -15 NCLOB = 2011 NULL = 0 NUMERIC = 2 NVARCHAR = -9 OTHER = 1111 REAL = 7 REF = 2006 REF_CURSOR = 2012 ROWID = -8 SMALLINT = 5 SQLXML = 2009 STRUCT = 2002 TIME = 92 TIMESTAMP = 93 TINYINT = -6 VARBINARY = -3 VARCHAR = 12 class JDBCType(Stub): """java.sql.JDBCType""" _type_map = {} def __init__(self, vendor_type_number): super().__init__() self._vendor_type_number = vendor_type_number def getVendorTypeNumber(self): return self._vendor_type_number def getName(self): for name, val in vars(Types).items(): if isinstance(val, int) and val == self._vendor_type_number: return name return "UNKNOWN" @staticmethod def valueOf(name): val = getattr(Types, name, None) if val is None: raise IllegalArgumentException(f"No JDBC type: {name}") return JDBCType(val) @staticmethod def values(): return [JDBCType(v) for v in set( v for v in vars(Types).values() if isinstance(v, int) )] # ============================================================ # Date / Time / Timestamp # ============================================================ class Date(_datetime.date): """java.sql.Date""" def __init__(self, *args): if len(args) == 1: ms = args[0] dt = _datetime.datetime.fromtimestamp(ms / 1000.0) super().__init__(dt.year, dt.month, dt.day) elif len(args) == 3: super().__init__(args[0], args[1], args[2]) else: super().__init__() def getTime(self): dt = _datetime.datetime.combine(self, _datetime.time.min) return int(dt.timestamp() * 1000) def setTime(self, ms): dt = _datetime.datetime.fromtimestamp(ms / 1000.0) super().__init__(dt.year, dt.month, dt.day) def toString(self): return self.strftime("%Y-%m-%d") @staticmethod def valueOf(s): parts = s.split("-") return Date(int(parts[0]), int(parts[1]), int(parts[2])) class Time(_datetime.time): """java.sql.Time""" def __init__(self, *args): if len(args) == 1: ms = args[0] dt = _datetime.datetime.fromtimestamp(ms / 1000.0) super().__init__(dt.hour, dt.minute, dt.second) elif len(args) == 3: super().__init__(args[0], args[1], args[2]) else: super().__init__() def getTime(self): dt = _datetime.datetime.combine(_datetime.date.today(), self) return int(dt.timestamp() * 1000) def setTime(self, ms): dt = _datetime.datetime.fromtimestamp(ms / 1000.0) super().__init__(dt.hour, dt.minute, dt.second) def toString(self): return self.strftime("%H:%M:%S") @staticmethod def valueOf(s): parts = s.split(":") return Time(int(parts[0]), int(parts[1]), int(parts[2])) class Timestamp(_datetime.datetime): """java.sql.Timestamp""" def __init__(self, *args): if len(args) == 1: ms = args[0] dt = _datetime.datetime.fromtimestamp(ms / 1000.0) super().__init__(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond) self._nanos = (ms % 1000) * 1000000 else: super().__init__(*args) self._nanos = 0 def getTime(self): return int(self.timestamp() * 1000) def setTime(self, ms): dt = _datetime.datetime.fromtimestamp(ms / 1000.0) super().__init__(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond) self._nanos = (ms % 1000) * 1000000 def getNanos(self): return self._nanos def setNanos(self, n): self._nanos = n def toString(self): return self.strftime("%Y-%m-%d %H:%M:%S") @staticmethod def valueOf(s): parts = s.split(" ") date_part = parts[0].split("-") time_part = parts[1].split(":") return Timestamp(int(date_part[0]), int(date_part[1]), int(date_part[2]), int(time_part[0]), int(time_part[1]), int(time_part[2])) # ============================================================ # Savepoint # ============================================================ class Savepoint(Stub): """java.sql.Savepoint""" def __init__(self, name=None): super().__init__() self._savepoint_id = id(self) self._savepoint_name = name def getSavepointId(self): if self._savepoint_name is not None: raise SQLException("Named savepoint") return self._savepoint_id def getSavepointName(self): if self._savepoint_name is None: raise SQLException("Unnamed savepoint") return self._savepoint_name # ============================================================ # Blob / Clob / NClob / Ref / RowId / Struct / SQLXML / Array # ============================================================ class Blob(Stub): """java.sql.Blob""" def __init__(self, data=b""): super().__init__() self._data = bytearray(data) self._length = len(data) def length(self): return self._length def getBytes(self, pos, length): start = pos - 1 return bytes(self._data[start:start + length]) def setBytes(self, pos, bytes_data, offset=0, length=None): start = pos - 1 if length is None: length = len(bytes_data) - offset self._data[start:start + length] = bytearray(bytes_data[offset:offset + length]) return length def position(self, pattern, start): return -1 def truncate(self, length): self._data = self._data[:length] self._length = length def free(self): self._data = bytearray() self._length = 0 def getBinaryStream(self, pos=None, length=None): import io return io.BytesIO(bytes(self._data)) class Clob(Stub): """java.sql.Clob""" def __init__(self, data=""): super().__init__() self._data = data self._length = len(data) def length(self): return self._length def getSubString(self, pos, length): start = pos - 1 return self._data[start:start + length] def setString(self, pos, val, offset=0, length=None): start = pos - 1 if length is None: length = len(val) - offset self._data = self._data[:start] + val[offset:offset + length] + self._data[start + length:] return length def position(self, search_str, start): return self._data.find(search_str, start - 1) def truncate(self, length): self._data = self._data[:length] self._length = length def free(self): self._data = "" self._length = 0 def getAsciiStream(self): import io return io.BytesIO(self._data.encode()) def getCharacterStream(self, pos=None, length=None): import io if pos is not None and length is not None: return io.StringIO(self._data[pos - 1:pos - 1 + length]) return io.StringIO(self._data) def setAsciiStream(self, pos, stream, length=None): data = stream.read() if length is None else stream.read(length) if isinstance(data, bytes): data = data.decode() self._data = self._data[:pos - 1] + data + self._data[pos - 1 + len(data):] class NClob(Clob): """java.sql.NClob""" pass class Ref(Stub): """java.sql.Ref""" def __init__(self, base_type_name=None, obj=None): super().__init__() self._base_type_name = base_type_name self._object = obj def getBaseTypeName(self): return self._base_type_name def getObject(self, type_map=None): return self._object def setObject(self, obj): self._object = obj class RowId(Stub): """java.sql.RowId""" def __init__(self, data=b""): super().__init__() self._data = bytes(data) def getBytes(self): return self._data def toString(self): return self._data.hex() def equals(self, other): if not isinstance(other, RowId): return False return self._data == other._data def hashCode(self): return hash(self._data) class Struct(Stub): """java.sql.Struct""" def __init__(self, sql_type_name, attributes): super().__init__() self._sql_type_name = sql_type_name self._attributes = list(attributes) def getSQLTypeName(self): return self._sql_type_name def getAttributes(self, type_map=None): return self._attributes class SQLXML(Stub): """java.sql.SQLXML""" def __init__(self, xml_string=""): super().__init__() self._xml = xml_string def getString(self): return self._xml def setString(self, value): self._xml = value def free(self): self._xml = "" def getBinaryStream(self): import io return io.BytesIO(self._xml.encode()) def setBinaryStream(self): import io buf = io.BytesIO() return buf def getCharacterStream(self): import io return io.StringIO(self._xml) def setCharacterStream(self): import io buf = io.StringIO() return buf def getSource(self, source_class=None): return None def getResult(self, result_class=None): return None class Array(Stub): """java.sql.Array""" def __init__(self, type_name=None, elements=None): super().__init__() self._type_name = type_name self._elements = list(elements) if elements else [] def getBaseTypeName(self): return self._type_name or "VARCHAR" def getBaseType(self): return Types.VARCHAR def getArray(self, index=None, count=None): if index is None: return self._elements start = index - 1 if count is None: return self._elements[start:] return self._elements[start:start + count] def getResultSet(self, index=None, count=None): raise SQLException("Not implemented") # ============================================================ # SQLData / SQLInput / SQLOutput # ============================================================ class SQLData(Stub): """java.sql.SQLData""" def getSQLTypeName(self): raise SQLException("Not implemented") def readSQL(self, stream, type_name): pass def writeSQL(self, stream): pass class SQLInput(Stub): """java.sql.SQLInput""" def __init__(self, data=None): super().__init__() self._data = list(data) if data else [] self._pos = 0 def readString(self): val = self._data[self._pos] if self._pos < len(self._data) else None self._pos += 1 return str(val) if val is not None else None def readBoolean(self): val = self._data[self._pos] if self._pos < len(self._data) else None self._pos += 1 return bool(val) def readByte(self): val = self._data[self._pos] if self._pos < len(self._data) else None self._pos += 1 return int(val) if val is not None else 0 def readShort(self): val = self._data[self._pos] if self._pos < len(self._data) else None self._pos += 1 return int(val) if val is not None else 0 def readInt(self): val = self._data[self._pos] if self._pos < len(self._data) else None self._pos += 1 return int(val) if val is not None else 0 def readLong(self): val = self._data[self._pos] if self._pos < len(self._data) else None self._pos += 1 return int(val) if val is not None else 0 def readFloat(self): val = self._data[self._pos] if self._pos < len(self._data) else None self._pos += 1 return float(val) if val is not None else 0.0 def readDouble(self): val = self._data[self._pos] if self._pos < len(self._data) else None self._pos += 1 return float(val) if val is not None else 0.0 def readBigDecimal(self): return self.readDouble() def readBytes(self): return b"" def readDate(self): val = self._data[self._pos] if self._pos < len(self._data) else None self._pos += 1 if isinstance(val, Date): return val return Date() def readTime(self): val = self._data[self._pos] if self._pos < len(self._data) else None self._pos += 1 if isinstance(val, Time): return val return Time() def readTimestamp(self): val = self._data[self._pos] if self._pos < len(self._data) else None self._pos += 1 if isinstance(val, Timestamp): return val return Timestamp() def readCharacterStream(self): import io return io.StringIO("") def readBinaryStream(self): import io return io.BytesIO(b"") def readObject(self): val = self._data[self._pos] if self._pos < len(self._data) else None self._pos += 1 return val def readRef(self): return Ref() def readBlob(self): return Blob() def readClob(self): return Clob() def readArray(self): return Array() def readURL(self): return None def readNClob(self): return NClob() def readNString(self): return self.readString() def readSQLXML(self): return SQLXML() def readRowId(self): return RowId() def wasNull(self): return False class SQLOutput(Stub): """java.sql.SQLOutput""" def __init__(self): super().__init__() self._data = [] def writeString(self, x): self._data.append(x) def writeBoolean(self, x): self._data.append(x) def writeByte(self, x): self._data.append(x) def writeShort(self, x): self._data.append(x) def writeInt(self, x): self._data.append(x) def writeLong(self, x): self._data.append(x) def writeFloat(self, x): self._data.append(x) def writeDouble(self, x): self._data.append(x) def writeBigDecimal(self, x): self._data.append(x) def writeBytes(self, x): self._data.append(x) def writeDate(self, x): self._data.append(x) def writeTime(self, x): self._data.append(x) def writeTimestamp(self, x): self._data.append(x) def writeCharacterStream(self, x): self._data.append(x.read() if hasattr(x, 'read') else x) def writeBinaryStream(self, x): self._data.append(x.read() if hasattr(x, 'read') else x) def writeObject(self, x): self._data.append(x) def writeRef(self, x): self._data.append(x) def writeBlob(self, x): self._data.append(x) def writeClob(self, x): self._data.append(x) def writeStruct(self, x): self._data.append(x) def writeArray(self, x): self._data.append(x) def writeURL(self, x): self._data.append(x) def writeNClob(self, x): self._data.append(x) def writeNString(self, x): self._data.append(x) def writeSQLXML(self, x): self._data.append(x) def writeRowId(self, x): self._data.append(x) # ============================================================ # Driver / DriverManager / DriverPropertyInfo # ============================================================ class Driver(Stub): """java.sql.Driver""" def connect(self, url, info): raise SQLException("No suitable driver") def acceptsURL(self, url): return False def getPropertyInfo(self, url, info): return [] def getMajorVersion(self): return 1 def getMinorVersion(self): return 0 def jdbcCompliant(self): return False def getParentLogger(self): return None class DriverPropertyInfo(Stub): """java.sql.DriverPropertyInfo""" def __init__(self, name, value=None): super().__init__() self.name = name self.description = None self.required = False self.value = value self.choices = None class DriverManager(Stub): """java.sql.DriverManager""" _registered_drivers = [] _log_stream = None _log_writer = None _login_timeout = 0 @staticmethod def getConnection(url, user=None, password=None): for driver in DriverManager._registered_drivers: if driver.acceptsURL(url): props = {} if user is not None: props["user"] = user if password is not None: props["password"] = password return driver.connect(url, props) raise SQLException(f"No suitable driver found for {url}") @staticmethod def registerDriver(driver): DriverManager._registered_drivers.append(driver) @staticmethod def deregisterDriver(driver): if driver in DriverManager._registered_drivers: DriverManager._registered_drivers.remove(driver) @staticmethod def getDrivers(): return DriverManager._registered_drivers @staticmethod def getLoginTimeout(): return DriverManager._login_timeout @staticmethod def setLoginTimeout(seconds): DriverManager._login_timeout = seconds @staticmethod def getLogWriter(): return DriverManager._log_writer @staticmethod def setLogWriter(writer): DriverManager._log_writer = writer @staticmethod def println(message): if DriverManager._log_writer is not None: DriverManager._log_writer.write(str(message) + "\n") # ============================================================ # Connection # ============================================================ class Connection(Stub): """java.sql.Connection""" def createStatement(self): return Statement() def prepareStatement(self, sql): return PreparedStatement(sql) def prepareCall(self, sql): return CallableStatement(sql) def nativeSQL(self, sql): return sql def setAutoCommit(self, auto_commit): pass def getAutoCommit(self): return True def commit(self): pass def rollback(self, savepoint=None): pass def close(self): pass def isClosed(self): return False def getMetaData(self): return DatabaseMetaData() def setReadOnly(self, read_only): pass def isReadOnly(self): return False def setCatalog(self, catalog): pass def getCatalog(self): return "" def setTransactionIsolation(self, level): pass def getTransactionIsolation(self): return Connection.TRANSACTION_READ_COMMITTED def getWarnings(self): return None def clearWarnings(self): pass def setSavepoint(self, name=None): return Savepoint(name) def releaseSavepoint(self, savepoint): pass def createStatement(self, result_set_type, result_set_concurrency): return Statement() def prepareStatement(self, sql, *args): return PreparedStatement(sql) def prepareCall(self, sql, result_set_type, result_set_concurrency): return CallableStatement(sql) def setTypeMap(self, type_map): pass def getTypeMap(self): return {} def setHoldability(self, holdability): pass def getHoldability(self): return HOLD_CURSORS_OVER_COMMIT def setSchema(self, schema): pass def getSchema(self): return "" def abort(self, executor): pass def getNetworkTimeout(self): return 0 def setNetworkTimeout(self, executor, milliseconds): pass def createArrayOf(self, type_name, elements): return Array(type_name, elements) def createBlob(self): return Blob() def createClob(self): return Clob() def createNClob(self): return NClob() def createSQLXML(self): return SQLXML() def createStruct(self, type_name, attributes): return Struct(type_name, attributes) def isValid(self, timeout): return not self.isClosed() # Transaction isolation constants TRANSACTION_NONE = 0 TRANSACTION_READ_COMMITTED = 2 TRANSACTION_READ_UNCOMMITTED = 1 TRANSACTION_REPEATABLE_READ = 4 TRANSACTION_SERIALIZABLE = 8 # ============================================================ # Statement # ============================================================ class Statement(Stub): """java.sql.Statement""" def __init__(self): super().__init__() self._max_rows = 0 self._query_timeout = 0 self._fetch_direction = FETCH_FORWARD self._fetch_size = 0 self._max_field_size = 0 self._poolable = True self._close_on_completion = False self._result_set_type = TYPE_FORWARD_ONLY self._result_set_concurrency = 0 self._result_set_holdability = HOLD_CURSORS_OVER_COMMIT self._generated_keys = None self._update_count = -1 self._result_set = None self._more_results = False self._closed = False self._warnings = None self._poolable = True def executeQuery(self, sql): return ResultSet() def executeUpdate(self, sql): return 0 def close(self): self._closed = True def getMaxFieldSize(self): return self._max_field_size def setMaxFieldSize(self, max_size): self._max_field_size = max_size def getMaxRows(self): return self._max_rows def setMaxRows(self, max_rows): self._max_rows = max_rows def setEscapeProcessing(self, enable): pass def getQueryTimeout(self): return self._query_timeout def setQueryTimeout(self, seconds): self._query_timeout = seconds def cancel(self): pass def getWarnings(self): return self._warnings def clearWarnings(self): self._warnings = None def setCursorName(self, name): pass def execute(self, sql): return False def getResultSet(self): return self._result_set def getUpdateCount(self): return self._update_count def getMoreResults(self, current=None): return False def setFetchDirection(self, direction): self._fetch_direction = direction def getFetchDirection(self): return self._fetch_direction def setFetchSize(self, rows): self._fetch_size = rows def getFetchSize(self): return self._fetch_size def getResultSetConcurrency(self): return self._result_set_concurrency def getResultSetType(self): return self._result_set_type def addBatch(self, sql): pass def clearBatch(self): pass def executeBatch(self): return [] def getConnection(self): return Connection() def getMoreResults(self, current): return False def getGeneratedKeys(self): return self._generated_keys or ResultSet() def getResultSetHoldability(self): return self._result_set_holdability def isClosed(self): return self._closed def setPoolable(self, poolable): self._poolable = poolable def isPoolable(self): return self._poolable def closeOnCompletion(self): self._close_on_completion = True def isCloseOnCompletion(self): return self._close_on_completion def executeLargeUpdate(self, sql): return 0 def getLargeUpdateCount(self): return self._update_count def getLargeMaxRows(self): return self._max_rows def setLargeMaxRows(self, max_rows): self._max_rows = max_rows def executeLargeBatch(self): return [] def unwrap(self, iface): return self def isWrapperFor(self, iface): return isinstance(self, iface) SUCCESS_NO_INFO = -2 EXECUTE_FAILED = -3 RETURN_GENERATED_KEYS = 1 NO_GENERATED_KEYS = 2 CLOSE_ALL_RESULTS = 3 KEEP_CURRENT_RESULT = 2 CLOSE_CURRENT_RESULT = 1 NO_GENERATED_KEYS = 2 RETURN_GENERATED_KEYS = 1 # ============================================================ # PreparedStatement # ============================================================ class PreparedStatement(Statement): """java.sql.PreparedStatement""" def __init__(self, sql=""): super().__init__() self._sql = sql self._parameters = [] def setNull(self, parameter_index, sql_type, type_name=None): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = None def setBoolean(self, parameter_index, x): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = x def setByte(self, parameter_index, x): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = x def setShort(self, parameter_index, x): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = x def setInt(self, parameter_index, x): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = x def setLong(self, parameter_index, x): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = x def setFloat(self, parameter_index, x): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = x def setDouble(self, parameter_index, x): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = x def setBigDecimal(self, parameter_index, x): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = x def setString(self, parameter_index, x): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = x def setBytes(self, parameter_index, x): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = bytes(x) if x else None def setDate(self, parameter_index, x, calendar=None): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = x def setTime(self, parameter_index, x, calendar=None): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = x def setTimestamp(self, parameter_index, x, calendar=None): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = x def setAsciiStream(self, parameter_index, stream, length=None): self._ensure_params(parameter_index) data = stream.read() if hasattr(stream, 'read') else stream if isinstance(data, bytes): data = data.decode() self._parameters[parameter_index - 1] = data def setBinaryStream(self, parameter_index, stream, length=None): self._ensure_params(parameter_index) data = stream.read() if hasattr(stream, 'read') else stream self._parameters[parameter_index - 1] = data def setObject(self, parameter_index, x, target_sql_type=None, scale_or_length=None): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = x def setCharacterStream(self, parameter_index, reader, length=None): self._ensure_params(parameter_index) data = reader.read() if hasattr(reader, 'read') else reader self._parameters[parameter_index - 1] = data def setBlob(self, parameter_index, blob): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = blob def setClob(self, parameter_index, clob): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = clob def setArray(self, parameter_index, array): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = array def setRef(self, parameter_index, ref): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = ref def setNString(self, parameter_index, value): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = value def setNClob(self, parameter_index, nclob): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = nclob def setNCharacterStream(self, parameter_index, reader, length=None): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = reader def setRowId(self, parameter_index, row_id): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = row_id def setSQLXML(self, parameter_index, xml): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = xml def setURL(self, parameter_index, url): self._ensure_params(parameter_index) self._parameters[parameter_index - 1] = url def clearParameters(self): self._parameters = [] def executeQuery(self): return ResultSet() def executeUpdate(self): return 0 def execute(self): return False def addBatch(self): pass def getParameterMetaData(self): return ResultSetMetaData() def getMetaData(self): return ResultSetMetaData() def _ensure_params(self, idx): while len(self._parameters) < idx: self._parameters.append(None) # ============================================================ # CallableStatement # ============================================================ class CallableStatement(PreparedStatement): """java.sql.CallableStatement""" def __init__(self, sql=""): super().__init__(sql) self._output_params = {} def registerOutParameter(self, parameter_index, sql_type, scale_or_type_name=None): pass def wasNull(self): return False def getString(self, parameter_index): return self._output_params.get(parameter_index) def getBoolean(self, parameter_index): return bool(self._output_params.get(parameter_index)) def getByte(self, parameter_index): return self._output_params.get(parameter_index, 0) def getShort(self, parameter_index): return self._output_params.get(parameter_index, 0) def getInt(self, parameter_index): return self._output_params.get(parameter_index, 0) def getLong(self, parameter_index): return self._output_params.get(parameter_index, 0) def getFloat(self, parameter_index): return float(self._output_params.get(parameter_index, 0.0)) def getDouble(self, parameter_index): return float(self._output_params.get(parameter_index, 0.0)) def getBigDecimal(self, parameter_index): return self._output_params.get(parameter_index) def getBytes(self, parameter_index): return b"" def getDate(self, parameter_index): return Date() def getTime(self, parameter_index): return Time() def getTimestamp(self, parameter_index): return Timestamp() def getObject(self, parameter_index, type_map=None): return self._output_params.get(parameter_index) def getRef(self, parameter_index): return Ref() def getBlob(self, parameter_index): return Blob() def getClob(self, parameter_index): return Clob() def getArray(self, parameter_index): return Array() def getURL(self, parameter_index): return None def getNClob(self, parameter_index): return NClob() def getNString(self, parameter_index): return self.getString(parameter_index) def getNCharacterStream(self, parameter_index): import io return io.StringIO("") def getRowId(self, parameter_index): return RowId() def getSQLXML(self, parameter_index): return SQLXML() # ============================================================ # ResultSet # ============================================================ class ResultSet(Stub): """java.sql.ResultSet""" def __init__(self): super().__init__() self._rows = [] self._row_index = -1 self._closed = False self._warnings = None self._fetch_direction = FETCH_FORWARD self._fetch_size = 0 self._type = TYPE_FORWARD_ONLY self._concurrency = 0 self._holdability = HOLD_CURSORS_OVER_COMMIT self._meta_data = ResultSetMetaData() def next(self): if self._row_index + 1 < len(self._rows): self._row_index += 1 return True return False def close(self): self._closed = True def wasNull(self): return False def getString(self, column_index_or_label): return str(self._get_value(column_index_or_label) or "") def getBoolean(self, column_index_or_label): return bool(self._get_value(column_index_or_label)) def getByte(self, column_index_or_label): return int(self._get_value(column_index_or_label) or 0) def getShort(self, column_index_or_label): return int(self._get_value(column_index_or_label) or 0) def getInt(self, column_index_or_label): return int(self._get_value(column_index_or_label) or 0) def getLong(self, column_index_or_label): return int(self._get_value(column_index_or_label) or 0) def getFloat(self, column_index_or_label): return float(self._get_value(column_index_or_label) or 0.0) def getDouble(self, column_index_or_label): return float(self._get_value(column_index_or_label) or 0.0) def getBytes(self, column_index_or_label): val = self._get_value(column_index_or_label) if isinstance(val, bytes): return val if isinstance(val, str): return val.encode() return b"" def getDate(self, column_index_or_label): val = self._get_value(column_index_or_label) if isinstance(val, Date): return val return Date() def getTime(self, column_index_or_label): val = self._get_value(column_index_or_label) if isinstance(val, Time): return val return Time() def getTimestamp(self, column_index_or_label): val = self._get_value(column_index_or_label) if isinstance(val, Timestamp): return val return Timestamp() def getObject(self, column_index_or_label, type_map=None): return self._get_value(column_index_or_label) def findColumn(self, column_label): return 1 def getMetaData(self): return self._meta_data def getWarnings(self): return self._warnings def clearWarnings(self): self._warnings = None def setFetchDirection(self, direction): self._fetch_direction = direction def getFetchDirection(self): return self._fetch_direction def setFetchSize(self, rows): self._fetch_size = rows def getFetchSize(self): return self._fetch_size def getType(self): return self._type def getConcurrency(self): return self._concurrency def rowUpdated(self): return False def rowInserted(self): return False def rowDeleted(self): return False def updateNull(self, column_index_or_label): pass def updateBoolean(self, column_index_or_label, x): pass def updateByte(self, column_index_or_label, x): pass def updateShort(self, column_index_or_label, x): pass def updateInt(self, column_index_or_label, x): pass def updateLong(self, column_index_or_label, x): pass def updateFloat(self, column_index_or_label, x): pass def updateDouble(self, column_index_or_label, x): pass def updateString(self, column_index_or_label, x): pass def updateBytes(self, column_index_or_label, x): pass def updateDate(self, column_index_or_label, x): pass def updateTime(self, column_index_or_label, x): pass def updateTimestamp(self, column_index_or_label, x): pass def updateRow(self): pass def insertRow(self): pass def deleteRow(self): pass def refreshRow(self): pass def cancelRowUpdates(self): pass def moveToInsertRow(self): pass def moveToCurrentRow(self): pass def isClosed(self): return self._closed def getHoldability(self): return self._holdability def getStatement(self): return None def getArray(self, column_index_or_label): return Array() def getBlob(self, column_index_or_label): return Blob() def getClob(self, column_index_or_label): return Clob() def getRef(self, column_index_or_label): return Ref() def getURL(self, column_index_or_label): return None def getNClob(self, column_index_or_label): return NClob() def getNString(self, column_index_or_label): return self.getString(column_index_or_label) def getNCharacterStream(self, column_index_or_label): import io return io.StringIO("") def getRowId(self, column_index_or_label): return RowId() def getSQLXML(self, column_index_or_label): return SQLXML() def getBinaryStream(self, column_index_or_label): import io return io.BytesIO(b"") def getCharacterStream(self, column_index_or_label): import io return io.StringIO("") def getAsciiStream(self, column_index_or_label): import io return io.BytesIO(b"") def updateObject(self, column_index_or_label, x, scale_or_target=None): pass def beforeFirst(self): self._row_index = -1 def afterLast(self): self._row_index = len(self._rows) def first(self): if self._rows: self._row_index = 0 return True return False def last(self): if self._rows: self._row_index = len(self._rows) - 1 return True return False def absolute(self, row): if row == 0: self._row_index = -1 return False idx = row - 1 if row > 0 else len(self._rows) + row if 0 <= idx < len(self._rows): self._row_index = idx return True return False def relative(self, rows): new_idx = self._row_index + rows if 0 <= new_idx < len(self._rows): self._row_index = new_idx return True return False def previous(self): if self._row_index > 0: self._row_index -= 1 return True return False def isBeforeFirst(self): return self._row_index < 0 and len(self._rows) > 0 def isAfterLast(self): return self._row_index >= len(self._rows) and len(self._rows) > 0 def isFirst(self): return self._row_index == 0 def isLast(self): return self._row_index == len(self._rows) - 1 def getRow(self): return self._row_index + 1 if 0 <= self._row_index < len(self._rows) else 0 def _get_value(self, col): if 0 <= self._row_index < len(self._rows): row = self._rows[self._row_index] if isinstance(col, int) and col - 1 < len(row): return row[col - 1] return None # Constants FETCH_FORWARD = 1000 FETCH_REVERSE = 1001 FETCH_UNKNOWN = 1002 TYPE_FORWARD_ONLY = 1003 TYPE_SCROLL_INSENSITIVE = 1004 TYPE_SCROLL_SENSITIVE = 1005 CONCUR_READ_ONLY = 1007 CONCUR_UPDATABLE = 1008 HOLD_CURSORS_OVER_COMMIT = 1 CLOSE_CURSORS_AT_COMMIT = 2 # ============================================================ # ResultSetMetaData # ============================================================ class ResultSetMetaData(Stub): """java.sql.ResultSetMetaData""" def __init__(self): super().__init__() self._column_count = 0 self._column_names = [] self._column_types = [] def getColumnCount(self): return self._column_count def isAutoIncrement(self, column): return False def isCaseSensitive(self, column): return True def isSearchable(self, column): return True def isCurrency(self, column): return False def isNullable(self, column): return ResultSetMetaData.columnNullable def isSigned(self, column): return True def getColumnDisplaySize(self, column): return 255 def getColumnLabel(self, column): return self.getColumnName(column) def getColumnName(self, column): if column - 1 < len(self._column_names): return self._column_names[column - 1] return f"COLUMN_{column}" def getSchemaName(self, column): return "" def getPrecision(self, column): return 0 def getScale(self, column): return 0 def getTableName(self, column): return "" def getCatalogName(self, column): return "" def getColumnType(self, column): if column - 1 < len(self._column_types): return self._column_types[column - 1] return Types.VARCHAR def getColumnTypeName(self, column): return "VARCHAR" def isReadOnly(self, column): return False def isWritable(self, column): return True def isDefinitelyWritable(self, column): return True def getColumnClassName(self, column): return "java.lang.String" columnNoNulls = 0 columnNullable = 1 columnNullableUnknown = 2 # ============================================================ # DatabaseMetaData # ============================================================ class DatabaseMetaData(Stub): """java.sql.DatabaseMetaData""" def getDatabaseProductName(self): return "Android-pyApi SQL" def getDatabaseProductVersion(self): return "1.0" def getDriverName(self): return "Android-pyApi JDBC Driver" def getDriverVersion(self): return "1.0" def getDriverMajorVersion(self): return 1 def getDriverMinorVersion(self): return 0 def getURL(self): return "" def getUserName(self): return "" def isReadOnly(self): return False def nullsAreSortedHigh(self): return True def nullsAreSortedLow(self): return False def nullsAreSortedAtStart(self): return False def nullsAreSortedAtEnd(self): return False def getDatabaseMajorVersion(self): return 1 def getDatabaseMinorVersion(self): return 0 def getJDBCMajorVersion(self): return 4 def getJDBCMinorVersion(self): return 2 def getDefaultTransactionIsolation(self): return Connection.TRANSACTION_READ_COMMITTED def supportsTransactions(self): return True def supportsTransactionIsolationLevel(self, level): return True def supportsResultSetType(self, type_): return True def supportsResultSetConcurrency(self, type_, concurrency): return True def getTables(self, catalog, schema_pattern, table_name_pattern, types): return ResultSet() def getColumns(self, catalog, schema_pattern, table_name_pattern, column_name_pattern): return ResultSet() def getPrimaryKeys(self, catalog, schema, table): return ResultSet() def getImportedKeys(self, catalog, schema, table): return ResultSet() def getExportedKeys(self, catalog, schema, table): return ResultSet() def getSchemas(self): return ResultSet() def getCatalogs(self): return ResultSet() def getTableTypes(self): return ResultSet() def getTypeInfo(self): return ResultSet() def getIndexInfo(self, catalog, schema, table, unique, approximate): return ResultSet() def getProcedures(self, catalog, schema_pattern, procedure_name_pattern): return ResultSet() def getProcedureColumns(self, catalog, schema_pattern, procedure_name_pattern, column_name_pattern): return ResultSet() def supportsSavepoints(self): return True def supportsBatchUpdates(self): return True def supportsStoredProcedures(self): return True def allProceduresAreCallable(self): return True def allTablesAreSelectable(self): return True def dataDefinitionCausesTransactionCommit(self): return False def dataDefinitionIgnoredInTransactions(self): return False def doesMaxRowSizeIncludeBlobs(self): return False def getMaxBinaryLiteralLength(self): return 0 def getMaxCharLiteralLength(self): return 0 def getMaxColumnNameLength(self): return 128 def getMaxColumnsInGroupBy(self): return 0 def getMaxColumnsInIndex(self): return 0 def getMaxColumnsInOrderBy(self): return 0 def getMaxColumnsInSelect(self): return 0 def getMaxColumnsInTable(self): return 0 def getMaxConnections(self): return 0 def getMaxCursorNameLength(self): return 0 def getMaxIndexLength(self): return 0 def getMaxSchemaNameLength(self): return 0 def getMaxProcedureNameLength(self): return 0 def getMaxRowSize(self): return 0 def getMaxStatementLength(self): return 0 def getMaxStatements(self): return 0 def getMaxTableNameLength(self): return 0 def getMaxTablesInSelect(self): return 0 def getMaxUserNameLength(self): return 0 def getNumericFunctions(self): return "" def getSQLKeywords(self): return "" def getStringFunctions(self): return "" def getSystemFunctions(self): return "" def getTimeDateFunctions(self): return "" def getSearchStringEscape(self): return "\\" def getExtraNameCharacters(self): return "" def getSchemaTerm(self): return "schema" def getCatalogTerm(self): return "catalog" def getProcedureTerm(self): return "procedure" def getCatalogSeparator(self): return "." def isCatalogAtStart(self): return True def autoCommitFailureClosesAllResultSets(self): return False def generatedKeyAlwaysReturned(self): return True def getSQLStateType(self): return DatabaseMetaData.sqlStateSQL def locatorsUpdateCopy(self): return False def supportsDifferentTableCorrelationNames(self): return True def supportsANSI92EntryLevelSQL(self): return True def supportsANSI92IntermediateSQL(self): return True def supportsANSI92FullSQL(self): return False def supportsIntegrityEnhancementFacility(self): return False def supportsOuterJoins(self): return True def supportsFullOuterJoins(self): return True def supportsLimitedOuterJoins(self): return True def supportsSchemasInDataManipulation(self): return True def supportsSchemasInProcedureCalls(self): return True def supportsSchemasInTableDefinitions(self): return True def supportsSchemasInIndexDefinitions(self): return True def supportsSchemasInPrivilegeDefinitions(self): return True def supportsCatalogsInDataManipulation(self): return True def supportsCatalogsInProcedureCalls(self): return True def supportsCatalogsInTableDefinitions(self): return True def supportsCatalogsInIndexDefinitions(self): return True def supportsCatalogsInPrivilegeDefinitions(self): return True def supportsPositionedDelete(self): return False def supportsPositionedUpdate(self): return False def supportsSelectForUpdate(self): return True def supportsSubqueriesInComparisons(self): return True def supportsSubqueriesInExists(self): return True def supportsSubqueriesInIns(self): return True def supportsSubqueriesInQuantifieds(self): return True def supportsCorrelatedSubqueries(self): return True def supportsUnion(self): return True def supportsUnionAll(self): return True def supportsOpenCursorsAcrossCommit(self): return True def supportsOpenCursorsAcrossRollback(self): return True def supportsOpenStatementsAcrossCommit(self): return True def supportsOpenStatementsAcrossRollback(self): return True def supportsMixedCaseIdentifiers(self): return True def storesMixedCaseIdentifiers(self): return True def supportsMixedCaseQuotedIdentifiers(self): return True def storesMixedCaseQuotedIdentifiers(self): return True def supportsAlterTableWithAddColumn(self): return True def supportsAlterTableWithDropColumn(self): return True def supportsColumnAliasing(self): return True def supportsConvert(self): return True def supportsTableCorrelationNames(self): return True def getConnection(self): return Connection() # Constants attributeNoNulls = 0 attributeNullable = 1 attributeNullableUnknown = 2 bestRowTemporary = 0 bestRowTransaction = 1 bestRowSession = 2 bestRowUnknown = 0 bestRowNotPseudo = 1 bestRowPseudo = 2 columnNoNulls = 0 columnNullable = 1 columnNullableUnknown = 2 functionColumnIn = 1 functionColumnInOut = 2 functionColumnOut = 3 functionColumnReturn = 4 functionColumnResult = 5 functionNoNulls = 0 functionNullable = 1 functionNullableUnknown = 2 functionResultUnknown = 0 functionNoTable = 1 functionReturnsTable = 2 importedKeyCascade = 0 importedKeyRestrict = 1 importedKeySetNull = 2 importedKeyNoAction = 3 importedKeySetDefault = 4 importedKeyInitiallyDeferred = 5 importedKeyInitiallyImmediate = 6 importedKeyNotDeferrable = 7 procedureColumnIn = 1 procedureColumnInOut = 2 procedureColumnOut = 4 procedureColumnReturn = 5 procedureColumnResult = 3 procedureNoNulls = 0 procedureNullable = 1 procedureNullableUnknown = 2 procedureResultUnknown = 0 sqlStateSQL = 2 sqlStateXOpen = 1 tableIndexStatistic = 0 tableIndexClustered = 1 tableIndexHashed = 2 tableIndexOther = 3 versionColumnUnknown = 0 versionColumnNotPseudo = 1 versionColumnPseudo = 2 # ============================================================ # IllegalArgumentException # ============================================================ class IllegalArgumentException(RuntimeException): """java.lang.IllegalArgumentException""" pass