Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correctly inserting literals in PL/PgSQL EXECUTE dynamic queries

The following is part of a plpgsql function. The problem is that the result of source_geom and target_geom is a character varying data type, and therefore I need to surround the both source_geom and target_geom in quotes(' '). The thing is that in plpgsql language how I don't know I can do it.
Here's what I have at the moment:

 EXECUTE 'update ' || quote_ident(geom_table) || 
        ' SET source = ' || source_geom || 
        ', target = ' || target_geom ||
        ' WHERE ' || quote_ident(gid_cname) || ' =  ' || _r.id;

The error that I am having is the following;

ERROR:  syntax error at or near "C03B9E3B66052D400DDEFC2BD0F24140"
LINE 1: ...pdate track_points SET source = 0101000020E6100000C03B9E3B66...
                                                             ^
QUERY:  update track_points SET source = 0101000020E6100000C03B9E3B66052D400DDEFC2BD0F24140, target = 0101000020E610000075690DEF83052D40F88E75CCD4F24140 WHERE ogc_fid =  2
CONTEXT:  PL/pgSQL function "create_network" line 26 at EXECUTE statement

Please any suggestions how I can solve this problem.?

like image 941
IT_info Avatar asked Oct 20 '12 16:10

IT_info


People also ask

How do I run a dynamic query in PostgreSQL?

To execute an SQL statement with a single result row, EXECUTE can be used. To save the result, add an INTO clause. EXEC SQL BEGIN DECLARE SECTION; const char *stmt = "SELECT a, b, c FROM test1 WHERE a > ?"; int v1, v2; VARCHAR v3[50]; EXEC SQL END DECLARE SECTION; EXEC SQL PREPARE mystmt FROM :stmt; ...

What does := mean in PostgreSQL?

:= is the assignment operator in PL/pgSQL. The expression searchsql:= searchsql || ' WHERE 1=1 ' ; appends the string ' WHERE 1=1 ' to the current value of the variable searchsql. See the manual for details: http://www.postgresql.org/docs/current/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-ASSIGNMENT.

How do I run a query in PostgreSQL?

To do this in PL/pgSQL, use the PERFORM statement: PERFORM query ; This executes query and discards the result. Write the query the same way you would write an SQL SELECT command, but replace the initial keyword SELECT with PERFORM .

What is execute in PostgreSQL?

The PostgreSQL EXECUTE command prepares and runs commands dynamically. The EXECUTE command can also run DDL statements and retrieve data using SQL commands. Similar to SQL Server, you can use the PostgreSQL EXECUTE command with bind variables.


1 Answers

Using EXECUTE ... USING with the format() function and its format specifiers will make your code much safer, simpler, easier to read and probably faster.


SQL INJECTION WARNING: If you ever accept source_geom or target_geom from the end user, your code is potentially vulnerable to SQL injection. It is important to use parameterized statements (like EXECUTE ... USING) or failing that, paranoid quoting to prevent SQL injection attacks. Even if you don't think your function takes user input you should still harden it against SQL injection, because you don't know how your app will evolve.


If you're on a newer PostgreSQL with the format function your code can be significantly simplified into:

EXECUTE format('update %I SET source = %L, target = %L WHERE %I = %L',
    geom_table, source_geom, target_geom, gid_cname, _r.id);

... which handles identifier (%I) and literal (%L) quoting for you using format specifiers so you don't have to write all that awful || concatenation and quote_literal/quote_ident stuff.

Then, as per the documentation on EXECUTE ... USING you can further refine the query into:

EXECUTE format(
    'update %I SET source = $1, target = $2 WHERE %I =  $3',
    geom_table, gid_cname
) USING source_geom, target_geom, _r.id;

which turns the query into a parameterised statement, clearly separating parameters from identifiers and reducing string processing costs for a more efficient query.

like image 80
Craig Ringer Avatar answered Sep 22 '22 15:09

Craig Ringer