Diff for /parser3/src/classes/table.C between versions 1.171 and 1.181

version 1.171, 2002/12/14 12:47:29 version 1.181, 2003/04/25 12:32:31
Line 1 Line 1
 /** @file  /** @file
         Parser: @b table parser class.          Parser: @b table parser class.
   
         Copyright (c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com)          Copyright (c) 2001, 2003 ArtLebedev Group (http://www.artlebedev.com)
         Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)          Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
 */  */
   
Line 30  public: // Methoded Line 30  public: // Methoded
   
 // methods  // methods
   
 static void get_copy_options(Request& r, const String& method_name, MethodParams *params, int param_index,  static Table::Action_options get_action_options(Request& r, 
                                                          const Table& source,                                       const String& method_name, MethodParams *params, 
                                                          int& offset,                                       const Table& source) {
                                                          int& limit) {          Table::Action_options result;
         offset=0;  
         limit=0;          if(!params->size())
         if(params->size()<=param_index)                  return result;
                 return;  
           Hash* options=params->get(params->size()-1).get_hash(&method_name);
         Value& voptions=params->as_no_junction(param_index, "options must be hash, not code");          if(!options)
         if(!voptions.is_string()) {                  return result;
                 if(Hash *options=voptions.get_hash(&method_name)) {  
                         int valid_options=0;          result.defined=true;
                         if(Value *voffset=(Value *)options->get(*sql_offset_name)) {          bool defined_offset=false;
                                 valid_options++;  
                                 if(voffset->is_string()) {          int valid_options=0;
                                         const String& soffset=*voffset->get_string();          if(Value *voffset=(Value *)options->get(*sql_offset_name)) {
                                         if(soffset == "cur")                  valid_options++;
                                                 offset=source.current();                  defined_offset=true;
                                         else                  if(voffset->is_string()) {
                                                 throw Exception("parser.runtime",                          const String& soffset=*voffset->get_string();
                                                         &soffset,                          if(soffset == "cur")
                                                         "must be 'cur' string or expression");                                  result.offset=source.current();
                                 } else                           else
                                         offset=r.process_to_value(*voffset).as_int();  
                         }  
                         if(Value *vlimit=(Value *)options->get(*sql_limit_name)) {  
                                 valid_options++;  
                                 limit=r.process_to_value(*vlimit).as_int();  
                         }  
                         if(valid_options!=options->size())  
                                 throw Exception("parser.runtime",                                  throw Exception("parser.runtime",
                                         &method_name,                                          &soffset,
                                         "called with invalid option");                                          "must be 'cur' string or expression");
                 } else                  } else 
                         throw Exception("parser.runtime",                          result.offset=r.process_to_value(*voffset).as_int();
                                 &method_name,          }
                                 "options must be hash");          if(Value *vlimit=(Value *)options->get(*sql_limit_name)) {
                   valid_options++;
                   result.limit=r.process_to_value(*vlimit).as_int();
           }
           if(Value *vreverse=(Value *)options->get(*table_reverse_name)) {
                   valid_options++;
                   result.reverse=r.process_to_value(*vreverse).as_bool();
                   if(result.reverse && !defined_offset)
                           result.offset=source.size()-1;
         }          }
         if(!limit) // zero limit = sould be 'nothing to copy', for methods zero means 'all'          if(valid_options!=options->size())
                 limit=-1; // thus fixing                  throw Exception("parser.runtime",
                           &method_name,
                           "called with invalid option");
   
           return result;
   }
   static void check_option_param(bool options_defined, 
                             const String& method_name, MethodParams *params, 
                             int next_param_index,
                             const char *msg) {
           if(next_param_index+(options_defined?1:0) != params->size())
                   throw Exception("parser.runtime",
                           &method_name,
                           "%s", msg);
 }  }
   
 static void _create(Request& r, const String& method_name, MethodParams *params) {  static void _create(Request& r, const String& method_name, MethodParams *params) {
         Pool& pool=r.pool();          Pool& pool=r.pool();
         // clone/copy part?          // clone/copy part?
         if(const Table *source=params->get(0).get_table()) {          if(const Table *source=params->get(0).get_table()) {
                 int offset, limit;                  Table::Action_options o=get_action_options(r, method_name, params, *source);
                 get_copy_options(r, method_name, params, 1, *source,                   check_option_param(o.defined, method_name, params, 1, 
                         offset, limit);                          "too many parameters");
                 static_cast<VTable *>(r.get_self())->set_table(*new(pool) Table(pool, *source, offset, limit));                  static_cast<VTable *>(r.get_self())->
                           set_table(*new(pool) Table(pool, *source, o));
                 return;                  return;
         }          }
   
Line 310  static void _menu(Request& r, const Stri Line 325  static void _menu(Request& r, const Stri
 }  }
   
 #ifndef DOXYGEN  #ifndef DOXYGEN
   enum Table2hash_distint { D_ILLEGAL, D_FIRST, D_TABLES };
 struct Row_info {  struct Row_info {
         Request *r;          Request *r;
         Table *table;          Table *table;
Line 317  struct Row_info { Line 333  struct Row_info {
         int key_field;          int key_field;
         Array *value_fields;          Array *value_fields;
         Hash *hash;          Hash *hash;
         bool distinct;          Table2hash_distint distinct;
         int row;          int row;
 };  };
 #endif  #endif
Line 337  static void table_row_to_hash(Array::Ite Line 353  static void table_row_to_hash(Array::Ite
         if(!key)          if(!key)
                 return; // ignore rows without key [too-short-record_array if-indexed]                  return; // ignore rows without key [too-short-record_array if-indexed]
                                   
         VHash& result=*new(pool) VHash(pool);          switch(ri.distinct) {
         Hash& hash=*result.get_hash(0);          case D_ILLEGAL: case D_FIRST:
         for(int i=0; i<ri.value_fields->size(); i++) {                  {
                 int value_field=ri.value_fields->get_int(i);                          VHash& result=*new(pool) VHash(pool);
                 if(value_field<row.size())                          Hash& hash=*result.get_hash(0);
                         hash.put(                          for(int i=0; i<ri.value_fields->size(); i++) {
                                 *ri.table->columns()->get_string(value_field),                                   int value_field=ri.value_fields->get_int(i);
                                 new(pool) VString(*row.get_string(value_field)));                                  if(value_field<row.size())
                                           hash.put(
                                                   *ri.table->columns()->get_string(value_field), 
                                                   new(pool) VString(*row.get_string(value_field)));
                           }
   
                           if(ri.hash->put_dont_replace(*key, &result)) // put. existed?
                                   if(ri.distinct==D_ILLEGAL)
                                           throw Exception("parser.runtime",
                                                   key,
                                                   "duplicate key");
                   }
                   break;
           case D_TABLES:
                   {
                           VTable* vtable=(VTable*)ri.hash->get(*key); // put. table existed?
                           Table* table;
                           if(vtable) 
                                   table=vtable->get_table();
                           else {
                                   // no? creating table of same structure as source
                                   Table::Action_options table_options(0, 0);
                                   table=new(pool) Table(pool, *ri.table, table_options/*no rows, just structure*/);
                                   ri.hash->put(*key, new(pool) VTable(pool, table));
                           }
                           *table+=&row;
                   }
                   break;
           default:
                   throw Exception(0,
                           0,
                           "invalid distinct code (#%d)", ri.distinct);
         }          }
   
         if(ri.hash->put_dont_replace(*key, &result)) // put. existed?  
                 if(!ri.distinct)  
                         throw Exception("parser.runtime",  
                                 key,  
                                 "duplicate key");  
 }  }
 static void _hash(Request& r, const String& method_name, MethodParams *params) {  static void _hash(Request& r, const String& method_name, MethodParams *params) {
         Pool& pool=r.pool();          Pool& pool=r.pool();
Line 359  static void _hash(Request& r, const Stri Line 401  static void _hash(Request& r, const Stri
         Value& result=*new(pool) VHash(pool);          Value& result=*new(pool) VHash(pool);
         if(const Array *columns=self_table.columns())          if(const Array *columns=self_table.columns())
                 if(columns->size()>0) {                  if(columns->size()>0) {
                         bool distinct=false;                          Table2hash_distint distinct=D_ILLEGAL;
                         int param_index=params->size()-1;                          int param_index=params->size()-1;
                         if(param_index>0) {                          if(param_index>0) {
                                 if(Hash *options=                                  if(Hash *options=
                                         params->as_no_junction(param_index, "param must not be code").get_hash(0)) {                                          params->as_no_junction(param_index, "param must not be code").get_hash(0)) {
                                         --param_index;                                          --param_index;
                                         int valid_options=0;                                          int valid_options=0;
                                         if(Value *vdistinct=(Value *)options->get(*sql_distinct_name)) {                                          if(Value *vdistinct_code=(Value *)options->get(*sql_distinct_name)) {
                                                 valid_options++;                                                  valid_options++;
                                                 distinct=r.process_to_value(*vdistinct).as_bool();                                                  Value& vdistinct_value=r.process_to_value(*vdistinct_code);
                                                   if(vdistinct_value.is_string()) {
                                                           const String& sdistinct=*vdistinct_value.get_string();
                                                           if(sdistinct=="tables")
                                                                   distinct=D_TABLES;
                                                           else
                                                                   throw Exception("parser.runtime",
                                                                           &sdistinct,
                                                                           "must be 'tables' or true/false");
                                                   } else
                                                           distinct=vdistinct_value.as_bool()?D_FIRST:D_ILLEGAL;
                                         }                                          }
                                         if(valid_options!=options->size())                                          if(valid_options!=options->size())
                                                 throw Exception("parser.runtime",                                                  throw Exception("parser.runtime",
Line 383  static void _hash(Request& r, const Stri Line 435  static void _hash(Request& r, const Stri
   
                         Array value_fields(pool);                          Array value_fields(pool);
                         if(param_index>0) {                          if(param_index>0) {
                                   if(distinct!=D_ILLEGAL && distinct!=D_FIRST)
                                           throw Exception("parser.runtime",
                                                   0,
                                                   "in distinct[tables] mode you may not specify value field(s)");
                                 Value& value_fields_param=params->as_no_junction(param_index, "value field(s) must not be code");                                  Value& value_fields_param=params->as_no_junction(param_index, "value field(s) must not be code");
                                 if(value_fields_param.is_string()) {                                  if(value_fields_param.is_string()) {
                                         value_fields+=self_table.column_name2index(value_fields_param.as_string(), true);                                          value_fields+=self_table.column_name2index(value_fields_param.as_string(), true);
Line 398  static void _hash(Request& r, const Stri Line 454  static void _hash(Request& r, const Stri
                                                 "value field(s) must be string or self_table"                                                  "value field(s) must be string or self_table"
                                         );                                          );
                         } else { // by all columns, including key                          } else { // by all columns, including key
                                 for(int i=0; i<columns->size(); i++)                                  if(!(distinct!=D_ILLEGAL && distinct!=D_FIRST))
                                         value_fields+=i;                                          for(int i=0; i<columns->size(); i++)
                                                   value_fields+=i;
                         }                          }
   
                         Value& key_param=params->get(0);                          Value& key_param=params->get(0);
Line 407  static void _hash(Request& r, const Stri Line 464  static void _hash(Request& r, const Stri
                         int key_field=key_code?-1                          int key_field=key_code?-1
                                 :self_table.column_name2index(key_param.as_string(), true);                                  :self_table.column_name2index(key_param.as_string(), true);
   
                         Row_info row_info={&r, &self_table, key_code, key_field, &value_fields, result.get_hash(0), distinct};                          Row_info row_info={&r, &self_table, 
                                   key_code, key_field, &value_fields, 
                                   result.get_hash(0), distinct};
   
                         int saved_current=self_table.current();                          int saved_current=self_table.current();
                         self_table.for_each(table_row_to_hash, &row_info);                          self_table.for_each(table_row_to_hash, &row_info);
Line 450  static void _sort(Request& r, const Stri Line 509  static void _sort(Request& r, const Stri
                 false; // default=asc                  false; // default=asc
   
         Table& old_table=static_cast<VTable *>(r.get_self())->table(&method_name);          Table& old_table=static_cast<VTable *>(r.get_self())->table(&method_name);
           if(old_table.size()==0)
                   return;
   
         Table& new_table=*new(pool) Table(pool, &method_name, old_table.columns());          Table& new_table=*new(pool) Table(pool, &method_name, old_table.columns());
   
         Table_seq_item *seq=(Table_seq_item *)pool.malloc(sizeof(Table_seq_item)*old_table.size());          Table_seq_item *seq=(Table_seq_item *)pool.malloc(sizeof(Table_seq_item)*old_table.size());
Line 482  static void _sort(Request& r, const Stri Line 544  static void _sort(Request& r, const Stri
         static_cast<VTable *>(r.get_self())->set_table(new_table);          static_cast<VTable *>(r.get_self())->set_table(new_table);
 }  }
   
 static bool _locate_expression(Request& r, const String& method_name, MethodParams *params) {  #ifndef DOXYGEN
         if(params->size()>1)  struct Locate_expression_func_info {
                 throw Exception("parser.runtime",           Request* r;
                         &method_name,          Value* expression_code;
                         "locate by expression has only one parameter - expression");  };
   #endif
   bool locate_expression_func(Table& self, void* ainfo) {
           Locate_expression_func_info& info=*static_cast<Locate_expression_func_info*>(ainfo);
           return info.r->process_to_value(*info.expression_code).as_bool();
   }
   static bool _locate_expression(Table& table, Table::Action_options o,
                                  Request& r, const String& method_name, MethodParams *params) {
           check_option_param(o.defined, method_name, params, 1,
                   "locate by expression only has parameters: expression and, maybe, options");
         Value& expression_code=params->as_junction(0, "must be expression");          Value& expression_code=params->as_junction(0, "must be expression");
   
         Table& table=static_cast<VTable *>(r.get_self())->table(&method_name);          Locate_expression_func_info info={&r, &expression_code};
         int saved_current=table.current();          return table.locate(locate_expression_func, &info, o);
         int size=table.size();  
         for(int row=0; row<size; row++) {  
                 table.set_current(row);  
   
                 if(r.process_to_value(expression_code).as_bool())  
                         return true;  
         }  
         table.set_current(saved_current);  
         return false;  
 }  }
 static bool _locate_name_value(Request& r, const String& method_name, MethodParams *params) {  static bool _locate_name_value(Table& table, Table::Action_options o,
         if(params->size()>2)                                 Request& r, const String& method_name, MethodParams *params) {
                 throw Exception("parser.runtime",           check_option_param(o.defined, method_name, params, 2,
                         &method_name,                  "locate by locate by name has parameters: name, value and, maybe, options");
                         "locate by name and value has only two parameters - name and value");          const String& name=params->as_string(0, "column name must be string");
           const String& value=params->as_string(1, "value must be string");
   
         Table& table=static_cast<VTable *>(r.get_self())->table(&method_name);          return table.locate(name, value, o);
         return table.locate(  
                 params->as_string(0, "column name must be string"),  
                 params->as_string(1, "value must be string")  
         );  
 }  }
 static void _locate(Request& r, const String& method_name, MethodParams *params) {  static void _locate(Request& r, const String& method_name, MethodParams *params) {
         Pool& pool=r.pool();          Pool& pool=r.pool();
           Table& table=static_cast<VTable *>(r.get_self())->table(&method_name);
   
           Table::Action_options o=get_action_options(r, method_name, params, table);
   
         bool result=params->get(0).get_junction()?          bool result=params->get(0).get_junction()?
                 _locate_expression(r, method_name, params) :                  _locate_expression(table, o, r, method_name, params) :
                 _locate_name_value(r, method_name, params);                  _locate_name_value(table, o, r, method_name, params);
         r.write_no_lang(*new(pool) VBool(pool, result));          r.write_no_lang(*new(pool) VBool(pool, result));
 }  }
   
Line 557  static void _append(Request& r, const St Line 619  static void _append(Request& r, const St
 static void _join(Request& r, const String& method_name, MethodParams *params) {  static void _join(Request& r, const String& method_name, MethodParams *params) {
         Pool& pool=r.pool();          Pool& pool=r.pool();
   
         Table *maybe_src=params->as_no_junction(0, "table ref must not be code").get_table();          Table* maybe_src=params->as_no_junction(0, "table ref must not be code").get_table();
         if(!maybe_src)          if(!maybe_src)
                 throw Exception("parser.runtime",                   throw Exception("parser.runtime", 
                         &method_name,                           &method_name, 
                         "source is not a table");                          "source is not a table");
   
         Table& src=*maybe_src;          Table& src=*maybe_src;
   
           Table::Action_options o=get_action_options(r, method_name, params, src);
           check_option_param(o.defined, method_name, params, 1,
                   "invalid extra parameter");
   
         Table& dest=static_cast<VTable *>(r.get_self())->table(&method_name);          Table& dest=static_cast<VTable *>(r.get_self())->table(&method_name);
         if(&src == &dest)          if(&src == &dest)
                 throw Exception("parser.runtime",                   throw Exception("parser.runtime", 
                         &method_name,                           &method_name, 
                         "source and destination are same table");                          "source and destination are same table");
   
         int offset, limit;          if(o.reverse)
         get_copy_options(r, method_name, params, 1, src,                   throw Exception(0,
                 offset, limit);                          &method_name,
                           "not implemented in this version, please upgrade");
         if(const Array *dest_columns=dest.columns()) { // dest is named          if(const Array *dest_columns=dest.columns()) { // dest is named
                 int saved_src_current=src.current();                  int saved_src_current=src.current();
                 int m=src.size()-offset;                  int m=src.size()-o.offset;
                 if(!limit || limit>m)                  if(o.limit<0 || o.limit>m)
                         limit=m;                          o.limit=m;
                 int end=offset+limit;                  int end=o.offset+o.limit;
                 for(int src_row=offset; src_row<end; src_row++) {                  for(int src_row=o.offset; src_row<end; src_row++) {
                         src.set_current(src_row);                          src.set_current(src_row);
                         Array& dest_row=*new(pool) Array(pool);                          Array& dest_row=*new(pool) Array(pool);
                         for(int dest_column=0; dest_column<dest_columns->size(); dest_column++) {                          for(int dest_column=0; dest_column<dest_columns->size(); dest_column++) {
Line 822  MTable::MTable(Pool& apool) : Methoded(a Line 888  MTable::MTable(Pool& apool) : Methoded(a
         add_native_method("sort", Method::CT_DYNAMIC, _sort, 1, 2);          add_native_method("sort", Method::CT_DYNAMIC, _sort, 1, 2);
   
         // ^table.locate[field;value]          // ^table.locate[field;value]
         add_native_method("locate", Method::CT_DYNAMIC, _locate, 1, 2);          add_native_method("locate", Method::CT_DYNAMIC, _locate, 1, 3);
   
         // ^table.flip[]          // ^table.flip[]
         add_native_method("flip", Method::CT_DYNAMIC, _flip, 0, 0);          add_native_method("flip", Method::CT_DYNAMIC, _flip, 0, 0);

Removed from v.1.171  
changed lines
  Added in v.1.181


E-mail: