Create PostgreSQL table comment using a prepared statement - sql

Is it possible to prepare a Postgres 'COMMENT ON' statement?
I have a program that allows users to create tables. I'd like to give them the option to add a description of the table's contents. As this data is coming from users, I'd like to use prepared statements.
Using Ruby and the 'pg' gem, I use the below to setup a Postgres connection and example data:
table_name = "test_shakespeare"
description = "Shakespeare's sonnets"
con = PG.connect(
:dbname => "poefy",
:user => "poefy",
:password => "poefy"
)
sql = "CREATE TABLE #{table_name} (example TEXT);"
con.exec(sql)
Here are my failed approaches, together with the errors they throw.
# ERROR: syntax error at or near "$1" (PG::SyntaxError)
sql = "COMMENT ON TABLE #{table_name} IS $1;"
con.exec(sql, [*description])
# ERROR: syntax error at or near "$1" (PG::SyntaxError)
sql = "COMMENT ON TABLE #{table_name} IS $1;"
con.prepare("comment", sql)
con.exec_prepared("comment", [*description])
# ERROR: could not determine data type of parameter $1 (PG::IndeterminateDatatype)
sql = "COMMENT ON TABLE #{table_name} IS '$1';"
con.exec(sql, [*description])
# ERROR: bind message supplies 1 parameters, but prepared statement "comment" requires 0 (PG::ProtocolViolation)
sql = "COMMENT ON TABLE #{table_name} IS '$1';"
con.prepare("comment", sql)
con.exec_prepared("comment", [*description])
It seems that preparation is not possible for this type of statement, and I should resort to SQL string manipulation. That being the case, what is the best way to go about this? The data is not sensitive or critical, and I am only really concerned with correctly represented quote marks and apostrophes.
Thanks in advance.

I assume ruby supports same statements as postgres, which does it for
Any SELECT, INSERT, UPDATE, DELETE, or VALUES statement
not COMMENT IS

It does appear that this is not possible.
So I went with the old "double all the single quotes" method.
safe_desc = description.gsub("'", "''")
con.exec "COMMENT ON TABLE #{table_name} IS '#{safe_desc}';"
This feels really hacky. But for now I'm marking it as the answer.
If there's a safer way, please let me know.

Related

DB2 PL/SQL structure, begin atomic including with query

I'm trying to use db2 pl/sql script giving a template code.
--#set delimiter !
begin atomic
for S as
<query statement that finds quests, "swaps", with a donor/donation & recipient pair>
do
<update statement that fixes Loot with the swap 'S'>;
end for;
-- handle each swap
end!
-- we're done once through
in my query statement i used something like this:
with
t1 (args) as (
...
)
...
select ...
where ... ;
in the update statement
update Loot set ... where ...
but the problem is, when i try to run the full sql code script on the database, I keep getting the message :
"An unexpected token "begin" was found following "<identifier>".
Expected tokens may include: "USER". SQLSTATE=42601 DB21007E End of file
reached while reading the command.
I want to know, how to use the proper syntax or format to include the "with queries" and also update statement to stop giving me the error. I have the "with query" working in a separate file, but when i combine both statements into the template, it would give me this error. Also as well, if I were to include triggers, which part of the code should i put it in. Thank you.
Here is an example that might help.
CREATE TABLE EG(I INT, J INT)!
INSERT INTO EG VALUES (1,1),(2,3)!
begin
for c as with w(i,u) as(values (2,5)) select i,u from w
do
update eg set j = j + c.u where i = c.i;
end for;
end
!
If this does not help your problem, please post a version of your code that we can run and which returns the error message that you are struggling with.

PDO Insert unknown sql errors

I am trying to insert into my database, and the only problem I can find is the sql not being correct somehow. I tried searching up the errors, but they are confusing at to what they are.
$pdo = new PDO("mysql:host=$dbhost;dbname=$dbvideos;", $dbusername, $dbpassword);
$sql = "INSERT INTO Video ('Channel ID', 'Name', 'VideoDescription', 'VideoLocation') VALUES (:chanID, :vidName, :vDesc, :vLoc)";
$stmt = $pdo->prepare($sql);
$stmt->execute(array(":chanID"=>$_POST['selectedChannel'], ":vidName"=>$_POST['videoName'], ":vDesc"=>$_POST['viddesc'], ":vLoc"=> $VideoLocation));
print_r($stmt->errorInfo());
With error output:
Array ( [0] => 42000 [1] => 1064 [2] => 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 'ID, Name, VideoDescription,VideoLocation) VALUES ('1', 'Testing Video', 'This is' at line 1 )
I pre-checked the variables (types match database, and they exist and with validation on previous page). The connection works fine. So SQL is the only error I can find.
I understand having no space in names- that one slipped my mind (I am usually on top of that, even when saving files). Some how removing the space and removing ' quotes made it work. (I originally used ' quoted because I saw some people use it so I though it would fix the problem).
Thank You Ryan Vincent.

How to prepare SQL statement without using where() method

Is there a way to prepare an SQL statement like that built by ActiveRecord where() method (using named placeholders):
Client.where("created_at >= :start_date AND created_at <= :end_date",
{start_date: params[:start_date], end_date: params[:end_date]})
I have to use this in CASE .. END statement after ORDER BY clause (or in SELECT to create a computed column) to protect it from SQL injection.
EDIT:
I have to retrieve all the ActiveRecord models by this query too. So can I use find_by_sql()? (trying...).
EDIT2:
find_by_sql() can't use named placeholders (:start_date in the above code example).
It's Rails 3.2.11
EDIT3:
Sorry, it can use with an Array as one parameter (find_by_sql with array format in Rails 3).
Yes, you can write / prepare anything that ActiveRecord does. Do you mean to use a direct DBI query?
I recommend you trace the SQL that ActiveRecord is generating.
Retrieving sql queries from Active-record queries in Rails 3
Tracing Rails 3 SQL queries
http://guides.rubyonrails.org/v2.3.11/debugging_rails_applications.html
See query_trace for one approach.
A tutorial on how to use Ruby DBI and prepared statements:
http://www.tutorialspoint.com/ruby/ruby_database_access.htm
Quoted directly from the tutorial:
#!/usr/bin/ruby -w
require "dbi"
begin
# connect to the MySQL server
dbh = DBI.connect("DBI:Mysql:TESTDB:localhost",
"testuser", "test123")
sth = dbh.prepare( "INSERT INTO EMPLOYEE(FIRST_NAME,
LAST_NAME,
AGE,
SEX,
INCOME)
VALUES (?, ?, ?, ?, ?)" )
sth.execute('John', 'Poul', 25, 'M', 2300)
sth.execute('Zara', 'Ali', 17, 'F', 1000)
sth.finish
dbh.commit
puts "Record has been created"
rescue DBI::DatabaseError => e
puts "An error occurred"
puts "Error code: #{e.err}"
puts "Error message: #{e.errstr}"
dbh.rollback
ensure
# disconnect from server
dbh.disconnect if dbh
end
Using find_by_sql() solved this.
But this can't be use as scoped query. (And thus cannot be chained).

Syntax error in WHERE clause near '?) AND (Date = ?)'

I am trying to send a SQL prepared statement to MySQL DB. This is what I have:
String sql1 = "SELECT idReimbursed_Funds As idReimFunds FROM reimbursedfunds Where ReimFundsName = ? AND Date = ?";
PreparedStatement pstmt1 = conn.prepareStatement(sql1);
pstmt1.setString(1, reimfund.getReimFundsName());
pstmt1.setDate(2, (Date) reimfund.getDate());
ResultSet rs1 = pstmt1.executeQuery(sql1);
while(rs1.next()){
idReimFunds = rs1.getInt("idReimFunds");
}
After googling this problem, I found solutions to use parenthesis around the question marks or the whole where clause such as:
String sql1 = "SELECT idReimbursed_Funds As idReimFunds FROM reimbursedfunds Where (ReimFundsName = ?) AND (Date = ?)";
This didn't work though. I get the same error message that is generated by my original code:
"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 '?) AND (Date = ?)' at line 1.
When I try the SQL statement in MySQL Workbench is works fine. Is there a way to use 2 where clauses with JDBC? I know in other posts people have answered that it has to be sent as two different queries, but I thought I would ask just in case someone else reads this posts and knows of a way. Thank you!
The problem (apart from the Date issue as mentioned by bgp), is the line:
ResultSet rs1 = pstmt1.executeQuery(sql1);
You are trying to execute a query string on a prepared statement, which is not allowed by the JDBC standard (MySQL should actually throw an exception instead of sending it to the server as it currently does, but the end result is the same). The documentation of Statement.executeQuery(String sql) says:
Throws:
SQLException - if a database access error occurs, this method is called on a closed Statement, the given SQL statement produces anything other than a single ResultSet object, the method is called on a PreparedStatement or CallableStatement
(emphasis mine)
The reason is that you want to execute the prepared statement, not any other query. You should call PreparedStatement.executeQuery() (so without a parameter):
ResultSet rs1 = pstmt1.executeQuery();
Pretty sure this is because "Date" is a MySQL keyword (reserved). Call the field something else or escape it with backticks, i.e. `Date`

Yii Join Table Command

I'm currently working on Yii SQL Injection. I have the following command sql command to run:
SELECT p.email, p.email_secret, p.verificationcode, r.name
FROM personal p
JOIN profile r
ON p.email='example#example.com'
I have written the following code with yii:
$connection=Yii::app()->db;
$command=$connection->createCommand();
$command->select('p.email, p.email_secret, p.verificationcode, r.name');
$command->from('personal p');
$command->join('profile r', 'p.email = r.email');
$command->where('p.email=:email', array(':email'=>'yeoh.chan1#gmail.com'));
$rows=$command->queryAll();
I would like to know where this would be vulnerable SQL Injection and if so, what would be a better approach to deal with table joinings.
Since this has no variables in it, there is no possibility for SQL injection. However, I am guessing that you are planning to pass the email address in as a parameter, and since you have the :email parameter marker you are safe.
Just a tidbit here, you don't have to repeat $command-> on every line. You can write it like this:
$connection=Yii::app()->db;
$command=$connection->createCommand();
$command->select('p.email, p.email_secret, p.verificationcode, r.name')
->from('personal p')
->join('profile r', 'p.email = r.email')
->where('p.email=:email', array(':email'=>'yeoh.chan1#gmail.com'));
$rows=$command->queryAll();
This works because all the statement clauses (except distinct) return the command object, and can be strung together. If you need distinct, you can make ->setDistinct() the last item in the chain.