Changeset: c3490c20f7db for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=c3490c20f7db
Modified Files:
        clients/mapilib/mapi.c
        clients/mapilib/mapi.h
Branch: mapi_changes
Log Message:

Define a new prompt and handle it in the client

This is the most basic handling: the client recognizes the prompt,
parses it, saves the file name in the handle and skips the rest of the
block.

The new prompt consists of:

the bytes \001\003
a single space
the length of the file path
a single space
the file path

This is subject to change as we understand the problem better. For
instance maybe we do not need the length of the file path.

Next steps are to figure out how to coordinate client and server when
actually transferring the file.


diffs (154 lines):

diff --git a/clients/mapilib/mapi.c b/clients/mapilib/mapi.c
--- a/clients/mapilib/mapi.c
+++ b/clients/mapilib/mapi.c
@@ -896,6 +896,7 @@ struct MapiStatement {
        struct MapiParam *params;
        struct MapiResultSet *result, *active, *lastresult;
        int needmore;           /* need more input */
+       char *filename; /* read the contents of the file */
        int *pending_close;
        int npending_close;
        MapiHdl prev, next;
@@ -1722,6 +1723,7 @@ mapi_new_handle(Mapi mid)
        hdl->lastresult = NULL;
        hdl->active = NULL;
        hdl->needmore = 0;
+       hdl->filename = NULL;
        hdl->pending_close = NULL;
        hdl->npending_close = 0;
        /* add to doubly-linked list */
@@ -1817,6 +1819,8 @@ mapi_close_handle(MapiHdl hdl)
        hdl->query = NULL;
        if (hdl->template)
                free(hdl->template);
+       if (hdl->filename)
+               free(hdl->filename);
        hdl->template = NULL;
        /* remove from doubly-linked list */
        if (hdl->prev)
@@ -3925,6 +3929,58 @@ parse_header_line(MapiHdl hdl, char *lin
        return result;
 }
 
+
+/* We have seen so far the prompt \001\003 which is meant to make the
+ * client read a file in 8K blocks and send data back to the
+ * server. Following this prompt should be one space, the lenght of
+ * the filepath, a space, and the filepath itself:
+ * \001\003 21 /home/alice/file1.csv
+ *
+ * The pointer passed to this function starts at the first space,
+ * right after the bytes \001 and \003. Note that filename is malloc'ed
+ * here so the caller is responsible to free it.
+ */
+static bool
+parse_file_prompt(const char *prompt, char *filename) {
+       const char *p = prompt;
+       char buf[BLOCK];
+
+       if (*p != ' ') {
+               return false;
+       }
+
+       p++;
+       while (isdigit(*p)) {
+               buf[p - prompt + 1] = *p;
+               p++;
+       }
+       buf[p - prompt + 1] = 0;
+       if (*p != ' ') {
+               return false;
+       }
+
+       errno = 0;
+       long sz = strtol(buf, NULL, 10);
+       if (errno != 0) {
+               return false;
+       }
+
+       /* As a basic sanity check reject any filenames that do not
+        * fit in one block (~8K bytes)
+        */
+       if (sz > BLOCK - (p - prompt + 1) - 4) {
+               return false;
+       }
+
+       filename = (char *)malloc(sz + 1);
+       if (filename == NULL) {
+               return false;
+       }
+       strncpy(filename, p + 1, (size_t)sz);
+       *(filename + sz) = 0;
+       return true;
+}
+
 /* Read ahead and cache data read.  Depending on the second argument,
    reading may stop at the first non-header and non-error line, or at
    a prompt.
@@ -3941,7 +3997,7 @@ parse_header_line(MapiHdl hdl, char *lin
 static MapiMsg
 read_into_cache(MapiHdl hdl, int lookahead)
 {
-       char *line, *copy;
+       char *line, *filename = NULL;
        Mapi mid;
        struct MapiResultSet *result;
 
@@ -3962,23 +4018,34 @@ read_into_cache(MapiHdl hdl, int lookahe
                case PROMPTBEG: /* \001 */
                        mid->active = NULL;
                        hdl->active = NULL;
-                       /* set needmore flag if line equals PROMPT2 up
-                          to newline */
-                       copy = PROMPT2; /* \001\002\n */
-                       while (*line) {
-                               if (*line != *copy) /* must be EOF or PROMPT1 
\001\001\n */
+                       switch (*(line + 1)) {
+                       case 1:  /* Server is ready for new input */
+                               return mid->error;
+                       case 2:  /* Server needs more */
+                               if (*(line + 2) == '\n' || *(line + 2) == 0) {
+                                       /* skip end of block */
+                                       mid->active = hdl;
+                                       read_line(mid);
+                                       hdl->needmore = 1;
+                                       mid->active = hdl;
+                               }
+                               return mid->error;
+                       case 3:  /* Server needs the contents of a file */
+                               if (!parse_file_prompt(line + 2, filename)) {
+                                       /* parsing failed, prepare an
+                                        * appropriate error */
+                                       mapi_setError(mid, "Cannot parse 
prompt", "read_into_cache", MERROR);
                                        return mid->error;
-                               line++;
-                               copy++;
-                       }
-                       if (*copy == '\n' || *copy == 0) {
-                               /* skip end of block */
+                               }
+                               /* skip to the end of the block */
                                mid->active = hdl;
                                read_line(mid);
-                               hdl->needmore = 1;
+                               hdl->filename = filename;
                                mid->active = hdl;
+                               return mid->error;
+                       default:
+                               return mid->error;
                        }
-                       return mid->error;
                case '!':
                        /* start a new result set if we don't have one
                           yet (duh!), or if we've already seen
diff --git a/clients/mapilib/mapi.h b/clients/mapilib/mapi.h
--- a/clients/mapilib/mapi.h
+++ b/clients/mapilib/mapi.h
@@ -57,6 +57,7 @@ typedef int MapiMsg;
 #define PROMPTBEG      '\001'  /* start prompt bracket */
 #define PROMPT1                "\001\001\n"    /* prompt: ready for new query 
*/
 #define PROMPT2                "\001\002\n"    /* prompt: more data needed */
+#define PROMPT3_PREFIX         "\001\003"      /* prompt: read and transmit 
the contents of a file */
 
 /*
  * The table field information is extracted from the table headers
_______________________________________________
checkin-list mailing list
checkin-list@monetdb.org
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to