00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "smart/vardatabase.h"
00028 #include "smart/varmap.hpp"
00029 #include "smart/varvalue.hpp"
00030 #include "base/map.hpp"
00031 #include "base/vector.hpp"
00032 #include "base/list.hpp"
00033 #include "base/memory.hpp"
00034 #include "base/string.hpp"
00035 #include "base/common.hpp"
00036 #include "base/keymaker.hpp"
00037
00038 terimber_vardatabase*
00039 terimber_vardatabase_factory::get_vardatabase()
00040 {
00041 return new TERIMBER::vardatabase();
00042 }
00043
00044
00045 BEGIN_TERIMBER_NAMESPACE
00046 #pragma pack(4)
00047
00048 const char* request_dtd = \
00049 "<?xml version=\"1.0\" encoding=\"UTF-8\"?> \
00050 <!ENTITY % ddltype \"(CREATE | DROP)\"> \
00051 <!ENTITY % dmltype \"(SELECT | INSERT | UPDATE | DELETE)\"> \
00052 <!ENTITY % logic \"(AND | OR)\"> \
00053 <!ENTITY % condition \"(GT | GE | LT | LE | EQ | NE | PM | FM)\"> \
00054 <!ENTITY % quality \"(low | normal | high)\"> \
00055 <!ENTITY % vtype \"(bool | sb1 | ub1 | sb2 | ub2 | sb4 | ub4 | sb8 | ub8 | float | double | numeric | guid | string | binary | mpart | mfuzzy)\"> \
00056 <!ELEMENT request (table | query)>\
00057 <!ELEMENT table (desc)*>\
00058 <!ELEMENT desc EMPTY>\
00059 <!ELEMENT query ((returns?, where) | (returns?, values) | (returns?, values, where) | (returns?, where))> \
00060 <!ELEMENT returns (col)*> \
00061 <!ELEMENT where (group | cond)> \
00062 <!ELEMENT values (col)*> \
00063 <!ELEMENT group (group | cond)+> \
00064 <!ELEMENT cond EMPTY> \
00065 <!ELEMENT col EMPTY> \
00066 <!ATTLIST request \
00067 timeout CTYPE vt_ub4 \"5000\"> \
00068 <!ATTLIST table \
00069 what %ddltype; #REQUIRED \
00070 name CDATA #REQUIRED> \
00071 <!ATTLIST desc \
00072 name CDATA #REQUIRED \
00073 type %vtype; #REQUIRED> \
00074 <!ATTLIST query \
00075 what %dmltype; #REQUIRED \
00076 name CDATA #REQUIRED> \
00077 <!ATTLIST group \
00078 join %logic; #REQUIRED> \
00079 <!ATTLIST cond \
00080 how %condition; #REQUIRED \
00081 pq %quality; #IMPLIED \
00082 nq %quality; #IMPLIED \
00083 deep CTYPE vt_bool #IMPLIED \
00084 name CDATA #IMPLIED \
00085 val CDATA #REQUIRED > \
00086 <!ATTLIST col \
00087 name CDATA #REQUIRED \
00088 val CDATA #IMPLIED>";
00089
00090 const char* response_dtd = \
00091 "<?xml version=\"1.0\" encoding=\"UTF-8\"?> \
00092 <!ELEMENT response (row)*> \
00093 <!ELEMENT row (col)*> \
00094 <!ELEMENT col EMPTY> \
00095 <!ATTLIST response \
00096 errCode CTYPE vt_sb4 #REQUIRED \
00097 errDesc CDATA #IMPLIED> \
00098 <!ATTLIST row \
00099 rowid CTYPE vt_ub4 #REQUIRED> \
00100 <!ATTLIST col \
00101 name CDATA #REQUIRED \
00102 val CDATA #IMPLIED>";
00103
00104
00105 vardatabase::vardatabase()
00106 {
00107 }
00108
00109
00110 vardatabase::~vardatabase()
00111 {
00112 }
00113
00114
00115 bool
00116 vardatabase::process_xml_request(const char* request, size_t len, xml_designer* parser)
00117 {
00118
00119 if (!parser->load(request, len, request_dtd, strlen(request_dtd))
00120 || !parser->select_root())
00121 {
00122 string_t err = parser->error();
00123 parser->load(0, 0 , response_dtd, strlen(response_dtd));
00124
00125 parser->add_child(ELEMENT_NODE, "response", 0, false);
00126 parser->add_child(ATTRIBUTE_NODE, "errCode", "-1", true);
00127 parser->add_child(ATTRIBUTE_NODE, "errDesc", err, true);
00128
00129 return true;
00130 }
00131
00132 ub4_t timeout = 0;
00133
00134 if (parser->select_attribute_by_name("timeout"))
00135 {
00136 const char* val = parser->get_value();
00137
00138 if (val)
00139 str_template::strscan(val, 32, "%u", &timeout);
00140
00141 parser->select_parent();
00142 }
00143
00144
00145 parser->select_first_child();
00146
00147 const char* DDL_DML = parser->get_name();
00148
00149 if (DDL_DML[0] == 't')
00150 {
00151 keylocker_server writeguard(_masterkey, timeout);
00152
00153 if (!writeguard)
00154 {
00155 parser->load(0, 0 , response_dtd, strlen(response_dtd));
00156 parser->add_child(ELEMENT_NODE, "response", 0, false);
00157 parser->add_child(ATTRIBUTE_NODE, "errCode", "-1", true);
00158 parser->add_child(ATTRIBUTE_NODE, "errDesc", "Timeout occurred", true);
00159 return true;
00160 }
00161
00162 parser->select_attribute_by_name("name");
00163 string_t name = parser->get_value();
00164 parser->select_parent();
00165
00166 parser->select_attribute_by_name("what");
00167 const char* what = parser->get_value();
00168
00169 if (what[0] == 'D')
00170 {
00171 parser->select_parent();
00172
00173 mutex_keeper keeper(_table_mtx);
00174 table_map_t::iterator it_table = _table_map.find(name);
00175 if (it_table != _table_map.end())
00176 {
00177 _table_map.erase(it_table);
00178
00179 parser->load(0, 0 , response_dtd, strlen(response_dtd));
00180 parser->add_child(ELEMENT_NODE, "response", 0, false);
00181 parser->add_child(ATTRIBUTE_NODE, "errCode", "0", true);
00182 }
00183 else
00184 {
00185
00186 parser->load(0, 0 , response_dtd, strlen(response_dtd));
00187 parser->add_child(ELEMENT_NODE, "response", 0, false);
00188 parser->add_child(ATTRIBUTE_NODE, "errCode", "-1", true);
00189
00190 string_t err = "Table ";
00191 err += name;
00192 err += " does not exist in the database";
00193
00194 parser->add_child(ATTRIBUTE_NODE, "errDesc", err, true);
00195 }
00196 }
00197 else
00198 {
00199 parser->select_parent();
00200
00201 mutex_keeper keeper(_table_mtx);
00202 vartable tbl;
00203 table_map_t::pairib_t it_table = _table_map.insert(name, tbl);
00204 if (it_table.first == _table_map.end())
00205 {
00206
00207 parser->load(0, 0 , response_dtd, strlen(response_dtd));
00208 parser->add_child(ELEMENT_NODE, "response", 0, false);
00209 parser->add_child(ATTRIBUTE_NODE, "errCode", "-1", true);
00210
00211 string_t err = "Not enough memory";
00212 parser->add_child(ATTRIBUTE_NODE, "errDesc", err, true);
00213 }
00214 else
00215 {
00216 if (it_table.second)
00217 {
00218 fill_schema(*it_table.first, parser);
00219
00220 parser->load(0, 0 , response_dtd, strlen(response_dtd));
00221 parser->add_child(ELEMENT_NODE, "response", 0, false);
00222 parser->add_child(ATTRIBUTE_NODE, "errCode", "0", true);
00223 }
00224 else
00225 {
00226
00227 parser->load(0, 0 , response_dtd, strlen(response_dtd));
00228 parser->add_child(ELEMENT_NODE, "response", 0, false);
00229 parser->add_child(ATTRIBUTE_NODE, "errCode", "-1", true);
00230
00231 string_t err = "Table ";
00232 err += name;
00233 err += " already exists in the database";
00234
00235 parser->add_child(ATTRIBUTE_NODE, "errDesc", err, true);
00236 }
00237 }
00238 }
00239 }
00240 else
00241 {
00242 keylocker_client readguard(_masterkey, timeout);
00243
00244 if (!readguard)
00245 {
00246 parser->load(0, 0 , response_dtd, strlen(response_dtd));
00247 parser->add_child(ELEMENT_NODE, "response", 0, false);
00248 parser->add_child(ATTRIBUTE_NODE, "errCode", "-1", true);
00249 parser->add_child(ATTRIBUTE_NODE, "errDesc", "Timeout occurred", true);
00250 return true;
00251 }
00252
00253 parser->select_attribute_by_name("name");
00254 string_t name = parser->get_value();
00255 parser->select_parent();
00256
00257 mutex_keeper keeper(_table_mtx);
00258 table_map_t::iterator it_table = _table_map.find(name);
00259 if (it_table != _table_map.end())
00260 {
00261 it_table->_tmp_all.clear_extra();
00262 it_table->_con_all.clear_extra();
00263
00264 parser->select_attribute_by_name("what");
00265 const char* what = parser->get_value();
00266
00267
00268 if (what[0] == 'S')
00269 {
00270 parser->select_parent();
00271
00272 keylocker_client qread(it_table->_key, timeout);
00273 if (!qread)
00274 {
00275 parser->load(0, 0 , response_dtd, strlen(response_dtd));
00276 parser->add_child(ELEMENT_NODE, "response", 0, false);
00277 parser->add_child(ATTRIBUTE_NODE, "errCode", "-1", true);
00278 parser->add_child(ATTRIBUTE_NODE, "errDesc", "Timeout occurred", true);
00279 return true;
00280 }
00281
00282 it_table->_tbl.process_query(parser, it_table->_con_all, it_table->_tmp_all, it_table->_inl_all);
00283 }
00284 else
00285 {
00286 parser->select_parent();
00287
00288 keylocker_server qwrite(it_table->_key, timeout);
00289 if (!qwrite)
00290 {
00291 parser->load(0, 0 , response_dtd, strlen(response_dtd));
00292 parser->add_child(ELEMENT_NODE, "response", 0, false);
00293 parser->add_child(ATTRIBUTE_NODE, "errCode", "-1", true);
00294 parser->add_child(ATTRIBUTE_NODE, "errDesc", "Timeout occurred", true);
00295 return true;
00296 }
00297
00298 it_table->_tbl.process_query(parser, it_table->_con_all, it_table->_tmp_all, it_table->_inl_all);
00299 }
00300 }
00301 else
00302 {
00303
00304 parser->load(0, 0 , response_dtd, strlen(response_dtd));
00305 parser->add_child(ELEMENT_NODE, "response", 0, false);
00306 parser->add_child(ATTRIBUTE_NODE, "errCode", "-1", true);
00307
00308 string_t err = "Table ";
00309 err += name;
00310 err += " does not exist in the database";
00311
00312 parser->add_child(ATTRIBUTE_NODE, "errDesc", err, true);
00313 }
00314 }
00315
00316 return true;
00317 }
00318
00319 bool
00320 vardatabase::fill_schema(vartable& tbl, xml_designer* parser)
00321 {
00322 if (!parser->select_first_child())
00323 return true;
00324
00325 _list< var_property_schema > l_tmp;
00326
00327 do
00328 {
00329
00330 if (ELEMENT_NODE != parser->get_type())
00331 continue;
00332
00333 var_property_schema dummy;
00334
00335 _list< var_property_schema >::iterator schema = l_tmp.push_back(tbl._tmp_all, dummy);
00336 if (schema == l_tmp.end())
00337 return false;
00338
00339
00340 schema->_is_searchable = false;
00341 schema->_is_fuzzy_match = false;
00342
00343 parser->select_attribute_by_name("name");
00344 TERIMBER::string_t name(parser->get_value(), &tbl._tmp_all);
00345 schema->_name = name;
00346 parser->select_parent();
00347
00348 parser->select_attribute_by_name("type");
00349 const char* val = parser->get_value();
00350
00351 switch (val[0])
00352 {
00353 case 'b':
00354 {
00355 if (val[1] == 'o')
00356 schema->_type = vt_bool;
00357 else
00358 schema->_type = vt_binary;
00359 }
00360 break;
00361 case 's':
00362 {
00363 if (val[1] == 't')
00364 schema->_type = vt_string;
00365 else
00366 {
00367 switch (val[2])
00368 {
00369 case '1':
00370 schema->_type = vt_sb1;
00371 break;
00372 case '2':
00373 schema->_type = vt_sb2;
00374 break;
00375 case '4':
00376 schema->_type = vt_sb4;
00377 break;
00378 case '8':
00379 schema->_type = vt_sb8;
00380 break;
00381 }
00382 }
00383 }
00384 break;
00385 case 'u':
00386 {
00387 switch (val[2])
00388 {
00389 case '1':
00390 schema->_type = vt_ub1;
00391 break;
00392 case '2':
00393 schema->_type = vt_ub2;
00394 break;
00395 case '4':
00396 schema->_type = vt_ub4;
00397 break;
00398 case '8':
00399 schema->_type = vt_ub8;
00400 break;
00401 }
00402 }
00403 break;
00404 case 'f':
00405 schema->_type = vt_float;
00406 break;
00407 case 'd':
00408 schema->_type = vt_double;
00409 break;
00410 case 'n':
00411 schema->_type = vt_numeric;
00412 break;
00413 case 'g':
00414 schema->_type = vt_guid;
00415 break;
00416 case 'm':
00417 schema->_type = vt_string;
00418 if (val[1] == 'p')
00419 schema->_is_searchable = true;
00420 else
00421 schema->_is_fuzzy_match = true;
00422 break;
00423 default:
00424 assert(false);
00425 }
00426
00427 parser->select_parent();
00428 }
00429 while (parser->select_next_sibling());
00430
00431 if (l_tmp.empty())
00432 return true;
00433
00434 size_t cols = l_tmp.size();
00435
00436 if (!tbl._schema.resize(tbl._all, cols))
00437 return false;
00438
00439 size_t index = 0;
00440 for (_list< var_property_schema >::const_iterator it = l_tmp.begin(); it != l_tmp.end(); ++it, ++index)
00441 {
00442 tbl._schema[index] = *it;
00443
00444 tbl._schema[index]._name = copy_string(it->_name, tbl._all, os_minus_one);
00445 }
00446
00447 return true;
00448 }
00449
00450 #pragma pack()
00451 END_TERIMBER_NAMESPACE