1 /* ***************************************************************************** 2 * ITSV GmbH 3 * 4 * Software Operations 5 * Zentrale Daten und Services 6 * 7 * Product: CCDB 8 * Module: db 9 * Description: This module contains database functions for CCDB 10 * History: 11 * Date | Author | Version | DESCRIPTION 12 * -----------+-----------+------------+------------------------------------------- 13 * 04.11.2015 | WSC | 0.6 | extracted from ccdb.js 14 * 12.01.2016 | WSC | 0.8 | start structures for dbtype 15 * | | | 16 * | | | 17 * | | | 18 * | | | 19 * | | | 20 */ 21 22 // var oracledb = require("oracledb"); 23 // var mysqldb = require("mysql"); 24 var oracledb = null; 25 var mysqldb = null; 26 27 var flow = require('flow'); 28 29 var aux = require('./auxiliary.js'); 30 var dbConfig = require('./dbConfig.js'); 31 32 var logger = null; 33 var mastername = "ccdb.db.mastername not set"; 34 var prefs = {"default" : "db.prefs not set"}; 35 36 var currentConfig = {}; 37 38 function init_database(cfg) { 39 var did_it = false; 40 cfg.dbtype = cfg.dbtype || "not_defined"; 41 if (cfg.dbtype=="oracledb") { 42 if (!oracledb) { 43 oracledb = require("oracledb"); 44 did_it = true; 45 } 46 } else if (cfg.dbtype=="mysql") { 47 if (!mysqldb) { 48 mysqldb = require("mysql"); 49 did_it = true; 50 } 51 } else { 52 logger.error("Illegal database type \""+cfg.dbtype+"\""); 53 } 54 if (did_it) { 55 logger.debug("Database "+cfg.dbname+" of type "+cfg.dbtype+" initialized"); 56 } 57 } 58 59 /* 60 * CLASS: Connection 61 * CONSTRUCTOR: 62 * INPUT: il - object with initial values for attributes: 63 * cfgname - name of configuration set in dbConfig to be used 64 */ 65 function Connection(il) { 66 if (il) { 67 if (il.cfgname) { 68 this.cfgname = il.cfgname; 69 } else if (il.dbcfg) { 70 this.cfg = il.dbcfg; 71 this.cfgname = this.cfg.getName(); 72 } 73 if (!this.cfg && this.cfgname) { 74 this.cfg = getConfigByName(this.cfgname); 75 } 76 } else { 77 this.cfgname = null; 78 } 79 if (!this.cfgname) { 80 this.cfg = getCurrentConfig(); 81 this.cfgname = this.cfg.getName(); 82 } 83 init_database(this.cfg); 84 this.status = "initialized"; 85 this.getConfig = function() { 86 return this.cfg; 87 } 88 this.connect = function(rfunc) { 89 // logger.debug("DB.Connection.connect.BEGIN.CFGNAME=\""+this.cfg.getName()+"\".TYPE="+this.cfg.getType()+"\".CFGSTATUS=\""+this.cfg.getStatus()+"\".CONNSTATUS=\""+this.status+"\""); 90 this.callback = rfunc; 91 this.status = "connecting"; 92 switch (this.cfg.dbtype) { 93 case "oracledb": 94 oracledb.getConnection( 95 { 96 user : this.cfg.getUser(), 97 password : this.cfg.getPassword(), 98 connectString : this.cfg.getConnectString(), 99 }, 100 function(err,conn) { 101 this.oracleConnCompl(err,conn); 102 }.bind(this)); 103 break; 104 case "mysql": 105 this.dbconnection = mysqldb.createConnection({ 106 user : this.cfg.user, 107 password: this.cfg.password, 108 database: this.cfg.database 109 }); 110 // logger.debug("DB.Connection.connect.have_connection_object_will_connect"); 111 this.dbconnection.connect(function(err) { 112 this.mysqlConnCompl(err); 113 }.bind(this)); 114 break; 115 default: 116 throw new Error("Illegal dbtype \""+this.cfg.dbtype+"\""); 117 } 118 } 119 this.mysqlConnCompl = function(err) { 120 // logger.debug("DB.Connection.mysqlconncomplete"); 121 if (err) { 122 aux.error_callback(this.callback,err,"Error connecting via mysql"); 123 return; 124 } 125 this.status = "connected"; 126 this.callback(null,this.dbconnection); 127 } 128 this.oracleConnCompl = function(err,conn) { 129 if (err) { 130 aux.error_callback(this.callback,err,"Error connecting via oracledb",conn); 131 return; 132 } 133 this.dbconnection = conn; 134 this.status = "connected"; 135 this.callback(null,this); 136 } 137 this.execute = function(dbr,rfunc) { 138 this.callback = rfunc; 139 this.mydbr = dbr; 140 if (!this.dbconnection) { 141 aux.error_callback(this.callback,null,"no database connection to execute upon",this); 142 return; 143 } 144 if (this.mydbr.options && this.mydbr.options.notranslate) { 145 this.translated_sql = this.mydbr.sql; // translation explicitely disabled => take the default SQL 146 } else { 147 if (this.mydbr['sql_'+this.cfg.dbtype]) { // there is a CFG-specific SQL in the DBR => no translation, take dbr.sql_<dbtype> 148 this.translated_sql = this.mydbr['sql_'+this.cfg.dbtype]; 149 } else { 150 this.translated_sql = this.translateSQL(this.mydbr.sql,this.mydbr.reqid,this.cfg.dbtype,this.mydbr.sqldbtype); // translate, if possible 151 } 152 } 153 /* 154 if (this.mydbr.sql!=this.translated_sql) { 155 logger.debug("db.Connection.execute.TRANSLATED_SQL=\""+this.translated_sql+"\""); 156 } 157 */ 158 switch (this.cfg.dbtype) { 159 case "oracledb": 160 this.dbconnection.execute(this.translated_sql,this.mydbr.params,{resultSet: this.mydbr.options.resultSet}, 161 function(err,result) { 162 this.oracledbExeCompl(err,result); 163 }.bind(this)); 164 break; 165 case "mysql": 166 // logger.debug("MYSQL.Execute: params: ",this.mydbr.params); 167 this.dbconnection.query(this.translated_sql,this.mydbr.params, 168 function(err,results,fields) { 169 this.mysqlExeCompl(err,results,fields); 170 }.bind(this) 171 ); 172 break; 173 default: 174 aux.error_callback(this.callback,null,"Illegal dbytpe \""+this.cfg.dbtype+"\" in db.Connection.execute"); 175 return; 176 } 177 } 178 this.oracledbExeCompl = function(err,result) { 179 this.callback(err,result); 180 } 181 this.mysqlExeCompl = function(err,results,fields) { 182 // logger.debug("MySQL exec complete:"); 183 // logger.debug("RESULTS: ",results); 184 // logger.debug("FIELDS: ",fields); 185 if (err) { 186 logger.error("MYSQL.Execute-error: ",err); 187 } 188 this.result = {resulttype: "dbresult"}; 189 if (results && fields) { 190 var curow = null; 191 var rn = 0; 192 var ci = 0; 193 this.result.rows = new Array(); 194 this.result.metaData = new Array(); 195 for (ci = 0; ci<fields.length; ci++) { // get column names from fields array, array index determines sequence of field values in results object 196 this.result.metaData.push({name: fields[ci].name}); 197 } 198 this.result.rowsinresult = results.length; 199 for (var rn = 0; rn<results.length; rn++) { // iterate over all rows in the result 200 if (this.mydbr.options && this.mydbr.options.maxrowstoget && (rn>=this.mydbr.options.maxrowstoget)) { 201 break; // if limit specified, cut off 202 } 203 curow = new Array(); 204 for (ci=0; ci<this.result.metaData.length; ci++) { // iterate over all fields in each row object as specified by fields array 205 curow.push(results[rn][this.result.metaData[ci].name]); 206 } 207 this.result.rows.push(curow); 208 } 209 this.result.rowsgot = this.result.rows.length; 210 } 211 this.callback(err,this.result); 212 } 213 this.translateSQL = function(sql,reqid,targetdbtype,sourcedbtype) { 214 if ((targetdbtype==sourcedbtype) && (sql)) { // if to be translated to the same DB type AND sql is known ... 215 return sql; // ... no action required 216 } 217 ttab = dbConfig.sqlstrings; 218 for (var i = 0; i<ttab.length; i++) { // search sqlstrings entry with matching REQID and DBTYPE 219 // logger.debug("translateSQL: checking TTAB DBTYPE/REQID \""+ttab[i].dbtype+"/"+ttab[i].reqid+"\" against requested DBTYPE/REQID \""+targetdbtype+"/"+reqid+"\""); 220 if ((reqid==ttab[i].reqid) && (targetdbtype==ttab[i].dbtype)) { 221 return ttab[i].sql; 222 } 223 } 224 logger.warn("No target SQL found for TARGETDBTYPE=\""+targetdbtype+"\".SOURCEDBTYPE=\""+sourcedbtype+"\".REQID=\""+reqid+"\".SQL:\n\""+sql+"\"\n, default to source SQL"); 225 return sql; 226 } 227 this.commit = function(rfunc) { 228 this.callback = rfunc; 229 this.status = "committing"; 230 switch (this.cfg.dbtype) { 231 case "oracledb": 232 this.dbconnection.commit(this.callback); 233 break; 234 case "mysql": 235 this.dbconnection.query("COMMIT",[], 236 function(err,results,fields) { 237 // logger.debug("MYSQLCOMMITCOMPLERR:",err); 238 this.mysqlCommitCompl(err,results,fields); 239 }.bind(this) 240 ); 241 break; 242 default: 243 aux.error_callback(this.callback,null,"Illegal dbtype \""+this.cfg.dbtype+"\" in db.Connection.commit"); 244 return; 245 } 246 } 247 this.mysqlCommitCompl = function(err,results,fields) { 248 // logger.debug("MySQL commit complete:"); 249 // logger.debug("RESULTS: ",results); 250 // logger.debug("FIELDS: ",fields); 251 this.callback(err,null); 252 } 253 this.release = function(rfunc) { 254 this.callback = rfunc; 255 // logger.debug("DB.Connection.release.DBTYPE=\""+this.cfg.dbtype+"\""); 256 switch (this.cfg.dbtype) { 257 case "oracledb": 258 this.dbconnection.release(function(err) { 259 if (err) logger.debug("ORACLEDBENDCOMPLERR:",err); 260 this.oracleEndCompl(err); 261 }.bind(this) 262 ); 263 break; 264 case "mysql": 265 this.dbconnection.end(function(err) { 266 if (err) logger.debug("MYSQLENDCOMPLERR:",err); 267 this.mysqlEndCompl(err); 268 }.bind(this) 269 ); 270 break; 271 default: 272 aux.error_callback(this.callback,null,"Illegal dbtype \""+this.cfg.dbtype+"\" in db.Connection.commit"); 273 return; 274 } 275 } 276 this.oracleEndCompl = function(err) { 277 this.callback(err); 278 } 279 this.mysqlEndCompl = function(err) { 280 this.callback(err); 281 } 282 } 283 284 /* 285 * CLASS: Request 286 */ 287 function Request(info,headertext,desctext,sql,params,options) { 288 if (typeof info === 'string') { // positional parameters, single strings 289 this.info = info; 290 this.headertext = headertext; 291 this.desctext = desctext; 292 this.sql = sql; 293 this.params = params; 294 this.options = options || {status: "no options provided to Request-constructor with positional parameters"}; 295 if (this.options.reqid) { // positional parameters do not allow reqid, but can be placed in options 296 this.reqid = this.options.reqid; 297 } 298 } else { // non-positional parameters, one object 299 var dbt = getCurrentConfigDBtype(); 300 this.sql = info.sql || "SELECT 'NO SQL PROVIDED in DBrequest Constructor' as ERROR FROM DUAL"; 301 if (info['sql_'+dbt]) { 302 this['sql_'+dbt] = info['sql_'+dbt]; 303 } 304 this.sqldbtype = info.sqldbtype || "oracledb"; 305 this.reqid = info.reqid || "RQID_NOTSET"; 306 this.info = info.info || "SQL: \""+this.sql+"\""; 307 this.headertext = info.headertext || "Result of "+this.info+":"; 308 this.desctext = info.desctext || "Result of "+this.info; 309 this.params = info.params || new Array(); 310 this.options = info.options || {status: "no options provided to Request-constructor with non-positional parameters"}; 311 } 312 if (this.reqid=="RQID_NOTSET") { 313 logger.error("Error in DBrequest: no REQID supplied, compatibility violated"); 314 } 315 this.config = this.options.config || getCurrentConfig(); 316 // ... methods ... 317 this.setParams = function(theParams) { 318 this.params = theParams; 319 } 320 this.getSQL = function() { 321 return this.sql; 322 } 323 this.setSQL = function(theSQL) { 324 this.sql = theSQL; 325 } 326 this.getConfig = function() { 327 return this.config; 328 } 329 this.getDBtype = function() { 330 return this.config.getType(); 331 } 332 } 333 334 /* 335 * CLASS: DBresult 336 */ 337 function Result() { 338 this.resulttype = 'dbresult'; 339 this.metaData = new Array(); 340 this.rows = new Array(); 341 } 342 343 /* 344 * CLASS: Config 345 */ 346 function Config(constrObj) { 347 this.status = "uninitialized"; 348 if (constrObj) { 349 if (typeof(constrObj)==="string") { // parameter is configuration name 350 this.cfgname = constrObj; 351 } else if (typeof(constrObj)==="object") { 352 if (constrObj.configName) { 353 this.cfgname = constrObj.configName 354 } 355 } else { 356 throw new Error("Illegal type of db.Config constructor parameter"); 357 } 358 if (this.cfgname && dbConfig.dbconfigs[this.cfgname]) { 359 this.configName = this.cfgname; 360 var o = dbConfig.dbconfigs[constrObj.configName]; 361 for (var a in o) { 362 this[a] = o[a]; 363 } 364 this.dbname = o.dbname; 365 this.user = o.user; 366 this.password = o.password; 367 this.connectString = o.connectString; 368 this.status = 'initialized'; 369 } 370 } 371 this.getAtt = function(attnam) { 372 return this[attnam]; 373 } 374 this.getName = function() { 375 return this.configName; 376 } 377 this.getConnectString = function() { 378 return this.connectString; 379 } 380 this.getHost = function() { 381 return this.host; 382 } 383 this.getDatabase = function() { 384 return this.database; 385 } 386 this.getUser = function() { 387 return this.user; 388 } 389 this.getPassword = function() { 390 return this.password; 391 } 392 this.setStatus = function(statxt) { 393 this.status = statxt; 394 } 395 this.getStatus = function() { 396 return this.status; 397 } 398 this.getType = function() { 399 return this.dbtype; 400 } 401 } 402 403 function getConfigByName(cfgname) { 404 return new Config(cfgname); 405 } 406 407 /* ***************************************************************************** 408 * 409 * FLOW: db.select 410 * INPUT: DBR - DBrequest object 411 * RFUNC - callback function to be called upon completion 412 * parameters: 413 * ERR - an Error Object, if undefined, everything OK 414 * RESULT - a RESULT-Object 415 * PFUNC - callback function to be called for progress info 416 * parameters: 417 * PROG - a hierarchical object describing the progress of the operation 418 * RETURNS: - 419 * DESCRIPTION: performs an SQL Select (or other DML statement) 420 * upon completion, RFUNC is called with an error object and a DBresult object as parameters 421 */ 422 423 function dbselect_keepalive(that) { 424 that.keepalivecounter++; 425 var kam = {action: "DBSelect", 426 stage: "execute", 427 stateunit: "seconds", 428 state: that.keepalivecounter}; 429 // logger.debug(kam); 430 if (that.dbr.pcallback) that.dbr.pcallback(kam); 431 that.keepalive = setTimeout(dbselect_keepalive,1000,that); 432 } 433 434 var select = flow.define( 435 // step 1: request database connection 436 function(dbr,rfunc,pfunc) { 437 aux.default_param(dbr,"sql","SELECT 'Error: no SQL-Statement given to DBSelect' from DUAL"); 438 aux.default_param(dbr,"params",new Array()); 439 aux.default_param(dbr,"options",{}); 440 aux.default_param(dbr,"sqldbtype","oracledb"); 441 aux.default_param(dbr,"dbcfg",getCurrentConfig()); 442 aux.default_param(dbr.options,"docommit",(dbr.sql.toUpperCase().substring(0,6)!='SELECT')); 443 if ((dbr.options.docommit) && (typeof dbr.options.docommit === 'string') && (dbr.options.docommit.toUpperCase()!='TRUE')) { 444 dbr.options.docommit = false; 445 } 446 aux.default_param(dbr.options,"maxrowstoget",1000); 447 aux.default_param(dbr.options,"numrows",200); 448 aux.default_param(dbr.options,"resultSet",!dbr.options.docommit); // resultSet can only be used if select statement, therefore we check if there is a commit 449 aux.default_param(dbr.options,"status_override",false); 450 aux.default_param(dbr,'headertext',dbr.sql); 451 aux.default_param(dbr,'info',"SQL=\""+(dbr.sql.length>10?dbr.sql.substr(0,10)+"...":dbr.sql)+"\""); 452 dbr.callback = rfunc; 453 dbr.pcallback = pfunc; 454 this.dbr = dbr; 455 this.dbr.starttime = Date.now(); // measure elapsed time in milliseconds starting here 456 // logger.debug("db.select.BEGIN.INFO="+this.dbr.info); 457 // logger.debug("db.select.OPTIONS:"); 458 // logger.debug(this.dbr.options); 459 if ((dbr.dbcfg.getStatus()!='ready') && !(dbr.options.status_override)) { 460 var err = new Error("DBSelect: cannot access database "+getCurrentConfig().getName()+", status is \""+getCurrentConfig().getStatus()+"\""); 461 logger.error(err.message); 462 this.dbr.callback(err,undefined); 463 return; 464 } 465 if (this.dbr.pcallback) this.dbr.pcallback({action: "DBSelect", stage: "1/6 - connecting"}); 466 this.dbconnection = new Connection(); 467 this.dbconnection.connect(this); 468 }, 469 // step 2: got connection, execute SQL 470 function(err) { 471 if (err) { 472 aux.error_callback(this.dbr.callback,err,"DBSelect: Error in Connect",this.dbconnection); 473 return; 474 } 475 // logger.debug("DBSelect.SQL=\""+this.dbr.sql+"\""+(this.dbr.params.length>0?".PARAMS=[\""+this.dbr.params.join("\",\"")+"\"]":".NOPARAMS")); 476 if (this.dbr.pcallback) this.dbr.pcallback({action: "DBSelect", stage: "2/6 - executing"}); 477 this.keepalivecounter = 0; 478 this.keepalive = setTimeout(dbselect_keepalive,1000,this); 479 this.dbconnection.execute(this.dbr,this); 480 }, 481 // step 3: executed, start fetching result 482 function(err,result) { 483 clearTimeout(this.keepalive); 484 if (err) { 485 aux.error_callback(this.dbr.callback,err,"DBSelect: Error in SQL-Execute",result); 486 return; 487 } 488 this.dbr.result = result; 489 this.dbr.result.timing = { unit: '1000ms_keepalive_cycles', count: this.keepalivecounter }; 490 if (this.dbr.result.resultSet) { // do we have results in a [resultSet] object? 491 this.dbr.result.rows = new Array(); 492 this.dbr.result.rowsgot = 0; 493 this.dbr.result.rowsinresult = 0; 494 if (this.dbr.pcallback) this.dbr.pcallback({action: "DBSelect", stage: "3/6 - fetch_result_1st_part", stateunit: "rowsgot", state: this.rowsgot}); 495 this.dbr.result.resultSet.getRows(this.dbr.options.numrows,this); // yes, begin fetching 496 } else { 497 this(); // no results, possibly result data in rows object, simulate fetch with no rows object to satisfy next step 498 } 499 }, 500 // step 4: one fetch complete 501 function(err,rows) { 502 if (err) { 503 logger.error("DBSelect: Error in getRows:"); 504 logger.error(err.message); 505 this.dbr.callback(new Error("DBSelect: Error in fetching result chunk row no. "+(this.dbr.result.rowsgot+1)+": "+err.message),rows); 506 return; 507 } 508 if ((rows) && rows.length>0) { // if we got a rows object with data, collect them in dbr.result.rows (up to options.maxrowstoget) 509 // logger.debug("DBSelect.ROWS_GOT="+rows.length); 510 for (var rn=0; rn<rows.length; rn++) { 511 if (this.dbr.result.rows.length<this.dbr.options.maxrowstoget) { 512 this.dbr.result.rows.push(rows[rn]); 513 this.dbr.result.rowsgot++; 514 } 515 this.dbr.result.rowsinresult++; 516 } 517 this.REWIND(); // stay at same step 518 if (this.dbr.pcallback) this.dbr.pcallback({action: "DBSelect", stage: "4/6 - fetch_result_following_part", stateunit: "rowsgot", state: this.dbr.result.rowsgot}); 519 this.dbr.result.resultSet.getRows(this.dbr.options.numrows,this); // request next junk of data 520 } else { 521 if (this.dbr.result.resultSet) { // there is a resultSet to close 522 if (this.dbr.pcallback) this.dbr.pcallback({action: "DBSelect", stage: "close_resultSet", stateunit: "step", state: "wait_close"}); 523 this.dbr.result.resultSet.close(this); // close the resultSet 524 } else { 525 this(); // no resultSet to close, proceed to next step immediately 526 } 527 } 528 }, 529 // step 4a: result set closed 530 function(err) { 531 if (err) { 532 var nerr = new Error("DBSelect: error in closing resultSet: "+e.message); 533 logger.error(nerr.message); 534 this.dbr.callback(nerr); 535 return; 536 } 537 if (this.dbr.result.resultSet) { 538 delete this.dbr.result.resultSet; 539 } 540 if (this.dbr.options.docommit) { // proceed with commit, if requested 541 if (this.dbr.pcallback) this.dbr.pcallback({action: "DBSelect", stage: "5/6 - committing"}); 542 // logger.debug("DBSelect.COMMITTING"); 543 this.dbconnection.commit(this); 544 } else { // no commit requested, push on to next step 545 this(); 546 } 547 }, 548 // step 5: commit complete 549 function(err) { 550 if (err) { 551 logger.error("DBSelect: Error in COMMIT"); 552 logger.error(err.message); 553 this.dbr.callback(new Error("DBSelect: Error in Commit: "+err.message),this.dbr.result); 554 return; 555 } 556 if (this.dbr.pcallback) this.dbr.pcallback({action: "DBSelect", stage: "6/6 - releasing"}); 557 // logger.debug("DB.select.before-release.connection:",this.dbconnection); 558 this.dbconnection.release(this); 559 }, 560 // step 5: release complete 561 function(err) { 562 if (err) { 563 logger.error("DBSelect: Error in RELEASE"); 564 logger.error(err.message); 565 this.dbr.callback(new Error("DBSelect: Error in Release: "+err.message),this.dbr.result); 566 return; 567 } 568 delete this.dbr.connection; 569 if (this.dbr.pcallback) this.dbr.pcallback({action: "DBSelect", stage: "END - complete"}); 570 this.dbr.result.timing = {level: 'DBSelect', unit: 'ms', count: Date.now()-this.dbr.starttime}; 571 this.dbr.result.resulttype = 'dbresult'; 572 // logger.debug("db.select.COMPLETE.ROWSINRESULT="+this.dbr.result.rowsinresult+".ROWSRETURNED="+this.dbr.result.rowsgot); 573 this.dbr.callback(undefined,this.dbr.result); 574 }); 575 576 577 /* 578 * FUNCTION: sync_database 579 * INPUT: thedb - db.Config object containing the current database configuration to set 580 * DESCRIPTION: synchronize the database configuration in <thedb> from the actual database we're connecting to 581 */ 582 var sync_database = flow.define( 583 function(thedb) { 584 logger.debug("SYNC_DATABASE.BEGIN.CFGNAME=\""+thedb.getName()+"\""); 585 this.thedb = thedb; 586 var dbr = new Request({info: "sync_database.scan_tables", 587 reqid: 'RQID_SCANTABLES', 588 sql: "select TABLE_NAME from ALL_TABLES where TABLE_NAME like 'CC%'", 589 params: [], 590 options: {status_override: true}}); 591 select(dbr,this); 592 }, 593 function(err,result) { 594 if (err) { 595 var errmsg = "Error in sync_database()/1 for "+this.thedb.getName()+": "+err.message; 596 logger.error(errmsg); 597 this.thedb.setStatus(errmsg); 598 return; 599 } 600 601 var dbr = new Request({info: "sync_database.scan_columns", 602 reqid: 'RQID_SCANCOLS', 603 sql: "select TABLE_NAME,COLUMN_NAME,DATA_TYPE,DATA_LENGTH from ALL_TAB_COLUMNS where TABLE_NAME like 'CC%'", 604 params: [], 605 options: {status_override: true}}); 606 select(dbr,this); 607 }, 608 function(err,result) { 609 if (err) { 610 var errmsg = "Error in sync_database()/2 for "+this.thedb.getName()+": "+err.message; 611 logger.error(errmsg); 612 this.thedb.setStatus(errmsg); 613 return; 614 } 615 var dbr = new Request({ info: "sync_database.scan_views", 616 reqid: 'RQID_SCANVIEWS', 617 sql: "select VIEW_NAME from ALL_VIEWS where VIEW_NAME like 'CC%'", 618 params: [], 619 options: {status_override: true} 620 }); 621 select(dbr,this); 622 }, 623 function(err,result) { 624 if (err) { 625 var errmsg = "Error in sync_database()/3 for "+this.thedb.getName()+": "+err.message; 626 logger.error(errmsg); 627 this.thedb.setStatus(errmsg); 628 return; 629 } 630 // 631 // all OK, let database be accessible 632 // 633 logger.debug("SYNC_DATABASE.READY.DATABASE=\""+this.thedb.getName()+"\""); 634 this.thedb.setStatus('ready'); 635 }); 636 637 /****************************************************************************** 638 * 639 * FUNCTION: setConfig 640 * INPUT: dbn - name of DB Configuration to be set 641 * RESULT: text describing the outcome of the operation 642 * GLOBALS: db.currentConfig - global current DB configuration 643 * dbConfig - global configuration structure 644 * DESCRIPTION: sets the current DB configuration to the one with name <dbn> 645 * configuration parameters are taken from global dbConfig 646 * if <dbn> is not given, the default configuration is used 647 * the name of the default configuration is taken from dbConfig.default 648 */ 649 function setConfig(dbn) { 650 if (dbn.length==0) { // use default 651 dbn = dbConfig.default; 652 logger.debug("CCDB.DB.SET_CONFIG.USING_DEFAULT=\""+dbn+"\""); 653 } 654 if (dbConfig.dbconfigs.hasOwnProperty(dbn)) { 655 currentConfig = new Config({configName: dbn}); 656 currentConfig.setStatus('not ready'); 657 init_database(currentConfig); 658 sync_database(currentConfig); 659 return "Database set to "+currentConfig.getName(); 660 } else { 661 var errtxt = "Database "+dbn+" cannot be set, nothing changed"; 662 logger.error(errtxt); 663 return errtxt; 664 } 665 } 666 667 function getCurrentConfig() { 668 return currentConfig; 669 } 670 671 function getCurrentConfigDBtype() { 672 return currentConfig.dbtype; 673 } 674 675 function listConfigs() { 676 var dbnames = new Array(); 677 for (dbn in dbConfig.dbconfigs) { 678 dbnames.push(dbn); 679 } 680 return dbnames; 681 } 682 683 /* ***************************************************************************** 684 * The module interface of CCDB.db 685 */ 686 687 var localexportobjects = { 688 Connection : Connection, 689 Request : Request, 690 Result : Result, 691 select : select, 692 setConfig : setConfig, 693 getCurrentConfig : getCurrentConfig, 694 listConfigs : listConfigs, 695 getCurrentConfigDBtype : getCurrentConfigDBtype 696 } 697 698 var logger; 699 var mastername; 700 701 module.exports = function(theLogger,theMasterName,thePrefs) { 702 logger = theLogger; 703 mastername = theMasterName; 704 prefs = thePrefs; 705 logger.debug("CCDB: this is the instantiation followup of "+__filename+", the master is "+mastername+"/"+theMasterName); 706 var c = 0; 707 var oal = ""; 708 for (var oa in module.exports) { 709 oal += ((c<1)?"":",")+oa; 710 c++; 711 } 712 // logger.debug("CCDB: module.exports has "+c+" attributes: "+oal); 713 return module.exports; 714 } 715 716 for (var oa in localexportobjects) { 717 module.exports[oa] = localexportobjects[oa]; 718 }