Skip to content

Commit 9416897

Browse files
Copilotmathiasrw
andauthored
Throw error for invalid column names starting with digits to close #1173 (#2278)
Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: mathiasrw <[email protected]> Co-authored-by: Mathias Wulff <[email protected]>
1 parent 4882f6e commit 9416897

File tree

3 files changed

+128
-47
lines changed

3 files changed

+128
-47
lines changed

src/alasqlparser.jison

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,9 @@ SETS return 'SET'
269269
'WHILE' return 'WHILE'
270270
'WITH' return 'WITH'
271271
'WORK' return 'TRANSACTION' /* Is this keyword required? */
272+
/* Issue #1173: Reject invalid identifiers like 6minAvgOpac (number followed by letters without space) */
273+
/* This rule must precede NUMBER to catch invalid patterns before they're tokenized as NUMBER + LITERAL */
274+
\d+[a-zA-Z_][a-zA-Z_0-9]* return 'INVALID'
272275
(\d+\.?\d*|\.\d+)([eE][+-]?\d+)? return 'NUMBER'
273276
'->' return 'ARROW'
274277
'#' return 'SHARP'

src/alasqlparser.js

Lines changed: 49 additions & 47 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/test1173.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
if (typeof exports === 'object') {
2+
var assert = require('assert');
3+
var alasql = require('..');
4+
}
5+
6+
describe('Test 1173 - Parser should error on column names starting with numbers', function () {
7+
const test = '1173';
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) Should parse correctly when column name is properly quoted with []', function () {
19+
var sql = 'SELECT ID, [6minAvgOpac] FROM test';
20+
var ast = alasql.parse(sql);
21+
assert.equal(ast.statements[0].columns.length, 2);
22+
assert.equal(ast.statements[0].columns[0].columnid, 'ID');
23+
assert.equal(ast.statements[0].columns[1].columnid, '6minAvgOpac');
24+
});
25+
26+
it('B) Should parse correctly when column name is properly quoted with backticks', function () {
27+
var sql = 'SELECT ID, `6minAvgOpac` FROM test';
28+
var ast = alasql.parse(sql);
29+
assert.equal(ast.statements[0].columns.length, 2);
30+
assert.equal(ast.statements[0].columns[0].columnid, 'ID');
31+
assert.equal(ast.statements[0].columns[1].columnid, '6minAvgOpac');
32+
});
33+
34+
it('C) Should throw error for unquoted column name starting with number', function () {
35+
var sql = 'SELECT ID, 6minAvgOpac FROM test';
36+
assert.throws(
37+
function () {
38+
alasql.parse(sql);
39+
},
40+
function (err) {
41+
return err instanceof SyntaxError || err instanceof Error;
42+
},
43+
'Should throw a SyntaxError for invalid column name starting with number'
44+
);
45+
});
46+
47+
it('D) Should throw error for similar invalid identifier pattern', function () {
48+
var sql = 'SELECT 123abc FROM test';
49+
assert.throws(
50+
function () {
51+
alasql.parse(sql);
52+
},
53+
function (err) {
54+
return err instanceof SyntaxError || err instanceof Error;
55+
},
56+
'Should throw a SyntaxError for invalid identifier 123abc'
57+
);
58+
});
59+
60+
it('E) Valid number literals followed by proper aliases should still work', function () {
61+
var sql = 'SELECT 6 AS minAvgOpac FROM test';
62+
var ast = alasql.parse(sql);
63+
assert.equal(ast.statements[0].columns.length, 1);
64+
assert.equal(ast.statements[0].columns[0].value, 6);
65+
assert.equal(ast.statements[0].columns[0].as, 'minAvgOpac');
66+
});
67+
68+
it('F) Number followed by space then literal alias (without AS) should still work', function () {
69+
// This is valid SQL: SELECT 6 minAvgOpac means SELECT 6 AS minAvgOpac
70+
var sql = 'SELECT 6 minAvgOpac FROM test';
71+
var ast = alasql.parse(sql);
72+
assert.equal(ast.statements[0].columns.length, 1);
73+
assert.equal(ast.statements[0].columns[0].value, 6);
74+
assert.equal(ast.statements[0].columns[0].as, 'minAvgOpac');
75+
});
76+
});

0 commit comments

Comments
 (0)