PostgreSQL内核开发过程介绍(三)-用户自定义基本类型

类型系统

基础类型

基础类型是那些被实现在SQL语言层面之下的类型(通常用一种底层语言,如 C),例如integer。它们通常对应于常说的抽象数据类型

容器类型

有三种“容器”类型,它们是包含多个其他类型值的类型。它们是数组、组合以及范围。

数组可以保存全部是同种类型的多个值。为每一种基本类型、组合类型、范围类型以及域类型都会自动创建一个数组类型。但是没有数组的数组。就类型系统的认知而言,多维数组就和一维数组一样。

只要用户创建一个表,就会创建组合类型或者行类型。也可以使用CREATE TYPE来定义一个没有关联表的“stand-alone”组合类型。一个组合类型只是一个具有相关域名称的类型列表。一个组合类型的值是一个行或者域值记录。用户可以访问来自SQL查询的组成域。

范围类型可以保存同种类型的两个值,它们是该范围的上下界。范围类型是用户创建的,不过也存在一些内建的范围类型。

一个域是基于一种特定底层类型的,并且出于很多目的它可以与其底层类型互换。不过,一个域能够具有约束来限制它的合法值于其底层基础类型允许值的一个子集。可以使用SQL命令CREATE DOMAIN创建域。

伪类型

有一些用于特殊目的“伪类型”。伪类型不能作为表列或者容器类型的组件出现,但是它们能被用于声明函数的参数和结果类型。这在类型系统中提供了一种机制来标识函数的特殊分类。

多态类型

特别让人感兴趣的一些伪类型是polymorphic types,用于声明polymorphic functions。 这种强大的特性允许单个函数定义对许多不同的数据类型进行操作,具体数据类型由特定调用中实际传递给它的数据类型确定。

自定义类型

拓展基础类型

示例:
步骤1:使用C语言定义一个输入输出函数。这些函数决定这个类型如何用字符串呈现和在内存中组织。输入函数结果一个null结束的字符串返回类型的内部形式。输出函数接收内部形式返回null结束的字符串。

#include <postgres.h>
#include <fmgr.h>

PG_MODULE_MAGIC;

typedef struct Complex 
{
    double    x;
    double    y;
} Complex;

PG_FUNCTION_INFO_V1(complex_in);

Datum
complex_in(PG_FUNCTION_ARGS)
{
    char       *str = PG_GETARG_CSTRING(0);
    double      x,
                y;
    Complex    *result;

    if (sscanf(str, " ( %lf , %lf )", &x, &y) != 2)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                 errmsg("invalid input syntax for type %s: \"%s\"",
                        "complex", str)));

    result = (Complex *) palloc(sizeof(Complex));
    result->x = x;
    result->y = y;
    PG_RETURN_POINTER(result);
}


PG_FUNCTION_INFO_V1(complex_out);

Datum
complex_out(PG_FUNCTION_ARGS)
{
    Complex    *complex = (Complex *) PG_GETARG_POINTER(0);
    char       *result;

    result = psprintf("(%g,%g)", complex->x, complex->y);
    PG_RETURN_CSTRING(result);
}

编译

gcc -I/usr/local/pgsql/include/server -fPIC -c complex.c -o complex.o
gcc -shared complex.o -o complex.so

安装

cp complex.so /usr/local/pgsql/lib

定义类型

语法

CREATE TYPE name (
    INPUT = input_function,
    OUTPUT = output_function
    [ , RECEIVE = receive_function ]
    [ , SEND = send_function ]
    [ , TYPMOD_IN = type_modifier_input_function ]
    [ , TYPMOD_OUT = type_modifier_output_function ]
    [ , ANALYZE = analyze_function ]
    [ , INTERNALLENGTH = { internallength | VARIABLE } ]
    [ , PASSEDBYVALUE ]
    [ , ALIGNMENT = alignment ]
    [ , STORAGE = storage ]
    [ , LIKE = like_type ]
    [ , CATEGORY = category ]
    [ , PREFERRED = preferred ]
    [ , DEFAULT = default ]
    [ , ELEMENT = element ]
    [ , DELIMITER = delimiter ]
    [ , COLLATABLE = collatable ]
)
create function complex_in(cstring) returns complex as
'$libdir/complex'
language c immutable strict;

create function complex_out(complex) returns cstring as
'$libdir/complex'
language c immutable strict;

create type complex (
	input = complex_in,
	output = complex_out,
	internallength = 16
);

使用

postgres=# create table complex_test(id int, val complex);
CREATE TABLE
postgres=# insert into complex_test(id, val) values(1, '(2,3)');
INSERT 0 1
postgres=# insert into complex_test(id, val) values(2, '(3,4)');
INSERT 0 1
postgres=# select * from complex_test;
 id |  val  
----+-------
  1 | (2,3)
  2 | (3,4)
(2 rows)

该类型还不能用与操作符比较和聚合参数,还需要进一步完善。

定义操作符

当想给表comple_test的where从句后面使用val进行操作符比较则需要进一步定义想给操作符。

语法

CREATE OPERATOR name (
    {FUNCTION|PROCEDURE} = function_name
    [, LEFTARG = left_type ] [, RIGHTARG = right_type ]
    [, COMMUTATOR = com_op ] [, NEGATOR = neg_op ]
    [, RESTRICT = res_proc ] [, JOIN = join_proc ]
    [, HASHES ] [, MERGES ]
)

C语言函数部分

PG_FUNCTION_INFO_V1(complex_cmp);

Datum
complex_cmp(PG_FUNCTION_ARGS)
{
    bool result;
    Complex * c1 = (Complex *)PG_GETARG_POINTER(0);
    Complex * c2 = (Complex *)PG_GETARG_POINTER(1);
    if (c1->x == c2->x && c1->y == c2->y)
    {
        result = true;
    }
    else 
    {
        result = false;
    }
    PG_RETURN_BOOL(result);
}

函数与操作符定义

create function complex_cmp(Complex, Complex) returns boolean as 
'$libdir/complex', 'complex_cmp'
language c immutable strict;

create operator = (
	function = complex_cmp,
	leftarg = complex, rightarg = complex,
	commutator = +
);

使用

postgres=# select * from complex_test;
 id |  val  
----+-------
  1 | (2,3)
  2 | (3,4)
(2 rows)

postgres=# select * from complex_test where val = '(2,3)';
 id |  val  
----+-------
  1 | (2,3)
(1 row)
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值