dbtour-source-mssql 0.2.4 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/map.d.ts CHANGED
@@ -1,8 +1,11 @@
1
1
  import type { Database } from 'dbtour';
2
+ /** node-mssql returns a bigint as a string, since it may not fit a JavaScript number. */
3
+ type Count = number | string;
2
4
  export interface InfoRow {
3
5
  name: string;
4
6
  version: string | null;
5
7
  description: string | null;
8
+ readAt?: string | null;
6
9
  }
7
10
  export interface TableRow {
8
11
  schema: string;
@@ -10,6 +13,9 @@ export interface TableRow {
10
13
  kind: 'table' | 'view';
11
14
  description: string | null;
12
15
  definition: string | null;
16
+ rows?: Count | null;
17
+ dataBytes?: Count | null;
18
+ indexBytes?: Count | null;
13
19
  }
14
20
  export interface ColumnRow {
15
21
  schema: string;
@@ -83,3 +89,4 @@ export declare function toRecordsets(sets: unknown[][]): Recordsets;
83
89
  export declare function mapRecordsets(sets: Recordsets, options?: MapOptions): Database;
84
90
  /** The type as SQL Server would spell it in a CREATE TABLE: nvarchar(320), varchar(max), decimal(18,2), datetime2(7). */
85
91
  export declare function formatType(row: Pick<ColumnRow, 'type' | 'maxLength' | 'precision' | 'scale'>): string;
92
+ export {};
package/dist/map.js CHANGED
@@ -22,6 +22,10 @@ export function mapRecordsets(sets, options = {}) {
22
22
  table.description = row.description;
23
23
  if (row.kind === 'view' && row.definition)
24
24
  table.definition = row.definition;
25
+ // A byte count past 2^53 loses its last digits as a number, which no reader of a size will miss. Only a
26
+ // table: an indexed view has rows in sys.partitions too, but they are the view's results, not stored data.
27
+ if (row.kind === 'table' && row.rows !== null && row.rows !== undefined)
28
+ table.stats = { rows: Number(row.rows), dataBytes: Number(row.dataBytes ?? 0), indexBytes: Number(row.indexBytes ?? 0) };
25
29
  schema.tables.push(table);
26
30
  tables.set(`${row.schema}.${row.name}`, table);
27
31
  }
@@ -91,6 +95,8 @@ export function mapRecordsets(sets, options = {}) {
91
95
  database.version = info.version;
92
96
  if (info.description)
93
97
  database.description = info.description;
98
+ if (info.readAt && [...tables.values()].some((t) => t.stats))
99
+ database.statsReadAt = info.readAt;
94
100
  return database;
95
101
  }
96
102
  /** The type as SQL Server would spell it in a CREATE TABLE: nvarchar(320), varchar(max), decimal(18,2), datetime2(7). */
package/dist/query.sql CHANGED
@@ -1,22 +1,50 @@
1
1
  -- Everything dbtour needs from SQL Server, in one batch of seven result sets, read in this order by map.ts.
2
- -- Reads the catalogue views only: a login with VIEW DEFINITION on the database is enough.
2
+ -- Reads the catalogue views only: a login with VIEW DEFINITION on the database is enough. That is why the
3
+ -- sizes come from sys.partitions and sys.allocation_units, catalogue views, rather than
4
+ -- sys.dm_db_partition_stats, which wants VIEW DATABASE STATE and would fail the whole batch without it.
3
5
  SET NOCOUNT ON;
4
6
 
5
7
  -- 1. The database
6
8
  SELECT DB_NAME() AS [name],
7
9
  CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(50)) AS [version],
8
- (SELECT TOP (1) CAST([value] AS nvarchar(max)) FROM sys.extended_properties WHERE class = 0 AND [name] = 'MS_Description') AS [description];
10
+ (SELECT TOP (1) CAST([value] AS nvarchar(max)) FROM sys.extended_properties WHERE class = 0 AND [name] = 'MS_Description') AS [description],
11
+ CONVERT(nvarchar(33), SYSUTCDATETIME(), 127) + 'Z' AS [readAt];
9
12
 
10
- -- 2. Tables and views
13
+ -- 2. Tables and views, with each table's rows and bytes as the catalogue counts them (no row is read).
14
+ -- Rows are the heap's or the clustered index's (index_id 0 or 1); data bytes are those pages, index bytes
15
+ -- every other index's. A page is 8 KB. A view has no partitions, so its three are NULL.
11
16
  SELECT s.[name] AS [schema],
12
17
  o.[name] AS [name],
13
18
  CASE o.[type] WHEN 'V' THEN 'view' ELSE 'table' END AS [kind],
14
19
  CAST(ep.[value] AS nvarchar(max)) AS [description],
15
- m.[definition] AS [definition]
20
+ m.[definition] AS [definition],
21
+ r.[rows] AS [rows],
22
+ b.dataBytes AS [dataBytes],
23
+ b.indexBytes AS [indexBytes]
16
24
  FROM sys.objects o
17
25
  JOIN sys.schemas s ON s.schema_id = o.schema_id
18
26
  LEFT JOIN sys.extended_properties ep ON ep.class = 1 AND ep.major_id = o.object_id AND ep.minor_id = 0 AND ep.[name] = 'MS_Description'
19
27
  LEFT JOIN sys.sql_modules m ON m.object_id = o.object_id
28
+ -- Counted apart: joining the allocation units to the partitions repeats each partition's rows.
29
+ OUTER APPLY (SELECT SUM(p.[rows]) AS [rows] FROM sys.partitions p WHERE p.object_id = o.object_id AND p.index_id IN (0, 1)) r
30
+ OUTER APPLY (
31
+ SELECT SUM(CASE WHEN u.index_id IN (0, 1) THEN u.used_pages ELSE 0 END) * 8192 AS dataBytes,
32
+ SUM(CASE WHEN u.index_id > 1 THEN u.used_pages ELSE 0 END) * 8192 AS indexBytes
33
+ FROM (
34
+ -- In-row and row-overflow pages belong to the partition's hobt, large-object pages to the partition.
35
+ SELECT p.index_id, au.used_pages
36
+ FROM sys.partitions p
37
+ JOIN sys.allocation_units au ON au.container_id = CASE WHEN au.[type] = 2 THEN p.partition_id ELSE p.hobt_id END
38
+ WHERE p.object_id = o.object_id
39
+ UNION ALL
40
+ -- A columnstore's delta stores, rows not yet compressed, are hobts of their own that sys.partitions
41
+ -- does not list: their pages are counted with the columnstore index they belong to.
42
+ SELECT rg.index_id, au.used_pages
43
+ FROM sys.column_store_row_groups rg
44
+ JOIN sys.allocation_units au ON au.container_id = rg.delta_store_hobt_id
45
+ WHERE rg.object_id = o.object_id AND rg.delta_store_hobt_id IS NOT NULL
46
+ ) u
47
+ ) b
20
48
  WHERE o.[type] IN ('U', 'V') AND o.is_ms_shipped = 0
21
49
  ORDER BY s.[name], o.[name];
22
50
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dbtour-source-mssql",
3
- "version": "0.2.4",
3
+ "version": "0.3.0",
4
4
  "description": "SQL Server source for dbtour: tables, views, columns, keys, relations, indexes, descriptions.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -36,6 +36,6 @@
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/mssql": "^9.1.8",
39
- "dbtour": "0.2.4"
39
+ "dbtour": "0.3.0"
40
40
  }
41
41
  }