97e94d7be6528ad782cab74e3881153e3808c19d
[reactos.git] / reactos / dll / win32 / msi / alter.c
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
3 *
4 * Copyright 2006 Mike McCormack
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 received 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 #define WIN32_NO_STATUS
22 #define _INC_WINDOWS
23 #define COM_NO_WINDOWS_H
24
25 //#include <stdarg.h>
26
27 //#include "windef.h"
28 //#include "winbase.h"
29 //#include "winerror.h"
30 #include <wine/debug.h>
31 //#include "msi.h"
32 //#include "msiquery.h"
33 //#include "objbase.h"
34 //#include "objidl.h"
35 //#include "msipriv.h"
36
37 #include "query.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(msidb);
40
41 typedef struct tagMSIALTERVIEW
42 {
43 MSIVIEW view;
44 MSIDATABASE *db;
45 MSIVIEW *table;
46 column_info *colinfo;
47 INT hold;
48 } MSIALTERVIEW;
49
50 static UINT ALTER_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
51 {
52 MSIALTERVIEW *av = (MSIALTERVIEW*)view;
53
54 TRACE("%p %d %d %p\n", av, row, col, val );
55
56 return ERROR_FUNCTION_FAILED;
57 }
58
59 static UINT ALTER_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm)
60 {
61 MSIALTERVIEW *av = (MSIALTERVIEW*)view;
62
63 TRACE("%p %d %d %p\n", av, row, col, stm );
64
65 return ERROR_FUNCTION_FAILED;
66 }
67
68 static UINT ALTER_get_row( struct tagMSIVIEW *view, UINT row, MSIRECORD **rec )
69 {
70 MSIALTERVIEW *av = (MSIALTERVIEW*)view;
71
72 TRACE("%p %d %p\n", av, row, rec );
73
74 return av->table->ops->get_row(av->table, row, rec);
75 }
76
77 static UINT ITERATE_columns(MSIRECORD *row, LPVOID param)
78 {
79 (*(UINT *)param)++;
80 return ERROR_SUCCESS;
81 }
82
83 static BOOL check_column_exists(MSIDATABASE *db, LPCWSTR table, LPCWSTR column)
84 {
85 MSIQUERY *view;
86 MSIRECORD *rec;
87 UINT r;
88
89 static const WCHAR query[] = {
90 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
91 '`','_','C','o','l','u','m','n','s','`',' ','W','H','E','R','E',' ',
92 '`','T','a','b','l','e','`','=','\'','%','s','\'',' ','A','N','D',' ',
93 '`','N','a','m','e','`','=','\'','%','s','\'',0
94 };
95
96 r = MSI_OpenQuery(db, &view, query, table, column);
97 if (r != ERROR_SUCCESS)
98 return FALSE;
99
100 r = MSI_ViewExecute(view, NULL);
101 if (r != ERROR_SUCCESS)
102 goto done;
103
104 r = MSI_ViewFetch(view, &rec);
105 if (r == ERROR_SUCCESS)
106 msiobj_release(&rec->hdr);
107
108 done:
109 msiobj_release(&view->hdr);
110 return (r == ERROR_SUCCESS);
111 }
112
113 static UINT alter_add_column(MSIALTERVIEW *av)
114 {
115 UINT r, colnum = 1;
116 MSIQUERY *view;
117 MSIVIEW *columns;
118
119 static const WCHAR szColumns[] = {'_','C','o','l','u','m','n','s',0};
120 static const WCHAR query[] = {
121 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
122 '`','_','C','o','l','u','m','n','s','`',' ','W','H','E','R','E',' ',
123 '`','T','a','b','l','e','`','=','\'','%','s','\'',' ','O','R','D','E','R',' ',
124 'B','Y',' ','`','N','u','m','b','e','r','`',0
125 };
126
127 r = TABLE_CreateView(av->db, szColumns, &columns);
128 if (r != ERROR_SUCCESS)
129 return r;
130
131 if (check_column_exists(av->db, av->colinfo->table, av->colinfo->column))
132 {
133 columns->ops->delete(columns);
134 return ERROR_BAD_QUERY_SYNTAX;
135 }
136
137 r = MSI_OpenQuery(av->db, &view, query, av->colinfo->table, av->colinfo->column);
138 if (r == ERROR_SUCCESS)
139 {
140 r = MSI_IterateRecords(view, NULL, ITERATE_columns, &colnum);
141 msiobj_release(&view->hdr);
142 if (r != ERROR_SUCCESS)
143 {
144 columns->ops->delete(columns);
145 return r;
146 }
147 }
148 r = columns->ops->add_column(columns, av->colinfo->table,
149 colnum, av->colinfo->column,
150 av->colinfo->type, (av->hold == 1));
151
152 columns->ops->delete(columns);
153 return r;
154 }
155
156 static UINT ALTER_execute( struct tagMSIVIEW *view, MSIRECORD *record )
157 {
158 MSIALTERVIEW *av = (MSIALTERVIEW*)view;
159 UINT ref;
160
161 TRACE("%p %p\n", av, record);
162
163 if (av->hold == 1)
164 av->table->ops->add_ref(av->table);
165 else if (av->hold == -1)
166 {
167 ref = av->table->ops->release(av->table);
168 if (ref == 0)
169 av->table = NULL;
170 }
171
172 if (av->colinfo)
173 return alter_add_column(av);
174
175 return ERROR_SUCCESS;
176 }
177
178 static UINT ALTER_close( struct tagMSIVIEW *view )
179 {
180 MSIALTERVIEW *av = (MSIALTERVIEW*)view;
181
182 TRACE("%p\n", av );
183
184 return ERROR_SUCCESS;
185 }
186
187 static UINT ALTER_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
188 {
189 MSIALTERVIEW *av = (MSIALTERVIEW*)view;
190
191 TRACE("%p %p %p\n", av, rows, cols );
192
193 return ERROR_FUNCTION_FAILED;
194 }
195
196 static UINT ALTER_get_column_info( struct tagMSIVIEW *view, UINT n, LPCWSTR *name,
197 UINT *type, BOOL *temporary, LPCWSTR *table_name )
198 {
199 MSIALTERVIEW *av = (MSIALTERVIEW*)view;
200
201 TRACE("%p %d %p %p %p %p\n", av, n, name, type, temporary, table_name );
202
203 return ERROR_FUNCTION_FAILED;
204 }
205
206 static UINT ALTER_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
207 MSIRECORD *rec, UINT row )
208 {
209 MSIALTERVIEW *av = (MSIALTERVIEW*)view;
210
211 TRACE("%p %d %p\n", av, eModifyMode, rec );
212
213 return ERROR_FUNCTION_FAILED;
214 }
215
216 static UINT ALTER_delete( struct tagMSIVIEW *view )
217 {
218 MSIALTERVIEW *av = (MSIALTERVIEW*)view;
219
220 TRACE("%p\n", av );
221 if (av->table)
222 av->table->ops->delete( av->table );
223 msi_free( av );
224
225 return ERROR_SUCCESS;
226 }
227
228 static UINT ALTER_find_matching_rows( struct tagMSIVIEW *view, UINT col,
229 UINT val, UINT *row, MSIITERHANDLE *handle )
230 {
231 TRACE("%p, %d, %u, %p\n", view, col, val, *handle);
232
233 return ERROR_FUNCTION_FAILED;
234 }
235
236 static const MSIVIEWOPS alter_ops =
237 {
238 ALTER_fetch_int,
239 ALTER_fetch_stream,
240 ALTER_get_row,
241 NULL,
242 NULL,
243 NULL,
244 ALTER_execute,
245 ALTER_close,
246 ALTER_get_dimensions,
247 ALTER_get_column_info,
248 ALTER_modify,
249 ALTER_delete,
250 ALTER_find_matching_rows,
251 NULL,
252 NULL,
253 NULL,
254 NULL,
255 NULL,
256 NULL,
257 };
258
259 UINT ALTER_CreateView( MSIDATABASE *db, MSIVIEW **view, LPCWSTR name, column_info *colinfo, int hold )
260 {
261 MSIALTERVIEW *av;
262 UINT r;
263
264 TRACE("%p %p %s %d\n", view, colinfo, debugstr_w(name), hold );
265
266 av = msi_alloc_zero( sizeof *av );
267 if( !av )
268 return ERROR_FUNCTION_FAILED;
269
270 r = TABLE_CreateView( db, name, &av->table );
271 if (r != ERROR_SUCCESS)
272 {
273 msi_free( av );
274 return r;
275 }
276
277 if (colinfo)
278 colinfo->table = name;
279
280 /* fill the structure */
281 av->view.ops = &alter_ops;
282 av->db = db;
283 av->hold = hold;
284 av->colinfo = colinfo;
285
286 *view = &av->view;
287
288 return ERROR_SUCCESS;
289 }