mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-05-02 10:13:57 +00:00
select page by row_number for MS SQL 2008 #93
This commit is contained in:
@@ -1,6 +1,14 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { GridConfig, GridCache, GridConfigColumns, createGridCache, GroupFunc } from './GridConfig';
|
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 { parseFilter, getFilterType, getFilterValueExpression } from 'dbgate-filterparser';
|
||||||
import { filterName } from './filterName';
|
import { filterName } from './filterName';
|
||||||
import { ChangeSetFieldDefinition, ChangeSetRowDefinition } from './ChangeSet';
|
import { ChangeSetFieldDefinition, ChangeSetRowDefinition } from './ChangeSet';
|
||||||
@@ -12,6 +20,7 @@ export class FormViewDisplay {
|
|||||||
isLoadedCorrectly = true;
|
isLoadedCorrectly = true;
|
||||||
columns: DisplayColumn[];
|
columns: DisplayColumn[];
|
||||||
public baseTable: TableInfo;
|
public baseTable: TableInfo;
|
||||||
|
dialect: SqlDialect;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public config: GridConfig,
|
public config: GridConfig,
|
||||||
@@ -19,8 +28,11 @@ export class FormViewDisplay {
|
|||||||
public cache: GridCache,
|
public cache: GridCache,
|
||||||
protected setCache: ChangeCacheFunc,
|
protected setCache: ChangeCacheFunc,
|
||||||
public driver?: EngineDriver,
|
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) {
|
addFilterColumn(column) {
|
||||||
if (!column) return;
|
if (!column) return;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
NamedObjectInfo,
|
NamedObjectInfo,
|
||||||
DatabaseInfo,
|
DatabaseInfo,
|
||||||
CollectionInfo,
|
CollectionInfo,
|
||||||
|
SqlDialect,
|
||||||
} from 'dbgate-types';
|
} from 'dbgate-types';
|
||||||
import { parseFilter, getFilterType } from 'dbgate-filterparser';
|
import { parseFilter, getFilterType } from 'dbgate-filterparser';
|
||||||
import { filterName } from './filterName';
|
import { filterName } from './filterName';
|
||||||
@@ -60,8 +61,12 @@ export abstract class GridDisplay {
|
|||||||
public cache: GridCache,
|
public cache: GridCache,
|
||||||
protected setCache: ChangeCacheFunc,
|
protected setCache: ChangeCacheFunc,
|
||||||
public driver?: EngineDriver,
|
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[];
|
columns: DisplayColumn[];
|
||||||
baseTable?: TableInfo;
|
baseTable?: TableInfo;
|
||||||
baseCollection?: CollectionInfo;
|
baseCollection?: CollectionInfo;
|
||||||
@@ -460,12 +465,75 @@ export abstract class GridDisplay {
|
|||||||
return select;
|
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) {
|
getPageQuery(offset: number, count: number) {
|
||||||
if (!this.driver) return null;
|
if (!this.driver) return null;
|
||||||
const select = this.createSelect();
|
let select = this.createSelect();
|
||||||
if (!select) return null;
|
if (!select) return null;
|
||||||
if (this.driver.dialect.rangeSelect) select.range = { offset: offset, limit: count };
|
if (this.dialect.rangeSelect) select.range = { offset: offset, limit: count };
|
||||||
else if (this.driver.dialect.limitSelect) select.topRecords = 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);
|
const sql = treeToSql(this.driver, select, dumpSqlSelect);
|
||||||
return sql;
|
return sql;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,9 +29,10 @@ export class TableFormViewDisplay extends FormViewDisplay {
|
|||||||
cache: GridCache,
|
cache: GridCache,
|
||||||
setCache: ChangeCacheFunc,
|
setCache: ChangeCacheFunc,
|
||||||
dbinfo: DatabaseInfo,
|
dbinfo: DatabaseInfo,
|
||||||
displayOptions
|
displayOptions,
|
||||||
|
serverVersion
|
||||||
) {
|
) {
|
||||||
super(config, setConfig, cache, setCache, driver, dbinfo);
|
super(config, setConfig, cache, setCache, driver, dbinfo, serverVersion);
|
||||||
this.gridDisplay = new TableGridDisplay(
|
this.gridDisplay = new TableGridDisplay(
|
||||||
tableName,
|
tableName,
|
||||||
driver,
|
driver,
|
||||||
@@ -40,7 +41,8 @@ export class TableFormViewDisplay extends FormViewDisplay {
|
|||||||
cache,
|
cache,
|
||||||
setCache,
|
setCache,
|
||||||
dbinfo,
|
dbinfo,
|
||||||
displayOptions
|
displayOptions,
|
||||||
|
serverVersion
|
||||||
);
|
);
|
||||||
this.gridDisplay.addAllExpandedColumnsToSelected = true;
|
this.gridDisplay.addAllExpandedColumnsToSelected = true;
|
||||||
|
|
||||||
|
|||||||
@@ -18,9 +18,10 @@ export class TableGridDisplay extends GridDisplay {
|
|||||||
cache: GridCache,
|
cache: GridCache,
|
||||||
setCache: ChangeCacheFunc,
|
setCache: ChangeCacheFunc,
|
||||||
dbinfo: DatabaseInfo,
|
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);
|
this.table = this.findTable(tableName);
|
||||||
if (!this.table) {
|
if (!this.table) {
|
||||||
|
|||||||
@@ -10,9 +10,10 @@ export class ViewGridDisplay extends GridDisplay {
|
|||||||
config: GridConfig,
|
config: GridConfig,
|
||||||
setConfig: ChangeConfigFunc,
|
setConfig: ChangeConfigFunc,
|
||||||
cache: GridCache,
|
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.columns = this.getDisplayColumns(view);
|
||||||
this.filterable = true;
|
this.filterable = true;
|
||||||
this.sortable = true;
|
this.sortable = true;
|
||||||
|
|||||||
@@ -62,5 +62,12 @@ export function dumpSqlCondition(dmp: SqlDumper, condition: Condition) {
|
|||||||
dumpSqlSelect(dmp, condition.subQuery);
|
dumpSqlSelect(dmp, condition.subQuery);
|
||||||
dmp.put(')');
|
dmp.put(')');
|
||||||
break;
|
break;
|
||||||
|
case 'between':
|
||||||
|
dumpSqlExpression(dmp, condition.expr);
|
||||||
|
dmp.put(' ^between ');
|
||||||
|
dumpSqlExpression(dmp, condition.left);
|
||||||
|
dmp.put(' ^and ');
|
||||||
|
dumpSqlExpression(dmp, condition.right);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,5 +38,14 @@ export function dumpSqlExpression(dmp: SqlDumper, expr: Expression) {
|
|||||||
case 'transform':
|
case 'transform':
|
||||||
dmp.transform(expr.transform, () => dumpSqlExpression(dmp, expr.expr));
|
dmp.transform(expr.transform, () => dumpSqlExpression(dmp, expr.expr));
|
||||||
break;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,6 +92,13 @@ export interface NotExistsCondition {
|
|||||||
subQuery: Select;
|
subQuery: Select;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface BetweenCondition {
|
||||||
|
conditionType: 'between';
|
||||||
|
expr: Expression;
|
||||||
|
left: Expression;
|
||||||
|
right: Expression;
|
||||||
|
}
|
||||||
|
|
||||||
export type Condition =
|
export type Condition =
|
||||||
| BinaryCondition
|
| BinaryCondition
|
||||||
| NotCondition
|
| NotCondition
|
||||||
@@ -99,7 +106,8 @@ export type Condition =
|
|||||||
| CompoudCondition
|
| CompoudCondition
|
||||||
| LikeCondition
|
| LikeCondition
|
||||||
| ExistsCondition
|
| ExistsCondition
|
||||||
| NotExistsCondition;
|
| NotExistsCondition
|
||||||
|
| BetweenCondition;
|
||||||
|
|
||||||
export interface Source {
|
export interface Source {
|
||||||
name?: NamedObjectInfo;
|
name?: NamedObjectInfo;
|
||||||
@@ -153,13 +161,19 @@ export interface TranformExpression {
|
|||||||
transform: TransformType;
|
transform: TransformType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RowNumberExpression {
|
||||||
|
exprType: 'rowNumber';
|
||||||
|
orderBy: OrderByExpression[];
|
||||||
|
}
|
||||||
|
|
||||||
export type Expression =
|
export type Expression =
|
||||||
| ColumnRefExpression
|
| ColumnRefExpression
|
||||||
| ValueExpression
|
| ValueExpression
|
||||||
| PlaceholderExpression
|
| PlaceholderExpression
|
||||||
| RawExpression
|
| RawExpression
|
||||||
| CallExpression
|
| CallExpression
|
||||||
| TranformExpression;
|
| TranformExpression
|
||||||
|
| RowNumberExpression;
|
||||||
export type OrderByExpression = Expression & { direction: 'ASC' | 'DESC' };
|
export type OrderByExpression = Expression & { direction: 'ASC' | 'DESC' };
|
||||||
|
|
||||||
export type ResultField = Expression & { alias?: string };
|
export type ResultField = Expression & { alias?: string };
|
||||||
|
|||||||
1
packages/types/dialect.d.ts
vendored
1
packages/types/dialect.d.ts
vendored
@@ -1,6 +1,7 @@
|
|||||||
export interface SqlDialect {
|
export interface SqlDialect {
|
||||||
rangeSelect?: boolean;
|
rangeSelect?: boolean;
|
||||||
limitSelect?: boolean;
|
limitSelect?: boolean;
|
||||||
|
rowNumberOverPaging?: boolean;
|
||||||
stringEscapeChar: string;
|
stringEscapeChar: string;
|
||||||
offsetFetchRangeSyntax?: boolean;
|
offsetFetchRangeSyntax?: boolean;
|
||||||
quoteIdentifier(s: string): string;
|
quoteIdentifier(s: string): string;
|
||||||
|
|||||||
1
packages/types/engines.d.ts
vendored
1
packages/types/engines.d.ts
vendored
@@ -61,6 +61,7 @@ export interface EngineDriver {
|
|||||||
analyseFull(pool: any): Promise<DatabaseInfo>;
|
analyseFull(pool: any): Promise<DatabaseInfo>;
|
||||||
analyseIncremental(pool: any, structure: DatabaseInfo): Promise<DatabaseInfo>;
|
analyseIncremental(pool: any, structure: DatabaseInfo): Promise<DatabaseInfo>;
|
||||||
dialect: SqlDialect;
|
dialect: SqlDialect;
|
||||||
|
dialectByVersion(version): SqlDialect;
|
||||||
createDumper(): SqlDumper;
|
createDumper(): SqlDumper;
|
||||||
getAuthTypes(): EngineAuthType[];
|
getAuthTypes(): EngineAuthType[];
|
||||||
readCollection(pool: any, options: ReadCollectionOptions): Promise<any>;
|
readCollection(pool: any, options: ReadCollectionOptions): Promise<any>;
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
|
|
||||||
$: connection = useConnectionInfo({ conid });
|
$: connection = useConnectionInfo({ conid });
|
||||||
$: dbinfo = useDatabaseInfo({ conid, database });
|
$: dbinfo = useDatabaseInfo({ conid, database });
|
||||||
// $: serverVersion = useDatabaseServerVersion({ conid, database });
|
$: serverVersion = useDatabaseServerVersion({ conid, database });
|
||||||
|
|
||||||
// $: console.log('serverVersion', $serverVersion);
|
// $: console.log('serverVersion', $serverVersion);
|
||||||
|
|
||||||
@@ -53,7 +53,8 @@
|
|||||||
|
|
||||||
// $: console.log('display', display);
|
// $: console.log('display', display);
|
||||||
|
|
||||||
$: display = connection
|
$: display =
|
||||||
|
connection && $serverVersion
|
||||||
? new TableGridDisplay(
|
? new TableGridDisplay(
|
||||||
{ schemaName, pureName },
|
{ schemaName, pureName },
|
||||||
findEngineDriver($connection, $extensions),
|
findEngineDriver($connection, $extensions),
|
||||||
@@ -62,11 +63,13 @@
|
|||||||
cache,
|
cache,
|
||||||
setCache,
|
setCache,
|
||||||
$dbinfo,
|
$dbinfo,
|
||||||
{ showHintColumns: getBoolSettingsValue('dataGrid.showHintColumns', true) }
|
{ showHintColumns: getBoolSettingsValue('dataGrid.showHintColumns', true) },
|
||||||
|
$serverVersion
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
$: formDisplay = connection
|
$: formDisplay =
|
||||||
|
connection && $serverVersion
|
||||||
? new TableFormViewDisplay(
|
? new TableFormViewDisplay(
|
||||||
{ schemaName, pureName },
|
{ schemaName, pureName },
|
||||||
findEngineDriver($connection, $extensions),
|
findEngineDriver($connection, $extensions),
|
||||||
@@ -75,7 +78,8 @@
|
|||||||
cache,
|
cache,
|
||||||
setCache,
|
setCache,
|
||||||
$dbinfo,
|
$dbinfo,
|
||||||
{ showHintColumns: getBoolSettingsValue('dataGrid.showHintColumns', true) }
|
{ showHintColumns: getBoolSettingsValue('dataGrid.showHintColumns', true) },
|
||||||
|
$serverVersion
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
import DataGrid from '../datagrid/DataGrid.svelte';
|
import DataGrid from '../datagrid/DataGrid.svelte';
|
||||||
import SqlDataGridCore from '../datagrid/SqlDataGridCore.svelte';
|
import SqlDataGridCore from '../datagrid/SqlDataGridCore.svelte';
|
||||||
import { extensions } from '../stores';
|
import { extensions } from '../stores';
|
||||||
import { useConnectionInfo, useViewInfo } from '../utility/metadataLoaders';
|
import { useConnectionInfo, useDatabaseServerVersion, useViewInfo } from '../utility/metadataLoaders';
|
||||||
import useGridConfig from '../utility/useGridConfig';
|
import useGridConfig from '../utility/useGridConfig';
|
||||||
|
|
||||||
export let tabid;
|
export let tabid;
|
||||||
@@ -22,12 +22,13 @@
|
|||||||
|
|
||||||
$: connection = useConnectionInfo({ conid });
|
$: connection = useConnectionInfo({ conid });
|
||||||
$: viewInfo = useViewInfo({ conid, database, schemaName, pureName });
|
$: viewInfo = useViewInfo({ conid, database, schemaName, pureName });
|
||||||
|
$: serverVersion = useDatabaseServerVersion({ conid, database });
|
||||||
|
|
||||||
const config = useGridConfig(tabid);
|
const config = useGridConfig(tabid);
|
||||||
const cache = writable(createGridCache());
|
const cache = writable(createGridCache());
|
||||||
|
|
||||||
$: display =
|
$: display =
|
||||||
$viewInfo && $connection
|
$viewInfo && $connection && $serverVersion
|
||||||
? new ViewGridDisplay(
|
? new ViewGridDisplay(
|
||||||
$viewInfo,
|
$viewInfo,
|
||||||
findEngineDriver($connection, $extensions),
|
findEngineDriver($connection, $extensions),
|
||||||
@@ -35,7 +36,8 @@
|
|||||||
$config,
|
$config,
|
||||||
config.update,
|
config.update,
|
||||||
$cache,
|
$cache,
|
||||||
cache.update
|
cache.update,
|
||||||
|
$serverVersion
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ const dialect = {
|
|||||||
limitSelect: true,
|
limitSelect: true,
|
||||||
rangeSelect: true,
|
rangeSelect: true,
|
||||||
offsetFetchRangeSyntax: true,
|
offsetFetchRangeSyntax: true,
|
||||||
|
rowNumberOverPaging: true,
|
||||||
stringEscapeChar: "'",
|
stringEscapeChar: "'",
|
||||||
fallbackDataType: 'nvarchar(max)',
|
fallbackDataType: 'nvarchar(max)',
|
||||||
explicitDropConstraint: false,
|
explicitDropConstraint: false,
|
||||||
@@ -21,6 +22,16 @@ const driver = {
|
|||||||
...driverBase,
|
...driverBase,
|
||||||
dumperClass: MsSqlDumper,
|
dumperClass: MsSqlDumper,
|
||||||
dialect,
|
dialect,
|
||||||
|
dialectByVersion(version) {
|
||||||
|
if (version && version.productVersionNumber < 11) {
|
||||||
|
return {
|
||||||
|
...dialect,
|
||||||
|
rangeSelect: false,
|
||||||
|
offsetFetchRangeSyntax: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return dialect;
|
||||||
|
},
|
||||||
engine: 'mssql@dbgate-plugin-mssql',
|
engine: 'mssql@dbgate-plugin-mssql',
|
||||||
title: 'Microsoft SQL Server',
|
title: 'Microsoft SQL Server',
|
||||||
defaultPort: 1433,
|
defaultPort: 1433,
|
||||||
|
|||||||
Reference in New Issue
Block a user