310 lines
6.4 KiB
Text
Executable file
310 lines
6.4 KiB
Text
Executable file
/***************************************************************
|
|
* Run Time Access
|
|
* Copyright (C) 2003 Robert W Smith (bsmith@linuxtoys.org)
|
|
*
|
|
* This program is distributed under the terms of the GNU LGPL.
|
|
* See the file COPYING file.
|
|
**************************************************************/
|
|
|
|
/***************************************************************
|
|
* parse.y -- Yacc parser for our subset of SQL.
|
|
**************************************************************/
|
|
|
|
%{
|
|
#include <stdlib.h>
|
|
#include "do_sql.h"
|
|
|
|
|
|
#define YYSTYPE int
|
|
|
|
|
|
/* While we parse the SET and WHERE clause we need someplace
|
|
* to temporarily store the type of relation */
|
|
static int whrrelat;
|
|
|
|
/* We don't want to pass pointers to allocated memory on the */
|
|
/* yacc stack, since the memory might not be freed when an */
|
|
/* error is detected. Instead, we allocate the memory and */
|
|
/* put the pointer into the following table where it is easy */
|
|
/* free on error. */
|
|
char *parsestr[MXPARSESTR];
|
|
|
|
static int n; /* temp/scratch integer */
|
|
|
|
extern struct Sql_Cmd cmd; /* encoded SQL command (a global) */
|
|
extern char *yytext;
|
|
extern int yyleng;
|
|
extern void yyerror(char *);
|
|
extern int yylex();
|
|
%}
|
|
|
|
%token SQLBEGIN
|
|
%token SQLCOMMIT
|
|
%token SELECT
|
|
%token UPDATE
|
|
%token FROM
|
|
%token WHERE
|
|
%token NAME
|
|
%token STRING
|
|
%token INTEGER
|
|
%token REALNUM
|
|
%token LIMIT
|
|
%token OFFSET
|
|
%token SET
|
|
/* relations for the where clause */
|
|
%token EQ
|
|
%token NE
|
|
%token GT
|
|
%token LT
|
|
%token GE
|
|
%token LE
|
|
|
|
|
|
%left AND
|
|
%left ','
|
|
%left '.'
|
|
%%
|
|
|
|
|
|
command:
|
|
{ YYABORT; }
|
|
| begin_statement
|
|
| commit_statement
|
|
| select_statement
|
|
| update_statement
|
|
| function_call
|
|
;
|
|
|
|
|
|
begin_statement:
|
|
SQLBEGIN ';'
|
|
{ cmd.command = RTA_BEGIN;
|
|
YYACCEPT;
|
|
}
|
|
| SQLBEGIN
|
|
{ cmd.command = RTA_BEGIN;
|
|
YYACCEPT;
|
|
}
|
|
;
|
|
|
|
commit_statement:
|
|
SQLCOMMIT ';'
|
|
{ cmd.command = RTA_COMMIT;
|
|
YYACCEPT;
|
|
}
|
|
| SQLCOMMIT
|
|
{ cmd.command = RTA_COMMIT;
|
|
YYACCEPT;
|
|
}
|
|
;
|
|
|
|
select_statement:
|
|
SELECT column_list FROM table_name where_clause limit_clause ';'
|
|
{ cmd.command = RTA_SELECT;
|
|
YYACCEPT;
|
|
}
|
|
| SELECT column_list FROM table_name where_clause limit_clause
|
|
{ cmd.command = RTA_SELECT;
|
|
YYACCEPT;
|
|
}
|
|
;
|
|
|
|
column_list:
|
|
NAME
|
|
{ cmd.cols[cmd.ncols] = parsestr[(int) $1];
|
|
parsestr[(int) $1] = (char *) NULL;
|
|
cmd.ncols++;
|
|
}
|
|
| column_list "," NAME
|
|
{ cmd.cols[cmd.ncols] = parsestr[(int) $3];
|
|
parsestr[(int) $3] = (char *) NULL;
|
|
cmd.ncols++;
|
|
if (cmd.ncols > NCMDCOLS) {
|
|
/* too many columns in list */
|
|
send_error(LOC, E_BADPARSE);
|
|
}
|
|
}
|
|
;
|
|
|
|
table_name:
|
|
NAME
|
|
{
|
|
cmd.tbl = parsestr[(int) $1];
|
|
parsestr[(int) $1] = (char *) NULL;
|
|
}
|
|
| NAME "." NAME
|
|
{
|
|
cmd.tbl = parsestr[(int) $3];
|
|
parsestr[(int) $3] = (char *) NULL;
|
|
}
|
|
;
|
|
|
|
|
|
where_clause:
|
|
/* empty, optional */
|
|
| WHERE test_condition
|
|
;
|
|
|
|
|
|
test_condition:
|
|
'(' test_condition ')'
|
|
| test_condition AND test_condition
|
|
| NAME relation literal
|
|
{ n = cmd.nwhrcols;
|
|
cmd.whrcols[n] = parsestr[(int) $1];
|
|
parsestr[(int) $1] = (char *) NULL;
|
|
cmd.whrrel[n] = whrrelat;
|
|
cmd.whrvals[n] = parsestr[(int) $3];
|
|
parsestr[(int) $3] = (char *) NULL;
|
|
cmd.nwhrcols++;
|
|
if (cmd.nwhrcols > NCMDCOLS) {
|
|
/* too many columns in list */
|
|
send_error(LOC, E_BADPARSE);
|
|
}
|
|
}
|
|
;
|
|
|
|
|
|
relation:
|
|
EQ { whrrelat = RTA_EQ; }
|
|
| NE { whrrelat = RTA_NE; }
|
|
| GT { whrrelat = RTA_GT; }
|
|
| LT { whrrelat = RTA_LT; }
|
|
| GE { whrrelat = RTA_GE; }
|
|
| LE { whrrelat = RTA_LE; }
|
|
;
|
|
|
|
|
|
limit_clause:
|
|
/* empty, optional */
|
|
| LIMIT INTEGER
|
|
{ cmd.limit = atoi(parsestr[(int) $2]);
|
|
free(parsestr[(int) $2]);
|
|
parsestr[(int) $2] = (char *) NULL;
|
|
}
|
|
| LIMIT INTEGER OFFSET INTEGER
|
|
{ cmd.limit = atoi(parsestr[(int) $2]);
|
|
free(parsestr[(int) $2]);
|
|
parsestr[(int) $2] = (char *) NULL;
|
|
cmd.offset = atoi(parsestr[(int) $4]);
|
|
free(parsestr[(int) $4]);
|
|
parsestr[(int) $4] = (char *) NULL;
|
|
}
|
|
;
|
|
|
|
|
|
update_statement:
|
|
UPDATE NAME SET set_list where_clause limit_clause ';'
|
|
{ cmd.command = RTA_UPDATE;
|
|
cmd.tbl = parsestr[(int) $2];
|
|
parsestr[(int) $2] = (char *) NULL;
|
|
}
|
|
| UPDATE NAME SET set_list where_clause limit_clause
|
|
{ cmd.command = RTA_UPDATE;
|
|
cmd.tbl = parsestr[(int) $2];
|
|
parsestr[(int) $2] = (char *) NULL;
|
|
}
|
|
;
|
|
|
|
set_list:
|
|
set_list ',' set_list
|
|
| NAME EQ literal
|
|
{ n = cmd.ncols;
|
|
cmd.cols[n] = parsestr[(int) $1];
|
|
parsestr[(int) $1] = (char *) NULL;
|
|
cmd.updvals[n] = parsestr[(int) $3];
|
|
parsestr[(int) $3] = (char *) NULL;
|
|
cmd.ncols++;
|
|
if (cmd.ncols > NCMDCOLS) {
|
|
/* too many columns in list */
|
|
send_error(LOC, E_BADPARSE);
|
|
}
|
|
}
|
|
;
|
|
|
|
literal:
|
|
NAME
|
|
| STRING
|
|
| INTEGER
|
|
| REALNUM
|
|
;
|
|
|
|
|
|
function_call:
|
|
SELECT NAME '(' ')' ';'
|
|
{ cmd.command = RTA_CALL;
|
|
cmd.tbl = parsestr[(int) $2];
|
|
parsestr[(int) $2] = (char *) NULL;
|
|
YYACCEPT;
|
|
}
|
|
| SELECT NAME '(' ')'
|
|
{ cmd.command = RTA_CALL;
|
|
cmd.tbl = parsestr[(int) $2];
|
|
parsestr[(int) $2] = (char *) NULL;
|
|
YYACCEPT;
|
|
}
|
|
;
|
|
|
|
|
|
%%
|
|
|
|
|
|
/***************************************************************
|
|
* freesql(): - Free allocated memory from previous command.
|
|
*
|
|
* Input: None.
|
|
* Output: None.
|
|
* Affects: Frees memory from last command
|
|
***************************************************************/
|
|
|
|
|
|
/***************************************************************
|
|
* dosql_init(): - Set up data structures prior to parse of
|
|
* an SQL command.
|
|
*
|
|
* Input: None.
|
|
* Output: None.
|
|
* Affects: structure cmd is initialized
|
|
***************************************************************/
|
|
void dosql_init() {
|
|
int i;
|
|
|
|
for (i=0; i<NCMDCOLS; i++) {
|
|
if (cmd.cols[i])
|
|
free(cmd.cols[i]);
|
|
if (cmd.updvals[i])
|
|
free(cmd.updvals[i]); /* values for column updates */
|
|
if (cmd.whrcols[i])
|
|
free(cmd.whrcols[i]); /* cols in where */
|
|
if (cmd.whrvals[i])
|
|
free(cmd.whrvals[i]); /* values in where clause */
|
|
cmd.cols[i] = (char *) 0;
|
|
cmd.updvals[i] = (char *) 0;
|
|
cmd.whrcols[i] = (char *) 0;
|
|
cmd.whrvals[i] = (char *) 0;
|
|
}
|
|
if (cmd.tbl);
|
|
free(cmd.tbl);
|
|
for (i=0; i<MXPARSESTR; i++) {
|
|
if (parsestr[i]) {
|
|
free(parsestr[i]);
|
|
parsestr[i] = (char *) NULL;
|
|
}
|
|
}
|
|
|
|
cmd.tbl = (char *) 0;
|
|
cmd.ptbl = (TBLDEF *) 0;
|
|
cmd.ncols = 0;
|
|
cmd.nwhrcols = 0;
|
|
cmd.limit = 1<<30; /* no real limit */
|
|
cmd.offset = 0;
|
|
cmd.err = 0;
|
|
}
|
|
|
|
void yyerror(char *s)
|
|
{
|
|
send_error(LOC, E_BADPARSE);
|
|
return;
|
|
}
|
|
|
|
|