Skip to content

Commit 08b8311

Browse files
committed
Expose all data from the API. Follow the protocol doc.
1 parent 4fea06a commit 08b8311

File tree

5 files changed

+251
-66
lines changed

5 files changed

+251
-66
lines changed

README.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -329,8 +329,8 @@ $result3 = $connection3->Query("...");
329329
| --- | --- |
330330
| <strong>__construct</strong> | Create a new connection to a MonetDB database. <br><br><strong>@param</strong> <em>string</em> <strong>$host</strong> : The host of the database. Use '127.0.0.1' if the DB is on the same machine.<br><strong>@param</strong> <em>int</em> <strong>$port</strong> : The port of the database. For MonetDB this is usually 50000.<br><strong>@param</strong> <em>string</em> <strong>$user</strong> : The user name.<br><strong>@param</strong> <em>string</em> <strong>$password</strong> : The password of the user.<br><strong>@param</strong> <em>string</em> <strong>$database</strong> : The name of the database to connect to. Don't forget to release and start it.<br><strong>@param</strong> <em>string</em> <strong>$saltedHashAlgo</strong> <em>= "SHA1"</em> : Optional. The preferred hash algorithm to be used for exchanging the password. It has to be supported by both the server and PHP. This is only used for the salted hashing. Another stronger algorithm is used first (usually SHA512).<br><strong>@param</strong> <em>bool</em> <strong>$syncTimeZone</strong> <em>= true</em> : If true, then tells the clients time zone offset to the server, which will convert all timestamps is case there's a difference. If false, then the timestamps will end up on the server unmodified.<br><strong>@param</strong> <em>int</em> <strong>$maxReplySize</strong> <em>= 200</em> : The maximal number of tuples returned in a response. A higher value results in smaller number of memory allocations and string operations, but also in higher memory footprint. |
331331
| <strong>Close</strong> | Close the connection |
332-
| <strong>Query</strong> | Execute an SQL query and return its response. For 'select' queries the response can be iterated using a 'foreach' statement. You can pass an array as second parameter to execute the query as prepared statement, where the array contains the parameter values. SECURITY WARNING: For prepared statements in MonetDB, the parameter values are passed in a regular 'EXECUTE' command, using escaping. Therefore the same security considerations apply here as for using the Connection->Escape(...) method. Please read the comments for that method. <br><br><strong>@param</strong> <em>string</em> <strong>$sql</strong><br><strong>@param</strong> <em>array</em> <strong>$params</strong> <em>= null</em> : An optional array for prepared statement parameters. If not provided (or null), then a normal query is executed, instead of a prepared statement. The parameter values will retain their PHP type if possible. The following values won't be converted to string: null, true, false and numeric values.<br><strong>@return</strong> <em>Response</em> |
333-
| <strong>QueryFirst</strong> | Execute an SQL query and return only the first row as an associative array. If there is more data on the stream, then discard all. Returns null if the query has empty result. You can pass an array as second parameter to execute the query as prepared statement, where the array contains the parameter values. <br><br><strong>@param</strong> <em>string</em> <strong>$sql</strong><br><strong>@param</strong> <em>array</em> <strong>$params</strong> <em>= null</em> : An optional array for prepared statement parameters. If not provided (or null), then a normal query is executed, instead of a prepared statement. See the 'Query' method for more information about the parameter values.<br><strong>@return</strong> <em>string[] -or- null</em> |
332+
| <strong>Query</strong> | Execute an SQL query and return its response. For 'select' queries the response can be iterated using a 'foreach' statement. You can pass an array as second parameter to execute the query as prepared statement, where the array contains the parameter values. SECURITY WARNING: For prepared statements in MonetDB, the parameter values are passed in a regular 'EXECUTE' command, using escaping. Therefore the same security considerations apply here as for using the Connection->Escape(...) method. Please read the comments for that method. <br><br><strong>@param</strong> <em>string</em> <strong>$sql</strong><br><strong>@param</strong> <em>array</em> <strong>$params</strong> <em>= null</em> : An optional array for prepared statement parameters. If not provided (or null), then a normal query is executed instead of a prepared statement. The parameter values will retain their PHP type if possible. The following values won't be converted to string: null, true, false and numeric values.<br><strong>@return</strong> <em>Response</em> |
333+
| <strong>QueryFirst</strong> | Execute an SQL query and return only the first row as an associative array. If there is more data on the stream, then discard all. Returns null if the query has empty result. You can pass an array as second parameter to execute the query as prepared statement, where the array contains the parameter values. <br><br><strong>@param</strong> <em>string</em> <strong>$sql</strong><br><strong>@param</strong> <em>array</em> <strong>$params</strong> <em>= null</em> : An optional array for prepared statement parameters. If not provided (or null), then a normal query is executed instead of a prepared statement. See the 'Query' method for more information about the parameter values.<br><strong>@return</strong> <em>string[] -or- null</em> |
334334
| <strong>Command</strong> | Send a 'command' to MonetDB. Commands are used for configuring the database, for example setting the maximal response size, or for requesting unread parts of a query response ('export').<br><br><strong>@param</strong> <em>string</em> <strong>$command</strong><br><strong>@param</strong> <em>bool</em> <strong>$noResponse</strong> <em>= true</em> : If true, then returns NULL and makes no read to the underlying socket.<br><strong>@return</strong> <em>Response -or- null</em> |
335335
| <strong>Escape</strong> | Escape a string value, to be inserted into a query, inside single quotes. The following characters are escaped by this method: backslash, single quote, carriage return, line feed, tabulator, null character, CTRL+Z. As a security measure this library forces the use of multi-byte support and UTF-8 encoding, which is also used by MonetDB, avoiding the SQL-injection attacks, which play with differences between character encodings. <br><br><strong>@param</strong> <em>string</em> <strong>$value</strong><br><strong>@return</strong> <em>string</em> |
336336
| <strong>ClearPsCache</strong> | Clears the in-memory cache of prepared statements. This is called automatically when an error is received from MonetDB, because that also purges the prepared statements and all session state in this case. |
@@ -361,13 +361,20 @@ $result3 = $connection3->Query("...");
361361
| --- | --- |
362362
| <strong>GetQueryType</strong> | Returns a short string which identifies the type of the query.<br><br><strong>@return</strong> <em>string</em> |
363363
| <strong>GetDescription</strong> | Returns a user-friendly text which describes the effect of the query.<br><br><strong>@return</strong> <em>string</em> |
364-
| <strong>GetExecutionTime</strong> | The time the server spent on executing the query. In milliseconds.<br><br><strong>@return</strong> <em>float -or- null</em> |
365-
| <strong>GetQueryParsingTime</strong> | The time it took to parse and optimize the query. In milliseconds.<br><br><strong>@return</strong> <em>float -or- null</em> |
364+
| <strong>GetQueryTime</strong> | The time the server spent on executing the query. In milliseconds.<br><br><strong>@return</strong> <em>float -or- null</em> |
365+
| <strong>GetSqlOptimizerTime</strong> | SQL optimizer time in milliseconds.<br><br><strong>@return</strong> <em>float -or- null</em> |
366+
| <strong>GetMalOptimizerTime</strong> | MAL optimizer time in milliseconds.<br><br><strong>@return</strong> <em>float -or- null</em> |
366367
| <strong>GetAffectedRows</strong> | The number of rows updated or inserted.<br><br><strong>@return</strong> <em>integer -or- null</em> |
367-
| <strong>GetRowCount</strong> | The number of rows in the response.<br><br><strong>@return</strong> <em>integer -or- null</em> |
368+
| <strong>GetTotalRowCount</strong> | The total number of rows in the result set. This includes those rows too, which are not in the current response.<br><br><strong>@return</strong> <em>integer -or- null</em> |
368369
| <strong>GetAsText</strong> | Get a description of the status response in a human-readable format.<br><br><strong>@return</strong> <em>string</em> |
369370
| <strong>GetPreparedStatementID</strong> | Get the ID of a created prepared statement. This ID can be used in an 'EXECUTE' statement, but only in the same session.<br><br><strong>@return</strong> <em>integer -or- null</em> |
370-
| <strong>GetQueryID</strong> | Returns the ID of the query response that is returned in the result set.<br><br><strong>@return</strong> <em>integer -or- null</em> |
371+
| <strong>GetResultID</strong> | Returns the ID of the result set that is returned for a query. It is stored on the server for this session, and parts of it can be queried using the "export" command.<br><br><strong>@return</strong> <em>integer -or- null</em> |
372+
| <strong>GetAutoCommitState</strong> | Available after "start transaction", "commit" or "rollback". Tells whether the current session is in auto-commit mode or not.<br><br><strong>@return</strong> <em>boolean -or- null</em> |
373+
| <strong>GetRowCount</strong> | The number of rows (tuples) in the current response only.<br><br><strong>@return</strong> <em>integer -or- null</em> |
374+
| <strong>GetColumnCount</strong> | Column count. If the response contains tabular data, then this tells the number of columns.<br><br><strong>@return</strong> <em>integer -or- null</em> |
375+
| <strong>GetQueryID</strong> | Query ID. A global ID which is also used in functions such as sys.querylog_catalog().<br><br><strong>@return</strong> <em>integer -or- null</em> |
376+
| <strong>GetLastInsertID</strong> | The last automatically generated ID by an insert statement. (Usually auto_increment) NULL if none.<br><br><strong>@return</strong> <em>integer -or- null</em> |
377+
| <strong>GetExportOffset</strong> | The index (offset) of the first row in a block response. (For an "export" command.)<br><br><strong>@return</strong> <em>integer -or- null</em> |
371378

372379
<hr><br>
373380

protocol_doc/README.md

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,11 @@ password hashing, then the formula for getting the hash string is the following:
151151
Where the hash functions output hexadecimal values. After the client calculated the hash,
152152
it sends it in a message like the following:
153153

154-
LIT:monetdb:{SHA1}b8cb82cca07f379e25e99262e3b4b70054546136:sql:myDatabase:
154+
LIT:monetdb:{SHA1}b8cb82cca07f379e25e99262e3b4b70054546136:sql:myDatabase:\n
155155

156-
Which is also separated by colons and the meanings of the values are:
156+
The `\n` at the end means a line feed character. (It seems to work well without that too,
157+
but mclient puts a newline there.) The line consists of colon-separated
158+
values with the following meanings:
157159

158160
| Value | Description |
159161
| --- | --- |
@@ -170,7 +172,7 @@ Optionally the client can allow the server the send/receive file
170172
transfer requests to/from the client, by adding a `FILETRANS` at the
171173
end, the following way:
172174

173-
LIT:monetdb:{SHA1}b8cb82cca07f379e25e99262e3b4b70054546136:sql:myDatabase:FILETRANS:
175+
LIT:monetdb:{SHA1}b8cb82cca07f379e25e99262e3b4b70054546136:sql:myDatabase:FILETRANS:\n
174176

175177
## 3.1. Possible responses to an authentication request
176178

@@ -194,8 +196,7 @@ After the client has sent the hashed password to the server, it can receive 3 ki
194196
## 3.2. The Merovingian redirect
195197

196198
The `Merovingian redirect` can be a real redirect, when the client is asked for connecting
197-
to a new host and port, but this case is not well documented and depend of special server
198-
configurations, therefore it will be ignored in this document.
199+
to a new host and port. For this see an example in section [Redirect](#51-redirect---).
199200

200201
A more common case of the `Merovingian redirect` is a request for the repetition of the authentication
201202
process. It happens in the existing TCP connection. No new connections are created. This repetition is
@@ -289,12 +290,24 @@ if the field count is less than expected.
289290

290291
## 5.1. Redirect - **^**
291292

292-
This response has been discussed already in chapter [The Merovingian redirect](#32-the-merovingian-redirect).
293-
Redirect messages always start with the `^` (caret) character. An example response:
293+
Redirect messages always start with the `^` (caret) character.
294+
This can be a real redirect, which instructs the client to close the current
295+
connection and open another one on a specific host/port. Example:
294296

295-
^mapi:merovingian://proxy?database=myDatabase
297+
^mapi:monetdb://localhost:50001/test?lang=sql&user=monetdb
298+
299+
| Sample value | Description |
300+
| --- | --- |
301+
| ^mapi:monetdb:// | This prefix identifies the redirect type |
302+
| localhost | Host name or IP address. (It can be IPv6) |
303+
| 50001 | Port. |
304+
| test | Database name. |
305+
| sql | Query language to request during the authentication. |
306+
| monetdb | User name to specify during the authentication. |
296307

297-
?? Investigate if there are different kinds of redirects.
308+
Or it can mean a [Merovingian redirect](#32-the-merovingian-redirect). Example:
309+
310+
^mapi:merovingian://proxy?database=myDatabase
298311

299312
## 5.2. Query response - **&**
300313

@@ -425,9 +438,9 @@ The first line of the response consists of 5 space-separated values:
425438
| --- | --- | --- |
426439
| 0 | &5 | Identifies the response type. (Prepared statement creation) |
427440
| 1 | 15 | The ID of the created prepared statement. This can be used in an `EXECUTE` statement. |
428-
| 2 | 4 | Row count |
441+
| 2 | 4 | Total row count in the result set. |
429442
| 3 | 6 | Column count |
430-
| 4 | 4 | Tuple count |
443+
| 4 | 4 | Row count in current response only. |
431444

432445
The original query requested only 3 columns, but this response returned 4 data rows, as the
433446
last one is for the `?` placeholder. The additional type information of the

src/Connection.php

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -207,19 +207,14 @@ private function Authenticate() {
207207
$pwHash = $challenge->HashPassword($this->password, $this->saltedHashAlgo);
208208
$upperSaltHash = strtoupper($this->saltedHashAlgo);
209209

210-
$this->Write("LIT:{$this->user}:{{$upperSaltHash}}{$pwHash}:sql:{$this->database}:");
210+
$this->Write("LIT:{$this->user}:{{$upperSaltHash}}{$pwHash}:sql:{$this->database}:\n");
211211

212212
$this->inputStream->LoadNextResponse();
213213
$inputStream = $this->inputStream->ReadNextLine();
214214
if (InputStream::IsResponse($inputStream, InputStream::MSG_REDIRECT, "mapi:merovingian:")) {
215215
/*
216-
Only the main process of MonetDB opens ports to listen on, and it spawns
217-
separate sub-processes for each database.
218-
The main process acts as a proxy and it forwards the queries to the
219-
processes of the databases. For security reasons the user has to
220-
authenticate not just at the main process, but also at the
221-
sub-process too. This repetition of the authentication process is
222-
called a "Merovingian redirect".
216+
See doc:
217+
https://github.com/MonetDB/MonetDB-PHP/tree/master/protocol_doc#32-the-merovingian-redirect
223218
*/
224219
continue;
225220
}

src/Response.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,8 @@ private function Parse() {
192192
If not all rows did fit into the window,
193193
request the next batch.
194194
*/
195-
$diff = $this->queryStatusRecord->GetRowCount() - $this->rowCount;
196-
$queryID = $this->queryStatusRecord->GetQueryID();
195+
$diff = $this->queryStatusRecord->GetTotalRowCount() - $this->rowCount;
196+
$queryID = $this->queryStatusRecord->GetResultID();
197197

198198
if ($diff > 0) {
199199
$size = min($diff, $this->connection->GetMaxReplySize());
@@ -237,7 +237,7 @@ private function Parse() {
237237
responses just get ignored.
238238
*/
239239
if ($this->queryStatusRecord !== null) {
240-
if ($this->queryStatusRecord->GetQueryID() != $status->GetQueryID()) {
240+
if ($this->queryStatusRecord->GetResultID() != $status->GetResultID()) {
241241
$this->ignoreTuples = true;
242242
}
243243
}
@@ -291,7 +291,7 @@ private function Parse() {
291291
continue;
292292
}
293293

294-
if ($this->queryStatusRecord->GetQueryID() != $status->GetQueryID()) {
294+
if ($this->queryStatusRecord->GetResultID() != $status->GetResultID()) {
295295
$this->ignoreTuples = true;
296296
continue;
297297
}

0 commit comments

Comments
 (0)