Changeset: eca8a61ef6bb for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/eca8a61ef6bb
Modified Files:
        monetdb5/modules/mal/tablet.c
        sql/test/copy/Tests/incorrect_columns.test
        sql/test/copy/Tests/int_parse_best.test
        sql/test/copy/Tests/load_stdin_incorrect_line_nr.test
        sql/test/copy/Tests/null_as_string_errors.test
Branch: Sep2022
Log Message:

Fixed up error reporting from COPY INTO.
All error reporting should go through the function tablet_error.
Before, if a HEAPextend failed during COPY INTO, I got a message from
algebra.select about Object missing!  Now we get the proper error from
COPY INTO itself.
Also, the strings in the sys.reject table now no longer contain line and
column numbers since they are already available in separate columns.


diffs (truncated from 376 to 300 lines):

diff --git a/monetdb5/modules/mal/tablet.c b/monetdb5/modules/mal/tablet.c
--- a/monetdb5/modules/mal/tablet.c
+++ b/monetdb5/modules/mal/tablet.c
@@ -613,6 +613,8 @@ typedef struct {
        bool ateof;                                     /* io control */
        bool from_stdin;
        bool escape;                            /* whether to handle \ escapes 
*/
+       bool besteffort;
+       char quote;
        bstream *b;
        stream *out;
        MT_Id tid;
@@ -624,7 +626,6 @@ typedef struct {
        char *errbuf;
        const char *csep, *rsep;
        size_t seplen, rseplen;
-       char quote;
 
        char *base[MAXBUFFERS], *input[MAXBUFFERS];     /* buffers for row 
splitter and tokenizer */
        size_t rowlimit[MAXBUFFERS]; /* determines maximal record length buffer 
*/
@@ -635,34 +636,50 @@ typedef struct {
 
        int *cols;                                      /* columns to handle */
        char ***fields;
-       int besteffort;
        bte *rowerror;
        int errorcnt;
 } READERtask;
 
+/* note, the column value that is passed here is the 0 based value; the
+ * lineno value on the other hand is 1 based */
 static void
-tablet_error(READERtask *task, lng row, lng lineno, int col, const char *msg, 
const char *fcn)
+tablet_error(READERtask *task, lng idx, lng lineno, int col, const char *msg, 
const char *fcn)
 {
+       assert(is_int_nil(col) || col >= 0);
+       assert(is_lng_nil(lineno) || lineno >= 1);
        MT_lock_set(&errorlock);
-       if (task->cntxt->error_row != NULL) {
-               if (BUNappend(task->cntxt->error_row, &lineno, false) != 
GDK_SUCCEED ||
-                       BUNappend(task->cntxt->error_fld, &col, false) != 
GDK_SUCCEED ||
-                       BUNappend(task->cntxt->error_msg, msg, false) != 
GDK_SUCCEED ||
-                       BUNappend(task->cntxt->error_input, fcn, false) != 
GDK_SUCCEED)
-                       task->besteffort = 0;
-               if (!is_lng_nil(row) && task->rowerror && row < task->limit)
-                       task->rowerror[row]++;
+       if (task->cntxt->error_row != NULL &&
+               (BUNappend(task->cntxt->error_row, &lineno, false) != 
GDK_SUCCEED ||
+                BUNappend(task->cntxt->error_fld, &(int){col+1}, false) != 
GDK_SUCCEED ||
+                BUNappend(task->cntxt->error_msg, msg, false) != GDK_SUCCEED ||
+                BUNappend(task->cntxt->error_input, fcn, false) != 
GDK_SUCCEED)) {
+               task->besteffort = false;
        }
+       if (!is_lng_nil(idx) && task->rowerror && idx < task->limit)
+               task->rowerror[idx]++;
        if (task->as->error == NULL) {
-               if (msg == NULL)
-                       task->besteffort = 0;
-               else if (!is_lng_nil(lineno)) {
-                       if (!is_int_nil(col))
-                               task->as->error = createException(MAL, 
"sql.copy_from", "line " LLFMT ": column %d: %s", lineno, col + 1, msg);
-                       else
+               const char *colnam = is_int_nil(col) || col < 0 || (BUN) col >= 
task->as->nr_attrs ? NULL : task->as->format[col].name;
+               if (msg == NULL) {
+                       task->besteffort = false;
+               } else if (!is_lng_nil(lineno)) {
+                       if (!is_int_nil(col)) {
+                               if (colnam)
+                                       task->as->error = createException(MAL, 
"sql.copy_from", "line " LLFMT ": column %d %s: %s", lineno, col + 1, colnam, 
msg);
+                               else
+                                       task->as->error = createException(MAL, 
"sql.copy_from", "line " LLFMT ": column %d: %s", lineno, col + 1, msg);
+                       } else {
                                task->as->error = createException(MAL, 
"sql.copy_from", "line " LLFMT ": %s", lineno, msg);
-               } else
-                       task->as->error = createException(MAL, "sql.copy_from", 
"%s", msg);
+                       }
+               } else {
+                       if (!is_int_nil(col)) {
+                               if (colnam)
+                                       task->as->error = createException(MAL, 
"sql.copy_from", "column %d %s: %s", col + 1, colnam, msg);
+                               else
+                                       task->as->error = createException(MAL, 
"sql.copy_from", "column %d: %s", col + 1, msg);
+                       } else {
+                               task->as->error = createException(MAL, 
"sql.copy_from", "%s", msg);
+                       }
+               }
        }
        task->errorcnt++;
        MT_lock_unset(&errorlock);
@@ -782,9 +799,9 @@ SQLload_error(READERtask *task, lng idx,
        }
 
        s = line = GDKmalloc(sz + task->rseplen + 1);
-       if (line == 0) {
+       if (line == NULL) {
                tablet_error(task, idx, lng_nil, int_nil, "SQLload malloc 
error", "SQLload_error");
-               return 0;
+               return NULL;
        }
        for (i = 0; i < attrs; i++) {
                if (task->fields[i][idx])
@@ -817,7 +834,7 @@ SQLinsert_val(READERtask *task, int col,
        int ret = 0;
 
        /* include testing on the terminating null byte !! */
-       if (s == 0) {
+       if (s == NULL) {
                adt = fmt->nildata;
                fmt->c->tnonil = false;
        } else {
@@ -835,61 +852,32 @@ SQLinsert_val(READERtask *task, int col,
                        adt = fmt->frstr(fmt, fmt->adt, s);
        }
 
-       /* col is zero-based, but for error messages it needs to be
-        * one-based, and from here on, we only use col anymore to produce
-        * error messages */
-       col++;
-
+       lng row = BATcount(fmt->c) + 1;
        if (adt == NULL) {
-               lng row = task->cnt + idx + 1;
-               snprintf(buf, sizeof(buf), "'%s' expected", fmt->type);
-               err = SQLload_error(task, idx, task->as->nr_attrs);
                if (task->rowerror) {
+                       err = SQLload_error(task, idx, task->as->nr_attrs);
                        if (s) {
                                size_t slen = mystrlen(s);
                                char *scpy = GDKmalloc(slen + 1);
                                if ( scpy == NULL){
-                                       task->rowerror[idx]++;
-                                       task->errorcnt++;
-                                       task->besteffort = 0; /* no longer best 
effort */
-                                       if (task->cntxt->error_row == NULL ||
-                                               
BUNappend(task->cntxt->error_row, &row, false) != GDK_SUCCEED ||
-                                               
BUNappend(task->cntxt->error_fld, &col, false) != GDK_SUCCEED ||
-                                               
BUNappend(task->cntxt->error_msg, SQLSTATE(HY013) MAL_MALLOC_FAIL, false) != 
GDK_SUCCEED ||
-                                               
BUNappend(task->cntxt->error_input, err, false) != GDK_SUCCEED) {
-                                               ;               /* ignore error 
here: we're already not best effort */
-                                       }
+                                       tablet_error(task, idx, row, col, 
SQLSTATE(HY013) MAL_MALLOC_FAIL, err);
+                                       task->besteffort = false; /* no longer 
best effort */
                                        GDKfree(err);
                                        return -1;
                                }
                                mycpstr(scpy, s);
                                s = scpy;
                        }
-                       MT_lock_set(&errorlock);
-                       snprintf(buf, sizeof(buf),
-                                        "line " LLFMT " field %s '%s' 
expected%s%s%s",
-                                        task->startlineno[task->cur][idx], 
fmt->name ? fmt->name : "", fmt->type,
-                                        s ? " in '" : "", s ? s : "", s ? "'" 
: "");
+                       snprintf(buf, sizeof(buf), "'%s' expected%s%s%s",
+                                        fmt->type, s ? " in '" : "", s ? s : 
"", s ? "'" : "");
                        GDKfree(s);
-                       if (task->as->error == NULL && (task->as->error = 
GDKstrdup(buf)) == NULL)
-                               task->as->error = createException(MAL, 
"sql.copy_from", SQLSTATE(HY013) MAL_MALLOC_FAIL);
-                       task->rowerror[idx]++;
-                       task->errorcnt++;
-                       if (task->cntxt->error_row == NULL ||
-                               BUNappend(task->cntxt->error_row, &row, false) 
!= GDK_SUCCEED ||
-                               BUNappend(task->cntxt->error_fld, &col, false) 
!= GDK_SUCCEED ||
-                               BUNappend(task->cntxt->error_msg, buf, false) 
!= GDK_SUCCEED ||
-                               BUNappend(task->cntxt->error_input, err, false) 
!= GDK_SUCCEED) {
-                               GDKfree(err);
-                               task->besteffort = 0; /* no longer best effort 
*/
-                               MT_lock_unset(&errorlock);
+                       tablet_error(task, idx, row, col, buf, err);
+                       GDKfree(err);
+                       if (!task->besteffort)
                                return -1;
-                       }
                        MT_lock_unset(&errorlock);
                }
                ret = -!task->besteffort; /* yep, two unary operators ;-) */
-               GDKfree(err);
-               err = NULL;
                /* replace it with a nil */
                adt = fmt->nildata;
                fmt->c->tnonil = false;
@@ -899,21 +887,12 @@ SQLinsert_val(READERtask *task, int col,
 
        /* failure */
        if (task->rowerror) {
-               lng row = BATcount(fmt->c);
-               MT_lock_set(&errorlock);
-               if (task->cntxt->error_row == NULL ||
-                       BUNappend(task->cntxt->error_row, &row, false) != 
GDK_SUCCEED ||
-                       BUNappend(task->cntxt->error_fld, &col, false) != 
GDK_SUCCEED ||
-                       BUNappend(task->cntxt->error_msg, "insert failed", 
false) != GDK_SUCCEED ||
-                       (err = SQLload_error(task, idx,task->as->nr_attrs)) == 
NULL ||
-                       BUNappend(task->cntxt->error_input, err, false) != 
GDK_SUCCEED)
-                       task->besteffort = 0;
+               char *msg = GDKerrbuf;
+               err = SQLload_error(task, idx,task->as->nr_attrs);
+               tablet_error(task, idx, row, col, msg && *msg ? msg : "insert 
failed", err);
                GDKfree(err);
-               task->rowerror[idx]++;
-               task->errorcnt++;
-               MT_lock_unset(&errorlock);
        }
-       task->besteffort = 0;           /* no longer best effort */
+       task->besteffort = false;               /* no longer best effort */
        return -1;
 }
 
@@ -966,7 +945,7 @@ SQLload_parse_row(READERtask *task, int 
        Tablet *as = task->as;
        Column *fmt = as->format;
        bool error = false;
-       str errline = 0;
+       str errline = NULL;
 
        assert(idx < task->top[task->cur]);
        assert(row);
@@ -985,7 +964,7 @@ SQLload_parse_row(READERtask *task, int 
                                if (!row) {
                                        errline = SQLload_error(task, idx, i+1);
                                        snprintf(errmsg, BUFSIZ, "Quote (%c) 
missing", task->quote);
-                                       tablet_error(task, idx, startlineno, 
(int) i + 1, errmsg, errline);
+                                       tablet_error(task, idx, startlineno, 
(int) i, errmsg, errline);
                                        GDKfree(errline);
                                        error = true;
                                        goto errors1;
@@ -1007,6 +986,7 @@ SQLload_parse_row(READERtask *task, int 
                        /* not enough fields */
                        if (i < as->nr_attrs - 1) {
                                errline = SQLload_error(task, idx, i+1);
+                               /* it's the next value that is missing */
                                tablet_error(task, idx, startlineno, (int) i + 
1, "Column value missing", errline);
                                GDKfree(errline);
                                error = true;
@@ -1042,6 +1022,7 @@ SQLload_parse_row(READERtask *task, int 
                        /* not enough fields */
                        if (i < as->nr_attrs - 1) {
                                errline = SQLload_error(task, idx,i+1);
+                               /* it's the next value that is missing */
                                tablet_error(task, idx, startlineno, (int) i + 
1, "Column value missing", errline);
                                GDKfree(errline);
                                error = true;
@@ -1062,7 +1043,7 @@ SQLload_parse_row(READERtask *task, int 
        if (row && *row && i == as->nr_attrs) {
                errline = SQLload_error(task, idx, task->as->nr_attrs);
                snprintf(errmsg, BUFSIZ, "Leftover data '%s'",row);
-               tablet_error(task, idx, startlineno, (int) i + 1, errmsg, 
errline);
+               tablet_error(task, idx, startlineno, (int) i, errmsg, errline);
                GDKfree(errline);
                error = true;
        }
@@ -1129,7 +1110,7 @@ SQLworker(void *arg)
 
   do_return:
        GDKfree(GDKerrbuf);
-       GDKsetbuf(0);
+       GDKsetbuf(NULL);
 }
 
 static void
@@ -1147,7 +1128,7 @@ SQLworkdivider(READERtask *task, READERt
                        ptask[j % threads].cols[i] = task->cols[i];
                return;
        }
-       memset((char *) loc, 0, sizeof(lng) * MAXWORKERS);
+       memset(loc, 0, sizeof(loc));
        /* use of load directives */
        for (i = 0; i < nr_attrs; i++)
                for (j = 0; j < threads; j++)
diff --git a/sql/test/copy/Tests/incorrect_columns.test 
b/sql/test/copy/Tests/incorrect_columns.test
--- a/sql/test/copy/Tests/incorrect_columns.test
+++ b/sql/test/copy/Tests/incorrect_columns.test
@@ -31,11 +31,11 @@ query IITT rowsort
 select * from sys.rejects()
 ----
 2
-1
+2
 Column value missing
 2@
 3
-1
+2
 Column value missing
 no tag@
 4
diff --git a/sql/test/copy/Tests/int_parse_best.test 
b/sql/test/copy/Tests/int_parse_best.test
--- a/sql/test/copy/Tests/int_parse_best.test
+++ b/sql/test/copy/Tests/int_parse_best.test
@@ -64,7 +64,7 @@ select * from sys.rejects
 ----
 2
 1
-line 2 field i 'int' expected in '5.1'
+'int' expected in '5.1'
 5.1@
 
 statement ok
@@ -93,15 +93,15 @@ select * from sys.rejects
 ----
 2
_______________________________________________
checkin-list mailing list -- checkin-list@monetdb.org
To unsubscribe send an email to checkin-list-le...@monetdb.org

Reply via email to