Repository: GoogleCloudPlatform/pgadapter
Pull request #49 (2022-03-01 09:11:44)

fix: Update Copy parser to handle ',' separated option list
Update Copy parser to handle ',' separated option list. Also expand single char regex to wider set of characters [! - ~].


Patch:
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/parsers/copy/Copy.java b/src/main/java/com/google/cloud/spanner/pgadapter/parsers/copy/Copy.java
index 7f48c6b0..90d65e0f 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/parsers/copy/Copy.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/parsers/copy/Copy.java
@@ -29,8 +29,7 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
     boolean jjtc000 = true;
     jjtree.openNodeScope(jjtn000);
     try {
-      Expression();
-      jj_consume_token(40);
+      Stmt();
       jjtree.closeNodeScope(jjtn000, true);
       jjtc000 = false;
       {
@@ -64,9 +63,23 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
     throw new Error("Missing return statement in function");
   }
 
-  /** An Expression. */
-  public final void Expression() throws ParseException {
-    CopyStmt();
+  public final void Stmt() throws ParseException {
+    switch ((jj_ntk == -1) ? jj_ntk_f() : jj_ntk) {
+      case K_COPY:
+        {
+          CopyStmt();
+          break;
+        }
+      default:
+        jj_la1[0] = jj_gen;
+        if (jj_2_1(2)) {
+          CopyStmt();
+          jj_consume_token(40);
+        } else {
+          jj_consume_token(-1);
+          throw new ParseException();
+        }
+    }
   }
 
   /** Copy Statement. */
@@ -151,11 +164,11 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
     boolean jjtc000 = true;
     jjtree.openNodeScope(jjtn000);
     try {
-      if (jj_2_1(2)) {
+      if (jj_2_2(2)) {
         identifier();
         jj_consume_token(41);
         namespace();
-      } else if (jj_2_2(2)) {
+      } else if (jj_2_3(2)) {
         quotedIdentifier();
         jj_consume_token(41);
         namespace();
@@ -166,14 +179,14 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
               identifier();
               break;
             }
-          case UNICODE:
           case QUOTED_IDENTIFIER:
+          case UNICODE:
             {
               quotedIdentifier();
               break;
             }
           default:
-            jj_la1[0] = jj_gen;
+            jj_la1[1] = jj_gen;
             jj_consume_token(-1);
             throw new ParseException();
         }
@@ -207,7 +220,7 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
 
   /** Optional Column List */
   public final void optColumnList() throws ParseException {
-    if (jj_2_3(2)) {
+    if (jj_2_4(2)) {
       jj_consume_token(42);
       columnList();
       jj_consume_token(43);
@@ -223,21 +236,21 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
     boolean jjtc000 = true;
     jjtree.openNodeScope(jjtn000);
     try {
-      if (jj_2_4(2)) {
+      if (jj_2_5(2)) {
         columnElem();
         jj_consume_token(44);
         columnList();
       } else {
         switch ((jj_ntk == -1) ? jj_ntk_f() : jj_ntk) {
-          case UNICODE:
           case QUOTED_IDENTIFIER:
           case IDENTIFIER:
+          case UNICODE:
             {
               columnElem();
               break;
             }
           default:
-            jj_la1[1] = jj_gen;
+            jj_la1[2] = jj_gen;
             jj_consume_token(-1);
             throw new ParseException();
         }
@@ -282,14 +295,14 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
             identifier();
             break;
           }
-        case UNICODE:
         case QUOTED_IDENTIFIER:
+        case UNICODE:
           {
             quotedIdentifier();
             break;
           }
         default:
-          jj_la1[2] = jj_gen;
+          jj_la1[3] = jj_gen;
           jj_consume_token(-1);
           throw new ParseException();
       }
@@ -348,7 +361,7 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
             break;
           }
         default:
-          jj_la1[3] = jj_gen;
+          jj_la1[4] = jj_gen;
           jj_consume_token(-1);
           throw new ParseException();
       }
@@ -389,7 +402,7 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
             break;
           }
         default:
-          jj_la1[4] = jj_gen;
+          jj_la1[5] = jj_gen;
           jj_consume_token(-1);
           throw new ParseException();
       }
@@ -429,7 +442,7 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
           break;
         }
       default:
-        jj_la1[5] = jj_gen;
+        jj_la1[6] = jj_gen;
     }
   }
 
@@ -440,9 +453,9 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
     boolean jjtc000 = true;
     jjtree.openNodeScope(jjtn000);
     try {
-      if (jj_2_5(2)) {
+      if (jj_2_6(3)) {
         jj_consume_token(42);
-        copyOptionList();
+        copyOptionGenericList();
         jj_consume_token(43);
       } else {
         copyOptionList();
@@ -474,6 +487,69 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
     }
   }
 
+  public final void copyOptionGenericList() throws ParseException {
+    /*@bgen(jjtree) CopyOptionList */
+    ASTCopyOptionList jjtn000 = new ASTCopyOptionList(JJTCOPYOPTIONLIST);
+    boolean jjtc000 = true;
+    jjtree.openNodeScope(jjtn000);
+    try {
+      if (jj_2_7(3)) {
+        copyOptionElement();
+        jj_consume_token(44);
+        copyOptionGenericList();
+      } else {
+        switch ((jj_ntk == -1) ? jj_ntk_f() : jj_ntk) {
+          case O_BINARY:
+          case O_CSV:
+          case O_TEXT:
+          case O_FORMAT:
+          case O_FREEZE:
+          case O_DELIMITER:
+          case O_NULL:
+          case O_HEADER:
+          case O_QUOTE:
+          case O_ESCAPE:
+          case O_FORCE_QUOTE:
+          case O_FORCE_NOT_NULL:
+          case O_FORCE_NULL:
+          case O_ENCODING:
+            {
+              copyOptionElement();
+              break;
+            }
+          default:
+            jj_la1[7] = jj_gen;
+            jj_consume_token(-1);
+            throw new ParseException();
+        }
+      }
+    } catch (Throwable jjte000) {
+      if (jjtc000) {
+        jjtree.clearNodeScope(jjtn000);
+        jjtc000 = false;
+      } else {
+        jjtree.popNode();
+      }
+      if (jjte000 instanceof RuntimeException) {
+        {
+          if (true) throw (RuntimeException) jjte000;
+        }
+      }
+      if (jjte000 instanceof ParseException) {
+        {
+          if (true) throw (ParseException) jjte000;
+        }
+      }
+      {
+        if (true) throw (Error) jjte000;
+      }
+    } finally {
+      if (jjtc000) {
+        jjtree.closeNodeScope(jjtn000, true);
+      }
+    }
+  }
+
   public final void copyOptionList() throws ParseException {
     /*@bgen(jjtree) CopyOptionList */
     ASTCopyOptionList jjtn000 = new ASTCopyOptionList(JJTCOPYOPTIONLIST);
@@ -501,7 +577,7 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
             break;
           }
         default:
-          jj_la1[6] = jj_gen;
+          jj_la1[8] = jj_gen;
           jjtree.closeNodeScope(jjtn000, true);
           jjtc000 = false;
       }
@@ -615,8 +691,8 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
             break;
           }
         default:
-          jj_la1[7] = jj_gen;
-          if (jj_2_6(3)) {
+          jj_la1[9] = jj_gen;
+          if (jj_2_8(3)) {
             jj_consume_token(O_FORCE_QUOTE);
             jj_consume_token(42);
             columnList();
@@ -627,7 +703,7 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
             {
               if (true) throw new ParseException("FORCE_QUOTE is not supported.");
             }
-          } else if (jj_2_7(3)) {
+          } else if (jj_2_9(3)) {
             jj_consume_token(O_FORCE_NOT_NULL);
             jj_consume_token(42);
             columnList();
@@ -638,7 +714,7 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
             {
               if (true) throw new ParseException("FORCE_NOT_NULL is not supported.");
             }
-          } else if (jj_2_8(3)) {
+          } else if (jj_2_10(3)) {
             jj_consume_token(O_FORCE_NULL);
             jj_consume_token(42);
             columnList();
@@ -664,7 +740,7 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
                   break;
                 }
               default:
-                jj_la1[8] = jj_gen;
+                jj_la1[10] = jj_gen;
                 jj_consume_token(-1);
                 throw new ParseException();
             }
@@ -729,7 +805,7 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
             break;
           }
         default:
-          jj_la1[9] = jj_gen;
+          jj_la1[11] = jj_gen;
           jj_consume_token(-1);
           throw new ParseException();
       }
@@ -791,7 +867,7 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
             break;
           }
         default:
-          jj_la1[10] = jj_gen;
+          jj_la1[12] = jj_gen;
           jj_consume_token(-1);
           throw new ParseException();
       }
@@ -844,7 +920,7 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
             break;
           }
         default:
-          jj_la1[11] = jj_gen;
+          jj_la1[13] = jj_gen;
           jj_consume_token(-1);
           throw new ParseException();
       }
@@ -951,129 +1027,272 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
     }
   }
 
-  private boolean jj_3_6() {
+  private boolean jj_2_9(int xla) {
+    jj_la = xla;
+    jj_lastpos = jj_scanpos = token;
+    try {
+      return (!jj_3_9());
+    } catch (LookaheadSuccess ls) {
+      return true;
+    } finally {
+      jj_save(8, xla);
+    }
+  }
+
+  private boolean jj_2_10(int xla) {
+    jj_la = xla;
+    jj_lastpos = jj_scanpos = token;
+    try {
+      return (!jj_3_10());
+    } catch (LookaheadSuccess ls) {
+      return true;
+    } finally {
+      jj_save(9, xla);
+    }
+  }
+
+  private boolean jj_3R_identifier_276_3_2() {
+    if (jj_scan_token(IDENTIFIER)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_formatType_265_5_32() {
+    if (jj_scan_token(O_CSV)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_formatType_262_5_31() {
+    if (jj_scan_token(O_BINARY)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_formatType_259_5_30() {
+    if (jj_scan_token(O_TEXT)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_formatType_259_5_25() {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_formatType_259_5_30()) {
+      jj_scanpos = xsp;
+      if (jj_3R_formatType_262_5_31()) {
+        jj_scanpos = xsp;
+        if (jj_3R_formatType_265_5_32()) return true;
+      }
+    }
+    return false;
+  }
+
+  private boolean jj_3R_columnElem_158_5_13() {
+    if (jj_3R_quotedIdentifier_289_5_3()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_copyOptionElement_251_5_23() {
+    if (jj_scan_token(O_ENCODING)) return true;
+    if (jj_3R_identifier_276_3_2()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_columnElem_157_3_5() {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_columnElem_157_3_12()) {
+      jj_scanpos = xsp;
+      if (jj_3R_columnElem_158_5_13()) return true;
+    }
+    return false;
+  }
+
+  private boolean jj_3R_columnElem_157_3_12() {
+    if (jj_3R_identifier_276_3_2()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_columnList_151_5_11() {
+    if (jj_3R_columnElem_157_3_5()) return true;
+    return false;
+  }
+
+  private boolean jj_3_10() {
+    if (jj_scan_token(O_FORCE_NULL)) return true;
+    if (jj_scan_token(42)) return true;
+    if (jj_3R_columnList_149_3_4()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_columnList_149_3_4() {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3_5()) {
+      jj_scanpos = xsp;
+      if (jj_3R_columnList_151_5_11()) return true;
+    }
+    return false;
+  }
+
+  private boolean jj_3_5() {
+    if (jj_3R_columnElem_157_3_5()) return true;
+    if (jj_scan_token(44)) return true;
+    return false;
+  }
+
+  private boolean jj_3_9() {
+    if (jj_scan_token(O_FORCE_NOT_NULL)) return true;
+    if (jj_scan_token(42)) return true;
+    if (jj_3R_columnList_149_3_4()) return true;
+    return false;
+  }
+
+  private boolean jj_3_8() {
     if (jj_scan_token(O_FORCE_QUOTE)) return true;
     if (jj_scan_token(42)) return true;
-    if (jj_3R_columnList_148_3_3()) return true;
+    if (jj_3R_columnList_149_3_4()) return true;
     return false;
   }
 
-  private boolean jj_3R_copyOptionElement_225_5_21() {
-    if (jj_scan_token(O_ESCAPE)) return true;
+  private boolean jj_3_4() {
+    if (jj_scan_token(42)) return true;
+    if (jj_3R_columnList_149_3_4()) return true;
     return false;
   }
 
-  private boolean jj_3_2() {
-    if (jj_3R_quotedIdentifier_281_5_2()) return true;
-    if (jj_scan_token(41)) return true;
+  private boolean jj_3R_copyOptionElement_233_5_22() {
+    if (jj_scan_token(O_ESCAPE)) return true;
+    if (jj_3R_singleChar_306_3_26()) return true;
     return false;
   }
 
-  private boolean jj_3_1() {
-    if (jj_3R_identifier_268_3_1()) return true;
-    if (jj_scan_token(41)) return true;
+  private boolean jj_3R_namespace_135_5_29() {
+    if (jj_3R_quotedIdentifier_289_5_3()) return true;
     return false;
   }
 
-  private boolean jj_3R_copyOptionElement_222_5_20() {
+  private boolean jj_3R_copyOptionElement_230_5_21() {
     if (jj_scan_token(O_QUOTE)) return true;
+    if (jj_3R_singleChar_306_3_26()) return true;
     return false;
   }
 
-  private boolean jj_3R_copyOptionElement_219_5_19() {
-    if (jj_scan_token(O_HEADER)) return true;
+  private boolean jj_3R_namespace_134_5_28() {
+    if (jj_3R_identifier_276_3_2()) return true;
     return false;
   }
 
-  private boolean jj_3R_identifier_268_3_1() {
-    if (jj_scan_token(IDENTIFIER)) return true;
+  private boolean jj_3_3() {
+    if (jj_3R_quotedIdentifier_289_5_3()) return true;
+    if (jj_scan_token(41)) return true;
     return false;
   }
 
-  private boolean jj_3R_copyOptionElement_216_5_18() {
-    if (jj_scan_token(O_NULL)) return true;
+  private boolean jj_3R_copyOptionElement_227_5_20() {
+    if (jj_scan_token(O_HEADER)) return true;
+    if (jj_3R_booleanOption_314_5_27()) return true;
     return false;
   }
 
-  private boolean jj_3R_copyOptionElement_213_5_17() {
-    if (jj_scan_token(O_DELIMITER)) return true;
+  private boolean jj_3_2() {
+    if (jj_3R_identifier_276_3_2()) return true;
+    if (jj_scan_token(41)) return true;
     return false;
   }
 
-  private boolean jj_3R_formatType_257_5_26() {
-    if (jj_scan_token(O_CSV)) return true;
+  private boolean jj_3R_namespace_130_5_24() {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3_2()) {
+      jj_scanpos = xsp;
+      if (jj_3_3()) {
+        jj_scanpos = xsp;
+        if (jj_3R_namespace_134_5_28()) {
+          jj_scanpos = xsp;
+          if (jj_3R_namespace_135_5_29()) return true;
+        }
+      }
+    }
     return false;
   }
 
-  private boolean jj_3R_copyOptionElement_209_5_16() {
-    if (jj_scan_token(O_FREEZE)) return true;
+  private boolean jj_3R_copyOptionElement_224_5_19() {
+    if (jj_scan_token(O_NULL)) return true;
+    if (jj_3R_quotedIdentifier_289_5_3()) return true;
     return false;
   }
 
-  private boolean jj_3R_formatType_254_5_25() {
-    if (jj_scan_token(O_BINARY)) return true;
+  private boolean jj_3R_copyOptionElement_221_5_18() {
+    if (jj_scan_token(O_DELIMITER)) return true;
+    if (jj_3R_singleChar_306_3_26()) return true;
     return false;
   }
 
-  private boolean jj_3R_copyOptionElement_206_5_15() {
-    if (jj_3R_formatType_251_5_23()) return true;
+  private boolean jj_3R_booleanOption_315_5_34() {
+    if (jj_scan_token(O_FALSE)) return true;
     return false;
   }
 
-  private boolean jj_3R_formatType_251_5_24() {
-    if (jj_scan_token(O_TEXT)) return true;
+  private boolean jj_3R_booleanOption_314_5_33() {
+    if (jj_scan_token(O_TRUE)) return true;
     return false;
   }
 
-  private boolean jj_3R_formatType_251_5_23() {
+  private boolean jj_3R_booleanOption_314_5_27() {
     Token xsp;
     xsp = jj_scanpos;
-    if (jj_3R_formatType_251_5_24()) {
+    if (jj_3R_booleanOption_314_5_33()) {
       jj_scanpos = xsp;
-      if (jj_3R_formatType_254_5_25()) {
-        jj_scanpos = xsp;
-        if (jj_3R_formatType_257_5_26()) return true;
-      }
+      if (jj_3R_booleanOption_315_5_34()) return true;
     }
     return false;
   }
 
-  private boolean jj_3R_columnElem_157_5_10() {
-    if (jj_3R_quotedIdentifier_281_5_2()) return true;
+  private boolean jj_3R_qualifiedName_125_3_8() {
+    if (jj_3R_namespace_130_5_24()) return true;
     return false;
   }
 
-  private boolean jj_3R_copyOptionElement_203_5_14() {
-    if (jj_scan_token(O_FORMAT)) return true;
+  private boolean jj_3R_copyOptionElement_217_5_17() {
+    if (jj_scan_token(O_FREEZE)) return true;
+    return false;
+  }
+
+  private boolean jj_3R_copyOptionElement_214_5_16() {
+    if (jj_3R_formatType_259_5_25()) return true;
+    return false;
+  }
+
+  private boolean jj_3R_CopyStmt_119_3_1() {
+    if (jj_scan_token(K_COPY)) return true;
+    if (jj_3R_qualifiedName_125_3_8()) return true;
     return false;
   }
 
-  private boolean jj_3R_copyOptionElement_203_5_13() {
+  private boolean jj_3R_copyOptionElement_211_5_7() {
     Token xsp;
     xsp = jj_scanpos;
-    if (jj_3R_copyOptionElement_203_5_14()) {
+    if (jj_3R_copyOptionElement_211_5_15()) {
       jj_scanpos = xsp;
-      if (jj_3R_copyOptionElement_206_5_15()) {
+      if (jj_3R_copyOptionElement_214_5_16()) {
         jj_scanpos = xsp;
-        if (jj_3R_copyOptionElement_209_5_16()) {
+        if (jj_3R_copyOptionElement_217_5_17()) {
           jj_scanpos = xsp;
-          if (jj_3R_copyOptionElement_213_5_17()) {
+          if (jj_3R_copyOptionElement_221_5_18()) {
             jj_scanpos = xsp;
-            if (jj_3R_copyOptionElement_216_5_18()) {
+            if (jj_3R_copyOptionElement_224_5_19()) {
               jj_scanpos = xsp;
-              if (jj_3R_copyOptionElement_219_5_19()) {
+              if (jj_3R_copyOptionElement_227_5_20()) {
                 jj_scanpos = xsp;
-                if (jj_3R_copyOptionElement_222_5_20()) {
+                if (jj_3R_copyOptionElement_230_5_21()) {
                   jj_scanpos = xsp;
-                  if (jj_3R_copyOptionElement_225_5_21()) {
+                  if (jj_3R_copyOptionElement_233_5_22()) {
                     jj_scanpos = xsp;
-                    if (jj_3_6()) {
+                    if (jj_3_8()) {
                       jj_scanpos = xsp;
-                      if (jj_3_7()) {
+                      if (jj_3_9()) {
                         jj_scanpos = xsp;
-                        if (jj_3_8()) {
+                        if (jj_3_10()) {
                           jj_scanpos = xsp;
-                          if (jj_3R_copyOptionElement_243_5_22()) return true;
+                          if (jj_3R_copyOptionElement_251_5_23()) return true;
                         }
                       }
                     }
@@ -1088,110 +1307,68 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
     return false;
   }
 
-  private boolean jj_3R_columnElem_156_3_4() {
-    Token xsp;
-    xsp = jj_scanpos;
-    if (jj_3R_columnElem_156_3_9()) {
-      jj_scanpos = xsp;
-      if (jj_3R_columnElem_157_5_10()) return true;
-    }
-    return false;
-  }
-
-  private boolean jj_3R_columnElem_156_3_9() {
-    if (jj_3R_identifier_268_3_1()) return true;
+  private boolean jj_3R_copyOptionElement_211_5_15() {
+    if (jj_scan_token(O_FORMAT)) return true;
+    if (jj_3R_formatType_259_5_25()) return true;
     return false;
   }
 
-  private boolean jj_3R_copyOptionList_199_5_12() {
+  private boolean jj_3R_singleChar_306_3_26() {
+    if (jj_scan_token(QUOTED_CHAR)) return true;
     return false;
   }
 
-  private boolean jj_3R_columnList_150_5_8() {
-    if (jj_3R_columnElem_156_3_4()) return true;
+  private boolean jj_3_1() {
+    if (jj_3R_CopyStmt_119_3_1()) return true;
     return false;
   }
 
-  private boolean jj_3R_copyOptionElement_243_5_22() {
-    if (jj_scan_token(O_ENCODING)) return true;
+  private boolean jj_3R_copyOptionGenericList_200_5_14() {
+    if (jj_3R_copyOptionElement_211_5_7()) return true;
     return false;
   }
 
-  private boolean jj_3R_copyOptionList_197_3_11() {
-    if (jj_3R_copyOptionElement_203_5_13()) return true;
+  private boolean jj_3R_quotedIdentifier_293_5_10() {
+    if (jj_scan_token(QUOTED_IDENTIFIER)) return true;
     return false;
   }
 
-  private boolean jj_3R_copyOptionList_197_3_5() {
+  private boolean jj_3R_copyOptionGenericList_198_3_6() {
     Token xsp;
     xsp = jj_scanpos;
-    if (jj_3R_copyOptionList_197_3_11()) {
+    if (jj_3_7()) {
       jj_scanpos = xsp;
-      if (jj_3R_copyOptionList_199_5_12()) return true;
+      if (jj_3R_copyOptionGenericList_200_5_14()) return true;
     }
     return false;
   }
 
-  private boolean jj_3_4() {
-    if (jj_3R_columnElem_156_3_4()) return true;
+  private boolean jj_3_7() {
+    if (jj_3R_copyOptionElement_211_5_7()) return true;
     if (jj_scan_token(44)) return true;
+    if (jj_3R_copyOptionGenericList_198_3_6()) return true;
     return false;
   }
 
-  private boolean jj_3R_columnList_148_3_3() {
+  private boolean jj_3R_quotedIdentifier_289_5_3() {
     Token xsp;
     xsp = jj_scanpos;
-    if (jj_3_4()) {
+    if (jj_3R_quotedIdentifier_289_5_9()) {
       jj_scanpos = xsp;
-      if (jj_3R_columnList_150_5_8()) return true;
+      if (jj_3R_quotedIdentifier_293_5_10()) return true;
     }
     return false;
   }
 
-  private boolean jj_3_8() {
-    if (jj_scan_token(O_FORCE_NULL)) return true;
-    if (jj_scan_token(42)) return true;
-    if (jj_3R_columnList_148_3_3()) return true;
-    return false;
-  }
-
-  private boolean jj_3R_quotedIdentifier_285_5_7() {
-    if (jj_scan_token(QUOTED_IDENTIFIER)) return true;
-    return false;
-  }
-
-  private boolean jj_3_5() {
-    if (jj_scan_token(42)) return true;
-    if (jj_3R_copyOptionList_197_3_5()) return true;
-    if (jj_scan_token(43)) return true;
-    return false;
-  }
-
-  private boolean jj_3R_quotedIdentifier_281_5_2() {
-    Token xsp;
-    xsp = jj_scanpos;
-    if (jj_3R_quotedIdentifier_281_5_6()) {
-      jj_scanpos = xsp;
-      if (jj_3R_quotedIdentifier_285_5_7()) return true;
-    }
-    return false;
-  }
-
-  private boolean jj_3R_quotedIdentifier_281_5_6() {
+  private boolean jj_3R_quotedIdentifier_289_5_9() {
     if (jj_scan_token(UNICODE)) return true;
     return false;
   }
 
-  private boolean jj_3_7() {
-    if (jj_scan_token(O_FORCE_NOT_NULL)) return true;
-    if (jj_scan_token(42)) return true;
-    if (jj_3R_columnList_148_3_3()) return true;
-    return false;
-  }
-
-  private boolean jj_3_3() {
+  private boolean jj_3_6() {
     if (jj_scan_token(42)) return true;
-    if (jj_3R_columnList_148_3_3()) return true;
+    if (jj_3R_copyOptionGenericList_198_3_6()) return true;
+    if (jj_scan_token(43)) return true;
     return false;
   }
 
@@ -1208,7 +1385,7 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
   private Token jj_scanpos, jj_lastpos;
   private int jj_la;
   private int jj_gen;
-  private final int[] jj_la1 = new int[12];
+  private final int[] jj_la1 = new int[14];
   private static int[] jj_la1_0;
   private static int[] jj_la1_1;
 
@@ -1220,17 +1397,19 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
   private static void jj_la1_init_0() {
     jj_la1_0 =
         new int[] {
-          0x20000000,
-          0x20000000,
-          0x20000000,
+          0x800,
+          0xc0000000,
+          0xc0000000,
+          0xc0000000,
           0x600,
-          0x180,
+          0x80000180,
           0x1000,
           0x7ffe000,
+          0x7ffe000,
           0x7fe000,
           0x4000000,
           0xe000,
-          0x20000000,
+          0x40000000,
           0x18000000,
         };
   }
@@ -1238,11 +1417,11 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
   private static void jj_la1_init_1() {
     jj_la1_1 =
         new int[] {
-          0x6, 0x6, 0x6, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0,
+          0x0, 0x10, 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0,
         };
   }
 
-  private final JJCalls[] jj_2_rtns = new JJCalls[8];
+  private final JJCalls[] jj_2_rtns = new JJCalls[10];
   private boolean jj_rescan = false;
   private int jj_gc = 0;
 
@@ -1261,7 +1440,7 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
     token = new Token();
     jj_ntk = -1;
     jj_gen = 0;
-    for (int i = 0; i < 12; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 14; i++) jj_la1[i] = -1;
     for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
   }
 
@@ -1281,7 +1460,7 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
     jj_ntk = -1;
     jjtree.reset();
     jj_gen = 0;
-    for (int i = 0; i < 12; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 14; i++) jj_la1[i] = -1;
     for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
   }
 
@@ -1292,7 +1471,7 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
     token = new Token();
     jj_ntk = -1;
     jj_gen = 0;
-    for (int i = 0; i < 12; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 14; i++) jj_la1[i] = -1;
     for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
   }
 
@@ -1312,7 +1491,7 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
     jj_ntk = -1;
     jjtree.reset();
     jj_gen = 0;
-    for (int i = 0; i < 12; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 14; i++) jj_la1[i] = -1;
     for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
   }
 
@@ -1322,7 +1501,7 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
     token = new Token();
     jj_ntk = -1;
     jj_gen = 0;
-    for (int i = 0; i < 12; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 14; i++) jj_la1[i] = -1;
     for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
   }
 
@@ -1333,7 +1512,7 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
     jj_ntk = -1;
     jjtree.reset();
     jj_gen = 0;
-    for (int i = 0; i < 12; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 14; i++) jj_la1[i] = -1;
     for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
   }
 
@@ -1472,7 +1651,7 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
       la1tokens[jj_kind] = true;
       jj_kind = -1;
     }
-    for (int i = 0; i < 12; i++) {
+    for (int i = 0; i < 14; i++) {
       if (jj_la1[i] == jj_gen) {
         for (int j = 0; j < 32; j++) {
           if ((jj_la1_0[i] & (1 << j)) != 0) {
@@ -1516,7 +1695,7 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
 
   private void jj_rescan_token() {
     jj_rescan = true;
-    for (int i = 0; i < 8; i++) {
+    for (int i = 0; i < 10; i++) {
       try {
         JJCalls p = jj_2_rtns[i];
 
@@ -1549,6 +1728,12 @@ public class Copy /*@bgen(jjtree)*/ implements CopyTreeConstants, CopyConstants
               case 7:
                 jj_3_8();
                 break;
+              case 8:
+                jj_3_9();
+                break;
+              case 9:
+                jj_3_10();
+                break;
             }
           }
           p = p.next;
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/parsers/copy/CopyConstants.java b/src/main/java/com/google/cloud/spanner/pgadapter/parsers/copy/CopyConstants.java
index f01c7511..27c920df 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/parsers/copy/CopyConstants.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/parsers/copy/CopyConstants.java
@@ -51,27 +51,27 @@ public interface CopyConstants {
   /** RegularExpression Id. */
   int O_FALSE = 28;
   /** RegularExpression Id. */
-  int UNICODE = 29;
+  int QUOTED_CHAR = 29;
   /** RegularExpression Id. */
-  int CODEPOINT_LIST = 30;
+  int QUOTED_IDENTIFIER = 30;
   /** RegularExpression Id. */
-  int CODEPOINT = 31;
+  int IDENTIFIER = 31;
   /** RegularExpression Id. */
-  int HEX = 32;
+  int SINGLE_CHAR = 32;
   /** RegularExpression Id. */
-  int QUOTED_IDENTIFIER = 33;
+  int DIGIT = 33;
   /** RegularExpression Id. */
-  int IDENTIFIER = 34;
+  int LETTER = 34;
   /** RegularExpression Id. */
-  int QUOTED_CHAR = 35;
+  int LOWER_CASE_LETTER = 35;
   /** RegularExpression Id. */
-  int SINGLE_CHAR = 36;
+  int UNICODE = 36;
   /** RegularExpression Id. */
-  int DIGIT = 37;
+  int CODEPOINT_LIST = 37;
   /** RegularExpression Id. */
-  int LETTER = 38;
+  int CODEPOINT = 38;
   /** RegularExpression Id. */
-  int LOWER_CASE_LETTER = 39;
+  int HEX = 39;
 
   /** Lexical state. */
   int DEFAULT = 0;
@@ -107,17 +107,17 @@ public interface CopyConstants {
     "\"ENCODING\"",
     "\"TRUE\"",
     "\"FALSE\"",
-    "<UNICODE>",
-    "<CODEPOINT_LIST>",
-    "<CODEPOINT>",
-    "<HEX>",
+    "<QUOTED_CHAR>",
     "<QUOTED_IDENTIFIER>",
     "<IDENTIFIER>",
-    "<QUOTED_CHAR>",
     "<SINGLE_CHAR>",
     "<DIGIT>",
     "<LETTER>",
     "<LOWER_CASE_LETTER>",
+    "<UNICODE>",
+    "<CODEPOINT_LIST>",
+    "<CODEPOINT>",
+    "<HEX>",
     "\";\"",
     "\".\"",
     "\"(\"",
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/parsers/copy/CopyTokenManager.java b/src/main/java/com/google/cloud/spanner/pgadapter/parsers/copy/CopyTokenManager.java
index e01e7a02..bb52adaf 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/parsers/copy/CopyTokenManager.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/parsers/copy/CopyTokenManager.java
@@ -23,31 +23,31 @@ public class CopyTokenManager implements CopyConstants {
     switch (curChar) {
       case 9:
         jjmatchedKind = 2;
-        return jjMoveNfa_0(27, 0);
+        return jjMoveNfa_0(0, 0);
       case 10:
         jjmatchedKind = 3;
-        return jjMoveNfa_0(27, 0);
+        return jjMoveNfa_0(0, 0);
       case 13:
         jjmatchedKind = 4;
-        return jjMoveNfa_0(27, 0);
+        return jjMoveNfa_0(0, 0);
       case 32:
         jjmatchedKind = 1;
-        return jjMoveNfa_0(27, 0);
+        return jjMoveNfa_0(0, 0);
       case 40:
         jjmatchedKind = 42;
-        return jjMoveNfa_0(27, 0);
+        return jjMoveNfa_0(0, 0);
       case 41:
         jjmatchedKind = 43;
-        return jjMoveNfa_0(27, 0);
+        return jjMoveNfa_0(0, 0);
       case 44:
         jjmatchedKind = 44;
-        return jjMoveNfa_0(27, 0);
+        return jjMoveNfa_0(0, 0);
       case 46:
         jjmatchedKind = 41;
-        return jjMoveNfa_0(27, 0);
+        return jjMoveNfa_0(0, 0);
       case 59:
         jjmatchedKind = 40;
-        return jjMoveNfa_0(27, 0);
+        return jjMoveNfa_0(0, 0);
       case 66:
         return jjMoveStringLiteralDfa1_0(0x2000L);
       case 67:
@@ -93,7 +93,7 @@ public class CopyTokenManager implements CopyConstants {
       case 119:
         return jjMoveStringLiteralDfa1_0(0x1000L);
       default:
-        return jjMoveNfa_0(27, 0);
+        return jjMoveNfa_0(0, 0);
     }
   }
 
@@ -101,7 +101,7 @@ public class CopyTokenManager implements CopyConstants {
     try {
       curChar = input_stream.readChar();
     } catch (java.io.IOException e) {
-      return jjMoveNfa_0(27, 0);
+      return jjMoveNfa_0(0, 0);
     }
     switch (curChar) {
       case 65:
@@ -151,15 +151,15 @@ public class CopyTokenManager implements CopyConstants {
       default:
         break;
     }
-    return jjMoveNfa_0(27, 1);
+    return jjMoveNfa_0(0, 1);
   }
 
   private int jjMoveStringLiteralDfa2_0(long old0, long active0) {
-    if (((active0 &= old0)) == 0L) return jjMoveNfa_0(27, 1);
+    if (((active0 &= old0)) == 0L) return jjMoveNfa_0(0, 1);
     try {
       curChar = input_stream.readChar();
     } catch (java.io.IOException e) {
-      return jjMoveNfa_0(27, 1);
+      return jjMoveNfa_0(0, 1);
     }
     switch (curChar) {
       case 65:
@@ -225,15 +225,15 @@ public class CopyTokenManager implements CopyConstants {
       default:
         break;
     }
-    return jjMoveNfa_0(27, 2);
+    return jjMoveNfa_0(0, 2);
   }
 
   private int jjMoveStringLiteralDfa3_0(long old0, long active0) {
-    if (((active0 &= old0)) == 0L) return jjMoveNfa_0(27, 2);
+    if (((active0 &= old0)) == 0L) return jjMoveNfa_0(0, 2);
     try {
       curChar = input_stream.readChar();
     } catch (java.io.IOException e) {
-      return jjMoveNfa_0(27, 2);
+      return jjMoveNfa_0(0, 2);
     }
     switch (curChar) {
       case 65:
@@ -335,15 +335,15 @@ public class CopyTokenManager implements CopyConstants {
       default:
         break;
     }
-    return jjMoveNfa_0(27, 3);
+    return jjMoveNfa_0(0, 3);
   }
 
   private int jjMoveStringLiteralDfa4_0(long old0, long active0) {
-    if (((active0 &= old0)) == 0L) return jjMoveNfa_0(27, 3);
+    if (((active0 &= old0)) == 0L) return jjMoveNfa_0(0, 3);
     try {
       curChar = input_stream.readChar();
     } catch (java.io.IOException e) {
-      return jjMoveNfa_0(27, 3);
+      return jjMoveNfa_0(0, 3);
     }
     switch (curChar) {
       case 65:
@@ -407,15 +407,15 @@ public class CopyTokenManager implements CopyConstants {
       default:
         break;
     }
-    return jjMoveNfa_0(27, 4);
+    return jjMoveNfa_0(0, 4);
   }
 
   private int jjMoveStringLiteralDfa5_0(long old0, long active0) {
-    if (((active0 &= old0)) == 0L) return jjMoveNfa_0(27, 4);
+    if (((active0 &= old0)) == 0L) return jjMoveNfa_0(0, 4);
     try {
       curChar = input_stream.readChar();
     } catch (java.io.IOException e) {
-      return jjMoveNfa_0(27, 4);
+      return jjMoveNfa_0(0, 4);
     }
     switch (curChar) {
       case 69:
@@ -487,15 +487,15 @@ public class CopyTokenManager implements CopyConstants {
       default:
         break;
     }
-    return jjMoveNfa_0(27, 5);
+    return jjMoveNfa_0(0, 5);
   }
 
   private int jjMoveStringLiteralDfa6_0(long old0, long active0) {
-    if (((active0 &= old0)) == 0L) return jjMoveNfa_0(27, 5);
+    if (((active0 &= old0)) == 0L) return jjMoveNfa_0(0, 5);
     try {
       curChar = input_stream.readChar();
     } catch (java.io.IOException e) {
-      return jjMoveNfa_0(27, 5);
+      return jjMoveNfa_0(0, 5);
     }
     switch (curChar) {
       case 78:
@@ -513,15 +513,15 @@ public class CopyTokenManager implements CopyConstants {
       default:
         break;
     }
-    return jjMoveNfa_0(27, 6);
+    return jjMoveNfa_0(0, 6);
   }
 
   private int jjMoveStringLiteralDfa7_0(long old0, long active0) {
-    if (((active0 &= old0)) == 0L) return jjMoveNfa_0(27, 6);
+    if (((active0 &= old0)) == 0L) return jjMoveNfa_0(0, 6);
     try {
       curChar = input_stream.readChar();
     } catch (java.io.IOException e) {
-      return jjMoveNfa_0(27, 6);
+      return jjMoveNfa_0(0, 6);
     }
     switch (curChar) {
       case 69:
@@ -551,15 +551,15 @@ public class CopyTokenManager implements CopyConstants {
       default:
         break;
     }
-    return jjMoveNfa_0(27, 7);
+    return jjMoveNfa_0(0, 7);
   }
 
   private int jjMoveStringLiteralDfa8_0(long old0, long active0) {
-    if (((active0 &= old0)) == 0L) return jjMoveNfa_0(27, 7);
+    if (((active0 &= old0)) == 0L) return jjMoveNfa_0(0, 7);
     try {
       curChar = input_stream.readChar();
     } catch (java.io.IOException e) {
-      return jjMoveNfa_0(27, 7);
+      return jjMoveNfa_0(0, 7);
     }
     switch (curChar) {
       case 76:
@@ -589,15 +589,15 @@ public class CopyTokenManager implements CopyConstants {
       default:
         break;
     }
-    return jjMoveNfa_0(27, 8);
+    return jjMoveNfa_0(0, 8);
   }
 
   private int jjMoveStringLiteralDfa9_0(long old0, long active0) {
-    if (((active0 &= old0)) == 0L) return jjMoveNfa_0(27, 8);
+    if (((active0 &= old0)) == 0L) return jjMoveNfa_0(0, 8);
     try {
       curChar = input_stream.readChar();
     } catch (java.io.IOException e) {
-      return jjMoveNfa_0(27, 8);
+      return jjMoveNfa_0(0, 8);
     }
     switch (curChar) {
       case 76:
@@ -621,15 +621,15 @@ public class CopyTokenManager implements CopyConstants {
       default:
         break;
     }
-    return jjMoveNfa_0(27, 9);
+    return jjMoveNfa_0(0, 9);
   }
 
   private int jjMoveStringLiteralDfa10_0(long old0, long active0) {
-    if (((active0 &= old0)) == 0L) return jjMoveNfa_0(27, 9);
+    if (((active0 &= old0)) == 0L) return jjMoveNfa_0(0, 9);
     try {
       curChar = input_stream.readChar();
     } catch (java.io.IOException e) {
-      return jjMoveNfa_0(27, 9);
+      return jjMoveNfa_0(0, 9);
     }
     switch (curChar) {
       case 69:
@@ -651,15 +651,15 @@ public class CopyTokenManager implements CopyConstants {
       default:
         break;
     }
-    return jjMoveNfa_0(27, 10);
+    return jjMoveNfa_0(0, 10);
   }
 
   private int jjMoveStringLiteralDfa11_0(long old0, long active0) {
-    if (((active0 &= old0)) == 0L) return jjMoveNfa_0(27, 10);
+    if (((active0 &= old0)) == 0L) return jjMoveNfa_0(0, 10);
     try {
       curChar = input_stream.readChar();
     } catch (java.io.IOException e) {
-      return jjMoveNfa_0(27, 10);
+      return jjMoveNfa_0(0, 10);
     }
     switch (curChar) {
       case 85:
@@ -669,15 +669,15 @@ public class CopyTokenManager implements CopyConstants {
       default:
         break;
     }
-    return jjMoveNfa_0(27, 11);
+    return jjMoveNfa_0(0, 11);
   }
 
   private int jjMoveStringLiteralDfa12_0(long old0, long active0) {
-    if (((active0 &= old0)) == 0L) return jjMoveNfa_0(27, 11);
+    if (((active0 &= old0)) == 0L) return jjMoveNfa_0(0, 11);
     try {
       curChar = input_stream.readChar();
     } catch (java.io.IOException e) {
-      return jjMoveNfa_0(27, 11);
+      return jjMoveNfa_0(0, 11);
     }
     switch (curChar) {
       case 76:
@@ -687,15 +687,15 @@ public class CopyTokenManager implements CopyConstants {
       default:
         break;
     }
-    return jjMoveNfa_0(27, 12);
+    return jjMoveNfa_0(0, 12);
   }
 
   private int jjMoveStringLiteralDfa13_0(long old0, long active0) {
-    if (((active0 &= old0)) == 0L) return jjMoveNfa_0(27, 12);
+    if (((active0 &= old0)) == 0L) return jjMoveNfa_0(0, 12);
     try {
       curChar = input_stream.readChar();
     } catch (java.io.IOException e) {
-      return jjMoveNfa_0(27, 12);
+      return jjMoveNfa_0(0, 12);
     }
     switch (curChar) {
       case 76:
@@ -713,7 +713,7 @@ public class CopyTokenManager implements CopyConstants {
       default:
         break;
     }
-    return jjMoveNfa_0(27, 13);
+    return jjMoveNfa_0(0, 13);
   }
 
   static final long[] jjbitVec0 = {0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL};
@@ -730,7 +730,7 @@ public class CopyTokenManager implements CopyConstants {
     }
     curPos = 0;
     int startsAt = 0;
-    jjnewStateCnt = 80;
+    jjnewStateCnt = 76;
     int i = 1;
     jjstateSet[0] = startState;
     int kind = 0x7fffffff;
@@ -740,7 +740,7 @@ public class CopyTokenManager implements CopyConstants {
         long l = 1L << curChar;
         do {
           switch (jjstateSet[--i]) {
-            case 27:
+            case 0:
               if (curChar == 39) {
                 jjAddStates(0, 1);
               } else if (curChar == 34) {
@@ -749,24 +749,20 @@ public class CopyTokenManager implements CopyConstants {
                 jjAddStates(4, 5);
               }
               break;
-            case 0:
-              if (curChar == 38) {
-                jjAddStates(6, 7);
-              }
-              break;
             case 1:
-              if (curChar == 34) {
-                jjCheckNAddTwoStates(2, 4);
-              }
+              if ((0x3ff000000000000L & l) == 0L) break;
+              if (kind > 31) kind = 31;
+              jjstateSet[jjnewStateCnt++] = 1;
               break;
             case 2:
-            case 10:
-              if ((0x3ff000000000000L & l) != 0L) {
-                jjCheckNAddStates(8, 10);
+              if (curChar == 38) {
+                jjAddStates(6, 7);
               }
               break;
             case 3:
-              if (curChar == 34 && kind > 29) kind = 29;
+              if (curChar == 34) {
+                jjCheckNAdd(4);
+              }
               break;
             case 5:
               if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 6;
@@ -775,54 +771,61 @@ public class CopyTokenManager implements CopyConstants {
               if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 7;
               break;
             case 7:
-              if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 8;
+            case 14:
+              if ((0x3ff000000000000L & l) != 0L) {
+                jjCheckNAdd(8);
+              }
               break;
             case 8:
-              if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 9;
-              break;
-            case 9:
-            case 13:
               if ((0x3ff000000000000L & l) != 0L) {
-                jjCheckNAdd(10);
+                jjCheckNAddTwoStates(9, 4);
               }
               break;
+            case 9:
+              if (curChar == 34 && kind > 36) kind = 36;
+              break;
+            case 10:
+              if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 11;
+              break;
             case 11:
               if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 12;
               break;
             case 12:
               if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 13;
               break;
-            case 14:
-              if (curChar == 39) {
-                jjCheckNAddTwoStates(15, 17);
-              }
+            case 13:
+              if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 14;
               break;
             case 15:
-            case 23:
-              if ((0x3ff000000000000L & l) != 0L) {
-                jjCheckNAddStates(11, 13);
+              if (curChar == 39) {
+                jjCheckNAdd(16);
               }
               break;
-            case 16:
-              if (curChar == 39 && kind > 29) kind = 29;
+            case 17:
+              if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 18;
               break;
             case 18:
               if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 19;
               break;
             case 19:
-              if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 20;
+            case 26:
+              if ((0x3ff000000000000L & l) != 0L) {
+                jjCheckNAdd(20);
+              }
               break;
             case 20:
-              if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 21;
+              if ((0x3ff000000000000L & l) != 0L) {
+                jjCheckNAddTwoStates(21, 16);
+              }
               break;
             case 21:
-              if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 22;
+              if (curChar == 39 && kind > 36) kind = 36;
               break;
             case 22:
-            case 26:
-              if ((0x3ff000000000000L & l) != 0L) {
-                jjCheckNAdd(23);
-              }
+              if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 23;
+              break;
+            case 23:
+              if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 24;
               break;
             case 24:
               if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 25;
@@ -832,60 +835,64 @@ public class CopyTokenManager implements CopyConstants {
               break;
             case 28:
               if (curChar == 38) {
-                jjAddStates(14, 15);
+                jjAddStates(8, 9);
               }
               break;
             case 29:
               if (curChar == 34) {
-                jjCheckNAddTwoStates(30, 31);
+                jjCheckNAdd(30);
               }
               break;
-            case 30:
-            case 37:
-              if ((0x3ff000000000000L & l) != 0L) {
-                jjCheckNAddStates(16, 18);
-              }
+            case 31:
+              if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 32;
               break;
             case 32:
               if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 33;
               break;
             case 33:
-              if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 34;
+            case 39:
+              if ((0x3ff000000000000L & l) != 0L) {
+                jjCheckNAdd(34);
+              }
               break;
             case 34:
-              if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 35;
+              if ((0x3ff000000000000L & l) != 0L) {
+                jjCheckNAddTwoStates(9, 30);
+              }
               break;
             case 35:
               if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 36;
               break;
             case 36:
-            case 40:
-              if ((0x3ff000000000000L & l) != 0L) {
-                jjCheckNAdd(37);
-              }
+              if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 37;
+              break;
+            case 37:
+              if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 38;
               break;
             case 38:
               if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 39;
               break;
-            case 39:
-              if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 40;
-              break;
-            case 41:
+            case 40:
               if (curChar == 39) {
-                jjCheckNAddTwoStates(42, 43);
+                jjCheckNAdd(41);
               }
               break;
             case 42:
-            case 49:
-              if ((0x3ff000000000000L & l) != 0L) {
-                jjCheckNAddStates(19, 21);
-              }
+              if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 43;
+              break;
+            case 43:
+              if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 44;
               break;
             case 44:
-              if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 45;
+            case 50:
+              if ((0x3ff000000000000L & l) != 0L) {
+                jjCheckNAdd(45);
+              }
               break;
             case 45:
-              if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 46;
+              if ((0x3ff000000000000L & l) != 0L) {
+                jjCheckNAddTwoStates(21, 41);
+              }
               break;
             case 46:
               if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 47;
@@ -894,111 +901,100 @@ public class CopyTokenManager implements CopyConstants {
               if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 48;
               break;
             case 48:
-            case 52:
-              if ((0x3ff000000000000L & l) != 0L) {
-                jjCheckNAdd(49);
-              }
-              break;
-            case 50:
-              if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 51;
-              break;
-            case 51:
-              if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 52;
+              if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 49;
               break;
-            case 55:
-              if ((0x3ff000000000000L & l) == 0L) break;
-              if (kind > 34) kind = 34;
-              jjstateSet[jjnewStateCnt++] = 55;
+            case 49:
+              if ((0x3ff000000000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 50;
               break;
-            case 56:
+            case 52:
               if (curChar == 47) {
                 jjAddStates(4, 5);
               }
               break;
-            case 57:
+            case 53:
               if (curChar == 47) {
-                jjCheckNAddStates(22, 24);
+                jjCheckNAddStates(10, 12);
               }
               break;
-            case 58:
+            case 54:
               if ((0xffffffffffffdbffL & l) != 0L) {
-                jjCheckNAddStates(22, 24);
+                jjCheckNAddStates(10, 12);
               }
               break;
-            case 59:
+            case 55:
               if ((0x2400L & l) != 0L && kind > 5) kind = 5;
               break;
-            case 60:
+            case 56:
               if (curChar == 10 && kind > 5) kind = 5;
               break;
-            case 61:
-              if (curChar == 13) jjstateSet[jjnewStateCnt++] = 60;
+            case 57:
+              if (curChar == 13) jjstateSet[jjnewStateCnt++] = 56;
               break;
-            case 62:
+            case 58:
               if (curChar == 42) {
-                jjCheckNAddTwoStates(63, 64);
+                jjCheckNAddTwoStates(59, 60);
               }
               break;
-            case 63:
+            case 59:
               if ((0xfffffbffffffffffL & l) != 0L) {
-                jjCheckNAddTwoStates(63, 64);
+                jjCheckNAddTwoStates(59, 60);
               }
               break;
-            case 64:
+            case 60:
               if (curChar == 42) {
-                jjAddStates(25, 26);
+                jjAddStates(13, 14);
               }
               break;
-            case 65:
+            case 61:
               if ((0xffff7fffffffffffL & l) != 0L) {
-                jjCheckNAddTwoStates(66, 64);
+                jjCheckNAddTwoStates(62, 60);
               }
               break;
-            case 66:
+            case 62:
               if ((0xfffffbffffffffffL & l) != 0L) {
-                jjCheckNAddTwoStates(66, 64);
+                jjCheckNAddTwoStates(62, 60);
               }
               break;
-            case 67:
+            case 63:
               if (curChar == 47 && kind > 6) kind = 6;
               break;
-            case 68:
+            case 64:
               if (curChar == 34) {
                 jjAddStates(2, 3);
               }
               break;
-            case 70:
-              if ((0x3ff000000000000L & l) != 0L) {
-                jjAddStates(27, 28);
-              }
+            case 65:
+              if ((0xfffffffe00000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 66;
               break;
-            case 71:
-              if (curChar == 34 && kind > 33) kind = 33;
+            case 66:
+              if (curChar == 34 && kind > 29) kind = 29;
               break;
-            case 72:
-              if ((0xf400fcfe00000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 73;
+            case 68:
+              if ((0x3ff000000000000L & l) != 0L) {
+                jjAddStates(15, 16);
+              }
               break;
-            case 73:
-              if (curChar == 34 && kind > 35) kind = 35;
+            case 69:
+              if (curChar == 34 && kind > 30) kind = 30;
               break;
-            case 74:
+            case 70:
               if (curChar == 39) {
                 jjAddStates(0, 1);
               }
               break;
-            case 76:
-              if ((0x3ff000000000000L & l) != 0L) {
-                jjAddStates(29, 30);
-              }
+            case 71:
+              if ((0xfffffffe00000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 72;
               break;
-            case 77:
-              if (curChar == 39 && kind > 33) kind = 33;
+            case 72:
+              if (curChar == 39 && kind > 29) kind = 29;
               break;
-            case 78:
-              if ((0xf400fcfe00000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 79;
+            case 74:
+              if ((0x3ff000000000000L & l) != 0L) {
+                jjAddStates(17, 18);
+              }
               break;
-            case 79:
-              if (curChar == 39 && kind > 35) kind = 35;
+            case 75:
+              if (curChar == 39 && kind > 30) kind = 30;
               break;
             default:
               break;
@@ -1008,24 +1004,26 @@ public class CopyTokenManager implements CopyConstants {
         long l = 1L << (curChar & 077);
         do {
           switch (jjstateSet[--i]) {
-            case 27:
+            case 0:
               if ((0x7fffffe87fffffeL & l) != 0L) {
-                if (kind > 34) kind = 34;
+                if (kind > 31) kind = 31;
                 {
-                  jjCheckNAdd(55);
+                  jjCheckNAdd(1);
                 }
               }
               if (curChar == 117) jjstateSet[jjnewStateCnt++] = 28;
-              else if (curChar == 85) jjstateSet[jjnewStateCnt++] = 0;
+              else if (curChar == 85) jjstateSet[jjnewStateCnt++] = 2;
               break;
-            case 2:
-              if ((0x7fffffe87fffffeL & l) != 0L) {
-                jjCheckNAddStates(8, 10);
+            case 1:
+              if ((0x7fffffe87fffffeL & l) == 0L) break;
+              if (kind > 31) kind = 31;
+              {
+                jjCheckNAdd(1);
               }
               break;
             case 4:
               if (curChar == 92) {
-                jjAddStates(31, 32);
+                jjAddStates(19, 20);
               }
               break;
             case 5:
@@ -1035,21 +1033,18 @@ public class CopyTokenManager implements CopyConstants {
               if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 7;
               break;
             case 7:
-              if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 8;
+            case 14:
+              if ((0x7e0000007eL & l) != 0L) {
+                jjCheckNAdd(8);
+              }
               break;
             case 8:
-              if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 9;
-              break;
-            case 9:
-            case 13:
               if ((0x7e0000007eL & l) != 0L) {
-                jjCheckNAdd(10);
+                jjCheckNAddTwoStates(9, 4);
               }
               break;
             case 10:
-              if ((0x7e0000007eL & l) != 0L) {
-                jjCheckNAddStates(8, 10);
-              }
+              if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 11;
               break;
             case 11:
               if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 12;
@@ -1057,99 +1052,101 @@ public class CopyTokenManager implements CopyConstants {
             case 12:
               if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 13;
               break;
-            case 15:
-              if ((0x7fffffe87fffffeL & l) != 0L) {
-                jjCheckNAddStates(11, 13);
-              }
+            case 13:
+              if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 14;
               break;
-            case 17:
+            case 16:
               if (curChar == 92) {
-                jjAddStates(33, 34);
+                jjAddStates(21, 22);
               }
               break;
+            case 17:
+              if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 18;
+              break;
             case 18:
               if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 19;
               break;
             case 19:
-              if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 20;
-              break;
-            case 20:
-              if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 21;
-              break;
-            case 21:
-              if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 22;
-              break;
-            case 22:
             case 26:
               if ((0x7e0000007eL & l) != 0L) {
-                jjCheckNAdd(23);
+                jjCheckNAdd(20);
               }
               break;
-            case 23:
+            case 20:
               if ((0x7e0000007eL & l) != 0L) {
-                jjCheckNAddStates(11, 13);
+                jjCheckNAddTwoStates(21, 16);
               }
               break;
+            case 22:
+              if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 23;
+              break;
+            case 23:
+              if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 24;
+              break;
             case 24:
               if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 25;
               break;
             case 25:
               if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 26;
               break;
+            case 27:
+              if (curChar == 85) jjstateSet[jjnewStateCnt++] = 2;
+              break;
             case 30:
-              if ((0x7fffffe87fffffeL & l) != 0L) {
-                jjCheckNAddStates(16, 18);
+              if (curChar == 92) {
+                jjAddStates(23, 24);
               }
               break;
             case 31:
-              if (curChar == 92) {
-                jjAddStates(35, 36);
-              }
+              if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 32;
               break;
             case 32:
               if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 33;
               break;
             case 33:
-              if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 34;
+            case 39:
+              if ((0x7e0000007eL & l) != 0L) {
+                jjCheckNAdd(34);
+              }
               break;
             case 34:
-              if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 35;
+              if ((0x7e0000007eL & l) != 0L) {
+                jjCheckNAddTwoStates(9, 30);
+              }
               break;
             case 35:
               if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 36;
               break;
             case 36:
-            case 40:
-              if ((0x7e0000007eL & l) != 0L) {
-                jjCheckNAdd(37);
-              }
+              if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 37;
               break;
             case 37:
-              if ((0x7e0000007eL & l) != 0L) {
-                jjCheckNAddStates(16, 18);
-              }
+              if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 38;
               break;
             case 38:
               if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 39;
               break;
-            case 39:
-              if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 40;
+            case 41:
+              if (curChar == 92) {
+                jjAddStates(25, 26);
+              }
               break;
             case 42:
-              if ((0x7fffffe87fffffeL & l) != 0L) {
-                jjCheckNAddStates(19, 21);
-              }
+              if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 43;
               break;
             case 43:
-              if (curChar == 92) {
-                jjAddStates(37, 38);
-              }
+              if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 44;
               break;
             case 44:
-              if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 45;
+            case 50:
+              if ((0x7e0000007eL & l) != 0L) {
+                jjCheckNAdd(45);
+              }
               break;
             case 45:
-              if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 46;
+              if ((0x7e0000007eL & l) != 0L) {
+                jjCheckNAddTwoStates(21, 41);
+              }
               break;
             case 46:
               if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 47;
@@ -1158,67 +1155,48 @@ public class CopyTokenManager implements CopyConstants {
               if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 48;
               break;
             case 48:
-            case 52:
-              if ((0x7e0000007eL & l) != 0L) {
-                jjCheckNAdd(49);
-              }
+              if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 49;
               break;
             case 49:
-              if ((0x7e0000007eL & l) != 0L) {
-                jjCheckNAddStates(19, 21);
-              }
-              break;
-            case 50:
-              if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 51;
+              if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 50;
               break;
             case 51:
-              if ((0x7e0000007eL & l) != 0L) jjstateSet[jjnewStateCnt++] = 52;
-              break;
-            case 53:
               if (curChar == 117) jjstateSet[jjnewStateCnt++] = 28;
               break;
             case 54:
-            case 55:
-              if ((0x7fffffe87fffffeL & l) == 0L) break;
-              if (kind > 34) kind = 34;
               {
-                jjCheckNAdd(55);
+                jjAddStates(10, 12);
               }
               break;
-            case 58:
+            case 59:
               {
-                jjAddStates(22, 24);
+                jjCheckNAddTwoStates(59, 60);
               }
               break;
-            case 63:
+            case 61:
+            case 62:
               {
-                jjCheckNAddTwoStates(63, 64);
+                jjCheckNAddTwoStates(62, 60);
               }
               break;
             case 65:
-            case 66:
-              {
-                jjCheckNAddTwoStates(66, 64);
-              }
+              if ((0x7fffffffffffffffL & l) != 0L) jjstateSet[jjnewStateCnt++] = 66;
               break;
-            case 69:
-            case 70:
+            case 67:
+            case 68:
               if ((0x7fffffe87fffffeL & l) != 0L) {
-                jjCheckNAddTwoStates(70, 71);
+                jjCheckNAddTwoStates(68, 69);
               }
               break;
-            case 72:
-              if ((0x1f8000001L & l) != 0L) jjstateSet[jjnewStateCnt++] = 73;
+            case 71:
+              if ((0x7fffffffffffffffL & l) != 0L) jjstateSet[jjnewStateCnt++] = 72;
               break;
-            case 75:
-            case 76:
+            case 73:
+            case 74:
               if ((0x7fffffe87fffffeL & l) != 0L) {
-                jjCheckNAddTwoStates(76, 77);
+                jjCheckNAddTwoStates(74, 75);
               }
               break;
-            case 78:
-              if ((0x1f8000001L & l) != 0L) jjstateSet[jjnewStateCnt++] = 79;
-              break;
             default:
               break;
           }
@@ -1228,20 +1206,20 @@ public class CopyTokenManager implements CopyConstants {
         long l2 = 1L << (curChar & 077);
         do {
           switch (jjstateSet[--i]) {
-            case 58:
+            case 54:
               if ((jjbitVec0[i2] & l2) != 0L) {
-                jjAddStates(22, 24);
+                jjAddStates(10, 12);
               }
               break;
-            case 63:
+            case 59:
               if ((jjbitVec0[i2] & l2) != 0L) {
-                jjCheckNAddTwoStates(63, 64);
+                jjCheckNAddTwoStates(59, 60);
               }
               break;
-            case 65:
-            case 66:
+            case 61:
+            case 62:
               if ((jjbitVec0[i2] & l2) != 0L) {
-                jjCheckNAddTwoStates(66, 64);
+                jjCheckNAddTwoStates(62, 60);
               }
               break;
             default:
@@ -1255,7 +1233,7 @@ public class CopyTokenManager implements CopyConstants {
         kind = 0x7fffffff;
       }
       ++curPos;
-      if ((i = jjnewStateCnt) == (startsAt = 80 - (jjnewStateCnt = startsAt))) break;
+      if ((i = jjnewStateCnt) == (startsAt = 76 - (jjnewStateCnt = startsAt))) break;
       try {
         curChar = input_stream.readChar();
       } catch (java.io.IOException e) {
@@ -1313,9 +1291,8 @@ public class CopyTokenManager implements CopyConstants {
   }
 
   static final int[] jjnextStates = {
-    75, 78, 69, 72, 57, 62, 1, 14, 2, 3, 4, 15, 16, 17, 29, 41,
-    30, 3, 31, 42, 16, 43, 58, 59, 61, 65, 67, 70, 71, 76, 77, 5,
-    11, 18, 24, 32, 38, 44, 50,
+    71, 73, 65, 67, 53, 58, 3, 15, 29, 40, 54, 55, 57, 61, 63, 68, 69, 74, 75, 5, 10, 17, 22, 31,
+    35, 42, 46,
   };
 
   int curLexState = 0;
@@ -1457,7 +1434,7 @@ public class CopyTokenManager implements CopyConstants {
   private void ReInitRounds() {
     int i;
     jjround = 0x80000001;
-    for (i = 80; i-- > 0; ) jjrounds[i] = 0x80000000;
+    for (i = 76; i-- > 0; ) jjrounds[i] = 0x80000000;
   }
 
   /** Reinitialise parser. */
@@ -1488,7 +1465,7 @@ public class CopyTokenManager implements CopyConstants {
   };
 
   static final long[] jjtoToken = {
-    0x1f0e3fffff81L,
+    0x1f10ffffff81L,
   };
   static final long[] jjtoSkip = {
     0x7eL,
@@ -1501,8 +1478,8 @@ public class CopyTokenManager implements CopyConstants {
   };
   protected SimpleCharStream input_stream;
 
-  private final int[] jjrounds = new int[80];
-  private final int[] jjstateSet = new int[2 * 80];
+  private final int[] jjrounds = new int[76];
+  private final int[] jjstateSet = new int[2 * 76];
   private final StringBuilder jjimage = new StringBuilder();
   private StringBuilder image = jjimage;
   private int jjimageLen;
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/statements/CopyStatement.java b/src/main/java/com/google/cloud/spanner/pgadapter/statements/CopyStatement.java
index 719edec5..532f7a4f 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/statements/CopyStatement.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/statements/CopyStatement.java
@@ -18,6 +18,7 @@ import static com.google.cloud.spanner.pgadapter.parsers.copy.Copy.parse;
 import static com.google.cloud.spanner.pgadapter.parsers.copy.CopyTreeParser.CopyOptions.Format;
 
 import com.google.cloud.spanner.pgadapter.parsers.copy.CopyTreeParser;
+import com.google.cloud.spanner.pgadapter.parsers.copy.TokenMgrError;
 import com.google.cloud.spanner.pgadapter.utils.MutationWriter;
 import com.google.cloud.spanner.pgadapter.utils.StatementParser;
 import com.google.common.base.Strings;
@@ -75,9 +76,7 @@ public class CopyStatement extends IntermediateStatement {
     if (options.getQuote() != '\0') {
       this.format = this.format.withQuote(options.getQuote());
     }
-    // if(options.hasHeader()) {
     this.format = this.format.withHeader(this.tableColumns.keySet().toArray(new String[0]));
-    // }
   }
 
   public CSVFormat getParserFormat() {
@@ -240,7 +239,7 @@ public class CopyStatement extends IntermediateStatement {
   private void parseCopyStatement() throws Exception {
     try {
       parse(sql, this.options);
-    } catch (Exception e) {
+    } catch (Exception | TokenMgrError e) {
       throw new SQLException("Invalid COPY statement syntax: " + e.toString());
     }
   }
diff --git a/src/main/javacc/copy.jjt b/src/main/javacc/copy.jjt
index 2b43ba57..f2315084 100644
--- a/src/main/javacc/copy.jjt
+++ b/src/main/javacc/copy.jjt
@@ -71,26 +71,15 @@ TOKEN [IGNORE_CASE] : /* COPY OPTIONS */
 | <O_FALSE: "FALSE">
 }
 
-TOKEN : /* UNICODE */
-{
-  < UNICODE: ("U&" <CODEPOINT_LIST> | "u&" <CODEPOINT_LIST>) >
-|
-  < #CODEPOINT_LIST: ("\"" (<CODEPOINT>|<LETTER>|<DIGIT>)+ "\"" | "\'" (<CODEPOINT>|<LETTER>|<DIGIT>)+ "\'") >
-|
-  < #CODEPOINT: ("\\" <HEX><HEX><HEX><HEX> | "\\" <HEX><HEX><HEX><HEX><HEX><HEX>) >
-|
-  < #HEX: ["0"-"9","A"-"F","a"-"f"] >
-}
-
 TOKEN : /* IDENTIFIERS */
 {
+  < QUOTED_CHAR: ("\"" <SINGLE_CHAR> "\"" | "\'" <SINGLE_CHAR> "\'") >
+|
   < QUOTED_IDENTIFIER: ("\"" <IDENTIFIER> "\"" | "\'" <IDENTIFIER> "\'") >
 |
   < IDENTIFIER: <LETTER> (<LETTER>|<DIGIT>)* >
 |
-  < QUOTED_CHAR: ("\"" <SINGLE_CHAR> "\"" | "\'" <SINGLE_CHAR> "\'") >
-|
-  < #SINGLE_CHAR: (["!"-"'","*"-"/",":","<"-"@","["-"`"]) >
+  < #SINGLE_CHAR: (["!"-"~"]) >
 |
   < #DIGIT: ["0"-"9"] >
 |
@@ -99,17 +88,29 @@ TOKEN : /* IDENTIFIERS */
   < #LOWER_CASE_LETTER: ["_","a"-"z"] >
 }
 
+TOKEN : /* UNICODE */
+{
+  < UNICODE: ("U&" <CODEPOINT_LIST> | "u&" <CODEPOINT_LIST>) >
+|
+  < #CODEPOINT_LIST: ("\"" (<CODEPOINT>)+ "\"" | "\'" (<CODEPOINT>)+ "\'") >
+|
+  < #CODEPOINT: ("\\" <HEX><HEX><HEX><HEX> | "\\" <HEX><HEX><HEX><HEX><HEX><HEX>) >
+|
+  < #HEX: ["0"-"9","A"-"F","a"-"f"] >
+}
+
 /** Main production. */
 ASTStart Start() #Start : {}
 {
-  Expression() ";"
+  Stmt()
   { return jjtThis; }
 }
 
-/** An Expression. */
-void Expression() : {}
+void Stmt() : {}
 {
-  CopyStmt()
+    CopyStmt()
+  | LOOKAHEAD(2)
+    CopyStmt() ";"
 }
 
 /** Copy Statement. */
@@ -187,11 +188,18 @@ void optWith() : {}
 /** Optional list of copy options */
 void copyOptions() #CopyOptions : {}
 {
-  LOOKAHEAD(2)
-  "(" copyOptionList() ")"
+  LOOKAHEAD(3)
+  "(" copyOptionGenericList() ")"
   | copyOptionList()
 }
 
+void copyOptionGenericList() #CopyOptionList : {}
+{
+  LOOKAHEAD(3)
+  copyOptionElement() "," copyOptionGenericList()
+  | copyOptionElement()
+}
+
 void copyOptionList() #CopyOptionList : {}
 {
   copyOptionElement() copyOptionList()
@@ -205,7 +213,7 @@ void copyOptionElement() #CopyOptionElement : {}
     }
   | formatType() {
       jjtThis.setName("FORMAT");
-  }
+    }
   | <O_FREEZE> {
       jjtThis.setName("FREEZE");
       throw new ParseException("FREEZE is not supported.");


Test patch:
diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/ParserTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/ParserTest.java
index 07997c91..ff3cd950 100644
--- a/src/test/java/com/google/cloud/spanner/pgadapter/ParserTest.java
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/ParserTest.java
@@ -42,6 +42,7 @@ import com.google.cloud.spanner.pgadapter.parsers.copy.CopyTreeParser.CopyOption
 import com.google.cloud.spanner.pgadapter.parsers.copy.CopyTreeParser.CopyOptions.FromTo;
 import com.google.cloud.spanner.pgadapter.parsers.copy.ParseException;
 import com.google.cloud.spanner.pgadapter.parsers.copy.TokenMgrError;
+import com.google.cloud.spanner.pgadapter.utils.StatementParser;
 import java.math.BigDecimal;
 import java.nio.charset.StandardCharsets;
 import java.sql.Array;
@@ -408,6 +409,8 @@ public class ParserTest {
       String sql = "COPY users FROM STDIN;";
       parse(sql, options);
 
+      assertEquals(
+          StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
       assertThat(options.getTableName(), is(equalTo("users")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.TEXT)));
@@ -419,6 +422,8 @@ public class ParserTest {
       String sql = "COPY Users FROM STDIN;";
       parse(sql, options);
 
+      assertEquals(
+          StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
       assertThat(options.getTableName(), is(equalTo("users")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.TEXT)));
@@ -430,6 +435,8 @@ public class ParserTest {
       String sql = "COPY UsErS FROM STDIN;";
       parse(sql, options);
 
+      assertEquals(
+          StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
       assertThat(options.getTableName(), is(equalTo("users")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.TEXT)));
@@ -441,6 +448,8 @@ public class ParserTest {
       String sql = "COPY USERS FROM STDIN;";
       parse(sql, options);
 
+      assertEquals(
+          StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
       assertThat(options.getTableName(), is(equalTo("users")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.TEXT)));
@@ -452,6 +461,8 @@ public class ParserTest {
       String sql = "COPY \'Users\' FROM STDIN;";
       parse(sql, options);
 
+      assertEquals(
+          StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
       assertThat(options.getTableName(), is(equalTo("Users")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.TEXT)));
@@ -463,6 +474,8 @@ public class ParserTest {
       String sql = "COPY \"UsErS\" FROM STDIN;";
       parse(sql, options);
 
+      assertEquals(
+          StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
       assertThat(options.getTableName(), is(equalTo("UsErS")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.TEXT)));
@@ -474,6 +487,8 @@ public class ParserTest {
       String sql = "COPY \'USERS\' FROM STDIN;";
       parse(sql, options);
 
+      assertEquals(
+          StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
       assertThat(options.getTableName(), is(equalTo("USERS")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.TEXT)));
@@ -485,6 +500,8 @@ public class ParserTest {
       String sql = "COPY users (id) FROM STDIN;";
       parse(sql, options);
 
+      assertEquals(
+          StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
       assertThat(options.getTableName(), is(equalTo("users")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.TEXT)));
@@ -496,6 +513,8 @@ public class ParserTest {
       String sql = "COPY users (id, age) FROM STDIN;";
       parse(sql, options);
 
+      assertEquals(
+          StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
       assertThat(options.getTableName(), is(equalTo("users")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.TEXT)));
@@ -507,6 +526,8 @@ public class ParserTest {
       String sql = "COPY users (id, age, name) FROM STDIN;";
       parse(sql, options);
 
+      assertEquals(
+          StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
       assertThat(options.getTableName(), is(equalTo("users")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.TEXT)));
@@ -518,6 +539,8 @@ public class ParserTest {
       String sql = "COPY users (ID, AGE, NAME) FROM STDIN;";
       parse(sql, options);
 
+      assertEquals(
+          StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
       assertThat(options.getTableName(), is(equalTo("users")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.TEXT)));
@@ -529,6 +552,8 @@ public class ParserTest {
       String sql = "COPY users (Id, Age, Name) FROM STDIN;";
       parse(sql, options);
 
+      assertEquals(
+          StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
       assertThat(options.getTableName(), is(equalTo("users")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.TEXT)));
@@ -540,6 +565,8 @@ public class ParserTest {
       String sql = "COPY users (iD, aGe, nAMe) FROM STDIN;";
       parse(sql, options);
 
+      assertEquals(
+          StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
       assertThat(options.getTableName(), is(equalTo("users")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.TEXT)));
@@ -551,6 +578,8 @@ public class ParserTest {
       String sql = "COPY users (\'ID\', \"AGE\", \'NAME\') FROM STDIN;";
       parse(sql, options);
 
+      assertEquals(
+          StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
       assertThat(options.getTableName(), is(equalTo("users")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.TEXT)));
@@ -562,6 +591,8 @@ public class ParserTest {
       String sql = "COPY users (\'Id\', \'Age\', \'Name\') FROM STDIN;";
       parse(sql, options);
 
+      assertEquals(
+          StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
       assertThat(options.getTableName(), is(equalTo("users")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.TEXT)));
@@ -573,6 +604,8 @@ public class ParserTest {
       String sql = "COPY users (\"iD\", \"aGe\", \"nAMe\") FROM STDIN;";
       parse(sql, options);
 
+      assertEquals(
+          StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
       assertThat(options.getTableName(), is(equalTo("users")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.TEXT)));
@@ -587,6 +620,8 @@ public class ParserTest {
       String sql = "COPY users FROM STDIN WITH FORMAT CSV;";
       parse(sql, options);
 
+      assertEquals(
+          StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
       assertThat(options.getTableName(), is(equalTo("users")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.CSV)));
@@ -597,6 +632,8 @@ public class ParserTest {
       String sql = "COPY users FROM STDIN WITH FORMAT BINARY;";
       parse(sql, options);
 
+      assertEquals(
+          StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
       assertThat(options.getTableName(), is(equalTo("users")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.BINARY)));
@@ -607,6 +644,8 @@ public class ParserTest {
       String sql = "COPY users FROM STDIN WITH FORMAT TEXT;";
       parse(sql, options);
 
+      assertEquals(
+          StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
       assertThat(options.getTableName(), is(equalTo("users")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.TEXT)));
@@ -617,6 +656,8 @@ public class ParserTest {
       String sql = "COPY users FROM STDIN CSV;";
       parse(sql, options);
 
+      assertEquals(
+          StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
       assertThat(options.getTableName(), is(equalTo("users")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.CSV)));
@@ -627,6 +668,8 @@ public class ParserTest {
       String sql = "COPY users FROM STDIN BINARY;";
       parse(sql, options);
 
+      assertEquals(
+          StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
       assertThat(options.getTableName(), is(equalTo("users")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.BINARY)));
@@ -637,6 +680,8 @@ public class ParserTest {
       String sql = "COPY users FROM STDIN TEXT;";
       parse(sql, options);
 
+      assertEquals(
+          StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
       assertThat(options.getTableName(), is(equalTo("users")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.TEXT)));
@@ -647,6 +692,8 @@ public class ParserTest {
       String sql = "COPY users FROM STDIN DELIMITER '*';";
       parse(sql, options);
 
+      assertEquals(
+          StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
       assertThat(options.getTableName(), is(equalTo("users")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.TEXT)));
@@ -658,6 +705,9 @@ public class ParserTest {
       String sql = "COPY users FROM STDIN ESCAPE '\\';";
       parse(sql, options);
 
+      assertThrows(
+          IllegalArgumentException.class,
+          () -> StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)));
       assertThat(options.getTableName(), is(equalTo("users")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.TEXT)));
@@ -669,6 +719,9 @@ public class ParserTest {
       String sql = "COPY users FROM STDIN QUOTE '\'';";
       parse(sql, options);
 
+      assertThrows(
+          IllegalArgumentException.class,
+          () -> StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)));
       assertThat(options.getTableName(), is(equalTo("users")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.TEXT)));
@@ -680,11 +733,69 @@ public class ParserTest {
       String sql = "COPY users FROM STDIN NULL 'null';";
       parse(sql, options);
 
+      assertEquals(
+          StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
       assertThat(options.getTableName(), is(equalTo("users")));
       assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
       assertThat(options.getFormat(), is(equalTo(Format.TEXT)));
       assertThat(options.getNullString(), is(equalTo("null")));
     }
+
+    {
+      char value;
+      for (value = '!'; value <= '~'; value++) {
+        CopyTreeParser.CopyOptions options = new CopyTreeParser.CopyOptions();
+        String sql = "COPY users FROM STDIN (QUOTE '" + value + "');";
+        parse(sql, options);
+        // These characters are not currently allowed since removeCommentsAndTrim() has special
+        // cases for their use: [' " \]  ('\'' and '\"' are actually allowed if they are wrapped by
+        // the other character)
+        if (value == '\'' || value == '\\') {
+          assertThrows(
+              IllegalArgumentException.class,
+              () -> StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)));
+        } else {
+          assertEquals(
+              StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
+        }
+        assertThat(options.getTableName(), is(equalTo("users")));
+        assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
+        assertThat(options.getFormat(), is(equalTo(Format.TEXT)));
+        assertThat(options.getQuote(), is(equalTo(value)));
+      }
+    }
+
+    {
+      char value;
+      for (value = '!'; value <= '|'; value++) {
+        char value1 = (char) (value + 1);
+        char value2 = (char) (value + 2);
+        CopyTreeParser.CopyOptions options = new CopyTreeParser.CopyOptions();
+        String sql =
+            "COPY users FROM STDIN (DELIMITER '"
+                + value
+                + "', QUOTE '"
+                + value1
+                + "', ESCAPE '"
+                + value2
+                + "');";
+        parse(sql, options);
+        if (value >= '%' && value <= '\'' || value >= 'Z' && value <= '\\') {
+          assertThrows(
+              IllegalArgumentException.class,
+              () -> StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)));
+        } else {
+          assertEquals(
+              StatementParser.parseCommand(StatementParser.removeCommentsAndTrim(sql)), "COPY");
+        }
+        assertThat(options.getTableName(), is(equalTo("users")));
+        assertThat(options.getFromTo(), is(equalTo(FromTo.FROM)));
+        assertThat(options.getFormat(), is(equalTo(Format.TEXT)));
+        assertThat(options.getDelimiter(), is(equalTo(value)));
+        assertThat(options.getQuote(), is(equalTo(value1)));
+        assertThat(options.getEscape(), is(equalTo(value2)));
+      }
+    }
   }
 
   @Test