I've got a query that should contain a literal at sign (#). How do I express this with a Dapper query?
var num = cnx.Query<int>("declare #foo int = 2; select #foo").Single();
I've tried using literals as a workaround:
var num = cnx.Query<int>(
"declare {=at}foo int = 2; select {=at}foo", new { at = "#" }
).Single();
But this throws a NotSupportedException since string literals aren't supported...
(Note that in my real code, I've got other #parameters that I actually do want replaced and auto-escaped for me, so I'd rather stick with Dapper if possible instead of just using a raw SqlCommand.)
Oh. I figured it out. If you have a #param that isn't actually bound to anything, it's passed as-is to the underlying SqlCommand, which passes it straight to the DB.
In other words, you don't need to do anything special to get this to work. My first example should run fine. Silly me.
Related
I am calling a stored proc [MS SQL] using EF5 from a .net application
The call from EF
return base.ExecuteFunction<sp_select_contracts_Result>("sp_select_contracts", x, y, z);
in the proc the parameter is defined as #para1 CHAR(2) etc
But in SQL Profiler I caught EF sending the following
exec [dbo].[sp_select_contracts_statistics] #x='15 '#y='24 ',#z='2010 '
Exactly like that - a huge amount of spaces after the actual value.
When I change the CHAR to VARCHAR it works correctly:
exec [dbo].[sp_select_contracts_statistics] #x='15','#y='24,#z='2010'
I could work around this easily, but I would like to know what I am missing
here.
Update:
Forgot to mention that in C# all the values are strings.
In the last call from c# before going through EF the values are correct:
x = "15" {String} etc..
Edit2:
Changing CHARS to VARCHARS worked as expected. Would still prefer to know if this is a bug or just something we are missing.
When you define a char parameter, you have to define the max length otherwise it is going to do something weird. It defaults to putting white space for all the other characters not defined for the full length of the max size. I'm guessing the max size default for EF for a char here is pretty big:
var parm = new SqlParameter("x", SqlDbType.Char, 2);
parm.Value = "15";
I have the following code:
string sql = "SELECT COUNT(*) FROM " + tableName;
var rtn = DapperConnection.Query<int>(sql);
This works and bring back 1 record in the rtn variable. When I inspect the variable it seems to have 2 members, one is "[0]" and the other is "Raw View".
The member [0] is of type int and has the expected value, but I can't seem to get to that value in my code. This seems like a stupid question because I should be able to get to it, but can't. The latest try was the following:
int rtnCount = (int)rtn[0];
This however gave me a compiler error. How do I get to this value in my code?
Please don't do this! It's fragile, and introduces a gaping sql injection vulnerability. If you can return your count for a given table with one line of very expressive code, and no vulnerability, why make it method?
Do this instead:
DapperConnection.ExecuteScalar<int>("SELECT COUNT(*) FROM customers");
// You will be happier and live longer if you avoid dynamically constructing
// sql with string concat.
Use rtn.First() — it is an enumeration so that's the general way to get its first (and only in this case) item.
I have a SQL Server stored procedure that accepts two input parameters of datetime datatype. I want to call it from Excel VBA.
VBA doesn't have a datetime type so I've tried something like this:
Dim spCommand As ADODB.Command
Set spCommand = New ADODB.Command
spCommand.ActiveConnection = cnn
spCommand.CommandText = "myProcedureName"
spCommand.CommandType = adCmdStoredProc
spCommand.Parameters.Refresh
spCommand.Parameters(1).Value = "6/1/2016" 'DateValue("2016-06-01") + TimeValue("00:00:00")
spCommand.Parameters(2).Value = "6/1/2016" 'DateValue("2016-06-01") + TimeValue("23:59:59")
spCommand.Execute
But I get this error:
How can I solve it?
EDIT 1
After followeing what #Joe suggested, I opened my debugger and get this, but error is still there:
Use the DateSerial function:
spCommand.Parameters(1).Value = DateSerial(2016,1,6)
and, if you need it, optionally the TimeSerial function:
spCommand.Parameters(2).Value = DateSerial(2016,1,6) + TimeSerial(23,59,59)
VBA doesn't have a datetime type
Yes, it does:
Dim dtDateTime as Date
dtDateTime = DateSerial(2016,1,6) + TimeSerial(23,59,59)
UPDATE
Following your edit, I see that the Parameters collection has three items. The first is a return parameter, and the second and third are input parameters of type adDBTimeStamp.
Also the Command.NamedParameters property is false, so you probably can't use named parameters as you seem to be attempting to do in the screenshot accompanying your edit.
UPDATE 2
VBA collections are indexed starting at 1, not 0, so you should be specifying your parameters as:
spCommand.Parameters(2).Value = ...
spCommand.Parameters(3).Value = ...
I think the above is wrong. Standard VB/VBA collections are indexed, starting at 1. I believe the rationale, mistaken in my view, was that 1-based indexes are "more intuitive".
When ADO was developed, I believe Microsoft realized that 1-based collections had been a mistake, and decided to make ADO collections 0-based. This makes them inconsistent with standard collections, but "more intuitive" to, say, javascript developers. What an inconsistent mess.
If I'm right (and it's a long time since I used ADO, and I haven't tested this), then you need:
spCommand.Parameters(1).Value = ...
spCommand.Parameters(2).Value = ...
which should eliminate your 3265 error, but doesn't solve your original problem. Your debug trace appears to show that the parameters have been set to the expected values. I can only suggest you try to generate an MCVE, including a simplified version of the Stored Procedure in question.
I'm wondering if/how this is possible, if it is, I'm sure its a simple fix that I can't seem to figure out
#SqlQuery("SELECT * FROM Table WHERE column LIKE '%:thingName%'")
public Set<Things> getThings(#Bind("thingName", String thingName)
Essentially for this toy example I am trying to select a row where a column contains [any text]thingName[anyText]. When using as above, I think the quotes obscure the bound variable so it literally looks for [any text]:thingName[anyText] and not my bound variable.
Thank you in advance,
Madeline
I use concat to surround input with % signs while still using a bound variable to avoid SQL injection:
#SqlQuery("select * from atable where acolumn like concat('%',:thingName,'%')")
public Set getNames(#Bind("thingName") String thingName);
It appears to be the case that you must add the '%' percentages to the bound variable:
#SqlQuery("SELECT * FROM Table WHERE column LIKE :thingName")
public Set<Things> getThings(#Bind("thingName") String thingName); // where thingName = "%" + thingName + "%"
See also: https://groups.google.com/forum/?fromgroups#!topic/jdbi/EwUi2jAEPdk
Quote from Brian McCallister
Using the :foo binding stuff creates a prepared statement and binds in the value for name in this case. You need the % to be part of the bound value, or you need to not use bindings to a prepared statement.
Approach 1 (the safer and generally better one):
"select … from foo where name like :name" and bind the value ("%" + name)
Approach 2 (which opens you up to sql injection):
"select … from foo where name like '%' " and define("name", name) (or in sql object, (#Define("name") name) -- which puts name in as a literal in your statement.
The key thing is that the % character is part of the value you are testing against, not part of the statement.
This must be the case with LIKE while binding variables. As per JDBI doc(Here) using SQL query concatenation can solve the issue. It worked for me.
I've read thread from 2005 and people said SOQL does not support string concatenation.
Though wondering if it is supported and someone has done this.
I'm trying to concat but no luck :(
Below is APEX code trying to find record with specified email.
String myEmail = 'my#email.com';
String foo = 'SELECT emailTo__c, source__c FROM EmailLog__c
WHERE source__c = \'' +
myEmail + '\';
Database.query(foo)
Even though the record is indeed in the database, it does not query anything. Debug shows
"row(0)" which means empty is returned.
Am I doing concat wrong way?
UPDATE
I just found a way not have to add single quote. Just needed to apply same colon variable even for String that has query.
String foo = DateTime.newInstance(......);
String bar = 'SELECT id FROM SomeObject__c WHERE createdOn__c = :foo';
List<SomeObject__c> result = Database.query(bar);
System.debug(result);
This works too and is necessary if WHERE clause contains DateTime since DateTime cannot be surrounded with single quotes.
Why do you use Database.query()? Stuff will be much simpler and faster if you'll use normal queries in brackets
[SELECT emailTo__c, source__c FROM EmailLog__c WHERE source__c = :myEmail]
Not to mention that parameter binding instead of string concatenation means no need to worry about SQL injections etc.. Please consider getting used to these queries in brackets, they look weird in beginnign but will save your butt many times (mistyped field names etc).
As for actual concatenation - it works like you described it, I'm just unsure about the need to escape apostrophes. Binding the variables is safest way to go.
http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_dynamic_soql.htm
http://www.salesforce.com/us/developer/docs/api/index_Left.htm#CSHID=sforce_api_calls_soql.htm|StartTopic=Content%2Fsforce_api_calls_soql.htm|SkinName=webhelp