SQLite3扩展C API

扩展C API

扩展API提供几种扩展或定制SQLite的基本方法,包括:创建用户自定义函数、聚合、排序规则和虚拟表,还可以在更底层实现一些方法,像虚拟文件系统,启动时可换的页缓存、内存分配和互斥的实现。

用户自定义函数是用户编写的用于特定应用的SQL函数,可以在SQL语句中调用他们。

聚合是一种特殊形式的函数,他与普通函数的工作方式基本相同,只是他对一组记录j进行操作并返回这一组记录中某个特定的字段的聚合值或表达式计算值,聚合函数可以从多个字段进行计算,而普通函数对单个记录进行操作。SQL中标准的聚合COUNT()、SUM()、AVG()。
排序规则是对文本进行比较和排序的方法。SQLite中默认的排序规则是BINARY,它通过memcmp()逐字节进行比较。仅适用于UTF-8编码。因此SQLite构建自定义排序规则以处理这些语言。

一、API

实现函数、聚合以及排序规则的基本方法都是使用回调函数,并在程序中注册,注册之后就可以在SQL中使用。函数和聚合使用相同的注册函数和类似的回调函数。虽然排序规则使用单独的注册函数,但是与函数和聚合的注册函数基本相同。

用户自定义聚合、函数和排序规则的生命周期是短暂的。他们是基于连续注册的,而且不存储在数据库中而是在程序中,需要确定用户已加载了定制并在连接中注册。扩展必须在每一个使用他们的连接上做。

1.注册函数
使用sqlite3_create_function()在连接中注册函数和聚合

函数:int sqlite3_create_function(sqlite3 *cnx, const char *zfunctionname, int narg, int etextrep, void *puserdata, void (*xfunc)(sqlite3_context*,int,sqlite3_value**), void (*xstep)(sqlite3_context*,int,sqlite3_value**), void (*xfinal)(sqlite3_context*));
参数:cnx:数据库连接句柄
      zfunctionname:将在SQL中调用的函数名称
      narg:自定义函数参数个数,如果是-1,SQLite允许参数个数可变
      etextrep:首先文本编码,SQLITE_UTF8、SQLITE_UTF16BE, SQLITE_UTF16LE、SQLITE_ANY(万能的)。
      puserdata:应用程序数据。该数据可供xfunc、xstep、xfinal指定的回调函数中使用
      xfunc:回调函数,SQL函数的真实实现,用户定义函数只需要提供该函数的回调函数,让xstep、xfinal函数指针为NULL,后两个是给聚合实现使用的。
      xstep:聚合步骤函数,SQLite每次处理聚合结果集中的一行都要使用xstep,以便聚合处理该行的相关字段值,并将其包含在聚合计算的结果中。
      xfinal:finalize聚合函数,处理完之后,SQLite调用该函数进行整个聚合汇总处理,该函数通常由计算最终值和可选的情况b部分组成。

2.步骤函数

函数:void fn(sqlite3_context* ctx, int narg, sqlite3_value** values);
参数:ctx:函数/聚合上下文环境。它保持特殊函数的实例状态,可以通过sqlite3_create_function()中的参数puserdata获取到。
narg:传递给函数的参数个数
values:sqlite3_value结构体数组,SQLite实际参数值的句柄。

二、函数

假设已实现函数hello_world();下面是示例

    void hello_world(sqlite3_context* ctx, int nargs, sqlite3_value** values)
    {
        const char *msg;
        msg = sqlite3_mprintf("hello %s", sqlite3_value_text(values[0]));
        sqlite3_result_text(ctx, msg, strlen(msg), sqlite3_free);
    }
    int main()
    {
        int rc,;
        sqlite3 *db;
        sqlite3_open_v2("test.db", &db);
        sqlite3_create_function(db, "hello_world", 1, SQLITE_UTF8, NULL, hello_world, NULL, NULL);

        print_sql_result(db, "select hello_world('CHINA')");
        sqlite3_close(db);
        return 0;
    }

其中print_sql_result函数只是简单封装sqlite3_prepare_v2的简单封装并将结果打印出来。sqlite3_result_text()是sqlite3_result_xxx()系列函数,用来为用户自定义函数和聚合返回值的。

错误处理函数

函数:void sqlite3_result_error(sqlite3_context* ctx, const char *msg, int len);
参数:ctx:函数上下文
      msg:错误消息保存buf
      len:错误消息长度

返回输入值

函数:sqlite3_result_value(sqlite3_context* ctx, sqlite3_value* value);
功能:将某个参数以相同的形式作为返回值传递回去
参数:ctx:函数上下文
      value:参数值

三、聚合
聚合比用户自定义函数稍微复杂一点,因为聚合有两个回调函数,一个是步骤函数计算进行中的值,另一个是finalize函数完成最终计算和清理工作。下图是一般处理过程:

SQLite3扩展C API

聚合和函数使用同一个注册函数sqlite3_create_function();聚合不需要为xfunc提供回调函数,设为NULL即可。

实例:
假定str_agg_step 和 str_agg_finalize 分别是xstep 和 xfinal 回调函数以实现。

int main()
{
    int rc;
    sqlite3 *db;
    char *sql = NULL;
    sqlite3_open_v2("test.db", &db);
    sqlite3_create_function(db, "str_agg", 1, SQLITE_UTF8, db, NULL, str_agg_step, str_agg_finalize);
    sql = "select season, str_agg(name, ', ') from episodes group by season";
    print_sql_result(db, sql);
    sqlite3_close(db);
    return 0;
}

四、排序规则

排序规则是对事物进行分类比较,那么当遇到不同类型的值的时候如何排序呢?SQLite对结果集中的字段排序时,第一件事就是根据存储类对字段值进行排序,然后在每种类型中进行排序,存储类型进行排序的顺序从前让后如下所示:

  1. NULL值
  2. INTEGER和REAL值
  3. TEXT值
  4. BLOB值

排序法定义:与逐个比特比较数字代码相反,排序规则使用语言敏感的规则对文本进行比较。

排序规则如何工作:通常来讲,排序方法对将要比较的两个字符串进行切分,通过排序序列逐以比较每个字符。从左到右比较字符。如果一个字符的数字值大于另一个,比较结束,有较大数字值的字符串是较大者。如果相同则继续比较下一个字符。直到发现不同,如果比完所以字符还未分出大小,那么由排序规则决定这种情况如何处理。

标准排序规则类型:SQLite中唯一内置的排序规则binary使用标准的C函数库memcmp()比较两个字符串,binary排序规则对英文文本使用很好,但是对于其他语言可以使用nocase,它对大小写不敏感。排序规则是通过表字段或索引定义以及在查询中指定的方法和字段关联起来。
例如:在foo中创建大小写不敏感的bar字段

create table foo (bar text collate nocase, baz nocase);

这时只要SQLite处理bar字段时,就会使用nocase排序规则,如果不想将排序规则附加到数据库对象上,而是需要时在查询中指定,可以直接在查询中指定如:

select cast(baz) collate nocase as baz_as_text from foo order by baz_as_text;

排序注册函数

函数:sqlite3_create_collation_v2(sqlite3 *db, const char *zname, int pref16, void* puserdata, int(*xcompare)(void*,int,const void*,int,const void*)void(*xdestory)(void*));
参数:db:数据库句柄
      zname:SQL语句中使用的排序规则名称
      pref16:编码格式
      puserdata:应用程序数据
      compare:int compare(void *data, int len1, const void* str1, int len2, const void* str2);
               参数:data:应用程序数据
                     len1:字符串1长度
                     str1:字符串1
                     len2:字符串2长度
                     str2:字符串2
 &#x8FD4;&#x56DE;&#x503C;&#xFF1A;&#x5B57;&#x7B26;&#x4E32;1 < &#x5B57;&#x7B26;&#x4E32;2 &#x8FD4;&#x56DE;&#x503C;&#x5C0F;&#x4E8E;0
         &#x5B57;&#x7B26;&#x4E32;1 = &#x5B57;&#x7B26;&#x4E32;2 &#x8FD4;&#x56DE;&#x503C;0
         &#x5B57;&#x7B26;&#x4E32;1 > &#x5B57;&#x7B26;&#x4E32;2 &#x8FD4;&#x56DE;&#x503C;&#x5927;&#x4E8E;0

按需排序
SQLite提供一种直到实际需要时才注册排序的延迟方式,因此,如果您不确定程序的排序规则,可以使用函数sqlite3_collation_needed(),将注册延迟到最后可能需要的时刻,只需要提供回调函数,SQLite会在需要时注册未知排序规则。

&#x51FD;&#x6570;&#xFF1A;int sqlite3_collation_needed(sqlite3 *db, void *data, void(*crf)(void*,sqlite3*,int etextrep,const char*));
&#x53C2;&#x6570;&#xFF1A;db&#xFF1A;&#x6570;&#x636E;&#x5E93;&#x53E5;&#x67C4;
      data&#xFF1A;&#x5E94;&#x7528;&#x7A0B;&#x5E8F;&#x6570;&#x636E;
      crf&#xFF1A;void crf(void *data, sqlite3 *db, int etextrep, const char*);
        &#x53C2;&#x6570;&#xFF1A;data&#xFF1A;&#x5E94;&#x7528;&#x7A0B;&#x5E8F;&#x6570;&#x636E;
              db&#xFF1A;&#x6570;&#x636E;&#x5E93;&#x53E5;&#x67C4;
              etextrep&#xFF1A;&#x7F16;&#x7801;&#x683C;&#x5F0F;
              const char*&#xFF1A;&#x6392;&#x5E8F;&#x89C4;&#x5219;&#x540D;&#x79F0;

Original: https://blog.csdn.net/qq_34934140/article/details/122165340
Author: 青湦
Title: SQLite3扩展C API

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/816732/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球