Files
Facilitor/APPL/Shared/m_connections.inc
Jos Groot Lipman 8877559b2a FCLT#87155 Bij een error op Oracle.ExecuteParam ook __DoLogForm doen voor troubleshooting
svn path=/Website/branches/v2024.3/; revision=67888
2025-02-06 14:18:40 +00:00

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 );
%>