--- parser3/src/classes/table.C 2013/10/17 21:52:32 1.299 +++ parser3/src/classes/table.C 2016/03/31 21:46:20 1.313 @@ -1,14 +1,10 @@ /** @file Parser: @b table parser class. - Copyright (c) 2001-2012 Art. Lebedev Studio (http://www.artlebedev.com) + Copyright (c) 2001-2015 Art. Lebedev Studio (http://www.artlebedev.com) Author: Alexandr Petrosian (http://paf.design.ru) */ -#if (!defined(NO_STRINGSTREAM) && !defined(FREEBSD4)) -#include -#endif - #include "classes.h" #include "pa_vmethod_frame.h" @@ -21,7 +17,12 @@ #include "pa_vbool.h" #include "pa_array.h" -volatile const char * IDENT_TABLE_C="$Id: table.C,v 1.299 2013/10/17 21:52:32 moko Exp $"; +#if (!defined(NO_STRINGSTREAM) && !defined(FREEBSD4)) +#include +#define USE_STRINGSTREAM +#endif + +volatile const char * IDENT_TABLE_C="$Id: table.C,v 1.313 2016/03/31 21:46:20 moko Exp $"; // class @@ -34,7 +35,7 @@ public: // global variable -DECLARE_CLASS_VAR(table, new MTable, 0); +DECLARE_CLASS_VAR(table, new MTable); #define TABLE_REVERSE_NAME "reverse" @@ -94,14 +95,6 @@ static Table::Action_options get_action_ return result; } -static void check_option_param(bool options_defined, - MethodParams& params, size_t next_param_index, - const char *msg) { - if(next_param_index+(options_defined?1:0) != params.count()) - throw Exception(PARSER_RUNTIME, - 0, - "%s", msg); -} struct TableSeparators { char column; const String* scolumn; @@ -143,8 +136,8 @@ static void _create(Request& r, MethodPa // clone/copy part? if(Table *source=params[0].get_table()) { Table::Action_options o=get_action_options(r, params, 1, *source); - check_option_param(o.defined, params, 1, - "too many parameters"); + if(params.count()>2) + throw Exception(PARSER_RUNTIME, 0, "too many parameters"); GET_SELF(r, VTable).set_table(*new Table(*source, o)); return; } @@ -185,7 +178,7 @@ static void _create(Request& r, MethodPa // data Temp_lang temp_lang(r, String::L_PASS_APPENDED); const String& data= - r.process_to_string(params.as_junction(data_param_index, "body must be code")); + r.process_to_string(params.as_junction(data_param_index, "body must be table or code")); // parse columns size_t raw_pos_after=0; @@ -396,10 +389,6 @@ static void _load(Request& r, MethodPara GET_SELF(r, VTable).set_table(table); } -#if (!defined(NO_STRINGSTREAM) && !defined(FREEBSD4)) - #define USE_STRINGSTREAM -#endif - #ifdef USE_STRINGSTREAM #include "gc_allocator.h" @@ -667,7 +656,7 @@ static void _count(Request& r, MethodPar if(params.count()) { const String& param=params.as_string(0, PARAMETER_MUST_BE_STRING); if(param == "columns") - result = table.columns() ? table.columns()->count() : 0; + result = table.columns() ? table.columns()->count() : table.max_cells(); else if(param == "cells") result = table.count() ? table[table.current()]->count() : 0; else if(param == "rows") // synonim for ^table.count[] @@ -815,7 +804,9 @@ static void table_row_to_hash(Table::ele table=new Table(*info->table, table_options/*no rows, just structure*/); info->hash->put(*key, new VTable(table)); } - *table+=row; + Table::element_type row_copy(new ArrayString(row->count())); + row_copy->append(*row); + *table+=row_copy; break; } } @@ -1043,10 +1034,9 @@ static bool expression_is_true(Table&, E static bool _locate_expression(Table& table, Request& r, MethodParams& params) { Value& expression_code=params.as_junction(0, "must be expression"); - const size_t options_index=1; - Table::Action_options o=get_action_options(r, params, options_index, table); - check_option_param(o.defined, params, options_index, "locate by expression only has parameters: expression and, maybe, options"); - + Table::Action_options o=get_action_options(r, params, 1, table); + if(params.count()>2) + throw Exception(PARSER_RUNTIME, 0, "locate by expression only has parameters: expression and, maybe, options"); Expression_is_true_info info={&r, &expression_code}; return table.table_first_that(expression_is_true, &info, o); } @@ -1054,10 +1044,7 @@ static bool _locate_expression(Table& ta static bool _locate_name_value(Table& table, Request& r, MethodParams& params) { const String& name=params.as_string(0, "column name must be string"); const String& value=params.as_string(1, VALUE_MUST_BE_STRING); - const size_t options_index=2; - Table::Action_options o=get_action_options(r, params, options_index, table); - check_option_param(o.defined, params, options_index, "locate by name has parameters: name, value and, maybe, options"); - + Table::Action_options o=get_action_options(r, params, 2, table); return table.locate(name, value, o); } @@ -1075,7 +1062,7 @@ static void _flip(Request& r, MethodPara Table& old_table=GET_SELF(r, VTable).table(); Table& new_table=*new Table(0); if(size_t old_count=old_table.count()) - if(size_t old_cols=old_table.columns()?old_table.columns()->count():old_table[0]->count()) + if(size_t old_cols=old_table.columns()?old_table.columns()->count():old_table.max_cells()) for(size_t column=0; columnput_element(*rownum_var_name, new VString(*new String(String::Body::Format(row), String::L_CLEAN))); + r.put_element(*var_context, *rownum_var_name, new VString(*new String(String::Body::Format(row), String::L_CLEAN))); if(value_var_name) - var_context->put_element(*value_var_name, new VTable(&table)); + r.put_element(*var_context, *value_var_name, new VTable(&table)); r.process_write(body_code); Request::Skip lskip=r.get_skip(); r.set_skip(Request::SKIP_NOTHING); @@ -1152,16 +1139,56 @@ static void _foreach(Request& r, MethodP table.set_current(saved_current); } -static void _append(Request& r, MethodParams& params) { +static void update_cell(HashStringValue::key_type aname, HashStringValue::value_type avalue, VTable *dest) { + dest->put_element(String(aname, String::L_CLEAN), avalue); // new not required +} + +inline Table::element_type row_from_string(Request& r, Value ¶m){ + if(!param.is_string() && !param.get_junction()) + throw Exception(PARSER_RUNTIME, 0, "row must be string, code or hash"); + Temp_lang temp_lang(r, String::L_PASS_APPENDED); - const String& string=r.process_to_string(params[0]); + const String& string=r.process_to_string(param); // parse cells Table::element_type row=new ArrayString; size_t pos_after=0; string.split(*row, pos_after, "\t", String::L_AS_IS); - GET_SELF(r, VTable).table()+=row; + return row; +} + +static void _append(Request& r, MethodParams& params) { + VTable vtable=GET_SELF(r, VTable); + Table& table=vtable.table(); + + HashStringValue* hash=params[0].get_hash(); + if(hash){ + table+=new ArrayString(); + size_t saved_current=table.current(); + table.set_current(table.count()-1); + hash->for_each(update_cell, &vtable); + table.set_current(saved_current); + } else { + table+=row_from_string(r, params[0]); + } +} + +static void _insert(Request& r, MethodParams& params) { + VTable vtable=GET_SELF(r, VTable); + Table& table=vtable.table(); + HashStringValue* hash=params[0].get_hash(); + if(hash){ + table.insert(table.current(), new ArrayString()); + hash->for_each(update_cell, &vtable); + } else { + table.insert(table.current(), row_from_string(r, params[0])); + } +} + +static void _delete(Request& r, MethodParams&) { + Table& table=GET_SELF(r, VTable).table(); + table.remove_current(); } static void join_named_row(Table& src, Table* dest) { @@ -1181,7 +1208,6 @@ static void _join(Request& r, MethodPara Table& src=*params.as_table(0, "source"); Table::Action_options o=get_action_options(r, params, 1, src); - check_option_param(o.defined, params, 1, "invalid extra parameter"); Table& dest=GET_SELF(r, VTable).table(); if(&src == &dest) @@ -1264,7 +1290,7 @@ static void marshal_bind( // not static, used elsewhere int marshal_binds(HashStringValue& hash, SQL_Driver::Placeholder*& placeholders) { int hash_count=hash.count(); - placeholders=new(UseGC) SQL_Driver::Placeholder[hash_count]; + placeholders=new SQL_Driver::Placeholder[hash_count]; SQL_Driver::Placeholder* ptr=placeholders; hash.for_each(marshal_bind, &ptr); return hash_count; @@ -1485,9 +1511,15 @@ MTable::MTable(): Methoded("table") { // ^table.foreach[row-num;value]{code}[delim] add_native_method("foreach", Method::CT_DYNAMIC, _foreach, 3, 4); - // ^table.append{r{tab}e{tab}c{tab}o{tab}r{tab}d} + // ^table.append{row{tab}data} add_native_method("append", Method::CT_DYNAMIC, _append, 1, 1); + // ^table.insert{row{tab}data} before current row + add_native_method("insert", Method::CT_DYNAMIC, _insert, 1, 1); + + // ^table.delete[] current row + add_native_method("delete", Method::CT_DYNAMIC, _delete, 0, 0); + // ^table.join[table][$.limit(10) $.offset(1) $.offset[cur] ] add_native_method("join", Method::CT_DYNAMIC, _join, 1, 2);