How can I filter input from URL param example
localhost:8080/v1/data/:id
And I want to use filter like mysql_real_escape_string param for id in Golang, I can't use ? cause this filter is dynamic, this param can be use or no, like this example
if status != "99" {
where = append(where, "vs.stats = '1'")
}
if cari != "" {
where = append(where, "(lm.title_member like '%"+cari+"%' OR " +
"lm.nama_member like '%"+cari+"%' )")
}
query := "select vs.*, lm.nama_member from volks_shift vs left join list_member lm on vs.id_m=lm.id_m where vs.id_s=?"
rows, err := s.DB.QueryContext(ctx, query, id_s)
and I want secure cari val, without use ?
There is no escape function in the database/sql package, see related issue #18478 (and it's also not nice to invoke a mysql-specific function when using a database abstraction layer).
But it is also not needed as you can still use ? in a dynamic query. Just build the query parameters dynamically together with the query, like so:
query := "SELECT vs.*, lm.nama_member" +
" FROM volks_shift vs LEFT JOIN list_member lm ON vs.id_m=lm.id_m" +
" WHERE vs.id_s=?"
params := []interface{}{id_s}
if status != "99" {
query += " AND vs.stats = '1'"
}
if cari != "" {
query += " AND (lm.title_member LIKE ? OR lm.nama_member LIKE ?)"
params = append(params, "%"+cari+"%", "%"+cari+"%")
}
rows, err := s.DB.QueryContext(ctx, query, params...)
Related
What would be the most readable way to parse a URL query string into a { 'param': 'value' } map in XSLT/XPath 3.0?
Note: this is the inverse function of the one described in Building a URL query string from a map of parameters with XPath.
Update: I neglected to mention that the function should support multi-value parameters such as a=1&a=2, and ideally parse them as an xs:string* sequence.
declare namespace map = "http://www.w3.org/2005/xpath-functions/map";
let $querystring := "a=1&b=2&c=3"
return
( tokenize($querystring, "&")
! (let $param := tokenize(., "=")
return map:entry($param[1], $param[2]) )
) => map:merge()
In order to support multiple values, you could can apply the $options parameter specifying what to do with duplicates:
declare namespace map = "http://www.w3.org/2005/xpath-functions/map";
let $querystring := "a=1&b=2&a=3"
return
( tokenize($querystring, "&")
! (let $param := tokenize(., "=")
return map:entry($param[1], $param[2]) )
) => map:merge(map:entry('duplicates', 'combine'))
2 more answers by Christian Grün:
let $querystring := "a=1&b=2&a=3"
return map:merge(
for $query in tokenize($querystring, "&")
let $param := tokenize($query, "=")
return map:entry(head($param), tail($param)),
map { 'duplicates': 'combine' }
)
One more solution (if you don’t wanna use the for clause):
let $querystring := "a=1&b=2&a=3"
return map:merge(
tokenize($querystring, "&")
! array { tokenize(., "=") }
! map:entry(.(1), .(2)),
map { 'duplicates': 'combine' }
)
let's see - substring to get ? and strip any trailing #... fragment identifier
then tokenize on [&;] (actually [;&] to get name=value pairs, which are separated by & or (less commonly) ;
then substring-before and after, or tokenize again, to get before and after the = (name value)
then uridecode the name and the value separately
let $query := substring-after($uri, '?'),
$beforefrag := substring-before($query || '#', '#')
return
tokenize($beforefrag, '[;&]')
! [substring-before(., '='), substring-after(., '=') ]
! map:entry(local:uridecode(.(1), local:uridecode(.(2))
might give us a sequene of map entries, and we can use map:merge on that.
If we know our input is plausibly encoded, we could use
declare function local:uridecode($input as xs:string?) as xs:string?
{
parse-xml-fragment(replace($input, '=(..)', '&x$1;'))
};
but a better version would just replace the two hex characters. It's really unfortunate we don't have a version of replace() that takes a function argument to be called for each matching subexpression, ala perl's e flag.```
and of course you can put that into
(...) => map:merge()
I have the following code that executes a SQL statement and looks for a result.
var sql = #"select BOQ_IMPORT_ID "
+ "from ITIS_PRJ.PRJ_BOQ_IMPORT_HEADER "
+ "where PROJECT_ID = :Projectid "
+ "order by CREATED_ON desc "
+ "fetch first 1 row only";
using (var conn = new OracleConnection(ApplicationSettings.ConnectionString))
using (var cmd = new OracleCommand(sql, conn))
{
conn.Open();
cmd.Parameters.Add(LocalCreateParameterRaw("ProjectId", projectId));
var reader = cmd.ExecuteReader();
if (reader.Read())
{
byte[] buffer = new byte[16];
reader.GetBytes(0, 0, buffer, 0, 16);
var boqId = new Guid(buffer);
return boqId;
}
return null;
}
Where LocalCreateParameterRaw is declared as:
public static OracleParameter LocalCreateParameterRaw(string name, object value)
{
OracleParameter oracleParameter = new OracleParameter();
oracleParameter.ParameterName = name;
oracleParameter.OracleDbType = OracleDbType.Raw;
oracleParameter.Size = 16;
oracleParameter.Value = value;
return oracleParameter;
}
The underlying type for 'projectId' is 'Guid'.
The if (reader.Read()) always evaluates to false, despite there being exactly one row in the table. It normally should return only one row.
Using GI Oracle Profiler I can catch the SQL sent to the db, but only once did the profiler provide a value for the :ProjectId parameter, and it was in lower case. Like that it returned no results, but as soon as I applied UPPER to that value, I get a result.
It looks like I somehow have to get my parameter into uppercase for the query to work, but I have no idea how. Yet if I do a ToString().ToUpper() on the projectId GUID, I get a parameter binding error.
VERY IMPORTANT:
I have tried removing the where clause altogether, and no longer add a parameter, so all rows in the table should be returned, yet still no results.
I don't know how, but making the SQL string a verbatim string (prefixed with #) causes the proc to work. So, it doesn't work with:
var sql = #"SELECT BOQ_IMPORT_ID "
+ "FROM ITIS_PRJ.PRJ_BOQ_IMPORT_HEADER "
+ "WHERE PROJECT_ID = :projectid "
+ "ORDER BY CREATED_ON DESC "
+ "FETCH FIRST ROW ONLY";
Yet the same command string in SQL Developer executes and returns results. When I make my SQL string verbatim, as below, I get results.
var sql = #"select BOQ_IMPORT_ID
from ITIS_PRJ.PRJ_BOQ_IMPORT_HEADER
where PROJECT_ID = :ProjectId
order by CREATED_ON desc
fetch first 1 row only";
Using a more general approach, try the following
var sql = "SELECT BOQ_IMPORT_ID "
+ "FROM ITIS_PRJ.PRJ_BOQ_IMPORT_HEADER "
+ "WHERE PROJECT_ID = :projectid "
+ "ORDER BY CREATED_ON DESC "
+ "FETCH FIRST ROW ONLY";
using (DbConnection conn = new OracleConnection(ApplicationSettings.ConnectionString))
using (DbCommand cmd = conn.CreateCommand()) {
DbParameter parameter = cmd.CreateParameter();
parameter.ParameterName = "projectid";
parameter.Value = projectId.ToString("N").ToUpper(); //<-- NOTE FORMAT USED
cmd.Parameters.Add(parameter);
cmd.CommandType = CommandType.Text;
cmd.CommandText = sql;
conn.Open();
var reader = cmd.ExecuteReader();
if (reader.Read()) {
var boqId = new Guid((byte[])reader[0]);
return boqId;
}
return null;
}
It looks like I somehow have to get my parameter into uppercase for the query to work, but I have no idea how. Yet if I do a ToString().ToUpper() on the projectId GUID, I get a parameter binding error.
Reference Guid.ToString Method
Specifier N formats it to 32 digits: 00000000000000000000000000000000
When no format is provided the default format is D which would include 32 digits separated by hyphens.
00000000-0000-0000-0000-000000000000
That would explain your binding error.
I am trying to do the following with a IQueryable expression:
(from Person p in s
select new
{
label = p.FirstName + " "
+ (string.IsNullOrWhiteSpace(p.MiddleName) ? p.MiddleName + " " : "")
+ p.LastName,
value = p.Id
}).ToList();
I am getting following error:
LINQ to Entities does not recognize the method 'Boolean
IsNullOrWhiteSpace(System.String)' method, and this method cannot be
translated into a store expression.
What is the solution for this?
String.IsNullOrWhitespace is a static function of the string object and cannot be used with Entity Framework queries, whereas p.FirstName.StartsWith("S") is a method of the entity property and can be used.
To answer your question you will have to roll your own inline. Try this:
(from Person p in s
select new
{
label = p.FirstName + " "
+ ((p.MiddleName != null && p.MiddleName != string.Empty) ? p.MiddleName + " " : "")
+ p.LastName,
value = p.Id
}).ToList();
Is there a way I can rewrite the following query to make it just one query?
try
{
var fileIds = (from f in context.SignalTo
where f.SignalFileID == 2
select new { f.GFileID }).ToList();
foreach (var id in fileIds)
{
var pp = (from p in context.ProjectFiles
where p.FileID == id.GFileID && p.ProjectID == ProjectID
select p);
if (pp != null)
{
ProjectFiles projectFile =(ProjectFiles) pp;
projectFile.MStatus = Status;
projectFile.DateLastUpdated = DateTime.Now;
context.SaveChanges();
}
}
}
You can combine the two query parts of your code into one.
You would then need to loop over the result set, making your updates. You would then call context.SaveChanges to submit all changes in one batch.
I can't tell if your existing code actually runs or compiles, but you need something like this:
Get the list of file ids you're interested in:
var fileIds = from f in context.SignalTo
where f.SignalFileID == 2
select f.GFileID;
fileIds is at this point an IQueryable where I assume T is an Int. No query has been excuted yet.
Now you can do
var pps = from p in context.ProjectFiles
where fileIds.Contains(p.FileID) && p.ProjectID == ProjectID
select p;
Still no query executed.
Then iterate over the result set
foreach( var pp in pps ) // query executed now
{
pp.MStatus = Status;
pp.DateLastUpdated = DateTime.Now;
}
context.SaveChanges(); // batch of updates executed now
I want to generate dynamic query to check manage the where clause with number of parameters available...if some parameter is null i don't want to include it in the where clause
var test = from p in _db.test
where if(str1 != null){p.test == str} else i dnt wanna check p.test
I have around 14 parameters for the where clause
need help,
thanks
You can do it in steps:
// set up the "main query"
var test = from p in _db.test select _db.test;
// if str1 is not null, add a where-condition
if(str1 != null)
{
test = test.Where(p => p.test == str);
}
In addition to #Fredrik's answer, you can also use the short-circuit rules when evaluating boolean expressions like so:
var test = from p in _db.test
where str1 == null || p.test == str1;
Edit If you have lots of strings to test, (str1, str2, etc...) then you can use the following, which will be translated to an SQL IN clause:
var strings = new List<string>();
if (str1 != null) strings.Add(str1);
if (str2 != null) strings.Add(str2);
if (str3 != null) strings.Add(str3);
...
var test = from p in _db.test
where strings.Contains(p.test);
It's even easier if your strings are already in a collection (which, if you've got 14 of them, I assume they would be...)
Consider param1 and param2 are the parameters. Your query should be as under:
string param1 = "Value1";
string param2 = "Value2";
var q = from bal in context.FxBalanceDetails
where (string.IsNullOrEmpty(param1) || bal.Column1 == param1)
&& (string.IsNullOrEmpty(param2) || bal.Column2 == param2)
select bal;
This will ensure that the where clause gets applied for the particular parameter only when it is not null.
var test =
from p in _db.test
where p.str1 != null ? p.str1 : ""
select p;
Do you check the strings against the same Field of the entity?
If so you can write something like:
var strings = new[] { "foo", "bar", "ok", "", null };
var query = dataContext.YourTable.AsQueryable();
query = strings.Where(s => !string.IsNullOrEmpty(s))
.ToList()
.Aggregate(query, (q, s) => q.Where(e => e.YourField == s));
EDIT:
The previous solution is overcomplicated:
var strings = new[] { "foo", "bar", "ok", "", null }.Where(s => !string.IsNullOrEmpty(s))
.ToList();
var query = dataContext.YourTable.Where(e => strings.Contains(e.YourField));