CREATE FUNCTION (TVF)
Creates a user-defined table-valued function (TVF). A TVF is a callable routine that accepts input parameters, executes a single
SELECT statement in the function body, and returns a single table-type value (similar to a view).
CREATE [OR REPLACE] FUNCTION function_name ( [parameter_list] ) RETURNS TABLE AS RETURN function_body ; parameter_list: variable_name data_type [data_type_modifier] [, ...] data_type_modifier: DEFAULT default_value | NOT NULL | NULL | COLLATE collation_name
If specified, replaces a TVF if one already exists with the same name.
The name of the function. Function names must be unique within a database, and cannot be duplicates of names for other TVFs, tables, views, user-defined functions (UDFs), user-defined aggregate functions (UDAFs), or stored procedures.
You can also specify
function_name together by replacing
database_name.function_name instead of defaulting to the current context database. For example, you can write the following:
CREATE FUNCTION db.some_func(a int) ...
Table Valued Function names are case-sensitive. For details on case-sensitivity, refer to the Database Object Case-Sensitivity topic.
Input parameters are optional. Any number of input parameters can be specified, and each must be delimited by a comma (
,). Each input parameter must be given a unique identifier name within the scope of the function.
The following example shows how to declare a single input parameter:
CREATE FUNCTION single_param_example(a INT) ...
The following example demonstrates how to declare more than one input parameter:
CREATE FUNCTION multi_param_example(a INT, b VARCHAR(255), c DECIMAL(19,4)) ...
Only scalar data types are allowed for TVF input parameters, and each valid type is enumerated in the syntax block above. Non-scalar types, such as
RECORD, cannot be declared as input parameters for TVFs.
Default values can be specified for input parameters by using the
DEFAULT constraint. Consider the following example:
CREATE FUNCTION default_example(a INT DEFAULT 5) ...
Input parameters can also specify data type modifiers, namely
COLLATE. Consider the following example:
CREATE FUNCTION modifier_example(a TEXT NOT NULL COLLATE utf8_bin) ...
Any scalar-valued data type as described in the Data Types topic. Non-scalar valued types are not allowed in TVFs, including
The function body of a TVF may contain any valid
Table-valued functions (TVFs) in MemSQL provide a mechanism to return a result set from a single user-defined
SELECT statement, much like a view. Unlike views, however, TVFs accept scalar-type input parameters that can be used inside the function body. Consider the following example TVF, which accepts a
DECIMAL input type and returns the items in a store’s inventory that match the desired price:
CREATE FUNCTION inventory_with_price(price DECIMAL(19,4)) RETURNS TABLE AS RETURN SELECT * FROM store_inventory WHERE item_price = price;
This TVF specifies an input parameter named
price, which is used to query the
store_inventory table and find all items of the specified price. The function is executed in the following way:
SELECT * FROM inventory_with_price(1.9900);
inventory_with_price function has been created, it can be executed with different
DECIMAL input values to query the
store_inventory table in a dynamic, reusable manner.
TVFs can also reference other TVFs in the function body. When a referenced TVF is executed inside the function body of a TVF, the result set from the referenced TVF can be queried like a table. Consider the following example where
CREATE FUNCTION tvf_1(a INT) RETURNS TABLE AS RETURN SELECT * FROM store_inventory LIMIT a; CREATE FUNCTION tvf_2() RETURNS TABLE AS RETURN SELECT * FROM tvf_1(10) GROUP BY item_price ORDER BY item_price LIMIT 10;
In the example above, a table named
store_inventory contains a
item_price column. The
tvf_1 function is referenced in
tvf_2 and its logical result set is queried as a table type.
Instead of copying/pasting TVFs, you can define a TVF in a
.sql file and execute it. The following example shows how to execute TVFs in a
cat userFile.sql **** USE db1; CREATE OR REPLACE FUNCTION tvf_2(num INT) RETURNS TABLE AS RETURN SELECT * FROM stock LIMIT num; SELECT * FROM tvf_2();
memsql < userFile.sql
memsql < userFile.sql runs all the commands in the
.sql file. The
memsql-client package is required to run this command.
MySQL Client Delimiters
When creating a TVF using a MySQL-compatible client connected to MemSQL, you must change the client delimiter to ensure that the function definition is correctly passed to the server and then set it back to a semicolon after the alternate delimiter is no longer needed. See the MySQL Client Delimiters topic for details on MySQL client delimiters.
Security and Permissions
TVFs in MemSQL use the Definer Security Model. The TVF’s definer must have the permissions to execute the
SELECT statement that makes up the TVF’s function body. The invoker of a TVF must have
EXECUTE permissions on the TVF. Also, the TVF’s definer must have
EXECUTE permissions on any TVFs used in the function’s body.
TVFs are limited in the following ways:
SELECT Statement Limitations
TVFs may only contain a single
SELECT statement; any other DML or DDL statement in the TVF function body is invalid. Multiple
SELECT statements are currently not supported.
Unique Column Names
Each column in a TVF’s logical result set must have a unique name. Duplicate column names are invalid, and will result in an error.
Scalar Input Parameters
TVF input parameters may only be scalar value types, such as
VARCHAR, and so on. UDF-specific data types such as
RECORD cannot be used as input parameter types.
Self-Calling (Recursive Calls)
While a TVF can reference other TVFs in the function body, a TVF may not call itself, directly or indirectly.
Unlike UDFs, TVFs may only be executed within the scope of the database in which they are created. Cross-database TVF execution is not supported. Additionally, referenced TVFs in a TVF function body cannot execute TVFs in another database. For example, the following TVF is invalid:
CREATE FUNCTION cross_database_invalid() RETURNS TABLE AS RETURN SELECT * FROM otherdb.other_tvf();