123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- /*
- Copyright (c) 2013 James Ahlborn
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA
- */
-
- package com.healthmarketscience.jackcess.impl;
-
- import java.io.IOException;
- import java.nio.ByteBuffer;
- import java.util.EnumSet;
- import java.util.List;
- import java.util.Set;
-
- import com.healthmarketscience.jackcess.Column;
- import com.healthmarketscience.jackcess.CursorBuilder;
- import com.healthmarketscience.jackcess.DataType;
- import com.healthmarketscience.jackcess.IndexCursor;
- import com.healthmarketscience.jackcess.Row;
- import com.healthmarketscience.jackcess.Table;
- import com.healthmarketscience.jackcess.complex.ComplexColumnInfo;
- import com.healthmarketscience.jackcess.complex.ComplexValue;
- import com.healthmarketscience.jackcess.impl.complex.AttachmentColumnInfoImpl;
- import com.healthmarketscience.jackcess.impl.complex.MultiValueColumnInfoImpl;
- import com.healthmarketscience.jackcess.impl.complex.UnsupportedColumnInfoImpl;
- import com.healthmarketscience.jackcess.impl.complex.VersionHistoryColumnInfoImpl;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
-
-
- /**
- * Utility code for loading complex columns.
- *
- * @author James Ahlborn
- */
- public class ComplexColumnSupport
- {
- private static final Log LOG = LogFactory.getLog(ComplexColumnSupport.class);
-
- private static final String COL_COMPLEX_TYPE_OBJECT_ID = "ComplexTypeObjectID";
- private static final String COL_TABLE_ID = "ConceptualTableID";
- private static final String COL_FLAT_TABLE_ID = "FlatTableID";
-
- private static final Set<DataType> MULTI_VALUE_TYPES = EnumSet.of(
- DataType.BYTE, DataType.INT, DataType.LONG, DataType.FLOAT,
- DataType.DOUBLE, DataType.GUID, DataType.NUMERIC, DataType.TEXT);
-
-
- /**
- * Creates a ComplexColumnInfo for a complex column.
- */
- public static ComplexColumnInfo<? extends ComplexValue> create(
- ColumnImpl column, ByteBuffer buffer, int offset)
- throws IOException
- {
- int complexTypeId = buffer.getInt(
- offset + column.getFormat().OFFSET_COLUMN_COMPLEX_ID);
-
- DatabaseImpl db = column.getDatabase();
- TableImpl complexColumns = db.getSystemComplexColumns();
- IndexCursor cursor = CursorBuilder.createCursor(
- complexColumns.getPrimaryKeyIndex());
- if(!cursor.findFirstRowByEntry(complexTypeId)) {
- throw new IOException(
- "Could not find complex column info for complex column with id " +
- complexTypeId);
- }
- Row cColRow = cursor.getCurrentRow();
- int tableId = (Integer)cColRow.get(COL_TABLE_ID);
- if(tableId != column.getTable().getTableDefPageNumber()) {
- throw new IOException(
- "Found complex column for table " + tableId + " but expected table " +
- column.getTable().getTableDefPageNumber());
- }
- int flatTableId = (Integer)cColRow.get(COL_FLAT_TABLE_ID);
- int typeObjId = (Integer)cColRow.get(COL_COMPLEX_TYPE_OBJECT_ID);
-
- TableImpl typeObjTable = db.getTable(typeObjId);
- TableImpl flatTable = db.getTable(flatTableId);
-
- if((typeObjTable == null) || (flatTable == null)) {
- throw new IOException(
- "Could not find supporting tables (" + typeObjId + ", " + flatTableId
- + ") for complex column with id " + complexTypeId);
- }
-
- // we inspect the structore of the "type table" to determine what kind of
- // complex info we are dealing with
- if(isMultiValueColumn(typeObjTable)) {
- return new MultiValueColumnInfoImpl(column, complexTypeId, typeObjTable,
- flatTable);
- } else if(isAttachmentColumn(typeObjTable)) {
- return new AttachmentColumnInfoImpl(column, complexTypeId, typeObjTable,
- flatTable);
- } else if(isVersionHistoryColumn(typeObjTable)) {
- return new VersionHistoryColumnInfoImpl(column, complexTypeId, typeObjTable,
- flatTable);
- }
-
- LOG.warn("Unsupported complex column type " + typeObjTable.getName());
- return new UnsupportedColumnInfoImpl(column, complexTypeId, typeObjTable,
- flatTable);
- }
-
-
- public static boolean isMultiValueColumn(Table typeObjTable) {
- // if we found a single value of a "simple" type, then we are dealing with
- // a multi-value column
- List<? extends Column> typeCols = typeObjTable.getColumns();
- return ((typeCols.size() == 1) &&
- MULTI_VALUE_TYPES.contains(typeCols.get(0).getType()));
- }
-
- public static boolean isAttachmentColumn(Table typeObjTable) {
- // attachment data has these columns FileURL(MEMO), FileName(TEXT),
- // FileType(TEXT), FileData(OLE), FileTimeStamp(SHORT_DATE_TIME),
- // FileFlags(LONG)
- List<? extends Column> typeCols = typeObjTable.getColumns();
- if(typeCols.size() < 6) {
- return false;
- }
-
- int numMemo = 0;
- int numText = 0;
- int numDate = 0;
- int numOle= 0;
- int numLong = 0;
-
- for(Column col : typeCols) {
- switch(col.getType()) {
- case TEXT:
- ++numText;
- break;
- case LONG:
- ++numLong;
- break;
- case SHORT_DATE_TIME:
- ++numDate;
- break;
- case OLE:
- ++numOle;
- break;
- case MEMO:
- ++numMemo;
- break;
- default:
- // ignore
- }
- }
-
- // be flexible, allow for extra columns...
- return((numMemo >= 1) && (numText >= 2) && (numOle >= 1) &&
- (numDate >= 1) && (numLong >= 1));
- }
-
- public static boolean isVersionHistoryColumn(Table typeObjTable) {
- // version history data has these columns <value>(MEMO),
- // <modified>(SHORT_DATE_TIME)
- List<? extends Column> typeCols = typeObjTable.getColumns();
- if(typeCols.size() < 2) {
- return false;
- }
-
- int numMemo = 0;
- int numDate = 0;
-
- for(Column col : typeCols) {
- switch(col.getType()) {
- case SHORT_DATE_TIME:
- ++numDate;
- break;
- case MEMO:
- ++numMemo;
- break;
- default:
- // ignore
- }
- }
-
- // be flexible, allow for extra columns...
- return((numMemo >= 1) && (numDate >= 1));
- }
- }
|