UndefinedFunction: ERROR: function st_distance(geography, geometry, numeric) does not exist - postgresql

I wanna to order by distance, but I got the error
UndefinedFunction: ERROR: function st_distance(geography, geometry, numeric) does not exist
by .order("ST_Distance(lonlat, ST_Geomfromtext('#{point}'), #{radius}) ")
If I removed the above line , it works fine.
What's wrong with it ?
model
scope :nearby, lambda { |radius_in_km, lon, lat|
point = GEOG_FACTORY.point(lon, lat)
radius = radius_in_km.to_f*1000
where("ST_DWithin(lonlat, ST_GeomFromText('#{point}'), #{radius} ) ")
.order("ST_Distance(lonlat, ST_Geomfromtext('#{point}'), #{radius}) ")
}
more detail error log
PG::UndefinedFunction: ERROR: function st_distance(geography, geometry, numeric) does not exist
LINE 1: ...4028 6.530438999999999)'), 100000.0 ) ) ORDER BY ST_Distanc...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
: SELECT "weather_logs".* FROM "weather_logs" WHERE (ST_DWithin(lonlat, ST_GeomFromText('POINT (101.3034028 6.530438999999999)'), 100000.0 ) ) ORDER BY ST_Distance(lonlat, ST_Geomfromtext('POINT (101.3034028 6.530438999999999)'), 100000.0) , "weather_logs"."datetime" ASC LIMIT 20000
Completed 200 OK in 161ms (Views: 0.2ms | ActiveRecord: 5.4ms)

You are mixing geography and geometry types, that is what the error message means. If you look at the ST_DWithin docs, you will see that the signature are ST_DWithin (geometry, geometry, distance) or ST_DWithin (geography, geography, distance).
I don't know much about Ruby, so am not sure if there is a GEOM_Factory equivalent of the GEO_Factory you have used, but if you use ST_GeogFromText instead of ST_GeomFromText in your where and order by clauses, then you will be dealing with two geographies, which should solve your issue.
As your coordinates are in lat/lon, 4326, it is appropriate to use the geography datatype. If you want to know more about the practicalities of geometry vs geography, see this gis.stackexchange question.

Related

DB2 SQL Error: SQLCODE=-302 while executing prepared statement

I have a SQL query which takes user inputs hence security flaw is present.
The existing query is:
SELECT BUS_NM, STR_ADDR_1, CITY_NM, STATE_CD, POSTAL_CD, COUNTRY_CD,
BUS_PHONE_NB,PEG_ACCOUNT_ID, GDN_ALERT_ID, GBIN, GDN_MON_REF_NB,
ALERT_DT, ALERT_TYPE, ALERT_DESC,ALERT_PRIORITY
FROM ( SELECT A.BUS_NM, AE.STR_ADDR_1, A.CITY_NM, A.STATE_CD, A.POSTAL_CD,
CC.COUNTRY_CD, A.BUS_PHONE_NB, A.PEG_ACCOUNT_ID, 'I' ||
LPAD(INTL_ALERT_DTL_ID, 9,'0') GDN_ALERT_ID,
LPAD(IA.GBIN, 9,'0') GBIN, IA.GDN_MON_REF_NB,
DATE(IAD.ALERT_TS) ALERT_DT,
XMLCAST(XMLQUERY('$A/alertTypeConfig/biqCode/text()' passing
IAC.INTL_ALERT_TYPE_CONFIG as "A") AS CHAR(4)) ALERT_TYPE,
, ROW_NUMBER() OVER () AS "RN"
FROM ACCOUNT A, Other tables
WHERE IA.GDN_MON_REF_NB = '100'
AND A.PEG_ACCOUNT_ID = IAAR.PEG_ACCOUNT_ID
AND CC.COUNTRY_CD = A.COUNTRY_ISO3_CD
ORDER BY IA.INTL_ALERT_ID ASC )
WHERE ALERT_TYPE IN (" +TriggerType+ ");
I changed it to accept TriggerType from setString like:
SELECT BUS_NM, STR_ADDR_1, CITY_NM, STATE_CD, POSTAL_CD, COUNTRY_CD,
BUS_PHONE_NB,PEG_ACCOUNT_ID, GDN_ALERT_ID, GBIN, GDN_MON_REF_NB,
ALERT_DT, ALERT_TYPE, ALERT_DESC,ALERT_PRIORITY
FROM ( SELECT A.BUS_NM, AE.STR_ADDR_1, A.CITY_NM, A.STATE_CD, A.POSTAL_CD,
CC.COUNTRY_CD, A.BUS_PHONE_NB, A.PEG_ACCOUNT_ID,
'I' || LPAD(INTL_ALERT_DTL_ID, 9,'0') GDN_ALERT_ID,
LPAD(IA.GBIN, 9,'0') GBIN, IA.GDN_MON_REF_NB,
DATE(IAD.ALERT_TS) ALERT_DT,
XMLCAST(XMLQUERY('$A/alertTypeConfig/biqCode/text()' passing
IAC.INTL_ALERT_TYPE_CONFIG as "A") AS CHAR(4)) ALERT_TYPE,
ROW_NUMBER() OVER () AS "RN"
FROM ACCOUNT A, other tables
WHERE IA.GDN_MON_REF_NB = '100'
AND A.PEG_ACCOUNT_ID = IAAR.PEG_ACCOUNT_ID
AND CC.COUNTRY_CD = A.COUNTRY_ISO3_CD
ORDER BY IA.INTL_ALERT_ID ASC )
WHERE ALERT_TYPE IN (?);
Setting trigger type as below:
if (StringUtils.isNotBlank(request.getTriggerType())) {
preparedStatement.setString(1, triggerType != null ? triggerType.toString() : "");
}
Getting error as
Caused by: com.ibm.db2.jcc.am.SqlDataException: DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null, DRIVER=4.19.26
The -302 SQLCODE indicates a conversion error of some sort.
SQLSTATE 22001 narrows that down a bit by telling us that you are trying to force a big string into a small variable. Given the limited information in your question, I am guessing it is the XMLCAST that is the culprit.
DB2 won't jam 30 pounds of crap into a 4 pound bag so to speak, it gives you an error. Maybe giving XML some extra room in the cast might be a help. If you need to make sure it ends up being only 4 characters long, you could explicitly do a LEFT(XMLCAST( ... AS VARCHAR(64)), 4). That way the XMLCAST has the space it needs, but you cut it back to fit your variable on the fetch.
The other thing could be that the variable being passed to the parameter marker is too long. DB2 will guess the type and length based on the length of ALERT_TYPE. Note that you can only pass a single value through a parameter marker. If you pass a comma separated list, it will not behave as expected (unless you expect ALERT_TYPE to also contain a comma separated list). If you are getting the comma separated list from a table, you can use a sub-select instead.
Wrong IN predicate use with a parameter.
Do not expect that IN ('AAAA, M250, ABCD') (as you try to do passing a comma-separated string as a single parameter) works as IN ('AAAA', 'M250', 'ABCD') (as you need). These predicates are not equivalent.
You need some "string tokenizer", if you want to pass such a comma-separated string like below.
select t.*
from
(
select XMLCAST(XMLQUERY('$A/alertTypeConfig/biqCode/text()' passing IAC.INTL_ALERT_TYPE_CONFIG as "A") AS CHAR(4)) ALERT_TYPE
from table(values xmlparse(document '<alertTypeConfig><biqCode>M250, really big code</biqCode></alertTypeConfig>')) IAC(INTL_ALERT_TYPE_CONFIG)
) t
--WHERE ALERT_TYPE IN ('AAAA, M250, ABCD')
join xmltable('for $id in tokenize($s, ",\s?") return <i>{string($id)}</i>'
passing cast('AAA, M250 , ABCD' as varchar(200)) as "s"
columns token varchar(200) path '.') x on x.token=t.ALERT_TYPE
;
Run the statement as is. Then you may uncomment the string with WHERE clause and comment out the rest to see what you try to do.
P.S.:
The error you get is probably because you don't specify the data type of the parameter (you don't use something like IN (cast(? as varchar(xxx))), and db2 compiler assumes that its length is equal to the length of the ALERT_TYPE expression (4 bytes).

How to use st_Line_Locate_Point() with a MULTILINESTRING convertion in PostGIS?

I am trying to get the index position of a POINT in a MULTILINESTRING.
Here is the whole query I'm stuck with :
SELECT req.id, (dp).geom, netgeo_point_tech.id, ST_Line_Locate_Point(st_lineMerge(geom_cable), (dp).geom)
FROM (SELECT id, ST_DumpPoints(geom) as dp, geom as geom_cable FROM netgeo_cable_test ) as req
JOIN netgeo_point_tech ON ST_dwithin(netgeo_point_tech.geom, (dp).geom, 1)
ORDER BY req.id, (dp).path [ 1] ASC
The error I get is : line_locate_point : 1st arg isnt a line.
The error is due to the return of st_lineMerge() function that is returning LINESTRING but also MULTILINESTRING.
I don't get this. st_lineMerge() is supposed to return only LINESTRING.ST_LineMerge()
When I jsut try a simple query like this :
select st_astext(st_linemerge(geom)) from netgeo_cable_test
The output is :
)
I want to learn from this, so, if possible, explain to me what I'm doing wrong here, or if my approach is lacking insight.
Thanks to #JGH for the suggestion to use ST_Dump I came up with this function:
create or replace function MultiLineLocatePoint(line geometry, point geometry) returns numeric as $$
select (base + extra) / ST_Length(line)
from (
select
sum(ST_Length(l.geom)) over (order by l.path) - ST_Length(l.geom) base,
ST_LineLocatePoint(l.geom, point) * ST_Length(l.geom) extra,
ST_Distance(l.geom, point) dist
from ST_Dump(line) l
) points
order by dist
limit 1;
$$ language SQL;

PostgreSQL ERROR: invalid input syntax for integer: "1e+06"

The full error message is:
ERROR: invalid input syntax for integer: "1e+06"
SQL state: 22P02
Context: In PL/R function sample
The query I'm using is:
WITH a as
(
SELECT a.tract_id_alias,
array_agg(a.pgid ORDER BY a.pgid) as pgids,
array_agg(a.sample_weight_geo ORDER BY a.pgid) as block_weights
FROM results_20161109.block_microdata_res_joined a
WHERE a.tract_id_alias in (66772, 66773, 66785, 66802, 66805, 66806, 66813)
AND a.bldg_count_res > 0
GROUP BY a.tract_id_alias
)
SELECT NULL::INTEGER agent_id,
a.tract_id_alias,
b.year,
unnest(shared.sample(a.pgids,
b.n_agents,
1 * b.year,
True,
a.block_weights)
) as pgid
FROM a
LEFT JOIN results_20161109.initial_agent_count_by_tract_res_11 b
ON a.tract_id_alias = b.tract_id_alias
ORDER BY b.year, a.tract_id_alias, pgid;
And the shared.sample function I'm using is:
CREATE OR REPLACE FUNCTION shared.sample(ids bigint[], size integer, seed integer DEFAULT 1, with_replacement boolean DEFAULT false, probabilities numeric[] DEFAULT NULL::numeric[])
RETURNS integer[] AS
$BODY$
set.seed(seed)
if (length(ids) == 1) {
s = rep(ids,size)
} else {
s = sample(ids,size, with_replacement,probabilities)
}
return(s)
$BODY$
LANGUAGE plr VOLATILE
COST 100;
ALTER FUNCTION shared.sample(bigint[], integer, integer, boolean, numeric[])
OWNER TO "server-superusers";
I'm pretty new to this stuff, so any help would be appreciated.
Not a problem of the function. Like the error messages says: The string '1e+06' cannot be cast to integer.
Obviously, the columns n_agents in your table results_20161109.initial_agent_count_by_tract_res_11 is not an integer column. Probably type text or varchar? (That info would help in your question.)
Either way, the assignment cast does not work for the target type integer. But it does for numeric:
Does not work:
SELECT '1e+06'::text::int; -- error as in question
Works:
SELECT '1e+06'::text::numeric::int;
If my assumptions hold, you can use this as stepping stone.
Replace b.n_agents in your query with b.n_agents::numeric::int.
It's your responsibility that numbers stay in integer range, or you get the next exception.
If that did not nail it, you need to look into function overloading:
Is there a way to disable function overloading in Postgres
And function type resolution:
PostgreSQL function call
The schema search path is relevant in many related cases, but you did schema-qualify all objects, so we can rule that out.
How does the search_path influence identifier resolution and the "current schema"
Your query generally looks good. I had a look and only found minor improvements:
SELECT NULL::int AS agent_id -- never omit the AS keyword for column alias
, a.tract_id_alias
, b.year
, s.pgid
FROM (
SELECT tract_id_alias
, array_agg(pgid) AS pgids
, array_agg(sample_weight_geo) AS block_weights
FROM ( -- use a subquery, cheaper than CTE
SELECT tract_id_alias
, pgid
, sample_weight_geo
FROM results_20161109.block_microdata_res_joined
WHERE tract_id_alias IN (66772, 66773, 66785, 66802, 66805, 66806, 66813)
AND bldg_count_res > 0
ORDER BY pgid -- sort once in a subquery. cheaper.
) sub
GROUP BY 1
) a
LEFT JOIN results_20161109.initial_agent_count_by_tract_res_11 b USING (tract_id_alias)
LEFT JOIN LATERAL
unnest(shared.sample(a.pgids
, b.n_agents
, b.year -- why "1 * b.year"?
, true
, a.block_weights)) s(pgid) ON true
ORDER BY b.year, a.tract_id_alias, s.pgid;

Postgresql/Postgis bug in ST_ApproximateMedialAxis?

I get what seems like a bug in Postgresql/Postgis. This is a completely reproducible example that demonstrates the problem:
#create a new srid for local area (formula for proj4text is taken from Quantum GIS)
INSERT INTO spatial_ref_sys (srid, auth_name, auth_srid, proj4text) VALUES (998997, 'EPSG', 998997, '+proj=tmerc +lat_0=0 +lon_0=44.55 +k=1 +x_0=2250000 +y_0=-5714743.504 +ellps=krass +towgs84=24,-123,-94,0.02,-0.25,-0.13,1.1 +units=m +no_defs ');
#create a new table for storing geometry data:
CREATE TABLE layer(
id SERIAL PRIMARY KEY,
geom geometry,
CONSTRAINT enforce_dims_geom_layer CHECK (st_ndims(geom) = 2),
CONSTRAINT enforce_srid_geom_layer CHECK (st_srid(geom) = 998997)
);
#add one polygon to the table:
INSERT INTO layer (geom) VALUES (ST_Force2D(ST_Transform(ST_GeomFromText('POLYGON((4832654.676302 7570323.2813639, 4810946.560269 7597840.6115465, 4836629.4017728 7629944.1634263, 4886772.0923279 7629944.1634263, 4902059.4979849 7591725.6492837, 4864452.4800686 7553507.1351411, 4832654.676302 7570323.2813639),(4845190.3489408 7589891.1606049, 4855585.7847875 7610376.2841853, 4876988.1527074 7604567.0700356, 4874847.9159154 7588362.4200392, 4858031.7696927 7575520.9992872, 4845190.3489408 7589891.1606049))', 3857),998997)));
#check that this polygon is valid!
SELECT ST_IsValid(ST_Force2D(ST_Transform(ST_GeomFromText('POLYGON((4832654.676302 7570323.2813639, 4810946.560269 7597840.6115465, 4836629.4017728 7629944.1634263, 4886772.0923279 7629944.1634263, 4902059.4979849 7591725.6492837, 4864452.4800686 7553507.1351411, 4832654.676302 7570323.2813639),(4845190.3489408 7589891.1606049, 4855585.7847875 7610376.2841853, 4876988.1527074 7604567.0700356, 4874847.9159154 7588362.4200392, 4858031.7696927 7575520.9992872, 4845190.3489408 7589891.1606049))', 3857),998997))) AS is_valid;
#^^^ it returns t. so, the geometry is 100% ok.
#check how it looks like in geojson format:
SELECT ST_AsGeoJSON(ST_Transform(geom, 3857))::json from layer
#^^^ Again it's ok and returns some nice geojson data
#Final step. Check ST_ApproximateMedialAxis function
SELECT ST_ApproximateMedialAxis(ST_Transform(geom, 3857)) from layer;
The final query returns an error message:
ERROR: Polygon is invalid : exterior ring and interior ring 0 have the same orientation : POLYGON((5189023446929109/1073741824 2032143182100511/268435456,5165714534831303/1073741824 31867653268373/4194304,1298322818976529/268435456 8192590163056015/1073741824,26
********** Error **********
So, all ingredients seem to be ok - formula for srid is taken from some standard widely used tool, data is inserted into the table without problems, the data is validated by ST_IsValid, geojson representation of data is also ok, but one library function still does not like something.
I have found this nice thread and came to the solution. I just have to use ST_ForceRHR Postgis function which
forces the orientation of the vertices in a polygon to follow the Right-Hand-Rule
So the right way to insert the data was:
INSERT INTO layer (geom) VALUES (ST_Force2D(ST_Transform(ST_ForceRHR(ST_GeomFromText('POLYGON((4832654.676302 7570323.2813639, 4810946.560269 7597840.6115465, 4836629.4017728 7629944.1634263, 4886772.0923279 7629944.1634263, 4902059.4979849 7591725.6492837, 4864452.4800686 7553507.1351411, 4832654.676302 7570323.2813639),(4845190.3489408 7589891.1606049, 4855585.7847875 7610376.2841853, 4876988.1527074 7604567.0700356, 4874847.9159154 7588362.4200392, 4858031.7696927 7575520.9992872, 4845190.3489408 7589891.1606049))', 3857)),998997)));

ERROR : The column index is out of range: 1, number of columns: 0

I'm using wso2dss 3.0.0.I'm trying to execute a postgresql query i.e.
SELECT addressid, geocode
FROM maddress
WHERE geocode::point <# circle '((18.9750,72.8258), 5)';
It is working fine in PostgreSQL.When i'm using same query in wso2dss i.e.
SELECT addressid, geocode
FROM maddress
WHERE geocode::point <# circle '((?,?), ?)';
It gives me error like :
DS Fault Message: Error in 'SQLQuery.processNormalQuery'
DS Code: DATABASE_ERROR
Source Data Service:-
Name: Geofence_DataService
Location: /Geofence_DataService.dbs
Description: N/A
Default Namespace: http://ws.wso2.org/dataservice
Current Request Name: adding_geofence_op
Current Params: {longitude=72.8258, radius=4, latitude=18.9750}
Nested Exception:-
DS Fault Message: Error in 'createProcessedPreparedStatement'
DS Code: UNKNOWN_ERROR
Nested Exception:-
org.postgresql.util.PSQLException: The column index is out of range: 1, number of columns: 0.
if i remove " ' "(quotation mark) of circle then also it will not execute. query '' look like this :
SELECT addressid, geocode
FROM maddress
WHERE geocode::point <# circle ((?,?), ?);
it'll give following error :
Caused by: javax.xml.stream.XMLStreamException: DS Fault Message: Error in 'SQLQuery.processNormalQuery'
DS Code: DATABASE_ERROR
Source Data Service:-
Name: Geofence_DataService
Location: /Geofence_DataService.dbs
Description: N/A
Default Namespace: http://ws.wso2.org/dataservice
Current Request Name: geofence_op
Current Params: {longitude=72.8258, radius=4, latitude=18.9750}
Nested Exception:-
org.postgresql.util.PSQLException: ERROR: function circle(record, double precision) does not exist
Hint: No function matches the given name and argument types. You might need to add explicit type cast
But circle is inbuilt geographical function of PostgreSQL then is it necessary to write explicit function? else where is the exact error? Even if i put the query with input parameter as i execute in PostgreSQL then also it's working.If so then why it is not accepting dynamic parameters? Please let me know..
Geometric types can be input in multiple ways.
In the first form, your ? parameters are not replaced with values because they are literal parts of a string. So 0 parameters are expected ...
In the second form without single quotes, your ? parameters are replaced, but ((18.9750,72.8258), 5) is interpreted to be a row type, which doesn't work with circle().
You are trying to invoke the geometric function circle() that takes a point and a double precision ("center and radius to circle"). These are valid syntax variants:
SELECT circle '((18.9750,72.8258), 5)' AS cast_literal
' <(18.9750,72.82580),5>'::circle AS cast_literal2
, circle(point '(18.9750,72.8258)', '5') AS literal_point_n_radius
, circle(point(18.9750,72.8258), '5') AS point_n_literal_radius
, circle(point(18.9750,72.8258), 5) AS point_n_radius
SQL fiddle.
The cast to ::text is just to sanitize the deranged display in SQL fiddle
In your case, to provide numeric values (not a string literal), use the last form and it should work:
SELECT addressid, geocode
FROM maddress
WHERE geocode::point <# circle(point(?,?), ?);
If wso2dss (which I have no experience with) does not accept functions, you have to use one of the first two forms and provide a single parameter as string literal:
SELECT addressid, geocode
FROM maddress
WHERE geocode::point <# circle ?;
... where the parameter is the concatenated literal as displayed above.
You could let Postgres do the concatenation and still pass three numeric values:
SELECT addressid, geocode
FROM maddress
WHERE geocode::point <# ('(('::text || ? || ',' || ? || '),' || ? || ')')::circle;