Make ole32 tests loadable on NT4.
[wine/multimedia.git] / dlls / msi / sql.y
blob86466b88731ea09918cb72f44c7c2379e86973e0
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 *, int sign);
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;
83 column_assignment update_col_info;
86 %token TK_ABORT TK_AFTER TK_AGG_FUNCTION TK_ALL TK_AND TK_AS TK_ASC
87 %token TK_BEFORE TK_BEGIN TK_BETWEEN TK_BITAND TK_BITNOT TK_BITOR TK_BY
88 %token TK_CASCADE TK_CASE TK_CHAR TK_CHECK TK_CLUSTER TK_COLLATE TK_COLUMN
89 %token TK_COMMA TK_COMMENT TK_COMMIT TK_CONCAT TK_CONFLICT
90 %token TK_CONSTRAINT TK_COPY TK_CREATE
91 %token TK_DEFAULT TK_DEFERRABLE TK_DEFERRED TK_DELETE TK_DELIMITERS TK_DESC
92 %token TK_DISTINCT TK_DOT TK_DROP TK_EACH
93 %token TK_ELSE TK_END TK_END_OF_FILE TK_EQ TK_EXCEPT TK_EXPLAIN
94 %token TK_FAIL TK_FLOAT TK_FOR TK_FOREIGN TK_FROM TK_FUNCTION
95 %token TK_GE TK_GLOB TK_GROUP TK_GT
96 %token TK_HAVING TK_HOLD
97 %token TK_IGNORE TK_ILLEGAL TK_IMMEDIATE TK_IN TK_INDEX TK_INITIALLY
98 %token <str> TK_ID
99 %token TK_INSERT TK_INSTEAD TK_INT
100 %token <str> TK_INTEGER
101 %token TK_INTERSECT TK_INTO TK_IS
102 %token TK_ISNULL
103 %token TK_JOIN TK_JOIN_KW
104 %token TK_KEY
105 %token TK_LE TK_LIKE TK_LIMIT TK_LONG TK_LONGCHAR TK_LP TK_LSHIFT TK_LT
106 %token TK_LOCALIZABLE
107 %token TK_MATCH TK_MINUS
108 %token TK_NE TK_NOT TK_NOTNULL TK_NULL
109 %token TK_OBJECT TK_OF TK_OFFSET TK_ON TK_OR TK_ORACLE_OUTER_JOIN TK_ORDER
110 %token TK_PLUS TK_PRAGMA TK_PRIMARY
111 %token TK_RAISE TK_REFERENCES TK_REM TK_REPLACE TK_RESTRICT TK_ROLLBACK
112 %token TK_ROW TK_RP TK_RSHIFT
113 %token TK_SELECT TK_SEMI TK_SET TK_SHORT TK_SLASH TK_SPACE TK_STAR TK_STATEMENT
114 %token <str> TK_STRING
115 %token TK_TABLE TK_TEMP TK_THEN TK_TRANSACTION TK_TRIGGER
116 %token TK_UMINUS TK_UNCLOSED_STRING TK_UNION TK_UNIQUE
117 %token TK_UPDATE TK_UPLUS TK_USING
118 %token TK_VACUUM TK_VALUES TK_VIEW
119 %token TK_WHEN TK_WHERE TK_WILDCARD
122 * These are extra tokens used by the lexer but never seen by the
123 * parser. We put them in a rule so that the parser generator will
124 * add them to the parse.h output file.
127 %nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
128 COLUMN AGG_FUNCTION.
130 %type <string> column table string_or_id
131 %type <column_list> selcollist
132 %type <query> from unorderedsel oneselect onequery onecreate oneinsert
133 %type <query> oneupdate onedelete
134 %type <expr> expr val column_val const_val
135 %type <column_type> column_type data_type data_type_l data_count
136 %type <column_info> column_def table_def
137 %type <val_list> constlist
138 %type <update_col_info> column_assignment update_assign_list
142 onequery:
143 oneselect
145 SQL_input* sql = (SQL_input*) info;
146 *sql->view = $1;
148 | onecreate
150 SQL_input* sql = (SQL_input*) info;
151 *sql->view = $1;
153 | oneinsert
155 SQL_input* sql = (SQL_input*) info;
156 *sql->view = $1;
158 | oneupdate
160 SQL_input* sql = (SQL_input*) info;
161 *sql->view = $1;
163 | onedelete
165 SQL_input* sql = (SQL_input*) info;
166 *sql->view = $1;
170 oneinsert:
171 TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP
173 SQL_input *sql = (SQL_input*) info;
174 MSIVIEW *insert = NULL;
176 INSERT_CreateView( sql->db, &insert, $3, $5, $9, FALSE );
177 $$ = insert;
179 | TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP TK_TEMP
181 SQL_input *sql = (SQL_input*) info;
182 MSIVIEW *insert = NULL;
184 INSERT_CreateView( sql->db, &insert, $3, $5, $9, TRUE );
185 $$ = insert;
189 onecreate:
190 TK_CREATE TK_TABLE table TK_LP table_def TK_RP
192 SQL_input* sql = (SQL_input*) info;
193 MSIVIEW *create = NULL;
195 if( !$5 )
196 YYABORT;
197 CREATE_CreateView( sql->db, &create, $3, $5, FALSE );
198 $$ = create;
200 | TK_CREATE TK_TABLE table TK_LP table_def TK_RP TK_HOLD
202 SQL_input* sql = (SQL_input*) info;
203 MSIVIEW *create = NULL;
205 if( !$5 )
206 YYABORT;
207 CREATE_CreateView( sql->db, &create, $3, $5, TRUE );
208 $$ = create;
212 oneupdate:
213 TK_UPDATE table TK_SET update_assign_list TK_WHERE expr
215 SQL_input* sql = (SQL_input*) info;
216 MSIVIEW *update = NULL;
218 UPDATE_CreateView( sql->db, &update, $2, &$4, $6 );
219 $$ = update;
223 onedelete:
224 TK_DELETE from
226 SQL_input* sql = (SQL_input*) info;
227 MSIVIEW *delete = NULL;
229 DELETE_CreateView( sql->db, &delete, $2 );
230 $$ = delete;
234 table_def:
235 column_def TK_PRIMARY TK_KEY selcollist
237 if( SQL_MarkPrimaryKeys( $1, $4 ) )
238 $$ = $1;
239 else
240 $$ = NULL;
244 column_def:
245 column_def TK_COMMA column column_type
247 create_col_info *ci;
249 for( ci = $1; ci->next; ci = ci->next )
252 ci->next = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ );
253 if( !ci->next )
255 /* FIXME: free $1 */
256 YYABORT;
258 ci->next->colname = $3;
259 ci->next->type = $4;
260 ci->next->next = NULL;
262 $$ = $1;
264 | column column_type
266 $$ = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ );
267 if( ! $$ )
268 YYABORT;
269 $$->colname = $1;
270 $$->type = $2;
271 $$->next = NULL;
275 column_type:
276 data_type_l
278 $$ = $1 | MSITYPE_VALID;
280 | data_type_l TK_LOCALIZABLE
282 FIXME("LOCALIZABLE ignored\n");
283 $$ = $1 | MSITYPE_VALID;
287 data_type_l:
288 data_type
290 $$ |= MSITYPE_NULLABLE;
292 | data_type TK_NOT TK_NULL
294 $$ = $1;
298 data_type:
299 TK_CHAR
301 $$ = MSITYPE_STRING | 1;
303 | TK_CHAR TK_LP data_count TK_RP
305 $$ = MSITYPE_STRING | 0x400 | $3;
307 | TK_LONGCHAR
309 $$ = 2;
311 | TK_SHORT
313 $$ = 2;
315 | TK_INT
317 $$ = 2;
319 | TK_LONG
321 $$ = 4;
323 | TK_OBJECT
325 $$ = 0;
329 data_count:
330 TK_INTEGER
332 SQL_input* sql = (SQL_input*) info;
333 int val = SQL_getint(sql);
334 if( ( val > 255 ) || ( val < 0 ) )
335 YYABORT;
336 $$ = val;
340 oneselect:
341 unorderedsel TK_ORDER TK_BY selcollist
343 SQL_input* sql = (SQL_input*) info;
345 if( !$1 )
346 YYABORT;
347 if( $4 )
348 $$ = do_order_by( sql->db, $1, $4 );
349 else
350 $$ = $1;
352 | unorderedsel
355 unorderedsel:
356 TK_SELECT selcollist from
358 SQL_input* sql = (SQL_input*) info;
359 if( !$3 )
360 YYABORT;
361 if( $2 )
363 $$ = do_one_select( sql->db, $3, $2 );
364 if( !$$ )
365 YYABORT;
367 else
368 $$ = $3;
370 | TK_SELECT TK_DISTINCT selcollist from
372 SQL_input* sql = (SQL_input*) info;
373 MSIVIEW *view = $4;
375 if( !view )
376 YYABORT;
377 if( $3 )
379 view = do_one_select( sql->db, view, $3 );
380 if( !view )
381 YYABORT;
383 DISTINCT_CreateView( sql->db, & $$, view );
387 selcollist:
388 column
390 string_list *list;
392 list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
393 if( !list )
394 YYABORT;
395 list->string = $1;
396 list->next = NULL;
398 $$ = list;
399 TRACE("Collist %s\n",debugstr_w($$->string));
401 | column TK_COMMA selcollist
403 string_list *list;
405 list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
406 if( !list )
407 YYABORT;
408 list->string = $1;
409 list->next = $3;
411 $$ = list;
412 TRACE("From table: %s\n",debugstr_w($$->string));
414 | TK_STAR
416 $$ = NULL;
420 from:
421 TK_FROM table
423 SQL_input* sql = (SQL_input*) info;
424 UINT r;
426 $$ = NULL;
427 TRACE("From table: %s\n",debugstr_w($2));
428 r = TABLE_CreateView( sql->db, $2, & $$ );
429 if( r != ERROR_SUCCESS )
430 YYABORT;
432 | TK_FROM table TK_WHERE expr
434 SQL_input* sql = (SQL_input*) info;
435 MSIVIEW *view = NULL;
436 UINT r;
438 $$ = NULL;
439 TRACE("From table: %s\n",debugstr_w($2));
440 r = TABLE_CreateView( sql->db, $2, &view );
441 if( r != ERROR_SUCCESS )
442 YYABORT;
443 r = WHERE_CreateView( sql->db, &view, view, $4 );
444 if( r != ERROR_SUCCESS )
445 YYABORT;
446 $$ = view;
450 expr:
451 TK_LP expr TK_RP
453 $$ = $2;
455 | column_val TK_EQ column_val
457 $$ = EXPR_complex( $1, OP_EQ, $3 );
459 | expr TK_AND expr
461 $$ = EXPR_complex( $1, OP_AND, $3 );
463 | expr TK_OR expr
465 $$ = EXPR_complex( $1, OP_OR, $3 );
467 | column_val TK_EQ val
469 $$ = EXPR_complex( $1, OP_EQ, $3 );
471 | column_val TK_GT val
473 $$ = EXPR_complex( $1, OP_GT, $3 );
475 | column_val TK_LT val
477 $$ = EXPR_complex( $1, OP_LT, $3 );
479 | column_val TK_LE val
481 $$ = EXPR_complex( $1, OP_LE, $3 );
483 | column_val TK_GE val
485 $$ = EXPR_complex( $1, OP_GE, $3 );
487 | column_val TK_NE val
489 $$ = EXPR_complex( $1, OP_NE, $3 );
491 | column_val TK_IS TK_NULL
493 $$ = EXPR_complex( $1, OP_ISNULL, NULL );
495 | column_val TK_IS TK_NOT TK_NULL
497 $$ = EXPR_complex( $1, OP_NOTNULL, NULL );
501 val:
502 column_val
503 | const_val
506 constlist:
507 const_val
509 value_list *vals;
511 vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
512 if( vals )
514 vals->val = $1;
515 vals->next = NULL;
517 $$ = vals;
519 | const_val TK_COMMA constlist
521 value_list *vals;
523 vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
524 if( vals )
526 vals->val = $1;
527 vals->next = $3;
529 $$ = vals;
533 update_assign_list:
534 column_assignment
535 | column_assignment TK_COMMA update_assign_list
537 $1.col_list->next = $3.col_list;
538 $1.val_list->next = $3.val_list;
539 $$ = $1;
543 column_assignment:
544 column TK_EQ const_val
546 $$.col_list = HeapAlloc( GetProcessHeap(), 0, sizeof *$$.col_list );
547 if( !$$.col_list )
548 YYABORT;
549 $$.col_list->string = $1;
550 $$.col_list->next = NULL;
551 $$.val_list = HeapAlloc( GetProcessHeap(), 0, sizeof *$$.val_list );
552 if( !$$.val_list )
553 YYABORT;
554 $$.val_list->val = $3;
555 $$.val_list->next = 0;
559 const_val:
560 TK_INTEGER
562 $$ = EXPR_ival( &$1, 1 );
564 | TK_MINUS TK_INTEGER
566 $$ = EXPR_ival( &$2, -1 );
568 | TK_STRING
570 $$ = EXPR_sval( &$1 );
572 | TK_WILDCARD
574 $$ = EXPR_wildcard();
578 column_val:
579 column
581 $$ = EXPR_column( $1 );
585 column:
586 table TK_DOT string_or_id
588 $$ = $3; /* FIXME */
590 | string_or_id
592 $$ = $1;
596 table:
597 string_or_id
599 $$ = $1;
603 string_or_id:
604 TK_ID
606 $$ = SQL_getstring( &$1 );
608 | TK_STRING
610 $$ = SQL_getstring( &$1 );
616 int SQL_lex( void *SQL_lval, SQL_input *sql)
618 int token;
619 struct sql_str * str = SQL_lval;
623 sql->n += sql->len;
624 if( ! sql->command[sql->n] )
625 return 0; /* end of input */
627 TRACE("string : %s\n", debugstr_w(&sql->command[sql->n]));
628 sql->len = sqliteGetToken( &sql->command[sql->n], &token );
629 if( sql->len==0 )
630 break;
631 str->data = &sql->command[sql->n];
632 str->len = sql->len;
634 while( token == TK_SPACE );
636 TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len));
638 return token;
641 LPWSTR SQL_getstring( struct sql_str *strdata)
643 LPCWSTR p = strdata->data;
644 UINT len = strdata->len;
645 LPWSTR str;
647 /* if there's quotes, remove them */
648 if( ( (p[0]=='`') && (p[len-1]=='`') ) ||
649 ( (p[0]=='\'') && (p[len-1]=='\'') ) )
651 p++;
652 len -= 2;
654 str = HeapAlloc( GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
655 if(!str )
656 return str;
657 memcpy(str, p, len*sizeof(WCHAR) );
658 str[len]=0;
660 return str;
663 INT SQL_getint( SQL_input *sql )
665 LPCWSTR p = &sql->command[sql->n];
667 return atoiW( p );
670 int SQL_error(const char *str)
672 return 0;
675 static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in,
676 string_list *columns )
678 MSIVIEW *view = NULL;
680 SELECT_CreateView( db, &view, in, columns );
681 delete_string_list( columns );
682 if( !view )
683 ERR("Error creating select query\n");
684 return view;
687 static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in,
688 string_list *columns )
690 MSIVIEW *view = NULL;
692 ORDER_CreateView( db, &view, in );
693 if( view )
695 string_list *x = columns;
697 for( x = columns; x ; x = x->next )
698 ORDER_AddColumn( view, x->string );
700 else
701 ERR("Error creating select query\n");
702 delete_string_list( columns );
703 return view;
706 static struct expr * EXPR_wildcard()
708 struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
709 if( e )
711 e->type = EXPR_WILDCARD;
713 return e;
716 static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r )
718 struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
719 if( e )
721 e->type = EXPR_COMPLEX;
722 e->u.expr.left = l;
723 e->u.expr.op = op;
724 e->u.expr.right = r;
726 return e;
729 static struct expr * EXPR_column( LPWSTR str )
731 struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
732 if( e )
734 e->type = EXPR_COLUMN;
735 e->u.sval = str;
737 return e;
740 static struct expr * EXPR_ival( struct sql_str *str , int sign)
742 struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
743 if( e )
745 e->type = EXPR_IVAL;
746 e->u.ival = atoiW( str->data ) * sign;
748 return e;
751 static struct expr * EXPR_sval( struct sql_str *str )
753 struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
754 if( e )
756 e->type = EXPR_SVAL;
757 e->u.sval = SQL_getstring( str );
759 return e;
762 void delete_expr( struct expr *e )
764 if( !e )
765 return;
766 if( e->type == EXPR_COMPLEX )
768 delete_expr( e->u.expr.left );
769 delete_expr( e->u.expr.right );
771 else if( e->type == EXPR_UTF8 )
772 HeapFree( GetProcessHeap(), 0, e->u.utf8 );
773 else if( e->type == EXPR_SVAL )
774 HeapFree( GetProcessHeap(), 0, e->u.sval );
775 HeapFree( GetProcessHeap(), 0, e );
778 void delete_string_list( string_list *sl )
780 while( sl )
782 string_list *t = sl->next;
783 HeapFree( GetProcessHeap(), 0, sl->string );
784 HeapFree( GetProcessHeap(), 0, sl );
785 sl = t;
789 void delete_value_list( value_list *vl )
791 while( vl )
793 value_list *t = vl->next;
794 delete_expr( vl->val );
795 HeapFree( GetProcessHeap(), 0, vl );
796 vl = t;
800 static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,
801 string_list *keys )
803 string_list *k;
804 BOOL found = TRUE;
806 for( k = keys; k && found; k = k->next )
808 create_col_info *c;
810 found = FALSE;
811 for( c = cols; c && !found; c = c->next )
813 if( lstrcmpW( k->string, c->colname ) )
814 continue;
815 c->type |= MSITYPE_KEY;
816 found = TRUE;
820 return found;
823 UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview )
825 SQL_input sql;
826 int r;
828 *phview = NULL;
830 sql.db = db;
831 sql.command = command;
832 sql.n = 0;
833 sql.len = 0;
834 sql.view = phview;
836 r = SQL_parse(&sql);
838 TRACE("Parse returned %d\n", r);
839 if( r )
841 if( *sql.view )
842 (*sql.view)->ops->delete( *sql.view );
843 *sql.view = NULL;
844 return ERROR_BAD_QUERY_SYNTAX;
847 return ERROR_SUCCESS;