#!/usr/bin/env python

"""
Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""

# 导入sqlite3数据库模块
import sqlite3

# 导入一些辅助函数
from lib.core.common import cleanReplaceUnicode  # 用于清理和替换Unicode字符
from lib.core.common import getSafeExString      # 用于安全地获取异常信息字符串
from lib.core.common import unsafeSQLIdentificatorNaming  # 用于SQL标识符命名
from lib.core.exception import SqlmapConnectionException  # 数据库连接异常
from lib.core.exception import SqlmapGenericException    # 通用异常
from lib.core.exception import SqlmapValueException      # 值错误异常
from lib.core.settings import UNICODE_ENCODING          # Unicode编码设置
from lib.utils.safe2bin import safechardecode          # 字符安全解码

class Replication(object):
    """
    这个类包含了所有用于数据库复制功能的方法和类。
    主要用于管理SQLite数据库的复制操作。
    """

    def __init__(self, dbpath):
        """
        初始化复制功能
        参数:
            dbpath: 数据库文件路径
        """
        try:
            self.dbpath = dbpath  # 保存数据库路径
            self.connection = sqlite3.connect(dbpath)  # 建立数据库连接
            self.connection.isolation_level = None     # 设置隔离级别为None,允许手动控制事务
            self.cursor = self.connection.cursor()     # 创建数据库游标
        except sqlite3.OperationalError as ex:
            errMsg = "error occurred while opening a replication "
            errMsg += "file '%s' ('%s')" % (dbpath, getSafeExString(ex))
            raise SqlmapConnectionException(errMsg)

    class DataType(object):
        """
        这个内部类用于定义SQLite数据类型的辅助对象。
        用于表示数据库中的各种数据类型。
        """

        def __init__(self, name):
            """
            初始化数据类型
            参数:
                name: 数据类型名称
            """
            self.name = name

        def __str__(self):
            """返回数据类型的字符串表示"""
            return self.name

        def __repr__(self):
            """返回数据类型的详细字符串表示"""
            return "<DataType: %s>" % self

    class Table(object):
        """
        这个内部类定义了用于操作数据库表的方法。
        包含创建表、插入数据、执行SQL等功能。
        """

        def __init__(self, parent, name, columns=None, create=True, typeless=False):
            """
            初始化表对象
            参数:
                parent: 父对象(Replication实例)
                name: 表名
                columns: 列定义
                create: 是否创建新表
                typeless: 是否不指定列类型
            """
            self.parent = parent
            self.name = unsafeSQLIdentificatorNaming(name)  # 处理表名
            self.columns = columns
            if create:
                try:
                    # 如果表存在则删除
                    self.execute('DROP TABLE IF EXISTS "%s"' % self.name)
                    if not typeless:
                        # 创建带数据类型的表
                        self.execute('CREATE TABLE "%s" (%s)' % (self.name, ','.join('"%s" %s' % (unsafeSQLIdentificatorNaming(colname), coltype) for colname, coltype in self.columns)))
                    else:
                        # 创建不带数据类型的表
                        self.execute('CREATE TABLE "%s" (%s)' % (self.name, ','.join('"%s"' % unsafeSQLIdentificatorNaming(colname) for colname in self.columns)))
                except Exception as ex:
                    errMsg = "problem occurred ('%s') while initializing the sqlite database " % getSafeExString(ex, UNICODE_ENCODING)
                    errMsg += "located at '%s'" % self.parent.dbpath
                    raise SqlmapGenericException(errMsg)

        def insert(self, values):
            """
            向当前表中插入数据行
            参数:
                values: 要插入的值列表
            """

            if len(values) == len(self.columns):
                self.execute('INSERT INTO "%s" VALUES (%s)' % (self.name, ','.join(['?'] * len(values))), safechardecode(values))
            else:
                errMsg = "wrong number of columns used in replicating insert"
                raise SqlmapValueException(errMsg)

        def execute(self, sql, parameters=None):
            """
            执行SQL语句
            参数:
                sql: SQL语句
                parameters: SQL参数
            """
            try:
                try:
                    self.parent.cursor.execute(sql, parameters or [])
                except UnicodeError:
                    self.parent.cursor.execute(sql, cleanReplaceUnicode(parameters or []))
            except sqlite3.OperationalError as ex:
                errMsg = "problem occurred ('%s') while accessing sqlite database " % getSafeExString(ex, UNICODE_ENCODING)
                errMsg += "located at '%s'. Please make sure that " % self.parent.dbpath
                errMsg += "it's not used by some other program"
                raise SqlmapGenericException(errMsg)

        def beginTransaction(self):
            """
            开始事务
            使用显式事务可以大大提高多次插入操作的性能
            """
            self.execute('BEGIN TRANSACTION')

        def endTransaction(self):
            """结束事务"""
            self.execute('END TRANSACTION')

        def select(self, condition=None):
            """
            从当前表中选择数据
            参数:
                condition: WHERE条件子句
            """
            _ = 'SELECT * FROM %s' % self.name
            if condition:
                _ += 'WHERE %s' % condition
            return self.execute(_)

    def createTable(self, tblname, columns=None, typeless=False):
        """
        创建表对象
        参数:
            tblname: 表名
            columns: 列定义
            typeless: 是否不指定列类型
        """
        return Replication.Table(parent=self, name=tblname, columns=columns, typeless=typeless)

    def __del__(self):
        """
        析构函数
        关闭数据库连接和游标
        """
        self.cursor.close()
        self.connection.close()

    # SQLite数据类型定义
    NULL = DataType('NULL')      # 空值类型
    INTEGER = DataType('INTEGER')  # 整数类型
    REAL = DataType('REAL')      # 浮点数类型
    TEXT = DataType('TEXT')      # 文本类型
    BLOB = DataType('BLOB')      # 二进制数据类型
