From d0b9b43d9f935f1f0c18b22b72284e31d182424a Mon Sep 17 00:00:00 2001 From: Jens Reimann Date: Mon, 2 Sep 2024 17:05:20 +0200 Subject: [PATCH] chore: mark fns a "immutable parallel safe" --- migration/src/lib.rs | 2 + migration/src/m0000580_mark_fns.rs | 153 ++++++++++++++++++ .../src/m0000580_mark_fns/is_numeric.sql | 10 ++ .../rpmver_version_matches.sql | 53 ++++++ .../src/m0000580_mark_fns/semver_cmp.sql | 128 +++++++++++++++ migration/src/m0000580_mark_fns/semver_eq.sql | 12 ++ migration/src/m0000580_mark_fns/semver_gt.sql | 12 ++ .../src/m0000580_mark_fns/semver_gte.sql | 12 ++ migration/src/m0000580_mark_fns/semver_lt.sql | 12 ++ .../src/m0000580_mark_fns/semver_lte.sql | 12 ++ .../semver_version_matches.sql | 53 ++++++ 11 files changed, 459 insertions(+) create mode 100644 migration/src/m0000580_mark_fns.rs create mode 100644 migration/src/m0000580_mark_fns/is_numeric.sql create mode 100644 migration/src/m0000580_mark_fns/rpmver_version_matches.sql create mode 100644 migration/src/m0000580_mark_fns/semver_cmp.sql create mode 100644 migration/src/m0000580_mark_fns/semver_eq.sql create mode 100644 migration/src/m0000580_mark_fns/semver_gt.sql create mode 100644 migration/src/m0000580_mark_fns/semver_gte.sql create mode 100644 migration/src/m0000580_mark_fns/semver_lt.sql create mode 100644 migration/src/m0000580_mark_fns/semver_lte.sql create mode 100644 migration/src/m0000580_mark_fns/semver_version_matches.sql diff --git a/migration/src/lib.rs b/migration/src/lib.rs index 93f43de5c..592a23994 100644 --- a/migration/src/lib.rs +++ b/migration/src/lib.rs @@ -70,6 +70,7 @@ mod m0000560_alter_vulnerability_cwe_column; mod m0000565_alter_advisory_vulnerability_cwe_column; mod m0000570_add_import_progress; mod m0000575_create_weakness; +mod m0000580_mark_fns; pub struct Migrator; @@ -147,6 +148,7 @@ impl MigratorTrait for Migrator { Box::new(m0000565_alter_advisory_vulnerability_cwe_column::Migration), Box::new(m0000570_add_import_progress::Migration), Box::new(m0000575_create_weakness::Migration), + Box::new(m0000580_mark_fns::Migration), ] } } diff --git a/migration/src/m0000580_mark_fns.rs b/migration/src/m0000580_mark_fns.rs new file mode 100644 index 000000000..1ebac3abf --- /dev/null +++ b/migration/src/m0000580_mark_fns.rs @@ -0,0 +1,153 @@ +use sea_orm_migration::prelude::*; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .get_connection() + .execute_unprepared(include_str!("m0000580_mark_fns/rpmver_version_matches.sql")) + .await + .map(|_| ())?; + + manager + .get_connection() + .execute_unprepared(include_str!("m0000580_mark_fns/semver_cmp.sql")) + .await + .map(|_| ())?; + + manager + .get_connection() + .execute_unprepared(include_str!("m0000580_mark_fns/semver_version_matches.sql")) + .await + .map(|_| ())?; + + manager + .get_connection() + .execute_unprepared(include_str!("m0000580_mark_fns/semver_version_matches.sql")) + .await + .map(|_| ())?; + + manager + .get_connection() + .execute_unprepared(include_str!("m0000580_mark_fns/is_numeric.sql")) + .await + .map(|_| ())?; + + manager + .get_connection() + .execute_unprepared(include_str!("m0000580_mark_fns/is_numeric.sql")) + .await + .map(|_| ())?; + + manager + .get_connection() + .execute_unprepared(include_str!("m0000580_mark_fns/semver_eq.sql")) + .await + .map(|_| ())?; + + manager + .get_connection() + .execute_unprepared(include_str!("m0000580_mark_fns/semver_gt.sql")) + .await + .map(|_| ())?; + + manager + .get_connection() + .execute_unprepared(include_str!("m0000580_mark_fns/semver_gte.sql")) + .await + .map(|_| ())?; + + manager + .get_connection() + .execute_unprepared(include_str!("m0000580_mark_fns/semver_lt.sql")) + .await + .map(|_| ())?; + + manager + .get_connection() + .execute_unprepared(include_str!("m0000580_mark_fns/semver_lte.sql")) + .await + .map(|_| ())?; + + Ok(()) + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .get_connection() + .execute_unprepared(include_str!( + "m0000345_create_version_comparison_fns/semver_lte.sql" + )) + .await + .map(|_| ())?; + + manager + .get_connection() + .execute_unprepared(include_str!( + "m0000345_create_version_comparison_fns/semver_lt.sql" + )) + .await + .map(|_| ())?; + + manager + .get_connection() + .execute_unprepared(include_str!( + "m0000345_create_version_comparison_fns/semver_gte.sql" + )) + .await + .map(|_| ())?; + + manager + .get_connection() + .execute_unprepared(include_str!( + "m0000345_create_version_comparison_fns/semver_gt.sql" + )) + .await + .map(|_| ())?; + + manager + .get_connection() + .execute_unprepared(include_str!( + "m0000345_create_version_comparison_fns/semver_eq.sql" + )) + .await + .map(|_| ())?; + + manager + .get_connection() + .execute_unprepared(include_str!( + "m0000345_create_version_comparison_fns/is_numeric.sql" + )) + .await + .map(|_| ())?; + + manager + .get_connection() + .execute_unprepared(include_str!( + "m0000475_improve_version_comparison_fns/semver_version_matches.sql" + )) + .await + .map(|_| ())?; + + manager + .get_connection() + .execute_unprepared(include_str!( + "m0000475_improve_version_comparison_fns/semver_cmp.sql" + )) + .await + .map(|_| ())?; + + manager + .get_connection() + .execute_unprepared(include_str!( + "m0000480_create_rpmver_cmp_fns/rpmver_version_matches.sql" + )) + .await + .map(|_| ())?; + + Ok(()) + } +} diff --git a/migration/src/m0000580_mark_fns/is_numeric.sql b/migration/src/m0000580_mark_fns/is_numeric.sql new file mode 100644 index 000000000..2fafe4865 --- /dev/null +++ b/migration/src/m0000580_mark_fns/is_numeric.sql @@ -0,0 +1,10 @@ +create or replace function is_numeric(str text) + returns bool +as +$$ +begin + return str ~ e'^[0-9]+$'; +end + +$$ + language 'plpgsql' immutable parallel safe; diff --git a/migration/src/m0000580_mark_fns/rpmver_version_matches.sql b/migration/src/m0000580_mark_fns/rpmver_version_matches.sql new file mode 100644 index 000000000..cf2702587 --- /dev/null +++ b/migration/src/m0000580_mark_fns/rpmver_version_matches.sql @@ -0,0 +1,53 @@ + +create or replace function rpmver_version_matches(version_p text, range_p version_range) + returns bool +as +$$ +declare + low_end integer; + high_end integer; +begin + if range_p.low_version is not null then + low_end := rpmver_cmp(version_p, range_p.low_version); + end if; + + if low_end is not null then + if range_p.low_inclusive then + if low_end < 0 then + return false; + end if; + else + if low_end <= 0 then + return false; + end if; + end if; + + end if; + + + if range_p.high_version is not null then + high_end := rpmver_cmp(version_p, range_p.high_version); + end if; + + if high_end is not null then + if range_p.high_inclusive then + if high_end > 0 then + return false; + end if; + else + if high_end >= 0 then + return false; + end if; + end if; + end if; + + if low_end is null and high_end is null then + return false; + end if; + + return true; + +end +$$ + language 'plpgsql' immutable parallel safe; + diff --git a/migration/src/m0000580_mark_fns/semver_cmp.sql b/migration/src/m0000580_mark_fns/semver_cmp.sql new file mode 100644 index 000000000..76092596f --- /dev/null +++ b/migration/src/m0000580_mark_fns/semver_cmp.sql @@ -0,0 +1,128 @@ + +create or replace function semver_cmp(left_p text, right_p text) + returns integer +as +$$ +declare + left_parts text[]; + right_parts text[]; + + left_major bigint; + left_minor bigint; + left_patch bigint; + left_pre text; + left_build text; + + right_major bigint; + right_minor bigint; + right_patch bigint; + right_pre text; + right_build text; + + left_numeric bool; + right_numeric bool; + + cur integer; + +begin + + raise notice 'semver_cmp % %', left_p, right_p; + + left_parts = regexp_split_to_array(left_p, E'\\+'); + left_build = left_parts[2]; + + left_parts = regexp_split_to_array(left_parts[1], E'-'); + left_pre = left_parts[2]; + + left_parts = regexp_split_to_array(left_parts[1], E'\\.'); + left_major = left_parts[1]::decimal; + left_minor = left_parts[2]::decimal; + left_patch = left_parts[3]::decimal; + + right_parts = regexp_split_to_array(right_p, E'\\+'); + right_build = right_parts[2]; + + right_parts = regexp_split_to_array(right_parts[1], E'-'); + right_pre = right_parts[2]; + + right_parts = regexp_split_to_array(right_parts[1], E'\\.'); + right_major = right_parts[1]::decimal; + right_minor = right_parts[2]::decimal; + right_patch = right_parts[3]::decimal; + + if left_major > right_major then + return +1; + elsif left_major < right_major then + return -1; + end if; + + if left_minor > right_minor then + return +1; + elsif left_minor < right_minor then + return -1; + end if; + + if left_patch > right_patch then + return +1; + elsif left_patch < right_patch then + return -1; + end if; + + if left_pre is null and right_pre is not null then + return +1; + elsif left_pre is not null and right_pre is null then + return -1; + elsif left_pre is not null and right_pre is not null then + left_parts = regexp_split_to_array(left_pre, E'\\.'); + right_parts = regexp_split_to_array(right_pre, E'\\.'); + -- do the hard work + + cur := 0; + loop + cur := cur + 1; + + left_pre := left_parts[cur]; + right_pre := right_parts[cur]; + + if left_pre is null and right_pre is null then + return 0; + end if; + + if left_pre is null and right_pre is not null then + return -1; + elsif left_pre is not null and right_pre is null then + return +1; + end if; + + left_numeric := is_numeric(left_pre); + right_numeric := is_numeric(right_pre); + + if left_numeric and right_numeric then + if left_pre::bigint < right_pre::bigint then + return -1; + elsif left_pre::bigint > right_pre::bigint then + return +1; + end if; + else + if left_pre < right_pre then + return -1; + elsif left_pre > right_pre then + return +1; + end if; + end if; + + if cur > 10 then + exit; + end if; + end loop; + else + return 0; + end if; + + return null; +exception + when others then + return null; +end +$$ + language 'plpgsql' immutable parallel safe; diff --git a/migration/src/m0000580_mark_fns/semver_eq.sql b/migration/src/m0000580_mark_fns/semver_eq.sql new file mode 100644 index 000000000..87ad2ea41 --- /dev/null +++ b/migration/src/m0000580_mark_fns/semver_eq.sql @@ -0,0 +1,12 @@ +create or replace function semver_eq(left_p text, right_p text) + returns bool +as +$$ +declare + cmp integer; +begin + cmp := semver_cmp(left_p, right_p); + return cmp = 0; +end +$$ + language 'plpgsql'; diff --git a/migration/src/m0000580_mark_fns/semver_gt.sql b/migration/src/m0000580_mark_fns/semver_gt.sql new file mode 100644 index 000000000..a6a8f57f0 --- /dev/null +++ b/migration/src/m0000580_mark_fns/semver_gt.sql @@ -0,0 +1,12 @@ +create or replace function semver_gt(left_p text, right_p text) + returns bool +as +$$ +declare + cmp integer; +begin + cmp := semver_cmp(left_p, right_p); + return cmp > 0; +end +$$ + language 'plpgsql' immutable parallel safe; diff --git a/migration/src/m0000580_mark_fns/semver_gte.sql b/migration/src/m0000580_mark_fns/semver_gte.sql new file mode 100644 index 000000000..8cf326526 --- /dev/null +++ b/migration/src/m0000580_mark_fns/semver_gte.sql @@ -0,0 +1,12 @@ +create or replace function semver_gte(left_p text, right_p text) + returns bool +as +$$ +declare + cmp integer; +begin + cmp := semver_cmp(left_p, right_p); + return cmp >= 0; +end +$$ + language 'plpgsql' immutable parallel safe; diff --git a/migration/src/m0000580_mark_fns/semver_lt.sql b/migration/src/m0000580_mark_fns/semver_lt.sql new file mode 100644 index 000000000..cfce523e7 --- /dev/null +++ b/migration/src/m0000580_mark_fns/semver_lt.sql @@ -0,0 +1,12 @@ +create or replace function semver_lt(left_p text, right_p text) + returns bool +as +$$ +declare + cmp integer; +begin + cmp := semver_cmp(left_p, right_p); + return cmp < 0; +end +$$ + language 'plpgsql' immutable parallel safe; diff --git a/migration/src/m0000580_mark_fns/semver_lte.sql b/migration/src/m0000580_mark_fns/semver_lte.sql new file mode 100644 index 000000000..9af41c8bd --- /dev/null +++ b/migration/src/m0000580_mark_fns/semver_lte.sql @@ -0,0 +1,12 @@ +create or replace function semver_lte(left_p text, right_p text) + returns bool +as +$$ +declare + cmp integer; +begin + cmp := semver_cmp(left_p, right_p); + return cmp <= 0; +end +$$ + language 'plpgsql' immutable parallel safe; diff --git a/migration/src/m0000580_mark_fns/semver_version_matches.sql b/migration/src/m0000580_mark_fns/semver_version_matches.sql new file mode 100644 index 000000000..04845813c --- /dev/null +++ b/migration/src/m0000580_mark_fns/semver_version_matches.sql @@ -0,0 +1,53 @@ + +create or replace function semver_version_matches(version_p text, range_p version_range) + returns bool +as +$$ +declare + low_end integer; + high_end integer; +begin + if range_p.low_version is not null then + low_end := semver_cmp(version_p, range_p.low_version); + end if; + + if low_end is not null then + if range_p.low_inclusive then + if low_end < 0 then + return false; + end if; + else + if low_end <= 0 then + return false; + end if; + end if; + + end if; + + + if range_p.high_version is not null then + high_end := semver_cmp(version_p, range_p.high_version); + end if; + + if high_end is not null then + if range_p.high_inclusive then + if high_end > 0 then + return false; + end if; + else + if high_end >= 0 then + return false; + end if; + end if; + end if; + + if low_end is null and high_end is null then + return false; + end if; + + return true; + +end +$$ + language 'plpgsql' immutable parallel safe; +