I am trying to test if pgrouting works fine or not. To do so I have created a table containing the following attributes.
Columns:
gid |
length |
the_geom |
source |
target
Now my problem is that when I try to execute the assign_vertex_id function it is giving me the following error;
PL/pgSQL function "assign_vertex_id" line 15 at EXECUTE statement
ERROR: query string argument of EXECUTE is null
CONTEXT: PL/pgSQL function "assign_vertex_id" line 32 at EXECUTE statement
********** Error **********
ERROR: query string argument of EXECUTE is null
SQL state: 22004
Context: PL/pgSQL function "assign_vertex_id" line 32 at EXECUTE statement
Any suggestions what does this mean?
assign_vertex_id() is defined as part of PGrouting in routing_topology.sql. (Running \df+ assign_vertex_id would also give you the current source.) Line 32's EXECUTE statement is:
EXECUTE 'update ' || quote_ident(geom_table) ||
' SET source = ' || source_id ||
', target = ' || target_id ||
' WHERE ' || quote_ident(gid_cname) || ' = ' || _r.id;
The error is that EXECUTE is being called with a NULL argument. How? Well, the SQL || operator means concatenate, and concatenating NULL to a string results in NULL:
=> select ('string' || null) is null;
?column?
----------
t
(1 row)
My guess is the gid column of the underlying table (_r.id here) contains NULLs, although I suppose it could be source/target_id too. Fix it, then add a constraint to prevent that going forward:
ALTER TABLE whatever ALTER COLUMN gid SET NOT NULL;
Are you using Postgis 2.0 and have a table with Multilinestrings?
The function ST_StartPoint() and ST_EndPoint() does not work on Multilinestrings anymore(http://postgis.refractions.net/docs/ST_StartPoint.html) in Postgis 2.0. So it will most likely fail there.
You need to convert your Multilinestrings to Linestrings. More info about that here:
Related
PostgreSQL 11.4, compiled by Visual C++ build 1914, 64-bit
Reviewed dozens of articles in Stackoverflow, no real match. The need: pass a comma separated string (id values), and use that list with the "ANY" postgresql clause.
Code
return query execute
'select aa.id, aa.course_id, aa.comments, aa.curr_cont_t_id, aa.date_done, ' ||
'aa.unit_id, aa.time_seq, aa.week_num, bb.module_id, bb.expected_hrs, ' ||
'bb.title unit_title, cc.module_name, cc.tally_hours, cc.time_of_day, ' ||
'bb.file_upload_expected, aa.app_files_id, xx.facility_id ' ||
'from course_content aa ' ||
'left outer join units bb on aa.unit_id = bb.id ' ||
'left outer join module_categories cc on bb.module_id = cc.id ' ||
'left outer join courses xx on aa.course_id = xx.id ' ||
'where xx.facility_id = any(''{' || $1 || '}'') '
using p_facilities;
I have checked p_facilities to ensure it is not empty or null. I have even specifically set p_facilities to a value inside the function like this:
p_facilities text = '3';
The returned error is consistently: 'query string argument of EXECUTE is null (SQL State 22004)'
The problem is that you are not referring to the using parameter anywhere in your query. Instead, you are concatenating $1 directly into your query, and this $1 refers to the first argument of the pl/pgsql function you are in (and apparently is NULL).
To use parameters in dynamically executed sql and pass them through using, you need to hardcode the text $1 into the query string:
EXECUTE 'SELECT … WHERE xx.facility_id = any($1)' USING some_array;
To interpolate a string into the query, you don't need any using clause, just refer to the string directly:
EXECUTE 'SELECT … WHERE xx.facility_id = any(''{' || p_facilities || '}'')';
However, notice that you don't need (and shouldn't use) dynamic sql here at all. You're constructing a value, not sql structure. You can just refer to that directly in a normal query:
SELECT … WHERE xx.facility_id = any( ('{' || p_facilities || '}')::int[] );
-- or better
SELECT … WHERE xx.facility_id = any( string_to_array(p_facilities, ',')::int[] );
I'm struggling with a stored procedure which heavily uses dynamic queries. Among others I need to store maximum value of an existing column into a variable.
Postgres documents state "if you want to use dynamically determined table or column names, you must insert them into the command string textually". Based on that I've come up with following statement:
EXECUTE 'SELECT MAX(' || pkColumn::regclass || ') FROM ' ||
tableName::regclass INTO maxValue;
Table name seems to be OK, column name triggers error.
What am I doing wrong ?
Pavel
EXECUTE 'SELECT MAX(' || pkColumn ||'::regclass) FROM ' || ...
::regclass is a cast done inside query. You can also skip it, or put " - which in PG works the same. So please try one of:
EXECUTE 'SELECT MAX(' || pkColumn || ') FROM ' || ...
or
EXECUTE 'SELECT MAX("' || pkColumn || '") FROM ' || ...
All tree should work. If not - just let me know. In that case it is my fault, postgresql simply works.
There is no reason to cast parameters as they are just identifiers. For better control and readability use the function format(), e.g.:
declare
pkcolumn text = 'my_column';
tablename text = 'my_table';
...
execute format('select max(%I) from %I', pkcolumn, tablename)
into maxvalue;
in my postgres 9.3 database, I have the following combination of function and a trigger to implement soft delete functionality:
ALTER TABLE "LIBN02"."trigger_test_1"
ADD COLUMN delete_ind integer
CREATE OR REPLACE FUNCTION trigger_test_1_soft_delete()
RETURNS trigger AS $$
DECLARE
command text := ' SET delete_ind = 1 WHERE uuid_col = $1';
BEGIN
EXECUTE 'UPDATE ' || "LIBN02"."trigger_test_1" || command USING OLD.uuid_col;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER test_1_soft_delete_trigger
BEFORE DELETE ON "LIBN02"."trigger_test_1"
FOR EACH ROW EXECUTE PROCEDURE trigger_test_1_soft_delete();
After all of the above is done, I run the following delete statement:
DELETE FROM "LIBN02"."trigger_test_1"
I get the following error:
ERROR: missing FROM-clause entry for table "LIBN02"
LINE 1: SELECT 'UPDATE ' || "LIBN02"."trigger_test_1" || command
^
QUERY: SELECT 'UPDATE ' || "LIBN02"."trigger_test_1" || command
CONTEXT: PL/pgSQL function trigger_test_1_soft_delete() line 5 at EXECUTE
********** Error **********
ERROR: missing FROM-clause entry for table "LIBN02"
SQL state: 42P01
Context: PL/pgSQL function trigger_test_1_soft_delete() line 5 at EXECUTE
What should I change in order for this to work?
The error you are receiving is because "LIBN02"."trigger_test_1" is not a string (these are quoted with single quotes), but an identifier. You should use
EXECUTE 'UPDATE "' || TG_TABLE_SCHEMA || '"."' || TG_TABLE_NAME || '" ' || command
USING OLD.uuid_col;
You could also add AND NOT deleted to the WHERE clause to avoid unnecessary churn.
I am building a trigger function in plpgsql for my partitioned table and I've got all of my logic working, but am having trouble inserting the actual record into my table.
I have to reference my specific table by a variable reference, so that (as far as I understand) forces me to use an EXECUTE command, as so:
EXECUTE 'INSERT INTO ' || tablename || ' VALUES ' || NEW.*;
However, this does not handle unpacking the record stored in NEW in a way that Postgres' INSERT function can understand. It converts the record into a string while preserving all of the double quotes within. I.e. the above turns into the following upon execution:
INSERT INTO cfs_hgt_05152016_05202016
VALUES ("2016-05-16 00:00:00","2016-05-12 06:00:00",HGT,"1000 mb",9,-71,-38.5371)
The problem with this is Postgres thinks these values are now columns due to the double quotes.
COPY cfs_hgt_master, line 1: ""2016-05-16 00:00:00","2016-05-12 06:00:00","HGT","1000 mb",9,-71,-38.5371"
ERROR: column "2016-05-16 00:00:00" does not exist
I tried to remedy this by the following:
record_text := regexp_replace(NEW.*, '"', '\'', 'gi');
EXECUTE 'INSERT INTO ' || tablename || ' VALUES ' || record_text;
But escaping the single quote like that produces an error:
psql:cfs_hgt_trigger_function.sql:36: ERROR: unterminated quoted string at or near "' || record_text;
LINE 30: ... EXECUTE 'INSERT INTO ' || tablename || ' VALUES ' || recor...
^
Could someone help me figure out how to either properly escape that single quote, or suggest an alternative means of accomplishing my task?
Don't convert values to their text representation at all. Pass values with the USING clause of EXECUTE.
And escape table names properly. You can use format() for this:
EXECUTE format('INSERT INTO %I SELECT $1.*', tablename)
USING NEW;
Details:
INSERT with dynamic table name in trigger function
How to pass NEW.* to EXECUTE in trigger function
The following Statement show error
EXECUTE quote_ident('Calculate' || calc_type_row."Name") || '($1,$2)' USING calc_type_row."IntervalTypeId",'Meter';
Name, IntervalTypeId are column in a table.
The statement EXECUTE is expecting valid SQL statement - in this case SELECT statement. So you are missing SELECT keyword:
EXECUTE format ('SELECT %I($1, $2)', 'Calculate' || calc_type."Name") USING ...