I have been writing queries using backticks
const firstUser = await connection
.getRepository(User)
.createQueryBuilder("user")
.where(`user.id = '${id}'`)
.getOne();
but in typeorm documentations, examples are written with colons.
const firstUser = await connection
.getRepository(User)
.createQueryBuilder("user")
.where("user.id = :id", { id: 1 })
.getOne();
So I'm wondering if there is any difference between using backticks and colons.
Any insights would be greatly appreciated.
thanks.
DO NOT USE STRING INTERPOLATION TO INSERT VALUES INTO SQL STATEMENTS
Sorry to yell, but this is important.
Read this: https://en.wikipedia.org/wiki/SQL_injection
And then this: https://xkcd.com/327/
When you do this:
.where(`user.id = '${id}'`)
Then the string is created first and then passed to the where() function. Which means if id is 123, then it's the same as:
.where(`user.id = '123'`)
Which seems fine. But what if id is 123' OR 1=1--'
You now get this:
.where(`user.id = '123' OR 1=1--'`) // Now returns ALL users!
This is called SQL injection, it's a big security issue. It's very very bad. Attackers could alter your queries and get access to data they shouldn't have access to, or change records to give themselves admin access, or all kinds of other really bad things. It's pretty close to giving everyone full read/write access to your database.
Which brings us to this:
.where("user.id = :id", { id: 1 })
To combat this, you ask TypeORM to put values in for you, this correctly escapes any value an attacker may add so the input has no executable instructions.
If id is something nefarious, then it will get turned into something like:
.where(`user.id = '123\' OR 1=1--'`) // note the backslash
// (actual query may vary based on different databases)
Here TypeORM ensures escape that the id is processed as a value, by escaping the close quote that the attacker inserted. This makes it safe to get user provided values and use them in your queries.
In conclusion, NEVER put user provided values interpolated directly into queries (really should be all values, just to be safe), and always use query parameters to ensure that values are properly escaled.
Related
I am using this library for connecting my node js application to an sqlite database. I saw its documentation for how to use prepared statements here but it is very brief and I cannot understand how to use it for my use case.
Lets say I have an sql string like this:
const sql = "INSERT INTO tbl(name) VALUES (?)"
So as per the documentation guess I should first create a statement and then use bind to populate it:
const stmt = await db.prepare(sql)
stmt.bind({? : "John"})
Is this the right way to do this? Also once I have created the Prepared statement how am I supposed to run this. All the examples mentioned in the docs are select statements, but if it is an insert statement I suppose stmt.get() or stmt.all() method are not correct as there is no result set to return here. How then am I supposed to do this?
I don't know the sqlite library too well, but the following example from the documentation performs a parameterised INSERT statement:
const result = await db.run('INSERT INTO tbl(col) VALUES (:col)', {
':col': 'something'
})
I think you're focusing on the phrase 'prepared statement' a little too much.
Instead of looking only for this exact phrase, look for any use of parameters whose values are passed separately to the main SQL string. The example above fits this: there is a parameter :col which appears in the SQL string and the value for it is provided in an object passed to db.run alongside the SQL string.
I've been trying to do some workaround on this thing but it just drives me crazy. The way I see it, it should work just fine but there is something going wrong with it... I hope I am not just really tired and missed a very easy mistake.
Anyway here is the thing. It's something pretty easy to do. an event is activated and then the algorithm below is supposed to read a certain database where I have the ids of the channels I want to send to stored, and it does one loop for each of those ids, outputting a different id on each loop,
(note: I am not doing it inside a client.on("message) event)
let channel = client.channels.get(dbresult)
channel.send(`test`);
This part was supposed to run 2 times with 2 separate numbers on the dbresult variable(since i have just 2 numbers on the database).
Now, when I run this part with just the id number alone and not the dbresult variable like this:
rows.forEach(function(row){
//let dbresult = row.newsid.toString()
let channel = client.channels.get(`0123456789`)
channel.send(`test`);
})
the script works just fine, but when I use the dbresult variable, it gives me this error
channel.send(`test`);
^
TypeError: Cannot read property 'send' of undefined
Now these are the things I've tried:
Putting a console.log(dbresult) just inside the foreach() block. It reads the ids just fine!
Making dbresult a string (as you can see) and also I've tried not converting it into a string too
Just Because I was desperate I even tried this: channel.send(${dbresult}), just in case.
Things that work:
The things I want to get triggered outside this part of the script are just fine, the script always gets activated successfully.
The script always reads each and every one of the ids of the channel. By removing the insides of "foreach" function and putting a console.log(dbresult), I saw that it outputs the different ids I want it to output.
Here is the whole script:
let db = new sqlite.Database('./databases/Serverinfo', sqlite.OPEN_READWRITE | sqlite.OPEN_CREATE);
const sql = 'SELECT newsid FROM news';
db.all(sql, function(error,rows){
if (rows.length <= 0){
return;
}
if (error){
throw error;
}
rows.forEach(function(row){
let dbresult = row.newsid.toString()
console.log(dbresult)
let channel = client.channels.get(dbresult)
channel.send(`test`);
})
db.close();
})
Any help is appriciated of course
If you are using discord.js v.12 you need to use the cache collection.
And yes, the id you want to use needs to be a string.
let channel = client.channels.cache.get(dbresult);
https://discord.js.org/#/docs/main/stable/class/ChannelManager
What you might consider doing is checking if the channel was found before you try to send something.
EDIT: The problem after updating comes from the fact that you store the channelID in your database as an INT which brings the following problem: Numeric literals with absolute values equal to 2^53 or greater are too large to be represented accurately as integers.
What that means is that it doesn't store the ID correctly because it is too large, we are talking in the Quadrillions here. This could happen either at your database or when you import the number into your code. Without knowing your DB setup I can't tell.
Example:
683328323304292410 // the actual ID of the channel
683328323304292400 // the INT that is stored
To fix this you have two options and both need to be implemented in your database.
You can either convert the datatype for the row which stores the channelID to bigINT or convert it when you import the ID source
You can store the channelID as a string in the first place. (probably the easier solution)
I have a project, where user can put in drop-down values that can be selected. One can select multiple values at a time. So, we have to store the selection and get it on edit mode.
First thought
Let's store them as comma separated in DB.
f.e.
If suggestions are A , B , C and user selects A and B, I was going to store A,B in DB and while getting back the value split it with comma.
Problem arises when user has genuine "comma" in the field, for an instance first,option & second,option. At that time joining with comma won't work.
Second thought
I can think of another option to store it in a stringified array format and parse it while getting back.
For the above instance, it would store the data as ["first,option","second,option"]. It seems to be a good (and only) option for me.
Even though I have a bit of hesitation doing so (which lead me questioning here!) because my users can access the api/DB value directly and for them it doesn't look good.
So, Is there any other way to address this issue to benefit both parties, developers and users? Thanks in advance!!
I'd suggest using a standardized format such as JSON, XML etc.
Serialize and parse and with a widely used library so all escaping of reserved / special characters is done for you. Rolling your own here will cause you problems!
Better yet, use different fields for each suggestion, this is a better design in general. As long as the number of potential fields is finite this will work, e.g. 1-10 suggestions.
If you're going down the JSON route, we can do this in JavaScript like this:
let suggestions = ['Choice A, commas are not, a problem, though punctuation is.', 'Choice B', 'Choice C'];
let json = JSON.stringify(suggestions);
// Save to DB
saveToDB(json);
let jsonFromDB = loadFromDB();
let deserializedSuggestions = JSON.parse(jsonFromDB);
console.log(deserializedSuggestions);
we use semicolon (;) for this exact use case in our current project.
So, as per your question, they will be stored in the DB as option1;option2;option3
and when we get it back from the DB we can use the split() method on it to convert it into an array of substrings.
var str = "option1;option2;option3";
var res = str.split(";");
console.log(res);
which would result in (3) ["option1", "option2", "option3"] in the console.
hope this helps.
my receipe data in firebase
![my receipe data in firebase][1]
My receipe data looks like the following
receipe/1/12: "{"itemno":"1","receipeno":"12","receipedescript..."
How can I filter all receipes where receipeno = 12 or starting with receipeno = 12, irrespective of itemno?
I have tried the following, but got no results or errors?
Also tried startAt
this.query = this.db.database.ref("receipe").orderByChild("receipeno").equalTo("12").limitToFirst(100);
BTW: this.query = this.db.database.ref("receipe") this returns all data
and this.db.database.ref("receipe/1") returns all receipe for itemno == 1.
I have updated the data to not use opaque strings.
[Updated db so as not to use opaque strings][2]
and have tried the following.
this.query = this.db.database.ref("receipe").orderByChild("itemno").equalTo("1").limitToFirst(100);
And
this.query = this.db.database.ref("receipe").orderByChild("receipeno").equalTo("r1").limitToFirst(100);
Firebase is not going to help you with deep queries. It filters and sorts at one level. Therefore, there is no way to say, "find me all the recipes with an id (or recipeno) of 12, under any node under recipes.
If you had a single level, then you would do orderByKey().equalTo("12"). Of course this will limit you to one recipe per ID.
If you are going to have multiple recipes with the number 12 and want to do this kind of querying, you need to change your database structure--essentially getting rid of the intermediate level where you currently have keys of 1, 2 etc. Most likely in this case you would use automatically generated keys of the kind that result from push, such as:
+ recipes
+ autokey1: {itemno, recipeno, recipedescription}
+ autokey2: {itemno, recipeno, recipedescription}
Then you could say
orderByChild('recipeno').equalTo('12')
This assumes, of course, as pointed out in a comment, that you are saving the data as objects, not as stringified JSON, which Firebase will never be able to query against the insides of.
This is a good case study of the notion that you should design your Firebase database structure carefully in advance to allow you to do the kinds of querying you will need to do.
By the way, this question has nothing to do whatsoever with Angular.
How can I change or update a data set's query after a parameter has been passed in BIRT report designing?
Detailing:
I've got a query that looks like this:
WHERE ?
That parameter marker can hold different values, after user input parameter, it would look like this e.g.:
WHERE column_name = 1
or
WHERE column_name = 2
or even
WHERE column_name IN (1,2)
I created a Report Parameter(RP) for that Data Set Parameter(DSP) and after trying for hours, I couldn't get to change it.
I tried:
Creating all sorts of javascript expressions on both, RP and DSP
Creating a RP that would change the value of the first RP and back to previous step
Editing the Property Binding, though I couldn't figure it out how exactly it should be done.
Just to make it clear, I'm designing a report and not integrating the runtime to an existing application.
I hope this is clear enough, I'm still editing the question so if you need more information just let me know.
Thanks
Assuming that you are on an Oracle DB (other systems may behave differently) you should be aware that a bind variable (in JDBC speech: the question mark) can replace a scalar value only, e.g. a string or a number.
But you want something like a list of numbers as input.
Thus a bind variable won't help you in this case.
Probably the easiest way to achieve what you want is this:
In your query, write:
WHERE column_name in (1) -- $REPLACE_THIS$
Note that I am using a comment in the query as a marker.
Then, in the query's beforeOpen event, modify the query text like this:
// construct a comma-separated string representation of your list
// based on your report parameter (exercise left to the reader)
// var replacement = my_to_sql_csv(params["my_report_parameter"].value);
// for demonstration use:
var replacement = "1,2";
// modify the `IN` expression inside the SQL
this.queryText = this.queryText.replaceAll("(1) -- $REPLACE_THIS$", "(" + replacement + ")";
That's it.