2015-01-14 5 views
0

Я пытаюсь выполнить параметрический запрос из C#, и я получаю ошибку:Ошибка синтаксического анализа в PostgreSQL параметрирована запрос из C#, но работает в pgAdmin III

ERROR: XX000: parse error - invalid geometry

с намеком

"POLYGON((:m" <-- parse error at position 11 within geometry

Но когда я запускаю запрос в pgAdmin III, заменяя параметры своими значениями, запрос работает. Код

command.CommandText = "SELECT area_code FROM area WHERE ST_INTERSECTS(ST_GeographyFromText('POLYGON((:minx :miny, :minx :maxy, :maxx :maxy, :maxx :miny, :minx :miny))'), shape) AND area_type_code = :typecode"; 
command.CommandType = CommandType.Text; 
var typeCodeParameter = new NpgsqlParameter 
{ 
    DbType = DbType.String, 
    ParameterName = "typecode", 
    Value = _typeCode 
}; 
var minxParameter = new NpgsqlParameter 
{ 
    DbType = DbType.Double, 
    ParameterName = "minx", 
    Value = _minX 
}; 
var minyParameter = new NpgsqlParameter 
{ 
    DbType = DbType.Double, 
    ParameterName = "miny", 
    Value = _minY 
}; 
var maxxParameter = new NpgsqlParameter 
{ 
    DbType = DbType.Double, 
    ParameterName = "maxx", 
    Value = _maxX 
}; 
var maxyParameter = new NpgsqlParameter 
{ 
    DbType = DbType.Double, 
    ParameterName = "maxy", 
    Value = _maxY 
}; 
command.Parameters.Add(typeCodeParameter); 
command.Parameters.Add(maxxParameter); 
command.Parameters.Add(maxyParameter); 
command.Parameters.Add(minxParameter); 
command.Parameters.Add(minyParameter); 
using (var reader = command.ExecuteReader()) 
    while (reader.Read()) 
     areas.Add((string)reader["area_code"]); 

и рабочий запрос

SELECT area_code FROM area WHERE ST_INTERSECTS(ST_GeographyFromText('POLYGON((-1.0042576967558934 50.78431084582985, -1.0042576967558934 51.199216033050647, 1.9400782407441057 51.199216033050647, 1.9400782407441057 50.78431084582985, -1.0042576967558934 50.78431084582985))'), shape) AND area_type_code = 'County' 

Что я делаю неправильно? Как установить параметры minx, miny, maxx, maxy?

ответ

2

Проблема в том, что вы отделяете координаты. Параметры не просто удаляются вместе внутри SQL (это не просто замена шаблона), он должен быть синтаксически допустимым местом для установки параметра. Хорошая проверка работоспособности заключается в том, чтобы попробовать один и тот же запрос, но вместо того, чтобы напрямую менять параметры со значениями, используйте процедурный SQL и переменные.

Вы увидите, что проблема заключается в том, что функция ST_GeographyFromText не расширяет параметры внутри строки, которую она вводит на вход - это ожидаемое поведение. Если вы хотите использовать эту функцию, вы не можете использовать параметры внутри строки - вам все равно нужно только все значения вверх и передать их как строку - то же самое, что вы сделали, когда вы «удалили параметры». Самое простое решение, вероятно, состояло бы в том, чтобы передать всю строку в качестве параметра или просто добавить параметры в строку в запросе (например, ST_GeographyFromText('POLYGON((' || cast(:minx ...) || '), ' || ... || ')') и т. Д.)

Кажется, что вы конвертируете старые «конкатенации связки строк» «SQL с параметризованными запросами. Продолжайте, но вам нужно учитывать синтаксис. Так же, как вы не можете просто поместить подзапрос в параметр, вы не можете просто отделить одно значение от двух параметров, подобных этому.

Таким образом, вам нужно либо использовать лучший тип, либо иметь некоторое вспомогательное преобразование (например, функцию, которая принимает два поплавка и возвращает нужный вам тип).

+0

Спасибо, это имеет смысл. Я уже придумал обходной путь, где я использую string.Format, чтобы поместить параметры координат в строку SQL. Это должно быть безопасно от SQL-инъекции, поскольку они имеют тип double, поэтому ничего не может быть неприятно в команде SQL. –

+0

@ AndyNichols Вам не нужно просто вставлять его в строку SQL - просто передайте весь аргумент 'ST_GeographyFromText' как один строковый параметр. Если функция 'ST_GeographyFromText' не делает что-то действительно странное, она должна быть полностью безопасной, и вы собираетесь использовать повторное использование плана выполнения. – Luaan

1

Правильный способ использования этого параметризованного запроса - использовать функцию, которая принимает числовые параметры для построения огибающей, например ST_MakeEnvelope(xmin, ymin, xmax, ymax).

SELECT area_code 
FROM area 
WHERE ST_Intersects(ST_MakeEnvelope(:minx, :miny, :maxx, :maxy)::geography, shape) 
    AND area_type_code = :typecode; 

Другие попытки форматирования текста (WKT) медленнее и с потерями, так как числа преобразуются в текст, а затем анализируется обратно к номерам.

 Смежные вопросы

  • Нет связанных вопросов^_^