4 * Implementation of the Microsoft Installer (msi.dll)
6 * Copyright 2002-2004 Mike McCormack for CodeWeavers
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.
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.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 #include "wine/debug.h"
34 #include "wine/unicode.h"
36 #define YYLEX_PARAM info
37 #define YYPARSE_PARAM info
39 extern int SQL_error(const char *str);
41 WINE_DEFAULT_DEBUG_CHANNEL(msi);
43 typedef struct tag_SQL_input
48 MSIVIEW **view; /* view structure for the resulting query */
51 static LPWSTR SQL_getstring( SQL_input *info );
52 static INT SQL_getint( SQL_input *sql );
53 static int SQL_lex( void *SQL_lval, SQL_input *info);
55 static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in,
56 string_list *columns );
57 static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in,
58 string_list *columns );
60 static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,
63 static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r );
64 static struct expr * EXPR_column( LPWSTR column );
65 static struct expr * EXPR_ival( INT ival );
66 static struct expr * EXPR_sval( LPWSTR string );
75 string_list *column_list;
80 create_col_info *column_info;
83 %token TK_ABORT TK_AFTER TK_AGG_FUNCTION TK_ALL TK_AND TK_AS TK_ASC
84 %token TK_BEFORE TK_BEGIN TK_BETWEEN TK_BITAND TK_BITNOT TK_BITOR TK_BY
85 %token TK_CASCADE TK_CASE TK_CHAR TK_CHECK TK_CLUSTER TK_COLLATE TK_COLUMN
86 %token TK_COMMA TK_COMMENT TK_COMMIT TK_CONCAT TK_CONFLICT
87 %token TK_CONSTRAINT TK_COPY TK_CREATE
88 %token TK_DEFAULT TK_DEFERRABLE TK_DEFERRED TK_DELETE TK_DELIMITERS TK_DESC
89 %token TK_DISTINCT TK_DOT TK_DROP TK_EACH
90 %token TK_ELSE TK_END TK_END_OF_FILE TK_EQ TK_EXCEPT TK_EXPLAIN
91 %token TK_FAIL TK_FLOAT TK_FOR TK_FOREIGN TK_FROM TK_FUNCTION
92 %token TK_GE TK_GLOB TK_GROUP TK_GT
93 %token TK_HAVING TK_HOLD
94 %token TK_IGNORE TK_ILLEGAL TK_IMMEDIATE TK_IN TK_INDEX TK_INITIALLY
96 %token TK_INSERT TK_INSTEAD TK_INT TK_INTEGER TK_INTERSECT TK_INTO TK_IS
98 %token TK_JOIN TK_JOIN_KW
100 %token TK_LE TK_LIKE TK_LIMIT TK_LONG TK_LONGCHAR TK_LP TK_LSHIFT TK_LT
101 %token TK_LOCALIZABLE
102 %token TK_MATCH TK_MINUS
103 %token TK_NE TK_NOT TK_NOTNULL TK_NULL
104 %token TK_OBJECT TK_OF TK_OFFSET TK_ON TK_OR TK_ORACLE_OUTER_JOIN TK_ORDER
105 %token TK_PLUS TK_PRAGMA TK_PRIMARY
106 %token TK_RAISE TK_REFERENCES TK_REM TK_REPLACE TK_RESTRICT TK_ROLLBACK
107 %token TK_ROW TK_RP TK_RSHIFT
108 %token TK_SELECT TK_SEMI TK_SET TK_SHORT TK_SLASH TK_SPACE TK_STAR TK_STATEMENT
109 %token <string> TK_STRING
110 %token TK_TABLE TK_TEMP TK_THEN TK_TRANSACTION TK_TRIGGER
111 %token TK_UMINUS TK_UNCLOSED_STRING TK_UNION TK_UNIQUE
112 %token TK_UPDATE TK_UPLUS TK_USING
113 %token TK_VACUUM TK_VALUES TK_VIEW
114 %token TK_WHEN TK_WHERE
117 * These are extra tokens used by the lexer but never seen by the
118 * parser. We put them in a rule so that the parser generator will
119 * add them to the parse.h output file.
122 %nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
125 %type <string> column table string_or_id
126 %type <column_list> selcollist
127 %type <query> from unorderedsel oneselect onequery onecreate oneinsert
128 %type <expr> expr val column_val const_val
129 %type <column_type> column_type data_type data_type_l data_count
130 %type <column_info> column_def table_def
131 %type <val_list> constlist
138 SQL_input* sql = (SQL_input*) info;
143 SQL_input* sql = (SQL_input*) info;
148 SQL_input* sql = (SQL_input*) info;
154 TK_INSERT TK_INTO table selcollist TK_VALUES constlist
156 SQL_input *sql = (SQL_input*) info;
157 MSIVIEW *insert = NULL;
159 INSERT_CreateView( sql->db, &insert, $3, $4, $6, FALSE );
162 | TK_INSERT TK_INTO table selcollist TK_VALUES constlist TK_TEMP
164 SQL_input *sql = (SQL_input*) info;
165 MSIVIEW *insert = NULL;
167 INSERT_CreateView( sql->db, &insert, $3, $4, $6, TRUE );
173 TK_CREATE TK_TABLE table TK_LP table_def TK_RP
175 SQL_input* sql = (SQL_input*) info;
180 CREATE_CreateView( sql->db, &create, $3, $5, FALSE );
183 | TK_CREATE TK_TABLE table TK_LP table_def TK_RP TK_HOLD
185 SQL_input* sql = (SQL_input*) info;
190 CREATE_CreateView( sql->db, &create, $3, $5, TRUE );
196 column_def TK_PRIMARY TK_KEY selcollist
198 if( SQL_MarkPrimaryKeys( $1, $4 ) )
206 column_def TK_COMMA column column_type
210 for( ci = $1; ci->next; ci = ci->next )
213 ci->next = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ );
216 ci->next->colname = $3;
218 ci->next->next = NULL;
222 HeapFree( GetProcessHeap(), 0, $1 );
229 $$ = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ );
244 | data_type_l TK_LOCALIZABLE
246 FIXME("LOCALIZABLE ignored\n");
254 $$ |= MSITYPE_NULLABLE;
256 | data_type TK_NOT TK_NULL
265 $$ = MSITYPE_STRING | 1;
267 | TK_CHAR TK_LP data_count TK_RP
269 $$ = MSITYPE_STRING | $3;
296 SQL_input* sql = (SQL_input*) info;
297 int val = SQL_getint(sql);
298 if( ( val > 255 ) || ( val < 0 ) )
305 unorderedsel TK_ORDER TK_BY selcollist
307 SQL_input* sql = (SQL_input*) info;
312 $$ = do_order_by( sql->db, $1, $4 );
320 TK_SELECT selcollist from
322 SQL_input* sql = (SQL_input*) info;
326 $$ = do_one_select( sql->db, $3, $2 );
330 | TK_SELECT TK_DISTINCT selcollist from
332 SQL_input* sql = (SQL_input*) info;
338 view = do_one_select( sql->db, view, $3 );
339 DISTINCT_CreateView( sql->db, & $$, view );
348 list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
355 TRACE("Collist %s\n",debugstr_w($$->string));
357 | column TK_COMMA selcollist
361 list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
368 TRACE("From table: %s\n",debugstr_w($$->string));
379 SQL_input* sql = (SQL_input*) info;
382 TRACE("From table: %s\n",debugstr_w($2));
383 TABLE_CreateView( sql->db, $2, & $$ );
385 | TK_FROM table TK_WHERE expr
387 SQL_input* sql = (SQL_input*) info;
388 MSIVIEW *view = NULL;
392 TRACE("From table: %s\n",debugstr_w($2));
393 r = TABLE_CreateView( sql->db, $2, &view );
394 if( r != ERROR_SUCCESS )
396 r = WHERE_CreateView( sql->db, &view, view );
397 if( r != ERROR_SUCCESS )
399 r = WHERE_AddCondition( view, $4 );
400 if( r != ERROR_SUCCESS )
411 | column_val TK_EQ column_val
413 $$ = EXPR_complex( $1, OP_EQ, $3 );
417 $$ = EXPR_complex( $1, OP_AND, $3 );
421 $$ = EXPR_complex( $1, OP_OR, $3 );
423 | column_val TK_EQ val
425 $$ = EXPR_complex( $1, OP_EQ, $3 );
427 | column_val TK_GT val
429 $$ = EXPR_complex( $1, OP_GT, $3 );
431 | column_val TK_LT val
433 $$ = EXPR_complex( $1, OP_LT, $3 );
435 | column_val TK_LE val
437 $$ = EXPR_complex( $1, OP_LE, $3 );
439 | column_val TK_GE val
441 $$ = EXPR_complex( $1, OP_GE, $3 );
443 | column_val TK_NE val
445 $$ = EXPR_complex( $1, OP_NE, $3 );
447 | column_val TK_IS TK_NULL
449 $$ = EXPR_complex( $1, OP_ISNULL, NULL );
451 | column_val TK_IS TK_NOT TK_NULL
453 $$ = EXPR_complex( $1, OP_NOTNULL, NULL );
467 vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
475 | constlist TK_COMMA const_val
479 vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
493 SQL_input* sql = (SQL_input*) info;
494 $$ = EXPR_ival( SQL_getint(sql) );
498 $$ = EXPR_sval( $1 );
505 $$ = EXPR_column( $1 );
510 table TK_DOT string_or_id
530 SQL_input* sql = (SQL_input*) info;
531 $$ = SQL_getstring(sql);
535 SQL_input* sql = (SQL_input*) info;
536 $$ = SQL_getstring(sql);
542 int SQL_lex( void *SQL_lval, SQL_input *sql)
549 if( ! sql->command[sql->n] )
550 return 0; /* end of input */
552 TRACE("string : %s\n", debugstr_w(&sql->command[sql->n]));
553 sql->len = sqliteGetToken( &sql->command[sql->n], &token );
557 while( token == TK_SPACE );
559 TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len));
564 LPWSTR SQL_getstring( SQL_input *sql )
566 LPCWSTR p = &sql->command[sql->n];
570 /* if there's quotes, remove them */
571 if( (p[0]=='`') && (p[len-1]=='`') )
576 str = HeapAlloc( GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
579 memcpy(str, p, len*sizeof(WCHAR) );
585 INT SQL_getint( SQL_input *sql )
587 LPCWSTR p = &sql->command[sql->n];
592 int SQL_error(const char *str)
597 static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in,
598 string_list *columns )
600 MSIVIEW *view = NULL;
602 SELECT_CreateView( db, &view, in );
605 string_list *x = columns;
609 string_list *t = x->next;
610 SELECT_AddColumn( view, x->string );
611 HeapFree( GetProcessHeap(), 0, x->string );
612 HeapFree( GetProcessHeap(), 0, x );
617 ERR("Error creating select query\n");
621 static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in,
622 string_list *columns )
624 MSIVIEW *view = NULL;
626 ORDER_CreateView( db, &view, in );
629 string_list *x = columns;
631 for( x = columns; x ; x = x->next )
632 ORDER_AddColumn( view, x->string );
635 ERR("Error creating select query\n");
636 delete_string_list( columns );
640 static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r )
642 struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
645 e->type = EXPR_COMPLEX;
653 static struct expr * EXPR_column( LPWSTR column )
655 struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
658 e->type = EXPR_COLUMN;
659 e->u.column = column;
664 static struct expr * EXPR_ival( INT ival )
666 struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
675 static struct expr * EXPR_sval( LPWSTR string )
677 struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
686 void delete_expr( struct expr *e )
690 if( e->type == EXPR_COMPLEX )
692 delete_expr( e->u.expr.left );
693 delete_expr( e->u.expr.right );
695 HeapFree( GetProcessHeap(), 0, e );
698 void delete_string_list( string_list *sl )
702 string_list *t = sl->next;
703 HeapFree( GetProcessHeap(), 0, sl->string );
704 HeapFree( GetProcessHeap(), 0, sl );
709 void delete_value_list( value_list *vl )
713 value_list *t = vl->next;
714 delete_expr( vl->val );
715 HeapFree( GetProcessHeap(), 0, vl );
720 static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,
726 for( k = keys; k && found; k = k->next )
731 for( c = cols; c && !found; c = c->next )
733 if( lstrcmpW( k->string, c->colname ) )
735 c->type |= MSITYPE_KEY;
743 UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview )
751 sql.command = command;
758 TRACE("Parse returned %d\n", r);
762 (*sql.view)->ops->delete( *sql.view );
763 return ERROR_BAD_QUERY_SYNTAX;
766 return ERROR_SUCCESS;