none
DefaultView.RowFilter causes a stackOverflow due to too many OR expressions

    Frage

  • Hi all,

     

    An ASP.Net page creashes IIS on a Widnows Server 2003 repeatedly (see my post at IIS.net) and it took me a while to figure out it has to do with the RowFilter of a DataView.  I wrote the following code just for the sake of reproducing this:

     

    Code Snippet

    DataTable dtCenter = new DataTable();

    dtCenter.Columns.Add(new DataColumn("Name", typeof(string)));

    dtCenter.Columns.Add(new DataColumn("A", typeof(int)));

    dtCenter.Columns.Add(new DataColumn("B", typeof(int)));

    dtCenter.Columns.Add(new DataColumn("C", typeof(int)));

    for (int i = 0; i < 100; ++i)

    {

    DataRow dr = dtCenter.NewRow();

    dr["Name"] = i.ToString();

    dr["A"] = i;

    dr["B"] = i;

    dr["C"] = i;

    //System.Threading.Thread.Sleep(1);

    dtCenter.Rows.Add(dr);

    }

    string sFilter = string.Empty;

    for(int i = 0; i < 70; ++i)

    {

    sFilter += "(Name LIKE '" + i.ToString() + "') OR ";

    }

    sFilter += " (1 = 0)";

    dtCenter.DefaultView.RowFilter = sFilter;

     
    If I change the loop number 70 to a smaller number such as 60, there will be no such problem.Any number greater than 70 will cause the problem. 
     
    Howere, there is no problem in running the same code with VS 2008 on an XP machine. 
     
    Any tip will be greatly appreciated.
    Mittwoch, 19. November 2008 18:59

Antworten

  • Hey, this is a very good question and I can tell you why this doesn't work well. When you use an OR in Dataset expression language the there is a recurcsion that is done. After so many the Stack will easily overflow. I took your example and it didn't repro at 70, it reproed at 290 probably due to differing amount of memory. Anyway there is a simple way to resolve this problem however. You can use the IN operator instead. It does not have any of the scaling issues that OR has. Below is an example of the IN operator using your schema from above.

     

    Code Snippet

    dtCenter.DefaultView.RowFilter = "Name IN ( '5','7','10');

     

     

     

    I have also gone and done some quick testing to verify that this does scale. Here is the code that I wrote to verify it would work for 1000 using your code snippet as a basis

     

    Code Snippet

    DataTable dtCenter = new DataTable();

    dtCenter.Columns.Add(new DataColumn("Name", typeof(string)));

    dtCenter.Columns.Add(new DataColumn("A", typeof(int)));

    dtCenter.Columns.Add(new DataColumn("B", typeof(int)));

    dtCenter.Columns.Add(new DataColumn("C", typeof(int)));

    for (int i = 0; i < 1000; ++i)

    {

    DataRow dr = dtCenter.NewRow();

    dr["Name"] = i.ToString();

    dr["A"] = i;

    dr["B"] = i;

    dr["C"] = i;

    //System.Threading.Thread.Sleep(1);

    dtCenter.Rows.Add(dr);

    }

    int startNumberOfOrs = 40;

    int endNumberOfOrs = 1000;

    int j = 0;

    for (j = startNumberOfOrs; j < endNumberOfOrs; j++)

    {

    bool error = false;

    try

    {

    Console.WriteLine(String.Format("Testing {0} number of OR's", j));

    string sFilter = "Name IN (";

    bool initial = true;

    for (int i = 0; i < j; ++i)

    {

    if (initial)

    {

    sFilter += String.Format("'{0}'", i);

    initial = false;

    }

    else

    sFilter += String.Format(",'{0}'", i);

    }

    sFilter += " )";

    dtCenter.DefaultView.RowFilter = sFilter;

    }

    catch (Exception)

    {

    error = true;

    }

    if (error)

    Console.WriteLine("ERROR");

    else

     

    Console.WriteLine("SUCCESS");

     

    }

     

     

     

    So bottom line is that if you are ORing lots of things together use IN instead.

     

    Thanks

    Chris Robinson

    Program Manager - DataSet

    Mittwoch, 19. November 2008 22:56