Skip to content

Commit 7e86a62

Browse files
committed
Add all missing options to the Import/Export Data functionality, and update the syntax of the COPY command to align with the latest standards. #8583
Updated documentation.
1 parent 5a50160 commit 7e86a62

20 files changed

Lines changed: 922 additions & 156 deletions
161 KB
Loading
28.3 KB
Loading
144 KB
Loading
138 KB
Loading
68.7 KB
Loading

docs/en_US/import_export_data.rst

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,29 @@ Use the fields in the *General* tab to specify import and export preferences:
3333
* Use the drop-down listbox in the *Encoding* field to specify the type of
3434
character encoding.
3535

36+
* use the drop-down listbox in the *On Error* field to specify how to behave
37+
when encountering an error converting a columns input value into its data type.
38+
An error_action value of stop means fail the command, while ignore means discard
39+
the input row and continue with the next one. The default is stop. This option is
40+
available from PG/EPAS version 17 and above.
41+
42+
* use the drop-down listbox in the *Log Verbosity* field to specify the amount
43+
of messages emitted by a COPY command: default or verbose. This is currently
44+
used in Import only when ON_ERROR option is set to ignore. This option is
45+
available from PG/EPAS version 17 and above.
46+
3647
.. image:: images/import_export_options.png
3748
:alt: Import Export data dialog options tab
3849
:align: center
3950

4051
* Use the fields in the *Options* tab to specify additional information:
4152

42-
* Move the *OID* switch to the *Yes* position to include the *OID* column.
43-
The *OID* is a system-assigned value that may not be modified. The default
44-
is *No*.
4553
* Move the *Header* switch to the *Yes* position to include the table header
4654
with the data rows. If you include the table header, the first row of the
4755
file will contain the column names.
56+
* Move the *Freeze* switch to the *Yes* position to requests copying the
57+
data with rows already frozen, just as they would be after running the
58+
VACUUM FREEZE command.
4859
* If you are exporting data, specify the delimiter that will separate the
4960
columns within the target file in the *Delimiter* field. The separating
5061
character can be a colon, semicolon, a vertical bar, or a tab.
@@ -54,8 +65,11 @@ Use the fields in the *General* tab to specify import and export preferences:
5465
be a single quote or a double quote.
5566
* Specify a character that should appear before a data character that matches
5667
the *QUOTE* value in the *Escape* field.
57-
* Use the *NULL Strings* field to specify a string that will represent a null
68+
* Use the *NULL String* field to specify a string that will represent a null
5869
value within the source or target file.
70+
* Use the *Default String* field to specify a string that will represent a default value.
71+
Each time the string is found in the input file, the default value of the corresponding
72+
column will be used. This option is available from PG/EPAS version 16 and above.
5973

6074
Click the *Columns* tab to continue.
6175

@@ -71,29 +85,39 @@ or exported:
7185
the left of the column name. Click an empty spot inside the field to access
7286
the drop-down list.
7387

88+
* If enabled, click inside the *Force Quote columns* field to forces quoting
89+
to be used for all non-NULL values in each specified column. NULL output is
90+
never quoted. To delete a column, click the *x* to the left of the column name.
91+
7492
* If enabled, click inside the *NOT NULL columns* field to select one or more
7593
columns that will not be checked for a NULL value. To delete a column, click
7694
the *x* to the left of the column name.
7795

96+
* If enabled, click inside the *NULL columns* field to match the specified columns
97+
values against the null string, even if it has been quoted, and if a match is
98+
found set the value to NULL. To delete a column, click the *x* to the left of the
99+
column name.
100+
78101
After completing the *Import/Export data* dialog, click the *OK* button to
79-
perform the import or export. pgAdmin will inform you when the background
102+
perform the import or export. pgAdmin will notify you when the background
80103
process completes:
81104

82105
.. image:: images/import_export_complete.png
83106
:alt: Import Export data completion notification
84107
:align: center
85108

86-
Use the **Stop Process** button to stop the Import/Export process.
87109

88-
Use the *Click here for details* link on the notification to open the *Process
110+
Use the *View Processes* button on the notification to open the *Process
89111
Watcher* and review detailed information about the execution of the command
90112
that performed the import or export:
91113

114+
Use the **End Process** button to end the Import/Export process.
115+
92116
.. image:: images/import_export_pw.png
93117
:alt: Import Export data process watcher
94118
:align: center
95119

96-
.. note:: If you are running *pgAdmin* in *Server Mode* you can click on the |sm_icon| icon in the process watcher window to open the file location in the Storage Manager. You can use the :ref:`Storage Manager <storage_manager>` to download the backup file on the client machine .
120+
.. note:: If you are running *pgAdmin* in *Server Mode* you can click on the |sm_icon| icon in the process watcher window to open the file location in the Storage Manager. You can use the :ref:`Storage Manager <storage_manager>` to download the exported file on the client machine .
97121

98122

99123
.. |sm_icon| image:: images/sm_icon.png

docs/en_US/processes.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ Process Watcher
4242

4343
The Process Watcher logs all the activity associated with the process/task and provides
4444
additional information for troubleshooting
45-
Use the **Stop Process** button to stop the Backup process.
45+
Use the **End Process** button to end the process.
4646

4747
.. note:: If you are running *pgAdmin* in *Server Mode* you can click on the |sm_icon| icon in the process watcher window to open the file location in the Storage Manager. You can use the :ref:`Storage Manager <storage_manager>` to download the backup file on the client machine .
4848

docs/en_US/release_notes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ notes for it.
1212
:maxdepth: 1
1313

1414

15+
release_notes_9_4
1516
release_notes_9_3
1617
release_notes_9_2
1718
release_notes_9_1

docs/en_US/release_notes_9_4.rst

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
***********
2+
Version 9.4
3+
***********
4+
5+
Release date: 2025-05-29
6+
7+
This release contains a number of bug fixes and new features since the release of pgAdmin 4 v9.3.
8+
9+
Supported Database Servers
10+
**************************
11+
**PostgreSQL**: 13, 14, 15, 16 and 17
12+
13+
**EDB Advanced Server**: 13, 14, 15, 16 and 17
14+
15+
Bundled PostgreSQL Utilities
16+
****************************
17+
**psql**, **pg_dump**, **pg_dumpall**, **pg_restore**: 17.2
18+
19+
20+
New features
21+
************
22+
23+
| `Issue #8583 <https://github.com/pgadmin-org/pgadmin4/issues/8583>`_ - Add all missing options to the Import/Export Data functionality, and update the syntax of the COPY command to align with the latest standards.
24+
25+
Housekeeping
26+
************
27+
28+
29+
Bug fixes
30+
*********
31+

web/pgadmin/tools/import_export/__init__.py

Lines changed: 39 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,14 @@
2323

2424
from config import PG_DEFAULT_DRIVER
2525
from pgadmin.model import Server
26-
from pgadmin.utils.constants import MIMETYPE_APP_JS, SERVER_NOT_FOUND
26+
from pgadmin.utils.constants import SERVER_NOT_FOUND
2727
from pgadmin.settings import get_setting, store_setting
2828
from pgadmin.tools.user_management.PgAdminPermissions import AllPermissionTypes
2929

3030
MODULE_NAME = 'import_export'
31+
NOT_NULL_COLUMNS = 'not_null_columns'
32+
NULL_COLUMNS = 'null_columns'
33+
FORCE_QUOTE_COLUMNS = 'force_quote_columns'
3134

3235

3336
class ImportExportModule(PgAdminModule):
@@ -142,32 +145,11 @@ def index():
142145
return bad_request(errormsg=_("This URL cannot be called directly."))
143146

144147

145-
def _get_ignored_column_list(data, driver, conn):
146-
"""
147-
Get list of ignored columns for import/export.
148-
:param data: Data.
149-
:param driver: PG Driver.
150-
:param conn: Connection.
151-
:return: return ignored column list.
152-
"""
153-
icols = None
154-
155-
if data['icolumns']:
156-
ignore_cols = data['icolumns']
157-
158-
# format the ignore column list required as per copy command
159-
# requirement
160-
if ignore_cols and len(ignore_cols) > 0:
161-
icols = ", ".join([
162-
driver.qtIdent(conn, col)
163-
for col in ignore_cols])
164-
return icols
165-
166-
167-
def _get_required_column_list(data, driver, conn):
148+
def _get_formatted_column_list(data, key, driver, conn):
168149
"""
169150
Get list of required columns for import/export.
170151
:param data: Data.
152+
:param key: Key.
171153
:param driver: PG Driver.
172154
:param conn: Connection.
173155
:return: return required column list.
@@ -176,8 +158,23 @@ def _get_required_column_list(data, driver, conn):
176158

177159
# format the column import/export list required as per copy command
178160
# requirement
179-
if data['columns']:
180-
columns = data['columns']
161+
162+
# If key is FORCE_QUOTE_COLUMNS and total columns is equal to selected
163+
# columns for force quote then return '*'
164+
if (key in data and 'total_columns' in data and
165+
key == FORCE_QUOTE_COLUMNS and
166+
len(data[key]) == data['total_columns']):
167+
cols = '*'
168+
# if server version is >= 17 and key is either NULL_COLUMNS or
169+
# NOT_NULL_COLUMNS and total columns is equal to selected columns then
170+
# return '*'
171+
elif (key in data and 'total_columns' in data and
172+
conn.manager.version >= 170000 and
173+
key in [NULL_COLUMNS, NOT_NULL_COLUMNS] and
174+
len(data[key]) == data['total_columns']):
175+
cols = '*'
176+
elif key in data:
177+
columns = data[key]
181178
if columns and len(columns) > 0:
182179
for col in columns:
183180
if cols:
@@ -192,8 +189,9 @@ def _get_required_column_list(data, driver, conn):
192189

193190
def _save_import_export_settings(settings):
194191
settings = {key: settings[key] for key in settings if key not in
195-
['icolumns', 'columns', 'database', 'schema', 'table',
196-
'save_btn_icon']}
192+
['columns', 'database', 'schema', 'table', 'save_btn_icon',
193+
'not_null_columns', 'null_columns', 'force_quote_columns',
194+
'total_columns']}
197195

198196
if settings['is_import']:
199197
settings['import_file_name'] = settings['filename']
@@ -283,21 +281,24 @@ def create_import_export_job(sid):
283281
else:
284282
return bad_request(errormsg=_('Please specify a valid file'))
285283

286-
# Get required and ignored column list
287-
icols = _get_ignored_column_list(data, driver, conn)
288-
cols = _get_required_column_list(data, driver, conn)
284+
# Get required and other columns list
285+
cols = _get_formatted_column_list(data, 'columns', driver, conn)
286+
not_null_cols = _get_formatted_column_list(data, NOT_NULL_COLUMNS,
287+
driver, conn)
288+
null_cols = _get_formatted_column_list(data, NULL_COLUMNS, driver,
289+
conn)
290+
quote_cols = _get_formatted_column_list(data, FORCE_QUOTE_COLUMNS,
291+
driver, conn)
289292

290293
# Save the settings
291294
_save_import_export_settings(new_settings)
292295

293296
# Create the COPY FROM/TO from template
294-
query = render_template(
295-
'import_export/sql/cmd.sql',
296-
conn=conn,
297-
data=data,
298-
columns=cols,
299-
ignore_column_list=icols
300-
)
297+
temp_path = 'import_export/sql/#{0}#/cmd.sql'.format(manager.version)
298+
query = render_template(temp_path, conn=conn, data=data, columns=cols,
299+
not_null_columns=not_null_cols,
300+
null_columns=null_cols,
301+
force_quote_columns=quote_cols)
301302

302303
args = ['--command', query]
303304

0 commit comments

Comments
 (0)