~ubuntu-branches/ubuntu/raring/apgdiff/raring

« back to all changes in this revision

Viewing changes to src/main/java/cz/startnet/utils/pgdiff/schema/PgFunction.java

  • Committer: Bazaar Package Importer
  • Author(s): Christoph Berg
  • Date: 2010-10-11 09:08:18 UTC
  • mfrom: (2.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20101011090818-sdw8yfemrnxo328k
Tags: 2.2.2-1
* New upstream version.
* Using changelog included in zipfile, thanks Miroslav for providing this.
* Update manpage.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * Copyright 2006 StartNet s.r.o.
 
3
 *
 
4
 * Distributed under MIT license
 
5
 */
1
6
package cz.startnet.utils.pgdiff.schema;
2
7
 
3
 
import java.util.regex.Matcher;
4
 
import java.util.regex.Pattern;
 
8
import cz.startnet.utils.pgdiff.PgDiffUtils;
 
9
import java.util.ArrayList;
 
10
import java.util.Collections;
 
11
import java.util.List;
 
12
import java.util.Locale;
5
13
 
6
14
/**
7
15
 * Stores function information.
11
19
public class PgFunction {
12
20
 
13
21
    /**
14
 
     * Pattern for checking whether function definition contains CREATE
15
 
     * OR REPLACE FUNCTION string.
16
 
     */
17
 
    private static final Pattern PATTERN_CREATE_FUNCTION = Pattern.compile(
18
 
            "(?:CREATE[\\s]+FUNCTION)([\\s]+.*)",
19
 
            Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
20
 
    /**
21
 
     * Declaration of the function. Contains function name and
22
 
     * arguments.
23
 
     */
24
 
    private String declaration;
25
 
    /**
26
 
     * Whole definition of the function.
27
 
     */
28
 
    private String definition;
29
 
    /**
30
22
     * Name of the function including argument types.
31
23
     */
32
24
    private String name;
 
25
    /**
 
26
     * List of arguments.
 
27
     */
 
28
    @SuppressWarnings("CollectionWithoutInitialCapacity")
 
29
    private final List<Argument> arguments = new ArrayList<Argument>();
 
30
    /**
 
31
     * Whole definition of the function from RETURNS keyword.
 
32
     */
 
33
    private String body;
33
34
 
34
35
    /**
35
36
     * Returns creation SQL of the function.
37
38
     * @return creation SQL
38
39
     */
39
40
    public String getCreationSQL() {
40
 
        final String result;
41
 
        final Matcher matcher = PATTERN_CREATE_FUNCTION.matcher(definition);
42
 
 
43
 
        if (matcher.matches()) {
44
 
            result = "CREATE OR REPLACE FUNCTION" + matcher.group(1);
45
 
        } else {
46
 
            result = getDefinition();
 
41
        final StringBuilder sbSQL = new StringBuilder(500);
 
42
        sbSQL.append("CREATE OR REPLACE FUNCTION ");
 
43
        sbSQL.append(PgDiffUtils.getQuotedName(name));
 
44
        sbSQL.append('(');
 
45
 
 
46
        boolean addComma = false;
 
47
 
 
48
        for (final Argument argument : arguments) {
 
49
            if (addComma) {
 
50
                sbSQL.append(", ");
 
51
            }
 
52
 
 
53
            sbSQL.append(argument.getDeclaration(true));
 
54
 
 
55
            addComma = true;
47
56
        }
48
57
 
49
 
        return result;
50
 
    }
51
 
 
52
 
    /**
53
 
     * Setter for {@link #declaration}.
54
 
     *
55
 
     * @param declaration {@link #declaration}
56
 
     */
57
 
    public void setDeclaration(final String declaration) {
58
 
        this.declaration = declaration;
59
 
    }
60
 
 
61
 
    /**
62
 
     * Getter for {@link #declaration}.
63
 
     *
64
 
     * @return {@link #declaration}
65
 
     */
66
 
    public String getDeclaration() {
67
 
        return declaration;
68
 
    }
69
 
 
70
 
    /**
71
 
     * Setter for {@link #definition}.
72
 
     *
73
 
     * @param definition {@link #definition}
74
 
     */
75
 
    public void setDefinition(final String definition) {
76
 
        this.definition = definition;
77
 
    }
78
 
 
79
 
    /**
80
 
     * Getter for {@link #definition}.
81
 
     *
82
 
     * @return {@link #definition}
83
 
     */
84
 
    public String getDefinition() {
85
 
        return definition;
 
58
        sbSQL.append(") ");
 
59
        sbSQL.append(body);
 
60
 
 
61
        return sbSQL.toString();
 
62
    }
 
63
 
 
64
    /**
 
65
     * Setter for {@link #body}.
 
66
     *
 
67
     * @param body {@link #body}
 
68
     */
 
69
    public void setBody(final String body) {
 
70
        this.body = body;
 
71
    }
 
72
 
 
73
    /**
 
74
     * Getter for {@link #body}.
 
75
     *
 
76
     * @return {@link #body}
 
77
     */
 
78
    public String getBody() {
 
79
        return body;
86
80
    }
87
81
 
88
82
    /**
91
85
     * @return created SQL
92
86
     */
93
87
    public String getDropSQL() {
94
 
        return "DROP FUNCTION " + getDeclaration() + ";";
 
88
        final StringBuilder sbString = new StringBuilder(100);
 
89
        sbString.append("DROP FUNCTION ");
 
90
        sbString.append(name);
 
91
        sbString.append('(');
 
92
 
 
93
        boolean addComma = false;
 
94
 
 
95
        for (final Argument argument : arguments) {
 
96
            if ("OUT".equalsIgnoreCase(argument.getMode())) {
 
97
                continue;
 
98
            }
 
99
 
 
100
            if (addComma) {
 
101
                sbString.append(", ");
 
102
            }
 
103
 
 
104
            sbString.append(argument.getDeclaration(false));
 
105
 
 
106
            addComma = true;
 
107
        }
 
108
 
 
109
        sbString.append(");");
 
110
 
 
111
        return sbString.toString();
95
112
    }
96
113
 
97
114
    /**
113
130
    }
114
131
 
115
132
    /**
116
 
     * {@inheritDoc}
117
 
     *
118
 
     * @param object {@inheritDoc}
119
 
     *
120
 
     * @return {@inheritDoc}
121
 
     */
 
133
     * Getter for {@link #arguments}. List cannot be modified.
 
134
     *
 
135
     * @return {@link #arguments}
 
136
     */
 
137
    public List<Argument> getArguments() {
 
138
        return Collections.unmodifiableList(arguments);
 
139
    }
 
140
 
 
141
    /**
 
142
     * Adds argument to the list of arguments.
 
143
     *
 
144
     * @param argument argument
 
145
     */
 
146
    public void addArgument(final Argument argument) {
 
147
        arguments.add(argument);
 
148
    }
 
149
 
 
150
    /**
 
151
     * Returns function signature. It consists of unquoted name and argument
 
152
     * data types.
 
153
     * 
 
154
     * @return function signature
 
155
     */
 
156
    public String getSignature() {
 
157
        final StringBuilder sbString = new StringBuilder(100);
 
158
        sbString.append(name);
 
159
        sbString.append('(');
 
160
 
 
161
        boolean addComma = false;
 
162
 
 
163
        for (final Argument argument : arguments) {
 
164
            if ("OUT".equalsIgnoreCase(argument.getMode())) {
 
165
                continue;
 
166
            }
 
167
 
 
168
            if (addComma) {
 
169
                sbString.append(',');
 
170
            }
 
171
 
 
172
            sbString.append(argument.getDataType().toLowerCase(Locale.ENGLISH));
 
173
 
 
174
            addComma = true;
 
175
        }
 
176
 
 
177
        sbString.append(')');
 
178
 
 
179
        return sbString.toString();
 
180
    }
 
181
 
122
182
    @Override
123
183
    public boolean equals(final Object object) {
 
184
        if (!(object instanceof PgFunction)) {
 
185
            return false;
 
186
        } else if (object == this) {
 
187
            return true;
 
188
        }
 
189
 
124
190
        return equals(object, false);
125
191
    }
126
192
 
127
193
    /**
128
194
     * Compares two objects whether they are equal. If both objects are of the
129
 
     * same class but they equal just in whitespace in {@link #definition},
 
195
     * same class but they equal just in whitespace in {@link #body},
130
196
     * they are considered being equal.
131
197
     *
132
198
     * @param object object to be compared
133
199
     * @param ignoreFunctionWhitespace whether multiple whitespaces in function
134
 
     * {@link #definition} should be ignored
 
200
     * {@link #body} should be ignored
135
201
     *
136
 
     * @return {@inheritDoc}
 
202
     * @return true if <code>object</code> is pg function and the function code
 
203
     * is the same when compared ignoring whitespace, otherwise returns false
137
204
     */
138
205
    public boolean equals(final Object object,
139
206
            final boolean ignoreFunctionWhitespace) {
143
210
            equals = true;
144
211
        } else if (object instanceof PgFunction) {
145
212
            final PgFunction function = (PgFunction) object;
146
 
            final String thisDefinition;
147
 
            final String thatDefinition;
 
213
 
 
214
            if (name == null && function.getName() != null
 
215
                    || name != null && !name.equals(function.getName())) {
 
216
                return false;
 
217
            }
 
218
 
 
219
            final String thisBody;
 
220
            final String thatBody;
148
221
 
149
222
            if (ignoreFunctionWhitespace) {
150
 
                thisDefinition = getDefinition().replaceAll("\\s+", " ");
151
 
                thatDefinition =
152
 
                        function.getDefinition().replaceAll("\\s+", " ");
153
 
            } else {
154
 
                thisDefinition = getDefinition();
155
 
                thatDefinition = function.getDefinition();
156
 
            }
157
 
            equals = declaration.equals(function.declaration)
158
 
                    && thisDefinition.equals(thatDefinition)
159
 
                    && name.equals(function.name);
 
223
                thisBody = body.replaceAll("\\s+", " ");
 
224
                thatBody =
 
225
                        function.getBody().replaceAll("\\s+", " ");
 
226
            } else {
 
227
                thisBody = body;
 
228
                thatBody = function.getBody();
 
229
            }
 
230
 
 
231
            if (thisBody == null && thatBody != null
 
232
                    || thisBody != null && !thisBody.equals(thatBody)) {
 
233
                return false;
 
234
            }
 
235
 
 
236
            if (arguments.size() != function.getArguments().size()) {
 
237
                return false;
 
238
            } else {
 
239
                for (int i = 0; i < arguments.size(); i++) {
 
240
                    if (!arguments.get(i).equals(function.getArguments().get(i))) {
 
241
                        return false;
 
242
                    }
 
243
                }
 
244
            }
 
245
 
 
246
            return true;
160
247
        }
161
248
 
162
249
        return equals;
163
250
    }
164
251
 
165
 
    /**
166
 
     * {@inheritDoc}
167
 
     *
168
 
     * @return {@inheritDoc}
169
 
     */
170
252
    @Override
171
253
    public int hashCode() {
172
 
        return (getClass().getName() + "|" + declaration + "|" + getDefinition()
173
 
                + "|" + name).hashCode();
 
254
        final StringBuilder sbString = new StringBuilder(500);
 
255
        sbString.append(body);
 
256
        sbString.append('|');
 
257
        sbString.append(name);
 
258
 
 
259
        for (final Argument argument : arguments) {
 
260
            sbString.append('|');
 
261
            sbString.append(argument.getDeclaration(true));
 
262
        }
 
263
 
 
264
        return sbString.toString().hashCode();
 
265
    }
 
266
 
 
267
    /**
 
268
     * Function argument information.
 
269
     */
 
270
    @SuppressWarnings("PublicInnerClass")
 
271
    public static class Argument {
 
272
 
 
273
        /**
 
274
         * Argument mode.
 
275
         */
 
276
        private String mode = "IN";
 
277
        /**
 
278
         * Argument name.
 
279
         */
 
280
        private String name;
 
281
        /**
 
282
         * Argument data type.
 
283
         */
 
284
        private String dataType;
 
285
        /**
 
286
         * Argument default expression.
 
287
         */
 
288
        private String defaultExpression;
 
289
 
 
290
        /**
 
291
         * Getter for {@link #dataType}.
 
292
         *
 
293
         * @return {@link #dataType}
 
294
         */
 
295
        public String getDataType() {
 
296
            return dataType;
 
297
        }
 
298
 
 
299
        /**
 
300
         * Setter for {@link #dataType}.
 
301
         *
 
302
         * @param dataType {@link #dataType}
 
303
         */
 
304
        public void setDataType(final String dataType) {
 
305
            this.dataType = dataType;
 
306
        }
 
307
 
 
308
        /**
 
309
         * Getter for {@link #defaultExpression}.
 
310
         *
 
311
         * @return {@link #defaultExpression}
 
312
         */
 
313
        public String getDefaultExpression() {
 
314
            return defaultExpression;
 
315
        }
 
316
 
 
317
        /**
 
318
         * Setter for {@link #defaultExpression}.
 
319
         *
 
320
         * @param defaultExpression {@link #defaultExpression}
 
321
         */
 
322
        public void setDefaultExpression(final String defaultExpression) {
 
323
            this.defaultExpression = defaultExpression;
 
324
        }
 
325
 
 
326
        /**
 
327
         * Getter for {@link #mode}.
 
328
         *
 
329
         * @return {@link #mode}
 
330
         */
 
331
        public String getMode() {
 
332
            return mode;
 
333
        }
 
334
 
 
335
        /**
 
336
         * Setter for {@link #mode}.
 
337
         *
 
338
         * @param mode {@link #mode}
 
339
         */
 
340
        public void setMode(final String mode) {
 
341
            this.mode = mode == null || mode.isEmpty() ? "IN" : mode;
 
342
        }
 
343
 
 
344
        /**
 
345
         * Getter for {@link #name}.
 
346
         *
 
347
         * @return {@link #name}
 
348
         */
 
349
        public String getName() {
 
350
            return name;
 
351
        }
 
352
 
 
353
        /**
 
354
         * Setter for {@link #name}.
 
355
         *
 
356
         * @param name {@link #name}
 
357
         */
 
358
        public void setName(final String name) {
 
359
            this.name = name;
 
360
        }
 
361
 
 
362
        /**
 
363
         * Creates argument declaration.
 
364
         *
 
365
         * @param includeDefaultValue whether to include default value
 
366
         *
 
367
         * @return argument declaration
 
368
         */
 
369
        public String getDeclaration(final boolean includeDefaultValue) {
 
370
            final StringBuilder sbString = new StringBuilder(50);
 
371
 
 
372
            if (mode != null && !"IN".equalsIgnoreCase(mode)) {
 
373
                sbString.append(mode);
 
374
                sbString.append(' ');
 
375
            }
 
376
 
 
377
            if (name != null && !name.isEmpty()) {
 
378
                sbString.append(PgDiffUtils.getQuotedName(name));
 
379
                sbString.append(' ');
 
380
            }
 
381
 
 
382
            sbString.append(dataType);
 
383
 
 
384
            if (includeDefaultValue && defaultExpression != null
 
385
                    && !defaultExpression.isEmpty()) {
 
386
                sbString.append(" = ");
 
387
                sbString.append(defaultExpression);
 
388
            }
 
389
 
 
390
            return sbString.toString();
 
391
        }
 
392
 
 
393
        @Override
 
394
        public boolean equals(final Object obj) {
 
395
            if (!(obj instanceof Argument)) {
 
396
                return false;
 
397
            } else if (this == obj) {
 
398
                return true;
 
399
            }
 
400
 
 
401
            final Argument argument = (Argument) obj;
 
402
 
 
403
            return (dataType == null ? argument.getDataType() == null
 
404
                    : dataType.equalsIgnoreCase(argument.getDataType()))
 
405
                    && (defaultExpression == null
 
406
                    ? argument.getDefaultExpression() == null
 
407
                    : defaultExpression.equals(defaultExpression))
 
408
                    && (mode == null ? argument.getMode() == null
 
409
                    : mode.equalsIgnoreCase(argument.getMode()))
 
410
                    && (name == null ? argument.getName() == null
 
411
                    : name.equals(argument.getName()));
 
412
        }
 
413
 
 
414
        @Override
 
415
        public int hashCode() {
 
416
            final StringBuilder sbString = new StringBuilder(50);
 
417
            sbString.append(
 
418
                    mode == null ? null : mode.toUpperCase(Locale.ENGLISH));
 
419
            sbString.append('|');
 
420
            sbString.append(name);
 
421
            sbString.append('|');
 
422
            sbString.append(dataType == null ? null
 
423
                    : dataType.toUpperCase(Locale.ENGLISH));
 
424
            sbString.append('|');
 
425
            sbString.append(defaultExpression);
 
426
 
 
427
            return sbString.toString().hashCode();
 
428
        }
174
429
    }
175
430
}