msi: Update tables using records, not integer by integer.
[wine] / dlls / msi / update.c
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2004 Mike McCormack for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have receuved a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winerror.h"
26 #include "wine/debug.h"
27 #include "msi.h"
28 #include "msiquery.h"
29 #include "objbase.h"
30 #include "objidl.h"
31 #include "msipriv.h"
32 #include "winnls.h"
33
34 #include "query.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(msidb);
37
38
39 /* below is the query interface to a table */
40
41 typedef struct tagMSIUPDATEVIEW
42 {
43     MSIVIEW          view;
44     MSIDATABASE     *db;
45     MSIVIEW         *wv;
46     column_info     *vals;
47 } MSIUPDATEVIEW;
48
49 static UINT UPDATE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
50 {
51     MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
52
53     TRACE("%p %d %d %p\n", uv, row, col, val );
54
55     return ERROR_FUNCTION_FAILED;
56 }
57
58 static UINT UPDATE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
59 {
60     MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
61     UINT i, r, col_count = 0, row_count = 0;
62     MSIRECORD *values = NULL;
63     MSIVIEW *wv;
64
65     TRACE("%p %p\n", uv, record );
66
67     wv = uv->wv;
68     if( !wv )
69         return ERROR_FUNCTION_FAILED;
70
71     r = wv->ops->execute( wv, 0 );
72     TRACE("tv execute returned %x\n", r);
73     if( r )
74         return r;
75
76     r = wv->ops->get_dimensions( wv, &row_count, &col_count );
77     if( r )
78         return r;
79
80     values = msi_query_merge_record( col_count, uv->vals, record );
81     if (!values)
82         return ERROR_FUNCTION_FAILED;
83
84     for ( i=0; i<row_count; i++ )
85     {
86         r = wv->ops->set_row( wv, i, values, (1 << col_count) - 1 );
87         if (r != ERROR_SUCCESS)
88             break;
89     }
90
91     msiobj_release( &values->hdr );
92
93     return r;
94 }
95
96
97 static UINT UPDATE_close( struct tagMSIVIEW *view )
98 {
99     MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
100     MSIVIEW *wv;
101
102     TRACE("%p\n", uv);
103
104     wv = uv->wv;
105     if( !wv )
106         return ERROR_FUNCTION_FAILED;
107
108     return wv->ops->close( wv );
109 }
110
111 static UINT UPDATE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
112 {
113     MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
114     MSIVIEW *wv;
115
116     TRACE("%p %p %p\n", uv, rows, cols );
117
118     wv = uv->wv;
119     if( !wv )
120         return ERROR_FUNCTION_FAILED;
121
122     return wv->ops->get_dimensions( wv, rows, cols );
123 }
124
125 static UINT UPDATE_get_column_info( struct tagMSIVIEW *view,
126                 UINT n, LPWSTR *name, UINT *type )
127 {
128     MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
129     MSIVIEW *wv;
130
131     TRACE("%p %d %p %p\n", uv, n, name, type );
132
133     wv = uv->wv;
134     if( !wv )
135         return ERROR_FUNCTION_FAILED;
136
137     return wv->ops->get_column_info( wv, n, name, type );
138 }
139
140 static UINT UPDATE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
141                 MSIRECORD *rec )
142 {
143     MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
144
145     TRACE("%p %d %p\n", uv, eModifyMode, rec );
146
147     return ERROR_FUNCTION_FAILED;
148 }
149
150 static UINT UPDATE_delete( struct tagMSIVIEW *view )
151 {
152     MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
153     MSIVIEW *wv;
154
155     TRACE("%p\n", uv );
156
157     wv = uv->wv;
158     if( wv )
159         wv->ops->delete( wv );
160     msiobj_release( &uv->db->hdr );
161     msi_free( uv );
162
163     return ERROR_SUCCESS;
164 }
165
166 static UINT UPDATE_find_matching_rows( struct tagMSIVIEW *view, UINT col, UINT val, UINT *row, MSIITERHANDLE *handle )
167 {
168     TRACE("%p %d %d %p\n", view, col, val, *handle );
169
170     return ERROR_FUNCTION_FAILED;
171 }
172
173
174 static MSIVIEWOPS update_ops =
175 {
176     UPDATE_fetch_int,
177     NULL,
178     NULL,
179     NULL,
180     UPDATE_execute,
181     UPDATE_close,
182     UPDATE_get_dimensions,
183     UPDATE_get_column_info,
184     UPDATE_modify,
185     UPDATE_delete,
186     UPDATE_find_matching_rows
187 };
188
189 UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
190                         column_info *columns, struct expr *expr )
191 {
192     MSIUPDATEVIEW *uv = NULL;
193     UINT r;
194     MSIVIEW *tv = NULL, *sv = NULL, *wv = NULL;
195
196     TRACE("%p\n", uv );
197
198     r = TABLE_CreateView( db, table, &tv );
199     if( r != ERROR_SUCCESS )
200         return r;
201
202     /* add conditions first */
203     r = WHERE_CreateView( db, &wv, tv, expr );
204     if( r != ERROR_SUCCESS )
205     {
206         tv->ops->delete( tv );
207         return r;
208     }
209     
210     /* then select the columns we want */
211     r = SELECT_CreateView( db, &sv, wv, columns );
212     if( r != ERROR_SUCCESS )
213     {
214         wv->ops->delete( wv );
215         return r;
216     }
217
218     uv = msi_alloc_zero( sizeof *uv );
219     if( !uv )
220         return ERROR_FUNCTION_FAILED;
221
222     /* fill the structure */
223     uv->view.ops = &update_ops;
224     msiobj_addref( &db->hdr );
225     uv->db = db;
226     uv->vals = columns;
227     uv->wv = sv;
228     *view = (MSIVIEW*) uv;
229
230     return ERROR_SUCCESS;
231 }