CQL支持两大类功能:
出于安全问题的考虑,默认情况下用户自定义函数是被禁止的(即使启用了,用户自定义函数的执行也是沙盒化执行并且恶意方法不被允许执行,但是没有沙盒是完美的,所以用户自定义方法是选择加入的)。请参见enable_user_defined_functionsin cassandra.yaml以启用它们。
函数通过其名称标识:
function_name ::= [keyspace_name
'.' ]name
cast函数可用于将一种本地数据类型转换为另一种数据类型。
下表描述了cast函数支持的转换。Cassandra将默认忽略任何将数据类型转换为其自己的数据类型的转换。
From | To |
---|---|
ascii |
text , varchar |
bigint |
tinyint , smallint , int ,float ,double , decimal ,varint ,text ,varchar |
boolean |
text , varchar |
counter |
tinyint , smallint , int ,bigint ,float , double ,decimal ,varint ,text ,varchar |
date |
timestamp |
decimal |
tinyint , smallint , int ,bigint ,float , double ,varint ,text ,varchar |
double |
tinyint , smallint , int ,bigint ,float , decimal ,varint ,text ,varchar |
float |
tinyint , smallint , int ,bigint ,double , decimal ,varint ,text ,varchar |
inet |
text , varchar |
int |
tinyint , smallint , bigint ,float ,double , decimal ,varint ,text ,varchar |
smallint |
tinyint , int , bigint ,float ,double , decimal ,varint ,text ,varchar |
time |
text , varchar |
timestamp |
date , text , varchar |
timeuuid |
timestamp , date , text ,varchar |
tinyint |
tinyint , smallint , int ,bigint ,float , double ,decimal ,varint ,text ,varchar |
uuid |
text , varchar |
varint |
tinyint , smallint , int ,bigint ,float , double ,decimal ,text ,varchar |
转换严格依赖于Java的语义。例如,double值1将被转换为文本值'1.0'。例如:
SELECT avg(cast(count as double)) FROM myTable
token函数允许计算给定分区键的token。token函数的确切签名取决于有关的表和集群使用的分区器。
token的参数类型取决于分区键列的类型。返回类型取决于正在使用的分区器:
例如,在使用默认Murmur3Partitioner的集群中,如果表定义如下:
CREATE TABLE users (
userid text PRIMARY KEY,
username text,
)
那么token函数将采用类型为text的单个参数(在这种情况下,分区键是userid(没有聚集列,因此分区键与主键相同)),返回类型将是bigint。
uuid函数不使用参数,并生成适用于INSERT或UPDATE语句的随机类型4 uuid。
now
now函数不使用参数,并且在协调器节点上生成新的唯一timeuuid(在使用它的语句被执行的时候)。注意,这个方法对插入是有用的,但在WHERE子句中很大程度上是无意义的。例如,以下形式的查询:
SELECT * FROM myTable WHERE t = now()
将不会返回任何设计结果,因为now()返回的值保证是唯一的。
minTimeuuid
andmaxTimeuuid
minTimeuuid(resp.maxTimeuuid)函数采用时间戳值t(其可以是时间戳或日期字符串<timestamps>),并返回与具有时间戳t的最小(最大)可能时间戳相对应的伪时间戳。例如:
SELECT * FROM myTable
WHERE t > maxTimeuuid('2013-01-01 00:05+0000')
AND t < minTimeuuid('2013-02-02 10:00+0000')
将选择timeuuid列t严格晚于'2013-01-01 00:05 + 0000'但严格早于'2013-02-02 10:00 + 0000'的所有行。请注意,t> = maxTimeuuid('2013-01-01 00:05 + 0000')仍然不会选择正好在'2013-01-01 00:05 + 0000'生成的时间流,并且基本上等于t> maxTimeuuid('2013-01-01 00:05 + 0000')。
提供了许多函数来将时间符,时间戳或日期“转换”成另一种本地类型。
函数名词 | 输入类型 | Description |
---|---|---|
toDate |
timeuuid |
将timeuuid参数转换为日期类型 |
toDate |
timestamp |
将时间戳参数转换为日期类型 |
toTimestamp |
timeuuid |
将timeuuid参数转换为时间戳类型 |
toTimestamp |
date |
将date参数转换为时间戳类型 |
toUnixTimestamp |
timeuuid |
将timeuuid参数转换为bigInt原始值 |
toUnixTimestamp |
timestamp |
将时间戳参数转换为bigInt原始值 |
toUnixTimestamp |
date |
将date参数转换为bigInt原始值 |
dateOf |
timeuuid |
类似于toTimestamp(timeuuid) |
unixTimestampOf |
timeuuid |
类似于toUnixTimestamp(timeuuid) |
CREATE FUNCTION sample ( arg int ) ...;
CREATE FUNCTION sample ( arg text ) ...;
用户自定义函数易受所选择的编程语言的普遍问题的影响。 因此,实现应该对空指针异常,非法参数或任何其他潜在的异常源是安全的。 在函数执行期间的异常将导致整个语句失败。
使用复杂类型(如集合,元组类型和用户定义的类型)作为参数和返回类型是有效的。元组类型和用户定义的类型由DataStax Java驱动程序的转换函数处理。有关处理元组类型和用户定义类型的详细信息,请参阅Java驱动程序的文档。
函数的参数可以是字面量或term。也可以使用准备语句的占位符。
您可以使用双引号字符串语法来包含UDF源代码。例如:
CREATE FUNCTION some_function ( arg int )
RETURNS NULL ON NULL INPUT
RETURNS int
LANGUAGE java
AS $$ return arg; $$;
SELECT some_function(column) FROM atable ...;
UPDATE atable SET col = some_function(?) ...;
CREATE TYPE custom_type (txt text, i int);
CREATE FUNCTION fct_using_udt ( udtarg frozen )
RETURNS NULL ON NULL INPUT
RETURNS text
LANGUAGE java
AS $$ return udtarg.getString("txt"); $$;
用户自定义函数可以在SELECT,INSERT和UPDATE语句中使用。
隐式可用的UDFContext字段(或对脚本UDF的绑定)提供了创建新UDT和元组值所必需的功能:
CREATE TYPE custom_type (txt text, i int);
CREATE FUNCTION fct\_using\_udt ( somearg int )
RETURNS NULL ON NULL INPUT
RETURNS custom_type
LANGUAGE java
AS $$
UDTValue udt = udfContext.newReturnUDTValue();
udt.setString("txt", "some string");
udt.setInt("i", 42);
return udt;
$$;
UDFContext接口的定义可以在org.apache.cassandra.cql3.functions.UDFContext的Apache Cassandra源代码中找到。
public interface UDFContext
{
UDTValue newArgUDTValue(String argName);
UDTValue newArgUDTValue(int argNum);
UDTValue newReturnUDTValue();
UDTValue newUDTValue(String udtName);
TupleValue newArgTupleValue(String argName);
TupleValue newArgTupleValue(int argNum);
TupleValue newReturnTupleValue();
TupleValue newTupleValue(String cqlDefinition);
}
Java UDF对已定义的公共接口和类已经有一些导入。这些导入是:
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.cassandra.cql3.functions.UDFContext;
import com.datastax.driver.core.TypeCodec;
import com.datastax.driver.core.TupleValue;
import com.datastax.driver.core.UDTValue;
这些便利的导入不适用于UDF脚本。
创建新的用户自定义函数使用CREATE FUNCTION语句:
create_function_statement ::= CREATE [ OR REPLACE ] FUNCTION [ IF NOT EXISTS]function_name
'('arguments_declaration
')' [ CALLED | RETURNS NULL ] ON NULL INPUT RETURNScql_type
LANGUAGEidentifier
ASstring
arguments_declaration ::=identifier
cql_type
( ','identifier
cql_type
)*
例如:
CREATE OR REPLACE FUNCTION somefunction(somearg int, anotherarg text, complexarg frozen<someUDT>, listarg list)
RETURNS NULL ON NULL INPUT
RETURNS text
LANGUAGE java
AS $$
// some Java code
$$;
CREATE FUNCTION IF NOT EXISTS akeyspace.fname(someArg int)
CALLED ON NULL INPUT
RETURNS text
LANGUAGE java
AS $$
// some Java code
$$;
CREATE FUNCTION与可选的OR REPLACE关键字创建一个函数或替换具有相同签名的现有函数。如果具有相同签名的函数已经存在,则无OR REPLACE的CREATE FUNCTION将失败。
如果使用可选的IF NOT EXISTS关键字,则只有具有相同签名的另一个函数不存在时,才会创建函数。
OR REPLACE和IF NOT EXISTS不能一起使用。
必须为每个函数定义使用空值调用的行为。有两个选项:
RETURNS NULL ON NULL INPUT声明如果任何输入参数为null,函数将返回null。
CALLED ON NULL INPUT声明函数将总是被执行。签名用于区分各个功能。签名包括:
键空间名称,函数名称和参数类型受默认命名约定和大小写敏感度规则的约束。
删除函数使用DROP FUNCTION语句:
drop_function_statement ::= DROP FUNCTION [ IF EXISTS ]function_name
[ '('arguments_signature
')' ] arguments_signature ::=cql_type
( ','cql_type
)*
例如:
DROP FUNCTION myfunction;
DROP FUNCTION mykeyspace.afunction;
DROP FUNCTION afunction ( int );
DROP FUNCTION afunction ( text );
如果存在具有相同名称但具有不同签名(重载函数)的多个函数,则必须指定要删除的函数的参数类型(arguments_signature)。
使用DROP FUNCTION和可选的IF EXISTS关键字删除一个已存在的函数,如果该函数不存在也不会抛出异常。
聚合函数处理一组行。 它们接收每行的值,并为整个集合返回一个值。
如果正常列,标量函数,UDT字段,writetime或ttl与聚合函数一起选择,则为它们返回的值将是与查询匹配的第一行的值。
count函数可用于计算查询返回的行。例:
SELECT COUNT (*) FROM plays;
SELECT COUNT (1) FROM plays;
它也可以用于计数给定列的非空值:
SELECT COUNT (scores) FROM plays;
max和min函数可用于计算查询对给定列返回的最大值和最小值。例如:
SELECT MIN (players), MAX (players) FROM plays WHERE game = 'quake';
sum函数可用于对给定列的查询返回的所有值进行求和。例如:
SELECT SUM (players) FROM plays;
avg函数可用于计算查询为给定列返回的所有值的平均值。例如:
SELECT AVG (players) FROM plays;
用户自定义的聚合允许创建自定义聚合函数。 聚合函数的常见示例为count,min和max。
每个聚合需要类型为STYPE的初始状态(INITCOND,默认为null)。状态函数的第一个参数必须具有类型STYPE。状态函数的其余参数必须与用户定义的聚合参数的类型匹配。状态函数对每一行调用一次,状态函数返回的值变为新的状态。在处理所有行之后,以最后状态值作为其参数来执行可选的FINALFUNC。
STYPE是强制的,以便能够区分可能的状态和/或finalfunction的重载版本(因为过载可以在聚合创建之后出现)。
用户定义的聚合可以在SELECT语句中使用。
用户定义聚合的完整工作示例(假定已使用USE语句选择了键空间):
CREATE OR REPLACE FUNCTION averageState(state tuple<int,bigint>, val int)
CALLED ON NULL INPUT
RETURNS tuple
LANGUAGE java
AS $$
if (val != null) {
state.setInt(0, state.getInt(0)+1);
state.setLong(1, state.getLong(1)+val.intValue());
}
return state;
$$;
CREATE OR REPLACE FUNCTION averageFinal (state tuple<int,bigint>)
CALLED ON NULL INPUT
RETURNS double
LANGUAGE java
AS $$
double r = 0;
if (state.getInt(0) == 0) return null;
r = state.getLong(1);
r /= state.getInt(0);
return Double.valueOf(r);
$$;
CREATE OR REPLACE AGGREGATE average(int)
SFUNC averageState
STYPE tuple
FINALFUNC averageFinal
INITCOND (0, 0);
CREATE TABLE atable (
pk int PRIMARY KEY,
val int
);
INSERT INTO atable (pk, val) VALUES (1,1);
INSERT INTO atable (pk, val) VALUES (2,2);
INSERT INTO atable (pk, val) VALUES (3,3);
INSERT INTO atable (pk, val) VALUES (4,4);
SELECT average(val) FROM atable;
创建(或替换)用户定义的聚合函数使用CREATE AGGREGATE语句:
create_aggregate_statement ::= CREATE [ OR REPLACE ] AGGREGATE [ IF NOT EXISTS ]function_name
'('arguments_signature
')' SFUNCfunction_name
STYPEcql_type
[ FINALFUNCfunction_name
] [ INITCONDterm
]
参见上面的一个完整的例子。
使用可选的OR REPLACE关键字创建AGGREGATE可创建聚合或替换具有相同签名的现有聚合。如果具有相同签名的聚合已存在,则无OR REPLACE的CREATE AGGREGATE将失败。
使用可选的IF NOT EXISTS关键字创建AGGREGATE可以创建聚合(如果它不存在)。
OR REPLACE和IF NOT EXISTS不能一起使用。
STYPE定义状态值的类型,必须指定。
可选的INITCOND定义聚合的初始状态值。它默认为null。必须为使用RETURNS NULL ON NULL INPUT声明的状态函数指定非空INITCOND。
SFUNC引用现有函数作为状态修改函数。状态函数的第一个参数的类型必须与STYPE匹配。状态函数的其余参数类型必须与聚合函数的参数类型相匹配。对于使用RETURNS NULL ON NULL INPUT声明并且使用null调用的状态函数,不会更新状态。
可选的FINALFUNC在返回聚合结果之前调用。它必须只有一个类型为STYPE的参数。FINALFUNC的返回类型可以是不同类型。使用RETURNS NULL ON NULL INPUT声明的最终函数意味着如果最后一个状态为null,则聚合的返回值将为null。
如果未定义FINALFUNC,则聚合函数的返回类型总为STYPE。如果定义了FINALFUNC,则是该函数的返回类型。
删除用户定义的聚合函数使用DROP AGGREGATE语句:
drop_aggregate_statement ::= DROP AGGREGATE [ IF EXISTS ]function_name
[ '('arguments_signature
')' ]
例如:
DROP AGGREGATE myAggregate;
DROP AGGREGATE myKeyspace.anAggregate;
DROP AGGREGATE someAggregate ( int );
DROP AGGREGATE someAggregate ( text );
DROP AGGREGATE语句删除使用CREATE AGGREGATE创建的聚合。如果有多个具有相同名称但具有不同签名的聚合(重载聚合),则必须指定要删除的聚合的参数类型。
DROP AGGREGATE使用可选的IF EXISTS关键字删除聚合(如果存在),如果具有签名的函数不存在,则不执行任何操作。