OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 67 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
17 ilm 1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
5
 *
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
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.
10
 *
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
13
 
14
 package org.openconcerto.sql.model;
15
 
16
import org.openconcerto.utils.CollectionUtils;
17
import org.openconcerto.utils.cc.ITransformer;
18
 
19
import java.util.ArrayList;
20
import java.util.Arrays;
21
import java.util.Collections;
22
import java.util.List;
23
import java.util.regex.Matcher;
24
import java.util.regex.Pattern;
25
 
26
/**
27
 * A dotted SQL name, eg "table.field" or "schema.table".
28
 *
29
 * @author Sylvain
30
 */
31
public final class SQLName {
32
 
33
    private static final Pattern unquoted = Pattern.compile("\\w+");
34
 
35
    /**
36
     * Parse a possibly quoted string to an SQL name.
37
     *
38
     * @param name a String, eg public."ta.ble seq".
39
     * @return the corresponding SQL name, eg "public"."ta.ble seq".
40
     */
41
    public static SQLName parse(String name) {
42
        name = name.trim();
43
        final List<String> res = new ArrayList<String>();
44
        int index = 0;
45
        while (index < name.length()) {
46
            final char c = name.charAt(index);
47
            final boolean inQuote = c == '"';
48
            if (inQuote) {
49
                // pass the opening quote
50
                index += 1;
51
                int index2 = findNextQuote(name, index);
52
                // handle escaped "
53
                String part = "";
54
                // while the char after " is also "
55
                while ((index2 + 1) < name.length() && name.charAt(index2 + 1) == '"') {
56
                    // index2+1 to keep the first quote
57
                    part += name.substring(index, index2 + 1);
58
                    // pass ""
59
                    index = index2 + 2;
60
                    index2 = findNextQuote(name, index);
61
                }
62
                part += name.substring(index, index2);
63
                res.add(part);
64
                // pass the closing quote
65
                index = index2 + 1;
66
            } else {
67
                final Matcher matcher = unquoted.matcher(name);
68
                if (!matcher.find(index))
69
                    throw new IllegalArgumentException("illegal unquoted name at " + index);
70
                final int index2 = matcher.end();
71
                res.add(name.substring(index, index2));
72
                index = index2;
73
            }
74
            if (index != name.length()) {
75
                if (name.charAt(index) != '.')
76
                    throw new IllegalArgumentException("no dot at " + index);
77
                if (index == name.length() - 1)
78
                    throw new IllegalArgumentException("trailing dot");
79
                // pass the dot
80
                index += 1;
81
            }
82
        }
83
 
84
        return new SQLName(res);
85
    }
86
 
87
    private static int findNextQuote(final String name, final int index) {
88
        final int res = name.indexOf('"', index);
89
        if (res < 0)
90
            throw new IllegalArgumentException("no corresponding quote " + index);
91
        return res;
92
    }
93
 
94
    final List<String> items;
95
 
96
    public SQLName(String... items) {
97
        this(Arrays.asList(items));
98
    }
99
 
100
    /**
101
     * Create a new instance, ignoring null items.
102
     *
103
     * @param items the names.
104
     */
105
    public SQLName(List<String> items) {
106
        super();
107
        this.items = new ArrayList<String>(items.size());
108
        for (final String item : items) {
109
            if (item != null)
110
                this.items.add(item);
111
        }
112
    }
113
 
114
    /**
115
     * Return the quoted form, eg for table.field : "table"."field".
116
     *
117
     * @return the quoted form of this name.
118
     */
119
    public String quote() {
120
        return CollectionUtils.join(this.items, ".", new ITransformer<String, String>() {
121
            public String transformChecked(String input) {
122
                return SQLBase.quoteIdentifier(input);
123
            }
124
        });
125
    }
126
 
127
    /**
128
     * Return the item at the given index. You can use negatives to count backwards (ie -1 is the
129
     * last item).
130
     *
131
     * @param index an int between 0 and count - 1, or between -count and -1.
132
     * @return the corresponding item.
133
     */
134
    public String getItem(int index) {
135
        if (index < 0)
136
            index = this.getItemCount() + index;
137
        return this.items.get(index);
138
    }
139
 
140
    /**
141
     * Same as getItem, but will return <code>null</code> if index is out of bound.
142
     *
143
     * @param index an int.
144
     * @return the corresponding item, or <code>null</code>.
145
     */
146
    public String getItemLenient(int index) {
147
        try {
148
            return this.getItem(index);
149
        } catch (IndexOutOfBoundsException e) {
150
            return null;
151
        }
152
    }
153
 
154
    public int getItemCount() {
155
        return this.items.size();
156
    }
157
 
158
    /**
159
     * The last part, eg "field" for table.field.
160
     *
161
     * @return the name.
162
     */
163
    public String getName() {
164
        return this.getItem(this.items.size() - 1);
165
    }
166
 
167
    public String getFirst() {
168
        return this.getItem(0);
169
    }
170
 
171
    public SQLName getRest() {
172
        return new SQLName(this.items.subList(1, this.items.size()));
173
    }
174
 
175
    public final List<String> asList() {
176
        return Collections.unmodifiableList(this.items);
177
    }
178
 
179
    @Override
180
    public boolean equals(Object obj) {
181
        if (obj instanceof SQLName) {
182
            final SQLName o = (SQLName) obj;
183
            return this.items.equals(o.items);
184
        } else
185
            return false;
186
    }
187
 
188
    @Override
189
    public int hashCode() {
190
        return this.items.hashCode();
191
    }
192
 
193
    public String toString() {
194
        return this.quote();
195
    }
196
}