*** misc/hsqldb/src/org/hsqldb/Constraint.java  Tue Apr 11 16:40:53 2006
--- misc/build/hsqldb/src/org/hsqldb/Constraint.java    Thu Jul 19 14:33:00 2007
***************
*** 111,123 ****
      int              constType;
  
      /**
!      *  Constructor declaration for UNIQUE
       */
!     Constraint(HsqlName name, Table t, Index index) {
  
          core           = new ConstraintCore();
          constName      = name;
!         constType      = UNIQUE;
          core.mainTable = t;
          core.mainIndex = index;
          /* fredt - in unique constraints column list for iColMain is the
--- 111,123 ----
      int              constType;
  
      /**
!      *  Constructor declaration for PK and UNIQUE
       */
!     Constraint(HsqlName name, Table t, Index index, int type) {
  
          core           = new ConstraintCore();
          constName      = name;
!         constType      = type;
          core.mainTable = t;
          core.mainIndex = index;
          /* fredt - in unique constraints column list for iColMain is the
***************
*** 179,195 ****
      }
  
      /**
-      * PK constraint constructor
-      */
-     Constraint(HsqlName name, int[] cols) {
- 
-         core              = new ConstraintCore();
-         constName         = name;
-         constType         = PRIMARY_KEY;
-         core.mainColArray = cols;
-     }
- 
-     /**
       * temp constraint constructor
       */
      Constraint(HsqlName name, int[] mainCols, Table refTable, int[] refCols,
--- 179,184 ----
*** misc/hsqldb/src/org/hsqldb/DatabaseCommandInterpreter.java  Mon Jul 17 00:29:34 2006
--- misc/build/hsqldb/src/org/hsqldb/DatabaseCommandInterpreter.java    Thu Jul 19 14:33:34 2007
***************
*** 1238,1245 ****
                  }
  
                  Constraint newconstraint =
!                     new Constraint(primaryConst.constName,
!                                    primaryConst.core.mainColArray);
  
                  t.addConstraint(newconstraint);
                  database.schemaManager.registerConstraintName(
--- 1238,1245 ----
                  }
  
                  Constraint newconstraint =
!                     new Constraint(primaryConst.constName, t, t.getPrimaryIndex(),
!                                    Constraint.PRIMARY_KEY);
  
                  t.addConstraint(newconstraint);
                  database.schemaManager.registerConstraintName(
***************
*** 2521,2527 ****
          boolean canAdd = true;
  
          if (t.findColumn(c.columnName.name) != -1) {
!             throw Trace.error(Trace.COLUMN_ALREADY_EXISTS);
          }
  
          if (c.isPrimaryKey() && t.hasPrimaryKey()) {
--- 2521,2527 ----
          boolean canAdd = true;
  
          if (t.findColumn(c.columnName.name) != -1) {
!             throw Trace.error(Trace.COLUMN_ALREADY_EXISTS, c.columnName.name);
          }
  
          if (c.isPrimaryKey() && t.hasPrimaryKey()) {
*** misc/hsqldb/src/org/hsqldb/Index.java   Fri Jul 21 15:37:43 2006
--- misc/build/hsqldb/src/org/hsqldb/Index.java Thu Jul 19 14:33:00 2007
***************
*** 101,107 ****
      private final HsqlName indexName;
      final boolean[]        colCheck;
      private final int[]    colIndex;
!     private final int[]    colType;
      final int[]            pkCols;
      final int[]            pkTypes;
      private final boolean  isUnique;    // DDL uniqueness
--- 101,107 ----
      private final HsqlName indexName;
      final boolean[]        colCheck;
      private final int[]    colIndex;
!     private final int[]    colTypes;
      final int[]            pkCols;
      final int[]            pkTypes;
      private final boolean  isUnique;    // DDL uniqueness
***************
*** 116,121 ****
--- 116,122 ----
          null);
      IndexRowIterator updatableIterators;
      final boolean    onCommitPreserve;
+     final Table      table;
  
      /**
       * Constructor declaration
***************
*** 131,147 ****
       * @param visColumns count of visible columns
       */
      Index(Database database, HsqlName name, Table table, int[] column,
!             int[] type, boolean isPk, boolean unique, boolean constraint,
              boolean forward, int[] pkcols, int[] pktypes, boolean temp) {
  
!         indexName    = name;
!         colIndex     = column;
!         colType      = type;
!         pkCols       = pkcols;
!         pkTypes      = pktypes;
!         isUnique     = unique;
!         isConstraint = constraint;
!         isForward    = forward;
          useRowId = (!isUnique && pkCols.length == 0)
                     || (colIndex.length == 0);
          colCheck = table.getNewColumnCheckList();
--- 132,149 ----
       * @param visColumns count of visible columns
       */
      Index(Database database, HsqlName name, Table table, int[] column,
!             int[] colTypes, boolean isPk, boolean unique, boolean constraint,
              boolean forward, int[] pkcols, int[] pktypes, boolean temp) {
  
!         this.table     = table;
!         this.indexName = name;
!         this.colIndex  = column;
!         this.colTypes  = colTypes;
!         this.pkCols    = pkcols;
!         this.pkTypes   = pktypes;
!         isUnique       = unique;
!         isConstraint   = constraint;
!         isForward      = forward;
          useRowId = (!isUnique && pkCols.length == 0)
                     || (colIndex.length == 0);
          colCheck = table.getNewColumnCheckList();
***************
*** 203,209 ****
       * Returns the array containing column indexes for index
       */
      int[] getColumnTypes() {
!         return colType;    // todo: this gives back also primary key field(s)!
      }
  
      /**
--- 205,227 ----
       * Returns the array containing column indexes for index
       */
      int[] getColumnTypes() {
!         return colTypes;    // todo: this gives back also primary key field(s)!
!     }
! 
!     String getColumnNameList() {
! 
!         String columnNameList = "";
! 
!         for (int j = 0; j < colIndex.length; ++j) {
!             columnNameList +=
!                 table.getColumn(colIndex[j]).columnName.statementName;
! 
!             if (j < colIndex.length - 1) {
!                 columnNameList += ",";
!             }
!         }
! 
!         return columnNameList;
      }
  
      /**
***************
*** 297,304 ****
              compare = compareRowForInsert(session, row, n.getRow());
  
              if (compare == 0) {
!                 throw Trace.error(Trace.VIOLATION_OF_UNIQUE_INDEX,
!                                   indexName.name);
              }
  
              isleft = compare < 0;
--- 315,334 ----
              compare = compareRowForInsert(session, row, n.getRow());
  
              if (compare == 0) {
!                 int    errorCode = Trace.VIOLATION_OF_UNIQUE_INDEX;
!                 String name      = indexName.statementName;
! 
!                 if (isConstraint) {
!                     Constraint c =
!                         table.getUniqueOrPKConstraintForIndex(this);
! 
!                     name      = c.getName().name;
!                     errorCode = Trace.VIOLATION_OF_UNIQUE_CONSTRAINT;
!                 }
! 
!                 throw Trace.error(errorCode, new Object[] {
!                     name, getColumnNameList()
!                 });
              }
  
              isleft = compare < 0;
***************
*** 848,854 ****
              boolean t =
                  Column.compare(
                      collation, value, x.getData()[colIndex[0]],
!                     colType[0]) >= iTest;
  
              if (t) {
                  Node r = x.getRight();
--- 878,884 ----
              boolean t =
                  Column.compare(
                      collation, value, x.getData()[colIndex[0]],
!                     colTypes[0]) >= iTest;
  
              if (t) {
                  Node r = x.getRight();
***************
*** 879,885 ****
          while (x != null) {
              Object colvalue = x.getData()[colIndex[0]];
              int result = Column.compare(collation, value, colvalue,
!                                         colType[0]);
  
              if (result >= iTest) {
                  x = next(x);
--- 909,915 ----
          while (x != null) {
              Object colvalue = x.getData()[colIndex[0]];
              int result = Column.compare(collation, value, colvalue,
!                                         colTypes[0]);
  
              if (result >= iTest) {
                  x = next(x);
***************
*** 914,920 ****
  
          while (x != null) {
              boolean t = Column.compare(
!                 collation, null, x.getData()[colIndex[0]], colType[0]) >= 0;
  
              if (t) {
                  Node r = x.getRight();
--- 944,950 ----
  
          while (x != null) {
              boolean t = Column.compare(
!                 collation, null, x.getData()[colIndex[0]], colTypes[0]) >= 0;
  
              if (t) {
                  Node r = x.getRight();
***************
*** 1146,1152 ****
                              Object[] b) throws HsqlException {
  
          int i = Column.compare(collation, a[rowColMap[0]], b[colIndex[0]],
!                                colType[0]);
  
          if (i != 0) {
              return i;
--- 1176,1182 ----
                              Object[] b) throws HsqlException {
  
          int i = Column.compare(collation, a[rowColMap[0]], b[colIndex[0]],
!                                colTypes[0]);
  
          if (i != 0) {
              return i;
***************
*** 1156,1162 ****
  
          for (int j = 1; j < fieldcount; j++) {
              i = Column.compare(collation, a[rowColMap[j]], b[colIndex[j]],
!                                colType[j]);
  
              if (i != 0) {
                  return i;
--- 1186,1192 ----
  
          for (int j = 1; j < fieldcount; j++) {
              i = Column.compare(collation, a[rowColMap[j]], b[colIndex[j]],
!                                colTypes[j]);
  
              if (i != 0) {
                  return i;
***************
*** 1214,1220 ****
          for (; j < colIndex.length; j++) {
              Object currentvalue = a[colIndex[j]];
              int i = Column.compare(collation, currentvalue, b[colIndex[j]],
!                                    colType[j]);
  
              if (i != 0) {
                  return i;
--- 1244,1250 ----
          for (; j < colIndex.length; j++) {
              Object currentvalue = a[colIndex[j]];
              int i = Column.compare(collation, currentvalue, b[colIndex[j]],
!                                    colTypes[j]);
  
              if (i != 0) {
                  return i;
*** misc/hsqldb/src/org/hsqldb/Table.java   Wed Jun 28 23:47:11 2006
--- misc/build/hsqldb/src/org/hsqldb/Table.java Thu Jul 19 14:33:34 2007
***************
*** 488,500 ****
       * @param  index
       * @return
       */
!     Constraint getUniqueConstraintForIndex(Index index) {
  
          for (int i = 0, size = constraintList.length; i < size; i++) {
              Constraint c = constraintList[i];
  
              if (c.getMainIndex() == index
!                     && c.getType() == Constraint.UNIQUE) {
                  return c;
              }
          }
--- 488,501 ----
       * @param  index
       * @return
       */
!     Constraint getUniqueOrPKConstraintForIndex(Index index) {
  
          for (int i = 0, size = constraintList.length; i < size; i++) {
              Constraint c = constraintList[i];
  
              if (c.getMainIndex() == index
!                     && (c.getType() == Constraint.UNIQUE
!                         || c.getType() == Constraint.PRIMARY_KEY)) {
                  return c;
              }
          }
***************
*** 531,537 ****
      void addColumn(Column column) throws HsqlException {
  
          if (findColumn(column.columnName.name) >= 0) {
!             throw Trace.error(Trace.COLUMN_ALREADY_EXISTS);
          }
  
          if (column.isIdentity()) {
--- 532,538 ----
      void addColumn(Column column) throws HsqlException {
  
          if (findColumn(column.columnName.name) >= 0) {
!             throw Trace.error(Trace.COLUMN_ALREADY_EXISTS, column.columnName.name);
          }
  
          if (column.isIdentity()) {
***************
*** 1498,1508 ****
  
          int newindexNo = createIndexStructureGetNo(column, name, unique,
              constraint, forward);
!         Index       newindex     = indexList[newindexNo];
!         Index       primaryindex = getPrimaryIndex();
!         RowIterator it           = primaryindex.firstRow(session);
!         int         rowCount     = 0;
!         int         error        = 0;
  
          try {
              while (it.hasNext()) {
--- 1499,1509 ----
  
          int newindexNo = createIndexStructureGetNo(column, name, unique,
              constraint, forward);
!         Index         newindex     = indexList[newindexNo];
!         Index         primaryindex = getPrimaryIndex();
!         RowIterator   it           = primaryindex.firstRow(session);
!         int           rowCount     = 0;
!         HsqlException error        = null;
  
          try {
              while (it.hasNext()) {
***************
*** 1521,1529 ****
  
              return newindex;
          } catch (java.lang.OutOfMemoryError e) {
!             error = Trace.OUT_OF_MEMORY;
          } catch (HsqlException e) {
!             error = Trace.VIOLATION_OF_UNIQUE_INDEX;
          }
  
          // backtrack on error
--- 1522,1533 ----
  
              return newindex;
          } catch (java.lang.OutOfMemoryError e) {
!             error = Trace.error(Trace.OUT_OF_MEMORY);
          } catch (HsqlException e) {
!             error = Trace.error(Trace.VIOLATION_OF_UNIQUE_INDEX,
!                                 new Object[] {
!                 newindex.getName().statementName, newindex.getColumnNameList()
!             });
          }
  
          // backtrack on error
***************
*** 1547,1553 ****
  
          setBestRowIdentifiers();
  
!         throw Trace.error(error);
      }
  
      /**
--- 1551,1557 ----
  
          setBestRowIdentifiers();
  
!         throw error;
      }
  
      /**
***************
*** 2031,2044 ****
                  indexList[i].insert(null, row, i);
              }
          } catch (HsqlException e) {
-             Index   index        = indexList[i];
-             boolean isconstraint = index.isConstraint;
  
!             if (isconstraint) {
!                 throw Trace.error(Trace.VIOLATION_OF_UNIQUE_CONSTRAINT,
!                                   index.getName().name);
              }
  
              throw e;
          }
      }
--- 2035,2051 ----
                  indexList[i].insert(null, row, i);
              }
          } catch (HsqlException e) {
  
!             // unique index violation - rollback insert
!             for (--i; i >= 0; i--) {
!                 Node n = row.getNode(i);
! 
!                 indexList[i].delete(null, n);
              }
  
+             row.delete();
+             removeRowFromStore(row);
+ 
              throw e;
          }
      }
***************
*** 3294,3301 ****
                  indexList[i].insert(session, row, i);
              }
          } catch (HsqlException e) {
-             Index   index        = indexList[i];
-             boolean isconstraint = index.isConstraint;
  
              // unique index violation - rollback insert
              for (--i; i >= 0; i--) {
--- 3301,3306 ----
***************
*** 3307,3320 ****
              row.delete();
              removeRowFromStore(row);
  
-             if (isconstraint) {
-                 Constraint c    = getUniqueConstraintForIndex(index);
-                 String     name = c == null ? index.getName().name
-                                             : c.getName().name;
- 
-                 throw Trace.error(Trace.VIOLATION_OF_UNIQUE_CONSTRAINT, name);
-             }
- 
              throw e;
          }
      }
--- 3312,3317 ----
*** misc/hsqldb/src/org/hsqldb/TableWorks.java  Tue Apr 11 16:56:40 2006
--- misc/build/hsqldb/src/org/hsqldb/TableWorks.java    Thu Jul 19 14:33:00 2007
***************
*** 224,230 ****
                  table.getSchemaName(), false);
          addOrDropPrimaryKey(cols, false);
  
!         Constraint newconstraint = new Constraint(name, cols);
  
          table.addConstraint(newconstraint);
          table.database.schemaManager.registerConstraintName(name.name,
--- 224,231 ----
                  table.getSchemaName(), false);
          addOrDropPrimaryKey(cols, false);
  
!         Constraint newconstraint = new Constraint(name, table,
!             table.getPrimaryIndex(), Constraint.PRIMARY_KEY);
  
          table.addConstraint(newconstraint);
          table.database.schemaManager.registerConstraintName(name.name,
***************
*** 286,293 ****
          // create an autonamed index
          HsqlName indexname = table.database.nameManager.newAutoName("IDX",
              name.name);
!         Index      index = createIndex(col, indexname, true, true, false);
!         Constraint newconstraint = new Constraint(name, table, index);
  
          table.addConstraint(newconstraint);
          table.database.schemaManager.registerConstraintName(name.name,
--- 287,295 ----
          // create an autonamed index
          HsqlName indexname = table.database.nameManager.newAutoName("IDX",
              name.name);
!         Index index = createIndex(col, indexname, true, true, false);
!         Constraint newconstraint = new Constraint(name, table, index,
!             Constraint.UNIQUE);
  
          table.addConstraint(newconstraint);
          table.database.schemaManager.registerConstraintName(name.name,
***************
*** 488,495 ****
  
          if (column.isPrimaryKey()) {
              HsqlName pkNameAdd = tn.makeSysPKName();
!             Constraint newconstraint = new Constraint(pkNameAdd,
!                 new int[]{ colIndex });
  
              table.addConstraint(newconstraint);
              table.database.schemaManager.registerConstraintName(
--- 490,497 ----
  
          if (column.isPrimaryKey()) {
              HsqlName pkNameAdd = tn.makeSysPKName();
!             Constraint newconstraint = new Constraint(pkNameAdd, table,
!                 table.getPrimaryIndex(), Constraint.PRIMARY_KEY);
  
              table.addConstraint(newconstraint);
              table.database.schemaManager.registerConstraintName(
*** misc/hsqldb/src/org/hsqldb/persist/TextCache.java   Mon Jul 24 13:20:45 2006
--- misc/build/hsqldb/src/org/hsqldb/persist/TextCache.java Thu Jul 19 14:33:00 2007
***************
*** 479,485 ****
                      wasNormal = true;
                      complete  = wasCR;
                      wasCR     = false;
!                     hasQuote  = !hasQuote;
                      break;
  
                  case CR_CHAR :
--- 479,487 ----
                      wasNormal = true;
                      complete  = wasCR;
                      wasCR     = false;
!                     if (isQuoted) {
!                         hasQuote  = !hasQuote;
!                     }
                      break;
  
                  case CR_CHAR :
*** misc/hsqldb/src/org/hsqldb/resources/sql-error-messages.properties  Thu Jun 15 13:15:06 2006
--- misc/build/hsqldb/src/org/hsqldb/resources/sql-error-messages.properties    Thu Jul 19 14:33:00 2007
***************
*** 10,16 ****
  006=22012 Division by zero
  007=22019 Invalid escape character
  008=23000 Integrity constraint violation
! 009=23000 Violation of unique index
  010=23000 Attempt to insert null into a non-nullable column
  011=37000 Unexpected token
  012=37000 Unexpected end of command
--- 10,16 ----
  006=22012 Division by zero
  007=22019 Invalid escape character
  008=23000 Integrity constraint violation
! 009=23000 Violation of unique index $$: duplicate value(s) for column(s) $$
  010=23000 Attempt to insert null into a non-nullable column
  011=37000 Unexpected token
  012=37000 Unexpected end of command
***************
*** 105,111 ****
  101=\u0020$$ table: $$
  102=duplicate column in list
  103=table has no primary key
! 104=23000 Unique constraint violation
  105=S0021 missing DEFAULT value on column $$
  106=S1000 Not a condition
  107=attempt to connect while db opening /closing
--- 105,111 ----
  101=\u0020$$ table: $$
  102=duplicate column in list
  103=table has no primary key
! 104=23000 Violation of unique constraint $$: duplicate value(s) for column(s) $$
  105=S0021 missing DEFAULT value on column $$
  106=S1000 Not a condition
  107=attempt to connect while db opening /closing
***************
*** 139,145 ****
  135=properties name is null or empty
  136=Server certificate has no Common Name
  137=Server certificate has empty Common Name
! 138=Unknown JDBC escape sequence: {$$
  139=Certificate Common Name[$$] does not match host name[$$]
  140=NA
  141=NA
--- 139,145 ----
  135=properties name is null or empty
  136=Server certificate has no Common Name
  137=Server certificate has empty Common Name
! 138=Unknown JDBC escape sequence: {$$
  139=Certificate Common Name[$$] does not match host name[$$]
  140=NA
  141=NA
*** misc/hsqldb/src/org/hsqldb/Parser.java  Wed Jun 14 14:24:48 2006
--- misc/build/hsqldb/src/org/hsqldb/Parser.java    Thu Jul 19 14:33:34 2007
***************
*** 73,79 ****
--- 73,82 ----
  import org.hsqldb.lib.HashMap;
  import org.hsqldb.lib.HashMappedList;
  import org.hsqldb.lib.HsqlArrayList;
+ import org.hsqldb.lib.IntKeyHashMap;
  import org.hsqldb.lib.IntValueHashMap;
+ import org.hsqldb.lib.Iterator;
+ import org.hsqldb.lib.StringConverter;
  import org.hsqldb.store.ValuePool;
  import org.hsqldb.lib.HashSet;
  
***************
*** 132,137 ****
--- 135,141 ----
      private Object    oData;
      private int       iType;
      private int       iToken;
+     private boolean   compilingView;
  
      //
      private int           subQueryLevel;
***************
*** 150,155 ****
--- 154,174 ----
          database     = db;
          tokenizer    = t;
          this.session = session;
+         compilingView = false;
+     }
+ 
+     /**
+      *  sets a flag indicating the parser is used for compiling a view
+      */
+     void setCompilingView() {
+         compilingView = true;
+     }
+ 
+     /**
+      *  determines whether the parser is used for compiling a view
+      */
+     boolean isCompilingView() {
+         return compilingView;
      }
  
      /**
***************
*** 394,401 ****
--- 413,432 ----
          HsqlArrayList vcolumn = new HsqlArrayList();
  
          do {
+             int expPos = tokenizer.getPosition();
              Expression e = parseExpression();
  
+             if (isCompilingView()) {
+                 if (e.getType() == Expression.ASTERISK) {
+                     if (select.asteriskPositions == null)
+                         select.asteriskPositions = new IntKeyHashMap();
+                     // remember the position of the asterisk. For the moment, just
+                     // remember the expression, so it can later be found and replaced
+                     // with the concrete column list
+                     select.asteriskPositions.put(expPos, e);
+                 }
+             }
+ 
              token = tokenizer.getString();
  
              if (tokenizer.wasThis(Token.T_AS)) {
***************
*** 880,885 ****
--- 911,917 ----
  
                  String tablename = e.getTableName();
  
+                 int oldPos = pos;
                  if (tablename == null) {
                      for (int i = 0; i < filters.length; i++) {
                          pos      = addFilterColumns(filters[i], vcolumn, pos);
***************
*** 895,900 ****
--- 927,955 ----
                      pos      = addFilterColumns(f, vcolumn, pos);
                      colcount = vcolumn.size();
                  }
+ 
+                 if (isCompilingView()) {
+                     // find this expression's position in the Select's asterisk list
+                     boolean foundAsteriskPos = false;
+                     Iterator expSearch = select.asteriskPositions.keySet().iterator();
+                     while (expSearch.hasNext()) {
+                         int expPos = expSearch.nextInt();
+                         if (e == select.asteriskPositions.get(expPos)) {
+                             // compile the complete column list which later is to replace the asterisk
+                             StringBuffer completeColList = new StringBuffer();
+                             for (int col=oldPos; col<pos; ++col) {
+                                 Expression resolvedColExpr = (Expression) (vcolumn.get(col));
+                                 completeColList.append(resolvedColExpr.getColumnDDL());
+                                 if ( col < pos - 1 )
+                                     completeColList.append( ", " );
+                             }
+                             select.asteriskPositions.put(expPos, completeColList.toString());
+                             foundAsteriskPos = true;
+                             break;
+                         }
+                     }
+                     Trace.doAssert(foundAsteriskPos);
+                 }
              } else {
                  if (e.getFilter() == null) {
                      for (int i = 0; i < filters.length; i++) {
***************
*** 918,931 ****
      /**
       * Add all columns of a table filter to list of columns
       */
!     static int addFilterColumns(TableFilter filter, HsqlArrayList columnList,
!                                 int position) {
  
          Table table = filter.getTable();
          int   count = table.getColumnCount();
  
          for (int i = 0; i < count; i++) {
              Expression e = new Expression(filter, table.getColumn(i));
  
              columnList.add(position++, e);
          }
--- 973,988 ----
      /**
       * Add all columns of a table filter to list of columns
       */
!     int addFilterColumns(TableFilter filter, HsqlArrayList columnList,
!                                 int position) throws HsqlException {
  
          Table table = filter.getTable();
          int   count = table.getColumnCount();
  
          for (int i = 0; i < count; i++) {
              Expression e = new Expression(filter, table.getColumn(i));
+             if (isCompilingView())
+                 e.resolveTables(filter);
  
              columnList.add(position++, e);
          }
*** misc/hsqldb/src/org/hsqldb/Select.java  Mon Jul 10 13:03:43 2006
--- misc/build/hsqldb/src/org/hsqldb/Select.java    Thu Jul 19 14:33:51 2007
***************
*** 70,75 ****
--- 70,76 ----
  import org.hsqldb.lib.HashMap;
  import org.hsqldb.lib.HashSet;
  import org.hsqldb.lib.HsqlArrayList;
+ import org.hsqldb.lib.IntKeyHashMap;
  import org.hsqldb.lib.Iterator;
  
  // fredt@users 20010701 - patch 1.6.1 by hybris
***************
*** 129,134 ****
--- 130,136 ----
                            EXCEPT    = 4;
      private boolean       simpleLimit;        // true if maxrows can be uses as is
      Result.ResultMetaData resultMetaData;
+     IntKeyHashMap         asteriskPositions;
  
      /**
       * Experimental.
***************
*** 461,467 ****
          checkAggregateOrGroupByColumns(groupByEnd, orderByStart);
  
          // order by columns
!         checkAggregateOrGroupByOrderColumns(orderByStart, orderByEnd);
          prepareSort();
  
          simpleLimit = (isDistinctSelect == false && isGrouped == false
--- 463,469 ----
          checkAggregateOrGroupByColumns(groupByEnd, orderByStart);
  
          // order by columns
!         checkAggregateOrGroupByOrderColumns(orderByStart, orderByEnd);
          prepareSort();
  
          simpleLimit = (isDistinctSelect == false && isGrouped == false
***************
*** 757,788 ****
                      continue;
                  }
  
!                 throw Trace.error(Trace.NOT_IN_AGGREGATE_OR_GROUP_BY, exp);
!             }
!         }
!     }
! 
!     private void checkAggregateOrGroupByOrderColumns(int start,
!             int end) throws HsqlException {
! 
!         checkAggregateOrGroupByColumns(start, end);
! 
!         if (start < end && isDistinctSelect) {
!             HsqlArrayList colExps = new HsqlArrayList();
! 
!             for (int i = start; i < end; i++) {
!                 exprColumns[i].collectInGroupByExpressions(colExps);
!             }
! 
!             for (int i = 0, size = colExps.size(); i < size; i++) {
!                 Expression exp = (Expression) colExps.get(i);
! 
!                 if (isSimilarIn(exp, 0, iResultLen)) {
!                     continue;
                  }
! 
!                 throw Trace.error(Trace.INVALID_ORDER_BY_IN_DISTINCT_SELECT,
!                                   exp);
              }
          }
      }
--- 759,790 ----
                      continue;
                  }
  
!                 throw Trace.error(Trace.NOT_IN_AGGREGATE_OR_GROUP_BY, exp);
!             }
!         }
!     }
! 
!     private void checkAggregateOrGroupByOrderColumns(int start,
!             int end) throws HsqlException {
! 
!         checkAggregateOrGroupByColumns(start, end);
! 
!         if (start < end && isDistinctSelect) {
!             HsqlArrayList colExps = new HsqlArrayList();
! 
!             for (int i = start; i < end; i++) {
!                 exprColumns[i].collectInGroupByExpressions(colExps);
!             }
! 
!             for (int i = 0, size = colExps.size(); i < size; i++) {
!                 Expression exp = (Expression) colExps.get(i);
! 
!                 if (isSimilarIn(exp, 0, iResultLen)) {
!                     continue;
                  }
! 
!                 throw Trace.error(Trace.INVALID_ORDER_BY_IN_DISTINCT_SELECT,
!                                   exp);
              }
          }
      }
*** misc/hsqldb/src/org/hsqldb/Tokenizer.java   Fri Jul 21 15:38:12 2006
--- misc/build/hsqldb/src/org/hsqldb/Tokenizer.java Thu Jul 19 14:33:35 2007
***************
*** 126,131 ****
--- 126,132 ----
      private int              beginIndex;
      private int              iType;
      private String           sToken;
+     private int              indexLongNameFirst = -1;
      private String           sLongNameFirst = null;
      private int              typeLongNameFirst;
  
***************
*** 160,175 ****
  
      public void reset(String s) {
  
!         sCommand          = s;
!         iLength           = s.length();
!         iIndex            = 0;
!         tokenIndex        = 0;
!         nextTokenIndex    = 0;
!         beginIndex        = 0;
!         iType             = NO_TYPE;
!         typeLongNameFirst = NO_TYPE;
!         sToken            = null;
!         sLongNameFirst    = null;
  
  //        sLongNameLast  = null;
          bWait             = false;
--- 161,177 ----
  
      public void reset(String s) {
  
!         sCommand           = s;
!         iLength            = s.length();
!         iIndex             = 0;
!         tokenIndex         = 0;
!         nextTokenIndex     = 0;
!         beginIndex         = 0;
!         iType              = NO_TYPE;
!         typeLongNameFirst  = NO_TYPE;
!         sToken             = null;
!         indexLongNameFirst = -1;
!         sLongNameFirst     = null;
  
  //        sLongNameLast  = null;
          bWait             = false;
***************
*** 188,194 ****
          }
  
          nextTokenIndex = iIndex;
!         iIndex         = tokenIndex;
          bWait          = true;
      }
  
--- 190,196 ----
          }
  
          nextTokenIndex = iIndex;
!         iIndex         = ( indexLongNameFirst != -1 ) ? indexLongNameFirst : tokenIndex;
          bWait          = true;
      }
  
***************
*** 741,748 ****
          }
  
          if (!retainFirst) {
!             sLongNameFirst    = null;
!             typeLongNameFirst = NO_TYPE;
          }
  
          while (iIndex < iLength
--- 743,751 ----
          }
  
          if (!retainFirst) {
!             sLongNameFirst     = null;
!             indexLongNameFirst = -1;
!             typeLongNameFirst  = NO_TYPE;
          }
  
          while (iIndex < iLength
***************
*** 876,883 ****
                      c = sCommand.charAt(iIndex);
  
                      if (c == '.') {
!                         sLongNameFirst    = sToken;
!                         typeLongNameFirst = iType;
  
                          iIndex++;
  
--- 879,887 ----
                      c = sCommand.charAt(iIndex);
  
                      if (c == '.') {
!                         sLongNameFirst     = sToken;
!                         indexLongNameFirst = tokenIndex;
!                         typeLongNameFirst  = iType;
  
                          iIndex++;
  
***************
*** 958,965 ****
                      }
  
                      if (c == '.') {
!                         typeLongNameFirst = iType;
!                         sLongNameFirst    = sToken;
  
                          iIndex++;
  
--- 962,970 ----
                      }
  
                      if (c == '.') {
!                         typeLongNameFirst  = iType;
!                         sLongNameFirst     = sToken;
!                         indexLongNameFirst = tokenIndex;
  
                          iIndex++;
  
*** misc/hsqldb/src/org/hsqldb/View.java    Sun Oct 23 19:40:21 2005
--- misc/build/hsqldb/src/org/hsqldb/View.java  Thu Jul 19 14:33:35 2007
***************
*** 82,87 ****
--- 82,88 ----
          compileTimeSchema = session.getSchemaHsqlName(null);
  
          compile(session);
+         replaceAsterisksInStatement();
  
          HsqlName[] schemas = getSchemas();
  
***************
*** 125,130 ****
--- 126,132 ----
          // create the working table
          Parser p = new Parser(session, this.database,
                                new Tokenizer(statement));
+         p.setCompilingView();
          int brackets = p.parseOpenBracketsSelect();
  
          viewSubQuery = p.parseSubquery(brackets, colList, true,
***************
*** 155,160 ****
--- 157,215 ----
      }
  
      /**
+      *  is a private helper for replaceAsterisksInStatement, to avoid some code duplication
+      */
+     private void collectAsteriskPos(final Select select, HsqlArrayList asteriskPositions) {
+ 
+         if (select.asteriskPositions == null)
+             return;
+ 
+         Iterator asterisks = select.asteriskPositions.keySet().iterator();
+         while (asterisks.hasNext()) {
+             int pos = asterisks.nextInt();
+             asteriskPositions.set(pos, select.asteriskPositions.get(pos) );
+         }
+     }
+ 
+     /**
+      *  replaces all asterisks in our statement with the actual column list
+      *
+      *  This way, we ensure what is required by the standard: a view returns a result
+      *  which reflects the structure of the underlying tables at the *time of the definition*
+      *  of the view.
+      */
+     private void replaceAsterisksInStatement() {
+ 
+         HsqlArrayList asteriskPositions = new HsqlArrayList();
+         asteriskPositions.setSize(statement.length());
+ 
+         // asterisk positions in sub queries
+         for (int i=0; i<viewSubqueries.length; ++i) {
+             // collect the occurances of asterisks in the statement
+             Select subSelect = viewSubqueries[i].select;
+             collectAsteriskPos(subSelect, asteriskPositions);
+ 
+             // the same for all (possible) UNION SELECTs of the sub select
+             if (subSelect.unionArray != null) {
+                 // start with index 1, not 0 - the first select is the one already covered by subSelect
+                 for (int u=1; u<subSelect.unionArray.length; ++u)
+                     collectAsteriskPos(subSelect.unionArray[u], asteriskPositions);
+             }
+         }
+ 
+         StringBuffer expandedStatement = new StringBuffer(statement);
+         for (int pos = asteriskPositions.size()-1; pos >= 0; --pos) {
+             String colList = (String)asteriskPositions.get(pos);
+             if (colList == null)
+                 continue;
+ 
+             expandedStatement.replace(pos, expandedStatement.indexOf("*", pos) + 1, colList );
+         }
+ 
+         statement = expandedStatement.toString();
+     }
+ 
+     /**
       * Overridden to disable SET TABLE READONLY DDL for View objects.
       */
      void setDataReadOnly(boolean value) throws HsqlException {
*** misc/hsqldb/src/org/hsqldb/Expression.java  Mon Jul 10 13:02:53 2006
--- misc/build/hsqldb/src/org/hsqldb/Expression.java    Thu Jul 19 14:33:51 2007
***************
*** 379,391 ****
       */
      Expression(Expression e, int dataType, int precision, int scale) {
  
!         this.exprType    = CONVERT;
!         this.eArg        = e;
!         this.dataType    = dataType;
!         this.precision   = precision;
!         this.scale       = scale;
!         this.columnAlias = e.columnAlias;
!         this.aliasQuoted = e.aliasQuoted;
  
          checkAggregate();
      }
--- 379,391 ----
       */
      Expression(Expression e, int dataType, int precision, int scale) {
  
!         this.exprType    = CONVERT;
!         this.eArg        = e;
!         this.dataType    = dataType;
!         this.precision   = precision;
!         this.scale       = scale;
!         this.columnAlias = e.columnAlias;
!         this.aliasQuoted = e.aliasQuoted;
  
          checkAggregate();
      }
***************
*** 535,540 ****
--- 535,568 ----
      }
  
      /**
+      *  returns the complete name of the column represented by the expression
+      *
+      *  If an alias is known for the column's table, this alias will precede the
+      *  column name, except it's "SYSTEM_SUBQUERY".
+      *  If no alias is known, the column's table will be asked for its
+      *  statementName, which then will precede the column name.
+      */
+     String getColumnDDL() throws HsqlException {
+ 
+         Trace.doAssert(exprType == COLUMN);
+ 
+         StringBuffer buf = new StringBuffer();
+ 
+         Table table = tableFilter.getTable();
+ 
+         if (tableName != null) {
+             if (!tableName.equals("SYSTEM_SUBQUERY"))
+                 buf.append('"').append(tableName).append('"').append('.');
+         }
+         else
+             buf.append(table.tableName.statementName).append('.');
+ 
+         buf.append(table.getColumn(columnIndex).columnName.statementName);
+ 
+         return buf.toString();
+     }
+ 
+     /**
       * For use with CHECK constraints. Under development.
       *
       * Currently supports a subset of expressions and is suitable for CHECK
***************
*** 2689,2695 ****
                  return tableFilter != null && tableFilter.isAssigned;
  
              case QUERY :
!                 return subQuery.isResolved;
          }
  
          // todo: could recurse here, but never miss a 'false'!
--- 2717,2723 ----
                  return tableFilter != null && tableFilter.isAssigned;
  
              case QUERY :
!                 return subQuery.isResolved;
          }
  
          // todo: could recurse here, but never miss a 'false'!
***************
*** 3258,3266 ****
                  try {
                      return tableFilter.currentData[columnIndex];
                  } catch (NullPointerException e) {
!                     String name = tableName == null ? columnName :
!                         tableName + '.' + columnName;
!                     throw Trace.error(Trace.COLUMN_NOT_FOUND, name);
                  }
              case FUNCTION :
                  return function.getValue(session);
--- 3286,3294 ----
                  try {
                      return tableFilter.currentData[columnIndex];
                  } catch (NullPointerException e) {
!                     String name = tableName == null ? columnName :
!                         tableName + '.' + columnName;
!                     throw Trace.error(Trace.COLUMN_NOT_FOUND, name);
                  }
              case FUNCTION :
                  return function.getValue(session);
