SQlite数据库的C编程接⼝(三)预处理语句
(PreparedStatements)
SQlite3数据库连接完成之后,就可以执⾏SQL命令了。下⾯将要介绍的prepare和step函数都是⽤来操作和执⾏SQL命令的。
典型的函数操作流程(伪代码):
这段程序⾸先调⽤sqlite3_prepare_v2函数,将⼀个SQL命令字符串转换成⼀条prepared语句,存储在sqlite3_stmt类型结构体中。随后调⽤sqlite3_bind_xxx函数给这条prepared语句绑定参数。然后不停的调⽤sqlite3_step函数执⾏这条prepared语句,获取结果集中的每⼀⾏数据,从每⼀⾏数据中调⽤qlite3_column_xxx函数获取有⽤的列数据,直到结果集中所有的⾏都被处理完毕。
prepared语句可以被重置(调⽤sqlite3_ret函数),然后可以重新绑定参数之后重新执⾏。sqlite3_prepare_v2函数代价昂贵,所以通常尽可能的重⽤prepared语句。最后,这条prepared语句确实不在使⽤时,调⽤sqlite3_finalize函数释放所有的内部资源和sqlite3_stmt数据结构,有效删除prepared语句。
预处理(Prepare)
这些函数的作⽤是将SQL命令字符串转换为prepared语句。参数db是由sqlite3_open函数返回的指向
补办银行卡需要什么
数据库连接的指针。参数zSql是UTF-8或者UTF-16编码的SQL命令字符串,参数nByte是zSql的字节长度。如果nByte为负值,则prepare函数会⾃动计算出zSql的字节长度,不过要确保zSql传⼊的是以NULL结尾的字符串。如果SQL命令字符串中只包含⼀条SQL语句,那么它没有必要以“;”结尾。参数ppStmt是⼀个指向指针的指针,⽤来传回⼀个指向新建的sqlite3_stmt结构体的指针,sqlite3_stmt结构体⾥⾯保存有转换好的SQL语句。如果SQL命令字符串包含多条SQL语句,同时参数pzTail不为NULL,那么它将指向SQL命令字符串中的下⼀条SQL语句。上⾯4个函数中的v2版本是加强版,与原始版函数参数相同,不同的是函数内部对于sqlite3_stmt结构体的表现上。细节不去理会,尽量使⽤v2版本。
在sqlite3_prepare函数转换⼀条语句完毕之后,可以给这条语句绑定参数。语句参数允许我们插⼊⼀个特殊的占位符,然后给这个参数占位符绑定指定的值,然后再执⾏它。执⾏完成之后,还可以重置语句,绑定新的参数值,再重新执⾏该语句。像INSERT操作,每次执
⾏INSERT命令,绑定不同的值,插⼊不同的数据。参数绑定是⼀个有点复杂的深⼊话题,在下⼀节中学习。
步进(Step)
sqlite3_prepare函数将SQL命令字符串解析并转换为⼀系列的命令字节码,这些字节码最终被传送到SQlite3的虚拟数据库引擎(VDBE: Virtual Databa Engine)中执⾏,完成这项⼯作的是sqlite3_step函数。⽐如⼀个SELECT查询操作,sqlite3_step函数的每次调⽤都会返回结果集中的其中⼀⾏,直到再没有有效数据⾏了。每次调⽤sqlite3_step函数如果返回SQLITE_ROW,代表获得了有效数据⾏,可以通
授权书图片过sqlite3_column函数提取某列的值。如果调⽤sqlite3_step函数返回SQLITE_DONE,则代表prepared语句已经执⾏到终点了,没有有效数据了。很多命令第⼀次调⽤sqlite3_step函数就会返回SQLITE_DONE,因为这些SQL命令不会返回数据。对
于INSERT,UPDATE,DELETE命令,会返回它们所修改的⾏号——⼀个单⾏单列的值。
结果列(Result Columns)
返回结果集的列数。
返回结果集中指定列的列名,列的序号以0开始。⽐如⼀条SQL语句:SELECT pid AS ,那么调⽤sqlite3_column_name函数返回结果集中第0列的列名就是person_id。返回的字符串指针将⼀直有效,直到再次调⽤sqlite3_column_name函数并再次读取该列的列名时失效。
该函数返回结果集中指定列的本地存储类型,
如SQLITE_INTEGER,SQLITE_FLOAT,SQLITE_TEXT,SQLITE_BLOB,SQLITE_NULL。为了获取正确的类型,该函数应该在任何试图提取数据的函数调⽤之前被调⽤。SQlite3数据库允许不同类型的数据存储在同⼀列中,所以对于不同⾏的相同索引的列调⽤该函数获取的列类型可能会不同。
返回⼀个指针,指向给定列的BLOB类型值。的感受
从给定列返回⼀个64位浮点值。
从给定列返回⼀个32位有符号整数,如果该列中包含的整型值⽆法⽤32位数值表⽰,那它将会在没有任何警告的情况下被截断。
从给定列返回⼀个64位有符号整数。
返回⼀个指针,指向给定列的UTF-8或者UTF-16编码的字符串,该字符串以NULL结尾。
返回⼀个指针,指向⼀个⽆保护的sqlite3_value结构,该结构⽆法进⾏安全的数据类型转换,所以⽆法调⽤sqlite3_value_xxx函数从这个结构体中提取原始数值。如果想提取原始数值,只能调⽤其它的sqlite3_column_xxx函数。对于该函数返回的指针,安全的⽤法是以它为参数调⽤sqlite3_bind_value函数给⼀个prepared语句绑定参数,或者以它为参数调⽤sqlite3_result_value函数得到⼀个⽤户⾃定导师意见
义的SQL函数的返回值。
对于这些sqlite3_column_xxx函数返回的指针,当再次调⽤sqlite3_column_xxx函数并操作相同的列的时失效,或者在sqlite3_step、sqlite3_ret、sqlite3_finalize等函数调⽤之后失效。
如果提取列值时使⽤的sqlite3_column_xxx函数版本与原始值的本地数据类型不同,SQlite数据库将进⾏转换。转换原则:
对于BLOB和text类型,sqlite3_column_blob和sqlite3_column_text函数将会返回⼀个buffer指针。通过sqlite3_value_bytes函数可以得
到buffer字节长度,对于text类型,这个字节长度将包括⼀个字符串结尾符。
沐浴文化
需要注意的是:假如先调⽤sqlite3_column_text函数获取⼀个指向UTF-8编码的字符串指针,之后⼜调⽤了sqlite3_column_bytes16在相同的列上获取buffer⼤⼩,那么该列的字符串将会从UTF-8编码转换为UTF-16编码,导致之前由sqlite3_column_text函数返回的指针失效。
正确做法是提取值时的函数和获取值buffer⼤⼩的函数,以相同类型匹配使⽤,如:
重置与完成(Ret and Finalize)
当sqlite3_step函数调⽤返回SQLITE_DONE时,则代表这条语句已经完成执⾏,这时如果还想重⽤这条prepared语句,就需要调
⽤sqlite3_ret函数进⾏重置。或者,⽐如我们只想提取结果集的前六⾏数据,那么我们就可以连续调⽤6次sqlite3_step函数,之后调
⽤sqlite3_ret函数重置prepared语句,以备下⼀次使⽤。筷子的英语
销毁prepared语句,释放资源。在关闭数据库连接之前,对于不再使⽤的prepared语句,⼀定要调⽤sqlite3_finalize函数进⾏销毁,
语句(状态)转换(Statement Transitions)
⼀条语句可以处于不同状态,对于⼀条新的或者刚刚被ret的语句,它们处于“ready”状态,代表它们已经准备好执⾏,但还没有开始执⾏。⼀条语句也有可能处于“running”状态,表明这条语句已经开始执⾏,但还没有完成。还有⼀种状态叫做“done”,表明⼀条语句已经执⾏完成。
对于有些API函数,只能在某条语句处于特定状态下才可以执⾏,⽐如sqlite3_bind_xxx函数,只有在⼀条语句处于“ready”状态时才可以被调⽤,否则函数将会返回SQLITE_MISUSE错误码。下图展⽰了⼀条语句所处于的不同状态,以及不同状态之间是如何转换的。
⽰例代码
(1)
剪纸教程简单CREATE TABLE语句没有返回值,调⽤sqlite3_step函数执⾏这条语句,最后在关闭数据库之前调⽤sqlite3_finalize销毁这条语句。(2)
这段代码循环提取表tbl的所有⾏,并把每⼀⾏第0列值打印出来。
意识的作用