Add a stub dll for the System Event Notification Service.
[wine] / dlls / msi / msiquery.c
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2002-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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winerror.h"
28 #include "wine/debug.h"
29 #include "wine/unicode.h"
30 #include "msi.h"
31 #include "msiquery.h"
32 #include "objbase.h"
33 #include "objidl.h"
34 #include "msipriv.h"
35 #include "winnls.h"
36
37 #include "query.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(msi);
40
41 void MSI_CloseView( MSIOBJECTHDR *arg )
42 {
43     MSIQUERY *query = (MSIQUERY*) arg;
44
45     if( query->view && query->view->ops->delete )
46         query->view->ops->delete( query->view );
47     msiobj_release( &query->db->hdr );
48 }
49
50 UINT VIEW_find_column( MSIVIEW *table, LPWSTR name, UINT *n )
51 {
52     LPWSTR col_name;
53     UINT i, count, r;
54
55     r = table->ops->get_dimensions( table, NULL, &count );
56     if( r != ERROR_SUCCESS )
57         return r;
58
59     for( i=1; i<=count; i++ )
60     {
61         INT x;
62
63         col_name = NULL;
64         r = table->ops->get_column_info( table, i, &col_name, NULL );
65         if( r != ERROR_SUCCESS )
66             return r;
67         x = lstrcmpW( name, col_name );
68         HeapFree( GetProcessHeap(), 0, col_name );
69         if( !x )
70         {
71             *n = i;
72             return ERROR_SUCCESS;
73         }
74     }
75
76     return ERROR_INVALID_PARAMETER;
77 }
78
79 UINT WINAPI MsiDatabaseOpenViewA(MSIHANDLE hdb,
80               LPCSTR szQuery, MSIHANDLE *phView)
81 {
82     UINT r;
83     LPWSTR szwQuery;
84
85     TRACE("%ld %s %p\n", hdb, debugstr_a(szQuery), phView);
86
87     if( szQuery )
88     {
89         UINT len = MultiByteToWideChar( CP_ACP, 0, szQuery, -1, NULL, 0 );
90         szwQuery = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
91         if( !szwQuery )
92             return ERROR_FUNCTION_FAILED;
93         MultiByteToWideChar( CP_ACP, 0, szQuery, -1, szwQuery, len );
94     }
95     else
96         szwQuery = NULL;
97
98     r = MsiDatabaseOpenViewW( hdb, szwQuery, phView);
99
100     HeapFree( GetProcessHeap(), 0, szwQuery );
101     return r;
102 }
103
104 UINT MSI_DatabaseOpenViewW(MSIDATABASE *db,
105               LPCWSTR szQuery, MSIQUERY **pView)
106 {
107     MSIQUERY *query;
108     UINT r;
109
110     TRACE("%s %p\n", debugstr_w(szQuery), pView);
111
112     if( !szQuery)
113         return ERROR_INVALID_PARAMETER;
114
115     /* pre allocate a handle to hold a pointer to the view */
116     query = alloc_msiobject( MSIHANDLETYPE_VIEW, sizeof (MSIQUERY),
117                               MSI_CloseView );
118     if( !query )
119         return ERROR_FUNCTION_FAILED;
120
121     msiobj_addref( &db->hdr );
122     query->row = 0;
123     query->db = db;
124     query->view = NULL;
125
126     r = MSI_ParseSQL( db, szQuery, &query->view );
127     if( r == ERROR_SUCCESS )
128     {
129         msiobj_addref( &query->hdr );
130         *pView = query;
131     }
132
133     msiobj_release( &query->hdr );
134     return r;
135 }
136
137 UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... )
138 {
139     LPWSTR szQuery;
140     LPCWSTR p;
141     UINT sz, rc;
142     va_list va;
143
144     /* figure out how much space we need to allocate */
145     va_start(va, fmt);
146     sz = strlenW(fmt) + 1;
147     p = fmt;
148     while (*p)
149     {
150         p = strchrW(p, '%');
151         if (!p)
152             break;
153         p++;
154         switch (*p)
155         {
156         case 's':  /* a string */
157             sz += strlenW(va_arg(va,LPCWSTR));
158             break;
159         case 'd':
160         case 'i':  /* an integer -2147483648 seems to be longest */
161             sz += 3*sizeof(int);
162             (void)va_arg(va,int);
163             break;
164         case '%':  /* a single % - leave it alone */
165             break;
166         default:
167             FIXME("Unhandled character type %c\n",*p);
168         }
169         p++;
170     }
171     va_end(va);
172
173     /* construct the string */
174     szQuery = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR));
175     va_start(va, fmt);
176     vsnprintfW(szQuery, sz, fmt, va);
177     va_end(va);
178
179     /* perform the query */
180     rc = MSI_DatabaseOpenViewW(db, szQuery, view);
181     HeapFree(GetProcessHeap(), 0, szQuery);
182     return rc;
183 }
184
185 UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb,
186               LPCWSTR szQuery, MSIHANDLE *phView)
187 {
188     MSIDATABASE *db;
189     MSIQUERY *query = NULL;
190     UINT ret;
191
192     TRACE("%s %p\n", debugstr_w(szQuery), phView);
193
194     db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
195     if( !db )
196         return ERROR_INVALID_HANDLE;
197
198     ret = MSI_DatabaseOpenViewW( db, szQuery, &query );
199     if( ret == ERROR_SUCCESS )
200     {
201         *phView = alloc_msihandle( &query->hdr );
202         msiobj_release( &query->hdr );
203     }
204     msiobj_release( &db->hdr );
205
206     return ret;
207 }
208
209 UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec)
210 {
211     MSIVIEW *view;
212     MSIRECORD *rec;
213     UINT row_count = 0, col_count = 0, i, ival, ret, type;
214
215     TRACE("%p %p\n", query, prec );
216
217     view = query->view;
218     if( !view )
219         return ERROR_FUNCTION_FAILED;
220
221     ret = view->ops->get_dimensions( view, &row_count, &col_count );
222     if( ret )
223         return ret;
224     if( !col_count )
225         return ERROR_INVALID_PARAMETER;
226
227     if( query->row >= row_count )
228         return ERROR_NO_MORE_ITEMS;
229
230     rec = MSI_CreateRecord( col_count );
231     if( !rec )
232         return ERROR_FUNCTION_FAILED;
233
234     for( i=1; i<=col_count; i++ )
235     {
236         ret = view->ops->get_column_info( view, i, NULL, &type );
237         if( ret )
238         {
239             ERR("Error getting column type for %d\n", i );
240             continue;
241         }
242         if (( type != MSITYPE_BINARY) && (type != (MSITYPE_BINARY |
243                                                    MSITYPE_NULLABLE)))
244         {
245             ret = view->ops->fetch_int( view, query->row, i, &ival );
246             if( ret )
247             {
248                 ERR("Error fetching data for %d\n", i );
249                 continue;
250             }
251             if( ! (type & MSITYPE_VALID ) )
252                 ERR("Invalid type!\n");
253
254             /* check if it's nul (0) - if so, don't set anything */
255             if( !ival )
256                 continue;
257
258             if( type & MSITYPE_STRING )
259             {
260                 LPWSTR sval;
261
262                 sval = MSI_makestring( query->db, ival );
263                 MSI_RecordSetStringW( rec, i, sval );
264                 HeapFree( GetProcessHeap(), 0, sval );
265             }
266             else
267             {
268                 if( (type & MSI_DATASIZEMASK) == 2 )
269                     MSI_RecordSetInteger( rec, i, ival - (1<<15) );
270                 else
271                     MSI_RecordSetInteger( rec, i, ival - (1<<31) );
272             }
273         }
274         else
275         {
276             IStream *stm = NULL;
277
278             ret = view->ops->fetch_stream( view, query->row, i, &stm );
279             if( ( ret == ERROR_SUCCESS ) && stm )
280             {
281                 MSI_RecordSetIStream( rec, i, stm );
282                 IStream_Release( stm );
283             }
284             else
285                 ERR("failed to get stream\n");
286         }
287     }
288     query->row ++;
289
290     *prec = rec;
291
292     return ERROR_SUCCESS;
293 }
294
295 UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record)
296 {
297     MSIQUERY *query;
298     MSIRECORD *rec = NULL;
299     UINT ret;
300
301     TRACE("%ld %p\n", hView, record);
302
303     query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
304     if( !query )
305         return ERROR_INVALID_HANDLE;
306     ret = MSI_ViewFetch( query, &rec );
307     if( ret == ERROR_SUCCESS )
308     {
309         *record = alloc_msihandle( &rec->hdr );
310         msiobj_release( &rec->hdr );
311     }
312     msiobj_release( &query->hdr );
313     return ret;
314 }
315
316 UINT MSI_ViewClose(MSIQUERY *query)
317 {
318     MSIVIEW *view;
319
320     TRACE("%p\n", query );
321
322     view = query->view;
323     if( !view )
324         return ERROR_FUNCTION_FAILED;
325     if( !view->ops->close )
326         return ERROR_FUNCTION_FAILED;
327
328     return view->ops->close( view );
329 }
330
331 UINT WINAPI MsiViewClose(MSIHANDLE hView)
332 {
333     MSIQUERY *query;
334     UINT ret;
335
336     TRACE("%ld\n", hView );
337
338     query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
339     if( !query )
340         return ERROR_INVALID_HANDLE;
341
342     ret = MSI_ViewClose( query );
343     msiobj_release( &query->hdr );
344     return ret;
345 }
346
347 UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec )
348 {
349     MSIVIEW *view;
350
351     TRACE("%p %p\n", query, rec);
352
353     view = query->view;
354     if( !view )
355         return ERROR_FUNCTION_FAILED;
356     if( !view->ops->execute )
357         return ERROR_FUNCTION_FAILED;
358     query->row = 0;
359
360     return view->ops->execute( view, rec );
361 }
362
363 UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec)
364 {
365     MSIQUERY *query;
366     MSIRECORD *rec = NULL;
367     UINT ret;
368     
369     TRACE("%ld %ld\n", hView, hRec);
370
371     query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
372     if( !query )
373         return ERROR_INVALID_HANDLE;
374
375     if( hRec )
376     {
377         rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD );
378         if( !rec )
379         {
380             ret = ERROR_INVALID_HANDLE;
381             goto out;
382         }
383     }
384
385     msiobj_lock( &rec->hdr );
386     ret = MSI_ViewExecute( query, rec );
387     msiobj_unlock( &rec->hdr );
388
389 out:
390     if( query )
391         msiobj_release( &query->hdr );
392     if( rec )
393         msiobj_release( &rec->hdr );
394
395     return ret;
396 }
397
398 UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec)
399 {
400     MSIVIEW *view;
401     MSIQUERY *query;
402     MSIHANDLE handle;
403     UINT ret, i, count = 0, type;
404     LPWSTR name;
405
406     TRACE("%ld %d %p\n", hView, info, hRec);
407
408     query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
409     if( !query )
410         return ERROR_INVALID_HANDLE;
411
412     view = query->view;
413     if( !view )
414         return ERROR_FUNCTION_FAILED;
415
416     if( !view->ops->get_dimensions )
417         return ERROR_FUNCTION_FAILED;
418
419     ret = view->ops->get_dimensions( view, NULL, &count );
420     if( ret )
421         return ret;
422     if( !count )
423         return ERROR_INVALID_PARAMETER;
424
425     handle = MsiCreateRecord( count );
426     if( !handle )
427         return ERROR_FUNCTION_FAILED;
428
429     for( i=0; i<count; i++ )
430     {
431         name = NULL;
432         ret = view->ops->get_column_info( view, i+1, &name, &type );
433         if( ret != ERROR_SUCCESS )
434             continue;
435         MsiRecordSetStringW( handle, i+1, name );
436         HeapFree( GetProcessHeap(), 0, name );
437     }
438
439     *hRec = handle;
440
441     return ERROR_SUCCESS;
442 }
443
444 UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb, 
445                  LPCSTR szTransformFile, int iErrorCond)
446 {
447     FIXME("%ld %s %d\n", hdb, debugstr_a(szTransformFile), iErrorCond);
448     return ERROR_CALL_NOT_IMPLEMENTED;
449 }
450
451 UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb, 
452                  LPCWSTR szTransformFile, int iErrorCond)
453 {
454     FIXME("%ld %s %d\n", hdb, debugstr_w(szTransformFile), iErrorCond);
455     return ERROR_CALL_NOT_IMPLEMENTED;
456 }
457
458 UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref,
459                  LPCSTR szTransformFile, int iReserved1, int iReserved2 )
460 {
461     FIXME("%ld %ld %s %d %d\n", hdb, hdbref, 
462            debugstr_a(szTransformFile), iReserved1, iReserved2);
463     return ERROR_CALL_NOT_IMPLEMENTED;
464 }
465
466 UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref,
467                  LPCWSTR szTransformFile, int iReserved1, int iReserved2 )
468 {
469     FIXME("%ld %ld %s %d %d\n", hdb, hdbref, 
470            debugstr_w(szTransformFile), iReserved1, iReserved2);
471     return ERROR_CALL_NOT_IMPLEMENTED;
472 }
473
474 UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
475 {
476     MSIDATABASE *db;
477     UINT r;
478
479     TRACE("%ld\n", hdb);
480
481     db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
482     if( !db )
483         return ERROR_INVALID_HANDLE;
484
485     /* FIXME: lock the database */
486
487     r = MSI_CommitTables( db );
488
489     /* FIXME: unlock the database */
490
491     msiobj_release( &db->hdr );
492
493     return r;
494 }
495
496 UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb, 
497                     LPCSTR table, MSIHANDLE* rec)
498 {
499     FIXME("%ld %s %p\n", hdb, debugstr_a(table), rec);
500     return ERROR_CALL_NOT_IMPLEMENTED;
501 }
502
503 UINT WINAPI MsiDatabaseGetPrimaryKeysW(MSIHANDLE hdb,
504                     LPCWSTR table, MSIHANDLE* rec)
505 {
506     FIXME("%ld %s %p\n", hdb, debugstr_w(table), rec);
507     return ERROR_CALL_NOT_IMPLEMENTED;
508 }
509
510 UINT WINAPI MsiViewModify(MSIHANDLE hView, MSIMODIFY eModifyMode, MSIHANDLE
511 hRecord)
512 {
513     FIXME("%ld %x %ld\n",hView, eModifyMode, hRecord);
514     return ERROR_CALL_NOT_IMPLEMENTED;
515 }
516
517 UINT WINAPI MsiDatabaseIsTablePersistentA(
518               MSIHANDLE hDatabase, LPSTR szTableName)
519 {
520     FIXME("%lx %s\n", hDatabase, debugstr_a(szTableName));
521     return ERROR_CALL_NOT_IMPLEMENTED;
522 }
523
524 UINT WINAPI MsiDatabaseIsTablePersistentW(
525               MSIHANDLE hDatabase, LPWSTR szTableName)
526 {
527     FIXME("%lx %s\n", hDatabase, debugstr_w(szTableName));
528     return ERROR_CALL_NOT_IMPLEMENTED;
529 }