Advertisement
Guest User

Untitled

a guest
Jan 6th, 2014
113
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 25.39 KB | None | 0 0
  1. After fixing the "delimiter //" problem i have a new problem :
  2. Your query produced 12 warnings:
  3. Warnings from last query:
  4. Note: PROCEDURE Baobab_GENERIC_Close_Gaps does not exist
  5.  
  6. While "Baobab_GENERIC_Close_Gaps " is exist in the bottom of the script
  7.  
  8.  
  9. DROP PROCEDURE IF EXISTS Baobab_GENERIC_Close_Gaps;
  10. CREATE PROCEDURE Baobab_GENERIC_Close_Gaps(
  11. IN choosen_tree INTEGER UNSIGNED)
  12. LANGUAGE SQL
  13. DETERMINISTIC ................
  14.  
  15.  
  16.  
  17.  
  18.  
  19. ##########################################
  20.  
  21. /**
  22. * Baobab (an implementation of Nested Set Model)
  23. *
  24. * Copyright 2010 Riccardo Attilio Galli <riccardo@sideralis.org> [http://www.sideralis.org]
  25. *
  26. * Licensed under the Apache License, Version 2.0 (the "License");
  27. * you may not use this file except in compliance with the License.
  28. * You may obtain a copy of the License at
  29. *
  30. * http://www.apache.org/licenses/LICENSE-2.0
  31. *
  32. * Unless required by applicable law or agreed to in writing, software
  33. * distributed under the License is distributed on an "AS IS" BASIS,
  34. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  35. * See the License for the specific language governing permissions and
  36. * limitations under the License.
  37. */
  38.  
  39. /**
  40. * .. note::
  41. * Each occurrence of the word "GENERIC" across this file is meant to be
  42. * replaced with the name of the tree (which must be a valid string to use
  43. * as SQL table name).
  44. */
  45.  
  46. /* ############################### */
  47. /* ###### TABLES AND VIEWS ####### */
  48. /* ############################### */
  49.  
  50. CREATE TABLE IF NOT EXISTS GENERIC (
  51. tree_id INTEGER UNSIGNED NOT NULL,
  52. id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  53. lft INTEGER NOT NULL CHECK (lft > 0),
  54. rgt INTEGER NOT NULL CHECK (rgt > 1),
  55. INDEX(tree_id),
  56. INDEX(lft),
  57. CONSTRAINT order_okay CHECK (lft < rgt)
  58. ) ENGINE INNODB;
  59.  
  60. DROP VIEW IF EXISTS GENERIC_AdjTree;
  61. CREATE VIEW GENERIC_AdjTree (tree_id,parent,child,lft)
  62. AS
  63. SELECT E.tree_id,B.id, E.id, E.lft
  64. FROM GENERIC AS E
  65. LEFT OUTER JOIN GENERIC AS B
  66. ON B.lft = ( SELECT MAX(lft)
  67. FROM GENERIC AS S
  68. WHERE E.lft > S.lft
  69. AND E.lft < S.rgt
  70. AND E.tree_id=S.tree_id)
  71. AND B.tree_id=E.tree_id
  72. ORDER BY lft ASC;
  73.  
  74. /* ##### LIST OF TREE NAMES IN USE ##### */
  75.  
  76. CREATE TABLE IF NOT EXISTS Baobab_ForestsNames (
  77. name VARCHAR(200) PRIMARY KEY
  78. ) ENGINE INNODB DEFAULT CHARSET=utf8;
  79.  
  80. INSERT INTO Baobab_ForestsNames(name) VALUES ('GENERIC')
  81. ON DUPLICATE KEY UPDATE name=name;
  82.  
  83. /* ##################################### */
  84.  
  85.  
  86. /* ########################### */
  87. /* ###### ERRORS CONTROL ##### */
  88. /* ########################### */
  89.  
  90. CREATE TABLE IF NOT EXISTS Baobab_Errors (
  91. code INTEGER UNSIGNED NOT NULL PRIMARY KEY,
  92. name VARCHAR(50) NOT NULL,
  93. msg TINYTEXT NOT NULL,
  94. CONSTRAINT unique_codename UNIQUE (name)
  95. ) ENGINE INNODB;
  96.  
  97. INSERT INTO Baobab_Errors(code,name,msg)
  98. VALUES
  99. (1000,'VERSION','1.0'),
  100. (1100,'ROOT_ERROR','Cannot add or move a node next to root'),
  101. (1200,'CHILD_OF_YOURSELF_ERROR','Cannot move a node inside his own subtree'),
  102. (1300,'INDEX_OUT_OF_RANGE','The index is out of range'),
  103. (1400,'NODE_DOES_NOT_EXIST',"Node doesn't exist"),
  104. (1500,'VERSION_NOT_MATCH',"The library and the sql schema have different versions")
  105. ON DUPLICATE KEY UPDATE code=code,name=name,msg=msg;
  106.  
  107. DROP FUNCTION IF EXISTS Baobab_getErrCode;
  108. CREATE FUNCTION Baobab_getErrCode(x TINYTEXT) RETURNS INT
  109. DETERMINISTIC
  110. RETURN (SELECT code from Baobab_Errors WHERE name=x);
  111.  
  112.  
  113.  
  114. /* ########################## */
  115. /* ######## DROP TREE ####### */
  116. /* ########################## */
  117. delimiter //
  118. DROP PROCEDURE IF EXISTS Baobab_GENERIC_DropTree;
  119. CREATE PROCEDURE Baobab_GENERIC_DropTree (
  120. IN node INTEGER UNSIGNED,
  121. IN update_numbers INTEGER)
  122. LANGUAGE SQL
  123. DETERMINISTIC
  124. MODIFIES SQL DATA
  125.  
  126. BEGIN
  127.  
  128. DECLARE drop_tree_id INTEGER UNSIGNED;
  129. DECLARE drop_id INTEGER UNSIGNED;
  130. DECLARE drop_lft INTEGER UNSIGNED;
  131. DECLARE drop_rgt INTEGER UNSIGNED;
  132.  
  133.  
  134. /*
  135. declare exit handler for not found rollback;
  136. declare exit handler for sqlexception rollback;
  137. declare exit handler for sqlwarning rollback;
  138. */
  139.  
  140. /* save the dropped subtree data with a singleton SELECT */
  141.  
  142. START TRANSACTION;
  143.  
  144. /* save the dropped subtree data with a singleton SELECT */
  145.  
  146. SELECT tree_id, id, lft, rgt
  147. INTO drop_tree_id, drop_id, drop_lft, drop_rgt
  148. FROM GENERIC
  149. WHERE id = node;
  150.  
  151. /* subtree deletion is easy */
  152.  
  153. DELETE FROM GENERIC
  154. WHERE tree_id=drop_tree_id AND lft BETWEEN drop_lft and drop_rgt;
  155.  
  156. IF update_numbers = 1 THEN
  157. /* close up the gap left by the subtree */
  158.  
  159. UPDATE GENERIC
  160. SET lft = CASE WHEN lft > drop_lft
  161. THEN lft - (drop_rgt - drop_lft + 1)
  162. ELSE lft END,
  163. rgt = CASE WHEN rgt > drop_lft
  164. THEN rgt - (drop_rgt - drop_lft + 1)
  165. ELSE rgt END
  166. WHERE tree_id=drop_tree_id AND lft > drop_lft OR rgt > drop_lft;
  167.  
  168. END IF;
  169.  
  170. COMMIT;
  171.  
  172. END//
  173.  
  174. /* ########################## */
  175. /* ###### APPEND CHILD ###### */
  176. /* ########################## */
  177.  
  178. /* Add a new child to a parent as last sibling
  179. If parent_id is 0, insert a new root node, moving the
  180. previous root (if any) as his child.
  181. If choosen_tree is 0, use the first available integer as id.
  182. If choosen_tree is not present as tree_id in the table, it is used.
  183. */
  184. DROP PROCEDURE IF EXISTS Baobab_GENERIC_AppendChild;
  185. CREATE PROCEDURE Baobab_GENERIC_AppendChild(
  186. IN choosen_tree INTEGER UNSIGNED,
  187. IN parent_id INTEGER UNSIGNED,
  188. OUT new_id INTEGER UNSIGNED,
  189. OUT cur_tree_id INTEGER UNSIGNED)
  190. LANGUAGE SQL
  191. DETERMINISTIC
  192.  
  193. BEGIN
  194.  
  195. DECLARE num INTEGER UNSIGNED;
  196.  
  197. START TRANSACTION;
  198.  
  199. SET cur_tree_id = IF(choosen_tree > 0,
  200. choosen_tree,
  201. IFNULL((SELECT MAX(tree_id)+1 FROM GENERIC),1)
  202. );
  203.  
  204. IF parent_id = 0 THEN /* inserting a new root node*/
  205.  
  206. UPDATE GENERIC
  207. SET lft = lft+1, rgt = rgt+1
  208. WHERE tree_id=cur_tree_id;
  209.  
  210. SET num = IFNULL((SELECT MAX(rgt)+1 FROM GENERIC WHERE tree_id=cur_tree_id),2);
  211.  
  212. INSERT INTO GENERIC(tree_id, id, lft, rgt)
  213. VALUES (cur_tree_id, NULL, 1, num);
  214.  
  215. ELSE /* append a new node as last right child of his parent */
  216.  
  217. SET num = (SELECT rgt
  218. FROM GENERIC
  219. WHERE id = parent_id
  220. );
  221.  
  222. UPDATE GENERIC
  223. SET lft = CASE WHEN lft > num
  224. THEN lft + 2
  225. ELSE lft END,
  226. rgt = CASE WHEN rgt >= num
  227. THEN rgt + 2
  228. ELSE rgt END
  229. WHERE tree_id=cur_tree_id AND rgt >= num;
  230.  
  231. INSERT INTO GENERIC(tree_id, id, lft, rgt)
  232. VALUES (cur_tree_id,NULL, num, (num + 1));
  233.  
  234. END IF;
  235.  
  236. SELECT LAST_INSERT_ID() INTO new_id;
  237.  
  238. COMMIT;
  239.  
  240. END//
  241.  
  242. /* ############################### */
  243. /* ###### INSERT NODE AFTER ###### */
  244. /* ############################### */
  245.  
  246. DROP PROCEDURE IF EXISTS Baobab_GENERIC_insertAfter;
  247. CREATE PROCEDURE Baobab_GENERIC_insertAfter(
  248. IN sibling_id INTEGER UNSIGNED,
  249. OUT new_id INTEGER UNSIGNED,
  250. OUT error_code INTEGER UNSIGNED)
  251. LANGUAGE SQL
  252. DETERMINISTIC
  253.  
  254. main:BEGIN
  255.  
  256. IF 1 = (SELECT lft FROM GENERIC WHERE id = sibling_id) THEN
  257. BEGIN
  258. SELECT Baobab_getErrCode('ROOT_ERROR') INTO error_code;
  259. LEAVE main;
  260. END;
  261. ELSE
  262. BEGIN
  263.  
  264. DECLARE lft_sibling INTEGER UNSIGNED;
  265. DECLARE choosen_tree INTEGER UNSIGNED;
  266.  
  267. START TRANSACTION;
  268.  
  269. SELECT tree_id,rgt
  270. INTO choosen_tree,lft_sibling
  271. FROM GENERIC
  272. WHERE id = sibling_id;
  273.  
  274. IF ISNULL(lft_sibling) THEN
  275. BEGIN
  276. SELECT Baobab_getErrCode('NODE_DOES_NOT_EXIST') INTO error_code;
  277. LEAVE main;
  278. END;
  279. END IF;
  280.  
  281. UPDATE GENERIC
  282. SET lft = CASE WHEN lft < lft_sibling
  283. THEN lft
  284. ELSE lft + 2 END,
  285. rgt = CASE WHEN rgt < lft_sibling
  286. THEN rgt
  287. ELSE rgt + 2 END
  288. WHERE tree_id=choosen_tree AND rgt > lft_sibling;
  289.  
  290. INSERT INTO GENERIC(tree_id,id,lft,rgt)
  291. VALUES (choosen_tree,NULL, (lft_sibling + 1),(lft_sibling + 2));
  292.  
  293. SELECT LAST_INSERT_ID() INTO new_id;
  294.  
  295. COMMIT;
  296.  
  297. END;
  298. END IF;
  299.  
  300. END//
  301.  
  302.  
  303. /* ################################ */
  304. /* ###### INSERT NODE BEFORE ###### */
  305. /* ################################ */
  306.  
  307. DROP PROCEDURE IF EXISTS Baobab_GENERIC_insertBefore;
  308. CREATE PROCEDURE Baobab_GENERIC_insertBefore(
  309. IN sibling_id INTEGER UNSIGNED,
  310. OUT new_id INTEGER UNSIGNED,
  311. OUT error_code INTEGER UNSIGNED)
  312. LANGUAGE SQL
  313. DETERMINISTIC
  314. main:BEGIN
  315.  
  316. IF 1 = (SELECT lft FROM GENERIC WHERE id = sibling_id) THEN
  317. BEGIN
  318. SELECT Baobab_getErrCode('ROOT_ERROR') INTO error_code;
  319. LEAVE main;
  320. END;
  321. ELSE
  322. BEGIN
  323.  
  324. DECLARE rgt_sibling INTEGER UNSIGNED;
  325. DECLARE choosen_tree INTEGER UNSIGNED;
  326.  
  327. START TRANSACTION;
  328.  
  329. SELECT tree_id,lft
  330. INTO choosen_tree,rgt_sibling
  331. FROM GENERIC
  332. WHERE id = sibling_id;
  333.  
  334. IF ISNULL(rgt_sibling) THEN
  335. BEGIN
  336. SELECT Baobab_getErrCode('NODE_DOES_NOT_EXIST') INTO error_code;
  337. LEAVE main;
  338. END;
  339. END IF;
  340.  
  341. UPDATE IGNORE GENERIC
  342. SET lft = CASE WHEN lft < rgt_sibling
  343. THEN lft
  344. ELSE lft + 2 END,
  345. rgt = CASE WHEN rgt < rgt_sibling
  346. THEN rgt
  347. ELSE rgt + 2 END
  348. WHERE tree_id=choosen_tree AND rgt >= rgt_sibling
  349. ORDER BY lft DESC; /* order by is meant to avoid uniqueness violation on update */
  350.  
  351. INSERT INTO GENERIC(tree_id,id,lft,rgt)
  352. VALUES (choosen_tree,NULL, rgt_sibling, rgt_sibling + 1);
  353.  
  354. SELECT LAST_INSERT_ID() INTO new_id;
  355.  
  356. COMMIT;
  357.  
  358. END;
  359. END IF;
  360.  
  361. END//
  362.  
  363.  
  364. /* ################################### */
  365. /* ###### INSERT CHILD AT INDEX ###### */
  366. /* ################################### */
  367.  
  368. /* Add a new child to parent 'parent_id' at index 'index'.
  369. index is the new child position, 0 will put the new node as first.
  370. index can be negative, where -1 will put the new node before the last one
  371. */
  372.  
  373. DROP PROCEDURE IF EXISTS Baobab_GENERIC_InsertChildAtIndex;
  374. CREATE PROCEDURE Baobab_GENERIC_InsertChildAtIndex(
  375. IN parent_id INTEGER UNSIGNED,
  376. IN idx INTEGER,
  377. OUT new_id INTEGER UNSIGNED,
  378. OUT error_code INTEGER UNSIGNED)
  379. LANGUAGE SQL
  380. DETERMINISTIC
  381.  
  382. BEGIN
  383.  
  384. DECLARE nth_child INTEGER UNSIGNED;
  385.  
  386. SET error_code=0;
  387. SET new_id=0;
  388.  
  389. CALL Baobab_GENERIC_getNthChild(parent_id,idx,nth_child,error_code);
  390.  
  391. IF NOT error_code THEN
  392. CALL Baobab_GENERIC_insertBefore(nth_child,new_id,error_code);
  393. END IF;
  394.  
  395. END//
  396.  
  397. /* ########################### */
  398. /* ###### GET NTH CHILD ###### */
  399. /* ########################### */
  400.  
  401. DROP PROCEDURE IF EXISTS Baobab_GENERIC_getNthChild;
  402. CREATE PROCEDURE Baobab_GENERIC_getNthChild(
  403. IN parent_id INTEGER UNSIGNED,
  404. IN idx INTEGER,
  405. OUT nth_child INTEGER UNSIGNED,
  406. OUT error_code INTEGER UNSIGNED)
  407. LANGUAGE SQL
  408. DETERMINISTIC
  409.  
  410. main:BEGIN
  411.  
  412. DECLARE num_children INTEGER;
  413.  
  414. SET error_code=0;
  415.  
  416. SELECT COUNT(*)
  417. INTO num_children
  418. FROM GENERIC_AdjTree WHERE parent = parent_id;
  419.  
  420. IF num_children = 0 OR IF(idx<0,(-idx)-1,idx) >= num_children THEN
  421. /* idx is out of range */
  422. BEGIN
  423. SELECT Baobab_getErrCode('INDEX_OUT_OF_RANGE') INTO error_code;
  424. LEAVE main;
  425. END;
  426. ELSE
  427.  
  428. SELECT child
  429. INTO nth_child
  430. FROM GENERIC_AdjTree as t1
  431. WHERE (SELECT count(*) FROM GENERIC_AdjTree as t2
  432. WHERE parent = parent_id AND t2.lft<=t1.lft AND t1.tree_id=t2.tree_id
  433. )
  434. = (CASE
  435. WHEN idx >= 0
  436. THEN idx+1
  437. ELSE num_children+1+idx
  438. END
  439. )
  440. LIMIT 1;
  441.  
  442. END IF;
  443.  
  444. END//
  445.  
  446.  
  447.  
  448. /* ###################################### */
  449. /* ###### MOVE SUBTREE BEFORE NODE ###### */
  450. /* ###################################### */
  451.  
  452. DROP PROCEDURE IF EXISTS Baobab_GENERIC_MoveSubtreeBefore;
  453. CREATE PROCEDURE Baobab_GENERIC_MoveSubtreeBefore(
  454. IN node_id_to_move INTEGER UNSIGNED,
  455. IN reference_node INTEGER UNSIGNED,
  456. OUT error_code INTEGER UNSIGNED)
  457. LANGUAGE SQL
  458. DETERMINISTIC
  459.  
  460. main:BEGIN
  461.  
  462. DECLARE node_revised INTEGER UNSIGNED;
  463. DECLARE move_as_first_sibling BOOLEAN;
  464. DECLARE ref_left INTEGER UNSIGNED;
  465. DECLARE ref_node_tree INTEGER UNSIGNED;
  466.  
  467. SET error_code=0; /* 0 means no error */
  468. SET move_as_first_sibling = TRUE;
  469.  
  470. SELECT tree_id,lft
  471. INTO ref_node_tree,ref_left
  472. FROM GENERIC WHERE id = reference_node;
  473.  
  474. IF ref_left = 1 THEN
  475. BEGIN
  476. /* cannot move a parent node before or after root */
  477. SELECT Baobab_getErrCode('ROOT_ERROR') INTO error_code;
  478. LEAVE main;
  479. END;
  480. END IF;
  481.  
  482. /* if reference_node is the first child of his parent, set node_revised
  483. to the parent id, else set node_revised to NULL */
  484. SET node_revised = ( SELECT id FROM GENERIC WHERE tree_id=ref_node_tree AND lft = -1+ ref_left);
  485.  
  486. IF ISNULL(node_revised) THEN /* if node_revised is NULL we must find the previous sibling */
  487. BEGIN
  488. SET node_revised= (SELECT id FROM GENERIC
  489. WHERE tree_id=ref_node_tree AND rgt = -1 + ref_left);
  490. SET move_as_first_sibling = FALSE;
  491. END;
  492. END IF;
  493.  
  494. CALL Baobab_GENERIC_MoveSubtree_real(
  495. node_id_to_move, node_revised , move_as_first_sibling, error_code
  496. );
  497.  
  498. END//
  499.  
  500.  
  501.  
  502. /* ##################################### */
  503. /* ###### MOVE SUBTREE AFTER NODE ###### */
  504. /* ##################################### */
  505.  
  506. DROP PROCEDURE IF EXISTS Baobab_GENERIC_MoveSubtreeAfter;
  507. CREATE PROCEDURE Baobab_GENERIC_MoveSubtreeAfter(
  508. IN node_id_to_move INTEGER UNSIGNED,
  509. IN reference_node INTEGER UNSIGNED,
  510. OUT error_code INTEGER UNSIGNED)
  511. LANGUAGE SQL
  512. DETERMINISTIC
  513.  
  514. BEGIN
  515.  
  516. SELECT 0 INTO error_code; /* 0 means no error */
  517.  
  518. CALL Baobab_GENERIC_MoveSubtree_real(
  519. node_id_to_move,reference_node,FALSE,error_code
  520. );
  521.  
  522. END//
  523.  
  524. delimiter //
  525.  
  526. /* ##################################### */
  527. /* ####### MOVE SUBTREE AT INDEX ####### */
  528. /* ##################################### */
  529.  
  530. DROP PROCEDURE IF EXISTS Baobab_GENERIC_MoveSubtreeAtIndex;
  531. CREATE PROCEDURE Baobab_GENERIC_MoveSubtreeAtIndex(
  532. IN node_id_to_move INTEGER UNSIGNED,
  533. IN parent_id INTEGER UNSIGNED,
  534. IN idx INTEGER,
  535. OUT error_code INTEGER)
  536. LANGUAGE SQL
  537. DETERMINISTIC
  538.  
  539. main:BEGIN
  540.  
  541. DECLARE nth_child INTEGER UNSIGNED;
  542. DECLARE num_children INTEGER;
  543.  
  544. SET error_code=0;
  545.  
  546. SELECT COUNT(*)
  547. INTO num_children
  548. FROM GENERIC_AdjTree WHERE parent = parent_id;
  549.  
  550. IF num_children = 0 THEN
  551. BEGIN
  552. SELECT Baobab_getErrCode('INDEX_OUT_OF_RANGE') INTO error_code;
  553. LEAVE main;
  554. END;
  555. END IF;
  556.  
  557. SET idx = IF(idx<0,num_children+idx,idx);
  558.  
  559. IF idx = 0 THEN /* moving as first child, special case */
  560. CALL Baobab_GENERIC_MoveSubtree_real(node_id_to_move,parent_id,TRUE,error_code);
  561. ELSE
  562. BEGIN
  563. /* search the node before idx, and we wil move our node after that */
  564. CALL Baobab_GENERIC_getNthChild(parent_id,idx-1,nth_child,error_code);
  565.  
  566. IF NOT error_code THEN
  567. CALL Baobab_GENERIC_MoveSubtree_real(node_id_to_move,nth_child,FALSE,error_code);
  568. END IF;
  569. END;
  570. END IF;
  571.  
  572. END//
  573.  
  574. /* ####################################### */
  575. /* ####### MOVE SUBTREE REAL LOGIC #######*/
  576. /* ####################################### */
  577.  
  578. /* If move_as_first_sibling is FALSE, move node_id_to_move after reference_node,
  579. else reference_node is the new father of node_id_to_move */
  580.  
  581. SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_UNSIGNED_SUBTRACTION';
  582.  
  583. DROP PROCEDURE IF EXISTS Baobab_GENERIC_MoveSubtree_real;
  584. CREATE PROCEDURE Baobab_GENERIC_MoveSubtree_real(
  585. IN node_id_to_move INTEGER UNSIGNED,
  586. IN reference_node INTEGER UNSIGNED,
  587. IN move_as_first_sibling BOOLEAN,
  588. OUT error_code INTEGER
  589. )
  590. LANGUAGE SQL
  591. DETERMINISTIC
  592.  
  593. main:BEGIN
  594.  
  595. DECLARE s_lft INTEGER UNSIGNED;
  596. DECLARE s_rgt INTEGER UNSIGNED;
  597. DECLARE ref_lft INTEGER UNSIGNED;
  598. DECLARE ref_rgt INTEGER UNSIGNED;
  599.  
  600. DECLARE source_node_tree INTEGER UNSIGNED;
  601. DECLARE ref_node_tree INTEGER UNSIGNED;
  602.  
  603. DECLARE diff_when_inside_sourcetree BIGINT SIGNED;
  604. DECLARE diff_when_next_sourcetree BIGINT SIGNED;
  605. DECLARE ext_bound_1 INTEGER UNSIGNED;
  606. DECLARE ext_bound_2 INTEGER UNSIGNED;
  607.  
  608. SET error_code=0;
  609.  
  610. START TRANSACTION;
  611.  
  612. /* select tree, left and right of the node to move */
  613. SELECT tree_id,lft, rgt
  614. INTO source_node_tree, s_lft, s_rgt
  615. FROM GENERIC
  616. WHERE id = node_id_to_move;
  617.  
  618. /* select left and right of the reference node
  619.  
  620. If moving as first sibling, ref_lft will become the new lft value of node_id_to_move,
  621. (and ref_rgt is unused), else we're saving left and right value of soon to be
  622. previous sibling
  623.  
  624. */
  625. SELECT tree_id, IF(move_as_first_sibling,lft+1,lft), rgt
  626. INTO ref_node_tree, ref_lft, ref_rgt
  627. FROM GENERIC
  628. WHERE id = reference_node;
  629.  
  630.  
  631. IF move_as_first_sibling = TRUE THEN
  632.  
  633. IF s_lft <= ref_lft AND s_rgt >= ref_rgt AND source_node_tree=ref_node_tree THEN
  634. /* cannot move a parent node inside his own subtree */
  635. BEGIN
  636. SELECT Baobab_getErrCode('CHILD_OF_YOURSELF_ERROR') INTO error_code;
  637. LEAVE main;
  638. END;
  639. ELSE
  640.  
  641. IF s_lft > ref_lft THEN BEGIN
  642. SET diff_when_inside_sourcetree = -(s_lft-ref_lft);
  643. SET diff_when_next_sourcetree = s_rgt-s_lft+1;
  644. SET ext_bound_1 = ref_lft;
  645. SET ext_bound_2 = s_lft-1;
  646.  
  647. END;
  648. ELSE BEGIN
  649. SET diff_when_inside_sourcetree = ref_lft-s_rgt-1;
  650. SET diff_when_next_sourcetree = -(s_rgt-s_lft+1);
  651. SET ext_bound_1 = s_rgt+1;
  652. SET ext_bound_2 = ref_lft-1;
  653.  
  654. END;
  655. END IF;
  656.  
  657. END IF;
  658. ELSE /* moving after an existing child */
  659.  
  660. IF ref_lft = 1 THEN /* cannot move a node before or after root */
  661. BEGIN
  662. SELECT Baobab_getErrCode('ROOT_ERROR') INTO error_code;
  663. LEAVE main;
  664. END;
  665. ELSEIF s_lft < ref_lft AND s_rgt > ref_rgt AND source_node_tree=ref_node_tree THEN
  666. /* cannot move a parent node inside his own subtree */
  667. BEGIN
  668. SELECT Baobab_getErrCode('CHILD_OF_YOURSELF_ERROR') INTO error_code;
  669. LEAVE main;
  670. END;
  671. ELSE
  672.  
  673. IF s_lft > ref_rgt THEN BEGIN
  674. SET diff_when_inside_sourcetree = -(s_lft-ref_rgt-1);
  675. SET diff_when_next_sourcetree = s_rgt-s_lft+1;
  676. SET ext_bound_1 = ref_rgt+1;
  677. SET ext_bound_2 = s_lft-1;
  678.  
  679. END;
  680. ELSE BEGIN
  681. SET diff_when_inside_sourcetree = ref_rgt-s_rgt;
  682. SET diff_when_next_sourcetree = -(s_rgt-s_lft+1);
  683. SET ext_bound_1 = s_rgt+1;
  684. SET ext_bound_2 = ref_rgt;
  685.  
  686. END;
  687. END IF;
  688.  
  689. END IF;
  690.  
  691. END IF;
  692.  
  693.  
  694. IF source_node_tree <> ref_node_tree THEN
  695. BEGIN
  696. CALL Baobab_GENERIC_MoveSubtree_Different_Trees(
  697. node_id_to_move,reference_node,move_as_first_sibling);
  698. LEAVE main;
  699. END;
  700. END IF;
  701.  
  702. UPDATE GENERIC
  703. SET lft =
  704. lft + CASE
  705. WHEN lft BETWEEN s_lft AND s_rgt
  706. THEN diff_when_inside_sourcetree
  707. WHEN lft BETWEEN ext_bound_1 AND ext_bound_2
  708. THEN diff_when_next_sourcetree
  709. ELSE 0 END
  710. ,
  711. rgt =
  712. rgt + CASE
  713.  
  714. WHEN rgt BETWEEN s_lft AND s_rgt
  715. THEN diff_when_inside_sourcetree
  716. WHEN rgt BETWEEN ext_bound_1 AND ext_bound_2
  717. THEN diff_when_next_sourcetree
  718. ELSE 0 END
  719. WHERE tree_id=source_node_tree;
  720.  
  721. COMMIT;
  722.  
  723. END//
  724.  
  725. SET sql_mode=@OLD_SQL_MODE;
  726.  
  727. DROP PROCEDURE IF EXISTS Baobab_GENERIC_MoveSubtree_Different_Trees;
  728. CREATE PROCEDURE Baobab_GENERIC_MoveSubtree_Different_Trees(
  729. IN node_id_to_move INTEGER UNSIGNED,
  730. IN reference_node INTEGER UNSIGNED,
  731. IN move_as_first_sibling BOOLEAN
  732. )
  733. LANGUAGE SQL
  734. DETERMINISTIC
  735.  
  736. main:BEGIN
  737.  
  738. DECLARE s_lft INTEGER UNSIGNED;
  739. DECLARE s_rgt INTEGER UNSIGNED;
  740. DECLARE ref_lft INTEGER UNSIGNED;
  741. DECLARE ref_rgt INTEGER UNSIGNED;
  742.  
  743. DECLARE source_node_tree INTEGER UNSIGNED;
  744. DECLARE ref_node_tree INTEGER UNSIGNED;
  745.  
  746. START TRANSACTION;
  747.  
  748. /* select tree, left and right of the node to move */
  749. SELECT tree_id,lft, rgt
  750. INTO source_node_tree, s_lft, s_rgt
  751. FROM GENERIC
  752. WHERE id = node_id_to_move;
  753.  
  754. /* The current select will behave differently whether we're moving
  755. the node as first sibling or not.
  756.  
  757. If move_as_first_sibling,
  758. ref_lft will have the value of the "lft" field of node_id_to_move at end
  759. of move (ref_rgt here is discarded)
  760. else
  761. ref_lft and ref_rgt will have the values of the node before node_id_to_move
  762. at end of move
  763. */
  764. SELECT tree_id, IF(move_as_first_sibling,lft+1,lft), rgt
  765. INTO ref_node_tree, ref_lft, ref_rgt
  766. FROM GENERIC
  767. WHERE id = reference_node;
  768.  
  769. IF (move_as_first_sibling) THEN BEGIN
  770.  
  771. /* create a gap in the destination tree to hold the subtree */
  772. UPDATE GENERIC
  773. SET lft = CASE WHEN lft < ref_lft
  774. THEN lft
  775. ELSE lft + s_rgt-s_lft+1 END,
  776. rgt = CASE WHEN rgt < ref_lft
  777. THEN rgt
  778. ELSE rgt + s_rgt-s_lft+1 END
  779. WHERE tree_id=ref_node_tree AND rgt >= ref_lft;
  780.  
  781. /* move the subtree to the new tree */
  782. UPDATE GENERIC
  783. SET lft = ref_lft + (lft-s_lft),
  784. rgt = ref_lft + (rgt-s_lft),
  785. tree_id = ref_node_tree
  786. WHERE tree_id = source_node_tree AND lft >= s_lft AND rgt <= s_rgt;
  787.  
  788. END;
  789. ELSE BEGIN
  790.  
  791. /* create a gap in the destination tree to hold the subtree */
  792. UPDATE GENERIC
  793. SET lft = CASE WHEN lft < ref_rgt
  794. THEN lft
  795. ELSE lft + s_rgt-s_lft+1 END,
  796. rgt = CASE WHEN rgt <= ref_rgt
  797. THEN rgt
  798. ELSE rgt + s_rgt-s_lft+1 END
  799. WHERE tree_id=ref_node_tree AND rgt > ref_rgt;
  800.  
  801. /* move the subtree to the new tree */
  802. UPDATE GENERIC
  803. SET lft = ref_rgt+1 + (lft-s_lft),
  804. rgt = ref_rgt+1 + (rgt-s_lft),
  805. tree_id = ref_node_tree
  806. WHERE tree_id = source_node_tree AND lft >= s_lft AND rgt <= s_rgt;
  807.  
  808. END;
  809.  
  810. END IF;
  811.  
  812. /* close the gap in the source tree */
  813. CALL Baobab_GENERIC_Close_Gaps(source_node_tree);
  814.  
  815. COMMIT;
  816.  
  817. END//
  818.  
  819. /* ########################## */
  820. /* ####### CLOSE GAPS ####### */
  821. /* ########################## */
  822.  
  823. DROP PROCEDURE IF EXISTS Baobab_GENERIC_Close_Gaps;
  824. CREATE PROCEDURE Baobab_GENERIC_Close_Gaps(
  825. IN choosen_tree INTEGER UNSIGNED)
  826. LANGUAGE SQL
  827. DETERMINISTIC
  828.  
  829. BEGIN
  830.  
  831. UPDATE GENERIC
  832. SET lft = (SELECT COUNT(*)
  833. FROM (
  834. SELECT lft as seq_nbr FROM GENERIC WHERE tree_id=choosen_tree
  835. UNION ALL
  836. SELECT rgt FROM GENERIC WHERE tree_id=choosen_tree
  837. ) AS LftRgt
  838. WHERE tree_id=choosen_tree AND seq_nbr <= lft
  839. ),
  840. rgt = (SELECT COUNT(*)
  841. FROM (
  842. SELECT lft as seq_nbr FROM GENERIC WHERE tree_id=choosen_tree
  843. UNION ALL
  844. SELECT rgt FROM GENERIC WHERE tree_id=choosen_tree
  845. ) AS LftRgt
  846. WHERE tree_id=choosen_tree AND seq_nbr <= rgt
  847. )
  848. WHERE tree_id=choosen_tree;
  849. END//
  850. delimiter ;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement