4.ソース読みに慣れよう - PostgreSQL のソースコードを読む

小さな課題を設定し読み進める事で PostgreSQL のソースを読みに慣れよう。昨日設定した課題は「/tcop/postgres.c にある exec_simple_query(const char *query_string) から大まかに処理を追い、結果をまとめる」。

結果は以下の通り。PostgreSQL のソースは比較的読みやすいと聞いていたが確かに読みやすかった。コメントが多いのが良い。

  • pg_parse_query(query_string)
    • SQL の parse
    • 戻り値は parse された Tree Listらしい
  • for-each item in Tree List
    • pg_analyze_and_rewrite
      • analyze は parse された生の item を Query にする
      • rewrite は Query を list の Query にしたり、必要なら Query を Copy (Rewrite
    • pg_plan_queries
      • pg_analyze_and_rewrite の結果を入力として query plan を列挙する
      • いや違う。分解された Query block それぞれに対して Query plan を構築する
      • 内部で planner 関数を読んでいる。optimizer 。
      • planner_hook とかあるよ。
      • 戻り値は PlannedStmt
    • PortalRun : 実行
      • PortalRunSelect
      • ExecutorRun : Query plan を実行する
      • ExecutePlan : 戻り値は TupleTableSlot

- EndCommand


さて次の課題はどうしようかな。tuple が Storage から fetch される部分を読んでみようか。

Query

typedef struct Query
{
NodeTag		type;

CmdType		commandType;	/* select|insert|update|delete|utility */

QuerySource querySource;	/* where did I come from? */

bool		canSetTag;		/* do I set the command result tag? */

Node	   *utilityStmt;	/* non-null if this is DECLARE CURSOR or a
 * non-optimizable statement */

int			resultRelation; /* rtable index of target relation for
 * INSERT/UPDATE/DELETE; 0 for SELECT */

IntoClause *intoClause;		/* target for SELECT INTO / CREATE TABLE AS */

bool		hasAggs;		/* has aggregates in tlist or havingQual */
bool		hasSubLinks;	/* has subquery SubLink */

List	   *rtable;			/* list of range table entries */
FromExpr   *jointree;		/* table join tree (FROM and WHERE clauses) */

List	   *targetList;		/* target list (of TargetEntry) */

List	   *returningList;	/* return-values list (of TargetEntry) */

List	   *groupClause;	/* a list of GroupClause's */

Node	   *havingQual;		/* qualifications applied to groups */

List	   *distinctClause; /* a list of SortClause's */

List	   *sortClause;		/* a list of SortClause's */

Node	   *limitOffset;	/* # of result tuples to skip (int8 expr) */
Node	   *limitCount;		/* # of result tuples to return (int8 expr) */

List	   *rowMarks;		/* a list of RowMarkClause's */

Node	   *setOperations;	/* set-operation tree if this is top level of
 * a UNION/INTERSECT/EXCEPT query */
} Query;

PlannedStmt

typedef struct PlannedStmt
{
NodeTag		type;

CmdType		commandType;	/* select|insert|update|delete */

bool		canSetTag;		/* do I set the command result tag? */

bool		transientPlan;	/* redo plan when TransactionXmin changes? */

struct Plan *planTree;		/* tree of Plan nodes */

List	   *rtable;			/* list of RangeTblEntry nodes */

/* rtable indexes of target relations for INSERT/UPDATE/DELETE */
List	   *resultRelations;	/* integer list of RT indexes, or NIL */

Node	   *utilityStmt;	/* non-null if this is DECLARE CURSOR */

IntoClause *intoClause;		/* target for SELECT INTO / CREATE TABLE AS */

List	   *subplans;		/* Plan trees for SubPlan expressions */

Bitmapset  *rewindPlanIDs;	/* indices of subplans that require REWIND */

/*
 * If the query has a returningList then the planner will store a list of
 * processed targetlists (one per result relation) here.  We must have a
 * separate RETURNING targetlist for each result rel because column
 * numbers may vary within an inheritance tree.  In the targetlists, Vars
 * referencing the result relation will have their original varno and
 * varattno, while Vars referencing other rels will be converted to have
 * varno OUTER and varattno referencing a resjunk entry in the top plan
 * node's targetlist.
 */
List	   *returningLists; /* list of lists of TargetEntry, or NIL */

List	   *rowMarks;		/* a list of RowMarkClause's */

List	   *relationOids;	/* OIDs of relations the plan depends on */

int			nParamExec;		/* number of PARAM_EXEC Params used */
} PlannedStmt;

Plan

typedef struct Plan
{
    NodeTag     type;

    /*
     * estimated execution costs for plan (see costsize.c for more info)
     */
    Cost        startup_cost;   /* cost expended before fetching any tuples */
    Cost        total_cost;     /* total cost (assuming all tuples fetched) */

    /*
     * planner's estimate of result size of this plan step
     */
    double      plan_rows;      /* number of rows plan is expected to emit */
    int         plan_width;     /* average row width in bytes */

    /*
     * Common structural data for all Plan types.
     */
    List       *targetlist;     /* target list to be computed at this node */
    List       *qual;           /* implicitly-ANDed qual conditions */
    struct Plan *lefttree;      /* input plan tree(s) */
    struct Plan *righttree;
    List       *initPlan;       /* Init Plan nodes (un-correlated expr
                                 * subselects) */

    /*
     * Information for management of parameter-change-driven rescanning
     *
     * extParam includes the paramIDs of all external PARAM_EXEC params
     * affecting this plan node or its children.  setParam params from the
     * node's initPlans are not included, but their extParams are.
     *
     * allParam includes all the extParam paramIDs, plus the IDs of local
     * params that affect the node (i.e., the setParams of its initplans).
     * These are _all_ the PARAM_EXEC params that affect this node.
     */
    Bitmapset  *extParam;
    Bitmapset  *allParam;
} Plan;

TupleTableSlot

typedef struct TupleTableSlot
{
NodeTag		type;			/* vestigial ... allows IsA tests */
bool		tts_isempty;	/* true = slot is empty */
bool		tts_shouldFree; /* should pfree tuple? */
bool		tts_slow;		/* saved state for slot_deform_tuple */
HeapTuple	tts_tuple;		/* physical tuple, or NULL if none */
TupleDesc	tts_tupleDescriptor;	/* slot's tuple descriptor */
MemoryContext tts_mcxt;		/* slot itself is in this context */
Buffer		tts_buffer;		/* tuple's buffer, or InvalidBuffer */
int			tts_nvalid;		/* # of valid values in tts_values */
Datum	   *tts_values;		/* current per-attribute values */
bool	   *tts_isnull;		/* current per-attribute isnull flags */
MinimalTuple tts_mintuple;	/* set if it's a minimal tuple, else NULL */
HeapTupleData tts_minhdr;	/* workspace if it's a minimal tuple */
long		tts_off;		/* saved state for slot_deform_tuple */
} TupleTableSlot;