SubSonic: MaxLength of TableColumn (exceeding) - c#

So, we're using SubSonic as our DAL/ORM for one of our projects. Everything has been running smoothly (the database already existed, so we used SubSonic on top of it), however, on occasion we'll run into an exception that says something like the integer is exceeding the max length. In this example, our MySql field is an int(4) signed. Which, according to MySql documentation will allow a range of the following:
-2147483647 to 2147483647.
Now, my question, how is MaxLength dictated in SubSonic? Is it the number of digits? Because that means it would only allow -9999 to 9999, correct? That seems like a rather huge discrepancy, and I'm hoping that isn't the case, or else we're going to have a ton of other problems.
Thanks,
-Steve

Using Reflector, and drilling down to ActiveRecord's Save function (which calls ValidateColumnSettings):
if ((!flag && (column.MaxLength > 0)) && ((column.DataType != DbType.Boolean) && (currentValue.ToString().Length > column.MaxLength)))
{
Utility.WriteTrace(string.Format("Max Length Exceeded {0} (can't exceed {1}); current value is set to {2}", column.ColumnName, column.MaxLength, currentValue.ToString().Length));
this.errorList.Add(string.Format(this.LengthExceptionMessage, str, column.MaxLength));
}
flag is set to true if the variable is null. So, yes, it's going off of the number of digits (see: ToString().Length). This doesn't seem to make any sense, since MySql doesn't use the length property of the data type to determine the number of digits for integer based values.
This is SubSonic 2.2.

Related

To Fortify, what constitutes validating an integer?

I'm using Fortify static code analyzer with a C#/.NET project. I'm taking an integer parameter, a year, from user input and starting a process with that:
int y = int.Parse(Year.SelectedValue); //Year is a DropDownList
if (y >= 2017 && y <= DateTime.Today.Year)
Process.Start(new ProcessStartInfo(Server.MapPath("~/bin/SomeProgram.exe"), "/x:" + y.ToString()));
Fortify doesn't like that, throws a "Command Injection" issue:
Data enters the application from an untrusted source.
In this case the data enters at get_SelectedValue() in ccc.aspx.cs at
line 25. Even though the data in this case is a number, it is
unvalidated and thus still considered malicious, hence the
vulnerability is still reported but with reduced priority values.
The data is used as or as part of a string representing a command that is executed by the application.
In this case the command is executed by ProcessStartInfo() in
ccc.aspx.cs at line 28.
There are literally two possible values of input that would cause the process to start (as of this writing) - 2017 and 2018. If the if() statement doesn't count as validation for Fortify, what would?
EDIT: on top of everything, unless you explicitly opt of ASP.NET's ViewState integrity check, DropDownList doesn't allow values outside of the assigned range. With this in mind, I don't see why SelectedValue of a DropDownList is treated as an untrusted source in the first place.
Mark it as a false positive and move on.
I don't think Fortify takes the datatype into account. You are taking the value out of a string to and int, doing validation, then using the int value not the original. So as far as the command injection goes not an issue (in this case).
--
What constitutes a validation?
When it comes to Fortify, there is a difference between what constitutes validation and what will make Fortify stop reporting on it.
Unfortunately, there are some cases (as far as I have found from my time 5+ years of using Fortify) that you just cannot make it happy without writing a custom rule for the analyzer to indicate that some method is cleansing the data.

Unique ticket numbers for software support system

I'm developing a ticketing system for tracking bugs and software changes using ASP.NET MVC 4 and Entity Framework 5. I need a way to pick a unique number from a set of possible numbers. My thought is to create a set of possible numbers and mark numbers from this set as they are used and assigned to a support ticket.
I have this code for generating all possible ticket numbers to choose from, but I want to have leading zeroes so that all ticket numbers have the same length:
public static class GenerateNumber
{
private static IEnumerable<int> GenerateNumbers(int count)
{
return Enumerable.Range(0, count);
}
public static IEnumerable<string> GenerateTicketNumbers(int count)
{
return GenerateNumbers(count).Select(n => "TN" + n.ToString());
}
}
I want the output of
IEnumerable<string> ticketNumbers = GenerateNumber.GenerateTicketNumbers(Int32.MaxValue);
to be something like this:
TN0000000001
.
.
.
TN2147483647
Hopefully we won't need anything as large as Int32.MaxValue as that would mean we have way too many bugs haha. I just wanted to be safe than sorry on the limits of the available numbers. Perhaps we could use the methodology of reusing ticket numbers after they have been resolved. However, I don't know how I feel about reuse as it could lead to ambiguity for referring to documentation later on.
Considering the size of this set, is this the most efficient method to go about having unique ticket numbers?
Use an identity column in the database - this will autoincrement for you.
If you need a prefix as well, then store this as a separate varchar column and then for display purposes you can concatenate it (with your requisite leading zeros if that is absolutely really necessary). Trying to store an incrementing number in a varchar field is going to bite you in the ass one day.
As a side note, why the leading zeros? If I am fixing a ticket, I want to annotate my code with the ticket number. Leading zeros are just a pain - why not just have TN-123 and have the number get bigger as required?

string(";P") is bigger or string("-_-") is bigger?

I found very confusing when sorting a text file. Different algorithm/application produces different result, for example, on comparing two string str1=";P" and str2="-_-"
Just for your reference here gave the ASCII for each char in those string:
char(';') = 59; char('P') = 80;
char('-') = 45; char('_') = 95;
So I've tried different methods to determine which string is bigger, here is my result:
In Microsoft Office Excel Sorting command:
";P" < "-_-"
C++ std::string::compare(string &str2), i.e. str1.compare(str2)
";P" > "-_-"
C# string.CompareTo(), i.e. str1.CompareTo(str2)
";P" < "-_-"
C# string.CompareOrdinal(), i.e. CompareOrdinal(w1, w2)
";P" > "-_-"
As shown, the result varied! Actually my intuitive result should equal to Method 2 and 4, since the ASCII(';') = 59 which is larger than ASCII('-') = 45 .
So I have no idea why Excel and C# string.CompareTo() gives a opposite answer. Noted that in C# the second comparison function named string.CompareOrdinal(). Does this imply that the default C# string.CompareTo() function is not "Ordinal" ?
Could anyone explain this inconsistency?
And could anyone explain in CultureInfo = {en-US}, why it tells ;P > -_- ? what's the underlying motivation or principle? And I have ever heard about different double multiplication in different cultureInfo. It's rather a cultural shock..!
?
std::string::compare: "the result of a character comparison depends only on its character code". It's simply ordinal.
String.CompareTo: "performs a word (case-sensitive and culture-sensitive) comparison using the current culture". So,this not ordinal, since typical users don't expect things to be sorted like that.
String::CompareOrdinal: Per the name, "performs a case-sensitive comparison using ordinal sort rules".
EDIT: CompareOptions has a hint: "For example, the hyphen ("-") might have a very small weight assigned to it so that "coop" and "co-op" appear next to each other in a sorted list."
Excel 2003 (and earlier) does a sort ignoring hyphens and apostrophes, so your sort really compares ; to _, which gives the result that you have. Here's a Microsoft Support link about it. Pretty sparse, but enough to get the point across.

MonoTouch on iPad: How to make text search faster?

I need to do text search based on user input in a relative large list (about 37K lines with 50 to 100 chars each line). The search is done after entering each character and the result is shown in a UITableView. This is my current code:
if (input.Any(x => Char.IsUpper(x)))
return _list.Where(x => x.Desc.Contains(input));
else
return _list.Where(x => x.Desc.ToLower().Contains(input));
It performs okay on a MacBook running simulator, but too slow on iPad.
On interesting thing I observed is that it takes longer and longer as input grows. For example, say "examin" as input. It takes about 1 second after entering e, 2 seconds after x, 5 seconds after a, but 28 seconds after m and so on. Why that?
I hope there is a simple way to improve it.
Always take care to avoid memory allocations in time sensitive code.
For example we often produce code often allocates string without realizing it, e.g.
x => x.Desc.ToLower().Contains(input)
That will allocate a string to return from ToLower. From your description this will occurs many time. You can easily avoid this by using:
x = x.Desc.IndexOf ("s", StringComparison.OrdinalIgnoreCase) != -1
note: just select the StringComparison.*IgnoreCase that match your need.
Also LINQ is nice but it hides allocations in many cases - maybe not in your case but measuring is key to get things faster. In that case using another algorithm (like suggested in another answer) could give you much better results (but keep in mind the allocations ;-)
UPDATE:
Mono's Contains(string) will call, after a few checks, the following:
CultureInfo.CurrentCulture.CompareInfo.IndexOf (this, value, 0, length, CompareOptions.Ordinal);
which, with your ToLower requirement that using StringComparison.OrdinalIgnoreCase is the perfect (i.e. identical) match for your existing code (it did not do any culture specific comparison).
Generally I've found that contains operations are not preferable for search, so I'd recommend you take a look at the Mastering Core Data Session (login required ) video on the WWDC 2010 page (around the 10 min mark). Apple knows that 'contains' is terrible w/ SQLite on mobile devices, you can essentially do what Apple does to sort of "hack" FTS on the version of SQLite they ship.
Essentially they do prefix matching by creating a table like:
[[ pk_id || input || normalized_input ]]
Where input and normalized_input are both indexed explicitly. Then they prefix match against the normalized value. So for instance if a user is searching for 'snuggles' and so far they've typed in 'snu' the prefix matching query would look like:
normalized_input >= 'snu' and normalized_input < 'snt'
Not sure if this translates given your use case, but I thought it was worth mentioning. Hope it's helpful!
You need to use a trie. See http://en.wikipedia.org/wiki/Trie

SQL Server CE 3.5 cuts off strings early (C#)

Hey Everyone, I am writing some code that makes use of SQL Server CE 3.5 and I am having a very strange problem. I have a string field in one of the tables that needs to store a full file path.
Over the course of trying to fix this problem I have that field set as nvarchar with a max size of 4000, but it is still cutting longer strings that are much shorter than the limit off
for example:
D:\iTunes\iTunes Media\Music\Abigail Williams\In The Absence Of Light\02 Final Destiny Of The Gods.m
This is clearly smaller than 4000 characters, yet it is missing the p3 at the end of the string.
I am using a table adapter to enter the data into the database with the following query:
INSERT INTO [Track] ([Artist_ID], [Album_ID], [FilePath], [LastUpdate])
VALUES (#Art, #Al, #Fp, #LU)
I know that the strings are fully formed on insert because I am using the following code to check:
if(!temp.Filepath.EndsWith(".mp3"))
MessageBox.Show("File Error");
this.trackTableAdapter1.InsertQuery(ArtID, AlID, temp.Filepath, File.GetLastWriteTime(temp.Filepath));
The message box does not get shown, so the string must end correctly on insert.
the query that extracts the data is:
SELECT
*
FROM Track
WHERE Artist_ID=#Artist_ID AND Album_ID=#Album_ID
The involved code is:
foreach (Database.MusicDBDataSet.TrackRow TR in this.trackTableAdapter1.GetAlbumTracks(AR.Artist_ID, AlR.Album_ID).Rows)
{
//if (!TR.FilePath.EndsWith(".mp3"))
//MessageBox.Show("File Path Error");
this.ArtistList[AR.Name].AlbumList[this.ArtistList[AR.Name].AlbumList.Count - 1].TrackList.Add(new Track(TR.FilePath, AlR.Name, AR.Name));
}
Has anyone ever run into this problem before?
Check the XSD file. Specifically, check the FilePath column of your table and look for the max length.
Maybe take a look at the SQLServerCE Parameter Size limitation.
What is the specific maximum length? Is it around 100 chars? (Guessing based on your provided input example).
The 100 unicode chars also matches with D.K. Mulligan's answer. Looking at SQL ServerCE Paramater Size Property
For variable-length data types, the Size property describes the maximum amount of data to send to the server. For example, the Size property can be used to limit the amount of data sent to the server for a string value to the first 100 bytes.
For Unicode string data, the Size property refers to the number of characters. The count for strings does not include the terminating character.
Try bumping the size to see if this is the magic number that is truncating your strings.

Categories

Resources