ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

postgresql/lightdb字段typemod属性的内部实现及物理表示pg_attribute.atttypmod

2022-01-31 16:03:15  阅读:227  来源: 互联网

标签:10 typemod postgresql pstate attribute NUMERIC tl Line typmod


以如下DDL为示例
zjh@postgres=# create table test_for_test1(id int primary key,id1 decimal(10,2),t text,t1 varchar(100)); CREATE TABLE zjh@postgres=# select * from pg_class where relname='test_for_test1'; oid | relname | relnamespace | reltype | reloftype | relowner | relam | relfilenode | reltablespace | relpages | reltuples | relallvisible | reltoastrelid | relhasindex | relissha red | relpersistence | relkind | relnatts | relchecks | relhasrules | relhastriggers | relhassubclass | relrowsecurity | relforcerowsecurity | relispopulated | relreplident | relispartition | relrewrite | relfrozenxid | relminmxid | relacl | reloptions | relpartbound -------+----------------+--------------+---------+-----------+----------+-------+-------------+---------------+----------+-----------+---------------+---------------+-------------+--------- ----+----------------+---------+----------+-----------+-------------+----------------+----------------+----------------+---------------------+----------------+--------------+--------------- -+------------+--------------+------------+--------+------------+-------------- 41052 | test_for_test1 | 2200 | 41054 | 0 | 10 | 2 | 41052 | 0 | 0 | 0 | 0 | 41055 | t | f | p | r | 4 | 0 | f | f | f | f | f | t | d | f | 0 | 17074219 | 1 | | | (1 row) zjh@postgres=# select attname,atttypmod from pg_attribute where attrelid = 41052; attname | atttypmod ----------+----------- tableoid | -1 cmax | -1 xmax | -1 cmin | -1 xmin | -1 ctid | -1 id | -1 id1 | 655366 t | -1 t1 | 104 (10 rows)

  先上答案,655366=10 << 16 | 2 + 4,也就是10,2。104 = 100 + 4。

  typemod的计算入口函数为typenameTypeMod,如下:

>	typenameTypeMod(ParseState * pstate=0x2143220, const TypeName * typeName=0x2142cb8, Type typ=0x7fc240f8bc60) Line 407	C
 	LookupTypeNameExtended(ParseState * pstate=0x2143220, const TypeName * typeName=0x2142cb8, int32 * typmod_p=0x0, _Bool temp_ok=true, _Bool missing_ok=false) Line 211	C
 	LookupTypeName(ParseState * pstate=0x2143220, const TypeName * typeName=0x2142cb8, int32 * typmod_p=0x0, _Bool missing_ok=false) Line 41	C
 	typenameType(ParseState * pstate=0x2143220, const TypeName * typeName=0x2142cb8, int32 * typmod_p=0x0) Line 268	C
 	transformColumnType(CreateStmtContext * cxt=0x7ffd456eff70, ColumnDef * column=0x2142bb0) Line 3705	C
 	transformColumnDefinition(CreateStmtContext * cxt=0x7ffd456eff70, ColumnDef * column=0x2142bb0) Line 592	C
 	transformCreateStmt(CreateStmt * stmt=0x2155a68, const char * queryString=0x205f2f8 "create table test_for_test1(id int primary key,id1 decimal(10,2),t text,t1 varchar(100));") Line 284	C
 	ProcessUtilitySlow(ParseState * pstate=0x2155958, PlannedStmt * pstmt=0x2175d98, const char * queryString=0x205f2f8 "create table test_for_test1(id int primary key,id1 decimal(10,2),t text,t1 varchar(100));", ProcessUtilityContext context=PROCESS_UTILITY_TOPLEVEL, ParamListInfo params=0x0, QueryEnvironment * queryEnv=0x0, DestReceiver * dest=0x21c7cb8, QueryCompletion * qc=0x7ffd456f0a10) Line 1147	C

  调用pg_proc中为每种数据类型定义的typmodin函数执行计算,如下:

foreach(l, typeName->typmods)
	{
		Node	   *tm = (Node *) lfirst(l);
		char	   *cstr = NULL;

		if (IsA(tm, A_Const))
		{
			A_Const    *ac = (A_Const *) tm;

			if (IsA(&ac->val, Integer))
			{
				cstr = psprintf("%ld", (long) ac->val.val.ival);
			}
			else if (IsA(&ac->val, Float) ||
					 IsA(&ac->val, String))
			{
				/* we can just use the str field directly. */
				cstr = ac->val.val.str;
			}
		}
		else if (IsA(tm, ColumnRef))
		{
			ColumnRef  *cr = (ColumnRef *) tm;

			if (list_length(cr->fields) == 1 &&
				IsA(linitial(cr->fields), String))
				cstr = strVal(linitial(cr->fields));
		}
		if (!cstr)
			ereport(ERROR,
					(errcode(ERRCODE_SYNTAX_ERROR),
					 errmsg("type modifiers must be simple constants or identifiers"),
					 parser_errposition(pstate, typeName->location)));
		datums[n++] = CStringGetDatum(cstr);
	}

	/* hardwired knowledge about cstring's representation details here */
	arrtypmod = construct_array(datums, n, CSTRINGOID,
								-2, false, TYPALIGN_CHAR);

	/* arrange to report location if type's typmodin function fails */
	setup_parser_errposition_callback(&pcbstate, pstate, typeName->location);

	result = DatumGetInt32(OidFunctionCall1(typmodin,
											PointerGetDatum(arrtypmod))); -- 通过动态函数调用实现

  其中varchar和numeric的typmodin函数分别如下:

zjh@postgres=# select * from pg_proc where oid=2915 or oid = 2917;
 oid  |     proname     | pronamespace | proowner | prolang | procost | prorows | provariadic | prosupport | prokind | prosecdef | proleakproof | proisstrict | proretset | provolatile | pro
parallel | pronargs | pronargdefaults | prorettype | proargtypes | proallargtypes | proargmodes | proargnames | proargdefaults | protrftypes |     prosrc      | probin | proconfig | proacl 
------+-----------------+--------------+----------+---------+---------+---------+-------------+------------+---------+-----------+--------------+-------------+-----------+-------------+----
---------+----------+-----------------+------------+-------------+----------------+-------------+-------------+----------------+-------------+-----------------+--------+-----------+--------
 2915 | varchartypmodin |           11 |       10 |      12 |       1 |       0 |           0 | -          | f       | f         | f            | t           | f         | i           | s  
         |        1 |               0 |         23 | 1263        |                |             |             |                |             | varchartypmodin |        |           | 
 2917 | numerictypmodin |           11 |       10 |      12 |       1 |       0 |           0 | -          | f       | f         | f            | t           | f         | i           | s  
         |        1 |               0 |         23 | 1263        |                |             |             |                |             | numerictypmodin |        |           | 
(2 rows)

  numerictypmodin和varcahrtypmodin的实现如下:

Datum
numerictypmodin(PG_FUNCTION_ARGS)
{
    ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);
    int32       *tl;
    int            n;
    int32        typmod;

    tl = ArrayGetIntegerTypmods(ta, &n);

    if (n == 2)
    {
        if (tl[0] < 1 || tl[0] > NUMERIC_MAX_PRECISION)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                     errmsg("NUMERIC precision %d must be between 1 and %d",
                            tl[0], NUMERIC_MAX_PRECISION)));
        if (tl[1] < 0 || tl[1] > tl[0])
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                     errmsg("NUMERIC scale %d must be between 0 and precision %d",
                            tl[1], tl[0])));
        typmod = ((tl[0] << 16) | tl[1]) + VARHDRSZ;
    }
    else if (n == 1)
    {
        if (tl[0] < 1 || tl[0] > NUMERIC_MAX_PRECISION)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                     errmsg("NUMERIC precision %d must be between 1 and %d",
                            tl[0], NUMERIC_MAX_PRECISION)));
        /* scale defaults to zero */
        typmod = (tl[0] << 16) + VARHDRSZ;
    }
    else
    {
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("invalid NUMERIC type modifier")));
        typmod = 0;                /* keep compiler quiet */
    }

    PG_RETURN_INT32(typmod);
}


Datum
varchartypmodin(PG_FUNCTION_ARGS)
{
    ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);

    PG_RETURN_INT32(anychar_typmodin(ta, "varchar"));
}

/* common code for bpchartypmodin and varchartypmodin */
static int32
anychar_typmodin(ArrayType *ta, const char *typename)
{
    int32        typmod;
    int32       *tl;
    int            n;

    tl = ArrayGetIntegerTypmods(ta, &n);

    /*
     * we're not too tense about good error message here because grammar
     * shouldn't allow wrong number of modifiers for CHAR
     */
    if (n != 1)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("invalid type modifier")));

    if (*tl < 1)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("length for type %s must be at least 1", typename)));
    if (*tl > MaxAttrSize)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("length for type %s cannot exceed %d",
                        typename, MaxAttrSize)));

    /*
     * For largely historical reasons, the typmod is VARHDRSZ plus the number
     * of characters; there is enough client-side code that knows about that
     * that we'd better not change it.
     */
    typmod = VARHDRSZ + *tl;

    return typmod;
}

  回到开始,655366=10 << 16 | 2 + 4,也就是10,2。104 = 100 + 4,其中的4是VARHDRSZ,可变数据类型头部长度。所以每种类型都可以通过xxxtypmodin和xxxtypmodout看到内部表示。

标签:10,typemod,postgresql,pstate,attribute,NUMERIC,tl,Line,typmod
来源: https://www.cnblogs.com/zhjh256/p/15858327.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有