github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/databases/orm/db_oracle.go (about) 1 // The original package is migrated from beego and modified, you can find orignal from following link: 2 // "github.com/beego/beego/" 3 // 4 // Copyright 2023 IAC. All Rights Reserved. 5 // 6 // Licensed under the Apache License, Version 2.0 (the "License"); 7 // you may not use this file except in compliance with the License. 8 // You may obtain a copy of the License at 9 // 10 // http://www.apache.org/licenses/LICENSE-2.0 11 // 12 // Unless required by applicable law or agreed to in writing, software 13 // distributed under the License is distributed on an "AS IS" BASIS, 14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 // See the License for the specific language governing permissions and 16 // limitations under the License. 17 18 package orm 19 20 import ( 21 "context" 22 "fmt" 23 "strings" 24 25 "github.com/mdaxf/iac/databases/orm/hints" 26 ) 27 28 // oracle operators. 29 var oracleOperators = map[string]string{ 30 "exact": "= ?", 31 "gt": "> ?", 32 "gte": ">= ?", 33 "lt": "< ?", 34 "lte": "<= ?", 35 "//iendswith": "LIKE ?", 36 } 37 38 // oracle column field types. 39 var oracleTypes = map[string]string{ 40 "pk": "NOT NULL PRIMARY KEY", 41 "bool": "bool", 42 "string": "VARCHAR2(%d)", 43 "string-char": "CHAR(%d)", 44 "string-text": "VARCHAR2(%d)", 45 "time.Time-date": "DATE", 46 "time.Time": "TIMESTAMP", 47 "int8": "INTEGER", 48 "int16": "INTEGER", 49 "int32": "INTEGER", 50 "int64": "INTEGER", 51 "uint8": "INTEGER", 52 "uint16": "INTEGER", 53 "uint32": "INTEGER", 54 "uint64": "INTEGER", 55 "float64": "NUMBER", 56 "float64-decimal": "NUMBER(%d, %d)", 57 "time.Time-precision": "TIMESTAMP(%d)", 58 } 59 60 // oracle dbBaser 61 type dbBaseOracle struct { 62 dbBase 63 } 64 65 var _ dbBaser = new(dbBaseOracle) 66 67 // create oracle dbBaser. 68 func newdbBaseOracle() dbBaser { 69 b := new(dbBaseOracle) 70 b.ins = b 71 return b 72 } 73 74 // OperatorSQL get oracle operator. 75 func (d *dbBaseOracle) OperatorSQL(operator string) string { 76 return oracleOperators[operator] 77 } 78 79 // DbTypes get oracle table field types. 80 func (d *dbBaseOracle) DbTypes() map[string]string { 81 return oracleTypes 82 } 83 84 // ShowTablesQuery show all the tables in database 85 func (d *dbBaseOracle) ShowTablesQuery() string { 86 return "SELECT TABLE_NAME FROM USER_TABLES" 87 } 88 89 // Oracle 90 func (d *dbBaseOracle) ShowColumnsQuery(table string) string { 91 return fmt.Sprintf("SELECT COLUMN_NAME FROM ALL_TAB_COLUMNS "+ 92 "WHERE TABLE_NAME ='%s'", strings.ToUpper(table)) 93 } 94 95 // check index is exist 96 func (d *dbBaseOracle) IndexExists(ctx context.Context, db dbQuerier, table string, name string) bool { 97 row := db.QueryRowContext(ctx, "SELECT COUNT(*) FROM USER_IND_COLUMNS, USER_INDEXES "+ 98 "WHERE USER_IND_COLUMNS.INDEX_NAME = USER_INDEXES.INDEX_NAME "+ 99 "AND USER_IND_COLUMNS.TABLE_NAME = ? AND USER_IND_COLUMNS.INDEX_NAME = ?", strings.ToUpper(table), strings.ToUpper(name)) 100 101 var cnt int 102 row.Scan(&cnt) 103 return cnt > 0 104 } 105 106 func (d *dbBaseOracle) GenerateSpecifyIndex(tableName string, useIndex int, indexes []string) string { 107 var s []string 108 Q := d.TableQuote() 109 for _, index := range indexes { 110 tmp := fmt.Sprintf(`%s%s%s`, Q, index, Q) 111 s = append(s, tmp) 112 } 113 114 var hint string 115 116 switch useIndex { 117 case hints.KeyUseIndex, hints.KeyForceIndex: 118 hint = `INDEX` 119 case hints.KeyIgnoreIndex: 120 hint = `NO_INDEX` 121 default: 122 DebugLog.Println("[WARN] Not a valid specifying action, so that action is ignored") 123 return `` 124 } 125 126 return fmt.Sprintf(` /*+ %s(%s %s)*/ `, hint, tableName, strings.Join(s, `,`)) 127 } 128 129 // execute insert sql with given struct and given values. 130 // insert the given values, not the field values in struct. 131 func (d *dbBaseOracle) InsertValue(ctx context.Context, q dbQuerier, mi *modelInfo, isMulti bool, names []string, values []interface{}) (int64, error) { 132 Q := d.ins.TableQuote() 133 134 marks := make([]string, len(names)) 135 for i := range marks { 136 marks[i] = ":" + names[i] 137 } 138 139 sep := fmt.Sprintf("%s, %s", Q, Q) 140 qmarks := strings.Join(marks, ", ") 141 columns := strings.Join(names, sep) 142 143 multi := len(values) / len(names) 144 145 if isMulti { 146 qmarks = strings.Repeat(qmarks+"), (", multi-1) + qmarks 147 } 148 149 query := fmt.Sprintf("INSERT INTO %s%s%s (%s%s%s) VALUES (%s)", Q, mi.table, Q, Q, columns, Q, qmarks) 150 151 d.ins.ReplaceMarks(&query) 152 153 if isMulti || !d.ins.HasReturningID(mi, &query) { 154 res, err := q.ExecContext(ctx, query, values...) 155 if err == nil { 156 if isMulti { 157 return res.RowsAffected() 158 } 159 160 lastInsertId, err := res.LastInsertId() 161 if err != nil { 162 DebugLog.Println(ErrLastInsertIdUnavailable, ':', err) 163 return lastInsertId, ErrLastInsertIdUnavailable 164 } else { 165 return lastInsertId, nil 166 } 167 } 168 return 0, err 169 } 170 row := q.QueryRowContext(ctx, query, values...) 171 var id int64 172 err := row.Scan(&id) 173 return id, err 174 }