diff --git a/process/Sql_lib/process.js b/process/Sql_lib/process.js index a8014755360de174c6529d7d096c9f90821e15e1..5c4b1876b6ee3a1765e04cc6855235c047d7fc86 100644 --- a/process/Sql_lib/process.js +++ b/process/Sql_lib/process.js @@ -3099,12 +3099,12 @@ function SqlMaskingUtils(alias) { * returns the concat symbol depending on database type * @return {String} Concat Symbol */ -SqlMaskingUtils.prototype.getConcatSymbol = function() { - var concatSymbol; - switch(Number(this.dbType)) { +SqlMaskingUtils.prototype.getConcatSymbol = function() +{ + switch(Number(this.dbType)) + { case db.DBTYPE_SQLSERVER2000: - concatSymbol = " + "; - break; + return " + "; case db.DBTYPE_MARIADB10: case db.DBTYPE_MYSQL4: case db.DBTYPE_ORACLE10_CLUSTER: @@ -3113,10 +3113,8 @@ SqlMaskingUtils.prototype.getConcatSymbol = function() { case db.DBTYPE_POSTGRESQL8: case db.DBTYPE_DERBY10: default: - concatSymbol = " || "; - break; + return " || "; } - return concatSymbol; } /** @@ -3131,18 +3129,11 @@ SqlMaskingUtils.prototype.getConcatSymbol = function() { * @return {String} <p> * Returns the trimmed string.<br> */ -SqlMaskingUtils.prototype.trim = function(pField) { - var dbType, resultStr; - dbType = this.dbType; - switch(dbType) { - case db.DBTYPE_SQLSERVER2000: - resultStr = "ltrim(rtrim(" + pField + "))"; - break; - default: - resultStr = "trim(" + pField + ")" - break; - } - return resultStr; +SqlMaskingUtils.prototype.trim = function(pField) +{ + if (this.dbType == db.DBTYPE_SQLSERVER2000) + return "ltrim(rtrim(" + pField + "))"; + return "trim(" + pField + ")"; } /** @@ -3267,10 +3258,10 @@ SqlMaskingUtils.prototype.cast = function(field, targetDatatype, targetLength) { switch(targetDatatype) { case SQLTYPES.VARCHAR: - datatype = "varchar2"; + sqlDataType = "varchar2"; break; case SQLTYPES.INTEGER: - datatype = "number"; + sqlDataType = "number"; targetLength = "10" break; case SQLTYPES.CHAR: @@ -3417,41 +3408,41 @@ SqlMaskingUtils.prototype.substring = function(field, start, length) { * if a sql field is empty no separator will be added * note that this function will often create a lot of sql-code * -* @param {Array} fields req fields (or expressions) that should be concatenated -* @param {String} [separatorCharacter=space-character] character for separating the fields; warning: the character will not be quoted -* @param {String} [autoTrimFields=true] autoTrimFields if true the expressions are always trimmed, false no change will be applied +* @param {Array} pFields fields (or expressions) that should be concatenated +* @param {String} [pSeparator=space-character] character for separating the fields +* @param {String} [pAutoTrimFields=true] autoTrimFields if true the expressions are always trimmed, false no change will be applied * * @return {String} part of SQL-querey */ -SqlMaskingUtils.prototype.concat = function(fields, separatorCharacter, autoTrimFields) { - var concatSql, retSql, isNotEmptyStrSql, isNotNullSql, separatorSql, _isNotEmpty, _trimIfAutoTrimEnabled; - if (fields.length == 0) +SqlMaskingUtils.prototype.concat = function(pFields, pSeparator, pAutoTrimFields) +{ + if (pFields.length === 0) return "''"; - else if (fields.length == 1) - return fields[0]; - concatSql = this.getConcatSymbol(); - isNotEmptyStrSql = " != '' "; - isNotNullSql = " is not null "; - separatorSql = separatorCharacter == undefined ? " " : separatorCharacter; - retSql = ""; - if (autoTrimFields == undefined) - autoTrimFields = true; + if (pFields.length === 1) + return pFields[0]; + + if (pAutoTrimFields == undefined) + pAutoTrimFields = true; + + if (pSeparator === null || pSeparator === undefined) + pSeparator = "' '"; + else if (pSeparator) + pSeparator = "'" + db.quote(pSeparator, this.alias) + "'"; + + var doEmptyStringCheck = true; - switch(this.dbType) + switch (this.dbType) { case db.DBTYPE_MYSQL4: case db.DBTYPE_MARIADB10: case db.DBTYPE_POSTGRESQL8: - retSql = " concat_ws( '" + separatorSql + "'"; - for (let i = 0; i < fields.length; i++) { - retSql += ", " + fields[i]; - } - return retSql + ") "; - break; + if (pAutoTrimFields) + pFields = pFields.map(this.trim, this); + return " concat_ws( " + pSeparator + ", " + pFields.join(", ") + ")"; case db.DBTYPE_ORACLE10_CLUSTER: case db.DBTYPE_ORACLE10_THIN: case db.DBTYPE_ORACLE10_OCI: - isNotEmptyStrSql = null; //empty strings are changed to DB-null-values internally in oracle; by specifing JS-null we disable this check + doEmptyStringCheck = false; //empty strings are changed to DB-null-values internally in oracle; by specifing JS-null we disable this check break; case db.DBTYPE_SQLSERVER2000: //MS SQL Server supports "concat_ws" (and ignoring null values) from version SQL Server 2017 and newer: @@ -3462,33 +3453,47 @@ SqlMaskingUtils.prototype.concat = function(fields, separatorCharacter, autoTrim default: throw new Error(translate.withArguments("${SQL_LIB_UNSUPPORTED_DBTYPE} function: %0", ["SqlMaskingUtils.prototype.concat"])); } - separatorSql = concatSql + "'" + separatorSql + "'"; - _trimIfAutoTrimEnabled = function(f){ - if (autoTrimFields) - return this.trim(f); + + var concatCharacter = this.getConcatSymbol(); + var concatSql = ""; + + for (let i = 0; i < pFields.length; i++) + { + let field = pFields[i]; + let isLast = i + 1 === pFields.length; + + if (!_isFixedValue(field)) + concatSql += (pAutoTrimFields ? this.trim(this.isNull(field)) : this.isNull(field)); else - return f; - } - _trimIfAutoTrimEnabled = _trimIfAutoTrimEnabled.bind(this); - _isNotEmpty = function(f){ - return _trimIfAutoTrimEnabled(f) + isNotEmptyStrSql + " and " + f + isNotNullSql; + concatSql += (pAutoTrimFields ? "'" + field.slice(1, -1).trim() + "'" : field); + + if (!isLast) + { + concatSql += concatCharacter; + let nextField = pFields[i+1]; + if (pSeparator && _isFixedValue(nextField)) + { + if (nextField.slice(1, -1).trim()) + concatSql += pSeparator + concatCharacter; + } + else if (pSeparator) + { + let nextFieldTrimmed = pAutoTrimFields ? this.trim(nextField) : nextField; + let nextNotNullCondition = nextField + " is not null "; + if (doEmptyStringCheck || pAutoTrimFields) + nextNotNullCondition += " and " + nextFieldTrimmed + " != '' "; + + concatSql += "case when " + nextNotNullCondition + " then " + pSeparator + " else '' end " + concatCharacter; + } + } } - _isNotEmpty = _isNotEmpty.bind(this); - for (let i = 0; i < fields.length; i++) { - if (retSql != "") - retSql += concatSql; - retSql += "case when " + _isNotEmpty(fields[i]) + " then "; - if ( i < fields.length - 1 ) //Prüfen, ob ein nachfolgender Wert kommt, sonst braucht man keinen Separator - retSql += " case when " + _isNotEmpty(fields[i + 1]) + " then " + _trimIfAutoTrimEnabled(fields[i]) + separatorSql + " else " + _trimIfAutoTrimEnabled(fields[i]) + " end "; - else - retSql += _trimIfAutoTrimEnabled(fields[i]); - //this blank is used just as in the old concat function which means this concat function has the same (wrong) behaviour - //TODO: find way to fix the case when separator is not a whitepsace (e.g. space) - //this concat-function does not work properly if you concat [<<value>>, <<null>>, <<value>>] by comma - retSql += " else ' ' end "; + return concatSql; + + function _isFixedValue (pSqlField) + { + return pSqlField.startsWith("'") && pSqlField.endsWith("'") && !pSqlField.slice(1, -1).includes("'"); } - return retSql; } /**