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


    以如下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看到内部表示。

  • 相关阅读:
    java中不常见的keyword:strictfp,transient
    D3DXMatrixMultiply 函数
    expect
    char* 和char[]的差别
    下载安装tomcat6.0
    Eclipse或SVN—怎样在Eclipse中安装SVNclient插件
    sharepoint 訪问缩略图
    斜率优化专题1——bzoj 1597 [Usaco2008 Mar] 土地购买 题解
    phpmywind教程:关于日期函数调用整理
    linux服务之smtp
  • 原文地址:https://www.cnblogs.com/zhjh256/p/15858327.html
Copyright © 2020-2023  润新知