| /* |
| * Copyright (c) 2014, 2020 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 v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // Oracle - initial API and implementation from Oracle TopLink |
| // 09/29/2016-2.7 Tomas Kraus |
| // - 426852: @GeneratedValue(strategy=GenerationType.IDENTITY) support in Oracle 12c |
| package org.eclipse.persistence.platform.database.oracle; |
| |
| import java.io.IOException; |
| import java.io.Writer; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.ConcurrentHashMap; |
| |
| import org.eclipse.persistence.descriptors.ClassDescriptor; |
| import org.eclipse.persistence.exceptions.ValidationException; |
| import org.eclipse.persistence.internal.sessions.AbstractSession; |
| import org.eclipse.persistence.internal.sessions.EmptyRecord; |
| import org.eclipse.persistence.logging.SessionLog; |
| import org.eclipse.persistence.queries.ValueReadQuery; |
| import org.eclipse.persistence.sequencing.NativeSequence; |
| import org.eclipse.persistence.sequencing.Sequence; |
| import org.eclipse.persistence.sessions.Session; |
| |
| /** |
| * <p><b>Purpose:</b> |
| * Supports usage of certain Oracle JDBC specific APIs for the Oracle 12 database.<br> |
| * Identity column:<br> |
| * {@code GENERATED [ ALWAYS | BY DEFAULT [ ON NULL ] ] AS IDENTITY [ ( identity_options ) ]} |
| */ |
| public class Oracle12Platform extends Oracle11Platform { |
| |
| /** Table name to identity sequence name storage. */ |
| private final Map<String, String> identitySequences; |
| |
| public Oracle12Platform() { |
| super(); |
| supportsIdentity = true; |
| identitySequences = new ConcurrentHashMap<>(); |
| } |
| |
| /** |
| * INTERNAL: |
| * Check whether current platform is Oracle 12c or later. |
| * @return Always returns {@code true} for instances of Oracle 12c platform. |
| * @since 2.7 |
| */ |
| @Override |
| public boolean isOracle12() { |
| return true; |
| } |
| |
| /** |
| * INTERNAL: |
| * Initialize platform specific identity sequences. |
| * @param session Active database session (in connected state). |
| * @param defaultIdentityGenerator Default identity generator sequence name. |
| * @since 2.7 |
| */ |
| @Override |
| public void initIdentitySequences(final Session session, final String defaultIdentityGenerator) { |
| if (sequences != null && sequences.containsKey(defaultIdentityGenerator)) { |
| for (final ClassDescriptor descriptor : session.getDescriptors().values()) { |
| final Sequence sequence = descriptor.getSequence(); |
| if (sequence != null && defaultIdentityGenerator.equals(sequence.getName())) { |
| final String tableName = descriptor.getTableName(); |
| final String seqName = getIdentitySequence(tableName, session); |
| if (seqName != null) { |
| final NativeSequence newSequence = new NativeSequence(seqName, 1, true); |
| newSequence.setShouldAcquireValueAfterInsert(true); |
| newSequence.onConnect(this); |
| descriptor.setSequence(newSequence); |
| descriptor.setSequenceNumberName(seqName); |
| identitySequences.put(tableName, seqName); |
| addSequence(newSequence); |
| if (session.getSessionLog().shouldLog(SessionLog.FINE)) { |
| session.getSessionLog().log(SessionLog.FINE, "platform_ora_init_id_seq", |
| new Object[] {defaultIdentityGenerator, seqName, tableName}); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Remove platform specific identity sequence for specified table. Default identity sequence is restored. |
| * @param session Active database session (in connected state). |
| * @param defaultIdentityGenerator Default identity generator sequence name. |
| * @param tableNames Set of table names to check for identity sequence removal. |
| * @since 2.7 |
| */ |
| @Override |
| public void removeIdentitySequences(final Session session, final String defaultIdentityGenerator, final Set<String> tableNames) { |
| if (sequences != null && sequences.containsKey(defaultIdentityGenerator)) { |
| final Sequence defaultSeq = getSequence(defaultIdentityGenerator); |
| for (final ClassDescriptor descriptor : session.getDescriptors().values()) { |
| final String tableName = descriptor.getTableName(); |
| if (tableName != null && identitySequences.containsKey(tableName)) { |
| final String seqName = identitySequences.remove(tableName); |
| removeSequence(seqName); |
| descriptor.setSequence(defaultSeq); |
| descriptor.setSequenceNumberName(defaultIdentityGenerator); |
| if (session.getSessionLog().shouldLog(SessionLog.FINE)) { |
| session.getSessionLog().log(SessionLog.FINE, "platform_ora_remove_id_seq", |
| new Object[] {seqName, defaultIdentityGenerator, tableName}); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Get sequence name corresponding to the table name. |
| * @param tableName Name of the table. |
| * @param session Active data source session. |
| * @return Sequence name corresponding to the table name or {@code null} if no such sequence exists. |
| * @since 2.7 |
| */ |
| private String getIdentitySequence(final String tableName, final Session session) { |
| // TABLE_NAME values are converted to upper case by default. |
| // Also TableDefinition.buildCreationWriter(AbstractSession,Writer) does not have support for quoting table names |
| // to make them case sensitive on Oracle DB. |
| final String sql = "SELECT SEQUENCE_NAME FROM USER_TAB_IDENTITY_COLS WHERE TABLE_NAME='" + tableName.toUpperCase() + "'"; |
| return (String)(new ValueReadQuery(sql)).execute((AbstractSession)session, EmptyRecord.getEmptyRecord()); |
| } |
| |
| /** |
| * INTERNAL: |
| * Append the receiver's field 'identity' constraint clause to a writer. |
| * @param writer Target writer. |
| * @since 2.7 |
| */ |
| @Override |
| public void printFieldIdentityClause(final Writer writer) throws ValidationException { |
| try { |
| writer.write(" GENERATED AS IDENTITY"); |
| } catch (IOException ioException) { |
| throw ValidationException.fileError(ioException); |
| } |
| } |
| |
| } |