zotero/resource/schema/triggers.sql
Dan Stillman 33dedd1753 Tags overhaul [DB reupgrade]
- Simplified schema
- Tags are now added without reloading entire tag selector
  - On my system, adding 400 tags to an item (separately, with the tag
    selector updating each time) went from 59 seconds to 42. (Given that
    it takes only 13 seconds with the tag selector closed, though,
    there's clearly more work to be done.)
- Tag selector now uses HTML flexbox (in identical fashion, for now, but
  with the possibility of fancier changes later, and with streamlined
  logic thanks to the flexbox 'order' property)
- Various async fixes
- Tests
2015-06-23 05:21:58 -04:00

228 lines
10 KiB
SQL

-- 18
-- Copyright (c) 2009 Center for History and New Media
-- George Mason University, Fairfax, Virginia, USA
-- http://zotero.org
--
-- This file is part of Zotero.
--
-- Zotero is free software: you can redistribute it and/or modify
-- it under the terms of the GNU Affero General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- Zotero is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU Affero General Public License for more details.
--
-- You should have received a copy of the GNU Affero General Public License
-- along with Zotero. If not, see <http://www.gnu.org/licenses/>.
-- ";---" is an ugly hack for Zotero.DB.executeSQLFile()
-- Triggers to validate date field
DROP TRIGGER IF EXISTS insert_date_field;
CREATE TRIGGER insert_date_field BEFORE INSERT ON itemData
FOR EACH ROW WHEN NEW.fieldID IN (14, 27, 52, 96, 100)
BEGIN
SELECT CASE
CAST(SUBSTR((SELECT value FROM itemDataValues WHERE valueID=NEW.valueID), 1, 4) AS INT) BETWEEN 0 AND 9999 AND
SUBSTR((SELECT value FROM itemDataValues WHERE valueID=NEW.valueID), 5, 1) = '-' AND
CAST(SUBSTR((SELECT value FROM itemDataValues WHERE valueID=NEW.valueID), 6, 2) AS INT) BETWEEN 0 AND 12 AND
SUBSTR((SELECT value FROM itemDataValues WHERE valueID=NEW.valueID), 8, 1) = '-' AND
CAST(SUBSTR((SELECT value FROM itemDataValues WHERE valueID=NEW.valueID), 9, 2) AS INT) BETWEEN 0 AND 31
WHEN 0 THEN RAISE (ABORT, 'Date field must begin with SQL date') END;---
END;
DROP TRIGGER IF EXISTS update_date_field;
CREATE TRIGGER update_date_field BEFORE UPDATE ON itemData
FOR EACH ROW WHEN NEW.fieldID IN (14, 27, 52, 96, 100)
BEGIN
SELECT CASE
CAST(SUBSTR((SELECT value FROM itemDataValues WHERE valueID=NEW.valueID), 1, 4) AS INT) BETWEEN 0 AND 9999 AND
SUBSTR((SELECT value FROM itemDataValues WHERE valueID=NEW.valueID), 5, 1) = '-' AND
CAST(SUBSTR((SELECT value FROM itemDataValues WHERE valueID=NEW.valueID), 6, 2) AS INT) BETWEEN 0 AND 12 AND
SUBSTR((SELECT value FROM itemDataValues WHERE valueID=NEW.valueID), 8, 1) = '-' AND
CAST(SUBSTR((SELECT value FROM itemDataValues WHERE valueID=NEW.valueID), 9, 2) AS INT) BETWEEN 0 AND 31
WHEN 0 THEN RAISE (ABORT, 'Date field must begin with SQL date') END;---
END;
-- Don't allow empty creators
DROP TRIGGER IF EXISTS insert_creatorData;
CREATE TRIGGER insert_creators BEFORE INSERT ON creators
FOR EACH ROW WHEN NEW.firstName='' AND NEW.lastName=''
BEGIN
SELECT RAISE (ABORT, 'Creator names cannot be empty');---
END;
DROP TRIGGER IF EXISTS update_creatorData;
CREATE TRIGGER update_creators BEFORE UPDATE ON creators
FOR EACH ROW WHEN NEW.firstName='' AND NEW.lastName=''
BEGIN
SELECT RAISE (ABORT, 'Creator names cannot be empty');---
END;
-- Don't allow collection parents in different libraries
DROP TRIGGER IF EXISTS fki_collections_parentCollectionID_libraryID;
CREATE TRIGGER fki_collections_parentCollectionID_libraryID
BEFORE INSERT ON collections
FOR EACH ROW BEGIN
SELECT RAISE(ABORT, 'insert on table "collections" violates foreign key constraint "fki_collections_parentCollectionID_libraryID"')
WHERE NEW.parentCollectionID IS NOT NULL AND
NEW.libraryID != (SELECT libraryID FROM collections WHERE collectionID = NEW.parentCollectionID);---
END;
DROP TRIGGER IF EXISTS fku_collections_parentCollectionID_libraryID;
CREATE TRIGGER fku_collections_parentCollectionID_libraryID
BEFORE UPDATE ON collections
FOR EACH ROW BEGIN
SELECT RAISE(ABORT, 'update on table "collections" violates foreign key constraint "fku_collections_parentCollectionID_libraryID"')
WHERE NEW.parentCollectionID IS NOT NULL AND
NEW.libraryID != (SELECT libraryID FROM collections WHERE collectionID = NEW.parentCollectionID);---
END;
-- collectionItems libraryID
DROP TRIGGER IF EXISTS fki_collectionItems_libraryID;
CREATE TRIGGER fki_collectionItems_libraryID
BEFORE INSERT ON collectionItems
FOR EACH ROW BEGIN
SELECT RAISE(ABORT, 'insert on table "collectionItems" violates foreign key constraint "fki_collectionItems_libraryID"')
WHERE (SELECT libraryID FROM collections WHERE collectionID = NEW.collectionID) != (SELECT libraryID FROM items WHERE itemID = NEW.itemID);---
END;
DROP TRIGGER IF EXISTS fku_collectionItems_libraryID;
CREATE TRIGGER fku_collectionItems_libraryID
BEFORE UPDATE ON collectionItems
FOR EACH ROW BEGIN
SELECT RAISE(ABORT, 'update on table "collectionItems" violates foreign key constraint "fku_collectionItems_libraryID"')
WHERE (SELECT libraryID FROM collections WHERE collectionID = NEW.collectionID) != (SELECT libraryID FROM items WHERE itemID = NEW.itemID);---
END;
-- Don't allow child items to exist explicitly in collections
DROP TRIGGER IF EXISTS fki_collectionItems_itemID_parentItemID;
CREATE TRIGGER fki_collectionItems_itemID_parentItemID
BEFORE INSERT ON collectionItems
FOR EACH ROW BEGIN
SELECT RAISE(ABORT, 'insert on table "collectionItems" violates foreign key constraint "fki_collectionItems_itemID_parentItemID"')
WHERE NEW.itemID IN (SELECT itemID FROM itemAttachments WHERE parentItemID IS NOT NULL UNION SELECT itemID FROM itemNotes WHERE parentItemID IS NOT NULL);---
END;
DROP TRIGGER IF EXISTS fku_collectionItems_itemID_parentItemID;
CREATE TRIGGER fku_collectionItems_itemID_parentItemID
BEFORE UPDATE OF itemID ON collectionItems
FOR EACH ROW BEGIN
SELECT RAISE(ABORT, 'update on table "collectionItems" violates foreign key constraint "fku_collectionItems_itemID_parentItemID"')
WHERE NEW.itemID IN (SELECT itemID FROM itemAttachments WHERE parentItemID IS NOT NULL UNION SELECT itemID FROM itemNotes WHERE parentItemID IS NOT NULL);---
END;
-- When making a standalone attachment a child, remove from any collections
DROP TRIGGER IF EXISTS fku_itemAttachments_parentItemID_collectionItems_itemID;
CREATE TRIGGER fku_itemAttachments_parentItemID_collectionItems_itemID
BEFORE UPDATE OF parentItemID ON itemAttachments
FOR EACH ROW WHEN OLD.parentItemID IS NULL AND NEW.parentItemID IS NOT NULL BEGIN
DELETE FROM collectionItems WHERE itemID = NEW.itemID;---
END;
-- When making a standalone note a child, remove from any collections
DROP TRIGGER IF EXISTS fku_itemNotes_parentItemID_collectionItems_itemID;
CREATE TRIGGER fku_itemNotes_parentItemID_collectionItems_itemID
BEFORE UPDATE OF parentItemID ON itemNotes
FOR EACH ROW WHEN OLD.parentItemID IS NULL AND NEW.parentItemID IS NOT NULL BEGIN
DELETE FROM collectionItems WHERE itemID = NEW.itemID;---
END;
-- itemAttachments
DROP TRIGGER IF EXISTS fki_itemAttachments;
CREATE TRIGGER fki_itemAttachments
BEFORE INSERT ON itemAttachments
FOR EACH ROW BEGIN
SELECT RAISE(ABORT, 'insert on table "itemAttachments" violates foreign key constraint "fki_itemAttachments"')
WHERE NEW.parentItemID IS NOT NULL AND
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) != (SELECT libraryID FROM items WHERE itemID = NEW.parentItemID);---
-- Make sure this is an attachment item
SELECT RAISE(ABORT, 'item is not an attachment')
WHERE (SELECT itemTypeID FROM items WHERE itemID = NEW.itemID) != 14;---
-- Make sure parent is a regular item
SELECT RAISE(ABORT, 'parent is not a regular item')
WHERE NEW.parentItemID IS NOT NULL AND (SELECT itemTypeID FROM items WHERE itemID = NEW.parentItemID) IN (1,14);---
-- If child, make sure attachment is not in a collection
SELECT RAISE(ABORT, 'collection item must be top level')
WHERE NEW.parentItemID IS NOT NULL AND (SELECT COUNT(*) FROM collectionItems WHERE itemID=NEW.itemID)>0;---
END;
DROP TRIGGER IF EXISTS fku_itemAttachments;
CREATE TRIGGER fku_itemAttachments
BEFORE UPDATE ON itemAttachments
FOR EACH ROW BEGIN
SELECT RAISE(ABORT, 'update on table "itemAttachments" violates foreign key constraint "fku_itemAttachments"')
WHERE NEW.parentItemID IS NOT NULL AND
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) != (SELECT libraryID FROM items WHERE itemID = NEW.parentItemID);---
-- Make sure parent is a regular item
SELECT RAISE(ABORT, 'parent is not a regular item')
WHERE NEW.parentItemID IS NOT NULL AND (SELECT itemTypeID FROM items WHERE itemID = NEW.parentItemID) IN (1,14);---
END;
-- itemNotes
DROP TRIGGER IF EXISTS fki_itemNotes;
CREATE TRIGGER fki_itemNotes
BEFORE INSERT ON itemNotes
FOR EACH ROW BEGIN
SELECT RAISE(ABORT, 'insert on table "itemNotes" violates foreign key constraint "fki_itemNotes_libraryID"')
WHERE NEW.parentItemID IS NOT NULL AND
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) != (SELECT libraryID FROM items WHERE itemID = NEW.parentItemID);---
-- Make sure this is a note or attachment item
SELECT RAISE(ABORT, 'item is not a note or attachment') WHERE
(SELECT itemTypeID FROM items WHERE itemID = NEW.itemID) NOT IN (1,14);---
-- Make sure parent is a regular item
SELECT RAISE(ABORT, 'parent is not a regular item') WHERE
NEW.parentItemID IS NOT NULL AND (SELECT itemTypeID FROM items WHERE itemID = NEW.parentItemID) IN (1,14);---
-- If child, make sure note is not in a collection
SELECT RAISE(ABORT, 'collection item must be top level') WHERE
NEW.parentItemID IS NOT NULL AND (SELECT COUNT(*) FROM collectionItems WHERE itemID=NEW.itemID)>0;---
END;
DROP TRIGGER IF EXISTS fku_itemNotes;
CREATE TRIGGER fku_itemNotes
BEFORE UPDATE ON itemNotes
FOR EACH ROW BEGIN
SELECT RAISE(ABORT, 'update on table "itemNotes" violates foreign key constraint "fku_itemNotes"')
WHERE NEW.parentItemID IS NOT NULL AND
(SELECT libraryID FROM items WHERE itemID = NEW.itemID) != (SELECT libraryID FROM items WHERE itemID = NEW.parentItemID);---
-- Make sure parent is a regular item
SELECT RAISE(ABORT, 'parent is not a regular item') WHERE
NEW.parentItemID IS NOT NULL AND (SELECT itemTypeID FROM items WHERE itemID = NEW.parentItemID) IN (1,14);---
END;
-- Make sure tags aren't empty
DROP TRIGGER IF EXISTS fki_tags;
CREATE TRIGGER fki_tags
BEFORE INSERT ON tags
FOR EACH ROW BEGIN
SELECT RAISE(ABORT, 'Tag cannot be blank')
WHERE TRIM(NEW.name)='';---
END;
DROP TRIGGER IF EXISTS fku_tags;
CREATE TRIGGER fku_tags
BEFORE UPDATE OF name ON tags
FOR EACH ROW BEGIN
SELECT RAISE(ABORT, 'Tag cannot be blank')
WHERE TRIM(NEW.name)='';---
END;