Merge pull request #11047 from Budibase/feat/surface-sql-errors

Surface SQL errors
This commit is contained in:
Michael Drury 2023-06-28 18:16:26 +01:00 committed by GitHub
commit 64c6333f9b
4 changed files with 72 additions and 8 deletions

View File

@ -0,0 +1,32 @@
import { SourceName } from "@budibase/types"
const mysqlErrorMessages: Record<number, string> = {
1045: "Access denied for the specified user. User does not have the necessary privileges or the provided credentials are incorrect. Please verify the credentials, and ensure that the user has appropriate permissions.",
1049: "The specified database does not exist. Please verify that the database name is correct.",
}
const postgresErrorMessages: Record<string, string> = {
"23505": "Duplicate key value violates unique constraint.",
"23502": "Null value not allowed for a column.",
"23503": "Foreign key violation.",
"23514": "Check constraint violation.",
"42703": "Undefined column.",
"42P01": "Undefined table.",
}
const sqlServerErrorMessages: Record<number, string> = {
547: "The INSERT statement conflicted with the FOREIGN KEY constraint.",
2601: "Cannot insert duplicate key row in object.",
515: "Cannot insert the value NULL into column.",
}
export const getReadableErrorMessage = (type: string, errno: number) => {
switch (type) {
case SourceName.MYSQL:
return mysqlErrorMessages[errno]
case SourceName.POSTGRES:
return postgresErrorMessages[errno]
case SourceName.SQL_SERVER:
return sqlServerErrorMessages[errno]
}
}

View File

@ -10,6 +10,7 @@ import {
DatasourcePlus,
DatasourceFeature,
ConnectionInfo,
SourceName,
} from "@budibase/types"
import {
getSqlQuery,
@ -20,6 +21,7 @@ import {
} from "./utils"
import Sql from "./base/sql"
import { MSSQLTablesResponse, MSSQLColumn } from "./base/types"
import { getReadableErrorMessage } from "./base/errorMapping"
import sqlServer from "mssql"
const DEFAULT_SCHEMA = "dbo"
@ -252,9 +254,16 @@ class SqlServerIntegration extends Sql implements DatasourcePlus {
? `${query.sql}; SELECT SCOPE_IDENTITY() AS id;`
: query.sql
return await request.query(sql)
} catch (err) {
// @ts-ignore
throw new Error(err)
} catch (err: any) {
let readableMessage = getReadableErrorMessage(
SourceName.SQL_SERVER,
err.number
)
if (readableMessage) {
throw new Error(readableMessage)
} else {
throw new Error(err.message as string)
}
}
}

View File

@ -9,6 +9,7 @@ import {
DatasourcePlus,
DatasourceFeature,
ConnectionInfo,
SourceName,
} from "@budibase/types"
import {
getSqlQuery,
@ -21,7 +22,7 @@ import dayjs from "dayjs"
import { NUMBER_REGEX } from "../utilities"
import Sql from "./base/sql"
import { MySQLColumn } from "./base/types"
import { getReadableErrorMessage } from "./base/errorMapping"
import mysql from "mysql2/promise"
interface MySQLConfig extends mysql.ConnectionOptions {
@ -175,7 +176,12 @@ class MySQLIntegration extends Sql implements DatasourcePlus {
)
response.connected = result?.checkRes == 2
} catch (e: any) {
response.error = e.message as string
let readableMessage = getReadableErrorMessage(SourceName.MYSQL, e.errno)
if (readableMessage) {
response.error = readableMessage
} else {
response.error = e.message as string
}
}
return response
}
@ -214,6 +220,13 @@ class MySQLIntegration extends Sql implements DatasourcePlus {
// Node MySQL is callback based, so we must wrap our call in a promise
const response = await this.client!.query(query.sql, bindings)
return response[0]
} catch (err: any) {
let readableMessage = getReadableErrorMessage(SourceName.MYSQL, err.errno)
if (readableMessage) {
throw new Error(readableMessage)
} else {
throw new Error(err.message as string)
}
} finally {
if (opts?.connect && this.client) {
await this.disconnect()

View File

@ -9,6 +9,7 @@ import {
DatasourcePlus,
DatasourceFeature,
ConnectionInfo,
SourceName,
} from "@budibase/types"
import {
getSqlQuery,
@ -22,6 +23,7 @@ import { PostgresColumn } from "./base/types"
import { escapeDangerousCharacters } from "../utilities"
import { Client, ClientConfig, types } from "pg"
import { getReadableErrorMessage } from "./base/errorMapping"
import { exec } from "child_process"
import { storeTempFile } from "../utilities/fileSystem"
@ -187,6 +189,7 @@ class PostgresIntegration extends Sql implements DatasourcePlus {
await this.openConnection()
response.connected = true
} catch (e: any) {
console.log(e)
response.error = e.message as string
} finally {
await this.closeConnection()
@ -245,10 +248,17 @@ class PostgresIntegration extends Sql implements DatasourcePlus {
}
try {
return await client.query(query.sql, query.bindings || [])
} catch (err) {
} catch (err: any) {
await this.closeConnection()
// @ts-ignore
throw new Error(err)
let readableMessage = getReadableErrorMessage(
SourceName.POSTGRES,
err.code
)
if (readableMessage) {
throw new Error(readableMessage)
} else {
throw new Error(err.message as string)
}
} finally {
if (close) {
await this.closeConnection()