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

Alle 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
  • hi Chris,

    My code had a same problem now I understood what caused the problem but if there is necessity to use Like operator.

     Suppose I want rows containing 'b'.

    a
    d
    abc
    dc
    b
    bc

    then what one should.

    Thanks.



    • Bearbeitet vivekuno Freitag, 26. Dezember 2014 09:35
    Freitag, 26. Dezember 2014 09:32
  • So are you saying that you have a bunch of OR statements using LIKE instead of = ... what does your code look like?

    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    Samstag, 27. Dezember 2014 16:49
  • Don't hi jack another thread from history.

    Create your own question. It cost nothing, but describe your problem well if you want an answer.


    Success
    Cor

    Sonntag, 28. Dezember 2014 16:54