mirror of
https://github.com/mdbtools/mdbtools.git
synced 2025-09-21 03:57:55 +08:00
Make SQL parser/lexer reentrant
Provides thread safety for mdbtools ODBC driver
This commit is contained in:
@@ -32,7 +32,8 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <mdbtools.h>
|
#include <mdbtools.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct MdbSQL
|
||||||
|
{
|
||||||
MdbHandle *mdb;
|
MdbHandle *mdb;
|
||||||
int all_columns;
|
int all_columns;
|
||||||
int sel_count;
|
int sel_count;
|
||||||
@@ -71,16 +72,10 @@ typedef struct {
|
|||||||
MdbSarg *sarg;
|
MdbSarg *sarg;
|
||||||
} MdbSQLSarg;
|
} MdbSQLSarg;
|
||||||
|
|
||||||
extern char *g_input_ptr;
|
|
||||||
|
|
||||||
#undef YY_INPUT
|
|
||||||
#define YY_INPUT(b, r, ms) (r = mdb_sql_yyinput(b, ms));
|
|
||||||
|
|
||||||
#define mdb_sql_has_error(sql) ((sql)->error_msg[0] ? 1 : 0)
|
#define mdb_sql_has_error(sql) ((sql)->error_msg[0] ? 1 : 0)
|
||||||
#define mdb_sql_last_error(sql) ((sql)->error_msg)
|
#define mdb_sql_last_error(sql) ((sql)->error_msg)
|
||||||
|
|
||||||
void mdb_sql_error(MdbSQL* sql, char *fmt, ...);
|
void mdb_sql_error(MdbSQL* sql, char *fmt, ...);
|
||||||
MdbSQL *_mdb_sql(MdbSQL *sql);
|
|
||||||
MdbSQL *mdb_sql_init(void);
|
MdbSQL *mdb_sql_init(void);
|
||||||
MdbSQLSarg *mdb_sql_alloc_sarg(void);
|
MdbSQLSarg *mdb_sql_alloc_sarg(void);
|
||||||
MdbHandle *mdb_sql_open(MdbSQL *sql, char *db_name);
|
MdbHandle *mdb_sql_open(MdbSQL *sql, char *db_name);
|
||||||
@@ -110,6 +105,9 @@ int mdb_sql_add_temp_col(MdbSQL *sql, MdbTableDef *ttable, int col_num, char *na
|
|||||||
void mdb_sql_bind_column(MdbSQL *sql, int colnum, void *varaddr, int *len_ptr);
|
void mdb_sql_bind_column(MdbSQL *sql, int colnum, void *varaddr, int *len_ptr);
|
||||||
int mdb_sql_add_limit(MdbSQL *sql, char *limit);
|
int mdb_sql_add_limit(MdbSQL *sql, char *limit);
|
||||||
|
|
||||||
|
|
||||||
|
int parse_sql(MdbSQL * mdb, const gchar* str);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
%{
|
|
||||||
/* MDB Tools - A library for reading MS Access database file
|
/* MDB Tools - A library for reading MS Access database file
|
||||||
* Copyright (C) 2000 Brian Bruns
|
* Copyright (C) 2000 Brian Bruns
|
||||||
*
|
*
|
||||||
@@ -17,14 +16,38 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
%option noyywrap
|
||||||
#include "mdbsql.h"
|
%option case-insensitive
|
||||||
#include "parser.h"
|
%option never-interactive
|
||||||
extern int mdb_sql_yyinput(char *buf, int need);
|
|
||||||
%}
|
|
||||||
|
|
||||||
%option nounput
|
%option nounput
|
||||||
%option noinput
|
%option noinput
|
||||||
|
%option yylineno
|
||||||
|
%option reentrant
|
||||||
|
%option bison-bridge
|
||||||
|
%option bison-locations
|
||||||
|
|
||||||
|
// ensure that lexer will be 8-bit (and not just 7-bit)
|
||||||
|
%option 8bit
|
||||||
|
|
||||||
|
%{
|
||||||
|
#include <string.h>
|
||||||
|
#include "mdbsql.h"
|
||||||
|
struct sql_context;
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
#define YY_NEVER_INTERACTIVE 1
|
||||||
|
|
||||||
|
#ifndef YY_NO_UNPUT
|
||||||
|
#define YY_NO_UNPUT // unused
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define YY_NO_UNISTD_H
|
||||||
|
#endif
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
%%
|
%%
|
||||||
select { return SELECT; }
|
select { return SELECT; }
|
||||||
@@ -58,48 +81,39 @@ strptime { return STRPTIME; }
|
|||||||
\"[^"]*\" {
|
\"[^"]*\" {
|
||||||
int ip, op, ilen;
|
int ip, op, ilen;
|
||||||
ilen = strlen(yytext);
|
ilen = strlen(yytext);
|
||||||
yylval.name = malloc(ilen-1);
|
yylval->name = malloc(ilen-1);
|
||||||
for (ip=1, op=0; ip<ilen-1; ip++, op++) {
|
for (ip=1, op=0; ip<ilen-1; ip++, op++) {
|
||||||
if (yytext[ip] != '"') {
|
if (yytext[ip] != '"') {
|
||||||
yylval.name[op] = yytext[ip];
|
yylval->name[op] = yytext[ip];
|
||||||
} else if (yytext[ip+1] == '"') {
|
} else if (yytext[ip+1] == '"') {
|
||||||
yylval.name[op] = yytext[ip++];
|
yylval->name[op] = yytext[ip++];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
yylval.name[op]='\0';
|
yylval->name[op]='\0';
|
||||||
return IDENT;
|
return IDENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
[a-z\xa0-\xff][a-z0-9_#@\xa0-\xff]* { yylval.name = g_strdup(yytext); return NAME; }
|
[a-z\xa0-\xff][a-z0-9_#@\xa0-\xff]* { yylval->name = g_strdup(yytext); return NAME; }
|
||||||
|
|
||||||
'[^']*'' {
|
'[^']*'' {
|
||||||
yyless(yyleng-1);
|
yyless(yyleng-1);
|
||||||
yymore();
|
yymore();
|
||||||
}
|
}
|
||||||
'[^']*' {
|
'[^']*' {
|
||||||
yylval.name = g_strdup(yytext);
|
yylval->name = g_strdup(yytext);
|
||||||
return STRING;
|
return STRING;
|
||||||
}
|
}
|
||||||
|
|
||||||
(-*[0-9]+|([0-9]*\.[0-9]+)(e[-+]?[0-9]+)?) {
|
(-*[0-9]+|([0-9]*\.[0-9]+)(e[-+]?[0-9]+)?) {
|
||||||
yylval.name = g_strdup(yytext); return NUMBER;
|
yylval->name = g_strdup(yytext); return NUMBER;
|
||||||
}
|
}
|
||||||
~?(\/?[a-z0-9\.\xa0-\xff]+)+ {
|
~?(\/?[a-z0-9\.\xa0-\xff]+)+ {
|
||||||
yylval.name = g_strdup(yytext); return PATH;
|
yylval->name = g_strdup(yytext); return PATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
. { return yytext[0]; }
|
. { return yytext[0]; }
|
||||||
%%
|
%%
|
||||||
|
|
||||||
int yywrap()
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
void yyerror(char *s)
|
|
||||||
{
|
|
||||||
fprintf(stderr,"Error at Line : %s near %s\n", s, yytext);
|
|
||||||
mdb_sql_error(_mdb_sql(NULL), "%s near %s", s, yytext);
|
|
||||||
}
|
|
||||||
#if 0
|
#if 0
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
@@ -36,8 +36,6 @@
|
|||||||
|
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
|
||||||
char *g_input_ptr;
|
|
||||||
|
|
||||||
/* Prevent warnings from -Wmissing-prototypes. */
|
/* Prevent warnings from -Wmissing-prototypes. */
|
||||||
#ifdef YYPARSE_PARAM
|
#ifdef YYPARSE_PARAM
|
||||||
#if defined __STDC__ || defined __cplusplus
|
#if defined __STDC__ || defined __cplusplus
|
||||||
@@ -67,19 +65,6 @@ va_list ap;
|
|||||||
fprintf(stderr, "%s\n", sql->error_msg);
|
fprintf(stderr, "%s\n", sql->error_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
MdbSQL *mdb_sql_init()
|
MdbSQL *mdb_sql_init()
|
||||||
{
|
{
|
||||||
MdbSQL *sql;
|
MdbSQL *sql;
|
||||||
@@ -112,14 +97,9 @@ mdb_sql_run_query (MdbSQL* sql, const gchar* querystr) {
|
|||||||
g_return_val_if_fail (sql, NULL);
|
g_return_val_if_fail (sql, NULL);
|
||||||
g_return_val_if_fail (querystr, NULL);
|
g_return_val_if_fail (querystr, NULL);
|
||||||
|
|
||||||
g_input_ptr = (gchar*) querystr;
|
|
||||||
|
|
||||||
/* calls to yyparse should be serialized for thread safety */
|
|
||||||
|
|
||||||
/* begin unsafe */
|
|
||||||
_mdb_sql (sql);
|
|
||||||
sql->error_msg[0]='\0';
|
sql->error_msg[0]='\0';
|
||||||
if (yyparse()) {
|
|
||||||
|
if (parse_sql (sql, querystr)) {
|
||||||
/* end unsafe */
|
/* end unsafe */
|
||||||
mdb_sql_error (sql, _("Could not parse '%s' command"), querystr);
|
mdb_sql_error (sql, _("Could not parse '%s' command"), querystr);
|
||||||
mdb_sql_reset (sql);
|
mdb_sql_reset (sql);
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
%{
|
|
||||||
/* MDB Tools - A library for reading MS Access database files
|
/* MDB Tools - A library for reading MS Access database files
|
||||||
* Copyright (C) 2000 Brian Bruns
|
* Copyright (C) 2000 Brian Bruns
|
||||||
*
|
*
|
||||||
@@ -16,30 +15,50 @@
|
|||||||
* License along with this library; if not, write to the Free Software
|
* License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
%{
|
||||||
#include "mdbsql.h"
|
#include "mdbsql.h"
|
||||||
|
|
||||||
int yylex(void);
|
struct sql_context;
|
||||||
int yyerror(char *);
|
#include "parser.h"
|
||||||
|
|
||||||
MdbSQL *_mdb_sql(MdbSQL *sql)
|
typedef void *yyscan_t;
|
||||||
|
typedef struct yy_buffer_state* YY_BUFFER_STATE;
|
||||||
|
extern int yylex_init(yyscan_t* scanner);
|
||||||
|
extern int yylex_destroy(yyscan_t scanner);
|
||||||
|
extern int yylex(YYSTYPE* yylval_param, YYLTYPE* yyloc, yyscan_t yyscanner);
|
||||||
|
extern YY_BUFFER_STATE yy_scan_string(const char* buffer, yyscan_t scanner);
|
||||||
|
|
||||||
|
/** error handler for bison */
|
||||||
|
void yyerror(YYLTYPE* yyloc, struct sql_context* sql_ctx, char const* msg);
|
||||||
|
|
||||||
|
typedef struct sql_context
|
||||||
{
|
{
|
||||||
static MdbSQL *g_sql;
|
// lexer context
|
||||||
|
yyscan_t flex_scanner;
|
||||||
|
|
||||||
if (sql) {
|
MdbSQL *mdb;
|
||||||
g_sql = sql;
|
} sql_context;
|
||||||
}
|
|
||||||
return g_sql;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#define scanner parser_ctx->flex_scanner
|
||||||
|
|
||||||
|
// we want verbose error messages
|
||||||
|
#define YYERROR_VERBOSE 1
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
// make the parser reentrant
|
||||||
|
%locations
|
||||||
|
%define api.pure
|
||||||
|
%lex-param {void * scanner}
|
||||||
|
%parse-param {struct sql_context* parser_ctx}
|
||||||
|
|
||||||
%union {
|
%union {
|
||||||
char *name;
|
char *name;
|
||||||
double dval;
|
double dval;
|
||||||
int ival;
|
int ival;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
%start stmt
|
||||||
|
|
||||||
%token <name> IDENT NAME PATH STRING NUMBER
|
%token <name> IDENT NAME PATH STRING NUMBER
|
||||||
%token SELECT FROM WHERE CONNECT DISCONNECT TO LIST TABLES AND OR NOT LIMIT COUNT STRPTIME
|
%token SELECT FROM WHERE CONNECT DISCONNECT TO LIST TABLES AND OR NOT LIMIT COUNT STRPTIME
|
||||||
@@ -56,24 +75,24 @@ static MdbSQL *g_sql;
|
|||||||
|
|
||||||
stmt:
|
stmt:
|
||||||
query
|
query
|
||||||
| error { yyclearin; mdb_sql_reset(_mdb_sql(NULL)); }
|
| error { yyclearin; mdb_sql_reset(parser_ctx->mdb); }
|
||||||
;
|
;
|
||||||
|
|
||||||
query:
|
query:
|
||||||
SELECT column_list FROM table where_clause limit_clause {
|
SELECT column_list FROM table where_clause limit_clause {
|
||||||
mdb_sql_select(_mdb_sql(NULL));
|
mdb_sql_select(parser_ctx->mdb);
|
||||||
}
|
}
|
||||||
| CONNECT TO database {
|
| CONNECT TO database {
|
||||||
mdb_sql_open(_mdb_sql(NULL), $3); free($3);
|
mdb_sql_open(parser_ctx->mdb, $3); free($3);
|
||||||
}
|
}
|
||||||
| DISCONNECT {
|
| DISCONNECT {
|
||||||
mdb_sql_close(_mdb_sql(NULL));
|
mdb_sql_close(parser_ctx->mdb);
|
||||||
}
|
}
|
||||||
| DESCRIBE TABLE table {
|
| DESCRIBE TABLE table {
|
||||||
mdb_sql_describe_table(_mdb_sql(NULL));
|
mdb_sql_describe_table(parser_ctx->mdb);
|
||||||
}
|
}
|
||||||
| LIST TABLES {
|
| LIST TABLES {
|
||||||
mdb_sql_listtables(_mdb_sql(NULL));
|
mdb_sql_listtables(parser_ctx->mdb);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -84,35 +103,35 @@ where_clause:
|
|||||||
|
|
||||||
limit_clause:
|
limit_clause:
|
||||||
/* empty */
|
/* empty */
|
||||||
| LIMIT NUMBER { mdb_sql_add_limit(_mdb_sql(NULL), $2); free($2); }
|
| LIMIT NUMBER { mdb_sql_add_limit(parser_ctx->mdb, $2); free($2); }
|
||||||
;
|
;
|
||||||
|
|
||||||
sarg_list:
|
sarg_list:
|
||||||
sarg
|
sarg
|
||||||
| '(' sarg_list ')'
|
| '(' sarg_list ')'
|
||||||
| NOT sarg_list { mdb_sql_add_not(_mdb_sql(NULL)); }
|
| NOT sarg_list { mdb_sql_add_not(parser_ctx->mdb); }
|
||||||
| sarg_list OR sarg_list { mdb_sql_add_or(_mdb_sql(NULL)); }
|
| sarg_list OR sarg_list { mdb_sql_add_or(parser_ctx->mdb); }
|
||||||
| sarg_list AND sarg_list { mdb_sql_add_and(_mdb_sql(NULL)); }
|
| sarg_list AND sarg_list { mdb_sql_add_and(parser_ctx->mdb); }
|
||||||
;
|
;
|
||||||
|
|
||||||
sarg:
|
sarg:
|
||||||
identifier operator constant {
|
identifier operator constant {
|
||||||
mdb_sql_add_sarg(_mdb_sql(NULL), $1, $2, $3);
|
mdb_sql_add_sarg(parser_ctx->mdb, $1, $2, $3);
|
||||||
free($1);
|
free($1);
|
||||||
free($3);
|
free($3);
|
||||||
}
|
}
|
||||||
| constant operator identifier {
|
| constant operator identifier {
|
||||||
mdb_sql_add_sarg(_mdb_sql(NULL), $3, $2, $1);
|
mdb_sql_add_sarg(parser_ctx->mdb, $3, $2, $1);
|
||||||
free($1);
|
free($1);
|
||||||
free($3);
|
free($3);
|
||||||
}
|
}
|
||||||
| constant operator constant {
|
| constant operator constant {
|
||||||
mdb_sql_eval_expr(_mdb_sql(NULL), $1, $2, $3);
|
mdb_sql_eval_expr(parser_ctx->mdb, $1, $2, $3);
|
||||||
free($1);
|
free($1);
|
||||||
free($3);
|
free($3);
|
||||||
}
|
}
|
||||||
| identifier nulloperator {
|
| identifier nulloperator {
|
||||||
mdb_sql_add_sarg(_mdb_sql(NULL), $1, $2, NULL);
|
mdb_sql_add_sarg(parser_ctx->mdb, $1, $2, NULL);
|
||||||
free($1);
|
free($1);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@@ -138,7 +157,7 @@ nulloperator:
|
|||||||
|
|
||||||
constant:
|
constant:
|
||||||
STRPTIME '(' constant ',' constant ')' {
|
STRPTIME '(' constant ',' constant ')' {
|
||||||
$$ = mdb_sql_strptime(_mdb_sql(NULL), $3, $5);
|
$$ = mdb_sql_strptime(parser_ctx->mdb, $3, $5);
|
||||||
free($3);
|
free($3);
|
||||||
free($5);
|
free($5);
|
||||||
}
|
}
|
||||||
@@ -152,19 +171,39 @@ database:
|
|||||||
;
|
;
|
||||||
|
|
||||||
table:
|
table:
|
||||||
identifier { mdb_sql_add_table(_mdb_sql(NULL), $1); free($1); }
|
identifier { mdb_sql_add_table(parser_ctx->mdb, $1); free($1); }
|
||||||
;
|
;
|
||||||
|
|
||||||
column_list:
|
column_list:
|
||||||
COUNT '(' '*' ')' { mdb_sql_sel_count(_mdb_sql(NULL)); }
|
COUNT '(' '*' ')' { mdb_sql_sel_count(parser_ctx->mdb); }
|
||||||
| '*' { mdb_sql_all_columns(_mdb_sql(NULL)); }
|
| '*' { mdb_sql_all_columns(parser_ctx->mdb); }
|
||||||
| column
|
| column
|
||||||
| column ',' column_list
|
| column ',' column_list
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
column:
|
column:
|
||||||
identifier { mdb_sql_add_column(_mdb_sql(NULL), $1); free($1); }
|
identifier { mdb_sql_add_column(parser_ctx->mdb, $1); free($1); }
|
||||||
;
|
;
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
|
|
||||||
|
int parse_sql( MdbSQL * mdb, const gchar *str)
|
||||||
|
{
|
||||||
|
sql_context ctx;
|
||||||
|
ctx.mdb = mdb;
|
||||||
|
|
||||||
|
yylex_init(&ctx.flex_scanner);
|
||||||
|
yy_scan_string(str, ctx.flex_scanner);
|
||||||
|
int res = yyparse(&ctx);
|
||||||
|
yylex_destroy(ctx.flex_scanner);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void yyerror(YYLTYPE* yyloc,sql_context* sql_ctx, char const * msg)
|
||||||
|
{
|
||||||
|
fprintf(stderr,"Error at Line : %s\n", msg);
|
||||||
|
mdb_sql_error(sql_ctx->mdb, "%s", msg);
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user