ソースを参照

!94 增加h2database数据库方言
Merge pull request !94 from 校长/master

JFinal 3 年 前
コミット
8775e93fcd

+ 115 - 0
src/main/java/com/jfinal/plugin/activerecord/builder/H2RecordBuilder.java

@@ -0,0 +1,115 @@
+/**
+ * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.jfinal.plugin.activerecord.builder;
+
+import com.jfinal.plugin.activerecord.CPI;
+import com.jfinal.plugin.activerecord.Config;
+import com.jfinal.plugin.activerecord.Record;
+import com.jfinal.plugin.activerecord.RecordBuilder;
+
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+
+/**
+ * H2Database ResultRet to Record Builder.
+ * <pre>
+ * 使用示例:
+ * H2Dialect dialect = new H2Dialect();
+ * dialect.setRecordBuilder(H2RecordBuilder.me);
+ * activeRecordPlugin.setDialect(dialect);
+ * </pre>
+ */
+public class H2RecordBuilder extends RecordBuilder {
+
+    public static final H2RecordBuilder me = new H2RecordBuilder();
+
+    @Override
+    public List<Record> build(Config config, ResultSet rs) throws SQLException {
+        return build(config, rs, null);
+    }
+
+    /**
+     * 处理h2database JDBC查询结果集到Record与oracle不同,h2database中 BLOB列数据直接getBytes()取数据不需要处理和转换
+     *
+     * @param config
+     * @param rs
+     * @param func
+     * @return
+     * @throws SQLException
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public List<Record> build(Config config, ResultSet rs, Function<Record, Boolean> func) throws SQLException {
+        List<Record> result = new ArrayList<Record>();
+        ResultSetMetaData rsmd = rs.getMetaData();
+        int columnCount = rsmd.getColumnCount();
+        String[] labelNames = new String[columnCount + 1];
+        int[] types = new int[columnCount + 1];
+        buildLabelNamesAndTypes(rsmd, labelNames, types);
+        while (rs.next()) {
+            Record record = new Record();
+            CPI.setColumnsMap(record, config.getContainerFactory().getColumnsMap());
+            Map<String, Object> columns = record.getColumns();
+            for (int i = 1; i <= columnCount; i++) {
+                Object value;
+                if (types[i] < Types.BLOB) {
+                    value = rs.getObject(i);
+                } else {
+                    if (types[i] == Types.CLOB) {
+                        value = rs.getString(i);
+                    } else if (types[i] == Types.NCLOB) {
+                        value = rs.getString(i);
+                    } else if (types[i] == Types.BLOB) {
+                        value = rs.getBytes(i);
+                    } else {
+                        value = rs.getObject(i);
+                    }
+                }
+                columns.put(labelNames[i], value);
+            }
+
+            if (func == null) {
+                result.add(record);
+            } else {
+                if (!func.apply(record)) {
+                    break;
+                }
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public void buildLabelNamesAndTypes(ResultSetMetaData rsmd, String[] labelNames, int[] types) throws SQLException {
+        for (int i = 1; i < labelNames.length; i++) {
+            // 备忘:getColumnLabel 获取 sql as 子句指定的名称而非字段真实名称
+            labelNames[i] = rsmd.getColumnLabel(i);
+            types[i] = rsmd.getColumnType(i);
+        }
+    }
+}
+
+
+
+
+

+ 273 - 0
src/main/java/com/jfinal/plugin/activerecord/dialect/H2Dialect.java

@@ -0,0 +1,273 @@
+/**
+ * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jfinal.plugin.activerecord.dialect;
+
+import com.jfinal.plugin.activerecord.Config;
+import com.jfinal.plugin.activerecord.Record;
+import com.jfinal.plugin.activerecord.Table;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * H2Database Dialect
+ * 使用h2database数据库存取blob数据时需要指定RecordBuilder
+ * dialect.setRecordBuilder(H2RecordBuilder.me)
+ */
+public class H2Dialect extends Dialect {
+
+
+    @Override
+    public List<Record> buildRecordList(Config config, ResultSet rs) throws SQLException {
+        return recordBuilder.build(config, rs);
+    }
+
+    /**
+     * blob column data using setBytes()
+     * @param pst
+     * @param paras
+     * @throws SQLException
+     */
+    @Override
+    public void fillStatement(PreparedStatement pst, Object... paras) throws SQLException {
+        for (int i = 0; i < paras.length; i++) {
+            Object para = paras[i];
+            if (para instanceof byte[]) {
+                pst.setBytes(i + 1, (byte[]) para);
+            } else {
+                pst.setObject(i + 1, para);
+            }
+        }
+    }
+
+    /**
+     * blob column data using setBytes()
+     * @param pst
+     * @param paras
+     * @throws SQLException
+     */
+    @Override
+    public void fillStatement(PreparedStatement pst, List<Object> paras) throws SQLException {
+        for (int i = 0, size = paras.size(); i < size; i++) {
+            Object para = paras.get(i);
+            if (para instanceof byte[]) {
+                pst.setBytes(i + 1, (byte[]) para);
+            } else {
+                pst.setObject(i + 1, para);
+            }
+        }
+    }
+
+    @Override
+    public String forTableBuilderDoBuild(String tableName) {
+        return "select * from " + tableName + " where rownum < 1";
+    }
+
+    @Override
+    public String forPaginate(int pageNumber, int pageSize, StringBuilder findSql) {
+        int start = (pageNumber - 1) * pageSize;
+        int end = pageNumber * pageSize;
+        StringBuilder ret = new StringBuilder();
+        ret.append("select * from ( select row_.*, rownum rownum_ from (  ");
+        ret.append(findSql);
+        ret.append(" ) row_ where rownum <= ").append(end).append(") table_alias");
+        ret.append(" where table_alias.rownum_ > ").append(start);
+        return ret.toString();
+    }
+
+    @Override
+    public String forModelFindById(Table table, String columns) {
+        StringBuilder sql = new StringBuilder("select ").append(columns).append(" from ");
+        sql.append(table.getName());
+        sql.append(" where ");
+        String[] pKeys = table.getPrimaryKey();
+        for (int i = 0; i < pKeys.length; i++) {
+            if (i > 0) {
+                sql.append(" and ");
+            }
+            sql.append(pKeys[i]).append(" = ?");
+        }
+        return sql.toString();
+    }
+
+    @Override
+    public String forModelDeleteById(Table table) {
+        String[] pKeys = table.getPrimaryKey();
+        StringBuilder sql = new StringBuilder(45);
+        sql.append("delete from ");
+        sql.append(table.getName());
+        sql.append(" where ");
+        for (int i = 0; i < pKeys.length; i++) {
+            if (i > 0) {
+                sql.append(" and ");
+            }
+            sql.append(pKeys[i]).append(" = ?");
+        }
+        return sql.toString();
+    }
+
+    @Override
+    public void forModelSave(Table table, Map<String, Object> attrs, StringBuilder sql, List<Object> paras) {
+        sql.append("insert into ").append(table.getName()).append("(");
+        StringBuilder temp = new StringBuilder(") values(");
+        String[] pKeys = table.getPrimaryKey();
+        int count = 0;
+        for (Entry<String, Object> e : attrs.entrySet()) {
+            String colName = e.getKey();
+            if (table.hasColumnLabel(colName)) {
+                if (count++ > 0) {
+                    sql.append(", ");
+                    temp.append(", ");
+                }
+                sql.append(colName);
+                Object value = e.getValue();
+                if (value instanceof String && isPrimaryKey(colName, pKeys) && ((String) value).endsWith(".nextval")) {
+                    temp.append(value);
+                } else {
+                    temp.append("?");
+                    paras.add(value);
+                }
+            }
+        }
+        sql.append(temp.toString()).append(")");
+    }
+
+    @Override
+    public void forModelUpdate(Table table, Map<String, Object> attrs, Set<String> modifyFlag, StringBuilder sql,
+                               List<Object> paras) {
+        sql.append("update ").append(table.getName()).append(" set ");
+        String[] pKeys = table.getPrimaryKey();
+        for (Entry<String, Object> e : attrs.entrySet()) {
+            String colName = e.getKey();
+            if (modifyFlag.contains(colName) && !isPrimaryKey(colName, pKeys) && table.hasColumnLabel(colName)) {
+                if (paras.size() > 0) {
+                    sql.append(", ");
+                }
+                sql.append(colName).append(" = ? ");
+                paras.add(e.getValue());
+            }
+        }
+        sql.append(" where ");
+        for (int i = 0; i < pKeys.length; i++) {
+            if (i > 0) {
+                sql.append(" and ");
+            }
+            sql.append(pKeys[i]).append(" = ?");
+            paras.add(attrs.get(pKeys[i]));
+        }
+    }
+
+    @Override
+    public String forDbFindById(String tableName, String[] pKeys) {
+        tableName = tableName.trim();
+        trimPrimaryKeys(pKeys);
+
+        StringBuilder sql = new StringBuilder("select * from ").append(tableName).append(" where ");
+        for (int i = 0; i < pKeys.length; i++) {
+            if (i > 0) {
+                sql.append(" and ");
+            }
+            sql.append(pKeys[i]).append(" = ?");
+        }
+        return sql.toString();
+    }
+
+    @Override
+    public String forDbDeleteById(String tableName, String[] pKeys) {
+        tableName = tableName.trim();
+        trimPrimaryKeys(pKeys);
+
+        StringBuilder sql = new StringBuilder("delete from ").append(tableName).append(" where ");
+        for (int i = 0; i < pKeys.length; i++) {
+            if (i > 0) {
+                sql.append(" and ");
+            }
+            sql.append(pKeys[i]).append(" = ?");
+        }
+        return sql.toString();
+    }
+
+    @Override
+    public void forDbSave(String tableName, String[] pKeys, Record record, StringBuilder sql, List<Object> paras) {
+        tableName = tableName.trim();
+        trimPrimaryKeys(pKeys);
+
+        sql.append("insert into ");
+        sql.append(tableName).append("(");
+        StringBuilder temp = new StringBuilder();
+        temp.append(") values(");
+
+        int count = 0;
+        for (Entry<String, Object> e : record.getColumns().entrySet()) {
+            String colName = e.getKey();
+            if (count++ > 0) {
+                sql.append(", ");
+                temp.append(", ");
+            }
+            sql.append(colName);
+
+            Object value = e.getValue();
+            if (value instanceof String && isPrimaryKey(colName, pKeys) && ((String) value).endsWith(".nextval")) {
+                temp.append(value);
+            } else {
+                temp.append("?");
+                paras.add(value);
+            }
+        }
+        sql.append(temp.toString()).append(")");
+    }
+
+    @Override
+    public void forDbUpdate(String tableName, String[] pKeys, Object[] ids, Record record, StringBuilder sql,
+                            List<Object> paras) {
+        tableName = tableName.trim();
+        trimPrimaryKeys(pKeys);
+
+        sql.append("update ").append(tableName).append(" set ");
+        for (Entry<String, Object> e : record.getColumns().entrySet()) {
+            String colName = e.getKey();
+            if (!isPrimaryKey(colName, pKeys)) {
+                if (paras.size() > 0) {
+                    sql.append(", ");
+                }
+                sql.append(colName).append(" = ? ");
+                paras.add(e.getValue());
+            }
+        }
+        sql.append(" where ");
+        for (int i = 0; i < pKeys.length; i++) {
+            if (i > 0) {
+                sql.append(" and ");
+            }
+            sql.append(pKeys[i]).append(" = ?");
+            paras.add(ids[i]);
+        }
+    }
+
+    /**
+     * h2database is similar to oracle
+     * @return
+     */
+    @Override
+    public boolean isOracle() {
+        return true;
+    }
+}