From 013eb629a20882b4db9729970d4bf9eb5c6e290c Mon Sep 17 00:00:00 2001 From: taozhi8833998 Date: Tue, 20 Aug 2024 20:28:04 +0800 Subject: [PATCH] fix: jsonb bug in pg --- pegjs/db2.pegjs | 7 ++--- pegjs/flinksql.pegjs | 7 ++--- pegjs/mysql.pegjs | 7 ++--- pegjs/noql.pegjs | 7 ++--- pegjs/postgresql.pegjs | 6 +--- pegjs/redshift.pegjs | 7 ++--- pegjs/snowflake.pegjs | 7 ++--- pegjs/sqlite.pegjs | 7 ++--- pegjs/trino.pegjs | 6 ++-- test/mysql-mariadb.spec.js | 6 ++-- test/postgres.spec.js | 64 ++++++++++++++++++++++++++++++++++++++ 11 files changed, 84 insertions(+), 47 deletions(-) diff --git a/pegjs/db2.pegjs b/pegjs/db2.pegjs index 4155d4e1..85873474 100644 --- a/pegjs/db2.pegjs +++ b/pegjs/db2.pegjs @@ -1826,11 +1826,8 @@ unary_operator = '!' / '-' / '+' / '~' jsonb_expr - = head:primary tail:(__ ('?|' / '?&' / '?' / '#-' / '#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW) __ primary)* { - if (!tail || tail.length === 0) return head - return createBinaryExprChain(head, tail) - } - / head:primary tail:(__ ('@>' / '<@') __ primary)* { + = head:primary __ tail: (__ ('?|' / '?&' / '?' / '#-' / '#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW / '@>' / '<@') __ primary)* { + // => primary | binary_expr if (!tail || tail.length === 0) return head return createBinaryExprChain(head, tail) } diff --git a/pegjs/flinksql.pegjs b/pegjs/flinksql.pegjs index 63f0a6d8..f1ece0d5 100644 --- a/pegjs/flinksql.pegjs +++ b/pegjs/flinksql.pegjs @@ -2629,11 +2629,8 @@ unary_operator = '!' / '-' / '+' / '~' jsonb_expr - = head:primary tail:(__ ('?|' / '?&' / '?' / '#-' / '#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW) __ primary)* { - if (!tail || tail.length === 0) return head - return createBinaryExprChain(head, tail) - } - / head:primary tail:(__ ('@>' / '<@') __ primary)* { + = head:primary __ tail: (__ ('?|' / '?&' / '?' / '#-' / '#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW / '@>' / '<@') __ primary)* { + // => primary | binary_expr if (!tail || tail.length === 0) return head return createBinaryExprChain(head, tail) } diff --git a/pegjs/mysql.pegjs b/pegjs/mysql.pegjs index 6538d180..66c28ebb 100644 --- a/pegjs/mysql.pegjs +++ b/pegjs/mysql.pegjs @@ -3068,11 +3068,8 @@ unary_operator = '!' / '-' / '+' / '~' jsonb_expr - = head:primary tail:(__ ('?|' / '?&' / '?' / '#-' / '#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW) __ primary)* { - if (!tail || tail.length === 0) return head - return createBinaryExprChain(head, tail) - } - / head:primary tail:(__ ('@>' / '<@') __ primary)* { + = head:primary __ tail: (__ ('?|' / '?&' / '?' / '#-' / '#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW / '@>' / '<@') __ primary)* { + // => primary | binary_expr if (!tail || tail.length === 0) return head return createBinaryExprChain(head, tail) } diff --git a/pegjs/noql.pegjs b/pegjs/noql.pegjs index f9de2d4b..46c12d31 100644 --- a/pegjs/noql.pegjs +++ b/pegjs/noql.pegjs @@ -3934,11 +3934,8 @@ unary_operator = '!' / '-' / '+' / '~' jsonb_expr - = head:primary tail:(__ ('?|' / '?&' / '?' / '#-' / '#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW) __ primary)* { - if (!tail || tail.length === 0) return head - return createBinaryExprChain(head, tail) - } - / head:primary tail:(__ ('@>' / '<@') __ primary)* { + = head:primary __ tail: (__ ('?|' / '?&' / '?' / '#-' / '#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW / '@>' / '<@') __ primary)* { + // => primary | binary_expr if (!tail || tail.length === 0) return head return createBinaryExprChain(head, tail) } diff --git a/pegjs/postgresql.pegjs b/pegjs/postgresql.pegjs index 75f186c3..641d7125 100644 --- a/pegjs/postgresql.pegjs +++ b/pegjs/postgresql.pegjs @@ -4294,11 +4294,7 @@ unary_operator = '!' / '-' / '+' / '~' jsonb_expr - = head:primary __ tail: (__ ('@>' / '<@') __ primary)+ { - // => binary_expr - return createBinaryExprChain(head, tail) - } - / head:primary __ tail: (__ ('?|' / '?&' / '?' / '#-' / '#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW) __ primary)* { + = head:primary __ tail: (__ ('?|' / '?&' / '?' / '#-' / '#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW / '@>' / '<@') __ primary)* { // => primary | binary_expr if (!tail || tail.length === 0) return head return createBinaryExprChain(head, tail) diff --git a/pegjs/redshift.pegjs b/pegjs/redshift.pegjs index f057c789..bbbb7552 100644 --- a/pegjs/redshift.pegjs +++ b/pegjs/redshift.pegjs @@ -3974,11 +3974,8 @@ unary_operator = '!' / '-' / '+' / '~' jsonb_expr - = head:primary tail:(__ ('?|' / '?&' / '?' / '#-' / '#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW) __ primary)* { - if (!tail || tail.length === 0) return head - return createBinaryExprChain(head, tail) - } - / head:primary tail:(__ ('@>' / '<@') __ primary)* { + = head:primary __ tail: (__ ('?|' / '?&' / '?' / '#-' / '#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW / '@>' / '<@') __ primary)* { + // => primary | binary_expr if (!tail || tail.length === 0) return head return createBinaryExprChain(head, tail) } diff --git a/pegjs/snowflake.pegjs b/pegjs/snowflake.pegjs index 2c78905b..c7984ff1 100644 --- a/pegjs/snowflake.pegjs +++ b/pegjs/snowflake.pegjs @@ -3400,11 +3400,8 @@ unary_operator = '!' / '-' / '+' / '~' jsonb_expr - = head:primary tail:(__ ('?|' / '?&' / '?' / '#-' / '#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW) __ primary)* { - if (!tail || tail.length === 0) return head - return createBinaryExprChain(head, tail) - } - / head:primary tail:(__ ('@>' / '<@') __ primary)* { + = head:primary __ tail: (__ ('?|' / '?&' / '?' / '#-' / '#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW / '@>' / '<@') __ primary)* { + // => primary | binary_expr if (!tail || tail.length === 0) return head return createBinaryExprChain(head, tail) } diff --git a/pegjs/sqlite.pegjs b/pegjs/sqlite.pegjs index cdb1cd6c..1b8307ea 100644 --- a/pegjs/sqlite.pegjs +++ b/pegjs/sqlite.pegjs @@ -2158,11 +2158,8 @@ unary_operator = '!' / '-' / '+' / '~' jsonb_expr - = head:primary tail:(__ ('?|' / '?&' / '?' / '#-' / '#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW) __ primary)* { - if (!tail || tail.length === 0) return head - return createBinaryExprChain(head, tail) - } - / head:primary tail:(__ ('@>' / '<@') __ primary)* { + = head:primary __ tail: (__ ('?|' / '?&' / '?' / '#-' / '#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW / '@>' / '<@') __ primary)* { + // => primary | binary_expr if (!tail || tail.length === 0) return head return createBinaryExprChain(head, tail) } diff --git a/pegjs/trino.pegjs b/pegjs/trino.pegjs index 6dbaaf4d..81a7f42d 100644 --- a/pegjs/trino.pegjs +++ b/pegjs/trino.pegjs @@ -3383,13 +3383,11 @@ unary_operator = '!' / '-' / '+' / '~' jsonb_expr - = head:primary __ tail: (__ ('?|' / '?&' / '?' / '#-' / '#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW) __ primary)* { + = head:primary __ tail: (__ ('?|' / '?&' / '?' / '#-' / '#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW / '@>' / '<@') __ primary)* { + // => primary | binary_expr if (!tail || tail.length === 0) return head return createBinaryExprChain(head, tail) } - / head:primary __ tail: (__ ('@>' / '<@') __ primary)+ { - return createBinaryExprChain(head, tail) - } string_constants_escape = 'E'i"'" __ n:single_char* __ "'" { diff --git a/test/mysql-mariadb.spec.js b/test/mysql-mariadb.spec.js index 2aabc57d..97dd425b 100644 --- a/test/mysql-mariadb.spec.js +++ b/test/mysql-mariadb.spec.js @@ -1107,10 +1107,10 @@ describe('mysql', () => { it('should throw error when args is not right', () => { let sql = `select convert(json_unquote(json_extract('{"thing": "252"}', "$.thing")));` - expect(parser.astify.bind(parser, sql)).to.throw('Expected "!=", "#", "#-", "#>", "#>>", "%", "&", "&&", "*", "+", ",", "-", "--", "->", "->>", "/", "/*", "<", "<<", "<=", "<>", "=", ">", ">=", ">>", "?", "?&", "?|", "AND", "BETWEEN", "IN", "IS", "LIKE", "NOT", "ON", "OR", "OVER", "REGEXP", "RLIKE", "USING", "XOR", "^", "div", "|", "||", or [ \\t\\n\\r] but ")" found.') - expect(parser.astify.bind(parser, 'select convert("");')).to.throw('Expected "!=", "#", "#-", "#>", "#>>", "%", "&", "&&", "*", "+", ",", "-", "--", "->", "->>", "/", "/*", "<", "<<", "<=", "<>", "=", ">", ">=", ">>", "?", "?&", "?|", "AND", "BETWEEN", "COLLATE", "IN", "IS", "LIKE", "NOT", "OR", "REGEXP", "RLIKE", "USING", "XOR", "^", "div", "|", "||", or [ \\t\\n\\r] but ")" found.') + expect(parser.astify.bind(parser, sql)).to.throw('Expected "!=", "#", "#-", "#>", "#>>", "%", "&", "&&", "*", "+", ",", "-", "--", "->", "->>", "/", "/*", "<", "<<", "<=", "<>", "<@", "=", ">", ">=", ">>", "?", "?&", "?|", "@>", "AND", "BETWEEN", "IN", "IS", "LIKE", "NOT", "ON", "OR", "OVER", "REGEXP", "RLIKE", "USING", "XOR", "^", "div", "|", "||", or [ \\t\\n\\r] but ")" found.') + expect(parser.astify.bind(parser, 'select convert("");')).to.throw('Expected "!=", "#", "#-", "#>", "#>>", "%", "&", "&&", "*", "+", ",", "-", "--", "->", "->>", "/", "/*", "<", "<<", "<=", "<>", "<@", "=", ">", ">=", ">>", "?", "?&", "?|", "@>", "AND", "BETWEEN", "COLLATE", "IN", "IS", "LIKE", "NOT", "OR", "REGEXP", "RLIKE", "USING", "XOR", "^", "div", "|", "||", or [ \\t\\n\\r] but ")" found.') sql = 'SELECT AVG(Quantity,age) FROM table1;' - expect(parser.astify.bind(parser, sql)).to.throw('Expected "!=", "#", "#-", "#>", "#>>", "%", "&", "&&", "(", ")", "*", "+", "-", "--", "->", "->>", ".", "/", "/*", "<", "<<", "<=", "<>", "=", ">", ">=", ">>", "?", "?&", "?|", "BETWEEN", "IN", "IS", "LIKE", "NOT", "REGEXP", "RLIKE", "XOR", "^", "div", "|", "||", [ \\t\\n\\r], [A-Za-z0-9_$\\x80-￿], or [A-Za-z0-9_:] but "," found.') + expect(parser.astify.bind(parser, sql)).to.throw('Expected "!=", "#", "#-", "#>", "#>>", "%", "&", "&&", "(", ")", "*", "+", "-", "--", "->", "->>", ".", "/", "/*", "<", "<<", "<=", "<>", "<@", "=", ">", ">=", ">>", "?", "?&", "?|", "@>", "BETWEEN", "IN", "IS", "LIKE", "NOT", "REGEXP", "RLIKE", "XOR", "^", "div", "|", "||", [ \\t\\n\\r], [A-Za-z0-9_$\\x80-￿], or [A-Za-z0-9_:] but "," found.') }) it('should join multiple table with comma', () => { diff --git a/test/postgres.spec.js b/test/postgres.spec.js index ce8affb9..2d117372 100644 --- a/test/postgres.spec.js +++ b/test/postgres.spec.js @@ -1974,4 +1974,68 @@ describe('Postgres', () => { expect(fun).to.throw(`Expected "--", "/*", "\\"", [ \\t\\n\\r], or [A-Za-z_一-龥] but "'" found.`) }) }) + describe('pg parse speed', function () { + this.timeout(30) + const sql = `SELECT + "pr"."destination_currency" AS "currency", + "pr"."idempotency_key" AS "unqiueRequestId", + "pr"."status" AS "paymentRequestStatus", + "pr"."payment_date" AS "paymentDate", + "pr"."provider_system_reference_number" AS "providerSystemReferenceNumber", + "pr"."destination_amount" AS "destinationAmount", + "pr"."error" AS "error", + "pr"."source_id" AS "sourceId", + "pr"."source_type" AS "sourceType", + "pr"."client_legal_entity_id" AS "clientLegalEntityId", + "pr"."beneficiary_legal_entity_id" AS "beneficiaryLegalEntityId", + "pr"."provider" AS "provider", + "txn"."created_at" AS "transactionCreatedAt", + "txn"."updated_at" AS "transactionUpdatedAt", + "txn"."provider_metadata" AS "providerMetadata", + "txn"."currency" AS "currency", + "txn"."amount" AS "amount", + "txn"."status" AS "status", + "txn"."type" AS "txnType", + "txn"."purpose_of_payment" AS "purposeOfPayment", + "txn"."client_reference" AS "clientReference", + "txn"."description" AS "transactionDescription", + pr.meta -> 'invoiceIds' AS "invoiceIds" + FROM + "public"."payment_request" "pr" + LEFT JOIN "public"."transaction" "txn" ON "txn"."payment_request_id" = "pr"."id" + WHERE + "pr"."source_id" IN ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34, $35, $36, $37, $38, $39, $40, $41, $42, $43, $44, $45, $46, $47, $48, $49, $50) + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + OR pr.meta::jsonb -> 'invoiceIds' @> '["c937cd8c-65bc-4006-9413-dde7b43c61b6"]' + ORDER BY + "pr"."created_at" DESC` + const ast = parser.astify(sql, opt) + expect(ast).to.be.an('object') + }) })