msi: Sort each table of the join separately.
This commit is contained in:
parent
f93ee6f420
commit
91c205e8c0
|
@ -32,7 +32,6 @@ C_SRCS = \
|
|||
msi.c \
|
||||
msi_main.c \
|
||||
msiquery.c \
|
||||
order.c \
|
||||
package.c \
|
||||
preview.c \
|
||||
record.c \
|
||||
|
|
|
@ -241,6 +241,7 @@ static const MSIVIEWOPS alter_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
UINT ALTER_CreateView( MSIDATABASE *db, MSIVIEW **view, LPCWSTR name, column_info *colinfo, int hold )
|
||||
|
|
|
@ -136,6 +136,7 @@ static const MSIVIEWOPS create_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static UINT check_columns( column_info *col_info )
|
||||
|
|
|
@ -267,6 +267,14 @@ static UINT DISTINCT_find_matching_rows( struct tagMSIVIEW *view, UINT col,
|
|||
return r;
|
||||
}
|
||||
|
||||
static UINT DISTINCT_sort(struct tagMSIVIEW *view, column_info *columns)
|
||||
{
|
||||
MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW *)view;
|
||||
|
||||
TRACE("%p %p\n", view, columns);
|
||||
|
||||
return dv->table->ops->sort( dv->table, columns );
|
||||
}
|
||||
|
||||
static const MSIVIEWOPS distinct_ops =
|
||||
{
|
||||
|
@ -287,6 +295,7 @@ static const MSIVIEWOPS distinct_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
DISTINCT_sort,
|
||||
};
|
||||
|
||||
UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )
|
||||
|
|
|
@ -238,6 +238,7 @@ static const MSIVIEWOPS insert_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static UINT count_column_info( const column_info *ci )
|
||||
|
|
|
@ -268,6 +268,24 @@ static UINT JOIN_find_matching_rows( struct tagMSIVIEW *view, UINT col,
|
|||
return ERROR_NO_MORE_ITEMS;
|
||||
}
|
||||
|
||||
static UINT JOIN_sort(struct tagMSIVIEW *view, column_info *columns)
|
||||
{
|
||||
MSIJOINVIEW *jv = (MSIJOINVIEW *)view;
|
||||
JOINTABLE *table;
|
||||
UINT r;
|
||||
|
||||
TRACE("%p %p\n", view, columns);
|
||||
|
||||
LIST_FOR_EACH_ENTRY(table, &jv->tables, JOINTABLE, entry)
|
||||
{
|
||||
r = table->view->ops->sort(table->view, columns);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static const MSIVIEWOPS join_ops =
|
||||
{
|
||||
JOIN_fetch_int,
|
||||
|
@ -287,6 +305,7 @@ static const MSIVIEWOPS join_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
JOIN_sort,
|
||||
};
|
||||
|
||||
UINT JOIN_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR tables )
|
||||
|
|
|
@ -133,6 +133,16 @@ typedef struct tagMSIMEDIADISK
|
|||
LPWSTR disk_prompt;
|
||||
} MSIMEDIADISK;
|
||||
|
||||
typedef struct _column_info
|
||||
{
|
||||
LPCWSTR table;
|
||||
LPCWSTR column;
|
||||
INT type;
|
||||
BOOL temporary;
|
||||
struct expr *val;
|
||||
struct _column_info *next;
|
||||
} column_info;
|
||||
|
||||
typedef const struct tagMSICOLUMNHASHENTRY *MSIITERHANDLE;
|
||||
|
||||
typedef struct tagMSIVIEWOPS
|
||||
|
@ -248,6 +258,11 @@ typedef struct tagMSIVIEWOPS
|
|||
* remove_column - removes the column represented by table name and column number from the table
|
||||
*/
|
||||
UINT (*remove_column)( struct tagMSIVIEW *view, LPCWSTR table, UINT number );
|
||||
|
||||
/*
|
||||
* sort - orders the table by columns
|
||||
*/
|
||||
UINT (*sort)( struct tagMSIVIEW *view, column_info *columns );
|
||||
} MSIVIEWOPS;
|
||||
|
||||
struct tagMSIVIEW
|
||||
|
|
376
dlls/msi/order.c
376
dlls/msi/order.c
|
@ -1,376 +0,0 @@
|
|||
/*
|
||||
* 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., 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 "winnls.h"
|
||||
|
||||
#include "query.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
|
||||
|
||||
|
||||
/* below is the query interface to a table */
|
||||
|
||||
typedef struct tagMSIORDERVIEW
|
||||
{
|
||||
MSIVIEW view;
|
||||
MSIDATABASE *db;
|
||||
MSIVIEW *table;
|
||||
UINT *reorder;
|
||||
UINT num_cols;
|
||||
UINT cols[1];
|
||||
} MSIORDERVIEW;
|
||||
|
||||
static UINT ORDER_compare( MSIORDERVIEW *ov, UINT a, UINT b, UINT *swap )
|
||||
{
|
||||
UINT r, i, a_val = 0, b_val = 0;
|
||||
|
||||
*swap = 0;
|
||||
for( i=0; i<ov->num_cols; i++ )
|
||||
{
|
||||
r = ov->table->ops->fetch_int( ov->table, a, ov->cols[i], &a_val );
|
||||
if( r != ERROR_SUCCESS )
|
||||
return r;
|
||||
|
||||
r = ov->table->ops->fetch_int( ov->table, b, ov->cols[i], &b_val );
|
||||
if( r != ERROR_SUCCESS )
|
||||
return r;
|
||||
|
||||
if( a_val != b_val )
|
||||
{
|
||||
if( a_val > b_val )
|
||||
*swap = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT ORDER_mergesort( MSIORDERVIEW *ov, UINT left, UINT right )
|
||||
{
|
||||
UINT r, centre = (left + right)/2, temp, swap = 0, i, j;
|
||||
UINT *array = ov->reorder;
|
||||
|
||||
if( left == right )
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
/* sort the left half */
|
||||
r = ORDER_mergesort( ov, left, centre );
|
||||
if( r != ERROR_SUCCESS )
|
||||
return r;
|
||||
|
||||
/* sort the right half */
|
||||
r = ORDER_mergesort( ov, centre+1, right );
|
||||
if( r != ERROR_SUCCESS )
|
||||
return r;
|
||||
|
||||
for( i=left, j=centre+1; (i<=centre) && (j<=right); i++ )
|
||||
{
|
||||
r = ORDER_compare( ov, array[i], array[j], &swap );
|
||||
if( r != ERROR_SUCCESS )
|
||||
return r;
|
||||
if( swap )
|
||||
{
|
||||
temp = array[j];
|
||||
memmove( &array[i+1], &array[i], (j-i)*sizeof (UINT) );
|
||||
array[i] = temp;
|
||||
j++;
|
||||
centre++;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT ORDER_verify( MSIORDERVIEW *ov, UINT num_rows )
|
||||
{
|
||||
UINT i, swap, r;
|
||||
|
||||
for( i=1; i<num_rows; i++ )
|
||||
{
|
||||
r = ORDER_compare( ov, ov->reorder[i-1], ov->reorder[i], &swap );
|
||||
if( r != ERROR_SUCCESS )
|
||||
return r;
|
||||
if( !swap )
|
||||
continue;
|
||||
ERR("Bad order! %d\n", i);
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT ORDER_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
|
||||
{
|
||||
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
|
||||
|
||||
TRACE("%p %d %d %p\n", ov, row, col, val );
|
||||
|
||||
if( !ov->table )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
row = ov->reorder[ row ];
|
||||
|
||||
return ov->table->ops->fetch_int( ov->table, row, col, val );
|
||||
}
|
||||
|
||||
static UINT ORDER_get_row( struct tagMSIVIEW *view, UINT row, MSIRECORD **rec )
|
||||
{
|
||||
MSIORDERVIEW *ov = (MSIORDERVIEW *)view;
|
||||
|
||||
TRACE("%p %d %p\n", ov, row, rec );
|
||||
|
||||
if (!ov->table)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
row = ov->reorder[row];
|
||||
|
||||
return ov->table->ops->get_row(ov->table, row, rec);
|
||||
}
|
||||
|
||||
static UINT ORDER_execute( struct tagMSIVIEW *view, MSIRECORD *record )
|
||||
{
|
||||
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
|
||||
UINT r, num_rows = 0, i;
|
||||
|
||||
TRACE("%p %p\n", ov, record);
|
||||
|
||||
if( !ov->table )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
r = ov->table->ops->execute( ov->table, record );
|
||||
if( r != ERROR_SUCCESS )
|
||||
return r;
|
||||
|
||||
r = ov->table->ops->get_dimensions( ov->table, &num_rows, NULL );
|
||||
if( r != ERROR_SUCCESS )
|
||||
return r;
|
||||
|
||||
ov->reorder = msi_alloc( num_rows*sizeof(UINT) );
|
||||
if( !ov->reorder )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
for( i=0; i<num_rows; i++ )
|
||||
ov->reorder[i] = i;
|
||||
|
||||
r = ORDER_mergesort( ov, 0, num_rows - 1 );
|
||||
if( r != ERROR_SUCCESS )
|
||||
return r;
|
||||
|
||||
r = ORDER_verify( ov, num_rows );
|
||||
if( r != ERROR_SUCCESS )
|
||||
return r;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT ORDER_close( struct tagMSIVIEW *view )
|
||||
{
|
||||
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
|
||||
|
||||
TRACE("%p\n", ov );
|
||||
|
||||
if( !ov->table )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
msi_free( ov->reorder );
|
||||
ov->reorder = NULL;
|
||||
|
||||
return ov->table->ops->close( ov->table );
|
||||
}
|
||||
|
||||
static UINT ORDER_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
|
||||
{
|
||||
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
|
||||
|
||||
TRACE("%p %p %p\n", ov, rows, cols );
|
||||
|
||||
if( !ov->table )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
return ov->table->ops->get_dimensions( ov->table, rows, cols );
|
||||
}
|
||||
|
||||
static UINT ORDER_get_column_info( struct tagMSIVIEW *view,
|
||||
UINT n, LPWSTR *name, UINT *type )
|
||||
{
|
||||
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
|
||||
|
||||
TRACE("%p %d %p %p\n", ov, n, name, type );
|
||||
|
||||
if( !ov->table )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
return ov->table->ops->get_column_info( ov->table, n, name, type );
|
||||
}
|
||||
|
||||
static UINT ORDER_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
|
||||
MSIRECORD *rec, UINT row )
|
||||
{
|
||||
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
|
||||
|
||||
TRACE("%p %d %p\n", ov, eModifyMode, rec );
|
||||
|
||||
if( !ov->table )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
return ov->table->ops->modify( ov->table, eModifyMode, rec, row );
|
||||
}
|
||||
|
||||
static UINT ORDER_delete( struct tagMSIVIEW *view )
|
||||
{
|
||||
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
|
||||
|
||||
TRACE("%p\n", ov );
|
||||
|
||||
if( ov->table )
|
||||
ov->table->ops->delete( ov->table );
|
||||
|
||||
msi_free( ov->reorder );
|
||||
ov->reorder = NULL;
|
||||
|
||||
msiobj_release( &ov->db->hdr );
|
||||
msi_free( ov );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT ORDER_find_matching_rows( struct tagMSIVIEW *view, UINT col,
|
||||
UINT val, UINT *row, MSIITERHANDLE *handle )
|
||||
{
|
||||
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
|
||||
UINT r;
|
||||
|
||||
TRACE("%p, %d, %u, %p\n", ov, col, val, *handle);
|
||||
|
||||
if( !ov->table )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
r = ov->table->ops->find_matching_rows( ov->table, col, val, row, handle );
|
||||
|
||||
*row = ov->reorder[ *row ];
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
static const MSIVIEWOPS order_ops =
|
||||
{
|
||||
ORDER_fetch_int,
|
||||
NULL,
|
||||
ORDER_get_row,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
ORDER_execute,
|
||||
ORDER_close,
|
||||
ORDER_get_dimensions,
|
||||
ORDER_get_column_info,
|
||||
ORDER_modify,
|
||||
ORDER_delete,
|
||||
ORDER_find_matching_rows,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static UINT ORDER_AddColumn( MSIORDERVIEW *ov, LPCWSTR name )
|
||||
{
|
||||
UINT n, count, r;
|
||||
MSIVIEW *table;
|
||||
|
||||
TRACE("%p adding %s\n", ov, debugstr_w( name ) );
|
||||
|
||||
if( ov->view.ops != &order_ops )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
table = ov->table;
|
||||
if( !table )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
if( !table->ops->get_dimensions )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
if( !table->ops->get_column_info )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
r = table->ops->get_dimensions( table, NULL, &count );
|
||||
if( r != ERROR_SUCCESS )
|
||||
return r;
|
||||
|
||||
if( ov->num_cols >= count )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
r = VIEW_find_column( table, name, &n );
|
||||
if( r != ERROR_SUCCESS )
|
||||
return r;
|
||||
|
||||
ov->cols[ov->num_cols] = n;
|
||||
TRACE("Ordering by column %s (%d)\n", debugstr_w( name ), n);
|
||||
|
||||
ov->num_cols++;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
|
||||
column_info *columns )
|
||||
{
|
||||
MSIORDERVIEW *ov = NULL;
|
||||
UINT count = 0, r;
|
||||
column_info *x;
|
||||
|
||||
TRACE("%p\n", ov );
|
||||
|
||||
r = table->ops->get_dimensions( table, NULL, &count );
|
||||
if( r != ERROR_SUCCESS )
|
||||
{
|
||||
ERR("can't get table dimensions\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
ov = msi_alloc_zero( sizeof *ov + sizeof (UINT) * count );
|
||||
if( !ov )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
/* fill the structure */
|
||||
ov->view.ops = &order_ops;
|
||||
msiobj_addref( &db->hdr );
|
||||
ov->db = db;
|
||||
ov->table = table;
|
||||
ov->reorder = NULL;
|
||||
ov->num_cols = 0;
|
||||
*view = (MSIVIEW*) ov;
|
||||
|
||||
for( x = columns; x ; x = x->next )
|
||||
ORDER_AddColumn( ov, x->column );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
|
@ -61,16 +61,6 @@ struct sql_str {
|
|||
INT len;
|
||||
};
|
||||
|
||||
typedef struct _column_info
|
||||
{
|
||||
LPCWSTR table;
|
||||
LPCWSTR column;
|
||||
UINT type;
|
||||
BOOL temporary;
|
||||
struct expr *val;
|
||||
struct _column_info *next;
|
||||
} column_info;
|
||||
|
||||
struct complex_expr
|
||||
{
|
||||
UINT op;
|
||||
|
|
|
@ -334,6 +334,14 @@ static UINT SELECT_find_matching_rows( struct tagMSIVIEW *view, UINT col,
|
|||
return sv->table->ops->find_matching_rows( sv->table, col, val, row, handle );
|
||||
}
|
||||
|
||||
static UINT SELECT_sort(struct tagMSIVIEW *view, column_info *columns)
|
||||
{
|
||||
MSISELECTVIEW *sv = (MSISELECTVIEW *)view;
|
||||
|
||||
TRACE("%p %p\n", view, columns);
|
||||
|
||||
return sv->table->ops->sort( sv->table, columns );
|
||||
}
|
||||
|
||||
static const MSIVIEWOPS select_ops =
|
||||
{
|
||||
|
@ -354,6 +362,7 @@ static const MSIVIEWOPS select_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
SELECT_sort,
|
||||
};
|
||||
|
||||
static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPCWSTR name )
|
||||
|
|
|
@ -373,16 +373,17 @@ data_count:
|
|||
oneselect:
|
||||
unorderedsel TK_ORDER TK_BY selcollist
|
||||
{
|
||||
SQL_input* sql = (SQL_input*) info;
|
||||
UINT r;
|
||||
|
||||
$$ = NULL;
|
||||
if( $4 )
|
||||
ORDER_CreateView( sql->db, &$$, $1, $4 );
|
||||
else
|
||||
$$ = $1;
|
||||
if( !$$ )
|
||||
{
|
||||
r = $1->ops->sort( $1, $4 );
|
||||
if ( r != ERROR_SUCCESS)
|
||||
YYABORT;
|
||||
}
|
||||
|
||||
$$ = $1;
|
||||
}
|
||||
| unorderedsel
|
||||
;
|
||||
|
||||
|
|
|
@ -379,6 +379,7 @@ static const MSIVIEWOPS streams_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static UINT add_streams_to_table(MSISTREAMSVIEW *sv)
|
||||
|
|
170
dlls/msi/table.c
170
dlls/msi/table.c
|
@ -62,6 +62,13 @@ typedef struct tagMSICOLUMNINFO
|
|||
MSICOLUMNHASHENTRY **hash_table;
|
||||
} MSICOLUMNINFO;
|
||||
|
||||
typedef struct tagMSIORDERINFO
|
||||
{
|
||||
UINT *reorder;
|
||||
UINT num_cols;
|
||||
UINT cols[1];
|
||||
} MSIORDERINFO;
|
||||
|
||||
struct tagMSITABLE
|
||||
{
|
||||
BYTE **data;
|
||||
|
@ -1114,6 +1121,7 @@ typedef struct tagMSITABLEVIEW
|
|||
MSIDATABASE *db;
|
||||
MSITABLE *table;
|
||||
MSICOLUMNINFO *columns;
|
||||
MSIORDERINFO *order;
|
||||
UINT num_cols;
|
||||
UINT row_size;
|
||||
WCHAR name[1];
|
||||
|
@ -1142,6 +1150,9 @@ static UINT TABLE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *
|
|||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
if (tv->order)
|
||||
row = tv->order->reorder[row];
|
||||
|
||||
if (row >= tv->table->row_count)
|
||||
{
|
||||
row -= tv->table->row_count;
|
||||
|
@ -1286,6 +1297,9 @@ static UINT TABLE_get_row( struct tagMSIVIEW *view, UINT row, MSIRECORD **rec )
|
|||
if (!tv->table)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (tv->order)
|
||||
row = tv->order->reorder[row];
|
||||
|
||||
return msi_view_get_row(tv->db, view, row, rec);
|
||||
}
|
||||
|
||||
|
@ -1728,6 +1742,10 @@ static UINT TABLE_find_matching_rows( struct tagMSIVIEW *view, UINT col,
|
|||
return ERROR_NO_MORE_ITEMS;
|
||||
|
||||
*row = entry->row;
|
||||
|
||||
if (tv->order)
|
||||
*row = tv->order->reorder[*row];
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1860,6 +1878,157 @@ done:
|
|||
return r;
|
||||
}
|
||||
|
||||
static UINT order_add_column(struct tagMSIVIEW *view, MSIORDERINFO *order, LPCWSTR name)
|
||||
{
|
||||
UINT n, r, count;
|
||||
|
||||
r = TABLE_get_dimensions(view, NULL, &count);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
if (order->num_cols >= count)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
r = VIEW_find_column(view, name, &n);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
order->cols[order->num_cols] = n;
|
||||
TRACE("Ordering by column %s (%d)\n", debugstr_w(name), n);
|
||||
|
||||
order->num_cols++;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT order_compare(struct tagMSIVIEW *view, MSIORDERINFO *order,
|
||||
UINT a, UINT b, UINT *swap)
|
||||
{
|
||||
UINT r, i, a_val = 0, b_val = 0;
|
||||
|
||||
*swap = 0;
|
||||
for (i = 0; i < order->num_cols; i++)
|
||||
{
|
||||
r = TABLE_fetch_int(view, a, order->cols[i], &a_val);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
r = TABLE_fetch_int(view, b, order->cols[i], &b_val);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
if (a_val != b_val)
|
||||
{
|
||||
if (a_val > b_val)
|
||||
*swap = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT order_mergesort(struct tagMSIVIEW *view, MSIORDERINFO *order,
|
||||
UINT left, UINT right)
|
||||
{
|
||||
UINT r, i, j, temp;
|
||||
UINT swap = 0, center = (left + right) / 2;
|
||||
UINT *array = order->reorder;
|
||||
|
||||
if (left == right)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
/* sort the left half */
|
||||
r = order_mergesort(view, order, left, center);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
/* sort the right half */
|
||||
r = order_mergesort(view, order, center + 1, right);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
for (i = left, j = center + 1; (i <= center) && (j <= right); i++)
|
||||
{
|
||||
r = order_compare(view, order, array[i], array[j], &swap);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
if (swap)
|
||||
{
|
||||
temp = array[j];
|
||||
memmove(&array[i + 1], &array[i], (j - i) * sizeof(UINT));
|
||||
array[i] = temp;
|
||||
j++;
|
||||
center++;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT order_verify(struct tagMSIVIEW *view, MSIORDERINFO *order, UINT num_rows)
|
||||
{
|
||||
UINT i, swap, r;
|
||||
|
||||
for (i = 1; i < num_rows; i++)
|
||||
{
|
||||
r = order_compare(view, order, order->reorder[i - 1],
|
||||
order->reorder[i], &swap);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
if (!swap)
|
||||
continue;
|
||||
|
||||
ERR("Bad order! %d\n", i);
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT TABLE_sort(struct tagMSIVIEW *view, column_info *columns)
|
||||
{
|
||||
MSITABLEVIEW *tv = (MSITABLEVIEW *)view;
|
||||
MSIORDERINFO *order;
|
||||
column_info *ptr;
|
||||
UINT r, i;
|
||||
UINT rows, cols;
|
||||
|
||||
TRACE("sorting table %s\n", debugstr_w(tv->name));
|
||||
|
||||
r = TABLE_get_dimensions(view, &rows, &cols);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
order = msi_alloc_zero(sizeof(MSIORDERINFO) + sizeof(UINT) * cols);
|
||||
if (!order)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
for (ptr = columns; ptr; ptr = ptr->next)
|
||||
order_add_column(view, order, ptr->column);
|
||||
|
||||
order->reorder = msi_alloc(rows * sizeof(UINT));
|
||||
if (!order->reorder)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
for (i = 0; i < rows; i++)
|
||||
order->reorder[i] = i;
|
||||
|
||||
r = order_mergesort(view, order, 0, rows - 1);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
r = order_verify(view, order, rows);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return r;
|
||||
|
||||
tv->order = order;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static const MSIVIEWOPS table_ops =
|
||||
{
|
||||
TABLE_fetch_int,
|
||||
|
@ -1879,6 +2048,7 @@ static const MSIVIEWOPS table_ops =
|
|||
TABLE_release,
|
||||
TABLE_add_column,
|
||||
TABLE_remove_column,
|
||||
TABLE_sort,
|
||||
};
|
||||
|
||||
UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view )
|
||||
|
|
|
@ -4610,16 +4610,10 @@ static void test_order(void)
|
|||
ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
|
||||
|
||||
val = MsiRecordGetInteger(hrec, 1);
|
||||
todo_wine
|
||||
{
|
||||
ok(val == 3, "Expected 3, got %d\n", val);
|
||||
}
|
||||
|
||||
val = MsiRecordGetInteger(hrec, 2);
|
||||
todo_wine
|
||||
{
|
||||
ok(val == 4, "Expected 3, got %d\n", val);
|
||||
}
|
||||
|
||||
MsiCloseHandle(hrec);
|
||||
|
||||
|
@ -4627,16 +4621,10 @@ static void test_order(void)
|
|||
ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
|
||||
|
||||
val = MsiRecordGetInteger(hrec, 1);
|
||||
todo_wine
|
||||
{
|
||||
ok(val == 5, "Expected 5, got %d\n", val);
|
||||
}
|
||||
|
||||
val = MsiRecordGetInteger(hrec, 2);
|
||||
todo_wine
|
||||
{
|
||||
ok(val == 6, "Expected 6, got %d\n", val);
|
||||
}
|
||||
|
||||
MsiCloseHandle(hrec);
|
||||
|
||||
|
@ -4644,16 +4632,10 @@ static void test_order(void)
|
|||
ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
|
||||
|
||||
val = MsiRecordGetInteger(hrec, 1);
|
||||
todo_wine
|
||||
{
|
||||
ok(val == 1, "Expected 1, got %d\n", val);
|
||||
}
|
||||
|
||||
val = MsiRecordGetInteger(hrec, 2);
|
||||
todo_wine
|
||||
{
|
||||
ok(val == 2, "Expected 2, got %d\n", val);
|
||||
}
|
||||
|
||||
MsiCloseHandle(hrec);
|
||||
|
||||
|
@ -4673,10 +4655,7 @@ static void test_order(void)
|
|||
ok(val == 1, "Expected 1, got %d\n", val);
|
||||
|
||||
val = MsiRecordGetInteger(hrec, 2);
|
||||
todo_wine
|
||||
{
|
||||
ok(val == 12, "Expected 12, got %d\n", val);
|
||||
}
|
||||
|
||||
MsiCloseHandle(hrec);
|
||||
|
||||
|
@ -4687,10 +4666,7 @@ static void test_order(void)
|
|||
ok(val == 3, "Expected 3, got %d\n", val);
|
||||
|
||||
val = MsiRecordGetInteger(hrec, 2);
|
||||
todo_wine
|
||||
{
|
||||
ok(val == 12, "Expected 12, got %d\n", val);
|
||||
}
|
||||
|
||||
MsiCloseHandle(hrec);
|
||||
|
||||
|
@ -4701,10 +4677,7 @@ static void test_order(void)
|
|||
ok(val == 5, "Expected 5, got %d\n", val);
|
||||
|
||||
val = MsiRecordGetInteger(hrec, 2);
|
||||
todo_wine
|
||||
{
|
||||
ok(val == 12, "Expected 12, got %d\n", val);
|
||||
}
|
||||
|
||||
MsiCloseHandle(hrec);
|
||||
|
||||
|
@ -4715,10 +4688,7 @@ static void test_order(void)
|
|||
ok(val == 1, "Expected 1, got %d\n", val);
|
||||
|
||||
val = MsiRecordGetInteger(hrec, 2);
|
||||
todo_wine
|
||||
{
|
||||
ok(val == 14, "Expected 14, got %d\n", val);
|
||||
}
|
||||
|
||||
MsiCloseHandle(hrec);
|
||||
|
||||
|
@ -4729,10 +4699,7 @@ static void test_order(void)
|
|||
ok(val == 3, "Expected 3, got %d\n", val);
|
||||
|
||||
val = MsiRecordGetInteger(hrec, 2);
|
||||
todo_wine
|
||||
{
|
||||
ok(val == 14, "Expected 14, got %d\n", val);
|
||||
}
|
||||
|
||||
MsiCloseHandle(hrec);
|
||||
|
||||
|
@ -4743,10 +4710,7 @@ static void test_order(void)
|
|||
ok(val == 5, "Expected 5, got %d\n", val);
|
||||
|
||||
val = MsiRecordGetInteger(hrec, 2);
|
||||
todo_wine
|
||||
{
|
||||
ok(val == 14, "Expected 14, got %d\n", val);
|
||||
}
|
||||
|
||||
MsiCloseHandle(hrec);
|
||||
|
||||
|
@ -4757,10 +4721,7 @@ static void test_order(void)
|
|||
ok(val == 1, "Expected 1, got %d\n", val);
|
||||
|
||||
val = MsiRecordGetInteger(hrec, 2);
|
||||
todo_wine
|
||||
{
|
||||
ok(val == 10, "Expected 10, got %d\n", val);
|
||||
}
|
||||
|
||||
MsiCloseHandle(hrec);
|
||||
|
||||
|
@ -4771,10 +4732,7 @@ static void test_order(void)
|
|||
ok(val == 3, "Expected 3, got %d\n", val);
|
||||
|
||||
val = MsiRecordGetInteger(hrec, 2);
|
||||
todo_wine
|
||||
{
|
||||
ok(val == 10, "Expected 10, got %d\n", val);
|
||||
}
|
||||
|
||||
MsiCloseHandle(hrec);
|
||||
|
||||
|
@ -4785,10 +4743,7 @@ static void test_order(void)
|
|||
ok(val == 5, "Expected 5, got %d\n", val);
|
||||
|
||||
val = MsiRecordGetInteger(hrec, 2);
|
||||
todo_wine
|
||||
{
|
||||
ok(val == 10, "Expected 10, got %d\n", val);
|
||||
}
|
||||
|
||||
MsiCloseHandle(hrec);
|
||||
|
||||
|
|
|
@ -532,6 +532,14 @@ static UINT WHERE_find_matching_rows( struct tagMSIVIEW *view, UINT col,
|
|||
return find_entry_in_hash(wv->reorder, *row, row);
|
||||
}
|
||||
|
||||
static UINT WHERE_sort(struct tagMSIVIEW *view, column_info *columns)
|
||||
{
|
||||
MSIWHEREVIEW *wv = (MSIWHEREVIEW *)view;
|
||||
|
||||
TRACE("%p %p\n", view, columns);
|
||||
|
||||
return wv->table->ops->sort(wv->table, columns);
|
||||
}
|
||||
|
||||
static const MSIVIEWOPS where_ops =
|
||||
{
|
||||
|
@ -552,6 +560,7 @@ static const MSIVIEWOPS where_ops =
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
WHERE_sort,
|
||||
};
|
||||
|
||||
static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr *cond,
|
||||
|
|
Loading…
Reference in New Issue