Move OpenQuery into msiquery.c and make it non-static.
[wine/testsucceed.git] / dlls / msi / msiquery.c
blob1bd5fd81893050cc209ab8135e45aa5ec959bff1
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <stdarg.h>
23 #define COBJMACROS
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"
37 #include "query.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msi);
41 void MSI_CloseView( MSIOBJECTHDR *arg )
43 MSIQUERY *query = (MSIQUERY*) arg;
45 if( query->view && query->view->ops->delete )
46 query->view->ops->delete( query->view );
47 msiobj_release( &query->db->hdr );
50 UINT VIEW_find_column( MSIVIEW *table, LPWSTR name, UINT *n )
52 LPWSTR col_name;
53 UINT i, count, r;
55 r = table->ops->get_dimensions( table, NULL, &count );
56 if( r != ERROR_SUCCESS )
57 return r;
59 for( i=1; i<=count; i++ )
61 INT x;
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 )
71 *n = i;
72 return ERROR_SUCCESS;
76 return ERROR_INVALID_PARAMETER;
79 UINT WINAPI MsiDatabaseOpenViewA(MSIHANDLE hdb,
80 LPCSTR szQuery, MSIHANDLE *phView)
82 UINT r;
83 LPWSTR szwQuery;
85 TRACE("%ld %s %p\n", hdb, debugstr_a(szQuery), phView);
87 if( szQuery )
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 );
95 else
96 szwQuery = NULL;
98 r = MsiDatabaseOpenViewW( hdb, szwQuery, phView);
100 HeapFree( GetProcessHeap(), 0, szwQuery );
101 return r;
104 UINT MSI_DatabaseOpenViewW(MSIDATABASE *db,
105 LPCWSTR szQuery, MSIQUERY **pView)
107 MSIQUERY *query;
108 UINT r;
110 TRACE("%s %p\n", debugstr_w(szQuery), pView);
112 if( !szQuery)
113 return ERROR_INVALID_PARAMETER;
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;
121 msiobj_addref( &db->hdr );
122 query->row = 0;
123 query->db = db;
124 query->view = NULL;
126 r = MSI_ParseSQL( db, szQuery, &query->view );
127 if( r == ERROR_SUCCESS )
129 msiobj_addref( &query->hdr );
130 *pView = query;
133 msiobj_release( &query->hdr );
134 return r;
137 UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... )
139 LPWSTR szQuery;
140 LPCWSTR p;
141 UINT sz, rc;
142 va_list va;
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)
150 p = strchrW(p, '%');
151 if (!p)
152 break;
153 p++;
154 switch (*p)
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);
169 p++;
171 va_end(va);
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);
179 /* perform the query */
180 rc = MSI_DatabaseOpenViewW(db, szQuery, view);
181 HeapFree(GetProcessHeap(), 0, szQuery);
182 return rc;
185 UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb,
186 LPCWSTR szQuery, MSIHANDLE *phView)
188 MSIDATABASE *db;
189 MSIQUERY *query = NULL;
190 UINT ret;
192 TRACE("%s %p\n", debugstr_w(szQuery), phView);
194 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
195 if( !db )
196 return ERROR_INVALID_HANDLE;
198 ret = MSI_DatabaseOpenViewW( db, szQuery, &query );
199 if( ret == ERROR_SUCCESS )
201 *phView = alloc_msihandle( &query->hdr );
202 msiobj_release( &query->hdr );
204 msiobj_release( &db->hdr );
206 return ret;
209 UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec)
211 MSIVIEW *view;
212 MSIRECORD *rec;
213 UINT row_count = 0, col_count = 0, i, ival, ret, type;
215 TRACE("%p %p\n", query, prec );
217 view = query->view;
218 if( !view )
219 return ERROR_FUNCTION_FAILED;
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;
227 if( query->row >= row_count )
228 return ERROR_NO_MORE_ITEMS;
230 rec = MSI_CreateRecord( col_count );
231 if( !rec )
232 return ERROR_FUNCTION_FAILED;
234 for( i=1; i<=col_count; i++ )
236 ret = view->ops->get_column_info( view, i, NULL, &type );
237 if( ret )
239 ERR("Error getting column type for %d\n", i );
240 continue;
242 if (( type != MSITYPE_BINARY) && (type != (MSITYPE_BINARY |
243 MSITYPE_NULLABLE)))
245 ret = view->ops->fetch_int( view, query->row, i, &ival );
246 if( ret )
248 ERR("Error fetching data for %d\n", i );
249 continue;
251 if( ! (type & MSITYPE_VALID ) )
252 ERR("Invalid type!\n");
254 /* check if it's nul (0) - if so, don't set anything */
255 if( !ival )
256 continue;
258 if( type & MSITYPE_STRING )
260 LPWSTR sval;
262 sval = MSI_makestring( query->db, ival );
263 MSI_RecordSetStringW( rec, i, sval );
264 HeapFree( GetProcessHeap(), 0, sval );
266 else
268 if( (type & MSI_DATASIZEMASK) == 2 )
269 MSI_RecordSetInteger( rec, i, ival - (1<<15) );
270 else
271 MSI_RecordSetInteger( rec, i, ival - (1<<31) );
274 else
276 IStream *stm = NULL;
278 ret = view->ops->fetch_stream( view, query->row, i, &stm );
279 if( ( ret == ERROR_SUCCESS ) && stm )
281 MSI_RecordSetIStream( rec, i, stm );
282 IStream_Release( stm );
284 else
285 ERR("failed to get stream\n");
288 query->row ++;
290 *prec = rec;
292 return ERROR_SUCCESS;
295 UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record)
297 MSIQUERY *query;
298 MSIRECORD *rec = NULL;
299 UINT ret;
301 TRACE("%ld %p\n", hView, record);
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 )
309 *record = alloc_msihandle( &rec->hdr );
310 msiobj_release( &rec->hdr );
312 msiobj_release( &query->hdr );
313 return ret;
316 UINT MSI_ViewClose(MSIQUERY *query)
318 MSIVIEW *view;
320 TRACE("%p\n", query );
322 view = query->view;
323 if( !view )
324 return ERROR_FUNCTION_FAILED;
325 if( !view->ops->close )
326 return ERROR_FUNCTION_FAILED;
328 return view->ops->close( view );
331 UINT WINAPI MsiViewClose(MSIHANDLE hView)
333 MSIQUERY *query;
334 UINT ret;
336 TRACE("%ld\n", hView );
338 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
339 if( !query )
340 return ERROR_INVALID_HANDLE;
342 ret = MSI_ViewClose( query );
343 msiobj_release( &query->hdr );
344 return ret;
347 UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec )
349 MSIVIEW *view;
351 TRACE("%p %p\n", query, rec);
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;
360 return view->ops->execute( view, rec );
363 UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec)
365 MSIQUERY *query;
366 MSIRECORD *rec = NULL;
367 UINT ret;
369 TRACE("%ld %ld\n", hView, hRec);
371 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
372 if( !query )
373 return ERROR_INVALID_HANDLE;
375 if( hRec )
377 rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD );
378 if( !rec )
380 ret = ERROR_INVALID_HANDLE;
381 goto out;
385 msiobj_lock( &rec->hdr );
386 ret = MSI_ViewExecute( query, rec );
387 msiobj_unlock( &rec->hdr );
389 out:
390 if( query )
391 msiobj_release( &query->hdr );
392 if( rec )
393 msiobj_release( &rec->hdr );
395 return ret;
398 UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec)
400 MSIVIEW *view;
401 MSIQUERY *query;
402 MSIHANDLE handle;
403 UINT ret, i, count = 0, type;
404 LPWSTR name;
406 TRACE("%ld %d %p\n", hView, info, hRec);
408 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
409 if( !query )
410 return ERROR_INVALID_HANDLE;
412 view = query->view;
413 if( !view )
414 return ERROR_FUNCTION_FAILED;
416 if( !view->ops->get_dimensions )
417 return ERROR_FUNCTION_FAILED;
419 ret = view->ops->get_dimensions( view, NULL, &count );
420 if( ret )
421 return ret;
422 if( !count )
423 return ERROR_INVALID_PARAMETER;
425 handle = MsiCreateRecord( count );
426 if( !handle )
427 return ERROR_FUNCTION_FAILED;
429 for( i=0; i<count; i++ )
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 );
439 *hRec = handle;
441 return ERROR_SUCCESS;
444 UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb,
445 LPCSTR szTransformFile, int iErrorCond)
447 FIXME("%ld %s %d\n", hdb, debugstr_a(szTransformFile), iErrorCond);
448 return ERROR_CALL_NOT_IMPLEMENTED;
451 UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb,
452 LPCWSTR szTransformFile, int iErrorCond)
454 FIXME("%ld %s %d\n", hdb, debugstr_w(szTransformFile), iErrorCond);
455 return ERROR_CALL_NOT_IMPLEMENTED;
458 UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref,
459 LPCSTR szTransformFile, int iReserved1, int iReserved2 )
461 FIXME("%ld %ld %s %d %d\n", hdb, hdbref,
462 debugstr_a(szTransformFile), iReserved1, iReserved2);
463 return ERROR_CALL_NOT_IMPLEMENTED;
466 UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref,
467 LPCWSTR szTransformFile, int iReserved1, int iReserved2 )
469 FIXME("%ld %ld %s %d %d\n", hdb, hdbref,
470 debugstr_w(szTransformFile), iReserved1, iReserved2);
471 return ERROR_CALL_NOT_IMPLEMENTED;
474 UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
476 MSIDATABASE *db;
477 UINT r;
479 TRACE("%ld\n", hdb);
481 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
482 if( !db )
483 return ERROR_INVALID_HANDLE;
485 /* FIXME: lock the database */
487 r = MSI_CommitTables( db );
489 /* FIXME: unlock the database */
491 msiobj_release( &db->hdr );
493 return r;
496 UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb,
497 LPCSTR table, MSIHANDLE* rec)
499 FIXME("%ld %s %p\n", hdb, debugstr_a(table), rec);
500 return ERROR_CALL_NOT_IMPLEMENTED;
503 UINT WINAPI MsiDatabaseGetPrimaryKeysW(MSIHANDLE hdb,
504 LPCWSTR table, MSIHANDLE* rec)
506 FIXME("%ld %s %p\n", hdb, debugstr_w(table), rec);
507 return ERROR_CALL_NOT_IMPLEMENTED;
510 UINT WINAPI MsiViewModify(MSIHANDLE hView, MSIMODIFY eModifyMode, MSIHANDLE
511 hRecord)
513 FIXME("%ld %x %ld\n",hView, eModifyMode, hRecord);
514 return ERROR_CALL_NOT_IMPLEMENTED;
517 UINT WINAPI MsiDatabaseIsTablePersistentA(
518 MSIHANDLE hDatabase, LPSTR szTableName)
520 FIXME("%lx %s\n", hDatabase, debugstr_a(szTableName));
521 return ERROR_CALL_NOT_IMPLEMENTED;
524 UINT WINAPI MsiDatabaseIsTablePersistentW(
525 MSIHANDLE hDatabase, LPWSTR szTableName)
527 FIXME("%lx %s\n", hDatabase, debugstr_w(szTableName));
528 return ERROR_CALL_NOT_IMPLEMENTED;