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