create a sql procedure - sql-server

im trying to create a procedure query with ms-sql for my game but Im kinda stucked..
Lets say,
I have a database with username and password rows.
I use the procedure query to select the username and password.
If everything is right, then the procedure will output the "result-code"
How I call the procedure query
BEGIN_DECLARE_SQLUNIT( SP_AccountSelect, "{ call AccountAuth(?,?) }" )
BEGIN_VARIABLE()
char m_szUserID[MAX_SIZE_USER_ID + 1];
char m_szUserPW[MAX_SIZE_USER_ID + 1];
int m_nResultCode;
END_VARIABLE()
BEGIN_PARAM(3)
PARAM_ENTRY_STR(SQL_PARAM_INPUT, m_szUserID)
PARAM_ENTRY_STR(SQL_PARAM_INPUT, m_szUserPW)
PARAM_ENTRY(SQL_PARAM_OUTPUT, m_nResultCode)
END_PARAM()
END_DECLARE_SQLUNIT()
procedure I have till now:
ALTER PROCEDURE [dbo].[AccountAuth] /* Procedure Name. */
#m_szUserID varchar(20),
#m_szUserPW varchar(50)
AS
SET NOCOUNT ON;
DECLARE #m_nResultCode int
select #m_nResultCode = 100
BEGIN
SELECT #m_szUserID = username, #m_szUserPW = password
FROM account
WHERE username = #m_szUserID;
END
my problem now is that I dont know how I make IFS like checking if the username is right, if the password is right.. because I always have to make different result code. Login wrong = result code 100, wrong username = 101, wrong password = 102..
Im searching for hours now but I cant find anything useful.
Does anyone know a link where I can find helpful things?

This is the most basic procedure you can write for a login call, but in real life application you will need to check logins which exists but maybe disabled, deleted, not logged in for over some period of time and bla bla. You can add as many as check needed to make sure only authorised people has access.
Try something like this.....
ALTER PROCEDURE [dbo].[AccountAuth] /* Procedure Name. */
#m_szUserID varchar(20),
#m_szUserPW varchar(50),
#m_nResultCode int OUTPUT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Password varchar(50);
IF EXISTS(SELECT 1 FROM account WHERE username = #m_szUserID)
BEGIN
SELECT #Password = [password]
FROM account
WHERE username = #m_szUserID;
IF (#Password = #m_szUserPW)
BEGIN
SET #m_nResultCode = 1; -- 1 for successful login
END
ELSE
BEGIN
SET #m_nResultCode = 0; -- 0 for Unsuccessful login
END
END
ELSE
BEGIN
SET #m_nResultCode = 2; -- 2 if User Name does not exists
END
END
Calling Stored Procedure
DECLARE #OUT_Result INT;
EXECUTE [dbo].[AccountAuth] #m_szUserID = 'UserName'
,#m_szUserPW = '123456'
,#m_nResultCode = #OUT_Result OUTPUT
-- Now do what ever you need to do with #OUT_Result variable.

Related

Stored Procedure that it's not working

I have this procedure, but it doesn't work..I can't figure it out why. Any ideas what am I doing wrong?
CREATE PROCEDURE [dbo].[spCheckLogin]
( #Username varchar(30),
#Password varchar(15))
AS
BEGIN
Declare
#Result int = 0;
IF (#Password=(SELECT password from users where Username=#Username))
set #Result=1
ELSE
set #Result=0
return #Result
END
GO
The comparison you are using is incorrect. It should be something like:
IF EXISTS (SELECT 1 from users where Username=#Username AND password = #password)
Also note that storing passwords in plaintext is not a good practice. Suggested reading: Why are plain text passwords bad, and how do I convince my boss that his treasured websites are in jeopardy?
Instead of a return value you would want to use an output value. However a return value is of type integer, thus might work for you.
You would never want to use a plain password stored, but I would assume you are doing this just for testing purposes on a hobby project.
CREATE PROCEDURE [dbo].[spCheckLogin]
( #Username varchar(30),
#Password varchar(15))
AS
BEGIN
Declare #Result int = case
when exists (SELECT *
from users
where Username=#Username and password = #Password))
THEN 1
ELSE 0
END
return #Result
END
GO
Like metnioned, use an OUTPUT paramter:
CREATE PROC [dbo].[spCheckLogin] #Username varchar(30),
#Password varchar(30),
#Success bit OUTPUT
AS
BEGIN
IF EXISTS (SELECT 1
FROM users
WHERE Username = #Username
AND Password = #Password)
BEGIN
SET #Success = 1;
END
ELSE
BEGIN
SET #Success = 0;
END
END
But, also, as mentioned, don't store passwords in an unhashed and unsalted format in your database. If you are, change your design.

How to get a output response as integer from a stored procedure in SQL Server

I'm trying to get the following response from a stored procedure to authenticate the user and read a response from stored procedure based on the user input.
CREATE Procedure sp_UserAuthentication
#UserName varchar(20),
#UserPassword varchar(20),
#Resp int output
AS
DECLARE #Count int;
DECLARE #IsAdmin bit;
DECLARE #IsActive bit;
Select #Count = COUNT(UserName) from tbl_UserDetails where UserName = #UserName and UserPassword = #UserPassword
IF #Count = 1
BEGIN
Select #IsActive = IsActive, #IsAdmin = #IsAdmin from tbl_UserDetails where UserName = #UserName and UserPassword = #UserPassword
IF #IsActive = 0 -- InActive user
BEGIN
SET #Resp = 3
END
ELSE IF #IsAdmin = 1 -- Admin user
BEGIN
SET #Resp = 2
END
ELSE -- Normal user
BEGIN
SET #Resp = 1
END
END
ELSE -- InValid user
BEGIN
SET #Resp = 0
END
GO
I'm getting response as always 1 for a valid user and 0 for invalid user. I'm not getting the response as 2 for admin and 3 for an inactive user.
DECLARE #Res int
exec sp_UserAuthentication 'user', 'pwd', #Res out
SELECT #Res
Table:
Create Table tbl_UserDetails(
UserName Varchar(20) primary key,
UserPassword Varchar(20) NOT NULL,
IsAdmin Bit Default 0,
IsActive Bit Default 1
);
Keep in mind everybody's stern reprimands about storing clear text passwords. You desperately need to read about and understand how to encrypt these. But your entire procedure could be greatly simplified to something like this.
CREATE Procedure UserAuthentication
(
#UserName varchar(20),
#UserPassword varchar(20),
#Resp int output
)
AS
set #Resp = 0 --This sets the response to invalid unless we actually find a user
Select #Resp =
case when IsActive = 0 then 3 --Inactive User
when IsAdmin = 1 then 2 --Admin user
else 1 --Normal user
end
from tbl_UserDetails
where UserName = #UserName
and UserPassword = #UserPassword
Let's ignore that you're putting usernames and passwords into a table. Please don't do that, and if you do, please use some kind of encryption/hashing. But look in your SELECT statement in the middle:
Select #IsAdmin = #IsAdmin
You are setting #IsAdmin to #IsAdmin, you need to set that to just IsAdmin.

Can I use output variables to get a value?

I have a stored procedure where I'm checking if username exists and if it does not exists insert into user table then gets userid for the same username. I was trying to use an output variable to get the userid. Am I going about this wrong?
alter Procedure Check_User_Name
(
#username varchar(25),
#password varchar(100),
#role_id integer,
#idn nvarchar output
)
As
Begin
IF NOT EXISTS(SELECT idn=#idn
FROM [user] WHERE username = #username)
BEGIN
INSERT INTO [user] (username,[password],role_id) VALUES
(#username, #password,#role_id)
--select #idn=idn from [user]
Print 'UserName inserted successfully'
End
Else IF EXISTS(SELECT * FROM [user] WHERE username = #username)
Begin
Print 'UserName already exists'
End
END
You had it close -- After replacing your column names to match with what is in my user table, this worked for me. (I think I replaced everything back).
On your Else, you're basically doing a second lookup by username - which is unnecessary in this case.
ALTER Procedure Check_User_Name
(
#username varchar(25),
#password varchar(100),
#role_id integer,
#idn nvarchar(20) output
)
As
Begin
IF NOT EXISTS(SELECT idn
FROM [user] WHERE username = #username)
BEGIN
INSERT INTO [user] (username,[password], role_id) VALUES
(#username, #password)
select #idn=idn from [user] WHERE username = #username
Print 'UserName inserted successfully'
End
Else
Begin
Print 'UserName already exists'
SELECT #idn = idn FROM [user]
WHERE username = #username
End
END
GO
Execute with:
DECLARE #idnOut nVarChar(20)
exec Check_User_Name #username = 'user2127184', #password = 'asdf', #role_id = 0, #idn = #idnOut OUTPUT
SELECT #idnOut
You can use out params, but I always avoid out params in SQL like I do in C# for the same reasons.
If you have a result set with just the UserId:
select #UserId;
then you expand it to include other things later:
select #UserId, #UserGuid;
without much trouble.
Even if you need to return a status (Login Allowed / Locked Out) and details you can just use multiple result sets:
select #Status;
select #UserId; //etc.
If you have out parameters you have to change the Signature of the procedure - which can be a problem if you are supporting multiple clients calling it.
The only change you need to make to the calling code with result sets is to keep finding the new column from the result set.

Setting output parameters in SELECT statement with an IF EXISTS check

I am trying to make an efficient SQL stored procedure for retrieving user data from my database, but I am running into a syntax issue I can't seem to figure out.
Basically, I want to assign my output variable within my SELECT statement. I also want to see if the user actually exists by IF EXISTS. Unfortunately, I can't seem to do both.
Here is my procedure:
CREATE PROCEDURE [dbo].FindUser(#UserID binary(16), #UserExists bit OUTPUT, #Name
nvarchar(MAX) OUTPUT)
AS
SET NOCOUNT ON
IF EXISTS (SELECT #Name = Name FROM Users WHERE UserID = #UserID)
BEGIN
SET #UserExists = 1
END
RETURN
Currently, it gives me an "SQL46010 :: Incorrect syntax near #Name." error.
If I remove IF EXISTS, the statement compiles fine!
Why does the IF EXISTS check cause a syntax error?
set #UserExists = 0;
select #Name = Name,
#UserExists = 1
from Users
where UserID = #UserID;
SET NOCOUNT ON
IF EXISTS (SELECT 1 FROM Users WHERE UserID = #UserID)
BEGIN
SET #UserExists = 1
/* do other stuff here select user name or whatever */
END
If there is a record for #UserID in users table Selecting 1 will return true for exists clause and control will enter the BEGIN..END block.

Problem in stored procedure result

I have a store procedure like this :
ALTER PROCEDURE [dbo].[CheckUser&Pass]
(
#Username nchar(15),
#Password nchar(15)
)
AS
SET NOCOUNT ON;
SELECT Username, Pass, Code_Person
FROM Login
WHERE (Username = #Username) AND (Pass = #Password)
And Execution :
DECLARE #return_value int
EXEC #return_value = [dbo].[CheckUser&Pass]
#Username = N'admin',
#Password = N'1234'
SELECT 'Return Value' = #return_value
GO
I Want to know how I can set #return_Value to 1 when the username is admin and password is 1234.
but it doesn't work properly, is that possible ?
To set the return value within a stored procedure, you need to use the RETURN statement
e.g.
IF (##ROWCOUNT > 0 AND #Username = 'admin' and password='1234')
RETURN 1
ELSE
RETURN 0
Please note, I've given exactly what you've asked for just to demonstrate use of the RETURN statement. There's a few concerns I have that should be pointed out:
Looks like you're storing the password in plain text, which if is the case, is a bad idea
This hardcoded condition for admin username and password combination is horrible. One better solution is to have an "IsAdmin" flag in the db - if the supplied username/password is valid, then return 1 if the flag indicates the account is an admin.
Use of nchar - all usernames and passwords will be padded out to 15 characters. You should consider nvarchar instead.
You could change your stored proc to return the count, assuming that username and password are unique you should get a 1 or a 0 for the result, but I reckon there must be a better way.
ALTER PROCEDURE [dbo].[CheckUser&Pass]
(
#Username nchar(15),
#Password nchar(15)
)
AS
SET NOCOUNT ON;
SELECT Count(Username)
FROM Login
WHERE (Username = #Username) AND (Pass = #Password)
you should change your stored procedure in order to return the value you want
ALTER PROCEDURE [dbo].[CheckUser&Pass]
(
#Username nchar(15),
#Password nchar(15)
)
AS
SET NOCOUNT ON;
DECLARE #cnt INT
SELECT #cnt = COUNT(*)
FROM Login
WHERE (Username = #Username) AND (Pass = #Password)
RETURN #cnt

Resources