|
12 | 12 | #include"utils.h"
|
13 | 13 | #include"pathman.h"
|
14 | 14 | #include"partition_creation.h"
|
| 15 | +#include"partition_filter.h" |
15 | 16 | #include"relation_info.h"
|
16 | 17 | #include"xact_handling.h"
|
17 | 18 |
|
18 |
| -#include"access/htup_details.h" |
| 19 | +#include"access/tupconvert.h" |
19 | 20 | #include"access/nbtree.h"
|
| 21 | +#include"access/htup_details.h" |
20 | 22 | #include"access/xact.h"
|
21 | 23 | #include"catalog/indexing.h"
|
22 | 24 | #include"catalog/pg_type.h"
|
|
32 | 34 | #include"utils/syscache.h"
|
33 | 35 |
|
34 | 36 |
|
| 37 | +staticOidget_partition_for_key(constPartRelationInfo*prel,Datumkey); |
| 38 | + |
| 39 | + |
35 | 40 | /* Function declarations */
|
36 | 41 |
|
37 | 42 | PG_FUNCTION_INFO_V1(on_partitions_created );
|
@@ -69,6 +74,8 @@ PG_FUNCTION_INFO_V1( check_security_policy );
|
69 | 74 | PG_FUNCTION_INFO_V1(debug_capture );
|
70 | 75 | PG_FUNCTION_INFO_V1(get_pathman_lib_version );
|
71 | 76 |
|
| 77 | +PG_FUNCTION_INFO_V1(update_trigger_func ); |
| 78 | + |
72 | 79 |
|
73 | 80 | /*
|
74 | 81 | * User context for function show_partition_list_internal().
|
@@ -926,3 +933,112 @@ get_pathman_lib_version(PG_FUNCTION_ARGS)
|
926 | 933 | {
|
927 | 934 | PG_RETURN_CSTRING(psprintf("%x",CURRENT_LIB_VERSION));
|
928 | 935 | }
|
| 936 | + |
| 937 | +/* |
| 938 | + * Update trigger |
| 939 | + */ |
| 940 | +Datum |
| 941 | +update_trigger_func(PG_FUNCTION_ARGS) |
| 942 | +{ |
| 943 | +constPartRelationInfo*prel; |
| 944 | +PartParentSearchparent_search; |
| 945 | +Oidparent; |
| 946 | +TriggerData*trigdata= (TriggerData*)fcinfo->context; |
| 947 | +char*key_name; |
| 948 | +Datumkey; |
| 949 | +boolisnull; |
| 950 | +TupleConversionMap*conversion_map; |
| 951 | + |
| 952 | +TupleDescsource_tupdesc; |
| 953 | +HeapTuplesource_tuple; |
| 954 | +Oidsource_relid; |
| 955 | +AttrNumbersource_key; |
| 956 | + |
| 957 | +Relationtarget_rel; |
| 958 | +TupleDesctarget_tupdesc; |
| 959 | +HeapTupletarget_tuple; |
| 960 | +Oidtarget_relid; |
| 961 | + |
| 962 | +/* This function can only be invoked as a trigger */ |
| 963 | +if (!CALLED_AS_TRIGGER(fcinfo)) |
| 964 | +elog(ERROR,"Function invoked not in a trigger context"); |
| 965 | + |
| 966 | +/* Make sure that trigger was fired during UPDATE command */ |
| 967 | +if (!TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) |
| 968 | +elog(ERROR,"This function must only be used as UPDATE trigger"); |
| 969 | + |
| 970 | +source_relid=trigdata->tg_relation->rd_id; |
| 971 | +source_tuple=trigdata->tg_newtuple; |
| 972 | +source_tupdesc=trigdata->tg_relation->rd_att; |
| 973 | + |
| 974 | +/* Find parent relation and partitioning info */ |
| 975 | +parent=get_parent_of_partition(source_relid,&parent_search); |
| 976 | +if (parent_search!=PPS_ENTRY_PART_PARENT) |
| 977 | +elog(ERROR,"relation \"%s\" is not a partition", |
| 978 | +get_rel_name_or_relid(source_relid)); |
| 979 | +prel=get_pathman_relation_info(parent); |
| 980 | +shout_if_prel_is_invalid(parent,prel,PT_INDIFFERENT); |
| 981 | + |
| 982 | +/* |
| 983 | + * Find partitioning key attribute of source partition. Keep in mind that |
| 984 | + * there could be dropped columns in parent relation or partition and so |
| 985 | + * key attribute may have different number |
| 986 | + */ |
| 987 | +key_name=get_attname(parent,prel->attnum); |
| 988 | +source_key=get_attnum(source_relid,key_name); |
| 989 | +key=heap_getattr(source_tuple,source_key,source_tupdesc,&isnull); |
| 990 | + |
| 991 | +/* Find partition it should go into */ |
| 992 | +target_relid=get_partition_for_key(prel,key); |
| 993 | + |
| 994 | +/* If target partition is the same then do nothing */ |
| 995 | +if (target_relid==source_relid) |
| 996 | +returnPointerGetDatum(source_tuple); |
| 997 | + |
| 998 | +target_rel=heap_open(target_relid,RowExclusiveLock); |
| 999 | +target_tupdesc=target_rel->rd_att; |
| 1000 | + |
| 1001 | +/* |
| 1002 | + * Else if it's a different partition then build a TupleConversionMap |
| 1003 | + * between original partition and new one. And then do a convertation |
| 1004 | + */ |
| 1005 | +conversion_map=convert_tuples_by_name(source_tupdesc, |
| 1006 | +target_tupdesc, |
| 1007 | +"Failed to convert tuple"); |
| 1008 | +target_tuple=do_convert_tuple(source_tuple,conversion_map); |
| 1009 | + |
| 1010 | +/* |
| 1011 | + * To make an UPDATE on a tuple in case when the tuple should be moved from |
| 1012 | + * one partition to another we need to perform two actions. First, remove |
| 1013 | + * old tuple from original partition and then insert updated version |
| 1014 | + * of tuple to the target partition |
| 1015 | + */ |
| 1016 | +simple_heap_delete(trigdata->tg_relation,&trigdata->tg_trigtuple->t_self); |
| 1017 | +simple_heap_insert(target_rel,target_tuple); |
| 1018 | + |
| 1019 | +heap_close(target_rel,RowExclusiveLock); |
| 1020 | +PG_RETURN_VOID(); |
| 1021 | +} |
| 1022 | + |
| 1023 | +/* |
| 1024 | + * Returns Oid of partition corresponding to partitioning key value. Throws |
| 1025 | + * an error if no partition found |
| 1026 | + */ |
| 1027 | +staticOid |
| 1028 | +get_partition_for_key(constPartRelationInfo*prel,Datumkey) |
| 1029 | +{ |
| 1030 | +Oid*parts; |
| 1031 | +intnparts; |
| 1032 | + |
| 1033 | +/* Search for matching partitions */ |
| 1034 | +parts=find_partitions_for_value(key,prel->atttype,prel,&nparts); |
| 1035 | + |
| 1036 | +if (nparts>1) |
| 1037 | +elog(ERROR,ERR_PART_ATTR_MULTIPLE); |
| 1038 | +elseif (nparts==0) |
| 1039 | +elog(ERROR, |
| 1040 | +"There is not partition to fit partition key \"%s\"", |
| 1041 | +datum_to_cstring(key,prel->atttype)); |
| 1042 | +else |
| 1043 | +returnparts[0]; |
| 1044 | +} |