pg: exec_params not replacing parameters? - ruby

First time using pg gem to access postgres database. I've connected successfully and can run queries using #exec, but now building a simple query with #exec_params does not seem to be replacing parameters. I.e:
get '/databases/:db/tables/:table' do |db_name, table_name|
conn = connect(db_name)
query_result = conn.exec_params("SELECT * FROM $1;", [table_name])
end
results in #<PG::SyntaxError: ERROR: syntax error at or near "$1" LINE 1: SELECT * FROM $1; ^ >
This seems like such a simple example to get working - am I fundamentally misunderstanding how to use this method?

You can use placeholders for values, not for identifiers (such as table and column names). This is the one place where you're stuck using string interpolation to build your SQL. Of course, if you're using string wrangling for your SQL, you must be sure to properly quote/escape things; for identifiers, that means using quote_ident:
+ (Object) quote_ident(str)
Returns a string that is safe for inclusion in a SQL query as an identifier. Note: this is not a quote function for values, but for identifiers.
So you'd say something like:
table_name = conn.quote_ident(table_name)
query_result = conn.exec("SELECT * FROM #{table_name}")

Related

Gorm query formatting breaking with `%` - "expected 0 arguments, got 1"

I am getting the error "expected 0 arguments, got 1" querying postgres with the following line:
db = db.Where("LOWER(name) LIKE LOWER('%?%')", nameSearch)
Which works when I hard code values into it like so:
db = db.Where("LOWER(name) LIKE LOWER('%some-value%')")
Can anyone spot my issue here as I have many where conditions similarly formatted that work but this one, with the extra % is breaking.
After a quick look at the docs, it seems like you should add the wildcards to the nameSearch variable: as shown here
db.Where("name LIKE ?", "%jin%").Find(&users)
// SELECT * FROM users WHERE name LIKE '%jin%';
So that would be:
db.Where("LOWER(name) LIKE LOWER(?)", fmt.Sprintf("%%%s%%", nameSearch))
Of course, you can just use "%" + nameSearch + "%"

Database query using array in ruby

I'm trying to find all rows with value in array, This is my code
require 'sqlite3'
db = SQLite3::Database.new('test.sqlite')
res = db.query("SELECT w1.synsetid
FROM words w1
WHERE w1.wordid IN (?)", arr)
arr: array of strings
And I get this error
SQLite3::RangeException: bind or column index out of range
Any Help?
The second argument to query is meant to be an array of placeholder values:
- (Object) query(sql, bind_vars = [], *args)
This is a convenience method for creating a statement, binding
paramters to it, and calling execute:
The query method doesn't know that it should treat your arr array specially, it just sees one placeholder and multiple values.
I think you have to do this this hard way: build the appropriate number of placeholders and paste them into the SQL. Something like this:
placeholders = (['?'] * arr.length).join(',')
res = db.query("select ... where w1.wordid in (#{placeholders})", arr)
You know exactly what is in placeholders so you don't have to worry about using string interpolation and injection issues when building your SQL like this.
If you're using Rails already then you could also wrap your SQLite tables with ActiveRecord and then use the usual ActiveRecord interface:
words = Word.where(:wordid => arr)

ORA - 00972 : identifier too long

I am getting error (ORA - 00972 : identifier too long) while creating the view.
Please find the view statement.
create or replace view ELVW_ATM_REC_HANDOFF_1
(Rectype
,Recseq
,Record_Type
,Record_Sequence
,MESSAGE_TYPE
,PAN
,PROCESSING_CODE
,TRANSACTION_AMOUNT
,TRANSACTION_CURRENCY_CODE
,SETTLEMENT_AMOUNT
,SETTLEMENT_CURRENCY_CODE
,Billing_AMOUNT
,Billing_CURRENCY_CODE
,Transaction_DATE
,Settlement_Date
,TRACE
,REFERENCE_NUMBER
,Switch_Log_ID
,AUTHORIZATION_NUMBER
,RESPONSE_CODE
,Host_Error_Code
,TERMINAL_ID
,Acceptor_ID
,ACQUIRING_INSTITUTION_CODE
,REV_FLAG
,Original_Trace_Number
,From_Account
,To_Account)
as
select * from
(select 'FT'
,'count'
,'DT'
,rownum
,msg_type
,pan,proc_code
,txn_amt
,txn_ccy_code
,setl_amt
,setl_ccy_code
,bill_amt
,bill_ccy_code
,trans_dt_time
,setl_date
,stan,trn_ref_no
,'iso field 60'
,'isofield 38'
,resp_code
,error_code
,term_id
,'ISOmessage42'
,acq_ins_id
,decode(substr(msg_type,1,1),4,reverse(msg_type),msg_type)
,'ISOfield90'
,from_acc
,to_acc
from swtb_txn_log)
It seems error occurs at the decode function. if i comment it. its working fine. Please find the below code
create or replace view ELVW_ATM_REC_HANDOFF_1(Rectype,Recseq,Record_Type,Record_Sequence,MESSAGE_TYPE,PAN,PROCESSING_CODE,TRANSACTION_AMOUNT,TRANSACTION_CURRENCY_CODE,SETTLEMENT_AMOUNT,SETTLEMENT_CURRENCY_CODE,Billing_AMOUNT,Billing_CURRENCY_CODE,Transaction_DATE,/*Transaction_TIME,*/Settlement_Date,TRACE,REFERENCE_NUMBER,Switch_Log_ID,AUTHORIZATION_NUMBER,RESPONSE_CODE,Host_Error_Code,TERMINAL_ID,Acceptor_ID,ACQUIRING_INSTITUTION_CODE,/*REV_FLAG,*/Original_Trace_Number,From_Account,To_Account) as
select * from (select 'FT','count','DT',rownum,msg_type,pan,proc_code,txn_amt,txn_ccy_code,setl_amt,setl_ccy_code,bill_amt,bill_ccy_code,trans_dt_time,/*trans_dt_time,*/setl_date,stan,trn_ref_no,'iso field 60',
'isofield 38',resp_code,error_code,term_id,'ISOmessage42',acq_ins_id,/*decode(substr(msg_type,1,1),4,reverse(msg_type),msg_type),*/'ISOfield90',from_acc,to_acc from swtb_txn_log)
I have checked the length of the column name. Its less than 30 characters. Looking forward for your help.
Try giving an alias (that is shorter than 30 characters) to the DECODE function.
Example:
DECODE( ...stuff... ) MYALIAS
True, all of the column names in the view spec are less than thirty characters.
Howver, your view includes a inline query:
select * from ( select ...
This may be the problem. Because it may be trying to work out at identifier for DECODE() statement at that intermediate point. I say "may" because I can't reproduce this on my 10g box: defining column names for the view solves the ORA-01948.
Regardless, you can fix the problem simply by giving your DECODE() column an alias which is of an acceptable length.

Why does LIKE in SQLite3 work in this statement but = does not?

I use SQLite3 and have a table called blobs that stores content and *hash_value*.
Here is the schema:
CREATE TABLE "blobs" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
"content" blob,
"hash_value" text,
"created_at" datetime NOT NULL,
"updated_at" datetime NOT NULL
);
Now I inserted some data. that looks like this:
1|--- foo
...
|34dc86f45b3dc92b352fd45f525192c0|2012-04-09 17:02:54.219504|2012-04-09 17:02:54.219504
And I tried the following two queries:
select * from blobs where hash_value = '34dc86f45b3dc92b352fd45f525192c0';
select * from blobs where hash_value LIKE '34dc86f45b3dc92b352fd45f525192c0';
The first does not work, but the second one does. I do not understand why the = operator does not work.
I tried to break this down to a simple example where my hash is just 'abc' and = works. I mean this string is hardly too long.
EDIT
Ok I actually narrowed it down to this:
I am using Ruby to generate the hash like this Digest::MD5.hexdigest("foobar")
This generates a string like this: '3858f62230ac3c915f300c664312c63f'
My test look somewhat like this: b = Blob.new(...);b.save!;Blob.find_by_hash(b.hash)
And the find_hash is Blob.find(:all, :conditions => ["hash_value = ?", hash_value])
It works if I set the hash manually to '3858f62230ac3c915f300c664312c63f' (hardcoded string).
But if this string is generated I get the following error:
Failure/Error: Blob.find_by_hash(b.hash_value)[0].load.should == txt
ArgumentError: wrong number of arguments (0 for 1)
And I cannot query SQLite3 as stated above.
Solution
The solution is:
Instead of using Digest::MD5.hexdigest("foobar") use Digest::MD5.base64digest("foobar")
I do not know why sqlite3 has problems with hexdigest but there definitively is something fishy about this.
The difference between the two is encoding:
Digest::MD5.hexdigest("foobar").encoding #=> #<Encoding:ASCII-8BIT>
Digest::MD5.base64digest("foobar").encoding #=> #<Encoding:US-ASCII>
I don't think there's a particular reason why hexdigest has the 8bit encoding (which effectively means 'this is raw data', but that's what ruby seems to do. When the ruby sqlite3 driver sees something with the ascii-8bit encoding it binds the value to the query as a blob, rather than as text. This in turn affects how sqlite3 does the comparison (although I don't understand exactly how).
See also this question
The solution is:
Instead of using Digest::MD5.hexdigest("foobar") use Digest::MD5.base64digest("foobar").
I do not know why sqlite3 has problems with hexdigest but there definitively is something fishy about this.

postgresql / greenplum parameter binding on jdbc, why does it think its a column name?

I have a query that looks something like this:
SELECT A.A, A.B, B.A, B.C, B.D
FROM tableone A, tabletwo B
WHERE A.A = B.A
AND B.C = :p_name
When the param :p_name is set to FOO I get an error like this:
[42703] ERROR: column "FOO" does not exist
When I manually set it to include single quotes 'FOO' it works.
I've tried padding escaped single quotes. I've tried the quote_* functions. I've ried using "#" "$" and "?" params stypes. This keeps popping up.
EDIT
Eliminating as much as I can, I tried the following from the sql console in IntelliJ
SELECT * from A where A.B = :p1
SELECT * from A where A.B = ?
SELECT * from A where A.B = #p1
And adding "Foo" the parameter to in the edit box. In all three cases, I get the same problem. When I add 'Foo' to the edit box, I get the results I expect.
I also used preparedStatement and ? rather than callableStatement with :p1 and also got the same results.
What am I doing wrong?
EDIT
Removing "stringtype=unspecified" from the JDBC URL seems to make the problem go away. This is why you shouldn't just copy snippets or other peoples code and just assume it will work for you.

Resources