I have a class file where I declare readonly string of my query to be used in a method. I met the error of
Must declare the scalar variable "#DBID"
May I know if I declare my variables wrongly?
Below are the code snippets:
Class file:
private static readonly string QUERY_GETMATCHEDRECORD = "SELECT [Title], [ItemLink], [RecordDocID] FROM [ERMS].[dbo].[Records] WHERE [ID] = #DBID AND [V1RecordID] = #recID AND [V1RecordDocID] = #recDocID";
public DataTable GetMatchedRecord(string DBID, string recID, string recDocID)
{
string Method = System.Reflection.MethodBase.GetCurrentMethod().Name;
DataTable dt = new DataTable();
try
{
using (DB db = new DB(_datasource, _initialCatalog))
{
db.OpenConnection();
using (SqlCommand command = new SqlCommand())
{
string commandText = QUERY_GETMATCHEDRECORD .FormatWith(DBID,recID,recDocID);
_log.LogDebug(Method, "Command|{0}".FormatWith(commandText));
command.CommandText = commandText;
dt = db.ExecuteDataTable(command);
}
db.CloseConnection();
}
}
catch (Exception ex)
{
_log.LogError(Method, "Error while retrieving matching records |{0}".FormatWith(ex.Message));
_log.LogError(ex);
}
return dt;
}
Program .cs file:
MatchedRecords = oDB.GetMatchedRecord(DBID, RecID, RecDocID);
using '#'-notated variables will only work if you add the parameters to the commands parameter-collection.
try the following:
using (DB db = new DB(_datasource, _initialCatalog))
{
db.OpenConnection();
using (SqlCommand command = new SqlCommand())
{
command.CommandText = QUERY_GETMATCHEDRECORD;
command.Parameters.AddWithValue("#DBID", DBID);
command.Parameters.AddWithValue("#recID", recID);
command.Parameters.AddWithValue("#recDocID",recDocID);
dt = db.ExecuteDataTable(command);
}
db.CloseConnection();
}
Related
When I run the code, the required information does not appear in the gridbox.
{
public partial class fatura : Form
{
SqlConnection baglanti = new SqlConnection("Server=localhost;Database=master; Trusted_Connection=True");
DataTable tablo;
araba_ekleme araba_ekleme = new araba_ekleme();
public fatura()
{
InitializeComponent();
}
public DataTable listele(SqlDataAdapter adtr, string sorgu)
{
tablo = new DataTable();
adtr = new SqlDataAdapter(sorgu, baglanti);
adtr.Fill(tablo);
baglanti.Close();
return tablo;
}
private void onay_bekleyen()
{
string cumle = "declare #tc_no bigint select tc_no,car_plate,total,date,tax from [invoice] WHERE (status=0) AND tc_no=#tc_no";
SqlDataAdapter adtr2 = new SqlDataAdapter();
dg_pending.DataSource = listele(adtr2, cumle);
}
private void onaylanan()
{
string cumle = "declare #tc_no bigint select tc_no,car_plate,total,date,tax from [invoice] WHERE (status=1) AND tc_no=#tc_no";
SqlDataAdapter adtr2 = new SqlDataAdapter();
dg_done.DataSource = listele(adtr2, cumle);
}
private void fatura_Load(object sender, EventArgs e)
{
onay_bekleyen();
onaylanan();
}
}
}
When I run this code it gives an error. string cumle = "select tc_no,car_plate,total,date,tax from [invoice] WHERE (status=0) AND tc_no=#tc_no";
So i used this code block string cumle = "declare #tc_no bigint select tc_no,car_plate,total,date,tax from [invoice] WHERE (status=0) AND tc_no=#tc_no"; and when I run the code, the required information does not appear in the gridbox.
edit (SqlDataAdapter adtr, string sorgu) function like the code below:
1- You don't need to send SqlDataAdapter as input and define it inside the function.
2- You must open the connection.
3- Use using for SqlDataAdapter and SqlConnection so that there is no need to dispose.
4- Use try- catch to catch the error (In the following function, if there is an error, it will be displayed as a meesageBox. You can write error in file, console or anywhere else)
public DataTable listele(string sorgu)
{
DataTable tablo = new DataTable();
using (SqlConnection MyConnnection = new SqlConnection(conString ))
{
using (SqlDataAdapter dataAdapter = new SqlDataAdapter(sorgu, MyConnnection))
{
try
{
MyConnnection.Open();
dataAdapter.Fill(tablo);
}catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
return tablo;
}
define connection string:
public partial class fatura : Form
{
public string conString = "Server=localhost;Database=master; Trusted_Connection=True";
SqlConnection baglanti = new SqlConnection("Server=localhost;Database=master; Trusted_Connection=True");
DataTable tablo;
araba_ekleme araba_ekleme = new araba_ekleme();
...
Call the function as below:
dg_pending.DataSource = listele(cumle);
I'm trying to write a function -like Dcount and Dlookup in VBA Access- in a public class to use it everywhere in my project so I did the following :
public class MyTools
{
SqlConnection Cn = new SqlConnection(#"Server = AMR-PC\SQLEXPRESS ; Database=PlanningDB ; Integrated Security = True");
SqlDataAdapter da;
DataTable dt = new DataTable();
// DataView dv = new DataView();
SqlCommand cmd;
SqlDataReader DataRead;
// Variables
string MyColumn, MyTable, MyCondition,DlookResult;
int DcountResult;
// Methods & Functions
// Dcount
public int DCount(string MyColumn, string MyTable, string MyCondition)
{
da = new SqlDataAdapter("Select Count(#MyColumn) from #MyTable where #MyColumn = #MyCondition", Cn);
da.Fill(dt);
DcountResult = int.Parse(dt.Rows[0].ToString());
return DcountResult;
}
}
// Dlookup
}
And tried to use it like this :
int Result = DCount(txtColumn.Text, txtTable.Text, txtCond.Text);
txtResult.Text = null;
txtResult.Text = Result.ToString();
But it throws the error "Must declare the scalar variable "#MyColumn".
I tried to use sqlcommand and DataRead but I need to close the connection after the return and it became Unreachable or close before the return so it returns nothing , That's why i used SqlDataAdapter.
Thanks in advance .
It would have to look something more like this:
public class MyTools
{
private static string ConnectionString {get;} = #"Server = AMR-PC\SQLEXPRESS ; Database=PlanningDB ; Integrated Security = True";
public static int DCount(string MyTable, string MyColumn, string MyCondition)
{
string sql = $"Select Count({MyColumn}) from {MyTable} where {MyColumn} = #MyCondition";
using (var cn = new SqlConnection(ConnectionString))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.AddWithValue("#MyCondition", MyCondition);
cn.Open();
return (int)cmd.ExecuteScalar();
}
}
}
Just be aware this uses dynamic SQL, and is more than a little dangerous. In fact, you should not do this. I know you don't want to "keep typing SQL queries", but that might be exactly what you should do.
Veracode report is showing a SQL injection flaw for the below query.
private const string DropDatabaseTemplate = #"DROP DATABASE [{0}]";
ExecuteNonQuery(connection, string.Format(DropDatabaseTemplate, databaseName));
private static int ExecuteNonQuery(SqlConnection connection, string commandText)
{
using (var command = new SqlCommand(commandText, connection))
{
return command.ExecuteNonQuery();
}
}
they suggested using parameterized prepared statements.
What would be my approach to remove this security vulnerability
Thanks in advance.
Ans :
You can simply avoid security vulnerability with this
private static void ExecuteNonQuery(SqlConnection connection, string commandText)
{
using (var command = new SqlCommand("exec sp_executesql #sqlCommandText", connection))
{
command.Prepare();
command.Parameters.Add("#sqlCommandText", SqlDbType.NVarChar);
command.Parameters["#sqlCommandText"].Value = commandText;
command.ExecuteNonQuery();
}
}
I've never tried it, but I suspect it will work:
private static void DropDbNamed(SqlConnection connection, string name)
{
using (var command = new SqlCommand("EXEC #q", connection))
{
command.Parameters.AddWithValue("#q", $"DROP DATABASE [{name}]");
var command.ExecuteScalar();
}
}
Note: Joel's standard "stop using AddWithValue" doesn't apply here
How it could look like.
private const string DropDatabaseTemplate = #"DROP DATABASE [{0}]";
private static int ExecuteNonQuery(SqlConnection connection, string commandText)
{
string dbNamesQuery_ = #"SELECT [name]
FROM sys.databases d
WHERE d.database_id > 4";
DataTable tableNames = new DataTable();
using (var command = new SqlCommand(dbNamesQuery_, connection))
{
SqlDataReader dataReader_ = command.ExecuteReader();
tableNames.Load(dataReader_); //allow you dynamically load actual list DB, but you can fill table manually.
//find exactly same name of DB that user requared.
var rowsData_ = tableNames.Select(String.Format("name = '{0}'", commandText));
if (rowsData_.Length == 1) //it will be prevent any kind of injection.
{
command.CommandText = String.Format(DropDatabaseTemplate, commandText);
return command.ExecuteNonQuery();
}
else
{
return -1;
}
}
}
I am using the following code to consume a CUBRID database java stored procedure.
string ConnectionString = "server=localhost;database=demodb;port=30000;user=dba;password=123456";
DataTable dt = new DataTable();
DataSet ds = new DataSet();
CUBRIDConnection con = new CUBRIDConnection(ConnectionString);
CUBRIDCommand com = new CUBRIDCommand();
com.CommandType = CommandType.StoredProcedure;
com.Connection = con;
com.CommandText = "select rset()";
CUBRIDParameter pan = new CUBRIDParameter();
pan.Direction = ParameterDirection.Output;
pan.CUBRIDDataType = CUBRIDDataType.CCI_U_TYPE_RESULTSET;
pan.ParameterName = "?p1";
CUBRIDDataAdapter dap = new CUBRIDDataAdapter(com);
con.Open();
int val = dap.Fill(ds);
con.Close();
and in the server use the next function and stored procedure in the server
public class JavaSP3 {
public static ResultSet TResultSet(){
try {
Class.forName("cubrid.jdbc.driver.CUBRIDDriver");
Connection con = DriverManager.getConnection("jdbc:default:connection:");
String sql = "select * from athlete";
Statement stmt=con.createStatement();
ResultSet rs = stmt.executeQuery(sql);
((CUBRIDResultSet)rs).setReturnable();
return rs;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
}
and the function code is this
CREATE FUNCTION "rset"() RETURN CURSOR
AS LANGUAGE JAVA
NAME 'JavaSP3.TResultSet() return cubrid.jdbc.driver.CUBRIDResultSet'
I run this with a function that result a string and return the value, but when I change to CUBRIDResultSet value dont work and CUBRID says>
execute error:-911
line 1 is not executed (error)
Error description:
Invalid call: it can not return ResultSet.
Please, I have 3 days trying to solve this any one can help me?
ADO.NET dont provide support for ResultSet.
http://www.cubrid.org/?mid=forum&category=195532&document_srl=358924
using System.Data;
using CUBRID.Data.CUBRIDClient;
using System.Data.Common;
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string ConnectionString = "server=localhost;database=demodb;port=30000;user=dba;password=123456";
DataTable dt = new DataTable();
DataSet ds = new DataSet();
CUBRIDConnection con = new CUBRIDConnection(ConnectionString);
CUBRIDCommand com = new CUBRIDCommand();
com.CommandType = CommandType.Text; //Important ADO.NET driver crash using call convention
com.Connection = con;
com.CommandText = "select rset();";
CUBRIDParameter pan = new CUBRIDParameter();
con.Open();
DbDataReader reader = com.ExecuteReader();
CustomAdapter da = new CustomAdapter();
da.FillFromReader(dt, reader);
con.Close();
DataRow fila = dt.Rows[0];
Console.WriteLine(fila[0].ToString());
Console.ReadKey();
}
}
public class CustomAdapter : System.Data.Common.DbDataAdapter
{
public int FillFromReader(DataTable dataTable, IDataReader dataReader)
{
return this.Fill(dataTable, dataReader);
}
protected override System.Data.Common.RowUpdatedEventArgs CreateRowUpdatedEvent(DataRow a, IDbCommand b, StatementType c, System.Data.Common.DataTableMapping d)
{
return (System.Data.Common.RowUpdatedEventArgs)new EventArgs();
}
protected override System.Data.Common.RowUpdatingEventArgs CreateRowUpdatingEvent(DataRow a, IDbCommand b, StatementType c, System.Data.Common.DataTableMapping d)
{
return (System.Data.Common.RowUpdatingEventArgs)new EventArgs();
}
protected override void OnRowUpdated(System.Data.Common.RowUpdatedEventArgs value)
{
}
protected override void OnRowUpdating(System.Data.Common.RowUpdatingEventArgs value)
{
}
}
java class
import java.sql.*;
import cubrid.jdbc.driver.*;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import javax.xml.transform.dom.*;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class JavaSP3 {
public static String TResultSet(){
ResultSet rs = null;
Statement stmt = null;
String sql;
try {
Class.forName("cubrid.jdbc.driver.CUBRIDDriver");
Connection con = DriverManager.getConnection("jdbc:default:connection:");
((CUBRIDConnection)con).setCharset("euc_kr");
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder =factory.newDocumentBuilder();
Document doc = builder.newDocument();
Element results = doc.createElement("Results");
doc.appendChild(results);
sql = "select * from athlete";
stmt=con.createStatement();
rs = stmt.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData();
int colCount = rsmd.getColumnCount();
while (rs.next()) {
Element row = doc.createElement("Row");
results.appendChild(row);
for (int ii = 1; ii <= colCount; ii++) {
String columnName = rsmd.getColumnName(ii);
Object value = rs.getObject(ii);
Element node = doc.createElement(columnName);
node.appendChild(doc.createTextNode(value.toString()));
row.appendChild(node);
}
}
String valor = getDocumentAsXml(doc);
return valor;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public static String getDocumentAsXml(Document doc)
throws TransformerConfigurationException, TransformerException {
DOMSource domSource = new DOMSource(doc);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
//transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,"yes");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.ENCODING,"ISO-8859-1");
transformer.setOutputProperty
("{http://xml.apache.org/xslt}indent-amount", "4");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
java.io.StringWriter sw = new java.io.StringWriter();
StreamResult sr = new StreamResult(sw);
transformer.transform(domSource, sr);
return sw.toString();
}
}
Cubrid function
CREATE FUNCTION "rset"() RETURN STRING
AS LANGUAGE JAVA
NAME 'JavaSP3.TResultSet() return java.lang.String'
This allow you get data from Java stored procedures in CUBRID using ADO.NET
First time user - hoping this is in the right format:
I am wanting to know if I can create SQL DbParameter values, esp on the ParamaterName.
My current code is:
DbCommand dbCommand = SqlDb.GetStoredProcCommand(uspCommand);
DbParameter ProcessedFileName = dbCommand.CreateParameter();
ProcessedFileName.DbType = DbType.String;
ProcessedFileName.ParameterName = "#FileName";
ProcessedFileName.Value = pstrProcessedFileName;
dbCommand.Parameters.Add(ProcessedFileName);
I am wanting to add:
ProcessedFileName.ParameterName = "#FileName1";
ProcessedFileName.ParameterName = "#FileName2";
ProcessedFileName.ParameterName = "#FileName3";
ProcessedFileName.ParameterName = "#FileName4";
with the #FileNames coming from an array.
Something like this should work:
DbCommand dbCommand = SqlDb.GetStoredProcCommand(uspCommand);
foreach(String param in MyParameters)
{
DbParameter ProcessedFileName = dbCommand.CreateParameter();
ProcessedFileName.DbType = DbType.String;
ProcessedFileName.ParameterName = param;
ProcessedFileName.Value = pstrProcessedFileName;
dbCommand.Parameters.Add(ProcessedFileName);
}
best way to do this is put them in Dictionary, because you will need value also
Dictionary<string, string> params = new Dictionary<string,string>();
and just add them many as you want
params.Add("#FileName1", "my_filename")
etc...
and then
foreach(var param in params)
dbCommand.Parameters.AddWithValue(param.Key, param.Value);
Creating dynamic SQL DbParameter values
This is very helpful when you are going to create project where there is dynamic database, or may in future you are going to migrate / switch database .
Here is step by step solution
step 1) Create Parameter structure
public struct Parameter
{
public string ParameterName { get; set; }
public ParameterDirection Direction { get; set; }
public DbType DbType { get; set; }
public object Value { get; set; }
public string SourceColumn { get; set; }
public int Size { get; set; }
}
Step 2) Create database handling class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;
using System.Configuration;
using System.Data.Common;
using MySql.Data.MySqlClient;
using MySql.Data;
using Oracle.DataAccess;
using Oracle.DataAccess.Client;
public class DBManagement
{
string connectionStr;
DbConnection con;
DbCommand cmd;
DbDataAdapter AD;
DataSet ds;
DbParameter[] sp;
IDBManagement Iobj = null;
public DBManagement()
{
this.Initialize();
}
void Initialize()
{
try
{
switch (ConfigurationManager.AppSettings["ActiveDatabase"].ToUpper())
{
case "MSSQL":
connectionStr = ConfigurationManager.ConnectionStrings["MSSQLConnectionString"].ConnectionString;
con = new SqlConnection();
cmd = new SqlCommand();
AD = new SqlDataAdapter();
break;
case "ORACLE":
connectionStr = ConfigurationManager.ConnectionStrings["OracleConnectionString"].ConnectionString;
con = new OracleConnection();
cmd = new OracleCommand();
AD = new OracleDataAdapter();
break;
case "MYSQL":
connectionStr = ConfigurationManager.ConnectionStrings["MYSQLConnectionString"].ConnectionString;
con = new MySqlConnection();
cmd = new MySqlCommand();
AD = new MySqlDataAdapter();
break;
default:
break;
}
con.ConnectionString = connectionStr;
cmd.Connection = con;
}
catch (Exception ex)
{
}
}
public DataSet ExecuteProcedure(string procName, CommandType cmdType, Parameter[] DBParameters = null)
{
try
{
cmd.CommandText = procName;
cmd.CommandType = cmdType;
cmd.Parameters.Clear();
if (DBParameters != null && DBParameters.Length > 0)
{
sp = DBParameters.ToParamerArray(cmd);
cmd.Parameters.AddRange(sp);
}
ds = new DataSet();
AD.SelectCommand = cmd;
AD.Fill(ds);
return ds;
}
catch (Exception ex)
{
throw ex;
}
}
}
Step 3) Convert parameter as per database
public static partial class GlobalExtensionFunctions
{
public static DbParameter[] ToParamerArray(this Parameter[] parameters,DbCommand cmd)
{
DbParameter[] sp = new DbParameter[parameters.Length];
int i = 0;
foreach (Parameter parameter in parameters)
{
// DbParameter p = cmd.CreateParameter();
sp[i] = cmd.CreateParameter();
sp[i].ParameterName = parameter.ParameterName;
sp[i].Value = parameter.Value;
sp[i].Direction = string.IsNullOrEmpty(Convert.ToString(parameter.Direction)) || parameter.Direction==0 ? ParameterDirection.Input : parameter.Direction;
sp[i].DbType = parameter.DbType;
sp[i].SourceColumn = parameter.SourceColumn;
sp[i].Size = parameter.Size;
i++;
}
return sp;
}
}
Step 4) Get Data
DBManagement c = new DBManagement();
public DataSet GetGetTestList(int testId)
{
Parameter[] p = new Parameter[1];
p[0].ParameterName = "#TestId";
p[0].Value = testId;
p[0].DbType = DbType.Int32;
return c.ExecuteProcedure(Procedures.TestDetails, CommandType.StoredProcedure,p);
}
Now use dataset or datatable and enjoy! :)
Abe - thanks - you got me in the right direction. Here is what I ended up doing:
inside my foreach loop, I'm calling my method:
foreach (DataRow row in GlobalClass.NAVdataTable.Rows)
{
GlobalClass.AddToDbCommand(ref dBCommand, row["FieldName"].ToString(), row["Value"].ToString());
connection.Open();
SqlDb.ExecuteNonQuery(dBCommand);
connection.Close();
dBCommand.Parameters.Clear();
}
and then my AddToDbCommand method contains:
public static void AddToDbCommand(ref DbCommand dbCommand, string FieldName, string FieldValue)
{
string FieldNameParameter = "#" + FieldName;
DbParameter dbParameter = dbCommand.CreateParameter();
dbParameter.ParameterName = FieldNameParameter;
dbParameter.Value = FieldValue;
dbCommand.Parameters.Add(dbParameter);
}
Refactored as an extension to DbCommand, also fieldName is left without #, so you need to pass # or : prefixes and fieldValue is set to object type (not only string).
public static class DbCommandExtensions
{
public static void AddParam(this DbCommand dbCommand, string fieldName, object fieldValue)
{
string fieldNameParameter = fieldName;
DbParameter dbParameter = dbCommand.CreateParameter();
dbParameter.ParameterName = fieldNameParameter;
dbParameter.Value = fieldValue;
dbCommand.Parameters.Add(dbParameter);
}
}