how to upgrade game database - mysql

How do you guys upgrade your game database?I actually mean add new column to your table, say we got a playerrole table which changes frequently.For some reason,I don't want to login to the database server to upgrade it.I want to write a script file to upgrade it when the game server start.Well, the patch script file looks something like the following one:
drop PROCEDURE IF EXISTS dbpatch;
DELIMITER ;;
create PROCEDURE dbpatch()
declare exit HANDLER for SQLEXCEPTION ROLLBACK;
BEGIN
start TRANSACTION;
// sql sentence
update version set v = versionnum;
commit;
end;;
DELIMITER;
call dbpatch();
drop PROCEDURE if EXISTS dbpatch;
The problem is that alter table statements which I put in dbpatch will end current active transaction and implicit commit according to mysql doc(https://dev.mysql.com/doc/refman/5.0/en/implicit-commit.html),this might cause partial success and could not be rolled back.For example, I got a table A and I want to add three new columns 'a', 'b', 'c' to this table,but table A already got column 'c'.The patch process will be terminated by sqlexception but column 'a' and 'b' will be added to talbe A.I hope it could be rolled back rather than partial success.Then I googled it, there are some ways to work around,but they tend to create a temporary table to hack it.
This way did not work for me,because I got some records in table,if I do it this way,I have to move records back and forth which is more error-prone.Any idea how to solve it?Any help will be appreciated.Our current mysql version is 5.5.27.

Related

Tracking database changes

Does anyone here can suggest a way to track database changes that were made through wordpress? For example I add a menu in wordpress, how can I keep track of this changes in database?
I use mysql
I tried searching and I only find toad and mysqldiff but still no luck. I also tried activating tracking for mysql but it only records changes that were made through phpmyadmin
You can create a trigger function in your mysql database. This function could copy the row before any UPDATE or INSERT statement into a separate table.
http://dev.mysql.com/doc/refman/5.7/en/create-trigger.html
BUT! Write a small IF check into your procedure so that you can disable it. Otherwise you will have a hard time when importing data through sql scripts during development.
A sample:
DROP TRIGGER IF EXISTS `backup`;
DELIMITER //
CREATE TRIGGER `backup`
BEFORE UPDATE
ON `sourceTable` FOR EACH ROW
BEGIN
IF #disableTriggers <> 1 THEN
INSERT INTO `backupTable` (col1,col2,col3) VALUES (OLD.col1,OLD.col2,OLD.col3)
END IF;
END;
//
DELIMITER ;

Syntax exception on trigger with multiple statements with MySQL and JDBC

I am trying to create a trigger that performs multiple operations in MySQL 5.5.28 with InnoDB.
I have two tables, "test" and "test_watcher": changes to the first are recorded in the watcher table with the help of triggers. The last trigger needs to perform 2 operations on DELETE, it works in MySQL Workbench (with DELIMITER) but doesn't if I create it with JDBC.
CREATE TRIGGER `AD_test_FER` AFTER DELETE
ON `test`
FOR EACH ROW
BEGIN
-- if it's been inserted, modified and deleted but never synced,
-- the revision is NULL: no one needs to know about it
DELETE FROM test_watcher WHERE pk = OLD.id AND revision IS NULL;
-- if it has been synced already, we just update the flag
UPDATE test_watcher SET flag = -1 WHERE pk = OLD.id;
END;
I keep getting com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax.
I know it works with DELIMITER $$ in Workbench, but JDBC doesn't support it.
I've achieved it in PostgreSQL and would post the code if necessary.
This behavior might be caused by the connection property allowMultiQueries=true. My guess is this property will make MySQL break up queries on the ; as a query separator and then execute those as separate queries, essentially breaking your trigger creation code.
As you said in a - now deleted - answer that adding allowMultiQueries=true actually solved the problem (contrary to my expectiation), the problem might actually be the last ; in your query. So another thing to check is if the problem goes away by removing the last ; (in END;) in your script (and not using allowMultiQueries=true). Some database don't consider ; to be valid at the end of a statement (as it is actually a delimiter to separate statements).
(this answer is based on my comment above)
If JDBC does not support delimiters (DELIMITER is a client command), then execute these two statements separately - one by one.

MySQL: trigger with clause "instead of update"

I'm trying to create a database with history in mind (experience shows you'll have to do this one day or another).
I've asked here database-design-how-to-handle-the-archive-problem but there's no better anser than the link here.
My problem is about where to do the code and technically, how (MySQL gives me headaches). First I've started doing this in Php: before doing any insert, duplicate the record mark it as "obsolete" then modify the record.
But there's a dependency problem (manytomany and manytoone associations must be updated as well) which implies coding (one way or another) all the dependancies and updates that come with the tables (which is not acceptable).
So I'm thinking about doing all the work on the database server side. This would greatly simplify my Php code.
The problem is that I have to "archive" the current record before modifying it. To do so, the code must be in a trigger "before update".
Here's my code:
DELIMITER ;;
DROP TRIGGER IF EXISTS produit_trigger_update_before;
CREATE TRIGGER produit_trigger_update_before
BEFORE UPDATE ON produit
FOR EACH ROW BEGIN
/* */
INSERT INTO produit SET
id_origine = OLD.id_origine,
date_v_creation = OLD.date_v_creation,
date_v_start = OLD.date_v_debut,
date_v_end = NOW(),
...
last_record = OLD.last_record;
/* Dependancies : */
SET #last=LAST_INSERT_ID();
UPDATE categorie_produit SET id_produit=#last
WHERE id_produit = OLD.id;
UPDATE produit_attribut SET id_produit=#last
WHERE id_produit = OLD.id;
END;;
DELIMITER ;;
If I get this code working, all my problems are gone. But damn it, it's not working:
mysql> update produit set importance=3;
ERROR 1442 (HY000): Can't update table 'produit' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
mysql> Bye
In this page there's a working sample, which uses INSTEAD OF UPDATE clause in the trigger. MySQL doesn't seem to support this.
So my question is both conceptual (= have you any other "principle" that could work) and/or technical (= can you make this trigger work).
If I get this code working, all my problems are gone. But damn it, it's not working:
As a rule you can't have a trigger on table A trigger inserts into table A - since that could cause an endless loop. (Trigger mutation in Oracle terms)
Personally I would not do this using triggers. Triggers can do "audit logging" - but this is not what you want here.
I suggest you solve it programatically - either with a PHP function or a MySQL stored procedure (whatever your preference) that you call something like "ModifyProduit".
The code would then do basically what you have the trigger above do. (It might be easier to just have the code set date_v_end on the current row, and then insert a completly new row. That way you don't have to mess around with updating your referenced tables)
you can do history of a table with an auxiliary table like this (i've done this for many tables on mysql and the speed is very good):
table produit_history has the same structure as produit + 2 additional columns: "history_start DATETIME NOT NULL" and "history_stop DATETIME DEFAULT NULL".
there are 3 triggers on produit table:
AFTER INSERT: in this trigger there is a simple insert into produit_history of the same data with history_start = NOW() and history_stop = NULL (NULL means the current row is valid)
AFTER UPDATE: this trigger performs two queries. The first is un update like this:
UPDATE produit_history set history_stop = NOW() WHERE id_origine = OLD.id_origine AND history_stop IS NULL;
The second query is an insert identical to the one in the AFTER INSERT trigger.
AFTER DELETE: this triggers there is a simple update which is identical to the one in the AFTER UPDATE.
You can then query this history table and obtain snapshots at whatever time you're interested in with the following where condition:
WHERE (history_start &lt= "interesting_time" AND (history_stop IS NULL OR history_stop &gt "interesting_time"))

MySQl Trigger help needed

using MySQL 5.1.36, I am trying to write trigger which drops scratch tables form "scratch" database.
CREATE DEFINER=`root`#`localhost` TRIGGER
`jobq`.`DropScratch`
BEFORE DELETE ON jobq.jobq FOR EACH ROW
BEGIN
DECLARE tblname VARCHAR(128);
set tblname=concat('scratch.',OLD.jobname);
DROP TABLE IF EXISTS tblname;
END;
I am always getting an error:
Explicit or implicit commit is not allowed in stored function or trigger.
Can I somehow overcome this restriction?
Thank you beforehand
Arman
The primary problem here is that you are not allowed to drop a table within a trigger. That's what the error message is getting at when it says "implicit commit" is not allowed. The drop table does an implicit commit.
So you will need to figure out a different way to do this other than a trigger. One way would be to set up a cron job which compares the data in information_schema.tables to the jobq table to look for tables in the scratch DB that can be dropped, and then drop them.
I should also point out that the way you are trying to dynamically create a drop table statement will not work. That is going to drop a table named literally "tblname", not "scratch.jobname". If you want to drop a table dynamically you will need to build the drop table statement in a separate scripting language, such as python, perl, shell, etc.
Good luck!

To check values in other databases using trigger

Is it possible to check whether a particular value in a column exists in other databases using trigger? These two databases are located inside the same MYSQL instance. Specifically, what I want to do is this:
Before a row is added to a table ( Document_Index_table) inside Database A ( Document_DB).
A trigger is fired. This trigger carries the one of the column value (usr_id) inside the row and pass it to Database B ( User_Control_DB).
Based on the values, User_Control_DB will check whether the usr_id exists in column usr_id of the table (Usr_Information).
If exists, then return a true to Document_DB and the row in 1. is allowed to add to the Document_DB.
If not, then an error is issued. No row is added to Document_DB.
How can this be done, if it can be done at all?
Edit: Both databases are MySQL databases
So, I'm a complete novice at database development, but you could do something like this:
Create a 'Before' insert trigger on your document_index_table.
The trigger does something like this:
declare numRows integer;
select count(*) from user_control_db.usr_information where usr_id = NEW.usr_id into num_rows;
if (numRows > 0) then
call NonExistentProc();
end if;
I believe that this would accomplish what you wanted. It'll produce an error like "PROCEDURE documentdb.NonExistenProc does not exist" and skip the insert if there isn't at least one row that has the matching usr id in the user control db.
Again, I'm a novice at this DB stuff so there might be a more elegant way, but this worked for my single test case.
Hope that helps.