diff --git a/dlls/msi/Makefile.in b/dlls/msi/Makefile.in index 845e6b91702..9cd096f8cbd 100644 --- a/dlls/msi/Makefile.in +++ b/dlls/msi/Makefile.in @@ -10,6 +10,7 @@ C_SRCS = \ create.c \ distinct.c \ handle.c \ + insert.c \ msi.c \ msiquery.c \ order.c \ diff --git a/dlls/msi/insert.c b/dlls/msi/insert.c new file mode 100644 index 00000000000..68369870e80 --- /dev/null +++ b/dlls/msi/insert.c @@ -0,0 +1,247 @@ +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2004 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wine/debug.h" +#include "msi.h" +#include "msiquery.h" +#include "objbase.h" +#include "objidl.h" +#include "msipriv.h" +#include "winnls.h" + +#include "query.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + + +/* below is the query interface to a table */ + +typedef struct tagMSIINSERTVIEW +{ + MSIVIEW view; + MSIDATABASE *db; + LPWSTR name; + BOOL bIsTemp; + string_list *cols; + value_list *vals; +} MSIINSERTVIEW; + +static UINT INSERT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) +{ + MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view; + + TRACE("%p %d %d %p\n", iv, row, col, val ); + + return ERROR_FUNCTION_FAILED; +} + +static UINT INSERT_execute( struct tagMSIVIEW *view, MSIHANDLE record ) +{ +#if 0 + MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view; + create_col_info *col; + UINT r, nField, row, table_val, column_val; + const WCHAR szTables[] = { '_','T','a','b','l','e','s',0 }; + const WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 }; + MSIVIEW *tv = NULL; + + TRACE("%p Table %s (%s)\n", iv, debugstr_w(iv->name), + iv->bIsTemp?"temporary":"permanent"); + + /* only add tables that don't exist already */ + if( TABLE_Exists(iv->db, iv->name ) ) + return ERROR_BAD_QUERY_SYNTAX; + + /* add the name to the _Tables table */ + table_val = msi_addstringW( iv->db->strings, 0, iv->name, -1, 1 ); + TRACE("New string %s -> %d\n", debugstr_w( iv->name ), table_val ); + if( table_val < 0 ) + return ERROR_FUNCTION_FAILED; + + r = TABLE_CreateView( iv->db, szTables, &tv ); + TRACE("CreateView returned %x\n", r); + if( r ) + return r; + + r = tv->ops->execute( tv, 0 ); + TRACE("tv execute returned %x\n", r); + if( r ) + return r; + + row = -1; + r = tv->ops->insert_row( tv, &row ); + TRACE("insert_row returned %x\n", r); + if( r ) + goto err; + + r = tv->ops->set_int( tv, row, 1, table_val ); + if( r ) + goto err; + tv->ops->delete( tv ); + tv = NULL; + + /* add each column to the _Columns table */ + r = TABLE_CreateView( iv->db, szColumns, &tv ); + if( r ) + return r; + + r = tv->ops->execute( tv, 0 ); + TRACE("tv execute returned %x\n", r); + if( r ) + return r; + + /* + * need to set the table, column number, col name and type + * for each column we enter in the table + */ + nField = 1; + for( col = iv->col_info; col; col = col->next ) + { + row = -1; + r = tv->ops->insert_row( tv, &row ); + if( r ) + goto err; + + column_val = msi_addstringW( iv->db->strings, 0, col->colname, -1, 1 ); + TRACE("New string %s -> %d\n", debugstr_w( col->colname ), column_val ); + if( column_val < 0 ) + break; + + r = tv->ops->set_int( tv, row, 1, table_val ); + if( r ) + break; + + r = tv->ops->set_int( tv, row, 2, 0x8000|nField ); + if( r ) + break; + + r = tv->ops->set_int( tv, row, 3, column_val ); + if( r ) + break; + + r = tv->ops->set_int( tv, row, 4, 0x8000|col->type ); + if( r ) + break; + } + if( !col ) + r = ERROR_SUCCESS; + +err: + /* FIXME: remove values from the string table on error */ + if( tv ) + tv->ops->delete( tv ); + return r; +#else + return ERROR_FUNCTION_FAILED; +#endif +} + +static UINT INSERT_close( struct tagMSIVIEW *view ) +{ + MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view; + + TRACE("%p\n", iv); + + return ERROR_SUCCESS; +} + +static UINT INSERT_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols ) +{ + MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view; + + TRACE("%p %p %p\n", iv, rows, cols ); + + return ERROR_FUNCTION_FAILED; +} + +static UINT INSERT_get_column_info( struct tagMSIVIEW *view, + UINT n, LPWSTR *name, UINT *type ) +{ + MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view; + + TRACE("%p %d %p %p\n", iv, n, name, type ); + + return ERROR_FUNCTION_FAILED; +} + +static UINT INSERT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec) +{ + MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view; + + TRACE("%p %d %ld\n", iv, eModifyMode, hrec ); + + return ERROR_FUNCTION_FAILED; +} + +static UINT INSERT_delete( struct tagMSIVIEW *view ) +{ + MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view; + + TRACE("%p\n", iv ); + + delete_string_list( iv->cols ); + delete_value_list( iv->vals ); + HeapFree( GetProcessHeap(), 0, iv->name ); + HeapFree( GetProcessHeap(), 0, iv ); + + return ERROR_SUCCESS; +} + + +MSIVIEWOPS insert_ops = +{ + INSERT_fetch_int, + NULL, + NULL, + INSERT_execute, + INSERT_close, + INSERT_get_dimensions, + INSERT_get_column_info, + INSERT_modify, + INSERT_delete +}; + +UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, + string_list *columns, value_list *values, BOOL temp ) +{ + MSIINSERTVIEW *iv = NULL; + + TRACE("%p\n", iv ); + + iv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *iv ); + if( !iv ) + return ERROR_FUNCTION_FAILED; + + /* fill the structure */ + iv->view.ops = &insert_ops; + iv->db = db; + iv->name = table; /* FIXME: strdupW it? */ + iv->cols = columns; + iv->vals = values; + iv->bIsTemp = temp; + *view = (MSIVIEW*) iv; + + return ERROR_SUCCESS; +} diff --git a/dlls/msi/query.h b/dlls/msi/query.h index 2870bc3c3b8..4c5fa3aa826 100644 --- a/dlls/msi/query.h +++ b/dlls/msi/query.h @@ -49,6 +49,12 @@ #define EXPR_SVAL 5 #define EXPR_UVAL 6 +typedef struct _string_list +{ + LPWSTR string; + struct _string_list *next; +} string_list; + struct complex_expr { UINT op; @@ -77,6 +83,12 @@ typedef struct _create_col_info struct _create_col_info *next; } create_col_info; +typedef struct _value_list +{ + struct expr *val; + struct _value_list *next; +} value_list; + UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phView); UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view ); @@ -95,6 +107,13 @@ UINT WHERE_AddCondition( MSIVIEW *view, struct expr *condition ); UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, create_col_info *col_info, BOOL temp ); +UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, + string_list *columns, value_list *values, BOOL temp ); + +void delete_expr( struct expr *e ); +void delete_string_list( string_list *sl ); +void delete_value_list( value_list *vl ); + int sqliteGetToken(const WCHAR *z, int *tokenType); #endif /* __WINE_MSI_QUERY_H */ diff --git a/dlls/msi/sql.y b/dlls/msi/sql.y index 292fbe35d63..934b6479d89 100644 --- a/dlls/msi/sql.y +++ b/dlls/msi/sql.y @@ -48,23 +48,17 @@ typedef struct tag_SQL_input MSIVIEW **view; /* view structure for the resulting query */ } SQL_input; -struct string_list -{ - LPWSTR string; - struct string_list *next; -}; - static LPWSTR SQL_getstring( SQL_input *info ); static INT SQL_getint( SQL_input *sql ); static int SQL_lex( void *SQL_lval, SQL_input *info); static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in, - struct string_list *columns ); + string_list *columns ); static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in, - struct string_list *columns ); + string_list *columns ); static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, - struct string_list *keys); + string_list *keys); static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r ); static struct expr * EXPR_column( LPWSTR column ); @@ -78,7 +72,8 @@ static struct expr * EXPR_sval( LPWSTR string ); %union { LPWSTR string; - struct string_list *column_list; + string_list *column_list; + value_list *val_list; MSIVIEW *query; struct expr *expr; USHORT column_type; @@ -129,10 +124,11 @@ static struct expr * EXPR_sval( LPWSTR string ); %type column table string_or_id %type selcollist -%type from unorderedsel oneselect onequery onecreate -%type expr val column_val +%type from unorderedsel oneselect onequery onecreate oneinsert +%type expr val column_val const_val %type column_type data_type data_type_l data_count %type column_def table_def +%type constlist %% @@ -147,6 +143,30 @@ onequery: SQL_input* sql = (SQL_input*) info; *sql->view = $1; } + | oneinsert + { + SQL_input* sql = (SQL_input*) info; + *sql->view = $1; + } + ; + +oneinsert: + TK_INSERT TK_INTO table selcollist TK_VALUES constlist + { + SQL_input *sql = (SQL_input*) info; + MSIVIEW *insert = NULL; + + INSERT_CreateView( sql->db, &insert, $3, $4, $6, FALSE ); + $$ = insert; + } + | TK_INSERT TK_INTO table selcollist TK_VALUES constlist TK_TEMP + { + SQL_input *sql = (SQL_input*) info; + MSIVIEW *insert = NULL; + + INSERT_CreateView( sql->db, &insert, $3, $4, $6, TRUE ); + $$ = insert; + } ; onecreate: @@ -323,7 +343,7 @@ unorderedsel: selcollist: column { - struct string_list *list; + string_list *list; list = HeapAlloc( GetProcessHeap(), 0, sizeof *list ); if( !list ) @@ -336,7 +356,7 @@ selcollist: } | column TK_COMMA selcollist { - struct string_list *list; + string_list *list; list = HeapAlloc( GetProcessHeap(), 0, sizeof *list ); if( !list ) @@ -436,10 +456,39 @@ expr: val: column_val + | const_val + ; + +constlist: + const_val { + value_list *vals; + + vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals ); + if( vals ) + { + vals->val = $1; + vals->next = NULL; + } + $$ = vals; + } + | constlist TK_COMMA const_val + { + value_list *vals; + + vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals ); + if( vals ) + { + vals->val = $3; + vals->next = NULL; + } + $1->next = vals; $$ = $1; } - | TK_INTEGER + ; + +const_val: + TK_INTEGER { SQL_input* sql = (SQL_input*) info; $$ = EXPR_ival( SQL_getint(sql) ); @@ -546,18 +595,18 @@ int SQL_error(const char *str) } static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in, - struct string_list *columns ) + string_list *columns ) { MSIVIEW *view = NULL; SELECT_CreateView( db, &view, in ); if( view ) { - struct string_list *x = columns; + string_list *x = columns; while( x ) { - struct string_list *t = x->next; + string_list *t = x->next; SELECT_AddColumn( view, x->string ); HeapFree( GetProcessHeap(), 0, x->string ); HeapFree( GetProcessHeap(), 0, x ); @@ -570,26 +619,21 @@ static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in, } static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in, - struct string_list *columns ) + string_list *columns ) { MSIVIEW *view = NULL; ORDER_CreateView( db, &view, in ); if( view ) { - struct string_list *x = columns; + string_list *x = columns; - while( x ) - { - struct string_list *t = x->next; + for( x = columns; x ; x = x->next ) ORDER_AddColumn( view, x->string ); - HeapFree( GetProcessHeap(), 0, x->string ); - HeapFree( GetProcessHeap(), 0, x ); - x = t; - } } else ERR("Error creating select query\n"); + delete_string_list( columns ); return view; } @@ -639,10 +683,44 @@ static struct expr * EXPR_sval( LPWSTR string ) return e; } -static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, - struct string_list *keys ) +void delete_expr( struct expr *e ) { - struct string_list *k; + if( !e ) + return; + if( e->type == EXPR_COMPLEX ) + { + delete_expr( e->u.expr.left ); + delete_expr( e->u.expr.right ); + } + HeapFree( GetProcessHeap(), 0, e ); +} + +void delete_string_list( string_list *sl ) +{ + while( sl ) + { + string_list *t = sl->next; + HeapFree( GetProcessHeap(), 0, sl->string ); + HeapFree( GetProcessHeap(), 0, sl ); + sl = t; + } +} + +void delete_value_list( value_list *vl ) +{ + while( vl ) + { + value_list *t = vl->next; + delete_expr( vl->val ); + HeapFree( GetProcessHeap(), 0, vl ); + vl = t; + } +} + +static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, + string_list *keys ) +{ + string_list *k; BOOL found = TRUE; for( k = keys; k && found; k = k->next ) diff --git a/dlls/msi/where.c b/dlls/msi/where.c index c115b0e8267..981d2ee8d3a 100644 --- a/dlls/msi/where.c +++ b/dlls/msi/where.c @@ -231,18 +231,6 @@ static UINT WHERE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHAN return wv->table->ops->modify( wv->table, eModifyMode, hrec ); } -static void WHERE_delete_expr( struct expr *e ) -{ - if( !e ) - return; - if( e->type == EXPR_COMPLEX ) - { - WHERE_delete_expr( e->u.expr.left ); - WHERE_delete_expr( e->u.expr.right ); - } - HeapFree( GetProcessHeap(), 0, e ); -} - static UINT WHERE_delete( struct tagMSIVIEW *view ) { MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; @@ -257,7 +245,7 @@ static UINT WHERE_delete( struct tagMSIVIEW *view ) wv->reorder = NULL; wv->row_count = 0; - WHERE_delete_expr( wv->cond ); + delete_expr( wv->cond ); HeapFree( GetProcessHeap(), 0, wv ); @@ -378,7 +366,7 @@ UINT WHERE_AddCondition( MSIVIEW *view, struct expr *cond ) TRACE("condition is %s\n", valid ? "valid" : "invalid" ); if( !valid ) { - WHERE_delete_expr( cond ); + delete_expr( cond ); return ERROR_FUNCTION_FAILED; }