mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Ensure that when pasting a row in query tool grid, default value is used for autogenerated/serial columns. #5922
This commit is contained in:
parent
1d7d6561f6
commit
861c66d180
Binary file not shown.
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 17 KiB |
@ -178,7 +178,12 @@ Data Editing Options
|
|||||||
| | | |
|
| | | |
|
||||||
| | * Click *Copy with headers* to copy the highlighted content along with the header. | |
|
| | * Click *Copy with headers* to copy the highlighted content along with the header. | |
|
||||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||||
| *Paste* | Click the *Paste* icon to paste a previously copied row into a new row. | Accesskey + P |
|
| *Paste* | Click the *Paste* icon to paste a previously copied row with or without serial/identity values: | Accesskey + P |
|
||||||
|
| | | |
|
||||||
|
| | * Click the *Paste* icon to paste a previously copied row into a new row. | |
|
||||||
|
| | | |
|
||||||
|
| | * Click the *Paste with SERIAL/IDENTITY values?* if you want to paste the copied column values | |
|
||||||
|
| | in the serial/identity columns. | |
|
||||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||||
| *Delete* | Click the *Delete* icon to mark the selected rows for deletion. These marked rows get deleted | Accesskey + D |
|
| *Delete* | Click the *Delete* icon to mark the selected rows for deletion. These marked rows get deleted | Accesskey + D |
|
||||||
| | when you click the *Save Data Changes* icon. | |
|
| | when you click the *Save Data Changes* icon. | |
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
SELECT DISTINCT att.attname as name, att.attnum as OID, pg_catalog.format_type(ty.oid,NULL) AS datatype,
|
SELECT DISTINCT att.attname as name, att.attnum as OID, pg_catalog.format_type(ty.oid,NULL) AS datatype,
|
||||||
att.attnotnull as not_null, att.atthasdef as has_default_val, des.description
|
att.attnotnull as not_null, att.atthasdef as has_default_val, des.description, seq.seqtypid
|
||||||
FROM pg_catalog.pg_attribute att
|
FROM pg_catalog.pg_attribute att
|
||||||
JOIN pg_catalog.pg_type ty ON ty.oid=atttypid
|
JOIN pg_catalog.pg_type ty ON ty.oid=atttypid
|
||||||
JOIN pg_catalog.pg_namespace tn ON tn.oid=ty.typnamespace
|
JOIN pg_catalog.pg_namespace tn ON tn.oid=ty.typnamespace
|
||||||
@ -11,6 +11,7 @@ FROM pg_catalog.pg_attribute att
|
|||||||
LEFT OUTER JOIN pg_catalog.pg_namespace ns ON ns.oid=cs.relnamespace
|
LEFT OUTER JOIN pg_catalog.pg_namespace ns ON ns.oid=cs.relnamespace
|
||||||
LEFT OUTER JOIN pg_catalog.pg_index pi ON pi.indrelid=att.attrelid AND indisprimary
|
LEFT OUTER JOIN pg_catalog.pg_index pi ON pi.indrelid=att.attrelid AND indisprimary
|
||||||
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=att.attrelid AND des.objsubid=att.attnum AND des.classoid='pg_class'::regclass)
|
LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=att.attrelid AND des.objsubid=att.attnum AND des.classoid='pg_class'::regclass)
|
||||||
|
LEFT OUTER JOIN pg_catalog.pg_sequence seq ON cs.oid=seq.seqrelid
|
||||||
WHERE
|
WHERE
|
||||||
att.attrelid = {{ tid|qtLiteral(conn) }}::oid
|
att.attrelid = {{ tid|qtLiteral(conn) }}::oid
|
||||||
{% if clid %}
|
{% if clid %}
|
||||||
|
@ -530,6 +530,8 @@ export class ResultSetUtils {
|
|||||||
'not_null': c.not_null,
|
'not_null': c.not_null,
|
||||||
'has_default_val': c.has_default_val,
|
'has_default_val': c.has_default_val,
|
||||||
'is_array': arrayBracketIdx > -1 && arrayBracketIdx + 2 == columnTypeInternal.length,
|
'is_array': arrayBracketIdx > -1 && arrayBracketIdx + 2 == columnTypeInternal.length,
|
||||||
|
'seqtypid': c.seqtypid,
|
||||||
|
'isPK': isPK
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -559,14 +561,19 @@ export class ResultSetUtils {
|
|||||||
return columns;
|
return columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
processClipboardVal(columnVal, col, rawCopiedVal) {
|
processClipboardVal(columnVal, col, rawCopiedVal, pasteSerials) {
|
||||||
if(columnVal === '') {
|
if(columnVal === '' ) {
|
||||||
if(col.has_default_val) {
|
if(col.has_default_val) {
|
||||||
|
// if column has default value
|
||||||
columnVal = undefined;
|
columnVal = undefined;
|
||||||
} else if(rawCopiedVal === null) {
|
} else if(rawCopiedVal === null) {
|
||||||
columnVal = null;
|
columnVal = null;
|
||||||
}
|
}
|
||||||
|
} else if (col.has_default_val && col.seqtypid && !pasteSerials) {
|
||||||
|
// if column has default value and is serial type
|
||||||
|
columnVal = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(col.cell === 'boolean') {
|
if(col.cell === 'boolean') {
|
||||||
if(columnVal == 'true') {
|
if(columnVal == 'true') {
|
||||||
columnVal = true;
|
columnVal = true;
|
||||||
@ -581,7 +588,7 @@ export class ResultSetUtils {
|
|||||||
return columnVal;
|
return columnVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
processRows(result, columns, fromClipboard=false) {
|
processRows(result, columns, fromClipboard=false, pasteSerials=false) {
|
||||||
let retVal = [];
|
let retVal = [];
|
||||||
if(!_.isArray(result) || !_.size(result)) {
|
if(!_.isArray(result) || !_.size(result)) {
|
||||||
return retVal;
|
return retVal;
|
||||||
@ -598,7 +605,7 @@ export class ResultSetUtils {
|
|||||||
let columnVal = rec[col.pos];
|
let columnVal = rec[col.pos];
|
||||||
/* If the source is clipboard, then it needs some extra handling */
|
/* If the source is clipboard, then it needs some extra handling */
|
||||||
if(fromClipboard) {
|
if(fromClipboard) {
|
||||||
columnVal = this.processClipboardVal(columnVal, col, copiedRowsObjects[recIdx]?.[col.key]);
|
columnVal = this.processClipboardVal(columnVal, col, copiedRowsObjects[recIdx]?.[col.key], pasteSerials);
|
||||||
}
|
}
|
||||||
rowObj[col.key] = columnVal;
|
rowObj[col.key] = columnVal;
|
||||||
}
|
}
|
||||||
@ -1207,14 +1214,14 @@ export function ResultSet() {
|
|||||||
}, [selectedRows, queryData, dataChangeStore, rows]);
|
}, [selectedRows, queryData, dataChangeStore, rows]);
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
const triggerAddRows = (_rows, fromClipboard)=>{
|
const triggerAddRows = (_rows, fromClipboard, pasteSerials)=>{
|
||||||
let insPosn = 0;
|
let insPosn = 0;
|
||||||
if(selectedRows.size > 0) {
|
if(selectedRows.size > 0) {
|
||||||
let selectedRowsSorted = Array.from(selectedRows);
|
let selectedRowsSorted = Array.from(selectedRows);
|
||||||
selectedRowsSorted.sort();
|
selectedRowsSorted.sort();
|
||||||
insPosn = _.findIndex(rows, (r)=>rowKeyGetter(r)==selectedRowsSorted[selectedRowsSorted.length-1])+1;
|
insPosn = _.findIndex(rows, (r)=>rowKeyGetter(r)==selectedRowsSorted[selectedRowsSorted.length-1])+1;
|
||||||
}
|
}
|
||||||
let newRows = rsu.current.processRows(_rows, columns, fromClipboard);
|
let newRows = rsu.current.processRows(_rows, columns, fromClipboard, pasteSerials);
|
||||||
setRows((prev)=>[
|
setRows((prev)=>[
|
||||||
...prev.slice(0, insPosn),
|
...prev.slice(0, insPosn),
|
||||||
...newRows,
|
...newRows,
|
||||||
|
@ -53,6 +53,7 @@ export function ResultSetToolbar({containerRef, canEdit, totalRowCount}) {
|
|||||||
const [checkedMenuItems, setCheckedMenuItems] = React.useState({});
|
const [checkedMenuItems, setCheckedMenuItems] = React.useState({});
|
||||||
/* Menu button refs */
|
/* Menu button refs */
|
||||||
const copyMenuRef = React.useRef(null);
|
const copyMenuRef = React.useRef(null);
|
||||||
|
const pasetMenuRef = React.useRef(null);
|
||||||
|
|
||||||
const queryToolPref = queryToolCtx.preferences.sqleditor;
|
const queryToolPref = queryToolCtx.preferences.sqleditor;
|
||||||
|
|
||||||
@ -72,8 +73,8 @@ export function ResultSetToolbar({containerRef, canEdit, totalRowCount}) {
|
|||||||
field_separator: queryToolPref.results_grid_field_separator,
|
field_separator: queryToolPref.results_grid_field_separator,
|
||||||
});
|
});
|
||||||
let copiedRows = copyUtils.getCopiedRows();
|
let copiedRows = copyUtils.getCopiedRows();
|
||||||
eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_ADD_ROWS, copiedRows, true);
|
eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_ADD_ROWS, copiedRows, true, checkedMenuItems['paste_with_serials']);
|
||||||
}, [queryToolPref]);
|
}, [queryToolPref, checkedMenuItems['paste_with_serials']]);
|
||||||
const copyData = ()=>{
|
const copyData = ()=>{
|
||||||
eventBus.fireEvent(QUERY_TOOL_EVENTS.COPY_DATA, checkedMenuItems['copy_with_headers']);
|
eventBus.fireEvent(QUERY_TOOL_EVENTS.COPY_DATA, checkedMenuItems['copy_with_headers']);
|
||||||
};
|
};
|
||||||
@ -163,6 +164,8 @@ export function ResultSetToolbar({containerRef, canEdit, totalRowCount}) {
|
|||||||
name="menu-copyheader" ref={copyMenuRef} onClick={openMenu} />
|
name="menu-copyheader" ref={copyMenuRef} onClick={openMenu} />
|
||||||
<PgIconButton title={gettext('Paste')} icon={<PasteIcon />}
|
<PgIconButton title={gettext('Paste')} icon={<PasteIcon />}
|
||||||
accesskey={shortcut_key(queryToolPref.btn_paste_row)} disabled={!canEdit} onClick={pasteRows} />
|
accesskey={shortcut_key(queryToolPref.btn_paste_row)} disabled={!canEdit} onClick={pasteRows} />
|
||||||
|
<PgIconButton title={gettext('Paste options')} icon={<KeyboardArrowDownIcon />} splitButton
|
||||||
|
name="menu-pasteoptions" ref={pasetMenuRef} onClick={openMenu} />
|
||||||
<PgIconButton title={gettext('Delete')} icon={<DeleteRoundedIcon />}
|
<PgIconButton title={gettext('Delete')} icon={<DeleteRoundedIcon />}
|
||||||
accesskey={shortcut_key(queryToolPref.btn_delete_row)} disabled={buttonsDisabled['delete-rows'] || !canEdit} onClick={deleteRows} />
|
accesskey={shortcut_key(queryToolPref.btn_delete_row)} disabled={buttonsDisabled['delete-rows'] || !canEdit} onClick={deleteRows} />
|
||||||
</PgButtonGroup>
|
</PgButtonGroup>
|
||||||
@ -188,6 +191,14 @@ export function ResultSetToolbar({containerRef, canEdit, totalRowCount}) {
|
|||||||
>
|
>
|
||||||
<PgMenuItem hasCheck value="copy_with_headers" checked={checkedMenuItems['copy_with_headers']} onClick={checkMenuClick}>{gettext('Copy with headers')}</PgMenuItem>
|
<PgMenuItem hasCheck value="copy_with_headers" checked={checkedMenuItems['copy_with_headers']} onClick={checkMenuClick}>{gettext('Copy with headers')}</PgMenuItem>
|
||||||
</PgMenu>
|
</PgMenu>
|
||||||
|
<PgMenu
|
||||||
|
anchorRef={pasetMenuRef}
|
||||||
|
open={menuOpenId=='menu-pasteoptions'}
|
||||||
|
onClose={handleMenuClose}
|
||||||
|
label={gettext('Paste Options Menu')}
|
||||||
|
>
|
||||||
|
<PgMenuItem hasCheck value="paste_with_serials" checked={checkedMenuItems['paste_with_serials']} onClick={checkMenuClick}>{gettext('Paste with SERIAL/IDENTITY values?')}</PgMenuItem>
|
||||||
|
</PgMenu>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,9 @@ def get_columns_types(is_query_tool, columns_info, table_oid, conn, has_oids):
|
|||||||
col['has_default_val'] = \
|
col['has_default_val'] = \
|
||||||
rset['rows'][key]['has_default_val']
|
rset['rows'][key]['has_default_val']
|
||||||
|
|
||||||
|
col_type['seqtypid'] = col['seqtypid'] = \
|
||||||
|
rset['rows'][key]['seqtypid']
|
||||||
|
|
||||||
else:
|
else:
|
||||||
for row in rset['rows']:
|
for row in rset['rows']:
|
||||||
if row['oid'] == col['table_column']:
|
if row['oid'] == col['table_column']:
|
||||||
@ -56,10 +59,14 @@ def get_columns_types(is_query_tool, columns_info, table_oid, conn, has_oids):
|
|||||||
|
|
||||||
col_type['has_default_val'] = \
|
col_type['has_default_val'] = \
|
||||||
col['has_default_val'] = row['has_default_val']
|
col['has_default_val'] = row['has_default_val']
|
||||||
|
|
||||||
|
col_type['seqtypid'] = col['seqtypid'] = \
|
||||||
|
rset['rows'][key]['seqtypid']
|
||||||
break
|
break
|
||||||
|
|
||||||
else:
|
else:
|
||||||
col_type['not_null'] = col['not_null'] = None
|
col_type['not_null'] = col['not_null'] = None
|
||||||
col_type['has_default_val'] = col['has_default_val'] = None
|
col_type['has_default_val'] = col['has_default_val'] = None
|
||||||
|
col_type['seqtypid'] = col['seqtypid'] = None
|
||||||
|
|
||||||
return column_types
|
return column_types
|
||||||
|
Loading…
Reference in New Issue
Block a user