msi/tests: Don't check more bytes than written to the file.
[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 #include "wine/unicode.h"
36
37 #define YYLEX_PARAM info
38 #define YYPARSE_PARAM info
39
40 static int sql_error(const char *str);
41
42 WINE_DEFAULT_DEBUG_CHANNEL(msi);
43
44 typedef struct tag_SQL_input
45 {
46     MSIDATABASE *db;
47     LPCWSTR command;
48     DWORD n, len;
49     UINT r;
50     MSIVIEW **view;  /* view structure for the resulting query */
51     struct list *mem;
52 } SQL_input;
53
54 static UINT SQL_getstring( void *info, const struct sql_str *strdata, LPWSTR *str );
55 static INT SQL_getint( void *info );
56 static int sql_lex( void *SQL_lval, SQL_input *info );
57
58 static LPWSTR parser_add_table( void *info, LPCWSTR list, LPCWSTR table );
59 static void *parser_alloc( void *info, unsigned int sz );
60 static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR column );
61
62 static BOOL SQL_MarkPrimaryKeys( column_info **cols, column_info *keys);
63
64 static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r );
65 static struct expr * EXPR_unary( void *info, struct expr *l, UINT op );
66 static struct expr * EXPR_column( void *info, const column_info *column );
67 static struct expr * EXPR_ival( void *info, int val );
68 static struct expr * EXPR_sval( void *info, const struct sql_str *str );
69 static struct expr * EXPR_wildcard( void *info );
70
71 %}
72
73 %pure-parser
74
75 %union
76 {
77     struct sql_str str;
78     LPWSTR string;
79     column_info *column_list;
80     MSIVIEW *query;
81     struct expr *expr;
82     USHORT column_type;
83     int integer;
84 }
85
86 %token TK_ALTER TK_AND TK_BY TK_CHAR TK_COMMA TK_CREATE TK_DELETE TK_DROP
87 %token TK_DISTINCT TK_DOT TK_EQ TK_FREE TK_FROM TK_GE TK_GT TK_HOLD TK_ADD
88 %token <str> TK_ID
89 %token TK_ILLEGAL TK_INSERT TK_INT
90 %token <str> TK_INTEGER
91 %token TK_INTO TK_IS TK_KEY TK_LE TK_LONG TK_LONGCHAR TK_LP TK_LT
92 %token TK_LOCALIZABLE TK_MINUS TK_NE TK_NOT TK_NULL
93 %token TK_OBJECT TK_OR TK_ORDER TK_PRIMARY TK_RP
94 %token TK_SELECT TK_SET TK_SHORT TK_SPACE TK_STAR
95 %token <str> TK_STRING
96 %token TK_TABLE TK_TEMPORARY TK_UPDATE TK_VALUES TK_WHERE TK_WILDCARD
97
98 /*
99  * These are extra tokens used by the lexer but never seen by the
100  * parser.  We put them in a rule so that the parser generator will
101  * add them to the parse.h output file.
102  *
103  */
104 %nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
105           COLUMN AGG_FUNCTION.
106
107 %type <string> table tablelist id
108 %type <column_list> selcollist column column_and_type column_def table_def
109 %type <column_list> column_assignment update_assign_list constlist
110 %type <query> query from fromtable selectfrom unorderedsel
111 %type <query> oneupdate onedelete oneselect onequery onecreate oneinsert onealter onedrop
112 %type <expr> expr val column_val const_val
113 %type <column_type> column_type data_type data_type_l data_count
114 %type <integer> number alterop
115
116 /* Reference: http://mates.ms.mff.cuni.cz/oracle/doc/ora815nt/server.815/a67779/operator.htm */
117 %left TK_OR
118 %left TK_AND
119 %left TK_NOT
120 %left TK_EQ TK_NE TK_LT TK_GT TK_LE TK_GE TK_LIKE
121 %right TK_NEGATION
122
123 %%
124
125 query:
126     onequery
127     {
128         SQL_input* sql = (SQL_input*) info;
129         *sql->view = $1;
130     }
131     ;
132
133 onequery:
134     oneselect
135   | onecreate
136   | oneinsert
137   | oneupdate
138   | onedelete
139   | onealter
140   | onedrop
141     ;
142
143 oneinsert:
144     TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP
145         {
146             SQL_input *sql = (SQL_input*) info;
147             MSIVIEW *insert = NULL;
148
149             INSERT_CreateView( sql->db, &insert, $3, $5, $9, FALSE );
150             if( !insert )
151                 YYABORT;
152             $$ = insert;
153         }
154   | TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP TK_TEMPORARY
155         {
156             SQL_input *sql = (SQL_input*) info;
157             MSIVIEW *insert = NULL;
158
159             INSERT_CreateView( sql->db, &insert, $3, $5, $9, TRUE );
160             if( !insert )
161                 YYABORT;
162             $$ = insert;
163         }
164     ;
165
166 onecreate:
167     TK_CREATE TK_TABLE table TK_LP table_def TK_RP
168         {
169             SQL_input* sql = (SQL_input*) info;
170             MSIVIEW *create = NULL;
171             UINT r;
172
173             if( !$5 )
174                 YYABORT;
175             r = CREATE_CreateView( sql->db, &create, $3, $5, FALSE );
176             if( !create )
177             {
178                 sql->r = r;
179                 YYABORT;
180             }
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 = NULL;
187
188             if( !$5 )
189                 YYABORT;
190             CREATE_CreateView( sql->db, &create, $3, $5, TRUE );
191             if( !create )
192                 YYABORT;
193             $$ = create;
194         }
195     ;
196
197 oneupdate:
198     TK_UPDATE table TK_SET update_assign_list TK_WHERE expr
199         {
200             SQL_input* sql = (SQL_input*) info;
201             MSIVIEW *update = NULL;
202
203             UPDATE_CreateView( sql->db, &update, $2, $4, $6 );
204             if( !update )
205                 YYABORT;
206             $$ = update;
207         }
208   | TK_UPDATE table TK_SET update_assign_list
209         {
210             SQL_input* sql = (SQL_input*) info;
211             MSIVIEW *update = NULL;
212
213             UPDATE_CreateView( sql->db, &update, $2, $4, NULL );
214             if( !update )
215                 YYABORT;
216             $$ = update;
217         }
218     ;
219
220 onedelete:
221     TK_DELETE from
222         {
223             SQL_input* sql = (SQL_input*) info;
224             MSIVIEW *delete = NULL;
225
226             DELETE_CreateView( sql->db, &delete, $2 );
227             if( !delete )
228                 YYABORT;
229             $$ = delete;
230         }
231     ;
232
233 onealter:
234     TK_ALTER TK_TABLE table alterop
235         {
236             SQL_input* sql = (SQL_input*) info;
237             MSIVIEW *alter = NULL;
238
239             ALTER_CreateView( sql->db, &alter, $3, NULL, $4 );
240             if( !alter )
241                 YYABORT;
242             $$ = alter;
243         }
244   | TK_ALTER TK_TABLE table TK_ADD column_and_type
245         {
246             SQL_input *sql = (SQL_input *)info;
247             MSIVIEW *alter = NULL;
248
249             ALTER_CreateView( sql->db, &alter, $3, $5, 0 );
250             if (!alter)
251                 YYABORT;
252             $$ = alter;
253         }
254   | TK_ALTER TK_TABLE table TK_ADD column_and_type TK_HOLD
255         {
256             SQL_input *sql = (SQL_input *)info;
257             MSIVIEW *alter = NULL;
258
259             ALTER_CreateView( sql->db, &alter, $3, $5, 1 );
260             if (!alter)
261                 YYABORT;
262             $$ = alter;
263         }
264     ;
265
266 alterop:
267     TK_HOLD
268         {
269             $$ = 1;
270         }
271   | TK_FREE
272         {
273             $$ = -1;
274         }
275   ;
276
277 onedrop:
278     TK_DROP TK_TABLE table
279         {
280             SQL_input* sql = (SQL_input*) info;
281             UINT r;
282
283             $$ = NULL;
284             r = DROP_CreateView( sql->db, &$$, $3 );
285             if( r != ERROR_SUCCESS || !$$ )
286                 YYABORT;
287         }
288   ;
289
290 table_def:
291     column_def TK_PRIMARY TK_KEY selcollist
292         {
293             if( SQL_MarkPrimaryKeys( &$1, $4 ) )
294                 $$ = $1;
295             else
296                 $$ = NULL;
297         }
298     ;
299
300 column_def:
301     column_def TK_COMMA column_and_type
302         {
303             column_info *ci;
304
305             for( ci = $1; ci->next; ci = ci->next )
306                 ;
307
308             ci->next = $3;
309             $$ = $1;
310         }
311   | column_and_type
312         {
313             $$ = $1;
314         }
315     ;
316
317 column_and_type:
318     column column_type
319         {
320             $$ = $1;
321             $$->type = ($2 | MSITYPE_VALID);
322             $$->temporary = $2 & MSITYPE_TEMPORARY ? TRUE : FALSE;
323         }
324     ;
325
326 column_type:
327     data_type_l
328         {
329             $$ = $1;
330         }
331   | data_type_l TK_LOCALIZABLE
332         {
333             $$ = $1 | MSITYPE_LOCALIZABLE;
334         }
335   | data_type_l TK_TEMPORARY
336         {
337             $$ = $1 | MSITYPE_TEMPORARY;
338         }
339     ;
340
341 data_type_l:
342     data_type
343         {
344             $$ |= MSITYPE_NULLABLE;
345         }
346   | data_type TK_NOT TK_NULL
347         {
348             $$ = $1;
349         }
350     ;
351
352 data_type:
353     TK_CHAR
354         {
355             $$ = MSITYPE_STRING | 1;
356         }
357   | TK_CHAR TK_LP data_count TK_RP
358         {
359             $$ = MSITYPE_STRING | 0x400 | $3;
360         }
361   | TK_LONGCHAR
362         {
363             $$ = MSITYPE_STRING | 0x400;
364         }
365   | TK_SHORT
366         {
367             $$ = 2 | 0x400;
368         }
369   | TK_INT
370         {
371             $$ = 2 | 0x400;
372         }
373   | TK_LONG
374         {
375             $$ = 4;
376         }
377   | TK_OBJECT
378         {
379             $$ = MSITYPE_STRING | MSITYPE_VALID;
380         }
381     ;
382
383 data_count:
384     number
385         {
386             if( ( $1 > 255 ) || ( $1 < 0 ) )
387                 YYABORT;
388             $$ = $1;
389         }
390     ;
391
392 oneselect:
393     unorderedsel TK_ORDER TK_BY selcollist
394         {
395             UINT r;
396
397             if( $4 )
398             {
399                 r = $1->ops->sort( $1, $4 );
400                 if ( r != ERROR_SUCCESS)
401                     YYABORT;
402             }
403
404             $$ = $1;
405         }
406   | unorderedsel
407     ;
408
409 unorderedsel:
410     TK_SELECT selectfrom
411         {
412             $$ = $2;
413         }
414   | TK_SELECT TK_DISTINCT selectfrom
415         {
416             SQL_input* sql = (SQL_input*) info;
417             UINT r;
418
419             $$ = NULL;
420             r = DISTINCT_CreateView( sql->db, &$$, $3 );
421             if (r != ERROR_SUCCESS)
422             {
423                 $3->ops->delete($3);
424                 YYABORT;
425             }
426         }
427     ;
428
429 selectfrom:
430     selcollist from
431         {
432             SQL_input* sql = (SQL_input*) info;
433             UINT r;
434
435             $$ = NULL;
436             if( $1 )
437             {
438                 r = SELECT_CreateView( sql->db, &$$, $2, $1 );
439                 if (r != ERROR_SUCCESS)
440                 {
441                     $2->ops->delete($2);
442                     YYABORT;
443                 }
444             }
445             else
446                 $$ = $2;
447         }
448     ;
449
450 selcollist:
451     column
452   | column TK_COMMA selcollist
453         {
454             $1->next = $3;
455         }
456   | TK_STAR
457         {
458             $$ = NULL;
459         }
460     ;
461
462 from:
463     fromtable
464   | fromtable TK_WHERE expr
465         {
466             SQL_input* sql = (SQL_input*) info;
467             UINT r;
468
469             $$ = NULL;
470             r = WHERE_CreateView( sql->db, &$$, $1, $3 );
471             if( r != ERROR_SUCCESS )
472             {
473                 $1->ops->delete( $1 );
474                 YYABORT;
475             }
476         }
477     ;
478
479 fromtable:
480     TK_FROM table
481         {
482             SQL_input* sql = (SQL_input*) info;
483             UINT r;
484
485             $$ = NULL;
486             r = TABLE_CreateView( sql->db, $2, &$$ );
487             if( r != ERROR_SUCCESS || !$$ )
488                 YYABORT;
489         }
490   | TK_FROM tablelist
491         {
492             SQL_input* sql = (SQL_input*) info;
493             UINT r;
494
495             r = JOIN_CreateView( sql->db, &$$, $2 );
496             if( r != ERROR_SUCCESS )
497                 YYABORT;
498         }
499     ;
500
501 tablelist:
502     table
503         {
504             $$ = $1;
505         }
506   |
507     table TK_COMMA tablelist
508         {
509             $$ = parser_add_table( info, $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( void *info, LPCWSTR list, LPCWSTR table )
700 {
701     static const WCHAR space[] = {' ',0};
702     DWORD len = strlenW( list ) + strlenW( table ) + 2;
703     LPWSTR ret;
704
705     ret = parser_alloc( info, len * sizeof(WCHAR) );
706     if( ret )
707     {
708         strcpyW( ret, list );
709         strcatW( ret, space );
710         strcatW( ret, table );
711     }
712     return ret;
713 }
714
715 static void *parser_alloc( void *info, unsigned int sz )
716 {
717     SQL_input* sql = (SQL_input*) info;
718     struct list *mem;
719
720     mem = msi_alloc( sizeof (struct list) + sz );
721     list_add_tail( sql->mem, mem );
722     return &mem[1];
723 }
724
725 static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR column )
726 {
727     column_info *col;
728
729     col = parser_alloc( info, sizeof (*col) );
730     if( col )
731     {
732         col->table = table;
733         col->column = column;
734         col->val = NULL;
735         col->type = 0;
736         col->next = NULL;
737     }
738
739     return col;
740 }
741
742 static int sql_lex( void *SQL_lval, SQL_input *sql )
743 {
744     int token;
745     struct sql_str * str = SQL_lval;
746
747     do
748     {
749         sql->n += sql->len;
750         if( ! sql->command[sql->n] )
751             return 0;  /* end of input */
752
753         /* TRACE("string : %s\n", debugstr_w(&sql->command[sql->n])); */
754         sql->len = sqliteGetToken( &sql->command[sql->n], &token );
755         if( sql->len==0 )
756             break;
757         str->data = &sql->command[sql->n];
758         str->len = sql->len;
759     }
760     while( token == TK_SPACE );
761
762     /* TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len)); */
763
764     return token;
765 }
766
767 UINT SQL_getstring( void *info, const struct sql_str *strdata, LPWSTR *str )
768 {
769     LPCWSTR p = strdata->data;
770     UINT len = strdata->len;
771
772     /* match quotes */
773     if( ( (p[0]=='`') && (p[len-1]!='`') ) ||
774         ( (p[0]=='\'') && (p[len-1]!='\'') ) )
775         return ERROR_FUNCTION_FAILED;
776
777     /* if there's quotes, remove them */
778     if( ( (p[0]=='`') && (p[len-1]=='`') ) ||
779         ( (p[0]=='\'') && (p[len-1]=='\'') ) )
780     {
781         p++;
782         len -= 2;
783     }
784     *str = parser_alloc( info, (len + 1)*sizeof(WCHAR) );
785     if( !*str )
786         return ERROR_OUTOFMEMORY;
787     memcpy( *str, p, len*sizeof(WCHAR) );
788     (*str)[len]=0;
789
790     return ERROR_SUCCESS;
791 }
792
793 INT SQL_getint( void *info )
794 {
795     SQL_input* sql = (SQL_input*) info;
796     LPCWSTR p = &sql->command[sql->n];
797     INT i, r = 0;
798
799     for( i=0; i<sql->len; i++ )
800     {
801         if( '0' > p[i] || '9' < p[i] )
802         {
803             ERR("should only be numbers here!\n");
804             break;
805         }
806         r = (p[i]-'0') + r*10;
807     }
808
809     return r;
810 }
811
812 static int sql_error( const char *str )
813 {
814     return 0;
815 }
816
817 static struct expr * EXPR_wildcard( void *info )
818 {
819     struct expr *e = parser_alloc( info, sizeof *e );
820     if( e )
821     {
822         e->type = EXPR_WILDCARD;
823     }
824     return e;
825 }
826
827 static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r )
828 {
829     struct expr *e = parser_alloc( info, sizeof *e );
830     if( e )
831     {
832         e->type = EXPR_COMPLEX;
833         e->u.expr.left = l;
834         e->u.expr.op = op;
835         e->u.expr.right = r;
836     }
837     return e;
838 }
839
840 static struct expr * EXPR_unary( void *info, struct expr *l, UINT op )
841 {
842     struct expr *e = parser_alloc( info, sizeof *e );
843     if( e )
844     {
845         e->type = EXPR_UNARY;
846         e->u.expr.left = l;
847         e->u.expr.op = op;
848         e->u.expr.right = NULL;
849     }
850     return e;
851 }
852
853 static struct expr * EXPR_column( void *info, const column_info *column )
854 {
855     struct expr *e = parser_alloc( info, sizeof *e );
856     if( e )
857     {
858         e->type = EXPR_COLUMN;
859         e->u.column.column = column->column;
860         e->u.column.table = column->table;
861     }
862     return e;
863 }
864
865 static struct expr * EXPR_ival( void *info, int val )
866 {
867     struct expr *e = parser_alloc( info, sizeof *e );
868     if( e )
869     {
870         e->type = EXPR_IVAL;
871         e->u.ival = val;
872     }
873     return e;
874 }
875
876 static struct expr * EXPR_sval( void *info, const struct sql_str *str )
877 {
878     struct expr *e = parser_alloc( info, sizeof *e );
879     if( e )
880     {
881         e->type = EXPR_SVAL;
882         if( SQL_getstring( info, str, (LPWSTR *)&e->u.sval ) != ERROR_SUCCESS )
883             return NULL; /* e will be freed by query destructor */
884     }
885     return e;
886 }
887
888 static void swap_columns( column_info **cols, column_info *A, int idx )
889 {
890     column_info *preA = NULL, *preB = NULL, *B, *ptr;
891     int i = 0;
892
893     B = NULL;
894     ptr = *cols;
895     while( ptr )
896     {
897         if( i++ == idx )
898             B = ptr;
899         else if( !B )
900             preB = ptr;
901
902         if( ptr->next == A )
903             preA = ptr;
904
905         ptr = ptr->next;
906     }
907
908     if( preB ) preB->next = A;
909     if( preA ) preA->next = B;
910     ptr = A->next;
911     A->next = B->next;
912     B->next = ptr;
913     if( idx == 0 )
914       *cols = A;
915 }
916
917 static BOOL SQL_MarkPrimaryKeys( column_info **cols,
918                                  column_info *keys )
919 {
920     column_info *k;
921     BOOL found = TRUE;
922     int count;
923
924     for( k = keys, count = 0; k && found; k = k->next, count++ )
925     {
926         column_info *c;
927         int idx;
928
929         found = FALSE;
930         for( c = *cols, idx = 0; c && !found; c = c->next, idx++ )
931         {
932             if( lstrcmpW( k->column, c->column ) )
933                 continue;
934             c->type |= MSITYPE_KEY;
935             found = TRUE;
936             if (idx != count)
937                 swap_columns( cols, c, count );
938         }
939     }
940
941     return found;
942 }
943
944 UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview,
945                    struct list *mem )
946 {
947     SQL_input sql;
948     int r;
949
950     *phview = NULL;
951
952     sql.db = db;
953     sql.command = command;
954     sql.n = 0;
955     sql.len = 0;
956     sql.r = ERROR_BAD_QUERY_SYNTAX;
957     sql.view = phview;
958     sql.mem = mem;
959
960     r = sql_parse(&sql);
961
962     TRACE("Parse returned %d\n", r);
963     if( r )
964     {
965         if (*sql.view)
966         {
967             (*sql.view)->ops->delete(*sql.view);
968             *sql.view = NULL;
969         }
970         return sql.r;
971     }
972
973     return ERROR_SUCCESS;
974 }