*
* You should have received a copy of the GNU Lesser 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "windef.h"
#include "winbase.h"
#include "query.h"
+#include "wine/list.h"
#include "wine/debug.h"
#include "wine/unicode.h"
#define YYLEX_PARAM info
#define YYPARSE_PARAM info
-extern int SQL_error(const char *str);
+static int sql_error(const char *str);
WINE_DEFAULT_DEBUG_CHANNEL(msi);
MSIDATABASE *db;
LPCWSTR command;
DWORD n, len;
+ UINT r;
MSIVIEW **view; /* view structure for the resulting query */
+ struct list *mem;
} SQL_input;
-static LPWSTR SQL_getstring( struct sql_str *str );
-static INT SQL_getint( SQL_input *sql );
-static int SQL_lex( void *SQL_lval, SQL_input *info);
+static UINT SQL_getstring( void *info, const struct sql_str *strdata, LPWSTR *str );
+static INT SQL_getint( void *info );
+static int sql_lex( void *SQL_lval, SQL_input *info );
-static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in,
- string_list *columns );
+static LPWSTR parser_add_table( void *info, LPCWSTR list, LPCWSTR table );
+static void *parser_alloc( void *info, unsigned int sz );
+static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR column );
-static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,
- string_list *keys);
+static BOOL SQL_MarkPrimaryKeys( column_info **cols, column_info *keys);
-static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r );
-static struct expr * EXPR_column( LPWSTR );
-static struct expr * EXPR_ival( struct sql_str *, int sign);
-static struct expr * EXPR_sval( struct sql_str *);
-static struct expr * EXPR_wildcard();
+static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r );
+static struct expr * EXPR_unary( void *info, struct expr *l, UINT op );
+static struct expr * EXPR_column( void *info, const column_info *column );
+static struct expr * EXPR_ival( void *info, int val );
+static struct expr * EXPR_sval( void *info, const struct sql_str *str );
+static struct expr * EXPR_wildcard( void *info );
%}
{
struct sql_str str;
LPWSTR string;
- string_list *column_list;
- value_list *val_list;
+ column_info *column_list;
MSIVIEW *query;
struct expr *expr;
USHORT column_type;
- create_col_info *column_info;
- column_assignment update_col_info;
+ int integer;
}
-%token TK_ABORT TK_AFTER TK_AGG_FUNCTION TK_ALL TK_AND TK_AS TK_ASC
-%token TK_BEFORE TK_BEGIN TK_BETWEEN TK_BITAND TK_BITNOT TK_BITOR TK_BY
-%token TK_CASCADE TK_CASE TK_CHAR TK_CHECK TK_CLUSTER TK_COLLATE TK_COLUMN
-%token TK_COMMA TK_COMMENT TK_COMMIT TK_CONCAT TK_CONFLICT
-%token TK_CONSTRAINT TK_COPY TK_CREATE
-%token TK_DEFAULT TK_DEFERRABLE TK_DEFERRED TK_DELETE TK_DELIMITERS TK_DESC
-%token TK_DISTINCT TK_DOT TK_DROP TK_EACH
-%token TK_ELSE TK_END TK_END_OF_FILE TK_EQ TK_EXCEPT TK_EXPLAIN
-%token TK_FAIL TK_FLOAT TK_FOR TK_FOREIGN TK_FROM TK_FUNCTION
-%token TK_GE TK_GLOB TK_GROUP TK_GT
-%token TK_HAVING TK_HOLD
-%token TK_IGNORE TK_ILLEGAL TK_IMMEDIATE TK_IN TK_INDEX TK_INITIALLY
-%token <str> TK_ID
-%token TK_INSERT TK_INSTEAD TK_INT
+%token TK_ALTER TK_AND TK_BY TK_CHAR TK_COMMA TK_CREATE TK_DELETE TK_DROP
+%token TK_DISTINCT TK_DOT TK_EQ TK_FREE TK_FROM TK_GE TK_GT TK_HOLD TK_ADD
+%token <str> TK_ID
+%token TK_ILLEGAL TK_INSERT TK_INT
%token <str> TK_INTEGER
-%token TK_INTERSECT TK_INTO TK_IS
-%token TK_ISNULL
-%token TK_JOIN TK_JOIN_KW
-%token TK_KEY
-%token TK_LE TK_LIKE TK_LIMIT TK_LONG TK_LONGCHAR TK_LP TK_LSHIFT TK_LT
-%token TK_LOCALIZABLE
-%token TK_MATCH TK_MINUS
-%token TK_NE TK_NOT TK_NOTNULL TK_NULL
-%token TK_OBJECT TK_OF TK_OFFSET TK_ON TK_OR TK_ORACLE_OUTER_JOIN TK_ORDER
-%token TK_PLUS TK_PRAGMA TK_PRIMARY
-%token TK_RAISE TK_REFERENCES TK_REM TK_REPLACE TK_RESTRICT TK_ROLLBACK
-%token TK_ROW TK_RP TK_RSHIFT
-%token TK_SELECT TK_SEMI TK_SET TK_SHORT TK_SLASH TK_SPACE TK_STAR TK_STATEMENT
+%token TK_INTO TK_IS TK_KEY TK_LE TK_LONG TK_LONGCHAR TK_LP TK_LT
+%token TK_LOCALIZABLE TK_MINUS TK_NE TK_NOT TK_NULL
+%token TK_OBJECT TK_OR TK_ORDER TK_PRIMARY TK_RP
+%token TK_SELECT TK_SET TK_SHORT TK_SPACE TK_STAR
%token <str> TK_STRING
-%token TK_TABLE TK_TEMP TK_THEN TK_TRANSACTION TK_TRIGGER
-%token TK_UMINUS TK_UNCLOSED_STRING TK_UNION TK_UNIQUE
-%token TK_UPDATE TK_UPLUS TK_USING
-%token TK_VACUUM TK_VALUES TK_VIEW
-%token TK_WHEN TK_WHERE TK_WILDCARD
+%token TK_TABLE TK_TEMPORARY TK_UPDATE TK_VALUES TK_WHERE TK_WILDCARD
/*
* These are extra tokens used by the lexer but never seen by the
%nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
COLUMN AGG_FUNCTION.
-%type <string> column table id
-%type <column_list> selcollist
-%type <query> query from unorderedsel
-%type <query> oneupdate onedelete oneselect onequery onecreate oneinsert
+%type <string> table tablelist id
+%type <column_list> selcollist column column_and_type column_def table_def
+%type <column_list> column_assignment update_assign_list constlist
+%type <query> query from fromtable selectfrom unorderedsel
+%type <query> oneupdate onedelete oneselect onequery onecreate oneinsert onealter onedrop
%type <expr> expr val column_val const_val
%type <column_type> column_type data_type data_type_l data_count
-%type <column_info> column_def table_def
-%type <val_list> constlist
-%type <update_col_info> column_assignment update_assign_list
+%type <integer> number alterop
+
+/* Reference: http://mates.ms.mff.cuni.cz/oracle/doc/ora815nt/server.815/a67779/operator.htm */
+%left TK_OR
+%left TK_AND
+%left TK_NOT
+%left TK_EQ TK_NE TK_LT TK_GT TK_LE TK_GE TK_LIKE
+%right TK_NEGATION
%%
| oneinsert
| oneupdate
| onedelete
+ | onealter
+ | onedrop
;
oneinsert:
TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP
- {
- SQL_input *sql = (SQL_input*) info;
- MSIVIEW *insert = NULL;
+ {
+ SQL_input *sql = (SQL_input*) info;
+ MSIVIEW *insert = NULL;
- INSERT_CreateView( sql->db, &insert, $3, $5, $9, FALSE );
- $$ = insert;
- }
- | TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP TK_TEMP
- {
- SQL_input *sql = (SQL_input*) info;
- MSIVIEW *insert = NULL;
+ INSERT_CreateView( sql->db, &insert, $3, $5, $9, FALSE );
+ if( !insert )
+ YYABORT;
+ $$ = insert;
+ }
+ | TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP TK_TEMPORARY
+ {
+ SQL_input *sql = (SQL_input*) info;
+ MSIVIEW *insert = NULL;
- INSERT_CreateView( sql->db, &insert, $3, $5, $9, TRUE );
- $$ = insert;
- }
+ INSERT_CreateView( sql->db, &insert, $3, $5, $9, TRUE );
+ if( !insert )
+ YYABORT;
+ $$ = insert;
+ }
;
onecreate:
TK_CREATE TK_TABLE table TK_LP table_def TK_RP
{
SQL_input* sql = (SQL_input*) info;
- MSIVIEW *create = NULL;
+ MSIVIEW *create = NULL;
+ UINT r;
if( !$5 )
YYABORT;
- CREATE_CreateView( sql->db, &create, $3, $5, FALSE );
+ r = CREATE_CreateView( sql->db, &create, $3, $5, FALSE );
+ if( !create )
+ {
+ sql->r = r;
+ YYABORT;
+ }
$$ = create;
}
| TK_CREATE TK_TABLE table TK_LP table_def TK_RP TK_HOLD
{
SQL_input* sql = (SQL_input*) info;
- MSIVIEW *create = NULL;
+ MSIVIEW *create = NULL;
if( !$5 )
YYABORT;
CREATE_CreateView( sql->db, &create, $3, $5, TRUE );
+ if( !create )
+ YYABORT;
$$ = create;
}
;
TK_UPDATE table TK_SET update_assign_list TK_WHERE expr
{
SQL_input* sql = (SQL_input*) info;
- MSIVIEW *update = NULL;
+ MSIVIEW *update = NULL;
- UPDATE_CreateView( sql->db, &update, $2, &$4, $6 );
+ UPDATE_CreateView( sql->db, &update, $2, $4, $6 );
+ if( !update )
+ YYABORT;
+ $$ = update;
+ }
+ | TK_UPDATE table TK_SET update_assign_list
+ {
+ SQL_input* sql = (SQL_input*) info;
+ MSIVIEW *update = NULL;
+
+ UPDATE_CreateView( sql->db, &update, $2, $4, NULL );
+ if( !update )
+ YYABORT;
$$ = update;
}
;
TK_DELETE from
{
SQL_input* sql = (SQL_input*) info;
- MSIVIEW *delete = NULL;
+ MSIVIEW *delete = NULL;
DELETE_CreateView( sql->db, &delete, $2 );
+ if( !delete )
+ YYABORT;
$$ = delete;
}
;
+onealter:
+ TK_ALTER TK_TABLE table alterop
+ {
+ SQL_input* sql = (SQL_input*) info;
+ MSIVIEW *alter = NULL;
+
+ ALTER_CreateView( sql->db, &alter, $3, NULL, $4 );
+ if( !alter )
+ YYABORT;
+ $$ = alter;
+ }
+ | TK_ALTER TK_TABLE table TK_ADD column_and_type
+ {
+ SQL_input *sql = (SQL_input *)info;
+ MSIVIEW *alter = NULL;
+
+ ALTER_CreateView( sql->db, &alter, $3, $5, 0 );
+ if (!alter)
+ YYABORT;
+ $$ = alter;
+ }
+ | TK_ALTER TK_TABLE table TK_ADD column_and_type TK_HOLD
+ {
+ SQL_input *sql = (SQL_input *)info;
+ MSIVIEW *alter = NULL;
+
+ ALTER_CreateView( sql->db, &alter, $3, $5, 1 );
+ if (!alter)
+ YYABORT;
+ $$ = alter;
+ }
+ ;
+
+alterop:
+ TK_HOLD
+ {
+ $$ = 1;
+ }
+ | TK_FREE
+ {
+ $$ = -1;
+ }
+ ;
+
+onedrop:
+ TK_DROP TK_TABLE table
+ {
+ SQL_input* sql = (SQL_input*) info;
+ UINT r;
+
+ $$ = NULL;
+ r = DROP_CreateView( sql->db, &$$, $3 );
+ if( r != ERROR_SUCCESS || !$$ )
+ YYABORT;
+ }
+ ;
+
table_def:
column_def TK_PRIMARY TK_KEY selcollist
{
- if( SQL_MarkPrimaryKeys( $1, $4 ) )
+ if( SQL_MarkPrimaryKeys( &$1, $4 ) )
$$ = $1;
else
$$ = NULL;
;
column_def:
- column_def TK_COMMA column column_type
+ column_def TK_COMMA column_and_type
{
- create_col_info *ci;
+ column_info *ci;
for( ci = $1; ci->next; ci = ci->next )
;
- ci->next = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ );
- if( !ci->next )
- {
- /* FIXME: free $1 */
- YYABORT;
- }
- ci->next->colname = $3;
- ci->next->type = $4;
- ci->next->next = NULL;
-
+ ci->next = $3;
$$ = $1;
}
- | column column_type
+ | column_and_type
{
- $$ = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ );
- if( ! $$ )
- YYABORT;
- $$->colname = $1;
- $$->type = $2;
- $$->next = NULL;
+ $$ = $1;
+ }
+ ;
+
+column_and_type:
+ column column_type
+ {
+ $$ = $1;
+ $$->type = ($2 | MSITYPE_VALID);
+ $$->temporary = $2 & MSITYPE_TEMPORARY ? TRUE : FALSE;
}
;
column_type:
data_type_l
{
- $$ = $1 | MSITYPE_VALID;
+ $$ = $1;
}
| data_type_l TK_LOCALIZABLE
{
- FIXME("LOCALIZABLE ignored\n");
- $$ = $1 | MSITYPE_VALID;
+ $$ = $1 | MSITYPE_LOCALIZABLE;
+ }
+ | data_type_l TK_TEMPORARY
+ {
+ $$ = $1 | MSITYPE_TEMPORARY;
}
;
}
| TK_LONGCHAR
{
- $$ = 2;
+ $$ = MSITYPE_STRING | 0x400;
}
| TK_SHORT
{
- $$ = 2;
+ $$ = 2 | 0x400;
}
| TK_INT
{
- $$ = 2;
+ $$ = 2 | 0x400;
}
| TK_LONG
{
}
| TK_OBJECT
{
- $$ = 0;
+ $$ = MSITYPE_STRING | MSITYPE_VALID;
}
;
data_count:
- TK_INTEGER
+ number
{
- SQL_input* sql = (SQL_input*) info;
- int val = SQL_getint(sql);
- if( ( val > 255 ) || ( val < 0 ) )
+ if( ( $1 > 255 ) || ( $1 < 0 ) )
YYABORT;
- $$ = val;
+ $$ = $1;
}
;
oneselect:
unorderedsel TK_ORDER TK_BY selcollist
{
- SQL_input* sql = (SQL_input*) info;
+ UINT r;
- $$ = NULL;
if( $4 )
- ORDER_CreateView( sql->db, &$$, $1, $4 );
- else
- $$ = $1;
- if( !$$ )
- YYABORT;
+ {
+ r = $1->ops->sort( $1, $4 );
+ if ( r != ERROR_SUCCESS)
+ YYABORT;
+ }
+
+ $$ = $1;
}
| unorderedsel
;
unorderedsel:
- TK_SELECT selcollist from
+ TK_SELECT selectfrom
+ {
+ $$ = $2;
+ }
+ | TK_SELECT TK_DISTINCT selectfrom
{
SQL_input* sql = (SQL_input*) info;
- if( !$3 )
- YYABORT;
- if( $2 )
+ UINT r;
+
+ $$ = NULL;
+ r = DISTINCT_CreateView( sql->db, &$$, $3 );
+ if (r != ERROR_SUCCESS)
{
- $$ = do_one_select( sql->db, $3, $2 );
- if( !$$ )
- YYABORT;
+ $3->ops->delete($3);
+ YYABORT;
}
- else
- $$ = $3;
}
- | TK_SELECT TK_DISTINCT selcollist from
+ ;
+
+selectfrom:
+ selcollist from
{
SQL_input* sql = (SQL_input*) info;
- MSIVIEW *view = $4;
+ UINT r;
- if( !view )
- YYABORT;
- if( $3 )
+ $$ = NULL;
+ if( $1 )
{
- view = do_one_select( sql->db, view, $3 );
- if( !view )
+ r = SELECT_CreateView( sql->db, &$$, $2, $1 );
+ if (r != ERROR_SUCCESS)
+ {
+ $2->ops->delete($2);
YYABORT;
+ }
}
- DISTINCT_CreateView( sql->db, & $$, view );
+ else
+ $$ = $2;
}
;
selcollist:
- column
- {
- string_list *list;
-
- list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
- if( !list )
- YYABORT;
- list->string = $1;
- list->next = NULL;
-
- $$ = list;
- TRACE("Collist %s\n",debugstr_w($$->string));
- }
+ column
| column TK_COMMA selcollist
- {
- string_list *list;
-
- list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
- if( !list )
- YYABORT;
- list->string = $1;
- list->next = $3;
-
- $$ = list;
- TRACE("From table: %s\n",debugstr_w($$->string));
+ {
+ $1->next = $3;
}
| TK_STAR
{
;
from:
- TK_FROM table
- {
+ fromtable
+ | fromtable TK_WHERE expr
+ {
SQL_input* sql = (SQL_input*) info;
UINT r;
$$ = NULL;
- TRACE("From table: %s\n",debugstr_w($2));
- r = TABLE_CreateView( sql->db, $2, & $$ );
+ r = WHERE_CreateView( sql->db, &$$, $1, $3 );
if( r != ERROR_SUCCESS )
+ {
+ $1->ops->delete( $1 );
YYABORT;
+ }
}
- | TK_FROM table TK_WHERE expr
- {
+ ;
+
+fromtable:
+ TK_FROM table
+ {
SQL_input* sql = (SQL_input*) info;
- MSIVIEW *view = NULL;
UINT r;
$$ = NULL;
- TRACE("From table: %s\n",debugstr_w($2));
- r = TABLE_CreateView( sql->db, $2, &view );
- if( r != ERROR_SUCCESS )
+ r = TABLE_CreateView( sql->db, $2, &$$ );
+ if( r != ERROR_SUCCESS || !$$ )
YYABORT;
- r = WHERE_CreateView( sql->db, &view, view, $4 );
+ }
+ | TK_FROM tablelist
+ {
+ SQL_input* sql = (SQL_input*) info;
+ UINT r;
+
+ r = JOIN_CreateView( sql->db, &$$, $2 );
if( r != ERROR_SUCCESS )
YYABORT;
- $$ = view;
+ }
+ ;
+
+tablelist:
+ table
+ {
+ $$ = $1;
+ }
+ |
+ table TK_COMMA tablelist
+ {
+ $$ = parser_add_table( info, $3, $1 );
+ if (!$$)
+ YYABORT;
}
;
TK_LP expr TK_RP
{
$$ = $2;
- }
- | column_val TK_EQ column_val
- {
- $$ = EXPR_complex( $1, OP_EQ, $3 );
if( !$$ )
YYABORT;
}
| expr TK_AND expr
{
- $$ = EXPR_complex( $1, OP_AND, $3 );
+ $$ = EXPR_complex( info, $1, OP_AND, $3 );
if( !$$ )
YYABORT;
}
| expr TK_OR expr
{
- $$ = EXPR_complex( $1, OP_OR, $3 );
+ $$ = EXPR_complex( info, $1, OP_OR, $3 );
if( !$$ )
YYABORT;
}
| column_val TK_EQ val
{
- $$ = EXPR_complex( $1, OP_EQ, $3 );
+ $$ = EXPR_complex( info, $1, OP_EQ, $3 );
if( !$$ )
YYABORT;
}
| column_val TK_GT val
{
- $$ = EXPR_complex( $1, OP_GT, $3 );
+ $$ = EXPR_complex( info, $1, OP_GT, $3 );
if( !$$ )
YYABORT;
}
| column_val TK_LT val
{
- $$ = EXPR_complex( $1, OP_LT, $3 );
+ $$ = EXPR_complex( info, $1, OP_LT, $3 );
if( !$$ )
YYABORT;
}
| column_val TK_LE val
{
- $$ = EXPR_complex( $1, OP_LE, $3 );
+ $$ = EXPR_complex( info, $1, OP_LE, $3 );
if( !$$ )
YYABORT;
}
| column_val TK_GE val
{
- $$ = EXPR_complex( $1, OP_GE, $3 );
+ $$ = EXPR_complex( info, $1, OP_GE, $3 );
if( !$$ )
YYABORT;
}
| column_val TK_NE val
{
- $$ = EXPR_complex( $1, OP_NE, $3 );
+ $$ = EXPR_complex( info, $1, OP_NE, $3 );
if( !$$ )
YYABORT;
}
| column_val TK_IS TK_NULL
{
- $$ = EXPR_complex( $1, OP_ISNULL, NULL );
+ $$ = EXPR_unary( info, $1, OP_ISNULL );
if( !$$ )
YYABORT;
}
| column_val TK_IS TK_NOT TK_NULL
{
- $$ = EXPR_complex( $1, OP_NOTNULL, NULL );
+ $$ = EXPR_unary( info, $1, OP_NOTNULL );
if( !$$ )
YYABORT;
}
constlist:
const_val
{
- value_list *vals;
-
- vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
- if( vals )
- {
- vals->val = $1;
- vals->next = NULL;
- }
- $$ = vals;
+ $$ = parser_alloc_column( info, NULL, NULL );
+ if( !$$ )
+ YYABORT;
+ $$->val = $1;
}
| const_val TK_COMMA constlist
{
- value_list *vals;
-
- vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
- if( vals )
- {
- vals->val = $1;
- vals->next = $3;
- }
- $$ = vals;
+ $$ = parser_alloc_column( info, NULL, NULL );
+ if( !$$ )
+ YYABORT;
+ $$->val = $1;
+ $$->next = $3;
}
;
column_assignment
| column_assignment TK_COMMA update_assign_list
{
- $1.col_list->next = $3.col_list;
- $1.val_list->next = $3.val_list;
$$ = $1;
+ $$->next = $3;
}
;
column_assignment:
column TK_EQ const_val
{
- $$.col_list = HeapAlloc( GetProcessHeap(), 0, sizeof *$$.col_list );
- if( !$$.col_list )
- YYABORT;
- $$.col_list->string = $1;
- $$.col_list->next = NULL;
- $$.val_list = HeapAlloc( GetProcessHeap(), 0, sizeof *$$.val_list );
- if( !$$.val_list )
- YYABORT;
- $$.val_list->val = $3;
- $$.val_list->next = 0;
+ $$ = $1;
+ $$->val = $3;
}
;
const_val:
- TK_INTEGER
+ number
{
- $$ = EXPR_ival( &$1, 1 );
+ $$ = EXPR_ival( info, $1 );
+ if( !$$ )
+ YYABORT;
}
- | TK_MINUS TK_INTEGER
+ | TK_MINUS number %prec TK_NEGATION
{
- $$ = EXPR_ival( &$2, -1 );
+ $$ = EXPR_ival( info, -$2 );
+ if( !$$ )
+ YYABORT;
}
| TK_STRING
{
- $$ = EXPR_sval( &$1 );
+ $$ = EXPR_sval( info, &$1 );
+ if( !$$ )
+ YYABORT;
}
| TK_WILDCARD
{
- $$ = EXPR_wildcard();
+ $$ = EXPR_wildcard( info );
+ if( !$$ )
+ YYABORT;
}
;
column_val:
- column
+ column
{
- $$ = EXPR_column( $1 );
+ $$ = EXPR_column( info, $1 );
+ if( !$$ )
+ YYABORT;
}
;
column:
table TK_DOT id
{
- $$ = $3; /* FIXME */
+ $$ = parser_alloc_column( info, $1, $3 );
+ if( !$$ )
+ YYABORT;
}
| id
{
- $$ = $1;
+ $$ = parser_alloc_column( info, NULL, $1 );
+ if( !$$ )
+ YYABORT;
}
;
id:
TK_ID
{
- $$ = SQL_getstring( &$1 );
+ if ( SQL_getstring( info, &$1, &$$ ) != ERROR_SUCCESS || !$$ )
+ YYABORT;
+ }
+ ;
+
+number:
+ TK_INTEGER
+ {
+ $$ = SQL_getint( info );
}
;
%%
-int SQL_lex( void *SQL_lval, SQL_input *sql)
+static LPWSTR parser_add_table( void *info, LPCWSTR list, LPCWSTR table )
+{
+ static const WCHAR space[] = {' ',0};
+ DWORD len = strlenW( list ) + strlenW( table ) + 2;
+ LPWSTR ret;
+
+ ret = parser_alloc( info, len * sizeof(WCHAR) );
+ if( ret )
+ {
+ strcpyW( ret, list );
+ strcatW( ret, space );
+ strcatW( ret, table );
+ }
+ return ret;
+}
+
+static void *parser_alloc( void *info, unsigned int sz )
+{
+ SQL_input* sql = (SQL_input*) info;
+ struct list *mem;
+
+ mem = msi_alloc( sizeof (struct list) + sz );
+ list_add_tail( sql->mem, mem );
+ return &mem[1];
+}
+
+static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR column )
+{
+ column_info *col;
+
+ col = parser_alloc( info, sizeof (*col) );
+ if( col )
+ {
+ col->table = table;
+ col->column = column;
+ col->val = NULL;
+ col->type = 0;
+ col->next = NULL;
+ }
+
+ return col;
+}
+
+static int sql_lex( void *SQL_lval, SQL_input *sql )
{
int token;
struct sql_str * str = SQL_lval;
if( ! sql->command[sql->n] )
return 0; /* end of input */
- TRACE("string : %s\n", debugstr_w(&sql->command[sql->n]));
+ /* TRACE("string : %s\n", debugstr_w(&sql->command[sql->n])); */
sql->len = sqliteGetToken( &sql->command[sql->n], &token );
if( sql->len==0 )
break;
}
while( token == TK_SPACE );
- TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len));
-
+ /* TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len)); */
+
return token;
}
-LPWSTR SQL_getstring( struct sql_str *strdata)
+UINT SQL_getstring( void *info, const struct sql_str *strdata, LPWSTR *str )
{
LPCWSTR p = strdata->data;
UINT len = strdata->len;
- LPWSTR str;
+
+ /* match quotes */
+ if( ( (p[0]=='`') && (p[len-1]!='`') ) ||
+ ( (p[0]=='\'') && (p[len-1]!='\'') ) )
+ return ERROR_FUNCTION_FAILED;
/* if there's quotes, remove them */
- if( ( (p[0]=='`') && (p[len-1]=='`') ) ||
+ if( ( (p[0]=='`') && (p[len-1]=='`') ) ||
( (p[0]=='\'') && (p[len-1]=='\'') ) )
{
p++;
len -= 2;
}
- str = HeapAlloc( GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
- if(!str )
- return str;
- memcpy(str, p, len*sizeof(WCHAR) );
- str[len]=0;
+ *str = parser_alloc( info, (len + 1)*sizeof(WCHAR) );
+ if( !*str )
+ return ERROR_OUTOFMEMORY;
+ memcpy( *str, p, len*sizeof(WCHAR) );
+ (*str)[len]=0;
- return str;
+ return ERROR_SUCCESS;
}
-INT SQL_getint( SQL_input *sql )
+INT SQL_getint( void *info )
{
+ SQL_input* sql = (SQL_input*) info;
LPCWSTR p = &sql->command[sql->n];
+ INT i, r = 0;
- return atoiW( p );
-}
+ for( i=0; i<sql->len; i++ )
+ {
+ if( '0' > p[i] || '9' < p[i] )
+ {
+ ERR("should only be numbers here!\n");
+ break;
+ }
+ r = (p[i]-'0') + r*10;
+ }
-int SQL_error(const char *str)
-{
- return 0;
+ return r;
}
-static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in,
- string_list *columns )
+static int sql_error( const char *str )
{
- MSIVIEW *view = NULL;
-
- SELECT_CreateView( db, &view, in, columns );
- delete_string_list( columns );
- if( !view )
- ERR("Error creating select query\n");
- return view;
+ return 0;
}
-static struct expr * EXPR_wildcard()
+static struct expr * EXPR_wildcard( void *info )
{
- struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
+ struct expr *e = parser_alloc( info, sizeof *e );
if( e )
{
e->type = EXPR_WILDCARD;
return e;
}
-static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r )
+static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r )
{
- struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
+ struct expr *e = parser_alloc( info, sizeof *e );
if( e )
{
e->type = EXPR_COMPLEX;
return e;
}
-static struct expr * EXPR_column( LPWSTR str )
+static struct expr * EXPR_unary( void *info, struct expr *l, UINT op )
{
- struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
+ struct expr *e = parser_alloc( info, sizeof *e );
if( e )
{
- e->type = EXPR_COLUMN;
- e->u.sval = str;
+ e->type = EXPR_UNARY;
+ e->u.expr.left = l;
+ e->u.expr.op = op;
+ e->u.expr.right = NULL;
}
return e;
}
-static struct expr * EXPR_ival( struct sql_str *str , int sign)
+static struct expr * EXPR_column( void *info, const column_info *column )
{
- struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
+ struct expr *e = parser_alloc( info, sizeof *e );
if( e )
{
- e->type = EXPR_IVAL;
- e->u.ival = atoiW( str->data ) * sign;
+ e->type = EXPR_COLUMN;
+ e->u.sval = column->column;
}
return e;
}
-static struct expr * EXPR_sval( struct sql_str *str )
+static struct expr * EXPR_ival( void *info, int val )
{
- struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
+ struct expr *e = parser_alloc( info, sizeof *e );
if( e )
{
- e->type = EXPR_SVAL;
- e->u.sval = SQL_getstring( str );
+ e->type = EXPR_IVAL;
+ e->u.ival = val;
}
return e;
}
-void delete_expr( struct expr *e )
+static struct expr * EXPR_sval( void *info, const struct sql_str *str )
{
- if( !e )
- return;
- if( e->type == EXPR_COMPLEX )
+ struct expr *e = parser_alloc( info, sizeof *e );
+ if( e )
{
- delete_expr( e->u.expr.left );
- delete_expr( e->u.expr.right );
+ e->type = EXPR_SVAL;
+ if( SQL_getstring( info, str, (LPWSTR *)&e->u.sval ) != ERROR_SUCCESS )
+ return NULL; /* e will be freed by query destructor */
}
- else if( e->type == EXPR_SVAL )
- HeapFree( GetProcessHeap(), 0, e->u.sval );
- HeapFree( GetProcessHeap(), 0, e );
+ return e;
}
-void delete_string_list( string_list *sl )
+static void swap_columns( column_info **cols, column_info *A, int idx )
{
- while( sl )
- {
- string_list *t = sl->next;
- HeapFree( GetProcessHeap(), 0, sl->string );
- HeapFree( GetProcessHeap(), 0, sl );
- sl = t;
- }
-}
+ column_info *preA = NULL, *preB = NULL, *B, *ptr;
+ int i = 0;
-void delete_value_list( value_list *vl )
-{
- while( vl )
+ B = NULL;
+ ptr = *cols;
+ while( ptr )
{
- value_list *t = vl->next;
- delete_expr( vl->val );
- HeapFree( GetProcessHeap(), 0, vl );
- vl = t;
+ if( i++ == idx )
+ B = ptr;
+ else if( !B )
+ preB = ptr;
+
+ if( ptr->next == A )
+ preA = ptr;
+
+ ptr = ptr->next;
}
+
+ if( preB ) preB->next = A;
+ if( preA ) preA->next = B;
+ ptr = A->next;
+ A->next = B->next;
+ B->next = ptr;
+ if( idx == 0 )
+ *cols = A;
}
-static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,
- string_list *keys )
+static BOOL SQL_MarkPrimaryKeys( column_info **cols,
+ column_info *keys )
{
- string_list *k;
+ column_info *k;
BOOL found = TRUE;
+ int count;
- for( k = keys; k && found; k = k->next )
+ for( k = keys, count = 0; k && found; k = k->next, count++ )
{
- create_col_info *c;
+ column_info *c;
+ int idx;
found = FALSE;
- for( c = cols; c && !found; c = c->next )
+ for( c = *cols, idx = 0; c && !found; c = c->next, idx++ )
{
- if( lstrcmpW( k->string, c->colname ) )
- continue;
- c->type |= MSITYPE_KEY;
- found = TRUE;
+ if( lstrcmpW( k->column, c->column ) )
+ continue;
+ c->type |= MSITYPE_KEY;
+ found = TRUE;
+ if (idx != count)
+ swap_columns( cols, c, count );
}
}
return found;
}
-UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview )
+UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview,
+ struct list *mem )
{
SQL_input sql;
int r;
sql.command = command;
sql.n = 0;
sql.len = 0;
+ sql.r = ERROR_BAD_QUERY_SYNTAX;
sql.view = phview;
+ sql.mem = mem;
- r = SQL_parse(&sql);
+ r = sql_parse(&sql);
TRACE("Parse returned %d\n", r);
if( r )
{
- if( *sql.view )
- (*sql.view)->ops->delete( *sql.view );
- *sql.view = NULL;
- return ERROR_BAD_QUERY_SYNTAX;
+ if (*sql.view)
+ {
+ (*sql.view)->ops->delete(*sql.view);
+ *sql.view = NULL;
+ }
+ return sql.r;
}
return ERROR_SUCCESS;