直接通过Name绑定SQLite参数

时间:2011-09-22 00:04:16

标签: objective-c ios xcode sqlite parameters

我最近 - 最近 - 开始学习如何为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);

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

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

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

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

任何见解都将受到赞赏。

1 个答案:

答案 0 :(得分:4)

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

    如果您考虑实现完整命名参数绑定方法需要什么,请考虑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);
    

    如果我们想要为命名参数添加明确的支持,那么该列表的长度将加倍,包括:

    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);
    

    两倍的功能意味着花费更多的时间来维护API,确保向后兼容性等等。但是,通过简单地引入sqlite3_bind_parameter_index(),他们能够添加对命名参数的完全支持,只需< em>单个功能。这意味着如果他们决定支持新的绑定类型(可能是sqlite3_bind_int128?),他们只需添加一个函数,而不是两个。

  2. 至于为什么似乎没有人使用它......我无法通过调查给出任何明确的答案。我的 guess 将是顺序引用参数更自然,在这种情况下,命名参数不是那么有用。如果您需要不按顺序引用参数,则命名参数似乎才有用。