static int vtxt_column (sqlite3_vtab_cursor * pCursor, sqlite3_context * pContext, int column) { /* fetching value for the Nth column */ int nCol = 1; int i; char buf[4096]; int type; const char *value; VirtualTextCursorPtr cursor = (VirtualTextCursorPtr) pCursor; gaiaTextReaderPtr text = cursor->pVtab->reader; if (column == 0) { /* the ROWNO column */ sqlite3_result_int (pContext, cursor->current_row); return SQLITE_OK; } if (text->current_line_ready == 0) return SQLITE_ERROR; for (i = 0; i < text->max_fields; i++) { if (nCol == column) { if (!gaiaTextReaderFetchField (text, i, &type, &value)) sqlite3_result_null (pContext); else { if (type == VRTTXT_INTEGER) { strcpy (buf, value); text_clean_integer (buf); #if defined(_WIN32) || defined(__MINGW32__) /* CAVEAT - M$ runtime has non-standard functions for 64 bits */ sqlite3_result_int64 (pContext, _atoi64 (buf)); #else sqlite3_result_int64 (pContext, atoll (buf)); #endif } else if (type == VRTTXT_DOUBLE) { strcpy (buf, value); text_clean_double (buf); sqlite3_result_double (pContext, atof (buf)); } else if (type == VRTTXT_TEXT) sqlite3_result_text (pContext, value, strlen (value), free); else sqlite3_result_null (pContext); } } nCol++; } return SQLITE_OK; }
static int vtxt_eval_constraints (VirtualTextCursorPtr cursor) { /* evaluating Filter constraints */ int nCol; int i; char buf[4096]; int type; const char *value = NULL; sqlite3_int64 int_value; double dbl_value; char *txt_value = NULL; int is_int = 0; int is_dbl = 0; int is_txt = 0; gaiaTextReaderPtr text = cursor->pVtab->reader; VirtualTextConstraintPtr pC; if (text->current_line_ready == 0) return SQLITE_ERROR; pC = cursor->firstConstraint; while (pC) { int ok = 0; if (pC->iColumn == 0) { /* the ROWNO column */ int_value = cursor->current_row; is_int = 1; goto eval; } nCol = 1; for (i = 0; i < text->max_fields; i++) { is_int = 0; is_dbl = 0; is_txt = 0; if (nCol == pC->iColumn) { if (!gaiaTextReaderFetchField (text, i, &type, &value)) ; else { if (type == VRTTXT_INTEGER) { strcpy (buf, value); text_clean_integer (buf); #if defined(_WIN32) || defined(__MINGW32__) /* CAVEAT - M$ runtime has non-standard functions for 64 bits */ int_value = _atoi64 (buf); #else int_value = atoll (buf); #endif is_int = 1; } else if (type == VRTTXT_DOUBLE) { strcpy (buf, value); text_clean_double (buf); dbl_value = atof (buf); is_dbl = 1; } else if (type == VRTTXT_TEXT) { txt_value = (char *) value; is_txt = 1; } } goto eval; } nCol++; } return 0; eval: ok = 0; if (pC->valueType == 'I') { if (is_int) { switch (pC->op) { case SQLITE_INDEX_CONSTRAINT_EQ: if (int_value == pC->intValue) ok = 1; break; case SQLITE_INDEX_CONSTRAINT_GT: if (int_value > pC->intValue) ok = 1; break; case SQLITE_INDEX_CONSTRAINT_LE: if (int_value <= pC->intValue) ok = 1; break; case SQLITE_INDEX_CONSTRAINT_LT: if (int_value < pC->intValue) ok = 1; break; case SQLITE_INDEX_CONSTRAINT_GE: if (int_value >= pC->intValue) ok = 1; break; }; } if (is_dbl) { switch (pC->op) { case SQLITE_INDEX_CONSTRAINT_EQ: if (dbl_value == pC->intValue) ok = 1; break; case SQLITE_INDEX_CONSTRAINT_GT: if (dbl_value > pC->intValue) ok = 1; break; case SQLITE_INDEX_CONSTRAINT_LE: if (dbl_value <= pC->intValue) ok = 1; break; case SQLITE_INDEX_CONSTRAINT_LT: if (dbl_value < pC->intValue) ok = 1; break; case SQLITE_INDEX_CONSTRAINT_GE: if (dbl_value >= pC->intValue) ok = 1; break; }; } } if (pC->valueType == 'D') { if (is_int) { switch (pC->op) { case SQLITE_INDEX_CONSTRAINT_EQ: if (int_value == pC->dblValue) ok = 1; break; case SQLITE_INDEX_CONSTRAINT_GT: if (int_value > pC->dblValue) ok = 1; break; case SQLITE_INDEX_CONSTRAINT_LE: if (int_value <= pC->dblValue) ok = 1; break; case SQLITE_INDEX_CONSTRAINT_LT: if (int_value < pC->dblValue) ok = 1; break; case SQLITE_INDEX_CONSTRAINT_GE: if (int_value >= pC->dblValue) ok = 1; break; }; } if (is_dbl) { switch (pC->op) { case SQLITE_INDEX_CONSTRAINT_EQ: if (dbl_value == pC->dblValue) ok = 1; break; case SQLITE_INDEX_CONSTRAINT_GT: if (dbl_value > pC->dblValue) ok = 1; break; case SQLITE_INDEX_CONSTRAINT_LE: if (dbl_value <= pC->dblValue) ok = 1; break; case SQLITE_INDEX_CONSTRAINT_LT: if (dbl_value < pC->dblValue) ok = 1; break; case SQLITE_INDEX_CONSTRAINT_GE: if (dbl_value >= pC->dblValue) ok = 1; break; }; } } if (pC->valueType == 'T') { if (is_txt) { int ret = strcmp (txt_value, pC->txtValue); switch (pC->op) { case SQLITE_INDEX_CONSTRAINT_EQ: if (ret == 0) ok = 1; break; case SQLITE_INDEX_CONSTRAINT_GT: if (ret > 0) ok = 1; break; case SQLITE_INDEX_CONSTRAINT_LE: if (ret <= 0) ok = 1; break; case SQLITE_INDEX_CONSTRAINT_LT: if (ret < 0) ok = 1; break; case SQLITE_INDEX_CONSTRAINT_GE: if (ret >= 0) ok = 1; break; }; } } if (txt_value) { free (txt_value); txt_value = NULL; } if (!ok) return 0; pC = pC->next; } if (txt_value) free (txt_value); return 1; }
static struct text_buffer * text_parse (char *path, char *encoding, char first_line_titles, char field_separator, char text_separator, char decimal_separator) { /* trying to open and parse the text file */ int c; int fld; int len; int max_cell; int is_string = 0; char last = '\0'; char *fields[4096]; char buffer[35536]; char *p = buffer; struct text_buffer *text; int nrows; int ncols; int errs; struct row_buffer *row; void *toUtf8; int encoding_errors; int ir; char title[64]; char *first_valid_row; int i; char *name; for (fld = 0; fld < 4096; fld++) { /* preparing an empty row */ fields[fld] = NULL; } /* trying to open the text file */ FILE *in = fopen (path, "rb"); if (!in) return NULL; text = text_buffer_alloc (); fld = 0; while ((c = getc (in)) != EOF) { /* parsing the file, one char at each time */ if (c == '\r' && !is_string) { last = c; continue; } if (c == field_separator && !is_string) { /* insering a field into the fields tmp array */ last = c; *p = '\0'; len = strlen (buffer); if (len) { fields[fld] = malloc (len + 1); strcpy (fields[fld], buffer); } fld++; p = buffer; *p = '\0'; continue; } if (c == text_separator) { /* found a text separator */ if (is_string) { is_string = 0; last = c; } else { if (last == text_separator) *p++ = text_separator; is_string = 1; } continue; } last = c; if (c == '\n' && !is_string) { /* inserting the row into the text buffer */ *p = '\0'; len = strlen (buffer); if (len) { fields[fld] = malloc (len + 1); strcpy (fields[fld], buffer); } fld++; p = buffer; *p = '\0'; max_cell = -1; for (fld = 0; fld < 4096; fld++) { if (fields[fld]) max_cell = fld; } text_insert_row (text, fields, max_cell); for (fld = 0; fld < 4096; fld++) { /* resetting an empty row */ fields[fld] = NULL; } fld = 0; continue; } *p++ = c; } fclose (in); /* checking if the text file really seems to contain a table */ nrows = 0; ncols = 0; errs = 0; row = text->first; while (row) { if (first_line_titles && row == text->first) { /* skipping first line */ row = row->next; continue; } nrows++; if (row->n_cells > ncols) ncols = row->n_cells; row = row->next; } if (nrows == 0 && ncols == 0) { text_buffer_free (text); return NULL; } text->n_rows = nrows; /* going to check the column types */ text->max_n_cells = ncols; text->types = malloc (sizeof (char) * text->max_n_cells); first_valid_row = malloc (sizeof (char) * text->max_n_cells); for (fld = 0; fld < text->max_n_cells; fld++) { /* initally assuming any cell contains TEXT */ *(text->types + fld) = VRTTXT_TEXT; *(first_valid_row + fld) = 1; } row = text->first; while (row) { if (first_line_titles && row == text->first) { /* skipping first line */ row = row->next; continue; } for (fld = 0; fld < row->n_cells; fld++) { if (*(row->cells + fld)) { if (text_is_integer (*(row->cells + fld))) { if (*(first_valid_row + fld)) { *(text->types + fld) = VRTTXT_INTEGER; *(first_valid_row + fld) = 0; } } else if (text_is_double (*(row->cells + fld), decimal_separator)) { if (*(first_valid_row + fld)) { *(text->types + fld) = VRTTXT_DOUBLE; *(first_valid_row + fld) = 0; } else { /* promoting an INTEGER column to be of the DOUBLE type */ if (*(text->types + fld) == VRTTXT_INTEGER) *(text->types + fld) = VRTTXT_DOUBLE; } } else { /* this column is anyway of the TEXT type */ *(text->types + fld) = VRTTXT_TEXT; if (*(first_valid_row + fld)) *(first_valid_row + fld) = 0; } } } row = row->next; } free (first_valid_row); /* preparing the column names */ text->titles = malloc (sizeof (char *) * text->max_n_cells); if (first_line_titles) { for (fld = 0; fld < text->max_n_cells; fld++) { if (fld >= text->first->n_cells) { /* this column name is NULL; setting a default name */ sprintf (title, "COL%03d", fld + 1); len = strlen (title); *(text->titles + fld) = malloc (len + 1); strcpy (*(text->titles + fld), title); } else { if (*(text->first->cells + fld)) { len = strlen (*(text->first->cells + fld)); *(text->titles + fld) = malloc (len + 1); strcpy (*(text->titles + fld), *(text->first->cells + fld)); name = *(text->titles + fld); for (i = 0; i < len; i++) { /* masking any space in the column name */ if (*(name + i) == ' ') *(name + i) = '_'; } } else { /* this column name is NULL; setting a default name */ sprintf (title, "COL%03d", fld + 1); len = strlen (title); *(text->titles + fld) = malloc (len + 1); strcpy (*(text->titles + fld), title); } } } } else { for (fld = 0; fld < text->max_n_cells; fld++) { sprintf (title, "COL%03d", fld + 1); len = strlen (title); *(text->titles + fld) = malloc (len + 1); strcpy (*(text->titles + fld), title); } } /* cleaning cell values when needed */ toUtf8 = iconvCreateUTF8Converter (encoding); if (!toUtf8) { text_buffer_free (text); return NULL; } encoding_errors = 0; row = text->first; while (row) { if (first_line_titles && row == text->first) { /* skipping first line */ row = row->next; continue; } for (fld = 0; fld < row->n_cells; fld++) { if (*(row->cells + fld)) { if (*(text->types + fld) == VRTTXT_INTEGER) text_clean_integer (*(row->cells + fld)); else if (*(text->types + fld) == VRTTXT_DOUBLE) text_clean_double (*(row->cells + fld)); else encoding_errors += text_clean_text (row->cells + fld, toUtf8); } } row = row->next; } iconvFreeUTF8Converter (toUtf8); if (encoding_errors) { text_buffer_free (text); return NULL; } /* ok, we can now go to prepare the rows array */ text->rows = malloc (sizeof (struct text_row *) * text->n_rows); ir = 0; row = text->first; while (row) { if (first_line_titles && row == text->first) { /* skipping first line */ row = row->next; continue; } *(text->rows + ir++) = row; row = row->next; } return text; }