Parameterizing postgis geometry query - postgresql

I'm trying to query whether any of a set of polygons (passed in at runtime) intersects with a set of polygons stored in the database in the "enclosing_polygons" field, which is a MultiPolygonField.
Here is an example of the query:
select * from my_table where field1 = any (?) and field2 = any (?) and (
ST_Intersects(ST_GeometryFromText('POLYGON((? ?, ? ?, ? ?, ? ?, ? ?))'), enclosing_polygons) or
ST_Intersects(ST_GeometryFromText('POLYGON((? ?, ? ?, ? ?, ? ?, ? ?))'), enclosing_polygons))
and detection_type = 0 order by confidence desc limit 2000
The query works fine with hardcoded values, but when I try to parameterize it, Postgres does not seem to recognize the ? placehoders for the polygon points as parameters when I try to populate them.
When I set the first two parameters (for field1 and field2), these JDBC statements succeed:
statement.setArray(1, array1)
statement.setArray(2, array2)
However, if I try to set any parameters beyond these first two, they fail. This statement:
statement.setDouble(3, point1x)
fails with the following error:
The column index is out of range: 3, number of columns: 2.
Why does Postgres not recognize these ?s in the POLYGON constructor as query parameters?
How can I make this work?

It is up to your driver to implement the ? placeholders, PostgreSQL never sees them. In your driver, like in almost all drivers, the question marks occurring inside the single quotes are just literal question marks, not place holders.
You probably need to construct the POLYGON((...)) string yourself, then pass that whole string into the query as a single placeholder. So that part of the query would look like ST_Intersects(ST_GeometryFromText(?), enclosing_polygons)
There are alternatives but they mostly just move the problem around without directly solving it. If you really want to just use plain question marks with each bound to one number, you could replace the ST_GeometryFromText function with something like:
st_makepolygon(st_makeline(array[st_makepoint(?,?),st_makepoint(?,?),st_makepoint(?,?),st_makepoint(?,?),st_makepoint(?,?)]))

Related

PostgreSQL, allow to filter by not existing fields

I'm using a PostgreSQL with a Go driver. Sometimes I need to query not existing fields, just to check - maybe something exists in a DB. Before querying I can't tell whether that field exists. Example:
where size=10 or length=10
By default I get an error column "length" does not exist, however, the size column could exist and I could get some results.
Is it possible to handle such cases to return what is possible?
EDIT:
Yes, I could get all the existing columns first. But the initial queries can be rather complex and not created by me directly, I can only modify them.
That means the query can be simple like the previous example and can be much more complex like this:
WHERE size=10 OR (length=10 AND n='example') OR (c BETWEEN 1 and 5 AND p='Mars')
If missing columns are length and c - does that mean I have to parse the SQL, split it by OR (or other operators), check every part of the query, then remove any part with missing columns - and in the end to generate a new SQL query?
Any easier way?
I would try to check within information schema first
"select column_name from INFORMATION_SCHEMA.COLUMNS where table_name ='table_name';"
And then based on result do query
Why don't you get a list of columns that are in the table first? Like this
select column_name
from information_schema.columns
where table_name = 'table_name' and (column_name = 'size' or column_name = 'length');
The result will be the columns that exist.
There is no way to do what you want, except for constructing an SQL string from the list of available columns, which can be got by querying information_schema.columns.
SQL statements are parsed before they are executed, and there is no conditional compilation or no short-circuiting, so you get an error if a non-existing column is referenced.

Is it possible to specify the column list for an INSERT statement in the SELECT statement?

I have to produce a dynamically generated T-SQL script that inserts records into various tables. I've done a bunch of searching and testing but can't seem to find the path I'm looking for.
I know that the following is valid SQL:
INSERT INTO [MyTable] ( [Col1], [Col2], [Col3] )
SELECT N'Val1', N'Val2', N'Val3';
But, is it at all possible to write something akin to this:
INSERT INTO [MyTable]
SELECT [Col1] = N'Val1', [Col2] = N'Val2', [Col3] = N'Val3';
By having the columns in the select statement, I'm able to do it all at once vs writing 2 separate lines. Obviously my idea doesn't work, I'm trying to figure out whether something similar is possible or I need to stick with the first one.
Much appreciated.
Best practice for insert statements is to specify the columns list in the insert clause, and for very good reasons:
It's far more readable. You know exactly what value goes into what column.
You don't have to provide values to nullable \ default valued columns.
You're not bound to the order of the columns in the table.
In case a column is added to the table, your insert statement might not break (It will if the newly added column is not nullable and doesn't have a default value).
In some cases, SQL Server demands you specify the columns list explicitly, like when identity_insert is set to on.
And in any case, the column names or aliases in the select clause of the insert...select statement does not have any effect as to what target columns the value column should go to. values are directed to target based only on their location in the statement.

Capturing DBIC exception to prevent script from dying

I'm running a perl script to update a currently working database with new datasets. Basically, the script receives molecule information as plain text (MDL if you are interested) and performs several chemical properties calculations through a bunch of third party softwares called via system.
The script have never had any problems processing data but the last dataset seems to have some molecules (or at least one, for what it's worth) for which some of the properties make no sense and I end up having truncated data insertions, which lastly causes a DBIC exception. Namely:
DBIx::Class::Storage::DBI::_dbh_execute(): DBI Exception: DBD::mysql::st execute failed: Column 'inchi' cannot be null [for Statement "INSERT INTO moldata ( formula, hba, hbd, inchi, inchikey, mol_id, pm, psa, ro3pass, ro5vio, rtb, smiles, xlogp3aa) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" with ParamValues: 0='I', 1='0', 2='0', 3=undef, 4='XMBWDFGMSWQBCA-YPZZEJLDSA-M', 5=936934, 6='125.00', 7='0', 8=6, 9=0, 10='0', 11='[125I-]', 12='0.86']
At this point, the program just dies. I can surely do some workarounds to avoid getting "undefs" in the inserts, but I'd like DBIC to be able to handle them and continue with the inserts while ignoring (and maybe warn me about them later) the bad ones.
What would be the right way to implement a try/catch scenario in perl for DBIC transactions?
Thanks!

Postgres HStore - Updating existing columns with values from Hstore

I am trying to move data from a HStore to a Column using the following query
update mytable set "height" = tags->"height" ,
"building:levels" = tags->"building:levels", "type" = tags->"type",
"building:part" = tags->"building:part"
Where ( tags->"building:levels" <>'' or "tags"->"height" <> ''
or "tags"->"type" <> '' or "tags"->"building:part" <> '' );
The idea was to try and speed the query up by testing for non null values in the HStore. (This is a very large database)
After two days of the query running, I am sure there must be a better way. This is my first attempt at moving data form HStore into a Column.
I can see populate_record in the documentation, but cannot figure out how to use it to just get the hstore tags I need to the correct columns.
Is my original syntax correct and is there any way I can do it faster using populate_record and if so, what should the query look like?
Many Thanks

Scala query generating invalid SQL

I'm using scalaquery to connect to both oracle and postgres servers.
This behaviour is occuring for both Oracle and Postgres, but it's only valid (and still incorrect) SQL in Postgres.
At some point, I'm running a query in scalaquery of the form:
row.foo.bind == parameter.foo || row.foo inSetBind parameter.foo.children
Parameter is a trait, which is known to have a foo in it.
The problem here is that out of the ~100 queries run, scala-query only generates the correct SQL once, of the form
...
WHERE row.foo = ? or row.foo in (?, ?, ?, ?, ?)
...
Most of the time it instead generates
...
WHERE row.foo = ? or false
...
Why is this happening inconsistently, is it a bug (I assume it is), and how do I work around it?
It turns out that the query was looking at an empty set, because parameter.foo had no childen in most cases.
Given that WHERE row.foo IN () is not valid SQL, it was instead written out as false.
This still leaves the issue of false being generated despite the code being targeted at oracle DB, but the root cause has now been cleared up.