Implement the UPDATE query.
[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                 $$ = do_one_select( sql->db, $3, $2 );
346             else
347                 $$ = $3;
348         }
349   | TK_SELECT TK_DISTINCT selcollist from 
350         {
351             SQL_input* sql = (SQL_input*) info;
352             MSIVIEW *view = $4;
353
354             if( !view )
355                 YYABORT;
356             if( $3 )
357                 view = do_one_select( sql->db, view, $3 );
358             DISTINCT_CreateView( sql->db, & $$, view );
359         }
360     ;
361
362 selcollist:
363     column 
364         { 
365             string_list *list;
366
367             list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
368             if( !list )
369                 YYABORT;
370             list->string = $1;
371             list->next = NULL;
372
373             $$ = list;
374             TRACE("Collist %s\n",debugstr_w($$->string));
375         }
376   | column TK_COMMA selcollist
377         { 
378             string_list *list;
379
380             list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
381             if( !list )
382                 YYABORT;
383             list->string = $1;
384             list->next = $3;
385
386             $$ = list;
387             TRACE("From table: %s\n",debugstr_w($$->string));
388         }
389   | TK_STAR
390         {
391             $$ = NULL;
392         }
393     ;
394
395 from:
396     TK_FROM table
397         { 
398             SQL_input* sql = (SQL_input*) info;
399
400             $$ = NULL;
401             TRACE("From table: %s\n",debugstr_w($2));
402             TABLE_CreateView( sql->db, $2, & $$ );
403         }
404   | TK_FROM table TK_WHERE expr
405         { 
406             SQL_input* sql = (SQL_input*) info;
407             MSIVIEW *view = NULL;
408             UINT r;
409
410             $$ = NULL;
411             TRACE("From table: %s\n",debugstr_w($2));
412             r = TABLE_CreateView( sql->db, $2, &view );
413             if( r != ERROR_SUCCESS )
414                 YYABORT;
415             r = WHERE_CreateView( sql->db, &view, view, $4 );
416             if( r != ERROR_SUCCESS )
417                 YYABORT;
418             $$ = view;
419         }
420     ;
421
422 expr:
423     TK_LP expr TK_RP
424         {
425             $$ = $2;
426         }
427   | column_val TK_EQ column_val
428         {
429             $$ = EXPR_complex( $1, OP_EQ, $3 );
430         }
431   | expr TK_AND expr
432         {
433             $$ = EXPR_complex( $1, OP_AND, $3 );
434         }
435   | expr TK_OR expr
436         {
437             $$ = EXPR_complex( $1, OP_OR, $3 );
438         }
439   | column_val TK_EQ val
440         {
441             $$ = EXPR_complex( $1, OP_EQ, $3 );
442         }
443   | column_val TK_GT val
444         {
445             $$ = EXPR_complex( $1, OP_GT, $3 );
446         }
447   | column_val TK_LT val
448         {
449             $$ = EXPR_complex( $1, OP_LT, $3 );
450         }
451   | column_val TK_LE val
452         {
453             $$ = EXPR_complex( $1, OP_LE, $3 );
454         }
455   | column_val TK_GE val
456         {
457             $$ = EXPR_complex( $1, OP_GE, $3 );
458         }
459   | column_val TK_NE val
460         {
461             $$ = EXPR_complex( $1, OP_NE, $3 );
462         }
463   | column_val TK_IS TK_NULL
464         {
465             $$ = EXPR_complex( $1, OP_ISNULL, NULL );
466         }
467   | column_val TK_IS TK_NOT TK_NULL
468         {
469             $$ = EXPR_complex( $1, OP_NOTNULL, NULL );
470         }
471     ;
472
473 val:
474     column_val
475   | const_val
476     ;
477
478 constlist:
479     const_val
480         {
481             value_list *vals;
482
483             vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
484             if( vals )
485             {
486                 vals->val = $1;
487                 vals->next = NULL;
488             }
489             $$ = vals;
490         }
491   | constlist TK_COMMA const_val
492         {
493             value_list *vals;
494
495             vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
496             if( vals )
497             {
498                 vals->val = $3;
499                 vals->next = NULL;
500             }
501             $1->next = vals;
502             $$ = $1;
503         }
504     ;
505
506 update_assign_list:
507     column_assignment
508   | column_assignment TK_COMMA update_assign_list
509         {
510             $1.col_list->next = $3.col_list;
511             $1.val_list->next = $3.val_list;
512             $$ = $1;
513         }
514     ;
515
516 column_assignment:
517     column TK_EQ const_val
518         {
519             $$.col_list = HeapAlloc( GetProcessHeap(), 0, sizeof *$$.col_list );
520             if( !$$.col_list )
521                 YYABORT;
522             $$.col_list->string = $1;
523             $$.col_list->next = NULL;
524             $$.val_list = HeapAlloc( GetProcessHeap(), 0, sizeof *$$.val_list );
525             if( !$$.val_list )
526                 YYABORT;
527             $$.val_list->val = $3;
528             $$.val_list->next = 0;
529         }
530     ;
531
532 const_val:
533     TK_INTEGER
534         {
535             $$ = EXPR_ival( &$1 );
536         }
537   | TK_STRING
538         {
539             $$ = EXPR_sval( &$1 );
540         }
541   | TK_WILDCARD
542         {
543             $$ = EXPR_wildcard();
544         }
545     ;
546
547 column_val:
548     column 
549         {
550             $$ = EXPR_column( $1 );
551         }
552     ;
553
554 column:
555     table TK_DOT string_or_id
556         {
557             $$ = $3;  /* FIXME */
558         }
559   | string_or_id
560         {
561             $$ = $1;
562         }
563     ;
564
565 table:
566     string_or_id
567         {
568             $$ = $1;
569         }
570     ;
571
572 string_or_id:
573     TK_ID
574         {
575             $$ = SQL_getstring( &$1 );
576         }
577   | TK_STRING
578         {
579             $$ = SQL_getstring( &$1 );
580         }
581     ;
582
583 %%
584
585 int SQL_lex( void *SQL_lval, SQL_input *sql)
586 {
587     int token;
588     struct sql_str * str = SQL_lval;
589
590     do
591     {
592         sql->n += sql->len;
593         if( ! sql->command[sql->n] )
594             return 0;  /* end of input */
595
596         TRACE("string : %s\n", debugstr_w(&sql->command[sql->n]));
597         sql->len = sqliteGetToken( &sql->command[sql->n], &token );
598         if( sql->len==0 )
599             break;
600         str->data = &sql->command[sql->n];
601         str->len = sql->len;
602     }
603     while( token == TK_SPACE );
604
605     TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len));
606     
607     return token;
608 }
609
610 LPWSTR SQL_getstring( struct sql_str *strdata)
611 {
612     LPCWSTR p = strdata->data;
613     UINT len = strdata->len;
614     LPWSTR str;
615
616     /* if there's quotes, remove them */
617     if( ( (p[0]=='`') && (p[len-1]=='`') ) || 
618         ( (p[0]=='\'') && (p[len-1]=='\'') ) )
619     {
620         p++;
621         len -= 2;
622     }
623     str = HeapAlloc( GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
624     if(!str )
625         return str;
626     memcpy(str, p, len*sizeof(WCHAR) );
627     str[len]=0;
628
629     return str;
630 }
631
632 INT SQL_getint( SQL_input *sql )
633 {
634     LPCWSTR p = &sql->command[sql->n];
635
636     return atoiW( p );
637 }
638
639 int SQL_error(const char *str)
640 {
641     return 0;
642 }
643
644 static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in, 
645                                string_list *columns )
646 {
647     MSIVIEW *view = NULL;
648
649     SELECT_CreateView( db, &view, in, columns );
650     delete_string_list( columns );
651     if( !view )
652         ERR("Error creating select query\n");
653     return view;
654 }
655
656 static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in, 
657                              string_list *columns )
658 {
659     MSIVIEW *view = NULL;
660
661     ORDER_CreateView( db, &view, in );
662     if( view )
663     {
664         string_list *x = columns;
665
666         for( x = columns; x ; x = x->next )
667             ORDER_AddColumn( view, x->string );
668     }
669     else
670         ERR("Error creating select query\n");
671     delete_string_list( columns );
672     return view;
673 }
674
675 static struct expr * EXPR_wildcard()
676 {
677     struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
678     if( e )
679     {
680         e->type = EXPR_WILDCARD;
681     }
682     return e;
683 }
684
685 static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r )
686 {
687     struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
688     if( e )
689     {
690         e->type = EXPR_COMPLEX;
691         e->u.expr.left = l;
692         e->u.expr.op = op;
693         e->u.expr.right = r;
694     }
695     return e;
696 }
697
698 static struct expr * EXPR_column( LPWSTR str )
699 {
700     struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
701     if( e )
702     {
703         e->type = EXPR_COLUMN;
704         e->u.sval = str;
705     }
706     return e;
707 }
708
709 static struct expr * EXPR_ival( struct sql_str *str )
710 {
711     struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
712     if( e )
713     {
714         e->type = EXPR_IVAL;
715         e->u.ival = atoiW( str->data );
716     }
717     return e;
718 }
719
720 static struct expr * EXPR_sval( struct sql_str *str )
721 {
722     struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
723     if( e )
724     {
725         e->type = EXPR_SVAL;
726         e->u.sval = SQL_getstring( str );
727     }
728     return e;
729 }
730
731 void delete_expr( struct expr *e )
732 {
733     if( !e )
734         return;
735     if( e->type == EXPR_COMPLEX )
736     {
737         delete_expr( e->u.expr.left );
738         delete_expr( e->u.expr.right );
739     }
740     else if( e->type == EXPR_UTF8 )
741         HeapFree( GetProcessHeap(), 0, e->u.utf8 );
742     else if( e->type == EXPR_SVAL )
743         HeapFree( GetProcessHeap(), 0, e->u.sval );
744     HeapFree( GetProcessHeap(), 0, e );
745 }
746
747 void delete_string_list( string_list *sl )
748 {
749     while( sl )
750     {
751         string_list *t = sl->next;
752         HeapFree( GetProcessHeap(), 0, sl->string );
753         HeapFree( GetProcessHeap(), 0, sl );
754         sl = t;
755     }
756 }
757
758 void delete_value_list( value_list *vl )
759 {
760     while( vl )
761     {
762         value_list *t = vl->next;
763         delete_expr( vl->val );
764         HeapFree( GetProcessHeap(), 0, vl );
765         vl = t;
766     }
767 }
768
769 static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,
770                                  string_list *keys )
771 {
772     string_list *k;
773     BOOL found = TRUE;
774
775     for( k = keys; k && found; k = k->next )
776     {
777         create_col_info *c;
778
779         found = FALSE;
780         for( c = cols; c && !found; c = c->next )
781         {
782              if( lstrcmpW( k->string, c->colname ) )
783                  continue;
784              c->type |= MSITYPE_KEY;
785              found = TRUE;
786         }
787     }
788
789     return found;
790 }
791
792 UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview )
793 {
794     SQL_input sql;
795     int r;
796
797     *phview = NULL;
798
799     sql.db = db;
800     sql.command = command;
801     sql.n = 0;
802     sql.len = 0;
803     sql.view = phview;
804
805     r = SQL_parse(&sql);
806
807     TRACE("Parse returned %d\n", r);
808     if( r )
809     {
810         if( *sql.view )
811             (*sql.view)->ops->delete( *sql.view );
812         *sql.view = NULL;
813         return ERROR_BAD_QUERY_SYNTAX;
814     }
815
816     return ERROR_SUCCESS;
817 }