winedbg: Don't dereference possibly NULL thread pointer.
[wine/zf.git] / dlls / msi / select.c
blobd5a8e1fde23b1da2356ebfa47e88ff88c8e4da63
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2002-2004 Mike McCormack for CodeWeavers
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.
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.
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
21 #include <stdarg.h>
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"
34 #include "query.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(msidb);
39 /* below is the query interface to a table */
41 typedef struct tagMSISELECTVIEW
43 MSIVIEW view;
44 MSIDATABASE *db;
45 MSIVIEW *table;
46 UINT num_cols;
47 UINT max_cols;
48 UINT cols[1];
49 } MSISELECTVIEW;
51 static UINT translate_record( MSISELECTVIEW *sv, MSIRECORD *in, MSIRECORD **out )
53 UINT r, col_count, i;
54 MSIRECORD *object;
56 if ((r = sv->table->ops->get_dimensions( sv->table, NULL, &col_count )))
57 return r;
59 if (!(object = MSI_CreateRecord( col_count )))
60 return ERROR_OUTOFMEMORY;
62 for (i = 0; i < sv->num_cols; i++)
64 if ((r = MSI_RecordCopyField( in, i + 1, object, sv->cols[i] )))
66 msiobj_release( &object->hdr );
67 return r;
71 *out = object;
72 return ERROR_SUCCESS;
75 static UINT SELECT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
77 MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
79 TRACE("%p %d %d %p\n", sv, row, col, val );
81 if( !sv->table )
82 return ERROR_FUNCTION_FAILED;
84 if( !col || col > sv->num_cols )
85 return ERROR_FUNCTION_FAILED;
87 col = sv->cols[ col - 1 ];
88 if( !col )
90 *val = 0;
91 return ERROR_SUCCESS;
93 return sv->table->ops->fetch_int( sv->table, row, col, val );
96 static UINT SELECT_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm)
98 MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
100 TRACE("%p %d %d %p\n", sv, row, col, stm );
102 if( !sv->table )
103 return ERROR_FUNCTION_FAILED;
105 if( !col || col > sv->num_cols )
106 return ERROR_FUNCTION_FAILED;
108 col = sv->cols[ col - 1 ];
109 if( !col )
111 *stm = NULL;
112 return ERROR_SUCCESS;
114 return sv->table->ops->fetch_stream( sv->table, row, col, stm );
117 static UINT SELECT_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask )
119 MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
120 UINT i, expanded_mask = 0, r = ERROR_SUCCESS, col_count = 0;
121 MSIRECORD *expanded;
123 TRACE("%p %d %p %08x\n", sv, row, rec, mask );
125 if ( !sv->table )
126 return ERROR_FUNCTION_FAILED;
128 /* test if any of the mask bits are invalid */
129 if ( mask >= (1<<sv->num_cols) )
130 return ERROR_INVALID_PARAMETER;
132 /* find the number of columns in the table below */
133 r = sv->table->ops->get_dimensions( sv->table, NULL, &col_count );
134 if( r )
135 return r;
137 /* expand the record to the right size for the underlying table */
138 expanded = MSI_CreateRecord( col_count );
139 if ( !expanded )
140 return ERROR_FUNCTION_FAILED;
142 /* move the right fields across */
143 for ( i=0; i<sv->num_cols; i++ )
145 r = MSI_RecordCopyField( rec, i+1, expanded, sv->cols[ i ] );
146 if (r != ERROR_SUCCESS)
147 break;
148 expanded_mask |= (1<<(sv->cols[i]-1));
151 /* set the row in the underlying table */
152 if (r == ERROR_SUCCESS)
153 r = sv->table->ops->set_row( sv->table, row, expanded, expanded_mask );
155 msiobj_release( &expanded->hdr );
156 return r;
159 static UINT SELECT_insert_row( struct tagMSIVIEW *view, MSIRECORD *record, UINT row, BOOL temporary )
161 MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
162 UINT table_cols, r;
163 MSIRECORD *outrec;
165 TRACE("%p %p\n", sv, record );
167 if ( !sv->table )
168 return ERROR_FUNCTION_FAILED;
170 /* rearrange the record to suit the table */
171 r = sv->table->ops->get_dimensions( sv->table, NULL, &table_cols );
172 if (r != ERROR_SUCCESS)
173 return r;
175 if ((r = translate_record( sv, record, &outrec )))
176 return r;
178 r = sv->table->ops->insert_row( sv->table, outrec, row, temporary );
180 msiobj_release( &outrec->hdr );
181 return r;
184 static UINT SELECT_execute( struct tagMSIVIEW *view, MSIRECORD *record )
186 MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
188 TRACE("%p %p\n", sv, record);
190 if( !sv->table )
191 return ERROR_FUNCTION_FAILED;
193 return sv->table->ops->execute( sv->table, record );
196 static UINT SELECT_close( struct tagMSIVIEW *view )
198 MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
200 TRACE("%p\n", sv );
202 if( !sv->table )
203 return ERROR_FUNCTION_FAILED;
205 return sv->table->ops->close( sv->table );
208 static UINT SELECT_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
210 MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
212 TRACE("%p %p %p\n", sv, rows, cols );
214 if( !sv->table )
215 return ERROR_FUNCTION_FAILED;
217 if( cols )
218 *cols = sv->num_cols;
220 return sv->table->ops->get_dimensions( sv->table, rows, NULL );
223 static UINT SELECT_get_column_info( struct tagMSIVIEW *view, UINT n, LPCWSTR *name,
224 UINT *type, BOOL *temporary, LPCWSTR *table_name )
226 MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
228 TRACE("%p %d %p %p %p %p\n", sv, n, name, type, temporary, table_name );
230 if( !sv->table )
231 return ERROR_FUNCTION_FAILED;
233 if( !n || n > sv->num_cols )
234 return ERROR_FUNCTION_FAILED;
236 n = sv->cols[ n - 1 ];
237 if( !n )
239 if (name) *name = L"";
240 if (type) *type = MSITYPE_UNKNOWN | MSITYPE_VALID;
241 if (temporary) *temporary = FALSE;
242 if (table_name) *table_name = L"";
243 return ERROR_SUCCESS;
245 return sv->table->ops->get_column_info( sv->table, n, name,
246 type, temporary, table_name );
249 UINT msi_select_update(MSIVIEW *view, MSIRECORD *rec, UINT row)
251 MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
252 UINT r, i, col, type, val;
253 IStream *stream;
254 LPCWSTR str;
256 for (i = 0; i < sv->num_cols; i++)
258 col = sv->cols[i];
260 r = SELECT_get_column_info(view, i + 1, NULL, &type, NULL, NULL);
261 if (r != ERROR_SUCCESS)
263 ERR("Failed to get column information: %d\n", r);
264 return r;
267 if (MSITYPE_IS_BINARY(type))
269 if (MSI_RecordGetIStream(rec, i + 1, &stream))
270 return ERROR_FUNCTION_FAILED;
271 r = sv->table->ops->set_stream(sv->table, row, col, stream);
273 else if (type & MSITYPE_STRING)
275 int len;
276 str = msi_record_get_string(rec, i + 1, &len);
277 r = sv->table->ops->set_string(sv->table, row, col, str, len);
279 else
281 val = MSI_RecordGetInteger(rec, i + 1);
282 r = sv->table->ops->set_int(sv->table, row, col, val);
285 if (r != ERROR_SUCCESS)
287 ERR("Failed to modify record: %d\n", r);
288 return r;
292 return ERROR_SUCCESS;
295 static UINT SELECT_modify( struct tagMSIVIEW *view, MSIMODIFY mode,
296 MSIRECORD *rec, UINT row )
298 MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
299 MSIRECORD *table_rec;
300 UINT r;
302 TRACE("view %p, mode %d, rec %p, row %u.\n", view, mode, rec, row);
304 if( !sv->table )
305 return ERROR_FUNCTION_FAILED;
307 /* Tests demonstrate that UPDATE only affects the columns selected and that
308 * others are left unchanged; however, ASSIGN overwrites unselected columns
309 * to NULL. Similarly, MERGE matches all unselected columns as NULL rather
310 * than just ignoring them. */
312 switch (mode)
314 case MSIMODIFY_REFRESH:
315 return msi_view_refresh_row(sv->db, view, row, rec);
316 case MSIMODIFY_UPDATE:
317 return msi_select_update(view, rec, row);
318 case MSIMODIFY_INSERT:
319 case MSIMODIFY_ASSIGN:
320 case MSIMODIFY_MERGE:
321 case MSIMODIFY_INSERT_TEMPORARY:
322 case MSIMODIFY_VALIDATE_NEW:
323 if ((r = translate_record( sv, rec, &table_rec )))
324 return r;
326 r = sv->table->ops->modify( sv->table, mode, table_rec, row );
327 msiobj_release( &table_rec->hdr );
328 return r;
329 case MSIMODIFY_DELETE:
330 return sv->table->ops->modify( sv->table, mode, rec, row );
331 default:
332 FIXME("unhandled mode %d\n", mode);
333 return ERROR_FUNCTION_FAILED;
337 static UINT SELECT_delete( struct tagMSIVIEW *view )
339 MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
341 TRACE("%p\n", sv );
343 if( sv->table )
344 sv->table->ops->delete( sv->table );
345 sv->table = NULL;
347 msi_free( sv );
349 return ERROR_SUCCESS;
352 static const MSIVIEWOPS select_ops =
354 SELECT_fetch_int,
355 SELECT_fetch_stream,
356 NULL,
357 NULL,
358 NULL,
359 SELECT_set_row,
360 SELECT_insert_row,
361 NULL,
362 SELECT_execute,
363 SELECT_close,
364 SELECT_get_dimensions,
365 SELECT_get_column_info,
366 SELECT_modify,
367 SELECT_delete,
368 NULL,
369 NULL,
370 NULL,
371 NULL,
372 NULL,
375 static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPCWSTR name,
376 LPCWSTR table_name )
378 UINT r, n;
379 MSIVIEW *table;
381 TRACE("%p adding %s.%s\n", sv, debugstr_w( table_name ),
382 debugstr_w( name ));
384 if( sv->view.ops != &select_ops )
385 return ERROR_FUNCTION_FAILED;
387 table = sv->table;
388 if( !table )
389 return ERROR_FUNCTION_FAILED;
390 if( !table->ops->get_dimensions )
391 return ERROR_FUNCTION_FAILED;
392 if( !table->ops->get_column_info )
393 return ERROR_FUNCTION_FAILED;
395 if( sv->num_cols >= sv->max_cols )
396 return ERROR_FUNCTION_FAILED;
398 if ( !name[0] ) n = 0;
399 else
401 r = VIEW_find_column( table, name, table_name, &n );
402 if( r != ERROR_SUCCESS )
403 return r;
406 sv->cols[sv->num_cols] = n;
407 TRACE("Translating column %s from %d -> %d\n",
408 debugstr_w( name ), sv->num_cols, n);
410 sv->num_cols++;
412 return ERROR_SUCCESS;
415 static int select_count_columns( const column_info *col )
417 int n;
418 for (n = 0; col; col = col->next)
419 n++;
420 return n;
423 UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
424 const column_info *columns )
426 MSISELECTVIEW *sv = NULL;
427 UINT count = 0, r = ERROR_SUCCESS;
429 TRACE("%p\n", sv );
431 count = select_count_columns( columns );
433 sv = msi_alloc_zero( FIELD_OFFSET( MSISELECTVIEW, cols[count] ));
434 if( !sv )
435 return ERROR_FUNCTION_FAILED;
437 /* fill the structure */
438 sv->view.ops = &select_ops;
439 sv->db = db;
440 sv->table = table;
441 sv->num_cols = 0;
442 sv->max_cols = count;
444 while( columns )
446 r = SELECT_AddColumn( sv, columns->column, columns->table );
447 if( r )
448 break;
449 columns = columns->next;
452 if( r == ERROR_SUCCESS )
453 *view = &sv->view;
454 else
455 msi_free( sv );
457 return r;