terom@37: terom@37: DROP TABLE IF EXISTS file_tree; terom@37: DROP TABLE IF EXISTS inodes; terom@37: DROP SEQUENCE IF EXISTS ino_seq; terom@37: terom@37: CREATE SEQUENCE ino_seq START 64; terom@37: terom@40: -- inodes terom@31: CREATE TABLE inodes ( terom@37: ino int4 primary key DEFAULT nextval('ino_seq'::regclass), terom@31: type char(3) NOT NULL, terom@31: mode int2 NOT NULL, terom@37: data oid, terom@40: link_path varchar(512), terom@40: terom@40: -- sanity checks terom@40: CONSTRAINT inodes_valid_reg CHECK (data IS NULL OR type = 'REG'), terom@40: CONSTRAINT inodes_valid_lnk CHECK (link_path IS NULL OR type = 'LNK') terom@31: ); terom@24: terom@40: -- filesystem layout terom@31: CREATE TABLE file_tree ( terom@31: "offset" serial4 primary key, terom@31: name varchar(256), terom@38: ino int4 references inodes(ino) NOT NULL, terom@38: ino_dir int4 references inodes(ino), terom@38: parent int4, terom@40: terom@40: -- structure terom@38: CONSTRAINT file_tree_uniq_direntry UNIQUE (parent, name), terom@38: CONSTRAINT file_tree_uniq_dir_ino UNIQUE (ino_dir), terom@40: CONSTRAINT file_tree_exist_parent FOREIGN KEY (parent) REFERENCES file_tree(ino_dir), terom@40: terom@40: -- sanity checks terom@40: CONSTRAINT file_tree_valid_root CHECK ((parent IS NULL AND name IS NULL AND ino = 1) OR (name IS NOT NULL and parent IS NOT NULL AND ino != 1)), terom@40: CONSTRAINT file_tree_valid_dir CHECK (ino_dir IS NULL OR ino_dir = ino) terom@31: ); terom@24: terom@37: INSERT INTO inodes (ino, type, mode, data) VALUES terom@31: (1, 'DIR', 365, NULL), terom@31: (2, 'REG', 292, lo_create(0)); terom@27: terom@38: INSERT INTO file_tree (name, parent, ino, ino_dir) VALUES terom@38: (NULL, NULL, 1, 1 ), terom@38: ('foo', 1, 2, NULL ); terom@31: terom@40: -- not sure how these work, I guess statements in functions aren't their own transactions terom@40: CREATE OR REPLACE FUNCTION lo_pread_oid (IN obj oid, IN len int4, IN "off" int4) RETURNS bytea LANGUAGE SQL STRICT AS 'select lo_open($1, 393216); select lo_lseek(0, $3, 0); select loread(0, $2);'; terom@40: CREATE OR REPLACE FUNCTION lo_pwrite_oid (IN obj oid, IN buf bytea, IN "off" int4) RETURNS int4 LANGUAGE SQL STRICT AS 'select lo_open($1, 393216); select lo_lseek(0, $3, 0); select lowrite(0, $2);'; terom@40: terom@40: CREATE OR REPLACE FUNCTION lo_otruncate (IN obj oid, IN len int4) RETURNS oid LANGUAGE SQL STRICT AS 'select lo_truncate(lo_open($1, 393216), $2); select $1;'; terom@37: CREATE OR REPLACE FUNCTION lo_size (oid) RETURNS int4 LANGUAGE SQL STABLE RETURNS NULL ON NULL INPUT AS 'select lo_lseek(lo_open($1, 262144), 0, 2);'; terom@37: CREATE OR REPLACE FUNCTION dbfs_size (type char, oid, link varchar) RETURNS int4 LANGUAGE SQL STABLE AS $$ terom@33: SELECT CASE $1 terom@33: WHEN 'LNK' THEN char_length($3) terom@33: WHEN 'REG' THEN lo_size($2) terom@33: ELSE 0 terom@33: END; terom@33: $$; terom@38: terom@38: CREATE OR REPLACE FUNCTION dbfs_link ( terom@38: IN ino int4, IN new_parent int4, IN new_name varchar, terom@38: OUT ino int4, OUT type char(3), OUT mode int2, OUT size int4, OUT nlink int8 terom@38: ) LANGUAGE SQL VOLATILE AS $$ terom@38: INSERT INTO file_tree (name, ino, parent) VALUES ($3, $1, $2); terom@38: SELECT ino, type, mode, dbfs_size(type, data, link_path) AS size, (SELECT COUNT(*) FROM inodes i LEFT JOIN file_tree ft ON (i.ino = ft.ino) WHERE i.ino = inodes.ino) AS nlink terom@38: FROM inodes WHERE ino = $1; terom@38: $$;