summaryrefslogtreecommitdiffstats
path: root/libmsi/libmsi-query.c
diff options
context:
space:
mode:
authorMarc-André Lureau <marcandre.lureau@gmail.com>2012-12-09 23:35:30 +0100
committerPaolo Bonzini <pbonzini@redhat.com>2012-12-10 17:26:22 +0100
commit6b7407cb031cf245a4998d8c79009039ead38fc5 (patch)
tree510263de28a0319b9070ededaa2cc7c5b6d98ac0 /libmsi/libmsi-query.c
parentada3b04b2246c13449e6b32b3857d7b86a8958f8 (diff)
downloadmsitools-6b7407cb031cf245a4998d8c79009039ead38fc5.tar.gz
msitools-6b7407cb031cf245a4998d8c79009039ead38fc5.tar.xz
msitools-6b7407cb031cf245a4998d8c79009039ead38fc5.zip
Split libmsi.h to be more gobject-like
Diffstat (limited to 'libmsi/libmsi-query.c')
-rw-r--r--libmsi/libmsi-query.c542
1 files changed, 542 insertions, 0 deletions
diff --git a/libmsi/libmsi-query.c b/libmsi/libmsi-query.c
new file mode 100644
index 0000000..d020e16
--- /dev/null
+++ b/libmsi/libmsi-query.c
@@ -0,0 +1,542 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2002-2005 Mike McCormack for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "debug.h"
+#include "unicode.h"
+#include "libmsi.h"
+#include "objbase.h"
+#include "objidl.h"
+#include "msipriv.h"
+#include "winnls.h"
+
+#include "query.h"
+
+
+static void _libmsi_query_destroy( LibmsiObject *arg )
+{
+ LibmsiQuery *query = (LibmsiQuery*) arg;
+ struct list *ptr, *t;
+
+ if( query->view && query->view->ops->delete )
+ query->view->ops->delete( query->view );
+ msiobj_release( &query->db->hdr );
+
+ LIST_FOR_EACH_SAFE( ptr, t, &query->mem )
+ {
+ msi_free( ptr );
+ }
+}
+
+unsigned _libmsi_view_find_column( LibmsiView *table, const WCHAR *name, const WCHAR *table_name, unsigned *n )
+{
+ const WCHAR *col_name;
+ const WCHAR *haystack_table_name;
+ unsigned i, count, r;
+
+ r = table->ops->get_dimensions( table, NULL, &count );
+ if( r != LIBMSI_RESULT_SUCCESS )
+ return r;
+
+ for( i=1; i<=count; i++ )
+ {
+ int x;
+
+ r = table->ops->get_column_info( table, i, &col_name, NULL,
+ NULL, &haystack_table_name );
+ if( r != LIBMSI_RESULT_SUCCESS )
+ return r;
+ x = strcmpW( name, col_name );
+ if( table_name )
+ x |= strcmpW( table_name, haystack_table_name );
+ if( !x )
+ {
+ *n = i;
+ return LIBMSI_RESULT_SUCCESS;
+ }
+ }
+ return LIBMSI_RESULT_INVALID_PARAMETER;
+}
+
+LibmsiResult libmsi_database_open_query(LibmsiDatabase *db,
+ const char *szQuery, LibmsiQuery **pQuery)
+{
+ unsigned r;
+ WCHAR *szwQuery;
+
+ TRACE("%d %s %p\n", db, debugstr_a(szQuery), pQuery);
+
+ if( szQuery )
+ {
+ szwQuery = strdupAtoW( szQuery );
+ if( !szwQuery )
+ return LIBMSI_RESULT_FUNCTION_FAILED;
+ }
+ else
+ szwQuery = NULL;
+
+ if( !db )
+ return LIBMSI_RESULT_INVALID_HANDLE;
+ msiobj_addref( &db->hdr);
+
+ r = _libmsi_database_open_query( db, szwQuery, pQuery );
+ msiobj_release( &db->hdr );
+
+ msi_free( szwQuery );
+ return r;
+}
+
+unsigned _libmsi_database_open_query(LibmsiDatabase *db,
+ const WCHAR *szQuery, LibmsiQuery **pView)
+{
+ LibmsiQuery *query;
+ unsigned r;
+
+ TRACE("%s %p\n", debugstr_w(szQuery), pView);
+
+ if( !szQuery)
+ return LIBMSI_RESULT_INVALID_PARAMETER;
+
+ /* pre allocate a handle to hold a pointer to the view */
+ query = alloc_msiobject( sizeof (LibmsiQuery), _libmsi_query_destroy );
+ if( !query )
+ return LIBMSI_RESULT_FUNCTION_FAILED;
+
+ msiobj_addref( &db->hdr );
+ query->db = db;
+ list_init( &query->mem );
+
+ r = _libmsi_parse_sql( db, szQuery, &query->view, &query->mem );
+ if( r == LIBMSI_RESULT_SUCCESS )
+ {
+ msiobj_addref( &query->hdr );
+ *pView = query;
+ }
+
+ msiobj_release( &query->hdr );
+ return r;
+}
+
+unsigned _libmsi_query_open( LibmsiDatabase *db, LibmsiQuery **view, const WCHAR *fmt, ... )
+{
+ unsigned r;
+ int size = 100, res;
+ WCHAR *query;
+
+ /* construct the string */
+ for (;;)
+ {
+ va_list va;
+ query = msi_alloc( size*sizeof(WCHAR) );
+ va_start(va, fmt);
+ res = vsnprintfW(query, size, fmt, va);
+ va_end(va);
+ if (res == -1) size *= 2;
+ else if (res >= size) size = res + 1;
+ else break;
+ msi_free( query );
+ }
+ /* perform the query */
+ r = _libmsi_database_open_query(db, query, view);
+ msi_free(query);
+ return r;
+}
+
+unsigned _libmsi_query_iterate_records( LibmsiQuery *view, unsigned *count,
+ record_func func, void *param )
+{
+ LibmsiRecord *rec = NULL;
+ unsigned r, n = 0, max = 0;
+
+ r = _libmsi_query_execute( view, NULL );
+ if( r != LIBMSI_RESULT_SUCCESS )
+ return r;
+
+ if( count )
+ max = *count;
+
+ /* iterate a query */
+ for( n = 0; (max == 0) || (n < max); n++ )
+ {
+ r = _libmsi_query_fetch( view, &rec );
+ if( r != LIBMSI_RESULT_SUCCESS )
+ break;
+ if (func)
+ r = func( rec, param );
+ msiobj_release( &rec->hdr );
+ if( r != LIBMSI_RESULT_SUCCESS )
+ break;
+ }
+
+ libmsi_query_close( view );
+
+ if( count )
+ *count = n;
+
+ if( r == LIBMSI_RESULT_NO_MORE_ITEMS )
+ r = LIBMSI_RESULT_SUCCESS;
+
+ return r;
+}
+
+/* return a single record from a query */
+LibmsiRecord *_libmsi_query_get_record( LibmsiDatabase *db, const WCHAR *fmt, ... )
+{
+ LibmsiRecord *rec = NULL;
+ LibmsiQuery *view = NULL;
+ unsigned r;
+ int size = 100, res;
+ WCHAR *query;
+
+ /* construct the string */
+ for (;;)
+ {
+ va_list va;
+ query = msi_alloc( size*sizeof(WCHAR) );
+ va_start(va, fmt);
+ res = vsnprintfW(query, size, fmt, va);
+ va_end(va);
+ if (res == -1) size *= 2;
+ else if (res >= size) size = res + 1;
+ else break;
+ msi_free( query );
+ }
+ /* perform the query */
+ r = _libmsi_database_open_query(db, query, &view);
+ msi_free(query);
+
+ if( r == LIBMSI_RESULT_SUCCESS )
+ {
+ _libmsi_query_execute( view, NULL );
+ _libmsi_query_fetch( view, &rec );
+ libmsi_query_close( view );
+ msiobj_release( &view->hdr );
+ }
+ return rec;
+}
+
+unsigned msi_view_get_row(LibmsiDatabase *db, LibmsiView *view, unsigned row, LibmsiRecord **rec)
+{
+ unsigned row_count = 0, col_count = 0, i, ival, ret, type;
+
+ TRACE("%p %p %d %p\n", db, view, row, rec);
+
+ ret = view->ops->get_dimensions(view, &row_count, &col_count);
+ if (ret)
+ return ret;
+
+ if (!col_count)
+ return LIBMSI_RESULT_INVALID_PARAMETER;
+
+ if (row >= row_count)
+ return LIBMSI_RESULT_NO_MORE_ITEMS;
+
+ *rec = libmsi_record_create(col_count);
+ if (!*rec)
+ return LIBMSI_RESULT_FUNCTION_FAILED;
+
+ for (i = 1; i <= col_count; i++)
+ {
+ ret = view->ops->get_column_info(view, i, NULL, &type, NULL, NULL);
+ if (ret)
+ {
+ ERR("Error getting column type for %d\n", i);
+ continue;
+ }
+
+ if (MSITYPE_IS_BINARY(type))
+ {
+ IStream *stm = NULL;
+
+ ret = view->ops->fetch_stream(view, row, i, &stm);
+ if ((ret == LIBMSI_RESULT_SUCCESS) && stm)
+ {
+ _libmsi_record_set_IStream(*rec, i, stm);
+ IStream_Release(stm);
+ }
+ else
+ WARN("failed to get stream\n");
+
+ continue;
+ }
+
+ ret = view->ops->fetch_int(view, row, i, &ival);
+ if (ret)
+ {
+ ERR("Error fetching data for %d\n", i);
+ continue;
+ }
+
+ if (! (type & MSITYPE_VALID))
+ ERR("Invalid type!\n");
+
+ /* check if it's nul (0) - if so, don't set anything */
+ if (!ival)
+ continue;
+
+ if (type & MSITYPE_STRING)
+ {
+ const WCHAR *sval;
+
+ sval = msi_string_lookup_id(db->strings, ival);
+ _libmsi_record_set_stringW(*rec, i, sval);
+ }
+ else
+ {
+ if ((type & MSI_DATASIZEMASK) == 2)
+ libmsi_record_set_int(*rec, i, ival - (1<<15));
+ else
+ libmsi_record_set_int(*rec, i, ival - (1<<31));
+ }
+ }
+
+ return LIBMSI_RESULT_SUCCESS;
+}
+
+LibmsiResult _libmsi_query_fetch(LibmsiQuery *query, LibmsiRecord **prec)
+{
+ LibmsiView *view;
+ LibmsiResult r;
+
+ TRACE("%p %p\n", query, prec );
+
+ view = query->view;
+ if( !view )
+ return LIBMSI_RESULT_FUNCTION_FAILED;
+
+ r = msi_view_get_row(query->db, view, query->row, prec);
+ if (r == LIBMSI_RESULT_SUCCESS)
+ query->row ++;
+
+ return r;
+}
+
+LibmsiResult libmsi_query_fetch(LibmsiQuery *query, LibmsiRecord **record)
+{
+ unsigned ret;
+
+ TRACE("%d %p\n", query, record);
+
+ if( !record )
+ return LIBMSI_RESULT_INVALID_PARAMETER;
+ *record = 0;
+
+ if( !query )
+ return LIBMSI_RESULT_INVALID_HANDLE;
+ msiobj_addref( &query->hdr);
+ ret = _libmsi_query_fetch( query, record );
+ msiobj_release( &query->hdr );
+ return ret;
+}
+
+LibmsiResult libmsi_query_close(LibmsiQuery *query)
+{
+ LibmsiView *view;
+ unsigned ret;
+
+ TRACE("%p\n", query );
+
+ if( !query )
+ return LIBMSI_RESULT_INVALID_HANDLE;
+
+ msiobj_addref( &query->hdr );
+ view = query->view;
+ if( !view )
+ return LIBMSI_RESULT_FUNCTION_FAILED;
+ if( !view->ops->close )
+ return LIBMSI_RESULT_FUNCTION_FAILED;
+
+ ret = view->ops->close( view );
+ msiobj_release( &query->hdr );
+ return ret;
+}
+
+LibmsiResult _libmsi_query_execute(LibmsiQuery *query, LibmsiRecord *rec )
+{
+ LibmsiView *view;
+
+ TRACE("%p %p\n", query, rec);
+
+ view = query->view;
+ if( !view )
+ return LIBMSI_RESULT_FUNCTION_FAILED;
+ if( !view->ops->execute )
+ return LIBMSI_RESULT_FUNCTION_FAILED;
+ query->row = 0;
+
+ return view->ops->execute( view, rec );
+}
+
+LibmsiResult libmsi_query_execute(LibmsiQuery *query, LibmsiRecord *rec)
+{
+ LibmsiResult ret;
+
+ TRACE("%d %d\n", query, rec);
+
+ if( !query )
+ return LIBMSI_RESULT_INVALID_HANDLE;
+ msiobj_addref( &query->hdr );
+
+ if( rec )
+ msiobj_addref( &rec->hdr );
+
+ ret = _libmsi_query_execute( query, rec );
+
+ msiobj_release( &query->hdr );
+ if( rec )
+ msiobj_release( &rec->hdr );
+
+ return ret;
+}
+
+static unsigned msi_set_record_type_string( LibmsiRecord *rec, unsigned field,
+ unsigned type, bool temporary )
+{
+ static const WCHAR fmt[] = { '%','d',0 };
+ WCHAR szType[0x10];
+
+ if (MSITYPE_IS_BINARY(type))
+ szType[0] = 'v';
+ else if (type & MSITYPE_LOCALIZABLE)
+ szType[0] = 'l';
+ else if (type & MSITYPE_UNKNOWN)
+ szType[0] = 'f';
+ else if (type & MSITYPE_STRING)
+ {
+ if (temporary)
+ szType[0] = 'g';
+ else
+ szType[0] = 's';
+ }
+ else
+ {
+ if (temporary)
+ szType[0] = 'j';
+ else
+ szType[0] = 'i';
+ }
+
+ if (type & MSITYPE_NULLABLE)
+ szType[0] &= ~0x20;
+
+ sprintfW( &szType[1], fmt, (type&0xff) );
+
+ TRACE("type %04x -> %s\n", type, debugstr_w(szType) );
+
+ return _libmsi_record_set_stringW( rec, field, szType );
+}
+
+unsigned _libmsi_query_get_column_info( LibmsiQuery *query, LibmsiColInfo info, LibmsiRecord **prec )
+{
+ unsigned r = LIBMSI_RESULT_FUNCTION_FAILED, i, count = 0, type;
+ LibmsiRecord *rec;
+ LibmsiView *view = query->view;
+ const WCHAR *name;
+ bool temporary;
+
+ if( !view )
+ return LIBMSI_RESULT_FUNCTION_FAILED;
+
+ if( !view->ops->get_dimensions )
+ return LIBMSI_RESULT_FUNCTION_FAILED;
+
+ r = view->ops->get_dimensions( view, NULL, &count );
+ if( r != LIBMSI_RESULT_SUCCESS )
+ return r;
+ if( !count )
+ return LIBMSI_RESULT_INVALID_PARAMETER;
+
+ rec = libmsi_record_create( count );
+ if( !rec )
+ return LIBMSI_RESULT_FUNCTION_FAILED;
+
+ for( i=0; i<count; i++ )
+ {
+ name = NULL;
+ r = view->ops->get_column_info( view, i+1, &name, &type, &temporary, NULL );
+ if( r != LIBMSI_RESULT_SUCCESS )
+ continue;
+ if (info == LIBMSI_COL_INFO_NAMES)
+ _libmsi_record_set_stringW( rec, i+1, name );
+ else
+ msi_set_record_type_string( rec, i+1, type, temporary );
+ }
+ *prec = rec;
+ return LIBMSI_RESULT_SUCCESS;
+}
+
+LibmsiResult libmsi_query_get_column_info(LibmsiQuery *query, LibmsiColInfo info, LibmsiRecord **prec)
+{
+ unsigned r;
+
+ TRACE("%d %d %p\n", query, info, prec);
+
+ if( !prec )
+ return LIBMSI_RESULT_INVALID_PARAMETER;
+
+ if( info != LIBMSI_COL_INFO_NAMES && info != LIBMSI_COL_INFO_TYPES )
+ return LIBMSI_RESULT_INVALID_PARAMETER;
+
+ if( !query )
+ return LIBMSI_RESULT_INVALID_HANDLE;
+
+ msiobj_addref ( &query->hdr );
+ r = _libmsi_query_get_column_info( query, info, prec );
+ msiobj_release( &query->hdr );
+
+ return r;
+}
+
+LibmsiDBError libmsi_query_get_error( LibmsiQuery *query, char *buffer, unsigned *buflen )
+{
+ const WCHAR *column;
+ LibmsiDBError r;
+ unsigned len;
+
+ TRACE("%u %p %p\n", query, buffer, buflen);
+
+ if (!buflen)
+ return LIBMSI_DB_ERROR_INVALIDARG;
+
+ if (!query)
+ return LIBMSI_DB_ERROR_INVALIDARG;
+
+ msiobj_addref( &query->hdr);
+ if ((r = query->view->error)) column = query->view->error_column;
+ else column = szEmpty;
+
+ len = WideCharToMultiByte( CP_ACP, 0, column, -1, NULL, 0, NULL, NULL );
+ if (buffer)
+ {
+ if (*buflen >= len)
+ WideCharToMultiByte( CP_ACP, 0, column, -1, buffer, *buflen, NULL, NULL );
+ else
+ r = LIBMSI_DB_ERROR_MOREDATA;
+ }
+ *buflen = len - 1;
+ msiobj_release( &query->hdr );
+ return r;
+}