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  }