Skip to content

Commit

Permalink
Merge branch 'develop' into persist_inspector_section_visibility
Browse files Browse the repository at this point in the history
  • Loading branch information
pavish authored Nov 7, 2024
2 parents fba9edb + c518a78 commit 28229a8
Show file tree
Hide file tree
Showing 3 changed files with 499 additions and 139 deletions.
105 changes: 69 additions & 36 deletions db/sql/00_msar.sql
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ $$ LANGUAGE sql RETURNS NULL ON NULL INPUT;
CREATE OR REPLACE FUNCTION
__msar.exec_dql(command text) RETURNS jsonb AS $$/*
Execute the given command, returning a JSON object describing the records in the following form:
[
[
{"id": 1, "col1_name": "value1", "col2_name": "value2"},
{"id": 2, "col1_name": "value1", "col2_name": "value2"},
{"id": 3, "col1_name": "value1", "col2_name": "value2"},
Expand Down Expand Up @@ -172,7 +172,7 @@ $$ LANGUAGE plpgsql RETURNS NULL ON NULL INPUT;
CREATE OR REPLACE FUNCTION
__msar.exec_dql(command_template text, arguments variadic anyarray) RETURNS jsonb AS $$/*
Execute a templated command, returning a JSON object describing the records in the following form:
[
[
{"id": 1, "col1_name": "value1", "col2_name": "value2"},
{"id": 2, "col1_name": "value1", "col2_name": "value2"},
{"id": 3, "col1_name": "value1", "col2_name": "value2"},
Expand Down Expand Up @@ -1063,7 +1063,7 @@ SELECT coalesce(
),
'[]'::jsonb
)
FROM pg_catalog.pg_class AS pgc
FROM pg_catalog.pg_class AS pgc
LEFT JOIN pg_catalog.pg_namespace AS pgn ON pgc.relnamespace = pgn.oid
WHERE pgc.relnamespace = sch_id AND pgc.relkind = 'r';
$$ LANGUAGE SQL RETURNS NULL ON NULL INPUT;
Expand Down Expand Up @@ -1093,7 +1093,7 @@ CREATE OR REPLACE FUNCTION msar.schema_info_table() RETURNS TABLE
current_role_owns boolean, -- Whether the current role owns the schema.
table_count integer -- The number of tables in the schema.
) AS $$
SELECT
SELECT
s.oid::bigint AS oid,
s.nspname AS name,
pg_catalog.obj_description(s.oid) AS description,
Expand Down Expand Up @@ -3144,7 +3144,7 @@ BEGIN
relation_name := __msar.get_qualified_relation_name_or_null(tab_id);
-- if_exists doesn't work while working with oids because
-- the SQL query gets parameterized with tab_id instead of relation_name
-- since we're unable to find the relation_name for a non existing table.
-- since we're unable to find the relation_name for a non existing table.
PERFORM __msar.drop_table(relation_name, cascade_, if_exists => false);
RETURN relation_name;
END;
Expand Down Expand Up @@ -3449,7 +3449,7 @@ BEGIN
) AS cast_expr
FROM jsonb_array_elements(col_cast_def) AS col_cast
)
SELECT
SELECT
__msar.exec_dql(sel_query, cast_expr, tab_name, rec_limit::text)
INTO records FROM preview_cte;
RETURN records;
Expand Down Expand Up @@ -3883,7 +3883,7 @@ BEGIN
END IF;

-- Here, we perform all description-changing alterations.
FOR description_alter IN
FOR description_alter IN
SELECT
(col_alter->>'attnum')::integer AS col_id,
col_alter->>'description' AS comment_
Expand Down Expand Up @@ -4019,7 +4019,7 @@ msar.add_foreign_key_column(
rel_id oid,
frel_id oid,
unique_link boolean DEFAULT false
) RETURNS smallint AS $$/*
) RETURNS smallint AS $$/*
Create a many-to-one or a one-to-one link between tables, returning the attnum of the newly created
column, returning the attnum of the added column.
Expand Down Expand Up @@ -4767,6 +4767,14 @@ LIMIT 1;
$$ LANGUAGE SQL STABLE RETURNS NULL ON NULL INPUT;


CREATE OR REPLACE FUNCTION msar.build_empty_record_summary_query() RETURNS TEXT AS $$/*
Returns a stringified query structured consistently with a record summary query but which will
yield no record summaries when run.
*/
SELECT $q$ SELECT NULL AS key, NULL AS summary WHERE FALSE $q$;
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;


CREATE OR REPLACE FUNCTION msar.build_record_summary_query_from_template(
tab_id oid,
key_col_id smallint,
Expand All @@ -4778,7 +4786,7 @@ CREATE OR REPLACE FUNCTION msar.build_record_summary_query_from_template(
Args:
tab_id: The OID of the table for which to generate a record summary query.
template: A JSON array that represents the record summary template (described in detail below).
Example template:
[
Expand All @@ -4798,7 +4806,7 @@ CREATE OR REPLACE FUNCTION msar.build_record_summary_query_from_template(
contains more than one column reference, it represents a chain of FK columns starting from
the base table and ending with a non-FK column. This function follows the foreign keys to
produce the joins. Multi-column FK constraints are not supported.
Return value: a stringified query which produces a result set matching the structure described
in the return value of msar.get_record_summaries_via_query.
*/
Expand All @@ -4814,10 +4822,15 @@ DECLARE
join_section text;
BEGIN
IF key_col_id IS NULL THEN
-- If the key column is NULL, then we can't generate a record summary query. We return a query
-- that will return no rows.
RETURN $q$ SELECT NULL AS key, NULL AS summary WHERE FALSE $q$;
-- If we don't have a key column, then we can't generate a record summary query.
RETURN msar.build_empty_record_summary_query();
END IF;

IF NOT pg_catalog.has_column_privilege(tab_id, key_col_id, 'SELECT') THEN
-- If we don't have permission to select the key column, then we can't generate a record
RETURN msar.build_empty_record_summary_query();
END IF;

IF jsonb_typeof(template) <> 'array' THEN
RAISE EXCEPTION 'Record summary template must be a JSON array.';
END IF;
Expand All @@ -4830,23 +4843,29 @@ BEGIN
fk_col_id smallint;
contextual_tab_id oid := tab_id;
prev_alias text := base_alias;
ref_column_name text;
ref_col_id smallint;
ref_col_name text;
BEGIN
-- Column reference template parts
IF ref_chain_length > 0 THEN
-- Except for the final ref_chain element, process all array elements as attnums of FK
-- columns.
FOREACH fk_col_id IN ARRAY ref_chain[1:ref_chain_length-1] LOOP
DECLARE
fk_col_name text := msar.get_column_name(contextual_tab_id, fk_col_id);
fk_col_name text;
ref_tab_id oid;
ref_col_id smallint;
ref_sch_name text;
ref_tab_name text;
ref_col_name text;
alias text;
join_clause text;
BEGIN
IF NOT pg_catalog.has_column_privilege(contextual_tab_id, fk_col_id, 'SELECT') THEN
-- Silently ignore FK columns that we don't have permissions to select.
CONTINUE template_parts_loop;
END IF;

fk_col_name := msar.get_column_name(contextual_tab_id, fk_col_id);

IF fk_col_name IS NULL THEN
-- Silently ignore references to non-existing FK columns. This can happen if a column
-- has been deleted.
Expand All @@ -4863,6 +4882,12 @@ BEGIN
CONTINUE template_parts_loop;
END IF;

IF NOT pg_catalog.has_column_privilege(ref_tab_id, ref_col_id, 'SELECT') THEN
-- Silently ignore FK columns which point to columns that we don't have permission to
-- select.
CONTINUE template_parts_loop;
END IF;

ref_tab_name := msar.get_relation_name(ref_tab_id);
ref_sch_name := msar.get_relation_schema_name(ref_tab_id);
ref_col_name := msar.get_column_name(ref_tab_id, ref_col_id);
Expand All @@ -4885,13 +4910,20 @@ BEGIN
END;
END LOOP;

ref_column_name := msar.get_column_name(contextual_tab_id, ref_chain[ref_chain_length]);
IF ref_column_name IS NOT NULL THEN
ref_col_id := ref_chain[ref_chain_length];

IF NOT pg_catalog.has_column_privilege(contextual_tab_id, ref_col_id, 'SELECT') THEN
-- Silently ignore the final column reference if we don't have permission to select it.
CONTINUE template_parts_loop;
END IF;

ref_col_name := msar.get_column_name(contextual_tab_id, ref_col_id);
IF ref_col_name IS NOT NULL THEN
expr_parts := array_append(
expr_parts,
concat(
'COALESCE(msar.format_data(',
prev_alias, '.', quote_ident(ref_column_name),
prev_alias, '.', quote_ident(ref_col_name),
E')::text, \'\')'
)
);
Expand Down Expand Up @@ -5123,15 +5155,15 @@ BEGIN
LEFT JOIN groups_cte ON enriched_results_cte.__mathesar_gid = groups_cte.id %14$s
CROSS JOIN count_cte
$q$,
/* %1 */ msar.build_selectable_column_expr(tab_id),
/* %1 */ COALESCE(msar.build_selectable_column_expr(tab_id), 'NULL'),
/* %2 */ msar.get_relation_schema_name(tab_id),
/* %3 */ msar.get_relation_name(tab_id),
/* %4 */ limit_,
/* %5 */ offset_,
/* %6 */ msar.build_order_by_expr(tab_id, order_),
/* %7 */ msar.build_where_clause(tab_id, filter_),
/* %8 */ msar.build_grouping_expr(tab_id, group_),
/* %9 */ msar.build_results_jsonb_expr(tab_id, 'enriched_results_cte', order_),
/* %8 */ COALESCE(msar.build_grouping_expr(tab_id, group_), 'NULL'),
/* %9 */ COALESCE(msar.build_results_jsonb_expr(tab_id, 'enriched_results_cte', order_), 'NULL'),
/* %10 */ COALESCE(
msar.build_grouping_results_jsonb_expr(tab_id, 'groups_cte', group_),
'NULL'
Expand Down Expand Up @@ -5220,27 +5252,30 @@ BEGIN
SELECT count(1) AS count FROM %2$I.%3$I %4$s
),
results_cte AS (
SELECT %1$s FROM %2$I.%3$I %4$s ORDER BY %6$s LIMIT %5$L
SELECT %1$s FROM %2$I.%3$I %4$s %6$s LIMIT %5$L
),
summary_cte_self AS (%7$s) %8$s
SELECT jsonb_build_object(
'results', coalesce(jsonb_agg(row_to_json(results_cte.*)), jsonb_build_array()),
'count', coalesce(max(count_cte.count), 0),
'linked_record_summaries', %10$s,
'record_summaries', %11$s,
'query', $iq$SELECT %1$s FROM %2$I.%3$I %4$s ORDER BY %6$s LIMIT %5$L$iq$
'query', $iq$SELECT %1$s FROM %2$I.%3$I %4$s %6$s LIMIT %5$L$iq$
)
FROM results_cte %9$s
CROSS JOIN count_cte
$q$,
/* %1 */ msar.build_selectable_column_expr(tab_id),
/* %1 */ COALESCE(msar.build_selectable_column_expr(tab_id), 'NULL'),
/* %2 */ msar.get_relation_schema_name(tab_id),
/* %3 */ msar.get_relation_name(tab_id),
/* %4 */ 'WHERE ' || msar.get_score_expr(tab_id, search_) || ' > 0',
/* %5 */ limit_,
/* %6 */ concat(
msar.get_score_expr(tab_id, search_) || ' DESC, ',
msar.build_total_order_expr(tab_id, null)
/* %6 */ 'ORDER BY ' || NULLIF(
concat(
msar.get_score_expr(tab_id, search_) || ' DESC, ',
msar.build_total_order_expr(tab_id, null)
),
''
),
/* %7 */ msar.build_record_summary_query_for_table(
tab_id,
Expand Down Expand Up @@ -5380,12 +5415,11 @@ BEGIN
EXECUTE format(
$q$
WITH insert_cte AS (%1$s RETURNING %2$s)
SELECT msar.format_data(%3$I)::text
SELECT *
FROM insert_cte
$q$,
/* %1 */ msar.build_single_insert_expr(tab_id, rec_def),
/* %2 */ msar.build_selectable_column_expr(tab_id),
/* %3 */ msar.get_pk_column(tab_id)
/* %2 */ msar.get_column_name(tab_id, msar.get_pk_column(tab_id))
) INTO rec_created_id;
rec_created := msar.get_record_from_table(
tab_id,
Expand Down Expand Up @@ -5443,8 +5477,8 @@ DECLARE
BEGIN
EXECUTE format(
$p$
WITH update_cte AS (%1$s %2$s RETURNING %3$s)
SELECT msar.format_data(%4$I)::text FROM update_cte
WITH update_cte AS (%1$s %2$s RETURNING %3$I)
SELECT * FROM update_cte
$p$,
msar.build_update_expr(tab_id, rec_def),
msar.build_where_clause(
Expand All @@ -5455,8 +5489,7 @@ BEGIN
)
)
),
msar.build_selectable_column_expr(tab_id),
msar.get_pk_column(tab_id)
msar.get_column_name(tab_id, msar.get_pk_column(tab_id))
) INTO rec_modified_id;
rec_modified := msar.get_record_from_table(
tab_id,
Expand Down
4 changes: 4 additions & 0 deletions db/sql/show_functions.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Print all Mathesar functions to the console for easy grepping

docker exec -it mathesar_dev_db bash -c "PAGER=cat psql -U mathesar --pset footer=off -qAtz -c $'SELECT DISTINCT routine_schema || \'.\' || routine_name as f FROM information_schema.routines WHERE routine_schema IN (\'msar\', \'__msar\') ORDER BY f;'"

Loading

0 comments on commit 28229a8

Please sign in to comment.