确保 SQLite 中从 Tcl 进行的变量替换始终是所需的类型?

问题描述 投票:0回答:2

确保 Tcl 变量在 SQLite 中被视为正确类型的正确方法是什么?

此活动会话似乎是将

number
设置为
50
的最简单场景,但 SQLite 似乎将
:number
视为字符串,
:number+0
$number
视为数字。

如果改为使用

incr nbr 50
,则 SQLite 将
: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
2个回答
0
投票

我记得,如果您通过

expr
运行该值,那么它会通过 SQLite 获得数字解释,但是您需要小心

,以阻止 Tcl 在测试时将值分解为文字:
set number 50
set number [expr {$number}]
db eval {select min(300, :number)}

在执行更多面向生产的代码时,这往往不是一个大问题,因为您将常量放入 SQL 代码中,并且仅参数化更改的值(无论如何,这些值很可能具有数字性质)。

如果您真的很担心,请在 SQL 中添加 
CAST


在字节码级别,
expr
 变成通过称为 
tryCvtToNumeric

的操作发送值,该操作为值提供数字解释(如果它们可以有的话)。文字默认没有解释。从形式上来说,我们更喜欢 C 代码不依赖于现有的值解释,而是只要求他们想要的解释,但 tclsqlite 扩展(这样称呼它是为了与底层库区分开来)不会这样做,也从来没有这样做过。 .

处理
BLOB
数据时更重要。那就是当你使用 
@var
 而不是 
:var

...

0
投票

据我记得,sqlite 会监听它收到的 Tcl 值的 objtype,并据此改变其行为,我认为这是对系统的滥用,或者至少是对系统的误解。该“类型”实际上只是一个缓存值,反映了它最后被处理的内容,并且实际上并不意味着该值is(就像数据库类型意义上的那样)。也就是说,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)改变,甚至一次。我用“转换”来表示)。在 Hydra 值模型下,上述代码将累积它所引用的所有 objtype,从而使后续访问任何这些 objtype 都变得快速。应该清楚的是,通过窥探 objtype 来假装 Tcl 值具有类型的方法在 Hydra 世界中完全崩溃了。

© www.soinside.com 2019 - 2024. All rights reserved.