I don't know if this question better suits here or in SO ...
This is a script that I'd like to launch (the code of the function was copied from a question on SO):
\c mydb
create or replace function truncate_tables(username in varchar) returns void as $$
declare
stmt RECORD;
statements cursor for select tablename from pg_tables where tableowner = username;
begin
for stmt in statements loop
execute 'truncate table ' || quote_ident(stmt.tablename) || ' CASCADE ;';
end loop;
end;
$$ language 'plpgsql';
I get the following error:
ERROR: syntax at or near "1ドル" LINE1: 1ドル
QUERY 1ドル
CONTEXT: SQL statement in PL/PgSQL function "truncate_tables" near line 5
I am new to Postgres and PL/pgSQL and don't know what this error message means.
-
It's a third party database. Just to explain the context: I want to be able to backup production databases onto our developement databases for debugging and diagnose... and it seems I have to truncate all our local tables before restoring, otherwise pg_restore thows hundreds of errors because of dupplicate keys.Stephane Rolland– Stephane Rolland2012年08月22日 14:54:46 +00:00Commented Aug 22, 2012 at 14:54
-
2"...it seems I have to truncate all our local tables before restoring..." The pg_dump utility can drop database objects before trying to create them. See the --clean argument on this page. Depending on your environment, it might be practical to drop the dev database before restoring to it. (Make sure the dump creates the database before you do that.)Mike Sherrill 'Cat Recall'– Mike Sherrill 'Cat Recall'2012年08月22日 16:04:26 +00:00Commented Aug 22, 2012 at 16:04
-
@Catcall, I'm dumping production databases and I don't want them to be cleared. What's updated I want to restore in developement databases, on which we can diagnose and debug.Stephane Rolland– Stephane Rolland2012年08月22日 16:14:52 +00:00Commented Aug 22, 2012 at 16:14
-
1@Stephane I don't think Catcall is referring to clearing the source database - rather generating sql to drop and recreate the tables in the development database.Jack Douglas– Jack Douglas2012年08月22日 16:49:07 +00:00Commented Aug 22, 2012 at 16:49
-
1Sadly, the answers for the question at SO where you got your advice from were not very good (IMO). I added an alternative answer there.Erwin Brandstetter– Erwin Brandstetter2012年08月22日 22:04:49 +00:00Commented Aug 22, 2012 at 22:04
2 Answers 2
Try dispensing with the explicit cursor:
begin;
set role dba;
create role stack;
grant stack to dba;
create schema authorization stack;
set role stack;
--
create table foo(id serial);
insert into foo default values;
create or replace function truncate_tables(username in varchar) returns void as $$
declare r record;
begin
for r in (select tablename from pg_tables where tableowner = username) loop
execute 'truncate table ' || quote_ident(r.tablename) || ' cascade';
end loop;
end;
$$ language 'plpgsql';
--
select truncate_tables('stack');
select * from foo;
/*
id
----
(0 rows)
*/
--
rollback;
-
also check you can run
select tablename from pg_tables where tableowner = 'foo'
as the user running the scriptJack Douglas– Jack Douglas2012年08月22日 16:18:31 +00:00Commented Aug 22, 2012 at 16:18 -
Bingo ! Does that mean that PL/PgSql doesn't support cursors ?Stephane Rolland– Stephane Rolland2012年08月22日 16:21:46 +00:00Commented Aug 22, 2012 at 16:21
-
I'm trying to find some doc on cursor limitation in 8.3. Maybe that's a known issue.Stephane Rolland– Stephane Rolland2012年08月22日 16:26:20 +00:00Commented Aug 22, 2012 at 16:26
-
All in all... for the moment I have found no limitation regarding cursors in 8.3 in documentation. Once again many thx Jack!Stephane Rolland– Stephane Rolland2012年08月22日 16:49:06 +00:00Commented Aug 22, 2012 at 16:49
-
2Detail you might be interested in: Unlike
expression IN (subquery)
in SQL,FOR target IN query LOOP
in plpgsql does not require parenthesis around the query.Erwin Brandstetter– Erwin Brandstetter2012年08月23日 01:09:57 +00:00Commented Aug 23, 2012 at 1:09
This particular example can be simpler.
You can TRUNCATE
multiple tables at once. Aggregate all tablenames and execute a single statement:
CREATE OR REPLACE FUNCTION truncate_tables(_username text)
RETURNS void AS
$func$
BEGIN
EXECUTE (
SELECT 'TRUNCATE TABLE '
|| string_agg(quote_ident(t.tablename), ', ')
|| ' CASCADE;'
FROM pg_tables t
WHERE t.tableowner = _username
AND t.schemaname = 'public'
);
END;
$func$ LANGUAGE plpgsql;
Call:
SELECT truncate_tables('postgres');
string_agg()
requires PostgreSQL 9.0 or later.
In 8.4 you can substitute:
array-to_string(array_agg(quote_ident(t.tablename)), ', ')
For v8.3 you would write your own aggregate function - rather simple, yet not simpler than the looping solution any more.
Performance degrades when deleting or truncating many tables at once in PostgreSQL 9.1. A fix for this in the upcoming version 9.2. I quote the release notes:
Improve performance of checkpointer's fsync-request queue when many tables are being dropped or truncated (Tom Lane)
Related thread at pgsql-hackers.
@Craig's related answer at SO helped me discover this.
-
+1 excellent. As you say elsewhere, simpler and faster.Jack Douglas– Jack Douglas2012年08月23日 08:12:00 +00:00Commented Aug 23, 2012 at 8:12
Explore related questions
See similar questions with these tags.