Проверьте ограничение для проверки поля IP-адреса - PullRequest
1 голос
/ 29 июля 2010

Я работаю над проектом, включающим C # и базу данных SQL Server 2008. В одной из таблиц у меня есть поле (nvarchar(15)), которое будет содержать IP-адрес.

Я хотел бы добавить проверочное ограничение, которое проверит, что входное значение фактически является IP-адресом.

Я хотел использовать для этого регулярное выражение, но, похоже, эта функция не поддерживается по умолчанию. Я видел вещи о написании пользовательских DLL с UDF внутри ( MSDN учебник ), но я не совсем понимаю, как это работает (то есть, где я должен разместить DLL?)

Есть ли "простой" способ добавить такое ограничение? Любое решение приветствуется.

Заранее спасибо!

Ответы [ 6 ]

2 голосов
/ 29 июля 2010

Самым простым способом, который я могу придумать, является создание функции, подобной fnCheckIP, и использование этой функции в ограничении.

Нет необходимости использовать UDF.

create function fnCheckIP(@ip varchar(15)) returns bit
AS
begin
    if (@ip is null)
        return null

    declare @num1 int
    declare @num varchar(15)    
    declare @pos int
    while (@ip is not null)
    begin
        set @pos = IsNull(NullIf(charindex('.', @ip), 0), Len(@ip) + 1)
        set @num = substring(@ip, 1, @pos - 1)

        if (isnumeric(@num) = 0) or (not cast(@num as int) between 0 and 255)
            return cast(0 as bit)

        if (len(@ip) - @pos <= 0)
            set @ip = null
        else        
            set @ip = NullIf(substring(@ip, @pos + 1, len(@ip) - @pos), '')
    end

    return cast (1 as bit)
end
go

select dbo.fnCheckIP('127.0.0.1')
select dbo.fnCheckIP('127.0.0.300')
2 голосов
/ 29 июля 2010

Есть несколько способов сделать это - наиболее производительным, вероятно, будет функция CLR в базе данных.

Это связано с тем, что в SQL довольно слабые инструменты для работы с текстом и нет собственного RegEx в SQL Server.

Как уже говорили другие, это лучше обрабатывается приложением перед вставкой в ​​БД.

1 голос
/ 29 июля 2010

Он не должен обрабатываться в базе данных, он должен обрабатываться в первую очередь в приложении.

Нет ничего плохого в том, чтобы добавить проверку в базу данных, но оставить ее на усмотрение БД для фильтрации ввода очень схематично.

0 голосов
/ 14 декабря 2018

Наконец, примерно через 10 лет после Oracle, sqlserver получил собственную компиляцию (с ограничениями)

    ALTER function fn_ValidateIPv4
(
@ip varchar(255)
)
RETURNS int
--WITH EXECUTE AS OWNER, SCHEMABINDING, NATIVE_COMPILATION  
AS
BEGIN 
--ATOMIC WITH (TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'us_english')
/* only sql2016 native Compilation **/
DECLARE @len_ip as int;
SET @len_ip =  len(@ip);
DECLARE @firstBlock varchar(4) = '';
DECLARE @secondBlock varchar(4) = '';
DECLARE @thirdBlock varchar(4) = '';
DECLARE @fourthBlock varchar(4) = '';
DECLARE @countDot as smallint = 0;
DECLARE @l_i as smallint = 0;

DECLARE @l_curChar varchar(1) = 'X';

DECLARE @Result int = 0
    IF (@len_ip <= 15)
    BEGIN
        WHILE (@l_i < @len_ip) 
        BEGIN
            set @l_i += 1;
            set @l_curChar = substring(@ip,@l_i,1);
            if @l_curChar = '.'
                SET @countDot += 1
            ELSE
            BEGIN
                IF @l_curChar IN ( '0','1','2','3','4','5','6','7','8','9' )
                BEGIN
                    IF @countDot = 0 
                        SET @firstBlock = @firstBlock + @l_curChar;
                    IF @countDot = 1
                        SET @secondBlock = @secondBlock + @l_curChar;
                    IF @countDot = 2
                        SET @thirdBlock = @thirdBlock + @l_curChar;
                    IF @countDot = 3
                        SET @fourthBlock = @fourthBlock + @l_curChar;
                    IF  @countDot > 3
                        set @firstBlock = 'AAA'; -- force error 
                END
                ELSE set @firstBlock = 'AAA'; -- force error                

            END;
        END;            

        IF ( @countDot = 3 and
            cast(@fourthBlock as int) between 1 and 255 and
            cast(@thirdBlock as int) between 0 and 255 and
            cast(@secondBlock as int) between 0 and 255 and
            cast(@firstBlock as int) between 0 and 255 
            )           
            set @Result = 1;
    END;

    /*
    select dbo.fn_ValidateIPv4( '127.0.0.258' );        
    */
RETURN @Result
END;

Мне пришлось удалить не поддерживаемые встроенные функции - числовые и т. Д. *

0 голосов
/ 05 июня 2015

Это решение похоже на Пауло, но использование любого из этих подходов потребует избавления от символа запятой, потому что isnumeric допускает запятые, которые приведут к ошибке приведения к int.

CREATE FUNCTION fn_ValidateIP
(
    @ip varchar(255)
)
RETURNS int
AS
BEGIN
    DECLARE @Result int = 0
        IF
            @ip not like '%,%' and
            len(@ip) <= 15 and
            isnumeric(PARSENAME(@ip,4)) = 1 and
            isnumeric(PARSENAME(@ip,3)) = 1 and
            isnumeric(PARSENAME(@ip,2)) = 1 and
            isnumeric(PARSENAME(@ip,1)) = 1 and
            cast(PARSENAME(@ip,4) as int) between 1 and 255 and
            cast(PARSENAME(@ip,3) as int) between 0 and 255 and
            cast(PARSENAME(@ip,2) as int) between 0 and 255 and
            cast(PARSENAME(@ip,1) as int) between 0 and 255
            set @Result = 1
        ELSE
            set @Result = 0
    RETURN @Result
END

select dbo.fn_ValidateIP('127.0.0.1')
0 голосов
/ 29 июля 2010

Это может быть не совсем практично, но одним из способов будет сохранение преобразованной строки ### - ### - ### - ### в двоичном (4) типе данных.Позвольте интерфейсу возиться с дефисами и иметь дело с преобразованием четырех чисел в двоичное и обратно (и это, вероятно, даже можно сделать с помощью вычисляемого столбца). Да, немного экстремально, но с двоичным (4) вы всегда будете сможет превратить его в IP-адрес.

...