From a62f73e7b5686d2989125396fb6623f17007ef73 Mon Sep 17 00:00:00 2001
From: taozhi8833998 <taozhi8833998@163.com>
Date: Fri, 19 Jul 2024 15:35:27 +0800
Subject: [PATCH 1/2] feat: support json and jsonb operator in all db

---
 pegjs/db2.pegjs            | 24 ++++++++++++--
 pegjs/flinksql.pegjs       | 23 +++++++++-----
 pegjs/mysql.pegjs          | 23 ++++++++++++--
 pegjs/noql.pegjs           | 62 +++++++++++++-----------------------
 pegjs/postgresql.pegjs     | 48 ++++++++++++++--------------
 pegjs/redshift.pegjs       | 62 +++++++++++++-----------------------
 pegjs/snowflake.pegjs      | 64 +++++++++++++-------------------------
 pegjs/sqlite.pegjs         | 23 ++++++++++++--
 pegjs/trino.pegjs          | 62 +++++++++++++-----------------------
 src/column.js              |  7 +++--
 src/expr.js                |  4 ++-
 src/func.js                | 17 ++++++++--
 test/mysql-mariadb.spec.js |  2 +-
 test/postgres.spec.js      | 12 +++++--
 14 files changed, 216 insertions(+), 217 deletions(-)

diff --git a/pegjs/db2.pegjs b/pegjs/db2.pegjs
index ea544fab..7a96402d 100644
--- a/pegjs/db2.pegjs
+++ b/pegjs/db2.pegjs
@@ -1728,6 +1728,7 @@ comparison_op_right
   / between_op_right
   / is_op_right
   / like_op_right
+  / jsonb_or_json_op_right
 
 arithmetic_op_right
   = l:(__ arithmetic_comparison_operator __ additive_expr)+ {
@@ -1781,6 +1782,24 @@ in_op_right
       return { op: op, right: e };
     }
 
+jsonb_or_json_op_right
+  = s: ('@>' / '<@' / '?|' / '?&' / '?' / '#-') __  e:expr {
+    // => { op: string; right: expr }
+    return {
+      type: 'jsonb',
+      op: s,
+      right: { type: 'expr', expr: e }
+    }
+  }
+  / s: ('#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW) __ e:expr {
+    // => { op: string; right: expr }
+    return {
+      type: 'json',
+      op: s,
+      right: { type: 'expr', expr: e }
+    }
+  }
+
 additive_expr
   = head:multiplicative_expr
     tail:(__ additive_operator  __ multiplicative_expr)* {
@@ -1826,15 +1845,14 @@ unary_operator
   = '!' / '-' / '+' / '~'
 
 column_ref
-  = tbl:(ident __ DOT __)? col:column __ a:((DOUBLE_ARROW / SINGLE_ARROW) __ (literal_string / literal_numeric))+ {
+  = tbl:(ident __ DOT __)? col:column __ jo:jsonb_or_json_op_right+ {
       const tableName = tbl && tbl[0] || null
       columnList.add(`select::${tableName}::${col}`);
       return {
         type: 'column_ref',
         table: tableName,
         column: col,
-        arrows: a.map(item => item[0]),
-        properties: a.map(item => item[2])
+        jsonb: jo,
       };
   }
   / tbl:ident __ DOT __ col:column_without_kw {
diff --git a/pegjs/flinksql.pegjs b/pegjs/flinksql.pegjs
index 9088f76a..1282209e 100644
--- a/pegjs/flinksql.pegjs
+++ b/pegjs/flinksql.pegjs
@@ -2469,7 +2469,7 @@ comparison_op_right
   / is_op_right
   / like_op_right
   / similar_to_op_right
-  / jsonb_op_right
+  / jsonb_or_json_op_right
 
 arithmetic_op_right
   = l:(__ arithmetic_comparison_operator __ additive_expr)+ {
@@ -2576,13 +2576,21 @@ exists_op_right
       return { op: op, right: l };
     }
 
-jsonb_op_right
-  = s: ('@>' / '<@' / OPERATOR_CONCATENATION / DOUBLE_WELL_ARROW / WELL_ARROW / '?' / '?|' / '?&' / '#-') __
-  c:column_list_item {
+jsonb_or_json_op_right
+  = s: ('@>' / '<@' / '?|' / '?&' / '?' / '#-') __  e:expr {
     // => { op: string; right: expr }
     return {
+      type: 'jsonb',
       op: s,
-      right: c && c.expr || c
+      right: { type: 'expr', expr: e }
+    }
+  }
+  / s: ('#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW) __ e:expr {
+    // => { op: string; right: expr }
+    return {
+      type: 'json',
+      op: s,
+      right: { type: 'expr', expr: e }
     }
   }
 
@@ -2682,7 +2690,7 @@ column_ref
           column: '*'
       }
     }
-  / tbl:(ident __ DOT)? __ col:column __ a:((DOUBLE_ARROW / SINGLE_ARROW) __ (literal_string / literal_numeric))+ {
+  / tbl:(ident __ DOT)? __ col:column __ jo:jsonb_or_json_op_right+ {
     // => IGNORE
       const tableName = tbl && tbl[0] || null
       columnList.add(`select::${tableName}::${col}`);
@@ -2690,8 +2698,7 @@ column_ref
         type: 'column_ref',
         table: tableName,
         column: col,
-        arrows: a.map(item => item[0]),
-        properties: a.map(item => item[2])
+        jsonb: jo,
       };
   }
   / tbl:ident __ DOT __ col:column {
diff --git a/pegjs/mysql.pegjs b/pegjs/mysql.pegjs
index 94e4f7c1..912125be 100644
--- a/pegjs/mysql.pegjs
+++ b/pegjs/mysql.pegjs
@@ -3034,6 +3034,24 @@ in_op_right
       return { op: op, right: e };
     }
 
+jsonb_or_json_op_right
+  = s: ('@>' / '<@' / '?|' / '?&' / '?' / '#-') __  e:expr {
+    // => { op: string; right: expr }
+    return {
+      type: 'jsonb',
+      op: s,
+      right: { type: 'expr', expr: e }
+    }
+  }
+  / s: ('#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW) __ e:expr {
+    // => { op: string; right: expr }
+    return {
+      type: 'json',
+      op: s,
+      right: { type: 'expr', expr: e }
+    }
+  }
+
 additive_expr
   = head: multiplicative_expr
     tail:(__ additive_operator  __ multiplicative_expr)* {
@@ -3090,15 +3108,14 @@ primary
   }
 
 column_ref
-  = tbl:(ident __ DOT __)? col:column __ a:((DOUBLE_ARROW / SINGLE_ARROW) __ literal)+ {
+  = tbl:(ident __ DOT __)? col:column __ jo:jsonb_or_json_op_right+ {
       const tableName = tbl && tbl[0] || null
       columnList.add(`select::${tableName}::${col}`);
       return {
         type: 'column_ref',
         table: tableName,
         column: col,
-        arrows: a.map(item => item[0]),
-        properties: a.map(item => item[2]),
+        jsonb: jo,
         ...getLocationObject(),
       };
   }
diff --git a/pegjs/noql.pegjs b/pegjs/noql.pegjs
index a574218a..75d21c71 100644
--- a/pegjs/noql.pegjs
+++ b/pegjs/noql.pegjs
@@ -2836,8 +2836,7 @@ column_list_item
     // => { expr: expr; as: null; }
     return { expr: c, as: null }
   }
-  / e:expr_item __ s:KW_DOUBLE_COLON __ t:cast_data_type __ a:((DOUBLE_ARROW / SINGLE_ARROW) __ (literal_string / literal_numeric))* __ tail:(__ (additive_operator / multiplicative_operator) __ expr_item)* __ alias:alias_clause? {
-    // => { type: 'cast'; expr: expr; symbol: '::'; target: cast_data_type;  as?: null; arrows?: ('->>' | '->')[]; property?: (literal_string | literal_numeric)[]; }
+  / e:expr_item __ s:KW_DOUBLE_COLON __ t:cast_data_type __ jo:jsonb_or_json_op_right* __ tail:(__ (additive_operator / multiplicative_operator) __ expr_item)* __ alias:alias_clause? {
     return {
       as: alias,
       type: 'cast',
@@ -2845,8 +2844,7 @@ column_list_item
       symbol: '::',
       target: t,
       tail: tail && tail[0] && { operator: tail[0][1], expr: tail[0][3] },
-      arrows: a.map(item => item[0]),
-      properties: a.map(item => item[2]),
+      jsonb: jo,
     }
   }
   / tbl:ident __ DOT pro:(ident __ DOT)? __ STAR {
@@ -3786,7 +3784,7 @@ comparison_op_right
   / between_op_right
   / is_op_right
   / like_op_right
-  / jsonb_op_right
+  / jsonb_or_json_op_right
   / regex_op_right
 
 arithmetic_op_right
@@ -3886,13 +3884,21 @@ in_op_right
       return { op: op, right: e };
     }
 
-jsonb_op_right
-  = s: ('@>' / '<@' / OPERATOR_CONCATENATION / DOUBLE_WELL_ARROW / WELL_ARROW / '?' / '?|' / '?&' / '#-') __
-  c:column_list_item {
+jsonb_or_json_op_right
+  = s: ('@>' / '<@' / '?|' / '?&' / '?' / '#-') __  e:expr_item {
     // => { op: string; right: expr }
     return {
+      type: 'jsonb',
       op: s,
-      right: c && c.expr || c
+      right: { type: 'expr', expr: e }
+    }
+  }
+  / s: ('#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW) __ e:expr_item {
+    // => { op: string; right: expr }
+    return {
+      type: 'json',
+      op: s,
+      right: { type: 'expr', expr: e }
     }
   }
 
@@ -3970,7 +3976,7 @@ column_ref
           column: '*'
       }
     }
-  / tbl:(ident __ DOT)? __ col:column __ a:((DOUBLE_ARROW / SINGLE_ARROW) __ (literal_string / literal_numeric))+ {
+  / tbl:(ident __ DOT)? __ col:column __ jo:jsonb_or_json_op_right+ {
     // => IGNORE
       const tableName = tbl && tbl[0] || null
       columnList.add(`select::${tableName}::${col}`)
@@ -3978,19 +3984,10 @@ column_ref
         type: 'column_ref',
         table: tableName,
         column: col,
-        arrows: a.map(item => item[0]),
-        properties: a.map(item => item[2])
+        jsonb: jo,
       };
   }
   / schema:ident tbl:(__ DOT __ ident) col:(__ DOT __ column) {
-    /* => {
-        type: 'column_ref';
-        schema: string;
-        table: string;
-        column: column | '*';
-        arrows?: ('->>' | '->')[];
-        property?: (literal_string | literal_numeric)[];
-      } */
       columnList.add(`select::${schema}.${tbl[3]}::${col[3]}`);
       return {
         type: 'column_ref',
@@ -4000,13 +3997,6 @@ column_ref
       };
     }
   / tbl:ident __ DOT __ col:column {
-      /* => {
-        type: 'column_ref';
-        table: ident;
-        column: column | '*';
-        arrows?: ('->>' | '->')[];
-        property?: (literal_string | literal_numeric)[];
-      } */
       columnList.add(`select::${tbl}::${col}`);
       return {
         type: 'column_ref',
@@ -4461,25 +4451,16 @@ scalar_func
   / "NTILE"i
 
 cast_double_colon
-  = s:KW_DOUBLE_COLON __ t:data_type __ a:((DOUBLE_ARROW / SINGLE_ARROW) __ (literal_string / literal_numeric))* __ alias:alias_clause? {
-    /* => {
-        as?: alias_clause,
-        symbol: '::' | 'as',
-        target: data_type;
-        arrows?: ('->>' | '->')[];
-        property?: (literal_string | literal_numeric)[];
-      }
-      */
+  = s:KW_DOUBLE_COLON __ t:data_type __ jo:jsonb_or_json_op_right* __ alias:alias_clause? {
     return {
       as: alias,
       symbol: '::',
       target: t,
-      arrows: a.map(item => item[0]),
-      properties: a.map(item => item[2]),
+      jsonb: jo,
     }
   }
 cast_expr
-  = c:KW_CAST __ LPAREN __ e:expr __ KW_AS __ t:data_type __ RPAREN __ a:((DOUBLE_ARROW / SINGLE_ARROW) __ (literal_string / literal_numeric))*  {
+  = c:KW_CAST __ LPAREN __ e:expr __ KW_AS __ t:data_type __ RPAREN __ jo:jsonb_or_json_op_right*  {
     // => IGNORE
     return {
       type: 'cast',
@@ -4487,8 +4468,7 @@ cast_expr
       expr: e,
       symbol: 'as',
       target: t,
-      arrows: a.map(item => item[0]),
-      properties: a.map(item => item[2]),
+      jsonb: jo,
     };
   }
   / c:KW_CAST __ LPAREN __ e:expr __ KW_AS __ KW_DECIMAL __ LPAREN __ precision:int __ RPAREN __ RPAREN {
diff --git a/pegjs/postgresql.pegjs b/pegjs/postgresql.pegjs
index 342f31d3..cca02a47 100644
--- a/pegjs/postgresql.pegjs
+++ b/pegjs/postgresql.pegjs
@@ -3145,8 +3145,8 @@ column_list_item
     // => { expr: expr; as: null; }
     return { expr: c, as: null }
   }
-  / e:(column_ref_quoted / expr_item) __ s:KW_DOUBLE_COLON __ t:cast_data_type __ a:((DOUBLE_ARROW / SINGLE_ARROW) __ (literal_string / literal_numeric))* __ tail:(__ (additive_operator / multiplicative_operator) __ expr_item)* __ alias:alias_clause? {
-    // => { type: 'cast'; expr: expr; symbol: '::'; target: cast_data_type;  as?: null; arrows?: ('->>' | '->')[]; property?: (literal_string | literal_numeric)[]; }
+  / e:(column_ref_quoted / expr_item) __ s:KW_DOUBLE_COLON __ t:cast_data_type __ jo:jsonb_or_json_op_right* __ tail:(__ (additive_operator / multiplicative_operator) __ expr_item)* __ alias:alias_clause? {
+    // => { type: 'cast'; expr: expr; symbol: '::'; target: cast_data_type;  as?: null; jsonb?: jsonb_or_json_op_right[]; }
     return {
       as: alias,
       type: 'cast',
@@ -3154,8 +3154,7 @@ column_list_item
       symbol: '::',
       target: t,
       tail: tail && tail[0] && { operator: tail[0][1], expr: tail[0][3] },
-      arrows: a.map(item => item[0]),
-      properties: a.map(item => item[2]),
+      jsonb: jo,
     }
   }
   / tbl:ident_type __ DOT pro:(ident_type __ DOT)? __ STAR {
@@ -4127,7 +4126,7 @@ comparison_op_right
   / between_op_right
   / is_op_right
   / like_op_right
-  / jsonb_op_right
+  / jsonb_or_json_op_right
   / regex_op_right
 
 arithmetic_op_right
@@ -4227,13 +4226,21 @@ in_op_right
       return { op: op, right: e };
     }
 
-jsonb_op_right
-  = s: ('@>' / '<@' / OPERATOR_CONCATENATION / DOUBLE_WELL_ARROW / WELL_ARROW / '?' / '?|' / '?&' / '#-') __
-  c:column_list_item {
+jsonb_or_json_op_right
+  = s: ('@>' / '<@' / '?|' / '?&' / '?' / '#-') __  e:expr_item {
     // => { op: string; right: expr }
     return {
+      type: 'jsonb',
       op: s,
-      right: c && c.expr || c
+      right: { type: 'expr', expr: e }
+    }
+  }
+  / s: ('#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW) __ e:expr_item {
+    // => { op: string; right: expr }
+    return {
+      type: 'json',
+      op: s,
+      right: { type: 'expr', expr: e }
     }
   }
 
@@ -4311,7 +4318,7 @@ column_ref
           column: '*'
       }
     }
-  / tbl:(ident __ DOT)? __ col:column_type __ a:((DOUBLE_ARROW / SINGLE_ARROW) __ (literal_string / literal_numeric))+ {
+  / tbl:(ident __ DOT)? __ col:column_type __ jo:jsonb_or_json_op_right+ {
     // => IGNORE
       const tableName = tbl && tbl[0] || null
       columnList.add(`select::${tableName}::${col.value}`)
@@ -4319,8 +4326,7 @@ column_ref
         type: 'column_ref',
         table: tableName,
         column: { expr: col },
-        arrows: a.map(item => item[0]),
-        properties: a.map(item => item[2])
+        jsonb: jo,
       };
   }
   / schema:ident tbl:(__ DOT __ ident) col:(__ DOT __ column_type) {
@@ -4329,8 +4335,7 @@ column_ref
         schema: string;
         table: string;
         column: column | '*';
-        arrows?: ('->>' | '->')[];
-        property?: (literal_string | literal_numeric)[];
+        jsonb?: jsonb_or_json_op_right[];
       } */
       columnList.add(`select::${schema}.${tbl[3]}::${col[3].value}`);
       return {
@@ -4345,8 +4350,6 @@ column_ref
         type: 'column_ref';
         table: ident;
         column: column | '*';
-        arrows?: ('->>' | '->')[];
-        property?: (literal_string | literal_numeric)[];
       } */
       columnList.add(`select::${tbl}::${col.value}`);
       return {
@@ -4830,25 +4833,23 @@ scalar_func
   / "NTILE"i
 
 cast_double_colon
-  = s:KW_DOUBLE_COLON __ t:data_type __ a:((DOUBLE_ARROW / SINGLE_ARROW) __ (literal_string / literal_numeric))* __ alias:alias_clause? {
+  = s:KW_DOUBLE_COLON __ t:data_type __ jo:jsonb_or_json_op_right* __ alias:alias_clause? {
     /* => {
         as?: alias_clause,
         symbol: '::' | 'as',
         target: data_type;
-        arrows?: ('->>' | '->')[];
-        property?: (literal_string | literal_numeric)[];
+        jsonb?: jsonb_or_json_op_right[];
       }
       */
     return {
       as: alias,
       symbol: '::',
       target: t,
-      arrows: a.map(item => item[0]),
-      properties: a.map(item => item[2]),
+      jsonb: jo
     }
   }
 cast_expr
-  = c:KW_CAST __ LPAREN __ e:expr __ KW_AS __ t:data_type __ RPAREN __ a:((DOUBLE_ARROW / SINGLE_ARROW) __ (literal_string / literal_numeric))*  {
+  = c:KW_CAST __ LPAREN __ e:expr __ KW_AS __ t:data_type __ RPAREN __ jo:jsonb_or_json_op_right*  {
     // => IGNORE
     return {
       type: 'cast',
@@ -4856,8 +4857,7 @@ cast_expr
       expr: e,
       symbol: 'as',
       target: t,
-      arrows: a.map(item => item[0]),
-      properties: a.map(item => item[2]),
+      jsonb: jo
     };
   }
   / c:KW_CAST __ LPAREN __ e:expr __ KW_AS __ KW_DECIMAL __ LPAREN __ precision:int __ RPAREN __ RPAREN {
diff --git a/pegjs/redshift.pegjs b/pegjs/redshift.pegjs
index 6ad2cfd8..38bb1987 100644
--- a/pegjs/redshift.pegjs
+++ b/pegjs/redshift.pegjs
@@ -2875,8 +2875,7 @@ column_list_item
     // => { expr: expr; as: null; }
     return { expr: c, as: null }
   }
-  / e:(column_ref_quoted / expr_item) __ s:KW_DOUBLE_COLON __ t:cast_data_type __ a:((DOUBLE_ARROW / SINGLE_ARROW) __ (literal_string / literal_numeric))* __ tail:(__ (additive_operator / multiplicative_operator) __ expr_item)* __ alias:alias_clause? {
-    // => { type: 'cast'; expr: expr; symbol: '::'; target: cast_data_type;  as?: null; arrows?: ('->>' | '->')[]; property?: (literal_string | literal_numeric)[]; }
+  / e:(column_ref_quoted / expr_item) __ s:KW_DOUBLE_COLON __ t:cast_data_type __ jo:jsonb_or_json_op_right* __ tail:(__ (additive_operator / multiplicative_operator) __ expr_item)* __ alias:alias_clause? {
     return {
       as: alias,
       type: 'cast',
@@ -2884,8 +2883,7 @@ column_list_item
       symbol: '::',
       target: t,
       tail: tail && tail[0] && { operator: tail[0][1], expr: tail[0][3] },
-      arrows: a.map(item => item[0]),
-      properties: a.map(item => item[2]),
+      jsonb: jo,
     }
   }
   / tbl:ident_type __ DOT pro:(ident_type __ DOT)? __ STAR {
@@ -3826,7 +3824,7 @@ comparison_op_right
   / between_op_right
   / is_op_right
   / like_op_right
-  / jsonb_op_right
+  / jsonb_or_json_op_right
   / regex_op_right
 
 arithmetic_op_right
@@ -3926,13 +3924,21 @@ in_op_right
       return { op: op, right: e };
     }
 
-jsonb_op_right
-  = s: ('@>' / '<@' / OPERATOR_CONCATENATION / DOUBLE_WELL_ARROW / WELL_ARROW / '?' / '?|' / '?&' / '#-') __
-  c:column_list_item {
+jsonb_or_json_op_right
+  = s: ('@>' / '<@' / '?|' / '?&' / '?' / '#-') __  e:expr_item {
     // => { op: string; right: expr }
     return {
+      type: 'jsonb',
       op: s,
-      right: c && c.expr || c
+      right: { type: 'expr', expr: e }
+    }
+  }
+  / s: ('#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW) __ e:expr_item {
+    // => { op: string; right: expr }
+    return {
+      type: 'json',
+      op: s,
+      right: { type: 'expr', expr: e }
     }
   }
 
@@ -4010,7 +4016,7 @@ column_ref
           column: '*'
       }
     }
-  / tbl:(ident __ DOT)? __ col:column_type __ a:((DOUBLE_ARROW / SINGLE_ARROW) __ (literal_string / literal_numeric))+ {
+  / tbl:(ident __ DOT)? __ col:column_type __ jo:jsonb_or_json_op_right+ {
     // => IGNORE
       const tableName = tbl && tbl[0] || null
       columnList.add(`select::${tableName}::${col.value}`)
@@ -4018,19 +4024,10 @@ column_ref
         type: 'column_ref',
         table: tableName,
         column: { expr: col },
-        arrows: a.map(item => item[0]),
-        properties: a.map(item => item[2])
+        jsonb: jo,
       };
   }
   / schema:ident tbl:(__ DOT __ ident) col:(__ DOT __ column_type) {
-    /* => {
-        type: 'column_ref';
-        schema: string;
-        table: string;
-        column: column | '*';
-        arrows?: ('->>' | '->')[];
-        property?: (literal_string | literal_numeric)[];
-      } */
       columnList.add(`select::${schema}.${tbl[3]}::${col[3].value}`);
       return {
         type: 'column_ref',
@@ -4040,13 +4037,6 @@ column_ref
       };
     }
   / tbl:ident __ DOT __ col:column_type {
-      /* => {
-        type: 'column_ref';
-        table: ident;
-        column: column | '*';
-        arrows?: ('->>' | '->')[];
-        property?: (literal_string | literal_numeric)[];
-      } */
       columnList.add(`select::${tbl}::${col.value}`);
       return {
         type: 'column_ref',
@@ -4529,25 +4519,16 @@ scalar_func
   / "NTILE"i
 
 cast_double_colon
-  = s:KW_DOUBLE_COLON __ t:data_type __ a:((DOUBLE_ARROW / SINGLE_ARROW) __ (literal_string / literal_numeric))* __ alias:alias_clause? {
-    /* => {
-        as?: alias_clause,
-        symbol: '::' | 'as',
-        target: data_type;
-        arrows?: ('->>' | '->')[];
-        property?: (literal_string | literal_numeric)[];
-      }
-      */
+  = s:KW_DOUBLE_COLON __ t:data_type __ jo:jsonb_or_json_op_right* __ alias:alias_clause? {
     return {
       as: alias,
       symbol: '::',
       target: t,
-      arrows: a.map(item => item[0]),
-      properties: a.map(item => item[2]),
+      jsonb: jo,
     }
   }
 cast_expr
-  = c:KW_CAST __ LPAREN __ e:expr __ KW_AS __ t:data_type __ RPAREN __ a:((DOUBLE_ARROW / SINGLE_ARROW) __ (literal_string / literal_numeric))*  {
+  = c:KW_CAST __ LPAREN __ e:expr __ KW_AS __ t:data_type __ RPAREN __ jo:jsonb_or_json_op_right*  {
     // => IGNORE
     return {
       type: 'cast',
@@ -4555,8 +4536,7 @@ cast_expr
       expr: e,
       symbol: 'as',
       target: t,
-      arrows: a.map(item => item[0]),
-      properties: a.map(item => item[2]),
+      jsonb: jo,
     };
   }
   / c:KW_CAST __ LPAREN __ e:expr __ KW_AS __ KW_DECIMAL __ LPAREN __ precision:int __ RPAREN __ RPAREN {
diff --git a/pegjs/snowflake.pegjs b/pegjs/snowflake.pegjs
index 886596c9..22f1c83a 100644
--- a/pegjs/snowflake.pegjs
+++ b/pegjs/snowflake.pegjs
@@ -2230,8 +2230,7 @@ column_list_item
     // => { expr: expr; as: null; }
     return { expr: c, as: null, ...getLocationObject(), }
   }
-  / e:expr_item __ s:KW_DOUBLE_COLON __ t:cast_data_type __ a:((DOUBLE_ARROW / SINGLE_ARROW) __ (literal_string / literal_numeric))* __ tail:(__ (additive_operator / multiplicative_operator) __ expr_item)* __ alias:alias_clause? {
-    // => { type: 'cast'; expr: expr; symbol: '::'; target: cast_data_type;  as?: null; arrows?: ('->>' | '->')[]; property?: (literal_string | literal_numeric)[]; }
+  / e:expr_item __ s:KW_DOUBLE_COLON __ t:cast_data_type __ jo:jsonb_or_json_op_right* __ tail:(__ (additive_operator / multiplicative_operator) __ expr_item)* __ alias:alias_clause? {
     return {
       as: alias,
       type: 'cast',
@@ -2239,8 +2238,7 @@ column_list_item
       symbol: '::',
       target: t,
       tail: tail && tail[0] && { operator: tail[0][1], expr: tail[0][3] },
-      arrows: a.map(item => item[0]),
-      properties: a.map(item => item[2]),
+      jsonb: jo,
       ...getLocationObject(),
     }
   }
@@ -3261,7 +3259,7 @@ comparison_op_right
   / between_op_right
   / is_op_right
   / like_op_right
-  / jsonb_op_right
+  / jsonb_or_json_op_right
   / regex_op_right
 
 arithmetic_op_right
@@ -3356,13 +3354,21 @@ in_op_right
       return { op: op, right: e };
     }
 
-jsonb_op_right
-  = s: ('@>' / '<@' / OPERATOR_CONCATENATION / DOUBLE_WELL_ARROW / WELL_ARROW / '?' / '?|' / '?&' / '#-') __
-  c:column_list_item {
+jsonb_or_json_op_right
+  = s: ('@>' / '<@' / '?|' / '?&' / '?' / '#-') __  e:expr_item {
     // => { op: string; right: expr }
     return {
+      type: 'jsonb',
       op: s,
-      right: c && c.expr || c
+      right: { type: 'expr', expr: e }
+    }
+  }
+  / s: ('#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW) __ e:expr_item {
+    // => { op: string; right: expr }
+    return {
+      type: 'json',
+      op: s,
+      right: { type: 'expr', expr: e }
     }
   }
 
@@ -3450,7 +3456,7 @@ column_ref
           ...getLocationObject()
       }
     }
-  / tbl:(ident __ column_symbol)? __ col:column __ a:((DOUBLE_ARROW / SINGLE_ARROW) __ (literal_string / literal_numeric))+ {
+  / tbl:(ident __ column_symbol)? __ col:column __ jo:jsonb_or_json_op_right+ {
     // => IGNORE
       const tableName = tbl && tbl[0] || null
       columnList.add(`select::${tableName}::${col}`)
@@ -3459,21 +3465,11 @@ column_ref
         table: tableName,
         column: col,
         notations: [tbl && tbl[2]],
-        arrows: a.map(item => item[0]),
-        properties: a.map(item => item[2]),
+        jsonb: jo,
         ...getLocationObject()
       };
   }
   / schema:ident tbl:(__ column_symbol __ ident) col:(__ column_symbol __ column) {
-    /* => {
-        type: 'column_ref';
-        schema: string;
-        table: string;
-        column: column | '*';
-        notations: string[];
-        arrows?: ('->>' | '->')[];
-        property?: (literal_string | literal_numeric)[];
-      } */
       columnList.add(`select::${schema}.${tbl[3]}::${col[3]}`);
       return {
         type: 'column_ref',
@@ -3485,14 +3481,6 @@ column_ref
       };
     }
   / tbl:ident __ s:column_symbol __ col:column {
-      /* => {
-        type: 'column_ref';
-        table: ident;
-        column: column | '*';
-        notations: string[];
-        arrows?: ('->>' | '->')[];
-        property?: (literal_string | literal_numeric)[];
-      } */
       columnList.add(`select::${tbl}::${col}`);
       return {
         type: 'column_ref',
@@ -4022,26 +4010,17 @@ scalar_func
   / "NTILE"i
 
 cast_double_colon
-  = s:KW_DOUBLE_COLON __ t:data_type __ a:((DOUBLE_ARROW / SINGLE_ARROW) __ (literal_string / literal_numeric))* __ alias:alias_clause? {
-    /* => {
-        as?: alias_clause,
-        symbol: '::' | 'as',
-        target: data_type;
-        arrows?: ('->>' | '->')[];
-        property?: (literal_string | literal_numeric)[];
-      }
-      */
+  = s:KW_DOUBLE_COLON __ t:data_type __ jo:jsonb_or_json_op_right* __ alias:alias_clause? {
     return {
       as: alias,
       symbol: '::',
       target: t,
-      arrows: a.map(item => item[0]),
-      properties: a.map(item => item[2]),
+      jsonb: jo,
       ...getLocationObject(),
     }
   }
 cast_expr
-  = c:KW_CAST __ LPAREN __ e:expr __ KW_AS __ t:data_type __ RPAREN __ a:((DOUBLE_ARROW / SINGLE_ARROW) __ (literal_string / literal_numeric))*  {
+  = c:KW_CAST __ LPAREN __ e:expr __ KW_AS __ t:data_type __ RPAREN __ jo:jsonb_or_json_op_right*  {
     // => IGNORE
     return {
       type: 'cast',
@@ -4049,8 +4028,7 @@ cast_expr
       expr: e,
       symbol: 'as',
       target: t,
-      arrows: a.map(item => item[0]),
-      properties: a.map(item => item[2]),
+      jsonb: jo,
     };
   }
   / c:KW_CAST __ LPAREN __ e:expr __ KW_AS __ KW_DECIMAL __ LPAREN __ precision:int __ RPAREN __ RPAREN {
diff --git a/pegjs/sqlite.pegjs b/pegjs/sqlite.pegjs
index f4d22390..a22a74af 100644
--- a/pegjs/sqlite.pegjs
+++ b/pegjs/sqlite.pegjs
@@ -2107,6 +2107,24 @@ in_op_right
       return { op: op, right: e };
     }
 
+jsonb_or_json_op_right
+  = s: ('@>' / '<@' / '?|' / '?&' / '?' / '#-') __  e:expr {
+    // => { op: string; right: expr }
+    return {
+      type: 'jsonb',
+      op: s,
+      right: { type: 'expr', expr: e }
+    }
+  }
+  / s: ('#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW) __ e:expr {
+    // => { op: string; right: expr }
+    return {
+      type: 'json',
+      op: s,
+      right: { type: 'expr', expr: e }
+    }
+  }
+
 additive_expr
   = head: multiplicative_expr
     tail:(__ additive_operator  __ multiplicative_expr)* {
@@ -2158,15 +2176,14 @@ unary_operator
   = '!' / '-' / '+' / '~'
 
 column_ref
-  = tbl:(ident __ DOT __)? col:column __ a:((DOUBLE_ARROW / SINGLE_ARROW) __ (literal_string / literal_numeric))+ {
+  = tbl:(ident __ DOT __)? col:column __ jo:jsonb_or_json_op_right+ {
       const tableName = tbl && tbl[0] || null
       columnList.add(`select::${tableName}::${col}`);
       return {
         type: 'column_ref',
         table: tableName,
         column: col,
-        arrows: a.map(item => item[0]),
-        properties: a.map(item => item[2])
+        jsonb: jo,
       };
   }
   / tbl:ident __ DOT __ col:column_without_kw {
diff --git a/pegjs/trino.pegjs b/pegjs/trino.pegjs
index ffc8d6c4..06ac65a2 100644
--- a/pegjs/trino.pegjs
+++ b/pegjs/trino.pegjs
@@ -2227,8 +2227,7 @@ column_list_item
     // => { expr: expr; as: null; }
     return { expr: c, as: null, ...getLocationObject(), }
   }
-  / e:expr_item __ s:KW_DOUBLE_COLON __ t:cast_data_type __ a:((DOUBLE_ARROW / SINGLE_ARROW) __ (literal_string / literal_numeric))* __ tail:(__ (additive_operator / multiplicative_operator) __ expr_item)* __ alias:alias_clause? {
-    // => { type: 'cast'; expr: expr; symbol: '::'; target: cast_data_type;  as?: null; arrows?: ('->>' | '->')[]; property?: (literal_string | literal_numeric)[]; }
+  / e:expr_item __ s:KW_DOUBLE_COLON __ t:cast_data_type __ jo:jsonb_or_json_op_right* __ tail:(__ (additive_operator / multiplicative_operator) __ expr_item)* __ alias:alias_clause? {
     return {
       as: alias,
       type: 'cast',
@@ -2236,8 +2235,7 @@ column_list_item
       symbol: '::',
       target: t,
       tail: tail && tail[0] && { operator: tail[0][1], expr: tail[0][3] },
-      arrows: a.map(item => item[0]),
-      properties: a.map(item => item[2]),
+      jsonb: jo,
       ...getLocationObject(),
     }
   }
@@ -3227,7 +3225,7 @@ comparison_op_right
   / between_op_right
   / is_op_right
   / like_op_right
-  / jsonb_op_right
+  / jsonb_or_json_op_right
   / regex_op_right
 
 arithmetic_op_right
@@ -3327,13 +3325,21 @@ in_op_right
       return { op: op, right: e };
     }
 
-jsonb_op_right
-  = s: ('@>' / '<@' / OPERATOR_CONCATENATION / DOUBLE_WELL_ARROW / WELL_ARROW / '?' / '?|' / '?&' / '#-') __
-  c:column_list_item {
+jsonb_or_json_op_right
+  = s: ('@>' / '<@' / '?|' / '?&' / '?' / '#-') __  e:expr_item {
     // => { op: string; right: expr }
     return {
+      type: 'jsonb',
       op: s,
-      right: c && c.expr || c
+      right: { type: 'expr', expr: e }
+    }
+  }
+  / s: ('#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW) __ e:expr_item {
+    // => { op: string; right: expr }
+    return {
+      type: 'json',
+      op: s,
+      right: { type: 'expr', expr: e }
     }
   }
 
@@ -3418,7 +3424,7 @@ column_ref
           ...getLocationObject()
       }
     }
-  / tbl:(ident __ DOT)? __ col:column_type __ a:((DOUBLE_ARROW / SINGLE_ARROW) __ (literal_string / literal_numeric))+ {
+  / tbl:(ident __ DOT)? __ col:column_type __ jo:jsonb_or_json_op_right+ {
     // => IGNORE
       const tableName = tbl && tbl[0] || null
       columnList.add(`select::${tableName}::${col.value}`)
@@ -3426,20 +3432,11 @@ column_ref
         type: 'column_ref',
         table: tableName,
         column: { expr: col },
-        arrows: a.map(item => item[0]),
-        properties: a.map(item => item[2]),
+        jsonb: jo,
         ...getLocationObject()
       };
   }
   / schema:ident tbl:(__ DOT __ ident) col:(__ DOT __ column_type) {
-    /* => {
-        type: 'column_ref';
-        schema: string;
-        table: string;
-        column: column | '*';
-        arrows?: ('->>' | '->')[];
-        property?: (literal_string | literal_numeric)[];
-      } */
       columnList.add(`select::${schema}.${tbl[3]}::${col[3].value}`);
       return {
         type: 'column_ref',
@@ -3450,13 +3447,6 @@ column_ref
       };
     }
   / tbl:ident __ DOT __ col:column_type {
-      /* => {
-        type: 'column_ref';
-        table: ident;
-        column: column | '*';
-        arrows?: ('->>' | '->')[];
-        property?: (literal_string | literal_numeric)[];
-      } */
       columnList.add(`select::${tbl}::${col.value}`);
       return {
         type: 'column_ref',
@@ -3986,26 +3976,17 @@ scalar_func
   / "NTILE"i
 
 cast_double_colon
-  = s:KW_DOUBLE_COLON __ t:data_type __ a:((DOUBLE_ARROW / SINGLE_ARROW) __ (literal_string / literal_numeric))* __ alias:alias_clause? {
-    /* => {
-        as?: alias_clause,
-        symbol: '::' | 'as',
-        target: data_type;
-        arrows?: ('->>' | '->')[];
-        property?: (literal_string | literal_numeric)[];
-      }
-      */
+  = s:KW_DOUBLE_COLON __ t:data_type __ jo:jsonb_or_json_op_right* __ alias:alias_clause? {
     return {
       as: alias,
       symbol: '::',
       target: t,
-      arrows: a.map(item => item[0]),
-      properties: a.map(item => item[2]),
+      jsonb: jo,
       ...getLocationObject(),
     }
   }
 cast_expr
-  = c:(KW_CAST / KW_TRY_CAST) __ LPAREN __ e:expr __ KW_AS __ t:data_type __ RPAREN __ a:((DOUBLE_ARROW / SINGLE_ARROW) __ (literal_string / literal_numeric))*  {
+  = c:(KW_CAST / KW_TRY_CAST) __ LPAREN __ e:expr __ KW_AS __ t:data_type __ RPAREN __ jo:jsonb_or_json_op_right*  {
     // => IGNORE
     return {
       type: 'cast',
@@ -4013,8 +3994,7 @@ cast_expr
       expr: e,
       symbol: 'as',
       target: t,
-      arrows: a.map(item => item[0]),
-      properties: a.map(item => item[2]),
+      jsonb: jo,
     };
   }
   / c:(KW_CAST / KW_TRY_CAST) __ LPAREN __ e:expr __ KW_AS __ KW_DECIMAL __ LPAREN __ precision:int __ RPAREN __ RPAREN {
diff --git a/src/column.js b/src/column.js
index 2b2b0d2a..380b027c 100644
--- a/src/column.js
+++ b/src/column.js
@@ -1,6 +1,6 @@
 import { constraintDefinitionToSQL } from './constrain'
 import { exprToSQL } from './expr'
-import { arrayDimensionToSymbol, castToSQL } from './func'
+import { arrayDimensionToSymbol, castToSQL, jsonOrJsonbToSQL } from './func'
 import { tablesToSQL } from './tables'
 import {
   autoIncrementToSQL,
@@ -35,7 +35,7 @@ function arrayIndexToSQL(arrayIndexList) {
 }
 function columnRefToSQL(expr) {
   const {
-    array_index, arrows = [], as, column, db, isDual, notations = [], schema, table, parentheses, properties,
+    array_index, as, column, db, isDual, notations = [], schema, table, parentheses, jsonb,
     suffix, order_by, subFields = [],
   } = expr
   let str = column === '*' ? '*' : columnOffsetToSQL(column, isDual)
@@ -52,7 +52,7 @@ function columnRefToSQL(expr) {
   const result = [
     str,
     commonOptionConnector('AS', exprToSQL, as),
-    arrows.map((arrow, index) => commonOptionConnector(arrow, literalToSQL, properties[index])).join(' '),
+    jsonOrJsonbToSQL(jsonb),
   ]
   result.push(toUpper(suffix))
   result.push(toUpper(order_by))
@@ -206,6 +206,7 @@ function columnsToSQL(columns, tables) {
 
 export {
   arrayIndexToSQL,
+  asToSQL,
   columnDefinitionToSQL,
   columnRefToSQL,
   columnToSQL,
diff --git a/src/expr.js b/src/expr.js
index ddd4c44d..dfa71fa4 100644
--- a/src/expr.js
+++ b/src/expr.js
@@ -70,7 +70,9 @@ function exprToSQL(exprOrigin) {
       expr[key] = ast[key]
     }
   }
-  return exprToSQLConvertFn[expr.type] ? exprToSQLConvertFn[expr.type](expr) : literalToSQL(expr)
+  const { type } = expr
+  if (type === 'expr') return exprToSQL(expr.expr)
+  return exprToSQLConvertFn[type] ? exprToSQLConvertFn[type](expr) : literalToSQL(expr)
 }
 
 function unaryToSQL(unarExpr) {
diff --git a/src/func.js b/src/func.js
index 0e412b16..568b71ac 100644
--- a/src/func.js
+++ b/src/func.js
@@ -1,4 +1,4 @@
-import { arrayIndexToSQL } from './column'
+import { arrayIndexToSQL, asToSQL } from './column'
 import { exprToSQL } from './expr'
 import { commonOptionConnector, hasVal, identifierToSql, literalToSQL, toUpper } from './util'
 import { overToSQL } from './over'
@@ -27,8 +27,16 @@ function arrayDimensionToSymbol(target) {
   return result.join('')
 }
 
+function jsonOrJsonbToSQL(jsonb) {
+  if (!jsonb || jsonb.length === 0) return ''
+  return jsonb.map(operator => {
+    const { op, right } = operator
+    return [commonOptionConnector(op, exprToSQL, right.expr), asToSQL(right.as)].filter(hasVal).join(' ')
+  }).join(' ')
+}
+
 function castToSQL(expr) {
-  const { arrows = [], target, expr: expression, keyword, symbol, as: alias, parentheses: outParentheses, properties = [] } = expr
+  const { target, expr: expression, keyword, symbol, as: alias, parentheses: outParentheses, jsonb } = expr
   const { length, dataType, parentheses, quoted, scale, suffix: dataTypeSuffix, expr: targetExpr } = target
   let str = targetExpr ? exprToSQL(targetExpr) : ''
   if (length != null) str = scale ? `${length}, ${scale}` : length
@@ -42,7 +50,9 @@ function castToSQL(expr) {
     suffix = ')'
     symbolChar = ` ${symbol.toUpperCase()} `
   }
-  suffix += arrows.map((arrow, index) => commonOptionConnector(arrow, literalToSQL, properties[index])).join(' ')
+  const jsonbOperatorStr = jsonOrJsonbToSQL(jsonb)
+  const whitespace = jsonbOperatorStr ? ' ' : ''
+  suffix += `${whitespace}${jsonbOperatorStr}`
   if (alias) suffix += ` AS ${identifierToSql(alias)}`
   const arrayDimension = arrayDimensionToSymbol(target)
   const result = [prefix, symbolChar, quoted, dataType, quoted, arrayDimension, str, suffix].filter(hasVal).join('')
@@ -117,6 +127,7 @@ export {
   flattenFunToSQL,
   funcToSQL,
   jsonObjectArgToSQL,
+  jsonOrJsonbToSQL,
   lambdaToSQL,
   tablefuncFunToSQL,
 }
diff --git a/test/mysql-mariadb.spec.js b/test/mysql-mariadb.spec.js
index a53f49d5..ae0931f9 100644
--- a/test/mysql-mariadb.spec.js
+++ b/test/mysql-mariadb.spec.js
@@ -1093,7 +1093,7 @@ describe('mysql', () => {
       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 23d9761e..71f251b2 100644
--- a/test/postgres.spec.js
+++ b/test/postgres.spec.js
@@ -921,14 +921,14 @@ describe('Postgres', () => {
       title: 'cast to jsonb and select key',
       sql: [
         "SELECT TextColumn::JSONB->>'name' FROM table1",
-        `SELECT TextColumn::JSONB->> 'name' FROM "table1"`
+        `SELECT TextColumn::JSONB ->> 'name' FROM "table1"`
       ]
     },
     {
       title: 'cast to jsonb and select key in function',
       sql: [
         "SELECT CAST(properties AS JSONB)->>'name' FROM table1",
-        `SELECT CAST(properties AS JSONB)->> 'name' FROM "table1"`
+        `SELECT CAST(properties AS JSONB) ->> 'name' FROM "table1"`
       ]
     },
     {
@@ -1562,6 +1562,13 @@ describe('Postgres', () => {
         'ALTER TABLE "transactions" ALTER COLUMN status SET NOT NULL',
       ]
     },
+    {
+      title: 'jsonb operator',
+      sql: [
+        "SELECT id,  collection::jsonb ?| array['val1', 'val2'] FROM instances",
+        `SELECT id, collection::JSONB ?| ARRAY['val1','val2'] FROM "instances"`
+      ]
+    },
   ]
   function neatlyNestTestedSQL(sqlList){
     sqlList.forEach(sqlInfo => {
@@ -1571,6 +1578,7 @@ describe('Postgres', () => {
         })
     })
   }
+
   neatlyNestTestedSQL(SQL_LIST)
 
   describe('tables to sql', () => {

From 5b03bfe77280cbf96aff3392e3dc89910a78fb0a Mon Sep 17 00:00:00 2001
From: taozhi8833998 <taozhi8833998@163.com>
Date: Fri, 19 Jul 2024 15:38:56 +0800
Subject: [PATCH 2/2] refactor: update type definition

---
 ast/postgresql.ts      | 60 ++++++++++++++++++++++++++++++++----------
 pegjs/postgresql.pegjs |  4 +--
 2 files changed, 48 insertions(+), 16 deletions(-)

diff --git a/ast/postgresql.ts b/ast/postgresql.ts
index 317b8b28..e66df085 100644
--- a/ast/postgresql.ts
+++ b/ast/postgresql.ts
@@ -277,7 +277,7 @@ export type create_table_definition = create_definition[];
 
 export type create_definition = create_column_definition | create_index_definition | create_fulltext_spatial_index_definition | create_constraint_definition;
 
-export type column_definition_opt = column_constraint | { auto_increment: 'auto_increment'; } | { unique: 'unique' | 'unique key'; } | { unique: 'key' | 'primary key'; } | { comment: keyword_comment; } | { collate: collate_expr; } | { column_format: column_format; } | { storage: storage } | { reference_definition: reference_definition; } | { check: check_constraint_definition; } | { character_set: collate_expr };
+export type column_definition_opt = column_constraint | { auto_increment: 'auto_increment'; } | { unique: 'unique' | 'unique key'; } | { unique: 'key' | 'primary key'; } | { comment: keyword_comment; } | { collate: collate_expr; } | { column_format: column_format; } | { storage: storage } | { reference_definition: reference_definition; } | { check: check_constraint_definition; } | { character_set: { type: 'CHARACTER SET'; symbol: '=' | null; value: ident_without_kw_type; } };
 
 
 
@@ -314,7 +314,7 @@ export type create_column_definition = {
 
 export type column_constraint = { nullable: literal_null | literal_not_null; default_val: default_expr; };
 
-export type collate_expr = { type: 'collate'; symbol: '=' | null; value: ident; };
+export type collate_expr = { type: 'collate'; keyword: 'collate'; collate: { symbol: '=' ; name: ident_type; value: ident_type; }} | { type: 'collate'; keyword: 'collate'; collate: { symbol: '=' | null ; name: ident_type; }};
 
 export type column_format = { type: 'column_format'; value: 'fixed' | 'dynamic' | 'default'; };
 
@@ -391,6 +391,9 @@ export type alter_schema_stmt = AstStatement<alter_resource_stmt_node>;
 export interface alter_table_stmt_node {
         type: 'alter';
         table: table_ref_list;
+        keyword: 'table';
+        if_exists: if_exists;
+        prefix?: literal_string;
         expr: alter_action_list;
       }
 
@@ -398,7 +401,7 @@ export type alter_table_stmt = AstStatement<alter_table_stmt_node>;
 
 export type alter_action_list = alter_action[];
 
-export type alter_action = ALTER_ADD_COLUMN | ALTER_ADD_CONSTRAINT | ALTER_DROP_COLUMN | ALTER_ADD_INDEX_OR_KEY | ALTER_ADD_FULLETXT_SPARITAL_INDEX | ALTER_RENAME | ALTER_ALGORITHM | ALTER_LOCK;
+export type alter_action = ALTER_ADD_COLUMN | ALTER_ADD_CONSTRAINT | ALTER_DROP_COLUMN | ALTER_ADD_INDEX_OR_KEY | ALTER_ADD_FULLETXT_SPARITAL_INDEX | ALTER_RENAME | ALTER_ALGORITHM | ALTER_LOCK | ALTER_COLUMN_DATA_TYPE | ALTER_COLUMN_DEFAULT | ALTER_COLUMN_NOT_NULL;
 
 
 
@@ -406,6 +409,7 @@ export type ALTER_ADD_COLUMN = {
         action: 'add';
         keyword: KW_COLUMN;
         resource: 'column';
+        if_not_exists: ife;
         type: 'alter';
       } & create_column_definition;;
 
@@ -415,6 +419,7 @@ export type ALTER_DROP_COLUMN = {
         action: 'drop';
         collumn: column_ref;
         keyword: KW_COLUMN;
+        if_exists: if_exists;
         resource: 'column';
         type: 'alter';
       };
@@ -471,6 +476,35 @@ export type ALTER_LOCK = {
 
 
 
+export type ALTER_COLUMN_DATA_TYPE = {
+        action: 'alter';
+        keyword?: KW_COLUMN;
+        using?: expr;
+        type: 'alter';
+      } & create_column_definition;;
+
+
+
+
+
+export type ALTER_COLUMN_DEFAULT = {
+        action: 'alter';
+        keyword?: KW_COLUMN;
+        default_val?: { type: 'set default', value: expr };
+        type: 'alter';
+      } & create_column_definition;;
+
+
+
+export type ALTER_COLUMN_NOT_NULL = {
+        action: 'alter';
+        keyword?: KW_COLUMN;
+        nullable: literal_not_null;
+        type: 'alter';
+      } & create_column_definition;;
+
+
+
 export type create_index_definition = {
          index: column;
          definition: cte_column_definition;
@@ -611,7 +645,7 @@ export type create_option_character_set_kw = string;
 export type create_option_character_set = {
       keyword: 'character set' | 'charset' | 'collate' | 'default character set' | 'default charset' | 'default collate';
       symbol: '=';
-      value: ident_name;
+      value: ident_without_kw_type;
       };
 
 
@@ -838,7 +872,7 @@ export type expr_item = binary_column_expr & { array_index: array_index };
 
 export type cast_data_type = data_type & { quoted?: string };
 
-export type column_list_item = { expr: expr; as: null; } | { type: 'cast'; expr: expr; symbol: '::'; target: cast_data_type;  as?: null; arrows?: ('->>' | '->')[]; property?: (literal_string | literal_numeric)[]; } | { expr: column_ref; as: null; } | { type: 'expr'; expr: expr; as?: alias_clause; };
+export type column_list_item = { expr: expr; as: null; } | { type: 'cast'; expr: expr; symbol: '::'; target: cast_data_type;  as?: null; jsonb?: jsonb_or_json_op_right[]; } | { expr: column_ref; as: null; } | { type: 'expr'; expr: expr; as?: alias_clause; };
 
 
 
@@ -881,7 +915,7 @@ export type table_ref = table_base | table_join;
 export type table_join = table_base & {join: join_op; using: ident_name[]; } | table_base & {join: join_op; on?: on_clause; } | {
       expr: (union_stmt | table_ref_list) & { parentheses: true; };
       as?: alias_clause;
-      join: join_op;
+      join: join_op | set_op;
       on?: on_clause;
     };
 
@@ -1114,7 +1148,7 @@ export type exists_expr = unary_expr;
 
 export type exists_op = 'NOT EXISTS' | KW_EXISTS;
 
-export type comparison_op_right = arithmetic_op_right | in_op_right | between_op_right | is_op_right | like_op_right | jsonb_op_right | regex_op_right;
+export type comparison_op_right = arithmetic_op_right | in_op_right | between_op_right | is_op_right | like_op_right | jsonb_or_json_op_right | regex_op_right;
 
 export type arithmetic_op_right = { type: 'arithmetic'; tail: any };
 
@@ -1146,7 +1180,7 @@ export type like_op_right = { op: like_op; right: (literal | comparison_expr) &
 
 export type in_op_right = {op: in_op; right: expr_list | var_decl | literal_string; };
 
-export type jsonb_op_right = { op: string; right: expr };
+export type jsonb_or_json_op_right = { op: string; right: { type: 'expr'; expr: expr_item } };
 
 export type additive_expr = binary_expr;
 
@@ -1175,14 +1209,11 @@ export type column_ref = string_constants_escape | {
         schema: string;
         table: string;
         column: column | '*';
-        arrows?: ('->>' | '->')[];
-        property?: (literal_string | literal_numeric)[];
+        jsonb?: jsonb_or_json_op_right[];
       } | {
         type: 'column_ref';
         table: ident;
         column: column | '*';
-        arrows?: ('->>' | '->')[];
-        property?: (literal_string | literal_numeric)[];
       };
 
 export type column_ref_quoted = unknown;
@@ -1307,8 +1338,7 @@ export type cast_double_colon = {
         as?: alias_clause,
         symbol: '::' | 'as',
         target: data_type;
-        arrows?: ('->>' | '->')[];
-        property?: (literal_string | literal_numeric)[];
+        jsonb?: jsonb_or_json_op_right[];
       };
 
 
@@ -1851,6 +1881,8 @@ export type data_type = {
 
 
 
+
+
 export type array_type = data_type;
 
 
diff --git a/pegjs/postgresql.pegjs b/pegjs/postgresql.pegjs
index cca02a47..95625981 100644
--- a/pegjs/postgresql.pegjs
+++ b/pegjs/postgresql.pegjs
@@ -4228,7 +4228,7 @@ in_op_right
 
 jsonb_or_json_op_right
   = s: ('@>' / '<@' / '?|' / '?&' / '?' / '#-') __  e:expr_item {
-    // => { op: string; right: expr }
+    // => { op: string; right: { type: 'expr'; expr: expr_item } }
     return {
       type: 'jsonb',
       op: s,
@@ -4236,7 +4236,7 @@ jsonb_or_json_op_right
     }
   }
   / s: ('#>>' / '#>' / DOUBLE_ARROW / SINGLE_ARROW) __ e:expr_item {
-    // => { op: string; right: expr }
+    // => { op: string; right: { type: 'expr'; expr: expr_item } }
     return {
       type: 'json',
       op: s,