2024-01-30 20:03:58 +08:00
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package dm
import (
"context"
"fmt"
"strings"
2025-12-03 17:52:05 +08:00
"github.com/gogf/gf/v2/container/gmap"
2024-01-30 20:03:58 +08:00
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/util/gutil"
)
2025-12-03 17:52:05 +08:00
// escapeSingleQuote escapes single quotes in the string to prevent SQL injection.
// In SQL, single quotes are escaped by doubling them (two single quotes).
func escapeSingleQuote ( s string ) string {
return strings . ReplaceAll ( s , "'" , "''" )
}
2024-01-30 20:03:58 +08:00
const (
feat(contrib/drivers/dm): add `Replace/InsertIgnore` support and field type/length enhancements for dm database (#4541)
This pull request introduces significant improvements to the DM database
driver, especially around insert operations, and refines documentation
and tests to reflect these changes. The main focus is enabling support
for "replace" and "insert ignore" operations using DM's `MERGE`
statement, improving type reporting for table fields, and updating
documentation for clarity and accuracy.
### DM Driver Insert Operations
* Added support for `Replace` and `InsertIgnore` operations in the DM
driver by internally mapping them to DM's `MERGE` statement. This
enables upsert and insert-ignore behavior for DM databases, improving
compatibility with other drivers.
* Implemented helper methods (`doMergeInsert`, `doInsertIgnore`, and
`getPrimaryKeys`) to generate correct `MERGE` SQL statements and
automatically detect primary keys when needed.
[[1]](diffhunk://#diff-f51b30e3f0b0f1284b905385a89992efd0de2fe9ff8c5a4062344dfab17d428eL31-R94)
[[2]](diffhunk://#diff-f51b30e3f0b0f1284b905385a89992efd0de2fe9ff8c5a4062344dfab17d428eL115-R212)
* Updated the logic for building update values and SQL generation to
ensure correct behavior for both upsert and insert-ignore cases.
[[1]](diffhunk://#diff-f51b30e3f0b0f1284b905385a89992efd0de2fe9ff8c5a4062344dfab17d428eL61-R109)
[[2]](diffhunk://#diff-f51b30e3f0b0f1284b905385a89992efd0de2fe9ff8c5a4062344dfab17d428eL89-R132)
[[3]](diffhunk://#diff-f51b30e3f0b0f1284b905385a89992efd0de2fe9ff8c5a4062344dfab17d428eL100-R144)
[[4]](diffhunk://#diff-f51b30e3f0b0f1284b905385a89992efd0de2fe9ff8c5a4062344dfab17d428eL115-R212)
### Table Field Type Reporting
* Improved the DM driver's `TableFields` method to report column types
with length/precision (e.g., `VARCHAR(128)` instead of just `VARCHAR`),
aligning with expectations and other drivers.
[[1]](diffhunk://#diff-40a365112421ae1967bd960f8acefcc91ddb8180865b78bc49cd090fbf4883daL26-R26)
[[2]](diffhunk://#diff-40a365112421ae1967bd960f8acefcc91ddb8180865b78bc49cd090fbf4883daR88-R105)
* Updated related unit tests to expect the new type format for DM table
fields.
### Documentation Updates
* Removed outdated or redundant documentation in both English and
Chinese driver README files, and clarified supported features and
limitations for DM and other drivers.
[[1]](diffhunk://#diff-d49f5bc3a34b11a6ccb82cc54675b06a7dea5f0a943ae91c4ca0d28bd5003299L1)
[[2]](diffhunk://#diff-d49f5bc3a34b11a6ccb82cc54675b06a7dea5f0a943ae91c4ca0d28bd5003299L47-R46)
[[3]](diffhunk://#diff-d49f5bc3a34b11a6ccb82cc54675b06a7dea5f0a943ae91c4ca0d28bd5003299L119-L122)
[[4]](diffhunk://#diff-05411a14e9c7ca235f7f436bfde732853aa93b364361fe80d65ac768f4e4d613L1-L126)
### Test Suite Enhancements
* Refactored and restored unit tests for DM driver insert operations,
including tests for `Save`, `Insert`, and the new `InsertIgnore`
functionality to ensure correct behavior and compatibility.
[[1]](diffhunk://#diff-2b1a59b8b2adaa1ca3074629374ab122929e4d4fbb4cc794b8e1db60ebf8d4c2L143-L245)
[[2]](diffhunk://#diff-2b1a59b8b2adaa1ca3074629374ab122929e4d4fbb4cc794b8e1db60ebf8d4c2R512-R632)
* Minor adjustments to DM test initialization for improved clarity.
### Core Insert Logic Minor Refactoring
* Minor variable renaming for clarity in the core insert logic
(`gdb_core.go`), improving code readability.
[[1]](diffhunk://#diff-b1bbe5e3995261813e4e0ac6ffee8a37c236eaa2759f2bd82e211711695a70bcL449-R452)
[[2]](diffhunk://#diff-b1bbe5e3995261813e4e0ac6ffee8a37c236eaa2759f2bd82e211711695a70bcL466-R474)
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-04 20:12:12 +08:00
tableFieldsSqlTmp = ` SELECT c.COLUMN_NAME, c.DATA_TYPE, c.DATA_LENGTH, c.DATA_DEFAULT, c.NULLABLE, cc.COMMENTS FROM ALL_TAB_COLUMNS c LEFT JOIN ALL_COL_COMMENTS cc ON c.COLUMN_NAME = cc.COLUMN_NAME AND c.TABLE_NAME = cc.TABLE_NAME AND c.OWNER = cc.OWNER WHERE c.TABLE_NAME = '%s' AND c.OWNER = '%s' `
2025-12-03 17:52:05 +08:00
tableFieldsPkSqlSchemaTmp = ` SELECT COLS.COLUMN_NAME AS PRIMARY_KEY_COLUMN FROM USER_CONSTRAINTS CONS JOIN USER_CONS_COLUMNS COLS ON CONS.CONSTRAINT_NAME = COLS.CONSTRAINT_NAME WHERE CONS.TABLE_NAME = '%s' AND CONS.CONSTRAINT_TYPE = 'P' `
tableFieldsPkSqlDBATmp = ` SELECT COLS.COLUMN_NAME AS PRIMARY_KEY_COLUMN FROM DBA_CONSTRAINTS CONS JOIN DBA_CONS_COLUMNS COLS ON CONS.CONSTRAINT_NAME = COLS.CONSTRAINT_NAME WHERE CONS.TABLE_NAME = '%s' AND CONS.OWNER = '%s' AND CONS.CONSTRAINT_TYPE = 'P' `
2024-01-30 20:03:58 +08:00
)
// TableFields retrieves and returns the fields' information of specified table of current schema.
func ( d * Driver ) TableFields (
ctx context . Context , table string , schema ... string ,
) ( fields map [ string ] * gdb . TableField , err error ) {
var (
2025-12-03 17:52:05 +08:00
result gdb . Result
pkResult gdb . Result
link gdb . Link
2024-01-30 20:03:58 +08:00
// When no schema is specified, the configuration item is returned by default
usedSchema = gutil . GetOrDefaultStr ( d . GetSchema ( ) , schema ... )
)
// When usedSchema is empty, return the default link
if link , err = d . SlaveLink ( usedSchema ) ; err != nil {
return nil , err
}
// The link has been distinguished and no longer needs to judge the owner
result , err = d . DoSelect (
ctx , link ,
fmt . Sprintf (
tableFieldsSqlTmp ,
2025-12-03 17:52:05 +08:00
escapeSingleQuote ( strings . ToUpper ( table ) ) ,
escapeSingleQuote ( strings . ToUpper ( d . GetSchema ( ) ) ) ,
2024-01-30 20:03:58 +08:00
) ,
)
if err != nil {
return nil , err
}
2025-12-03 17:52:05 +08:00
// Query the primary key field
pkResult , err = d . DoSelect (
ctx , link ,
fmt . Sprintf ( tableFieldsPkSqlSchemaTmp , escapeSingleQuote ( strings . ToUpper ( table ) ) ) ,
)
if err != nil {
return nil , err
}
if pkResult . IsEmpty ( ) {
pkResult , err = d . DoSelect (
ctx , link ,
fmt . Sprintf ( tableFieldsPkSqlDBATmp , escapeSingleQuote ( strings . ToUpper ( table ) ) , escapeSingleQuote ( strings . ToUpper ( d . GetSchema ( ) ) ) ) ,
)
if err != nil {
return nil , err
}
}
2024-01-30 20:03:58 +08:00
fields = make ( map [ string ] * gdb . TableField )
2025-12-03 17:52:05 +08:00
pkFields := gmap . NewStrStrMap ( )
for _ , pk := range pkResult {
pkFields . Set ( pk [ "PRIMARY_KEY_COLUMN" ] . String ( ) , "PRI" )
}
2024-01-30 20:03:58 +08:00
for i , m := range result {
// m[NULLABLE] returns "N" "Y"
// "N" means not null
// "Y" means could be null
var nullable bool
if m [ "NULLABLE" ] . String ( ) != "N" {
nullable = true
}
feat(contrib/drivers/dm): add `Replace/InsertIgnore` support and field type/length enhancements for dm database (#4541)
This pull request introduces significant improvements to the DM database
driver, especially around insert operations, and refines documentation
and tests to reflect these changes. The main focus is enabling support
for "replace" and "insert ignore" operations using DM's `MERGE`
statement, improving type reporting for table fields, and updating
documentation for clarity and accuracy.
### DM Driver Insert Operations
* Added support for `Replace` and `InsertIgnore` operations in the DM
driver by internally mapping them to DM's `MERGE` statement. This
enables upsert and insert-ignore behavior for DM databases, improving
compatibility with other drivers.
* Implemented helper methods (`doMergeInsert`, `doInsertIgnore`, and
`getPrimaryKeys`) to generate correct `MERGE` SQL statements and
automatically detect primary keys when needed.
[[1]](diffhunk://#diff-f51b30e3f0b0f1284b905385a89992efd0de2fe9ff8c5a4062344dfab17d428eL31-R94)
[[2]](diffhunk://#diff-f51b30e3f0b0f1284b905385a89992efd0de2fe9ff8c5a4062344dfab17d428eL115-R212)
* Updated the logic for building update values and SQL generation to
ensure correct behavior for both upsert and insert-ignore cases.
[[1]](diffhunk://#diff-f51b30e3f0b0f1284b905385a89992efd0de2fe9ff8c5a4062344dfab17d428eL61-R109)
[[2]](diffhunk://#diff-f51b30e3f0b0f1284b905385a89992efd0de2fe9ff8c5a4062344dfab17d428eL89-R132)
[[3]](diffhunk://#diff-f51b30e3f0b0f1284b905385a89992efd0de2fe9ff8c5a4062344dfab17d428eL100-R144)
[[4]](diffhunk://#diff-f51b30e3f0b0f1284b905385a89992efd0de2fe9ff8c5a4062344dfab17d428eL115-R212)
### Table Field Type Reporting
* Improved the DM driver's `TableFields` method to report column types
with length/precision (e.g., `VARCHAR(128)` instead of just `VARCHAR`),
aligning with expectations and other drivers.
[[1]](diffhunk://#diff-40a365112421ae1967bd960f8acefcc91ddb8180865b78bc49cd090fbf4883daL26-R26)
[[2]](diffhunk://#diff-40a365112421ae1967bd960f8acefcc91ddb8180865b78bc49cd090fbf4883daR88-R105)
* Updated related unit tests to expect the new type format for DM table
fields.
### Documentation Updates
* Removed outdated or redundant documentation in both English and
Chinese driver README files, and clarified supported features and
limitations for DM and other drivers.
[[1]](diffhunk://#diff-d49f5bc3a34b11a6ccb82cc54675b06a7dea5f0a943ae91c4ca0d28bd5003299L1)
[[2]](diffhunk://#diff-d49f5bc3a34b11a6ccb82cc54675b06a7dea5f0a943ae91c4ca0d28bd5003299L47-R46)
[[3]](diffhunk://#diff-d49f5bc3a34b11a6ccb82cc54675b06a7dea5f0a943ae91c4ca0d28bd5003299L119-L122)
[[4]](diffhunk://#diff-05411a14e9c7ca235f7f436bfde732853aa93b364361fe80d65ac768f4e4d613L1-L126)
### Test Suite Enhancements
* Refactored and restored unit tests for DM driver insert operations,
including tests for `Save`, `Insert`, and the new `InsertIgnore`
functionality to ensure correct behavior and compatibility.
[[1]](diffhunk://#diff-2b1a59b8b2adaa1ca3074629374ab122929e4d4fbb4cc794b8e1db60ebf8d4c2L143-L245)
[[2]](diffhunk://#diff-2b1a59b8b2adaa1ca3074629374ab122929e4d4fbb4cc794b8e1db60ebf8d4c2R512-R632)
* Minor adjustments to DM test initialization for improved clarity.
### Core Insert Logic Minor Refactoring
* Minor variable renaming for clarity in the core insert logic
(`gdb_core.go`), improving code readability.
[[1]](diffhunk://#diff-b1bbe5e3995261813e4e0ac6ffee8a37c236eaa2759f2bd82e211711695a70bcL449-R452)
[[2]](diffhunk://#diff-b1bbe5e3995261813e4e0ac6ffee8a37c236eaa2759f2bd82e211711695a70bcL466-R474)
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-04 20:12:12 +08:00
// Build field type with length/precision
// For NUMBER(p,s): use DATA_PRECISION and DATA_SCALE
// For VARCHAR2/CHAR: use DATA_LENGTH
var (
fieldType string
dataType = m [ "DATA_TYPE" ] . String ( )
dataLength = m [ "DATA_LENGTH" ] . Int ( )
)
if dataLength > 0 {
fieldType = fmt . Sprintf ( "%s(%d)" , dataType , dataLength )
} else {
fieldType = dataType
}
2024-01-30 20:03:58 +08:00
fields [ m [ "COLUMN_NAME" ] . String ( ) ] = & gdb . TableField {
Index : i ,
Name : m [ "COLUMN_NAME" ] . String ( ) ,
feat(contrib/drivers/dm): add `Replace/InsertIgnore` support and field type/length enhancements for dm database (#4541)
This pull request introduces significant improvements to the DM database
driver, especially around insert operations, and refines documentation
and tests to reflect these changes. The main focus is enabling support
for "replace" and "insert ignore" operations using DM's `MERGE`
statement, improving type reporting for table fields, and updating
documentation for clarity and accuracy.
### DM Driver Insert Operations
* Added support for `Replace` and `InsertIgnore` operations in the DM
driver by internally mapping them to DM's `MERGE` statement. This
enables upsert and insert-ignore behavior for DM databases, improving
compatibility with other drivers.
* Implemented helper methods (`doMergeInsert`, `doInsertIgnore`, and
`getPrimaryKeys`) to generate correct `MERGE` SQL statements and
automatically detect primary keys when needed.
[[1]](diffhunk://#diff-f51b30e3f0b0f1284b905385a89992efd0de2fe9ff8c5a4062344dfab17d428eL31-R94)
[[2]](diffhunk://#diff-f51b30e3f0b0f1284b905385a89992efd0de2fe9ff8c5a4062344dfab17d428eL115-R212)
* Updated the logic for building update values and SQL generation to
ensure correct behavior for both upsert and insert-ignore cases.
[[1]](diffhunk://#diff-f51b30e3f0b0f1284b905385a89992efd0de2fe9ff8c5a4062344dfab17d428eL61-R109)
[[2]](diffhunk://#diff-f51b30e3f0b0f1284b905385a89992efd0de2fe9ff8c5a4062344dfab17d428eL89-R132)
[[3]](diffhunk://#diff-f51b30e3f0b0f1284b905385a89992efd0de2fe9ff8c5a4062344dfab17d428eL100-R144)
[[4]](diffhunk://#diff-f51b30e3f0b0f1284b905385a89992efd0de2fe9ff8c5a4062344dfab17d428eL115-R212)
### Table Field Type Reporting
* Improved the DM driver's `TableFields` method to report column types
with length/precision (e.g., `VARCHAR(128)` instead of just `VARCHAR`),
aligning with expectations and other drivers.
[[1]](diffhunk://#diff-40a365112421ae1967bd960f8acefcc91ddb8180865b78bc49cd090fbf4883daL26-R26)
[[2]](diffhunk://#diff-40a365112421ae1967bd960f8acefcc91ddb8180865b78bc49cd090fbf4883daR88-R105)
* Updated related unit tests to expect the new type format for DM table
fields.
### Documentation Updates
* Removed outdated or redundant documentation in both English and
Chinese driver README files, and clarified supported features and
limitations for DM and other drivers.
[[1]](diffhunk://#diff-d49f5bc3a34b11a6ccb82cc54675b06a7dea5f0a943ae91c4ca0d28bd5003299L1)
[[2]](diffhunk://#diff-d49f5bc3a34b11a6ccb82cc54675b06a7dea5f0a943ae91c4ca0d28bd5003299L47-R46)
[[3]](diffhunk://#diff-d49f5bc3a34b11a6ccb82cc54675b06a7dea5f0a943ae91c4ca0d28bd5003299L119-L122)
[[4]](diffhunk://#diff-05411a14e9c7ca235f7f436bfde732853aa93b364361fe80d65ac768f4e4d613L1-L126)
### Test Suite Enhancements
* Refactored and restored unit tests for DM driver insert operations,
including tests for `Save`, `Insert`, and the new `InsertIgnore`
functionality to ensure correct behavior and compatibility.
[[1]](diffhunk://#diff-2b1a59b8b2adaa1ca3074629374ab122929e4d4fbb4cc794b8e1db60ebf8d4c2L143-L245)
[[2]](diffhunk://#diff-2b1a59b8b2adaa1ca3074629374ab122929e4d4fbb4cc794b8e1db60ebf8d4c2R512-R632)
* Minor adjustments to DM test initialization for improved clarity.
### Core Insert Logic Minor Refactoring
* Minor variable renaming for clarity in the core insert logic
(`gdb_core.go`), improving code readability.
[[1]](diffhunk://#diff-b1bbe5e3995261813e4e0ac6ffee8a37c236eaa2759f2bd82e211711695a70bcL449-R452)
[[2]](diffhunk://#diff-b1bbe5e3995261813e4e0ac6ffee8a37c236eaa2759f2bd82e211711695a70bcL466-R474)
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-04 20:12:12 +08:00
Type : fieldType ,
2024-01-30 20:03:58 +08:00
Null : nullable ,
Default : m [ "DATA_DEFAULT" ] . Val ( ) ,
2025-12-03 17:52:05 +08:00
Key : pkFields . Get ( m [ "COLUMN_NAME" ] . String ( ) ) ,
2024-01-30 20:03:58 +08:00
// Extra: m["Extra"].String(),
2025-12-03 17:52:05 +08:00
Comment : m [ "COMMENTS" ] . String ( ) ,
2024-01-30 20:03:58 +08:00
}
}
return fields , nil
}