using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

public partial class UserDefinedFunctions
{

  struct primeIndex
  {
    public int n;
    public int p;
    public primeIndex(int n, int p)
    {
      this.n = n; this.p = p;
    }
  }

  static bool isPrime(int p)
  {
    if (p < 2) return false;
    if (p == 2) return true;
    if (p % 2 == 0) return false;
    for (int d = 3; d * d < p; d += 2)
    {
      if (p % d == 0) return false;
    }
    return true;
  }

  static int nextPrime(int p)
  {
    int result = p + 1;
    while (!isPrime(result)) result++;
    return result;
  }


  [SqlFunction(FillRowMethodName = "clrGetPrimeNumbersFillRow", TableDefinition = "n int,p int,est float")]
  public static System.Collections.IEnumerable clrGetPrimeNumbers(int n)
  {
    int p = 1;
    for (int i = 1; i <= n; i++)
    {
      p = nextPrime(p);
      yield return new primeIndex(i, p);
    }
  }

  private static void clrGetPrimeNumbersFillRow(object source, out int n, out int p, out SqlDouble est)
  {
    primeIndex pi = (primeIndex)source;
    n = pi.n;
    p = pi.p;
    if (n < 5)
      est = SqlDouble.Null;
    else
    {
      double log = Math.Log(n);
      double loglog = Math.Log(log);
      est = n * (log + loglog - 1 + loglog / log - 2 / log);
    }
  }

};

