Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add lint for no primary key #5

Merged
merged 4 commits into from
Mar 5, 2024
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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ __pycache__/
*.py[cod]
*$py.class

# test artifacts
regression.diffs
regression.out

# C extensions
*.so

Expand Down
24 changes: 3 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,34 +41,16 @@ Detects if calls to auth.function() in RLS policies are being unnecessarily re-e
- Level: WARN
- Facing: EXTERNAL

## TODO Lints

The following are lints on the TODO list with a WIP associated query showing how to get at "some" of the data.

### tables_missing_primary_key
### 0004_no_primary_key

Detect tables without a primary key.

- Level: INFO
- Facing: EXTERNAL

## TODO Lints

```sql
SELECT n.nspname as schema_name,
c.relname as table_name
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = 'r'
AND NOT EXISTS (
SELECT 1
FROM pg_catalog.pg_constraint con
WHERE con.conrelid = c.oid
AND con.contype = 'p'
)
AND n.nspname <> 'pg_catalog'
AND n.nspname <> 'information_schema'
AND n.nspname !~ '^pg_toast';
```
The following are lints on the TODO list with a WIP associated query showing how to get at "some" of the data.

### unused_indexes

Expand Down
2 changes: 1 addition & 1 deletion bin/installcheck
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ else
fi

# Execute the test fixtures
psql -v ON_ERROR_STOP= -f test/fixtures.sql -f lints/0001*.sql -f lints/0002*.sql -f lints/0003*.sql -d contrib_regression
psql -v ON_ERROR_STOP= -f test/fixtures.sql -f lints/0001*.sql -f lints/0002*.sql -f lints/0003*.sql -f lints/0004*.sql -d contrib_regression

# Run tests
${REGRESS} --use-existing --dbname=contrib_regression --inputdir=${TESTDIR} ${TESTS}
36 changes: 36 additions & 0 deletions lints/0004_no_primary_key.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
create view lint."0004_no_primary_key" as

select
'no_primary_key' as name,
'INFO' as level,
'EXTERNAL' as facing,
'Detects if a table does not have a primary key. Tables without a primary key can be inefficient to interact with at scale.' as description,
format(
'Table "%s.%s" does not have a primary key',
pgns.nspname,
pgc.relname
) as detail,
null as remediation,
null as metadata,
format(
'no_primary_key_%s_%s',
pgns.nspname,
pgc.relname
) as cache_key
from
pg_class pgc
join pg_namespace pgns
on pgns.oid = pgc.relnamespace
left join pg_index pgi
on pgi.indrelid = pgc.oid
where
pgc.relkind = 'r' -- regular tables
and pgns.nspname not in (
'pg_catalog', 'information_schema', 'auth', 'storage', 'vault', 'pgsodium'
)
group by
pgc.oid,
pgns.nspname,
pgc.relname
having
max(coalesce(pgi.indisprimary, false)::int) = 0;
23 changes: 23 additions & 0 deletions test/expected/0004_no_primary_key.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
begin;
-- No issues
select * from lint."0004_no_primary_key";
name | level | facing | description | detail | remediation | metadata | cache_key
------+-------+--------+-------------+--------+-------------+----------+-----------
(0 rows)

-- Table with a primary key
create table public.foo (
id int primary key
);
-- Table with a primary key
create table public.bar (
id int
);
-- Only the "bar" table is listed
select * from lint."0004_no_primary_key";
name | level | facing | description | detail | remediation | metadata | cache_key
----------------+-------+----------+----------------------------------------------------------------------------------------------------------------------------+------------------------------------------------+-------------+----------+---------------------------
no_primary_key | INFO | EXTERNAL | Detects if a table does not have a primary key. Tables without a primary key can be inefficient to interact with at scale. | Table "public.bar" does not have a primary key | | | no_primary_key_public_bar
(1 row)

rollback;
6 changes: 0 additions & 6 deletions test/expected/select_one.out

This file was deleted.

19 changes: 19 additions & 0 deletions test/sql/0004_no_primary_key.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
begin;

-- No issues
select * from lint."0004_no_primary_key";

-- Table with a primary key
create table public.foo (
id int primary key
);

-- Table with a primary key
create table public.bar (
id int
);

-- Only the "bar" table is listed
select * from lint."0004_no_primary_key";

rollback;
Loading