Implement dispatch variant marshalling.
[wine/multimedia.git] / dlls / msi / sql.y
blob41566ea2359a7fbb762e351ea066c3728bb353ac
1 %{
3 /*
4 * Implementation of the Microsoft Installer (msi.dll)
6 * Copyright 2002 Mike McCormack for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "config.h"
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
30 #include "windef.h"
31 #include "winbase.h"
32 #include "query.h"
33 #include "wine/debug.h"
34 #include "wine/unicode.h"
36 #define YYLEX_PARAM info
37 #define YYPARSE_PARAM info
39 extern int yyerror(char *str);
41 WINE_DEFAULT_DEBUG_CHANNEL(msi);
43 typedef struct tag_yyinput
45 MSIDATABASE *db;
46 LPCWSTR command;
47 DWORD n, len;
48 MSIVIEW **view; /* view structure for the resulting query */
49 } yyinput;
51 struct string_list
53 LPWSTR string;
54 struct string_list *next;
57 static LPWSTR yygetstring( yyinput *info );
58 static INT yygetint( yyinput *sql );
59 static int yylex( void *yylval, yyinput *info);
61 static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in,
62 struct string_list *columns );
63 static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in,
64 struct string_list *columns );
66 static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r );
67 static struct expr * EXPR_column( LPWSTR column );
68 static struct expr * EXPR_ival( INT ival );
69 static struct expr * EXPR_sval( LPWSTR string );
73 %pure-parser
75 %union
77 LPWSTR string;
78 struct string_list *column_list;
79 MSIVIEW *table;
80 struct expr *expr;
83 %token TK_ABORT TK_AFTER TK_AGG_FUNCTION TK_ALL TK_AND TK_AS TK_ASC
84 %token TK_BEFORE TK_BEGIN TK_BETWEEN TK_BITAND TK_BITNOT TK_BITOR TK_BY
85 %token TK_CASCADE TK_CASE TK_CHECK TK_CLUSTER TK_COLLATE TK_COLUMN TK_COMMA
86 %token TK_COMMENT TK_COMMIT TK_CONCAT TK_CONFLICT
87 %token TK_CONSTRAINT TK_COPY TK_CREATE
88 %token TK_DEFAULT TK_DEFERRABLE TK_DEFERRED TK_DELETE TK_DELIMITERS TK_DESC
89 %token TK_DISTINCT TK_DOT TK_DROP TK_EACH
90 %token TK_ELSE TK_END TK_END_OF_FILE TK_EQ TK_EXCEPT TK_EXPLAIN
91 %token TK_FAIL TK_FLOAT TK_FOR TK_FOREIGN TK_FROM TK_FUNCTION
92 %token TK_GE TK_GLOB TK_GROUP TK_GT
93 %token TK_HAVING
94 %token TK_IGNORE TK_ILLEGAL TK_IMMEDIATE TK_IN TK_INDEX TK_INITIALLY
95 %token <string> TK_ID
96 %token TK_INSERT TK_INSTEAD TK_INTEGER TK_INTERSECT TK_INTO TK_IS TK_ISNULL
97 %token TK_JOIN TK_JOIN_KW
98 %token TK_KEY
99 %token TK_LE TK_LIKE TK_LIMIT TK_LP TK_LSHIFT TK_LT
100 %token TK_MATCH TK_MINUS
101 %token TK_NE TK_NOT TK_NOTNULL TK_NULL
102 %token TK_OF TK_OFFSET TK_ON TK_OR TK_ORACLE_OUTER_JOIN TK_ORDER
103 %token TK_PLUS TK_PRAGMA TK_PRIMARY
104 %token TK_RAISE TK_REFERENCES TK_REM TK_REPLACE TK_RESTRICT TK_ROLLBACK
105 %token TK_ROW TK_RP TK_RSHIFT
106 %token TK_SELECT TK_SEMI TK_SET TK_SLASH TK_SPACE TK_STAR TK_STATEMENT
107 %token <string> TK_STRING
108 %token TK_TABLE TK_TEMP TK_THEN TK_TRANSACTION TK_TRIGGER
109 %token TK_UMINUS TK_UNCLOSED_STRING TK_UNION TK_UNIQUE
110 %token TK_UPDATE TK_UPLUS TK_USING
111 %token TK_VACUUM TK_VALUES TK_VIEW
112 %token TK_WHEN TK_WHERE
115 * These are extra tokens used by the lexer but never seen by the
116 * parser. We put them in a rule so that the parser generator will
117 * add them to the parse.h output file.
120 %nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
121 COLUMN AGG_FUNCTION.
123 %type <query> oneselect
124 %type <string> column table string_or_id
125 %type <column_list> selcollist
126 %type <table> from unorderedsel
127 %type <expr> expr val column_val
131 oneselect:
132 unorderedsel TK_ORDER TK_BY selcollist
134 yyinput* sql = (yyinput*) info;
136 if( !$1 )
137 YYABORT;
138 if( $4 )
139 *sql->view = do_order_by( sql->db, $1, $4 );
140 else
141 *sql->view = $1;
143 | unorderedsel
145 yyinput* sql = (yyinput*) info;
147 *sql->view = $1;
151 unorderedsel:
152 TK_SELECT selcollist from
154 yyinput* sql = (yyinput*) info;
155 if( !$3 )
156 YYABORT;
157 if( $2 )
158 $$ = do_one_select( sql->db, $3, $2 );
159 else
160 $$ = $3;
162 | TK_SELECT TK_DISTINCT selcollist from
164 yyinput* sql = (yyinput*) info;
165 MSIVIEW *view = $4;
167 if( !view )
168 YYABORT;
169 if( $3 )
170 view = do_one_select( sql->db, view, $3 );
171 DISTINCT_CreateView( sql->db, & $$, view );
175 selcollist:
176 column
178 struct string_list *list;
180 list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
181 if( !list )
182 YYABORT;
183 list->string = $1;
184 list->next = NULL;
186 $$ = list;
187 TRACE("Collist %s\n",debugstr_w($$->string));
189 | column TK_COMMA selcollist
191 struct string_list *list;
193 list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
194 if( !list )
195 YYABORT;
196 list->string = $1;
197 list->next = $3;
199 $$ = list;
200 TRACE("From table: %s\n",debugstr_w($$->string));
202 | TK_STAR
204 $$ = NULL;
208 from:
209 TK_FROM table
211 yyinput* sql = (yyinput*) info;
213 $$ = NULL;
214 TRACE("From table: %s\n",debugstr_w($2));
215 TABLE_CreateView( sql->db, $2, & $$ );
217 | TK_FROM table TK_WHERE expr
219 yyinput* sql = (yyinput*) info;
220 MSIVIEW *view = NULL;
221 UINT r;
223 $$ = NULL;
224 TRACE("From table: %s\n",debugstr_w($2));
225 r = TABLE_CreateView( sql->db, $2, &view );
226 if( r != ERROR_SUCCESS )
227 YYABORT;
228 r = WHERE_CreateView( sql->db, &view, view );
229 if( r != ERROR_SUCCESS )
230 YYABORT;
231 r = WHERE_AddCondition( view, $4 );
232 if( r != ERROR_SUCCESS )
233 YYABORT;
234 $$ = view;
238 expr:
239 TK_LP expr TK_RP
241 $$ = $2;
243 | column_val TK_EQ column_val
245 $$ = EXPR_complex( $1, OP_EQ, $3 );
247 | expr TK_AND expr
249 $$ = EXPR_complex( $1, OP_AND, $3 );
251 | expr TK_OR expr
253 $$ = EXPR_complex( $1, OP_OR, $3 );
255 | column_val TK_EQ val
257 $$ = EXPR_complex( $1, OP_EQ, $3 );
259 | column_val TK_GT val
261 $$ = EXPR_complex( $1, OP_GT, $3 );
263 | column_val TK_LT val
265 $$ = EXPR_complex( $1, OP_LT, $3 );
267 | column_val TK_LE val
269 $$ = EXPR_complex( $1, OP_LE, $3 );
271 | column_val TK_GE val
273 $$ = EXPR_complex( $1, OP_GE, $3 );
275 | column_val TK_NE val
277 $$ = EXPR_complex( $1, OP_NE, $3 );
279 | column_val TK_IS TK_NULL
281 $$ = EXPR_complex( $1, OP_ISNULL, NULL );
283 | column_val TK_IS TK_NOT TK_NULL
285 $$ = EXPR_complex( $1, OP_NOTNULL, NULL );
289 val:
290 column_val
292 $$ = $1;
294 | TK_INTEGER
296 yyinput* sql = (yyinput*) info;
297 $$ = EXPR_ival( yygetint(sql) );
299 | TK_STRING
301 $$ = EXPR_sval( $1 );
305 column_val:
306 column
308 $$ = EXPR_column( $1 );
312 column:
313 table TK_DOT string_or_id
315 $$ = $3; /* FIXME */
317 | string_or_id
319 $$ = $1;
323 table:
324 string_or_id
326 $$ = $1;
330 string_or_id:
331 TK_ID
333 yyinput* sql = (yyinput*) info;
334 $$ = yygetstring(sql);
336 | TK_STRING
338 yyinput* sql = (yyinput*) info;
339 $$ = yygetstring(sql);
345 int yylex( void *yylval, yyinput *sql)
347 int token;
351 sql->n += sql->len;
352 if( ! sql->command[sql->n] )
353 return 0; /* end of input */
355 TRACE("string : %s\n", debugstr_w(&sql->command[sql->n]));
356 sql->len = sqliteGetToken( &sql->command[sql->n], &token );
357 if( sql->len==0 )
358 break;
360 while( token == TK_SPACE );
362 TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len));
364 return token;
367 LPWSTR yygetstring( yyinput *sql )
369 LPCWSTR p = &sql->command[sql->n];
370 LPWSTR str;
371 UINT len = sql->len;
373 /* if there's quotes, remove them */
374 if( (p[0]=='`') && (p[len-1]=='`') )
376 p++;
377 len -= 2;
379 str = HeapAlloc( GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
380 if(!str )
381 return str;
382 memcpy(str, p, len*sizeof(WCHAR) );
383 str[len]=0;
385 return str;
388 INT yygetint( yyinput *sql )
390 LPCWSTR p = &sql->command[sql->n];
392 return atoiW( p );
395 int yyerror(char *str)
397 return 0;
400 static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in,
401 struct string_list *columns )
403 MSIVIEW *view = NULL;
405 SELECT_CreateView( db, &view, in );
406 if( view )
408 struct string_list *x = columns;
410 while( x )
412 struct string_list *t = x->next;
413 SELECT_AddColumn( view, x->string );
414 HeapFree( GetProcessHeap(), 0, x->string );
415 HeapFree( GetProcessHeap(), 0, x );
416 x = t;
419 else
420 ERR("Error creating select query\n");
421 return view;
424 static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in,
425 struct string_list *columns )
427 MSIVIEW *view = NULL;
429 ORDER_CreateView( db, &view, in );
430 if( view )
432 struct string_list *x = columns;
434 while( x )
436 struct string_list *t = x->next;
437 ORDER_AddColumn( view, x->string );
438 HeapFree( GetProcessHeap(), 0, x->string );
439 HeapFree( GetProcessHeap(), 0, x );
440 x = t;
443 else
444 ERR("Error creating select query\n");
445 return view;
448 static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r )
450 struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
451 if( e )
453 e->type = EXPR_COMPLEX;
454 e->u.expr.left = l;
455 e->u.expr.op = op;
456 e->u.expr.right = r;
458 return e;
461 static struct expr * EXPR_column( LPWSTR column )
463 struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
464 if( e )
466 e->type = EXPR_COLUMN;
467 e->u.column = column;
469 return e;
472 static struct expr * EXPR_ival( INT ival )
474 struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
475 if( e )
477 e->type = EXPR_IVAL;
478 e->u.ival = ival;
480 return e;
483 static struct expr * EXPR_sval( LPWSTR string )
485 struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
486 if( e )
488 e->type = EXPR_SVAL;
489 e->u.sval = string;
491 return e;
494 UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview )
496 yyinput sql;
497 int r;
499 *phview = NULL;
501 sql.db = db;
502 sql.command = command;
503 sql.n = 0;
504 sql.len = 0;
505 sql.view = phview;
507 r = yyparse(&sql);
509 TRACE("Parse returned %d\n", r);
510 if( r )
512 if( *sql.view )
513 (*sql.view)->ops->delete( *sql.view );
514 return ERROR_BAD_QUERY_SYNTAX;
517 return ERROR_SUCCESS;