mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-17 22:36:01 +00:00
PostgreSQL export to SQL and XML bytea contents #1228
This commit is contained in:
@@ -16,7 +16,7 @@ class QueryStreamTableWriter {
|
|||||||
this.sesid = sesid;
|
this.sesid = sesid;
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeFromQuery(structure, resultIndex, chartDefinition, autoDetectCharts = false) {
|
initializeFromQuery(structure, resultIndex, chartDefinition, autoDetectCharts = false, options = {}) {
|
||||||
this.jslid = crypto.randomUUID();
|
this.jslid = crypto.randomUUID();
|
||||||
this.currentFile = path.join(jsldir(), `${this.jslid}.jsonl`);
|
this.currentFile = path.join(jsldir(), `${this.jslid}.jsonl`);
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
@@ -24,6 +24,7 @@ class QueryStreamTableWriter {
|
|||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
...structure,
|
...structure,
|
||||||
__isStreamHeader: true,
|
__isStreamHeader: true,
|
||||||
|
...options
|
||||||
}) + '\n'
|
}) + '\n'
|
||||||
);
|
);
|
||||||
this.currentStream = fs.createWriteStream(this.currentFile, { flags: 'a' });
|
this.currentStream = fs.createWriteStream(this.currentFile, { flags: 'a' });
|
||||||
@@ -166,7 +167,7 @@ class StreamHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
recordset(columns) {
|
recordset(columns, options) {
|
||||||
if (this.rowsLimitOverflow) {
|
if (this.rowsLimitOverflow) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -176,7 +177,8 @@ class StreamHandler {
|
|||||||
Array.isArray(columns) ? { columns } : columns,
|
Array.isArray(columns) ? { columns } : columns,
|
||||||
this.queryStreamInfoHolder.resultIndex,
|
this.queryStreamInfoHolder.resultIndex,
|
||||||
this.frontMatter?.[`chart-${this.queryStreamInfoHolder.resultIndex + 1}`],
|
this.frontMatter?.[`chart-${this.queryStreamInfoHolder.resultIndex + 1}`],
|
||||||
this.autoDetectCharts
|
this.autoDetectCharts,
|
||||||
|
options
|
||||||
);
|
);
|
||||||
this.queryStreamInfoHolder.resultIndex += 1;
|
this.queryStreamInfoHolder.resultIndex += 1;
|
||||||
this.rowCounter = 0;
|
this.rowCounter = 0;
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ export class SqlDumper implements AlterProcessor {
|
|||||||
else if (_isNumber(value)) this.putRaw(value.toString());
|
else if (_isNumber(value)) this.putRaw(value.toString());
|
||||||
else if (_isDate(value)) this.putStringValue(new Date(value).toISOString());
|
else if (_isDate(value)) this.putStringValue(new Date(value).toISOString());
|
||||||
else if (value?.type == 'Buffer' && _isArray(value?.data)) this.putByteArrayValue(value?.data);
|
else if (value?.type == 'Buffer' && _isArray(value?.data)) this.putByteArrayValue(value?.data);
|
||||||
|
else if (value?.$binary) this.putByteArrayValue(Buffer.from(value?.$binary.base64, 'base64'));
|
||||||
else if (value?.$bigint) this.putRaw(value?.$bigint);
|
else if (value?.$bigint) this.putRaw(value?.$bigint);
|
||||||
else if (_isPlainObject(value) || _isArray(value)) this.putStringValue(JSON.stringify(value));
|
else if (_isPlainObject(value) || _isArray(value)) this.putStringValue(JSON.stringify(value));
|
||||||
else this.put('^null');
|
else this.put('^null');
|
||||||
|
|||||||
@@ -43,6 +43,14 @@ export function hexStringToArray(inputString) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function base64ToHex(base64String) {
|
||||||
|
const binaryString = atob(base64String);
|
||||||
|
const hexString = Array.from(binaryString, c =>
|
||||||
|
c.charCodeAt(0).toString(16).padStart(2, '0')
|
||||||
|
).join('');
|
||||||
|
return '0x' + hexString.toUpperCase();
|
||||||
|
};
|
||||||
|
|
||||||
export function parseCellValue(value, editorTypes?: DataEditorTypesBehaviour) {
|
export function parseCellValue(value, editorTypes?: DataEditorTypesBehaviour) {
|
||||||
if (!_isString(value)) return value;
|
if (!_isString(value)) return value;
|
||||||
|
|
||||||
@@ -230,6 +238,13 @@ export function stringifyCellValue(
|
|||||||
if (value === true) return { value: 'true', gridStyle: 'valueCellStyle' };
|
if (value === true) return { value: 'true', gridStyle: 'valueCellStyle' };
|
||||||
if (value === false) return { value: 'false', gridStyle: 'valueCellStyle' };
|
if (value === false) return { value: 'false', gridStyle: 'valueCellStyle' };
|
||||||
|
|
||||||
|
if (value?.$binary?.base64) {
|
||||||
|
return {
|
||||||
|
value: base64ToHex(value.$binary.base64),
|
||||||
|
gridStyle: 'valueCellStyle',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (editorTypes?.parseHexAsBuffer) {
|
if (editorTypes?.parseHexAsBuffer) {
|
||||||
if (value?.type == 'Buffer' && _isArray(value.data)) {
|
if (value?.type == 'Buffer' && _isArray(value.data)) {
|
||||||
return { value: '0x' + arrayToHexString(value.data), gridStyle: 'valueCellStyle' };
|
return { value: '0x' + arrayToHexString(value.data), gridStyle: 'valueCellStyle' };
|
||||||
|
|||||||
@@ -47,6 +47,9 @@ function transformRow(row, columnsToTransform) {
|
|||||||
if (dataTypeName == 'geography') {
|
if (dataTypeName == 'geography') {
|
||||||
row[columnName] = extractGeographyDate(row[columnName]);
|
row[columnName] = extractGeographyDate(row[columnName]);
|
||||||
}
|
}
|
||||||
|
else if (dataTypeName == 'bytea' && row[columnName]) {
|
||||||
|
row[columnName] = { $binary: { base64: Buffer.from(row[columnName]).toString('base64') } };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return row;
|
return row;
|
||||||
@@ -142,7 +145,7 @@ const drivers = driverBases.map(driverBase => ({
|
|||||||
conid,
|
conid,
|
||||||
};
|
};
|
||||||
|
|
||||||
const datatypes = await this.query(dbhan, `SELECT oid, typname FROM pg_type WHERE typname in ('geography')`);
|
const datatypes = await this.query(dbhan, `SELECT oid, typname FROM pg_type WHERE typname in ('geography', 'bytea')`);
|
||||||
const typeIdToName = _.fromPairs(datatypes.rows.map(cur => [cur.oid, cur.typname]));
|
const typeIdToName = _.fromPairs(datatypes.rows.map(cur => [cur.oid, cur.typname]));
|
||||||
dbhan['typeIdToName'] = typeIdToName;
|
dbhan['typeIdToName'] = typeIdToName;
|
||||||
|
|
||||||
@@ -164,7 +167,14 @@ const drivers = driverBases.map(driverBase => ({
|
|||||||
}
|
}
|
||||||
const res = await dbhan.client.query({ text: sql, rowMode: 'array' });
|
const res = await dbhan.client.query({ text: sql, rowMode: 'array' });
|
||||||
const columns = extractPostgresColumns(res, dbhan);
|
const columns = extractPostgresColumns(res, dbhan);
|
||||||
return { rows: (res.rows || []).map(row => zipDataRow(row, columns)), columns };
|
|
||||||
|
const transormableTypeNames = Object.values(dbhan.typeIdToName ?? {});
|
||||||
|
const columnsToTransform = columns.filter(x => transormableTypeNames.includes(x.dataTypeName));
|
||||||
|
|
||||||
|
const zippedRows = (res.rows || []).map(row => zipDataRow(row, columns));
|
||||||
|
const transformedRows = zippedRows.map(row => transformRow(row, columnsToTransform));
|
||||||
|
|
||||||
|
return { rows: transformedRows, columns };
|
||||||
},
|
},
|
||||||
stream(dbhan, sql, options) {
|
stream(dbhan, sql, options) {
|
||||||
const handleNotice = notice => {
|
const handleNotice = notice => {
|
||||||
@@ -191,7 +201,7 @@ const drivers = driverBases.map(driverBase => ({
|
|||||||
if (!wasHeader) {
|
if (!wasHeader) {
|
||||||
columns = extractPostgresColumns(query._result, dbhan);
|
columns = extractPostgresColumns(query._result, dbhan);
|
||||||
if (columns && columns.length > 0) {
|
if (columns && columns.length > 0) {
|
||||||
options.recordset(columns);
|
options.recordset(columns, { engine: driverBase.engine });
|
||||||
}
|
}
|
||||||
wasHeader = true;
|
wasHeader = true;
|
||||||
}
|
}
|
||||||
@@ -310,6 +320,7 @@ const drivers = driverBases.map(driverBase => ({
|
|||||||
columns = extractPostgresColumns(query._result, dbhan);
|
columns = extractPostgresColumns(query._result, dbhan);
|
||||||
pass.write({
|
pass.write({
|
||||||
__isStreamHeader: true,
|
__isStreamHeader: true,
|
||||||
|
engine: driverBase.engine,
|
||||||
...(structure || { columns }),
|
...(structure || { columns }),
|
||||||
});
|
});
|
||||||
wasHeader = true;
|
wasHeader = true;
|
||||||
|
|||||||
@@ -45,6 +45,10 @@ class StringifyStream extends stream.Transform {
|
|||||||
|
|
||||||
elementValue(element, value) {
|
elementValue(element, value) {
|
||||||
this.startElement(element);
|
this.startElement(element);
|
||||||
|
if (value?.$binary?.base64) {
|
||||||
|
const buffer = Buffer.from(value.$binary.base64, 'base64');
|
||||||
|
value = '0x' +buffer.toString('hex').toUpperCase();
|
||||||
|
}
|
||||||
this.push(escapeXml(`${value}`));
|
this.push(escapeXml(`${value}`));
|
||||||
this.endElement(element);
|
this.endElement(element);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user