001// lexical analyzer  for GSQLParser component java version
002
003/****************************************************
004   Lexical analizer for GSQLParser Java component   
005   Copyright (c) 2004-2024 by Gudu software         
006****************************************************/
007
008package gudusoft.gsqlparser;
009
010import java.util.HashMap;
011import java.io.InputStreamReader;
012
013import java.util.Locale;
014import java.io.BufferedReader;
015import java.io.IOException;
016
017        
018public class TLexerSnowflake extends TCustomLexer{
019    static int yynmarks = 0  ;
020    static int yynmatches ;
021    static int yyntrans   ;
022    static int yynstates  ;
023    static int[]  yyk,yym ; // 1 based
024    static int[]  yytint;  // 1 based
025    static TYytRec[] yyt ;  // 1 based
026    static int[]  yykl,yykh,yyml,yymh,yytl,yyth ; // 0 based
027    private  static  String[] keywordlist;
028    static String   table_file;
029    static HashMap<String, Integer> keywordValueList;
030    static HashMap<Integer, Integer> keywordTypeList;
031        static int[][] yystateTable;
032
033    static {
034              keywordValueList = new HashMap<String, Integer>();
035              keywordTypeList = new HashMap<Integer, Integer>();
036          table_file = "/gudusoft/gsqlparser/parser/snowflake/snowflake_lex_table.txt";
037                  if (TBaseType.enterprise_edition||TBaseType.snowflake_edition){
038                  inittable();
039              }
040    }
041    
042    public TLexerSnowflake(){
043          super();
044          dbvendor = EDbVendor.dbvsnowflake;
045    }
046
047    // Track non-SQL languages (JAVA, PYTHON, SCALA) so $$ body is not parsed as SQL
048    private boolean isNonSQLLanguageDetected = false;
049    private boolean isLanguagePending = false;
050
051public boolean canBeColumnName(int tokencode){
052    //http://blog.csdn.net/superbeck/article/details/5387476
053    boolean ret = false;
054    int modifiers = keyword_type_identifier | keyword_type_column ;
055    Integer s = keywordTypeList.get(tokencode);
056     if (s != null){
057        int modifier = s;
058        ret = (modifiers & modifier) == modifier;
059    }
060
061    return ret;
062}
063   
064 public  int iskeyword(String str){
065        int ret = -1;
066        Integer s = keywordValueList.get(str.toUpperCase(Locale.ENGLISH));
067        if( s != null){
068            ret = s;
069        }
070        return ret;// -1 means not a keyword
071     }
072
073     public int getkeywordvalue(String keyword){
074        int ret = 0;
075        Integer s = keywordValueList.get(keyword.toUpperCase(Locale.ENGLISH));
076        if( s != null){
077            ret = s;
078         }
079        return ret;// 0 means not a keyword
080     }
081         
082    public static EKeywordType getKeywordType(String keyword){
083        return TCustomLexer.getKeywordType(keyword,keywordValueList,keywordTypeList);
084    }            
085
086    static void yystateLookupConfigure() {
087        int yystates = yytl.length;
088        yystateTable = new int[257][yystates];
089
090        // initialize to empty
091        for(int i = 0; i < yystates; i++) {
092            for (int j = 0; j < 257; j++)
093                yystateTable[j][i] = -1;
094        }
095
096        for(int i = 0; i < yystates; i++) {
097            int low = yytl[i];
098            int high = yyth[i];
099            for (int j = low; j <= high; j++) {
100                for (char c: yyt[j].cc) {
101                    yystateTable[c][i] = j;
102                }
103            }
104        }
105    }
106        
107    int yylex(){
108          int yyn;
109           while (true) { // top level while
110              yynew();
111              while (true){  //scan
112                 for(yyn = yykl[yystate]; yyn <= yykh[yystate]; yyn++){
113                     yymark(yyk[yyn]);
114                 }
115
116                 for(yyn=yymh[yystate]; yyn>= yyml[yystate]; yyn--){
117                    yymatch(yym[yyn]);
118                 }
119
120                 if(yytl[yystate] > yyth[yystate]){
121                     break;
122                 }
123
124                 yyscan();
125//                 yyn = yytl[yystate];
126                 totablechar();
127//                 while( (yyn <= yyth[yystate]) && (!(charinarray(yytablechar,yyt[yyn].cc))) ){
128//                   yyn++;
129//                 }
130//                 if (yyn > yyth[yystate]){
131//                     break;
132//                 }
133
134                 yyn = yystateTable[yytablechar][yystate];
135                 if (yyn == -1)
136                     break;
137                                         
138                 yystate = yyt[yyn].s;
139              } //scan
140
141              while (true){ //action
142                int yyrule;
143                if ( (yyrule = yyfind()) != -1 ){
144                   yyaction(yyrule);
145                   if (yyreject){
146                       continue;
147                   }
148                }else if( (!yydefault() ) && (yywrap()) ){
149                   yyclear();
150                   returni(0);
151                }
152                break;
153              }
154
155              if (!yydone) {
156                  continue;
157              }
158              break;
159            } // top level while
160
161           return yyretval;
162        }
163
164    static void inittable(){
165                
166                //if (yynmarks > 0) return; //init table already
167
168        String line;
169        boolean inyyk=false,inyym=false,inyykl=false,inyykh=false,inyyml=false,inyymh=false,inyytl=false,inyyth=false,inyytint=false,inyyt=false,inkeyword=false;
170        int yyk_count=0,yym_count=0,yykl_count=0,yykh_count=0,yyml_count=0,yymh_count=0,yytl_count=0,yyth_count=0,yytint_count=0,yyt_count=0;
171        int c=0;
172        keywordValueList.clear();
173        keywordTypeList.clear();
174        
175        BufferedReader br = new BufferedReader(new InputStreamReader(TLexerSnowflake.class.getResourceAsStream(table_file)));
176
177            try{
178                while( (line = br.readLine()) != null){
179                          if (line.trim().startsWith("yynmarks=")){
180                             String[] ss = line.split("[=;]");
181                              yynmarks=Integer.parseInt(ss[1].trim());
182                              yyk = new int[yynmarks+1];
183                          }else if (line.trim().startsWith("yynmatches=")){
184                              String[] ss = line.split("[=;]");
185                               yynmatches=Integer.parseInt(ss[1].trim());
186                               yym = new int[yynmatches+1];
187                          }else if (line.trim().startsWith("yyntrans=")){
188                              String[] ss = line.split("[=;]");
189                               yyntrans=Integer.parseInt(ss[1].trim());
190                               yytint = new int[yyntrans+1];
191                               yyt = new TYytRec[yyntrans+1];
192                          }else if (line.trim().startsWith("yynstates=")){
193                              String[] ss = line.split("[=;]");
194                               yynstates=Integer.parseInt(ss[1].trim());
195                               yykl = new int[yynstates];
196                               yykh = new int[yynstates];
197                              yyml = new int[yynstates];
198                              yymh = new int[yynstates];
199                              yytl = new int[yynstates];
200                              yyth = new int[yynstates];
201                          }else if (line.trim().startsWith("<end>")){
202                              if (inyyk){
203                                  inyyk = false;
204                                 if (yynmarks+1 != yyk_count ){
205                                    System.out.println("required1:"+(yynmarks)+" actually:"+(yyk_count-1));
206                                 }
207                              }
208                              else if(inyym){
209                                     inyym = false;
210                                    if (yynmatches+1 != yym_count ){
211                                       System.out.println("required2:"+(yynmatches)+" actually:"+(yym_count-1));
212                                    }
213                              }
214                              else if(inyykl){
215                                     inyykl = false;
216                                    if (yynstates != yykl_count ){
217                                       System.out.println("required3:"+(yynstates)+" actually:"+(yykl_count));
218                                    }
219                              }
220                              else if(inyykh){
221                                     inyykh = false;
222                                    if (yynstates != yykh_count ){
223                                       System.out.println("required4:"+(yynstates)+" actually:"+(yykh_count));
224                                    }
225                              }
226                              else if(inyyml){
227                                     inyyml = false;
228                                    if (yynstates != yyml_count ){
229                                       System.out.println("required5:"+(yynstates)+" actually:"+(yyml_count));
230                                    }
231                              }
232                              else if(inyymh){
233                                     inyymh = false;
234                                    if (yynstates != yymh_count ){
235                                       System.out.println("required:"+(yynstates)+" actually:"+(yymh_count));
236                                    }
237                              }
238                              else if(inyytl){
239                                     inyytl = false;
240                                    if (yynstates != yytl_count ){
241                                       System.out.println("required6:"+(yynstates)+" actually:"+(yytl_count));
242                                    }
243                              }
244                              else if(inyyth){
245                                     inyyth = false;
246                                    if (yynstates != yyth_count ){
247                                       System.out.println("required7:"+(yynstates)+" actually:"+(yyth_count));
248                                    }
249                              }
250                              else if(inyytint){
251                                     inyytint = false;
252                                    if (yyntrans + 1 != yytint_count ){
253                                       System.out.println("required8:"+(yyntrans)+" actually:"+(yytint_count-1));
254                                    }
255                              }
256                              else if(inyyt){
257                                     inyyt = false;
258                                    if (yyntrans+1 != yyt_count ){
259                                       System.out.println("required9:"+(yyntrans)+" actually:"+(yyt_count-1));
260                                    }
261                              }
262                              else if(inkeyword){
263                                     inkeyword = false;
264                              }
265                          }else if(line.trim().startsWith("yyk =")){
266                             inyyk = true; 
267                          }else if(line.trim().startsWith("yym =")){
268                             inyym = true;
269                          }else if(line.trim().startsWith("yykl =")){
270                             inyykl = true;
271                          }else if(line.trim().startsWith("yykh =")){
272                             inyykh = true;
273                          }else if(line.trim().startsWith("yyml =")){
274                             inyyml = true;
275                          }else if(line.trim().startsWith("yymh =")){
276                             inyymh = true;
277                          }else if(line.trim().startsWith("yytl =")){
278                             inyytl = true;
279                          }else if(line.trim().startsWith("yyth =")){
280                             inyyth = true;
281                          }else if(line.trim().startsWith("yytint =")){
282                             inyytint = true;
283                          }else if(line.trim().startsWith("yyt =")){
284                             inyyt = true;
285                        }else if(line.trim().startsWith("keywordsvalue =")){
286                           inkeyword = true;
287                        }else if(inyyk){
288                             String[] ss = line.split("[,]");
289                               for(int j=0;j<ss.length;j++){
290                                   // System.out.println(ss[j].trim());
291                                 yyk[yyk_count++] = Integer.parseInt(ss[j].trim());
292                               }
293                          }else if(inyym){
294                               String[] ss = line.split("[,]");
295                                 for(int j=0;j<ss.length;j++){
296                                     // System.out.println(ss[j].trim());
297                                   yym[yym_count++] = Integer.parseInt(ss[j].trim());
298                                 }
299                          }else if(inyykl){
300                               String[] ss = line.split("[,]");
301                                 for(int j=0;j<ss.length;j++){
302                                    //  System.out.println(ss[j].trim());
303                                   yykl[yykl_count++] = Integer.parseInt(ss[j].trim());
304                                 }
305                          }else if(inyykh){
306                               String[] ss = line.split("[,]");
307                                 for(int j=0;j<ss.length;j++){
308                                     // System.out.println(ss[j].trim());
309                                   yykh[yykh_count++] = Integer.parseInt(ss[j].trim());
310                                 }
311                          }else if(inyyml){
312                               String[] ss = line.split("[,]");
313                                 for(int j=0;j<ss.length;j++){
314                                     // System.out.println(ss[j].trim());
315                                   yyml[yyml_count++] = Integer.parseInt(ss[j].trim());
316                                 }
317                          }else if(inyymh){
318                               String[] ss = line.split("[,]");
319                                 for(int j=0;j<ss.length;j++){
320                                     // System.out.println(ss[j].trim());
321                                   yymh[yymh_count++] = Integer.parseInt(ss[j].trim());
322                                 }
323                          }else if(inyytl){
324                               String[] ss = line.split("[,]");
325                                 for(int j=0;j<ss.length;j++){
326                                     // System.out.println(ss[j].trim());
327                                   yytl[yytl_count++] = Integer.parseInt(ss[j].trim());
328                                 }
329                          }else if(inyyth){
330                               String[] ss = line.split("[,]");
331                                 for(int j=0;j<ss.length;j++){
332                                     // System.out.println(ss[j].trim());
333                                   yyth[yyth_count++] = Integer.parseInt(ss[j].trim());
334                                 }
335                          }else if(inyytint){
336                               String[] ss = line.split("[,]");
337                                 for(int j=0;j<ss.length;j++){
338                                     // System.out.println(ss[j].trim());
339                                   yytint[yytint_count++] = Integer.parseInt(ss[j].trim());
340                                 }
341                          }else if(inyyt){
342                                //System.out.println(line.trim());
343
344                              c = 0;
345                              String[] st = line.trim().split(",,");
346                              char[] tmp = new char[st.length];
347                              for(int i=0;i<st.length;i++){
348
349                                  if(st[i].startsWith("\'")) {
350                                      if(st[i].length() == 3){  // 'a'
351                                          tmp[c++] = st[i].charAt(1);
352                                      }else if(st[i].length() == 4) { // '\\'
353                                          tmp[c++] = st[i].charAt(2);
354                                      }else{
355                                         System.out.println(" read yytstr error, error string is "+st[i]+ "line: "+ yyt_count);
356                                      }
357                                  }else{
358                                      try{
359                                           tmp[c++] = (char)Integer.parseInt(st[i]);   // char in number like 32 that represent space
360                                          } catch (NumberFormatException nfe) {
361                                             System.out.println("NumberFormatException: " + nfe.getMessage());
362                                          }
363                                  }
364                              } //while hasmoreTokens
365
366                          //yyt[lineno] = new YYTrec(tmp,yytint[lineno]);
367                              yyt[yyt_count] = new TYytRec(tmp,yytint[yyt_count]);
368                              yyt_count++;
369
370                          }else if(inkeyword){
371                              String[] ss =line.split("[=]");
372
373                              int val1 = -1;
374                              int val2 = -1;
375                              try {
376                                  val1 = Integer.parseInt(ss[1]);
377                                  val2 = Integer.parseInt(ss[2]);
378                              }
379                              catch (NumberFormatException nfe) {
380                                  System.out.println("NumberFormatException: " + nfe.getMessage());
381                              }
382                              keywordValueList.put(ss[0].toUpperCase(),val1);
383                              keywordTypeList.put(val1,val2);
384                             }
385                }
386                }catch(IOException e){
387                  System.out.println(e.toString());
388                }
389                                
390                                yystateLookupConfigure();
391
392    }
393
394
395    void yyaction(int yyruleno){
396                                
397
398      int ic;
399      char[] tmparray = {'=','+','-','*','/','>','<'};
400
401      yylvalstr = getyytext();
402  /* actions: */
403  switch(yyruleno){
404  case 1:
405                
406        {
407     returni (filepath_sign);
408     break;
409        }
410        
411  case 2:
412                   
413                {
414                                        if (yylvalstr.equalsIgnoreCase(dolqstart))
415                                        {
416                                                //dolqstart = "";
417                                                start(init);
418                                                addlit(yylvalstr,yytextlen);
419                                                yylvalstr = litbufdup();
420                                                returni(sconst);
421                                        }
422                                        else
423                                        {
424                                                //nchars = yytextlen;
425                                                addlit(yylvalstr, yytextlen-1);
426                                                yyless(yytextlen-1);
427                                                return;
428                                        }
429                                        //System.out.println("<xdolq>{dolqdelim}: "+dolqstart);
430                                        break;
431                }
432                                
433  case 3:
434            
435          {
436              if (isReadyForFunctionBody) { // meet the first $$
437                  //isInFunctionBody = true;
438                  isReadyForFunctionBody = false;
439                  functionBodyDelimiterIndex++;
440                  functionBodyDelimiter.add(yylvalstr);
441                 // System.out.println("start function body:"+functionBodyDelimiter.get(functionBodyDelimiterIndex));
442                  returni(snowflake_function_delimiter);
443              }else if ((functionBodyDelimiterIndex>=0)&&(functionBodyDelimiter.get(functionBodyDelimiterIndex).equalsIgnoreCase(yylvalstr))){ // meet the second $$
444                  // Lookahead to check if this $$ is ending function body or starting a nested string
445                  // If next char is whitespace, ';', ')', or EOF, it's ending the function body
446                  // If next char is alphanumeric, backslash, or other content, it's starting a nested string
447                  char nextChar = get_char();
448                  boolean isEndingFunctionBody = (nextChar == ' ' || nextChar == '\t' || nextChar == '\n' ||
449                                                   nextChar == '\r' || nextChar == ';' || nextChar == ')' ||
450                                                   nextChar == '\0' || nextChar == 0);
451                  if (nextChar != '\0' && nextChar != 0) {
452                      unget_char(nextChar); // put the character back
453                  }
454
455                  if (isEndingFunctionBody) {
456                      //isInFunctionBody = false;
457                      //System.out.println("end function body:"+functionBodyDelimiter.get(functionBodyDelimiterIndex));
458                      functionBodyDelimiter.remove(functionBodyDelimiterIndex);
459                      functionBodyDelimiterIndex--;
460                      returni(snowflake_function_delimiter);
461                  } else {
462                      // Not ending function body, start a nested dollar-quoted string
463                      start(xdolq);
464                      startlit();
465                      dolqstart = yylvalstr;
466                      addlit(yylvalstr,yytextlen);
467                  }
468              }else {             
469                                  if (getyysstate() == xq){
470                                          nchars = yytextlen;
471                                          addlit(yylvalstr, yytextlen-1);
472                                          yyless(nchars-1);
473                                          return;//exit;
474                                  }else{
475                                          start(xdolq);
476                                          startlit();
477                                          dolqstart = yylvalstr;
478                                          addlit(yylvalstr,yytextlen);
479                                  }
480                            }
481
482              break;
483          }
484
485  case 4:
486                    
487        {
488                addlit(yylvalstr, yytextlen);
489          //System.out.println("<xdolq>{dolqinside}: "+yylvalstr);
490                break;
491        }
492                                
493  case 5:
494                    
495        {
496                        addlit(yylvalstr, yytextlen);
497                        break;
498        }
499                                
500  case 6:
501                        
502                {
503         addlitchar(yylvalstr.charAt(0));
504         break;
505                }
506          
507
508  case 7:
509           
510          {
511              if (getyysstate() == xq)
512              {
513                  nchars = yytextlen;
514                  addlit(yylvalstr, yytextlen-1);
515                  yyless(nchars-1);
516                  return;//exit;
517              }
518
519              start(xq);
520              startlit();
521              addlit(yylvalstr,yytextlen);
522              break;
523          }
524
525  case 8:
526                
527          {
528              if (getyysstate() == xq)
529              {
530                  nchars = yytextlen;
531                  addlit(yylvalstr, yytextlen-1);
532                  yyless(nchars-1);
533                  return;//exit;
534              }
535
536              start(xq);
537              startlit();
538              addlit(yylvalstr,yytextlen);
539              break;
540          }
541
542  case 9:
543                
544          {
545              if (getyysstate() == xq)
546              {
547                  nchars = yytextlen;
548                  addlit(yylvalstr, yytextlen-1);
549                  yyless(nchars-1);
550                  return;//exit;
551              }
552
553              start(xq);
554              startlit();
555              addlit(yylvalstr,yytextlen);
556              break;
557          }
558
559  case 10:
560                
561        {
562                    addlit(yylvalstr,yytextlen);
563                    if (xcdepth <= 0)
564                       {
565                        start(init);
566                        yylvalstr = litbufdup();
567                        returni(cmtslashstar);
568                       }
569                    else
570                       xcdepth--;
571
572                  break;
573        }
574
575
576  case 11:
577                
578                  {
579                      if (yylvalstr.equalsIgnoreCase("/*+")){
580                         xcdepth++;
581                          yyless(2);
582                          addlit(yylvalstr,yytextlen);
583                      }else{
584                          yyless(1);
585                          addlit(yylvalstr,1);
586                      }
587        
588                      break;
589
590                   }
591
592  case 12:
593                        
594                  {
595
596                      if (getyysstate() == xq)
597                      {
598                          nchars = yytextlen;
599                          addlit(yylvalstr, yytextlen-1);
600                          yyless(nchars-1);
601                          return;//exit;
602                      }
603
604                      xcdepth = 0;
605                      start(xc);
606                      startlit();
607                      yyless(2);
608                      addlit(yylvalstr,yytextlen);
609
610                  break;
611                  }
612
613  case 13:
614                
615                  {
616                    addlit(yylvalstr,yytextlen);
617        
618                    break;
619                  }
620
621  case 14:
622                
623                  {
624                      addlitchar(yylvalstr.charAt(0));
625        
626                      break;
627                  }
628
629  case 15:
630                
631                  {
632                      start(init);
633                      addlit(yylvalstr, yytextlen);
634                      yylvalstr = litbufdup();
635                      if( yylvalstr.startsWith("b")|| (yylvalstr.startsWith("B"))){
636                          returni(bconst);
637                      }else if( yylvalstr.startsWith("x")|| (yylvalstr.startsWith("X"))){
638                          returni(xconst);
639                      }else 
640                      {
641                      returni(sconst);
642                      }
643                      break;
644                  }
645
646  case 16:
647                
648                    {
649                    if (insqlpluscmd){
650                        yyless(0);
651                        yylvalstr = litbufdup();
652                        start(init);
653                        returni(sconst);
654                    }else{
655                      addlit(yylvalstr,yytextlen);
656                    }
657
658                    break;
659                }
660  case 17:
661            
662                  {
663                      if (getyysstate() == xq)
664                      {
665                          nchars = yytextlen;
666                          addlit(yylvalstr, yytextlen-1);
667                          yyless(nchars-1);
668                          return;//exit;
669                      }
670
671                      start(xq);
672                      startlit();
673                      addlit(yylvalstr,yytextlen);
674
675                      dummych1 = get_char();
676                      if (dummych1 == '\\') // recognize string like '\'
677                        {
678                          dummych2 = get_char();
679                          if (dummych2 == '\'')
680                          {
681                             // start(init);
682                              addlit("\\", 1);
683                              addlit("\'", 1);
684                              //yylvalstr = litbufdup();
685                              //returni(sconst);
686                          }
687                          else
688                           {
689                              unget_char(dummych2);
690                              unget_char(dummych1);
691                            }
692                        }
693                      else
694                      { unget_char(dummych1);}
695
696                      break;
697                  }
698
699  case 18:
700                        
701                  {
702                          start(xq);
703                          startlit();
704                          addlit(yylvalstr, yytextlen);
705                          dummych1 = get_char();
706                          if (dummych1 == '\\') // recognize string like '\'
707                            {
708                              dummych2 = get_char();
709                              if (dummych2 == '\'')
710                              {
711                                 // start(init);
712                                  addlit("\\", 1);
713                                  addlit("\'", 1);
714                                  //yylvalstr = litbufdup();
715                                  //returni(sconst);
716                              }
717                              else
718                               {
719                                  unget_char(dummych2);
720                                  unget_char(dummych1);
721                                }
722                            }
723                          else
724                          { unget_char(dummych1);}
725
726                      break;
727                  }
728
729  case 19:
730                
731                  {
732                      addlit(yylvalstr, yytextlen);
733                      break;
734                  }
735
736  case 20:
737                
738          {
739            dummych1 = get_char();
740            unget_char(dummych1);
741            if (dummych1 == (char)10)
742              {
743                if (insqlpluscmd){
744                  nchars = yytextlen;
745                  if(yylvalstr.charAt(nchars-1) == (char)13){
746                      yyless(nchars - 1);
747                      yylvalstr = yylvalstr.substring(0,nchars);
748                  }
749                    start(init);
750                    addlit(yylvalstr, nchars-1);
751                    yylvalstr = litbufdup();
752                    returni(sconst); //in sqlplus command, characters between ' and return is treated as a string
753
754                }else{
755                        dummych1 = get_char();
756                        addlit(yylvalstr+dummych1, yytextlen+1);
757                }
758              } else if (dummych1 == '\\')
759                  {
760                      // Handle backslash inside string literals
761                      // Snowflake supports both \' (C-style escape) and '' (SQL standard escape)
762                      // The pattern \'' is ambiguous:
763                      //   - Could be \' (escape) + ' (close) - e.g., 'text\'' means text' then close
764                      //   - Could be \ (literal) + '' (escape) - e.g., 'text\''more' means text\'more
765                      // We distinguish by looking at what follows \'' :
766                      //   - \''' : \' (escape) + '' (leave for xqdouble) - two quote chars in value
767                      //   - \''<letter/digit>: \ + '' (backslash + escape, string continues)
768                      //   - \''<space><SQL keyword>: \' + close (string ends, keyword follows)
769                      //   - \''<space><other>: \ + '' (backslash + escape, string continues with space)
770                      //   - \''<EOF/control>: \' + close
771                      // See mantisbt issue 4298 for details
772                      dummych1 = get_char();  // Read the backslash
773                      dummych2 = get_char();  // Read the next char
774                      if (dummych2 == '\'') {
775                          // Have \' - check if followed by another quote
776                          char dummych3 = get_char();
777                          if (dummych3 == '\'') {
778                              // \'' pattern - check what comes after
779                              char dummych4 = get_char();
780                              if (dummych4 == '\'') {
781                                  // \''' : consume \' as escape, leave '' for xqdouble
782                                  unget_char(dummych4);
783                                  unget_char(dummych3);
784                                  addlit(yylvalstr+dummych1+dummych2, yytextlen+2);
785                              } else if (Character.isLetterOrDigit(dummych4) || dummych4 == '_') {
786                                  // \''<letter/digit>: \ + '' (string continues)
787                                  unget_char(dummych4);
788                                  unget_char(dummych3);
789                                  unget_char(dummych2);
790                                  addlit(yylvalstr+dummych1, yytextlen+1);
791                              } else if (dummych4 == ' ' || dummych4 == '\t') {
792                                  // \''<space> - check if followed by SQL keyword
793                                  char dummych5 = get_char();
794                                  char dummych6 = get_char();
795                                  // Check for SQL keywords that typically follow a column/value expression
796                                  // Only check keywords that wouldn't appear as regular words in strings
797                                  String twoChars = "" + Character.toLowerCase(dummych5) + Character.toLowerCase(dummych6);
798                                  if (twoChars.equals("as")) {  // AS is the most reliable indicator of SQL context
799                                      // Likely SQL keyword follows - treat \'' as \' + close
800                                      unget_char(dummych6);
801                                      unget_char(dummych5);
802                                      unget_char(dummych4);
803                                      unget_char(dummych3);
804                                      addlit(yylvalstr+dummych1+dummych2, yytextlen+2);
805                                  } else {
806                                      // Not a SQL keyword - treat as \ + '' (string continues)
807                                      unget_char(dummych6);
808                                      unget_char(dummych5);
809                                      unget_char(dummych4);
810                                      unget_char(dummych3);
811                                      unget_char(dummych2);
812                                      addlit(yylvalstr+dummych1, yytextlen+1);
813                                  }
814                              } else if (dummych4 == ';' || dummych4 == ',' || dummych4 == ')'
815                                      || dummych4 == '|' || dummych4 == '+' || dummych4 == '='
816                                      || dummych4 == '<' || dummych4 == '>' || dummych4 == '/'
817                                      || dummych4 == '*') {
818                                  // \''<SQL-punctuation>: \' (escape) + ' (close string)
819                                  unget_char(dummych4);
820                                  unget_char(dummych3);
821                                  addlit(yylvalstr+dummych1+dummych2, yytextlen+2);
822                              } else if (dummych4 >= ' ' && dummych4 != (char)0 && dummych4 != (char)-1) {
823                                  // Other printable: \ + '' (string continues)
824                                  unget_char(dummych4);
825                                  unget_char(dummych3);
826                                  unget_char(dummych2);
827                                  addlit(yylvalstr+dummych1, yytextlen+1);
828                              } else {
829                                  // \'' at EOF or followed by control char: \' escape + ' closes string
830                                  unget_char(dummych4);
831                                  unget_char(dummych3);
832                                  addlit(yylvalstr+dummych1+dummych2, yytextlen+2);
833                              }
834                          } else {
835                              // \' followed by non-quote: consume \' as C-style escape
836                              unget_char(dummych3);
837                              addlit(yylvalstr+dummych1+dummych2, yytextlen+2);
838                          }
839                      } else {
840                          // \X where X is not quote: consume both
841                          addlit(yylvalstr+dummych1+dummych2, yytextlen+2);
842                      }
843                  }
844                else
845                    { addlit(yylvalstr, yytextlen);}
846
847                        break;
848         }
849 
850  case 21:
851               
852                  {
853                      addlit(yylvalstr, yytextlen);
854                      // When the matched literal ends in a backslash, decide
855                      // whether that final backslash is the first half of a
856                      // \' escape pair (so the next quote should be consumed
857                      // as the escape's second half) or the second half of a
858                      // \\ escape pair (so the next quote is the literal's
859                      // closing delimiter). Resolve via the parity of the
860                      // trailing backslash run:
861                      //   - odd  : final backslash unpaired -> treat next
862                      //            quote as \' escape (mantisbt issue 4435,
863                      //            cases like '\\'\\'X', '\\'\\''')
864                      //   - even : all trailing backslashes form \\ pairs
865                      //            already -> let the next quote close
866                      //            (preserve literals like '\\\\').
867                      int trailingBackslashes = 0;
868                      for (int bi = yytextlen - 1; bi >= 0 && yylvalstr.charAt(bi) == '\\'; bi--)
869                      {
870                          trailingBackslashes++;
871                      }
872                      if ((trailingBackslashes & 1) == 1)
873                      {
874                          dummych1 = get_char();
875                          if (dummych1 == '\'')
876                          {
877                              dummych2 = get_char();
878                              if (dummych2 == '\'')
879                              {
880                                  char dummych3 = get_char();
881                                  if (dummych3 == '\'')
882                                  {
883                                      // \''' : \' (escape) + '' (leave for xqdouble)
884                                      unget_char(dummych3);
885                                      unget_char(dummych2);
886                                      addlit("\'", 1);
887                                  }
888                                  else if (Character.isLetterOrDigit(dummych3) || dummych3 == '_')
889                                  {
890                                      // \''<letter/digit>: backslash literal + ''
891                                      // (string continues with xqdouble matching '')
892                                      unget_char(dummych3);
893                                      unget_char(dummych2);
894                                      unget_char(dummych1);
895                                  }
896                                  else if (dummych3 == ' ' || dummych3 == '\t')
897                                  {
898                                      char dummych4 = get_char();
899                                      char dummych5 = get_char();
900                                      String twoChars = "" + Character.toLowerCase(dummych4) + Character.toLowerCase(dummych5);
901                                      if (twoChars.equals("as"))
902                                      {
903                                          // \''<space>AS : \' (escape) + ' (close) + AS
904                                          unget_char(dummych5);
905                                          unget_char(dummych4);
906                                          unget_char(dummych3);
907                                          unget_char(dummych2);
908                                          addlit("\'", 1);
909                                      }
910                                      else
911                                      {
912                                          // \''<space><other> : backslash literal + ''
913                                          unget_char(dummych5);
914                                          unget_char(dummych4);
915                                          unget_char(dummych3);
916                                          unget_char(dummych2);
917                                          unget_char(dummych1);
918                                      }
919                                  }
920                                  else if (dummych3 == ';' || dummych3 == ',' || dummych3 == ')'
921                                          || dummych3 == '|' || dummych3 == '+' || dummych3 == '='
922                                          || dummych3 == '<' || dummych3 == '>' || dummych3 == '/'
923                                          || dummych3 == '*')
924                                  {
925                                      // \''<SQL-punctuation>: \' (escape) + ' (close)
926                                      unget_char(dummych3);
927                                      unget_char(dummych2);
928                                      addlit("\'", 1);
929                                  }
930                                  else if (dummych3 >= ' ' && dummych3 != (char)0 && dummych3 != (char)-1)
931                                  {
932                                      // Other printable: backslash literal + ''
933                                      unget_char(dummych3);
934                                      unget_char(dummych2);
935                                      unget_char(dummych1);
936                                  }
937                                  else
938                                  {
939                                      // \'' at EOF or control char: \' (escape) + ' (close)
940                                      unget_char(dummych3);
941                                      unget_char(dummych2);
942                                      addlit("\'", 1);
943                                  }
944                              }
945                              else
946                              {
947                                  // \' followed by non-quote: simple C-style escape
948                                  unget_char(dummych2);
949                                  addlit("\'", 1);
950                              }
951                          }
952                          else
953                          {
954                              unget_char(dummych1);
955                          }
956                      }
957                      break;
958                  }
959
960
961
962  case 22:
963            
964                  {
965                      start(init);
966                      addlit(yylvalstr, yytextlen);
967                      if ((literallen == 0) && (!insqlpluscmd))
968                        {returni (error);}
969                      if (literallen >= namedatalen)
970                      {
971                         setlengthofliteralbuf(namedatalen);
972                         literallen = namedatalen;
973                      }
974                      yylvalstr = litbufdup();
975                      returni (ident);
976
977                      break;
978                  }
979
980
981  case 23:
982                
983                  {
984                      if (insqlpluscmd){
985                          yyless(0);
986                          yylvalstr = litbufdup();
987                          start(init);
988                          returni(sconst);
989                      }else{
990                          addlit(yylvalstr, yytextlen);
991                      }
992
993                      break;
994                  }
995
996  case 24:
997               
998                  {
999                      addlit(yylvalstr, yytextlen);
1000                      break;
1001                  }
1002
1003  case 25:
1004         
1005                  {
1006                      // Handle ""identifier"" pattern from Snowflake GET_DDL() output.
1007                      // When we see " followed by another ", and then identifier content
1008                      // ending with "", consume the whole thing as one identifier token.
1009                      dummych1 = get_char();
1010                      if (dummych1 == '"') {
1011                          // We have "" at the start. Peek to see if identifier content follows.
1012                          dummych2 = get_char();
1013                          if (Character.isLetter(dummych2) || dummych2 == '_' || (dummych2 >= '\200' && dummych2 <= '\377')) {
1014                              // This is ""identifier..."" pattern. Read until closing "".
1015                              startlit();
1016                              addlit("\"\"", 2);
1017                              addlit(String.valueOf(dummych2), 1);
1018                              // Read chars until we find closing ""
1019                              while (true) {
1020                                  char ch = get_char();
1021                                  if (ch == '"') {
1022                                      char ch2 = get_char();
1023                                      if (ch2 == '"') {
1024                                          // Found "" - this is the closing ""
1025                                          addlit("\"\"", 2);
1026                                          yylvalstr = litbufdup();
1027                                          returni(ident);
1028                                          break;
1029                                      }
1030                                      // Single " not followed by " - treat as closing quote
1031                                      unget_char(ch2);
1032                                      addlit("\"", 1);
1033                                      yylvalstr = litbufdup();
1034                                      returni(ident);
1035                                      break;
1036                                  }
1037                                  if (ch == '\n' || ch == (char)0 || ch == (char)-1) {
1038                                      // End of line or input - close the identifier
1039                                      unget_char(ch);
1040                                      addlit("\"", 1);
1041                                      yylvalstr = litbufdup();
1042                                      returni(ident);
1043                                      break;
1044                                  }
1045                                  addlit(String.valueOf(ch), 1);
1046                              }
1047                              break;
1048                          }
1049                          // "" not followed by identifier content - push back and handle normally
1050                          unget_char(dummych2);
1051                          unget_char(dummych1);
1052                      } else {
1053                          unget_char(dummych1);
1054                      }
1055                      start(xd);
1056                      startlit();
1057                      addlit(yylvalstr, yytextlen);
1058                      break;
1059                  }
1060
1061  case 26:
1062                
1063                  {
1064                    dummych1 = get_char();
1065                    unget_char(dummych1);
1066                    if (dummych1 == (char)10)
1067                      {
1068                          if (insqlpluscmd){
1069                            nchars = yytextlen;
1070                            if(yylvalstr.charAt(nchars-1) == (char)13){
1071                                yyless(nchars - 1);
1072                                yylvalstr = yylvalstr.substring(0,nchars);
1073                            }
1074                              start(init);
1075                              addlit(yylvalstr, nchars-1);
1076                              yylvalstr = litbufdup();
1077                              returni(sconst); //in sqlplus command, characters between ' and return is treated as a string
1078
1079                          }else{
1080                          dummych1 = get_char();
1081                          addlit(yylvalstr+dummych1, yytextlen+1);
1082                          }
1083
1084                      } else
1085                        addlit(yylvalstr, yytextlen);
1086
1087                  break;
1088                  }
1089
1090  case 27:
1091                
1092                  {
1093                    returni(lexnewline);
1094                    break;
1095                  }
1096
1097  case 28:
1098        
1099                  {
1100                      returni(lexspace);
1101                      break;
1102                  }
1103
1104  case 29:
1105                
1106                  {
1107                  if ((getyysstate() == xq)
1108                      || (getyysstate() == xd)
1109                      || (getyysstate() == xc)
1110                   )
1111                  {
1112                      addlit(yylvalstr, 1);
1113                      yyless(1);
1114                      return;//exit;
1115                  }
1116
1117                  returni(cmtdoublehyphen);
1118                  break;
1119                  }
1120
1121  case 30:
1122      
1123                  {
1124                       if (yylvalstr.charAt(0) == '{') {
1125                           // Look ahead for {{variable}} template substitution syntax
1126                           char ch1 = get_char();
1127                           if (ch1 == '{') {
1128                               StringBuilder varBuf = new StringBuilder();
1129                               boolean closed = false;
1130                               while (true) {
1131                                   char ch = get_char();
1132                                   if (ch == 0) break;
1133                                   if (ch == '}') {
1134                                       char ch2 = get_char();
1135                                       if (ch2 == '}') {
1136                                           closed = true;
1137                                           break;
1138                                       } else {
1139                                           varBuf.append(ch);
1140                                           if (ch2 != 0) varBuf.append(ch2);
1141                                           else break;
1142                                       }
1143                                   } else {
1144                                       varBuf.append(ch);
1145                                   }
1146                               }
1147                               if (closed) {
1148                                   yylvalstr = "{{" + varBuf.toString() + "}}";
1149                                   yytextlen = yylvalstr.length();
1150                                   // Consume trailing identifier chars (e.g., {{env}}_suffix)
1151                                   StringBuilder trailBuf2 = new StringBuilder();
1152                                   while (true) {
1153                                       char tc2 = get_char();
1154                                       if (tc2 == 0) break;
1155                                       if (Character.isLetterOrDigit(tc2) || tc2 == '_') {
1156                                           trailBuf2.append(tc2);
1157                                       } else {
1158                                           unget_char(tc2);
1159                                           break;
1160                                       }
1161                                   }
1162                                   if (trailBuf2.length() > 0) {
1163                                       yylvalstr = yylvalstr + trailBuf2.toString();
1164                                       yytextlen = yylvalstr.length();
1165                                   }
1166                                   returni(ident);
1167                               } else {
1168                                   // Unclosed — put back and return '{'
1169                                   String s = varBuf.toString();
1170                                   for (int i = s.length() - 1; i >= 0; i--) {
1171                                       unget_char(s.charAt(i));
1172                                   }
1173                                   unget_char(ch1);
1174                                   returnc('{');
1175                               }
1176                           } else {
1177                               if (ch1 != 0) unget_char(ch1);
1178                               returnc('{');
1179                           }
1180                       } else {
1181                           returnc(yylvalstr.charAt(0));
1182                       }
1183                       break;
1184                  }
1185
1186  case 31:
1187                       
1188                  {
1189                    returni(cmpop);
1190                    break;
1191                  }
1192
1193  case 32:
1194           
1195                  {
1196
1197                  if (getyysstate() == xc)
1198                     {
1199                      slashstar = yylvalstr.indexOf("*/");
1200                        if (slashstar >= 0)
1201                          {
1202                              start(init);
1203                              addlit(yylvalstr,slashstar+2);
1204                              yylvalstr = litbufdup();
1205                              yyless(slashstar+2);
1206                              returni(cmtslashstar);
1207                          }
1208                        else
1209                          {
1210                              addlit(yylvalstr,1);
1211                              yyless(1);
1212                          }
1213                     }
1214                  else if (getyysstate() == xq)
1215                  {
1216                              addlit(yylvalstr,1);
1217                              yyless(1);
1218                  }
1219                  else
1220                    {
1221                      nchars = yytextlen;
1222                      slashstar = yylvalstr.indexOf("/*");
1223                      dashdash = yylvalstr.indexOf("--");
1224                      if ((slashstar > 0) && (dashdash > 0))
1225                        {
1226                          //if both appear, take the first one
1227                           if (slashstar > dashdash)
1228                            {slashstar = dashdash;}
1229                        }
1230                      else
1231                        {
1232                          //   if slashstar=0 then slashstar := dashdash;
1233                          // add (getyysstate <> xc) to avoid something like this */--,here */ should be handled instead of --
1234                          if ((slashstar > 0) && (getyysstate() != xc)) {
1235                            nchars = slashstar;
1236                            }
1237                        }
1238
1239                      while ((nchars > 1)
1240                              && ( (yylvalstr.charAt(nchars-1) == '+' )
1241                                  || (yylvalstr.charAt(nchars-1) =='-'))
1242                              && (getyysstate() != xc))
1243                        {
1244                          for (ic = nchars - 1; ic>=1; ic--)
1245                          {
1246                            if (isopchar(yylvalstr.charAt(ic-1)))  break;
1247                          }
1248                          if (ic >= 1) break;
1249                          nchars--;
1250                        }
1251
1252                      if (nchars < yytextlen)
1253                        {
1254                          //Strip the unwanted chars from the token
1255                          yyless(nchars);
1256                          yylvalstr = yylvalstr.substring(0,nchars);
1257                        }
1258
1259                          ///*
1260                          // * If what we have left is only one char, and it's
1261                          // * one of the characters matching "self", then
1262                          // * return it as a character token the same way
1263                          // * that the "self" rule would have.
1264                          // * make sure @ return as self char, by james wang
1265                          // */
1266                          if ((nchars == 1) && (isselfchar(yylvalstr.charAt(0)) || (yylvalstr.charAt(0) == '@')))
1267                            {
1268                              returnc(yylvalstr.charAt(0));
1269                            }
1270                          else if (
1271                                      (nchars >= 2)
1272                                          &&(
1273                                               charinarray(yylvalstr.charAt(nchars-1-1), tmparray)
1274                                               && ((yylvalstr.charAt(nchars-1) == ':')
1275                                                                ||(yylvalstr.charAt(nchars-1) == '.')
1276                                                        )
1277                                               )
1278                                   )
1279                              {
1280                                yyless(nchars-1);
1281                                 yylvalstr = yylvalstr.substring(0,nchars-1);
1282                                if (nchars == 2)
1283                                  returnc(yylvalstr.charAt(0));
1284                                else
1285                                  returni(op);
1286                              }
1287                            else if (
1288                                        (nchars >= 2)
1289                                            && (
1290                                                  charinarray(yylvalstr.charAt(nchars-1-1),tmparray)
1291                                                  && (yylvalstr.charAt(nchars-1) == '&')
1292                                                 )
1293                                       )
1294                                {
1295                                  yyless(nchars-1);
1296                                   yylvalstr = yylvalstr.substring(0,nchars-1);
1297                                  if (nchars == 2)
1298                                    returnc(yylvalstr.charAt(0));
1299                                  else
1300                                    returni(op);
1301                                }
1302                            else if ( (nchars > 1) && (yylvalstr.charAt(0) == '~'))
1303                              {
1304                                      yyless(1);
1305                                     returnc(yylvalstr.charAt(0));
1306                              }
1307                                                  else if ( (nchars == 2) && (yylvalstr.charAt(0) == '.') && (yylvalstr.charAt(1) == '*'))
1308                              {
1309                                      yyless(1);
1310                                     returnc(yylvalstr.charAt(0));
1311                              }
1312                                      else if ((nchars == 2) && ((yylvalstr.charAt(0) == '=') && ( (yylvalstr.charAt(1) == '?')||(yylvalstr.charAt(1) == '@')) ))
1313                                          {
1314                                            yyless(1);
1315                                            returnc(yylvalstr.charAt(0));
1316                                          }
1317                          else if ( (nchars >= 2) && ((yylvalstr.charAt(0) == '@')&&(yylvalstr.charAt(1) != '>')))
1318                            {
1319                                    yyless(1);
1320                                   returnc(yylvalstr.charAt(0));
1321                            }
1322                          else if ( (nchars >= 2) && ((yylvalstr.charAt(0) == '/')))
1323                            {
1324                                    yyless(1);
1325                                   returnc(yylvalstr.charAt(0));
1326                            }
1327                                                        else if (((nchars > 2) && (yylvalstr.charAt(0) == '*'))
1328                                      && (yylvalstr.charAt(1) == '/')
1329                                      && (getyysstate() == xc)
1330                                      )
1331                                   { //in comment, and find */ , then it must the end of comment
1332                                     yyless(2);
1333                                        addlit(yylvalstr,yytextlen);
1334                                     if (xcdepth <= 0)
1335                                       {
1336                                         start(init);
1337                                         yylvalstr = litbufdup();
1338                                         returni(cmtslashstar);
1339                                       }
1340                                     else
1341                                       xcdepth--;
1342                                   }
1343                              else
1344                                returni(op);
1345                       }
1346
1347                  break;
1348                  }
1349
1350  case 33:
1351                        
1352                  {
1353                       returni(iconst);
1354                       break;
1355                  }
1356
1357  case 34:
1358                        
1359                  {
1360                    ///*  for i in 1..5 loop, we can't recognize 1. as a decimal,but 1 as decimal
1361                    nchars = yytextlen;
1362                    if (yylvalstr.charAt(nchars-1) == '.')
1363                      {
1364                        dummych1 = get_char();
1365                        unget_char(dummych1);
1366                        if (dummych1 == '.')
1367                          {
1368                              yyless(nchars-1);
1369                            yylvalstr = yylvalstr.substring(0,nchars - 1);
1370                            returni (iconst);
1371                            return;//exit;
1372                          }
1373                      }
1374                    returni (fconst);
1375                   break;
1376                  }
1377
1378  case 35:
1379      
1380                  {
1381                   returni (fconst);
1382                   break;
1383                  }
1384
1385  case 36:
1386                                            
1387        {
1388     returni (sconst);
1389     break;
1390        }
1391
1392  case 37:
1393              
1394                  {
1395                     boolean dollarConstant = false;
1396                          if (getyysstate() == xdolq){
1397                           int p = yylvalstr.indexOf("$");
1398                       if (p > 0){
1399                           dollarConstant = true;
1400                           addlit(yylvalstr, p);
1401                          yyless(p);
1402                          return;
1403                       }
1404                      }
1405
1406                      // Handle identifiers ending with $$ inside function body (e.g., "b$$")
1407                      // When inside a function body, split identifier at $$ boundary
1408                      // Only split if the identifier contains $$ (the function body delimiter)
1409                      // Do NOT split identifiers like SYSTEM$TASK_RUNTIME_INFO that contain single $
1410                      if (functionBodyDelimiterIndex >= 0){ // inside function body
1411                          int p = yylvalstr.indexOf("$$");
1412                          if (p > 0){
1413                              yylvalstr = yylvalstr.substring(0,p);
1414                              yyless(p);
1415                          }
1416                      }
1417
1418                          if (!dollarConstant){
1419                        // Look ahead for {{variable}} template to merge with identifier
1420                        // e.g., FOCG{{env_suffix}} -> single ident "FOCG{{env_suffix}}"
1421                        while (true) {
1422                            char lk1 = get_char();
1423                            if (lk1 == '{') {
1424                                char lk2 = get_char();
1425                                if (lk2 == '{') {
1426                                    StringBuilder vBuf = new StringBuilder();
1427                                    boolean vClosed = false;
1428                                    while (true) {
1429                                        char vc = get_char();
1430                                        if (vc == 0) break;
1431                                        if (vc == '}') {
1432                                            char vc2 = get_char();
1433                                            if (vc2 == '}') { vClosed = true; break; }
1434                                            else { vBuf.append(vc); if (vc2 != 0) vBuf.append(vc2); else break; }
1435                                        } else { vBuf.append(vc); }
1436                                    }
1437                                    if (vClosed) {
1438                                        yylvalstr = yylvalstr + "{{" + vBuf.toString() + "}}";
1439                                        yytextlen = yylvalstr.length();
1440                                        // Continue loop to check for more {{}} or trailing identifier chars
1441                                        // Consume any trailing identifier chars after }}
1442                                        StringBuilder trailing = new StringBuilder();
1443                                        while (true) {
1444                                            char tc = get_char();
1445                                            if (tc == 0) break;
1446                                            if (Character.isLetterOrDigit(tc) || tc == '_') {
1447                                                trailing.append(tc);
1448                                            } else {
1449                                                unget_char(tc);
1450                                                break;
1451                                            }
1452                                        }
1453                                        if (trailing.length() > 0) {
1454                                            yylvalstr = yylvalstr + trailing.toString();
1455                                            yytextlen = yylvalstr.length();
1456                                        }
1457                                        continue; // check for another {{
1458                                    } else {
1459                                        String s = vBuf.toString();
1460                                        for (int si = s.length() - 1; si >= 0; si--) unget_char(s.charAt(si));
1461                                        unget_char(lk2);
1462                                        unget_char(lk1);
1463                                        break;
1464                                    }
1465                                } else {
1466                                    unget_char(lk2);
1467                                    unget_char(lk1);
1468                                    break;
1469                                }
1470                            } else {
1471                                if (lk1 != 0) unget_char(lk1);
1472                                break;
1473                            }
1474                        }
1475
1476                            int rw;
1477                            if ( (rw = iskeyword(yylvalstr)) != -1)   {
1478                            if (rw == TBaseType.rrw_as){
1479                                isReadyForFunctionBody = true;
1480                                // check whether language is javascript, if yes, don't set isReadyForFunctionBody to true
1481                                if ((TOKEN_TABLE[TBaseType.rrw_snowflake_language][COLUMN0_COUNT] > 0)
1482                                &&(TOKEN_TABLE[TBaseType.rrw_snowflake_javascript][COLUMN0_COUNT] > 0)){
1483                                    if (TOKEN_TABLE[TBaseType.rrw_snowflake_javascript][COLUMN5_FIRST_POS] - TOKEN_TABLE[TBaseType.rrw_snowflake_language][COLUMN5_FIRST_POS] <= 2){
1484                                        // RETURNS STRING LANGUAGE JAVASCRIPT
1485                                        // 如果是 RETURNS STRING LANGUAGE JAVASCRIPT,那么不需要设置isReadyForFunctionBody = true,即把整个$$...$$当作字符串处理
1486                                        isReadyForFunctionBody = false;
1487                                    }
1488                                }
1489                                // Also check for non-SQL languages (JAVA, PYTHON, SCALA) detected earlier
1490                                if (isNonSQLLanguageDetected) {
1491                                    isReadyForFunctionBody = false;
1492                                }
1493
1494                            }else if (rw == TBaseType.rrw_snowflake_language){
1495                                isLanguagePending = true;
1496                                isReadyForFunctionBody = false;
1497                            }else{
1498                                isReadyForFunctionBody = false;
1499                            }
1500                                                                      returni(rw);
1501                                                          }
1502                            else
1503                            {
1504                        if (isLanguagePending) {
1505                            String langName = yylvalstr.toLowerCase(Locale.ROOT);
1506                            if (langName.equals("java") || langName.equals("python") || langName.equals("scala")) {
1507                                isNonSQLLanguageDetected = true;
1508                            }
1509                            isLanguagePending = false;
1510                        }
1511                        isReadyForFunctionBody = false;
1512                        returni(ident);
1513                                                          }
1514                          }
1515
1516                    break;
1517                  }
1518 
1519  case 38:
1520        
1521      {
1522        if (getyysstate() == xdolq){
1523                                        addlit(yylvalstr, yytextlen);
1524          return;
1525        }else{
1526                returni (param);
1527        }
1528        
1529       break;
1530      }
1531
1532  case 39:
1533                
1534          {
1535           returni (outer_join);
1536           break;
1537          }
1538                                  
1539  case 40:
1540           
1541        {
1542     returni (typecast);
1543     break;
1544        }
1545        
1546  case 41:
1547           
1548        {
1549     returni (double_dot);
1550     break;
1551        }
1552
1553  case 42:
1554               
1555        {
1556     returni (assign_sign);
1557     break;
1558        }
1559
1560  case 43:
1561           
1562        {
1563     returni (variable);
1564     break;
1565        }
1566
1567  case 44:
1568               
1569        {
1570     returni (bind_v);
1571     break;
1572        }
1573        
1574        
1575  case 45:
1576          
1577          {
1578            // Backtick-quoted identifier (SnowSQL compatibility)
1579            StringBuilder buf = new StringBuilder();
1580            buf.append('`');
1581            while (true) {
1582                char ch = get_char();
1583                if (ch == 0) break;
1584                buf.append(ch);
1585                if (ch == '`') break;
1586            }
1587            yylvalstr = buf.toString();
1588            yytextlen = yylvalstr.length();
1589            returni(ident);
1590            break;
1591          }
1592
1593  case 46:
1594        
1595          {
1596            // Look ahead for ${variable} template substitution syntax
1597            char ch1 = get_char();
1598            if (ch1 == '{') {
1599                StringBuilder varBuf = new StringBuilder();
1600                boolean closed = false;
1601                while (true) {
1602                    char ch = get_char();
1603                    if (ch == 0) break;
1604                    if (ch == '}') { closed = true; break; }
1605                    varBuf.append(ch);
1606                }
1607                if (closed) {
1608                    // Simple ${name} — return as IDENT for template variable substitution
1609                    yylvalstr = "${" + varBuf.toString() + "}";
1610                    yytextlen = yylvalstr.length();
1611                    returni(ident);
1612                } else {
1613                    // Unclosed — put back and return error
1614                    String s = varBuf.toString();
1615                    for (int i = s.length() - 1; i >= 0; i--) {
1616                        unget_char(s.charAt(i));
1617                    }
1618                    unget_char('{');
1619                    returni(error);
1620                }
1621            } else {
1622                if (ch1 != 0) unget_char(ch1);
1623                returni(error);
1624            }
1625            break;
1626          }
1627
1628  case 47:
1629       
1630                  {
1631                   returni (error);
1632                   break;
1633                  }
1634
1635    default:{
1636     System.out.println("fatal error in yyaction");
1637    }
1638   }//switch
1639}/*yyaction*/;
1640
1641
1642
1643        }