0
点赞
收藏
分享

微信扫一扫

MySQL如何初始化常量Item?

jjt二向箔 2023-06-15 阅读 93


MySQL中的一切表达式都是继承自Item类,常量也不外乎如此。以Item_float为例子说明MySQL如何初始化常量Item。

首先在Parser里面:

NUM_literal:
          NUM
          {
            int error;
            $$= new (YYTHD->mem_root)
                  Item_int($1,
                           (longlong) my_strtoll10($1.str, NULL, &error),
                           $1.length);
            if ($$ == NULL)
              MYSQL_YYABORT;
          }
        | LONG_NUM
          {
            int error;
            $$= new (YYTHD->mem_root)
                  Item_int($1,
                           (longlong) my_strtoll10($1.str, NULL, &error),
                           $1.length);
            if ($$ == NULL)
              MYSQL_YYABORT;
           }
        | ULONGLONG_NUM
          {
            $$= new (YYTHD->mem_root) Item_uint($1.str, $1.length);
            if ($$ == NULL)
              MYSQL_YYABORT;
          }
        | DECIMAL_NUM
          {
            $$= new (YYTHD->mem_root) Item_decimal($1.str, $1.length,
                                                   YYTHD->charset());
            if (($$ == NULL) || (YYTHD->is_error()))
            {
              MYSQL_YYABORT;
            }
          }
        | FLOAT_NUM
          {
            $$= new (YYTHD->mem_root) Item_float($1.str, $1.length);
            if (($$ == NULL) || (YYTHD->is_error()))
            {
              MYSQL_YYABORT;
            }
          }
        ;

FLOAT_NUM部分编译后变成如下代码:

case 1946:
/* Line 1455 of yacc.c  */
#line 13534 "/export/home/pb2/build/sb_0-15908920-1436909309.31
#            /mysql-5.6.26-release-export-8213452_gpl/sql/sql_yacc.yy"
{
     (yyval.item_num)=
        new (YYTHD->mem_root) Item_float((yyvsp[(1) - (1)].lex_str).str,
                                         (yyvsp[(1) - (1)].lex_str).length);
     if (((yyval.item_num) == NULL) || (YYTHD->is_error()))
     {
          MYSQL_YYABORT;
     }
}
break;

对应的Item_float构造函数为:

/**
  This function is only called during parsing:
  - when parsing SQL query from sql_yacc.yy
  - when parsing XPath query from item_xmlfunc.cc
  We will signal an error if value is not a true double value (overflow):
  eng: Illegal %s '%-.192s' value found during parsing

  Note: str_arg does not necessarily have to be a null terminated string,
  e.g. it is NOT when called from item_xmlfunc.cc or sql_yacc.yy.
*/

Item_float::Item_float(const char *str_arg, uint length)
{
  int error;
  char *end_not_used;
  value= my_strntod(&my_charset_bin, (char*) str_arg,
                    length, &end_not_used,
                    &error);
  if (error)
  {
    char tmp[NAME_LEN + 1];
    my_snprintf(tmp, sizeof(tmp), "%.*s", length, str_arg);
    my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "double", tmp);
  }
  presentation.copy(str_arg, length);
  item_name.copy(str_arg, length);
  decimals=(uint8) nr_of_decimals(str_arg, str_arg+length);
  max_length=length;
  fixed= 1;
}

可见,对于Float、Int、Decimal等,都是先传入字符串及其长度,然后他们内部进行解析,以确定max_length、decimals等值。

既然说到了Item_float,就顺便说一下里面的一个函数nr_of_decimals,它用来计算浮点数中小数点后面的位数,然而,如代码中的注释所言,这个函数跟没有啥鸟用,是Decimal出现之前的产物。在Decimal出现之前 1.35会被当做一个浮点数,下面的函数会计算出decimal=2;有了Decimal之后,1.35根本不会被当做float,而是直接当做Decimal处理。

static uint nr_of_decimals(const char *str, const char *end)
{
  const char *decimal_point;

  /* Find position for '.' */
  for (;;)
  {
    if (str == end)
      return 0;
    if (*str == 'e' || *str == 'E')
      return NOT_FIXED_DEC;
    if (*str++ == '.')
      break;
  }
  decimal_point= str;
  for ( ; str < end && my_isdigit(system_charset_info, *str) ; str++)
    ;
  if (str < end && (*str == 'e' || *str == 'E'))
    return NOT_FIXED_DEC;
  /*
    QQ:
    The number of decimal digist in fact should be (str - decimal_point - 1).
    But it seems the result of nr_of_decimals() is never used!

    In case of 'e' and 'E' nr_of_decimals returns NOT_FIXED_DEC.
    In case if there is no 'e' or 'E' parser code in sql_yacc.yy
    never calls Item_float::Item_float() - it creates Item_decimal instead.

    The only piece of code where we call Item_float::Item_float(str, len)
    without having 'e' or 'E' is item_xmlfunc.cc, but this Item_float
    never appears in metadata itself. Changing the code to return
    (str - decimal_point - 1) does not make any changes in the test results.

    This should be addressed somehow.
    Looks like a reminder from before real DECIMAL times.
  */
  return (uint) (str - decimal_point);
  }

所以,对于float来说,这个函数总是返回NOT_FIXED_DEC(=31)

fix variable decimals which always is NOT_FIXED_DEC

关于NOT_FIXED_DEC,会在下一篇博客中详细讨论。


举报

相关推荐

0 条评论