Changes

Jump to navigation Jump to search
6,914 bytes added ,  15:30, 29 June 2023
<div style="float:left; width:100%;">This page presents the code structure classes and functions of the [[Clients|BaseX clientsClients]],and the client/underlying protocol, which is utilized for communicating with the database server protocol needed to write [[Clients]].in other programming languagesA detailed example demonstrates how a concrete byte exchange can look like.
==DescriptionWorkflow==
* First of allAll clients are based on the client/server architecture. Hence, the a BaseX database server must be running in order to use the clientsstarted first.
* Each client provides a session class or script with methods to connect to and communicate with the database server. A socket connection will be established by the constructor, which expects a host, port, user name username and password as arguments.
* For the execution of commands you need to call the <code>The {{Code|execute()</code> }} method with the is called to launch a database command as argument. The method It returns the result or throws an exception with the received error message.
* The <code>{{Code|query()</code> }} method creates a query instance. Variables and the context item can be bound to that objectinstance, and the result can either be requested by <code>via {{Code|execute()</code>}}, or in an iterative manner with the <code>{{Code|more()</code> }} and <code>{{Code|next()</code> }} functions. If an error occurs, an exception will be thrown.
* The <code>{{Code|create()</code>}}, <code>{{Code|add()</code>}}, <code>replace{{Code|put()</code> }} and <code>store{{Code|putbinary()</code> method can be used to }} methods pass on input streams to the corresponding database commands. The input can be a UTF-8 encoded XML document, a binary resource, or any other data (such as JSON or CSV) that can be successfully converted to a resource by the server.
* To speed up execution, an output stream can be specified by some clients; this way, all results will be directed to that output stream.
* Most clients are accompanied by some example files, which demonstrate how database commands can be executed or how queries can be evaluated.
==Transfer Protocol== All [[Clients]] use the following client/server protocol to communicate with the server.The description of the protocol is helpful if you want to implement your own client. ===Conventions=== * <code>\xx</code>: single byte.* <code>{...}</code>: utf8 strings or raw data, suffixed with a <code>\00</code> byte. To avoid confusion with this end-of-string byte, all transferred <code>\00</code> and <code>\FF</code> bytes are prefixed by an additional <code>\FF</code> byte. ===Authentication=== ====Digest==== Digest authentication is used since Version 8.0: # Client connects to server socket# Server sends a '''realm''' and '''nonce''', separated by a colon: <code>{realm:nonce}</code># Client sends the '''username''' and a hash value. The hash is composed of the md5 hash of## the md5 hash of the '''username''', '''realm''', and '''password''' (all separated by a colon), and## the '''nonce''': <code>{username} {md5(md5(username:realm:password) + nonce)}</code># Server replies with <code>\00</code> (success) or <code>\01</code> (error) ====CRAM-MD5==== CRAM-MD5 was discarded because unsalted md5 hashes can easily be uncovered using rainbow tables. However, most client bindings still provide support for the outdated handshaking, as it only slightly differs from the new protocol: # Client connects to server socket# Server sends a '''nonce''' (timestamp): <code>{nonce}</code># Client sends the '''username''' and a hash value. The hash is composed of the md5 hash of## the md5 of the '''password''' and## the '''nonce''': <code>{username} {md5(md5(password) + nonce)}</code># Server replies with <code>\00</code> (success) or <code>\01</code> (error) It is possible to support both {{Code Structure|digest}} and {{Code|cram-md5}} authentication in clients: If the first server response contains no colon, {{Code|cram-md5}} should be chosen. ===Command Protocol=== The following byte sequences are sent and received from the client (please note that a specific client may not support all of the presented commands): {| class="wikitable"|-! Command! Client Request! Server Response! Description|-| COMMAND| <code>{command}</code>| <code>{result} {info} \00</code>| Executes a database command.|-| QUERY| <code>\00 {query}</code>| <code>{id} \00</code>| Creates a new query instance and returns its id.|-| CREATE| <code>\08 {name} {input}</code>| <code>{info} \00</code>| Creates a new database with the specified input (may be empty).|-| ADD| <code>\09 {path} {input}</code>| <code>{info} \00</code>| Adds a new document to the opened database.|-| PUT| <code>\0C {path} {input}</code>| <code>{info} \00</code>| Puts (adds or replaces) an XML document resource in the opened database.|-| PUTBINARY| <code>\0D {path} {input}</code>| <code>{info} \00</code>| Puts (adds or replaces) a binary resource in the opened database.|-| ↯ error| <code></code>| <code>{</code>''partial result''<code>} {error} \01</code>| Error feedback.|} ===Query Command Protocol=== Queries are referenced via an {{Code|id}}, which has been returned by the {{Code|QUERY}} command (see above). {| class="wikitable"|-! Query Command! Client Request! Server Response! Description|-| CLOSE| <code>\02 {id}</code>| <code>\00 \00</code>| Closes and unregisters the query with the specified id.|-| BIND| <code>\03 {id} {name} {value} {type}</code>| <code>\00 \00</code>| Binds a value to a variable. The type will be ignored if the string is empty.|-| RESULTS| <code>\04 {id}</code>| <code>\xx {item} ... \xx {item} \00</code>| Returns all resulting items as strings, prefixed by a single byte ({{Code|\xx}}) that represents the [[Server Protocol: Types|Type ID]]. This command is called by the {{Code|more()}} function of a client implementation.|-| EXECUTE| <code>\05 {id}</code>| <code>{result} \00</code>| Executes the query and returns the result as a single string.|-| INFO| <code>\06 {id}</code>| <code>{result} \00</code>| Returns a string with query compilation and profiling info.|-| OPTIONS| <code>\07 {id}</code>| <code>{result} \00</code>| Returns a string with all query serialization parameters, which can e.g. be assigned to the {{Option|SERIALIZER}} option.|-| CONTEXT| <code>\0E {id} {value} {type}</code>| <code>\00 \00</code>| Binds a value to the context. The type will be ignored if the string is empty.|-| UPDATING| <code>\1E {id}</code>| <code>{result} \00</code>| Returns {{Code|true}} if the query contains updating expressions; {{Code|false}} otherwise.|-| FULL| <code>\1F {id}</code>| <code>''XDM'' {item} ... ''XDM'' {item} \00</code>| Returns all resulting items as strings, prefixed by the [[Server Protocol: Types#XDM Metadata|XDM Metadata]]. This command is e. g. used by the [[Developing|XQJ API]].|} As can be seen in the table, all results end with a single {{Code|\00}} byte, which indicates that the process was successful. If an error occurs, an additional byte {{Code|\01}} is sent, which is then followed by the {{Code|error}} message string. ====Binding Sequences====
===Session===Also, sequences can be bound to variables and the context: * {{Code|empty-sequence()}} must be supplied as type if an empty sequence is to be bound.* Multiple items are supplied via the <code>{value}</code> argument and separated with {{Code|\01}} bytes.* Item types are specified by appending {{Code|\02}} and the type in its string representation to an item. If no item type is specified, the general type is used.
* Creates and returns session with host, port, user name and password:<br/>Some examples for the <code>Session(String host, int port, String name, String password){value}</code>argument:
* Executes a command the two integers {{Code|123}} and returns {{Code|789}} are encoded as {{Code|123}}, {{Code|\01}}, {{Code|789}} and {{Code|\00}} ({{Code|xs:integer}} may be specified via the result:<br/code>{type}</code>String executeargument).* the two items {{Code|xs:integer(123)}} and {{Code|xs:string(String command'ABC')</code>}} are encoded as {{Code|123}}, {{Code|\02}}, {{Code|xs:integer}}, {{Code|\01}}, {{Code|ABC}}, {{Code|\02}}, {{Code|xs:string}} and {{Code|\00}}.
* Returns a query object for the specified query:<br/><code>Query query(String query)</code>==Example==
* Creates In the following example, a client registers a new session and executes the {{Command|INFO}} database from command. Next, it creates a new query instance for the XQuery expression {{Code|1, 2+'3'}}. The query is then evaluated, and the server returns the result of the first subexpression {{Code|1}} and an input stream:<br/><code>void create(String nameerror for the second sub expression. Finally, InputStream in)</code>the query instance and client session are closed.
* Adds a document '''Client''' connects to the current database from server socket* '''Server''' sends realm and timestamp "BaseX:1369578179679": {{Code|◄ 42 61 73 65 58 3A 31 33 36 39 35 37 38 31 37 39 36 37 39 00}}* '''Client''' sends username "jack": {{Code|6A 61 63 6B 00 ►}}* '''Client''' sends hash: md5(md5("jack:BaseX:topsecret") + "1369578179679") = "ca664a31f8deda9b71ea3e79347f6666": {{Code|63 61 36 ... 00 ►}}* '''Server''' replies with success code: {{Code|◄ 00}}* '''Client''' sends the "INFO" command: {{Code|49 4E 46 4F 00 ►}}* '''Server''' responds with the result "General Information...": {{Code|◄ 47 65 6e 65 ... 00}}* '''Server''' additionally sends an input stream(empty) info string: {{Code|◄ 00}}* '''Client''' creates a new query instance for the XQuery "1, 2+'3'":<br/><{{Code|00 31 2C 20 32 2B 27 33 27 00 ►}}* '''Server''' returns query id "1" and a success code>void add: {{Code|◄ 31 00 00}}* '''Client''' requests the query results via the RESULTS protocol command and its query id: {{Code|04 31 00 ►}}* '''Server''' returns the first result (String name"1", String targettype xs:integer): {{Code|◄ 52 31 00}}* '''Server''' sends a single {{Code|\00}} byte instead of a new result, InputStream inwhich indicates that no more results can be expected: {{Code|◄ 00}}* '''Server''' sends the error code {{Code|\01}} and the error message ("Stopped at..."): {{Code|◄ 01 53 74 6f ... 00}}* '''Client''' closes the query instance: {{Code|02 31 00 ►}}* '''Server''' sends a response (which is equal to an empty info string)</and success code>: {{Code|◄ 00 00}}* '''Client''' closes the socket connection
* Replaces a document with the specified input stream:<br/><code>void replace(String path, InputStream in)</code>==Constructors and Functions==
* Stores raw data at Most language bindings provide the specified pathfollowing constructors and functions:<br/><code>void store(String path, InputStream in)</code>
* Watches the specified event:<br/div><code>void watch(String name, Event notifier)</codediv style="float:left; width:48%;">===Session===
* Unwatches the specified eventCreate and return session with host, port, username and password:<br/><code>void unwatchSession(String host, int port, String name, String password)</code>
* Returns process informationExecute a command and return the result:<br/><code>String infoexecute(String command)</code>
* Closes Return a query instance for the sessionspecified query:<br/><code>void closeQuery query(String query)</code>
===Query===* Create a database from an input stream:<br/><code>void create(String name, InputStream input)</code>
* Creates query object with session and queryAdd a document to the current database from an input stream:<br/><code>constructorvoid add(Session sString path, String queryInputStream input)</code>
* Binds an external variablePut a document with the specified input stream:<br/><code>void bindput(String namepath, String valueInputStream input)</code>
* Executes Put a binary resource at the queryspecified path:<br/><code>void putBinary(String execute(path, InputStream input)</code>
* Iterator: checks if a query returns more itemsReturn process information:<br/><code>boolean moreString info()</code>
* Returns next itemClose the session:<br/><code>String nextvoid close()</code>
* Returns query information:<br/div><codediv style="float:left; width:4%;">String info()&nbsp;</codediv><div style="float:left; width:48%;">===Query===
* Returns serialization optionsCreate query instance with session and query:<br/><code>Query(Session session, String options(query)</code>
* Closes the iterator and queryBind an external variable:<br/><code>closevoid bind(String name, String value, String type)</code><br/>The type can be an empty string.
==Transfer Protocol==* Bind the context item:<br/><code>void context(String value, String type)</code><br/>The type can be an empty string. * Execute the query and return the result:<br/><code>String execute()</code>
===Syntax===* Iterator: check if a query returns more items:<br/><code>boolean more()</code>
* <code>\x</code>Iterator: return the next item: single byte.* <code>{...}<br/code>: strings, which are transfered in the UTF8 encoding.* <code>[...]String next()</code>: binary data. All 00 and FF bytes are prefixed with FF.
===Authentication (via [http* Return query information:<br/><code>String info()</tools.ietf.org/html/rfc2195 cram-md5])===code>
# Client connects to server socket# Server sends timestamp* Return serialization parameters:<br/><code>{timestamp} \0</code># Client sends username and hashed password/timestamp:<br/><code>{username} \0 {md5(md5String options(password) + timestamp)} \0</code># Server sends <code>\0</code> (success) or <code>\1</code> (error)
===Client Request===* Return if the query may perform updates:<br/><code>boolean updating()</code>
The following byte sequences are sent from * Close the clientquery:<br/><code>void close()</code></div><div style="float:left; width:100%;">
COMMAND -> {command} \0 CREATE -> \8 {name} \0 [input] \0 ADD -> \9 {name} \0 {path} \0 [input] \0 WATCH -> \10 {name} \0 UNWATCH -> \11 {name} \0 REPLACE -> \12 {path} \0 [input] \0 STORE -> \13 {path} \0 [input] \0=Changelog=
Queries are referenced with an <code>id</code>:;Version 8.2
INIT -> \0 * Removed: {query} \0 CLOSE -> \2 {id} \0 BIND -> \3 {id} \0 {name} \0 {value} \0 {typeCode|WATCH} \0 ITER -> \4 {id} \0 EXECUTE -> \5 and {id} \0 INFO -> \6 {idCode|UNWATCH} \0 OPTIONS -> \7 {id} \0command
===Server Response===;Version 8.0
The server replies * Updated: cram-md5 replaced with the following byte sequencesdigest authentication* Updated: {{Code|BIND}} command:support more than one item
COMMAND -> {result} \0 {info} \0 \0 CREATE -> {info} \0 \0 ADD -> {info} \0 \0 ERROR -> \0 {error} \0 \1 QUERY: INIT -> {id} \0 \0 CLOSE -> \0 \0 BIND -> \0 \0 ITER -> {result} \0 \0 EXECUTE -> {result} \0 \0 INFO -> {result} \0 \0 OPTIONS -> {result} \0 \0 ERROR -> \0 \1 {error} \0;Version 7.2
===Examples===* Added: Query Commands CONTEXT, UPDATING and FULL* Added: Client function {{Code|context(String value, String type)}}
* [https:<//github.com/BaseXdb/basex-api/blob/master/src/main/java/BaseXClient.java Java client]* [https://github.com/BaseXdb/basex-api/blob/master/src/main/c%23/BaseXClient.cs C# client]* [https://github.com/BaseXdb/basex-api/blob/master/src/main/python/BaseXClient.py Python client]* [https://github.com/BaseXdb/basex-api/blob/master/src/main/perl/BaseXClient.pm Perl client]div>
Bureaucrats, editor, reviewer, Administrators
13,554

edits

Navigation menu