mirror of
https://github.com/dbgate/dbgate
synced 2024-11-07 20:26:23 +00:00
get version result and login from oracle
This commit is contained in:
parent
1535dfd407
commit
4939b74179
21
plugins/dbgate-plugin-oracle/LICENSE
Normal file
21
plugins/dbgate-plugin-oracle/LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021 Jan Prochazka
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
10
plugins/dbgate-plugin-oracle/README.md
Normal file
10
plugins/dbgate-plugin-oracle/README.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier)
|
||||||
|
[![NPM version](https://img.shields.io/npm/v/dbgate-plugin-oracle.svg)](https://www.npmjs.com/package/dbgate-plugin-oracle)
|
||||||
|
|
||||||
|
# dbgate-plugin-oracle
|
||||||
|
|
||||||
|
Use DbGate for install of this plugin
|
||||||
|
|
||||||
|
set NODE_OPTIONS=--openssl-legacy-provider
|
||||||
|
|
||||||
|
Map pg.client and pg.query to oracledb
|
22
plugins/dbgate-plugin-oracle/icon.svg
Normal file
22
plugins/dbgate-plugin-oracle/icon.svg
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||||
|
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
|
||||||
|
<svg width="432.071pt" height="445.383pt" viewBox="0 0 432.071 445.383" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="orginal" style="fill-rule:nonzero;clip-rule:nonzero;stroke:#000000;stroke-miterlimit:4;">
|
||||||
|
</g>
|
||||||
|
<g id="Layer_x0020_3" style="fill-rule:nonzero;clip-rule:nonzero;fill:none;stroke:#FFFFFF;stroke-width:12.4651;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;">
|
||||||
|
<path style="fill:#000000;stroke:#000000;stroke-width:37.3953;stroke-linecap:butt;stroke-linejoin:miter;" d="M323.205,324.227c2.833-23.601,1.984-27.062,19.563-23.239l4.463,0.392c13.517,0.615,31.199-2.174,41.587-7c22.362-10.376,35.622-27.7,13.572-23.148c-50.297,10.376-53.755-6.655-53.755-6.655c53.111-78.803,75.313-178.836,56.149-203.322 C352.514-5.534,262.036,26.049,260.522,26.869l-0.482,0.089c-9.938-2.062-21.06-3.294-33.554-3.496c-22.761-0.374-40.032,5.967-53.133,15.904c0,0-161.408-66.498-153.899,83.628c1.597,31.936,45.777,241.655,98.47,178.31 c19.259-23.163,37.871-42.748,37.871-42.748c9.242,6.14,20.307,9.272,31.912,8.147l0.897-0.765c-0.281,2.876-0.157,5.689,0.359,9.019c-13.572,15.167-9.584,17.83-36.723,23.416c-27.457,5.659-11.326,15.734-0.797,18.367c12.768,3.193,42.305,7.716,62.268-20.224 l-0.795,3.188c5.325,4.26,4.965,30.619,5.72,49.452c0.756,18.834,2.017,36.409,5.856,46.771c3.839,10.36,8.369,37.05,44.036,29.406c29.809-6.388,52.6-15.582,54.677-101.107"/>
|
||||||
|
<path style="fill:#336791;stroke:none;" d="M402.395,271.23c-50.302,10.376-53.76-6.655-53.76-6.655c53.111-78.808,75.313-178.843,56.153-203.326c-52.27-66.785-142.752-35.2-144.262-34.38l-0.486,0.087c-9.938-2.063-21.06-3.292-33.56-3.496c-22.761-0.373-40.026,5.967-53.127,15.902 c0,0-161.411-66.495-153.904,83.63c1.597,31.938,45.776,241.657,98.471,178.312c19.26-23.163,37.869-42.748,37.869-42.748c9.243,6.14,20.308,9.272,31.908,8.147l0.901-0.765c-0.28,2.876-0.152,5.689,0.361,9.019c-13.575,15.167-9.586,17.83-36.723,23.416 c-27.459,5.659-11.328,15.734-0.796,18.367c12.768,3.193,42.307,7.716,62.266-20.224l-0.796,3.188c5.319,4.26,9.054,27.711,8.428,48.969c-0.626,21.259-1.044,35.854,3.147,47.254c4.191,11.4,8.368,37.05,44.042,29.406c29.809-6.388,45.256-22.942,47.405-50.555 c1.525-19.631,4.976-16.729,5.194-34.28l2.768-8.309c3.192-26.611,0.507-35.196,18.872-31.203l4.463,0.392c13.517,0.615,31.208-2.174,41.591-7c22.358-10.376,35.618-27.7,13.573-23.148z"/>
|
||||||
|
<path d="M215.866,286.484c-1.385,49.516,0.348,99.377,5.193,111.495c4.848,12.118,15.223,35.688,50.9,28.045c29.806-6.39,40.651-18.756,45.357-46.051c3.466-20.082,10.148-75.854,11.005-87.281"/>
|
||||||
|
<path d="M173.104,38.256c0,0-161.521-66.016-154.012,84.109c1.597,31.938,45.779,241.664,98.473,178.316c19.256-23.166,36.671-41.335,36.671-41.335"/>
|
||||||
|
<path d="M260.349,26.207c-5.591,1.753,89.848-34.889,144.087,34.417c19.159,24.484-3.043,124.519-56.153,203.329"/>
|
||||||
|
<path style="stroke-linejoin:bevel;" d="M348.282,263.953c0,0,3.461,17.036,53.764,6.653c22.04-4.552,8.776,12.774-13.577,23.155c-18.345,8.514-59.474,10.696-60.146-1.069c-1.729-30.355,21.647-21.133,19.96-28.739c-1.525-6.85-11.979-13.573-18.894-30.338 c-6.037-14.633-82.796-126.849,21.287-110.183c3.813-0.789-27.146-99.002-124.553-100.599c-97.385-1.597-94.19,119.762-94.19,119.762"/>
|
||||||
|
<path d="M188.604,274.334c-13.577,15.166-9.584,17.829-36.723,23.417c-27.459,5.66-11.326,15.733-0.797,18.365c12.768,3.195,42.307,7.718,62.266-20.229c6.078-8.509-0.036-22.086-8.385-25.547c-4.034-1.671-9.428-3.765-16.361,3.994z"/>
|
||||||
|
<path d="M187.715,274.069c-1.368-8.917,2.93-19.528,7.536-31.942c6.922-18.626,22.893-37.255,10.117-96.339c-9.523-44.029-73.396-9.163-73.436-3.193c-0.039,5.968,2.889,30.26-1.067,58.548c-5.162,36.913,23.488,68.132,56.479,64.938"/>
|
||||||
|
<path style="fill:#FFFFFF;stroke-width:4.155;stroke-linecap:butt;stroke-linejoin:miter;" d="M172.517,141.7c-0.288,2.039,3.733,7.48,8.976,8.207c5.234,0.73,9.714-3.522,9.998-5.559c0.284-2.039-3.732-4.285-8.977-5.015c-5.237-0.731-9.719,0.333-9.996,2.367z"/>
|
||||||
|
<path style="fill:#FFFFFF;stroke-width:2.0775;stroke-linecap:butt;stroke-linejoin:miter;" d="M331.941,137.543c0.284,2.039-3.732,7.48-8.976,8.207c-5.238,0.73-9.718-3.522-10.005-5.559c-0.277-2.039,3.74-4.285,8.979-5.015c5.239-0.73,9.718,0.333,10.002,2.368z"/>
|
||||||
|
<path d="M350.676,123.432c0.863,15.994-3.445,26.888-3.988,43.914c-0.804,24.748,11.799,53.074-7.191,81.435"/>
|
||||||
|
<path style="stroke-width:3;" d="M0,60.232"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 4.3 KiB |
41
plugins/dbgate-plugin-oracle/package.json
Normal file
41
plugins/dbgate-plugin-oracle/package.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"name": "dbgate-plugin-oracle",
|
||||||
|
"main": "dist/backend.js",
|
||||||
|
"version": "5.0.0-alpha.1",
|
||||||
|
"license": "MIT",
|
||||||
|
"description": "Oracle connector plugin for DbGate",
|
||||||
|
"homepage": "https://dbgate.org",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/dbgate/dbgate"
|
||||||
|
},
|
||||||
|
"author": "Rinie Kervel",
|
||||||
|
"keywords": [
|
||||||
|
"dbgate",
|
||||||
|
"dbgateplugin",
|
||||||
|
"oracle"
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"dist",
|
||||||
|
"icon.svg"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build:frontend": "webpack --config webpack-frontend.config",
|
||||||
|
"build:frontend:watch": "webpack --watch --config webpack-frontend.config",
|
||||||
|
"build:backend": "webpack --config webpack-backend.config.js",
|
||||||
|
"build": "yarn build:frontend && yarn build:backend",
|
||||||
|
"plugin": "yarn build && yarn pack && dbgate-plugin dbgate-plugin-oracle",
|
||||||
|
"copydist": "yarn build && yarn pack && dbgate-copydist ../dist/dbgate-plugin-oracle",
|
||||||
|
"plugout": "dbgate-plugout dbgate-plugin-oracle",
|
||||||
|
"prepublishOnly": "yarn build"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"dbgate-plugin-tools": "^1.0.7",
|
||||||
|
"dbgate-query-splitter": "^4.9.0",
|
||||||
|
"dbgate-tools": "^5.0.0-alpha.1",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"oracledb": "^5.0.0",
|
||||||
|
"webpack": "^4.42.0",
|
||||||
|
"webpack-cli": "^3.3.11"
|
||||||
|
}
|
||||||
|
}
|
9
plugins/dbgate-plugin-oracle/prettier.config.js
Normal file
9
plugins/dbgate-plugin-oracle/prettier.config.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
module.exports = {
|
||||||
|
trailingComma: 'es5',
|
||||||
|
tabWidth: 2,
|
||||||
|
semi: true,
|
||||||
|
singleQuote: true,
|
||||||
|
arrowParen: 'avoid',
|
||||||
|
arrowParens: 'avoid',
|
||||||
|
printWidth: 120,
|
||||||
|
};
|
353
plugins/dbgate-plugin-oracle/src/backend/Analyser.js
Normal file
353
plugins/dbgate-plugin-oracle/src/backend/Analyser.js
Normal file
@ -0,0 +1,353 @@
|
|||||||
|
const fp = require('lodash/fp');
|
||||||
|
const _ = require('lodash');
|
||||||
|
const sql = require('./sql');
|
||||||
|
|
||||||
|
const { DatabaseAnalyser } = require('dbgate-tools');
|
||||||
|
const { isTypeString, isTypeNumeric } = require('dbgate-tools');
|
||||||
|
|
||||||
|
function normalizeTypeName(dataType) {
|
||||||
|
if (dataType == 'character varying') return 'varchar';
|
||||||
|
if (dataType == 'timestamp without time zone') return 'timestamp';
|
||||||
|
return dataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getColumnInfo(
|
||||||
|
{ is_nullable, column_name, data_type, char_max_length, numeric_precision, numeric_ccale, default_value },
|
||||||
|
table = undefined,
|
||||||
|
geometryColumns = undefined,
|
||||||
|
geographyColumns = undefined
|
||||||
|
) {
|
||||||
|
const normDataType = normalizeTypeName(data_type);
|
||||||
|
let fullDataType = normDataType;
|
||||||
|
if (char_max_length && isTypeString(normDataType)) fullDataType = `${normDataType}(${char_max_length})`;
|
||||||
|
if (numeric_precision && numeric_ccale && isTypeNumeric(normDataType))
|
||||||
|
fullDataType = `${normDataType}(${numeric_precision},${numeric_ccale})`;
|
||||||
|
const autoIncrement = !!(default_value && default_value.startsWith('nextval('));
|
||||||
|
if (
|
||||||
|
table &&
|
||||||
|
geometryColumns &&
|
||||||
|
geometryColumns.rows.find(
|
||||||
|
x => x.schema_name == table.schemaName && x.pure_name == table.pureName && x.column_name == column_name
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
fullDataType = 'geometry';
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
table &&
|
||||||
|
geographyColumns &&
|
||||||
|
geographyColumns.rows.find(
|
||||||
|
x => x.schema_name == table.schemaName && x.pure_name == table.pureName && x.column_name == column_name
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
fullDataType = 'geography';
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
columnName: column_name,
|
||||||
|
dataType: fullDataType,
|
||||||
|
notNull: !is_nullable || is_nullable == 'NO' || is_nullable == 'no',
|
||||||
|
defaultValue: autoIncrement ? undefined : default_value,
|
||||||
|
autoIncrement,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class Analyser extends DatabaseAnalyser {
|
||||||
|
constructor(pool, driver, version) {
|
||||||
|
super(pool, driver, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
createQuery(resFileName, typeFields) {
|
||||||
|
const query = super.createQuery(sql[resFileName], typeFields);
|
||||||
|
if (query) return query.replace('#REFTABLECOND#', this.driver.__analyserInternals.refTableCond);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _computeSingleObjectId() {
|
||||||
|
const { typeField, schemaName, pureName } = this.singleObjectFilter;
|
||||||
|
this.singleObjectId = `${typeField}:${schemaName || 'public'}.${pureName}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _runAnalysis() {
|
||||||
|
this.feedback({ analysingMessage: 'Loading tables' });
|
||||||
|
const tables = await this.driver.query(
|
||||||
|
this.pool,
|
||||||
|
this.createQuery(this.driver.dialect.stringAgg ? 'tableModifications' : 'tableList', ['tables'])
|
||||||
|
);
|
||||||
|
this.feedback({ analysingMessage: 'Loading columns' });
|
||||||
|
const columns = await this.driver.query(this.pool, this.createQuery('columns', ['tables', 'views']));
|
||||||
|
this.feedback({ analysingMessage: 'Loading primary keys' });
|
||||||
|
const pkColumns = await this.driver.query(this.pool, this.createQuery('primaryKeys', ['tables']));
|
||||||
|
|
||||||
|
let fkColumns = null;
|
||||||
|
|
||||||
|
// if (true) {
|
||||||
|
if (this.containsObjectIdCondition(['tables']) || this.driver.__analyserInternals.refTableCond) {
|
||||||
|
this.feedback({ analysingMessage: 'Loading foreign keys' });
|
||||||
|
fkColumns = await this.driver.query(this.pool, this.createQuery('foreignKeys', ['tables']));
|
||||||
|
} else {
|
||||||
|
this.feedback({ analysingMessage: 'Loading foreign key constraints' });
|
||||||
|
const fk_tableConstraints = await this.driver.query(
|
||||||
|
this.pool,
|
||||||
|
this.createQuery('fk_tableConstraints', ['tables'])
|
||||||
|
);
|
||||||
|
|
||||||
|
this.feedback({ analysingMessage: 'Loading foreign key refs' });
|
||||||
|
const fk_referentialConstraints = await this.driver.query(
|
||||||
|
this.pool,
|
||||||
|
this.createQuery('fk_referentialConstraints', ['tables'])
|
||||||
|
);
|
||||||
|
|
||||||
|
this.feedback({ analysingMessage: 'Loading foreign key columns' });
|
||||||
|
const fk_keyColumnUsage = await this.driver.query(this.pool, this.createQuery('fk_keyColumnUsage', ['tables']));
|
||||||
|
|
||||||
|
const cntKey = x => `${x.constraint_name}|${x.constraint_schema}`;
|
||||||
|
const rows = [];
|
||||||
|
const constraintDct = _.keyBy(fk_tableConstraints.rows, cntKey);
|
||||||
|
for (const fkRef of fk_referentialConstraints.rows) {
|
||||||
|
const cntBase = constraintDct[cntKey(fkRef)];
|
||||||
|
const cntRef = constraintDct[`${fkRef.unique_constraint_name}|${fkRef.unique_constraint_schema}`];
|
||||||
|
if (!cntBase || !cntRef) continue;
|
||||||
|
const baseCols = _.sortBy(
|
||||||
|
fk_keyColumnUsage.rows.filter(
|
||||||
|
x => x.table_name == cntBase.table_name && x.constraint_name == cntBase.constraint_name
|
||||||
|
),
|
||||||
|
'ordinal_position'
|
||||||
|
);
|
||||||
|
const refCols = _.sortBy(
|
||||||
|
fk_keyColumnUsage.rows.filter(
|
||||||
|
x => x.table_name == cntRef.table_name && x.constraint_name == cntRef.constraint_name
|
||||||
|
),
|
||||||
|
'ordinal_position'
|
||||||
|
);
|
||||||
|
if (baseCols.length != refCols.length) continue;
|
||||||
|
|
||||||
|
for (let i = 0; i < baseCols.length; i++) {
|
||||||
|
const baseCol = baseCols[i];
|
||||||
|
const refCol = refCols[i];
|
||||||
|
|
||||||
|
rows.push({
|
||||||
|
...fkRef,
|
||||||
|
pure_name: cntBase.table_name,
|
||||||
|
schema_name: cntBase.table_schema,
|
||||||
|
ref_table_name: cntRef.table_name,
|
||||||
|
ref_schema_name: cntRef.table_schema,
|
||||||
|
column_name: baseCol.column_name,
|
||||||
|
ref_column_name: refCol.column_name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fkColumns = { rows };
|
||||||
|
}
|
||||||
|
|
||||||
|
this.feedback({ analysingMessage: 'Loading views' });
|
||||||
|
const views = await this.driver.query(this.pool, this.createQuery('views', ['views']));
|
||||||
|
this.feedback({ analysingMessage: 'Loading materialized views' });
|
||||||
|
const matviews = this.driver.dialect.materializedViews
|
||||||
|
? await this.driver.query(this.pool, this.createQuery('matviews', ['matviews']))
|
||||||
|
: null;
|
||||||
|
this.feedback({ analysingMessage: 'Loading materialized view columns' });
|
||||||
|
const matviewColumns = this.driver.dialect.materializedViews
|
||||||
|
? await this.driver.query(this.pool, this.createQuery('matviewColumns', ['matviews']))
|
||||||
|
: null;
|
||||||
|
this.feedback({ analysingMessage: 'Loading routines' });
|
||||||
|
const routines = await this.driver.query(this.pool, this.createQuery('routines', ['procedures', 'functions']));
|
||||||
|
this.feedback({ analysingMessage: 'Loading indexes' });
|
||||||
|
const indexes = this.driver.__analyserInternals.skipIndexes
|
||||||
|
? { rows: [] }
|
||||||
|
: await this.driver.query(this.pool, this.createQuery('indexes', ['tables']));
|
||||||
|
this.feedback({ analysingMessage: 'Loading index columns' });
|
||||||
|
const indexcols = this.driver.__analyserInternals.skipIndexes
|
||||||
|
? { rows: [] }
|
||||||
|
: await this.driver.query(this.pool, this.createQuery('indexcols', ['tables']));
|
||||||
|
this.feedback({ analysingMessage: 'Loading unique names' });
|
||||||
|
const uniqueNames = await this.driver.query(this.pool, this.createQuery('uniqueNames', ['tables']));
|
||||||
|
|
||||||
|
let geometryColumns = { rows: [] };
|
||||||
|
if (views.rows.find(x => x.pure_name == 'geometry_columns' && x.schema_name == 'public')) {
|
||||||
|
this.feedback({ analysingMessage: 'Loading geometry columns' });
|
||||||
|
geometryColumns = await this.safeQuery(this.createQuery('geometryColumns', ['tables']));
|
||||||
|
}
|
||||||
|
let geographyColumns = { rows: [] };
|
||||||
|
if (views.rows.find(x => x.pure_name == 'geography_columns' && x.schema_name == 'public')) {
|
||||||
|
this.feedback({ analysingMessage: 'Loading geography columns' });
|
||||||
|
geographyColumns = await this.safeQuery(this.createQuery('geographyColumns', ['tables']));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.feedback({ analysingMessage: 'Finalizing DB structure' });
|
||||||
|
|
||||||
|
const columnColumnsMapped = fkColumns.rows.map(x => ({
|
||||||
|
pureName: x.pure_name,
|
||||||
|
schemaName: x.schema_name,
|
||||||
|
constraintSchema: x.constraint_schema,
|
||||||
|
constraintName: x.constraint_name,
|
||||||
|
columnName: x.column_name,
|
||||||
|
refColumnName: x.ref_column_name,
|
||||||
|
updateAction: x.update_action,
|
||||||
|
deleteAction: x.delete_action,
|
||||||
|
refTableName: x.ref_table_name,
|
||||||
|
refSchemaName: x.ref_schema_name,
|
||||||
|
}));
|
||||||
|
const pkColumnsMapped = pkColumns.rows.map(x => ({
|
||||||
|
pureName: x.pure_name,
|
||||||
|
schemaName: x.schema_name,
|
||||||
|
constraintSchema: x.constraint_schema,
|
||||||
|
constraintName: x.constraint_name,
|
||||||
|
columnName: x.column_name,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const res = {
|
||||||
|
tables: tables.rows.map(table => {
|
||||||
|
const newTable = {
|
||||||
|
pureName: table.pure_name,
|
||||||
|
schemaName: table.schema_name,
|
||||||
|
objectId: `tables:${table.schema_name}.${table.pure_name}`,
|
||||||
|
contentHash: table.hash_code_columns ? `${table.hash_code_columns}-${table.hash_code_constraints}` : null,
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
...newTable,
|
||||||
|
columns: columns.rows
|
||||||
|
.filter(col => col.pure_name == table.pure_name && col.schema_name == table.schema_name)
|
||||||
|
.map(col => getColumnInfo(col, newTable, geometryColumns, geographyColumns)),
|
||||||
|
primaryKey: DatabaseAnalyser.extractPrimaryKeys(newTable, pkColumnsMapped),
|
||||||
|
foreignKeys: DatabaseAnalyser.extractForeignKeys(newTable, columnColumnsMapped),
|
||||||
|
indexes: indexes.rows
|
||||||
|
.filter(
|
||||||
|
x =>
|
||||||
|
x.table_name == table.pure_name &&
|
||||||
|
x.schema_name == table.schema_name &&
|
||||||
|
!uniqueNames.rows.find(y => y.constraint_name == x.index_name)
|
||||||
|
)
|
||||||
|
.map(idx => ({
|
||||||
|
constraintName: idx.index_name,
|
||||||
|
isUnique: idx.is_unique,
|
||||||
|
columns: _.compact(
|
||||||
|
idx.indkey
|
||||||
|
.split(' ')
|
||||||
|
.map(colid => indexcols.rows.find(col => col.oid == idx.oid && col.attnum == colid))
|
||||||
|
.filter(col => col != null)
|
||||||
|
.map(col => ({
|
||||||
|
columnName: col.column_name,
|
||||||
|
}))
|
||||||
|
),
|
||||||
|
})),
|
||||||
|
uniques: indexes.rows
|
||||||
|
.filter(
|
||||||
|
x =>
|
||||||
|
x.table_name == table.pure_name &&
|
||||||
|
x.schema_name == table.schema_name &&
|
||||||
|
uniqueNames.rows.find(y => y.constraint_name == x.index_name)
|
||||||
|
)
|
||||||
|
.map(idx => ({
|
||||||
|
constraintName: idx.index_name,
|
||||||
|
columns: _.compact(
|
||||||
|
idx.indkey
|
||||||
|
.split(' ')
|
||||||
|
.map(colid => indexcols.rows.find(col => col.oid == idx.oid && col.attnum == colid))
|
||||||
|
.filter(col => col != null)
|
||||||
|
.map(col => ({
|
||||||
|
columnName: col.column_name,
|
||||||
|
}))
|
||||||
|
),
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
views: views.rows.map(view => ({
|
||||||
|
objectId: `views:${view.schema_name}.${view.pure_name}`,
|
||||||
|
pureName: view.pure_name,
|
||||||
|
schemaName: view.schema_name,
|
||||||
|
contentHash: view.hash_code,
|
||||||
|
createSql: `CREATE VIEW "${view.schema_name}"."${view.pure_name}"\nAS\n${view.create_sql}`,
|
||||||
|
columns: columns.rows
|
||||||
|
.filter(col => col.pure_name == view.pure_name && col.schema_name == view.schema_name)
|
||||||
|
.map(col => getColumnInfo(col)),
|
||||||
|
})),
|
||||||
|
matviews: matviews
|
||||||
|
? matviews.rows.map(matview => ({
|
||||||
|
objectId: `matviews:${matview.schema_name}.${matview.pure_name}`,
|
||||||
|
pureName: matview.pure_name,
|
||||||
|
schemaName: matview.schema_name,
|
||||||
|
contentHash: matview.hash_code,
|
||||||
|
createSql: `CREATE MATERIALIZED VIEW "${matview.schema_name}"."${matview.pure_name}"\nAS\n${matview.definition}`,
|
||||||
|
columns: matviewColumns.rows
|
||||||
|
.filter(col => col.pure_name == matview.pure_name && col.schema_name == matview.schema_name)
|
||||||
|
.map(col => getColumnInfo(col)),
|
||||||
|
}))
|
||||||
|
: undefined,
|
||||||
|
procedures: routines.rows
|
||||||
|
.filter(x => x.object_type == 'PROCEDURE')
|
||||||
|
.map(proc => ({
|
||||||
|
objectId: `procedures:${proc.schema_name}.${proc.pure_name}`,
|
||||||
|
pureName: proc.pure_name,
|
||||||
|
schemaName: proc.schema_name,
|
||||||
|
createSql: `CREATE PROCEDURE "${proc.schema_name}"."${proc.pure_name}"() LANGUAGE ${proc.language}\nAS\n$$\n${proc.definition}\n$$`,
|
||||||
|
contentHash: proc.hash_code,
|
||||||
|
})),
|
||||||
|
functions: routines.rows
|
||||||
|
.filter(x => x.object_type == 'FUNCTION')
|
||||||
|
.map(func => ({
|
||||||
|
objectId: `functions:${func.schema_name}.${func.pure_name}`,
|
||||||
|
createSql: `CREATE FUNCTION "${func.schema_name}"."${func.pure_name}"() RETURNS ${func.data_type} LANGUAGE ${func.language}\nAS\n$$\n${func.definition}\n$$`,
|
||||||
|
pureName: func.pure_name,
|
||||||
|
schemaName: func.schema_name,
|
||||||
|
contentHash: func.hash_code,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
|
||||||
|
this.feedback({ analysingMessage: null });
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _getFastSnapshot() {
|
||||||
|
const tableModificationsQueryData = this.driver.dialect.stringAgg
|
||||||
|
? await this.driver.query(this.pool, this.createQuery('tableModifications'))
|
||||||
|
: null;
|
||||||
|
const viewModificationsQueryData = await this.driver.query(this.pool, this.createQuery('viewModifications'));
|
||||||
|
const matviewModificationsQueryData = this.driver.dialect.materializedViews
|
||||||
|
? await this.driver.query(this.pool, this.createQuery('matviewModifications'))
|
||||||
|
: null;
|
||||||
|
const routineModificationsQueryData = await this.driver.query(this.pool, this.createQuery('routineModifications'));
|
||||||
|
|
||||||
|
return {
|
||||||
|
tables: tableModificationsQueryData
|
||||||
|
? tableModificationsQueryData.rows.map(x => ({
|
||||||
|
objectId: `tables:${x.schema_name}.${x.pure_name}`,
|
||||||
|
pureName: x.pure_name,
|
||||||
|
schemaName: x.schema_name,
|
||||||
|
contentHash: `${x.hash_code_columns}-${x.hash_code_constraints}`,
|
||||||
|
}))
|
||||||
|
: null,
|
||||||
|
views: viewModificationsQueryData.rows.map(x => ({
|
||||||
|
objectId: `views:${x.schema_name}.${x.pure_name}`,
|
||||||
|
pureName: x.pure_name,
|
||||||
|
schemaName: x.schema_name,
|
||||||
|
contentHash: x.hash_code,
|
||||||
|
})),
|
||||||
|
matviews: matviewModificationsQueryData
|
||||||
|
? matviewModificationsQueryData.rows.map(x => ({
|
||||||
|
objectId: `matviews:${x.schema_name}.${x.pure_name}`,
|
||||||
|
pureName: x.pure_name,
|
||||||
|
schemaName: x.schema_name,
|
||||||
|
contentHash: x.hash_code,
|
||||||
|
}))
|
||||||
|
: undefined,
|
||||||
|
procedures: routineModificationsQueryData.rows
|
||||||
|
.filter(x => x.object_type == 'PROCEDURE')
|
||||||
|
.map(x => ({
|
||||||
|
objectId: `procedures:${x.schema_name}.${x.pure_name}`,
|
||||||
|
pureName: x.pure_name,
|
||||||
|
schemaName: x.schema_name,
|
||||||
|
contentHash: x.hash_code,
|
||||||
|
})),
|
||||||
|
functions: routineModificationsQueryData.rows
|
||||||
|
.filter(x => x.object_type == 'FUNCTION')
|
||||||
|
.map(x => ({
|
||||||
|
objectId: `functions:${x.schema_name}.${x.pure_name}`,
|
||||||
|
pureName: x.pure_name,
|
||||||
|
schemaName: x.schema_name,
|
||||||
|
contentHash: x.hash_code,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Analyser;
|
303
plugins/dbgate-plugin-oracle/src/backend/drivers.js
Normal file
303
plugins/dbgate-plugin-oracle/src/backend/drivers.js
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
const _ = require('lodash');
|
||||||
|
const stream = require('stream');
|
||||||
|
|
||||||
|
const driverBases = require('../frontend/drivers');
|
||||||
|
const Analyser = require('./Analyser');
|
||||||
|
//--const pg = require('pg');
|
||||||
|
const oracledb = require('oracledb');
|
||||||
|
const { createBulkInsertStreamBase, makeUniqueColumnNames } = require('dbgate-tools');
|
||||||
|
|
||||||
|
/*
|
||||||
|
pg.types.setTypeParser(1082, 'text', val => val); // date
|
||||||
|
pg.types.setTypeParser(1114, 'text', val => val); // timestamp without timezone
|
||||||
|
pg.types.setTypeParser(1184, 'text', val => val); // timestamp
|
||||||
|
*/
|
||||||
|
|
||||||
|
function extractOracleColumns(result) {
|
||||||
|
console.log('result', result);
|
||||||
|
console.log('result.name', result[0].name);
|
||||||
|
console.log('result.map', result.map(fld => ({
|
||||||
|
columnName: fld.name.toLowerCase(),
|
||||||
|
})));
|
||||||
|
if (!result /*|| !result.fields */) return [];
|
||||||
|
const res = result.map(fld => ({
|
||||||
|
columnName: fld.name.toLowerCase(),
|
||||||
|
}));
|
||||||
|
makeUniqueColumnNames(res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
function zipDataRow(rowArray, columns) {
|
||||||
|
return _.zipObject(
|
||||||
|
columns.map(x => x.columnName),
|
||||||
|
rowArray
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {import('dbgate-types').EngineDriver} */
|
||||||
|
const drivers = driverBases.map(driverBase => ({
|
||||||
|
...driverBase,
|
||||||
|
analyserClass: Analyser,
|
||||||
|
|
||||||
|
async connect({
|
||||||
|
engine,
|
||||||
|
server,
|
||||||
|
port,
|
||||||
|
user,
|
||||||
|
password,
|
||||||
|
database,
|
||||||
|
databaseUrl,
|
||||||
|
useDatabaseUrl,
|
||||||
|
ssl,
|
||||||
|
isReadOnly,
|
||||||
|
authType,
|
||||||
|
socketPath,
|
||||||
|
}) {
|
||||||
|
let options = null;
|
||||||
|
|
||||||
|
if (engine == 'redshift@dbgate-plugin-oracle') {
|
||||||
|
let url = databaseUrl;
|
||||||
|
if (url && url.startsWith('jdbc:redshift://')) {
|
||||||
|
url = url.substring('jdbc:redshift://'.length);
|
||||||
|
}
|
||||||
|
if (user && password) {
|
||||||
|
url = `oracle://${user}:${password}@${url}`;
|
||||||
|
} else if (user) {
|
||||||
|
url = `oracle://${user}@${url}`;
|
||||||
|
} else {
|
||||||
|
url = `oracle://${url}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
options = {
|
||||||
|
connectionString: url,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
options = useDatabaseUrl
|
||||||
|
? {
|
||||||
|
connectionString: databaseUrl,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
host: authType == 'socket' ? socketPath || driverBase.defaultSocketPath : server,
|
||||||
|
port: authType == 'socket' ? null : port,
|
||||||
|
user,
|
||||||
|
password,
|
||||||
|
database: database || 'oracle',
|
||||||
|
ssl,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('OPTIONS', options);
|
||||||
|
/*
|
||||||
|
const client = new pg.Client(options);
|
||||||
|
await client.connect();
|
||||||
|
|
||||||
|
if (isReadOnly) {
|
||||||
|
await this.query(client, 'SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY');
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
client = await oracledb.getConnection( {
|
||||||
|
user : options.user,
|
||||||
|
password : options.password,
|
||||||
|
connectString : options.host
|
||||||
|
});
|
||||||
|
return client;
|
||||||
|
},
|
||||||
|
async close(pool) {
|
||||||
|
return pool.end();
|
||||||
|
},
|
||||||
|
async query(client, sql) {
|
||||||
|
if (sql == null) {
|
||||||
|
return {
|
||||||
|
rows: [],
|
||||||
|
columns: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
console.log('sql', sql);
|
||||||
|
const res = await client.execute(sql);
|
||||||
|
console.log('res', res);
|
||||||
|
const columns = extractOracleColumns(res.metaData);
|
||||||
|
console.log('columns', columns);
|
||||||
|
return { rows: (res.rows || []).map(row => zipDataRow(row, columns)), columns };
|
||||||
|
},
|
||||||
|
stream(client, sql, options) {
|
||||||
|
/*
|
||||||
|
const query = new pg.Query({
|
||||||
|
text: sql,
|
||||||
|
rowMode: 'array',
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
console.log('queryStream', sql);
|
||||||
|
const query = client.queryStream(sql);
|
||||||
|
let wasHeader = false;
|
||||||
|
|
||||||
|
query.on('metaData', row => {
|
||||||
|
console.log('metaData', row);
|
||||||
|
if (!wasHeader) {
|
||||||
|
columns = extractOracleColumns(query.metaData);
|
||||||
|
if (columns && columns.length > 0) {
|
||||||
|
options.recordset(columns);
|
||||||
|
}
|
||||||
|
wasHeader = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
options.row(zipDataRow(row, columns));
|
||||||
|
});
|
||||||
|
|
||||||
|
query.on('data', row => {
|
||||||
|
console.log('DATA', row);
|
||||||
|
if (!wasHeader) {
|
||||||
|
columns = extractOracleColumns(query._result);
|
||||||
|
if (columns && columns.length > 0) {
|
||||||
|
options.recordset(columns);
|
||||||
|
}
|
||||||
|
wasHeader = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
options.row(zipDataRow(row, columns));
|
||||||
|
});
|
||||||
|
|
||||||
|
query.on('end', () => {
|
||||||
|
const { command, rowCount } = query._result || {};
|
||||||
|
|
||||||
|
if (command != 'SELECT' && _.isNumber(rowCount)) {
|
||||||
|
options.info({
|
||||||
|
message: `${rowCount} rows affected`,
|
||||||
|
time: new Date(),
|
||||||
|
severity: 'info',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wasHeader) {
|
||||||
|
columns = extractOracleColumns(query._result);
|
||||||
|
if (columns && columns.length > 0) {
|
||||||
|
options.recordset(columns);
|
||||||
|
}
|
||||||
|
wasHeader = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
options.done();
|
||||||
|
});
|
||||||
|
|
||||||
|
query.on('error', error => {
|
||||||
|
console.log('ERROR', error);
|
||||||
|
const { message, lineNumber, procName } = error;
|
||||||
|
options.info({
|
||||||
|
message,
|
||||||
|
line: lineNumber,
|
||||||
|
procedure: procName,
|
||||||
|
time: new Date(),
|
||||||
|
severity: 'error',
|
||||||
|
});
|
||||||
|
options.done();
|
||||||
|
});
|
||||||
|
|
||||||
|
client.query(query);
|
||||||
|
},
|
||||||
|
async getVersion(client) {
|
||||||
|
//const { rows } = await this.query(client, "SELECT banner as version FROM v$version WHERE banner LIKE 'Oracle%'");
|
||||||
|
const { rows } = await this.query(client, "SELECT version FROM v$instance");
|
||||||
|
const { version } = rows[0];
|
||||||
|
|
||||||
|
const isCockroach = false; //version.toLowerCase().includes('cockroachdb');
|
||||||
|
const isRedshift = false; // version.toLowerCase().includes('redshift');
|
||||||
|
const isOracle = true;
|
||||||
|
|
||||||
|
const m = version.match(/([\d\.]+)/);
|
||||||
|
//console.log('M', m);
|
||||||
|
let versionText = null;
|
||||||
|
let versionMajor = null;
|
||||||
|
let versionMinor = null;
|
||||||
|
if (m) {
|
||||||
|
if (isOracle) versionText = `Oracle ${m[1]}`;
|
||||||
|
const numbers = m[1].split('.');
|
||||||
|
if (numbers[0]) versionMajor = parseInt(numbers[0]);
|
||||||
|
if (numbers[1]) versionMinor = parseInt(numbers[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
version,
|
||||||
|
versionText,
|
||||||
|
isOracle,
|
||||||
|
isCockroach,
|
||||||
|
isRedshift,
|
||||||
|
versionMajor,
|
||||||
|
versionMinor,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
async readQuery(client, sql, structure) {
|
||||||
|
/*
|
||||||
|
const query = new pg.Query({
|
||||||
|
text: sql,
|
||||||
|
rowMode: 'array',
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
console.log('readQuery', sql, structure);
|
||||||
|
const query = await client.queryStream(sql);
|
||||||
|
|
||||||
|
let wasHeader = false;
|
||||||
|
let columns = null;
|
||||||
|
|
||||||
|
const pass = new stream.PassThrough({
|
||||||
|
objectMode: true,
|
||||||
|
highWaterMark: 100,
|
||||||
|
});
|
||||||
|
|
||||||
|
query.on('data', row => {
|
||||||
|
if (!wasHeader) {
|
||||||
|
columns = extractOracleColumns(query._result);
|
||||||
|
pass.write({
|
||||||
|
__isStreamHeader: true,
|
||||||
|
...(structure || { columns }),
|
||||||
|
});
|
||||||
|
wasHeader = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pass.write(zipDataRow(row, columns));
|
||||||
|
});
|
||||||
|
|
||||||
|
query.on('end', () => {
|
||||||
|
if (!wasHeader) {
|
||||||
|
columns = extractOracleColumns(query._result);
|
||||||
|
pass.write({
|
||||||
|
__isStreamHeader: true,
|
||||||
|
...(structure || { columns }),
|
||||||
|
});
|
||||||
|
wasHeader = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pass.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
query.on('error', error => {
|
||||||
|
console.error(error);
|
||||||
|
pass.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
client.query(query);
|
||||||
|
|
||||||
|
return pass;
|
||||||
|
},
|
||||||
|
async writeTable(pool, name, options) {
|
||||||
|
// @ts-ignore
|
||||||
|
return createBulkInsertStreamBase(this, stream, pool, name, options);
|
||||||
|
},
|
||||||
|
async listDatabases(client) {
|
||||||
|
const { rows } = await this.query(client, 'SELECT instance_name AS name FROM v$instance');
|
||||||
|
return rows;
|
||||||
|
},
|
||||||
|
|
||||||
|
getAuthTypes() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
title: 'Host and port',
|
||||||
|
name: 'hostPort',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Socket',
|
||||||
|
name: 'socket',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
module.exports = drivers;
|
6
plugins/dbgate-plugin-oracle/src/backend/index.js
Normal file
6
plugins/dbgate-plugin-oracle/src/backend/index.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
const drivers = require('./drivers');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
packageName: 'dbgate-plugin-oracle',
|
||||||
|
drivers,
|
||||||
|
};
|
23
plugins/dbgate-plugin-oracle/src/backend/sql/columns.js
Normal file
23
plugins/dbgate-plugin-oracle/src/backend/sql/columns.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
module.exports = `
|
||||||
|
select
|
||||||
|
table_schema as "schema_name",
|
||||||
|
table_name as "pure_name",
|
||||||
|
column_name as "column_name",
|
||||||
|
is_nullable as "is_nullable",
|
||||||
|
data_type as "data_type",
|
||||||
|
character_maximum_length as "char_max_length",
|
||||||
|
numeric_precision as "numeric_precision",
|
||||||
|
numeric_scale as "numeric_scale",
|
||||||
|
column_default as "default_value"
|
||||||
|
from information_schema.columns
|
||||||
|
where
|
||||||
|
table_schema <> 'information_schema'
|
||||||
|
and table_schema <> 'pg_catalog'
|
||||||
|
and table_schema !~ '^pg_toast'
|
||||||
|
and (
|
||||||
|
('tables:' || table_schema || '.' || table_name) =OBJECT_ID_CONDITION
|
||||||
|
or
|
||||||
|
('views:' || table_schema || '.' || table_name) =OBJECT_ID_CONDITION
|
||||||
|
)
|
||||||
|
order by ordinal_position
|
||||||
|
`;
|
@ -0,0 +1,10 @@
|
|||||||
|
module.exports = `
|
||||||
|
select
|
||||||
|
basecol.constraint_name,
|
||||||
|
basecol.constraint_schema,
|
||||||
|
basecol.column_name as "column_name",
|
||||||
|
basecol.table_schema,
|
||||||
|
basecol.table_name,
|
||||||
|
basecol.ordinal_position
|
||||||
|
from information_schema.key_column_usage basecol
|
||||||
|
`;
|
@ -0,0 +1,10 @@
|
|||||||
|
module.exports = `
|
||||||
|
select
|
||||||
|
fk.constraint_name as "constraint_name",
|
||||||
|
fk.constraint_schema as "constraint_schema",
|
||||||
|
fk.update_rule as "update_action",
|
||||||
|
fk.delete_rule as "delete_action",
|
||||||
|
fk.unique_constraint_name as "unique_constraint_name",
|
||||||
|
fk.unique_constraint_schema as "unique_constraint_schema"
|
||||||
|
from information_schema.referential_constraints fk
|
||||||
|
`;
|
@ -0,0 +1,8 @@
|
|||||||
|
module.exports = `
|
||||||
|
select
|
||||||
|
base.table_name as "table_name",
|
||||||
|
base.table_schema as "table_schema",
|
||||||
|
base.constraint_name as "constraint_name",
|
||||||
|
base.constraint_schema as "constraint_schema"
|
||||||
|
from information_schema.table_constraints base
|
||||||
|
`;
|
24
plugins/dbgate-plugin-oracle/src/backend/sql/foreignKeys.js
Normal file
24
plugins/dbgate-plugin-oracle/src/backend/sql/foreignKeys.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
module.exports = `
|
||||||
|
select
|
||||||
|
fk.constraint_name as "constraint_name",
|
||||||
|
fk.constraint_schema as "constraint_schema",
|
||||||
|
base.table_name as "pure_name",
|
||||||
|
base.table_schema as "schema_name",
|
||||||
|
fk.update_rule as "update_action",
|
||||||
|
fk.delete_rule as "delete_action",
|
||||||
|
ref.table_name as "ref_table_name",
|
||||||
|
ref.table_schema as "ref_schema_name",
|
||||||
|
basecol.column_name as "column_name",
|
||||||
|
refcol.column_name as "ref_column_name"
|
||||||
|
from information_schema.referential_constraints fk
|
||||||
|
inner join information_schema.table_constraints base on fk.constraint_name = base.constraint_name and fk.constraint_schema = base.constraint_schema
|
||||||
|
inner join information_schema.table_constraints ref on fk.unique_constraint_name = ref.constraint_name and fk.unique_constraint_schema = ref.constraint_schema #REFTABLECOND#
|
||||||
|
inner join information_schema.key_column_usage basecol on base.table_name = basecol.table_name and base.constraint_name = basecol.constraint_name
|
||||||
|
inner join information_schema.key_column_usage refcol on ref.table_name = refcol.table_name and ref.constraint_name = refcol.constraint_name and basecol.ordinal_position = refcol.ordinal_position
|
||||||
|
where
|
||||||
|
base.table_schema <> 'information_schema'
|
||||||
|
and base.table_schema <> 'pg_catalog'
|
||||||
|
and base.table_schema !~ '^pg_toast'
|
||||||
|
and ('tables:' || base.table_schema || '.' || base.table_name) =OBJECT_ID_CONDITION
|
||||||
|
order by basecol.ordinal_position
|
||||||
|
`;
|
@ -0,0 +1,8 @@
|
|||||||
|
module.exports = `
|
||||||
|
select
|
||||||
|
f_table_schema as "schema_name",
|
||||||
|
f_table_name as "pure_name",
|
||||||
|
f_geography_column as "column_name"
|
||||||
|
from public.geography_columns
|
||||||
|
where ('tables:' || f_table_schema || '.' || f_table_name) =OBJECT_ID_CONDITION
|
||||||
|
`;
|
@ -0,0 +1,8 @@
|
|||||||
|
module.exports = `
|
||||||
|
select
|
||||||
|
f_table_schema as "schema_name",
|
||||||
|
f_table_name as "pure_name",
|
||||||
|
f_geometry_column as "column_name"
|
||||||
|
from public.geometry_columns
|
||||||
|
where ('tables:' || f_table_schema || '.' || f_table_name) =OBJECT_ID_CONDITION
|
||||||
|
`;
|
44
plugins/dbgate-plugin-oracle/src/backend/sql/index.js
Normal file
44
plugins/dbgate-plugin-oracle/src/backend/sql/index.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
const columns = require('./columns');
|
||||||
|
const tableModifications = require('./tableList');
|
||||||
|
const tableList = require('./tableList');
|
||||||
|
const viewModifications = require('./views');
|
||||||
|
const matviewModifications = require('./matviewModifications');
|
||||||
|
const primaryKeys = require('./primaryKeys');
|
||||||
|
const foreignKeys = require('./foreignKeys');
|
||||||
|
const views = require('./views');
|
||||||
|
const matviews = require('./matviews');
|
||||||
|
const routines = require('./routines');
|
||||||
|
const routineModifications = require('./routineModifications');
|
||||||
|
const matviewColumns = require('./matviewColumns');
|
||||||
|
const indexes = require('./indexes');
|
||||||
|
const indexcols = require('./indexcols');
|
||||||
|
const uniqueNames = require('./uniqueNames');
|
||||||
|
const geometryColumns = require('./geometryColumns');
|
||||||
|
const geographyColumns = require('./geographyColumns');
|
||||||
|
|
||||||
|
const fk_keyColumnUsage = require('./fk_key_column_usage');
|
||||||
|
const fk_referentialConstraints = require('./fk_referential_constraints');
|
||||||
|
const fk_tableConstraints = require('./fk_table_constraints');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
columns,
|
||||||
|
tableModifications,
|
||||||
|
tableList,
|
||||||
|
viewModifications,
|
||||||
|
primaryKeys,
|
||||||
|
foreignKeys,
|
||||||
|
fk_keyColumnUsage,
|
||||||
|
fk_referentialConstraints,
|
||||||
|
fk_tableConstraints,
|
||||||
|
views,
|
||||||
|
routines,
|
||||||
|
routineModifications,
|
||||||
|
matviews,
|
||||||
|
matviewModifications,
|
||||||
|
matviewColumns,
|
||||||
|
indexes,
|
||||||
|
indexcols,
|
||||||
|
uniqueNames,
|
||||||
|
geometryColumns,
|
||||||
|
geographyColumns,
|
||||||
|
};
|
24
plugins/dbgate-plugin-oracle/src/backend/sql/indexcols.js
Normal file
24
plugins/dbgate-plugin-oracle/src/backend/sql/indexcols.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
module.exports = `
|
||||||
|
select
|
||||||
|
a.attname as "column_name",
|
||||||
|
a.attnum as "attnum",
|
||||||
|
a.attrelid as "oid"
|
||||||
|
from
|
||||||
|
pg_class t,
|
||||||
|
pg_class i,
|
||||||
|
pg_attribute a,
|
||||||
|
pg_index ix,
|
||||||
|
pg_namespace c
|
||||||
|
where
|
||||||
|
t.oid = ix.indrelid
|
||||||
|
and a.attnum = ANY(ix.indkey)
|
||||||
|
and a.attrelid = t.oid
|
||||||
|
and i.oid = ix.indexrelid
|
||||||
|
and t.relkind = 'r'
|
||||||
|
and ix.indisprimary = false
|
||||||
|
and t.relnamespace = c.oid
|
||||||
|
and c.nspname != 'pg_catalog'
|
||||||
|
and ('tables:' || c.nspname || '.' || t.relname) =OBJECT_ID_CONDITION
|
||||||
|
order by
|
||||||
|
t.relname
|
||||||
|
`;
|
25
plugins/dbgate-plugin-oracle/src/backend/sql/indexes.js
Normal file
25
plugins/dbgate-plugin-oracle/src/backend/sql/indexes.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
module.exports = `
|
||||||
|
select
|
||||||
|
t.relname as "table_name",
|
||||||
|
c.nspname as "schema_name",
|
||||||
|
i.relname as "index_name",
|
||||||
|
ix.indisprimary as "is_primary",
|
||||||
|
ix.indisunique as "is_unique",
|
||||||
|
ix.indkey as "indkey",
|
||||||
|
t.oid as "oid"
|
||||||
|
from
|
||||||
|
pg_class t,
|
||||||
|
pg_class i,
|
||||||
|
pg_index ix,
|
||||||
|
pg_namespace c
|
||||||
|
where
|
||||||
|
t.oid = ix.indrelid
|
||||||
|
and i.oid = ix.indexrelid
|
||||||
|
and t.relkind = 'r'
|
||||||
|
and ix.indisprimary = false
|
||||||
|
and t.relnamespace = c.oid
|
||||||
|
and c.nspname != 'pg_catalog'
|
||||||
|
and ('tables:' || c.nspname || '.' || t.relname) =OBJECT_ID_CONDITION
|
||||||
|
order by
|
||||||
|
t.relname
|
||||||
|
`;
|
@ -0,0 +1,17 @@
|
|||||||
|
module.exports = `
|
||||||
|
SELECT pg_namespace.nspname AS "schema_name"
|
||||||
|
, pg_class.relname AS "pure_name"
|
||||||
|
, pg_attribute.attname AS "column_name"
|
||||||
|
, pg_catalog.format_type(pg_attribute.atttypid, pg_attribute.atttypmod) AS "data_type"
|
||||||
|
FROM pg_catalog.pg_class
|
||||||
|
INNER JOIN pg_catalog.pg_namespace
|
||||||
|
ON pg_class.relnamespace = pg_namespace.oid
|
||||||
|
INNER JOIN pg_catalog.pg_attribute
|
||||||
|
ON pg_class.oid = pg_attribute.attrelid
|
||||||
|
-- Keeps only materialized views, and non-db/catalog/index columns
|
||||||
|
WHERE pg_class.relkind = 'm'
|
||||||
|
AND pg_attribute.attnum >= 1
|
||||||
|
AND ('matviews:' || pg_namespace.nspname || '.' || pg_class.relname) =OBJECT_ID_CONDITION
|
||||||
|
|
||||||
|
ORDER BY pg_attribute.attnum
|
||||||
|
`;
|
@ -0,0 +1,8 @@
|
|||||||
|
module.exports = `
|
||||||
|
select
|
||||||
|
matviewname as "pure_name",
|
||||||
|
schemaname as "schema_name",
|
||||||
|
md5(definition) as "hash_code"
|
||||||
|
from
|
||||||
|
pg_catalog.pg_matviews WHERE schemaname NOT LIKE 'pg_%'
|
||||||
|
`;
|
10
plugins/dbgate-plugin-oracle/src/backend/sql/matviews.js
Normal file
10
plugins/dbgate-plugin-oracle/src/backend/sql/matviews.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
module.exports = `
|
||||||
|
select
|
||||||
|
matviewname as "pure_name",
|
||||||
|
schemaname as "schema_name",
|
||||||
|
definition as "definition",
|
||||||
|
md5(definition) as "hash_code"
|
||||||
|
from
|
||||||
|
pg_catalog.pg_matviews WHERE schemaname NOT LIKE 'pg_%'
|
||||||
|
and ('matviews:' || schemaname || '.' || matviewname) =OBJECT_ID_CONDITION
|
||||||
|
`;
|
17
plugins/dbgate-plugin-oracle/src/backend/sql/primaryKeys.js
Normal file
17
plugins/dbgate-plugin-oracle/src/backend/sql/primaryKeys.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
module.exports = `
|
||||||
|
select
|
||||||
|
table_constraints.constraint_schema as "constraint_schema",
|
||||||
|
table_constraints.constraint_name as "constraint_name",
|
||||||
|
table_constraints.table_schema as "schema_name",
|
||||||
|
table_constraints.table_name as "pure_name",
|
||||||
|
key_column_usage.column_name as "column_name"
|
||||||
|
from information_schema.table_constraints
|
||||||
|
inner join information_schema.key_column_usage on table_constraints.table_name = key_column_usage.table_name and table_constraints.constraint_name = key_column_usage.constraint_name
|
||||||
|
where
|
||||||
|
table_constraints.table_schema <> 'information_schema'
|
||||||
|
and table_constraints.table_schema <> 'pg_catalog'
|
||||||
|
and table_constraints.table_schema !~ '^pg_toast'
|
||||||
|
and table_constraints.constraint_type = 'PRIMARY KEY'
|
||||||
|
and ('tables:' || table_constraints.table_schema || '.' || table_constraints.table_name) =OBJECT_ID_CONDITION
|
||||||
|
order by key_column_usage.ordinal_position
|
||||||
|
`;
|
@ -0,0 +1,10 @@
|
|||||||
|
module.exports = `
|
||||||
|
select
|
||||||
|
routine_name as "pure_name",
|
||||||
|
routine_schema as "schema_name",
|
||||||
|
md5(routine_definition) as "hash_code",
|
||||||
|
routine_type as "object_type"
|
||||||
|
from
|
||||||
|
information_schema.routines where routine_schema != 'information_schema' and routine_schema != 'pg_catalog'
|
||||||
|
and routine_type in ('PROCEDURE', 'FUNCTION')
|
||||||
|
`;
|
17
plugins/dbgate-plugin-oracle/src/backend/sql/routines.js
Normal file
17
plugins/dbgate-plugin-oracle/src/backend/sql/routines.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
module.exports = `
|
||||||
|
select
|
||||||
|
routine_name as "pure_name",
|
||||||
|
routine_schema as "schema_name",
|
||||||
|
routine_definition as "definition",
|
||||||
|
md5(routine_definition) as "hash_code",
|
||||||
|
routine_type as "object_type",
|
||||||
|
data_type as "data_type",
|
||||||
|
external_language as "language"
|
||||||
|
from
|
||||||
|
information_schema.routines where routine_schema != 'information_schema' and routine_schema != 'pg_catalog'
|
||||||
|
and (
|
||||||
|
(routine_type = 'PROCEDURE' and ('procedures:' || routine_schema || '.' || routine_name) =OBJECT_ID_CONDITION)
|
||||||
|
or
|
||||||
|
(routine_type = 'FUNCTION' and ('functions:' || routine_schema || '.' || routine_name) =OBJECT_ID_CONDITION)
|
||||||
|
)
|
||||||
|
`;
|
18
plugins/dbgate-plugin-oracle/src/backend/sql/tableList.js
Normal file
18
plugins/dbgate-plugin-oracle/src/backend/sql/tableList.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
module.exports = `
|
||||||
|
select ao.owner as "schema_name", ao.object_name as "pure_name"
|
||||||
|
from all_objects ao
|
||||||
|
where exists(select null from user_objects uo where uo.object_id = ao.object_id)
|
||||||
|
and object_type = 'TABLE'
|
||||||
|
`;
|
||||||
|
/*
|
||||||
|
module.exports = `
|
||||||
|
select infoTables.table_schema as "schema_name", infoTables.table_name as "pure_name"
|
||||||
|
from information_schema.tables infoTables
|
||||||
|
where infoTables.table_type not like '%VIEW%'
|
||||||
|
and ('tables:' || infoTables.table_schema || '.' || infoTables.table_name) =OBJECT_ID_CONDITION
|
||||||
|
and infoTables.table_schema <> 'pg_catalog'
|
||||||
|
and infoTables.table_schema <> 'information_schema'
|
||||||
|
and infoTables.table_schema <> 'pg_internal'
|
||||||
|
and infoTables.table_schema !~ '^pg_toast'
|
||||||
|
`;
|
||||||
|
*/
|
@ -0,0 +1,28 @@
|
|||||||
|
module.exports = `
|
||||||
|
select infoTables.table_schema as "schema_name", infoTables.table_name as "pure_name",
|
||||||
|
(
|
||||||
|
select md5(string_agg(
|
||||||
|
infoColumns.column_name || '|' || infoColumns.data_type || '|' || infoColumns.is_nullable::varchar(255) || '|' || coalesce(infoColumns.character_maximum_length, -1)::varchar(255)
|
||||||
|
|| '|' || coalesce(infoColumns.numeric_precision, -1)::varchar(255) ,
|
||||||
|
',' order by infoColumns.ordinal_position
|
||||||
|
)) as "hash_code_columns"
|
||||||
|
from information_schema.columns infoColumns
|
||||||
|
where infoColumns.table_schema = infoTables.table_schema and infoColumns.table_name = infoTables.table_name
|
||||||
|
),
|
||||||
|
(
|
||||||
|
select md5(string_agg(
|
||||||
|
infoConstraints.constraint_name || '|' || infoConstraints.constraint_type ,
|
||||||
|
',' order by infoConstraints.constraint_name
|
||||||
|
)) as "hash_code_constraints"
|
||||||
|
from information_schema.table_constraints infoConstraints
|
||||||
|
where infoConstraints.table_schema = infoTables.table_schema and infoConstraints.table_name = infoTables.table_name
|
||||||
|
)
|
||||||
|
|
||||||
|
from information_schema.tables infoTables
|
||||||
|
where infoTables.table_type not like '%VIEW%'
|
||||||
|
and ('tables:' || infoTables.table_schema || '.' || infoTables.table_name) =OBJECT_ID_CONDITION
|
||||||
|
and infoTables.table_schema <> 'pg_catalog'
|
||||||
|
and infoTables.table_schema <> 'information_schema'
|
||||||
|
and infoTables.table_schema <> 'pg_internal'
|
||||||
|
and infoTables.table_schema !~ '^pg_toast'
|
||||||
|
`;
|
@ -0,0 +1,3 @@
|
|||||||
|
module.exports = `
|
||||||
|
select conname as "constraint_name" from pg_constraint where contype = 'u'
|
||||||
|
`;
|
@ -0,0 +1,8 @@
|
|||||||
|
module.exports = `
|
||||||
|
select
|
||||||
|
table_name as "pure_name",
|
||||||
|
table_schema as "schema_name",
|
||||||
|
md5(view_definition) as "hash_code"
|
||||||
|
from
|
||||||
|
information_schema.views where table_schema != 'information_schema' and table_schema != 'pg_catalog'
|
||||||
|
`;
|
9
plugins/dbgate-plugin-oracle/src/backend/sql/views.js
Normal file
9
plugins/dbgate-plugin-oracle/src/backend/sql/views.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
module.exports = `
|
||||||
|
select
|
||||||
|
ao.owner as "schema_name", ao.object_name as "pure_name",
|
||||||
|
'later' as "create_sql",
|
||||||
|
object_id as "hash_code"
|
||||||
|
from all_objects ao
|
||||||
|
where exists(select null from user_objects uo where uo.object_id = ao.object_id)
|
||||||
|
and object_type = 'VIEW'
|
||||||
|
`;
|
100
plugins/dbgate-plugin-oracle/src/frontend/Dumper.js
Normal file
100
plugins/dbgate-plugin-oracle/src/frontend/Dumper.js
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
const { SqlDumper, arrayToHexString, testEqualTypes } = global.DBGATE_TOOLS;
|
||||||
|
|
||||||
|
class Dumper extends SqlDumper {
|
||||||
|
/** @param type {import('dbgate-types').TransformType} */
|
||||||
|
transform(type, dumpExpr) {
|
||||||
|
switch (type) {
|
||||||
|
case 'GROUP:YEAR':
|
||||||
|
case 'YEAR':
|
||||||
|
this.put('^extract(^year ^from %c)', dumpExpr);
|
||||||
|
break;
|
||||||
|
case 'MONTH':
|
||||||
|
this.put('^extract(^month ^from %c)', dumpExpr);
|
||||||
|
break;
|
||||||
|
case 'DAY':
|
||||||
|
this.put('^extract(^day ^from %c)', dumpExpr);
|
||||||
|
break;
|
||||||
|
case 'GROUP:MONTH':
|
||||||
|
this.put("^to_char(%c, '%s')", dumpExpr, 'YYYY-MM');
|
||||||
|
break;
|
||||||
|
case 'GROUP:DAY':
|
||||||
|
this.put("^to_char(%c, '%s')", dumpExpr, 'YYYY-MM-DD');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dumpExpr();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dropRecreatedTempTable(tmptable) {
|
||||||
|
this.putCmd('^drop ^table %i ^cascade', tmptable);
|
||||||
|
}
|
||||||
|
|
||||||
|
renameTable(obj, newname) {
|
||||||
|
this.putCmd('^alter ^table %f ^rename ^to %i', obj, newname);
|
||||||
|
}
|
||||||
|
|
||||||
|
renameColumn(column, newcol) {
|
||||||
|
this.putCmd('^alter ^table %f ^rename ^column %i ^to %i', column, column.columnName, newcol);
|
||||||
|
}
|
||||||
|
|
||||||
|
dropTable(obj, options = {}) {
|
||||||
|
this.put('^drop ^table');
|
||||||
|
if (options.testIfExists) this.put(' ^if ^exists');
|
||||||
|
this.put(' %f', obj);
|
||||||
|
this.endCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
//public override void CreateIndex(IndexInfo ix)
|
||||||
|
//{
|
||||||
|
//}
|
||||||
|
|
||||||
|
enableConstraints(table, enabled) {
|
||||||
|
this.putCmd('^alter ^table %f %k ^trigger ^all', table, enabled ? 'enable' : 'disable');
|
||||||
|
}
|
||||||
|
|
||||||
|
columnDefinition(col, options) {
|
||||||
|
if (col.autoIncrement) {
|
||||||
|
this.put('^serial');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
super.columnDefinition(col, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
changeColumn(oldcol, newcol, constraints) {
|
||||||
|
if (oldcol.columnName != newcol.columnName) {
|
||||||
|
this.putCmd('^alter ^table %f ^rename ^column %i ^to %i', oldcol, oldcol.columnName, newcol.columnName);
|
||||||
|
}
|
||||||
|
if (!testEqualTypes(oldcol, newcol)) {
|
||||||
|
this.putCmd('^alter ^table %f ^alter ^column %i ^type %s', oldcol, newcol.columnName, newcol.dataType);
|
||||||
|
}
|
||||||
|
if (oldcol.notNull != newcol.notNull) {
|
||||||
|
if (newcol.notNull) this.putCmd('^alter ^table %f ^alter ^column %i ^set ^not ^null', newcol, newcol.columnName);
|
||||||
|
else this.putCmd('^alter ^table %f ^alter ^column %i ^drop ^not ^null', newcol, newcol.columnName);
|
||||||
|
}
|
||||||
|
if (oldcol.defaultValue != newcol.defaultValue) {
|
||||||
|
if (newcol.defaultValue == null) {
|
||||||
|
this.putCmd('^alter ^table %f ^alter ^column %i ^drop ^default', newcol, newcol.columnName);
|
||||||
|
} else {
|
||||||
|
this.putCmd(
|
||||||
|
'^alter ^table %f ^alter ^column %i ^set ^default %s',
|
||||||
|
newcol,
|
||||||
|
newcol.columnName,
|
||||||
|
newcol.defaultValue
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
putValue(value) {
|
||||||
|
if (value === true) this.putRaw('true');
|
||||||
|
else if (value === false) this.putRaw('false');
|
||||||
|
else super.putValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
putByteArrayValue(value) {
|
||||||
|
this.putRaw(`e'\\\\x${arrayToHexString(value)}'`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Dumper;
|
200
plugins/dbgate-plugin-oracle/src/frontend/drivers.js
Normal file
200
plugins/dbgate-plugin-oracle/src/frontend/drivers.js
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
const { driverBase } = global.DBGATE_TOOLS;
|
||||||
|
const Dumper = require('./Dumper');
|
||||||
|
const { oracleSplitterOptions } = require('dbgate-query-splitter/lib/options');
|
||||||
|
|
||||||
|
const spatialTypes = ['GEOGRAPHY'];
|
||||||
|
|
||||||
|
/** @type {import('dbgate-types').SqlDialect} */
|
||||||
|
const dialect = {
|
||||||
|
rangeSelect: true,
|
||||||
|
ilike: true,
|
||||||
|
// stringEscapeChar: '\\',
|
||||||
|
stringEscapeChar: "'",
|
||||||
|
fallbackDataType: 'varchar',
|
||||||
|
anonymousPrimaryKey: true,
|
||||||
|
enableConstraintsPerTable: true,
|
||||||
|
dropColumnDependencies: ['dependencies'],
|
||||||
|
quoteIdentifier(s) {
|
||||||
|
return '"' + s + '"';
|
||||||
|
},
|
||||||
|
stringAgg: true,
|
||||||
|
|
||||||
|
createColumn: true,
|
||||||
|
dropColumn: true,
|
||||||
|
changeColumn: true,
|
||||||
|
createIndex: true,
|
||||||
|
dropIndex: true,
|
||||||
|
createForeignKey: true,
|
||||||
|
dropForeignKey: true,
|
||||||
|
createPrimaryKey: true,
|
||||||
|
dropPrimaryKey: true,
|
||||||
|
createUnique: true,
|
||||||
|
dropUnique: true,
|
||||||
|
createCheck: true,
|
||||||
|
dropCheck: true,
|
||||||
|
|
||||||
|
dropReferencesWhenDropTable: true,
|
||||||
|
|
||||||
|
predefinedDataTypes: [
|
||||||
|
'bigint',
|
||||||
|
'bigserial',
|
||||||
|
'bit',
|
||||||
|
'varbit',
|
||||||
|
'boolean',
|
||||||
|
'box',
|
||||||
|
'bytea',
|
||||||
|
'char(20)',
|
||||||
|
'varchar(250)',
|
||||||
|
'cidr',
|
||||||
|
'circle',
|
||||||
|
'date',
|
||||||
|
'double precision',
|
||||||
|
'inet',
|
||||||
|
'int',
|
||||||
|
'interval',
|
||||||
|
'json',
|
||||||
|
'jsonb',
|
||||||
|
'line',
|
||||||
|
'lseg',
|
||||||
|
'macaddr',
|
||||||
|
'macaddr8',
|
||||||
|
'money',
|
||||||
|
'numeric(10,2)',
|
||||||
|
'path',
|
||||||
|
'pg_lsn',
|
||||||
|
'pg_snapshot',
|
||||||
|
'point',
|
||||||
|
'polygon',
|
||||||
|
'real',
|
||||||
|
'smallint',
|
||||||
|
'smallserial',
|
||||||
|
'serial',
|
||||||
|
'text',
|
||||||
|
'time',
|
||||||
|
'timetz',
|
||||||
|
'timestamp',
|
||||||
|
'timestamptz',
|
||||||
|
'tsquery',
|
||||||
|
'tsvector',
|
||||||
|
'txid_snapshot',
|
||||||
|
'uuid',
|
||||||
|
'xml',
|
||||||
|
],
|
||||||
|
|
||||||
|
createColumnViewExpression(columnName, dataType, source, alias) {
|
||||||
|
if (dataType && spatialTypes.includes(dataType.toUpperCase())) {
|
||||||
|
return {
|
||||||
|
exprType: 'call',
|
||||||
|
func: 'ST_AsText',
|
||||||
|
alias: alias || columnName,
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
exprType: 'column',
|
||||||
|
columnName,
|
||||||
|
source,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const oracleDriverBase = {
|
||||||
|
...driverBase,
|
||||||
|
dumperClass: Dumper,
|
||||||
|
dialect,
|
||||||
|
// showConnectionField: (field, values) =>
|
||||||
|
// ['server', 'port', 'user', 'password', 'defaultDatabase', 'singleDatabase'].includes(field),
|
||||||
|
getQuerySplitterOptions: () => oracleSplitterOptions,
|
||||||
|
readOnlySessions: true,
|
||||||
|
|
||||||
|
databaseUrlPlaceholder: 'e.g. oracledb://user:password@localhost:1521',
|
||||||
|
|
||||||
|
showConnectionField: (field, values) => {
|
||||||
|
if (field == 'useDatabaseUrl') return true;
|
||||||
|
if (values.useDatabaseUrl) {
|
||||||
|
return ['databaseUrl', 'isReadOnly'].includes(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
['authType', 'user', 'password', 'defaultDatabase', 'singleDatabase', 'isReadOnly'].includes(field) ||
|
||||||
|
(values.authType == 'socket' && ['socketPath'].includes(field)) ||
|
||||||
|
(values.authType != 'socket' && ['server', 'port'].includes(field))
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
beforeConnectionSave: connection => {
|
||||||
|
const { databaseUrl } = connection;
|
||||||
|
if (databaseUrl) {
|
||||||
|
const m = databaseUrl.match(/\/([^/]+)($|\?)/);
|
||||||
|
return {
|
||||||
|
...connection,
|
||||||
|
singleDatabase: !!m,
|
||||||
|
defaultDatabase: m ? m[1] : null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return connection;
|
||||||
|
},
|
||||||
|
|
||||||
|
__analyserInternals: {
|
||||||
|
refTableCond: '',
|
||||||
|
},
|
||||||
|
|
||||||
|
getNewObjectTemplates() {
|
||||||
|
return [
|
||||||
|
{ label: 'New view', sql: 'CREATE VIEW myview\nAS\nSELECT * FROM table1' },
|
||||||
|
{ label: 'New materialized view', sql: 'CREATE MATERIALIZED VIEW myview\nAS\nSELECT * FROM table1' },
|
||||||
|
{
|
||||||
|
label: 'New procedure',
|
||||||
|
sql: `CREATE PROCEDURE myproc (arg1 INT)
|
||||||
|
LANGUAGE SQL
|
||||||
|
AS $$
|
||||||
|
SELECT * FROM table1;
|
||||||
|
$$`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'New function (plpgsql)',
|
||||||
|
sql: `CREATE FUNCTION myfunc (arg1 INT)
|
||||||
|
RETURNS INT
|
||||||
|
AS $$
|
||||||
|
BEGIN
|
||||||
|
RETURN 1;
|
||||||
|
END
|
||||||
|
$$ LANGUAGE plpgsql;`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
|
|
||||||
|
authTypeLabel: 'Connection mode',
|
||||||
|
defaultAuthTypeName: 'hostPort',
|
||||||
|
defaultSocketPath: '/var/run/oracledb',
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @type {import('dbgate-types').EngineDriver} */
|
||||||
|
const oracleDriver = {
|
||||||
|
...oracleDriverBase,
|
||||||
|
engine: 'oracle@dbgate-plugin-oracle',
|
||||||
|
title: 'OracleDB',
|
||||||
|
defaultPort: 1521,
|
||||||
|
dialect: {
|
||||||
|
...dialect,
|
||||||
|
materializedViews: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
dialectByVersion(version) {
|
||||||
|
if (version) {
|
||||||
|
return {
|
||||||
|
...dialect,
|
||||||
|
materializedViews:
|
||||||
|
version &&
|
||||||
|
version.versionMajor != null &&
|
||||||
|
version.versionMinor != null &&
|
||||||
|
(version.versionMajor > 9 || version.versionMajor == 9 || version.versionMinor >= 3),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return dialect;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = [oracleDriver];
|
6
plugins/dbgate-plugin-oracle/src/frontend/index.js
Normal file
6
plugins/dbgate-plugin-oracle/src/frontend/index.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import drivers from './drivers';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
packageName: 'dbgate-plugin-oracle',
|
||||||
|
drivers,
|
||||||
|
};
|
33
plugins/dbgate-plugin-oracle/test/testdb.sql
Normal file
33
plugins/dbgate-plugin-oracle/test/testdb.sql
Normal file
File diff suppressed because one or more lines are too long
40
plugins/dbgate-plugin-oracle/webpack-backend.config.js
Normal file
40
plugins/dbgate-plugin-oracle/webpack-backend.config.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
var webpack = require('webpack');
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
context: __dirname + '/src/backend',
|
||||||
|
|
||||||
|
entry: {
|
||||||
|
app: './index.js',
|
||||||
|
},
|
||||||
|
target: 'node',
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, 'dist'),
|
||||||
|
filename: 'backend.js',
|
||||||
|
libraryTarget: 'commonjs2',
|
||||||
|
},
|
||||||
|
|
||||||
|
// uncomment for disable minimalization
|
||||||
|
// optimization: {
|
||||||
|
// minimize: false,
|
||||||
|
// },
|
||||||
|
|
||||||
|
plugins: [
|
||||||
|
new webpack.IgnorePlugin({
|
||||||
|
checkResource(resource) {
|
||||||
|
const lazyImports = ['oracledb', 'uws'];
|
||||||
|
if (!lazyImports.includes(resource)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
require.resolve(resource);
|
||||||
|
} catch (err) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = config;
|
30
plugins/dbgate-plugin-oracle/webpack-frontend.config.js
Normal file
30
plugins/dbgate-plugin-oracle/webpack-frontend.config.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
var webpack = require('webpack');
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
context: __dirname + '/src/frontend',
|
||||||
|
|
||||||
|
entry: {
|
||||||
|
app: './index.js',
|
||||||
|
},
|
||||||
|
target: 'web',
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, 'dist'),
|
||||||
|
filename: 'frontend.js',
|
||||||
|
libraryTarget: 'var',
|
||||||
|
library: 'plugin',
|
||||||
|
},
|
||||||
|
|
||||||
|
plugins: [
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'global.DBGATE_TOOLS': 'window.DBGATE_TOOLS',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
|
||||||
|
// uncomment for disable minimalization
|
||||||
|
// optimization: {
|
||||||
|
// minimize: false,
|
||||||
|
// },
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = config;
|
@ -8195,6 +8195,11 @@ optionator@^0.8.1, optionator@^0.8.3:
|
|||||||
resolved "https://registry.yarnpkg.com/opts/-/opts-2.0.2.tgz#a17e189fbbfee171da559edd8a42423bc5993ce1"
|
resolved "https://registry.yarnpkg.com/opts/-/opts-2.0.2.tgz#a17e189fbbfee171da559edd8a42423bc5993ce1"
|
||||||
integrity sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg==
|
integrity sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg==
|
||||||
|
|
||||||
|
oracledb@^5.0.0:
|
||||||
|
version "5.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/oracledb/-/oracledb-5.5.0.tgz#0cf9af5d0c0815f74849ae9ed56aee823514d71b"
|
||||||
|
integrity sha512-i5cPvMENpZP8nnqptB6l0pjiOyySj1IISkbM4Hr3yZEDdANo2eezarwZb9NQ8fTh5pRjmgpZdSyIbnn9N3AENw==
|
||||||
|
|
||||||
os-browserify@^0.3.0:
|
os-browserify@^0.3.0:
|
||||||
version "0.3.0"
|
version "0.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27"
|
resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27"
|
||||||
|
Loading…
Reference in New Issue
Block a user