Getting Bound Statement from Snowflake SQL Connection - node.js

I am trying to find a way to get the sql statements with the bound parameters to print.
I have a snowflake connector object that is similar to this:
snowflake.execute({
sqlText: 'SELECT * FROM TBL_A WHERE A B ?',
binds: [12],
fetchAsString: ['NUMBER'],
complete: function (err, stmt, rows) {
if (err) {
console.error('Failed to execute statement due to the following error: ' + stmt.getSqlText())
}
else {
// Do some stuff
}
}
})
When it errors out, I want it to show me the actual SQL text being executed:
'SELECT * FROM TBL_A WHERE A B 12'
However, the only thing I can get it to print is the sql with the parameter holder.

Related

Javascript promise to iterate/include dynamic number of Arguments

I'm using the mssql npm module (with Tedious driver) to read/write to Azure Sql database from my node Server. https://www.npmjs.com/package/mssql
All the examples I've found provide an hardcoded example of the query whether to read or write records, like this:
var insertRecordIntoTable = function (callback) {
sql.connect(dbConfig).then(pool => {
return pool.request()
.input('ID', sql.Int, 210)
.input('Name', sql.NVarChar, "John Doe")
.input('EmailAddress', sql.NVarChar, "test#test.com")
.query("INSERT INTO Accounts (ID, Name, EmailAddress) VALUES (#ID, #Name, #EmailAddress)")
}).then(result => {
console.dir(result)
callback(result);
}).catch(err => {
// ... error checks
console.log("Error occured: " + err);
callback(err);
});
}
Obviously, I'd like to write one standard method to write records to any table in the database.
Now I can fetch structure of each table and use that to find how what datatype each field should be from the key in jsonRecord and write something like this:
var insertRecordIntoTable = function (jsonRecord, tableName, callback) {
let arrKeys = jsonRecord.allKeys();
let columnNames = getCommaSeparatedColumnNames(arrKeys);
let valuePlaceholders = getValuePlaceholdersForSql(arrKeys);
sql.connect(dbConfig).then(pool => {
return pool.request()
// how do I write something like this so that dynamic number of fields and values get populated in the query inside this promise.
// I'm open to methods without promise as well.
for(let x=0; x < arrKeys.length; x++){
let key = arrKeys[x];
// .input('ID', sql.Int, 210)
.input(key, getTypeForKey(key, tableName), jsonRecord[ key ] )
}
.query("INSERT INTO " + tableName + " (" + columnNames + ") VALUES (" + valuePlaceholders + ")")
}).then(result => {
console.dir(result)
callback(result);
}).catch(err => {
// ... error checks
console.log("Error occured: " + err);
callback(err);
});
}
function getTypeForKey(key){. // looks up table schema and returns keyType }
function getCommaSeparatedColumnNames(arrKeys){ return arrKeys.join(", "); }
function getValuePlaceholdersForSql(arrKeys){ // write code to append '#' before every key and then join using comma's and return that string }
I'm sure node.js writing to SQL is a fairly common functionality and there may be better ways to achieve what I'm trying to do here. Please feel free to go a different route.
P.S. - Although I should say that I prefer mssql over Tedious package. It just seems better in functionality after going through the documentation in the last several hours.
If you want to interact with your database without creating all the queries by yourself, you can use a query builder like knex to manage the data as objects:
knex('Accounts').insert({ID: 210, Name: "John Doe", EmailAddress: "test#test.com"})
Would be similar to:
insert into `Accounts` (`EmailAddress`, `ID`, `Name`) values ('test#test.com', 210, 'John Doe')
Also I see you are checking types. If you need validation, maybe a complete ORM (I like Objection.js) would be a good choice.

query all data from 2 postgres tables using node.js

I am querying all the data from a single table in a schema called data in postgres using the following node code :
const getperson = (request, response) => {
db.query('SELECT * FROM data.person', (error, results) => {
if (error) {
throw error
}
response.status(200).json(results.rows)
})
app.get('/person', getperson)
This schema also contains other tables, I would also like to get data from those tables, put together and displayed when someone lands on /getall.
I tried changing the query to this SELECT * FROM data.person JOIN data.animal, but it returned nothing.
Or this SELECT * FROM data.person, data.animal, but this returned only the results of uncommon objects in the table, for example if the id of data.person was 1 and data.animal was 1 it would only return the id of one of the two.
The best way to do this is probably to make several SELECT * FROM table and handle it with Node…
However, if all the queries returns the same number of columns, then you can use UNION like:
SELECT * FROM tbl_name_1
UNION
SELECT * FROM tbl_name_2
...
The easiest is to concatenate the queries:
const getAll = (request, response) => {
db.query('SELECT * FROM data.person;SELECT * FROM data.animal', (error, data) => {
if (error) {
throw error;
}
response.status(200).json({people: data[0].rows, animals: data[1].rows});
})
app.get('/all', getAll);

how to insert and update data into postgresql from node js using if condition

i have to "UPDATE" data in postgresql if data is already present in database and "INSERT" i.e create a new user_Id and insert data using IF condition. i have tried with this but i am not getting output. please help me if you know .
if(data.Details){
db.query('UPDATE Details SET fullName = $2,address= $3,phone = $4 WHERE user_id = $1 RETURNING *', [query, data.Details.fullName, data.Details.address, data.Details.phone],function(err,details) {
if (err) return callback(new Error('error'));
})
}else{
db.query('INSERT INTO Details(user_id,fullName,address,phone) VALUES($1,$2,$3,$4) RETURNING *', [query, data.Details.fullName, data.Details.address, data.Details.phone],function(err,details) {
if (err) return callback(new Error('error'));
})
}
If you want to get fancy, you can also use UPSERT/ON CONFLICT in Postgres 9.5 and later.
It is designed for this exact use case, and executes as a single "instruction", rather than having to do a query check whether something exists, and another one to update or insert, both in a transaction.

PostgreSQL ERROR: relation does not exist on INSERT Statement

I am trying to have my code INSERT a row into my table called thoughtentries. It is in the public schema. I am able to run ths command while connected to my database using psql:
INSERT INTO thoughtentries VALUES('12/17/2016 14:10', 'hi');
The first column is of character type with length 17. The second column is of type text.
When I have my code attempt to INSERT using the same command above I get the error in my log:
ERROR: relation "thoughtentries" does not exist at character 13
STATEMENT: INSERT INTO thoughtentries VALUES('12/17/2016 14:11', 'hi');
I am using pg and pg-format to format the command. Here is my code to do this:
client.connect(function (err) {
if (err) throw err
app.listen(3000, function () {
console.log('listening on 3000')
})
var textToDB = format('INSERT INTO thoughtentries VALUES(%s, %s);', timestamp, "'hi'")
client.query(textToDB, function (err, result) {
if (err) {
console.log(err)
}
console.log(result)
client.end(function (err) {
if (err) throw err
})
})
})
How do I go about fixing this?
Have you verified that the table was, in fact, created in the public schema?
SELECT *
FROM information_schema.tables
WHERE table_name = 'thoughtentries';
Once you have verified that, I see two possible explanations remaining:
You are connecting to a different database by mistake. Verify, in the same session, with:
select current_database();
Your search_path setting does not include the public schema. If that's the case, you can schema-qualify the table to fix: public.thoughtentries
How does the search_path influence identifier resolution and the "current schema"
Aside: Save timestamps as data type timestamp, not character(17).
Actually, don't use character(n) at all:
Any downsides of using data type "text" for storing strings?

node-postgres prepared statement - sql injection

I am new to node-postgres and am unable to resolve this error when I try to ensure no sql injection is possible with my prepared statement.
Here is a snippet of the code
// the prepared statement
var preparedstatement = client.query({
text: "select ST_AsText(ST_Transform(geodata,4326)) from table_name where ST_Contains(ST_GeomFromText($1,4326),table_name.geodata)",
values: ["POINT(Lat Long)"],
name: 'where'
});
// the query
var queryresult = client.query({name: 'where', values: [msg]},["'; DROP TABLE user;"], function(err) {
if (err) {
socket.emit('query error', String(err));
}
});
Whenever I enter the geodata (as a message from the client using socket.io), the socket.emit returns an error saying
Invalid geometry
However the code works fine when I remove ["'; DROP TABLE user;"], from the code i.e.
// the query
var queryresult = client.query({name: 'where', values: [msg]}, function(err) {
if (err) {
socket.emit('query error', String(err));
}
});
(above) works perfectly. Any help in helping me understand what I am doing wrong here would be great.
var preparedstatement = client.query({
text: "select ST_AsText(ST_Transform(geodata,4326)) from table_name where ST_Contains(ST_GeomFromText($1,4326),table_name.geodata)",
values: ["POINT(Lat Long)"],
name: 'where'
});
results to SQL smth like
prepare "where" as
select ST_AsText(ST_Transform(geodata,4326))
from table_name
where ST_Contains(ST_GeomFromText($1,4326),table_name.geodata);
execute "where" (POINT(Lat Long));
which probably could work if lat nad long are table_name attributes
next:
var queryresult = client.query({name: 'where', values: [msg]}, function(err) {
if (err) {
socket.emit('query error', String(err));
}
});
does:
execute "where" (msg_value);
which probably works if they are of compatible data type
and finally:
var queryresult = client.query({name: 'where', values: [msg]},["'; DROP TABLE user;"], function(err) {
if (err) {
socket.emit('query error', String(err));
}
});
runs SQL:
execute "where" ('''; DROP TABLE user;');
which gives an error as this text is not a valid geometry...
noticable here that lient.query(text QUERY,array VALUES) here is used as lient.query(object QUERY,array VALUES) and VALUES overcame such in QUERY object, this your [msg] was "ignored"...
NB
checking if prepared statements are prune to such sql injection is pointless as this feature was implemented with idea to be safe for such injections. For example even if you would use data type text (to avoid type mismatch) and try to inject semicolon and drop statement, prepared statement would treat injection as literal value and thsus be safe. eg:
var preparedstatement = client.query({
text: "select $1::text resulting_att",
values: ['some default'],
name: 'ps_name'}
);
var queryresult = client.query({name: 'ps_name'},["'; DROP TABLE user;"], function(err,res) {
console.log(err,res.rows)
client.end()
});
logs:
null [ anonymous { resulting_att: '\'; DROP TABLE user;' } ]
and not tries to drop anything.

Resources