001/** 002 * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.mybatisflex.core.dialect.impl; 017 018import com.mybatisflex.core.dialect.KeywordWrap; 019import com.mybatisflex.core.dialect.LimitOffsetProcessor; 020import com.mybatisflex.core.row.Row; 021import com.mybatisflex.core.table.TableInfo; 022import com.mybatisflex.core.util.CollectionUtil; 023import com.mybatisflex.core.util.StringUtil; 024 025import java.util.List; 026import java.util.Map; 027import java.util.Set; 028import java.util.StringJoiner; 029 030public class OracleDialect extends CommonsDialectImpl { 031 032 private static final Set<String> keywords = CollectionUtil.newHashSet( 033 "ACCESS", "ADD", "ALL", "ALTER", 034 "AND", "ANY", "ARRAYLEN", "AS", 035 "ASC", "AUDIT", "BETWEEN", "BY", 036 "CHAR", "CHECK", "CLUSTER", "COLUMN", 037 "COMMENT", "COMPRESS", "CONNECT", "CREATE", 038 "CURRENT", "DATE", "DECIMAL", "DEFAULT", 039 "DELETE", "DESC", "DISTINCT", "DROP", 040 "ELSE", "EXCLUSIVE", "EXISTS", "FILE", 041 "FLOAT", "FOR", "FROM", "GRANT", 042 "GROUP", "HAVING", "IDENTIFIED", "IMMEDIATE", 043 "IN", "INCREMENT", "INDEX", "INITIAL", 044 "INSERT", "INTEGER", "INTERSECT", "INTO", 045 "IS", "LEVEL", "LIKE", "LOCK", 046 "LONG", "MAXEXTENTS", "MINUS", "MODE", 047 "MODIFY", "NOAUDIT", "NOCOMPRESS", "NOT", 048 "NOTFOUND", "NOWAIT", "NULL", "NUMBER", 049 "OF", "OFFLINE", "ON", "ONLINE", 050 "OPTION", "OR", "ORDER", "PCTFREE", 051 "PRIOR", "PRIVILEGES", "PUBLIC", "RAW", 052 "RENAME", "RESOURCE", "REVOKE", "ROW", 053 "ROWID", "ROWLABEL", "ROWNUM", "ROWS", 054 "START", "SELECT", "SESSION", "SET", 055 "SHARE", "SIZE", "SMALLINT", "SQLBUF", 056 "SUCCESSFUL", "SYNONYM", "SYSDATE", "TABLE", 057 "THEN", "TO", "TRIGGER", "UID", 058 "UNION", "UNIQUE", "UPDATE", "USER", 059 "VALIDATE", "VALUES", "VARCHAR", "VARCHAR2" 060 ); 061 062 public OracleDialect() { 063 this(LimitOffsetProcessor.ORACLE); 064 } 065 066 public OracleDialect(LimitOffsetProcessor limitOffsetProcessor) { 067 super(new KeywordWrap(keywords, "\"", "\""), limitOffsetProcessor); 068 } 069 070 @Override 071 public String forInsertEntityBatch(TableInfo tableInfo, List<?> entities) { 072 /** 073 * INSERT ALL 074 * INTO t (col1, col2, col3) VALUES ('val1_1', 'val1_2', 'val1_3') 075 * INTO t (col1, col2, col3) VALUES ('val2_1', 'val2_2', 'val2_3') 076 * INTO t (col1, col2, col3) VALUES ('val3_1', 'val3_2', 'val3_3') 077 * . 078 * . 079 * . 080 * SELECT 1 FROM DUAL; 081 */ 082 StringBuilder sql = new StringBuilder(); 083 sql.append("INSERT ALL"); 084 String[] insertColumns = tableInfo.obtainInsertColumns(null, false); 085 String[] warpedInsertColumns = new String[insertColumns.length]; 086 for (int i = 0; i < insertColumns.length; i++) { 087 warpedInsertColumns[i] = wrap(insertColumns[i]); 088 } 089 090 091 Map<String, String> onInsertColumns = tableInfo.getOnInsertColumns(); 092 for (int i = 0; i < entities.size(); i++) { 093 sql.append(" INTO ").append(tableInfo.getWrapSchemaAndTableName(this)); 094 sql.append(" (").append(StringUtil.join(", ", warpedInsertColumns)).append(")"); 095 sql.append(" VALUES "); 096 097 StringJoiner stringJoiner = new StringJoiner(", ", "(", ")"); 098 for (String insertColumn : insertColumns) { 099 if (onInsertColumns != null && onInsertColumns.containsKey(insertColumn)) { 100 //直接读取 onInsert 配置的值,而不用 "?" 代替 101 stringJoiner.add(onInsertColumns.get(insertColumn)); 102 } else { 103 stringJoiner.add("?"); 104 } 105 } 106 sql.append(stringJoiner); 107 } 108 109 return sql.append(" SELECT 1 FROM DUAL").toString(); 110 } 111 112 113 @Override 114 public String forInsertBatchWithFirstRowColumns(String schema, String tableName, List<Row> rows) { 115 /** 116 * INSERT ALL 117 * INTO t (col1, col2, col3) VALUES ('val1_1', 'val1_2', 'val1_3') 118 * INTO t (col1, col2, col3) VALUES ('val2_1', 'val2_2', 'val2_3') 119 * INTO t (col1, col2, col3) VALUES ('val3_1', 'val3_2', 'val3_3') 120 * . 121 * . 122 * . 123 * SELECT 1 FROM DUAL; 124 */ 125 StringBuilder fields = new StringBuilder(); 126 Row firstRow = rows.get(0); 127 Set<String> attrs = firstRow.obtainModifyAttrs(); 128 int index = 0; 129 for (String column : attrs) { 130 fields.append(wrap(column)); 131 if (index != attrs.size() - 1) { 132 fields.append(", "); 133 } 134 index++; 135 } 136 137 StringBuilder sql = new StringBuilder(); 138 sql.append("INSERT ALL"); 139 140 String tableNameWrap = StringUtil.isNotBlank(schema) 141 ? wrap(getRealSchema(schema)) + "." + wrap(getRealTable(tableName)) 142 : wrap(getRealTable(tableName)); 143 String questionStrings = buildQuestion(attrs.size(), true); 144 145 for (int i = 0; i < rows.size(); i++) { 146 sql.append(" INTO ").append(tableNameWrap); 147 sql.append(" (").append(fields).append(")"); 148 sql.append(" VALUES ").append(questionStrings); 149 } 150 151 return sql.append(" SELECT 1 FROM DUAL").toString(); 152 } 153}