Link Search Menu Expand Document Documentation Menu

Migrating partitioned tables to Babelfish

Note: This workaround applies to Babelfish clusters running in single-db mode.

The primary difference between partitioned tables created on the Babelfish TDS port and partitioned tables created on the PostgreSQL port is the table owner. The examples that follow demonstrate changing the owner of the tables created on the PostgreSQL port to dbo, so you can access the tables on both the Babelfish port and the PostgreSQL port.

Range Partitioning Example

The example that follows creates and tests a partitioned table with two partitions. First, use pgAdmin (on the PostgreSQL port) to create the table:

DROP TABLE IF EXISTS dbo.PartitionTest;
DROP TABLE IF EXISTS dbo.PartitionTest_y2022m01;
DROP TABLE IF EXISTS dbo.PartitionTest_y2022m02;
DROP INDEX dbo.partitiontest_logdate_idx;`

CREATE TABLE IF NOT EXISTS dbo.PartitionTest
(
    city_id integer NOT NULL,
    logdate date NOT NULL,
    peaktemp integer,
    unitsales integer
) PARTITION BY RANGE (logdate);

CREATE INDEX PartitionTest_logdate_idx
    ON dbo.PartitionTest(logdate ASC NULLS LAST);

Then, create the partitions:

CREATE TABLE IF NOT EXISTS dbo.PartitionTest_y2022m01 PARTITION OF dbo.PartitionTest
    FOR VALUES FROM ('2022-01-01') TO ('2022-02-01');
    
CREATE TABLE IF NOT EXISTS dbo.PartitionTest_y2022m02 PARTITION OF dbo.PartitionTest
    FOR VALUES FROM ('2022-02-01') TO ('2022-03-01');

Then, use pgAdmin to add data:

INSERT INTO dbo.partitiontest VALUES (1,'2022-01-01',1,1);
INSERT INTO dbo.partitiontest VALUES (2,'2022-01-10',1,2);
INSERT INTO dbo.partitiontest VALUES (3,'2022-01-15',1,3);
INSERT INTO dbo.partitiontest VALUES (4,'2022-02-01',2,1);
INSERT INTO dbo.partitiontest VALUES (5,'2022-02-03',2,2);
INSERT INTO dbo.partitiontest VALUES (6,'2022-02-11',2,3);
INSERT INTO dbo.partitiontest VALUES (7,'2022-02-15',2,4);
INSERT INTO dbo.partitiontest VALUES (8,'2022-02-16',2,5);
INSERT INTO dbo.partitiontest VALUES (8,'2022-02-17',2,6);
INSERT INTO dbo.partitiontest VALUES (8,'2022-02-20',2,7);
INSERT INTO dbo.partitiontest VALUES (8,'2022-02-21',2,8);

When you query the data from pgAdmin and Babelfish:

SELECT * FROM dbo.partitiontest  

• pgAdmin (on the PostgreSQL port) will display all the data. • SSMS (on the Babelfish port) will display the following error message and the object browser will not display the table name:

Msg 33557097, Level 16, State 1, Line 3
relation "master_dbo.partitiontest" does not exist

Use pgAdmin (on the PostgreSQL port) to change the table owner to dbo:

ALTER TABLE dbo.partitiontest OWNER to dbo;
ALTER TABLE dbo.partitiontest_y2022m01 OWNER to dbo;
ALTER TABLE dbo.partitiontest_y2022m02 OWNER to dbo;

Then, when you query the data from pgAdmin and SSMS:

SELECT * FROM dbo.partitiontest
  • pgAdmin (on the PostgreSQL port) will display all the data.
  • SSMS (on the Babelfish port) will display the data and you should see the tables in the object browser.

Analyzing the result set

First, query the database using SSMS on the TDS port:

SET BABELFISH_SHOWPLAN_ALL ON

SELECT * FROM dbo.partitiontest WHERE logdate = '2022-02-21'

Query Text: Select * from dbo.partitiontest where logdate = '2022-02-21'
Bitmap Heap Scan on partitiontest_y2022m02 partitiontest  (cost=4.22..14.76 rows=9 width=16)
  Recheck Cond: (logdate = '2022-02-21'::date)
  ->  Bitmap Index Scan on partitiontest_y2022m02_logdate_idx  (cost=0.00..4.22 rows=9 width=0)
        Index Cond: (logdate = '2022-02-21'::date)

Then, using pgAdmin on the PostgreSQL port:

EXPLAIN ANALYZE
SELECT * FROM dbo.partitiontest WHERE logdate = '2022-02-21'

"Bitmap Heap Scan on partitiontest_y2022m02 partitiontest  (cost=4.22..14.76 rows=9 width=16) (actual time=0.015..0.016 rows=1 loops=1)"
"  Recheck Cond: (logdate = '2022-02-21'::date)"
"  Heap Blocks: exact=1"
"  ->  Bitmap Index Scan on partitiontest_y2022m02_logdate_idx  (cost=0.00..4.22 rows=9 width=0) (actual time=0.011..0.011 rows=1 loops=1)"
"        Index Cond: (logdate = '2022-02-21'::date)"
"Planning Time: 0.124 ms"
"Execution Time: 0.043 ms"

Inheritance Partitioning Example

First, create the database objects that will be used in our example:

DROP TRIGGER IF EXISTS insert_measurement_trigger ON dbo.measurement_inheritance;
DROP FUNCTION IF EXISTS dbo.measurement_inheritance_insert_trigger();
DROP TABLE IF EXISTS dbo.measurement_inheritance_y2006m02;
DROP TABLE  IF EXISTS dbo.measurement_inheritance_y2006m03;
DROP TABLE  IF EXISTS dbo.measurement_inheritance;  
CREATE TABLE dbo.measurement_inheritance (
    city_id         int not null,
    logdate         date not null,
    peaktemp        int,
    unitsales       int
);

CREATE TABLE dbo.measurement_inheritance_y2006m02 (
    CHECK ( logdate >= DATE '2006-02-01' AND logdate < DATE '2006-03-01' )
) INHERITS (dbo.measurement_inheritance);

CREATE TABLE dbo.measurement_inheritance_y2006m03 (
    CHECK ( logdate >= DATE '2006-03-01' AND logdate < DATE '2006-04-01' )
) INHERITS (dbo.measurement_inheritance);

DROP INDEX IF EXISTS dbo_log_measurement_inheritance_y2006m02;
DROP INDEX IF EXISTS dbo_log_measurement_inheritance_y2006m03;

CREATE INDEX dbo_log_measurement_inheritance_y2006m02 ON dbo.measurement_inheritance_y2006m02 (logdate);
CREATE INDEX dbo_log_measurement_inheritance_y2006m03 ON dbo.measurement_inheritance_y2006m03 (logdate);


CREATE OR REPLACE FUNCTION dbo.measurement_insert_trigger()
RETURNS TRIGGER AS $$
DECLARE
  year1 int;
  month1 smallint;
BEGIN
  year1 = EXTRACT(YEAR FROM   new.logdate );
  month1 = EXTRACT(month FROM   new.logdate );
  raise info 'year1 : % ',year1;
  if month1<10 then
  EXECUTE 'INSERT INTO dbo.measurement_inheritance_y'|| year1::varchar(4)||'m0'||  month1::varchar||' VALUES ('||
            NEW.city_id::varchar||','|| '''' ||NEW.logdate::date||''''
            ' ,'|| NEW.peaktemp::varchar||','||NEW.unitsales::varchar
            || ')'; 
  ELSE
  EXECUTE 'INSERT INTO dbo.measurement_inheritance_y'|| year1::varchar(4)||'m'|| month1::varchar||' VALUES ('||
            NEW.city_id::varchar||','|| '''' ||NEW.logdate::date||''''
            ' ,'|| NEW.peaktemp::varchar||','||NEW.unitsales::varchar
            || ')'; 
END IF;
     -- 2008m01 VALUES (NEW.*);
     RETURN NULL;
END;
$$
LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS insert_measurement_trigger ON dbo.measurement_inheritance;

CREATE TRIGGER insert_measurement_trigger
    BEFORE INSERT ON dbo. measurement_inheritance
    FOR EACH ROW EXECUTE FUNCTION dbo.measurement_insert_trigger();

Then, add half of the test data to the table using pgAdmin (on the PostgreSQL port):

INSERT INTO dbo.measurement_inheritance VALUES (1,'2006-02-01',1,1);
INSERT INTO dbo.measurement_inheritance VALUES (2,'2006-02-10',1,2);
INSERT INTO dbo.measurement_inheritance VALUES (3,'2006-02-15',1,3);
INSERT INTO dbo.measurement_inheritance VALUES (4,'2006-03-01',2,1);
INSERT INTO dbo.measurement_inheritance VALUES (5,'2006-03-03',2,2);
INSERT INTO dbo.measurement_inheritance VALUES (6,'2006-03-11',2,3);
INSERT INTO dbo.measurement_inheritance VALUES (7,'2006-03-15',2,4);
INSERT INTO dbo.measurement_inheritance VALUES (8,'2006-03-16',2,5);
INSERT INTO dbo.measurement_inheritance VALUES (8,'2006-03-17',2,6);
INSERT INTO dbo.measurement_inheritance VALUES (8,'2006-03-20',2,7);
INSERT INTO dbo.measurement_inheritance VALUES (8,'2006-03-21',2,8);

Use pgAdmin to change the table owner to dbo:

ALTER FUNCTION dbo.measurement_insert_trigger() OWNER TO dbo;
ALTER TABLE dbo.measurement_inheritance OWNER to dbo;
ALTER TABLE dbo.measurement_inheritance_y2006m02 OWNER TO dbo;
ALTER TABLE dbo.measurement_inheritance_y2006m03 OWNER TO dbo;

Add Data from SSMS:

INSERT INTO dbo.measurement_inheritance values (1,'2006-02-05',1,4);
INSERT INTO dbo.measurement_inheritance values (2,'2006-02-15',1,5);
INSERT INTO dbo.measurement_inheritance values (3,'2006-02-20',1,6);
INSERT INTO dbo.measurement_inheritance values (4,'2006-03-02',2,9);
INSERT INTO dbo.measurement_inheritance values (5,'2006-03-05',2,10);
INSERT INTO dbo.measurement_inheritance values (6,'2006-03-12',2,11);
INSERT INTO dbo.measurement_inheritance values (7,'2006-03-16',2,12);
INSERT INTO dbo.measurement_inheritance values (8,'2006-03-18',2,13);
INSERT INTO dbo.measurement_inheritance values (8,'2006-03-19',2,14);
INSERT INTO dbo.measurement_inheritance values (8,'2006-03-23',2,15);
INSERT INTO dbo.measurement_inheritance values (8,'2006-03-25',2,16);

Turn on the EXECUTE ANALYZE functionality, and query the data:

SET BABELFISH_SHOWPLAN_ALL on

SELECT * FROM dbo.measurement_inheritance WHERE logdate ='2006-03-25';

On-conflict Partitioning Example

First, create the database objects that will be used in our example:

DROP TABLE IF EXISTS  dbo.customers;

CREATE TABLE dbo.customers (
    customer_id serial PRIMARY KEY,
    name VARCHAR UNIQUE,
    email VARCHAR NOT NULL,
    active bool NOT NULL DEFAULT TRUE
);

Then, add data:

INSERT INTO 
    dbo.customers (name, email)
VALUES 
    (ABC, 'contact@abc.com'),
    ('MBA', 'contact@mba.com'),
    ('XYZ', 'contact@xyz.com');
    

CREATE OR REPLACE FUNCTION dbo.onConflictTestFromSSM()
RETURNS void AS $$
DECLARE
    year1 int;
    month1 smallint;
BEGIN
  INSERT INTO dbo.customers (NAME, email)
    VALUES('MBA','hotline@mbacom') 
    ON CONFLICT (name )
    DO 
   UPDATE SET email = EXCLUDED.email || ';' || customers.email;
    RAISE INFO 'function executes';
END;
$$
LANGUAGE plpgsql;

ALTER FUNCTION dbo.onConflictTestFromSSM()  OWNER TO dbo;
ALTER TABLE dbo.customers  OWNER to dbo;

Use SSMS to query dbo.onConflictTestFromSSM():

SELECT * FROM dbo.onConflictTestFromSSM()
EXEC dbo.onConflictTestFromSSM

SELECT * FROM dbo.customers

For more information about using Babelfish from the TDS port and the PostgreSQL port, visit the Babelfish website.

Babelfish for PostgreSQL Links