2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2002 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(msidb
);
38 typedef struct tagDISTINCTSET
43 struct tagDISTINCTSET
*nextrow
;
44 struct tagDISTINCTSET
*nextcol
;
47 typedef struct tagMSIDISTINCTVIEW
56 static DISTINCTSET
** distinct_insert( DISTINCTSET
**x
, UINT val
, UINT row
)
58 /* horrible O(n) find */
61 if( (*x
)->val
== val
)
69 /* nothing found, so add one */
70 *x
= msi_alloc( sizeof (DISTINCTSET
) );
82 static void distinct_free( DISTINCTSET
*x
)
86 DISTINCTSET
*next
= x
->nextrow
;
87 distinct_free( x
->nextcol
);
93 static UINT
DISTINCT_fetch_int( struct tagMSIVIEW
*view
, UINT row
, UINT col
, UINT
*val
)
95 MSIDISTINCTVIEW
*dv
= (MSIDISTINCTVIEW
*)view
;
97 TRACE("%p %d %d %p\n", dv
, row
, col
, val
);
100 return ERROR_FUNCTION_FAILED
;
102 if( row
>= dv
->row_count
)
103 return ERROR_INVALID_PARAMETER
;
105 row
= dv
->translation
[ row
];
107 return dv
->table
->ops
->fetch_int( dv
->table
, row
, col
, val
);
110 static UINT
DISTINCT_execute( struct tagMSIVIEW
*view
, MSIRECORD
*record
)
112 MSIDISTINCTVIEW
*dv
= (MSIDISTINCTVIEW
*)view
;
113 UINT r
, i
, j
, r_count
, c_count
;
114 DISTINCTSET
*rowset
= NULL
;
116 TRACE("%p %p\n", dv
, record
);
119 return ERROR_FUNCTION_FAILED
;
121 r
= dv
->table
->ops
->execute( dv
->table
, record
);
122 if( r
!= ERROR_SUCCESS
)
125 r
= dv
->table
->ops
->get_dimensions( dv
->table
, &r_count
, &c_count
);
126 if( r
!= ERROR_SUCCESS
)
129 dv
->translation
= msi_alloc( r_count
*sizeof(UINT
) );
130 if( !dv
->translation
)
131 return ERROR_FUNCTION_FAILED
;
134 for( i
=0; i
<r_count
; i
++ )
136 DISTINCTSET
**x
= &rowset
;
138 for( j
=1; j
<=c_count
; j
++ )
141 r
= dv
->table
->ops
->fetch_int( dv
->table
, i
, j
, &val
);
142 if( r
!= ERROR_SUCCESS
)
144 ERR("Failed to fetch int at %d %d\n", i
, j
);
145 distinct_free( rowset
);
148 x
= distinct_insert( x
, val
, i
);
151 ERR("Failed to insert at %d %d\n", i
, j
);
152 distinct_free( rowset
);
153 return ERROR_FUNCTION_FAILED
;
159 /* check if it was distinct and if so, include it */
162 TRACE("Row %d -> %d\n", dv
->row_count
, i
);
163 dv
->translation
[dv
->row_count
++] = i
;
167 distinct_free( rowset
);
169 return ERROR_SUCCESS
;
172 static UINT
DISTINCT_close( struct tagMSIVIEW
*view
)
174 MSIDISTINCTVIEW
*dv
= (MSIDISTINCTVIEW
*)view
;
179 return ERROR_FUNCTION_FAILED
;
181 msi_free( dv
->translation
);
182 dv
->translation
= NULL
;
185 return dv
->table
->ops
->close( dv
->table
);
188 static UINT
DISTINCT_get_dimensions( struct tagMSIVIEW
*view
, UINT
*rows
, UINT
*cols
)
190 MSIDISTINCTVIEW
*dv
= (MSIDISTINCTVIEW
*)view
;
192 TRACE("%p %p %p\n", dv
, rows
, cols
);
195 return ERROR_FUNCTION_FAILED
;
199 if( !dv
->translation
)
200 return ERROR_FUNCTION_FAILED
;
201 *rows
= dv
->row_count
;
204 return dv
->table
->ops
->get_dimensions( dv
->table
, NULL
, cols
);
207 static UINT
DISTINCT_get_column_info( struct tagMSIVIEW
*view
,
208 UINT n
, LPWSTR
*name
, UINT
*type
)
210 MSIDISTINCTVIEW
*dv
= (MSIDISTINCTVIEW
*)view
;
212 TRACE("%p %d %p %p\n", dv
, n
, name
, type
);
215 return ERROR_FUNCTION_FAILED
;
217 return dv
->table
->ops
->get_column_info( dv
->table
, n
, name
, type
);
220 static UINT
DISTINCT_modify( struct tagMSIVIEW
*view
, MSIMODIFY eModifyMode
,
221 MSIRECORD
*rec
, UINT row
)
223 MSIDISTINCTVIEW
*dv
= (MSIDISTINCTVIEW
*)view
;
225 TRACE("%p %d %p\n", dv
, eModifyMode
, rec
);
228 return ERROR_FUNCTION_FAILED
;
230 return dv
->table
->ops
->modify( dv
->table
, eModifyMode
, rec
, row
);
233 static UINT
DISTINCT_delete( struct tagMSIVIEW
*view
)
235 MSIDISTINCTVIEW
*dv
= (MSIDISTINCTVIEW
*)view
;
240 dv
->table
->ops
->delete( dv
->table
);
242 msi_free( dv
->translation
);
243 msiobj_release( &dv
->db
->hdr
);
246 return ERROR_SUCCESS
;
249 static UINT
DISTINCT_find_matching_rows( struct tagMSIVIEW
*view
, UINT col
,
250 UINT val
, UINT
*row
, MSIITERHANDLE
*handle
)
252 MSIDISTINCTVIEW
*dv
= (MSIDISTINCTVIEW
*)view
;
255 TRACE("%p, %d, %u, %p\n", view
, col
, val
, *handle
);
258 return ERROR_FUNCTION_FAILED
;
260 r
= dv
->table
->ops
->find_matching_rows( dv
->table
, col
, val
, row
, handle
);
262 if( *row
> dv
->row_count
)
263 return ERROR_NO_MORE_ITEMS
;
265 *row
= dv
->translation
[ *row
];
271 static const MSIVIEWOPS distinct_ops
=
281 DISTINCT_get_dimensions
,
282 DISTINCT_get_column_info
,
285 DISTINCT_find_matching_rows
,
292 UINT
DISTINCT_CreateView( MSIDATABASE
*db
, MSIVIEW
**view
, MSIVIEW
*table
)
294 MSIDISTINCTVIEW
*dv
= NULL
;
299 r
= table
->ops
->get_dimensions( table
, NULL
, &count
);
300 if( r
!= ERROR_SUCCESS
)
302 ERR("can't get table dimensions\n");
306 dv
= msi_alloc_zero( sizeof *dv
);
308 return ERROR_FUNCTION_FAILED
;
310 /* fill the structure */
311 dv
->view
.ops
= &distinct_ops
;
312 msiobj_addref( &db
->hdr
);
315 dv
->translation
= NULL
;
317 *view
= (MSIVIEW
*) dv
;
319 return ERROR_SUCCESS
;