FCO / Red

A WiP ORM for Raku

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

IN sub-select generates SQL malformed SQL

jonathanstowe opened this issue · comments

While looking at #520 I noticed that an IN with a sub-select like:

#!/usr/bin/env raku

use Red;

my $*RED-DB = database 'SQLite';
my $*RED-DEBUG = True;

model A {
    has Str $.id is id;
    has     @.bs is relationship({ .a-id }, model => 'B' );
}

model B {
    has Int $.id is serial;
    has Str $.a-id is column({ name => 'a', model-name => 'A', column-name => 'id' });
    has     $.a    is relationship({ .a-id }, model => 'A');
    has Int $.c-id is referencing(model => 'C', column => 'id' );
    has     $.c is relationship({ .c-id }, model => 'C');
    has Bool $.d is column is rw = True;
}

model C {
    has Int $.id is serial;
    has Str $.d is column;
    has     @.bs is relationship({ .c-id }, model => 'B' );
}

A.^create-table;
C.^create-table;
B.^create-table;

my $a = A.^create( id => 'FOO');

my $sub =   $a.bs.grep( *.c.d (>) <a b c> ).map( *.id );
say $a.bs.grep(*.id (<) $sub).map( { .d = True }).save;

# vim: ft=raku

Gives rise to:

SQL : CREATE TABLE "a" (
   id varchar(255) NOT NULL primary key 
)
BIND: []
SQL : CREATE TABLE "c" (
   id integer NOT NULL primary key AUTOINCREMENT,
   d varchar(255) NOT NULL 
)
BIND: []
SQL : CREATE TABLE "b" (
   id integer NOT NULL primary key AUTOINCREMENT,
   a varchar(255) NOT NULL references a(id),
   c_id integer NULL references c(id),
   d integer NOT NULL 
)
BIND: []
SQL : BEGIN
BIND: []
SQL : INSERT INTO "a"(
   id
)
VALUES(
   ?
)
BIND: ["FOO"]
SQL : SELECT
   "a".id 
FROM
   "a"
WHERE
   _rowid_ = last_insert_rowid()
LIMIT 1
BIND: []
SQL : SELECT
   "a".id 
FROM
   "a"
WHERE
   "a".id = 'FOO'
LIMIT 1
BIND: []
SQL : COMMIT
BIND: []
SQL : UPDATE b SET
   d = 1
WHERE "b".a = ? AND "b".id IN SELECT
   "b".id as "data_1"
FROM
   "b"
    LEFT JOIN "c" as b_c ON "b".c_id = "b_c".id
WHERE
   "b".a = ? AND "b_c".d NOT IN ( ?, ?, ? )

    Unknown Error!!!
    Please, copy this backtrace and open an issue on https://github.com/FCO/Red/issues/new
    Driver: Red::Driver::SQLite
    Original error: X::DBDish::DBError.new(driver-name => "DBDish::SQLite", native-message => "near \"SELECT\": syntax error", code => 1, why => "Error")

Original error:
DBDish::SQLite: Error: near "SELECT": syntax error (1)
  in method handle-error at /home/jonathan/.raku/sources/9649AE51DBA2ED07FF0A6B99F0A2C5DDBAD5E7E0 (DBDish::SQLite::Connection) line 17
  in method prepare at /home/jonathan/.raku/sources/9649AE51DBA2ED07FF0A6B99F0A2C5DDBAD5E7E0 (DBDish::SQLite::Connection) line 26
  in method prepare at /home/jonathan/devel/raku/3rdparty-modules/Red/lib/Red/Driver/SQLite.pm6 (Red::Driver::SQLite) line 56
  in code  at /home/jonathan/devel/raku/3rdparty-modules/Red/lib/Red/Driver.pm6 (Red::Driver) line 84
  in code  at /home/jonathan/devel/raku/3rdparty-modules/Red/lib/Red/Driver.pm6 (Red::Driver) line 83
  in method prepare at /home/jonathan/devel/raku/3rdparty-modules/Red/lib/Red/Driver.pm6 (Red::Driver) line 80
  in method execute at /home/jonathan/devel/raku/3rdparty-modules/Red/lib/Red/Driver.pm6 (Red::Driver) line 114
  in method save at /home/jonathan/devel/raku/3rdparty-modules/Red/lib/Red/ResultSeq.pm6 (Red::ResultSeq) line 376
  in block <unit> at rec6 line 35

Actually thrown at:
  in block  at /home/jonathan/devel/raku/3rdparty-modules/Red/lib/Red/Driver/SQLite.pm6 (Red::Driver::SQLite) line 52
  in any  at /home/jonathan/devel/raku/3rdparty-modules/Red/lib/Red/Driver/SQLite.pm6 (Red::Driver::SQLite) line 50
  in method prepare at /home/jonathan/.raku/sources/9649AE51DBA2ED07FF0A6B99F0A2C5DDBAD5E7E0 (DBDish::SQLite::Connection) line 37
  in method prepare at /home/jonathan/devel/raku/3rdparty-modules/Red/lib/Red/Driver/SQLite.pm6 (Red::Driver::SQLite) line 56
  in code  at /home/jonathan/devel/raku/3rdparty-modules/Red/lib/Red/Driver.pm6 (Red::Driver) line 84
  in code  at /home/jonathan/devel/raku/3rdparty-modules/Red/lib/Red/Driver.pm6 (Red::Driver) line 83
  in method prepare at /home/jonathan/devel/raku/3rdparty-modules/Red/lib/Red/Driver.pm6 (Red::Driver) line 80
  in method execute at /home/jonathan/devel/raku/3rdparty-modules/Red/lib/Red/Driver.pm6 (Red::Driver) line 114
  in method save at /home/jonathan/devel/raku/3rdparty-modules/Red/lib/Red/ResultSeq.pm6 (Red::ResultSeq) line 376
  in block <unit> at rec6 line 35

i.e. it is omitting the required parentheses around the sub-select.

I thought this would be an easy fix, but it seems that it isn't so. Most sub-selects do get the parentheses but this one doesn't.

I'm planing to add an multi method translation(Red::AST::In $_ where *.right ~~ Red::AST::Select, $) or something like that

Actually you could do that do that for any Red::AST::Infix in order to support any sub-select on the RHS easily.

It breaks t/20-in-sql.t :(

It breaks t/20-in-sql.t :(

Yes that's what I found when I did my first (dumb) attempt at putting the parens round any sub-select.

@jonathanstowe could you confirm that's fixed?

Yep that's great 👍