Basics
To get all index definitions you can use the system catalog information function pg_get_indexdef(index_oid) like @a_horse already provided.
The query can be considerably simpler, though, using a regclass parameter. For a table called tbl in the public schema:
SELECT pg_get_indexdef(indexrelid) || ';' AS idx
FROM pg_index
WHERE indrelid = 'public.tbl'::regclass; -- optionally schema-qualified
This includes all indexes: PK, partial, functional, unique, with special operator classes, etc.
Details for regclass:
Prepare DDL statements
You cannot work with this, yet. You have to replace the old table name with the new one - and you don't want to replace false positives in the string (like a column name that matches the table name):
If you are working with the default naming convention of Postgres, index definitions look like this:
CREATE INDEX tbl_tbl_id_idx ON tbl USING btree (tbl_id);
CREATE INDEX tbl_people_gin_idx ON tbl
USING gin (((data -> 'people'::text)) jsonb_path_ops);
CREATE INDEX tbl_comecol_nonull_idx ON tbl
USING btree (somecol) WHERE (cutblade IS NOT NULL);
I bolded every occurrence of the original table name. Note the three false positives (part of column name or index name) which we do not want to replace.
This query should work flawlessly - but verify that against your actual indexes yourself!
SELECT regexp_replace(regexp_replace(
pg_get_indexdef(indexrelid)
, 'tbl', 'tbl1')
, ' ON tbl ', ' ON tbl1 ')
|| ';' AS idx
FROM pg_index
WHERE indrelid = 'public.tbl'::regclass;
The 1st replace() only replaces the first match in the name (unless instructed otherwise). The 2nd regexp_preplace() is more specific and only replaces the actual table name.
For the given examples you get:
CREATE INDEX tbl1_tbl_id_idx ON tbl1 USING btree (tbl_id);
CREATE INDEX tbl1_people_gin_idx ON tbl1
USING gin (((data -> 'people'::text)) jsonb_path_ops);
CREATE INDEX tbl1_somecol_nonull_idx ON tbl1
USING btree (somecol) WHERE (cutblade IS NOT NULL);
But we have not yet considered non-standard table names, schemas or the search_path setting. All of that is built into the function below.
Full automation
If you are confident in your naming scheme you can fully automate:
CREATE OR REPLACE FUNCTION f_copy_idx(_tbl text, _tbl1 text
, _sch text = 'public', _sch1 text = 'public')
RETURNS void AS
$func$
DECLARE
_full_tbl text := format('%I.%I', _sch, _tbl);
_full_tbl1 text := format('%I.%I', _sch1, _tbl1);
BEGIN
-- RAISE NOTICE '%', -- for testing
EXECUTE
(SELECT string_agg(
regexp_replace(regexp_replace(
pg_get_indexdef(indexrelid)
, _tbl, _tbl1)
, ' ON ' || _full_tbl || ' ', ' ON ' || _full_tbl1 || ' ')
, '; ') AS idx
FROM pg_index
WHERE indrelid = _full_tbl::regclass);
END
$func$ LANGUAGE plpgsql SET search_path = '';
This is also prepared for non-standard table names that need double-quoting and differing schemas.
To force schema-qualified table names I reset the search_path inside the function (SET search_path = ''). This way I get reliable results that do not depend on the setting.
I added 'public' as default value for the schema parameters _sch and _sch1. So if both tables reside in the public schema, you can simple ignore the schema parameters.
Call:
SELECT f_copy_idx('mytbl', 'newtbl'); -- all in schema public
Or for table names that require double-quoting and different schemas:
SELECT f_copy_idx('old_TBL', 'table', 'public', 'New_SCHEmA');
SQL Fiddle demonstrating the function in use.