相关 Postgresql源码(51)变长类型实现(valena.c)) Postgresql源码(56)可扩展类型分析ExpandedObject/ExpandedRecord
ExpandedObjectHeader总结:在应用时注意第七点,有的函数(datumCopy)需要的不是EOH头(4B头),是需要一个eoh_rw_ptr指针(1b_e头)。在使用函数前确认好datum传什么进去。
-1
= 0b11111111 11111111 11111111 11111111
ExpandedRecordHeader总结
扩展类型使用变长类型hdr来实现(遵循PG约定),下面第一部分分析header和相关函数,第二部分分析具体的扩展类型实现ExpandedRecordHeader。
struct ExpandedObjectHeader
{
/* Phony varlena header */
int32 vl_len_; /* always EOH_HEADER_MAGIC, see below */
const ExpandedObjectMethods *eoh_methods;
MemoryContext eoh_context;
char eoh_rw_ptr[EXPANDED_POINTER_SIZE]; // varattrib_1b_e 头加个 ExpandedObjectHeader指针
char eoh_ro_ptr[EXPANDED_POINTER_SIZE]; // varattrib_1b_e 头加个 ExpandedObjectHeader指针
};
typedef struct ExpandedObjectHeader ExpandedObjectHeader;
typedef struct varatt_expanded
{
ExpandedObjectHeader *eohptr;
} varatt_expanded;
typedef struct
{
uint8 va_header; /* Always 0x80 or 0x01 */
uint8 va_tag; /* Type of datum */
char va_data[FLEXIBLE_ARRAY_MEMBER]; /* Type-specific data */
} varattrib_1b_e;
varatt_expanded是什么?
ExpandedObjectHeader是什么?
EXPANDED_POINTER_SIZE = VARHDRSZ_EXTERNAL + sizeof(varatt_expanded)
保存了varattrib_1b_e的va_header、va_tag和一个指向ExpandedObjectHeader的指针eohptr。所以用这两个指针拿出去的是varattrib_1b_e头的指针。-1
=0b11111111 11111111 11111111 11111111
,按varattrib_4b的规范来看,低2位是表示类型的,这里是11四种类型有类似这样的继承关系:
varatt_expanded :ExpandedObjectHeader指针
|
|
ExpandedObjectHeader :扩展类型通用head
| \
| |
ExpandedRecordHeader ExpandedArrayHeader :两个扩展类型,扩展行类型和扩展数据类型
mermaid test:
#mermaid-svg-NplipRgANL0SJUZj {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-NplipRgANL0SJUZj .error-icon{fill:#552222;}#mermaid-svg-NplipRgANL0SJUZj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NplipRgANL0SJUZj .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-NplipRgANL0SJUZj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NplipRgANL0SJUZj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NplipRgANL0SJUZj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NplipRgANL0SJUZj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NplipRgANL0SJUZj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NplipRgANL0SJUZj .marker.cross{stroke:#333333;}#mermaid-svg-NplipRgANL0SJUZj svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NplipRgANL0SJUZj g.classGroup text{fill:#9370DB;fill:#131300;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-NplipRgANL0SJUZj g.classGroup text .title{font-weight:bolder;}#mermaid-svg-NplipRgANL0SJUZj .nodeLabel,#mermaid-svg-NplipRgANL0SJUZj .edgeLabel{color:#131300;}#mermaid-svg-NplipRgANL0SJUZj .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-NplipRgANL0SJUZj .label text{fill:#131300;}#mermaid-svg-NplipRgANL0SJUZj .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-NplipRgANL0SJUZj .classTitle{font-weight:bolder;}#mermaid-svg-NplipRgANL0SJUZj .node rect,#mermaid-svg-NplipRgANL0SJUZj .node circle,#mermaid-svg-NplipRgANL0SJUZj .node ellipse,#mermaid-svg-NplipRgANL0SJUZj .node polygon,#mermaid-svg-NplipRgANL0SJUZj .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-NplipRgANL0SJUZj .divider{stroke:#9370DB;stroke:1;}#mermaid-svg-NplipRgANL0SJUZj g.clickable{cursor:pointer;}#mermaid-svg-NplipRgANL0SJUZj g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-NplipRgANL0SJUZj g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-NplipRgANL0SJUZj .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-NplipRgANL0SJUZj .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-NplipRgANL0SJUZj .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-NplipRgANL0SJUZj .dashed-line{stroke-dasharray:3;}#mermaid-svg-NplipRgANL0SJUZj #compositionStart,#mermaid-svg-NplipRgANL0SJUZj .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-NplipRgANL0SJUZj #compositionEnd,#mermaid-svg-NplipRgANL0SJUZj .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-NplipRgANL0SJUZj #dependencyStart,#mermaid-svg-NplipRgANL0SJUZj .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-NplipRgANL0SJUZj #dependencyStart,#mermaid-svg-NplipRgANL0SJUZj .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-NplipRgANL0SJUZj #extensionStart,#mermaid-svg-NplipRgANL0SJUZj .extension{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-NplipRgANL0SJUZj #extensionEnd,#mermaid-svg-NplipRgANL0SJUZj .extension{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-NplipRgANL0SJUZj #aggregationStart,#mermaid-svg-NplipRgANL0SJUZj .aggregation{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-NplipRgANL0SJUZj #aggregationEnd,#mermaid-svg-NplipRgANL0SJUZj .aggregation{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-NplipRgANL0SJUZj .edgeTerminals{font-size:11px;}#mermaid-svg-NplipRgANL0SJUZj :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}
varatt_expanded
ExpandedObjectHeader *eohptr
ExpandedObjectHeader
int32 vl_len_
const ExpandedObjectMethods *eoh_methods
MemoryContext eoh_context
char eoh_rw_ptrEXPANDED_POINTER_SIZE
char eoh_ro_ptrEXPANDED_POINTER_SIZE
ExpandedRecordHeader
ExpandedArrayHeader
#define EOH_HEADER_MAGIC (-1)
/* EOH的va_header永远是-1,注意这里是EOH的header,这里用的4b头;里面eoh_rw_ptr用的是1b_e结构 */
#define VARATT_IS_EXPANDED_HEADER(PTR) \
(((varattrib_4b *) (PTR))->va_4byte.va_header == (uint32) EOH_HEADER_MAGIC)
#define EOHPGetRWDatum(eohptr) PointerGetDatum((eohptr)->eoh_rw_ptr)
#define EOHPGetRODatum(eohptr) PointerGetDatum((eohptr)->eoh_ro_ptr)
/* 给datum判断能不能写,注意这里的datum其实就对应着eoh_rw_ptr或eoh_ro_ptr,采用1b_e结构 */
#define DatumIsReadWriteExpandedObject(d, isnull, typlen) \
(((isnull) || (typlen) != -1) ? false : \
VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(d)))
#define MakeExpandedObjectReadOnly(d, isnull, typlen) \
(((isnull) || (typlen) != -1) ? (d) : \
MakeExpandedObjectReadOnlyInternal(d))
DatumGetEOHP:输入1b_e,返回EOH指针
ExpandedObjectHeader *
DatumGetEOHP(Datum d)
{
varattrib_1b_e *datum = (varattrib_1b_e *) DatumGetPointer(d);
varatt_expanded ptr;
memcpy(&ptr, VARDATA_EXTERNAL(datum), sizeof(ptr));
return ptr.eohptr;
}
EOH_init_header:输入eoh指针,初始化eoh结构,主要是eoh的两个1b_e结构的data部分,保存指向eoh的指针
void
EOH_init_header(ExpandedObjectHeader *eohptr,
const ExpandedObjectMethods *methods,
MemoryContext obj_context)
{
varatt_expanded ptr;
eohptr->vl_len_ = EOH_HEADER_MAGIC;
eohptr->eoh_methods = methods;
eohptr->eoh_context = obj_context;
ptr.eohptr = eohptr;
SET_VARTAG_EXTERNAL(eohptr->eoh_rw_ptr, VARTAG_EXPANDED_RW);
memcpy(VARDATA_EXTERNAL(eohptr->eoh_rw_ptr), &ptr, sizeof(ptr));
SET_VARTAG_EXTERNAL(eohptr->eoh_ro_ptr, VARTAG_EXPANDED_RO);
memcpy(VARDATA_EXTERNAL(eohptr->eoh_ro_ptr), &ptr, sizeof(ptr));
}
输入给一个1b_e指针,返回一个1b_e指向的eoh的只读部分的1b_e
Datum
MakeExpandedObjectReadOnlyInternal(Datum d)
{
ExpandedObjectHeader *eohptr;
/* Nothing to do if not a read-write expanded-object pointer */
if (!VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(d)))
return d;
/* Now safe to extract the object pointer */
eohptr = DatumGetEOHP(d);
/* Return the built-in read-only pointer instead of given pointer */
return EOHPGetRODatum(eohptr);
}
TransferExpandedObject把memorycontext挂在新的parent下面
Datum
TransferExpandedObject(Datum d, MemoryContext new_parent)
{
ExpandedObjectHeader *eohptr = DatumGetEOHP(d);
/* Assert caller gave a R/W pointer */
Assert(VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(d)));
/* Transfer ownership */
MemoryContextSetParent(eohptr->eoh_context, new_parent);
/* Return the object's standard read-write pointer */
return EOHPGetRWDatum(eohptr);
}
DeleteExpandedObject删除memorycontext
void
DeleteExpandedObject(Datum d)
{
ExpandedObjectHeader *eohptr = DatumGetEOHP(d);
/* Assert caller gave a R/W pointer */
Assert(VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(d)));
/* Kill it */
MemoryContextDelete(eohptr->eoh_context);
}
EOH的第二个变量提供了两个函数指针的位置,功能:
flattene格式数据必须是4b头的varlena对象
The flattened representation must be a valid in-line, non-compressed,4-byte-header varlena object.
typedef Size (*EOM_get_flat_size_method) (ExpandedObjectHeader *eohptr);
typedef void (*EOM_flatten_into_method) (ExpandedObjectHeader *eohptr,
void *result, Size allocated_size);
/* Struct of function pointers for an expanded object's methods */
typedef struct ExpandedObjectMethods
{
EOM_get_flat_size_method get_flat_size;
EOM_flatten_into_method flatten_into;
} ExpandedObjectMethods;
用传入类型构造EOH_RECORD
tupdesc->tdrefcount >= 0
,有别人引用,注册回调函数;drop table tf1;
create table tf1(c1 int, c2 int, c3 varchar(32), c4 varchar(32), c5 int);
insert into tf1 values(1,1000, 'China','Dalian', 23000);
insert into tf1 values(2,4000, 'Janpan', 'Tokio', 45000);
insert into tf1 values(3,1500, 'China', 'Xian', 25000);
insert into tf1 values(4,300, 'China', 'Changsha', 24000);
insert into tf1 values(5,400,'USA','New York', 35000);
insert into tf1 values(6,5000, 'USA', 'Bostom', 15000);
CREATE OR REPLACE PROCEDURE tfun1(id int) AS $$
DECLARE
row1 tf1%ROWTYPE;
row2 tf1%ROWTYPE;
BEGIN
select * into row1 from tf1 where c1 = 1;
select * into row1 from tf1 where c1 = id;
raise notice 'row1(record) %', row1;
select * into row2 from tf1 where c1 = 1;
row2.c2 = id;
raise notice 'row2(record) %', row2;
raise notice 'p_rrow2.c2(rowtypec) %', row2.c2;
END;
$$ LANGUAGE plpgsql;
CALL tfun1(1);
用tupledesc匹配有没有传入的列名,如果有返回true并填入ExpandedRecordFieldInfo返回
typedef struct ExpandedRecordFieldInfo
{
int fnumber; /* field's attr number in record */
Oid ftypeid; /* field's type/typmod info */
int32 ftypmod;
Oid fcollation; /* field's collation if any */
} ExpandedRecordFieldInfo;
用传入tuple向EOH_RECORD中塞值
(例如上面case中:select * into row1 from tf1 where c1 = 1;
,整个句子删除into row1后,用SPI去PG中执行,执行完了拿到tuple后,用这个函数给EOH_RECORD中塞值)(为什么不直接用tuple?因为tuple是紧凑的,适合存储不适合计算)
MemoryContextSwitchTo(erh->hdr.eoh_context)
newtuple = heap_copytuple(tuple)
erh->fvalue = newtuple;
erh->fstartptr = (char *) newtuple->t_data;
erh->fendptr = ((char *) newtuple->t_data) + newtuple->t_len;
erh->fvalue
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有