winspool: Implement AddPortW.
[wine] / dlls / msi / join.c
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2006 Mike McCormack for CodeWeavers
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winerror.h"
26 #include "wine/debug.h"
27 #include "msi.h"
28 #include "msiquery.h"
29 #include "objbase.h"
30 #include "objidl.h"
31 #include "msipriv.h"
32 #include "query.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(msidb);
35
36 typedef struct tagMSIJOINVIEW
37 {
38     MSIVIEW        view;
39     MSIDATABASE   *db;
40     MSIVIEW       *left, *right;
41     UINT           left_count, right_count;
42     UINT           left_rows, right_rows;
43 } MSIJOINVIEW;
44
45 static UINT JOIN_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
46 {
47     MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
48     MSIVIEW *table;
49
50     TRACE("%p %d %d %p\n", jv, row, col, val );
51
52     if( !jv->left || !jv->right )
53          return ERROR_FUNCTION_FAILED;
54
55     if( (col==0) || (col>(jv->left_count + jv->right_count)) )
56          return ERROR_FUNCTION_FAILED;
57
58     if( row >= (jv->left_rows * jv->right_rows) )
59          return ERROR_FUNCTION_FAILED;
60
61     if( col <= jv->left_count )
62     {
63         table = jv->left;
64         row = (row/jv->right_rows);
65     }
66     else
67     {
68         table = jv->right;
69         row = (row % jv->right_rows);
70         col -= jv->left_count;
71     }
72
73     return table->ops->fetch_int( table, row, col, val );
74 }
75
76 static UINT JOIN_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm)
77 {
78     MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
79     MSIVIEW *table;
80
81     TRACE("%p %d %d %p\n", jv, row, col, stm );
82
83     if( !jv->left || !jv->right )
84          return ERROR_FUNCTION_FAILED;
85
86     if( (col==0) || (col>(jv->left_count + jv->right_count)) )
87          return ERROR_FUNCTION_FAILED;
88
89     if( row >= jv->left_rows * jv->right_rows )
90          return ERROR_FUNCTION_FAILED;
91
92     if( row <= jv->left_count )
93     {
94         table = jv->left;
95         row = (row/jv->right_rows);
96     }
97     else
98     {
99         table = jv->right;
100         row = (row % jv->right_rows);
101         col -= jv->left_count;
102     }
103
104     return table->ops->fetch_stream( table, row, col, stm );
105 }
106
107 static UINT JOIN_execute( struct tagMSIVIEW *view, MSIRECORD *record )
108 {
109     MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
110     UINT r, *ldata = NULL, *rdata = NULL;
111
112     TRACE("%p %p\n", jv, record);
113
114     if( !jv->left || !jv->right )
115          return ERROR_FUNCTION_FAILED;
116
117     r = jv->left->ops->execute( jv->left, NULL );
118     if (r != ERROR_SUCCESS)
119         return r;
120
121     r = jv->right->ops->execute( jv->right, NULL );
122     if (r != ERROR_SUCCESS)
123         return r;
124
125     /* get the number of rows in each table */
126     r = jv->left->ops->get_dimensions( jv->left, &jv->left_rows, NULL );
127     if( r != ERROR_SUCCESS )
128     {
129         ERR("can't get left table dimensions\n");
130         goto end;
131     }
132
133     r = jv->right->ops->get_dimensions( jv->right, &jv->right_rows, NULL );
134     if( r != ERROR_SUCCESS )
135     {
136         ERR("can't get right table dimensions\n");
137         goto end;
138     }
139
140 end:
141     msi_free( ldata );
142     msi_free( rdata );
143
144     return r;
145 }
146
147 static UINT JOIN_close( struct tagMSIVIEW *view )
148 {
149     MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
150
151     TRACE("%p\n", jv );
152
153     if( !jv->left || !jv->right )
154         return ERROR_FUNCTION_FAILED;
155
156     jv->left->ops->close( jv->left );
157     jv->right->ops->close( jv->right );
158
159     return ERROR_SUCCESS;
160 }
161
162 static UINT JOIN_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
163 {
164     MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
165
166     TRACE("%p %p %p\n", jv, rows, cols );
167
168     if( cols )
169         *cols = jv->left_count + jv->right_count;
170
171     if( rows )
172     {
173         if( !jv->left || !jv->right )
174             return ERROR_FUNCTION_FAILED;
175
176         *rows = jv->left_rows * jv->right_rows;
177     }
178
179     return ERROR_SUCCESS;
180 }
181
182 static UINT JOIN_get_column_info( struct tagMSIVIEW *view,
183                 UINT n, LPWSTR *name, UINT *type )
184 {
185     MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
186
187     TRACE("%p %d %p %p\n", jv, n, name, type );
188
189     if( !jv->left || !jv->right )
190         return ERROR_FUNCTION_FAILED;
191
192     if( (n==0) || (n>(jv->left_count + jv->right_count)) )
193         return ERROR_FUNCTION_FAILED;
194
195     if( n <= jv->left_count )
196         return jv->left->ops->get_column_info( jv->left, n, name, type );
197
198     n = n - jv->left_count;
199
200     return jv->right->ops->get_column_info( jv->right, n, name, type );
201 }
202
203 static UINT JOIN_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
204                 MSIRECORD *rec )
205 {
206     MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
207
208     TRACE("%p %d %p\n", jv, eModifyMode, rec );
209
210     return ERROR_FUNCTION_FAILED;
211 }
212
213 static UINT JOIN_delete( struct tagMSIVIEW *view )
214 {
215     MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
216
217     TRACE("%p\n", jv );
218
219     if( jv->left )
220         jv->left->ops->delete( jv->left );
221     jv->left = NULL;
222
223     if( jv->right )
224         jv->right->ops->delete( jv->right );
225     jv->right = NULL;
226
227     msi_free( jv );
228
229     return ERROR_SUCCESS;
230 }
231
232 static UINT JOIN_find_matching_rows( struct tagMSIVIEW *view, UINT col,
233     UINT val, UINT *row, MSIITERHANDLE *handle )
234 {
235     MSIJOINVIEW *jv = (MSIJOINVIEW*)view;
236
237     FIXME("%p, %d, %u, %p\n", jv, col, val, *handle);
238
239     return ERROR_FUNCTION_FAILED;
240 }
241
242 static const MSIVIEWOPS join_ops =
243 {
244     JOIN_fetch_int,
245     JOIN_fetch_stream,
246     NULL,
247     NULL,
248     JOIN_execute,
249     JOIN_close,
250     JOIN_get_dimensions,
251     JOIN_get_column_info,
252     JOIN_modify,
253     JOIN_delete,
254     JOIN_find_matching_rows
255 };
256
257 UINT JOIN_CreateView( MSIDATABASE *db, MSIVIEW **view,
258                       LPCWSTR left, LPCWSTR right )
259 {
260     MSIJOINVIEW *jv = NULL;
261     UINT r = ERROR_SUCCESS;
262
263     TRACE("%p (%s,%s)\n", jv, debugstr_w(left), debugstr_w(right) );
264
265     jv = msi_alloc_zero( sizeof *jv );
266     if( !jv )
267         return ERROR_FUNCTION_FAILED;
268
269     /* fill the structure */
270     jv->view.ops = &join_ops;
271     jv->db = db;
272
273     /* create the tables to join */
274     r = TABLE_CreateView( db, left, &jv->left );
275     if( r != ERROR_SUCCESS )
276     {
277         ERR("can't create left table\n");
278         goto end;
279     }
280
281     r = TABLE_CreateView( db, right, &jv->right );
282     if( r != ERROR_SUCCESS )
283     {
284         ERR("can't create right table\n");
285         goto end;
286     }
287
288     /* get the number of columns in each table */
289     r = jv->left->ops->get_dimensions( jv->left, NULL, &jv->left_count );
290     if( r != ERROR_SUCCESS )
291     {
292         ERR("can't get left table dimensions\n");
293         goto end;
294     }
295
296     r = jv->right->ops->get_dimensions( jv->right, NULL, &jv->right_count );
297     if( r != ERROR_SUCCESS )
298     {
299         ERR("can't get right table dimensions\n");
300         goto end;
301     }
302
303     *view = &jv->view;
304     return ERROR_SUCCESS;
305
306 end:
307     jv->view.ops->delete( &jv->view );
308
309     return r;
310 }