Files
Android-pyApi/android_pyapi/android/database.py
T
shuiyu1123 bfe27fdc08 feat: Android-pyApi v1.0 - 全面翻译 Android SDK API 为 Python
52 个模块覆盖 Android + Java + org.json 标准库
2026-06-24 11:16:16 +00:00

1076 lines
37 KiB
Python

"""
Android Database 组件 — Cursor, MatrixCursor, ContentObserver 等
方法签名完全对齐 Android SDK
"""
import os
import sys
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
from .._core import (
Stub, AndroidOnlyError, android_context,
resolve_android_path, to_android_path,
_sdcard_root, _app_data_dir, _package_name,
)
# ═══════════════════════════════════════════════════════════════
# SQLException hierarchy
# ═══════════════════════════════════════════════════════════════
class SQLException(RuntimeError):
"""SQLException — 数据库异常基类"""
def __init__(self, message: str = ""):
super().__init__(message)
self._error_message = message
def getMessage(self) -> str:
return self._error_message
def toString(self) -> str:
return f"SQLException: {self._error_message}"
class CursorIndexOutOfBoundsException(SQLException):
"""CursorIndexOutOfBoundsException — 游标越界"""
def __init__(self, message: str = ""):
super().__init__(message)
# ═══════════════════════════════════════════════════════════════
# ContentObserver
# ═══════════════════════════════════════════════════════════════
class ContentObserver(Stub):
"""ContentObserver — 内容观察者"""
def __init__(self, handler: Any = None):
super().__init__()
self._handler = handler
self._notify_for_descendants = False
def onChange(self, self_change: bool = True):
pass
def onChange(self, self_change: bool, uri: Any = None): # type: ignore
pass
def deliverSelfNotifications(self) -> bool:
return True
def getSelfChangeNotify(self) -> bool:
return True
def dispatchChange(self, self_change: bool, uri: Any = None):
self.onChange(self_change, uri)
# ═══════════════════════════════════════════════════════════════
# DataSetObserver
# ═══════════════════════════════════════════════════════════════
class DataSetObserver(Stub):
"""DataSetObserver — 数据集观察者"""
def onChanged(self):
pass
def onInvalidated(self):
pass
# ═══════════════════════════════════════════════════════════════
# ContentObservable
# ═══════════════════════════════════════════════════════════════
class ContentObservable(Stub):
"""ContentObservable — 内容可观察对象"""
def __init__(self):
super().__init__()
self._observers: List[ContentObserver] = []
def registerObserver(self, observer: ContentObserver):
if observer not in self._observers:
self._observers.append(observer)
def unregisterObserver(self, observer: ContentObserver):
self._observers = [o for o in self._observers if o is not observer]
def dispatchChange(self, self_change: bool, uri: Any = None):
for observer in list(self._observers):
observer.dispatchChange(self_change, uri)
def notifyChange(self, self_change: bool):
for observer in list(self._observers):
observer.onChange(self_change)
# ═══════════════════════════════════════════════════════════════
# DataSetObservable
# ═══════════════════════════════════════════════════════════════
class DataSetObservable(Stub):
"""DataSetObservable — 数据集可观察对象"""
def __init__(self):
super().__init__()
self._observers: List[DataSetObserver] = []
def registerObserver(self, observer: DataSetObserver):
if observer not in self._observers:
self._observers.append(observer)
def unregisterObserver(self, observer: DataSetObserver):
self._observers = [o for o in self._observers if o is not observer]
def notifyChanged(self):
for observer in list(self._observers):
observer.onChanged()
def notifyInvalidated(self):
for observer in list(self._observers):
observer.onInvalidated()
# ═══════════════════════════════════════════════════════════════
# CharArrayBuffer
# ═══════════════════════════════════════════════════════════════
class CharArrayBuffer(Stub):
"""CharArrayBuffer — 字符数组缓冲区"""
def __init__(self, size: int = 0):
super().__init__()
self.data: List[str] = [""] * size
# ═══════════════════════════════════════════════════════════════
# DatabaseErrorHandler
# ═══════════════════════════════════════════════════════════════
class DatabaseErrorHandler(Stub):
"""DatabaseErrorHandler — 数据库错误处理器"""
def onCorruption(self, db_obj: Any):
pass
class DefaultDatabaseErrorHandler(DatabaseErrorHandler):
"""DefaultDatabaseErrorHandler — 默认数据库错误处理器"""
def onCorruption(self, db_obj: Any):
import sys
sys.stderr.write(f"[DatabaseError] Corruption detected for {db_obj}\n")
# ═══════════════════════════════════════════════════════════════
# CursorWindow
# ═══════════════════════════════════════════════════════════════
class CursorWindow(Stub):
"""CursorWindow — 游标窗口"""
def __init__(self, name: str = "unnamed"):
super().__init__()
self._name = name
self._start_position: int = 0
self._num_rows: int = 0
self._num_columns: int = 0
self._data: List[List[Optional[Any]]] = []
def setStartPosition(self, pos: int):
self._start_position = pos
def getStartPosition(self) -> int:
return self._start_position
def allocRow(self) -> bool:
self._data.append([None] * self._num_columns)
self._num_rows = len(self._data)
return True
def freeRow(self, row: int):
if 0 <= row < len(self._data):
self._data[row] = [None] * self._num_columns
def freeLastRow(self):
if self._data:
self._data.pop()
self._num_rows = len(self._data)
def getNumRows(self) -> int:
return self._num_rows
def setNumColumns(self, num_columns: int):
self._num_columns = num_columns
def getNumColumns(self) -> int:
return self._num_columns
def writeString(self, value: str, row: int, col: int):
while len(self._data) <= row:
self._data.append([None] * self._num_columns)
while len(self._data[row]) <= col:
self._data[row].append(None)
self._data[row][col] = value
def writeLong(self, value: int, row: int, col: int):
while len(self._data) <= row:
self._data.append([None] * self._num_columns)
while len(self._data[row]) <= col:
self._data[row].append(None)
self._data[row][col] = value
def writeDouble(self, value: float, row: int, col: int):
while len(self._data) <= row:
self._data.append([None] * self._num_columns)
while len(self._data[row]) <= col:
self._data[row].append(None)
self._data[row][col] = value
def writeBlob(self, value: bytes, row: int, col: int):
while len(self._data) <= row:
self._data.append([None] * self._num_columns)
while len(self._data[row]) <= col:
self._data[row].append(None)
self._data[row][col] = value
def writeNull(self, row: int, col: int):
while len(self._data) <= row:
self._data.append([None] * self._num_columns)
while len(self._data[row]) <= col:
self._data[row].append(None)
self._data[row][col] = None
def getString(self, row: int, col: int) -> Optional[str]:
try:
v = self._data[row][col]
return str(v) if v is not None else None
except (IndexError, TypeError):
return None
def getLong(self, row: int, col: int) -> int:
try:
v = self._data[row][col]
return int(v) if v is not None else 0
except (IndexError, ValueError, TypeError):
return 0
def getDouble(self, row: int, col: int) -> float:
try:
v = self._data[row][col]
return float(v) if v is not None else 0.0
except (IndexError, ValueError, TypeError):
return 0.0
def getBlob(self, row: int, col: int) -> Optional[bytes]:
try:
v = self._data[row][col]
if isinstance(v, bytes):
return v
if isinstance(v, str):
return v.encode("utf-8")
return None
except IndexError:
return None
def isNull(self, row: int, col: int) -> bool:
try:
return self._data[row][col] is None
except IndexError:
return True
def clear(self):
self._data.clear()
self._num_rows = 0
def toString(self) -> str:
return f"CursorWindow(name={self._name}, rows={self._num_rows}, cols={self._num_columns})"
# ═══════════════════════════════════════════════════════════════
# Cursor interface
# ═══════════════════════════════════════════════════════════════
class Cursor(Stub):
"""Cursor — 游标接口"""
FIELD_TYPE_NULL = 0
FIELD_TYPE_INTEGER = 1
FIELD_TYPE_FLOAT = 2
FIELD_TYPE_STRING = 3
FIELD_TYPE_BLOB = 4
def __init__(self):
super().__init__()
self._pos: int = -1
self._closed: bool = False
def getCount(self) -> int:
return 0
def getPosition(self) -> int:
return self._pos
def moveToFirst(self) -> bool:
return self.moveToPosition(0)
def moveToLast(self) -> bool:
return self.moveToPosition(self.getCount() - 1)
def moveToNext(self) -> bool:
return self.moveToPosition(self._pos + 1)
def moveToPrevious(self) -> bool:
return self.moveToPosition(self._pos - 1)
def move(self, offset: int) -> bool:
return self.moveToPosition(self._pos + offset)
def moveToPosition(self, position: int) -> bool:
if position < -1 or position >= self.getCount():
return False
self._pos = position
return True
def isFirst(self) -> bool:
return self._pos == 0
def isLast(self) -> bool:
return self._pos == self.getCount() - 1
def isBeforeFirst(self) -> bool:
return self._pos < 0
def isAfterLast(self) -> bool:
return self._pos >= self.getCount()
def getColumnIndex(self, column_name: str) -> int:
names = self.getColumnNames()
try:
return names.index(column_name)
except ValueError:
return -1
def getColumnIndexOrThrow(self, column_name: str) -> int:
idx = self.getColumnIndex(column_name)
if idx < 0:
raise IllegalArgumentException(f"Column '{column_name}' does not exist")
return idx
def getColumnName(self, column_index: int) -> str:
names = self.getColumnNames()
if 0 <= column_index < len(names):
return names[column_index]
return ""
def getColumnNames(self) -> List[str]:
return []
def getType(self, column_index: int) -> int:
return self.FIELD_TYPE_NULL
def getString(self, column_index: int) -> Optional[str]:
return None
def getInt(self, column_index: int) -> int:
return 0
def getLong(self, column_index: int) -> int:
return 0
def getFloat(self, column_index: int) -> float:
return 0.0
def getDouble(self, column_index: int) -> float:
return 0.0
def getShort(self, column_index: int) -> int:
return 0
def getBlob(self, column_index: int) -> Optional[bytes]:
return None
def getBytes(self, column_index: int) -> Optional[bytes]:
return self.getBlob(column_index)
def close(self):
self._closed = True
def isClosed(self) -> bool:
return self._closed
def requery(self) -> bool:
return False
def deactivate(self):
pass
def registerContentObserver(self, observer: ContentObserver):
pass
def unregisterContentObserver(self, observer: ContentObserver):
pass
def registerDataSetObserver(self, observer: DataSetObserver):
pass
def unregisterDataSetObserver(self, observer: DataSetObserver):
pass
def getWantsAllOnMoveCalls(self) -> bool:
return False
def getExtras(self) -> Any:
return None
def respond(self, extras: Any) -> Any:
return None
def setNotificationUri(self, cr: Any, uri: Any):
pass
def getNotificationUri(self) -> Any:
return None
def fillWindow(self, pos: int, window: CursorWindow):
pass
def copyStringToBuffer(self, column_index: int, buffer: CharArrayBuffer):
val = self.getString(column_index)
if val is not None:
buffer.data = list(val)
def isNull(self, column_index: int) -> bool:
return self.getType(column_index) == self.FIELD_TYPE_NULL
# ═══════════════════════════════════════════════════════════════
# AbstractCursor
# ═══════════════════════════════════════════════════════════════
class AbstractCursor(Cursor):
"""AbstractCursor — 游标抽象基类"""
def __init__(self):
super().__init__()
self._content_observable = ContentObservable()
self._data_set_observable = DataSetObservable()
self._notification_uri: Any = None
self._self_observer: Optional[ContentObserver] = None
def getCount(self) -> int:
return 0
def getColumnNames(self) -> List[str]:
return []
def registerContentObserver(self, observer: ContentObserver):
self._content_observable.registerObserver(observer)
def unregisterContentObserver(self, observer: ContentObserver):
self._content_observable.unregisterObserver(observer)
def registerDataSetObserver(self, observer: DataSetObserver):
self._data_set_observable.registerObserver(observer)
def unregisterDataSetObserver(self, observer: DataSetObserver):
self._data_set_observable.unregisterObserver(observer)
def setNotificationUri(self, cr: Any, uri: Any):
self._notification_uri = uri
def getNotificationUri(self) -> Any:
return self._notification_uri
def onChange(self, self_change: bool):
self._content_observable.dispatchChange(self_change)
def getWantsAllOnMoveCalls(self) -> bool:
return False
def getExtras(self) -> Any:
return None
def respond(self, extras: Any) -> Any:
return None
def fillWindow(self, pos: int, window: CursorWindow):
pass
# ═══════════════════════════════════════════════════════════════
# AbstractWindowedCursor
# ═══════════════════════════════════════════════════════════════
class AbstractWindowedCursor(AbstractCursor):
"""AbstractWindowedCursor — 带窗口的游标"""
def __init__(self):
super().__init__()
self._window: Optional[CursorWindow] = None
def getWindow(self) -> Optional[CursorWindow]:
return self._window
def setWindow(self, window: CursorWindow):
self._window = window
def hasWindow(self) -> bool:
return self._window is not None
def clearBlobCache(self):
pass
def fillWindow(self, pos: int, window: CursorWindow):
if self._window:
self._window.clear()
def getString(self, column_index: int) -> Optional[str]:
if self._window and self._pos >= 0:
return self._window.getString(self._pos, column_index)
return None
def getInt(self, column_index: int) -> int:
if self._window and self._pos >= 0:
return self._window.getLong(self._pos, column_index)
return 0
def getLong(self, column_index: int) -> int:
if self._window and self._pos >= 0:
return self._window.getLong(self._pos, column_index)
return 0
def getFloat(self, column_index: int) -> float:
if self._window and self._pos >= 0:
return self._window.getDouble(self._pos, column_index)
return 0.0
def getDouble(self, column_index: int) -> float:
if self._window and self._pos >= 0:
return self._window.getDouble(self._pos, column_index)
return 0.0
def getBlob(self, column_index: int) -> Optional[bytes]:
if self._window and self._pos >= 0:
return self._window.getBlob(self._pos, column_index)
return None
def isNull(self, column_index: int) -> bool:
if self._window and self._pos >= 0:
return self._window.isNull(self._pos, column_index)
return True
# ═══════════════════════════════════════════════════════════════
# CursorWrapper
# ═══════════════════════════════════════════════════════════════
class CursorWrapper(Cursor):
"""CursorWrapper — 游标包装器"""
def __init__(self, cursor: Cursor):
super().__init__()
self._wrapped_cursor = cursor
def getWrappedCursor(self) -> Cursor:
return self._wrapped_cursor
def getCount(self) -> int:
return self._wrapped_cursor.getCount()
def getPosition(self) -> int:
return self._wrapped_cursor.getPosition()
def moveToFirst(self) -> bool:
return self._wrapped_cursor.moveToFirst()
def moveToLast(self) -> bool:
return self._wrapped_cursor.moveToLast()
def moveToNext(self) -> bool:
return self._wrapped_cursor.moveToNext()
def moveToPrevious(self) -> bool:
return self._wrapped_cursor.moveToPrevious()
def move(self, offset: int) -> bool:
return self._wrapped_cursor.move(offset)
def moveToPosition(self, position: int) -> bool:
return self._wrapped_cursor.moveToPosition(position)
def getColumnNames(self) -> List[str]:
return self._wrapped_cursor.getColumnNames()
def getColumnIndex(self, column_name: str) -> int:
return self._wrapped_cursor.getColumnIndex(column_name)
def getColumnIndexOrThrow(self, column_name: str) -> int:
return self._wrapped_cursor.getColumnIndexOrThrow(column_name)
def getString(self, column_index: int) -> Optional[str]:
return self._wrapped_cursor.getString(column_index)
def getInt(self, column_index: int) -> int:
return self._wrapped_cursor.getInt(column_index)
def getLong(self, column_index: int) -> int:
return self._wrapped_cursor.getLong(column_index)
def getFloat(self, column_index: int) -> float:
return self._wrapped_cursor.getFloat(column_index)
def getDouble(self, column_index: int) -> float:
return self._wrapped_cursor.getDouble(column_index)
def getShort(self, column_index: int) -> int:
return self._wrapped_cursor.getShort(column_index)
def getBlob(self, column_index: int) -> Optional[bytes]:
return self._wrapped_cursor.getBlob(column_index)
def close(self):
self._wrapped_cursor.close()
def isClosed(self) -> bool:
return self._wrapped_cursor.isClosed()
def registerContentObserver(self, observer: ContentObserver):
self._wrapped_cursor.registerContentObserver(observer)
def unregisterContentObserver(self, observer: ContentObserver):
self._wrapped_cursor.unregisterContentObserver(observer)
def registerDataSetObserver(self, observer: DataSetObserver):
self._wrapped_cursor.registerDataSetObserver(observer)
def unregisterDataSetObserver(self, observer: DataSetObserver):
self._wrapped_cursor.unregisterDataSetObserver(observer)
def getWantsAllOnMoveCalls(self) -> bool:
return self._wrapped_cursor.getWantsAllOnMoveCalls()
# ═══════════════════════════════════════════════════════════════
# CrossProcessCursor / CrossProcessCursorWrapper
# ═══════════════════════════════════════════════════════════════
class CrossProcessCursor(Cursor):
"""CrossProcessCursor — 跨进程游标"""
def fillWindow(self, pos: int, window: CursorWindow):
pass
def getWindow(self) -> Optional[CursorWindow]:
return None
def onMove(self, old_position: int, new_position: int) -> bool:
return True
class CrossProcessCursorWrapper(CursorWrapper):
"""CrossProcessCursorWrapper — 跨进程游标包装器"""
def __init__(self, cursor: Cursor):
super().__init__(cursor)
self._cursor = cursor
def fillWindow(self, pos: int, window: CursorWindow):
if isinstance(self._cursor, CrossProcessCursor):
self._cursor.fillWindow(pos, window)
def getWindow(self) -> Optional[CursorWindow]:
if isinstance(self._cursor, CrossProcessCursor):
return self._cursor.getWindow()
return None
def onMove(self, old_position: int, new_position: int) -> bool:
if isinstance(self._cursor, CrossProcessCursor):
return self._cursor.onMove(old_position, new_position)
return True
# ═══════════════════════════════════════════════════════════════
# MatrixCursor
# ═══════════════════════════════════════════════════════════════
class MatrixCursor(AbstractCursor):
"""MatrixCursor — 内存矩阵游标"""
class RowBuilder(Stub):
"""RowBuilder — 行构建器"""
def __init__(self, cursor: "MatrixCursor", row_index: int):
super().__init__()
self._cursor = cursor
self._row_index = row_index
def add(self, column_value: Any) -> "MatrixCursor.RowBuilder":
self._cursor._add_row_value(self._row_index, column_value)
return self
def __init__(self, column_names: List[str], initial_capacity: int = 0):
super().__init__()
self._column_names = list(column_names)
self._rows: List[List[Optional[Any]]] = []
self._num_columns = len(column_names)
def _add_row_value(self, row_index: int, value: Any):
while len(self._rows) <= row_index:
self._rows.append([])
self._rows[row_index].append(value)
def addRow(self, values: Union[List[Any], Tuple[Any, ...]]) -> None:
row = list(values) + [None] * (self._num_columns - len(values))
self._rows.append(row[:self._num_columns])
def newRow(self) -> RowBuilder:
row_index = len(self._rows)
self._rows.append([])
return MatrixCursor.RowBuilder(self, row_index)
def getCount(self) -> int:
return len(self._rows)
def getColumnNames(self) -> List[str]:
return list(self._column_names)
def getString(self, column_index: int) -> Optional[str]:
if self._pos < 0 or self._pos >= len(self._rows):
return None
if column_index < 0 or column_index >= len(self._rows[self._pos]):
return None
v = self._rows[self._pos][column_index]
return str(v) if v is not None else None
def getInt(self, column_index: int) -> int:
v = self.getString(column_index)
if v is None:
return 0
try:
return int(float(v))
except (ValueError, TypeError):
return 0
def getLong(self, column_index: int) -> int:
return self.getInt(column_index)
def getFloat(self, column_index: int) -> float:
v = self.getString(column_index)
if v is None:
return 0.0
try:
return float(v)
except (ValueError, TypeError):
return 0.0
def getDouble(self, column_index: int) -> float:
return self.getFloat(column_index)
def getBlob(self, column_index: int) -> Optional[bytes]:
if self._pos < 0 or self._pos >= len(self._rows):
return None
if column_index < 0 or column_index >= len(self._rows[self._pos]):
return None
v = self._rows[self._pos][column_index]
if isinstance(v, bytes):
return v
if isinstance(v, str):
return v.encode("utf-8")
return None
def getType(self, column_index: int) -> int:
v = None
if 0 <= self._pos < len(self._rows):
row = self._rows[self._pos]
if 0 <= column_index < len(row):
v = row[column_index]
if v is None:
return Cursor.FIELD_TYPE_NULL
if isinstance(v, int):
return Cursor.FIELD_TYPE_INTEGER
if isinstance(v, float):
return Cursor.FIELD_TYPE_FLOAT
if isinstance(v, bytes):
return Cursor.FIELD_TYPE_BLOB
return Cursor.FIELD_TYPE_STRING
def isNull(self, column_index: int) -> bool:
return self.getType(column_index) == Cursor.FIELD_TYPE_NULL
def toString(self) -> str:
return f"MatrixCursor(cols={self._column_names}, rows={len(self._rows)})"
# ═══════════════════════════════════════════════════════════════
# MergeCursor
# ═══════════════════════════════════════════════════════════════
class MergeCursor(AbstractCursor):
"""MergeCursor — 合并多个游标"""
def __init__(self, cursors: List[Cursor]):
super().__init__()
self._cursors = cursors
self._cursor_index = 0
self._current_cursor: Optional[Cursor] = None
def getCount(self) -> int:
return sum(c.getCount() for c in self._cursors)
def getColumnNames(self) -> List[str]:
if self._cursors:
return self._cursors[0].getColumnNames()
return []
def moveToPosition(self, position: int) -> bool:
if position < -1:
return False
if position >= self.getCount():
return False
offset = 0
for i, c in enumerate(self._cursors):
count = c.getCount()
if position < offset + count:
self._cursor_index = i
self._current_cursor = c
return c.moveToPosition(position - offset)
offset += count
return False
def getString(self, column_index: int) -> Optional[str]:
if self._current_cursor and self._pos >= 0:
return self._current_cursor.getString(column_index)
return None
def getInt(self, column_index: int) -> int:
if self._current_cursor and self._pos >= 0:
return self._current_cursor.getInt(column_index)
return 0
def close(self):
for c in self._cursors:
c.close()
super().close()
# ═══════════════════════════════════════════════════════════════
# CursorJoiner
# ═══════════════════════════════════════════════════════════════
class CursorJoiner(Stub):
"""CursorJoiner — 游标连接器"""
class Result(Stub):
BOTH = 0
LEFT = 1
RIGHT = 2
def __init__(self, cursor_a: Cursor, column_names_a: List[str],
cursor_b: Cursor, column_names_b: List[str]):
super().__init__()
self._cursor_a = cursor_a
self._cursor_b = cursor_b
self._col_names_a = column_names_a
self._col_names_b = column_names_b
self._has_next = False
def hasNext(self) -> bool:
return self._has_next
def next(self) -> int:
return self.Result.BOTH
# ═══════════════════════════════════════════════════════════════
# DatabaseUtils
# ═══════════════════════════════════════════════════════════════
class DatabaseUtils(Stub):
"""DatabaseUtils — 数据库工具"""
STATEMENT_ABORT = "ABORT"
STATEMENT_FAIL = "FAIL"
STATEMENT_IGNORE = "IGNORE"
STATEMENT_REPLACE = "REPLACE"
STATEMENT_ROLLBACK = "ROLLBACK"
@staticmethod
def cursorFillWindow(cursor: Cursor, pos: int, window: CursorWindow):
cursor.fillWindow(pos, window)
@staticmethod
def cursorStringToContentValues(cursor: Cursor, field: str, values: Any):
pass
@staticmethod
def cursorIntToContentValues(cursor: Cursor, field: str, values: Any):
pass
@staticmethod
def cursorLongToContentValues(cursor: Cursor, field: str, values: Any):
pass
@staticmethod
def cursorDoubleToContentValues(cursor: Cursor, field: str, values: Any):
pass
@staticmethod
def cursorRowToContentValues(cursor: Cursor, values: Any):
for col_name in cursor.getColumnNames():
idx = cursor.getColumnIndex(col_name)
val = cursor.getString(idx)
if hasattr(values, "put"):
values.put(col_name, val)
@staticmethod
def dumpCursor(cursor: Cursor):
col_names = cursor.getColumnNames()
sys.stderr.write(f"Rows: {cursor.getCount()}\n")
sys.stderr.write(f"Columns: {col_names}\n")
@staticmethod
def dumpCursorToString(cursor: Cursor) -> str:
return f"Cursor(count={cursor.getCount()})"
@staticmethod
def bindObjectToProgram(program: Any, index: int, value: Any):
pass
@staticmethod
def cursorToContentValues(cursor: Cursor, values: Any):
DatabaseUtils.cursorRowToContentValues(cursor, values)
@staticmethod
def longForQuery(db: Any, query: str, args: Optional[List[str]] = None) -> int:
return 0
@staticmethod
def stringForQuery(db: Any, query: str, args: Optional[List[str]] = None) -> Optional[str]:
return None
@staticmethod
def blobForQuery(db: Any, query: str, args: Optional[List[str]] = None) -> Optional[bytes]:
return None
@staticmethod
def sqlEscapeString(value: str) -> str:
return value.replace("'", "''")
@staticmethod
def appendEscapedSQLString(sb: Any, value: str):
escaped = DatabaseUtils.sqlEscapeString(value)
sb.append(f"'{escaped}'")
@staticmethod
def appendValueToSql(sb: Any, value: Any):
if value is None:
sb.append("NULL")
elif isinstance(value, bool):
sb.append("1" if value else "0")
elif isinstance(value, (int, float)):
sb.append(str(value))
else:
DatabaseUtils.appendEscapedSQLString(sb, str(value))
@staticmethod
def appendSelectionArgs(original_values: List[str], new_values: List[str]) -> List[str]:
return list(original_values) + list(new_values)
@staticmethod
def getCollationKey(name: str) -> str:
return name.lower()
@staticmethod
def getHexCollationKey(name: str) -> str:
return name.lower().encode("utf-8").hex()
@staticmethod
def createDbFromSqlStatements(context: Any, db_name: str, db_version: int, sql_statements: str):
from .database_sqlite import SQLiteDatabase
db_path = os.path.join(_app_data_dir, "databases", db_name)
os.makedirs(os.path.dirname(db_path), exist_ok=True)
db = SQLiteDatabase.openOrCreateDatabase(db_path, None)
for stmt in sql_statements.split(";"):
stmt = stmt.strip()
if stmt:
try:
db.execSQL(stmt)
except Exception:
pass
return db
# ═══════════════════════════════════════════════════════════════
# DatabaseUtilsInsertHelper
# ═══════════════════════════════════════════════════════════════
class DatabaseUtilsInsertHelper(Stub):
"""DatabaseUtils.InsertHelper — 插入辅助类"""
TABLE_INFO_PRAGMA_COLUMNNAME_INDEX = 1
def __init__(self, db: Any, table_name: str):
super().__init__()
self._db = db
self._table_name = table_name
def getTableName(self) -> str:
return self._table_name
def prepareForInsert(self) -> int:
return 0
def prepareForReplace(self) -> int:
return 0
def bind(self, index: int, value: Any):
pass
def execute(self) -> int:
return 0
def close(self):
pass
# ═══════════════════════════════════════════════════════════════
# Helper
# ═══════════════════════════════════════════════════════════════
class IllegalArgumentException(RuntimeError):
"""IllegalArgumentException — 非法参数异常"""
pass
# ═══════════════════════════════════════════════════════════════
# __all__
# ═══════════════════════════════════════════════════════════════
__all__ = [
"Cursor",
"MatrixCursor",
"AbstractCursor",
"AbstractWindowedCursor",
"ContentObservable",
"ContentObserver",
"DataSetObservable",
"DatabaseErrorHandler",
"DatabaseUtils",
"DefaultDatabaseErrorHandler",
"CharArrayBuffer",
"CursorJoiner",
"CursorWindow",
"CursorWrapper",
"CrossProcessCursor",
"CrossProcessCursorWrapper",
"DataSetObserver",
"MergeCursor",
"SQLException",
"CursorIndexOutOfBoundsException",
"DatabaseUtilsInsertHelper",
]