gavo.adql.ufunctions module

“User” defined functions, i.e., ADQL functions defined only on this system.

See the userFunction docstring on how to use these.

class gavo.adql.ufunctions.HistogramNode(args=(), funName=None)[source]

Bases: FunctionNode

addFieldInfo(context)[source]
class gavo.adql.ufunctions.UserFunction(args=(), funName=None)[source]

Bases: FunctionNode

A node processing user defined functions.

See the userFunction docstring for how ADQL user defined functions are defined.

addFieldInfo(context)[source]
flatten()[source]

returns a string representation of the text content of the tree.

This default implementation will only work if you returned all parsed elements as children. This, in turn, is something you only want to do if you are sure that the node is question will not be morphed.

Otherwise, override it to create an SQL fragment out of the parsed attributes.

type = 'userDefinedFunction'
gavo.adql.ufunctions.userFunction(name, signature, doc, returntype='double precision', unit='', ucd='', polymorphism=(), additionalNames=[], depends=None)[source]

a decorator adding some metadata to python functions to make them suitable as ADQL user defined functions.

name is the name the function will be visible under in ADQL; signature is a signature not including the name of the form ‘(parName1 type1, parName1 type2) -> resulttype’; doc is preformatted ASCII documentation. The indentation of the second line will be removed from all lines.

returntype is the SQL return type, which defaults to double precision. While ADQL 2.0 appears to say that UDFs must be numeric, in practice nobody cares; so, return whatever you see fit.

unit and ucd are optional for when you actually have a good guess what’s coming back from your ufunc. They can also be callable; in that case, they’ll be passed the (annotated) arguments, and whatever they return will be the unit/ucd.

polymorphism, if given, must be a sequence of pairs of (signature, documentation) for alternative signatures of the UDF.

additionalNames, if given, is a list of names the function can also be used as. This is intended for when you started with gavo_somefunc and then want to move on to ivo_somefunc without functional change and want to keep legacy queries working.

depends if non-None, is a name of a postgres function that this UDF needs. This is for when UDF should disappear when an extension is missing. This is not evaluated right away because we do not have a database connection during import. Host code has to arrange for calling cleanForConn(conn).

The python function receives a list of arguments; this will in general be ADQL expression trees. It must return either

  • a string that will go literally into the eventual serialised SQL string (so take care to quote; in general, you will use nodes.flatten(arg) to flatten individual args);

  • or they may return None, in which case the expression tree remains unchanged. This is for when the actual implementation is in the database.

  • or they may raise nodes.ReplaceNode(r), where r is a nodes.ADQLNode

    instance, which then replaces the user defined function in the parse tree and will be annotated as usual.

If you receive bad arguments or something else goes awry, raise a UfuncError.