Changeset: c14ea353b4cd for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=c14ea353b4cd
Modified Files:
        sql/backends/monet5/sql.c
        sql/server/rel_updates.c
        sql/server/sql_parser.y
Branch: default
Log Message:

Update COPY BINARY INTO to accept a column list (like COPY FROM).

This is accomplished by passing str:nil instead of a filename for columns that 
are not mentioned. Missing columns are then filled with NULL values.


diffs (202 lines):

diff --git a/sql/backends/monet5/sql.c b/sql/backends/monet5/sql.c
--- a/sql/backends/monet5/sql.c
+++ b/sql/backends/monet5/sql.c
@@ -3635,6 +3635,7 @@ mvc_bin_import_table_wrap(Client cntxt, 
        mvc *m = NULL;
        str msg;
        BUN cnt = 0;
+       int init = 0;
        int i;
        str sname = *getArgReference_str(stk, pci, 0 + pci->retc);
        str tname = *getArgReference_str(stk, pci, 1 + pci->retc);
@@ -3661,9 +3662,15 @@ mvc_bin_import_table_wrap(Client cntxt, 
        for (i = pci->retc + 2, n = t->columns.set->h; i < pci->argc && n; i++, 
n = n->next) {
                sql_column *col = n->data;
                const char *fname = *getArgReference_str(stk, pci, i);
-               size_t flen = strlen(fname);
+               size_t flen;
                char *fn;
 
+               if (strcmp(fname, str_nil) == 0)  {
+                       // no file name passed for this column
+                       continue;
+               }
+               flen =  strlen(fname);
+
                if (ATOMvarsized(col->type.type->localtype) && 
col->type.type->localtype != TYPE_str)
                        throw(SQL, "sql", "Failed to attach file %s", 
*getArgReference_str(stk, pci, i));
                fn = GDKmalloc(flen + 1);
@@ -3684,12 +3691,16 @@ mvc_bin_import_table_wrap(Client cntxt, 
                sql_column *col = n->data;
                BAT *c = NULL;
                int tpe = col->type.type->localtype;
+               str fname = *getArgReference_str(stk, pci, i);
 
                /* handle the various cases */
-               if (tpe < TYPE_str || tpe == TYPE_date || tpe == TYPE_daytime 
|| tpe == TYPE_timestamp) {
-                       c = BATattach(col->type.type->localtype, 
*getArgReference_str(stk, pci, i), PERSISTENT);
+               if (strcmp(fname, str_nil) == 0) {
+                       // no filename for this column, skip for now because we 
potentially don't know the count yet
+                       continue;
+               } else if (tpe < TYPE_str || tpe == TYPE_date || tpe == 
TYPE_daytime || tpe == TYPE_timestamp) {
+                       c = BATattach(col->type.type->localtype, fname, 
PERSISTENT);
                        if (c == NULL)
-                               throw(SQL, "sql", "Failed to attach file %s", 
*getArgReference_str(stk, pci, i));
+                               throw(SQL, "sql", "Failed to attach file %s", 
fname);
                        BATsetaccess(c, BAT_READ);
                } else if (tpe == TYPE_str) {
                        /* get the BAT and fill it with the strings */
@@ -3699,7 +3710,7 @@ mvc_bin_import_table_wrap(Client cntxt, 
                        /* this code should be extended to deal with larger 
text strings. */
                        f = fopen(*getArgReference_str(stk, pci, i), "r");
                        if (f == NULL)
-                               throw(SQL, "sql", "Failed to re-open file %s", 
*getArgReference_str(stk, pci, i));
+                               throw(SQL, "sql", "Failed to re-open file %s", 
fname);
 
                        buf = GDKmalloc(bufsiz);
                        if (!buf) {
@@ -3715,14 +3726,35 @@ mvc_bin_import_table_wrap(Client cntxt, 
                        fclose(f);
                        GDKfree(buf);
                } else {
-                       throw(SQL, "sql", "Failed to attach file %s", 
*getArgReference_str(stk, pci, i));
+                       throw(SQL, "sql", "Failed to attach file %s", fname);
                }
-               if (i != (pci->retc + 2) && cnt != BATcount(c))
+               if (init && cnt != BATcount(c))
                        throw(SQL, "sql", "binary files for table '%s' have 
inconsistent counts", tname);
                cnt = BATcount(c);
+               init = 1;
                *getArgReference_bat(stk, pci, i - (2 + pci->retc)) = 
c->batCacheid;
                BBPkeepref(c->batCacheid);
        }
+       if (init) {
+               for (i = pci->retc + 2, n = t->columns.set->h; i < pci->argc && 
n; i++, n = n->next) {
+                       // now that we know the BAT count, we can fill in the 
columns for which no parameters were pasesd
+                       sql_column *col = n->data;
+                       BAT *c = NULL;
+                       int tpe = col->type.type->localtype;
+
+                       str fname = *getArgReference_str(stk, pci, i);
+                       if (strcmp(fname, str_nil) == 0) {
+                               BUN loop = 0;
+                               const void* nil = ATOMnilptr(tpe);
+                               c = COLnew(0, tpe, cnt, PERSISTENT);
+                               for(loop = 0; loop < cnt; loop++) {
+                                       BUNappend(c, nil, 0);
+                               }
+                               *getArgReference_bat(stk, pci, i - (2 + 
pci->retc)) = c->batCacheid;
+                               BBPkeepref(c->batCacheid);
+                       }
+               }
+       } 
        return MAL_SUCCEED;
 }
 
diff --git a/sql/server/rel_updates.c b/sql/server/rel_updates.c
--- a/sql/server/rel_updates.c
+++ b/sql/server/rel_updates.c
@@ -1415,7 +1415,7 @@ copyfrom(mvc *sql, dlist *qname, dlist *
 }
 
 static sql_rel *
-bincopyfrom(mvc *sql, dlist *qname, dlist *files, int constraint)
+bincopyfrom(mvc *sql, dlist *qname, dlist *columns, dlist *files, int 
constraint)
 {
        char *sname = qname_schema(qname);
        char *tname = qname_table(qname);
@@ -1426,11 +1426,14 @@ bincopyfrom(mvc *sql, dlist *qname, dlis
        node *n;
        sql_rel *res;
        list *exps, *args;
-       sql_subtype tpe;
+       sql_subtype strtpe;
        sql_exp *import;
        sql_schema *sys = mvc_bind_schema(sql, "sys");
        sql_subfunc *f = sql_find_func(sql->sa, sys, "copyfrom", 2, F_UNION, 
NULL); 
+       list *collist;
+       size_t i;
 
+       assert(f);
        if (!copy_allowed(sql, 1)) {
                (void) sql_error(sql, 02, "COPY INTO: insufficient privileges: "
                                "binary COPY INTO requires database 
administrator rights");
@@ -1455,18 +1458,37 @@ bincopyfrom(mvc *sql, dlist *qname, dlis
        if (files == NULL)
                return sql_error(sql, 02, "COPY INTO: must specify files");
 
+       collist = check_table_columns(sql, t, columns, "COPY BINARY", tname);
+       if (!collist)
+               return NULL;
+
        f->res = table_column_types(sql->sa, t);
-       sql_find_subtype(&tpe, "varchar", 0, 0);
-       args = append( append( new_exp_list(sql->sa), 
-               exp_atom_str(sql->sa, t->s?t->s->base.name:NULL, &tpe)), 
-               exp_atom_str(sql->sa, t->base.name, &tpe));
+       sql_find_subtype(&strtpe, "varchar", 0, 0);
+       args = append( append( new_exp_list(sql->sa),
+               exp_atom_str(sql->sa, t->s?t->s->base.name:NULL, &strtpe)), 
+               exp_atom_str(sql->sa, t->base.name, &strtpe));
 
-       for (dn = files->h; dn; dn = dn->next) {
-               append(args, exp_atom_str(sql->sa, dn->data.sval, &tpe)); 
+       // create the list of files that is passed to the function as parameter
+       for(i = 0; i < t->columns.set->cnt; i++) {
+               // we have one file per column, however, because we have column 
selection that file might be NULL
+               // first, check if this column number is present in the passed 
in the parameters
+               int found = 0;
+               dn = files->h;
+               for (n = collist->h; n && dn; n = n->next, dn = dn->next) {
+                       sql_column *c = n->data;
+                       if (i == c->colnr) {
+                               // this column number was present in the input 
arguments; pass in the file name
+                               append(args, exp_atom_str(sql->sa, 
dn->data.sval, &strtpe)); 
+                               found = 1;
+                               break;
+                       }
+               }
+               if (!found) {
+                       // this column was not present in the input arguments; 
pass in NULL
+                       append(args, exp_atom_str(sql->sa, NULL, &strtpe)); 
+               }
+       }
 
-               /* extend the bincopyfrom, with extra args and types */
-       }
-       
        import = exp_op(sql->sa,  args, f); 
 
        exps = new_exp_list(sql->sa);
@@ -1696,7 +1718,7 @@ rel_updates(mvc *sql, symbol *s)
        {
                dlist *l = s->data.lval;
 
-               ret = bincopyfrom(sql, l->h->data.lval, l->h->next->data.lval, 
l->h->next->next->data.i_val);
+               ret = bincopyfrom(sql, l->h->data.lval, l->h->next->data.lval, 
l->h->next->next->data.lval, l->h->next->next->next->data.i_val);
                sql->type = Q_UPDATE;
        }
                break;
diff --git a/sql/server/sql_parser.y b/sql/server/sql_parser.y
--- a/sql/server/sql_parser.y
+++ b/sql/server/sql_parser.y
@@ -2567,15 +2567,16 @@ copyfrom_stmt:
          append_list(l, $4);
          append_symbol(l, $6);
          $$ = _symbol_create_list( SQL_COPYLOADER, l ); }
-   | COPY opt_nr BINARY INTO qname FROM string_commalist /* binary copy from 
*/ opt_constraint
+   | COPY opt_nr BINARY INTO qname opt_column_list FROM string_commalist /* 
binary copy from */ opt_constraint
        { dlist *l = L();
          if ($2 != NULL) {
                yyerror(m, "COPY INTO: cannot pass number of records when using 
binary COPY INTO");
                YYABORT;
          }
          append_list(l, $5);
-         append_list(l, $7);
-         append_int(l, $8);
+         append_list(l, $6);
+         append_list(l, $8);
+         append_int(l, $9);
          $$ = _symbol_create_list( SQL_BINCOPYFROM, l ); }
   | COPY query_expression_def INTO string opt_seps opt_null_string 
        { dlist *l = L();
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to