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

Postgresql源码(139)vim直接修改postgresql表文件的简单实例

1 前言

  1. PG可以用pageinspect方便的读取查看表文件。
  2. 本篇介绍一种用vim查看、编辑的方法,案例比较简单,主要分享原理。

修改表文件和controlfile是非常危险的行为,请不要在生产尝试。

2 用例

简化问题,用简单编码的数据类型。

drop table t1;
create table t1 (a int, b int);
insert into t1 select t.i, t.i/10 from generate_series(1,1000) t(i);

analyze t1;

select relname,relfilenode,relpages from pg_class where relname = 't1';
 relname | relfilenode | relpages
---------+-------------+----------
 t1      |       49158 |        5

checkpoint;

select ctid, xmin, * from t1 order by 1 limit 10 offset 220;
  ctid   |   xmin   |  a  | b
---------+----------+-----+----
 (0,221) | 50889007 | 221 | 22
 (0,222) | 50889007 | 222 | 22
 (0,223) | 50889007 | 223 | 22
 (0,224) | 50889007 | 224 | 22
 (0,225) | 50889007 | 225 | 22
 (0,226) | 50889007 | 226 | 22
 (1,1)   | 50889007 | 227 | 22
 (1,2)   | 50889007 | 228 | 22
 (1,3)   | 50889007 | 229 | 22
 (1,4)   | 50889007 | 230 | 23

模拟页面损坏,编辑修改a=230 b=23这一行的数据,把xmin编辑成错误的值,制造报错。

3 vim打开表文件找到页面位置

前面查询到表文件49158,使用vim编辑并转换为16进制显示:
在这里插入图片描述
转换后
在这里插入图片描述
每个页面8KB,一个页面的地址占用0x2000,所以一号页面的地址范围是0x2000 - 0x4000
(ctid得知我们需要修改的数据在1号页面)
在这里插入图片描述

4 根据地址定位元组位置

ctid = (1,4) 元组在1号页面的第4个位置,根据PG的页面布局,我们从页面尾部,向上找第四个元组

postgres=# select ctid, xmin, * from t1 where a = 230;
 ctid  |   xmin   |  a  | b
-------+----------+-----+----
 (1,4) | 50889007 | 230 | 23

在这里插入图片描述

根据页面地址范围,1号页面的结尾在00004000处,向上找四个元组,因为这里元组都是定长的,可以按规律找四个即可。这里数据简单可以用这种方法。

如果数据类型比较复杂,长短不一,可根据每个元组头部的xmin确定位置。例如我们需要找的元组的xmin是50889007,看到下面第四行的元组头部为

2f81 0803 = 十六进制:0x308812f = 十进制:50889007 等于xmin的值

所以可以根据xmin的值,从最后一个一个向上找。
在这里插入图片描述

5 如何解析表中的二进制数据?

拿到页面1的第四行数据:

00003f80: 2f81 0803 0000 0000 0000 0000 0000 0100
00003f90: 0400 0200 0009 1800 e600 0000 1700 0000

这段数据可以分成三段来看

第一部分:HeapTupleHeaderData
-----------------------------------
第二部分:nulls bitmap 不一定有
-----------------------------------
第三部分:具体数据值

头上一定是一个HeapTupleHeaderData,而HeapTupleHeaderData的第一个元素是一个uint32记录的xmin。

struct HeapTupleHeaderData
{
	union
	{
		HeapTupleFields t_heap;
		DatumTupleFields t_datum;
	}			t_choice;
	ItemPointerData t_ctid;		/* current TID of this or newer tuple (or a
	uint16		t_infomask2;	/* number of attributes + various flags */
	uint16		t_infomask;		/* various flag bits, see below */
	uint8		t_hoff;			/* sizeof header incl. bitmap, padding */
	bits8		t_bits[FLEXIBLE_ARRAY_MEMBER];	/* bitmap of NULLs */
	/* MORE DATA FOLLOWS AT END OF STRUCT */
};
typedef struct HeapTupleFields
{
	TransactionId t_xmin;		/* inserting xact ID */
	TransactionId t_xmax;		/* deleting or locking xact ID */
	union
	{
		CommandId	t_cid;		/* inserting or deleting command ID, or both */
		TransactionId t_xvac;	/* old-style VACUUM FULL xact ID */
	}			t_field3;
} HeapTupleFields;

所以按顺序来解析,因为我这台机器是小端序的(lscpu可以看),所以低地址存低位的值,解析出来:

  • 2f81 0803 = 十六进制:0x308812f = 十进制:50889007 等于xmin的值。
  • 0200 = 十六进制:0x2 = t_infomask2
  • 0009 = 十六进制:0x900 = t_infomask
  • e600 0000 = 十六进制:0xe6 = 十进制:230 = a列的值
  • 1700 0000 = 十六进制:0x17 = 十进制:23 = b列的值
00003f80:           2f81 0803 0000 0000 0000 0000 0000 0100
                    |        |         |         |         
                    |xmin(4B)| xmax(4B)| cid(4B) |  t_ctid
                    
00003f90:           0400  0200  0009 1800      e600 0000 1700 0000
                         |mask2|mask|hoff|     这里没有null值数组,所以就是数据了。
   
t_infomask  = 0x900
t_infomask2 = 0x02
t_hoff      = 0x18

结果和真实数据对得上:

postgres=# select ctid, xmin, * from t1 where a = 230;
 ctid  |   xmin   |  a  | b
-------+----------+-----+----
 (1,4) | 50889007 | 230 | 23

6 vim修改表文件中的数据

先做个实验,把b列的值也改成230:

select ctid, xmin, * from t1 where a = 230;
 ctid  |   xmin   |  a  | b
-------+----------+-----+----
 (1,4) | 50889007 | 230 | 23

在这里插入图片描述
使用vim编辑
在这里插入图片描述
转换回二进制:
在这里插入图片描述
wq保存退出。

重新查询b还是23,为什么呢?因为页面已经在shared_buffer中了,现在没有负载所以页面不会重新从磁盘读上来。
在这里插入图片描述

这里需要重启一下,注意不要kill -9,redo有可能会把数据盖掉,让数据库正常checkpoint后关闭,在启动:

在这里插入图片描述


http://www.kler.cn/a/468284.html

相关文章:

  • C++ static关键字(八股总结)
  • 极客说|微软 Phi 系列小模型和多模态小模型
  • 【C++】构造函数与析构函数
  • node.js内置模块之---http 和 https 模块
  • 《新概念模拟电路》-电流源电路
  • 【软考网工笔记】计算机基础理论与安全——网络规划与设计
  • 字玩FontPlayer开发笔记3 性能优化 大量canvas渲染卡顿问题
  • CSS——6. 导入样式
  • GraphRAG实践:neo4j试用
  • Xcode 16.1: Warning: unable to build chain to self-signed root for signer
  • 降维算法之PCA(PrincipalComponent Analysis,主成分分析)
  • Python实现一个简单的 HTTP echo 服务器
  • 举例说明AI模型怎么聚类,最后神经网络怎么保存
  • Linux 基础七 内存
  • 自动驾驶控制算法-横纵向控制仿真
  • 【pyqt】(二)基础框架
  • Anaconda环境配置(Windows11+python3.9)
  • 【Python】Flink和Flask区别总结
  • Markdown流程图
  • 让 Agent 具备语音交互能力:技术突破与应用前景(16/30)
  • element输入框及表单元素自定义前缀
  • 【mybatis-plus问题集锦系列】使用mybatis实现数据的基础增删改查
  • GESP真题 | 2024年12月1级-编程题4《美丽数字》及答案(C++版)
  • 【Ubuntu】不能连上网络
  • 基于Spring Boot微信小程序电影管理系统
  • _使用CLion的Vcpkg安装SDL2,添加至CMakelists时报错,编译报错