-/*\r
- * Implementation of the Microsoft Installer (msi.dll)\r
- *\r
- * Copyright 2002 Mike McCormack for CodeWeavers\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
- */\r
-\r
-#include <stdarg.h>\r
-\r
-#include "windef.h"\r
-#include "winbase.h"\r
-#include "winerror.h"\r
-#include "wine/debug.h"\r
-#include "msi.h"\r
-#include "msiquery.h"\r
-#include "objbase.h"\r
-#include "objidl.h"\r
-#include "msipriv.h"\r
-#include "winnls.h"\r
-\r
-#include "query.h"\r
-\r
-WINE_DEFAULT_DEBUG_CHANNEL(msi);\r
-\r
-typedef struct tagDISTINCTSET\r
-{\r
- UINT val;\r
- UINT count;\r
- UINT row;\r
- struct tagDISTINCTSET *nextrow;\r
- struct tagDISTINCTSET *nextcol;\r
-} DISTINCTSET;\r
-\r
-typedef struct tagMSIDISTINCTVIEW\r
-{\r
- MSIVIEW view;\r
- MSIDATABASE *db;\r
- MSIVIEW *table;\r
- UINT row_count;\r
- UINT *translation;\r
-} MSIDISTINCTVIEW;\r
-\r
-static DISTINCTSET ** distinct_insert( DISTINCTSET **x, UINT val, UINT row )\r
-{\r
- /* horrible O(n) find */\r
- while( *x )\r
- {\r
- if( (*x)->val == val )\r
- {\r
- (*x)->count++;\r
- return x;\r
- }\r
- x = &(*x)->nextrow;\r
- }\r
-\r
- /* nothing found, so add one */\r
- *x = HeapAlloc( GetProcessHeap(), 0, sizeof (DISTINCTSET) );\r
- if( *x )\r
- {\r
- (*x)->val = val;\r
- (*x)->count = 1;\r
- (*x)->row = row;\r
- (*x)->nextrow = NULL;\r
- (*x)->nextcol = NULL;\r
- }\r
- return x;\r
-}\r
-\r
-static void distinct_free( DISTINCTSET *x )\r
-{\r
- while( x )\r
- {\r
- DISTINCTSET *next = x->nextrow;\r
- distinct_free( x->nextcol );\r
- HeapFree( GetProcessHeap(), 0, x );\r
- x = next;\r
- }\r
-}\r
-\r
-static UINT DISTINCT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )\r
-{\r
- MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;\r
-\r
- TRACE("%p %d %d %p\n", dv, row, col, val );\r
-\r
- if( !dv->table )\r
- return ERROR_FUNCTION_FAILED;\r
-\r
- if( row >= dv->row_count )\r
- return ERROR_INVALID_PARAMETER;\r
-\r
- row = dv->translation[ row ];\r
-\r
- return dv->table->ops->fetch_int( dv->table, row, col, val );\r
-}\r
-\r
-static UINT DISTINCT_execute( struct tagMSIVIEW *view, MSIRECORD *record )\r
-{\r
- MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;\r
- UINT r, i, j, r_count, c_count;\r
- DISTINCTSET *rowset = NULL;\r
-\r
- TRACE("%p %p\n", dv, record);\r
-\r
- if( !dv->table )\r
- return ERROR_FUNCTION_FAILED;\r
-\r
- r = dv->table->ops->execute( dv->table, record );\r
- if( r != ERROR_SUCCESS )\r
- return r;\r
-\r
- r = dv->table->ops->get_dimensions( dv->table, &r_count, &c_count );\r
- if( r != ERROR_SUCCESS )\r
- return r;\r
-\r
- dv->translation = HeapAlloc( GetProcessHeap(), 0, r_count*sizeof(UINT) );\r
- if( !dv->translation )\r
- return ERROR_FUNCTION_FAILED;\r
-\r
- /* build it */\r
- for( i=0; i<r_count; i++ )\r
- {\r
- DISTINCTSET **x = &rowset;\r
-\r
- for( j=1; j<=c_count; j++ )\r
- {\r
- UINT val = 0;\r
- r = dv->table->ops->fetch_int( dv->table, i, j, &val );\r
- if( r != ERROR_SUCCESS )\r
- {\r
- ERR("Failed to fetch int at %d %d\n", i, j );\r
- distinct_free( rowset );\r
- return r;\r
- }\r
- x = distinct_insert( x, val, i );\r
- if( !*x )\r
- {\r
- ERR("Failed to insert at %d %d\n", i, j );\r
- distinct_free( rowset );\r
- return ERROR_FUNCTION_FAILED;\r
- }\r
- if( j != c_count )\r
- x = &(*x)->nextcol;\r
- }\r
-\r
- /* check if it was distinct and if so, include it */\r
- if( (*x)->row == i )\r
- {\r
- TRACE("Row %d -> %d\n", dv->row_count, i);\r
- dv->translation[dv->row_count++] = i;\r
- }\r
- }\r
-\r
- distinct_free( rowset );\r
-\r
- return ERROR_SUCCESS;\r
-}\r
-\r
-static UINT DISTINCT_close( struct tagMSIVIEW *view )\r
-{\r
- MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;\r
-\r
- TRACE("%p\n", dv );\r
-\r
- if( !dv->table )\r
- return ERROR_FUNCTION_FAILED;\r
-\r
- HeapFree( GetProcessHeap(), 0, dv->translation );\r
- dv->translation = NULL;\r
- dv->row_count = 0;\r
-\r
- return dv->table->ops->close( dv->table );\r
-}\r
-\r
-static UINT DISTINCT_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )\r
-{\r
- MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;\r
-\r
- TRACE("%p %p %p\n", dv, rows, cols );\r
-\r
- if( !dv->table )\r
- return ERROR_FUNCTION_FAILED;\r
-\r
- if( rows )\r
- {\r
- if( !dv->translation )\r
- return ERROR_FUNCTION_FAILED;\r
- *rows = dv->row_count;\r
- }\r
-\r
- return dv->table->ops->get_dimensions( dv->table, NULL, cols );\r
-}\r
-\r
-static UINT DISTINCT_get_column_info( struct tagMSIVIEW *view,\r
- UINT n, LPWSTR *name, UINT *type )\r
-{\r
- MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;\r
-\r
- TRACE("%p %d %p %p\n", dv, n, name, type );\r
-\r
- if( !dv->table )\r
- return ERROR_FUNCTION_FAILED;\r
-\r
- return dv->table->ops->get_column_info( dv->table, n, name, type );\r
-}\r
-\r
-static UINT DISTINCT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,\r
- MSIRECORD *rec )\r
-{\r
- MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;\r
-\r
- TRACE("%p %d %p\n", dv, eModifyMode, rec );\r
-\r
- if( !dv->table )\r
- return ERROR_FUNCTION_FAILED;\r
-\r
- return dv->table->ops->modify( dv->table, eModifyMode, rec );\r
-}\r
-\r
-static UINT DISTINCT_delete( struct tagMSIVIEW *view )\r
-{\r
- MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;\r
-\r
- TRACE("%p\n", dv );\r
-\r
- if( dv->table )\r
- dv->table->ops->delete( dv->table );\r
-\r
- HeapFree( GetProcessHeap(), 0, dv->translation );\r
- msiobj_release( &dv->db->hdr );\r
- HeapFree( GetProcessHeap(), 0, dv );\r
-\r
- return ERROR_SUCCESS;\r
-}\r
-\r
-\r
-MSIVIEWOPS distinct_ops =\r
-{\r
- DISTINCT_fetch_int,\r
- NULL,\r
- NULL,\r
- NULL,\r
- DISTINCT_execute,\r
- DISTINCT_close,\r
- DISTINCT_get_dimensions,\r
- DISTINCT_get_column_info,\r
- DISTINCT_modify,\r
- DISTINCT_delete\r
-};\r
-\r
-UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )\r
-{\r
- MSIDISTINCTVIEW *dv = NULL;\r
- UINT count = 0, r;\r
-\r
- TRACE("%p\n", dv );\r
-\r
- r = table->ops->get_dimensions( table, NULL, &count );\r
- if( r != ERROR_SUCCESS )\r
- {\r
- ERR("can't get table dimensions\n");\r
- return r;\r
- }\r
-\r
- dv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *dv );\r
- if( !dv )\r
- return ERROR_FUNCTION_FAILED;\r
- \r
- /* fill the structure */\r
- dv->view.ops = &distinct_ops;\r
- msiobj_addref( &db->hdr );\r
- dv->db = db;\r
- dv->table = table;\r
- dv->translation = NULL;\r
- dv->row_count = 0;\r
- *view = (MSIVIEW*) dv;\r
-\r
- return ERROR_SUCCESS;\r
-}\r
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "wine/debug.h"
+#include "msi.h"
+#include "msiquery.h"
+#include "objbase.h"
+#include "objidl.h"
+#include "msipriv.h"
+#include "winnls.h"
+
+#include "query.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+typedef struct tagDISTINCTSET
+{
+ UINT val;
+ UINT count;
+ UINT row;
+ struct tagDISTINCTSET *nextrow;
+ struct tagDISTINCTSET *nextcol;
+} DISTINCTSET;
+
+typedef struct tagMSIDISTINCTVIEW
+{
+ MSIVIEW view;
+ MSIDATABASE *db;
+ MSIVIEW *table;
+ UINT row_count;
+ UINT *translation;
+} MSIDISTINCTVIEW;
+
+static DISTINCTSET ** distinct_insert( DISTINCTSET **x, UINT val, UINT row )
+{
+ /* horrible O(n) find */
+ while( *x )
+ {
+ if( (*x)->val == val )
+ {
+ (*x)->count++;
+ return x;
+ }
+ x = &(*x)->nextrow;
+ }
+
+ /* nothing found, so add one */
+ *x = HeapAlloc( GetProcessHeap(), 0, sizeof (DISTINCTSET) );
+ if( *x )
+ {
+ (*x)->val = val;
+ (*x)->count = 1;
+ (*x)->row = row;
+ (*x)->nextrow = NULL;
+ (*x)->nextcol = NULL;
+ }
+ return x;
+}
+
+static void distinct_free( DISTINCTSET *x )
+{
+ while( x )
+ {
+ DISTINCTSET *next = x->nextrow;
+ distinct_free( x->nextcol );
+ HeapFree( GetProcessHeap(), 0, x );
+ x = next;
+ }
+}
+
+static UINT DISTINCT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
+{
+ MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
+
+ TRACE("%p %d %d %p\n", dv, row, col, val );
+
+ if( !dv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ if( row >= dv->row_count )
+ return ERROR_INVALID_PARAMETER;
+
+ row = dv->translation[ row ];
+
+ return dv->table->ops->fetch_int( dv->table, row, col, val );
+}
+
+static UINT DISTINCT_execute( struct tagMSIVIEW *view, MSIRECORD *record )
+{
+ MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
+ UINT r, i, j, r_count, c_count;
+ DISTINCTSET *rowset = NULL;
+
+ TRACE("%p %p\n", dv, record);
+
+ if( !dv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ r = dv->table->ops->execute( dv->table, record );
+ if( r != ERROR_SUCCESS )
+ return r;
+
+ r = dv->table->ops->get_dimensions( dv->table, &r_count, &c_count );
+ if( r != ERROR_SUCCESS )
+ return r;
+
+ dv->translation = HeapAlloc( GetProcessHeap(), 0, r_count*sizeof(UINT) );
+ if( !dv->translation )
+ return ERROR_FUNCTION_FAILED;
+
+ /* build it */
+ for( i=0; i<r_count; i++ )
+ {
+ DISTINCTSET **x = &rowset;
+
+ for( j=1; j<=c_count; j++ )
+ {
+ UINT val = 0;
+ r = dv->table->ops->fetch_int( dv->table, i, j, &val );
+ if( r != ERROR_SUCCESS )
+ {
+ ERR("Failed to fetch int at %d %d\n", i, j );
+ distinct_free( rowset );
+ return r;
+ }
+ x = distinct_insert( x, val, i );
+ if( !*x )
+ {
+ ERR("Failed to insert at %d %d\n", i, j );
+ distinct_free( rowset );
+ return ERROR_FUNCTION_FAILED;
+ }
+ if( j != c_count )
+ x = &(*x)->nextcol;
+ }
+
+ /* check if it was distinct and if so, include it */
+ if( (*x)->row == i )
+ {
+ TRACE("Row %d -> %d\n", dv->row_count, i);
+ dv->translation[dv->row_count++] = i;
+ }
+ }
+
+ distinct_free( rowset );
+
+ return ERROR_SUCCESS;
+}
+
+static UINT DISTINCT_close( struct tagMSIVIEW *view )
+{
+ MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
+
+ TRACE("%p\n", dv );
+
+ if( !dv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ HeapFree( GetProcessHeap(), 0, dv->translation );
+ dv->translation = NULL;
+ dv->row_count = 0;
+
+ return dv->table->ops->close( dv->table );
+}
+
+static UINT DISTINCT_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
+{
+ MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
+
+ TRACE("%p %p %p\n", dv, rows, cols );
+
+ if( !dv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ if( rows )
+ {
+ if( !dv->translation )
+ return ERROR_FUNCTION_FAILED;
+ *rows = dv->row_count;
+ }
+
+ return dv->table->ops->get_dimensions( dv->table, NULL, cols );
+}
+
+static UINT DISTINCT_get_column_info( struct tagMSIVIEW *view,
+ UINT n, LPWSTR *name, UINT *type )
+{
+ MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
+
+ TRACE("%p %d %p %p\n", dv, n, name, type );
+
+ if( !dv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ return dv->table->ops->get_column_info( dv->table, n, name, type );
+}
+
+static UINT DISTINCT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
+ MSIRECORD *rec )
+{
+ MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
+
+ TRACE("%p %d %p\n", dv, eModifyMode, rec );
+
+ if( !dv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ return dv->table->ops->modify( dv->table, eModifyMode, rec );
+}
+
+static UINT DISTINCT_delete( struct tagMSIVIEW *view )
+{
+ MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
+
+ TRACE("%p\n", dv );
+
+ if( dv->table )
+ dv->table->ops->delete( dv->table );
+
+ HeapFree( GetProcessHeap(), 0, dv->translation );
+ msiobj_release( &dv->db->hdr );
+ HeapFree( GetProcessHeap(), 0, dv );
+
+ return ERROR_SUCCESS;
+}
+
+
+MSIVIEWOPS distinct_ops =
+{
+ DISTINCT_fetch_int,
+ NULL,
+ NULL,
+ NULL,
+ DISTINCT_execute,
+ DISTINCT_close,
+ DISTINCT_get_dimensions,
+ DISTINCT_get_column_info,
+ DISTINCT_modify,
+ DISTINCT_delete
+};
+
+UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )
+{
+ MSIDISTINCTVIEW *dv = NULL;
+ UINT count = 0, r;
+
+ TRACE("%p\n", dv );
+
+ r = table->ops->get_dimensions( table, NULL, &count );
+ if( r != ERROR_SUCCESS )
+ {
+ ERR("can't get table dimensions\n");
+ return r;
+ }
+
+ dv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *dv );
+ if( !dv )
+ return ERROR_FUNCTION_FAILED;
+
+ /* fill the structure */
+ dv->view.ops = &distinct_ops;
+ msiobj_addref( &db->hdr );
+ dv->db = db;
+ dv->table = table;
+ dv->translation = NULL;
+ dv->row_count = 0;
+ *view = (MSIVIEW*) dv;
+
+ return ERROR_SUCCESS;
+}