1
1
mirror of https://github.com/Fabio286/antares.git synced 2025-06-05 21:59:22 +02:00

fix(PostgreSQL): wrong values exporting table content

This commit is contained in:
2022-04-02 11:44:55 +02:00
parent 638a88a1fb
commit 0f9c991f53
4 changed files with 88 additions and 100 deletions

View File

@ -39,6 +39,7 @@ module.exports = {
schemaEdit: false, schemaEdit: false,
schemaDrop: false, schemaDrop: false,
schemaExport: false, schemaExport: false,
exportByChunks: false,
schemaImport: false, schemaImport: false,
tableSettings: false, tableSettings: false,
tableOptions: false, tableOptions: false,

View File

@ -35,6 +35,7 @@ module.exports = {
schemaEdit: true, schemaEdit: true,
schemaDrop: true, schemaDrop: true,
schemaExport: true, schemaExport: true,
exportByChunks: true,
schemaImport: true, schemaImport: true,
tableSettings: true, tableSettings: true,
viewSettings: true, viewSettings: true,

View File

@ -1,5 +1,5 @@
import { SqlExporter } from './SqlExporter'; import { SqlExporter } from './SqlExporter';
import { BLOB, BIT, DATE, DATETIME, FLOAT, SPATIAL, IS_MULTI_SPATIAL, NUMBER } from 'common/fieldTypes'; import { BLOB, BIT, DATE, DATETIME, FLOAT, NUMBER, TEXT_SEARCH } from 'common/fieldTypes';
import hexToBinary from 'common/libs/hexToBinary'; import hexToBinary from 'common/libs/hexToBinary';
import { getArrayDepth } from 'common/libs/getArrayDepth'; import { getArrayDepth } from 'common/libs/getArrayDepth';
import moment from 'moment'; import moment from 'moment';
@ -17,12 +17,14 @@ SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0; SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8'; SET client_encoding = 'UTF8';
SET standard_conforming_strings = on; SET standard_conforming_strings = on;
-- SELECT pg_catalog.set_config('search_path', '', false); SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false; SET check_function_bodies = false;
SET xmloption = content; SET xmloption = content;
SET client_min_messages = warning; SET client_min_messages = warning;
SET row_security = off;\n\n\n`; SET row_security = off;\n\n\n`;
if (this.schemaName !== 'public') dump += `CREATE SCHEMA "${this.schemaName}";\n\n`;
dump += await this.getCreateTypes(); dump += await this.getCreateTypes();
return dump; return dump;
@ -43,19 +45,19 @@ SET row_security = off;\n\n\n`;
}; };
// Table columns // Table columns
const { rows } = await this._client const { rows } = await this._client.raw(`
.select('*') SELECT *
.schema('information_schema') FROM "information_schema"."columns"
.from('columns') WHERE "table_schema" = '${this.schemaName}'
.where({ table_schema: `= '${this.schemaName}'`, table_name: `= '${tableName}'` }) AND "table_name" = '${tableName}'
.orderBy({ ordinal_position: 'ASC' }) ORDER BY "ordinal_position" ASC
.run(); `, { schema: 'information_schema' });
if (!rows.length) return ''; if (!rows.length) return '';
for (const column of rows) { for (const column of rows) {
let fieldType = column.data_type; let fieldType = column.data_type;
if (fieldType === 'USER-DEFINED') fieldType = column.udt_name; if (fieldType === 'USER-DEFINED') fieldType = `"${this.schemaName}".${column.udt_name}`;
else if (fieldType === 'ARRAY') { else if (fieldType === 'ARRAY') {
if (Object.keys(arrayTypes).includes(fieldType)) if (Object.keys(arrayTypes).includes(fieldType))
fieldType = arrayTypes[type] + '[]'; fieldType = arrayTypes[type] + '[]';
@ -71,8 +73,7 @@ SET row_security = off;\n\n\n`;
if (column.column_default) { if (column.column_default) {
columnArr.push(`DEFAULT ${column.column_default}`); columnArr.push(`DEFAULT ${column.column_default}`);
if (column.column_default.includes('nextval')) { if (column.column_default.includes('nextval')) {
let sequenceName = column.column_default.split('\'')[1]; const sequenceName = column.column_default.split('\'')[1];
if (sequenceName.includes('.')) sequenceName = sequenceName.split('.')[1];
sequences.push(sequenceName); sequences.push(sequenceName);
} }
} }
@ -82,7 +83,9 @@ SET row_security = off;\n\n\n`;
} }
// Table sequences // Table sequences
for (const sequence of sequences) { for (let sequence of sequences) {
if (sequence.includes('.')) sequence = sequence.split('.')[1];
const { rows } = await this._client const { rows } = await this._client
.select('*') .select('*')
.schema('information_schema') .schema('information_schema')
@ -91,7 +94,7 @@ SET row_security = off;\n\n\n`;
.run(); .run();
if (rows.length) { if (rows.length) {
createSql += `CREATE SEQUENCE "${sequence}" createSql += `CREATE SEQUENCE "${this.schemaName}"."${sequence}"
START WITH ${rows[0].start_value} START WITH ${rows[0].start_value}
INCREMENT BY ${rows[0].increment} INCREMENT BY ${rows[0].increment}
MINVALUE ${rows[0].minimum_value} MINVALUE ${rows[0].minimum_value}
@ -103,7 +106,7 @@ SET row_security = off;\n\n\n`;
} }
// Table create // Table create
createSql += `\nCREATE TABLE "${tableName}"( createSql += `\nCREATE TABLE "${this.schemaName}"."${tableName}"(
${columnsSql.join(',\n ')} ${columnsSql.join(',\n ')}
);\n`; );\n`;
@ -119,7 +122,7 @@ SET row_security = off;\n\n\n`;
.run(); .run();
for (const index of indexes) for (const index of indexes)
createSql += `${index.indexdef.replaceAll(`${this.schemaName}.`, '')};\n`; createSql += `${index.indexdef};\n`;
// Table foreigns // Table foreigns
const { rows: foreigns } = await this._client.raw(` const { rows: foreigns } = await this._client.raw(`
@ -147,15 +150,15 @@ SET row_security = off;\n\n\n`;
`); `);
for (const foreign of foreigns) { for (const foreign of foreigns) {
this._postTablesSql += `\nALTER TABLE ONLY "${tableName}" this._postTablesSql += `\nALTER TABLE ONLY "${this.schemaName}"."${tableName}"
ADD CONSTRAINT "${foreign.constraint_name}" FOREIGN KEY ("${foreign.column_name}") REFERENCES "${foreign.foreign_table_name}" ("${foreign.foreign_column_name}") ON UPDATE ${foreign.update_rule} ON DELETE ${foreign.delete_rule};\n`; ADD CONSTRAINT "${foreign.constraint_name}" FOREIGN KEY ("${foreign.column_name}") REFERENCES "${this.schemaName}"."${foreign.foreign_table_name}" ("${foreign.foreign_column_name}") ON UPDATE ${foreign.update_rule} ON DELETE ${foreign.delete_rule};\n`;
} }
return createSql; return createSql;
} }
getDropTable (tableName) { getDropTable (tableName) {
return `DROP TABLE IF EXISTS "${tableName}";`; return `DROP TABLE IF EXISTS "${this.schemaName}"."${tableName}";`;
} }
async * getTableInsert (tableName) { async * getTableInsert (tableName) {
@ -166,16 +169,12 @@ SET row_security = off;\n\n\n`;
if (countResults.rows.length === 1) rowCount = countResults.rows[0].count; if (countResults.rows.length === 1) rowCount = countResults.rows[0].count;
if (rowCount > 0) { if (rowCount > 0) {
let queryLength = 0;
let rowsWritten = 0;
const { sqlInsertDivider, sqlInsertAfter } = this._options;
const columns = await this._client.getTableColumns({ const columns = await this._client.getTableColumns({
table: tableName, table: tableName,
schema: this.schemaName schema: this.schemaName
}); });
const notGeneratedColumns = columns.filter(col => !col.generated); const columnNames = columns.map(col => '"' + col.name + '"').join(', ');
const columnNames = notGeneratedColumns.map(col => '"' + col.name + '"').join(', ');
yield sqlStr; yield sqlStr;
@ -190,20 +189,12 @@ SET row_security = off;\n\n\n`;
return; return;
} }
let sqlInsertString = `INSERT INTO "${tableName}" (${columnNames}) VALUES`; let sqlInsertString = `INSERT INTO "${this.schemaName}"."${tableName}" (${columnNames}) VALUES`;
if (
(sqlInsertDivider === 'bytes' && queryLength >= sqlInsertAfter * 1024) ||
(sqlInsertDivider === 'rows' && rowsWritten === sqlInsertAfter)
) {
queryLength = 0;
rowsWritten = 0;
}
sqlInsertString += ' ('; sqlInsertString += ' (';
for (const i in notGeneratedColumns) { for (const i in columns) {
const column = notGeneratedColumns[i]; const column = columns[i];
const val = row[column.name]; const val = row[column.name];
if (val === null) sqlInsertString += 'NULL'; if (val === null) sqlInsertString += 'NULL';
@ -221,31 +212,24 @@ SET row_security = off;\n\n\n`;
? this.escapeAndQuote(moment(val).format(`YYYY-MM-DD HH:mm:ss${datePrecision}`)) ? this.escapeAndQuote(moment(val).format(`YYYY-MM-DD HH:mm:ss${datePrecision}`))
: this.escapeAndQuote(val); : this.escapeAndQuote(val);
} }
else if (column.isArray) {
let parsedVal;
if (Array.isArray(val))
parsedVal = JSON.stringify(val).replaceAll('[', '{').replaceAll(']', '}');
else
parsedVal = typeof val === 'string' ? val.replaceAll('[', '{').replaceAll(']', '}') : '';
sqlInsertString += `'${parsedVal}'`;
}
else if (TEXT_SEARCH.includes(column.type))
sqlInsertString += `'${val.replaceAll('\'', '\'\'')}'`;
else if (BIT.includes(column.type)) else if (BIT.includes(column.type))
sqlInsertString += `b'${hexToBinary(Buffer.from(val).toString('hex'))}'`; sqlInsertString += `b'${hexToBinary(Buffer.from(val).toString('hex'))}'`;
else if (BLOB.includes(column.type)) else if (BLOB.includes(column.type))
sqlInsertString += `X'${val.toString('hex').toUpperCase()}'`; sqlInsertString += `decode('${val.toString('hex').toUpperCase()}', 'hex')`;
else if (NUMBER.includes(column.type)) else if (NUMBER.includes(column.type))
sqlInsertString += val; sqlInsertString += val;
else if (FLOAT.includes(column.type)) else if (FLOAT.includes(column.type))
sqlInsertString += parseFloat(val); sqlInsertString += parseFloat(val);
else if (SPATIAL.includes(column.type)) {
let geoJson;
if (IS_MULTI_SPATIAL.includes(column.type)) {
const features = [];
for (const element of val)
features.push(this.getMarkers(element));
geoJson = {
type: 'FeatureCollection',
features
};
}
else
geoJson = this._getGeoJSON(val);
sqlInsertString += `ST_GeomFromGeoJSON('${JSON.stringify(geoJson)}')`;
}
else if (val === '') sqlInsertString += '\'\''; else if (val === '') sqlInsertString += '\'\'';
else { else {
sqlInsertString += typeof val === 'string' sqlInsertString += typeof val === 'string'
@ -255,14 +239,12 @@ SET row_security = off;\n\n\n`;
: val; : val;
} }
if (parseInt(i) !== notGeneratedColumns.length - 1) if (parseInt(i) !== columns.length - 1)
sqlInsertString += ', '; sqlInsertString += ', ';
} }
sqlInsertString += ');\n'; sqlInsertString += ');\n';
queryLength += sqlInsertString.length;
rowsWritten++;
yield sqlInsertString; yield sqlInsertString;
} }
@ -293,7 +275,7 @@ SET row_security = off;\n\n\n`;
}, []); }, []);
for (const type of typesArr) { for (const type of typesArr) {
sqlString += `CREATE TYPE "${type.name}" AS ENUM ( sqlString += `CREATE TYPE "${this.schemaName}"."${type.name}" AS ENUM (
${type.enums.join(',\n\t')} ${type.enums.join(',\n\t')}
);`; );`;
} }
@ -339,7 +321,7 @@ SET row_security = off;\n\n\n`;
); );
if (aggregateDef.length) if (aggregateDef.length)
sqlString += '\n\n' + aggregateDef[0].format.replaceAll(`${this.schemaName}.`, ''); sqlString += '\n\n' + aggregateDef[0].format;
} }
} }
@ -353,25 +335,25 @@ SET row_security = off;\n\n\n`;
for (const view of views) { for (const view of views) {
sqlString += `\nDROP VIEW IF EXISTS "${view.viewname}";\n`; sqlString += `\nDROP VIEW IF EXISTS "${view.viewname}";\n`;
const { rows: columns } = await this._client // const { rows: columns } = await this._client
.select('*') // .select('*')
.schema('information_schema') // .schema('information_schema')
.from('columns') // .from('columns')
.where({ table_schema: `= '${this.schemaName}'`, table_name: `= '${view.viewname}'` }) // .where({ table_schema: `= '${this.schemaName}'`, table_name: `= '${view.viewname}'` })
.orderBy({ ordinal_position: 'ASC' }) // .orderBy({ ordinal_position: 'ASC' })
.run(); // .run();
sqlString += ` // sqlString += `
CREATE VIEW "${view.viewname}" AS // CREATE VIEW "${this.schemaName}"."${view.viewname}" AS
SELECT // SELECT
${columns.reduce((acc, curr) => { // ${columns.reduce((acc, curr) => {
const fieldType = curr.data_type === 'USER-DEFINED' ? curr.udt_name : curr.data_type; // const fieldType = curr.data_type === 'USER-DEFINED' ? curr.udt_name : curr.data_type;
acc.push(`NULL::${fieldType}${curr.character_maximum_length ? `(${curr.character_maximum_length})` : ''} AS "${curr.column_name}"`); // acc.push(`NULL::${fieldType}${curr.character_maximum_length ? `(${curr.character_maximum_length})` : ''} AS "${curr.column_name}"`);
return acc; // return acc;
}, []).join(',\n ')}; // }, []).join(',\n ')};
`; // `;
sqlString += `\nCREATE OR REPLACE VIEW "${view.viewname}" AS \n${view.definition}\n`; sqlString += `\nCREATE OR REPLACE VIEW "${this.schemaName}"."${view.viewname}" AS \n${view.definition}\n`;
} }
return sqlString; return sqlString;
@ -389,7 +371,7 @@ SELECT
const { rows: functionDef } = await this._client.raw( const { rows: functionDef } = await this._client.raw(
`SELECT pg_get_functiondef((SELECT oid FROM pg_proc WHERE proname = '${func.name}')) AS definition` `SELECT pg_get_functiondef((SELECT oid FROM pg_proc WHERE proname = '${func.name}')) AS definition`
); );
sqlString += `\n${functionDef[0].definition.replaceAll(`${this.schemaName}.`, '')};\n`; sqlString += `\n${functionDef[0].definition};\n`;
} }
const { rows: triggers } = await this._client.raw( const { rows: triggers } = await this._client.raw(
@ -409,7 +391,7 @@ SELECT
}, []); }, []);
for (const trigger of remappedTriggers) for (const trigger of remappedTriggers)
sqlString += `\nCREATE TRIGGER "${trigger.trigger_name}" ${trigger.action_timing} ${trigger.events.join(' OR ')} ON "${trigger.event_object_table}" FOR EACH ${trigger.action_orientation} ${trigger.action_statement};\n`; sqlString += `\nCREATE TRIGGER "${trigger.trigger_name}" ${trigger.action_timing} ${trigger.events.join(' OR ')} ON "${this.schemaName}"."${trigger.event_object_table}" FOR EACH ${trigger.action_orientation} ${trigger.action_statement};\n`;
return sqlString; return sqlString;
} }
@ -424,7 +406,7 @@ SELECT
const { rows: functionDef } = await this._client.raw( const { rows: functionDef } = await this._client.raw(
`SELECT pg_get_functiondef((SELECT oid FROM pg_proc WHERE proname = '${func.name}')) AS definition` `SELECT pg_get_functiondef((SELECT oid FROM pg_proc WHERE proname = '${func.name}')) AS definition`
); );
sqlString += `\n${functionDef[0].definition.replaceAll(`${this.schemaName}.`, '')};\n`; sqlString += `\n${functionDef[0].definition};\n`;
} }
sqlString += await this.getCreateAggregates(); sqlString += await this.getCreateAggregates();
@ -442,7 +424,7 @@ SELECT
const { rows: functionDef } = await this._client.raw( const { rows: functionDef } = await this._client.raw(
`SELECT pg_get_functiondef((SELECT oid FROM pg_proc WHERE proname = '${func.name}')) AS definition` `SELECT pg_get_functiondef((SELECT oid FROM pg_proc WHERE proname = '${func.name}')) AS definition`
); );
sqlString += `\n${functionDef[0].definition.replaceAll(`${this.schemaName}.`, '')};\n`; sqlString += `\n${functionDef[0].definition};\n`;
} }
return sqlString; return sqlString;

View File

@ -192,28 +192,29 @@
> >
<input v-model="options.includes[key]" type="checkbox"><i class="form-icon" /> {{ $tc(`word.${key}`, 2) }} <input v-model="options.includes[key]" type="checkbox"><i class="form-icon" /> {{ $tc(`word.${key}`, 2) }}
</label> </label>
<div v-if="customizations.exportByChunks">
<div class="h6 mt-4 mb-2"> <div class="h6 mt-4 mb-2">
{{ $t('message.newInserStmtEvery') }}: {{ $t('message.newInserStmtEvery') }}:
</div>
<div class="columns">
<div class="column col-6">
<input
v-model.number="options.sqlInsertAfter"
type="number"
class="form-input"
value="250"
>
</div> </div>
<div class="column col-6"> <div class="columns">
<select v-model="options.sqlInsertDivider" class="form-select"> <div class="column col-6">
<option value="bytes"> <input
KiB v-model.number="options.sqlInsertAfter"
</option> type="number"
<option value="rows"> class="form-input"
{{ $tc('word.row', 2) }} value="250"
</option> >
</select> </div>
<div class="column col-6">
<select v-model="options.sqlInsertDivider" class="form-select">
<option value="bytes">
KiB
</option>
<option value="rows">
{{ $tc('word.row', 2) }}
</option>
</select>
</div>
</div> </div>
</div> </div>
@ -306,6 +307,9 @@ export default {
currentWorkspace () { currentWorkspace () {
return this.getWorkspace(this.selectedWorkspace); return this.getWorkspace(this.selectedWorkspace);
}, },
customizations () {
return this.currentWorkspace.customizations;
},
schemaItems () { schemaItems () {
const db = this.currentWorkspace.structure.find(db => db.name === this.selectedSchema); const db = this.currentWorkspace.structure.find(db => db.name === this.selectedSchema);
if (db) if (db)