postgresql 为CREATE TYPE记录INPUT函数的Postgres文档似乎不正确

5us2dqdw  于 2022-11-23  发布在  PostgreSQL
关注(0)|答案(1)|浏览(135)

我已经为如下数据类型创建了一个输入函数:

mytimestamp(X)

Postgres文档指出,在这种情况下,当调用输入函数时,类型修饰符将作为第三个参数传递给函数。然而,在我的情况下,类型修饰符总是为-1,这没有意义。下面的命令:

select atttypid,atttypmod 
from pq_attribute 
where attname='mytimestamp';

显示类型已创建,atttypmod值也是我所期望的。然而,input函数仍然显示类型修饰符为-1。我也尝试使用getBaseTypeAndTypmod函数,但它也返回了类型修饰符-1。我完全不知道下一步该怎么做才能解决这个问题。
这和我定义类型的方式有什么关系吗?

create type mytimestamp
( 
   INPUT = mytimestampin, 
   OUTPUT = mytimestampout,
   RECEIVE = mytimestamprecv,
   SEND = mytimestampsend,
   TYPEMOD_IN = mytimestamptypmodin,
--       TYPEMOD_OUT = mytimestamptypmodout,
   STORAGE = extended, 
   CATEGORY = 'd', 
   PREFERRED = true 
);

并且函数被定义为:

CREATE OR REPLACE FUNCTION mytimestampin(cstring, oid, int4) RETURNS mytimestamp
            AS '$libdir/libmy_pgmod', 'mytimestampin'
            LANGUAGE C IMMUTABLE STRICT;
CREATE OR REPLACE FUNCTION mytimestampout(mytimestamp) RETURNS cstring
            AS '$libdir/libmy_pgmod', 'mytimestampout'
            LANGUAGE C IMMUTABLE STRICT;
CREATE OR REPLACE FUNCTION mytimestamprecv(internal, oid, int4) RETURNS mytimestamp
            AS '$libdir/libmy_pgmod', 'mytimestamprecv'
            LANGUAGE C STABLE STRICT;
CREATE OR REPLACE FUNCTION mytimestampsend(mytimestamp) RETURNS bytea
            AS '$libdir/libmy_pgmod', 'mytimestampsend'
            LANGUAGE C STABLE STRICT;
CREATE OR REPLACE FUNCTION mytimestamptypmodin(cstring[]) RETURNS int4
            AS '$libdir/libmy_pgmod', 'mytimestamptypmodin'
            LANGUAGE C IMMUTABLE STRICT;
--CREATE OR REPLACE FUNCTION mytimestamptypmodout(int4) RETURNS cstring
--                AS '$libdir/libmy_pgmod', 'mytimestamptypmodout'
--                LANGUAGE C IMMUTABLE STRICT;

我不能把完整的代码放在这里,但是,这里是开始:

PG_FUNCTION_INFO_V1(mytimestampin);
...
Datum mytimestampin( PG_FUNCTION_ARGS ) {
    const char     *pszTS      = PG_GETARG_CSTRING( 0 );
    uint32_t        atttypmod  = PG_GETARG_INT32( 2 );
    struct varlena *result     = NULL;
    PAPrSqBs_t      pTimestamp = NULL;
    PAPrSqCl_t      pCol       = NULL;
    int64_t         width      = 0;
    int             length     = 0;
    unsigned char  *pOut       = NULL;
    int32_t         precision  = -1;

    PAPrSqRcInit( );

    pTimestamp = PAPrSqBs_new( timestamp );
    pCol       = PAPrSqCl_new( timestamp );

    /**
     * Get the precision.
     */
    if ( (uint32_t)-1 == atttypmod ) {
            precision = PAPrSqCl_getPrecision( pCol, max );
    } else {
            precision = atttypmod;
    }
    ...

    /**
     * Destroy the column and timestamp types.
     */
    PAPrSqCl_delete( pCol );
    PAPrSqBs_delete( pTimestamp );

    PAPrSqRcClean( );

    PG_RETURN_POINTER( result );
}

查询请求的结果如下:

attname |  atttypid   | atttypmod
---------+-------------+-----------
 TS      | mytimestamp |         6
 CHAR10  | mychar      |    656506
 VCHAR20 | myvarchar   |   1311866
 FB31    | integer     |        -1
 FB15    | smallint    |        -1
 DT      | mydate      |        -1
 TM      | mytime      |        -1
(7 rows)
vsmadaxz

vsmadaxz1#

简短回答

您需要:

CREATE CAST(mytimestamp AS mytimestamp) WITH FUNCTION mytimestamp(mytimestamp, integer);
说明

你需要一个从你的类型到...相同类型的强制转换函数,带有一个类型修饰符;如果您希望在初始输入之后的某个时间点应用/强制修改器,这是必要的。
假设SELECT '2016-09-06-15.24.35.123456' ::mytimestamp(8)将:

  • 使用 typemod 8 调用mytimestampin

但您得到是:

  • 使用 typemod -1 调用mytimestampin,后跟
  • 使用 typemod 8 进行自转换。

如果没有提供这样的自投,它将只是耸耸肩。
这实际上并不是一个与类型定义(或mytimestampin)相关的问题,而是一个假设,即您必须至少提供一些类型转换,才能使您的类型像内置函数一样可用。

参考

PostgreSQL Documentation: Reference / SQL Commands / CREATE CAST — define a new cast
通常,转换必须具有不同的源数据类型和目标数据类型。但是,如果转换的转换实现函数具有多个参数,则允许使用相同的源数据类型和目标数据类型声明转换。这用于表示系统目录中特定于类型的长度强制转换函数。命名函数用于将类型的值强制转换为由其第二个参数给定的类型修饰符值。
当转换具有不同的源类型和目标类型以及采用多个参数的函数时,它支持在一个步骤中从一种类型转换为另一种类型并应用长度强制。当没有这样的条目时,对使用类型修饰符的类型的强制涉及两个转换步骤,一个步骤用于在数据类型之间转换,另一个步骤用于应用修饰符。

相关问题