如果您真的愿意调整源代码,您可以在 PostgreSQL 中执行以下操作。
首先,一些注意事项:
- 这样做是一个非常糟糕的主意,它仅用于教育目的。首先,因为它会减慢速度,其次因为它会使您的服务器崩溃(我没有正确测试)
- 我在 PostgreSQL 9.2 中尝试过以下操作,它应该可以与其他版本一起使用,我只是没有尝试过。
现在,想法是,首先,创建一个将元组转储到字符串的函数。为了方便起见,我创建了一个名为src/include/debugtuple.h
(在 pg 源中)的文件,其中包含以下内容:
#ifndef _DEBUGTUPLE_H_
#define _DEBUGTUPLE_H_
#include "postgres.h"
#include "access/relscan.h"
#include "executor/execdebug.h"
#include "utils/rel.h"
static void InitScanRelation(SeqScanState *node, EState *estate);
static TupleTableSlot *SeqNext(SeqScanState *node);
static char *
ExecBuildSlotValueDescription(TupleTableSlot *slot, int maxfieldlen)
{
StringInfoData buf;
TupleDesc tupdesc = slot->tts_tupleDescriptor;
int i;
/* Make sure the tuple is fully deconstructed */
slot_getallattrs(slot);
initStringInfo(&buf);
appendStringInfoChar(&buf, '(');
for (i = 0; i < tupdesc->natts; i++)
{
char *val;
int vallen;
if (slot->tts_isnull[i])
val = "null";
else
{
Oid foutoid;
bool typisvarlena;
getTypeOutputInfo(tupdesc->attrs[i]->atttypid,
&foutoid, &typisvarlena);
val = OidOutputFunctionCall(foutoid, slot->tts_values[i]);
}
if (i > 0)
appendStringInfoString(&buf, ", ");
/* truncate if needed */
vallen = strlen(val);
if (vallen <= maxfieldlen)
appendStringInfoString(&buf, val);
else
{
vallen = pg_mbcliplen(val, vallen, maxfieldlen);
appendBinaryStringInfo(&buf, val, vallen);
appendStringInfoString(&buf, "...");
}
}
appendStringInfoChar(&buf, ')');
return buf.data;
}
#endif
现在,您将必须编辑位于src/backend/executor/
、nodeSeqscan.c
和的两个文件,这两个文件nodeIndexscan.c
都包含上面创建的文件,并带有以下内容(在文件的开头):
#include "debugtuple.h"
在nodeSeqscan.c
处,找到SeqNext
函数并对其进行编辑以匹配以下内容(仅添加这两行):
static TupleTableSlot *
SeqNext(SeqScanState *node)
{
[...]
ExecClearTuple(slot);
/* ADD THE TWO FOLLOWING LINES: */
if (slot && slot->tts_tuple)
elog(NOTICE, "Seq Scan processed: %s", ExecBuildSlotValueDescription(slot, 1000));
return slot;
}
现在,nodeIndexscan.c
对函数执行相同的操作IndexNext
:
static TupleTableSlot *
IndexNext(IndexScanState *node)
{
[...]
while ((tuple = index_getnext(scandesc, direction)) != NULL)
{
[...]
/* ADD THE TWO FOLLOWING LINES: */
if (slot && slot->tts_tuple)
elog(NOTICE, "Index Scan processed: %s", ExecBuildSlotValueDescription(slot, 1000));
return slot;
}
...
return ExecClearTuple(slot);
}
最后,到源码根目录重新编译:
make && make install
现在,这个修改后的版本将在它处理的每个元组上引发一个 NOTICE 消息seqscan
or indexscan
(并且只有那些)。您可以使用函数调用修改该行elog
以执行您想要的任何操作。
玩得开心。