node-ejs-renderer/node_modules/sequelize/lib/dialects/oracle/query-generator.js
2024-06-09 13:55:01 -04:00

939 lines
35 KiB
JavaScript

"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
var __export = (target, all) => {
__markAsModule(target);
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
__export(exports, {
OracleQueryGenerator: () => OracleQueryGenerator
});
const Utils = require("../../utils");
const DataTypes = require("../../data-types");
const AbstractQueryGenerator = require("../abstract/query-generator");
const _ = require("lodash");
const util = require("util");
const Transaction = require("../../transaction");
const ORACLE_RESERVED_WORDS = ["ACCESS", "ADD", "ALL", "ALTER", "AND", "ANY", "ARRAYLEN", "AS", "ASC", "AUDIT", "BETWEEN", "BY", "CHAR", "CHECK", "CLUSTER", "COLUMN", "COMMENT", "COMPRESS", "CONNECT", "CREATE", "CURRENT", "DATE", "DECIMAL", "DEFAULT", "DELETE", "DESC", "DISTINCT", "DROP", "ELSE", "EXCLUSIVE", "EXISTS", "FILE", "FLOAT", "FOR", "FROM", "GRANT", "GROUP", "HAVING", "IDENTIFIED", "IMMEDIATE", "IN", "INCREMENT", "INDEX", "INITIAL", "INSERT", "INTEGER", "INTERSECT", "INTO", "IS", "LEVEL", "LIKE", "LOCK", "LONG", "MAXEXTENTS", "MINUS", "MODE", "MODIFY", "NOAUDIT", "NOCOMPRESS", "NOT", "NOTFOUND", "NOWAIT", "NULL", "NUMBER", "OF", "OFFLINE", "ON", "ONLINE", "OPTION", "OR", "ORDER", "PCTFREE", "PRIOR", "PRIVILEGES", "PUBLIC", "RAW", "RENAME", "RESOURCE", "REVOKE", "ROW", "ROWID", "ROWLABEL", "ROWNUM", "ROWS", "SELECT", "SESSION", "SET", "SHARE", "SIZE", "SMALLINT", "SQLBUF", "START", "SUCCESSFUL", "SYNONYM", "SYSDATE", "TABLE", "THEN", "TO", "TRIGGER", "UID", "UNION", "UNIQUE", "UPDATE", "USER", "VALIDATE", "VALUES", "VARCHAR", "VARCHAR2", "VIEW", "WHENEVER", "WHERE", "WITH"];
const JSON_FUNCTION_REGEX = /^\s*((?:[a-z]+_){0,2}jsonb?(?:_[a-z]+){0,2})\([^)]*\)/i;
const JSON_OPERATOR_REGEX = /^\s*(->>?|@>|<@|\?[|&]?|\|{2}|#-)/i;
const TOKEN_CAPTURE_REGEX = /^\s*((?:([`"'])(?:(?!\2).|\2{2})*\2)|[\w\d\s]+|[().,;+-])/i;
class OracleQueryGenerator extends AbstractQueryGenerator {
constructor(options) {
super(options);
}
getCatalogName(value) {
if (value) {
if (this.options.quoteIdentifiers === false) {
const quotedValue = this.quoteIdentifier(value);
if (quotedValue === value) {
value = value.toUpperCase();
}
}
}
return value;
}
getSchemaNameAndTableName(table) {
const tableName = this.getCatalogName(table.tableName || table);
const schemaName = this.getCatalogName(table.schema);
return [tableName, schemaName];
}
createSchema(schema) {
const quotedSchema = this.quoteIdentifier(schema);
return [
"DECLARE",
"USER_FOUND BOOLEAN := FALSE;",
"BEGIN",
" BEGIN",
" EXECUTE IMMEDIATE ",
this.escape(`CREATE USER ${quotedSchema} IDENTIFIED BY 12345 DEFAULT TABLESPACE USERS`),
";",
" EXCEPTION WHEN OTHERS THEN",
" IF SQLCODE != -1920 THEN",
" RAISE;",
" ELSE",
" USER_FOUND := TRUE;",
" END IF;",
" END;",
" IF NOT USER_FOUND THEN",
" EXECUTE IMMEDIATE ",
this.escape(`GRANT "CONNECT" TO ${quotedSchema}`),
";",
" EXECUTE IMMEDIATE ",
this.escape(`GRANT CREATE TABLE TO ${quotedSchema}`),
";",
" EXECUTE IMMEDIATE ",
this.escape(`GRANT CREATE VIEW TO ${quotedSchema}`),
";",
" EXECUTE IMMEDIATE ",
this.escape(`GRANT CREATE ANY TRIGGER TO ${quotedSchema}`),
";",
" EXECUTE IMMEDIATE ",
this.escape(`GRANT CREATE ANY PROCEDURE TO ${quotedSchema}`),
";",
" EXECUTE IMMEDIATE ",
this.escape(`GRANT CREATE SEQUENCE TO ${quotedSchema}`),
";",
" EXECUTE IMMEDIATE ",
this.escape(`GRANT CREATE SYNONYM TO ${quotedSchema}`),
";",
" EXECUTE IMMEDIATE ",
this.escape(`ALTER USER ${quotedSchema} QUOTA UNLIMITED ON USERS`),
";",
" END IF;",
"END;"
].join(" ");
}
showSchemasQuery() {
return `SELECT USERNAME AS "schema_name" FROM ALL_USERS WHERE COMMON = ('NO') AND USERNAME != user`;
}
dropSchema(schema) {
return [
"BEGIN",
"EXECUTE IMMEDIATE ",
this.escape(`DROP USER ${this.quoteTable(schema)} CASCADE`),
";",
"EXCEPTION WHEN OTHERS THEN",
" IF SQLCODE != -1918 THEN",
" RAISE;",
" END IF;",
"END;"
].join(" ");
}
versionQuery() {
return "SELECT VERSION_FULL FROM PRODUCT_COMPONENT_VERSION WHERE PRODUCT LIKE 'Oracle%'";
}
createTableQuery(tableName, attributes, options) {
const primaryKeys = [], foreignKeys = Object.create(null), attrStr = [], checkStr = [];
const values = {
table: this.quoteTable(tableName)
};
for (let attr in attributes) {
if (!Object.prototype.hasOwnProperty.call(attributes, attr))
continue;
const dataType = attributes[attr];
attr = this.quoteIdentifier(attr);
if (dataType.includes("PRIMARY KEY")) {
primaryKeys.push(attr);
if (dataType.includes("REFERENCES")) {
const match = dataType.match(/^(.+) (REFERENCES.*)$/);
attrStr.push(`${attr} ${match[1].replace(/PRIMARY KEY/, "")}`);
foreignKeys[attr] = match[2];
} else {
attrStr.push(`${attr} ${dataType.replace(/PRIMARY KEY/, "").trim()}`);
}
} else if (dataType.includes("REFERENCES")) {
const match = dataType.match(/^(.+) (REFERENCES.*)$/);
attrStr.push(`${attr} ${match[1]}`);
foreignKeys[attr] = match[2];
} else {
attrStr.push(`${attr} ${dataType}`);
}
}
values["attributes"] = attrStr.join(", ");
const pkString = primaryKeys.map((pk) => this.quoteIdentifier(pk)).join(", ");
if (pkString.length > 0) {
values.attributes += `,PRIMARY KEY (${pkString})`;
}
for (const fkey in foreignKeys) {
if (!Object.prototype.hasOwnProperty.call(foreignKeys, fkey))
continue;
if (foreignKeys[fkey].indexOf("ON DELETE NO ACTION") > -1) {
foreignKeys[fkey] = foreignKeys[fkey].replace("ON DELETE NO ACTION", "");
}
values.attributes += `,FOREIGN KEY (${this.quoteIdentifier(fkey)}) ${foreignKeys[fkey]}`;
}
if (checkStr.length > 0) {
values.attributes += `, ${checkStr.join(", ")}`;
}
if (options && options.indexes && options.indexes.length > 0) {
const idxToDelete = [];
options.indexes.forEach((index, idx) => {
if ("unique" in index && (index.unique === true || index.unique.length > 0 && index.unique !== false)) {
const fields = index.fields.map((field) => {
if (typeof field === "string") {
return field;
}
return field.attribute;
});
let canContinue = true;
if (options.uniqueKeys) {
const keys = Object.keys(options.uniqueKeys);
for (let fieldIdx = 0; fieldIdx < keys.length; fieldIdx++) {
const currUnique = options.uniqueKeys[keys[fieldIdx]];
if (currUnique.fields.length === fields.length) {
for (let i = 0; i < currUnique.fields.length; i++) {
const field = currUnique.fields[i];
if (_.includes(fields, field)) {
canContinue = false;
} else {
canContinue = true;
break;
}
}
}
}
if (canContinue) {
const indexName = "name" in index ? index.name : "";
const constraintToAdd = {
name: indexName,
fields
};
if (!("uniqueKeys" in options)) {
options.uniqueKeys = {};
}
options.uniqueKeys[indexName] = constraintToAdd;
idxToDelete.push(idx);
} else {
idxToDelete.push(idx);
}
}
}
});
idxToDelete.forEach((idx) => {
options.indexes.splice(idx, 1);
});
}
if (options && !!options.uniqueKeys) {
_.each(options.uniqueKeys, (columns, indexName) => {
let canBeUniq = false;
primaryKeys.forEach((primaryKey) => {
primaryKey = primaryKey.replace(/"/g, "");
if (!_.includes(columns.fields, primaryKey)) {
canBeUniq = true;
}
});
columns.fields.forEach((field) => {
let currField = "";
if (!_.isString(field)) {
currField = field.attribute.replace(/[.,"\s]/g, "");
} else {
currField = field.replace(/[.,"\s]/g, "");
}
if (currField in attributes) {
if (attributes[currField].toUpperCase().indexOf("UNIQUE") > -1 && canBeUniq) {
const attrToReplace = attributes[currField].replace("UNIQUE", "");
values.attributes = values.attributes.replace(attributes[currField], attrToReplace);
}
}
});
if (canBeUniq) {
const index = options.uniqueKeys[columns.name];
delete options.uniqueKeys[columns.name];
indexName = indexName.replace(/[.,\s]/g, "");
columns.name = indexName;
options.uniqueKeys[indexName] = index;
if (indexName.length === 0) {
values.attributes += `,UNIQUE (${columns.fields.map((field) => this.quoteIdentifier(field)).join(", ")})`;
} else {
values.attributes += `, CONSTRAINT ${this.quoteIdentifier(indexName)} UNIQUE (${columns.fields.map((field) => this.quoteIdentifier(field)).join(", ")})`;
}
}
});
}
const query = Utils.joinSQLFragments([
"CREATE TABLE",
values.table,
`(${values.attributes})`
]);
return Utils.joinSQLFragments([
"BEGIN",
"EXECUTE IMMEDIATE",
`${this.escape(query)};`,
"EXCEPTION WHEN OTHERS THEN",
"IF SQLCODE != -955 THEN",
"RAISE;",
"END IF;",
"END;"
]);
}
tableExistsQuery(table) {
const [tableName, schemaName] = this.getSchemaNameAndTableName(table);
return `SELECT TABLE_NAME FROM ALL_TABLES WHERE TABLE_NAME = ${this.escape(tableName)} AND OWNER = ${table.schema ? this.escape(schemaName) : "USER"}`;
}
describeTableQuery(tableName, schema) {
const currTableName = this.getCatalogName(tableName.tableName || tableName);
schema = this.getCatalogName(schema);
return [
"SELECT atc.COLUMN_NAME, atc.DATA_TYPE, atc.DATA_LENGTH, atc.CHAR_LENGTH, atc.DEFAULT_LENGTH, atc.NULLABLE, ucc.constraint_type ",
"FROM all_tab_columns atc ",
"LEFT OUTER JOIN ",
"(SELECT acc.column_name, acc.table_name, ac.constraint_type FROM all_cons_columns acc INNER JOIN all_constraints ac ON acc.constraint_name = ac.constraint_name) ucc ",
"ON (atc.table_name = ucc.table_name AND atc.COLUMN_NAME = ucc.COLUMN_NAME) ",
schema ? `WHERE (atc.OWNER = ${this.escape(schema)}) ` : "WHERE atc.OWNER = USER ",
`AND (atc.TABLE_NAME = ${this.escape(currTableName)})`,
"ORDER BY atc.COLUMN_NAME, CONSTRAINT_TYPE DESC"
].join("");
}
renameTableQuery(before, after) {
return Utils.joinSQLFragments([
"ALTER TABLE",
this.quoteTable(before),
"RENAME TO",
this.quoteTable(after)
]);
}
showConstraintsQuery(table) {
const tableName = this.getCatalogName(table.tableName || table);
return `SELECT CONSTRAINT_NAME constraint_name FROM user_cons_columns WHERE table_name = ${this.escape(tableName)}`;
}
showTablesQuery() {
return `SELECT owner as table_schema, table_name, 0 as lvl FROM all_tables where OWNER IN(SELECT USERNAME AS "schema_name" FROM ALL_USERS WHERE ORACLE_MAINTAINED = 'N')`;
}
dropTableQuery(tableName) {
return Utils.joinSQLFragments([
"BEGIN ",
"EXECUTE IMMEDIATE 'DROP TABLE",
this.quoteTable(tableName),
"CASCADE CONSTRAINTS PURGE';",
"EXCEPTION WHEN OTHERS THEN",
" IF SQLCODE != -942 THEN",
" RAISE;",
" END IF;",
"END;"
]);
}
addIndexQuery(tableName, attributes, options, rawTablename) {
if (typeof tableName !== "string" && attributes.name) {
attributes.name = `${tableName.schema}.${attributes.name}`;
}
return super.addIndexQuery(tableName, attributes, options, rawTablename);
}
addConstraintQuery(tableName, options) {
options = options || {};
if (options.onUpdate) {
delete options.onUpdate;
}
if (options.onDelete && options.onDelete.toUpperCase() === "NO ACTION") {
delete options.onDelete;
}
const constraintSnippet = this.getConstraintSnippet(tableName, options);
tableName = this.quoteTable(tableName);
return `ALTER TABLE ${tableName} ADD ${constraintSnippet};`;
}
addColumnQuery(table, key, dataType) {
dataType.field = key;
const attribute = Utils.joinSQLFragments([
this.quoteIdentifier(key),
this.attributeToSQL(dataType, {
attributeName: key,
context: "addColumn"
})
]);
return Utils.joinSQLFragments([
"ALTER TABLE",
this.quoteTable(table),
"ADD",
attribute
]);
}
removeColumnQuery(tableName, attributeName) {
return Utils.joinSQLFragments([
"ALTER TABLE",
this.quoteTable(tableName),
"DROP COLUMN",
this.quoteIdentifier(attributeName),
";"
]);
}
_alterForeignKeyConstraint(definition, table, attributeName) {
const [tableName, schemaName] = this.getSchemaNameAndTableName(table);
const attributeNameConstant = this.escape(this.getCatalogName(attributeName));
const schemaNameConstant = table.schema ? this.escape(this.getCatalogName(schemaName)) : "USER";
const tableNameConstant = this.escape(this.getCatalogName(tableName));
const getConsNameQuery = [
"SELECT constraint_name INTO cons_name",
"FROM (",
" SELECT DISTINCT cc.owner, cc.table_name, cc.constraint_name, cc.column_name AS cons_columns",
" FROM all_cons_columns cc, all_constraints c",
" WHERE cc.owner = c.owner",
" AND cc.table_name = c.table_name",
" AND cc.constraint_name = c.constraint_name",
" AND c.constraint_type = 'R'",
" GROUP BY cc.owner, cc.table_name, cc.constraint_name, cc.column_name",
")",
"WHERE owner =",
schemaNameConstant,
"AND table_name =",
tableNameConstant,
"AND cons_columns =",
attributeNameConstant,
";"
].join(" ");
const secondQuery = Utils.joinSQLFragments([
`ALTER TABLE ${this.quoteIdentifier(tableName)}`,
"ADD FOREIGN KEY",
`(${this.quoteIdentifier(attributeName)})`,
definition.replace(/.+?(?=REFERENCES)/, "")
]);
return [
"BEGIN",
getConsNameQuery,
"EXCEPTION",
"WHEN NO_DATA_FOUND THEN",
" CONS_NAME := NULL;",
"END;",
"IF CONS_NAME IS NOT NULL THEN",
` EXECUTE IMMEDIATE 'ALTER TABLE ${this.quoteTable(table)} DROP CONSTRAINT "'||CONS_NAME||'"';`,
"END IF;",
`EXECUTE IMMEDIATE ${this.escape(secondQuery)};`
].join(" ");
}
_modifyQuery(definition, table, attributeName) {
const query = Utils.joinSQLFragments([
"ALTER TABLE",
this.quoteTable(table),
"MODIFY",
this.quoteIdentifier(attributeName),
definition
]);
const secondQuery = query.replace("NOT NULL", "").replace("NULL", "");
return [
"BEGIN",
`EXECUTE IMMEDIATE ${this.escape(query)};`,
"EXCEPTION",
"WHEN OTHERS THEN",
" IF SQLCODE = -1442 OR SQLCODE = -1451 THEN",
` EXECUTE IMMEDIATE ${this.escape(secondQuery)};`,
" ELSE",
" RAISE;",
" END IF;",
"END;"
].join(" ");
}
changeColumnQuery(table, attributes) {
const sql = [
"DECLARE",
"CONS_NAME VARCHAR2(200);",
"BEGIN"
];
for (const attributeName in attributes) {
if (!Object.prototype.hasOwnProperty.call(attributes, attributeName))
continue;
const definition = attributes[attributeName];
if (definition.match(/REFERENCES/)) {
sql.push(this._alterForeignKeyConstraint(definition, table, attributeName));
} else {
sql.push(this._modifyQuery(definition, table, attributeName));
}
}
sql.push("END;");
return sql.join(" ");
}
renameColumnQuery(tableName, attrBefore, attributes) {
const newName = Object.keys(attributes)[0];
return `ALTER TABLE ${this.quoteTable(tableName)} RENAME COLUMN ${this.quoteIdentifier(attrBefore)} TO ${this.quoteIdentifier(newName)}`;
}
populateInsertQueryReturnIntoBinds(returningModelAttributes, returnTypes, inbindLength, returnAttributes, options) {
const oracledb = this.sequelize.connectionManager.lib;
const outBindAttributes = Object.create(null);
const outbind = [];
const outbindParam = this.bindParam(outbind, inbindLength);
returningModelAttributes.forEach((element, index) => {
if (element.startsWith('"')) {
element = element.substring(1, element.length - 1);
}
outBindAttributes[element] = Object.assign(returnTypes[index]._getBindDef(oracledb), { dir: oracledb.BIND_OUT });
const returnAttribute = `${this.format(void 0, void 0, { context: "INSERT" }, outbindParam)}`;
returnAttributes.push(returnAttribute);
});
options.outBindAttributes = outBindAttributes;
}
upsertQuery(tableName, insertValues, updateValues, where, model, options) {
const rawAttributes = model.rawAttributes;
const updateQuery = this.updateQuery(tableName, updateValues, where, options, rawAttributes);
options.bind = updateQuery.bind;
const insertQuery = this.insertQuery(tableName, insertValues, rawAttributes, options);
const sql = [
"DECLARE ",
"BEGIN ",
updateQuery.query ? [
updateQuery.query,
"; ",
" IF ( SQL%ROWCOUNT = 0 ) THEN ",
insertQuery.query,
" :isUpdate := 0; ",
"ELSE ",
" :isUpdate := 1; ",
" END IF; "
].join("") : [
insertQuery.query,
" :isUpdate := 0; ",
"EXCEPTION WHEN OTHERS THEN",
" IF SQLCODE != -1 THEN",
" RAISE;",
" END IF;"
].join(""),
"END;"
];
const query = sql.join("");
const result = { query };
if (options.bindParam !== false) {
result.bind = updateQuery.bind || insertQuery.bind;
}
return result;
}
bulkInsertQuery(tableName, fieldValueHashes, options, fieldMappedAttributes) {
options = options || {};
options.executeMany = true;
fieldMappedAttributes = fieldMappedAttributes || {};
const tuples = [];
const allColumns = {};
const inBindBindDefMap = {};
const outBindBindDefMap = {};
const oracledb = this.sequelize.connectionManager.lib;
for (const fieldValueHash of fieldValueHashes) {
_.forOwn(fieldValueHash, (value, key) => {
allColumns[key] = fieldMappedAttributes[key] && fieldMappedAttributes[key].autoIncrement === true && value === null;
});
}
let inBindPosition;
for (const fieldValueHash of fieldValueHashes) {
const tuple = [];
const inbindParam = options.bindParam === void 0 ? this.bindParam(tuple) : options.bindParam;
const tempBindPositions = Object.keys(allColumns).map((key) => {
if (allColumns[key] === true) {
if (fieldValueHash[key] !== null) {
throw Error("For an auto-increment column either all row must be null or non-null, a mix of null and non-null is not allowed!");
}
return "DEFAULT";
}
return this.format(fieldValueHash[key], fieldMappedAttributes[key], { context: "INSERT" }, inbindParam);
});
if (!inBindPosition) {
inBindPosition = tempBindPositions;
}
tuples.push(tuple);
}
const returnColumn = [];
const returnColumnBindPositions = [];
const insertColumns = [];
for (const key of Object.keys(allColumns)) {
if (fieldMappedAttributes[key]) {
const bindDef = fieldMappedAttributes[key].type._getBindDef(oracledb);
if (allColumns[key]) {
bindDef.dir = oracledb.BIND_OUT;
outBindBindDefMap[key] = bindDef;
returnColumn.push(this.quoteIdentifier(key));
returnColumnBindPositions.push(`:${tuples[0].length + returnColumn.length}`);
} else {
bindDef.dir = oracledb.BIND_IN;
inBindBindDefMap[key] = bindDef;
}
}
insertColumns.push(this.quoteIdentifier(key));
}
let query = Utils.joinSQLFragments([
"INSERT",
"INTO",
this.quoteTable(tableName),
`(${insertColumns.join(",")})`,
"VALUES",
`(${inBindPosition})`
]);
if (returnColumn.length > 0) {
options.outBindAttributes = outBindBindDefMap;
query = Utils.joinSQLFragments([
query,
"RETURNING",
`${returnColumn.join(",")}`,
"INTO",
`${returnColumnBindPositions}`
]);
}
const result = { query };
result.bind = tuples;
options.inbindAttributes = inBindBindDefMap;
return result;
}
truncateTableQuery(tableName) {
return `TRUNCATE TABLE ${this.quoteTable(tableName)}`;
}
deleteQuery(tableName, where, options, model) {
options = options || {};
const table = tableName;
where = this.getWhereConditions(where, null, model, options);
let queryTmpl;
if (options.limit) {
const whereTmpl = where ? ` AND ${where}` : "";
queryTmpl = `DELETE FROM ${this.quoteTable(table)} WHERE rowid IN (SELECT rowid FROM ${this.quoteTable(table)} WHERE rownum <= ${this.escape(options.limit)}${whereTmpl})`;
} else {
const whereTmpl = where ? ` WHERE ${where}` : "";
queryTmpl = `DELETE FROM ${this.quoteTable(table)}${whereTmpl}`;
}
return queryTmpl;
}
showIndexesQuery(table) {
const [tableName, owner] = this.getSchemaNameAndTableName(table);
const sql = [
"SELECT i.index_name,i.table_name, i.column_name, u.uniqueness, i.descend, c.constraint_type ",
"FROM all_ind_columns i ",
"INNER JOIN all_indexes u ",
"ON (u.table_name = i.table_name AND u.index_name = i.index_name) ",
"LEFT OUTER JOIN all_constraints c ",
"ON (c.table_name = i.table_name AND c.index_name = i.index_name) ",
`WHERE i.table_name = ${this.escape(tableName)}`,
" AND u.table_owner = ",
owner ? this.escape(owner) : "USER",
" ORDER BY index_name, column_position"
];
return sql.join("");
}
removeIndexQuery(tableName, indexNameOrAttributes) {
let indexName = indexNameOrAttributes;
if (typeof indexName !== "string") {
indexName = Utils.underscore(`${tableName}_${indexNameOrAttributes.join("_")}`);
}
return `DROP INDEX ${this.quoteIdentifier(indexName)}`;
}
attributeToSQL(attribute, options) {
if (!_.isPlainObject(attribute)) {
attribute = {
type: attribute
};
}
attribute.onUpdate = "";
if (attribute.references) {
if (attribute.Model && attribute.Model.tableName === attribute.references.model) {
this.sequelize.log("Oracle does not support self referencial constraints, we will remove it but we recommend restructuring your query");
attribute.onDelete = "";
}
}
let template;
template = attribute.type.toSql ? attribute.type.toSql() : "";
if (attribute.type instanceof DataTypes.JSON) {
template += ` CHECK (${this.quoteIdentifier(options.attributeName)} IS JSON)`;
return template;
}
if (Utils.defaultValueSchemable(attribute.defaultValue)) {
template += ` DEFAULT ${this.escape(attribute.defaultValue)}`;
}
if (attribute.allowNull === false) {
template += " NOT NULL";
}
if (attribute.type instanceof DataTypes.ENUM) {
if (attribute.type.values && !attribute.values)
attribute.values = attribute.type.values;
template += ` CHECK (${this.quoteIdentifier(options.attributeName)} IN(${_.map(attribute.values, (value) => {
return this.escape(value);
}).join(", ")}))`;
return template;
}
if (attribute.type instanceof DataTypes.BOOLEAN) {
template += ` CHECK (${this.quoteIdentifier(options.attributeName)} IN('1', '0'))`;
return template;
}
if (attribute.autoIncrement) {
template = " NUMBER(*,0) GENERATED BY DEFAULT ON NULL AS IDENTITY";
} else if (attribute.type && attribute.type.key === DataTypes.DOUBLE.key) {
template = attribute.type.toSql();
} else if (attribute.type) {
let unsignedTemplate = "";
if (attribute.type._unsigned) {
attribute.type._unsigned = false;
unsignedTemplate += ` check(${this.quoteIdentifier(options.attributeName)} >= 0)`;
}
template = attribute.type.toString();
if (attribute.type && attribute.type !== "TEXT" && attribute.type._binary !== true && Utils.defaultValueSchemable(attribute.defaultValue)) {
template += ` DEFAULT ${this.escape(attribute.defaultValue)}`;
}
if (!attribute.autoIncrement) {
if (attribute.allowNull === false) {
template += " NOT NULL";
} else if (!attribute.primaryKey && !Utils.defaultValueSchemable(attribute.defaultValue)) {
template += " NULL";
}
}
template += unsignedTemplate;
} else {
template = "";
}
if (attribute.unique === true && !attribute.primaryKey) {
template += " UNIQUE";
}
if (attribute.primaryKey) {
template += " PRIMARY KEY";
}
if ((!options || !options.withoutForeignKeyConstraints) && attribute.references) {
template += ` REFERENCES ${this.quoteTable(attribute.references.model)}`;
if (attribute.references.key) {
template += ` (${this.quoteIdentifier(attribute.references.key)})`;
} else {
template += ` (${this.quoteIdentifier("id")})`;
}
if (attribute.onDelete && attribute.onDelete.toUpperCase() !== "NO ACTION") {
template += ` ON DELETE ${attribute.onDelete.toUpperCase()}`;
}
}
return template;
}
attributesToSQL(attributes, options) {
const result = {};
for (const key in attributes) {
const attribute = attributes[key];
const attributeName = attribute.field || key;
result[attributeName] = this.attributeToSQL(attribute, __spreadValues({ attributeName }, options));
}
return result;
}
createTrigger() {
throwMethodUndefined("createTrigger");
}
dropTrigger() {
throwMethodUndefined("dropTrigger");
}
renameTrigger() {
throwMethodUndefined("renameTrigger");
}
createFunction() {
throwMethodUndefined("createFunction");
}
dropFunction() {
throwMethodUndefined("dropFunction");
}
renameFunction() {
throwMethodUndefined("renameFunction");
}
getConstraintsOnColumn(table, column) {
const [tableName, schemaName] = this.getSchemaNameAndTableName(table);
column = this.getCatalogName(column);
const sql = [
"SELECT CONSTRAINT_NAME FROM user_cons_columns WHERE TABLE_NAME = ",
this.escape(tableName),
" and OWNER = ",
table.schema ? this.escape(schemaName) : "USER",
" and COLUMN_NAME = ",
this.escape(column),
" AND POSITION IS NOT NULL ORDER BY POSITION"
].join("");
return sql;
}
getForeignKeysQuery(table) {
const [tableName, schemaName] = this.getSchemaNameAndTableName(table);
const sql = [
'SELECT DISTINCT a.table_name "tableName", a.constraint_name "constraintName", a.owner "owner", a.column_name "columnName",',
' b.table_name "referencedTableName", b.column_name "referencedColumnName"',
" FROM all_cons_columns a",
" JOIN all_constraints c ON a.owner = c.owner AND a.constraint_name = c.constraint_name",
" JOIN all_cons_columns b ON c.owner = b.owner AND c.r_constraint_name = b.constraint_name",
" WHERE c.constraint_type = 'R'",
" AND a.table_name = ",
this.escape(tableName),
" AND a.owner = ",
table.schema ? this.escape(schemaName) : "USER",
" ORDER BY a.table_name, a.constraint_name"
].join("");
return sql;
}
dropForeignKeyQuery(tableName, foreignKey) {
return this.dropConstraintQuery(tableName, foreignKey);
}
getPrimaryKeyConstraintQuery(table) {
const [tableName, schemaName] = this.getSchemaNameAndTableName(table);
const sql = [
"SELECT cols.column_name, atc.identity_column ",
"FROM all_constraints cons, all_cons_columns cols ",
"INNER JOIN all_tab_columns atc ON(atc.table_name = cols.table_name AND atc.COLUMN_NAME = cols.COLUMN_NAME )",
"WHERE cols.table_name = ",
this.escape(tableName),
"AND cols.owner = ",
table.schema ? this.escape(schemaName) : "USER ",
"AND cons.constraint_type = 'P' ",
"AND cons.constraint_name = cols.constraint_name ",
"AND cons.owner = cols.owner ",
"ORDER BY cols.table_name, cols.position"
].join("");
return sql;
}
dropConstraintQuery(tableName, constraintName) {
return `ALTER TABLE ${this.quoteTable(tableName)} DROP CONSTRAINT ${constraintName}`;
}
setIsolationLevelQuery(value, options) {
if (options.parent) {
return;
}
switch (value) {
case Transaction.ISOLATION_LEVELS.READ_UNCOMMITTED:
case Transaction.ISOLATION_LEVELS.READ_COMMITTED:
return "SET TRANSACTION ISOLATION LEVEL READ COMMITTED;";
case Transaction.ISOLATION_LEVELS.REPEATABLE_READ:
return "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;";
default:
throw new Error(`isolation level "${value}" is not supported`);
}
}
getAliasToken() {
return "";
}
startTransactionQuery(transaction) {
if (transaction.parent) {
return `SAVEPOINT ${this.quoteIdentifier(transaction.name)}`;
}
return "BEGIN TRANSACTION";
}
commitTransactionQuery(transaction) {
if (transaction.parent) {
return;
}
return "COMMIT TRANSACTION";
}
rollbackTransactionQuery(transaction) {
if (transaction.parent) {
return `ROLLBACK TO SAVEPOINT ${this.quoteIdentifier(transaction.name)}`;
}
return "ROLLBACK TRANSACTION";
}
handleSequelizeMethod(smth, tableName, factory, options, prepend) {
let str;
if (smth instanceof Utils.Json) {
if (smth.conditions) {
const conditions = this.parseConditionObject(smth.conditions).map((condition) => `${this.jsonPathExtractionQuery(condition.path[0], _.tail(condition.path))} = '${condition.value}'`);
return conditions.join(" AND ");
}
if (smth.path) {
if (this._checkValidJsonStatement(smth.path)) {
str = smth.path;
} else {
const paths = _.toPath(smth.path);
const column = paths.shift();
str = this.jsonPathExtractionQuery(column, paths);
}
if (smth.value) {
str += util.format(" = %s", this.escape(smth.value));
}
return str;
}
}
if (smth instanceof Utils.Cast) {
if (smth.val instanceof Utils.SequelizeMethod) {
str = this.handleSequelizeMethod(smth.val, tableName, factory, options, prepend);
if (smth.type === "boolean") {
str = `(CASE WHEN ${str}='true' THEN 1 ELSE 0 END)`;
return `CAST(${str} AS NUMBER)`;
}
if (smth.type === "timestamptz" && /json_value\(/.test(str)) {
str = str.slice(0, -1);
return `${str} RETURNING TIMESTAMP WITH TIME ZONE)`;
}
}
}
return super.handleSequelizeMethod(smth, tableName, factory, options, prepend);
}
_checkValidJsonStatement(stmt) {
if (typeof stmt !== "string") {
return false;
}
let currentIndex = 0;
let openingBrackets = 0;
let closingBrackets = 0;
let hasJsonFunction = false;
let hasInvalidToken = false;
while (currentIndex < stmt.length) {
const string = stmt.substr(currentIndex);
const functionMatches = JSON_FUNCTION_REGEX.exec(string);
if (functionMatches) {
currentIndex += functionMatches[0].indexOf("(");
hasJsonFunction = true;
continue;
}
const operatorMatches = JSON_OPERATOR_REGEX.exec(string);
if (operatorMatches) {
currentIndex += operatorMatches[0].length;
hasJsonFunction = true;
continue;
}
const tokenMatches = TOKEN_CAPTURE_REGEX.exec(string);
if (tokenMatches) {
const capturedToken = tokenMatches[1];
if (capturedToken === "(") {
openingBrackets++;
} else if (capturedToken === ")") {
closingBrackets++;
} else if (capturedToken === ";") {
hasInvalidToken = true;
break;
}
currentIndex += tokenMatches[0].length;
continue;
}
break;
}
if (hasJsonFunction && (hasInvalidToken || openingBrackets !== closingBrackets)) {
throw new Error(`Invalid json statement: ${stmt}`);
}
return hasJsonFunction;
}
jsonPathExtractionQuery(column, path) {
let paths = _.toPath(path);
const quotedColumn = this.isIdentifierQuoted(column) ? column : this.quoteIdentifier(column);
paths = paths.map((subPath) => {
return /\D/.test(subPath) ? Utils.addTicks(subPath, '"') : subPath;
});
const pathStr = this.escape(["$"].concat(paths).join(".").replace(/\.(\d+)(?:(?=\.)|$)/g, (__, digit) => `[${digit}]`));
return `json_value(${quotedColumn},${pathStr})`;
}
addLimitAndOffset(options, model) {
let fragment = "";
const offset = options.offset || 0, isSubQuery = options.hasIncludeWhere || options.hasIncludeRequired || options.hasMultiAssociation;
let orders = {};
if (options.order) {
orders = this.getQueryOrders(options, model, isSubQuery);
}
if (options.limit || options.offset) {
if (!orders.mainQueryOrder || !orders.mainQueryOrder.length || isSubQuery && (!orders.subQueryOrder || !orders.subQueryOrder.length)) {
const tablePkFragment = `${this.quoteTable(options.tableAs || model.name)}.${this.quoteIdentifier(model.primaryKeyField)}`;
fragment += ` ORDER BY ${tablePkFragment}`;
}
if (options.offset || options.limit) {
fragment += ` OFFSET ${this.escape(offset)} ROWS`;
}
if (options.limit) {
fragment += ` FETCH NEXT ${this.escape(options.limit)} ROWS ONLY`;
}
}
return fragment;
}
booleanValue(value) {
return value ? 1 : 0;
}
quoteIdentifier(identifier, force = false) {
const optForceQuote = force;
const optQuoteIdentifiers = this.options.quoteIdentifiers !== false;
const rawIdentifier = Utils.removeTicks(identifier, '"');
const regExp = /^(([\w][\w\d_]*))$/g;
if (optForceQuote !== true && optQuoteIdentifiers === false && regExp.test(rawIdentifier) && !ORACLE_RESERVED_WORDS.includes(rawIdentifier.toUpperCase())) {
return rawIdentifier;
}
return Utils.addTicks(rawIdentifier, '"');
}
bindParam(bind, posOffset = 0) {
return (value) => {
bind.push(value);
return `:${bind.length + posOffset}`;
};
}
authTestQuery() {
return "SELECT 1+1 AS result FROM DUAL";
}
}
function throwMethodUndefined(methodName) {
throw new Error(`The method "${methodName}" is not defined! Please add it to your sql dialect.`);
}
//# sourceMappingURL=query-generator.js.map