From 652625fc81ef9f373c7f86e707e1f630d35881c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Laiola=20Guimar=C3=A3es?= Date: Thu, 11 Apr 2024 07:57:45 -0300 Subject: [PATCH 1/6] Update parser_ra.ts --- src/db/parser/parser_ra.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/db/parser/parser_ra.ts b/src/db/parser/parser_ra.ts index 318a260fe..f7775d07c 100644 --- a/src/db/parser/parser_ra.ts +++ b/src/db/parser/parser_ra.ts @@ -3,6 +3,9 @@ import { i18n } from 'calc2/i18n'; const pegParserRelalg = require('./grammar_ra.pegjs') as any; export function parseRelalg(text: string, relationNames: string[] = []): relalgAst.rootRelalg { + // Remove any whitespace before '(' character + text = text.replace(/\s*\(/g, '('); + const ast = pegParserRelalg.parse(text, { startRule: 'start', relationNames: relationNames, From 2c815445a4ed95c3854636481e2ebb161adf8ada Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Laiola=20Guimar=C3=A3es?= Date: Thu, 11 Apr 2024 08:36:48 -0300 Subject: [PATCH 2/6] Update relalg.ts --- src/db/relalg.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/db/relalg.ts b/src/db/relalg.ts index 3ac5a684d..6f2cd8e6e 100644 --- a/src/db/relalg.ts +++ b/src/db/relalg.ts @@ -137,7 +137,8 @@ const pegParserSql = require('./parser/grammar_sql.pegjs') as any; export function parseSQLSelect(text: string): sqlAst.rootSql { return pegParserSql.parse( - text, + // Remove any whitespace before '(' character + text.replace(/\s*\(/g, '('), { startRule: 'start', tracer: undefined, From 7c2a35d73c6b39a743b999264f528f864ff489a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Laiola=20Guimar=C3=A3es?= Date: Fri, 12 Apr 2024 17:20:27 -0300 Subject: [PATCH 3/6] Fix --- src/db/parser/grammar_ra.pegjs | 8 ++++---- src/db/parser/parser_ra.ts | 3 --- src/db/relalg.ts | 3 +-- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/db/parser/grammar_ra.pegjs b/src/db/parser/grammar_ra.pegjs index 5e52bdaa5..e8f9abc09 100644 --- a/src/db/parser/grammar_ra.pegjs +++ b/src/db/parser/grammar_ra.pegjs @@ -1506,7 +1506,7 @@ valueExprFunctionsNary ('coalesce'i { return ['coalesce', 'null']; }) / ('concat'i { return ['concat', 'string']; }) ) -'(' _ arg0:valueExpr _ argn:(',' _ valueExpr _ )* ')' +_ '(' _ arg0:valueExpr _ argn:(',' _ valueExpr _ )* ')' { var args = [arg0]; for(var i = 0; i < argn.length; i++){ @@ -1533,7 +1533,7 @@ valueExprFunctionsBinary / ('mul'i { return ['mul', 'number']; }) / ('div'i { return ['div', 'number']; }) ) -'(' _ arg0:valueExpr _ ',' _ arg1:valueExpr _ ')' +_ '(' _ arg0:valueExpr _ ',' _ arg1:valueExpr _ ')' { return { type: 'valueExpr', @@ -1567,7 +1567,7 @@ valueExprFunctionsUnary / ('second'i { return ['second', 'number']; }) / ('dayofmonth'i { return ['dayofmonth', 'number']; }) ) -'(' _ arg0:valueExpr _ ')' +_ '(' _ arg0:valueExpr _ ')' { return { type: 'valueExpr', @@ -1593,7 +1593,7 @@ valueExprFunctionsNullary / ('clock_timestamp'i { return ['clock_timestamp', 'date']; }) / ('sysdate'i { return ['clock_timestamp', 'date']; }) ) -'(' _ ')' +_ '(' _ ')' { return { type: 'valueExpr', diff --git a/src/db/parser/parser_ra.ts b/src/db/parser/parser_ra.ts index f7775d07c..318a260fe 100644 --- a/src/db/parser/parser_ra.ts +++ b/src/db/parser/parser_ra.ts @@ -3,9 +3,6 @@ import { i18n } from 'calc2/i18n'; const pegParserRelalg = require('./grammar_ra.pegjs') as any; export function parseRelalg(text: string, relationNames: string[] = []): relalgAst.rootRelalg { - // Remove any whitespace before '(' character - text = text.replace(/\s*\(/g, '('); - const ast = pegParserRelalg.parse(text, { startRule: 'start', relationNames: relationNames, diff --git a/src/db/relalg.ts b/src/db/relalg.ts index 6f2cd8e6e..3ac5a684d 100644 --- a/src/db/relalg.ts +++ b/src/db/relalg.ts @@ -137,8 +137,7 @@ const pegParserSql = require('./parser/grammar_sql.pegjs') as any; export function parseSQLSelect(text: string): sqlAst.rootSql { return pegParserSql.parse( - // Remove any whitespace before '(' character - text.replace(/\s*\(/g, '('), + text, { startRule: 'start', tracer: undefined, From 013c6d965dd5f828f10cf83d0b818c5db7de81fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Laiola=20Guimar=C3=A3es?= Date: Sat, 13 Apr 2024 08:11:23 -0300 Subject: [PATCH 4/6] Update grammar_ra.pegjs --- src/db/parser/grammar_ra.pegjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/db/parser/grammar_ra.pegjs b/src/db/parser/grammar_ra.pegjs index e8f9abc09..f14033c25 100644 --- a/src/db/parser/grammar_ra.pegjs +++ b/src/db/parser/grammar_ra.pegjs @@ -538,14 +538,14 @@ listOfOrderByArgs aggFunction -= func:$('sum'i / 'count'i / 'avg'i / 'min'i / 'max'i) '(' _ col:columnName _ ')' += func:$('sum'i / 'count'i / 'avg'i / 'min'i / 'max'i) _ '(' _ col:columnName _ ')' { return { aggFunction: func.toUpperCase(), col: col }; } -/ 'count(*)'i +/ 'count'i _ '(' _ '*' _ ')' { return { aggFunction: 'COUNT_ALL', From 1038784e0b2efce6758cc884e776507a29131abd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Laiola=20Guimar=C3=A3es?= Date: Sat, 13 Apr 2024 08:27:05 -0300 Subject: [PATCH 5/6] Update grammar_sql.pegjs --- src/db/parser/grammar_sql.pegjs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/db/parser/grammar_sql.pegjs b/src/db/parser/grammar_sql.pegjs index 5af7dd145..239d39009 100644 --- a/src/db/parser/grammar_sql.pegjs +++ b/src/db/parser/grammar_sql.pegjs @@ -230,7 +230,7 @@ columnIndex } aggFunction -= func:$('sum'i / 'count'i / 'avg'i / 'min'i / 'max'i) '(' _ ('ALL'i __)? col:columnName _ ')' += func:$('sum'i / 'count'i / 'avg'i / 'min'i / 'max'i) _ '(' _ ('ALL'i __)? col:columnName _ ')' { return { type: 'aggFunction', @@ -238,7 +238,7 @@ aggFunction col: col }; } -/ 'count(*)'i +/ 'count'i _ '(' _ '*' _ ')' { return { type: 'aggFunction', @@ -1339,7 +1339,7 @@ valueExprFunctionsNary ('coalesce'i { return ['coalesce', 'null']; }) / ('concat'i { return ['concat', 'string']; }) ) -'(' _ arg0:valueExpr _ argn:(',' _ valueExpr _ )* ')' +_ '(' _ arg0:valueExpr _ argn:(',' _ valueExpr _ )* ')' { var args = [arg0]; for(var i = 0; i < argn.length; i++){ @@ -1366,7 +1366,7 @@ valueExprFunctionsBinary / ('mul'i { return ['mul', 'number']; }) / ('div'i { return ['div', 'number']; }) ) -'(' _ arg0:valueExpr _ ',' _ arg1:valueExpr _ ')' +_ '(' _ arg0:valueExpr _ ',' _ arg1:valueExpr _ ')' { return { type: 'valueExpr', @@ -1400,7 +1400,7 @@ valueExprFunctionsUnary / ('second'i { return ['second', 'number']; }) / ('dayofmonth'i { return ['dayofmonth', 'number']; }) ) -'(' _ arg0:valueExpr _ ')' +_ '(' _ arg0:valueExpr _ ')' { return { type: 'valueExpr', @@ -1426,7 +1426,7 @@ valueExprFunctionsNullary / ('clock_timestamp'i { return ['clock_timestamp', 'date']; }) / ('sysdate'i { return ['clock_timestamp', 'date']; }) ) -'(' _ ')' +_ '(' _ ')' { return { type: 'valueExpr', From 0746c611350c48ff80b9c7963db88a762dd74539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Laiola=20Guimar=C3=A3es?= Date: Thu, 18 Apr 2024 10:29:34 -0300 Subject: [PATCH 6/6] Add tests --- src/db/tests/translate_tests_ra.ts | 67 +++++++++++++++++++++++++++++ src/db/tests/translate_tests_sql.ts | 45 +++++++++++++++++++ 2 files changed, 112 insertions(+) diff --git a/src/db/tests/translate_tests_ra.ts b/src/db/tests/translate_tests_ra.ts index f2116f60a..45539862e 100644 --- a/src/db/tests/translate_tests_ra.ts +++ b/src/db/tests/translate_tests_ra.ts @@ -1223,3 +1223,70 @@ QUnit.test('groupby textgen', function (assert) { "\t'a' , 1 \n" + '} ) '); }); + +QUnit.test('whitespace(s) between aggregate function and opening parenthesis', function (assert) { + const result = exec_ra("gamma ; sum (a)->total_a (R)", getTestRelations()).getResult(); + result.eliminateDuplicateRows(); + + const reference = exec_ra('{total_a\n' + + '19\n' + + '}', {}).getResult(); + + assert.deepEqual(result, reference); +}); + +QUnit.test('whitespace(s) between count(*) function and opening parenthesis', function (assert) { + const result = exec_ra("gamma ; count (*)->n (R)", getTestRelations()).getResult(); + result.eliminateDuplicateRows(); + + const reference = exec_ra('{n\n' + + '5\n' + + '}', {}).getResult(); + + assert.deepEqual(result, reference); +}); + +QUnit.test('whitespace(s) between n-ary text function and opening parenthesis', function (assert) { + const result = exec_ra("pi concat (a, b, c)->k (R)", getTestRelations()).getResult(); + result.eliminateDuplicateRows(); + + const reference = exec_ra('{k\n' + + '1ad\n' + + '3cc\n' + + '4df\n' + + '5db\n' + + '6ef\n' + + '}', {}).getResult(); + + assert.deepEqual(result, reference); +}); + +QUnit.test('whitespace(s) between binary function and opening parenthesis', function (assert) { + const result = exec_ra("pi add (a, 5)->a_plus_5 (R)", getTestRelations()).getResult(); + result.eliminateDuplicateRows(); + + const reference = exec_ra('{a_plus_5\n' + + '6\n' + + '8\n' + + '9\n' + + '10\n' + + '11\n' + + '}', {}).getResult(); + + assert.deepEqual(result, reference); +}); + +QUnit.test('whitespace(s) between unary function and opening parenthesis', function (assert) { + const result = exec_ra("pi a + length ( c )->x, upper ( b )->k (R)", getTestRelations()).getResult(); + result.eliminateDuplicateRows(); + + const reference = exec_ra('{\tx:number, k:string\n' + + "\t2, 'A'\n" + + "\t4, 'C'\n" + + "\t5, 'D'\n" + + "\t6, 'D'\n" + + "\t7, 'E'\n" + + '}', {}).getResult(); + + assert.deepEqual(result, reference); +}); diff --git a/src/db/tests/translate_tests_sql.ts b/src/db/tests/translate_tests_sql.ts index 74065bba9..f57bc1ff2 100644 --- a/src/db/tests/translate_tests_sql.ts +++ b/src/db/tests/translate_tests_sql.ts @@ -907,3 +907,48 @@ QUnit.skip('test aggregate function in value-expression', function (assert) { assert.deepEqual(exec_sql(query).getResult(), exec_ra(queryRef).getResult()); }); + +QUnit.test('whitespace(s) between aggregate function and opening parenthesis', function (assert) { + const query = ` + SELECT sum(a) AS total_a + FROM R`; + const queryRef = `gamma ; sum (a)->total_a (R)`; + + assert.deepEqual(exec_sql(query).getResult(), exec_ra(queryRef).getResult()); +}); + +QUnit.test('whitespace(s) between count(*) function and opening parenthesis', function (assert) { + const query = ` + SELECT count (*) AS n + FROM R`; + const queryRef = `gamma ; count(*)->n (R)`; + + assert.deepEqual(exec_sql(query).getResult(), exec_ra(queryRef).getResult()); +}); + +QUnit.test('whitespace(s) between n-ary text function and opening parenthesis', function (assert) { + const query = ` + SELECT concat (a, b, c) AS k + FROM R`; + const queryRef = `pi concat(a, b, c)->k (R)`; + + assert.deepEqual(exec_sql(query).getResult(), exec_ra(queryRef).getResult()); +}); + +QUnit.test('whitespace(s) between binary function and opening parenthesis', function (assert) { + const query = ` + SELECT add (a, 5) AS a_plus_5 + FROM R`; + const queryRef = `pi add(a, 5)->a_plus_5 (R)`; + + assert.deepEqual(exec_sql(query).getResult(), exec_ra(queryRef).getResult()); +}); + +QUnit.test('whitespace(s) between unary function and opening parenthesis', function (assert) { + const query = ` + SELECT a + length ( c ) AS x, upper ( b ) AS k + FROM R`; + const queryRef = `pi a + length(c)->x, upper(b)->k (R)`; + + assert.deepEqual(exec_sql(query).getResult(), exec_ra(queryRef).getResult()); +});