如何向postgreSQL中添加bytea类型的大js 对象类型数据

> 博客详情
摘要: 主要介绍PostgreSQL的基础数据类型(那些pg专属的类型和地理数据就不做详细介绍了)。
& & 前期,我参与了公司开发的数据库数据迁移工具的工作,以及之前的对,在此进一步将数据库的数据类型做一下分析记录。
&&&&一、数据库系统表pg_type
& & PostgreSQL的所有数据类型都存储在系统表中。 & & pg_type的表结构如下(这里是从源码中进行介绍的,源码可以点击):
CATALOG(pg_type,1247) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71) BKI_SCHEMA_MACRO
/* type name */
/* OID of namespace containing this type */
/* type owner */
/* arbitrary type classification */
/* is type "preferred" within its category? */
/* delimiter for arrays of this type */
/* 0 if not a composite type */
/* text format (required) */
/* binary format (optional) */
#ifdef CATALOG_VARLEN
/* variable-length fields start here */
typacl[1];
} FormData_pg_ & & 下面来简单介绍pg_type的各个字段含义。
&&&&typname、typnamespace、typowner 这三个字段名字上就可以看出来他们的含义。 &&&&typlen:这是标明类型的长度的,如果类型是定长的就是写明字段的长度(字节)。如果是变长的则是-1。比如int4也就是int或者integer,typlen为4,占用4个字节,varchar则为-1。 &&&&typbyval:判断内部过程传递这个类型的数值时是通过传值还是传引用。如果该类型不是 1, 2, 4, 8 字节长将只能按应用传递,因此 typbyval 最好是假。 即使可以传值,typbyval 也可以为假。比如float4就是如此。 &&&&typtype:对于基础类型是b, 对于复合类型是 c (比如,一个表的行类型)。对于域类型是d,对于伪类型是p. 本博文也是主要分析基础类型。 &&&&typcategory:这是对数据类型进行分类的,int2、int4、int8的typcategory都是N。typcategory的分类详看下表:
Array types
Boolean types
Composite types
Date/time types
Enum types
Geometric types
Network address types
Numeric types
Pseudo-types
Range types
String types
Timespan types
User-defined types
Bit-string types
unknown&type
typispreferred:这个字段和 typcategory是一起工作的,表示是否在 typcategory分类中首选的。
typisdefined:这个字段是类型能否使用的前提,标识数据类型是否被定义,false的话,根本无法使用。(大家可以将int4的
typis的fined改为false,然后用int4作为表的字段类型建表,会直接报错type integer is only a shell)。
typdelim:当分析数组输入时,分隔两个此类型数值的字符请注意该分隔符是与数组元素数据类型相关联的,而不是和数组数据类型关联。
typrelid:如果是复合类型(见 typtype)那么这个字段指向 pg_class 中定义该表的行。对于自由存在的复合类型,pg_class 记录并不表示一个表,但是总需要它来查找该类型连接的 pg_attribute 记录。对于非复合类型为零。
typelem:如果不为 0 ,那么它标识 pg_type 里面的另外一行。当前类型可以当做一个产生类型为 typelem 的数组来描述。一个"真正的"数组类型是变长的(typlen = -1),但是一些定长的(typlen & 0)类型也拥有非零的 typelem(比如 name 和 point)。如果一个定长类型拥有一个 typelem ,那么他的内部形式必须是 typelem 数据类型的某个数目的个数值,不能有其它数据。变长数组类型有一个该数组子过程定义的头(文件)。
typarray:指向同类型的数组类型的Oid。
typinput,typoutput:类型的输入输出函数,数据库进行对数字进行存储或者输出,首先由客户端获取数据
(一般为字符串
)进行转化,变为数据库能够使用的数据类型。输出函数亦然。
&&&&typreceive,typsend:输入、输出转换函数,多用于二进制格式。 &&&&typmodin,typmodout:对于变长的数据的输入、输出,这里主要是指vachar、time、timestamp等。这个字段和系统表pg_attribute的atttypmod相关联。 &&&&typanalyze:自定义的 ANALYZE 函数,如果使用标准函数,则为 0。 &&&&typalign:当存储此类型的数值时要求的对齐性质。它应用于磁盘存储以及该值在 PostgreSQL 内部的大多数形式。如果数值是连续存放的,比如在磁盘上以完全的裸数据的形式存放时,那么先在此类型的数据前填充空白,这样它就可以按照要求的界限存储。对齐引用是该序列中第一个数据的开头。 可能的值有: &&&&&&&&&&&&&&&&c = char 对齐,也就是不需要对齐。 &&&&&&&&&&&&&&&&s = short 对齐(在大多数机器上是 2 字节) &&&&&&&&&&&&&&&&i = int 对齐(在大多数机器上是 4 字节) &&&&&&&&&&&&&&&&d = double 对齐(在大多数机器上是 8 字节,但不一定是全部) &&&&typstorage:告诉一个变长类型(那些有 typlen = -1)的)说该类型是否准备好应付非常规值,以及对这种属性的类型的缺省策略是什么。可能的值有:&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&p: 数值总是以简单方式存储 &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&e: 数值可以存储在一个"次要"关系中 &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&m: 数值可以以内联的压缩方式存储 &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&x: 数值可以以内联的压缩方式或者在"次要"表里存储。 请注意 m 域也可以移到从属表里存储,但只是最后的解决方法(e 和 x 域先移走)。 &&&&typnotnull:代表在某类型上的一个 NOTNULL 约束。目前只用于域。 &&&&typbasetype:如果这是一个衍生类型(参阅 typtype),那么该标识作为这个类型的基础的类型。如果不是衍生类型则为零。 &&&&typtypmod:域使用 typtypmod 记录要作用到它们的基础类型上的 typmod (如果基础类型不使用 typmod 则为 -1)。如果这种类型不是域,那么为 -1 。 &&&&typndims:如果一个域是数组,那么 typndims 是数组维数的数值(也就是说,typbasetype 是一个数组类型;域的 typelem 将匹配基本类型的 typelem)。非域非数组域为零。 &&&&typcollation:指定类型的排序规则。如果类型不支持的排序规则,这将是零。支持排序规则基本类型都会有DEFAULT_COLLATION_OID这里。在一个collatable类型一个域可以有一些其他的排序规则的OID,如果已为域指定。 &&&&typdefaultbin:如果为非 NULL ,那么它是该类型缺省表达式的 nodeToString() 表现形式。目前这个字段只用于域。 &&&&typdefault:如果某类型没有相关缺省值,那么 typdefault 是 NULL 。如果 typdefaultbin 不是 NULL ,那么 typdefault 必须包含一个 typdefaultbin 代表的缺省表达式的人类可读的版本。如果 typdefaultbin 为 NULL 但 typdefault 不是,那么 typdefault 是该类型缺省值的外部表现形式,可以把它交给该类型的输入转换器生成一个常量。 &&&&typacl[1]:用户对类型的权限。
rolename=xxxx -- privileges granted to a role
=xxxx -- privileges granted to PUBLIC
r -- SELECT ("read")
w -- UPDATE ("write")
a -- INSERT ("append")
d -- DELETE
D -- TRUNCATE
x -- REFERENCES
t -- TRIGGER
X -- EXECUTE
U -- USAGE
C -- CREATE
c -- CONNECT
T -- TEMPORARY
arwdDxt -- ALL PRIVILEGES (for tables, varies for other objects)
* -- grant option for preceding privilege
/yyyy -- role that granted this privilege
& & 以上就是对系统表pg_type的介绍。下面主要针对每一个基础数据类型分析。
&&&&二、类型详解:
&&&&1、整数类型
& & (1)整数类型:
& & 首先是整数类型int2、int4(等价integer)、int8。 & & 为了方便说明,用下表来说明一下:
PostgreSQL类型名
占位(字节)
C\C++类型名
Java类型名
int2(samllint)
-32,768到32,767
int4(int、integer)
-2,147,483,648到2,147,483,647
int8(bigint)
-9,223,372,036,854,775,808到9,223,372,036, 854,775,807
&& & 在数据库物理文件存储的整数数字是以二进制的形式存储的。下面做一下小实验:
highgo=# create table aa(a1 int2, a2 int4, a3 int8);
CREATE TABLE
highgo=# insert into aa values (204,1530);
INSERT 0 1
CHECKPOINT & & 通过hexdump(输出16进制
)对二进制文件进行查看:
[root@localhost 12943]# hexdump 16385
0 8a 1c 1fd8
0 00 9fd8 00
0 00 00 0000
0 00 069b 00
0 00 00 0018
cc 0000 dddd 0000 aaaa aaaa
& & cc、dddd、aaaaaaaa正好是我插入的三个数字204, 51530。
& & (2)浮点数
& & float4、float8:这两个类型有些不同,先看看范围:
float4(real)
float&&&&&&&&
6 位十进制数字精度
float8(double precision)
15 位十进制数字精度
&&&&在源码中为:
typedef float float4;
typedef double float8;
& & 存储方式和C\C++中是相同的。可以看一下示例:
postgres=# create table floatdouble(f1 float4, d1 float8);
CREATE TABLE
postgres=# insert into floatdouble values (1);
INSERT 0 1
postgres=#
CHECKPOINT & & 看一下物理文件存储的数据(这里都是以16进制显示的):
[root@localhost 12814]# hexdump 16399
00 001c 1fd8
0 00 9fd8 00
0 00 00 0000
0 00 06b9 00
0 00 00 0018
0 00 c80 40c8
0002000 & & 12345变为了 e400 4640(float4),12345变为了 1c80 40c8。
& & 现在简单介绍一下float,它的存储方式为:
&&&&共计32位,折合4字节。由最高到最低位分别是第 31、30、29、……、0位。31位是符号位,1表示该数为负,0反之。30-23位,一共8位是指数位。22-0位,一共23 位是尾数位。
&&&&现在让我们按照IEEE浮点数表示法,一步步的将float型浮点数12345转换为十六进制代码。首先数字是正整数,所以符号位为0,接下来12345的二进制表示为01,小数点向左移,一直移到离最高位只有1位,就是最高位的1。即1.1*2^13,所有的二进制数字最前边都有一个1,所以可以去掉,那么尾数位的精确度其实可以为24 bit。再来看指数位,因为是有8 bit,所以只为能够表示的为0~255,也可以说是-128~127,所以指数为为正的话,必须加上127,即13+127=140,即。好了,所有的数据都整理好了,现在表示12345的float存储方式即,现在把它转化为16进制,即,而存储文件是从下向上写入的,所以表示为 e400 4640。
&&&&double,它的存储方式为:
& & 指数位与尾数部分都要比float增加了长度,所以计算方法还是同上,只不过现在的指数位要加的是1023,尾数部分自动补更多的零。
& & 注:PostgreSQL 还支持 SQL 标准表示法 float 和 float(p) 用于声明非精确的数值类型。其中的 p 声明以二进制位表示的最低可接受精度。在选取 real 类型的时候,PostgreSQL 接受 float(1) 到 float(24),在选取 double precision 的时候,接受 float(25) 到 float(53) 。在允许范围之外的 p 值将导致一个错误。没有声明精度的 float 将被当作 double precision 。
& & (3)Numeric
& &数字类型还有一种便是numeric(decimal),这种数据类型是数字当中最为复杂的一种了,他是一种结构体,在源码中为:
typedef int16 NumericD
struct NumericShort
/* Sign + display scale + weight */
NumericDigit n_data[1];
/* Digits */
struct NumericLong
n_sign_ /* Sign + display scale */
/* Weight of 1st digit */
NumericDigit n_data[1];
/* Digits */
union NumericChoice
/* Header word */
struct NumericLong n_ /* Long form (4-byte header) */
struct NumericShort n_ /* Short form (2-byte header) */
struct NumericData
/* varlena header (do not touch directly!) */
union NumericC /* choice of format */
& & 因为这里使用的是union,所以我们可以对struct重新定义一下,按照在内存中的表现形式:
struct NumericShort_memory
NumericDigit n_data[1];
struct NumericLong_memory
NumericDigit n_data[1];
& & 还有一个比较重要的结构体,它的作用是最为char*和numeric之间进行转化的中间体:
typedef struct NumericVar
/* # of digits in digits[] - can be 0! */
/* weight of first digit */
/* NUMERIC_POS, NUMERIC_NEG, or NUMERIC_NAN */
/* display scale */
NumericDigit *
/* start of palloc'd space for digits[] */
NumericDigit *
/* base-NBASE digits */
} NumericV
&&&&组成numeric的结构体就有四个,比较复杂,而且基本上都是通过数组进行存储的,他的范围为小数点前为131072位,小数点后为16383位。 & & 首先要讲的是NumericVar,这是将数据变为numeirc的第一步,现在以‘’为例子讲一下答题过程,具体的函数以后可能会继续讲一下。数据库首先读取字符串'',然后将字符串变为NumericVar,要说明的是,数据都是存储到buf(这应该是在物理文件中的补齐所设置的,不过不是特别确定)和digits中的,比如'',是这样存储的 &45 6780,这些都是数字存入到数组中。ndigits是指的digits数组元素的个数,这里就是3,而weight表示的是整数部分所占用的数组元素个数,不过进行了一系列的运算,在保证有整数部分,&weight = (整数部分个数 + 4 - 1)/4 - 1。sign,这是对数字进行标记的,有正负标记。dscale则表示的是小数部分数字个数。
& & 下面主要讲一下NumericData,按照上面的顺序说明一下各个结构体的结构,
&&&&NumericShort,这是数据库对小数据进行存储用的格式。其中n_header是对数据的标记,根据正负、类型(指的是数字大小类型:NUMERIC_SIGN_MASK、NUMERIC_POS、NUMERIC_NEG、NUMERIC_SHORT、NUMERIC_NAN)weight进行运算得到一个标记。n_data和NumericVar中的digits是相同的。
& & 标记的运算:
result-&choice.n_short.n_header =
(sign == NUMERIC_NEG ? (NUMERIC_SHORT | NUMERIC_SHORT_SIGN_MASK)
&&&&: NUMERIC_SHORT)
&&&&| (var-&dscale && NUMERIC_SHORT_DSCALE_SHIFT)
&&&&| (weight & 0 ? NUMERIC_SHORT_WEIGHT_SIGN_MASK : 0)
&&&&| (weight & NUMERIC_SHORT_WEIGHT_MASK);
& & NumericLong,这是数据库对大数据进行存储用的格式。其中n_sign_dscale是对数据的标记,根据正负、类型(指的是数字大小类型:NUMERIC_SIGN_MASK、NUMERIC_POS、NUMERIC_NEG、NUMERIC_SHORT、NUMERIC_NAN)进行运算得到一个标记。weight和NumericVar的是相同的。n_data和NumericVar中的digits是相同的。
& & 标记的运算:
result-&choice.n_long.n_sign_dscale =
sign | (var-&dscale & NUMERIC_DSCALE_MASK);
result-&choice.n_long.n_weight =
& & NumericChoice,这是union,这能引用同一个存储块。然后最后总的NumericData,这里的vl_len_是对数据所占位计算而来的,计算方法见下。
& & 在Java中可以用getBigDecimal来读取数据。
& & 下面看一下物理存储:
postgres=# create table numerictest (n1 numeric);
CREATE TABLE
postgres=# select pg_relation_filepath('numerictest');
pg_relation_filepath
----------------------
postgres=# insert into numerictest values (123),(1234),(12345),(),(),(),(789);
INSERT 0 7
postgres=#
CHECKPOINT
[root@localhost 12892]# hexdump 16390
0 00 9fe0 003a 9fc0 003a
fa0 003e 9f78
f00 004a 9ee0 00
0 00 00 0000
a0 00 00 0000
8 18 00 0000
f 00 00 0000
e04 00 069f 00
0 00 02 0018
7 09 641a 00
f 00 00 0000
5 18 00 8509
a 00 069f 00
0 00 02 0018
3 c09 001a 00
f 00 00 0000
3 18 010f 09
f 00 00 0000
2 18 000b d280
f 00 00 0000
1 18 000b 7b80
0002000 &&&&这里列一个表具体的看一下(这里只说一下short类型的):
000b 7b80 0000
000b d280 0004&
00 7c09 001a
00 00 0000
d2 162e 2328
d209&2e04 00
& & 注:这里的16进制是按照digits内存储的整数转换的,比如12345在数组digits内为,转化为16进制为。 &&&&&&&&&&再比如带有小数的数字例如,,在数组中为,6780,转化为16进制为a7c。 &&&&&&&&& 这上面的存储的前两个字节中的第一个(看起来是第二个),这个值和数据长度vl_len_是相关的,它的计算公式为:
& & 正常的计算为:
len = NUMERIC_HDRSZ_SHORT + n * sizeof(NumericDigit);
len = NUMERIC_HDRSZ + n * sizeof(NumericDigit);
SET_VARSIZE(result, len);
#define SET_VARSIZE(PTR, len)
SET_VARSIZE_4B(PTR, len)
#define SET_VARSIZE_4B(PTR,len) \
(((varattrib_4b *) (PTR))-&va_4byte.va_header = (((uint32) (len)) && 2))
& & 当数据库向物理文件进行写入的时候,数据将会发生改变,计算公式如下:
else if (VARLENA_ATT_IS_PACKABLE(att[i]) &&
VARATT_CAN_MAKE_SHORT(val))
&&&&/* convert to short varlena -- no alignment */
&&&&data_length = VARATT_CONVERTED_SHORT_SIZE(val);
&&&&SET_VARSIZE_SHORT(data, data_length);
&&&&memcpy(data + 1, VARDATA(val), data_length - 1);
& &注:&一个 numeric 类型的标度(scale)是小数部分的位数,精度(precision)是全部数据位的数目,也就是小数点两边的位数总和。因此数字 23.5141 的精度为 6 而标度为 4 。你可以认为整数的标度为零。
& & 2、货币类型& &
&数字类型中的money,也不能说它完全是数字类型,还能够支持‘$1000.00’,这种格式。在C\C++和Java中都没有对应的数字类型。他的范围是-47758.08 to +47758.07,int8是它的100倍,它在物理文件存储为:
postgres=# create table moneytable(m1 money);
CREATE TABLE
postgres=# insert into moneytable values ('$1')
INSERT 0 1
postgres=# select *
postgres=#
CHECKPOINT
postgres=# select pg_relation_filepath('moneytable');
pg_relation_filepath
----------------------
postgres=# insert into moneytable values ('2')
INSERT 0 1
postgres=#
CHECKPOINT
postgres=# insert into moneytable values ('100')
INSERT 0 1
postgres=#
CHECKPOINT
[root@localhost 12814]# hexdump 16467
019e 24 1fa0
fa0 00 00 0000
0 00 00 0000
eb 00 00 0000
3 18 00 0000
ea 00 00 0000
2 18 00c8 00
e9 00 00 0000
1 18 00 0000
& & 每个值都变为原来的100倍。 这也是为什么能表示两位小数的原因。
&&&&3、字符类型
& & 字符类型有:char、char(n)、bpchar、bpchar(n)、character(n)&、varchar、varchar(n)、character varying(n)、text、name、cstring。
& & (1)一般字符类型
& & char、char(n) 、character(n)、bpchar、bpchar(n), 这些(这些类型都是bpchar的马甲)是同一种类型,使用的是同一个输入输出函数。
& &&character(n)&、varchar、varchar(n)、character varying(n),这些(这些类型都是varchar的马甲)是同一种类型,使用的是相同的输入输出函数。
& & text是一种非SQL标准类型,它和上边除了char单字节外,用的都是相同的结构体:
typedef struct varlena BpC /* blank-padded char, ie SQL char(n) */
typedef struct varlena VarC /* var-length char, ie SQL varchar(n) */
struct varlena
vl_len_[4];
/* Do not touch this field directly! */
vl_dat[1];
}; & & 这里还要说一个类型cstring,这个类型,在C中为char*。不能作为一个类型对字段进行定义。它和text的关系比较近。
& & 在textin中是这么定义的:
textin(PG_FUNCTION_ARGS)
*inputText = PG_GETARG_CSTRING(0);
PG_RETURN_TEXT_P(cstring_to_text(inputText));
cstring_to_text(const char *s)
return cstring_to_text_with_len(s, strlen(s));
cstring_to_text_with_len(const char *s, int len)
*result = (text *) palloc(len + VARHDRSZ);
SET_VARSIZE(result, len + VARHDRSZ);
memcpy(VARDATA(result), s, len);
&&&&这里对text的处理只是在cstring基础上加了一个长度而已。其他的类型处理还是比较多的。
&&&&这里bpchar对数据的存储为当声明长度的时候,输入函数会对输入的数据进行判断,当长度大于声明的长度时,数据库会中断请求,报错。当小于时,函数会对数据进行填补空格,直到达到长度为止。 & & varchar的输入函数不会对数据进行补白,但是当声明长度时,超过时,同样会报错。 & & text不需要进行长度声明,它的存储几乎没有限制。
& & 但是,这些存储确实是有限制的:
if (*tl & MaxAttrSize)
&&&&ereport(ERROR,
&&&&(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
&&&&&&&&errmsg("length for type %s cannot exceed %d",
&&&&&&&&&&&&typename, MaxAttrSize)));
#define MaxAttrSize
(10 * 1024 * 1024) 这里的限制大小是10GB,但是还有一个数据库本身对文件的限制:
Maximum size for a database? unlimited (32 TB databases exist)
Maximum size for a table? 32 TB
Maximum size for a row? 400 GB
Maximum size for a field? 1 GB
Maximum number of rows in a table? unlimited
Maximum number of columns in a table? 250-1600 depending on column types
Maximum number of indexes on a table? unlimited
&&&&所以目前对字段最大存储为1GB。
& &下面介绍一下在物理文件存储的格式:
& & 建立表test:
postgres=# create table test(t1 char, t2 char(10), t3 varchar, t4 varchar(10), t5 bpchar, t6 text);
CREATE TABLE
postgres=#
CHECKPOINT
postgres=# select pg_relation_filepath('test');
pg_relation_filepath
----------------------
(1 row) & & 插入数值:
postgres=# insert into test values ('a','a','a','a','a','a');
INSERT 0 1
postgres=# insert into test values ('b','b','b','b','b','b');
INSERT 0 1
postgres=# insert into test values ('a','aa','aa','aa','aa','aa');
INSERT 0 1
postgres=# insert into test values ('b','bb','bb','bb','bb','bb');
INSERT 0 1
postgres=#
CHECKPOINT
postgres=# select *
| t3 | t4 | t5 | t6
----+------------+----+----+----+----
| aa | aa | aa | aa
| bb | bb | bb | bb
(4 rows) &&&&看一下物理文件:
[root@localhost 12892]# hexdump 16490
0 0000 ab48 00
0 00 9fd0 005a 9fa0 005a
0 00 00 0000
de 00 00 0000
4 18 62 2020
0 62 62 6207
2 00 06dd 00
0 00 02 0018
5 20 20 6161
7 07 00 0000
dc 00 00 0000
2 18 20 2020
0 62 62 0000
db 00 00 0000
1 18 20 2020
0 61 61 0000
物理文件内容
物理文件内容
物理文件内容
物理文件内容
varchar(10)
& & 这里的数据都受到SET_VARSIZE_SHORT的影响,表示长度的位置标为1字节,然后进行计算。
& & 还要说明的是,当数据达到一定长度时,数据库会对数据进行压缩,主要是采用的TOAST机制。采用了一种LZ压缩算法,这是一种无损压缩算法,该算法在函数toast_compress_datum 中进行了具体实现。简单来说,LZ压缩算法被认为是基于字符串匹配的算法。LZ算法压缩算法的详情,可以参阅相关文献,这里就不多展开了。
& & (2)name
&&&&name:基础类型, 在C\C++中没有直接对应的类型,在源码中是这样定义的:
typedef struct nameData
data[NAMEDATALEN];
typedef NameData *N
,在物理文件的存储如下:
postgres=# create table nametable(n1 name);
CREATE TABLE
postgres=# insert into nametable values ('liu');
INSERT 0 1
postgres=#
CHECKPOINT
postgres=# select pg_relation_filepath('nametable');
pg_relation_filepath
----------------------
[root@localhost 12814]# hexdump 16461
0 9b 1c 1fa8
0 00 9fa8 00b0
0 00 00 0000
0 00 06de 00
0 00 00 0018
c 00 00 0000
0 00 00 0000
liu = 6c 69 75(16进制)。
& & 4、日期时间类型
& & 这里列举数据库支持的日期类型的大概信息:
存储空间(单位:字节)
Resolution
timestamp [ (p) ] [ without time zone ]
日期和时间
1 microsecond / 14 digits
timestamp [ (p) ] with time zone
日期和时间,带时区
1 microsecond / 14 digits
只用于日期
5874897 AD
time [ (p) ] [ without time zone ]
只用于一日内时间
1 microsecond / 14 digits
time [ (p) ] with time zone
只用于一日内时间,带时区
00:00:00+1459
24:00:00-1459
1 microsecond / 14 digits
interval [ fields ] [ (p) ]
1 microsecond / 14 digits
& & (1)date
&&&&这里首先要说明的是date类型,它的定义其实很简单:
typedef int32 DateADT;
& & PostgreSQL按照儒略日(Julian day,JD),即公元前日作为起始,具体的原因这里就不去探究了。
& & 它其实是一个整型数字,之所以能够表示 'yyyy-mm-dd'的原因主要是date类型的输入输出函数。它对输入的字符,即格式为'yyyy-mm-dd'或'yyyy:mm:dd'或'yyyy.mm.dd'的字符串进行读取,然后进行一系列的运算然后得到一个32bits的数字,存入到物理文件中。比如''存入数据库中为4725。
postgres=# create table datetest(d1 date);
CREATE TABLE
postgres=# insert into datetest values ('');
INSERT 0 1
postgres=#
CHECKPOINT
postgres=# select pg_relation_filepath('datetest');
pg_relation_filepath
----------------------
[root@localhost 12892]# hexdump 16499
0 8c 1c 1fe0
0 00 9fe0 00
0 00 00 0000
e4 00 00 0000
1 18 00 0000
0002000 & & 0x。
& & (2)time和time with time zone
& & 这里的time和time with time zone,表示时间的部分和date类似都是整型。为了增加时区,这里有新的结构体TimeTzADT,它们的源码为:
#ifdef HAVE_INT64_TIMESTAMP
typedef int64 TimeADT;
typedef float8 TimeADT;
typedef struct
/* all time units other than months and years */
/* numeric time zone, in seconds */
} TimeTzADT; & & 这里对事件的存储,是按照秒数来计算的,并且由于能够表示到小数点后6位,在此扩大了1000000倍。即,10:10:10.000001表示为数字。
& & 还有对时区的存储也是表示为秒数,比如正八区(+8:00:00)为-28800,即0xFFFF8F80。
postgres=# create table timeandtimetz(t1 time, t2 timetz);
CREATE TABLE
postgres=# insert into timeandtimetz values ('10:10:10.000001', '10:10:10.:00:00');
the y is 2014 , the m is 4 , the d is 21
the century is 68
the julian1 is 2454943
the julian2 is 2456595
the julian3 is 2456769
the time_in time is
the timetz_in time is
the timetz_in tz is -28800
INSERT 0 1
postgres=#
CHECKPOINT
postgres=# select pg_relation_filepath('timeandtimetz');
pg_relation_filepath
----------------------
[root@localhost 12892]# hexdump 16508
0 8f 1c 1fd0
0 00 9fd0 00
0 00 00 0000
ec 00 00 0000
1 18 08 0000
1 00 8f80 ffff
& &&(3)timestamp 和&timestamp with time zone
& & 这两个类型都包含了日期与时间,唯一不同的地方便是timestamp with time zone带有时区,它们的定义为:
typedef int64 T
typedef int64 TimestampTz;
&&&&同样是经过一系列的转换,公式,将格式为'yyyy-mm-dd hh:mm:ss +/-hh:mm:ss',变为一个长整型。比如:' 20:00:00.000001',为001;' 20:00:00.:00:00'为001。
postgres=# create table timesandtimestz(t1 timestamp(6), t2 timestamptz(6));
CREATE TABLE
postgres=# insert into timesandtimestz values (' 20:00:00.000001', ' 20:00:00.:00:00');
the y is 2013 , the m is 1 , the d is 1
the century is 68
the julian1 is 2454213
the julian2 is 2455865
the julian3 is 2456294
the y is 2013 , the m is 1 , the d is 1
the century is 68
the julian1 is 2454213
the julian2 is 2455865
the julian3 is 2456294
timestamp_in timestamp is 001
the y is 2013 , the m is 1 , the d is 1
the century is 68
the julian1 is 2454213
the julian2 is 2455865
the julian3 is 2456294
timestamptz_out timestamptz is 001
INSERT 0 1
postgres=#
CHECKPOINT
postgres=# select pg_relation_filepath('timesandtimestz');
pg_relation_filepath
----------------------
[root@localhost 12892]# hexdump 16528
0 96 1c 1fd8
0 00 9fd8 00
0 00 00 0000
0 00 06fc 00
0 00 00 0018
1 57e8 753e
& & (4)interval
& & interval,时间间隔类型,这个反而是所有时间类型当中最复杂的数据类型。
typedef struct
TimeOffset
/* all time units other than days, months and
* years */
/* days, after time for alignment */
/* months and years, after time for alignment */
typedef int64 TimeO & & 这里只是一个混合的结构体。
& & 注:这里的时间类型格式还有其他形式,我这就不一一列举了,大体过程类似,都是将日期变为数字,进行存储。
& & 5、对象标识符类型
&&&&oid:基础类型,占位4字节。下面是Oid的定义:
typedef unsigned int O & & 完全按照ascii码表示的。&
postgres=# create table oidt(o1 oid);
CREATE TABLE
postgres=# insert into oidt values (1);
INSERT 0 1
postgres=# insert into oidt values (2);
INSERT 0 1
postgres=# insert into oidt values (1);
INSERT 0 1
postgres=#
CHECKPOINT
postgres=# select pg_relation_filepath('oidt');
pg_relation_filepath
----------------------
[root@localhost 12892]# hexdump 16522
0 0000 cf08 00
fa0 00 00 0000
0 00 00 0000
f8 00 00 0000
3 18 00 0000
f7 00 00 0000
2 18 00 0000
f6 00 00 0000
1 18 00 0000
& & 6、布尔型
&&&&bool:基础类型,占位1字节。以0、1来表示false, true。
postgres=# create table boolt(b1 bool);
CREATE TABLE
postgres=# insert into boolt values ('t'),('f');
INSERT 0 2
postgres=#
CHECKPOINT
postgres=# select pg_relation_filepath('boolt');
pg_relation_filepath
----------------------
[root@localhost 12892]# hexdump 16522
0 0000 cf08 00
fa0 00 00 0000
0 00 00 0000
f8 00 00 0000
3 18 00 0000
f7 00 00 0000
2 18 00 0000
f6 00 00 0000
1 18 00 0000
& & 7、二进制类型
& & bytea,二进制类型,和text等用的相同的结构体,同样受到数据库的限制。
postgres=# create table byteat(b1 bytea);
CREATE TABLE
postgres=# insert into byteat values ('ab');
INSERT 0 1
postgres=#
CHECKPOINT
postgres=# select pg_relation_filepath('byteat');
pg_relation_filepath
----------------------
postgres=# insert into byteat values ('abcde');
the data_length is 6
INSERT 0 1
postgres=#
CHECKPOINT
[root@localhost 12892]# hexdump 16516
0 92 20 1fc0
0 00 00 0000
f4 00 00 0000
2 18 610d 00
f3 00 00 0000
1 18 00 0000
&&&&三、总结
& & 在这里只是介绍了比较简单的几种数据类型,其中的用法上写的都比较简单,但是基本上都是如此。若有什么不对的地方请及时和我交流,希望和大家共同学习。
人打赏支持
参与源创会
领取时间:
“”在线下联结了各位 OSCer,推广开源项目和理念,很荣幸有你的参与~
领取条件:参与过开源中国“源创会”的 OSCer 可以领取
码字总数 56410
支付宝支付
微信扫码支付
打赏金额: ¥
已支付成功
打赏金额: ¥

我要回帖

更多关于 java判断对象类型 的文章

 

随机推荐