postgresai 0.17.0-dev.2 → 0.17.0-dev.3
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/README.md +156 -3
- package/dist/bin/postgres-ai.js +14860 -11764
- package/dist/sql/01.role.sql +2 -1
- package/dist/sql/06.helpers.sql +29 -8
- package/dist/sql/sql/01.role.sql +2 -1
- package/dist/sql/sql/06.helpers.sql +29 -8
- package/package.json +1 -1
- package/sql/01.role.sql +2 -1
- package/sql/06.helpers.sql +29 -8
package/dist/sql/01.role.sql
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
-- Role creation / password update (template-filled by cli/lib/init.ts)
|
|
2
2
|
--
|
|
3
|
-
--
|
|
3
|
+
-- A race-safe pattern: create if missing, then alter to set the password.
|
|
4
|
+
-- `pgai connect` omits the alter, so an existing role keeps its password:
|
|
4
5
|
-- do $$ begin
|
|
5
6
|
-- if not exists (select 1 from pg_catalog.pg_roles where rolname = '...') then
|
|
6
7
|
-- begin
|
package/dist/sql/06.helpers.sql
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
-- Helper functions for postgres_ai monitoring user (template-filled by cli/lib/init.ts)
|
|
2
|
-
-- These functions use SECURITY DEFINER to allow the monitoring user to perform
|
|
3
|
-
-- operations they don't have direct permissions for.
|
|
4
2
|
|
|
5
3
|
/*
|
|
6
4
|
* table_describe
|
|
@@ -15,18 +13,25 @@
|
|
|
15
13
|
*
|
|
16
14
|
* Usage:
|
|
17
15
|
* select postgres_ai.table_describe('public.users');
|
|
18
|
-
* select postgres_ai.table_describe('my_table'); --
|
|
16
|
+
* select postgres_ai.table_describe('my_table'); -- pg_catalog, then public
|
|
17
|
+
*
|
|
18
|
+
* SECURITY INVOKER: it reads only the world-readable catalog, so it needs no
|
|
19
|
+
* privilege the caller lacks. Names are resolved by catalog query, not regclass
|
|
20
|
+
* (which demands USAGE on the schema): unqualified in pg_catalog, then public.
|
|
21
|
+
* search_path is pg_catalog, pg_temp so objects in a writable schema cannot
|
|
22
|
+
* shadow a built-in the function calls.
|
|
19
23
|
*/
|
|
20
24
|
create or replace function postgres_ai.table_describe(
|
|
21
25
|
in table_name text,
|
|
22
26
|
out result text
|
|
23
27
|
)
|
|
24
28
|
language plpgsql
|
|
25
|
-
security
|
|
26
|
-
set search_path = pg_catalog,
|
|
29
|
+
security invoker
|
|
30
|
+
set search_path = pg_catalog, pg_temp
|
|
27
31
|
as $$
|
|
28
32
|
declare
|
|
29
33
|
v_oid oid;
|
|
34
|
+
v_ident text[];
|
|
30
35
|
v_schema text;
|
|
31
36
|
v_table text;
|
|
32
37
|
v_relkind char;
|
|
@@ -37,8 +42,24 @@ declare
|
|
|
37
42
|
v_rec record;
|
|
38
43
|
v_constraint_count int := 0;
|
|
39
44
|
begin
|
|
40
|
-
-- Resolve table name to OID
|
|
41
|
-
|
|
45
|
+
-- Resolve table name to OID: [current database.]schema.table (pg_temp is the
|
|
46
|
+
-- caller's temp schema), or an unqualified name in pg_catalog, then public
|
|
47
|
+
v_ident := parse_ident(table_name);
|
|
48
|
+
select c.oid into v_oid
|
|
49
|
+
from pg_class c
|
|
50
|
+
join pg_namespace n on n.oid = c.relnamespace
|
|
51
|
+
where (cardinality(v_ident) <= 2 or (cardinality(v_ident) = 3 and v_ident[1] = current_database()))
|
|
52
|
+
and c.relname = v_ident[cardinality(v_ident)]::name
|
|
53
|
+
and case
|
|
54
|
+
when cardinality(v_ident) = 1 then n.nspname in ('pg_catalog', 'public')
|
|
55
|
+
when v_ident[cardinality(v_ident) - 1] = 'pg_temp' then n.oid = pg_my_temp_schema()
|
|
56
|
+
else n.nspname = v_ident[cardinality(v_ident) - 1]::name
|
|
57
|
+
end
|
|
58
|
+
order by n.nspname = 'public'
|
|
59
|
+
limit 1;
|
|
60
|
+
if v_oid is null then
|
|
61
|
+
raise exception 'relation "%" does not exist', table_name using errcode = '42P01';
|
|
62
|
+
end if;
|
|
42
63
|
|
|
43
64
|
-- Get basic table info
|
|
44
65
|
select
|
|
@@ -207,7 +228,7 @@ begin
|
|
|
207
228
|
when 'f' then v_line := v_line || 'FK: ';
|
|
208
229
|
when 'u' then v_line := v_line || 'UNIQUE: ';
|
|
209
230
|
when 'c' then v_line := v_line || 'CHECK: ';
|
|
210
|
-
else v_line := v_line || v_rec.contype || ': ';
|
|
231
|
+
else v_line := v_line || v_rec.contype::text || ': ';
|
|
211
232
|
end case;
|
|
212
233
|
v_line := v_line || v_rec.conname || ' ' || v_rec.condef;
|
|
213
234
|
v_lines := array_append(v_lines, v_line);
|
package/dist/sql/sql/01.role.sql
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
-- Role creation / password update (template-filled by cli/lib/init.ts)
|
|
2
2
|
--
|
|
3
|
-
--
|
|
3
|
+
-- A race-safe pattern: create if missing, then alter to set the password.
|
|
4
|
+
-- `pgai connect` omits the alter, so an existing role keeps its password:
|
|
4
5
|
-- do $$ begin
|
|
5
6
|
-- if not exists (select 1 from pg_catalog.pg_roles where rolname = '...') then
|
|
6
7
|
-- begin
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
-- Helper functions for postgres_ai monitoring user (template-filled by cli/lib/init.ts)
|
|
2
|
-
-- These functions use SECURITY DEFINER to allow the monitoring user to perform
|
|
3
|
-
-- operations they don't have direct permissions for.
|
|
4
2
|
|
|
5
3
|
/*
|
|
6
4
|
* table_describe
|
|
@@ -15,18 +13,25 @@
|
|
|
15
13
|
*
|
|
16
14
|
* Usage:
|
|
17
15
|
* select postgres_ai.table_describe('public.users');
|
|
18
|
-
* select postgres_ai.table_describe('my_table'); --
|
|
16
|
+
* select postgres_ai.table_describe('my_table'); -- pg_catalog, then public
|
|
17
|
+
*
|
|
18
|
+
* SECURITY INVOKER: it reads only the world-readable catalog, so it needs no
|
|
19
|
+
* privilege the caller lacks. Names are resolved by catalog query, not regclass
|
|
20
|
+
* (which demands USAGE on the schema): unqualified in pg_catalog, then public.
|
|
21
|
+
* search_path is pg_catalog, pg_temp so objects in a writable schema cannot
|
|
22
|
+
* shadow a built-in the function calls.
|
|
19
23
|
*/
|
|
20
24
|
create or replace function postgres_ai.table_describe(
|
|
21
25
|
in table_name text,
|
|
22
26
|
out result text
|
|
23
27
|
)
|
|
24
28
|
language plpgsql
|
|
25
|
-
security
|
|
26
|
-
set search_path = pg_catalog,
|
|
29
|
+
security invoker
|
|
30
|
+
set search_path = pg_catalog, pg_temp
|
|
27
31
|
as $$
|
|
28
32
|
declare
|
|
29
33
|
v_oid oid;
|
|
34
|
+
v_ident text[];
|
|
30
35
|
v_schema text;
|
|
31
36
|
v_table text;
|
|
32
37
|
v_relkind char;
|
|
@@ -37,8 +42,24 @@ declare
|
|
|
37
42
|
v_rec record;
|
|
38
43
|
v_constraint_count int := 0;
|
|
39
44
|
begin
|
|
40
|
-
-- Resolve table name to OID
|
|
41
|
-
|
|
45
|
+
-- Resolve table name to OID: [current database.]schema.table (pg_temp is the
|
|
46
|
+
-- caller's temp schema), or an unqualified name in pg_catalog, then public
|
|
47
|
+
v_ident := parse_ident(table_name);
|
|
48
|
+
select c.oid into v_oid
|
|
49
|
+
from pg_class c
|
|
50
|
+
join pg_namespace n on n.oid = c.relnamespace
|
|
51
|
+
where (cardinality(v_ident) <= 2 or (cardinality(v_ident) = 3 and v_ident[1] = current_database()))
|
|
52
|
+
and c.relname = v_ident[cardinality(v_ident)]::name
|
|
53
|
+
and case
|
|
54
|
+
when cardinality(v_ident) = 1 then n.nspname in ('pg_catalog', 'public')
|
|
55
|
+
when v_ident[cardinality(v_ident) - 1] = 'pg_temp' then n.oid = pg_my_temp_schema()
|
|
56
|
+
else n.nspname = v_ident[cardinality(v_ident) - 1]::name
|
|
57
|
+
end
|
|
58
|
+
order by n.nspname = 'public'
|
|
59
|
+
limit 1;
|
|
60
|
+
if v_oid is null then
|
|
61
|
+
raise exception 'relation "%" does not exist', table_name using errcode = '42P01';
|
|
62
|
+
end if;
|
|
42
63
|
|
|
43
64
|
-- Get basic table info
|
|
44
65
|
select
|
|
@@ -207,7 +228,7 @@ begin
|
|
|
207
228
|
when 'f' then v_line := v_line || 'FK: ';
|
|
208
229
|
when 'u' then v_line := v_line || 'UNIQUE: ';
|
|
209
230
|
when 'c' then v_line := v_line || 'CHECK: ';
|
|
210
|
-
else v_line := v_line || v_rec.contype || ': ';
|
|
231
|
+
else v_line := v_line || v_rec.contype::text || ': ';
|
|
211
232
|
end case;
|
|
212
233
|
v_line := v_line || v_rec.conname || ' ' || v_rec.condef;
|
|
213
234
|
v_lines := array_append(v_lines, v_line);
|
package/package.json
CHANGED
package/sql/01.role.sql
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
-- Role creation / password update (template-filled by cli/lib/init.ts)
|
|
2
2
|
--
|
|
3
|
-
--
|
|
3
|
+
-- A race-safe pattern: create if missing, then alter to set the password.
|
|
4
|
+
-- `pgai connect` omits the alter, so an existing role keeps its password:
|
|
4
5
|
-- do $$ begin
|
|
5
6
|
-- if not exists (select 1 from pg_catalog.pg_roles where rolname = '...') then
|
|
6
7
|
-- begin
|
package/sql/06.helpers.sql
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
-- Helper functions for postgres_ai monitoring user (template-filled by cli/lib/init.ts)
|
|
2
|
-
-- These functions use SECURITY DEFINER to allow the monitoring user to perform
|
|
3
|
-
-- operations they don't have direct permissions for.
|
|
4
2
|
|
|
5
3
|
/*
|
|
6
4
|
* table_describe
|
|
@@ -15,18 +13,25 @@
|
|
|
15
13
|
*
|
|
16
14
|
* Usage:
|
|
17
15
|
* select postgres_ai.table_describe('public.users');
|
|
18
|
-
* select postgres_ai.table_describe('my_table'); --
|
|
16
|
+
* select postgres_ai.table_describe('my_table'); -- pg_catalog, then public
|
|
17
|
+
*
|
|
18
|
+
* SECURITY INVOKER: it reads only the world-readable catalog, so it needs no
|
|
19
|
+
* privilege the caller lacks. Names are resolved by catalog query, not regclass
|
|
20
|
+
* (which demands USAGE on the schema): unqualified in pg_catalog, then public.
|
|
21
|
+
* search_path is pg_catalog, pg_temp so objects in a writable schema cannot
|
|
22
|
+
* shadow a built-in the function calls.
|
|
19
23
|
*/
|
|
20
24
|
create or replace function postgres_ai.table_describe(
|
|
21
25
|
in table_name text,
|
|
22
26
|
out result text
|
|
23
27
|
)
|
|
24
28
|
language plpgsql
|
|
25
|
-
security
|
|
26
|
-
set search_path = pg_catalog,
|
|
29
|
+
security invoker
|
|
30
|
+
set search_path = pg_catalog, pg_temp
|
|
27
31
|
as $$
|
|
28
32
|
declare
|
|
29
33
|
v_oid oid;
|
|
34
|
+
v_ident text[];
|
|
30
35
|
v_schema text;
|
|
31
36
|
v_table text;
|
|
32
37
|
v_relkind char;
|
|
@@ -37,8 +42,24 @@ declare
|
|
|
37
42
|
v_rec record;
|
|
38
43
|
v_constraint_count int := 0;
|
|
39
44
|
begin
|
|
40
|
-
-- Resolve table name to OID
|
|
41
|
-
|
|
45
|
+
-- Resolve table name to OID: [current database.]schema.table (pg_temp is the
|
|
46
|
+
-- caller's temp schema), or an unqualified name in pg_catalog, then public
|
|
47
|
+
v_ident := parse_ident(table_name);
|
|
48
|
+
select c.oid into v_oid
|
|
49
|
+
from pg_class c
|
|
50
|
+
join pg_namespace n on n.oid = c.relnamespace
|
|
51
|
+
where (cardinality(v_ident) <= 2 or (cardinality(v_ident) = 3 and v_ident[1] = current_database()))
|
|
52
|
+
and c.relname = v_ident[cardinality(v_ident)]::name
|
|
53
|
+
and case
|
|
54
|
+
when cardinality(v_ident) = 1 then n.nspname in ('pg_catalog', 'public')
|
|
55
|
+
when v_ident[cardinality(v_ident) - 1] = 'pg_temp' then n.oid = pg_my_temp_schema()
|
|
56
|
+
else n.nspname = v_ident[cardinality(v_ident) - 1]::name
|
|
57
|
+
end
|
|
58
|
+
order by n.nspname = 'public'
|
|
59
|
+
limit 1;
|
|
60
|
+
if v_oid is null then
|
|
61
|
+
raise exception 'relation "%" does not exist', table_name using errcode = '42P01';
|
|
62
|
+
end if;
|
|
42
63
|
|
|
43
64
|
-- Get basic table info
|
|
44
65
|
select
|
|
@@ -207,7 +228,7 @@ begin
|
|
|
207
228
|
when 'f' then v_line := v_line || 'FK: ';
|
|
208
229
|
when 'u' then v_line := v_line || 'UNIQUE: ';
|
|
209
230
|
when 'c' then v_line := v_line || 'CHECK: ';
|
|
210
|
-
else v_line := v_line || v_rec.contype || ': ';
|
|
231
|
+
else v_line := v_line || v_rec.contype::text || ': ';
|
|
211
232
|
end case;
|
|
212
233
|
v_line := v_line || v_rec.conname || ' ' || v_rec.condef;
|
|
213
234
|
v_lines := array_append(v_lines, v_line);
|