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