home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 January / Chip_2001-01_cd1.bin / tema / mysql / mysql-3.23.28g-win-source.exe / sql / sql_lex.cpp < prev    next >
C/C++ Source or Header  |  2000-10-11  |  23KB  |  813 lines

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
  2.    
  3.    This program is free software; you can redistribute it and/or modify
  4.    it under the terms of the GNU General Public License as published by
  5.    the Free Software Foundation; either version 2 of the License, or
  6.    (at your option) any later version.
  7.    
  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.
  12.    
  13.    You should have received a copy of the GNU General Public License
  14.    along with this program; if not, write to the Free Software
  15.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  16.  
  17.  
  18. /* A lexical scanner on a temporary buffer with a yacc interface */
  19.  
  20. #include "mysql_priv.h"
  21. #include "item_create.h"
  22. #include <m_ctype.h>
  23. #include <hash.h>
  24.  
  25. LEX_STRING tmp_table_alias= {(char*) "tmp-table",8};
  26.  
  27. /* Macros to look like lex */
  28.  
  29. #define yyGet()        *(lex->ptr++)
  30. #define yyGetLast()    lex->ptr[-1]
  31. #define yyPeek()    lex->ptr[0]
  32. #define yyPeek2()    lex->ptr[1]
  33. #define yyUnget()    lex->ptr--
  34. #define yySkip()    lex->ptr++
  35. #define yyLength()    ((uint) (lex->ptr - lex->tok_start)-1)
  36.  
  37. #if MYSQL_VERSION_ID < 32300
  38. #define FLOAT_NUM    REAL_NUM
  39. #endif
  40.  
  41. pthread_key(LEX*,THR_LEX);
  42.  
  43. #define TOCK_NAME_LENGTH 24
  44.  
  45. /*
  46.   The following is based on the latin1 character set, and is only
  47.   used when comparing keywords
  48. */
  49.  
  50. uchar to_upper_lex[] = {
  51.     0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
  52.    16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
  53.    32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
  54.    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
  55.    64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
  56.    80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
  57.    96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
  58.    80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,123,124,125,126,127,
  59.   128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
  60.   144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
  61.   160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
  62.   176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
  63.   192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
  64.   208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
  65.   192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
  66.   208,209,210,211,212,213,214,247,216,217,218,219,220,221,222,255
  67. };
  68.  
  69. inline int lex_casecmp(const char *s, const char *t, uint len)
  70. {
  71.   while (len-- != 0 &&
  72.      to_upper_lex[(uchar) *s++] == to_upper_lex[(uchar) *t++]) ;
  73.   return (int) len+1;
  74. }
  75.  
  76. #include "lex_hash.h"
  77.  
  78. static uchar state_map[256];
  79.  
  80.  
  81. void lex_init(void)
  82. {
  83.   uint i;
  84.   DBUG_ENTER("lex_init");
  85.   for (i=0 ; i < array_elements(symbols) ; i++)
  86.     symbols[i].length=(uchar) strlen(symbols[i].name);
  87.   for (i=0 ; i < array_elements(sql_functions) ; i++)
  88.     sql_functions[i].length=(uchar) strlen(sql_functions[i].name);
  89.  
  90.   VOID(pthread_key_create(&THR_LEX,NULL));
  91.  
  92.   /* Fill state_map with states to get a faster parser */
  93.   for (i=0; i < 256 ; i++)
  94.   {
  95.     if (isalpha(i))
  96.       state_map[i]=(uchar) STATE_IDENT;
  97.     else if (isdigit(i))
  98.       state_map[i]=(uchar) STATE_NUMBER_IDENT;
  99. #if defined(USE_MB) && defined(USE_MB_IDENT)
  100.     else if (use_mb(default_charset_info) && my_ismbhead(default_charset_info, i))
  101.       state_map[i]=(uchar) STATE_IDENT;
  102. #endif
  103.     else if (!isgraph(i))
  104.       state_map[i]=(uchar) STATE_SKIP;      
  105.     else
  106.       state_map[i]=(uchar) STATE_CHAR;
  107.   }
  108.   state_map[(uchar)'_']=state_map[(uchar)'$']=(uchar) STATE_IDENT;
  109.   state_map[(uchar)'\'']=state_map[(uchar)'"']=(uchar) STATE_STRING;
  110.   state_map[(uchar)'-']=state_map[(uchar)'+']=(uchar) STATE_SIGNED_NUMBER;
  111.   state_map[(uchar)'.']=(uchar) STATE_REAL_OR_POINT;
  112.   state_map[(uchar)'>']=state_map[(uchar)'=']=state_map[(uchar)'!']= (uchar) STATE_CMP_OP;
  113.   state_map[(uchar)'<']= (uchar) STATE_LONG_CMP_OP;
  114.   state_map[(uchar)'&']=state_map[(uchar)'|']=(uchar) STATE_BOOL;
  115.   state_map[(uchar)'#']=(uchar) STATE_COMMENT;
  116.   state_map[(uchar)';']=(uchar) STATE_COLON;
  117.   state_map[(uchar)':']=(uchar) STATE_SET_VAR;
  118.   state_map[0]=(uchar) STATE_EOL;
  119.   state_map[(uchar)'\\']= (uchar) STATE_ESCAPE;
  120.   state_map[(uchar)'/']= (uchar) STATE_LONG_COMMENT;
  121.   state_map[(uchar)'*']= (uchar) STATE_END_LONG_COMMENT;
  122.   state_map[(uchar)'@']= (uchar) STATE_USER_END;
  123.   state_map[(uchar) '`']= (uchar) STATE_USER_VARIABLE_DELIMITER;
  124.   if (thd_startup_options & OPTION_ANSI_MODE)
  125.   {
  126.     state_map[(uchar) '"'] = STATE_USER_VARIABLE_DELIMITER;
  127.   }
  128.   DBUG_VOID_RETURN;
  129. }
  130.  
  131.  
  132. void lex_free(void)
  133. {                    // Call this when daemon ends
  134.   DBUG_ENTER("lex_free");
  135.   DBUG_VOID_RETURN;
  136. }
  137.  
  138.  
  139. LEX *lex_start(THD *thd, uchar *buf,uint length)
  140. {
  141.   LEX *lex= &thd->lex;
  142.   lex->next_state=STATE_START;
  143.   lex->end_of_query=(lex->ptr=buf)+length;
  144.   lex->yylineno = 1;
  145.   lex->create_refs=lex->in_comment=0;
  146.   lex->length=0;
  147.   lex->in_sum_expr=0;
  148.   lex->expr_list.empty();
  149.   lex->ftfunc_list.empty();
  150.   lex->convert_set=(lex->thd=thd)->convert_set;
  151.   lex->yacc_yyss=lex->yacc_yyvs=0;
  152.   lex->ignore_space=test(thd->client_capabilities & CLIENT_IGNORE_SPACE);
  153.   return lex;
  154. }
  155.  
  156. void lex_end(LEX *lex)
  157. {
  158.   lex->expr_list.delete_elements();    // If error when parsing sql-varargs
  159.   x_free(lex->yacc_yyss);
  160.   x_free(lex->yacc_yyvs);
  161. }
  162.  
  163.  
  164. static int find_keyword(LEX *lex, uint len, bool function)
  165. {
  166.   uchar *tok=lex->tok_start;
  167.  
  168.   SYMBOL *symbol = get_hash_symbol((const char *)tok,len,function);
  169.   if (symbol)
  170.   {
  171.     lex->yylval->symbol.symbol=symbol;
  172.     lex->yylval->symbol.str= (char*) tok;
  173.     lex->yylval->symbol.length=len;
  174.     return symbol->tok;
  175.   }
  176. #ifdef HAVE_DLOPEN
  177.   udf_func *udf;
  178.   if (function && using_udf_functions && (udf=find_udf((char*) tok, len)))
  179.   {
  180.     switch (udf->returns) {
  181.     case STRING_RESULT:
  182.       lex->yylval->udf=udf;
  183.       return (udf->type == UDFTYPE_FUNCTION) ? UDF_CHAR_FUNC : UDA_CHAR_SUM;
  184.     case REAL_RESULT:
  185.       lex->yylval->udf=udf;
  186.       return (udf->type == UDFTYPE_FUNCTION) ? UDF_FLOAT_FUNC : UDA_FLOAT_SUM;
  187.     case INT_RESULT:
  188.       lex->yylval->udf=udf;
  189.       return (udf->type == UDFTYPE_FUNCTION) ? UDF_INT_FUNC : UDA_INT_SUM;
  190.     }
  191.   }
  192. #endif
  193.   return 0;
  194. }
  195.  
  196.  
  197. /* make a copy of token before ptr and set yytoklen */
  198.  
  199. static inline LEX_STRING get_token(LEX *lex,uint length)
  200. {
  201.   LEX_STRING tmp;
  202.   yyUnget();            // ptr points now after last token char
  203.   tmp.length=lex->yytoklen=length;
  204.   tmp.str=(char*) sql_strmake((char*) lex->tok_start,tmp.length);
  205.   return tmp;
  206. }
  207.  
  208. /* Return an unescaped text literal without quotes */
  209. /* Fix sometimes to do only one scan of the string */
  210.  
  211. static char *get_text(LEX *lex)
  212. {
  213.   reg1 uchar c,sep;
  214.   uint found_escape=0;
  215.  
  216.   sep= yyGetLast();            // String should end with this
  217.   //lex->tok_start=lex->ptr-1;        // Remember '
  218.   while (lex->ptr != lex->end_of_query)
  219.   {
  220.     c = yyGet();
  221. #ifdef USE_MB
  222.     int l;
  223.     if (use_mb(default_charset_info) &&
  224.         (l = my_ismbchar(default_charset_info,
  225.                          (const char *)lex->ptr-1,
  226.                          (const char *)lex->end_of_query))) {
  227.     lex->ptr += l-1;
  228.     continue;
  229.     }
  230. #endif
  231.     if (c == '\\')
  232.     {                    // Escaped character
  233.       found_escape=1;
  234.       if (lex->ptr == lex->end_of_query)
  235.     return 0;
  236.       yySkip();
  237.     }
  238.     else if (c == sep)
  239.     {
  240.       if (c == yyGet())            // Check if two separators in a row
  241.       {
  242.     found_escape=1;            // dupplicate. Remember for delete
  243.     continue;
  244.       }
  245.       else
  246.     yyUnget();
  247.  
  248.       /* Found end. Unescape and return string */
  249.       uchar *str,*end,*start;
  250.  
  251.       str=lex->tok_start+1;
  252.       end=lex->ptr-1;
  253.       start=(uchar*) sql_alloc((uint) (end-str)+1);
  254.       if (!found_escape)
  255.       {
  256.     lex->yytoklen=(uint) (end-str);
  257.     memcpy(start,str,lex->yytoklen);
  258.     start[lex->yytoklen]=0;
  259.       }
  260.       else
  261.       {
  262.     uchar *to;
  263.     for (to=start ; str != end ; str++)
  264.     {
  265. #ifdef USE_MB
  266.       int l;
  267.       if (use_mb(default_charset_info) &&
  268.               (l = my_ismbchar(default_charset_info,
  269.                                (const char *)str, (const char *)end))) {
  270.           while (l--)
  271.           *to++ = *str++;
  272.           str--;
  273.           continue;
  274.       }
  275. #endif
  276.       if (*str == '\\' && str+1 != end)
  277.       {
  278.         switch(*++str) {
  279.         case 'n':
  280.           *to++='\n';
  281.           break;
  282.         case 't':
  283.           *to++= '\t';
  284.           break;
  285.         case 'r':
  286.           *to++ = '\r';
  287.           break;
  288.         case 'b':
  289.           *to++ = '\b';
  290.           break;
  291.         case '0':
  292.           *to++= 0;            // Ascii null
  293.           break;
  294.         case 'Z':            // ^Z must be escaped on Win32
  295.           *to++='\032';
  296.           break;
  297.         case '_':
  298.         case '%':
  299.           *to++= '\\';        // remember prefix for wildcard
  300.           /* Fall through */
  301.         default:
  302.           *to++ = *str;
  303.           break;
  304.         }
  305.       }
  306.       else if (*str == sep)
  307.         *to++= *str++;        // Two ' or "
  308.       else
  309.         *to++ = *str;
  310.  
  311.     }
  312.     *to=0;
  313.     lex->yytoklen=(uint) (to-start);
  314.       }
  315.       if (lex->convert_set)
  316.     lex->convert_set->convert((char*) start,lex->yytoklen);
  317.       return (char*) start;
  318.     }
  319.   }
  320.   return 0;                    // unexpected end of query
  321. }
  322.  
  323.  
  324. /*
  325. ** Calc type of integer; long integer, longlong integer or real.
  326. ** Returns smallest type that match the string.
  327. ** When using unsigned long long values the result is converted to a real
  328. ** because else they will be unexpected sign changes because all calculation
  329. ** is done with longlong or double.
  330. */
  331.  
  332. static const char *long_str="2147483647";
  333. static const uint long_len=10;
  334. static const char *signed_long_str="-2147483648";
  335. static const char *longlong_str="9223372036854775807";
  336. static const uint longlong_len=19;
  337. static const char *signed_longlong_str="-9223372036854775808";
  338. static const uint signed_longlong_len=19;
  339.  
  340.  
  341. inline static uint int_token(const char *str,uint length)
  342. {
  343.   if (length < long_len)            // quick normal case
  344.     return NUM;
  345.   bool neg=0;
  346.  
  347.   if (*str == '+')                // Remove sign and pre-zeros
  348.   {
  349.     str++; length--;
  350.   }
  351.   else if (*str == '-')
  352.   {
  353.     str++; length--;
  354.     neg=1;
  355.   }
  356.   while (*str == '0' && length)
  357.   {
  358.     str++; length --;
  359.   }
  360.   if (length < long_len)
  361.     return NUM;
  362.  
  363.   uint smaller,bigger;
  364.   const char *cmp;
  365.   if (neg)
  366.   {
  367.     if (length == long_len)
  368.     {
  369.       cmp= signed_long_str+1;
  370.       smaller=NUM;                // If <= signed_long_str
  371.       bigger=LONG_NUM;                // If >= signed_long_str
  372.     }
  373.     else if (length < signed_longlong_len)
  374.       return LONG_NUM;
  375.     else if (length > signed_longlong_len)
  376.       return REAL_NUM;
  377.     else
  378.     {
  379.       cmp=signed_longlong_str+1;
  380.       smaller=LONG_NUM;                // If <= signed_longlong_str
  381.       bigger=REAL_NUM;
  382.     }
  383.   }
  384.   else
  385.   {
  386.     if (length == long_len)
  387.     {
  388.       cmp= long_str;
  389.       smaller=NUM;
  390.       bigger=LONG_NUM;
  391.     }
  392.     else if (length < longlong_len)
  393.       return LONG_NUM;
  394.     else if (length > longlong_len)
  395.       return REAL_NUM;
  396.     else
  397.     {
  398.       cmp=longlong_str;
  399.       smaller=LONG_NUM;
  400.       bigger=REAL_NUM;
  401.     }
  402.   }
  403.   while (*cmp && *cmp++ == *str++) ;
  404.   return ((uchar) str[-1] <= (uchar) cmp[-1]) ? smaller : bigger;
  405. }
  406.  
  407.  
  408. // yylex remember the following states from the following yylex()
  409. // STATE_EOQ ; found end of query
  410. // STATE_OPERATOR_OR_IDENT ; last state was an ident, text or number
  411. //                  (which can't be followed by a signed number)
  412.  
  413. int yylex(void *arg)
  414. {
  415.   reg1    uchar c;
  416.   int    tokval;
  417.   uint length;
  418.   enum lex_states state,prev_state;
  419.   LEX    *lex=current_lex;
  420.   YYSTYPE *yylval=(YYSTYPE*) arg;
  421.  
  422.   lex->yylval=yylval;            // The global state
  423.   lex->tok_start=lex->tok_end=lex->ptr;
  424.   prev_state=state=lex->next_state;
  425.   lex->next_state=STATE_OPERATOR_OR_IDENT;
  426.   LINT_INIT(c);
  427.   for (;;)
  428.   {
  429.     switch(state) {
  430.     case STATE_OPERATOR_OR_IDENT:    // Next is operator or keyword
  431.     case STATE_START:            // Start of token
  432.       // Skipp startspace
  433.       for (c=yyGet() ; (state_map[c] == STATE_SKIP) ; c= yyGet())
  434.       {
  435.     if (c == '\n')
  436.       lex->yylineno++;
  437.       }
  438.       lex->tok_start=lex->ptr-1;    // Start of real token
  439.       state= (enum lex_states) state_map[c];
  440.       break;
  441.     case STATE_ESCAPE:
  442.       if (yyGet() == 'N')
  443.       {                    // Allow \N as shortcut for NULL
  444.     yylval->lex_str.str=(char*) "\\N";
  445.     yylval->lex_str.length=2;
  446.     return NULL_SYM;
  447.       }
  448.     case STATE_CHAR:            // Unknown or single char token
  449.     case STATE_SKIP:            // This should not happen
  450.       yylval->lex_str.str=(char*) (lex->ptr=lex->tok_start);// Set to first char
  451.       yylval->lex_str.length=1;
  452.       c=yyGet();
  453.       if (c != ')')
  454.     lex->next_state= STATE_START;    // Allow signed numbers
  455.       if (c == ',')
  456.     lex->tok_start=lex->ptr;    // Let tok_start point at next item
  457.       return((int) c);
  458.  
  459.     case STATE_IDENT:            // Incomplete keyword or ident
  460. #if defined(USE_MB) && defined(USE_MB_IDENT)
  461.       if (use_mb(default_charset_info))
  462.       {
  463.         if (my_ismbhead(default_charset_info, yyGetLast()))
  464.         {
  465.           int l = my_ismbchar(default_charset_info,
  466.                               (const char *)lex->ptr-1,
  467.                               (const char *)lex->end_of_query);
  468.           if (l == 0) {
  469.             state = STATE_CHAR;
  470.             continue;
  471.           }
  472.           lex->ptr += l - 1;
  473.         }
  474.         while (state_map[c=yyGet()] == STATE_IDENT ||
  475.                state_map[c] == STATE_NUMBER_IDENT)
  476.         {
  477.           if (my_ismbhead(default_charset_info, c))
  478.           {
  479.             int l;
  480.             if ((l = my_ismbchar(default_charset_info,
  481.                               (const char *)lex->ptr-1,
  482.                               (const char *)lex->end_of_query)) == 0)
  483.               break;
  484.             lex->ptr += l-1;
  485.           }
  486.         }
  487.       }
  488.       else
  489. #endif
  490.         while (state_map[c=yyGet()] == STATE_IDENT ||
  491.                state_map[c] == STATE_NUMBER_IDENT) ;
  492.       length= (uint) (lex->ptr - lex->tok_start)-1;
  493.       if (lex->ignore_space)
  494.       {
  495.     for ( ; state_map[c] == STATE_SKIP ; c= yyGet());
  496.       }
  497.       if (c == '.' && (state_map[yyPeek()] == STATE_IDENT ||
  498.                state_map[yyPeek()] == STATE_NUMBER_IDENT))
  499.     lex->next_state=STATE_IDENT_SEP;
  500.       else
  501.       {                    // '(' must follow directly if function
  502.     yyUnget();
  503.     if ((tokval = find_keyword(lex,length,c == '(')))
  504.     {
  505.       lex->next_state= STATE_START;    // Allow signed numbers
  506.       return(tokval);        // Was keyword
  507.     }
  508.     yySkip();            // next state does a unget
  509.       }
  510.       yylval->lex_str=get_token(lex,length);
  511.       return(IDENT);
  512.  
  513.     case STATE_IDENT_SEP:        // Found ident and now '.'
  514.       lex->next_state=STATE_IDENT_START;// Next is an ident (not a keyword)
  515.       yylval->lex_str.str=(char*) lex->ptr;
  516.       yylval->lex_str.length=1;
  517.       c=yyGet();            // should be '.'
  518.       return((int) c);
  519.  
  520.     case STATE_NUMBER_IDENT:        // number or ident which starts with num
  521.       while (isdigit((c = yyGet()))) ;
  522.       if (state_map[c] != STATE_IDENT)
  523.       {                    // Can't be identifier
  524.     state=STATE_INT_OR_REAL;
  525.     break;
  526.       }
  527.       if (c == 'e' || c == 'E')
  528.       {
  529.     // The following test is written this way to allow numbers of type 1e1
  530.     if (isdigit(yyPeek()) || (c=(yyGet())) == '+' || c == '-')
  531.     {                // Allow 1E+10
  532.       if (isdigit(yyPeek()))    // Number must have digit after sign
  533.       {
  534.         yySkip();
  535.         while (isdigit(yyGet())) ;
  536.         yylval->lex_str=get_token(lex,yyLength());
  537.         return(FLOAT_NUM);
  538.       }
  539.     }
  540.     yyUnget(); /* purecov: inspected */
  541.       }
  542.       else if (c == 'x' && (lex->ptr - lex->tok_start) == 2 &&
  543.       lex->tok_start[0] == '0' )
  544.       {                        // Varbinary
  545.     while (isxdigit((c = yyGet()))) ;
  546.     if ((lex->ptr - lex->tok_start) >= 4)
  547.     {
  548.       yylval->lex_str=get_token(lex,yyLength());
  549.       yylval->lex_str.str+=2;        // Skipp 0x
  550.       yylval->lex_str.length-=2;
  551.       lex->yytoklen-=2;
  552.       return (HEX_NUM);
  553.     }
  554.     yyUnget();
  555.       }
  556.       // fall through
  557.     case STATE_IDENT_START:        // Incomplete ident
  558. #if defined(USE_MB) && defined(USE_MB_IDENT)
  559.       if (use_mb(default_charset_info))
  560.       {
  561.         if (my_ismbhead(default_charset_info, yyGetLast()))
  562.         {
  563.           int l = my_ismbchar(default_charset_info,
  564.                               (const char *)lex->ptr-1,
  565.                               (const char *)lex->end_of_query);
  566.           if (l == 0)
  567.           {
  568.             state = STATE_CHAR;
  569.             continue;
  570.           }
  571.           lex->ptr += l - 1;
  572.         }
  573.         while (state_map[c=yyGet()] == STATE_IDENT ||
  574.                state_map[c] == STATE_NUMBER_IDENT)
  575.         {
  576.           if (my_ismbhead(default_charset_info, c))
  577.           {
  578.             int l;
  579.             if ((l = my_ismbchar(default_charset_info,
  580.                                  (const char *)lex->ptr-1,
  581.                                  (const char *)lex->end_of_query)) == 0)
  582.               break;
  583.             lex->ptr += l-1;
  584.           }
  585.         }
  586.       }
  587.       else
  588. #endif
  589.         while (state_map[c = yyGet()] == STATE_IDENT ||
  590.                state_map[c] == STATE_NUMBER_IDENT) ;
  591.  
  592.       if (c == '.' && (state_map[yyPeek()] == STATE_IDENT ||
  593.                state_map[yyPeek()] == STATE_NUMBER_IDENT))
  594.     lex->next_state=STATE_IDENT_SEP;// Next is '.'
  595.       // fall through
  596.  
  597.     case STATE_FOUND_IDENT:        // Complete ident
  598.       yylval->lex_str=get_token(lex,yyLength());
  599.       return(IDENT);
  600.  
  601.     case STATE_USER_VARIABLE_DELIMITER:
  602.       lex->tok_start=lex->ptr;            // Skipp first `
  603.       while ((c=yyGet()) && state_map[c] != STATE_USER_VARIABLE_DELIMITER &&
  604.          c != (uchar) NAMES_SEP_CHAR) ;
  605.       yylval->lex_str=get_token(lex,yyLength());
  606.       if (state_map[c] == STATE_USER_VARIABLE_DELIMITER)
  607.     yySkip();                // Skipp end `
  608.       return(IDENT);
  609.  
  610.     case STATE_SIGNED_NUMBER:        // Incomplete signed number
  611.       if (prev_state == STATE_OPERATOR_OR_IDENT)
  612.       {
  613.     if (c == '-' && yyPeek() == '-' && isspace(yyPeek2()))
  614.       state=STATE_COMMENT;
  615.     else
  616.       state= STATE_CHAR;        // Must be operator
  617.     break;
  618.       }
  619.       if (!isdigit(c=yyGet()) || yyPeek() == 'x')
  620.       {
  621.     if (c != '.')
  622.     {
  623.       if (c == '-' && isspace(yyPeek()))
  624.         state=STATE_COMMENT;
  625.       else
  626.         state = STATE_CHAR;        // Return sign as single char
  627.       break;
  628.     }
  629.     yyUnget();            // Fix for next loop
  630.       }
  631.       while (isdigit(c=yyGet())) ;    // Incomplete real or int number
  632.       if ((c == 'e' || c == 'E') &&
  633.       (yyPeek() == '+' || yyPeek() == '-' || isdigit(yyPeek())))
  634.       {                    // Real number
  635.     yyUnget();
  636.     c= '.';                // Fool next test
  637.       }
  638.       // fall through
  639.     case STATE_INT_OR_REAL:        // Compleat int or incompleat real
  640.       if (c != '.')
  641.       {                    // Found complete integer number.
  642.     yylval->lex_str=get_token(lex,yyLength());
  643.     return int_token(yylval->lex_str.str,yylval->lex_str.length);
  644.       }
  645.       // fall through
  646.     case STATE_REAL:            // Incomplete real number
  647.       while (isdigit(c = yyGet())) ;
  648.  
  649.       if (c == 'e' || c == 'E')
  650.       {
  651.     c = yyGet();
  652.     if (c != '-' && c != '+' && !isdigit(c))
  653.     {                // No exp sig found
  654.       state= STATE_CHAR;
  655.       break;
  656.     }
  657.     if (!isdigit(yyGet()))
  658.     {                // No digit after sign
  659.       state= STATE_CHAR;
  660.       break;
  661.     }
  662.     while (isdigit(yyGet())) ;
  663.     yylval->lex_str=get_token(lex,yyLength());
  664.     return(FLOAT_NUM);
  665.       }
  666.       yylval->lex_str=get_token(lex,yyLength());
  667.       return(REAL_NUM);
  668.  
  669.     case STATE_CMP_OP:            // Incomplete comparison operator
  670.       if (state_map[yyPeek()] == STATE_CMP_OP ||
  671.       state_map[yyPeek()] == STATE_LONG_CMP_OP)
  672.     yySkip();
  673.       if ((tokval = find_keyword(lex,(uint) (lex->ptr - lex->tok_start),0)))
  674.       {
  675.     lex->next_state= STATE_START;    // Allow signed numbers
  676.     return(tokval);
  677.       }
  678.       state = STATE_CHAR;        // Something fishy found
  679.       break;
  680.  
  681.     case STATE_LONG_CMP_OP:        // Incomplete comparison operator
  682.       if (state_map[yyPeek()] == STATE_CMP_OP ||
  683.       state_map[yyPeek()] == STATE_LONG_CMP_OP)
  684.       {
  685.     yySkip();
  686.     if (state_map[yyPeek()] == STATE_CMP_OP)
  687.       yySkip();
  688.       }
  689.       if ((tokval = find_keyword(lex,(uint) (lex->ptr - lex->tok_start),0)))
  690.       {
  691.     lex->next_state= STATE_START;    // Found long op
  692.     return(tokval);
  693.       }
  694.       state = STATE_CHAR;        // Something fishy found
  695.       break;
  696.  
  697.     case STATE_BOOL:
  698.       if (c != yyPeek())
  699.       {
  700.     state=STATE_CHAR;
  701.     break;
  702.       }
  703.       yySkip();
  704.       tokval = find_keyword(lex,2,0);    // Is a bool operator
  705.       lex->next_state= STATE_START;    // Allow signed numbers
  706.       return(tokval);
  707.  
  708.     case STATE_STRING:            // Incomplete text string
  709.       if (!(yylval->lex_str.str = get_text(lex)))
  710.       {
  711.     state= STATE_CHAR;        // Read char by char
  712.     break;
  713.       }
  714.       yylval->lex_str.length=lex->yytoklen;
  715.       return(TEXT_STRING);
  716.  
  717.     case STATE_COMMENT:            //  Comment
  718.       while ((c = yyGet()) != '\n' && c) ;
  719.       yyUnget();            // Safety against eof
  720.       state = STATE_START;        // Try again
  721.       break;
  722.     case STATE_LONG_COMMENT:        /* Long C comment? */
  723.       if (yyPeek() != '*')
  724.       {
  725.     state=STATE_CHAR;        // Probable division
  726.     break;
  727.       }
  728.       yySkip();                // Skip '*'
  729.       if (yyPeek() == '!')        // MySQL command in comment
  730.       {
  731.     ulong version=MYSQL_VERSION_ID;
  732.     yySkip();
  733.     state=STATE_START;
  734.     if (isdigit(yyPeek()))
  735.     {                // Version number
  736.       version=strtol((char*) lex->ptr,(char**) &lex->ptr,10);
  737.     }
  738.     if (version <= MYSQL_VERSION_ID)
  739.     {
  740.       lex->in_comment=1;
  741.       break;
  742.     }
  743.       }
  744.       while (lex->ptr != lex->end_of_query &&
  745.          ((c=yyGet()) != '*' || yyPeek() != '/'))
  746.       {
  747.     if (c == '\n')
  748.       lex->yylineno++;
  749.       }
  750.       if (lex->ptr != lex->end_of_query)
  751.     yySkip();            // remove last '/'
  752.       state = STATE_START;        // Try again
  753.       break;
  754.     case STATE_END_LONG_COMMENT:
  755.       if (lex->in_comment && yyPeek() == '/')
  756.       {
  757.     yySkip();
  758.     lex->in_comment=0;
  759.     state=STATE_START;
  760.       }
  761.       else
  762.     state=STATE_CHAR;        // Return '*'
  763.       break;
  764.     case STATE_SET_VAR:            // Check if ':='
  765.       if (yyPeek() != '=')
  766.       {
  767.     state=STATE_CHAR;        // Return ':'
  768.     break;
  769.       }
  770.       yySkip();
  771.       return (SET_VAR);
  772.     case STATE_COLON:            // optional line terminator
  773.       if (yyPeek())
  774.       {
  775.     state=STATE_CHAR;        // Return ';'
  776.     break;
  777.       }
  778.       /* fall true */
  779.     case STATE_EOL:
  780.       lex->next_state=STATE_END;    // Mark for next loop
  781.       return(END_OF_INPUT);
  782.     case STATE_END:
  783.       lex->next_state=STATE_END;
  784.       return(0);            // We found end of input last time
  785.  
  786.       // Actually real shouldn't start
  787.       // with . but allow them anyhow
  788.     case STATE_REAL_OR_POINT:
  789.       if (isdigit(yyPeek()))
  790.     state = STATE_REAL;        // Real
  791.       else
  792.       {
  793.     state = STATE_CHAR;        // return '.'
  794.     lex->next_state=STATE_IDENT_START;// Next is an ident (not a keyword)
  795.       }
  796.       break;
  797.     case STATE_USER_END:        // end '@' of user@hostname
  798.       if (state_map[yyPeek()] != STATE_STRING &&
  799.       state_map[yyPeek()] != STATE_USER_VARIABLE_DELIMITER)
  800.     lex->next_state=STATE_HOSTNAME;    // Mark for next loop     
  801.       yylval->lex_str.str=(char*) lex->ptr;
  802.       yylval->lex_str.length=1;
  803.       return((int) '@');
  804.     case STATE_HOSTNAME:        // end '@' of user@hostname
  805.       for (c=yyGet() ;
  806.        isalnum(c) || c == '.' || c == '_' || c == '$';
  807.        c= yyGet()) ;
  808.       yylval->lex_str=get_token(lex,yyLength());
  809.       return(LEX_HOSTNAME);
  810.     }
  811.   }
  812. }
  813.