How to pass a string literal parameter to a peewee fn call - peewee

I've got a issue passing a string literal parameter to a SQL function using peewee's fn construct. I've got an object defined as:
class User(BaseModel):
computingID = CharField()
firstName = CharField()
lastName = CharField()
role = ForeignKeyField(Role)
lastLogin = DateTimeField()
class Meta:
database = database
I'm attempting to use the mySQL timestampdiff function in a select to get the number of days since the last login. The query should look something like this:
SELECT t1.`id`, t1.`computingID`, t1.`firstName`, t1.`lastName`, t1.`role_id`, t1.`lastLogin`, timestampdiff(day, t1.`lastLogin`, now()) AS daysSinceLastLogin FROM `user` AS t1
Here's the python peewee code I'm trying to use:
bob = User.select(User, fn.timestampdiff('day', User.lastLogin, fn.now()).alias('daysSinceLastLogin'))
result = bob[0].daysSinceLastLogin
But when I execute this code, I get an error:
ProgrammingError: (1064, u"You have an error in your SQL syntax; check
the manual that corresponds to your MySQL server version for the right
syntax to use near ''day', t1.lastLogin, now()) AS
daysSinceLastLogin FROM user AS t1' at line 1")
Judging from this message, it looks like the quote marks around the 'day' parameter are being retained in the SQL that peewee is generating. And mySQL doesn't like quotes around the parameter. I obviously can't leave off the quotes in the python code, so can someone tell me what I'm doing wrong please?
Update: I have my query working as intended by using the SQL() peewee command to add the DAY parameter, sans quote marks:
User.select(User, fn.timestampdiff(SQL('day'), User.lastLogin, fn.now()).alias('daysSinceLastLogin'))
But I'm not sure why I had to use SQL() in this situation. Am I missing anything, or is this the right answer?

Is there a reason you need to use an SQL function to do this?
In part because I'm not very comfortable with SQL functions, I would probably do something like this:
import datetime as dt
bob = user.get(User = "Bob") #or however you want to get the User instance
daysSinceLastLogin = (dt.datetime.now() - bob.lastLogin).days

Related

SPLIT_PART function used in a select statement in Snowflake Stored procedure returns null value

SPLIT_PART function used in a select statement in Snowflake Stored procedure returns null value.
var stmt5 = snowflake.CreateStatement({sqltext:`Select SPLIT_PART(SPLIT_PART(:1,''/'',2),''.gz'',1)`,binds:[stagename]});
var queryText=stmt5.getSqlText();
var x=stmt5.execute();
x.next();
stagename is retrieved from the List #my_stage command result and the result of the Split Part is used in the Copy Command for inserting records into a snowflake table.
If somebody responds will share the code thru an email to help me fix the issue. Thanks in advance.
You're using JavaScript with backticks, so there's no need to escape the single quotes. By doing so, it actually looks like an empty string. This is how it would look in your SQL history tab:
Select SPLIT_PART(SPLIT_PART(:1,''/'',2),''.gz'',1)
If you put a file name in and try that:
Select SPLIT_PART(SPLIT_PART('mypath/myfile.gz',''/'',2),''.gz'',1)
This doesn't actually return a null value. It's a syntax error, so maybe this execute call is in a try/catch block. That would return a null value when you try to use .next(),
Try it with the quotes single:
var stmt5 = snowflake.CreateStatement({sqltext:`Select SPLIT_PART(SPLIT_PART(:1,'/',2),'.gz',1)`,binds:[stagename]});

How to prevent SQL injection in Snowflake after using LIKE keyword?

I use the following function for the connection with the Snowflake. For SQL injection prevention I use paramstyle = "numeric".
import snowflake.connector
def get_snowflake_connector(
user: str,
password: str,
account: str,
warehouse: str,
role: str,
):
params = {
"user": user,
"password": password,
"account": account,
"warehouse": warehouse,
"role": role,
}
snowflake.connector.paramstyle = "numeric"
conn = snowflake.connector.connect(**params)
return conn
So, when I use returned connection object conn I can execute queries over Snowflake. For example:
conn.cursor().execute(query, params)
Where query is for example:
query = """
SELECT *
FROM IDENTIFIER(:1)
LIMIT :2;
"""
and params are string replacements for places where we have :1 and :2. In this case, for example, params=("DATABASE_NAME.SCHEMA_NAME.TABLE_NAME", 100000).
So, the result is like this:
conn.cursor().execute(
"SELECT * FROM IDENTIFIER(:1) LIMIT :2;", params=("DATABASE_NAME.SCHEMA_NAME.TABLE_NAME", 100000)
)
And this is working. I use IDENTIFIER(:N) for the objects and without it, I use :N for literals.
But the problem appears when I use LIKE keyword. For example, query = "SHOW USERS LIKE 'some_user'".
What should I use instead of 'some_user'? IDENTIFIER(:1) doesn't work because it is not an object, but also :1 doesn't work. And I wonder what is the solution to prevent this from SQL injection?
There is a workaround but it uses two queries instead of one.
One could use:
conn.cursor().execute('SHOW USERS')
conn.cursor().execute('SELECT * FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()) WHERE "name" = :1', ('some_user',))
This way SQL injection is prevented, but this is more time-consuming.
I don't think "paramstyle" has anything to do with the problem, but check the docs: "The percent character (“%”) is both a wildcard character for SQL LIKE and a format binding character for Python. If you use format binding, and if your SQL command contains the percent character, you might need to escape the percent character". You might also have to double-up on your quotes.
This does not help with the SQL injection question though. Snowflake has no equivalent to Oracle's dbms_assert package for a start. Proceed with extreme caution: sanity check the various binds first, at the very least.
This could be the answer:
select * from snowflake.account_usage.users where name = 'slobokv83';
and with SQL injection prevention:
conn.cursor().execute('select * from snowflake.account_usage.users where name = :1', ('slobokv83',))
The same goes for "snowflake.account_usage.roles":
conn.cursor().execute('select * from snowflake.account_usage.roles where name = :1', ('role_name',))
and for "snowflake.account_usage.databases" column "name" is "database_name":
conn.cursor().execute('select * from snowflake.account_usage.databases where database_name = :1', ('database_name',))
However, this is more time-consuming than simple
SHOW USERS LIKE 'slobokv83'

c++ builder: getting values via ADOQuery using SELECT

The question is as for delphi coders as for c++ builder coders, cuz I'm using the same components.
I'm trying to fill labels on the form by the data from database. I do a SELECT query via TADOQuery. But when I try to get a result, I always get an error like "ADOQuery1: Field 'count' not found".
'id' passed to the function is an autoincrement field value, which is EXACTLY exists in database (it was got via DBLookupComboBox). Also, executing the query manually to show result in DBGrid is successfull.
Querying without parameters and writing 'id' value to query string fails too.
What's the problem? Here's the code.
void TSellForm::LoadData(int id) {
TADOQuery* q = DataModule1->ADOQuery1;
q->Active = false;
try
{
q->SQL->Text = "select * from drugs where(id=:id)";
q->Parameters->ParamByName("id")->Value = IntToStr(id);
q->ExecSQL();
this->LabelAvail->Caption = q->FieldByName("count")->Value;
}
catch (Exception* e) {
MessageBox(NULL, PChar(WideString(e->Message)),
L"Exception", MB_OK|MB_ICONWARNING);
}
q->SQL->Clear();
}
ExecSQL is only used for SQL statements that don't return a recordset, and to determine the results you use RowsAffected.
For SELECT statements (which return a recordset), you use Open or set Active to true.
Also, count is a reserved word in most SQL dialects (as in SELECT Count(*) FROM ..., so if you have a column with that name you're going to need to escape it, typically by using either [] or double-quotes around it or by aliasing it in the SELECT itself.
ADOQuery1->Close();
ADOQuery1->SQL->Text= "SELECT * FROM reportTble WHERE (firstName =:firstName) " ;
ADOQuery1->Parameters->ParamByName("firstName")->Value = textBox->Text ;
ADOQuery1->Open();
This is how you can use ADOQuery

Dapper parameters not working?

Dapper 1.34 (on earlier Dapper ver like 1.1x this worked fine).
db.Query(#"Select [whatever] from #TableName Where [PREFIX]='#Prefix' order by [something] desc",
new { TableName = tableName, Prefix = prefix })
Error: System.Data.SqlClient.SqlException (0x80131904): Must declare the table variable "#TableName".
I get same error trying to define DynamicParameters and passing those.
=======
I am currently doing string substitution {%1} .. but that does not seem acceptable ...
Can I please get a sample, also looking at test class for dapper I cant see it running, maybe something wrong with my project setup ?
No, that has never worked fine, due to how SQL works:
table names cannot be parameterized, and dapper has never offered this; that could work if you pass in a DataTable as a table-valued-parameter, though - which dapper does support - but I don't think this is what you are after
'#Prefix' is a string literal; you just mean #Prefix (no single quotes)

CodeIgniter SQLite where field IN array condition

I'm having some trouble trying to set a 'WHERE field IN ...' clause in CodeIgniter using SQLite. I got an array of all where clause conditions called $conditions, and added the WHERE IN clause in this way:
$this->browse_model->conditions['username IN'] = "(SELECT like_to FROM likes WHERE like_from = '".$this->user->username."')";
and inside of my browse_model I use the following code to run the query:
$get = $this->db->get_where('users', $this->conditions, 6, $_SESSION['browse_page']*6);
but somehow when I use the condition I wrote above it is giving me the following error:
Fatal error: Call to a member function execute() on a non-object in
../www/system/database/drivers/pdo/pdo_driver.php on line 193
As far as I'm concerned the 'field IN array' statement is allowed in SQLite too, so I really don't know why this isn't working. Does anyone know how to make this work?
Thanks in advance!
Greets,
Skyfe.
EDIT: Tried setting the condition in the following way and didn't get an error but neither any results:
$this->browse_model->conditions['username'] = "IN (SELECT like_to FROM likes WHERE like_from = '".$this->user->username."')";
So I guess that's still not the correct way to do it..
EDIT2: 'Fixed' it, somehow it didn't interpetate the field => value way of notating the where clause correctly for the IN statement, so defined it in a custom string:
$this->browse_model->custom_condition = username IN (SELECT like_to FROM likes WHERE like_from = '".$this->user->username."')
Their is some problem in formatting IN clause,
SELECT * FROM users WHERE gender = 'f' AND gender_preference = 'm' AND username IN (SELECT like_to FROM likes WHERE like_from = 'testtest')

Resources