diff options
Diffstat (limited to 'lang/sql/odbc/blobtoxy.c')
-rw-r--r-- | lang/sql/odbc/blobtoxy.c | 634 |
1 files changed, 422 insertions, 212 deletions
diff --git a/lang/sql/odbc/blobtoxy.c b/lang/sql/odbc/blobtoxy.c index 638bb2e8..09f1d5aa 100644 --- a/lang/sql/odbc/blobtoxy.c +++ b/lang/sql/odbc/blobtoxy.c @@ -1,12 +1,12 @@ -/* +/** * @file blobtoxy.c * SQLite extension module for read-only BLOB to X/Y mapping * using SQLite 3.3.x virtual table API plus some useful * scalar and aggregate functions. * - * $Id: blobtoxy.c,v 1.19 2011/08/21 10:11:24 chw Exp chw $ + * $Id: blobtoxy.c,v 1.22 2013/01/11 12:19:55 chw Exp chw $ * - * Copyright (c) 2007-2011 Christian Werner <chw@ch-werner.de> + * Copyright (c) 2007-2013 Christian Werner <chw@ch-werner.de> * * See the file "license.terms" for information on usage * and redistribution of this file and for a @@ -30,71 +30,71 @@ * CREATE VIRTUAL TABLE t1 * USING blobtoxy (t, key, data, short_le, x_scale, x_offset, * y_scale, y_offset, "foo, bar"); - * CREATE VIRTUAL TABLE t2 + * <br>CREATE VIRTUAL TABLE t2 * USING blobtoxy (t, key, data, uchar, null, null, null, null, 'bar'); - * CREATE VIRTUAL TABLE t3 + * <br>CREATE VIRTUAL TABLE t3 * USING blobtoxy (t, key, data, int_be, 10.0, null, 10.0, null, "foo"); - * CREATE VIRTUAL TABLE t4 + * <br>CREATE VIRTUAL TABLE t4 * USING blobtoxy (t, key, data, float, null, -10, null, 10); * * Arguments to "blobtoxy" module: * - * 0. master table name (required). - * 1. key column in master table (required). - * 2. blob column in master table (required). - * 3. type code (optional), defaults to "char". + * 0. master table name (required).<br> + * 1. key column in master table (required).<br> + * 2. blob column in master table (required).<br> + * 3. type code (optional), defaults to "char".<br> * 4. X scale column in master table (optional), * may be specified as integer or float constant, too, * to explicitely omit scale, use an empty string ('') - * or null. + * or null.<br> * 5. X offset column in master table (optional), * may be specified as integer or float constant, too, * to explicitely omit offset, use an empty string ('') - * or null. - * 6. Y scale column in master table (optional), see point 4. - * 7. Y offset column in master table (optional), see point 5. + * or null.<br> + * 6. Y scale column in master table (optional), see point 4.<br> + * 7. Y offset column in master table (optional), see point 5.<br> * 8. other columns of the master table to appear in the * result set (optional), must be specified as a * single or double quoted string with comma * separated column names as a sequence of named * columns as it would be written in a SELECT - * statement. + * statement.<br> * 9. X start index (optional), specified as integer - * in type specific blob units, zero based. + * in type specific blob units, zero based.<br> * 10. X length (optional), specified as integer, - * number of blob units (= number of rows). + * number of blob units (= number of rows).<br> * * Supported data types: * - * "char" -> BLOB is a signed char array - * "uchar" -> BLOB is an unsigned char array - * "short_le" -> BLOB is a short array little endian - * "short_be" -> BLOB is a short array big endian - * "ushort_le" -> BLOB is an unsigned short array little endian - * "ushort_be" -> BLOB is an unsigned short array big endian - * "int_le" -> BLOB is a int array little endian - * "int_be" -> BLOB is a int array big endian - * "uint_le" -> BLOB is an unsigned int array little endian - * "uint_be" -> BLOB is an unsigned int array big endian - * "bigint_le" -> BLOB is an large integer array little endian - * "bigint_be" -> BLOB is an large integer array big endian - * "float" -> BLOB is a float array - * "double" -> BLOB is a double array + * "char" -> BLOB is a signed char array<br> + * "uchar" -> BLOB is an unsigned char array<br> + * "short_le" -> BLOB is a short array little endian<br> + * "short_be" -> BLOB is a short array big endian<br> + * "ushort_le" -> BLOB is an unsigned short array little endian<br> + * "ushort_be" -> BLOB is an unsigned short array big endian<br> + * "int_le" -> BLOB is a int array little endian<br> + * "int_be" -> BLOB is a int array big endian<br> + * "uint_le" -> BLOB is an unsigned int array little endian<br> + * "uint_be" -> BLOB is an unsigned int array big endian<br> + * "bigint_le" -> BLOB is an large integer array little endian<br> + * "bigint_be" -> BLOB is an large integer array big endian<br> + * "float" -> BLOB is a float array<br> + * "double" -> BLOB is a double array<br> * * Columns of "blobtoxy" mapped virtual table: * - * "key" Key column for JOINing with master table - * "x" index within BLOB. + * "key" Key column for JOINing with master table<br> + * "x" index within BLOB.<br> * This value is optionally translated by * the "x_scale" and "x_offset" columns * i.e. x' = x * x_scale + x_offset, yielding - * a floating point result. - * "y" BLOB's value at "x"-unscaled-index + * a floating point result.<br> + * "y" BLOB's value at "x"-unscaled-index<br> * This value is optionally translated by * the "y_scale" and "y_offset" columns * i.e. y' = y * y_scale + y_offset, yielding - * a floating point result. - * ... Other columns, see above + * a floating point result.<br> + * ... Other columns, see above<br> * * If the "key" field of the master table is an integer data * type, it is used as the ROWID of the mapped virtual table. @@ -105,43 +105,43 @@ * * Scalar context: * - * svg_path_from_blob(data, type, x_scale, x_offset, y_scale, y_offset) - * tk_path_from_blob(data, type, x_scale, x_offset, y_scale, y_offset) - * blt_vec_(x|y)(data, type, x_scale, x_offset, y_scale, y_offset) + * svg_path_from_blob(data, type, x_scale, x_offset, y_scale, y_offset)<br> + * tk_path_from_blob(data, type, x_scale, x_offset, y_scale, y_offset)<br> + * blt_vec_(x|y)(data, type, x_scale, x_offset, y_scale, y_offset)<br> * tk3d_path_from_blob(data, type, x_scale, x_offset, y_scale, y_offset, - * z_value, z_scale, z_offset) + * z_value, z_scale, z_offset)<br> * * Like BLOB to X/Y mapping but produces SVG or Tk Canvas * path/polyline as a string, e.g. * - * SVG: "M 1 1 L 2 2 L 3 7 L 4 1 - * Tk Canvas: "1 1 2 2 3 7 4 1" - * BLT Vector X: "1 2 3 4" - * BLT Vector Y: "1 2 7 1" - * Tk 3D Canvas: "1 1 0 2 2 0 3 7 0 4 1 0" + * SVG: "M 1 1 L 2 2 L 3 7 L 4 1<br> + * Tk Canvas: "1 1 2 2 3 7 4 1"<br> + * BLT Vector X: "1 2 3 4"<br> + * BLT Vector Y: "1 2 7 1"<br> + * Tk 3D Canvas: "1 1 0 2 2 0 3 7 0 4 1 0"<br> * * Arguments: * * 0. blob data (required); this parameter is always * interpreted as blob. It must contain at least * two elements, otherwise the function's result - * is NULL to indicate that nothing need be drawn - * 1. type code (optional), defaults to "char" - * 2. X scale (optional), see above - * 3. X offset (optional), see above - * 4. Y scale (optional), see above - * 5. Y offset (optional), see above - * 6. Z value (optional) - * 8. Z scale (optional) - * 9. Z offset (optional) + * is NULL to indicate that nothing need be drawn<br> + * 1. type code (optional), defaults to "char"<br> + * 2. X scale (optional), see above<br> + * 3. X offset (optional), see above<br> + * 4. Y scale (optional), see above<br> + * 5. Y offset (optional), see above<br> + * 6. Z value (optional)<br> + * 8. Z scale (optional)<br> + * 9. Z offset (optional)<br> * * Aggregate context: * - * svg_path(xdata, ydata, x_scale, x_offset, y_scale, y_offset) - * tk_path(xdata, ydata, x_scale, x_offset, y_scale, y_offset) - * blt_vec(data, scale, offset) + * svg_path(xdata, ydata, x_scale, x_offset, y_scale, y_offset)<br> + * tk_path(xdata, ydata, x_scale, x_offset, y_scale, y_offset)<br> + * blt_vec(data, scale, offset)<br> * tk3d_path(xdata, ydata, x_scale, x_offset, y_scale, y_offset, - * zdata, z_scale, z_offset) + * zdata, z_scale, z_offset)<br> * * Same behaviour except that xdata/ydata/data/zdata are interpreted * directly as numeric values. @@ -153,20 +153,20 @@ * * Works somewhat like substr, e.g. * - * select quote(subblob(X'0A0B0C0D0E0F0001',2,2,1,3)) + * select quote(subblob(X'0A0B0C0D0E0F0001',2,2,1,3))<br> * -> X'0B0F' * * Arguments: * * 0. blob data (required); this parameter is always - * interpreted as blob. + * interpreted as blob.<br> * 1. start offset (required) in bytes as in substr - * function (1-based, negative offsets count from end) - * 2. length (required) in bytes to be copied + * function (1-based, negative offsets count from end)<br> + * 2. length (required) in bytes to be copied<br> * 3. size (optional) of items in bytes to be copied - * in combination with skip argument + * in combination with skip argument<br> * 4. skip (optional) in bytes after one item of - * size argument has been copied + * size argument has been copied<br> * * * Exported SQLite function rownumber @@ -178,8 +178,8 @@ * must be provided to this function in order to satisfy * some needs of the SQLite3 C API, e.g. * - * rownumber(0), rownumber('foo') right - * rownumber(column_name) wrong, will yield always 0 + * rownumber(0), rownumber('foo') right<br> + * rownumber(column_name) wrong, will yield always 0<br> * */ @@ -187,7 +187,7 @@ #include <sqlite3.h> #else #include <sqlite3ext.h> -SQLITE_EXTENSION_INIT1 +static SQLITE_EXTENSION_INIT1 #endif #include <stdlib.h> @@ -219,50 +219,68 @@ SQLITE_EXTENSION_INIT1 #define TYPE_FLOAT TYPE_CODE(12, float) #define TYPE_DOUBLE TYPE_CODE(13, double) +/** + * @typedef b2xy_table + * @struct b2xy_table + * Structure to describe a virtual table. + */ + typedef struct b2xy_table { - sqlite3_vtab base; /* SQLite's base virtual table struct */ - sqlite3 *db; /* Open database */ - char *master_table; /* Table where to fetch BLOB from */ - char *fq_master_table; /* Fully qualified master_table */ - char *key_column; /* Name of key column */ - char *blob_column; /* Name of BLOB column */ - char *x_scale_column; /* Name of column giving X scale or NULL */ - char *x_offset_column; /* Name of column giving X offset or NULL */ - char *y_scale_column; /* Name of column giving Y scale or NULL */ - char *y_offset_column; /* Name of column giving Y offset or NULL */ - char *other_columns; /* Other columns or empty string */ - int type; /* Data type of BLOB */ - int do_x_sl; /* If true, apply X start/length */ - int x_start, x_length; /* X start/length */ - int argc; /* Number arguments from b2xy_create() call */ - char **argv; /* Argument vector from b2xy_create() call */ + sqlite3_vtab base; /**< SQLite's base virtual table struct */ + sqlite3 *db; /**< Open database */ + char *master_table; /**< Table where to fetch BLOB from */ + char *fq_master_table; /**< Fully qualified master_table */ + char *key_column; /**< Name of key column */ + char *blob_column; /**< Name of BLOB column */ + char *x_scale_column; /**< Name of column giving X scale or NULL */ + char *x_offset_column; /**< Name of column giving X offset or NULL */ + char *y_scale_column; /**< Name of column giving Y scale or NULL */ + char *y_offset_column; /**< Name of column giving Y offset or NULL */ + char *other_columns; /**< Other columns or empty string */ + int type; /**< Data type of BLOB */ + int do_x_sl; /**< If true, apply X start/length */ + int x_start, x_length; /**< X start/length */ + int argc; /**< Number args from b2xy_create() call */ + char **argv; /**< Argument vector from b2xy_create() call */ } b2xy_table; +/** + * @typedef b2xy_cursor + * @struct b2xy_cursor + * Structure to describe a cursor in the virtual table. + */ + typedef struct b2xy_cursor { - sqlite3_vtab_cursor base; /* SQLite's base cursor struct */ - b2xy_table *table; /* Link to table struct */ - sqlite3_stmt *select; /* Prepared SELECT statement or NULL */ - sqlite3_value *key; /* Value of current key */ - int fix_cols; /* Fixed number of columns of result set */ - int num_cols; /* Total number of columns of result set */ - char *val; /* Value of current BLOB */ - int val_len; /* Length of current BLOB */ - int x_scale_col; /* Column number of X scale or 0 */ - int x_offset_col; /* Column number of X offset or 0 */ - double x_scale, x_offset; /* Current X scale and offset */ - int y_scale_col; /* Column number of Y scale or 0 */ - int y_offset_col; /* Column number of Y offset or 0 */ - double y_scale, y_offset; /* Current X scale and offset */ - int do_x_scale; /* If true, use X scale and offset */ - int do_y_scale; /* If true, use Y scale and offset */ - int do_x_sl; /* If true, apply X start/length */ - int x_start, x_length; /* X start/length */ - int type; /* Data type of BLOB */ - int index; /* Current index in BLOB */ - int rowid_from_key; /* When true, ROWID used from key column */ - sqlite_int64 rowid; /* Current ROWID */ + sqlite3_vtab_cursor base; /**< SQLite's base cursor struct */ + b2xy_table *table; /**< Link to table struct */ + sqlite3_stmt *select; /**< Prepared SELECT statement or NULL */ + sqlite3_value *key; /**< Value of current key */ + int fix_cols; /**< Fixed number of columns of result set */ + int num_cols; /**< Total number of columns of result set */ + char *val; /**< Value of current BLOB */ + int val_len; /**< Length of current BLOB */ + int x_scale_col; /**< Column number of X scale or 0 */ + int x_offset_col; /**< Column number of X offset or 0 */ + double x_scale, x_offset; /**< Current X scale and offset */ + int y_scale_col; /**< Column number of Y scale or 0 */ + int y_offset_col; /**< Column number of Y offset or 0 */ + double y_scale, y_offset; /**< Current X scale and offset */ + int do_x_scale; /**< If true, use X scale and offset */ + int do_y_scale; /**< If true, use Y scale and offset */ + int do_x_sl; /**< If true, apply X start/length */ + int x_start, x_length; /**< X start/length */ + int type; /**< Data type of BLOB */ + int index; /**< Current index in BLOB */ + int rowid_from_key; /**< When true, ROWID used from key column */ + sqlite_int64 rowid; /**< Current ROWID */ } b2xy_cursor; +/** + * Map type string to type code. + * @param str type string, e.g. "char" + * @result type code, e.g. TYPE_CHAR + */ + static int string_to_type(const char *str) { @@ -311,6 +329,12 @@ string_to_type(const char *str) return 0; } +/** + * Destroy virtual table. + * @param vtab virtual table pointer + * @result always SQLITE_OK + */ + static int b2xy_destroy(sqlite3_vtab *vtab) { @@ -320,6 +344,34 @@ b2xy_destroy(sqlite3_vtab *vtab) return SQLITE_OK; } +/** + * Create virtual table + * @param db SQLite database pointer + * @param userdata user specific pointer (unused) + * @param argc argument count + * @param argv argument vector + * @param vtabret pointer receiving virtual table pointer + * @param errp pointer receiving error messag + * @result SQLite error code + * + * Argument vector contains: + * + * argv[0] - module name<br> + * argv[1] - database name<br> + * argv[2] - table name (virtual table)<br> + * argv[3] - master table name (required)<br> + * argv[4] - key column (required)<br> + * argv[5] - blob column (required)<br> + * argv[6] - type code (optional)<br> + * argv[7] - X scale column (optional)<br> + * argv[8] - X offset column (optional)<br> + * argv[9] - Y scale column (optional)<br> + * argv[10] - Y offset column (optional)<br> + * argv[11] - other columns (optional)<br> + * argv[12] - X start (optional)<br> + * argv[13] - X length (optional)<br> + */ + static int b2xy_create(sqlite3 *db, void *userdata, int argc, const char * const *argv, sqlite3_vtab **vtabret, char **errp) @@ -329,22 +381,6 @@ b2xy_create(sqlite3 *db, void *userdata, int argc, int i, size, type = TYPE_CHAR; int x_start = -1, x_length = 0; - /* - * argv[0] - module name - * argv[1] - database name - * argv[2] - table name (virtual table) - * argv[3] - master table name (required) - * argv[4] - key column (required) - * argv[5] - blob column (required) - * argv[6] - type code (optional) - * argv[7] - X scale column (optional) - * argv[8] - X offset column (optional) - * argv[9] - Y scale column (optional) - * argv[10] - Y offset column (optional) - * argv[11] - other columns (optional) - * argv[12] - X start (optional) - * argv[13] - X length (optional) - */ if (argc < 6) { *errp = sqlite3_mprintf("need at least 3 arguments"); return SQLITE_ERROR; @@ -357,7 +393,7 @@ b2xy_create(sqlite3 *db, void *userdata, int argc, } } if (argc > 11) { - if (argv[11][0] != '"' && argv[11][0] != '\'') { + if ((argv[11][0] != '"') && (argv[11][0] != '\'')) { *errp = sqlite3_mprintf("other columns must be quoted"); return SQLITE_ERROR; } @@ -366,7 +402,7 @@ b2xy_create(sqlite3 *db, void *userdata, int argc, char *endp = 0; x_start = strtol(argv[12], &endp, 10); - if (endp == argv[12] || (endp && endp[0] != '\0')) { + if ((endp == argv[12]) || (endp && (endp[0] != '\0'))) { *errp = sqlite3_mprintf("X start index must be integer"); return SQLITE_ERROR; } @@ -379,7 +415,7 @@ b2xy_create(sqlite3 *db, void *userdata, int argc, char *endp = 0; x_length = strtol(argv[13], &endp, 10); - if (endp == argv[13] || (endp && endp[0] != '\0')) { + if ((endp == argv[13]) || (endp && (endp[0] != '\0'))) { *errp = sqlite3_mprintf("X length must be integer"); return SQLITE_ERROR; } @@ -433,25 +469,25 @@ b2xy_create(sqlite3 *db, void *userdata, int argc, } bt->key_column = bt->argv[4]; bt->blob_column = bt->argv[5]; - if (bt->argc > 7 && bt->argv[7][0]) { + if ((bt->argc > 7) && bt->argv[7][0]) { bt->x_scale_column = bt->argv[7]; if (strcasecmp(bt->x_scale_column, "null") == 0) { bt->x_scale_column = 0; } } - if (bt->argc > 8 && bt->argv[8][0]) { + if ((bt->argc > 8) && bt->argv[8][0]) { bt->x_offset_column = bt->argv[8]; if (strcasecmp(bt->x_offset_column, "null") == 0) { bt->x_offset_column = 0; } } - if (bt->argc > 9 && bt->argv[9][0]) { + if ((bt->argc > 9) && bt->argv[9][0]) { bt->y_scale_column = bt->argv[9]; if (strcasecmp(bt->y_scale_column, "null") == 0) { bt->y_scale_column = 0; } } - if (bt->argc > 10 && bt->argv[10][0]) { + if ((bt->argc > 10) && bt->argv[10][0]) { bt->y_offset_column = bt->argv[10]; if (strcasecmp(bt->y_offset_column, "null") == 0) { bt->y_offset_column = 0; @@ -462,7 +498,7 @@ b2xy_create(sqlite3 *db, void *userdata, int argc, p[0] = ','; bt->other_columns = p; p += strlen(p) - 1; - if (*p == '"' || *p == '\'') { + if ((*p == '"') || (*p == '\'')) { *p = '\0'; } } else { @@ -470,13 +506,13 @@ b2xy_create(sqlite3 *db, void *userdata, int argc, } /* find out types of key and x/y columns */ if (bt->x_scale_column || bt->x_offset_column || - bt->type == TYPE_FLOAT || bt->type == TYPE_DOUBLE) { + (bt->type == TYPE_FLOAT) || (bt->type == TYPE_DOUBLE)) { x_type = " DOUBLE"; } else { x_type = " INTEGER"; } if (bt->y_scale_column || bt->y_offset_column || - bt->type == TYPE_FLOAT || bt->type == TYPE_DOUBLE) { + (bt->type == TYPE_FLOAT) || (bt->type == TYPE_DOUBLE)) { y_type = " DOUBLE"; } else { y_type = " INTEGER"; @@ -491,9 +527,9 @@ b2xy_create(sqlite3 *db, void *userdata, int argc, rc = sqlite3_get_table(db, p, &rows, &nrows, &ncols, 0); sqlite3_free(p); if (rc == SQLITE_OK) { - for (i = 1; ncols >= 3 && i <= nrows; i++) { + for (i = 1; (ncols >= 3) && (i <= nrows); i++) { p = rows[i * ncols + 1]; - if (p && strcasecmp(bt->key_column, p) == 0) { + if (p && (strcasecmp(bt->key_column, p) == 0)) { key_type = sqlite3_mprintf(" %s", rows[i * ncols + 2]); break; } @@ -518,7 +554,7 @@ b2xy_create(sqlite3 *db, void *userdata, int argc, rc = sqlite3_prepare(db, p, -1, &stmt, 0); #endif sqlite3_free(p); - if (rc == SQLITE_OK && stmt) { + if ((rc == SQLITE_OK) && stmt) { sqlite3_step(stmt); for (i = 0; i < sqlite3_column_count(stmt); i++) { p = sqlite3_mprintf("%s%s\"%s\" %s", @@ -567,6 +603,13 @@ b2xy_create(sqlite3 *db, void *userdata, int argc, return rc; } +/** + * Open virtual table and return cursor. + * @param vtab virtual table pointer + * @param curret pointer receiving cursor pointer + * @result SQLite error code + */ + static int b2xy_open(sqlite3_vtab *vtab, sqlite3_vtab_cursor **curret) { @@ -588,6 +631,12 @@ b2xy_open(sqlite3_vtab *vtab, sqlite3_vtab_cursor **curret) return rc; } +/** + * Close virtual table cursor. + * @param cur cursor pointer + * @result SQLite error code + */ + static int b2xy_close(sqlite3_vtab_cursor *cur) { @@ -598,6 +647,14 @@ b2xy_close(sqlite3_vtab_cursor *cur) return SQLITE_OK; } +/** + * Return column data of virtual table. + * @param cur virtual table cursor + * @param ctx SQLite function context + * @param i column index + * @result SQLite error code + */ + static int b2xy_column(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i) { @@ -618,7 +675,8 @@ b2xy_column(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i) } break; case 2: - if (!bc->val || (bc->index + 1) * TYPE_SIZE(bc->type) > bc->val_len) { + if (!bc->val || + ((bc->index + 1) * TYPE_SIZE(bc->type) > bc->val_len)) { goto put_null; } p = bc->val + bc->index * TYPE_SIZE(bc->type); @@ -762,7 +820,7 @@ b2xy_column(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i) break; default: i += bc->fix_cols - 3; - if (i < 0 || i >= bc->num_cols) { + if ((i < 0) || (i >= bc->num_cols)) { sqlite3_result_null(ctx); } else { sqlite3_result_value(ctx, sqlite3_column_value(bc->select, i)); @@ -772,6 +830,13 @@ b2xy_column(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i) return SQLITE_OK; } +/** + * Return current rowid of virtual table cursor + * @param cur virtual table cursor + * @param rowidp value buffer to receive current rowid + * @result SQLite error code + */ + static int b2xy_rowid(sqlite3_vtab_cursor *cur, sqlite_int64 *rowidp) { @@ -781,6 +846,12 @@ b2xy_rowid(sqlite3_vtab_cursor *cur, sqlite_int64 *rowidp) return SQLITE_OK; } +/** + * Return end of table state of virtual table cursor + * @param cur virtual table cursor + * @result true/false + */ + static int b2xy_eof(sqlite3_vtab_cursor *cur) { @@ -789,6 +860,12 @@ b2xy_eof(sqlite3_vtab_cursor *cur) return bc->select ? 0 : 1; } +/** + * Retrieve next row from virtual table cursor + * @param cur virtual table cursor + * @result SQLite error code + */ + static int b2xy_next(sqlite3_vtab_cursor *cur) { @@ -838,7 +915,7 @@ refetch: } } if (!(bc->do_x_sl && bc->x_length) && - ((bc->index + 1) * TYPE_SIZE(bc->type) > bc->val_len)) { + (((bc->index + 1) * TYPE_SIZE(bc->type) > bc->val_len))) { goto refetch; } bc->key = sqlite3_column_value(bc->select, 0); @@ -875,6 +952,16 @@ refetch: return SQLITE_OK; } +/** + * Filter function for virtual table. + * @param cur virtual table cursor + * @param idxNum used for expression (<, =, >, etc.) + * @param idxStr optional order by clause + * @param argc number arguments (0 or 1) + * @param argv argument (nothing or RHS of filter expression) + * @result SQLite error code + */ + static int b2xy_filter(sqlite3_vtab_cursor *cur, int idxNum, const char *idxStr, int argc, sqlite3_value **argv) @@ -943,7 +1030,7 @@ b2xy_filter(sqlite3_vtab_cursor *cur, int idxNum, const char *idxStr, return SQLITE_NOMEM; } query = tmp; - if (idxNum && argc > 0) { + if (idxNum && (argc > 0)) { switch (idxNum) { case SQLITE_INDEX_CONSTRAINT_EQ: op = "="; @@ -1001,6 +1088,14 @@ b2xy_filter(sqlite3_vtab_cursor *cur, int idxNum, const char *idxStr, return (rc == SQLITE_OK) ? b2xy_next(cur) : rc; } +/** + * Determines information for filter function + * according to constraints. + * @param tab virtual table + * @param info index/constraint iinformation + * @result SQLite error code + */ + static int b2xy_bestindex(sqlite3_vtab *tab, sqlite3_index_info *info) { @@ -1020,8 +1115,8 @@ b2xy_bestindex(sqlite3_vtab *tab, sqlite3_index_info *info) */ for (i = 0; i < info->nConstraint; ++i) { if (info->aConstraint[i].usable) { - if (info->aConstraint[i].iColumn == 0 && - info->aConstraint[i].op != 0) { + if ((info->aConstraint[i].iColumn == 0) && + (info->aConstraint[i].op != 0)) { info->idxNum = info->aConstraint[i].op; info->aConstraintUsage[i].argvIndex = 1; info->aConstraintUsage[i].omit = 1; @@ -1041,7 +1136,7 @@ b2xy_bestindex(sqlite3_vtab *tab, sqlite3_index_info *info) if (info->aOrderBy[i].iColumn == 0) { key_order = info->aOrderBy[i].desc ? -1 : 1; consumed++; - } else if (info->aOrderBy[i].iColumn == 1 && + } else if ((info->aOrderBy[i].iColumn == 1) && !info->aOrderBy[i].desc) { consumed++; } @@ -1049,7 +1144,7 @@ b2xy_bestindex(sqlite3_vtab *tab, sqlite3_index_info *info) if (consumed) { /* check for other ORDER BY columns */ for (i = 0; i < info->nOrderBy; i++) { - if (info->aOrderBy[i].iColumn == 1 && + if ((info->aOrderBy[i].iColumn == 1) && info->aOrderBy[i].desc) { consumed = 0; } else if (info->aOrderBy[i].iColumn > 1) { @@ -1060,7 +1155,7 @@ b2xy_bestindex(sqlite3_vtab *tab, sqlite3_index_info *info) if (consumed && key_order) { info->idxStr = sqlite3_mprintf("ORDER BY \"%s\" %s", bt->key_column, - key_order < 0 ? "DESC" : "ASC"); + (key_order < 0) ? "DESC" : "ASC"); info->needToFreeIdxStr = 1; } info->orderByConsumed = consumed; @@ -1068,16 +1163,24 @@ b2xy_bestindex(sqlite3_vtab *tab, sqlite3_index_info *info) } #if (SQLITE_VERSION_NUMBER > 3004000) + +/** + * Rename virtual table. + * @param newname new name for table + * @result SQLite error code + */ + static int b2xy_rename(sqlite3_vtab *tab, const char *newname) { return SQLITE_OK; } + #endif static const sqlite3_module b2xy_module = { 1, /* iVersion */ - b2xy_create, /* xCreate */ + b2xy_create, /* xCreate */ b2xy_create, /* xConnect */ b2xy_bestindex, /* xBestIndex */ b2xy_destroy, /* xDisconnect */ @@ -1100,17 +1203,30 @@ static const sqlite3_module b2xy_module = { #endif }; +/** + * @typedef strbuf + * @struct strbuf + * Internal dynamic string buffer. + */ + typedef struct { - int max, idx; - char *str; + int max; /**< maximum capacity */ + int idx; /**< current index */ + char *str; /**< string buffer */ } strbuf; +/** + * Initialize dynamic string buffer with capacity 1024. + * @param sb pointer to string buffer + * @result SQLite error code + */ + static int init_strbuf(strbuf *sb) { int n = 1024; - if (sb->max <= 0 || !sb->str) { + if ((sb->max <= 0) || !sb->str) { sb->str = sqlite3_malloc(n); if (!sb->str) { return SQLITE_NOMEM; @@ -1121,13 +1237,19 @@ init_strbuf(strbuf *sb) return SQLITE_OK; } +/** + * Expand or initialize dynamic string buffer. + * @param sb pointer to string buffer + * @result SQLite error code + */ + static int expand_strbuf(strbuf *sb) { int n; char *str; - if (sb->max <= 0 || !sb->str) { + if ((sb->max <= 0) || !sb->str) { return init_strbuf(sb); } n = sb->max * 2; @@ -1140,6 +1262,11 @@ expand_strbuf(strbuf *sb) return SQLITE_OK; } +/** + * Free resources of dynamic string buffer. + * @param sb pointer to string buffer + */ + static void drop_strbuf(strbuf *sb) { @@ -1150,6 +1277,13 @@ drop_strbuf(strbuf *sb) sb->max = 0; } +/** + * Format printf-like into dynamic string buffer. + * @param sb pointer to string buffer + * @param fmt printf-like format string + * @result SQLite error code + */ + static int print_strbuf(strbuf *sb, const char *fmt, ...) { @@ -1166,7 +1300,7 @@ print_strbuf(strbuf *sb, const char *fmt, ...) } rc = SQLITE_NOMEM; n = vsnprintf(sb->str + sb->idx, sb->max - sb->idx, fmt, ap); - if (n >= 0 && (sb->idx + n) < (sb->max - 1)) { + if ((n >= 0) && ((sb->idx + n) < (sb->max - 1))) { sb->idx += n; rc = SQLITE_OK; break; @@ -1183,6 +1317,25 @@ print_strbuf(strbuf *sb, const char *fmt, ...) #define PATH_MODE_BLT ((void *) 4) #define PATH_MODE_TK3D ((void *) 5) +/** + * Make path/polyline from blob. + * @param ctx SQLite function context + * @param nargs number arguments + * @param args arguments + * + * Arguments: + * + * args[0] - blob data (required)<br> + * args[1] - type (optional, default "char")<br> + * args[2] - X scale (optional)<br> + * args[3] - X offset (optional)<br> + * args[4] - Y scale (optional)<br> + * args[5] - Y offset (optional)<br> + * args[6] - Z value (optional)<br> + * args[7] - Z scale (optional)<br> + * args[8] - Z offset (optional)<br> + */ + static void common_path_func(sqlite3_context *ctx, int nargs, sqlite3_value **args) { @@ -1193,17 +1346,6 @@ common_path_func(sqlite3_context *ctx, int nargs, sqlite3_value **args) double x_scale, x_offset, y_scale, y_offset, z0, z_scale, z_offset; strbuf sb; - /* - * args[0] - blob data (required) - * args[1] - type (optional) - * args[2] - X scale (optional) - * args[3] - X offset (optional) - * args[4] - Y scale (optional) - * args[5] - Y offset (optional) - * args[6] - Z value (optional) - * args[7] - Z scale (optional) - * args[8] - Z offset (optional) - */ if (nargs < 1) { sqlite3_result_error(ctx, "need at least 1 argument", -1); return; @@ -1218,8 +1360,8 @@ common_path_func(sqlite3_context *ctx, int nargs, sqlite3_value **args) data = (char *) sqlite3_value_blob(args[0]); size = sqlite3_value_bytes(args[0]) / TYPE_SIZE(type); if (!data || - (mode != PATH_MODE_BLT_X && mode != PATH_MODE_BLT_Y && size < 2) || - size < 1) { + ((mode != PATH_MODE_BLT_X) && (mode != PATH_MODE_BLT_Y) && + (size < 2)) || (size < 1)) { goto nullorempty; } x_scale = 1; @@ -1245,14 +1387,14 @@ common_path_func(sqlite3_context *ctx, int nargs, sqlite3_value **args) z0 = 0; z_scale = 1; z_offset = 0; - if (mode == PATH_MODE_TK3D && nargs > 6) { + if ((mode == PATH_MODE_TK3D) && (nargs > 6)) { z0 = sqlite3_value_double(args[6]); } - if (mode == PATH_MODE_TK3D && nargs > 7) { + if ((mode == PATH_MODE_TK3D) && (nargs > 7)) { z_scale = sqlite3_value_double(args[7]); do_z_scale++; } - if (mode == PATH_MODE_TK3D && nargs > 8) { + if ((mode == PATH_MODE_TK3D) && (nargs > 8)) { z_offset = sqlite3_value_double(args[8]); do_z_scale++; } @@ -1318,7 +1460,7 @@ common_path_func(sqlite3_context *ctx, int nargs, sqlite3_value **args) if (do_y_scale) { y = y * y_scale + y_offset; } - if (mode == PATH_MODE_BLT_X || mode == PATH_MODE_BLT_Y) { + if ((mode == PATH_MODE_BLT_X) || (mode == PATH_MODE_BLT_Y)) { double v = (mode == PATH_MODE_BLT_X) ? x : y; if (print_strbuf(&sb, (i == 0) ? "%g" : " %g", v) != SQLITE_OK) { @@ -1327,11 +1469,11 @@ common_path_func(sqlite3_context *ctx, int nargs, sqlite3_value **args) } continue; } - if (mode == PATH_MODE_SVG && i == 0) { + if ((mode == PATH_MODE_SVG) && (i == 0)) { fmt = "M %g %g"; - } else if (mode == PATH_MODE_SVG && i == 1) { + } else if ((mode == PATH_MODE_SVG) && (i == 1)) { fmt = " L %g %g"; - } else if (mode == PATH_MODE_SVG && sb.idx >= linebreak) { + } else if ((mode == PATH_MODE_SVG) && (sb.idx >= linebreak)) { fmt = "\nL %g %g"; linebreak = sb.idx + 100; } else if (i == 0) { @@ -1350,19 +1492,47 @@ common_path_func(sqlite3_context *ctx, int nargs, sqlite3_value **args) return; } nullorempty: - if (mode == PATH_MODE_BLT_X || mode == PATH_MODE_BLT_Y) { + if ((mode == PATH_MODE_BLT_X) || (mode == PATH_MODE_BLT_Y)) { sqlite3_result_text(ctx, "", 0, SQLITE_STATIC); } else { sqlite3_result_null(ctx); } } +/** + * @typedef path_aggctx + * @struct path_aggctx + * Internal aggregate context for path/polyline function. + */ + typedef struct { - int init, count, linebreak; - void *mode; - strbuf sb; + int init; /**< init flag, true when initialized */ + int count; /**< counts formatted elements */ + int linebreak; /**< when to add newline to output */ + void *mode; /**< mode, see PATH_* defines */ + strbuf sb; /**< string buffer for result */ } path_aggctx; +/** + * Path/polyline step callback for "tk_path", "svg_path", and + * "tk3d_path" aggregate functions. + * @param ctx SQLite function context + * @param nargs number arguments + * @param args arguments + * + * Arguments: + * + * args[0] - X value (required)<br> + * args[1] - Y value (required)<br> + * args[2] - X scale (optional)<br> + * args[3] - X offset (optional)<br> + * args[4] - Y scale (optional)<br> + * args[5] - Y offset (optional)<br> + * args[6] - Z value (optional)<br> + * args[7] - Z scale (optional)<br> + * args[8] - Z offset (optional)<br> + */ + static void common_path_step(sqlite3_context *ctx, int nargs, sqlite3_value **args) { @@ -1372,17 +1542,6 @@ common_path_step(sqlite3_context *ctx, int nargs, sqlite3_value **args) double x, y, z = 0; double x_scale, y_scale, x_offset, y_offset, z_scale, z_offset; - /* - * args[0] - X value (required) - * args[1] - Y value (required) - * args[2] - X scale (optional) - * args[3] - X offset (optional) - * args[4] - Y scale (optional) - * args[5] - Y offset (optional) - * args[6] - Z value (optional) - * args[7] - Z scale (optional) - * args[8] - Z offset (optional) - */ if (nargs < 2) { return; } @@ -1397,11 +1556,11 @@ common_path_step(sqlite3_context *ctx, int nargs, sqlite3_value **args) pag->init = 1; } type = sqlite3_value_type(args[0]); - if (type != SQLITE_INTEGER && type != SQLITE_FLOAT) { + if ((type != SQLITE_INTEGER) && (type != SQLITE_FLOAT)) { return; } type = sqlite3_value_type(args[1]); - if (type != SQLITE_INTEGER && type != SQLITE_FLOAT) { + if ((type != SQLITE_INTEGER) && (type != SQLITE_FLOAT)) { return; } x = sqlite3_value_double(args[0]); @@ -1410,13 +1569,13 @@ common_path_step(sqlite3_context *ctx, int nargs, sqlite3_value **args) x_offset = 0; if (nargs > 2) { type = sqlite3_value_type(args[2]); - if (type == SQLITE_INTEGER || type == SQLITE_FLOAT) { + if ((type == SQLITE_INTEGER) || (type == SQLITE_FLOAT)) { x_scale = sqlite3_value_double(args[2]); } } if (nargs > 3) { type = sqlite3_value_type(args[3]); - if (type == SQLITE_INTEGER || type == SQLITE_FLOAT) { + if ((type == SQLITE_INTEGER) || (type == SQLITE_FLOAT)) { x_offset = sqlite3_value_double(args[3]); } } @@ -1424,29 +1583,29 @@ common_path_step(sqlite3_context *ctx, int nargs, sqlite3_value **args) y_offset = 0; if (nargs > 4) { type = sqlite3_value_type(args[4]); - if (type == SQLITE_INTEGER || type == SQLITE_FLOAT) { + if ((type == SQLITE_INTEGER) || (type == SQLITE_FLOAT)) { y_scale = sqlite3_value_double(args[4]); } } if (nargs > 5) { type = sqlite3_value_type(args[5]); - if (type == SQLITE_INTEGER || type == SQLITE_FLOAT) { + if ((type == SQLITE_INTEGER) || (type == SQLITE_FLOAT)) { y_offset = sqlite3_value_double(args[5]); } } z_scale = 1; z_offset = 0; - if (pag->mode == PATH_MODE_TK3D && nargs > 6) { + if ((pag->mode == PATH_MODE_TK3D) && (nargs > 6)) { z = sqlite3_value_double(args[6]); if (nargs > 7) { type = sqlite3_value_type(args[7]); - if (type == SQLITE_INTEGER || type == SQLITE_FLOAT) { + if ((type == SQLITE_INTEGER) || (type == SQLITE_FLOAT)) { z_scale = sqlite3_value_double(args[7]); } } if (nargs > 8) { type = sqlite3_value_type(args[8]); - if (type == SQLITE_INTEGER || type == SQLITE_FLOAT) { + if ((type == SQLITE_INTEGER) || (type == SQLITE_FLOAT)) { z_offset = sqlite3_value_double(args[8]); } } @@ -1454,11 +1613,12 @@ common_path_step(sqlite3_context *ctx, int nargs, sqlite3_value **args) } x = x * x_scale + x_offset; y = y * y_scale + y_offset; - if (pag->mode == PATH_MODE_SVG && pag->count == 0) { + if ((pag->mode == PATH_MODE_SVG) && (pag->count == 0)) { fmt = "M %g %g"; - } else if (pag->mode == PATH_MODE_SVG && pag->count == 1) { + } else if ((pag->mode == PATH_MODE_SVG) && (pag->count == 1)) { fmt = " L %g %g"; - } else if (pag->mode == PATH_MODE_SVG && pag->sb.idx >= pag->linebreak) { + } else if ((pag->mode == PATH_MODE_SVG) && + (pag->sb.idx >= pag->linebreak)) { fmt = "\nL %g %g"; pag->linebreak = pag->sb.idx + 100; } else if (pag->count == 0) { @@ -1474,13 +1634,18 @@ common_path_step(sqlite3_context *ctx, int nargs, sqlite3_value **args) } } +/** + * Path/polyline finalizer. + * @param ctx SQLite function context + */ + static void common_path_finalize(sqlite3_context *ctx) { path_aggctx *pag = sqlite3_aggregate_context(ctx, sizeof (*pag)); if (pag->init) { - if (pag->count > 1 || pag->mode == PATH_MODE_BLT) { + if ((pag->count > 1) || (pag->mode == PATH_MODE_BLT)) { sqlite3_result_text(ctx, pag->sb.str, pag->sb.idx, sqlite3_free); pag->sb.str = 0; pag->init = 0; @@ -1495,6 +1660,19 @@ common_path_finalize(sqlite3_context *ctx) } } +/** + * Path/polyline step callback for "blt_vec" aggregate functions. + * @param ctx SQLite function context + * @param nargs number arguments + * @param args arguments + * + * Arguments: + * + * args[0] - value (required)<br> + * args[1] - scale (optional)<br> + * args[2] - offset (optional)<br> + */ + static void blt_vec_step(sqlite3_context *ctx, int nargs, sqlite3_value **args) { @@ -1502,11 +1680,6 @@ blt_vec_step(sqlite3_context *ctx, int nargs, sqlite3_value **args) int type; double v, scale, offset; - /* - * args[0] - value (required) - * args[1] - scale (optional) - * args[2] - offset (optional) - */ if (nargs < 1) { return; } @@ -1520,7 +1693,7 @@ blt_vec_step(sqlite3_context *ctx, int nargs, sqlite3_value **args) pag->init = 1; } type = sqlite3_value_type(args[0]); - if (type != SQLITE_INTEGER && type != SQLITE_FLOAT) { + if ((type != SQLITE_INTEGER) && (type != SQLITE_FLOAT)) { return; } v = sqlite3_value_double(args[0]); @@ -1528,13 +1701,13 @@ blt_vec_step(sqlite3_context *ctx, int nargs, sqlite3_value **args) offset = 0; if (nargs > 1) { type = sqlite3_value_type(args[1]); - if (type == SQLITE_INTEGER || type == SQLITE_FLOAT) { + if ((type == SQLITE_INTEGER) || (type == SQLITE_FLOAT)) { scale = sqlite3_value_double(args[2]); } } if (nargs > 2) { type = sqlite3_value_type(args[2]); - if (type == SQLITE_INTEGER || type == SQLITE_FLOAT) { + if ((type == SQLITE_INTEGER) || (type == SQLITE_FLOAT)) { offset = sqlite3_value_double(args[3]); } } @@ -1548,6 +1721,13 @@ blt_vec_step(sqlite3_context *ctx, int nargs, sqlite3_value **args) } } +/** + * "subblob" function similar to "substr". + * @param ctx SQLite function context + * @param nargs number arguments + * @param args arguments + */ + static void subblob_func(sqlite3_context *ctx, int nargs, sqlite3_value **args) { @@ -1561,7 +1741,7 @@ subblob_func(sqlite3_context *ctx, int nargs, sqlite3_value **args) } indata = (char *) sqlite3_value_blob(args[0]); insize = sqlite3_value_bytes(args[0]); - if (!indata || insize <= 0) { + if (!indata || (insize <= 0)) { isnull: sqlite3_result_null(ctx); return; @@ -1587,7 +1767,7 @@ isnull: } if (nargs > 3) { itemsize = sqlite3_value_int(args[3]); - if (itemsize <= 0 || itemsize > outsize) { + if ((itemsize <= 0) || (itemsize > outsize)) { goto isnull; } } @@ -1624,18 +1804,31 @@ isnull: sqlite3_free(outdata); } +/** + * @typedef rownumber_ctx + * @struct rownumber_ctx + * SQLite context structure for "rownumber" function. + */ + typedef struct { - sqlite3_context *ctx; - sqlite3_value *value; - sqlite_int64 count; + sqlite3_context *ctx; /**< SQLite context */ + sqlite3_value *value; /**< SQLite value for this context */ + sqlite_int64 count; /**< Counter giving row number */ } rownumber_ctx; +/** + * "rownumber" function. + * @param ctx SQLite function context + * @param nargs number arguments + * @param args arguments + */ + static void rownumber_func(sqlite3_context *ctx, int nargs, sqlite3_value **args) { rownumber_ctx *rn = sqlite3_get_auxdata(ctx, 0); - if (!rn || rn->ctx != ctx || rn->value != args[0]) { + if (!rn || (rn->ctx != ctx) || (rn->value != args[0])) { rn = sqlite3_malloc(sizeof (*rn)); if (rn) { rn->ctx = ctx; @@ -1649,6 +1842,13 @@ rownumber_func(sqlite3_context *ctx, int nargs, sqlite3_value **args) sqlite3_result_int64(ctx, rn ? rn->count : 0); } +/** + * Module initializer creating SQLite functions and + * modules. + * @param db SQLite database pointer + * @result SQLite error code + */ + #ifndef STANDALONE static #endif @@ -1681,6 +1881,15 @@ b2xy_init(sqlite3 *db) } #ifndef STANDALONE + +/** + * Initializer for SQLite extension load mechanism. + * @param db SQLite database pointer + * @param errmsg pointer receiving error message + * @param api SQLite API routines + * @result SQLite error code + */ + int sqlite3_extension_init(sqlite3 *db, char **errmsg, const sqlite3_api_routines *api) @@ -1688,4 +1897,5 @@ sqlite3_extension_init(sqlite3 *db, char **errmsg, SQLITE_EXTENSION_INIT2(api); return b2xy_init(db); } + #endif |