直接通过Name绑定SQLite参数

bri*_*ins 10 sqlite parameters xcode objective-c ios

我最近 - 最近 - 开始学习如何为iOS编程,并且被(在我看来)在SQLite3中公然疏忽所困扰.让我通过说在上周之前我对Mac,Objective C,Xcode,iOS或SQLite没有(实际)经验来证明这一点,所以我对于在经过验证的工具领域跳华尔兹并发现明显错误没有任何妄想在我第一次尝试.我认为有一个很好的解释.

然而,在使用SQL Server,MySQL和PostgreSQL过去几个月之后,我惊讶地发现SQLite没有更好的功能来按名称添加参数.我在网上找到的所有东西(文档,论坛[包括SO])都说使用整数索引来分配参数,如果你修改了你的查询,这似乎很难维护.即使您可以在语句中命名参数并执行类似的操作

sqlite3_bind_int(stmt, sqlite3_bind_parameter_index(stmt, "@my_param"), myInt);
Run Code Online (Sandbox Code Playgroud)

似乎没有人这样做.事实上,似乎没有人试图将其自动化; 我能找到的唯一替代方法是使用参数数组和循环计数器,并检查每个参数以确定要插入的对象类型.我最初考虑过类似的方法,但是a)我的老板的立场是数据库参数应该始终进行类型检查(我同意,虽然我知道SQLite字段不是强类型的,我在技术上也可以做到这一点),b)它感觉就像一个不优雅的黑客,并且c)我认为这种方法没有被广泛使用的原因.所以:

1)为什么SQLite中没有接受参数名称的绑定方法(例如,'const char')?或者在那里,我错过了什么?

2)为什么没有人似乎使用上述示例的方法?

我稍微挖了一下源代码,并认为我可以轻松地修改库或者只编写我自己的(类型)类方法,这些方法可以为我做上述操作,但我假设有一个原因没有人将它构建到SQLite中.我唯一的猜测是,在[insert iDevice here]中找到参数索引所需的额外内存和周期太宝贵了,并且不值得使用参数名称...?

任何见解将不胜感激.

Dav*_*ong 5

  1. 有; 这是sqlite3_bind_parameter_index()您提到的用于将参数名称转换为索引的sqlite3_bind_*()函数,然后您可以将其与函数一起使用。但是,没有任何sqlite3_bind_*_by_name()功能或类似的东西。这是为了帮助防止 API 膨胀。流行的Flying Meat Database sqlite 包装器在其分支之一中支持命名参数,如果您有兴趣了解它是如何使用的。

    如果您考虑实现全命名参数绑定方法需要什么,请考虑当前的bind函数列表:

    int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
    int sqlite3_bind_double(sqlite3_stmt*, int, double);
    int sqlite3_bind_int(sqlite3_stmt*, int, int);
    int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
    int sqlite3_bind_null(sqlite3_stmt*, int);
    int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));
    int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
    int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
    int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
    
    Run Code Online (Sandbox Code Playgroud)

    如果我们想添加对命名参数的显式支持,该列表的长度将加倍以包括:

    int sqlite3_bind_name_blob(sqlite3_stmt*, const char*, const void*, int n, void(*)(void*));
    int sqlite3_bind_name_double(sqlite3_stmt*, const char*, double);
    int sqlite3_bind_name_int(sqlite3_stmt*, const char*, int);
    int sqlite3_bind_name_int64(sqlite3_stmt*, const char*, sqlite3_int64);
    int sqlite3_bind_name_null(sqlite3_stmt*, const char*);
    int sqlite3_bind_name_text(sqlite3_stmt*, const char*, const char*, int n, void(*)(void*));
    int sqlite3_bind_name_text16(sqlite3_stmt*, const char*, const void*, int, void(*)(void*));
    int sqlite3_bind_name_value(sqlite3_stmt*, const char*, const sqlite3_value*);
    int sqlite3_bind_name_zeroblob(sqlite3_stmt*, const char*, int n);
    
    Run Code Online (Sandbox Code Playgroud)

    两倍多的功能,是指用于维护API更多的时间,以确保向后兼容性,等等等等。但是,通过简单的介绍sqlite3_bind_parameter_index(),他们能够增加对命名参数完整的支持,只有一个单一的功能。这意味着如果他们决定支持新的绑定类型(也许sqlite3_bind_int128?),他们只需要添加一个函数,而不是两个。

  2. 至于为什么似乎没有人使用它......我无法通过进行调查给出任何明确的答案。我的猜测是,按顺序引用参数会更自然一些,在这种情况下,命名参数就没那么有用了。命名参数似乎只有在您需要无序引用参数时才有用。

  • @brichins,您可以准备一个语句并将参数索引读入变量一次,然后重用该准备好的语句并将不同的参数绑定到它多次。这避免了每个参数的字典查找。删除基于索引的 API 会*迫使*人们降低效率,所以如果发生这种情况我会感到惊讶;-)。 (3认同)