/*
_____       _    _    Corso   Italia,  178
(_|__   .  (_   |_|_  56125           Pisa
(_|_) |)|(()_)()| |   tel.  +39  050 46380
  |   |               picosoft@picosoft.it

 Copyright (C) Picosoft s.r.l. 1995-2002

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, or (at your option)
 any later version.

 This program 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 General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/
# include "sqlpars.h"
static char rcsid[] = "$Id: parsddl.cpp 5.3 2001/04/19 09:36:06 picoSoft Exp Marco $";
# include "relview.h"
extern "C" {
# include <stdlib.h>
# ifdef WIN32
# include <process.h>
# else
# include <unistd.h>
# endif
}

# define CHECK_OPTION " WITH CHECK OPTION"

Error
SqlParser::Create (Lex &l)
{
   Error Return = SQL_ERROR;
   Token *t;

   if ((t = l.GetToken()) == 0)
      PrintError (E_SYNTAX_ERROR_000, "Expected keyword, found <end_statement>");
   else if (t->token == TABLE)
      Return = CreateTable (l);
   else if (t->token == UNIQUE)
      if ((t = l.GetToken()) && t->token == INDEX)
         Return = CreateIndex (l, PTrue);
      else
         PrintError (E_SYNTAX_ERROR_000, "Expected INDEX");
   else if (t->token == INDEX)
      Return = CreateIndex (l, PFalse);
   else if (t->token == VIEW)
      Return = CreateView (l);
   else
      PrintError (E_SYNTAX_ERROR_000, "Unexpected token <" + t->word + ">" );
   return Return;
}

Error
SqlParser::CreateView (Lex &l)
{
   Error Return = SQL_ERROR;
   Token *t;
   PString viewName;
   PStringList fieldsName;
   StmtRel *sr;
   int i, j;

   if ((t = l.GetToken()) == 0 || t->token != USER_NAME)
      PrintError (E_SYNTAX_ERROR_000, "Missing username");
   else if (DB->GetRelObject(t->word) || DB->GetRelView(t->word))
      PrintError (E_SYNTAX_ERROR_000, "Duplicate object");
   else {
      viewName = t->word;
      if ((t = l.GetToken()) == 0)
         PrintError (E_SYNTAX_ERROR_000, "Unexpected end of CREATE VIEW statement");
      else if (t->token == '(') {
         do {
            t = l.GetToken();
            if (t && t->token == USER_NAME) {
               fieldsName.AddItem (&t->word);
               t = l.GetToken();
            }
         } while (t != 0 && t->token == ',');
         if (t == 0) {
            PrintError (E_SYNTAX_ERROR_000, "Unexpected end of CREATE VIEW statement");
            return Return;
         } else if (t->token != ')') {
            PrintError (E_SYNTAX_ERROR_000, "Expected <)>, found <" + t->word + ">");
            return Return;
         } else if ((t = l.GetToken()) == 0) {
            PrintError (E_SYNTAX_ERROR_000, "Expected <AS>, found end statement");
            return Return;
         }
      }
      if (t->token != AS)
         PrintError (E_SYNTAX_ERROR_000, "Expected <AS>, found <" + t->word + ">");
      else {
         PString cmd;
         t = l.GetToken ();
         if (t == 0) {
            PrintError (E_SYNTAX_ERROR_000, "Unexpected end of CREATE VIEW statement");
         } else if (t->token != SELECT) {
            PrintError (E_SYNTAX_ERROR_000, "Expected <SELECT>, found <" + t->word + ">");
         } else {
            cmd = "SELECT ";
            while ((t = l.GetToken()) != 0 && t->token != WITH) {
               cmd += t->word;
               cmd += ' ';
            }
            Return = Parse (cmd.gets(), cmd.size());
            if (Return == SQL_SUCCESS && t) {
               if ((t = l.GetToken()) && t->token == CHECK &&
                   (t = l.GetToken()) && t->token == OPTION) {
                  char *tmp = new char[strlen (sqlCmd) +
                                       strlen (CHECK_OPTION) + 1];
                  strcpy (tmp, sqlCmd);
                  strcat (tmp, CHECK_OPTION);
                  delete sqlCmd;
                  sqlCmd = tmp;
               } else {
                   if (t)
                      PrintError (E_SYNTAX_ERROR_000,
                                 "Unexpected token <"+t->word+">");
                     else
                        PrintError (E_SYNTAX_ERROR_000,
                                    "Unexpected end of CREATE VIEW statement");
                  Return = SQL_ERROR;
               }
            }

            if (Return == SQL_SUCCESS) {
               for (i = 0, sr = FromList.GetFirst(); sr;
                    i++, sr = FromList.GetNext()) {
                  sr->setName (RIVCHAR + viewName + RIVCHAR +
                               sr->getName() + RIVCHAR + ToPString (i));
                  if (i > 0 && sr->joinCond == 0) {
                     PrintError (E_SYNTAX_ERROR_000,
                                 "Tables in CREATE VIEW must be joined using ON clause");
                     Return = SQL_ERROR;
                     break;
                  }
               }
            }
            if (Return == SQL_SUCCESS) {
               // Manca il controllo sulle viste ricorsive ??
               // e il controllo sulle SUBQUERY ??
               if (Params.GetItemNum() > 0) {
                  PrintError (E_SYNTAX_ERROR_000,
                              "Parameters are not allowed in CREATE VIEW");
                  Return = SQL_ERROR;
               } else if (OrderList.GetItemNum() > 0) {
                  PrintError (E_SYNTAX_ERROR_000,
                              "ORDER BY is not allowed in CREATE VIEW");
                  Return = SQL_ERROR;
               } else if (GroupList != 0) {
                  PrintError (E_SYNTAX_ERROR_000,
                              "Aggregate functions are not allowed in CREATE VIEW");
                  Return = SQL_ERROR;
               } else if (fieldsName.GetItemNum() > 0 &&
                          Selected.GetItemNum() != fieldsName.GetItemNum()) {
                  PrintError (E_SYNTAX_ERROR_000,
                              "Invalid number of fields in CREATE VIEW");
                  Return = SQL_ERROR;
               } else {
                  View.setName (viewName);
                  Expression *e;
                  ExpressionIterator ei(Selected);
                  PString *s;
                  if (fieldsName.GetItemNum() > 0)
                     for (e = Selected.GetFirst(), s = fieldsName.GetFirst();
                          e && s;
                          e = Selected.GetNext(), s = fieldsName.GetNext()){
                        e->setName(*s);
                     }
                  for (i = 0, e = Selected.GetFirst(); e; i++, e = Selected.GetNext()) {
                     for (j = 0, ei.reset(); j < i; j++, ei++)
                        if ((*ei)->getName() == e->getName()) {
                           PrintError (E_SYNTAX_ERROR_000,
                                      "Duplicated field name in CREATE VIEW");
                           Return = SQL_ERROR;
                           return Return;
                        }
                  }
               }
            }
         }
      }
   }
   Command = CREATE_VIEW;
   return Return;
}


Error
SqlParser::ExecCreateView ()
{
   PBool ckOpt = !strcmp(&sqlCmd[strlen(sqlCmd)-strlen(CHECK_OPTION)],
                         CHECK_OPTION);
   Error Return = doCreateView (ckOpt);

   if (Return == SQL_SUCCESS) {
      Expression *e;
      PString cmd = "CREATE VIEW ";
      cmd += View.getName();
      cmd += " (";

      for (e = Selected.GetFirst(); ;) {
         cmd += e->getName();
         e = Selected.GetNext();
         if (e)
            cmd += ",";
         else
            break;
      }
      cmd += ") AS ";
      cmd += sqlCmd;
      Return = DB->CreateView (this, View.getName(), cmd.gets(), ckOpt);
   }
   Clear();
   return Return;
}

Error
SqlParser::doCreateView (PBool checkOption)
{
   Error Return = SQL_SUCCESS;
   Expression *e;
   StmtRel *sr;
   RelView *newView = new RelView (View.getName(), *DB);
   PString s;
   Token *t;

/*
   for (sr = FromList.GetFirst(); sr; sr = FromList.GetNext())
      newView->addTable (sr->getName(), sr->getRel()->getName());
*/
   for (e = Selected.GetFirst(); e; e = Selected.GetNext()) {
      s = "";
      e->toString (s);
      Lex l(s.gets());
      PutKeyToken (l);
      newView->addField (e->getName(), l, *e->getValue()->getAttr());
   }
   newView->setJoin (explicitJoin);
   s = "";
   WhereStack.toString (s);
   newView->setWhere (s);
   newView->addFrom (new Token ((toknum)'(', "("));
   for (sr = FromList.GetFirst(); sr; sr = FromList.GetNext()) {
      if (sr->joinCond) {
         newView->headFrom (new Token ((toknum)'(', "("));
         newView->addFrom (new Token ((toknum)')', ")"));
         if (sr->leftJoin) {
            newView->addFrom (new Token (LEFT, "LEFT"));
            newView->addFrom (new Token (OUTER, "OUTER"));
         } else {
            newView->addFrom (new Token (INNER, "INNER"));
         }
         newView->addFrom (new Token (JOIN, "JOIN"));
         newView->addFrom (new Token (USER_NAME, sr->getRel()->getName()));
         newView->addFrom (new Token (USER_NAME, sr->getName()));
         newView->addFrom (new Token (ON, "ON"));
         s = "";
         sr->joinCond->toString(s);
         Lex w(s.gets());
         PutKeyToken (w);
         while (t = w.GetToken())
            newView->addFrom (new Token (*t));
      } else {
         newView->addFrom (new Token (USER_NAME, sr->getRel()->getName()));
         newView->addFrom (new Token (USER_NAME, sr->getName()));
      }
   }
   newView->addFrom (new Token ((toknum)')', ")"));

   PString debug;

   for (TokenIterator ti(newView->getFrom()); *ti; ti++)
      debug += (*ti)->word + ' ';

   newView->setCheckOption(checkOption);
   DB->addView (newView);
   return Return;
}

extern "C" {
#include "picoisam.h"
}

Error
SqlParser::CreateTable (Lex &l)
{
   StmtRel  *sr;
   Relation *r;
   Token *t = 0;
   Error Return = SQL_ERROR;

   Command = CREATE_TABLE;
   t = l.GetToken();
   if (t) {
      if (t->token == USER_NAME) {
         sr = getRelation (t, l);
      } else {
         PrintError (E_SYNTAX_ERROR_000, "Unexpected token<" + t->word + ">");
         return Return = SQL_ERROR;
      }
   } else {
      PrintError (E_SYNTAX_ERROR_000, "Unexpected end of statement");
      return Return = SQL_ERROR;
   }
   if (sr == 0) {
      PStringList pk;
      DelError();
      if ((Return = CreateRelation (l, t, pk)) == SQL_SUCCESS) {
         sr = getRelation (t, l);
         sr->getRel()->SetExistant();
         if (pk.GetItemNum () > 0) {
            PString *s;
            StmtAttr *sa;
            Attribute *a;
            IndexPart ip;
            int i;
            SearchIndex *is = new SearchIndex(1);

            ip.setNumber (1);
            ip.setDups (PFalse);
            for (i = 1, s = pk.GetFirst(); s; i++, s = pk.DeleteCurrent()) {
               sa = sr->getByName(*s);
               a = sa->getAttr();
               ip.setPart (i);
               a->AddIndex (ip);
               is->AddAttr (sa);
               delete s;
            }
            is->initKey ();
            sr->AddIndex (is);
         }
      } else {
        return Return;
      }
   } 
   
   FromList.AddItem (sr);
   sr->BufferStmtRelAlloc();
   sr->Clear();

   r = DB->GetRelation (sr->getName(), this);
   if (r == 0){
      PrintError (E_SYNTAX_ERROR_S02, "");
      return Return;
   }
   else
      if (r->FileOpenExists()){
         PrintError (E_SYNTAX_ERROR_S01, "");
         return Return;
      } 
      else
         Return = SQL_SUCCESS;

   return Return;
}

Error
SqlParser::primaryKey (AttributeList &al, Lex &l, PStringList &pk)
{
   Token *t;
   AttributeIterator ai(al);
   Error Return = SQL_ERROR;

   if ((t = l.GetToken()) != 0) {
      if (t->token == ',' &&
          (t = l.GetToken()) != 0 && t->token == PRIMARY &&
          (t = l.GetToken()) != 0 && t->token == KEY &&
          (t = l.GetToken()) != 0 && t->token == '(') {
         if (pk.GetItemNum () > 0) {
            PrintError (E_SYNTAX_ERROR_000,
                       "Duplicate primary key definition");
         } else {
            for ( ; ; ) {
               if ((t = l.GetToken()) == 0) {
                  PrintError (E_SYNTAX_ERROR_000,
                          "Expected token <USER_NAME>, found end statement");
                  break;
               } else if (t->token != USER_NAME) {
                  PrintError (E_SYNTAX_ERROR_000,
                             "Expected token <USER_NAME>, found <"
                             + t->word + ">");
                  break;
               } else {
                  for (ai.reset(); *ai; ai++)
                     if ((*ai)->getName() == t->word)
                        break;
                  if (*ai) {
                     pk.AddItem (new PString (t->word));
                     if ((t = l.GetToken()) == 0) {
                        PrintError (E_SYNTAX_ERROR_000,
                            "Expected token <,> or <)>, found end statement");
                        break;
                     } else if (t->token == ')') {
                        Return = SQL_SUCCESS;
                        break;
                     } else if (t->token != ',') {
                        PrintError (E_SYNTAX_ERROR_000,
                                   "Expected token <,> or <)>, found <"
                                   + t->word + ">");
                        break;
                     }
                  } else {
                     PrintError (E_SYNTAX_ERROR_000,
                            "Unknown attribute <" + t->word +
                            "> in PRIMARY KEY CLAUSE");
                     break;
                  }
               }
            }
         }
      }
   } else {
      Return = SQL_SUCCESS;
   }
   return Return;
}

Error
SqlParser::CreateRelation (Lex &l, Token *t, PStringList &pk)
{
   Error Return = SQL_ERROR;
   PString tName = t->word;
   PString fName;
   Attribute *f;
   AttributeList al;

   t = l.GetToken();
   if (t) {
      if (t->token == '(') {
         for ( ; ; ) {
            t = l.GetToken();
            if (t) {
               if (t->token == USER_NAME) {
                  fName = t->word;
                  t = l.GetToken();
                  if (t) {
                     f = 0;
                     if (t->token == CHAR_ || t->token == VARCHAR) {
                        if ((t = l.GetToken()) == 0) {
                           PrintError (E_SYNTAX_ERROR_000,
                                      "Expected <(>, found end statement");
                           break;
                        } else if (t->token != '(') {
                           PrintError (E_SYNTAX_ERROR_000,
                                      "Expected <(>, found <"
                                       + t->word + ">");
                           break;
                        } else if ((t = l.GetToken()) == 0) {
                           PrintError (E_SYNTAX_ERROR_000,
                                       "Expected NUMBER, found end statement");
                           break;
                        } else if (t->token != NUMBER) {
                           PrintError (E_SYNTAX_ERROR_000,
                                       "Expected NUMBER, found <"
                                       + t->word + ">");
                           break;
                        } else {
                           f = new Attribute (fName, 0, ATTR_ALL);
                           f->setType (T_CSTRING, atoi(t->word.gets()), 0);
                           if ((t = l.GetToken()) == 0) {
                              PrintError (E_SYNTAX_ERROR_000,
                                         "Expected <)>, found end statement");
                              break;
                           } else if (t->token != ')') {
                              PrintError (E_SYNTAX_ERROR_000,
                                         "Expected <)>, found <"
                                          + t->word + ">");
                              break;
                           }
                        }
                     } else if (t->token == NUMERIC) {
                        int len = 0;
                        int scale = 0;
                        if ((t = l.GetToken()) == 0) {
                           PrintError (E_SYNTAX_ERROR_000,
                                      "Expected <(>, found end statement");
                           break;
                        } else if (t->token != '(') {
                           PrintError (E_SYNTAX_ERROR_000,
                                      "Expected <(>, found <"
                                       + t->word + ">");
                           break;
                        } else if ((t = l.GetToken()) == 0) {
                           PrintError (E_SYNTAX_ERROR_000,
                                       "Expected NUMBER, found end statement");
                           break;
                        } else if (t->token != NUMBER) {
                           PrintError (E_SYNTAX_ERROR_000,
                                       "Expected NUMBER, found <"
                                       + t->word + ">");
                           break;
                        } else {
                           len = atoi(t->word.gets());
                           t = l.GetToken();
                           if (t == 0) {
                              PrintError (E_SYNTAX_ERROR_000,
                                         "Expected <)> or <,>, found end statement");
                              break;
                           } else if (t->token != ',') {
                              l.UngetToken();
                              scale = 0;
                           } else if ((t = l.GetToken()) == 0) {
                              PrintError (E_SYNTAX_ERROR_000,
                                         "Expected NUMBER, found end statement");
                              break;
                           } else if (t->token != NUMBER) {
                              PrintError (E_SYNTAX_ERROR_000,
                                         "Expected NUMBER, found <"
                                          + t->word + ">");
                              break;
                           } else {
                              scale = atoi(t->word.gets());
                           }
                           if (len < 1 || len > 18 || scale < 0 || scale > len) {
                              PrintError (E_SYNTAX_ERROR_000,
                                         "Malformed number " + fName);
                              break;
                           }
                           f = new Attribute (fName, 0, ATTR_ALL);
                           f->setType (T_PACKED_ORDERED, len, scale);
                           f->setSign (UNSIGNED);
                           if ((t = l.GetToken()) == 0) {
                              PrintError (E_SYNTAX_ERROR_000,
                                         "Expected <)>, found end statement");
                              break;
                           } else if (t->token != ')') {
                              PrintError (E_SYNTAX_ERROR_000,
                                         "Expected <)>, found <"
                                          + t->word + ">");
                              break;
                           }
                        }
                     } else if (t->token == SERIAL) {
                        f = new Attribute (fName, 0, ATTR_ALL);
                        f->setType (T_PACKED_ORDERED, 11, 0, PTrue);
                        f->setSign (UNSIGNED);
                     } else if (t->token == DOUBLE_) {
                        f = new Attribute (fName, 0, ATTR_ALL);
                        f->setType (T_DOUBLE, 0, 0);
                        f->setSign (INTERNAL_LEADING);
                     } else if (t->token == REAL || t->token == FLOAT_) {
                        f = new Attribute (fName, 0, ATTR_ALL);
                        f->setType (T_FLOAT, 0, 0);
                        f->setSign (INTERNAL_LEADING);
                     } else if (t->token == INTEGER || t->token == INT_) {
                        f = new Attribute (fName, 0, ATTR_ALL);
                        f->setType (T_LONG, 0, 0);
                        f->setSign (INTERNAL_LEADING);
                     } else if (t->token == SMALLINT) {
                        f = new Attribute (fName, 0, ATTR_ALL);
                        f->setType (T_SHORT, 0, 0);
                        f->setSign (INTERNAL_LEADING);
                     } else if (t->token == TIMESTAMP) {
                        f = new Attribute (fName, 0, ATTR_ALL);
                        f->setType (T_PACKED_ORDERED, strlen(TIMEST_INTFMT), 0);
                        f->setSign (UNSIGNED);
                        f->setDateFmt (TIMEST_INTFMT);
                     } else if (t->token == DATE_) {
                        f = new Attribute (fName, 0, ATTR_ALL);
                        f->setType (T_PACKED_ORDERED, strlen(DATE_INTFMT), 0);
                        f->setSign (UNSIGNED);
                        f->setDateFmt (DATE_INTFMT);
                     } else if (t->token == TIME) {
                        f = new Attribute (fName, 0, ATTR_ALL);
                        f->setType (T_PACKED_ORDERED, strlen(TIME_INTFMT), 0);
                        f->setSign (UNSIGNED);
                        f->setDateFmt (TIME_INTFMT);
                     } else if (t->token == BLOB_) {
                        f = new Attribute (fName, 0, ATTR_ALL);
                        f->setType (T_BLOB, 11, 0);
                        f->setSign (UNSIGNED);
                     } else if (t->token == CLOB) {
                        f = new Attribute (fName, 0, ATTR_ALL);
                        f->setType (T_CLOB, 11, 0);
                        f->setSign (UNSIGNED);
                     } else if (t->token == LONGVARCHAR) {
                        if (t = l.GetToken()) {
                           if (t->token == '(') {
                              if ((t = l.GetToken()) && t->token == NUMBER &&
                                  (t = l.GetToken()) && t->token == ')') {
                                 ;
                              } else {
                                 PrintError (E_SYNTAX_ERROR_000,
                                            "Invalid LONGVARCHAR declaration");
                                 break;
                              }
                           } else {
                             l.UngetToken();
                           }
                        }
                        f = new Attribute (fName, 0, ATTR_ALL);
                        f->setType (T_CLOB, 11, 0);
                        f->setSign (UNSIGNED);
                     } else {
                        PrintError(E_SYNTAX_ERROR_000,"Expected <TYPE>, found <"
                                                            + t->word + ">");
                        break;
                     }
                     if (f) {
                        if (t = l.GetToken()) {
                           if (t->token == NOT) {
                              if (t = l.GetToken()) {
                                 if (t->token == NULL_) {
                                    ;
                                 } else {
                                    PrintError (E_SYNTAX_ERROR_000,
                                               "Expected <NULL>, found <"
                                                   + t->word + ">");
                                    break;
                                 }
                              } else {
                                 PrintError (E_SYNTAX_ERROR_000,
                                    "Expected <KEY>, found <end statement>");
                                 break;
                              }
                           } else {
                              l.UngetToken();
                           }
                        }
                        if (t = l.GetToken()) {
                           if (t->token == PRIMARY) {
                              if (t = l.GetToken()) {
                                 if (t->token == KEY) {
                                    pk.AddItem (new PString(fName));
                                 } else {
                                    PrintError (E_SYNTAX_ERROR_000,
                                               "Expected <KEY>, found <"
                                                   + t->word + ">");
                                    break;
                                 }
                              } else {
                                 PrintError (E_SYNTAX_ERROR_000,
                                    "Expected <KEY>, found <end statement>");
                                 break;
                              }
                           } else {
                             l.UngetToken();
                           }
                        }
                        al.AddItem(f);
                     }
                  } else {
                     PrintError (E_SYNTAX_ERROR_000,
                                "Expected <USER NAME>, found <end statement>");
                     break;
                  }
               } else if (t->token == (toknum)',') {
                  ;
               } else if (t->token == (toknum)')') {
                  if ((Return = primaryKey (al, l, pk)) != SQL_SUCCESS) {
                     PString *s;
                     for (s = pk.GetFirst(); s; s = pk.DeleteCurrent())
                        delete (s);
                  }
                  break;
               } else {
                  PrintError (E_SYNTAX_ERROR_000, "Unexpected token <" + t->word + ">");
                  break;
               }
            } else {
               PrintError (E_SYNTAX_ERROR_000, "Unexpected end of statement");
               break;
            }
         }
      } else {
         PrintError (E_SYNTAX_ERROR_000, "Expected <(>, found <" + t->word + ">");
      }
   } else {
      PrintError (E_SYNTAX_ERROR_000, "Expected <(>, found <end statement>");
   }
   if (Return == SQL_SUCCESS) {
      Return = DB->CreateRelation (this, tName, al);
   }
   for (f = al.GetFirst(); f; f = al.DeleteCurrent())
      delete f;
   return Return;
}

Error
SqlParser::DropTable (Lex &l)
{  
   StmtRel  *sr;
   Relation *r;
   Token *t = 0;
   Error Return = SQL_ERROR;

   Return = From (l, PFalse); 
   if (Return != SQL_SUCCESS)
      return Return;
   sr = FromList.GetFirst();
   if (sr == 0) {
      PrintError (E_SYNTAX_ERROR_S02, "" );
      return Return;
   }
   sr->BufferStmtRelAlloc();
   sr->Clear();

   r = DB->GetRelation (sr->getName(), this);
   if (r == 0){
      PrintError (E_SYNTAX_ERROR_S02, "");
      return Return;
   }
   else
      if ( ! r->FileOpenExists()){
         PrintError (E_SYNTAX_ERROR_S02, "Base table not found");
         return Return;
      } 
      else
         Return = SQL_SUCCESS;

   return Return;
}

Error
SqlParser::DropView (Lex &l)
{
   RelView *rv;
   Token *t = 0;
   Error Return = SQL_ERROR;

   t = l.GetToken();
   if (t) {
      if (t->token == USER_NAME) {
         rv = DB->GetRelView (t->word);
         if (rv == 0)
            PrintError (E_SYNTAX_ERROR_000, "View not found <"+ t->word + ">");
         else {
            ViewList.AddItem (new StmtRelView (*rv));
            Return = SQL_SUCCESS;
         }
      } else {
         PrintError (E_SYNTAX_ERROR_000,
                    "Expected <USER NAME>, found <"+ t->word + ">");
      }
   } else {
      PrintError (E_SYNTAX_ERROR_000,
                 "Expected <USER NAME>, found <end statement>");
   }
   return Return;
}

Error
SqlParser::CreateIndex (Lex &l, PBool unique)
{
   StmtRel  *sr;
   Token *t = 0;
   Error Return = SQL_ERROR;

   if (unique)
      Command = CREATE_UNIQUE_INDEX;
   else
      Command = CREATE_INDEX;
   if ((t = l.GetToken()) == 0) {
      PrintError (E_SYNTAX_ERROR_000, "Expected token <USER_NAME>, found end statement");
   } else if (t->token != USER_NAME) {
      PrintError (E_SYNTAX_ERROR_000, "Expected token <USER_NAME>, found <" + t->word + ">");
   } else  if ((t = l.GetToken()) == 0) {
      PrintError (E_SYNTAX_ERROR_000, "Expected token ON, found end statement");
   } else if (t->token != ON) {
      PrintError (E_SYNTAX_ERROR_000, "Expected token ON, found <" + t->word + ">");
   } else if (From (l, PFalse) == SQL_SUCCESS) {
      sr = FromList.GetFirst();
      sr->BufferStmtRelAlloc();
      sr->Clear();
      if ((t = l.GetToken()) == 0) {
         PrintError (E_SYNTAX_ERROR_000, "Expected token <(>, found end statement");
      } else if (t->token != '(') {
         PrintError (E_SYNTAX_ERROR_000, "Expected token <(>, found <" + t->word + ">");
      } else {
         PString dummy;
         for ( ; ; ) {
            if ((t = l.GetToken()) == 0) {
               PrintError (E_SYNTAX_ERROR_000,
                          "Expected token <USER_NAME>, found end statement");
               break;
            } else if (t->token != USER_NAME) {
               PrintError (E_SYNTAX_ERROR_000, "Expected token <USER_NAME>, found <"
                           + t->word + ">");
               break;
            } else if (AddField (t->word, dummy, dummy) != SQL_SUCCESS) {
               break;
            }
            if ((t = l.GetToken()) == 0) {
               PrintError (E_SYNTAX_ERROR_000,
                          "Expected token <,> or <)>, found end statement");
               break;
            }
            if (t->token == ASC) {
               if ((t = l.GetToken()) == 0) {
                  PrintError (E_SYNTAX_ERROR_000,
                             "Expected token <,> or <)>, found end statement");
                  break;
               }
            } else if (t->token == DESC) {
               PrintError (E_SYNTAX_ERROR_000,
                          "<DESC> keyword not supported!");
               break;
            }
            if (t->token == ')') {
               Return = SQL_SUCCESS;
               break;
            } else if (t->token != ',') {
               PrintError (E_SYNTAX_ERROR_000, "Expected token <,> or <)>, found <"
                           + t->word + ">");
               break;
            }
         }
      }
   }
   return Return;
}

Error
SqlParser::DropIndex (Lex &l)
{
   StmtRel  *sr;
   Token *t = 0;
   Error Return = SQL_ERROR;

   Command = DROP_INDEX;
   if ((t = l.GetToken()) == 0) {
      PrintError (E_SYNTAX_ERROR_000, "Unexpected end of statement");
   } else if (t->token != USER_NAME) {
      PrintError (E_SYNTAX_ERROR_000, 
                             "Expected <USER_NAME>, found <" + t->word + ">");
   } else {
      PString indexNum;
      PString indexName = t->word;
      indexNum = t->word(t->word.size() - 2, 2);
      t->word = t->word(0, t->word.size() - 3);
      if ((sr = getRelation (t, l)) == 0) {
         PrintError (E_SYNTAX_ERROR_000, "Index not found <" + indexName + ">");
      } else if (atoi(indexNum.gets()) <= 0) {
         PrintError (E_SYNTAX_ERROR_000, "Index not found <" + indexName + ">");
      } else {
         Token tk (NUMBER, indexNum);
         FromList.AddItem (sr);
         Selected.AddItem (new Expression (*DB, tk));
         Return = SQL_SUCCESS;
      }
   }
   return Return;
}

Error
SqlParser::ExecCreateTable ()
{
   StmtAttr *sa;
   SearchIndex *idx;
   Error Return = SQL_SUCCESS;
   IndexPart *ip;

   StmtRel *sr = FromList.GetFirst();
   ClearExec ();
   for (sa = sr->GetFirstField(); sa != 0;
        sa = sr->GetNextField())
      for (ip = sa->getAttr()->GetFirstIndex(); ip;
           ip = sa->getAttr()->GetNextIndex())
         if (ip->getPart() == 1) {
            idx = new SearchIndex (ip->getNumber());
            idx->AddAttr (sa);
            idx->initKey ();
            sr->AddIndex (idx);
         }
   Return = sr->Create();
   if (Return != SQL_SUCCESS) {
      PrintError (E_GENERAL_ERROR_000, "Error creating table", sr->getStatus());
      Return = SQL_ERROR;
   }
   return Return;
}

Error
SqlParser::ExecDropTable ()
{
   Error Return = SQL_SUCCESS;
   StmtRel *sr = FromList.GetFirst();
   Relation *r = sr->getRel();

   ClearExec ();
   while (DB->UnloadOpenCache())
      ;
   Return = sr->Drop();
   if (Return != SQL_SUCCESS) {
      PrintError (E_GENERAL_ERROR_000, "Error dropping table",sr->getStatus());
      Return = SQL_ERROR;
   } else {
      Return = DB->DropRelation (this, r);
      Clear();
   }
   return Return;
}


Error
SqlParser::ExecDropView ()
{
   Error Return = SQL_SUCCESS;
   RelObject *ro = ViewList.GetFirst()->getRelView();

   ClearExec ();
   Return = DB->DropView (this, ro);
   Clear();
   return Return;
}


Error
SqlParser::ExecCreateIndex ()
{
   Error Return = SQL_ERROR; 
   StmtRel *sr = FromList.GetFirst();
   StmtAttr *sa;
   Attribute *a;
   struct keydesc key;
   int offset = -1;
   int type, lastType = MAXTYPE;
 
   ClearExec ();
   while (DB->UnloadOpenCache())
      ;

   if (Command == CREATE_UNIQUE_INDEX)
      key.k_flags = ISNODUPS;
   else
      key.k_flags = ISDUPS;
   key.k_nparts = 0;
   for (sa = Fields.GetFirst(); sa; sa = Fields.GetNext()) {
      a = sa->getAttr();
      switch (a->GetType()) {
      case T_SHORT:
         type = INTTYPE;
         break;
      case T_LONG:
         type = LONGTYPE;
         break;
      case T_FLOAT:
         type = FLOATTYPE;
         break;
      case T_DOUBLE:
         type = DOUBLETYPE;
         break;
      default:
         type = CHARTYPE;
         break;
      }
      if (type==lastType && type==CHARTYPE && a->getFldPos() == offset) {
         key.k_part[key.k_nparts - 1].kp_leng += (short)a->getFldSize();
         offset += a->getFldSize();
      } else if (key.k_nparts < NPARTS) {
         key.k_part[key.k_nparts].kp_type = type;
         key.k_part[key.k_nparts].kp_start = (short)a->getFldPos();
         key.k_part[key.k_nparts].kp_leng = (short)a->getFldSize();
         offset = key.k_part[key.k_nparts].kp_start +
                  key.k_part[key.k_nparts].kp_leng;
         key.k_nparts++;
      } else
         break;
      lastType = type;
   }
   if (key.k_nparts > 0) {
      if (sr->Open() != SQL_SUCCESS) {
         PrintError (E_GENERAL_ERROR_000, "Error opening table in CREATE INDEX",
                                          sr->getStatus());
      } else {
         int isfd = sr->getFsId().id_isam;
         if (pIsaddindex (isfd, &key) != 0) {
            PrintError (E_GENERAL_ERROR_000, "Error creating index",
                                           pIserrno);
         } else {
            /*
            sr->ReloadRelation(this);
            */
            int i;
            IndexPart ip, *pip;
            int indexNum = 1; /* 0 == PrimaryKey */
            for (sa = sr->GetFirstField(); sa != 0;
                 sa = sr->GetNextField())
               for (pip = sa->getAttr()->GetFirstIndex(); pip;
                    pip = sa->getAttr()->GetNextIndex())
                  if (pip->getNumber() > indexNum)
                     indexNum = pip->getNumber();
            indexNum++;
            /*
            SearchIndex *is = new SearchIndex(indexNum);
            */
            
            ip.setNumber (indexNum);
            ip.setDups (Command != CREATE_UNIQUE_INDEX);
            for (i = 1,sa = Fields.GetFirst(); sa; i++,sa = Fields.GetNext()) {
               a = sa->getAttr();
               ip.setPart (i);
               a->AddIndex (ip);
               // is->AddAttr (sa);
            }
            Return = SQL_SUCCESS;
         }
         sr->Close();
      }
   } else {
       PrintError (E_GENERAL_ERROR_000, "void index");
   }
   return Return;
}

Error
SqlParser::ExecDropIndex ()
{
   Error Return = SQL_ERROR; 
   StmtRel *sr = FromList.GetFirst();
   StmtAttr *sa;
   struct keydesc key;
   long dummy = 0;
   short indexNum = 0;
   
 
   ClearExec ();
   while (DB->UnloadOpenCache())
      ;

   sa = Selected.GetFirst()->getValue();
   sa->ToShort (indexNum, dummy);
   if (sr->Open() != SQL_SUCCESS) {
      PrintError (E_GENERAL_ERROR_000, "Error opening table in DROP INDEX",
                                          sr->getStatus());
   } else {
      int isfd = sr->getFsId().id_isam;
      if (pIsindexinfo (isfd, &key, indexNum) != 0) {
          PrintError (E_GENERAL_ERROR_000, "Error finding index", pIserrno);
      } else if (pIsdelindex (isfd, &key) != 0) {
          PrintError (E_GENERAL_ERROR_000, "Error dropping index", pIserrno);
      } else {
         sr->ReloadRelation(this);
         Return = SQL_SUCCESS;
      }
      sr->Close();
   }
   return Return;
}

Error
SqlParser::AlterTable (Lex &l)
{
   Error Return = SQL_ERROR;
   Token *t;
   StmtRel *sr ;
   Relation *r;

   /*
   t = l.GetToken();
   if (t) {
      if (t->token == USER_NAME) {
         sr = getRelation (t, l);
         if (sr == 0) {
            PrintError (E_SYNTAX_ERROR_000,"Unknown table <" + t->word + ">");
            return Return = SQL_ERROR;
         }
      } else {
         PrintError (E_SYNTAX_ERROR_000, "Unexpected token<" + t->word + ">");
         return Return = SQL_ERROR;
      }
   } else {
      PrintError (E_SYNTAX_ERROR_000, "Unexpected end of statement");
      return Return = SQL_ERROR;
   }
   */

   Return = From (l, PFalse); 
   if (Return != SQL_SUCCESS)
      return Return;
   sr = FromList.GetFirst();
   if (sr == 0) {
      PrintError (E_SYNTAX_ERROR_S02, "" );
      return Return;
   }
   sr->BufferStmtRelAlloc();
   sr->Clear();

   r = DB->GetRelation (sr->getName(), this);
   if (r == 0){
      PrintError (E_SYNTAX_ERROR_S02, "");
      return Return;
   } else if ( ! r->FileOpenExists()){
      PrintError (E_SYNTAX_ERROR_S02, "Base table not found");
      return Return;
   }

   if ((t = l.GetToken()) == 0)
      PrintError (E_SYNTAX_ERROR_000, "Expected keyword, found <end_statement>");
   else if (t->token == ADD) {
      Return = AlterTableAdd (l, sr);
      Command = ALTER_TABLE_ADD;
   } else if (t->token == DROP) {
      Return = AlterTableDrop (l, sr);
      Command = ALTER_TABLE_DROP;
   } else if (t->token == RENAME) {
      Return = AlterTableRename (l, sr);
      Command = ALTER_TABLE_RENAME;
   } else {
      PrintError (E_SYNTAX_ERROR_000, "Unexpected token <" + t->word + ">" );
   }
   return Return;
}

Attribute *
SqlParser::AttrDefinition (Lex &l,  Token *t)
{
   Attribute *Return = 0;
   PString fName;

   fName = t->word;
   t = l.GetToken();
   if (t) {
      Return = 0;
      if (t->token == CHAR_ || t->token == VARCHAR) {
         if ((t = l.GetToken()) == 0) {
            PrintError (E_SYNTAX_ERROR_000,
                                    "Expected <(>, found end statement");
         } else if (t->token != '(') {
            PrintError (E_SYNTAX_ERROR_000,
                                    "Expected <(>, found <" + t->word + ">");
         } else if ((t = l.GetToken()) == 0) {
            PrintError (E_SYNTAX_ERROR_000,
                                    "Expected NUMBER, found end statement");
         } else if (t->token != NUMBER) {
            PrintError (E_SYNTAX_ERROR_000,
                                  "Expected NUMBER, found <" + t->word + ">");
         } else {
            Return = new Attribute (fName, 0, ATTR_ALL);
            Return->setType (T_CSTRING, atoi(t->word.gets()), 0);
            if ((t = l.GetToken()) == 0) {
               PrintError (E_SYNTAX_ERROR_000,
                                   "Expected <)>, found end statement");
            } else if (t->token != ')') {
               PrintError (E_SYNTAX_ERROR_000, "Expected <)>, found <" +
                                               t->word + ">");
            }
         }
      } else if (t->token == NUMERIC) {
         int len = 0;
         int scale = 0;
         if ((t = l.GetToken()) == 0) {
            PrintError (E_SYNTAX_ERROR_000,
                        "Expected <(>, found end statement");
         } else if (t->token != '(') {
            PrintError (E_SYNTAX_ERROR_000, "Expected <(>, found <" +
                                             t->word + ">");
         } else if ((t = l.GetToken()) == 0) {
            PrintError (E_SYNTAX_ERROR_000,
                                      "Expected NUMBER, found end statement");
         } else if (t->token != NUMBER) {
            PrintError (E_SYNTAX_ERROR_000, "Expected NUMBER, found <" +
                                             t->word + ">");
         } else {
            len = atoi(t->word.gets());
            t = l.GetToken();
            if (t == 0) {
               PrintError (E_SYNTAX_ERROR_000,
                                   "Expected <)> or <,>, found end statement");
            } else if (t->token != ',') {
               l.UngetToken();
               scale = 0;
            } else if ((t = l.GetToken()) == 0) {
               PrintError (E_SYNTAX_ERROR_000,
                                     "Expected NUMBER, found end statement");
            } else if (t->token != NUMBER) {
               PrintError (E_SYNTAX_ERROR_000, "Expected NUMBER, found <" +
                                                t->word + ">");
            } else {
               scale = atoi(t->word.gets());
            }
            if (len < 1 || len > 18 || scale < 0 || scale > len) {
               PrintError (E_SYNTAX_ERROR_000, "Malformed number " + fName);
            }
            Return = new Attribute (fName, 0, ATTR_ALL);
            Return->setType (T_PACKED_ORDERED, len, scale);
            Return->setSign (UNSIGNED);
            if ((t = l.GetToken()) == 0) {
               PrintError (E_SYNTAX_ERROR_000,
                                         "Expected <)>, found end statement");
            } else if (t->token != ')') {
               PrintError (E_SYNTAX_ERROR_000, "Expected <)>, found <" +
                                                t->word + ">");
            }
         }
      } else if (t->token == DOUBLE_) {
         Return = new Attribute (fName, 0, ATTR_ALL);
         Return->setType (T_DOUBLE, 0, 0);
         Return->setSign (INTERNAL_LEADING);
      } else if (t->token == REAL) {
         Return = new Attribute (fName, 0, ATTR_ALL);
         Return->setType (T_FLOAT, 0, 0);
         Return->setSign (INTERNAL_LEADING);
      } else if (t->token == INTEGER || t->token == INT_) {
         Return = new Attribute (fName, 0, ATTR_ALL);
         Return->setType (T_LONG, 0, 0);
         Return->setSign (INTERNAL_LEADING);
      } else if (t->token == SMALLINT) {
         Return = new Attribute (fName, 0, ATTR_ALL);
         Return->setType (T_SHORT, 0, 0);
         Return->setSign (INTERNAL_LEADING);
      } else if (t->token == TIMESTAMP) {
         Return = new Attribute (fName, 0, ATTR_ALL);
         Return->setType (T_PACKED_ORDERED, strlen(TIMEST_INTFMT), 0);
         Return->setSign (UNSIGNED);
         Return->setDateFmt (TIMEST_INTFMT);
      } else if (t->token == DATE_) {
         Return = new Attribute (fName, 0, ATTR_ALL);
         Return->setType (T_PACKED_ORDERED, strlen(DATE_INTFMT), 0);
         Return->setSign (UNSIGNED);
         Return->setDateFmt (DATE_INTFMT);
      } else if (t->token == TIME) {
         Return = new Attribute (fName, 0, ATTR_ALL);
         Return->setType (T_PACKED_ORDERED, strlen(TIME_INTFMT), 0);
         Return->setSign (UNSIGNED);
         Return->setDateFmt (TIME_INTFMT);
      } else if (t->token == BLOB_) {
         Return = new Attribute (fName, 0, ATTR_ALL);
         Return->setType (T_BLOB, 11, 0);
         Return->setSign (UNSIGNED);
      } else if (t->token == CLOB) {
         Return = new Attribute (fName, 0, ATTR_ALL);
         Return->setType (T_CLOB, 11, 0);
         Return->setSign (UNSIGNED);
      } else {
         PrintError (E_SYNTAX_ERROR_000, "Expected <TYPE>, found <" +
                                          t->word + ">");
      }
   }
   return Return;
}

Error
SqlParser::AlterTableAdd (Lex &l, StmtRel *sr)
{
   Error Return = SQL_ERROR;
   Attribute *f;
   Token *t;

   while ((t = l.GetToken()) && t->token == COLUMN)
      ;
   if (t) {
      if (t->token == USER_NAME) {
         if (f = AttrDefinition(l, t)) {
            StmtAttr *sa;
            for (sa = sr->GetFirstField(); sa; sa = sr->GetNextField())
               if (sa->getAttr()->getName() == t->word)
                  break;
            if (sa == 0) {
               Info.AddItem (new StmtAttr (*DB, *f));
               Return = SQL_SUCCESS;
            } else {
               PrintError (E_SYNTAX_ERROR_000, 
                             "Attribute already existing<" + t->word + ">");
            }
            delete f;
         }
      } else {
         PrintError (E_SYNTAX_ERROR_000, 
                             "Expected <USER_NAME>, found <" + t->word + ">");
      }
   } else {
      PrintError (E_SYNTAX_ERROR_000, "Unexpected end of statement");
   }
   return Return;
}

Error
SqlParser::AlterTableDrop (Lex &l, StmtRel *sr)
{
   Error Return = SQL_ERROR;
   Token *t;

   while ((t = l.GetToken()) && t->token == COLUMN)
      ;
   if (t) {
      if (t->token == USER_NAME) {
         StmtAttr *sa;
         for (sa = sr->GetFirstField(); sa; sa = sr->GetNextField())
            if (sa->getAttr()->getName() == t->word)
               break;
         if (sa) {
            Selected.AddItem (new Expression (this, sa));
            Return = SQL_SUCCESS;
         } else {
            PrintError (E_SYNTAX_ERROR_000, 
                             "Unknown attribute <" + t->word + ">");
         }
      } else {
         PrintError (E_SYNTAX_ERROR_000, 
                             "Expected <USER_NAME>, found <" + t->word + ">");
      }
   } else {
      PrintError (E_SYNTAX_ERROR_000, "Unexpected end of statement");
   }
   return Return;
}

Error
SqlParser::AlterTableRename (Lex &l, StmtRel *sr)
{
   Error Return = SQL_ERROR;
   Token *t = l.GetToken();

   if (t) {
      if (t->token == USER_NAME) {
         Token tt(STR_LITERAL, "\"" + t->word + "\"");
         Selected.AddItem (new Expression (*DB, tt));
         Return = SQL_SUCCESS;
      } else {
         PrintError (E_SYNTAX_ERROR_000, 
                             "Unknown attribute <" + t->word + ">");
      }
   } else {
      PrintError (E_SYNTAX_ERROR_000, "Unexpected end of statement");
   }
   return Return;
}

Error
SqlParser::ExecAlterTableRename ()
{
   Error Return = SQL_SUCCESS;
   StmtRel *sr = FromList.GetFirst();
   PString oldName = sr->getName();
   PString newName = Selected.GetFirst()->getName();

   ClearExec ();
   if (sr->Rename (newName.gets()) == 0) {
      Return = DB->RenameRelation (this, oldName.gets(), sr->getRel());
      Clear();
   } else {
      PrintError (E_GENERAL_ERROR_000, "Cannot alter table name",
                  sr->getStatus());
      Return = SQL_ERROR;
   }
   return Return;
}

Error
SqlParser::ExecAlterTableDrop ()
{
   Error Return = SQL_SUCCESS;
   StmtRel *sr = FromList.GetFirst();
   StmtAttr *dropField = Selected.GetFirst()->getValue();
   StmtAttr *sa;
   PString tmpName;
   SqlParser drop(DB);
   PString cmd1 = "create table ";
   PString cmd2 = "insert into ";
   PString cmd3 = "drop table ";
   PString cmd4 = "alter table ";
   static int cnt = 0;

   ClearExec ();
   
   tmpName.prints("_T%d_%d", getpid(), cnt++);
   cmd1 += tmpName;
   cmd1 += "(";

   for (sa = sr->GetFirstField(); sa; sa = sr->GetNextField()) {
      if (sa != dropField) {
         cmd1 += sa->getAttr()->getName();
         cmd1 += " ";
         cmd1 += sa->getAttr()->getCreateDesc();
         cmd1 += ",";
      }
   }
   cmd1[cmd1.size() - 1] = ')';

   cmd2 += tmpName;
   cmd2 += "(";
   for (sa = sr->GetFirstField(); sa; sa = sr->GetNextField()) {
      if (sa != dropField) {
         cmd2 += sa->getAttr()->getName();
         cmd2 += ",";
      }
   }
   cmd2[cmd2.size() - 1] = ')';
   cmd2 += " select ";
   for (sa = sr->GetFirstField(); sa; sa = sr->GetNextField()) {
      if (sa != dropField) {
         cmd2 += sa->getAttr()->getName();
         cmd2 += ",";
      }
   }
   cmd2[cmd2.size() - 1] = ' ';
   cmd2 += "from ";
   cmd2 += sr->getName();

   cmd3 += sr->getName();

   cmd4 += tmpName;
   cmd4 += " rename ";
   cmd4 += sr->getName();

   FromList.DeleteCurrent();
   delete sr;
   Parsed = PFalse;

   if ((Return = drop.Parse (cmd1.gets(), SQL_NTS)) != SQL_SUCCESS ||
       (Return = drop.Exec ()) != SQL_SUCCESS ||
       (Return = drop.Parse (cmd2.gets(), SQL_NTS)) != SQL_SUCCESS ||
       (Return = drop.Exec ()) != SQL_SUCCESS ||
       (Return = drop.Parse (cmd3.gets(), SQL_NTS)) != SQL_SUCCESS ||
       (Return = drop.Exec ()) != SQL_SUCCESS ||
       (Return = drop.Parse (cmd4.gets(), SQL_NTS)) != SQL_SUCCESS ||
       (Return = drop.Exec ()) != SQL_SUCCESS)
      MoveStmtError (this, &drop);
   return Return;
}


Error
SqlParser::ExecAlterTableAdd ()
{
   Error Return = SQL_SUCCESS;
   StmtRel *sr = FromList.GetFirst();
   StmtAttr *addField = Info.GetFirst();
   StmtAttr *sa;
   PString tmpName;
   SqlParser add(DB);
   PString cmd1 = "create table ";
   PString cmd2 = "insert into ";
   PString cmd3 = "drop table ";
   PString cmd4 = "alter table ";
   static int cnt = 0;

   ClearExec ();
   
   tmpName.prints("_T%d_%d", getpid(), cnt++);
   cmd1 += tmpName;
   cmd1 += "(";

   for (sa = sr->GetFirstField(); sa; sa = sr->GetNextField()) {
      cmd1 += sa->getAttr()->getName();
      cmd1 += " ";
      cmd1 += sa->getAttr()->getCreateDesc();
      cmd1 += ",";
   }
   cmd1 += addField->getAttr()->getName();
   cmd1 += " ";
   cmd1 += addField->getAttr()->getCreateDesc();
   cmd1 += ")";

   cmd2 += tmpName;
   cmd2 += "(";
   for (sa = sr->GetFirstField(); sa; sa = sr->GetNextField()) {
      cmd2 += sa->getAttr()->getName();
      cmd2 += ",";
   }
   cmd2[cmd2.size() - 1] = ')';
   cmd2 += " select ";
   for (sa = sr->GetFirstField(); sa; sa = sr->GetNextField()) {
      cmd2 += sa->getAttr()->getName();
      cmd2 += ",";
   }
   cmd2[cmd2.size() - 1] = ' ';
   cmd2 += "from ";
   cmd2 += sr->getName();

   cmd3 += sr->getName();

   cmd4 += tmpName;
   cmd4 += " rename ";
   cmd4 += sr->getName();

   FromList.DeleteCurrent();
   delete sr;
   Parsed = PFalse;

   if ((Return = add.Parse (cmd1.gets(), SQL_NTS)) != SQL_SUCCESS ||
       (Return = add.Exec ()) != SQL_SUCCESS ||
       (Return = add.Parse (cmd2.gets(), SQL_NTS)) != SQL_SUCCESS ||
       (Return = add.Exec ()) != SQL_SUCCESS ||
       (Return = add.Parse (cmd3.gets(), SQL_NTS)) != SQL_SUCCESS ||
       (Return = add.Exec ()) != SQL_SUCCESS ||
       (Return = add.Parse (cmd4.gets(), SQL_NTS)) != SQL_SUCCESS ||
       (Return = add.Exec ()) != SQL_SUCCESS)
      MoveStmtError (this, &add);
   return Return;
}
