MySQL stored procedure anomaly: One line gets executed, another skipped? - mysql

I have a stored procedure, that checks if there is a user with the same e-mail address as the input, if not, then registeres one.
Here is the table:
CREATE TABLE IF NOT EXISTS `overkill`.`accounts` (
`accountID` INT NOT NULL AUTO_INCREMENT ,
`email` VARCHAR(64) NOT NULL ,
`firstName` VARCHAR(32) NOT NULL ,
`lastName` VARCHAR(32) NOT NULL ,
`passSaltedSHA` BINARY(20) NOT NULL ,
`salt` BINARY(20) NOT NULL ,
`gender` ENUM('m','f') NOT NULL ,
`birthDate` DATE NOT NULL ,
`regTime` TIMESTAMP NOT NULL ,
PRIMARY KEY (`accountID`) )
ENGINE = InnoDB;
Here is the stored procedure:
DELIMITER $$
CREATE PROCEDURE `overkill`.`registerUser` (
IN emailIN VARCHAR(64),
IN passwordIN VARCHAR(16),
IN firstNameIN VARCHAR(32),
IN lastNameIn VARCHAR(32),
IN birthIN DATE,
IN genderIN ENUM('f','m'))
BEGIN
DECLARE existingMailAccLOG INT DEFAULT NULL;
DECLARE saltLOC CHAR(40);
DECLARE regSuccessLOC BOOLEAN DEFAULT FALSE;
SELECT COUNT(*) INTO existingMailAccLOG FROM `overkill`.`accounts` WHERE `accounts`.`email` = emailIN;
IF existingMailAccLOG = 0 THEN
SET saltLOC = SHA1(rand());
SET regSuccessLOC = TRUE;
INSERT INTO `overkill`.`accounts` (`email`, `firstName`, `lastName`, `passSaltedSHA`, `salt`, `gender`, `birthDate`) VALUES(emailIN, firstNameIN, lastNameIn, UNHEX(SHA1(CONCAT(passwordIN, saltLOC))), UNHEX(saltLOC), genderIN, birthIN);
END IF;
SELECT regSuccessLOC AS `registered`, saltLOC AS `salt`;
END
If I call:
CALL registerUser("abc#def.com", "pass", "firstn", "lastn", "2012-01-01", "f");
It inserts a line into the accounts table, but forgets to return the proper values that I set inside the IF
SET saltLOC = SHA1(rand());
SET regSuccessLOC = TRUE;
How is it even possible? Why are theese lines skipped and INSERT still gets executed, without mistake?

Try to add "#" in front of your variable names after DECLARE keyword. It can cause some confusion, as it is described here: MySQL: #variable vs. variable. Whats the difference? (Part2) and here: MySQL: #variable vs. variable. Whats the difference?

Related

Column count doesn't match with the value count in row 1

I am trying to populate a mqsql table with random values. I created a stored procedure for this but it gives me the error "column count doesn't match with the value count in row 1" when I execute it.
Below is what I have tried
The stored procedure
CREATE DEFINER=`root`#`localhost` PROCEDURE `GenerateManagerData`()
BEGIN
DECLARE i INT DEFAULT 1;
WHILE i <= 100 DO
INSERT INTO projectManager(id,name,email,contact_number) VALUES (i+ 'M', CAST(i AS CHAR(10)), 'e'+ CAST(i AS CHAR(10))+ '#gmail.com', 'TP' + CAST(i AS CHAR(10)));
SET i = i + 1;
END WHILE;
END
This is the table I have created
CREATE TABLE `projectmanager` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`name` varchar(100) DEFAULT NULL,
`email` varchar(100) DEFAULT NULL,
`contact_number` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email_UNIQUE` (`email`)
);
I have given all the columns in the stored procedure. Please help me with this.
It was an issue with the CAST funation. Using CONCAT() fixed the issue,
CREATE DEFINER=`root`#`localhost` PROCEDURE `GenerateManagerData`()
BEGIN
DECLARE i INT DEFAULT 38;
WHILE i <= 100 DO
INSERT INTO projectManager(name,email,contact_number) VALUES (CONCAT('M', i), CONCAT('e', i, '#gmail.com'), CONCAT('TP', i));
SET i = i + 1;
END WHILE;
END

Stored procedure not working as expected

Am trying to create a stored procedure that will notify me if a username or email already exists in the table.
Here is the structure of my table
CREATE TABLE IF NOT EXISTS `user` (
`user_id` smallint(5) unsigned NOT NULL,
`username` varchar(40) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`email` varchar(60) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`password` varchar(128) NOT NULL,
`active` tinyint(4) NOT NULL DEFAULT '1',
`date_joined` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`user_category_id` tinyint(3) unsigned NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;
and here is the code for the stored procedure
DELIMITER $$
CREATE PROCEDURE `sp_create_account`( username_param VARCHAR(40), email_param VARCHAR(60), pass VARCHAR(30), category_id TINYINT )
BEGIN
DECLARE salt VARCHAR(60);
DECLARE username_var VARCHAR(40);
DECLARE email_var VARCHAR(60);
SELECT username_var INTO username_var FROM user WHERE username = username_param;
SELECT email_var INTO email_var FROM user WHERE email = email_param;
IF username_var = username_param THEN
SELECT 'username' AS message;
ELSEIF email_var = email_param THEN
SELECT 'email' AS message;
ELSE
SET salt = '#4$^7EC%?';
SET salt = CONCAT( username_param, salt );
INSERT INTO user VALUES
( DEFAULT, username_param, email_param, AES_ENCRYPT( pass, salt ), DEFAULT, DEFAULT, category_id );
SELECT 'created' AS message;
END IF;
END$$
DELIMITER ;
Two problems:
Problem 1:
Everything works fine when inserting an unique entry in which has the username or email does not exist, but when the username or email does exist i get these errors in the screenshot below yet i expect the stored procedure to return a simple select indicating where the problem could be or indicated success as the in case when it returns 'created'
Problem 2
If it is a unique entry and it gets inserted into the table, the password column cell in that particular row gets inserted with an empty string.
What could be the cause of all the above? Thanks you.
Perhaps these changes are what you are looking for. Changes to the schema, and your if blocks, and return values.
The return value is the AUTO_INCREMENT of the user id. Note, I pretty much followed your schema. Your Primary Key in that table could probably be collapsed a bit. Some might go lean with no user id or user name, but just the email address as the PK. Those are things to think about. I also added a unique key for email address.
Schema:
CREATE TABLE IF NOT EXISTS `user` (
`user_id` int auto_increment primary key,
`username` varchar(40) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`email` varchar(60) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`password` varbinary(128) NOT NULL,
`active` tinyint(4) NOT NULL DEFAULT '1',
`date_joined` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`user_category_id` tinyint(3) unsigned NOT NULL,
unique key (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- truncate table user;
Stored Procedure:
drop procedure if exists sp_create_account;
DELIMITER $$
CREATE PROCEDURE `sp_create_account`
( username_param VARCHAR(40),
email_param VARCHAR(60),
pass VARCHAR(30),
category_id TINYINT
)
BEGIN
DECLARE salt VARCHAR(60);
DECLARE username_var VARCHAR(40);
DECLARE email_var VARCHAR(60);
DECLARE recFound int;
DECLARE foundStatus int DEFAULT 0;
SELECT user_id INTO recFound FROM user WHERE username = username_param;
IF recFound is null THEN
SELECT user_id INTO recFound FROM user WHERE email = email_param;
IF recFound is not null THEN
SET foundStatus=1;
END IF;
ELSE
SET foundStatus=1;
END IF;
IF foundStatus=0 THEN
SET salt = '#4$^7EC%?';
SET salt = CONCAT( username_param, salt );
INSERT INTO user (username,email,password,active,date_joined,user_category_id) VALUES
( username_param, email_param, AES_ENCRYPT( pass, salt ), DEFAULT, DEFAULT, category_id );
set recFound=LAST_INSERT_ID();
END IF;
SELECT recFound;
END$$
DELIMITER ;
Test:
call sp_create_account('Katherine','ksmith#hotmail.com','thepass01',101);
call sp_create_account('Katherine','ksmith#hotmail.com','thepass01',101);
call sp_create_account('Katherine','ksmith#hotmail.com','thepass01',101);
call sp_create_account('caspar','caspar001#gmail.com','thepass02',77);
select * from user;
+---------+-----------+---------------------+------------------+--------+---------------------+------------------+
| user_id | username | email | password | active | date_joined | user_category_id |
+---------+-----------+---------------------+------------------+--------+---------------------+------------------+
| 1 | Katherine | ksmith#hotmail.com | _╦*Fó▄GàB╔┌O►²§' | 1 | 2016-07-13 17:56:54 | 101 |
| 2 | caspar | caspar001#gmail.com | ♀½B§5U├↨I♀#*├ ∟L | 1 | 2016-07-13 17:57:09 | 77 |
+---------+-----------+---------------------+------------------+--------+---------------------+------------------+
2 rows in set (0.00 sec)
Your last ELSE needs to have all the commands you expect to execute in it enclosed in BEGIN ... END. Maybe? I've been working more in MSSQL lately.

Create Table and Insert using stored Procedure

I'am trying to create a procedure checking table and insert
but it show me some error which i'am not sure how to fix it
this is the error code
Explicit or implicit commit is not allowed in stored function or
trigger
DELIMITER ;;
CREATE FUNCTION `getLabel`(paradocid INT, paradoctype char(10),paradoclineid INT,paraqty INT,paracreated date,paracreatedby INT) RETURNS int(100)
BEGIN
DECLARE transtotal int;
DECLARE i int DEFAULT 0;
DECLARE total int;
CREATE TABLE IF NOT EXISTS `sim_lable`(
`label_id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
`doctype` varchar(10) NOT NULL,
`docid` int NOT NULL,
`doclineid` int NOT NULL,
`created` date NOT NULL,
`createdby` int NOT NULL
) ENGINE='InnoDB' COLLATE 'utf8_unicode_ci';
DELETE FROM sim_lable where
(TIME_TO_SEC(TIMEDIFF(paracreatedby,createdby))/60) >30;
SELECT #total=coalesce(count(*),0) as total2 from sim_label where
doctype=paradoctype and paradocid=docid;
IF total = 0 THEN
WHILE i < paraqty DO
INSERT INTO dbo.Students
(
`doctype` ,
`docid`,
`doclineid` ,
`created` ,
`createdby`
)
VALUES
(
paradoctype,
paradocid,
paradoclineid,
paracreated,
paracreatedby
) ;
END WHILE;
END IF;
END
As the error message says, explicit or implicit commit is not allowed in stored function or trigger. CREATE TABLE statement causes an implicit commit, therefore it is not allowed in a function.
Your code does not seem to return any value (there is no return statement in the function's body) and what you are doing there should be done in a stored procedure, rather than in a function.

ORA-02070: database [MySQL] does not support subqueries in this context. - ORACLE

I have the following tables:
MySQL table: member_interact
CREATE TABLE `member_interact` (
`INT_MEMBER_ID` int(11) NOT NULL,
`INT_ID` int(11) NOT NULL AUTO_INCREMENT,
`INT_SOURCE` varchar(1) NOT NULL,
`INT_DATE` datetime DEFAULT NULL,
`INT_TYPE` varchar(30) NOT NULL,
`COPY_TO_STG` varchar(12) NOT NULL DEFAULT 'NO',
`NEW_STG_SEQ` int(11) DEFAULT NULL,
`COPY_TO_STG_DATE` datetime DEFAULT NULL,
PRIMARY KEY (`INT_ID`),
UNIQUE KEY `INT_ID_UNIQUE` (`INT_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=31246 DEFAULT CHARSET=utf8$$
Oracle table: MEMBER_INTERACT_MYSQL_STG
CREATE TABLE "JTI_HTP"."MEMBER_INTERACT_MYSQL_STG"
( "INT_MEMBER_ID" NUMBER(10,0) NOT NULL ENABLE,
"INT_ID" NUMBER(10,0),
"INT_SOURCE" NVARCHAR2(1) NOT NULL ENABLE,
"INT_DATE" DATE,
"INT_TYPE" NVARCHAR2(30) NOT NULL ENABLE,
"INSERTING_DATE" DATE,
"MYSQL_ID" NUMBER(12,0)
) SEGMENT CREATION DEFERRED
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
TABLESPACE "USERS" ;
Basically, I need to copy member_interact into member_interact_mysql_stg with adding new columns as follow:
MEMBER_INTERACT_MYSQL_STG.STG_INT_ID = NEW_SEQ
MEMBER_INTERACT_MYSQL_STG.MYSQL_INT_ID = MEMBER_INTERACT.INT_ID
MEMBER_INTERACT.COPY_TO_STG = 'YES', once the copy operation is completed.
MEMBER_INTERACT.NEW_STG_SEQ = MEMBER_INTERACT_MYSQL_STG.STG_INT_ID
I have created the following Procedures:
create or replace PROCEDURE COPY_MYSQL_MOB_INT_TO_STG(
P_BATCH_NO IN NUMBER)
IS
CURSOR src
IS
SELECT *
FROM "jtipartn_mydb"."MEMBER_INTERACT"#"JTIPARTNER_HTP"
WHERE "NEW_STG_SEQ" IS NULL
AND "INT_ID" <= 7000;
STG_INT_ID NUMBER;
BEGIN
FOR des IN src
LOOP
STG_INT_ID := STG_SEQ.NEXTVAL;
INSERT
INTO MEMBER_INTERACT_MYSQL_STG VALUES
(
DES.INT_MEMBER_ID,
STG_INT_ID,
des.int_source,
des.int_date,
des.int_type,
NULL,
DES.INT_ID
);
UPDATE_COPIED_MEMBER_INTERACT(STG_INT_ID, DES.INT_ID);
COMMIT;
END LOOP;
END;
create or replace PROCEDURE UPDATE_COPIED_MEMBER_INTERACT( STG_INT_ID IN NUMBER, MYSQL_INT_ID IN NUMBER)
IS
BEGIN
UPDATE "jtipartn_mydb"."MEMBER_INTERACT"#"JTIPARTNER_HTP"
SET "COPY_TO_STG" = 'YES',
"NEW_STG_SEQ" = STG_INT_ID
WHERE "INT_ID" = MYSQL_INT_ID;
END;
In fact, there were one procedure to update both tables, but due the error I received I find it might be easier to eliminate the eror by separating the procedure into two.
The error I get is :
ORA-02047: cannot join the distributed transaction in progress
ORA-06512: at "JTI_HTP.UPDATE_COPIED_MEMBER_INTERACT", line 19
ORA-06512: at "JTI_HTP.COPY_MYSQL_MOB_INT_TO_STG", line 28
ORA-06512: at line 6
line 19 is where the second procedure is called. Which I suspected that something has to do with the MySQL table update.
UPDATE
I have updated my script based on #Maheswaran Ravisankar answer as follow:
CREATE OR REPLACE PROCEDURE COPY_MYSQL_MOB_INT_TO_STG_V3(
P_BATCH_NO IN NUMBER)
IS
BEGIN
INSERT INTO MEMBER_INTERACT_MYSQL_STG
SELECT "INT_MEMBER_ID",
STG_SEQ.NEXTVAL,
"INT_SOURCE",
"INT_DATE",
"INT_TYPE",
CURRENT_DATE,
"INT_ID"
FROM "jtipartn_mydb"."MEMBER_INTERACT"#"JTIPARTNER_HTP" des
WHERE "NEW_STG_SEQ" IS NULL;
UPDATE "jtipartn_mydb"."MEMBER_INTERACT"#"JTIPARTNER_HTP" A
SET "COPY_TO_STG" = 'YES',
"NEW_STG_SEQ" =
(SELECT STG_INT_ID
FROM MEMBER_INTERACT_MYSQL_STG B
WHERE A."INT_ID" = B.STG_INT_ID
);
END;
However, I am getting error ORA-02070: database JTIPARTNER_HTP does not support subqueries in this context.
INSERT
INTO MEMBER_INTERACT_MYSQL_STG
SELECt
DES.INT_MEMBER_ID,
STG_SEQ.NEXTVAL,
des.int_source,
des.int_date,
des.int_type,
NULL,
DES.INT_ID
FROM "jtipartn_mydb"."MEMBER_INTERACT"#"JTIPARTNER_HTP" des
WHERE "NEW_STG_SEQ" IS NULL
/* RETURNING STG_INT_ID BULK COLLECT INTO SOME RECORD; --Needed if only processed in array!*/
And update like below,
UPDATE "jtipartn_mydb"."MEMBER_INTERACT"#"JTIPARTNER_HTP" A
SET "COPY_TO_STG" = 'YES',
"NEW_STG_SEQ" = (SELECT STG_INT_ID FROM MEMBER_INTERACT_MYSQL_STG B
WHERE A.INT_ID = B.INT_ID);
(OR)
FOR REC IN (SELECT STG_INT_ID,INT_ID FROM MEMBER_INTERACT_MYSQL_STG)
LOOP
UPDATE "jtipartn_mydb"."MEMBER_INTERACT"#"JTIPARTNER_HTP" A
SET "COPY_TO_STG" = 'YES',
"NEW_STG_SEQ" = REC.STG_INT_ID
WHERE A.INT_ID = REC.INT_ID;
END LOOP;

Generate auto incremented id for BPM application

Within a BPM web application, I have a field for an invoice # on a particular page but I need for it to be auto generated every time a user attaches an invoice and views that page. That number must be unique and preferably auto-incremented. A value for the invoice # field can be displayed by querying from a table from an external MYSQL database. So every time a user lands on that particular page, a SELECT query statement can be fired.
On MYSQL end, how would I set this up? So basically, I would like to setup a query for that invoice # field where it will for run a query for example,
SELECT invoice_num FROM invoice_generator
and every time this query runs, it would return the next incremented number.
You can use mysql trigger concept here....
I have added one example here...
It will be very usefull for u (see this link also :http://www.freemindsystems.com/mysql-triggers-a-practical-example/)
CREATE TABLE `products` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL DEFAULT '',
`price` int(20) NOT NULL DEFAULT '0',
`other` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `products_name_idx` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `freetags` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`tag` varchar(50) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `freetagged_objects` (
`tag_id` int(20) NOT NULL DEFAULT '0',
`object_id` int(20) NOT NULL DEFAULT '0',
`tagged_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`module` varchar(50) NOT NULL DEFAULT '',
PRIMARY KEY (`tag_id`, `object_id`),
KEY `freetagged_objects_tag_id_object_id_idx` (`tag_id`, `object_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
INSERT_PRODUCTS_TAGS
DELIMITER ||
DROP TRIGGER IF EXISTS insert_products_tags;
||
DELIMITER ##
CREATE TRIGGER insert_products_tags AFTER INSERT ON products
FOR EACH ROW
BEGIN
DECLARE current_id integer;
DECLARE tag_id integer;
DECLARE next integer;
DECLARE tag_field varchar(255);
DECLARE next_sep integer;
DECLARE current_tag varchar(255);
DECLARE right_tag varchar(255);
-- We use the field other as comma-separated tag_field
SET tag_field = NEW.other;
-- Check for empty tags
IF (CHAR_LENGTH(tag_field) <> 0) THEN
-- Loop until no more ocurrencies
set next = 1;
WHILE next = 1 DO
-- Find possition of the next ","
SELECT INSTR(tag_field, ',') INTO next_sep;
IF (next_sep > 0) THEN
SELECT SUBSTR(tag_field, 1, next_sep - 1) INTO current_tag;
SELECT SUBSTR(tag_field, next_sep + 1, CHAR_LENGTH(tag_field)) INTO right_tag;
set tag_field = right_tag;
ELSE
set next = 0;
set current_tag = tag_field;
END IF;
-- Drop spaces between comas
SELECT TRIM(current_tag) INTO current_tag;
-- Insert the tag if not already present
IF (NOT EXISTS (SELECT tag FROM freetags WHERE tag = current_tag)) THEN
-- Insert the tag
INSERT INTO freetags (tag) values (current_tag);
SELECT LAST_INSERT_ID() INTO tag_id;
ELSE
-- Or get the id
SELECT id FROM freetags WHERE tag = current_tag INTO tag_id;
END IF;
-- Link the object tagged with the tag
INSERT INTO freetagged_objects
(tag_id, object_id, module)
values
(tag_id, NEW.id, 'products');
END WHILE;
END IF;
END;
##
Now If you execute an insert on products table:
INSERT INTO PRODUCTS
(name, price, other)
values
("product1", 2, "tag1, tag2,tag3 , tag 4");