Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ Notable changes to `@tinbase/pg-mem`, the tinbase fork of pg-mem.

Released from `main`, which carries the scoped package name. Upstream is tracked through the `upstream` remote (`oguimbal/pg-mem`) rather than a branch; the leftover `master` is vestigial.

## 4.0.3

- A user column named after a system column (`tableoid`, `xmin`, `cmin`, `xmax`, `cmax`, `ctid`) is refused in CREATE TABLE, ADD COLUMN and RENAME COLUMN, as postgres does: `column name "xmin" conflicts with a system column name`. The migration validator accepted DDL postgres rejects.

## 4.0.2

Gaps found by running 80 production projects' migrations and seeds through the agent's validator on pg-mem and on PGlite; all 80 now match. Requires `@tinbase/pgsql-ast-parser` 12.2.1.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tinbase/pg-mem",
"version": "4.0.2",
"version": "4.0.3",
"description": "Fork of pg-mem with extended Postgres conformance (PL/pgSQL, triggers, RLS, correlated subqueries, MERGE, ranges, full-text, partitioning, ...). Tracks oguimbal/pg-mem; pending upstream PR #476.",
"main": "index.js",
"publishConfig": {
Expand Down
2 changes: 2 additions & 0 deletions src/column.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { _Column, IValue, _IIndex, NotSupported, _Transaction, QueryError, _IType, SchemaField, ChangeHandler, nil, ISubscription, DropHandler } from './interfaces-private';
import type { MemoryTable } from './table';
import { assertNotSystemColumn } from './table';
import { Evaluator } from './evaluator';
import { ColumnConstraint, AlterColumn, Expr, toSql, DataTypeDef } from 'pgsql-ast-parser';
import { policiesDependingOn } from './execution/policy-deps';
Expand Down Expand Up @@ -133,6 +134,7 @@ export class ColRef implements _Column {
if (this.table.getColumnRef(to, true)) {
throw new QueryError(`Column "${to}" already exists`);
}
assertNotSystemColumn(to);

// first, move data (this cannot throw => OK to modify mutable data)
this.table.remapData(t, v => {
Expand Down
10 changes: 10 additions & 0 deletions src/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,15 @@ class ColumnManager {
}
}

/** every postgres table has these hidden columns; no user column may take their names */
const SYSTEM_COLUMNS = new Set(['tableoid', 'xmin', 'cmin', 'xmax', 'cmax', 'ctid']);

export function assertNotSystemColumn(name: string) {
if (SYSTEM_COLUMNS.has(name)) {
throw new QueryError(`column name "${name}" conflicts with a system column name`, '42701');
}
}

export class MemoryTable extends DataSourceBase implements IMemoryTable<any>, _ITable {
comment: string | nil;
readonly rls: TableRls = emptyRls();
Expand Down Expand Up @@ -264,6 +273,7 @@ export class MemoryTable extends DataSourceBase implements IMemoryTable<any>, _I
if (this.columnMgr.has(column.name)) {
throw new QueryError(`Column "${column.name}" already exists`);
}
assertNotSystemColumn(column.name);
const type = typeof column.type === 'string'
? this.ownerSchema.getType(column.type)
: column.type;
Expand Down
10 changes: 10 additions & 0 deletions src/tests/corpus-parity.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,16 @@ describe('corpus parity', () => {
});
});

describe('system column names', () => {
it('are refused for user columns, as in postgres', () => {
expectQueryError(() => none(`create table t ("xmin" text)`), /column name "xmin" conflicts with a system column name/);
none(`create table z (id int)`);
expectQueryError(() => none(`alter table z add column ctid text`), /conflicts with a system column name/);
expectQueryError(() => none(`alter table z rename column id to tableoid`), /conflicts with a system column name/);
none(`create table w (xminimum int, "Xmin" int)`);
});
});

describe('CREATE OR REPLACE TRIGGER', () => {
it('replaces an existing trigger', () => {
none(`create table o (id int, n int);
Expand Down
Loading