无法解析调用方 sqlite3_bind:无法理解我的 Perl 6 脚本中的此错误

Cannot resolve caller sqlite3_bind: Do not understand this error in my Perl 6 script

脚本的用途:我希望能够使用它来将费用插入 SQLite 数据库,然后制作自定义报告以提取信息,以便更好地预算我的费用。

我完全不明白这个错误代码。

perl6 budgetpro.p6

Apple

An apple a day keeps the doctor away

Hi, I am Essential, nice to meet you, Eggman

Cannot resolve caller sqlite3_bind(DBDish::SQLite::Native::STMT, Int,
Date); none of these signatures match:
    (DBDish::SQLite::Native::STMT $stmt, Int $n, Blob:D $b)
    (DBDish::SQLite::Native::STMT $stmt, Int $n, Real:D $d)
    (DBDish::SQLite::Native::STMT $stmt, Int $n, Int:D $i)
    (DBDish::SQLite::Native::STMT $stmt, Int $n, Any:U)
    (DBDish::SQLite::Native::STMT $stmt, Int $n, Str:D $d)   
    in method execute at /home/jon/opt/rakudo-star/share/perl6/site/sources/2D749062AA6D5641452CDA214FC7C566E7E3E2A1
(DBDish::SQLite::StatementHandle) line 38
    in method insert at budgetpro.p6 line 54   in block <unit> at budgetpro.p6 line 86`
  2
  3 use v6;
  4 use DBIish;
  5
  6 constant DB = 'budgetpro.sqlite3';
  7 my $dbh = DBIish.connect('SQLite', database => DB);
  8
  9 #$dbh.do('drop table if exists Essential, Savings, Personal');
 10
 11 sub create-schema {
 12     $dbh.do(qq:to/SCHEMA/);
 13         create table if not exists Essential(
 14             id          integer primary key not null,
 15             name        varchar not null,
 16             quantity    integer not null,
 17             price       numeric(5,2) not null,
 18             description varchar not null,
 19             date        timestamp not null default (datetime('now'))
 20         );
 21         create table is not exists Savings(
 22             id          integer primary key not null,
 23             name        varchar not null,
 24             quantity    integer not null,
 25             price       numeric(5,2) not null,
 26             description varchar not null,
 27             date        timestamp not null default (datetime('now'))
 28         );
 29         create table if not exists Personal(
 30             id          integer primary key not null,
 31             name        varchar not null,
 32             quantity    integer not null,
 33             price       numeric(5,2) not null,
 34             description varchar not null,
 35             date        timestamp not null default (datetime('now'))
 36         );
 37     SCHEMA
 38 }
 39
 40 create-schema;
 41
 42 class Item {
 43     has $!table = 'Essential';
 44     has $.name;
 45     has $.quantity;
 46     has $.price;
 47     has $.description is rw;
 48     has $.timestamp;
 49     has Str $.notes is rw;
 50     method notes() { "$!notes\n" };
 51
 52     method insert($name, $quantity?, $price?, $description?, $timestamp?) {
 53         my $sth = $dbh.prepare("insert into Essential(name,quantity,price,description,date) values (?,?,?,?,?)");
 54         $sth.execute($name, $quantity, $price, $description, $timestamp);
 55
 56         say "Inserted $name, $quantity, $price, $description, $timestamp";
 57     }
 58 }
 59
 60 class Essential is Item {
 61     method greet($me: $person) {
 62         say "Hi, I am $me.^name(), nice to meet you, $person";
 63     }
 64 }
 65
 66 class Savings is Item {
 67 }
 68
 69 class Personal is Item {
 70 }
 71 
 72 my $food = Essential.new(
 73     name => 'Apple',
 74     price => .99,
 75     quantity => 2,
 76     notes => 'An apple a day keeps the doctor away'
 77 );
 78
 79 say $food.name;
 80 say $food.notes;
 81 Essential.new.greet('Eggman');
 82 say '';
 83
 84 my $test = Item.new();
 85
 86 $test.insert("Cheese", 2, 1.99, 'Block of cheddar', Date.new(now));
 87
 88 say $test.name;

问题是你调用了:

$test.insert("Cheese", 2, 1.99, 'Block of cheddar', Date.new(now));

最终会调用 sqlite3_bind,但没有一个候选者接受 Date 的实例作为第三个参数。


它将接受 BlobIntRealNumeric 但不是 Complex)或 Str 的实例.它还会接受未定义的值 (Any:U)。

在我看来,这是数据库驱动程序中的一个错误或缺失的功能,它不接受 DateTime 甚至可能是 Instant 对象,并自动将其转换为什么SQLite 预计。


我还想指出还有 Date.todayDateTime.now。后者将跟踪当前时区信息,而 DateTime.new(now) 则不会。
(这是故意的,因为无法知道 Instant 来自哪里。)

@Brad Gilbert 是对的。语句只接受5种数据结构,其中none是DateTIME and DATE are standard data types in SQL,但目前他们似乎没有 DBIish 的支持。在这种情况下,您可以将第 85 行更改为

$test.insert("Cheese", 2, 1.99, 'Block of cheddar', Date.new(now).Str);

并让您的程序处理与日期之间的转换,您还必须更改 Essential table 的定义。您还可以让数据库处理默认值。你将不得不删除 "not null",因为它与 default 句子冲突。

还有一些小错误。这减少到最小表达式,工作并将默认时间戳正确插入数据库(使用 sqlite3 命令行检查):

use v6;
use DBIish;

constant DB = 'budgetpro.sqlite3';
my $dbh = DBIish.connect('SQLite', database => DB);

#$dbh.do('drop table if exists Essential, Savings, Personal');

sub create-schema {
    $dbh.do(qq:to/SCHEMA/);
        create table if not exists Essential(
            id          integer primary key not null,
            name        varchar not null,
            quantity    integer not null,
            price       numeric(5,2) not null,
            description varchar not null,
            date        timestamp default (datetime('now'))
        );
    SCHEMA
}

create-schema;

class Item {
    has $!table = 'Essential';
    has $.name;
    has $.quantity;
    has $.price;
    has $.description is rw;
    has $.timestamp;
    has Str $.notes is rw;
    method notes() { "$!notes\n" };

    method insert($name, $quantity?, $price?, $description?, $timestamp?) {
        my $sth = $dbh.prepare("insert into Essential(name,quantity,price,description) values (?,?,?,?)");
        $sth.execute($name, $quantity, $price, $description);

        say "Inserted $name, $quantity, $price, $description";
    }
}

Item.new().insert("Cheese", 2, 1.99, 'Block of cheddar');

请注意,您的 Item class 实际上并未由 运行 一个 insert 句子实例化,因此最后一行中的 $test.name 只会return 一个空对象,默认值分配给实例变量。您可能希望将 insert 方法更改为实例化项目的子方法 将其插入数据库。