/* Auto-generated — do not edit.
 * Run 'make gen-sql' after modifying any .sql file.
 */

static const char sql_citus_distributed_tables[] =
	"with ordered as (\n"
	"  select\n"
	"    table_name::text                                            as tname,\n"
	"    distribution_column,\n"
	"    colocation_id,\n"
	"    shard_count,\n"
	"    row_number() over (partition by colocation_id\n"
	"                       order by table_name::text)              as rn,\n"
	"    first_value(table_name::text) over (\n"
	"        partition by colocation_id\n"
	"        order by table_name::text)                             as anchor\n"
	"  from citus_tables\n"
	"  where citus_table_type = 'distributed'\n"
	")\n"
	" select\n"
	"  case\n"
	"    when rn = 1 then\n"
	"      format(\n"
	"        'select create_distributed_table(%L, %L, shard_count := %s, colocate_with := %L)',\n"
	"        tname, distribution_column, shard_count, 'none')\n"
	"    else\n"
	"      format(\n"
	"        'select create_distributed_table(%L, %L, colocate_with := %L)',\n"
	"        tname, distribution_column, anchor)\n"
	"  end\n"
	" from ordered\n"
	" order by colocation_id, rn\n"
;

static const char sql_citus_reference_tables[] =
	"select format('select create_reference_table(%L)', table_name::text)\n"
	"  from citus_tables\n"
	" where citus_table_type = 'reference'\n"
	" order by table_name::text\n"
;

static const char sql_filter_table_arrays[] =
	"-- SQLite query used by catalog_filter_table_arrays().\n"
	"-- $1 : section name ('excl_table', 'incl_table', 'xdat_table', 'excl_index')\n"
	"--\n"
	"-- Returns 8 PostgreSQL array literals '{v1,...}' (or NULL when the class has\n"
	"-- no entries) for the four EE/ER/RE/RR match classes in one scan of f_table.\n"
	"-- One CTE scan replaces the eight correlated subqueries of the original query.\n"
	"--\n"
	"-- group_concat() returns NULL for zero matching rows, so the expression\n"
	"-- '{' || NULL || '}' evaluates to NULL — the same sentinel the C caller uses\n"
	"-- to detect an absent category (outputs[col] == NULL check).\n"
	"WITH rows AS (\n"
	"    SELECT nspname, nspname_re, relname, relname_re\n"
	"      FROM f_table\n"
	"     WHERE section = $1\n"
	")\n"
	"SELECT\n"
	"  -- EE: exact nspname + exact relname\n"
	"  '{' || group_concat(nspname,    ',') FILTER (WHERE nspname    IS NOT NULL AND nspname_re IS NULL\n"
	"                                                 AND relname    IS NOT NULL AND relname_re IS NULL) || '}',\n"
	"  '{' || group_concat(relname,    ',') FILTER (WHERE nspname    IS NOT NULL AND nspname_re IS NULL\n"
	"                                                 AND relname    IS NOT NULL AND relname_re IS NULL) || '}',\n"
	"  -- ER: exact nspname + regex relname\n"
	"  '{' || group_concat(nspname,    ',') FILTER (WHERE nspname    IS NOT NULL AND nspname_re IS NULL\n"
	"                                                 AND relname    IS NULL     AND relname_re IS NOT NULL) || '}',\n"
	"  '{' || group_concat(relname_re, ',') FILTER (WHERE nspname    IS NOT NULL AND nspname_re IS NULL\n"
	"                                                 AND relname    IS NULL     AND relname_re IS NOT NULL) || '}',\n"
	"  -- RE: regex nspname + exact relname\n"
	"  '{' || group_concat(nspname_re, ',') FILTER (WHERE nspname    IS NULL     AND nspname_re IS NOT NULL\n"
	"                                                 AND relname    IS NOT NULL AND relname_re IS NULL) || '}',\n"
	"  '{' || group_concat(relname,    ',') FILTER (WHERE nspname    IS NULL     AND nspname_re IS NOT NULL\n"
	"                                                 AND relname    IS NOT NULL AND relname_re IS NULL) || '}',\n"
	"  -- RR: regex nspname + regex relname\n"
	"  '{' || group_concat(nspname_re, ',') FILTER (WHERE nspname    IS NULL     AND nspname_re IS NOT NULL\n"
	"                                                 AND relname    IS NULL     AND relname_re IS NOT NULL) || '}',\n"
	"  '{' || group_concat(relname_re, ',') FILTER (WHERE nspname    IS NULL     AND nspname_re IS NOT NULL\n"
	"                                                 AND relname    IS NULL     AND relname_re IS NOT NULL) || '}'\n"
	"  FROM rows\n"
;

static const char sql_list_collations[] =
	"with indcols as\n"
	" (\n"
	"   select indexrelid, n, colloid\n"
	"     from pg_index i\n"
	"     join pg_class c on c.oid = i.indexrelid\n"
	"     join pg_namespace n on n.oid = c.relnamespace,\n"
	"          unnest(indcollation) with ordinality as t (colloid, n)\n"
	"    where n.nspname !~ '^pg_' and n.nspname <> 'information_schema'\n"
	" ),\n"
	"all_colls as\n"
	" (\n"
	"   select colloid, collname,\n"
	"          pg_describe_object('pg_class'::regclass, indexrelid, 0)\n"
	"              as description,\n"
	"          format('%s %s %s',\n"
	"                 regexp_replace(n.nspname, '[\\n\\r]', ' '),\n"
	"                 regexp_replace(c.collname, '[\\n\\r]', ' '),\n"
	"                 regexp_replace(auth.rolname, '[\\n\\r]', ' '))\n"
	"              as restore_list_name\n"
	"     from indcols\n"
	"          join pg_collation c on c.oid = colloid\n"
	"          join pg_roles auth ON auth.oid = c.collowner\n"
	"          join pg_namespace n on n.oid = c.collnamespace\n"
	"    where colloid <> 0\n"
	"      and collname <> 'default'\n"
	"   union\n"
	"   select c.oid as colloid, c.collname,\n"
	"          format('database %s', d.datname) as description,\n"
	"          format('%s %s %s',\n"
	"                 regexp_replace(n.nspname, '[\\n\\r]', ' '),\n"
	"                 regexp_replace(c.collname, '[\\n\\r]', ' '),\n"
	"                 regexp_replace(auth.rolname, '[\\n\\r]', ' '))\n"
	"              as restore_list_name\n"
	"     from pg_database d\n"
	"          join pg_collation c on c.collname = d.datcollate\n"
	"          join pg_roles auth ON auth.oid = c.collowner\n"
	"          join pg_namespace n on n.oid = c.collnamespace\n"
	"    where d.datname = current_database()\n"
	"   union\n"
	"   select coll.oid as colloid, coll.collname,\n"
	"          pg_describe_object('pg_class'::regclass, attrelid, attnum)\n"
	"              as description,\n"
	"          format('%s %s %s',\n"
	"                 regexp_replace(cn.nspname, '[\\n\\r]', ' '),\n"
	"                 regexp_replace(coll.collname, '[\\n\\r]', ' '),\n"
	"                 regexp_replace(auth.rolname, '[\\n\\r]', ' '))\n"
	"              as restore_list_name\n"
	"     from pg_attribute a\n"
	"          join pg_class c on c.oid = a.attrelid\n"
	"          join pg_namespace n on n.oid = c.relnamespace\n"
	"          join pg_collation coll on coll.oid = attcollation\n"
	"          join pg_roles auth ON auth.oid = coll.collowner\n"
	"          join pg_namespace cn on cn.oid = coll.collnamespace\n"
	"    where collname <> 'default'\n"
	"      and n.nspname !~ '^pg_' and n.nspname <> 'information_schema'\n"
	" )\n"
	"select distinct on (colloid) colloid, collname, description,\n"
	"       restore_list_name\n"
	"  from all_colls\n"
	"order by colloid, description\n"
;

static const char sql_list_database_properties[] =
	"select d.datname, NULL as rolname,\n"
	"       unnest(rs.setconfig) as setconfig\n"
	"  from pg_db_role_setting rs\n"
	"       join pg_database d on d.oid = rs.setdatabase\n"
	" where d.datname = current_database()\n"
	"   and setrole = 0\n"
	"\n"
	"union all\n"
	"\n"
	"select d.datname, format('%I', rolname) as rolname,\n"
	"       unnest(rs.setconfig)  as setconfig\n"
	"  from pg_db_role_setting rs\n"
	"       join pg_database d on d.oid = rs.setdatabase\n"
	"       join pg_roles r on r.oid = rs.setrole\n"
	" where d.datname = current_database()\n"
;

static const char sql_list_databases[] =
	"select d.oid, datname, pg_database_size(d.oid) as bytes,\n"
	"       pg_size_pretty(pg_database_size(d.oid))\n"
	"  from pg_database d\n"
	" where datname not in ('template0', 'template1')\n"
	"order by datname\n"
;

static const char sql_list_ext_schemas[] =
	"select distinct on (n.oid) n.oid, n.nspname,\n"
	"       format('- %s %s',\n"
	"                regexp_replace(n.nspname, '[\\n\\r]', ' '),\n"
	"                regexp_replace(auth.rolname, '[\\n\\r]', ' '))\n"
	"  from pg_namespace n\n"
	"       join pg_roles auth ON auth.oid = n.nspowner\n"
	"       join pg_depend d\n"
	"         on d.refclassid = 'pg_namespace'::regclass\n"
	"        and d.refobjid = n.oid\n"
	"        and d.classid = 'pg_extension'::regclass\n"
	" where nspname <> 'public' and nspname !~ '^pg_'\n"
;

static const char sql_list_ext_versions[] =
	"select e.name, e.default_version, e.installed_version,\n"
	"       u.versions\n"
	"\n"
	"from pg_available_extensions e\n"
	"     left join lateral\n"
	"     (\n"
	"       with updates as\n"
	"       (\n"
	"         select source,\n"
	"                array_length(regexp_split_to_array(path, '--'), 1) as steps\n"
	"           from pg_extension_update_paths(e.name)\n"
	"          where (   target = e.default_version\n"
	"                 or source = e.default_version)\n"
	"           and source not in ('unpackaged', 'ANY')\n"
	"           and path is not null\n"
	"\n"
	"     union all\n"
	"\n"
	"        select e.default_version, 0\n"
	"\n"
	"      order by steps, source desc\n"
	"       )\n"
	"       select coalesce(jsonb_agg(source),\n"
	"                       jsonb_build_array(e.default_version))\n"
	"       from updates\n"
	"     )\n"
	"     as u(versions) on true\n"
	"\n"
	"group by e.name, e.default_version, e.installed_version, u.versions\n"
	"order by e.name\n"
;

static const char sql_list_extensions[] =
	"with recursive extconfig_paths as (\n"
	"     select extconfig\n"
	"     from pg_extension\n"
	"     where extconfig is not null\n"
	" ), fk_constraints as (\n"
	"     select fk.oid, fk.conrelid, fk.confrelid\n"
	"     from pg_constraint fk\n"
	"     inner join extconfig_paths\n"
	"         on fk.conrelid = any(extconfig_paths.extconfig)\n"
	"         or fk.confrelid = any(extconfig_paths.extconfig)\n"
	"     where fk.contype = 'f' and fk.conrelid <> fk.confrelid\n"
	" ), raw_ordered_fk_constraints as (\n"
	"     select\n"
	"            distinct c.confrelid as relid,\n"
	"            0 as depth,\n"
	"            false as is_cycle,\n"
	"            ARRAY[c.oid] as path\n"
	"       from fk_constraints c\n"
	"      where not exists (\n"
	"            select 1\n"
	"              from fk_constraints fc\n"
	"             where fc.conrelid = c.confrelid\n"
	"            )\n"
	"     UNION\n"
	"     select\n"
	"            distinct c.conrelid as relid,\n"
	"            r.depth + 1 as depth,\n"
	"            c.oid = ANY(path) as is_cycle,\n"
	"            path || c.oid as path\n"
	"       from raw_ordered_fk_constraints r\n"
	"       join fk_constraints c ON c.confrelid = r.relid\n"
	"      where not is_cycle\n"
	" ), ordered_fk_constraints AS (\n"
	"     select\n"
	"            relid,\n"
	"            max(depth) as depth\n"
	"       from raw_ordered_fk_constraints group by relid\n"
	" ), extension_config_data as (\n"
	"select e.oid, extname, extnamespace::regnamespace, extrelocatable,\n"
	"       0 as count, null as n,\n"
	"       null as extconfig, null as nspname, null as relname,\n"
	"       null as extcondition,\n"
	"       null as relkind\n"
	"  from pg_extension e\n"
	" where extconfig is null\n"
	"\n"
	" UNION ALL\n"
	"\n"
	"  select e.oid, extname, extnamespace::regnamespace, extrelocatable,\n"
	"         array_length(e.extconfig, 1) as count,\n"
	"         extconfig.n,\n"
	"         extconfig.extconfig,\n"
	"         format('%I', n.nspname) as nspname,\n"
	"         format('%I', c.relname) as relname,\n"
	"         extcondition[extconfig.n],\n"
	"         c.relkind as relkind\n"
	"    from pg_extension e,\n"
	"         unnest(extconfig) with ordinality as extconfig(extconfig, n)\n"
	"          left join pg_class c on c.oid = extconfig.extconfig\n"
	"          join pg_namespace n on c.relnamespace = n.oid\n"
	"   where extconfig.extconfig is not null\n"
	")\n"
	"select oid, extname, extnamespace, extrelocatable,\n"
	"       count,\n"
	"       row_number() over (partition by oid order by depth) as n,\n"
	"       extconfig,\n"
	"       nspname,\n"
	"       relname,\n"
	"       extcondition,\n"
	"       relkind\n"
	" from extension_config_data\n"
	"      left outer join ordered_fk_constraints ofc on extconfig = ofc.relid\n"
;

static const char sql_list_filtered_excl_tables[] =
	"-- Returns tables that ARE excluded by exclude-schema or exclude-table rules;\n"
	"-- these are the objects filtered out when exclusion filters are active.\n"
	"-- $1/$2: incl_exact/incl_re schema arrays (for include-only-schema pass-through).\n"
	"-- $3..$10: paired text[] arrays for EE/ER/RE/RR exclude-table patterns.\n"
	"-- A table is returned when it fails the schema include filter OR matches\n"
	"-- an exclude-table pattern.\n"
	"WITH filters AS (\n"
	"    SELECT\n"
	"        -- schema-level: include-only exact/regex (table is excluded if schema not included)\n"
	"        $1::text[] AS incl_schema_exact,\n"
	"        $2::text[] AS incl_schema_re,\n"
	"        -- schema-level: exclude exact/regex\n"
	"        $3::text[] AS excl_schema_exact,\n"
	"        $4::text[] AS excl_schema_re,\n"
	"        -- exclude table: exact nsp + exact rel\n"
	"        $5::text[] AS excl_ee_nsp, $6::text[] AS excl_ee_rel,\n"
	"        -- exclude table: exact nsp + regex rel\n"
	"        $7::text[] AS excl_er_nsp, $8::text[] AS excl_er_rel,\n"
	"        -- exclude table: regex nsp + exact rel\n"
	"        $9::text[] AS excl_re_nsp, $10::text[] AS excl_re_rel,\n"
	"        -- exclude table: regex nsp + regex rel\n"
	"        $11::text[] AS excl_rr_nsp, $12::text[] AS excl_rr_rel\n"
	")\n"
	"SELECT c.oid,\n"
	"       format('%I', n.nspname) AS nspname,\n"
	"       format('%I', c.relname) AS relname,\n"
	"       c.relkind AS relkind,\n"
	"       pg_am.amname,\n"
	"       c.relpages, c.reltuples::bigint,\n"
	"       c.relpages * current_setting('block_size')::bigint AS bytesestimate,\n"
	"       pg_size_pretty(c.relpages * current_setting('block_size')::bigint),\n"
	"       false AS excludedata,\n"
	"       format('%s %s %s',\n"
	"              regexp_replace(n.nspname, '[\\n\\r]', ' '),\n"
	"              regexp_replace(c.relname, '[\\n\\r]', ' '),\n"
	"              regexp_replace(auth.rolname, '[\\n\\r]', ' ')),\n"
	"       CASE WHEN pkeys.attname IS NOT NULL\n"
	"            THEN format('%I', pkeys.attname)\n"
	"       END AS partkey\n"
	"\n"
	"  FROM pg_catalog.pg_class c\n"
	"  JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid\n"
	"  LEFT JOIN pg_catalog.pg_am ON c.relam = pg_am.oid\n"
	"  JOIN pg_roles auth ON auth.oid = c.relowner,\n"
	"       filters f\n"
	"\n"
	"-- find a copy partition key candidate\n"
	"  LEFT JOIN LATERAL (\n"
	"      SELECT indrelid, indexrelid, a.attname\n"
	"        FROM pg_index x\n"
	"        JOIN pg_class i ON i.oid = x.indexrelid\n"
	"        JOIN pg_attribute a\n"
	"          ON a.attrelid = c.oid AND attnum = indkey[0]\n"
	"       WHERE x.indrelid = c.oid\n"
	"         AND (indisprimary OR indisunique)\n"
	"         AND array_length(indkey::integer[], 1) = 1\n"
	"         AND atttypid IN ('smallint'::regtype, 'int'::regtype, 'bigint'::regtype)\n"
	"    ORDER BY NOT indisprimary, NOT indisunique\n"
	"       LIMIT 1\n"
	"  ) AS pkeys ON true\n"
	"\n"
	" WHERE c.relkind IN ('r', 'p', 'm') AND c.relpersistence IN ('p', 'u')\n"
	"   AND n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'\n"
	"   AND n.nspname !~ 'pgcopydb'\n"
	"   -- table is in the excluded set if its schema is excluded OR if the table itself\n"
	"   -- matches an exclude-table entry\n"
	"   AND (\n"
	"       -- schema not in include-only set (when include-only-schema is active):\n"
	"       -- a schema is excluded only when it matches NONE of the include rules\n"
	"       (\n"
	"           (f.incl_schema_exact IS NOT NULL OR f.incl_schema_re IS NOT NULL)\n"
	"           AND (f.incl_schema_exact IS NULL OR n.nspname <> ALL(f.incl_schema_exact))\n"
	"           AND (f.incl_schema_re IS NULL OR NOT (n.nspname ~ ANY(f.incl_schema_re)))\n"
	"       )\n"
	"    OR -- schema matches an explicit exclude-schema rule\n"
	"       n.nspname = ANY(f.excl_schema_exact)\n"
	"    OR (f.excl_schema_re IS NOT NULL AND n.nspname ~ ANY(f.excl_schema_re))\n"
	"    OR -- table matches an explicit exclude-table rule\n"
	"       EXISTS (SELECT 1 FROM unnest(f.excl_ee_nsp, f.excl_ee_rel) AS t(nsp, rel)\n"
	"               WHERE n.nspname = t.nsp AND c.relname = t.rel)\n"
	"    OR EXISTS (SELECT 1 FROM unnest(f.excl_er_nsp, f.excl_er_rel) AS t(nsp, rel_re)\n"
	"               WHERE n.nspname = t.nsp AND c.relname ~ t.rel_re)\n"
	"    OR EXISTS (SELECT 1 FROM unnest(f.excl_re_nsp, f.excl_re_rel) AS t(nsp_re, rel)\n"
	"               WHERE n.nspname ~ t.nsp_re AND c.relname = t.rel)\n"
	"    OR EXISTS (SELECT 1 FROM unnest(f.excl_rr_nsp, f.excl_rr_rel) AS t(nsp_re, rel_re)\n"
	"               WHERE n.nspname ~ t.nsp_re AND c.relname ~ t.rel_re)\n"
	"   )\n"
	"   -- extension guard\n"
	"   AND NOT EXISTS (\n"
	"       SELECT 1 FROM pg_depend d\n"
	"        WHERE d.classid = 'pg_class'::regclass\n"
	"          AND d.objid = c.oid AND d.deptype = 'e'\n"
	"   )\n"
	"\n"
	" ORDER BY n.nspname, c.relname\n"
;

static const char sql_list_filtered_not_incl_tables[] =
	"-- Returns tables that are NOT in the include-only-table list; these are the\n"
	"-- objects filtered out when include-only-table constraints are active.\n"
	"-- $1..$8: paired text[] arrays for EE/ER/RE/RR include-only-table patterns.\n"
	"WITH filters AS (\n"
	"    SELECT\n"
	"        -- include-only table: exact nsp + exact rel\n"
	"        $1::text[] AS incl_ee_nsp,  $2::text[] AS incl_ee_rel,\n"
	"        -- include-only table: exact nsp + regex rel\n"
	"        $3::text[] AS incl_er_nsp,  $4::text[] AS incl_er_rel,\n"
	"        -- include-only table: regex nsp + exact rel\n"
	"        $5::text[] AS incl_re_nsp, $6::text[] AS incl_re_rel,\n"
	"        -- include-only table: regex nsp + regex rel\n"
	"        $7::text[] AS incl_rr_nsp, $8::text[] AS incl_rr_rel\n"
	")\n"
	"SELECT c.oid,\n"
	"       format('%I', n.nspname) AS nspname,\n"
	"       format('%I', c.relname) AS relname,\n"
	"       c.relkind AS relkind,\n"
	"       pg_am.amname,\n"
	"       c.relpages, c.reltuples::bigint,\n"
	"       c.relpages * current_setting('block_size')::bigint AS bytesestimate,\n"
	"       pg_size_pretty(c.relpages * current_setting('block_size')::bigint),\n"
	"       false AS excludedata,\n"
	"       format('%s %s %s',\n"
	"              regexp_replace(n.nspname, '[\\n\\r]', ' '),\n"
	"              regexp_replace(c.relname, '[\\n\\r]', ' '),\n"
	"              regexp_replace(auth.rolname, '[\\n\\r]', ' ')),\n"
	"       CASE WHEN pkeys.attname IS NOT NULL\n"
	"            THEN format('%I', pkeys.attname)\n"
	"       END AS partkey\n"
	"\n"
	"  FROM pg_catalog.pg_class c\n"
	"  JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid\n"
	"  LEFT JOIN pg_catalog.pg_am ON c.relam = pg_am.oid\n"
	"  JOIN pg_roles auth ON auth.oid = c.relowner,\n"
	"       filters f\n"
	"\n"
	"-- find a copy partition key candidate\n"
	"  LEFT JOIN LATERAL (\n"
	"      SELECT indrelid, indexrelid, a.attname\n"
	"        FROM pg_index x\n"
	"        JOIN pg_class i ON i.oid = x.indexrelid\n"
	"        JOIN pg_attribute a\n"
	"          ON a.attrelid = c.oid AND attnum = indkey[0]\n"
	"       WHERE x.indrelid = c.oid\n"
	"         AND (indisprimary OR indisunique)\n"
	"         AND array_length(indkey::integer[], 1) = 1\n"
	"         AND atttypid IN ('smallint'::regtype, 'int'::regtype, 'bigint'::regtype)\n"
	"    ORDER BY NOT indisprimary, NOT indisunique\n"
	"       LIMIT 1\n"
	"  ) AS pkeys ON true\n"
	"\n"
	" WHERE c.relkind IN ('r', 'p', 'm') AND c.relpersistence IN ('p', 'u')\n"
	"   AND n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'\n"
	"   AND n.nspname !~ 'pgcopydb'\n"
	"   -- keep tables NOT matching any include-only-table entry\n"
	"   AND NOT (\n"
	"       EXISTS (SELECT 1 FROM unnest(f.incl_ee_nsp, f.incl_ee_rel) AS t(nsp, rel)\n"
	"               WHERE n.nspname = t.nsp AND c.relname = t.rel)\n"
	"    OR EXISTS (SELECT 1 FROM unnest(f.incl_er_nsp, f.incl_er_rel) AS t(nsp, rel_re)\n"
	"               WHERE n.nspname = t.nsp AND c.relname ~ t.rel_re)\n"
	"    OR EXISTS (SELECT 1 FROM unnest(f.incl_re_nsp, f.incl_re_rel) AS t(nsp_re, rel)\n"
	"               WHERE n.nspname ~ t.nsp_re AND c.relname = t.rel)\n"
	"    OR EXISTS (SELECT 1 FROM unnest(f.incl_rr_nsp, f.incl_rr_rel) AS t(nsp_re, rel_re)\n"
	"               WHERE n.nspname ~ t.nsp_re AND c.relname ~ t.rel_re)\n"
	"   )\n"
	"   -- extension guard\n"
	"   AND NOT EXISTS (\n"
	"       SELECT 1 FROM pg_depend d\n"
	"        WHERE d.classid = 'pg_class'::regclass\n"
	"          AND d.objid = c.oid AND d.deptype = 'e'\n"
	"   )\n"
	"\n"
	" ORDER BY n.nspname, c.relname\n"
;

static const char sql_list_schemas[] =
	"WITH filters AS (\n"
	"    SELECT $1::text[] AS incl_exact,\n"
	"           $2::text[] AS incl_re,\n"
	"           $3::text[] AS excl_exact,\n"
	"           $4::text[] AS excl_re\n"
	")\n"
	"SELECT n.oid,\n"
	"       n.nspname,\n"
	"       format('- %s %s',\n"
	"                regexp_replace(n.nspname, '[\\n\\r]', ' '),\n"
	"                regexp_replace(auth.rolname, '[\\n\\r]', ' '))\n"
	"  FROM pg_namespace n\n"
	"  JOIN pg_roles auth ON auth.oid = n.nspowner,\n"
	"       filters f\n"
	" WHERE n.nspname <> 'information_schema'\n"
	"   AND n.nspname !~ '^pg_'\n"
	"   AND n.nspname <> 'pgcopydb'\n"
	"   AND (\n"
	"       f.incl_exact IS NULL AND f.incl_re IS NULL\n"
	"       OR (f.incl_exact IS NOT NULL AND n.nspname = ANY(f.incl_exact))\n"
	"       OR (f.incl_re IS NOT NULL AND n.nspname ~ ANY(f.incl_re))\n"
	"   )\n"
	"   AND (f.excl_exact IS NULL OR n.nspname <> ALL(f.excl_exact))\n"
	"   AND (f.excl_re IS NULL OR NOT (n.nspname ~ ANY(f.excl_re)))\n"
	" ORDER BY n.nspname\n"
;

static const char sql_list_source_depend[] =
	"-- $1::oid[] : table OIDs from s_table (NULL means no filter)\n"
	"WITH RECURSIVE\n"
	"filters AS (\n"
	"    SELECT $1::oid[] AS table_oids\n"
	"),\n"
	"edges AS (\n"
	"SELECT\n"
	"    ARRAY[refclassid::int, refobjid::int, refobjsubid] AS from_obj,\n"
	"    ARRAY[classid::int, objid::int, objsubid] AS to_obj,\n"
	"    deptype\n"
	"FROM pg_catalog.pg_depend\n"
	"UNION\n"
	"SELECT\n"
	"    ARRAY[refclassid::int, refobjid::int, 0] AS from_obj,\n"
	"    ARRAY[refclassid::int, refobjid::int, refobjsubid] AS to_obj,\n"
	"    deptype\n"
	"FROM pg_catalog.pg_depend WHERE refobjsubid > 0\n"
	"UNION\n"
	"SELECT\n"
	"    ARRAY[classid::int, objid::int, 0] AS from_obj,\n"
	"    ARRAY[classid::int, objid::int, objsubid] AS to_obj,\n"
	"    deptype\n"
	"FROM pg_catalog.pg_depend WHERE objsubid > 0\n"
	"),\n"
	"objects_with_internal_objects AS (\n"
	"SELECT from_obj AS obj FROM edges WHERE deptype = 'i'\n"
	"EXCEPT\n"
	"SELECT to_obj FROM edges WHERE deptype = 'i'\n"
	"),\n"
	"objects_without_internal_objects AS (\n"
	"SELECT from_obj AS obj FROM edges WHERE deptype IN ('n','a')\n"
	"UNION\n"
	"SELECT to_obj AS obj FROM edges WHERE deptype IN ('n','a')\n"
	"EXCEPT\n"
	"SELECT obj FROM objects_with_internal_objects\n"
	"),\n"
	"find_internal_recursively AS (\n"
	"SELECT\n"
	"    objects_with_internal_objects.obj AS normal_obj,\n"
	"    objects_with_internal_objects.obj AS internal_obj\n"
	"FROM objects_with_internal_objects\n"
	"UNION ALL\n"
	"SELECT\n"
	"    find_internal_recursively.normal_obj,\n"
	"    edges.to_obj\n"
	"FROM find_internal_recursively\n"
	"JOIN edges ON (edges.deptype = 'i' AND edges.from_obj = find_internal_recursively.internal_obj)\n"
	"),\n"
	"remap_edges AS (\n"
	"SELECT\n"
	"COALESCE(remap_from.normal_obj,edges.from_obj) AS from_obj,\n"
	"COALESCE(remap_to.normal_obj,edges.to_obj) AS to_obj,\n"
	"edges.deptype\n"
	"FROM edges\n"
	"LEFT JOIN find_internal_recursively AS remap_from ON (edges.from_obj = remap_from.internal_obj)\n"
	"LEFT JOIN find_internal_recursively AS remap_to   ON (edges.to_obj   = remap_to.internal_obj)\n"
	"WHERE edges.deptype IN ('n','a')\n"
	"),\n"
	"unconcat AS (\n"
	"SELECT\n"
	"    from_obj[1]::oid AS refclassid,\n"
	"    from_obj[2]::oid AS refobjid,\n"
	"    from_obj[3]::integer AS refobjsubid,\n"
	"    to_obj[1]::oid AS classid,\n"
	"    to_obj[2]::oid AS objid,\n"
	"    to_obj[3]::integer AS objsubid,\n"
	"    deptype\n"
	"FROM remap_edges\n"
	")\n"
	"  SELECT cn.nspname, c.relname,\n"
	"         refclassid, refobjid, classid, objid,\n"
	"         deptype, type, identity\n"
	"    FROM unconcat\n"
	"\n"
	"         JOIN pg_class c\n"
	"           ON unconcat.refclassid = 'pg_class'::regclass\n"
	"          AND unconcat.refobjid = c.oid\n"
	"\n"
	"         JOIN pg_catalog.pg_namespace cn\n"
	"           ON c.relnamespace = cn.oid\n"
	"\n"
	"         CROSS JOIN filters f\n"
	"\n"
	"         , pg_identify_object(classid, objid, objsubid)\n"
	"\n"
	"   WHERE NOT (refclassid = classid AND refobjid = objid)\n"
	"     AND cn.nspname !~ '^pg_' AND cn.nspname <> 'information_schema'\n"
	"     AND cn.nspname !~ 'pgcopydb'\n"
	"     AND type NOT IN ('toast table column', 'default value')\n"
	"     -- table filter: restrict to included tables (or all when NULL)\n"
	"     AND (f.table_oids IS NULL OR c.oid = ANY(f.table_oids))\n"
	"\n"
	"GROUP BY cn.nspname, c.relname,\n"
	"         refclassid, refobjid, classid, objid, deptype, type, identity\n"
;

static const char sql_list_source_indexes[] =
	"-- $1::oid[]   : table OIDs from s_table (NULL means all tables)\n"
	"-- $2::text[], $3::text[] : excl_index nspname/relname paired arrays\n"
	"-- $4::boolean : true = filtersDB query (include excl indexes + indexes on excl tables)\n"
	"--               false = sourceDB query (exclude explicitly-excluded indexes)\n"
	"WITH filters AS (\n"
	"    SELECT $1::oid[]  AS table_oids,\n"
	"           $2::text[] AS excl_idx_nsp,\n"
	"           $3::text[] AS excl_idx_rel,\n"
	"           $4::boolean AS for_filter\n"
	")\n"
	"SELECT i.oid,\n"
	"       format('%I', n.nspname) AS inspname,\n"
	"       format('%I', i.relname) AS irelname,\n"
	"       r.oid,\n"
	"       format('%I', rn.nspname) AS rnspname,\n"
	"       format('%I', r.relname) AS rrelname,\n"
	"       indisprimary,\n"
	"       indisunique,\n"
	"       (SELECT string_agg(format('%I', attname), ',')\n"
	"          FROM pg_attribute\n"
	"         WHERE attrelid = r.oid\n"
	"           AND array[attnum::integer] <@ indkey::integer[]\n"
	"       ) AS cols,\n"
	"       pg_get_indexdef(indexrelid),\n"
	"       c.oid,\n"
	"       c.condeferrable,\n"
	"       c.condeferred,\n"
	"       CASE WHEN conname IS NOT NULL\n"
	"            THEN format('%I', c.conname)\n"
	"       END AS conname,\n"
	"       pg_get_constraintdef(c.oid),\n"
	"       format('%s %s %s',\n"
	"              regexp_replace(n.nspname, '[\\n\\r]', ' '),\n"
	"              regexp_replace(i.relname, '[\\n\\r]', ' '),\n"
	"              regexp_replace(auth.rolname, '[\\n\\r]', ' '))\n"
	"\n"
	"  FROM pg_index x\n"
	"  JOIN pg_class i ON i.oid = x.indexrelid\n"
	"  JOIN pg_class r ON r.oid = x.indrelid\n"
	"  JOIN pg_namespace n ON n.oid = i.relnamespace\n"
	"  JOIN pg_namespace rn ON rn.oid = r.relnamespace\n"
	"  JOIN pg_roles auth ON auth.oid = i.relowner\n"
	"  LEFT JOIN pg_depend d\n"
	"         ON d.classid = 'pg_class'::regclass\n"
	"        AND d.objid = i.oid\n"
	"        AND d.refclassid = 'pg_constraint'::regclass\n"
	"        AND d.deptype = 'i'\n"
	"  LEFT JOIN pg_constraint c ON c.oid = d.refobjid,\n"
	"       filters f\n"
	"\n"
	" WHERE r.relkind IN ('r', 'm') AND r.relpersistence IN ('p', 'u')\n"
	"   AND n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'\n"
	"   AND n.nspname !~ 'pgcopydb'\n"
	"   -- extension guard\n"
	"   AND NOT EXISTS (\n"
	"       SELECT 1 FROM pg_depend d2\n"
	"        WHERE d2.classid = 'pg_class'::regclass\n"
	"          AND d2.objid = r.oid AND d2.deptype = 'e'\n"
	"   )\n"
	"   AND (\n"
	"       -- sourceDB path: index on an in-scope table AND not in excl list\n"
	"       (NOT f.for_filter\n"
	"        AND (f.table_oids IS NULL OR r.oid = ANY(f.table_oids))\n"
	"        AND NOT EXISTS (SELECT 1 FROM unnest(f.excl_idx_nsp, f.excl_idx_rel) AS t(nsp, rel)\n"
	"                        WHERE n.nspname = t.nsp AND i.relname = t.rel)\n"
	"       )\n"
	"    OR\n"
	"       -- filtersDB path: index on excluded table OR explicitly excluded\n"
	"       (f.for_filter\n"
	"        AND (\n"
	"            r.oid = ANY(f.table_oids)\n"
	"            OR (f.excl_idx_nsp IS NOT NULL\n"
	"                AND EXISTS (SELECT 1 FROM unnest(f.excl_idx_nsp, f.excl_idx_rel) AS t(nsp, rel)\n"
	"                            WHERE n.nspname = t.nsp AND i.relname = t.rel))\n"
	"        )\n"
	"       )\n"
	"   )\n"
	"\n"
	" ORDER BY n.nspname, r.relname, i.relname\n"
;

static const char sql_list_source_sequences[] =
	"-- $1::oid[] : table OIDs from s_table (NULL means no table filter)\n"
	"-- $2::oid[] : namespace OIDs from s_namespace (NULL means no namespace filter)\n"
	"-- $3::oid[] : \"keep\" table OIDs — when non-empty, subtract sequences owned by\n"
	"--             or used as DEFAULT by a non-excluded table.  Used for\n"
	"--             SOURCE_FILTER_TYPE_LIST_EXCL to prevent landing sequences that\n"
	"--             belong to non-excluded tables (e.g. a partitioned parent,\n"
	"--             relkind='p', absent from s_table) into filtersDB.  Pass '{}'\n"
	"--             when no subtraction is needed.\n"
	"WITH\n"
	" filters AS (\n"
	"     SELECT $1::oid[] AS table_oids,\n"
	"            $2::oid[] AS namespace_oids,\n"
	"            $3::oid[] AS keep_table_oids\n"
	" ),\n"
	" seqs AS (\n"
	"    SELECT s.oid AS seqoid,\n"
	"           format('%I', sn.nspname) AS nspname,\n"
	"           format('%I', s.relname) AS relname,\n"
	"           format('%s %s %s',\n"
	"                  regexp_replace(sn.nspname, '[\\n\\r]', ' '),\n"
	"                  regexp_replace(s.relname, '[\\n\\r]', ' '),\n"
	"                  regexp_replace(auth.rolname, '[\\n\\r]', ' ')) AS restore_list_name,\n"
	"           sn.oid AS relnamespace\n"
	"\n"
	"      FROM pg_class s\n"
	"      JOIN pg_namespace sn ON sn.oid = s.relnamespace\n"
	"      JOIN pg_roles auth ON auth.oid = s.relowner\n"
	"\n"
	"     WHERE s.relkind = 'S'\n"
	"       AND sn.nspname !~ 'pgcopydb'\n"
	"       AND NOT EXISTS (\n"
	"           SELECT 1 FROM pg_depend d\n"
	"            WHERE d.classid = 'pg_class'::regclass\n"
	"              AND d.objid = s.oid\n"
	"              AND d.deptype = 'e'\n"
	"       )\n"
	" )\n"
	"SELECT s.seqoid,\n"
	"       s.nspname,\n"
	"       s.relname,\n"
	"       s.restore_list_name,\n"
	"       r1.oid              AS ownedby,\n"
	"       r2.oid              AS attrelid,\n"
	"       d2.attrdef_oid      AS attroid\n"
	"\n"
	"  FROM seqs AS s\n"
	"\n"
	"  -- Use LATERAL+LIMIT 1 to avoid duplicate rows when a sequence has both\n"
	"  -- deptype='a' (OWNED BY) and deptype='i' (internal) pg_depend entries,\n"
	"  -- which happens for SERIAL columns after pg_restore.  Prefer 'a' over 'i'.\n"
	"  LEFT JOIN LATERAL (\n"
	"      SELECT refobjid\n"
	"        FROM pg_depend\n"
	"       WHERE objid = s.seqoid\n"
	"         AND classid = 'pg_class'::regclass\n"
	"         AND refclassid = 'pg_class'::regclass\n"
	"         AND deptype IN ('i', 'a')\n"
	"       ORDER BY CASE deptype WHEN 'a' THEN 0 ELSE 1 END\n"
	"       LIMIT 1\n"
	"  ) d1 ON true\n"
	"\n"
	"  -- Use LATERAL+LIMIT 1 to avoid duplicate rows when a sequence is used as\n"
	"  -- DEFAULT for multiple columns (e.g. partitioned table + each partition).\n"
	"  LEFT JOIN LATERAL (\n"
	"      SELECT d2.objid AS attrdef_oid, at.attrelid\n"
	"        FROM pg_depend d2\n"
	"        JOIN pg_attrdef a  ON a.oid = d2.objid\n"
	"        JOIN pg_attribute at ON at.attrelid = a.adrelid AND at.attnum = a.adnum\n"
	"       WHERE d2.refobjid = s.seqoid\n"
	"         AND d2.refclassid = 'pg_class'::regclass\n"
	"         AND d2.classid = 'pg_attrdef'::regclass\n"
	"       ORDER BY at.attrelid\n"
	"       LIMIT 1\n"
	"  ) d2 ON true\n"
	"\n"
	"  LEFT JOIN pg_class r1 ON r1.oid = d1.refobjid\n"
	"  LEFT JOIN pg_class r2 ON r2.oid = d2.attrelid\n"
	"\n"
	"  CROSS JOIN filters f\n"
	"\n"
	" WHERE (\n"
	"     -- no filter: include all sequences\n"
	"     (f.table_oids IS NULL AND f.namespace_oids IS NULL)\n"
	"\n"
	"     -- standalone sequence: no ownership → filter by namespace\n"
	"  OR (r1.oid IS NULL AND r2.oid IS NULL\n"
	"      AND (f.namespace_oids IS NULL OR s.relnamespace = ANY(f.namespace_oids)))\n"
	"\n"
	"     -- sequence owned via OWNED BY relationship\n"
	"  OR (r1.oid IS NOT NULL\n"
	"      AND (f.table_oids IS NULL OR r1.oid = ANY(f.table_oids)))\n"
	"\n"
	"     -- sequence used as column DEFAULT (no table filter: include if any attrdef exists)\n"
	"  OR (r2.oid IS NOT NULL AND f.table_oids IS NULL)\n"
	"\n"
	"     -- sequence used as column DEFAULT (table filter active): use EXISTS to check ALL\n"
	"     -- tables using this sequence as default, not just the d2 LATERAL representative.\n"
	"     -- Needed when a sequence is OWNED BY a filtered-out table but used as DEFAULT\n"
	"     -- by an included table (e.g. LIKE ... INCLUDING ALL across schemas).\n"
	"  OR (f.table_oids IS NOT NULL\n"
	"      AND EXISTS (\n"
	"          SELECT 1\n"
	"            FROM pg_depend d2x\n"
	"            JOIN pg_attrdef a2 ON a2.oid = d2x.objid\n"
	"            JOIN pg_attribute at2 ON at2.attrelid = a2.adrelid AND at2.attnum = a2.adnum\n"
	"           WHERE d2x.refobjid = s.seqoid\n"
	"             AND d2x.refclassid = 'pg_class'::regclass\n"
	"             AND d2x.classid = 'pg_attrdef'::regclass\n"
	"             AND at2.attrelid = ANY(f.table_oids)\n"
	"      ))\n"
	" )\n"
	"\n"
	"   -- Subtract sequences that should not be placed into filtersDB.\n"
	"   -- When keep_table_oids is non-empty (LIST_EXCL complement queries), drop\n"
	"   -- any sequence that is \"owned\" (directly or via DEFAULT) by a non-excluded\n"
	"   -- table.  Two cases:\n"
	"   --\n"
	"   -- Case 1: sequence has an explicit OWNED BY (r1.oid IS NOT NULL) pointing\n"
	"   --         to a table that is NOT in the excluded set.\n"
	"   --\n"
	"   -- Case 2: sequence has no OWNED BY (r1.oid IS NULL) but at least one\n"
	"   --         non-excluded table uses it as a column DEFAULT.  This covers\n"
	"   --         partitioned parents whose child partitions are excluded but whose\n"
	"   --         parent is not.  For example, payment_payment_id_seq has no OWNED\n"
	"   --         BY in pagila but is DEFAULT on both payment (non-excluded) and\n"
	"   --         payment_p* (excluded).  Without this clause it lands in filtersDB\n"
	"   --         via condition 5 and catalog_prepare_filter wrongly suppresses\n"
	"   --         CREATE SEQUENCE, causing payment to fail with \"relation does not\n"
	"   --         exist\".  We scan ALL attrdef entries (not just the d2 LATERAL\n"
	"   --         pick) to avoid OID-order sensitivity.\n"
	" AND NOT (\n"
	"     f.keep_table_oids IS NOT NULL\n"
	"     AND cardinality(f.keep_table_oids) > 0\n"
	"     AND (\n"
	"         (r1.oid IS NOT NULL AND NOT r1.oid = ANY(f.table_oids))\n"
	"         OR (r1.oid IS NULL AND EXISTS (\n"
	"             SELECT 1\n"
	"               FROM pg_depend d3\n"
	"               JOIN pg_attrdef a3 ON a3.oid = d3.objid\n"
	"               JOIN pg_attribute at3 ON at3.attrelid = a3.adrelid\n"
	"                AND at3.attnum = a3.adnum\n"
	"              WHERE d3.refobjid = s.seqoid\n"
	"                AND d3.refclassid = 'pg_class'::regclass\n"
	"                AND d3.classid = 'pg_attrdef'::regclass\n"
	"                AND NOT at3.attrelid = ANY(f.table_oids)\n"
	"         ))\n"
	"     )\n"
	" )\n"
	"\n"
	" ORDER BY nspname, relname\n"
;

static const char sql_list_source_table_size[] =
	"-- $1::oid[] : table OIDs from s_table (NULL means all tables)\n"
	"WITH filters AS (\n"
	"    SELECT $1::oid[] AS table_oids\n"
	")\n"
	"SELECT c.oid,\n"
	"       pg_table_size(c.oid) AS bytes,\n"
	"       pg_size_pretty(pg_table_size(c.oid))\n"
	"\n"
	"  FROM pg_catalog.pg_class c\n"
	"  JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid,\n"
	"       filters f\n"
	"\n"
	" WHERE c.relkind = 'r' AND c.relpersistence IN ('p', 'u')\n"
	"   AND n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'\n"
	"   -- table filter: restrict to included tables (or all when NULL)\n"
	"   AND (f.table_oids IS NULL OR c.oid = ANY(f.table_oids))\n"
	"   -- extension guard\n"
	"   AND NOT EXISTS (\n"
	"       SELECT 1 FROM pg_depend d\n"
	"        WHERE d.classid = 'pg_class'::regclass\n"
	"          AND d.objid = c.oid AND d.deptype = 'e'\n"
	"   )\n"
;

static const char sql_list_source_tables[] =
	"WITH filters AS (\n"
	"    SELECT\n"
	"        -- namespace OIDs from s_namespace (included schemas only)\n"
	"        $1::oid[]  AS nsp_oids,\n"
	"        -- include-only table: exact nsp + exact rel\n"
	"        $2::text[] AS incl_ee_nsp,  $3::text[] AS incl_ee_rel,\n"
	"        -- include-only table: exact nsp + regex rel\n"
	"        $4::text[] AS incl_er_nsp,  $5::text[] AS incl_er_rel,\n"
	"        -- include-only table: regex nsp + exact rel\n"
	"        $6::text[] AS incl_re_nsp, $7::text[] AS incl_re_rel,\n"
	"        -- include-only table: regex nsp + regex rel\n"
	"        $8::text[] AS incl_rr_nsp, $9::text[] AS incl_rr_rel,\n"
	"        -- exclude table: exact nsp + exact rel\n"
	"        $10::text[] AS excl_ee_nsp, $11::text[] AS excl_ee_rel,\n"
	"        -- exclude table: exact nsp + regex rel\n"
	"        $12::text[] AS excl_er_nsp, $13::text[] AS excl_er_rel,\n"
	"        -- exclude table: regex nsp + exact rel\n"
	"        $14::text[] AS excl_re_nsp, $15::text[] AS excl_re_rel,\n"
	"        -- exclude table: regex nsp + regex rel\n"
	"        $16::text[] AS excl_rr_nsp, $17::text[] AS excl_rr_rel,\n"
	"        -- exclude-data: exact nsp + exact rel\n"
	"        $18::text[] AS xdat_ee_nsp, $19::text[] AS xdat_ee_rel,\n"
	"        -- exclude-data: exact nsp + regex rel\n"
	"        $20::text[] AS xdat_er_nsp, $21::text[] AS xdat_er_rel,\n"
	"        -- exclude-data: regex nsp + exact rel\n"
	"        $22::text[] AS xdat_re_nsp, $23::text[] AS xdat_re_rel,\n"
	"        -- exclude-data: regex nsp + regex rel\n"
	"        $24::text[] AS xdat_rr_nsp, $25::text[] AS xdat_rr_rel\n"
	")\n"
	"SELECT c.oid,\n"
	"       format('%I', n.nspname) AS nspname,\n"
	"       format('%I', c.relname) AS relname,\n"
	"       c.relkind AS relkind,\n"
	"       pg_am.amname,\n"
	"       c.relpages, c.reltuples::bigint,\n"
	"       c.relpages * current_setting('block_size')::bigint AS bytesestimate,\n"
	"       pg_size_pretty(c.relpages * current_setting('block_size')::bigint),\n"
	"       -- exclude-data: true if table matches any exclude-data entry\n"
	"       (\n"
	"           EXISTS (SELECT 1 FROM unnest(f.xdat_ee_nsp, f.xdat_ee_rel) AS t(nsp, rel)\n"
	"                   WHERE n.nspname = t.nsp AND c.relname = t.rel)\n"
	"        OR EXISTS (SELECT 1 FROM unnest(f.xdat_er_nsp, f.xdat_er_rel) AS t(nsp, rel_re)\n"
	"                   WHERE n.nspname = t.nsp AND c.relname ~ t.rel_re)\n"
	"        OR EXISTS (SELECT 1 FROM unnest(f.xdat_re_nsp, f.xdat_re_rel) AS t(nsp_re, rel)\n"
	"                   WHERE n.nspname ~ t.nsp_re AND c.relname = t.rel)\n"
	"        OR EXISTS (SELECT 1 FROM unnest(f.xdat_rr_nsp, f.xdat_rr_rel) AS t(nsp_re, rel_re)\n"
	"                   WHERE n.nspname ~ t.nsp_re AND c.relname ~ t.rel_re)\n"
	"       ) AS excludedata,\n"
	"       format('%s %s %s',\n"
	"              regexp_replace(n.nspname, '[\\n\\r]', ' '),\n"
	"              regexp_replace(c.relname, '[\\n\\r]', ' '),\n"
	"              regexp_replace(auth.rolname, '[\\n\\r]', ' ')),\n"
	"       CASE WHEN pkeys.attname IS NOT NULL\n"
	"            THEN format('%I', pkeys.attname)\n"
	"       END AS partkey\n"
	"\n"
	"  FROM pg_catalog.pg_class c\n"
	"  JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid\n"
	"  LEFT JOIN pg_catalog.pg_am ON c.relam = pg_am.oid\n"
	"  JOIN pg_roles auth ON auth.oid = c.relowner,\n"
	"       filters f\n"
	"\n"
	"-- find a copy partition key candidate\n"
	"  LEFT JOIN LATERAL (\n"
	"      SELECT indrelid, indexrelid, a.attname\n"
	"        FROM pg_index x\n"
	"        JOIN pg_class i ON i.oid = x.indexrelid\n"
	"        JOIN pg_attribute a\n"
	"          ON a.attrelid = c.oid AND attnum = indkey[0]\n"
	"       WHERE x.indrelid = c.oid\n"
	"         AND (indisprimary OR indisunique)\n"
	"         AND array_length(indkey::integer[], 1) = 1\n"
	"         AND atttypid IN ('smallint'::regtype, 'int'::regtype, 'bigint'::regtype)\n"
	"    ORDER BY NOT indisprimary, NOT indisunique\n"
	"       LIMIT 1\n"
	"  ) AS pkeys ON true\n"
	"\n"
	" WHERE c.relkind IN ('r', 'm') AND c.relpersistence IN ('p', 'u')\n"
	"   AND n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'\n"
	"   AND n.nspname !~ 'pgcopydb'\n"
	"   -- namespace filter: restrict to included schemas\n"
	"   AND n.oid = ANY(f.nsp_oids)\n"
	"   -- include-only table filter: pass when no include-only constraints, or table matches one\n"
	"   AND (\n"
	"       f.incl_ee_nsp IS NULL AND f.incl_er_nsp IS NULL\n"
	"       AND f.incl_re_nsp IS NULL AND f.incl_rr_nsp IS NULL\n"
	"    OR EXISTS (SELECT 1 FROM unnest(f.incl_ee_nsp, f.incl_ee_rel) AS t(nsp, rel)\n"
	"               WHERE n.nspname = t.nsp AND c.relname = t.rel)\n"
	"    OR EXISTS (SELECT 1 FROM unnest(f.incl_er_nsp, f.incl_er_rel) AS t(nsp, rel_re)\n"
	"               WHERE n.nspname = t.nsp AND c.relname ~ t.rel_re)\n"
	"    OR EXISTS (SELECT 1 FROM unnest(f.incl_re_nsp, f.incl_re_rel) AS t(nsp_re, rel)\n"
	"               WHERE n.nspname ~ t.nsp_re AND c.relname = t.rel)\n"
	"    OR EXISTS (SELECT 1 FROM unnest(f.incl_rr_nsp, f.incl_rr_rel) AS t(nsp_re, rel_re)\n"
	"               WHERE n.nspname ~ t.nsp_re AND c.relname ~ t.rel_re)\n"
	"   )\n"
	"   -- exclude table filter: reject tables that match any exclude entry\n"
	"   AND NOT (\n"
	"       EXISTS (SELECT 1 FROM unnest(f.excl_ee_nsp, f.excl_ee_rel) AS t(nsp, rel)\n"
	"               WHERE n.nspname = t.nsp AND c.relname = t.rel)\n"
	"    OR EXISTS (SELECT 1 FROM unnest(f.excl_er_nsp, f.excl_er_rel) AS t(nsp, rel_re)\n"
	"               WHERE n.nspname = t.nsp AND c.relname ~ t.rel_re)\n"
	"    OR EXISTS (SELECT 1 FROM unnest(f.excl_re_nsp, f.excl_re_rel) AS t(nsp_re, rel)\n"
	"               WHERE n.nspname ~ t.nsp_re AND c.relname = t.rel)\n"
	"    OR EXISTS (SELECT 1 FROM unnest(f.excl_rr_nsp, f.excl_rr_rel) AS t(nsp_re, rel_re)\n"
	"               WHERE n.nspname ~ t.nsp_re AND c.relname ~ t.rel_re)\n"
	"   )\n"
	"   -- extension guard\n"
	"   AND NOT EXISTS (\n"
	"       SELECT 1 FROM pg_depend d\n"
	"        WHERE d.classid = 'pg_class'::regclass\n"
	"          AND d.objid = c.oid AND d.deptype = 'e'\n"
	"   )\n"
	"\n"
	" ORDER BY n.nspname, c.relname\n"
;

static const char sql_list_table_attributes[] =
	"with recursive\n"
	"\n"
	"-- Resolve binary I/O support for each distinct column type used across the\n"
	"-- selected tables.  Running the recursive walk once per distinct type (rather\n"
	"-- than once per column via LATERAL) keeps cost proportional to the number of\n"
	"-- distinct types, not the number of columns.\n"
	"resolved(\n"
	"    root_typid,\n"
	"    oid, typtype, typsend, typreceive,\n"
	"    typbasetype, typelem, typrelid,\n"
	"    typsendfunc, depth, followed_array\n"
	") as (\n"
	"    select t.oid,\n"
	"           t.oid, t.typtype,\n"
	"           t.typsend, t.typreceive,\n"
	"           t.typbasetype, t.typelem, t.typrelid,\n"
	"           p.proname::text,\n"
	"           0, false\n"
	"      from (\n"
	"          select distinct a.atttypid\n"
	"            from pg_attribute a\n"
	"           where a.attrelid = any($1::oid[])\n"
	"             and not a.attisdropped\n"
	"             and a.attnum > 0\n"
	"      ) dt\n"
	"      join pg_type t on t.oid = dt.atttypid\n"
	"      left join pg_proc p on p.oid = t.typsend\n"
	"\n"
	"-- Single recursive arm covering domain-follow and array-element unwrap.\n"
	"    union all\n"
	"\n"
	"    select r.root_typid,\n"
	"           t.oid, t.typtype,\n"
	"           t.typsend, t.typreceive,\n"
	"           t.typbasetype, t.typelem, t.typrelid,\n"
	"           p.proname::text,\n"
	"           r.depth + 1,\n"
	"           case when r.typtype = 'd'\n"
	"                then r.followed_array\n"
	"                else true end\n"
	"      from resolved r\n"
	"      join pg_type t\n"
	"        on (\n"
	"             t.oid = r.typbasetype\n"
	"             and r.typtype = 'd'\n"
	"           )\n"
	"           or (\n"
	"                t.oid = r.typelem\n"
	"                and r.typelem <> 0\n"
	"                and r.typtype <> 'd'\n"
	"                and not r.followed_array\n"
	"              )\n"
	"      left join pg_proc p on p.oid = t.typsend\n"
	"     where r.depth < 10\n"
	"),\n"
	"\n"
	"composite_attrs(root_typid, typsendfunc) as (\n"
	"    select distinct r.root_typid, cp.proname\n"
	"      from resolved r\n"
	"      join pg_attribute ca\n"
	"        on ca.attrelid = r.typrelid\n"
	"       and ca.attnum > 0\n"
	"       and not ca.attisdropped\n"
	"      join pg_type ct on ct.oid = ca.atttypid\n"
	"      join pg_proc cp on cp.oid = ct.typsend\n"
	"     where r.typtype = 'c'\n"
	"),\n"
	"\n"
	"all_send_funcs(root_typid, typsendfunc) as (\n"
	"    select root_typid, typsendfunc\n"
	"      from resolved\n"
	"     where typsendfunc is not null\n"
	"    union\n"
	"    select root_typid, typsendfunc\n"
	"      from composite_attrs\n"
	"),\n"
	"\n"
	"-- One row per distinct type: hasbinaryio and comma-separated send func names\n"
	"-- for C-side blocklist checking.\n"
	"type_bincompat(atttypid, hasbinaryio, typsendfunc) as (\n"
	"    select r.root_typid,\n"
	"           bool_and(r.typsend <> 0 and r.typreceive <> 0) as hasbinaryio,\n"
	"           (\n"
	"               select string_agg(f.typsendfunc, ',')\n"
	"                 from all_send_funcs f\n"
	"                where f.root_typid = r.root_typid\n"
	"           ) as typsendfunc\n"
	"      from resolved r\n"
	"     group by r.root_typid\n"
	")\n"
	"\n"
	"select a.attrelid,\n"
	"       a.attnum,\n"
	"       a.atttypid::integer,\n"
	"       format('%I', a.attname) as attname,\n"
	"       i.indrelid is not null as attisprimary,\n"
	"       ri.indrelid is not null as attisreplident,\n"
	"       col.is_generated = 'ALWAYS' as attisgenerated,\n"
	"       coalesce(a.attidentity, '') as attidentity,\n"
	"       tb.hasbinaryio,\n"
	"       tb.typsendfunc\n"
	"\n"
	"  from pg_attribute a\n"
	"       join pg_class c on c.oid = a.attrelid\n"
	"       join pg_namespace n on n.oid = c.relnamespace\n"
	"       left join pg_index i\n"
	"              on i.indrelid = a.attrelid\n"
	"             and a.attnum = ANY(i.indkey)\n"
	"             and i.indisprimary\n"
	"       left join pg_index ri\n"
	"              on ri.indrelid = a.attrelid\n"
	"             and a.attnum = ANY(ri.indkey)\n"
	"             and ri.indisreplident\n"
	"       left join information_schema.columns col\n"
	"              on col.column_name = a.attname\n"
	"             and col.table_name = c.relname\n"
	"             and col.table_schema = n.nspname\n"
	"       join type_bincompat tb on tb.atttypid = a.atttypid\n"
	"\n"
	" where a.attrelid = any($1::oid[])\n"
	"   and not a.attisdropped\n"
	"   and a.attnum > 0\n"
	"\n"
	" order by a.attrelid, a.attnum\n"
;

static const char sql_list_table_attributes_pg96[] =
	"with recursive\n"
	"\n"
	"-- Resolve binary I/O support for each distinct column type used across the\n"
	"-- selected tables.  Running the recursive walk once per distinct type (rather\n"
	"-- than once per column via LATERAL) keeps cost proportional to the number of\n"
	"-- distinct types, not the number of columns.\n"
	"resolved(\n"
	"    root_typid,\n"
	"    oid, typtype, typsend, typreceive,\n"
	"    typbasetype, typelem, typrelid,\n"
	"    typsendfunc, depth, followed_array\n"
	") as (\n"
	"    select t.oid,\n"
	"           t.oid, t.typtype,\n"
	"           t.typsend, t.typreceive,\n"
	"           t.typbasetype, t.typelem, t.typrelid,\n"
	"           p.proname::text,\n"
	"           0, false\n"
	"      from (\n"
	"          select distinct a.atttypid\n"
	"            from pg_attribute a\n"
	"           where a.attrelid = any($1::oid[])\n"
	"             and not a.attisdropped\n"
	"             and a.attnum > 0\n"
	"      ) dt\n"
	"      join pg_type t on t.oid = dt.atttypid\n"
	"      left join pg_proc p on p.oid = t.typsend\n"
	"\n"
	"-- Single recursive arm covering domain-follow and array-element unwrap.\n"
	"    union all\n"
	"\n"
	"    select r.root_typid,\n"
	"           t.oid, t.typtype,\n"
	"           t.typsend, t.typreceive,\n"
	"           t.typbasetype, t.typelem, t.typrelid,\n"
	"           p.proname::text,\n"
	"           r.depth + 1,\n"
	"           case when r.typtype = 'd'\n"
	"                then r.followed_array\n"
	"                else true end\n"
	"      from resolved r\n"
	"      join pg_type t\n"
	"        on (\n"
	"             t.oid = r.typbasetype\n"
	"             and r.typtype = 'd'\n"
	"           )\n"
	"           or (\n"
	"                t.oid = r.typelem\n"
	"                and r.typelem <> 0\n"
	"                and r.typtype <> 'd'\n"
	"                and not r.followed_array\n"
	"              )\n"
	"      left join pg_proc p on p.oid = t.typsend\n"
	"     where r.depth < 10\n"
	"),\n"
	"\n"
	"composite_attrs(root_typid, typsendfunc) as (\n"
	"    select distinct r.root_typid, cp.proname\n"
	"      from resolved r\n"
	"      join pg_attribute ca\n"
	"        on ca.attrelid = r.typrelid\n"
	"       and ca.attnum > 0\n"
	"       and not ca.attisdropped\n"
	"      join pg_type ct on ct.oid = ca.atttypid\n"
	"      join pg_proc cp on cp.oid = ct.typsend\n"
	"     where r.typtype = 'c'\n"
	"),\n"
	"\n"
	"all_send_funcs(root_typid, typsendfunc) as (\n"
	"    select root_typid, typsendfunc\n"
	"      from resolved\n"
	"     where typsendfunc is not null\n"
	"    union\n"
	"    select root_typid, typsendfunc\n"
	"      from composite_attrs\n"
	"),\n"
	"\n"
	"-- One row per distinct type: hasbinaryio and comma-separated send func names\n"
	"-- for C-side blocklist checking.\n"
	"type_bincompat(atttypid, hasbinaryio, typsendfunc) as (\n"
	"    select r.root_typid,\n"
	"           bool_and(r.typsend <> 0 and r.typreceive <> 0) as hasbinaryio,\n"
	"           (\n"
	"               select string_agg(f.typsendfunc, ',')\n"
	"                 from all_send_funcs f\n"
	"                where f.root_typid = r.root_typid\n"
	"           ) as typsendfunc\n"
	"      from resolved r\n"
	"     group by r.root_typid\n"
	")\n"
	"\n"
	"select a.attrelid,\n"
	"       a.attnum,\n"
	"       a.atttypid::integer,\n"
	"       format('%I', a.attname) as attname,\n"
	"       i.indrelid is not null as attisprimary,\n"
	"       ri.indrelid is not null as attisreplident,\n"
	"       col.is_generated = 'ALWAYS' as attisgenerated,\n"
	"       '' as attidentity,\n"
	"       tb.hasbinaryio,\n"
	"       tb.typsendfunc\n"
	"\n"
	"  from pg_attribute a\n"
	"       join pg_class c on c.oid = a.attrelid\n"
	"       join pg_namespace n on n.oid = c.relnamespace\n"
	"       left join pg_index i\n"
	"              on i.indrelid = a.attrelid\n"
	"             and a.attnum = ANY(i.indkey)\n"
	"             and i.indisprimary\n"
	"       left join pg_index ri\n"
	"              on ri.indrelid = a.attrelid\n"
	"             and a.attnum = ANY(ri.indkey)\n"
	"             and ri.indisreplident\n"
	"       left join information_schema.columns col\n"
	"              on col.column_name = a.attname\n"
	"             and col.table_name = c.relname\n"
	"             and col.table_schema = n.nspname\n"
	"       join type_bincompat tb on tb.atttypid = a.atttypid\n"
	"\n"
	" where a.attrelid = any($1::oid[])\n"
	"   and not a.attisdropped\n"
	"   and a.attnum > 0\n"
	"\n"
	" order by a.attrelid, a.attnum\n"
;
