Changes

Jump to navigation Jump to search
7,449 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 clients Clients]],andthe client/server underlying protocol of BaseX that , which is needed toutilized for communicating with the database server.write [[Clients]] in other programming languagesA detailed example demonstrates how a concrete byte exchange can look like.
==DescriptionWorkflow==
First of all* All clients are based on the client/server architecture. Hence, the a BaseX database server must be running towork with the clientsstarted first.
* Each client provides a session class or script with methodsto connect to and communicate with the database server. A socket connection will be established by the constructor, which expects a host, port, username and password as arguments.
A socket connection will be established by * The {{Code|execute()}} method is called to launch a database command. It returns the constructor, whichexpects a host, port, user name and password as argumentsresult or throws an exception with the received error message.
For * The {{Code|query()}} method creates a query instance. Variables and the execution of commands you need context item can be bound to call that instance, and the <code>result can either be requested via {{Code|execute()</code>method }}, or in an iterative manner with the database command as argument{{Code|more()}} and {{Code|next()}} functions. The method returns theresult or throws If an error occurs, an exception with the received error messagewill be thrown.
To speedup execution* The {{Code|create()}}, an output stream {{Code|add()}}, {{Code|put()}} and {{Code|putbinary()}} methods pass on input streams to the corresponding database commands. The input can be specified by some clients;this waya UTF-8 encoded XML document, a binary resource, all results will or any other data (such as JSON or CSV) that can be directed successfully converted to that output streama resource by the server.
The <code>query()</code> method creates a query instance. Variables can bebound to that object* To speed up execution, and the result an output stream can either be requested specified by<code>execute()</code>some clients; this way, or in an iterative manner with the<code>more()</code> and <code>next()</code> functions.If an error occurs, an exception all results will be throwndirected to that output stream.
The <code>create()</code>* Most clients are accompanied by some example files, <code>add()</code>, <code>replace()</code>and <code>store()</code> method which demonstrate how database commands can be executed or how queries can be used to pass on input streamsto the corresponding database commandsevaluated.
Most clients ==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 accompanied prefixed by some example filesan 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''', which demonstrateseparated by a colon: <code>{realm:nonce}</code>how database commands can be executed # 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 how queries can be evaluated.<code>\01</code> (error)
==Code Structure==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|digest}} and {{Code|cram-md5}} authentication in clients: If the first server response contains no colon, {{Code|cram-md5}} should be chosen. ===SessionCommand 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==== 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. Some examples for the <code>{value}</code> argument: * the two integers {{Code|123}} and {{Code|789}} are encoded as {{Code|123}}, {{Code|\01}}, {{Code|789}} and {{Code|\00}} ({{Code|xs:integer}} may be specified via the <code>{type}</code> argument).* the two items {{Code|xs:integer(123)}} and {{Code|xs:string('ABC')}} are encoded as {{Code|123}}, {{Code|\02}}, {{Code|xs:integer}}, {{Code|\01}}, {{Code|ABC}}, {{Code|\02}}, {{Code|xs:string}} and {{Code|\00}}. ==Example== In the following example, a client registers a new session and executes the {{Command|INFO}} database 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 error for the second sub expression. Finally, the query instance and client session are closed. * '''Client''' connects to the database 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 (empty) info string: {{Code|◄ 00}}* '''Client''' creates a new query instance for the XQuery "1, 2+'3'": {{Code|00 31 2C 20 32 2B 27 33 27 00 ►}}* '''Server''' returns query id "1" and a success code: {{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 ("1", type xs:integer): {{Code|◄ 52 31 00}}* '''Server''' sends a single {{Code|\00}} byte instead of a new result, which 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 ==Constructors and Functions==
* Creates Most language bindings provide the following constructors and returns session with host, port, user name and passwordfunctions:<br/><code>Session(String host, int port, String name, String password)</code>
* Executes a command and returns the result:<br/div><code>String execute(String command)</codediv style="float:left; width:48%;">===Session===
* Returns a query object for the specified queryCreate and return session with host, port, username and password:<br/><code>Query querySession(String queryhost, int port, String name, String password)</code>
* Creates Execute a database from an input streamcommand and return the result:<br/><code>void createString execute(String name, InputStream incommand)</code>
* Adds Return a document to query instance for the current database from an input streamspecified query:<br/><code>void addQuery query(String name, String target, InputStream inquery)</code>
* Replaces Create a document with the specified database from an input stream:<br/><code>void replacecreate(String pathname, InputStream ininput)</code>
* Stores raw data at Add a document to the specified pathcurrent database from an input stream:<br/><code>void storeadd(String path, InputStream ininput)</code>
* Watches Put a document with the specified eventinput stream:<br/><code>void watchput(String namepath, Event notifierInputStream input)</code>
* Unwatches Put a binary resource at the specified eventpath:<br/><code>void unwatchputBinary(String namepath, InputStream input)</code>
* Returns Return process information:<br/><code>String info()</code>
* Closes Close the session:<br/><code>void close()</code>
</div><div style="float:left; width:4%;">&nbsp;
</div><div style="float:left; width:48%;">
===Query===
* Creates Create query object instance with session and query:<br/><code>constructorQuery(Session ssession, String query)</code> * Bind an external variable:<br/><code>void bind(String name, String value, String type)</code><br/>The type can be an empty string.
* Binds an external variableBind the context item:<br/><code>void bindcontext(String namevalue, String valuetype)</code><br/>The type can be an empty string.
* Executes Execute the queryand return the result:<br/><code>String execute()</code>
* Iterator: checks check if a query returns more items:<br/><code>boolean more()</code>
* Returns Iterator: return the next item:<br/><code>String next()</code>
* Returns Return query information:<br/><code>String info()</code>
* Returns Return serialization optionsparameters:<br/><code>String options()</code>
* Closes Return if the iterator and querymay perform updates:<br/><code>closeboolean updating()</code>
* Close the query:<br/><code>void close()</code></div><div style==Transfer Protocol=="float:left; width:100%;">
===Syntax==Changelog=
* <code>\x</code>: single byte.* <code>{...}</code>: strings, which are transfered in the UTF8 encoding.* <code>[...]</code>: binary data. All 00 and FF bytes are prefixed with FF;Version 8.2
===Authentication===* Removed: {{Code|WATCH}} and {{Code|UNWATCH}} command
# Client connects to server socket# Server sends timestamp: <code>{timestamp} \;Version 8.0</code># Client sends username and hash: <code>{username} \0 {md5(md5(password) + timestamp)} \0</code># Server sends <code>\0</code> (success) or <code>\1</code> (error)
===Client Request===* Updated: cram-md5 replaced with digest authentication* Updated: {{Code|BIND}} command: support more than one item
- 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 - query: start -> \0 {query} \0 bind -> \3 {id} \0 {variable} \0 {value} \0 {type} \0 next -> \1 {id} \0 execute -> \5 {id} \0 info -> \6 {id} \0 options -> \;Version 7 {id} \0 close -> \.2 {id} \0
===Server Response===* Added: Query Commands CONTEXT, UPDATING and FULL* Added: Client function {{Code|context(String value, String type)}}
- command: -</div> {result} \0 {info} \0 \0 - create: -> {info} \0 \0 - add: -> {info} \0 \0 error -> \0 {error} \0 \1 - query: start -> {id} \0 \0 bind -> \0 \0 next -> {result} \0 \0 execute -> {result} \0 \0 info -> {result} \0 \0 options -> {result} \0 \0 close -> \0 \0 error -> \0 \1 {error} \0
Bureaucrats, editor, reviewer, Administrators
13,554

edits

Navigation menu