perl-DBD-SQLite/0003-Handle-unknown-op-in-DBD-SQLite-VirtualTable-PerlDat.patch
2020-07-01 11:44:14 +08:00

156 lines
5.0 KiB
Diff

From 1fd1a0d15f2be081391710c5035f2ba69d5a51a0 Mon Sep 17 00:00:00 2001
From: Max Maischein <corion@corion.net>
Date: Fri, 25 Jan 2019 19:05:07 +0100
Subject: [PATCH 089/102] Handle 'unknown' op in
DBD::SQLite::VirtualTable::PerlData
This patch adds code and a test when SQLite generates an 'unknown'
op for a table join in the BEST_INDEX() callback. The Perl code crashed
when such an op was generated for a JOIN criterion by the SQLite engine.
The SQLite engine creates an 'unknown' op on the following SQL
for example:
select r.nodepath
from temp.scan_results r
left join temp.scan_results m
on r.nodepath = m.nodepath+1
where m.nodepath is null
The important part is that the right side of the left join must be
checked for IS NULL.
---
MANIFEST | 1 +
lib/DBD/SQLite/VirtualTable/PerlData.pm | 2 +-
t/virtual_table/unknown_op.t | 93 +++++++++++++++++++++++++
3 files changed, 95 insertions(+), 1 deletion(-)
create mode 100644 t/virtual_table/unknown_op.t
diff --git a/MANIFEST b/MANIFEST
index 96e1192..c53f269 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -138,5 +138,6 @@ t/virtual_table/20_perldata.t
t/virtual_table/21_perldata_charinfo.t
t/virtual_table/rt_99748.t
+t/virtual_table/unknown_op.t
typemap
xt/cpp_comments.t
xt/meta.t
diff --git a/lib/DBD/SQLite/VirtualTable/PerlData.pm b/lib/DBD/SQLite/VirtualTable/PerlData.pm
index 39ca09b..0e58d7d 100644
--- a/lib/DBD/SQLite/VirtualTable/PerlData.pm
+++ b/lib/DBD/SQLite/VirtualTable/PerlData.pm
@@ -88,7 +88,7 @@ sub BEST_INDEX {
# in FILTER() for deciding which rows match the constraints.
my @conditions;
my $ix = 0;
- foreach my $constraint (grep {$_->{usable}} @$constraints) {
+ foreach my $constraint (grep {$_->{usable} and exists $SQLOP2PERLOP{ $_->{op} } } @$constraints) {
my $col = $constraint->{col};
my ($member, $optype);
diff --git a/t/virtual_table/unknown_op.t b/t/virtual_table/unknown_op.t
new file mode 100644
index 0000000..e8fe04b
--- /dev/null
+++ b/t/virtual_table/unknown_op.t
@@ -0,0 +1,93 @@
+#!perl -w
+
+use strict;
+use Test::More tests => 4;
+
+our $scan_results = [
+ { nodepath => 1 },
+ { nodepath => 2 },
+ { nodepath => 3 },
+];
+
+my $dbh = DBI->connect("dbi:SQLite:dbname=:memory:", '', '',
+ {RaiseError => 1, AutoCommit => 1});
+
+# register the module
+$dbh->sqlite_create_module(perl => "DBD::SQLite::VirtualTable::PerlData");
+$dbh->do(<<'SQL');
+ CREATE VIRTUAL TABLE temp.scan_results
+ USING perl(file varchar,
+ value varchar,
+ selector varchar,
+ nodepath varchar,
+ expected integer,
+ preference integer,
+ complexity integer,
+ location varchar,
+ type varchar,
+ hashrefs="main::scan_results")
+SQL
+
+my $ok = eval {
+ my $sth = $dbh->prepare(<<'SQL');
+ select distinct r.selector
+ from temp.scan_results r
+ left join temp.scan_results m
+ on r.nodepath = m.nodepath+1
+ where m.nodepath = 1
+SQL
+$sth->execute;
+ #use DBIx::RunSQL; print DBIx::RunSQL->format_results( sth => $sth );
+ 1;
+};
+is $ok, 1, "We survive a numeric comparison";
+undef $ok;
+
+$ok = eval {
+ my $sth = $dbh->prepare(<<'SQL');
+ select distinct r.selector
+ from temp.scan_results r
+ left join temp.scan_results m
+ on r.nodepath = m.nodepath+1
+ where m.nodepath is not null
+SQL
+ $sth->execute;
+ 1;
+ #use DBIx::RunSQL; print DBIx::RunSQL->format_results( sth => $sth );
+};
+is $ok, 1, "We survive an isnull comparison";
+undef $ok;
+
+$ok = eval {
+ my $sth = $dbh->prepare(<<'SQL');
+ select r.nodepath
+ from temp.scan_results r
+ left join temp.scan_results m
+ on r.nodepath = m.nodepath+1
+ where r.nodepath is null
+SQL
+ $sth->execute;
+ 1;
+ #use DBIx::RunSQL; print DBIx::RunSQL->format_results( sth => $sth );
+};
+is $ok, 1, "We survive an isnull comparison on the left side";
+undef $ok;
+
+my $sth;
+$ok = eval {
+ $sth = $dbh->prepare(<<'SQL');
+ select r.nodepath
+ from temp.scan_results r
+ left join temp.scan_results m
+ on r.nodepath = m.nodepath+1
+ where m.nodepath is null
+SQL
+ $sth->execute;
+ 1;
+ #use DBIx::RunSQL; print DBIx::RunSQL->format_results( sth => $sth );
+};
+is $ok, 1, "We survive an isnull comparison on the right side";
+undef $ok;
+#my $rows = $sth->fetchall_arrayref;
+#use Data::Dumper;
+#warn Dumper $rows;
\ No newline at end of file
--
2.19.1