【OpenGauss源码学习(CopyOneRowTo)】

可优化语句执行

  • 概述
  • CopyOneRowTo函数
    • ScalarVector类
    • CopySendString 函数
    • FixedRowOut 函数
    • CopySendInt32 函数
    • CopySendData 函数
    • appendBinaryStringInfo 函数

声明:本文的部分内容参考了他人的文章。在编写过程中,我们尊重他人的知识产权和学术成果,力求遵循合理使用原则,并在适用的情况下注明引用来源。
本文主要参考了 OpenGauss1.1.0 的开源代码

概述

  本文主要围绕列存储进行学习。

CopyOneRowTo函数

  CopyOneRowTo 函数的作用是将一个数据行(row)从一个源 ScalarVector 复制到目标 ScalarVector,以实现数据的拷贝。具体来说,它用于在处理批次数据时,从一个源列(ScalarVector)复制数据到另一个目标列(ScalarVector),以便在数据处理过程中进行转换修改等操作,CopyOneRowTo 函数帮助实现了批次数据的复制和转换。
  CopyOneRowTo函数源码如下:(src/gausskernel/optimizer/commands/copy.cpp

/** Emit one row during CopyTo().*/
static void CopyOneRowTo(CopyState cstate, Oid tupleOid, Datum* values, const bool* nulls)
{bool need_delim = false;  // 标志是否需要添加分隔符FmgrInfo* out_functions = cstate->out_functions;  // 输出函数的信息MemoryContext oldcontext;  // 保存旧的内存上下文ListCell* cur = NULL;  // 遍历属性列表的指针char* string = NULL;  // 临时字符串// 重置行内存上下文,切换到行内存上下文MemoryContextReset(cstate->rowcontext);oldcontext = MemoryContextSwitchTo(cstate->rowcontext);if (IS_BINARY(cstate)) {// 对于二进制格式,发送元组的二进制头部信息CopySendInt16(cstate, list_length(cstate->attnumlist));// 如果需要,发送 OIDif (cstate->oids) {// 假设 Oid 和 int32 大小相同CopySendInt32(cstate, sizeof(int32));CopySendInt32(cstate, tupleOid);}} else if (cstate->oids) {// 对于文本格式,如果需要,发送 OID// 假设数字不需要引用或编码转换string = DatumGetCString(DirectFunctionCall1(oidout, ObjectIdGetDatum(tupleOid)));CopySendString(cstate, string);need_delim = true;}// 是否为固定列宽if (IS_FIXED(cstate))FixedRowOut(cstate, values, nulls);else {// 遍历属性列表foreach (cur, cstate->attnumlist) {int attnum = lfirst_int(cur);  // 属性序号Datum value = values[attnum - 1];  // 属性值bool isnull = nulls[attnum - 1];  // 是否为 NULL 值if (cstate->fileformat == FORMAT_CSV || cstate->fileformat == FORMAT_TEXT) {// 对于 CSV 或文本格式,添加分隔符if (need_delim)CopySendString(cstate, cstate->delim);need_delim = true;}if (isnull) {// 处理 NULL 值switch (cstate->fileformat) {case FORMAT_CSV:case FORMAT_TEXT:CopySendString(cstate, cstate->null_print_client);break;case FORMAT_BINARY:CopySendInt32(cstate, -1);break;default:ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Invalid file format")));}} else {if (!IS_BINARY(cstate)) {// 非二进制格式,将值转换为字符串并处理string = OutputFunctionCall(&out_functions[attnum - 1], value);switch (cstate->fileformat) {case FORMAT_CSV:CopyAttributeOutCSV(cstate,string,cstate->force_quote_flags[attnum - 1],list_length(cstate->attnumlist) == 1);break;case FORMAT_TEXT:CopyAttributeOutText(cstate, string);break;default:ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Invalid file format")));}} else {// 二进制格式,调用输出函数并发送数据bytea* outputbytes = NULL;outputbytes = SendFunctionCall(&out_functions[attnum - 1], value);CopySendInt32(cstate, VARSIZE(outputbytes) - VARHDRSZ);CopySendData(cstate, VARDATA(outputbytes), VARSIZE(outputbytes) - VARHDRSZ);}}}}// 发送行数据,并切换回旧的内存上下文cstate->writelineFunc(cstate);(void)MemoryContextSwitchTo(oldcontext);
}

ScalarVector类

  ScalarVector 类是一种数据结构,用于存储单一数据列的向量化数据。在数据库系统中,数据通常以表格的形式存储,每个列都包含一组数据。ScalarVector 类的作用是为了优化这些列数据的处理,提高数据访问和计算的效率。
  ScalarVector 类的源码如下:(路径:src/include/vecexecutor/vectorbatch.h

// the core data structure for a column
class ScalarVector : public BaseObject {friend class VectorBatch;public:// number of values.int m_rows;// type desciption information for this scalar value.ScalarDesc m_desc;// this value means that the value in the scalarvector is always the samebool m_const;// flags in the scalar value array.uint8* m_flag;// a company buffer for store the data if the data type is not plain.VarBuf* m_buf;// the value array.ScalarValue* m_vals;public:// decode a variable length data.// null value judgement should be outside of this function.FORCE_INLINEstatic Datum Decode(ScalarValue val){return val;}// convert a datum to scalar valuestatic ScalarValue DatumToScalar(Datum datumVal, Oid datumType, bool isNull);template <Oid datumType>static ScalarValue DatumToScalarT(Datum datumVal, bool isNull);public:// constructor/deconstructor.ScalarVector();~ScalarVector();// init the ScalarVector.//void init(MemoryContext cxt, ScalarDesc desc);// used in tsdb. init with another ScalarVector object.//void init(MemoryContext cxt, ScalarVector* vec, const int batchSize);// serialize the Scalar vector//void Serialize(StringInfo buf);// serialize the Scalar vector of the particular index//void Serialize(StringInfo buf, int idx);// Deserialize the vector//char* Deserialize(char* msg, size_t len);// Add a variable length data// this var may be from// cstring, fixed length(> 8) data type, or pg traditional header-contain variable lengthDatum AddVar(Datum data, int index);// Add a header-contain variableDatum AddVarWithHeader(Datum data);// Add a variable without header on a special position. The original variable will be// transfered in together with the length of the content. And inside the funtion, the header// of the ScalarValue will be added before the actual content according to the data type.Datum AddBPCharWithoutHeader(const char* data, int maxLen, int len, int aindex);Datum AddVarCharWithoutHeader(const char* data, int len, int aindex);// Add a short decimal without header on a special position. The value of decimal// will be transfered in by int64 format together with the scale of it. And inside the function,// the header will be added and the value will be converted into PG format. Here we only support// short decimal which can be stored using int64.Datum AddShortNumericWithoutHeader(int64 value, uint8 scale, int aindex);Datum AddBigNumericWithoutHeader(int128 value, uint8 scale, int aindex);char* AddVars(const char* src, int length);// add a normal header-contain valDatum AddHeaderVar(Datum data, int index);// add a cstring type valDatum AddCStringVar(Datum data, int index);// add a fixed length valtemplate <Size len>Datum AddFixLenVar(Datum data, int index);// copy a vectorvoid copy(ScalarVector* vector, int start_idx, int endIdx);void copy(ScalarVector* vector);void copyDeep(ScalarVector* vector, int start_idx, int endIdx);void copyNth(ScalarVector* vector, int Nth);void copy(ScalarVector* vector, const bool* pSel);// convert a cstring to Scalar value.static Datum DatumCstringToScalar(Datum data, Size len);// convert a fixed len datatype to Scalar Valuestatic Datum DatumFixLenToScalar(Datum data, Size len);FORCE_INLINEbool IsNull(int i){Assert(i >= 0 && i < m_rows);return ((m_flag[i] & V_NULL_MASK) == V_NULL_MASK);}FORCE_INLINEvoid SetNull(int i){Assert(i >= 0 && i < BatchMaxSize);m_flag[i] |= V_NULL_MASK;}FORCE_INLINEvoid SetAllNull(){for (int i = 0; i < m_rows; i++) {SetNull(i);}}private:// init some function pointer.void BindingFp();Datum (ScalarVector::*m_addVar)(Datum data, int index);
};

CopySendString 函数

  CopySendString 函数,这个函数的目的是将字符串数据添加到 CopyState 结构中的前端消息缓冲区中,以便之后将这些数据发送给客户端。它使用 appendBinaryStringInfo 函数将字符串数据追加到消息缓冲区中。CopySendString 函数源码如下:(src/gausskernel/optimizer/commands/copy.cpp

// CopySendString does the same for null-terminated strings
void CopySendString(CopyState cstate, const char* str)
{appendBinaryStringInfo(cstate->fe_msgbuf, str, strlen(str));
}

  appendBinaryStringInfo 函数用于向StringInfo结构中追加任意二进制数据。首先,它会检查 StringInfo 结构是否为空。然后,根据需要分配更多空间以容纳要追加的数据。接下来,使用 memcpy_s 函数将数据追加到 StringInfo 结构的末尾,并更新长度信息。最后,会在字符串的末尾添加一个 null 字符,即使对于二进制数据来说,这个 null 字符可能没有实际用处。appendBinaryStringInfo 函数源码如下:(src/common/backend/lib/stringinfo.cpp

/** appendBinaryStringInfo** 向StringInfo结构追加任意二进制数据,如果需要的话会分配更多空间。*/
void appendBinaryStringInfo(StringInfo str, const char* data, int datalen)
{Assert(str != NULL);  // 断言:确保StringInfo结构非空/* 如果需要的话分配更多空间 */enlargeStringInfo(str, datalen);/* 追加数据 */errno_t rc = memcpy_s(str->data + str->len, (size_t)(str->maxlen - str->len), data, (size_t)datalen);securec_check(rc, "\0", "\0");str->len += datalen;/** 保持末尾的null,尽管对于二进制数据来说可能没有用处。* (一些调用者处理的是文本数据,但是因为输入没有以null结尾,所以调用了这个函数。)*/str->data[str->len] = '\0';
}

  DatumGetCString 是一个宏,作用是将 Datum 类型的数据转换为C字符串。源码如下:(路径:src/include/postgres.h

/** DatumGetCString*		Returns C string (null-terminated string) value of a datum.** Note: C string is not a full-fledged Postgres type at present,* but type input functions use this conversion for their inputs.*/#define DatumGetCString(X) ((char*)DatumGetPointer(X))

FixedRowOut 函数

  FixedRowOut 函数是在固定列宽格式下将一行数据输出。它首先根据格式信息扩展输出缓冲区,然后遍历每个字段进行处理,根据字段的值和是否为null,调用相应的处理函数输出数据或null值。源码如下:(路径:src/gausskernel/optimizer/commands/formatter.cpp

// 固定列宽格式下输出一行数据
void FixedRowOut(CopyState cstate, Datum* values, const bool* nulls)
{// 获取输出函数信息和固定列宽格式信息FmgrInfo* out_functions = cstate->out_functions; // 输出函数信息FixFormatter* formatter = (FixFormatter*)cstate->formatter; // 固定列宽格式信息FieldDesc* descs = formatter->fieldDesc; // 字段描述char* string = NULL; // 临时字符串指针// 根据行大小扩展输出缓冲区enlargeStringInfo(cstate->fe_msgbuf, formatter->lineSize);// 遍历每个字段进行处理for (int i = 0; i < formatter->nfield; i++) {// 获取当前字段的属性序号和对应的值int attnum = formatter->fieldDesc[i].attnum; // 当前字段属性序号Datum value = values[attnum - 1]; // 当前字段值bool isnull = nulls[attnum - 1]; // 当前字段是否为null// 根据是否为null进行处理if (isnull) {// 调用AttributeOutFixed函数输出null值AttributeOutFixed<false>(cstate, descs[i].nullString, descs + i);} else {// 对非null值,调用输出函数并输出string = OutputFunctionCall(&out_functions[attnum - 1], value);Assert(string != NULL);AttributeOutFixed<false>(cstate, string, descs + i);}}
}

CopySendInt32 函数

  CopySendInt32 函数用于将一个 int32 类型的值以网络字节序发送出去。它首先将传入的 int32 值转换为网络字节序,并将结果存储在 buf 中,然后通过调用 CopySendData 函数将 buf 中的数据发送出去。函数源码如下:(路径:src/gausskernel/optimizer/commands/copy.cpp

/** 这些函数会进行一些数据转换*//** CopySendInt32 以网络字节序发送 int32 类型的值*/
static void CopySendInt32(CopyState cstate, int32 val)
{uint32 buf;// 将 int32 类型的值转换为网络字节序,并存储在 buf 中buf = htonl((uint32)val);// 调用 CopySendData 函数将 buf 中的数据发送出去,发送的字节数为 sizeof(buf)CopySendData(cstate, &buf, sizeof(buf));
}

CopySendData 函数

  这段代码定义了一系列发送数据的函数,这些函数会将指定的数据追加到 cstate->fe_msgbuf 中,其中 cstateCopyState 结构体的指针,表示数据拷贝的状态。这些函数分别用于发送二进制数据、以 null 结尾的字符串、单个字符以及在每行数据末尾执行适当的操作。这些函数并不会对数据进行任何转换,只是简单地将数据追加到消息缓冲区中。

/* ----------* CopySendData 将输出数据发送到目标(文件或前端)* CopySendString 对以 null 结尾的字符串执行相同操作* CopySendChar 对单个字符执行相同操作* CopySendEndOfRow 在每行数据末尾执行适当的操作*  (实际上只有在 CopySendEndOfRow 时才会刷新数据,其他函数不会刷新数据)** 注意:这些函数不会对数据进行任何转换* ----------*/
static void CopySendData(CopyState cstate, const void* databuf, int datasize)
{// 调用 appendBinaryStringInfo 函数将指定大小的数据追加到 cstate->fe_msgbuf 中appendBinaryStringInfo(cstate->fe_msgbuf, (const char*)databuf, datasize);
}

appendBinaryStringInfo 函数

  appendBinaryStringInfo 函数接受一个 StringInfo 结构体指针 str,一个 const char* 类型的数据指针 data,以及一个整数 datalen,表示数据的长度。函数会首先确保 str 不为空,然后根据需要分配更多空间,将指定长度的数据复制到 str 的数据缓冲区中,然后更新已追加数据的长度,并在数据末尾添加一个 null 字符,以保证字符串的正确终止。这个函数通常用于将二进制数据添加到 StringInfo 结构体中,StringInfo 是一个动态字符串结构体,它的大小可以根据需要自动增长。源码如下:(路径:src/common/backend/lib/stringinfo.cpp

/** appendBinaryStringInfo** 将任意的二进制数据追加到 StringInfo 中,如果需要的话会分配更多的空间。*/
void appendBinaryStringInfo(StringInfo str, const char* data, int datalen)
{Assert(str != NULL);  // 断言确保 str 不为空/* 如果需要的话分配更多空间 */enlargeStringInfo(str, datalen);/* 将数据追加到 str 中 */errno_t rc = memcpy_s(str->data + str->len, (size_t)(str->maxlen - str->len), data, (size_t)datalen);securec_check(rc, "\0", "\0");str->len += datalen;  // 更新已追加数据的长度/** 保持末尾的 null 字符,即使对于二进制数据它可能没有用处。* (一些调用者处理文本,但调用这个函数是因为输入可能没有以 null 结尾。)*/str->data[str->len] = '\0';
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/46977.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HTTPS代理搭建技巧分享

今天我们来分享一下如何搭建一个能够实现中间人 检测和防护的HTTPS代理。保护我们的网络通信安全是至关重要的&#xff0c;让我们一起学习如何构建一个安全可靠的HTTPS代理吧&#xff01; 什么是中间人 &#xff1f; 首先&#xff0c;让我们来了解一下什么是中间人 。中间人 是…

RK3399平台开发系列讲解(内核调试篇)内核中内存泄漏的调试

🚀返回专栏总目录 文章目录 一、Linux 内核内存泄漏二、如何观测内核内存泄漏?三、kmemleak 工具沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 内核内存泄漏往往都会是很严重的问题,那么,我们该如何判断内存泄漏是否是内核导致的呢? 一、Linux 内核内存泄漏 …

GPT-3.5——从 人工智障 到 大人工智障

有人说&#xff0c;GPT是从人工智障到人工智能的蜕变&#xff0c;但是。。。 我认为&#xff0c;GPT是从 人工智障 到 大人工智障 的退化。。。 从 人工智障 到 大人工智障 GPT-3.5学术介绍No.1---- 西红柿炒钢丝球基本信息详细制作方法材料步骤 幕后花絮 No.2---- 顶尖数学家…

【数据分析入门】Jupyter Notebook

目录 一、保存/加载二、适用多种编程语言三、编写代码与文本3.1 编辑单元格3.2 插入单元格3.3 运行单元格3.4 查看单元格 四、Widgets五、帮助 Jupyter Notebook是基于网页的用于交互计算的应用程序。其可被应用于全过程计算&#xff1a;开发、文档编写、运行代码和展示结果。 …

自然语言处理从入门到应用——LangChain:索引(Indexes)-[文本分割器(Text Splitters)]

分类目录&#xff1a;《自然语言处理从入门到应用》总目录 当我们需要处理长文本时&#xff0c;有必要将文本分割成块。虽然这听起来很简单&#xff0c;但这里存在很多潜在的复杂性。理想情况下&#xff0c;我们希望将语义相关的文本块保持在一起&#xff0c;但什么是"语义…

自动驾驶合成数据科普一:不做真实数据的“颠覆者”,做“杠杆”

前言&#xff1a; 在7月底的一篇文章中&#xff0c;九章智驾提到&#xff0c;数据闭环能力是自动驾驶下半场的“入场券”&#xff0c;这一观点在行业内引起了广泛共鸣。 在数据闭环体系中&#xff0c;仿真技术无疑是非常关键的一环。仿真的起点是数据&#xff0c;而数据又分为真…

基于MATLAB开发AUTOSAR软件应用层Code mapping专题-part 3 Paramter标签页介绍

这页是参数设置的界面,那首先要知道什么是参数,参数就是算法中的系数这些可以更改的变量,接下来就是要学习如何创建参数,如下图: 打开模型资源管理器 选择model Workspace标签,点击上边工具栏里的创建参数的按钮(红色箭头指向的按钮),添加一个新的参数K,值设置为4,数…

linux部署clickhouse(单机)

一、下载安装 1.1、下载地址 阿里巴巴开源镜像站-OPSX镜像站-阿里云开发者社区阿里巴巴开源镜像站&#xff0c;免费提供Linux镜像下载服务&#xff0c;拥有Ubuntu、CentOS、Deepin、MongoDB、Apache、Maven、Composer等多种开源软件镜像源&#xff0c;此外还提供域名解析DNS、…

opencv进阶14-Harris角点检测-cv2.cornerHarris

类似于人的眼睛和大脑&#xff0c;OpenCV可以检测图像的主要特征并将这 些特征提取到所谓的图像描述符中。然后&#xff0c;可以将这些特征作为数据 库&#xff0c;支持基于图像的搜索。此外&#xff0c;我们可以使用关键点将图像拼接起 来&#xff0c;组成更大的图像。&#x…

软件开发bug问题跟踪与管理

一、Redmine 项目管理和缺陷跟踪工具 官网&#xff1a;https://www.redmine.org/ Redmine 是一个开源的、基于 Web 的项目管理和缺陷跟踪工具。它用日历和甘特图辅助项目及进度可视化显示&#xff0c;同时它又支持多项目管理。Redmine 是一个自由开源软件解决方案&#xff0c;…

手机传感器的基础知识

目录 1. 手机传感器的种类 2. 手机传感器的工作原理 3.不同类型的传感器 1. 手机传感器的种类 常见的手机传感器有加速度计、陀螺仪、磁力计、距离传感器、光线传感器、压力传感器等。这些传感器可以测量手机的运动状态、方向、磁场、光照强度、压力等信息。 2. 手机传感器…

idea - 报错 Mybatis提示Tag name expected的问题< 小于号 无法识别

问题&#xff1a;Mybatis提示Tag name expected 原因&#xff1a; 当我们在mapper中编写sql语句的时候会发现使用"<“符号会提示一个Tag name expected。这是因为xml文件中不识别”<"符号和“&”符号。防止与xml本身的元素命名混淆&#xff0c;导致无法解…

通过DBeaver 给Postgre SQL表 设置主键自增

1.创建表 CREATE TABLE public.company ( id int4 NOT NULL , name text NOT NULL, age int4 NOT NULL, address bpchar(50) NULL, salary float4 NULL, join_date date NULL, CONSTRAINT company_pkey PRIMARY KEY (id) ); 2.插入数据&#xff08;不传入id&#xff…

Vue使用html2canvas将DOM节点生成对应的PDF

要通过Vue使用html2canvas将DOM节点生成对应的PDF&#xff0c;您需要安装html2canvas和jspdf这两个库。html2canvas用于将DOM节点转换为Canvas&#xff0c;而jspdf用于将Canvas转换为PDF。以下是一个简单的示例代码&#xff0c;展示了如何使用html2canvas和jspdf生成PDF文件&am…

机器学习:什么是分类/回归/聚类/降维/决策

目录 学习模式分为三大类&#xff1a;监督&#xff0c;无监督&#xff0c;强化学习 监督学习基本问题 分类问题 回归问题 无监督学习基本问题 聚类问题 降维问题 强化学习基本问题 决策问题 如何选择合适的算法 我们将涵盖目前「五大」最常见机器学习任务&#xff1a…

Android学习之路(7) Frament

Fragment 表示应用界面中可重复使用的一部分。fragment 定义和管理自己的布局&#xff0c;具有自己的生命周期&#xff0c;并且可以处理自己的输入事件。fragment 不能独立存在。它们必须由 activity 或其他 fragment 托管。fragment 的视图层次结构会成为宿主的视图层次结构的…

人事变动?前沃尔沃汽车大中华区总裁钦培吉将加盟吉利

根据消息&#xff0c;吉利控股集团高级副总裁杨学良在今天上午通过微博宣布&#xff0c;前沃尔沃汽车大中华区总裁钦培吉将加盟吉利。钦培吉将担任吉利汽车集团销售公司副总经理&#xff0c;并负责集团渠道发展委员会的主任一职&#xff0c;向吉利汽车集团的高级副总裁林杰报告…

0006Java程序设计-jsp婚恋交友网设计与实现

摘 要 在线交友是互联网发展的必然产物&#xff0c;它改变了人们的网络交往形态&#xff0c;使得人们的即时通信变得更加的直观和亲切&#xff0c;并且具有良好的发展趋势。 婚恋交友网站我们使用 Microsoft公司的JSP开发工具&#xff0c;利用其提供的各种面向对象的开发工具…

【C#学习笔记】委托和事件

文章目录 委托委托的定义委托实例化委托的调用多播委托 为什么使用委托&#xff1f;官方委托泛型方法和泛型委托 事件为什么要有事件&#xff1f;事件和委托的区别&#xff1a; 题外话——委托与观察者模式 委托 在 .NET 中委托提供后期绑定机制。 后期绑定意味着调用方在你所…

java面向对象——继承以及super关键字

继承的概念 1. 被继承的类称为父类&#xff08;超类&#xff09;&#xff0c;继承父类的类都称为子类&#xff08;派生类&#xff09; 2. 继承是指一个对象直接使用另一个对象的属性和方法&#xff0c;但是能继承非私有的属性和方法&#xff1b;(1) 构造方法不能被继承。(2) 但…