@crvouga/mockingbird-service-postgres 1.5.1 → 1.7.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/AGENTS.md +5 -6
- package/CHANGELOG.md +27 -0
- package/COMPATIBILITY.md +14 -5
- package/README.md +30 -13
- package/dist/admin.js +191 -54
- package/dist/admin.js.map +4 -4
- package/dist/ast/nodes.d.ts +1 -0
- package/dist/index.js +118 -32
- package/dist/index.js.map +3 -3
- package/dist/runtime/database-context.d.ts +4 -0
- package/dist/server.d.ts +9 -0
- package/dist/server.js +25808 -0
- package/dist/server.js.map +7 -0
- package/dist/sql/deparse.d.ts +1 -0
- package/dist/unstable.js +96 -31
- package/dist/unstable.js.map +3 -3
- package/dist/wire/cli.js +1766 -173
- package/dist/wire/cli.js.map +4 -4
- package/dist/wire/cluster.d.ts +23 -8
- package/dist/wire/connection.d.ts +25 -1
- package/dist/wire/fleet.d.ts +80 -0
- package/dist/wire/index.d.ts +11 -1
- package/dist/wire/index.js +608 -78
- package/dist/wire/index.js.map +3 -3
- package/dist/wire/probe.d.ts +2 -0
- package/dist/wire/protocol.d.ts +4 -0
- package/package.json +13 -2
package/dist/ast/nodes.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -3460,7 +3460,13 @@ var DatabaseState = class _DatabaseState {
|
|
|
3460
3460
|
this.settings.set("lc_numeric", "C");
|
|
3461
3461
|
this.settings.set("lc_time", "C");
|
|
3462
3462
|
this.settings.set("default_transaction_isolation", "read committed");
|
|
3463
|
+
this.settings.set("lock_timeout", "0");
|
|
3464
|
+
this.settings.set("idle_in_transaction_session_timeout", "0");
|
|
3465
|
+
this.settings.set("transaction_timeout", "0");
|
|
3463
3466
|
this.settings.set("statement_timeout", "0");
|
|
3467
|
+
this.settings.set("check_function_bodies", "on");
|
|
3468
|
+
this.settings.set("xmloption", "content");
|
|
3469
|
+
this.settings.set("row_security", "on");
|
|
3464
3470
|
this.settings.set("array_nulls", "on");
|
|
3465
3471
|
this.settings.set("backslash_quote", "safe_encoding");
|
|
3466
3472
|
}
|
|
@@ -7062,6 +7068,19 @@ function exactDegTan(x) {
|
|
|
7062
7068
|
return Math.tan(x * Math.PI / 180);
|
|
7063
7069
|
}
|
|
7064
7070
|
|
|
7071
|
+
// src/sql/deparse.ts
|
|
7072
|
+
function quoteIdent(name) {
|
|
7073
|
+
if (/^[a-z_][a-z0-9_$]*$/.test(name)) return name;
|
|
7074
|
+
return `"${name.replaceAll('"', '""')}"`;
|
|
7075
|
+
}
|
|
7076
|
+
|
|
7077
|
+
// src/runtime/database-context.ts
|
|
7078
|
+
var contexts = /* @__PURE__ */ new WeakMap();
|
|
7079
|
+
var fallback = { name: "postgres", names: () => ["postgres"] };
|
|
7080
|
+
function databaseCatalogContext(state) {
|
|
7081
|
+
return contexts.get(state) ?? fallback;
|
|
7082
|
+
}
|
|
7083
|
+
|
|
7065
7084
|
// src/functions/misc-fns.ts
|
|
7066
7085
|
var PG_VERSION_TEXT = "PostgreSQL 18.3 (postgres-mem) on TypeScript, in-memory engine";
|
|
7067
7086
|
function findSequenceForCall(ctx, name) {
|
|
@@ -7145,8 +7164,8 @@ function sequenceNextval(ctx, seq) {
|
|
|
7145
7164
|
function getMiscFunctions() {
|
|
7146
7165
|
const m = /* @__PURE__ */ new Map();
|
|
7147
7166
|
m.set("version", () => tv("text", PG_VERSION_TEXT));
|
|
7148
|
-
m.set("current_database", () => tv("name",
|
|
7149
|
-
m.set("current_catalog", () => tv("name",
|
|
7167
|
+
m.set("current_database", (ctx) => tv("name", databaseCatalogContext(ctx.state).name));
|
|
7168
|
+
m.set("current_catalog", (ctx) => tv("name", databaseCatalogContext(ctx.state).name));
|
|
7150
7169
|
m.set("current_schema", (ctx) => {
|
|
7151
7170
|
const path = ctx.state.effectiveSearchPath();
|
|
7152
7171
|
const first = path.find((s) => ctx.state.schemas.has(s));
|
|
@@ -7268,7 +7287,7 @@ function getMiscFunctions() {
|
|
|
7268
7287
|
if (!col.identity) return tv("text", null);
|
|
7269
7288
|
return tv(
|
|
7270
7289
|
"text",
|
|
7271
|
-
col.identity.sequence.split(".").map(
|
|
7290
|
+
col.identity.sequence.split(".").map(quoteIdent).join(".")
|
|
7272
7291
|
);
|
|
7273
7292
|
})
|
|
7274
7293
|
);
|
|
@@ -14518,14 +14537,19 @@ var Parser = class {
|
|
|
14518
14537
|
parseIdentityOptions() {
|
|
14519
14538
|
const options = {};
|
|
14520
14539
|
if (this.eatPunct("(")) {
|
|
14521
|
-
Object.assign(options, this.parseSequenceOptions());
|
|
14540
|
+
Object.assign(options, this.parseSequenceOptions(true));
|
|
14522
14541
|
this.expectPunct(")");
|
|
14523
14542
|
}
|
|
14524
14543
|
return options;
|
|
14525
14544
|
}
|
|
14526
|
-
parseSequenceOptions() {
|
|
14545
|
+
parseSequenceOptions(identity = false) {
|
|
14527
14546
|
const options = {};
|
|
14528
14547
|
for (; ; ) {
|
|
14548
|
+
if (identity && this.eatKw("sequence")) {
|
|
14549
|
+
this.expectKw("name");
|
|
14550
|
+
options.sequenceName = this.qualifiedName();
|
|
14551
|
+
continue;
|
|
14552
|
+
}
|
|
14529
14553
|
if (this.eatKw("increment")) {
|
|
14530
14554
|
this.eatKw("by");
|
|
14531
14555
|
options.increment = this.parseSignedBigInt();
|
|
@@ -20527,6 +20551,27 @@ function parseCsvLine(line, delim, quote) {
|
|
|
20527
20551
|
}
|
|
20528
20552
|
return fields;
|
|
20529
20553
|
}
|
|
20554
|
+
function splitCsvRecords(data, quote) {
|
|
20555
|
+
const records = [];
|
|
20556
|
+
let start = 0;
|
|
20557
|
+
let quoted = false;
|
|
20558
|
+
for (let i = 0; i < data.length; i++) {
|
|
20559
|
+
const char = data[i];
|
|
20560
|
+
if (char === quote) {
|
|
20561
|
+
if (quoted && data[i + 1] === quote) i++;
|
|
20562
|
+
else quoted = !quoted;
|
|
20563
|
+
continue;
|
|
20564
|
+
}
|
|
20565
|
+
if (char === "\n" && !quoted) {
|
|
20566
|
+
const end = i > start && data[i - 1] === "\r" ? i - 1 : i;
|
|
20567
|
+
records.push(data.slice(start, end));
|
|
20568
|
+
start = i + 1;
|
|
20569
|
+
}
|
|
20570
|
+
}
|
|
20571
|
+
if (quoted) throw pgError("invalid_text_representation", "unterminated CSV quoted field", "22P04");
|
|
20572
|
+
if (start < data.length) records.push(data.slice(start));
|
|
20573
|
+
return records;
|
|
20574
|
+
}
|
|
20530
20575
|
function executeCopyFromData(env, stmt, data) {
|
|
20531
20576
|
const format = String(stmt.options.format ?? "text").toLowerCase();
|
|
20532
20577
|
if (format !== "text" && format !== "csv") throw unsupported(`COPY format ${format}`);
|
|
@@ -20537,7 +20582,7 @@ function executeCopyFromData(env, stmt, data) {
|
|
|
20537
20582
|
const nullStr = String(stmt.options.null ?? (format === "csv" ? "" : "\\N"));
|
|
20538
20583
|
const quote = String(stmt.options.quote ?? '"');
|
|
20539
20584
|
const header = stmt.options.header === true || String(stmt.options.header ?? "").toLowerCase() === "true";
|
|
20540
|
-
let lines = data.split(/\r?\n/);
|
|
20585
|
+
let lines = format === "csv" ? splitCsvRecords(data, quote) : data.split(/\r?\n/);
|
|
20541
20586
|
const endMarker = lines.indexOf("\\.");
|
|
20542
20587
|
if (endMarker !== -1) lines = lines.slice(0, endMarker);
|
|
20543
20588
|
if (lines.length > 0 && lines[lines.length - 1] === "") lines = lines.slice(0, -1);
|
|
@@ -21271,7 +21316,8 @@ function pgSettings(ctx) {
|
|
|
21271
21316
|
"pg_settings"
|
|
21272
21317
|
);
|
|
21273
21318
|
}
|
|
21274
|
-
function pgDatabase() {
|
|
21319
|
+
function pgDatabase(ctx) {
|
|
21320
|
+
const names = databaseCatalogContext(ctx.state).names();
|
|
21275
21321
|
return rel(
|
|
21276
21322
|
[
|
|
21277
21323
|
["oid", "oid"],
|
|
@@ -21280,7 +21326,7 @@ function pgDatabase() {
|
|
|
21280
21326
|
["datistemplate", "bool"],
|
|
21281
21327
|
["datallowconn", "bool"]
|
|
21282
21328
|
],
|
|
21283
|
-
[
|
|
21329
|
+
names.map((name, index) => [5 + index, name, 6, false, true]),
|
|
21284
21330
|
"pg_database"
|
|
21285
21331
|
);
|
|
21286
21332
|
}
|
|
@@ -21315,13 +21361,14 @@ function pgTrigger(ctx) {
|
|
|
21315
21361
|
"pg_trigger"
|
|
21316
21362
|
);
|
|
21317
21363
|
}
|
|
21318
|
-
var
|
|
21364
|
+
var catalogName = (state) => databaseCatalogContext(state).name;
|
|
21319
21365
|
function infoSchemata(state) {
|
|
21366
|
+
const catalog = catalogName(state);
|
|
21320
21367
|
const rows = [
|
|
21321
|
-
[
|
|
21322
|
-
[
|
|
21368
|
+
[catalog, "pg_catalog", OWNER],
|
|
21369
|
+
[catalog, "information_schema", OWNER]
|
|
21323
21370
|
];
|
|
21324
|
-
for (const s of state.schemas.values()) rows.push([
|
|
21371
|
+
for (const s of state.schemas.values()) rows.push([catalog, s.name, OWNER]);
|
|
21325
21372
|
return rel(
|
|
21326
21373
|
[
|
|
21327
21374
|
["catalog_name", "name"],
|
|
@@ -21333,13 +21380,14 @@ function infoSchemata(state) {
|
|
|
21333
21380
|
);
|
|
21334
21381
|
}
|
|
21335
21382
|
function infoTables(ctx) {
|
|
21383
|
+
const catalog = catalogName(ctx.state);
|
|
21336
21384
|
const rows = [];
|
|
21337
21385
|
for (const schema of ctx.state.schemas.values()) {
|
|
21338
21386
|
for (const t of schema.tables.values()) {
|
|
21339
|
-
rows.push([
|
|
21387
|
+
rows.push([catalog, t.schema, t.name, t.temp ? "LOCAL TEMPORARY" : "BASE TABLE", "YES"]);
|
|
21340
21388
|
}
|
|
21341
21389
|
for (const v of schema.views.values()) {
|
|
21342
|
-
if (!v.materialized) rows.push([
|
|
21390
|
+
if (!v.materialized) rows.push([catalog, v.schema, v.name, "VIEW", "NO"]);
|
|
21343
21391
|
}
|
|
21344
21392
|
}
|
|
21345
21393
|
return rel(
|
|
@@ -21355,6 +21403,7 @@ function infoTables(ctx) {
|
|
|
21355
21403
|
);
|
|
21356
21404
|
}
|
|
21357
21405
|
function infoColumns(ctx) {
|
|
21406
|
+
const catalog = catalogName(ctx.state);
|
|
21358
21407
|
const rows = [];
|
|
21359
21408
|
for (const t of allTables(ctx.state)) {
|
|
21360
21409
|
t.columns.forEach((c, i) => {
|
|
@@ -21365,7 +21414,7 @@ function infoColumns(ctx) {
|
|
|
21365
21414
|
const dataType = isArrayType(id) ? "ARRAY" : isEnumType(id) ? "USER-DEFINED" : typeDisplayName(id);
|
|
21366
21415
|
const udt = isArrayType(id) ? `_${arrayUdt(id)}` : isEnumType(id) ? id.slice(5).split(".").pop() : id;
|
|
21367
21416
|
rows.push([
|
|
21368
|
-
|
|
21417
|
+
catalog,
|
|
21369
21418
|
t.schema,
|
|
21370
21419
|
t.name,
|
|
21371
21420
|
c.name,
|
|
@@ -21410,10 +21459,11 @@ function arrayUdt(t) {
|
|
|
21410
21459
|
return isEnumType(elem) ? elem.slice(5).split(".").pop() : elem;
|
|
21411
21460
|
}
|
|
21412
21461
|
function infoViews(ctx) {
|
|
21462
|
+
const catalog = catalogName(ctx.state);
|
|
21413
21463
|
const rows = [];
|
|
21414
21464
|
for (const schema of ctx.state.schemas.values()) {
|
|
21415
21465
|
for (const v of schema.views.values()) {
|
|
21416
|
-
if (!v.materialized) rows.push([
|
|
21466
|
+
if (!v.materialized) rows.push([catalog, v.schema, v.name, null]);
|
|
21417
21467
|
}
|
|
21418
21468
|
}
|
|
21419
21469
|
return rel(
|
|
@@ -21428,10 +21478,11 @@ function infoViews(ctx) {
|
|
|
21428
21478
|
);
|
|
21429
21479
|
}
|
|
21430
21480
|
function infoSequences(ctx) {
|
|
21481
|
+
const catalog = catalogName(ctx.state);
|
|
21431
21482
|
const rows = [];
|
|
21432
21483
|
for (const s of allSequences(ctx.state)) {
|
|
21433
21484
|
rows.push([
|
|
21434
|
-
|
|
21485
|
+
catalog,
|
|
21435
21486
|
s.schema,
|
|
21436
21487
|
s.name,
|
|
21437
21488
|
typeDisplayName(s.dataType),
|
|
@@ -21459,11 +21510,12 @@ function infoSequences(ctx) {
|
|
|
21459
21510
|
);
|
|
21460
21511
|
}
|
|
21461
21512
|
function infoTableConstraints(ctx) {
|
|
21513
|
+
const catalog = catalogName(ctx.state);
|
|
21462
21514
|
const rows = [];
|
|
21463
21515
|
for (const t of allTables(ctx.state)) {
|
|
21464
21516
|
for (const c of t.constraints) {
|
|
21465
21517
|
const type = c.kind === "primary_key" ? "PRIMARY KEY" : c.kind === "unique" ? "UNIQUE" : c.kind === "check" ? "CHECK" : "FOREIGN KEY";
|
|
21466
|
-
rows.push([
|
|
21518
|
+
rows.push([catalog, t.schema, c.name, catalog, t.schema, t.name, type]);
|
|
21467
21519
|
}
|
|
21468
21520
|
}
|
|
21469
21521
|
return rel(
|
|
@@ -21481,12 +21533,13 @@ function infoTableConstraints(ctx) {
|
|
|
21481
21533
|
);
|
|
21482
21534
|
}
|
|
21483
21535
|
function infoKeyColumnUsage(ctx) {
|
|
21536
|
+
const catalog = catalogName(ctx.state);
|
|
21484
21537
|
const rows = [];
|
|
21485
21538
|
for (const t of allTables(ctx.state)) {
|
|
21486
21539
|
for (const c of t.constraints) {
|
|
21487
21540
|
if (c.kind !== "primary_key" && c.kind !== "unique" && c.kind !== "foreign_key") continue;
|
|
21488
21541
|
c.columns.forEach((col, i) => {
|
|
21489
|
-
rows.push([
|
|
21542
|
+
rows.push([catalog, t.schema, c.name, catalog, t.schema, t.name, col, i + 1]);
|
|
21490
21543
|
});
|
|
21491
21544
|
}
|
|
21492
21545
|
}
|
|
@@ -21506,12 +21559,13 @@ function infoKeyColumnUsage(ctx) {
|
|
|
21506
21559
|
);
|
|
21507
21560
|
}
|
|
21508
21561
|
function infoRoutines(ctx) {
|
|
21562
|
+
const catalog = catalogName(ctx.state);
|
|
21509
21563
|
const rows = [];
|
|
21510
21564
|
for (const schema of ctx.state.schemas.values()) {
|
|
21511
21565
|
for (const fns of schema.functions.values()) {
|
|
21512
21566
|
for (const f of fns) {
|
|
21513
21567
|
rows.push([
|
|
21514
|
-
|
|
21568
|
+
catalog,
|
|
21515
21569
|
f.schema,
|
|
21516
21570
|
f.name,
|
|
21517
21571
|
"FUNCTION",
|
|
@@ -21568,7 +21622,7 @@ function buildCatalogRelation(ctx, schema, name) {
|
|
|
21568
21622
|
case "pg_settings":
|
|
21569
21623
|
return pgSettings(ctx);
|
|
21570
21624
|
case "pg_database":
|
|
21571
|
-
return pgDatabase();
|
|
21625
|
+
return pgDatabase(ctx);
|
|
21572
21626
|
case "pg_roles":
|
|
21573
21627
|
case "pg_user":
|
|
21574
21628
|
return pgRoles();
|
|
@@ -21749,6 +21803,11 @@ var MAX_IDENT = 63;
|
|
|
21749
21803
|
function truncIdent(s) {
|
|
21750
21804
|
return s.length > MAX_IDENT ? s.slice(0, MAX_IDENT) : s;
|
|
21751
21805
|
}
|
|
21806
|
+
function identitySequenceTarget(env, tableSchema, defaultName, options) {
|
|
21807
|
+
const parts = options.sequenceName;
|
|
21808
|
+
if (!parts || parts.length === 0) return { schema: tableSchema, name: defaultName };
|
|
21809
|
+
return targetSchema(env, parts);
|
|
21810
|
+
}
|
|
21752
21811
|
var SEQ_LIMITS = {
|
|
21753
21812
|
int2: { min: -32768n, max: 32767n },
|
|
21754
21813
|
int4: { min: -2147483648n, max: 2147483647n },
|
|
@@ -21925,8 +21984,8 @@ function buildColumn(env, schema, tableName, def, out, taken) {
|
|
|
21925
21984
|
break;
|
|
21926
21985
|
}
|
|
21927
21986
|
case "generated_identity": {
|
|
21928
|
-
const
|
|
21929
|
-
const seq = buildSequence(env, schema,
|
|
21987
|
+
const target = identitySequenceTarget(env, schema, truncIdent(`${tableName}_${def.name}_seq`), c.options);
|
|
21988
|
+
const seq = buildSequence(env, target.schema, target.name, c.options, false);
|
|
21930
21989
|
if (!c.options.as) {
|
|
21931
21990
|
seq.dataType = col.type.id === "int2" || col.type.id === "int4" || col.type.id === "int8" ? col.type.id : "int8";
|
|
21932
21991
|
const limits = SEQ_LIMITS[seq.dataType];
|
|
@@ -21935,7 +21994,7 @@ function buildColumn(env, schema, tableName, def, out, taken) {
|
|
|
21935
21994
|
}
|
|
21936
21995
|
seq.ownedBy = { table: tableName, column: def.name };
|
|
21937
21996
|
out.sequences.push(seq);
|
|
21938
|
-
col.identity = { always: c.always, sequence: `${schema.name}.${
|
|
21997
|
+
col.identity = { always: c.always, sequence: `${target.schema.name}.${target.name}` };
|
|
21939
21998
|
col.notNull = true;
|
|
21940
21999
|
break;
|
|
21941
22000
|
}
|
|
@@ -22071,10 +22130,11 @@ function executeCreateTable(env, stmt) {
|
|
|
22071
22130
|
throw pgError("invalid_table_definition", `multiple primary keys for table "${name}" are not allowed`, "42P16");
|
|
22072
22131
|
}
|
|
22073
22132
|
for (const seq of built.sequences) {
|
|
22074
|
-
|
|
22133
|
+
const seqSchema = state.getSchema(seq.schema);
|
|
22134
|
+
if (seqSchema.hasRelation(seq.name)) {
|
|
22075
22135
|
throw pgError("duplicate_table", `relation "${seq.name}" already exists`, "42P07");
|
|
22076
22136
|
}
|
|
22077
|
-
|
|
22137
|
+
seqSchema.sequences.set(seq.name, seq);
|
|
22078
22138
|
}
|
|
22079
22139
|
const table = new TableData(schema.name, name, built.columns, state.nextOid(), stmt.temp);
|
|
22080
22140
|
table.constraints = built.constraints;
|
|
@@ -22426,7 +22486,13 @@ function executeAlterTable(env, stmt) {
|
|
|
22426
22486
|
const built = { columns: [], constraints: [], sequences: [] };
|
|
22427
22487
|
const taken = constraintNames(table);
|
|
22428
22488
|
const col = buildColumn(env, schema, table.name, action.column, built, taken);
|
|
22429
|
-
for (const seq of built.sequences)
|
|
22489
|
+
for (const seq of built.sequences) {
|
|
22490
|
+
const seqSchema = state.getSchema(seq.schema);
|
|
22491
|
+
if (seqSchema.hasRelation(seq.name)) {
|
|
22492
|
+
throw pgError("duplicate_table", `relation "${seq.name}" already exists`, "42P07");
|
|
22493
|
+
}
|
|
22494
|
+
seqSchema.sequences.set(seq.name, seq);
|
|
22495
|
+
}
|
|
22430
22496
|
table.columns.push(col);
|
|
22431
22497
|
table.constraints.push(...built.constraints);
|
|
22432
22498
|
for (let i = 0; i < rows.length; i++) {
|
|
@@ -22746,12 +22812,32 @@ function executeAlterTable(env, stmt) {
|
|
|
22746
22812
|
"42P16"
|
|
22747
22813
|
);
|
|
22748
22814
|
}
|
|
22749
|
-
|
|
22750
|
-
|
|
22815
|
+
if (!col.notNull) {
|
|
22816
|
+
throw pgError(
|
|
22817
|
+
"object_not_in_prerequisite_state",
|
|
22818
|
+
`column "${action.column}" of relation "${table.name}" must be declared NOT NULL before identity can be added`,
|
|
22819
|
+
"55000"
|
|
22820
|
+
);
|
|
22821
|
+
}
|
|
22822
|
+
const target = identitySequenceTarget(
|
|
22823
|
+
env,
|
|
22824
|
+
schema,
|
|
22825
|
+
truncIdent(`${table.name}_${action.column}_seq`),
|
|
22826
|
+
action.options
|
|
22827
|
+
);
|
|
22828
|
+
if (target.schema.hasRelation(target.name)) {
|
|
22829
|
+
throw pgError("duplicate_table", `relation "${target.name}" already exists`, "42P07");
|
|
22830
|
+
}
|
|
22831
|
+
const seq = buildSequence(env, target.schema, target.name, action.options, false);
|
|
22832
|
+
if (!action.options.as) {
|
|
22833
|
+
seq.dataType = col.type.id === "int2" || col.type.id === "int4" || col.type.id === "int8" ? col.type.id : "int8";
|
|
22834
|
+
const limits = SEQ_LIMITS[seq.dataType];
|
|
22835
|
+
if (action.options.maxValue === void 0) seq.maxValue = seq.increment > 0n ? limits.max : -1n;
|
|
22836
|
+
if (action.options.minValue === void 0) seq.minValue = seq.increment > 0n ? 1n : limits.min;
|
|
22837
|
+
}
|
|
22751
22838
|
seq.ownedBy = { table: table.name, column: action.column };
|
|
22752
|
-
schema.sequences.set(
|
|
22753
|
-
col.identity = { always:
|
|
22754
|
-
col.notNull = true;
|
|
22839
|
+
target.schema.sequences.set(target.name, seq);
|
|
22840
|
+
col.identity = { always: action.always, sequence: `${target.schema.name}.${target.name}` };
|
|
22755
22841
|
break;
|
|
22756
22842
|
}
|
|
22757
22843
|
case "drop_identity": {
|