blob: 5965eb093c396c8e1bbbab55bab6104d0954d039 [file] [log] [blame]
/*
* Copyright (c) 1998, 2021 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
package org.eclipse.persistence.internal.sessions;
import java.io.StringWriter;
import java.util.*;
import org.eclipse.persistence.internal.helper.*;
import org.eclipse.persistence.sessions.DatabaseRecord;
/**
* PERF: Optimized record implementation using arrays instead of Vector.
* Currently only used when fetch rows from the database.
*/
public class ArrayRecord extends DatabaseRecord {
protected DatabaseField[] fieldsArray;
protected Object[] valuesArray;
protected ArrayRecord() {
super();
}
public ArrayRecord(Vector fields, DatabaseField[] fieldsArray, Object[] valuesArray) {
super(fields, null, fieldsArray.length);
this.fieldsArray = fieldsArray;
this.valuesArray = valuesArray;
}
/**
* Reset the fields and values from the arrays.
* This removes the optimization if a non-optimized method is called.
*/
protected void checkValues() {
if (this.values == null) {
this.values = new NonSynchronizedVector(this.valuesArray.length);
for (Object value : this.valuesArray) {
this.values.add(value);
}
}
}
/**
* INTERNAL:
* Add the field-value pair to the row. Will not check,
* will simply add to the end of the row
*/
@Override
public void add(DatabaseField key, Object value) {
checkValues();
this.fieldsArray = null;
this.valuesArray = null;
super.add(key, value);
}
/**
* PUBLIC:
* Clear the contents of the row.
*/
@Override
public void clear() {
this.fieldsArray = null;
this.valuesArray = null;
super.clear();
}
/**
* INTERNAL:
* Clone the row and its values.
*/
@Override
public AbstractRecord clone() {
checkValues();
return super.clone();
}
/**
* INTERNAL:
* Check if the field is contained in the row.
*/
@Override
public boolean containsKey(DatabaseField key) {
if (this.fieldsArray != null) {
// Optimize check.
int index = key.index;
if ((index >= 0) && (index < this.size)) {
DatabaseField field = this.fieldsArray[index];
if ((field == key) || field.equals(key)) {
return true;
}
}
for (DatabaseField field : this.fieldsArray) {
if ((field == key) || field.equals(key)) {
return true;
}
}
return false;
} else {
return super.containsKey(key);
}
}
/**
* PUBLIC:
* Check if the value is contained in the row.
*/
@Override
public boolean containsValue(Object value) {
if (this.valuesArray != null) {
for (Object rowValue : this.valuesArray) {
if ((value == rowValue) || rowValue.equals(value)) {
return true;
}
}
return false;
} else {
return super.containsValue(value);
}
}
/**
* INTERNAL:
* Retrieve the value for the field. If missing null is returned.
*/
@Override
public Object get(DatabaseField key) {
if (this.fieldsArray != null) {
// Optimize check.
int index = key.index;
if ((index >= 0) && (index < this.size)) {
DatabaseField field = this.fieldsArray[index];
if ((field == key) || field.equals(key)) {
return this.valuesArray[index];
}
}
for (int fieldIndex = 0; fieldIndex < this.size; fieldIndex++) {
DatabaseField field = this.fieldsArray[fieldIndex];
if ((field == key) || field.equals(key)) {
// PERF: If the fields index was not set, then set it.
if (index == -1) {
key.setIndex(fieldIndex);
}
return this.valuesArray[fieldIndex];
}
}
return null;
} else {
return super.get(key);
}
}
/**
* INTERNAL:
* Retrieve the value for the field. If missing DatabaseRow.noEntry is returned.
*/
@Override
public Object getIndicatingNoEntry(DatabaseField key) {
if (this.fieldsArray != null) {
// Optimize check.
int index = key.index;
if ((index >= 0) && (index < this.size)) {
DatabaseField field = this.fieldsArray[index];
if ((field == key) || field.equals(key)) {
return this.valuesArray[index];
}
}
for (int fieldIndex = 0; fieldIndex < this.size; fieldIndex++) {
DatabaseField field = this.fieldsArray[fieldIndex];
if ((field == key) || field.equals(key)) {
// PERF: If the fields index was not set, then set it.
if (index == -1) {
key.setIndex(fieldIndex);
}
return this.valuesArray[fieldIndex];
}
}
return AbstractRecord.noEntry;
} else {
return super.get(key);
}
}
/**
* INTERNAL:
* Returns the row's field with the same name.
*/
@Override
public DatabaseField getField(DatabaseField key) {
if (this.fieldsArray != null) {
// Optimize check.
int index = key.index;
if ((index >= 0) && (index < this.size)) {
DatabaseField field = this.fieldsArray[index];
if ((field == key) || field.equals(key)) {
return field;
}
}
for (int fieldIndex = 0; fieldIndex < this.size; fieldIndex++) {
DatabaseField field = this.fieldsArray[fieldIndex];
if ((field == key) || field.equals(key)) {
return field;
}
}
return null;
} else {
return super.getField(key);
}
}
/**
* INTERNAL:
*/
@Override
public Vector getFields() {
checkValues();
return super.getFields();
}
/**
* INTERNAL:
*/
@Override
public Vector getValues() {
checkValues();
return super.getValues();
}
/**
* INTERNAL:
* Add the field-value pair to the row.
*/
@Override
public Object put(DatabaseField key, Object value) {
checkValues();
this.fieldsArray = null;
this.valuesArray = null;
return super.put(key, value);
}
/**
* INTERNAL:
* Remove the field key from the row.
*/
@Override
public Object remove(DatabaseField key) {
checkValues();
this.fieldsArray = null;
this.valuesArray = null;
return super.remove(key);
}
/**
* INTERNAL:
* replaces the value at index with value
*/
@Override
public void replaceAt(Object value, int index) {
if (this.valuesArray != null) {
this.valuesArray[index] = value;
} else {
super.replaceAt(value, index);
}
}
/**
* INTERNAL:
* replaces the value at field with value
*/
@Override
public void replaceAt(Object value, DatabaseField key) {
if (this.fieldsArray != null) {
// Optimize check.
int index = key.index;
if ((index >= 0) && (index < this.size)) {
DatabaseField field = this.fieldsArray[index];
if ((field == key) || field.equals(key)) {
this.valuesArray[index] = value;
return;
}
}
for (int fieldIndex = 0; fieldIndex < this.size; fieldIndex++) {
DatabaseField field = this.fieldsArray[fieldIndex];
if ((field == key) || field.equals(key)) {
// PERF: If the fields index was not set, then set it.
if (index == -1) {
key.setIndex(fieldIndex);
}
this.valuesArray[fieldIndex] = value;
return;
}
}
} else {
super.replaceAt(value, key);
}
}
@Override
protected void setFields(Vector fields) {
checkValues();
this.fieldsArray = null;
this.valuesArray = null;
super.setFields(fields);
}
@Override
protected void setValues(Vector values) {
checkValues();
this.fieldsArray = null;
this.valuesArray = null;
super.setValues(values);
}
/**
* PUBLIC:
* Return the number of field/value pairs in the row.
*/
@Override
public int size() {
if (this.fieldsArray == null) {
return this.fields.size();
} else {
return this.fieldsArray.length;
}
}
@Override
public String toString() {
if (this.valuesArray != null) {
StringWriter writer = new StringWriter();
writer.write(Helper.getShortClassName(getClass()));
writer.write("(");
writer.write(toStringAditional());
for (int index = 0; index < this.fieldsArray.length; index++) {
writer.write(Helper.cr());
writer.write("\t");
writer.write(String.valueOf(this.fieldsArray[index]));
writer.write(" => ");
writer.write(String.valueOf(this.valuesArray[index]));
}
if (this.sopObject != null) {
writer.write(Helper.cr());
writer.write(" sopObject = ");
writer.write(this.sopObject.toString());
}
writer.write(")");
return writer.toString();
} else {
return super.toString();
}
}
protected String toStringAditional() {
return "";
}
}