Ignite 3
Edit

Custom SQL Functions

The SQL Engine can extend the SQL functions' set, defined by the ANSI-99 specification, via the addition of custom SQL functions written in Java.

A custom SQL function is just a public or public static method marked by the @QuerySqlFunction annotation.

static class SqlFunctions {
    @QuerySqlFunction
    public static int sqr(int x) {
        return x * x;
    }
}

The class that owns the custom SQL function has to be registered in the CacheConfiguration. To do that, use the setSqlFunctionClasses(…​) method.

// Preparing a cache configuration.
CacheConfiguration cfg = new CacheConfiguration("myCache");

// Registering the class that contains custom SQL functions.
cfg.setSqlFunctionClasses(SqlFunctions.class);

IgniteCache cache = ignite.createCache(cfg);

Once you have deployed a cache with the above configuration, you can call the custom function from within SQL queries:

// Preparing the query that uses the custom defined 'sqr' function.
SqlFieldsQuery query = new SqlFieldsQuery("SELECT name FROM myCache WHERE sqr(size) > 100");

// Executing the query.
cache.query(query).getAll();

Custom SQL function can be a table function. Result of table function is treated as a row set (a table) and can be used by other SQL operators. Custom SQL function is also a public or public static method marked by annotation @QuerySqlTableFunction. Table function must return an Iterable as a row set. Each row can be represented by an Object[] or by a Collection. Row length must match the defined number of column types. Row value types must match the defined column types or be able assigned to them.

static class SqlTableFunctions {
    @QuerySqlTableFunction(columnTypes = {Integer.class, String.class}, columnNames = {"INT_COL", "STR_COL"})
    public static Iterable<Object[]> table_function(int i) {
        return Arrays.asList(
            new Object[] {i, "" + i},
            new Object[] {i * 10, "empty"}
        );
    }
}
CacheConfiguration cfg = new CacheConfiguration("myCache");

cfg.setSqlFunctionClasses(SqlTableFunctions.class);

IgniteCache cache = ignite.createCache(cfg);

SqlFieldsQuery query = new SqlFieldsQuery("SELECT STR_COL FROM TABLE_FUNCTION(10) WHERE INT_COL > 50");

cache.query(query).getAll();

With custom SQL function you can get access to application attributes set on the client side via SessionContext API.

Note
Creating custom functions in the system schema is forbidden. Creating a custom function in schema 'PUBLIC' is forbidden if the function name interferes with a standard function like 'TYPEOF' or 'SUBSTRING'.
Note
The table functions and application attributes are currently available only with Calcite.
Note
With Calcite, a custom SQL function can execute nested SQL queries through Ignite APIs such as SqlFieldsQuery only when the blocking query task executor is enabled with the -DIGNITE_CALCITE_USE_QUERY_BLOCKING_TASK_EXECUTOR=true system property. The default striped query task executor can lead to deadlocks for queries started from user-defined functions.
Note
When nested SQL queries are executed from user-defined functions, configure IgniteConfiguration.QueryThreadPoolSize so it is greater than the maximum number of concurrent queries initiated from UDFs. Otherwise, nested queries can fail because of query thread pool starvation.
Note
Classes registered with CacheConfiguration.setSqlFunctionClasses(…​) must be added to the classpath of all the nodes where the defined custom functions might be executed. Otherwise, you will get a ClassNotFoundException error when trying to execute the custom function.