|
250 | 250 | DECLARE
|
251 | 251 | v_parent_relid OID;
|
252 | 252 | v_child_relid OID := p_partition::regclass::oid;
|
253 |
| - v_atttype INT; |
254 | 253 | v_attname TEXT;
|
255 |
| - -- v_range ANYARRAY; |
256 |
| - -- v_min ANYELEMENT; |
257 |
| - -- v_max ANYELEMENT; |
258 | 254 | v_cond TEXT;
|
259 | 255 | v_new_partition TEXT;
|
| 256 | + v_part_type INTEGER; |
260 | 257 | BEGIN
|
261 | 258 | v_parent_relid := inhparent
|
262 | 259 | FROM pg_inherits
|
263 | 260 | WHERE inhrelid = v_child_relid;
|
264 | 261 |
|
265 |
| - SELECT attname INTO v_attname |
| 262 | + SELECT attname, parttype INTO v_attname, v_part_type |
266 | 263 | FROM pg_pathman_rels
|
267 | 264 | WHERE relname = v_parent_relid::regclass::text;
|
268 | 265 |
|
| 266 | + /* Check if this is RANGE partition */ |
| 267 | + IF v_part_type != 2 THEN |
| 268 | + RAISE EXCEPTION 'Specified partition isn''t RANGE partition'; |
| 269 | + END IF; |
| 270 | + |
269 | 271 | /* Get partition values range */
|
270 | 272 | p_range := get_partition_range(v_parent_relid, v_child_relid);
|
271 | 273 | IF p_range IS NULL THEN
|
272 | 274 | RAISE EXCEPTION 'Could not find specified partition';
|
273 | 275 | END IF;
|
274 |
| - RAISE NOTICE 'range: % - %', p_range[1], p_range[2]; |
275 | 276 |
|
276 | 277 | /* Check if value fit into the range */
|
277 | 278 | IF p_range[1] > p_value OR p_range[2] <= p_value
|
|
314 | 315 | LANGUAGE plpgsql;
|
315 | 316 |
|
316 | 317 |
|
| 318 | +/* |
| 319 | + * Merge RANGE partitions |
| 320 | + * |
| 321 | + * Note: we had to have at least one argument of type |
| 322 | + */ |
| 323 | + -- , OUT p_range1 ANYARRAY |
| 324 | +CREATE OR REPLACE FUNCTION merge_range_partitions( |
| 325 | + p_partition1 TEXT |
| 326 | + , p_partition2 TEXT) |
| 327 | +RETURNS VOID AS |
| 328 | +$$ |
| 329 | +DECLARE |
| 330 | + v_parent_relid1 OID; |
| 331 | + v_parent_relid2 OID; |
| 332 | + v_part1_relid OID := p_partition1::regclass::oid; |
| 333 | + v_part2_relid OID := p_partition2::regclass::oid; |
| 334 | + v_attname TEXT; |
| 335 | + v_part_type INTEGER; |
| 336 | + v_atttype TEXT; |
| 337 | +BEGIN |
| 338 | + IF v_part1_relid = v_part2_relid THEN |
| 339 | + RAISE EXCEPTION 'Cannot merge partition with itself'; |
| 340 | + END IF; |
| 341 | + |
| 342 | + v_parent_relid1 := inhparent FROM pg_inherits WHERE inhrelid = v_part1_relid; |
| 343 | + v_parent_relid2 := inhparent FROM pg_inherits WHERE inhrelid = v_part2_relid; |
| 344 | + |
| 345 | + IF v_parent_relid1 != v_parent_relid2 THEN |
| 346 | + RAISE EXCEPTION 'Cannot merge partitions having different parents'; |
| 347 | + END IF; |
| 348 | + |
| 349 | + SELECT attname, parttype INTO v_attname, v_part_type |
| 350 | + FROM pg_pathman_rels |
| 351 | + WHERE relname = v_parent_relid1::regclass::text; |
| 352 | + |
| 353 | + /* Check if this is RANGE partition */ |
| 354 | + IF v_part_type != 2 THEN |
| 355 | + RAISE EXCEPTION 'Specified partitions aren''t RANGE partitions'; |
| 356 | + END IF; |
| 357 | + |
| 358 | + SELECT typname INTO v_atttype |
| 359 | + FROM pg_type |
| 360 | + JOIN pg_attribute on atttypid = "oid" |
| 361 | + WHERE attrelid = 'num_range_rel'::regclass::oid and attname = lower(v_attname); |
| 362 | + |
| 363 | + EXECUTE format('SELECT merge_range_partitions_internal($1, $2 , $3, NULL::%s)', v_atttype) |
| 364 | + USING v_parent_relid1, v_part1_relid , v_part2_relid; |
| 365 | +END |
| 366 | +$$ |
| 367 | +LANGUAGE plpgsql; |
| 368 | + |
| 369 | + |
| 370 | +/* |
| 371 | + * Merge two partitions. All data will be copied to the first one. Second |
| 372 | + * partition will be destroyed. |
| 373 | + * |
| 374 | + * Notes: dummy field is used to pass the element type to the function |
| 375 | + * (it is neccessary because of pseudo-types used in function) |
| 376 | + */ |
| 377 | +CREATE OR REPLACE FUNCTION merge_range_partitions_internal( |
| 378 | + p_parent_relid OID |
| 379 | + , p_part1_relid OID |
| 380 | + , p_part2_relid OID |
| 381 | + , dummy ANYELEMENT |
| 382 | + , OUT p_range ANYARRAY) |
| 383 | +RETURNS ANYARRAY AS |
| 384 | +$$ |
| 385 | +DECLARE |
| 386 | + v_attname TEXT; |
| 387 | + v_cond TEXT; |
| 388 | +BEGIN |
| 389 | + SELECT attname INTO v_attname FROM pg_pathman_rels |
| 390 | + WHERE relname = p_parent_relid::regclass::text; |
| 391 | + |
| 392 | + /* |
| 393 | + * Get ranges |
| 394 | + * first and second elements of array are MIN and MAX of partition1 |
| 395 | + * third and forth elements are MIN and MAX of partition2 |
| 396 | + */ |
| 397 | + p_range := get_partition_range(p_parent_relid, p_part1_relid) || |
| 398 | + get_partition_range(p_parent_relid, p_part2_relid); |
| 399 | + RAISE NOTICE 'type: %', pg_typeof(p_range[1]); |
| 400 | + RAISE NOTICE 'min %, max %', pg_typeof(least(p_range[1], p_range[3])), |
| 401 | + pg_typeof(greatest(p_range[2], p_range[4])); |
| 402 | + |
| 403 | + /* Check if ranges are adjacent */ |
| 404 | + IF p_range[1] != p_range[4] AND p_range[2] != p_range[3] THEN |
| 405 | + RAISE EXCEPTION 'Merge failed. Partitions must be adjacent'; |
| 406 | + END IF; |
| 407 | + |
| 408 | + /* Extend first partition */ |
| 409 | + v_cond := get_range_condition(v_attname |
| 410 | + , least(p_range[1], p_range[3]) |
| 411 | + , greatest(p_range[2], p_range[4]) - least(p_range[1], p_range[3])); |
| 412 | + RAISE NOTICE 'cond: %', v_cond; |
| 413 | + |
| 414 | + /* Alter first table */ |
| 415 | + EXECUTE format('ALTER TABLE %s DROP CONSTRAINT %s_%s_check' |
| 416 | + , p_part1_relid::regclass::text |
| 417 | + , p_part1_relid::regclass::text |
| 418 | + , v_attname); |
| 419 | + EXECUTE format('ALTER TABLE %s ADD CHECK (%s)' |
| 420 | + , p_part1_relid::regclass::text |
| 421 | + , v_cond); |
| 422 | + |
| 423 | + /* Copy data from second partition to the first one */ |
| 424 | + EXECUTE format('WITH part_data AS (DELETE FROM %s RETURNING *) |
| 425 | + INSERT INTO %s SELECT * FROM part_data' |
| 426 | + , p_part2_relid::regclass::text |
| 427 | + , p_part1_relid::regclass::text); |
| 428 | + |
| 429 | + /* Remove second partition */ |
| 430 | + EXECUTE format('DROP TABLE %s', p_part2_relid::regclass::text); |
| 431 | +END |
| 432 | +$$ LANGUAGE plpgsql; |
| 433 | + |
| 434 | + |
317 | 435 | /*
|
318 | 436 | * Creates range partitioning insert trigger
|
319 | 437 | */
|
|
0 commit comments