Skip to content

Commit

Permalink
Add plpgsql stored proc to compare debian versions
Browse files Browse the repository at this point in the history
  • Loading branch information
Matthias Dellweg authored and m-bucher committed Jul 1, 2019
1 parent f5108d0 commit 091f489
Showing 1 changed file with 125 additions and 0 deletions.
125 changes: 125 additions & 0 deletions db/migrate/20180601160100_add_deb_version_cmp_function_to_db.rb
@@ -0,0 +1,125 @@
class AddDebVersionCmpFunctionToDb < ActiveRecord::Migration[4.2]
# Implementation of version compare for debian packages
# Reference: http://man7.org/linux/man-pages/man5/deb-version.5.html
def self.up
unless connection.adapter_name.downcase.include?('sqlite')
execute "
CREATE OR REPLACE FUNCTION deb_version_cmp_num(_left text, _right text) RETURNS integer AS $$
DECLARE
lint integer := 0;
rint integer := 0;
BEGIN
IF _left != '' THEN
lint := _left AS integer;
END IF;
IF _right != '' THEN
rint := _right AS integer;
END IF;
IF lint < rint THEN
RETURN -1;
ELSEIF lint > rint THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END;
$$ IMMUTABLE STRICT LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION deb_version_cmp_al(_left text, _right text)
RETURNS integer
AS $$
DECLARE
lpair text ARRAY[2];
rpair text ARRAY[2];
BEGIN
lpair := ARRAY['', _left];
rpair := ARRAY['', _right];
LOOP
IF lpair[2] = '' AND rpair[2] = '' THEN
return 0;
END IF;
lpair := regexp_matches(lpair[2], '(.?)(.*)');
rpair := regexp_matches(rpair[2], '(.?)(.*)');
IF lpair[1] = rpair[1] THEN
CONTINUE;
END IF;
IF lpair[1] = '~' THEN
RETURN -1;
END IF;
IF rpair[1] = '~' THEN
RETURN 1;
END IF;
IF lpair[1] = '' THEN
RETURN -1;
END IF;
IF rpair[1] = '' THEN
RETURN 1;
END IF;
IF lpair[1] SIMILAR TO '[a-zA-Z]' THEN
IF rpair[1] SIMILAR TO '[a-zA-Z]' AND ascii(lpair[1]) > ascii(rpair[1]) THEN
RETURN 1;
END IF;
RETURN -1;
END IF;
IF rpair[1] SIMILAR TO '[a-zA-Z]' THEN
RETURN 1;
END IF;
IF ascii(lpair[1]) < ascii(rpair[1]) THEN
RETURN -1;
END IF;
RETURN 1;
END LOOP;
END;
$$ IMMUTABLE STRICT LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION deb_version_cmp(_left text, _right text)
RETURNS integer
AS $$
DECLARE
lpair text ARRAY[2];
rpair text ARRAY[2];
res integer;
BEGIN
lpair := ARRAY['', _left];
rpair := ARRAY['', _right];
LOOP
IF lpair[2] = '' AND rpair[2] = '' THEN
return 0;
END IF;
lpair := regexp_matches(lpair[2], '([^\\d]*)(.*)');
rpair := regexp_matches(rpair[2], '([^\\d]*)(.*)');
res := deb_version_cmp_al(lpair[1], rpair[1]);
IF res != 0 THEN
RETURN res;
END IF;
lpair := regexp_matches(lpair[2], '(\\d*)(.*)');
rpair := regexp_matches(rpair[2], '(\\d*)(.*)');
res := deb_version_cmp_num(lpair[1], rpair[1]);
IF res != 0 THEN
RETURN res;
END IF;
END LOOP;
END
$$ IMMUTABLE STRICT LANGUAGE plpgsql;
"
end
end

def self.down
unless connection.adapter_name.downcase.include?('sqlite')
execute "
DROP FUNCTION deb_version_cmp(text, text) CASCADE;
DROP FUNCTION deb_version_cmp_al(text, text) CASCADE;
DROP FUNCTION deb_version_cmp_num(text, text) CASCADE;
"
end
end
end

0 comments on commit 091f489

Please sign in to comment.