adminpack 提供了大量支持功能,pgAdmin 和其他管理工具可以使用这些功能提供额外功能,例如远程管理服务器日志文件。默认情况下,只有数据库超级用户才能使用所有这些功能,但其他用户也可以使用 GRANT 命令使用这些功能。
我们先来看一下他支持的函数,可以通过 \dx+ adminpack 来进行查看
- function pg_file_rename(text,text) 重命名文件
- function pg_file_rename(text,text,text) 重命名文件,如果新文件存在,将将其命名为第三个参数的名字
- function pg_file_sync(text) 文件刷入磁盘
- function pg_file_unlink(text) 删除文件
- function pg_file_write(text,text,boolean) 写文件
- function pg_logdir_ls() 列出日志目录下的文件
pg_file_rename(text,text)
用于重命名文件,我们看一下 sql 代码
CREATE FUNCTION pg_catalog.pg_file_rename(text, text)
RETURNS bool
AS 'SELECT pg_catalog.pg_file_rename($1, $2, NULL::pg_catalog.text);'
LANGUAGE SQL VOLATILE STRICT;
这里我们看到两个参数版本的 pg_file_rename
直接调用来三参数版本的 pg_file_rename
, 因此我们直接查看三参数版本的 SQL 代码
CREATE OR REPLACE FUNCTION pg_catalog.pg_file_rename(text, text, text)
RETURNS bool
AS 'MODULE_PATHNAME', 'pg_file_rename_v1_1'
LANGUAGE C VOLATILE;
这个 SQL 代码直接调用来 C 函数 pg_file_rename_v1_1
来实现文件重命名。
现在我们来看一下 C 函数 pg_file_rename_v1_1
Datum
pg_file_rename_v1_1(PG_FUNCTION_ARGS)
{
text *file1;
text *file2;
text *file3;
bool result;
if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
PG_RETURN_NULL();
file1 = PG_GETARG_TEXT_PP(0);
file2 = PG_GETARG_TEXT_PP(1);
if (PG_ARGISNULL(2))
file3 = NULL;
else
file3 = PG_GETARG_TEXT_PP(2);
result = pg_file_rename_internal(file1, file2, file3);
PG_RETURN_BOOL(result);
}
这个代码中仅仅是判断参数是否为空,如果不为空,则获取参数,然后调用 pg_file_rename_internal
这个函数
static bool
pg_file_rename_internal(text *file1, text *file2, text *file3)
{
char *fn1,
*fn2,
*fn3;
int rc;
fn1 = convert_and_check_filename(file1);
fn2 = convert_and_check_filename(file2);
if (file3 == NULL)
fn3 = NULL;
else
fn3 = convert_and_check_filename(file3);
if (access(fn1, W_OK) < 0)
{
ereport(WARNING,
(errcode_for_file_access(),
errmsg("file \"%s\" is not accessible: %m", fn1)));
return false;
}
if (fn3 && access(fn2, W_OK) < 0)
{
ereport(WARNING,
(errcode_for_file_access(),
errmsg("file \"%s\" is not accessible: %m", fn2)));
return false;
}
rc = access(fn3 ? fn3 : fn2, W_OK);
if (rc >= 0 || errno != ENOENT)
{
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_FILE),
errmsg("cannot rename to target file \"%s\"",
fn3 ? fn3 : fn2)));
}
if (fn3)
{
if (rename(fn2, fn3) != 0)
{
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not rename \"%s\" to \"%s\": %m",
fn2, fn3)));
}
if (rename(fn1, fn2) != 0)
{
ereport(WARNING,
(errcode_for_file_access(),
errmsg("could not rename \"%s\" to \"%s\": %m",
fn1, fn2)));
if (rename(fn3, fn2) != 0)
{
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not rename \"%s\" back to \"%s\": %m",
fn3, fn2)));
}
else
{
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FILE),
errmsg("renaming \"%s\" to \"%s\" was reverted",
fn2, fn3)));
}
}
}
else if (rename(fn1, fn2) != 0)
{
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not rename \"%s\" to \"%s\": %m", fn1, fn2)));
}
return true;
}
这个函数的整体逻辑为,先将 text* 类型的数据转换为 char* 类型的数据,会在这个转换的过程中处理一些路径相关和权限验证的问题。
然后先判断一下 fn1 是不是存在,如果不存在那肯定是没法重命名的,然后判断一下 fn3 是不是为空,并且 fn2 是不是存在,如果不存在,那么将 fn2 重命名为 fn3 也会失败。
然后判断一下 fn3 是不是存在,如果存在,那么说明文件已经存在,肯定不能重命名,也会报一个 DUPLICATE 的错误。如果 fn3 为空,那么就判断 fn2 文件是不是存在,如果存在那也是不能重命名的。
接下来,我们就可以将 fn2 重命名成 fn3, 然后将 fn1 重命名为 fn2,
如果 fn1 重命名为 fn2 出错,则将 fn3 重名名为 fn2 ,即撤消之前的修改操作。
那如果 fn3 为空,直接将 fn1 重命名为 fn2 就可以了,
标签:rename,插件,fn3,fn2,text,PG14,源码,pg,file From: https://www.cnblogs.com/zardfans/p/18062886