@query-doctor/core 0.0.3 → 0.0.4
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/index.cjs +222 -97
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +218 -97
- package/dist/index.js.map +1 -1
- package/dist/optimizer/genalgo.d.ts +9 -5
- package/dist/optimizer/genalgo.d.ts.map +1 -1
- package/dist/optimizer/genalgo.js +304 -0
- package/dist/optimizer/statistics.d.ts +1 -24
- package/dist/optimizer/statistics.d.ts.map +1 -1
- package/dist/optimizer/statistics.js +700 -0
- package/dist/package.json +25 -0
- package/dist/sql/analyzer.d.ts +3 -3
- package/dist/sql/analyzer.js +270 -0
- package/dist/sql/analyzer.test.d.ts +2 -0
- package/dist/sql/analyzer.test.d.ts.map +1 -0
- package/dist/sql/analyzer_test.js +584 -0
- package/dist/sql/builder.js +77 -0
- package/dist/sql/database.d.ts +5 -0
- package/dist/sql/database.d.ts.map +1 -1
- package/dist/sql/database.js +20 -0
- package/dist/sql/indexes.d.ts +8 -0
- package/dist/sql/indexes.d.ts.map +1 -0
- package/dist/sql/indexes.js +12 -0
- package/dist/sql/nudges.js +241 -0
- package/dist/sql/permutations.test.d.ts +2 -0
- package/dist/sql/permutations.test.d.ts.map +1 -0
- package/dist/sql/permutations_test.js +53 -0
- package/dist/sql/pg-identifier.d.ts +9 -0
- package/dist/sql/pg-identifier.d.ts.map +1 -0
- package/dist/sql/pg-identifier.test.d.ts +2 -0
- package/dist/sql/pg-identifier.test.d.ts.map +1 -0
- package/dist/sql/walker.d.ts +2 -2
- package/dist/sql/walker.js +295 -0
- package/package.json +2 -2
- package/dist/index.mjs +0 -24297
- package/dist/index.mjs.map +0 -1
- package/dist/sql/schema_dump.d.ts +0 -132
- package/dist/sql/schema_dump.d.ts.map +0 -1
- package/dist/sql/trace.d.ts +0 -1
- package/dist/sql/trace.d.ts.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -41,13 +41,17 @@ __export(index_exports, {
|
|
|
41
41
|
ExportedStatsV1: () => ExportedStatsV1,
|
|
42
42
|
IndexOptimizer: () => IndexOptimizer,
|
|
43
43
|
PROCEED: () => PROCEED,
|
|
44
|
+
PgIdentifier: () => PgIdentifier,
|
|
44
45
|
PostgresQueryBuilder: () => PostgresQueryBuilder,
|
|
45
46
|
PostgresVersion: () => PostgresVersion,
|
|
46
47
|
SKIP: () => SKIP,
|
|
47
48
|
Statistics: () => Statistics,
|
|
48
49
|
StatisticsMode: () => StatisticsMode,
|
|
49
50
|
StatisticsSource: () => StatisticsSource,
|
|
51
|
+
dropIndex: () => dropIndex,
|
|
50
52
|
ignoredIdentifier: () => ignoredIdentifier,
|
|
53
|
+
isIndexProbablyDroppable: () => isIndexProbablyDroppable,
|
|
54
|
+
isIndexSupported: () => isIndexSupported,
|
|
51
55
|
parseNudges: () => parseNudges,
|
|
52
56
|
permuteWithFeedback: () => permuteWithFeedback
|
|
53
57
|
});
|
|
@@ -749,9 +753,26 @@ var Analyzer = class {
|
|
|
749
753
|
// src/sql/database.ts
|
|
750
754
|
var import_zod = require("zod");
|
|
751
755
|
var PostgresVersion = import_zod.z.string().brand("PostgresVersion");
|
|
756
|
+
async function dropIndex(tx, index) {
|
|
757
|
+
try {
|
|
758
|
+
await tx.exec(`
|
|
759
|
+
savepoint idx_drop;
|
|
760
|
+
drop index if exists ${index} cascade;
|
|
761
|
+
`);
|
|
762
|
+
return true;
|
|
763
|
+
} catch (error) {
|
|
764
|
+
await tx.exec(`rollback to idx_drop`);
|
|
765
|
+
return false;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
752
768
|
|
|
753
|
-
// src/
|
|
754
|
-
|
|
769
|
+
// src/sql/indexes.ts
|
|
770
|
+
function isIndexSupported(index) {
|
|
771
|
+
return index.index_type === "btree";
|
|
772
|
+
}
|
|
773
|
+
function isIndexProbablyDroppable(index) {
|
|
774
|
+
return !index.is_primary && !index.is_unique;
|
|
775
|
+
}
|
|
755
776
|
|
|
756
777
|
// src/sql/builder.ts
|
|
757
778
|
var PostgresQueryBuilder = class _PostgresQueryBuilder {
|
|
@@ -833,7 +854,141 @@ var PostgresQueryBuilder = class _PostgresQueryBuilder {
|
|
|
833
854
|
}
|
|
834
855
|
};
|
|
835
856
|
|
|
857
|
+
// src/sql/pg-identifier.ts
|
|
858
|
+
var _PgIdentifier = class _PgIdentifier {
|
|
859
|
+
constructor(value, quoted) {
|
|
860
|
+
this.value = value;
|
|
861
|
+
this.quoted = quoted;
|
|
862
|
+
}
|
|
863
|
+
static fromString(identifier) {
|
|
864
|
+
const identifierRegex = /^[a-z_][a-zA-Z0-9_]*$/;
|
|
865
|
+
const match = identifier.match(/^"(.+)"$/);
|
|
866
|
+
if (match) {
|
|
867
|
+
return new _PgIdentifier(match[1], true);
|
|
868
|
+
}
|
|
869
|
+
const quoted = !identifierRegex.test(identifier) || this.reservedKeywords.has(identifier.toLowerCase());
|
|
870
|
+
return new _PgIdentifier(identifier, quoted);
|
|
871
|
+
}
|
|
872
|
+
toString() {
|
|
873
|
+
if (this.quoted) {
|
|
874
|
+
return `"${this.value.replace(/"/g, '""')}"`;
|
|
875
|
+
}
|
|
876
|
+
return this.value;
|
|
877
|
+
}
|
|
878
|
+
};
|
|
879
|
+
__publicField(_PgIdentifier, "reservedKeywords", /* @__PURE__ */ new Set([
|
|
880
|
+
"abort",
|
|
881
|
+
"analyze",
|
|
882
|
+
"binary",
|
|
883
|
+
"cluster",
|
|
884
|
+
"constraint",
|
|
885
|
+
"copy",
|
|
886
|
+
"do",
|
|
887
|
+
"explain",
|
|
888
|
+
"extend",
|
|
889
|
+
"listen",
|
|
890
|
+
"load",
|
|
891
|
+
"lock",
|
|
892
|
+
"move",
|
|
893
|
+
"new",
|
|
894
|
+
"none",
|
|
895
|
+
"notify",
|
|
896
|
+
"offset",
|
|
897
|
+
"reset",
|
|
898
|
+
"setof",
|
|
899
|
+
"show",
|
|
900
|
+
"unlisten",
|
|
901
|
+
"until",
|
|
902
|
+
"vacuum",
|
|
903
|
+
"verbose",
|
|
904
|
+
"all",
|
|
905
|
+
"any",
|
|
906
|
+
"asc",
|
|
907
|
+
"between",
|
|
908
|
+
"bit",
|
|
909
|
+
"both",
|
|
910
|
+
"case",
|
|
911
|
+
"cast",
|
|
912
|
+
"char",
|
|
913
|
+
"character",
|
|
914
|
+
"check",
|
|
915
|
+
"coalesce",
|
|
916
|
+
"collate",
|
|
917
|
+
"column",
|
|
918
|
+
"constraint",
|
|
919
|
+
"cross",
|
|
920
|
+
"current",
|
|
921
|
+
"current_date",
|
|
922
|
+
"current_time",
|
|
923
|
+
"current_timestamp",
|
|
924
|
+
"current_user",
|
|
925
|
+
"dec",
|
|
926
|
+
"decimal",
|
|
927
|
+
"default",
|
|
928
|
+
"desc",
|
|
929
|
+
"distinct",
|
|
930
|
+
"else",
|
|
931
|
+
"end",
|
|
932
|
+
"except",
|
|
933
|
+
"exists",
|
|
934
|
+
"extract",
|
|
935
|
+
"false",
|
|
936
|
+
"float",
|
|
937
|
+
"for",
|
|
938
|
+
"foreign",
|
|
939
|
+
"from",
|
|
940
|
+
"full",
|
|
941
|
+
"global",
|
|
942
|
+
"group",
|
|
943
|
+
"having",
|
|
944
|
+
"in",
|
|
945
|
+
"inner",
|
|
946
|
+
"intersect",
|
|
947
|
+
"into",
|
|
948
|
+
"is",
|
|
949
|
+
"join",
|
|
950
|
+
"leading",
|
|
951
|
+
"left",
|
|
952
|
+
"like",
|
|
953
|
+
"local",
|
|
954
|
+
"natural",
|
|
955
|
+
"nchar",
|
|
956
|
+
"not",
|
|
957
|
+
"null",
|
|
958
|
+
"nullif",
|
|
959
|
+
"numeric",
|
|
960
|
+
"on",
|
|
961
|
+
"or",
|
|
962
|
+
"order",
|
|
963
|
+
"outer",
|
|
964
|
+
"overlaps",
|
|
965
|
+
"position",
|
|
966
|
+
"precision",
|
|
967
|
+
"primary",
|
|
968
|
+
"public",
|
|
969
|
+
"references",
|
|
970
|
+
"right",
|
|
971
|
+
"select",
|
|
972
|
+
"session_user",
|
|
973
|
+
"some",
|
|
974
|
+
"substring",
|
|
975
|
+
"table",
|
|
976
|
+
"then",
|
|
977
|
+
"to",
|
|
978
|
+
"transaction",
|
|
979
|
+
"trim",
|
|
980
|
+
"true",
|
|
981
|
+
"union",
|
|
982
|
+
"unique",
|
|
983
|
+
"user",
|
|
984
|
+
"varchar",
|
|
985
|
+
"when",
|
|
986
|
+
"where"
|
|
987
|
+
]));
|
|
988
|
+
var PgIdentifier = _PgIdentifier;
|
|
989
|
+
|
|
836
990
|
// src/optimizer/genalgo.ts
|
|
991
|
+
var import_colorette2 = require("colorette");
|
|
837
992
|
var _IndexOptimizer = class _IndexOptimizer {
|
|
838
993
|
constructor(db, statistics, existingIndexes, config = {}) {
|
|
839
994
|
this.db = db;
|
|
@@ -841,8 +996,12 @@ var _IndexOptimizer = class _IndexOptimizer {
|
|
|
841
996
|
this.existingIndexes = existingIndexes;
|
|
842
997
|
this.config = config;
|
|
843
998
|
}
|
|
844
|
-
async run(builder, indexes) {
|
|
845
|
-
const baseExplain = await this.
|
|
999
|
+
async run(builder, indexes, beforeQuery) {
|
|
1000
|
+
const baseExplain = await this.testQueryWithStats(builder, async (tx) => {
|
|
1001
|
+
if (beforeQuery) {
|
|
1002
|
+
await beforeQuery(tx);
|
|
1003
|
+
}
|
|
1004
|
+
});
|
|
846
1005
|
const baseCost = Number(baseExplain.Plan["Total Cost"]);
|
|
847
1006
|
if (baseCost === 0) {
|
|
848
1007
|
return {
|
|
@@ -850,76 +1009,17 @@ var _IndexOptimizer = class _IndexOptimizer {
|
|
|
850
1009
|
explainPlan: baseExplain
|
|
851
1010
|
};
|
|
852
1011
|
}
|
|
853
|
-
|
|
854
|
-
const
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
for (const { table, schema, columns } of permutedIndexes.values()) {
|
|
858
|
-
const permutations = permuteWithFeedback(columns);
|
|
859
|
-
let iter = permutations.next(PROCEED);
|
|
860
|
-
const previousCost = baseCost;
|
|
861
|
-
while (!iter.done) {
|
|
862
|
-
const columns2 = iter.value;
|
|
863
|
-
const existingIndex = this.indexAlreadyExists(table, columns2);
|
|
864
|
-
if (existingIndex) {
|
|
865
|
-
console.log(` <${(0, import_colorette2.gray)("skip")}> ${(0, import_colorette2.gray)(existingIndex.index_name)}`);
|
|
866
|
-
iter = permutations.next(PROCEED);
|
|
867
|
-
continue;
|
|
868
|
-
}
|
|
869
|
-
let indexDefinition = "?";
|
|
870
|
-
const indexName = this.indexName();
|
|
871
|
-
const { raw, colored } = this.toDefinition({
|
|
872
|
-
columns: columns2,
|
|
873
|
-
schema,
|
|
874
|
-
table
|
|
875
|
-
});
|
|
876
|
-
const shortenedSchema = schema === "public" ? "" : `"${schema}".`;
|
|
877
|
-
const indexDefinitionClean = `${shortenedSchema}"${table}"(${columns2.map((c) => `"${c.column}"`).join(", ")})`;
|
|
878
|
-
indexDefinition = colored;
|
|
879
|
-
const query = PostgresQueryBuilder.createIndex(
|
|
880
|
-
raw,
|
|
881
|
-
indexName
|
|
882
|
-
).introspect();
|
|
883
|
-
triedIndexes.set(indexName, {
|
|
884
|
-
schema,
|
|
885
|
-
table,
|
|
886
|
-
columns: columns2,
|
|
887
|
-
definition: indexDefinitionClean
|
|
888
|
-
});
|
|
889
|
-
const explain = await this.testQueryWithStats(builder, async (sql) => {
|
|
890
|
-
await sql.exec(query.build());
|
|
891
|
-
});
|
|
892
|
-
const explainCost = Number(explain.Plan["Total Cost"]);
|
|
893
|
-
const costDeltaPercentage = (previousCost - explainCost) / previousCost * 100;
|
|
894
|
-
if (previousCost > explainCost) {
|
|
895
|
-
console.log(
|
|
896
|
-
`${(0, import_colorette2.green)(
|
|
897
|
-
`+${costDeltaPercentage.toFixed(2).padStart(5, "0")}%`
|
|
898
|
-
)} ${indexDefinition} `
|
|
899
|
-
);
|
|
900
|
-
iter = permutations.next(PROCEED);
|
|
901
|
-
} else {
|
|
902
|
-
console.log(
|
|
903
|
-
`${previousCost === explainCost ? ` ${(0, import_colorette2.gray)("00.00%")}` : `${(0, import_colorette2.red)(
|
|
904
|
-
`-${Math.abs(costDeltaPercentage).toFixed(2).padStart(5, "0")}%`
|
|
905
|
-
)}`} ${indexDefinition}`
|
|
906
|
-
);
|
|
907
|
-
iter = permutations.next(PROCEED);
|
|
908
|
-
}
|
|
909
|
-
nextStage.push({
|
|
910
|
-
name: indexName,
|
|
911
|
-
schema,
|
|
912
|
-
table,
|
|
913
|
-
columns: columns2
|
|
914
|
-
});
|
|
1012
|
+
const toCreate = this.indexesToCreate(indexes);
|
|
1013
|
+
const finalExplain = await this.testQueryWithStats(builder, async (tx) => {
|
|
1014
|
+
if (beforeQuery) {
|
|
1015
|
+
await beforeQuery(tx);
|
|
915
1016
|
}
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
);
|
|
1017
|
+
for (const permutation of toCreate) {
|
|
1018
|
+
const createIndex = PostgresQueryBuilder.createIndex(
|
|
1019
|
+
this.toDefinition(permutation).raw,
|
|
1020
|
+
permutation.name
|
|
1021
|
+
).introspect().build();
|
|
1022
|
+
await tx.exec(createIndex);
|
|
923
1023
|
}
|
|
924
1024
|
});
|
|
925
1025
|
const finalCost = Number(finalExplain.Plan["Total Cost"]);
|
|
@@ -938,14 +1038,15 @@ var _IndexOptimizer = class _IndexOptimizer {
|
|
|
938
1038
|
)} ${(0, import_colorette2.gray)("If there's a better index, we haven't tried it")}`
|
|
939
1039
|
);
|
|
940
1040
|
}
|
|
941
|
-
const
|
|
1041
|
+
const baseIndexes = this.findUsedIndexes(baseExplain.Plan);
|
|
1042
|
+
const finalIndexes = this.findUsedIndexes(finalExplain.Plan);
|
|
942
1043
|
return {
|
|
943
1044
|
kind: "ok",
|
|
944
1045
|
baseCost,
|
|
945
1046
|
finalCost,
|
|
946
|
-
newIndexes,
|
|
947
|
-
existingIndexes:
|
|
948
|
-
triedIndexes,
|
|
1047
|
+
newIndexes: finalIndexes.newIndexes,
|
|
1048
|
+
existingIndexes: baseIndexes.existingIndexes,
|
|
1049
|
+
triedIndexes: new Map(toCreate.map((index) => [index.name, index])),
|
|
949
1050
|
baseExplainPlan: baseExplain,
|
|
950
1051
|
explainPlan: finalExplain
|
|
951
1052
|
};
|
|
@@ -969,6 +1070,37 @@ var _IndexOptimizer = class _IndexOptimizer {
|
|
|
969
1070
|
(index) => index.index_type === "btree" && index.table_name === table && index.index_columns.length === columns.length && index.index_columns.every((c, i) => columns[i].column === c.name)
|
|
970
1071
|
);
|
|
971
1072
|
}
|
|
1073
|
+
/**
|
|
1074
|
+
* Derive the list of indexes [tableA(X, Y, Z), tableB(H, I, J)]
|
|
1075
|
+
**/
|
|
1076
|
+
indexesToCreate(rootCandidates) {
|
|
1077
|
+
const permutedIndexes = this.tableColumnIndexCandidates(rootCandidates);
|
|
1078
|
+
const nextStage = [];
|
|
1079
|
+
for (const { table, schema, columns } of permutedIndexes.values()) {
|
|
1080
|
+
const permutations = permuteWithFeedback(columns);
|
|
1081
|
+
let iter = permutations.next(PROCEED);
|
|
1082
|
+
while (!iter.done) {
|
|
1083
|
+
const columns2 = iter.value;
|
|
1084
|
+
const existingIndex = this.indexAlreadyExists(table, columns2);
|
|
1085
|
+
if (existingIndex) {
|
|
1086
|
+
iter = permutations.next(PROCEED);
|
|
1087
|
+
continue;
|
|
1088
|
+
}
|
|
1089
|
+
const indexName = this.indexName();
|
|
1090
|
+
const shortenedSchema = schema === "public" ? "" : `"${schema}".`;
|
|
1091
|
+
const indexDefinitionClean = `${shortenedSchema}"${table}"(${columns2.map((c) => `"${c.column}"`).join(", ")})`;
|
|
1092
|
+
iter = permutations.next(PROCEED);
|
|
1093
|
+
nextStage.push({
|
|
1094
|
+
name: indexName,
|
|
1095
|
+
schema,
|
|
1096
|
+
table,
|
|
1097
|
+
columns: columns2,
|
|
1098
|
+
definition: indexDefinitionClean
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
return nextStage;
|
|
1103
|
+
}
|
|
972
1104
|
toDefinition(permuted) {
|
|
973
1105
|
const make = (col, order, where, keyword) => {
|
|
974
1106
|
const baseColumn = `"${permuted.schema}"."${permuted.table}"(${permuted.columns.map((c) => {
|
|
@@ -991,16 +1123,15 @@ var _IndexOptimizer = class _IndexOptimizer {
|
|
|
991
1123
|
return { raw, colored };
|
|
992
1124
|
}
|
|
993
1125
|
/**
|
|
994
|
-
* Drop indexes that can be dropped
|
|
1126
|
+
* Drop indexes that can be dropped. Ignore the ones that can't
|
|
995
1127
|
*/
|
|
996
1128
|
async dropExistingIndexes(tx) {
|
|
997
1129
|
for (const index of this.existingIndexes) {
|
|
998
|
-
if (index
|
|
1130
|
+
if (!isIndexProbablyDroppable(index)) {
|
|
999
1131
|
continue;
|
|
1000
1132
|
}
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
);
|
|
1133
|
+
const indexName = `${index.schema_name}.${index.index_name}`;
|
|
1134
|
+
await dropIndex(tx, indexName);
|
|
1004
1135
|
}
|
|
1005
1136
|
}
|
|
1006
1137
|
whereClause(c, col, keyword) {
|
|
@@ -1189,13 +1320,7 @@ var ExportedStatsStatistics = import_zod2.z.object({
|
|
|
1189
1320
|
});
|
|
1190
1321
|
var ExportedStatsColumns = import_zod2.z.object({
|
|
1191
1322
|
columnName: import_zod2.z.string(),
|
|
1192
|
-
stats: ExportedStatsStatistics.nullable()
|
|
1193
|
-
dataType: import_zod2.z.string(),
|
|
1194
|
-
isNullable: import_zod2.z.boolean(),
|
|
1195
|
-
numericScale: import_zod2.z.number().nullable(),
|
|
1196
|
-
columnDefault: import_zod2.z.string().nullable(),
|
|
1197
|
-
numericPrecision: import_zod2.z.number().nullable(),
|
|
1198
|
-
characterMaximumLength: import_zod2.z.number().nullable()
|
|
1323
|
+
stats: ExportedStatsStatistics.nullable()
|
|
1199
1324
|
});
|
|
1200
1325
|
var ExportedStatsIndex = import_zod2.z.object({
|
|
1201
1326
|
indexName: import_zod2.z.string(),
|
|
@@ -1663,12 +1788,6 @@ var _Statistics = class _Statistics {
|
|
|
1663
1788
|
json_agg(
|
|
1664
1789
|
json_build_object(
|
|
1665
1790
|
'columnName', c.column_name,
|
|
1666
|
-
'dataType', c.data_type,
|
|
1667
|
-
'isNullable', (c.is_nullable = 'YES')::boolean,
|
|
1668
|
-
'characterMaximumLength', c.character_maximum_length,
|
|
1669
|
-
'numericPrecision', c.numeric_precision,
|
|
1670
|
-
'numericScale', c.numeric_scale,
|
|
1671
|
-
'columnDefault', c.column_default,
|
|
1672
1791
|
'stats', (
|
|
1673
1792
|
SELECT json_build_object(
|
|
1674
1793
|
'starelid', s.starelid,
|
|
@@ -1764,6 +1883,7 @@ var _Statistics = class _Statistics {
|
|
|
1764
1883
|
COALESCE(pt.parent_table::text, t.relname) AS table_name,
|
|
1765
1884
|
i.relname AS index_name,
|
|
1766
1885
|
ix.indisprimary as is_primary,
|
|
1886
|
+
ix.indisunique as is_unique,
|
|
1767
1887
|
am.amname AS index_type,
|
|
1768
1888
|
array_agg(
|
|
1769
1889
|
CASE
|
|
@@ -1794,9 +1914,10 @@ var _Statistics = class _Statistics {
|
|
|
1794
1914
|
LEFT JOIN pg_attribute a ON a.attnum = k.attnum AND a.attrelid = t.oid
|
|
1795
1915
|
JOIN pg_namespace n ON t.relnamespace = n.oid
|
|
1796
1916
|
WHERE
|
|
1797
|
-
n.nspname
|
|
1917
|
+
n.nspname not like 'pg_%' and
|
|
1918
|
+
n.nspname <> 'information_schema'
|
|
1798
1919
|
GROUP BY
|
|
1799
|
-
n.nspname, COALESCE(pt.parent_table::text, t.relname), i.relname, am.amname, ix.indisprimary
|
|
1920
|
+
n.nspname, COALESCE(pt.parent_table::text, t.relname), i.relname, am.amname, ix.indisprimary, ix.indisunique
|
|
1800
1921
|
ORDER BY
|
|
1801
1922
|
COALESCE(pt.parent_table::text, t.relname), i.relname; -- @qd_introspection
|
|
1802
1923
|
`);
|
|
@@ -1820,13 +1941,17 @@ var Statistics = _Statistics;
|
|
|
1820
1941
|
ExportedStatsV1,
|
|
1821
1942
|
IndexOptimizer,
|
|
1822
1943
|
PROCEED,
|
|
1944
|
+
PgIdentifier,
|
|
1823
1945
|
PostgresQueryBuilder,
|
|
1824
1946
|
PostgresVersion,
|
|
1825
1947
|
SKIP,
|
|
1826
1948
|
Statistics,
|
|
1827
1949
|
StatisticsMode,
|
|
1828
1950
|
StatisticsSource,
|
|
1951
|
+
dropIndex,
|
|
1829
1952
|
ignoredIdentifier,
|
|
1953
|
+
isIndexProbablyDroppable,
|
|
1954
|
+
isIndexSupported,
|
|
1830
1955
|
parseNudges,
|
|
1831
1956
|
permuteWithFeedback
|
|
1832
1957
|
});
|