Create the WHERE part of a query in one function call.
[wine.git] / dlls / msi / sql.y
blobbcad30e017dcac0bf75bd62ddf4046eadedb3a59
1 %{
3 /*
4 * Implementation of the Microsoft Installer (msi.dll)
6 * Copyright 2002-2004 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 SQL_error(const char *str);
41 WINE_DEFAULT_DEBUG_CHANNEL(msi);
43 typedef struct tag_SQL_input
45 MSIDATABASE *db;
46 LPCWSTR command;
47 DWORD n, len;
48 MSIVIEW **view; /* view structure for the resulting query */
49 } SQL_input;
51 static LPWSTR SQL_getstring( struct sql_str *str );
52 static INT SQL_getint( SQL_input *sql );
53 static int SQL_lex( void *SQL_lval, SQL_input *info);
55 static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in,
56 string_list *columns );
57 static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in,
58 string_list *columns );
60 static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,
61 string_list *keys);
63 static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r );
64 static struct expr * EXPR_column( LPWSTR );
65 static struct expr * EXPR_ival( struct sql_str *);
66 static struct expr * EXPR_sval( struct sql_str *);
67 static struct expr * EXPR_wildcard();
71 %pure-parser
73 %union
75 struct sql_str str;
76 LPWSTR string;
77 string_list *column_list;
78 value_list *val_list;
79 MSIVIEW *query;
80 struct expr *expr;
81 USHORT column_type;
82 create_col_info *column_info;
85 %token TK_ABORT TK_AFTER TK_AGG_FUNCTION TK_ALL TK_AND TK_AS TK_ASC
86 %token TK_BEFORE TK_BEGIN TK_BETWEEN TK_BITAND TK_BITNOT TK_BITOR TK_BY
87 %token TK_CASCADE TK_CASE TK_CHAR TK_CHECK TK_CLUSTER TK_COLLATE TK_COLUMN
88 %token TK_COMMA TK_COMMENT TK_COMMIT TK_CONCAT TK_CONFLICT
89 %token TK_CONSTRAINT TK_COPY TK_CREATE
90 %token TK_DEFAULT TK_DEFERRABLE TK_DEFERRED TK_DELETE TK_DELIMITERS TK_DESC
91 %token TK_DISTINCT TK_DOT TK_DROP TK_EACH
92 %token TK_ELSE TK_END TK_END_OF_FILE TK_EQ TK_EXCEPT TK_EXPLAIN
93 %token TK_FAIL TK_FLOAT TK_FOR TK_FOREIGN TK_FROM TK_FUNCTION
94 %token TK_GE TK_GLOB TK_GROUP TK_GT
95 %token TK_HAVING TK_HOLD
96 %token TK_IGNORE TK_ILLEGAL TK_IMMEDIATE TK_IN TK_INDEX TK_INITIALLY
97 %token <str> TK_ID
98 %token TK_INSERT TK_INSTEAD TK_INT
99 %token <str> TK_INTEGER
100 %token TK_INTERSECT TK_INTO TK_IS
101 %token TK_ISNULL
102 %token TK_JOIN TK_JOIN_KW
103 %token TK_KEY
104 %token TK_LE TK_LIKE TK_LIMIT TK_LONG TK_LONGCHAR TK_LP TK_LSHIFT TK_LT
105 %token TK_LOCALIZABLE
106 %token TK_MATCH TK_MINUS
107 %token TK_NE TK_NOT TK_NOTNULL TK_NULL
108 %token TK_OBJECT TK_OF TK_OFFSET TK_ON TK_OR TK_ORACLE_OUTER_JOIN TK_ORDER
109 %token TK_PLUS TK_PRAGMA TK_PRIMARY
110 %token TK_RAISE TK_REFERENCES TK_REM TK_REPLACE TK_RESTRICT TK_ROLLBACK
111 %token TK_ROW TK_RP TK_RSHIFT
112 %token TK_SELECT TK_SEMI TK_SET TK_SHORT TK_SLASH TK_SPACE TK_STAR TK_STATEMENT
113 %token <str> TK_STRING
114 %token TK_TABLE TK_TEMP TK_THEN TK_TRANSACTION TK_TRIGGER
115 %token TK_UMINUS TK_UNCLOSED_STRING TK_UNION TK_UNIQUE
116 %token TK_UPDATE TK_UPLUS TK_USING
117 %token TK_VACUUM TK_VALUES TK_VIEW
118 %token TK_WHEN TK_WHERE TK_WILDCARD
121 * These are extra tokens used by the lexer but never seen by the
122 * parser. We put them in a rule so that the parser generator will
123 * add them to the parse.h output file.
126 %nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
127 COLUMN AGG_FUNCTION.
129 %type <string> column table string_or_id
130 %type <column_list> selcollist
131 %type <query> from unorderedsel oneselect onequery onecreate oneinsert
132 %type <expr> expr val column_val const_val
133 %type <column_type> column_type data_type data_type_l data_count
134 %type <column_info> column_def table_def
135 %type <val_list> constlist
139 onequery:
140 oneselect
142 SQL_input* sql = (SQL_input*) info;
143 *sql->view = $1;
145 | onecreate
147 SQL_input* sql = (SQL_input*) info;
148 *sql->view = $1;
150 | oneinsert
152 SQL_input* sql = (SQL_input*) info;
153 *sql->view = $1;
157 oneinsert:
158 TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP
160 SQL_input *sql = (SQL_input*) info;
161 MSIVIEW *insert = NULL;
163 INSERT_CreateView( sql->db, &insert, $3, $5, $9, FALSE );
164 $$ = insert;
166 | TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP TK_TEMP
168 SQL_input *sql = (SQL_input*) info;
169 MSIVIEW *insert = NULL;
171 INSERT_CreateView( sql->db, &insert, $3, $5, $9, TRUE );
172 $$ = insert;
176 onecreate:
177 TK_CREATE TK_TABLE table TK_LP table_def TK_RP
179 SQL_input* sql = (SQL_input*) info;
180 MSIVIEW *create;
182 if( !$5 )
183 YYABORT;
184 CREATE_CreateView( sql->db, &create, $3, $5, FALSE );
185 $$ = create;
187 | TK_CREATE TK_TABLE table TK_LP table_def TK_RP TK_HOLD
189 SQL_input* sql = (SQL_input*) info;
190 MSIVIEW *create;
192 if( !$5 )
193 YYABORT;
194 CREATE_CreateView( sql->db, &create, $3, $5, TRUE );
195 $$ = create;
199 table_def:
200 column_def TK_PRIMARY TK_KEY selcollist
202 if( SQL_MarkPrimaryKeys( $1, $4 ) )
203 $$ = $1;
204 else
205 $$ = NULL;
209 column_def:
210 column_def TK_COMMA column column_type
212 create_col_info *ci;
214 for( ci = $1; ci->next; ci = ci->next )
217 ci->next = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ );
218 if( !ci->next )
220 /* FIXME: free $1 */
221 YYABORT;
223 ci->next->colname = $3;
224 ci->next->type = $4;
225 ci->next->next = NULL;
227 $$ = $1;
229 | column column_type
231 $$ = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ );
232 if( ! $$ )
233 YYABORT;
234 $$->colname = $1;
235 $$->type = $2;
236 $$->next = NULL;
240 column_type:
241 data_type_l
243 $$ = $1 | MSITYPE_VALID;
245 | data_type_l TK_LOCALIZABLE
247 FIXME("LOCALIZABLE ignored\n");
248 $$ = $1 | MSITYPE_VALID;
252 data_type_l:
253 data_type
255 $$ |= MSITYPE_NULLABLE;
257 | data_type TK_NOT TK_NULL
259 $$ = $1;
263 data_type:
264 TK_CHAR
266 $$ = MSITYPE_STRING | 1;
268 | TK_CHAR TK_LP data_count TK_RP
270 $$ = MSITYPE_STRING | 0x400 | $3;
272 | TK_LONGCHAR
274 $$ = 2;
276 | TK_SHORT
278 $$ = 2;
280 | TK_INT
282 $$ = 2;
284 | TK_LONG
286 $$ = 4;
288 | TK_OBJECT
290 $$ = 0;
294 data_count:
295 TK_INTEGER
297 SQL_input* sql = (SQL_input*) info;
298 int val = SQL_getint(sql);
299 if( ( val > 255 ) || ( val < 0 ) )
300 YYABORT;
301 $$ = val;
305 oneselect:
306 unorderedsel TK_ORDER TK_BY selcollist
308 SQL_input* sql = (SQL_input*) info;
310 if( !$1 )
311 YYABORT;
312 if( $4 )
313 $$ = do_order_by( sql->db, $1, $4 );
314 else
315 $$ = $1;
317 | unorderedsel
320 unorderedsel:
321 TK_SELECT selcollist from
323 SQL_input* sql = (SQL_input*) info;
324 if( !$3 )
325 YYABORT;
326 if( $2 )
327 $$ = do_one_select( sql->db, $3, $2 );
328 else
329 $$ = $3;
331 | TK_SELECT TK_DISTINCT selcollist from
333 SQL_input* sql = (SQL_input*) info;
334 MSIVIEW *view = $4;
336 if( !view )
337 YYABORT;
338 if( $3 )
339 view = do_one_select( sql->db, view, $3 );
340 DISTINCT_CreateView( sql->db, & $$, view );
344 selcollist:
345 column
347 string_list *list;
349 list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
350 if( !list )
351 YYABORT;
352 list->string = $1;
353 list->next = NULL;
355 $$ = list;
356 TRACE("Collist %s\n",debugstr_w($$->string));
358 | column TK_COMMA selcollist
360 string_list *list;
362 list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
363 if( !list )
364 YYABORT;
365 list->string = $1;
366 list->next = $3;
368 $$ = list;
369 TRACE("From table: %s\n",debugstr_w($$->string));
371 | TK_STAR
373 $$ = NULL;
377 from:
378 TK_FROM table
380 SQL_input* sql = (SQL_input*) info;
382 $$ = NULL;
383 TRACE("From table: %s\n",debugstr_w($2));
384 TABLE_CreateView( sql->db, $2, & $$ );
386 | TK_FROM table TK_WHERE expr
388 SQL_input* sql = (SQL_input*) info;
389 MSIVIEW *view = NULL;
390 UINT r;
392 $$ = NULL;
393 TRACE("From table: %s\n",debugstr_w($2));
394 r = TABLE_CreateView( sql->db, $2, &view );
395 if( r != ERROR_SUCCESS )
396 YYABORT;
397 r = WHERE_CreateView( sql->db, &view, view, $4 );
398 if( r != ERROR_SUCCESS )
399 YYABORT;
400 $$ = view;
404 expr:
405 TK_LP expr TK_RP
407 $$ = $2;
409 | column_val TK_EQ column_val
411 $$ = EXPR_complex( $1, OP_EQ, $3 );
413 | expr TK_AND expr
415 $$ = EXPR_complex( $1, OP_AND, $3 );
417 | expr TK_OR expr
419 $$ = EXPR_complex( $1, OP_OR, $3 );
421 | column_val TK_EQ val
423 $$ = EXPR_complex( $1, OP_EQ, $3 );
425 | column_val TK_GT val
427 $$ = EXPR_complex( $1, OP_GT, $3 );
429 | column_val TK_LT val
431 $$ = EXPR_complex( $1, OP_LT, $3 );
433 | column_val TK_LE val
435 $$ = EXPR_complex( $1, OP_LE, $3 );
437 | column_val TK_GE val
439 $$ = EXPR_complex( $1, OP_GE, $3 );
441 | column_val TK_NE val
443 $$ = EXPR_complex( $1, OP_NE, $3 );
445 | column_val TK_IS TK_NULL
447 $$ = EXPR_complex( $1, OP_ISNULL, NULL );
449 | column_val TK_IS TK_NOT TK_NULL
451 $$ = EXPR_complex( $1, OP_NOTNULL, NULL );
455 val:
456 column_val
457 | const_val
460 constlist:
461 const_val
463 value_list *vals;
465 vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
466 if( vals )
468 vals->val = $1;
469 vals->next = NULL;
471 $$ = vals;
473 | constlist TK_COMMA const_val
475 value_list *vals;
477 vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
478 if( vals )
480 vals->val = $3;
481 vals->next = NULL;
483 $1->next = vals;
484 $$ = $1;
488 const_val:
489 TK_INTEGER
491 $$ = EXPR_ival( &$1 );
493 | TK_STRING
495 $$ = EXPR_sval( &$1 );
497 | TK_WILDCARD
499 $$ = EXPR_wildcard();
503 column_val:
504 column
506 $$ = EXPR_column( $1 );
510 column:
511 table TK_DOT string_or_id
513 $$ = $3; /* FIXME */
515 | string_or_id
517 $$ = $1;
521 table:
522 string_or_id
524 $$ = $1;
528 string_or_id:
529 TK_ID
531 $$ = SQL_getstring( &$1 );
533 | TK_STRING
535 $$ = SQL_getstring( &$1 );
541 int SQL_lex( void *SQL_lval, SQL_input *sql)
543 int token;
544 struct sql_str * str = SQL_lval;
548 sql->n += sql->len;
549 if( ! sql->command[sql->n] )
550 return 0; /* end of input */
552 TRACE("string : %s\n", debugstr_w(&sql->command[sql->n]));
553 sql->len = sqliteGetToken( &sql->command[sql->n], &token );
554 if( sql->len==0 )
555 break;
556 str->data = &sql->command[sql->n];
557 str->len = sql->len;
559 while( token == TK_SPACE );
561 TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len));
563 return token;
566 LPWSTR SQL_getstring( struct sql_str *strdata)
568 LPCWSTR p = strdata->data;
569 UINT len = strdata->len;
570 LPWSTR str;
572 /* if there's quotes, remove them */
573 if( ( (p[0]=='`') && (p[len-1]=='`') ) ||
574 ( (p[0]=='\'') && (p[len-1]=='\'') ) )
576 p++;
577 len -= 2;
579 str = HeapAlloc( GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
580 if(!str )
581 return str;
582 memcpy(str, p, len*sizeof(WCHAR) );
583 str[len]=0;
585 return str;
588 INT SQL_getint( SQL_input *sql )
590 LPCWSTR p = &sql->command[sql->n];
592 return atoiW( p );
595 int SQL_error(const char *str)
597 return 0;
600 static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in,
601 string_list *columns )
603 MSIVIEW *view = NULL;
605 SELECT_CreateView( db, &view, in, columns );
606 delete_string_list( columns );
607 if( !view )
608 ERR("Error creating select query\n");
609 return view;
612 static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in,
613 string_list *columns )
615 MSIVIEW *view = NULL;
617 ORDER_CreateView( db, &view, in );
618 if( view )
620 string_list *x = columns;
622 for( x = columns; x ; x = x->next )
623 ORDER_AddColumn( view, x->string );
625 else
626 ERR("Error creating select query\n");
627 delete_string_list( columns );
628 return view;
631 static struct expr * EXPR_wildcard()
633 struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
634 if( e )
636 e->type = EXPR_WILDCARD;
638 return e;
641 static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r )
643 struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
644 if( e )
646 e->type = EXPR_COMPLEX;
647 e->u.expr.left = l;
648 e->u.expr.op = op;
649 e->u.expr.right = r;
651 return e;
654 static struct expr * EXPR_column( LPWSTR str )
656 struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
657 if( e )
659 e->type = EXPR_COLUMN;
660 e->u.sval = str;
662 return e;
665 static struct expr * EXPR_ival( struct sql_str *str )
667 struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
668 if( e )
670 e->type = EXPR_IVAL;
671 e->u.ival = atoiW( str->data );
673 return e;
676 static struct expr * EXPR_sval( struct sql_str *str )
678 struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
679 if( e )
681 e->type = EXPR_SVAL;
682 e->u.sval = SQL_getstring( str );
684 return e;
687 void delete_expr( struct expr *e )
689 if( !e )
690 return;
691 if( e->type == EXPR_COMPLEX )
693 delete_expr( e->u.expr.left );
694 delete_expr( e->u.expr.right );
696 else if( e->type == EXPR_UTF8 )
697 HeapFree( GetProcessHeap(), 0, e->u.utf8 );
698 else if( e->type == EXPR_SVAL )
699 HeapFree( GetProcessHeap(), 0, e->u.sval );
700 HeapFree( GetProcessHeap(), 0, e );
703 void delete_string_list( string_list *sl )
705 while( sl )
707 string_list *t = sl->next;
708 HeapFree( GetProcessHeap(), 0, sl->string );
709 HeapFree( GetProcessHeap(), 0, sl );
710 sl = t;
714 void delete_value_list( value_list *vl )
716 while( vl )
718 value_list *t = vl->next;
719 delete_expr( vl->val );
720 HeapFree( GetProcessHeap(), 0, vl );
721 vl = t;
725 static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,
726 string_list *keys )
728 string_list *k;
729 BOOL found = TRUE;
731 for( k = keys; k && found; k = k->next )
733 create_col_info *c;
735 found = FALSE;
736 for( c = cols; c && !found; c = c->next )
738 if( lstrcmpW( k->string, c->colname ) )
739 continue;
740 c->type |= MSITYPE_KEY;
741 found = TRUE;
745 return found;
748 UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview )
750 SQL_input sql;
751 int r;
753 *phview = NULL;
755 sql.db = db;
756 sql.command = command;
757 sql.n = 0;
758 sql.len = 0;
759 sql.view = phview;
761 r = SQL_parse(&sql);
763 TRACE("Parse returned %d\n", r);
764 if( r )
766 if( *sql.view )
767 (*sql.view)->ops->delete( *sql.view );
768 *sql.view = NULL;
769 return ERROR_BAD_QUERY_SYNTAX;
772 return ERROR_SUCCESS;