# Trying pgContext on an Existing pgvector Database

pgContext can be installed alongside pgvector and can index existing
`vector` columns directly — no data movement, no schema changes, no
downtime. This page covers coexist mode: what works, what to expect, and
how to migrate when you are ready.

## Install order matters

Install pgvector first, pgContext second:

```sql
CREATE EXTENSION vector;     -- already present on a pgvector database
CREATE EXTENSION pgcontext;  -- detects pgvector and binds to its types
```

When pgvector is present, pgContext skips creating its own `vector`,
`halfvec`, and `sparsevec` types and instead binds its operators, index
operator classes, and functions to pgvector's types. The two vector
representations are byte-for-byte identical, so there is no conversion
anywhere on the query path.

If pgContext was installed first, its own types occupy the public type
names and `CREATE EXTENSION vector` will fail. Reaching coexist mode
then requires reinstalling in the right order (`DROP EXTENSION
pgcontext`, install pgvector, reinstall pgContext);
`pgcontext.enable_pgvector_binding()` explains the same steps in-band.

## Indexing an existing pgvector column

```sql
CREATE INDEX ON items USING pgcontext_hnsw (embedding pgcontext.vector_hnsw_cosine_ops);
```

The pgvector index (if any) and the pgContext index coexist on the same
column; PostgreSQL's planner picks one per query. Available operator
classes: `pgcontext.vector_hnsw_ops` (L2),
`pgcontext.vector_hnsw_cosine_ops`, `pgcontext.vector_hnsw_ip_ops`,
`pgcontext.vector_hnsw_l1_ops`.

The registered-collection API works over pgvector columns the same way:
`pgcontext.create_collection` / `register_vector` accept them directly.

## The advisory notice

The first time a backend builds or scans a pgContext index over a
pgvector-typed column, it emits one `NOTICE` recommending
`pgcontext.migration_report()`. Results are always complete — the notice
is guidance, never a gate. Disable it with:

```sql
SET pgcontext.pgvector_compat_warnings = off;
```

## Migration tooling

- **`pgcontext.migration_report()`** — read-only inventory: every
  pgvector-typed column, its dimensions, existing pgvector and pgContext
  indexes, and the exact suggested `CREATE INDEX` command per column.
- **`pgcontext.adopt_pgvector(target => NULL, dry_run => true,
  drop_old => false)`** — migrates pgvector `hnsw`/`ivfflat` indexes to
  `pgcontext_hnsw` equivalents with the matching metric. The default is
  a dry run that only prints the commands; pass `dry_run => false` to
  execute, and `drop_old => true` to also drop each pgvector index after
  its replacement builds. Index creation inside the function uses plain
  `CREATE INDEX` (it cannot run `CONCURRENTLY`); on busy tables, prefer
  taking the dry-run commands and running them yourself with
  `CREATE INDEX CONCURRENTLY`.

Column types are never changed by these tools: in coexist mode your
data stays in pgvector's types, and dropping the pgvector extension is
intentionally not possible. Full drop-in replacement (pgvector-spelled
SQL with pgvector absent) is a separate roadmap stage.

## Comparing indexes side by side

`pgcontext.compare_indexes(table_name, column_name, queries => 20)`
measures every ANN index on a column — pgvector `hnsw`/`ivfflat` and
`pgcontext_hnsw` alike — using sampled stored vectors as queries. For
each reachable operator family it times the planner-chosen index scan
and scores top-10 recall against an exact sequential-scan oracle with
the same operator, returning one row per index:
`(index_name, access_method, operator, p50_ms, p95_ms, recall_at_10)`.
Indexes the planner never chose (for example one shadowed by a cheaper
index of the same operator family) report NULL measurements. The
function is read-only; expect it to run `2 x queries` statements per
measured family.

## Current limitations

- `vector` and `halfvec` columns are fully supported: pgContext's
  storage for both is byte-for-byte pgvector's layout (halfvec elements
  are true IEEE 754 binary16, canonicalized with round-to-nearest-even
  on input exactly as pgvector does). `sparsevec` columns are not yet
  served in coexist mode: pgContext operations over them fail with an
  error rather than producing results (that representation has not yet
  been certified byte-compatible).
- Restoring a dump of a coexist database requires pgvector to be created
  before pgContext, which matches the order `pg_dump` preserves.
- `DROP EXTENSION vector CASCADE` in coexist mode also drops the
  pgContext objects bound to pgvector's types. Run
  `pgcontext.migration_report()` first and migrate deliberately instead.
