489 lines
18 KiB
PHP
489 lines
18 KiB
PHP
<% /*
|
|
$Revision$
|
|
$Id$
|
|
*/ %>
|
|
<%
|
|
|
|
var adExecuteNoRecords = 0x80;
|
|
var _LastFacError = {}; // Deze kun je direct na een error raadplegen voor een vriendelijkere tekst
|
|
// als catchErrors is gedefinieerd (overigens alleen ondersteund voor INSERT/UPDATE/DELETE en *niet* voor SELECT)
|
|
// dan worden alle Oracle errors afgevangen en wordt bij fouten _LastFacError opgeleverd
|
|
|
|
var _all_recordset = [];
|
|
var _sql_time = 0;
|
|
var _sql_cnt = 0;
|
|
|
|
// Execute(mldUpd, catchErrors) is also supported
|
|
function SafeExec( sql, catchErrors ) {
|
|
if (typeof sql == "object") // when calling with mldUpd object
|
|
{
|
|
var bindparams = sql.bindparams;
|
|
var thesql = sql.sql;
|
|
if (bindparams && bindparams.length) {
|
|
return Oracle.ExecuteParam(thesql, bindparams, catchErrors);
|
|
}
|
|
else
|
|
{
|
|
sql = thesql; // gewoon doorvallen
|
|
}
|
|
}
|
|
|
|
var result;
|
|
__LogMarker = this.marker; // uit Putorders.inc
|
|
var handle = __Log(sql, SafeExec.caller, true /* leave_open */);
|
|
_sql_cnt ++;
|
|
var startTime = us_timer();
|
|
var hasRecords = !sql.match(/^(DELETE|INSERT|UPDATE|BEGIN|DECLARE|ALTER)/ig); // Waarschijnlijk alleen SELECT en WITH over
|
|
|
|
_LastFacError = { fullMsg: "", faccode : "", friendlyMsg : "" };
|
|
try {
|
|
if (hasRecords)
|
|
{
|
|
result = this.RealConnection.Execute( sql );
|
|
if (Application("otap_environment") == "O")
|
|
{
|
|
check_recordsets(); // alle gesloten recordsets verwijderen
|
|
_all_recordset.push({ rs: result, caller: SafeExec.caller });
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (this._inTransaction)
|
|
{
|
|
//if (sql.match(/^BEGIN.*END\;$/i)) // Een BEGIN ... END wordt er bij de transactie omheen geplaatst, hier weg dus
|
|
// sql = sql.replace(/^BEGIN(.*)END;$/i, "$1");
|
|
if (sql.substr(0, 5) == 'BEGIN' && sql.substr(sql.length - 4) == 'END;')
|
|
{
|
|
sql = sql.substr(5, sql.length - 5 - 4);
|
|
sql = sql.replace(/;\s+$/, ""); // laatste ; en spaties eraf
|
|
}
|
|
this._Statements.push(sql);
|
|
__LogCloseLine(null, "<div style=\"background-color: #00FF00;\">Delayed {0} (transaction)</div>".format(this._Statements.length));
|
|
return {};
|
|
}
|
|
else
|
|
this.RealConnection.Execute( sql, null, adExecuteNoRecords); // Voorkomt out-of-cursors
|
|
result = {}; // er moet later wel een err.friendlyMsg getest kunnen worden
|
|
}
|
|
} catch( e1 ) {
|
|
__LogCloseLine(null, "FAIL", "#FF0000");
|
|
var msg = e1.description;
|
|
var knownError = false;
|
|
_LastFacError = { fullMsg: msg,
|
|
faccode : "",
|
|
friendlyMsg : msg };
|
|
if (msg.match(/^ORA-20\d{3}:(.*)\nORA-06512/i) || msg.match(/^ORA-20000/i) || msg.match(/^ORA-20004/i) || msg.match(/^ORA-00001/i) || msg.match(/^ORA-02290/i) || msg.match(/^ORA-02291/i) || msg.match(/^ORA-02292/i))
|
|
{
|
|
RegCode = msg.match(/^ORA-20000: (\w*)(.*)\nORA-/i); // Zoek: ORA-20000: res_m039 ORA-06512: at "UWVA_500.ALG_T_ALG_RUIMTE_B_IU", line 71 ORA-04088: error during execution of trigger 'UWVA_500.ALG_T_ALG_RUIMTE_B_IU'
|
|
if (!RegCode || RegCode.length == 0)
|
|
{
|
|
RegCode = msg.match(/^ORA-20\d{3}:(.*)\nORA-06512/i); // Zoek: (ORA-20000 - ORA-20999): ORA-06512: at .......
|
|
if (RegCode && RegCode.length > 1)
|
|
{
|
|
_LastFacError.friendlyMsg = RegCode[1];
|
|
}
|
|
}
|
|
if (!RegCode || RegCode.length == 0)
|
|
RegCode = msg.match(/^ORA-20004: (\w*)(.*)\nORA-/i); // Zoek: ORA-20004: ins_m145,Normverbruik,0, ORA-06512: at .......
|
|
if (!RegCode || RegCode.length == 0)
|
|
RegCode = msg.match(/^ORA-00001: .* \(.*\.(\w*)\)/i) // Zoek: ORA-00001: unique constraint (UWVA_500.ALG_U_ALG_RUIMTE_UPPER_NR) violated
|
|
if (!RegCode || RegCode.length == 0)
|
|
RegCode = msg.match(/^ORA-02290: .* \(.*\.(\w*)\)/i) // Zoek: ORA-02290: check constraint (UWVA_500.ALG_C_ALG_RUIMTE_UPPER_NR) violated
|
|
if (!RegCode || RegCode.length == 0)
|
|
RegCode = msg.match(/^ORA-02291: .* \(.*\.(\w*)\)/i) // Zoek: ORA-02291: integrity constraint violated - parent key not found
|
|
if (!RegCode || RegCode.length == 0)
|
|
RegCode = msg.match(/^ORA-02292: .* \(.*\.(\w*)\)/i) // Zoek: ORA-02292: integrity constraint violated - child record found
|
|
|
|
if (RegCode && RegCode.length > 1)
|
|
{
|
|
_LastFacError.faccode = RegCode[1];
|
|
}
|
|
if (msg.match(/^ORA-20000/i) && RegCode && RegCode.length > 2)
|
|
{
|
|
_LastFacError.friendlyMsg = RegCode[2] || _LastFacError.faccode; // een ORA-20000 met ingebouwde tekst zoals ORA-20000: alg_m999 Ruimte kan nog niet verwijderd worden. Er zijn nog lopende meldingen
|
|
var knownError = true;
|
|
}
|
|
else if (msg.match(/^ORA-20001/i)) // Alleen tekst: 'ORA-20001 Deze ruimte of voorziening is niet beschikbaar. Kies een andere ruimte of een ander tijdstip!'
|
|
{
|
|
var knownError = true;
|
|
}
|
|
// We gaan proberen de tekst er bij te zoeken
|
|
var ignoreError = /res_m999|res_m960/; // Ruimte niet beschikbaar niet proberen te vertalen
|
|
if (_LastFacError.faccode != "" && !_LastFacError.faccode.match(ignoreError))
|
|
{
|
|
var sql2 = "SELECT fac_message_text FROM fac_message WHERE fac_message_code = "+safe.quoted_sql_upper(_LastFacError.faccode);
|
|
var oRs = this.RealConnection.Execute( sql2 );
|
|
if (!oRs.Eof)
|
|
{
|
|
var knownError = true;
|
|
_LastFacError.friendlyMsg = oRs("FAC_MESSAGE_TEXT").Value + "\n(" + _LastFacError.faccode + ")";
|
|
}
|
|
else if (!knownError)
|
|
{
|
|
__SafeDoLog("TODO: <em>{0}</em> opnemen in een XXX_INI.SRC (FCLT#51673)?".format(safe.html(_LastFacError.faccode)));
|
|
}
|
|
oRs.Close();
|
|
}
|
|
if (knownError && !_LastFacError.faccode.match(ignoreError))
|
|
{
|
|
__Log("Bovenstaande ging fout, " + _LastFacError.faccode + " betekent:\n" + _LastFacError.friendlyMsg);
|
|
}
|
|
else
|
|
__Log("Foutcode: " + _LastFacError.faccode + " niet gevonden in fac_message");
|
|
}
|
|
|
|
// multiline test to check for any matches
|
|
if (RegExp(/^ORA-\d*:\s/m).test(_LastFacError.friendlyMsg))
|
|
{
|
|
var arr = _LastFacError.friendlyMsg.split("\n");
|
|
var index;
|
|
for (index = 0; index < arr.length; index++)
|
|
{
|
|
// only for messages that start with ORA-ddddd:
|
|
if (RegExp(/^ORA-\d*:\s/).test(arr[index])) // prevent hacker-usable ORA- information in friendlyMsg
|
|
{
|
|
arr[index] = arr[index].replace(/^ORA-\d*:\s/,"").replace(/\"{1}\w*\.{0,1}\w*\"{1}.{0,1}|\({1}\w*\.{0,1}\w*\){1}.{0,1}/g,"");
|
|
// _____________ _____________________________ _____________________________
|
|
// remove string "ORA-ddddd: " | | |
|
|
// | |
|
|
// remove strings with db info "COMP_TEST"."INS_SRTKENMERK"."INS_SRTKENMERKTYPE" | |
|
|
// |
|
|
// remove strings with constraint/trigger names enclosed in Parentheses eg (INS_T_INS_SRTKENMERK_B_IU) |
|
|
}
|
|
}
|
|
_LastFacError.friendlyMsg = arr.join("\n");
|
|
}
|
|
if (!knownError)
|
|
{
|
|
if (!(__Logging & 1))
|
|
__DoLog(sql); // alsnog
|
|
__SafeDoLog("Database exception:<br>" + Server.HTMLEncode(e1.description).replace(/\n/g,"<br/>"), "#f00");
|
|
dump_recordsets();
|
|
|
|
try {
|
|
if (Request.Form.Count>0) __DoLogForm("#FF0000");
|
|
}
|
|
catch(e)
|
|
{ /* er is al een Request.BinaryRead geweest */ }
|
|
}
|
|
|
|
if (!catchErrors)
|
|
{
|
|
Session("last_sql") = sql; // wordt door 500-error.asp opgepikt
|
|
Session("last_caller") = __callerTekst(SafeExec.caller);
|
|
if (typeof THIS_FILE == "string")
|
|
Session("THIS_FILE") = THIS_FILE;
|
|
throw e1; // Throw again
|
|
}
|
|
else
|
|
return _LastFacError;
|
|
}
|
|
|
|
// Geen errors blijkbaar.
|
|
var eofText = "";
|
|
try {
|
|
if( hasRecords && result.State != 0 && result.Eof) // This Eof test may take some time!
|
|
eofText = "<b>N/R</b>";
|
|
} catch( e3 ) {
|
|
__LogCloseLine(null, "<div style=\"background-color: #FF0000;\">Error while getting result.Eof: " + e3.description + "</div>");
|
|
throw e3; // Throw again
|
|
}
|
|
|
|
if (hasRecords && _all_recordset.length > 1)
|
|
eofText += (eofText?"<br>":"") + "rs: " + _all_recordset.length;
|
|
|
|
var ms_taken = (us_timer() - startTime) / 1000;
|
|
_sql_time += ms_taken;
|
|
|
|
// Indien ingesteld registreren we het aantal statements dat een bepaalde drempelwaarde
|
|
// (in millisecondes) overschrijdt. Hoe, dat bepaalt een databaseprocedure.
|
|
if (S("perfmon_threshold") > -1) {
|
|
if (S("perfmon_threshold") < 500) S("perfmon_threshold") = 500; // daaronder wordt het riskanter en valsspelen.
|
|
if (ms_taken > S("perfmon_threshold")) {
|
|
var isql = "BEGIN fac.fac_perfmon_incr("+S("perfmon_threshold")+", "+ms_taken+"); END;"
|
|
this.RealConnection.Execute( isql, null, adExecuteNoRecords);
|
|
eofText = eofText+"<br><b>#P#</b>";
|
|
}
|
|
}
|
|
|
|
__LogCloseLine(handle, eofText);
|
|
|
|
return result;
|
|
}
|
|
|
|
function SafeOracle( ora )
|
|
{
|
|
this.RealConnection = ora;
|
|
this.Execute = SafeExec;
|
|
|
|
this._inTransaction = false;
|
|
this._Statements = [];
|
|
}
|
|
|
|
SafeOracle.prototype.rs2hash = function _rs2hash (oRs)
|
|
{
|
|
var result = [];
|
|
while(!oRs.Eof)
|
|
{
|
|
var datahash = {};
|
|
for (var i = 0; i < oRs.Fields.Count; i++)
|
|
{
|
|
var v = oRs.Fields(i).Value;
|
|
if (v != null && oRs.Fields(i).Type == 135) // adDBTimeStamp
|
|
v = new Date(v);
|
|
datahash[oRs.Fields(i).Name.toLowerCase()] = v;
|
|
}
|
|
result.push(datahash);
|
|
oRs.MoveNext();
|
|
}
|
|
return result;
|
|
}
|
|
SafeOracle.prototype.Get = function _get (descfield, table, keyname, key)
|
|
{
|
|
if (typeof key == "undefined")
|
|
{
|
|
key = keyname;
|
|
keyname = table + "_KEY";
|
|
}
|
|
var sql = "SELECT {0} FROM {1} WHERE {2} = {3}".format(descfield, table, keyname, key);
|
|
var oRs = this.Execute(sql);
|
|
var res = oRs.Fields(0).Value;
|
|
oRs.Close();
|
|
return res;
|
|
}
|
|
|
|
SafeOracle.prototype.Transaction = function ()
|
|
{
|
|
if (this._inTransaction)
|
|
INTERNAL_ERROR_NESTED_TRANSACTION;
|
|
this._inTransaction = true;
|
|
this._Statements = [];
|
|
}
|
|
SafeOracle.prototype.Commit = function ()
|
|
{
|
|
if (!this._inTransaction)
|
|
INTERNAL_ERROR_NO_TRANSACTION;
|
|
this._inTransaction = false;
|
|
__Log("Committing transaction");
|
|
var sql = "BEGIN \n{0};\nEND;".format(this._Statements.join(";\n\n"));
|
|
Oracle.Execute(sql);
|
|
this._Statements = [];
|
|
}
|
|
SafeOracle.prototype.Rollback = function ()
|
|
{
|
|
if (!this._inTransaction)
|
|
INTERNAL_ERROR_NO_TRANSACTION;
|
|
this.inTransaction = false;
|
|
this._Statements = [];
|
|
}
|
|
|
|
var adParamInput = 1;
|
|
var adParamOutput = 2;
|
|
var adParamInputOutput = 3;
|
|
var adVarChar = 200;
|
|
var adInteger = 3;
|
|
var adStateOpen = 1;
|
|
var adUseClient = 3;
|
|
var adOpenStatic = 3;
|
|
var adCmdStoredProc = 4;
|
|
var adCmdText = 1;
|
|
var adLongVarChar = 201; // Ook Oracle CLOB
|
|
|
|
// Eerste opzet parameterized queries
|
|
// Doet nog wel iets minder logging dan de reguliere Oracle.Execute
|
|
// Geintroduceerd voor bez.copy_afspraak() om de nieuwe key te kunnen krijgen
|
|
SafeOracle.prototype.ExecuteParam = function (sql, params, catchErrors)
|
|
{
|
|
__Log(sql);
|
|
|
|
var cmdo = new ActiveXObject("ADODB.Command")
|
|
cmdo.CommandText = sql;
|
|
cmdo.CommandType = adCmdText;
|
|
cmdo.ActiveConnection = this.RealConnection;
|
|
cmdo.NamedParameters = true; // Lijkt hoe dan ook niet te lukken met Oracle
|
|
var hasRecords = !sql.match(/^(DELETE|INSERT|UPDATE|BEGIN|DECLARE|ALTER)/ig); // Waarschijnlijk alleen SELECT en WITH over
|
|
|
|
for (var i = 0; i < params.length; i++)
|
|
{
|
|
var itm = params[i];
|
|
__Log("==== Binding ====");
|
|
__Log(itm);
|
|
var dir = itm.dir || (("val" in itm)?adParamInput:adOutput)
|
|
if (!("len" in itm) && typeof itm.val == "string")
|
|
{
|
|
itm.len = itm.val.length;
|
|
}
|
|
|
|
var prm = cmdo.CreateParameter("", itm.typ, dir, itm.len);
|
|
|
|
if ("val" in itm)
|
|
{
|
|
prm.Value = itm.val;
|
|
if (typeof itm.val == "string")
|
|
prm.Size = itm.val.length;
|
|
}
|
|
|
|
if (dir == adParamOutput || dir == adParamInputOutput) // dan onthouden
|
|
params[i].AdoParameter = prm;
|
|
|
|
cmdo.Parameters.Append(prm);
|
|
}
|
|
cmdo.prepared = false;
|
|
_LastFacError = { fullMsg: "", faccode : "", friendlyMsg : "" };
|
|
try
|
|
{
|
|
//if (hasRecords)
|
|
var oRs = cmdo.Execute();
|
|
// else
|
|
// var oRs = cmdo.Execute(null, null, adExecuteNoRecords); // Voorkomt out-of-cursors maar doet bij bind-params netto geen update
|
|
}
|
|
catch( e1 )
|
|
{
|
|
__LogCloseLine(null, "FAIL", "#FF0000");
|
|
var msg = e1.description;
|
|
_LastFacError = { fullMsg: msg,
|
|
faccode : "",
|
|
friendlyMsg : msg };
|
|
__Log(e1.description);
|
|
if (!(__Logging & 1))
|
|
__DoLog(sql); // alsnog
|
|
__SafeDoLog("Database exception:<br>" + Server.HTMLEncode(e1.description).replace(/\n/g,"<br/>"), "#f00");
|
|
|
|
try {
|
|
if (Request.Form.Count>0) __DoLogForm("#FF0000");
|
|
}
|
|
catch(e)
|
|
{ /* er is al een Request.BinaryRead geweest */ }
|
|
|
|
if (!catchErrors)
|
|
{
|
|
Session("last_sql") = sql; // wordt door 500-error.asp opgepikt
|
|
Session("last_caller") = __callerTekst(SafeExec.caller);
|
|
throw e1; // Throw again
|
|
}
|
|
else
|
|
return _LastFacError;
|
|
}
|
|
for (var i = 0; i < params.length; i++)
|
|
{
|
|
if ("AdoParameter" in params[i])
|
|
{
|
|
params[i].val = params[i].AdoParameter.Value
|
|
__Log("Out value: " + params[i].val);
|
|
|
|
}
|
|
}
|
|
if (catchErrors)
|
|
return {}; // er moet later wel een err.friendlyMsg getest kunnen worden
|
|
|
|
return oRs;
|
|
}
|
|
|
|
function check_recordsets()
|
|
{
|
|
for (var i = 0; i < _all_recordset.length; i++)
|
|
{
|
|
var rs = _all_recordset[i].rs;
|
|
if (rs.state == 0)
|
|
{
|
|
_all_recordset.splice(i, 1);
|
|
i--;
|
|
}
|
|
}
|
|
}
|
|
|
|
function dump_recordsets()
|
|
{
|
|
var cnt = 0;
|
|
for (var i =0; i < _all_recordset.length; i++)
|
|
{
|
|
var rs = _all_recordset[i].rs;
|
|
var caller = _all_recordset[i].caller;
|
|
if (rs.state == 1)
|
|
{
|
|
__DoLog("Unclosed recordset {0}:\n{1}".format(++cnt, rs.Source), "#ff0", caller);
|
|
}
|
|
}
|
|
}
|
|
|
|
var _cache_F = [];
|
|
function F(fac_functie_code)
|
|
{
|
|
if (!(fac_functie_code in _cache_F))
|
|
{
|
|
var sql = "SELECT fac_functie_key "
|
|
+ " FROM fac_functie"
|
|
+ " WHERE fac_functie_code = " + safe.quoted_sql(fac_functie_code);
|
|
var oRs = Oracle.Execute(sql);
|
|
_cache_F[fac_functie_code] = oRs("fac_functie_key").Value;
|
|
oRs.Close()
|
|
}
|
|
return _cache_F[fac_functie_code];
|
|
}
|
|
|
|
// ===================================
|
|
// Initialize the global Oracle object
|
|
// ===================================
|
|
if( ! this.Oracle )
|
|
try {
|
|
var str = Server.MapPath(custpath + "/Oracle.udl");
|
|
var o = Server.CreateObject("ADODB.Connection");
|
|
o.Open('File Name=' + str);
|
|
Oracle = new SafeOracle(o);
|
|
|
|
} catch( e1 ) {
|
|
objFile = Server.CreateObject("Scripting.FileSystemObject");
|
|
if (!objFile.FileExists(str))
|
|
{
|
|
Response.write("oracle.udl niet gevonden voor: " + customerId);
|
|
Response.end;
|
|
}
|
|
__SafeDoLog(str + "<div style=\"background-color: #FF00FF;\">Cannot create database connection: " + safe.html(e1.description) + "</div>");
|
|
__LogfileName = shared.tempFolder() + "/../log_database.html"; // van alle klanten verzamelen in hetzelfde bestand
|
|
__SafeDoLog(str + "<div style=\"background-color: #FF00FF;\">Cannot create database connection: " + safe.html(e1.description) + "</div>");
|
|
if (Session("page_start"))
|
|
{
|
|
var now = new Date();
|
|
var start = new Date(Session("page_start"));
|
|
var duration = Math.round((now.getTime() - start.getTime()) / 100) / 10;
|
|
__SafeDoLog("Page started for {0} at {1} which is {2} second(s) ago".format(customerId, toISODateTimeString(start), duration));
|
|
}
|
|
Response.write("Fatal error, unable to open database connection:<xmp>{0}</xmp>".format(safe.html(e1.description)));
|
|
// *Zo* fataal dat ik niet eens de AiAi handler in wil gaan.
|
|
Response.Status = "500 Internal Server Error";
|
|
Response.End;
|
|
//throw e1; // Throw again, VERY fatal
|
|
}
|
|
|
|
// Merk op: iets als user_lang bepaling zou je eerder verwachten in common.inc
|
|
// We zitten hier echter met een kip-ei probleem: we willen het *direct* gebruiken
|
|
// voor fac.initsession maar kunnen het pas gebruiken als we database connectie
|
|
// hebben. Daarom dus hier.
|
|
var user_lang = Session("user_lang");
|
|
var fac_lang = getQParamSafe("fac_lang", "").toUpperCase(); // overrule via param
|
|
if (fac_lang)
|
|
{
|
|
if (typeof user_lang == "undefined")
|
|
Session("user_lang") = fac_lang;
|
|
user_lang = fac_lang; // In ieder geval voor *deze* pagina
|
|
}
|
|
|
|
if (!user_lang || typeof user_lang == "undefined")
|
|
{
|
|
var oRs = o.Execute("SELECT fac_version_lang FROM fac_version");
|
|
user_lang = oRs("fac_version_lang").Value; // De database taal voorlopig.
|
|
oRs.Close();
|
|
}
|
|
var ident = "";
|
|
if (Session("user_key")>0)
|
|
ident = String(Session("user_key"))
|
|
//else
|
|
// ident += "<system>";
|
|
|
|
var oraprefix = "BEGIN"
|
|
+ " fac.initsession("+safe.quoted_sql(ident)+", "+safe.quoted_sql(user_lang)+", "+safe.quoted_sql(Session("time_zone"))+");"
|
|
+ "END;";
|
|
|
|
o.Execute( oraprefix );
|
|
%>
|