IDEMPIERE-5963 Implement Sub-Partitioning and Detach Partition (#2150)
* IDEMPIERE-5963 Implement Sub-Partitioning and Detach Partition Implement sub-partitioning for PostgreSQL Implement sub-partitioning for Oracle Implement detach/re-attach
This commit is contained in:
parent
18146a57a6
commit
6f110b2d2f
|
@ -0,0 +1,137 @@
|
|||
-- IDEMPIERE-5963 Implement Sub-Partitioning and Detach Partition
|
||||
SELECT register_migration_script('202312261050_IDEMPIERE-5963.sql') FROM dual;
|
||||
|
||||
SET SQLBLANKLINES ON
|
||||
SET DEFINE OFF
|
||||
|
||||
-- Dec 26, 2023, 10:50:32 AM MYT
|
||||
INSERT INTO AD_Process (AD_Process_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,Help,IsReport,Value,IsDirectPrint,Classname,AccessLevel,EntityType,Statistic_Count,Statistic_Seconds,IsBetaFunctionality,ShowHelp,CopyFromProcess,AD_Process_UU,AllowMultipleExecution) VALUES (200158,0,0,'Y',TO_TIMESTAMP('2023-12-26 10:50:30','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-26 10:50:30','YYYY-MM-DD HH24:MI:SS'),100,'Detach/re-attach Table Partition','Detach or re-attach table partition','Detach an attached table partition or re-attach a detached table partition','N','DetachOrReAttachPartition','N','org.idempiere.tablepartition.process.ChangePartitionStatus','4','D',0,0,'N','Y','N','d55b6a76-26f7-45a6-9117-a8a9cdb78e0f','PA')
|
||||
;
|
||||
|
||||
-- Dec 26, 2023, 10:52:22 AM MYT
|
||||
INSERT INTO AD_Element (AD_Element_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,ColumnName,Name,Description,PrintName,EntityType,AD_Element_UU) VALUES (203890,0,0,'Y',TO_TIMESTAMP('2023-12-26 10:52:21','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-26 10:52:21','YYYY-MM-DD HH24:MI:SS'),100,'IsPartitionAttached','Attached','Partition attached to table','Attached','D','f2ba716f-605e-4f68-9ae7-96a384f5902c')
|
||||
;
|
||||
|
||||
-- Dec 26, 2023, 10:53:31 AM MYT
|
||||
INSERT INTO AD_Column (AD_Column_ID,Version,Name,Description,AD_Table_ID,ColumnName,DefaultValue,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,SeqNoSelection,IsToolbarButton,IsSecure,IsHtml,IsPartitionKey) VALUES (216306,0,'Attached','Partition attached to table',200411,'IsPartitionAttached','Y',1,'N','N','Y','N','N',0,'N',20,0,0,'Y',TO_TIMESTAMP('2023-12-26 10:53:30','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-26 10:53:30','YYYY-MM-DD HH24:MI:SS'),100,203890,'Y','N','D','N','N','N','Y','9217549b-ee10-4ca0-9322-82822314c180','N',0,'N','N','N','N')
|
||||
;
|
||||
|
||||
-- Dec 26, 2023, 10:53:37 AM MYT
|
||||
ALTER TABLE AD_TablePartition ADD IsPartitionAttached CHAR(1) DEFAULT 'Y' CHECK (IsPartitionAttached IN ('Y','N')) NOT NULL
|
||||
;
|
||||
|
||||
-- Dec 26, 2023, 11:01:05 AM MYT
|
||||
INSERT INTO AD_Column (AD_Column_ID,Version,Name,AD_Table_ID,ColumnName,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,AD_Process_ID,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,SeqNoSelection,IsToolbarButton,IsSecure,IsHtml,IsPartitionKey) VALUES (216307,0,'Process Now',200411,'Processing',1,'N','N','N','N','N',0,'N',28,0,0,'Y',TO_TIMESTAMP('2023-12-26 11:01:04','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-26 11:01:04','YYYY-MM-DD HH24:MI:SS'),100,524,'Y',200158,'N','D','N','Y','N','Y','ddcbfcb0-e232-4ccd-876a-af4b89265ed1','N',0,'B','N','N','N')
|
||||
;
|
||||
|
||||
-- Dec 26, 2023, 11:01:10 AM MYT
|
||||
ALTER TABLE AD_TablePartition ADD Processing CHAR(1) DEFAULT NULL
|
||||
;
|
||||
|
||||
-- Dec 26, 2023, 11:02:50 AM MYT
|
||||
INSERT INTO AD_Field (AD_Field_ID,Name,Description,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLength,SeqNo,SortNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,XPosition,ColumnSpan,NumLines,IsQuickEntry,IsDefaultFocus,IsAdvancedField,IsQuickForm) VALUES (208096,'Attached','Partition attached to table',200381,216306,'Y',0,80,0,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2023-12-26 11:02:49','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-26 11:02:49','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','32e3959f-1ddf-4764-b2d2-e706e4b5a1b6','Y',60,2,2,1,'N','N','N','N')
|
||||
;
|
||||
|
||||
-- Dec 26, 2023, 11:04:14 AM MYT
|
||||
INSERT INTO AD_Field (AD_Field_ID,Name,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLength,SeqNo,SortNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,XPosition,ColumnSpan,NumLines,IsQuickEntry,IsDefaultFocus,IsAdvancedField,IsQuickForm) VALUES (208097,'Process Now',200381,216307,'Y',0,90,0,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2023-12-26 11:04:14','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-26 11:04:14','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','8ade7442-7e4e-440a-8a79-86431c3164ac','Y',70,1,2,1,'N','N','N','N')
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 10:55:25 AM MYT
|
||||
INSERT INTO AD_Element (AD_Element_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,ColumnName,Name,Description,PrintName,EntityType,AD_Element_UU) VALUES (203891,0,0,'Y',TO_TIMESTAMP('2023-12-27 10:55:24','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-27 10:55:24','YYYY-MM-DD HH24:MI:SS'),100,'Parent_TablePartition_ID','Parent Partition','Parent table partition','Parent Partition','D','b8a4d585-9114-43c9-b5cb-36a65783844e')
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 10:56:58 AM MYT
|
||||
INSERT INTO AD_Reference (AD_Reference_ID,Name,Description,ValidationType,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,EntityType,IsOrderByValue,AD_Reference_UU,ShowInactive) VALUES (200262,'AD_TablePartition','Table Partition','T',0,0,'Y',TO_TIMESTAMP('2023-12-27 10:56:56','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-27 10:56:56','YYYY-MM-DD HH24:MI:SS'),100,'D','N','71d7e81f-de03-4329-86d4-41c0f07fa488','N')
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 11:00:04 AM MYT
|
||||
INSERT INTO AD_Ref_Table (AD_Reference_ID,AD_Table_ID,AD_Key,AD_Display,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsValueDisplayed,EntityType,AD_Ref_Table_UU) VALUES (200262,200411,216289,216297,0,0,'Y',TO_TIMESTAMP('2023-12-27 11:00:04','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-27 11:00:04','YYYY-MM-DD HH24:MI:SS'),100,'N','D','e667c6e5-b53c-43c5-a85f-243d3b188458')
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 11:00:23 AM MYT
|
||||
INSERT INTO AD_Column (AD_Column_ID,Version,Name,Description,AD_Table_ID,ColumnName,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Reference_Value_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,SeqNoSelection,IsToolbarButton,IsSecure,IsHtml,IsPartitionKey) VALUES (216308,0,'Parent Partition','Parent table partition',200411,'Parent_TablePartition_ID',10,'N','N','N','N','N',0,'N',30,200262,0,0,'Y',TO_TIMESTAMP('2023-12-27 11:00:21','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-27 11:00:21','YYYY-MM-DD HH24:MI:SS'),100,203891,'N','N','D','N','N','N','Y','43a932ca-0f17-48b7-be99-e7b4327a7a22','N',0,'N','N','N','N')
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 11:00:28 AM MYT
|
||||
UPDATE AD_Column SET FKConstraintName='ParentTablePartition_ADTablePa', FKConstraintType='N',Updated=TO_TIMESTAMP('2023-12-27 11:00:28','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=216308
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 11:00:28 AM MYT
|
||||
ALTER TABLE AD_TablePartition ADD Parent_TablePartition_ID NUMBER(10) DEFAULT NULL
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 11:00:28 AM MYT
|
||||
ALTER TABLE AD_TablePartition ADD CONSTRAINT ParentTablePartition_ADTablePa FOREIGN KEY (Parent_TablePartition_ID) REFERENCES ad_tablepartition(ad_tablepartition_id) DEFERRABLE INITIALLY DEFERRED
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 11:02:48 AM MYT
|
||||
INSERT INTO AD_Field (AD_Field_ID,Name,Description,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLength,SeqNo,SortNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,XPosition,ColumnSpan,NumLines,IsQuickEntry,IsDefaultFocus,IsAdvancedField,IsQuickForm) VALUES (208098,'Parent Partition','Parent table partition',200381,216308,'Y',0,100,0,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2023-12-27 11:02:48','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-27 11:02:48','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','cbd9fb43-e055-4e99-9d23-562d1ed515a6','Y',80,1,2,1,'N','N','N','N')
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 11:03:46 AM MYT
|
||||
UPDATE AD_Field SET IsDisplayed='Y', SeqNo=70, XPosition=1,Updated=TO_TIMESTAMP('2023-12-27 11:03:46','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=208098
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 11:03:46 AM MYT
|
||||
UPDATE AD_Field SET IsDisplayed='Y', SeqNo=90, XPosition=5,Updated=TO_TIMESTAMP('2023-12-27 11:03:46','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=208097
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 11:03:46 AM MYT
|
||||
UPDATE AD_Field SET SeqNo=100,Updated=TO_TIMESTAMP('2023-12-27 11:03:46','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=208091
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 11:03:46 AM MYT
|
||||
UPDATE AD_Field SET SeqNo=0,Updated=TO_TIMESTAMP('2023-12-27 11:03:46','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=208089
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 11:03:46 AM MYT
|
||||
UPDATE AD_Field SET SeqNo=0,Updated=TO_TIMESTAMP('2023-12-27 11:03:46','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=208088
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 1:39:36 PM MYT
|
||||
UPDATE AD_Column SET IsUpdateable='N', IsAllowCopy='N',Updated=TO_TIMESTAMP('2023-12-27 13:39:36','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=216301
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 1:39:43 PM MYT
|
||||
UPDATE AD_Column SET IsMandatory='Y', IsUpdateable='N',Updated=TO_TIMESTAMP('2023-12-27 13:39:43','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=216296
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 1:39:49 PM MYT
|
||||
UPDATE AD_Column SET IsMandatory='Y', IsUpdateable='N',Updated=TO_TIMESTAMP('2023-12-27 13:39:49','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=216306
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 1:39:55 PM MYT
|
||||
UPDATE AD_Column SET IsUpdateable='N', IsAllowCopy='N',Updated=TO_TIMESTAMP('2023-12-27 13:39:55','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=216297
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 1:40:04 PM MYT
|
||||
UPDATE AD_Column SET IsAlwaysUpdateable='N',Updated=TO_TIMESTAMP('2023-12-27 13:40:04','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=216307
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 1:40:52 PM MYT
|
||||
UPDATE AD_Tab SET IsReadOnly='N',Updated=TO_TIMESTAMP('2023-12-27 13:40:52','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Tab_ID=200381
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 2:20:41 PM MYT
|
||||
UPDATE AD_Column SET IsMandatory='Y', IsUpdateable='Y',Updated=TO_TIMESTAMP('2023-12-27 14:20:41','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=216306
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 2:20:59 PM MYT
|
||||
UPDATE AD_Field SET IsReadOnly='Y',Updated=TO_TIMESTAMP('2023-12-27 14:20:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=208096
|
||||
;
|
||||
|
||||
-- Dec 28, 2023, 1:55:33 PM MYT
|
||||
INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('E','Can''t detach or re-attach default partition',0,0,'Y',TO_TIMESTAMP('2023-12-28 13:55:32','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-28 13:55:32','YYYY-MM-DD HH24:MI:SS'),100,200859,'CantDetachReattachDefaultPartition','D','375e3278-6231-4486-a8ef-8a978ce57698')
|
||||
;
|
||||
|
||||
-- Dec 28, 2023, 4:11:58 PM MYT
|
||||
INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('I','The partition {0} has been successfully detached from table {1}',0,0,'Y',TO_TIMESTAMP('2023-12-28 16:11:57','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-28 16:11:57','YYYY-MM-DD HH24:MI:SS'),100,200860,'PartitionDetachFromTable','D','3b92cf36-e6e4-401b-8663-5897e54b8966')
|
||||
;
|
||||
|
||||
-- Dec 28, 2023, 4:12:21 PM MYT
|
||||
INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('I','The partition {0} has been successfully re-attached to table {1}',0,0,'Y',TO_TIMESTAMP('2023-12-28 16:12:21','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-28 16:12:21','YYYY-MM-DD HH24:MI:SS'),100,200861,'PartitionReAttachToTable','D','4a3c84d0-fc35-4d62-b5ab-3ba018453783')
|
||||
;
|
||||
|
||||
-- Dec 29, 2023, 5:45:23 PM MYT
|
||||
INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('E','A maximum of two columns can be specified as partition keys. The first column defines the primary partition, and the second (optional) column defines the subpartition',0,0,'Y',TO_TIMESTAMP('2023-12-29 17:45:17','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-29 17:45:17','YYYY-MM-DD HH24:MI:SS'),100,200862,'OnlyTwoPartitionKeyAllowed','D','8b27d206-d764-4291-80ce-b00b135daa32')
|
||||
;
|
|
@ -0,0 +1,134 @@
|
|||
-- IDEMPIERE-5963 Implement Sub-Partitioning and Detach Partition
|
||||
SELECT register_migration_script('202312271420_IDEMPIERE-5963.sql') FROM dual;
|
||||
|
||||
-- Dec 26, 2023, 10:50:32 AM MYT
|
||||
INSERT INTO AD_Process (AD_Process_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,Help,IsReport,Value,IsDirectPrint,Classname,AccessLevel,EntityType,Statistic_Count,Statistic_Seconds,IsBetaFunctionality,ShowHelp,CopyFromProcess,AD_Process_UU,AllowMultipleExecution) VALUES (200158,0,0,'Y',TO_TIMESTAMP('2023-12-26 10:50:30','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-26 10:50:30','YYYY-MM-DD HH24:MI:SS'),100,'Detach/re-attach Table Partition','Detach or re-attach table partition','Detach an attached table partition or re-attach a detached table partition','N','DetachOrReAttachPartition','N','org.idempiere.tablepartition.process.ChangePartitionStatus','4','D',0,0,'N','Y','N','d55b6a76-26f7-45a6-9117-a8a9cdb78e0f','PA')
|
||||
;
|
||||
|
||||
-- Dec 26, 2023, 10:52:22 AM MYT
|
||||
INSERT INTO AD_Element (AD_Element_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,ColumnName,Name,Description,PrintName,EntityType,AD_Element_UU) VALUES (203890,0,0,'Y',TO_TIMESTAMP('2023-12-26 10:52:21','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-26 10:52:21','YYYY-MM-DD HH24:MI:SS'),100,'IsPartitionAttached','Attached','Partition attached to table','Attached','D','f2ba716f-605e-4f68-9ae7-96a384f5902c')
|
||||
;
|
||||
|
||||
-- Dec 26, 2023, 10:53:31 AM MYT
|
||||
INSERT INTO AD_Column (AD_Column_ID,Version,Name,Description,AD_Table_ID,ColumnName,DefaultValue,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,SeqNoSelection,IsToolbarButton,IsSecure,IsHtml,IsPartitionKey) VALUES (216306,0,'Attached','Partition attached to table',200411,'IsPartitionAttached','Y',1,'N','N','Y','N','N',0,'N',20,0,0,'Y',TO_TIMESTAMP('2023-12-26 10:53:30','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-26 10:53:30','YYYY-MM-DD HH24:MI:SS'),100,203890,'Y','N','D','N','N','N','Y','9217549b-ee10-4ca0-9322-82822314c180','N',0,'N','N','N','N')
|
||||
;
|
||||
|
||||
-- Dec 26, 2023, 10:53:37 AM MYT
|
||||
ALTER TABLE AD_TablePartition ADD COLUMN IsPartitionAttached CHAR(1) DEFAULT 'Y' CHECK (IsPartitionAttached IN ('Y','N')) NOT NULL
|
||||
;
|
||||
|
||||
-- Dec 26, 2023, 11:01:05 AM MYT
|
||||
INSERT INTO AD_Column (AD_Column_ID,Version,Name,AD_Table_ID,ColumnName,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,AD_Process_ID,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,SeqNoSelection,IsToolbarButton,IsSecure,IsHtml,IsPartitionKey) VALUES (216307,0,'Process Now',200411,'Processing',1,'N','N','N','N','N',0,'N',28,0,0,'Y',TO_TIMESTAMP('2023-12-26 11:01:04','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-26 11:01:04','YYYY-MM-DD HH24:MI:SS'),100,524,'Y',200158,'N','D','N','Y','N','Y','ddcbfcb0-e232-4ccd-876a-af4b89265ed1','N',0,'B','N','N','N')
|
||||
;
|
||||
|
||||
-- Dec 26, 2023, 11:01:10 AM MYT
|
||||
ALTER TABLE AD_TablePartition ADD COLUMN Processing CHAR(1) DEFAULT NULL
|
||||
;
|
||||
|
||||
-- Dec 26, 2023, 11:02:50 AM MYT
|
||||
INSERT INTO AD_Field (AD_Field_ID,Name,Description,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLength,SeqNo,SortNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,XPosition,ColumnSpan,NumLines,IsQuickEntry,IsDefaultFocus,IsAdvancedField,IsQuickForm) VALUES (208096,'Attached','Partition attached to table',200381,216306,'Y',0,80,0,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2023-12-26 11:02:49','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-26 11:02:49','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','32e3959f-1ddf-4764-b2d2-e706e4b5a1b6','Y',60,2,2,1,'N','N','N','N')
|
||||
;
|
||||
|
||||
-- Dec 26, 2023, 11:04:14 AM MYT
|
||||
INSERT INTO AD_Field (AD_Field_ID,Name,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLength,SeqNo,SortNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,XPosition,ColumnSpan,NumLines,IsQuickEntry,IsDefaultFocus,IsAdvancedField,IsQuickForm) VALUES (208097,'Process Now',200381,216307,'Y',0,90,0,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2023-12-26 11:04:14','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-26 11:04:14','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','8ade7442-7e4e-440a-8a79-86431c3164ac','Y',70,1,2,1,'N','N','N','N')
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 10:55:25 AM MYT
|
||||
INSERT INTO AD_Element (AD_Element_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,ColumnName,Name,Description,PrintName,EntityType,AD_Element_UU) VALUES (203891,0,0,'Y',TO_TIMESTAMP('2023-12-27 10:55:24','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-27 10:55:24','YYYY-MM-DD HH24:MI:SS'),100,'Parent_TablePartition_ID','Parent Partition','Parent table partition','Parent Partition','D','b8a4d585-9114-43c9-b5cb-36a65783844e')
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 10:56:58 AM MYT
|
||||
INSERT INTO AD_Reference (AD_Reference_ID,Name,Description,ValidationType,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,EntityType,IsOrderByValue,AD_Reference_UU,ShowInactive) VALUES (200262,'AD_TablePartition','Table Partition','T',0,0,'Y',TO_TIMESTAMP('2023-12-27 10:56:56','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-27 10:56:56','YYYY-MM-DD HH24:MI:SS'),100,'D','N','71d7e81f-de03-4329-86d4-41c0f07fa488','N')
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 11:00:04 AM MYT
|
||||
INSERT INTO AD_Ref_Table (AD_Reference_ID,AD_Table_ID,AD_Key,AD_Display,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsValueDisplayed,EntityType,AD_Ref_Table_UU) VALUES (200262,200411,216289,216297,0,0,'Y',TO_TIMESTAMP('2023-12-27 11:00:04','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-27 11:00:04','YYYY-MM-DD HH24:MI:SS'),100,'N','D','e667c6e5-b53c-43c5-a85f-243d3b188458')
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 11:00:23 AM MYT
|
||||
INSERT INTO AD_Column (AD_Column_ID,Version,Name,Description,AD_Table_ID,ColumnName,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Reference_Value_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,SeqNoSelection,IsToolbarButton,IsSecure,IsHtml,IsPartitionKey) VALUES (216308,0,'Parent Partition','Parent table partition',200411,'Parent_TablePartition_ID',10,'N','N','N','N','N',0,'N',30,200262,0,0,'Y',TO_TIMESTAMP('2023-12-27 11:00:21','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-27 11:00:21','YYYY-MM-DD HH24:MI:SS'),100,203891,'N','N','D','N','N','N','Y','43a932ca-0f17-48b7-be99-e7b4327a7a22','N',0,'N','N','N','N')
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 11:00:28 AM MYT
|
||||
UPDATE AD_Column SET FKConstraintName='ParentTablePartition_ADTablePa', FKConstraintType='N',Updated=TO_TIMESTAMP('2023-12-27 11:00:28','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=216308
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 11:00:28 AM MYT
|
||||
ALTER TABLE AD_TablePartition ADD COLUMN Parent_TablePartition_ID NUMERIC(10) DEFAULT NULL
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 11:00:28 AM MYT
|
||||
ALTER TABLE AD_TablePartition ADD CONSTRAINT ParentTablePartition_ADTablePa FOREIGN KEY (Parent_TablePartition_ID) REFERENCES ad_tablepartition(ad_tablepartition_id) DEFERRABLE INITIALLY DEFERRED
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 11:02:48 AM MYT
|
||||
INSERT INTO AD_Field (AD_Field_ID,Name,Description,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLength,SeqNo,SortNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,XPosition,ColumnSpan,NumLines,IsQuickEntry,IsDefaultFocus,IsAdvancedField,IsQuickForm) VALUES (208098,'Parent Partition','Parent table partition',200381,216308,'Y',0,100,0,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2023-12-27 11:02:48','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-27 11:02:48','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','cbd9fb43-e055-4e99-9d23-562d1ed515a6','Y',80,1,2,1,'N','N','N','N')
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 11:03:46 AM MYT
|
||||
UPDATE AD_Field SET IsDisplayed='Y', SeqNo=70, XPosition=1,Updated=TO_TIMESTAMP('2023-12-27 11:03:46','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=208098
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 11:03:46 AM MYT
|
||||
UPDATE AD_Field SET IsDisplayed='Y', SeqNo=90, XPosition=5,Updated=TO_TIMESTAMP('2023-12-27 11:03:46','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=208097
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 11:03:46 AM MYT
|
||||
UPDATE AD_Field SET SeqNo=100,Updated=TO_TIMESTAMP('2023-12-27 11:03:46','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=208091
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 11:03:46 AM MYT
|
||||
UPDATE AD_Field SET SeqNo=0,Updated=TO_TIMESTAMP('2023-12-27 11:03:46','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=208089
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 11:03:46 AM MYT
|
||||
UPDATE AD_Field SET SeqNo=0,Updated=TO_TIMESTAMP('2023-12-27 11:03:46','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=208088
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 1:39:36 PM MYT
|
||||
UPDATE AD_Column SET IsUpdateable='N', IsAllowCopy='N',Updated=TO_TIMESTAMP('2023-12-27 13:39:36','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=216301
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 1:39:43 PM MYT
|
||||
UPDATE AD_Column SET IsMandatory='Y', IsUpdateable='N',Updated=TO_TIMESTAMP('2023-12-27 13:39:43','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=216296
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 1:39:49 PM MYT
|
||||
UPDATE AD_Column SET IsMandatory='Y', IsUpdateable='N',Updated=TO_TIMESTAMP('2023-12-27 13:39:49','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=216306
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 1:39:55 PM MYT
|
||||
UPDATE AD_Column SET IsUpdateable='N', IsAllowCopy='N',Updated=TO_TIMESTAMP('2023-12-27 13:39:55','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=216297
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 1:40:04 PM MYT
|
||||
UPDATE AD_Column SET IsAlwaysUpdateable='N',Updated=TO_TIMESTAMP('2023-12-27 13:40:04','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=216307
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 1:40:52 PM MYT
|
||||
UPDATE AD_Tab SET IsReadOnly='N',Updated=TO_TIMESTAMP('2023-12-27 13:40:52','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Tab_ID=200381
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 2:20:41 PM MYT
|
||||
UPDATE AD_Column SET IsMandatory='Y', IsUpdateable='Y',Updated=TO_TIMESTAMP('2023-12-27 14:20:41','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=216306
|
||||
;
|
||||
|
||||
-- Dec 27, 2023, 2:20:59 PM MYT
|
||||
UPDATE AD_Field SET IsReadOnly='Y',Updated=TO_TIMESTAMP('2023-12-27 14:20:59','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=208096
|
||||
;
|
||||
|
||||
-- Dec 28, 2023, 1:55:33 PM MYT
|
||||
INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('E','Can''t detach or re-attach default partition',0,0,'Y',TO_TIMESTAMP('2023-12-28 13:55:32','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-28 13:55:32','YYYY-MM-DD HH24:MI:SS'),100,200859,'CantDetachReattachDefaultPartition','D','375e3278-6231-4486-a8ef-8a978ce57698')
|
||||
;
|
||||
|
||||
-- Dec 28, 2023, 4:11:58 PM MYT
|
||||
INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('I','The partition {0} has been successfully detached from table {1}',0,0,'Y',TO_TIMESTAMP('2023-12-28 16:11:57','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-28 16:11:57','YYYY-MM-DD HH24:MI:SS'),100,200860,'PartitionDetachFromTable','D','3b92cf36-e6e4-401b-8663-5897e54b8966')
|
||||
;
|
||||
|
||||
-- Dec 28, 2023, 4:12:21 PM MYT
|
||||
INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('I','The partition {0} has been successfully re-attached to table {1}',0,0,'Y',TO_TIMESTAMP('2023-12-28 16:12:21','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-28 16:12:21','YYYY-MM-DD HH24:MI:SS'),100,200861,'PartitionReAttachToTable','D','4a3c84d0-fc35-4d62-b5ab-3ba018453783')
|
||||
;
|
||||
|
||||
-- Dec 29, 2023, 5:45:23 PM MYT
|
||||
INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('E','A maximum of two columns can be specified as partition keys. The first column defines the primary partition, and the second (optional) column defines the subpartition',0,0,'Y',TO_TIMESTAMP('2023-12-29 17:45:17','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-12-29 17:45:17','YYYY-MM-DD HH24:MI:SS'),100,200862,'OnlyTwoPartitionKeyAllowed','D','8b27d206-d764-4291-80ce-b00b135daa32')
|
||||
;
|
|
@ -26,6 +26,7 @@ package org.compiere.db.partition;
|
|||
|
||||
import org.compiere.model.MColumn;
|
||||
import org.compiere.model.MTable;
|
||||
import org.compiere.model.X_AD_TablePartition;
|
||||
import org.compiere.process.ProcessInfo;
|
||||
|
||||
/**
|
||||
|
@ -33,37 +34,69 @@ import org.compiere.process.ProcessInfo;
|
|||
*/
|
||||
public interface ITablePartitionService {
|
||||
/**
|
||||
* Is table already a partitioned table in DB
|
||||
* @param table
|
||||
* @param trxName
|
||||
* @return true if table have been partition in DB
|
||||
*/
|
||||
public boolean isPartitionedTable(MTable table, String trxName);
|
||||
|
||||
/**
|
||||
* Make existing table a partition table
|
||||
* @param table
|
||||
* @param trxName
|
||||
* @param processInfo
|
||||
* @return true if success
|
||||
*/
|
||||
public boolean createPartitionedTable(MTable table, String trxName, ProcessInfo processInfo);
|
||||
|
||||
/**
|
||||
* Add new partition for new data and migrate data to new partition (if needed by DB)
|
||||
* @param table
|
||||
* @param trxName
|
||||
* @param processInfo
|
||||
* @return true if success
|
||||
*/
|
||||
public boolean addPartitionAndMigrateData(MTable table, String trxName, ProcessInfo processInfo);
|
||||
|
||||
/**
|
||||
* Run post partition process (if needed)
|
||||
* @param table
|
||||
* @param trxName
|
||||
* @param processInfo
|
||||
* @return true if success
|
||||
*/
|
||||
public boolean runPostPartitionProcess(MTable table, String trxName, ProcessInfo processInfo);
|
||||
|
||||
/**
|
||||
* Validate partition configuration for table object
|
||||
* @param table
|
||||
* @return String error-code - null if not error
|
||||
*/
|
||||
public String isValidConfiguration(MTable table);
|
||||
|
||||
/**
|
||||
* Validate partition configuration for column object
|
||||
* @param column
|
||||
* @return String error-code - null if not error
|
||||
*/
|
||||
public String isValidConfiguration(MColumn column);
|
||||
|
||||
/**
|
||||
* Detach an attached table partition
|
||||
* @param table
|
||||
* @param partition
|
||||
* @param trxName
|
||||
* @param processInfo
|
||||
*/
|
||||
public void detachPartition(MTable table, X_AD_TablePartition partition, String trxName, ProcessInfo processInfo);
|
||||
|
||||
/**
|
||||
* Re-attach a detached table partition
|
||||
* @param table
|
||||
* @param partition
|
||||
* @param trxName
|
||||
* @param processInfo
|
||||
*/
|
||||
public void reattachPartition(MTable table, X_AD_TablePartition partition, String trxName, ProcessInfo processInfo);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import org.compiere.util.KeyNamePair;
|
|||
|
||||
/** Generated Interface for AD_TablePartition
|
||||
* @author iDempiere (generated)
|
||||
* @version Release 11
|
||||
* @version Release 12
|
||||
*/
|
||||
public interface I_AD_TablePartition
|
||||
{
|
||||
|
@ -156,6 +156,19 @@ public interface I_AD_TablePartition
|
|||
*/
|
||||
public boolean isActive();
|
||||
|
||||
/** Column name IsPartitionAttached */
|
||||
public static final String COLUMNNAME_IsPartitionAttached = "IsPartitionAttached";
|
||||
|
||||
/** Set Attached.
|
||||
* Partition attached to table
|
||||
*/
|
||||
public void setIsPartitionAttached (boolean IsPartitionAttached);
|
||||
|
||||
/** Get Attached.
|
||||
* Partition attached to table
|
||||
*/
|
||||
public boolean isPartitionAttached();
|
||||
|
||||
/** Column name Name */
|
||||
public static final String COLUMNNAME_Name = "Name";
|
||||
|
||||
|
@ -169,6 +182,30 @@ public interface I_AD_TablePartition
|
|||
*/
|
||||
public String getName();
|
||||
|
||||
/** Column name Parent_TablePartition_ID */
|
||||
public static final String COLUMNNAME_Parent_TablePartition_ID = "Parent_TablePartition_ID";
|
||||
|
||||
/** Set Parent Partition.
|
||||
* Parent table partition
|
||||
*/
|
||||
public void setParent_TablePartition_ID (int Parent_TablePartition_ID);
|
||||
|
||||
/** Get Parent Partition.
|
||||
* Parent table partition
|
||||
*/
|
||||
public int getParent_TablePartition_ID();
|
||||
|
||||
public org.compiere.model.I_AD_TablePartition getParent_TablePartition() throws RuntimeException;
|
||||
|
||||
/** Column name Processing */
|
||||
public static final String COLUMNNAME_Processing = "Processing";
|
||||
|
||||
/** Set Process Now */
|
||||
public void setProcessing (boolean Processing);
|
||||
|
||||
/** Get Process Now */
|
||||
public boolean isProcessing();
|
||||
|
||||
/** Column name Updated */
|
||||
public static final String COLUMNNAME_Updated = "Updated";
|
||||
|
||||
|
|
|
@ -1019,12 +1019,28 @@ public class MTable extends X_AD_Table implements ImmutablePOSupport
|
|||
* @return new X_AD_TablePartition record
|
||||
*/
|
||||
public X_AD_TablePartition createTablePartition(String name, String expression, String trxName, MColumn column)
|
||||
{
|
||||
return createTablePartition(name, expression, trxName, column, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and save new X_AD_TablePartition record.
|
||||
* @param name
|
||||
* @param expression
|
||||
* @param trxName
|
||||
* @param column
|
||||
* @param parentPartition
|
||||
* @return new X_AD_TablePartition record
|
||||
*/
|
||||
public X_AD_TablePartition createTablePartition(String name, String expression, String trxName, MColumn column, X_AD_TablePartition parentPartition)
|
||||
{
|
||||
X_AD_TablePartition partition = new X_AD_TablePartition(Env.getCtx(), 0, trxName);
|
||||
partition.setAD_Table_ID(getAD_Table_ID());
|
||||
partition.setName(name);
|
||||
partition.setExpressionPartition(expression);
|
||||
partition.setAD_Column_ID(column.getAD_Column_ID());
|
||||
partition.setAD_Column_ID(column.getAD_Column_ID());
|
||||
if (parentPartition != null)
|
||||
partition.setParent_TablePartition_ID(parentPartition.getAD_TablePartition_ID());
|
||||
partition.saveEx();
|
||||
return partition;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import java.util.Properties;
|
|||
|
||||
/** Generated Model for AD_TablePartition
|
||||
* @author iDempiere (generated)
|
||||
* @version Release 11 - $Id$ */
|
||||
* @version Release 12 - $Id$ */
|
||||
@org.adempiere.base.Model(table="AD_TablePartition")
|
||||
public class X_AD_TablePartition extends PO implements I_AD_TablePartition, I_Persistent
|
||||
{
|
||||
|
@ -30,7 +30,7 @@ public class X_AD_TablePartition extends PO implements I_AD_TablePartition, I_Pe
|
|||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 20231222L;
|
||||
private static final long serialVersionUID = 20231227L;
|
||||
|
||||
/** Standard Constructor */
|
||||
public X_AD_TablePartition (Properties ctx, int AD_TablePartition_ID, String trxName)
|
||||
|
@ -41,6 +41,8 @@ public class X_AD_TablePartition extends PO implements I_AD_TablePartition, I_Pe
|
|||
setAD_Column_ID (0);
|
||||
setAD_Table_ID (0);
|
||||
setExpressionPartition (null);
|
||||
setIsPartitionAttached (true);
|
||||
// Y
|
||||
setName (null);
|
||||
} */
|
||||
}
|
||||
|
@ -54,6 +56,8 @@ public class X_AD_TablePartition extends PO implements I_AD_TablePartition, I_Pe
|
|||
setAD_Column_ID (0);
|
||||
setAD_Table_ID (0);
|
||||
setExpressionPartition (null);
|
||||
setIsPartitionAttached (true);
|
||||
// Y
|
||||
setName (null);
|
||||
} */
|
||||
}
|
||||
|
@ -67,6 +71,8 @@ public class X_AD_TablePartition extends PO implements I_AD_TablePartition, I_Pe
|
|||
setAD_Column_ID (0);
|
||||
setAD_Table_ID (0);
|
||||
setExpressionPartition (null);
|
||||
setIsPartitionAttached (true);
|
||||
// Y
|
||||
setName (null);
|
||||
} */
|
||||
}
|
||||
|
@ -80,6 +86,8 @@ public class X_AD_TablePartition extends PO implements I_AD_TablePartition, I_Pe
|
|||
setAD_Column_ID (0);
|
||||
setAD_Table_ID (0);
|
||||
setExpressionPartition (null);
|
||||
setIsPartitionAttached (true);
|
||||
// Y
|
||||
setName (null);
|
||||
} */
|
||||
}
|
||||
|
@ -221,6 +229,29 @@ public class X_AD_TablePartition extends PO implements I_AD_TablePartition, I_Pe
|
|||
return (String)get_Value(COLUMNNAME_ExpressionPartition);
|
||||
}
|
||||
|
||||
/** Set Attached.
|
||||
@param IsPartitionAttached Partition attached to table
|
||||
*/
|
||||
public void setIsPartitionAttached (boolean IsPartitionAttached)
|
||||
{
|
||||
set_Value (COLUMNNAME_IsPartitionAttached, Boolean.valueOf(IsPartitionAttached));
|
||||
}
|
||||
|
||||
/** Get Attached.
|
||||
@return Partition attached to table
|
||||
*/
|
||||
public boolean isPartitionAttached()
|
||||
{
|
||||
Object oo = get_Value(COLUMNNAME_IsPartitionAttached);
|
||||
if (oo != null)
|
||||
{
|
||||
if (oo instanceof Boolean)
|
||||
return ((Boolean)oo).booleanValue();
|
||||
return "Y".equals(oo);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Set Name.
|
||||
@param Name Alphanumeric identifier of the entity
|
||||
*/
|
||||
|
@ -236,4 +267,54 @@ public class X_AD_TablePartition extends PO implements I_AD_TablePartition, I_Pe
|
|||
{
|
||||
return (String)get_Value(COLUMNNAME_Name);
|
||||
}
|
||||
|
||||
public org.compiere.model.I_AD_TablePartition getParent_TablePartition() throws RuntimeException
|
||||
{
|
||||
return (org.compiere.model.I_AD_TablePartition)MTable.get(getCtx(), org.compiere.model.I_AD_TablePartition.Table_ID)
|
||||
.getPO(getParent_TablePartition_ID(), get_TrxName());
|
||||
}
|
||||
|
||||
/** Set Parent Partition.
|
||||
@param Parent_TablePartition_ID Parent table partition
|
||||
*/
|
||||
public void setParent_TablePartition_ID (int Parent_TablePartition_ID)
|
||||
{
|
||||
if (Parent_TablePartition_ID < 1)
|
||||
set_ValueNoCheck (COLUMNNAME_Parent_TablePartition_ID, null);
|
||||
else
|
||||
set_ValueNoCheck (COLUMNNAME_Parent_TablePartition_ID, Integer.valueOf(Parent_TablePartition_ID));
|
||||
}
|
||||
|
||||
/** Get Parent Partition.
|
||||
@return Parent table partition
|
||||
*/
|
||||
public int getParent_TablePartition_ID()
|
||||
{
|
||||
Integer ii = (Integer)get_Value(COLUMNNAME_Parent_TablePartition_ID);
|
||||
if (ii == null)
|
||||
return 0;
|
||||
return ii.intValue();
|
||||
}
|
||||
|
||||
/** Set Process Now.
|
||||
@param Processing Process Now
|
||||
*/
|
||||
public void setProcessing (boolean Processing)
|
||||
{
|
||||
set_Value (COLUMNNAME_Processing, Boolean.valueOf(Processing));
|
||||
}
|
||||
|
||||
/** Get Process Now.
|
||||
@return Process Now */
|
||||
public boolean isProcessing()
|
||||
{
|
||||
Object oo = get_Value(COLUMNNAME_Processing);
|
||||
if (oo != null)
|
||||
{
|
||||
if (oo instanceof Boolean)
|
||||
return ((Boolean)oo).booleanValue();
|
||||
return "Y".equals(oo);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ import java.sql.ResultSet;
|
|||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
@ -38,8 +39,10 @@ import org.compiere.db.partition.RangePartitionInterval;
|
|||
import org.compiere.model.MColumn;
|
||||
import org.compiere.model.MTable;
|
||||
import org.compiere.model.Query;
|
||||
import org.compiere.model.X_AD_Column;
|
||||
import org.compiere.model.X_AD_TablePartition;
|
||||
import org.compiere.process.ProcessInfo;
|
||||
import org.compiere.util.CLogger;
|
||||
import org.compiere.util.DB;
|
||||
import org.compiere.util.DisplayType;
|
||||
import org.compiere.util.Env;
|
||||
|
@ -71,6 +74,9 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
.append(" MODIFY PARTITION BY ");
|
||||
List<MColumn> partitionKeyColumns = table.getPartitionKeyColumns(false);
|
||||
MColumn partitionKeyColumn = partitionKeyColumns.get(0);
|
||||
MColumn subPartitionColumn = null;
|
||||
if (partitionKeyColumns.size() > 1)
|
||||
subPartitionColumn = partitionKeyColumns.get(1);
|
||||
String partitioningMethod = partitionKeyColumn.getPartitioningMethod();
|
||||
if (partitioningMethod.equals(MColumn.PARTITIONINGMETHOD_List))
|
||||
alterStmt.append("List");
|
||||
|
@ -79,18 +85,28 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
else
|
||||
throw new IllegalArgumentException(Msg.getMsg(Env.getCtx(), "PartitioningMethodNotSupported", new Object[]{partitioningMethod}));
|
||||
|
||||
alterStmt.append(" (" + partitionKeyColumn.getColumnName() + ")");
|
||||
alterStmt.append(" (").append(partitionKeyColumn.getColumnName()).append(")");
|
||||
|
||||
if (partitioningMethod.equals(MColumn.PARTITIONINGMETHOD_List) && useAutomaticListPartition) {
|
||||
//with automatic, we still need to create at least one partition and we will create a null partition to fulfill the requirement
|
||||
alterStmt.append(" AUTOMATIC (PARTITION default_partition ");
|
||||
alterStmt.append(" AUTOMATIC ");
|
||||
} else if (useIntervalPartition) {
|
||||
alterStmt.append(" INTERVAL(");
|
||||
alterStmt.append(getIntervalExpression(partitionKeyColumn));
|
||||
alterStmt.append(") (PARTITION default_partition ");
|
||||
} else {
|
||||
alterStmt.append(" (PARTITION default_partition ");
|
||||
alterStmt.append(") ");
|
||||
}
|
||||
//oracle will auto create default partition for sub-partition
|
||||
if (subPartitionColumn != null) {
|
||||
alterStmt.append("SUBPARTITION BY ");
|
||||
if (subPartitionColumn.getPartitioningMethod().equals(MColumn.PARTITIONINGMETHOD_List))
|
||||
alterStmt.append("List");
|
||||
else if (subPartitionColumn.getPartitioningMethod().equals(MColumn.PARTITIONINGMETHOD_Range))
|
||||
alterStmt.append("Range");
|
||||
else
|
||||
throw new IllegalArgumentException(Msg.getMsg(Env.getCtx(), "PartitioningMethodNotSupported", new Object[]{subPartitionColumn.getPartitioningMethod()}));
|
||||
alterStmt.append(" (").append(subPartitionColumn.getColumnName()).append(")");
|
||||
}
|
||||
alterStmt.append(" (PARTITION default_partition ");
|
||||
StringBuilder defaultExpression = new StringBuilder();
|
||||
if (partitioningMethod.equals(MColumn.PARTITIONINGMETHOD_List)) {
|
||||
defaultExpression.append("VALUES (");
|
||||
|
@ -124,6 +140,10 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param partitionKeyColumn
|
||||
* @return Oracle year/month interval expression (using NUMTOYMINTERVAL) for column range interval
|
||||
*/
|
||||
private String getIntervalExpression(MColumn partitionKeyColumn) {
|
||||
if (DisplayType.isDate(partitionKeyColumn.getAD_Reference_ID()) || DisplayType.isTimestampWithTimeZone(partitionKeyColumn.getAD_Reference_ID())) {
|
||||
RangePartitionInterval.Interval interval = RangePartitionInterval.getInterval(partitionKeyColumn);
|
||||
|
@ -157,11 +177,14 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
List<MColumn> partitionKeyColumns = table.getPartitionKeyColumns(false);
|
||||
if (partitionKeyColumns.size() == 0)
|
||||
return false;
|
||||
MColumn partitionKeyColumn = partitionKeyColumns.get(0);
|
||||
MColumn partitionKeyColumn = partitionKeyColumns.get(0);
|
||||
String sql = "SELECT Column_Name FROM User_Part_Key_Columns WHERE Name=? ORDER BY Column_Position";
|
||||
String partKeyColumn = DB.getSQLValueString(trxName, sql, table.getTableName().toUpperCase());
|
||||
if (!partitionKeyColumn.getColumnName().equalsIgnoreCase(partKeyColumn))
|
||||
return false;
|
||||
MColumn subPartitionColumn = null;
|
||||
if (partitionKeyColumns.size() > 1)
|
||||
subPartitionColumn = partitionKeyColumns.get(1);
|
||||
String partitioningMethod = partitionKeyColumn.getPartitioningMethod();
|
||||
if (partitioningMethod.equals(MColumn.PARTITIONINGMETHOD_List))
|
||||
{
|
||||
|
@ -172,7 +195,7 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
}
|
||||
else
|
||||
{
|
||||
isUpdated = addListPartition(table, partitionKeyColumn, trxName, processInfo);
|
||||
isUpdated = addListPartition(table, partitionKeyColumn, trxName, processInfo, "default_partition", null, null);
|
||||
}
|
||||
}
|
||||
else if (partitioningMethod.equals(MColumn.PARTITIONINGMETHOD_Range))
|
||||
|
@ -193,16 +216,90 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
else
|
||||
{
|
||||
syncRange(table, partitionKeyColumn, trxName, interval, processInfo);
|
||||
isUpdated = addRangePartition(table, partitionKeyColumn, trxName, processInfo);
|
||||
isUpdated = addRangePartition(table, partitionKeyColumn, trxName, processInfo, "default_partition", null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
throw new IllegalArgumentException(Msg.getMsg(Env.getCtx(), "PartitioningMethodNotSupported", new Object[]{partitioningMethod}));
|
||||
|
||||
if (subPartitionColumn != null) {
|
||||
List<X_AD_TablePartition> primaryPartitions = getPrimaryPartitions(table, partitionKeyColumn, trxName);
|
||||
if (subPartitionColumn.getPartitioningMethod().equals(MColumn.PARTITIONINGMETHOD_List))
|
||||
{
|
||||
for(X_AD_TablePartition primaryPartition : primaryPartitions)
|
||||
{
|
||||
String defaultSubPartition = getDefaultSubPartitionName(table, primaryPartition, false, trxName);
|
||||
if (defaultSubPartition == null)
|
||||
continue;
|
||||
isUpdated = addListPartition(table, subPartitionColumn, trxName, processInfo, defaultSubPartition, primaryPartition.getName(), primaryPartition);
|
||||
}
|
||||
}
|
||||
else if (subPartitionColumn.getPartitioningMethod().equals(MColumn.PARTITIONINGMETHOD_Range))
|
||||
{
|
||||
for(X_AD_TablePartition primaryPartition : primaryPartitions)
|
||||
{
|
||||
String defaultSubPartition = getDefaultSubPartitionName(table, primaryPartition, true, trxName);
|
||||
if (defaultSubPartition == null)
|
||||
continue;
|
||||
isUpdated = addRangePartition(table, subPartitionColumn, trxName, processInfo, defaultSubPartition, primaryPartition.getName(), primaryPartition);
|
||||
}
|
||||
}
|
||||
else
|
||||
throw new IllegalArgumentException(Msg.getMsg(Env.getCtx(), "PartitioningMethodNotSupported", new Object[]{subPartitionColumn.getPartitioningMethod()}));
|
||||
}
|
||||
return isUpdated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find name of default sub-partition auto created by Oracle
|
||||
* @param table
|
||||
* @param primaryPartition
|
||||
* @param range true if sub-partition is range, false for list
|
||||
* @param trxName
|
||||
* @return name of default sub-partition
|
||||
*/
|
||||
private String getDefaultSubPartitionName(MTable table, X_AD_TablePartition primaryPartition, boolean range, String trxName) {
|
||||
String sql =
|
||||
"""
|
||||
SELECT High_Value, SubPartition_Name
|
||||
FROM User_Tab_SubPartitions
|
||||
WHERE Table_Name=? AND Partition_Name=?
|
||||
""";
|
||||
try(PreparedStatement stmt = DB.prepareStatement(sql, trxName)) {
|
||||
stmt.setString(1, table.getTableName().toUpperCase());
|
||||
stmt.setString(2, primaryPartition.getName().toUpperCase());
|
||||
ResultSet rs = stmt.executeQuery();
|
||||
while(rs.next()) {
|
||||
String expression = rs.getString(1);
|
||||
if (range) {
|
||||
if ("MAXVALUE".equals(expression))
|
||||
return rs.getString(2);
|
||||
} else {
|
||||
if ("DEFAULT".equals(expression)) {
|
||||
return rs.getString(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new DBException(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the list of partition for partitionKeyColumn
|
||||
* @param table
|
||||
* @param partitionKeyColumn
|
||||
* @param trxName
|
||||
* @return list of partition for column
|
||||
*/
|
||||
private List<X_AD_TablePartition> getPrimaryPartitions(MTable table, MColumn partitionKeyColumn, String trxName) {
|
||||
String whereClause = "AD_Table_ID=? AND AD_Column_ID=? And Name != 'DEFAULT_PARTITION' AND IsPartitionAttached='Y' AND IsActive='Y'";
|
||||
Query query = new Query(Env.getCtx(), MTable.get(Env.getCtx(), X_AD_TablePartition.Table_ID), whereClause, trxName);
|
||||
return query.setParameters(table.getAD_Table_ID(), partitionKeyColumn.getAD_Column_ID()).list();
|
||||
}
|
||||
|
||||
/**
|
||||
* Change partition method from list to range
|
||||
* @param table
|
||||
|
@ -215,7 +312,7 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
StringBuilder alterStmt = new StringBuilder("ALTER TABLE ")
|
||||
.append(table.getTableName())
|
||||
.append(" MODIFY PARTITION BY RANGE ")
|
||||
.append(" (" + partitionKeyColumn.getColumnName() + ")");
|
||||
.append(" (").append(partitionKeyColumn.getColumnName()).append(")");
|
||||
if (useIntervalPartition) {
|
||||
alterStmt.append(" INTERVAL(");
|
||||
alterStmt.append(getIntervalExpression(partitionKeyColumn));
|
||||
|
@ -264,7 +361,7 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
StringBuilder alterStmt = new StringBuilder("ALTER TABLE ")
|
||||
.append(table.getTableName())
|
||||
.append(" MODIFY PARTITION BY List ");
|
||||
alterStmt.append(" (" + keyColumn + ")");
|
||||
alterStmt.append(" (").append(keyColumn).append(")");
|
||||
alterStmt.append(" AUTOMATIC (PARTITION default_partition VALUES (");
|
||||
alterStmt.append("NULL");
|
||||
alterStmt.append("))");
|
||||
|
@ -321,7 +418,7 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
StringBuilder alterStmt = new StringBuilder("ALTER TABLE ")
|
||||
.append(table.getTableName())
|
||||
.append(" MODIFY PARTITION BY Range ");
|
||||
alterStmt.append(" (" + partitionKeyColumn.getColumnName() + ")");
|
||||
alterStmt.append(" (").append(partitionKeyColumn.getColumnName()).append(")");
|
||||
alterStmt.append(" (PARTITION default_partition VALUES LESS THAN (");
|
||||
alterStmt.append("MAXVALUE");
|
||||
alterStmt.append("))");
|
||||
|
@ -345,7 +442,7 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
FROM User_Tab_Partitions
|
||||
WHERE Table_Name=?
|
||||
""";
|
||||
Query query = new Query(Env.getCtx(), X_AD_TablePartition.Table_Name, "AD_Table_ID=?", trxName);
|
||||
Query query = new Query(Env.getCtx(), X_AD_TablePartition.Table_Name, "AD_Table_ID=? AND Parent_TablePartition_ID IS NULL", trxName);
|
||||
List<X_AD_TablePartition> existingList = query.setParameters(table.getAD_Table_ID()).list();
|
||||
List<Integer> matchedIds = new ArrayList<Integer>();
|
||||
List<MColumn> partitionKeyColumns = table.getPartitionKeyColumns(false);
|
||||
|
@ -429,15 +526,19 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
* @param partitionKeyColumn
|
||||
* @param trxName
|
||||
* @param pi
|
||||
* @param fromPartition name of default partition to select from
|
||||
* @param partitionNamePrefix
|
||||
* @param parentPartition
|
||||
* @return true if new list partition added
|
||||
*/
|
||||
private boolean addListPartition(MTable table, MColumn partitionKeyColumn, String trxName, ProcessInfo pi) {
|
||||
private boolean addListPartition(MTable table, MColumn partitionKeyColumn, String trxName, ProcessInfo pi, String fromPartition, String partitionNamePrefix, X_AD_TablePartition parentPartition) {
|
||||
boolean isUpdated = false;
|
||||
List<X_AD_TablePartition> partitions = new ArrayList<>();
|
||||
boolean subPartition = parentPartition != null;
|
||||
|
||||
StringBuilder sql = new StringBuilder();
|
||||
sql.append("SELECT DISTINCT ").append(partitionKeyColumn.getColumnName());
|
||||
sql.append(" FROM ").append(table.getTableName()).append(" PARTITION (default_partition) ");
|
||||
sql.append(" FROM ").append(table.getTableName()).append(" ").append(subPartition ? "SubPartition(" : "Partition(").append(fromPartition).append(") ");
|
||||
sql.append("ORDER BY ").append(partitionKeyColumn.getColumnName());
|
||||
|
||||
try (PreparedStatement pstmt = DB.prepareStatement(sql.toString(), trxName))
|
||||
|
@ -447,6 +548,8 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
{
|
||||
StringBuilder name = new StringBuilder();
|
||||
StringBuilder expression = new StringBuilder("VALUES (");
|
||||
if (!Util.isEmpty(partitionNamePrefix, true))
|
||||
name.append(partitionNamePrefix).append("_");
|
||||
String s = rs.getString(partitionKeyColumn.getColumnName());
|
||||
name.append(s);
|
||||
if (DisplayType.isText(partitionKeyColumn.getAD_Reference_ID()))
|
||||
|
@ -459,13 +562,12 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
expression.append(rs.getInt(partitionKeyColumn.getColumnName()));
|
||||
else if (DisplayType.isNumeric(partitionKeyColumn.getAD_Reference_ID()))
|
||||
expression.append(rs.getBigDecimal(partitionKeyColumn.getColumnName()).toPlainString());
|
||||
|
||||
|
||||
|
||||
expression.append(")");
|
||||
if (Character.isDigit(name.charAt(0))) {
|
||||
name.insert(0, "p");
|
||||
}
|
||||
X_AD_TablePartition partition = table.createTablePartition(name.toString(), expression.toString(), trxName, partitionKeyColumn);
|
||||
X_AD_TablePartition partition = table.createTablePartition(name.toString(), expression.toString(), trxName, partitionKeyColumn, parentPartition);
|
||||
partitions.add(partition);
|
||||
}
|
||||
}
|
||||
|
@ -477,10 +579,10 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
for(X_AD_TablePartition partition : partitions)
|
||||
{
|
||||
StringBuilder alterStmt = new StringBuilder();
|
||||
alterStmt.append("ALTER TABLE " + table.getTableName() + " SPLIT PARTITION default_partition ");
|
||||
alterStmt.append("ALTER TABLE ").append(table.getTableName()).append(" SPLIT ").append(subPartition ? "SubPartition " : "Partition ").append(fromPartition).append(" ");
|
||||
alterStmt.append(partition.getExpressionPartition());
|
||||
alterStmt.append(" INTO ( PARTITION ").append(partition.getName()).append(", ");
|
||||
alterStmt.append("PARTITION default_partition )");
|
||||
alterStmt.append(" INTO ( ").append(subPartition ? "SUBPARTITION " : "PARTITION ").append(partition.getName()).append(", ");
|
||||
alterStmt.append(subPartition ? "SubPartition " : "Partition ").append(fromPartition).append(" )");
|
||||
int no = DB.executeUpdateEx(alterStmt.toString(), trxName);
|
||||
if (pi != null)
|
||||
pi.addLog(0, null, null, no + " " + alterStmt.toString());
|
||||
|
@ -496,12 +598,16 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
* @param partitionKeyColumn
|
||||
* @param trxName
|
||||
* @param pi
|
||||
* @param fromPartition name of default partition to select from
|
||||
* @param partitionNamePrefix
|
||||
* @param parentPartition
|
||||
* @return true if new range partition added
|
||||
*/
|
||||
private boolean addRangePartition(MTable table, MColumn partitionKeyColumn, String trxName, ProcessInfo pi) {
|
||||
private boolean addRangePartition(MTable table, MColumn partitionKeyColumn, String trxName, ProcessInfo pi, String fromPartition, String partitionNamePrefix, X_AD_TablePartition parentPartition) {
|
||||
boolean isUpdated = false;
|
||||
X_AD_TablePartition partition = null;
|
||||
RangePartitionColumn rangePartitionColumn = null;
|
||||
boolean subPartition = parentPartition != null;
|
||||
|
||||
String partitionKeyColumnName = partitionKeyColumn.getColumnName();
|
||||
String partitionKeyColumnRangeIntervalPattern = partitionKeyColumn.getRangePartitionInterval();
|
||||
|
@ -509,7 +615,7 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
StringBuilder sql = new StringBuilder();
|
||||
sql.append("SELECT MIN(").append(partitionKeyColumnName).append(") AS min_value, ");
|
||||
sql.append("MAX(").append(partitionKeyColumnName).append(") AS max_value ");
|
||||
sql.append("FROM ").append(table.getTableName()).append(" PARTITION (default_partition) ");
|
||||
sql.append("FROM ").append(table.getTableName()).append(" ").append(subPartition ? "SubPartition(" : "Partition(").append(fromPartition).append(")");
|
||||
|
||||
List<Object> values = DB.getSQLValueObjectsEx(trxName, sql.toString());
|
||||
if (values.get(0) != null && values.get(1) != null)
|
||||
|
@ -529,17 +635,19 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
for(RangePartitionInterval rangePartitionInterval : rangePartitionIntervals)
|
||||
{
|
||||
StringBuilder name = new StringBuilder();
|
||||
if (!Util.isEmpty(partitionNamePrefix, true))
|
||||
name.append(partitionNamePrefix).append("_");
|
||||
name.append(rangePartitionInterval.getName());
|
||||
|
||||
StringBuilder countStmt = new StringBuilder("SELECT Count(*) FROM ")
|
||||
.append(table.getTableName()).append(" ")
|
||||
.append(table.getTableName()).append(" ").append(subPartition ? "SubPartition(" : "Partition(").append(fromPartition).append(") ")
|
||||
.append("WHERE ").append(" ")
|
||||
.append(partitionKeyColumn.getColumnName()).append(" >= ");
|
||||
if (DisplayType.isDate(partitionKeyColumn.getAD_Reference_ID()) || DisplayType.isTimestampWithTimeZone(partitionKeyColumn.getAD_Reference_ID()))
|
||||
countStmt.append("TO_DATE(").append(rangePartitionInterval.getFrom()).append(",'YYYY-MM-DD') ");
|
||||
else
|
||||
countStmt.append(rangePartitionInterval.getFrom()).append(" ");
|
||||
countStmt.append("AND " + partitionKeyColumn.getColumnName()).append(" < ");
|
||||
countStmt.append("AND ").append(partitionKeyColumn.getColumnName()).append(" < ");
|
||||
if (DisplayType.isDate(partitionKeyColumn.getAD_Reference_ID()) || DisplayType.isTimestampWithTimeZone(partitionKeyColumn.getAD_Reference_ID()))
|
||||
countStmt.append("TO_DATE(").append(rangePartitionInterval.getTo()).append(",'YYYY-MM-DD') ");
|
||||
else
|
||||
|
@ -574,14 +682,14 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
name.insert(0, "p");
|
||||
}
|
||||
if (!tablePartitionNames.contains(name.toString()))
|
||||
partition = table.createTablePartition(name.toString(), expression.toString(), trxName, partitionKeyColumn);
|
||||
partition = table.createTablePartition(name.toString(), expression.toString(), trxName, partitionKeyColumn, parentPartition);
|
||||
|
||||
if (partition != null)
|
||||
{
|
||||
StringBuilder alterStmt = new StringBuilder();
|
||||
alterStmt.append("ALTER TABLE " + table.getTableName() + " SPLIT PARTITION default_partition ");
|
||||
alterStmt.append(" INTO ( PARTITION ").append(partition.getName()).append(" ").append(partition.getExpressionPartition()).append(", ");
|
||||
alterStmt.append("PARTITION default_partition )");
|
||||
alterStmt.append("ALTER TABLE ").append(table.getTableName()).append(" SPLIT ").append(subPartition ? "SubPartition " : "Partition ").append(fromPartition);
|
||||
alterStmt.append(" INTO ( ").append(subPartition ? "SUBPARTITION " : "PARTITION ").append(partition.getName()).append(" ").append(partition.getExpressionPartition()).append(", ");
|
||||
alterStmt.append(subPartition ? "SubPartition " : "Partition ").append(fromPartition).append(" )");
|
||||
int no = DB.executeUpdateEx(alterStmt.toString(), trxName);
|
||||
if (pi != null)
|
||||
pi.addLog(0, null, null, no + " " + alterStmt.toString());
|
||||
|
@ -594,6 +702,53 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
|
||||
@Override
|
||||
public boolean runPostPartitionProcess(MTable table, String trxName, ProcessInfo processInfo) {
|
||||
String sql =
|
||||
"""
|
||||
select index_name, partition_name, 'partition' ddl_type
|
||||
from user_ind_partitions
|
||||
where (index_name) in
|
||||
( select index_name
|
||||
from user_indexes
|
||||
where table_name = ?
|
||||
)
|
||||
and status = 'UNUSABLE'
|
||||
union all
|
||||
select index_name, subpartition_name, 'subpartition' ddl_type
|
||||
from user_ind_subpartitions
|
||||
where (index_name) in
|
||||
( select index_name
|
||||
from user_indexes
|
||||
where table_name = ?
|
||||
)
|
||||
and status = 'UNUSABLE'
|
||||
union all
|
||||
select index_name, null, null
|
||||
from user_indexes
|
||||
where table_name = ?
|
||||
and status = 'UNUSABLE'
|
||||
""";
|
||||
|
||||
try (PreparedStatement stmt = DB.prepareStatement(sql, trxName)) {
|
||||
stmt.setString(1, table.getTableName().toUpperCase());
|
||||
stmt.setString(2, table.getTableName().toUpperCase());
|
||||
stmt.setString(3, table.getTableName().toUpperCase());
|
||||
ResultSet rs = stmt.executeQuery();
|
||||
while(rs.next()) {
|
||||
StringBuilder alter = new StringBuilder("ALTER INDEX ")
|
||||
.append(rs.getString(1))
|
||||
.append(" REBUILD ");
|
||||
String ddlType = rs.getString(3);
|
||||
if (!Util.isEmpty(ddlType, true) ) {
|
||||
alter.append(ddlType).append(" ").append(rs.getString(2));
|
||||
}
|
||||
int no = DB.executeUpdateEx(alter.toString(), trxName);
|
||||
if (processInfo != null)
|
||||
processInfo.addLog(0, null, null, no + " " + alter.toString());
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
CLogger.getCLogger(getClass()).log(Level.SEVERE, e.getMessage(), e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -621,28 +776,174 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
partitionKeyColumns.remove(column);
|
||||
}
|
||||
|
||||
if (partitionKeyColumns.size() > 1)
|
||||
return Msg.getMsg(Env.getCtx(), "OnlyOnePartitionKeyAllowed");
|
||||
if (partitionKeyColumns.size() > 2)
|
||||
return Msg.getMsg(Env.getCtx(), "OnlyTwoPartitionKeyAllowed");
|
||||
|
||||
if (column.isActive() && column.isPartitionKey() && column.getPartitioningMethod().equals(MColumn.PARTITIONINGMETHOD_Range)) {
|
||||
String error = RangePartitionInterval.validateIntervalPattern(column);
|
||||
if (!Util.isEmpty(error))
|
||||
return error;
|
||||
}
|
||||
|
||||
if (!isPartitionedTable(table, trxName))
|
||||
return null;
|
||||
|
||||
//can't change partition key column for range partition
|
||||
if ((!column.isPartitionKey() || !column.isActive()) && Boolean.TRUE.equals(column.get_ValueOld("IsPartitionKey"))) {
|
||||
if (isRangePartitionedTable(table, trxName))
|
||||
if (partitionKeyColumns.size() == 2
|
||||
|| (partitionKeyColumns.size() == 1 && !column.isPartitionKey())
|
||||
|| isRangePartitionedTable(table, trxName))
|
||||
return Msg.getMsg(Env.getCtx(), "PartitionConfigurationChanged");
|
||||
}
|
||||
|
||||
if (column.isActive() && column.isPartitionKey() && partitionKeyColumns.size() == 2) {
|
||||
if (column.is_ValueChanged(MColumn.COLUMNNAME_PartitioningMethod)) {
|
||||
return Msg.getMsg(Env.getCtx(), "PartitionConfigurationChanged");
|
||||
} else if (column.is_ValueChanged(MColumn.COLUMNNAME_SeqNoPartition)) {
|
||||
int oldSeq = column.get_ValueOldAsInt(MColumn.COLUMNNAME_SeqNoPartition);
|
||||
int newSeq = column.getSeqNoPartition();
|
||||
int otherSeq = partitionKeyColumns.get(0).getAD_Column_ID() == column.getAD_Column_ID()
|
||||
? partitionKeyColumns.get(1).getSeqNoPartition()
|
||||
: partitionKeyColumns.get(0).getSeqNoPartition();
|
||||
if (!(((newSeq < otherSeq) && (oldSeq < otherSeq)) || ((oldSeq > otherSeq) && (newSeq > otherSeq))))
|
||||
return Msg.getMsg(Env.getCtx(), "PartitionConfigurationChanged");
|
||||
}
|
||||
}
|
||||
|
||||
//can't change partition type to list for range partition
|
||||
if (column.isActive() && column.isPartitionKey() && column.getPartitioningMethod().equals(MColumn.PARTITIONINGMETHOD_List)) {
|
||||
if (isRangePartitionedTable(table, trxName))
|
||||
return Msg.getMsg(Env.getCtx(), "PartitionConfigurationChanged");
|
||||
}
|
||||
|
||||
if (column.isActive() && column.isPartitionKey() && column.getPartitioningMethod().equals(MColumn.PARTITIONINGMETHOD_Range)) {
|
||||
String error = RangePartitionInterval.validateIntervalPattern(column);
|
||||
if (!Util.isEmpty(error))
|
||||
return error;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detachPartition(MTable table, X_AD_TablePartition partition, String trxName,
|
||||
ProcessInfo processInfo) {
|
||||
if (partition.isPartitionAttached()) {
|
||||
String defaultPartitionName = "default_partition";
|
||||
if (partition.getParent_TablePartition_ID() > 0) {
|
||||
X_AD_TablePartition parentPartition = new X_AD_TablePartition(Env.getCtx(), partition.getParent_TablePartition_ID(), trxName);
|
||||
MColumn partitionKeyColumn = MColumn.get(partition.getAD_Column_ID());
|
||||
defaultPartitionName = getDefaultSubPartitionName(table, parentPartition, X_AD_Column.PARTITIONINGMETHOD_Range.equals(partitionKeyColumn.getPartitioningMethod()), trxName);
|
||||
}
|
||||
if (!defaultPartitionName.equalsIgnoreCase(partition.getName())) {
|
||||
StringBuilder exchangeTableName = new StringBuilder(table.getTableName())
|
||||
.append("_")
|
||||
.append(partition.getName());
|
||||
StringBuilder alter = null;
|
||||
Query query = new Query(Env.getCtx(), X_AD_TablePartition.Table_Name, "Parent_TablePartition_ID=? And IsActive='Y' AND IsPartitionAttached='Y'", trxName);
|
||||
List<X_AD_TablePartition> subPartitions = query.setParameters(partition.getAD_TablePartition_ID())
|
||||
.setOrderBy("Name")
|
||||
.list();
|
||||
if (subPartitions.size() > 0) {
|
||||
alter = new StringBuilder("CREATE TABLE ")
|
||||
.append(exchangeTableName)
|
||||
.append(" AS SELECT * FROM ")
|
||||
.append(table.getTableName())
|
||||
.append(" WHERE ROWNUM=-1 ");
|
||||
|
||||
int no = DB.executeUpdateEx(alter.toString(), trxName);
|
||||
if (processInfo != null)
|
||||
processInfo.addLog(0, null, null, no + " " + alter.toString());
|
||||
|
||||
alter = new StringBuilder("ALTER TABLE ")
|
||||
.append(exchangeTableName)
|
||||
.append(" MODIFY PARTITION BY ");
|
||||
MColumn subKeyColumn = MColumn.get(subPartitions.get(0).getAD_Column_ID());
|
||||
if (MColumn.PARTITIONINGMETHOD_Range.equals(subKeyColumn.getPartitioningMethod()))
|
||||
alter.append("RANGE (").append(subKeyColumn.getColumnName()).append(") ");
|
||||
else
|
||||
alter.append("LIST (").append(subKeyColumn.getColumnName()).append(") ");
|
||||
alter.append("(");
|
||||
for(X_AD_TablePartition subPartition : subPartitions) {
|
||||
alter.append("PARTITION ").append(subPartition.getExpressionPartition()).append(",");
|
||||
}
|
||||
if (MColumn.PARTITIONINGMETHOD_Range.equals(subKeyColumn.getPartitioningMethod()))
|
||||
alter.append("PARTITION VALUES LESS THAN (MAXVALUE))");
|
||||
else
|
||||
alter.append("PARTITION VALUES (DEFAULT))");
|
||||
no = DB.executeUpdateEx(alter.toString(), trxName);
|
||||
if (processInfo != null)
|
||||
processInfo.addLog(0, null, null, no + " " + alter.toString());
|
||||
} else {
|
||||
alter = new StringBuilder("CREATE TABLE ")
|
||||
.append(exchangeTableName)
|
||||
.append(" FOR EXCHANGE WITH TABLE ")
|
||||
.append(table.getTableName());
|
||||
|
||||
int no = DB.executeUpdateEx(alter.toString(), trxName);
|
||||
if (processInfo != null)
|
||||
processInfo.addLog(0, null, null, no + " " + alter.toString());
|
||||
}
|
||||
|
||||
alter = new StringBuilder("ALTER TABLE ")
|
||||
.append(table.getTableName());
|
||||
if (partition.getParent_TablePartition_ID() > 0)
|
||||
alter.append(" EXCHANGE SUBPARTITION ");
|
||||
else
|
||||
alter.append(" EXCHANGE PARTITION ");
|
||||
alter.append(partition.getName())
|
||||
.append(" WITH TABLE ")
|
||||
.append(exchangeTableName);
|
||||
int no = DB.executeUpdateEx(alter.toString(), trxName);
|
||||
if (processInfo != null)
|
||||
processInfo.addLog(0, null, null, no + " " + alter.toString());
|
||||
partition.setIsPartitionAttached(false);
|
||||
partition.saveEx();
|
||||
} else {
|
||||
throw new AdempiereException(Msg.getMsg(Env.getCtx(), "CantDetachReattachDefaultPartition"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reattachPartition(MTable table, X_AD_TablePartition partition, String trxName,
|
||||
ProcessInfo processInfo) {
|
||||
if (!partition.isPartitionAttached()) {
|
||||
String defaultPartitionName = "default_partition";
|
||||
if (partition.getParent_TablePartition_ID() > 0) {
|
||||
X_AD_TablePartition parentPartition = new X_AD_TablePartition(Env.getCtx(), partition.getParent_TablePartition_ID(), trxName);
|
||||
MColumn partitionKeyColumn = MColumn.get(partition.getAD_Column_ID());
|
||||
defaultPartitionName = getDefaultSubPartitionName(table, parentPartition, X_AD_Column.PARTITIONINGMETHOD_Range.equals(partitionKeyColumn.getPartitioningMethod()), trxName);
|
||||
}
|
||||
if (!defaultPartitionName.equalsIgnoreCase(partition.getName())) {
|
||||
StringBuilder exchangeTableName = new StringBuilder(table.getTableName())
|
||||
.append("_")
|
||||
.append(partition.getName());
|
||||
StringBuilder updateStmt = new StringBuilder();
|
||||
updateStmt.append("INSERT INTO ").append(table.getTableName()).append(" ");
|
||||
updateStmt.append("SELECT * FROM ").append(exchangeTableName);
|
||||
int no = DB.executeUpdateEx(updateStmt.toString(), trxName);
|
||||
if (processInfo != null)
|
||||
processInfo.addLog(0, null, null, no + " " + updateStmt.toString());
|
||||
|
||||
updateStmt = new StringBuilder("DELETE FROM ").append(exchangeTableName);
|
||||
no = DB.executeUpdateEx(updateStmt.toString(), trxName);
|
||||
if (processInfo != null)
|
||||
processInfo.addLog(0, null, null, no + " " + updateStmt.toString());
|
||||
|
||||
Query query = new Query(Env.getCtx(), X_AD_TablePartition.Table_Name, "Parent_TablePartition_ID=?", trxName);
|
||||
List<X_AD_TablePartition> subPartitions = query.setParameters(partition.getAD_TablePartition_ID()).list();
|
||||
for(X_AD_TablePartition subPartition : subPartitions) {
|
||||
subPartition.deleteEx(true);
|
||||
}
|
||||
|
||||
partition.deleteEx(true);
|
||||
table.getTablePartitions(true, trxName);
|
||||
addPartitionAndMigrateData(table, trxName, processInfo);
|
||||
|
||||
updateStmt = new StringBuilder("DROP TABLE ")
|
||||
.append(exchangeTableName);
|
||||
no = DB.executeUpdateEx(updateStmt.toString(), trxName);
|
||||
if (processInfo != null)
|
||||
processInfo.addLog(0, null, null, no + " " + updateStmt.toString());
|
||||
} else {
|
||||
throw new AdempiereException(Msg.getMsg(Env.getCtx(), "CantDetachReattachDefaultPartition"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.sql.SQLException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.adempiere.exceptions.AdempiereException;
|
||||
|
@ -44,6 +45,7 @@ import org.compiere.util.DB;
|
|||
import org.compiere.util.DisplayType;
|
||||
import org.compiere.util.Env;
|
||||
import org.compiere.util.Msg;
|
||||
import org.compiere.util.Trx;
|
||||
import org.compiere.util.Util;
|
||||
|
||||
public class TablePartitionService implements ITablePartitionService {
|
||||
|
@ -76,7 +78,7 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
*/
|
||||
private boolean renameOriginalTable(MTable table, String trxName, ProcessInfo processInfo) {
|
||||
StringBuilder sql = new StringBuilder();
|
||||
sql.append("ALTER TABLE " + table.getTableName() + " RENAME TO " + getDefaultPartitionName(table));
|
||||
sql.append("ALTER TABLE ").append(table.getTableName()).append(" RENAME TO ").append(getDefaultPartitionName(table));
|
||||
int no = DB.executeUpdateEx(sql.toString(), trxName);
|
||||
if (processInfo != null)
|
||||
processInfo.addLog(0, null, null, no + " " + sql.toString());
|
||||
|
@ -123,8 +125,8 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
if (constraint_definition.startsWith("PRIMARY KEY ") || constraint_definition.startsWith("UNIQUE "))
|
||||
{
|
||||
StringBuilder alterStmt = new StringBuilder();
|
||||
alterStmt.append("ALTER TABLE " + getDefaultPartitionName(table) + " ");
|
||||
alterStmt.append("DROP CONSTRAINT " + constraint_name + " CASCADE");
|
||||
alterStmt.append("ALTER TABLE ").append(getDefaultPartitionName(table)).append(" ");
|
||||
alterStmt.append("DROP CONSTRAINT ").append(constraint_name).append(" CASCADE");
|
||||
int no = DB.executeUpdateEx(alterStmt.toString(), trxName);
|
||||
if (pi != null)
|
||||
pi.addLog(0, null, null, no + " " + alterStmt.toString());
|
||||
|
@ -141,15 +143,15 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
}
|
||||
|
||||
alterStmt = new StringBuilder();
|
||||
alterStmt.append("ALTER TABLE " + table.getTableName() + " ");
|
||||
alterStmt.append("ADD CONSTRAINT " + constraint_name + " ");
|
||||
alterStmt.append("ALTER TABLE ").append(table.getTableName()).append(" ");
|
||||
alterStmt.append("ADD CONSTRAINT ").append(constraint_name).append(" ");
|
||||
alterStmt.append(constraint_definition.substring(0, constraint_definition.length()-1));
|
||||
for (int x = 0; x < lowerCasePartitionKeyColumnNames.size(); x++)
|
||||
alterStmt.append(", " + lowerCasePartitionKeyColumnNames.get(x));
|
||||
alterStmt.append(", ").append(lowerCasePartitionKeyColumnNames.get(x));
|
||||
alterStmt.append(")");
|
||||
no = DB.executeUpdateEx(alterStmt.toString(), trxName);
|
||||
if (pi != null)
|
||||
pi.addLog(0, null, null, no + " " + alterStmt.toString());
|
||||
pi.addLog(0, null, null, no + " " + alterStmt.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -173,8 +175,8 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
constraint_definition = constraint_definition.replace(getDefaultPartitionName(table).toLowerCase(), table.getTableName().toLowerCase());
|
||||
}
|
||||
StringBuilder alterStmt = new StringBuilder();
|
||||
alterStmt.append("ALTER TABLE " + table.getTableName() + " ");
|
||||
alterStmt.append("ADD CONSTRAINT " + constraint_name + " ");
|
||||
alterStmt.append("ALTER TABLE ").append(table.getTableName()).append(" ");
|
||||
alterStmt.append("ADD CONSTRAINT ").append(constraint_name).append(" ");
|
||||
alterStmt.append(constraint_definition);
|
||||
int no = DB.executeUpdateEx(alterStmt.toString(), trxName);
|
||||
if (pi != null)
|
||||
|
@ -189,6 +191,108 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-create indexes from the renamed table
|
||||
* @param table
|
||||
* @param trxName
|
||||
* @param pi
|
||||
* @return true if success
|
||||
*/
|
||||
private boolean migrateDBIndexes(MTable table, String trxName, ProcessInfo pi) {
|
||||
String indexs =
|
||||
"""
|
||||
select indexname
|
||||
from pg_indexes
|
||||
where schemaname='adempiere'
|
||||
and tablename=?;
|
||||
""";
|
||||
|
||||
String sql =
|
||||
"""
|
||||
select a.attname, i.indisunique
|
||||
from pg_index i
|
||||
join pg_attribute a on (a.attrelid=i.indexrelid)
|
||||
where i.indrelid::regclass = ?::regclass
|
||||
and i.indexrelid::regclass = ?::regclass
|
||||
order by a.attnum;
|
||||
""";
|
||||
|
||||
Map<String, List<String>> indexMap = new HashMap<String, List<String>>();
|
||||
Map<String, List<String>> uniqueMap = new HashMap<String, List<String>>();
|
||||
try (PreparedStatement stmt = DB.prepareStatement(indexs, trxName)) {
|
||||
stmt.setString(1, getDefaultPartitionName(table).toLowerCase());
|
||||
ResultSet rs = stmt.executeQuery();
|
||||
while(rs.next()) {
|
||||
String indexName = rs.getString(1);
|
||||
boolean unique = false;
|
||||
List<String> columns = new ArrayList<String>();
|
||||
try(PreparedStatement stmt1 = DB.prepareStatement(sql, trxName)) {
|
||||
stmt1.setString(1, getDefaultPartitionName(table).toLowerCase());
|
||||
stmt1.setString(2, indexName);
|
||||
ResultSet rs1 = stmt1.executeQuery();
|
||||
while(rs1.next()) {
|
||||
String columnName = rs1.getString(1);
|
||||
unique = rs1.getBoolean(2);
|
||||
columns.add(columnName.toLowerCase());
|
||||
}
|
||||
}
|
||||
if (unique)
|
||||
uniqueMap.put(indexName, columns);
|
||||
else
|
||||
indexMap.put(indexName, columns);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new DBException(e);
|
||||
}
|
||||
|
||||
List<String> partitionKeyColumnNames = table.getPartitionKeyColumnNames();
|
||||
for(String indexName : uniqueMap.keySet()) {
|
||||
String consql = "select conindid::regclass from pg_constraint where conrelid = ?::regclass and conindid = ?::regclass";
|
||||
String conindid = DB.getSQLValueString(trxName, consql, table.getTableName().toLowerCase(), indexName.toLowerCase());
|
||||
if (conindid != null && conindid.equalsIgnoreCase(indexName))
|
||||
continue;
|
||||
|
||||
//unique index must include partition key column
|
||||
List<String> columns = uniqueMap.get(indexName);
|
||||
for(String partitionKey : partitionKeyColumnNames) {
|
||||
if (!columns.contains(partitionKey.toLowerCase()))
|
||||
columns.add(partitionKey.toLowerCase());
|
||||
}
|
||||
StringBuilder alter = new StringBuilder("DROP INDEX ").append(indexName);
|
||||
DB.executeUpdateEx(alter.toString(), trxName);
|
||||
alter = new StringBuilder("CREATE UNIQUE INDEX ")
|
||||
.append(indexName)
|
||||
.append(" ")
|
||||
.append("ON ")
|
||||
.append(table.getTableName())
|
||||
.append("(")
|
||||
.append(String.join(",", columns))
|
||||
.append(")");
|
||||
DB.executeUpdateEx(alter.toString(), trxName);
|
||||
}
|
||||
|
||||
for(String indexName : indexMap.keySet()) {
|
||||
String consql = "select conindid::regclass from pg_constraint where conrelid = ?::regclass and conindid = ?::regclass";
|
||||
String conindid = DB.getSQLValueString(trxName, consql, table.getTableName().toLowerCase(), indexName.toLowerCase());
|
||||
if (conindid != null && conindid.equalsIgnoreCase(indexName))
|
||||
continue;
|
||||
|
||||
List<String> columns = indexMap.get(indexName);
|
||||
StringBuilder alter = new StringBuilder("DROP INDEX ").append(indexName);
|
||||
DB.executeUpdateEx(alter.toString(), trxName);
|
||||
alter = new StringBuilder("CREATE INDEX ")
|
||||
.append(indexName)
|
||||
.append(" ")
|
||||
.append("ON ")
|
||||
.append(table.getTableName())
|
||||
.append("(")
|
||||
.append(String.join(",", columns))
|
||||
.append(")");
|
||||
DB.executeUpdateEx(alter.toString(), trxName);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach renamed original table as default partition
|
||||
* @param table
|
||||
|
@ -211,8 +315,8 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
return true;
|
||||
|
||||
StringBuilder alterStmt = new StringBuilder();
|
||||
alterStmt.append("ALTER TABLE " + table.getTableName() + " ");
|
||||
alterStmt.append("ATTACH PARTITION " + getDefaultPartitionName(table) + " DEFAULT");
|
||||
alterStmt.append("ALTER TABLE ").append(table.getTableName()).append(" ");
|
||||
alterStmt.append("ATTACH PARTITION ").append(getDefaultPartitionName(table)).append(" DEFAULT");
|
||||
int no = DB.executeUpdateEx(alterStmt.toString(), trxName);
|
||||
if (pi != null)
|
||||
pi.addLog(0, null, null, no + " " + alterStmt.toString());
|
||||
|
@ -255,24 +359,24 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
if (createStmt == null)
|
||||
{
|
||||
createStmt = new StringBuilder();
|
||||
createStmt.append("CREATE TABLE " + table_schema + "." + table.getTableName() + " (");
|
||||
createStmt.append("CREATE TABLE ").append(table_schema).append(".").append(table.getTableName()).append(" (");
|
||||
}
|
||||
else
|
||||
{
|
||||
createStmt.append(", ");
|
||||
}
|
||||
|
||||
createStmt.append(column_name + " " + data_type);
|
||||
createStmt.append(column_name).append(" ").append(data_type);
|
||||
if (data_type.equals("numeric") && numeric_precision > 0)
|
||||
createStmt.append("(" + numeric_precision + "," + numeric_scale + ")");
|
||||
createStmt.append("(").append(numeric_precision).append(",").append(numeric_scale).append(")");
|
||||
else if (data_type.startsWith("character") && character_maximum_length > 0)
|
||||
createStmt.append("(" + character_maximum_length + ")");
|
||||
createStmt.append("(").append(character_maximum_length).append(")");
|
||||
|
||||
if ("NO".equals(is_nullable))
|
||||
createStmt.append(" NOT NULL");
|
||||
|
||||
if (!Util.isEmpty(column_default))
|
||||
createStmt.append(" DEFAULT " + column_default);
|
||||
createStmt.append(" DEFAULT ").append(column_default);
|
||||
}
|
||||
|
||||
if (createStmt != null)
|
||||
|
@ -288,7 +392,7 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
else
|
||||
throw new IllegalArgumentException(Msg.getMsg(Env.getCtx(), "PartitioningMethodNotSupported", new Object[]{partitioningMethod}));
|
||||
|
||||
createStmt.append(" (" + partitionKeyColumn.getColumnName() + ")");
|
||||
createStmt.append(" (").append(partitionKeyColumn.getColumnName()).append(")");
|
||||
|
||||
int no = DB.executeUpdateEx(createStmt.toString(), trxName);
|
||||
if (processInfo != null)
|
||||
|
@ -297,6 +401,9 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
if (!migrateDBContrainsts(table, trxName, processInfo))
|
||||
throw new AdempiereException(Msg.getMsg(Env.getCtx(), "FailedMigrateDatabaseConstraints"));
|
||||
|
||||
if (!migrateDBIndexes(table, trxName, processInfo))
|
||||
throw new AdempiereException(Msg.getMsg(Env.getCtx(), "FailedMigrateDatabaseConstraints"));
|
||||
|
||||
if (!attachDefaultPartition(table, trxName, processInfo))
|
||||
throw new AdempiereException(Msg.getMsg(Env.getCtx(), "FailedAttachDefaultPartition"));
|
||||
|
||||
|
@ -363,14 +470,17 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
|
||||
List<MColumn> partitionKeyColumns = table.getPartitionKeyColumns(false);
|
||||
MColumn partitionKeyColumn = partitionKeyColumns.get(0);
|
||||
MColumn subPartitionColumn = null;
|
||||
if (partitionKeyColumns.size() > 1)
|
||||
subPartitionColumn = partitionKeyColumns.get(1);
|
||||
String partitioningMethod = partitionKeyColumn.getPartitioningMethod();
|
||||
if (partitioningMethod.equals(MColumn.PARTITIONINGMETHOD_List))
|
||||
{
|
||||
isUpdated = addListPartition(table, partitionKeyColumn, trxName, pi);
|
||||
isUpdated = addListPartition(table, partitionKeyColumn, trxName, pi, subPartitionColumn);
|
||||
}
|
||||
else if (partitioningMethod.equals(MColumn.PARTITIONINGMETHOD_Range))
|
||||
{
|
||||
isUpdated = addRangePartition(table, partitionKeyColumn, trxName, pi);
|
||||
isUpdated = addRangePartition(table, partitionKeyColumn, trxName, pi, subPartitionColumn);
|
||||
}
|
||||
else
|
||||
throw new IllegalArgumentException(Msg.getMsg(Env.getCtx(), "PartitioningMethodNotSupported", new Object[]{partitioningMethod}));
|
||||
|
@ -379,34 +489,144 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
}
|
||||
|
||||
/**
|
||||
* Add new range partition
|
||||
* @param table
|
||||
* @param partitionKeyColumn
|
||||
* Create new {@link RangePartitionColumn} instance
|
||||
* @param fromTableName table name for FROM clause
|
||||
* @param partitionKeyColumn
|
||||
* @param trxName
|
||||
* @param pi
|
||||
* @return true if new range partition added
|
||||
* @return new RangePartitionColumn instance
|
||||
*/
|
||||
private boolean addRangePartition(MTable table, MColumn partitionKeyColumn, String trxName, ProcessInfo pi) {
|
||||
boolean isUpdated = false;
|
||||
X_AD_TablePartition partition = null;
|
||||
RangePartitionColumn rangePartitionColumn = null;
|
||||
|
||||
private RangePartitionColumn buildRangePartitionColumn(String fromTableName, MColumn partitionKeyColumn, String trxName) {
|
||||
String partitionKeyColumnName = partitionKeyColumn.getColumnName();
|
||||
String partitionKeyColumnRangeIntervalPattern = partitionKeyColumn.getRangePartitionInterval();
|
||||
|
||||
StringBuilder sql = new StringBuilder();
|
||||
sql.append("SELECT MIN(").append(partitionKeyColumnName).append(") AS min_value, ");
|
||||
sql.append("MAX(").append(partitionKeyColumnName).append(") AS max_value ");
|
||||
sql.append("FROM ").append(getDefaultPartitionName(table));
|
||||
sql.append("FROM ").append(fromTableName);
|
||||
|
||||
List<Object> values = DB.getSQLValueObjectsEx(trxName, sql.toString());
|
||||
if (values.get(0) != null && values.get(1) != null)
|
||||
{
|
||||
rangePartitionColumn = new RangePartitionColumn(
|
||||
return new RangePartitionColumn(
|
||||
partitionKeyColumnName, partitionKeyColumnRangeIntervalPattern,
|
||||
values.get(0), values.get(1));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new X_AD_TablePartition record for a range partition interval
|
||||
* @param rangePartitionInterval
|
||||
* @param tablePartitionNames existing partition names
|
||||
* @param table
|
||||
* @param partitionKeyColumn
|
||||
* @param partitionNamePrefix Prefix for the new range partition name
|
||||
* @param defaultPartitionName default partition name to select from
|
||||
* @param parentPartition
|
||||
* @param trxName
|
||||
* @return new X_AD_TablePartition record or null (if 0 record in defaultPartitionName for rangePartitionInterval)
|
||||
*/
|
||||
private X_AD_TablePartition createNewRangePartition(RangePartitionInterval rangePartitionInterval, List<String> tablePartitionNames, MTable table, MColumn partitionKeyColumn,
|
||||
String partitionNamePrefix, String defaultPartitionName, X_AD_TablePartition parentPartition, String trxName) {
|
||||
X_AD_TablePartition partition = null;
|
||||
StringBuilder name = new StringBuilder();
|
||||
name.append(partitionNamePrefix);
|
||||
name.append("_");
|
||||
name.append(rangePartitionInterval.getName());
|
||||
|
||||
StringBuilder expression = new StringBuilder();
|
||||
expression.append("FOR VALUES FROM (");
|
||||
expression.append(rangePartitionInterval.getFrom());
|
||||
expression.append(") TO (");
|
||||
expression.append(rangePartitionInterval.getTo());
|
||||
expression.append(")");
|
||||
|
||||
StringBuilder countStmt = new StringBuilder("SELECT Count(*) FROM ")
|
||||
.append(defaultPartitionName).append(" ")
|
||||
.append("WHERE ").append(" ")
|
||||
.append(partitionKeyColumn.getColumnName()).append(" >= ");
|
||||
if (DisplayType.isDate(partitionKeyColumn.getAD_Reference_ID()) || DisplayType.isTimestampWithTimeZone(partitionKeyColumn.getAD_Reference_ID()))
|
||||
countStmt.append("TO_DATE(").append(rangePartitionInterval.getFrom()).append(",'yyyy-MM-dd') ");
|
||||
else
|
||||
countStmt.append(rangePartitionInterval.getFrom()).append(" ");
|
||||
countStmt.append("AND ").append(partitionKeyColumn.getColumnName()).append(" < ");
|
||||
if (DisplayType.isDate(partitionKeyColumn.getAD_Reference_ID()) || DisplayType.isTimestampWithTimeZone(partitionKeyColumn.getAD_Reference_ID()))
|
||||
countStmt.append("TO_DATE(").append(rangePartitionInterval.getTo()).append(",'yyyy-MM-dd') ");
|
||||
else
|
||||
countStmt.append(rangePartitionInterval.getTo()).append(" ");
|
||||
int recordCount = DB.getSQLValueEx(trxName, countStmt.toString());
|
||||
|
||||
if (recordCount == 0) {
|
||||
if (tablePartitionNames.contains(name.toString())) {
|
||||
Query query = new Query(Env.getCtx(), X_AD_TablePartition.Table_Name, "AD_Table_ID=? AND Name=?", trxName);
|
||||
X_AD_TablePartition toDelete = query.setParameters(table.getAD_Table_ID(), name.toString()).first();
|
||||
if (toDelete != null)
|
||||
toDelete.deleteEx(true);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!tablePartitionNames.contains(name.toString())) {
|
||||
partition = table.createTablePartition(name.toString(), expression.toString(), trxName, partitionKeyColumn, parentPartition);
|
||||
tablePartitionNames.add(name.toString());
|
||||
}
|
||||
return partition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move data from default partition to a range partition
|
||||
* @param partition range partition
|
||||
* @param partitionKeyColumn
|
||||
* @param tableName table name to attached partition
|
||||
* @param defaultPartitionName name of default partition
|
||||
* @param rangePartitionInterval
|
||||
* @param pi
|
||||
* @param trxName
|
||||
*/
|
||||
private void moveDefaultPartitionDataForRange(X_AD_TablePartition partition, MColumn partitionKeyColumn, String tableName,
|
||||
String defaultPartitionName, RangePartitionInterval rangePartitionInterval, ProcessInfo pi, String trxName) {
|
||||
StringBuilder updateStmt = new StringBuilder();
|
||||
updateStmt.append("WITH x AS ( ");
|
||||
updateStmt.append("DELETE FROM ").append(defaultPartitionName).append(" ");
|
||||
updateStmt.append("WHERE ").append(" ");
|
||||
updateStmt.append(partitionKeyColumn.getColumnName()).append(" >= ");
|
||||
if (DisplayType.isDate(partitionKeyColumn.getAD_Reference_ID()) || DisplayType.isTimestampWithTimeZone(partitionKeyColumn.getAD_Reference_ID()))
|
||||
updateStmt.append("TO_DATE(").append(rangePartitionInterval.getFrom()).append(",'yyyy-MM-dd') ");
|
||||
else
|
||||
updateStmt.append(rangePartitionInterval.getFrom()).append(" ");
|
||||
updateStmt.append("AND ").append(partitionKeyColumn.getColumnName()).append(" < ");
|
||||
if (DisplayType.isDate(partitionKeyColumn.getAD_Reference_ID()) || DisplayType.isTimestampWithTimeZone(partitionKeyColumn.getAD_Reference_ID()))
|
||||
updateStmt.append("TO_DATE(").append(rangePartitionInterval.getTo()).append(",'yyyy-MM-dd') ");
|
||||
else
|
||||
updateStmt.append(rangePartitionInterval.getTo()).append(" ");
|
||||
|
||||
updateStmt.append("RETURNING *) ");
|
||||
updateStmt.append("INSERT INTO ").append(partition.getName()).append(" ");
|
||||
updateStmt.append("SELECT * FROM x");
|
||||
int no = DB.executeUpdateEx(updateStmt.toString(), trxName);
|
||||
if (pi != null)
|
||||
pi.addLog(0, null, null, no + " " + updateStmt.toString());
|
||||
|
||||
StringBuilder alterStmt = new StringBuilder();
|
||||
alterStmt.append("ALTER TABLE ").append(tableName).append(" ");
|
||||
alterStmt.append("ATTACH PARTITION ").append(partition.getName()).append(" ").append(partition.getExpressionPartition());
|
||||
no = DB.executeUpdateEx(alterStmt.toString(), trxName);
|
||||
if (pi != null)
|
||||
pi.addLog(0, null, null, no + " " + alterStmt.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new range partition
|
||||
* @param table
|
||||
* @param partitionKeyColumn
|
||||
* @param trxName
|
||||
* @param pi
|
||||
* @param subPartitionColumn
|
||||
* @return true if new range partition added
|
||||
*/
|
||||
private boolean addRangePartition(MTable table, MColumn partitionKeyColumn, String trxName, ProcessInfo pi, MColumn subPartitionColumn) {
|
||||
boolean isUpdated = false;
|
||||
RangePartitionColumn rangePartitionColumn = buildRangePartitionColumn(getDefaultPartitionName(table), partitionKeyColumn, trxName);
|
||||
if (rangePartitionColumn == null)
|
||||
return false;
|
||||
|
||||
|
@ -415,111 +635,128 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
|
||||
for (RangePartitionInterval rangePartitionInterval : rangePartitionIntervals)
|
||||
{
|
||||
StringBuilder name = new StringBuilder();
|
||||
name.append(table.getTableName().toLowerCase());
|
||||
name.append("_");
|
||||
name.append(rangePartitionInterval.getName());
|
||||
|
||||
StringBuilder expression = new StringBuilder();
|
||||
expression.append("FOR VALUES FROM (");
|
||||
expression.append(rangePartitionInterval.getFrom());
|
||||
expression.append(") TO (");
|
||||
expression.append(rangePartitionInterval.getTo());
|
||||
expression.append(")");
|
||||
|
||||
StringBuilder countStmt = new StringBuilder("SELECT Count(*) FROM ")
|
||||
.append(getDefaultPartitionName(table)).append(" ")
|
||||
.append("WHERE ").append(" ")
|
||||
.append(partitionKeyColumn.getColumnName()).append(" >= ");
|
||||
if (DisplayType.isDate(partitionKeyColumn.getAD_Reference_ID()) || DisplayType.isTimestampWithTimeZone(partitionKeyColumn.getAD_Reference_ID()))
|
||||
countStmt.append("TO_DATE(").append(rangePartitionInterval.getFrom()).append(",'yyyy-MM-dd') ");
|
||||
else
|
||||
countStmt.append(rangePartitionInterval.getFrom()).append(" ");
|
||||
countStmt.append("AND " + partitionKeyColumn.getColumnName()).append(" < ");
|
||||
if (DisplayType.isDate(partitionKeyColumn.getAD_Reference_ID()) || DisplayType.isTimestampWithTimeZone(partitionKeyColumn.getAD_Reference_ID()))
|
||||
countStmt.append("TO_DATE(").append(rangePartitionInterval.getTo()).append(",'yyyy-MM-dd') ");
|
||||
else
|
||||
countStmt.append(rangePartitionInterval.getTo()).append(" ");
|
||||
int recordCount = DB.getSQLValueEx(trxName, countStmt.toString());
|
||||
|
||||
if (recordCount == 0) {
|
||||
if (tablePartitionNames.contains(name.toString())) {
|
||||
Query query = new Query(Env.getCtx(), X_AD_TablePartition.Table_Name, "AD_Table_ID=? AND Name=?", trxName);
|
||||
X_AD_TablePartition toDelete = query.setParameters(table.getAD_Table_ID(), name.toString()).first();
|
||||
if (toDelete != null)
|
||||
toDelete.deleteEx(true);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!tablePartitionNames.contains(name.toString()))
|
||||
partition = table.createTablePartition(name.toString(), expression.toString(), trxName, partitionKeyColumn);
|
||||
|
||||
X_AD_TablePartition partition = createNewRangePartition(rangePartitionInterval, tablePartitionNames, table, partitionKeyColumn, table.getTableName().toLowerCase(),
|
||||
getDefaultPartitionName(table), null, trxName);
|
||||
if (partition != null)
|
||||
{
|
||||
StringBuilder createStmt = new StringBuilder();
|
||||
createStmt.append("CREATE TABLE ").append(partition.getName()).append(" (").append(DB_PostgreSQL.NATIVE_MARKER).append("LIKE ");
|
||||
createStmt.append(getDefaultPartitionName(table)).append(" INCLUDING ALL)");
|
||||
if (subPartitionColumn != null) {
|
||||
createStmt.append(" PARTITION BY ");
|
||||
if (MColumn.PARTITIONINGMETHOD_List.equals(subPartitionColumn.getPartitioningMethod()))
|
||||
createStmt.append(" LIST(");
|
||||
else if (MColumn.PARTITIONINGMETHOD_Range.equals(subPartitionColumn.getPartitioningMethod()))
|
||||
createStmt.append(" RANGE(");
|
||||
else
|
||||
throw new IllegalArgumentException(Msg.getMsg(Env.getCtx(), "PartitioningMethodNotSupported", new Object[]{subPartitionColumn.getPartitioningMethod()}));
|
||||
createStmt.append(subPartitionColumn.getColumnName());
|
||||
createStmt.append(")");
|
||||
}
|
||||
int no = DB.executeUpdateEx(createStmt.toString(), trxName);
|
||||
if (pi != null)
|
||||
pi.addLog(0, null, null, no + " " + createStmt.toString());
|
||||
|
||||
StringBuilder updateStmt = new StringBuilder();
|
||||
updateStmt.append("WITH x AS ( ");
|
||||
updateStmt.append("DELETE FROM ").append(getDefaultPartitionName(table)).append(" ");
|
||||
updateStmt.append("WHERE ").append(" ");
|
||||
updateStmt.append(partitionKeyColumn.getColumnName()).append(" >= ");
|
||||
if (DisplayType.isDate(partitionKeyColumn.getAD_Reference_ID()) || DisplayType.isTimestampWithTimeZone(partitionKeyColumn.getAD_Reference_ID()))
|
||||
updateStmt.append("TO_DATE(").append(rangePartitionInterval.getFrom()).append(",'yyyy-MM-dd') ");
|
||||
else
|
||||
updateStmt.append(rangePartitionInterval.getFrom()).append(" ");
|
||||
updateStmt.append("AND ").append(partitionKeyColumn.getColumnName()).append(" < ");
|
||||
if (DisplayType.isDate(partitionKeyColumn.getAD_Reference_ID()) || DisplayType.isTimestampWithTimeZone(partitionKeyColumn.getAD_Reference_ID()))
|
||||
updateStmt.append("TO_DATE(").append(rangePartitionInterval.getTo()).append(",'yyyy-MM-dd') ");
|
||||
else
|
||||
updateStmt.append(rangePartitionInterval.getTo()).append(" ");
|
||||
|
||||
updateStmt.append("RETURNING *) ");
|
||||
updateStmt.append("INSERT INTO ").append(partition.getName()).append(" ");
|
||||
updateStmt.append("SELECT * FROM x");
|
||||
no = DB.executeUpdateEx(updateStmt.toString(), trxName);
|
||||
if (pi != null)
|
||||
pi.addLog(0, null, null, no + " " + updateStmt.toString());
|
||||
|
||||
StringBuilder alterStmt = new StringBuilder();
|
||||
alterStmt.append("ALTER TABLE ").append(table.getTableName()).append(" ");
|
||||
alterStmt.append("ATTACH PARTITION ").append(partition.getName()).append(" ").append(partition.getExpressionPartition());
|
||||
no = DB.executeUpdateEx(alterStmt.toString(), trxName);
|
||||
if (pi != null)
|
||||
pi.addLog(0, null, null, no + " " + alterStmt.toString());
|
||||
pi.addLog(0, null, null, no + " " + createStmt.toString().replace(DB_PostgreSQL.NATIVE_MARKER, ""));
|
||||
if (subPartitionColumn != null) {
|
||||
createSubDefaultPartition(table, subPartitionColumn, partition, pi, trxName);
|
||||
}
|
||||
|
||||
moveDefaultPartitionDataForRange(partition, partitionKeyColumn, table.getTableName(), getDefaultPartitionName(table), rangePartitionInterval, pi, trxName);
|
||||
isUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (subPartitionColumn != null) {
|
||||
List<X_AD_TablePartition> partitions = new ArrayList<>();
|
||||
tablePartitionNames = new ArrayList<>();
|
||||
try (PreparedStatement stmt = DB.prepareStatement("SELECT * FROM AD_TablePartition WHERE IsActive='Y' AND AD_Table_ID=? AND AD_Column_ID=? AND IsPartitionAttached='Y'", trxName)) {
|
||||
stmt.setInt(1, table.getAD_Table_ID());
|
||||
stmt.setInt(2, partitionKeyColumn.getAD_Column_ID());
|
||||
ResultSet rs = stmt.executeQuery();
|
||||
while(rs.next()) {
|
||||
X_AD_TablePartition partition = new X_AD_TablePartition(Env.getCtx(), rs, trxName);
|
||||
if (partition.getName().toLowerCase().endsWith("_default_partition"))
|
||||
continue;
|
||||
partitions.add(partition);
|
||||
tablePartitionNames.add(partition.getName());
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new DBException(e);
|
||||
}
|
||||
for(X_AD_TablePartition partition : partitions) {
|
||||
String subDefaultPartition = partition.getName() + "_default_partition";
|
||||
String sql =
|
||||
"""
|
||||
SELECT COUNT(*)
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = LOWER(?)
|
||||
""";
|
||||
int count = DB.getSQLValueEx(trxName, sql, subDefaultPartition);
|
||||
if (count <= 0)
|
||||
continue;
|
||||
if (MColumn.PARTITIONINGMETHOD_List.equals(subPartitionColumn.getPartitioningMethod())) {
|
||||
HashMap<String, Object> subValues = new HashMap<>();
|
||||
List<X_AD_TablePartition> subPartitions = generateListPartition(table, partition.getName(), subDefaultPartition, subPartitionColumn, subValues, partition, trxName);
|
||||
for(X_AD_TablePartition subPartition : subPartitions) {
|
||||
StringBuilder createStmt = new StringBuilder();
|
||||
createStmt.append("CREATE TABLE ").append(subPartition.getName()).append(" (").append(DB_PostgreSQL.NATIVE_MARKER).append("LIKE ");
|
||||
createStmt.append(subDefaultPartition).append(" INCLUDING ALL)");
|
||||
int no = DB.executeUpdateEx(createStmt.toString(), trxName);
|
||||
if (pi != null)
|
||||
pi.addLog(0, null, null, no + " " + createStmt.toString().replace(DB_PostgreSQL.NATIVE_MARKER, ""));
|
||||
Object subValue = subValues.get(subPartition.getName());
|
||||
moveDefaultPartitionDataForList(subPartition, subPartitionColumn, partition.getName(), subDefaultPartition, subValue, pi, trxName);
|
||||
}
|
||||
} else if (MColumn.PARTITIONINGMETHOD_Range.equals(subPartitionColumn.getPartitioningMethod())) {
|
||||
rangePartitionColumn = buildRangePartitionColumn(partition.getName(), subPartitionColumn, trxName);
|
||||
if (rangePartitionColumn != null)
|
||||
{
|
||||
rangePartitionIntervals = RangePartitionInterval.createInterval(table, rangePartitionColumn, trxName);
|
||||
for (RangePartitionInterval rangePartitionInterval : rangePartitionIntervals)
|
||||
{
|
||||
X_AD_TablePartition subPartition = createNewRangePartition(rangePartitionInterval, tablePartitionNames, table, subPartitionColumn, partition.getName(),
|
||||
subDefaultPartition, partition, trxName);
|
||||
if (subPartition != null)
|
||||
{
|
||||
StringBuilder createStmt = new StringBuilder();
|
||||
createStmt.append("CREATE TABLE ").append(subPartition.getName()).append(" (").append(DB_PostgreSQL.NATIVE_MARKER).append("LIKE ");
|
||||
createStmt.append(subDefaultPartition).append(" INCLUDING ALL)");
|
||||
int no = DB.executeUpdateEx(createStmt.toString(), trxName);
|
||||
if (pi != null)
|
||||
pi.addLog(0, null, null, no + " " + createStmt.toString().replace(DB_PostgreSQL.NATIVE_MARKER, ""));
|
||||
moveDefaultPartitionDataForRange(subPartition, subPartitionColumn, partition.getName(), subDefaultPartition, rangePartitionInterval, pi, trxName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isUpdated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new list partition
|
||||
* Generate new X_AD_TablePartition records
|
||||
* @param table
|
||||
* @param partitionKeyColumn
|
||||
* @param partitionNamePrefix name prefix for new list partition
|
||||
* @param fromPartitionTable table name for FROM clause
|
||||
* @param partitionKeyColumn
|
||||
* @param columnValues List Partition Name:List Value map
|
||||
* @param parentPartition
|
||||
* @param trxName
|
||||
* @param pi
|
||||
* @return true if new list partition added
|
||||
* @return list of generated X_AD_TablePartition records
|
||||
*/
|
||||
private boolean addListPartition(MTable table, MColumn partitionKeyColumn, String trxName, ProcessInfo pi) {
|
||||
boolean isUpdated = false;
|
||||
private List<X_AD_TablePartition> generateListPartition(MTable table, String partitionNamePrefix, String fromPartitionTable, MColumn partitionKeyColumn, HashMap<String, Object> columnValues,
|
||||
X_AD_TablePartition parentPartition, String trxName) {
|
||||
List<X_AD_TablePartition> partitions = new ArrayList<X_AD_TablePartition>();
|
||||
String nameColumn = "'" + table.getTableName().toLowerCase() + "_' || " + partitionKeyColumn.getColumnName();
|
||||
String nameColumn = "'" + partitionNamePrefix + "_' || " + partitionKeyColumn.getColumnName();
|
||||
String expressionColumn = "'FOR VALUES IN (''' || " + partitionKeyColumn.getColumnName() + " || ''')'";
|
||||
|
||||
StringBuilder sql = new StringBuilder();
|
||||
sql.append("SELECT DISTINCT ").append(nameColumn).append(" AS name, ");
|
||||
sql.append(expressionColumn).append(" AS expression, ");
|
||||
sql.append(partitionKeyColumn.getColumnName()).append(" ");
|
||||
sql.append("FROM ").append(getDefaultPartitionName(table)).append(" ");
|
||||
sql.append("FROM ").append(fromPartitionTable).append(" ");
|
||||
|
||||
HashMap<String, Object> columnValues = new HashMap<>();
|
||||
try (PreparedStatement pstmt = DB.prepareStatement(sql.toString(), trxName))
|
||||
{
|
||||
ResultSet rs = pstmt.executeQuery();
|
||||
|
@ -532,7 +769,7 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
value = rs.getObject(partitionKeyColumn.getColumnName());
|
||||
columnValues.put(name, value);
|
||||
|
||||
X_AD_TablePartition partition = table.createTablePartition(name, expression, trxName, partitionKeyColumn);
|
||||
X_AD_TablePartition partition = table.createTablePartition(name, expression, trxName, partitionKeyColumn, parentPartition);
|
||||
partitions.add(partition);
|
||||
}
|
||||
}
|
||||
|
@ -540,7 +777,61 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
{
|
||||
throw new DBException(e);
|
||||
}
|
||||
return partitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move records from default partition to a list partition
|
||||
* @param partition list partition
|
||||
* @param partitionKeyColumn
|
||||
* @param tableName table name to attached list partition
|
||||
* @param defaultPartitionName name of default partition
|
||||
* @param listValue key value of list partition
|
||||
* @param pi
|
||||
* @param trxName
|
||||
*/
|
||||
private void moveDefaultPartitionDataForList(X_AD_TablePartition partition, MColumn partitionKeyColumn, String tableName,
|
||||
String defaultPartitionName, Object listValue, ProcessInfo pi, String trxName) {
|
||||
StringBuilder updateStmt = new StringBuilder();
|
||||
updateStmt.append("WITH x AS ( ");
|
||||
updateStmt.append("DELETE FROM ").append(defaultPartitionName).append(" ");
|
||||
updateStmt.append("WHERE ").append(" ");
|
||||
|
||||
updateStmt.append(partitionKeyColumn.getColumnName()).append("=");
|
||||
|
||||
if (DisplayType.isText(partitionKeyColumn.getAD_Reference_ID()))
|
||||
updateStmt.append("'").append(listValue).append("' ");
|
||||
else
|
||||
updateStmt.append(listValue).append(" ");
|
||||
|
||||
updateStmt.append("RETURNING *) ");
|
||||
updateStmt.append("INSERT INTO ").append(partition.getName()).append(" ");
|
||||
updateStmt.append("SELECT * FROM x");
|
||||
int no = DB.executeUpdateEx(updateStmt.toString(), trxName);
|
||||
if (pi != null)
|
||||
pi.addLog(0, null, null, no + " " + updateStmt.toString());
|
||||
|
||||
StringBuilder alterStmt = new StringBuilder();
|
||||
alterStmt.append("ALTER TABLE ").append(tableName).append(" ");
|
||||
alterStmt.append("ATTACH PARTITION ").append(partition.getName()).append(" ").append(partition.getExpressionPartition());
|
||||
no = DB.executeUpdateEx(alterStmt.toString(), trxName);
|
||||
if (pi != null)
|
||||
pi.addLog(0, null, null, no + " " + alterStmt.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new list partition
|
||||
* @param table
|
||||
* @param partitionKeyColumn
|
||||
* @param trxName
|
||||
* @param pi
|
||||
* @param subPartitionColumn
|
||||
* @return true if new list partition added
|
||||
*/
|
||||
private boolean addListPartition(MTable table, MColumn partitionKeyColumn, String trxName, ProcessInfo pi, MColumn subPartitionColumn) {
|
||||
boolean isUpdated = false;
|
||||
HashMap<String, Object> columnValues = new HashMap<>();
|
||||
List<X_AD_TablePartition> partitions = generateListPartition(table, table.getTableName().toLowerCase(), getDefaultPartitionName(table), partitionKeyColumn, columnValues, null, trxName);
|
||||
for (X_AD_TablePartition partition : partitions)
|
||||
{
|
||||
Object value = columnValues.get(partition.getName());
|
||||
|
@ -548,41 +839,124 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
StringBuilder createStmt = new StringBuilder();
|
||||
createStmt.append("CREATE TABLE ").append(partition.getName()).append(" (").append(DB_PostgreSQL.NATIVE_MARKER).append("LIKE ");
|
||||
createStmt.append(getDefaultPartitionName(table)).append(" INCLUDING ALL)");
|
||||
if (subPartitionColumn != null) {
|
||||
createStmt.append(" PARTITION BY ");
|
||||
if (MColumn.PARTITIONINGMETHOD_List.equals(subPartitionColumn.getPartitioningMethod()))
|
||||
createStmt.append(" LIST(");
|
||||
else if (MColumn.PARTITIONINGMETHOD_Range.equals(subPartitionColumn.getPartitioningMethod()))
|
||||
createStmt.append(" RANGE(");
|
||||
else
|
||||
throw new IllegalArgumentException(Msg.getMsg(Env.getCtx(), "PartitioningMethodNotSupported", new Object[]{subPartitionColumn.getPartitioningMethod()}));
|
||||
createStmt.append(subPartitionColumn.getColumnName());
|
||||
createStmt.append(")");
|
||||
}
|
||||
int no = DB.executeUpdateEx(createStmt.toString(), trxName);
|
||||
if (pi != null)
|
||||
pi.addLog(0, null, null, no + " " + createStmt.toString());
|
||||
|
||||
StringBuilder updateStmt = new StringBuilder();
|
||||
updateStmt.append("WITH x AS ( ");
|
||||
updateStmt.append("DELETE FROM ").append(getDefaultPartitionName(table)).append(" ");
|
||||
updateStmt.append("WHERE ").append(" ");
|
||||
|
||||
updateStmt.append(partitionKeyColumn.getColumnName()).append("=");
|
||||
|
||||
if (DisplayType.isText(partitionKeyColumn.getAD_Reference_ID()))
|
||||
updateStmt.append("'").append(value).append("' ");
|
||||
else
|
||||
updateStmt.append(value).append(" ");
|
||||
pi.addLog(0, null, null, no + " " + createStmt.toString().replace(DB_PostgreSQL.NATIVE_MARKER, ""));
|
||||
|
||||
updateStmt.append("RETURNING *) ");
|
||||
updateStmt.append("INSERT INTO ").append(partition.getName()).append(" ");
|
||||
updateStmt.append("SELECT * FROM x");
|
||||
no = DB.executeUpdateEx(updateStmt.toString(), trxName);
|
||||
if (pi != null)
|
||||
pi.addLog(0, null, null, no + " " + updateStmt.toString());
|
||||
if (subPartitionColumn != null) {
|
||||
createSubDefaultPartition(table, subPartitionColumn, partition, pi, trxName);
|
||||
}
|
||||
|
||||
StringBuilder alterStmt = new StringBuilder();
|
||||
alterStmt.append("ALTER TABLE ").append(table.getTableName()).append(" ");
|
||||
alterStmt.append("ATTACH PARTITION ").append(partition.getName()).append(" ").append(partition.getExpressionPartition());
|
||||
no = DB.executeUpdateEx(alterStmt.toString(), trxName);
|
||||
if (pi != null)
|
||||
pi.addLog(0, null, null, no + " " + alterStmt.toString());
|
||||
moveDefaultPartitionDataForList(partition, partitionKeyColumn, table.getTableName(), getDefaultPartitionName(table), value, pi, trxName);
|
||||
|
||||
isUpdated = true;
|
||||
}
|
||||
|
||||
if (subPartitionColumn != null) {
|
||||
List<String> tablePartitionNames = new ArrayList<>();
|
||||
partitions = new ArrayList<>();
|
||||
try (PreparedStatement stmt = DB.prepareStatement("SELECT * FROM AD_TablePartition WHERE IsActive='Y' AND AD_Table_ID=? AND AD_Column_ID=? AND IsPartitionAttached='Y'", trxName)) {
|
||||
stmt.setInt(1, table.getAD_Table_ID());
|
||||
stmt.setInt(2, partitionKeyColumn.getAD_Column_ID());
|
||||
ResultSet rs = stmt.executeQuery();
|
||||
while(rs.next()) {
|
||||
X_AD_TablePartition partition = new X_AD_TablePartition(Env.getCtx(), rs, trxName);
|
||||
if (partition.getName().toLowerCase().endsWith("_default_partition"))
|
||||
continue;
|
||||
partitions.add(partition);
|
||||
tablePartitionNames.add(partition.getName());
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new DBException(e);
|
||||
}
|
||||
for(X_AD_TablePartition partition : partitions) {
|
||||
String subDefaultPartition = partition.getName() + "_default_partition";
|
||||
String sql =
|
||||
"""
|
||||
SELECT COUNT(*)
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = LOWER(?)
|
||||
""";
|
||||
int count = DB.getSQLValueEx(trxName, sql, subDefaultPartition);
|
||||
if (count <= 0)
|
||||
continue;
|
||||
if (MColumn.PARTITIONINGMETHOD_List.equals(subPartitionColumn.getPartitioningMethod())) {
|
||||
HashMap<String, Object> subValues = new HashMap<>();
|
||||
List<X_AD_TablePartition> subPartitions = generateListPartition(table, partition.getName(), subDefaultPartition, subPartitionColumn, subValues, partition, trxName);
|
||||
for(X_AD_TablePartition subPartition : subPartitions) {
|
||||
StringBuilder createStmt = new StringBuilder();
|
||||
createStmt.append("CREATE TABLE ").append(subPartition.getName()).append(" (").append(DB_PostgreSQL.NATIVE_MARKER).append("LIKE ");
|
||||
createStmt.append(subDefaultPartition).append(" INCLUDING ALL)");
|
||||
int no = DB.executeUpdateEx(createStmt.toString(), trxName);
|
||||
if (pi != null)
|
||||
pi.addLog(0, null, null, no + " " + createStmt.toString().replace(DB_PostgreSQL.NATIVE_MARKER, ""));
|
||||
Object subValue = subValues.get(subPartition.getName());
|
||||
moveDefaultPartitionDataForList(subPartition, subPartitionColumn, partition.getName(), subDefaultPartition, subValue, pi, trxName);
|
||||
}
|
||||
} else if (MColumn.PARTITIONINGMETHOD_Range.equals(subPartitionColumn.getPartitioningMethod())) {
|
||||
RangePartitionColumn rangePartitionColumn = buildRangePartitionColumn(partition.getName(), subPartitionColumn, trxName);
|
||||
if (rangePartitionColumn != null)
|
||||
{
|
||||
List<RangePartitionInterval> rangePartitionIntervals = RangePartitionInterval.createInterval(table, rangePartitionColumn, trxName);
|
||||
for (RangePartitionInterval rangePartitionInterval : rangePartitionIntervals)
|
||||
{
|
||||
X_AD_TablePartition subPartition = createNewRangePartition(rangePartitionInterval, tablePartitionNames, table, subPartitionColumn, partition.getName(),
|
||||
subDefaultPartition, partition, trxName);
|
||||
if (subPartition != null)
|
||||
{
|
||||
StringBuilder createStmt = new StringBuilder();
|
||||
createStmt.append("CREATE TABLE ").append(subPartition.getName()).append(" (").append(DB_PostgreSQL.NATIVE_MARKER).append("LIKE ");
|
||||
createStmt.append(subDefaultPartition).append(" INCLUDING ALL)");
|
||||
int no = DB.executeUpdateEx(createStmt.toString(), trxName);
|
||||
if (pi != null)
|
||||
pi.addLog(0, null, null, no + " " + createStmt.toString().replace(DB_PostgreSQL.NATIVE_MARKER, ""));
|
||||
moveDefaultPartitionDataForRange(subPartition, subPartitionColumn, partition.getName(), subDefaultPartition, rangePartitionInterval, pi, trxName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return isUpdated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create default partition table for sub-partition
|
||||
* @param table
|
||||
* @param subPartitionColumn sub-partition column
|
||||
* @param partition parent partition
|
||||
* @param pi
|
||||
* @param trxName
|
||||
*/
|
||||
private void createSubDefaultPartition(MTable table, MColumn subPartitionColumn, X_AD_TablePartition partition, ProcessInfo pi, String trxName) {
|
||||
StringBuilder subStmt = new StringBuilder("CREATE TABLE ")
|
||||
.append(partition.getName()).append("_default_partition (").append(DB_PostgreSQL.NATIVE_MARKER).append("LIKE ")
|
||||
.append(partition.getName())
|
||||
.append(" INCLUDING ALL)");
|
||||
int no = DB.executeUpdateEx(subStmt.toString(), trxName);
|
||||
if (pi != null)
|
||||
pi.addLog(0, null, null, no + " " + subStmt.toString());
|
||||
subStmt = new StringBuilder("ALTER TABLE ")
|
||||
.append(partition.getName())
|
||||
.append(" ATTACH PARTITION ")
|
||||
.append(partition.getName()).append("_default_partition DEFAULT ");
|
||||
no = DB.executeUpdateEx(subStmt.toString(), trxName);
|
||||
if (pi != null)
|
||||
pi.addLog(0, null, null, no + " " + subStmt.toString().replace(DB_PostgreSQL.NATIVE_MARKER, ""));
|
||||
table.createTablePartition(partition.getName()+"_default_partition", "DEFAULT", trxName, subPartitionColumn, partition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean runPostPartitionProcess(MTable table, String trxName, ProcessInfo processInfo) {
|
||||
StringBuilder stmt = new StringBuilder();
|
||||
|
@ -627,8 +1001,8 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
if (partitionKeyColumns.contains(column))
|
||||
partitionKeyColumns.remove(column);
|
||||
}
|
||||
if (partitionKeyColumns.size() > 1)
|
||||
return Msg.getMsg(Env.getCtx(), "OnlyOnePartitionKeyAllowed");
|
||||
if (partitionKeyColumns.size() > 2)
|
||||
return Msg.getMsg(Env.getCtx(), "OnlyTwoPartitionKeyAllowed");
|
||||
|
||||
if (column.isActive() && column.isPartitionKey() && column.getPartitioningMethod().equals(MColumn.PARTITIONINGMETHOD_Range)) {
|
||||
String error = RangePartitionInterval.validateIntervalPattern(column);
|
||||
|
@ -638,14 +1012,113 @@ public class TablePartitionService implements ITablePartitionService {
|
|||
|
||||
if (!isPartitionedTable(table, trxName))
|
||||
return null;
|
||||
|
||||
if (column.is_ValueChanged(MColumn.COLUMNNAME_IsPartitionKey)
|
||||
|| (column.isPartitionKey() && column.is_ValueChanged(MColumn.COLUMNNAME_IsActive))
|
||||
|| (column.isPartitionKey() && column.is_ValueChanged(MColumn.COLUMNNAME_SeqNoPartition))) {
|
||||
return validateConfiguration(table, trxName);
|
||||
|| (column.isPartitionKey() && column.is_ValueChanged(MColumn.COLUMNNAME_PartitioningMethod))) {
|
||||
if (partitionKeyColumns.size() == 2 || (partitionKeyColumns.size()==1 && !column.isPartitionKey() && column.is_ValueChanged(MColumn.COLUMNNAME_IsPartitionKey)))
|
||||
return Msg.getMsg(Env.getCtx(), "PartitionConfigurationChanged");
|
||||
else
|
||||
return validateConfiguration(table, trxName);
|
||||
}
|
||||
|
||||
if (column.isPartitionKey() && column.is_ValueChanged(MColumn.COLUMNNAME_SeqNoPartition) && partitionKeyColumns.size() == 2) {
|
||||
int oldSeq = column.get_ValueOldAsInt(MColumn.COLUMNNAME_SeqNoPartition);
|
||||
int newSeq = column.getSeqNoPartition();
|
||||
int otherSeq = partitionKeyColumns.get(0).getAD_Column_ID() == column.getAD_Column_ID()
|
||||
? partitionKeyColumns.get(1).getSeqNoPartition()
|
||||
: partitionKeyColumns.get(0).getSeqNoPartition();
|
||||
if (!(((newSeq < otherSeq) && (oldSeq < otherSeq)) || ((oldSeq > otherSeq) && (newSeq > otherSeq))))
|
||||
return Msg.getMsg(Env.getCtx(), "PartitionConfigurationChanged");
|
||||
}
|
||||
|
||||
if (column.isPartitionKey() && column.is_ValueChanged(MColumn.COLUMNNAME_RangePartitionInterval))
|
||||
return Msg.getMsg(Env.getCtx(), "PartitionConfigurationChanged") + " [" + MColumn.COLUMNNAME_RangePartitionInterval + "]";
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detachPartition(MTable table, X_AD_TablePartition partition, String trxName,
|
||||
ProcessInfo processInfo) {
|
||||
if (partition.isPartitionAttached()) {
|
||||
if (!"default".equalsIgnoreCase(partition.getExpressionPartition())) {
|
||||
StringBuilder alter = new StringBuilder("ALTER TABLE ");
|
||||
if (partition.getParent_TablePartition_ID() > 0) {
|
||||
X_AD_TablePartition parentPartition = new X_AD_TablePartition(Env.getCtx(), partition.getParent_TablePartition_ID(), trxName);
|
||||
alter.append(parentPartition.getName()).append(" ");
|
||||
} else {
|
||||
alter.append(table.getTableName()).append(" ");
|
||||
}
|
||||
alter.append("DETACH PARTITION ").append(partition.getName());
|
||||
int no = DB.executeUpdateEx(alter.toString(), trxName);
|
||||
if (processInfo != null)
|
||||
processInfo.addLog(0, null, null, no + " " + alter.toString());
|
||||
partition.setIsPartitionAttached(false);
|
||||
partition.saveEx();
|
||||
} else {
|
||||
throw new AdempiereException(Msg.getMsg(Env.getCtx(), "CantDetachReattachDefaultPartition"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reattachPartition(MTable table, X_AD_TablePartition partition, String trxName,
|
||||
ProcessInfo processInfo) {
|
||||
if (!partition.isPartitionAttached()) {
|
||||
if (!"default".equalsIgnoreCase(partition.getExpressionPartition())) {
|
||||
StringBuilder alter = new StringBuilder("ALTER TABLE ");
|
||||
if (partition.getParent_TablePartition_ID() > 0) {
|
||||
X_AD_TablePartition parentPartition = new X_AD_TablePartition(Env.getCtx(), partition.getParent_TablePartition_ID(), trxName);
|
||||
alter.append(parentPartition.getName()).append(" ");
|
||||
} else {
|
||||
alter.append(table.getTableName()).append(" ");
|
||||
}
|
||||
alter.append("ATTACH PARTITION ")
|
||||
.append(partition.getName())
|
||||
.append(" ")
|
||||
.append(partition.getExpressionPartition());
|
||||
boolean success = true;
|
||||
try {
|
||||
int no = DB.executeUpdateEx(alter.toString(), trxName);
|
||||
if (processInfo != null)
|
||||
processInfo.addLog(0, null, null, no + " " + alter.toString());
|
||||
} catch (RuntimeException e) {
|
||||
success = false;
|
||||
Trx.get(trxName, false).rollback();
|
||||
}
|
||||
|
||||
if (success) {
|
||||
partition.setIsPartitionAttached(true);
|
||||
partition.saveEx();
|
||||
} else {
|
||||
//fallback to insert and delete
|
||||
StringBuilder updateStmt = new StringBuilder();
|
||||
updateStmt.append("WITH x AS ( ");
|
||||
updateStmt.append("DELETE FROM ").append(partition.getName()).append(" ");
|
||||
updateStmt.append("RETURNING *) ");
|
||||
updateStmt.append("INSERT INTO ").append(table.getTableName()).append(" ");
|
||||
updateStmt.append("SELECT * FROM x");
|
||||
int no = DB.executeUpdateEx(updateStmt.toString(), trxName);
|
||||
if (processInfo != null)
|
||||
processInfo.addLog(0, null, null, no + " " + updateStmt.toString());
|
||||
alter = new StringBuilder("DROP TABLE ").append(partition.getName());
|
||||
no = DB.executeUpdateEx(alter.toString(), trxName);
|
||||
if (processInfo != null)
|
||||
processInfo.addLog(0, null, null, no + " " + alter.toString());
|
||||
try {
|
||||
Trx.get(trxName, false).commit(true);
|
||||
} catch (SQLException e) {
|
||||
throw new DBException(e);
|
||||
}
|
||||
|
||||
partition.deleteEx(true);
|
||||
table.getTablePartitions(true, trxName);
|
||||
addPartitionAndMigrateData(table, trxName, processInfo);
|
||||
}
|
||||
} else {
|
||||
throw new AdempiereException(Msg.getMsg(Env.getCtx(), "CantDetachReattachDefaultPartition"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ public class TablePartitionTask {
|
|||
|
||||
try
|
||||
{
|
||||
table.set_TrxName(trxName);
|
||||
addLog(Msg.getElement(Env.getCtx(), "TableName") + ": " + table.getTableName());
|
||||
|
||||
List<MColumn> partitionKeyColumns = table.getPartitionKeyColumns(true);
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/***********************************************************************
|
||||
* This file is part of iDempiere ERP Open Source *
|
||||
* http://www.idempiere.org *
|
||||
* *
|
||||
* Copyright (C) Contributors *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
|
||||
* MA 02110-1301, USA. *
|
||||
**********************************************************************/
|
||||
package org.idempiere.tablepartition.process;
|
||||
|
||||
import org.compiere.db.partition.ITablePartitionService;
|
||||
import org.compiere.model.MTable;
|
||||
import org.compiere.model.X_AD_TablePartition;
|
||||
import org.compiere.process.SvrProcess;
|
||||
import org.compiere.util.DB;
|
||||
import org.compiere.util.Env;
|
||||
import org.compiere.util.Msg;
|
||||
|
||||
@org.adempiere.base.annotation.Process
|
||||
public class ChangePartitionStatus extends SvrProcess {
|
||||
|
||||
private int p_record_ID = 0;
|
||||
private MTable table = null;
|
||||
|
||||
@Override
|
||||
protected void prepare() {
|
||||
p_record_ID = getRecord_ID();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doIt() throws Exception {
|
||||
ITablePartitionService service = DB.getDatabase().getTablePartitionService();
|
||||
if (service == null) {
|
||||
return "@Error@ " + Msg.getMsg(getCtx(), "DBAdapterNoTablePartitionSupport");
|
||||
}
|
||||
|
||||
if (p_record_ID <= 0)
|
||||
return "@Error@ " + Msg.getMsg(getCtx(), "FillMandatory", new Object[]{"Record ID"});
|
||||
|
||||
X_AD_TablePartition partition = new X_AD_TablePartition(Env.getCtx(), p_record_ID, get_TrxName());
|
||||
if (partition.get_ID() != p_record_ID)
|
||||
return "@Error@ " + Msg.getMsg(getCtx(), "FillMandatory", new Object[]{"Record ID"});
|
||||
|
||||
table = new MTable(Env.getCtx(), partition.getAD_Table_ID(), get_TrxName());
|
||||
if (partition.isPartitionAttached())
|
||||
return detachPartition(partition, service);
|
||||
else
|
||||
return reattachPartition(partition, service);
|
||||
}
|
||||
|
||||
private String reattachPartition(X_AD_TablePartition partition, ITablePartitionService service) {
|
||||
String partitionName = partition.getName();
|
||||
service.reattachPartition(table, partition, get_TrxName(), getProcessInfo());
|
||||
return Msg.getMsg(getCtx(), "PartitionReAttachToTable", new Object[] {partitionName, table.getTableName()});
|
||||
}
|
||||
|
||||
private String detachPartition(X_AD_TablePartition partition, ITablePartitionService service) {
|
||||
String partitionName = partition.getName();
|
||||
service.detachPartition(table, partition, get_TrxName(), getProcessInfo());
|
||||
return Msg.getMsg(getCtx(), "PartitionDetachFromTable", new Object[] {partitionName, table.getTableName()});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postProcess(boolean success) {
|
||||
if (success) {
|
||||
ITablePartitionService service = DB.getDatabase().getTablePartitionService();
|
||||
if (service != null) {
|
||||
service.runPostPartitionProcess(table, null, getProcessInfo());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue