pg11新特性,可以瞬间向一个表中添加非空默认字段。
今天研究了一下这个特性的内核实现方式,写个博客简单记录一下。
结论奉上
pg在从硬盘或者内存获取到一条数据记录后(以下称tuple),会使用
heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc,Datum *values, bool *isnull)
函数把这个tuple根据其所在表的表结构(tupleDesc)进行"肢解",肢解结果放到values数组里。
也就是说values数组里的每一个元素对应着一个字段的值。isnull也是一个数组,这个数组记录着
对应的字段是否有值。
在pg11中heap_deform_tuple()函数增加了一段代码
for (; attnum < tdesc_natts; attnum++)
values[attnum] = getmissingattr(tupleDesc, attnum + 1, &isnull[attnum]);
用于对values为空但是有缺失默认值的字段追加赋值。
(只对增加列时就制定了默认值的字段有效,先增加列后指定默认值的无效)
这样增加字段的之前tuple的数据没有任何改动的情况下,就可以查询出默认值。
系统表的改变
postgres=# \d pg_attribute
Table "pg_catalog.pg_attribute"
Column | Type | Collation | Nullable | Default
---------------+-----------+-----------+----------+---------
attrelid | oid | | not null |
attname | name | | not null |
atttypid | oid | | not null |
attstattarget | integer | | not null |
attlen | smallint | | not null |
attnum | smallint | | not null |
attndims | integer | | not null |
attcacheoff | integer | | not null |
atttypmod | integer | | not null |
attbyval | boolean | | not null |
attstorage | "char" | | not null |
attalign | "char" | | not null |
attnotnull | boolean | | not null |
atthasdef | boolean | | not null |
atthasmissing | boolean | | not null |
attidentity | "char" | | not null |
attisdropped | boolean | | not null |
attislocal | boolean | | not null |
attinhcount | integer | | not null |
attcollation | oid | | not null |
attacl | aclitem[] | | |
attoptions | text[] | | |
attfdwoptions | text[] | | |
attmissingval | anyarray | | |
Indexes:
"pg_attribute_relid_attnam_index" UNIQUE, btree (attrelid, attname)
"pg_attribute_relid_attnum_index" UNIQUE, btree (attrelid, attnum)
postgres=#
系统表pg_attribute中增加了atthasmissing和attmissingval字段。
atthasmissing:这个字段是否有缺失默认值
attmissingval:缺失默认值,getmissingattr()函数获取的值的来源就是这里。
增加一个有默认值的字段时这个字段的atthasmissing设置为true,attmissingval设置为默认值。
注意:当修改某个字段的默认值时,只会修改pg_attrdef系统表里的默认值,不会修改pg_attribute表里的默认值
也就是说,增加列之后缺失默认值的值不会再发生改变。如果你在增加列时未指定默认值,那么这个列的值永远不
会自动填充。