@@ -421,20 +421,20 @@ BEGIN
421
421
END $$ LANGUAGE plpgsql STRICT;
422
422
423
423
-- Drop all foreign server's options. Yes, I don't know simpler ways.
424
- CREATE FUNCTION reset_foreign_server_opts (sname name) RETURNS void AS $$
424
+ CREATE FUNCTION reset_foreign_server_opts (server_name name) RETURNS void AS $$
425
425
DECLARE
426
426
opts text [];
427
427
opt text ;
428
428
opt_key text ;
429
429
BEGIN
430
- ASSERT EXISTS (SELECT 1 FROM pg_foreign_server WHERE srvname = sname );
430
+ ASSERT EXISTS (SELECT 1 from pg_foreign_server WHERE srvname= server_name );
431
431
EXECUTE format($q$SELECT coalesce(srvoptions, ' {}' ::text []) FROM
432
432
pg_foreign_server WHERE srvname = %L$q$,
433
- sname ) INTO opts;
434
- FOREACH opt IN ARRAY opts LOOP
435
- opt_key := regexp_replace(substring (opt from ' ^.*?=' ), ' =$' , ' ' );
436
- EXECUTE format(' ALTER SERVER %I OPTIONS (DROP %s);' , sname , opt_key);
437
- END LOOP;
433
+ server_name ) INTO opts;
434
+ FOREACH opt IN ARRAY opts LOOP
435
+ opt_key := regexp_replace(substring (opt from ' ^.*?=' ), ' =$' , ' ' );
436
+ EXECUTE format(' ALTER SERVER %I OPTIONS (DROP %s);' , server_name , opt_key);
437
+ END LOOP;
438
438
END $$ LANGUAGE plpgsql STRICT;
439
439
-- Same for resetting user mapping opts
440
440
CREATE or replace FUNCTION reset_um_opts (srvname name, umuser regrole)
@@ -449,19 +449,53 @@ BEGIN
449
449
ON fs .oid = ums .umserver WHERE fs .srvname = %L AND
450
450
ums .umuser = umuser$q$, srvname)
451
451
INTO opts;
452
-
453
- FOREACH opt IN ARRAY opts LOOP
454
- opt_key := regexp_replace(substring (opt from ' ^.*?=' ), ' =$' , ' ' );
455
- EXECUTE format(' ALTER USER MAPPING FOR %I SERVER %I OPTIONS (DROP %s);' ,
452
+ IF opts IS NOT NULL THEN
453
+ FOREACH opt IN ARRAY opts LOOP
454
+ opt_key := regexp_replace(substring (opt from ' ^.*?=' ), ' =$' , ' ' );
455
+ EXECUTE format(' ALTER USER MAPPING FOR %I SERVER %I OPTIONS (DROP %s);' ,
456
456
umuser::name, srvname, opt_key);
457
- END LOOP;
457
+ END LOOP;
458
+ END IF;
459
+ END $$ LANGUAGE plpgsql STRICT;
460
+
461
+ CREATE FUNCTION create_foreign_server (node_id integer ) RETURNS void AS $$
462
+ DECLARE
463
+ connstring text ;
464
+ server_opts text ;
465
+ um_opts text ;
466
+ server_name text ;
467
+ BEGIN
468
+ SELECT nodes .connstring FROM shardman .nodes WHERE id = node_id
469
+ INTO connstring;
470
+ SELECT * FROM shardman .conninfo_to_postgres_fdw_opts (connstring)
471
+ INTO server_opts, um_opts;
472
+ server_name := ' node_' || node_id;
473
+ IF NOT EXISTS (SELECT 1 from pg_foreign_server WHERE srvname= server_name)
474
+ THEN
475
+ RAISE DEBUG ' Create foreign server % for with options %' , server_name, server_opts;
476
+ EXECUTE format(' CREATE SERVER %I FOREIGN DATA WRAPPER postgres_fdw %s;' ,
477
+ server_name, server_opts);
478
+ -- TODO: support not only CURRENT_USER
479
+ EXECUTE format(' CREATE USER MAPPING FOR CURRENT_USER SERVER %I %s;' ,
480
+ server_name, um_opts);
481
+ ELSE
482
+ RAISE DEBUG ' Use existed foreign server % with options %' , server_name, server_opts;
483
+ PERFORM shardman .reset_foreign_server_opts (server_name);
484
+ PERFORM shardman .reset_um_opts (server_name, current_user ::regrole);
485
+
486
+ IF server_opts != ' ' THEN
487
+ EXECUTE format(' ALTER SERVER %I %s' , server_name, server_opts);
488
+ END IF;
489
+ IF um_opts != ' ' THEN
490
+ EXECUTE format(' ALTER USER MAPPING FOR CURRENT_USER SERVER %I %s' ,
491
+ server_name, um_opts);
492
+ END IF;
493
+ END IF;
458
494
END $$ LANGUAGE plpgsql STRICT;
459
495
460
496
-- Update foreign server and user mapping params on current node according to
461
497
-- partition part, so this is expected to be called on server/um params
462
- -- change. We use dedicated server for each partition because we plan to use
463
- -- multiple hosts/ports in connstrings for transient fallback to replica if
464
- -- server with main partition fails. FDW server, user mapping, foreign table and
498
+ -- change. FDW server, user mapping, foreign table and
465
499
-- (obviously) parent partition must exist when called if they need to be
466
500
-- updated; however, it is ok to call this func on nodes which don't need fdw
467
501
-- setup for this part because they hold primary partition.
@@ -472,6 +506,8 @@ DECLARE
472
506
um_opts text ;
473
507
me int := shardman .my_id ();
474
508
my_part shardman .partitions ;
509
+ server_oid oid ;
510
+ foreign_table_oid oid ;
475
511
BEGIN
476
512
RAISE DEBUG ' [SHMN] update_fdw_server called for part %, owner %' ,
477
513
part .part_name , part .owner ;
@@ -487,24 +523,11 @@ BEGIN
487
523
END IF;
488
524
END IF;
489
525
490
- SELECT nodes .connstring FROM shardman .nodes WHERE id = part .owner
491
- INTO connstring;
492
- SELECT * FROM shardman .conninfo_to_postgres_fdw_opts (connstring)
493
- INTO server_opts, um_opts;
494
-
495
- -- ALTER FOREIGN TABLE doesn't support changing server, ALTER SERVER doesn't
496
- -- support dropping all params, and I don't want to recreate foreign table
497
- -- each time server params change, so resorting to these hacks.
498
- PERFORM shardman .reset_foreign_server_opts (part .part_name );
499
- PERFORM shardman .reset_um_opts (part .part_name , current_user ::regrole);
526
+ PERFORM shardman .create_foreign_server (part .owner );
500
527
501
- IF server_opts != ' ' THEN
502
- EXECUTE format(' ALTER SERVER %I %s' , part .part_name , server_opts);
503
- END IF;
504
- IF um_opts != ' ' THEN
505
- EXECUTE format(' ALTER USER MAPPING FOR CURRENT_USER SERVER %I %s' ,
506
- part .part_name , um_opts);
507
- END IF;
528
+ SELECT oid FROM pg_foreign_server WHERE srvname= ' node_' || part .owner into server_oid;
529
+ SELECT oid FROM pg_class WHERE relname= part .part_name || ' _fdw' into foreign_table_oid;
530
+ UPDATE pg_foreign_table SET ftserver = server_oid WHERE ftrelid = foreign_table_oid;
508
531
END $$ LANGUAGE plpgsql STRICT;
509
532
510
533
-- Replace existing hash partition with foreign, assuming 'partition' shows
@@ -514,23 +537,11 @@ CREATE FUNCTION replace_usual_part_with_foreign(part partitions)
514
537
DECLARE
515
538
connstring text ;
516
539
fdw_part_name text ;
517
- server_opts text ;
518
- um_opts text ;
540
+ server_name text ;
519
541
BEGIN
520
- EXECUTE format(' DROP SERVER IF EXISTS %I CASCADE;' , part .part_name );
521
-
522
- SELECT nodes .connstring FROM shardman .nodes WHERE id = part .owner
523
- INTO connstring;
524
- SELECT * FROM shardman .conninfo_to_postgres_fdw_opts (connstring)
525
- INTO server_opts, um_opts;
542
+ server_name := ' node_' || part .owner ;
543
+ PERFORM shardman .create_foreign_server (part .owner );
526
544
527
- EXECUTE format(' CREATE SERVER %I FOREIGN DATA WRAPPER
528
- postgres_fdw %s;' , part .part_name , server_opts);
529
- EXECUTE format(' DROP USER MAPPING IF EXISTS FOR CURRENT_USER SERVER %I;' ,
530
- part .part_name );
531
- -- TODO: support not only CURRENT_USER
532
- EXECUTE format(' CREATE USER MAPPING FOR CURRENT_USER SERVER %I
533
- %s;' , part .part_name , um_opts);
534
545
SELECT shardman .get_fdw_part_name (part .part_name ) INTO fdw_part_name;
535
546
EXECUTE format(' DROP FOREIGN TABLE IF EXISTS %I;' , fdw_part_name);
536
547
@@ -552,7 +563,7 @@ BEGIN
552
563
(SELECT
553
564
shardman .reconstruct_table_attrs (
554
565
format(' %I' , part .relation ))),
555
- part . part_name ,
566
+ server_name ,
556
567
part .part_name );
557
568
-- replace local partition with foreign table
558
569
EXECUTE format(' SELECT replace_hash_partition(%L, %L)' ,
0 commit comments