2016-03-25 08:05:54 +03:00
|
|
|
-- ---------------------------------------------------------
|
2016-03-22 04:28:08 +03:00
|
|
|
-- persistent values
|
|
|
|
|
2016-03-31 08:38:35 +03:00
|
|
|
-- list of types for type_id
|
|
|
|
-- 0: nil
|
|
|
|
-- 1: false
|
|
|
|
-- 2: true
|
|
|
|
-- 3: integer
|
|
|
|
-- 4: float
|
|
|
|
-- 5: string
|
|
|
|
-- 6: keyword (not used, uses prefixed string)
|
|
|
|
-- 7: symbol
|
|
|
|
-- 8: list
|
|
|
|
-- 9: vector
|
|
|
|
-- 10: hashmap
|
|
|
|
-- 11: function
|
|
|
|
-- 12: malfunc
|
|
|
|
-- 13: atom
|
|
|
|
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE SCHEMA types
|
|
|
|
|
|
|
|
CREATE SEQUENCE value_id_seq START WITH 3 -- skip nil, false, true
|
|
|
|
|
|
|
|
CREATE TABLE value (
|
|
|
|
value_id integer NOT NULL DEFAULT nextval('value_id_seq'),
|
|
|
|
type_id integer NOT NULL,
|
|
|
|
val_int bigint, -- set for integers
|
|
|
|
val_string varchar, -- set for strings, keywords, symbols,
|
|
|
|
-- and native functions (function name)
|
|
|
|
val_seq integer[], -- set for lists and vectors
|
|
|
|
val_hash hstore, -- set for hash-maps
|
|
|
|
ast_id integer, -- set for malfunc
|
|
|
|
params_id integer, -- set for malfunc
|
|
|
|
env_id integer, -- set for malfunc
|
|
|
|
macro boolean, -- set for malfunc
|
|
|
|
meta_id integer -- can be set for any collection
|
|
|
|
);
|
|
|
|
|
|
|
|
ALTER TABLE types.value ADD CONSTRAINT pk_value_id
|
2016-03-22 04:28:08 +03:00
|
|
|
PRIMARY KEY (value_id);
|
|
|
|
-- drop sequence when table dropped
|
2016-05-03 07:02:29 +03:00
|
|
|
ALTER SEQUENCE types.value_id_seq OWNED BY types.value.value_id;
|
|
|
|
ALTER TABLE types.value ADD CONSTRAINT fk_meta_id
|
|
|
|
FOREIGN KEY (meta_id) REFERENCES types.value(value_id);
|
|
|
|
ALTER TABLE types.value ADD CONSTRAINT fk_params_id
|
|
|
|
FOREIGN KEY (params_id) REFERENCES types.value(value_id);
|
2016-03-22 04:28:08 +03:00
|
|
|
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE INDEX ON types.value (value_id, type_id);
|
2016-03-26 09:44:43 +03:00
|
|
|
|
2016-05-03 07:02:29 +03:00
|
|
|
INSERT INTO types.value (value_id, type_id) VALUES (0, 0); -- nil
|
|
|
|
INSERT INTO types.value (value_id, type_id) VALUES (1, 1); -- false
|
|
|
|
INSERT INTO types.value (value_id, type_id) VALUES (2, 2); -- true
|
2016-03-22 04:28:08 +03:00
|
|
|
|
|
|
|
|
2016-03-22 08:53:31 +03:00
|
|
|
-- ---------------------------------------------------------
|
|
|
|
-- general functions
|
|
|
|
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._wraptf(val boolean) RETURNS integer AS $$
|
2016-03-22 08:53:31 +03:00
|
|
|
BEGIN
|
|
|
|
IF val THEN
|
|
|
|
RETURN 2;
|
|
|
|
ELSE
|
|
|
|
RETURN 1;
|
|
|
|
END IF;
|
2016-03-31 08:38:35 +03:00
|
|
|
END; $$ LANGUAGE plpgsql IMMUTABLE;
|
2016-03-22 08:53:31 +03:00
|
|
|
|
2016-03-26 07:11:40 +03:00
|
|
|
-- pun both NULL and false to false
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._tf(val boolean) RETURNS boolean AS $$
|
2016-03-26 07:11:40 +03:00
|
|
|
BEGIN
|
|
|
|
IF val IS NULL OR val = false THEN
|
|
|
|
RETURN false;
|
|
|
|
END IF;
|
|
|
|
RETURN true;
|
2016-03-31 08:38:35 +03:00
|
|
|
END; $$ LANGUAGE plpgsql IMMUTABLE;
|
2016-03-26 07:11:40 +03:00
|
|
|
|
|
|
|
-- pun both NULL and 0 to false
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._tf(val integer) RETURNS boolean AS $$
|
2016-03-26 07:11:40 +03:00
|
|
|
BEGIN
|
|
|
|
IF val IS NULL OR val = 0 THEN
|
|
|
|
RETURN false;
|
|
|
|
END IF;
|
|
|
|
RETURN true;
|
2016-03-31 08:38:35 +03:00
|
|
|
END; $$ LANGUAGE plpgsql IMMUTABLE;
|
2016-03-26 07:11:40 +03:00
|
|
|
|
|
|
|
-- return the type of the given value_id
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._type(obj integer) RETURNS integer AS $$
|
2016-03-26 07:11:40 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
RETURN (SELECT type_id FROM types.value WHERE value_id = obj);
|
2016-03-26 07:11:40 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._equal_Q(a integer, b integer) RETURNS boolean AS $$
|
2016-03-22 08:53:31 +03:00
|
|
|
DECLARE
|
|
|
|
atype integer;
|
|
|
|
btype integer;
|
2016-03-31 07:58:03 +03:00
|
|
|
anum bigint;
|
|
|
|
bnum bigint;
|
2016-03-26 07:11:40 +03:00
|
|
|
avid integer;
|
|
|
|
bvid integer;
|
2016-03-31 07:58:03 +03:00
|
|
|
aseq integer[];
|
|
|
|
bseq integer[];
|
|
|
|
ahash hstore;
|
|
|
|
bhash hstore;
|
|
|
|
kv RECORD;
|
2016-03-22 08:53:31 +03:00
|
|
|
i integer;
|
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
atype := types._type(a);
|
|
|
|
btype := types._type(b);
|
|
|
|
IF NOT ((atype = btype) OR
|
|
|
|
(types._sequential_Q(a) AND types._sequential_Q(b))) THEN
|
2016-03-22 08:53:31 +03:00
|
|
|
RETURN false;
|
|
|
|
END IF;
|
|
|
|
CASE
|
|
|
|
WHEN atype = 3 THEN -- integer
|
2016-05-03 07:02:29 +03:00
|
|
|
SELECT val_int FROM types.value INTO anum WHERE value_id = a;
|
|
|
|
SELECT val_int FROM types.value INTO bnum WHERE value_id = b;
|
2016-03-31 07:58:03 +03:00
|
|
|
RETURN anum = bnum;
|
2016-03-22 08:53:31 +03:00
|
|
|
WHEN atype = 5 OR atype = 7 THEN -- string/symbol
|
2016-05-03 07:02:29 +03:00
|
|
|
RETURN types._valueToString(a) = types._valueToString(b);
|
2016-03-31 07:58:03 +03:00
|
|
|
WHEN atype IN (8, 9) THEN -- list/vector
|
2016-05-03 07:02:29 +03:00
|
|
|
IF types._count(a) <> types._count(b) THEN
|
2016-03-22 08:53:31 +03:00
|
|
|
RETURN false;
|
|
|
|
END IF;
|
2016-05-03 07:02:29 +03:00
|
|
|
SELECT val_seq INTO aseq FROM types.value WHERE value_id = a;
|
|
|
|
SELECT val_seq INTO bseq FROM types.value WHERE value_id = b;
|
|
|
|
FOR i IN 1 .. types._count(a)
|
2016-03-31 07:58:03 +03:00
|
|
|
LOOP
|
2016-05-03 07:02:29 +03:00
|
|
|
IF NOT types._equal_Q(aseq[i], bseq[i]) THEN
|
2016-03-31 07:58:03 +03:00
|
|
|
return false;
|
|
|
|
END IF;
|
|
|
|
END LOOP;
|
|
|
|
RETURN true;
|
|
|
|
WHEN atype = 10 THEN -- hash-map
|
2016-05-03 07:02:29 +03:00
|
|
|
SELECT val_hash INTO ahash FROM types.value WHERE value_id = a;
|
|
|
|
SELECT val_hash INTO bhash FROM types.value WHERE value_id = b;
|
2016-03-31 07:58:03 +03:00
|
|
|
IF array_length(akeys(ahash), 1) <> array_length(akeys(bhash), 1) THEN
|
|
|
|
RETURN false;
|
2016-03-26 07:11:40 +03:00
|
|
|
END IF;
|
2016-03-31 07:58:03 +03:00
|
|
|
FOR kv IN SELECT * FROM each(ahash) LOOP
|
|
|
|
avid := CAST((ahash -> kv.key) AS integer);
|
|
|
|
bvid := CAST((bhash -> kv.key) AS integer);
|
2016-05-03 07:02:29 +03:00
|
|
|
IF bvid IS NULL OR NOT types._equal_Q(avid, bvid) THEN
|
2016-03-31 07:58:03 +03:00
|
|
|
return false;
|
|
|
|
END IF;
|
|
|
|
END LOOP;
|
2016-03-22 08:53:31 +03:00
|
|
|
RETURN true;
|
|
|
|
ELSE
|
|
|
|
RETURN a = b;
|
|
|
|
END CASE;
|
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
|
2016-03-25 05:10:10 +03:00
|
|
|
-- _clone:
|
|
|
|
-- take a value_id of a collection
|
|
|
|
-- returns a new value_id of a cloned collection
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._clone(id integer) RETURNS integer AS $$
|
2016-03-25 05:10:10 +03:00
|
|
|
DECLARE
|
|
|
|
result integer;
|
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
INSERT INTO types.value (type_id,val_int,val_string,val_seq,val_hash,
|
2016-03-31 08:38:35 +03:00
|
|
|
ast_id,params_id,env_id,meta_id)
|
2016-03-31 07:58:03 +03:00
|
|
|
(SELECT type_id,val_int,val_string,val_seq,val_hash,
|
2016-03-31 08:38:35 +03:00
|
|
|
ast_id,params_id,env_id,meta_id
|
2016-05-03 07:02:29 +03:00
|
|
|
FROM types.value
|
2016-03-31 07:58:03 +03:00
|
|
|
WHERE value_id = id)
|
|
|
|
RETURNING value_id INTO result;
|
2016-03-25 05:10:10 +03:00
|
|
|
RETURN result;
|
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
|
2016-03-22 04:28:08 +03:00
|
|
|
-- ---------------------------------------------------------
|
|
|
|
-- scalar functions
|
|
|
|
|
|
|
|
|
2016-03-22 08:53:31 +03:00
|
|
|
-- _nil_Q:
|
|
|
|
-- takes a value_id
|
|
|
|
-- returns the whether value_id is nil
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._nil_Q(id integer) RETURNS boolean AS $$
|
2016-03-22 08:53:31 +03:00
|
|
|
BEGIN
|
|
|
|
RETURN id = 0;
|
2016-03-31 08:38:35 +03:00
|
|
|
END; $$ LANGUAGE plpgsql IMMUTABLE;
|
2016-03-22 08:53:31 +03:00
|
|
|
|
2016-03-26 07:11:40 +03:00
|
|
|
-- _true_Q:
|
|
|
|
-- takes a value_id
|
|
|
|
-- returns the whether value_id is true
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._true_Q(id integer) RETURNS boolean AS $$
|
2016-03-26 07:11:40 +03:00
|
|
|
BEGIN
|
|
|
|
RETURN id = 2;
|
2016-03-31 08:38:35 +03:00
|
|
|
END; $$ LANGUAGE plpgsql IMMUTABLE;
|
2016-03-26 07:11:40 +03:00
|
|
|
|
2016-03-22 08:53:31 +03:00
|
|
|
-- _false_Q:
|
|
|
|
-- takes a value_id
|
|
|
|
-- returns the whether value_id is false
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._false_Q(id integer) RETURNS boolean AS $$
|
2016-03-22 08:53:31 +03:00
|
|
|
BEGIN
|
|
|
|
RETURN id = 1;
|
2016-03-31 08:38:35 +03:00
|
|
|
END; $$ LANGUAGE plpgsql IMMUTABLE;
|
2016-03-22 08:53:31 +03:00
|
|
|
|
2016-03-26 07:11:40 +03:00
|
|
|
-- _string_Q:
|
2016-03-22 08:53:31 +03:00
|
|
|
-- takes a value_id
|
2016-03-26 07:11:40 +03:00
|
|
|
-- returns the whether value_id is string type
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._string_Q(id integer) RETURNS boolean AS $$
|
2016-03-22 08:53:31 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
IF (SELECT 1 FROM types.value WHERE type_id = 5 AND value_id = id) THEN
|
|
|
|
RETURN NOT types._keyword_Q(id);
|
2016-03-26 07:11:40 +03:00
|
|
|
END IF;
|
|
|
|
RETURN false;
|
2016-03-22 08:53:31 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
2016-03-26 07:11:40 +03:00
|
|
|
|
|
|
|
-- _valueToString:
|
2016-03-22 08:53:31 +03:00
|
|
|
-- takes a value_id for a string
|
|
|
|
-- returns the varchar value of the string
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._valueToString(sid integer) RETURNS varchar AS $$
|
2016-03-22 08:53:31 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
RETURN (SELECT val_string FROM types.value WHERE value_id = sid);
|
2016-03-22 08:53:31 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
-- _stringish:
|
2016-03-22 04:28:08 +03:00
|
|
|
-- takes a varchar string
|
2016-03-22 08:53:31 +03:00
|
|
|
-- returns the value_id of a stringish type (string, symbol, keyword)
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._stringish(str varchar, type integer) RETURNS integer AS $$
|
2016-03-22 04:28:08 +03:00
|
|
|
DECLARE
|
|
|
|
result integer;
|
|
|
|
BEGIN
|
2016-03-22 08:53:31 +03:00
|
|
|
-- TODO: share string data between string types
|
|
|
|
-- lookup if it exists
|
2016-05-03 07:02:29 +03:00
|
|
|
SELECT value_id FROM types.value INTO result
|
2016-03-25 08:05:54 +03:00
|
|
|
WHERE val_string = str AND type_id = type;
|
2016-03-22 08:53:31 +03:00
|
|
|
IF result IS NULL THEN
|
2016-03-25 08:05:54 +03:00
|
|
|
-- Create string entry
|
2016-05-03 07:02:29 +03:00
|
|
|
INSERT INTO types.value (type_id, val_string)
|
2016-03-25 08:05:54 +03:00
|
|
|
VALUES (type, str)
|
2016-03-22 08:53:31 +03:00
|
|
|
RETURNING value_id INTO result;
|
|
|
|
END IF;
|
2016-03-22 04:28:08 +03:00
|
|
|
RETURN result;
|
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
2016-03-25 05:10:10 +03:00
|
|
|
-- _stringv:
|
2016-03-22 08:53:31 +03:00
|
|
|
-- takes a varchar string
|
|
|
|
-- returns the value_id of a string (new or existing)
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._stringv(str varchar) RETURNS integer AS $$
|
2016-03-22 08:53:31 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
RETURN types._stringish(str, 5);
|
2016-03-22 08:53:31 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
2016-03-25 08:05:54 +03:00
|
|
|
-- _keywordv:
|
|
|
|
-- takes a varchar string
|
|
|
|
-- returns the value_id of a keyword (new or existing)
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._keywordv(name varchar) RETURNS integer AS $$
|
2016-03-25 08:05:54 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
RETURN types._stringish(chr(CAST(x'7f' AS integer)) || name, 5);
|
2016-03-25 08:05:54 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
-- _keyword_Q:
|
|
|
|
-- takes a value_id
|
|
|
|
-- returns the whether value_id is keyword type
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._keyword_Q(id integer) RETURNS boolean AS $$
|
2016-03-25 08:05:54 +03:00
|
|
|
DECLARE
|
|
|
|
str varchar;
|
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
IF (SELECT 1 FROM types.value WHERE type_id = 5 AND value_id = id) THEN
|
|
|
|
str := types._valueToString(id);
|
2016-03-25 08:05:54 +03:00
|
|
|
IF char_length(str) > 0 AND
|
2016-03-31 09:04:15 +03:00
|
|
|
chr(CAST(x'7f' AS integer)) = substring(str FROM 1 FOR 1) THEN
|
2016-03-25 08:05:54 +03:00
|
|
|
RETURN true;
|
|
|
|
END IF;
|
|
|
|
END IF;
|
|
|
|
RETURN false;
|
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
2016-03-25 05:10:10 +03:00
|
|
|
-- _symbolv:
|
2016-03-22 08:53:31 +03:00
|
|
|
-- takes a varchar string
|
|
|
|
-- returns the value_id of a symbol (new or existing)
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._symbolv(name varchar) RETURNS integer AS $$
|
2016-03-22 08:53:31 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
RETURN types._stringish(name, 7);
|
2016-03-22 08:53:31 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
2016-03-22 04:28:08 +03:00
|
|
|
-- _symbol_Q:
|
|
|
|
-- takes a value_id
|
|
|
|
-- returns the whether value_id is symbol type
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._symbol_Q(id integer) RETURNS boolean AS $$
|
2016-03-22 04:28:08 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
RETURN types._tf((SELECT 1 FROM types.value
|
|
|
|
WHERE type_id = 7 AND value_id = id));
|
2016-03-22 04:28:08 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
2016-03-22 08:53:31 +03:00
|
|
|
-- _numToValue:
|
2016-03-26 09:44:43 +03:00
|
|
|
-- takes an bigint number
|
2016-03-22 08:53:31 +03:00
|
|
|
-- returns the value_id for the number
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._numToValue(num bigint) RETURNS integer AS $$
|
2016-03-22 08:53:31 +03:00
|
|
|
DECLARE
|
|
|
|
result integer;
|
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
SELECT value_id FROM types.value INTO result
|
2016-03-26 09:44:43 +03:00
|
|
|
WHERE val_int = num AND type_id = 3;
|
|
|
|
IF result IS NULL THEN
|
|
|
|
-- Create an integer entry
|
2016-05-03 07:02:29 +03:00
|
|
|
INSERT INTO types.value (type_id, val_int)
|
2016-03-26 09:44:43 +03:00
|
|
|
VALUES (3, num)
|
|
|
|
RETURNING value_id INTO result;
|
|
|
|
END IF;
|
2016-03-22 08:53:31 +03:00
|
|
|
RETURN result;
|
|
|
|
END; $$ LANGUAGE plpgsql;
|
2016-03-22 04:28:08 +03:00
|
|
|
|
|
|
|
-- ---------------------------------------------------------
|
|
|
|
-- sequence functions
|
|
|
|
|
2016-03-22 08:53:31 +03:00
|
|
|
-- _sequential_Q:
|
|
|
|
-- return true if obj value_id is a list or vector
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._sequential_Q(obj integer) RETURNS boolean AS $$
|
2016-03-22 08:53:31 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
RETURN types._tf((SELECT 1 FROM types.value
|
2016-03-26 07:11:40 +03:00
|
|
|
WHERE value_id = obj AND (type_id = 8 OR type_id = 9)));
|
2016-03-22 08:53:31 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
2016-03-26 07:11:40 +03:00
|
|
|
-- _collection:
|
2016-03-22 04:28:08 +03:00
|
|
|
-- takes a array of value_id integers
|
2016-03-26 07:11:40 +03:00
|
|
|
-- returns the value_id of a new list (8), vector (9) or hash-map (10)
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._collection(items integer[], type integer) RETURNS integer AS $$
|
2016-03-22 04:28:08 +03:00
|
|
|
DECLARE
|
2016-03-26 09:44:43 +03:00
|
|
|
vid integer;
|
2016-03-22 04:28:08 +03:00
|
|
|
BEGIN
|
2016-03-31 07:58:03 +03:00
|
|
|
IF type IN (8, 9) THEN
|
2016-05-03 07:02:29 +03:00
|
|
|
INSERT INTO types.value (type_id, val_seq)
|
2016-03-31 07:58:03 +03:00
|
|
|
VALUES (type, items)
|
|
|
|
RETURNING value_id INTO vid;
|
|
|
|
ELSIF type = 10 THEN
|
|
|
|
IF (array_length(items, 1) % 2) = 1 THEN
|
|
|
|
RAISE EXCEPTION 'hash-map: odd number of arguments';
|
|
|
|
END IF;
|
2016-05-03 07:02:29 +03:00
|
|
|
INSERT INTO types.value (type_id, val_hash)
|
2016-03-31 07:58:03 +03:00
|
|
|
VALUES (type, hstore(CAST(items AS varchar[])))
|
|
|
|
RETURNING value_id INTO vid;
|
2016-03-22 04:28:08 +03:00
|
|
|
END IF;
|
2016-03-26 09:44:43 +03:00
|
|
|
RETURN vid;
|
2016-03-26 07:11:40 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
|
2016-03-25 05:10:10 +03:00
|
|
|
-- _list:
|
|
|
|
-- takes a array of value_id integers
|
2016-03-22 04:28:08 +03:00
|
|
|
-- returns the value_id of a new list
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._list(items integer[]) RETURNS integer AS $$
|
2016-03-22 04:28:08 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
RETURN types._collection(items, 8);
|
2016-03-22 04:28:08 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
2016-03-25 05:10:10 +03:00
|
|
|
-- _vector:
|
|
|
|
-- takes a array of value_id integers
|
2016-03-22 04:28:08 +03:00
|
|
|
-- returns the value_id of a new list
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._vector(items integer[]) RETURNS integer AS $$
|
2016-03-22 04:28:08 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
RETURN types._collection(items, 9);
|
2016-03-22 04:28:08 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
2016-03-22 08:53:31 +03:00
|
|
|
-- _list_Q:
|
|
|
|
-- return true if obj value_id is a list
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._list_Q(obj integer) RETURNS boolean AS $$
|
2016-03-22 08:53:31 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
RETURN types._tf((SELECT 1 FROM types.value
|
|
|
|
WHERE value_id = obj and type_id = 8));
|
2016-03-22 08:53:31 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
2016-03-25 05:10:10 +03:00
|
|
|
-- _vector_Q:
|
|
|
|
-- return true if obj value_id is a list
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._vector_Q(obj integer) RETURNS boolean AS $$
|
2016-03-25 05:10:10 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
RETURN types._tf((SELECT 1 FROM types.value
|
|
|
|
WHERE value_id = obj and type_id = 9));
|
2016-03-25 05:10:10 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
2016-03-22 08:53:31 +03:00
|
|
|
|
2016-03-25 05:10:10 +03:00
|
|
|
-- _valueToArray:
|
|
|
|
-- takes an value_id referring to a list or vector
|
|
|
|
-- returns an array of the value_ids from the list/vector
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._valueToArray(seq integer) RETURNS integer[] AS $$
|
2016-03-31 07:58:03 +03:00
|
|
|
DECLARE
|
|
|
|
result integer[];
|
2016-03-22 08:53:31 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
result := (SELECT val_seq FROM types.value WHERE value_id = seq);
|
2016-03-31 07:58:03 +03:00
|
|
|
IF result IS NULL THEN
|
|
|
|
result := ARRAY[]::integer[];
|
|
|
|
END IF;
|
|
|
|
RETURN result;
|
2016-03-22 08:53:31 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
2016-03-31 07:58:03 +03:00
|
|
|
-- From: https://wiki.postgresql.org/wiki/Array_reverse
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types.array_reverse(a integer[]) RETURNS integer[] AS $$
|
2016-03-31 07:58:03 +03:00
|
|
|
SELECT ARRAY(
|
|
|
|
SELECT a[i]
|
|
|
|
FROM generate_subscripts(a,1) AS s(i)
|
|
|
|
ORDER BY i DESC
|
|
|
|
);
|
|
|
|
$$ LANGUAGE 'sql' STRICT IMMUTABLE;
|
|
|
|
|
2016-03-22 08:53:31 +03:00
|
|
|
|
2016-03-22 04:28:08 +03:00
|
|
|
-- _nth:
|
|
|
|
-- takes value_id and an index
|
|
|
|
-- returns the value_id of nth element in list/vector
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._nth(seq_id integer, indx integer) RETURNS integer AS $$
|
2016-03-22 04:28:08 +03:00
|
|
|
DECLARE
|
|
|
|
result integer;
|
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
RETURN (SELECT val_seq[indx+1] FROM types.value WHERE value_id = seq_id);
|
2016-03-22 04:28:08 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
-- _first:
|
|
|
|
-- takes value_id
|
|
|
|
-- returns the value_id of first element in list/vector
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._first(seq_id integer) RETURNS integer AS $$
|
2016-03-22 04:28:08 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
RETURN types._nth(seq_id, 0);
|
2016-03-22 04:28:08 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
|
|
|
|
-- _restArray:
|
|
|
|
-- takes value_id
|
|
|
|
-- returns the array of value_ids
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._restArray(seq_id integer) RETURNS integer[] AS $$
|
2016-03-31 07:58:03 +03:00
|
|
|
DECLARE
|
|
|
|
result integer[];
|
2016-03-22 04:28:08 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
result := (SELECT val_seq FROM types.value WHERE value_id = seq_id);
|
2016-03-31 07:58:03 +03:00
|
|
|
RETURN result[2:array_length(result, 1)];
|
2016-03-22 04:28:08 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
2016-03-22 08:53:31 +03:00
|
|
|
|
|
|
|
-- _slice:
|
|
|
|
-- takes value_id, a first index and an last index
|
|
|
|
-- returns the value_id of new list from first (inclusive) to last (exclusive)
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._slice(seq_id integer, first integer, last integer)
|
2016-03-26 07:11:40 +03:00
|
|
|
RETURNS integer AS $$
|
2016-03-22 08:53:31 +03:00
|
|
|
DECLARE
|
2016-03-31 07:58:03 +03:00
|
|
|
seq integer[];
|
2016-03-22 08:53:31 +03:00
|
|
|
vid integer;
|
|
|
|
i integer;
|
|
|
|
result integer;
|
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
SELECT val_seq INTO seq FROM types.value WHERE value_id = seq_id;
|
|
|
|
INSERT INTO types.value (type_id, val_seq)
|
2016-03-31 07:58:03 +03:00
|
|
|
VALUES (8, seq[first+1:last])
|
2016-03-22 08:53:31 +03:00
|
|
|
RETURNING value_id INTO result;
|
|
|
|
RETURN result;
|
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
-- _rest:
|
|
|
|
-- takes value_id
|
|
|
|
-- returns the value_id of new list
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._rest(seq_id integer) RETURNS integer AS $$
|
2016-03-22 08:53:31 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
RETURN types._slice(seq_id, 1, types._count(seq_id));
|
2016-03-22 08:53:31 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
-- _count:
|
|
|
|
-- takes value_id
|
|
|
|
-- returns a count (not value_id)
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._count(seq_id integer) RETURNS integer AS $$
|
2016-03-22 08:53:31 +03:00
|
|
|
DECLARE
|
2016-03-31 07:58:03 +03:00
|
|
|
result integer[];
|
2016-03-22 08:53:31 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
result := (SELECT val_seq FROM types.value
|
2016-03-31 07:58:03 +03:00
|
|
|
WHERE value_id = seq_id);
|
|
|
|
RETURN COALESCE(array_length(result, 1), 0);
|
2016-03-22 08:53:31 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
|
2016-03-26 07:11:40 +03:00
|
|
|
-- ---------------------------------------------------------
|
|
|
|
-- hash-map functions
|
|
|
|
|
|
|
|
-- _hash_map:
|
|
|
|
-- return value_id of a new hash-map
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._hash_map(items integer[]) RETURNS integer AS $$
|
2016-03-26 07:11:40 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
RETURN types._collection(items, 10);
|
2016-03-26 07:11:40 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
-- _hash_map_Q:
|
|
|
|
-- return true if obj value_id is a list
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._hash_map_Q(obj integer) RETURNS boolean AS $$
|
2016-03-26 07:11:40 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
RETURN types._tf((SELECT 1 FROM types.value
|
|
|
|
WHERE value_id = obj and type_id = 10));
|
2016-03-26 07:11:40 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
2016-03-31 07:58:03 +03:00
|
|
|
-- _assoc_BANG:
|
|
|
|
-- return value_id of the hash-map with new elements appended
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._assoc_BANG(hm integer, items integer[]) RETURNS integer AS $$
|
2016-03-31 07:58:03 +03:00
|
|
|
DECLARE
|
|
|
|
hash hstore;
|
|
|
|
BEGIN
|
|
|
|
IF (array_length(items, 1) % 2) = 1 THEN
|
|
|
|
RAISE EXCEPTION 'hash-map: odd number of arguments';
|
|
|
|
END IF;
|
2016-05-03 07:02:29 +03:00
|
|
|
SELECT val_hash INTO hash FROM types.value WHERE value_id = hm;
|
2016-03-31 07:58:03 +03:00
|
|
|
IF hash IS NULL THEN
|
2016-05-03 07:02:29 +03:00
|
|
|
UPDATE types.value SET val_hash = hstore(CAST(items AS varchar[]))
|
2016-03-31 07:58:03 +03:00
|
|
|
WHERE value_id = hm;
|
|
|
|
ELSE
|
2016-05-03 07:02:29 +03:00
|
|
|
UPDATE types.value
|
|
|
|
SET val_hash = hash || hstore(CAST(items AS varchar[]))
|
2016-03-31 07:58:03 +03:00
|
|
|
WHERE value_id = hm;
|
|
|
|
END IF;
|
|
|
|
RETURN hm;
|
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
-- _dissoc_BANG:
|
2016-03-26 07:11:40 +03:00
|
|
|
-- return value_id of the hash-map with elements removed
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._dissoc_BANG(hm integer, items integer[]) RETURNS integer AS $$
|
2016-03-26 07:11:40 +03:00
|
|
|
DECLARE
|
2016-03-31 07:58:03 +03:00
|
|
|
hash hstore;
|
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
SELECT val_hash INTO hash FROM types.value WHERE value_id = hm;
|
|
|
|
UPDATE types.value SET val_hash = hash - CAST(items AS varchar[])
|
2016-03-31 07:58:03 +03:00
|
|
|
WHERE value_id = hm;
|
2016-03-26 07:11:40 +03:00
|
|
|
RETURN hm;
|
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
-- _get:
|
|
|
|
-- return value_id of the hash-map entry matching key
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._get(hm integer, key varchar) RETURNS integer AS $$
|
2016-03-31 07:58:03 +03:00
|
|
|
DECLARE
|
|
|
|
hash hstore;
|
2016-03-26 07:11:40 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
SELECT val_hash INTO hash FROM types.value WHERE value_id = hm;
|
|
|
|
RETURN hash -> CAST(types._stringv(key) AS varchar);
|
2016-03-26 07:11:40 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
-- _contains_Q:
|
|
|
|
-- return true if hash-map contains entry matching key
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._contains_Q(hm integer, key varchar) RETURNS boolean AS $$
|
2016-03-31 07:58:03 +03:00
|
|
|
DECLARE
|
|
|
|
hash hstore;
|
2016-03-26 07:11:40 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
SELECT val_hash INTO hash FROM types.value WHERE value_id = hm;
|
|
|
|
RETURN types._tf(hash ? CAST(types._stringv(key) AS varchar));
|
2016-03-26 07:11:40 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
-- _keys:
|
|
|
|
-- return array of key value_ids from hash-map
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._keys(hm integer) RETURNS integer[] AS $$
|
2016-03-31 07:58:03 +03:00
|
|
|
DECLARE
|
|
|
|
hash hstore;
|
2016-03-26 07:11:40 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
SELECT val_hash INTO hash FROM types.value WHERE value_id = hm;
|
2016-03-31 07:58:03 +03:00
|
|
|
RETURN CAST(akeys(hash) AS integer[]);
|
2016-03-26 07:11:40 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
-- _vals:
|
|
|
|
-- return array of value value_ids from hash-map
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._vals(hm integer) RETURNS integer[] AS $$
|
2016-03-31 07:58:03 +03:00
|
|
|
DECLARE
|
|
|
|
hash hstore;
|
2016-03-26 07:11:40 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
SELECT val_hash INTO hash FROM types.value WHERE value_id = hm;
|
2016-03-31 07:58:03 +03:00
|
|
|
RETURN CAST(avals(hash) AS integer[]);
|
2016-03-26 07:11:40 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
|
2016-03-22 08:53:31 +03:00
|
|
|
-- ---------------------------------------------------------
|
|
|
|
-- function functions
|
|
|
|
|
|
|
|
-- _function:
|
2016-03-31 07:58:03 +03:00
|
|
|
-- takes a function name
|
|
|
|
-- returns the value_id of a new
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._function(fname varchar)
|
2016-03-31 07:58:03 +03:00
|
|
|
RETURNS varchar AS $$
|
|
|
|
DECLARE
|
|
|
|
result integer;
|
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
INSERT INTO types.value (type_id, val_string)
|
2016-03-31 07:58:03 +03:00
|
|
|
VALUES (11, fname)
|
|
|
|
RETURNING value_id INTO result;
|
|
|
|
RETURN CAST(result AS varchar);
|
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
-- _malfunc:
|
2016-03-22 08:53:31 +03:00
|
|
|
-- takes a ast value_id, params value_id and env_id
|
|
|
|
-- returns the value_id of a new function
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._malfunc(ast integer, params integer, env integer)
|
2016-03-26 07:11:40 +03:00
|
|
|
RETURNS integer AS $$
|
2016-03-22 08:53:31 +03:00
|
|
|
DECLARE
|
|
|
|
cid integer = NULL;
|
|
|
|
result integer;
|
|
|
|
BEGIN
|
|
|
|
-- Create function entry
|
2016-05-03 07:02:29 +03:00
|
|
|
INSERT INTO types.value (type_id, ast_id, params_id, env_id)
|
2016-03-31 07:58:03 +03:00
|
|
|
VALUES (12, ast, params, env)
|
2016-03-22 08:53:31 +03:00
|
|
|
RETURNING value_id into result;
|
|
|
|
RETURN result;
|
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
2016-03-25 05:10:10 +03:00
|
|
|
-- _macro:
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._macro(func integer) RETURNS integer AS $$
|
2016-03-25 05:10:10 +03:00
|
|
|
DECLARE
|
|
|
|
newfunc integer;
|
|
|
|
cid integer;
|
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
newfunc := types._clone(func);
|
|
|
|
UPDATE types.value SET macro = true WHERE value_id = newfunc;
|
2016-03-25 05:10:10 +03:00
|
|
|
RETURN newfunc;
|
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._apply(func integer, args integer[]) RETURNS integer AS $$
|
2016-03-22 08:53:31 +03:00
|
|
|
DECLARE
|
|
|
|
type integer;
|
|
|
|
fcid integer;
|
|
|
|
fname varchar;
|
|
|
|
fast integer;
|
|
|
|
fparams integer;
|
|
|
|
fenv integer;
|
|
|
|
result integer;
|
|
|
|
BEGIN
|
2016-03-31 08:38:35 +03:00
|
|
|
SELECT type_id, val_string, ast_id, params_id, env_id
|
2016-03-31 07:58:03 +03:00
|
|
|
INTO type, fname, fast, fparams, fenv
|
2016-05-03 07:02:29 +03:00
|
|
|
FROM types.value WHERE value_id = func;
|
2016-03-22 08:53:31 +03:00
|
|
|
IF type = 11 THEN
|
|
|
|
EXECUTE format('SELECT %s($1);', fname)
|
|
|
|
INTO result USING args;
|
|
|
|
RETURN result;
|
|
|
|
ELSIF type = 12 THEN
|
|
|
|
-- NOTE: forward reference to current step EVAL function
|
2016-05-03 07:02:29 +03:00
|
|
|
RETURN mal.EVAL(fast, envs.new(fenv, fparams, args));
|
2016-03-22 08:53:31 +03:00
|
|
|
ELSE
|
|
|
|
RAISE EXCEPTION 'Invalid function call';
|
|
|
|
END IF;
|
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
-- ---------------------------------------------------------
|
|
|
|
-- atom functions
|
|
|
|
|
|
|
|
-- _atom:
|
|
|
|
-- takes an ast value_id
|
|
|
|
-- returns a new atom value_id
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._atom(val integer) RETURNS integer AS $$
|
2016-03-22 08:53:31 +03:00
|
|
|
DECLARE
|
|
|
|
cid integer = NULL;
|
|
|
|
result integer;
|
|
|
|
BEGIN
|
2016-03-31 07:58:03 +03:00
|
|
|
-- Create atom
|
2016-05-03 07:02:29 +03:00
|
|
|
INSERT INTO types.value (type_id, val_seq)
|
2016-03-31 07:58:03 +03:00
|
|
|
VALUES (13, ARRAY[val])
|
2016-03-26 09:44:43 +03:00
|
|
|
RETURNING value_id INTO result;
|
2016-03-22 08:53:31 +03:00
|
|
|
RETURN result;
|
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
-- _atom_Q:
|
|
|
|
-- takes a value_id
|
|
|
|
-- returns the whether value_id is an atom
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._atom_Q(id integer) RETURNS boolean AS $$
|
2016-03-22 08:53:31 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
RETURN EXISTS(SELECT 1 FROM types.value
|
|
|
|
WHERE type_id = 13 AND value_id = id);
|
2016-03-22 08:53:31 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
-- _deref:
|
|
|
|
-- takes an atom value_id
|
|
|
|
-- returns a atom value value_id
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._deref(atm integer) RETURNS integer AS $$
|
2016-03-22 08:53:31 +03:00
|
|
|
DECLARE
|
|
|
|
result integer;
|
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
RETURN (SELECT val_seq[1] FROM types.value WHERE value_id = atm);
|
2016-03-22 08:53:31 +03:00
|
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
-- _reset_BANG:
|
|
|
|
-- takes an atom value_id and new value value_id
|
|
|
|
-- returns a new value value_id
|
2016-05-03 07:02:29 +03:00
|
|
|
CREATE FUNCTION types._reset_BANG(atm integer, newval integer) RETURNS integer AS $$
|
2016-03-22 08:53:31 +03:00
|
|
|
BEGIN
|
2016-05-03 07:02:29 +03:00
|
|
|
UPDATE types.value SET val_seq = ARRAY[newval] WHERE value_id = atm;
|
2016-03-22 08:53:31 +03:00
|
|
|
RETURN newval;
|
|
|
|
END; $$ LANGUAGE plpgsql;
|