本节简单介绍了PostgreSQL创建函数的过程,其实现函数是CreateFunction。这里介绍了CreateFunction中的通用函数construct_array。
一、数据结构
Form_pg_language
plpgsql语言定义结构体
/* ----------------
* pg_language definition. cpp turns this into
* typedef struct FormData_pg_language
* ----------------
*/
CATALOG(pg_language,2612,LanguageRelationId)
{
Oid oid; /* oid */
/* Language name */
NameData lanname;
/* Language's owner */
Oid lanowner BKI_DEFAULT(PGUID);
/* Is a procedural language */
bool lanispl BKI_DEFAULT(f);
/* PL is trusted */
bool lanpltrusted BKI_DEFAULT(f);
/* Call handler, if it's a PL */
Oid lanplcallfoid BKI_DEFAULT(0) BKI_LOOKUP(pg_proc);
/* Optional anonymous-block handler function */
Oid laninline BKI_DEFAULT(0) BKI_LOOKUP(pg_proc);
/* Optional validation function */
Oid lanvalidator BKI_DEFAULT(0) BKI_LOOKUP(pg_proc);
#ifdef CATALOG_VARLEN /* variable-length fields start here */
/* Access privileges */
aclitem lanacl[1] BKI_DEFAULT(_null_);
#endif
} FormData_pg_language;
/* ----------------
* Form_pg_language corresponds to a pointer to a tuple with
* the format of pg_language relation.
* ----------------
*/
typedef FormData_pg_language *Form_pg_language;
ArrayType
/*
* Arrays are varlena objects, so must meet the varlena convention that
* the first int32 of the object contains the total object size in bytes.
* Be sure to use VARSIZE() and SET_VARSIZE() to access it, though!
* Arrays是可变对象集,必须符合varlena约定,即对象的第一个int32包含对象的总大小(以字节为单位)。
* 但是,一定要确保使用VARSIZE和SET_VARSIZE函数范围该结构体
*
* CAUTION: if you change the header for ordinary arrays you will also
* need to change the headers for oidvector and int2vector!
*/
typedef struct
{
//可变的header
int32 vl_len_; /* varlena header (do not touch directly!) */
//维度
int ndim; /* # of dimensions */
//指向数据的偏移量,如为0则表示没有位图
int32 dataoffset; /* offset to data, or 0 if no bitmap */
//元素类型的OID
Oid elemtype; /* element type OID */
} ArrayType;
DefElem
typedef struct DefElem
{
NodeTag type;
char *defnamespace; /* NULL if unqualified name */
char *defname;
Node *arg; /* a (Value *) or a (TypeName *) */
DefElemAction defaction; /* unspecified action, or SET/ADD/DROP */
int location; /* token location, or -1 if unknown */
} DefElem;
FunctionParameter
typedef enum FunctionParameterMode
{
/* the assigned enum values appear in pg_proc, don't change 'em! */
FUNC_PARAM_IN = 'i', /* input only */
FUNC_PARAM_OUT = 'o', /* output only */
FUNC_PARAM_INOUT = 'b', /* both */
FUNC_PARAM_VARIADIC = 'v', /* variadic (always input) */
FUNC_PARAM_TABLE = 't' /* table function output column */
} FunctionParameterMode;
typedef struct FunctionParameter
{
NodeTag type;
char *name; /* parameter name, or NULL if not given */
TypeName *argType; /* TypeName for parameter type */
FunctionParameterMode mode; /* IN/OUT/etc */
Node *defexpr; /* raw default expr, or NULL if not given */
} FunctionParameter;
二、源码解读
/*
*allParameterTypes = construct_array(allTypes, parameterCount, OIDOID,sizeof(Oid), true, 'i');
*parameterModes = construct_array(paramModes, parameterCount, CHAROID,1, true, 'c');
*/
/*
* construct_array --- simple method for constructing an array object
* 构建数组对象的简单方法
*
* elems: array of Datum items to become the array contents
* (NULL element values are not supported).
* nelems: number of items
* elmtype, elmlen, elmbyval, elmalign: info for the datatype of the items
*
* elems: 数组中的元素
* nelems:元素数量
* elmtype,elmlen,elmbyval,elmalign:元素的数据类型信息
*
* A palloc'd 1-D array object is constructed and returned. Note that
* elem values will be copied into the object even if pass-by-ref type.
* Also note the result will be 0-D not 1-D if nelems = 0.
* 构建一维数组对象并返回.
* 注意元素值即使引用传递类型也会拷贝到对象中.
* 同时要注意如元素个数为0,结果是0-D数组而不是一维数组.
*
* NOTE: it would be cleaner to look up the elmlen/elmbval/elmalign info
* from the system catalogs, given the elmtype. However, the caller is
* in a better position to cache this info across multiple uses, or even
* to hard-wire values if the element type is hard-wired.
* 给定elmtype的情况下,从系统目录中获取元素elmlen/elmbval/elmalign应更加清晰.
* 但是,调用者便于跨用户缓存这些信息.
*/
ArrayType *
construct_array(Datum *elems, int nelems,
Oid elmtype,
int elmlen, bool elmbyval, char elmalign)
{
int dims[1];
int lbs[1];
dims[0] = nelems;//数组元素个数
lbs[0] = 1;
return construct_md_array(elems, NULL, 1, dims, lbs,
elmtype, elmlen, elmbyval, elmalign);
}
/*
* construct_md_array --- simple method for constructing an array object
* with arbitrary dimensions and possible NULLs
* construct_md_array:构建任意维度和可能存在NULLs的数据对象
*
* elems: array of Datum items to become the array contents
* nulls: array of is-null flags (can be NULL if no nulls)
* ndims: number of dimensions
* dims: integer array with size of each dimension
* lbs: integer array with lower bound of each dimension
* elmtype, elmlen, elmbyval, elmalign: info for the datatype of the items
* elems:同construct_array
* nulls:is-null标记数组
* ndims:维度数
* dims:每个维度大小的整型数组
* lbs:每个维度的下界整型数组
* elmtype, elmlen, elmbyval, elmalign: 元素的数据类型信息
*
* A palloc'd ndims-D array object is constructed and returned. Note that
* elem values will be copied into the object even if pass-by-ref type.
* Also note the result will be 0-D not ndims-D if any dims[i] = 0.
* 构建ndims维数组并返回.
*
* NOTE: it would be cleaner to look up the elmlen/elmbval/elmalign info
* from the system catalogs, given the elmtype. However, the caller is
* in a better position to cache this info across multiple uses, or even
* to hard-wire values if the element type is hard-wired.
*/
ArrayType *
construct_md_array(Datum *elems,//元素内容
bool *nulls,//nulls标记数组(每个元素占用一个位置)
int ndims,//维度数
int *dims,//每个维度的元素大小
int *lbs,//每个维度的下界数组(low bound)
Oid elmtype, int elmlen, bool elmbyval, char elmalign)
{
ArrayType *result;//结果
bool hasnulls;//是否存在null值
int32 nbytes;//以字节为单位的大小
int32 dataoffset;//数据偏移
int i;//临时变量
int nelems;//元素数目
//校验维数
if (ndims < 0) /* we do allow zero-dimension arrays */
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid number of dimensions: %d", ndims)));
if (ndims > MAXDIM)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
ndims, MAXDIM)));
//元素数目:每个维数的大小相乘
nelems = ArrayGetNItems(ndims, dims);
/* if ndims <= 0 or any dims[i] == 0, return empty array */
//维数≤0或者任意一维的个数等于0,返回空数组
if (nelems <= 0)
return construct_empty_array(elmtype);
/* compute required space */
//计算需要的空间大小
nbytes = 0;
hasnulls = false;
for (i = 0; i < nelems; i++)
{
if (nulls && nulls[i])
{
//存在null值
hasnulls = true;
continue;
}
/* make sure data is not toasted */
//确保数据没有toasted
if (elmlen == -1)
elems[i] = PointerGetDatum(PG_DETOAST_DATUM(elems[i]));
//以字节为单位的大小
nbytes = att_addlength_datum(nbytes, elmlen, elems[i]);
//#define att_align_nominal(cur_offset,attalign) ( ((attalign) == 'i') ? INTALIGN(cur_offset) : (((attalign) == 'c') ? (uintptr_t) (cur_offset) : (((attalign) == 'd') ? DOUBLEALIGN(cur_offset) : ( AssertMacro((attalign) == 's'), SHORTALIGN(cur_offset) ))) )
//( ((elmalign) == 'i') ? (((uintptr_t) ((nbytes)) + ((ALIGNOF_INT) - 1)) & ~((uintptr_t) ((ALIGNOF_INT) - 1))) : (((elmalign) == 'c') ? (uintptr_t) (nbytes) : (((elmalign) == 'd') ? (((uintptr_t) ((nbytes)) + ((ALIGNOF_DOUBLE) - 1)) & ~((uintptr_t) ((ALIGNOF_DOUBLE) - 1))) : ( ((void)((bool) 1)), (((uintptr_t) ((nbytes)) + ((ALIGNOF_SHORT) - 1)) & ~((uintptr_t) ((ALIGNOF_SHORT) - 1))) ))) )
nbytes = att_align_nominal(nbytes, elmalign);
/* check for overflow of total request */
//检查是否溢出
//#define AllocSizeIsValid(size) ((Size) (size) <= MaxAllocSize)
//((Size) (nbytes) <= ((Size) 0x3fffffff))(2的30次方)
if (!AllocSizeIsValid(nbytes))
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("array size exceeds the maximum allowed (%d)",
(int) MaxAllocSize)));
}
/* Allocate and initialize result array */
//分配和初始化结果数组
if (hasnulls)
{
//分配null bitmap空间
dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nelems);
nbytes += dataoffset;
}
else
{
//无null bitmap
dataoffset = 0; /* marker for no null bitmap */
//#define ARR_OVERHEAD_WITHNULLS(ndims,nitems) MAXALIGN(sizeof(ArrayType) + 2 * sizeof(int) * (ndims) + ((nitems) + 7) / 8)
//(((uintptr_t) ((sizeof(ArrayType) + 2 * sizeof(int) * (ndims))) + ((MAXIMUM_ALIGNOF) - 1)) & ~((uintptr_t) ((MAXIMUM_ALIGNOF) - 1)))
//#define ARR_OVERHEAD_NONULLS(ndims) MAXALIGN(sizeof(ArrayType) + 2 * sizeof(int) * (ndims))
//(((uintptr_t) ((sizeof(ArrayType) + 2 * sizeof(int) * (ndims))) + ((MAXIMUM_ALIGNOF) - 1)) & ~((uintptr_t) ((MAXIMUM_ALIGNOF) - 1)))
nbytes += ARR_OVERHEAD_NONULLS(ndims);
}
//分配空间
result = (ArrayType *) palloc0(nbytes);
//设置大小
//SET_VARSIZE -->
//#define SET_VARSIZE(PTR,len) SET_VARSIZE_4B(PTR, len)
//(((varattrib_4b *) (result))->va_4byte.va_header = (((uint32) (nbytes)) << 2))
//nbytes * 4
SET_VARSIZE(result, nbytes);
//维数
result->ndim = ndims;
//数据偏移(前面是null bitmap)
result->dataoffset = dataoffset;
//元素类型
result->elemtype = elmtype;
//ARR_DIMS --> 元素个数
//#define ARR_DIMS(a) ((int *) (((char *) (a)) + sizeof(ArrayType)))
//((int *) (((char *) (result)) + sizeof(ArrayType))) --> ((int *) (((char *) (result)) + 16))
memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));
//ARR_LBOUND --> 下限边界
//#define ARR_LBOUND(a) ((int *) (((char *) (a)) + sizeof(ArrayType) + sizeof(int) * ARR_NDIM(a)))
//((int *) (((char *) (result)) + sizeof(ArrayType) + sizeof(int) * ((result)->ndim)))
memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));
//拷贝数组元素
CopyArrayEls(result,
elems, nulls, nelems,
elmlen, elmbyval, elmalign,
false);
return result;
}
/*
* Convert array dimensions into number of elements
* 转换数组的维数为元素个数
*
* This must do overflow checking, since it is used to validate that a user
* dimensionality request doesn't overflow what we can handle.
* 必须执行溢出检查.
*
* We limit array sizes to at most about a quarter billion elements,
* so that it's not necessary to check for overflow in quite so many
* places --- for instance when palloc'ing Datum arrays.
* 数组的大小限制在大概100w/4.
*
* The multiplication overflow check only works on machines that have int64
* arithmetic, but that is nearly all platforms these days, and doing check
* divides for those that don't seems way too expensive.
*/
int
ArrayGetNItems(int ndim, const int *dims)
{
int32 ret;
int i;
#define MaxArraySize ((Size) (MaxAllocSize / sizeof(Datum)))
if (ndim <= 0)
return 0;
ret = 1;
for (i = 0; i < ndim; i++)
{
int64 prod;
/* A negative dimension implies that UB-LB overflowed ... */
if (dims[i] < 0)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("array size exceeds the maximum allowed (%d)",
(int) MaxArraySize)));
prod = (int64) ret * (int64) dims[i];
ret = (int32) prod;
if ((int64) ret != prod)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("array size exceeds the maximum allowed (%d)",
(int) MaxArraySize)));
}
Assert(ret >= 0);
if ((Size) ret > MaxArraySize)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("array size exceeds the maximum allowed (%d)",
(int) MaxArraySize)));
return (int) ret;
}
/*
* Copy data into an array object from a temporary array of Datums.
* 从Datums临时数组中拷贝数据到数组对象中.
*
* array: array object (with header fields already filled in)
* values: array of Datums to be copied
* nulls: array of is-null flags (can be NULL if no nulls)
* nitems: number of Datums to be copied
* typbyval, typlen, typalign: info about element datatype
* freedata: if true and element type is pass-by-ref, pfree data values
* referenced by Datums after copying them.
*
* array:数组对象(头部已填充)
* values:将要拷贝的Datums数组
* nulls:is-null标记数组
* nitems:元素数目
* typbyval,typlen, typalign:元素数据类型信息
* freedata:如为T并且元素类型是引用传递,则拷贝后释放空间
*
* If the input data is of varlena type, the caller must have ensured that
* the values are not toasted. (Doing it here doesn't work since the
* caller has already allocated space for the array...)
* 如果输入数据是varlena类型,调用者必须确保值没有toasted.
*/
void
CopyArrayEls(ArrayType *array,
Datum *values,
bool *nulls,
int nitems,
int typlen,
bool typbyval,
char typalign,
bool freedata)
{
//#define ARR_DATA_PTR(a) (((char *) (a)) + ARR_DATA_OFFSET(a))
//(((char *) (array)) + (((array)->dataoffset != 0) ? (array)->dataoffset : (((uintptr_t) ((sizeof(ArrayType) + 2 * sizeof(int) * (((array)->ndim)))) + ((MAXIMUM_ALIGNOF) - 1)) & ~((uintptr_t) ((MAXIMUM_ALIGNOF) - 1)))))
char *p = ARR_DATA_PTR(array);
//#define ARR_NULLBITMAP(a) (ARR_HASNULL(a) ? (bits8 *) (((char *) (a)) + sizeof(ArrayType) + 2 * sizeof(int) * ARR_NDIM(a)) : (bits8 *) NULL)
//(((array)->dataoffset != 0) ? (bits8 *) (((char *) (array)) + sizeof(ArrayType) + 2 * sizeof(int) * ((array)->ndim)) : (bits8 *) NULL)
bits8 *bitmap = ARR_NULLBITMAP(array);
int bitval = 0;
int bitmask = 1;
int i;
if (typbyval)//传值
freedata = false;
for (i = 0; i < nitems; i++)//遍历元素
{
if (nulls && nulls[i])
{
//如为null,则bitmap不能为空指针
if (!bitmap) /* shouldn't happen */
elog(ERROR, "null array element where not supported");
/* bitmap bit stays 0 */
}
else
{
//
bitval |= bitmask;
p += ArrayCastAndSet(values[i], typlen, typbyval, typalign, p);
if (freedata)
pfree(DatumGetPointer(values[i]));
}
if (bitmap)
{
bitmask <<= 1;
if (bitmask == 0x100)
{
*bitmap++ = bitval;
bitval = 0;
bitmask = 1;
}
}
}
if (bitmap && bitmask != 1)
*bitmap = bitval;
}
/*
* Copy datum to *dest and return total space used (including align padding)
*
* Caller must have handled case of NULL element
*/
static int
ArrayCastAndSet(Datum src,
int typlen,
bool typbyval,
char typalign,
char *dest)
{
int inc;
if (typlen > 0)
{
if (typbyval)
store_att_byval(dest, src, typlen);
else
memmove(dest, DatumGetPointer(src), typlen);
inc = att_align_nominal(typlen, typalign);
}
else
{
Assert(!typbyval);
inc = att_addlength_datum(0, typlen, src);
memmove(dest, DatumGetPointer(src), inc);
inc = att_align_nominal(inc, typalign);
}
return inc;
}
三、跟踪分析
测试脚本
create or replace function func_test(pi_v1 in int,pi_v2 varchar,pio_v3 inout varchar,po_v4 out int,po_v5 out varchar)
returns record
as
$$
declare
begin
raise notice 'pi_v1 := %,pi_v2 := %,pi_v3 := %',pi_v1,pi_v2,pio_v3;
pio_v3 := 'pio_v3 i/o';
po_v4 := 100;
po_v5 := 'po_v5 out';
end;
$$ LANGUAGE plpgsql;
启动GDB跟踪
(gdb) b construct_array
Breakpoint 1 at 0x91eaeb: file arrayfuncs.c, line 3298.
(gdb) c
Continuing.
Breakpoint 1, construct_array (elems=0x22d9da0, nelems=5, elmtype=26, elmlen=4, elmbyval=true, elmalign=105 'i') at arrayfuncs.c:3298
3298 dims[0] = nelems;
(gdb) bt
#0 construct_array (elems=0x22d9da0, nelems=5, elmtype=26, elmlen=4, elmbyval=true, elmalign=105 'i') at arrayfuncs.c:3298
#1 0x000000000066fa48 in interpret_function_parameter_list (pstate=0x22d9c88, parameters=0x22b3d30, languageOid=13581, objtype=OBJECT_FUNCTION, parameterTypes=0x7fff6bde92b8,
allParameterTypes=0x7fff6bde92b0, parameterModes=0x7fff6bde92a8, parameterNames=0x7fff6bde92a0, parameterDefaults=0x7fff6bde9298, variadicArgType=0x7fff6bde9294,
requiredResultType=0x7fff6bde9290) at functioncmds.c:434
#2 0x000000000067100f in CreateFunction (pstate=0x22d9c88, stmt=0x22b48c8) at functioncmds.c:1053
#3 0x00000000008f61a6 in ProcessUtilitySlow (pstate=0x22d9c88, pstmt=0x22b4c48,
queryString=0x22b2ed8 "create or replace function func_test(pi_v1 in int,pi_v2 varchar,pio_v3 inout varchar,po_v4 out int,po_v5 out varchar)\nreturns record \nas\n$$\ndeclare\nbegin\n raise notice 'pi_v1 := %,pi_v2 := %,pi_v3 :="..., context=PROCESS_UTILITY_TOPLEVEL, params=0x0, queryEnv=0x0, dest=0x22b4d40, completionTag=0x7fff6bde9a60 "") at utility.c:1478
#4 0x00000000008f5069 in standard_ProcessUtility (pstmt=0x22b4c48,
queryString=0x22b2ed8 "create or replace function func_test(pi_v1 in int,pi_v2 varchar,pio_v3 inout varchar,po_v4 out int,po_v5 out varchar)\nreturns record \nas\n$$\ndeclare\nbegin\n raise notice 'pi_v1 := %,pi_v2 := %,pi_v3 :="..., context=PROCESS_UTILITY_TOPLEVEL, params=0x0, queryEnv=0x0, dest=0x22b4d40, completionTag=0x7fff6bde9a60 "") at utility.c:927
#5 0x00000000008f418f in ProcessUtility (pstmt=0x22b4c48,
queryString=0x22b2ed8 "create or replace function func_test(pi_v1 in int,pi_v2 varchar,pio_v3 inout varchar,po_v4 out int,po_v5 out varchar)\nreturns record \nas\n$$\ndeclare\nbegin\n raise notice 'pi_v1 := %,pi_v2 := %,pi_v3 :="..., context=PROCESS_UTILITY_TOPLEVEL, params=0x0, queryEnv=0x0, dest=0x22b4d40, completionTag=0x7fff6bde9a60 "") at utility.c:360
#6 0x00000000008f3188 in PortalRunUtility (portal=0x231a248, pstmt=0x22b4c48, isTopLevel=true, setHoldSnapshot=false, dest=0x22b4d40, completionTag=0x7fff6bde9a60 "") at pquery.c:1175
#7 0x00000000008f339e in PortalRunMulti (portal=0x231a248, isTopLevel=true, setHoldSnapshot=false, dest=0x22b4d40, altdest=0x22b4d40, completionTag=0x7fff6bde9a60 "") at pquery.c:1321
#8 0x00000000008f28d3 in PortalRun (portal=0x231a248, count=9223372036854775807, isTopLevel=true, run_once=true, dest=0x22b4d40, altdest=0x22b4d40, completionTag=0x7fff6bde9a60 "")
at pquery.c:796
#9 0x00000000008ec882 in exec_simple_query (
query_string=0x22b2ed8 "create or replace function func_test(pi_v1 in int,pi_v2 varchar,pio_v3 inout varchar,po_v4 out int,po_v5 out varchar)\nreturns record \nas\n$$\ndeclare\nbegin\n ---Type to continue, or q to quit---^CQuit
(gdb)
输入参数:
5个参数的OID,分别是23/1043/1043/23/1043;有5个元素;类型为26-OID;元素长度为4(int32);以传值方式传递;对其方式为i-INT
(gdb) p elems[0]
$73 = 23
(gdb) p elems[1]
$74 = 1043
(gdb) p elems[2]
$75 = 1043
(gdb) p elems[3]
$76 = 23
(gdb) p elems[4]
$77 = 1043
(gdb)
进入construct_md_array,输入参数维数-1,5个元素,数组下界为1
(gdb) n
3299 lbs[0] = 1;
(gdb)
3301 return construct_md_array(elems, NULL, 1, dims, lbs,
(gdb) step
construct_md_array (elems=0x22d9dd8, nulls=0x0, ndims=1, dims=0x7fff6bde9070, lbs=0x7fff6bde9060, elmtype=26, elmlen=4, elmbyval=true, elmalign=105 'i') at arrayfuncs.c:3340
3340 if (ndims < 0) /* we do allow zero-dimension arrays */
(gdb)
执行相关校验(最大维数为6),获取元素个数(5)
(gdb) n
3344 if (ndims > MAXDIM)
(gdb) p MAXDIM
$78 = 6
(gdb) n
3350 nelems = ArrayGetNItems(ndims, dims);
(gdb)
3353 if (nelems <= 0)
(gdb) p nelems
$79 = 5
(gdb)
计算需占用的空间
(gdb) n
3357 nbytes = 0;
(gdb)
3358 hasnulls = false;
(gdb)
3359 for (i = 0; i < nelems; i++)
(gdb)
3361 if (nulls && nulls[i])
(gdb)
3367 if (elmlen == -1)
(gdb)
3369 nbytes = att_addlength_datum(nbytes, elmlen, elems[i]);
(gdb)
3370 nbytes = att_align_nominal(nbytes, elmalign);
(gdb)
3372 if (!AllocSizeIsValid(nbytes))
(gdb)
3359 for (i = 0; i < nelems; i++)
(gdb)
3361 if (nulls && nulls[i])
(gdb)
3367 if (elmlen == -1)
(gdb)
3369 nbytes = att_addlength_datum(nbytes, elmlen, elems[i]);
(gdb)
3370 nbytes = att_align_nominal(nbytes, elmalign);
(gdb)
3372 if (!AllocSizeIsValid(nbytes))
(gdb)
3359 for (i = 0; i < nelems; i++)
(gdb)
3361 if (nulls && nulls[i])
(gdb)
3367 if (elmlen == -1)
(gdb)
3369 nbytes = att_addlength_datum(nbytes, elmlen, elems[i]);
(gdb)
3370 nbytes = att_align_nominal(nbytes, elmalign);
(gdb)
3372 if (!AllocSizeIsValid(nbytes))
(gdb)
3359 for (i = 0; i < nelems; i++)
(gdb)
3361 if (nulls && nulls[i])
(gdb)
3367 if (elmlen == -1)
(gdb)
3369 nbytes = att_addlength_datum(nbytes, elmlen, elems[i]);
(gdb)
3370 nbytes = att_align_nominal(nbytes, elmalign);
(gdb)
3372 if (!AllocSizeIsValid(nbytes))
(gdb)
3359 for (i = 0; i < nelems; i++)
(gdb)
3361 if (nulls && nulls[i])
(gdb)
3367 if (elmlen == -1)
(gdb)
3369 nbytes = att_addlength_datum(nbytes, elmlen, elems[i]);
(gdb)
3370 nbytes = att_align_nominal(nbytes, elmalign);
(gdb)
3372 if (!AllocSizeIsValid(nbytes))
(gdb)
3359 for (i = 0; i < nelems; i++)
(gdb)
3380 if (hasnulls)
(gdb)
5个OID,需占用20个bytes
(gdb) p nbytes
$80 = 20
(gdb)
没有null bitmap,偏移为0;添加头部空间(ArrayType的大小16+2*4*维数,这里是24)
(gdb) n
3387 dataoffset = 0; /* marker for no null bitmap */
(gdb)
3388 nbytes += ARR_OVERHEAD_NONULLS(ndims);
(gdb)
3390 result = (ArrayType *) palloc0(nbytes);
(gdb) p nbyes
$81 = 44
(gdb)
分配空间,赋值结构体
(gdb) n
3391 SET_VARSIZE(result, nbytes);
(gdb) n
3392 result->ndim = ndims;
(gdb) p nbytes
$82 = 44
(gdb) p *result
$83 = {vl_len_ = 176, ndim = 0, dataoffset = 0, elemtype = 0}
(gdb) n
3393 result->dataoffset = dataoffset;
(gdb)
3394 result->elemtype = elmtype;
(gdb)
3395 memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));-->元素个数
(gdb)
3396 memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));-->第一个维度的下界
(gdb) p *result
$84 = {vl_len_ = 176, ndim = 1, dataoffset = 0, elemtype = 26}
(gdb) p *(int *)((char *)result+16)
$85 = 5
(gdb) p *(int *)((char *)result+20)
$86 = 0
(gdb) p *(int *)((char *)result+24)
$87 = 0
(gdb) p *(int *)((char *)result+28)
$88 = 0
(gdb) n
3398 CopyArrayEls(result,
(gdb) p *(int *)((char *)result+20)
$89 = 1
(gdb)
拷贝OID到数组中,从24开始,每个值占用4个byte,共5个值
(gdb) n
3403 return result;
(gdb) p *(int *)((char *)result+24)
$90 = 23
(gdb) p *(int *)((char *)result+28)
$91 = 1043
(gdb) p *(int *)((char *)result+32)
$92 = 1043
(gdb) p *(int *)((char *)result+36)
$93 = 23
(gdb) p *(int *)((char *)result+40)
$94 = 1043
(gdb)
完成函数调用
(gdb) n
3404 }
(gdb)
construct_array (elems=0x22d9dd8, nelems=5, elmtype=26, elmlen=4, elmbyval=true, elmalign=105 'i') at arrayfuncs.c:3303
3303 }
(gdb)
DONE!
四、参考资料
N/A