Open mwhebert opened 6 years ago
Hi, I had a quick look at this and the bug replication code can be distilled to just one table using a primary key:
let alasql = require('alasql');
let DemoDB = {
appliance: [
{name: "A", type: 'Fast'},
{name: "B", type: 'Medium'},
{name: "C", type: 'Slow'}
]
}
alasql('CREATE DATABASE [Demo]');
alasql('USE DATABASE [Demo]');
alasql("CREATE TABLE appliance (name STRING PRIMARY KEY, type STRING)");
alasql('SELECT * INTO appliance FROM ?',[DemoDB.appliance]);
console.log("Delete appliance:",alasql("DELETE FROM appliance WHERE name = 'A'"));
The error comes from within the table["delete"] function:
if (this.pk) {
var pk = this.pk;
var addr = pk.onrightfn(r);
if (typeof this.uniqs[pk.hh][addr] === 'undefined') {
throw new Error('Something wrong with primary key index on table');
} else {
this.uniqs[pk.hh][addr] = undefined;
}
}
Any updates on this issue? I'm still getting the same error when trying to delete from a table with a primary key
Some comments:
The root cause of the issue is 'SELECT INTO' logic circumventing the usual insert logic by doing a push directly on the table data (file 40select.js, lines 308-315 - at time of writing, code may change).
The second problem comes from the deletion: primary key and unique key indices are checked on deletion, and if one or the other does not exist an exception is thrown (file 60createtable.js, lines 544 and 553). The check in itself makes sense, but it is a check not on the users data (which may or may not be correct regarding the primary key or the uniqueness) but on the internals of the database. Hence, a user of the library would expect an error statement but no exception, making the ‘SELECT INTO’-logic unusable to him. Hence, I would prefer lines 544 and 553 of 60createtable.js to hold logging statements with additional information on the context (affected table etc.).
The root issue with ‘SELECT INTO’ is similar to issue #92 with ‘INSERT INTO’ solved in April 2015 (where a direct concat of the data was used instead of insert).
I made a quick fix replacing lines 308-315 of 40select.js with the following code:
query.intofns =
"var db = alasql.databases['" +(this.into.databaseid || databaseid) + "'];" +
"var table = db.tables['" + this.into.tableid + "'];" +
"var cR = alasql.utils.cloneDeep(r);" +
"if (table.defaultfns) {" +
" var defaultfns = 'return alasql.utils.extend(r,{' + table.defaultfns + '})';" +
" var defaultfn = new Function('r,db,params,alasql', defaultfns);" +
" defaultfn(cR, db, [], alasql);" +
"}" +
"if (table.insert) {" +
" table.insert(cR, false);" +
"} else {" +
"table.data.push(cR);" +
"}";
It ran smooth with alasql tests, the test code given in this issue and in my own table with unique constraints. I have not tested tables with column defaults, yet. However, I am not comfortable with fix and do not directly create a pull request for it: I would prefer a more elaborated version - especially in the long run. On one hand, creating code with string and new Function (or eval()) is not the best solution as long as there are alternatives in a given context. On the other hand, code in ‘INSERT INTO’ and ‘SELECT INTO’ functionality have overlapping logic and an unified version without - partial - code duplication would be preferable.
Hope, it helps! Thank you for providing AlaSql!
sample test below fails with "Something wrong with primary key index on table" which I would not expect.