diff options
Diffstat (limited to 'keximdb/src/mdbtools/libmdb/sargs.c')
-rw-r--r-- | keximdb/src/mdbtools/libmdb/sargs.c | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/keximdb/src/mdbtools/libmdb/sargs.c b/keximdb/src/mdbtools/libmdb/sargs.c new file mode 100644 index 0000000..44a75c4 --- /dev/null +++ b/keximdb/src/mdbtools/libmdb/sargs.c @@ -0,0 +1,266 @@ +/* MDB Tools - A library for reading MS Access database file + * Copyright (C) 2000 Brian Bruns + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * code for handling searchable arguments (sargs) used primary by the sql + * engine to support where clause handling. The sargs are configured in + * a tree with AND/OR operators connecting the child nodes. NOT operations + * have only one child on the left side. Logical operators (=,<,>,etc..) + * have no children. + * + * datatype support is a bit weak at this point. To add more types create + * a mdb_test_[type]() function and invoke it from mdb_test_sarg() + */ +#include "mdbtools.h" + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +void +mdb_sql_walk_tree(MdbSargNode *node, MdbSargTreeFunc func, gpointer data) +{ + if (func(node, data)) + return; + if (node->left) mdb_sql_walk_tree(node->left, func, data); + if (node->right) mdb_sql_walk_tree(node->right, func, data); +} +int +mdb_test_string(MdbSargNode *node, char *s) +{ +int rc; + + if (node->op == MDB_LIKE) { + return mdb_like_cmp(s,node->value.s); + } + rc = strncmp(node->value.s, s, 255); + switch (node->op) { + case MDB_EQUAL: + if (rc==0) return 1; + break; + case MDB_GT: + if (rc<0) return 1; + break; + case MDB_LT: + if (rc>0) return 1; + break; + case MDB_GTEQ: + if (rc<=0) return 1; + break; + case MDB_LTEQ: + if (rc>=0) return 1; + break; + default: + fprintf(stderr, "Calling mdb_test_sarg on unknown operator. Add code to mdb_test_string() for operator %d\n",node->op); + break; + } + return 0; +} +int mdb_test_int(MdbSargNode *node, gint32 i) +{ + switch (node->op) { + case MDB_EQUAL: + + if (node->value.i == i) return 1; + break; + case MDB_GT: + if (node->value.i < i) return 1; + break; + case MDB_LT: + if (node->value.i > i) return 1; + break; + case MDB_GTEQ: + if (node->value.i <= i) return 1; + break; + case MDB_LTEQ: + if (node->value.i >= i) return 1; + break; + default: + fprintf(stderr, "Calling mdb_test_sarg on unknown operator. Add code to mdb_test_int() for operator %d\n",node->op); + break; + } + return 0; +} +#if 0 +#endif +int +mdb_find_indexable_sargs(MdbSargNode *node, gpointer data) +{ + MdbSarg sarg; + + if (node->op == MDB_OR || node->op == MDB_NOT) return 1; + + /* + * right now all we do is look for sargs that are anded together from + * the root. Later we may put together OR ops into a range, and then + * range scan the leaf pages. That is col1 = 2 or col1 = 4 becomes + * col1 >= 2 and col1 <= 4 for the purpose of index scans, and then + * extra rows are thrown out when the row is tested against the main + * sarg tree. range scans are generally only a bit better than table + * scanning anyway. + * + * also, later we should support the NOT operator, but it's generally + * a pretty worthless test for indexes, ie NOT col1 = 3, we are + * probably better off table scanning. + */ + if (mdb_is_relational_op(node->op) && node->col) { + + sarg.op = node->op; + sarg.value = node->value; + mdb_add_sarg(node->col, &sarg); + } + return 0; +} +int +mdb_test_sarg(MdbHandle *mdb, MdbColumn *col, MdbSargNode *node, MdbField *field) +{ + char tmpbuf[256]; + + if (node->op == MDB_ISNULL) { + if (field->is_null) return 0; + else return 1; + } else if (node->op == MDB_NOTNULL) { + if (field->is_null) return 1; + else return 0; + } + switch (col->col_type) { + case MDB_BOOL: + return mdb_test_int(node, !field->is_null); + break; + case MDB_BYTE: + return mdb_test_int(node, (gint32)((char *)field->value)[0]); + break; + case MDB_INT: + return mdb_test_int(node, (gint32)mdb_get_int16(field->value, 0)); + break; + case MDB_LONGINT: + return mdb_test_int(node, (gint32)mdb_get_int32(field->value, 0)); + break; + case MDB_TEXT: + mdb_unicode2ascii(mdb, field->value, field->siz, tmpbuf, 256); + return mdb_test_string(node, tmpbuf); + default: + fprintf(stderr, "Calling mdb_test_sarg on unknown type. Add code to mdb_test_sarg() for type %d\n",col->col_type); + break; + } + return 1; +} +int +mdb_find_field(int col_num, MdbField *fields, int num_fields) +{ + int i; + + for (i=0;i<num_fields;i++) { + if (fields[i].colnum == col_num) return i; + } + return -1; +} +int +mdb_test_sarg_node(MdbHandle *mdb, MdbSargNode *node, MdbField *fields, int num_fields) +{ + int elem; + MdbColumn *col; + int rc; + + if (mdb_is_relational_op(node->op)) { + col = node->col; + /* for const = const expressions */ + if (!col) { + return (node->value.i); + } + elem = mdb_find_field(col->col_num, fields, num_fields); + if (!mdb_test_sarg(mdb, col, node, &fields[elem])) + return 0; + } else { /* logical op */ + switch (node->op) { + case MDB_NOT: + rc = mdb_test_sarg_node(mdb, node->left, fields, num_fields); + return !rc; + break; + case MDB_AND: + if (!mdb_test_sarg_node(mdb, node->left, fields, num_fields)) + return 0; + return mdb_test_sarg_node(mdb, node->right, fields, num_fields); + break; + case MDB_OR: + if (mdb_test_sarg_node(mdb, node->left, fields, num_fields)) + return 1; + return mdb_test_sarg_node(mdb, node->right, fields, num_fields); + break; + } + } + return 1; +} +int +mdb_test_sargs(MdbTableDef *table, MdbField *fields, int num_fields) +{ + MdbSargNode *node; + MdbCatalogEntry *entry = table->entry; + MdbHandle *mdb = entry->mdb; + + node = table->sarg_tree; + + /* there may not be a sarg tree */ + if (!node) return 1; + + return mdb_test_sarg_node(mdb, node, fields, num_fields); +} +#if 0 +int mdb_test_sargs(MdbHandle *mdb, MdbColumn *col, int offset, int len) +{ +MdbSarg *sarg; +int i; + + for (i=0;i<col->num_sargs;i++) { + sarg = g_ptr_array_index (col->sargs, i); + if (!mdb_test_sarg(mdb, col, sarg, offset, len)) { + /* sarg didn't match, no sense going on */ + return 0; + } + } + + return 1; +} +#endif +int mdb_add_sarg(MdbColumn *col, MdbSarg *in_sarg) +{ +MdbSarg *sarg; + if (!col->sargs) { + col->sargs = g_ptr_array_new(); + } + sarg = g_memdup(in_sarg,sizeof(MdbSarg)); + g_ptr_array_add(col->sargs, sarg); + col->num_sargs++; + + return 1; +} +int mdb_add_sarg_by_name(MdbTableDef *table, char *colname, MdbSarg *in_sarg) +{ + MdbColumn *col; + unsigned int i; + + for (i=0;i<table->num_cols;i++) { + col = g_ptr_array_index (table->columns, i); + if (!strcasecmp(col->name,colname)) { + return mdb_add_sarg(col, in_sarg); + } + } + /* else didn't find the column return 0! */ + return 0; +} |