pgtypes 库将PostgreSQL数据库类型映射到 C 中等价的类型以便在 C 程序中使用。它还提供在 C 中对这些类型进行基本计算的函数,即不依赖PostgreSQL服务器进行计算。请看下面的例子:
EXEC SQL BEGIN DECLARE SECTION;
date date1;
timestamp ts1, tsout;
interval iv1;
char *out;
EXEC SQL END DECLARE SECTION;
PGTYPESdate_today(&date1);
EXEC SQL SELECT started, duration INTO :ts1, :iv1 FROM datetbl WHERE d=:date1;
PGTYPEStimestamp_add_interval(&ts1, &iv1, &tsout);
out = PGTYPEStimestamp_to_asc(&tsout);
printf("Started + duration: %s\n", out);
PGTYPESchar_free(out);
PGTYPESnumeric_to_asc
之类的一些函数返回一个新分配的字符串的指针。这些结果应该用PGTYPESchar_free
而不是free
释放(这只在Windows上很重要,因为Windows上的内存分配和释放有时候需要由同一个库完成)。
numeric类型用来完成对任意精度的计算。PostgreSQL服务器中等效的类型请见第 8.1 节。因为要用于任意精度,这种变量需要能够动态地扩展和收缩。这也是为什么你只能用PGTYPESnumeric_new
和 PGTYPESnumeric_free
函数在堆上创建numeric变量。decimal类型与numeric类型相似但是在精度上有限制,decimal类型可以在堆上创建也可以在栈上创建。
下列函数可以用于numeric类型:
PGTYPESnumeric_new
请求一个指向新分配的numeric变量的指针。
numeric *PGTYPESnumeric_new(void);
PGTYPESnumeric_free
释放一个numeric类型,释放它所有的内存。
void PGTYPESnumeric_free(numeric *var);
PGTYPESnumeric_from_asc
从字符串记号中解析一个numeric类型。
numeric *PGTYPESnumeric_from_asc(char *str, char **endptr);
例如,可用的格式是: -2
、 .794
、 +3.44
、 592.49E07
或者 -32.84e-4
。 如果值能被成功地解析,将返回一个有效的指针,否则返回 NULL 指针。目前 ECPG 总是解析整个字符串并且因此当前不支持把第一个非法字符的地址存储在 *endptr
中。你可以安全地把endptr
设置为 NULL。
PGTYPESnumeric_to_asc
返回由malloc
分配的字符串的指针,它包含numeric类型num
的字符串表达。
char *PGTYPESnumeric_to_asc(numeric *num, int dscale);
numeric值将被使用dscale
小数位打印,必要时会圆整。结果必须用PGTYPESchar_free()
释放。
PGTYPESnumeric_add
把两个numeric变量相加放到第三个numeric变量中。
int PGTYPESnumeric_add(numeric *var1, numeric *var2, numeric *result);
该函数把变量var1
和var2
相加放到结果变量result
中。成功时该函数返回 0,出错时返回 -1。
PGTYPESnumeric_sub
把两个numeric变量相减并且把结果返回到第三个numeric变量。
int PGTYPESnumeric_sub(numeric *var1, numeric *var2, numeric *result);
该函数把变量var2
从变量var1
中减除。该操作的结果被存储在变量result
中。成功时该函数返回 0,出错时返回 -1。
PGTYPESnumeric_mul
把两个numeric变量相乘并且把结果返回到第三个numeric变量。
int PGTYPESnumeric_mul(numeric *var1, numeric *var2, numeric *result);
该函数把变量var1
和var2
相乘。该操作的结果被存储在变量result
中。成功时该函数返回 0,出错时返回 -1。
PGTYPESnumeric_div
把两个numeric变量相除并且把结果返回到第三个numeric变量。
int PGTYPESnumeric_div(numeric *var1, numeric *var2, numeric *result);
该函数用变量var2
除变量var1
。该操作的结果被存储在变量result
中。成功时该函数返回 0,出错时返回 -1。
PGTYPESnumeric_cmp
比较两个numeric变量。
int PGTYPESnumeric_cmp(numeric *var1, numeric *var2)
这个函数比较两个numeric变量。错误时会返回INT_MAX
。成功时,该函数返回三种可能结果之一:
var1
大于var2
则返回 1
如果var1
小于var2
则返回 -1
如果var1
和var2
相等则返回 0
PGTYPESnumeric_from_int
把一个整数变量转换成一个numeric变量。
int PGTYPESnumeric_from_int(signed int int_val, numeric *var);
这个函数接受一个有符号整型变量并且把它存储在numeric变量var
中。成功时返回 0,失败时返回 -1。
PGTYPESnumeric_from_long
把一个长整型变量转换成一个numeric变量。
int PGTYPESnumeric_from_long(signed long int long_val, numeric *var);
这个函数接受一个有符号长整型变量并且把它存储在numeric变量var
中。成功时返回 0,失败时返回 -1。
PGTYPESnumeric_copy
把一个numeric变量复制到另一个中。
int PGTYPESnumeric_copy(numeric *src, numeric *dst);
这个函数把src
指向的变量的值复制到dst
指向的变量中。成功时该函数返回 0,出错时返回 -1。
PGTYPESnumeric_from_double
把一个双精度类型的变量转换成一个numeric变量。
int PGTYPESnumeric_from_double(double d, numeric *dst);
这个函数接受一个双精度类型的变量并且把结果存储在dst
指向的变量中。成功时该函数返回 0,出错时返回 -1。
PGTYPESnumeric_to_double
将一个numeric类型的变量转换成双精度。
int PGTYPESnumeric_to_double(numeric *nv, double *dp)
这个函数将nv
指向的变量中的numeric值转换成dp
指向的双精度变量。成功时该函数返回 0,出错时返回 -1(包括溢出)。溢出时,全局变量errno
将被额外地设置成PGTYPES_NUM_OVERFLOW
。
PGTYPESnumeric_to_int
将一个numeric类型的变量转换成整数。
int PGTYPESnumeric_to_int(numeric *nv, int *ip);
该函数将nv
指向的变量的numeric值转换成ip
指向的整数变量。成功时该函数返回 0,出错时返回 -1(包括溢出)。溢出时,全局变量errno
将被额外地设置成PGTYPES_NUM_OVERFLOW
。
PGTYPESnumeric_to_long
将一个numeric类型的变量转换成长整型。
int PGTYPESnumeric_to_long(numeric *nv, long *lp);
该函数将nv
指向的变量的numeric值转换成ip
指向的长整型变量。成功时该函数返回 0,出错时返回 -1(包括溢出)。溢出时,全局变量errno
将被额外地设置成PGTYPES_NUM_OVERFLOW
。
PGTYPESnumeric_to_decimal
将一个numeric类型的变量转换成decimal。
int PGTYPESnumeric_to_decimal(numeric *src, decimal *dst);
该函数将nv
指向的变量的numeric值转换成ip
指向的decimal变量。成功时该函数返回 0,出错时返回 -1(包括溢出)。溢出时,全局变量errno
将被额外地设置成PGTYPES_NUM_OVERFLOW
。
PGTYPESnumeric_from_decimal
将一个decimal类型的变量转换成numeric。
int PGTYPESnumeric_from_decimal(decimal *src, numeric *dst);
该函数将nv
指向的变量的decimal值转换成ip
指向的numeric变量。成功时该函数返回 0,出错时返回 -1(包括溢出)。因为decimal类型被实现为numeric类型的一个有限的版本,在这个转换上不会发生溢出。
C 中的日期类型允许你的程序处理 SQL 日期类型的数据。PostgreSQL服务器的等效类型可见第 8.5 节。
下列函数可以被用于日期类型:
PGTYPESdate_from_timestamp
从一个时间戳中抽取日期部分。
date PGTYPESdate_from_timestamp(timestamp dt);
该函数接收一个时间戳作为它的唯一参数并且从这个时间戳返回抽取的日期部分。
PGTYPESdate_from_asc
从日期的文本表达解析一个日期。
date PGTYPESdate_from_asc(char *str, char **endptr);
该函数接收一个 C 的字符串str
以及一个指向 C 字符串的指针endptr
。当前 ECPG 总是解析完整的字符串并且因此当前不支持将第一个非法字符的地址存储在*endptr
中。你可以安全地把endptr
设置为 NULL。
注意该函数总是假定格式按照 MDY 格式化并且当前在 ECPG 中没有变体可以改变这种格式。
表 35.2展示了所有允许的输入格式。
表 35.2. PGTYPESdate_from_asc
的合法输入格式
输入 | 结果 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PGTYPESdate_to_asc
返回一个日期变量的文本表达。
char *PGTYPESdate_to_asc(date dDate);
该函数接收日期dDate
作为它的唯一参数。它将以形式1999-01-18
输出该日期,即以YYYY-MM-DD
格式输出。结果必须用PGTYPESchar_free()
释放。
PGTYPESdate_julmdy
从一个日期类型变量中抽取日、月和年的值。
void PGTYPESdate_julmdy(date d, int *mdy);
该函数接收日期d
以及一个指向有 3 个整数值的数组mdy
的指针。变量名就表明了顺序:mdy[0]
将被设置为包含月份,mdy[1]
将被设置为日的值,而mdy[2]
将包含年。
PGTYPESdate_mdyjul
从一个由 3 个整数构成的数组创建一个日期值,3 个整数分别指定日、月和年。
void PGTYPESdate_mdyjul(int *mdy, date *jdate);
这个函数接收 3 个整数(mdy
)组成的数组作为其第一个参数,其第二个参数是一个指向日期类型变量的指针,它被用来保存操作的结果。
PGTYPESdate_dayofweek
为一个日期值返回表示它是星期几的数字。
int PGTYPESdate_dayofweek(date d);
这个函数接收日期变量d
作为它唯一的参数并且返回一个整数说明这个日期是星期几。
0 - 星期日
1 - 星期一
2 - 星期二
3 - 星期三
4 - 星期四
5 - 星期五
6 - 星期六
PGTYPESdate_today
得到当前日期。
void PGTYPESdate_today(date *d);
该函数接收一个指向一个日期变量(d
)的指针并且把该参数设置为当前日期。
PGTYPESdate_fmt_asc
使用一个格式掩码将一个日期类型的变量转换成它的文本表达。
int PGTYPESdate_fmt_asc(date dDate, char *fmtstring, char *outbuf);
该函数接收要转换的日期(dDate
)、格式掩码(fmtstring
)以及将要保存日期的文本表达的字符串(outbuf
)。
成功时,返回 0;如果发生错误,则返回一个负值。
下面是你可以使用的域指示符:
dd
- 一个月中的第几天。
mm
- 一年中的第几个月。
yy
- 两位数的年份。
yyyy
- 四位数的年份。
ddd
- 星期几的名称(简写)。
mmm
- 月份的名称(简写)。
所有其他字符会被原封不动地复制到输出字符串中。
表 35.3指出了一些可能的格式。这将给你一些线索如何使用这个函数。所有输出都是基于同一个日期:1959年11月23日。
表 35.3. PGTYPESdate_fmt_asc
的合法输入格式
格式 | 结果 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PGTYPESdate_defmt_asc
使用一个格式掩码把一个 C 的 char*
子返回串转换成一个日期类型的值。
int PGTYPESdate_defmt_asc(date *d, char *fmt, char *str);
该函数接收一个用来保存操作结果的指向日期值的指针(d
)、用于解析日期的格式掩码(fmt
)以及包含日期文本表达的 C char* 串(str
)。该函数期望文本表达匹配格式掩码。不过你不需要字符串和格式掩码的一一映射。该函数只分析相继顺序并且查找表示年份位置的文字yy
或者 yyyy
、表示月份位置的mm
以及表示日位置的dd
。
表 35.4给出了一些可能的格式。这将给你一些线索如何使用这个函数。
表 35.4. rdefmtdate
的合法输入格式
格式 | 字符串 | 结果 |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
C 中的时间戳类型允许你的程序处理 SQL 时间戳类型的数据。PostgreSQL服务器的等效类型可见第 8.5 节。
下列函数可用于时间戳类型:
PGTYPEStimestamp_from_asc
从文本表达解析一个时间戳并放到一个时间戳变量中。
timestamp PGTYPEStimestamp_from_asc(char *str, char **endptr);
这个函数接收一个要解析的字符串(str
)以及一个 C char* 的指针(endptr
)。当前 ECPG 总是解析完整的字符串并且因此当前不支持将第一个非法字符的地址存储在*endptr
中。你可以安全地把endptr
设置为 NULL。
成功时该函数返回解析到的时间戳。错误时,会返回PGTYPESInvalidTimestamp
并且errno
会被设置为PGTYPES_TS_BAD_TIMESTAMP
。关于这个值的重要提示请见 PGTYPESInvalidTimestamp
。
通常,该输入字符串能够包含一个允许的日期说明、一个空格字符和一个允许的时间说明的任意组合。注意 ECPG 不支持时区。它能够解析时区但是不会应用任何计算(例如PostgreSQL服务器所作的事情)。时区指示符会被无声无息地丢弃。
表 35.5包含输入字符串的一些例子。
表 35.5. PGTYPEStimestamp_from_asc
的合法输入格式
输入 | 结果 |
---|---|
|
|
|
|
|
|
|
|
PGTYPEStimestamp_to_asc
将一个日期转换成一个 C char* 字符串。
char *PGTYPEStimestamp_to_asc(timestamp tstamp);
该函数接收时间戳tstamp
作为它的唯一参数并且返回一个分配好的包含该时间戳文本表达的字符串。结果必须用PGTYPESchar_free()
释放。
PGTYPEStimestamp_current
检索当前的时间戳。
void PGTYPEStimestamp_current(timestamp *ts);
该函数检索当前的时间戳并且将它保存在ts
指向的时间戳变量。
PGTYPEStimestamp_fmt_asc
使用一个格式掩码将一个时间戳变量转换成一个 C char* 。
int PGTYPEStimestamp_fmt_asc(timestamp *ts, char *output, int str_len, char *fmtstr);
该函数接收一个指向时间戳的指针作为它的第一个参数(ts
)、一个指向输出缓冲区的指针(output
)、为输出缓冲区分配的最大长度(str_len
)以及用于转换的格式掩码(fmtstr
)。
成功时,该函数返回 0;如果有错误发生,则返回一个负值。
你可以为格式掩码使用下列格式指示符。格式指示符就是用在libc的strftime
函数中的那一些。任何非格式指示符将被复制到输出缓冲区。
%A
- 被完整的星期几名称的本国表达所替换。
%a
- 被简写星期几名称的本国表达所替换。
%B
- 被完整的月份名称的本国表达所替换。
%b
- 被简写月份名称的本国表达所替换。
%C
- 被十进制数(年份/100)所替换,单一数字会被前置一个零。
%c
- 被时间和日期的本国表达所替换。
%D
- 等效于%m/%d/%y
。
%d
- 被十进制数(01–31)的日所替换。
%E*
%O*
- POSIX 区域扩展。序列 %Ec
%EC
%Ex
%EX
%Ey
%EY
%Od
%Oe
%OH
%OI
%Om
%OM
%OS
%Ou
%OU
%OV
%Ow
%OW
%Oy
被假定提供可供选择的表达。
此外还实现了%OB
来表达可供选择的月份名称(单独使用,不用提过的日)。
%e
- 被十进制数(1–31)的日所替换,单一数字被前置一个空格。
%F
- 等效于%Y-%m-%d
。
%G
- 被替换为一个带有世纪的十进制数年份。这个年份是包含这一周大部分的年份(星期一作为这一周的第一天)。
%g
- 被替换为与%G
中相同的年份,但是作为一个不带世纪的十进制数(00–99)。
%H
- 被替换为一个十进制数的小时(24 小时制,00–23)。
%h
- 和%b
相同。
%I
- 被替换为一个十进制数的小时(12 小时制,01–12)。
%j
- 被替换为一个十进制数的积日(001–366)。
%k
- 被替换为一个十进制数的小时(24 小时制,0–23),单一数字被前置一个空白。
%l
- 被替换为一个十进制数的小时(12 小时制,1–12),单一数字被前置一个空白。
%M
- 被替换为一个十进制数的分钟(00–59)。
%m
- 被替换为一个十进制数的月份(01–12)。
%n
- 被替换为一个新行。
%O*
- 和%E*
相同。
%p
- 根据情况被替换为“午前”或“午后”的本国表达。
%R
- 等效于%H:%M
。
%r
- 等效于%I:%M:%S%p
。
%S
- 被替换为十进制数的秒(00–60)。
%s
- 被替换为从 UTC 新纪元以来的秒数。
%T
- 等效于%H:%M:%S
%t
- 被替换为一个制表符。
%U
- 被替换为十进制数的周数(周日作为一周的第一天,00–53)。
%u
- 被替换为十进制数的星期几(周一作为一周的第一天,1–7)。
%V
- 被替换为十进制数的周数(周一作为一周的第一天,01–53)。如果包含 1 月 1 日的周在新年中有 4 天或更多天,那么它是第一周。否则它是前一年的最后一周,并且下一周是第一周。
%v
- 等效于%e-%b-%Y
。
%W
- 被替换为十进制数的周数(周一作为一周的第一天,00–53)。
%w
- 被替换为十进制数的星期几(0–6,周日作为一周的第一天)。
%X
- 被替换为时间的本国表达。
%x
- 被替换为日期的本国表达。
%Y
- 被替换为十进制数的带世纪的年份。
%y
- 被替换为十进制数的不带世纪的年份(00–99)。
%Z
- 被替换为时区名称。
%z
- 被替换为相对于 UTC 的时区偏移;一个前导的加号表示 UTC 东部,一个负号表示 UTC 西部,接着是分别有两个数字的小时和分钟并且它们之间没有定界符(RFC 822 日期头部的一般形式)。
%+
- 被替换为日期和时间的本国表达。
%-*
- GNU libc 扩展。在执行数值输出时不做任何填充。
$_* - GNU libc 扩展。显式地指定用空格填充。
%0*
- GNU libc 扩展。显式地指定用零填充。
%%
- 被替换为%
。
PGTYPEStimestamp_sub
从一个时间戳中减去另一个时间戳并且把结果保存在一个区间类型的变量中。
int PGTYPEStimestamp_sub(timestamp *ts1, timestamp *ts2, interval *iv);
该函数将从ts1
指向的时间戳变量中减去ts2
指向的时间戳变量,并且将把结果存储在iv
指向的区间变量中。
成功时,该函数返回 0;发生错误时则返回一个负值。
PGTYPEStimestamp_defmt_asc
用一个格式掩码从时间戳的文本表达解析其值。
int PGTYPEStimestamp_defmt_asc(char *str, char *fmt, timestamp *d);
该函数接收一个放在变量str
中的时间戳文本表达以及放在变量fmt
中的要使用的格式掩码。结果将被存放在d
指向的变量中。
如果格式掩码fmt
是NULL,该函数将回退到使用默认的格式掩码%Y-%m-%d %H:%M:%S
。
这是PGTYPEStimestamp_fmt_asc
的逆函数。可能的格式掩码项可以参考那个函数的文档。
PGTYPEStimestamp_add_interval
把一个interval变量加到一个时间戳变量上。
int PGTYPEStimestamp_add_interval(timestamp *tin, interval *span, timestamp *tout);
该函数接收一个指向时间戳变量的指针tin
以及一个指向interval变量的指针span
。它把interval加到时间戳上,然后将结果时间戳保存在tout
指向的变量中。
成功时该函数返回0,如果发生错误则返回一个负值。
PGTYPEStimestamp_sub_interval
从一个时间戳变量中减去一个interval变量。
int PGTYPEStimestamp_sub_interval(timestamp *tin, interval *span, timestamp *tout);
该函数从tin
指向的时间戳变量中减去span
指向的interval变量,然后把结果保存在tout
指向的变量中。
成功时该函数返回0,如果发生错误则返回一个负值。
C 中的区间类型允许你的程序处理 SQL 区间类型的数据。PostgreSQL服务器的等效类型可见第 8.5 节。
下列函数可以用于区间类型:
PGTYPESinterval_new
返回一个指向新分配的区间变量的指针。
interval *PGTYPESinterval_new(void);
PGTYPESinterval_free
释放先前分配的区间变量的内存。
void PGTYPESinterval_free(interval *intvl);
PGTYPESinterval_from_asc
从文本表达解析一个区间。
interval *PGTYPESinterval_from_asc(char *str, char **endptr);
该函数解析输入字符串str
并且返回一个已分配的区间变量的指针。目前 ECPG 总是解析整个字符串并且因此当前不支持把第一个非法字符的地址存储在*endptr
中。你可以安全地把endptr
设置为 NULL。
PGTYPESinterval_to_asc
将一个区间类型的变量转换成它的文本表达。
char *PGTYPESinterval_to_asc(interval *span);
该函数将span
指向的区间变量转换成一个 C char*。输出看起来像这个例子: @ 1 day 12 hours 59 mins 10 secs
。结果必须用PGTYPESchar_free()
释放。
PGTYPESinterval_copy
复制一个区间类型的变量。
int PGTYPESinterval_copy(interval *intvlsrc, interval *intvldest);
该函数将intvlsrc
指向的区间变量复制到intvldest
指向的区间变量。注意你需要现为目标变量分配好内存。
decimal类型和numeric类型相似。不过,它被限制为最大精度是 30 个有效位。与numeric类型只能在堆上创建相反,decimal类型既可以在栈上也可以在堆上创建(使用函数PGTYPESdecimal_new
和PGTYPESdecimal_free
)。在第 35.15 节中描述的 Informix兼容模式中有很多其它函数可以处理decimal类型。
下列函数可以被用于decimal类型并且不仅被包含于libcompat
库中。
PGTYPESdecimal_new
要求一个指向新分配的decimal变量的指针。
decimal *PGTYPESdecimal_new(void);
PGTYPESdecimal_free
释放一个decimal类型,释放它的所有内存。
void PGTYPESdecimal_free(decimal *var);
PGTYPES_NUM_BAD_NUMERIC
一个参数应该包含一个numeric变量(或者指向一个numeric变量),但是实际上它的内存表达非法。
PGTYPES_NUM_OVERFLOW
发生一次溢出。由于numeric类型可以处理几乎任何精度,将一个numeric变量转换成其他类型可能导致溢出。
PGTYPES_NUM_UNDERFLOW
发生一次下溢。由于numeric类型可以处理几乎任何精度,将一个numeric变量转换成其他类型可能导致下溢。
PGTYPES_NUM_DIVIDE_ZERO
尝试了一次除零。
PGTYPES_DATE_BAD_DATE
一个非法的日期字符串被传给了PGTYPESdate_from_asc
函数。
PGTYPES_DATE_ERR_EARGS
非法参数被传给了PGTYPESdate_defmt_asc
函数。
PGTYPES_DATE_ERR_ENOSHORTDATE
PGTYPESdate_defmt_asc
函数在输入字符串中发现了一个非法记号。
PGTYPES_INTVL_BAD_INTERVAL
一个非法的区间字符串被传给了PGTYPESinterval_from_asc
函数,或者一个非法的区间值被传给了PGTYPESinterval_to_asc
函数。
PGTYPES_DATE_ERR_ENOTDMY
在PGTYPESdate_defmt_asc
函数中有日/月/年不匹配的赋值。
PGTYPES_DATE_BAD_DAY
PGTYPESdate_defmt_asc
函数发现了月中的一个非法日值。
PGTYPES_DATE_BAD_MONTH
PGTYPESdate_defmt_asc
函数发现了一个非法的月值。
PGTYPES_TS_BAD_TIMESTAMP
一个非法的时间戳字符串被传给了PGTYPEStimestamp_from_asc
函数,或者一个非法的时间戳值被传给了PGTYPEStimestamp_to_asc
函数。
PGTYPES_TS_ERR_EINFTIME
在一个无法处理无限时间戳值的环境中遇到了这样一个值。
PGTYPESInvalidTimestamp
表示一个非法时间戳的时间戳类型值。在解析错误时,函数PGTYPEStimestamp_from_asc
会返回这个值。注意由于timestamp
数据类型的内部表达,PGTYPESInvalidTimestamp
在同时也是一个合法的时间戳。它被设置为1899-12-31 23:59:59
。为了检测到错误,确认你的应用在每次调用 PGTYPEStimestamp_from_asc
后不仅仅测试PGTYPESInvalidTimestamp
,还应该测试errno != 0
。
备案信息: 粤ICP备15087711号-2
Copyright © 2008-2024 啊嘎哇在线工具箱 All Rights.
本站所有资料来源于网络,版权归原作者所有,仅作学习交流使用,如不慎侵犯了您的权利,请联系我们。