SQL Email Verification Function using Regex - sql

I am trying to create a function in SQL Server 2005 to check to see if an email is in a valid format with regular expressions.
Here is what I have so far:
CREATE FUNCTION isValidEmailFormat
(
#Email varchar(100)
)
RETURNS bit
AS
BEGIN
DECLARE #Result bit
SET #Result = (SELECT CASE
WHEN #Email LIKE '%[a-zA-Z0-9_\-]+#([a-zA-Z0-9_\-]+\.)+ (com|org|edu|nz|au])%'
THEN 1
ELSE 0
END AS Valid)
RETURN #Result
END
Am I doing something wrong with my regular expression? Or do I have to do something more to compare a varchar to a regular expression?
-Edit-
Right now, whatever string I put in returns a 0, even if the email format itself is correct.

The short answer is that no, it cannot be done. The syntax for LIKE is not the same as (and way less powerful than) regular expressions. See also SQL Server Regular expressions in T-SQL
But you can make the hop to .Net and do the matching there. You can instantiate a VBScript.RegExp inside T-SQL using sp_OACreate and use that.
CREATE FUNCTION dbo.isValidEmailFormat
(
#Email varchar(100)
)
RETURNS bit
AS
BEGIN
DECLARE #pattern varchar(4000)
SET #pattern = '[a-zA-Z0-9_\-]+#([a-zA-Z0-9_\-]+\.)+(com|org|edu|nz|au)'
DECLARE #Result bit
DECLARE #objRegexExp INT
EXEC sp_OACreate 'VBScript.RegExp', #objRegexExp OUT
EXEC sp_OASetProperty #objRegexExp, 'Pattern', #pattern
EXEC sp_OASetProperty #objRegexExp, 'IgnoreCase', 1
EXEC sp_OASetProperty #objRegexExp, 'MultiLine', 0
EXEC sp_OASetProperty #objRegexExp, 'Global', false
EXEC sp_OASetProperty #objRegexExp, 'CultureInvariant', true
EXEC sp_OAMethod #objRegexExp, 'Test', #Result OUT, #Email
EXEC sp_OADestroy #objRegexExp
RETURN #Result
END
Do take a peek at Regex email verification error - using JavaScript to see if you want to be a bit less restrictive on what characters are allowed.

I used #flup 's answer and updated the RegExp pattern as follows:
dots are allowed in the portion before #, but not as first or last character there
the expression is anchored to start and end of string with ^ and $
specific TLDs and country codes were added for the data I was using
The TLDs are whitelisted explicitly to exclude many typos where .com was entered as .co or .cm -- valid country codes for Colombia or Cameroon but not for my data.
The updated line:
SET #pattern = '^([a-zA-Z0-9_\-]+\.)*[a-zA-Z0-9_\-]+#([a-zA-Z0-9_\-]+\.)+(com|org|edu|net|ca|au|coop|de|ee|es|fm|fr|gr|ie|in|it|jp|me|nl|nu|ru|uk|us|za)$'
I hope this adds value to an already-excellent answer.

Related

Chilkat SQL not working/returning anything

I am trying 30 days free trial of Chilkat and I am not getting any results in SQL, nor error information (unless it is a string text value, hardcoded). I have installed the module on the server and it confirms correctly
For example this piece of code with obviously incorrect address just runs through without any feedback (the code is from their tutorial - apart from the address - so should be technically correct)
DECLARE #hr int
DECLARE #iTmp0 int
DECLARE #sTmp0 nvarchar(max)
DECLARE #rest int
EXEC #hr = sp_OACreate 'Chilkat_9_5_0.Rest', #rest OUT
IF #hr <> 0
BEGIN
PRINT 'Failed to create ActiveX component'
RETURN
END
-- Connect to the REST server.
DECLARE #bTls int
SELECT #bTls = 1
DECLARE #port int
SELECT #port = 443
DECLARE #bAutoReconnect int
SELECT #bAutoReconnect = 1
DECLARE #success int
EXEC sp_OAMethod #rest, 'Connect', #success OUT, 'www.incorrect_address.co', #port, #bTls, #bAutoReconnect
IF #success <> 1
BEGIN
EXEC sp_OAGetProperty #rest, 'LastErrorText', #sTmp0 OUT
PRINT #sTmp0
EXEC #hr = sp_OADestroy #rest
RETURN
END
the Global Unlock method returns message that it is working
'Unlocked in trial mode.'
do you have any idea why it does not work? Any messages hardcoded (like 'unlocked in trial mode') are working but anything that should return values of objects - does not. I have of course enabled Configuration option 'Ole Automation Procedures' in SQL
Slav
The contents of the LastErrorText property is likely too large for limits imposed by sp_OAGetProperty. Try using a temp table like this:
DECLARE #tmp1 TABLE (lastErrText ntext)
INSERT INTO #tmp1 EXEC sp_OAGetProperty #rest, 'LastErrorText'
SELECT * from #tmp1

Calling Scalar Function on a linked Server

I am trying to call a scalar function on a linked server but I am having a little trouble setting it up. I am hoping to set it up as a function on my server.
Below is the best I came up with.
I am trying to wrap an openquery statement within the function on my server. However, the query works by itself by I am not able to return the results without causing an error.
USE POWERVIEW
GO
ALTER FUNCTION DBO.FN_VAR_DUMPNAME (#DUMPLOC NVARCHAR(40))
RETURNS NVARCHAR(40)
AS
BEGIN
--DECLARE #DUMPLOC NVARCHAR(40)='D11'
DECLARE #sql nvarchar(800)
DECLARE #param Nvarchar(20)= #DUMPLOC
DECLARE #retval NVARCHAR(40)
DECLARE #ParmDefinition nvarchar(500)=N'#retvalOUT NVARCHAR(40) OUTPUT'
DECLARE #innersql nvarchar(400)
SET #innersql = 'SELECT POWERVIEW.DBO.FN_VAR_DUMPNAME('''+''''+#param +''''+''')'
SET #sql = 'select * from openquery(MINESQLSERVER,'''+ #innersql +''' )'
***RETURN EXEC sp_executesql #sql --This line does not work***
END
This is too long for a comment.
SQL Server does not allow functions to call dynamic SQL. Hence you cannot do what you want.
You have other problems as well:
return exec is not something I've every seen before.
exec returns an integer.
The function returns a string.
You will need to solve your problem using some other method -- a stored procedure comes to mind.

Sp_oamethod to upload file with size greater than 8000

This is part of my procedure to return #v_buffer variable.
Problem is that, the size of file i want to upload is greater than 8000 bytes. That's why i need to use varbinary(max) type.
But sp_oamethod read returns me an error.
Is someone know hot to use sp_oamethod to solve my problem?
declare #returnCode int
declare #v_file int
declare #v_buffer varbinary(max)
declare #v_fullpath nvarchar(400) --pdf file phusical location
exec #returncode = sp_oacreate 'adodb.stream', #v_file out
exec #returncode = sp_oamethod #v_file, 'open'
exec #returncode = sp_oasetproperty #v_file, 'type', 1
exec #returncode = sp_oasetproperty #v_file, 'loadfromfile', #v_fullpath
exec #returnCode = sp_oamethod #v_file, 'read', #v_buffer out, -1
if #returncode <> 0
begin
exec sp_oageterrorinfo #v_file
end
exec #returnCode = sp_OAMethod #v_file, 'Close'
exec #returnCode = sp_OADestroy #v_file
Error message returned by sp_oageterrorinfo:
0x8004271A, ODSOLE Extended Procedure, Error in srv_convert.
Please do not use the OLE Automation stored procedures (i.e. sp_OA* ) as they have been deprecated since SQL Server 2005 was released. What you are trying to do is rather simple with SQLCLR (i.e. .NET-based objects that exist within SQL Server). You can create a scalar function to accept a filepath and return its bytes using the File.ReadAllBytes method. Return that byte[] via the SqlBytes type.
You will need to set your Assembly to PERMISSION_SET = EXTERNAL_ACCESS. In order to accomplish that, please do not set the database to TRUSTWORTHY ON as that is an unnecessary security risk. Instead, sign the Assembly (using a password), then create an Asymmetric Key in the master Database from the DLL, then create a Login from that Key, and finally grant the Login the EXTERNAL ACCESS ASSEMBLY permission.
For a lot more information on working with SQLCLR, including many examples, please see the series of articles I am writing on this topic on SQL Server Central: Stairway to SQLCLR (that site does require free registration in order to read their content).
Or, if you don't want to deal with any coding, I created a library of over 270 functions and stored procedures called SQL#. There are several file system related functions, though none of them are available in the Free version. Still, the one that would help here is called: File_GetFileBinary.
If you try to pass a string that is greater than 4000 characters but less than or equal to 8000 characters in length to the sp_OASetProperty or to the sp_OAMethod OLE Automation extended stored procedure, the input string is silently truncated to 4000 characters before it is passed to the object and no error is returned.
If you try to set a property to a string that is greater than 8000 characters through the sp_OASetProperty OLE Automation extended stored procedure, or if you try to pass an input parameter to the sp_OAMethod OLE Automation extended stored procedure that is longer than 8000 characters, you receive the following error message:
hr Source Description
---------- ---------------------------- --------------------------
0x8004271A ODSOLE Extended Procedure Error in srv_convert.
https://support.microsoft.com/en-us/kb/325492
If someone had same problem, i have done it like this:
In my procedure i create temp #IMG table:
create table #IMG (FileID2 nvarchar(50), img image)
If the file size is greater than 8k, i split it to parts in size 8000 and update #IMG:
exec #returnCode = sp_oamethod #v_file, 'read', #v_buffer out, 8000
update #IMG set img = #v_buffer
SELECT #ptrval = TEXTPTR(Img) FROM #IMG WHERE FileID2 = #v_FileID2
--file split section
select #v_Blocks = #v_FileSize/8000+1
if #v_Blocks = 1
begin
WRITETEXT #IMG.Img #ptrval #v_buffer
end
else
begin
WRITETEXT #IMG.Img #ptrval #v_buffer
set #j=#v_blocks-1
while #j>0
begin
exec #returnCode = sp_oamethod #v_file, 'read', #v_buffer out , 8000
set #i=(select DATALENGTH(Img) from #IMG WHERE FileID2= #v_FileID2)
UPDATETEXT #IMG.Img #ptrval #i 0 #v_buffer
set #j=#j-1
end
end
You could use the same workaround as described at 0x8004271A ODSOLE Extended Procedure Error in srv_convert.
In your case, the line
exec #returnCode = sp_oamethod #v_file, 'read', #v_buffer out, -1
should be replaced by
Create table #tmp(dt varbinary(max))
insert into #tmp
exec #hr = sp_oamethod #v_file, 'read', #mode = -1
Select dt from #tmp -- single column/single row.
Drop Table #tmp -- clean up
Caution: this code wasn't tested. However the following code works fine for 32KB xml output:
Create table #tmp(dt xml)
insert into #tmp
exec #hr = sp_OAGetProperty #obj, 'responseXML.XML'
/*
Here is the trick: inserting from the returned result set, i.e.
`insert into <table>(<columns>) select <columns>`
*/
Select dt from #tmp -- single column/single row.
Drop Table #tmp -- clean up
responseXML.XML returns the whole xml document after calling MSXML2.ServerXMLHttp.send. The trick works according to section Result Sets of sp_OAMethod.
When the table variable type is available, the code can be even shorter:
DECLARE #xml(val xml);
insert into #xml
exec #hr = sp_OAGetProperty #obj, 'responseXML.XML'
Select * from #xml; -- just to see the output
I.e. there is no need to clean up.
I received the same issue. Apparently, you cannot use sp_OAMethod with a VARBINARY(MAX) variable.
Try changing: declare #v_buffer varbinary(max)
to declare #v_buffer varbinary(8000).
Good luck!

Getting an error when executing a dynamic sql within a function (SQL Server)?

I create a function to execute dynamic SQL and return a value. I am getting "Only functions and some extended stored procedures can be executed from within a function." as an error.
The function:
Create Function fn_GetPrePopValue(#paramterValue nvarchar(100))
returns int as
begin
declare #value nvarchar(500);
Set #SQLString = 'Select Grant_Nr From Grant_Master where grant_id=' + #paramterValue
exec sp_executesql
#query = #SQLString,
#value = #value output
return #value
end
The execution:
Select dbo.fn_GetPrePopValue('10002618') from Questions Where QuestionID=114
and:
Select fn_GetPrePopValue('10002618') from Questions Where QuestionID=114
Is the function being called properly or is the function incorrect?
You cannot use dynamic SQL from a function, neither can you call
stored procedures.
Create proc GetPrePopValue(#paramterValue nvarchar(100))
as
begin
declare #value nvarchar(500),
#SQLString nvarchar(4000)
Set #SQLString = 'Select #value = Grant_Nr From Grant_Master where grant_id = #paramterValue'
exec sp_executesql #SQLString, N'#paramterValue nvarchar(100)',
#paramterValue,
#value = #value output
return #value
end
Functions are limited in what they can use, so that you can use them in a query without accidentally make something that would give horrible performance. Using dynamic queries is one of those things, as that would cause a query planning for each execution, and also would keep the function from being able to be part of a query plan.
You don't need the dynamic query at all in this case, just return the value:
Create Function fn_GetPrePopValue(#paramterValue nvarchar(100))
returns int as
begin
return (select Grant_Nr From Grant_Master where grant_id = #paramterValue)
end
I don't think you can use dynamic SQL from a function, nor do I think you need to in your case. Looks like you want something closer to this:
Create Function dbo.fn_GetPrePopValue(#paramterValue nvarchar(100))
returns int as
begin
declare #value int
declare #SQLString varchar(MAX)
Select #value=Grant_Nr From Grant_Master where grant_id=#paramterValue
return #value
end
SQL Fiddle Demo
Also, please check your data types to make sure you're fields are correct. Seems odd to pass in a varchar for the id and return an int for the other field. Either way, this should help you get going in the right direction.

Sql string manipulation within stored procedure

I have a field which contains article titles. I need to create friendly or pretty url's out of the article titles.
I need help manipulating the string with SQL. This has to be done within a stored procedure or function.
The requirements:
The only characters allowed are lowercase letters and numbers (a-z and 0-9)
All spaces need to be replaced with dashes.
Thanks!
(updated) I am using Sql Server 2008
I found the answer over here. Thank you all!
How to strip all non-alphabetic characters from string in SQL Server?
CREATE Function [dbo].[create_pretty_url](#Temp VarChar(1000))
Returns VarChar(1000)
AS
Begin
While PatIndex('%[^A-za-z0-9]%', #Temp) > 0
Set #Temp = LOWER(Stuff(#Temp, PatIndex('%[^A-za-z0-9]%', #Temp), 1, ''))
Return #Temp
End
To check for lowercase letters, you can use a binary collation like Latin1_General_BIN.
This SQL Server procedure checks if a string contains only spaces, digits or lowercase letters. If so, it returns 1 and replaces spaces with underscores. Else it returns -1.
if OBJECT_ID('TestProc') is null
exec ('create procedure TestProc as select 1')
go
alter procedure TestProc(
#str varchar(256),
#result varchar(256) output)
as
begin
set #result = null
set #str = REPLACE(#str,' ','_')
if #str like '%[^0-9a-z_]%' collate Latin1_General_BIN
return -1
set #result = #str
return 1
end
go
Test data:
declare #rc int
declare #result varchar(256)
exec #rc = TestProc '11 aa', #result out
select #rc, #result
exec #rc = TestProc 'NO CAPS', #result out
select #rc, #result
exec #rc = TestProc '%#$#$', #result out
select #rc, #result
-->
1 11_aa
-1 NULL
-1 NULL
You did not state which database, or version for that matter, but lets go with:
I you were to be using Sql Server 2005, 2008, have a look at using CLR functions
Adding Regular Expressions (Regex) to SQL Server 2005