1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
|
use strict;
use warnings;
use lib "t/lib";
use SQLiteTest qw/connect_ok $sqlite_call/;
use Test::More;
use if -d ".git", "Test::FailWarnings";
my $dbh = connect_ok( RaiseError => 1, PrintError => 0, AutoCommit => 1 );
$dbh->$sqlite_call(create_module => vtab => "DBD::SQLite::VirtualTable::T");
ok $dbh->do("CREATE VIRTUAL TABLE foobar USING vtab(foo INTEGER, bar INTEGER)"),
"created foobar";
# overload functions "abs" and "substr"
$DBD::SQLite::VirtualTable::T::funcs{abs}{overloaded}
= sub {my $val = shift; return "fake_abs($val)" };
$DBD::SQLite::VirtualTable::T::funcs{substr}{overloaded}
= sub {my ($val, $offset, $len) = @_; return "fake_substr($val, $offset, $len)" };
# make a first query
my $row = $dbh->selectrow_hashref(<<"");
SELECT abs(foo) afoo,
abs(bar) abar,
substr(foo, 3, 5) sfoo,
trim(foo) tfoo
FROM foobar
is $DBD::SQLite::VirtualTable::T::funcs{abs}{calls}, 1, "abs called";
is $DBD::SQLite::VirtualTable::T::funcs{substr}{calls}, 1, "substr called";
is $DBD::SQLite::VirtualTable::T::funcs{trim}{calls}, 1, "trim called";
is_deeply $row, { 'abar' => 'fake_abs(1)',
'afoo' => 'fake_abs(0)',
'sfoo' => 'fake_substr(0, 3, 5)',
'tfoo' => '0' }, "func results";
# new query : FIND_FUNCTION should not be called again
$row = $dbh->selectrow_hashref(<<"");
SELECT abs(foo) afoo,
abs(bar) abar,
substr(foo, 3, 5) sfoo,
trim(foo) tfoo
FROM foobar
is $DBD::SQLite::VirtualTable::T::funcs{abs}{calls}, 1, "abs still 1";
is $DBD::SQLite::VirtualTable::T::funcs{substr}{calls}, 1, "substr still 1";
is $DBD::SQLite::VirtualTable::T::funcs{trim}{calls}, 1, "trim still 1";
# new table : should issue new calls to FIND_FUNCTION
ok $dbh->do("CREATE VIRTUAL TABLE barfoo USING vtab(foo INTEGER, bar INTEGER)"),
"created barfoo";
$row = $dbh->selectrow_hashref(<<"");
SELECT abs(foo) afoo,
abs(bar) abar,
substr(foo, 3, 5) sfoo,
trim(foo) tfoo
FROM barfoo
is $DBD::SQLite::VirtualTable::T::funcs{abs}{calls}, 2, "abs now 2";
is $DBD::SQLite::VirtualTable::T::funcs{substr}{calls}, 2, "substr now 2";
is $DBD::SQLite::VirtualTable::T::funcs{trim}{calls}, 2, "trim now 2";
# drop table : should free references to functions
ok $dbh->do("DROP TABLE foobar");
# drop connection
undef $dbh;
note "done";
done_testing;
package DBD::SQLite::VirtualTable::T;
use strict;
use warnings;
use base 'DBD::SQLite::VirtualTable';
sub BEST_INDEX {
my ($self, $constraints, $order_by) = @_;
my $ix = 0;
foreach my $constraint (@$constraints) {
$constraint->{argvIndex} = $ix++;
$constraint->{omit} = 1; # to prevent sqlite core to check values
}
my $outputs = {
idxNum => 1,
idxStr => "foobar",
orderByConsumed => 0,
estimatedCost => 1.0,
estimatedRows => undef,
};
return $outputs;
}
our %funcs;
sub FIND_FUNCTION {
my ($self, $n_arg, $function_name) = @_;
$funcs{$function_name}{calls} += 1;
my $func = $funcs{$function_name}{overloaded};
return $func;
}
package DBD::SQLite::VirtualTable::T::Cursor;
use strict;
use warnings;
use base 'DBD::SQLite::VirtualTable::Cursor';
sub NEW {
my $class = shift;
my $self = $class->DBD::SQLite::VirtualTable::Cursor::NEW(@_);
$self->{row_count} = 5;
return $self;
}
sub FILTER {
my ($self, $idxNum, $idxStr, @values) = @_;
return;
}
sub EOF {
my $self = shift;
return !$self->{row_count};
}
sub NEXT {
my $self = shift;
$self->{row_count}--;
}
sub COLUMN {
my ($self, $idxCol) = @_;
return $idxCol;
}
sub ROWID {
my ($self) = @_;
return $self->{row_count};
}
1;
|