alter.c 6.98 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
/*
 * Implementation of the Microsoft Installer (msi.dll)
 *
 * Copyright 2006 Mike McCormack
 *
 * 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>

#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 "query.h"

WINE_DEFAULT_DEBUG_CHANNEL(msidb);

typedef struct tagMSIALTERVIEW
{
    MSIVIEW        view;
    MSIDATABASE   *db;
41
    MSIVIEW       *table;
42
    column_info   *colinfo;
43
    INT hold;
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
} MSIALTERVIEW;

static UINT ALTER_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
{
    MSIALTERVIEW *av = (MSIALTERVIEW*)view;

    TRACE("%p %d %d %p\n", av, row, col, val );

    return ERROR_FUNCTION_FAILED;
}

static UINT ALTER_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm)
{
    MSIALTERVIEW *av = (MSIALTERVIEW*)view;

    TRACE("%p %d %d %p\n", av, row, col, stm );

    return ERROR_FUNCTION_FAILED;
}

64 65 66 67 68 69 70 71 72
static UINT ALTER_get_row( struct tagMSIVIEW *view, UINT row, MSIRECORD **rec )
{
    MSIALTERVIEW *av = (MSIALTERVIEW*)view;

    TRACE("%p %d %p\n", av, row, rec );

    return av->table->ops->get_row(av->table, row, rec);
}

73 74 75 76 77 78
static UINT ITERATE_columns(MSIRECORD *row, LPVOID param)
{
    (*(UINT *)param)++;
    return ERROR_SUCCESS;
}

79
static BOOL check_column_exists(MSIDATABASE *db, LPCWSTR table, LPCWSTR column)
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
{
    MSIQUERY *view;
    MSIRECORD *rec;
    UINT r;

    static const WCHAR query[] = {
        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
        '`','_','C','o','l','u','m','n','s','`',' ','W','H','E','R','E',' ',
        '`','T','a','b','l','e','`','=','\'','%','s','\'',' ','A','N','D',' ',
        '`','N','a','m','e','`','=','\'','%','s','\'',0
    };

    r = MSI_OpenQuery(db, &view, query, table, column);
    if (r != ERROR_SUCCESS)
        return FALSE;

    r = MSI_ViewExecute(view, NULL);
    if (r != ERROR_SUCCESS)
        goto done;

    r = MSI_ViewFetch(view, &rec);
    if (r == ERROR_SUCCESS)
        msiobj_release(&rec->hdr);

done:
    msiobj_release(&view->hdr);
    return (r == ERROR_SUCCESS);
}

static UINT alter_add_column(MSIALTERVIEW *av)
{
    UINT r, colnum = 1;
    MSIQUERY *view;
    MSIVIEW *columns;

    static const WCHAR szColumns[] = {'_','C','o','l','u','m','n','s',0};
    static const WCHAR query[] = {
        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
        '`','_','C','o','l','u','m','n','s','`',' ','W','H','E','R','E',' ',
        '`','T','a','b','l','e','`','=','\'','%','s','\'',' ','O','R','D','E','R',' ',
        'B','Y',' ','`','N','u','m','b','e','r','`',0
    };

    r = TABLE_CreateView(av->db, szColumns, &columns);
    if (r != ERROR_SUCCESS)
        return r;

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 134 135 136 137

    r = MSI_OpenQuery(av->db, &view, query, av->colinfo->table, av->colinfo->column);
    if (r == ERROR_SUCCESS)
    {
        r = MSI_IterateRecords(view, NULL, ITERATE_columns, &colnum);
        msiobj_release(&view->hdr);
138 139 140 141 142
        if (r != ERROR_SUCCESS)
        {
            columns->ops->delete(columns);
            return r;
        }
143 144 145
    }
    r = columns->ops->add_column(columns, av->colinfo->table,
                                 colnum, av->colinfo->column,
146
                                 av->colinfo->type, (av->hold == 1));
147

148
    columns->ops->delete(columns);
149 150 151
    return r;
}

152 153 154
static UINT ALTER_execute( struct tagMSIVIEW *view, MSIRECORD *record )
{
    MSIALTERVIEW *av = (MSIALTERVIEW*)view;
155
    UINT ref;
156

157 158 159 160 161
    TRACE("%p %p\n", av, record);

    if (av->hold == 1)
        av->table->ops->add_ref(av->table);
    else if (av->hold == -1)
162 163 164 165 166
    {
        ref = av->table->ops->release(av->table);
        if (ref == 0)
            av->table = NULL;
    }
167 168

    if (av->colinfo)
169
        return alter_add_column(av);
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191

    return ERROR_SUCCESS;
}

static UINT ALTER_close( struct tagMSIVIEW *view )
{
    MSIALTERVIEW *av = (MSIALTERVIEW*)view;

    TRACE("%p\n", av );

    return ERROR_SUCCESS;
}

static UINT ALTER_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
{
    MSIALTERVIEW *av = (MSIALTERVIEW*)view;

    TRACE("%p %p %p\n", av, rows, cols );

    return ERROR_FUNCTION_FAILED;
}

192 193
static UINT ALTER_get_column_info( struct tagMSIVIEW *view, UINT n, LPCWSTR *name,
                                   UINT *type, BOOL *temporary, LPCWSTR *table_name )
194 195 196
{
    MSIALTERVIEW *av = (MSIALTERVIEW*)view;

197
    TRACE("%p %d %p %p %p %p\n", av, n, name, type, temporary, table_name );
198 199 200 201 202

    return ERROR_FUNCTION_FAILED;
}

static UINT ALTER_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
203
                          MSIRECORD *rec, UINT row )
204 205 206 207 208 209 210 211 212 213 214 215 216
{
    MSIALTERVIEW *av = (MSIALTERVIEW*)view;

    TRACE("%p %d %p\n", av, eModifyMode, rec );

    return ERROR_FUNCTION_FAILED;
}

static UINT ALTER_delete( struct tagMSIVIEW *view )
{
    MSIALTERVIEW *av = (MSIALTERVIEW*)view;

    TRACE("%p\n", av );
217 218
    if (av->table)
        av->table->ops->delete( av->table );
219
    msi_free( av );
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235

    return ERROR_SUCCESS;
}

static UINT ALTER_find_matching_rows( struct tagMSIVIEW *view, UINT col,
    UINT val, UINT *row, MSIITERHANDLE *handle )
{
    TRACE("%p, %d, %u, %p\n", view, col, val, *handle);

    return ERROR_FUNCTION_FAILED;
}

static const MSIVIEWOPS alter_ops =
{
    ALTER_fetch_int,
    ALTER_fetch_stream,
236
    ALTER_get_row,
237 238
    NULL,
    NULL,
239
    NULL,
240 241 242 243 244 245
    ALTER_execute,
    ALTER_close,
    ALTER_get_dimensions,
    ALTER_get_column_info,
    ALTER_modify,
    ALTER_delete,
246 247 248
    ALTER_find_matching_rows,
    NULL,
    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
{
Mike McCormack's avatar
Mike McCormack committed
257
    MSIALTERVIEW *av;
258
    UINT r;
259

260
    TRACE("%p %p %s %d\n", view, colinfo, debugstr_w(name), hold );
261 262 263 264 265

    av = msi_alloc_zero( sizeof *av );
    if( !av )
        return ERROR_FUNCTION_FAILED;

266
    r = TABLE_CreateView( db, name, &av->table );
267 268 269
    if (r != ERROR_SUCCESS)
    {
        msi_free( av );
270
        return r;
271
    }
272

273 274 275
    if (colinfo)
        colinfo->table = name;

276 277 278
    /* fill the structure */
    av->view.ops = &alter_ops;
    av->db = db;
279
    av->hold = hold;
280
    av->colinfo = colinfo;
281 282 283 284 285

    *view = &av->view;

    return ERROR_SUCCESS;
}