暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PostgreSQL查询引擎——Transform Expressions之const

肥叔菌 2023-02-08
392

定义在src/backend/parser/parser_expr.c文件中的Node *transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)函数用于分析和转换表达式,包含类型检查和类型转换的工作。该函数将原始语法输出转换为具有完全确定语义的表达式树(Type checking and type casting is done here. This processing converts the raw grammar output into expression trees with fully determined semantics)。

static Node *transformExprRecurse(ParseState *pstate, Node *expr)
函数用于递归处理表达式,其整体代码框架如下所示。

    static Node *transformExprRecurse(ParseState *pstate, Node *expr){
    Node *result;
    if (expr == NULL) return NULL;
    check_stack_depth(); /* Guard against stack overflow due to overly complex expressions */


    switch (nodeTag(expr)){
    case T_ColumnRef:
    case T_ParamRef:
    case T_A_Const:
    {
    A_Const *con = (A_Const *) expr; Value *val = &con->val;
    result = (Node *) make_const(pstate, val, con->location);
    break;
    }
    case T_A_Indirection:
    case T_A_ArrayExpr:
    case T_TypeCast:
    case T_CollateClause:
    case T_A_Expr:
    case T_BoolExpr:
    case T_FuncCall:
    case T_MultiAssignRef:
    case T_GroupingFunc:
    case T_NamedArgExpr:
    case T_SubLink:
    case T_CaseExpr:
    case T_RowExpr:
    case T_CoalesceExpr:
    case T_MinMaxExpr:
    case T_SQLValueFunction:
    case T_XmlExpr:
    case T_XmlSerialize:
    case T_NullTest:
    case T_BooleanTest:
    case T_CurrentOfExpr:
    case T_SetToDefault:
    case T_CaseTestExpr:
    case T_Var:
    default:
    /* should not reach here */
    elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
    result = NULL; /* keep compiler quiet */ break;
    }
    return result;
    }
    复制

    T_A_Const

    T_A_Const分支代码用于将A_Const节点转换成Const,主要依靠make_const函数。该函数需要确定常量的数据类型OID、常量数据类型的字节大小typlen、常量值和值存储位置constbyval(true:数据存储在constvalue Datum中,false:数据存储在constvalue Datum指向的内存中)。该函数将Value节点(由语法返回)转换为常量的“自然”类型的Const节点。注意,此例程仅在常量没有显式转换时使用,因此我们必须猜测需要什么类型。对于字符串文本,我们生成一个UNKNOWN类型的常量,其表示形式与cstring相同,但它向稍后的类型解析表明,我们还不确定应该考虑什么类型(从上述常量规则来看,true和false也是T_String类型,其val.str为’t’和’f’,所以这里typeid需要设置为UNKNOWNOID,以供结合父节点判定其语义)。显式“NULL”常量也被类型化为UNKNOWN。对于整数和浮点数,我们根据数字的值生成int4、int8或数字。XXX我们也应该生成int2,但在完成之前需要进行额外的清理;如果我们尝试,有太多的例子会失败。Convert a Value node (as returned by the grammar) to a Const node of the “natural” type for the constant. Note that this routine is only used when there is no explicit cast for the constant, so we have to guess what type is wanted. For string literals we produce a constant of type UNKNOWN ---- whose representation is the same as cstring, but it indicates to later type resolution that we’re not sure yet what type it should be considered. Explicit “NULL” constants are also typed as UNKNOWN. For integers and floats we produce int4, int8, or numeric depending on the value of the number. XXX We should produce int2 as well, but additional cleanup is needed before we can do that; there are too many examples that fail if we try.

      Const *make_const(ParseState *pstate, Value *value, int location){
      Const *con; ParseCallbackState pcbstate;
      Datum val; int64 val64;
      Oid typeid; int typelen; bool typebyval;

      switch (nodeTag(value)){
      case T_Integer:
      val = Int32GetDatum(intVal(value)); typeid = INT4OID; typelen = sizeof(int32);typebyval = true;
      break;

      case T_Float:/* could be an oversize integer as well as a float ... */
      if (scanint8(strVal(value), true, &val64)){
      /* It might actually fit in int32. Probably only INT_MIN can occur, but we'll code the test generally just to be sure. */
      int32 val32 = (int32) val64;
      if (val64 == (int64) val32){
      val = Int32GetDatum(val32); typeid = INT4OID; typelen = sizeof(int32); typebyval = true;
      }else{
      val = Int64GetDatum(val64); typeid = INT8OID; typelen = sizeof(int64); typebyval = FLOAT8PASSBYVAL; /* int8 and float8 alike */
      }
      }else{/* arrange to report location if numeric_in() fails */
      setup_parser_errposition_callback(&pcbstate, pstate, location);
      val = DirectFunctionCall3(numeric_in, CStringGetDatum(strVal(value)), ObjectIdGetDatum(InvalidOid), Int32GetDatum(-1));
      cancel_parser_errposition_callback(&pcbstate);
      typeid = NUMERICOID; typelen = -1; /* variable len */ typebyval = false;
      }
      break;


      case T_String: /* We assume here that UNKNOWN's internal representation is the same as CSTRING */
      val = CStringGetDatum(strVal(value));
      typeid = UNKNOWNOID; /* will be coerced later */ typelen = -2; /* cstring-style varwidth type */ typebyval = false;
      break;


      case T_BitString:/* arrange to report location if bit_in() fails */
      setup_parser_errposition_callback(&pcbstate, pstate, location);
      val = DirectFunctionCall3(bit_in, CStringGetDatum(strVal(value)), ObjectIdGetDatum(InvalidOid), Int32GetDatum(-1));
      cancel_parser_errposition_callback(&pcbstate);
      typeid = BITOID; typelen = -1; typebyval = false;
      break;


      case T_Null:/* return a null const */
      con = makeConst(UNKNOWNOID, -1, InvalidOid, -2, (Datum) 0, true, false);
      con->location = location;
      return con;


      default:
      elog(ERROR, "unrecognized node type: %d", (int) nodeTag(value));
      return NULL; /* keep compiler quiet */
      }


      con = makeConst(typeid,-1, /* typmod -1 is OK for all cases */InvalidOid, /* all cases are uncollatable types */typelen,val,false,typebyval);
      con->location = location;
      return con;
      }
      复制

      欢迎关注微信公众号肥叔菌PostgreSQL数据库专栏:



      文章转载自肥叔菌,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

      评论