views:

220

answers:

1

Thank you for bobince in solving the first bugs!

How can you use *pg.escape_bytea* or *pg.escape_string* in the following?

#1 With both pg.escape_string and pg.escape_bytea

    con1.query(
            "INSERT INTO files (file, file_name) VALUES ('%s', '%s')" %
            (pg.escape_bytea(pg.espace_string(f.read())), pg.espace_string(pg.escape_bytea(f.name)))

I get the error

AttributeError: 'module' object has no attribute 'espace_string'

I tested the two escapes in the reverse order unsuccessfully too.

#2 Without pg.escape_string()

 con1.query(
                "INSERT INTO files (file, file_name) VALUES ('%s', '%s')" %
                (pg.escape_bytea(f.read()), pg.escape_bytea(f.name))
        )

I get

WARNING:  nonstandard use of \\ in a string literal
LINE 1: INSERT INTO files (file, file_name) VALUES ('%PDF-1.4\\012%\...
                                                    ^
HINT:  Use the escape string syntax for backslashes, e.g., E'\\'.
------------------------
-- Putting pdf files in

I get the following error

# 3 With only pg.escape_string

------------------------
-- Putting pdf files in
------------------------
Traceback (most recent call last):
  File "<stdin>", line 30, in <module>
  File "<stdin>", line 27, in put_pdf_files_in
  File "/usr/lib/python2.6/dist-packages/pg.py", line 313, in query
    return self.db.query(qstr)
pg.ProgrammingError: ERROR:  invalid byte sequence for encoding "UTF8": 0xc7ec
HINT:  This error can also happen if the byte sequence does not match the encoding expected by the server, which is controlled by "client_encoding".
+4  A: 

INSERT INTO files('binf','file_name') VALUES(file,file_name)

You've got the (...) sections the wrong way round, you're trying to insert the columns (file, filename) into the string literals ('binf', 'file_name'). You're also not actually inserting the contents of the variables binf and file_name into the query.

The pg module's query call does not support parameterisation. You would have to make the string yourself:

con1.query(
    "INSERT INTO files (file, file_name) VALUES ('%s', '%s')" %
    (pg.escape_string(f.read()), pg.escape_string(f.name))
)

This is assuming f is a file object; I'm not sure where file is coming from in the code above or what .read(binf) is supposed to mean. If you are using a bytea column to hold your file data you must use escape_bytea instead of escape_string.

Better than creating your own queries is letting pg do it for you with the insert method:

con1.insert('files', file= f.read(), file_name= f.name)

Alternatively, consider using the pgdb interface or one of the other DB-API-compliant interfaces that is not PostgreSQL-specific, if you ever want to consider running your app on a different database. DB-API gives you parameterisation in the execute method:

cursor.execute(
    'INSERT INTO files (file, file_name) VALUES (%(content)s, %(name)s)', 
    {'content': f.read(), 'name': f.name }
)
bobince
+1 Glad to see my uneducated response was generally pointing out to the same areas, but let me delete my response now that expert help has arrived.
mjv
I don't know about ‘expert’, I've never used pg/pgdb in my life either! :-) Last time I used Python with PostgreSQL it was a different access layer.
bobince
I get `Attribute Error` for the command `con1.insert('files', file= f.read(), file_name= f.name)`.
Masi
Oh! I guess your `con1` isn't a `pg.DB` then. To get `insert` and other convenience methods you have to wrap your connection in a `DB` (see http://www.pygresql.org/pg.html#the-db-wrapper-class). Otherwise, you'll have to use the tedious `pg.escape_string` method (or DB-API).
bobince
@bobince: I get the following error message at the moment: http://dpaste.com/123106/
Masi
You're trying to store binary data in a column marked as UTF-8-encoded text; binary streams may contain byte sequences that aren't valid as UTF-8. You'll probably need to use a column of type `bytea` for pure-binary content like PDF.
bobince
My column `file` is of the type `bytea`. It is strange that I get the UTF-8 error. My table `files` looks like http://dpaste.com/123231/
Masi
Oh dear. I'm looking at the source of `pg` now and it seems it doesn't have any support for `bytea` in the DB wrapper. Sorry about that... looks like for `bytea` columns you will have to make the INSERT string yourself using `escape_bytea`, which is a bit inconvenient. :-(
bobince
I updated my question. The current problem is now in the use of `pg.escape_bytea` because of the auto-creation of the argument `self`.
Masi
Your snippet is a SyntaxError for me, the quotes seem to be in the wrong place. For manual encoding with `escape_bytea` you would have to use `con1.query` as in the example in my answer above rather than `insert`, except using `escape_bytea` instead of `escape_string` in the first parameter (the file contents).
bobince
I run your suggestions unsuccessfully. I updated my question to reflect the recent changes.
Masi
`'module' object has no attribute 'espace_string'`: well yes, check the spelling ;-) However you shouldn't need both `escape_string` *and* `escape_bytea`; AIUI it should be bytea for the file contents and string for the filename, so #2 was nearly right.
bobince
`WARNING: nonstandard use of \\ in a string literal`: is, as it says only a warning; it should still work. PostgreSQL gets a bit shirty around backslashes because ANSI SQL says they're not escapes but in MySQL and old versions of PostgreSQL they are. Try doing as it suggests and saying `"VALUES (E'%s', '%s')" % (pg.escape_bytea(f.read()), pg.escape_string(f.name))`. See http://dbaspot.com/forums/postgresql/251026-many-warning-pg-logs-nonstandard-use-string-literalat-character.html for some discussion and alternative approaches.
bobince
(It remains to be seen whether `escape_bytea` will continue to generate backslash-escaped `E'...'`-compatible strings in future versions. This is really a terrible mess!)
bobince