/cmdbuild/src/main/webapp/WEB-INF/sql/sample_schemas/demo_schema.sql

https://bitbucket.org/tecnoteca/cmdbuild · SQL · 12371 lines · 5494 code · 6846 blank · 31 comment · 197 complexity · f1267c04c0fee2540a0aa8141064b3df MD5 · raw file

Large files are truncated click here to view the full file

  1. SET standard_conforming_strings = off;
  2. SET check_function_bodies = false;
  3. SET client_min_messages = warning;
  4. CREATE FUNCTION _cm_add_class_cascade_delete_on_relations_trigger(tableid oid) RETURNS void
  5. LANGUAGE plpgsql
  6. AS $$
  7. BEGIN
  8. EXECUTE '
  9. CREATE TRIGGER "_CascadeDeleteOnRelations"
  10. AFTER UPDATE
  11. ON '|| TableId::regclass ||'
  12. FOR EACH ROW
  13. EXECUTE PROCEDURE _cm_trigger_cascade_delete_on_relations();
  14. ';
  15. END;
  16. $$;
  17. CREATE FUNCTION _cm_add_class_history_trigger(tableid oid) RETURNS void
  18. LANGUAGE plpgsql
  19. AS $$
  20. BEGIN
  21. EXECUTE '
  22. CREATE TRIGGER "_CreateHistoryRow"
  23. AFTER DELETE OR UPDATE
  24. ON '|| TableId::regclass ||'
  25. FOR EACH ROW
  26. EXECUTE PROCEDURE _cm_trigger_create_card_history_row()
  27. ';
  28. END;
  29. $$;
  30. CREATE FUNCTION _cm_add_class_sanity_check_trigger(tableid oid) RETURNS void
  31. LANGUAGE plpgsql
  32. AS $$
  33. BEGIN
  34. EXECUTE '
  35. CREATE TRIGGER "_SanityCheck"
  36. BEFORE INSERT OR UPDATE OR DELETE
  37. ON '|| TableId::regclass ||'
  38. FOR EACH ROW
  39. EXECUTE PROCEDURE _cm_trigger_sanity_check();
  40. ';
  41. END;
  42. $$;
  43. CREATE FUNCTION _cm_add_domain_history_trigger(domainid oid) RETURNS void
  44. LANGUAGE plpgsql
  45. AS $$
  46. BEGIN
  47. EXECUTE '
  48. CREATE TRIGGER "_CreateHistoryRow"
  49. AFTER DELETE OR UPDATE
  50. ON '|| DomainId::regclass ||'
  51. FOR EACH ROW
  52. EXECUTE PROCEDURE _cm_trigger_create_relation_history_row()
  53. ';
  54. END;
  55. $$;
  56. CREATE FUNCTION _cm_add_domain_sanity_check_trigger(domainid oid) RETURNS void
  57. LANGUAGE plpgsql
  58. AS $$
  59. BEGIN
  60. EXECUTE '
  61. CREATE TRIGGER "_SanityCheck"
  62. BEFORE INSERT OR UPDATE OR DELETE
  63. ON '|| DomainId::regclass ||'
  64. FOR EACH ROW
  65. EXECUTE PROCEDURE _cm_trigger_sanity_check();
  66. ';
  67. END
  68. $$;
  69. CREATE FUNCTION _cm_add_fk_constraints(fksourceid oid, attributename text) RETURNS void
  70. LANGUAGE plpgsql
  71. AS $$
  72. DECLARE
  73. FKTargetId oid := _cm_get_fk_target_table_id(FKSourceId, AttributeName);
  74. SubTableId oid;
  75. BEGIN
  76. IF FKTargetId IS NULL THEN
  77. RETURN;
  78. END IF;
  79. FOR SubTableId IN SELECT _cm_subtables_and_itself(FKSourceId) LOOP
  80. PERFORM _cm_add_fk_trigger(SubTableId, FKSourceId, AttributeName, FKTargetId);
  81. END LOOP;
  82. FOR SubTableId IN SELECT _cm_subtables_and_itself(FKTargetId) LOOP
  83. PERFORM _cm_add_restrict_trigger(SubTableId, FKSourceId, AttributeName);
  84. END LOOP;
  85. END;
  86. $$;
  87. CREATE FUNCTION _cm_add_fk_trigger(tableid oid, fksourceid oid, fkattribute text, fktargetid oid) RETURNS void
  88. LANGUAGE plpgsql
  89. AS $$
  90. DECLARE
  91. TriggerVariant text;
  92. BEGIN
  93. IF _cm_is_simpleclass(FKSourceId) THEN
  94. TriggerVariant := 'simple';
  95. ELSE
  96. TriggerVariant := '';
  97. END IF;
  98. EXECUTE '
  99. CREATE TRIGGER ' || quote_ident(_cm_classfk_name(FKSourceId, FKAttribute)) || '
  100. BEFORE INSERT OR UPDATE
  101. ON ' || TableId::regclass || '
  102. FOR EACH ROW
  103. EXECUTE PROCEDURE _cm_trigger_fk('||
  104. quote_literal(FKAttribute) || ',' ||
  105. quote_literal(FKTargetId::regclass) || ',' ||
  106. quote_literal(TriggerVariant) ||
  107. ');
  108. ';
  109. END;
  110. $$;
  111. CREATE FUNCTION _cm_add_reference_handling(tableid oid, attributename text) RETURNS void
  112. LANGUAGE plpgsql
  113. AS $$
  114. DECLARE
  115. objid integer;
  116. referencedid integer;
  117. ctrlint integer;
  118. AttributeComment text := _cm_comment_for_attribute(TableId, AttributeName);
  119. ReferenceTargetId oid := _cm_read_reference_target_id_comment(AttributeComment);
  120. AttributeReferenceType text := _cm_read_reference_type_comment(AttributeComment);
  121. ReferenceDomainId oid := _cm_read_reference_domain_id_comment(AttributeComment);
  122. RefSourceIdAttribute text := _cm_get_ref_source_id_domain_attribute(TableId, AttributeName);
  123. RefSourceClassIdAttribute text := _cm_get_ref_source_class_domain_attribute(TableId, AttributeName);
  124. RefTargetIdAttribute text := _cm_get_ref_target_id_domain_attribute(TableId, AttributeName);
  125. ChildId oid;
  126. BEGIN
  127. IF ReferenceTargetId IS NULL OR AttributeReferenceType IS NULL OR ReferenceDomainId IS NULL THEN
  128. RETURN;
  129. END IF;
  130. -- Updates the reference for every relation
  131. -- TODO: UNDERSTAND WHAT IT DOES AND MAKE IT READABLE!
  132. FOR objid IN EXECUTE 'SELECT "Id" from '||TableId::regclass||' WHERE "Status"=''A'''
  133. LOOP
  134. FOR referencedid IN EXECUTE '
  135. SELECT '|| quote_ident(RefTargetIdAttribute) ||
  136. ' FROM '|| ReferenceDomainId::regclass ||
  137. ' WHERE '|| quote_ident(RefSourceClassIdAttribute) ||'='|| TableId ||
  138. ' AND '|| quote_ident(RefSourceIdAttribute) ||'='|| objid ||
  139. ' AND "Status"=''A'''
  140. LOOP
  141. EXECUTE 'SELECT count(*) FROM '||ReferenceTargetId::regclass||' where "Id"='||referencedid INTO ctrlint;
  142. IF(ctrlint<>0) THEN
  143. EXECUTE 'UPDATE '|| TableId::regclass ||
  144. ' SET '|| quote_ident(AttributeName) ||'='|| referencedid ||
  145. ' WHERE "Id"='|| objid;
  146. END IF;
  147. END LOOP;
  148. END LOOP;
  149. -- Trigger on reference class (reference -> relation)
  150. FOR ChildId IN SELECT _cm_subtables_and_itself(TableId) LOOP
  151. PERFORM _cm_add_update_relation_trigger(ChildId, TableId, AttributeName);
  152. END LOOP;
  153. -- Trigger on domain (relation -> reference)
  154. PERFORM _cm_add_update_reference_trigger(TableId, AttributeName);
  155. END;
  156. $$;
  157. CREATE FUNCTION _cm_add_restrict_trigger(fktargetclassid oid, fkclassid oid, fkattribute text) RETURNS void
  158. LANGUAGE plpgsql
  159. AS $$
  160. BEGIN
  161. IF FKClassId IS NULL THEN
  162. RETURN;
  163. END IF;
  164. EXECUTE '
  165. CREATE TRIGGER ' || quote_ident('_Constr_'||_cm_cmtable(FKClassId)||'_'||FKAttribute) || '
  166. BEFORE UPDATE OR DELETE
  167. ON ' || FKTargetClassId::regclass || '
  168. FOR EACH ROW
  169. EXECUTE PROCEDURE _cm_trigger_restrict(' ||
  170. quote_literal(FKClassId::regclass) || ',' ||
  171. quote_literal(FKAttribute) ||
  172. ');
  173. ';
  174. END;
  175. $$;
  176. CREATE FUNCTION _cm_add_simpleclass_sanity_check_trigger(tableid oid) RETURNS void
  177. LANGUAGE plpgsql
  178. AS $$
  179. BEGIN
  180. EXECUTE '
  181. CREATE TRIGGER "_SanityCheck"
  182. BEFORE INSERT OR UPDATE OR DELETE
  183. ON '|| TableId::regclass ||'
  184. FOR EACH ROW
  185. EXECUTE PROCEDURE _cm_trigger_sanity_check_simple();
  186. ';
  187. END;
  188. $$;
  189. CREATE FUNCTION _cm_add_spherical_mercator() RETURNS void
  190. LANGUAGE plpgsql
  191. AS $$
  192. DECLARE
  193. FoundSrid integer;
  194. BEGIN
  195. SELECT "srid" INTO FoundSrid FROM "spatial_ref_sys" WHERE "srid" = 900913 LIMIT 1;
  196. IF NOT FOUND THEN
  197. INSERT INTO "spatial_ref_sys" ("srid","auth_name","auth_srid","srtext","proj4text") VALUES (900913,'spatialreferencing.org',900913,'','+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +units=m +k=1.0 +nadgrids=@null +no_defs');
  198. END IF;
  199. END;
  200. $$;
  201. CREATE FUNCTION _cm_add_update_reference_trigger(tableid oid, refattribute text) RETURNS void
  202. LANGUAGE plpgsql
  203. AS $$
  204. DECLARE
  205. DomainId oid := _cm_get_reference_domain_id(TableId, RefAttribute);
  206. DomainSourceIdAttribute text := _cm_get_ref_source_id_domain_attribute(TableId, RefAttribute);
  207. DomainTargetIdAttribute text := _cm_get_ref_target_id_domain_attribute(TableId, RefAttribute);
  208. BEGIN
  209. IF DomainId IS NULL OR DomainSourceIdAttribute IS NULL OR DomainTargetIdAttribute IS NULL THEN
  210. RETURN;
  211. END IF;
  212. EXECUTE '
  213. CREATE TRIGGER ' || quote_ident(_cm_update_reference_trigger_name(TableId, RefAttribute)) || '
  214. AFTER INSERT OR UPDATE
  215. ON ' || DomainId::regclass || '
  216. FOR EACH ROW
  217. EXECUTE PROCEDURE _cm_trigger_update_reference(' ||
  218. quote_literal(RefAttribute) || ',' ||
  219. quote_literal(TableId::regclass) || ',' ||
  220. quote_literal(DomainSourceIdAttribute) || ',' ||
  221. quote_literal(DomainTargetIdAttribute) ||
  222. ');
  223. ';
  224. END;
  225. $$;
  226. CREATE FUNCTION _cm_add_update_relation_trigger(tableid oid, reftableid oid, refattribute text) RETURNS void
  227. LANGUAGE plpgsql
  228. AS $$
  229. DECLARE
  230. DomainId oid := _cm_get_reference_domain_id(RefTableId, RefAttribute);
  231. DomainSourceIdAttribute text := _cm_get_ref_source_id_domain_attribute(RefTableId, RefAttribute);
  232. DomainTargetIdAttribute text := _cm_get_ref_target_id_domain_attribute(RefTableId, RefAttribute);
  233. BEGIN
  234. IF DomainId IS NULL OR DomainSourceIdAttribute IS NULL OR DomainTargetIdAttribute IS NULL THEN
  235. RETURN;
  236. END IF;
  237. EXECUTE '
  238. CREATE TRIGGER ' || quote_ident(_cm_update_relation_trigger_name(RefTableId, RefAttribute)) || '
  239. AFTER INSERT OR UPDATE
  240. ON ' || TableId::regclass || '
  241. FOR EACH ROW
  242. EXECUTE PROCEDURE _cm_trigger_update_relation(' ||
  243. quote_literal(RefAttribute) || ',' ||
  244. quote_literal(DomainId::regclass) || ',' ||
  245. quote_literal(DomainSourceIdAttribute) || ',' ||
  246. quote_literal(DomainTargetIdAttribute) ||
  247. ');
  248. ';
  249. END;
  250. $$;
  251. CREATE FUNCTION _cm_attribute_default_to_src(tableid oid, attributename text, newdefault text) RETURNS text
  252. LANGUAGE plpgsql
  253. AS $$
  254. DECLARE
  255. SQLType text := _cm_get_attribute_sqltype(TableId, AttributeName);
  256. BEGIN
  257. IF (NewDefault IS NULL OR TRIM(NewDefault) = '') THEN
  258. RETURN NULL;
  259. END IF;
  260. IF SQLType ILIKE 'varchar%' OR SQLType = 'text' OR
  261. ((SQLType = 'date' OR SQLType = 'timestamp') AND TRIM(NewDefault) <> 'now()')
  262. THEN
  263. RETURN quote_literal(NewDefault);
  264. ELSE
  265. RETURN NewDefault;
  266. END IF;
  267. END;
  268. $$;
  269. CREATE FUNCTION _cm_attribute_is_empty(tableid oid, attributename text) RETURNS boolean
  270. LANGUAGE plpgsql
  271. AS $$
  272. DECLARE
  273. Out boolean;
  274. BEGIN
  275. EXECUTE 'SELECT (COUNT(*) = 0) FROM '|| TableId::regclass ||
  276. ' WHERE '|| quote_ident(AttributeName) ||' IS NOT NULL' ||
  277. ' AND '|| quote_ident(AttributeName) ||'::text <> '''' LIMIT 1' INTO Out;
  278. RETURN Out;
  279. END;
  280. $$;
  281. CREATE FUNCTION _cm_attribute_is_inherited(tableid oid, attributename text) RETURNS boolean
  282. LANGUAGE sql
  283. AS $_$
  284. SELECT pg_attribute.attinhcount <> 0
  285. FROM pg_attribute
  286. WHERE pg_attribute.attrelid = $1 AND pg_attribute.attname = $2;
  287. $_$;
  288. CREATE FUNCTION _cm_attribute_is_local(tableid oid, attributename text) RETURNS boolean
  289. LANGUAGE sql STABLE
  290. AS $_$
  291. SELECT (attinhcount = 0) FROM pg_attribute WHERE attrelid = $1 AND attname = $2 LIMIT 1;
  292. $_$;
  293. CREATE FUNCTION _cm_attribute_is_notnull(tableid oid, attributename text) RETURNS boolean
  294. LANGUAGE sql
  295. AS $_$
  296. SELECT pg_attribute.attnotnull OR c.oid IS NOT NULL
  297. FROM pg_attribute
  298. LEFT JOIN pg_constraint AS c
  299. ON c.conrelid = pg_attribute.attrelid
  300. AND c.conname::text = _cm_notnull_constraint_name(pg_attribute.attname::text)
  301. WHERE pg_attribute.attrelid = $1 AND pg_attribute.attname = $2;
  302. $_$;
  303. CREATE FUNCTION _cm_attribute_is_unique(tableid oid, attributename text) RETURNS boolean
  304. LANGUAGE plpgsql STABLE
  305. AS $$
  306. DECLARE
  307. IsUnique boolean;
  308. BEGIN
  309. SELECT INTO IsUnique (count(*) > 0) FROM pg_class
  310. JOIN pg_index ON pg_class.oid = pg_index.indexrelid
  311. WHERE pg_index.indrelid = TableId AND relname = _cm_unique_index_name(TableId, AttributeName);
  312. RETURN IsUnique;
  313. END;
  314. $$;
  315. CREATE FUNCTION _cm_attribute_list(tableid oid) RETURNS SETOF text
  316. LANGUAGE sql STABLE
  317. AS $_$
  318. SELECT attname::text FROM pg_attribute WHERE attrelid = $1 AND attnum > 0 AND atttypid > 0 ORDER BY attnum;
  319. $_$;
  320. CREATE FUNCTION _cm_attribute_list_cs(classid oid) RETURNS text
  321. LANGUAGE sql STABLE
  322. AS $_$
  323. SELECT array_to_string(array(
  324. SELECT quote_ident(name) FROM _cm_attribute_list($1) AS name
  325. ),',');
  326. $_$;
  327. CREATE FUNCTION _cm_attribute_notnull_is_check(tableid oid, attributename text) RETURNS boolean
  328. LANGUAGE plpgsql
  329. AS $$
  330. DECLARE
  331. AttributeComment text := _cm_comment_for_attribute(TableId, AttributeName);
  332. BEGIN
  333. RETURN NOT (
  334. _cm_is_simpleclass(TableId)
  335. OR _cm_is_system(TableId)
  336. OR _cm_check_comment(_cm_comment_for_attribute(TableId, AttributeName), 'MODE', 'reserved')
  337. );
  338. END
  339. $$;
  340. CREATE FUNCTION _cm_attribute_root_table_id(tableid oid, attributename text) RETURNS oid
  341. LANGUAGE plpgsql
  342. AS $$
  343. DECLARE
  344. CurrentTableId oid := TableId;
  345. BEGIN
  346. LOOP
  347. EXIT WHEN CurrentTableId IS NULL OR _cm_attribute_is_local(CurrentTableId, AttributeName);
  348. CurrentTableId := _cm_parent_id(CurrentTableId);
  349. END LOOP;
  350. RETURN CurrentTableId;
  351. END
  352. $$;
  353. CREATE FUNCTION _cm_attribute_set_notnull(tableid oid, attributename text, willbenotnull boolean) RETURNS void
  354. LANGUAGE plpgsql
  355. AS $$
  356. DECLARE
  357. AttributeComment text := _cm_comment_for_attribute(TableId, AttributeName);
  358. BEGIN
  359. IF WillBeNotNull = _cm_attribute_is_notnull(TableId, AttributeName) THEN
  360. RETURN;
  361. END IF;
  362. IF WillBeNotNull AND _cm_is_superclass(TableId) AND _cm_check_comment(AttributeComment, 'MODE', 'write')
  363. THEN
  364. RAISE NOTICE 'Non-system superclass attributes cannot be not null';
  365. RAISE EXCEPTION 'CM_FORBIDDEN_OPERATION';
  366. END IF;
  367. PERFORM _cm_attribute_set_notnull_unsafe(TableId, AttributeName, WillBeNotNull);
  368. END;
  369. $$;
  370. CREATE FUNCTION _cm_attribute_set_notnull_unsafe(tableid oid, attributename text, willbenotnull boolean) RETURNS void
  371. LANGUAGE plpgsql
  372. AS $$
  373. DECLARE
  374. IsCheck boolean := _cm_attribute_notnull_is_check(TableId, AttributeName);
  375. BEGIN
  376. IF (WillBeNotNull) THEN
  377. IF (IsCheck) THEN
  378. EXECUTE 'ALTER TABLE '|| TableId::regclass ||
  379. ' ADD CONSTRAINT ' || quote_ident(_cm_notnull_constraint_name(AttributeName)) ||
  380. ' CHECK ("Status"<>''A'' OR ' || quote_ident(AttributeName) || ' IS NOT NULL)';
  381. ELSE
  382. EXECUTE 'ALTER TABLE '|| TableId::regclass ||' ALTER COLUMN '|| quote_ident(AttributeName) ||' SET NOT NULL';
  383. END IF;
  384. ELSE
  385. IF (IsCheck) THEN
  386. EXECUTE 'ALTER TABLE '|| TableId::regclass ||' DROP CONSTRAINT '||
  387. quote_ident(_cm_notnull_constraint_name(AttributeName));
  388. ELSE
  389. EXECUTE 'ALTER TABLE '|| TableId::regclass ||' ALTER COLUMN '|| quote_ident(AttributeName) ||' DROP NOT NULL';
  390. END IF;
  391. END IF;
  392. END;
  393. $$;
  394. CREATE FUNCTION _cm_attribute_set_uniqueness(tableid oid, attributename text, attributeunique boolean) RETURNS void
  395. LANGUAGE plpgsql
  396. AS $$
  397. BEGIN
  398. IF _cm_attribute_is_unique(TableId, AttributeName) <> AttributeUnique THEN
  399. IF AttributeUnique AND (_cm_is_simpleclass(TableId) OR _cm_is_superclass(TableId)) AND NOT _cm_is_system(TableId) THEN
  400. RAISE NOTICE 'User defined superclass or simple class attributes cannot be unique';
  401. RAISE EXCEPTION 'CM_FORBIDDEN_OPERATION';
  402. END IF;
  403. PERFORM _cm_attribute_set_uniqueness_unsafe(TableId, AttributeName, AttributeUnique);
  404. END IF;
  405. END;
  406. $$;
  407. CREATE FUNCTION _cm_attribute_set_uniqueness_unsafe(tableid oid, attributename text, attributeunique boolean) RETURNS void
  408. LANGUAGE plpgsql
  409. AS $$
  410. BEGIN
  411. IF _cm_is_simpleclass(TableId) THEN
  412. IF AttributeUnique THEN
  413. EXECUTE 'ALTER TABLE '|| TableId::regclass ||' ADD UNIQUE ('|| quote_ident(AttributeName) || ')';
  414. ELSE
  415. EXECUTE 'ALTER TABLE '|| TableId::regclass ||' DROP UNIQUE ('|| quote_ident(AttributeName) || ')';
  416. END IF;
  417. ELSE
  418. IF AttributeUnique THEN
  419. EXECUTE 'CREATE UNIQUE INDEX '||
  420. quote_ident(_cm_unique_index_name(TableId, AttributeName)) ||
  421. ' ON '|| TableId::regclass ||' USING btree (('||
  422. ' CASE WHEN "Status"::text = ''N''::text THEN NULL'||
  423. ' ELSE '|| quote_ident(AttributeName) || ' END))';
  424. ELSE
  425. EXECUTE 'DROP INDEX '|| _cm_unique_index_id(TableId, AttributeName)::regclass;
  426. END IF;
  427. END IF;
  428. END
  429. $$;
  430. CREATE FUNCTION _cm_cascade(id integer, tableid oid, attributename text) RETURNS void
  431. LANGUAGE plpgsql
  432. AS $$
  433. BEGIN
  434. EXECUTE 'DELETE FROM '|| TableId::regclass ||
  435. ' WHERE '||quote_ident(AttributeName)||' = '||Id::text;
  436. END;
  437. $$;
  438. CREATE FUNCTION _cm_check_attribute_comment_and_type(attributecomment text, sqltype text) RETURNS void
  439. LANGUAGE plpgsql
  440. AS $$
  441. DECLARE
  442. SpecialTypeCount integer := 0;
  443. BEGIN
  444. IF _cm_read_reference_domain_comment(AttributeComment) IS NOT NULL THEN
  445. SpecialTypeCount := SpecialTypeCount +1;
  446. END IF;
  447. IF _cm_get_fk_target_comment(AttributeComment) IS NOT NULL THEN
  448. SpecialTypeCount := SpecialTypeCount +1;
  449. END IF;
  450. IF _cm_get_lookup_type_comment(AttributeComment) IS NOT NULL THEN
  451. SpecialTypeCount := SpecialTypeCount +1;
  452. END IF;
  453. IF (SpecialTypeCount > 1) THEN
  454. RAISE NOTICE 'Too many CMDBuild types specified';
  455. RAISE EXCEPTION 'CM_FORBIDDEN_OPERATION';
  456. END IF;
  457. IF SpecialTypeCount = 1 AND SQLType NOT IN ('int4','integer') THEN
  458. RAISE NOTICE 'The SQL type does not match the CMDBuild type';
  459. RAISE EXCEPTION 'CM_FORBIDDEN_OPERATION';
  460. END IF;
  461. END;
  462. $$;
  463. CREATE FUNCTION _cm_check_comment(classcomment text, key text, value text) RETURNS boolean
  464. LANGUAGE sql STABLE
  465. AS $_$
  466. SELECT (_cm_read_comment($1, $2) ILIKE $3);
  467. $_$;
  468. CREATE FUNCTION _cm_check_id_exists(id integer, tableid oid, deletedalso boolean) RETURNS boolean
  469. LANGUAGE sql STABLE
  470. AS $_$
  471. SELECT _cm_check_value_exists($1, $2, 'Id', $3);
  472. $_$;
  473. CREATE FUNCTION _cm_check_value_exists(id integer, tableid oid, attributename text, deletedalso boolean) RETURNS boolean
  474. LANGUAGE plpgsql STABLE
  475. AS $$
  476. DECLARE
  477. Out BOOLEAN := TRUE;
  478. StatusPart TEXT;
  479. BEGIN
  480. IF _cm_is_simpleclass(TableId) OR DeletedAlso THEN
  481. StatusPart := '';
  482. ELSE
  483. StatusPart := ' AND "Status"=''A''';
  484. END IF;
  485. IF Id IS NOT NULL THEN
  486. EXECUTE 'SELECT (COUNT(*) > 0) FROM '|| TableId::regclass ||' WHERE '||
  487. quote_ident(AttributeName)||'='||Id||StatusPart||' LIMIT 1' INTO Out;
  488. END IF;
  489. RETURN Out;
  490. END
  491. $$;
  492. CREATE FUNCTION _cm_class_has_children(tableid oid) RETURNS boolean
  493. LANGUAGE sql STABLE
  494. AS $_$
  495. SELECT (COUNT(*) > 0) FROM pg_inherits WHERE inhparent = $1 AND _cm_is_cmobject(inhrelid) LIMIT 1;
  496. $_$;
  497. CREATE FUNCTION _cm_class_has_domains(tableid oid) RETURNS boolean
  498. LANGUAGE sql
  499. AS $_$
  500. SELECT (COUNT(*) > 0) FROM _cm_domain_list() AS d
  501. WHERE _cm_table_id(_cm_read_comment(_cm_comment_for_cmobject(d), 'CLASS1')) = $1 OR
  502. _cm_table_id(_cm_read_comment(_cm_comment_for_cmobject(d), 'CLASS2')) = $1;
  503. $_$;
  504. CREATE FUNCTION _cm_class_list() RETURNS SETOF oid
  505. LANGUAGE sql STABLE
  506. AS $$
  507. SELECT oid FROM pg_class WHERE _cm_is_any_class_comment(_cm_comment_for_cmobject(oid));
  508. $$;
  509. CREATE FUNCTION _cm_classfk_name(cmclassname text, attributename text) RETURNS text
  510. LANGUAGE sql IMMUTABLE
  511. AS $_$
  512. SELECT _cm_cmtable($1) || '_' || $2 || '_fkey';
  513. $_$;
  514. CREATE FUNCTION _cm_classfk_name(tableid oid, attributename text) RETURNS text
  515. LANGUAGE sql IMMUTABLE
  516. AS $_$
  517. SELECT _cm_cmtable($1) || '_' || $2 || '_fkey';
  518. $_$;
  519. CREATE FUNCTION _cm_classidx_name(tableid oid, attributename text) RETURNS text
  520. LANGUAGE sql IMMUTABLE
  521. AS $_$
  522. SELECT 'idx_' || REPLACE(_cm_cmtable_lc($1), '_', '') || '_' || lower($2);
  523. $_$;
  524. CREATE FUNCTION _cm_classpk_name(cmclassname text) RETURNS text
  525. LANGUAGE sql IMMUTABLE
  526. AS $_$
  527. SELECT _cm_cmtable($1) || '_pkey';
  528. $_$;
  529. CREATE FUNCTION _cm_cmschema(cmname text) RETURNS text
  530. LANGUAGE sql IMMUTABLE
  531. AS $_$
  532. SELECT (_cm_split_cmname($1))[1];
  533. $_$;
  534. CREATE FUNCTION _cm_cmschema(tableid oid) RETURNS text
  535. LANGUAGE sql STABLE
  536. AS $_$
  537. SELECT pg_namespace.nspname::text FROM pg_class
  538. JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid
  539. WHERE pg_class.oid=$1
  540. $_$;
  541. CREATE FUNCTION _cm_cmtable(cmname text) RETURNS text
  542. LANGUAGE sql IMMUTABLE
  543. AS $_$
  544. SELECT (_cm_split_cmname($1))[2];
  545. $_$;
  546. CREATE FUNCTION _cm_cmtable(tableid oid) RETURNS text
  547. LANGUAGE sql STABLE
  548. AS $_$
  549. SELECT pg_class.relname::text FROM pg_class WHERE pg_class.oid=$1
  550. $_$;
  551. CREATE FUNCTION _cm_cmtable_lc(cmname text) RETURNS text
  552. LANGUAGE sql IMMUTABLE
  553. AS $_$
  554. SELECT lower(_cm_cmtable($1));
  555. $_$;
  556. CREATE FUNCTION _cm_cmtable_lc(tableid oid) RETURNS text
  557. LANGUAGE sql IMMUTABLE
  558. AS $_$
  559. SELECT lower(_cm_cmtable($1));
  560. $_$;
  561. CREATE FUNCTION _cm_comment_for_attribute(tableid oid, attributename text) RETURNS text
  562. LANGUAGE sql STABLE
  563. AS $_$
  564. SELECT description
  565. FROM pg_description
  566. JOIN pg_attribute ON pg_description.objoid = pg_attribute.attrelid AND pg_description.objsubid = pg_attribute.attnum
  567. WHERE attrelid = $1 and attname = $2 LIMIT 1;
  568. $_$;
  569. CREATE FUNCTION _cm_comment_for_class(cmclass text) RETURNS text
  570. LANGUAGE sql STABLE
  571. AS $_$
  572. SELECT _cm_comment_for_table_id(_cm_table_id($1));
  573. $_$;
  574. CREATE FUNCTION _cm_comment_for_cmobject(tableid oid) RETURNS text
  575. LANGUAGE sql STABLE
  576. AS $_$
  577. SELECT description FROM pg_description
  578. WHERE objoid = $1 AND objsubid = 0 AND _cm_read_comment(description, 'TYPE') IS NOT NULL LIMIT 1;
  579. $_$;
  580. CREATE FUNCTION _cm_comment_for_domain(cmdomain text) RETURNS text
  581. LANGUAGE sql STABLE STRICT
  582. AS $_$
  583. SELECT _cm_comment_for_table_id(_cm_domain_id($1));
  584. $_$;
  585. CREATE FUNCTION _cm_comment_for_table_id(tableid oid) RETURNS text
  586. LANGUAGE sql STABLE
  587. AS $_$
  588. SELECT description FROM pg_description WHERE objoid = $1;
  589. $_$;
  590. CREATE FUNCTION _cm_copy_fk_trigger(fromid oid, toid oid) RETURNS void
  591. LANGUAGE sql
  592. AS $_$
  593. SELECT _cm_copy_trigger($1, $2, '%_fkey');
  594. $_$;
  595. CREATE FUNCTION _cm_copy_restrict_trigger(fromid oid, toid oid) RETURNS void
  596. LANGUAGE sql
  597. AS $_$
  598. SELECT _cm_copy_trigger($1, $2, '_Constr_%');
  599. $_$;
  600. CREATE FUNCTION _cm_copy_superclass_attribute_comments(tableid oid, parenttableid oid) RETURNS void
  601. LANGUAGE plpgsql
  602. AS $$
  603. DECLARE
  604. AttributeName text;
  605. BEGIN
  606. FOR AttributeName IN SELECT * FROM _cm_attribute_list(ParentTableId)
  607. LOOP
  608. EXECUTE 'COMMENT ON COLUMN '|| TableId::regclass || '.' || quote_ident(AttributeName) ||
  609. ' IS '|| quote_literal(_cm_comment_for_attribute(ParentTableId, AttributeName));
  610. END LOOP;
  611. END
  612. $$;
  613. CREATE FUNCTION _cm_copy_trigger(fromid oid, toid oid, triggernamematcher text) RETURNS void
  614. LANGUAGE plpgsql
  615. AS $$
  616. DECLARE
  617. TriggerData record;
  618. BEGIN
  619. FOR TriggerData IN
  620. SELECT
  621. t.tgname AS TriggerName,
  622. t.tgtype AS TriggerType,
  623. p.proname AS TriggerFunction,
  624. array_to_string(array(
  625. SELECT quote_literal(q.param)
  626. FROM (SELECT regexp_split_to_table(encode(tgargs, 'escape'), E'\\\\000') AS param) AS q
  627. WHERE q.param <> ''
  628. ),',') AS TriggerParams
  629. FROM pg_trigger t, pg_proc p
  630. WHERE tgrelid = FromId AND tgname LIKE TriggerNameMatcher AND t.tgfoid = p.oid
  631. LOOP
  632. EXECUTE '
  633. CREATE TRIGGER '|| quote_ident(TriggerData.TriggerName) ||'
  634. '|| _cm_trigger_when(TriggerData.TriggerType) ||'
  635. ON '|| ToId::regclass ||'
  636. FOR EACH '|| _cm_trigger_row_or_statement(TriggerData.TriggerType) ||'
  637. EXECUTE PROCEDURE '|| quote_ident(TriggerData.TriggerFunction) ||'('|| TriggerData.TriggerParams ||')
  638. ';
  639. END LOOP;
  640. END;
  641. $$;
  642. CREATE FUNCTION _cm_copy_update_relation_trigger(fromid oid, toid oid) RETURNS void
  643. LANGUAGE sql
  644. AS $_$
  645. SELECT _cm_copy_trigger($1, $2, '_UpdRel_%');
  646. $_$;
  647. CREATE FUNCTION _cm_create_class_history(cmclassname text) RETURNS void
  648. LANGUAGE plpgsql
  649. AS $$
  650. BEGIN
  651. EXECUTE '
  652. CREATE TABLE '|| _cm_history_dbname_unsafe(CMClassName) ||'
  653. (
  654. "CurrentId" int4 NOT NULL,
  655. "EndDate" timestamp NOT NULL DEFAULT now(),
  656. CONSTRAINT ' || quote_ident(_cm_historypk_name(CMClassName)) ||' PRIMARY KEY ("Id"),
  657. CONSTRAINT '|| quote_ident(_cm_historyfk_name(CMClassName, 'CurrentId')) ||' FOREIGN KEY ("CurrentId")
  658. REFERENCES '||_cm_table_dbname(CMClassName)||' ("Id") ON UPDATE RESTRICT ON DELETE SET NULL
  659. ) INHERITS ('||_cm_table_dbname(CMClassName)||');
  660. ';
  661. PERFORM _cm_create_index(_cm_history_id(CMClassName), 'CurrentId');
  662. END;
  663. $$;
  664. CREATE FUNCTION _cm_create_class_indexes(tableid oid) RETURNS void
  665. LANGUAGE plpgsql
  666. AS $$
  667. BEGIN
  668. PERFORM _cm_create_index(TableId, 'Code');
  669. PERFORM _cm_create_index(TableId, 'Description');
  670. PERFORM _cm_create_index(TableId, 'IdClass');
  671. END;
  672. $$;
  673. CREATE FUNCTION _cm_create_class_triggers(tableid oid) RETURNS void
  674. LANGUAGE plpgsql
  675. AS $$
  676. BEGIN
  677. IF _cm_is_superclass(TableId) THEN
  678. RAISE DEBUG 'Not creating triggers for class %', TableId::regclass;
  679. ELSIF _cm_is_simpleclass(TableId) THEN
  680. PERFORM _cm_add_simpleclass_sanity_check_trigger(TableId);
  681. ELSE
  682. PERFORM _cm_add_class_sanity_check_trigger(TableId);
  683. PERFORM _cm_add_class_history_trigger(TableId);
  684. PERFORM _cm_add_class_cascade_delete_on_relations_trigger(TableId);
  685. END IF;
  686. END;
  687. $$;
  688. CREATE FUNCTION _cm_create_domain_indexes(domainid oid) RETURNS void
  689. LANGUAGE plpgsql
  690. AS $$
  691. DECLARE
  692. Cardinality text := _cm_domain_cardinality(DomainId);
  693. BEGIN
  694. PERFORM _cm_create_index(DomainId, 'IdDomain');
  695. PERFORM _cm_create_index(DomainId, 'IdObj1');
  696. PERFORM _cm_create_index(DomainId, 'IdObj2');
  697. EXECUTE 'CREATE UNIQUE INDEX ' || quote_ident(_cm_domainidx_name(DomainId, 'ActiveRows')) ||
  698. ' ON ' || DomainId::regclass ||
  699. ' USING btree ('||
  700. '(CASE WHEN "Status" = ''N'' THEN NULL ELSE "IdDomain" END),'||
  701. '(CASE WHEN "Status" = ''N'' THEN NULL ELSE "IdClass1" END),'||
  702. '(CASE WHEN "Status" = ''N'' THEN NULL ELSE "IdObj1" END),'||
  703. '(CASE WHEN "Status" = ''N'' THEN NULL ELSE "IdClass2" END),'||
  704. '(CASE WHEN "Status" = ''N'' THEN NULL ELSE "IdObj2" END)'||
  705. ')';
  706. IF substring(Cardinality, 3, 1) = '1' THEN
  707. EXECUTE
  708. 'CREATE UNIQUE INDEX ' || quote_ident(_cm_domainidx_name(DomainId,'UniqueLeft')) ||
  709. ' ON ' || DomainId::regclass ||
  710. ' USING btree ( '||
  711. '(CASE WHEN "Status"::text = ''A'' THEN "IdClass1" ELSE NULL END),'||
  712. '(CASE WHEN "Status"::text = ''A'' THEN "IdObj1" ELSE NULL END)'||
  713. ' )';
  714. END IF;
  715. IF substring(Cardinality, 1, 1) = '1' THEN
  716. EXECUTE
  717. 'CREATE UNIQUE INDEX ' || quote_ident(_cm_domainidx_name(DomainId,'UniqueRight')) ||
  718. ' ON ' || DomainId::regclass ||
  719. ' USING btree ( '||
  720. '(CASE WHEN "Status"::text = ''A'' THEN "IdClass2" ELSE NULL END),'||
  721. '(CASE WHEN "Status"::text = ''A'' THEN "IdObj2" ELSE NULL END)'||
  722. ' )';
  723. END IF;
  724. END
  725. $$;
  726. CREATE FUNCTION _cm_create_domain_triggers(domainid oid) RETURNS void
  727. LANGUAGE plpgsql
  728. AS $$
  729. BEGIN
  730. PERFORM _cm_add_domain_sanity_check_trigger(DomainId);
  731. PERFORM _cm_add_domain_history_trigger(DomainId);
  732. END;
  733. $$;
  734. CREATE FUNCTION _cm_create_index(tableid oid, attributename text) RETURNS void
  735. LANGUAGE plpgsql
  736. AS $$
  737. BEGIN
  738. EXECUTE 'CREATE INDEX ' || quote_ident(_cm_classidx_name(TableId, AttributeName)) ||
  739. ' ON ' || TableId::regclass ||
  740. ' USING btree (' || quote_ident(AttributeName) || ')';
  741. EXCEPTION
  742. WHEN undefined_column THEN
  743. RAISE LOG 'Index for attribute %.% not created because the attribute does not exist',
  744. TableId::regclass, quote_ident(AttributeName);
  745. END
  746. $$;
  747. CREATE FUNCTION _cm_create_schema_if_needed(cmname text) RETURNS void
  748. LANGUAGE plpgsql
  749. AS $$
  750. BEGIN
  751. IF _cm_cmschema(CMName) IS NOT NULL THEN
  752. EXECUTE 'CREATE SCHEMA '||quote_ident(_cm_cmschema(CMName));
  753. END IF;
  754. EXCEPTION
  755. WHEN duplicate_schema THEN
  756. RETURN;
  757. END;
  758. $$;
  759. CREATE FUNCTION _cm_delete_local_attributes(tableid oid) RETURNS void
  760. LANGUAGE plpgsql
  761. AS $$
  762. DECLARE
  763. AttributeName text;
  764. BEGIN
  765. FOR AttributeName IN SELECT _cm_attribute_list(TableId) LOOP
  766. IF NOT _cm_attribute_is_inherited(TableId, AttributeName) THEN
  767. PERFORM cm_delete_attribute(TableId, AttributeName);
  768. END IF;
  769. END LOOP;
  770. END
  771. $$;
  772. CREATE FUNCTION _cm_delete_relation(username text, domainid oid, cardidcolumn text, cardid integer) RETURNS void
  773. LANGUAGE plpgsql
  774. AS $$
  775. DECLARE
  776. BEGIN
  777. EXECUTE 'UPDATE ' || DomainId::regclass ||
  778. ' SET "Status" = ''N'', "User" = ' || coalesce(quote_literal(UserName),'NULL') ||
  779. ' WHERE "Status" = ''A'' AND ' || quote_ident(CardIdColumn) || ' = ' || CardId;
  780. END;
  781. $$;
  782. CREATE FUNCTION _cm_dest_classid_for_domain_attribute(domainid oid, attributename text) RETURNS oid
  783. LANGUAGE sql STABLE STRICT
  784. AS $_$
  785. SELECT _cm_table_id(
  786. _cm_read_comment(
  787. _cm_comment_for_table_id($1),
  788. CASE $2
  789. WHEN 'IdObj1' THEN
  790. 'CLASS1'
  791. WHEN 'IdObj2' THEN
  792. 'CLASS2'
  793. ELSE
  794. NULL
  795. END
  796. )
  797. );
  798. $_$;
  799. CREATE FUNCTION _cm_dest_reference_classid(domainid oid, refidcolumn text, refid integer) RETURNS oid
  800. LANGUAGE sql STABLE STRICT
  801. AS $_$
  802. SELECT _cm_subclassid(_cm_dest_classid_for_domain_attribute($1, $2), $3)
  803. $_$;
  804. CREATE FUNCTION _cm_disable_triggers_recursively(superclass regclass) RETURNS void
  805. LANGUAGE plpgsql
  806. AS $_$
  807. DECLARE
  808. CurrentClass regclass := $1;
  809. BEGIN
  810. FOR CurrentClass IN SELECT _cm_subtables_and_itself(SuperClass) LOOP
  811. EXECUTE 'ALTER TABLE '|| CurrentClass::regclass ||' DISABLE TRIGGER USER';
  812. END LOOP;
  813. END;
  814. $_$;
  815. CREATE FUNCTION _cm_domain_cardinality(domainid oid) RETURNS text
  816. LANGUAGE sql STABLE
  817. AS $_$
  818. SELECT _cm_read_domain_cardinality(_cm_comment_for_table_id($1));
  819. $_$;
  820. CREATE FUNCTION _cm_domain_cmname(cmdomain text) RETURNS text
  821. LANGUAGE sql IMMUTABLE
  822. AS $_$
  823. SELECT coalesce(_cm_cmschema($1)||'.','')||coalesce('Map_'||_cm_cmtable($1),'Map');
  824. $_$;
  825. CREATE FUNCTION _cm_domain_cmname_lc(cmdomainname text) RETURNS text
  826. LANGUAGE sql IMMUTABLE
  827. AS $_$
  828. SELECT lower(_cm_domain_cmname($1));
  829. $_$;
  830. CREATE FUNCTION _cm_domain_dbname(cmdomain text) RETURNS regclass
  831. LANGUAGE sql STABLE
  832. AS $_$
  833. SELECT _cm_table_dbname(_cm_domain_cmname($1));
  834. $_$;
  835. CREATE FUNCTION _cm_domain_dbname_unsafe(cmdomain text) RETURNS text
  836. LANGUAGE sql IMMUTABLE
  837. AS $_$
  838. SELECT _cm_table_dbname_unsafe(_cm_domain_cmname($1));
  839. $_$;
  840. CREATE FUNCTION _cm_domain_direction(domainid oid) RETURNS boolean
  841. LANGUAGE plpgsql STABLE STRICT
  842. AS $$
  843. DECLARE
  844. Cardinality text := _cm_domain_cardinality(DomainId);
  845. BEGIN
  846. IF Cardinality = 'N:1' THEN
  847. RETURN TRUE;
  848. ELSIF Cardinality = '1:N' THEN
  849. RETURN FALSE;
  850. ELSE
  851. RETURN NULL;
  852. END IF;
  853. END
  854. $$;
  855. CREATE FUNCTION _cm_domain_id(cmdomain text) RETURNS oid
  856. LANGUAGE sql STABLE STRICT
  857. AS $_$
  858. SELECT _cm_table_id(_cm_domain_cmname($1));
  859. $_$;
  860. CREATE FUNCTION _cm_domain_list() RETURNS SETOF oid
  861. LANGUAGE sql STABLE
  862. AS $$
  863. SELECT oid FROM pg_class WHERE _cm_is_domain_comment(_cm_comment_for_cmobject(oid));
  864. $$;
  865. CREATE FUNCTION _cm_domainidx_name(domainid oid, type text) RETURNS text
  866. LANGUAGE sql IMMUTABLE
  867. AS $_$
  868. SELECT 'idx_' || _cm_cmtable_lc($1) || '_' || lower($2);
  869. $_$;
  870. CREATE FUNCTION _cm_domainpk_name(cmdomainname text) RETURNS text
  871. LANGUAGE sql IMMUTABLE
  872. AS $_$
  873. SELECT _cm_classpk_name(_cm_domain_cmname($1));
  874. $_$;
  875. CREATE FUNCTION _cm_drop_triggers_recursively(tableid oid, triggername text) RETURNS void
  876. LANGUAGE plpgsql
  877. AS $$
  878. DECLARE
  879. SubClassId oid;
  880. BEGIN
  881. FOR SubClassId IN SELECT _cm_subtables_and_itself(TableId) LOOP
  882. EXECUTE 'DROP TRIGGER IF EXISTS '|| quote_ident(TriggerName) ||' ON '|| SubClassId::regclass;
  883. END LOOP;
  884. END;
  885. $$;
  886. CREATE FUNCTION _cm_enable_triggers_recursively(superclass regclass) RETURNS void
  887. LANGUAGE plpgsql
  888. AS $_$
  889. DECLARE
  890. CurrentClass regclass := $1;
  891. BEGIN
  892. FOR CurrentClass IN SELECT _cm_subtables_and_itself(SuperClass) LOOP
  893. EXECUTE 'ALTER TABLE '|| CurrentClass::text ||' ENABLE TRIGGER USER';
  894. END LOOP;
  895. END;
  896. $_$;
  897. CREATE FUNCTION _cm_function_list(OUT function_name text, OUT function_id oid, OUT arg_io character[], OUT arg_names text[], OUT arg_types text[], OUT returns_set boolean) RETURNS SETOF record
  898. LANGUAGE plpgsql STABLE
  899. AS $_$
  900. DECLARE
  901. R record;
  902. i integer;
  903. BEGIN
  904. FOR R IN
  905. SELECT *
  906. FROM pg_proc
  907. WHERE _cm_comment_for_cmobject(oid) IS NOT NULL
  908. LOOP
  909. function_name := R.proname::text;
  910. function_id := R.oid;
  911. returns_set := R.proretset;
  912. IF R.proargmodes IS NULL
  913. THEN
  914. arg_io := '{}'::char[];
  915. arg_types := '{}'::text[];
  916. arg_names := '{}'::text[];
  917. -- add input columns
  918. FOR i IN SELECT generate_series(1, array_upper(R.proargtypes,1)) LOOP
  919. arg_io := arg_io || 'i'::char;
  920. arg_types := arg_types || _cm_get_sqltype_string(R.proargtypes[i], NULL);
  921. arg_names := arg_names || COALESCE(R.proargnames[i], '$'||i);
  922. END LOOP;
  923. -- add single output column
  924. arg_io := arg_io || 'o'::char;
  925. arg_types := arg_types || _cm_get_sqltype_string(R.prorettype, NULL);
  926. arg_names := arg_names || function_name;
  927. ELSE
  928. -- just normalize existing columns
  929. arg_io := R.proargmodes;
  930. arg_types := '{}'::text[];
  931. arg_names := R.proargnames;
  932. FOR i IN SELECT generate_series(1, array_upper(arg_io,1)) LOOP
  933. -- normalize table output
  934. IF arg_io[i] = 't' THEN
  935. arg_io[i] := 'o';
  936. ELSIF arg_io[i] = 'b' THEN
  937. arg_io[i] := 'io';
  938. END IF;
  939. arg_types := arg_types || _cm_get_sqltype_string(R.proallargtypes[i], NULL);
  940. IF arg_names[i] = '' THEN
  941. IF arg_io[i] = 'i' THEN
  942. arg_names[i] = '$'||i;
  943. ELSE
  944. arg_names[i] = 'column'||i;
  945. END IF;
  946. END IF;
  947. END LOOP;
  948. END IF;
  949. RETURN NEXT;
  950. END LOOP;
  951. RETURN;
  952. END
  953. $_$;
  954. CREATE FUNCTION _cm_get_attribute_default(tableid oid, attributename text) RETURNS text
  955. LANGUAGE sql STABLE
  956. AS $_$
  957. SELECT pg_attrdef.adsrc
  958. FROM pg_attribute JOIN pg_attrdef ON pg_attrdef.adrelid = pg_attribute.attrelid AND pg_attrdef.adnum = pg_attribute.attnum
  959. WHERE pg_attribute.attrelid = $1 AND pg_attribute.attname = $2;
  960. $_$;
  961. CREATE FUNCTION _cm_get_attribute_sqltype(tableid oid, attributename text) RETURNS text
  962. LANGUAGE sql STABLE
  963. AS $_$
  964. SELECT _cm_get_sqltype_string(pg_attribute.atttypid, pg_attribute.atttypmod)
  965. FROM pg_attribute
  966. WHERE pg_attribute.attrelid = $1 AND pg_attribute.attname = $2;
  967. $_$;
  968. CREATE FUNCTION _cm_get_domain_reference_target_comment(domaincomment text) RETURNS text
  969. LANGUAGE sql STABLE STRICT
  970. AS $_$
  971. SELECT CASE _cm_read_domain_cardinality($1)
  972. WHEN '1:N' THEN _cm_read_comment($1, 'CLASS1')
  973. WHEN 'N:1' THEN _cm_read_comment($1, 'CLASS2')
  974. ELSE NULL
  975. END
  976. $_$;
  977. CREATE FUNCTION _cm_get_fk_target(tableid oid, attributename text) RETURNS text
  978. LANGUAGE plpgsql STABLE STRICT
  979. AS $$
  980. DECLARE
  981. AttributeComment text := _cm_comment_for_attribute(TableId, AttributeName);
  982. BEGIN
  983. RETURN COALESCE(
  984. _cm_get_fk_target_comment(AttributeComment),
  985. _cm_read_reference_target_comment(AttributeComment)
  986. );
  987. END
  988. $$;
  989. CREATE FUNCTION _cm_get_fk_target_comment(attributecomment text) RETURNS text
  990. LANGUAGE sql STABLE STRICT
  991. AS $_$
  992. SELECT _cm_read_comment($1, 'FKTARGETCLASS');
  993. $_$;
  994. CREATE FUNCTION _cm_get_fk_target_table_id(tableid oid, attributename text) RETURNS oid
  995. LANGUAGE plpgsql STABLE STRICT
  996. AS $_$ BEGIN
  997. RETURN _cm_table_id(_cm_get_fk_target($1, $2));
  998. END $_$;
  999. CREATE FUNCTION _cm_get_geometry_type(tableid oid, attribute text) RETURNS text
  1000. LANGUAGE plpgsql STABLE
  1001. AS $_$
  1002. DECLARE
  1003. GeoType text;
  1004. BEGIN
  1005. SELECT geometry_columns.type INTO GeoType
  1006. FROM pg_attribute
  1007. LEFT JOIN geometry_columns
  1008. ON f_table_schema = _cm_cmschema($1)
  1009. AND f_table_name = _cm_cmtable($1)
  1010. AND f_geometry_column = $2
  1011. WHERE attrelid = $1 AND attname = $2 AND attnum > 0 AND atttypid > 0;
  1012. RETURN GeoType;
  1013. EXCEPTION WHEN undefined_table THEN
  1014. RETURN NULL;
  1015. END
  1016. $_$;
  1017. CREATE FUNCTION _cm_get_lookup_type_comment(attributecomment text) RETURNS text
  1018. LANGUAGE sql
  1019. AS $_$
  1020. SELECT _cm_read_comment($1, 'LOOKUP');
  1021. $_$;
  1022. CREATE FUNCTION _cm_get_ref_source_class_domain_attribute(tableid oid, attributename text) RETURNS text
  1023. LANGUAGE sql STABLE
  1024. AS $_$
  1025. SELECT CASE _cm_domain_direction(_cm_get_reference_domain_id($1, $2))
  1026. WHEN TRUE THEN 'IdClass1'
  1027. WHEN FALSE THEN 'IdClass2'
  1028. ELSE NULL
  1029. END;
  1030. $_$;
  1031. CREATE FUNCTION _cm_get_ref_source_id_domain_attribute(tableid oid, attributename text) RETURNS text
  1032. LANGUAGE sql STABLE
  1033. AS $_$
  1034. SELECT CASE _cm_domain_direction(_cm_get_reference_domain_id($1, $2))
  1035. WHEN TRUE THEN 'IdObj1'
  1036. WHEN FALSE THEN 'IdObj2'
  1037. ELSE NULL
  1038. END;
  1039. $_$;
  1040. CREATE FUNCTION _cm_get_ref_target_id_domain_attribute(tableid oid, attributename text) RETURNS text
  1041. LANGUAGE sql STABLE
  1042. AS $_$
  1043. SELECT CASE _cm_domain_direction(_cm_get_reference_domain_id($1, $2))
  1044. WHEN TRUE THEN 'IdObj2'
  1045. WHEN FALSE THEN 'IdObj1'
  1046. ELSE NULL
  1047. END;
  1048. $_$;
  1049. CREATE FUNCTION _cm_get_reference_domain_id(tableid oid, attributename text) RETURNS oid
  1050. LANGUAGE sql STABLE
  1051. AS $_$
  1052. SELECT _cm_read_reference_domain_id_comment(_cm_comment_for_attribute($1, $2));
  1053. $_$;
  1054. CREATE FUNCTION _cm_get_sqltype_string(sqltypeid oid, typemod integer) RETURNS text
  1055. LANGUAGE sql STABLE
  1056. AS $_$
  1057. SELECT pg_type.typname::text || COALESCE(
  1058. CASE
  1059. WHEN pg_type.typname IN ('varchar','bpchar') THEN '(' || $2 - 4 || ')'
  1060. WHEN pg_type.typname = 'numeric' THEN '(' ||
  1061. $2 / 65536 || ',' ||
  1062. $2 - $2 / 65536 * 65536 - 4|| ')'
  1063. END, '')
  1064. FROM pg_type WHERE pg_type.oid = $1;
  1065. $_$;
  1066. CREATE FUNCTION _cm_get_type_comment(classcomment text) RETURNS text
  1067. LANGUAGE sql STABLE STRICT
  1068. AS $_$
  1069. SELECT _cm_read_comment($1, 'TYPE');
  1070. $_$;
  1071. CREATE FUNCTION _cm_history_cmname(cmclass text) RETURNS text
  1072. LANGUAGE sql IMMUTABLE
  1073. AS $_$
  1074. SELECT $1 || '_history';
  1075. $_$;
  1076. CREATE FUNCTION _cm_history_dbname(cmtable text) RETURNS regclass
  1077. LANGUAGE sql STABLE
  1078. AS $_$
  1079. SELECT _cm_table_dbname(_cm_history_cmname($1));
  1080. $_$;
  1081. CREATE FUNCTION _cm_history_dbname_unsafe(cmtable text) RETURNS text
  1082. LANGUAGE sql IMMUTABLE
  1083. AS $_$
  1084. SELECT _cm_table_dbname_unsafe(_cm_history_cmname($1));
  1085. $_$;
  1086. CREATE FUNCTION _cm_history_id(cmtable text) RETURNS oid
  1087. LANGUAGE sql STABLE
  1088. AS $_$
  1089. SELECT _cm_table_id(_cm_history_cmname($1));
  1090. $_$;
  1091. CREATE FUNCTION _cm_historyfk_name(cmclassname text, attributename text) RETURNS text
  1092. LANGUAGE sql IMMUTABLE
  1093. AS $_$
  1094. SELECT _cm_classfk_name(_cm_history_cmname($1), $2);
  1095. $_$;
  1096. CREATE FUNCTION _cm_historypk_name(cmclassname text) RETURNS text
  1097. LANGUAGE sql IMMUTABLE
  1098. AS $_$
  1099. SELECT _cm_classpk_name(_cm_history_cmname($1));
  1100. $_$;
  1101. CREATE FUNCTION _cm_insert_relation(username text, domainid oid, cardidcolumn text, cardid integer, refidcolumn text, refid integer, cardclassid oid) RETURNS void
  1102. LANGUAGE plpgsql
  1103. AS $$
  1104. DECLARE
  1105. CardClassIdColumnPart text;
  1106. RefClassIdColumnPart text;
  1107. CardClassIdValuePart text;
  1108. RefClassIdValuePart text;
  1109. StopRecursion boolean;
  1110. BEGIN
  1111. IF (CardId IS NULL OR RefId IS NULL) THEN
  1112. RAISE EXCEPTION 'CM_FORBIDDEN_OPERATION';
  1113. END IF;
  1114. -- Needed for backward compatibility
  1115. CardClassIdColumnPart := coalesce(quote_ident('IdClass'||substring(CardIdColumn from '^IdObj(.)+')) || ', ', '');
  1116. RefClassIdColumnPart := coalesce(quote_ident('IdClass'||substring(RefIdColumn from '^IdObj(.)+')) || ', ', '');
  1117. CardClassIdValuePart := CASE WHEN CardClassIdColumnPart IS NOT NULL THEN (coalesce(CardClassId::text, 'NULL') || ', ') ELSE '' END;
  1118. RefClassIdValuePart := coalesce(_cm_dest_reference_classid(DomainId, RefIdColumn, RefId)::text, 'NULL') || ', ';
  1119. -- Stop trigger recursion
  1120. EXECUTE 'SELECT (COUNT(*) > 0) FROM ' || DomainId::regclass ||
  1121. ' WHERE' ||
  1122. ' "IdDomain" = ' || DomainId::text || -- NOTE: why is this check done?
  1123. ' AND ' || quote_ident(CardIdColumn) || ' = ' || CardId::text ||
  1124. ' AND ' || quote_ident(RefIdColumn) || ' = ' || RefId::text ||
  1125. ' AND "Status" = ''A''' INTO StopRecursion;
  1126. IF NOT StopRecursion THEN
  1127. EXECUTE 'INSERT INTO ' || DomainId::regclass ||
  1128. ' (' ||
  1129. '"IdDomain", ' ||
  1130. quote_ident(CardIdColumn) || ', ' ||
  1131. quote_ident(RefIdColumn) || ', ' ||
  1132. CardClassIdColumnPart ||
  1133. RefClassIdColumnPart ||
  1134. '"Status", ' ||
  1135. '"User"' ||
  1136. ') VALUES (' ||
  1137. DomainId::text || ', ' ||
  1138. CardId::text || ', ' ||
  1139. RefId::text || ', ' ||
  1140. CardClassIdValuePart ||
  1141. RefClassIdValuePart ||
  1142. '''A'', ' ||
  1143. coalesce(quote_literal(UserName), 'NULL') ||
  1144. ')';
  1145. END IF;
  1146. END;
  1147. $$;
  1148. CREATE FUNCTION _cm_is_active_comment(classcomment text) RETURNS boolean
  1149. LANGUAGE sql STABLE
  1150. AS $_$
  1151. SELECT _cm_check_comment($1, 'STATUS', 'active');
  1152. $_$;
  1153. CREATE FUNCTION _cm_is_any_class(classid oid) RETURNS boolean
  1154. LANGUAGE sql STABLE
  1155. AS $_$
  1156. SELECT _cm_is_any_class_comment(_cm_comment_for_table_id($1))
  1157. $_$;
  1158. CREATE FUNCTION _cm_is_any_class_comment(classcomment text) RETURNS boolean
  1159. LANGUAGE sql STABLE
  1160. AS $_$
  1161. SELECT _cm_check_comment($1, 'TYPE', '%class');
  1162. $_$;
  1163. CREATE FUNCTION _cm_is_cmobject(tableid oid) RETURNS boolean
  1164. LANGUAGE sql STABLE
  1165. AS $_$
  1166. SELECT _cm_comment_for_cmobject($1) IS NOT NULL;
  1167. $_$;
  1168. CREATE FUNCTION _cm_is_domain_comment(classcomment text) RETURNS boolean
  1169. LANGUAGE sql STABLE
  1170. AS $_$
  1171. SELECT _cm_check_comment($1, 'TYPE', 'domain');
  1172. $_$;
  1173. CREATE FUNCTION _cm_is_geometry_type(cmattributetype text) RETURNS boolean
  1174. LANGUAGE sql STABLE
  1175. AS $_$
  1176. SELECT $1 IN ('POINT','LINESTRING','POLYGON');
  1177. $_$;
  1178. CREATE FUNCTION _cm_is_process(classid oid) RETURNS boolean
  1179. LANGUAGE sql STABLE
  1180. AS $_$
  1181. SELECT $1 IN (SELECT _cm_subtables_and_itself(_cm_table_id('Activity')));
  1182. $_$;
  1183. CREATE FUNCTION _cm_is_process(cmclass text) RETURNS boolean
  1184. LANGUAGE sql STABLE
  1185. AS $_$
  1186. SELECT _cm_is_process(_cm_table_id($1));
  1187. $_$;
  1188. CREATE FUNCTION _cm_is_reference_comment(attributecomment text) RETURNS boolean
  1189. LANGUAGE sql STABLE STRICT
  1190. AS $_$
  1191. SELECT COALESCE(_cm_read_reference_domain_comment($1),'') != '';
  1192. $_$;
  1193. CREATE FUNCTION _cm_is_simpleclass(cmclass text) RETURNS boolean
  1194. LANGUAGE sql STABLE
  1195. AS $_$
  1196. SELECT _cm_is_simpleclass_comment(_cm_comment_for_class($1));
  1197. $_$;
  1198. CREATE FUNCTION _cm_is_simpleclass(classid oid) RETURNS boolean
  1199. LANGUAGE sql STABLE
  1200. AS $_$
  1201. SELECT _cm_is_simpleclass_comment(_cm_comment_for_table_id($1))
  1202. $_$;
  1203. CREATE FUNCTION _cm_is_simpleclass_comment(classcomment text) RETURNS boolean
  1204. LANGUAGE sql STABLE
  1205. AS $_$
  1206. SELECT _cm_check_comment($1, 'TYPE', 'simpleclass');
  1207. $_$;
  1208. CREATE FUNCTION _cm_is_superclass(cmclass text) RETURNS boolean
  1209. LANGUAGE sql STABLE
  1210. AS $_$
  1211. SELECT _cm_is_superclass_comment(_cm_comment_for_class($1));
  1212. $_$;
  1213. CREATE FUNCTION _cm_is_superclass(classid oid) RETURNS boolean
  1214. LANGUAGE sql STABLE
  1215. AS $_$
  1216. SELECT _cm_is_superclass_comment(_cm_comment_for_table_id($1));
  1217. $_$;
  1218. CREATE FUNCTION _cm_is_superclass_comment(classcomment text) RETURNS boolean
  1219. LANGUAGE sql STABLE
  1220. AS $_$
  1221. SELECT _cm_check_comment($1, 'SUPERCLASS', 'true');
  1222. $_$;
  1223. CREATE FUNCTION _cm_is_system(tableid oid) RETURNS boolean
  1224. LANGUAGE sql STABLE
  1225. AS $_$
  1226. SELECT _cm_check_comment(_cm_comment_for_table_id($1), 'MODE', 'reserved')
  1227. $_$;
  1228. CREATE FUNCTION _cm_join_cmname(cmschema name, cmtable name) RETURNS text
  1229. LANGUAGE sql IMMUTABLE
  1230. AS $_$
  1231. SELECT $1 || '.' || $2;
  1232. $_$;
  1233. CREATE FUNCTION _cm_legacy_get_menu_code(boolean, boolean, boolean, boolean) RETURNS character varying
  1234. LANGUAGE plpgsql
  1235. AS $_$
  1236. DECLARE
  1237. issuperclass ALIAS FOR $1;
  1238. isprocess ALIAS FOR $2;
  1239. isreport ALIAS FOR $3;
  1240. isview ALIAS FOR $4;
  1241. menucode varchar;
  1242. BEGIN
  1243. IF (issuperclass) THEN IF (isprocess) THEN menucode='superclassprocess'; ELSE menucode='superclass'; END IF;
  1244. ELSIF(isview) THEN menucode='view';
  1245. ELSIF(isreport) THEN menucode='report';
  1246. ELSIF (isprocess) THEN menucode='processclass'; ELSE menucode='class';
  1247. END IF;
  1248. RETURN menucode;
  1249. END;
  1250. $_$;
  1251. CREATE FUNCTION _cm_legacy_get_menu_type(boolean, boolean, boolean, boolean) RETURNS character varying
  1252. LANGUAGE plpgsql
  1253. AS $_$
  1254. DECLARE
  1255. issuperclass ALIAS FOR $1;
  1256. isprocess ALIAS FOR $2;
  1257. isreport ALIAS FOR $3;
  1258. isview ALIAS FOR $4;
  1259. menutype varchar;
  1260. BEGIN
  1261. IF (isprocess) THEN menutype='processclass';
  1262. ELSIF(isview) THEN menutype='view';
  1263. ELSIF(isreport) THEN menutype='report';
  1264. ELSE menutype='class';
  1265. END IF;
  1266. RETURN menutype;
  1267. END;
  1268. $_$;
  1269. CREATE FUNCTION _cm_legacy_read_comment(text, text) RETURNS character varying
  1270. LANGUAGE sql STABLE
  1271. AS $_$
  1272. SELECT COALESCE(_cm_read_comment($1, $2), '');
  1273. $_$;
  1274. CREATE FUNCTION _cm_new_card_id() RETURNS integer
  1275. LANGUAGE sql
  1276. AS $$
  1277. SELECT nextval(('class_seq'::text)::regclass)::integer;
  1278. $$;
  1279. CREATE FUNCTION _cm_notnull_constraint_name(attributename text) RETURNS text
  1280. LANGUAGE sql IMMUTABLE
  1281. AS $_$
  1282. SELECT '_NotNull_'||$1;
  1283. $_$;
  1284. CREATE FUNCTION _cm_parent_id(tableid oid) RETURNS SETOF oid
  1285. LANGUAGE sql
  1286. AS $_$
  1287. SELECT COALESCE((SELECT inhparent FROM pg_inherits WHERE inhrelid = $1 AND _cm_is_cmobject(inhparent) LIMIT 1), NULL);
  1288. $_$;
  1289. CREATE FUNCTION _cm_propagate_superclass_triggers(tableid oid) RETURNS void
  1290. LANGUAGE plpgsql
  1291. AS $$
  1292. DECLARE
  1293. ParentId oid := _cm_parent_id(TableId);
  1294. BEGIN
  1295. PERFORM _cm_copy_restrict_trigger(ParentId, TableId);
  1296. PERFORM _cm_copy_update_relation_trigger(ParentId, TableId);
  1297. PERFORM _cm_copy_fk_trigger(ParentId, TableId);
  1298. END
  1299. $$;
  1300. CREATE FUNCTION _cm_read_comment(comment text, key text) RETURNS text
  1301. LANGUAGE sql STABLE STRICT
  1302. AS $_$
  1303. SELECT TRIM(SUBSTRING($1 FROM E'(?:^|\\|)'||$2||E':[ ]*([^\\|]+)'));
  1304. $_$;
  1305. CREATE FUNCTION _cm_read_domain_cardinality(attributecomment text) RETURNS text
  1306. LANGUAGE sql STABLE
  1307. AS $_$
  1308. SELECT _cm_read_comment($1, 'CARDIN');
  1309. $_$;
  1310. CREATE FUNCTION _cm_read_reference_domain_comment(attributecomment text) RETURNS text
  1311. LANGUAGE sql STABLE STRICT
  1312. AS $_$
  1313. SELECT _cm_read_comment($1, 'REFERENCEDOM');
  1314. $_$;
  1315. CREATE FUNCTION _cm_read_reference_domain_id_comment(attributecomment text) RETURNS oid
  1316. LANGUAGE sql STABLE STRICT
  1317. AS $_$
  1318. SELECT _cm_domain_id(_cm_read_reference_domain_comment($1));
  1319. $_$;
  1320. CREATE FUNCTION _cm_read_reference_target_comment(attributecomment text) RETURNS text
  1321. LANGUAGE sql STABLE STRICT
  1322. AS $_$
  1323. SELECT _cm_get_domain_reference_target_comment(_cm_comment_for_domain(_cm_read_reference_domain_comment($1)));
  1324. $_$;
  1325. CREATE FUNCTION _cm_read_reference_target_id_comment(attributecomment text) RETURNS oid
  1326. LANGUAGE sql STABLE STRICT
  1327. AS $_$
  1328. SELECT _cm_table_id(_cm_read_reference_target_comment($1));
  1329. $_$;
  1330. CREATE FUNCTION _cm_read_reference_type_comment(attributecomment text) RETURNS text
  1331. LANGUAGE sql STABLE STRICT
  1332. AS $_$
  1333. SELECT COALESCE(NULLIF(_cm_read_comment($1, 'REFERENCETYPE'), ''), 'restrict');
  1334. $_$;
  1335. CREATE FUNCTION _cm_remove_attribute_triggers(tableid oid, attributename text) RETURNS void
  1336. LANGUAGE plpgsql
  1337. AS $$
  1338. BEGIN
  1339. PERFORM _cm_remove_fk_constraints(TableId, AttributeName);
  1340. PERFORM _cm_remove_reference_handling(TableId, AttributeName);
  1341. END;
  1342. $$;
  1343. CREATE FUNCTION _cm_remove_constraint_trigger(fktargetclassid oid, fkclassid oid, fkattribute text) RETURNS void
  1344. LANGUAGE plpgsql
  1345. AS $$
  1346. BEGIN
  1347. EXECUTE '
  1348. DROP TRIGGER ' || quote_ident('_Constr_'||_cm_cmtable(FKClassId)||'_'||FKAttribute) ||
  1349. ' ON ' || FKTargetClassId::regclass || ';
  1350. ';
  1351. END;
  1352. $$;
  1353. CREATE FUNCTION _cm_remove_fk_constraints(fksourceid oid, attributename text) RETURNS void
  1354. LANGUAGE plpgsql
  1355. AS $$
  1356. DECLARE
  1357. TargetId oid := _cm_get_fk_target_table_id(FKSourceId, AttributeName);
  1358. SubTableId oid;
  1359. BEGIN
  1360. IF TargetId IS NULL THEN
  1361. RETURN;
  1362. END IF;
  1363. FOR SubTableId IN SELECT _cm_subtables_and_itself(FKSourceId) LOOP
  1364. EXECUTE 'DROP TRIGGER '|| quote_ident(_cm_classfk_name(FKSourceId, AttributeName)) ||
  1365. ' ON '|| SubTableId::regclass;
  1366. END LOOP;
  1367. FOR SubTableId IN SELECT _cm_subtables_and_itself(TargetId) LOOP
  1368. PERFORM _cm_remove_constraint_trigger(SubTableId, FKSourceId, AttributeName);
  1369. END LOOP;
  1370. END;
  1371. $$;
  1372. CREATE FUNCTION _cm_remove_reference_handling(tableid oid, attributename text) RETURNS void
  1373. LANGUAGE plpgsql
  1374. AS $$
  1375. BEGIN
  1376. -- remove UpdRel and UpdRef triggers
  1377. PERFORM _cm_drop_triggers_recursively(
  1378. TableId,
  1379. _cm_update_relation_trigger_name(TableId, AttributeName)
  1380. );
  1381. PERFORM _cm_drop_triggers_recursively(
  1382. _cm_get_reference_domain_id(TableId, AttributeName),
  1383. _cm_update_reference_trigger_name(TableId, AttributeName)
  1384. );
  1385. END
  1386. $$;
  1387. CREATE FUNCTION _cm_restrict(id integer, tableid oid, attributename text) RETURNS void
  1388. LANGUAGE plpgsql
  1389. AS $_$
  1390. BEGIN
  1391. IF _cm_check_value_exists($1, $2, $3, FALSE) THEN
  1392. RAISE EXCEPTION 'CM_RESTRICT_VIOLATION';
  1393. END IF;
  1394. END;
  1395. $_$;
  1396. CREATE FUNCTION _cm_set_attribute_comment(tableid oid, attributename text, comment text) RETURNS void
  1397. LANGUAGE plpgsql
  1398. AS $$
  1399. DECLARE
  1400. SubClassId oid;
  1401. BEGIN
  1402. FOR SubClassId IN SELECT _cm_subtables_and_itself(TableId) LOOP
  1403. EXECUTE 'COMMENT ON COLUMN '|| SubClassId::regclass ||'.'|| quote_ident(AttributeName) ||' IS '|| quote_literal(Comment);
  1404. END LOOP;
  1405. END;
  1406. $$;
  1407. CREATE FUNCTION _cm_set_attribute_default(tableid oid, attributename text, newdefault text, updateexisting boolean) RETURNS void
  1408. LANGUAGE plpgsql
  1409. AS $$
  1410. DECLARE
  1411. CurrentDefaultSrc text := _cm_get_attribute_default(TableId, AttributeName);
  1412. NewDefaultSrc text := _cm_attribute_default_to_src(TableId, AttributeName, NewDefault);
  1413. BEGIN
  1414. IF (NewDefaultSrc IS DISTINCT FROM CurrentDefaultSrc) THEN
  1415. IF (CurrentDefaultSrc IS NULL) THEN
  1416. EXECUTE 'ALTER TABLE ' || TableId::regclass ||
  1417. ' ALTER COLUMN ' || quote_ident(AttributeName) ||
  1418. ' SET DEFAULT ' || NewDefaultSrc;
  1419. IF UpdateExisting THEN
  1420. EXECUTE 'UPDATE '|| TableId::regclass ||' SET '|| quote_ident(AttributeName) ||' = '|| NewDefaultSrc;
  1421. END IF;
  1422. ELSE
  1423. EXECUTE 'ALTER TABLE '|| TableId::regclass ||' ALTER COLUMN '|| quote_ident(AttributeName) ||' DROP DEFAULT';
  1424. END IF;
  1425. END IF;
  1426. END;
  1427. $$;
  1428. CREATE FUNCTION _cm_setnull(id integer, tableid oid, attributename text) RETURNS void
  1429. LANGUAGE plpgsql
  1430. AS $$
  1431. BEGIN
  1432. EXECUTE 'UPDATE '|| TableId::regclass ||
  1433. ' SET '||quote_ident(AttributeName)||' = NULL'||
  1434. ' WHERE '||quote_ident(AttributeName)||' = '||Id::text;
  1435. END;
  1436. $$;
  1437. CREATE FUNCTION _cm_split_cmname(cmname text) RETURNS text[]
  1438. LANGUAGE sql IMMUTABLE
  1439. AS $_$
  1440. SELECT regexp_matches($1,E'(?:([^\\.]+)\\.)?([^\\.]+)?');
  1441. $_$;
  1442. CREATE FUNCTION _cm_subclassid(superclassid oid, cardid integer) RETURNS oid
  1443. LANGUAGE plpgsql STABLE STRICT
  1444. AS $$
  1445. DECLARE
  1446. Out integer;
  1447. BEGIN
  1448. EXECUTE 'SELECT tableoid FROM '||SuperClassId::regclass||' WHERE "Id"='||CardId||' LIMIT 1' INTO Out;
  1449. RETURN Out;
  1450. END;
  1451. $$;
  1452. CREATE FUNCTION _cm_subtables_and_itself(tableid oid) RETURNS SETOF oid
  1453. LANGUAGE sql
  1454. AS $_$
  1455. SELECT $1 WHERE _cm_is_cmobject($1)
  1456. UNION
  1457. SELECT _cm_subtables_and_itself(inhrelid) FROM pg_inherits WHERE inhparent = $1
  1458. $_$;
  1459. CREATE FUNCTION _cm_table_dbname(cmname text) RETURNS regclass
  1460. LANGUAGE sql STABLE
  1461. AS $_$
  1462. SELECT _cm_table_dbname_unsafe($1)::regclass;
  1463. $_$;
  1464. CREATE FUNCTION _cm_table_dbname_unsafe(cmname text) RETURNS text
  1465. LANGUAGE sql IMMUTABLE
  1466. AS $_$
  1467. SELECT coalesce(quote_ident(_cm_cmschema($1))||'.','')||quote_ident(_cm_cmtable($1));
  1468. $_$;
  1469. CREATE FUNCTION _cm_table_id(cmname text) RETURNS oid
  1470. LANGUAGE sql STABLE
  1471. AS $_$
  1472. SELECT _cm_table_dbname_unsafe($1)::regclass::oid;
  1473. $_$;
  1474. CREATE FUNCTION _cm_table_is_empty(tableid oid) RETURNS boolean
  1475. LANGUAGE plpgsql
  1476. AS $$
  1477. DECLARE
  1478. NotFound boolean;
  1479. BEGIN
  1480. -- Note: FOUND variable is not set on EXECUTE, so we can't use it!
  1481. EXECUTE 'SELECT (COUNT(*) = 0) FROM '|| TableId::regclass ||' LIMIT 1' INTO NotFoun