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