前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Postgresql源码(86)varchar的创建与插入分析

Postgresql源码(86)varchar的创建与插入分析

作者头像
mingjie
发布2022-10-28 10:46:30
4850
发布2022-10-28 10:46:30
举报
文章被收录于专栏:Postgresql源码分析

一般PG数据类型不会带括号,varchar和numeric是比较特殊的基本类型,后面可以带括号指定长度或精度。

本篇回答下面两个问题:

  • 分析这种特殊类型(类型带括号)创建与使用细节。
  • 分析长度限制(括号内的值)在哪个阶段处理、生效。

0 总结速查

varchar和varchar(2)区别:

  1. 建表时:语法分析大体相同,varchar(2)会在TypeName->typmods链表上挂一个A_Const记录长度 限制。DDL执行后会记录到表结构中。
  2. 插入数据时:
    • 语法解析:生成值对应的A_Const记录原始数据。
    • 语义分析:varchar和varchar(2)都会在targetlist中所用Const记录,区别是有长度限制的字段的Const->consttypmod会记录具体限制的值(例如consttypmod=6表示长度限制为2,因为mod要减去varheadsize=4后使用)。
    • 优化器:优化器遇到consttypmod!=-1会构造表达式计算,调用varchar函数对Const进行验证,如果长度超出限制直接报错。(如何调入varchar函数?表达式执行框架,参考《Postgresql源码(85)》

1 建表

create table v1(c1 varchar, c2 varchar(2), c3 varchar(4));

1.1 varchar语法解析

varchar和varchar(2)的区别主要是在:

  • TypeName->typmods链表会挂一个A_Const记录括号内给的长度。

1.2 varchar语义解析

transform函数不会处理建表时的varchar类型,语义解析生成的Query树结构:

1.3 varchar优化器

优化器无处理。

2 插入

insert into v1 values ('12345', '12', '1234');

1.1 varchar语法解析

结果

代码语言:javascript
复制
InsertStmt
  relation
  selectStmt
    type = T_SelectStmt
    valuesLists = 0x2a26170
      {ptr_value = 0x2a25f80}
        {ptr_value = 0x2a25f50}
          {type = T_A_Const, fval = {type = T_String, fval = 0x2a25f38 "12345"}}
        {ptr_value = 0x2a25fe8}
          {type = T_A_Const, fval = {type = T_String, fval = 0x2a25f38 "12"}}
        {ptr_value = 0x2a26030}
          {type = T_A_Const, fval = {type = T_String, fval = 0x2a25f38 "1234"}}

1.2 varchar语义解析

语义分析结果,数据在targetList中包装成三个Const

代码语言:javascript
复制
Query
  rtable = 0x2a26d60
    {ptr_value = 0x2a26820}
      {type = T_RangeTblEntry, rtekind = RTE_RELATION, relid = 16489, relkind = 114 'r', ...}
  jointree = 0x2b11870
    {type = T_FromExpr, fromlist = 0x0, quals = 0x0}
  targetList = 0x2b11780
    {ptr_value = 0x2b11730}
      {xpr = {type = T_TargetEntry}, expr = 0x2a27118, resno = 1, resname = 0x2a26e50 "c1"}
        expr = 
          Const = 
            {xpr = {type = T_Const}, 
            consttype = 1043, 
            consttypmod = -1, 
            constcollid = 100, 
            constlen = -1, 
            constvalue = 44198808, 
            constisnull = false,
            constbyval = false, 
            location = 23}
    {ptr_value = 0x2b117d0}
      {xpr = {type = T_TargetEntry}, expr = 0x2a27330, resno = 2, resname = 0x2a26f58 "c2"}
        expr = 
          Const = 
            {xpr = {type = T_Const}, 
            consttype = 1043, 
            consttypmod = 6,      // 6 - 4(varheadersize) = 2 就是长度限制
            constcollid = 100, 
            constlen = -1, 
            constvalue = 45161664, 
            constisnull = false,
            constbyval = false, 
            location = -1}
    {ptr_value = 0x2b11820}
      {xpr = {type = T_TargetEntry}, expr = 0x2b116e0, resno = 3, resname = 0x2a26fc0 "c3"}
        expr = 
          Const = 
            {xpr = {type = T_Const}, 
            consttype = 1043, 
            consttypmod = 8, 
            constcollid = 100, 
            constlen = -1, 
            constvalue = 45162248, 
            constisnull = false,
            constbyval = false, 
            location = -1}

1.3 varchar优化器

优化器会把T_FuncExpr类型的Const执行掉

代码语言:javascript
复制
pg_plan_queries
  pg_plan_query
    planner
      standard_planner
        subquery_planner
          preprocess_expression
            eval_const_expressions
              eval_const_expressions_mutator
                expression_tree_mutator_impl
                  eval_const_expressions_mutator
                    expression_tree_mutator_impl
                      eval_const_expressions_mutator
                        simplify_function
                          evaluate_function
                            evaluate_expr
                              ExecEvalExprSwitchContext
                                ExecInterpExprStillValid
                                  ExecInterpExpr

函数ExecInterpExpr开始执行

  • p state->steps_len = 2, 共一步(结尾填充一步)
  • 处理分支 EEO_CASE(EEOP_FUNCEXPR_STRICT)

执行需要数据结构p op->d

代码语言:javascript
复制
p op->d.func

  finfo = 0x2b1cd98, 
    FmgrInfo = {fn_addr = 0xb100d8 <varchar>, fn_oid = 669, fn_nargs = 3, fn_strict = true, fn_retset = false, fn_stats = 2 '\002', fn_extra = 0x0, fn_mcxt = 0x2b1c9e0, fn_expr = 0x2b121a8}
  
  fcinfo_data = 0x2b1cde8, 
    FunctionCallInfo = {flinfo = 0x2b1cd98, context = 0x0, resultinfo = 0x0, fncollation = 100, isnull = false, nargs = 3, args = 0x2b1ce08}
      args[0] = {value = 44200488, isnull = false}
      args[1] = {value = 6, isnull = false}
      args[2] = {value = 0, isnull = false}
      
  
  fn_addr = 0xb100d8 <varchar>, 
  nargs = 3}

执行过程

代码语言:javascript
复制
ExecInterpExpr
...
...
		EEO_CASE(EEOP_FUNCEXPR_STRICT)
		{
			FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
			NullableDatum *args = fcinfo->args;
			int			nargs = op->d.func.nargs;
			Datum		d;

// nargs = 3
			/* strict function, so check for NULL args */
			for (int argno = 0; argno < nargs; argno++)
			{
				if (args[argno].isnull)
				{
					*op->resnull = true;
					goto strictfail;
				}
			}
			fcinfo->isnull = false;
			d = op->d.func.fn_addr(fcinfo);
			*op->resvalue = d;
			*op->resnull = fcinfo->isnull;

	strictfail:
			EEO_NEXT();
		}

进入varchar函数,3个入参:

代码语言:javascript
复制
VarChar *source = {vl_len_ = "\030\000\000", vl_dat = 0x2a2722c "12"}
int32 typmod = 6
bool isExplicit = false

当前长度:

代码语言:javascript
复制
len = VARSIZE_ANY_EXHDR(source);
len = 2

最大长度:

代码语言:javascript
复制
maxlen = typmod - VARHDRSZ;
2 = 6 - 4

长度合适可以直接返回,如果长度不满足,在varchar函数中报错。

最终优化器输出:可以看到TargetEntry只有常量Const了,函数Const被优化器处理掉了。

代码语言:javascript
复制
PlannedStmt
  planTree = 0x2a26930
    ModifyTable
      lefttree = 0x2b12c48
        Result
          targetlist = 0x2b12d28
            {ptr_value = 0x2b12cd8}
              TargetEntry
                expr = Const{consttype = 1043, consttypmod = -1, constcollid = 100, constlen = -1, constvalue = 44200296}
                resno = 1, 
                resname = 0x2a26e50 "c1"
            {ptr_value = 0x2b12d78}
              TargetEntry
                expr = Const{consttype = 1043, consttypmod = 6, constcollid = 100, constlen = -1, constvalue = 45163000}
                resno = 2, 
                resname = 0x2a26f58 "c2"
            {ptr_value = 0x2b12dc8}
              TargetEntry
                expr = Const{consttype = 1043, consttypmod = 8, constcollid = 100, constlen = -1, constvalue = 45163584}
                resno = 3, 
                resname = 0x2a26fc0 "c3"
          lefttree = 0x0, 
          righttree = 0x0
      righttree = 0x0
      resultRelations = 0x2b12b08
      
  rtable = 0x2b12ea8
    {ptr_value = 0x2a26ba0}
      {type = T_RangeTblEntry, rtekind = RTE_RELATION, relid = 16489, relkind = 114 'r'}
    {ptr_value = 0x2b12f48}
      {type = T_RangeTblEntry, rtekind = RTE_RESULT, relid = 0, relkind = 0 '\000'}
  resultRelations = 0x2b13058
  relationOids = 0x2b12ef8
  paramExecTypes = 0x2b12b58
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-10-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0 总结速查
  • 1 建表
    • 1.1 varchar语法解析
      • 1.2 varchar语义解析
        • 1.3 varchar优化器
        • 2 插入
          • 1.1 varchar语法解析
            • 1.2 varchar语义解析
              • 1.3 varchar优化器
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档