sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'Ole Automation Procedures', 1;
GO
RECONFIGURE;
GO

if object_id (N'gc_pr_get_prime_num_combn', N'P') is not null
begin
    drop procedure gc_pr_get_prime_num_combn;
end
go

if object_id (N'gc_pr_rand_as_string', N'P') is not null
begin
    drop procedure gc_pr_rand_as_string;
end
go

if object_id (N'gc_pr_gb_pair_rm', N'P') is not null
begin
    drop procedure gc_pr_gb_pair_rm;
end
go

CREATE proc gc_pr_get_prime_num_combn
    @start_num numeric(38),
    @end_num numeric(38),
    @primality_testing_method int = 3 /*1 - AKS; 2 - Trial Divison; 3 - Rabin-Miller*/,
    @num_trials int = 0 /*Valid only if @primality_testing_method is set to 3. Otherwise it is ignored.*/,
    @all_combns bit = 0,
    @output_results bit = 1 /*0 - Just to verify the conjecture*/

as

set nocount on;

declare @object_token int;
set @object_token = -1;
declare @source nvarchar(1000), @desc nvarchar(3000), @error_msg nvarchar(4000);
begin try
   if(@start_num > @end_num)
    begin
        declare @temp numeric(38)
        set @temp = @start_num;
        set @start_num = @end_num;
        set @end_num = @temp;
    end;

    if(@start_num is null or @end_num is null or @primality_testing_method is null or
        @num_trials is null or @all_combns is null or @output_results is null or
        @end_num < 4 or @end_num > 99999999999999999999999999999999999998 or
        @primality_testing_method < 1 or @primality_testing_method > 3 or
        (@primality_testing_method = 3 and @num_trials < 0))
    begin
        set @error_msg = N'Invalid parameter(s) specified.';
        raiserror(@error_msg, 15, 10); 
    end;

    if(@output_results = 1)
    begin
        create table #results (
            s numeric(38) not null,
            p1 numeric(38) not null,
            p2 numeric(38) not null
            );
    end;

    declare @counter numeric(38);
    set @counter = @start_num;
    if(cast(right(convert(nvarchar(200), @counter), 1) as int) % 2 <> 0)
    begin
        set @counter = @counter + 1;
    end;

    if(cast(right(convert(nvarchar(200), @end_num), 1) as int) % 2 <> 0)
    begin
        set @end_num = @end_num + 1;
    end;

    if(@counter <= 4)
    begin
        if(@counter < 4)
        begin
            set @counter = 4;
        end;
        if(@output_results = 1)
        begin
            insert into #results (s, p1, p2) values (@counter, 2, 2);
        end;
        set @counter = @counter + 2;
    end;

    declare @hr int;
    exec @hr = sp_OACreate N'gc.Prime.1', @object_token out;
    if(@hr <> 0)
    begin
        exec sp_OAGetErrorInfo @object_token, @source out, @desc out;
        set @error_msg = N'Exception occurred. ' + N'Source: ' + @source + N'; ' +
            N'Description: ' + @desc;
        raiserror(@error_msg, 15, 10);
    end;

    --waitfor delay N'00:00:30'
        
    declare @p1 numeric(38), @p2 numeric(38);
    declare @is_prime int;
    declare @combn_found bit;
    declare @prime_counter numeric(38);
    declare @prime_num_string nvarchar(200);
    while(@counter <= @end_num)
    begin
        set @combn_found = 0;
        set @prime_counter = 3;
        while(@prime_counter < @end_num)
        begin
            set @is_prime = 0;
            set @prime_num_string = convert(nvarchar(100), @prime_counter);
            exec @hr =
                sp_OAMethod @object_token, N'IsPrime', null,
                    @prime_num_string, @primality_testing_method, @num_trials, @is_prime out;
            if(@hr <> 0)
            begin
                exec sp_OAGetErrorInfo @object_token, @source out, @desc out;
                set @error_msg = N'Exception occurred. ' + N'Source: ' + @source + N'; ' +
                    N'Description: ' + @desc;
                raiserror(@error_msg, 15, 10);
            end;
            if(@is_prime = 1)
            begin
                set @p1 = @prime_counter;
                if(@all_combns = 1 and @p1 > @counter / 2)
                begin
                    break;
                end;
                set @p2 = @counter - @p1;
                set @prime_num_string = convert(nvarchar(100), @p2);
                set @is_prime = 0;
                exec @hr =
                    sp_OAMethod @object_token, N'IsPrime', null,
                        @prime_num_string, @primality_testing_method, @num_trials, @is_prime out;
                if(@hr <> 0)
                begin
                    exec sp_OAGetErrorInfo @object_token, @source out, @desc out;
                    set @error_msg = N'Exception occurred. ' + N'Source: ' + @source + N'; ' +
                       N'Description: ' + @desc;
                    raiserror(@error_msg, 15, 10);
                end;
                if(@is_prime = 1)
                begin
                    if(@combn_found = 0)
                    begin
                        set @combn_found = 1;
                    end;
                    if(@output_results = 1)
                    begin
                        insert into #results (s, p1, p2) values (@counter, @p1, @p2);
                    end;
                    if(@all_combns = 0)
                    begin
                        break;
                    end;
                end;
            end;
            set @prime_counter = @prime_counter + 2;
        end;
        if(@combn_found = 0)
        begin
            -- If we get here, should we say that Goldbach Conjecture
            -- is false for the even natural number <@counter>?
            set @error_msg = N'Goldbach Conjecture is false for the even natural number ' +
                convert(varchar(200), @counter);
            raiserror(@error_msg, 15, 10);
        end;
        set @counter = @counter + 2;
    end;
    if(@output_results = 1)
    begin
        select s, p1, p2 from #results;
    end;
    else
    begin
        print N'Verified Goldbach Conjecture successfully  between ' +
            convert(nvarchar(4000), @start_num) + N' and ' +
            convert(nvarchar(4000), @end_num) + N' inclusive.';
    end;
end try
begin catch
    set @error_msg = error_message();
    declare @severity int, @state int;
    select @severity = error_severity(), @state = error_state();
    raiserror(@error_msg, @severity, @state);
end catch;

if(@object_token <> -1)
begin
    exec @hr = sp_OADestroy @object_token;
    if(@hr <> 0)
    begin
        exec sp_OAGetErrorInfo @object_token, @source out, @desc out;
        set @error_msg = N'Exception occurred. ' + N'Source: ' + @source + N'; ' +
            N'Description: ' + @desc;
        raiserror(@error_msg, 15, 10);
    end;
end;

return 0;
go

CREATE proc gc_pr_rand_as_string
    @precision int,
    @rand_big nvarchar(4000) out
as

set nocount on;

begin try
    if(@precision is null or @rand_big is null)
    begin
        raiserror(N'Invalid parameter(s) specified.', 15, 10);
    end;

    if(@precision > 2500)
    begin
        raiserror(N'Max. precision supported is 2500.', 15, 10);
    end;

    set @rand_big = N'';
    declare @rand nvarchar(37);
    declare @n int, @len int;
    set @len = 0;
    while(@len <= @precision)
    begin
        set @rand = convert(nvarchar(37), cast(rand() as numeric(18, 17)));
        set @rand = substring(replace(@rand, N'.', N''), 2, len(@rand) - 1);
        set @n = charindex(N'0', @rand);
        if(@len = 0 and @n = 1)
        begin
            continue;
        end;
        set @rand_big = @rand_big + @rand;
        set @len = len(@rand_big);
    end;
    set @rand_big = substring(@rand_big, 1, @precision);
end try
begin catch
    declare @error_msg nvarchar(4000);
    set @error_msg = error_message();
    declare @severity int, @state int;
    select @severity = error_severity(), @state = error_state();
    raiserror(@error_msg, @severity, @state);
end catch;

return 0;
go

CREATE proc gc_pr_gb_pair_rm
    @num_random_nums numeric(38) = 25 /*Number of random even natural numbers to test for*/,
    @precision int = 39 /*Number of digits to use in order to represent a random even natural number*/,
    @num_trials int = 0 /*Procedure uses Rabin-Miller test*/,
    @output_results bit = 1 /*0 - Just to verify the conjecture*/,
    @num_thrds_per_core int = 130 /*Number of threads to use per core*/

as

set nocount on;

declare @object_token int;
set @object_token = -1;
declare @source nvarchar(1000), @desc nvarchar(3000), @error_msg nvarchar(4000);
begin try
    if(@num_random_nums is null or @precision is null or
        @num_trials is null or @output_results is null or
        @precision < 39 or @precision > 2500 or @num_trials < 0 or 
		@num_thrds_per_core < 2 or @num_thrds_per_core > 2147483647)
    begin
        set @error_msg = N'Invalid parameter(s) specified.';
        raiserror(@error_msg, 15, 10); 
    end;

    if(@output_results = 1)
    begin
        create table #results_rand (
            s nvarchar(2600) not null,
            p1 nvarchar(2600) not null,
            p2 nvarchar(2600) not null
            );
    end;

    declare @hr int;
    exec @hr = sp_OACreate N'gc.Prime.1', @object_token out;
    if(@hr <> 0)
    begin
        exec sp_OAGetErrorInfo @object_token, @source out, @desc out;
        set @error_msg = N'Exception occurred. ' + N'Source: ' + @source + N'; ' +
            N'Description: ' + @desc;
        raiserror(@error_msg, 15, 10);
    end;

    --waitfor delay N'00:00:30'
        
    declare @counter numeric(38);
    set @counter = 1;
    declare @s nvarchar(4000), @p1 nvarchar(2600), @p2 nvarchar(2600);
    declare @combn_found int;
    while(@counter <= @num_random_nums)
    begin
        set @s = N'';
        exec gc_pr_rand_as_string @precision, @s out
        if(cast(right(@s, 1) as int) % 2 <> 0)
        begin
            continue;
        end;

        select @p1 = N'', @p2 = N'';
        set @combn_found = 0;
        exec @hr =
            sp_OAMethod @object_token, N'GetGBPairUsingRM', null,
                @s, @num_trials, @p1 out, @p2 out, @combn_found out, @num_thrds_per_core;
        if(@hr <> 0)
        begin
            exec sp_OAGetErrorInfo @object_token, @source out, @desc out;
            set @error_msg = N'Exception occurred. ' + N'Source: ' + @source + N'; ' +
                N'Description: ' + @desc;
            raiserror(@error_msg, 15, 10);
        end;
        if(@combn_found = 0)
        begin
            -- If we get here, should we say that Goldbach Conjecture
            -- is false for the even natural number <@s>?
            select @s
            set @error_msg = N'Goldbach Conjecture is false for the even natural number ' + @s;
            raiserror(@error_msg, 15, 10);
        end;
        if(@output_results = 1)
        begin
            insert into #results_rand (s, p1, p2) values (@s, @p1, @p2);
        end;
        set @counter = @counter + 1;
    end;
    if(@output_results = 1)
    begin
        select distinct s, p1, p2 from #results_rand order by s;
    end;
    else
    begin
        print N'Verified Goldbach Conjecture successfully for ' + convert(nvarchar(80), @num_random_nums) +
            N' random even natural number(s) of precision ' + convert(nvarchar(4000), @precision) + N'.'
    end;
end try
begin catch
    set @error_msg = error_message();
    declare @severity int, @state int;
    select @severity = error_severity(), @state = error_state();
    raiserror(@error_msg, @severity, @state);
end catch;

if(@object_token <> -1)
begin
    exec @hr = sp_OADestroy @object_token;
    if(@hr <> 0)
    begin
        exec sp_OAGetErrorInfo @object_token, @source out, @desc out;
        set @error_msg = N'Exception occurred. ' + N'Source: ' + @source + N'; ' +
            N'Description: ' + @desc;
        raiserror(@error_msg, 15, 10);
    end;
end;

return 0;
go