首先看 lappend
00128 lappend(List *list, void *datum) 00129 { 00130 Assert(IsPointerList(list)); 00131 00132 if (list == NIL) 00133 list = new_list(T_List); 00134 else 00135 new_tail_cell(list); 00136 00137 lfirst(list->tail) = datum; 00138 check_list_invariants(list); 00139 return list; 00140 }
再看 list 的定义:
typedef struct List { NodeTag type; int length; ListCell *head; ListCell *tail; } List;
和 ListCell 的定义
struct ListCell { union { void *ptr_value; int int_value; Oid oid_value; }data; ListCell *next; }
再看 gram.y 中的 target_list 的定义:
target_list: target_el { $$ = list_make1($1); } | target_list ',' target_el { $$ = lappend($1, $3); } ;
也就是说:target_lsit 中的 lappend 相当于:
$1->tail->data.ptr_value = $3
换句话说,$1 是一个 List, $2 是一个 ListCell。
从最开始 的 target_el 的 listmake1($1) ,可以知道,
刚开始的时候,是List 的 head 指向 ListCell,而ListCell的 ptr_value指针,指向第一个ResTarget。
此ResTarget对应的就是 select id1, id2 中,id1 或 id2 。
然后,如果select 的字段不止一个,就会走到
target_list ',' target_el {$$ = lappend($1, $3); }
也就是说:$1->tail->data.ptr_value = $3, 即 第一个ResTarget 已经关联到第二个 ResTarget。
这种情况具体说来:
00108 new_tail_cell(List *list) 00109 { 00110 ListCell *new_tail; 00111 00112 new_tail = (ListCell *) palloc(sizeof(*new_tail)); 00113 new_tail->next = NULL; 00114 00115 list->tail->next = new_tail; 00116 list->tail = new_tail; 00117 list->length++; 00118 }
如图: