Quadcap Embeddable Database

com/quadcap/sql/TupleImpl.java

Go to the documentation of this file.
00001 package com.quadcap.sql; 00002 00003 /* Copyright 1999 - 2003 Quadcap Software. All rights reserved. 00004 * 00005 * This software is distributed under the Quadcap Free Software License. 00006 * This software may be used or modified for any purpose, personal or 00007 * commercial. Open Source redistributions are permitted. Commercial 00008 * redistribution of larger works derived from, or works which bundle 00009 * this software requires a "Commercial Redistribution License"; see 00010 * http://www.quadcap.com/purchase. 00011 * 00012 * Redistributions qualify as "Open Source" under one of the following terms: 00013 * 00014 * Redistributions are made at no charge beyond the reasonable cost of 00015 * materials and delivery. 00016 * 00017 * Redistributions are accompanied by a copy of the Source Code or by an 00018 * irrevocable offer to provide a copy of the Source Code for up to three 00019 * years at the cost of materials and delivery. Such redistributions 00020 * must allow further use, modification, and redistribution of the Source 00021 * Code under substantially the same terms as this license. 00022 * 00023 * Redistributions of source code must retain the copyright notices as they 00024 * appear in each source code file, these license terms, and the 00025 * disclaimer/limitation of liability set forth as paragraph 6 below. 00026 * 00027 * Redistributions in binary form must reproduce this Copyright Notice, 00028 * these license terms, and the disclaimer/limitation of liability set 00029 * forth as paragraph 6 below, in the documentation and/or other materials 00030 * provided with the distribution. 00031 * 00032 * The Software is provided on an "AS IS" basis. No warranty is 00033 * provided that the Software is free of defects, or fit for a 00034 * particular purpose. 00035 * 00036 * Limitation of Liability. Quadcap Software shall not be liable 00037 * for any damages suffered by the Licensee or any third party resulting 00038 * from use of the Software. 00039 */ 00040 00041 import java.io.Externalizable; 00042 import java.io.IOException; 00043 import java.io.ObjectInput; 00044 import java.io.ObjectOutput; 00045 00046 import java.util.HashMap; 00047 import java.util.Iterator; 00048 import java.util.Vector; 00049 00050 import java.sql.SQLException; 00051 00052 import com.quadcap.sql.types.Type; 00053 00054 import com.quadcap.util.Debug; 00055 00056 /** 00057 * Base class for tuple implementations. 00058 * 00059 * @author Stan Bailes 00060 */ 00061 public class TupleImpl implements Tuple, Externalizable { 00062 protected String qual; 00063 protected String qualifier; 00064 protected Vector columns = new Vector(); 00065 protected HashMap names = new HashMap(); 00066 00067 /** 00068 * Default constructor 00069 */ 00070 public TupleImpl() { 00071 this.qualifier = ""; 00072 this.qual = ""; 00073 } 00074 00075 /** 00076 * Named tuple constructor 00077 */ 00078 public TupleImpl(String qualifier) { 00079 setName(qualifier); 00080 } 00081 00082 /** 00083 * Set the tuple's name 00084 */ 00085 public void setName(String name) { 00086 if (name == null) name = ""; 00087 this.qualifier = name; 00088 if (qualifier.length() > 0) { 00089 this.qual = qualifier + "."; 00090 } else { 00091 this.qual = ""; 00092 } 00093 } 00094 00095 /** 00096 * Add, in order, the columns from the definition of tuple 't' to 00097 * the column list for this tuple. 00098 */ 00099 public void addColumns(Session session, Tuple t) throws SQLException { 00100 addColumns(session, t, true); 00101 } 00102 00103 /** 00104 * Add all the columns from the other tuple to this one. 00105 */ 00106 public void addColumns(Session session, Tuple t, boolean resolve) 00107 throws SQLException 00108 { 00109 Connection conn = session.getConnection(); 00110 boolean as = qual.length() > 0; 00111 for (int i = 1; i <= t.getColumnCount(); i++) { 00112 Column col = t.getColumn(i); 00113 String name = conn.resolveColname(col.getName(), this); 00114 //Debug.println("[" + getClass().getName() + "].addColumns " + i + ": " + 00115 // col.getName() + "/" + col.getShortName() + "/" + name); 00116 Column ncol = new Column(name, col); 00117 if (col.isJoinColumn()) ncol.setJoinColumn(true); 00118 addColumn(ncol); 00119 } 00120 if (resolve) resolveColumns(); 00121 } 00122 00123 /** 00124 * Once all of the column names are available, we can look for duplicates 00125 * and shortest-unique names, etc. 00126 */ 00127 public void resolveColumns() throws SQLException { 00128 for (int i = 1; i <= getColumnCount(); i++) { 00129 Column col = getColumn(i); 00130 String name = col.getName(); 00131 for (int j = name.length() - 1; j > 0; j--) { 00132 if (name.charAt(j) == '.') { 00133 String qname = name.substring(j+1); 00134 Object obj = names.get(qname); 00135 if (obj == col) { 00136 col.setShortName(qname); 00137 break; 00138 } 00139 } 00140 } 00141 } 00142 //Debug.println("resolveColumns: " + this); 00143 } 00144 00145 /** 00146 * addColumn helper 00147 */ 00148 private final void addName(String name, Column col) { 00149 if (names.get(name) != null) { 00150 names.put(name, "duplicate"); 00151 } else { 00152 names.put(name, col); 00153 } 00154 } 00155 00156 /** 00157 * Return the number of columns in this tuple 00158 */ 00159 public int getColumnCount() throws SQLException { 00160 return columns.size(); 00161 } 00162 00163 /** 00164 * Return the specified (one-based) column 00165 */ 00166 public Column getColumn(int i) throws SQLException { 00167 return (Column)columns.elementAt(i-1); 00168 } 00169 00170 /** 00171 * Return the column with the specified name/shortname 00172 */ 00173 public Column getColumn(String name) throws SQLException { 00174 Column c = null; 00175 Object obj = names.get(name); 00176 if (obj != null && obj instanceof Column) { 00177 c = (Column)obj; 00178 } 00179 return c; 00180 } 00181 00182 /** 00183 * Map the specified column names into an array of integer (one-based) 00184 * column indexes 00185 */ 00186 public int[] mapColumns(Vector names) throws SQLException { 00187 int[] ret; 00188 if (names == null) { 00189 ret = new int[columns.size()]; 00190 for (int i = 0; i < ret.length; i++) { 00191 ret[i] = i+1; 00192 } 00193 } else { 00194 ret = new int[names.size()]; 00195 for (int i = 0; i < ret.length; i++) { 00196 String name = (String)names.elementAt(i); 00197 ret[i] = getColumnIndex(name); 00198 if (ret[i] <= 0) { 00199 throw new SQLException("No such column: " + name, "42000"); 00200 } 00201 } 00202 } 00203 return ret; 00204 } 00205 00206 /** 00207 * Return the tuple's name 00208 */ 00209 public String getName() { return qualifier; } 00210 00211 /** 00212 * Find the first occurence of the '.' name separator in 00213 * the given SQL identifier string. 00214 */ 00215 static int nextUnquotedPeriod(String s) { 00216 boolean q = false; 00217 for (int i = 0; i < s.length(); i++) { 00218 char c = s.charAt(i); 00219 if (c == '"') q = !q; 00220 if (!q && c == '.') return i; 00221 } 00222 return -1; 00223 } 00224 00225 /** 00226 * Add a new column to the tuple 00227 */ 00228 public void addColumn(Column col) throws SQLException { 00229 columns.addElement(col); 00230 col.setColumn(columns.size()); 00231 col.setTable(this); 00232 String name = col.getName(); 00233 addName(name, col); 00234 int idx = nextUnquotedPeriod(name); 00235 while (idx >= 0) { 00236 name = name.substring(idx+1); 00237 addName(name, col); 00238 idx = nextUnquotedPeriod(name); 00239 } 00240 } 00241 00242 /** 00243 * Add a new column to the tuple in a specified position, 00244 * moving columns at that position and greater on position 00245 * to the right. 00246 */ 00247 public void addColumn(Column col, int pos) throws SQLException { 00248 columns.addElement(col); 00249 int np = columns.size(); 00250 while (np > pos) { 00251 Column col2 = (Column)columns.get(np-2); 00252 col2.setColumn(np); 00253 columns.set(np-1, col2); 00254 np--; 00255 } 00256 columns.set(pos-1, col); 00257 col.setColumn(pos); 00258 col.setTable(this); 00259 String name = col.getName(); 00260 addName(name, col); 00261 int idx = nextUnquotedPeriod(name); 00262 while (idx >= 0) { 00263 name = name.substring(idx+1); 00264 addName(name, col); 00265 idx = nextUnquotedPeriod(name); 00266 } 00267 } 00268 00269 /** 00270 * Add a column of the specified name and type to the tuple 00271 */ 00272 public void addColumn(String name, Type type) throws SQLException { 00273 addColumn(new Column(name, type)); 00274 } 00275 00276 /** 00277 * Delete the specified column 00278 */ 00279 public void deleteColumn(int col) throws SQLException, IOException { 00280 Column delCol = getColumn(col); 00281 int del = 0; 00282 for (int i = 1; i <= columns.size(); i++) { 00283 if (i == col) del++; 00284 else { 00285 Column cx = getColumn(i); 00286 cx.setColumn(i-del); 00287 columns.set(i-del-1, cx); 00288 } 00289 } 00290 columns.setSize(columns.size()-1); 00291 00292 Iterator iter = names.keySet().iterator(); 00293 while (iter.hasNext()) { 00294 String name = iter.next().toString(); 00295 if (names.get(name) == delCol) iter.remove(); 00296 } 00297 } 00298 00299 /** 00300 * Return the (one-based) column index of the column with the 00301 * specified name 00302 */ 00303 public int getColumnIndex(String name) throws SQLException { 00304 Column col = getColumn(name); 00305 if (col == null) { 00306 return -1; 00307 } 00308 return col.getColumn(); 00309 } 00310 00311 /** 00312 * Externalizable.readExternal(): Read me from a stream. 00313 */ 00314 public void readExternal(ObjectInput in) 00315 throws IOException, ClassNotFoundException 00316 { 00317 qualifier = (String)in.readObject(); 00318 if (qualifier.length() > 0) { 00319 this.qual = qualifier + "."; 00320 } else { 00321 this.qual = ""; 00322 } 00323 Vector c = (Vector)in.readObject(); 00324 this.columns = new Vector(); 00325 this.names = new HashMap(); 00326 for (int i = 0; i < c.size(); i++) { 00327 try { 00328 addColumn((Column)c.elementAt(i)); 00329 } catch (SQLException e) { 00330 //#ifdef DEBUG 00331 Debug.print(e); 00332 //#endif 00333 throw new IOException(e.toString()); 00334 } 00335 } 00336 try { 00337 resolveColumns(); 00338 } catch (SQLException e) { 00339 //#ifdef DEBUG 00340 Debug.print(e); 00341 //#endif 00342 throw new IOException(e.toString()); 00343 } 00344 } 00345 00346 /** 00347 * Externalizable.writeExternal(): Write me to a stream. 00348 */ 00349 public void writeExternal(ObjectOutput out) throws IOException { 00350 out.writeObject(qualifier); 00351 out.writeObject(columns); 00352 } 00353 00354 //#ifdef DEBUG 00355 /** 00356 * Return a string representation for debugging 00357 */ 00358 public String toString() { 00359 try { 00360 StringBuffer sb = new StringBuffer( 00361 Table.strip(getClass().getName())); 00362 sb.append(" "); 00363 sb.append(qualifier); 00364 sb.append("\n"); 00365 for (int i = 1; i <= getColumnCount(); i++) { 00366 Column c = getColumn(i); 00367 if (i > 1) sb.append("\n"); 00368 sb.append(" col " + i + ": "); 00369 sb.append(c.toString()); 00370 } 00371 sb.append("\n"); 00372 //sb.append(names.toString()); 00373 return sb.toString(); 00374 } catch (Exception e) { 00375 Debug.print(e); 00376 return e.toString(); 00377 } 00378 } 00379 //#endif 00380 00381 } 00382