Skip to content

Commit

Permalink
fixup! tests
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kharbat authored and kovrus committed Mar 21, 2017
1 parent 80f5af4 commit f7f0aee
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 85 deletions.
207 changes: 122 additions & 85 deletions blackbox/docs/sql/administration/user_defined_functions.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. _sql_administration_udf:

User defined Functions
======================

Expand All @@ -9,54 +11,61 @@ for a full syntax description.

These functions can be created like this::

cr> CREATE FUNCTION subtract(integer, integer)
... RETURNS integer
... LANGUAGE JAVASCRIPT
... AS 'function subtract(a, b) {
... return a - b;
... }';
cr> CREATE FUNCTION subtract(integer, integer)
... RETURNS integer
... LANGUAGE JAVASCRIPT
... AS 'function subtract(a, b) { return a - b; }';
CREATE OK, 1 row affected (... sec)

cr> SELECT subtract(3, 1);
+----------------+
| subtract(3, 1) |
+----------------+
| 2 |
+----------------+
SELECT 1 rows in set (... sec)
.. hide:

cr> _wait_for_function('doc', 'subtract')

cr> SELECT subtract(3, 1);
+----------------+
| subtract(3, 1) |
+----------------+
| 2 |
+----------------+
SELECT 1 row in set (... sec)

``OR REPLACE`` can be used to replace an existing function::

cr> CREATE OR REPLACE FUNCTION log10(long)
... RETURNS double
... LANGUAGE JAVASCRIPT
... AS 'function log10(a) {
... return Math.log10(a);
... }';
cr> CREATE FUNCTION log10(long)
... RETURNS double
... LANGUAGE JAVASCRIPT
... AS 'function log10(a) { return Math.log(a)/Math.log(10); }';
CREATE OK, 1 row affected (... sec)

cr> SELECT log10(10);
+----------------+
| log10(10) |
+----------------+
| 1 |
+----------------+
SELECT 1 rows in set (... sec)

.. NOTE::
.. hide:

cr> _wait_for_function('doc', 'log10')

The function name in the definition must be the same as the name of the
user defined function.
cr> SELECT log10(10);
+----------------+
| log10(10) |
+----------------+
| 1.0 |
+----------------+
SELECT 1 row in set (... sec)

Arguments can be named in the function definition.

For example, if you wanted to name two ``geo_point`` arguments ``start`` and
``end`` you would do it like this::

cr> CREATE OR REPLACE FUNCTION calculate_distance(start geo_point, end geo_point)
... RETURNS float
... LANGUAGE JAVASCRIPT
... AS 'function calculate_distance(start_point, end_point) {
... return Math.sqrt( Math.pow(end_point[0] - start_point[0], 2), Math.pow(end_point[1] - start_point[1], 2));
... }';
cr> CREATE OR REPLACE FUNCTION calculate_distance(start geo_point, end geo_point)
... RETURNS float
... LANGUAGE JAVASCRIPT
... AS 'function calculate_distance(start_point, end_point){
... return Math.sqrt( Math.pow(end_point[0] - start_point[0], 2), Math.pow(end_point[1] - start_point[1], 2));
... }';
CREATE OK, 1 row affected (... sec)

.. hide:

cr> _wait_for_function('doc', 'calculate_distance')

.. NOTE::

Expand All @@ -68,22 +77,25 @@ specified, the function will be created in the current schema.

You can explicitly assign a schema like this::

cr> CREATE FUNCTION my_schema.subtract(long, long)
... RETURNS integer
... LANGUAGE JAVASCRIPT
... AS 'function subtract(a, b) {
... return a - b;
... }';
cr> CREATE FUNCTION my_schema.subtract(long, long)
... RETURNS integer
... LANGUAGE JAVASCRIPT
... AS 'function subtract(a, b) { return a - b; }';
CREATE OK, 1 row affected (... sec)

.. hide:

cr> _wait_for_function('my_schema', 'subtract')

Functions can be accessed from any schema if the full name is provided::

cr> SELECT my_schema.subtract(1, 2);
+-------------------------+
| my_schema.subtract(1, 2)|
+-------------------------+
| -1 |
+-------------------------+
SELECT 1 rows in set (... sec)
cr> SELECT my_schema.subtract(1, 2);
+-------------------------+
| my_schema.subtract(1, 2)|
+-------------------------+
| -1 |
+-------------------------+
SELECT 1 row in set (... sec)


Supported Types
Expand All @@ -104,26 +116,24 @@ data types.
OVERLOADING
-----------

Within a specific schema, you can overload functions by defining two functions
with the same name that have a different set of arguments.
Within a specific schema, you can overload functions by defining two functions with the
same name that have a different set of arguments

This would overload our ``subtract`` function with different argument types::

cr> CREATE FUNCTION my_schema.subtract(long, long)
... RETURNS long
... LANGUAGE JAVASCRIPT
... AS 'function subtract(a, b) {
... return a - b;
... }';
cr> CREATE FUNCTION my_schema.subtract(long, long)
... RETURNS long
... LANGUAGE JAVASCRIPT
... AS 'function subtract(a, b) { return a - b; }';
CREATE OK, 1 row affected (... sec)

This would overload our ``subtract`` function with more arguments::

cr> CREATE FUNCTION my_schema.subtract(long, long, long)
... RETURNS long
... LANGUAGE JAVASCRIPT
... AS 'function subtract(a, b, c) {
... return a - b - c;
... }';
cr> CREATE FUNCTION my_schema.subtract(long, long, long)
... RETURNS long
... LANGUAGE JAVASCRIPT
... AS 'function subtract(a, b, c) { return a - b - c; }';
CREATE OK, 1 row affected (... sec)

.. NOTE::

Expand Down Expand Up @@ -153,41 +163,68 @@ The current version of CrateDB supports ECMAScript 5.1.
Supported Types
...............

If a user-defined function specifies ``geo_point`` or ``ARRAY`` as a return
type, then the JavaScript function should return an ``Array``::
JavaScript user-defined functions can handle all CrateDB data types, but

cr> CREATE FUNCTION rotate_point(point geo_point, angle float)
If a user-defined function requires ``geo_point`` as a return type, then the
JavaScript function must return either a ``double array`` of size 2 or
a ``WKT String``, or a ``GeoJson``.

Here is an example of a JavaScript function returning a ``double array``::


cr> CREATE FUNCTION rotate_point(point geo_point, angle float)
... RETURNS geo_point
... LANGUAGE JAVASCRIPT
... AS 'function rotate_point(point, angle) {
... var cos = Math.cos(angle);
... var sin = Math.sin(angle);
... var x = cos * point[0] - sin * point[1];
... var y = sin * point[0] + cos * point[1];
... return [x, y];
... }';
CREATE OK, 1 row affected (... sec)

Here is an example of a JavaScript function returning a ``GeoJson``::


cr> CREATE OR REPLACE FUNCTION rotate_point(point geo_point, angle float)
... RETURNS geo_point
... LANGUAGE JAVASCRIPT
... AS 'function rotate_point(point, angle) {
... var cos = Math.cos(angle);
... var sin = Math.sin(angle);
... var x = cos * point[0] - sin * point[1];
... var y = sin * point[0] + cos * point[1];
... return { "type": "Point", "coordinates": [x, y] };
... }';
CREATE OK, 1 row affected (... sec)

Below is an example of a JavaScript function returning ``WKT String``,
which will be casted into a ``geo_point``::


cr> CREATE FUNCTION symmetric_point(point geo_point)
... RETURNS geo_point
... LANGUAGE JAVASCRIPT
... AS 'function rotate_point(point, angle) {
... var cos = Math.cos(angle),
... sin = Math.sin(angle),
... x = cos * point[0] - sin * point[1],
... y = sin * point[0] + cos * point[1];
... return [x, y];
... AS 'function(point, angle) {
... var x = - point[0],
... y = - point[1];
... return "POINT (\" + x + \", \" + y +\")";
... }';
CREATE OK, 1 row affected (... sec)

Similarly, if the function specifies ``geo_shape`` or ``object``
as a return type, then the JavaScript function should return
an ``object`` or a ``GeoJson``::

Similarly, if the function specifies ``geo_shape`` or ``object`` as a return
type, then the JavaScript function should return an ``object``::

cr> CREATE FUNCTION point_object(point geo_point)
... RETURNS object
... LANGUAGE JAVASCRIPT
... AS 'function point_object(point) {
... return {'lon': point[0], 'lat': point[1]};
... }';

Furthermore, if the javascript function returns a ``WKT String``, it will be
cast into the corresponding return type ::

cr> CREATE FUNCTION symmetric_point(point geo_point)
... RETURNS geo_point
... LANGUAGE JAVASCRIPT
... AS 'function symmetric_point(point, angle) {
... var x = - point[0],
... y = - point[1];
... return \"POINT (\" + x + \", \" + y +\"; }\";
... }';
CREATE OK, 1 row affected (... sec)

.. NOTE::

Expand Down
14 changes: 14 additions & 0 deletions blackbox/docs/src/crate/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,17 @@ def wait_for_schema_update(schema, table, column):
(schema, table, column))
count = c.fetchone()[0]

def wait_for_function(schema, name):
conn = connect('localhost:' + str(CRATE_HTTP_PORT))
c = conn.cursor()
while True:
c.execute(('select count(*) from information_schema.routines '
'where routine_schema = ? and routine_name = ? '
'and routine_type = ?'),
(schema, name, 'FUNCTION'))
if int(c.fetchone()[0]) != 0:
break


def bash_transform(s):
# The examples in the docs show the real port '4200' to a reader.
Expand Down Expand Up @@ -314,6 +325,8 @@ def tearDownCountries(test):
def setUpLocationsAndQuotes(test):
setUpLocations(test)
setUpQuotes(test)
test.globs['wait_for_function'] = wait_for_function


def tearDownLocationsAndQuotes(test):
tearDownLocations(test)
Expand Down Expand Up @@ -383,6 +396,7 @@ def setUpTutorials(test):
def setUp(test):
test.globs['cmd'] = cmd
test.globs['wait_for_schema_update'] = wait_for_schema_update
test.globs['wait_for_function'] = wait_for_function



Expand Down

0 comments on commit f7f0aee

Please sign in to comment.