PGresult 结构:
struct pg_result
{
int ntups;
int numAttributes;
PGresAttDesc *attDescs;
PGresAttValue **tuples;
int tupArrSize;
int numParameters;
PGresParamDesc *paramDescs;
ExecStatusType resultStatus;
char cmdStatus[CMDSTATUS_LEN];
PGNoticeHooks noticeHooks;
PGEvent *events;
int nEvents;
int client_encoding; /* encoding id */
char *errMsg; /* error message, or NULL if no error */
PGMessageField *errFields; /* message broken into fields */
char *errQuery; /* text of triggering query, if available */
PGresult_data *curBlock; /* most recently allocated block */
int curOffset; /* start offset of free space in block */
int spaceLeft; /* number of free bytes remaining in block */
};
PGresult.tuples:
返回的 tuple 的实际的值都存放在 tuples 中,tuples 是一个 PGresAttValue * 类型的二位数组,
tuples[row_number][column_number] 就代表返回的表(关系)中第 row_number 行第 column_number 列中数据的值;
PGresult.PGresAttDesc:
该结构是对每一列(属性)的描述,attDescs[column_number] 就是第 column_number 列的描述信息,
typedef struct pgresAttDesc
{
char *name; /* column name */
Oid tableid; /* source table, if known */
int columnid; /* source column, if known */
int format; /* format code for value (text/binary) */
Oid typid; /* type id */
int typlen; /* type size */
int atttypmod; /* type-specific modifier info */
} PGresAttDesc;
name 是列名,typid 是列的类型的oid,format 则是列的格式,0 代表文本格式,1 代表二进制模式;
FDW 下 Postgres 将 PGresult 转化为本地 heaptuple 存储的过程为:
参照 make_tuple_from_result_row() 函数,
从远端取回的 PGresult 一定会对应一个本地已经生成的表,可能是一张基本表或是一张由 join 形成的临时的表,通过下面的语句获取该表的 tupleDesc 元组描述信息:
if (rel)
tupdesc = RelationGetDescr(rel);
else
{
PgFdwScanState *fdw_sstate;
Assert(fsstate);
fdw_sstate = (PgFdwScanState *) fsstate->fdw_state;
tupdesc = fdw_sstate->tupdesc;
}
由于 FDW 会对发到远端执行的语句有筛选,所以函数还传入了一个 retrieved_attrs,retrieved_attrs 是一个 List,每一项表示从远端取回的列(属性)的列 id,从 1 开始计数,
foreach(lc, retrieved_attrs)
{
int i = lfirst_int(lc);
char *valstr;
/* fetch next column's textual value */
if (PQgetisnull(res, row, j))
valstr = NULL;
else
valstr = PQgetvalue(res, row, j);
/* convert value to internal representation */
errpos.cur_attno = i;
if (i > 0)
{
/* ordinary column */
Assert(i <= tupdesc->natts);
nulls[i - 1] = (valstr == NULL);
/* Apply the input function even to nulls, to support domains */
values[i - 1] = InputFunctionCall(&attinmeta->attinfuncs[i - 1],
valstr,
attinmeta->attioparams[i - 1],
attinmeta->atttypmods[i - 1]);
}
对于取回的每一列,如果不为空的话,就将其中的文本值指针保存到 valstr 中( “valstr = PQgetvalue(res, row, j);” ),
在 bool nulls[] 数组中存储每一列中是否为空,值为 true(0) 或 false(1),
在 datum values[] 中则存放由 C 字符串转化为 tuple datum 格式的数据值,转化的方法由 attinmeta 提供。
上述的 tupleDesc, retrieved_attrs 和 attinmeta 若有需要,都是可以通过调用一些函数自己构造的,文末将会提供构造方法。
最后调用 heap_form_tuple(tupdesc, values, nulls) 由 tupdesc,、values[]、nulls[] 构造一个 HeapTuple。