Pass 2D array from C# to Postgresql function - c#

Here is postgresql running query with pg admin iii. (Below query working fine with pg admin and it is returning result set without any issue)
select * from pg_sp_getmainrates_11(9,10,array[[5,10,10,10],[30,20,15,16]]);
Here is parameter declaration of pg function.
CREATE OR REPLACE FUNCTION pg_sp_getmainrates_11(
IN fromcountryid integer,
IN tocountryid integer,
IN alldimensions_we_le_he_wi double precision[]
)
-- My logic is going here
But when passing array using C# code, it is returning error when executing the query.
Exeption attributes
Basemessage : syntax error at or near ","
ErrorSql : SELECT * FROM pg_sp_getmainrates_11(9,10,System.Double[,])
Here is my C# code.
double[,] codes = new double[,]
{
{ 5,10,10,10},{ 30,20,15,16}
};
string quy = "pg_sp_getmainrates_11(" + FromCountryId +
"," + ToCountryId +
"," + codes + ")";
NpgsqlCommand command = new NpgsqlCommand(quy, conn);
command.CommandType = CommandType.StoredProcedure;
NpgsqlDataReader dr = command.ExecuteReader();
I need a small direction to pass an array (like above) to my postgresql function.

Up to now I found a solution for this. (Don't know whether this is the optimum solution)
The simple thing to send parameter as string.
With my C# code I make some string like below.
String arr = "array[[5,10,10,10],[30,20,15,16]]";
This arr will be passed as query parameter.
string quy = "pg_sp_getmainrates_11(" + FromCountryId +
"," + ToCountryId +
"," + arr+ ")";
Above solution works fine.

You can use using Newtonsoft.Json; and insert your array like the following:
string[][] arr = {{5, 10, 10, 10},{30, 20, 15, 16}};
var arrayOutput = JsonConvert.SerializeObject(arr);
try
{
string sql1 = "INSERT INTO tbt(img, fcth, dev) VALUES (ARRAY'" + arrayOutput + "')";
dbcmd.CommandText = sql1;
cmd.ExecuteNonQuery();
}
catch (NpgsqlException ex)
{
if (ex.Data == null)
{
throw;
}
else
{
}
}
This example Just for array column.

Related

OleDbCommand with 'where in' and dbParameter

I try to delete some rows from a table in an access database file via C#.
This attempt fails with no error which leads me to the conclusion that I have a valid query with incorrect data.
I tried to see if I can query the data with a select statement from my code and I can narrow the problem down to the parameters.
The statement should look as follows
SELECT * FROM tbIndex where pguid in ('4a651816-e15b-4c6a-85c4-74033ca6c423', '0add7bff-a22f-4238-9c7f-e1ff4ed3c7e2', '742fae8b-2692-4a6f-802c-848fad570696', '5e6b65de-2403-4800-a47d-e57c7bd8e0a6')
I tried two different ways*(dbCmd2 and dbCmd3)* from which the first*(dbCmd2)* works but is, due to injection problems, not my prefered solution.
using (OleDbCommand dbCmd2 = new OleDbCommand { Connection = m_Connection })
{
dbCmd2.CommandText = "SELECT * FROM tbIndex where pguid in ("+pguid+")";
using (DbDataReader reader = dbCmd2.ExecuteReader())
{
List<object[]> readValuesFromIndex = new List<object[]>();
while (reader.Read())
{
//Point reached
object[] arr = new object[reader.VisibleFieldCount];
reader.GetValues(arr);
//...
}
reader.Close();
}
using (OleDbCommand dbCmd3 = new OleDbCommand { Connection = m_Connection })
{
dbCmd3.CommandText = "SELECT * FROM tbIndex where pguid in (#pguid)";
dbCmd3.Parameters.Add("#pguid", OleDbType.VarChar).Value = pguid;
using (DbDataReader reader = dbCmd3.ExecuteReader())
{
List<object[]> readValuesFromIndex = new List<object[]>();
while (reader.Read())
{
//Point not reached
object[] arr = new object[reader.VisibleFieldCount];
reader.GetValues(arr);
//...
}
reader.Close();
}
}
Note that pguid is set to "'4a651816-e15b-4c6a-85c4-74033ca6c423', '0add7bff-a22f-4238-9c7f-e1ff4ed3c7e2', '742fae8b-2692-4a6f-802c-848fad570696', '5e6b65de-2403-4800-a47d-e57c7bd8e0a6'".
I always thought that the second option would simply replace the parameter in a safe manner but this is obviously not the case.
My question is:
Why doesn't the second option return any values?
A parameter always is a single value.
An in clause requires multiple values, separated by comma's.
You can do something like the following to pass them like separate parameters:
string[] guids = pguid.Split(',');
string sqlin = "";
int paramno = -1;
foreach (var guid in guids)
{
parametercount ++;
sqlin = sqlin + "#Param" + (string)parametercount; + ","
}
dbCmd3.CommandText = "SELECT * FROM tbIndex where pguid in (" + sqlin.Substring(0, sqlin.Length-1) + ")";
for(int i = 0; i <= parametercount; i++){
dbCmd3.Parameters.Add("#Param" + (string)i, OleDbType.VarChar).Value = guids[i].Replace("'", "");
}

How to pass a C# variable with apostrophe through MySql

I'm having a problem inputting variables into my database. I've seen other posts on how to pass a variable through by just escaping it, but those solutions do not apply because I am getting my variable's through an API. I'm cycling though data with a foreach loop by the way.
level = "" + x.Account_Level + "";
name = "" + x.name + "";
command.CommandText = "INSERT INTO `data` (`level`, `name`) VALUES(" + level + ", " + name + ")";
command.ExecuteNonQuery();
Sometimes, a variable will come back with an apostrophe and will screw up the code. Is it possible to insert a slash before every apostrophe or is there a way like in PHP to just push the whole variable through with single quotes? Thanks!
Edit:
Would this work? I think I need to add the i to change the name of the parameter each loop, due to it claiming the parameter as already declared.
using (var web = new WebClient())
{
web.Encoding = System.Text.Encoding.UTF8;
var jsonString = responseFromServer;
var jss = new JavaScriptSerializer();
var MatchesList = jss.Deserialize<List<Matches>>(jsonString);
string connectString = "Server=myServer;Database=myDB;Uid=myUser;Pwd=myPass;";
MySqlConnection connect = new MySqlConnection(connectString);
MySqlCommand command = connect.CreateCommand();
int i = 1;
connect.Open();
foreach (Matches x in MatchesList)
{
command.CommandText = "INSERT INTO `data` (`level`, `name`) VALUES(?level" + i + ", ?name" + i + ")";
command.Parameters.AddWithValue("level" + i, x.Account_Level);
command.Parameters.AddWithValue("mode" + i, x.name);
command.ExecuteNonQuery();
i++;
}
connect.Close();
}
The quick and dirty fix is to use something like:
level = level.Replace("'","whatever");
but there are still problems with that. It won't catch other bad characters and it probably won't even work for edge cases on the apostrophe.
The best solution is to not construct queries that way. Instead, learn how to use parameterised queries so that SQL injection attacks are impossible, and the parameters work no matter what you put in them (within reason, of course).
For example (off the top of my head so may need some debugging):
MySqlCommand cmd = new MySqlCommand(
"insert into data (level, name) values (?lvl, ?nm)", con);
cmd.Parameters.Add(new MySqlParameter("lvl", level));
cmd.Parameters.Add(new MySqlParameter("nm", name));
cmd.ExecuteNonQuery();

Retrieving the return value from Oracle with C#

I'd like to be able to retrieve the return value from a function in Oracle with c#.
Currently, this is what I have:
For SQL:
FUNCTION add_resource (
project_view BOOLEAN,
project_id NUMBER,
worker_id NUMBER,
role_id NUMBER) RETURN NUMBER IS
resource_id NUMBER;
BEGIN
INSERT INTO RESOURCE_T (WORKERID, ROLEID, PROJECTID)
VALUES (worker_id, role_id, project_id)
RETURNING RESOURCEID INTO resource_id;
RETURN resource_id;
END add_resource;
For C#
cmdText = "DECLARE resource_id NUMBER; BEGIN resource_id := PKG_RAP.add_resource(" + projectView + "," + id + "," + record["WORKERID"] + "," + record["ROLEID"] + "); END;";
using (OracleCommand cmd = new OracleCommand(cmdText, conn))
{
OracleTransaction trans = conn.BeginTransaction();
try
{
OracleParameter prm = new OracleParameter("resource_id", OracleDbType.Int32, ParameterDirection.ReturnValue);
cmd.Parameters.Add(prm);
cmd.ExecuteNonQuery();
trans.Commit();
}catch
{
trans.Rollback();
throw;
}
}
The query works individually when I test it out in the database, however, the c# is not able to grab the value for resource_id and only gets "null". Any tips would be appreciated!
Does something like this not work?
cmdText = #"select PKG_RAP.add_resource(:projectView, :projectId, :workerId, :roleId) from dual";
using (var cmd = new OracleCommand(cmdText, conn))
using (cmd.Parameters.Add(":projectView", projectView))
using (cmd.Parameters.Add(":projectId", id))
using (cmd.Parameters.Add(":workerId", record["WORKERID"]))
using (cmd.Parameters.Add(":roleId", record["ROLEID"]))
using (var tx = conn.BeginTransaction()) {
try {
// resource ID
var resourceId = Convert.ToInt32(cmd.ExecuteScalar());
tx.Commit();
return resourceId;
} catch {
tx.Rollback();
throw;
}
}
This seems (to me) like the simplest solution to calling a PL-SQL function to return a single value.
ETA: I don't have sufficient rep to comment, yet, but Marc, above, means that you don't return anything in the PL-SQL block you are executing.
The command text must be like this one if you like to call a function (and if you want or have to avoid select ... from dual:
cmdText = "BEGIN :resource_id := PKG_RAP.add_resource(" + projectView + "," + id + "," + record["WORKERID"] + "," + record["ROLEID"] + "); END;";
As John Pederson already answered, all parameters should be defined as bind values, e.i.
cmdText = "BEGIN :resource_id := PKG_RAP.add_resource(:projectView, :projectId, :workerId, :roleId); END;";
However, I don't think you can use boolean variables when calling from C#. You have to cast it, e.g. to "0" and "1"

Index was outside the bounds of the array exception

Here is my code to get data from a flat file and insert into SQL Server. It is generating an exception (Index was outside the bounds of the array).
string path = string.Concat(Server.MapPath("~/TempFiles/"), Fileupload1.FileName);
string text = System.IO.File.ReadAllText(path);
string[] lines = text.Split(' ');
con.Open();
SqlCommand cmd = new SqlCommand();
string[] Values = new string[3];
foreach (string line1 in lines)
{
Values = line1.Split(';');
string query = "INSERT INTO demooo VALUES ('" + Values[0] + "','" + Values[1] + "','" + Values[2] + "')";
cmd = new SqlCommand(query,con);
cmd.ExecuteNonQuery();
}
The exception happens because one of your lines has less than three elements separated with a semicolon. Even though you declare Values as a String array of three elements, affecting the variable to the result of String.Split() function makes that irrelevant: your array will have whatever length the returned array has. If it's less, your code will definitely fail.
If it's not supposed to happen I suggest you do an assertion in your code to help you debugging:
// ...
Values = line1.Split(';');
// the following will make the debugger stop execution if line.Length is smaller than 3
Debug.Assert(line1.Length >= 3);
// ...
As a side note, I should mention making a batch INSERT would be far more efficient. Also your way of declaring and reaffecting cmd variable isn't quite correct. And finally you should call String.Replace on your values to make sure any apostrophes is doubled. Otherwise your code will be open for SQL injection attacks.
Some details on how your code is behaving at run-time:
// This line declares a variable named Values and sets its value to
// a new array of strings. However, this new array is never used
// because the loop overwrites Values with a new array before doing
// anything else with it.
string[] Values = new string[3];
foreach (string line1 in lines)
{
Values = line1.Split(';');
// At this point in the code, whatever was previously stored in Values has been
// tossed on the garbage heap, and Values now contains a brand new array containing
// the results of splitting line1 on semicolons.
// That means that it is no longer safe to assume how many elements the Values array has.
// For example, if line1 is blank (which often happens at the end of a text file), then
// Values will be an empty array, and trying to get anything out of it will throw an
// exception
string query = "INSERT INTO demooo VALUES ('" + Values[0] + "','" + Values[1] + "','" + Values[2] + "')";
cmd = new SqlCommand(query,con);
cmd.ExecuteNonQuery();
}
Similar to how Values keeps getting overwritten, that SqlCommand that's created outside the loop will also never get used. It's safe to put both of these declarations inside the loop instead. The following code does that, and also adds some error checking to make sure that a usable number of values was retrieved from the line. It will simply skip any lines that aren't long enough - if that's not OK then you might need to create some more complex error-handling code of your own.
foreach(string line in lines)
{
string[] values = line.split[';'];
if(values.Length >= 3)
{
string query = "INSERT INTO demooo VALUES ('" + Values[0] + "','" + Values[1] + "','" + Values[2] + "')";
using (SqlCommand command = new SqlCommand(query, con))
{
cmd.ExecuteNonQuery();
}
}
}
As one final note, the above code might be vulnerable to hackers if you were using it in something like a Web application. Think about what command might get sent to the server if you were processing a file that looked like this:
1;2;3
4;5;6
7;8;9') DROP TABLE demooo SELECT DATALENGTH('1
A safer option is to use parameterized queries, which will help protect against this kind of attack. They do this by separating the command from its arguments, which helps protect you against passing in values for arguments that look like SQL code. An example of how to set things up that way would look more like this:
string query = "INSERT INTO demooo VALUES (#val1, #val2, #val3);
using (var command = new SqlCommand(query, con))
{
command.Parameters.AddWithValue("#val1", Values[0]);
command.Parameters.AddWithValue("#val2", Values[1]);
command.Parameters.AddWithValue("#val3", Values[2]);
command.ExecuteNonQuery();
}
Try this.
string path = string.Concat(Server.MapPath("~/TempFiles/"), Fileupload1.FileName);
string text = System.IO.File.ReadAllText(path);
string[] lines = text.Split(' ');
con.Open();
string[] Values;
foreach (string line1 in lines)
{
Values = line1.Split(';');
if (Values.Length >= 3)
{
string query = "INSERT INTO demooo VALUES ('" + Values[0] + "','" + Values[1] + "','" + Values[2] + "')";
}
else
{
//Some error occured
}
using (var cmd = new SqlCommand(query,con))
{
cmd.ExecuteNonQuery();
}
}

Insert DateTime into Access

The problem:
I'm trying to insert a date time into an access database using the Oledb interface in C#.
Hacking solution: Generate my on insert string without using command.Properties
I can insert text into the database with no problem, but when trying datetime, I end up with this error: System.Data.OleDb.OleDbException {"Data type mismatch in criteria expression."}
There are several posts similar to this but alas with no working solution.
Here is my code:
void TransferData()
{
string instCmd = Get_InsertCommand(0); // hard coded table 0 for testing
Fill_ProductTable_ToInsert();
con.Open();
// It would be nice not to have to separate the date indexes
int[] textIndex = { 0, 1, 2, 3, 4, 7 };
int[] dateIndex = { 5, 6 };
try
{
foreach (DataRow row in DataToStore.Tables[0].Rows)
{
OleDbCommand command = new OleDbCommand();
command.Connection = con;
command.CommandText = instCmd;
foreach(int j in textIndex)
command.Parameters.AddWithValue("#" + j, row[j]);
foreach (int j in dateIndex)
{
// TESTING CODE
///////////////////////////////////////////////////////////////////////////
string input = "#\'" +DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") +"\'#";
command.Parameters.AddWithValue("#" + j, input.ToString());
Program.WriteLine(input.ToString());
///////////////////////////////////////////////////////////////////////////
}
command.ExecuteNonQuery();
}
}
finally
{
con.Close();
}
}
string Get_InsertCommand(int i)
{
string sqlIns = "INSERT INTO " + DataToStore.Tables[0].TableName + " (";
string temp = "VALUES (";
for (int j = 0; j < expected_header[i].Length - 1; j++)
{
sqlIns += expected_header[i][j] + ", ";
temp += "#" + j + ", ";
}
int lastIndex = expected_header[i].Length -1;
sqlIns += expected_header[i][lastIndex] + ") ";
temp += "#" + lastIndex + ")";
sqlIns += temp;
return sqlIns;
}
Inside the area labeled testing code, I have tried every permutation of date time I could think of.
I tried every format with # and '
I tried these formats: yyyy-MM-dd, yyyyMMdd, yyyy\MM\dd, yyyy/MM/dd
I also tried ToOADate()
And ToString(), ToShortDateString()
I also tried setting the database to accept ANSI-92 Sql
I'm running out of ideas.
Note: This code is set up to deal with multiple tables from multiple databases, mind the loops...
Use parameters properly, and don't worry about the format of the datetime value that you concatenate in your query.
I don't understand why you want to convert the datetime value to a string value ?
DateTime theDate = new DateTime(2012,10,16);
var cmd = new OleDbCommand();
cmd.CommandText = "INSERT INTO sometable (column) VALUES (#p_bar)";
cmd.Parameters.Add ("#p_bar", OleDbType.DateTime).Value = theDate;
I was able to solve this issue by not using command properties. I generated my own sql input and set it to cmd.commandText. The text input for datetime to a data base is #yyyy-MM-dd#

Categories

Resources