msi: A non-temporary table cannot have a temporary primary key.
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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/list.h"
34 #include "wine/debug.h"
35
36 #define YYLEX_PARAM info
37 #define YYPARSE_PARAM info
38
39 static 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     UINT r;
49     MSIVIEW **view;  /* view structure for the resulting query */
50     struct list *mem;
51 } SQL_input;
52
53 static UINT SQL_getstring( void *info, const struct sql_str *strdata, LPWSTR *str );
54 static INT SQL_getint( void *info );
55 static int sql_lex( void *SQL_lval, SQL_input *info );
56
57 static LPWSTR parser_add_table( LPWSTR list, LPWSTR table );
58 static void *parser_alloc( void *info, unsigned int sz );
59 static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR column );
60
61 static BOOL SQL_MarkPrimaryKeys( column_info *cols, column_info *keys);
62
63 static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r );
64 static struct expr * EXPR_unary( void *info, struct expr *l, UINT op );
65 static struct expr * EXPR_column( void *info, const column_info *column );
66 static struct expr * EXPR_ival( void *info, int val );
67 static struct expr * EXPR_sval( void *info, const struct sql_str *str );
68 static struct expr * EXPR_wildcard( void *info );
69
70 %}
71
72 %pure-parser
73
74 %union
75 {
76     struct sql_str str;
77     LPWSTR string;
78     column_info *column_list;
79     MSIVIEW *query;
80     struct expr *expr;
81     USHORT column_type;
82     int integer;
83 }
84
85 %token TK_ALTER TK_AND TK_BY TK_CHAR TK_COMMA TK_CREATE TK_DELETE TK_DROP
86 %token TK_DISTINCT TK_DOT TK_EQ TK_FREE TK_FROM TK_GE TK_GT TK_HOLD TK_ADD
87 %token <str> TK_ID
88 %token TK_ILLEGAL TK_INSERT TK_INT
89 %token <str> TK_INTEGER
90 %token TK_INTO TK_IS TK_KEY TK_LE TK_LONG TK_LONGCHAR TK_LP TK_LT
91 %token TK_LOCALIZABLE TK_MINUS TK_NE TK_NOT TK_NULL
92 %token TK_OBJECT TK_OR TK_ORDER TK_PRIMARY TK_RP
93 %token TK_SELECT TK_SET TK_SHORT TK_SPACE TK_STAR
94 %token <str> TK_STRING
95 %token TK_TABLE TK_TEMPORARY TK_UPDATE TK_VALUES TK_WHERE TK_WILDCARD
96
97 /*
98  * These are extra tokens used by the lexer but never seen by the
99  * parser.  We put them in a rule so that the parser generator will
100  * add them to the parse.h output file.
101  *
102  */
103 %nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
104           COLUMN AGG_FUNCTION.
105
106 %type <string> table tablelist id
107 %type <column_list> selcollist column column_and_type column_def table_def
108 %type <column_list> column_assignment update_assign_list constlist
109 %type <query> query from fromtable selectfrom unorderedsel
110 %type <query> oneupdate onedelete oneselect onequery onecreate oneinsert onealter onedrop
111 %type <expr> expr val column_val const_val
112 %type <column_type> column_type data_type data_type_l data_count
113 %type <integer> number alterop
114
115 /* Reference: http://mates.ms.mff.cuni.cz/oracle/doc/ora815nt/server.815/a67779/operator.htm */
116 %left TK_OR
117 %left TK_AND
118 %left TK_NOT
119 %left TK_EQ TK_NE TK_LT TK_GT TK_LE TK_GE TK_LIKE
120 %right TK_NEGATION
121
122 %%
123
124 query:
125     onequery
126     {
127         SQL_input* sql = (SQL_input*) info;
128         *sql->view = $1;
129     }
130     ;
131
132 onequery:
133     oneselect
134   | onecreate
135   | oneinsert
136   | oneupdate
137   | onedelete
138   | onealter
139   | onedrop
140     ;
141
142 oneinsert:
143     TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP
144         {
145             SQL_input *sql = (SQL_input*) info;
146             MSIVIEW *insert = NULL;
147
148             INSERT_CreateView( sql->db, &insert, $3, $5, $9, FALSE );
149             if( !insert )
150                 YYABORT;
151             $$ = insert;
152         }
153   | TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP TK_TEMPORARY
154         {
155             SQL_input *sql = (SQL_input*) info;
156             MSIVIEW *insert = NULL;
157
158             INSERT_CreateView( sql->db, &insert, $3, $5, $9, TRUE );
159             if( !insert )
160                 YYABORT;
161             $$ = insert;
162         }
163     ;
164
165 onecreate:
166     TK_CREATE TK_TABLE table TK_LP table_def TK_RP
167         {
168             SQL_input* sql = (SQL_input*) info;
169             MSIVIEW *create = NULL;
170             UINT r;
171
172             if( !$5 )
173                 YYABORT;
174             r = CREATE_CreateView( sql->db, &create, $3, $5, FALSE );
175             if( !create )
176             {
177                 sql->r = r;
178                 YYABORT;
179             }
180             $$ = create;
181         }
182   | TK_CREATE TK_TABLE table TK_LP table_def TK_RP TK_HOLD
183         {
184             SQL_input* sql = (SQL_input*) info;
185             MSIVIEW *create = NULL;
186
187             if( !$5 )
188                 YYABORT;
189             CREATE_CreateView( sql->db, &create, $3, $5, TRUE );
190             if( !create )
191                 YYABORT;
192             $$ = create;
193         }
194     ;
195
196 oneupdate:
197     TK_UPDATE table TK_SET update_assign_list TK_WHERE expr
198         {
199             SQL_input* sql = (SQL_input*) info;
200             MSIVIEW *update = NULL;
201
202             UPDATE_CreateView( sql->db, &update, $2, $4, $6 );
203             if( !update )
204                 YYABORT;
205             $$ = update;
206         }
207   | TK_UPDATE table TK_SET update_assign_list
208         {
209             SQL_input* sql = (SQL_input*) info;
210             MSIVIEW *update = NULL;
211
212             UPDATE_CreateView( sql->db, &update, $2, $4, NULL );
213             if( !update )
214                 YYABORT;
215             $$ = update;
216         }
217     ;
218
219 onedelete:
220     TK_DELETE from
221         {
222             SQL_input* sql = (SQL_input*) info;
223             MSIVIEW *delete = NULL;
224
225             DELETE_CreateView( sql->db, &delete, $2 );
226             if( !delete )
227                 YYABORT;
228             $$ = delete;
229         }
230     ;
231
232 onealter:
233     TK_ALTER TK_TABLE table alterop
234         {
235             SQL_input* sql = (SQL_input*) info;
236             MSIVIEW *alter = NULL;
237
238             ALTER_CreateView( sql->db, &alter, $3, NULL, $4 );
239             if( !alter )
240                 YYABORT;
241             $$ = alter;
242         }
243   | TK_ALTER TK_TABLE table TK_ADD column_and_type
244         {
245             SQL_input *sql = (SQL_input *)info;
246             MSIVIEW *alter = NULL;
247
248             ALTER_CreateView( sql->db, &alter, $3, $5, 0 );
249             if (!alter)
250                 YYABORT;
251             $$ = alter;
252         }
253   | TK_ALTER TK_TABLE table TK_ADD column_and_type TK_HOLD
254         {
255             SQL_input *sql = (SQL_input *)info;
256             MSIVIEW *alter = NULL;
257
258             ALTER_CreateView( sql->db, &alter, $3, $5, 1 );
259             if (!alter)
260                 YYABORT;
261             $$ = alter;
262         }
263     ;
264
265 alterop:
266     TK_HOLD
267         {
268             $$ = 1;
269         }
270   | TK_FREE
271         {
272             $$ = -1;
273         }
274   ;
275
276 onedrop:
277     TK_DROP TK_TABLE table
278         {
279             SQL_input* sql = (SQL_input*) info;
280             UINT r;
281
282             $$ = NULL;
283             r = DROP_CreateView( sql->db, &$$, $3 );
284             if( r != ERROR_SUCCESS || !$$ )
285                 YYABORT;
286         }
287   ;
288
289 table_def:
290     column_def TK_PRIMARY TK_KEY selcollist
291         {
292             if( SQL_MarkPrimaryKeys( $1, $4 ) )
293                 $$ = $1;
294             else
295                 $$ = NULL;
296         }
297     ;
298
299 column_def:
300     column_def TK_COMMA column_and_type
301         {
302             column_info *ci;
303
304             for( ci = $1; ci->next; ci = ci->next )
305                 ;
306
307             ci->next = $3;
308             $$ = $1;
309         }
310   | column_and_type
311         {
312             $$ = $1;
313         }
314     ;
315
316 column_and_type:
317     column column_type
318         {
319             $$ = $1;
320             $$->type = ($2 | MSITYPE_VALID);
321             $$->temporary = $2 & MSITYPE_TEMPORARY ? TRUE : FALSE;
322         }
323     ;
324
325 column_type:
326     data_type_l
327         {
328             $$ = $1;
329         }
330   | data_type_l TK_LOCALIZABLE
331         {
332             $$ = $1 | MSITYPE_LOCALIZABLE;
333         }
334   | data_type_l TK_TEMPORARY
335         {
336             $$ = $1 | MSITYPE_TEMPORARY;
337         }
338     ;
339
340 data_type_l:
341     data_type
342         {
343             $$ |= MSITYPE_NULLABLE;
344         }
345   | data_type TK_NOT TK_NULL
346         {
347             $$ = $1;
348         }
349     ;
350
351 data_type:
352     TK_CHAR
353         {
354             $$ = MSITYPE_STRING | 1;
355         }
356   | TK_CHAR TK_LP data_count TK_RP
357         {
358             $$ = MSITYPE_STRING | 0x400 | $3;
359         }
360   | TK_LONGCHAR
361         {
362             $$ = 2;
363         }
364   | TK_SHORT
365         {
366             $$ = 2;
367         }
368   | TK_INT
369         {
370             $$ = 2;
371         }
372   | TK_LONG
373         {
374             $$ = 4;
375         }
376   | TK_OBJECT
377         {
378             $$ = MSITYPE_STRING | MSITYPE_VALID;
379         }
380     ;
381
382 data_count:
383     number
384         {
385             if( ( $1 > 255 ) || ( $1 < 0 ) )
386                 YYABORT;
387             $$ = $1;
388         }
389     ;
390
391 oneselect:
392     unorderedsel TK_ORDER TK_BY selcollist
393         {
394             UINT r;
395
396             if( $4 )
397             {
398                 r = $1->ops->sort( $1, $4 );
399                 if ( r != ERROR_SUCCESS)
400                     YYABORT;
401             }
402
403             $$ = $1;
404         }
405   | unorderedsel
406     ;
407
408 unorderedsel:
409     TK_SELECT selectfrom
410         {
411             $$ = $2;
412         }
413   | TK_SELECT TK_DISTINCT selectfrom
414         {
415             SQL_input* sql = (SQL_input*) info;
416             UINT r;
417
418             $$ = NULL;
419             r = DISTINCT_CreateView( sql->db, &$$, $3 );
420             if (r != ERROR_SUCCESS)
421             {
422                 $3->ops->delete($3);
423                 YYABORT;
424             }
425         }
426     ;
427
428 selectfrom:
429     selcollist from
430         {
431             SQL_input* sql = (SQL_input*) info;
432             UINT r;
433
434             $$ = NULL;
435             if( $1 )
436             {
437                 r = SELECT_CreateView( sql->db, &$$, $2, $1 );
438                 if (r != ERROR_SUCCESS)
439                 {
440                     $2->ops->delete($2);
441                     YYABORT;
442                 }
443             }
444             else
445                 $$ = $2;
446         }
447     ;
448
449 selcollist:
450     column
451   | column TK_COMMA selcollist
452         {
453             $1->next = $3;
454         }
455   | TK_STAR
456         {
457             $$ = NULL;
458         }
459     ;
460
461 from:
462     fromtable
463   | fromtable TK_WHERE expr
464         {
465             SQL_input* sql = (SQL_input*) info;
466             UINT r;
467
468             $$ = NULL;
469             r = WHERE_CreateView( sql->db, &$$, $1, $3 );
470             if( r != ERROR_SUCCESS )
471             {
472                 $1->ops->delete( $1 );
473                 YYABORT;
474             }
475         }
476     ;
477
478 fromtable:
479     TK_FROM table
480         {
481             SQL_input* sql = (SQL_input*) info;
482             UINT r;
483
484             $$ = NULL;
485             r = TABLE_CreateView( sql->db, $2, &$$ );
486             if( r != ERROR_SUCCESS || !$$ )
487                 YYABORT;
488         }
489   | TK_FROM tablelist
490         {
491             SQL_input* sql = (SQL_input*) info;
492             UINT r;
493
494             r = JOIN_CreateView( sql->db, &$$, $2 );
495             msi_free( $2 );
496             if( r != ERROR_SUCCESS )
497                 YYABORT;
498         }
499     ;
500
501 tablelist:
502     table
503         {
504             $$ = strdupW($1);
505         }
506   |
507     table TK_COMMA tablelist
508         {
509             $$ = parser_add_table($3, $1);
510             if (!$$)
511                 YYABORT;
512         }
513     ;
514
515 expr:
516     TK_LP expr TK_RP
517         {
518             $$ = $2;
519             if( !$$ )
520                 YYABORT;
521         }
522   | expr TK_AND expr
523         {
524             $$ = EXPR_complex( info, $1, OP_AND, $3 );
525             if( !$$ )
526                 YYABORT;
527         }
528   | expr TK_OR expr
529         {
530             $$ = EXPR_complex( info, $1, OP_OR, $3 );
531             if( !$$ )
532                 YYABORT;
533         }
534   | column_val TK_EQ val
535         {
536             $$ = EXPR_complex( info, $1, OP_EQ, $3 );
537             if( !$$ )
538                 YYABORT;
539         }
540   | column_val TK_GT val
541         {
542             $$ = EXPR_complex( info, $1, OP_GT, $3 );
543             if( !$$ )
544                 YYABORT;
545         }
546   | column_val TK_LT val
547         {
548             $$ = EXPR_complex( info, $1, OP_LT, $3 );
549             if( !$$ )
550                 YYABORT;
551         }
552   | column_val TK_LE val
553         {
554             $$ = EXPR_complex( info, $1, OP_LE, $3 );
555             if( !$$ )
556                 YYABORT;
557         }
558   | column_val TK_GE val
559         {
560             $$ = EXPR_complex( info, $1, OP_GE, $3 );
561             if( !$$ )
562                 YYABORT;
563         }
564   | column_val TK_NE val
565         {
566             $$ = EXPR_complex( info, $1, OP_NE, $3 );
567             if( !$$ )
568                 YYABORT;
569         }
570   | column_val TK_IS TK_NULL
571         {
572             $$ = EXPR_unary( info, $1, OP_ISNULL );
573             if( !$$ )
574                 YYABORT;
575         }
576   | column_val TK_IS TK_NOT TK_NULL
577         {
578             $$ = EXPR_unary( info, $1, OP_NOTNULL );
579             if( !$$ )
580                 YYABORT;
581         }
582     ;
583
584 val:
585     column_val
586   | const_val
587     ;
588
589 constlist:
590     const_val
591         {
592             $$ = parser_alloc_column( info, NULL, NULL );
593             if( !$$ )
594                 YYABORT;
595             $$->val = $1;
596         }
597   | const_val TK_COMMA constlist
598         {
599             $$ = parser_alloc_column( info, NULL, NULL );
600             if( !$$ )
601                 YYABORT;
602             $$->val = $1;
603             $$->next = $3;
604         }
605     ;
606
607 update_assign_list:
608     column_assignment
609   | column_assignment TK_COMMA update_assign_list
610         {
611             $$ = $1;
612             $$->next = $3;
613         }
614     ;
615
616 column_assignment:
617     column TK_EQ const_val
618         {
619             $$ = $1;
620             $$->val = $3;
621         }
622     ;
623
624 const_val:
625     number
626         {
627             $$ = EXPR_ival( info, $1 );
628             if( !$$ )
629                 YYABORT;
630         }
631   | TK_MINUS number %prec TK_NEGATION
632         {
633             $$ = EXPR_ival( info, -$2 );
634             if( !$$ )
635                 YYABORT;
636         }
637   | TK_STRING
638         {
639             $$ = EXPR_sval( info, &$1 );
640             if( !$$ )
641                 YYABORT;
642         }
643   | TK_WILDCARD
644         {
645             $$ = EXPR_wildcard( info );
646             if( !$$ )
647                 YYABORT;
648         }
649     ;
650
651 column_val:
652     column
653         {
654             $$ = EXPR_column( info, $1 );
655             if( !$$ )
656                 YYABORT;
657         }
658     ;
659
660 column:
661     table TK_DOT id
662         {
663             $$ = parser_alloc_column( info, $1, $3 );
664             if( !$$ )
665                 YYABORT;
666         }
667   | id
668         {
669             $$ = parser_alloc_column( info, NULL, $1 );
670             if( !$$ )
671                 YYABORT;
672         }
673     ;
674
675 table:
676     id
677         {
678             $$ = $1;
679         }
680     ;
681
682 id:
683     TK_ID
684         {
685             if ( SQL_getstring( info, &$1, &$$ ) != ERROR_SUCCESS || !$$ )
686                 YYABORT;
687         }
688     ;
689
690 number:
691     TK_INTEGER
692         {
693             $$ = SQL_getint( info );
694         }
695     ;
696
697 %%
698
699 static LPWSTR parser_add_table(LPWSTR list, LPWSTR table)
700 {
701     DWORD size = lstrlenW(list) + lstrlenW(table) + 2;
702     static const WCHAR space[] = {' ',0};
703
704     list = msi_realloc(list, size * sizeof(WCHAR));
705     if (!list) return NULL;
706
707     lstrcatW(list, space);
708     lstrcatW(list, table);
709     return list;
710 }
711
712 static void *parser_alloc( void *info, unsigned int sz )
713 {
714     SQL_input* sql = (SQL_input*) info;
715     struct list *mem;
716
717     mem = msi_alloc( sizeof (struct list) + sz );
718     list_add_tail( sql->mem, mem );
719     return &mem[1];
720 }
721
722 static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR column )
723 {
724     column_info *col;
725
726     col = parser_alloc( info, sizeof (*col) );
727     if( col )
728     {
729         col->table = table;
730         col->column = column;
731         col->val = NULL;
732         col->type = 0;
733         col->next = NULL;
734     }
735
736     return col;
737 }
738
739 static int sql_lex( void *SQL_lval, SQL_input *sql )
740 {
741     int token;
742     struct sql_str * str = SQL_lval;
743
744     do
745     {
746         sql->n += sql->len;
747         if( ! sql->command[sql->n] )
748             return 0;  /* end of input */
749
750         /* TRACE("string : %s\n", debugstr_w(&sql->command[sql->n])); */
751         sql->len = sqliteGetToken( &sql->command[sql->n], &token );
752         if( sql->len==0 )
753             break;
754         str->data = &sql->command[sql->n];
755         str->len = sql->len;
756     }
757     while( token == TK_SPACE );
758
759     /* TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len)); */
760
761     return token;
762 }
763
764 UINT SQL_getstring( void *info, const struct sql_str *strdata, LPWSTR *str )
765 {
766     LPCWSTR p = strdata->data;
767     UINT len = strdata->len;
768
769     /* match quotes */
770     if( ( (p[0]=='`') && (p[len-1]!='`') ) ||
771         ( (p[0]=='\'') && (p[len-1]!='\'') ) )
772         return ERROR_FUNCTION_FAILED;
773
774     /* if there's quotes, remove them */
775     if( ( (p[0]=='`') && (p[len-1]=='`') ) ||
776         ( (p[0]=='\'') && (p[len-1]=='\'') ) )
777     {
778         p++;
779         len -= 2;
780     }
781     *str = parser_alloc( info, (len + 1)*sizeof(WCHAR) );
782     if( !*str )
783         return ERROR_OUTOFMEMORY;
784     memcpy( *str, p, len*sizeof(WCHAR) );
785     (*str)[len]=0;
786
787     return ERROR_SUCCESS;
788 }
789
790 INT SQL_getint( void *info )
791 {
792     SQL_input* sql = (SQL_input*) info;
793     LPCWSTR p = &sql->command[sql->n];
794     INT i, r = 0;
795
796     for( i=0; i<sql->len; i++ )
797     {
798         if( '0' > p[i] || '9' < p[i] )
799         {
800             ERR("should only be numbers here!\n");
801             break;
802         }
803         r = (p[i]-'0') + r*10;
804     }
805
806     return r;
807 }
808
809 static int sql_error( const char *str )
810 {
811     return 0;
812 }
813
814 static struct expr * EXPR_wildcard( void *info )
815 {
816     struct expr *e = parser_alloc( info, sizeof *e );
817     if( e )
818     {
819         e->type = EXPR_WILDCARD;
820     }
821     return e;
822 }
823
824 static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r )
825 {
826     struct expr *e = parser_alloc( info, sizeof *e );
827     if( e )
828     {
829         e->type = EXPR_COMPLEX;
830         e->u.expr.left = l;
831         e->u.expr.op = op;
832         e->u.expr.right = r;
833     }
834     return e;
835 }
836
837 static struct expr * EXPR_unary( void *info, struct expr *l, UINT op )
838 {
839     struct expr *e = parser_alloc( info, sizeof *e );
840     if( e )
841     {
842         e->type = EXPR_UNARY;
843         e->u.expr.left = l;
844         e->u.expr.op = op;
845         e->u.expr.right = NULL;
846     }
847     return e;
848 }
849
850 static struct expr * EXPR_column( void *info, const column_info *column )
851 {
852     struct expr *e = parser_alloc( info, sizeof *e );
853     if( e )
854     {
855         e->type = EXPR_COLUMN;
856         e->u.sval = column->column;
857     }
858     return e;
859 }
860
861 static struct expr * EXPR_ival( void *info, int val )
862 {
863     struct expr *e = parser_alloc( info, sizeof *e );
864     if( e )
865     {
866         e->type = EXPR_IVAL;
867         e->u.ival = val;
868     }
869     return e;
870 }
871
872 static struct expr * EXPR_sval( void *info, const struct sql_str *str )
873 {
874     struct expr *e = parser_alloc( info, sizeof *e );
875     if( e )
876     {
877         e->type = EXPR_SVAL;
878         if( SQL_getstring( info, str, (LPWSTR *)&e->u.sval ) != ERROR_SUCCESS )
879         {
880             msi_free( e );
881             return NULL;
882         }
883     }
884     return e;
885 }
886
887 static BOOL SQL_MarkPrimaryKeys( column_info *cols,
888                                  column_info *keys )
889 {
890     column_info *k;
891     BOOL found = TRUE;
892
893     for( k = keys; k && found; k = k->next )
894     {
895         column_info *c;
896
897         found = FALSE;
898         for( c = cols; c && !found; c = c->next )
899         {
900              if( lstrcmpW( k->column, c->column ) )
901                  continue;
902              c->type |= MSITYPE_KEY;
903              found = TRUE;
904         }
905     }
906
907     return found;
908 }
909
910 UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview,
911                    struct list *mem )
912 {
913     SQL_input sql;
914     int r;
915
916     *phview = NULL;
917
918     sql.db = db;
919     sql.command = command;
920     sql.n = 0;
921     sql.len = 0;
922     sql.r = ERROR_BAD_QUERY_SYNTAX;
923     sql.view = phview;
924     sql.mem = mem;
925
926     r = sql_parse(&sql);
927
928     TRACE("Parse returned %d\n", r);
929     if( r )
930     {
931         *sql.view = NULL;
932         return sql.r;
933     }
934
935     return ERROR_SUCCESS;
936 }