From 58cb55ef0a76da57a7c0c92b9daf686d2fb0a0e2 Mon Sep 17 00:00:00 2001 From: brianb Date: Sun, 8 Apr 2001 01:32:43 +0000 Subject: [PATCH] First attempt at sql engine --- src/include/mdbtools.h | 1 + src/libmdb/catalog.c | 4 + src/libmdb/data.c | 36 +++++ src/libmdb/file.c | 2 +- src/sql/Makefile | 30 ++++ src/sql/main.c | 76 +++++++++ src/sql/mdbsql.c | 357 +++++++++++++++++++++++++++++++++++++++++ src/sql/mdbsql.h | 48 ++++++ src/sql/sql.l | 46 ++++++ src/sql/sql.y | 81 ++++++++++ 10 files changed, 680 insertions(+), 1 deletion(-) create mode 100644 src/sql/Makefile create mode 100644 src/sql/main.c create mode 100644 src/sql/mdbsql.c create mode 100644 src/sql/mdbsql.h create mode 100644 src/sql/sql.l create mode 100644 src/sql/sql.y diff --git a/src/include/mdbtools.h b/src/include/mdbtools.h index 1d97d64..913ee3b 100644 --- a/src/include/mdbtools.h +++ b/src/include/mdbtools.h @@ -159,6 +159,7 @@ typedef struct { int num_sargs; GPtrArray *sargs; unsigned char is_fixed; + int query_order; } MdbColumn; typedef union { diff --git a/src/libmdb/catalog.c b/src/libmdb/catalog.c index bff2aa3..e9fc009 100644 --- a/src/libmdb/catalog.c +++ b/src/libmdb/catalog.c @@ -106,6 +106,7 @@ int next_pg, next_pg_off; #if 0 next_pg = MDB_CATALOG_PG; mdb_free_catalog(mdb); + mdb->num_catalog = 0; while (next_pg) { mdb_read_pg(mdb, next_pg); @@ -126,6 +127,9 @@ int next_pg, next_pg_off; } return (mdb->catalog); #endif + mdb_free_catalog(mdb); + mdb->num_catalog = 0; + mdb->catalog = g_array_new(FALSE,FALSE,sizeof(MdbCatalogEntry)); next_pg=0; while (mdb_read_pg(mdb,next_pg)) { diff --git a/src/libmdb/data.c b/src/libmdb/data.c index 4ca59b2..4356f78 100644 --- a/src/libmdb/data.c +++ b/src/libmdb/data.c @@ -411,3 +411,39 @@ time_t t; } return NULL; } +int mdb_col_disp_size(MdbColumn *col) +{ + switch (col->col_type) { + case MDB_BOOL: + return 1; + break; + case MDB_BYTE: + return 3; + break; + case MDB_INT: + return 5; + break; + case MDB_LONGINT: + return 7; + break; + case MDB_FLOAT: + return 10; + break; + case MDB_DOUBLE: + return 10; + break; + case MDB_TEXT: + return col->col_size; + break; + case MDB_SDATETIME: + return 20; + break; + case MDB_MEMO: + return 255; + break; + case MDB_MONEY: + return 12; + break; + } + return 0; +} diff --git a/src/libmdb/file.c b/src/libmdb/file.c index a194adc..fbaead6 100644 --- a/src/libmdb/file.c +++ b/src/libmdb/file.c @@ -33,7 +33,7 @@ int j,pos; mdb->fd = open(filename,O_RDONLY); if (mdb->fd==-1) { - fprintf(stderr,"Couldn't open file %s\n",filename); + /* fprintf(stderr,"Couldn't open file %s\n",filename); */ return NULL; } if (!mdb_read_pg(mdb, 0)) { diff --git a/src/sql/Makefile b/src/sql/Makefile new file mode 100644 index 0000000..29c3e8f --- /dev/null +++ b/src/sql/Makefile @@ -0,0 +1,30 @@ +SHELL = /bin/sh +LEX = flex -i +YACC = yacc -d +CC = gcc +CPPFLAGS = +CFLAGS = $(CPPFLAG) -g -O2 -DHW_LITTLE_ENDIAN +LDFLAGS = +LIBS = -L ../libmdb -lmdb -ll `glib-config --libs` -lreadline -lncurses + +INC = -I ../include `glib-config --cflags` -I/usr/include/readline +OBJS = y.tab.o lex.yy.o mdbsql.o main.o + +all: sql + +libmdb: $(OBJS) + rm -f libmdb.a + ar cq libmdb.a $(OBJS) +clean: + rm -f core *.o *.a y.tab.* lex.yy.c sql + +lex.yy.c: sql.l + $(LEX) $< +y.tab.c: sql.y + $(YACC) $< +.c.o: + $(CC) $(CFLAGS) -g -c $< $(INC) + +sql: $(OBJS) + $(CC) -o $@ $(LDFLAGS) $(OBJS) $(LIBS) + diff --git a/src/sql/main.c b/src/sql/main.c new file mode 100644 index 0000000..08b46e7 --- /dev/null +++ b/src/sql/main.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include "mdbsql.h" + +extern MdbSQL *g_sql; + +char *g_input_ptr; + +int mdb_sql_yyinput(char *buf, int need) +{ +int cplen, have; + + have = strlen(g_input_ptr); + cplen = need > have ? have : need; + + if (cplen>0) { + memcpy(buf, g_input_ptr, cplen); + g_input_ptr += cplen; + } + return cplen; +} + +int parse(char *buf) +{ + g_input_ptr = buf; + if (yyparse()) { + fprintf(stderr, "Couldn't parse SQL\n"); + return 1; + } else { + return 0; + } +} + +main() +{ +char *s; +char prompt[20]; +int line = 1; +char *mybuf; +int bufsz = 4096; +int done = 0; + + /* initialize the SQL engine */ + g_sql = mdb_sql_init(); + + /* give the buffer an initial size */ + bufsz = 4096; + mybuf = (char *) malloc(bufsz); + mybuf[0]='\0'; + + sprintf(prompt,"1 => "); + s=readline(prompt); + while (!done) { + if (!strcmp(s,"go")) { + line = 0; + parse(mybuf); + mybuf[0]='\0'; + } else if (!strcmp(s,"reset")) { + line = 0; + mybuf[0]='\0'; + } else { + add_history(s); + strcat(mybuf,s); + /* preserve line numbering for the parser */ + strcat(mybuf,"\n"); + } + sprintf(prompt,"%d => ",++line); + free(s); + s=readline(prompt); + if (!strcmp(s,"exit") || !strcmp(s,"quit") || !strcmp(s,"bye")) { + done = 1; + } + } + mdb_sql_exit(g_sql); +} diff --git a/src/sql/mdbsql.c b/src/sql/mdbsql.c new file mode 100644 index 0000000..ab59c98 --- /dev/null +++ b/src/sql/mdbsql.c @@ -0,0 +1,357 @@ +#include "mdbsql.h" +#include + +mdb_sql_error(char *fmt, ...) +{ +va_list ap; + + va_start(ap, fmt); + vfprintf (stderr,fmt, ap); + va_end(ap); + fprintf(stderr,"\n"); +} +MdbSQL *mdb_sql_init() +{ +MdbSQL *sql; + + mdb_init(); + sql = (MdbSQL *) g_malloc0(sizeof(MdbSQL)); + sql->columns = g_ptr_array_new(); + sql->tables = g_ptr_array_new(); + sql->sargs = g_ptr_array_new(); + + return sql; +} + +MdbSQLSarg *mdb_sql_alloc_sarg() +{ +MdbSQLSarg *sql_sarg; + sql_sarg = (MdbSQLSarg *) malloc(sizeof(MdbSQLSarg)); + memset(sql_sarg,0,sizeof(MdbSQLSarg)); + sql_sarg->sarg = (MdbSarg *) malloc(sizeof(MdbSarg)); + memset(sql_sarg->sarg,0,sizeof(MdbSarg)); + return sql_sarg; +} +MdbSQLColumn *mdb_sql_alloc_column() +{ +MdbSQLColumn *c; + + c = (MdbSQLColumn *) malloc(sizeof(MdbSQLColumn)); + memset(c,0,sizeof(MdbSQLColumn)); + return c; +} +MdbSQLTable *mdb_sql_alloc_table() +{ +MdbSQLTable *t; + + t = (MdbSQLTable *) malloc(sizeof(MdbSQLTable)); + memset(t,0,sizeof(MdbSQLTable)); + return t; +} + +MdbHandle *mdb_sql_open(MdbSQL *sql, char *db_name) +{ +int fail = 0; + if (!(sql->mdb = mdb_open(db_name))) { + if (!strstr(db_name, ".mdb")) { + char *tmpstr = (char *) malloc(strlen(db_name)+5); + strcpy(tmpstr,db_name); + strcat(tmpstr,".mdb"); + if (!(sql->mdb = mdb_open(tmpstr))) { + fail++; + } + free(tmpstr); + } else { + fail++; + } + } + if (fail) { + mdb_sql_error("Unable to locate database %s", db_name); + } + return sql->mdb; + +} +int mdb_sql_add_sarg(MdbSQL *sql, char *col_name, int op, char *constant) +{ +MdbSQLSarg *sql_sarg; + + sql_sarg = mdb_sql_alloc_sarg(); + sql_sarg->col_name = g_strdup(col_name); + sql_sarg->sarg->op = op; + sql_sarg->sarg->value.i = atoi(constant); + g_ptr_array_add(sql->sargs, sql_sarg); + sql->num_sargs++; +} +int mdb_sql_all_columns(MdbSQL *sql) +{ + sql->all_columns=1; +} +int mdb_sql_add_column(MdbSQL *sql, char *column_name) +{ +MdbSQLColumn *c, *cp; + + c = mdb_sql_alloc_column(); + c->name = g_strdup(column_name); + g_ptr_array_add(sql->columns, c); + sql->num_columns++; + return 0; +} +int mdb_sql_add_table(MdbSQL *sql, char *table_name) +{ +MdbSQLTable *t; + + t = mdb_sql_alloc_table(); + t->name = g_strdup(table_name); + t->alias = NULL; + g_ptr_array_add(sql->tables, t); + sql->num_tables++; + return 0; +} +void mdb_sql_dump(MdbSQL *sql) +{ +int i; +MdbSQLColumn *c; +MdbSQLTable *t; + + for (i=0;inum_columns;i++) { + c = g_ptr_array_index(sql->columns,i); + printf("column = %s\n",c->name); + } + for (i=0;inum_tables;i++) { + t = g_ptr_array_index(sql->tables,i); + printf("table = %s\n",t->name); + } +} +void mdb_sql_exit(MdbSQL *sql) +{ +int i; +MdbSQLColumn *c; +MdbSQLTable *t; +MdbSQLSarg *sql_sarg; + + for (i=0;inum_columns;i++) { + c = g_ptr_array_index(sql->columns,i); + if (c->name) g_free(c->name); + } + for (i=0;inum_tables;i++) { + t = g_ptr_array_index(sql->tables,i); + if (t->name) g_free(t->name); + } + for (i=0;inum_sargs;i++) { + sql_sarg = g_ptr_array_index(sql->sargs,i); + if (sql_sarg->col_name) g_free(sql_sarg->col_name); + if (sql_sarg->sarg) g_free(sql_sarg->sarg); + } + g_ptr_array_free(sql->columns,TRUE); + g_ptr_array_free(sql->tables,TRUE); + g_ptr_array_free(sql->sargs,TRUE); +} +void mdb_sql_reset(MdbSQL *sql) +{ +int i; +MdbSQLColumn *c; +MdbSQLTable *t; +MdbSQLSarg *sql_sarg; + + for (i=0;inum_columns;i++) { + c = g_ptr_array_index(sql->columns,i); + if (c->name) g_free(c->name); + } + for (i=0;inum_tables;i++) { + t = g_ptr_array_index(sql->tables,i); + if (t->name) g_free(t->name); + } + for (i=0;inum_sargs;i++) { + sql_sarg = g_ptr_array_index(sql->sargs,i); + if (sql_sarg->col_name) g_free(sql_sarg->col_name); + if (sql_sarg->sarg) g_free(sql_sarg->sarg); + } + g_ptr_array_free(sql->columns,TRUE); + g_ptr_array_free(sql->tables,TRUE); + g_ptr_array_free(sql->sargs,TRUE); + + sql->all_columns = 0; + sql->num_columns = 0; + sql->columns = g_ptr_array_new(); + sql->num_tables = 0; + sql->tables = g_ptr_array_new(); + sql->num_sargs = 0; + sql->sargs = g_ptr_array_new(); +} +static void print_break(int sz, int first) +{ +int i; + if (first) { + fprintf(stdout,"+"); + } + for (i=0;i= vlen ? ' ' : v[i]); + } + fprintf(stdout,"|"); +} +void mdb_sql_listtables(MdbSQL *sql) +{ +int i; +MdbCatalogEntry entry; +MdbHandle *mdb = sql->mdb; + + if (!mdb) { + mdb_sql_error("You must connect to a database first"); + return; + } + mdb_read_catalog (mdb, MDB_TABLE); + + + print_break (30,1); + fprintf(stdout,"\n"); + print_value ("Tables",30,1); + fprintf(stdout,"\n"); + print_break (30,1); + fprintf(stdout,"\n"); + /* loop over each entry in the catalog */ + for (i=0; i < mdb->num_catalog; i++) { + entry = g_array_index (mdb->catalog, MdbCatalogEntry, i); + /* if it's a table */ + if (entry.object_type == MDB_TABLE) { + if (strncmp (entry.object_name, "MSys", 4)) { + print_value (entry.object_name,30,1); + fprintf(stdout,"\n"); + } + } + } + print_break (30,1); + fprintf(stdout,"\n"); +} +void mdb_sql_select(MdbSQL *sql) +{ +int i,j; +MdbCatalogEntry entry; +MdbHandle *mdb = sql->mdb; +MdbTableDef *table = NULL; +MdbSQLTable *sql_tab; +char *bound_values[256]; +MdbColumn *col; +MdbSQLColumn *sqlcol; +MdbSQLSarg *sql_sarg; +int found = 0; + + if (!mdb) { + mdb_sql_error("You must connect to a database first"); + return; + } + + sql_tab = g_ptr_array_index(sql->tables,0); + + mdb_read_catalog(mdb, MDB_TABLE); + + for (i=0;inum_catalog;i++) { + entry = g_array_index(mdb->catalog,MdbCatalogEntry,i); + if (entry.object_type == MDB_TABLE && + !strcmp(entry.object_name,sql_tab->name)) { + table = mdb_read_table(&entry); + break; + } + } + if (!table) { + mdb_sql_error("%s is not a table in this database", sql_tab->name); + /* the column and table names are no good now */ + mdb_sql_reset(sql); + return; + } + mdb_read_columns(table); + mdb_rewind_table(table); + + if (sql->all_columns) { + for (i=0;inum_cols;i++) { + col=g_ptr_array_index(table->columns,i); + sqlcol = mdb_sql_alloc_column(); + sqlcol->name = g_strdup(col->name); + g_ptr_array_add(sql->columns, sqlcol); + sql->num_columns++; + } + } + for (i=0;inum_columns;i++) { + sqlcol = g_ptr_array_index(sql->columns,i); + found=0; + for (j=0;jnum_cols;j++) { + col=g_ptr_array_index(table->columns,j); + if (!strcmp(sqlcol->name, col->name)) { + bound_values[i] = (char *) malloc(MDB_BIND_SIZE); + bound_values[i][0] = '\0'; + /* bind the column to its listed (SQL) position */ + mdb_bind_column(table, j+1, bound_values[i]); + sqlcol->disp_size = mdb_col_disp_size(col); + found=1; + break; + } + } + if (!found) { + mdb_sql_error("Column %s not found",sqlcol->name); + mdb_sql_reset(sql); + return; + } + } + + /* now add back the sargs */ + for (i=0;inum_sargs;i++) { + sql_sarg=g_ptr_array_index(sql->sargs,i); + fprintf(stdout,"Sarg for %s\n",sql_sarg->col_name); + mdb_add_sarg_by_name(table,sql_sarg->col_name, sql_sarg->sarg); + } + + /* print header */ + for (j=0;jnum_columns;j++) { + sqlcol = g_ptr_array_index(sql->columns,j); + print_break(sqlcol->disp_size, !j); + } + fprintf(stdout,"\n"); + for (j=0;jnum_columns;j++) { + sqlcol = g_ptr_array_index(sql->columns,j); + print_value(sqlcol->name,sqlcol->disp_size,!j); + } + fprintf(stdout,"\n"); + for (j=0;jnum_columns;j++) { + sqlcol = g_ptr_array_index(sql->columns,j); + print_break(sqlcol->disp_size, !j); + } + fprintf(stdout,"\n"); + + /* print each row */ + while(mdb_fetch_row(table)) { + for (j=0;jnum_columns;j++) { + sqlcol = g_ptr_array_index(sql->columns,j); + print_value(bound_values[j],sqlcol->disp_size,!j); + } + fprintf(stdout,"\n"); + } + + /* footer */ + for (j=0;jnum_columns;j++) { + sqlcol = g_ptr_array_index(sql->columns,j); + print_break(sqlcol->disp_size, !j); + } + + fprintf(stdout,"\n"); + /* clean up */ + for (j=0;jnum_columns;j++) { + if (bound_values[j]) free(bound_values[j]); + } + + /* the column and table names are no good now */ + mdb_sql_reset(sql); +} + diff --git a/src/sql/mdbsql.h b/src/sql/mdbsql.h new file mode 100644 index 0000000..269b876 --- /dev/null +++ b/src/sql/mdbsql.h @@ -0,0 +1,48 @@ +#include +#include +#include +#include + +typedef struct { + MdbHandle *mdb; + int all_columns; + int num_columns; + GPtrArray *columns; + int num_tables; + GPtrArray *tables; + int num_sargs; + GPtrArray *sargs; +} MdbSQL; + +typedef struct { + char *name; + int disp_size; +} MdbSQLColumn; + +typedef struct { + char *name; + char *alias; +} MdbSQLTable; + +typedef struct { + char *col_name; + MdbSarg *sarg; +} MdbSQLSarg; + +#undef YY_INPUT +#define YY_INPUT(b, r, ms) (r = mdb_sql_yyinput(b, ms)); + +MdbSQL *mdb_sql_init(); +MdbSQLSarg *mdb_sql_alloc_sarg(); +MdbSQLColumn *mdb_sql_alloc_column(); +MdbSQLTable *mdb_sql_alloc_table(); +MdbHandle *mdb_sql_open(MdbSQL *sql, char *db_name); +int mdb_sql_add_sarg(MdbSQL *sql, char *col_name, int op, char *constant); +int mdb_sql_all_columns(MdbSQL *sql); +int mdb_sql_add_column(MdbSQL *sql, char *column_name); +int mdb_sql_add_table(MdbSQL *sql, char *table_name); +void mdb_sql_dump(MdbSQL *sql); +void mdb_sql_exit(MdbSQL *sql); +void mdb_sql_reset(MdbSQL *sql); +void mdb_sql_listtables(MdbSQL *sql); +void mdb_sql_select(MdbSQL *sql); diff --git a/src/sql/sql.l b/src/sql/sql.l new file mode 100644 index 0000000..1c3ea89 --- /dev/null +++ b/src/sql/sql.l @@ -0,0 +1,46 @@ +%{ +#include "y.tab.h" +#include +#include "mdbsql.h" + +extern MdbSQL *g_sql; +%} + +%% +select { return SELECT; } +from { return FROM; } +connect { return CONNECT; } +to { return TO; } +list { return LIST; } +where { return WHERE; } +and { return AND; } +tables { return TABLES; } +[ \t\r] ; +[A-z][A-z0-9]* { yylval.name = strdup(yytext); return NAME; } +'.*' { yylval.name = strdup(yytext); return STRING; } +([0-9]+|([0-9]*\.[0-9+)([eE][-+]?[0-9]+)?) { + yylval.name = strdup(yytext); return NUMBER; + } +(\/?[A-z0-9\.]+)+ { yylval.name = strdup(yytext); return PATH; } +. { return yytext[0]; } +%% + +void yyerror(char *s) +{ + fprintf(stderr,"Error at Line : %s near %s\n", s, yytext); +} +#if 0 +int main(int argc, char **argv) +{ +int i; + + g_sql = mdb_sql_init(); + yyin = stdin; + if (yyparse()) { + fprintf(stderr, "Couldn't parse SQL\n"); + exit(1); + } + mdb_sql_dump(g_sql); + mdb_sql_exit(g_sql); +} +#endif diff --git a/src/sql/sql.y b/src/sql/sql.y new file mode 100644 index 0000000..7bb4112 --- /dev/null +++ b/src/sql/sql.y @@ -0,0 +1,81 @@ +%{ +#include "mdbsql.h" + +MdbSQL *g_sql; +%} + +%union { + char *name; + double dval; + int ival; +} + +%token NAME PATH NUMBER STRING +%token SELECT FROM WHERE CONNECT TO LIST TABLES WHERE AND + +%% + +query: + SELECT column_list FROM table where_clause { + mdb_sql_select(g_sql); + } + | CONNECT TO database { + mdb_sql_open(g_sql, $3.name); free($3.name); + } + | LIST TABLES { + mdb_sql_listtables(g_sql); + } + ; + +where_clause: + /* empty */ + | WHERE sarg_list + ; + +sarg_list: + sarg + | sarg AND sarg_list + ; + +sarg: + NAME operator constant { + mdb_sql_add_sarg(g_sql, $1.name, $2.ival, $3.name); + free($1.name); + free($3.name); + } + | constant operator NAME { + mdb_sql_add_sarg(g_sql, $3.name, $2.ival, $1.name); + free($1.name); + free($3.name); + } + ; + +operator: + '=' { $$.ival = MDB_EQUAL; } + | '>' { $$.ival = MDB_GT; } + | '<' { $$.ival = MDB_LT; } + ; +constant: + NUMBER { $$.name = $1.name; } + | STRING { $$.name = $1.name; } + ; + +database: + PATH + | NAME + +table: + NAME { mdb_sql_add_table(g_sql, $1.name); free($1.name); } + ; + +column_list: + '*' { mdb_sql_all_columns(g_sql); } + | column + | column ',' column_list + ; + +column: + NAME { mdb_sql_add_column(g_sql, $1.name); free($1.name); } + ; + +%%