Generic syntax of HTSQL query is described in following syntax diagrams. Refer to How to read syntax diagrams section to learn understanding them.
query (description):
[ credentials_clause ]
{ [ command_call ]... |
path_clause [ command_call ]... [ filter_clause ] }
( credentials_clause - command_call - path_clause - filter_clause )
credentials_clause:
"/~" perspective
path_clause:
"/" tree_clause [";" "/" tree_clause ]...
( tree_clause )
tree_clause (description):
segment_clause [ "/" segment_clause ]... [ "(" tree_clause [ ";" tree_clause ]... ")" ]
( segment_clause )
segment_clause (description):
[ "*" ]
[ table_qualifier [ locator_clause ] ]
[ selector_clause ]
[ filter_clause ]
( locator_clause - selector_clause - filter_clause )
selector_clause (description):
"{" selection [ "," selection ]... "}"
( selection )
selection (description):
[ expression ]
{ [ { "+" | "-" } ] [ "^" ] |
selector_clause [ { "+" | "-" } ] [ "^" ] [ filter_clause ] }
( selector_clause - filter_clause )
filter_clause (description):
"?" { condition | assignment } [ "&" assignment ]...
( assignment )
locator_clause (description):
"[" location [ "," location ]... [ ";" tag ] "]"
( location )
location (description):
label [ "." label ]...
( label )
label (description):
{ "*" | literal | sub_locator_clause | variable }
sublocator_clause (description):
{ locator_clause |
"(" location [ "," location ]... [ ";" tag ] ")"
( location )
command_call (description):
{ "/" command "(" [ argument_list ] ")" |
"." command [ "(" argument_list ")" ] }
( argument_list )
argument_list (description):
[ argument [ "," argument ]... ] [ name "=" argument [ name "=" argument ]... ]
( argument )
argument:
{ constant | query }
( query )
tree_clause(s) define database objects and structures, which commands in commands_clause are applyed to. If more than one tree_clause is specified, more than one dataset is passed to the specified commands.
If more than one tree_clauses are specified, the filter_clause relates only to the last tree. This way filter_clause on the top level is syntactical equivalent to filter_clause within the top segment of the last tree. This is shown in example:
/organization;/project/select()?start_date !== null()
is equivalent for
/organization;/project?start_date !== null()/select()
Tree is a set of consecutive segment declarations with possible branching on the bottom level.
Consecutive segments mean, that context tables of all these segments are linked with each other with foregin key references, and HTSQL for each row of separate segment will return all linked rows of nextcoming segments in hierarchical way.
Top level segment generates main dataset, while subsegments generate embedded datasets. This way resulting tree is built. For example:
/organization{id()}?is_active/project{id()}/person{id()}.xml
--->
<htsql:result root="http://localhost:8081" base="http://localhost:8081">
<op:organization htsql:id="lake-carmen" id="lake-carmen">
<op:project htsql:id="lt-711" id="lt-711"/>
<op:project htsql:id="lt-802" id="lt-802">
<op:person htsql:id="lakeside.amy" id="lakeside.amy"/>
<op:person htsql:id="meyers.hill" id="meyers.hill"/>
<op:person htsql:id="meyers.jack" id="meyers.jack"/>
<op:person htsql:id="meyers.jim" id="meyers.jim"/>
</op:project>
</op:organization>
<op:organization htsql:id="meyers" id="meyers"/>
<op:organization htsql:id="meyers_elec" id="meyers_elec"/>
<op:organization htsql:id="stewart" id="stewart"/>
</htsql:result>
XML illustrates well hierarchical structure of result.
tree_clause may contain several embedded trees, braced and separated with “;”. This construction is called branching and results in several sets of linked rows:
/organization{id()}?!is_active/(project{id()};person{id()}).xml
--->
<htsql:result root="http://localhost:8081" base="http://localhost:8081">
<op:organization htsql:id="acorn" id="acorn">
<op:project htsql:id="la-102" id="la-102"/>
<op:person htsql:id="acorn.hideo" id="acorn.hideo"/>
</op:organization>
<op:organization htsql:id="lake-apts" id="lake-apts">
<op:project htsql:id="la-334" id="la-334"/>
<op:person htsql:id="lake-apts.tom" id="lake-apts.tom"/>
</op:organization>
<op:organization htsql:id="smith" id="smith">
<op:project htsql:id="smak" id="smak"/>
<op:project htsql:id="smbl" id="smbl"/>
<op:project htsql:id="smen" id="smen"/>
<op:person htsql:id="smith.jack" id="smith.jack"/>
<op:person htsql:id="smith.jose" id="smith.jose"/>
<op:person htsql:id="smith.maggy" id="smith.maggy"/>
</op:organization>
</htsql:result>
Segment is a construction, that generates single dataset: set of rows with defined structure.
table_qualifier defines aspect context for a segment. If not specified scalar context is considered. Expressions within selector_clause and filter_clause are evaluated in this context.
`*` hint tells SQL generator to perform inner join with the parent segment. The result of this hint is that rows of parent segment, containing no rows of current segment will not be returned:
/organization{id()}?is_active/*project{id()}/*person{id()}.xml
--->
<htsql:result root="http://localhost:8081" base="http://localhost:8081">
<op:organization htsql:id="lake-carmen" id="lake-carmen">
<op:project htsql:id="lt-802" id="lt-802">
<op:person htsql:id="lakeside.amy" id="lakeside.amy"/>
<op:person htsql:id="meyers.hill" id="meyers.hill"/>
<op:person htsql:id="meyers.jack" id="meyers.jack"/>
<op:person htsql:id="meyers.jim" id="meyers.jim"/>
</op:project>
</op:organization>
</htsql:result>
Obviously, this hint makes sence only for subsegments of a tree.
Selector specifies structure of returned rows and contains set of comma-separated selection constructions. Each selection defines one or more (is case of subselector usage) columns of resulting dataset.
Selection may be simple or contain subselector.
Simple selection in an expression, that is used to calculate values of specific result column. The expression must be strictly singular.
Selection with subselector may define more than one resulting columns, depending on how many selections subselector contains. Subselector is just a syntactical shortcut to define several columns at once: forehand expression is a context for expressions within subselector:
context { expr1, expr2 }
is equivalent for
context.expr1, context.expr2
Like in example:
/project{id(), name, organization{id(), name}}
is equivalent for
/project{id(), name, organization{id(), name}}
Context for subselector may be any valid singular or plural expression:
/organization{id(), project{count(), first(name)}}
is equivalent for
/organization{id(), project.count(), project.first(name)}
/organization{(name+' **')[1:]{this(), length()}}
is equivalent for
/organization{(name+' **')[1:].this(), (name+' **')[1:].length()}
When context for subselector is plural, selection may have optional filter_clause, which is called in this case a sieve. It defines a condition for a plural expression to filter rows before aggregate functions within a subselector will be applied.
/organization{id(), project{count()}} —>
acorn 1 lake-apts 1 lake-carmen 2 lakeside 0 meyers 0 meyers_elec 0 smith 3 stewart 0/organization{id(), project{count()}?status=’completed’} —>
acorn 1 lake-apts 1 lake-carmen 0 lakeside 0 meyers 0 meyers_elec 0 smith 2 stewart 0
Several hints can be used in selection clause:
- “+” hint sorts result by this selection in ascending order. With subselector hint sorts result by all selections in subselector.
- “-” hint sorts result by this selection in descending order. With subselector hint sorts result by all selections in subselector.
- “^” hint groups result by this selection. If one of selections is marked with such hint, all others within selector must be aggregates or also be marked for grouping.
Filter is a conditional expression layed upon rows of segment dataset or plural expression to exclude rows, which don’t satisfy the condition. Filter expression is also called predicate expression.
If filter expression is not boolean, an implicit cast is performed. Refer to Boolean conversion for details.
If filter expression is plural, implicit exists function is applies.
When data modification command is specified in a query, filter clause may contain assignments, which define new column values. It’s obvious, that assignments may be used only in aspect context:
/project[la-102]?status='completed'&name:=name+' xxx'/update()?description:=description+' ***'
In this example two assignments are placed in different filter clauses, but it doesn’t matter, since they are evaluated in the same aspect context. Single filter clause could be used as well, containing both assignments.
Locator is construction for selecting particular rows of a given table using primary key columns and is indentical to the more formal filter syntax:
/organization[meyers]
is equivalent for
/op:organization?org_id='meyers'
When using this syntax, each value associated with a primary key column is called a label. As follows from an example, labels are compared via usual equality (not null-safe). Labels unlike other non-numeric literals may be unquoted.
Locator accepts several row locations, separated by comma “,”.
If primary key of specific table is composite, location is a dot-separated sequence of labels for each key column of a composite key:
/person[acorn.hideo]
Wildcard `*` accepts any value of the column and subselector specifies set of specific values.
Sublocator may be enclosed in square brackets (like ordinary locator) or in parenthesis.
Commands define actions executed within the htsql query.
Command call looks like a function: command name followed by parenthesis wich argument list. Command is prefixed with either slash “/” or dot “.”. The only difference is that with dot prefix command without arguments may be called without trailing parenthesis:
/organization/xml()
is equivalent for
/organization.xml
Command arguments are passed in order of declaration or by name in any order. By name arguments are passed in form of name=argument pairs, coming at the end of argument list, after all ordinary arguments.