File: Informix11Platform.java

package info (click to toggle)
eclipselink 2.6.9-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 44,528 kB
  • sloc: java: 475,126; xml: 72; makefile: 21; sh: 10
file content (487 lines) | stat: -rw-r--r-- 17,818 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
/*******************************************************************************
 * Copyright (c) 2011, 2014 Jenzabar, Inc, Oracle and/or its affiliates. All rights reserved.
 * This program and the accompanying materials are made available under the 
 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 
 * which accompanies this distribution. 
 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
 * and the Eclipse Distribution License is available at 
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * Contributors:
 *     Jenzabar - Initial implementation
 ******************************************************************************/  

package org.eclipse.persistence.platform.database;

import java.io.IOException;
import java.io.Serializable; // for javadoc only
import java.io.Writer;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

import java.util.Collection;

import org.eclipse.persistence.internal.databaseaccess.DatasourcePlatform; // for javadoc only

import org.eclipse.persistence.internal.sessions.AbstractSession;

import org.eclipse.persistence.expressions.ExpressionOperator;

import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.internal.helper.DatabaseTable;

import org.eclipse.persistence.platform.database.H2Platform; // for javadoc only
import org.eclipse.persistence.platform.database.InformixPlatform;

import org.eclipse.persistence.queries.UpdateAllQuery; // for javadoc only

/**
 * An {@link InformixPlatform} that fixes many EclipseLink bugs
 * related to Informix support.
 *
 * @see <a
 * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=401393">EclipseLink
 * bug 401393</a>
 *
 * @see <a
 * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=401718">EclipseLink
 * bug 401718</a>
 *
 * @see <a
 * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=401746">EclipseLink
 * bug 401746</a> 
 *
 * @see <a
 * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=402037">EclipseLink
 * bug 402037</a>
 *
 * @see <a
 * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=402180">EclipseLink
 * bug 402180</a>
 *
 * @see <a
 * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=402600">EclipseLink
 * bug 402600</a>
 *
 * @see <a
 * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=402953">EclipseLink
 * bug 402953</a>
 *
 * @see <a
 * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=405645">EclipseLink
 * bug 405645</a>
 */
public class Informix11Platform extends InformixPlatform {

  /**
   * The version of this class for serialization purposes.
   *
   * @see Serializable
   */
  private static final long serialVersionUID = 1L;

  /**
   * Creates a new {@link Informix11Platform}.  Calls {@link
   * #setShouldBindLiterals(boolean)} with {@code false} as a
   * parameter value.
   *
   * @see <a
   * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=401718">EclipseLink
   * bug 401718</a>
   */
  public Informix11Platform() {
    super();
    this.setShouldBindLiterals(false);
  }

  /**
   * Fixes <a
   * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=402600">EclipseLink
   * bug 402600</a> by making sure that the {@link
   * ExpressionOperator#distinct() Distinct} {@link
   * ExpressionOperator} is set to {@linkplain
   * ExpressionOperator#printsAs(String) print as} {@code
   * DISTINCT&nbsp;} (no parentheses, one trailing space), and fixes
   * <a
   * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=402953">EclipseLink
   * bug 402953</a> by {@linkplain
   * DatasourcePlatform#addOperator(ExpressionOperator) adding
   * platform operators} for {@linkplain
   * ExpressionOperator#CurrentDate current date} and {@linkplain
   * ExpressionOperator#CurrentTime current time}.
   *
   * @see #currentDateOperator()
   *
   * @see #currentTimeOperator()
   *
   * @see <a
   * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=402600">EclipseLink
   * bug 402600</a>
   *
   * @see <a
   * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=402953">EclipseLink
   * bug 402953</a>
   */
  @Override
  protected void initializePlatformOperators() {
    final ExpressionOperator distinctOverride = ExpressionOperator.getOperator(Integer.valueOf(ExpressionOperator.Distinct));
    assert distinctOverride != null;
    distinctOverride.printsAs("DISTINCT "); // no parens, one space
    super.initializePlatformOperators();
    this.addOperator(this.currentDateOperator());
    this.addOperator(this.currentTimeOperator());
  }

  /**
   * Fixes <a
   * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=402953">EclipseLink
   * bug 402953</a> by returning the result of running the following
   * code: {@link ExpressionOperator#simpleFunctionNoParentheses(int,
   * String)
   * ExpressionOperator.simpleFunctionNoParentheses(ExpressionOperator.CurrentDate,
   * "CURRENT YEAR TO DAY");}
   *
   * @return a non-{@code null} {@link ExpressionOperator}
   *
   * @see <a
   * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=402953">EclipseLink
   * bug 402953</a>
   */
  protected ExpressionOperator currentDateOperator() {
    return ExpressionOperator.simpleFunctionNoParentheses(ExpressionOperator.CurrentDate, "CURRENT YEAR TO DAY");
  }

  /**
   * Fixes <a
   * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=402953">EclipseLink
   * bug 402953</a> by returning the result of running the following
   * code: {@link ExpressionOperator#simpleFunctionNoParentheses(int,
   * String)
   * ExpressionOperator.simpleFunctionNoParentheses(ExpressionOperator.CurrentDate,
   * "CURRENT YEAR TO FRACTION(3)");}
   *
   * @return a non-{@code null} {@link ExpressionOperator}
   *
   * <a
   * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=402953">EclipseLink
   * bug 402953</a>
   */
  protected ExpressionOperator currentTimeOperator() {
    return ExpressionOperator.simpleFunctionNoParentheses(ExpressionOperator.CurrentDate, "CURRENT YEAR TO FRACTION(3)");
  }

  /**
   * Overrides the default behavior to return {@code false},
   * indicating that ANSI {@code OUTER JOIN} syntax should be used,
   * since all modern versions of Informix support it.
   *
   * @return {@code false} when invoked
   *
   * @see <a
   * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=401393">EclipseLink
   * bug 401393</a>
   */
  @Override
  public boolean isInformixOuterJoin() {
    return false;
  }

  /**
   * Fixes <a
   * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=401746">EclipseLink
   * bug 401746</a> by writing out either {@code 't'} or {@code
   * 'f'}&mdash;with single quotes&mdash; instead of {@code 1} or
   * {@code 0}.
   *
   * @param booleanValue a non-{@code null} {@link Boolean} to append
   *
   * @param writer a non-{@code null} {@link Writer} to append the
   * literal value to
   *
   * @exception IllegalArgumentException if either {@code
   * booleanValue} or {@code writer} is {@code null}
   *
   * @exception IOException if the supplied {@link Writer} throws an
   * {@link IOException}
   *
   * @see <a
   * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=401393">EclipseLink
   * bug 401393</a>
   */
  @Override
  protected void appendBoolean(final Boolean booleanValue, final Writer writer) throws IOException {
    if (booleanValue == null) {
      throw new IllegalArgumentException("booleanValue", new NullPointerException("booleanValue"));
    }
    if (writer == null) {
      throw new IllegalArgumentException("writer", new NullPointerException("writer"));
    }
    if (Boolean.TRUE.equals(booleanValue)) {
      writer.write("'t'");
    } else {
      writer.write("'f'");
    }
  }

  /**
   * Returns {@code true} when invoked to indicate that parameter
   * binding <em>must not</em> be used when working with temporary
   * tables as part of an {@code UPDATE} query.
   *
   * <p>Parsing the English is a little difficult in this method name.
   * It means: "Do not bind parameters in queries that are part of an
   * overall 'update all' operation where {@linkplain
   * #shouldAlwaysUseTempStorageForModifyAll() temporary tables are
   * being used}."</p>
   *
   * @return {@code true} when invoked
   *
   * @see <a
   * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=402037">EclipseLink
   * bug 402037</a>
   */
  @Override
  public boolean dontBindUpdateAllQueryUsingTempTables() {
    return true;
  }

  /**
   * Returns {@code true} when invoked to force Informix to use
   * temporary storage when constructing bulk {@code UPDATE}
   * statements.
   *
   * @return {@code true} in all cases
   *
   * @see <a
   * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=402037">EclipseLink
   * bug 402037</a>
   */
  @Override
  public boolean shouldAlwaysUseTempStorageForModifyAll() {
    return true;
  }

  /**
   * Returns {@code true} when invoked to indicate that Informix does
   * indeed support <em>local temporary tables</em>.
   *
   * <p><em>local</em> is defined by EclipseLink in {@link
   * org.eclipse.persistence.internal.databaseaccess.DatabasePlatform}
   * to mean:</p>
   *
   * <blockquote>"Local" means that several threads may create
   * temporary tables with the same name.
   * Local temporary table is created in the beginning of {@link UpdateAllQuery}
   * execution and dropped in the end of it.</blockquote>
   *
   * @return {@code true} when invoked
   *
   * @see <a
   * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=402037">EclipseLink
   * bug 402037</a>
   */
  @Override
  public boolean supportsLocalTempTables() {
    return true;
  }

  /**
   * Returns {@code CREATE TEMP TABLE} when invoked, per
   * the <a
   * href="http://publib.boulder.ibm.com/infocenter/idshelp/v117/topic/com.ibm.sqls.doc/ids_sqs_0571.htm">Informix
   * 11.70 Information Center documentation</a>.
   *
   * <p>While Informix 11.70 supports an additional {@code IF NOT
   * EXISTS} clause, Informix 11.50 does not, so this method does not
   * add the {@code IF NOT EXISTS} clause.  In practice this should be
   * fine as temporary tables are scoped to the Informix session, and
   * EclipseLink takes care of cleaning up any temporary tables that
   * it creates.</p>
   *
   * @return {@code CREATE TEMP TABLE} when invoked
   *
   * @see <a
   * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=402037">EclipseLink
   * bug 402037</a>
   */
  @Override
  protected String getCreateTempTableSqlPrefix() {
    return "CREATE TEMP TABLE ";
  }

  /**
   * Overrides the superclass implementation to return a new {@link
   * DatabaseTable} with no {@linkplain
   * DatabaseTable#getTableQualifier()}.  Informix 11.50 and above do
   * not support table qualifiers of any kind on temporary tables.
   *
   * @param table the {@link DatabaseTable} for which a temporary
   * {@link DatabaseTable} should be returned; must not be {@code
   * null}
   *
   * @return a new {@link DatabaseTable} with no {@linkplain
   * DatabaseTable#getTableQualifier() table qualifier}
   *
   * @exception IllegalArgumentException if {@code table} is {@code
   * null}
   *
   * @see <a
   * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=402037">EclipseLink
   * bug 402037</a>
   *
   * @see <a
   * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=402180">EclipseLink
   * bug 402180</a>
   */
  @Override
  public DatabaseTable getTempTableForTable(final DatabaseTable table) {
    if (table == null) {
      throw new IllegalArgumentException("table", new NullPointerException("table"));
    }
    return new DatabaseTable("TL_" + table.getName(), "" /* no table qualifier */, table.shouldUseDelimiters(), this.getStartDelimiter(), this.getEndDelimiter());
  }
  
  /**
   * Returns {@code WITH NO LOG} when invoked, per the <a
   * href="http://publib.boulder.ibm.com/infocenter/idshelp/v117/topic/com.ibm.sqls.doc/ids_sqs_0571.htm">Informix
   * 11.70 Information Center documentation</a>, since transactions
   * are not needed on temp tables for the purposes for which
   * EclipseLink uses them.
   *
   * @return {@code WITH NO LOG} when invoked
   *
   * @see <a
   * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=402037">EclipseLink
   * bug 402037</a>
   */
  @Override
  protected String getCreateTempTableSqlSuffix() {
    return " WITH NO LOG";
  }

  /**
   * Overrides {@link
   * org.eclipse.persistence.internal.databaseaccess.DatabasePlatform#writeUpdateOriginalFromTempTableSql(Writer,
   * DatabaseTable, Collection, Collection)} to ensure that a {@code
   * SET} clause that is supposed to set a value for only one column
   * does not wrap that column name in parentheses.
   *
   * <p>The code for this method is identical to that of the stock
   * {@link H2Platform}, since the H2 database has the same
   * requirement.</p>
   *
   * @param writer the {@link Writer} that will be writing SQL; must
   * not be {@code null}
   *
   * @param table the {@link DatabaseTable} to be updated; must not be
   * {@code null}
   *
   * @param pkFields a {@link Collection} of {@link DatabaseField}s
   * each of which is a primary key of the table to be updated; must
   * not be {@code null}
   *
   * @param assignedFields a {@link Collection} of {@link
   * DatabaseField}s that are receiving updated values; must not be
   * {@code null}
   *
   * @exception IOException if an input/output error is thrown by the
   * supplied {@link Writer}
   *
   * @exception NullPointerException if any of the supplied parameters
   * is {@code null}
   *
   * @see <a
   * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=402037">EclipseLink
   * bug 402037</a>
   */
  @Override
  public void writeUpdateOriginalFromTempTableSql(final Writer writer, final DatabaseTable table, final Collection pkFields, final Collection assignedFields) throws IOException {
    writer.write("UPDATE ");
    final String tableName = table.getQualifiedNameDelimited(this);    
    writer.write(tableName);
    writer.write(" SET ");
    final int size = assignedFields.size();
    if (size > 1) {
      writer.write("(");            
    }
    writeFieldsList(writer, assignedFields, this);
    if (size > 1) {
      writer.write(")");            
    }
    writer.write(" = (SELECT ");        
    writeFieldsList(writer, assignedFields, this);
    writer.write(" FROM ");
    final String tempTableName = this.getTempTableForTable(table).getQualifiedNameDelimited(this);
    writer.write(tempTableName);
    writeAutoJoinWhereClause(writer, null, tableName, pkFields, this);
    writer.write(") WHERE EXISTS(SELECT ");
    writer.write(((DatabaseField)pkFields.iterator().next()).getNameDelimited(this));
    writer.write(" FROM ");
    writer.write(tempTableName);
    writeAutoJoinWhereClause(writer, null, tableName, pkFields, this);
    writer.write(")");
  }

  /**
   * Overrides {@link
   * org.eclipse.persistence.internal.databaseaccess.DatabasePlatform#getObjectFromResultSet(ResultSet,
   * int, int, AbstractSession)} so that if the supplied {@code
   * jdbcType} is equal to {@link Types#LONGVARCHAR}, then the {@link
   * ResultSet#getString(int)} method (instead of the {@link
   * ResultSet#getObject(int)} method) is used to fetch the "raw"
   * value of the column indicated by the supplied {@code
   * columnNumber} from the supplied {@link ResultSet}.
   *
   * <p>This works around an issue with the Informix JDBC driver,
   * version 3.70.JC7 and earlier, where a {@code TEXT} column is
   * reported to be mappable to the JDBC type of {@link
   * Types#LONGVARCHAR LONGVARCHAR}, but the actual object returned by
   * {@link ResultSet#getObject(int)} is a {@code byte[]} (instead of
   * either a {@code char[]} or a {@link String}).  Invoking {@link
   * ResultSet#getString(int)} instead returns the desired result.</p>
   *
   * @param resultSet the {@link ResultSet} to {@linkplain
   * ResultSet#getObject(int) get an <code>Object</code>} from; may be
   * {@code null}
   *
   * @param columnNumber the {@code 1}-based column number indicating
   * the column to use
   *
   * @param jdbcType an {@code int} indicating the {@linkplain Types
   * JDBC type} of which the column in the {@link ResultSet} indicated
   * by the supplied {@code columnNumber} is expected to be
   *
   * @param session an {@link AbstractSession} that, when used at all,
   * is passed to the superclass implementation of this method; may be
   * {@code null}
   *
   * @return the {@link Object} resulting from a call to {@link
   * ResultSet#getObject(int)}; may be {@code null}
   *
   * @exception SQLException if any error occurs
   *
   * @see <a
   * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=405645">EclipseLink
   * bug 405645</a>
   */
  @Override
  public Object getObjectFromResultSet(final ResultSet resultSet, final int columnNumber, final int jdbcType, final AbstractSession session) throws SQLException {
    Object returnValue = null;
    switch (jdbcType) {
    case Types.LONGVARCHAR:
      if (resultSet != null) {
        returnValue = resultSet.getString(columnNumber);
      } else {
        returnValue = super.getObjectFromResultSet(resultSet, columnNumber, jdbcType, session);
      }
      break;
    default:
      returnValue = super.getObjectFromResultSet(resultSet, columnNumber, jdbcType, session);
    }
    return returnValue;
  }

}