Start implementing MsiOpenPackage.
[wine] / dlls / msi / sql.y
1 %{
2
3 /*
4  * Implementation of the Microsoft Installer (msi.dll)
5  *
6  * Copyright 2002-2004 Mike McCormack for CodeWeavers
7  *
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.
12  *
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.
17  *
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
21  */
22
23
24 #include "config.h"
25
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "query.h"
33 #include "wine/debug.h"
34 #include "wine/unicode.h"
35
36 #define YYLEX_PARAM info
37 #define YYPARSE_PARAM info
38
39 extern int SQL_error(const char *str);
40
41 WINE_DEFAULT_DEBUG_CHANNEL(msi);
42
43 typedef struct tag_SQL_input
44 {
45     MSIDATABASE *db;
46     LPCWSTR command;
47     DWORD n, len;
48     MSIVIEW **view;  /* view structure for the resulting query */
49 } SQL_input;
50
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);
54
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 );
59
60 static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,
61                                  string_list *keys);
62
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();
68
69 %}
70
71 %pure-parser
72
73 %union
74 {
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 }
84
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
119
120 /*
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.
124  *
125  */
126 %nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
127           COLUMN AGG_FUNCTION.
128
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
136
137 %%
138
139 onequery:
140     oneselect
141     {
142         SQL_input* sql = (SQL_input*) info;
143         *sql->view = $1;
144     }
145   | onecreate
146     {
147         SQL_input* sql = (SQL_input*) info;
148         *sql->view = $1;
149     }
150   | oneinsert
151     {
152         SQL_input* sql = (SQL_input*) info;
153         *sql->view = $1;
154     }
155     ;
156
157 oneinsert:
158     TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP
159     {
160         SQL_input *sql = (SQL_input*) info;
161         MSIVIEW *insert = NULL; 
162
163         INSERT_CreateView( sql->db, &insert, $3, $5, $9, FALSE ); 
164         $$ = insert;
165     }
166   | TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP TK_TEMP
167     {
168         SQL_input *sql = (SQL_input*) info;
169         MSIVIEW *insert = NULL; 
170
171         INSERT_CreateView( sql->db, &insert, $3, $5, $9, TRUE ); 
172         $$ = insert;
173     }
174     ;
175
176 onecreate:
177     TK_CREATE TK_TABLE table TK_LP table_def TK_RP
178         {
179             SQL_input* sql = (SQL_input*) info;
180             MSIVIEW *create; 
181
182             if( !$5 )
183                 YYABORT;
184             CREATE_CreateView( sql->db, &create, $3, $5, FALSE );
185             $$ = create;
186         }
187   | TK_CREATE TK_TABLE table TK_LP table_def TK_RP TK_HOLD
188         {
189             SQL_input* sql = (SQL_input*) info;
190             MSIVIEW *create; 
191
192             if( !$5 )
193                 YYABORT;
194             CREATE_CreateView( sql->db, &create, $3, $5, TRUE );
195             $$ = create;
196         }
197     ;
198
199 table_def:
200     column_def TK_PRIMARY TK_KEY selcollist
201         {
202             if( SQL_MarkPrimaryKeys( $1, $4 ) )
203                 $$ = $1;
204             else
205                 $$ = NULL;
206         }
207     ;
208
209 column_def:
210     column_def TK_COMMA column column_type
211         {
212             create_col_info *ci;
213
214             for( ci = $1; ci->next; ci = ci->next )
215                 ;
216
217             ci->next = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ );
218             if( ci->next )
219             {
220                 ci->next->colname = $3;
221                 ci->next->type = $4;
222                 ci->next->next = NULL;
223             }
224             else if( $1 )
225             {
226                 HeapFree( GetProcessHeap(), 0, $1 );
227                 $1 = NULL;
228             }
229             $$ = $1;
230         }
231   | column column_type
232         {
233             $$ = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ );
234             if( $$ )
235             {
236                 $$->colname = $1;
237                 $$->type = $2;
238                 $$->next = NULL;
239             }
240         }
241     ;
242
243 column_type:
244     data_type_l
245         {
246             $$ = $1;
247         }
248   | data_type_l TK_LOCALIZABLE
249         {
250             FIXME("LOCALIZABLE ignored\n");
251             $$ = $1;
252         }
253     ;
254
255 data_type_l:
256     data_type
257         {
258             $$ |= MSITYPE_NULLABLE;
259         }
260   | data_type TK_NOT TK_NULL
261         {
262             $$ = $1;
263         }
264     ;
265
266 data_type:
267     TK_CHAR
268         {
269             $$ = MSITYPE_STRING | 1;
270         }
271   | TK_CHAR TK_LP data_count TK_RP
272         {
273             $$ = MSITYPE_STRING | 0x500 | $3;
274         }
275   | TK_LONGCHAR
276         {
277             $$ = 2;
278         }
279   | TK_SHORT
280         {
281             $$ = 2;
282         }
283   | TK_INT
284         {
285             $$ = 2;
286         }
287   | TK_LONG
288         {
289             $$ = 4;
290         }
291   | TK_OBJECT
292         {
293             $$ = 0;
294         }
295     ;
296
297 data_count:
298     TK_INTEGER
299         {
300             SQL_input* sql = (SQL_input*) info;
301             int val = SQL_getint(sql);
302             if( ( val > 255 ) || ( val < 0 ) )
303                 YYABORT;
304             $$ = val;
305         }
306     ;
307
308 oneselect:
309     unorderedsel TK_ORDER TK_BY selcollist
310         {
311             SQL_input* sql = (SQL_input*) info;
312
313             if( !$1 )
314                 YYABORT;
315             if( $4 )
316                 $$ = do_order_by( sql->db, $1, $4 );
317             else
318                 $$ = $1;
319         }
320   | unorderedsel
321     ;
322
323 unorderedsel:
324     TK_SELECT selcollist from 
325         {
326             SQL_input* sql = (SQL_input*) info;
327             if( !$3 )
328                 YYABORT;
329             if( $2 )
330                 $$ = do_one_select( sql->db, $3, $2 );
331             else
332                 $$ = $3;
333         }
334   | TK_SELECT TK_DISTINCT selcollist from 
335         {
336             SQL_input* sql = (SQL_input*) info;
337             MSIVIEW *view = $4;
338
339             if( !view )
340                 YYABORT;
341             if( $3 )
342                 view = do_one_select( sql->db, view, $3 );
343             DISTINCT_CreateView( sql->db, & $$, view );
344         }
345     ;
346
347 selcollist:
348     column 
349         { 
350             string_list *list;
351
352             list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
353             if( !list )
354                 YYABORT;
355             list->string = $1;
356             list->next = NULL;
357
358             $$ = list;
359             TRACE("Collist %s\n",debugstr_w($$->string));
360         }
361   | column TK_COMMA selcollist
362         { 
363             string_list *list;
364
365             list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
366             if( !list )
367                 YYABORT;
368             list->string = $1;
369             list->next = $3;
370
371             $$ = list;
372             TRACE("From table: %s\n",debugstr_w($$->string));
373         }
374   | TK_STAR
375         {
376             $$ = NULL;
377         }
378     ;
379
380 from:
381     TK_FROM table
382         { 
383             SQL_input* sql = (SQL_input*) info;
384
385             $$ = NULL;
386             TRACE("From table: %s\n",debugstr_w($2));
387             TABLE_CreateView( sql->db, $2, & $$ );
388         }
389   | TK_FROM table TK_WHERE expr
390         { 
391             SQL_input* sql = (SQL_input*) info;
392             MSIVIEW *view = NULL;
393             UINT r;
394
395             $$ = NULL;
396             TRACE("From table: %s\n",debugstr_w($2));
397             r = TABLE_CreateView( sql->db, $2, &view );
398             if( r != ERROR_SUCCESS )
399                 YYABORT;
400             r = WHERE_CreateView( sql->db, &view, view );
401             if( r != ERROR_SUCCESS )
402                 YYABORT;
403             r = WHERE_AddCondition( view, $4 );
404             if( r != ERROR_SUCCESS )
405                 YYABORT;
406             $$ = view;
407         }
408     ;
409
410 expr:
411     TK_LP expr TK_RP
412         {
413             $$ = $2;
414         }
415   | column_val TK_EQ column_val
416         {
417             $$ = EXPR_complex( $1, OP_EQ, $3 );
418         }
419   | expr TK_AND expr
420         {
421             $$ = EXPR_complex( $1, OP_AND, $3 );
422         }
423   | expr TK_OR expr
424         {
425             $$ = EXPR_complex( $1, OP_OR, $3 );
426         }
427   | column_val TK_EQ val
428         {
429             $$ = EXPR_complex( $1, OP_EQ, $3 );
430         }
431   | column_val TK_GT val
432         {
433             $$ = EXPR_complex( $1, OP_GT, $3 );
434         }
435   | column_val TK_LT val
436         {
437             $$ = EXPR_complex( $1, OP_LT, $3 );
438         }
439   | column_val TK_LE val
440         {
441             $$ = EXPR_complex( $1, OP_LE, $3 );
442         }
443   | column_val TK_GE val
444         {
445             $$ = EXPR_complex( $1, OP_GE, $3 );
446         }
447   | column_val TK_NE val
448         {
449             $$ = EXPR_complex( $1, OP_NE, $3 );
450         }
451   | column_val TK_IS TK_NULL
452         {
453             $$ = EXPR_complex( $1, OP_ISNULL, NULL );
454         }
455   | column_val TK_IS TK_NOT TK_NULL
456         {
457             $$ = EXPR_complex( $1, OP_NOTNULL, NULL );
458         }
459     ;
460
461 val:
462     column_val
463   | const_val
464     ;
465
466 constlist:
467     const_val
468         {
469             value_list *vals;
470
471             vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
472             if( vals )
473             {
474                 vals->val = $1;
475                 vals->next = NULL;
476             }
477             $$ = vals;
478         }
479   | constlist TK_COMMA const_val
480         {
481             value_list *vals;
482
483             vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
484             if( vals )
485             {
486                 vals->val = $3;
487                 vals->next = NULL;
488             }
489             $1->next = vals;
490             $$ = $1;
491         }
492         ;
493
494 const_val:
495     TK_INTEGER
496         {
497             $$ = EXPR_ival( &$1 );
498         }
499   | TK_STRING
500         {
501             $$ = EXPR_sval( &$1 );
502         }
503   | TK_WILDCARD
504         {
505             $$ = EXPR_wildcard();
506         }
507     ;
508
509 column_val:
510     column 
511         {
512             $$ = EXPR_column( $1 );
513         }
514     ;
515
516 column:
517     table TK_DOT string_or_id
518         {
519             $$ = $3;  /* FIXME */
520         }
521   | string_or_id
522         {
523             $$ = $1;
524         }
525     ;
526
527 table:
528     string_or_id
529         {
530             $$ = $1;
531         }
532     ;
533
534 string_or_id:
535     TK_ID
536         {
537             $$ = SQL_getstring( &$1 );
538         }
539   | TK_STRING
540         {
541             $$ = SQL_getstring( &$1 );
542         }
543     ;
544
545 %%
546
547 int SQL_lex( void *SQL_lval, SQL_input *sql)
548 {
549     int token;
550     struct sql_str * str = SQL_lval;
551
552     do
553     {
554         sql->n += sql->len;
555         if( ! sql->command[sql->n] )
556             return 0;  /* end of input */
557
558         TRACE("string : %s\n", debugstr_w(&sql->command[sql->n]));
559         sql->len = sqliteGetToken( &sql->command[sql->n], &token );
560         if( sql->len==0 )
561             break;
562         str->data = &sql->command[sql->n];
563         str->len = sql->len;
564     }
565     while( token == TK_SPACE );
566
567     TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len));
568     
569     return token;
570 }
571
572 LPWSTR SQL_getstring( struct sql_str *strdata)
573 {
574     LPCWSTR p = strdata->data;
575     UINT len = strdata->len;
576     LPWSTR str;
577
578     /* if there's quotes, remove them */
579     if( ( (p[0]=='`') && (p[len-1]=='`') ) || 
580         ( (p[0]=='\'') && (p[len-1]=='\'') ) )
581     {
582         p++;
583         len -= 2;
584     }
585     str = HeapAlloc( GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
586     if(!str )
587         return str;
588     memcpy(str, p, len*sizeof(WCHAR) );
589     str[len]=0;
590
591     return str;
592 }
593
594 INT SQL_getint( SQL_input *sql )
595 {
596     LPCWSTR p = &sql->command[sql->n];
597
598     return atoiW( p );
599 }
600
601 int SQL_error(const char *str)
602 {
603     return 0;
604 }
605
606 static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in, 
607                                string_list *columns )
608 {
609     MSIVIEW *view = NULL;
610
611     SELECT_CreateView( db, &view, in, columns );
612     delete_string_list( columns );
613     if( !view )
614         ERR("Error creating select query\n");
615     return view;
616 }
617
618 static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in, 
619                              string_list *columns )
620 {
621     MSIVIEW *view = NULL;
622
623     ORDER_CreateView( db, &view, in );
624     if( view )
625     {
626         string_list *x = columns;
627
628         for( x = columns; x ; x = x->next )
629             ORDER_AddColumn( view, x->string );
630     }
631     else
632         ERR("Error creating select query\n");
633     delete_string_list( columns );
634     return view;
635 }
636
637 static struct expr * EXPR_wildcard()
638 {
639     struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
640     if( e )
641     {
642         e->type = EXPR_WILDCARD;
643     }
644     return e;
645 }
646
647 static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r )
648 {
649     struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
650     if( e )
651     {
652         e->type = EXPR_COMPLEX;
653         e->u.expr.left = l;
654         e->u.expr.op = op;
655         e->u.expr.right = r;
656     }
657     return e;
658 }
659
660 static struct expr * EXPR_column( LPWSTR str )
661 {
662     struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
663     if( e )
664     {
665         e->type = EXPR_COLUMN;
666         e->u.sval = str;
667     }
668     return e;
669 }
670
671 static struct expr * EXPR_ival( struct sql_str *str )
672 {
673     struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
674     if( e )
675     {
676         e->type = EXPR_IVAL;
677         e->u.ival = atoiW( str->data );
678     }
679     return e;
680 }
681
682 static struct expr * EXPR_sval( struct sql_str *str )
683 {
684     struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
685     if( e )
686     {
687         e->type = EXPR_SVAL;
688         e->u.sval = SQL_getstring( str );
689     }
690     return e;
691 }
692
693 void delete_expr( struct expr *e )
694 {
695     if( !e )
696         return;
697     if( e->type == EXPR_COMPLEX )
698     {
699         delete_expr( e->u.expr.left );
700         delete_expr( e->u.expr.right );
701     }
702     else if( e->type == EXPR_UTF8 )
703         HeapFree( GetProcessHeap(), 0, e->u.utf8 );
704     else if( e->type == EXPR_SVAL )
705         HeapFree( GetProcessHeap(), 0, e->u.sval );
706     HeapFree( GetProcessHeap(), 0, e );
707 }
708
709 void delete_string_list( string_list *sl )
710 {
711     while( sl )
712     {
713         string_list *t = sl->next;
714         HeapFree( GetProcessHeap(), 0, sl->string );
715         HeapFree( GetProcessHeap(), 0, sl );
716         sl = t;
717     }
718 }
719
720 void delete_value_list( value_list *vl )
721 {
722     while( vl )
723     {
724         value_list *t = vl->next;
725         delete_expr( vl->val );
726         HeapFree( GetProcessHeap(), 0, vl );
727         vl = t;
728     }
729 }
730
731 static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,
732                                  string_list *keys )
733 {
734     string_list *k;
735     BOOL found = TRUE;
736
737     for( k = keys; k && found; k = k->next )
738     {
739         create_col_info *c;
740
741         found = FALSE;
742         for( c = cols; c && !found; c = c->next )
743         {
744              if( lstrcmpW( k->string, c->colname ) )
745                  continue;
746              c->type |= MSITYPE_KEY;
747              found = TRUE;
748         }
749     }
750
751     return found;
752 }
753
754 UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview )
755 {
756     SQL_input sql;
757     int r;
758
759     *phview = NULL;
760
761     sql.db = db;
762     sql.command = command;
763     sql.n = 0;
764     sql.len = 0;
765     sql.view = phview;
766
767     r = SQL_parse(&sql);
768
769     TRACE("Parse returned %d\n", r);
770     if( r )
771     {
772         if( *sql.view )
773             (*sql.view)->ops->delete( *sql.view );
774         *sql.view = NULL;
775         return ERROR_BAD_QUERY_SYNTAX;
776     }
777
778     return ERROR_SUCCESS;
779 }