Icontem

File: lib-js/xbsdb.js

Recommend this page to a friend!
  Classes of Alexey Znaev  >  XBSDB  >  lib-js/xbsdb.js  >  Download  
File: lib-js/xbsdb.js
Role: Class source
Content type: text/plain
Description: Main class
Class: XBSDB
Manipulate arrays with an SQL-like language
Author: By
Last change: changed Listing priority
Date: 8 years ago
Size: 41,014 bytes
 

Contents

Class file image Download
///////////////////////////////////////////////////////////////////////////
//
//    XBSDB - Cross-Browser JavaScript Database library
//    Copyright (C) 2010 Alexey A.Znayev
//
//    This file is part of XBSDB.
//
//    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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
//
//    Alexey A.Znayev, znaeff@mail.ru
//
///////////////////////////////////////////////////////////////////////////

// This file contains public class XBSDB

///////////////////////////////////////////////////////////////////////////
// database

///////////////////////////////////////////////////////////////////////////
// constructor
// parameters:
// [sLocale] - string of current locale or null (means 'en')
// returns:
// object of XBSDB
function XBSDB(sLocale){
 // public fields
 this.sResultCode = 'OK';
 // private fields
 if(sLocale && typeof sLocale == 'string'){
  if(XBSDB.prototype.Text && typeof XBSDB.prototype.Text == 'object' && typeof XBSDB.prototype.Text[sLocale] == 'object'){
   this._sLocale = sLocale;
  }else{
   this.sResultCode = 'DB_LOCALE_NOT_DEFINED';
   this._sLocale = 'en';
  }
 }else{
  this.sResultCode = 'DB_LOCALE_NOT_STRING';
  this._sLocale = 'en';
 }
 this._oTables = {}; // hash for tables
}

///////////////////////////////////////////////////////////////////////////
// class fields

///////////////////////////////////////////////////////////////////////////
// Text - hash of locale-based texts used
// ex: Text['en']['OK'] = 'No errors';
// locale-based texts must be in separate files
if(!XBSDB.prototype.Text || typeof XBSDB.prototype.Text != 'object'){ XBSDB.prototype.Text = {}; }


///////////////////////////////////////////////////////////////////////////
// public methods


///////////////////////////////////////////////////////////////////////////
// database related

///////////////////////////////////////////////////////////////////////////
// LoadDB - loads entire database from database import dump
// parameters:
// object or string vDatabase - database import dump object or its JSON-string
// returns:
// true when success
// false when failed (sResultCode != 'OK')
XBSDB.prototype.LoadDB = function(vDatabase){
 this.sResultCode = 'OK';

 var oDatabase;
 if(typeof vDatabase == 'string'){
  try{
   eval('oDatabase = ' + vDatabase);
  }catch(e){
   this.sResultCode = 'DB_LOADDB_BAD_STRING';
   return false;
  }

  if(typeof oDatabase != 'object'){
   this.sResultCode = 'DB_LOADDB_EVAL_NOT_OBJECT';
   return false;
  }
 }else if(typeof vDatabase == 'object'){
  oDatabase = vDatabase;
 }else{
  this.sResultCode = 'DB_LOADDB_NOT_STRING_NOT_OBJECT';
  return false;
 }
 if(!oDatabase){
  this.sResultCode = 'DB_LOADDB_OBJECT_NULL';
  return false;
 }

 this._oTables = {};
 for(var sTableName in oDatabase){
  if(!this.LoadTable(sTableName, oDatabase[sTableName])){
   return false;
  }
 }
 return true;
}

///////////////////////////////////////////////////////////////////////////
// DumpDB - dumps entire database (all tables) to database export dump
// parameters:
// [string sType] - type of dump, 'object' or 'string' or null (means 'object')
// returns:
// database export dump when success
// false when failed (sResultCode != 'OK')
XBSDB.prototype.DumpDB = function(sType){
 this.sResultCode = 'OK';

 var oDump = {}, vTableDump;

 for(var sTableName in this._oTables){
  vTableDump = this._oTables[sTableName].Dump();
  if(typeof vTableDump == 'boolean'){
   this.sResultCode = this._oTables[sTableName].sResultCode;
   return false;
  }
  oDump[sTableName] = vTableDump;
 }
 
 if(sType && sType == 'string'){
  var vJSON = this._JSONize(oDump);
  if(typeof vJSON == 'string'){
   return vJSON;
  }else{
   this.sResultCode = 'DB_CANNOT_JSONIZE_DB';
   return false;
  }
 }else{
  return oDump;
 }
}

///////////////////////////////////////////////////////////////////////////
// table related

///////////////////////////////////////////////////////////////////////////
// LoadTable - loads table structure, data and maybe indexes from table import dump
// parameters:
// string sTableName       - table name to load structure and data
// object or string vTable - table import dump object or its JSON-string
// returns:
// true when success
// false when failed (sResultCode != 'OK')
XBSDB.prototype.LoadTable = function(sTableName, vTable){
 this.sResultCode = 'OK';

 var oTable;
 if(typeof vTable == 'string'){
  try{
   eval('oTable = ' + vTable);
  }catch(e){
   this.sResultCode = 'DB_LOADTABLE_BAD_STRING';
   return false;
  }

  if(typeof oTable != 'object'){
   this.sResultCode = 'DB_LOADTABLE_EVAL_NOT_OBJECT';
   return false;
  }
 }else if(typeof vTable == 'object'){
  oTable = vTable;
 }else{
  this.sResultCode = 'DB_LOADTABLE_NOT_STRING_NOT_OBJECT';
  return false;
 }
 if(!oTable){
  this.sResultCode = 'DB_LOADTABLE_OBJECT_NULL';
  return false;
 }

 if(typeof sTableName != 'string'){
  this.sResultCode = 'DB_TABLE_NAME_NOT_STRING';
  return false;
 }
 if(Object.prototype.toString.call(oTable.aStructure) !== '[object Array]'){
  this.sResultCode = 'DB_STRUCTURE_NOT_ARRAY';
  return false;
 }
 if(this.IsTable(sTableName)){
  if(!this.DropTable(sTableName)){
   return false;
  } 
 }
 if(!this.CreateTable(sTableName,oTable.aStructure)){
  return false;
 }

 if(!this.LoadTableData(sTableName,oTable)){
  return false;
 }

 return true;
}

///////////////////////////////////////////////////////////////////////////
// LoadTableData - loads table data and maybe indexes from table data import dump
// parameters:
// string sTableName       - table name to load data
// object or string vTable - table import dump object or its JSON-string
// returns:
// true when success
// false when failed (sResultCode != 'OK')
XBSDB.prototype.LoadTableData = function(sTableName, vTable){
 this.sResultCode = 'OK';

 var oTable;
 if(!this._IsParamTableNameOKExist(sTableName)){
  return false;
 }

 if(typeof vTable == 'string'){
  try{
   eval('oTable = ' + vTable);
  }catch(e){
   this.sResultCode = 'DB_LOADTABLEDATA_BAD_STRING';
   return false;
  }
  if(typeof oTable != 'object'){
   this.sResultCode = 'DB_LOADTABLEDATA_EVAL_NOT_OBJECT';
   return false;
  }
 }else if(typeof vTable == 'object'){
  oTable = vTable;
 }else{
  this.sResultCode = 'DB_LOADTABLEDATA_NOT_STRING_OBJECT';
  return false;
 }
 if(!oTable){
  this.sResultCode = 'DB_LOADTABLEDATA_OBJECT_NULL';
  return false;
 }

 if(oTable.aData){
  if(Object.prototype.toString.call(oTable.aData) === '[object Array]'){
   if(!this._oTables[sTableName].Load(oTable.aData)){
    return false;
   }
   if(oTable.aKeys){
    if(Object.prototype.toString.call(oTable.aKeys) === '[object Array]'){
     for(var i=0; i<oTable.aKeys.length; i++){
      if(typeof oTable.aKeys[i] != 'object'){
       this.sResultCode = 'DB_LOADTABLEDATA_KEY_NOT_OBJECT';
       return false;
      }
      if(typeof oTable.aKeys[i].sExpression != 'string'){
       this.sResultCode = 'DB_LOADTABLEDATA_KEY_EXPR_NOT_STRING';
       return false;
      }
      if(oTable.aKeys[i].aData && Object.prototype.toString.call(oTable.aKeys[i].aData) !== '[object Array]'){
       this.sResultCode = 'DB_LOADTABLEDATA_KEY_DATA_NOT_ARRAY';
       return false;
      }
      if(!this._oTables[sTableName].AddKey(oTable.aKeys[i].sExpression,oTable.aKeys[i].aData)){
       this.sResultCode = this._oTables[sTableName].sResultCode;
       return false;
      }
     }
    }else{
     this.sResultCode = 'DB_LOADTABLEDATA_KEYS_NOT_ARRAY';
     return false;
    }
   } 
  }else{
   this.sResultCode = 'DB_LOADTABLEDATA_DATA_NOT_ARRAY';
   return false;
  }
 }
 return true;
}

///////////////////////////////////////////////////////////////////////////
// DumpTable - dumps table without indexes to table export dump
// parameters:
// string sTableName     - table name to create
// [string sType]        - type of dump, 'object' or 'string' or null (means 'object')
// returns:
// table export dump when success
// false when failed (sResultCode != 'OK')
XBSDB.prototype.DumpTable = function(sTableName, sType){
 this.sResultCode = 'OK';

 if(!this._IsParamTableNameOKExist(sTableName)){
  return false;
 }

 var vTableDump = this._oTables[sTableName].Dump();
 if(typeof vTableDump == 'boolean'){
  this.sResultCode = this._oTables[sTableName].sResultCode;
  return false;
 }
 if(sType && sType == 'string'){
  var vJSON = this._JSONize(vTableDump);
  if(typeof vJSON == 'string'){
   return vJSON;
  }else{
   this.sResultCode = 'DB_CANNOT_JSONIZE_TABLE';
   return false;
  }
 }else{
  return vTableDump;
 }

}

///////////////////////////////////////////////////////////////////////////
// CreateTable - creates a new table in database
// parameters:
// string sTableName     - table name to create
// array aTableStructure - table structure
// returns:
// true when success
// false when failed (sResultCode != 'OK')
XBSDB.prototype.CreateTable = function(sTableName, aTableStructure){
 this.sResultCode = 'OK';

 if(!this._IsParamTableNameOKNotExist(sTableName)){
  return false;
 }

 if(Object.prototype.toString.call(aTableStructure) !== '[object Array]'){
  this.sResultCode = 'DB_STRUCTURE_NOT_ARRAY';
  return false;
 }
 if(aTableStructure.length > 0){
  var oFieldNames = {}, i;
  for(i = 0; i < aTableStructure.length; i++){
   if(Object.prototype.toString.call(aTableStructure[i]) === '[object Array]'){
    if(aTableStructure[i].length < 2){
     this.sResultCode = 'DB_STRUCTURE_BAD';
     return false;
    }
    if(typeof aTableStructure[i][0] != 'string'){
     this.sResultCode = 'DB_FIELD_NAME_NOT_STRING';
     return false;
    }
    if(aTableStructure[i][0].length == 0){
     this.sResultCode = 'DB_FIELD_NAME_EMPTY';
     return false;
    }
    if(oFieldNames[aTableStructure[i][0]]){
     this.sResultCode = 'DB_STRUCTURE_FIELD_DUPLICATE';
     return false;
    }else{
     oFieldNames[aTableStructure[i][0]] = true;
    }
   }else{
    this.sResultCode = 'DB_STRUCTURE_BAD';
    return false;
   }
  }
 }else{
  this.sResultCode = 'DB_STRUCTURE_EMPTY';
  return false;
 }

 var oTable = new XBSTable(aTableStructure);
 if(oTable.sResultCode == 'OK'){
  this._oTables[sTableName] = oTable;
  return true;
 }else{
  this.sResultCode = oTable.sResultCode;
  delete oTable;
  return false;
 }
}

///////////////////////////////////////////////////////////////////////////
// IsTable - checks is table exists or not
// parameters:
// string sTableName - table name to check
// returns:
// true  when table exists
// false when table doesn't exist
// false when failed (sResultCode != 'OK')
XBSDB.prototype.IsTable = function(sTableName){
 this.sResultCode = 'OK';

 if(!this._IsParamTableNameOK(sTableName)){
  return false;
 }
 
 if(this._oTables[sTableName]){
  return true;
 }else{
  return false;
 }
}

///////////////////////////////////////////////////////////////////////////
// ShowTables - lists all tables in database
// parameters:
// none
// returns:
// array with table names when success
// false when failed (sResultCode != 'OK')
XBSDB.prototype.ShowTables = function(){
 this.sResultCode = 'OK';

 var aResult = [];
 for(var s in this._oTables){
  aResult.push(s);
 }
 return aResult;
}

///////////////////////////////////////////////////////////////////////////
// DropTable - removes table from a database
// parameters:
// string sTableName - table name to remove
// returns:
// true when table removed
// false when failed (sResultCode != 'OK')
XBSDB.prototype.DropTable = function(sTableName){
 this.sResultCode = 'OK';

 if(!this._IsParamTableNameOKExist(sTableName)){
  return false;
 }
 
 delete this._oTables[sTableName];
 return true;
}


///////////////////////////////////////////////////////////////////////////
// field related

///////////////////////////////////////////////////////////////////////////
// ShowFields - lists fields names & types in table
// parameters:
// string sTableName - table name
// returns:
// array of 2-element arrays [name, type]
// false when failed (sResultCode != 'OK')
XBSDB.prototype.ShowFields = function(sTableName){
 this.sResultCode = 'OK';

 if(!this._IsParamTableNameOKExist(sTableName)){
  return false;
 }

 var vResult = this._oTables[sTableName].GetStructure();
 if(vResult){
  return vResult;
 }else{
  this.sResultCode = this._oTables[sTableName].sResultCode;
  return false;
 }
}
 
///////////////////////////////////////////////////////////////////////////
// key related

///////////////////////////////////////////////////////////////////////////
// CreateIndex - creates a new key in table
// parameters:
// string sTableName - table name
// string sKeyExpr   - key expression
// returns:
// key id (normalized key expression) when success
// false when failed (sResultCode != 'OK')
XBSDB.prototype.CreateIndex = function(sTableName, sKeyExpr){
 this.sResultCode = 'OK';

 if(!this._IsParamTableNameOKExist(sTableName)){
  return false;
 }

 if(typeof sKeyExpr != 'string'){
  this.sResultCode = 'DB_KEY_EXPR_NOT_STRING';
  return false;
 }
 if(sKeyExpr.length == 0){
  this.sResultCode = 'DB_KEY_EXPR_EMPTY';
  return false;
 }

 var vResult = this._oTables[sTableName].AddKey(sKeyExpr);
 if(vResult){
  return vResult;
 }else{
  this.sResultCode = this._oTables[sTableName].sResultCode;
  return false;
 }
}

///////////////////////////////////////////////////////////////////////////
// IsIndex - checks is key exists or not
// parameters:
// string sTableName - table name
// string sKeyID     - key id
// returns:
// true when key exists
// false when key doesn't exist
// false when failed (sResultCode != 'OK')
XBSDB.prototype.IsIndex = function(sTableName, sKeyID){
 this.sResultCode = 'OK';

 if(!this._IsParamTableNameOKExist(sTableName)){
  return false;
 }
 if(!this._IsParamKeyIDOK(sKeyID)){
  return false;
 }

 var vResult = this._oTables[sTableName].IsKey(sKeyID);
 if(vResult){
  return vResult;
 }else{
  this.sResultCode = this._oTables[sTableName].sResultCode;
  return false;
 }
}

///////////////////////////////////////////////////////////////////////////
// ShowIndexes - lists all keys of one type in table
// parameters:
// string sTableName - table name
// returns:
// array with key names when success
// false when failed (sResultCode != 'OK')
XBSDB.prototype.ShowIndexes = function(sTableName){
 this.sResultCode = 'OK';

 if(!this._IsParamTableNameOKExist(sTableName)){
  return false;
 }

 var vResult = this._oTables[sTableName].GetKeyIDs();
 if(vResult){
  return vResult;
 }else{
  this.sResultCode = this._oTables[sTableName].sResultCode;
  return false;
 }
}

///////////////////////////////////////////////////////////////////////////
// DropIndex - removes key from table
// parameters:
// string sTableName - table name
// string sKeyID     - key id
// returns:
// true when key removed
// false when failed (sResultCode != 'OK')
XBSDB.prototype.DropIndex = function(sTableName, sKeyID){
 this.sResultCode = 'OK';

 if(!this._IsParamTableNameOKExist(sTableName)){
  return false;
 }
 if(!this._IsParamKeyIDOK(sKeyID)){
  return false;
 }

 if(this._oTables[sTableName].DropKey(sKeyID)){
  return true;
 }else{
  this.sResultCode = this._oTables[sTableName].sResultCode;
  return false;
 }
}

///////////////////////////////////////////////////////////////////////////
// data related

///////////////////////////////////////////////////////////////////////////
// InsertOne - inserts one record into table
// parameters:
// string sTableName   - table name
// array aFieldValues  - array of fields values
// [array aFieldNames] - array of fields names or null
// returns:
// true  when success
// false when failed (sResultCode != 'OK')
XBSDB.prototype.InsertOne = function(sTableName, aFieldValues, aFieldNames){
 this.sResultCode = 'OK';

 if(!this._IsParamTableNameOKExist(sTableName)){
  return false;
 }

 if(Object.prototype.toString.call(aFieldNames) === '[object Array]'){
  if(aFieldNames.length == 0){
   aFieldNames = null;
  }
 }

 if(aFieldNames){
  if(!this._IsParamFieldNamesOK(sTableName,aFieldNames)){
   return false;
  }
  if(!this._IsParamFieldValuesOKByNames(sTableName,aFieldNames,aFieldValues)){
   return false;
  }

  if(this._oTables[sTableName].InsertOneByFields(aFieldNames,aFieldValues)){
   return true;
  }else{
   this.sResultCode = this._oTables[sTableName].sResultCode;
   return false;
  }
 }else{
  if(!this._IsParamFieldValuesOKByNumbers(sTableName,aFieldValues)){
   return false;
  }

  if(this._oTables[sTableName].InsertOneByOrder(aFieldValues)){
   return true;
  }else{
   this.sResultCode = this._oTables[sTableName].sResultCode;
   return false;
  }
 }
}

///////////////////////////////////////////////////////////////////////////
// InsertMany - inserts many records into table at once
// parameters:
// string sTableName   - table name
// array aRows         - array of arrays of fields values
// [array aFieldNames] - array of fields names or null
// returns:
// true  when success
// false when failed (sResultCode != 'OK')
XBSDB.prototype.InsertMany = function(sTableName, aRows, aFieldNames){
 this.sResultCode = 'OK';

 if(!this._IsParamTableNameOKExist(sTableName)){
  return false;
 }

 if(Object.prototype.toString.call(aFieldNames) === '[object Array]'){
  if(aFieldNames.length == 0){
   aFieldNames = null;
  }
 }

 if(Object.prototype.toString.call(aRows) !== '[object Array]'){
  this.sResultCode = 'DB_AROWS_NOT_ARRAY';
  return false;
 }

 var vInserted, i;
 
 if(aFieldNames){

  if(!this._IsParamFieldNamesOK(sTableName,aFieldNames)){
   return false;
  }
  for(i = 0; i < aRows.length; i++){
   if(!this._IsParamFieldValuesOKByNames(sTableName,aFieldNames,aRows[i])){
    return false;
   }
  }
  vInserted = this._oTables[sTableName].InsertManyByFields(aFieldNames,aRows);
  if(typeof vInserted == 'number'){
   return vInserted;
  }else{
   this.sResultCode = this._oTables[sTableName].sResultCode;
   return false;
  }

 }else{

  for(i= 0;  i < aRows.length; i++){
   if(!this._IsParamFieldValuesOKByNumbers(sTableName,aRows[i])){
    return false;
   }
  }
  vInserted = this._oTables[sTableName].InsertManyByOrder(aRows);
  if(typeof vInserted == 'number'){
   return vInserted;
  }else{
   this.sResultCode = this._oTables[sTableName].sResultCode;
   return false;
  }

 }
}

///////////////////////////////////////////////////////////////////////////
// Update - updates data in table
// parameters:
// string sTableName   - table name
// array aFieldValues  - array of fields values
// [array aFieldNames] - array of fields names or null
// [string sWhereExpr] - WHERE-expression or null
// returns:
// true  when success
// false when failed (sResultCode != 'OK')
XBSDB.prototype.Update = function(sTableName, aFieldValues, aFieldNames, sWhereExpr){
 this.sResultCode = 'OK';

 if(!this._IsParamTableNameOKExist(sTableName)){
  return false;
 }

 if(Object.prototype.toString.call(aFieldNames) === '[object Array]'){
  if(aFieldNames.length == 0){
   aFieldNames = null;
  }
 }

 if(sWhereExpr){
  sWhereExpr = sWhereExpr.replace(/^\s+/,'').replace(/\s+$/,'');
  if(sWhereExpr != ''){
   if(!this._IsParamWhereExprOK(sWhereExpr)){
    return false;
   }
  }
 }else{
  sWhereExpr = '';
 }

 var vUpdated, vWhereResult;
 
 if(aFieldNames){

  if(!this._IsParamFieldNamesOK(sTableName,aFieldNames)){
   return false;
  }

  if(!this._IsParamFieldValuesOKByNames(sTableName,aFieldNames,aFieldValues)){
   return false;
  }

  if(sWhereExpr.length > 0){
   vWhereResult = this._GetRecordsWhere(sTableName,sWhereExpr);
  }else{
   vWhereResult = this._GetRecordsAll(sTableName);
  }
  if(Object.prototype.toString.call(vWhereResult) !== '[object Array]'){
   this.sResultCode = this._oTables[sTableName].sResultCode;
   return false;
  }

  vUpdated = this._oTables[sTableName].UpdateByFields(aFieldNames,aFieldValues,vWhereResult);
  if(typeof vUpdated == 'number'){
   if(vUpdated == vWhereResult.length){
    return vUpdated;
   }else{
    this.sResultCode = 'DB_RECORDS_2UPD_NE_UPDATED : updated ' + vUpdated + ' instead of ' + vWhereResult.length;
    return false;
   }
  }else{
   this.sResultCode = this._oTables[sTableName].sResultCode;
   return false;
  }

 }else{

  if(!this._IsParamFieldValuesOKByNumbers(sTableName,aFieldValues)){
   return false;
  }

  if(sWhereExpr.length > 0){
   vWhereResult = this._GetRecordsWhere(sTableName,sWhereExpr);
  }else{
   vWhereResult = this._GetRecordsAll(sTableName);
  }
  if(Object.prototype.toString.call(vWhereResult) !== '[object Array]'){
   this.sResultCode = this._oTables[sTableName].sResultCode;
   return false;
  }

  vUpdated = this._oTables[sTableName].UpdateByOrder(aFieldValues,vWhereResult);
  if(typeof vUpdated == 'number'){
   if(vUpdated == vWhereResult.length){
    return vUpdated;
   }else{
    this.sResultCode = 'DB_RECORDS_2UPD_NE_UPDATED : updated ' + vUpdated + ' instead of ' + vWhereResult.length;
    return false;
   }
  }else{
   this.sResultCode = this._oTables[sTableName].sResultCode;
   return false;
  }

 }
}

///////////////////////////////////////////////////////////////////////////
// Delete - removes data from table
// parameters:
// string sTableName   - table name
// [string sWhereExpr] - WHERE-expression or null
// returns:
// number of deleted records when success
// false when failed (sResultCode != 'OK')
XBSDB.prototype.Delete = function(sTableName, sWhereExpr){
 this.sResultCode = 'OK';

 if(!this._IsParamTableNameOKExist(sTableName)){
  return false;
 }

 if(sWhereExpr){
  sWhereExpr = sWhereExpr.replace(/^\s+/,'').replace(/\s+$/,'');
  if(sWhereExpr != ''){
   if(!this._IsParamWhereExprOK(sWhereExpr)){
    return false;
   }
  }
 }else{
  sWhereExpr = '';
 }

 var vWhereResult, nRecDel;

 if(sWhereExpr.length > 0){
  vWhereResult = this._GetRecordsWhere(sTableName,sWhereExpr);
 }else{
  vWhereResult = this._GetRecordsAll(sTableName);
 }
 if(Object.prototype.toString.call(vWhereResult) !== '[object Array]'){
  this.sResultCode = this._oTables[sTableName].sResultCode;
  return false;
 }

 if(vWhereResult.length > 0){
  nRecDel = this._oTables[sTableName].Delete(vWhereResult);
  if(nRecDel == vWhereResult.length){
   return nRecDel;
  }else{
   this.sResultCode = 'DB_RECORDS_2DEL_NE_DELETED' + ' : ' + this._oTables[sTableName].sResultCode;
   return false;
  }
 }else{
  return 0;
 }
}

///////////////////////////////////////////////////////////////////////////
// Select - selects data from table
// parameters:
// string sTableName     - table name
// [array aFieldNames]   - array of result fields names or null
// [string sWhereExpr]   - WHERE expression or null
// [string sOrderByExpr] - ORDER BY expression to sort output or null
// [boolean bDescFlag]   - DESC flag of reverse sorting or null, valid when sOrderByExpr not null only
// [string sGroupByExpr] - GROUP BY expression to group output or null
// returns:
// array of record values arrays when success
// false when failed (sResultCode != 'OK')
XBSDB.prototype.Select = function(sTableName, aFieldNames, sWhereExpr, sOrderByExpr, bDescFlag, sGroupByExpr){
 var vResult = this.SelectToRecordSet(sTableName,sWhereExpr,sOrderByExpr,bDescFlag,sGroupByExpr);
 if(vResult){
  return this.SelectFromRecordSet(sTableName,vResult,aFieldNames);
 }
 return false;
}

///////////////////////////////////////////////////////////////////////////
// SelectToRecordSet - gets array of record identifiers from table
// parameters:
// string sTableName     - table name
// [string sWhereExpr]   - WHERE-expression or null
// [string sOrderByExpr] - ORDER BY expression to sort output or null
// [boolean bDescFlag]   - DESC flag of reverse sorting or null, valid when sOrderByExpr not null only
// [string sGroupByExpr] - GROUP BY expression to group output or null
// returns:
// array of record identifiers when success
// false when failed (sResultCode != 'OK')
XBSDB.prototype.SelectToRecordSet = function(sTableName, sWhereExpr, sOrderByExpr, bDescFlag, sGroupByExpr){
 this.sResultCode = 'OK';

 if(!this._IsParamTableNameOKExist(sTableName)){
  return false;
 }

 if(sWhereExpr){
  sWhereExpr = sWhereExpr.replace(/^\s+/,'').replace(/\s+$/,'');
  if(sWhereExpr != ''){
   if(!this._IsParamWhereExprOK(sWhereExpr)){
    return false;
   }
  }
 }else{
  sWhereExpr = '';
 }

 if(sOrderByExpr){
  if(!this._IsParamOrderByExprOK(sOrderByExpr)){
   return false;
  }
 }else{
  sOrderByExpr = '';
 }

 if(bDescFlag){
  if(!this._IsParamDescFlagOK(bDescFlag)){
   return false;
  }
 }else{
  bDescFlag = false;
 }

 if(sGroupByExpr){
  if(!this._IsParamGroupByExprOK(sGroupByExpr)){
   return false;
  }
 }else{
  sGroupByExpr = '';
 }

 var vResult;

 if(sWhereExpr.length > 0){
  vResult = this._GetRecordsWhere(sTableName,sWhereExpr);
 }else{
  vResult = this._GetRecordsAll(sTableName);
 }

 if(!vResult){
  this.sResultCode = this._oTables[sTableName].sResultCode;
  return false;
 }

 if(sOrderByExpr.length > 0){
  var bResult = this._oTables[sTableName].SortRecordsOrderBy(vResult,sOrderByExpr,bDescFlag);
  if(!bResult){
   this.sResultCode = this._oTables[sTableName].sResultCode;
   return false;
  }
 }

 if(sGroupByExpr.length > 0){
  var vResult = this._oTables[sTableName].GetRecordsGroupBy(vResult,sGroupByExpr);
  if(!vResult){
   this.sResultCode = this._oTables[sTableName].sResultCode;
   return false;
  }
 }

 return vResult;
}

///////////////////////////////////////////////////////////////////////////
// SelectFromRecordSet - selects data from array of record identifiers
// parameters:
// string sTableName   - table name
// array aRecords      - array of record identifiers
// [array aFieldNames] - array of result fields names or null
// [number nOffset]    - offset of result records or null
// [number nLimit]     - number of result records or null
// returns:
// array of record values arrays when success
// false when failed (sResultCode != 'OK')
XBSDB.prototype.SelectFromRecordSet = function(sTableName, aRecords, aFieldNames, nOffset, nLimit){
 this.sResultCode = 'OK';

 if(!this._IsParamTableNameOKExist(sTableName)){
  return false;
 }

 if(Object.prototype.toString.call(aRecords) === '[object Array]'){
  if(aRecords.length == 0){
   return [];
  }
 }else{
  this.sResultCode = 'DB_RECORDS_NOT_ARRAY';
  return false;
 }

 if(Object.prototype.toString.call(aFieldNames) === '[object Array]'){
  if(aFieldNames.length == 0){
   aFieldNames = null;
  }
 }

 if(aFieldNames){
  if(!this._IsParamFieldNamesOK(sTableName,aFieldNames)){
   return false;
  }
 }

 if(nOffset){
  if(typeof nOffset == 'number'){
   if(nOffset < 0){
    this.sResultCode = 'DB_OFFSET_NEGATIVE';
    return false;
   }
  }else{
   this.sResultCode = 'DB_OFFSET_NOT_NUMBER';
   return false;
  }
 }else{
  nOffset = 0;
 }

 if(nLimit){
  if(typeof nLimit == 'number'){
   if(nLimit < 0){
    this.sResultCode = 'DB_LIMIT_NEGATIVE';
    return false;
   }
  }else{
   this.sResultCode = 'DB_LIMIT_NOT_NUMBER';
   return false;
  }
 }else{
  nLimit = aRecords.length;
 }

 if(aFieldNames){
  vResult = this._oTables[sTableName].GetRows(aFieldNames,aRecords,nOffset,nLimit);
 }else{
  vResult = this._oTables[sTableName].GetRowsAll(aRecords,nOffset,nLimit);
 }

 if(!vResult){
  this.sResultCode = this._oTables[sTableName].sResultCode;
  return false;
 }
 return vResult;
}

///////////////////////////////////////////////////////////////////////////
// Rows2String - gets string from array of record value arrays, uses toString
// parameters:
// array aRows         - array of record values arrays
// string sRowBefore   - string to put before each row
// string sRowAfter    - string to put after each row
// string sValueBefore - string to put before each value
// string sValueAfter  - string to put after each value
// string sEmptyString - string to replace empty string values
// returns:
// string
// false when failed (sResultCode != 'OK')
XBSDB.prototype.Rows2String = function(aRows, sRowBefore, sRowAfter, sValueBefore, sValueAfter, sValueEmpty){
 this.sResultCode = 'OK';

 if(Object.prototype.toString.call(aRows) !== '[object Array]'){
  this.sResultCode = 'DB_AROWS_NOT_ARRAY';
  return false;
 }
 
 if(sRowBefore){
  if(typeof sRowBefore != 'string'){
   this.sResultCode = 'DB_ROW_BEFORE_NOT_STRING';
   return false;
  }
 }else{
  sRowBefore = '';
 }

 if(sRowAfter){
  if(typeof sRowAfter != 'string'){
   this.sResultCode = 'DB_ROW_AFTER_NOT_STRING';
   return false;
  }
 }else{
  sRowAfter = '';
 }

 if(sValueBefore){
  if(typeof sValueBefore != 'string'){
   this.sResultCode = 'DB_VALUE_BEFORE_NOT_STRING';
   return false;
  }
 }else{
  sValueBefore = '';
 }

 if(sValueAfter){
  if(typeof sValueAfter != 'string'){
   this.sResultCode = 'DB_VALUE_AFTER_NOT_STRING';
   return false;
  }
 }else{
  sValueAfter = '';
 }

 if(sValueEmpty){
  if(typeof sValueEmpty != 'string'){
   this.sResultCode = 'DB_VALUE_EMPTY_NOT_STRING';
   return false;
  }
 }else{
  sValueEmpty = '';
 }

 var sResult = '', i, j, sOut;
 for(i = 0; i < aRows.length; i++){
  if(Object.prototype.toString.call(aRows[i]) === '[object Array]'){
   sResult += sRowBefore;
   for(j = 0; j < aRows[i].length; j++){
    if(aRows[i][j] != null){
     sOut = aRows[i][j].toString();
    }else{
     sOut = sValueEmpty;
    }
    sResult += sValueBefore + sOut + sValueAfter;
   }
   sResult += sRowAfter;
  }
 }
 return sResult;
}

///////////////////////////////////////////////////////////////////////////
// Rows2LocaleString - gets string from array of record value arrays, uses toLocaleString
// parameters:
// array aRows         - array of record values arrays
// string sRowBefore   - string to put before each row
// string sRowAfter    - string to put after each row
// string sValueBefore - string to put before each value
// string sValueAfter  - string to put after each value
// string sEmptyString - string to replace empty string values
// returns:
// string
// false when failed (sResultCode != 'OK')
XBSDB.prototype.Rows2LocaleString = function(aRows, sRowBefore, sRowAfter, sValueBefore, sValueAfter, sValueEmpty){
 this.sResultCode = 'OK';

 if(Object.prototype.toString.call(aRows) !== '[object Array]'){
  this.sResultCode = 'DB_AROWS_NOT_ARRAY';
  return false;
 }
 
 if(sRowBefore){
  if(typeof sRowBefore != 'string'){
   this.sResultCode = 'DB_ROW_BEFORE_NOT_STRING';
   return false;
  }
 }else{
  sRowBefore = '';
 }

 if(sRowAfter){
  if(typeof sRowAfter != 'string'){
   this.sResultCode = 'DB_ROW_AFTER_NOT_STRING';
   return false;
  }
 }else{
  sRowAfter = '';
 }

 if(sValueBefore){
  if(typeof sValueBefore != 'string'){
   this.sResultCode = 'DB_VALUE_BEFORE_NOT_STRING';
   return false;
  }
 }else{
  sValueBefore = '';
 }

 if(sValueAfter){
  if(typeof sValueAfter != 'string'){
   this.sResultCode = 'DB_VALUE_AFTER_NOT_STRING';
   return false;
  }
 }else{
  sValueAfter = '';
 }

 if(sValueEmpty){
  if(typeof sValueEmpty != 'string'){
   this.sResultCode = 'DB_VALUE_EMPTY_NOT_STRING';
   return false;
  }
 }else{
  sValueEmpty = '';
 }

 var sResult = '', i, j, sOut;
 for(i = 0; i < aRows.length; i++){
  if(Object.prototype.toString.call(aRows[i]) === '[object Array]'){
   sResult += sRowBefore;
   for(j = 0; j < aRows[i].length; j++){
    if(aRows[i][j] != null){
     sOut = aRows[i][j].toLocaleString();
    }else{
     sOut = sValueEmpty;
    }
    sResult += sValueBefore + sOut + sValueAfter;
   }
   sResult += sRowAfter;
  }
 }
 return sResult;
}

///////////////////////////////////////////////////////////////////////////
// locale related

///////////////////////////////////////////////////////////////////////////
// ResultText - returns last result status explaination in current locale
// returns:
// string
XBSDB.prototype.ResultText = function(){
 var sResultText = this.sResultCode;
 if(sResultText != 'OK'){
  sResultText = 'ERROR: ' + sResultText;
 }
 if(this.Text[this._sLocale] && typeof this.Text[this._sLocale] == 'object'){
  for(var s in this.Text[this._sLocale]){
   sResultText = sResultText.replace(s,this.Text[this._sLocale][s]);
  }
 }
 return sResultText;
}

///////////////////////////////////////////////////////////////////////////
// SetLocale - sets database locale
// parameters:
// string sLocale - string of locale
// returns:
// true when success
// false when failed (sResultCode != 'OK')
XBSDB.prototype.SetLocale = function(sLocale){
 this.sResultCode = 'OK';

 if(sLocale && typeof sLocale == 'string'){
  if(XBSDB.prototype.Text && typeof XBSDB.prototype.Text == 'object' && typeof XBSDB.prototype.Text[sLocale] == 'object'){
   this._sLocale = sLocale;
   return true;
  }else{
   this.sResultCode = 'DB_LOCALE_NOT_DEFINED';
   return false;
  }
 }else{
  this.sResultCode = 'DB_LOCALE_NOT_STRING';
  return false;
 }
}

///////////////////////////////////////////////////////////////////////////
// GetLocale - gets database locale
// parameters:
// none
// returns:
// string - current locale
XBSDB.prototype.GetLocale = function(){
 this.sResultCode = 'OK';

 return this._sLocale;
}

///////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
// private methods

///////////////////////////////////////////////////////////////////////////
// parameter checking methods
XBSDB.prototype._IsParamTableNameOK = function(sTableName){
 if(typeof sTableName != 'string'){
  this.sResultCode = 'DB_TABLE_NAME_NOT_STRING';
  return false;
 }
 if(sTableName.length == 0){
  this.sResultCode = 'DB_TABLE_NAME_EMPTY';
  return false;
 }
 return true;
}

XBSDB.prototype._IsParamTableNameOKExist = function(sTableName){
 if(!this._IsParamTableNameOK(sTableName)){
  return false;
 }
 if(!this._oTables[sTableName]){
  this.sResultCode = 'DB_TABLE_NOT_EXIST';
  return false;
 }
 return true;
}

XBSDB.prototype._IsParamTableNameOKNotExist = function(sTableName){
 if(!this._IsParamTableNameOK(sTableName)){
  return false;
 }
 if(this._oTables[sTableName]){
  this.sResultCode = 'DB_TABLE_EXIST';
  return false;
 }
 return true;
}

XBSDB.prototype._IsParamFieldNamesOK = function(sTableName,aFieldNames){
 if(Object.prototype.toString.call(aFieldNames) !== '[object Array]'){
  this.sResultCode = 'DB_FIELD_NAMES_NOT_ARRAY';
  return false;
 }
 if(aFieldNames.length > 0){
  var oFieldNames = {}, i;
  for(i = 0; i < aFieldNames.length; i++){
    if(typeof aFieldNames[i] != 'string'){
     this.sResultCode = 'DB_FIELD_NAME_TYPE_NOT_STRING';
     return false;
    }
    if(!this._oTables[sTableName].IsCol(aFieldNames[i])){
     this.sResultCode = 'DB_FIELD_NAME_NOT_EXIST';
     return false;
    }
    if(oFieldNames[aFieldNames[i]]){
     this.sResultCode = 'DB_FIELD_DUPLICATE';
     return false;
    }else{
     oFieldNames[aFieldNames[i]] = true;
    }
  }
 }else{
  this.sResultCode = 'DB_FIELD_NAMES_EMPTY';
  return false;
 }
 return true;
}

XBSDB.prototype._IsParamFieldValuesOKByNames = function(sTableName,aFieldNames,aFieldValues){
 if(Object.prototype.toString.call(aFieldValues) !== '[object Array]'){
  this.sResultCode = 'DB_FIELD_VALUES_NOT_ARRAY';
  return false;
 }
 if(aFieldValues.length > 0){
  for(var i = 0; i < aFieldValues.length; i++){
    if(typeof aFieldValues[i] != this._oTables[sTableName].GetColTypeByName(aFieldNames[i])){
     this.sResultCode = 'DB_FIELD_VALUE_TYPE_MISMATCH';
     return false;
    }
  }
 }else{
  this.sResultCode = 'DB_FIELD_VALUES_EMPTY';
  return false;
 }
 return true;
}

XBSDB.prototype._IsParamFieldValuesOKByNumbers = function(sTableName,aFieldValues){
 if(Object.prototype.toString.call(aFieldValues) !== '[object Array]'){
  this.sResultCode = 'DB_FIELD_VALUES_NOT_ARRAY';
  return false;
 }
 if(aFieldValues.length > 0){
  for(var i = 0; i < aFieldValues.length; i++){
    if(typeof aFieldValues[i] != this._oTables[sTableName].GetColTypeByNumber(i)){
     this.sResultCode = 'DB_FIELD_VALUE_TYPE_MISMATCH';
     return false;
    }
  }
 }else{
  this.sResultCode = 'DB_FIELD_VALUES_EMPTY';
  return false;
 }
 return true;
}

XBSDB.prototype._IsParamKeyIDOK = function(sKeyID){
 if(typeof sKeyID != 'string'){
  this.sResultCode = 'DB_KEY_ID_NOT_STRING';
  return false;
 }
 if(sKeyID.length == 0){
  this.sResultCode = 'DB_KEY_ID_EMPTY';
  return false;
 }
 return true;
}

XBSDB.prototype._IsParamWhereExprOK = function(sWhereExpr){
 if(typeof sWhereExpr != 'string'){
  this.sResultCode = 'DB_WHERE_EXPR_NOT_STRING';
  return false;
 }
 return true;
}

XBSDB.prototype._IsParamOrderByExprOK = function(sOrderByExpr){
 if(typeof sOrderByExpr != 'string'){
  this.sResultCode = 'DB_ORDER_BY_EXPR_NOT_STRING';
  return false;
 }
 return true;
}

XBSDB.prototype._IsParamDescFlagOK = function(bDescFlag){
 if(typeof bDescFlag != 'boolean'){
  this.sResultCode = 'DB_DESC_FLAG_NOT_BOOL';
  return false;
 }
 return true;
}

XBSDB.prototype._IsParamGroupByExprOK = function(sGroupByExpr){
 if(typeof sGroupByExpr != 'string'){
  this.sResultCode = 'DB_GROUP_BY_EXPR_NOT_STRING';
  return false;
 }
 return true;
}

///////////////////////////////////////////////////////////////////////////
// data operation methods
XBSDB.prototype._GetRecordsWhere = function(sTableName, sWhereExpr){
 var vResult = this._oTables[sTableName].GetRecordsWhere(sWhereExpr);
 if(vResult){
  if(Object.prototype.toString.call(vResult) === '[object Array]'){
   return vResult;
  }else{
   this.sResultCode = 'DB_RECORDS_NOT_ARRAY';
   return false;
  }
 }else{
  this.sResultCode = this._oTables[sTableName].sResultCode;
  return false;
 }
}

XBSDB.prototype._GetRecordsAll = function(sTableName){
 var vResult = this._oTables[sTableName].GetRecordsAllPacked();
 if(vResult){
  if(Object.prototype.toString.call(vResult) === '[object Array]'){
   return vResult;
  }else{
   this.sResultCode = 'DB_RECORDS_NOT_ARRAY';
   return false;
  }
 }else{
  this.sResultCode = this._oTables[sTableName].sResultCode;
  return false;
 }
}

///////////////////////////////////////////////////////////////////////////
// JSON operation methods
XBSDB.prototype._JSONize = function(vValue){
 switch(typeof vValue){
  case 'boolean' :
  case 'number' :
   return('' + vValue);
  case 'string' :
   return('"' + vValue.replace(/\\/g,'\\').replace(/"/g,'\"').replace(/\//g,'\/').replace(/[\b]/g,'\b').replace(/\f/g,'\f').replace(/\n/g,'\n').replace(/\r/g,'\r').replace(/\t/g,'\t') + '"');
  case 'object' :
   var sResult = '', vJSON, i
   if(Object.prototype.toString.call(vValue) === '[object Array]'){
    sResult = '';
    for(i=0; i<vValue.length; i++){
     vJSON = this._JSONize(vValue[i]);
     if(typeof vJSON == 'string'){
      sResult += (sResult.length == 0 ? '' : ',') + vJSON;
     }else{
      return false;
     }
    }
    sResult = '[' + sResult + ']';
   }else{
    sResult = '';
    for(i in vValue){
     vJSON = this._JSONize(vValue[i]);
     if(typeof vJSON == 'string'){
      sResult += (sResult.length == 0 ? '' : ',') + '"' + i + '":' + vJSON + '';
     }else{
      return false;
     }
    }
    sResult = '{' + sResult + '}';
   }
   return sResult;
 }
 return false;
}