How to check if a song exists? - c#

I can Insert, Update, Delete and Search the MySql Database
I wish to know how to check if a Song Exists in MySql DataBase ...
void CheckIfFileExists(String file, String dir)
{
// $mysqli = new mysqli(SERVER, DBUSER, DBPASS, DATABASE);
string song = Path.GetFileName(file);
song = MySql.Data.MySqlClient.MySqlHelper.DoubleQuoteString(song);
string ConString = " datasource = localhost; port = *;
username = ***; password = *****";
string sql = "SELECT id FROM music WHERE song = " + song);
using (MySqlConnection cn = new MySqlConnection(ConString))
{
cn.Open();
using (MySqlCommand cmd = new MySqlCommand(sql, cn))
{
//if id exixts?
if (???????????)
{
// "Song exists";
}
else
{
// "Song does not exist";
InsertIntoDataBase(String file, String dir);
}
}
}
}

I'll go straight to the real issue, how to upsert correctly, before the question gets closed. Use MySQL's custom INSERT IGNORE and parameterized queries. Using Dapper makes this a one-liner:
var sql=#"INSERT IGNORE INTO music
(ID,song,folder)
VALUES (1, #song,#folder)";
using (var cn= new MySqlConnection(ConString))
{
cn.Execute(sql,new {song=song,folder=#dir});
}
Dapper will open the connection to execute the command and close it afterwards. It will generate a MySqlCommand, generate parameters for every property in the supplied object (#song for song, #folder for folder).
INSERT IGNORE will try to insert a new row to the table. If a row with the same primary key already exists, the INSERT will be ignored.
Generating SQL strings by concatenating input is very dangerous. No amount of quoting can prevent SQL injection attacks, or more benign conversion errors. What would happen if the song was named '0'; DROP TABLE music;-- ? What if the value was a date or number? The query string would end up with invalid characters.
Parameterized queries on the other hand are like C# functions. The parameters are passed to the server outside the string itself, as part of the RPC call. The server generates an execution plan from the query and feeds the parameter values to the compiled execution plan.
The values never change to text or get combined with the query, so there's no way to inject SQL or end up with type conversion issues

Related

C# cannot convert database value to string

I am working on a school project and am having trouble converting a piece of data from a Access database into a string that I can pass to a second form in C#. I know the connection to the database is working and that I am referencing the right table in it to get the information, so I'm not sure what I'm doing wrong. It doesn't show any errors in the code, but every time I run the application, it crashes because it can't find a value from the database for the string at the string accountnumber = reader["Account_Number"].ToString(); line. Is there something I'm doing wrong?
OleDbCommand command = new OleDbCommand();
command.Connection = connection;
command.CommandText = "select * from User_Info where Username='" +txt_Username.Text+ "' and Password='" +txt_Password.Text+ "'";
OleDbDataReader reader = command.ExecuteReader();
int count = 0;
string accountnumber = reader["Account_Number"].ToString();
while (reader.Read())
{
count = count+1;
}
if (count == 1)
{
MessageBox.Show("Login Successful!", "Success!");
connection.Close();
connection.Dispose();
this.Hide();
User_Account_Screen UAS = new User_Account_Screen();
UAS.Number = accountnumber;
UAS.ShowDialog();
Try not to reuse connections unless you have to. The main reason is that you generally want to close connections as soon as possible and it will guard you against possible race conditions later if you have multiple events/actions that can occur at the same time that are data driven.
Close your connections as soon as possible so you do not have open external resources.
To ensure that 1 and 2 occur wrap your IDisposable types in a using block.
Always use parameters instead of string concatenation in your queries. It guards against sql injection (not applicable to MS Access) and ensures you never has issues with strings that contain escape charaters.
A note about MS Access and parameters: Place holders are usually specified by the ? character and are position dependent. This is critical, you cannot rely on the name of the parameter. If you have a parameter collection with 3 parameters in that collection then those parameters must appear in the same order in the query.
I notice you probably have password as plain text, never store passwords in plain text! Instead store a hash of the password. To see if the password matches the user's supplied password at login hash that input as well and then compare that hash to the stored hash to see if they are the same. Use a secure password hashing algorithm like pbkdf2, scrypt, or bcrypt.
To see if a row exists or to just return a single value you can also use ExecuteScalar with a null check as it will return null if no records are returned. I altered the code to just return accountnumber using ExecuteScalar. I also enclosed the column name in brackets which is good practice when including characters outside the range of a-z and 0-9 in your column name.
If you were to want to return data and read it using a data reader then do not use * for your return. Specify your column names instead. This will guard your code against schema changes like columns being added or column order changes.
Here is the updated code.
string accountnumber = null;
using(OleDbConnection connection = new OleDbConnection(/*add your connection string here*/))
using(OleDbCommand command = new OleDbCommand("select [Account_Number] from User_Info where Username = ? AND Password = ?", connection))
{
command.Parameters.Add(new OleDbParameter("#username", OleDbType.VarChar)).Value = txt_Username.Text;
command.Parameters.Add(new OleDbParameter("#password", OleDbType.VarChar)).Value = txt_Password.Text;
connection.Open();
accountnumber = command.ExecuteScalar() as string;
}
if (accountnumber != null)
{
MessageBox.Show("Login Successful!", "Success!");
this.Hide();
User_Account_Screen UAS = new User_Account_Screen();
UAS.Number = accountnumber;
UAS.ShowDialog();
}

Properly check if a record already exists in a database

I have read other questions on this, but it does not help for the most part.
Trying to check if a file has already been uploaded(filename is sent to this table) before creating another record and allowing them to upload the same file again.
I am using this code and it keeps telling me every file is a new file, even when I use the same file for testing. Obviously it should result in "Exists". Connection is already established using "this.Master.Conn" so please no SQLCommand stuff.
I even tried using wildcards in the query.
private string SQLCheck(string FileName)
{
string Check = "Select VideoURL from TrainingVideo2 where VideoURL Like '" + FileName +"' and Status=1;";
Object ob = this.Master.Conn.ExecuteSqlScalarCommand(Check);
string Result;
if (DBNull.Value.Equals(ob))
{
Result = "Exists";
}
else
{
Result = "NewFile";
}
return Result;
}
Also, does anybody have a better(more efficient) way of doing this?
Trying to basically rewrite this in c#.
Private Function CheckName(name As String) As Int32
Dim sql As String = "SELECT ID FROM Company Where Name Like '" & name & "' "
Dim ob As Object = Conn.ExecuteSqlScalarCommand(sql)
If IsDBNull(ob) Then
Return 0
Else
Return CInt(ob)
End If
End Function
There are new and more innovative methods devised to get around the simple "replace all ` and " characters with ..." SQL injection prevention techniques. In your case, if the VideoURL happens to be a varchar (and not nvarchar), then using unicode character U+02BC (URL encoded = %CA%BC) would pass in a quote character as a unicode string, which would bypass your C# checks, but SQL Server will conveniently convert to a quote character in your query. This is just one example of why you should not be doing this :).
In terms of you check, I always prefer using TOP 1 to let SQL Server cut a potential table scan short. So, I would use this query:
Select TOP 1 SomeNonNullIntColumn from TrainingVideo2 where VideoURL Like ... and Status=1;
Execute the query with ExecuteScalar. If the result is null, then the record does not exist.
Never build up an SQL string like that. See SQL injection.
Why are you using like? Do you really have Sql wildcards in that fileName?
Example (sorry for the "SqlCommand stuff", but it's important):
string sql = "select count(*) from TrainingVideo2 where VideoURL = #Name and Status=1"
using (SqlConnection conn = new SqlConnection(connString))
{
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.Add("#Name", fileName);
conn.Open();
return (Int32)cmd.ExecuteScalar() > 0;
}

How to Modify FoxPro memo in C#?

I have a very big string to be updated to the memo field of FoxPro Table, I tried
cmd = db.GetSqlStringCommandWrapper("UPDATE xxx SET memo1 = "adfsd" WHERE condition1 = 'satisfied'");
db.ExecuteNonQuery(cmd);
This query overwrites the previous values in the memo1.
I Cannot use MODIFY memo in C#.
How do I append a string to a already existing memo field in Foxpro using C# ?
Try making the command say:
UPDATE xxx SET memo1 = memo1 + "adfsd"
I think the issue is probably with GetSqlStringCommandWrapper which as far as I can see is deprecated.
This shouldn't be a problem to do, for example using the OLEDB provider:
var DBC = #"C:\mydata.dbc";
string ConnectionString = string.Format("Provider=VFPOLEDB.1;Data Source={0};Exclusive=false;Ansi=true;OLE DB Services = 0", DBC);
using (OleDbConnection testConnection = new OleDbConnection(ConnectionString))
{
OleDbCommand updateCommand = new OleDbCommand(#"update mytable set mymemo=alltrim(mymemo)+ttoc(datetime()) where thisfield='THISVALUE'", testConnection);
testConnection.Open();
updateCommand.ExecuteNonQuery();
Console.WriteLine(#"Finished - press ENTER.");
Console.ReadLine();
}
You need to parameterize your query.. Assuming your query wrapper gets the sql connection handle to the database. The VFP OleDB Provider uses "?" as a "place-holder" for parameters and must match the order as associated to your query.
I have a more detailed sample to a very similar question here...
Try something like
string whatToSetItTo = "this is a test string that can even include 'quotes'";
cmd = db.GetSqlStringCommandWrapper("UPDATE YourTable SET memo1 = ? WHERE someKeyColumn = ?");
cmd.Parameters.Add( "parmForMemoField", whatToSetItTo);
cmd.Parameters.Add( "parmForKeyColumn", "satisfied" );
db.ExecuteNonQuery(cmd);
Notice the parameters added in same sequence. whatever the string value is (or could even be integer, date, etc respective to your table structure, but your sample only was based on strings) the place-holders are filled in order. The values would update accordingly.

Delete file from server

I have an application that I am using as a file uploader with an admin panel on the backend of things. I have most of everything completed on it, but I'm running into a wall where I can't delete the physical file from the server. Permissions are correct to allow such action.
On the click of a delete button next to the entry I'm calling the primary ID of the row and as such I'm able to call from the SQL the stored filePath. Here's my code to do so:
DbConn dbConnx = new DbConn();
SQL = "SELECT filePath FROM database WHERE id='"+ primaryID +"'";
myReader = dbConnx.createDataReader(SQL);
string fn44 = Convert.ToString(myReader.Read());
string url = fn44; //I know redundant
System.IO.File.Delete(url);
All I'm able to gather is that the only information that is pulled is 'true'. I believe this is because I'm trying to convert the information to a string and it doesn't like that. How would I go about taking the value stored in SQL and using it with a variable to perform the delete?
Any help/resources would be greatly appreciated.
I don't know the datatype of myReader, but assuming that is a DataReader of some kind then calling
myReader.Read();
returns a boolean value that tells you if the datareader is positioned on a valid row or not.
To get the content of the record on which the reader is positioned (assuming the previous call returns true) you need to write
myReader = dbConnx.createDataReader(SQL);
if(myReader.Read())
{
string fn44 = Convert.ToString(myReader[0]);
....
}
Your code has another problem called Sql Injection.
You should not use string concatenation with user input when building a sql command.
You use a parameterized query like this
SQL = "SELECT filePath FROM database WHERE id=#p1";
using(SqlConnection con = new SqlConnection(......))
using(SqlCommand cmd = new SqlCommand(SQL, con))
{
con.Open();
cmd.Parameters.AddWithValue("#p1",primaryID);
using(SqlDataReader myReader = cmd.ExecuteReader())
{
.....
}
}
yyy
Having fixed the reading from the database, now you need to check what kind of string is stored in the FilePath field in the database. Remember that every file IO operation on a web site should get to the effective file name using the Server.MapPath method

How to save unicode data to oracle?

I am trying to save unicode data (greek) in oracle database (10 g). I have created a simple table:
I understand that NVARCHAR2 always uses UTF-16 encoding so it must be fine for all (human) languages.
Then I am trying to insert a string in database. I have hardcoded the string ("How are you?" in Greek) in code. Then I try to get it back from database and show it.
class Program
{
static string connectionString = "<my connection string>";
static void Main (string[] args) {
string textBefore = "Τι κάνεις;";
DeleteAll ();
SaveToDatabase (textBefore);
string textAfter = GetFromDatabase ();
string beforeData = String.Format ("Before: {0}, ({1})", textBefore, ToHex (textBefore));
string afterData = String.Format ("After: {0}, ({1})", textAfter, ToHex (textAfter));
Console.WriteLine (beforeData);
Console.WriteLine (afterData);
MessageBox.Show (beforeData);
MessageBox.Show (afterData);
Console.ReadLine ();
}
static void DeleteAll () {
using (var oraConnection = new OracleConnection (connectionString)) {
oraConnection.Open ();
var command = oraConnection.CreateCommand ();
command.CommandText = "delete from UNICODEDATA";
command.ExecuteNonQuery ();
}
}
static void SaveToDatabase (string stringToSave) {
using (var oraConnection = new OracleConnection (connectionString)) {
oraConnection.Open ();
var command = oraConnection.CreateCommand ();
command.CommandText = "INSERT into UNICODEDATA (ID, UNICODESTRING) Values (11, :UnicodeString)";
command.Parameters.Add (":UnicodeString", stringToSave);
command.ExecuteNonQuery ();
}
}
static string GetFromDatabase () {
using (var oraConnection = new OracleConnection (connectionString)) {
oraConnection.Open ();
var command = oraConnection.CreateCommand ();
command.CommandText = "Select * from UNICODEDATA";
var erpReader = command.ExecuteReader ();
string s = String.Empty;
while (erpReader.Read ()) {
string text = erpReader.GetString (1);
s += text + ", ";
}
return s;
}
}
static string ToHex (string input) {
string bytes = String.Empty;
foreach (var c in input)
bytes += ((int)c).ToString ("X4") + " ";
return bytes;
}
}
Here are different outputs:
Text before sending to database in a message box:
Text after getting from database in a message box:
Console Output:
Please can you suggest what I might be doing wrong here?
I can see five potential areas for problems:
How are you actually getting the text into your .NET application? If it's hardcoded in a string literal, are you sure that the compiler is assuming the right encoding for your source file?
There could be a problem in how you're sending it to the database.
There could be a problem with how it's being stored in the database.
There could be a problem with how you're fetching it in the database.
There could be a problem with how you're displaying it again afterwards.
Now areas 2-4 sound like they're less likely to be an issue than 1 and 5. How are you displaying the text afterwards? Are you actually fetching it out of the database in .NET, or are you using Toad or something similar to try to see it?
If you're writing it out again from .NET, I suggest you skip the database entirely - if you just display the string itself, what do you see?
I have an article you might find useful on debugging Unicode problems. In particular, concentrate on every place where the encoding could be going wrong, and make sure that whenever you "display" a string you dump out the exact Unicode characters (as integers) so you can check those rather than just whatever your current font wants to display.
EDIT: Okay, so the database is involved somewhere in the problem.
I strongly suggest that you remove anything like ASP and HTML out of the equation. Write a simple console app that does nothing but insert the string and fetch it again. Make it dump the individual Unicode characters (as integers) before and after. Then try to see what's in the database (e.g. using Toad). I don't know the Oracle functions to convert strings into sequences of individual Unicode characters and then convert those characters into integers, but that would quite possibly be the next thing I'd try.
EDIT: Two more suggestions (good to see the console app, btw).
Specify the data type for the parameter, instead of just giving it an object. For instance:
command.Parameters.Add (":UnicodeString",
OracleType.NVarChar).Value = stringToSave;
Consider using Oracle's own driver instead of the one built into .NET. You may wish to do this anyway, as it's generally reckoned to be faster and more reliable, I believe.
You can determine what characterset your database uses for NCHAR with the query:
SQL> SELECT VALUE
2 FROM nls_database_parameters
3 WHERE parameter = 'NLS_NCHAR_CHARACTERSET';
VALUE
------------
AL16UTF16
to check if your database configuration is correct, you could run the following in SQL*Plus:
SQL> CREATE TABLE unicodedata (ID NUMBER, unicodestring NVARCHAR2(100));
Table created
SQL> INSERT INTO unicodedata VALUES (11, 'Τι κάνεις;');
1 row inserted
SQL> SELECT * FROM unicodedata;
ID UNICODESTRING
---------- ---------------------------------------------------
11 Τι κάνεις;
One more thing worth noting.
If you are using oracle client, and would like to include unicode characters in the CommandText, you should add the folloing line to the start of your application:
System.Environment.SetEnvironmentVariable("ORA_NCHAR_LITERAL_REPLACE", "TRUE");
This will allow you, in case you need it, to use the following syntax:
command.CommandText = "INSERT into UNICODEDATA (ID, UNICODESTRING) Values (11, N'Τι κάνεις;')";
After some investigations here we go:
string input = "•";
char s = input[0];
//table kuuku with column kuku(nvarchar2(100))
string connString = "your connection";
//CLEAN TABLE
using (System.Data.OracleClient.OracleConnection cn = new System.Data.OracleClient.OracleConnection(connString))
{
cn.Open();
System.Data.OracleClient.OracleCommand cmd = new System.Data.OracleClient.OracleCommand("delete from kuku ", cn);
cmd.ExecuteNonQuery();
cn.Close();
}
//INSERT WITH PARAMETER BINDING - UNICODE SAVED
using (System.Data.OracleClient.OracleConnection cn = new System.Data.OracleClient.OracleConnection(connString))
{
cn.Open();
System.Data.OracleClient.OracleCommand cmd = new System.Data.OracleClient.OracleCommand("insert into kuku (kuku) values(:UnicodeString)", cn);
cmd.Parameters.Add(":UnicodeString", System.Data.OracleClient.OracleType.NVarChar).Value = input + " OK" ;
cmd.ExecuteNonQuery();
cn.Close();
}
//INSERT WITHOUT PARAMETER BINDING - UNICODE NOT SAVED
using (System.Data.OracleClient.OracleConnection cn = new System.Data.OracleClient.OracleConnection(connString))
{
cn.Open();
System.Data.OracleClient.OracleCommand cmd = new System.Data.OracleClient.OracleCommand("insert into kuku (kuku) values('" +input+" WRONG')", cn);
cmd.ExecuteNonQuery();
cn.Close();
}
//FETCH RESULT
using (System.Data.OracleClient.OracleConnection cn = new System.Data.OracleClient.OracleConnection(connString))
{
cn.Open();
System.Data.OracleClient.OracleCommand cmd = new System.Data.OracleClient.OracleCommand("select kuku from kuku", cn);
System.Data.OracleClient.OracleDataReader dr = cmd.ExecuteReader();
if(dr.Read())
{
string output = (string) dr[0];
char sa = output[0];
}
cn.Close();
}
}
On reading records, try
Encoding utf = Encoding.Default;
var utfBytes = odatareader.GetOracleString(0).GetNonUnicodeBytes();//OracleDataReader
Console.WriteLine(utf.GetString(utfBytes));
Solution: set NLS_LANG!
Details:
I just had the same problem, and actually had exact the same situation as described in Sergey Bazarnik's investigation. Using bind variables it works, and without them it doesn't.
The SOLUTION is to set NLS_LANG in proper place. Since I have Windows server I set it in windows registry under
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\ORACLE\KEY_OraClient11g_home1
Please note that regitry location may difer so the easiest way is to search registry for "ORACLE_HOME" string. Also other systems like Linux, Unix can set this on different way (export NLS_LANG ...)
In my case I put "NLS_LANG"="CROATIAN_CROATIA.UTF8". Since I had no that variable set it went to default value.
After changing registry you should restart process.
In my case I restarted IIS.
Regarding reason why it works with bind variables may be because it actually happens on server side, while without it actually happens on client side. So even that DB can insert proper values - before that happens, client does the unwanted corrections, since it thinks that is should do that. That is because NLS_LANG defaults to simpler code page. But instead of doing useful task, that creates a problem, which (as shown in investigation looks hard to understand).
In case you have multiple oracle versions, be sure to correct all versions in registry (in my case Oracle 10 had valid setting, but Oracle 11 had no NLS_LANG set at all).

Categories

Resources