Ppeixianzhongfix bug
10c4f6ad创建于 2025年8月21日历史提交
/*
 * @Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All rights reserved.
 */

package mysqlclient_ffi

/*
 * sql语句预执行
 */
public class MysqlStatement <: Statement {
    private var mysql: CPointer<Unit>
    var stmt: CPointer<Unit>
    let closed = AtomicBool(false)
    private let params: Array<Any>
    /*
     * 预执行sql语句中,占位的参数个数
     */
    public var parameterCount: Int64

    /*
     * 初始化sql语句预执行
     *
     * 参数 mysql - 初始化的mysql
     * 参数 stmt - 初始化的stmt
     */
    init(mysql: CPointer<Unit>, stmt: CPointer<Unit>) {
        this.mysql = mysql
        this.stmt = stmt
        var count: UInt64 = 0
        unsafe {
            // 预准备语句中的参数数
            count = mysql_stmt_param_count(stmt)
        }
        parameterCount = Int64(count)
        this.params = Array<Any>(parameterCount, repeat: Option<Any>.None)
    }

    /*
     * 预执行 sql 语句中,占位参数的列信息(不支持)
     */
    public override prop parameterColumnInfos: Array<ColumnInfo> {
        get() {
            return []
        }
    }

    /**
     * 设置预执行sql语句选项(不支持)
     */
    public override func setOption(_: String, _: String): Unit {
    }

    /**
     * 设置预执行sql语句选项
     *
     * 参数 option - C中枚举 enum enum_stmt_attr_type
     * 参数 arg - 值
     * 异常 SqlException - 参数设置错误。
     */
    public func setOption(option: MysqlStmtAttrType, arg: Bool): Unit {
        unsafe {
            let argCPointer: CPointer<Byte> = LibC.malloc<Byte>()
            if (argCPointer.isNull()) {
                throw SqlException("Native malloc Failed.")
            }
            if (arg) {
                argCPointer.write(1)
            } else {
                argCPointer.write(0)
            }
            let argCPointer1: CPointer<Unit> = CPointer<Unit>(argCPointer)

            // 设置预准备语句的属性值
            let isBool: Bool = mysql_stmt_attr_set(stmt, option.toInt32(), argCPointer1)
            LibC.free<Byte>(argCPointer)
            if (isBool) {
                // 发生错误为非零值
                throw SqlException(mysql_stmt_error(stmt).toString())
            }
        }
    }

    /**
     * 设置预执行sql语句选项
     *
     * 参数 option - C中枚举 enum enum_stmt_attr_type
     * 参数 arg - 值
     * 异常 SqlException - 参数设置错误。
     */
    public func setOption(option: MysqlStmtAttrType, arg: UInt64): Unit {
        unsafe {
            let argCPointer: CPointer<UInt64> = LibC.malloc<UInt64>()
            if (argCPointer.isNull()) {
                throw SqlException("Native malloc Failed.")
            }
            argCPointer.write(arg)
            let argCPointer1: CPointer<Unit> = CPointer<Unit>(argCPointer)

            // 设置预准备语句的属性值
            let isBool: Bool = mysql_stmt_attr_set(stmt, option.toInt32(), argCPointer1)
            LibC.free<UInt64>(argCPointer)
            if (isBool) {
                // 发生错误为非零值
                throw SqlException(mysql_stmt_error(stmt).toString())
            }
        }
    }

    /**
     * 设置预执行sql语句参数
     *
     * 参数 index - 位置
     * 参数 value - 值
     * 异常 Exception - 参数设置错误。
     */
    public override func set<T>(index: Int, value: T): Unit {
        checkResource()
        if (index < 0) {
            throw SqlException("The parameter index must be greater than 0")
        }
        if (index > parameterCount -1) {
            throw SqlException("parameter index error")
        }
        func unwrap<T>(value: ?T) {
            if (let Some(v) <- value) {
                params[index] = v
            } else {
                params[index] = Option<Any>.None
            }
        }
        match (value) {
            case v: ?Bool => unwrap(v)
            case v: ?Int8 => unwrap(v)
            case v: ?UInt8 => unwrap(v)
            case v: ?Int16 => unwrap(v)
            case v: ?UInt16 => unwrap(v)
            case v: ?Int32 => unwrap(v)
            case v: ?UInt32 => unwrap(v)
            case v: ?Int64 => unwrap(v)
            case v: ?UInt64 => unwrap(v)
            case v: ?Float16 => unwrap(v)
            case v: ?Float32 => unwrap(v)
            case v: ?Float64 => unwrap(v)
            case v: ?Rune => unwrap(v)
            case v: ?String => unwrap(v)
            case v: ?DateTime => unwrap(v)
            case v: ?BigInt => unwrap(v)
            case v: ?Decimal => unwrap(v)
            case v: ?Array<Byte> => unwrap(v)
            case v: ?InputStream => unwrap(v)
            case _ => params[index] = value
        }
    }

    /**
     * 设置预执行sql语句null参数
     *
     * 参数 index - 位置
     * 异常 Exception - 参数设置错误。
     */
    public override func setNull(index: Int): Unit {
        checkResource()
        if (index < 0) {
            throw SqlException("The parameter index must be greater than 0")
        }
        if (index > parameterCount -1) {
            throw SqlException("parameter index error")
        }
        params[index] = Option<Any>.None
    }

    /**
     * 执行sql语句,得到更新结果
     *
     * 返回值 UpdateResult - 更新结果。
     * 异常 Exception - 传入参数错误。
     */
    public override func update(): MysqlUpdateResult {
        checkResource()
        let rows: Int64
        unsafe {
            var bindsCPInt8: CPointer<Int8> = LibC.malloc<Int8>(count: 8)
            var bindsCP: CPointer<Unit> = CPointer<Unit>(bindsCPInt8)
            if (bindsCP.isNull()) {
                throw SqlException("Native malloc Failed.")
            }
            if (params.size > 0) {
                bindsCP = init_bind(params.size)
            }
            if (bindsCP.isNull()) {
                // 初始化失败,有可能内存不足导致的malloc失败
                throw SqlException("Init Bind Failed!")
            }
            for (i in 0..params.size) {
                var isBool: Bool = cjTypeToMysqlType(bindsCP, i, params[i])
                if (!isBool) {
                    free_mysql_cj(bindsCP, i)
                    throw SqlException("Malloc  Failed!")
                }
            }
            // 将应用程序数据缓冲区与prepared语句中的参数标记关联
            let isBool: Bool = mysql_stmt_bind_param(stmt, bindsCP)
            if (isBool) {
                free_mysql_cj(bindsCP, params.size)
                // 发生错误非零值,true在c语言中是1,false是0.
                throw SqlException(mysql_stmt_error(stmt).toString())
            }
            // 执行预准备语句
            let execute: Int32 = mysql_stmt_execute(stmt)
            if (execute != 0) {
                free_mysql_cj(bindsCP, params.size)
                // 发生错误非零值
                throw SqlException(mysql_stmt_error(stmt).toString())
            }
            free_mysql_cj(bindsCP, params.size)
            // 上次更新、删除或插入语句更改/删除/插入的行数
            rows = Int64(mysql_stmt_affected_rows(stmt))
            return MysqlUpdateResult(rows, this.stmt)
        }
    }

    /**
     * 执行sql语句,得到查询结果
     *
     * 返回值 QueryResult - 查询结果。
     * 异常 Exception - 传入参数错误。
     */
    public override func query(): MysqlQueryResult {
        checkResource()
        unsafe {
            var bindsCPInt8: CPointer<Int8> = LibC.malloc<Int8>(count: 8)
            var bindsCP: CPointer<Unit> = CPointer<Unit>(bindsCPInt8)
            if (bindsCP.isNull()) {
                throw SqlException("Native malloc Failed.")
            }
            if (params.size > 0) {
                bindsCP = init_bind(params.size)
            }
            if (bindsCP.isNull()) {
                // 初始化失败,有可能内存不足导致的malloc失败
                throw SqlException("Init Bind Failed!")
            }
            for (i in 0..params.size) {
                var isBool: Bool = cjTypeToMysqlType(bindsCP, i, params[i])
                if (!isBool) {
                    free_mysql_cj(bindsCP, i)
                    throw SqlException("Malloc  Failed!")
                }
            }
            // 将应用程序数据缓冲区与prepared语句中的参数标记关联
            let isBool: Bool = mysql_stmt_bind_param(stmt, bindsCP)
            if (isBool) {
                free_mysql_cj(bindsCP, params.size)
                // 发生错误非零值,true在c语言中是1,false是0.
                throw SqlException(mysql_stmt_error(stmt).toString())
            }
            let execute: Int32 = mysql_stmt_execute(stmt)
            if (execute != 0) {
                free_mysql_cj(bindsCP, params.size)
                // 发生错误非零值
                throw SqlException(mysql_stmt_error(stmt).toString())
            }
            free_mysql_cj(bindsCP, params.size)
            return MysqlQueryResult(stmt, getInfo())
        }
    }

    /**
     * 执行sql语句,得到更新结果 - todo:废弃
     *
     * 参数 _ - 填充预执行语句中问号的数据。
     * 返回值 UpdateResult - 更新结果。
     * 异常 SqlException - 传入参数错误。
     */
    @Deprecated
    public override func update(params: Array<SqlDbType>): MysqlUpdateResult {
        let rows: Int64
        if (parameterCount == params.size) {
            unsafe {
                var bindsCPInt8: CPointer<Int8> = LibC.malloc<Int8>(count:8)
                var bindsCP: CPointer<Unit> = CPointer<Unit>(bindsCPInt8)
                if (bindsCP.isNull()) {
                    throw SqlException("Native malloc Failed.")
                }
                if (params.size > 0) {
                    bindsCP = init_bind(params.size)
                }
                if (bindsCP.isNull()) {
                    // 初始化失败,有可能内存不足导致的malloc失败
                    throw SqlException("Init Bind Failed!")
                }
                for (i in 0..params.size) {
                    var isBool: Bool = cjTypeToMysqlOldType(bindsCP, i, params[i])
                    if (!isBool) {
                        free_mysql_cj(bindsCP, i)
                        throw SqlException("Malloc  Failed!")
                    }
                }

                // 将应用程序数据缓冲区与prepared语句中的参数标记关联
                let isBool: Bool = mysql_stmt_bind_param(stmt, bindsCP)
                if (isBool) {
                    free_mysql_cj(bindsCP, params.size)

                    // 发生错误非零值,true在c语言中是1,false是0.
                    throw SqlException(mysql_stmt_error(stmt).toString())
                }

                // 	执行预准备语句
                let execute: Int32 = mysql_stmt_execute(stmt)
                if (execute != 0) {
                    free_mysql_cj(bindsCP, params.size)

                    // 发生错误非零值
                    throw SqlException(mysql_stmt_error(stmt).toString())
                }
                free_mysql_cj(bindsCP, params.size)

                // 上次更新、删除或插入语句更改/删除/插入的行数
                rows = Int64(mysql_stmt_affected_rows(stmt))
                return MysqlUpdateResult(rows, this.stmt)
            }
        } else {
            throw SqlException("update wrong number of parameters.")
        }
    }

    /**
     * 执行sql语句,得到查询结果 - todo:废弃
     *
     * 参数 _ - 填充预执行语句中问号的数据。
     * 返回值 QueryResult - 查询结果。
     * 异常 SqlException - 传入参数错误。
     */
    @Deprecated
    public override func query(params: Array<SqlDbType>): MysqlQueryResult {
        if (parameterCount == params.size) {
            unsafe {
                var bindsCPInt8: CPointer<Int8> = LibC.malloc<Int8>(count:8)
                var bindsCP: CPointer<Unit> = CPointer<Unit>(bindsCPInt8)
                if (bindsCP.isNull()) {
                    throw SqlException("Native malloc Failed.")
                }
                if (params.size > 0) {
                    bindsCP = init_bind(params.size)
                }
                if (bindsCP.isNull()) {
                    // 初始化失败,有可能内存不足导致的malloc失败
                    throw SqlException("Init Bind Failed!")
                }
                for (i in 0..params.size) {
                    var isBool: Bool = cjTypeToMysqlOldType(bindsCP, i, params[i])
                    if (!isBool) {
                        free_mysql_cj(bindsCP, i)
                        throw SqlException("Malloc  Failed!")
                    }
                }

                // 将应用程序数据缓冲区与prepared语句中的参数标记关联
                let isBool: Bool = mysql_stmt_bind_param(stmt, bindsCP)
                if (isBool) {
                    free_mysql_cj(bindsCP, params.size)

                    // 发生错误非零值,true在c语言中是1,false是0.
                    throw SqlException(mysql_stmt_error(stmt).toString())
                }
                let execute: Int32 = mysql_stmt_execute(stmt)
                if (execute != 0) {
                    free_mysql_cj(bindsCP, params.size)

                    // 发生错误非零值
                    throw SqlException(mysql_stmt_error(stmt).toString())
                }
                free_mysql_cj(bindsCP, params.size)

                return MysqlQueryResult(stmt, getOldInfo())
            }
        } else {
            throw SqlException("query wrong number of parameters.")
        }
    }

    /*
     * 关闭资源
     *
     * 异常 SqlException - 关闭资源失败。
     */
    public override func close(): Unit {
        if (isClosed()) {
            return
        }
        closed.store(true)
        unsafe {
            // 释放预准备语句内存资源
            let isBool: Bool = mysql_stmt_close(stmt)
            if (isBool) {
                throw SqlException(mysql_stmt_error(stmt).toString())
            }
        }
    }

    /*
     * 判断资源是否关闭
     *
     * 返回值 Bool - 如果已经关闭返回true,否则返回false
     */
    public override func isClosed(): Bool {
        return closed.load()
    }

    private func checkResource() {
        if (isClosed()) {
            throw SqlException("The Statement has been closed")
        }
    }

    private func getInfo(): Array<MysqlColumnInfo> {
        unsafe {
            let metadataUnit: CPointer<Unit> = mysql_stmt_result_metadata(stmt)
            if (metadataUnit.isNull()) {
                // 不存在准备好的元信息申明,返回NULL
                throw SqlException(mysql_stmt_error(stmt).toString())
            }
            let columnCount: UInt32 = mysql_stmt_field_count(stmt)
            let columnCountInt64: Int64 = Int64(columnCount)
            var cMysqlColumnInfos: Array<MYSQL_COLUMN_INFO> = Array<MYSQL_COLUMN_INFO>(
                columnCountInt64,
                repeat: MYSQL_COLUMN_INFO()
            )
            var cp: CPointerHandle<MYSQL_COLUMN_INFO> = acquireArrayRawData<MYSQL_COLUMN_INFO>(
                cMysqlColumnInfos.toArray())
            let bytesCPointer: CPointer<MYSQL_COLUMN_INFO> = cp.pointer
            get_res_data(metadataUnit, columnCountInt64, bytesCPointer)
            var mysqlColumnInfos: Array<MysqlColumnInfo> = Array<MysqlColumnInfo>(
                columnCountInt64,
                repeat: MysqlColumnInfo("", "", 0, 0, 0, false)
            )
            for (i in 0..columnCountInt64) {
                var field: MYSQL_COLUMN_INFO = bytesCPointer.read(i)
                var mysqlColumnInfo: MysqlColumnInfo = MysqlColumnInfo(
                    field.name_string.toString(),
                    mysqlType(field.field_type),
                    field.display_size_int64,
                    field.length_int64,
                    field.scale_int64,
                    field.flags % 2 != 0
                )
                mysqlColumnInfos[i] = mysqlColumnInfo
            }
            releaseArrayRawData<MYSQL_COLUMN_INFO>(cp)
            mysql_free_result(metadataUnit)
            return mysqlColumnInfos
        }
    }

    private func getOldInfo(): Array<MysqlColumnInfo> {
        unsafe {
            let metadataUnit: CPointer<Unit> = mysql_stmt_result_metadata(stmt)
            if (metadataUnit.isNull()) {
                // 不存在准备好的元信息申明,返回NULL
                throw SqlException(mysql_stmt_error(stmt).toString())
            }
            let columnCount: UInt32 = mysql_stmt_field_count(stmt)
            let columnCountInt64: Int64 = Int64(columnCount)
            var cMysqlColumnInfos: Array<MYSQL_COLUMN_INFO> = Array<MYSQL_COLUMN_INFO>(
                columnCountInt64,
                repeat: MYSQL_COLUMN_INFO()
            )
            var cp: CPointerHandle<MYSQL_COLUMN_INFO> = acquireArrayRawData<MYSQL_COLUMN_INFO>(
                cMysqlColumnInfos.toArray())
            let bytesCPointer: CPointer<MYSQL_COLUMN_INFO> = cp.pointer
            get_res_data(metadataUnit, columnCountInt64, bytesCPointer)
            var mysqlColumnInfos: Array<MysqlColumnInfo> = Array<MysqlColumnInfo>(
                columnCountInt64,
                repeat: MysqlColumnInfo("", "", 0, 0, 0, false)
            )
            for (i in 0..columnCountInt64) {
                var field: MYSQL_COLUMN_INFO = bytesCPointer.read(i)
                var mysqlColumnInfo: MysqlColumnInfo = MysqlColumnInfo(
                    field.name_string.toString(),
                    mysqlOldType(field.field_type, field.flags % 2 != 0),
                    field.display_size_int64,
                    field.length_int64,
                    field.scale_int64,
                    field.flags % 2 != 0
                )
                mysqlColumnInfos[i] = mysqlColumnInfo
            }
            releaseArrayRawData<MYSQL_COLUMN_INFO>(cp)
            mysql_free_result(metadataUnit)
            return mysqlColumnInfos
        }
    }
}

func cjTypeToMysqlType(bindsCP: CPointer<Unit>, index: Int64, sqlDbType: Any): Bool {
    return match (sqlDbType) {
        // String --- SqlChar/SqlVarchar --- CHAR/VARCHAR --- CHAR/VARCHAR --- MYSQL_TYPE_STRING/MYSQL_TYPE_VAR_STRING --- char[]
        case v: String => setString(bindsCP, index, v)
        case v: ?String => setString(bindsCP, index, v)
        // Array<Byte> --- SqlBinary/SqlVarBinary --- BINARY/VARBINARY --- BINARY/VARBINARY --- MYSQL_TYPE_BLOB --- char[]
        case v: Array<Byte> => setBytes(bindsCP, index, v)
        case v: ?Array<Byte> => setBytes(bindsCP, index, v)
        // InputStream --- SqlBlob/SqlClob --- BLOB/CLOB --- BLOB/LONGTEXT --- MYSQL_TYPE_BLOB/MYSQL_TYPE_LONG_BLOB --- char[]
        case v: InputStream => setBlob(bindsCP, index, v)
        case v: ?InputStream => setBlob(bindsCP, index, v)
        // Bool --- SqlBool --- BOOLEAN --- TINYINT --- MYSQL_TYPE_TINY --- signed char
        case v: Bool => setBool(bindsCP, index, v)
        case v: ?Bool => setBool(bindsCP, index, v)
        // Int8 --- SqlByte --- TINYINT --- TINYINT --- MYSQL_TYPE_TINY --- signed char
        case v: Int8 => setInt8(bindsCP, index, v)
        case v: ?Int8 => setInt8(bindsCP, index, v)
        // UInt8 --- Int8 --- SqlByte --- TINYINT --- TINYINT --- MYSQL_TYPE_TINY --- signed char
        case v: UInt8 => setUInt8(bindsCP, index, v)
        case v: ?UInt8 => setUInt8(bindsCP, index, v)
        // Int16 --- SqlSmallInt --- SMALLINT --- SMALLINT --- MYSQL_TYPE_SHORT --- short int
        case v: Int16 => setInt16(bindsCP, index, v)
        case v: ?Int16 => setInt16(bindsCP, index, v)
        // UInt16 --- Int16 --- SqlSmallInt --- SMALLINT --- SMALLINT --- MYSQL_TYPE_SHORT --- short int
        case v: UInt16 => setUInt16(bindsCP, index, v)
        case v: ?UInt16 => setUInt16(bindsCP, index, v)
        // Int32 --- SqlInteger --- INTEGER --- INT --- MYSQL_TYPE_LONG --- int
        case v: Int32 => setInt32(bindsCP, index, v)
        case v: ?Int32 => setInt32(bindsCP, index, v)
        // UInt32 --- Int32 --- SqlInteger --- INTEGER --- INT --- MYSQL_TYPE_LONG --- int
        case v: UInt32 => setUInt32(bindsCP, index, v)
        case v: ?UInt32 => setUInt32(bindsCP, index, v)
        // Int64 --- SqlBigInt --- BIGINT --- BIGINT --- MYSQL_TYPE_LONGLONG --- long long int
        case v: Int64 => setInt64(bindsCP, index, v)
        case v: ?Int64 => setInt64(bindsCP, index, v)
        // UInt64 --- Int64 --- SqlBigInt --- BIGINT --- BIGINT --- MYSQL_TYPE_LONGLONG --- long long int
        case v: UInt64 => setUInt64(bindsCP, index, v)
        case v: ?UInt64 => setUInt64(bindsCP, index, v)
        // Float32 --- SqlReal --- REAL --- FLOAT --- MYSQL_TYPE_FLOAT --- float
        case v: Float32 => setFloat32(bindsCP, index, v)
        case v: ?Float32 => setFloat32(bindsCP, index, v)
        // Float64 --- SqlDouble --- DOUBLE --- DOUBLE --- MYSQL_TYPE_DOUBLE --- double
        case v: Float64 => setFloat64(bindsCP, index, v)
        case v: ?Float64 => setFloat64(bindsCP, index, v)
        // DateTime --- SqlDateTime --- DATETIME --- DATETIME --- MYSQL_TYPE_DATETIME --- MYSQL_TIME
        case v: DateTime => setDateTime(bindsCP, index, v)
        case v: ?DateTime => setDateTime(bindsCP, index, v)
        // MysqlTypeDate --- DateTime --- SqlDate ---  DATE --- DATE --- MYSQL_TYPE_DATE --- MYSQL_TIME
        case v: MysqlTypeDate => setDate(bindsCP, index, v)
        case v: ?MysqlTypeDate => setDate(bindsCP, index, v)
        // MysqlTypeTime --- DateTime --- SqlTime --- TIME --- TIME --- MYSQL_TYPE_TIME --- MYSQL_TIME
        case v: MysqlTypeTime => setTime(bindsCP, index, v)
        case v: ?MysqlTypeTime => setTime(bindsCP, index, v)
        // MysqlTypeTimeTimestamp --- DateTime --- SqlTimestamp --- TIMESTAMP --- TIMESTAMP --- MYSQL_TYPE_TIMESTAMP --- MYSQL_TIME
        case v: MysqlTypeTimeTimestamp => setTimestamp(bindsCP, index, v)
        case v: ?MysqlTypeTimeTimestamp => setTimestamp(bindsCP, index, v)
        // DECIMAL --- MYSQL_TYPE_NEWDECIMAL
        case v: Decimal => setDecimal(bindsCP, index, v)
        case v: ?Decimal => setDecimal(bindsCP, index, v)
        // null
        case v: ?Any => setNull(bindsCP, index)
        // 其他参数
        case _ => throw SqlException("Unsupported data type.")
    }
}

func setString(bindsCP: CPointer<Unit>, index: Int64, value: Option<String>): Bool {
    match (value) {
        case Some(v) => unsafe {
            let strCtring: CString = LibC.mallocCString(v)
            var ret = set_string(bindsCP, index, strCtring)
            LibC.free(strCtring)
            return ret
        }
        case None => unsafe {
            set_null(bindsCP, index)
        }
    }
}

func setBytes(bindsCP: CPointer<Unit>, index: Int64, value: Option<Array<Byte>>): Bool {
    match (value) {
        case Some(v) => unsafe {
            var cp: CPointerHandle<Byte> = acquireArrayRawData<Byte>(v)
            let bytesCPointer: CPointer<UInt8> = cp.pointer
            var ret = set_bytes(bindsCP, index, bytesCPointer, v.size)
            releaseArrayRawData<Byte>(cp)
            return ret
        }
        case None => unsafe {
            set_null(bindsCP, index)
        }
    }
}

func setBlob(bindsCP: CPointer<Unit>, index: Int64, value: Option<InputStream>): Bool {
    match (value) {
        case Some(v) =>
            var arr: Array<Byte> = Array<Byte>(1, repeat: 0)
            var list: ArrayList<Byte> = ArrayList<Byte>()
            var length: Int64 = 0
            while (true) {
                var date: Int64 = v.read(arr)
                if (date == 0) {
                    break
                }
                list.add(arr[0])
                length++
            }
            unsafe {
                var cp: CPointerHandle<Byte> = acquireArrayRawData<Byte>(list.toArray())
                let bytesCPointer: CPointer<UInt8> = cp.pointer
                var ret = set_blob(bindsCP, index, bytesCPointer, list.size)
                releaseArrayRawData<Byte>(cp)
                return ret
            }
        case None => unsafe {
            set_null(bindsCP, index)
        }
    }
}

func setBool(bindsCP: CPointer<Unit>, index: Int64, value: Option<Bool>): Bool {
    match (value) {
        case Some(v) => unsafe {
            if (v) {
                set_bool(bindsCP, index, 1)
            } else {
                set_bool(bindsCP, index, 0)
            }
        }
        case None => unsafe {
            set_null(bindsCP, index)
        }
    }
}

func setInt8(bindsCP: CPointer<Unit>, index: Int64, value: Option<Int8>): Bool {
    match (value) {
        case Some(v) => unsafe {
            set_int8(bindsCP, index, v)
        }
        case None => unsafe {
            set_null(bindsCP, index)
        }
    }
}

@OverflowWrapping
func setUInt8(bindsCP: CPointer<Unit>, index: Int64, value: Option<UInt8>): Bool {
    match (value) {
        case Some(v) => unsafe {
            set_int8(bindsCP, index, Int8(v))
        }
        case None => unsafe {
            set_null(bindsCP, index)
        }
    }
}

func setInt16(bindsCP: CPointer<Unit>, index: Int64, value: Option<Int16>): Bool {
    match (value) {
        case Some(v) => unsafe {
            set_int16(bindsCP, index, v)
        }
        case None => unsafe {
            set_null(bindsCP, index)
        }
    }
}

@OverflowWrapping
func setUInt16(bindsCP: CPointer<Unit>, index: Int64, value: Option<UInt16>): Bool {
    match (value) {
        case Some(v) => unsafe {
            set_int16(bindsCP, index, Int16(v))
        }
        case None => unsafe {
            set_null(bindsCP, index)
        }
    }
}


func setInt32(bindsCP: CPointer<Unit>, index: Int64, value: Option<Int32>): Bool {
    match (value) {
        case Some(v) => unsafe {
            set_int32(bindsCP, index, v)
        }
        case None => unsafe {
            set_null(bindsCP, index)
        }
    }
}

@OverflowWrapping
func setUInt32(bindsCP: CPointer<Unit>, index: Int64, value: Option<UInt32>): Bool {
    match (value) {
        case Some(v) => unsafe {
            set_int32(bindsCP, index, Int32(v))
        }
        case None => unsafe {
            set_null(bindsCP, index)
        }
    }
}

func setInt64(bindsCP: CPointer<Unit>, index: Int64, value: Option<Int64>): Bool {
    match (value) {
        case Some(v) => unsafe {
            set_int64(bindsCP, index, v)
        }
        case None => unsafe {
            set_null(bindsCP, index)
        }
    }
}

@OverflowWrapping
func setUInt64(bindsCP: CPointer<Unit>, index: Int64, value: Option<UInt64>): Bool {
    match (value) {
        case Some(v) => unsafe {
            set_int64(bindsCP, index, Int64(v))
        }
        case None => unsafe {
            set_null(bindsCP, index)
        }
    }
}

func setFloat32(bindsCP: CPointer<Unit>, index: Int64, value: Option<Float32>): Bool {
    match (value) {
        case Some(v) => unsafe {
            set_float32(bindsCP, index, v)
        }
        case None => unsafe {
            set_null(bindsCP, index)
        }
    }
}

func setFloat64(bindsCP: CPointer<Unit>, index: Int64, value: Option<Float64>): Bool {
    match (value) {
        case Some(v) => unsafe {
            set_float64(bindsCP, index, v)
        }
        case None => unsafe {
            set_null(bindsCP, index)
        }
    }
}

func setDate(bindsCP: CPointer<Unit>, index: Int64, value: Option<MysqlTypeDate>): Bool {
    match (value) {
        case Some(v) => unsafe {
            set_date(bindsCP, index, UInt32(v.value.year), UInt32(v.value.month.toInteger()), UInt32(v.value.dayOfMonth))
        }
        case None => unsafe {
            set_null(bindsCP, index)
        }
    }
}

func setTime(bindsCP: CPointer<Unit>, index: Int64, value: Option<MysqlTypeTime>): Bool {
    match (value) {
        case Some(v) => unsafe {
            set_time(bindsCP, index, UInt32(v.value.hour), UInt32(v.value.minute), UInt32(v.value.second))
        }
        case None => unsafe {
            set_null(bindsCP, index)
        }
    }
}

func setTimestamp(bindsCP: CPointer<Unit>, index: Int64, value: Option<MysqlTypeTimeTimestamp>): Bool {
    match (value) {
        case Some(v) => unsafe {
            set_timestamp(
                bindsCP,
                index,
                UInt32(v.value.year),
                UInt32(v.value.month.toInteger()),
                UInt32(v.value.dayOfMonth),
                UInt32(v.value.hour),
                UInt32(v.value.minute),
                UInt32(v.value.second)
            )
        }
        case None => unsafe {
            set_null(bindsCP, index)
        }
    }
}

func setDateTime(bindsCP: CPointer<Unit>, index: Int64, value: Option<DateTime>): Bool {
    match (value) {
        case Some(v) => unsafe {
            set_date_time(
                bindsCP,
                index,
                UInt32(v.year),
                UInt32(v.month.toInteger()),
                UInt32(v.dayOfMonth),
                UInt32(v.hour),
                UInt32(v.minute),
                UInt32(v.second)
            )
        }
        case None => unsafe {
            set_null(bindsCP, index)
        }
    }
}

func setDecimal(bindsCP: CPointer<Unit>, index: Int64, value: Option<Decimal>): Bool {
    match (value) {
        case Some(v) => unsafe {
            let strCtring: CString = LibC.mallocCString(v.toString())
            var ret = set_decimal(bindsCP, index, strCtring)
            LibC.free(strCtring)
            return ret
        }
        case None => unsafe {
            set_null(bindsCP, index)
        }
    }
}

func setNull(bindsCP: CPointer<Unit>, index: Int64): Bool {
    unsafe {
        set_null(bindsCP, index)
    }
}

func mysqlType(types: Int32): String {
    match (types) {
        case 1 => return MysqlTypeEnum.SqlInt8.toString() // MYSQL_TYPE_TINY
        case 2 => return MysqlTypeEnum.SqlInt16.toString() // MYSQL_TYPE_SHORT
        case 3 | 9 => return MysqlTypeEnum.SqlInt32.toString() // MYSQL_TYPE_LONG | MYSQL_TYPE_INT24
        case 4 => return MysqlTypeEnum.SqlFloat32.toString() // MYSQL_TYPE_FLOAT
        case 5 => return MysqlTypeEnum.SqlFloat64.toString() // MYSQL_TYPE_DOUBLE
        case 6 => return MysqlTypeEnum.SqlNull.toString() // MYSQL_TYPE_NULL
        case 7 => return MysqlTypeEnum.SqlMysqlTypeTimeTimestamp.toString() // MYSQL_TYPE_TIMESTAMP
        case 8 => return MysqlTypeEnum.SqlInt64.toString() // MYSQL_TYPE_LONGLONG
        case 10 => return MysqlTypeEnum.SqlMysqlTypeDate.toString() // MYSQL_TYPE_DATE
        case 11 => return MysqlTypeEnum.SqlMysqlTypeTime.toString() // MYSQL_TYPE_TIME
        case 12 => return MysqlTypeEnum.SqlDateTime.toString() // MYSQL_TYPE_DATETIME
        case 246 => return MysqlTypeEnum.SqlDecimal.toString() // MYSQL_TYPE_NEWDECIMAL
        case 249 | 250 | 251 | 252 => return MysqlTypeEnum.SqlArrayByte.toString() // MYSQL_TYPE_TINY_BLOB | MYSQL_TYPE_MEDIUM_BLOB | MYSQL_TYPE_LONG_BLOB | MYSQL_TYPE_BLOB
        case 253 | 254 => return MysqlTypeEnum.SqlString.toString() // MYSQL_TYPE_VAR_STRING | MYSQL_TYPE_STRING
        case _ => return MysqlTypeEnum.SqlOther.toString()
    }
}

func cjTypeToMysqlOldType(bindsCP: CPointer<Unit>, index: Int64, sqlDbType: SqlDbType): Bool {
    return match (sqlDbType) {
        // String----SqlChar----CHAR----CHAR----MYSQL_TYPE_STRING----char[]
        case v: SqlChar => setOldString(bindsCP, index, v.value)
        case v: SqlNullableChar => setOldString(bindsCP, index, v.value)

        // String----SqlVarchar----VARCHAR----VARCHAR----MYSQL_TYPE_VAR_STRING----char[]
        case v: SqlVarchar => setOldString(bindsCP, index, v.value)
        case v: SqlNullableVarchar => setOldString(bindsCP, index, v.value)

        // Array<Byte>----SqlBinary----BINARY----BINARY----MYSQL_TYPE_BLOB----char[]
        case v: SqlBinary => setOldBytes(bindsCP, index, v.value)
        case v: SqlNullableBinary => setOldBytes(bindsCP, index, v.value)

        // Array<Byte>----SqlVarBinary----VARBINARY----VARBINARY----MYSQL_TYPE_BLOB----char[]
        case v: SqlVarBinary => setOldBytes(bindsCP, index, v.value)
        case v: SqlNullableVarBinary => setOldBytes(bindsCP, index, v.value)

        // 长字符串,mysql输入对应表格没有给出,在输出表格有对应数据
        // Array<InputStream>----SqlClob----CLOB----LONGTEXT----MYSQL_TYPE_LONG_BLOB----char[]
        case v: SqlClob => setOldClob(bindsCP, index, v.value)
        case v: SqlNullableClob => setOldClob(bindsCP, index, v.value)

        // Array<InputStream>----SqlBlob----BLOB----BLOB----MYSQL_TYPE_BLOB----char[]
        case v: SqlBlob => setOldBlob(bindsCP, index, v.value)
        case v: SqlNullableBlob => setOldBlob(bindsCP, index, v.value)

        // 布尔类型在mysql数据库中表现形式是TINYINT
        // Bool----SqlBool----BOOLEAN----TINYINT----MYSQL_TYPE_TINY----signed char
        case v: SqlBool => setOldBool(bindsCP, index, v.value)
        case v: SqlNullableBool => setOldBool(bindsCP, index, v.value)

        // Int8----SqlByte----TINYINT----TINYINT----MYSQL_TYPE_TINY----signed char
        case v: SqlByte => setOldInt8(bindsCP, index, v.value)
        case v: SqlNullableByte => setOldInt8(bindsCP, index, v.value)

        // Int16----SqlSmallInt----SMALLINT----SMALLINT----MYSQL_TYPE_SHORT----short int
        case v: SqlSmallInt => setOldInt16(bindsCP, index, v.value)
        case v: SqlNullableSmallInt => setOldInt16(bindsCP, index, v.value)

        // SQL类型不同,但是数据值相对应
        // Int32----SqlInteger----INTEGER----INT----MYSQL_TYPE_LONG----int
        case v: SqlInteger => setOldInt32(bindsCP, index, v.value)
        case v: SqlNullableInteger => setOldInt32(bindsCP, index, v.value)

        // Int64----SqlBigInt----BIGINT----BIGINT----MYSQL_TYPE_LONGLONG----long long int
        case v: SqlBigInt => setOldInt64(bindsCP, index, v.value)
        case v: SqlNullableBigInt => setOldInt64(bindsCP, index, v.value)

        // SQL类型不同,但是数据值相对应
        // Float32----SqlReal----REAL----FLOAT----MYSQL_TYPE_FLOAT----float
        case v: SqlReal => setOldFloat32(bindsCP, index, v.value)
        case v: SqlNullableReal => setOldFloat32(bindsCP, index, v.value)

        // Float64----SqlDouble----DOUBLE----DOUBLE----MYSQL_TYPE_DOUBLE----double
        case v: SqlDouble => setOldFloat64(bindsCP, index, v.value)
        case v: SqlNullableDouble => setOldFloat64(bindsCP, index, v.value)

        // DateTime----SqlDate----DATE----DATE----MYSQL_TYPE_DATE----MYSQL_TIME
        case v: SqlDate => setOldDate(bindsCP, index, v.value)
        case v: SqlNullableDate => setOldDate(bindsCP, index, v.value)

        // DateTime----SqlTime----TIME----TIME----MYSQL_TYPE_TIME----MYSQL_TIME
        case v: SqlTime => setOldTime(bindsCP, index, v.value)
        case v: SqlNullableTime => setOldTime(bindsCP, index, v.value)

        // DateTime----SqlTimeTz----TIMETZ----TIME----MYSQL_TYPE_TIME----MYSQL_TIME
        // mysql不支持
        case _: SqlTimeTz => throw SqlException("Unsupported data type.")
        case _: SqlNullableTimeTz => throw SqlException("Unsupported data type.")

        // DateTime----SqlTimestamp----TIMESTAMP----TIMESTAMP----MYSQL_TYPE_TIMESTAMP----MYSQL_TIME
        case v: SqlTimestamp => setOldTimestamp(bindsCP, index, v.value)
        case v: SqlNullableTimestamp => setOldTimestamp(bindsCP, index, v.value)

        // Duration----SqlInterval----INTERVAL----DATE----MYSQL_TYPE_DATE----MYSQL_TIME
        // mysql不支持
        case _: SqlInterval => throw SqlException("Unsupported data type.")
        case _: SqlNullableInterval => throw SqlException("Unsupported data type.")

        // 自定义类
        // DATETIME----MYSQL_TYPE_DATETIME----MYSQL_TIME
        case v: SqlDateTime => setOldDateTime(bindsCP, index, v.value)
        case v: SqlNullableDateTime => setOldDateTime(bindsCP, index, v.value)

        // 自定义类
        // DECIMAL----MYSQL_TYPE_NEWDECIMAL
        case v: SqlDecimal => setOldDecimal(bindsCP, index, v.value)
        case v: SqlNullableDecimal => setOldDecimal(bindsCP, index, v.value)

        case _ => throw SqlException("Unsupported data type.")
    }
}

func setOldString(bindsCP: CPointer<Unit>, index: Int64, value: Option<String>): Bool {
    match (value) {
        case Some(v) => unsafe {
                let strCtring: CString = LibC.mallocCString(v)
                var ret = set_string(bindsCP, index, strCtring)
                LibC.free(strCtring)
                return ret
            }
        case None => unsafe {
                set_null(bindsCP, index)
            }
    }
}

func setOldBytes(bindsCP: CPointer<Unit>, index: Int64, value: Option<Array<Byte>>): Bool {
    match (value) {
        case Some(v) => unsafe {
                var cp: CPointerHandle<Byte> = acquireArrayRawData<Byte>(v)
                let bytesCPointer: CPointer<UInt8> = cp.pointer
                var ret = set_bytes(bindsCP, index, bytesCPointer, v.size)
                releaseArrayRawData<Byte>(cp)
                return ret
            }
        case None => unsafe {
                set_null(bindsCP, index)
            }
    }
}

func setOldClob(bindsCP: CPointer<Unit>, index: Int64, value: Option<InputStream>): Bool {
    match (value) {
        case Some(v) =>
            var arr: Array<Byte> = Array<Byte>(1, repeat: 0)
            var list: ArrayList<Byte> = ArrayList<Byte>()
            var length: Int64 = 0
            while (true) {
                var date: Int64 = v.read(arr)
                if (date == 0) {
                    break
                }
                list.add(arr[0])
                length++
            }
            unsafe {
                var cp: CPointerHandle<Byte> = acquireArrayRawData<Byte>(list.toArray())
                let bytesCPointer: CPointer<UInt8> = cp.pointer
                var ret = set_clob(bindsCP, index, bytesCPointer, list.size)
                releaseArrayRawData<Byte>(cp)
                return ret
            }
        case None => unsafe {
                set_null(bindsCP, index)
            }
    }
}

func setOldBlob(bindsCP: CPointer<Unit>, index: Int64, value: Option<InputStream>): Bool {
    match (value) {
        case Some(v) =>
            var arr: Array<Byte> = Array<Byte>(1, repeat: 0)
            var list: ArrayList<Byte> = ArrayList<Byte>()
            var length: Int64 = 0
            while (true) {
                var date: Int64 = v.read(arr)
                if (date == 0) {
                    break
                }
                list.add(arr[0])
                length++
            }
            unsafe {
                var cp: CPointerHandle<Byte> = acquireArrayRawData<Byte>(list.toArray())
                let bytesCPointer: CPointer<UInt8> = cp.pointer
                var ret = set_blob(bindsCP, index, bytesCPointer, list.size)
                releaseArrayRawData<Byte>(cp)
                return ret
            }
        case None => unsafe {
                set_null(bindsCP, index)
            }
    }
}

func setOldBool(bindsCP: CPointer<Unit>, index: Int64, value: Option<Bool>): Bool {
    match (value) {
        case Some(v) => unsafe {
                if (v) {
                    set_bool(bindsCP, index, 1)
                } else {
                    set_bool(bindsCP, index, 0)
                }
            }
        case None => unsafe {
                set_null(bindsCP, index)
            }
    }
}

func setOldInt8(bindsCP: CPointer<Unit>, index: Int64, value: Option<Int8>): Bool {
    match (value) {
        case Some(v) => unsafe {
                set_int8(bindsCP, index, v)
            }
        case None => unsafe {
                set_null(bindsCP, index)
            }
    }
}

func setOldInt16(bindsCP: CPointer<Unit>, index: Int64, value: Option<Int16>): Bool {
    match (value) {
        case Some(v) => unsafe {
                set_int16(bindsCP, index, v)
            }
        case None => unsafe {
                set_null(bindsCP, index)
            }
    }
}

func setOldInt32(bindsCP: CPointer<Unit>, index: Int64, value: Option<Int32>): Bool {
    match (value) {
        case Some(v) => unsafe {
                set_int32(bindsCP, index, v)
            }
        case None => unsafe {
                set_null(bindsCP, index)
            }
    }
}

func setOldInt64(bindsCP: CPointer<Unit>, index: Int64, value: Option<Int64>): Bool {
    match (value) {
        case Some(v) => unsafe {
                set_int64(bindsCP, index, v)
            }
        case None => unsafe {
                set_null(bindsCP, index)
            }
    }
}

func setOldFloat32(bindsCP: CPointer<Unit>, index: Int64, value: Option<Float32>): Bool {
    match (value) {
        case Some(v) => unsafe {
                set_float32(bindsCP, index, v)
            }
        case None => unsafe {
                set_null(bindsCP, index)
            }
    }
}

func setOldFloat64(bindsCP: CPointer<Unit>, index: Int64, value: Option<Float64>): Bool {
    match (value) {
        case Some(v) => unsafe {
                set_float64(bindsCP, index, v)
            }
        case None => unsafe {
                set_null(bindsCP, index)
            }
    }
}

func setOldDate(bindsCP: CPointer<Unit>, index: Int64, value: Option<DateTime>): Bool {
    match (value) {
        case Some(v) => unsafe {
                set_date(bindsCP, index, UInt32(v.year), UInt32(v.month.toInteger()), UInt32(v.dayOfMonth))
            }
        case None => unsafe {
                set_null(bindsCP, index)
            }
    }
}

func setOldTime(bindsCP: CPointer<Unit>, index: Int64, value: Option<DateTime>): Bool {
    match (value) {
        case Some(v) => unsafe {
                set_time(bindsCP, index, UInt32(v.hour), UInt32(v.minute), UInt32(v.second))
            }
        case None => unsafe {
                set_null(bindsCP, index)
            }
    }
}

func setOldTimestamp(bindsCP: CPointer<Unit>, index: Int64, value: Option<DateTime>): Bool {
    match (value) {
        case Some(v) => unsafe {
                set_timestamp(
                    bindsCP,
                    index,
                    UInt32(v.year),
                    UInt32(v.month.toInteger()),
                    UInt32(v.dayOfMonth),
                    UInt32(v.hour),
                    UInt32(v.minute),
                    UInt32(v.second)
                )
            }
        case None => unsafe {
                set_null(bindsCP, index)
            }
    }
}

func setOldDateTime(bindsCP: CPointer<Unit>, index: Int64, value: Option<DateTime>): Bool {
    match (value) {
        case Some(v) => unsafe {
                set_date_time(
                    bindsCP,
                    index,
                    UInt32(v.year),
                    UInt32(v.month.toInteger()),
                    UInt32(v.dayOfMonth),
                    UInt32(v.hour),
                    UInt32(v.minute),
                    UInt32(v.second)
                )
            }
        case None => unsafe {
            set_null(bindsCP, index)
        }
    }
}

func setOldDecimal(bindsCP: CPointer<Unit>, index: Int64, value: Option<Decimal>): Bool {
    match (value) {
        case Some(v) => unsafe {
            let strCtring: CString = LibC.mallocCString(v.toString())
            var ret = set_decimal(bindsCP, index, strCtring)
            LibC.free(strCtring)
            return ret
        }
        case None => unsafe {
                set_null(bindsCP, index)
            }
    }
}

func mysqlOldType(types: Int32, isNull: Bool): String {
    if (types == MYSQL_TYPE_DECIMAL) {
        return "MYSQL_TYPE_DECIMAL"
    }
    if (types == MYSQL_TYPE_TINY) {
        if (!isNull) {
            return "SqlNullableByte"
        } else {
            return "SqlByte"
        }
    }
    if (types == MYSQL_TYPE_SHORT) {
        if (!isNull) {
            return "SqlNullableSmallInt"
        } else {
            return "SqlSmallInt"
        }
    }
    if (types == MYSQL_TYPE_LONG) {
        if (!isNull) {
            return "SqlNullableInteger"
        } else {
            return "SqlInteger"
        }
    }
    if (types == MYSQL_TYPE_FLOAT) {
        if (!isNull) {
            return "SqlNullableReal"
        } else {
            return "SqlReal"
        }
    }
    if (types == MYSQL_TYPE_DOUBLE) {
        if (!isNull) {
            return "SqlNullableDouble"
        } else {
            return "SqlDouble"
        }
    }
    if (types == MYSQL_TYPE_NULL) {
        return "MYSQL_TYPE_NULL"
    }
    if (types == MYSQL_TYPE_TIMESTAMP) {
        if (!isNull) {
            return "SqlNullableTimestamp"
        } else {
            return "SqlTimestamp"
        }
    }
    if (types == MYSQL_TYPE_LONGLONG) {
        if (!isNull) {
            return "SqlNullableBigInt"
        } else {
            return "SqlBigInt"
        }
    }
    if (types == MYSQL_TYPE_INT24) {
        if (!isNull) {
            return "SqlNullableInteger"
        } else {
            return "SqlInteger"
        }
    }
    if (types == MYSQL_TYPE_DATE) {
        if (!isNull) {
            return "SqlNullableDate"
        } else {
            return "SqlDate"
        }
    }
    if (types == MYSQL_TYPE_TIME) {
        if (!isNull) {
            return "SqlNullableTime"
        } else {
            return "SqlTime"
        }
    }

    // 自定义类型
    if (types == MYSQL_TYPE_DATETIME) {
        if (!isNull) {
            return "SqlNullableDateTime"
        } else {
            return "SqlDateTime"
        }
    }
    if (types == MYSQL_TYPE_YEAR) {
        return "MYSQL_TYPE_YEAR"
    }
    if (types == MYSQL_TYPE_NEWDATE) {
        return "MYSQL_TYPE_NEWDATE"
    }
    if (types == MYSQL_TYPE_VARCHAR) {
        return "MYSQL_TYPE_VARCHAR"
    }
    if (types == MYSQL_TYPE_BIT) {
        return "MYSQL_TYPE_BIT"
    }
    if (types == MYSQL_TYPE_TIMESTAMP2) {
        return "MYSQL_TYPE_TIMESTAMP2"
    }
    if (types == MYSQL_TYPE_DATETIME2) {
        return "MYSQL_TYPE_DATETIME2"
    }
    if (types == MYSQL_TYPE_TIME2) {
        return "MYSQL_TYPE_TIME2"
    }
    if (types == MYSQL_TYPE_TYPED_ARRAY) {
        return "MYSQL_TYPE_TYPED_ARRAY"
    }
    if (types == MYSQL_TYPE_INVALID) {
        return "MYSQL_TYPE_INVALID"
    }
    if (types == MYSQL_TYPE_BOOL) {
        return "MYSQL_TYPE_BOOL"
    }
    if (types == MYSQL_TYPE_JSON) {
        return "MYSQL_TYPE_JSON"
    }
    if (types == MYSQL_TYPE_NEWDECIMAL) {
        if (!isNull) {
            return "SqlNullableDecimal"
        } else {
            return "SqlDecimal"
        }
    }
    if (types == MYSQL_TYPE_ENUM) {
        return "MYSQL_TYPE_ENUM"
    }
    if (types == MYSQL_TYPE_SET) {
        return "MYSQL_TYPE_SET"
    }
    if (types == MYSQL_TYPE_TINY_BLOB) {
        if (!isNull) {
            return "SqlNullableBlob"
        } else {
            return "SqlBlob"
        }
    }
    if (types == MYSQL_TYPE_MEDIUM_BLOB) {
        if (!isNull) {
            return "SqlNullableBlob"
        } else {
            return "SqlBlob"
        }
    }
    if (types == MYSQL_TYPE_LONG_BLOB) {
        if (!isNull) {
            return "SqlNullableClob"
        } else {
            return "SqlClob"
        }
    }
    if (types == MYSQL_TYPE_BLOB) {
        if (!isNull) {
            return "SqlNullableBlob"
        } else {
            return "SqlBlob"
        }
    }
    if (types == MYSQL_TYPE_VAR_STRING) {
        if (!isNull) {
            return "SqlNullableVarchar"
        } else {
            return "SqlVarchar"
        }
    }
    if (types == MYSQL_TYPE_STRING) {
        if (!isNull) {
            return "SqlNullableChar"
        } else {
            return "SqlChar"
        }
    }
    if (types == MYSQL_TYPE_GEOMETRY) {
        return "MYSQL_TYPE_GEOMETRY"
    }
    return "unknownType"
}