string getting truncated when saved into database - c#

I have a database datatype defined as Text:
text columns are variable-length columns that can hold up to 2,147,483,647 (231 - 1) bytes of printable characters.
What does that means exactly? How many string characters will I be able to save into the Text column?
Basically, I try to save a c# string object into that column where
myString.ToString().Length == 39418
but when I pull it back from the database
myString.ToString().Length == 32768
-----------EDITED---------------
guys this is very confusing.
The Text column is defined as 2,147,483,647 bytes which is 2GB
The string i'm trying to save is ?System.Text.ASCIIEncoding.Unicode.GetByteCount(param.Value.ToString()) 78836 bytes i.e. 0.0000734217 gigabytes
So that confirms that what I am trying to save IS NOT too big for the Text datatype column? i.e. I'm saving 0.0000734217 GB into a column capable of handling 2GB
I'm using Sybase. Saving like this:
OdbcParameter param = new OdbcParameter();
param.DbType = DbType.String;
param.Size = int.MaxValue;
param.Value = myBigString
parameters.Add(param);
OdbcHelper.ExecuteNonQuery(connectionString, sql, parameters);
And retreiving like this
DataSet ds = new DataSet();
OdbcConnection conn = new OdbcConnection(connectionString);
OdbcDataAdapter adp = new OdbcDataAdapter(command, conn);
conn.Open();
adp.Fill(ds);....
Also when I try this I can still see the data is truncated so it doesn't look like a problem when retreiving the data
var obj = OdbcHelper.ExecuteScalar(connectionString, "select myBigString FROM ...");

As I mentioned in my comment, do not use TEXT as it is deprecated. Use VARCHAR or NVARCHAR for Unicode data. This will allow you to store up to 2GB of data.
http://msdn.microsoft.com/en-us/library/ms186939.aspx
Variable-length Unicode string data. n defines the string length and
can be a value from 1 through 4,000. max indicates that the maximum
storage size is 2^31-1 bytes (2 GB). The storage size, in bytes, is
two times the actual length of data entered + 2 bytes. The ISO
synonyms for nvarchar are national char varying and national character
varying.
2,147,483,647 bytes is approximately 1.862GB and the maximum capacity for that column. I assume the data you're attempting to store is too large for the column, hence the data being truncated.

use the nvarchar(MAX) type for that column

In my connection string I needed to add textsize=2147483647

Related

SqlCommand with parameters accepting different data formats

Imagine this code:
string value = "1.23";
string query = "UPDATE MYTABLE SET COL1=#p1";
SqlCommand cmd = new SqlCommand(query, connection);
cmd.Parameters.AddWithValue("#p1", value);
cmd.ExecuteNonQuery();
On my database it will work with value="1.23" if COL1 is decimal type column. But it will fail if value is "1,23" (comma instead of a dot as a decimal point). The error is
Error converting data type nvarchar to numeric
I'd like it to work in both cases with "value" being a string variable.
Unfortunately I cannot just replace comma for the dot as this code is going to be more universal, dealing both with numeric and varchar columns
Is there any way that an query accepts a parameter with number written as a string both with dot and a comma and correctly puts it in into table?
Thanks for any help
If the value isn't semantically a string, you shouldn't send it as a string. The type of the parameter value is important, and influences how it is transmitted and can lead to culture issues (comma vs dot, etc).
If the value is semantically a decimal, then use something like:
string value = "1.23";
var typedValue = decimal.Parse(value); // possible specifying a culture-info
//...
cmd.Parameters.AddWithValue("#p1", typedValue);
Then it should work reliably.
Unrelated, but you can make ADO.NET a lot easier with tools like "Dapper":
connection.Execute("UPDATE MYTABLE SET COL1=#typedValue", new { typedValue });

ColumnSize of numeric is not same original (c#)(dBase)

I want to get a database schema (dBase), so I use "oledb" to get data from a dbase file for using getchemaTable to get the schema of data, but the "ColumnSize" of the numeric data type excludes "19". As the original data, such as "object_id" Type: nummeric column size: 12, but it returns the output to "19".
I want to show the results to the exact same. but..
I don't know what to do next.
public static DataSet getStructureDBF(string dir, string input)
{
OleDbConnection objConn = new OleDbConnection(#"Provider=VFPOLEDB.1;Data Source=" + dir + ";Persist Security Info=False;");
objConn.Open();
OleDbCommand objCmd = new OleDbCommand("Select * from " + input, objConn);
OleDbDataReader objDataReader = objCmd.ExecuteReader();
DataTable schemaTable = objDataReader.GetSchemaTable();
DataSet dsnew = new DataSet();
dsnew.Tables.Add(schemaTable);
return dsnew;
}
For all data types, dBASE field definitions store field length and precision. The latter is only relevant for numeric types, and the former is the maximum number width in digits, because that is how dBASE stores numbers: actual strings of digits.
See dbf file format specification
Edit
Note that data types Numeric and Float are stored as strings of digits. Number types in more recent versions of dBASE are stored as binary values.
Also see DBF reader implementation notes

SHA2_512 encryption c# and SQL methods gives different results

I have intercepted the word "admin" using this c# code
Byte[] inputBytes = Encoding.UTF8.GetBytes(stringpassword);
SHA512 shaM = new SHA512Managed();
Byte[] hashedBytes = shaM.ComputeHash(inputBytes);
string hashedpassword = BitConverter.ToString(hashedBytes);
and got the result of this "DA-EF-49-53-B9-78-33-65-CA-D6-61-52-23-72-05-06-CC". and I encrypyt the same word "admin" using SQL stored procedure
SET #password = HASHBYTES('SHA2_512',#password);
and get this as output "Ç­DË­v*] ¤RùèTýÁàç¥*8_#óê±Ø“ÔrcMúÇÓN¼5Ñj·ûŠÈ"
Why is there difference between these to methods?
From the documentation of the HASHBYTES function:
Return Value
varbinary (maximum 8000 bytes)
The issue here is that you're trying to interpret arbitrary binary data (the output of HASHBYTES) as a textual value, which just won't work. In this case SQL server is trying to interpret the raw byte values as characters in whatever collation your database is using.
The standard way of representing binary data in a textual form is to convert it to a base64 representation. To do this in C# replace the last line with:
string hashedpassword = Convert.ToBase64String(hashedBytes);
Then in your SQL you can do the following to convert your hashed value to base64 (based on this SO answer):
DECLARE #hashedValue VARBINARY(8000) = HASHBYTES('SHA2_512', 'admin')
SELECT
CAST(N'' AS XML).value(
'xs:base64Binary(xs:hexBinary(sql:column("bin")))'
, 'VARCHAR(MAX)'
) Base64Encoding
FROM (
SELECT #hashedValue AS bin
) AS bin_sql_server_temp;
If you run this you will observe that the base64 encoded values are identical.

How to store UTF-8 bytes from a C# String in a SQL Server 2000 TEXT column

I have an existing SQL Server 2000 database that stores UTF-8 representations of text in a TEXT column. I don't have the option of modifying the type of the column, and must be able to store non-ASCII Unicode data from a C# program into that column.
Here's the code:
sqlcmd.CommandText =
"INSERT INTO Notes " +
"(UserID, LocationID, Note) " +
"VALUES (" +
Note.UserId.ToString() + ", " +
Note.LocationID.ToString() + ", " +
"#note); " +
"SELECT CAST(SCOPE_IDENTITY() AS BIGINT) ";
SqlParameter noteparam = new SqlParameter( "#note", System.Data.SqlDbType.Text, int.MaxValue );
At this point I've tried a few different ways to get my UTF-8 data into the parameter. For example:
// METHOD ONE
byte[] bytes = (byte[]) Encoding.UTF8.GetBytes( Note.Note );
char[] characters = bytes.Select( b => (char) b ).ToArray();
noteparam.Value = new String( characters );
I've also tried simply
// METHOD TWO
noteparam.Value = Note.Note;
And
// METHOD THREE
byte[] bytes = (byte[]) Encoding.UTF8.GetBytes( Note.Note );
noteparam.Value = bytes;
Continuing, here's the rest of the code:
sqlcmd.Parameters.Add( noteparam );
sqlcmd.Prepare();
try
{
Note.RecordId = (Int64) sqlcmd.ExecuteScalar();
}
catch
{
return false;
}
Method one (get UTF8 bytes into a string) does something strange -- I think it is UTF-8 encoding the string a second time.
Method two stores garbage.
Method three throws an exception in ExecuteScalar() claiming it can't convert the parameter to a String.
Things I already know, so no need telling me:
SQL Server 2000 is past/approaching end-of-life
TEXT columns are not meant for Unicode text
Seriously, SQL Server 2000 is old. You need to upgrade.
Any suggestions?
If your database collation is SQL_Latin1_General_CP1 (the default for the U.S. edition of SQL Server 2000), then you can use the following trick to store Unicode text as UTF-8 in a char, varchar, or text column:
byte[] bytes = Encoding.UTF8.GetBytes(Note.Note);
noteparam.Value = Encoding.GetEncoding(1252).GetString(bytes);
Later, when you want to read back the text, reverse the process:
SqlDataReader reader;
// ...
byte[] bytes = Encoding.GetEncoding(1252).GetBytes((string)reader["Note"]);
string note = Encoding.UTF8.GetString(bytes);
If your database collation is not SQL_Latin1_General_CP1, then you will need to replace 1252 with the correct code page.
Note: If you look at the stored text in Enterprise Manager or Query Analyzer, you'll see strange characters in place of non-ASCII text, just as if you opened a UTF-8 document in a text editor that didn't support Unicode.
How it works: When storing Unicode text in a non-Unicode column, SQL Server automatically converts the text from Unicode to the code page specified by the database collation. Any Unicode characters that don't exist in the target code page will be irreversibly mangled, which is why your first two methods didn't work.
But you were on the right track with method one. The missing step is to "protect" the raw UTF-8 bytes by converting them to Unicode using the Windows-1252 code page. Now, when SQL Server performs the automatic conversion from Unicode to Windows-1252, it gets back the original UTF-8 bytes untouched.

How to retrieve 0 as the first number in C#

scenario:
I have a database having a record 001234 and I am calling it with cmd.executescaler(); into a int variable. The problem is when I retrieve the saved data (001234) data from that variable it gives only 1234. 00 in 001234 are important, this was the problem first coming in db where sql omits the first zero's then I changed the datatype to nvarchar which works, how I can retrieve the data on the form exactly 001234.
Note: I cannot take the data into string as I have to also apply some calculations on them.
using Sql Server visual studio 2010 c#
Hope it is clear not vague. If you need more information tell me.
Thanks in advance.
Numeric datatype don't have and can't have leading zeros. So the only way to have leading zeros is to store the value as a string.
However, this is just a matter of formatting the output that is shown to the user. You can read the database value into an int variable, do your calculations and when showing the value, you can do:
string displayValue = String.Format("{0:D6}", intValue);
and show the value of displayValue.
If you want to work on the Code side:
string displayValue = String.Format("{0:D6}", intValue);
If you want to work on the DB side you need a Pad function that allows to write this kind of query:
SELECT dbo.PadString ('8', '0', 5)
->Result: 00008
SELECT dbo.PadString ('abc', '*', 12)
->Result: *********abc
SELECT dbo.PadString ('abc', '0', 7)
->Result: 0000abc
Create a function in T-SQL
CREATE FUNCTION [dbo].[PadString]
(#Seq varchar(16),
#PadWith char(1),
#PadLength int
)
RETURNS varchar(16) AS
BEGIN
declare #curSeq varchar(16)
SELECT #curSeq = ISNULL(REPLICATE(#PadWith, #PadLength - len(ISNULL(#Seq ,0))), '') + #Seq
RETURN #curSeq
END
If those leading zeros have some meaning and can't be left out, conversion can be done:
int number = 0;
string strNumber = (string)cmd.ExecuteScalar();
if(int.TryParse(strNumber, out number))
{
// process number
// if you want some output to be formatted with leading
// zeros you can use PadLeft method
int totalNumberOfDigits = 6;
string strResult = number.ToString().PadLeft(totalNumberOfDigits, '0');
}
you can use string.PadLeft() in c# after retrieving your number, as you have fixed length numbers
example from msdn,
string str = "forty-two";
char pad = '.';
Console.WriteLine(str.PadLeft(15, pad)); // Displays "......forty-two".
Console.WriteLine(str.PadLeft(2, pad)); // Displays "forty-two".
The reason SQL does this is because 001234 = 1234 in any number format no matter what type it is. As a "Dirty" solution you could cast it as an int which will give you 1234, perform your calculations and then cast your answer back to string adding the leading zeros.
int myValue = Int32.Parse("001234");
int myAnswer = myValue * 2;
string myAnswerString = "00" + myAnswer.ToString();
The best way to go though would be to format your string as suggested by #Thorsten Dittmar. If possible, do not store numeric values in the database as varchar to begin with, however I know that this is sometimes a requirement, but the I cannot see the point on doing calculations on those values.

Categories