HTSQL Functions and Operators

Preliminaries

We need to decide on the names and signatures of the HTSQL functions. Here is the list of HTSQL functions and operators together with their SQL/PostgreSQL definitions. We will also give their counterparts in other languages, like Python and Javascript.

There are a number of requirements for HTSQL functions:

  • the name and the signature of a function should be plain and clear. SQL functions rarely possess these qualities, that's why we should also take a look to similar functions in Python and Javascript land.
  • a function or an operator must be implementable in SQL with all the function arguments being evaluated only once.

Domains

In HTSQL, types are called domains.

An HTSQL function accepts some (maybe none) arguments of specific domains and produces a value of another domain.

There is also another kind of functions, called macros, which transform the syntax tree. The difference between ordinary functions and macros is that a function evaluates the syntax nodes passed as arguments into code objects first, then processes the code objects. Each code object has a domain. A macro does not convert the arguments into code objects, it operates on the syntax tree directly. The effect of this is that it does not make sense to talk about a macro argument domain.

The following domains are defined in HTSQL:

domains.Boolean
represents SQL's BOOLEAN.
domains.Numeric
represents SQL's INTEGER, DECIMAL and FLOAT.
domains.String
represents SQL's CHAR, VARCHAR and TEXT.
domains.Binary
represents SQL's BLOB.
domains.BitString
represents SQL's BIT and VARBIT.
domains.Date
represents SQL's DATE.
domains.Time
represents SQL's TIME.
domains.DateTime
represents SQL's TIMESTAMP.
domains.TimeDelta
represents SQL's INTERVAL.
domains.Array
represents SQL's ARRAY.
domains.Composite
represents SQL composite data types.
domains.Unknown
represents any other SQL data type, which HTSQL does not support directly.
domains.Null
the result domain of the HTSQL function null(). A column domain could not be Null.
domains.Tuple
represents the type of multicolumn values, such as those produced by SELECT statements and by HTSQL's select() commands. It is also the domain of the codes.Table objects.

The names of the domains mostly borrowed from Python.

Operators

The following operators are defined in HTSQL:

    &       |       !
    =       ==      !=      !==
    <       <=      >       >=
    ~       ~=      !~      !~=
    +       -       *       /
    div     mod

In HTSQL, operators are functions defined in the htsql:operator namespace. That is, 2+2 is equivalent to htsql:operator:"+"(2,2). Ordinary functions and macros are defined in the htsql namespace.

List of HTSQL Macros, Functions and Operators

NULL-related functions and operators

Function HTSQL SQL Javascript Python
The NULL constant null() value is NULL null None

Signature: htsql:null() -> Null

In Javascript, there are two constants of null-ish kind: null and undefined.


Function HTSQL SQL Javascript Python
Check if the value is NULL is_null(value) value IS NULL value === null value is None

Signature: htsql:is_null(Any value) -> Boolean

There are several alternative names for the HTSQL function:

  • is_null(value)
  • isnull(value)
  • value=null() (it's not clear if it could work)

The SQL expression value IS NOT NULL is transformed to HTSQL as !is_null(value).

Note that in Javascript, value == null is also true if value is undefined.


Function HTSQL SQL Javascript Python
Replace a NULL value ??? COALESCE(value, null_replacement) -- --

Does this function belong to HTSQL? If so, should be retain the name COALESCE (it sounds a bit odd)?


Function HTSQL SQL Javascript Python
Return the first non-NULL argument ??? COALESCE(value1, value2, ...) -- --

The same question: do we leave this function in HTSQL and under what name?

Boolean functions and operators

Function HTSQL SQL Javascript Python
The FALSE constant false() FALSE false False
The TRUE constant true() TRUE true True

Signatures:

  • htsql:false() -> Boolean
  • htsql:true() -> Boolean

Function HTSQL SQL Javascript Python
Check if the value is FALSE is_false(value) value IS FALSE value === false value is False
Check if the value is TRUE is_true(value) value IS TRUE value === true value is True

Signatures:

  • htsql:is_false(Boolean value) -> Boolean
  • htsql:is_true(Boolean value) -> Boolean

The following table indicates the difference between the functions is_false(value) and is_true(value) and the expressions value == false() and value == true():

Expression / Value NULL FALSE TRUE
is_null(value) TRUE FALSE FALSE
value = null() NULL NULL NULL
is_false(value) FALSE TRUE FALSE
value = false() NULL TRUE FALSE
is_true(value) FALSE FALSE TRUE
value = true() NULL FALSE TRUE

Note that the functions is_null(value), is_false(value) and is_true(value) never produces a NULL value.

The SQL expressions value IS NOT FALSE and value IS NOT TRUE are converted to HTSQL as !is_false(value) and !is_true(value).


Function HTSQL SQL Javascript Python
Cast to Boolean boolean(value) -- Boolean(value) bool(value)

Signature: htsql:boolean(Any value) -> Any

A question: Should we stick to full or abbreviated function names? That is, is it boolean(value) or bool(value)?

Note that the Boolean cast is often performed implicitly.

SQL supports some form of Boolean cast, but we do not follow it.

The cast is performed according to the following rule:

  • A value of the Boolean domain is passed intact, including a NULL value.
  • Otherwise, NULL, 0, 0.0, '', binary(''), bitstring(''), timedelta('00:00:00'), array() are converted to FALSE.
  • All the other values are converted to TRUE.

In HTSQL, the way a value is converted to Boolean depends on the value domain. The convertion is done according to the following table:

Domain Values converted to FALSE Values converted to TRUE Values converted to NULL
Boolean FALSE TRUE NULL
Numeric NULL, 0, 0.0 all the others none
String NULL, '' all the others none
Binary NULL, E'' all the others none
BitString NULL, B'' all the others none
Date NULL all the others none
Time NULL all the others none
DateTime NULL all the others none
TimeDelta NULL, INTERVAL '00:00:00' all the others none
Array NULL, ARRAY[] all the others none
Composite NULL all the others none
Unknown NULL all the others none
Null NULL none none

Note that is_null(boolean(value)) is true if and only if the domain of value is Boolean and the value itself is NULL.

In Javascript, 0, null, false, NaN, undefined, and the empty string ("") are converted to false. All the other values are converted to true.

In Python, None, 0, False, the empty string(""), the empty list ([]) and other values that could be considered "empty" are converted to False. All the other values are converted to True.


Function HTSQL SQL Javascript Python
Boolean OR value1 | value2 | ... value1 OR value2 OR ... value1 || value2 || ... value1 or value2 or ...
Boolean AND value1 & value2 & ... value1 AND value2 AND ... value1 && value2 && ... value1 and value2 and ...
Boolean NOT !value NOT value !value not value

Signatures:

  • htsql:operator:"|"(Any1 value1, Any2 value2, ...) -> Boolean
  • htsql:operator:"&"(Any1 value1, Any2 value2, ...) -> Boolean
  • htsql:operator:"!"(Any value) -> Boolean

The arguments of a Boolean operation are converted to Boolean using the htsql:boolean cast before the operation is applied.

The operations follow the SQL rules for evaluation of Boolean operations:

value1 value2 value1 | value2 value1 & value2
TRUE TRUE TRUE TRUE
TRUE FALSE TRUE FALSE
TRUE NULL TRUE NULL
FALSE FALSE FALSE FALSE
FALSE NULL NULL FALSE
NULL NULL NULL NULL

and

value !value
TRUE FALSE
FALSE TRUE
NULL NULL

Note that since the Boolean cast is applied to the arguments first, the value of a Boolean operation with NULL arguments depends on the domain of the arguments.

For instance, consider two HTSQL expressions:

  • !employee.is_contractor
  • !employee.hourly_rate

Suppose that the domains of the is_contractor and hourly_rate fields are Boolean and Numeric respectively. Moreover, suppose that both is_contractor and hourly_rate are NULL. For these expressions, the value of the former is NULL while the value of the latter is TRUE.

According to SQL rules, NOT NULL is equal to NULL, that is why !employee.is_contractor is evaluated to NULL. However, an implicit Numeric to Boolean cast is performed for a Numeric value (!boolean(employee.hourly_rate)) which converts the NULL value to FALSE. Then NOT FALSE is evaluated to TRUE.