当前位置: 首页 > news >正文

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

一般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语法解析

结果

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

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执行掉

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

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}

执行过程

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个入参:

VarChar *source = {vl_len_ = "\030\000\000", vl_dat = 0x2a2722c "12"}
int32 typmod = 6
bool isExplicit = false

当前长度:

len = VARSIZE_ANY_EXHDR(source);
len = 2

最大长度:

maxlen = typmod - VARHDRSZ;
2 = 6 - 4

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

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

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

相关文章:

  • VMware创建虚拟机及安装Linux操作系统
  • 基于51单片机的指纹考勤机密码锁系统
  • 科研小白上路的必备工具链
  • HTML5七夕情人节表白代码 (动态3D相册) HTML+CSS+JS
  • 【云原生 | 从零开始学istio】一、Istio介绍—服务网格
  • 花咲の姫君(異時層ツキハ) / 花咲(异时层妖刀)
  • 体系结构实验(6)—— Cache映射策略
  • 牛客网专项练习30天Pytnon篇第16天
  • 【DS】6.堆知识总结!!!
  • kali工具熟悉——存活主机识别
  • 剖释C++内存管理底层细节 | 明晰池化技术中内存管理的原理
  • LVGL v8学习笔记 | 10 - Tabview控件的使用方法
  • 【漏洞复现-dedecms-文件上传】vulfocus/dedecms-cve_2019_8933
  • 罗克韦尔AB PLC安装Studio5000提示未安装Microsoft .NET Framework 3.5的解决方法
  • C++类和对象详解(下篇)
  • [分享]iOS开发-关于在xcode中引用文件夹右边出现问号的解决办法
  • “寒冬”下的金三银四跳槽季来了,帮你客观分析一下局面
  • 【挥舞JS】JS实现继承,封装一个extends方法
  • CAP 一致性协议及应用解析
  • gitlab-ci配置详解(一)
  • JS数组方法汇总
  • Median of Two Sorted Arrays
  • mysql常用命令汇总
  • nodejs:开发并发布一个nodejs包
  • Promise面试题2实现异步串行执行
  • rc-form之最单纯情况
  • supervisor 永不挂掉的进程 安装以及使用
  • TiDB 源码阅读系列文章(十)Chunk 和执行框架简介
  • V4L2视频输入框架概述
  • 动态魔术使用DBMS_SQL
  • 机器人定位导航技术 激光SLAM与视觉SLAM谁更胜一筹?
  • 全栈开发——Linux
  • 如何进阶一名有竞争力的程序员?
  • 如何使用Mybatis第三方插件--PageHelper实现分页操作
  • media数据库操作,可以进行增删改查,实现回收站,隐私照片功能 SharedPreferences存储地址:
  • 400多位云计算专家和开发者,加入了同一个组织 ...
  • ​一、什么是射频识别?二、射频识别系统组成及工作原理三、射频识别系统分类四、RFID与物联网​
  • ​一些不规范的GTID使用场景
  • #图像处理
  • $.ajax()参数及用法
  • %check_box% in rails :coditions={:has_many , :through}
  • (16)Reactor的测试——响应式Spring的道法术器
  • (9)目标检测_SSD的原理
  • (Java)【深基9.例1】选举学生会
  • (办公)springboot配置aop处理请求.
  • (二)【Jmeter】专栏实战项目靶场drupal部署
  • (力扣记录)235. 二叉搜索树的最近公共祖先
  • (六)什么是Vite——热更新时vite、webpack做了什么
  • (论文阅读22/100)Learning a Deep Compact Image Representation for Visual Tracking
  • (一)Neo4j下载安装以及初次使用
  • (转)拼包函数及网络封包的异常处理(含代码)
  • (转载)从 Java 代码到 Java 堆
  • ***通过什么方式***网吧
  • .net mvc actionresult 返回字符串_.NET架构师知识普及
  • .netcore 如何获取系统中所有session_如何把百度推广中获取的线索(基木鱼,电话,百度商桥等)同步到企业微信或者企业CRM等企业营销系统中...