提问人:Gary 提问时间:11/11/2023 最后编辑:Gary 更新时间:11/11/2023 访问量:73
确保 Tcl 的 SQLite 中的变量替换始终是所需的类型?
Ensuring that variable substituion in SQLite from Tcl will always be of the desired type?
问:
在SQLite中确保Tcl变量被视为正确类型的正确方法是什么?
此活动会话似乎是设置为 的最简单的方案,但它似乎 SQLite 将其视为字符串和数字。number
50
:number
:number+0
$number
如果改为使用 SQLite,则SQLite将被视为一个数字。incr nbr 50
:nbr
有没有办法在 Tcl 中“声明”变量,以便 SQLite 根据需要处理它;还是应该在 SQL 表达式中强制转换每个值?
我想知道如何确保查询始终按预期工作,而不是仅仅使用“失败”的变量,以便在测试时被识别为所需的变量;我还没有认识到一些模式或最佳实践。cast
如果所有变量替换都不被视为字符串并转换为 SQL 中的数字(除非测试显示问题),那么未来的 SQLite 版本是否会导致它“正常工作”的实例更改为需要强制转换?
谢谢。
% package require sqlite3
3.43.2
% sqlite3 db
% set number 50
50
% db eval {select min(300, :number)}
300
% db eval {select min(300,:number+0)}
50
% db eval "select min(300,$number)"
50
% db eval {select min(300, cast(:number as integer))}
50
% incr nbr 50
50
% db eval {select min(300,:nbr)}
50
% db eval "select min(300,$nbr)"
50
% db eval {create table numbers (id integer, value integer);
insert into numbers values (1,300);}
% db eval {select min(value,:number) from numbers;}
300
答:
我记得,如果你运行这个值,那么它会得到SQLite的数字解释,但你需要小心一点,阻止Tcl在测试时只是将值作为文字分解出来:expr
set number 50
set number [expr {$number}]
db eval {select min(300, :number)}
在执行更多面向生产的代码时,这往往不是一个大问题,因为您在 SQL 代码中放置常量并且只参数化更改的值(无论如何,这些值很可能具有数字性质)。
如果你真的担心它,在你的 SQL 中放一个。CAST
在字节码级别,通过调用的操作发送值,如果值可以有,则为值提供数字解释。文本默认为没有解释。从形式上讲,我们更喜欢 C 代码不依赖于现有的值解释,而只是要求他们想要的值,但 tclsqlite 扩展(称为它以将其与底层库区分开来)没有这样做,也从未这样做过。expr
tryCvtToNumeric
在处理数据时,这一点更为重要。那是你使用而不是......BLOB
@var
:var
评论
CAST
INSERT
UPDATE
CAST
CAST
据我所知,sqlite 窥探了它收到的 Tcl 值的 objtype,并据此改变它的行为,我认为这是对系统的滥用,或者至少是对它的误解。该“类型”实际上只是一个缓存值,反映了它上次被处理的内容,并且实际上对该值是什么没有任何意义(就像在数据库类型意义上一样)。也就是说,sqlite 本身更多地将数据库类型视为准则而不是规则,并且会很乐意存储列声明以外的内容,因此如果您眯着眼睛看得恰到好处,它应该大部分工作正常。
您的示例演示了为什么窥探上次使用的 objtype 不是一个有效的策略:
set number 50
puts "at this stage, number's objtype is: [tcl::unsupported::representation $number]"
# Programmer likely thinks of $number as containing a number,
# but it's actually a string
set number [expr {$number}]
puts "after coercion by expr: [tcl::unsupported::representation $number]"
# Now it's been used as a number, and has an integer objtype
puts "digits in number: [string length $number]"
# Programmer still thinks it's a number, but now it's a string again:
puts "after string length: [tcl::unsupported::representation $number]"
# And, just for fun, let's view it as a list:
puts "llength: [llength $number]"
# now it's a list:
puts "after llength: [tcl::unsupported::representation $number]"
输出:
at this stage, number's objtype is: value is a pure string with a refcount of 2, object pointer at 0xffffffffdba1d820, string representation "50"
after coercion by expr: value is a int with a refcount of 2, object pointer at 0xffffffffdba1e270, internal representation 0x32:0x0, no string representation
digits in number: 2
after string length: value is a utf32string with a refcount of 2, object pointer at 0xffffffffdba1e270, internal representation 0xffffffffdba505b0:0x0, string representation "50"
llength: 1
after llength: value is a list with a refcount of 2, object pointer at 0xffffffffdba1e270, internal representation 0xffffffffdba48c10:0x0, string representation "50"
这些年来,我与一些人进行过很多讨论,他们无法接受 Tcl 值真的、真的没有字符串以外的形式类型,并坚持假装他们有,每个案例都有这个问题。
更进一步,允许 Tcl 值具有多个缓存的 objtype 的工作进展缓慢(提示 445 隐藏了实现与值关联的 objtype 的内部细节,以便可以对其进行更改以支持此想法)。几年前,我做了一个实验,使用TIP(通常称为“Hydra”——一个多头Tcl值系统)实现了这个想法,所以我有具体的证据证明它工作和执行正确。这主要是为了解决一个性能问题,即一个值被快速连续地反复使用,并有两种或多种解释,称为“闪烁”(尽管我开始看到人们使用该术语来指代 obtype 的变化,甚至一次。为此,我使用“converted”)。在 Hydra 值模型下,上述代码将累积它所引用的所有 objtypes,从而使后续访问成为这些 objtypes 中的任何一个都很快。应该清楚的是,通过窥探 objtype 来假装 Tcl 值具有类型的方法在 Hydra 世界中完全崩溃了。
评论
min()
:
评论