diff --git a/process/Sql_lib/Sql_lib.aod b/process/Sql_lib/Sql_lib.aod new file mode 100644 index 0000000000000000000000000000000000000000..219d4933b00f340d7713045764594227adbd45c6 --- /dev/null +++ b/process/Sql_lib/Sql_lib.aod @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<process xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.7" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/process/1.1.7"> + <name>Sql_lib</name> + <majorModelMode>DISTRIBUTED</majorModelMode> + <process>%aditoprj%/process/Sql_lib/process.js</process> +</process> diff --git a/process/Sql_lib/process.js b/process/Sql_lib/process.js new file mode 100644 index 0000000000000000000000000000000000000000..a83d17a091f3998a8d416006d469425f3f385ba4 --- /dev/null +++ b/process/Sql_lib/process.js @@ -0,0 +1,1053 @@ +import("system.translate"); +import("system.vars"); +import("system.db"); +import("system.datetime"); +import("system.tools"); +import("system.SQLTYPES"); +import("Util_lib") +/** + *Class containing utilities for SQL + * + *@class + */ +function SqlUtils() +{ + var that = this; + /** + * masks the function cast. + * + * @param {String} pField req + * @param {String} pDatatype req the datatypes, which should be casted to + * (varchar, integer, char, decimal or the SQLTYPES-Constants + * sowie SQLTYPES.DATE) + * @param {Integer|Interger[]} pLength req the length of the data + * decimal: [length, decimals] + * @param {String} pAlias req the database alias + * + * @return {String} + */ + this.cast = function(pField, pDatatype, pLength, pAlias) + { + if (pAlias == undefined) + pAlias = vars.getString("$sys.dbalias"); + var dbtype = db.getDatabaseType(pAlias); + var func = ""; + var datatype = ""; + + switch(Number(dbtype)) + { + case db.DBTYPE_ORACLE10_CLUSTER: + case db.DBTYPE_ORACLE10_THIN: + case db.DBTYPE_ORACLE10_OCI: + func = "cast"; + switch(pDatatype) + { + case "char": + case SQLTYPES.CHAR: + datatype = "char"; + break; + case "varchar": + case SQLTYPES.VARCHAR: + datatype = "varchar2"; + break; + case "integer": + case SQLTYPES.INTEGER: + datatype = "number(22,0)"; + break; + case "decimal": + case SQLTYPES.DECIMAL: + datatype = "decimal"; + break; + case SQLTYPES.DATE: + datatype = "date"; + break; + } + break; + case db.DBTYPE_POSTGRESQL8: + func = "cast"; + switch(pDatatype) + { + case "char": + case SQLTYPES.CHAR: + datatype = "char"; + break; + case "varchar": + case SQLTYPES.VARCHAR: + datatype = "varchar"; + break; + case "integer": + case SQLTYPES.INTEGER: + datatype = "numeric(22,0)"; + break; + case "decimal": + case SQLTYPES.DECIMAL: + datatype = "numeric"; + break; + case SQLTYPES.DATE: + return pField + "::date"; + } + break; + case db.DBTYPE_SQLSERVER2000: + func = "cast"; + switch(pDatatype) + { + case "char": + case SQLTYPES.CHAR: + datatype = "char"; + break; + case "varchar": + case SQLTYPES.VARCHAR: + datatype = "varchar"; + break; + case "integer": + case SQLTYPES.INTEGER: + datatype = "int"; + break; + case "decimal": + case SQLTYPES.DECIMAL: + datatype = "decimal"; + break; + case SQLTYPES.DATE: + datatype = "date"; + break; + } + break; + case db.DBTYPE_MYSQL4: + case db.DBTYPE_MARIADB10: + func = "cast"; + switch(pDatatype) + { + case "char": + case SQLTYPES.CHAR: + datatype = "char"; + break; + case "varchar": + case SQLTYPES.VARCHAR: + datatype = "char"; + break; + case "integer": + case SQLTYPES.INTEGER: + datatype = "integer"; + break; + case "decimal": + case SQLTYPES.DECIMAL: + datatype = "decimal"; + break; + case SQLTYPES.DATE: + datatype = "date"; + break; + } + break; + case db.DBTYPE_DERBY10: + func = "cast"; + if(pLength > 254) + pLength = 254; + switch(pDatatype) + { + + case "varchar": + case SQLTYPES.VARCHAR: + // Because of a Derby bug, you can't cast INTEGER into VARCHAR + // Therefor first cast to char then to varchar + // https://issues.apache.org/jira/browse/DERBY-2072 + func = "rtrim(" + func; + pField = " cast( " + pField + " as char("+pLength+")) "; + datatype = "varchar"; + pLength += ")"; + break; + + case "char": + case SQLTYPES.CHAR: + datatype = "char"; + break; + case "integer": + case SQLTYPES.INTEGER: + datatype = "int"; + break; + case "decimal": + case SQLTYPES.DECIMAL: + datatype = "numeric"; + break; + case SQLTYPES.DATE: + datatype = "date"; + break; + } + break; + case db.DBTYPE_FIREBIRD250: + func = "cast"; + switch(pDatatype) + { + case "char": + case SQLTYPES.CHAR: + datatype = "char"; + break; + case "varchar": + case SQLTYPES.VARCHAR: + datatype = "varchar"; + break; + case "integer": + case SQLTYPES.INTEGER: + datatype = "numeric(22,0)"; + break; + case "decimal": + case SQLTYPES.DECIMAL: + datatype = "numeric"; + break; + case SQLTYPES.DATE: + datatype = "date"; + break; + } + break; + } + + if(pLength == undefined) + pLength = ""; + else if(pLength != "") + { + if(typeof(pLength == "object") && (pLength instanceof Array)) + pLength = "(" + pLength.join(", ") + ")"; + else + pLength = "(" + pLength + ")"; + } + + return func + "(" + pField + " as " + datatype + pLength + ")"; + } + + /** + * masks the cast function for lob datatypes(clob, blob) + * + * @param {String} pField req the data field + * @param {Integer|Interger[]} pLength req the length of the data + * decimal: [length, decimals] + * @param {String} pAlias req the database alias + * + * @return {String} (Teil einer SQL-Anweisung) + */ + this.castLob = function(pField, pLength, pAlias) + { + if(pAlias == undefined) + pAlias = vars.getString("$sys.dbalias"); + + var dbtype = db.getDatabaseType(pAlias); + + switch(Number(dbtype)) + { + case db.DBTYPE_ORACLE10_CLUSTER: + case db.DBTYPE_ORACLE10_THIN: + case db.DBTYPE_ORACLE10_OCI: + return "DBMS_LOB.SUBSTR(" + pField + ", " + pLength + ", 1)"; + break; + default: + return cast(pField, "varchar", pLength, pAlias); + break; + } + } + /** + * masks the function substring. + * + * @param {String }pExpression req + * @param {Integer} pStart req index of the beginning + * @param {String} pAlias req database alias + * @param {Integer} pLength req + * + * @return {String} + */ + this.substring = function(pExpression, pStart, pLength, pAlias) + { + if(pLength == undefined) + pLength = 100; + if(pAlias == undefined) + pAlias = vars.getString("$sys.dbalias"); + + var dbtype = db.getDatabaseType(pAlias); + var string = ""; + + switch(Number(dbtype)) + { + case db.DBTYPE_ORACLE10_CLUSTER: + case db.DBTYPE_ORACLE10_THIN: + case db.DBTYPE_ORACLE10_OCI: + string = "substr"; + break; + case db.DBTYPE_DERBY10: + string = "substr"; + break; + case db.DBTYPE_POSTGRESQL8: + string = "substr"; + break; + case db.DBTYPE_SQLSERVER2000: + string = "substring"; + break; + case db.DBTYPE_MYSQL4: + case db.DBTYPE_MARIADB10: + string = "substring"; + break; + } + + return string + "(" + pExpression + ", " + pStart + ", " + pLength + ")"; + } + + /** + * masks the function concat. + * + * @param {Array} pFields req fields that should be concatenated + * @param {String} pSeparator opt field separator + * @param {String} pAlias opt database alias + * + * @return {String} part of SQL-querey + */ + this.concat = function(pFields, pSeparator, pAlias) + { + var i; + if(pAlias == undefined || pAlias == "") + pAlias = vars.getString("$sys.dbalias"); + + var dbtype = db.getDatabaseType(pAlias); + var concat_string = " || "; + var retstr = ""; + var blank = "' '"; + + //it must be checked for empty string and null + var isNotEmpty = " != '' "; + var isNotNull = " is not null "; + if(pSeparator == undefined) + pSeparator = " "; + + switch(Number(dbtype)) + { + case db.DBTYPE_MYSQL4: + case db.DBTYPE_MARIADB10: + retstr = " concat_ws( '" + pSeparator + "'"; + for(i=0; i<pFields.length; i++) + { + retstr += ", " + pFields[i]; + } + return retstr + ") "; + break; + + case db.DBTYPE_ORACLE10_CLUSTER: + case db.DBTYPE_ORACLE10_THIN: + case db.DBTYPE_ORACLE10_OCI: + blank = "trim(' ')"; + isNotEmpty = " is not null "; //needed for oracle + break; + + case db.DBTYPE_SQLSERVER2000: + concat_string = " + "; + break; + } + pSeparator = concat_string + "'" + pSeparator + "'"; + for(i = 0; i < pFields.length; i++) + { + if(retstr != "") + retstr += concat_string; + if ( i < pFields.length - 1 ) //Check if another value follows, if not separator is not needed + retstr += " case when " + pFields[i] + isNotEmpty + " then case when " + trimSQL(pFields[i+1], pAlias) + isNotEmpty + " and " + + trimSQL(pFields[i+1], pAlias) + isNotNull + " then " + pFields[i] + pSeparator + " else " + pFields[i] + " end" + " else " + blank + " end "; + else + retstr += " case when " + pFields[i] + isNotEmpty + " then " + pFields[i] + " else " + blank + " end "; + } + return retstr; + } + /** + * builds a condition out of multiple conditions + * + * @param {Array} pArray req Array containing the conditions + * @param {String} pOperator req Operator that concatenates the conditions (AND/OR) + * + * @return {String} concatenated Condition + */ + this.concatConditions = function(pArray, pOperator) + { + var resultCondition = ""; + + for(var i = 0; i < pArray.length; i++) + { + if(pArray[i] != null && pArray[i] != '') + { + if(resultCondition.length > 0) + resultCondition += (" " + pOperator + " "); + + resultCondition += pArray[i]; + } + } + + return resultCondition; + } + /** + * Checks if a new entry already exists + * + * @param {String} pTable req Databasetable(z.B. "comm") + * @param {Array} pColumns req colums, like sqlInsert + * @param {Array} pTypes req die datatypes, like sqlInsert + * @param {Array} pValues req values, like sqlInsert + * @param {Array} pExcludeFields opt columns, that should not be checked + * @param {String} pAlias opt Database alias + * + * @return {Integer} + */ + this.isDuplicat = function(pTable, pColumns, pTypes, pValues, pExcludeFields, pAlias) + { + var col = new Array(); + var typ = new Array(); + var val = new Array(); + var excludefields = ["DATE_NEW" ,"DATE_EDIT" ,"USER_NEW" ,"USER_EDIT", "KEYVALUE", "KEYSORT", pTable.toUpperCase() + "ID"]; + + if(pExcludeFields != undefined) + excludefields = excludefields.concat(pExcludeFields); + if(pAlias == undefined) + pAlias = vars.getString("$sys.dbalias"); + + for(var i = 0; i < pColumns.length; i++) + { + if(!hasElement(excludefields, pColumns[i], true) && pValues[i] != "" && pTypes[i] != SQLTYPES.LONGVARCHAR && pTypes[i] != SQLTYPES.CLOB) + { + col.push(pColumns[i]); + typ.push(pTypes[i]); + val.push(pValues[i]); + } + } + var count = db.getRowCount(pTable, col, typ, val, pAlias); + return count; + } + /** + * returns the trim function depending on the database + * + * @param {String} pField field the should be trimmed + * @param {String} pAlias opt database alias + * + * @return {String} + */ + this.trimSql = function(pField, pAlias) + { + if(pAlias == undefined || pAlias == "") + pAlias = vars.getString("$sys.dbalias"); + + var dbtype = db.getDatabaseType(pAlias); + var string; + + switch(Number(dbtype)) + { + case db.DBTYPE_SQLSERVER2000: + string = "ltrim(rtrim(" + pField + "))"; + break; + default: + string = "trim(" + pField + ")" + break; + } + return string; + } + /** + * returns the day of a date + * + * @param {Datetime} pDate req the date + * @param {String} pAlias req database alias + * + * @return {String} + */ + this.dayFromDate = function(pDate, pAlias) + { + var usedAlias = pAlias; + + if(pAlias == undefined) + usedAlias = vars.getString("$sys.dbalias"); + + var dbAlias = db.getDatabaseType(usedAlias); + var string = ""; + + switch(Number(dbAlias)) + { + case db.DBTYPE_ORACLE10_CLUSTER: + case db.DBTYPE_ORACLE10_THIN: + case db.DBTYPE_ORACLE10_OCI: + string = "to_char(" + pDate + ",'dd')"; + break; + case db.DBTYPE_DERBY10: + case db.DBTYPE_SQLSERVER2000: + case db.DBTYPE_MYSQL4: + case db.DBTYPE_MARIADB10: + string = "DAY(" + pDate + ")"; + break; + case db.DBTYPE_POSTGRESQL8: + string = "EXTRACT (DAY from " + pDate + ")"; + break; + } + return string; + } + /** + * returns the month of a date + * + * @param {Datetime} pDate req the date + * @param {String} pAlias req database alias + * + * @return {String} + */ + this.monthFromDate = function(pDate, pAlias) + { + var usedAlias = pAlias; + if(pAlias == undefined) + usedAlias = vars.getString("$sys.dbalias"); + + var dbAlias = db.getDatabaseType(usedAlias); + var string = ""; + + switch(Number(dbAlias)) + { + case db.DBTYPE_ORACLE10_CLUSTER: + case db.DBTYPE_ORACLE10_THIN: + case db.DBTYPE_ORACLE10_OCI: + string = "to_char(" + pDate + ",'MM')"; + break; + case db.DBTYPE_DERBY10: + case db.DBTYPE_SQLSERVER2000: + case db.DBTYPE_MYSQL4: + case db.DBTYPE_MARIADB10: + string = "MONTH(" + pDate + ")"; + break; + case db.DBTYPE_POSTGRESQL8: + string = "EXTRACT (MONTH FROM " + pDate + ")"; + break; + } + return string; + } + /** + * returns the year of a date + * + * @param {Datetime} pDate req the date + * @param {String} pAlias req database alias + * + * @return {String} + */ + this.yearFromDate = function(pDate, pAlias) + { + var usedAlias = pAlias; + if(pAlias == undefined) + usedAlias = vars.getString("$sys.dbalias"); + + var dbAlias = db.getDatabaseType(usedAlias); + var string = ""; + + switch(Number(dbAlias)) + { + case db.DBTYPE_ORACLE10_CLUSTER: + case db.DBTYPE_ORACLE10_THIN: + case db.DBTYPE_ORACLE10_OCI: + string = "to_char(" + pDate + ",'yyyy')"; + break; + case db.DBTYPE_DERBY10: + case db.DBTYPE_SQLSERVER2000: + case db.DBTYPE_MYSQL4: + case db.DBTYPE_MARIADB10: + string = "YEAR(" + pDate + ")"; + break; + case db.DBTYPE_POSTGRESQL8: + string = "EXTRACT (YEAR FROM " + pDate + ")"; + break; + } + return string; + } + /** + * returns the function for current date depending on database + * + * @return {String} expression + */ + this.currentDate = function() + { + var dbtype = db.getDatabaseType(vars.getString("$sys.dbalias")); + var expression = ""; + + switch (Number(dbtype)) + { + case db.DBTYPE_ORACLE10_CLUSTER: + case db.DBTYPE_ORACLE10_THIN: + case db.DBTYPE_ORACLE10_OCI: + case db.DBTYPE_DERBY10: + expression = "CURRENT_DATE"; + break; + case db.DBTYPE_SQLSERVER2000: + expression = "GETDATE()"; + break; + case db.DBTYPE_MYSQL4: + case db.DBTYPE_MARIADB10: + expression = "NOW()"; + break; + } + return expression; + } + /** + * returns the current search string incl placeholders + * + * @param {String} pfield req the search field + * @param {String} pfind req the search string + * @param {String} pIgnoreCase opt (true/false) + * @param {String} pPlaceHolder opt (Platzhalter config) + * + * @return {String} + */ + this.getPlacerholderCondition = function( pfield, pfind, pIgnoreCase, pPlaceHolder ) + { + var user = tools.getCurrentUser(); + var IgCa; + var PlHo; + + //wenn optoinal IgnoreCase und PlaceHolder vorhanden, dann diese verwenden + if(pIgnoreCase != undefined) + IgCa = pIgnoreCase; + else + IgCa = user[tools.PARAMS][tools.SELECTION_IGNORECASE]; + + if(pPlaceHolder != undefined) + PlHo = pPlaceHolder; + else + PlHo = user[tools.PARAMS][tools.SELECTION_PLACEHOLDER]; + + if ( pfind ) + { + pfind = pfind.replace( new RegExp("\\'", "g"), "''"); + pfind = pfind.replace( new RegExp("\\*", "g"), "%"); + var ic = (IgCa == "true" ? "UPPER" : ""); + var cond = ""; + switch( PlHo ) + { + case "1": + cond = ic + "(" + pfield + ") like " + ic + "('" + pfind + "%')"; + break; + case "2": + cond = ic + "(" + pfield + ") like " + ic + "('%" + pfind + "')"; + break; + case "3": + cond = ic + "(" + pfield + ") like " + ic + "('%" + pfind + "%')"; + break; + case "4": + cond = ic + "(" + pfield + ") like " + ic + "('" + pfind + "')"; + break; + default: + cond = ic + "(" + pfield + ") = " + ic + "('" + pfind + "')"; + break; + } + } + return cond; + } + /** + * returns SQLSystax for a date. + * + * @param {String} pColumn req Column name + * @param {String} pAlias opt Database alias + * @param {Boolean} pWithTime opt if true, then add time hh:mm:ss + * @param {String} pFormat opt type of the format, e.g. dd.MM.yyyy; possible placeholers are: -dd -MM -yyyy + * + *@return {String} sqlstr, fully functional select for sql for different types of databases + */ + this.getSqlFormattedDate = function(pColumn, pAlias, pWithTime, pFormat) + { + if(pAlias == undefined) + pAlias = vars.getString("$sys.dbalias"); + + var pDatabaseType = db.getDatabaseType(pAlias); + + if (pFormat == undefined) + pFormat = translate.text("dd.MM.yyyy"); + + var str = ""; + + switch(Number(pDatabaseType)) + { + case db.DBTYPE_SQLSERVER2000: + day = "right('0' + cast(day(" + pColumn + ") as varchar(2)) , 2)"; + month = "right('0' + cast(month(" + pColumn + ") as varchar(2)) , 2)"; + year = "cast(year(" + pColumn + ") as char(4))"; + time = pWithTime == true? that.concat(["' '","cast(cast(" + pColumn + " as time) as char(8))"], "", pAlias) : ""; + break; + case db.DBTYPE_POSTGRESQL8: + day = "extract(day from " + pColumn + ")"; + month = "extract(month from " + pColumn + ")"; + year = "extract(year from " + pColumn + ")"; + time = pWithTime == true? that.concat(["' '","extract(time from" + pColumn + ")"], "", pAlias) : ""; + break; + case db.DBTYPE_DERBY10: + case db.DBTYPE_MYSQL4: + case db.DBTYPE_MARIADB10: + // concat will try to have a leading blank space if the number is => 10. This is why we had to use substr. + day = that.substring(that.concat(["case when day(" + pColumn + ") <= 9 then '00' else '0' end " + , " trim(cast(day(" + pColumn + ") as char(2)))"], "", pAlias), 2, 2, pAlias); + month = that.substring(that.concat(["case when month(" + pColumn + ") <= 9 then '00' else '0' end " + , "trim(cast(month(" + pColumn + ") as char(2)))"], "", pAlias), 2, 2, pAlias); + year = "trim(cast(year(" + pColumn + ") as char(4)))"; + time = pWithTime == true? that.concat(["cast(' ' as char(1))", "trim(cast(time(" + pColumn + ") as char(8)))"], "", pAlias) : ""; + break; + case db.DBTYPE_ORACLE10_CLUSTER: + case db.DBTYPE_ORACLE10_OCI: + case db.DBTYPE_ORACLE10_THIN: + + day = "to_char(" + pColumn + ", 'dd') "; + month = "to_char(" + pColumn + ", 'MM') "; + year = "to_char(" + pColumn + ", 'yyyy') "; + time = pWithTime == true ? " to_char(" + pColumn + ", ' hh24:mi:ss')" : ""; + break; + default: + str = "cast(" + pColumn + " as varchar (10))"; + return str; + break; + } + + var re = /(dd)|(MM)|(yyyy)/g // Regex to check the date + var matchResult; + var endOfLastMatch = 0; + var res = []; + + while ((matchResult = re.exec(pFormat)) !== null) + { + if( endOfLastMatch != matchResult.index) + { + res.push("'" + db.quote(pFormat.substring(endOfLastMatch, matchResult.index), pAlias) + "'"); // making sure we get the correct amount of quotations + } + switch(matchResult[0]) + { + case "dd": + res.push(day); + break; + case "MM": + res.push(month); + break; + case "yyyy": + res.push(year); + break; + } + endOfLastMatch = re.lastIndex; + } + // making sure we get the correct amount of quotations + // allows us to add custom strings behind the format which will be shown in the output + // e.g. "yyyy-MM-dd 00:00", "date: MM/dd/yyyy" + res.push("'" + db.quote(pFormat.slice(endOfLastMatch), pAlias) + "'"); + + if(time != "") + res.push(time); + + str = concat(res, "", pAlias); + + return str; + } + /** + * returns a SQL operator depending on an integer value, i.e. $local.operator + * + * @param {int} pVal + * + * @return {string} + */ + this.getSQLOperator = function(pVal) + { + var retval = ""; + switch(Number(pVal)) + { + case 1: + retval = "="; + break; //equals + case 2: + retval = "<>"; + break; //not equal + case 3: + retval = ">"; + break; //greater + case 4: + retval = "<"; + break; //lesser + case 5: + retval = "<="; + break; //lesser or equal + case 6: + retval = ">="; + break; //greater or equal + case 7: + retval = "like"; + break; //contains + case 8: + retval = "not like"; + break; //contains not + case 9: + retval = ""; + break; + case 10: + retval = ""; + break; + case 11: + retval = "is not null"; + break; + case 12: + retval = "is null"; + break; + } + return retval; + } + /** + * returns the function which determines the length of binary data, depending on db type + * + * @param {String} pField name of the checked field + * + * @return {String} + */ + this.binDataLength = function(pField) + { + var dbtype = db.getDatabaseType(vars.getString("$sys.dbalias")); + var length; + + switch(Number(dbtype)) + { + case db.DBTYPE_MARIADB10: + case db.DBTYPE_MYSQL4: + case db.DBTYPE_ORACLE10_CLUSTER: + case db.DBTYPE_ORACLE10_THIN: + case db.DBTYPE_ORACLE10_OCI: + case db.DBTYPE_POSTGRESQL8: + case db.DBTYPE_DERBY10: + length = "LENGTH("+pField+")"; + break; + case db.DBTYPE_SQLSERVER2000: + length = "DATALENGTH("+pField+")"; + break; + } + return length; + } + /** + * returns the function for replacing a null value + * + * @param {String} pValue req + * @param {String} pReplaceWith + * + * @return {string} + */ + this.isNull = function(pValue, pReplaceWith) + { + var pAlias = vars.getString("$sys.dbalias"); + + if(pReplaceWith == undefined) + pReplaceWith = 0; + + var pDatabaseType = db.getDatabaseType(pAlias); + + switch(Number(pDatabaseType)) + { + case db.DBTYPE_SQLSERVER2000: + str = "isnull("+ pValue +", " + pReplaceWith+ ")"; + break; + case db.DBTYPE_ORACLE10_CLUSTER: + case db.DBTYPE_ORACLE10_OCI: + case db.DBTYPE_ORACLE10_THIN : + str = "NVL("+ pValue +", "+ pReplaceWith+ ")"; + break; + case db.DBTYPE_POSTGRESQL8: + case db.DBTYPE_DERBY10: + case db.DBTYPE_MYSQL4: + case db.DBTYPE_MARIADB10: + default: + str = "COALESCE("+ pValue +", "+ pReplaceWith+ ")"; + break; + } + return str; + } + /** + * returns the concat symbol depending on database type + * + * @param {String} pAlias opt database alias + * + * @return {String} Concat Symbol + */ + this.getConcatSymbol = function(pAlias) + { + if(pAlias == undefined || pAlias == "") + pAlias = vars.getString("$sys.dbalias"); + + var dbtype = db.getDatabaseType(pAlias); + var concatSymbol = " "; + + switch(Number(dbtype)) + { + case db.DBTYPE_SQLSERVER2000: + concatSymbol = " + "; + break; + case db.DBTYPE_MARIADB10: + case db.DBTYPE_MYSQL4: + case db.DBTYPE_ORACLE10_CLUSTER: + case db.DBTYPE_ORACLE10_THIN: + case db.DBTYPE_ORACLE10_OCI: + case db.DBTYPE_POSTGRESQL8: + case db.DBTYPE_DERBY10: + default: + concatSymbol = " || "; + break; + } + + return concatSymbol; + } + /** + * Builds a SQL IN condition, while accounting for the 1000 elements maximum + * Single conditions are concatenated with OR, which can be devastating for performance! + * + * @param {String} pFieldname req name of the field with table alias + * z.B ORGREL.RELATIONID + * @param {String[]|String[][]} pData req Data as ID Array + * @param {String} pQuoteSymbol opt symbol for quoting values, + * Strings i.e.: ' default is no symbol + * + * @return {String} SQL condition: where VALS in (1,2,3) + */ + this.getSqlInStatement = function(pFieldname, pData, pQuoteSymbol) + { + if (pData.length == 0) + return " 1 = 2 "; + + var res = ""; + var qs = pQuoteSymbol || ""; + + var MAX_COUNT = 1000; + //pData.length -1 um für den Fall, dass MAX_COUNT == pData.length ist trotzdem nur einen Aufruf + //zu machen + var count = ((pData.length -1) / MAX_COUNT) >> 0;//aus kommazahl eine ganzzahl machen + //<= verwenden, da bei einer Länge von "126" der Vorgang einmal ausgeführt werden soll + for (var i = 0; i <= count; i++) + { + if (i > 0) + res += "or "; + + res += pFieldname + " in (" + qs + pData.slice(i * MAX_COUNT, i * MAX_COUNT + MAX_COUNT) + .join(qs + ", " + qs) + qs + ") "; + } + + //wenn mehrere Zeilen mit "or" verknüpft wurden nochmal klammern + if (count > 0) + res = "(" + res + ")"; + + return res; + } + /** + * Setzt eine Condition zusammen und liefert sie zurück + * builds a conditions and returns it + * + * @param {Object} pValue req Filtervalue + * @param {String} pCondition req variable in which the condition should be written + * @param {String} pWhere req additional condition + * @param {Integer} pSQLType opt SQLTYPES type of pValue + * @param {Array} pPreparedValues opt Value for the condition, if it's a prepared statement + * + * @return {String} + */ + this.makeCondition = function( pValue, pCondition, pWhere, pSQLType, pPreparedValues) + { + if ( pValue != "" ) + { + if ( pCondition != "" ) + pCondition += " and "; + + pCondition += pWhere; + + if(pPreparedValues != undefined) + { + pPreparedValues.push([pValue, pSQLType]); + } + } + return pCondition; + } + /** + * returns a type of column in the database + * + * @param {String} pTableName req name of a table (e.g. "EVENT") OR if pColumnName is not passed table.column (e.g. "EVENT.STATUS") + * @param {String} pColumnName opt name of column (e.g. "STATUS") if in pTableName only tablename is passed + * @param {String} pAlias opt Alias to the database where the type should be loaded; default is current alias + * + * @return {String} type of column such as SQLTYPES.xyz + */ + this.getSingleColumnType = function(pTableName, pColumnName, pAlias) + { + if (pColumnName == undefined) + { + pColumnName = pTableName.substring(pTableName.indexOf(".") + 1); + pTableName = pTableName.substring(0, pTableName.indexOf(".")); + } + if (pAlias == undefined) + pAlias = db.getCurrentAlias(); + + return db.getColumnTypes(pTableName, [pColumnName], pAlias)[0]; + } + /** + * calls a given function for N blocks of sql-data as long as records are available or the paging-process is manually canceled + * + * @param {Object|String} pSql req sql statement that shall be executed + * String: SQL-query in a simple text form + * Object: prepared-sql-query: [sqlStr, [[value1, type1], [valueN, typeN]]] + * @param {Number} pBlockSize req Amount of records that shall be read per block. (you need to specify an ORDER BY in your SQL-query) + * "0" <=> all records + * @param {Object (function)} pCallback req a callback-function that is called for every block and has the following params: + * myCallback(myDataBlockAs2Darray, myLoopCountThatStartsWith1) + * If "false" is returned sqlPageData will abort the paging process and return false + * @param {String} pDbAlias opt Database-Aliasname, where the SQL-Statement shall be executed; default is the current dbalias + * @param {Number} pTimeout opt Timeout in milliseconds; When it's reached the SQL-Statement will abort; default is in PREFERENCES configured + * @param {Number} pStartOffset opt Position where to begin with the data-reading-process; default is 0 + * + * + * @return {bool} returns whether the function read all available data or not: + * false if the callback-function returned false, otherwise true + * + * @example + * var varValues = [];//you've got access to variables declared with 'var' + * let letValues = [];//you've got access to variables declared with 'let' + * var count = 0;//you cannot overwrite a variable of 'sqlPageData' by accident + * + * var sql = "select ORGNAME from ORG"; + * var blockSize = 5 * 1000; + * + * var allRows = +db.cell("select count(*) from ORG"); + * + * sqlPageData(sql, blockSize, function (pData, pRunNo){ + * var j = pData.length;//pData is the current block with data + * logging.log(pRunNo.toString() + "#" + j);//pRunNo is the amount how often the func. has been already called + * //you can calculate the progress easily by: progress = (blockSize* (pRunNo-1) + pData.length) / (allRows - startOffset) + * //example in per cent: + * var startOffset = 0;//we did not pass any startOffset to sqlPageData - this is equivalent to zero + * var progress = (blockSize* (pRunNo-1) + pData.length) / (allRows - startOffset); + * logging.log("progess: " + eMath.roundDec(progress * 100, 2, eMath.ROUND_CEILING) + "%"); + * + * for (var i = 0; i < j; i++) + * { + * varValues.push(pData[i][0]); + * letValues.push(pData[i][0]); + * } + * + * count += pRunNo * 100; + * logging.log("count:" + count);//you cannot overwrite a variable of 'sqlPageData' by accident + * }); + * + * logging.show(letValues);//contains orgnames + * logging.show(varValues);//contains orgnames + */ + this.sqlPageData = function(pSql, pBlockSize, pCallback, pDbAlias, pTimeout, pStartOffset) + { + if (pDbAlias == undefined) + pDbAlias = db.getCurrentAlias(); + + if (pStartOffset == undefined) + pStartOffset = 0; + + let count = 0; + while (pStartOffset > -1) + { + let data; + if (pTimeout == undefined) + data = db.tablePage(pSql, pDbAlias, pStartOffset, pBlockSize); + else + data = db.tablePage(pSql, pDbAlias, pStartOffset, pBlockSize, pTimeout); + + pStartOffset += pBlockSize; + + //this happens when all-records % pBlockSize == 0 + //we do not want to call the callback-fn + if (data.length == 0) + return true; + else if (data.length < pBlockSize || pBlockSize == 0)//blocksize 0 is everything + pStartOffset = -1;//call callback the last time + + if (pCallback.call(this, data, ++count) === false) + return false;//callback can return false to manually stop the paging-process + + } + return true; + } +} \ No newline at end of file