Hi still trying to debug this issue so I've stripped things down to the bare basics, following the PHP manual.
SP:
DROP IF EXISTS(`login_validator`);
CREATE PROCEDURE `login_validator` (
IN Username VARCHAR(75),
OUT ReturnValue VARCHAR(1000)
)
BEGIN
END
PHP call:
$SP1SQL = 'call login_validator(:Username, :ReturnValue)';
$Stmt = $DBConnection->Prepare($SP1SQL);
$Stmt->BindParam('Username', $Name, PDO::PARAM_STR);
$Return = null;
$Stmt->BindParam(':ReturnValue', $Return, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT, 1000);
$Stmt->Execute();
I get:
SQLSTATE[42000]: Syntax error or access violation: 1414 OUT or INOUT argument 2 for routine myDB.login_validator is not a variable or NEW pseudo-variable in BEFORE trigger
Everything I read says this should work...
I'm trying to get this sp to update the user_login_attempts tbl if the user enters the wrong username and return some values to the calling script.
When called The SP runs without errors and returns only one value
I expect it's some flaw in my logic, but I can't spot it...
I'm calling it like this
$SP1 = 'call login_authentication(:Username, :LoginIP, :IPGeoLocation, #ReturnStatus)';
// binding variables
// execute
If I vardump
$SP1RS = $Stmt->fetchAll(PDO::FETCH_ASSOC);
var_dump($SP1RS);
I get back the correct value of v_Username and all the other values are set to SP's default declarations
If I call it the usual way
$SP1 = 'call login_authentication(:Username, :LoginIP, :IPGeoLocation, :ReturnStatus)';
I get the error MySQL :: Error 1414 OUT or INOUT argument 4 for routine login_authentication is not a variable or NEW pseudo-variable in BEFORE trigger.
CREATE PROCEDURE `login_authentication`(
IN `v_Username` VARCHAR(75),
IN `v_LoginIP` VARBINARY(16),
IN `v_IPGeoLocation` VARCHAR(30),
INOUT `v_ReturnStatus` VARCHAR(1000)
)
BEGIN
DECLARE v_QueryDB BOOLEAN DEFAULT 1;
DECLARE v_Error BOOLEAN DEFAULT 0;
DECLARE v_ErrorMsg VARCHAR(250) DEFAULT null;
DECLARE v_Attempts TINYINT(1) DEFAULT 0;
DECLARE v_LastAttempt TIMESTAMP DEFAULT null;
DECLARE v_Hash VARBINARY(256) DEFAULT null;
# DECLARE v_LoginIP VARBINARY(16) DEFAULT INET_ATON(v_LoginIP);
SET v_LoginIP = INET_ATON(v_LoginIP);
# Check if user has any previous unsuccessful login attempts
IF EXISTS(SELECT Username FROM users_login_attempts WHERE Username = v_Username AND Attempts > 4) THEN
SELECT Attempts INTO v_Attempts FROM users_login_attempts WHERE Username = v_Username;
SELECT LastAttempt INTO v_LastAttempt FROM users_login_attempts WHERE Username = v_Username; # Get time of last users last login
# User has been timed out
IF (v_Attempts = 5 AND v_LastAttempt > (NOW() - INTERVAL 10 minute)) THEN
SET v_Error = 1;
SET v_ErrorMsg = 'Sorry, you are still timed out!';
SET v_QueryDB = 0;
END IF;
# other conditions
END IF;
# Query DB for valid username
IF (v_QueryDB = 1) THEN
# Query DB for password hash
IF EXISTS(SELECT Password FROM users WHERE(Email = v_Username || Mobile = v_Username)) THEN
SELECT Password INTO v_Hash FROM users WHERE(Email = v_Username || Mobile = v_Username);
ELSE
# Username not found in DB
# Update user logins table with failed attempt if not already locked
IF (v_Attempts < 7) THEN
INSERT INTO users_login_attempts(
Username,
Attempts,
IPAddress,
IPGeoLocation)
VALUES(
v_Username,
v_Attempts,
v_LoginIP,
v_IPGeoLocation)
ON DUPLICATE KEY UPDATE
Attempts = Attempts +1,
IPAddress = VALUES(IPAddress),
IPGeoLocation = VALUES(IPGeoLocation);
# Update Attempts from DB
SELECT Attempts INTO v_Attempts FROM users_login_attempts WHERE Username = v_Username;
END IF;
END IF;
# Set error messages for failed login attempts
IF (v_Attempts > 0) THEN
SET v_ErrorMsg = 'The supplied credentials were not recognised'; # Default msg
IF (v_Attempts = 5) THEN
SET v_Error = 1;
SET v_ErrorMsg = 'Due to repeated failed login attempts, Your account has been temporarily locked for 10 minutes!';
END IF;
# more conditions
END IF;
END IF;
# set output result
IF (v_Hash != null) THEN
SELECT v_Hash AS PasswordHash;
ELSE
SELECT v_ErrorMsg AS ErrorMsg,
v_Attempts AS LoginAttempts,
INET_NTOA(v_LoginIP) AS IPAddress,
v_Username AS Username;
END IF;
END
check this line:
$Stmt->BindParam(':Username', $Name, PDO::PARAM_STR);
especially ':Username'
Related
I'm writting a function in MySQL which has to check that the values from PHP form exists in Database.
I have tried to return a VARCHAR variable from my function which is set in SELECT... CASE statement by a CONCAT function, but still i see an error.
CREATE FUNCTION checkNewUser(login VARCHAR(30),password VARCHAR(255),email VARCHAR(255))
RETURNS VARCHAR(255)
BEGIN
set #result = "";
SELECT user_login,user_password,user_email,
CASE
WHEN user_login = login THEN #result = CONCAT(#result," This login is not avaible!")
WHEN user_password = password THEN #result = CONCAT(#result," This password is not avaible!")
WHEN user_email = email THEN #result = CONCAT(#result," This email is not avaible!")
ELSE #result = NULL
END
FROM users;
RETURN #result;
END//
I want to return an information, which value from form is wrong. But i still see an error: ERROR 1415 (0A000): Not allowed to return a result set from a function
I'm trying to find if the user has been allotted shares using mySql query. I have those queries in a function and it return 'No' all the time. However If I run the following queries at mySql command prompt I get 'Yes'. I have been breaking my head over this.. Very silly though.. Not able able to crack it. Any help would be appreciated. Thx!
//This returns 0 because the employee has been allotted shared now
//THIS IS THE MOST RECENT RECORD
SELECT ISNULL(NewEquityShares) INTO #PRESENT FROM System_Users_Share_Allotment_Info WHERE UserID = 'xyz' AND MostRecentRecord = 'Yes';
//This returns 1 because the employee was not allotted shared before
//THIS IS ONE RECORD BEFORE THE MOST RECENT RECORD
SELECT ISNULL(NewEquityShares) INTO #PREVIOUSLY FROM System_Users_Share_Allotment_Info WHERE UserID = 'xyz' AND MostRecentRecord = 'No';
//
SELECT IF ( #PRESENT = 0 AND #PREVIOUSLY = 1,'Yes','No');
mySQL Function:
DELIMITER $$
CREATE FUNCTION `fn_isNewSharesAlloted`(UserID VARCHAR(36)) RETURNS VARCHAR(3) CHARSET utf8
BEGIN
DECLARE strResponse VARCHAR(3) DEFAULT NULL;
DECLARE strUserID VARCHAR(36) DEFAULT NULL;
SET strUserID = UserID;
-- This returns 0 because the employee has been allotted shared now
SELECT ISNULL(NewEquityShares) INTO #PRESENT FROM System_Users_Share_Allotment_Info WHERE UserID = strUserID AND MostRecentRecord = 'Yes';
-- This returns 1 because the employee was not allotted shared before
SELECT ISNULL(NewEquityShares) INTO #PREVIOUSLY FROM System_Users_Share_Allotment_Info WHERE UserID = strUserID AND MostRecentRecord = 'No';
SELECT IF ( #PRESENT = 0 AND #PREVIOUSLY = 1,'Yes','No') INTO strResponse;
RETURN strResponse;
END$$
DELIMITER ;
I am working Login Authentication with Stored Procedures in MySQL Database.
Below is the code, i wrote but its not working. Let me know, what is wrong.
I have below questions
How to check, whether CURSOR is empty or null
Is there any way, we write the procedure.
What I am doing..
Taking two input parameters and two parameters for ouput.
Check if the user or password is not valid, stored those values in OUT parameters
SELECT 'Invalid username and password', 'null' INTO oMessage, oUserID;
If user and password in valid, but isActive column is 0 then
SELECT 'Inactive account', 'null' INTO oMessage, oUserID;
If success,
SELECT 'Success', v_UserID INTO oMessage, oUserID;
SQL Code
DELIMITER $$
USE `acl`$$
CREATE
DEFINER = `FreeUser`#`localhost`
PROCEDURE `acl`.`checkAuthenticationTwo`(
IN iUsername VARCHAR(50),
IN iPassword VARCHAR(50),
OUT oMessage VARCHAR(50),
OUT oUserID INT
)
BEGIN
DECLARE v_isActive INT;
DECLARE v_UserID INT;
DECLARE v_count INT;
DECLARE cur1 CURSOR FOR SELECT UserID, IsActive FROM m_users WHERE (LoginName = TRIM(iUsername) OR Email = TRIM(iUsername)) AND `Password` = iPassword;
OPEN cur1;
SET v_count = (SELECT FOUND_ROWS());
IF (v_count > 0)
FETCH cur1 INTO v_UserID, v_isActive;
IF (v_isActive = 0) THEN
SELECT 'Inactive account', 'null' INTO oMessage, oUserID;
ELSE
SELECT 'Success', v_UserID INTO oMessage, oUserID;
END IF;
ELSE
SELECT 'Invalid username and password', 'null' INTO oMessage, oUserID;
END IF;
END$$
DELIMITER ;
You definitely don't need CURSORs for that; use plain simple SELECT. A more concise version of your SP might look like
DELIMITER $$
CREATE DEFINER = `FreeUser`#`localhost` PROCEDURE `acl`.`checkAuthenticationTwo`
(
IN iUsername VARCHAR(50),
IN iPassword VARCHAR(50),
OUT oMessage VARCHAR(50),
OUT oUserID INT
)
BEGIN
SELECT CASE WHEN IsActive = 0 THEN 'Inactive account' ELSE 'Success' END,
CASE WHEN IsActive = 0 THEN NULL ELSE UserID END
INTO oMessage, oUserID
FROM m_users
WHERE (LoginName = TRIM(iUsername)
OR Email = TRIM(iUsername))
AND `Password` = iPassword
LIMIT 1; -- you better protect yourself from duplicates
SET oMessage = IFNULL(oMessage, 'Invalid username and password');
END$$
DELIMITER ;
What it does it tries to select a row where username or email equals to iUsername and password equals to iPassword and outputs two values to output variables. Along the way it uses CASE to look at isActive value. If it's 0 then sets a message to 'Inactive' and NULL for userid. Otherwise it returns 'Success' message and real userid that has been found. Now, if a user has not been found both variables will be set to NULL. We can leverage that and use IFNULL() function to detect that fact and set a message to 'Invalid username and password'.
Here is SQLFiddle demo
Personally I'd go further and simplify it a bit more and make it a one-statement SP with the following interface:
Returns:
userid (which is > 0) if a user with username and password if found
0 - username and(or) password incorrect
-1 - a user is inactive
The idea is that it's a presentation layer's task to produce appropriate messages for the user and not scatter all those message literals across data layer.
CREATE DEFINER = `FreeUser`#`localhost` PROCEDURE `acl`.`checkAuthenticationThree`
(
IN iUsername VARCHAR(50),
IN iPassword VARCHAR(50),
OUT oUserID INT
)
SET oUserID = IFNULL(
(
SELECT CASE WHEN IsActive = 0 THEN -1 ELSE UserID END
FROM m_users
WHERE (LoginName = TRIM(iUsername)
OR Email = TRIM(iUsername))
AND `Password` = iPassword
LIMIT 1 -- you better protect yourself from duplicates
), 0);
Here is SQLFiddle demo
this is my first mySQL stored-function 'cause i've always managed such things with php.
I want a function that checks if a user can log in my client-area.
I wrote the code above:
DELIMITER $$
CREATE FUNCTION `A05`.`login` (user VARCHAR(64),pass VARCHAR(64)) RETURNS INT
BEGIN
declare num_rows int;
declare id int;
SELECT (#num_rows:=COUNT(*)),(#id:=`Credential_id`) FROM `A05`.`Credentials` where `Credential_UserName` = user;
if num_rows = 0 then
-- user not present
return (-1);
end if;
-- user present, checking password
SELECT (#num_rows:=COUNT(*)),(#id:=`Credential_id`) FROM `A05`.`Credentials` where `Credential_id` = id AND `Credential_PASSWORD` = SHA1(pass);
if num_rows = 0 then
-- user presente, password incorrect
INSERT INTO `a05`.`Events` (
`Event_id` ,
`Event_RegistrationDate` ,
`Event_VariationDate` ,
`Event_State`,
`Event_Notes`,
`Event_SenderId`,
`Event_Type`
)
VALUES (
NULL , NOW(), NOW(), 'wp', NULL, id, 1
);
return (-2);
end if;
-- user present, password correct
UPDATE `A05`.`Credentials` SET `Credential_LastAccess`=NOW() where `Credential_id` = id;
INSERT INTO `a05`.`Events` (
`Event_id` ,
`Event_RegistrationDate` ,
`Event_VariationDate` ,
`Event_State`,
`Event_Notes`,
`Event_SenderId`,
`Event_Type`
)
VALUES (
NULL , NOW(), NOW(), 'ok', NULL, id, 0
);
return id;
END
I think that the syntax should be right except for the last statement return id cause i return a set instead of an integer.
The problem is that when i try to store this function on mysql i get this error:
Error 1415: Not allowed to return a result set from a function
Then i changed the last statement from 'return id' to 'return 0' for testing purpose but i keep getting the same error.
Probably is a newbie error cause it's the very first time for me on sql "advanced" scripting.
Thank you very much in advance!
I have the following function. When I try to create it on a webserver, it fails with
You do not have the SUPER privilege and binary logging is enabled (you might want to use the less safe log_bin_trust_function_creators variable)
I never had the same problem with any other webhosting (and the exact same function), how can I fix this? (I can't change MySQL settings).
CREATE FUNCTION `has_action_access`(in_role VARCHAR(255), in_request VARCHAR(255), in_action VARCHAR(255)) RETURNS tinyint(1)
READS SQL DATA
DETERMINISTIC
BEGIN
DECLARE current_role VARCHAR(255);
DECLARE found, cont TINYINT(1) DEFAULT 0;
SET current_role = in_role;
findattempt: REPEAT
SELECT COUNT(*) FROM cyp_action_access WHERE request = in_request AND action = in_action AND role = current_role INTO found;
IF found = 0 THEN
SELECT COUNT(*) FROM cyp_roles WHERE name = current_role INTO cont;
IF cont = 1 THEN
SELECT inherits FROM cyp_roles WHERE name = current_role INTO current_role;
END IF;
END IF;
UNTIL (cont = 0 OR found > 0) END REPEAT;
RETURN found;
END;
MySQL server's version is 5.0.90-log.
Your user does not have super privilege. You will need to contact your webhosting provider and have them update this. If they will not grant you that option ask them to execute the script for you.