--- parser3/src/classes/hash.C 2024/09/23 23:16:41 1.159 +++ parser3/src/classes/hash.C 2024/09/28 19:42:41 1.164 @@ -17,7 +17,7 @@ #include "pa_vbool.h" #include "pa_vmethod_frame.h" -volatile const char * IDENT_HASH_C="$Id: hash.C,v 1.159 2024/09/23 23:16:41 moko Exp $"; +volatile const char * IDENT_HASH_C="$Id: hash.C,v 1.164 2024/09/28 19:42:41 moko Exp $"; // class @@ -41,7 +41,7 @@ class Hash_sql_event_handlers: public SQ HashStringValue& result; Value* row_value; int column_index; - ArrayString& columns; + ArrayString* columns; bool one_bool_column; Table2hash_value_type value_type; int columns_count; @@ -53,7 +53,7 @@ public: result(aresult), row_value(0), column_index(0), - columns(*new ArrayString), + columns(new ArrayString), one_bool_column(false), value_type(avalue_type), empty(0) { @@ -61,7 +61,12 @@ public: bool add_column(SQL_Error& error, const char* str, size_t ) { try { - columns+=new String(str, String::L_TAINTED /* no length as 0x00 can be inside */); + if(columns_count){ + // another query in multi_statements mode + columns=new ArrayString; + columns_count=0; + } + *columns+=new String(str, String::L_TAINTED /* no length as 0x00 can be inside */); return false; } catch(...) { error=SQL_Error("exception occurred in Hash_sql_event_handlers::add_column"); @@ -70,24 +75,27 @@ public: } bool before_rows(SQL_Error& error) { - if(columns.count()<1) { + columns_count=columns->count(); + if(columns_count<1) { error=SQL_Error("no columns"); return true; } - switch(value_type){ - case C_STRING: { - if(columns.count()>2){ - error=SQL_Error("only 2 columns allowed for $.type[string]."); - return true; + if(columns_count==1) { + one_bool_column=true; + } else { + switch(value_type){ + case C_STRING: { + if(columns_count>2){ + error=SQL_Error("only 2 columns allowed for $.type[string]"); + return true; + } + break; + } + case C_TABLE: { + // create empty table which we'll copy later + empty=new Table(columns); + break; } - } - case C_TABLE: { - // create empty table which we'll copy later - empty=new Table(&columns); - columns_count=columns.count(); - } - case C_HASH: { - one_bool_column=columns.count()==1; } } return false; @@ -102,6 +110,12 @@ public: try { const String& cell=str ? *new String(str, String::L_TAINTED /* no length as 0x00 can be inside */) : String::Empty; + if(column_index==columns_count){ + // should never happen, buggy driver case + error=SQL_Error("columns index exceed the columns count"); + return true; + } + bool duplicate=false; if(one_bool_column) { duplicate=result.put_dont_replace(cell, &VBool::get(true)); // put. existed? @@ -121,32 +135,29 @@ public: } case C_TABLE: { VTable* vtable=(VTable*)result.get(cell); - Table* table; if(vtable) { // table with this key exist? if(!distinct) { duplicate=true; break; } - table=vtable->get_table(); } else { // no? creating table of same structure as source Table::Action_options table_options(0, 0); - table=new Table(*empty, table_options/*no rows, just structure*/); - vtable=new VTable(table); + vtable=new VTable(new Table(*empty, table_options/*no rows, just structure*/)); result.put(cell, vtable); // put } ArrayString* row=new ArrayString(columns_count); row_value=(Value*)row; *row+=&cell; - *table+=row; + *vtable->get_table()+=row; break; } } } else { switch(value_type) { case C_HASH: { - row_value->get_hash()->put(*columns[column_index], new VString(cell)); + row_value->get_hash()->put(*columns->get(column_index), new VString(cell)); break; } case C_STRING: { @@ -315,25 +326,25 @@ static void _sql(Request& r, MethodParam if(params.count()>1) if(HashStringValue* options=params.as_hash(1, "sql options")) { int valid_options=0; - if(Value* vbind=options->get(sql_bind_name)) { - valid_options++; - bind=vbind->get_hash(); - } - if(Value* vlimit=options->get(sql_limit_name)) { - valid_options++; - limit=(ulong)r.process(*vlimit).as_double(); - } - if(Value* voffset=options->get(sql_offset_name)) { - valid_options++; - offset=(ulong)r.process(*voffset).as_double(); - } - if(Value* vdistinct=options->get(sql_distinct_name)) { - valid_options++; - distinct=r.process(*vdistinct).as_bool(); - } - if(Value* vvalue_type=options->get(sql_value_type_name)) { - valid_options++; - value_type=get_value_type(r.process(*vvalue_type)); + for(HashStringValue::Iterator i(*options); i; i.next() ){ + String::Body key=i.key(); + Value* value=i.value(); + if(key == sql_bind_name) { + bind=value->get_hash(); + valid_options++; + } else if(key == sql_limit_name) { + limit=(ulong)r.process(*value).as_double(); + valid_options++; + } else if(key == sql_offset_name) { + offset=(ulong)r.process(*value).as_double(); + valid_options++; + } else if (key == sql_distinct_name) { + distinct=r.process(*value).as_bool(); + valid_options++; + } else if (key == sql_value_type_name) { + value_type=get_value_type(r.process(*value)); + valid_options++; + } } if(valid_options!=options->count()) throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION);