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