1 /* 2 * Implementation of the Microsoft Installer (msi.dll) 3 * 4 * Copyright 2006 Mike McCormack 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 33 #include "query.h" 34 35 WINE_DEFAULT_DEBUG_CHANNEL(msidb); 36 37 typedef struct tagMSIALTERVIEW 38 { 39 MSIVIEW view; 40 MSIDATABASE *db; 41 MSIVIEW *table; 42 column_info *colinfo; 43 INT hold; 44 } MSIALTERVIEW; 45 46 static UINT ALTER_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) 47 { 48 MSIALTERVIEW *av = (MSIALTERVIEW*)view; 49 50 TRACE("%p %d %d %p\n", av, row, col, val ); 51 52 return ERROR_FUNCTION_FAILED; 53 } 54 55 static UINT ALTER_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm) 56 { 57 MSIALTERVIEW *av = (MSIALTERVIEW*)view; 58 59 TRACE("%p %d %d %p\n", av, row, col, stm ); 60 61 return ERROR_FUNCTION_FAILED; 62 } 63 64 static UINT ALTER_get_row( struct tagMSIVIEW *view, UINT row, MSIRECORD **rec ) 65 { 66 MSIALTERVIEW *av = (MSIALTERVIEW*)view; 67 68 TRACE("%p %d %p\n", av, row, rec ); 69 70 return av->table->ops->get_row(av->table, row, rec); 71 } 72 73 static UINT ITERATE_columns(MSIRECORD *row, LPVOID param) 74 { 75 (*(UINT *)param)++; 76 return ERROR_SUCCESS; 77 } 78 79 static BOOL check_column_exists(MSIDATABASE *db, LPCWSTR table, LPCWSTR column) 80 { 81 MSIQUERY *view; 82 MSIRECORD *rec; 83 UINT r; 84 85 static const WCHAR query[] = { 86 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 87 '`','_','C','o','l','u','m','n','s','`',' ','W','H','E','R','E',' ', 88 '`','T','a','b','l','e','`','=','\'','%','s','\'',' ','A','N','D',' ', 89 '`','N','a','m','e','`','=','\'','%','s','\'',0 90 }; 91 92 r = MSI_OpenQuery(db, &view, query, table, column); 93 if (r != ERROR_SUCCESS) 94 return FALSE; 95 96 r = MSI_ViewExecute(view, NULL); 97 if (r != ERROR_SUCCESS) 98 goto done; 99 100 r = MSI_ViewFetch(view, &rec); 101 if (r == ERROR_SUCCESS) 102 msiobj_release(&rec->hdr); 103 104 done: 105 msiobj_release(&view->hdr); 106 return (r == ERROR_SUCCESS); 107 } 108 109 static UINT alter_add_column(MSIALTERVIEW *av) 110 { 111 UINT r, colnum = 1; 112 MSIQUERY *view; 113 MSIVIEW *columns; 114 115 static const WCHAR szColumns[] = {'_','C','o','l','u','m','n','s',0}; 116 static const WCHAR query[] = { 117 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 118 '`','_','C','o','l','u','m','n','s','`',' ','W','H','E','R','E',' ', 119 '`','T','a','b','l','e','`','=','\'','%','s','\'',' ','O','R','D','E','R',' ', 120 'B','Y',' ','`','N','u','m','b','e','r','`',0 121 }; 122 123 r = TABLE_CreateView(av->db, szColumns, &columns); 124 if (r != ERROR_SUCCESS) 125 return r; 126 127 if (check_column_exists(av->db, av->colinfo->table, av->colinfo->column)) 128 { 129 columns->ops->delete(columns); 130 return ERROR_BAD_QUERY_SYNTAX; 131 } 132 133 r = MSI_OpenQuery(av->db, &view, query, av->colinfo->table, av->colinfo->column); 134 if (r == ERROR_SUCCESS) 135 { 136 r = MSI_IterateRecords(view, NULL, ITERATE_columns, &colnum); 137 msiobj_release(&view->hdr); 138 if (r != ERROR_SUCCESS) 139 { 140 columns->ops->delete(columns); 141 return r; 142 } 143 } 144 r = columns->ops->add_column(columns, av->colinfo->table, 145 colnum, av->colinfo->column, 146 av->colinfo->type, (av->hold == 1)); 147 148 columns->ops->delete(columns); 149 return r; 150 } 151 152 static UINT ALTER_execute( struct tagMSIVIEW *view, MSIRECORD *record ) 153 { 154 MSIALTERVIEW *av = (MSIALTERVIEW*)view; 155 UINT ref; 156 157 TRACE("%p %p\n", av, record); 158 159 if (av->hold == 1) 160 av->table->ops->add_ref(av->table); 161 else if (av->hold == -1) 162 { 163 ref = av->table->ops->release(av->table); 164 if (ref == 0) 165 av->table = NULL; 166 } 167 168 if (av->colinfo) 169 return alter_add_column(av); 170 171 return ERROR_SUCCESS; 172 } 173 174 static UINT ALTER_close( struct tagMSIVIEW *view ) 175 { 176 MSIALTERVIEW *av = (MSIALTERVIEW*)view; 177 178 TRACE("%p\n", av ); 179 180 return ERROR_SUCCESS; 181 } 182 183 static UINT ALTER_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols ) 184 { 185 MSIALTERVIEW *av = (MSIALTERVIEW*)view; 186 187 TRACE("%p %p %p\n", av, rows, cols ); 188 189 return ERROR_FUNCTION_FAILED; 190 } 191 192 static UINT ALTER_get_column_info( struct tagMSIVIEW *view, UINT n, LPCWSTR *name, 193 UINT *type, BOOL *temporary, LPCWSTR *table_name ) 194 { 195 MSIALTERVIEW *av = (MSIALTERVIEW*)view; 196 197 TRACE("%p %d %p %p %p %p\n", av, n, name, type, temporary, table_name ); 198 199 return ERROR_FUNCTION_FAILED; 200 } 201 202 static UINT ALTER_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, 203 MSIRECORD *rec, UINT row ) 204 { 205 MSIALTERVIEW *av = (MSIALTERVIEW*)view; 206 207 TRACE("%p %d %p\n", av, eModifyMode, rec ); 208 209 return ERROR_FUNCTION_FAILED; 210 } 211 212 static UINT ALTER_delete( struct tagMSIVIEW *view ) 213 { 214 MSIALTERVIEW *av = (MSIALTERVIEW*)view; 215 216 TRACE("%p\n", av ); 217 if (av->table) 218 av->table->ops->delete( av->table ); 219 msi_free( av ); 220 221 return ERROR_SUCCESS; 222 } 223 224 static UINT ALTER_find_matching_rows( struct tagMSIVIEW *view, UINT col, 225 UINT val, UINT *row, MSIITERHANDLE *handle ) 226 { 227 TRACE("%p, %d, %u, %p\n", view, col, val, *handle); 228 229 return ERROR_FUNCTION_FAILED; 230 } 231 232 static const MSIVIEWOPS alter_ops = 233 { 234 ALTER_fetch_int, 235 ALTER_fetch_stream, 236 ALTER_get_row, 237 NULL, 238 NULL, 239 NULL, 240 ALTER_execute, 241 ALTER_close, 242 ALTER_get_dimensions, 243 ALTER_get_column_info, 244 ALTER_modify, 245 ALTER_delete, 246 ALTER_find_matching_rows, 247 NULL, 248 NULL, 249 NULL, 250 NULL, 251 NULL, 252 NULL, 253 }; 254 255 UINT ALTER_CreateView( MSIDATABASE *db, MSIVIEW **view, LPCWSTR name, column_info *colinfo, int hold ) 256 { 257 MSIALTERVIEW *av; 258 UINT r; 259 260 TRACE("%p %p %s %d\n", view, colinfo, debugstr_w(name), hold ); 261 262 av = msi_alloc_zero( sizeof *av ); 263 if( !av ) 264 return ERROR_FUNCTION_FAILED; 265 266 r = TABLE_CreateView( db, name, &av->table ); 267 if (r != ERROR_SUCCESS) 268 { 269 msi_free( av ); 270 return r; 271 } 272 273 if (colinfo) 274 colinfo->table = name; 275 276 /* fill the structure */ 277 av->view.ops = &alter_ops; 278 av->db = db; 279 av->hold = hold; 280 av->colinfo = colinfo; 281 282 *view = &av->view; 283 284 return ERROR_SUCCESS; 285 } 286