看PostgreSQL文档:
SELECT EXTRACT(CENTURY FROM TIMESTAMP '2000-12-16 12:21:13');
Result: 20
SELECT EXTRACT(CENTURY FROM TIMESTAMP '2001-02-16 20:38:40');
Result: 21
参数感觉有些诡异,但看起来很智能。
打开psql,并不存在extract这个函数
flying=# \df extract
List of functions
Schema | Name | Result data type | Argument data types | Type
--------+------+------------------+---------------------+------
(0 rows)
flying=#
运行刚才的例子,会发现返回结果的标题是date_part,而不是像正常函数那样标题是函数名本身。
flying=# SELECT EXTRACT(CENTURY FROM TIMESTAMP '2000-12-16 12:21:13');
date_part
-----------
20
(1 row)
flying=#
打开语法引擎gram.y,EXTRACT是一个列名关键字(含义见col_name_keyword注释)
EXTRACT '(' extract_list ')'
{
$$ = (Node *) makeFuncCall(SystemFuncName("date_part"), $3, @1);
}
它是个语法结构而不是一个真正的函数,被语法引擎转换为date_part函数的调用,所以才会出现我们前边所说的没有函数定义,执行结果标题是date_part的现象。这里标题可以用别名封装一下,效果会更真实,但也并没有必要,我们知道可以做到就可以了。
还没说到标识符作参数,下边就是,我们来看 extract_list 定义
extract_list:
extract_arg FROM a_expr
{
$$ = list_make2(makeStringConst($1, @1), $3);
}
| /*EMPTY*/ { $$ = NIL; }
;
/* Allow delimited string Sconst in extract_arg as an SQL extension.
* - thomas 2001-04-12
*/
extract_arg:
IDENT { $$ = $1; }
| YEAR_P { $$ = "year"; }
| MONTH_P { $$ = "month"; }
| DAY_P { $$ = "day"; }
| HOUR_P { $$ = "hour"; }
| MINUTE_P { $$ = "minute"; }
| SECOND_P { $$ = "second"; }
| Sconst { $$ = $1; }
;
从 extract_arg 可以看到,标识符并不是真的传给了函数,跟extract一样,只是语法封装。
想定义Sybase的datepart、dateadd、datediff效果,知道怎么做了吧?
datepart(ms, timestamp value) 用FROM分隔和逗号分隔没什么区别,上篇文章就提到过,gram.y里边也有大把例子。
缺点:定义太多这类语法转义(可能这么叫、错了在心里自行纠正),引入很多关键字,也许不是好事,至少语法部分代码维护要麻烦一些。