OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 132 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 132 Rev 180
1
/*
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 * 
3
 * 
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
5
 * 
5
 * 
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
9
 * language governing permissions and limitations under the License.
10
 * 
10
 * 
11
 * When distributing the software, include this License Header Notice in each file.
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
12
 */
13
 
13
 
14
 package org.openconcerto.sql.changer.correct;
14
 package org.openconcerto.sql.changer.correct;
15
 
15
 
16
import org.openconcerto.sql.Configuration;
16
import org.openconcerto.sql.Configuration;
17
import org.openconcerto.sql.changer.Changer;
17
import org.openconcerto.sql.changer.Changer;
18
import org.openconcerto.sql.element.SQLElement;
18
import org.openconcerto.sql.element.SQLElement;
19
import org.openconcerto.sql.element.SQLElementDirectory;
19
import org.openconcerto.sql.element.SQLElementDirectory;
20
import org.openconcerto.sql.element.SQLElementLink;
20
import org.openconcerto.sql.element.SQLElementLink;
21
import org.openconcerto.sql.element.SQLElementLink.LinkType;
21
import org.openconcerto.sql.element.SQLElementLink.LinkType;
22
import org.openconcerto.sql.model.DBSystemRoot;
22
import org.openconcerto.sql.model.DBSystemRoot;
23
import org.openconcerto.sql.model.SQLField;
23
import org.openconcerto.sql.model.SQLField;
24
import org.openconcerto.sql.model.SQLRowValues;
24
import org.openconcerto.sql.model.SQLRowValues;
25
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
25
import org.openconcerto.sql.model.SQLRowValuesListFetcher;
26
import org.openconcerto.sql.model.SQLSelect;
26
import org.openconcerto.sql.model.SQLSelect;
27
import org.openconcerto.sql.model.SQLSelect.ArchiveMode;
27
import org.openconcerto.sql.model.SQLSelect.ArchiveMode;
-
 
28
import org.openconcerto.sql.model.SQLSystem;
28
import org.openconcerto.sql.model.SQLTable;
29
import org.openconcerto.sql.model.SQLTable;
29
import org.openconcerto.sql.model.Where;
30
import org.openconcerto.sql.model.Where;
30
import org.openconcerto.sql.model.graph.Path;
31
import org.openconcerto.sql.model.graph.Path;
31
import org.openconcerto.sql.model.graph.Step;
32
import org.openconcerto.sql.model.graph.Step;
32
import org.openconcerto.sql.utils.SQLUtils;
33
import org.openconcerto.sql.utils.SQLUtils;
33
import org.openconcerto.sql.utils.SQLUtils.SQLFactory;
34
import org.openconcerto.sql.utils.SQLUtils.SQLFactory;
34
import org.openconcerto.utils.cc.ITransformer;
35
import org.openconcerto.utils.cc.ITransformer;
35
 
36
 
36
import java.sql.SQLException;
37
import java.sql.SQLException;
-
 
38
import java.util.EnumSet;
37
import java.util.List;
39
import java.util.List;
38
 
40
 
39
/**
41
/**
40
 * Find the private foreign fields for the passed tables and copy the shared private rows. Eg if
42
 * Find the private foreign fields for the passed tables and copy the shared private rows. Eg if
41
 * CPI1 -> OBS1{DES='pb'} and CPI2 -> OBS1{DES='pb'} this clones OBS1 : CPI1 -> OBS1{DES='pb'} and
43
 * CPI1 -> OBS1{DES='pb'} and CPI2 -> OBS1{DES='pb'} this clones OBS1 : CPI1 -> OBS1{DES='pb'} and
42
 * CPI2 -> OBS2{DES='pb'}.
44
 * CPI2 -> OBS2{DES='pb'}.
43
 * 
45
 * 
44
 * @author Sylvain
46
 * @author Sylvain
45
 */
47
 */
46
public class FixSharedPrivate extends Changer<SQLTable> {
48
public class FixSharedPrivate extends Changer<SQLTable> {
47
 
49
 
48
    private final SQLElementDirectory dir;
50
    private final SQLElementDirectory dir;
49
 
51
 
50
    public FixSharedPrivate(DBSystemRoot b) {
52
    public FixSharedPrivate(DBSystemRoot b) {
51
        this(b, null);
53
        this(b, null);
52
    }
54
    }
53
 
55
 
54
    public FixSharedPrivate(DBSystemRoot b, final SQLElementDirectory dir) {
56
    public FixSharedPrivate(DBSystemRoot b, final SQLElementDirectory dir) {
55
        super(b);
57
        super(b);
56
        if (dir == null) {
58
        if (dir == null) {
57
            if (Configuration.getInstance() == null)
59
            if (Configuration.getInstance() == null)
58
                throw new IllegalStateException("no conf");
60
                throw new IllegalStateException("no conf");
59
            this.dir = Configuration.getInstance().getDirectory();
61
            this.dir = Configuration.getInstance().getDirectory();
60
            if (this.dir == null)
62
            if (this.dir == null)
61
                throw new IllegalStateException("no directory in conf");
63
                throw new IllegalStateException("no directory in conf");
62
        } else {
64
        } else {
63
            this.dir = dir;
65
            this.dir = dir;
64
        }
66
        }
65
        assert this.dir != null;
67
        assert this.dir != null;
66
    }
68
    }
67
 
69
 
68
    public final SQLElementDirectory getDir() {
70
    public final SQLElementDirectory getDir() {
69
        return this.dir;
71
        return this.dir;
70
    }
72
    }
-
 
73
 
-
 
74
    @Override
-
 
75
    protected EnumSet<SQLSystem> getCompatibleSystems() {
-
 
76
        // When executing deleteReq :
-
 
77
        // - if PRIVATE_REFS is temporary : "Can't reopen table"
-
 
78
        // - if not : "You can't specify target table 'PRIVATE_REFS' for update in FROM clause"
-
 
79
        return EnumSet.complementOf(EnumSet.of(SQLSystem.MYSQL));
-
 
80
    }
71
 
81
 
72
    @Override
82
    @Override
73
    protected void changeImpl(final SQLTable t) throws SQLException {
83
    protected void changeImpl(final SQLTable t) throws SQLException {
74
        getStream().print(t);
84
        getStream().print(t);
75
        final SQLElement elem = this.getDir().getElement(t);
85
        final SQLElement elem = this.getDir().getElement(t);
76
        if (elem == null) {
86
        if (elem == null) {
77
            getStream().println(" : no element");
87
            getStream().println(" : no element");
78
            return;
88
            return;
79
        } else {
89
        } else {
80
            getStream().println("... ");
90
            getStream().println("... ");
81
        }
91
        }
82
 
92
 
83
        for (final SQLElementLink elemLink : elem.getOwnedLinks().getByType(LinkType.COMPOSITION)) {
93
        for (final SQLElementLink elemLink : elem.getOwnedLinks().getByType(LinkType.COMPOSITION)) {
84
            // e.g. to either MISSION (i.e. empty path) or MISSION_Q18
94
            // e.g. to either MISSION (i.e. empty path) or MISSION_Q18
85
            final Path pathToForeign = elemLink.getPath().minusLast();
95
            final Path pathToForeign = elemLink.getPath().minusLast();
86
            // e.g. ID_Q18
96
            // e.g. ID_Q18
87
            final Step toPrivateStep = elemLink.getPath().getStep(-1);
97
            final Step toPrivateStep = elemLink.getPath().getStep(-1);
88
 
98
 
89
            // eg Q18
99
            // eg Q18
90
            final SQLElement privateElement = elemLink.getOwned();
100
            final SQLElement privateElement = elemLink.getOwned();
91
            final SQLTable privateTable = privateElement.getTable();
101
            final SQLTable privateTable = privateElement.getTable();
92
            // SELECT q.ID FROM Ideation_2007.Q18 q
102
            // SELECT q.ID FROM Ideation_2007.Q18 q
93
            // JOIN Ideation_2007.MISSION m on m.ID_Q18 = q.ID
103
            // JOIN Ideation_2007.MISSION m on m.ID_Q18 = q.ID
94
            // where q.ID != 1
104
            // where q.ID != 1
95
            // GROUP BY q.ID
105
            // GROUP BY q.ID
96
            // HAVING count(q.ID) > 1;
106
            // HAVING count(q.ID) > 1;
97
            final SQLSelect sel = new SQLSelect();
107
            final SQLSelect sel = new SQLSelect();
98
            sel.setArchivedPolicy(ArchiveMode.BOTH);
108
            sel.setArchivedPolicy(ArchiveMode.BOTH);
99
            sel.addSelect(privateTable.getKey());
109
            sel.addSelect(privateTable.getKey());
100
            // The last step of a ElementLink is always foreign, be it a simple foreign key or with
110
            // The last step of a ElementLink is always foreign, be it a simple foreign key or with
101
            // a join table. Thus we don't need to go back to the main row to find duplicates.
111
            // a join table. Thus we don't need to go back to the main row to find duplicates.
102
            assert toPrivateStep.isForeign();
112
            assert toPrivateStep.isForeign();
103
            sel.addJoin("INNER", null, toPrivateStep.reverse(), "m");
113
            sel.addJoin("INNER", null, toPrivateStep.reverse(), "m");
104
            final String req = sel.asString() + " GROUP BY " + privateTable.getKey().getFieldRef() + " HAVING count(" + privateTable.getKey().getFieldRef() + ")>1";
114
            final String req = sel.asString() + " GROUP BY " + privateTable.getKey().getFieldRef() + " HAVING count(" + privateTable.getKey().getFieldRef() + ")>1";
105
 
115
 
106
            @SuppressWarnings("unchecked")
116
            @SuppressWarnings("unchecked")
107
            final List<Number> privateIDs = t.getDBSystemRoot().getDataSource().executeCol(req);
117
            final List<Number> privateIDs = t.getDBSystemRoot().getDataSource().executeCol(req);
108
            if (privateIDs.size() > 0) {
118
            if (privateIDs.size() > 0) {
109
                getStream().println("\t" + elemLink + " fixing " + privateIDs.size() + " ... ");
119
                getStream().println("\t" + elemLink + " fixing " + privateIDs.size() + " ... ");
110
                final SQLField archF = t.getArchiveField();
120
                final SQLField archF = t.getArchiveField();
111
                final SQLField privateArchF = privateTable.getArchiveField();
121
                final SQLField privateArchF = privateTable.getArchiveField();
112
                if ((archF == null) != (privateArchF == null))
122
                if ((archF == null) != (privateArchF == null))
113
                    throw new IllegalStateException("Incoherent archive field : " + archF + " / " + privateArchF);
123
                    throw new IllegalStateException("Incoherent archive field : " + archF + " / " + privateArchF);
114
                SQLUtils.executeAtomic(t.getDBSystemRoot().getDataSource(), new SQLFactory<Object>() {
124
                SQLUtils.executeAtomic(t.getDBSystemRoot().getDataSource(), new SQLFactory<Object>() {
115
                    @Override
125
                    @Override
116
                    public Object create() throws SQLException {
126
                    public Object create() throws SQLException {
117
                        // for each private pointed by more than one parent
127
                        // for each private pointed by more than one parent
118
                        for (final Number privateID : privateIDs) {
128
                        for (final Number privateID : privateIDs) {
119
                            final SQLRowValues vals = new SQLRowValues(t);
129
                            final SQLRowValues vals = new SQLRowValues(t);
120
                            if (archF != null)
130
                            if (archF != null)
121
                                vals.putNulls(archF.getName());
131
                                vals.putNulls(archF.getName());
122
                            // e.g. ID_OBSERVATION
132
                            // e.g. ID_OBSERVATION
123
                            final SQLField ff = toPrivateStep.getSingleField();
133
                            final SQLField ff = toPrivateStep.getSingleField();
124
                            vals.assurePath(pathToForeign).putNulls(ff.getName());
134
                            vals.assurePath(pathToForeign).putNulls(ff.getName());
125
 
135
 
126
                            final SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(vals);
136
                            final SQLRowValuesListFetcher fetcher = SQLRowValuesListFetcher.create(vals);
127
                            fetcher.setSelTransf(new ITransformer<SQLSelect, SQLSelect>() {
137
                            fetcher.setSelTransf(new ITransformer<SQLSelect, SQLSelect>() {
128
                                @Override
138
                                @Override
129
                                public SQLSelect transformChecked(SQLSelect fixSel) {
139
                                public SQLSelect transformChecked(SQLSelect fixSel) {
130
                                    fixSel.setArchivedPolicy(ArchiveMode.BOTH);
140
                                    fixSel.setArchivedPolicy(ArchiveMode.BOTH);
131
                                    fixSel.setWhere(new Where(fixSel.getAlias(ff), "=", privateID));
141
                                    fixSel.setWhere(new Where(fixSel.getAlias(ff), "=", privateID));
132
                                    return fixSel;
142
                                    return fixSel;
133
                                }
143
                                }
134
                            });
144
                            });
135
 
145
 
136
                            final List<SQLRowValues> tIDs = fetcher.fetch();
146
                            final List<SQLRowValues> tIDs = fetcher.fetch();
137
                            for (final SQLRowValues tID : tIDs) {
147
                            for (final SQLRowValues tID : tIDs) {
138
                                // the first one can keep its private
148
                                // the first one can keep its private
139
                                final SQLRowValues reallyPrivate;
149
                                final SQLRowValues reallyPrivate;
140
                                if (tID == tIDs.get(0))
150
                                if (tID == tIDs.get(0))
141
                                    reallyPrivate = new SQLRowValues(privateElement.getTable()).setID(privateID);
151
                                    reallyPrivate = new SQLRowValues(privateElement.getTable()).setID(privateID);
142
                                else
152
                                else
143
                                    reallyPrivate = privateElement.createCopy(privateID.intValue());
153
                                    reallyPrivate = privateElement.createCopy(privateID.intValue());
144
                                // keep archive coherence
154
                                // keep archive coherence
145
                                if (archF != null)
155
                                if (archF != null)
146
                                    reallyPrivate.put(privateArchF.getName(), tID.getObject(archF.getName()));
156
                                    reallyPrivate.put(privateArchF.getName(), tID.getObject(archF.getName()));
147
                                new SQLRowValues(pathToForeign.getLast()).setID(tID.followPath(pathToForeign).getIDNumber()).put(ff.getName(), reallyPrivate).update();
157
                                new SQLRowValues(pathToForeign.getLast()).setID(tID.followPath(pathToForeign).getIDNumber()).put(ff.getName(), reallyPrivate).update();
148
                            }
158
                            }
149
                        }
159
                        }
150
                        return null;
160
                        return null;
151
                    }
161
                    }
152
                });
162
                });
153
            }
163
            }
154
        }
164
        }
155
        getStream().println(t + " done");
165
        getStream().println(t + " done");
156
    }
166
    }
157
}
167
}