Skip to content

Commit c69ff4f

Browse files
Copilotmathiasrw
andauthored
Fix UPDATE on tables with PK when data is directly assigned to close #1989 (#2341)
Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: mathiasrw <[email protected]>
1 parent d2b171e commit c69ff4f

File tree

2 files changed

+130
-2
lines changed

2 files changed

+130
-2
lines changed

src/60createtable.js

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -574,14 +574,34 @@ yy.CreateTable.prototype.execute = function (databaseid, params, cb) {
574574
pk = this.pk;
575575
pk.pkaddr = pk.onrightfn(r, params);
576576
if (typeof this.uniqs[pk.hh][pk.pkaddr] === 'undefined') {
577-
throw new Error('Something wrong with index on table');
577+
// If index is not populated (e.g., data was directly assigned), rebuild it.
578+
// This allows UPDATE to work when data bypasses normal INSERT validation.
579+
// Note: If data contains duplicate PKs, last occurrence wins (matches direct assignment semantics).
580+
// This rebuild happens at most once per table since the index will be populated afterward.
581+
this.uniqs[pk.hh] = {};
582+
for (var j = 0; j < this.data.length; j++) {
583+
var addr = pk.onrightfn(this.data[j]);
584+
this.uniqs[pk.hh][addr] = this.data[j];
585+
}
586+
// Recalculate pkaddr after rebuilding
587+
pk.pkaddr = pk.onrightfn(r, params);
578588
}
579589
}
580590
if (table.uk && table.uk.length) {
581591
table.uk.forEach(function (uk) {
582592
uk.ukaddr = uk.onrightfn(r);
583593
if (typeof table.uniqs[uk.hh][uk.ukaddr] === 'undefined') {
584-
throw new Error('Something wrong with unique index on table');
594+
// If index is not populated (e.g., data was directly assigned), rebuild it.
595+
// This allows UPDATE to work when data bypasses normal INSERT validation.
596+
// Note: If data contains duplicate unique keys, last occurrence wins (matches direct assignment semantics).
597+
// This rebuild happens at most once per table since the index will be populated afterward.
598+
table.uniqs[uk.hh] = {};
599+
for (var j = 0; j < table.data.length; j++) {
600+
var addr = uk.onrightfn(table.data[j]);
601+
table.uniqs[uk.hh][addr] = table.data[j];
602+
}
603+
// Recalculate ukaddr after rebuilding
604+
uk.ukaddr = uk.onrightfn(r);
585605
}
586606
});
587607
}

test/test2318.js

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
if (typeof exports === 'object') {
2+
var assert = require('assert');
3+
var alasql = require('..');
4+
}
5+
6+
describe('Test 2318 - Update table with PK and direct data assignment', function () {
7+
const test = '2318';
8+
9+
before(function () {
10+
alasql('create database test' + test);
11+
alasql('use test' + test);
12+
});
13+
14+
after(function () {
15+
alasql('drop database test' + test);
16+
});
17+
18+
it('A) Update with no PK and direct assignment works', function () {
19+
alasql('create table nopk (id int, name string)');
20+
var db = alasql.databases['test' + test];
21+
db.tables.nopk.data = [
22+
{id: 1, name: 'Alice'},
23+
{id: 2, name: 'Bob'},
24+
];
25+
26+
var res = alasql('update nopk set name = ? where id = ?', ['Charlie', 1]);
27+
assert.equal(res, 1);
28+
29+
var data = alasql('select * from nopk order by id');
30+
assert.deepEqual(data, [
31+
{id: 1, name: 'Charlie'},
32+
{id: 2, name: 'Bob'},
33+
]);
34+
});
35+
36+
it('B) Update with PK and INSERT works', function () {
37+
alasql('create table withpk (id int primary key, name string)');
38+
alasql('insert into withpk values (1, ?)', ['Alice']);
39+
alasql('insert into withpk values (2, ?)', ['Bob']);
40+
41+
var res = alasql('update withpk set name = ? where id = ?', ['Charlie', 1]);
42+
assert.equal(res, 1);
43+
44+
var data = alasql('select * from withpk order by id');
45+
assert.deepEqual(data, [
46+
{id: 1, name: 'Charlie'},
47+
{id: 2, name: 'Bob'},
48+
]);
49+
});
50+
51+
it('C) Update with PK and direct assignment should work', function () {
52+
alasql('create table withpk2 (id int primary key, name string)');
53+
var db = alasql.databases['test' + test];
54+
db.tables.withpk2.data = [
55+
{id: 1, name: 'Alice'},
56+
{id: 2, name: 'Bob'},
57+
];
58+
59+
// This should work but currently throws "Something wrong with index on table"
60+
var res = alasql('update withpk2 set name = ? where id = ?', ['Charlie', 1]);
61+
assert.equal(res, 1);
62+
63+
var data = alasql('select * from withpk2 order by id');
64+
assert.deepEqual(data, [
65+
{id: 1, name: 'Charlie'},
66+
{id: 2, name: 'Bob'},
67+
]);
68+
});
69+
70+
it('D) Update with composite PK and direct assignment should work', function () {
71+
alasql('create table composite (id1 int, id2 int, name string, primary key(id1, id2))');
72+
var db = alasql.databases['test' + test];
73+
db.tables.composite.data = [
74+
{id1: 1, id2: 1, name: 'Alice'},
75+
{id1: 1, id2: 2, name: 'Bob'},
76+
];
77+
78+
var res = alasql('update composite set name = ? where id1 = ? and id2 = ?', ['Charlie', 1, 1]);
79+
assert.equal(res, 1);
80+
81+
var data = alasql('select * from composite order by id1, id2');
82+
assert.deepEqual(data, [
83+
{id1: 1, id2: 1, name: 'Charlie'},
84+
{id1: 1, id2: 2, name: 'Bob'},
85+
]);
86+
});
87+
88+
it('E) Update with UNIQUE constraint and direct assignment should work', function () {
89+
alasql('create table withunique (id int, email string unique, name string)');
90+
var db = alasql.databases['test' + test];
91+
db.tables.withunique.data = [
92+
{id: 1, email: '[email protected]', name: 'Alice'},
93+
{id: 2, email: '[email protected]', name: 'Bob'},
94+
];
95+
96+
var res = alasql('update withunique set name = ? where email = ?', [
97+
'Charlie',
98+
99+
]);
100+
assert.equal(res, 1);
101+
102+
var data = alasql('select * from withunique order by id');
103+
assert.deepEqual(data, [
104+
{id: 1, email: '[email protected]', name: 'Charlie'},
105+
{id: 2, email: '[email protected]', name: 'Bob'},
106+
]);
107+
});
108+
});

0 commit comments

Comments
 (0)