select page by row_number for MS SQL 2008 #93

This commit is contained in:
Jan Prochazka
2021-04-25 11:48:23 +02:00
parent 8ff706a17f
commit 67e1913683
13 changed files with 178 additions and 45 deletions

View File

@@ -1,6 +1,14 @@
import _ from 'lodash';
import { GridConfig, GridCache, GridConfigColumns, createGridCache, GroupFunc } from './GridConfig';
import { ForeignKeyInfo, TableInfo, ColumnInfo, EngineDriver, NamedObjectInfo, DatabaseInfo } from 'dbgate-types';
import {
ForeignKeyInfo,
TableInfo,
ColumnInfo,
EngineDriver,
NamedObjectInfo,
DatabaseInfo,
SqlDialect,
} from 'dbgate-types';
import { parseFilter, getFilterType, getFilterValueExpression } from 'dbgate-filterparser';
import { filterName } from './filterName';
import { ChangeSetFieldDefinition, ChangeSetRowDefinition } from './ChangeSet';
@@ -12,6 +20,7 @@ export class FormViewDisplay {
isLoadedCorrectly = true;
columns: DisplayColumn[];
public baseTable: TableInfo;
dialect: SqlDialect;
constructor(
public config: GridConfig,
@@ -19,8 +28,11 @@ export class FormViewDisplay {
public cache: GridCache,
protected setCache: ChangeCacheFunc,
public driver?: EngineDriver,
public dbinfo: DatabaseInfo = null
) {}
public dbinfo: DatabaseInfo = null,
public serverVersion = null
) {
this.dialect = (driver?.dialectByVersion && driver?.dialectByVersion(serverVersion)) || driver?.dialect;
}
addFilterColumn(column) {
if (!column) return;

View File

@@ -8,6 +8,7 @@ import {
NamedObjectInfo,
DatabaseInfo,
CollectionInfo,
SqlDialect,
} from 'dbgate-types';
import { parseFilter, getFilterType } from 'dbgate-filterparser';
import { filterName } from './filterName';
@@ -60,8 +61,12 @@ export abstract class GridDisplay {
public cache: GridCache,
protected setCache: ChangeCacheFunc,
public driver?: EngineDriver,
public dbinfo: DatabaseInfo = null
) {}
public dbinfo: DatabaseInfo = null,
public serverVersion = null
) {
this.dialect = (driver?.dialectByVersion && driver?.dialectByVersion(serverVersion)) || driver?.dialect;
}
dialect: SqlDialect;
columns: DisplayColumn[];
baseTable?: TableInfo;
baseCollection?: CollectionInfo;
@@ -460,12 +465,75 @@ export abstract class GridDisplay {
return select;
}
getRowNumberOverSelect(select: Select, offset: number, count: number): Select {
const innerSelect: Select = {
commandType: 'select',
from: select.from,
where: select.where,
columns: [
...select.columns,
{
alias: '_rowNumber',
exprType: 'rowNumber',
orderBy: select.orderBy
? select.orderBy.map(x =>
x.exprType != 'column'
? x
: x.source
? x
: {
...x,
source: { alias: 'basetbl' },
}
)
: [
{
...select.columns[0],
direction: 'ASC',
},
],
},
],
};
const res: Select = {
commandType: 'select',
selectAll: true,
from: {
subQuery: innerSelect,
alias: '_RowNumberResult',
},
where: {
conditionType: 'between',
expr: {
exprType: 'column',
columnName: '_RowNumber',
source: {
alias: '_RowNumberResult',
},
},
left: {
exprType: 'value',
value: offset + 1,
},
right: {
exprType: 'value',
value: offset + count,
},
},
};
return res;
}
getPageQuery(offset: number, count: number) {
if (!this.driver) return null;
const select = this.createSelect();
let select = this.createSelect();
if (!select) return null;
if (this.driver.dialect.rangeSelect) select.range = { offset: offset, limit: count };
else if (this.driver.dialect.limitSelect) select.topRecords = count;
if (this.dialect.rangeSelect) select.range = { offset: offset, limit: count };
else if (this.dialect.rowNumberOverPaging && offset > 0)
select = this.getRowNumberOverSelect(select, offset, count);
else if (this.dialect.limitSelect) select.topRecords = count;
const sql = treeToSql(this.driver, select, dumpSqlSelect);
return sql;
}

View File

@@ -29,9 +29,10 @@ export class TableFormViewDisplay extends FormViewDisplay {
cache: GridCache,
setCache: ChangeCacheFunc,
dbinfo: DatabaseInfo,
displayOptions
displayOptions,
serverVersion
) {
super(config, setConfig, cache, setCache, driver, dbinfo);
super(config, setConfig, cache, setCache, driver, dbinfo, serverVersion);
this.gridDisplay = new TableGridDisplay(
tableName,
driver,
@@ -40,7 +41,8 @@ export class TableFormViewDisplay extends FormViewDisplay {
cache,
setCache,
dbinfo,
displayOptions
displayOptions,
serverVersion
);
this.gridDisplay.addAllExpandedColumnsToSelected = true;

View File

@@ -18,9 +18,10 @@ export class TableGridDisplay extends GridDisplay {
cache: GridCache,
setCache: ChangeCacheFunc,
dbinfo: DatabaseInfo,
public displayOptions: any
public displayOptions: any,
serverVersion
) {
super(config, setConfig, cache, setCache, driver, dbinfo);
super(config, setConfig, cache, setCache, driver, dbinfo, serverVersion);
this.table = this.findTable(tableName);
if (!this.table) {

View File

@@ -10,9 +10,10 @@ export class ViewGridDisplay extends GridDisplay {
config: GridConfig,
setConfig: ChangeConfigFunc,
cache: GridCache,
setCache: ChangeCacheFunc
setCache: ChangeCacheFunc,
serverVersion
) {
super(config, setConfig, cache, setCache, driver);
super(config, setConfig, cache, setCache, driver, serverVersion);
this.columns = this.getDisplayColumns(view);
this.filterable = true;
this.sortable = true;

View File

@@ -62,5 +62,12 @@ export function dumpSqlCondition(dmp: SqlDumper, condition: Condition) {
dumpSqlSelect(dmp, condition.subQuery);
dmp.put(')');
break;
case 'between':
dumpSqlExpression(dmp, condition.expr);
dmp.put(' ^between ');
dumpSqlExpression(dmp, condition.left);
dmp.put(' ^and ');
dumpSqlExpression(dmp, condition.right);
break;
}
}

View File

@@ -38,5 +38,14 @@ export function dumpSqlExpression(dmp: SqlDumper, expr: Expression) {
case 'transform':
dmp.transform(expr.transform, () => dumpSqlExpression(dmp, expr.expr));
break;
case 'rowNumber':
dmp.put(" ^row_number() ^over (^order ^by ");
dmp.putCollection(', ', expr.orderBy, x => {
dumpSqlExpression(dmp, x);
dmp.put(' %k', x.direction);
});
dmp.put(")");
break;
}
}

View File

@@ -92,6 +92,13 @@ export interface NotExistsCondition {
subQuery: Select;
}
export interface BetweenCondition {
conditionType: 'between';
expr: Expression;
left: Expression;
right: Expression;
}
export type Condition =
| BinaryCondition
| NotCondition
@@ -99,7 +106,8 @@ export type Condition =
| CompoudCondition
| LikeCondition
| ExistsCondition
| NotExistsCondition;
| NotExistsCondition
| BetweenCondition;
export interface Source {
name?: NamedObjectInfo;
@@ -153,13 +161,19 @@ export interface TranformExpression {
transform: TransformType;
}
export interface RowNumberExpression {
exprType: 'rowNumber';
orderBy: OrderByExpression[];
}
export type Expression =
| ColumnRefExpression
| ValueExpression
| PlaceholderExpression
| RawExpression
| CallExpression
| TranformExpression;
| TranformExpression
| RowNumberExpression;
export type OrderByExpression = Expression & { direction: 'ASC' | 'DESC' };
export type ResultField = Expression & { alias?: string };

View File

@@ -1,6 +1,7 @@
export interface SqlDialect {
rangeSelect?: boolean;
limitSelect?: boolean;
rowNumberOverPaging?: boolean;
stringEscapeChar: string;
offsetFetchRangeSyntax?: boolean;
quoteIdentifier(s: string): string;

View File

@@ -61,6 +61,7 @@ export interface EngineDriver {
analyseFull(pool: any): Promise<DatabaseInfo>;
analyseIncremental(pool: any, structure: DatabaseInfo): Promise<DatabaseInfo>;
dialect: SqlDialect;
dialectByVersion(version): SqlDialect;
createDumper(): SqlDumper;
getAuthTypes(): EngineAuthType[];
readCollection(pool: any, options: ReadCollectionOptions): Promise<any>;

View File

@@ -43,7 +43,7 @@
$: connection = useConnectionInfo({ conid });
$: dbinfo = useDatabaseInfo({ conid, database });
// $: serverVersion = useDatabaseServerVersion({ conid, database });
$: serverVersion = useDatabaseServerVersion({ conid, database });
// $: console.log('serverVersion', $serverVersion);
@@ -53,31 +53,35 @@
// $: console.log('display', display);
$: display = connection
? new TableGridDisplay(
{ schemaName, pureName },
findEngineDriver($connection, $extensions),
config,
setConfig,
cache,
setCache,
$dbinfo,
{ showHintColumns: getBoolSettingsValue('dataGrid.showHintColumns', true) }
)
: null;
$: display =
connection && $serverVersion
? new TableGridDisplay(
{ schemaName, pureName },
findEngineDriver($connection, $extensions),
config,
setConfig,
cache,
setCache,
$dbinfo,
{ showHintColumns: getBoolSettingsValue('dataGrid.showHintColumns', true) },
$serverVersion
)
: null;
$: formDisplay = connection
? new TableFormViewDisplay(
{ schemaName, pureName },
findEngineDriver($connection, $extensions),
config,
setConfig,
cache,
setCache,
$dbinfo,
{ showHintColumns: getBoolSettingsValue('dataGrid.showHintColumns', true) }
)
: null;
$: formDisplay =
connection && $serverVersion
? new TableFormViewDisplay(
{ schemaName, pureName },
findEngineDriver($connection, $extensions),
config,
setConfig,
cache,
setCache,
$dbinfo,
{ showHintColumns: getBoolSettingsValue('dataGrid.showHintColumns', true) },
$serverVersion
)
: null;
const setChildConfig = (value, reference = undefined) => {
if (_.isFunction(value)) {

View File

@@ -11,7 +11,7 @@
import DataGrid from '../datagrid/DataGrid.svelte';
import SqlDataGridCore from '../datagrid/SqlDataGridCore.svelte';
import { extensions } from '../stores';
import { useConnectionInfo, useViewInfo } from '../utility/metadataLoaders';
import { useConnectionInfo, useDatabaseServerVersion, useViewInfo } from '../utility/metadataLoaders';
import useGridConfig from '../utility/useGridConfig';
export let tabid;
@@ -22,12 +22,13 @@
$: connection = useConnectionInfo({ conid });
$: viewInfo = useViewInfo({ conid, database, schemaName, pureName });
$: serverVersion = useDatabaseServerVersion({ conid, database });
const config = useGridConfig(tabid);
const cache = writable(createGridCache());
$: display =
$viewInfo && $connection
$viewInfo && $connection && $serverVersion
? new ViewGridDisplay(
$viewInfo,
findEngineDriver($connection, $extensions),
@@ -35,7 +36,8 @@
$config,
config.update,
$cache,
cache.update
cache.update,
$serverVersion
)
: null;
</script>

View File

@@ -6,6 +6,7 @@ const dialect = {
limitSelect: true,
rangeSelect: true,
offsetFetchRangeSyntax: true,
rowNumberOverPaging: true,
stringEscapeChar: "'",
fallbackDataType: 'nvarchar(max)',
explicitDropConstraint: false,
@@ -21,6 +22,16 @@ const driver = {
...driverBase,
dumperClass: MsSqlDumper,
dialect,
dialectByVersion(version) {
if (version && version.productVersionNumber < 11) {
return {
...dialect,
rangeSelect: false,
offsetFetchRangeSyntax: false,
};
}
return dialect;
},
engine: 'mssql@dbgate-plugin-mssql',
title: 'Microsoft SQL Server',
defaultPort: 1433,