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