fix(sap): normalize deprecated/removed data types in SAP HANA Cloud (#11356)

* fix(sap): SAP HANA Cloud data types

* fix(sap): fall back to regular index when fulltext is not supported

* fix: remove dead code
This commit is contained in:
Lucian Mocanu 2025-04-01 20:54:54 +02:00 committed by GitHub
parent 863caf1471
commit 460ef023ba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 152 additions and 76 deletions

View File

@ -13,6 +13,7 @@
- [Column types for `sqlite` / `cordova` / `react-native` / `expo`](#column-types-for-sqlite--cordova--react-native--expo)
- [Column types for `mssql`](#column-types-for-mssql)
- [Column types for `oracle`](#column-types-for-oracle)
- [Column types for `sap`](#column-types-for-sap)
- [Column types for `spanner`](#column-types-for-spanner)
- [`enum` column type](#enum-column-type)
- [`set` column type](#set-column-type)
@ -380,7 +381,6 @@ or
> Note: UUID, INET4, and INET6 are only available for mariadb and for respective versions that made them available.
### Column types for `postgres`
`int`, `int2`, `int4`, `int8`, `smallint`, `integer`, `bigint`, `decimal`, `numeric`, `real`,
@ -425,6 +425,12 @@ or
`timestamp with local time zone`, `interval year to month`, `interval day to second`, `bfile`, `blob`, `clob`,
`nclob`, `rowid`, `urowid`
### Column types for `sap`
`tinyint`, `smallint`, `integer`, `bigint`, `smalldecimal`, `decimal`, `real`, `double`, `date`, `time`, `seconddate`, `timestamp`, `boolean`, `char`, `nchar`, `varchar`, `nvarchar`, `text`, `alphanum`, `shorttext`, `array`, `varbinary`, `blob`, `clob`, `nclob`, `st_geometry`, `st_point`.
> Note: SAP HANA Cloud deprecated or removed some of these data types. TypeORM will convert them to the closest available alternative when connected to a Cloud version.
### Column types for `spanner`
`bool`, `int64`, `float64`, `numeric`, `string`, `json`, `bytes`, `date`, `timestamp`, `array`

View File

@ -110,31 +110,31 @@ export class SapDriver implements Driver {
supportedDataTypes: ColumnType[] = [
"tinyint",
"smallint",
"int", // alias for "integer"
"int", // typeorm alias for "integer"
"integer",
"bigint",
"smalldecimal",
"decimal",
"dec", // alias for "decimal"
"dec", // typeorm alias for "decimal"
"real",
"double",
"float",
"float", // database alias for "real" / "double"
"date",
"time",
"seconddate",
"timestamp",
"boolean",
"char", // not officially supported
"char", // not officially supported, in SAP HANA Cloud: alias for "nchar"
"nchar", // not officially supported
"varchar", // deprecated
"varchar", // in SAP HANA Cloud: alias for "nvarchar"
"nvarchar",
"text", // deprecated
"alphanum", // deprecated
"shorttext", // deprecated
"text", // removed in SAP HANA Cloud
"alphanum", // removed in SAP HANA Cloud
"shorttext", // removed in SAP HANA Cloud
"array",
"varbinary",
"blob",
"clob", // deprecated
"clob", // in SAP HANA Cloud: alias for "nclob"
"nclob",
"st_geometry",
"st_point",
@ -571,6 +571,18 @@ export class SapDriver implements Driver {
return "integer"
} else if (column.type === "dec") {
return "decimal"
} else if (column.type === "float") {
const length =
typeof column.length === "string"
? parseInt(column.length)
: column.length
// https://help.sap.com/docs/SAP_HANA_PLATFORM/4fe29514fd584807ac9f2a04f6754767/4ee2f261e9c44003807d08ccc2e249ac.html
if (length && length < 25) {
return "real"
}
return "double"
} else if (column.type === String) {
return "nvarchar"
} else if (column.type === Date) {
@ -588,9 +600,24 @@ export class SapDriver implements Driver {
return "nclob"
} else if (column.type === "simple-enum") {
return "nvarchar"
} else {
return (column.type as string) || ""
}
if (DriverUtils.isReleaseVersionOrGreater(this, "4.0")) {
// SAP HANA Cloud deprecated / removed these data types
if (
column.type === "varchar" ||
column.type === "alphanum" ||
column.type === "shorttext"
) {
return "nvarchar"
} else if (column.type === "text" || column.type === "clob") {
return "nclob"
} else if (column.type === "char") {
return "nchar"
}
}
return (column.type as string) || ""
}
/**
@ -747,26 +774,12 @@ export class SapDriver implements Driver {
const tableColumn = tableColumns.find(
(c) => c.name === columnMetadata.databaseName,
)
if (!tableColumn) return false // we don't need new columns, we only need exist and changed
if (!tableColumn) {
// we don't need new columns, we only need exist and changed
return false
}
// console.log("table:", columnMetadata.entityMetadata.tableName);
// console.log("name:", tableColumn.name, columnMetadata.databaseName);
// console.log("type:", tableColumn.type, _this.normalizeType(columnMetadata));
// console.log("length:", tableColumn.length, _this.getColumnLength(columnMetadata));
// console.log("width:", tableColumn.width, columnMetadata.width);
// console.log("precision:", tableColumn.precision, columnMetadata.precision);
// console.log("scale:", tableColumn.scale, columnMetadata.scale);
// console.log("default:", tableColumn.default, columnMetadata.default);
// console.log("isPrimary:", tableColumn.isPrimary, columnMetadata.isPrimary);
// console.log("isNullable:", tableColumn.isNullable, columnMetadata.isNullable);
// console.log("isUnique:", tableColumn.isUnique, _this.normalizeIsUnique(columnMetadata));
// console.log("isGenerated:", tableColumn.isGenerated, columnMetadata.isGenerated);
// console.log((columnMetadata.generationStrategy !== "uuid" && tableColumn.isGenerated !== columnMetadata.isGenerated));
// console.log("==========================================");
const normalizeDefault = this.normalizeDefault(columnMetadata)
const hanaNullComapatibleDefault =
normalizeDefault == null ? undefined : normalizeDefault
const normalizedDefault = this.normalizeDefault(columnMetadata)
return (
tableColumn.name !== columnMetadata.databaseName ||
@ -779,7 +792,7 @@ export class SapDriver implements Driver {
tableColumn.comment !==
this.escapeComment(columnMetadata.comment) ||
(!tableColumn.isGenerated &&
hanaNullComapatibleDefault !== tableColumn.default) || // we included check for generated here, because generated columns already can have default values
normalizedDefault !== tableColumn.default) || // we included check for generated here, because generated columns already can have default values
tableColumn.isPrimary !== columnMetadata.isPrimary ||
tableColumn.isNullable !== columnMetadata.isNullable ||
tableColumn.isUnique !==
@ -808,7 +821,7 @@ export class SapDriver implements Driver {
* Returns true if driver supports fulltext indices.
*/
isFullTextColumnTypeSupported(): boolean {
return true
return !DriverUtils.isReleaseVersionOrGreater(this, "4.0")
}
/**

View File

@ -2788,12 +2788,6 @@ export class SapQueryRunner extends BaseQueryRunner implements QueryRunner {
if (dbColumn["COMMENTS"]) {
tableColumn.comment = dbColumn["COMMENTS"]
}
if (dbColumn["character_set_name"])
tableColumn.charset =
dbColumn["character_set_name"]
if (dbColumn["collation_name"])
tableColumn.collation =
dbColumn["collation_name"]
return tableColumn
}),
)
@ -3153,7 +3147,7 @@ export class SapQueryRunner extends BaseQueryRunner implements QueryRunner {
if (index.isUnique) {
indexType += "UNIQUE "
}
if (index.isFulltext) {
if (index.isFulltext && this.driver.isFullTextColumnTypeSupported()) {
indexType += "FULLTEXT "
}
@ -3349,8 +3343,6 @@ export class SapQueryRunner extends BaseQueryRunner implements QueryRunner {
) {
let c =
`"${column.name}" ` + this.connection.driver.createFullType(column)
if (column.charset) c += " CHARACTER SET " + column.charset
if (column.collation) c += " COLLATE " + column.collation
if (column.default !== undefined && column.default !== null) {
c += " DEFAULT " + column.default
} else if (explicitDefault) {

View File

@ -1,12 +1,13 @@
import "reflect-metadata"
import { expect } from "chai"
import { Post } from "./entity/Post"
import "reflect-metadata"
import { DataSource } from "../../../../../src"
import {
closeTestingConnections,
createTestingConnections,
reloadTestingDatabases,
} from "../../../../utils/test-utils"
import { Post } from "./entity/Post"
describe("database schema > column length > sap", () => {
let connections: DataSource[]

View File

@ -1,14 +1,16 @@
import "reflect-metadata"
import { Post } from "./entity/Post"
import { DataSource } from "../../../../../src"
import { DriverUtils } from "../../../../../src/driver/DriverUtils"
import { DateUtils } from "../../../../../src/util/DateUtils"
import {
closeTestingConnections,
createTestingConnections,
reloadTestingDatabases,
} from "../../../../utils/test-utils"
import { Post } from "./entity/Post"
import { PostWithOptions } from "./entity/PostWithOptions"
import { PostWithoutTypes } from "./entity/PostWithoutTypes"
import { DateUtils } from "../../../../../src/util/DateUtils"
describe("database schema > column types > sap", () => {
let connections: DataSource[]
@ -144,21 +146,10 @@ describe("database schema > column types > sap", () => {
.findColumnByName("double")!
.type.should.be.equal("double")
table!.findColumnByName("float")!.type.should.be.equal("double")
table!.findColumnByName("char")!.type.should.be.equal("char")
table!.findColumnByName("nchar")!.type.should.be.equal("nchar")
table!
.findColumnByName("varchar")!
.type.should.be.equal("varchar")
table!
.findColumnByName("nvarchar")!
.type.should.be.equal("nvarchar")
table!
.findColumnByName("alphanum")!
.type.should.be.equal("alphanum")
table!.findColumnByName("text")!.type.should.be.equal("text")
table!
.findColumnByName("shorttext")!
.type.should.be.equal("shorttext")
table!.findColumnByName("dateObj")!.type.should.be.equal("date")
table!.findColumnByName("date")!.type.should.be.equal("date")
table!.findColumnByName("timeObj")!.type.should.be.equal("time")
@ -170,7 +161,6 @@ describe("database schema > column types > sap", () => {
.findColumnByName("seconddate")!
.type.should.be.equal("seconddate")
table!.findColumnByName("blob")!.type.should.be.equal("blob")
table!.findColumnByName("clob")!.type.should.be.equal("clob")
table!.findColumnByName("nclob")!.type.should.be.equal("nclob")
table!
.findColumnByName("boolean")!
@ -181,6 +171,52 @@ describe("database schema > column types > sap", () => {
table!
.findColumnByName("simpleArray")!
.type.should.be.equal("nclob")
// Deprecated column types that have a different behavior in SAP HANA Cloud
if (
DriverUtils.isReleaseVersionOrGreater(
connection.driver,
"4.0",
)
) {
table!
.findColumnByName("char")!
.type.should.be.equal("nchar")
table!
.findColumnByName("varchar")!
.type.should.be.equal("nvarchar")
table!
.findColumnByName("alphanum")!
.type.should.be.equal("nvarchar")
table!
.findColumnByName("shorttext")!
.type.should.be.equal("nvarchar")
table!
.findColumnByName("text")!
.type.should.be.equal("nclob")
table!
.findColumnByName("clob")!
.type.should.be.equal("nclob")
} else {
table!
.findColumnByName("char")!
.type.should.be.equal("char")
table!
.findColumnByName("varchar")!
.type.should.be.equal("varchar")
table!
.findColumnByName("alphanum")!
.type.should.be.equal("alphanum")
table!
.findColumnByName("shorttext")!
.type.should.be.equal("shorttext")
table!
.findColumnByName("text")!
.type.should.be.equal("text")
table!
.findColumnByName("clob")!
.type.should.be.equal("clob")
}
}),
))
@ -224,30 +260,58 @@ describe("database schema > column types > sap", () => {
.findColumnByName("decimal")!
.precision!.should.be.equal(10)
table!.findColumnByName("decimal")!.scale!.should.be.equal(3)
table!
.findColumnByName("varchar")!
.type.should.be.equal("varchar")
table!
.findColumnByName("varchar")!
.length!.should.be.equal("50")
table!
.findColumnByName("nvarchar")!
.type.should.be.equal("nvarchar")
table!
.findColumnByName("nvarchar")!
.length!.should.be.equal("50")
table!
.findColumnByName("alphanum")!
.type.should.be.equal("alphanum")
table!
.findColumnByName("alphanum")!
.length!.should.be.equal("50")
table!
.findColumnByName("shorttext")!
.type.should.be.equal("shorttext")
table!
.findColumnByName("shorttext")!
.length!.should.be.equal("50")
// Deprecated column types that have a different behavior in SAP HANA Cloud
if (
DriverUtils.isReleaseVersionOrGreater(
connection.driver,
"4.0",
)
) {
table!
.findColumnByName("varchar")!
.type.should.be.equal("nvarchar")
table!
.findColumnByName("varchar")!
.length!.should.be.equal("50")
table!
.findColumnByName("alphanum")!
.type.should.be.equal("nvarchar")
table!
.findColumnByName("alphanum")!
.length!.should.be.equal("50")
table!
.findColumnByName("shorttext")!
.type.should.be.equal("nvarchar")
table!
.findColumnByName("shorttext")!
.length!.should.be.equal("50")
} else {
table!
.findColumnByName("varchar")!
.type.should.be.equal("varchar")
table!
.findColumnByName("varchar")!
.length!.should.be.equal("50")
table!
.findColumnByName("alphanum")!
.type.should.be.equal("alphanum")
table!
.findColumnByName("alphanum")!
.length!.should.be.equal("50")
table!
.findColumnByName("shorttext")!
.type.should.be.equal("shorttext")
table!
.findColumnByName("shorttext")!
.length!.should.be.equal("50")
}
}),
))