--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.store.access.conglomerate.ConglomerateUtil\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.store.access.conglomerate;\r
+\r
+import org.apache.derby.iapi.reference.Property;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.services.io.CompressedNumber;\r
+import org.apache.derby.iapi.services.io.Formatable;\r
+import org.apache.derby.iapi.services.io.FormatIdUtil;\r
+\r
+import org.apache.derby.iapi.store.access.ColumnOrdering;\r
+import org.apache.derby.iapi.store.access.RowUtil;\r
+\r
+import org.apache.derby.iapi.store.raw.FetchDescriptor;\r
+import org.apache.derby.iapi.store.raw.Page;\r
+import org.apache.derby.iapi.store.raw.RawStoreFactory;\r
+import org.apache.derby.iapi.store.raw.RecordHandle;\r
+\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+import org.apache.derby.iapi.types.StringDataValue;\r
+\r
+import java.io.IOException; \r
+import java.io.ObjectInput;\r
+import java.io.ObjectOutput;\r
+\r
+import java.util.Properties;\r
+\r
+/**\r
+ * Static utility routine package for all Conglomerates.\r
+ * <p>\r
+ * A collection of static utility routines that are shared by multiple\r
+ * Conglomerate implementations.\r
+ * <p>\r
+ **/\r
+public final class ConglomerateUtil\r
+{\r
+\r
+ /* Public Methods of This class: (arranged Alphabetically ) */\r
+\r
+ /**\r
+ * Create a list of all the properties that Access wants to export\r
+ * through the getInternalTablePropertySet() call.\r
+ * <p>\r
+ * This utility routine creates a list of properties that are shared by\r
+ * all conglomerates. This list contains the following:\r
+ *\r
+ * derby.storage.initialPages\r
+ * derby.storage.minimumRecordSize\r
+ * derby.storage.pageReservedSpace\r
+ * derby.storage.pageSize \r
+ * derby.storage.reusableRecordId\r
+ * \r
+ * <p>\r
+ *\r
+ * @return The Property set filled in.\r
+ *\r
+ * @param prop If non-null the property set to fill in.\r
+ **/\r
+ public static Properties createRawStorePropertySet(\r
+ Properties prop)\r
+ {\r
+ prop = createUserRawStorePropertySet(prop);\r
+\r
+ prop.put(RawStoreFactory.PAGE_REUSABLE_RECORD_ID, "");\r
+\r
+ return(prop);\r
+ }\r
+\r
+ /**\r
+ * Create a list of all the properties that Access wants to export\r
+ * through the getInternalTablePropertySet() call.\r
+ * <p>\r
+ * This utility routine creates a list of properties that are shared by\r
+ * all conglomerates. This list contains the following:\r
+ *\r
+ * derby.storage.initialPages\r
+ * derby.storage.minimumRecordSize\r
+ * derby.storage.pageReservedSpace\r
+ * derby.storage.pageSize \r
+ * \r
+ * <p>\r
+ *\r
+ * @return The Property set filled in.\r
+ *\r
+ * @param prop If non-null the property set to fill in.\r
+ **/\r
+ public static Properties createUserRawStorePropertySet(\r
+ Properties prop)\r
+ {\r
+ if (prop == null)\r
+ prop = new Properties();\r
+\r
+ prop.put(Property.PAGE_SIZE_PARAMETER, "");\r
+ prop.put(RawStoreFactory.MINIMUM_RECORD_SIZE_PARAMETER, "");\r
+ prop.put(RawStoreFactory.PAGE_RESERVED_SPACE_PARAMETER, "");\r
+ prop.put(RawStoreFactory.CONTAINER_INITIAL_PAGES, "");\r
+\r
+ return(prop);\r
+ }\r
+\r
+\r
+ /**\r
+ * Given an array of objects, return an array of format id's.\r
+ * <p>\r
+ *\r
+ * @return An array of format id's describing the input array of objects.\r
+ *\r
+ * @param template a row.\r
+ *\r
+ **/\r
+ public static int[] createFormatIds(\r
+ DataValueDescriptor[] template)\r
+ {\r
+\r
+ // get format id's from each column in template\r
+ // conglomerate state.\r
+\r
+ int[] format_ids = new int[template.length];\r
+\r
+ for (int i = 0; i < template.length; i++)\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ if (template[i] == null)\r
+ {\r
+ SanityManager.THROWASSERT("row template is null for "+\r
+ "column["+i+"].");\r
+ }\r
+ if (!(template[i] instanceof Formatable))\r
+ {\r
+ SanityManager.THROWASSERT("row template is not formatable "+\r
+ "column["+i+"]. Type is "+template[i].getClass().getName());\r
+ }\r
+ }\r
+\r
+ format_ids[i] = ((Formatable) template[i]).getTypeFormatId();\r
+ }\r
+\r
+ return(format_ids);\r
+ }\r
+\r
+ /**\r
+ * Read a format id array in from a stream.\r
+ * <p>\r
+ *\r
+ * @return A new array of format id's.\r
+ *\r
+ * @param num The number of format ids to read.\r
+ * @param in The stream to read the array of format id's from.\r
+ *\r
+ * @exception IOException Thown on read error.\r
+ **/\r
+ public static int[] readFormatIdArray(\r
+ int num,\r
+ ObjectInput in)\r
+ throws IOException\r
+ {\r
+ // read in the array of format id's\r
+\r
+ int[] format_ids = new int[num];\r
+ for (int i = 0; i < num; i++)\r
+ {\r
+ format_ids[i] = FormatIdUtil.readFormatIdInteger(in);\r
+ }\r
+\r
+ return(format_ids);\r
+ }\r
+\r
+ /**\r
+ * Write a format id array to a stream.\r
+ * <p>\r
+ *\r
+ * @param format_id_array The array of format ids to write.\r
+ * @param out The stream to write the array of format id's to.\r
+ *\r
+ * @exception IOException Thown on write error.\r
+ **/\r
+ public static void writeFormatIdArray(\r
+ int[] format_id_array,\r
+ ObjectOutput out)\r
+ throws IOException\r
+ {\r
+ for (int i = 0; i < format_id_array.length; i++)\r
+ {\r
+ FormatIdUtil.writeFormatIdInteger(out, format_id_array[i]);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Given an array of columnOrderings, return an array of collation ids.\r
+ * <p>\r
+ * If input array is null, produce a default collation_id array of all\r
+ * StringDataValue.COLLATION_TYPE_UCS_BASIC values.\r
+ *\r
+ * @return An array of collation id's describing the input array of objects.\r
+ **/\r
+ public static int[] createCollationIds(\r
+ int sizeof_ids,\r
+ int[] collationIds)\r
+ {\r
+ int[] collation_ids = new int[sizeof_ids];\r
+ if (collationIds != null)\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ if (sizeof_ids != collationIds.length)\r
+ {\r
+ SanityManager.THROWASSERT(\r
+ "sizeof_ids = " + sizeof_ids +\r
+ ";collationIds.length = " + collationIds.length);\r
+ }\r
+ }\r
+ System.arraycopy(\r
+ collationIds, 0, collation_ids, 0, collationIds.length);\r
+ }\r
+ else\r
+ {\r
+ for (int i = 0; i < collation_ids.length; i++)\r
+ {\r
+ collation_ids[i] = StringDataValue.COLLATION_TYPE_UCS_BASIC;\r
+ }\r
+ }\r
+\r
+ return(collation_ids);\r
+ }\r
+\r
+ /**\r
+ * Write array of collation id's as a sparse array.\r
+ * <p>\r
+ * The format only writes out those array entries which are not \r
+ * StringDataValue.COLLATION_TYPE_UCS_BASIC. The sparse array\r
+ * first writes the number of entries as a compressed int. And\r
+ * then for each non-COLLATION_TYPE_UCS_BASIC, it writes out a\r
+ * pair of compressed ints:\r
+ *\r
+ * (array offset, array entry value)\r
+ *\r
+ * @param collation_id_array The array of collation ids to write.\r
+ * @param out The stream to write the collation id's to.\r
+ *\r
+ * @exception IOException Thown on write error.\r
+ **/\r
+ public static void writeCollationIdArray(\r
+ int[] collation_id_array, \r
+ ObjectOutput out)\r
+ throws IOException\r
+ {\r
+ // count non COLLATION_TYPE_UCS_BASIC values.\r
+ int non_collate_val_count = 0;\r
+ for (int i = 0; i < collation_id_array.length; i++)\r
+ {\r
+ if (collation_id_array[i] != \r
+ StringDataValue.COLLATION_TYPE_UCS_BASIC)\r
+ {\r
+ non_collate_val_count++;\r
+ }\r
+ }\r
+\r
+ // write number of sparse entries as compressed int\r
+ CompressedNumber.writeInt(out, non_collate_val_count);\r
+\r
+ for (int i = 0; i < collation_id_array.length; i++)\r
+ {\r
+ if (collation_id_array[i] != \r
+ StringDataValue.COLLATION_TYPE_UCS_BASIC)\r
+ {\r
+ // write array index as compressed number\r
+ CompressedNumber.writeInt(out, i);\r
+\r
+ // write array[i] value as compressed number\r
+ CompressedNumber.writeInt(out, collation_id_array[i]);\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Read "sparse" array of collation id's\r
+ * <p>\r
+ * The format to be read first has the number of entries as a compressed \r
+ * int. And then for each non-COLLATION_TYPE_UCS_BASIC value there is\r
+ * pair of compressed ints:\r
+ *\r
+ * (array offset, array entry value)\r
+ * <p>\r
+ * reads the sparse array as written by writeCollationIdArray().\r
+ *\r
+ * @param collation_id_array update's only those array entries that have\r
+ * been set in the sparse array stream.\r
+ * Those values are set as indicated by reading \r
+ * the sparse array from the stream.\r
+ * \r
+ * @param in The stream to read the collation info from.\r
+ *\r
+ **/\r
+ public static void readCollationIdArray(\r
+ int[] collation_id_array,\r
+ ObjectInput in)\r
+ throws IOException\r
+ {\r
+\r
+ // A sparse array is stored on disk, only \r
+ // non-COLLATION_TYPE_UCS_BASIC values are stored. \r
+ // These are stored as pairs of compressed ints:\r
+ // (array offset, array entry value)\r
+\r
+\r
+ // 1st on disk is number of entries stored as compressed a int\r
+ int num_compressed_entries = CompressedNumber.readInt(in);\r
+ for (int i = 0; i < num_compressed_entries; i++)\r
+ {\r
+ // values are stored in the stream as pairs: (index, value)\r
+ int array_index = CompressedNumber.readInt(in);\r
+ collation_id_array[array_index] = CompressedNumber.readInt(in);\r
+ }\r
+ }\r
+\r
+ /**\r
+ ** Format a page of data, as access see's it.\r
+ **/\r
+\r
+ public static String debugPage(\r
+ Page page,\r
+ int start_slot,\r
+ boolean full_rh,\r
+ DataValueDescriptor[] template)\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ StringBuffer string = new StringBuffer(4096);\r
+\r
+ string.append("PAGE:(");\r
+ string.append(page.getPageNumber());\r
+ string.append(")------------------------------------------:\n");\r
+\r
+ try\r
+ {\r
+ if (page != null)\r
+ {\r
+ int numrows = page.recordCount();\r
+\r
+ for (int slot_no = start_slot; slot_no < numrows; slot_no++)\r
+ {\r
+ RecordHandle rh = \r
+ page.fetchFromSlot(\r
+ (RecordHandle) null, slot_no, template, \r
+ (FetchDescriptor) null,\r
+ true);\r
+\r
+ // pre-pend either "D:" if deleted, or " :" if not.\r
+ string.append(\r
+ page.isDeletedAtSlot(slot_no) ? "D:" : " :");\r
+\r
+ // row[slot,id]:\r
+ string.append("row[");\r
+ string.append(slot_no);\r
+ string.append("](id:");\r
+ string.append(rh.getId());\r
+ string.append("):\t");\r
+\r
+ // long record handle: \r
+ // Record id=78 Page(31,Container(0, 919707766934))\r
+ if (full_rh)\r
+ {\r
+ string.append("[");\r
+ string.append(rh.toString());\r
+ string.append("]:");\r
+ }\r
+\r
+ // row:\r
+ string.append(RowUtil.toString(template));\r
+ string.append("\n");\r
+ }\r
+\r
+ // string.append(page.toString());\r
+ }\r
+ }\r
+ catch (Throwable t)\r
+ {\r
+ string.append("Error encountered while building string");\r
+ }\r
+\r
+ return(string.toString());\r
+ }\r
+ else\r
+ {\r
+ return(null);\r
+ }\r
+ }\r
+}\r