/* * ********************************************************************************************************************* * * !! * .F88X * X8888Y * .}888888N; * i888888N; .:! .I$WI: * R888888I .'N88~ i8}+8Y&8"l8i$8>8W~'>W8}8]KW+8IIN"8& * .R888888I .;N8888~ .X8' "8I.!,/8" !%NY8`"8I8~~8>,88I * +888888N; .8888888Y "&&8Y.}8, * ./888888N; .R888888Y .'}~ .>}'.`+> i}! "i' +/' .'i~ !11,.:">, .~]! .i}i * ~888888%: .I888888l .]88~`1/iY88Ii+1'.R$8$8]"888888888> Y8$ W8E X8E W8888'188Il}Y88$* * 18888888 E8888881 .]W%8$`R8X'&8%++N8i,8N%N8+l8%` .}8N:.R$RE%N88N%N$K$R 188,FE$8%~Y88I * .E888888I .i8888888' .:$8I;88+`E8R:/8N,.>881.`$8E/1/]N8X.Y8N`"KF&&FK!'88*."88K./$88%RN888+~ * 8888888I .,N888888~ ~88i"8W,!N8*.I88.}888%F,i$88"F88" 888:E8X.>88!i88>`888*.}Fl1]*}1YKi' * i888888N' I888Y ]88;/EX*IFKFK88X K8R .l8W 88Y ~88}'88E&%8W.X8N``]88!.$8K .:W8I * .i888888N; I8Y .&8$ .X88! i881.:%888>I88 ;88] +88+.';;;;:.Y88X 18N.,88l .+88/ * .:R888888I * .&888888I Copyright (c) 2009-2020. 博锐尚格科技股份有限公司 * ~8888' * .!88~ All rights reserved. * * ********************************************************************************************************************* */ package com.persagy.postgresql import com.persagy.base.extensions.isBaseType import com.persagy.base.extensions.toJson import com.persagy.base.extensions.toJsonAll import com.persagy.database.* import com.persagy.database.enums.SDatabaseType import com.persagy.database.enums.SOps import com.persagy.gis.entity.SAbstractGisGeometry import com.persagy.mybatis.SAbstractDriver import com.persagy.mybatis.SSqlProvider import org.apache.ibatis.jdbc.SQL import org.slf4j.LoggerFactory /** * PostgreSQL 驱动 * * @author 庞利祥 */ class SPostgreSqlDriver : SAbstractDriver() { /** 静态对象 */ companion object { /** 日志记录器 */ private val logger = LoggerFactory.getLogger(SPostgreSqlDriver::class.java) } /** * 在数据库中插入实体 * * @param argsMap 注入参数 * @return 插入 SQL 语句 */ @Suppress("UNCHECKED_CAST") override fun insert(argsMap: Map): String { val builder = argsMap["builder"] as SInsetBuilder<*> val entityClass = argsMap["entityClass"] as Class<*> val entity = argsMap["entity"] as HashMap val sql = object: SQL() { init { /** 如果查询构建器朱指定了表名 */ if (builder!=null&&!builder.tableName.isNullOrEmpty()) { INSERT_INTO(builder.tableName!!) } else { INSERT_INTO(SSqlProvider.driver.tableName(entityClass)) } for ((key, value) in entity) { if (value != null) { if (value is Map<*,*>) { VALUES(SSqlProvider.driver.escName(key), "'${value.toJsonAll().replace("'", "''")}'") } else if (value is List<*>) { VALUES(SSqlProvider.driver.escName(key), "'${value.toJsonAll().replace("'", "''")}'") } else if (value::class.java.isPrimitive){ VALUES(SSqlProvider.driver.escName(key), "'${value.toJsonAll().replace("'", "''")}'") } else if (value is SAbstractGisGeometry) { VALUES(SSqlProvider.driver.escName(key), "ST_GeomFromText('${value.toWkt()}')") } else { VALUES(SSqlProvider.driver.escName(key), SSqlProvider.driver.entityValue(entity, key)) } // if (value::class.java.isPrimitive) { // VALUES(driver.escName(key), driver.entityValue(entity, key)) // } else { // VALUES(driver.escName(key), "'${value.toJsonAll()}'") // } } } } }.toString() logger.debug("INSERT SQL= $sql") return sql } /** * 在数据库中替换实体 * * @param argsMap 注入参数 * * @return 替换 SQL 语句 */ @Suppress("UNCHECKED_CAST") override fun replace(argsMap: Map): String { val sql: String val builder = argsMap["builder"] as SReplaceBuilder<*> val entity = argsMap["entity"] as Map val keyColumnList = argsMap["keyColumnList"] as ArrayList val upSqlBuilder = StringBuilder() logger.debug("entity=${entity.toJson()}") for ((key, value) in entity) { if (value != null) { if (upSqlBuilder.length > 1) { upSqlBuilder.append(",") } if (value is Map<*,*>) { upSqlBuilder.append("${escName(key)} = '${value.toJsonAll().replace("'", "''")}'") } else if (value is List<*>) { upSqlBuilder.append("${escName(key)} = '${value.toJsonAll().replace("'", "''")}'") } else if (value::class.java.isPrimitive){ upSqlBuilder.append("${escName(key)} = '${value.toJsonAll().replace("'", "''")}'") } else if (value is SAbstractGisGeometry) { upSqlBuilder.append("${escName(key)} = ST_GeomFromText('${value.toWkt()}')") // VALUES(SSqlProvider.driver.escName(key), "ST_GeomFromText('${value.toWkt()}')") } else { upSqlBuilder.append("${escName(key)} = #{entity.$key}") } // if (value::class.java.isPrimitive) { // upSqlBuilder.append("${escName(key)} = #{entity.$key}") // } else { // upSqlBuilder.append("${escName(key)} = '${value.toJsonAll()}'") // } } else { // 维新有特殊要求 // if (upSqlBuilder.length > 1) { // upSqlBuilder.append(",") // } // upSqlBuilder.append("${driver.keyEsc}$key${driver.keyEsc} = null") } } val confict = StringBuilder() keyColumnList.forEach { if (confict.length > 1) { confict.append(",") } confict.append("\"$it\"") } sql = "${replaceInsert(argsMap)} ON conflict ( $confict ) DO UPDATE SET $upSqlBuilder" logger.debug("REPLACE SQL= $sql") return sql } // @Suppress("UNCHECKED_CAST") // open fun update(argsMap: Map): String { // // } /** * 根据条件更新 * * @param argsMap 注入参数 * @return 更新 SQL 语句 */ override fun update(argsMap: Map): String { val entityClass = argsMap["entityClass"] as Class<*> val entity = argsMap["entity"] as HashMap val filterArgs = argsMap["filterArgs"] as List val whereArgs = argsMap["whereArgs"] as HashMap val nullItemList = ArrayList() if (argsMap.containsKey("nullItems")) { val fields = argsMap["nullItems"] as ArrayList? /** 转换属性名 */ fields?.forEach { try { val colName = SAbstractDao.columnName(entityClass, it.trim()) nullItemList.add(colName) } catch (e: Exception) { e.printStackTrace() } } } // val updateNull = fieldList.size > 0 // val clause = buildWhereArgList(entityClass, filterArgs, whereArgs) val sql = object: SQL() { init { UPDATE(SSqlProvider.driver.tableName(entityClass)) // 遍历传入的对象的属性 键值 for ((key, value) in entity) { // if (nullItemList.size > 0 && !nullItemList.contains(key)) { // continue // } // if (value == null && updateNull) { // // PostgreSQL使用参数更新,为空更新不成功。必须使用sql直接设置 // SET("${SSqlProvider.driver.escName(key)} = null") // } // 值不为空的更新 if (value != null) { if (value is Map<*,*>) { SET("${SSqlProvider.driver.escName(key)} = ${SSqlProvider.driver.updateJson(key, value)}") }else if (value is List<*>) { SET("${SSqlProvider.driver.escName(key)} = ${SSqlProvider.driver.updateJson(key, value)}") } else if (value is SAbstractGisGeometry) { SET("${SSqlProvider.driver.escName(key)} = ST_GeomFromText('${value.toWkt()}')") } else { SET("${SSqlProvider.driver.escName(key)} = ${SSqlProvider.driver.entityValue(entity, key)}") } // if (value::class.java.isPrimitive) { // SET("${driver.keyEsc}$key${driver.keyEsc} = ${driver.entityValue(entity, key)}") // } else { // SET("${driver.keyEsc}$key${driver.keyEsc} = ${driver.updateJson(key, value)}") // } } } // 遍历置空属性列表 for (nullItem in nullItemList){ // PostgreSQL使用参数更新,为空更新不成功。必须使用sql直接设置 val pos = nullItem.indexOf(".") if (pos > 0){ SET(SSqlProvider.driver.updateNullItem(nullItem)) }else{ SET("${SSqlProvider.driver.escName(nullItem)} = null") } } // 更新条件为空不拼接条件 if (clause.isNotEmpty()) { WHERE(clause) } } }.toString() logger.debug("SQL= $sql") return sql } /** * 根据条件删除 * * @param argsMap 注入参数 * @return 删除 SQL 语句 */ @Suppress("UNCHECKED_CAST") override fun delete(argsMap: Map): String { val builder = argsMap["builder"] as SDeleteBuilder<*> val entityClass = argsMap["entityClass"] as Class<*> /** 从入参中获得过虑条件 */ val filterArgs = argsMap["filterArgs"] as List /** 转换后的where语句参数 */ val whereArgs = argsMap["whereArgs"] as HashMap val clause = buildWhereArgList(entityClass, filterArgs, whereArgs) val sql = object: SQL() { init { /** 如果查询构建器朱指定了表名 */ if (builder!=null&&!builder.tableName.isNullOrEmpty()) { DELETE_FROM(builder.tableName!!) } else { DELETE_FROM(SSqlProvider.driver.tableName(entityClass)) } if (clause.isNotEmpty()) { WHERE(clause) } } }.toString() logger.debug("SQL= $sql") return sql } /** * 删除所有记录 * * @param argsMap 注入参数 * @return 删除 SQL 语句 */ @Suppress("UNCHECKED_CAST") override fun deleteAll(argsMap: Map): String { val builder = argsMap["builder"] as SDeleteBuilder<*>? val entityClass = argsMap["entityClass"] as Class<*> val sql = object: SQL() { init { if (builder!=null&&!builder.tableName.isNullOrEmpty()) { DELETE_FROM(builder.tableName!!) } else { DELETE_FROM(SSqlProvider.driver.tableName(entityClass)) } } }.toString() logger.debug("SQL= $sql") return sql } /** * 执行查询操作 * * @param argsMap 注入参数 * @return 查询 SQL 语句 */ @Suppress("UNCHECKED_CAST") override fun execQuery(argsMap: Map): String { val entityClass = argsMap["entityClass"] as Class<*> val builder = argsMap["builder"] as SQueryBuilder<*> val whereArgs = argsMap["whereArgs"] as HashMap val clause = buildWhereArgList(entityClass, builder.filterList, whereArgs) var sql = object: SQL() { init { logger.debug("333333333333333") /** 如果选择去重 */ if (builder.isDistinct) { SELECT_DISTINCT(buildColumns(entityClass, builder.fieldList)) } else { SELECT(buildColumns(entityClass, builder.fieldList)) } /** 如果查询构建器朱指定了表名 */ if (builder.tableName.isNullOrEmpty()) { FROM(SSqlProvider.driver.tableName(entityClass)) } else { FROM(builder.tableName!!) } /** 过滤条件 */ if (clause.isNotEmpty()) { WHERE(clause) } /** 排序条件 */ for (col in builder.orderArgs) { var path: String? = null var propertyName = col.name val pos = propertyName.indexOf(".") if (pos > 0) { path = propertyName.substring(pos + 1) propertyName = propertyName.substring(0, pos) } val colName = SAbstractDao.columnName(entityClass, SAbstractDao.propertyName(entityClass, propertyName)) ORDER_BY("${SSqlProvider.driver.columnName(colName, path)} ${col.direction}") } /** 分组 */ if (!builder.group.nameList.isNullOrEmpty()) { for (name in builder.group.nameList) { val colName = SAbstractDao.columnName(entityClass, name) GROUP_BY(SSqlProvider.driver.escName(colName)) } if (builder.group.count !=null && builder.group.count!!) { SELECT("count(1) as _statistics_count") } if (!builder.group.sumList.isNullOrEmpty()) { for (name in builder.group.sumList) { val colName = SAbstractDao.columnName(entityClass, SAbstractDao.propertyName(entityClass, name)) SELECT("sum(${SSqlProvider.driver.columnName(colName, null)}) as _statistics_sum_$name") } } if (!builder.group.avgList.isNullOrEmpty()) { for (name in builder.group.sumList) { val colName = SAbstractDao.columnName(entityClass, SAbstractDao.propertyName(entityClass, name)) SELECT("avg(${SSqlProvider.driver.columnName(colName, null)}) as _statistics_avg_$name") } } if (!builder.group.maxList.isNullOrEmpty()) { for (name in builder.group.sumList) { val colName = SAbstractDao.columnName(entityClass, SAbstractDao.propertyName(entityClass, name)) SELECT("max(${SSqlProvider.driver.columnName(colName, null)}) as _statistics_max_$name") } } if (!builder.group.minList.isNullOrEmpty()) { for (name in builder.group.sumList) { val colName = SAbstractDao.columnName(entityClass, SAbstractDao.propertyName(entityClass, name)) SELECT("min(${SSqlProvider.driver.columnName(colName, null)}) as _statistics_min_$name") } } } } }.toString() if (builder.count != null) { sql += SSqlProvider.driver.limit(builder.offset, builder.count) } logger.debug("SQL= $sql") return sql } /** * 获得表名,取实体类 @Table 注解的名称,如果没有注解,则取实体类类名。 * * @param clz mapper 类类型 * @return 表名 */ override fun tableName(clz: Class<*>): String { val tableAnno = clz.getAnnotation(javax.persistence.Table::class.java) // 如果有@Table注解,则取注解的表名;否则使用类名做为表名 val tableName = tableAnno?.name ?: clz.simpleName val name = tableName.replace(".", "\".\"") return "\"$name\"" } /** * 将 name 加上引用符号 * * @param name 名称 * @return 加上引用符号的名称 */ override fun escName(name: String): String { return "\"$name\"" } /** * 实体类的值,如果不是基本类型,则转换为 json * * @param entity 实体类 * @param name 名称 * @return 加上引用符号的名称 */ override fun entityValue(entity: HashMap, name: String): String { val value = entity[name] ?: return "null" if (value.isBaseType()) { return "#{entity.$name}" } return "'${value.toJson()}'" } /** * 生成 limit 语句 * * @param offset 偏移位置 * @param count 取得的记录数 * @return LIMIT 子句 */ override fun limit(offset: Int?, count: Int?): String { if (count == null){ return " OFFSET ${offset ?: 0} LIMIT ${count ?: 1}" }else if (offset!=null&&count!=null){ return " OFFSET ${offset ?: 0} LIMIT ${count ?: 1}" }else{ return " OFFSET ${offset ?: 0} LIMIT ${count ?: 1}" } // return " OFFSET ${offset ?: 0} LIMIT ${count ?: 1}" } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 函数 /** * 处理函数支持 * * @param func 函数对象 * @param colName 字段名 * @return 生成的 SQL 语句 */ override fun processFunction(func: SAbstractFunction, colName: String): String { func.colName = colName return func.toSql(SDatabaseType.PostgreSQL) } //---------------------------------------------------------------------------------------------------------------------- /** * 转换where字句参数 * * @param argName 参数名 * @param argValue 参数值 * @param ops 运算符 * @return 转换后的 SQL */ override fun whereArg(argName: String, argValue: String, ops: SOps): String { when (ops) { SOps.EQ -> { /** 等于 */ return "$argName = $argValue" } SOps.NE -> { /** 不等于 */ return "$argName <> $argValue" } SOps.GT -> { /** 大于 */ return "$argName > $argValue" } SOps.GTE -> { /** 大于等于 */ return "$argName >= $argValue" } SOps.LT -> { /** 小于 */ return "$argName < $argValue" } SOps.LTE -> { /** 小于等行 */ return "$argName <= $argValue" } SOps.CONTAIN -> { /** 包含 */ return if (argName.indexOf("#") > 0) { "($argName)::TEXT LIKE ('%' || $argValue || '%')" } else { // todo: 拓扑图和平面图临时支持ArrayList 模糊查询字符串 /// 临时代码开始 logger.debug("argName=${argName}=11111111111111111111111111111111") if (argName.indexOf("label") > 0){ "$argName::TEXT LIKE ('%' || $argValue || '%')" }else { logger.debug("11111111111111111111111111111111111") "$argName LIKE ('%' || $argValue || '%')" } // 临时代码结束 ////////////////////// // 原始代码开始 // "$argName LIKE ('%' || $argValue || '%')" // 原始代码结束 } } SOps.STARTWITH -> { /** 以指定字符串开始 */ return if (argName.indexOf("#") > 0) { "($argName)::TEXT LIKE ($argValue || '%')" } else { "$argName LIKE ($argValue || '%')" } } SOps.ENDWITH -> { /** 以指定字符串结束 */ return if (argName.indexOf("#") > 0) { "($argName)::TEXT LIKE ('%' || $argValue)" } else { "$argName LIKE ('%' || $argValue)" } } SOps.ISNULL -> { /** 为空 */ return "$argName ISNULL" } else -> { } } return "" } /** * 转换参数名 SQL 语句 * * @param name 字段名 * @param path json 路径。如果不是 json 对象,则该值为空 * @return 转换后的 SQL */ override fun argName(name: String, path: String?): String { return if (path == null) { "\"$name\"" } else { val p = path.`replace`(".", ",") "\"$name\"#>'{$p}'" } } /** * 更新字段为空 */ override fun updateNullItem(nullItem: String): String { val pos = nullItem.indexOf(".") val path = nullItem.substring(pos + 1).replace(".",",") val propertyName = nullItem.substring(0, pos) return "${SSqlProvider.driver.escName(propertyName)} = (jsonb_set(${SSqlProvider.driver.escName(propertyName)}::jsonb,'{$path}','null'::jsonb))" } /** * 转换参数值 SQL 语句 * * @param argName 参数名 * @param isJson 是否 Json 对象 * @return 转换后的 SQL */ override fun argValue(argName: String, isJson: Boolean): String { return if (isJson) { "to_jsonb(#{whereArgs.$argName})" } else { "#{whereArgs.$argName}" } } /** * 转换 IN 条件表达式 * * @param name 字段名 * @param path json 路径,如果字段不为 json,则 path 为 null * @param inArg in 操作参数 * @return 转换后的 SQL */ override fun inArg(name: String, path: String?, inArg: String): String { return if (path == null) { "\"$name\" IN ($inArg)" } else { val p = path.replace(".", ",") "\"$name\"#>'{$p}' IN ($inArg)" } } /** * 将名称及 json 路径转换为 SQL * * @param name 字段名 * @param path json 路径,如果字段不为 json,则 path 为 null * @return 转换后的 SQL */ override fun columnName(name: String, path: String?): String { return if (path == null) { "\"$name\"" } else { val p = path.replace(".", ",") "\"$name\"#>'{$p}'" } } /** * 将参数值转换为 SQL 语句 * * @param value 值 * @param isJson 值是否转换为 json 格式 * @return 转换后的 SQL */ override fun argValueToJson(value: String, isJson: Boolean): String { return if (isJson) { "to_jsonb($value)" } else { value } } /** * 更新 Json 类型字段 * * @param name 字段名 * @param value 值 * @return 更新 SQL 字符串 */ override fun updateJson(name: String, value: Any): String { return "COALESCE(\"$name\", '{}') || '${value.toJsonAll().replace("'", "''")}'" } /** * 在数据库中替换实体-生成replace语句部分插入sql语句 * * @param argsMap 注入参数 * * @return 替换 SQL 语句 */ @Suppress("UNCHECKED_CAST") private fun replaceInsert(argsMap: Map): String { val builder = argsMap["builder"] as SReplaceBuilder<*>? val entityClass = argsMap["entityClass"] as Class<*> val entity = argsMap["entity"] as HashMap val sql = object : SQL() { init { /** 如果查询构建器朱指定了表名 */ if (builder!=null&&!builder.tableName.isNullOrEmpty()) { INSERT_INTO(builder.tableName!!) } else { INSERT_INTO(SSqlProvider.driver.tableName(entityClass)) } for ((key, value) in entity) { if (value != null) { if (value is Map<*, *>) { VALUES(SSqlProvider.driver.escName(key), "'${value.toJsonAll().replace("'", "''")}'") } else if (value is List<*>) { VALUES(SSqlProvider.driver.escName(key), "'${value.toJsonAll().replace("'", "''")}'") } else if (value::class.java.isPrimitive) { VALUES(SSqlProvider.driver.escName(key), "'${value.toJsonAll().replace("'", "''")}'") } else { VALUES(SSqlProvider.driver.escName(key), SSqlProvider.driver.entityValue(entity, key)) } // if (value::class.java.isPrimitive) { // VALUES(driver.escName(key), driver.entityValue(entity, key)) // } else { // VALUES(driver.escName(key), "'${value.toJsonAll()}'") // } } } } }.toString() logger.debug("INSERT SQL= $sql") return sql } }