6.2.2 C API 预处理语句类型转换

预处理语句使用客户端上的 C 语言变量来传输客户端和服务器之间的数据,这些变量对应于服务器端的 SQL 值。如果客户端上的 C 变量类型与服务器端相应的 SQL 值类型不匹配,MySQL 会在两个方向上执行隐式类型转换。

MySQL 知道服务器端 SQL 值的类型代码。buffer_type 值在 MYSQL_BIND 结构中表示客户端上保存值的 C 变量的类型代码。这两个代码一起告诉 MySQL 必须执行什么转换,如果有的话。以下是一些示例

  • 如果您使用 MYSQL_TYPE_LONG 和一个 int 变量将一个整数传递给服务器,该整数将被存储到一个 FLOAT 列中,MySQL 会在存储该值之前将该值转换为浮点格式。

  • 如果您获取一个 SQL MEDIUMINT 列值,但指定一个 buffer_type 值为 MYSQL_TYPE_LONGLONG 并使用类型为 long long int 的 C 变量作为目标缓冲区,MySQL 会将 MEDIUMINT 值(需要小于 8 个字节)转换为 long long int(一个 8 字节变量)进行存储。

  • 如果您将数值列的值 255 提取到一个 char[4] 字符数组中,并指定一个 buffer_type 值为 MYSQL_TYPE_STRING,则数组中的结果值为一个 4 字节字符串 '255\0'

  • MySQL 返回 DECIMAL 值作为原始服务器端值的字符串表示形式,这就是为什么相应的 C 类型为 char[]。例如,12.345 会以 '12.345' 的形式返回给客户端。如果您指定 MYSQL_TYPE_NEWDECIMAL 并将字符串缓冲区绑定到 MYSQL_BIND 结构,mysql_stmt_fetch() 会将值存储在缓冲区中,作为字符串,不进行转换。如果您改为指定一个数值变量和类型代码,mysql_stmt_fetch() 会将字符串格式的 DECIMAL 值转换为数值形式。

  • 对于 MYSQL_TYPE_BIT 类型代码,BIT 值会返回到一个字符串缓冲区中,这就是为什么相应的 C 类型为 char[]。该值表示一个位字符串,需要在客户端进行解释。要将值返回为更容易处理的类型,您可以使用以下两种类型的表达式之一将值强制转换为整数

    SELECT bit_col + 0 FROM t
    SELECT CAST(bit_col AS UNSIGNED) FROM t

    要检索值,请绑定一个足够大的整数变量来保存值,并指定相应的整数类型代码。

在将变量绑定到将用于提取列值的 MYSQL_BIND 结构之前,您可以检查结果集中每列的类型代码。如果您想确定使用哪些变量类型最适合避免类型转换,这可能很有用。要获取类型代码,请在使用 mysql_stmt_execute() 执行语句后调用 mysql_stmt_result_metadata()。元数据提供对结果集类型代码的访问,如 第 6.4.24 节,“mysql_stmt_result_metadata()”第 5.2 节,“C API 基本数据结构” 中所述。

要确定从服务器返回的结果集中的输出字符串值是否包含二进制或非二进制数据,请检查结果集元数据的 charsetnr 值是否为 63(参见 第 5.2 节,“C API 基本数据结构”)。如果是,则字符集为 binary,表示二进制数据而不是非二进制数据。这使您能够区分 BINARYCHARVARBINARYVARCHAR,以及 BLOB 类型与 TEXT 类型。

如果您导致 MYSQL_FIELD 列元数据结构的 max_length 成员被设置(通过调用 mysql_stmt_attr_set()),请注意结果集的 max_length 值表示结果值的字符串表示形式的最长长度,而不是二进制表示形式的长度。也就是说,max_length 不一定对应于使用预处理语句的二进制协议提取值所需的缓冲区的大小。请根据要提取值的变量的类型选择缓冲区的大小。例如,包含值 -128 的 TINYINT 列可能有一个 max_length 值为 4。但是任何 TINYINT 值的二进制表示形式只需要 1 个字节进行存储,因此您可以提供一个 signed char 变量来存储该值,并设置 is_unsigned 来表示值是有符号的。

预处理语句引用的表或视图的元数据更改会被检测到,并在下次执行语句时导致自动重新准备语句。有关更多信息,请参见 预处理语句和存储过程的缓存