Added memory allocation inline functions (part 2).
[wine/wine-kai.git] / dlls / msi / msiquery.c
bloba18f4dfd15b8f1658747b593e2c0e4e8e4114f27
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2002-2005 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 static void MSI_CloseView( MSIOBJECTHDR *arg )
43 MSIQUERY *query = (MSIQUERY*) arg;
44 struct list *ptr, *t;
46 if( query->view && query->view->ops->delete )
47 query->view->ops->delete( query->view );
48 msiobj_release( &query->db->hdr );
50 LIST_FOR_EACH_SAFE( ptr, t, &query->mem )
52 msi_free( ptr );
56 UINT VIEW_find_column( MSIVIEW *table, LPCWSTR name, UINT *n )
58 LPWSTR col_name;
59 UINT i, count, r;
61 r = table->ops->get_dimensions( table, NULL, &count );
62 if( r != ERROR_SUCCESS )
63 return r;
65 for( i=1; i<=count; i++ )
67 INT x;
69 col_name = NULL;
70 r = table->ops->get_column_info( table, i, &col_name, NULL );
71 if( r != ERROR_SUCCESS )
72 return r;
73 x = lstrcmpW( name, col_name );
74 msi_free( col_name );
75 if( !x )
77 *n = i;
78 return ERROR_SUCCESS;
82 return ERROR_INVALID_PARAMETER;
85 UINT WINAPI MsiDatabaseOpenViewA(MSIHANDLE hdb,
86 LPCSTR szQuery, MSIHANDLE *phView)
88 UINT r;
89 LPWSTR szwQuery;
91 TRACE("%ld %s %p\n", hdb, debugstr_a(szQuery), phView);
93 if( szQuery )
95 szwQuery = strdupAtoW( szQuery );
96 if( !szwQuery )
97 return ERROR_FUNCTION_FAILED;
99 else
100 szwQuery = NULL;
102 r = MsiDatabaseOpenViewW( hdb, szwQuery, phView);
104 msi_free( szwQuery );
105 return r;
108 UINT MSI_DatabaseOpenViewW(MSIDATABASE *db,
109 LPCWSTR szQuery, MSIQUERY **pView)
111 MSIQUERY *query;
112 UINT r;
114 TRACE("%s %p\n", debugstr_w(szQuery), pView);
116 if( !szQuery)
117 return ERROR_INVALID_PARAMETER;
119 /* pre allocate a handle to hold a pointer to the view */
120 query = alloc_msiobject( MSIHANDLETYPE_VIEW, sizeof (MSIQUERY),
121 MSI_CloseView );
122 if( !query )
123 return ERROR_FUNCTION_FAILED;
125 msiobj_addref( &db->hdr );
126 query->row = 0;
127 query->db = db;
128 query->view = NULL;
129 list_init( &query->mem );
131 r = MSI_ParseSQL( db, szQuery, &query->view, &query->mem );
132 if( r == ERROR_SUCCESS )
134 msiobj_addref( &query->hdr );
135 *pView = query;
138 msiobj_release( &query->hdr );
139 return r;
142 UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... )
144 UINT r;
145 int size = 100, res;
146 LPWSTR query;
148 /* construct the string */
149 for (;;)
151 va_list va;
152 query = msi_alloc( size*sizeof(WCHAR) );
153 va_start(va, fmt);
154 res = vsnprintfW(query, size, fmt, va);
155 va_end(va);
156 if (res == -1) size *= 2;
157 else if (res >= size) size = res + 1;
158 else break;
159 msi_free( query );
161 /* perform the query */
162 r = MSI_DatabaseOpenViewW(db, query, view);
163 msi_free(query);
164 return r;
167 UINT MSI_IterateRecords( MSIQUERY *view, DWORD *count,
168 record_func func, LPVOID param )
170 MSIRECORD *rec = NULL;
171 UINT r, n = 0, max = 0;
173 r = MSI_ViewExecute( view, NULL );
174 if( r != ERROR_SUCCESS )
175 return r;
177 if( count )
178 max = *count;
180 /* iterate a query */
181 for( n = 0; (max == 0) || (n < max); n++ )
183 r = MSI_ViewFetch( view, &rec );
184 if( r != ERROR_SUCCESS )
185 break;
186 r = func( rec, param );
187 msiobj_release( &rec->hdr );
188 if( r != ERROR_SUCCESS )
189 break;
192 MSI_ViewClose( view );
194 if( count )
195 *count = n;
197 if( r == ERROR_NO_MORE_ITEMS )
198 r = ERROR_SUCCESS;
200 return r;
203 /* return a single record from a query */
204 MSIRECORD *MSI_QueryGetRecord( MSIDATABASE *db, LPCWSTR fmt, ... )
206 MSIRECORD *rec = NULL;
207 MSIQUERY *view = NULL;
208 UINT r;
209 int size = 100, res;
210 LPWSTR query;
212 /* construct the string */
213 for (;;)
215 va_list va;
216 query = msi_alloc( size*sizeof(WCHAR) );
217 va_start(va, fmt);
218 res = vsnprintfW(query, size, fmt, va);
219 va_end(va);
220 if (res == -1) size *= 2;
221 else if (res >= size) size = res + 1;
222 else break;
223 msi_free( query );
225 /* perform the query */
226 r = MSI_DatabaseOpenViewW(db, query, &view);
227 msi_free(query);
229 if( r == ERROR_SUCCESS )
231 MSI_ViewExecute( view, NULL );
232 MSI_ViewFetch( view, &rec );
233 MSI_ViewClose( view );
234 msiobj_release( &view->hdr );
236 return rec;
239 UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb,
240 LPCWSTR szQuery, MSIHANDLE *phView)
242 MSIDATABASE *db;
243 MSIQUERY *query = NULL;
244 UINT ret;
246 TRACE("%s %p\n", debugstr_w(szQuery), phView);
248 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
249 if( !db )
250 return ERROR_INVALID_HANDLE;
252 ret = MSI_DatabaseOpenViewW( db, szQuery, &query );
253 if( ret == ERROR_SUCCESS )
255 *phView = alloc_msihandle( &query->hdr );
256 msiobj_release( &query->hdr );
258 msiobj_release( &db->hdr );
260 return ret;
263 UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec)
265 MSIVIEW *view;
266 MSIRECORD *rec;
267 UINT row_count = 0, col_count = 0, i, ival, ret, type;
269 TRACE("%p %p\n", query, prec );
271 view = query->view;
272 if( !view )
273 return ERROR_FUNCTION_FAILED;
275 ret = view->ops->get_dimensions( view, &row_count, &col_count );
276 if( ret )
277 return ret;
278 if( !col_count )
279 return ERROR_INVALID_PARAMETER;
281 if( query->row >= row_count )
282 return ERROR_NO_MORE_ITEMS;
284 rec = MSI_CreateRecord( col_count );
285 if( !rec )
286 return ERROR_FUNCTION_FAILED;
288 for( i=1; i<=col_count; i++ )
290 ret = view->ops->get_column_info( view, i, NULL, &type );
291 if( ret )
293 ERR("Error getting column type for %d\n", i );
294 continue;
296 if (( type != MSITYPE_BINARY) && (type != (MSITYPE_BINARY |
297 MSITYPE_NULLABLE)))
299 ret = view->ops->fetch_int( view, query->row, i, &ival );
300 if( ret )
302 ERR("Error fetching data for %d\n", i );
303 continue;
305 if( ! (type & MSITYPE_VALID ) )
306 ERR("Invalid type!\n");
308 /* check if it's nul (0) - if so, don't set anything */
309 if( !ival )
310 continue;
312 if( type & MSITYPE_STRING )
314 LPWSTR sval;
316 sval = MSI_makestring( query->db, ival );
317 MSI_RecordSetStringW( rec, i, sval );
318 msi_free( sval );
320 else
322 if( (type & MSI_DATASIZEMASK) == 2 )
323 MSI_RecordSetInteger( rec, i, ival - (1<<15) );
324 else
325 MSI_RecordSetInteger( rec, i, ival - (1<<31) );
328 else
330 IStream *stm = NULL;
332 ret = view->ops->fetch_stream( view, query->row, i, &stm );
333 if( ( ret == ERROR_SUCCESS ) && stm )
335 MSI_RecordSetIStream( rec, i, stm );
336 IStream_Release( stm );
338 else
339 ERR("failed to get stream\n");
342 query->row ++;
344 *prec = rec;
346 return ERROR_SUCCESS;
349 UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record)
351 MSIQUERY *query;
352 MSIRECORD *rec = NULL;
353 UINT ret;
355 TRACE("%ld %p\n", hView, record);
357 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
358 if( !query )
359 return ERROR_INVALID_HANDLE;
360 ret = MSI_ViewFetch( query, &rec );
361 if( ret == ERROR_SUCCESS )
363 *record = alloc_msihandle( &rec->hdr );
364 msiobj_release( &rec->hdr );
366 msiobj_release( &query->hdr );
367 return ret;
370 UINT MSI_ViewClose(MSIQUERY *query)
372 MSIVIEW *view;
374 TRACE("%p\n", query );
376 view = query->view;
377 if( !view )
378 return ERROR_FUNCTION_FAILED;
379 if( !view->ops->close )
380 return ERROR_FUNCTION_FAILED;
382 return view->ops->close( view );
385 UINT WINAPI MsiViewClose(MSIHANDLE hView)
387 MSIQUERY *query;
388 UINT ret;
390 TRACE("%ld\n", hView );
392 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
393 if( !query )
394 return ERROR_INVALID_HANDLE;
396 ret = MSI_ViewClose( query );
397 msiobj_release( &query->hdr );
398 return ret;
401 UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec )
403 MSIVIEW *view;
405 TRACE("%p %p\n", query, rec);
407 view = query->view;
408 if( !view )
409 return ERROR_FUNCTION_FAILED;
410 if( !view->ops->execute )
411 return ERROR_FUNCTION_FAILED;
412 query->row = 0;
414 return view->ops->execute( view, rec );
417 UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec)
419 MSIQUERY *query;
420 MSIRECORD *rec = NULL;
421 UINT ret;
423 TRACE("%ld %ld\n", hView, hRec);
425 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
426 if( !query )
427 return ERROR_INVALID_HANDLE;
429 if( hRec )
431 rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD );
432 if( !rec )
434 ret = ERROR_INVALID_HANDLE;
435 goto out;
439 msiobj_lock( &rec->hdr );
440 ret = MSI_ViewExecute( query, rec );
441 msiobj_unlock( &rec->hdr );
443 out:
444 msiobj_release( &query->hdr );
445 if( rec )
446 msiobj_release( &rec->hdr );
448 return ret;
451 UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec)
453 MSIVIEW *view = NULL;
454 MSIQUERY *query = NULL;
455 MSIRECORD *rec = NULL;
456 UINT r = ERROR_FUNCTION_FAILED, i, count = 0, type;
457 LPWSTR name;
459 TRACE("%ld %d %p\n", hView, info, hRec);
461 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
462 if( !query )
463 return ERROR_INVALID_HANDLE;
465 view = query->view;
466 if( !view )
467 goto out;
469 if( !view->ops->get_dimensions )
470 goto out;
472 r = view->ops->get_dimensions( view, NULL, &count );
473 if( r )
474 goto out;
475 if( !count )
477 r = ERROR_INVALID_PARAMETER;
478 goto out;
481 rec = MSI_CreateRecord( count );
482 if( !rec )
484 r = ERROR_FUNCTION_FAILED;
485 goto out;
488 for( i=0; i<count; i++ )
490 name = NULL;
491 r = view->ops->get_column_info( view, i+1, &name, &type );
492 if( r != ERROR_SUCCESS )
493 continue;
494 MSI_RecordSetStringW( rec, i+1, name );
495 msi_free( name );
498 *hRec = alloc_msihandle( &rec->hdr );
500 out:
501 msiobj_release( &query->hdr );
502 if( rec )
503 msiobj_release( &rec->hdr );
505 return r;
508 UINT WINAPI MsiViewModify( MSIHANDLE hView, MSIMODIFY eModifyMode,
509 MSIHANDLE hRecord)
511 MSIVIEW *view = NULL;
512 MSIQUERY *query = NULL;
513 MSIRECORD *rec = NULL;
514 UINT r = ERROR_FUNCTION_FAILED;
516 TRACE("%ld %x %ld\n", hView, eModifyMode, hRecord);
518 query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
519 if( !query )
520 return ERROR_INVALID_HANDLE;
522 view = query->view;
523 if( !view )
524 goto out;
526 if( !view->ops->modify )
527 goto out;
529 rec = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
530 if( !rec )
532 r = ERROR_INVALID_HANDLE;
533 goto out;
536 r = view->ops->modify( view, eModifyMode, rec );
538 out:
539 msiobj_release( &query->hdr );
540 if( rec )
541 msiobj_release( &rec->hdr );
543 return r;
546 MSIDBERROR WINAPI MsiViewGetErrorW( MSIHANDLE handle, LPWSTR szColumnNameBuffer,
547 DWORD *pcchBuf )
549 MSIQUERY *query = NULL;
550 static const WCHAR szError[] = { 0 };
551 MSIDBERROR r = MSIDBERROR_NOERROR;
552 int len;
554 FIXME("%ld %p %p - returns empty error string\n",
555 handle, szColumnNameBuffer, pcchBuf );
557 if( !pcchBuf )
558 return MSIDBERROR_INVALIDARG;
560 query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
561 if( !query )
562 return MSIDBERROR_INVALIDARG;
564 len = lstrlenW( szError );
565 if( szColumnNameBuffer )
567 if( *pcchBuf > len )
568 lstrcpyW( szColumnNameBuffer, szError );
569 else
570 r = MSIDBERROR_MOREDATA;
572 *pcchBuf = len;
574 msiobj_release( &query->hdr );
575 return r;
578 MSIDBERROR WINAPI MsiViewGetErrorA( MSIHANDLE handle, LPSTR szColumnNameBuffer,
579 DWORD *pcchBuf )
581 static const CHAR szError[] = { 0 };
582 MSIQUERY *query = NULL;
583 MSIDBERROR r = MSIDBERROR_NOERROR;
584 int len;
586 FIXME("%ld %p %p - returns empty error string\n",
587 handle, szColumnNameBuffer, pcchBuf );
589 if( !pcchBuf )
590 return MSIDBERROR_INVALIDARG;
592 query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
593 if( !query )
594 return MSIDBERROR_INVALIDARG;
596 len = lstrlenA( szError );
597 if( szColumnNameBuffer )
599 if( *pcchBuf > len )
600 lstrcpyA( szColumnNameBuffer, szError );
601 else
602 r = MSIDBERROR_MOREDATA;
604 *pcchBuf = len;
606 msiobj_release( &query->hdr );
607 return r;
610 UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb,
611 LPCSTR szTransformFile, int iErrorCond)
613 FIXME("%ld %s %d\n", hdb, debugstr_a(szTransformFile), iErrorCond);
614 return ERROR_CALL_NOT_IMPLEMENTED;
617 UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb,
618 LPCWSTR szTransformFile, int iErrorCond)
620 FIXME("%ld %s %d\n", hdb, debugstr_w(szTransformFile), iErrorCond);
621 return ERROR_CALL_NOT_IMPLEMENTED;
624 UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref,
625 LPCSTR szTransformFile, int iReserved1, int iReserved2 )
627 FIXME("%ld %ld %s %d %d\n", hdb, hdbref,
628 debugstr_a(szTransformFile), iReserved1, iReserved2);
629 return ERROR_CALL_NOT_IMPLEMENTED;
632 UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref,
633 LPCWSTR szTransformFile, int iReserved1, int iReserved2 )
635 FIXME("%ld %ld %s %d %d\n", hdb, hdbref,
636 debugstr_w(szTransformFile), iReserved1, iReserved2);
637 return ERROR_CALL_NOT_IMPLEMENTED;
640 UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
642 MSIDATABASE *db;
643 UINT r;
645 TRACE("%ld\n", hdb);
647 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
648 if( !db )
649 return ERROR_INVALID_HANDLE;
651 /* FIXME: lock the database */
653 r = MSI_CommitTables( db );
655 /* FIXME: unlock the database */
657 msiobj_release( &db->hdr );
659 return r;
662 struct msi_primary_key_record_info
664 DWORD n;
665 MSIRECORD *rec;
668 static UINT msi_primary_key_iterator( MSIRECORD *rec, LPVOID param )
670 struct msi_primary_key_record_info *info = param;
671 LPCWSTR name;
672 DWORD type;
674 type = MSI_RecordGetInteger( rec, 4 );
675 if( type & MSITYPE_KEY )
677 info->n++;
678 if( info->rec )
680 name = MSI_RecordGetString( rec, 3 );
681 MSI_RecordSetStringW( info->rec, info->n, name );
685 return ERROR_SUCCESS;
688 UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *db,
689 LPCWSTR table, MSIRECORD **prec )
691 static const WCHAR sql[] = {
692 's','e','l','e','c','t',' ','*',' ',
693 'f','r','o','m',' ','`','_','C','o','l','u','m','n','s','`',' ',
694 'w','h','e','r','e',' ',
695 '`','T','a','b','l','e','`',' ','=',' ','\'','%','s','\'',0 };
696 struct msi_primary_key_record_info info;
697 MSIQUERY *query = NULL;
698 MSIVIEW *view;
699 UINT r;
701 r = MSI_OpenQuery( db, &query, sql, table );
702 if( r != ERROR_SUCCESS )
703 return r;
705 view = query->view;
707 /* count the number of primary key records */
708 info.n = 0;
709 info.rec = 0;
710 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
711 if( r == ERROR_SUCCESS )
713 TRACE("Found %ld primary keys\n", info.n );
715 /* allocate a record and fill in the names of the tables */
716 info.rec = MSI_CreateRecord( info.n );
717 info.n = 0;
718 r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info );
719 if( r == ERROR_SUCCESS )
720 *prec = info.rec;
721 else
722 msiobj_release( &info.rec->hdr );
724 msiobj_release( &query->hdr );
726 return r;
729 UINT WINAPI MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb,
730 LPCWSTR table, MSIHANDLE* phRec )
732 MSIRECORD *rec = NULL;
733 MSIDATABASE *db;
734 UINT r;
736 TRACE("%ld %s %p\n", hdb, debugstr_w(table), phRec);
738 db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
739 if( !db )
740 return ERROR_INVALID_HANDLE;
742 r = MSI_DatabaseGetPrimaryKeys( db, table, &rec );
743 if( r == ERROR_SUCCESS )
745 *phRec = alloc_msihandle( &rec->hdr );
746 msiobj_release( &rec->hdr );
748 msiobj_release( &db->hdr );
750 return r;
753 UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb,
754 LPCSTR table, MSIHANDLE* phRec)
756 LPWSTR szwTable = NULL;
757 UINT r;
759 TRACE("%ld %s %p\n", hdb, debugstr_a(table), phRec);
761 if( table )
763 szwTable = strdupAtoW( table );
764 if( !szwTable )
765 return ERROR_OUTOFMEMORY;
767 r = MsiDatabaseGetPrimaryKeysW( hdb, szwTable, phRec );
768 msi_free( szwTable );
770 return r;
773 UINT WINAPI MsiDatabaseIsTablePersistentA(
774 MSIHANDLE hDatabase, LPSTR szTableName)
776 FIXME("%lx %s\n", hDatabase, debugstr_a(szTableName));
777 return ERROR_CALL_NOT_IMPLEMENTED;
780 UINT WINAPI MsiDatabaseIsTablePersistentW(
781 MSIHANDLE hDatabase, LPWSTR szTableName)
783 FIXME("%lx %s\n", hDatabase, debugstr_w(szTableName));
784 return ERROR_CALL_NOT_IMPLEMENTED;