Step 1 of 3 — Verify your schema

See whether your warehouse can produce customer-level margin— without connecting it

Run one metadata-only query. Usually takes under two minutes. NemulAI never receives warehouse credentials or customer records.

What actually leaves your systems

Sent to NemulAI

  • Table names
  • Column names
  • Column types (e.g. BIGINT, TIMESTAMPTZ)

Never sent, never asked for

  • Database credentials or connection strings
  • OAuth grants or production access
  • An SDK, agent, or proxy in your stack
  • Customer names, prompts, or any row of data

Nothing is stored until you choose to save it — the analysis below runs anonymously. When you do run the audit, you run our generated read-only SQL yourself, in your own warehouse, and upload the results. We never connect to your database.

Metadata only. NemulAI receives table names, column names, data types and relationships — never rows, values or credentials, and never a connection to your database.

Choosing a database does not connect NemulAI to it. It only determines which query we generate.

Comma-separated. Defaults to public. Most warehouses keep this data somewhere else — analytics, dbt_prod, raw — and only the schemas you name here are exported.

Your metadata query

One row per column: schema, table, column, data type, whether it is nullable, and any declared primary or foreign key.

-- NemulAI schema metadata.
-- Read-only: catalog reads only, no DML. Review it before running.
-- Scanning schema(s): public
WITH fk AS (
    -- One row per (referencing column -> referenced column).
    -- The constraint is identified by catalog + schema + name, never name
    -- alone, or identically named constraints in two schemas collide.
    -- The referenced column is matched POSITIONALLY, so a composite key
    -- yields ordered pairs instead of a cartesian product.
    SELECT
        src.table_schema,
        src.table_name,
        src.column_name,
        tgt.table_schema AS foreign_table_schema,
        tgt.table_name   AS foreign_table_name,
        tgt.column_name  AS foreign_column_name
    FROM information_schema.key_column_usage src
    JOIN information_schema.referential_constraints rc
      ON  rc.constraint_catalog = src.constraint_catalog
      AND rc.constraint_schema  = src.constraint_schema
      AND rc.constraint_name    = src.constraint_name
    JOIN information_schema.key_column_usage tgt
      ON  tgt.constraint_catalog = rc.unique_constraint_catalog
      AND tgt.constraint_schema  = rc.unique_constraint_schema
      AND tgt.constraint_name    = rc.unique_constraint_name
      AND tgt.ordinal_position   = src.position_in_unique_constraint
),
pk AS (
    SELECT kcu.table_schema, kcu.table_name, kcu.column_name
    FROM information_schema.table_constraints tc
    JOIN information_schema.key_column_usage kcu
      ON  kcu.constraint_catalog = tc.constraint_catalog
      AND kcu.constraint_schema  = tc.constraint_schema
      AND kcu.constraint_name    = tc.constraint_name
    WHERE tc.constraint_type = 'PRIMARY KEY'
)
SELECT
    c.table_schema                AS table_schema,
    c.table_name                  AS table_name,
    c.column_name                 AS column_name,
    c.data_type                   AS data_type,
    c.is_nullable                 AS is_nullable,
    CASE WHEN pk.column_name IS NOT NULL
         THEN 'YES' ELSE 'NO' END AS is_primary_key,
    fk.foreign_table_schema       AS foreign_table_schema,
    fk.foreign_table_name         AS foreign_table,
    fk.foreign_column_name        AS foreign_column
FROM information_schema.columns c
LEFT JOIN pk
  ON  pk.table_schema = c.table_schema
  AND pk.table_name   = c.table_name
  AND pk.column_name  = c.column_name
LEFT JOIN fk
  ON  fk.table_schema = c.table_schema
  AND fk.table_name   = c.table_name
  AND fk.column_name  = c.column_name
WHERE c.table_schema IN ('public')
ORDER BY c.table_schema, c.table_name, c.ordinal_position;

Where to run it: psql, TablePlus, DBeaver, pgAdmin — anywhere you normally run a SELECT.

Paste your query results

Copy straight out of your warehouse — comma, tab or pipe separated all work.

Paste your query results above, or open the file options.