├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── decor ├── arrow-transition.png ├── block.png ├── branch-closed-dark.svg ├── branch-closed-light.svg ├── branch-closed.png ├── branch-open.png ├── branch-opened-dark.svg ├── branch-opened-light.svg ├── counter.png ├── database-medium.png ├── equalizer.png ├── fingerprint.png ├── function.png ├── ghost.png ├── hard-hat.png ├── image-saturation-up.png ├── information-white.png ├── key.png ├── layers-small.png ├── operator-classes.png ├── operator-families.png ├── operators-related.png ├── operators.png ├── paper-plane.png ├── procedure.png ├── sd-memory-card.png ├── table-foreign.png ├── table-join.png ├── table.png ├── tables.png ├── traffic-cone.png ├── transparent.png ├── ui-paginator.png ├── user-medium.png ├── users.png └── views.png ├── scripts ├── README.md ├── odbc │ ├── default │ │ └── hl.conf │ └── microsoft sql │ │ ├── content │ │ ├── connection.sql │ │ ├── database.sql │ │ ├── function.sql │ │ ├── procedure.sql │ │ ├── sp_who.sql │ │ ├── table.sql │ │ ├── tables.sql │ │ ├── temp.sql │ │ ├── test_html.sql │ │ ├── trigger.sql │ │ └── view.sql │ │ ├── hl.conf │ │ ├── preview │ │ ├── table.sql │ │ └── view.sql │ │ ├── tree │ │ ├── connection.sql │ │ ├── constraints.sql │ │ ├── database.sql │ │ ├── foreign keys.sql │ │ ├── function.sql │ │ ├── functions.sql │ │ ├── indexes.sql │ │ ├── logins.sql │ │ ├── procedure.sql │ │ ├── procedures.sql │ │ ├── role.sql │ │ ├── roles.sql │ │ ├── schemas.sql │ │ ├── server roles.sql │ │ ├── table.sql │ │ ├── tables.sql │ │ ├── triggers.sql │ │ ├── users.sql │ │ ├── view.sql │ │ └── views.sql │ │ └── version.sql └── postgres │ ├── autocomplete │ ├── columns.sql │ └── objects.sql │ ├── content │ ├── agg_function.sql │ ├── checkpoint_state.sql │ ├── cluster_initialization_state.sql │ ├── column.sql │ ├── constraint.sql │ ├── control_file_state.sql │ ├── database.sql │ ├── domain.sql │ ├── extension.sql │ ├── function.sql │ ├── functions.sql │ ├── index.sql │ ├── indexes.sql │ ├── information_schema.sql │ ├── operator.sql │ ├── operator_class.sql │ ├── operator_classes.sql │ ├── operator_families.sql │ ├── operators.sql │ ├── pg_settings_group.sql │ ├── procedure.sql │ ├── procedures.sql │ ├── recovery_state.sql │ ├── role.sql │ ├── roles.sql │ ├── rule.sql │ ├── schema.sql │ ├── sequence.sql │ ├── sessions.sql │ ├── table.sql │ ├── tables.sql │ ├── tablespaces.sql │ ├── test_html.sql │ ├── trigger.sql │ ├── type.sql │ ├── types.sql │ └── views.sql │ ├── hl.conf │ ├── preview │ ├── database.sql │ ├── db_locks.sql │ ├── role.sql │ ├── roles.sql │ ├── table.sql │ ├── table_locks.sql │ └── table_stats.sql │ ├── recorded_statistics.sql │ ├── statistics.sql │ └── tree │ ├── cluster_state.sql │ ├── connection.sql │ ├── constraints.sql │ ├── database.sql │ ├── dependent_constraints.sql │ ├── domains.sql │ ├── extensions.sql │ ├── function.sql │ ├── functions.sql │ ├── indexes.sql │ ├── operator_classes.sql │ ├── operators.sql │ ├── operators_related.sql │ ├── pg_settings.sql │ ├── procedures.sql │ ├── roles.sql │ ├── rules.sql │ ├── schema.sql │ ├── sequences.sql │ ├── table.sql │ ├── tables.sql │ ├── triggers.sql │ ├── types.sql │ └── views.sql ├── sqt.svg └── src ├── appeventhandler.cpp ├── appeventhandler.h ├── codeeditor.cpp ├── codeeditor.h ├── connectiondialog.cpp ├── connectiondialog.h ├── connectiondialog.ui ├── copycontext.cpp ├── copycontext.h ├── datatable.cpp ├── datatable.h ├── dbconnection.cpp ├── dbconnection.h ├── dbconnectionfactory.cpp ├── dbconnectionfactory.h ├── dbobject.cpp ├── dbobject.h ├── dbobjectsmodel.cpp ├── dbobjectsmodel.h ├── dbosortfilterproxymodel.cpp ├── dbosortfilterproxymodel.h ├── dbtreeitemdelegate.cpp ├── dbtreeitemdelegate.h ├── extfiledialog.cpp ├── extfiledialog.h ├── findandreplacepanel.cpp ├── findandreplacepanel.h ├── findandreplacepanel.ui ├── img ├── arrow-circle-double-135.png ├── bookmark.png ├── control-stop.png ├── control.png ├── database-sql.png ├── database-sql_24.png ├── databases.png ├── gear.png ├── server--plus.png ├── server.png ├── shovel.png └── sql.png ├── jsonsyntaxhighlighter.cpp ├── jsonsyntaxhighlighter.h ├── logindialog.cpp ├── logindialog.h ├── logindialog.ui ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui ├── odbcconnection.cpp ├── odbcconnection.h ├── pgconnection.cpp ├── pgconnection.h ├── pgparams.cpp ├── pgparams.h ├── pgtypes.h ├── queryoptions.cpp ├── queryoptions.h ├── querywidget.cpp ├── querywidget.h ├── scripting.cpp ├── scripting.h ├── settings.cpp ├── settings.h ├── settingsdialog.cpp ├── settingsdialog.h ├── settingsdialog.ui ├── sqlparser.cpp ├── sqlparser.h ├── sqlsyntaxhighlighter.cpp ├── sqlsyntaxhighlighter.h ├── sqt.ico ├── sqt.pro ├── sqt.qrc ├── sqt.rc ├── stuff.cpp ├── stuff.h ├── styling.cpp ├── styling.h ├── tablemodel.cpp ├── tablemodel.h ├── timechart.cpp ├── timechart.h ├── timechartscene.cpp └── timechartscene.h /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sql linguist-detectable=true 2 | scripts/postgres/**/*.sql linguist-language=PLpgSQL 3 | scripts/odbc/microsoft*/**/*.sql linguist-language=TSQL 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pro.user* 2 | build*/ 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2013-2019 Andrey Lukyanov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /decor/arrow-transition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/arrow-transition.png -------------------------------------------------------------------------------- /decor/block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/block.png -------------------------------------------------------------------------------- /decor/branch-closed-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /decor/branch-closed-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /decor/branch-closed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/branch-closed.png -------------------------------------------------------------------------------- /decor/branch-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/branch-open.png -------------------------------------------------------------------------------- /decor/branch-opened-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /decor/branch-opened-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /decor/counter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/counter.png -------------------------------------------------------------------------------- /decor/database-medium.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/database-medium.png -------------------------------------------------------------------------------- /decor/equalizer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/equalizer.png -------------------------------------------------------------------------------- /decor/fingerprint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/fingerprint.png -------------------------------------------------------------------------------- /decor/function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/function.png -------------------------------------------------------------------------------- /decor/ghost.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/ghost.png -------------------------------------------------------------------------------- /decor/hard-hat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/hard-hat.png -------------------------------------------------------------------------------- /decor/image-saturation-up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/image-saturation-up.png -------------------------------------------------------------------------------- /decor/information-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/information-white.png -------------------------------------------------------------------------------- /decor/key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/key.png -------------------------------------------------------------------------------- /decor/layers-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/layers-small.png -------------------------------------------------------------------------------- /decor/operator-classes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/operator-classes.png -------------------------------------------------------------------------------- /decor/operator-families.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/operator-families.png -------------------------------------------------------------------------------- /decor/operators-related.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/operators-related.png -------------------------------------------------------------------------------- /decor/operators.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/operators.png -------------------------------------------------------------------------------- /decor/paper-plane.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/paper-plane.png -------------------------------------------------------------------------------- /decor/procedure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/procedure.png -------------------------------------------------------------------------------- /decor/sd-memory-card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/sd-memory-card.png -------------------------------------------------------------------------------- /decor/table-foreign.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/table-foreign.png -------------------------------------------------------------------------------- /decor/table-join.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/table-join.png -------------------------------------------------------------------------------- /decor/table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/table.png -------------------------------------------------------------------------------- /decor/tables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/tables.png -------------------------------------------------------------------------------- /decor/traffic-cone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/traffic-cone.png -------------------------------------------------------------------------------- /decor/transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/transparent.png -------------------------------------------------------------------------------- /decor/ui-paginator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/ui-paginator.png -------------------------------------------------------------------------------- /decor/user-medium.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/user-medium.png -------------------------------------------------------------------------------- /decor/users.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/users.png -------------------------------------------------------------------------------- /decor/views.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/decor/views.png -------------------------------------------------------------------------------- /scripts/README.md: -------------------------------------------------------------------------------- 1 | The script's file name (excluding extension) corresponds to the node's type (see `node_type` column below) being processed. 2 | 3 | A script may contain dbms minimal version boudaries like (so order matters): 4 | ```sql 5 | /* if version 100000 */ 6 | select s.datname, s.pid, s.backend_type, s.usename --, ... 7 | from pg_stat_activity s 8 | 9 | /* elif version 90000 */ 10 | select s.datname, s.pid, s.usename --, ... 11 | from pg_stat_activity s 12 | 13 | /* else version */ 14 | select 15 | /* if version 83000 */ 16 | ... 17 | /* elif version 70000 */ 18 | ... 19 | /* endif version */ 20 | from pg_stat_activity 21 | /* endif version */ 22 | ``` 23 | Nesting is ok and allows to combine a final script by parts. PostgreSQL uses libpq's PQserverVersion(), ODBC data sources must provide version.sql or version.qs to return this value if used within scripts. E.g. `scripts/odbc/microsoft sql/version.sql` (uses compartibility_level as a comparable version). 24 | 25 | ## `/tree` scripts 26 | 27 | Script to build tree must return resultset with the following columns: 28 | 29 | |name|type|description| 30 | |--|--|--| 31 | |ui_name|varchar|*Mandatory* label to be displayed. E.g.:
`light-colored text`
`italic text`
and so on| 32 | |node_type|varchar|*Mandatory* type of node.
(= file name of dependent script inside sibling folders)| 33 | |name|varchar|`name` field to reference to from another script. Usually it's a full or schemaless quoted or unquoted db object's name depending on the way you use the value within the script.| 34 | |id|varchar|As a rule it's an internal id of database object to be referenced from dependent scripts (or any other convenient value).| 35 | |tag|varchar/int|Any data to be used within dependent scripts.| 36 | |icon|varchar|Icon file name.| 37 | |allow_multiselect|bool|Whether the object may have multiple selected children.| 38 | |sort1|varchar/int|Value to sort on.| 39 | |sort2|varchar/int|Value for alternative sorting.| 40 | 41 | Script may contain macro `$.$` E.g. if current object (being processed by current script) has parent node of type `schema`, then `$schema.id$` within script will be replaced with `id` 42 | value of that node. `$schema.name$` and `$schema.tag$` will be replaced with that node's `name` or `tag` value accordingly. If current node has no parent of specified type, or that parent does not have corresponding field, the macro is replaced by `NULL`. 43 | 44 | Actually, user is free to place any kind of data in columns `name`, `id` and `tag`. This is just what you get in script by means of the corresponding macro. 45 | 46 | >There are two hardcoded node types: `connection` and `database`. `connection` is used internally to represent database connection, so the first script to be executed is `connection.sql` or `connection.qs`. `database` nodes are usually children of `connection` node, and their `name` property has a special meaning: every database node generates separate database connection with connection string built with parent connection string appended with `;Database={}` for odbc data source and `dbname=''` for postgresql data source. 47 | 48 | ## `/content` scripts 49 | Script must return one of the following resultset: 50 | - 1 row 1 column named `script`; 51 | - 1 row 1 column named `html`; 52 | - any other resultset. 53 | 54 | Sql script for PostgreSQL may contain [plpgsql anonymous code block](https://github.com/parihaaraka/sqt/blob/master/scripts/postgres/content/table.sql) and return textual data in the following ways: 55 | - `raise notice '' using hint='script'`; 56 | - `raise notice '' using hint='html'`. 57 | 58 | 59 | Besides described macroses the script may contain: 60 | * `$dbms.version$` - comparable dbms version (integer value); 61 | * `$children.ids$` - ids of selected nodes (comma separated); 62 | * `$children.names$` - names of selected nodes (comma separated, enclosed in single quotes if not yet). 63 | `$children.` macro is actual in case of multiple nodes selection and works within parent node content script. When there is no multiple selected children of the node being scripted, the first macro is replaced by -1, the second one - by `''` (empty quoted string). 64 | 65 | ## `/preview` scripts 66 | Every node type may have corresponding script to display additional single resultset. Use it, for example, to display table/view content preview. Current implementation displays preview resultset only if content script didn't return resultset already. 67 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/content/connection.sql: -------------------------------------------------------------------------------- 1 | select @@version as text -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/content/database.sql: -------------------------------------------------------------------------------- 1 | declare @result nvarchar(max); 2 | 3 | select @result = 4 | ' ' + db.name + '
' + 5 | '' + 6 | '' + 7 | '' + 8 | '' + 20 | '' + 21 | '' + 22 | '' + 36 | '' + 37 | '' + 59 | '
state:' + (db.state_desc COLLATE SQL_Latin1_General_CP1_CI_AS) + '
collation:' + db.collation_name + '
files:' + isnull('' + 9 | (select 10 | (select type_desc + ': ' as td for xml path(''), type), 11 | (select name + ' (' + lower(state_desc) + ') ' as td for xml path(''), type), 12 | (select cast(size*8/1024 as nvarchar(50)) + ' MB ' as td for xml path(''), type), 13 | (select physical_name as td for xml path(''), type) 14 | from sys.master_files 15 | where database_id = $database.id$ 16 | order by type_desc desc, size desc 17 | for xml path('tr')) + 18 | '
', '') + 19 | '
user access:' + db.user_access_desc + '
recovery model:' + db.recovery_model_desc + '
compatibility level:' + cast(db.compatibility_level as nvarchar(5)) + 23 | case db.compatibility_level 24 | when 60 then ' (SQL Server 6.0)' 25 | when 65 then ' (SQL Server 6.5)' 26 | when 70 then ' (SQL Server 7.0)' 27 | when 80 then ' (SQL Server 2000)' 28 | when 90 then ' (SQL Server 2005)' 29 | when 100 then ' (SQL Server 2008)' 30 | when 110 then ' (SQL Server 2012)' 31 | when 120 then ' (SQL Server 2014)' 32 | when 130 then ' (SQL Server 2016)' 33 | when 140 then ' (SQL Server 2017)' 34 | else '' 35 | end + '
create date:' + convert(varchar(20), db.create_date, 120) + '
backups:' + 38 | isnull((select 39 | (select case type when 'D' then 'Database' 40 | when 'I' then 'Differential database' 41 | when 'L' then 'Log' 42 | when 'F' then 'File or filegroup' 43 | when 'G' then 'Differential file' 44 | when 'P' then 'Partial' 45 | when 'Q' then 'Differential partial' else '' end as td for xml path(''), type), 46 | (select ' ' + 47 | ltrim(isnull(str(abs(datediff(day, getdate(),backup_finish_date))) + ' days ago', 'NEVER')) + ' (' + 48 | convert(varchar(20), backup_start_date, 120) + ', done in ' + 49 | + cast(datediff(second, bk.backup_start_date, bk.backup_finish_date) as varchar(4)) + 50 | ' seconds)' as td for xml path(''), type) 51 | from msdb..backupset bk 52 | where bk.database_name = '$database.name$' and backup_set_id >= isnull(( 53 | select top(1) backup_set_id 54 | from msdb..backupset 55 | where database_name = '$database.name$' and type = 'D' order by backup_set_id desc), 0) 56 | order by backup_set_id desc 57 | for xml path('tr')), '') + 58 | '
' 60 | from sys.databases db 61 | where db.database_id = $database.id$; 62 | 63 | select @result as html; 64 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/content/function.sql: -------------------------------------------------------------------------------- 1 | declare @result nvarchar(max); 2 | 3 | select @result = 4 | N'-- created: ' + convert(nvarchar(19), o.create_date, 120) + ' 5 | -- modified: ' + convert(nvarchar(19), o.modify_date, 120) + ' 6 | 7 | ' + replace(sm.definition, 'CREATE FUNCTION', 'ALTER FUNCTION') 8 | from sys.sql_modules as sm 9 | left outer join sys.objects as o on sm.object_id = o.object_id 10 | where sm.object_id = $function.id$; 11 | 12 | select @result script; 13 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/content/procedure.sql: -------------------------------------------------------------------------------- 1 | declare @result nvarchar(max); 2 | 3 | select @result = 4 | N'-- created: ' + convert(nvarchar(19), o.create_date, 120) + ' 5 | -- modified: ' + convert(nvarchar(19), o.modify_date, 120) + ' 6 | 7 | ' + isnull(replace(sm.definition, 'CREATE PROCEDURE', 'ALTER PROCEDURE'), 'encrypted') 8 | from sys.sql_modules as sm 9 | left outer join sys.objects as o on sm.object_id = o.object_id 10 | where sm.object_id = $procedure.id$; 11 | 12 | select @result script; 13 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/content/sp_who.sql: -------------------------------------------------------------------------------- 1 | exec sp_who2 -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/content/table.sql: -------------------------------------------------------------------------------- 1 | declare 2 | @insert_script nvarchar(max), 3 | @update_script nvarchar(max), 4 | @list nvarchar(max), 5 | @values nvarchar(max); 6 | 7 | set @insert_script = N'insert into $table.name$ ('; 8 | set @update_script = N'update $table.name$ 9 | set '; 10 | set @list = N''; 11 | set @values = N''; 12 | 13 | select @insert_script = @insert_script + 14 | case when @list = N'' then N'' else N', ' end + quotename([name]), 15 | @update_script = @update_script + 16 | case when @list = N'' then N'' else N', 17 | ' end + quotename([name]) + N' = ?', 18 | @list = @list + 19 | case when @list = N'' then N'' else N', ' end + quotename([name]), 20 | @values = @values + 21 | case when @values = N'' then N'?' else N', ?' end 22 | from sys.columns 23 | where object_id = $table.id$ and (column_id in ($children.ids$) or '$children.ids$' = '-1') 24 | order by column_id; 25 | 26 | set @insert_script = @insert_script + N') 27 | values (' + @values + N')'; 28 | set @update_script = @update_script + N' 29 | where '; 30 | 31 | select N'select 32 | ' + @list + N' 33 | from $table.name$ 34 | where 35 | 36 | ' + @insert_script + N' 37 | 38 | ' + @update_script script; 39 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/content/tables.sql: -------------------------------------------------------------------------------- 1 | -- source: http://2smart4school.com/understand-use-and-modify-the-stored-procedure-sp_spaceused/ 2 | 3 | with i as 4 | ( 5 | -- XML Indexes or Fulltext Indexes which use internal tables tied user table 6 | select 7 | it.parent_id [object_id], 8 | sum(reserved_page_count) reservedpages, 9 | sum(used_page_count) usedpages 10 | from sys.internal_tables it 11 | inner join sys.dm_db_partition_stats p on it.object_id = p.object_id 12 | where it.internal_type in (202,204,211,212,213,214,215,216) 13 | group by it.parent_id 14 | ), 15 | pt as 16 | ( 17 | select 18 | s.name [schema], 19 | o.name, 20 | o.object_id, 21 | sum(p.reserved_page_count) reservedpages, 22 | sum(p.used_page_count) usedpages, 23 | sum( 24 | case 25 | when (p.index_id < 2) then (p.in_row_data_page_count + p.lob_used_page_count + p.row_overflow_used_page_count) 26 | else p.lob_used_page_count + p.row_overflow_used_page_count 27 | end 28 | ) [pages], 29 | sum(case when (p.index_id < 2) then row_count else 0 end) [rowcount] 30 | from sys.objects o 31 | inner join sys.schemas s on o.schema_id = s.schema_id 32 | inner join sys.dm_db_partition_stats p on o.object_id = p.object_id 33 | where o.type = 'U' 34 | group by s.name, o.name, o.object_id 35 | ), 36 | res as 37 | ( 38 | select 39 | pt.[schema], 40 | pt.name, 41 | pt.[rowcount] [rows], 42 | pt.reservedpages + isnull(i.reservedpages, 0) reservedpages, 43 | pt.usedpages + isnull(i.usedpages, 0) usedpages, 44 | pt.[pages] 45 | from pt 46 | left outer join i on pt.object_id = i.object_id 47 | ) 48 | select 49 | [schema], 50 | name, 51 | [rows], 52 | convert(decimal(15,0), [reservedpages] * 8) reserved, 53 | convert(decimal(15,0), [pages] * 8) [data], 54 | convert(decimal(15,0), (case when usedpages > pages then (usedpages - [pages]) else 0 end) * 8) index_size, 55 | convert(decimal(15,0), (case when reservedpages > usedpages then (reservedpages - usedpages) else 0 end) * 8) unused, 56 | 'kb' unit 57 | from res 58 | order by reserved desc 59 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/content/temp.sql: -------------------------------------------------------------------------------- 1 | -- Get all of the dependency information 2 | SELECT OBJECT_NAME(sed.referencing_id) AS referencing_entity_name, 3 | o.type_desc AS referencing_desciption, 4 | COALESCE(COL_NAME(sed.referencing_id, sed.referencing_minor_id), '(n/a)') AS referencing_minor_id, 5 | sed.referencing_class_desc, sed.referenced_class_desc, 6 | sed.referenced_server_name, sed.referenced_database_name, sed.referenced_schema_name, 7 | sed.referenced_entity_name, 8 | COALESCE(COL_NAME(sed.referenced_id, sed.referenced_minor_id), '(n/a)') AS referenced_column_name, 9 | sed.is_caller_dependent, sed.is_ambiguous 10 | -- from the two system tables sys.sql_expression_dependencies and sys.object 11 | FROM sys.sql_expression_dependencies AS sed 12 | INNER JOIN sys.objects AS o ON sed.referencing_id = o.object_id 13 | -- on the function dbo.ufnGetProductDealerPrice 14 | WHERE sed.referencing_id = OBJECT_ID('dbo.ufnGetProductDealerPrice'); 15 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/content/test_html.sql: -------------------------------------------------------------------------------- 1 | select ' 2 | 3 | 4 |

Qt has a very limited support of html (without WebKit), 5 | but it is still enough for simple formatted output


6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
ValueDescription
DebitIn bookkeeping, an entry in the left hand column of an account to record a debt
CreditThe granting of a loan and the creation of debt. It is any form of deferred payment
20 | 21 | 22 | ' as html; -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/content/trigger.sql: -------------------------------------------------------------------------------- 1 | declare @result nvarchar(max); 2 | 3 | select @result = 4 | N'-- created: ' + convert(nvarchar(19), o.create_date, 120) + ' 5 | -- modified: ' + convert(nvarchar(19), o.modify_date, 120) + ' 6 | 7 | ' + replace(sm.definition, 'CREATE TRIGGER', 'ALTER TRIGGER') 8 | from sys.sql_modules as sm 9 | left outer join sys.objects as o on sm.object_id = o.object_id 10 | where sm.object_id = $trigger.id$; 11 | 12 | select @result script; 13 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/content/view.sql: -------------------------------------------------------------------------------- 1 | declare 2 | @list nvarchar(max), 3 | @create_script nvarchar(max); 4 | 5 | set @list = N''; 6 | 7 | select @list = @list + 8 | case when @list = '' then '' else ', ' end + '[' + [name] + ']' 9 | from sys.columns 10 | where object_id = $view.id$ and (column_id in ($children.ids$) or '$children.ids$' = '-1') 11 | order by column_id; 12 | 13 | if '$children.ids$' = '-1' 14 | select @create_script = 15 | N'-- created: ' + convert(nvarchar(19), o.create_date, 120) + ' 16 | -- modified: ' + convert(nvarchar(19), o.modify_date, 120) + ' 17 | 18 | ' + sm.definition 19 | from sys.sql_modules as sm 20 | left outer join sys.objects as o on sm.object_id = o.object_id 21 | where sm.object_id = $view.id$; 22 | 23 | select isnull(@create_script + N' 24 | -------------------------------- 25 | 26 | ', N'') + N'select 27 | ' + @list + N' 28 | from $view.name$ 29 | where' script; 30 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/preview/table.sql: -------------------------------------------------------------------------------- 1 | select top(100) * from $table.name$ -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/preview/view.sql: -------------------------------------------------------------------------------- 1 | select top(100) * from $view.name$ -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/tree/connection.sql: -------------------------------------------------------------------------------- 1 | select 2 | case when state != 0 then 'dummy' else 'database' end as node_type, 3 | [name] "name", 4 | [name] + isnull(' (' + 5 | case when state != 0 then state_desc COLLATE SQL_Latin1_General_CP1_CI_AS 6 | when is_read_only = 1 then 'read only' 7 | end 8 | + ')', '') ui_name, 9 | database_id id, 10 | 'database-medium.png' icon, 11 | '0' + [name] sort1 12 | from master.sys.databases --where database_id > 4 13 | union all 14 | select 15 | 'logins', 16 | null, 17 | 'Logins', 18 | null, 19 | null, 20 | '1' 21 | union all 22 | select 23 | 'server roles', 24 | null, 25 | 'Server roles', 26 | null, 27 | null, 28 | '2' 29 | union all 30 | select 31 | 'sp_who', 32 | null, 33 | 'Current sessions', 34 | null, 35 | null, 36 | '3' 37 | union all 38 | select 39 | 'test_html', 40 | null, 41 | 'Test HTML result', 42 | null, 43 | null, 44 | '4' 45 | 46 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/tree/constraints.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'default constraint' node_type, 3 | k.[name] + '
  default ' + 4 | k.definition + 5 | '' ui_name, 6 | k.object_id id, 7 | '0' + k.[name] sort1 8 | from sys.default_constraints k 9 | where k.parent_object_id = $table.id$ 10 | union all 11 | select 12 | 'check constraint' node_type, 13 | k.[name] + '' + 14 | case when k.is_disabled = 1 then ' (disabled)' else '' end + 15 | '
  check ' + 16 | (select definition from sys.check_constraints 17 | where object_id = k.object_id for xml path('')) + 18 | '
' ui_name, 19 | k.object_id id, 20 | '1' + k.[name] sort1 21 | from sys.check_constraints k 22 | where k.parent_object_id = $table.id$ 23 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/tree/database.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'tables' node_type, 3 | 'Tables' ui_name, 4 | 'fake_id' id, 5 | cast(null as sysname) icon, 6 | '0' sort1 7 | union all 8 | select 9 | 'views', 10 | 'Views', 11 | null, 12 | null, 13 | '1' 14 | union all 15 | select 16 | 'procedures', 17 | 'Procedures', 18 | null, 19 | null, 20 | '2' 21 | union all 22 | select 23 | 'functions', 24 | 'Functions', 25 | null, 26 | null, 27 | '3' 28 | union all 29 | select 30 | 'schemas', 31 | 'Schemas', 32 | null, 33 | null, 34 | '4' 35 | union all 36 | select 37 | 'users', 38 | 'Users', 39 | null, 40 | null, 41 | '5' 42 | union all 43 | select 44 | 'roles', 45 | 'Roles', 46 | null, 47 | null, 48 | '6' 49 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/tree/foreign keys.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'foreign key' node_type, 3 | k.[name] + case when k.is_disabled = 1 then ' (disabled)' else '' end + 4 | '
  (' + 5 | substring( 6 | (select ', ' + nc.[name] AS [text()] 7 | from sys.foreign_key_columns c 8 | inner join sys.columns nc on c.parent_object_id = nc.object_id and c.parent_column_id = nc.column_id 9 | where c.constraint_object_id = k.object_id 10 | order by c.constraint_column_id 11 | for xml path('')), 3, 1000) + 12 | ') → ' + s.[name] + '.' + ro.[name] + ' (' + 13 | substring( 14 | (select ', ' + nc.[name] AS [text()] 15 | from sys.foreign_key_columns c 16 | inner join sys.columns nc on c.referenced_object_id = nc.object_id and c.referenced_column_id = nc.column_id 17 | where c.constraint_object_id = k.object_id 18 | order by nc.column_id 19 | for xml path('')), 3, 1000) + ')' ui_name, 20 | k.object_id id, 21 | k.[name] sort1 22 | from sys.foreign_keys k 23 | inner join sys.objects ro on k.referenced_object_id = ro.object_id 24 | inner join sys.schemas s on ro.schema_id = s.schema_id 25 | where k.parent_object_id = $table.id$ 26 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/tree/function.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'parameter' node_type, 3 | isnull(nullif(p.[name], ''), 'returns') + ' ' + t.[name] + 4 | case 5 | when t.[name] like '%char%' or t.[name] like '%binary%' then '(' + 6 | case when p.max_length = -1 then 'max' 7 | else cast(p.max_length / (case when t.[name] like 'n%' then 2 else 1 end) as varchar(10)) 8 | end + ')' 9 | when t.[name] = 'float' and p.[precision] != 53 then '(' + cast(p.[precision] as varchar(3)) + ')' 10 | when t.[name] in ('numeric', 'decimal') then '(' + cast(p.[precision] as varchar(3)) + case when p.[scale] != 0 then ',' + cast(p.[scale] as varchar(3)) else '' end + ')' 11 | else '' 12 | end + '' ui_name, 13 | cast(p.parameter_id as sysname) id, 14 | null icon, 15 | p.parameter_id sort1, 16 | p.[name] sort2 17 | from sys.parameters p 18 | left outer join sys.types t on p.user_type_id = t.user_type_id 19 | where p.object_id = $function.id$ 20 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/tree/functions.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'function' node_type, 3 | '' + s.name + '.' + o.name + 4 | ' (' + 5 | case o.type 6 | when 'FN' then 'scalar' 7 | when 'TF' then 'table' 8 | when 'FS' then 'CLR scalar' 9 | when 'FT' then 'CLR table' 10 | end + ')' ui_name, 11 | o.object_id id, 12 | o.name + s.name sort2, 13 | s.name + o.name sort1 14 | from sys.objects o 15 | inner join sys.schemas s on o.schema_id = s.schema_id 16 | where type in ('FN', 'FS', 'FT', 'TF') 17 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/tree/indexes.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'index' node_type, 3 | i.[name] + 4 | case when i.is_primary_key = 1 then ' (pk)' 5 | when i.is_unique = 1 then ' (unique)' else '' end + 6 | '
  ' + substring( 7 | (select ', ' + nc.[name] AS [text()] 8 | from sys.index_columns c 9 | inner join sys.columns nc on c.object_id = nc.object_id and c.column_id = nc.column_id 10 | where c.object_id = i.object_id and c.index_id = i.index_id 11 | order by c.key_ordinal 12 | for xml path('')), 3, 1000) + 13 | '' ui_name, 14 | i.index_id id, 15 | i.index_id sort1, 16 | i.[name] sort2 17 | from sys.indexes i 18 | where i.object_id = isnull($table.id$, $view.id$) and i.type != 0 -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/tree/logins.sql: -------------------------------------------------------------------------------- 1 | SELECT 2 | 'login' node_type, 3 | p.[name] + ' (' + 4 | lower(p.type_desc COLLATE SQL_Latin1_General_CP1_CI_AS) + 5 | case when p.is_disabled = 1 then ', disabled' else '' end + ')' + 6 | isnull('
  ' + substring( 7 | (select ', ' + rp.[name] 8 | from sys.server_role_members m 9 | inner join sys.server_principals rp on m.role_principal_id = rp.principal_id 10 | where m.member_principal_id = p.principal_id 11 | order by rp.sid 12 | for xml path('')), 3, 1000), '') + '
' 13 | ui_name, 14 | p.principal_id id, 15 | p.[name] sort1 16 | from sys.server_principals p 17 | where p.[type] in ('S', 'U') and p.[name] not like 'NT %' 18 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/tree/procedure.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'parameter' node_type, 3 | isnull(nullif(p.[name], ''), 'returns') + ' ' + t.[name] + 4 | case 5 | when t.[name] like '%char%' or t.[name] like '%binary%' then '(' + 6 | case when p.max_length = -1 then 'max' 7 | else cast(p.max_length / (case when t.[name] like 'n%' then 2 else 1 end) as varchar(10)) 8 | end + ')' 9 | when t.[name] = 'float' and p.[precision] != 53 then '(' + cast(p.[precision] as varchar(3)) + ')' 10 | when t.[name] in ('numeric', 'decimal') then '(' + cast(p.[precision] as varchar(3)) + case when p.[scale] != 0 then ',' + cast(p.[scale] as varchar(3)) else '' end + ')' 11 | else '' 12 | end + '' ui_name, 13 | cast(p.parameter_id as sysname) id, 14 | null icon, 15 | p.parameter_id sort1, 16 | p.[name] sort2 17 | from sys.parameters p 18 | left outer join sys.types t on p.user_type_id = t.user_type_id 19 | where p.object_id = $procedure.id$ 20 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/tree/procedures.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'procedure' node_type, 3 | '' + s.name + '.' + o.name ui_name, 4 | o.object_id id, 5 | o.name + s.name sort2, 6 | s.name + o.name sort1 7 | from sys.objects o 8 | inner join sys.schemas s on o.schema_id = s.schema_id 9 | where o.type in ('P') 10 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/tree/role.sql: -------------------------------------------------------------------------------- 1 | SELECT 2 | 'role member' node_type, 3 | rp.[name] + ' (' + 4 | lower(rp.type_desc COLLATE SQL_Latin1_General_CP1_CI_AS) 5 | + ')' ui_name, 6 | rp.principal_id id, 7 | case when rp.[type] in ('S', 'U') then '0' else '1' end + rp.[name] sort1, 8 | rp.[name] sort2 9 | from sys.database_role_members m 10 | inner join sys.database_principals rp on m.member_principal_id = rp.principal_id 11 | where m.role_principal_id = $role.id$ 12 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/tree/roles.sql: -------------------------------------------------------------------------------- 1 | SELECT 2 | 'role' node_type, 3 | [name] ui_name, 4 | principal_id id, 5 | case when [name] like 'db[_]%' then '1' else '0' end + [name] sort1, 6 | [name] sort2 7 | from sys.database_principals 8 | where [type] = 'R' and [name] != 'public' 9 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/tree/schemas.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'schema' node_type, 3 | [name] ui_name, 4 | schema_id id, 5 | quotename([name]) "name", 6 | 'layers-small.png' icon 7 | from sys.schemas 8 | where schema_id between 5 and 16383 or schema_id = 1 9 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/tree/server roles.sql: -------------------------------------------------------------------------------- 1 | DECLARE @t table ([name] sysname, descr sysname); 2 | insert into @t exec sp_helpsrvrole; 3 | select 4 | 'server role' node_type, 5 | [name] + isnull('
  ' + descr + '', '') ui_name, 6 | [name] id, 7 | case when [name] like '%admin' then '1' else '0' end + [name] sort1, 8 | [name] sort2 9 | from @t; 10 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/tree/table.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'column' node_type, 3 | c.[name] + ' ' + t.[name] + 4 | case 5 | when t.[name] like '%char%' or t.[name] like '%binary%' then '(' + 6 | case when c.max_length = -1 then 'max' 7 | else cast(c.max_length / (case when t.[name] like 'n%' then 2 else 1 end) as varchar(10)) 8 | end + ')' 9 | when t.[name] = 'float' and c.[precision] != 53 then '(' + cast(c.[precision] as varchar(3)) + ')' 10 | when t.[name] in ('numeric', 'decimal') then '(' + cast(c.[precision] as varchar(3)) + case when c.[scale] != 0 then ',' + cast(c.[scale] as varchar(3)) else '' end + ')' 11 | else '' + 12 | case when c.is_identity = 1 then ' identity(' + cast(ident_seed('$table.name$') as varchar(20)) + ',' + cast(ident_incr('$table.name$') as varchar(20)) + ')' else '' end + 13 | case when c.is_nullable = 0 then ' not null' else '' end 14 | end + 15 | isnull('
  default ' + df.definition, '') + '
' 16 | ui_name, 17 | cast(c.column_id as sysname) id, 18 | null icon, 19 | c.column_id sort1, 20 | '0' + c.[name] sort2 21 | from sys.columns c 22 | left outer join sys.types t on c.user_type_id = t.user_type_id 23 | left outer join sys.default_constraints df on c.object_id = df.parent_object_id and c.column_id = df.parent_column_id 24 | where c.object_id = $table.id$ 25 | union all 26 | select 27 | 'triggers', 28 | 'Triggers', 29 | null, 30 | null, 31 | 1000, 32 | '1' 33 | union all 34 | select 35 | 'indexes', 36 | 'Indexes', 37 | null, 38 | null, 39 | 1001, 40 | '2' 41 | union all 42 | select 43 | 'foreign keys', 44 | 'Foreign keys', 45 | null, 46 | null, 47 | 1002, 48 | '3' 49 | union all 50 | select 51 | 'constraints', 52 | 'Constraints', 53 | null, 54 | null, 55 | 1003, 56 | '4' 57 | order by 6 58 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/tree/tables.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'table' node_type, 3 | '' + s.name + '.' + o.name ui_name, 4 | quotename(s.name) + '.' + quotename(o.name) "name", 5 | o.object_id id, 6 | o.name + s.name sort2, 7 | s.name + o.name sort1, 8 | cast(1 as bit) allow_multiselect 9 | from sys.objects o 10 | inner join sys.schemas s on o.schema_id = s.schema_id 11 | where o.type = 'U' 12 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/tree/triggers.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'trigger' node_type, 3 | '' + s.name + '.' + o.name + 4 | '' + isnull('(' + 5 | nullif(case when t.type = 'TA' then 'CLR' else '' end + 6 | case when t.is_disabled = 1 then 7 | case when t.type = 'TA' then ', ' else '' end + 8 | 'disabled' else '' 9 | end, '') + 10 | ')', '') + '
  ' + 11 | case when t.is_instead_of_trigger = 1 then 'INSTEAD OF ' else '' end + 12 | substring( 13 | (select ', ' + type_desc 14 | from sys.trigger_events 15 | where object_id = o.object_id 16 | order by [type] 17 | for xml path('')), 3, 1000) + 18 | '
' ui_name, 19 | o.object_id id, 20 | o.name sort1 21 | from sys.objects o 22 | inner join sys.triggers t on o.object_id = t.object_id 23 | inner join sys.schemas s on o.schema_id = s.schema_id 24 | where o.type in ('TR') and o.parent_object_id = isnull($table.id$, $view.id$) 25 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/tree/users.sql: -------------------------------------------------------------------------------- 1 | SELECT 2 | 'user' node_type, 3 | dpr.[name] + '' + 4 | isnull(' → ' + (spr.[name] COLLATE SQL_Latin1_General_CP1_CI_AS), '') + 5 | isnull('
  ' + substring( 6 | (select ', ' + rp.[name] 7 | from sys.database_role_members m 8 | inner join sys.database_principals rp on m.role_principal_id = rp.principal_id 9 | where m.member_principal_id = dpr.principal_id 10 | order by rp.sid 11 | for xml path('')), 3, 1000), '') + '
' 12 | ui_name, 13 | dpr.principal_id id, 14 | dpr.[name] sort1 15 | from sys.database_principals dpr 16 | left outer join sys.server_principals spr on dpr.[sid] = spr.[sid] 17 | where dpr.[type] in ('S', 'U') and isnull(dpr.[sid], 0x0) != 0x0 18 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/tree/view.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'column' node_type, 3 | c.[name] + ' ' + t.[name] + 4 | case 5 | when t.[name] like '%char%' or t.[name] like '%binary%' then '(' + 6 | case when c.max_length = -1 then 'max' 7 | else cast(c.max_length / (case when t.[name] like 'n%' then 2 else 1 end) as varchar(10)) 8 | end + ')' 9 | when t.[name] = 'float' and c.[precision] != 53 then '(' + cast(c.[precision] as varchar(3)) + ')' 10 | when t.[name] in ('numeric', 'decimal') then '(' + cast(c.[precision] as varchar(3)) + case when c.[scale] != 0 then ',' + cast(c.[scale] as varchar(3)) else '' end + ')' 11 | else '' + 12 | case when c.is_identity = 1 then ' identity(' + cast(ident_seed('$view.name$') as varchar(20)) + ',' + cast(ident_incr('$view.name$') as varchar(20)) + ')' else '' end + 13 | case when c.is_nullable = 0 then ' not null' else '' end + '' 14 | end ui_name, 15 | cast(c.column_id as sysname) id, 16 | null icon, 17 | c.column_id sort1, 18 | '0' + c.[name] sort2 19 | from sys.columns c 20 | left outer join sys.types t on c.user_type_id = t.user_type_id 21 | where c.object_id = $view.id$ 22 | union all 23 | select 24 | 'triggers', 25 | 'Triggers', 26 | null, 27 | null, 28 | 1000, 29 | '1' 30 | union all 31 | select 32 | 'indexes', 33 | 'Indexes', 34 | null, 35 | null, 36 | 1001, 37 | '2' 38 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/tree/views.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'view' node_type, 3 | '' + s.name + '.' + o.name ui_name, 4 | quotename(s.name) + '.' + quotename(o.name) "name", 5 | o.object_id id, 6 | o.name + s.name sort2, 7 | s.name + o.name sort1, 8 | cast(1 as bit) allow_multiselect 9 | from sys.objects o 10 | inner join sys.schemas s on o.schema_id = s.schema_id 11 | where o.type = 'V' 12 | -------------------------------------------------------------------------------- /scripts/odbc/microsoft sql/version.sql: -------------------------------------------------------------------------------- 1 | -- query to return comparable dbms version for further work with 2 | -- accordingly marked part of dependent script 3 | -- (see README.txt for details) 4 | 5 | select db.compatibility_level 6 | /* 7 | case db.compatibility_level 8 | when 60 then ' (SQL Server 6.0)' 9 | when 65 then ' (SQL Server 6.5)' 10 | when 70 then ' (SQL Server 7.0)' 11 | when 80 then ' (SQL Server 2000)' 12 | when 90 then ' (SQL Server 2005)' 13 | when 100 then ' (SQL Server 2008)' 14 | when 110 then ' (SQL Server 2012)' 15 | when 120 then ' (SQL Server 2014)' 16 | when 130 then ' (SQL Server 2016)' 17 | when 140 then ' (SQL Server 2017)' 18 | else ' unknown' 19 | end 20 | */ 21 | from sys.databases db 22 | where db.database_id = db_id() 23 | -------------------------------------------------------------------------------- /scripts/postgres/autocomplete/columns.sql: -------------------------------------------------------------------------------- 1 | /* 2 | autocomplete source, table-level 3 | */ 4 | 5 | with t as 6 | ( 7 | select c.oid 8 | from pg_catalog.pg_class c 9 | join pg_catalog.pg_namespace ns on c.relnamespace = ns.oid 10 | left join unnest(current_schemas(true)) with ordinality as cs(n, ord) on ns.nspname = cs.n 11 | where 12 | c.relname = '$table.name$' and 13 | ( 14 | ('$schema.name$' = 'NULL' and cs.ord is not null) or -- on search path 15 | ns.nspname = '$schema.name$' -- exact namespace 16 | ) and 17 | c.relkind in ('r'::"char", 'p'::"char", 'f'::"char", 'v'::"char", 'm'::"char") 18 | order by coalesce(cs.ord, 0) 19 | limit 1 20 | ) 21 | select 22 | a.attname "name", 23 | jsonb_build_object( 24 | 'n', pg_catalog.format_type(a.atttypid, a.atttypmod), 25 | 'd', col_description(t.oid, a.attnum) 26 | ) info 27 | from t 28 | join pg_catalog.pg_attribute a on t.oid = a.attrelid 29 | where a.attnum > 0 and not a.attisdropped 30 | order by 1 -------------------------------------------------------------------------------- /scripts/postgres/autocomplete/objects.sql: -------------------------------------------------------------------------------- 1 | /* 2 | autocomplete source, schema-level 3 | */ 4 | 5 | with ns as 6 | ( 7 | select oid, nspname 8 | from pg_catalog.pg_namespace 9 | where nspname not like 'pg_toast%' and nspname not like 'pg_temp%' 10 | ), 11 | target_ns as 12 | ( 13 | select ns.*, cs.ord 14 | from ns 15 | join unnest(current_schemas(true)) with ordinality as cs(n, ord) on ns.nspname = cs.n 16 | where '$schema.name$' = 'NULL' 17 | union all 18 | -- add schema that is not in search_path 19 | select *, 0 20 | from ns 21 | where nspname = '$schema.name$' 22 | ) 23 | --schemas 24 | select nspname "name", jsonb_build_object('n', 'schema') info 25 | from ns 26 | where '$schema.name$' = 'NULL' -- return schemas if current schema is not specified 27 | union all 28 | --.table,view,etc 29 | select * from ( 30 | select distinct on (c.relname) -- first found in search path or specified schema 31 | c.relname, 32 | jsonb_build_object( 33 | 'n', -- name 34 | case c.relkind 35 | when 'r'::"char" then 'table' 36 | when 'p'::"char" then 'table' 37 | when 'f'::"char" then 'table' 38 | when 'c'::"char" then 'type' 39 | when 'v'::"char" then 'view' 40 | when 'm'::"char" then 'view' 41 | when 'S'::"char" then 'sequence' 42 | else null 43 | end, 44 | 'd', -- description 45 | obj_description(c.oid, 'pg_class') 46 | ) 47 | from target_ns ns 48 | join pg_class c on ns.oid = c.relnamespace 49 | where c.relkind not in ('i'::"char", 't'::"char") -- not an index or toast table 50 | order by c.relname, ns.ord 51 | ) tmp 52 | union all 53 | --.type 54 | select * from ( 55 | select distinct on (t.typname) -- first found in search path or specified schema 56 | t.typname, 57 | jsonb_build_object( 58 | 'n', 59 | case 60 | when t.typtype = 'b'::"char" then 'base type' 61 | when t.typtype = 'd'::"char" then 'domain' 62 | when t.typtype = 'e'::"char" then 'enum' 63 | when t.typtype = 'p'::"char" then 'pseudo-type' 64 | when t.typtype = 'r'::"char" then 'range' 65 | end, 66 | 'd', 67 | obj_description(t.oid, 'pg_type') 68 | ) 69 | from target_ns ns 70 | join pg_type t on ns.oid = t.typnamespace 71 | left join pg_class c on t.typrelid = c.oid 72 | where c.relkind is null and -- see prev subquery 73 | t.typname not like '\_%' -- not an array 74 | order by t.typname, ns.ord 75 | ) tmp 76 | union all 77 | --.function 78 | select 79 | p.proname, 80 | jsonb_agg( 81 | jsonb_build_object( 82 | 'n', 83 | case when '$schema.name$' = 'NULL' then quote_ident(ns.nspname) || '.' else '' end || 84 | quote_ident(p.proname) || 85 | '(' || oidvectortypes(p.proargtypes) || ') → ' || 86 | -- prorettype::regtype::text shows long name (e.g. timestamp with time zone) but displays arrays with brackets 87 | -- typname contains short name with leading '_' for arrays 88 | case when left(t.typname, 1) = '_' then p.prorettype::regtype::text else t.typname end, 89 | 'd', 90 | d 91 | ) 92 | ) 93 | from target_ns ns 94 | join pg_proc p on ns.oid = p.pronamespace 95 | left join pg_type t on p.prorettype = t.oid 96 | left join lateral obj_description(p.oid, 'pg_proc') d on true 97 | where p.prorettype != 'trigger'::regtype and 98 | ( 99 | d is null or 100 | ( 101 | d not like 'I/O%' and 102 | d not like 'internal%' and 103 | d not like 'hash%' and 104 | d not like 'SP-GiST support%' and 105 | d not in ('less-equal-greater' ,'(internal)', 'larger of two', 'smaller of two') and 106 | d not like '%selectivity%' and 107 | d !~ '(operator|final function|transition function|support|pg_upgrade|osolete\)|combine function|serial function)$' and 108 | d not like '%index access%' 109 | ) 110 | ) 111 | group by p.proname 112 | order by 1 -------------------------------------------------------------------------------- /scripts/postgres/content/agg_function.sql: -------------------------------------------------------------------------------- 1 | do 2 | $$ 3 | declare 4 | _opt text; 5 | _opts text[] := '{}'::text[]; 6 | _def jsonb; 7 | _r record; 8 | _params text; 9 | begin 10 | _def := to_jsonb((select pg_aggregate from pg_aggregate where aggfnoid = $agg_function.id$)); 11 | for _r in select * from jsonb_each_text(_def) loop 12 | _opt := 13 | case 14 | when _r.key = 'aggtransfn' then 'SFUNC = ' || _r.value 15 | when _r.key = 'aggtranstype' then 'STYPE = ' || _r.value::regtype 16 | when _r.key = 'aggfinalfn' and _r.value != '-' then 'FINALFUNC = ' || _r.value 17 | when _r.key = 'aggsortop' and _r.value != '0' then 'SORTOP = ' || (select quote_ident(oprname) from pg_operator where oid = _r.value::oid) 18 | when _r.key = 'agginitval' and _r.value is not null then 'INITCOND = ' || quote_literal(_r.value) 19 | when _r.key = 'aggfinalextra' and _r.value::boolean then 'FINALFUNC_EXTRA' 20 | when _r.key = 'aggcombinefn' and _r.value != '-' then 'COMBINEFUNC = ' || _r.value 21 | when _r.key = 'aggserialfn' and _r.value != '-' then 'SERIALFUNC = ' || _r.value 22 | when _r.key = 'aggdeserialfn' and _r.value != '-' then 'DESERIALFUNC = ' || _r.value 23 | else null 24 | end; 25 | 26 | if _opt is not null then 27 | _opts := _opts || _opt; 28 | end if; 29 | end loop; 30 | 31 | select string_agg(E'\t' || p, E',\n') into _opt 32 | from unnest(_opts) o(p); 33 | 34 | select oidvectortypes(proargtypes) into _params 35 | from pg_proc 36 | where "oid" = $agg_function.id$; 37 | 38 | raise notice E'CREATE AGGREGATE $schema.name$.$agg_function.name$(%)\n(\n%\n);', _params, _opt using hint = 'script'; 39 | end 40 | $$ 41 | -------------------------------------------------------------------------------- /scripts/postgres/content/checkpoint_state.sql: -------------------------------------------------------------------------------- 1 | select * from jsonb_each_text(to_jsonb((select r from pg_control_checkpoint() r))) 2 | order by 1 3 | -------------------------------------------------------------------------------- /scripts/postgres/content/cluster_initialization_state.sql: -------------------------------------------------------------------------------- 1 | select * from jsonb_each_text(to_jsonb((select r from pg_control_init() r))) 2 | order by 1 3 | -------------------------------------------------------------------------------- /scripts/postgres/content/column.sql: -------------------------------------------------------------------------------- 1 | with tmp as 2 | ( 3 | select * 4 | from pg_stats 5 | where tablename = '$table.name$' and schemaname = '$schema.name$' and attname = '$column.name$' 6 | ), 7 | tmp2 as 8 | ( 9 | select k,v 10 | from jsonb_each_text(to_jsonb((select tmp from tmp)) - '{tablename,schemaname,attname}'::text[]) as x(k,v) 11 | ) 12 | select 13 | coalesce(format(E'COMMENT ON COLUMN %I.%I.%I IS\n', '$schema.name$','$table.name$','$column.name$') || quote_literal(col_description($table.id$, $column.id$)) || E';\n\n', '') || 14 | coalesce(nullif(string_agg(format('%-25s: %s', k, v::text), E'\n'), ''), '-- statistics not found') as script 15 | from tmp2 16 | --order by 1 -------------------------------------------------------------------------------- /scripts/postgres/content/constraint.sql: -------------------------------------------------------------------------------- 1 | select E'ALTER TABLE ' || nullif(conrelid, 0)::regclass::text || E' DROP CONSTRAINT $constraint.name$;\n\n' || 2 | E'ALTER TABLE ' || nullif(conrelid, 0)::regclass::text || E'\n\tADD CONSTRAINT $constraint.name$\n\t' || 3 | regexp_replace(pg_get_constraintdef(oid, true), '\m(on|using|with)\M', E'\n\t\\1', 'ig') || E';\n' as script 4 | from pg_constraint 5 | where oid = $constraint.id$ -------------------------------------------------------------------------------- /scripts/postgres/content/control_file_state.sql: -------------------------------------------------------------------------------- 1 | select * from jsonb_each_text(to_jsonb((select r from pg_control_system() r))) 2 | order by 1 3 | -------------------------------------------------------------------------------- /scripts/postgres/content/database.sql: -------------------------------------------------------------------------------- 1 | do 2 | $$ 3 | declare 4 | _r record; 5 | _acl text; 6 | _def_acl text; 7 | _script text; 8 | _db_id oid := $database.id$; 9 | _db_name text := '$database.name$'; 10 | begin 11 | 12 | select * into _r 13 | from pg_database 14 | where oid = _db_id; 15 | 16 | with tmp as 17 | ( 18 | select 19 | d.defaclobjtype obj, 20 | a.grantee, 21 | string_agg(a.privilege_type, ', ') priv, 22 | a.is_grantable 23 | from pg_default_acl d 24 | cross join lateral aclexplode(d.defaclacl) a 25 | where d.defaclnamespace = 0 -- db level 26 | group by d.defaclobjtype, a.grantee, a.is_grantable 27 | ) 28 | select string_agg( 29 | E'ALTER DEFAULT PRIVILEGES\n\tGRANT ' || 30 | priv || ' ON ' || 31 | case tmp.obj 32 | when 'r'::"char" then 'TABLES' 33 | when 'f'::"char" then 'FUNCTIONS' 34 | when 'S'::"char" then 'SEQUENCES' 35 | when 'T'::"char" then 'TYPES' 36 | else tmp.obj::text 37 | end || ' TO ' || 38 | case when tmp.grantee = 0 then 'public' else quote_ident(grantee::regrole::text) end || 39 | case when tmp.is_grantable then ' WITH GRANT OPTION' else '' end || ';' 40 | , E'\n') 41 | into _def_acl 42 | from tmp; 43 | 44 | with tmp as 45 | ( 46 | select 47 | grantee, 48 | string_agg(privilege_type, ', ') priv, 49 | array_agg(privilege_type) priv_array, 50 | is_grantable 51 | from aclexplode(_r.datacl) a 52 | group by grantee, is_grantable 53 | ), 54 | tmp2 as 55 | ( 56 | select 57 | string_agg(case when grantee = 0 then 'public' else quote_ident(grantee::regrole::text) end, ', ') grantees, 58 | priv, priv_array, is_grantable 59 | from tmp 60 | group by priv, priv_array, is_grantable 61 | ) 62 | select string_agg( 63 | 'GRANT ' || 64 | case when cardinality(priv_array) = 3 /*check exact values?*/ then 'ALL' else priv end || 65 | ' ON DATABASE ' || _db_name || ' TO ' || grantees || 66 | case when is_grantable then ' WITH GRANT OPTION' else '' end || ';' 67 | , E'\n') 68 | into _acl 69 | from tmp2; 70 | 71 | _script := 'CREATE DATABASE ' || _db_name || ' WITH' || 72 | E'\n\tOWNER = ' || quote_ident(_r.datdba::regrole::text) || 73 | E'\n\tENCODING = ' || quote_literal(pg_encoding_to_char(_r.encoding)) || 74 | E'\n\tLC_COLLATE = ' || quote_literal(_r.datcollate) || 75 | E'\n\tLC_CTYPE = ' || quote_literal(_r.datctype) || 76 | E'\n\tTABLESPACE = ' || (select spcname from pg_tablespace where oid = _r.dattablespace) || 77 | case when not _r.datallowconn then E'\n\tALLOW_CONNECTIONS = false' else '' end || 78 | case when not _r.datconnlimit != -1 then E'\n\tCONNECTION LIMIT = ' || _r.datconnlimit::text else '' end || 79 | case when _r.datistemplate then E'\n\tIS_TEMPLATE = true' else '' end 80 | || E';\n\n' || 81 | format(E'COMMENT ON DATABASE %s IS %s;\n', 82 | _db_name, 83 | coalesce(E'\n' || quote_literal(shobj_description(_db_id, 'pg_database')), 'NULL')) || 84 | coalesce(E'\n' || _def_acl, '') || 85 | coalesce(E'\n' || _acl, ''); 86 | 87 | raise notice '%', _script using hint = 'script'; 88 | 89 | end 90 | $$ 91 | -------------------------------------------------------------------------------- /scripts/postgres/content/domain.sql: -------------------------------------------------------------------------------- 1 | do 2 | $$ 3 | declare 4 | _type text := '$domain.tag$'; 5 | _obj_name text := '$schema.name$.$domain.name$'; 6 | _obj_id oid := $domain.id$; 7 | _content text; 8 | _comment text; 9 | begin 10 | 11 | select 12 | 'CREATE DOMAIN ' || _obj_name || E' AS ' || pg_catalog.format_type(t.typbasetype, t.typtypmod) || 13 | case 14 | -- do we have a simpler way to detect default collation oid? 15 | when t.typcollation = 0 or pg_describe_object('pg_collation'::regclass::oid, t.typcollation, 0) ilike '%default' then '' 16 | else E'\n\tCOLLATE ' || (pg_identify_object('pg_collation'::regclass::oid, t.typcollation, 0)).identity 17 | end || 18 | coalesce(E'\n\tDEFAULT ' || t.typdefault, '') || 19 | case when t.typnotnull then E'\n\tNOT NULL' else '' end || 20 | coalesce( 21 | ( 22 | select string_agg(E'\n\tCONSTRAINT ' || quote_ident(c.conname) || ' ' || pg_catalog.pg_get_constraintdef(c.oid, true), '') 23 | from pg_catalog.pg_constraint c 24 | where c.contypid = t.oid 25 | ), '' 26 | ) || ';' 27 | into _content 28 | from pg_type t 29 | left join pg_catalog.pg_constraint c on t.oid = c.contypid 30 | where t.oid = _obj_id; 31 | 32 | _comment := format(E'COMMENT ON DOMAIN %s IS %s;\n', 33 | _obj_name, 34 | coalesce(E'\n' || quote_literal(obj_description(_obj_id, 'pg_type')), 'NULL')); 35 | 36 | raise notice E'%\n\n%', _content, _comment using hint = 'script'; 37 | end 38 | $$ 39 | -------------------------------------------------------------------------------- /scripts/postgres/content/extension.sql: -------------------------------------------------------------------------------- 1 | select 'DROP EXTENSION ' || quote_ident(extname) || E';\n\n' || 2 | 'CREATE EXTENSION ' || quote_ident(extname) || 3 | E'\n\tSCHEMA ' || quote_ident(extnamespace::regnamespace::text) || 4 | E'\n\tVERSION ' || quote_ident(extversion) || ';' as script 5 | from pg_extension 6 | where oid = $extension.id$; -------------------------------------------------------------------------------- /scripts/postgres/content/function.sql: -------------------------------------------------------------------------------- 1 | do 2 | $$ 3 | declare 4 | _fn_oid oid := $function.id$; 5 | _comment text := obj_description(_fn_oid, 'pg_proc'); 6 | _fn_name text := '$schema.name$.$function.name$'; 7 | _tmp text; 8 | begin 9 | 10 | if '$children.ids$' = '-1' then 11 | select E'/*\nDROP FUNCTION ' || _fn_name || '(' || oidvectortypes(p.proargtypes) || E');\n' || 12 | E'COMMENT ON FUNCTION ' || _fn_name || '(' || oidvectortypes(p.proargtypes) || ') IS ' || 13 | coalesce(E'\n' || quote_literal(_comment), 'NULL') || E';\n*/\n' 14 | into _tmp 15 | from pg_proc p 16 | where p.oid = _fn_oid; 17 | 18 | raise notice E'%\n%;', _tmp, rtrim(pg_get_functiondef(_fn_oid), E'\n') 19 | using hint = 'script'; 20 | else 21 | with tmp as 22 | ( 23 | select a.n, a.i, row_number() over () as rn 24 | from pg_proc p 25 | cross join lateral ( 26 | -- stuff to support functions with anonimous arguments 27 | select a.n, coalesce(a.i, s.i) i 28 | from generate_series(1, p.pronargs) s(i) 29 | left join unnest(p.proargnames) with ordinality a(n, i) on s.i = a.i 30 | ) a 31 | where p.oid = _fn_oid and a.i in ($children.ids$) 32 | ) 33 | select 'SELECT * FROM ' || _fn_name || '(' || 34 | string_agg( 35 | coalesce(n || '=>', 36 | case when rn = 1 then '/*you can''t use named notation with anon arguments*/' 37 | else '' 38 | end) || 39 | '$' || rn::text, 40 | ', ' order by tmp.i) || E');\n' 41 | into _tmp 42 | from tmp; 43 | 44 | raise notice E'%', _tmp using hint = 'script'; 45 | end if; 46 | end 47 | $$ 48 | -------------------------------------------------------------------------------- /scripts/postgres/content/functions.sql: -------------------------------------------------------------------------------- 1 | /* if version 110000 */ 2 | select 3 | p.proname || ' (' || oidvectortypes(p.proargtypes) || ')' "function", 4 | p.oid, 5 | case 6 | when p.prokind = 'a' then 'aggregate' 7 | when p.prokind = 'w' then 'window' 8 | when t.oid is not null then 'trigger' 9 | else '' 10 | end "type", 11 | p.proowner::regrole "owner", 12 | obj_description(p.oid, 'pg_proc') "comment" 13 | from pg_proc p 14 | left join lateral ( 15 | select t.oid 16 | from pg_trigger t 17 | where t.tgfoid = p.oid and not t.tgisinternal 18 | limit 1) t on true 19 | where p.pronamespace = $schema.id$ and p.prokind is distinct from 'p' 20 | order by 1 21 | 22 | /* elif version 80000 */ 23 | select 24 | p.proname || ' (' || oidvectortypes(p.proargtypes) || ')' "function", 25 | p.oid, 26 | case when p.proisagg then 'aggregate' when t.oid is not null then ' trigger' end "type", 27 | p.proowner::regrole "owner", 28 | obj_description(p.oid, 'pg_proc') "comment" 29 | from pg_proc p 30 | left join lateral ( 31 | select t.oid 32 | from pg_trigger t 33 | where t.tgfoid = p.oid and not t.tgisinternal 34 | limit 1) t on true 35 | where p.pronamespace = $schema.id$ 36 | order by 1 37 | 38 | /* endif version */ -------------------------------------------------------------------------------- /scripts/postgres/content/index.sql: -------------------------------------------------------------------------------- 1 | select E'DROP INDEX $schema.name$.$index.name$;\n\n' || 2 | regexp_replace(pg_get_indexdef($index.id$), '\m(on|using|with)\M', E'\n\t\\1', 'ig') || 3 | case 4 | when $index.tag$ = 0 then '' 5 | else E'\n\tTABLESPACE ' || (pg_identify_object('pg_tablespace'::regclass::oid, $index.tag$, 0)).identity 6 | end || 7 | E';\n\n' || 8 | format(E'COMMENT ON INDEX $schema.name$.$index.name$ IS %s;\n', 9 | coalesce(E'\n' || quote_literal(obj_description($index.id$, 'pg_class')), 'NULL')) 10 | as script 11 | -------------------------------------------------------------------------------- /scripts/postgres/content/indexes.sql: -------------------------------------------------------------------------------- 1 | select 2 | i.relname as index_name, 3 | regexp_replace(pg_get_indexdef(i.oid), '.*(USING\s*)+?', '') expr, 4 | x.indisunique, 5 | pg_size_pretty(pg_relation_size(x.indexrelid)) index_size, 6 | stat.idx_scan, 7 | stat.idx_tup_read, 8 | stat.idx_tup_fetch, 9 | iostat.idx_blks_read, 10 | iostat.idx_blks_hit 11 | from pg_index x 12 | left join pg_class i on x.indexrelid = i.oid 13 | left join pg_stat_all_indexes stat on x.indexrelid = stat.indexrelid 14 | left join pg_statio_all_indexes iostat on x.indexrelid = iostat.indexrelid 15 | where x.indrelid = $table.id$ 16 | -------------------------------------------------------------------------------- /scripts/postgres/content/information_schema.sql: -------------------------------------------------------------------------------- 1 | select 'create schema $information_schema.name$;' script; -------------------------------------------------------------------------------- /scripts/postgres/content/operator.sql: -------------------------------------------------------------------------------- 1 | do 2 | $$ 3 | declare 4 | _obj_id oid := $operator.id$; 5 | _pgns regnamespace := 'pg_catalog'::regnamespace; 6 | _obj_name text := case when $schema.id$ = _pgns then '' else '$schema.name$.' end || '$operator.name$'; 7 | _content text; 8 | _comment text; 9 | _ltypname text; 10 | _rtypname text; 11 | begin 12 | 13 | select 14 | 'CREATE OPERATOR ' || _obj_name || E'\n(\n' || 15 | E'\tPROCEDURE = ' || 16 | case when p.pronamespace = _pgns then '' else quote_ident(p.pronamespace::regnamespace::text) || '.' end || 17 | quote_ident(p.proname) || coalesce(E',\n' || 18 | E'\tLEFTARG = ' || 19 | case when l.typnamespace = _pgns then '' else quote_ident(l.typnamespace::regnamespace::text) || '.' end || 20 | l.typname, '') || coalesce(E',\n' || 21 | E'\tRIGHTARG = ' || 22 | case when r.typnamespace = _pgns then '' else quote_ident(r.typnamespace::regnamespace::text) || '.' end || 23 | r.typname, '') || coalesce(E',\n' || 24 | E'\tCOMMUTATOR = ' || 25 | case 26 | when com.oprnamespace != op.oprnamespace 27 | then 'OPERATOR(' || quote_ident(com.oprnamespace::regnamespace::text) || '.' || com.oprname || ')' 28 | else com.oprname 29 | end, '') || coalesce(E',\n' || 30 | E'\tNEGATOR = ' || 31 | case 32 | when neg.oprnamespace != op.oprnamespace 33 | then 'OPERATOR(' || quote_ident(neg.oprnamespace::regnamespace::text) || '.' || neg.oprname || ')' 34 | else neg.oprname 35 | end, '') || coalesce(E',\n' || 36 | E'\tRESTRICT = ' || 37 | case when rst.pronamespace = _pgns then '' else quote_ident(rst.pronamespace::regnamespace::text) || '.' end || 38 | quote_ident(rst.proname), '') || coalesce(E',\n' || 39 | E'\tJOIN = ' || 40 | case when j.pronamespace = _pgns then '' else quote_ident(j.pronamespace::regnamespace::text) || '.' end || 41 | quote_ident(j.proname), '') || coalesce(E',\n' || 42 | E'\tHASHES' || case when op.oprcanhash then '' else null end, '') || coalesce(E',\n' || 43 | E'\tMERGES' || case when op.oprcanmerge then '' else null end, '') || 44 | E'\n);', l.typname, r.typname 45 | into _content, _ltypname, _rtypname 46 | from pg_catalog.pg_operator op 47 | left join pg_catalog.pg_type l on op.oprleft = l.oid 48 | left join pg_catalog.pg_type r on op.oprright = r.oid 49 | left join pg_catalog.pg_operator com on op.oprcom = com.oid 50 | left join pg_catalog.pg_operator neg on op.oprnegate = neg.oid 51 | left join pg_catalog.pg_proc rst on op.oprrest = rst.oid 52 | left join pg_catalog.pg_proc j on op.oprjoin = j.oid 53 | left join pg_catalog.pg_proc p on op.oprcode = p.oid 54 | where op.oid = _obj_id; 55 | 56 | _comment := format(E'COMMENT ON OPERATOR %s(%s, %s) IS %s;\n', 57 | _obj_name, coalesce(_ltypname, 'NONE'), coalesce(_rtypname, 'NONE'), 58 | coalesce(E'\n' || quote_literal(obj_description(_obj_id, 'pg_operator')), 'NULL')); 59 | 60 | raise notice E'%\n\n%', _content, _comment using hint = 'script'; 61 | end 62 | $$ 63 | -------------------------------------------------------------------------------- /scripts/postgres/content/operator_class.sql: -------------------------------------------------------------------------------- 1 | do 2 | $$ 3 | declare 4 | _obj_name text := '$schema.name$.$operator_class.name$'; 5 | _obj_id oid := $operator_class.id$; 6 | _operators text; 7 | _functions text; 8 | _content text; 9 | _comment text; 10 | _pgns regnamespace := 'pg_catalog'::regnamespace; 11 | _r record; 12 | begin 13 | 14 | select 15 | c.*, t.typnamespace, t.typname, m.amname, f.opfnamespace, f.opfname, 16 | st.typnamespace storage_typnamespace, 17 | st.typname storage_typname 18 | into _r 19 | from pg_catalog.pg_opclass c 20 | join pg_catalog.pg_type t on c.opcintype = t.oid 21 | left join pg_catalog.pg_type st on c.opckeytype = st.oid 22 | join pg_catalog.pg_am m on c.opcmethod = m.oid 23 | join pg_catalog.pg_opfamily f on c.opcfamily = f.oid 24 | where c.oid = _obj_id; 25 | 26 | select 27 | string_agg( 28 | E'\t\tOPERATOR ' || amop.amopstrategy || ' ' || op.oprname || 29 | case when l.oid = _r.opcintype and r.oid = _r.opcintype then '' else ' (' || 30 | coalesce(case when l.typnamespace = _pgns then '' else quote_ident(l.typnamespace::regnamespace::text) || '.' end || l.typname, 'NONE') || ', ' || 31 | coalesce(case when r.typnamespace = _pgns then '' else quote_ident(r.typnamespace::regnamespace::text) || '.' end || r.typname, 'NONE') || ')' 32 | end || 33 | case when amop.amoppurpose = 's'::"char" then '' else ' FOR ORDER BY ' || f.opfname end, 34 | E',\n' order by amop.amopstrategy) 35 | into _operators 36 | from pg_catalog.pg_amop amop 37 | join pg_catalog.pg_operator op on amop.amopopr = op.oid 38 | left join pg_catalog.pg_opfamily f on amop.amopsortfamily = f.oid 39 | left join pg_catalog.pg_type l on op.oprleft = l.oid 40 | left join pg_catalog.pg_type r on op.oprright = r.oid 41 | where amop.amopfamily = _r.opcfamily and amop.amopmethod = _r.opcmethod; 42 | 43 | select 44 | string_agg( 45 | E'\t\tFUNCTION ' || pc.amprocnum || ' (' || 46 | coalesce(case when l.typnamespace = _pgns then '' else quote_ident(l.typnamespace::regnamespace::text) || '.' end || l.typname, 'NONE') || ', ' || 47 | coalesce(case when r.typnamespace = _pgns then '' else quote_ident(r.typnamespace::regnamespace::text) || '.' end || r.typname, 'NONE') || ') ' || 48 | case when p.pronamespace = _pgns then '' else quote_ident(p.pronamespace::regnamespace::text) || '.' end || 49 | p.proname || '(' || oidvectortypes(p.proargtypes) || ')', 50 | E',\n' order by pc.amprocnum) 51 | into _functions 52 | from pg_catalog.pg_amproc pc 53 | join pg_catalog.pg_proc p on pc.amproc = p.oid 54 | left join pg_catalog.pg_type l on pc.amproclefttype = l.oid 55 | left join pg_catalog.pg_type r on pc.amprocrighttype = r.oid 56 | where pc.amprocfamily = _r.opcfamily; 57 | 58 | _content := 59 | 'CREATE OPERATOR CLASS ' || _obj_name || case when _r.opcdefault then ' DEFAULT' else '' end || 60 | ' FOR TYPE ' || 61 | case when _r.typnamespace = _pgns then '' else quote_ident(_r.typnamespace::regnamespace::text) || '.' end || 62 | _r.typname || E'\n\t' || 63 | 'USING ' || _r.amname || 64 | case when _r.opfname = _r.opcname then '' else ' FAMILY ' || 65 | case when _r.opfnamespace = _pgns then '' else quote_ident(_r.opfnamespace::regnamespace::text) || '.' end || 66 | _r.opfname 67 | end || E' AS\n' || 68 | coalesce(E'\t\tSTORAGE ' || 69 | case when _r.storage_typnamespace = _pgns then '' else quote_ident(_r.storage_typnamespace::regnamespace::text) || '.' end || 70 | _r.storage_typname || 71 | E',\n', '') || 72 | _operators || E',\n' || 73 | _functions || ';'; 74 | 75 | _comment := format(E'COMMENT ON OPERATOR CLASS %s USING %s IS %s;\n', 76 | _obj_name, _r.amname, 77 | coalesce(E'\n' || quote_literal(obj_description(_obj_id, 'pg_opclass')), 'NULL')); 78 | 79 | raise notice E'%\n\n%', _content, _comment using hint = 'script'; 80 | end 81 | $$ 82 | -------------------------------------------------------------------------------- /scripts/postgres/content/operator_classes.sql: -------------------------------------------------------------------------------- 1 | select 2 | op.opcname || ' (' || m.amname || ')' "opclass", 3 | op.oid, 4 | op.opcowner::regrole "owner", 5 | obj_description(op.oid, 'pg_opclass') "comment" 6 | from pg_catalog.pg_opclass op 7 | left join pg_catalog.pg_am m on op.opcmethod = m.oid 8 | where op.opcnamespace = $schema.id$ 9 | order by 1 10 | -------------------------------------------------------------------------------- /scripts/postgres/content/operator_families.sql: -------------------------------------------------------------------------------- 1 | select 2 | f.opfname || coalesce(' (' || m.amname || ')', '') "opfamily", 3 | f.oid, 4 | f.opfowner::regrole "owner", 5 | obj_description(f.oid, 'pg_opfamily') "comment" 6 | from pg_catalog.pg_opfamily f 7 | left join pg_catalog.pg_am m on f.opfmethod = m.oid 8 | where f.opfnamespace = $schema.id$ 9 | order by 1 10 | -------------------------------------------------------------------------------- /scripts/postgres/content/operators.sql: -------------------------------------------------------------------------------- 1 | select 2 | op.oprname || ' (' || 3 | case 4 | when op.oprkind = 'b'::"char" then l.typname || ',' || r.typname 5 | else coalesce(l.typname, r.typname) 6 | end || ') → ' || res.typname "operator", 7 | op.oid, 8 | op.oprowner::regrole "owner", 9 | obj_description(op.oid, 'pg_operator') "comment" 10 | from pg_catalog.pg_operator op 11 | left join pg_catalog.pg_type l on op.oprleft = l.oid 12 | left join pg_catalog.pg_type r on op.oprright = r.oid 13 | left join pg_catalog.pg_type res on op.oprresult = res.oid 14 | where op.oprnamespace = $schema.id$ 15 | order by (op.oprname || case 16 | when op.oprkind = 'b'::"char" then l.typname || ',' || r.typname 17 | else coalesce(l.typname, r.typname) 18 | end)::text collate "C" 19 | -------------------------------------------------------------------------------- /scripts/postgres/content/pg_settings_group.sql: -------------------------------------------------------------------------------- 1 | select 2 | "name", 3 | setting, 4 | unit, 5 | short_desc || coalesce(extra_desc) description, 6 | context, 7 | vartype, 8 | source, 9 | min_val, 10 | max_val, 11 | enumvals, 12 | boot_val, 13 | reset_val, 14 | sourcefile, 15 | sourceline 16 | /* if version 90500 */ 17 | ,pending_restart 18 | /* endif version */ 19 | from pg_settings 20 | where category = '$pg_settings_group.name$' 21 | order by "name" 22 | -------------------------------------------------------------------------------- /scripts/postgres/content/procedure.sql: -------------------------------------------------------------------------------- 1 | do 2 | $$ 3 | declare 4 | _proc_oid oid := $procedure.id$; 5 | _comment text := obj_description(_proc_oid, 'pg_proc'); 6 | _proc_name text := '$schema.name$.$procedure.name$'; 7 | _tmp text; 8 | begin 9 | 10 | if '$children.ids$' = '-1' then 11 | select E'/*\nDROP PROCEDURE ' || _proc_name || '(' || oidvectortypes(p.proargtypes) || E');\n' || 12 | E'COMMENT ON PROCEDURE ' || _proc_name || '(' || oidvectortypes(p.proargtypes) || ') IS ' || 13 | coalesce(E'\n' || quote_literal(_comment), 'NULL') || E';\n*/\n' 14 | into _tmp 15 | from pg_proc p 16 | where p.oid = _proc_oid; 17 | 18 | raise notice E'%\n%;', _tmp, rtrim(pg_get_functiondef(_proc_oid), E'\n') 19 | using hint = 'script'; 20 | else 21 | with tmp as 22 | ( 23 | select a.n, a.i, row_number() over () as rn 24 | from pg_proc p 25 | cross join lateral ( 26 | -- stuff to support functions with anonimous arguments 27 | select a.n, coalesce(a.i, s.i) i 28 | from generate_series(1, p.pronargs) s(i) 29 | left join unnest(p.proargnames) with ordinality a(n, i) on s.i = a.i 30 | ) a 31 | where p.oid = _proc_oid and a.i in ($children.ids$) 32 | ) 33 | select 'CALL ' || _proc_name || '(' || 34 | string_agg( 35 | coalesce(n || '=>', 36 | case when rn = 1 then '/*you can''t use named notation with anon arguments*/' 37 | else '' 38 | end) || 39 | '$' || rn::text, 40 | ', ' order by tmp.i) || E');\n' 41 | into _tmp 42 | from tmp; 43 | 44 | raise notice E'%', _tmp using hint = 'script'; 45 | end if; 46 | end 47 | $$ 48 | -------------------------------------------------------------------------------- /scripts/postgres/content/procedures.sql: -------------------------------------------------------------------------------- 1 | select 2 | p.proname || ' (' || oidvectortypes(p.proargtypes) || ')' "procedure", 3 | p.oid, 4 | p.proowner::regrole "owner", 5 | obj_description(p.oid, 'pg_proc') "comment" 6 | from pg_proc p 7 | where p.pronamespace = $schema.id$ and p.prokind = 'p' 8 | order by 1 9 | -------------------------------------------------------------------------------- /scripts/postgres/content/recovery_state.sql: -------------------------------------------------------------------------------- 1 | select * from jsonb_each_text(to_jsonb((select r from pg_control_recovery() r))) 2 | order by 1 3 | -------------------------------------------------------------------------------- /scripts/postgres/content/role.sql: -------------------------------------------------------------------------------- 1 | do 2 | $$ 3 | declare 4 | _r record; 5 | _script text; 6 | begin 7 | if has_table_privilege('pg_authid'::regclass, 'select') then 8 | select r.oid, r.* into _r 9 | from pg_authid r 10 | where r.oid = $role.id$; 11 | else 12 | select * into _r 13 | from pg_roles r 14 | where r.oid = $role.id$; 15 | end if; 16 | 17 | _script := 18 | 'CREATE ROLE ' || quote_ident(_r.rolname) || 19 | coalesce(' WITH' || 20 | nullif( 21 | case when _r.rolcanlogin then E'\n\tLOGIN' else '' end || 22 | case when _r.rolsuper then E'\n\tSUPERUSER' else '' end || 23 | case when not _r.rolinherit then E'\n\tNOINHERIT' else '' end || 24 | case when _r.rolcreaterole then E'\n\tCREATEROLE' else '' end || 25 | case when _r.rolcreatedb then E'\n\tCREATEDB' else '' end || 26 | case when _r.rolreplication then E'\n\tREPLICATION' else '' end || 27 | case when _r.rolbypassrls then E'\n\tBYPASSRLS' else '' end || 28 | case when _r.rolconnlimit != -1 then E'\n\tCONNECTION LIMIT ' || _r.rolconnlimit::text else '' end || 29 | case when _r.rolpassword is not null then E'\n\tENCRYPTED PASSWORD ' || quote_literal(_r.rolpassword) else '' end || 30 | case when _r.rolvaliduntil is not null then E'\n\tVALID UNTIL ' || quote_literal(_r.rolvaliduntil::text) else '' end || 31 | coalesce(E'\n\tIN ROLE ' || (select string_agg(b.rolname, ', ') 32 | from pg_catalog.pg_auth_members m 33 | join pg_catalog.pg_roles b on m.roleid = b.oid 34 | where m.member = _r.oid and not m.admin_option), '') 35 | , '') 36 | , '') || E';\n' || 37 | coalesce( 38 | (select string_agg(E'GRANT ' || quote_ident(b.rolname) || ' TO ' || 39 | quote_ident(_r.rolname) || ' WITH ADMIN OPTION;', E'\n') 40 | from pg_catalog.pg_auth_members m 41 | join pg_catalog.pg_roles b on m.roleid = b.oid 42 | where m.member = _r.oid and m.admin_option) || E'\n' 43 | , '') || E'\n' || 44 | format(E'COMMENT ON ROLE %I IS %s;\n', 45 | _r.rolname, 46 | coalesce(E'\n' || quote_literal(shobj_description(_r.oid, 'pg_authid')), 'NULL')); 47 | 48 | raise notice '%', _script using hint = 'script'; 49 | end 50 | $$ 51 | -------------------------------------------------------------------------------- /scripts/postgres/content/roles.sql: -------------------------------------------------------------------------------- 1 | do 2 | $$ 3 | declare 4 | _r record; 5 | _script text := ''; 6 | _cursor refcursor; 7 | _levels jsonb; 8 | begin 9 | -- provide corect order of roles 10 | with recursive tmp as 11 | ( 12 | select r.oid roleid, 0 lvl 13 | from pg_roles r 14 | where not exists (select 1 from pg_auth_members where member = r.oid) 15 | union all 16 | select m.member, tmp.lvl + 1 17 | from tmp 18 | join pg_auth_members m on tmp.roleid = m.roleid 19 | ), 20 | levels as 21 | ( 22 | select roleid, min(lvl) lvl 23 | from tmp 24 | group by roleid 25 | ) 26 | select jsonb_object_agg(roleid::text, lvl) into _levels 27 | from levels; 28 | 29 | if has_table_privilege('pg_authid'::regclass, 'select') then 30 | open _cursor no scroll for 31 | select r.oid, r.* 32 | from pg_catalog.pg_authid r 33 | where r.oid in ($children.ids$) or '$children.ids$' = '-1' 34 | order by (_levels->>(r.oid::text))::int, r.rolcanlogin; 35 | else 36 | open _cursor no scroll for 37 | select * 38 | from pg_catalog.pg_roles r 39 | where r.oid in ($children.ids$) or '$children.ids$' = '-1' 40 | order by (_levels->>(r.oid::text))::int, r.rolcanlogin; 41 | end if; 42 | 43 | loop 44 | fetch _cursor into _r; 45 | exit when not found; 46 | 47 | _script := _script || 48 | 'CREATE ROLE ' || quote_ident(_r.rolname) || 49 | coalesce(' WITH' || 50 | nullif( 51 | case when _r.rolcanlogin then E'\n\tLOGIN' else '' end || 52 | case when _r.rolsuper then E'\n\tSUPERUSER' else '' end || 53 | case when not _r.rolinherit then E'\n\tNOINHERIT' else '' end || 54 | case when _r.rolcreaterole then E'\n\tCREATEROLE' else '' end || 55 | case when _r.rolcreatedb then E'\n\tCREATEDB' else '' end || 56 | case when _r.rolreplication then E'\n\tREPLICATION' else '' end || 57 | case when _r.rolbypassrls then E'\n\tBYPASSRLS' else '' end || 58 | case when _r.rolconnlimit != -1 then E'\n\tCONNECTION LIMIT ' || _r.rolconnlimit::text else '' end || 59 | case when _r.rolpassword is not null then E'\n\tENCRYPTED PASSWORD ' || quote_literal(_r.rolpassword) else '' end || 60 | case when _r.rolvaliduntil is not null then E'\n\tVALID UNTIL ' || quote_literal(_r.rolvaliduntil::text) else '' end || 61 | coalesce(E'\n\tIN ROLE ' || 62 | (select string_agg(b.rolname, ', ') 63 | from pg_catalog.pg_auth_members m 64 | join pg_catalog.pg_roles b on m.roleid = b.oid 65 | where m.member = _r.oid and not m.admin_option), '') 66 | , '') 67 | , '') || E';\n' || 68 | coalesce( 69 | (select string_agg(E'GRANT ' || quote_ident(b.rolname) || ' TO ' || 70 | quote_ident(_r.rolname) || ' WITH ADMIN OPTION;', E'\n') 71 | from pg_catalog.pg_auth_members m 72 | join pg_catalog.pg_roles b on m.roleid = b.oid 73 | where m.member = _r.oid and m.admin_option) || E'\n' 74 | , '') || 75 | coalesce('COMMENT ON ROLE ' || quote_ident(_r.rolname) || E' IS\n' || 76 | quote_literal(shobj_description(_r.oid, 'pg_authid')) || E'\n', ''); 77 | end loop; 78 | close _cursor; 79 | 80 | raise notice '%', _script using hint = 'script'; 81 | end 82 | $$ 83 | -------------------------------------------------------------------------------- /scripts/postgres/content/rule.sql: -------------------------------------------------------------------------------- 1 | select regexp_replace(pg_get_ruledef($rule.id$, true), '(\s+)(on|where|do)\s+', E'\n\t\\2 ', 'ig') as script; 2 | -------------------------------------------------------------------------------- /scripts/postgres/content/schema.sql: -------------------------------------------------------------------------------- 1 | do 2 | $$ 3 | declare 4 | _acl text; 5 | _def_acl text; 6 | _script text; 7 | _obj_id oid := $schema.id$; 8 | _obj_name text := '$schema.name$'; 9 | _nspacl aclitem[]; 10 | begin 11 | 12 | select 13 | 'CREATE SCHEMA ' || _obj_name || E'\n\tAUTHORIZATION ' || 14 | quote_ident(nspowner::regrole::text) || E';\n\n' || 15 | format(E'COMMENT ON SCHEMA %s IS %s;\n', 16 | _obj_name, 17 | coalesce(E'\n' || quote_literal(obj_description(_obj_id, 'pg_namespace')), 'NULL')), 18 | nspacl 19 | into _script, _nspacl 20 | from pg_catalog.pg_namespace 21 | where oid = _obj_id; 22 | 23 | with tmp as 24 | ( 25 | select 26 | d.defaclobjtype obj, 27 | a.grantee, 28 | string_agg(a.privilege_type, ', ') priv, 29 | array_agg(a.privilege_type) priv_array, 30 | a.is_grantable 31 | from pg_default_acl d 32 | cross join lateral aclexplode(d.defaclacl) a 33 | where d.defaclnamespace = _obj_id 34 | group by d.defaclobjtype, a.grantee, a.is_grantable 35 | ), 36 | tmp2 as 37 | ( 38 | select 39 | string_agg(case when grantee = 0 then 'public' else quote_ident(grantee::regrole::text) end, ', ') grantees, 40 | obj, priv, priv_array, is_grantable 41 | from tmp 42 | group by obj, priv, priv_array, is_grantable 43 | ) 44 | select string_agg( 45 | E'ALTER DEFAULT PRIVILEGES IN SCHEMA ' || _obj_name || 46 | E'\n\tGRANT ' || 47 | case 48 | when obj = 'r'::"char" and cardinality(priv_array) = 7 then 'ALL' 49 | else priv 50 | end || 51 | ' ON ' || 52 | case obj 53 | when 'r'::"char" then 'TABLES' 54 | when 'f'::"char" then 'FUNCTIONS' 55 | when 'S'::"char" then 'SEQUENCES' 56 | when 'T'::"char" then 'TYPES' 57 | else obj::text 58 | end || E' TO ' || grantees || 59 | case when is_grantable then ' WITH GRANT OPTION' else '' end || ';' 60 | , E'\n') 61 | into _def_acl 62 | from tmp2; 63 | 64 | with tmp as 65 | ( 66 | select 67 | grantee, 68 | string_agg(privilege_type, ', ') priv, 69 | array_agg(privilege_type) priv_array, 70 | is_grantable 71 | from aclexplode(_nspacl) a 72 | group by grantee, is_grantable 73 | ), 74 | tmp2 as 75 | ( 76 | select 77 | string_agg(case when grantee = 0 then 'public' else quote_ident(grantee::regrole::text) end, ', ') grantees, 78 | priv, priv_array, is_grantable 79 | from tmp 80 | group by priv, priv_array, is_grantable 81 | ) 82 | select string_agg( 83 | 'GRANT ' || 84 | case when cardinality(priv_array) = 2 /*check exact values?*/ then 'ALL' else priv end || 85 | ' ON SCHEMA ' || _obj_name || ' TO ' || grantees || 86 | case when is_grantable then ' WITH GRANT OPTION' else '' end || ';' 87 | , E'\n') 88 | into _acl 89 | from tmp2; 90 | 91 | _script := _script || 92 | coalesce(E'\n' || _def_acl, '') || 93 | coalesce(E'\n' || _acl, ''); 94 | 95 | raise notice '%', _script using hint = 'script'; 96 | 97 | end 98 | $$ 99 | -------------------------------------------------------------------------------- /scripts/postgres/content/sequence.sql: -------------------------------------------------------------------------------- 1 | /* if version 100000 */ 2 | do 3 | $$ 4 | declare 5 | _s record; 6 | _owned_by text; 7 | begin 8 | 9 | select * into _s 10 | from pg_catalog.pg_sequence s 11 | cross join $schema.name$.$sequence.name$ ss 12 | where s.seqrelid = $sequence.id$; 13 | 14 | select coalesce(quote_ident(t.relname) || '.' || quote_ident(a.attname), 'none') 15 | into _owned_by 16 | from pg_class s 17 | left join 18 | ( 19 | pg_depend d 20 | join pg_class t on d.refobjid = t.oid 21 | join pg_attribute a on a.attnum = d.refobjsubid and t.oid = a.attrelid 22 | ) on s.oid = d.objid 23 | where s.oid = $sequence.id$; 24 | 25 | raise notice 'CREATE SEQUENCE $schema.name$.$sequence.name$ 26 | INCREMENT % 27 | MINVALUE % 28 | MAXVALUE % 29 | START % 30 | CACHE % 31 | %CYCLE 32 | OWNED BY %;', 33 | _s.seqincrement, 34 | _s.seqmin, 35 | _s.seqmax, 36 | _s.last_value, 37 | _s.seqcache, 38 | case when _s.seqcycle then '' else 'NO ' end, 39 | _owned_by 40 | using hint='script'; 41 | end 42 | $$ 43 | 44 | /* elif version 90000 */ 45 | do 46 | $$ 47 | declare 48 | _s record; 49 | _owned_by text; 50 | begin 51 | select * into _s 52 | from $schema.name$.$sequence.name$; 53 | 54 | select coalesce(quote_ident(t.relname) || '.' || quote_ident(a.attname), 'none') 55 | into _owned_by 56 | from pg_class s 57 | left join 58 | ( 59 | pg_depend d 60 | join pg_class t on d.refobjid = t.oid 61 | join pg_attribute a on a.attnum = d.refobjsubid and t.oid = a.attrelid 62 | ) on s.oid = d.objid 63 | where s.oid = $sequence.id$; 64 | 65 | raise notice 'CREATE SEQUENCE $schema.name$.$sequence.name$ 66 | INCREMENT % 67 | MINVALUE % 68 | MAXVALUE % 69 | START % 70 | CACHE % 71 | %CYCLE 72 | OWNED BY %;', 73 | _s.increment_by, 74 | _s.min_value, 75 | _s.max_value, 76 | _s.last_value, 77 | _s.cache_value, 78 | case when _s.is_cycled then '' else 'NO ' end, 79 | _owned_by 80 | using hint='script'; 81 | end 82 | $$ 83 | /* endif version */ -------------------------------------------------------------------------------- /scripts/postgres/content/sessions.sql: -------------------------------------------------------------------------------- 1 | /* if version 100000 */ 2 | 3 | select 4 | s.datname, s.pid, 5 | now() - s.xact_start xact_duration, 6 | case when s.wait_event_type like '%Lock' then pg_blocking_pids(s.pid) end blocking_pids, 7 | s.backend_type, s.usename, s.application_name, s.client_addr, s.client_hostname, 8 | s.backend_start, s.xact_start, s.query_start, s.state_change, 9 | s.wait_event_type, s.wait_event, s.state, 10 | s.backend_xid, s.backend_xmin, s.query 11 | from pg_stat_activity s 12 | order by 1, 6, 2 13 | 14 | /* else version */ 15 | 16 | select 17 | s.datname, s.pid, 18 | now() - s.xact_start xact_duration, 19 | case when s.wait_event_type like '%Lock' then pg_blocking_pids(s.pid) end blocking_pids, 20 | s.usename, s.application_name, s.client_addr, s.client_hostname, 21 | s.backend_start, s.xact_start, s.query_start, s.state_change, 22 | /* if version 90600 */ 23 | s.wait_event_type, s.wait_event, s.state, 24 | /* else version */ 25 | s.state, 26 | /* endif version */ 27 | s.backend_xid, s.backend_xmin, s.query 28 | from pg_stat_activity s 29 | order by 1, 5, 2 30 | 31 | /* endif version */ -------------------------------------------------------------------------------- /scripts/postgres/content/tables.sql: -------------------------------------------------------------------------------- 1 | select 2 | c.relname as "name", 3 | c.oid, 4 | case 5 | when c.relnamespace = pg_my_temp_schema() then 'local temporary' 6 | when c.relkind = 'r'::"char" then 'ordinary table' 7 | when c.relkind = 'p'::"char" then 'partitioned table' 8 | when c.relkind = 'v'::"char" then 'view' 9 | when c.relkind = 'f'::"char" then 'foreign table' 10 | else null::text 11 | end as "type", 12 | (c.relkind = any (array['r'::"char", 'p'::"char"])) 13 | or (c.relkind = any (array['v'::"char", 'f'::"char"])) 14 | and (pg_relation_is_updatable(c.oid::regclass, false) & 8) = 8 15 | as is_insertable_into, 16 | pg_size_pretty(pg_relation_size(c.oid)) as table_size, 17 | c.reltuples, 18 | ( 19 | select pg_size_pretty(sum(pg_relation_size(x.indexrelid))) 20 | from pg_index x 21 | where x.indrelid = c.oid 22 | ) indexes_size, 23 | pg_size_pretty(inherited.inherited_size) inherited_size, 24 | inherited.inherited_reltuples, 25 | pg_size_pretty(inherited.inherited_indexes_size) inherited_indexes_size 26 | from pg_class c 27 | left join lateral ( 28 | select 29 | sum(pg_relation_size(i.inhrelid)) inherited_size, 30 | sum(pg_class.reltuples) inherited_reltuples, 31 | ( 32 | select sum(pg_relation_size(indexrelid)) 33 | from pg_index 34 | where indrelid = any(array_agg(pg_class.oid)) 35 | ) inherited_indexes_size 36 | from pg_inherits i 37 | join pg_class on i.inhrelid = pg_class.oid 38 | where i.inhparent = c.oid 39 | ) inherited on c.relkind = 'p'::"char" 40 | where c.relnamespace = $schema.id$ and 41 | (c.relkind = any (array['r'::"char", 'f'::"char", 'p'::"char"])) and 42 | not pg_is_other_temp_schema(c.relnamespace) and 43 | ( 44 | pg_has_role(c.relowner, 'usage'::text) or 45 | has_table_privilege(c.oid, 'select, insert, update, delete, truncate, references, trigger'::text) or 46 | has_any_column_privilege(c.oid, 'select, insert, update, references'::text) 47 | ) 48 | /* if version 110000 */ 49 | and 50 | ( 51 | ( 52 | $tables.id$ is null and 53 | coalesce(c.relispartition, false) = false 54 | ) 55 | or 56 | ( 57 | coalesce(c.relispartition, false) = true and 58 | exists ( 59 | select 1 60 | from pg_inherits p 61 | where p.inhrelid = c.oid and p.inhparent = $tables.id$ 62 | ) 63 | ) 64 | ) 65 | /* endif version */ 66 | order by greatest(pg_relation_size(c.oid), inherited.inherited_size) desc -------------------------------------------------------------------------------- /scripts/postgres/content/tablespaces.sql: -------------------------------------------------------------------------------- 1 | /* if version 90200 */ 2 | select 3 | s.spcname "name", 4 | pg_size_pretty(pg_tablespace_size(s.oid)) "size", 5 | s.oid, 6 | r.rolname "owner", 7 | pg_tablespace_location(s.oid) "location", 8 | s.spcacl acl, 9 | s.spcoptions "options", 10 | shobj_description(s.oid, 'pg_tablespace') description 11 | from pg_tablespace s 12 | join pg_roles r on s.spcowner = r.oid 13 | order by 1 14 | 15 | /* endif version */ -------------------------------------------------------------------------------- /scripts/postgres/content/test_html.sql: -------------------------------------------------------------------------------- 1 | select ' 2 | 3 | 4 |

Qt has a very limited support of html (without WebKit), 5 | but it is still enough for simple formatted output

6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
ValueDescription
DebitIn bookkeeping, an entry in the left hand column of an account to record a debt
CreditThe granting of a loan and the creation of debt. It is any form of deferred payment
20 | 21 | 22 | ' as html; -------------------------------------------------------------------------------- /scripts/postgres/content/trigger.sql: -------------------------------------------------------------------------------- 1 | select E'/*\nDROP TRIGGER $trigger.name$ ON $schema.name$.$table.name$;\n\n' || 2 | regexp_replace(pg_get_triggerdef($trigger.id$, true) || E';\n*/\n\n', '\m(after|before|on|for|execute)\M', E'\n\t\\1', 'ig') || 3 | pg_get_functiondef((select tgfoid from pg_trigger where oid = $trigger.id$)) || E';\n' as script 4 | -------------------------------------------------------------------------------- /scripts/postgres/content/type.sql: -------------------------------------------------------------------------------- 1 | do 2 | $$ 3 | declare 4 | _type text := '$type.tag$'; 5 | _obj_name text := '$schema.name$.$type.name$'; 6 | _obj_id oid := $type.id$; 7 | _content text; 8 | _comment text; 9 | begin 10 | 11 | if _type = 'e' then -- enum 12 | select 13 | 'CREATE TYPE ' || _obj_name || E' AS ENUM\n(\n' || 14 | string_agg( 15 | E'\t' || quote_literal(e.enumlabel), 16 | E',\n' order by e.enumsortorder) || E'\n);' 17 | into _content 18 | from pg_catalog.pg_enum e 19 | where e.enumtypid = _obj_id; 20 | elsif _type = 'c' then -- composite 21 | select 22 | 'CREATE TYPE ' || _obj_name || E' AS\n(\n' || 23 | string_agg( 24 | E'\t' || quote_ident(a.attname) || ' ' || pg_catalog.format_type(a.atttypid, a.atttypmod) || coalesce( 25 | ' COLLATE ' || 26 | case when a.attcollation = 0 or pg_describe_object('pg_collation'::regclass::oid, a.attcollation, 0) ilike '%default' then null 27 | else (pg_identify_object('pg_collation'::regclass::oid, a.attcollation, 0)).identity 28 | end, ''), 29 | E',\n' order by a.attnum) || E'\n);' 30 | into _content 31 | from pg_catalog.pg_type t 32 | join pg_catalog.pg_attribute a on t.typrelid = a.attrelid and not a.attisdropped 33 | where t.oid = _obj_id; 34 | elsif _type = 'r' then -- range 35 | select 36 | 'CREATE TYPE ' || _obj_name || E' AS RANGE\n(\n' || 37 | E'\tSUBTYPE = ' || t.typname || coalesce(E',\n' || 38 | E'\tSUBTYPE_OPCLASS = ' || opc.opcname, '') || coalesce(E',\n' || 39 | E'\tCOLLATION = ' || 40 | case when r.rngcollation = 0 or pg_describe_object('pg_collation'::regclass::oid, r.rngcollation, 0) ilike '%default' then null 41 | else (pg_identify_object('pg_collation'::regclass::oid, r.rngcollation, 0)).identity 42 | end, '') || coalesce(E',\n' || 43 | E'\tCANONICAL = ' || nullif(r.rngcanonical::text, '-'), '') || coalesce(E',\n' || 44 | E'\tSUBTYPE_DIFF = ' || nullif(r.rngsubdiff::text, '-'), '') || 45 | E'\n);' 46 | into _content 47 | from pg_catalog.pg_range r 48 | join pg_catalog.pg_type t on r.rngsubtype = t.oid 49 | left join pg_catalog.pg_opclass opc on r.rngsubopc = opc.oid 50 | where r.rngtypid = _obj_id; 51 | 52 | elsif _type in ('b','p') then -- base, preudo 53 | select 54 | 'CREATE TYPE ' || _obj_name || E'\n(\n' || 55 | E'\tINPUT = ' || t.typinput || E',\n' || 56 | E'\tOUTPUT = ' || t.typoutput || coalesce(E',\n' || 57 | E'\tRECEIVE = ' || nullif(t.typreceive::text, '-'), '') || coalesce(E',\n' || 58 | E'\tSEND = ' || nullif(t.typsend::text, '-'), '') || coalesce(E',\n' || 59 | E'\tTYPMOD_IN = ' || nullif(t.typmodin::text, '-'), '') || coalesce(E',\n' || 60 | E'\tTYPMOD_OUT = ' || nullif(t.typmodout::text, '-'), '') || coalesce(E',\n' || 61 | E'\tANALYZE = ' || nullif(t.typanalyze::text, '-'), '') || coalesce(E',\n' || 62 | E'\tINTERNALLENGTH = ' || nullif(t.typlen, -1)::text, '') || coalesce(E',\n' || 63 | E'\tPASSEDBYVALUE' || case when t.typbyval then '' else null end, '') || coalesce(E',\n' || 64 | E'\tALIGNMENT = ' || 65 | case t.typalign 66 | when 'c'::"char" then 'char' 67 | when 's'::"char" then 'short' 68 | when 'd'::"char" then 'double' 69 | else null -- int4 70 | end, '') || coalesce(E',\n' || 71 | E'\tSTORAGE = ' || case t.typstorage 72 | when 'e'::"char" then 'EXTERNAL' 73 | when 'm'::"char" then 'MAIN' 74 | when 'x'::"char" then 'EXTENDED' 75 | else null -- plain 76 | end, '') || coalesce(E',\n' || 77 | E'\tCATEGORY = ' || quote_literal(nullif(t.typcategory, 'U'::"char")::text), '') || coalesce(E',\n' || 78 | E'\tPREFERRED = ' || nullif(t.typispreferred, false), '') || coalesce(E',\n' || 79 | E'\tDEFAULT = ' || t.typdefault, '') || coalesce(E',\n' || 80 | E'\tELEMENT = ' || el.typname, '') || coalesce(E',\n' || 81 | E'\tDELIMITER = ' || nullif(t.typdelim, ','::"char")::text, '') || coalesce(E',\n' || 82 | E'\tCOLLATABLE = ' || nullif(t.typcollation != 0, false), '') || -- <-- ? not sure 83 | E'\n);' 84 | into _content 85 | from pg_catalog.pg_type t 86 | left join pg_catalog.pg_type el on t.typelem = el.oid 87 | where t.oid = _obj_id; 88 | 89 | else 90 | _content := E'not implemented\n'; 91 | end if; 92 | 93 | _comment := format(E'COMMENT ON TYPE %s IS %s;\n', 94 | _obj_name, 95 | coalesce(E'\n' || quote_literal(obj_description(_obj_id, 'pg_type')), 'NULL')); 96 | 97 | raise notice E'%\n\n%', _content, _comment using hint = 'script'; 98 | end 99 | $$ 100 | -------------------------------------------------------------------------------- /scripts/postgres/content/types.sql: -------------------------------------------------------------------------------- 1 | select 2 | t.typname, t.oid, t.typowner::regrole, obj_description(t.oid, 'pg_type') "comment" 3 | from pg_type t 4 | left join pg_class c on t.typrelid = c.oid 5 | where t.typnamespace = $schema.id$ and 6 | t.typtype not in ('d'::"char") and --exclude domains 7 | (c.relkind is null or c.relkind = 'c') and -- exclude composite types 8 | t.typname not like '\_%' -- not an array 9 | order by 1 -------------------------------------------------------------------------------- /scripts/postgres/content/views.sql: -------------------------------------------------------------------------------- 1 | select 2 | c.relname as "name", 3 | c.oid, 4 | case 5 | when nc.oid = pg_my_temp_schema() then 'local temporary' 6 | when c.relkind = any (array['r'::"char", 'p'::"char"]) then 'base table' 7 | when c.relkind = 'v'::"char" then 'view' 8 | when c.relkind = 'm'::"char" then 'materialized view' 9 | when c.relkind = 'f'::"char" then 'foreign table' 10 | else null::text 11 | end as "type", 12 | (c.relkind = any (array['r'::"char", 'p'::"char"])) 13 | or (c.relkind = any (array['v'::"char", 'f'::"char"])) 14 | and (pg_relation_is_updatable(c.oid::regclass, false) & 8) = 8 15 | as is_insertable_into 16 | from pg_namespace nc 17 | join pg_class c on nc.oid = c.relnamespace 18 | where nc.oid = $schema.id$ and 19 | c.relkind in ('v'::"char", 'm'::"char") and 20 | not pg_is_other_temp_schema(nc.oid) and 21 | ( 22 | pg_has_role(c.relowner, 'usage'::text) or 23 | has_table_privilege(c.oid, 'select, insert, update, delete, truncate, references, trigger'::text) or 24 | has_any_column_privilege(c.oid, 'select, insert, update, references'::text) 25 | ) 26 | order by c.relname -------------------------------------------------------------------------------- /scripts/postgres/preview/database.sql: -------------------------------------------------------------------------------- 1 | with tmp as 2 | ( 3 | select 4 | pg_get_userbyid(db.datdba) datdba, pg_encoding_to_char(db.encoding) "encoding", 5 | db.datcollate, db.datctype, db.datallowconn, db.datconnlimit, 6 | db.datfrozenxid, db.datminmxid, db.dattablespace, db.datacl, 7 | s.*, c.* 8 | from pg_database db 9 | join pg_stat_database s on db.oid = s.datid 10 | join pg_stat_database_conflicts c on db.oid = c.datid 11 | where db.oid = $database.id$ 12 | ) 13 | select "key", 14 | case "key" 15 | when 'temp_bytes' then pg_size_pretty("value"::bigint)::text 16 | when 'dattablespace' then (select spcname from pg_tablespace where oid = "value"::oid) 17 | else "value" 18 | end "value" 19 | from jsonb_each_text(to_jsonb((select tmp from tmp))) 20 | union all 21 | select 'database_size', pg_size_pretty(pg_database_size($database.id$))::text 22 | order by 1 23 | -------------------------------------------------------------------------------- /scripts/postgres/preview/db_locks.sql: -------------------------------------------------------------------------------- 1 | select 2 | l.locktype, l.relation::regclass::text relation, 3 | l.page, l.tuple, l.virtualxid, l.transactionid, 4 | --l.classid, l.objid, 5 | l.mode, l."granted", l.pid, pg_blocking_pids(l.pid) as wait_for, 6 | now() - s.xact_start xact_duration, 7 | s.backend_type, s.usename, s.application_name, s.client_addr, s.client_hostname, 8 | s.backend_start, s.xact_start, s.query_start, s.state_change, 9 | s.wait_event_type, s.wait_event, s.state, 10 | s.backend_xid, s.backend_xmin, s.query 11 | from pg_locks l 12 | left join pg_class c on l.relation = c.oid 13 | left join pg_stat_activity s on l.pid = s.pid 14 | where (l.database = $database.id$ or l.database = 0 or l.database is null) and (c.oid is null or c.relnamespace::regnamespace::text not in ('pg_catalog')) 15 | order by 1, 2 -------------------------------------------------------------------------------- /scripts/postgres/preview/role.sql: -------------------------------------------------------------------------------- 1 | with recursive tmp1 as 2 | ( 3 | -- roles which contain current role 4 | select member, roleid, 0 lvl 5 | from pg_auth_members 6 | where member = $role.id$ 7 | union all 8 | select m.member, m.roleid, tmp1.lvl + 1 9 | from tmp1 10 | join pg_auth_members m on tmp1.roleid = m.member 11 | ), 12 | tmp2 as 13 | ( -- members of current role 14 | select member, roleid, 0 lvl 15 | from pg_auth_members 16 | where roleid = $role.id$ 17 | union all 18 | select m.member, m.roleid, tmp2.lvl + 1 19 | from tmp2 20 | join pg_auth_members m on tmp2.member = m.roleid 21 | ), 22 | res1 as 23 | ( 24 | select distinct on (tmp1.roleid) tmp1.lvl, 25 | case when tmp1.lvl = 0 then 'direct' else 'indirect' end member_of, 26 | null::text contains, 27 | tmp1.roleid 28 | from tmp1 29 | order by tmp1.roleid, tmp1.lvl 30 | ), 31 | res2 as 32 | ( 33 | select distinct on (tmp2.member) tmp2.lvl, 34 | null::text member_of, 35 | case when tmp2.lvl = 0 then 'direct' else 'indirect' end contains, 36 | tmp2.member 37 | from tmp2 38 | order by tmp2.member, tmp2.lvl 39 | ) 40 | select 41 | res.member_of, res.contains, 42 | pg_get_userbyid(res.roleid) rolname, 43 | res.roleid, 44 | r.rolsuper, r.rolinherit, r.rolcreaterole, r.rolcreatedb, r.rolcanlogin, r.rolreplication, 45 | ( 46 | select array_agg(d.datname) 47 | from pg_database d 48 | where not d.datistemplate and has_database_privilege(r.oid, d.oid, 'CONNECT') 49 | ) may_connect 50 | from (select * from res1 union all select * from res2) res 51 | join pg_roles r on res.roleid = r.oid 52 | order by res.member_of is null, res.lvl, 2 -------------------------------------------------------------------------------- /scripts/postgres/preview/roles.sql: -------------------------------------------------------------------------------- 1 | select 2 | r.rolname, 3 | r.oid, 4 | r.rolsuper, 5 | r.rolinherit, 6 | r.rolcreaterole, 7 | r.rolcreatedb, 8 | r.rolcanlogin, 9 | r.rolconnlimit, r.rolvaliduntil, 10 | (select string_agg(b.rolname, ',') 11 | from pg_catalog.pg_auth_members m 12 | join pg_catalog.pg_roles b on m.roleid = b.oid 13 | where m.member = r.oid) as memberof, 14 | r.rolreplication, 15 | r.rolbypassrls, 16 | ( 17 | select array_agg(d.datname) 18 | from pg_database d 19 | where not d.datistemplate and has_database_privilege(r.oid, d.oid, 'CONNECT') 20 | ) may_connect 21 | from pg_catalog.pg_roles r 22 | order by not rolcanlogin, 1; -------------------------------------------------------------------------------- /scripts/postgres/preview/table.sql: -------------------------------------------------------------------------------- 1 | select * from $schema.name$.$table.name$ limit 100 -------------------------------------------------------------------------------- /scripts/postgres/preview/table_locks.sql: -------------------------------------------------------------------------------- 1 | select 2 | l.locktype, l.mode, l."granted", l.pid, pg_blocking_pids(l.pid) as wait_for, 3 | now() - s.xact_start xact_duration, 4 | s.backend_type, s.usename, s.application_name, s.client_addr, s.client_hostname, 5 | s.backend_start, s.xact_start, s.query_start, s.state_change, 6 | s.wait_event_type, s.wait_event, s.state, 7 | s.backend_xid, s.backend_xmin, s.query 8 | from pg_locks l 9 | left join pg_stat_activity s on l.pid = s.pid 10 | where l.relation = $table.id$::regclass; 11 | -------------------------------------------------------------------------------- /scripts/postgres/preview/table_stats.sql: -------------------------------------------------------------------------------- 1 | select 2 | attname, inherited, null_frac, avg_width, n_distinct, 3 | most_common_vals, most_common_freqs, histogram_bounds, 4 | correlation, most_common_elems, most_common_elem_freqs, elem_count_histogram 5 | from pg_stats where tablename = '$table.name$' and schemaname = '$schema.name$' 6 | -------------------------------------------------------------------------------- /scripts/postgres/recorded_statistics.sql: -------------------------------------------------------------------------------- 1 | /*sqt 2 | { 3 | "charts": [ 4 | { 5 | "name": "recorded statistics", 6 | "x": "ts", 7 | "y": { "f1": "#0c0" } 8 | } 9 | ] 10 | } 11 | */ 12 | 13 | select 14 | s.ts, 15 | 1 + sin(extract(epoch from s.ts)/10) + 2 * random() f1 16 | from generate_series(now(), now() + '20min'::interval, '1sec'::interval) as s(ts) -------------------------------------------------------------------------------- /scripts/postgres/statistics.sql: -------------------------------------------------------------------------------- 1 | /*sqt 2 | { 3 | "interval": 1000, 4 | "charts": [ 5 | { 6 | "name": "sessions", 7 | "y": { "active": "#0b0", "total": "#c00", "idle": "#00c" } 8 | }, 9 | { 10 | "name": "transactions, backends", 11 | "agg_y": { "xact_commit": "#0b0", "xact_rollback": "#c00" }, 12 | "y" : { "numbackends": "#00c" } 13 | }, 14 | { 15 | "name": "tuples out", 16 | "agg_y": { "fetched": "#cb0", "returned": "#0c0" } 17 | } 18 | ] 19 | } 20 | */ 21 | 22 | select count(*) total, 23 | count(*) filter (where state = 'active') active, 24 | count(*) filter (where state = 'idle') idle 25 | from pg_stat_activity; 26 | 27 | select 28 | sum(xact_commit) xact_commit, 29 | sum(numbackends) numbackends, 30 | sum(xact_rollback) xact_rollback, 31 | sum(tup_fetched) fetched, 32 | sum(tup_returned) returned 33 | from pg_stat_database; 34 | -------------------------------------------------------------------------------- /scripts/postgres/tree/cluster_state.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'checkpoint_state' node_type, 3 | 'Current checkpoint state' ui_name, 4 | '05' sort1 5 | union all 6 | select 7 | 'control_file_state', 8 | 'Current control file state', 9 | '06' 10 | union all 11 | select 12 | 'cluster_initialization_state', 13 | 'Cluster initialization state', 14 | '07' 15 | union all 16 | select 17 | 'recovery_state', 18 | 'Recovery state', 19 | '08' 20 | -------------------------------------------------------------------------------- /scripts/postgres/tree/connection.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'database' node_type, 3 | quote_ident(datname) "name", 4 | datname ui_name, 5 | oid::text id, 6 | false allow_multiselect, 7 | 'database-medium.png' icon, 8 | '00' || datname sort1 9 | from pg_database 10 | where not datistemplate 11 | union all 12 | select 13 | 'roles', 14 | null, 15 | 'Roles', 16 | null, 17 | true allow_multiselect, 18 | 'fingerprint.png', 19 | '01' 20 | union all 21 | select 22 | 'cluster_state', 23 | null, 24 | 'Cluster state', 25 | null, 26 | false, 27 | 'information-white.png', 28 | '02' 29 | where $dbms.version$ > 90600 30 | union all 31 | select 32 | 'pg_settings', 33 | null, 34 | 'Settings', 35 | null, 36 | false, 37 | 'equalizer.png', 38 | '04' 39 | union all 40 | select 41 | 'tablespaces', 42 | null, 43 | 'Tablespaces', 44 | null, 45 | false, 46 | null, 47 | '05' 48 | union all 49 | select 50 | 'sessions', 51 | null, 52 | 'Current sessions', 53 | null, 54 | false, 55 | null, 56 | '06' 57 | union all 58 | select 59 | 'test_html', 60 | null, 61 | 'Test HTML result', 62 | null, 63 | false, 64 | null, 65 | '10' 66 | -------------------------------------------------------------------------------- /scripts/postgres/tree/constraints.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'constraint' node_type, 3 | conname || coalesce( 4 | '  ' || 5 | case contype::text 6 | when 'f' then ' → ' || nullif(confrelid, 0)::regclass::text 7 | when 'c' then 'check' 8 | when 'p' then 'primary key' 9 | when 'u' then 'unique' 10 | when 't' then 'trigger' 11 | when 'x' then 'exclusion' 12 | else null 13 | end || '', 14 | '') ui_name, 15 | oid id, 16 | conname "name" 17 | from pg_constraint 18 | where conrelid = $table.id$ 19 | -------------------------------------------------------------------------------- /scripts/postgres/tree/database.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'schema' node_type, 3 | case when nspname in ('information_schema', 'pg_catalog') then '' || nspname || '' 4 | else nspname end ui_name, 5 | quote_ident(nspname) "name", 6 | oid id, 7 | 'layers-small.png' icon, 8 | case when nspname in ('information_schema', 'pg_catalog') then '0' else '1' end || nspname sort1 9 | from pg_catalog.pg_namespace 10 | where nspname !~ ('pg_toast.*|pg_temp.*') 11 | union all 12 | select 13 | 'extensions' node_type, 14 | 'Extensions' ui_name, 15 | null "name", 16 | null id, 17 | 'sd-memory-card.png' icon, 18 | 'z1' sort1 19 | union all 20 | select 21 | 'db_locks', 22 | 'Locks', 23 | null, 24 | null, 25 | null, 26 | 'z2' sort1 27 | -------------------------------------------------------------------------------- /scripts/postgres/tree/dependent_constraints.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'constraint' node_type, 3 | conname || coalesce( 4 | '  ' || 5 | case contype::text 6 | when 'f' then ' ← ' || nullif(conrelid, 0)::regclass::text 7 | else contype::text 8 | end || '', 9 | '') ui_name, 10 | oid id, 11 | conname "name" 12 | from pg_constraint 13 | where confrelid = $table.id$ 14 | -------------------------------------------------------------------------------- /scripts/postgres/tree/domains.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'domain' node_type, 3 | t.typname || coalesce(' ' || 4 | pg_catalog.format_type(t.typbasetype, t.typtypmod) || 5 | case when t.typnotnull then ' NOT NULL' else '' end || 6 | '', '') ui_name, 7 | t.oid id, 8 | quote_ident(t.typname) "name", 9 | t.typtype tag 10 | from pg_type t 11 | where t.typnamespace = $schema.id$ and 12 | t.typtype = 'd' 13 | -------------------------------------------------------------------------------- /scripts/postgres/tree/extensions.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'extension' node_type, 3 | extname || ' ' || extversion || '' ui_name, 4 | extname "name", 5 | oid id 6 | from pg_extension -------------------------------------------------------------------------------- /scripts/postgres/tree/function.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'fn_argument' node_type, 3 | arg.i id, 4 | coalesce(arg.n || '  ', '') || '' || 5 | format_type(arg.t, null) || 6 | '' ui_name, 7 | quote_ident(arg.n) "name", 8 | arg.i sort1, 9 | arg.n sort2 10 | from pg_proc p 11 | cross join unnest(p.proargnames, p.proargmodes, p.proargtypes::oid[]) with ordinality arg(n, m, t, i) 12 | where p.oid = $function.id$ and arg.t is not null 13 | -------------------------------------------------------------------------------- /scripts/postgres/tree/functions.sql: -------------------------------------------------------------------------------- 1 | /* if version 110000 */ 2 | select 3 | case p.prokind when 'a' then 'agg_function' else 'function' end node_type, 4 | p.oid id, 5 | format( 6 | '%I (%s) %s', --
 -> %s', 7 | p.proname, 8 | --pg_get_function_identity_arguments(p.oid), 9 | oidvectortypes(p.proargtypes), 10 | --pg_get_function_result(p.oid) 11 | case 12 | when p.prokind = 'a' then 'Σ' 13 | when t.oid is not null then ' tr' 14 | else '' 15 | end 16 | ) ui_name, 17 | quote_ident(p.proname) "name", 18 | --'function.png' icon, 19 | (p.prokind != 'a' and p.proargnames is not null) as allow_multiselect, 20 | p.proname || oidvectortypes(p.proargtypes) sort1, 21 | case 22 | when p.prokind = 'a' then '2' 23 | when t.oid is not null then '1' 24 | else '0' 25 | end || p.proname || oidvectortypes(p.proargtypes) sort2 26 | from pg_proc p 27 | left join lateral ( 28 | select t.oid 29 | from pg_trigger t 30 | where t.tgfoid = p.oid and not t.tgisinternal 31 | limit 1) t on true 32 | where p.pronamespace = $schema.id$ and p.prokind != 'p' 33 | 34 | /* elif version 80000 */ 35 | select 36 | case when p.proisagg then 'agg_function' else 'function' end node_type, 37 | p.oid id, 38 | format( 39 | '%I (%s) %s', --
 -> %s', 40 | p.proname, 41 | --pg_get_function_identity_arguments(p.oid), 42 | oidvectortypes(p.proargtypes), 43 | --pg_get_function_result(p.oid) 44 | case 45 | when p.proisagg then 'Σ' 46 | when t.oid is not null then ' tr' 47 | else '' 48 | end 49 | ) ui_name, 50 | quote_ident(p.proname) "name", 51 | --'function.png' icon, 52 | (not p.proisagg and p.proargnames is not null) as allow_multiselect, 53 | p.proname || oidvectortypes(p.proargtypes) sort1, 54 | case 55 | when p.proisagg then '2' 56 | when t.oid is not null then '1' 57 | else '0' 58 | end || p.proname || oidvectortypes(p.proargtypes) sort2 59 | from pg_proc p 60 | left join lateral ( 61 | select t.oid 62 | from pg_trigger t 63 | where t.tgfoid = p.oid and not t.tgisinternal 64 | limit 1) t on true 65 | where p.pronamespace = $schema.id$ 66 | /* endif version */ -------------------------------------------------------------------------------- /scripts/postgres/tree/indexes.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'index' node_type, 3 | i.relname || 4 | ' ' || am.amname || ' ' || 5 | case when x.indisprimary then 'P' else '' end || 6 | case when x.indisunique then 'u' else '' end || 7 | '' ui_name, 8 | i.oid id, 9 | i.relname "name", 10 | i.reltablespace tag, 11 | i.relname sort1 12 | from pg_index x 13 | join pg_class c on c.oid = x.indrelid 14 | join pg_class i on i.oid = x.indexrelid 15 | left join pg_am am on i.relam = am.oid 16 | where c.oid = $table.id$ and x.indislive -------------------------------------------------------------------------------- /scripts/postgres/tree/operator_classes.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'operator_class' node_type, 3 | right(left(xmlelement(name x, oc.opcname)::text, -4), -3) || ' (' || 4 | m.amname || ')' || '' ui_name, 5 | oc.opcname "name", 6 | oc.oid id, 7 | oc.opcname || m.amname sort1, 8 | m.amname || oc.opcname sort2 9 | from pg_catalog.pg_opclass oc 10 | left join pg_catalog.pg_am m on oc.opcmethod = m.oid 11 | where oc.opcnamespace = $schema.id$ 12 | -------------------------------------------------------------------------------- /scripts/postgres/tree/operators.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'operator' node_type, 3 | right(left(xmlelement(name x, op.oprname)::text, -4), -3) || ' (' || 4 | case 5 | when op.oprkind = 'b'::"char" then l.typname || ',' || r.typname 6 | else coalesce(l.typname, r.typname) 7 | end || ') → ' || res.typname || '' ui_name, 8 | op.oprname "name", 9 | op.oid id, 10 | op.oprname || case 11 | when op.oprkind = 'b'::"char" then l.typname || ',' || r.typname 12 | else coalesce(l.typname, r.typname) 13 | end sort1 14 | from pg_catalog.pg_operator op 15 | left join pg_catalog.pg_type l on op.oprleft = l.oid 16 | left join pg_catalog.pg_type r on op.oprright = r.oid 17 | left join pg_catalog.pg_type res on op.oprresult = res.oid 18 | where op.oprnamespace = $schema.id$ -------------------------------------------------------------------------------- /scripts/postgres/tree/operators_related.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'operators' node_type, 3 | null::text "name", 4 | 'Operators' ui_name, 5 | null::text id, 6 | 'operators.png' icon, 7 | 1 sort1 8 | union all 9 | select 10 | 'operator_classes', 11 | null::text, 12 | 'Operator classes', 13 | null, 14 | 'operator-classes.png', 15 | 2 16 | union all 17 | select 18 | 'operator_families', 19 | null::text, 20 | 'Operator families', 21 | null, 22 | 'operator-families.png', 23 | 3 -------------------------------------------------------------------------------- /scripts/postgres/tree/pg_settings.sql: -------------------------------------------------------------------------------- 1 | select distinct 2 | 'pg_settings_group' node_type, 3 | category "name", 4 | category ui_name, 5 | category sort1 6 | from pg_settings 7 | -------------------------------------------------------------------------------- /scripts/postgres/tree/procedures.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'procedure' node_type, 3 | p.oid id, 4 | format( 5 | '%I (%s)', --
 -> %s', 6 | p.proname, 7 | --pg_get_function_identity_arguments(p.oid), 8 | oidvectortypes(p.proargtypes) 9 | --pg_get_function_result(p.oid) 10 | ) ui_name, 11 | quote_ident(p.proname) "name", 12 | --'function.png' icon, 13 | (p.proargnames is not null) as allow_multiselect, 14 | p.proname || oidvectortypes(p.proargtypes) sort1 15 | from pg_proc p 16 | where p.pronamespace = $schema.id$ and p.prokind = 'p' 17 | -------------------------------------------------------------------------------- /scripts/postgres/tree/roles.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'role' node_type, 3 | rolname ui_name, 4 | rolname "name", 5 | oid id, 6 | case 7 | when not rolcanlogin then 'users.png' 8 | when rolsuper then 'ghost.png' 9 | else 'user-medium.png' 10 | end icon, 11 | (not rolcanlogin)::int::text || rolname sort1 12 | from pg_catalog.pg_roles 13 | -------------------------------------------------------------------------------- /scripts/postgres/tree/rules.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'rule' node_type, 3 | r.rulename ui_name, 4 | quote_ident(r.rulename) "name", 5 | r.oid id 6 | from pg_rewrite r 7 | where r.ev_class = $table.id$ and r.rulename != '_RETURN'; -------------------------------------------------------------------------------- /scripts/postgres/tree/schema.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'functions' node_type, 3 | null::text "name", 4 | 'Functions' ui_name, 5 | null::text id, 6 | 'function.png' icon, 7 | --null::text icon, 8 | 1 sort1 9 | union all 10 | select 11 | 'procedures', 12 | null, 13 | 'Procedures', 14 | null, 15 | 'procedure.png', 16 | 2 17 | where $dbms.version$ >= 110000 18 | union all 19 | select 20 | 'sequences', 21 | null, 22 | 'Sequences', 23 | null, 24 | 'ui-paginator.png', 25 | 3 26 | union all 27 | select 28 | 'tables', 29 | null, 30 | 'Tables', 31 | null, 32 | 'tables.png', 33 | 4 34 | union all 35 | select 36 | 'types', 37 | null, 38 | 'Types', 39 | null, 40 | 'block.png', 41 | 5 42 | union all 43 | select 44 | 'domains', 45 | null, 46 | 'Domains', 47 | null, 48 | 'hard-hat.png', 49 | 6 50 | union all 51 | select 52 | 'views', 53 | null, 54 | 'Views', 55 | null, 56 | 'views.png', 57 | 7 58 | union all 59 | select 60 | 'operators_related', 61 | null, 62 | 'Ops', 63 | null, 64 | 'operators-related.png', 65 | 8 66 | -------------------------------------------------------------------------------- /scripts/postgres/tree/sequences.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'sequence' node_type, 3 | s.relname || coalesce(' → ' || quote_ident(t.relname) || '(' || quote_ident(a.attname) || ')', '') ui_name, 4 | s.oid id, 5 | s.relname "name", 6 | s.relname sort1 7 | from pg_class s 8 | left join 9 | ( 10 | pg_depend d 11 | join pg_class t on d.refobjid = t.oid 12 | join pg_attribute a on a.attnum = d.refobjsubid and t.oid = a.attrelid 13 | ) on s.oid = d.objid 14 | where s.relkind = 'S' and s.relnamespace = $schema.id$; 15 | -------------------------------------------------------------------------------- /scripts/postgres/tree/table.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'column' node_type, 3 | a.attname || 4 | ' ' || 5 | case when x.indexrelid is null then '' else ' ⚷ ' end || 6 | pg_catalog.format_type(a.atttypid, a.atttypmod) || 7 | case when a.attnotnull then ' NOT NULL' else '' end || 8 | '' as ui_name, 9 | a.attnum id, 10 | a.attname "name", 11 | --case when x.indexrelid is null then 'transparent.png' else 'key.png' end icon, 12 | null icon, 13 | attnum sort1, 14 | '0' || a.attname sort2 15 | from pg_catalog.pg_attribute a 16 | left join pg_index x on 17 | $table.id$ = x.indrelid and 18 | x.indisprimary and 19 | a.attnum = any(x.indkey) and 20 | x.indislive 21 | where a.attnum > 0 and not a.attisdropped and a.attrelid = $table.id$ 22 | union all 23 | select 24 | 'tables', 25 | 'Partitions', 26 | $table.id$, 27 | null, 28 | 'tables.png', 29 | x'7FFFFFF0'::int, 30 | '1' 31 | where '$table.tag$' = 'p' 32 | union all 33 | select 34 | 'triggers', 35 | 'Triggers', 36 | null, 37 | null, 38 | 'arrow-transition.png', 39 | x'7FFFFFF1'::int, 40 | '1' 41 | where '$table.tag$' != 'f' 42 | union all 43 | select 44 | 'indexes', 45 | 'Indexes', 46 | null, 47 | null, 48 | 'paper-plane.png', 49 | x'7FFFFFF2'::int, 50 | '2' 51 | where '$table.tag$' not in ('v', 'f') 52 | union all 53 | select 54 | 'constraints', 55 | 'Constraints', 56 | null, 57 | null, 58 | 'traffic-cone.png', 59 | x'7FFFFFF3'::int, 60 | '3' 61 | where '$table.tag$' in ('r', 'p') 62 | union all 63 | select 64 | 'dependent_constraints', 65 | 'Dependent constraints', 66 | null, 67 | null, 68 | 'traffic-cone.png', 69 | x'7FFFFFF3'::int, 70 | '4' 71 | where '$table.tag$' in ('r', 'p') 72 | union all 73 | select 74 | 'rules', 75 | 'Rules', 76 | null, 77 | null, 78 | 'image-saturation-up.png', 79 | x'7FFFFFF4'::int, 80 | '5' 81 | where '$table.tag$' != 'f' 82 | union all 83 | select 84 | 'table_locks', 85 | 'Locks', 86 | null, 87 | null, 88 | null, 89 | x'7FFFFFF5'::int, 90 | '6' 91 | union all 92 | select 93 | 'table_stats', 94 | 'Per-column statistics', 95 | null, 96 | null, 97 | null, 98 | x'7FFFFFF6'::int, 99 | '7' 100 | -------------------------------------------------------------------------------- /scripts/postgres/tree/tables.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'table' node_type, 3 | c.relname || coalesce(' ' || 4 | case 5 | when c.relpersistence = 'u'::"char" then 'unlogged' 6 | when c.relkind = 'f'::"char" then 7 | '← ' || 8 | (select srvname 9 | from pg_foreign_table t 10 | join pg_foreign_server s on t.ftserver = s.oid 11 | where t.ftrelid = c.oid) 12 | else '' 13 | end || 14 | case when c.relkind = 'p'::"char" then 'partitioned' else '' end || 15 | '', '') ui_name, 16 | c.oid id, 17 | c.relkind::text tag, 18 | quote_ident(c.relname) "name", 19 | true allow_multiselect, 20 | 'table.png' icon, 21 | c.relname sort1, 22 | c.relkind::text || c.relname sort2 23 | from pg_class c 24 | where c.relnamespace = $schema.id$ and 25 | (c.relkind = any (array['r'::"char", 'f'::"char", 'p'::"char"])) and 26 | not pg_is_other_temp_schema(c.relnamespace) and 27 | ( 28 | pg_has_role(c.relowner, 'usage'::text) or 29 | has_table_privilege(c.oid, 'select, insert, update, delete, truncate, references, trigger'::text) or 30 | has_any_column_privilege(c.oid, 'select, insert, update, references'::text) 31 | ) 32 | /* if version 110000 */ 33 | and 34 | ( 35 | ( 36 | $tables.id$ is null and 37 | coalesce(c.relispartition, false) = false 38 | ) 39 | or 40 | ( 41 | coalesce(c.relispartition, false) = true and 42 | exists ( 43 | select 1 44 | from pg_inherits p 45 | where p.inhrelid = c.oid and p.inhparent = $tables.id$ 46 | ) 47 | ) 48 | ) 49 | /* endif version */ 50 | order by c.relname desc -------------------------------------------------------------------------------- /scripts/postgres/tree/triggers.sql: -------------------------------------------------------------------------------- 1 | SELECT 2 | 'trigger' node_type, 3 | t.tgname || 4 | '  ' || 5 | case 6 | when (t.tgtype & (1 << 1))::boolean then 'before' 7 | when (t.tgtype & (1 << 6))::boolean then 'instead of' 8 | else 'after' 9 | end || ' ' || 10 | ( 11 | select string_agg(act, '') 12 | from unnest( 13 | ARRAY[ 14 | case when (t.tgtype & (1 << 2))::boolean then 'I' else null end, 15 | case when (t.tgtype & (1 << 3))::boolean then 'D' else null end, 16 | case when (t.tgtype & (1 << 4))::boolean then 'U' else null end, 17 | case when (t.tgtype & (1 << 5))::boolean then 'T' else null end 18 | ]) a(act) 19 | where act is not null 20 | ) || ' ' || 21 | case when (t.tgtype & (1 << 0))::boolean then 'row' else 'statement' end || 22 | '' ui_name, 23 | t.oid id, 24 | t.tgname "name", 25 | t.tgname sort1 26 | FROM pg_trigger t 27 | WHERE t.tgrelid = coalesce($table.id$, $view.id$) and not t.tgisinternal 28 | -------------------------------------------------------------------------------- /scripts/postgres/tree/types.sql: -------------------------------------------------------------------------------- 1 | select 2 | 'type' node_type, 3 | t.typname || coalesce(' ' || 4 | case 5 | when t.typtype = 'b'::"char" then 'base' 6 | when t.typtype = 'c'::"char" then 'composite' 7 | when t.typtype = 'e'::"char" then 'enum' 8 | when t.typtype = 'p'::"char" then 'pseudo-type' 9 | when t.typtype = 'r'::"char" then 'range' 10 | end || '', '') ui_name, 11 | t.oid id, 12 | quote_ident(t.typname) "name", 13 | t.typtype tag, 14 | t.typname sort1 15 | from pg_type t 16 | left join pg_class c on t.typrelid = c.oid 17 | where t.typnamespace = $schema.id$ and 18 | t.typtype not in ('d'::"char") and --exclude domains 19 | (c.relkind is null or c.relkind = 'c') and 20 | t.typname not like '\_%' -- not an array 21 | -------------------------------------------------------------------------------- /scripts/postgres/tree/views.sql: -------------------------------------------------------------------------------- 1 | select 2 | --case when c.relkind = 'v'::"char" then 'view' else 'mview' end node_type, 3 | 'table' node_type, 4 | c.relname || 5 | case when c.relkind = 'm'::"char" then ' M' else '' end ui_name, 6 | c.oid id, 7 | c.relkind::text tag, 8 | quote_ident(c.relname) "name", 9 | true allow_multiselect, 10 | 'table-join.png' icon, 11 | c.relname sort1 12 | from pg_namespace nc 13 | join pg_class c on nc.oid = c.relnamespace 14 | where nc.oid = $schema.id$ and 15 | c.relkind in ('v'::"char", 'm'::"char") and 16 | not pg_is_other_temp_schema(nc.oid) and 17 | ( 18 | pg_has_role(c.relowner, 'usage'::text) or 19 | has_table_privilege(c.oid, 'select, insert, update, delete, truncate, references, trigger'::text) or 20 | has_any_column_privilege(c.oid, 'select, insert, update, references'::text) 21 | ) 22 | order by c.relname -------------------------------------------------------------------------------- /sqt.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | background 10 | 11 | 12 | 13 | 14 | 15 | 16 | Layer 1 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/appeventhandler.h: -------------------------------------------------------------------------------- 1 | #ifndef APPEVENTHANDLER_H 2 | #define APPEVENTHANDLER_H 3 | 4 | #include 5 | 6 | class AppEventHandler : public QObject 7 | { 8 | Q_OBJECT 9 | public: 10 | explicit AppEventHandler(QObject *parent = nullptr); 11 | 12 | protected: 13 | bool eventFilter(QObject *obj, QEvent *event); 14 | }; 15 | 16 | #endif // APPEVENTHANDLER_H 17 | -------------------------------------------------------------------------------- /src/codeeditor.h: -------------------------------------------------------------------------------- 1 | #ifndef CODEEDITOR_H 2 | #define CODEEDITOR_H 3 | 4 | #include 5 | #include 6 | 7 | class CodeBlockProperties; 8 | class QCompleter; 9 | class CodeEditor; 10 | 11 | namespace Bookmarks 12 | { 13 | CodeBlockProperties* next(); 14 | CodeBlockProperties* previous(); 15 | CodeBlockProperties* last(); 16 | void remove(CodeBlockProperties* item); 17 | void suspend(); 18 | void resume(); 19 | } 20 | 21 | class CodeBlockProperties : public QTextBlockUserData 22 | { 23 | public: 24 | CodeBlockProperties(CodeEditor *editor, CodeBlockProperties *toReplace); 25 | CodeBlockProperties(CodeEditor *editor); 26 | ~CodeBlockProperties(); 27 | CodeEditor* editor() const; 28 | private: 29 | // bool _isBookmarked = true; 30 | CodeEditor *_editor; 31 | }; 32 | 33 | class CodeEditor : public QPlainTextEdit 34 | { 35 | Q_OBJECT 36 | public: 37 | CodeEditor(QWidget *parent = nullptr); 38 | void leftSideBarPaintEvent(QPaintEvent *event); 39 | int leftSideBarWidth() const; 40 | QString text() const; 41 | void setCompleter(QCompleter *completer); 42 | 43 | protected: 44 | void resizeEvent(QResizeEvent *event) override; 45 | virtual bool eventFilter(QObject *object, QEvent *event) override; 46 | virtual void keyPressEvent(QKeyEvent *e) override; 47 | void insertFromMimeData(const QMimeData *source) override; 48 | 49 | private slots: 50 | void updateLeftSideBarWidth(); 51 | void updateLeftSideBar(const QRect &rect, int dy); 52 | void onHlTimerTimeout(); 53 | void insertCompletion(const QString &completion); 54 | 55 | private: 56 | QList matchBracket(QString &docContent, const QTextCursor &selectedBracket, int darkerFactor = 100) const; 57 | QList currentLineSelection() const; 58 | bool isEnveloped(int pos) const; 59 | QWidget *_leftSideBar; 60 | QTimer *_hlTimer; 61 | QCompleter *_completer = nullptr; 62 | 63 | signals: 64 | void completerRequest(); 65 | }; 66 | 67 | #endif // CODEEDITOR_H 68 | -------------------------------------------------------------------------------- /src/connectiondialog.cpp: -------------------------------------------------------------------------------- 1 | #include "connectiondialog.h" 2 | #include "ui_connectiondialog.h" 3 | #include 4 | //#include 5 | #include 6 | 7 | ConnectionDialog::ConnectionDialog(QWidget *parent, QString name, QString connectionString) : 8 | QDialog(parent), 9 | ui(new Ui::ConnectionDialog) 10 | { 11 | ui->setupUi(this); 12 | ui->editCS->setWordWrapMode(QTextOption::WrapAnywhere); 13 | setWindowFlags(Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint); 14 | 15 | if (connectionString.isEmpty()) 16 | { 17 | // i was forced to do this rainbow :/ 18 | // some people don't understand that odbc and pg connection string patterns are mutually exclusive 19 | QTextCharFormat fmt = ui->editCS->currentCharFormat(); 20 | auto appendText = [this, &fmt](const QColor &color, const QString &text) { 21 | fmt.setForeground(QBrush(color)); 22 | ui->editCS->mergeCurrentCharFormat(fmt); 23 | ui->editCS->appendPlainText(text); 24 | }; 25 | appendText(Qt::darkGray, tr("make use of ONE of these two sample patterns:")); 26 | appendText(Qt::darkGray, tr(" ↓ postgresql native")); 27 | appendText("#E03080FF", "host=127.0.0.1 port=5432 dbname=postgres user=%user% password=%pass% connect_timeout=5"); 28 | appendText(Qt::darkGray, tr(" ↓ odbc")); 29 | appendText("#E03080FF", 30 | #ifdef Q_OS_WIN32 31 | "Driver={SQL Server Native Client 11.0};Server=srv_name;Database=db_name;Trusted_Connection=yes;App=sqt;" 32 | #else 33 | "Driver=FreeTDS;Server=mssql.local;TDS_Version=7.2;Port=1433;Database=master;UID=%user%;PWD=%pass%;ClientCharset=UTF-8;App=sqt;" 34 | #endif 35 | ); 36 | } 37 | else 38 | { 39 | ui->editCS->setPlainText(connectionString); 40 | } 41 | ui->editName->setText(name); 42 | QRect frect = frameGeometry(); 43 | // QWidget::screen() is too new to be used 44 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 45 | QScreen *screen = QGuiApplication::screenAt(QApplication::activeWindow()->pos()); 46 | #else 47 | QScreen *screen = QApplication::activeWindow()->screen(); 48 | #endif 49 | frect.moveCenter(screen->availableGeometry().center()); 50 | move(frect.topLeft()); 51 | } 52 | 53 | ConnectionDialog::~ConnectionDialog() 54 | { 55 | delete ui; 56 | } 57 | 58 | QString ConnectionDialog::name() 59 | { 60 | return ui->editName->text(); 61 | } 62 | 63 | QString ConnectionDialog::connectionString() 64 | { 65 | return ui->editCS->toPlainText(); 66 | } 67 | 68 | void ConnectionDialog::changeEvent(QEvent *e) 69 | { 70 | QDialog::changeEvent(e); 71 | switch (e->type()) { 72 | case QEvent::LanguageChange: 73 | ui->retranslateUi(this); 74 | break; 75 | default: 76 | break; 77 | } 78 | } 79 | 80 | void ConnectionDialog::on_buttonBox_clicked(QAbstractButton *button) 81 | { 82 | if (ui->buttonBox->standardButton(button) == QDialogButtonBox::Ok) 83 | accept(); 84 | else 85 | reject(); 86 | } 87 | -------------------------------------------------------------------------------- /src/connectiondialog.h: -------------------------------------------------------------------------------- 1 | #ifndef CONNECTIONDIALOG_H 2 | #define CONNECTIONDIALOG_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class ConnectionDialog; 8 | } 9 | 10 | class QAbstractButton; 11 | 12 | class ConnectionDialog : public QDialog 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | explicit ConnectionDialog(QWidget *parent = nullptr, QString name = QString(), QString connectionString = QString()); 18 | ~ConnectionDialog(); 19 | QString name(); 20 | QString connectionString(); 21 | 22 | protected: 23 | void changeEvent(QEvent *e); 24 | 25 | private slots: 26 | void on_buttonBox_clicked(QAbstractButton *button); 27 | 28 | private: 29 | Ui::ConnectionDialog *ui; 30 | }; 31 | 32 | #endif // CONNECTIONDIALOG_H 33 | -------------------------------------------------------------------------------- /src/connectiondialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | ConnectionDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 814 10 | 312 11 | 12 | 13 | 14 | dbms connection 15 | 16 | 17 | 18 | 19 | 20 | Name 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | ODBC <b>or</b> PostgreSQL connection string 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | QLabel { font-size: 9pt; color: teal;} 41 | 42 | 43 | <html><head/><body><span>macroses %user% and %pass% available</span><br/><span><a href="http://www.freetds.org/userguide/choosingtdsprotocol.htm"><span style=" text-decoration: underline; color:#0000ff;">TDS_Version</span></a></span></body></html> 44 | 45 | 46 | true 47 | 48 | 49 | true 50 | 51 | 52 | 53 | 54 | 55 | 56 | Qt::Vertical 57 | 58 | 59 | QSizePolicy::Fixed 60 | 61 | 62 | 63 | 20 64 | 5 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | Qt::Horizontal 73 | 74 | 75 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | buttonBox 85 | accepted() 86 | ConnectionDialog 87 | accept() 88 | 89 | 90 | 257 91 | 224 92 | 93 | 94 | 157 95 | 274 96 | 97 | 98 | 99 | 100 | buttonBox 101 | rejected() 102 | ConnectionDialog 103 | reject() 104 | 105 | 106 | 325 107 | 224 108 | 109 | 110 | 286 111 | 274 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /src/copycontext.cpp: -------------------------------------------------------------------------------- 1 | #include "copycontext.h" 2 | #include 3 | #include "queryoptions.h" 4 | 5 | void PgCopyContext::init(const QString &query) 6 | { 7 | clear(); 8 | auto qo = QueryOptions::Extract(query); 9 | if (qo.contains("copy_src")) 10 | _srcFiles = qo["copy_src"].toVariant().toStringList(); 11 | if (qo.contains("copy_dst")) 12 | _dstFiles = qo["copy_dst"].toVariant().toStringList(); 13 | _initialized = true; 14 | } 15 | 16 | void PgCopyContext::clear() 17 | { 18 | _file.close(); 19 | _srcFiles.clear(); 20 | _dstFiles.clear(); 21 | _curSrcIndex = -1; 22 | _curDstIndex = -1; 23 | _initialized = false; 24 | } 25 | 26 | bool PgCopyContext::nextSource() 27 | { 28 | if (_file.isOpen()) 29 | _file.close(); 30 | if (++_curSrcIndex > _srcFiles.size() - 1) 31 | { 32 | emit error(tr("COPY source file is not specified.\n" 33 | " Use special comment to pass source file: /*sqt { \"copy_src\": [\"\", \"\"...] } */" 34 | " In case of single COPY FROM query non-array form is allowed: /*sqt { \"copy_src\": \"\" } */\n")); 35 | return false; 36 | } 37 | _file.setFileName(_srcFiles[_curSrcIndex]); 38 | if (!_file.open(QIODevice::ReadOnly)) 39 | { 40 | emit error(_file.errorString()); 41 | return false; 42 | } 43 | return true; 44 | } 45 | 46 | bool PgCopyContext::nextDestination() 47 | { 48 | if (_file.isOpen()) 49 | _file.close(); 50 | if (++_curDstIndex > _dstFiles.size() - 1) 51 | { 52 | emit error(tr("COPY destination file is not specified.\n" 53 | " Use special comment to pass destination files: /*sqt { \"copy_dst\": [\"\", \"\"...] } */\n" 54 | " In case of single COPY TO query non-array form is allowed: /*sqt { \"copy_dst\": \"\" } */\n" 55 | " Specify an empty string instead of file name for output to the log widget.")); 56 | return false; 57 | } 58 | 59 | // empty string as file name => use log widget for output 60 | if (_dstFiles[_curDstIndex].isEmpty()) 61 | return true; 62 | 63 | _file.setFileName(_dstFiles[_curDstIndex]); 64 | if (!_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) 65 | { 66 | emit error(_file.errorString()); 67 | return false; 68 | } 69 | return true; 70 | } 71 | 72 | bool PgCopyContext::write(const char *data, qint64 size) 73 | { 74 | if (_dstFiles[_curDstIndex].isEmpty()) 75 | emit message(QString::fromStdString(data)); 76 | else 77 | { 78 | qint64 bytesWritten = _file.write(data, size); 79 | if (bytesWritten == size) 80 | return true; 81 | else if (bytesWritten < 0) 82 | emit error(_file.errorString()); 83 | else 84 | emit error(tr("% bytes out of % were sucessfully written").arg(bytesWritten).arg(size)); 85 | return false; 86 | } 87 | return true; 88 | } 89 | 90 | bool PgCopyContext::read(std::vector &data, size_t maxSize) 91 | { 92 | if (data.size() < maxSize) 93 | data.resize(maxSize); 94 | qint64 size = _file.read(data.data(), static_cast(maxSize)); 95 | if (size < 0) 96 | { 97 | data.resize(0); 98 | emit error(_file.errorString()); 99 | return false; 100 | } 101 | if (static_cast(size) < maxSize) 102 | data.resize(static_cast(size)); 103 | return true; 104 | } 105 | 106 | PgCopyContext::operator bool() const 107 | { 108 | return _initialized; 109 | } 110 | -------------------------------------------------------------------------------- /src/copycontext.h: -------------------------------------------------------------------------------- 1 | #ifndef COPYCONTEXT_H 2 | #define COPYCONTEXT_H 3 | 4 | #include 5 | #include 6 | 7 | class PgCopyContext : public QObject 8 | { 9 | Q_OBJECT 10 | public: 11 | PgCopyContext() = default; 12 | void init(const QString &query); 13 | void clear(); 14 | bool nextSource(); 15 | bool nextDestination(); 16 | operator bool() const; 17 | bool write(const char *data, qint64 size); 18 | bool read(std::vector &data, size_t maxSize); 19 | private: 20 | QFile _file; 21 | QStringList _srcFiles; 22 | QStringList _dstFiles; 23 | int _curSrcIndex; 24 | int _curDstIndex; 25 | bool _initialized = false; 26 | signals: 27 | void message(const QString &msg); 28 | void error(const QString &msg); 29 | }; 30 | 31 | #endif // COPYCONTEXT_H 32 | -------------------------------------------------------------------------------- /src/datatable.h: -------------------------------------------------------------------------------- 1 | #ifndef DATATABLE_H 2 | #define DATATABLE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class DataTable; 11 | // TODO 12 | // rethink this mostly legacy code 13 | class DataColumn 14 | { 15 | public: 16 | DataColumn(const DataColumn &column) = default; 17 | DataColumn(const QString &name = "", 18 | const QString &typeName = "", 19 | QMetaType::Type type = QMetaType::QString, 20 | int sqlType = 0, 21 | int length = -1, 22 | int16_t decDigits = -1, 23 | int8_t nullableDesc = 1, 24 | Qt::AlignmentFlag hAlignment = Qt::AlignLeft, 25 | int arrayElementType = -1); 26 | 27 | // ctor for postgres only for delayed column type specification (it's about arrays) 28 | DataColumn(const QString &name, QMetaType::Type type, int sqlType, int modifier, int8_t nullableDesc, Qt::AlignmentFlag hAlignment); 29 | void clarifyType(const QString &type, int length = -1, int16_t decDigits = -1, int arrayElementType = -1); 30 | 31 | QMetaType::Type variantType() const noexcept { return _varType; } 32 | int sqlType() const noexcept { return _sqlType; } 33 | int arrayElementType() const noexcept { return _arrayElementType; } 34 | QString name() const noexcept { return _name; } 35 | Qt::AlignmentFlag hAlignment() const noexcept { return _hAlignment; } 36 | int length() const noexcept { return _length; } 37 | int16_t scale() const noexcept { return _decDigits; } 38 | int modifier() const noexcept { return _modifier; } 39 | QString typeName() const noexcept { return _typeName; } 40 | 41 | private: 42 | QString _name, _typeName; 43 | QMetaType::Type _varType; 44 | int _sqlType; 45 | int _length = -1; 46 | int _modifier = -1; 47 | int16_t _decDigits = -1; 48 | int8_t _nullableDesc = 1; 49 | Qt::AlignmentFlag _hAlignment = Qt::AlignLeft; 50 | int _arrayElementType = -1; 51 | }; 52 | 53 | class DataRow 54 | { 55 | friend class DataTable; 56 | public: 57 | DataRow(const DataRow &row); 58 | DataRow(DataTable* _table); 59 | ~DataRow(); 60 | QVariant& operator[](QString column_name); 61 | QVariant& operator[](int index); 62 | private: 63 | QVector _row; 64 | DataTable* _table; 65 | }; 66 | 67 | class DataTable : public QObject 68 | { 69 | Q_OBJECT 70 | public: 71 | DataTable(const DataTable &table); 72 | DataTable(QObject *parent = nullptr); 73 | ~DataTable(); 74 | void clear(); 75 | void clearRows(); 76 | DataRow& addRow(); 77 | void addColumn(DataColumn *column); 78 | void addRow(DataRow *row); 79 | DataColumn& getColumn(QString column_name) const; 80 | DataColumn& getColumn(int ord) const; 81 | int getColumnOrd(QString column_name) const; 82 | DataRow& getRow(int ind) const; 83 | mutable QMutex mutex; 84 | public slots: 85 | int columnCount() const; 86 | int rowCount() const; 87 | QVariant value(int row, int column) const; 88 | QVariant value(int row, QString columnName) const; 89 | DataTable* takeRows(DataTable *source); 90 | private: 91 | QVector _columns; 92 | QVector _rows; 93 | }; 94 | 95 | Q_DECLARE_METATYPE(DataTable) 96 | 97 | #endif // DATATABLE_H 98 | -------------------------------------------------------------------------------- /src/dbconnection.cpp: -------------------------------------------------------------------------------- 1 | #include "dbconnection.h" 2 | #include 3 | #include 4 | #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 5 | #include 6 | #endif 7 | 8 | DbConnection::DbConnection() : 9 | QObject(nullptr) 10 | { 11 | _query_state = QueryState::Inactive; 12 | } 13 | 14 | DbConnection::~DbConnection() 15 | { 16 | clearResultsets(); 17 | } 18 | 19 | QString DbConnection::dbmsScriptingID() const noexcept 20 | { 21 | return _dbmsScriptingID; 22 | } 23 | 24 | QString DbConnection::transactionStatus() const noexcept 25 | { 26 | return ""; 27 | } 28 | 29 | QString DbConnection::escapeIdentifier(const QString &identifier) 30 | { 31 | // TODO 32 | return identifier; 33 | } 34 | 35 | QPair DbConnection::typeInfo(int /*sqlType*/) 36 | { 37 | // TODO 38 | return {"unknown", -1}; 39 | } 40 | 41 | void DbConnection::setDatabase(const QString &database) noexcept 42 | { 43 | if (_database != database) 44 | { 45 | close(); 46 | _database = database; 47 | } 48 | } 49 | 50 | void DbConnection::setConnectionString(const QString &connectionString) 51 | { 52 | close(); 53 | _connection_string = connectionString; 54 | } 55 | 56 | QString DbConnection::connectionString() const noexcept 57 | { 58 | return _connection_string; 59 | } 60 | 61 | QueryState DbConnection::queryState() const noexcept 62 | { 63 | return _query_state; 64 | } 65 | 66 | DataTable* DbConnection::execute(const QString &query, const QVariantList ¶ms) 67 | { 68 | QVector p = params.toVector(); 69 | // * synchronous usage only - no need to use _resultsetsGuard 70 | if (execute(query, &p) && !_resultsets.empty()) 71 | { 72 | // return only last resultset to keep scripting api simple 73 | // (script takes ownership of the pointer) 74 | return _resultsets.takeLast(); 75 | } 76 | return nullptr; 77 | } 78 | 79 | void DbConnection::setQueryState(QueryState state) 80 | { 81 | if (_query_state != state) 82 | { 83 | _query_state = state; 84 | if (state == QueryState::Inactive) 85 | _elapsed_ms = _timer.elapsed(); 86 | emit queryStateChanged(state); 87 | } 88 | } 89 | 90 | QString DbConnection::elapsed() const noexcept 91 | { 92 | int elapsed_ms = _elapsed_ms; 93 | int precision = 3; 94 | if (_query_state != QueryState::Inactive) 95 | { 96 | // round milliseconds during execution because of refresh period 0.2 sec 97 | elapsed_ms = _timer.elapsed() / 100 * 100; 98 | // rough precision to display simple float 99 | precision = 1; 100 | } 101 | 102 | if (elapsed_ms < 60000) 103 | return QString::number(elapsed_ms / 1000.0, 'f', precision) + " sec"; 104 | 105 | #if QT_VERSION < QT_VERSION_CHECK(6, 5, 0) 106 | return QDateTime::fromMSecsSinceEpoch(elapsed_ms, Qt::UTC). 107 | #else 108 | return QDateTime::fromMSecsSinceEpoch(elapsed_ms, QTimeZone::UTC). 109 | #endif 110 | toString(elapsed_ms < 60 * 60000 ? 111 | "mm:ss.zzz": 112 | "HH:mm:ss"); 113 | } 114 | 115 | void DbConnection::clearResultsets() noexcept 116 | { 117 | QMutexLocker lk(&_resultsetsGuard); 118 | qDeleteAll(_resultsets); 119 | _resultsets.clear(); 120 | } 121 | -------------------------------------------------------------------------------- /src/dbconnectionfactory.cpp: -------------------------------------------------------------------------------- 1 | #include "dbconnectionfactory.h" 2 | #include "odbcconnection.h" 3 | #include "pgconnection.h" 4 | #include 5 | 6 | QHash> DbConnectionFactory::_connections; 7 | 8 | std::shared_ptr DbConnectionFactory::connection(QString name) 9 | { 10 | if (_connections.contains(name)) 11 | return _connections[name]; 12 | return nullptr; 13 | } 14 | 15 | std::shared_ptr DbConnectionFactory::createConnection(QString name, QString connectionString, QString database) 16 | { 17 | std::shared_ptr res; 18 | QRegularExpression re("\\b(dsn|driver)\\s*=", QRegularExpression::CaseInsensitiveOption); 19 | if (re.match(connectionString).hasMatch()) 20 | res = std::shared_ptr(new OdbcConnection()); 21 | else 22 | res = std::shared_ptr(new PgConnection()); 23 | 24 | if (!name.isEmpty()) 25 | _connections[name] = res; 26 | 27 | res->setConnectionString(connectionString); 28 | res->setDatabase(database); 29 | return res; 30 | } 31 | 32 | void DbConnectionFactory::removeConnection(QString name) 33 | { 34 | if (!_connections.contains(name)) 35 | return; 36 | _connections.remove(name); 37 | } 38 | 39 | -------------------------------------------------------------------------------- /src/dbconnectionfactory.h: -------------------------------------------------------------------------------- 1 | #ifndef DBCONNECTIONFACTORY_H 2 | #define DBCONNECTIONFACTORY_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class DbConnection; 9 | 10 | class DbConnectionFactory 11 | { 12 | public: 13 | DbConnectionFactory() = delete; 14 | static std::shared_ptr connection(QString name); 15 | static std::shared_ptr createConnection(QString name, QString connectionString = QString(), QString database = QString()); 16 | static void removeConnection(QString name); 17 | private: 18 | static QHash> _connections; 19 | }; 20 | 21 | #endif // DBCONNECTIONFACTORY_H 22 | -------------------------------------------------------------------------------- /src/dbobject.cpp: -------------------------------------------------------------------------------- 1 | #include "dbobject.h" 2 | #include "dbconnectionfactory.h" 3 | #include "odbcconnection.h" 4 | 5 | DbObject::DbObject(DbObject *parent) 6 | { 7 | _parent = parent; 8 | //setData(true, DbObject::ParentRole); 9 | setData(0, DbObject::CurrentSortRole); 10 | setData(false, DbObject::MultiselectRole); 11 | } 12 | 13 | DbObject::DbObject(DbObject *parent, QString text, QString type, QFont font) : _parent(parent) 14 | { 15 | setData(text); 16 | setData(type, DbObject::TypeRole); 17 | //setData(true, DbObject::ParentRole); 18 | setData(font, Qt::FontRole); 19 | setData(0, DbObject::CurrentSortRole); 20 | setData(false, DbObject::MultiselectRole); 21 | } 22 | 23 | DbObject::~DbObject() 24 | { 25 | qDeleteAll(_conceived); 26 | _conceived.clear(); 27 | qDeleteAll(_children); 28 | _children.clear(); 29 | QString type = data(DbObject::TypeRole).toString(); 30 | if (type == "connection" || type == "database") 31 | { 32 | QString id = QString::number(std::intptr_t(this)); 33 | DbConnectionFactory::removeConnection(id); 34 | } 35 | } 36 | 37 | void DbObject::setData(const QVariant &value, int role) 38 | { 39 | _itemData[role] = value; 40 | } 41 | 42 | void DbObject::appendChild(DbObject *item) 43 | { 44 | _children.append(item); 45 | item->setParent(this); 46 | } 47 | 48 | QVariant DbObject::data(int role) const 49 | { 50 | QVariant defValue; 51 | switch (role) 52 | { 53 | case DbObject::ParentRole: 54 | defValue = false; 55 | break; 56 | } 57 | return _itemData.value(role, defValue); 58 | } 59 | 60 | int DbObject::row() const 61 | { 62 | if (_parent) 63 | return _parent->_children.indexOf(const_cast(this)); 64 | return 0; 65 | } 66 | 67 | bool DbObject::insertChild(int beforeRow) 68 | { 69 | if (beforeRow > _children.count()) 70 | return false; 71 | _children.insert(beforeRow, new DbObject(this)); 72 | return true; 73 | } 74 | 75 | bool DbObject::removeChild(int pos) 76 | { 77 | if (pos >= _children.count()) 78 | return false; 79 | delete _children.at(pos); 80 | _children.removeAt(pos); 81 | return true; 82 | } 83 | -------------------------------------------------------------------------------- /src/dbobject.h: -------------------------------------------------------------------------------- 1 | #ifndef DBOBJECT_H 2 | #define DBOBJECT_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class DbObject 9 | { 10 | public: 11 | DbObject(DbObject *parent = nullptr); 12 | DbObject(DbObject *parent, QString text, QString type, QFont font = QFont()); 13 | ~DbObject(); 14 | 15 | enum ObjectRole 16 | { 17 | IdRole = Qt::UserRole + 1, ///< unique id 18 | NameRole, ///< unquoted (typically) name 19 | TypeRole, ///< tree node type [connection | database | schema | table | function ...] 20 | ContentRole, ///< content data 21 | ContentTypeRole, ///< content type [script | text | html | table] 22 | FavouriteRole, ///< marked as favourite 23 | ParentRole, ///< if node may have children 24 | ChildObjectsCountRole, ///< number of child items with id 25 | DataRole, 26 | CurrentSortRole, 27 | MultiselectRole, 28 | TagRole, ///< any valuable data accessible by $.tag$ macro 29 | Sort1Role, 30 | Sort2Role 31 | }; 32 | 33 | void setData(const QVariant &value, int role = Qt::DisplayRole); 34 | void appendChild(DbObject *item); 35 | void setParent(DbObject *parent) { _parent = parent; } 36 | DbObject *child(int row) const { return _children.value(row, nullptr); } 37 | DbObject *parent() const { return _parent; } 38 | int childCount() const { return _children.count(); } 39 | QVariant data(int role = Qt::DisplayRole) const; 40 | int row() const; 41 | bool insertChild(int beforeRow); 42 | bool removeChild(int pos); 43 | 44 | private: 45 | QList _children; 46 | QList _conceived; 47 | QHash _itemData; 48 | DbObject *_parent; 49 | }; 50 | 51 | #endif // DBOBJECT_H 52 | -------------------------------------------------------------------------------- /src/dbobjectsmodel.h: -------------------------------------------------------------------------------- 1 | #ifndef DBOBJECTSMODEL_H 2 | #define DBOBJECTSMODEL_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class DbObject; 9 | class DbConnection; 10 | class DataTable; 11 | 12 | template 13 | class ScopeGuard 14 | { 15 | Fn _exitHandler; 16 | public: 17 | ScopeGuard(Fn exitHandler): _exitHandler(exitHandler) {} 18 | ~ScopeGuard() { _exitHandler(); } 19 | }; 20 | 21 | class DbObjectsModel : public QAbstractItemModel 22 | { 23 | Q_OBJECT 24 | public: 25 | explicit DbObjectsModel(QObject *parent = nullptr); 26 | ~DbObjectsModel(); 27 | 28 | virtual QModelIndex parent(const QModelIndex &index) const; 29 | virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; 30 | virtual int columnCount(const QModelIndex & = QModelIndex()) const { return 1; } 31 | virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; 32 | virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; 33 | virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); 34 | virtual Qt::ItemFlags flags(const QModelIndex &index) const; 35 | virtual bool insertRows(int pos, int count, const QModelIndex &parent = QModelIndex()); 36 | virtual bool removeRows(int pos, int count, const QModelIndex &parent = QModelIndex()); 37 | //QVariant dataAtCurrent(const QAbstractItemView *view, QString column_name) const; 38 | 39 | virtual bool hasChildren(const QModelIndex &parent = QModelIndex()) const; 40 | virtual bool canFetchMore(const QModelIndex & parent) const; 41 | virtual void fetchMore(const QModelIndex & parent); 42 | 43 | bool fillChildren(const QModelIndex &parent = QModelIndex()); 44 | 45 | std::shared_ptr dbConnection(const QModelIndex &index); 46 | QVariant parentNodeProperty(const QModelIndex &index, QString type); 47 | bool addServer(QString name, QString connectionString); 48 | bool removeConnection(QModelIndex &index); 49 | bool alterConnection(QModelIndex &index, QString name, QString connectionString); 50 | 51 | private: 52 | DbObject *_rootItem; 53 | 54 | signals: 55 | void error(QString err); 56 | void message(QString msg); 57 | 58 | public slots: 59 | void saveConnectionSettings(); 60 | }; 61 | 62 | #endif // DBOBJECTSMODEL_H 63 | -------------------------------------------------------------------------------- /src/dbosortfilterproxymodel.cpp: -------------------------------------------------------------------------------- 1 | #include "dbosortfilterproxymodel.h" 2 | #include "dbobject.h" 3 | 4 | DboSortFilterProxyModel::DboSortFilterProxyModel(QObject *parent) : 5 | QSortFilterProxyModel(parent) 6 | { 7 | } 8 | 9 | bool DboSortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const 10 | { 11 | Q_UNUSED(sourceRow) 12 | Q_UNUSED(sourceParent) 13 | return true; 14 | } 15 | 16 | bool DboSortFilterProxyModel::lessThan(const QModelIndex &left, 17 | const QModelIndex &right) const 18 | { 19 | /* 20 | // nodes with id are always first 21 | QVariant leftId = sourceModel()->data(left, DbObject::IdRole); 22 | QVariant rightId = sourceModel()->data(right, DbObject::IdRole); 23 | if (leftId.isValid() && !rightId.isValid()) 24 | return true; 25 | if (!leftId.isValid() && rightId.isValid()) 26 | return false; 27 | */ 28 | 29 | QVariant sortMode = sourceModel()->data(left.parent(), DbObject::CurrentSortRole); 30 | int mode = (sortMode.isValid() ? sortMode.toInt() : 0); 31 | 32 | QVariant leftS1 = sourceModel()->data(left, DbObject::Sort1Role); 33 | QVariant leftS2 = sourceModel()->data(left, DbObject::Sort2Role); 34 | QString leftN = sourceModel()->data(left, Qt::DisplayRole).toString().toLower(); 35 | QVariant rightS1 = sourceModel()->data(right, DbObject::Sort1Role); 36 | QVariant rightS2 = sourceModel()->data(right, DbObject::Sort2Role); 37 | QString rightN = sourceModel()->data(right, Qt::DisplayRole).toString().toLower(); 38 | 39 | if (mode == 0) 40 | { 41 | if (leftS1.isValid() && rightS1.isValid()) 42 | return compare(leftS1, rightS1); 43 | } 44 | else 45 | { 46 | if (leftS2.isValid() && rightS2.isValid()) 47 | return compare(leftS2, rightS2); 48 | } 49 | return leftN < rightN; 50 | } 51 | 52 | bool DboSortFilterProxyModel::compare(const QVariant &varl, const QVariant &varr) const 53 | { 54 | bool ok_l, ok_r; 55 | qlonglong long_varl = varl.toLongLong(&ok_l); 56 | qlonglong long_varr = varr.toLongLong(&ok_r); 57 | if (ok_l && ok_r) 58 | return long_varl < long_varr; 59 | 60 | return varl.toString().toLower() < varr.toString().toLower(); 61 | } 62 | -------------------------------------------------------------------------------- /src/dbosortfilterproxymodel.h: -------------------------------------------------------------------------------- 1 | #ifndef DBOSORTFILTERPROXYMODEL_H 2 | #define DBOSORTFILTERPROXYMODEL_H 3 | 4 | #include 5 | 6 | class DboSortFilterProxyModel : public QSortFilterProxyModel 7 | { 8 | Q_OBJECT 9 | public: 10 | explicit DboSortFilterProxyModel(QObject *parent = nullptr); 11 | bool compare(const QVariant &varl, const QVariant &varr) const; 12 | 13 | protected: 14 | bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; 15 | bool lessThan(const QModelIndex &left, const QModelIndex &right) const; 16 | 17 | signals: 18 | 19 | public slots: 20 | 21 | }; 22 | 23 | #endif // DBOSORTFILTERPROXYMODEL_H 24 | -------------------------------------------------------------------------------- /src/dbtreeitemdelegate.h: -------------------------------------------------------------------------------- 1 | #ifndef DBTREEITEMDELEGATE_H 2 | #define DBTREEITEMDELEGATE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class DbTreeItemDelegate : public QStyledItemDelegate 12 | { 13 | Q_OBJECT 14 | public: 15 | explicit DbTreeItemDelegate(QObject *parent = nullptr); 16 | virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; 17 | virtual QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const; 18 | void prepareDocToDrawDbTreeNode(const QStyleOptionViewItem & option, const QModelIndex & index, QTextDocument &doc) const; 19 | 20 | }; 21 | 22 | class MyProxyStyle : public QProxyStyle 23 | { 24 | private: 25 | QIcon _closed, _open; 26 | 27 | public: 28 | MyProxyStyle(QStyle *style = nullptr); 29 | void drawPrimitive(PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = nullptr) const; 30 | }; 31 | 32 | #endif // DBTREEITEMDELEGATE_H 33 | -------------------------------------------------------------------------------- /src/extfiledialog.cpp: -------------------------------------------------------------------------------- 1 | #include "extfiledialog.h" 2 | #include 3 | #include 4 | #include 5 | #include "settings.h" 6 | 7 | ExtFileDialog::ExtFileDialog(QWidget *parent) : 8 | QFileDialog(parent) 9 | { 10 | setOption(QFileDialog::DontUseNativeDialog); 11 | setDefaultSuffix("sql"); 12 | QGridLayout* mainLayout = qobject_cast(layout()); 13 | 14 | if (!mainLayout) 15 | return; 16 | else 17 | { 18 | QHBoxLayout *hbl = new QHBoxLayout(); 19 | _encodingCombo = new QComboBox(this); 20 | hbl->addStretch(); 21 | hbl->addWidget(new QLabel(tr("Encoding"))); 22 | hbl->addWidget(_encodingCombo); 23 | int numRows = mainLayout->rowCount(); 24 | mainLayout->addLayout(hbl, numRows,0,1,-1); 25 | } 26 | } 27 | 28 | QString ExtFileDialog::encoding() 29 | { 30 | return _encodingCombo->currentText(); 31 | } 32 | 33 | void ExtFileDialog::setEncoding(const QString &encoding) 34 | { 35 | int ind = _encodingCombo->findData(encoding, Qt::DisplayRole); 36 | if (ind == -1) 37 | { 38 | if (encoding.isEmpty()) 39 | { 40 | if (!_encodingCombo->count()) 41 | _encodingCombo->addItem("UTF-8"); 42 | ind = 0; 43 | } 44 | else 45 | { 46 | _encodingCombo->addItem(encoding); 47 | ind = _encodingCombo->count() - 1; 48 | } 49 | } 50 | _encodingCombo->setCurrentIndex(ind); 51 | } 52 | 53 | void ExtFileDialog::fillEncodings() 54 | { 55 | _encodingCombo->clear(); 56 | _encodingCombo->addItems( 57 | SqtSettings::value("encodings").toString(). 58 | split(',', 59 | #if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) 60 | Qt::SkipEmptyParts 61 | #else 62 | QString::SkipEmptyParts 63 | #endif 64 | )); 65 | if (!_encodingCombo->count()) 66 | _encodingCombo->setCurrentIndex(0); 67 | } 68 | -------------------------------------------------------------------------------- /src/extfiledialog.h: -------------------------------------------------------------------------------- 1 | #ifndef EXTFILEDIALOG_H 2 | #define EXTFILEDIALOG_H 3 | 4 | #include 5 | 6 | class QComboBox; 7 | 8 | class ExtFileDialog : public QFileDialog 9 | { 10 | Q_OBJECT 11 | public: 12 | explicit ExtFileDialog(QWidget *parent = nullptr); 13 | QString encoding(); 14 | void setEncoding(const QString &encoding); 15 | void fillEncodings(); 16 | 17 | private: 18 | QComboBox *_encodingCombo; 19 | 20 | }; 21 | 22 | #endif // EXTFILEDIALOG_H 23 | -------------------------------------------------------------------------------- /src/findandreplacepanel.h: -------------------------------------------------------------------------------- 1 | #ifndef FINDANDREPLACEPANEL_H 2 | #define FINDANDREPLACEPANEL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class QPlainTextEdit; 10 | class QueryWidget; 11 | 12 | namespace Ui { 13 | class FindAndReplacePanel; 14 | } 15 | 16 | struct ReplaceChunk 17 | { 18 | int refNum; 19 | QString value; 20 | }; 21 | 22 | class FindAndReplacePanel : public QWidget 23 | { 24 | Q_OBJECT 25 | 26 | public: 27 | explicit FindAndReplacePanel(QWidget *parent = nullptr); 28 | ~FindAndReplacePanel(); 29 | QList actions(); 30 | void setEditor(QueryWidget *qw); 31 | void refreshActions(); 32 | 33 | private slots: 34 | void findTriggered(); 35 | void on_actionReplace_and_find_next_triggered(); 36 | void on_cbRegexp_toggled(bool checked); 37 | void on_btnReplace_clicked(); 38 | void on_btnReplaceAll_clicked(); 39 | 40 | private: 41 | enum FindMode {Forward, Backward, Check}; 42 | Ui::FindAndReplacePanel *ui; 43 | QueryWidget *_queryWidget; 44 | QTextCursor find(const QTextCursor &cursor = QTextCursor(), bool *nextPass = nullptr, FindMode mode = Forward); 45 | QRegularExpression::PatternOptions regexpOptions(); 46 | QVector unescape(QString ui_string, QString *err); 47 | QString replaceMatch(const QRegularExpressionMatch &match, const QVector &repl); 48 | 49 | protected: 50 | bool eventFilter(QObject *target, QEvent *event); 51 | }; 52 | 53 | #endif // FINDANDREPLACEPANEL_H 54 | -------------------------------------------------------------------------------- /src/img/arrow-circle-double-135.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/src/img/arrow-circle-double-135.png -------------------------------------------------------------------------------- /src/img/bookmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/src/img/bookmark.png -------------------------------------------------------------------------------- /src/img/control-stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/src/img/control-stop.png -------------------------------------------------------------------------------- /src/img/control.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/src/img/control.png -------------------------------------------------------------------------------- /src/img/database-sql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/src/img/database-sql.png -------------------------------------------------------------------------------- /src/img/database-sql_24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/src/img/database-sql_24.png -------------------------------------------------------------------------------- /src/img/databases.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/src/img/databases.png -------------------------------------------------------------------------------- /src/img/gear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/src/img/gear.png -------------------------------------------------------------------------------- /src/img/server--plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/src/img/server--plus.png -------------------------------------------------------------------------------- /src/img/server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/src/img/server.png -------------------------------------------------------------------------------- /src/img/shovel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/src/img/shovel.png -------------------------------------------------------------------------------- /src/img/sql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/src/img/sql.png -------------------------------------------------------------------------------- /src/jsonsyntaxhighlighter.h: -------------------------------------------------------------------------------- 1 | #ifndef JSONSYNTAXHIGHLIGHTER_H 2 | #define JSONSYNTAXHIGHLIGHTER_H 3 | 4 | #include 5 | 6 | class JsonSyntaxHighlighter : public QSyntaxHighlighter 7 | { 8 | Q_OBJECT 9 | public: 10 | explicit JsonSyntaxHighlighter(QObject *parent = nullptr); 11 | 12 | protected: 13 | virtual void highlightBlock(const QString &text); 14 | 15 | private: 16 | const QString delimiters = " \t\r\n\f\b\":[]{},/"; 17 | QVector formats; 18 | }; 19 | 20 | #endif // JSONSYNTAXHIGHLIGHTER_H 21 | -------------------------------------------------------------------------------- /src/logindialog.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "logindialog.h" 3 | #include "ui_logindialog.h" 4 | #include 5 | #include 6 | 7 | LoginDialog::LoginDialog(QWidget *parent, QString user) : 8 | QDialog(parent), 9 | ui(new Ui::LoginDialog) 10 | { 11 | ui->setupUi(this); 12 | if (!user.isNull()) 13 | { 14 | connect(ui->eUser, &QLineEdit::textChanged, this, &LoginDialog::userChanged); 15 | ui->eUser->setText(user); 16 | } 17 | else 18 | { 19 | ui->lUser->setVisible(false); 20 | ui->eUser->setVisible(false); 21 | } 22 | if (!user.isEmpty()) 23 | ui->ePass->setFocus(); 24 | 25 | adjustSize(); 26 | QRect frect = frameGeometry(); 27 | frect.moveCenter(parent->frameGeometry().center()); 28 | move(frect.topLeft()); 29 | } 30 | 31 | LoginDialog::~LoginDialog() 32 | { 33 | delete ui; 34 | } 35 | 36 | QString LoginDialog::user() 37 | { 38 | return ui->eUser->text(); 39 | } 40 | 41 | QString LoginDialog::password() 42 | { 43 | return ui->ePass->text(); 44 | } 45 | 46 | void LoginDialog::changeEvent(QEvent *e) 47 | { 48 | QDialog::changeEvent(e); 49 | switch (e->type()) { 50 | case QEvent::LanguageChange: 51 | ui->retranslateUi(this); 52 | break; 53 | default: 54 | break; 55 | } 56 | } 57 | 58 | void LoginDialog::userChanged(QString val) 59 | { 60 | ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(val.length() > 0); 61 | } 62 | -------------------------------------------------------------------------------- /src/logindialog.h: -------------------------------------------------------------------------------- 1 | #ifndef LOGINDIALOG_H 2 | #define LOGINDIALOG_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class LoginDialog; 8 | } 9 | 10 | class LoginDialog : public QDialog { 11 | Q_OBJECT 12 | public: 13 | LoginDialog(QWidget *parent = nullptr, QString user = QString()); 14 | ~LoginDialog(); 15 | QString user(); 16 | QString password(); 17 | 18 | protected: 19 | void changeEvent(QEvent *e); 20 | 21 | private: 22 | Ui::LoginDialog *ui; 23 | 24 | private slots: 25 | void userChanged(QString); 26 | }; 27 | 28 | #endif // LOGINDIALOG_H 29 | -------------------------------------------------------------------------------- /src/logindialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | LoginDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 316 10 | 135 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | true 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | User name 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | Password 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 170 47 | 0 48 | 49 | 50 | 51 | QLineEdit::Password 52 | 53 | 54 | 55 | 56 | 57 | 58 | Qt::Vertical 59 | 60 | 61 | 62 | 20 63 | 20 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 0 75 | 0 76 | 77 | 78 | 79 | Qt::Horizontal 80 | 81 | 82 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 83 | 84 | 85 | false 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | buttonBox 95 | accepted() 96 | LoginDialog 97 | accept() 98 | 99 | 100 | 257 101 | 135 102 | 103 | 104 | 157 105 | 144 106 | 107 | 108 | 109 | 110 | buttonBox 111 | rejected() 112 | LoginDialog 113 | reject() 114 | 115 | 116 | 308 117 | 135 118 | 119 | 120 | 286 121 | 144 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "mainwindow.h" 3 | #include "appeventhandler.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 8 | QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 9 | QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); 10 | #endif 11 | QApplication a(argc, argv); 12 | a.setWindowIcon(QIcon(":/sqt.ico")); 13 | QCoreApplication::setOrganizationName("parihaaraka"); 14 | QCoreApplication::setApplicationName("sqt"); 15 | QCoreApplication::setApplicationVersion("0.4.7"); 16 | setlocale(LC_NUMERIC, "C"); 17 | 18 | AppEventHandler appEventHandler; 19 | a.installEventFilter(&appEventHandler); 20 | 21 | MainWindow w; 22 | w.show(); 23 | 24 | return a.exec(); 25 | } 26 | -------------------------------------------------------------------------------- /src/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include "extfiledialog.h" 6 | #include 7 | #include 8 | #include 9 | #include "dbconnection.h" 10 | 11 | namespace Ui { 12 | class MainWindow; 13 | } 14 | 15 | namespace Scripting { 16 | class CppConductor; 17 | } 18 | 19 | class SqlSyntaxHighlighter; 20 | class QueryWidget; 21 | class TableModel; 22 | class FindAndReplacePanel; 23 | class DbObjectsModel; 24 | class CodeBlockProperties; 25 | class MyProxyStyle; 26 | 27 | class MainWindow : public QMainWindow 28 | { 29 | Q_OBJECT 30 | 31 | public: 32 | explicit MainWindow(QWidget *parent = nullptr); 33 | virtual ~MainWindow() override; 34 | void activateEditorBlock(CodeBlockProperties *blockProperties); 35 | void queryStateChanged(QueryWidget *w, QueryState state); 36 | 37 | protected: 38 | virtual void closeEvent(QCloseEvent *event) override; 39 | virtual void changeEvent(QEvent *e) override; 40 | 41 | private slots: 42 | void on_addConnectionAction_triggered(); 43 | void on_actionAbout_triggered(); 44 | void on_objectsView_activated(const QModelIndex &index); 45 | void on_objectsView_customContextMenuRequested(const QPoint &pos); 46 | void on_actionRefresh_triggered(); 47 | void on_actionChange_sort_mode_triggered(); 48 | void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); 49 | void currentChanged(const QModelIndex ¤t, const QModelIndex &previous); 50 | void viewModeActionTriggered(QAction *action); 51 | void on_actionExecute_query_triggered(); 52 | void on_actionNew_triggered(); 53 | void on_tabWidget_tabCloseRequested(int index); 54 | void sqlChanged(); 55 | void on_actionOpen_triggered(); 56 | void on_actionSave_triggered(); 57 | void on_actionSave_as_triggered(); 58 | void scriptSelectedObjects(); 59 | void showContent(QModelIndex &index, const Scripting::CppConductor *content); 60 | void showTextualContent(const QVariant &value, const QVariant &type, std::shared_ptr con); 61 | void objectsViewAdjustColumnWidth(const QModelIndex &); 62 | void on_actionFind_triggered(); 63 | void on_tabWidget_currentChanged(int index); 64 | void onActionOpenFile(); 65 | void openFile(const QString &fileName, const QString &encoding); 66 | 67 | void on_actionSettings_triggered(); 68 | 69 | private: 70 | QLabel _contextLabel, _positionLabel, _durationLabel; 71 | ExtFileDialog _fileDialog; 72 | QStringList _mruDirs; // QFileDialog::history() keeps unused directories :( 73 | Ui::MainWindow *ui; 74 | MyProxyStyle *_proxyStyle; 75 | DbObjectsModel *_objectsModel; 76 | TableModel *_tableModel; 77 | QueryWidget* currentQueryWidget(); 78 | QueryWidget* _objectScript; 79 | bool closeTab(int index); 80 | bool ensureSaved(int index, bool ask_name = false, bool forceWarning = false); 81 | FindAndReplacePanel *_frPanel; 82 | QTimer *_hideTimer; 83 | QTimer *_durationRefreshTimer; 84 | void log(const QString &msg); 85 | void adjustMru(); 86 | void addMruFile(); 87 | 88 | public slots: 89 | QVariant current(const QString &nodeType, const QString &field); 90 | QVariantList selected(const QString &nodeType, const QString &field); 91 | virtual bool eventFilter(QObject *object, QEvent *event) override; 92 | 93 | void refreshActions(); 94 | void refreshContextInfo(); 95 | void refreshCursorInfo(); 96 | void refreshConnectionState(); 97 | void onMessage(const QString &msg); 98 | void onError(const QString &err); 99 | }; 100 | 101 | #endif // MAINWINDOW_H 102 | -------------------------------------------------------------------------------- /src/odbcconnection.h: -------------------------------------------------------------------------------- 1 | #ifndef ODBCCONNECTION_H 2 | #define ODBCCONNECTION_H 3 | 4 | #define SQL_VARIANT (-150) // windows only? 5 | #define SQL_SS_TIME2 (-154) // windows only? 6 | 7 | #include 8 | 9 | #ifdef Q_OS_WIN32 10 | #include 11 | #else 12 | #include 13 | #endif 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "dbconnection.h" 20 | 21 | class QueryCanceller; 22 | 23 | class OdbcConnection : public DbConnection 24 | { 25 | Q_OBJECT 26 | public: 27 | OdbcConnection(); 28 | virtual ~OdbcConnection() override; 29 | virtual DbConnection* clone() override; 30 | 31 | virtual bool open() override; 32 | virtual void close() noexcept override; 33 | virtual bool isOpened() const noexcept override; 34 | virtual void cancel() noexcept override; 35 | virtual QString context() const noexcept override; 36 | virtual QString database() const noexcept override; 37 | virtual QString dbmsInfo() const noexcept override; 38 | virtual QString dbmsName() const noexcept override; 39 | virtual QString dbmsVersion() const noexcept override; 40 | virtual int dbmsComparableVersion() override; 41 | virtual bool isUnquotedType(int sqlType) const noexcept override; 42 | virtual bool isNumericType(int sqlType) const noexcept override; 43 | virtual QMetaType::Type sqlTypeToVariant(int sqlType) const noexcept override; 44 | virtual void executeAsync(const QString &query, const QVector *params = nullptr) noexcept override; 45 | virtual bool execute(const QString &query, const QVector *params = nullptr) override; 46 | virtual void clarifyTableStructure(DataTable &table) override; 47 | 48 | private: 49 | SQLHENV _henv; 50 | SQLHDBC _hdbc; 51 | std::atomic _hstmt; // to cancel query from another thread 52 | bool checkStmt(RETCODE retcode, SQLHSTMT handle); 53 | bool check(RETCODE retcode, SQLHANDLE handle, SQLSMALLINT handle_type) const; 54 | std::string finalConnectionString() const noexcept; 55 | }; 56 | 57 | #endif // ODBCCONNECTION_H 58 | -------------------------------------------------------------------------------- /src/pgconnection.h: -------------------------------------------------------------------------------- 1 | #ifndef PGCONNECTION_H 2 | #define PGCONNECTION_H 3 | 4 | #include 5 | #include "dbconnection.h" 6 | #include 7 | #include 8 | #include "pgparams.h" 9 | #include "copycontext.h" 10 | 11 | class QSocketNotifier; 12 | 13 | class PgConnection : public DbConnection 14 | { 15 | Q_OBJECT 16 | public: 17 | PgConnection(); 18 | virtual ~PgConnection() override; 19 | virtual DbConnection* clone() override; 20 | 21 | virtual bool open() override; 22 | virtual void close() noexcept override; 23 | virtual bool isOpened() const noexcept override; 24 | virtual void cancel() noexcept override; 25 | virtual QString context() const noexcept override; 26 | virtual QString database() const noexcept override; 27 | virtual QString dbmsInfo() const noexcept override; 28 | virtual QString dbmsName() const noexcept override; 29 | virtual QString dbmsVersion() const noexcept override; 30 | virtual QString transactionStatus() const noexcept override; 31 | virtual int dbmsComparableVersion() override; 32 | virtual bool isUnquotedType(int sqlType) const noexcept override; 33 | virtual bool isNumericType(int sqlType) const noexcept override; 34 | virtual QMetaType::Type sqlTypeToVariant(int sqlType) const noexcept override; 35 | virtual void executeAsync(const QString &query, const QVector *params = nullptr) noexcept override; 36 | virtual bool execute(const QString &query, const QVector *params = nullptr) override; 37 | 38 | virtual QString escapeIdentifier(const QString &identifier) override; 39 | virtual QPair typeInfo(int sqlType) override; 40 | virtual void clarifyTableStructure(DataTable &table) override; 41 | 42 | private: 43 | enum class async_stage 44 | { 45 | none, 46 | connecting, 47 | sending_query, 48 | flush, 49 | flush_copy, 50 | wait_ready_read, 51 | copy_out, 52 | copy_in 53 | }; 54 | QSocketNotifier *_readNotifier, *_writeNotifier; 55 | PGconn *_conn = nullptr; 56 | async_stage _async_stage = async_stage::none; 57 | DataTable* _temp_result; ///< temporary resultset for asynchronous processing 58 | QString _query_tmp; ///< query storage during asynchronous connection if needed 59 | PgParams _params_tmp; 60 | int _temp_result_rowcount; 61 | PgCopyContext _copy_context; 62 | std::vector _copy_in_buf; 63 | /*! 64 | * \brief > 65 | * 66 | * Although pg's Oid is unsigned int, it's small values let us use signed int to 67 | * support both ms sql and postgresql. Or may be we should not spare bits and switch 68 | * to int64_t? Then it's necessary to change sqlType in DbConnection interface 69 | * (and fix DataTable). 70 | */ 71 | QHash> _data_types; ///< non-static, not version-specific storage because of db-level user types 72 | 73 | virtual void openAsync() noexcept; 74 | bool isIdle() const noexcept; 75 | static void noticeReceiver(void *arg, const PGresult *res); 76 | void fetchNotifications(); 77 | void fetch() noexcept; 78 | void asyncConnectionProceed(); 79 | void getCopyData(); 80 | void putCopyData(); 81 | void readyReadSocket(); 82 | void readyWriteSocket(); 83 | int appendRawDataToTable(DataTable &dst, PGresult *src) noexcept; 84 | std::string finalConnectionString() const noexcept; 85 | 86 | private slots: 87 | void watchSocket(int mode); 88 | 89 | signals: 90 | void closeConnectionWanted(); 91 | }; 92 | 93 | #endif // PGCONNECTION_H 94 | -------------------------------------------------------------------------------- /src/pgparams.cpp: -------------------------------------------------------------------------------- 1 | #include "pgparams.h" 2 | 3 | PgParams &PgParams::add(std::string &¶m) 4 | { 5 | _temps.push_back(param); 6 | return addref(_temps.back().data(), static_cast(_temps.back().size())); 7 | } 8 | 9 | PgParams &PgParams::add(const std::string ¶m) 10 | { 11 | return add(std::string(param)); 12 | } 13 | 14 | PgParams &PgParams::add(const char *param, int size) 15 | { 16 | if (!param) 17 | return addref(nullptr, 0); 18 | 19 | if (size == -1) 20 | return add(std::string(param)); 21 | 22 | return add(std::string(param, static_cast(size))); 23 | } 24 | 25 | PgParams &PgParams::operator<<(std::string &¶m) 26 | { 27 | return add(param); 28 | } 29 | 30 | PgParams &PgParams::operator<<(const std::string ¶m) 31 | { 32 | return add(param); 33 | } 34 | 35 | PgParams &PgParams::operator<<(const char *param) 36 | { 37 | return add(param); 38 | } 39 | 40 | PgParams &PgParams::addref(std::string &¶m) 41 | { 42 | return add(param); 43 | } 44 | 45 | PgParams &PgParams::addref(const std::string ¶m) 46 | { 47 | return addref(param.data(), param.size()); 48 | } 49 | 50 | PgParams &PgParams::addref(const char *param, int size) 51 | { 52 | _param_pointers.push_back(param); 53 | _param_lengths.push_back(size); 54 | return *this; 55 | } 56 | 57 | PgParams &PgParams::add(const QString ¶m) 58 | { 59 | if (param.isNull()) 60 | return add(nullptr); 61 | return add(param.toStdString()); 62 | } 63 | 64 | PgParams &PgParams::add(const QVariant ¶m) 65 | { 66 | if (!param.isValid() || param.isNull()) 67 | return add(nullptr); 68 | return add(param.toString().toStdString()); 69 | } 70 | 71 | PgParams &PgParams::clear() 72 | { 73 | _param_pointers.clear(); 74 | _param_lengths.clear(); 75 | _temps.clear(); 76 | return *this; 77 | } 78 | -------------------------------------------------------------------------------- /src/pgparams.h: -------------------------------------------------------------------------------- 1 | #ifndef PGPARAMS_H 2 | #define PGPARAMS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class PgParams 10 | { 11 | public: 12 | PgParams& add(std::string &¶m); 13 | PgParams& add(const std::string ¶m); 14 | PgParams& add(const char *param, int size = -1); 15 | 16 | PgParams& operator<<(std::string &¶m); 17 | PgParams& operator<<(const std::string ¶m); 18 | PgParams& operator<<(const char *param); 19 | 20 | PgParams& addref(std::string &¶m); 21 | PgParams& addref(const std::string ¶m); 22 | PgParams& addref(const char *param, int size = -1); 23 | 24 | PgParams& add(const QString ¶m); 25 | PgParams& add(const QVariant ¶m); 26 | 27 | const char* const* values() const { return _param_pointers.data(); } 28 | const int* lengths() const { return _param_lengths.data(); } 29 | size_t count() const { return _param_lengths.size(); } 30 | PgParams& clear(); 31 | 32 | private: 33 | std::vector _param_pointers; 34 | std::vector _param_lengths; 35 | std::vector _temps; 36 | }; 37 | 38 | 39 | #endif // PGPARAMS_H 40 | -------------------------------------------------------------------------------- /src/pgtypes.h: -------------------------------------------------------------------------------- 1 | #ifndef PG_TYPES_H 2 | #define PG_TYPES_H 3 | 4 | #define VARHDRSZ 4 5 | 6 | #define BOOLOID 16 7 | #define BYTEAOID 17 8 | #define CHAROID 18 9 | #define NAMEOID 19 10 | #define INT8OID 20 11 | #define INT2OID 21 12 | #define INT2VECTOROID 22 13 | #define INT4OID 23 14 | #define REGPROCOID 24 15 | #define TEXTOID 25 16 | #define OIDOID 26 17 | #define TIDOID 27 18 | #define XIDOID 28 19 | #define CIDOID 29 20 | #define OIDVECTOROID 30 21 | #define JSONOID 114 22 | #define XMLOID 142 23 | #define PGNODETREEOID 194 24 | #define PGDDLCOMMANDOID 32 25 | #define POINTOID 600 26 | #define LSEGOID 601 27 | #define PATHOID 602 28 | #define BOXOID 603 29 | #define POLYGONOID 604 30 | #define LINEOID 628 31 | #define FLOAT4OID 700 32 | #define FLOAT8OID 701 33 | #define ABSTIMEOID 702 34 | #define RELTIMEOID 703 35 | #define TINTERVALOID 704 36 | #define UNKNOWNOID 705 37 | #define CIRCLEOID 718 38 | #define CASHOID 790 39 | #define MACADDROID 829 40 | #define INETOID 869 41 | #define CIDROID 650 42 | #define INT2ARRAYOID 1005 43 | #define INT4ARRAYOID 1007 44 | #define TEXTARRAYOID 1009 45 | #define OIDARRAYOID 1028 46 | #define FLOAT4ARRAYOID 1021 47 | #define ACLITEMOID 1033 48 | #define CSTRINGARRAYOID 1263 49 | #define BPCHAROID 1042 50 | #define VARCHAROID 1043 51 | #define DATEOID 1082 52 | #define TIMEOID 1083 53 | #define TIMESTAMPOID 1114 54 | #define TIMESTAMPTZOID 1184 55 | #define INTERVALOID 1186 56 | #define TIMETZOID 1266 57 | #define BITOID 1560 58 | #define VARBITOID 1562 59 | #define NUMERICOID 1700 60 | #define REFCURSOROID 1790 61 | #define REGPROCEDUREOID 2202 62 | #define REGOPEROID 2203 63 | #define REGOPERATOROID 2204 64 | #define REGCLASSOID 2205 65 | #define REGTYPEOID 2206 66 | #define REGROLEOID 4096 67 | #define REGNAMESPACEOID 4089 68 | #define REGTYPEARRAYOID 2211 69 | #define UUIDOID 2950 70 | #define LSNOID 3220 71 | #define TSVECTOROID 3614 72 | #define GTSVECTOROID 3642 73 | #define TSQUERYOID 3615 74 | #define REGCONFIGOID 3734 75 | #define REGDICTIONARYOID 3769 76 | #define JSONBOID 3802 77 | #define INT4RANGEOID 3904 78 | #define RECORDOID 2249 79 | #define RECORDARRAYOID 2287 80 | #define CSTRINGOID 2275 81 | #define ANYOID 2276 82 | #define ANYARRAYOID 2277 83 | #define VOIDOID 2278 84 | #define TRIGGEROID 2279 85 | #define EVTTRIGGEROID 3838 86 | #define LANGUAGE_HANDLEROID 2280 87 | #define INTERNALOID 2281 88 | #define OPAQUEOID 2282 89 | #define ANYELEMENTOID 2283 90 | #define ANYNONARRAYOID 2776 91 | #define ANYENUMOID 3500 92 | #define FDW_HANDLEROID 3115 93 | #define TSM_HANDLEROID 3310 94 | #define ANYRANGEOID 3831 95 | 96 | #endif // PG_TYPES_H 97 | -------------------------------------------------------------------------------- /src/queryoptions.h: -------------------------------------------------------------------------------- 1 | #ifndef QUERYOPTIONS_H 2 | #define QUERYOPTIONS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class QueryOptions 10 | { 11 | public: 12 | QueryOptions() = delete; 13 | static QJsonObject Extract(const QString &query); 14 | }; 15 | 16 | #endif // QUERYOPTIONS_H 17 | -------------------------------------------------------------------------------- /src/querywidget.h: -------------------------------------------------------------------------------- 1 | #ifndef QUERYWIDGET_H 2 | #define QUERYWIDGET_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class DbConnection; 12 | class TableModel; 13 | class SqlSyntaxHighlighter; 14 | class QMenu; 15 | class FindAndReplacePanel; 16 | class QVBoxLayout; 17 | class DataTable; 18 | class CodeEditor; 19 | class QCompleter; 20 | class QTimer; 21 | 22 | class QueryWidget : public QSplitter 23 | { 24 | Q_OBJECT 25 | public: 26 | explicit QueryWidget(QWidget *parent = nullptr); 27 | explicit QueryWidget(DbConnection *connection, QWidget *parent = nullptr); 28 | ~QueryWidget(); 29 | const QString& fileName() { return _fn; } 30 | bool openFile(const QString &fileName, const QString &encoding); 31 | bool saveFile(const QString &fileName, const QString &encoding = QString()); 32 | QString encoding() { return _encoding; } 33 | DbConnection* dbConnection() { return _connection.get(); } 34 | void setDbConnection(DbConnection *connection); 35 | void ShowFindPanel(FindAndReplacePanel *panel); 36 | void highlight(std::shared_ptr con = nullptr); 37 | void dehighlight(); 38 | 39 | void setReadOnly(bool ro = true); 40 | bool isReadOnly() const; 41 | void clear(); 42 | bool isModified() const; 43 | void setModified(bool m = true); 44 | void setTextCursor(const QTextCursor &cursor); 45 | QString toPlainText(); 46 | QTextCursor textCursor() const; 47 | QTextDocument* document() const; 48 | QWidget* editor() const; 49 | void setPlainText(const QString &text); 50 | void setHtml(const QString &html); 51 | void setQuerySettings(QJsonObject &querySettings); 52 | bool isTimerActive() const; 53 | void stopTimer(); 54 | void executeOnTimer(const QString &query, int interval); 55 | 56 | signals: 57 | void sqlChanged(); 58 | void error(QString msg) const; 59 | 60 | public slots: 61 | void onMessage(const QString &text); 62 | void onError(const QString &text); 63 | void fetched(DataTable *table); 64 | void clearResult(); 65 | void onCompleterRequest(); 66 | //void onCustomGridContextMenuRequested(const QPoint & pos); 67 | //void on_customEditorContextMenuRequested(const QPoint & pos); 68 | 69 | private: 70 | QTimer *_timer; 71 | QJsonObject _querySettings; 72 | QString _fn; 73 | QString _encoding; 74 | QWidget *_editor; 75 | QPlainTextEdit *_messages; 76 | QSplitter *_resSplitter; 77 | std::shared_ptr _connection; 78 | SqlSyntaxHighlighter *_highlighter; 79 | QVBoxLayout *_editorLayout; 80 | QList _tables; 81 | QMenu *_resultMenu; 82 | QAction *_actionCopy; 83 | void log(const QString &text, QColor color); 84 | static QCompleter *completer(); 85 | }; 86 | 87 | #endif // QUERYWIDGET_H 88 | -------------------------------------------------------------------------------- /src/scripting.h: -------------------------------------------------------------------------------- 1 | #ifndef SCRIPTS_H 2 | #define SCRIPTS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class DbConnection; 10 | class DataTable; 11 | 12 | namespace Scripting 13 | { 14 | 15 | /*! 16 | * \brief Class emits api to js code. 17 | * 18 | * Technically, sql or js script may return a bunch of data (resultsets, scripts) 19 | * to be used to display db object content (tab pages with grids, scripts and so on). 20 | * CppConductor accumulates all the returned data, that's why there are lists of 21 | * resultsets, scripts and html content. This multipart result may be used in the future, 22 | * but for now we use simple gui and display only one item at a time. To show additional 23 | * data on the db object's dependent part of gui the one should add additional subitems 24 | * within db tree node and display every part of context data separately. 25 | */ 26 | class CppConductor : public QObject 27 | { 28 | Q_OBJECT 29 | public: 30 | CppConductor(std::shared_ptr cn, std::function cb) : _cn(cn), _cb(cb) {} 31 | CppConductor(const CppConductor&) = delete; 32 | ~CppConductor(); 33 | 34 | private: 35 | std::shared_ptr _cn; 36 | std::function _cb; 37 | 38 | public: 39 | QList resultsets; 40 | QList scripts; 41 | QList htmls; 42 | QList texts; 43 | std::shared_ptr connection() const { return _cn; } 44 | 45 | public slots: 46 | QVariant value(QString type); 47 | void appendTable(DataTable *table); 48 | void appendScript(QString script); 49 | void appendHtml(QString html); 50 | void appendText(QString text); 51 | void clear(); 52 | }; 53 | 54 | enum class Context { Root = 0, Tree, Content, Preview, Autocomplete }; 55 | struct Script 56 | { 57 | enum class Type { SQL, QS }; 58 | Script(QString body, Type type) : body(body), type(type) {} 59 | QString body; 60 | Type type = Type::SQL; 61 | }; 62 | 63 | QString dbmsScriptPath(DbConnection *con, Context context = Context::Root); 64 | void refresh(DbConnection *connection, Context context); 65 | Script* getScript(DbConnection *connection, Context context, const QString &objectType); 66 | // unable to make QObject movable, but we can't allow CppConductor to be copied => unique_ptr 67 | std::unique_ptr execute( 68 | std::shared_ptr connection, 69 | Context context, 70 | const QString &objectType, 71 | std::function envCallback); 72 | std::unique_ptr execute( 73 | DbConnection *connection, 74 | Context context, 75 | const QString &objectType, 76 | std::function envCallback); 77 | } 78 | 79 | #endif // SCRIPTS_H 80 | -------------------------------------------------------------------------------- /src/settings.h: -------------------------------------------------------------------------------- 1 | #ifndef SETTINGS_H 2 | #define SETTINGS_H 3 | 4 | #include 5 | 6 | struct RecentFile 7 | { 8 | QString fileName; 9 | QString encoding; 10 | }; 11 | Q_DECLARE_METATYPE(QList) 12 | 13 | namespace SqtSettings 14 | { 15 | 16 | void load(); 17 | QVariant value(const QString &name, const QVariant &defaultValue = QVariant()); 18 | void setValue(const QString &key, const QVariant &value); 19 | 20 | } // namespace SqtSettings 21 | 22 | #endif // SETTINGS_H 23 | -------------------------------------------------------------------------------- /src/settingsdialog.cpp: -------------------------------------------------------------------------------- 1 | #include "settingsdialog.h" 2 | #include "ui_settingsdialog.h" 3 | #include "settings.h" 4 | #include 5 | 6 | SettingsDialog::SettingsDialog(QWidget *parent) : 7 | QDialog(parent), 8 | ui(new Ui::SettingsDialog) 9 | { 10 | ui->setupUi(this); 11 | restoreGeometry(SqtSettings::value("settingsDialogGeometry").toByteArray()); 12 | ui->appStyle->setPlainText(SqtSettings::value("appStyle").toString()); 13 | ui->encodings->setText(SqtSettings::value("encodings").toString()); 14 | ui->tabSize->setValue(SqtSettings::value("tabSize").toInt()); 15 | ui->singleRowMode->setChecked(SqtSettings::value("pgSingleRowMode", false).toBool()); 16 | ui->highlightCurrentLine->setChecked(SqtSettings::value("highlightCurrentLine", false).toBool()); 17 | ui->f1url->setText(SqtSettings::value("f1url").toString()); 18 | ui->shiftF1url->setText(SqtSettings::value("shiftF1url").toString()); 19 | } 20 | 21 | SettingsDialog::~SettingsDialog() 22 | { 23 | delete ui; 24 | } 25 | 26 | void SettingsDialog::on_okBtn_clicked() 27 | { 28 | SqtSettings::setValue("appStyle", ui->appStyle->toPlainText()); 29 | SqtSettings::setValue("encodings", ui->encodings->text()); 30 | SqtSettings::setValue("tabSize", ui->tabSize->value()); 31 | SqtSettings::setValue("pgSingleRowMode", ui->singleRowMode->isChecked()); 32 | SqtSettings::setValue("highlightCurrentLine", ui->highlightCurrentLine->isChecked()); 33 | SqtSettings::setValue("f1url", ui->f1url->text()); 34 | SqtSettings::setValue("shiftF1url", ui->shiftF1url->text()); 35 | SqtSettings::setValue("settingsDialogGeometry", saveGeometry()); 36 | accept(); 37 | SqtSettings::load(); 38 | } 39 | -------------------------------------------------------------------------------- /src/settingsdialog.h: -------------------------------------------------------------------------------- 1 | #ifndef SETTINGSDIALOG_H 2 | #define SETTINGSDIALOG_H 3 | 4 | #include 5 | 6 | class QAbstractButton; 7 | 8 | namespace Ui { 9 | class SettingsDialog; 10 | } 11 | 12 | class SettingsDialog : public QDialog 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | explicit SettingsDialog(QWidget *parent = nullptr); 18 | ~SettingsDialog(); 19 | 20 | private slots: 21 | void on_okBtn_clicked(); 22 | 23 | private: 24 | Ui::SettingsDialog *ui; 25 | }; 26 | 27 | #endif // SETTINGSDIALOG_H 28 | -------------------------------------------------------------------------------- /src/settingsdialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | SettingsDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 773 10 | 470 11 | 12 | 13 | 14 | Settings 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Application-wide style 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | File dialog encodings<br/><i>(comma separated)</i> 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | Single row mode<br/><i>(PostgreSQL native)</i> 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | Highlight current line 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | Tab size, characters 63 | 64 | 65 | 66 | 67 | 68 | 69 | 1 70 | 71 | 72 | 8 73 | 74 | 75 | 76 | 77 | 78 | 79 | Qt::Horizontal 80 | 81 | 82 | 83 | 40 84 | 20 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | F1 url 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | Shift+F1 url 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | Qt::Horizontal 117 | 118 | 119 | 120 | 40 121 | 20 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | Ok 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /src/sqlparser.h: -------------------------------------------------------------------------------- 1 | #ifndef SQLPARSER_H 2 | #define SQLPARSER_H 3 | 4 | #include 5 | #include 6 | 7 | namespace SqlParser 8 | { 9 | 10 | enum class AliasSearchStatus 11 | { 12 | NotFound, ///< aliased object not found 13 | NotParsed, ///< parsing of the object is not implemented (completion impossible) 14 | Name, ///< caller should acquire columns from database 15 | Fields ///< words ready to use within completer 16 | }; 17 | 18 | QPair explainAlias(const QString &alias, const QString &text, int pos) noexcept; 19 | 20 | }; // sqlparser namespace 21 | 22 | #endif // SQLPARSER_H 23 | -------------------------------------------------------------------------------- /src/sqlsyntaxhighlighter.h: -------------------------------------------------------------------------------- 1 | #ifndef SQLSYNTAXHIGHLIGHTER_H 2 | #define SQLSYNTAXHIGHLIGHTER_H 3 | 4 | #include 5 | 6 | class SqlSyntaxHighlighter : public QSyntaxHighlighter 7 | { 8 | Q_OBJECT 9 | public: 10 | explicit SqlSyntaxHighlighter(const QJsonObject &settings, QObject *parent = nullptr); 11 | bool isKeyword(const QString &word); 12 | 13 | protected: 14 | virtual void highlightBlock(const QString &text); 15 | 16 | private: 17 | enum class LastWordOption { Yes, No, MayBe }; 18 | struct WordInfo 19 | { 20 | char formatIndex; 21 | LastWordOption isLastWord; 22 | QHash nextWords; 23 | }; 24 | QHash keywords; 25 | 26 | QVector formats; 27 | QHash functions; 28 | QString delimiters; 29 | bool tsqlBrackets; 30 | }; 31 | 32 | #endif // SQLSYNTAXHIGHLIGHTER_H 33 | -------------------------------------------------------------------------------- /src/sqt.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parihaaraka/sqt/610e14e483fc5b27c19040ddfa4432d0aef4d990/src/sqt.ico -------------------------------------------------------------------------------- /src/sqt.pro: -------------------------------------------------------------------------------- 1 | QT += widgets qml 2 | 3 | TARGET = sqt 4 | TEMPLATE = app 5 | CONFIG += c++17 # for the sake of [[fallthrough]] only (for now) 6 | 7 | # prevent making debug and release subfolders in target dir on windows 8 | CONFIG -= debug_and_release debug_and_release_target 9 | 10 | SOURCES += main.cpp\ 11 | mainwindow.cpp \ 12 | dbobjectsmodel.cpp \ 13 | dbobject.cpp \ 14 | logindialog.cpp \ 15 | dbosortfilterproxymodel.cpp \ 16 | odbcconnection.cpp \ 17 | querywidget.cpp \ 18 | styling.cpp \ 19 | tablemodel.cpp \ 20 | extfiledialog.cpp \ 21 | dbtreeitemdelegate.cpp \ 22 | findandreplacepanel.cpp \ 23 | connectiondialog.cpp \ 24 | dbconnection.cpp \ 25 | datatable.cpp \ 26 | dbconnectionfactory.cpp \ 27 | pgconnection.cpp \ 28 | pgparams.cpp \ 29 | sqlsyntaxhighlighter.cpp \ 30 | scripting.cpp \ 31 | appeventhandler.cpp \ 32 | copycontext.cpp \ 33 | codeeditor.cpp \ 34 | settings.cpp \ 35 | settingsdialog.cpp \ 36 | jsonsyntaxhighlighter.cpp \ 37 | sqlparser.cpp \ 38 | queryoptions.cpp \ 39 | timechart.cpp \ 40 | timechartscene.cpp 41 | 42 | HEADERS += mainwindow.h \ 43 | dbobjectsmodel.h \ 44 | dbobject.h \ 45 | logindialog.h \ 46 | dbosortfilterproxymodel.h \ 47 | odbcconnection.h \ 48 | querywidget.h \ 49 | styling.h \ 50 | tablemodel.h \ 51 | extfiledialog.h \ 52 | dbtreeitemdelegate.h \ 53 | findandreplacepanel.h \ 54 | connectiondialog.h \ 55 | dbconnection.h \ 56 | datatable.h \ 57 | dbconnectionfactory.h \ 58 | pgconnection.h \ 59 | pgtypes.h \ 60 | pgparams.h \ 61 | sqlsyntaxhighlighter.h \ 62 | scripting.h \ 63 | appeventhandler.h \ 64 | copycontext.h \ 65 | codeeditor.h \ 66 | settings.h \ 67 | settingsdialog.h \ 68 | jsonsyntaxhighlighter.h \ 69 | sqlparser.h \ 70 | queryoptions.h \ 71 | timechart.h \ 72 | timechartscene.h 73 | 74 | FORMS += mainwindow.ui \ 75 | logindialog.ui \ 76 | findandreplacepanel.ui \ 77 | connectiondialog.ui \ 78 | settingsdialog.ui 79 | 80 | RESOURCES += \ 81 | sqt.qrc 82 | 83 | #https://wiki.qt.io/Install_Qt_5_on_Ubuntu 84 | unix { 85 | INCLUDEPATH += /usr/include/postgresql 86 | LIBS += -lodbc -lpq -lssl 87 | QMAKE_POST_LINK += $$quote($$QMAKE_SYMBOLIC_LINK $$system_quote($${_PRO_FILE_PWD_}/../decor) $$system_quote($$OUT_PWD))$$escape_expand(\n\t) 88 | QMAKE_POST_LINK += $$quote($$QMAKE_SYMBOLIC_LINK $$system_quote($${_PRO_FILE_PWD_}/../scripts) $$system_quote($$OUT_PWD))$$escape_expand(\n\t) 89 | } 90 | 91 | win32 { 92 | #win32-g++:contains(QMAKE_HOST.arch, x86_64):{ 93 | win32-msvc*:contains(QMAKE_HOST.arch, x86_64):{ 94 | LIBS += "-LC:/Program Files (x86)/Microsoft SDKs/Windows/v7.1A/Lib/x64" \ 95 | -lodbc32 \ 96 | -lodbccp32 97 | } else { 98 | LIBS += "-LC:/Program Files (x86)/Microsoft SDKs/Windows/v7.1A/Lib" \ 99 | -lodbc32 \ 100 | -lodbccp32 101 | } 102 | RC_FILE = sqt.rc 103 | 104 | PG_BIN_TREE = "C:/Dev/pgsql-9.6.6" 105 | LIBS += "$${PG_BIN_TREE}/lib/libpq.lib" 106 | INCLUDEPATH += "$${PG_BIN_TREE}/include" "$${PG_BIN_TREE}/include/libpq" 107 | 108 | QMAKE_EXTRA_TARGETS += makedirs 109 | makedirs.target = sqt_subdirs 110 | makedirs.commands = $$sprintf($$QMAKE_MKDIR_CMD, $$OUT_PWD/decor) $$escape_expand(\n\t) $$sprintf($$QMAKE_MKDIR_CMD, $$OUT_PWD/scripts) 111 | 112 | QMAKE_POST_LINK += $$QMAKE_COPY_DIR $$system_quote($$shell_path($${_PRO_FILE_PWD_}/../decor)) $$system_quote($$shell_path($$OUT_PWD/decor))$$escape_expand(\n\t) 113 | QMAKE_POST_LINK += $$QMAKE_COPY_DIR $$system_quote($$shell_path($${_PRO_FILE_PWD_}/../scripts)) $$system_quote($$shell_path($$OUT_PWD/scripts))$$escape_expand(\n\t) 114 | } 115 | -------------------------------------------------------------------------------- /src/sqt.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | img/database-sql.png 4 | img/arrow-circle-double-135.png 5 | img/server--plus.png 6 | img/server.png 7 | img/shovel.png 8 | img/sql.png 9 | img/control.png 10 | img/control-stop.png 11 | sqt.ico 12 | img/bookmark.png 13 | img/gear.png 14 | img/databases.png 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/sqt.rc: -------------------------------------------------------------------------------- 1 | IDI_ICON1 ICON DISCARDABLE "sqt.ico" -------------------------------------------------------------------------------- /src/stuff.h: -------------------------------------------------------------------------------- 1 | #ifndef STUFF_H 2 | #define STUFF_H 3 | 4 | #include 5 | #include 6 | 7 | int utf16le_to_utf8(unsigned int c, char *outbuf); 8 | 9 | std::string convertToUtf8(const char* chars, int len); 10 | 11 | void append_string(std::string &source, std::vector &destination); 12 | 13 | std::string get_string(std::vector &source, int *position); 14 | 15 | void append_int32(int source, std::vector &destination); 16 | 17 | int get_int32(std::vector &source, int *position); 18 | 19 | void str_replace(std::string &src, std::string substr, std::string res); 20 | 21 | std::string trim(const std::string &a_str); 22 | 23 | const char* timed_prefix(const char* prefix = NULL); 24 | 25 | void GpgCmd(std::vector source, std::string command, std::vector &out, std::string &log); 26 | 27 | std::vector Decrypt(int client_id, std::string message, char *key_id); 28 | 29 | std::string Encrypt(char *key_id, std::vector message); 30 | 31 | #endif // STUFF_H 32 | -------------------------------------------------------------------------------- /src/styling.cpp: -------------------------------------------------------------------------------- 1 | #include "styling.h" 2 | #include 3 | #include 4 | 5 | #if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) 6 | #include 7 | #endif 8 | 9 | bool isDarkMode() 10 | { 11 | #if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) 12 | const auto scheme = QGuiApplication::styleHints()->colorScheme(); 13 | return scheme == Qt::ColorScheme::Dark; 14 | #else 15 | const QPalette defaultPalette; 16 | const auto text = defaultPalette.color(QPalette::WindowText); 17 | const auto window = defaultPalette.color(QPalette::Window); 18 | return text.lightness() > window.lightness(); 19 | #endif 20 | } 21 | -------------------------------------------------------------------------------- /src/styling.h: -------------------------------------------------------------------------------- 1 | #ifndef STYLING_H 2 | #define STYLING_H 3 | 4 | bool isDarkMode(); 5 | 6 | #endif // STYLING_H 7 | -------------------------------------------------------------------------------- /src/tablemodel.h: -------------------------------------------------------------------------------- 1 | #ifndef TABLEMODEL_H 2 | #define TABLEMODEL_H 3 | 4 | #include 5 | 6 | class DataTable; 7 | class TableModel : public QAbstractItemModel 8 | { 9 | Q_OBJECT 10 | public: 11 | explicit TableModel(QObject *parent = nullptr); 12 | virtual ~TableModel() override; 13 | 14 | virtual QModelIndex parent(const QModelIndex &) const override; 15 | virtual int rowCount(const QModelIndex & = QModelIndex()) const override; 16 | virtual int columnCount(const QModelIndex & = QModelIndex()) const override; 17 | virtual QModelIndex index(int row, int column, const QModelIndex & = QModelIndex()) const override; 18 | virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; 19 | virtual Qt::ItemFlags flags(const QModelIndex &index) const override; 20 | virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; 21 | void take(DataTable *srcTable); 22 | void clear(); 23 | DataTable* table() const { return _table; } 24 | 25 | private: 26 | DataTable *_table; 27 | 28 | }; 29 | 30 | #endif // TABLEMODEL_H 31 | -------------------------------------------------------------------------------- /src/timechart.h: -------------------------------------------------------------------------------- 1 | #ifndef TIME_CHART_H 2 | #define TIME_CHART_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class TimeChartScene; 12 | class TimeChart : public QGraphicsView 13 | { 14 | Q_OBJECT 15 | friend class TimeChartScene; 16 | public: 17 | explicit TimeChart(QWidget *parent = nullptr); 18 | virtual ~TimeChart() override = default; 19 | bool pathExists(const QString &name) const; 20 | QStringList pathNames() const; 21 | void createPath(const QString &name, const QColor &color, bool cumulative = false); 22 | void appendValue(const QString &name, qreal value, const QDateTime &moment); 23 | void applyNewValues(); 24 | void setXSourceField(const QString &name); 25 | QString xSourceField() const; 26 | protected: 27 | virtual void wheelEvent(QWheelEvent *event) override; 28 | virtual void resizeEvent(QResizeEvent * event) override; 29 | private: 30 | struct Path { 31 | QGraphicsPathItem* pathItem; 32 | qreal prevValue; // to process cumulative values 33 | bool cumulative; 34 | }; 35 | QMap> _pathParts; 36 | QDateTime _startMoment; 37 | QMap _paths; 38 | QRect _viewportClipRect; 39 | qreal _scaleX, _scaleY; 40 | qreal _maxValue = 0; 41 | QString _xSourceField; 42 | QString xLabel(qreal x, qreal secApproxInterval); 43 | static qreal beautifyInterval(qreal interval); 44 | static qreal beautifyTimeInterval(qreal interval); 45 | private slots: 46 | void adjustViewport(); 47 | }; 48 | 49 | #endif // TIME_CHART_H 50 | -------------------------------------------------------------------------------- /src/timechartscene.h: -------------------------------------------------------------------------------- 1 | #ifndef TIMECHARTSCENE_H 2 | #define TIMECHARTSCENE_H 3 | 4 | #include 5 | #include 6 | 7 | class TimeChartScene : public QGraphicsScene 8 | { 9 | Q_OBJECT 10 | friend class TimeChart; 11 | public: 12 | QRectF clipRect(); 13 | private: 14 | QRectF _sceneClipRect; 15 | QRect _yLabelRect; 16 | qreal _intervalX = 0; 17 | qreal _intervalY = 0; 18 | protected: 19 | TimeChartScene(QObject *parent = nullptr); 20 | virtual ~TimeChartScene() override = default; 21 | virtual void drawBackground(QPainter *painter, const QRectF &rect) override; 22 | virtual void drawForeground(QPainter *painter, const QRectF &rect) override; 23 | }; 24 | 25 | #endif // TIMECHARTSCENE_H 26 | --------------------------------------------------------------------------------