直接按名称绑定SQLite参数

问题描述:

最近 - 最近 - 我开始学习如何为iOS编程,并且被SQLite3中出现(在我看来)公然监督的东西所困扰。让我通过说,在上周之前,我对Mac,Objective C,Xcode,iOS或SQLite有零(实践)经验,所以我没有妄想进入尝试和真正的工具领域并发现明显的错误在我第一次尝试。我假设有一个很好的解释。直接按名称绑定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呢。我唯一的猜测是,在[在此处插入iDevice]时,查找参数索引所需的额外内存和周期太宝贵,并且不值得使用参数名称的方便性。 。 。 ?

任何有识之士将不胜感激。

+0

SQLite确实提供这个功能:http://www.sqlite.org/lang_expr.html – Tim

+0

有用的资源 - 但不知道它与我的问题有何关系? – brichins

+0

对我来说,它不会在命名参数上精神负担,正如Tim所说,它受SQLite支持。像.NET这样的语言使命名参数更容易访问。 – Echilon

  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(),他们能够一dd完全支持命名参数,只有单个函数。这意味着如果他们决定支持新的绑定类型(可能是sqlite3_bind_int128?),他们只需添加一个函数,而不是两个。

  2. 至于为什么没有人似乎使用它...我不能给任何明确的答案进行调查。我的猜想会是顺序参考参数有点更自然,在这种情况下命名参数是没有用的。如果您需要参考不按顺序参数,命名参数似乎很有用。

+0

从维护的角度来看是有意义的......但是你可以使用以'name'作为参数的方法,并删除那些取'int'的方法(除了向后兼容性,但你必须在某个点跳转) 。我仍然感到惊讶的是,SQLite标准是在每一个其他SQL数据库系统(至少我知道的)都使用命名参数时按顺序列出它们 - 对我而言,这恰恰是因为你可以与它们一起工作而无需担心顺序。感谢您的链接,我将不得不看看SQLite包装下一步:) – brichins

+1

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