Compare commits

...

991 Commits

Author SHA1 Message Date
Esther Lozano
076cacc6f1 Release 0.35.0 2019-12-30 15:37:16 +01:00
Raúl Marín
741d171f4a Merge pull request #392 from Algunenano/test_bionic
Test bionic
2019-12-26 18:11:30 +01:00
Raul Marin
093e0bcb36 Always use @@plpythonu@@ as variable 2019-12-26 17:59:29 +01:00
Raul Marin
ca1d5b0c91 Avoid outputting python error messages in regress tests 2019-12-26 17:46:10 +01:00
Raul Marin
cd62071757 Try to use bionic for PG12 2019-12-26 15:54:42 +01:00
Raúl Marín
4c15fafd72 Merge pull request #387 from CartoDB/2273_support
use literal substitution instead of identifier
2019-12-24 14:24:32 +01:00
Raúl Marín
b246ada312 Update NEWS 2019-12-24 14:17:03 +01:00
Raúl Marín
ecf0a06448 Merge remote-tracking branch 'carto/master' into 2273_support 2019-12-24 14:14:33 +01:00
Raúl Marín
ec0d94dd0e Add test for CDB_UserDataSize identifier quoation 2019-12-24 14:14:26 +01:00
Raúl Marín
c5bbb180c2 Merge pull request #391 from Algunenano/python3again
Set python3 as dependency for PG12+ again
2019-12-24 14:08:02 +01:00
Raúl Marín
9fa532623d Set python3 as dependency for PG12+ again 2019-12-24 13:57:13 +01:00
Raúl Marín
921800e6a3 Merge pull request #390 from Algunenano/revert_the_revert
Add huge warnings
2019-12-24 01:05:02 +01:00
Raúl Marín
dfd26d930e Add huge warnings 2019-12-24 00:59:11 +01:00
Raúl Marín
c0270068c4 Merge pull request #389 from Algunenano/revert_the_revert
Revert "Revert 0.33.0"
2019-12-24 00:39:22 +01:00
Raúl Marín
9010642326 Revert "Revert 0.33.0"
This reverts commit 24cb6cf9c1.
2019-12-24 00:33:35 +01:00
Raúl Marín
8974986d61 Release 0.34.0 2019-12-23 20:34:11 +01:00
Raúl Marín
fea2474117 Merge pull request #388 from Algunenano/revert0330
Revert changes in 0.33.0
2019-12-23 20:31:51 +01:00
Raúl Marín
654fa3ac02 Update NEWS.md
Co-Authored-By: Daniel G. Aubert <danielgarciaaubert@gmail.com>
2019-12-23 20:25:36 +01:00
Raúl Marín
24cb6cf9c1 Revert 0.33.0 2019-12-23 20:23:02 +01:00
Alberto Romeu
1c7b0c71ec use literal substitution instead of identifier 2019-12-20 16:27:03 +01:00
Daniel García Aubert
5e3adba2d4 Increase version number to 0.33.0 2019-12-20 12:42:09 +01:00
Daniel G. Aubert
89c9025431 Merge pull request #382 from Algunenano/federated_functions
Federated Server functions
2019-12-20 12:39:05 +01:00
Raúl Marín
6ebffe1b2c PR review improvements 2019-12-17 11:26:56 +01:00
Raúl Marín
b3503ea429 FederatedTableList: Fix column parsing with default names 2019-12-12 15:52:50 +01:00
Raúl Marín
3c869e3d5a FServer list: Return the username if the user has been granted access to the server 2019-12-11 18:37:26 +01:00
Raúl Marín
dac135890d CDB_Federated_Table_Register: Reuse webmercator_column if geom_column is NULL 2019-12-10 18:08:25 +01:00
Raúl Marín
9372c9f4e0 FederatedServer: Fix a bug when extracting the webmercator column from the view definition 2019-12-05 16:26:37 +01:00
Raúl Marín
06b6d9140d Merge remote-tracking branch 'carto/master' into federated_functions 2019-12-02 16:51:35 +01:00
Raúl Marín
beb985b64f Merge pull request #386 from Algunenano/revertPG12
Revert PG12 + Python3
2019-12-02 16:50:25 +01:00
Raúl Marín
eea750c904 Revert PG12 + Python3 2019-12-02 16:46:58 +01:00
Raúl Marín
da570c50aa Merge remote-tracking branch 'carto/master' into federated_functions 2019-11-15 13:50:21 +01:00
Raúl Marín
d549ecced4 Merge pull request #385 from CartoDB/federated_functions_permissions
Federated functions permissions
2019-11-15 13:47:16 +01:00
Raúl Marín
fde12c818a Update comments 2019-11-15 13:09:52 +01:00
Raúl Marín
e99e4a02c9 Remove TODO
Since the server registration requires superadmin priviledges
it doesn't make sense to over protect the role creation
2019-11-14 19:00:09 +01:00
Raúl Marín
fa5f0bcbc1 CDB_Federated_Server_Grant_Access: comment about search_path 2019-11-14 18:55:38 +01:00
Raúl Marín
adca727169 Revert "Go back to public user mappings"
This reverts commit 64e185b841.
2019-11-14 18:46:45 +01:00
Raúl Marín
0893fae025 Revert "CDB_Federated_Server_Unregister: Drop owned in cascade"
This reverts commit 1b86517007.
2019-11-14 18:46:02 +01:00
Raúl Marín
e69d3b1c30 Place all views in a shared schema 2019-11-14 18:45:09 +01:00
Rafa de la Torre
a57431a04d Merge pull request #384 from CartoDB/federated_diagnostics_latency
Federated diagnostics latency
2019-11-14 18:29:25 +01:00
Rafa de la Torre
064cc2a76b Fix for missing port in pg_foreign_server: default to standard 5432 2019-11-14 17:57:05 +01:00
Rafa de la Torre
7f9905cbd5 Test what happens when missing PG port 2019-11-14 17:56:29 +01:00
Raúl Marín
6e455efcdd Improve warning 2019-11-14 14:15:56 +01:00
Raúl Marín
1b86517007 CDB_Federated_Server_Unregister: Drop owned in cascade
Since now views might be owned by other roles, we need to drop them
in cascade to force deletion
2019-11-14 14:07:41 +01:00
Raúl Marín
64e185b841 Go back to public user mappings 2019-11-14 13:43:28 +01:00
Raúl Marín
38d8a470bc Federated Server: Grant all over postgis and cartodb schemas 2019-11-14 13:24:32 +01:00
Raúl Marín
4920029560 CDB_FederatedServerTables: Improve permission handling and error messages 2019-11-14 13:10:21 +01:00
Rafa de la Torre
9b91704480 Calculate stats only when they make sense 2019-11-13 19:27:56 +01:00
Rafa de la Torre
a340f98b96 Update tests with latency stats 2019-11-13 19:19:39 +01:00
Rafa de la Torre
57dcfc2a35 Add a bunch of statistics 2019-11-13 18:55:09 +01:00
Rafa de la Torre
3ae7b1fe05 Fix bug: do not initialize samples in every iter 2019-11-13 18:27:14 +01:00
Rafa de la Torre
f7d10adbc2 Fix another python2/3 incompat: xrange 2019-11-13 17:16:53 +01:00
Rafa de la Torre
203bd64058 Fix python2/3 compat issue 2019-11-13 17:02:22 +01:00
Rafa de la Torre
19c6de2096 Comment out suspected line
This may be causing the error

     ERROR:  could not compile PL/Python function "__cdb_fs_tcp_foreign_server_latency"
     DETAIL:  SyntaxError: invalid syntax (<string>, line 26)

when testing in PG12 + plpythonu3
2019-11-13 14:52:24 +01:00
Raúl Marín
e231500c46 Give permissions over cartodb to the FS role 2019-11-13 14:20:08 +01:00
Rafa de la Torre
4b9c048235 Close socket properly before the next iteration
This avoid the errors `[Errno 106] Transport endpoint is already
connected` which are due to connections kept in TIME_WAIT state.

We don't use socket.SO_REUSEADDR as it would make the first connection
a special case compared to the following ones.
2019-11-13 12:25:41 +01:00
Rafa de la Torre
5897d8a9cb Fix timer start in measurements 2019-11-13 12:24:59 +01:00
Rafa de la Torre
980657c4a4 Do not add None to samples in case of connection error
Otherwise we get `TypeError: unsupported operand type(s) for +: 'float'
and 'NoneType'` when calculating the average.
2019-11-13 12:16:21 +01:00
Rafa de la Torre
a4a4a1dff1 Honor n_samples param 2019-11-13 12:13:42 +01:00
Rafa de la Torre
0362825b8c Encapsulate python in __CDB_FS_TCP_Foreign_Server_Latency
Instead of having a generic function, merge
__CDB_FS_TCP_Network_Latency and __CDB_FS_Foreign_Server_Host_PG into
one function so that it can only "ping" federated servers.
2019-11-13 11:44:24 +01:00
Raúl Marín
9eab5e2533 __CDB_FS_Generate_Server_Role_Name: set to STABLE
current_database() is stable, not immutable
2019-11-12 18:15:20 +01:00
Raúl Marín
0d455d9521 __CDB_FS_List_Foreign_Schemas_PG: Remove extra role generation 2019-11-12 18:14:36 +01:00
Rafa de la Torre
364933b6b9 Compatibility with PG 9.6 and 10
See https://www.postgresql.org/message-id/flat/55137679-fd6b-baf0-bfbf-6558ce5cb409%40postgrespro.ru
2019-11-12 15:57:15 +01:00
Rafa de la Torre
18f9f79fe8 Rename key to server_latency_ms to be self-explanatory 2019-11-12 15:08:26 +01:00
Rafa de la Torre
a032cc08e0 Measure latency as the avg of n_samples 2019-11-12 15:01:56 +01:00
Rafa de la Torre
9dc547c838 Add test for wrong port 2019-11-12 13:37:04 +01:00
Rafa de la Torre
d3ae4b808c Remove default port 5432 in generic function 2019-11-12 13:27:42 +01:00
Rafa de la Torre
26f91001ee Retrieve port from the catalog 2019-11-12 13:06:14 +01:00
Rafa de la Torre
43b242e610 Retrieve host from the catalog 2019-11-12 13:02:04 +01:00
Rafa de la Torre
e14c49b223 Add kind of meaningful test for latency 2019-11-12 12:59:36 +01:00
Rafa de la Torre
8c7a75dd0c Implement __CDB_FS_TCP_Network_Latency 2019-11-12 12:42:28 +01:00
Rafa de la Torre
dbed2d1ede More scaffolding for latency in diagnostics 2019-11-12 12:41:37 +01:00
Rafa de la Torre
1c27443ff4 Stub remote server latency (WIP) 2019-11-12 12:41:37 +01:00
Rafa de la Torre
944b111bb1 Merge pull request #383 from CartoDB/federated_diagnostics
Retrieve target PG and postgis versions
2019-11-12 10:45:26 +01:00
Rafa de la Torre
d5ecb39250 Replace hardcoded 5432 by @@PGPORT@@
as requested in review comment
2019-11-12 10:32:25 +01:00
Rafa de la Torre
0ad7cd485d Simplify function with aggregate 2019-11-11 21:34:51 +01:00
Rafa de la Torre
6e9ee296c5 Remove useless commented code 2019-11-11 20:48:14 +01:00
Rafa de la Torre
d87d27d7e5 Use pg_options_to_table instead of manual parsing 2019-11-11 20:42:00 +01:00
Rafa de la Torre
5c9f6964a3 Fix typo: hardcoded loopback server 2019-11-11 18:46:07 +01:00
Rafa de la Torre
d76e3ccc3e Add server options to diagnostics 2019-11-11 16:02:04 +01:00
Rafa de la Torre
eba6cf4565 Test when postgis is not installed in the remote 2019-11-08 20:27:24 +01:00
Rafa de la Torre
6700d24232 Refactor: extract __CDB_FS_Import_If_Not_Exists 2019-11-08 20:16:26 +01:00
Rafa de la Torre
511e24a40e Remove unused var role_name 2019-11-08 20:05:08 +01:00
Rafa de la Torre
80f01d4a51 Implement retrieval of remote postgis version 2019-11-08 20:02:51 +01:00
Rafa de la Torre
d4bc69cd3c Return postgis version in diagnostics info (WIP) 2019-11-08 19:49:16 +01:00
Rafa de la Torre
8730292097 Function to retrieve remote PG server ver 2019-11-08 19:20:08 +01:00
Rafa de la Torre
efd757ffa3 Check against correct server version 2019-11-08 18:18:28 +01:00
Rafa de la Torre
40a2ba9569 Stub function to add server_version to diagnostics 2019-11-08 18:09:22 +01:00
Rafa de la Torre
35b2b7e589 Check the server is of type PG and return jsonb 2019-11-08 18:06:35 +01:00
Rafa de la Torre
4100b66f3b Scaffolding for diagnostic function(s) 2019-11-08 17:11:04 +01:00
Esther Lozano
b1830e49af Increase version number to 0.32.0 2019-11-08 13:09:45 +01:00
Esther Lozano
70f1e00980 Merge pull request #379 from CartoDB/fix-oauth-reassign-functions
Fix OAuth ownership re-assignation for functions
2019-11-08 12:38:43 +01:00
Esther Lozano
8a4a59b340 Document default privileges on functions 2019-11-07 15:03:46 +01:00
Esther Lozano
f06b899605 Add drop permission test for functions 2019-11-07 11:14:26 +01:00
Esther Lozano
09076924c0 Functions are selectable by all roles but not dropable 2019-11-06 21:12:44 +01:00
Raul Marin
d5b3953568 Regress: Remove output that depends on PROJ release 2019-11-06 18:34:20 +01:00
Raul Marin
c64c61781e Make tests path insensitive 2019-11-06 18:26:58 +01:00
Raul Marin
82d8f7e1aa Deprecate FDW user setup ;__( 2019-11-06 18:26:37 +01:00
Esther Lozano
e63f5040d9 Use privileged action on functions for tests 2019-11-06 17:51:00 +01:00
Raul Marin
3cde55ed3a Enforce output order in CDB_Federated_Server_List_Remote_Columns 2019-11-06 17:32:48 +01:00
Raul Marin
a91f14371a Use always the modern notation for named parameters 2019-11-06 17:25:10 +01:00
Raul Marin
899a12fc53 FederatedServer: Use NAME for internal types 2019-11-06 17:12:40 +01:00
Raul Marin
01258530ff Federated Server: Unify remote table listing
- Removes DB_Federated_Server_List_Registered_Tables in favor
of CDB_Federated_Server_List_Remote_Tables that now returns
both registered and unregistered tables and, when they are
registered, the information about the associated view
2019-11-06 17:04:11 +01:00
Raul Marin
90b58fcdec Federated Server: Test with incorrect password 2019-11-06 10:20:53 +01:00
Raul Marin
29e2ee670f Accept PG9.5 and PG10 permission error messages 2019-11-05 18:29:08 +01:00
Raul Marin
e98b18fd25 Add test around grant permissions and accessing registered tables 2019-11-05 18:07:11 +01:00
Raul Marin
e6f07d4f96 Rework API to grant and revoke permissions 2019-11-05 17:18:49 +01:00
Raul Marin
c9b01592e7 CDB_Federated_Table_Register: Handle conflict nicely 2019-11-05 16:53:25 +01:00
Raul Marin
e2beefdb53 Test around NULLs and invalids arguments 2019-11-05 16:39:13 +01:00
Raul Marin
73ee4107d4 CDB_FederatedServerTables: Improve tests readability 2019-11-05 14:48:52 +01:00
Raul Marin
aa481f4219 Permission tests and fixes for CDB_FederatedServerListRemote 2019-11-05 14:35:52 +01:00
Raul Marin
bac7d79ab3 CDB_FederatedServer: Improve tests readability 2019-11-05 13:22:45 +01:00
Raul Marin
98b2b02199 Improve tests readability and test deleting a server from granted access 2019-11-05 11:19:50 +01:00
Raul Marin
10ed64789d Add functions to grant and revoke permissions over federated servers 2019-11-04 19:23:36 +01:00
Raul Marin
0f66c54ce5 Comment cleanup 2019-11-04 16:53:48 +01:00
Raul Marin
03bc3436cd Add more tests for [un-]registering servers 2019-11-04 16:29:18 +01:00
Raul Marin
57f420ab4c CDB_FederatedServerListRemote: Add rainy tests 2019-11-04 15:32:34 +01:00
Raul Marin
c740cfa499 CDB_Federated_Server_List_Remote_Columns: Return also type name 2019-11-04 15:18:46 +01:00
Raul Marin
eea0198864 Add CDB_Federated_Server_List_Remote_Columns 2019-10-31 15:29:37 +01:00
Raul Marin
f75756138a CDB_FederatedServerTables: Avoid decimal mismatch 2019-10-30 15:21:00 +01:00
Raul Marin
28376ffecb CDB_Federated_Table_Register works to refresh a table 2019-10-30 13:53:56 +01:00
Raul Marin
f20a007160 CDB_FederatedServerTables: Some comments 2019-10-30 13:27:44 +01:00
Raul Marin
cf6b00dfd8 CDB_FederatedServerListRemote: Improve comments 2019-10-30 13:20:41 +01:00
Raul Marin
cc5fb37abb CDB_FederatedServer: Improve comments 2019-10-30 13:16:31 +01:00
Raul Marin
b839235801 Add CDB_Federated_Server_List_Registered_Tables 2019-10-30 12:19:30 +01:00
Raul Marin
d5f84784f0 Add CDB_Federated_Table_Unregister 2019-10-30 11:55:02 +01:00
Raul Marin
7bb0b93f8b Test renaming 2019-10-30 11:47:45 +01:00
Raul Marin
a26b96347a Initial implementation of CDB_Federated_Table_Register 2019-10-30 11:40:35 +01:00
Raul Marin
77868a541d Fix symlinks :D 2019-10-29 18:55:18 +01:00
Raul Marin
b76b754811 CDB_FederatedServerTables skeleton 2019-10-29 18:53:05 +01:00
Raul Marin
664468b1e5 Rename CDB_FederatedServerListRemote files 2019-10-29 18:51:47 +01:00
Raul Marin
d85faa8f85 Now trully fix installcheck target 2019-10-29 18:45:10 +01:00
Raul Marin
f7ab3d28a8 __CDB_FS_List_Foreign_Schemas_PG: Handle order and ignore pg_% schemas automatically 2019-10-29 18:35:02 +01:00
Raul Marin
144c4e722b Add federated server list remotes
Includes:
- CDB_Federated_Server_List_Remote_Schemas
- CDB_Federated_Server_List_Remote_Tables
2019-10-29 18:26:52 +01:00
Raul Marin
e22aaee5f5 Test re-registration of a server with different options 2019-10-29 16:47:35 +01:00
Raul Marin
da9ff0c750 Reimplement CDB_Federated_Server_Register_PG and CDB_Federated_Server_Unregister 2019-10-29 16:19:46 +01:00
Raul Marin
e6cb03300b Add auxiliar functions to handle internal naming 2019-10-29 15:38:58 +01:00
Raul Marin
bc7031d872 Move existence check to __CDB_FS_Generate_Object_Name 2019-10-29 13:19:11 +01:00
Raul Marin
427ad94235 Fix installcheck target 2019-10-29 12:34:29 +01:00
Raul Marin
1375894e99 CDB_Federated_Server_Unregister: Better error handling 2019-10-29 12:27:07 +01:00
Raul Marin
f285c806fc Remove error context 2019-10-29 11:57:24 +01:00
Raul Marin
acf1f2dbd4 WIP: Add CDB_Federated_Server_Unregister 2019-10-28 18:34:46 +01:00
Raul Marin
eb02ca4d86 Regress: Allow variables in the tests 2019-10-28 17:12:38 +01:00
Raul Marin
b475eb4356 Federated Server List 2019-10-28 17:10:53 +01:00
Raúl Marín
510a9d12e4 Merge pull request #380 from Algunenano/regress_target
Regress target
2019-10-28 17:08:52 +01:00
Raul Marin
77213f0588 Update NEWS 2019-10-28 16:18:37 +01:00
Raul Marin
8ff0ad74af Add regress target
Runs the regress tests without installing the extension
2019-10-28 16:17:29 +01:00
Raul Marin
a25efc3fc5 Unpackaged: Make it work 2019-10-28 16:14:50 +01:00
Raul Marin
87dec4dbe4 Update README 2019-10-28 16:14:45 +01:00
Gonzalo Riestra
f2e8d029eb check error message 2019-10-25 12:39:30 +02:00
Gonzalo Riestra
036127af9c add schema to function calls 2019-10-25 12:26:21 +02:00
Gonzalo Riestra
2ce4d8ee14 fix grant query 2019-10-25 12:02:08 +02:00
Gonzalo Riestra
a8966270bd add test expect 2019-10-25 11:50:03 +02:00
Gonzalo Riestra
11b30c8f59 fix oauth reassign ownership for functions 2019-10-25 11:34:59 +02:00
Raúl Marín
415220777e Merge pull request #378 from Algunenano/pg12
PG 12 + PLPYTHON 3 compatibility
2019-10-24 17:39:07 +02:00
Raul Marin
1dcc23db15 CDB_UserTablesTest: Make tests work even if the user doesn't have cartodb in the searchpath 2019-10-24 13:45:36 +02:00
Raul Marin
164fba197f test_foreign_tables: Better debugging and query the default database when needed 2019-10-24 12:35:46 +02:00
Raul Marin
7f9a748119 Make CDB_OAuth independent of the PG version 2019-10-24 12:35:46 +02:00
Raul Marin
409b067721 Quota: Remove kb error from regress tests 2019-10-24 11:15:15 +02:00
Raul Marin
21c319eb9a Add postgis 3 build 2019-10-23 17:24:41 +02:00
Raul Marin
dac1f5bffc Update NEWS 2019-10-23 17:15:50 +02:00
Raul Marin
9469871029 Remove unneeded change 2019-10-23 17:06:47 +02:00
Raul Marin
021c7318a3 Adapt QuotaTest to avoid randoms 2019-10-23 16:49:57 +02:00
Raul Marin
29397ff929 Make it work without postgis_raster 2019-10-23 14:21:45 +02:00
Raul Marin
34684507cb Cast sql_identifier to text 2019-10-23 13:46:04 +02:00
Raul Marin
a4bcf4c78f Update error messages 2019-10-22 20:13:38 +02:00
Raul Marin
e787b1d097 Missing qualification 2019-10-22 20:09:15 +02:00
Raul Marin
8245156038 Use distribution package for python redis 2019-10-22 20:06:20 +02:00
Raul Marin
9248ce76bd Update pip3 2019-10-22 19:48:00 +02:00
Raul Marin
d1eb740a00 Missing qualifications 2019-10-22 19:45:42 +02:00
Raul Marin
cb019ff194 Install python3 for PG12 run 2019-10-22 19:35:26 +02:00
Raul Marin
1a99151d0e Install pip and pip3 2019-10-22 18:23:27 +02:00
Raul Marin
8fac0c89eb python3: Try to adapt pathname2url 2019-10-22 18:06:29 +02:00
Raul Marin
9686ad5cfe Try to work with both python2 and python3 2019-10-22 16:49:08 +02:00
Raul Marin
0cecfdb112 log level 2019-10-22 16:32:30 +02:00
Raul Marin
ccbaf785cf Updates 2019-10-22 16:00:29 +02:00
Raul Marin
aed88fd958 Force all PG12 to use plpython3u 2019-10-22 15:29:45 +02:00
Raul Marin
3b4669df11 Try hacking plpythonu -> plpython3u 2019-10-22 14:24:20 +02:00
Raul Marin
9f904b5926 plpython2 is dead, long live plpython 2019-10-22 14:10:14 +02:00
Raul Marin
4802501387 Travis: Test against PG12 2019-10-22 11:59:42 +02:00
Raul Marin
b68ce72889 Release 0.31.0 2019-10-08 12:47:32 +02:00
Raúl Marín
7a23ea815c Merge pull request #371 from Algunenano/sec_definer
Sec definer
2019-10-08 12:32:26 +02:00
Raul Marin
2533d0996c Add NEWs 2019-10-03 18:59:01 +02:00
Raul Marin
048234cd80 CDB_Groups_API: Secure search_path 2019-10-03 18:58:27 +02:00
Raul Marin
5a12033609 Adapt tests to changes 2019-10-03 18:58:27 +02:00
Raul Marin
a580bedefc Set safe schema on some functions 2019-10-03 18:58:27 +02:00
Raul Marin
0e891eff7f Remove cartodb from search path
All calls to the extension functions should, and are,
be properly qualified, so there is no need to keep
the cartodb schema in the search_path
2019-10-03 18:58:27 +02:00
Raul Marin
52b3290d26 CDB_TableMetadata: Use secure search_path 2019-10-03 18:58:27 +02:00
Raul Marin
186ee37a57 CDB_Username: Set secure search_path 2019-10-03 18:58:27 +02:00
Raul Marin
0898881470 Oauth: Set secure search_path 2019-10-03 18:58:27 +02:00
Raul Marin
4dfd71639a CDB_OAuthReassignTableOwnerOnCreation: Use CDB_Conf_GetConf
Instead of accessing the cdb_conf table directly
2019-10-03 18:58:27 +02:00
Raul Marin
c6b90aac8a GhostTables: Set secure search_path 2019-10-03 18:58:27 +02:00
Raúl Marín
8a87f96f04 Merge pull request #370 from Algunenano/ghost_matview
Ghost tables: Add missing tags
2019-10-03 15:06:11 +02:00
Raul Marin
7c10fcc363 Update NEWS 2019-10-01 11:03:53 +02:00
Raul Marin
2f178bd89e _CDB_SetUp_User_PG_FDW_Server: Minor log changes 2019-10-01 11:02:34 +02:00
Raul Marin
32489c4eab Ghost tables: Add missing tags
- Add materialized views commands.
- Add missing alter trigger.
- Add 'IMPORT FOREIGN SCHEMA' since it might create new tables.
- Add 'DROP EXTENSION' and 'DROP TYPE' since they alter table columns.
- Add 'DROP SCHEMA' and 'DROP SERVER' as they drop tables.
2019-10-01 11:02:34 +02:00
Rafa de la Torre
afa52aa92b Prepare release 0.30.0 2019-07-17 09:58:21 +02:00
Rafa de la Torre
746dbea434 Merge pull request #369 from CartoDB/user-defined-fdw
User defined FDW's
2019-07-17 09:52:23 +02:00
Rafa de la Torre
f9bd469ea9 Make oauth tests a bit more robust 2019-07-17 09:46:49 +02:00
Rafa de la Torre
402d97daa6 Merge remote-tracking branch 'origin/master' into user-defined-fdw 2019-07-17 09:18:35 +02:00
Rafa de la Torre
e41d2ec019 Add a flag to force drop of user FDW and related objects
If force = true then it will add the subclause `CASCADE` to the SQL
DDL sentences that support it, otherwise it'll use `RESTRICT` which is
the default and exact opposite.
2019-07-16 17:40:05 +02:00
Rafa de la Torre
3c460f1a85 Add a bunch of RAISE NOTICE's to inform user about progress 2019-07-16 17:03:23 +02:00
Rafa de la Torre
076207c49c Make sure there are no (double)escaping issues 2019-07-16 16:24:02 +02:00
Rafa de la Torre
ce1e9ac41c Prefix all objects created with cdb_fdw_
Build the DB objects related to a user FDW with the following form:
`cdb_fdw_name`. This is aimed at easily inspect and filter them.

As requested in code review.
2019-07-16 15:35:35 +02:00
Rafa de la Torre
0f33ee8b22 Prepend an underscore (_) to functions meant to be run by superuser
_CDB_SetUp_User_PG_FDW_Server and _CDB_Drop_User_PG_FDW_Server are
meant to be executed by a superuser. Therefore they shouldn't be
considered part of the public API and hence the _CDB_Private_Function
naming convention.
2019-07-16 14:32:32 +02:00
Rafa de la Torre
a32dea0282 Remove SECURITY DEFINER from user-defined FDW's 2019-07-16 13:26:03 +02:00
Rafa de la Torre
3a255df9d0 Rename PG-FDW's-specific functions to _PG_FDW_
As per review comment.
2019-07-16 13:14:11 +02:00
Rafa de la Torre
c4e2549dc8 A few more permissions tests for completeness 2019-07-15 18:14:23 +02:00
Rafa de la Torre
2e9f642378 Check when users shall not have permissions to the FDW 2019-07-15 17:32:48 +02:00
Rafa de la Torre
99096d41e0 Drop the role when dropping a user-defined FDW 2019-07-15 17:25:48 +02:00
Rafa de la Torre
3a10ef7e76 Add ability to grant fdw role to org members 2019-07-15 16:54:23 +02:00
Rafa de la Torre
a20676f391 Add a test/example of granting the fdw role 2019-07-15 16:19:06 +02:00
Rafa de la Torre
37004db047 Add new function to drop a user-defined foreign server 2019-07-15 16:14:07 +02:00
Rafa de la Torre
1189d70b2a Request host auth to use password
This is required for non superusers to use FDW's. See
https://www.postgresql.org/docs/11/postgres-fdw.html#id-1.11.7.42.10
2019-07-15 14:52:39 +02:00
Rafa de la Torre
8cfc8e65cf Test with a regular user (non-superadmin) 2019-07-15 14:44:21 +02:00
Gonzalo Riestra
32db4fd81e Merge pull request #367 from CartoDB/oauth_create_table_trigger
Oauth create table trigger
2019-07-15 13:43:08 +02:00
Gonzalo Riestra
a1e3e9a8df update news 2019-07-15 13:42:43 +02:00
Rafa de la Torre
6e34e16b8d Add basic test for user-defined FDW's 2019-07-15 13:16:14 +02:00
Rafa de la Torre
70220e04c1 Allow for imports of tables in different source schemas 2019-07-15 13:13:21 +02:00
Gonzalo Riestra
a5cb9f268d reassign ownership for sequences and functions as well 2019-07-15 12:31:44 +02:00
Rafa de la Torre
d2d909145d Add convenience function to import fdw tables 2019-07-12 16:53:34 +02:00
Rafa de la Torre
34dec227c4 Rename to CDB_SetUp_User_Foreign_Server 2019-07-12 16:53:34 +02:00
Rafa de la Torre
99e92e2505 Create a "PUBLIC" user mapping 2019-07-12 16:53:34 +02:00
Rafa de la Torre
c58a084102 Tweak ownership of db objects 2019-07-12 16:53:34 +02:00
Rafa de la Torre
b7907ff82f Fix typo granting perms 2019-07-12 16:53:34 +02:00
Rafa de la Torre
12d955075a Fix bug iterating user_mapping options 2019-07-12 16:53:34 +02:00
Rafa de la Torre
10a4d85c01 Fix typo in example: missing closing } 2019-07-12 16:53:24 +02:00
Rafa de la Torre
524bb6ad42 Fix copy/paste typos 2019-07-12 12:49:59 +02:00
Rafa de la Torre
4da89d8abd First version of the function WIP 2019-07-12 12:40:02 +02:00
Rafa de la Torre
c7311ba48e A stub of a convenient FDW function 2019-07-12 12:00:30 +02:00
Gonzalo Riestra
2eae7876e2 fix makefile 2019-07-12 08:38:21 +02:00
Mario de Frutos Dieguez
91c3b86d45 Updated NEWS and tests README 2019-07-04 17:53:11 +02:00
Mario de Frutos Dieguez
f55d789c41 Make some tests to have different expects for different PG versions 2019-07-04 17:48:01 +02:00
Mario de Frutos Dieguez
3eb8ab24d8 Improved tests 2019-07-04 17:48:01 +02:00
Mario de Frutos Dieguez
0f1c98c743 Check for empty strings as well 2019-07-04 17:48:01 +02:00
Mario de Frutos Dieguez
8ecd2cd5e2 Reuser creator_role
Co-Authored-By: Alberto Romeu <alrocar@users.noreply.github.com>
2019-07-04 17:48:00 +02:00
Mario de Frutos Dieguez
f4be59cae0 Added tests 2019-07-04 17:48:00 +02:00
Mario de Frutos Dieguez
fe66b2865a Upgrade version to 0.29.0 2019-07-04 17:48:00 +02:00
Mario de Frutos Dieguez
2be9d2d81a Enable OAuth scripts 2019-07-04 17:47:36 +02:00
Mario de Frutos Dieguez
5744921065 OAuth functions
- Create/drop reassign event trigger and the function with the logic
- Function that reassings owner to ownership role if defined
2019-07-04 17:47:36 +02:00
Rafa de la Torre
4c93258cd2 Prepare release of 0.28.1 2019-07-04 16:09:53 +02:00
Javier Goizueta
bf140890d8 Merge pull request #365 from CartoDB/table-syncer-notmps
Sync tables without using temporary hash tables
2019-07-04 16:05:21 +02:00
Rafa de la Torre
29a31d4c40 Merge pull request #362 from CartoDB/fdw-affected-tables
Make CDB_Get_Foreign_Updated_At robust to missing CDB_TableMetadata
2019-07-04 16:02:46 +02:00
Javier Goizueta
dbd403a2f6 Fix cases of double-quoting identifiers 2019-07-04 12:47:58 +02:00
Javier Goizueta
cb353ec6a8 Add tests for quoted table & column names 2019-07-04 12:47:01 +02:00
Javier Goizueta
2beabfced6 Add test for double schema-quoting 2019-07-03 18:48:49 +02:00
Javier Goizueta
7bdee5c13e Avoid double-quoting
Since dst_schema is a REGNAMESPACE, it is automatically quoted when casted to TEXT
2019-07-03 18:34:54 +02:00
Javier Goizueta
c07784566a NEWS for next release 2019-07-03 17:02:36 +02:00
Javier Goizueta
2e1fe2933c Fix whitespace 2019-07-03 16:56:29 +02:00
Rafa de la Torre
d378ca6fe0 Test for missing foreign CDB_TableMetadata 2019-07-03 16:25:16 +02:00
Rafa de la Torre
446f4113d9 Return NULL instead of NOW()
The absence of foreign CDB_TableMetadata actually means that we cannot
really tell when a remote table was modified.

Therefore we're using NULL with the meaning of "I don't know when it
was last modified".

To be taken in other caching layers, to adjust headers accordingly.
2019-07-03 16:19:46 +02:00
Javier Goizueta
5963c67376 Order the columns of a cartodbfied table consistently
The final order of the columns of a cartodbfied table wasn't uniquely specified, so could vary across PG versions.
This was a problem in particular for having deterministic test results.
2019-07-03 16:16:37 +02:00
Javier Goizueta
f5f18ca57c Fix the order of the columns 2019-07-02 18:14:18 +02:00
Javier Goizueta
d8c840d126 Quote table and column names when necessary
Also use type NAME when appropriate. Note that quoted column names are not NAMES (may be longer).
2019-07-02 18:14:04 +02:00
Javier Goizueta
65483743b4 Remove unused vars 2019-07-02 17:44:06 +02:00
Javier Goizueta
4651883454 Fix order of test results 2019-07-02 17:43:13 +02:00
Javier Goizueta
470bae6268 Merge branch 'master' into table-syncer-notmps
# Conflicts:
#	scripts-available/CDB_SyncTable.sql
2019-07-02 12:21:49 +02:00
Javier Goizueta
75ba13b834 Merge pull request #364 from CartoDB/synctable-doc
Document CDB_SyncTable
2019-07-02 10:20:24 +02:00
Javier Goizueta
057695361d Fix typo 2019-07-01 17:49:42 +02:00
Javier Goizueta
0e1aeb0a76 Minor copy edit 2019-07-01 17:00:22 +02:00
Javier Goizueta
f2dae651b3 More complete sync table example 2019-07-01 16:58:24 +02:00
Javier Goizueta
9f414938ba Document CDB_SyncTable 2019-07-01 16:41:40 +02:00
Javier Goizueta
4f7b07f922 Merge pull request #363 from CartoDB/fix-sync-schema
Fix cartodb schema references
2019-07-01 16:15:25 +02:00
Javier Goizueta
69cc56b589 Remove schema from public function examples 2019-07-01 15:13:48 +02:00
Javier Goizueta
1028b24333 Fix cartodb schema references 2019-07-01 14:48:42 +02:00
Javier Goizueta
4d1c4f6a22 Release 0.28.0 2019-07-01 10:56:06 +02:00
Javier Goizueta
83ab128a01 Merge pull request #355 from CartoDB/table-syncer
[WIP] Table syncer
2019-07-01 10:49:06 +02:00
Rafa de la Torre
b0b4a92240 Add a test case for missing foreign CDB_Tablementadata 2019-06-28 16:19:57 +02:00
Rafa de la Torre
c06d24aa19 Make CDB_Get_Foreign_Updated_At robust to missing CDB_TableMetadata
This may happen with non-carto DB's, when checking the updated_at
times and not finding the corresponding remote.cdb_tablemetadata
imported from the foreign non-carto DB.

Instead of failing, return a NOW() timestampt, so that caching logic
just assumes there may have been changes.

This makes it work today, and leaves open the possibility of adding
the required carto metadata for homogeneous caching in the future.
2019-06-28 16:25:52 +02:00
Javier Goizueta
4f4df2de8d Merge branch 'table-syncer' into table-syncer-notmps 2019-06-28 15:28:06 +02:00
Javier Goizueta
b5f36902c5 Merge branch 'master' into table-syncer 2019-06-28 13:50:46 +02:00
Javier Goizueta
0bcbf6708a Remove usage of temporary tables 2019-06-28 13:49:15 +02:00
Gonzalo Riestra
2e665a56b4 release 0.27.2 2019-06-21 09:19:04 +02:00
Gonzalo Riestra
1e8ef2e1d9 Merge pull request #360 from CartoDB/fix-ghost-tables-trigger
Improve Ghost Tables functions
2019-06-21 09:15:20 +02:00
Gonzalo Riestra
e6ecde4346 add CREATE/ALTER/DROP FOREIGN TABLE to ddl commands 2019-06-20 11:20:48 +02:00
Gonzalo Riestra
2d42e6197a use bigint to store values from txid_current() 2019-06-20 11:20:03 +02:00
Gonzalo Riestra
5605fdd9b2 fix event trigger 2019-06-19 15:27:28 +02:00
Sergio Conde Gómez
ab7082d4c3 Merge pull request #359 from CartoDB/fix_carto-package
Fix carto-package requirements to be SemVer compliant
2019-06-17 13:40:35 +02:00
Sergio Conde Gomez
f9ac627e0e Fix carto-package requirements to be SemVer compliant 2019-06-17 13:33:24 +02:00
Raul Marin
cc2066ea89 Release 0.27.1 2019-06-03 17:57:42 +02:00
Raúl Marín
aa380171b4 Merge pull request #358 from Algunenano/missing
Add missing qualifications
2019-06-03 16:26:10 +02:00
Raul Marin
a43abb37e0 Add missing qualifications 2019-06-03 15:22:52 +02:00
Raul Marin
787b513715 Release 0.27.0 2019-06-03 12:51:25 +02:00
Raúl Marín
362af5e6a0 Merge pull request #357 from Algunenano/full_schema_rebase
Qualify all function calls
2019-06-03 12:45:04 +02:00
Raul Marin
8dbd797429 Update CONTRIBUTING.md 2019-06-03 12:31:06 +02:00
Raul Marin
57ac26cbe7 Travis: Add PG 9.6 to the test matrix 2019-05-31 16:26:07 +02:00
Raul Marin
010cbe6e18 Remove unnecessary changes 2019-05-31 15:52:55 +02:00
Raul Marin
8e68f2a0a7 Add NEWS 2019-05-31 15:38:29 +02:00
Raul Marin
52aab9d564 Raise minimum requirement to Postgis 9.6 2019-05-31 15:37:15 +02:00
Raul Marin
06f563bb73 Tests: Only create publicuser if necessary
Also, don't try to drop it since it's used by default
CARTO installation
2019-05-31 15:37:15 +02:00
Raul Marin
78077a6ec1 Bash tests improvements
- Stop loading sql files manually.
- Make tests independent.
- Single DB setup (not once per test)
2019-05-31 15:37:15 +02:00
Raul Marin
c45ef6c540 Fully qualify function calls 2019-05-31 15:37:15 +02:00
Rafa de la Torre
42dc03d77b Qualify functions with extension schema
This avoids some issues with search_path and scripting black magic.
2019-05-30 16:56:12 +02:00
Rafa de la Torre
9254723719 Make format expression more readable
Make an EXECUTE format('', param1, ..., paramN) more readable by
adding the index of the argument to print (`position`) in the format
specifier.
2019-05-29 13:13:30 +02:00
Rafa de la Torre
26ad966ab6 Add some timing info 2019-05-28 16:40:01 +02:00
Rafa de la Torre
a2723a3c90 Exclude certain columns from sync if instructed to do so
For the Geocoding (and in general for LDS use cases) it may come in
handy to exclude geometry columns from the list of stuff to
syncrhonize. Otherwise they may be lost, overwritten with NULL values.
2019-05-28 16:11:56 +02:00
Rafa de la Torre
2f8ea7e4ea Avoid tables name clashing when executing within same transaction
Generate more unique temp table names when the CDB_SyncTable function
is executed multiple times within the same transaction.

When executed in isolation, there will be always an implicit
surrounding transaction.

But when executed several times within the same transaction it can
give an `ERROR:  relation "src_sync_718794" already exists`.

E.g:

```
BEGIN;
SELECT cartodb.CDB_SyncTable('source1', 'public', 'dest1');
SELECT cartodb.CDB_SyncTable('source12, 'public', 'dest2');
COMMIT;
```
2019-05-28 15:39:02 +02:00
Rafa de la Torre
45c21d7f42 Make other tests resilient to CDB_SyncTable test failures
Use a transaction to avoid leaving stuff after our tests, that affect
Quota and User Tables tests.
2019-05-28 15:33:55 +02:00
Rafa de la Torre
f442c21fa4 Fix the test/CDB_AnalysisCheckTest.sql
These tests are failing in PG11:

```
*** /home/travis/build/CartoDB/cartodb-postgresql/expected/test/CDB_AnalysisCheckTest.out	2019-05-27 16:09:45.063543994 +0000
--- /home/travis/build/CartoDB/cartodb-postgresql/results/test/CDB_AnalysisCheckTest.out	2019-05-27 16:12:39.770847666 +0000
***************
*** 5,12 ****
  CREATE TABLE
  CREATE TABLE
  CREATE TABLE
- (analysis_2f13a3dbd7_41bd92976fc6dd97072afe4ee450054f4c0715d5,public,analysis_2f13a3dbd7_41bd92976fc6dd97072afe4ee450054f4c0715d5)
  (analysis_2f13a3dbd7_f00cee44e9e6152b450bde3a92eb9ae0d099da94,public,analysis_2f13a3dbd7_f00cee44e9e6152b450bde3a92eb9ae0d099da94)
  0

  1
--- 5,12 ----
  CREATE TABLE
  CREATE TABLE
  CREATE TABLE
  (analysis_2f13a3dbd7_f00cee44e9e6152b450bde3a92eb9ae0d099da94,public,analysis_2f13a3dbd7_f00cee44e9e6152b450bde3a92eb9ae0d099da94)
+ (analysis_2f13a3dbd7_41bd92976fc6dd97072afe4ee450054f4c0715d5,public,analysis_2f13a3dbd7_41bd92976fc6dd97072afe4ee450054f4c0715d5)
  0

  1
```

The reason for that is that they rely on row ordering that cannot be
guaranteed as per SQL Standard. Forcing that assumed ordering is
enough to get it working again.
2019-05-28 09:34:10 +02:00
Rafa de la Torre
ee9d08a2be Some functional E2E tests for the CDB_SyncTable() function 2019-05-27 17:56:36 +02:00
Rafa de la Torre
7606585672 Perf optimization: use EXCEPT instead of NOT IN
With javitonino's help, greatly reduce the processing time by using
EXCEPT instead of NOT IN, which causes it to use a `HashSetOp Except`
plan on the subqueries rather than a `Seq Scan` on `Materialize`'d
subtables.
2019-05-27 15:20:06 +02:00
Rafa de la Torre
81d0f338cf Create HASH indices on the temp tables 2019-05-27 15:18:13 +02:00
Rafa de la Torre
951f257654 Simplify code by using ON COMMIT DROP
Simplify code by relying on automatic removal of temp tables with ON
COMMIT DROP, so that we avoid the messy EXCEPTION management.
2019-05-27 12:02:12 +02:00
Rafa de la Torre
f461faf0b6 Simplify udpate: use * instead of column list 2019-05-27 11:56:41 +02:00
Rafa de la Torre
a8d57abda6 Update changed rows 2019-05-27 11:54:38 +02:00
Rafa de la Torre
982ddfdeff Helper function to generate UPDATE SET clause 2019-05-27 11:31:07 +02:00
Rafa de la Torre
da4331ac78 WIP: A function to sync tables
It assumes there's a cartodb_id column in both source and target. It
does not perform unnecessary actions. It respects augmented columns in
target table, if they exist. It is meant to be efficient.
2019-05-24 18:38:28 +02:00
Gonzalo Riestra
07d43275f8 Merge pull request #354 from CartoDB/update-readme
Add Redis dependency to Readme
2019-05-23 10:58:33 +02:00
Gonzalo Riestra
ec38444b7d better link 2019-05-23 08:12:57 +02:00
Gonzalo Riestra
ee9010dc23 add redis module to dependencies in readme 2019-05-23 08:03:37 +02:00
Gonzalo Riestra
74210c5b5c release 0.26.1 2019-03-19 17:43:36 +01:00
Gonzalo Riestra
d14d1d9994 Merge pull request #351 from CartoDB/remove_default_tis_config
Remove default TIS config in Ghost Table function
2019-03-14 12:23:06 +01:00
Gonzalo Riestra
5b19d0fc5e fix test correctly 2019-03-14 12:08:33 +01:00
Gonzalo Riestra
2baee24f30 fix test 2019-03-14 11:47:41 +01:00
Gonzalo Riestra
85d6164956 add log when there is no tig config 2019-03-14 11:39:10 +01:00
Gonzalo Riestra
a5b2b66bb6 fix test comment 2019-03-14 10:06:04 +01:00
Gonzalo Riestra
3faa389860 improve logs 2019-03-13 18:16:08 +01:00
Gonzalo Riestra
bc5d532735 remove default TIS config 2019-03-13 18:12:48 +01:00
Gonzalo Riestra
4f3d19ce7a Merge pull request #350 from CartoDB/explicit-schema-for-ghost-tables
Add explicit schema for Ghost Tables functions
2019-03-13 10:42:13 +01:00
Gonzalo Riestra
45fed9cf1b more explicit schemas 2019-03-13 10:29:50 +01:00
Gonzalo Riestra
e19489144c simplify queries 2019-03-13 09:08:13 +01:00
Gonzalo Riestra
83707297de add explicit schema for all functions 2019-03-12 18:39:48 +01:00
Gonzalo Riestra
2f40261b8d Merge pull request #349 from CartoDB/ghost_tables
Ghost tables functions
2019-03-11 15:29:17 +01:00
Gonzalo Riestra
b1202011f6 update news 2019-03-11 15:28:48 +01:00
Gonzalo Riestra
65d51fd8bd move cdb_ddl_execution table creation/drop to functions 2019-03-11 14:02:45 +01:00
Gonzalo Riestra
1a271d977b bump version 2019-03-11 12:24:14 +01:00
Gonzalo Riestra
9c6294d95b move trigger drop/creation inside functions 2019-03-11 11:28:45 +01:00
Gonzalo Riestra
c7bba14e9a simplify code 2019-03-11 09:20:05 +01:00
Gonzalo Riestra
667f896cfb add again views to the trigger 2019-03-08 13:21:11 +01:00
Gonzalo Riestra
cc1df0a708 use redis module version from carto 2019-03-08 13:01:56 +01:00
Gonzalo Riestra
d1ee383d9b add redis module for python to travis 2019-03-08 12:50:51 +01:00
Gonzalo Riestra
a794fb3d31 read tis config from cdb_conf 2019-03-08 12:03:55 +01:00
Gonzalo Riestra
50e41179fc fix test 2019-03-08 09:18:46 +01:00
Gonzalo Riestra
e3138cd56a make enable/disable trigger idempotent 2019-03-08 08:43:22 +01:00
Gonzalo Riestra
ab6720ad32 add create/drop/alter view to the trigger 2019-03-08 08:28:24 +01:00
Gonzalo Riestra
5f154a5859 use TIS instead of Redis 2019-03-08 08:28:06 +01:00
Gonzalo Riestra
99dd7cefc7 ghost tables functions using redis 2019-03-06 18:20:04 +01:00
Raúl Marín
85997e2445 Merge pull request #348 from Algunenano/shiftLongitude
Update ST_Shift_Longitude to ST_ShiftLongitude
2019-03-01 12:06:24 +01:00
Raul Marin
1bd4b9a6e3 Update NEWS 2019-03-01 11:47:30 +01:00
Raul Marin
5d4f1d98d7 Update ST_Shift_Longitude to ST_ShiftLongitude 2019-03-01 11:27:09 +01:00
Gonzalo Riestra
1637257772 Merge pull request #346 from CartoDB/username
Add CDB_Username function
2019-02-22 09:20:47 +01:00
Gonzalo Riestra
a904b101a3 update news 2019-02-22 08:39:17 +01:00
Javier Torres
917a975baa Tabs vs spaces 2019-02-21 15:20:24 +01:00
Gonzalo Riestra
0568b36a90 use session_user instead of current_user 2019-02-20 14:45:57 +01:00
Gonzalo Riestra
6d122462bb decouple tests from cartodb 2019-02-20 13:34:11 +01:00
Gonzalo Riestra
ffaf5e4400 Bump to 0.25.0 2019-02-20 10:38:16 +01:00
Gonzalo Riestra
2a4ecd4850 Add CDB_Username() function 2019-02-20 10:38:00 +01:00
Raul Marin
3f4479fe12 Release 0.24.1 2019-01-03 14:46:11 +01:00
Raúl Marín
34032964c0 Merge pull request #344 from Algunenano/recover_hooks
Recover hooks
2019-01-03 14:28:00 +01:00
Raul Marin
6c57751579 CDB_TransformToWebmercator: Yet another hack over a function that shouldn't exist 2019-01-02 19:33:28 +01:00
Raul Marin
9a3ac908a9 Test with PG11 2019-01-02 19:01:30 +01:00
Raul Marin
80fdd00541 Drop functions removed in 0.11.1 2019-01-02 18:56:24 +01:00
Raul Marin
aeec2bbe06 Release 0.24.0 2018-09-13 10:29:24 +02:00
Raúl Marín
5033a0ba35 Merge pull request #340 from Algunenano/trav_jenkins
Improvements in `CDB_JenksBins`
2018-09-13 10:24:41 +02:00
Raul Marin
d2a00852a8 Jenks: Iterate increasing the number of moved elements exponentially 2018-09-11 19:22:48 +02:00
Raul Marin
7e131ac88d Jenks: Add test for less data than breaks 2018-09-10 16:15:02 +02:00
Raul Marin
e374b9128f Add NEWS 2018-09-10 16:12:54 +02:00
Raul Marin
e605234d38 Jenks: Remove log messages 2018-09-10 15:53:02 +02:00
Raul Marin
272d5be776 Jenks: Add inverse request test 2018-09-10 15:42:54 +02:00
Raul Marin
0e7d797400 Jenks: Fix multiple bugs 2018-09-10 15:42:35 +02:00
Raul Marin
fcc06e82bf Jenks: Force valid tests 2018-09-10 13:16:25 +02:00
Raúl Marín
60a21d34bf Merge pull request #339 from Algunenano/update_travis
Update travis +  _cdb_estimated_extent fix
2018-09-05 17:42:18 +02:00
Raul Marin
74f939fd53 CDB_OverviewsTest: Run analyze for consistency 2018-09-04 18:22:22 +02:00
Raul Marin
7e131143f9 _cdb_estimated_extent: Adapt to ST_EstimatedExtent change
The behaviour was changed in Postgis 1.5.4 to return NULL instead of throwing
2018-09-04 18:21:28 +02:00
Raul Marin
ac15a6da25 Test: Update CDB_GreatCircle_expect for Postgis 2.4 2018-09-04 17:25:22 +02:00
Raul Marin
c0a7714f33 Travis: Test with Postgresql 9.5 and 10, and Postgis 2.4 2018-09-04 17:25:03 +02:00
Javier Torres
0c864694b6 Merge pull request #338 from CartoDB/naming-fixes
Update carto-package.json
2018-08-20 15:30:38 +02:00
Alejandro Guirao Rodríguez
4b246d34c8 PostGIS uses 4 numbers 2018-08-17 10:48:21 +02:00
Alejandro Guirao Rodríguez
87454ac37f Update carto-package.json 2018-08-17 10:21:50 +02:00
Javier Torres
e3837c603d Merge pull request #337 from CartoDB/carto_package_json
Created carto-package.json
2018-08-14 16:28:58 +02:00
Javier Torres
e84832b7f4 Created carto-package.json 2018-08-10 14:20:23 +02:00
Eneko Lakasta
b209726b1c Merge pull request #320 from bloomberg/v0_18_5/cdb_tablemetadata_text_hotfix
Fix incorrect timestamps in CDB_TableMetadata_Text
2018-07-23 16:00:19 +02:00
Javier Torres
51a669f93c Release 0.23.2 2018-07-20 14:15:05 +02:00
Javier Torres
c8a1119556 Merge pull request #335 from CartoDB/s1669-sql_api_injection_query_tables
Don't rely on regexp to identify non explainable queries
2018-07-20 14:12:59 +02:00
Javier Torres
24a37be1a9 Change querytables expect test 2018-07-20 13:22:02 +02:00
Javier Torres
5659275c0c Don't rely on regexp to identify non explainable queries 2018-07-20 13:01:51 +02:00
Javier Goizueta
7760d6b30d Release 0.23.1 2018-07-19 17:11:56 +02:00
Javier Goizueta
4515c8547e Merge pull request #334 from CartoDB/333-parallel-unsafe
Fix PARALLEL tags
2018-07-19 16:57:22 +02:00
Javier Goizueta
2766bbc83a Fix PARALLEL tags
Fixes #333
2018-07-18 12:13:31 +02:00
Rafa de la Torre
c4980a90f9 Merge pull request #332 from CartoDB/cdb-table-exists
Cdb table exists
2018-07-03 15:45:17 +02:00
Rafa de la Torre
61d2024eb5 Make the code nicer by avoiding IF/THEN/ELSE
As suggested by Algunenano.
2018-07-03 15:35:05 +02:00
Rafa de la Torre
af142306aa Mark _CDB_Table_Exists() as PARALLEL UNSAFE
As pointed out by Algunenano, PL/pgSQL function which establishes an
EXCEPTION block to catch errors must be qualified with it.
2018-07-03 15:26:48 +02:00
Rafa de la Torre
7437a9686b Use a more suitable version number 0.23.0 & NEWS
Use a better version number (as it adds a new function) and update
NEWS.md accordingly.
2018-07-03 15:08:34 +02:00
Rafa de la Torre
82f90e618c Use CREATE OR REPLACE FUNCTION 2018-07-03 13:04:39 +02:00
Rafa de la Torre
55a77b0ef0 Add a new helper function _CDB_Table_Exists 2018-07-03 13:00:24 +02:00
Javier Torres
2e68626165 Merge pull request #331 from CartoDB/fix_0_22_1_hyphens
Fix 0 22 1 hyphens
2018-05-31 17:36:09 +02:00
Javier Torres
06b7eb8504 Bump to 0.22.2 2018-05-31 17:06:47 +02:00
Javier Torres
ccbabaa3b4 Missing quote idents 2018-05-31 17:06:39 +02:00
Javier Torres
0da36eab44 Bump to 0.22.1 2018-05-29 17:10:37 +02:00
Javier Torres
7f5bef1203 Escape regclass call with quote_ident 2018-05-29 14:04:53 +02:00
Javier Torres
625d62c448 Remove unneeded variable 2018-05-28 20:29:36 +02:00
Javier Torres
f06418c99b Extract sequence-listing function 2018-05-28 20:14:57 +02:00
Javier Torres
1958f2de5b Working code to add permission to all table sequences 2018-05-28 20:07:16 +02:00
Javier Torres
c19c88c9e0 Test for granting permissions for table with non-seria lcartodb_id 2018-05-28 19:54:19 +02:00
Javier Torres
716f47edae We should be able to grant permission to non-cartodbfied tables 2018-05-28 19:46:58 +02:00
Andy Eschbacher
cd83ee21bb Merge pull request #329 from CartoDB/update-readme-pg-version
updates pg version based on cdb_quantiles update
2018-05-07 10:13:36 -04:00
Andy Eschbacher
d98ae59535 updates pg version based on cdb_quantiles update 2018-04-25 09:09:55 -04:00
Mario de Frutos
a2e99ac533 Merge pull request #327 from CartoDB/test_for_325
Added test for the case that arose in #325
2018-03-22 12:02:47 +01:00
Mario de Frutos
da5d3ea8d9 Added test for the case that arose in #325 2018-03-22 11:53:50 +01:00
Mario de Frutos
fed64e4850 Update NEWS.md 2018-03-21 17:20:21 +01:00
Mario de Frutos
9959581b7a Merge pull request #326 from CartoDB/325_fix_seq_error
Fixed a trucate problem with the seq rename
2018-03-21 17:14:57 +01:00
Mario de Frutos
c9f4685e5d Fix error with hyphens, moving logic to the Format part 2018-03-21 16:33:05 +01:00
Mario de Frutos
f96c334f48 Fixed a trucate problem with the seq rename. See #325 2018-03-21 12:05:56 +01:00
Mario de Frutos
04dc39bb16 Merge pull request #316 from CartoDB/quantiles-bins-updates
Updates quantile bins to use native PostgreSQL precentile functions
2018-03-19 13:09:13 +01:00
Mario de Frutos
0a6f263106 Bump version to 0.22.0 2018-03-14 12:14:50 +01:00
Andy Eschbacher
697a0a3a36 Merge branch 'master' into quantiles-bins-updates 2018-03-12 09:50:01 -04:00
Paul Ramsey
7559151ab5 Merge pull request #319 from CartoDB/seq-drop
Sequence Rename to avoid Collision. Helps interop with older ogr2ogr.
2018-03-09 10:00:59 -08:00
Paul Ramsey
2c62730301 News entry for this fix 2018-03-09 10:00:10 -08:00
Paul Ramsey
62c27ab140 Merge branch 'master' of github.com:CartoDB/cartodb-postgresql into seq-drop 2018-03-09 09:58:25 -08:00
Andy Eschbacher
17c872ed61 changes version number 2018-03-08 11:02:19 -05:00
Andy Eschbacher
6714feea8f updates news 2018-03-08 10:38:03 -05:00
Andy Eschbacher
b6b0ef704a Merge branch 'master' into quantiles-bins-updates 2018-03-08 10:33:01 -05:00
Andy Eschbacher
39998a9c88 fix syntax error oof oof 2018-03-08 10:21:43 -05:00
Andy Eschbacher
cf38d4cf25 oof include SELECT 2018-03-08 10:14:08 -05:00
Andy Eschbacher
0467c075f7 opts for array version of percentile_disc 2018-03-08 10:00:52 -05:00
Javier Goizueta
c1c55bf59f Release 0.21.0 2018-02-15 17:22:42 +01:00
Javier Goizueta
0a58c05049 Merge pull request #323 from CartoDB/321-grant-sequence
grant usage on cartodb_id sequence when sharing read write
2018-02-15 16:29:25 +01:00
Javier Goizueta
81f2fad3ad Merge pull request #322 from CartoDB/max-grid-size
Add limit to the grid-generating functions
2018-02-15 16:09:12 +01:00
Javier Goizueta
0a0f2e294b Fix tests 2018-02-15 10:27:19 +01:00
Alberto Romeu
cd4653ecc0 grant usage on cartodb_id sequence when sharing read write 2018-02-15 08:40:17 +01:00
Javier Goizueta
7ea428913a Add limit to the grid-generating functions
This adds an optinal maxcells parameter to the rectangle and hexagonal grids,
with a default value of 262144 (2^18).
An error occurs when the grids would need more cells.
2018-02-14 17:50:06 +01:00
Tyler Parsons
5c86029029 Test for correct timestamps in cdb_tablemetadata_text 2018-01-25 23:08:28 -05:00
Tyler Parsons
acd101af9b Use PGPORT as fdw port if specified 2018-01-25 23:08:12 -05:00
Tyler Parsons
d811a71da0 Fix incorrect timestamps in CDB_TableMetadata_Text
Instead of performing a proper join on tabname, CDB_TableMetadata_Text joins
cdb_tablemetadata against pg_catalog.pg_class (i.e. All postgres tables,
views, indices, etc.) and gives a record for every possible tabname and
updated_at combination.  This results in the latest updated timestamp being
chosen for any table in CDB_Get_Foreign_Updated_At, which leads to unnecessary
and incorrect cache invalidation.
2018-01-25 12:27:38 -05:00
Paul Ramsey
4050555801 Quiet errors where there's no existing sequence 2018-01-18 10:26:01 -08:00
Paul Ramsey
e4b0e7ea7a Make user final seq has the right desired name 2018-01-18 10:06:38 -08:00
Paul Ramsey
a79c2cb7a8 draft tweek on seq handling 2018-01-18 09:27:46 -08:00
Andy Eschbacher
dbaf795a79 adjust expectation to reality instead of expectation (added TODOs) 2017-12-06 08:18:24 -05:00
Andy Eschbacher
4b937de415 updates JenksTests to reflect expectations without nulls 2017-12-06 08:10:09 -05:00
Andy Eschbacher
2fe02d8154 fix alias of column 2017-12-05 16:24:11 -05:00
Andy Eschbacher
691b9a8312 moves quantile bins to use postgres precentile functions 2017-12-05 16:16:39 -05:00
Raul Marin
5243192296 Change sed in-place for tmpfiles 2017-11-14 15:57:40 +01:00
Raul Marin
8131887204 Release version 0.20.0 2017-11-13 09:35:20 +01:00
Raul Marin
36550440bf Update CONTRIBUTING with information about function labels 2017-11-13 09:35:20 +01:00
Raul Marin
9d980ab17c Mark CDB_JenksBins as VOLATILE as it uses random 2017-11-13 09:35:20 +01:00
Raul Marin
72c214a8e4 Fix regex for PARALLEL aggregations
Worked in pg10, but it didn't in pg9.5
2017-11-13 09:35:20 +01:00
Raul Marin
0f7a1c4882 Remove PARALLEL mode in older versions (up to 9.6) 2017-11-13 09:35:20 +01:00
Raul Marin
0abc2ba250 Add PARALLEL parameter to functions 2017-11-13 09:35:20 +01:00
Raul Marin
f24d15f6ca Fix issues when running under pg10 2017-10-25 14:38:06 +02:00
Raul Marin
386eccdda2 Travis: Set dist as Ubuntu Precise 2017-10-24 15:12:24 +02:00
Rafa de la Torre
5d43faecaf Release version 0.19.2 2017-06-30 15:04:35 +02:00
Rafa de la Torre
acbaf634dc Merge pull request #306 from CartoDB/305-fix-unique-identifiers
305 fix unique identifiers
2017-06-30 15:00:49 +02:00
Rafa de la Torre
c379946c95 Update dependencies of travis script #305 2017-06-30 12:52:26 +02:00
Rafa de la Torre
711c954d1a Fix evil tests #305
Basically force generation of long name identifiers that conflict
with first choice of another unique identifier.
2017-06-29 18:53:26 +02:00
Rafa de la Torre
ffb779eb74 Increase search space of ids by 100x #305 2017-06-29 17:54:42 +02:00
Rafa de la Torre
8db73ae9bd Add test for faulty use case #305 2017-06-29 17:53:43 +02:00
Mario de Frutos
208ebb2724 Update NEWS.md for version 0.19.1 2017-06-05 11:20:38 +02:00
Mario de Frutos
951ec51968 Merge pull request #302 from CartoDB/regenerate_overviews_deadlock
Regenerate overviews deadlock
2017-06-05 11:17:14 +02:00
Mario de Frutos
8a3d506a53 Add some debug logs to be used in the future 2017-06-02 15:41:18 +02:00
Mario de Frutos
c839f74c63 Fixed travis shield 2017-06-02 15:30:19 +02:00
Mario de Frutos
8389b39c00 Bump new version 2017-06-02 15:23:47 +02:00
Mario de Frutos
4908bacc4b If existing overviews we regenerate them
Instead of make a DROP/CREATE always, in case we have existing
overviews we have to make DELETE/INSERT because DDL operations require
AccessExclusiveLock which is not compatible with AccessShareLock that
is used by the queries used to gather data for the tiler.

This incompatibility above mentioned leads to have deadlocks
2017-06-02 15:23:47 +02:00
Mario de Frutos
38fa3b485c Remove unused and old _CDB_GridCluster_Reduce_Strategy function for overviews 2017-06-02 13:05:05 +02:00
Javier Goizueta
2d473cf693 New version 0.19.0 2017-04-11 11:22:20 +02:00
Javier Goizueta
4193ff3874 Merge pull request #298 from CartoDB/295-estimate-row-count
Add CDB_EstimateRowCount function
2017-04-11 11:01:31 +02:00
Javier Goizueta
68a0752849 Use PG 9.5 for travis tests; fix tests 2017-04-10 15:58:49 +02:00
Javier Goizueta
815b5b429d Fix tests 2017-04-10 13:50:37 +02:00
Javier Goizueta
76bdb3657a Fix tests 2017-04-10 12:17:47 +02:00
Javier Goizueta
234373df11 Replace unnecessary count 2017-04-10 08:08:59 +02:00
Javier Goizueta
a486eed2e3 Add CDB_EstimateRowCount function
See #295
2017-04-07 15:35:48 +02:00
Mario de Frutos
795d92da8d Added CLA paragraph 2017-01-25 10:54:12 +01:00
Javier Goizueta
58e2e7e238 Release 0.18.5 2016-11-30 17:17:45 +01:00
Javier Goizueta
25d27263cb Merge pull request #249 from CartoDB/nullbins
Test behavior of binning fuctions with nulls
2016-11-30 16:09:23 +01:00
Javier Goizueta
bbadcc838e Merge pull request #244 from CartoDB/equalbins
Convert CDB_EqualIntervalBins to a single SQL statement and add float version
2016-11-30 16:09:05 +01:00
Javier Goizueta
b1a0904c07 Merge pull request #181 from CartoDB/update_to_cdb_stats
Fix for division by zero error on empty or homogenous array
2016-11-30 16:08:40 +01:00
Javier Goizueta
399b680b41 Merge pull request #283 from CartoDB/157-test-fixes
Fix tests: race condition with publicuser #157
2016-11-30 16:08:21 +01:00
Javier Goizueta
7c0636c5f9 Merge pull request #290 from CartoDB/286-overview-strategies
Add point overview strategies
2016-11-30 11:46:29 +01:00
Javier Goizueta
f58f870457 Remove use of first aggregator in sample-cluster overviews strategy
This is not more efficient but the geometry now corresponds to the cartodb_id
and the dependency with custom aggregators (firt) is removed.
2016-11-29 14:08:08 +01:00
Javier Goizueta
a7c8dc04e3 Release 0.18.4
This just fixes the lack of migration path from 0.18.2
2016-11-04 16:25:03 +01:00
Javier Goizueta
90ee56eb35 Merge pull request #288 from CartoDB/fix-migration
Fix migration script generation
2016-11-04 16:22:56 +01:00
Javier Goizueta
1032737600 Fix migration script generation
In the 0.18.3 release the script to migrate from 0.18.2 was missing.
This will generate a new version 0.18.4 that when install will generate
scripts to migrate from all old versions to it, so it will be possible
to migrate existing users to 0.18.4 (but not to 0.18.3)
2016-11-04 16:19:06 +01:00
Javier Goizueta
24639713f1 Release 0.18.3
The exclusion of analysis cache tables size from the quota (#281)
was meant to be included in 0.18.0 but missed the release, so
it's being released in this version.
2016-11-03 16:13:57 +01:00
Javier Goizueta
fff7e926c9 Merge pull request #287 from CartoDB/fix-281-merge
Fix 281 merge
2016-11-03 16:09:02 +01:00
Javier Goizueta
7d7ecc06f5 Merge branch 'master' into fix-281-merge 2016-11-03 15:57:24 +01:00
Javier Goizueta
5992304b47 Add a couple of overview clustering strategies 2016-11-03 13:31:04 +01:00
Alejandro Martínez
5c52e7564f Release 0.18.2 2016-10-20 16:00:12 +02:00
Alejandro Martínez
0b7fbdc1cb Merge pull request #285 from CartoDB/reorder_analysis_catalog_columns
Move "username" column to the last position on analysis_catalog - fixes #276
2016-10-20 15:44:05 +02:00
Alejandro Martínez
0bfdeae147 Move "username" column to the last position on analysis_catalog - fixes #276
Due to the way it was first implemented, the "username" column would be
on a different position depending on if it was an extension upgrade or
a fresh install.

This caused problems with pg_dumping databases and restoring them.
pg_dump does not include the extension source (so this table's schema is
not included on the dump) but does include this contents, using a COPY
without column names by default and failing due to the order difference.

After this has run, all tables (whether updated or not) will have the
"username" column on the last position.
2016-10-20 14:30:02 +02:00
Rafa de la Torre
89b2999a80 Release 0.18.1 2016-10-19 13:00:56 +02:00
Rafa de la Torre
2080d6d422 Merge pull request #284 from CartoDB/analysis-quota-factor
Analysis quota factor
2016-10-19 12:57:57 +02:00
Rafa de la Torre
bc5e23b143 Replace qmax by nominal_quota
Since the analysis quota factor can be greater than 1, `qmax` can be a
misleading name. Thus the change in var name.
2016-10-19 12:41:19 +02:00
Rafa de la Torre
64fae71a37 Default factor for analysis size from 0.2 to 2
Change the default value for the factor of analysis tables size from 0.2
to 2. I also checked it is applied on the "nominal" user quota.
2016-10-19 12:36:57 +02:00
Rafa de la Torre
594543916d New version 0.18.0 2016-10-17 18:03:00 +02:00
Rafa de la Torre
aa9286eaba Merge pull request #281 from CartoDB/277-exclude-analysis-quota
Exclude analysis cache tables from the quota
2016-10-17 17:56:21 +02:00
Rafa de la Torre
ce762f41ac Merge pull request #280 from CartoDB/279-check-analysis
Implement CDB_CheckAnalysisQuota
2016-10-17 17:55:45 +02:00
Rafa de la Torre
529b12af20 Cosmetic fix: s/INT8/bigint #279 2016-10-17 17:16:04 +02:00
Rafa de la Torre
f98b6fb0a1 Merge pull request #270 from CartoDB/269-overviews-non-null
Exclude null geometries to create overviews
2016-10-17 17:07:17 +02:00
Rafa de la Torre
30cd4cf1f9 Fix tests: race condition with publicuser #157 2016-10-17 16:31:10 +02:00
Javier Goizueta
1356131ec1 Fix tests 2016-10-14 11:22:06 +02:00
Javier Goizueta
9731ce38ec Exclude configuration tables from the quota
cdb_tablemetadata was already being excluded, but not cdb_conf and cdb_analysis_catalog
2016-10-14 10:58:16 +02:00
Javier Goizueta
07892271e5 Exclude analysis cache tables from the quota
See #277
2016-10-14 10:56:14 +02:00
Javier Goizueta
066c574709 Fix: cdb_conf table is not accessible to regular users 2016-10-11 17:52:11 +02:00
Javier Goizueta
4786e0a2ae Test cleanup 2016-10-11 17:49:50 +02:00
Javier Goizueta
358c89b332 Add tests for CDB_CheckAnalysisQuota() 2016-10-11 16:35:08 +02:00
Javier Goizueta
fa6f9a8a66 Implement CDB_CheckAnalysisQuota
see #279
2016-10-11 15:14:44 +02:00
Rafa de la Torre
091aea088e Merge pull request #275 from GeographicaGS/cdb-usertables-doc
Improve CDB_UserTables doc
2016-09-13 16:47:46 +02:00
Alberto Asuero
7ecdca1b8c Improve CDB_UserTables doc 2016-09-05 11:52:39 +02:00
Antonio Zamorano
9ee3125913 Relase 0.17.1 2016-08-16 11:30:06 +02:00
Antonio Zamorano
279eba95b7 Merge pull request #274 from CartoDB/273-cache_table_cdb_analysis_catalog
Adding a new column to have the name of the cached analysis in case there is one
2016-08-16 11:27:52 +02:00
Antonio Zamorano
b462e969a1 Adding cache_tables to the create table too 2016-08-12 11:52:24 +02:00
Antonio Zamorano
5d323456ee Chaging the type of the cached tables to a regclass array, fixes #273 2016-08-12 09:42:50 +02:00
Antonio Zamorano
6e130c336e Adding a new column to have the name of the cached analysis in case there is one, fixes #273 2016-08-11 16:27:18 +02:00
Javier Goizueta
457b614d96 Exclude null geometries to create overviews
Fixes #269
2016-07-05 16:45:12 +02:00
Raul Ochoa
415d96082e Release 0.17.0 2016-07-04 13:25:09 +02:00
Raul Ochoa
5eddf5ce8e Merge pull request #268 from CartoDB/cdb_analysis_catalog-export-config
Add export config for cdb_analysis_catalog table
2016-07-01 14:58:34 +02:00
Raul Ochoa
006c3cc50f Merge pull request #267 from CartoDB/cdb_analysis_catalog-new-fields
Add some extra fields to cdb_analysis_catalog table
2016-07-01 13:07:42 +02:00
Raul Ochoa
2b24390a8a Do not raise anything on existing columns 2016-07-01 12:56:44 +02:00
Raul Ochoa
69f04bb8b0 Add export config for cdb_analysis_catalog table
Closes #251
2016-07-01 12:36:07 +02:00
Raul Ochoa
c96bf7c7d5 Do not use plpgsql language 2016-07-01 12:34:40 +02:00
Raul Ochoa
15a8876d06 Rename to last_* pattern 2016-07-01 12:25:05 +02:00
Raul Ochoa
89e991aae9 Document new fields 2016-07-01 12:24:44 +02:00
Raul Ochoa
064b26ccd3 Add some extra fields to cdb_analysis_catalog table
Track user, error_message for failures, and last entity modifying the node.
2016-07-01 12:13:31 +02:00
Javier Goizueta
5bf35bddc1 Merge pull request #262 from CartoDB/261-overviews-quota
Exclude overviews from user data size
2016-06-20 11:03:56 +02:00
Javier Goizueta
2b69823949 💄 indent/parenthesize for clarity 2016-06-13 10:39:05 +02:00
Javier Goizueta
1f01ecae30 Exclude overviews from user data size
Fixes #261

Some internal functions from the Overviews module
have been moved to a separate file because they're now
used from Quaota function.
2016-06-13 10:04:13 +02:00
Javier Goizueta
58fd5d4060 Release 0.16.4 2016-05-30 10:45:12 +02:00
Javier Goizueta
a2a1ff6ae8 Merge pull request #258 from CartoDB/257-max-overviews-level
Fix problems computing feature density for overviews creation
2016-05-27 16:15:59 +02:00
Javier Goizueta
326aae4edb Merge pull request #259 from CartoDB/zoom_from_scale
Use standard formula for CDB_ZoomFromScale
2016-05-27 16:15:42 +02:00
Javier Goizueta
2a30eb2fd3 Fix zoom from scale condition for NULL result
And rewrite in cleaner form.
2016-05-27 15:10:20 +02:00
Javier Goizueta
0b3ad5e569 Limit the maximum zoom level
Avoid returning zoom levels greater than the maximum
'safe' level. For a zero denominator (which would imply
and infinite zoom level) return the maximum level too.
2016-05-27 12:29:52 +02:00
Paul Norman
aa302c237d Use standard formula for CDB_ZoomFromScale
postgis-vt-util comes with a standard formula for zoom from
scaleDenominator, and this is well tested. This also fixes the
function throwing an error on NULL input.
2016-05-27 12:29:43 +02:00
Javier Goizueta
9526f0448f Fix bug in feature density recursive query
If the table had x and/or y columns they were picked by an inner
select instead of the recursive arguments.
Fixes #256
2016-05-26 18:25:11 +02:00
Javier Goizueta
3399f2b9a5 Fix max overviews level usage
Note that _CDB_Feature_Density_Ref_Z_Strategy returns the first
level for which overviews should not be used, and that in some
cases _CDB_Feature_Density should look beyond the max level to
compute a feature density estimate.
2016-05-25 14:00:55 +02:00
Javier Goizueta
803b3671d0 Fixes for feature density computation
* The initial iteration of the recursive feature density query shouldn't
  start beyond the maximum level
* Correct off-by-one limit the rest of iterations
2016-05-25 11:21:12 +02:00
Javier Goizueta
c3fada29a8 Comment how the max overview level is defined 2016-05-25 11:07:06 +02:00
Javier Goizueta
86e5f6d317 Limit the maximum overview level to 23
Fixes #257

23 = 32 bits per integer - 1 sign bit - 8 bits px/tile
2016-05-24 18:18:58 +02:00
Javier Goizueta
f5f59be5b0 Release version 0.16.3
Fixes overviews creation problem
2016-05-09 13:08:50 +02:00
Javier Goizueta
d99dc394c2 Merge pull request #253 from CartoDB/252-estimateextent-quoting
Do not quote arguments to ST_EstimatedExtent
2016-05-09 13:04:44 +02:00
Javier Goizueta
8d7860dc7a Fixes #252 2016-05-09 11:54:56 +02:00
Javier Goizueta
b5427c65c8 Drop aggregate to be defined
Otherwise future versions will fail to recreate the aggregate
2016-04-29 08:46:01 +02:00
Paul Norman
3122a0479d Test behavior of binning fuctions with nulls
All test results are based off of existing behavior, which doesn't
always make sense (ref #247)
2016-04-28 09:59:33 -07:00
Paul Norman
956e56cd37 Use anyarray for equalintervalbins 2016-04-27 16:10:01 -07:00
Javier Goizueta
8f1435c049 Release 0.16.2 2016-04-27 18:30:26 +02:00
Javier Goizueta
8302f89413 Merge pull request #246 from CartoDB/245-categories-mode
Use the mode to aggregate category columns in overviews
2016-04-27 18:16:05 +02:00
Javier Goizueta
e9050178a8 Merge branch 'master' of github.com:CartoDB/cartodb-postgresql 2016-04-27 16:23:46 +02:00
Javier Goizueta
3e34ca4654 Overviews documentation fixes 2016-04-27 16:23:25 +02:00
Javier Goizueta
a067cc7da1 Generate stats used to identify category columns in overviews if needed
This only generates the stats if no stats are available for a table.
This doesn't warrant that the stats are up to date or accurate.
2016-04-27 15:06:09 +02:00
Javier Goizueta
2c43943df6 Fix syntax 2016-04-26 18:27:52 +02:00
Javier Goizueta
417cbe7902 Fix category columns aggregation in overviews
Overviews are created in cascade, each one from the inmediate
lower level, but the stats to decide if a column is a category
should be taken always from the base table.
2016-04-26 18:02:25 +02:00
Javier Goizueta
9a73703954 Use mode to aggregate categorical columns in overviews
Fixes #245
2016-04-26 15:15:24 +02:00
Rafa de la Torre
36ac831bd1 Update cartodbfy-requirements.rst
Fix broken link to doc
2016-04-26 14:43:24 +02:00
Paul Norman
b19a5fc3dc Convert CDB_EqualIntervalBins to a single SQL statement and add float version 2016-04-25 14:35:26 -07:00
Javier Goizueta
1358964628 Release 0.16.1 2016-04-25 18:47:42 +02:00
Javier Goizueta
efe381ad94 Merge pull request #243 from CartoDB/241-webmercator
Compute webmercator resolution with full accuracy
2016-04-25 17:30:40 +02:00
Javier Goizueta
f7cce21eb7 Merge pull request #242 from CartoDB/240-overviews-pixels
Adjust overview points to pixel centers
2016-04-25 17:30:25 +02:00
Javier Goizueta
18267477da Merge pull request #238 from CartoDB/235-column-names
Optimize column information functions
2016-04-25 17:30:07 +02:00
Javier Goizueta
11ad45306f Remove unneeded pg_catalog schema name 2016-04-25 16:30:58 +02:00
Javier Goizueta
75c7ae98e4 Compute webmercator resolution with full accuracy
Fixes #241
2016-04-25 14:02:26 +02:00
Javier Goizueta
3c12cf629f Optimize overview pixel adjustment for integer-pixel cells 2016-04-25 13:53:59 +02:00
Javier Goizueta
7b2100b51e Adjust overview coordinates to pixel centers
This makes the adjustment for all grid sizes, not only
for integral number of pixels.
2016-04-25 13:33:43 +02:00
Javier Goizueta
580ec38ab8 Adjust overview clustered point to pixel centers
Fixes #240
2016-04-23 15:07:06 +02:00
Raul Ochoa
897689dd43 Release 0.16.0 2016-04-19 15:44:37 +02:00
Raul Ochoa
808fc9fc25 Merge pull request #237 from CartoDB/analysis-catalog
Adds table for storing camshaft analysis nodes
2016-04-19 15:32:46 +02:00
Javier Goizueta
65415bb335 Optimize funcion CDB_COlumnType 2016-04-18 19:07:33 +02:00
Javier Goizueta
06ebb27160 Optimize internal funcion _cdb_unlimited_text_column 2016-04-18 18:50:37 +02:00
Javier Goizueta
bd5ae84e90 Optimize CDB_ColumnNames
This implementation is about 1000 times faster
2016-04-18 18:49:58 +02:00
Raul Ochoa
de5a702510 Adds table for storing camshaft analysis nodes 2016-04-18 17:41:39 +02:00
Javier Goizueta
6908fb4672 Release 0.15.1
Overviews bugfixes & enhancements
2016-04-15 18:15:35 +02:00
Javier Goizueta
a528a250d4 Merge pull request #234 from CartoDB/231-overviews-text-aggr
Aggregate small number of text items in overviews
2016-04-15 18:04:07 +02:00
Javier Goizueta
ef43623f77 Remove unneeded variable 2016-04-15 17:58:03 +02:00
Javier Goizueta
09ad550de3 Fix tests 2016-04-15 17:50:47 +02:00
Javier Goizueta
1b0f77aa96 Always retain single-valued aggregated texts
This makes columns which have the same value in a group to be aggregated
maintain that value (rather than replacing it by the multiple-value
indicator *) whatever the group value is. (Previously this happend
only for small groups)
2016-04-15 17:49:00 +02:00
Javier Goizueta
45f063d469 Aggregate small number of text items in overviews
Instead of nulling text fields for non-singleton aggregated records
concatenate distinct text values when they're few (5 or less).
Fixes #231
2016-04-15 12:37:16 +02:00
Carla
20989e2f28 Merge pull request #233 from CartoDB/232-overviews-avg
Fix AVG computation in overview tables
2016-04-15 11:10:26 +02:00
Javier Goizueta
176d69d09e Fix AVG computation in overview tables
Fixes #232
Averages of averages are not equal to overall averages.
2016-04-15 10:48:08 +02:00
Javier Goizueta
9fdbfda60a Merge pull request #228 from CartoDB/225-no-centroid-master
Use cell centers, not cluster centroids when grouping points
2016-04-15 10:06:44 +02:00
Javier Goizueta
9a3d93976c Merge pull request #227 from CartoDB/226-add_count_aggregated_features
Include and aggregate _vovw_count column to count aggregated features
2016-04-15 10:06:05 +02:00
Javier Goizueta
46b45f6dd4 Merge pull request #224 from CartoDB/223-fix-dropoverviews
Fix CDB_DropOverviews and CDB_Overviews problems
2016-04-15 10:05:28 +02:00
Carla Iriberri
fd14750ce5 Rename _vovw_count to _feature_count 2016-04-14 18:23:09 +02:00
Javier Goizueta
c595e45c11 Add _vovw_count columnt to tables for which overviews are created
Initially we planned to add this column to the queries sent to the
tiler only, but that makes the column hard to access from the editor.
2016-04-14 17:32:18 +02:00
Carla
1cf7074fb1 Merge pull request #230 from CartoDB/229-set_tolerance_px_to_1_overviews
Set tolerance to 1 pixel in overviews by default
2016-04-14 17:26:37 +02:00
Javier Goizueta
f785e71d3b Fix: numeric is a valid numeric column type
Actually this is the type of aggregated _vovw_count columns
2016-04-14 15:46:03 +02:00
Carla
14b8cd7d99 Set default value to 1 and remove typo line 2016-04-14 12:12:17 +02:00
Carla
213adcca16 Fixes tests for tolerance_px = 1.0, with no zoom 3 2016-04-14 11:24:10 +02:00
Carla
1a571c8a9c Set tolerance to 1 pixel 2016-04-14 11:13:59 +02:00
Carla Iriberri
8f44f5347a Fix indent for code clarity 2016-04-13 17:51:30 +02:00
Carla Iriberri
f96163265b Fix bug for tables without geom or with no potential overviews
If the table doesn't have geometries but the createoverviews function is
called, the current geometry type checks won't work because "null" will
not give a boolean value in the type comparisons.

Also, if the createoverviews function is called over a simple table with
would not require overviews according to the strategies it is handled
correctly.
2016-04-13 17:49:38 +02:00
Javier Goizueta
1c67214b09 Use cell centers, not cluster centroids when grouping points
Fixes #225
2016-04-13 11:14:09 +02:00
Carla Iriberri
16d08ef52b Include and aggregate _vovw_count column to count aggregated features 2016-04-12 11:10:55 +02:00
Javier Goizueta
15ac9a2cd9 Remove unneeded code 2016-04-07 10:30:10 +02:00
Javier Goizueta
ee61d46100 💄 rename variable for clarity 2016-04-07 10:24:02 +02:00
Javier Goizueta
49e7094c8a Make CDB_CreateOverview usable by superuser
CDB_CreateOverview had to be executed with the user role
corresponding to the owner of the table; now it can be executed
by the postgres user.
2016-04-07 07:52:58 +02:00
Javier Goizueta
fb910be12f Fix conversion of regclass to indentifier 2016-04-07 07:07:20 +02:00
Javier Goizueta
34c39662ec Replace use of CDB_UserTables in CDB_Overviews
Use a function that returns reclasses and schema names properly instead.
2016-04-07 00:07:45 +02:00
Javier Goizueta
84cac16d1c Temporary fix 2016-04-06 22:05:00 +02:00
Javier Goizueta
c1fc07d2ac Fix typo
This function isn't beint actively used; should consider removing it
or testing it properly
2016-04-06 18:58:37 +02:00
Javier Goizueta
5c3c0f5fc9 Fix bug in CDB_DropOverviews
Fixes #223
2016-04-06 18:57:52 +02:00
Javier Goizueta
e68d5eca45 Release 0.15.0
This release includes some overviews enhancements
2016-04-05 14:22:46 +02:00
Javier Goizueta
16a58c479d Merge pull request #221 from CartoDB/219-overviews-tolerance
New function CDB_CreateOverviewsWithToleranceInPixels
2016-04-05 14:01:25 +02:00
Javier Goizueta
06bb669d4c Add comment
Clarify the reason why some functions are dropped at the
end of the file and not where their new definitions are.
2016-04-05 13:22:07 +02:00
Javier Goizueta
00a3d6e650 Fix upgrades from prior versions 2016-04-05 13:10:00 +02:00
Javier Goizueta
f0ff197c56 Merge branch 'master' into 219-overviews-tolerance
# Conflicts:
#	scripts-available/CDB_Overviews.sql
#	test/CDB_OverviewsTest_expect
2016-04-05 13:08:22 +02:00
Javier Goizueta
c6885c2972 Merge pull request #220 from CartoDB/218-org-users-overviews
Add support for explicit schema names in overview functions
2016-04-05 13:01:16 +02:00
Javier Goizueta
57c32332e2 New function CDB_CreateOverviewsWithToleranceInPixels
This function allows defining the previously fixed parameter grid_px.
The lim parameter used to define the reference Z level is also
correlated to this value.

Fixes #219
2016-04-04 19:21:10 +02:00
Javier Goizueta
3c71eecbae Fix cases that require explicit schema name
This allows using overview functions in situations where
the base tables require being qualified with the schema name.
2016-04-04 17:45:20 +02:00
Javier Goizueta
6d9424746c Fix expected tests output 2016-04-04 17:42:10 +02:00
Javier Goizueta
c0262a05eb Fix CDB_Overviews for cases that require explicit schema name
Fixes #218
2016-04-04 17:02:59 +02:00
Javier Goizueta
aff7ae3e2e Release 0.14.4 2016-03-29 13:09:09 +02:00
Carla
01757a1b6d Merge pull request #207 from CartoDB/update_docs_user_table
Update CartoDB User table docs and minor edits on cartodbfy reqs
2016-03-29 12:58:20 +02:00
Carla
f946bfe4fe remove bigint mention 2016-03-29 12:57:58 +02:00
Javier Goizueta
a098713bfa Merge pull request #215 from CartoDB/213-makefile-echo
Fix backslashes in generated files
2016-03-29 12:51:02 +02:00
Javier Goizueta
217ff4ffb9 Merge pull request #214 from CartoDB/211-boolean-col-overviews
Support boolean columns when creating overviews
2016-03-29 12:50:57 +02:00
Javier Goizueta
a0bb7b1b03 Fix backslashes in generated files
Fixes #213
Some systems treat escaping of text passed to the echo command
from a Makefile differently.
This seems to work for our needs.
2016-03-21 14:59:05 +01:00
Javier Goizueta
4074173c05 Add support for boolean columns in overview creation 2016-03-21 12:58:29 +01:00
Javier Goizueta
603b1ceed8 Adjust Overviews test expectations 2016-03-21 12:58:00 +01:00
Javier Goizueta
0caf6c50dd Fix the tests for boolean columns and overview creation 2016-03-21 12:27:00 +01:00
Carla
224b2ce395 Update travis button to show only master status 2016-03-19 12:33:17 +01:00
Javier Goizueta
70eeab5748 Tests for revealing issue #211
Test creating overviews for tables with boolean columns
2016-03-17 19:27:51 +01:00
Carla
06c05a1d67 Merge pull request #212 from CartoDB/release_0_14_3
Release 0.14.3
2016-03-17 10:53:59 +01:00
Carla
6567d5441b Release 0.14.3 2016-03-17 10:45:54 +01:00
Carla
e10d7c3a27 Update NEWS.md 2016-03-17 10:44:12 +01:00
Carla
b89a752548 Merge pull request #210 from CartoDB/209-remove_bigint_casting_cartodb_id
Remove casting to bigint in cartodb_id column
2016-03-17 10:31:06 +01:00
Carla
90fa45b59d Remove casting to bigint 2016-03-16 11:03:46 +01:00
Carla
eb48e26eec Update CartoDB-user-table.rst 2016-03-15 16:39:56 +01:00
Carla
85e1b92199 Add non-zero requirement 2016-03-15 16:39:39 +01:00
Carla
2dc6ec618f Merge pull request #208 from CartoDB/release_0_14_2
Release 0.14.2
2016-03-15 11:19:42 +01:00
Carla
3127b9d398 Release 0.14.2 2016-03-15 10:57:06 +01:00
Carla
91158fafb0 Release 0.14.2 2016-03-15 10:52:52 +01:00
Carla
16cf70bb4a Merge pull request #202 from CartoDB/cartodbfication_cartodb_id_text
Add support to detect string cartodb_id columns
2016-03-15 10:49:22 +01:00
Carla
6ea0013343 Update cartodbfy-requirements.rst 2016-03-09 15:49:18 +01:00
Carla
80bd7f8f10 Update cartodbfy-requirements.rst 2016-03-09 15:48:33 +01:00
Carla
bb061981ad style edits 2016-03-09 15:47:26 +01:00
Carla
e289b4725f Update information and convert to .rst 2016-03-09 15:26:45 +01:00
Carla
0b8bada553 Remove unused variable 2016-03-09 11:54:59 +01:00
Carla Iriberri
7b48c2765e Fix error detection and fix tests 2016-03-08 14:06:58 +01:00
Carla Iriberri
3d0f580fc2 Add idempotence test 2016-03-08 12:10:46 +01:00
Carla Iriberri
d495bd45ba Merge branch 'cartodbfication_cartodb_id_text' of https://github.com/CartoDB/cartodb-postgresql into cartodbfication_cartodb_id_text 2016-03-08 11:59:00 +01:00
Carla Iriberri
f4b51807a1 Make cartodb_id inconsistencies fail and update tests 2016-03-08 11:58:30 +01:00
Alejandro Martínez
33b4f3718b Release 0.14.1 2016-03-07 12:05:22 +01:00
Alejandro Martínez
2e186c8565 Merge pull request #204 from CartoDB/fully-qualified-invalidations
Fully qualify invalidation calls (Fixes #198)
2016-03-07 11:45:01 +01:00
Carla
5bc725c8ab Add drop function if exists 2016-03-03 16:58:31 +01:00
Carla Iriberri
73906b60da Verbosity terse for tests 2016-03-02 18:19:21 +01:00
Carla Iriberri
03ff0365fd Change exception message and edit tests 2016-03-02 17:41:02 +01:00
Carla Iriberri
76a2cb9132 Improve exception error message 2016-03-02 17:36:45 +01:00
Alejandro Martínez
90c16fdb13 Fully qualify invalidations 2016-03-02 16:22:22 +01:00
Carla Iriberri
a80664e72a Delete outdated comments 2016-03-02 15:53:20 +01:00
Carla Iriberri
7e2193d3db Fix test expectation 2016-03-02 15:52:57 +01:00
Carla Iriberri
a18cbeb2cd Third iteration, expect a viable cartodb_id 2016-03-02 14:58:53 +01:00
Carla Iriberri
0d5f83b3c4 Rewriting function 2016-03-01 19:17:45 +01:00
Carla Iriberri
7559257d49 cartodb_id string tests 2016-03-01 17:45:15 +01:00
Carla Iriberri
1198454046 Better exception handling 2016-03-01 17:43:21 +01:00
Carla Iriberri
32307ceef0 Add support to detect string cartodb_id columns 2016-03-01 15:24:40 +01:00
Rafa de la Torre
54973c01f2 Add new version 0.14.0 with FDW support 2016-02-12 16:37:59 +01:00
Rafa de la Torre
eb4564ecee Merge pull request #199 from CartoDB/fdw-function-calls-with-schema
Fdw function calls with schema
2016-02-12 16:31:58 +01:00
Rafa de la Torre
abdc39f122 Merge pull request #200 from CartoDB/fdw-cdb_tablemetadata_text
Add CDB_TableMetadata_Text view as a proxy to access FDW tablemetadata
2016-02-12 14:47:05 +01:00
Rafa de la Torre
d2450ff361 Fix small typo in makefile 2016-02-12 11:34:04 +01:00
Rafa de la Torre
a0fe55bd5d Add a small bit of func doc about the quoting 2016-02-12 11:27:28 +01:00
Alejandro Martínez
56fed12392 Add CDB_TableMetadata_Text view as a proxy to access FDW tablemetadata 2016-02-11 19:16:00 +01:00
Rafa de la Torre
2f26b44142 tDo not quote dbname identifier
Turns out that for caching it is our standard not to have the dbname
quoted.
2016-02-11 16:10:27 +01:00
Rafa de la Torre
9596e8d9bc A couple checks for quoted idents in CDB_Last_Updated_Time 2016-02-10 19:10:57 +01:00
Rafa de la Torre
06036e2fe8 Quote identifiers returned by CDB_QueryTables_Updated_At 2016-02-10 18:58:01 +01:00
Rafa de la Torre
e870cf96e0 Merge pull request #196 from CartoDB/fdw-query-tables-updated-at
Fdw query tables updated at
2016-02-10 09:30:47 +01:00
Rafa de la Torre
2bce771488 Add some tests
Tests for:
* CDB_QueryTables_Updated_At
* CDB_Last_Updated_Time
2016-02-09 19:24:08 +01:00
Rafa de la Torre
cd4ad29e39 Remove schema when selecting from CDB_TableMetadata
to ease testing. When creating CDB_TableMetadata it is always put in
cartodb when done from the extension, but for tests it is done in
public.
2016-02-09 18:49:20 +01:00
Rafa de la Torre
d59b826d37 Fix silly bug: ordering of functions 2016-02-09 17:11:16 +01:00
Rafa de la Torre
1c637f8689 Small fixes: qualify cartodb function calls 2016-02-09 16:38:11 +01:00
Rafa de la Torre
ecbdb4a430 Move fdw-aware functions to CDB_ForeignTable.sql 2016-02-09 13:40:18 +01:00
Rafa de la Torre
eb84dd04c9 Add func CDB_Last_Updated_Time 2016-02-09 13:30:00 +01:00
Rafa de la Torre
276b5cf9ea Rename func to CDB_QueryTables_Updated_At
s/CDB_QueryTablesUpdatedAt/CDB_QueryTables_Updated_At and also add a bit
more inline doc.
2016-02-09 13:29:10 +01:00
Rafa de la Torre
ec34b8ee28 Minor changes: use plain SQL func 2016-02-08 19:29:14 +01:00
Rafa de la Torre
0f21db51b6 Simplify the code and get the updated_at 2016-02-08 19:29:14 +01:00
Rafa de la Torre
a074f4df5d Adapt CDB_QueryTablesUpdatedAt to _cdb_fqtn_from_text 2016-02-08 19:29:14 +01:00
Rafa de la Torre
1a12fd3b69 Make _cdb_fqtn_from_text return a table
with type instead of a record
2016-02-08 19:29:14 +01:00
Rafa de la Torre
78a75cf22d Implementation of _cdb_fqtn_from_text (WIP) 2016-02-08 19:29:14 +01:00
Rafa de la Torre
1e3c7ace99 Implementation of _cdb_dbname_of_foreign_table (WIP) 2016-02-08 19:29:14 +01:00
Rafa de la Torre
c210008184 Skeleton of a possible solution (WIP) 2016-02-08 19:29:14 +01:00
Rafa de la Torre
0c43fe2731 Define API of CDB_QueryTablesUpdatedAt 2016-02-08 19:29:14 +01:00
Alejandro Martínez
fdbad0f93c Fix specs on 9.3 2016-02-08 17:33:41 +01:00
Alejandro Martínez
131aee1503 Fully qualify function names 2016-02-08 16:35:26 +01:00
Alejandro Martínez
e858ddfa0b Add CDB_ForeignTable specs 2016-02-08 15:46:25 +01:00
Alejandro Martínez
edf79d9368 Add remote cdb_tablemetadata manually from public schema 2016-02-08 15:45:58 +01:00
Rafa de la Torre
c26ab0fdd1 Merge pull request #195 from CartoDB/fdw-rtorre
Fix small typos: s/name/fdw_name/
2016-02-05 13:18:24 +01:00
Rafa de la Torre
8dedd2b3f4 Fix small typos: s/name/fdw_name/ 2016-02-05 13:15:20 +01:00
Rafa de la Torre
11834dfdab Fix typo: missing semicolon 2016-02-05 10:44:55 +01:00
Alejandro Martínez
b957635e78 Add CDB_Get_Foreign_Updated_At function 2016-02-04 18:26:43 +01:00
Alejandro Martínez
a9b9f1ff6c Rename CDB_FDW_Create to CDB_FDW_Setup, formatting fixes 2016-02-04 12:06:22 +01:00
Alejandro Martínez
d7b560324a Add _Create_FDW function to create a FDW defined on the config by name 2016-02-03 18:07:23 +01:00
Alejandro Martínez
7b52058265 Add CDB_ForeignTable functions 2016-02-03 17:50:13 +01:00
Javier Goizueta
40a163f885 Release 0.13.1 2016-02-01 19:23:38 +01:00
Javier Goizueta
01d432c22c Merge pull request #193 from CartoDB/fix-multiline-fn
Fix function declaration for create_from_unpackaged.sh use
2016-02-01 19:16:37 +01:00
Javier Goizueta
5285943dbf Fix function declaration for create_from_unpackaged.sh use
The script create_from_unpackaged.sh does not support
function declarations where the signature (name and parameter list
of the function, including parentheses) is not on a single line.
2016-02-01 18:56:55 +01:00
Javier Goizueta
8414bdff31 Release 0.13.0 2016-01-29 17:53:51 +01:00
Javier Goizueta
5f96908df4 Merge pull request #185 from CartoDB/overviews
Overviews (new feature)
2016-01-29 17:44:47 +01:00
Javier Goizueta
06dd31f4ad Fix: should be floating point divistion, not integer division 2016-01-29 16:51:52 +01:00
Javier Goizueta
6a11698a16 Merge branch 'overviews' into sql_lang 2016-01-29 16:29:23 +01:00
Javier Goizueta
00bd302f01 Avoid creating GridCluster overviews for non-point datasets 2016-01-29 16:19:35 +01:00
Javier Goizueta
93d4a6ead0 Restrict SECURITY DEFINER to overview registration
And check it is applied only overview tables with valid names
2016-01-28 17:04:06 +01:00
Javier Goizueta
66387c2d44 Make CDB_CreateOverviews a SECURITY DEFINER function
So that it can change the permissions of overview tables
(by updating pg_class) even when executed by non-priviledeged users.
2016-01-28 16:32:40 +01:00
Javier Goizueta
26c95347cd Merge branch 'master' into overviews 2016-01-27 16:56:15 +01:00
Javier Goizueta
6a5e4b0460 Fix overviews tests
The aggregation method for strings has changed
2016-01-27 16:54:30 +01:00
Javier Goizueta
b8d50204dd Avoid aggregation which causes out-of-memory crashes in PostgreSQL
The use of multiple string_agg functions, even if applied to groups
of one single record causes out of memory crashes in PG 9.3.4 for
some (large) tables.
2016-01-27 15:24:04 +01:00
Alejandro Martínez
845ac6dc9a Release 0.12.0 2016-01-27 14:28:56 +01:00
Alejandro Martínez
350f101c3d Merge pull request #190 from CartoDB/remove_schema_triggers
Remove schema triggers
2016-01-27 14:19:21 +01:00
Javier Goizueta
474de01757 Change the overview table naming scheme
The scheme is changed from table_ovN to _vovw_N_table for
lower collision probability.
Also future naming changes will be easier by using the functions
_CDB_OverviewTableDiscriminator, _CDB_OverviewTableName,
_CDB_IsOverviewTableOf, etc.
2016-01-26 13:20:28 +01:00
Javier Goizueta
1ebaeb76ac Overload CDB_Overviews to accept either a single table or an array
The result of CDB_Overviews has been expandend with a base_table column
2016-01-26 10:39:26 +01:00
Alejandro Martínez
eb1222729d Remove ddl triggers specs 2016-01-21 11:46:39 +01:00
Javier Goizueta
7033a8d9ac Fixes for table names that require quotes or which include a schema name
Some cases left unsolved, with FIXME comments
2016-01-13 18:49:27 +01:00
Javier Goizueta
46bc774d38 Fix CDB_Overviews for the case that the table name requires quoting 2016-01-13 18:24:06 +01:00
Javier Goizueta
a9e2d19918 Document CDB_DropOverviews 2016-01-12 16:20:11 +01:00
Javier Goizueta
d352e1c463 Update Overviews tests 2016-01-12 15:36:07 +01:00
Javier Goizueta
5b47c51221 Add function to drop overviews 2016-01-12 15:35:50 +01:00
Javier Goizueta
ebaded0c7a Merge branch 'master' into overviews 2016-01-12 13:34:26 +01:00
Javier Goizueta
ccdf8de59e Enhance documentation, update comments 2016-01-12 12:08:41 +01:00
Javier Goizueta
a2f6cb4c04 Fix documentation 2016-01-12 11:59:57 +01:00
Javier Goizueta
02f386be33 Regard the GridCluster reduction strategy as private
The *strategy* parameteriation will be considered an
implementation detail for the time being.
2016-01-12 11:59:42 +01:00
Javier Goizueta
a7c70fe497 Fix: CDB_ZoomFromScale deviation for lowest zoom levels 2016-01-12 11:46:47 +01:00
Javier Goizueta
0a066e0126 Change the default overview reduction strategy to GridCluster 2016-01-11 15:35:04 +01:00
Javier Goizueta
913640e2dc Preserve the column ordering of the base table in overviews 2016-01-11 15:34:10 +01:00
Javier Goizueta
ef7e613d41 Change CDB_ColumnNames to order columns names as in table 2016-01-11 15:28:27 +01:00
Javier Goizueta
fd7a8cff71 Change regular expression for consistency 2016-01-11 15:27:05 +01:00
Javier Goizueta
6ea63af974 Add function to obtain existing overviews of a table 2016-01-11 14:50:10 +01:00
Javier Goizueta
496f079b1c Copy dataset privileges to overview tables 2016-01-04 18:06:56 +01:00
Javier Goizueta
4580c9cd5c Change the cartodb_ids of aggregated overviews
Instead of arbitrary ids, the id of one of the aggregated records
is used, so that if it is used in the UI to query point
the information of one of the records grouped at the point will be
retrieved.
2016-01-04 10:33:39 +01:00
Javier Goizueta
08828b8b7d Set owner of overlays to the owner of the base table 2015-12-29 15:22:12 +01:00
Javier Goizueta
cecba655eb Preserve aggregated attributes of singleton groups 2015-12-29 14:56:47 +01:00
Javier Goizueta
b34a752172 Generate overviews for all Z levels
Skipping levels produces visually inferior results
2015-12-29 14:56:04 +01:00
Javier Goizueta
8ba9e74c4a Order columns of aggregated overlays as in the base table 2015-12-29 13:38:07 +01:00
Alejandro Martínez
045ede6908 Remove schema_triggers from travis.yml 2015-12-29 10:43:37 +01:00
Alejandro Martínez
cd5c8f2904 Remove outdated references to schema triggers and change triggers 2015-12-29 10:43:18 +01:00
Alejandro Martínez
172ca45ea5 Merge remote-tracking branch 'origin/master' into remove_schema_triggers 2015-12-29 10:41:13 +01:00
Javier Goizueta
6a6a5bc96a Fix Sampling reduction to avoid RandomTids problems
The fixed cases will not be common but do occur in tests.
This is an interim fix which should be reverted if CDB_randomTids changes.
2015-12-28 19:41:14 +01:00
Javier Goizueta
2ff686de27 Clean up: remove spurious comment 2015-12-28 19:30:20 +01:00
Javier Goizueta
07326626b7 More efficient sampling strategy
It is also renamed properly.
2015-12-28 19:28:20 +01:00
Javier Goizueta
4afc427008 Rename Ref. Z strategy function
It's not that *dummy* anymore, so choose a more descriptive name
2015-12-28 17:47:57 +01:00
Paul Norman
2ab059460b Merge pull request #189 from pnorman/fix_travis
Fix test errors on Travis
2015-12-23 10:56:56 -08:00
Alejandro Martínez
2a2a7d534a Merge remote-tracking branch 'origin/master' into remove_schema_triggers 2015-12-23 17:09:41 +01:00
Javier Goizueta
8d1bbc63fa Add overview tests 2015-12-23 16:33:34 +01:00
Javier Goizueta
06ca4f74ee Enable Overviews module in the extension 2015-12-23 16:32:44 +01:00
Javier Goizueta
a8a2c04d71 Remove invalid comment 2015-12-23 14:20:57 +01:00
Javier Goizueta
a5bca7d715 Add function for post-processing new overview tables 2015-12-23 14:17:50 +01:00
Javier Goizueta
552206464e Make strategy function public 2015-12-23 12:50:04 +01:00
Javier Goizueta
2af0b9a57f Add function comments 2015-12-23 12:42:40 +01:00
Javier Goizueta
1b5de84c9a Add missing attribute-aggregationto the point reduction strategy 2015-12-23 12:17:37 +01:00
Paul Norman
3b48acf60c Round extent outputs in test
Travis was reporting rounded results, so this should make the behavior more consistent
2015-12-22 16:34:18 -08:00
Paul Norman
efb319074a Add constraint to QueryTablesTest 2015-12-22 16:21:54 -08:00
Javier Goizueta
c36a5d35c3 Merge branch 'overviews' of github.com:CartoDB/cartodb-postgresql into overviews 2015-12-22 18:02:16 +01:00
Javier Goizueta
5a78ee2896 Optimize the gridded clustering strategy
The internal grid_px parameter is adjusted for best results with default symbol size
2015-12-22 17:59:49 +01:00
Rafa de la Torre
480e2d0979 Merge pull request #187 from CartoDB/overviews-rtorre
Overviews rtorre touches
2015-12-22 17:45:14 +01:00
Javier Goizueta
c8a1ef6f68 Slight optimization of gridded clustering 2015-12-22 15:25:21 +01:00
Paul Norman
ea7c16fbaf Convert some simple functions from plpgsql to sql
SQL is a faster language to call, and these are very simple functions.
2015-12-21 23:59:26 -08:00
Rafa de la Torre
564ab75d2d Use _cdb_estimated_extent instead of ST_Extent
With a 3.8M points table, this was a ~30% gain in my local env.
2015-12-21 18:41:50 +01:00
Rafa de la Torre
5010109c7d Add _cdb_estimated_extent to get the extent from stats 2015-12-21 18:41:45 +01:00
Paul Norman
a9f6e26fed Merge pull request #184 from pnorman/readme_url
Update wiki URL
2015-12-21 08:35:01 -08:00
Rafa de la Torre
e60f73a31b A bit of internal documentation 2015-12-21 13:16:57 +01:00
Javier Goizueta
415a09392f Gridded clustering aggregation strategy for overviews 2015-12-16 17:45:36 +01:00
Javier Goizueta
e5cc9ef0bd Fix: typo 2015-12-16 17:26:17 +01:00
Javier Goizueta
f7857945c1 Change feature density computation algorithm
Now parameterize by the number of levels to traverse and
start with the level that covers the extent of the table
with at least N*N tiles (N=4).
2015-12-16 16:39:38 +01:00
Javier Goizueta
554464e43e Use tile-recursive computation of feature density
This is a more adaptive way of estimating the feature density to
determine the base Z level.
Applying technique from http://javisantana.com/2014/10/22/traversing-quadtree.html
2015-12-16 12:14:37 +01:00
Javier Goizueta
d7c8f3d7e8 Fix: overlay generation was not using the proper scale 2015-12-15 19:13:39 +01:00
Javier Goizueta
4c85d7f3ad Compute the reference Z level for a table 2015-12-15 19:12:48 +01:00
Javier Goizueta
d0e66910a0 Sketch for new Overview-creation functionality 2015-12-15 17:36:27 +01:00
Paul Norman
dcf0b684e2 Update wiki URL 2015-12-08 10:08:17 -08:00
Stuart Lynn
0ecbbd8e71 Make sure that empty arrays or arrays with all the same entry return 0 for Skewness and Kurtosis rather than throwing a division by zero error 2015-12-04 14:54:15 -05:00
Javier Goizueta
a88bfc51a3 Upgrade version to 0.11.5 2015-11-27 17:03:51 +01:00
Javier Goizueta
21d5ee5813 Merge pull request #178 from CartoDB/disable-log-invalidation-time
Disable log invalidation time
2015-11-27 15:03:46 +01:00
Javier Goizueta
9a58c03ac0 Upgrade version to 0.11.4 2015-11-24 17:00:45 +01:00
Rafa de la Torre
53acee4ddb Merge pull request #180 from CartoDB/174_cartodbfy
174 cartodbfy
2015-11-24 16:38:13 +01:00
Javier Goizueta
68099e780c Merge remote-tracking branch 'origin' into 174_cartodbfy 2015-11-24 16:29:32 +01:00
Rafa de la Torre
9dba6fa7c4 Merge pull request #175 from CartoDB/155-fix-wrong-delimiters
Removes extra d in delimiter 155
2015-11-24 15:58:54 +01:00
Rafa de la Torre
bf711d5c9b Merge pull request #171 from CartoDB/great_circle_generator
Adding function to produce a great circle between two points.
2015-11-24 15:54:47 +01:00
Javier Goizueta
f14fc057e2 Add optional parameter for max. great circle segment length 2015-11-23 17:13:17 +01:00
Javier Goizueta
aa81c6a1ab Add comment to CDB_GreatCircle 2015-11-23 17:07:24 +01:00
Javier Goizueta
1b8ced22a5 Fix name of expected results file 2015-11-23 16:57:34 +01:00
Javier Goizueta
2d13903d50 Cleanup coding style 2015-11-23 16:51:34 +01:00
Javier Goizueta
3bc92d4046 Fix CDB_GreatCircle syntax 2015-11-23 16:40:42 +01:00
Carla
a684c37f6d Merge pull request #151 from CartoDB/cartobdfy-requirements-doc
First version of the cartodbfy requirements
2015-11-23 15:51:09 +01:00
Carla Iriberri
bcfe8d8f3b Adds not null constraint for cartodb_id 2015-11-20 17:24:01 +01:00
Carla Iriberri
333a408199 Add Paul and Rafa feedback 2015-11-20 17:15:37 +01:00
Javier Goizueta
83ac8f4502 Fix: Allow dots in column names to be cartodbfied
This fixes #6144 of cartodb
Note that prior commit ea9503bd32
only added the tests for this, but not the actual fix (oops)
2015-11-20 13:05:15 +01:00
Javier Goizueta
a0ca2288f4 Fix: Cartodbfication failed with existing PK
This fixes #174
When a unique index and a primary key contraint existed for a column
named cartodb_id cartodbfy tried to add another PK constraint
2015-11-20 12:56:52 +01:00
Javier Goizueta
ea9503bd32 Allow dots in column names to be cartodbfied
This fixes #6144 of cartodb
2015-11-20 12:24:46 +01:00
Stuart Lynn
d597f0fe6d removing comments 2015-11-18 15:56:31 +00:00
Stuart Lynn
f43d1cc3c4 Merge branch 'master' into great_circle_generator 2015-11-18 15:36:51 +00:00
Stuart Lynn
f36f1ab536 formatting 2015-11-18 15:30:16 +00:00
Luis Bosque
d39a032024 Revert "Write invalidation duration in postgresql log"
This reverts commit 37160c7b35.
2015-11-17 13:10:19 +01:00
Luis Bosque
4cceb2a21f Revert "Optimize invalidation time logging"
This reverts commit d1d5ed6df3.
2015-11-17 13:10:15 +01:00
Guido Fioravantti
4803abf365 Fix typo in expected 155 2015-11-06 16:32:56 +01:00
Guido Fioravantti
cce63f0eae Adds ::integer cast for USING 155 2015-11-06 16:26:03 +01:00
Guido Fioravantti
7cf0d02935 Fixes expected 155 2015-11-06 15:11:08 +01:00
Guido Fioravantti
545196811f Changes logger level to error 155 2015-11-06 14:41:12 +01:00
Guido Fioravantti
6252907de2 Rises verbosity level before tests for _CDB_create_cartodb_id_column 155 2015-11-05 17:11:27 +01:00
Alejandro Martínez
2a8d467949 Merge remote-tracking branch 'origin/master' into remove_schema_triggers 2015-11-05 14:49:46 +01:00
Alejandro Martínez
8895d9f3af Remove DDL from Makefile 2015-11-04 17:26:38 +01:00
Alejandro Martínez
ef376fd243 Remove schema_triggers 2015-11-04 17:06:54 +01:00
Guido Fioravantti
081ed36aae Fixes NULL max in rec 155 2015-11-02 11:47:14 +01:00
Guido Fioravantti
453b3af872 Removes extra d in delimiter 155 2015-10-30 17:49:27 +01:00
Guido Fioravantti
e99231252e Merge pull request #173 from CartoDB/better-unique-identifiers
Better unique identifiers
2015-10-27 14:19:50 +01:00
Guido Fioravantti
d171afb9f4 Increase version number and update NEWS.md 2015-10-27 14:16:17 +01:00
Guido Fioravantti
fdfbe8e62c Typo fixing 173 2015-10-27 12:11:00 +01:00
Guido Fioravantti
32c729e464 Refactors code 173 2015-10-27 10:33:15 +01:00
Guido Fioravantti
58b2705383 Rename relname to colname in _CDB_Unique_Column_Identifier 2015-10-26 18:35:12 +01:00
Guido Fioravantti
8734608792 Removes unnecessary salt 173 2015-10-26 18:25:48 +01:00
Guido Fioravantti
bb54eb83c1 Drops CDB_Trim_Octets for CDB_Octet_Truncate 2015-10-26 18:01:03 +01:00
Guido Fioravantti
2e701f73ba Reworks _CDB_Octet_Trim 173 2015-10-26 16:35:33 +01:00
Guido Fioravantti
710a3c9672 Removes ability to examine all relations for _CDB_Unique_Column_Identifier 173 2015-10-26 16:17:25 +01:00
Guido Fioravantti
bb18d71995 Adds comment for magic number and constant for maxlen 173 2015-10-26 16:15:55 +01:00
Guido Fioravantti
629214f32f Adds explanation for SCHEMA DEFAULT NULL 173 2015-10-26 15:54:08 +01:00
Guido Fioravantti
270d5b3146 Remove code from deprecated methods 173 2015-10-26 15:50:19 +01:00
Guido Fioravantti
89f5987f53 Fix CDB_HelperTest_expect 173 2015-10-26 12:02:54 +01:00
Guido Fioravantti
cf8c5e5a33 Fixes CDB_HelperTest_expect 173 2015-10-23 12:11:40 +02:00
Guido Fioravantti
b4acfeca22 Fixes Typo in throwing exception 173 2015-10-23 10:38:24 +02:00
Guido Fioravantti
9850399693 Adds test for CDB_Unique_Column_Identifier 173 2015-10-22 19:23:38 +02:00
Guido Fioravantti
aed8671e77 Uses underscore prefix for private tables 173 2015-10-22 19:00:18 +02:00
Guido Fioravantti
58deeb088d Raises error on deprecated methods. 2015-10-22 18:56:50 +02:00
Guido Fioravantti
d14436da6c Renames test file 173 2015-10-22 17:14:13 +02:00
Guido Fioravantti
974f7f9899 Fixes tests 173 2015-10-22 17:08:23 +02:00
Guido Fioravantti
8479c3375b Adds CDB_Unique_Column_Identifier for columns 173 2015-10-22 17:01:47 +02:00
Guido Fioravantti
0d1ba2538b Adds test for new CDB_Helper 173 2015-10-22 16:18:46 +02:00
Guido Fioravantti
5dfe56a664 Moves new CDB_Unique_Identifier and _CDB_Octet_Trim to CDB_Helper.sql file 2015-10-22 12:38:00 +02:00
Guido Fioravantti
5f46ff10e9 Doc change 172 2015-10-21 17:35:13 +02:00
Guido Fioravantti
7c14dd8212 Adds new functions to generate length aware identifiers 172 2015-10-21 17:33:01 +02:00
Luis Bosque
cf2587ca54 New version 0.11.2 2015-10-19 14:35:10 +02:00
Luis Bosque
d1d5ed6df3 Optimize invalidation time logging 2015-10-19 14:09:52 +02:00
Luis Bosque
37160c7b35 Write invalidation duration in postgresql log 2015-10-16 18:23:18 +02:00
Alejandro Martínez
811c7474de Merge pull request #170 from CartoDB/fix-schema-group-sequence
Fix schema not being specified on pg_get_serial_sequence
2015-10-15 17:39:46 +02:00
Stuart Lynn
66249843e8 making some text lowercase 2015-10-14 12:12:12 -04:00
Stuart Lynn
2908c270b3 Fixing typo with symlink 2015-10-14 11:57:36 -04:00
Stuart Lynn
eb475fe55f Adding function to produce a great circle between two points. 2015-10-14 11:36:48 -04:00
Alejandro Martínez
1f63811383 Fix schema not being specified on pg_get_serial_sequence 2015-10-06 18:09:37 +02:00
Rafa de la Torre
913bfd72f8 New version 0.11.1
- Added CDB_DateToNumber(timestamp with time zone) [#169](https://github.com/CartoDB/cartodb-postgresql/pull/169)
- cartodbfy now discards cartodb_id candidates that contain nulls [#148](https://github.com/CartoDB/cartodb-postgresql/issues/148)
2015-10-06 14:45:35 +02:00
Rafa de la Torre
15dd4935d6 Merge pull request #168 from CartoDB/148-cartodbfy-checks-for-null-cartodb-id
148 cartodbfy checks for null cartodb id
2015-10-06 14:39:00 +02:00
Rafa de la Torre
39e558f494 Merge pull request #169 from CartoDB/2202-DateToNumber-with-time-zones
Changes CDB_DateToNumber() to accept timestamps with time zones 2202
2015-10-06 12:52:52 +02:00
Guido Fioravantti
03636fafc4 Update CONTRIBUTING.md 2015-10-06 11:33:56 +02:00
Guido Fioravantti
6b3b28f01f Makes CDB_DateToNumber() tests more intuitive 2202 2015-10-05 14:56:45 +02:00
Guido Fioravantti
186ed34ee5 Overloads CDB_DateToNumber() and adds test 2015-10-05 13:32:03 +02:00
Guido Fioravantti
e4ce12d1a3 Changes CDB_DateToNumber() to accept timestamps with time zones 2202 2015-10-05 11:51:13 +02:00
Guido Fioravantti
5de395a4a8 Uses CDB_CartodbfyTableCheck() 148 2015-09-29 19:01:30 +02:00
Guido Fioravantti
3429e93979 Makes cartodbfy check for null cartodb_id 2015-09-29 18:04:00 +02:00
Guido Fioravantti
777e8c6e4c Adds test to check cartodbfy works with null cartodb_id 2015-09-29 18:03:20 +02:00
Juan Ignacio Sánchez Lara
bce61c1e43 Merge pull request #104 from CartoDB/103-Extension_Group_API
103 extension group api
2015-09-28 10:30:32 +02:00
Juan Ignacio Sánchez Lara
1f72be0390 Merge branch 'master' into 103-Extension_Group_API 2015-09-28 09:48:46 +02:00
Juan Ignacio Sánchez Lara
a59a95fddc Merge pull request #165 from CartoDB/162-Allow_non_sync_group_permission_management_queries
162 allow non sync group permission management queries
2015-09-28 09:42:54 +02:00
Juan Ignacio Sánchez Lara
0081ec16a9 Sync-flag functions should be private 2015-09-27 18:42:24 +02:00
Juan Ignacio Sánchez Lara
e7008d04ee https support back 2015-09-25 19:13:04 +02:00
Juan Ignacio Sánchez Lara
3330421887 sync parameter at group functions closes #162 2015-09-25 19:02:39 +02:00
Rafa de la Torre
7d106e68b0 Merge pull request #161 from CartoDB/160-add-drop-function-if-exists
Add DROP FUNCTION back to allow migrations #160
2015-09-24 18:26:30 +02:00
Rafa de la Torre
567e815fd0 Add DROP FUNCTION back to allow migrations #160 2015-09-24 17:56:00 +02:00
Juan Ignacio Sánchez Lara
a0204d50db X-Forwarded-Proto 2015-09-21 19:01:40 +02:00
Juan Ignacio Sánchez Lara
a2ddb76ef3 Shorter admin role name 2015-09-21 16:31:12 +02:00
Juan Ignacio Sánchez Lara
cc1e357caa Removed unnecessary EXECUTEs 2015-09-21 15:47:52 +02:00
Juan Ignacio Sánchez Lara
0e4f3955f6 1108 separator for cleaner SQL 2015-09-21 15:37:10 +02:00
Juan Ignacio Sánchez Lara
8fdf5cb9c4 Merge branch 'master' into 103-Extension_Group_API 2015-09-21 14:52:37 +02:00
Rafa de la Torre
255618f57d Merge pull request #159 from CartoDB/fix-type-already-exists
Fix creation of type _cdb_has_usable_geom_record
2015-09-21 14:50:44 +02:00
Juan Ignacio Sánchez Lara
bf4f30c99d Removed IMMUTABLE for functions depending on current database 2015-09-21 14:35:28 +02:00
Rafa de la Torre
5ea1b7d4d7 Fix creation of type _cdb_has_usable_geom_record
Fix the ERROR:  type "_cdb_has_usable_geom_record" already exists by
checking for existence before. Duly noted for upgrades.
2015-09-21 14:16:32 +02:00
Juan Ignacio Sánchez Lara
963f8ea97b #103 0.11.0 version 2015-09-21 12:54:14 +02:00
Juan Ignacio Sánchez Lara
458cbf2a80 Merge branch 'master' into 103-Extension_Group_API 2015-09-21 12:21:58 +02:00
Rafa de la Torre
0c14df5f89 Fix upgrade from 0.10.0 to 0.10.1 2015-09-16 14:40:18 +02:00
Rafa de la Torre
c2780773d2 Update NEWS.md and version to 0.10.1 2015-09-16 12:40:14 +02:00
Rafa de la Torre
14508ff5f3 Merge pull request #152 from CartoDB/141-fix-table-multiple-geometry-columns
141 fix table multiple geometry columns
2015-09-16 12:22:49 +02:00
Rafa de la Torre
6ba809e798 Remove usage of _CDB_Geometry_SRID #154
This is only used from _CDB_Has_Usable_Geom. It doesn't do what's
promised in the comment. The effect is that a column is taken as valid
when it actually needs setting its SRID restriction so better not use
it as it will need rewrite anyway.
2015-09-16 12:17:40 +02:00
Rafa de la Torre
c8e3cf5500 Add test courtesy of Paul #154 2015-09-16 12:17:35 +02:00
Rafa de la Torre
d268497030 Add expectation for new test #141 2015-09-15 19:14:06 +02:00
Rafa de la Torre
fa514a3b7c Add a couple of NOTICE's to expectations #141 2015-09-15 18:49:59 +02:00
Rafa de la Torre
0ebd12a0eb Avoid double-escaping of reloid::text #141 2015-09-15 18:49:59 +02:00
Rafa de la Torre
e7c974e957 Fix silly typo #141 2015-09-15 18:49:59 +02:00
Rafa de la Torre
789e89a5d2 Create a return type for _cdb_has_usable_geom_record #141 2015-09-15 18:49:59 +02:00
Rafa de la Torre
3fdce65368 Move column renaming out of _CDB_Has_Usable_Geom #141 2015-09-15 18:49:59 +02:00
Rafa de la Torre
5caddc6cc7 Fix for MultiPoint geometry issue #141 2015-09-15 18:49:59 +02:00
Rafa de la Torre
fc0e883c20 First version of the cartodbfy requirements 2015-09-15 11:51:27 +02:00
Rafa de la Torre
9d8d79eb40 Slightly improve the test #141 2015-09-14 17:55:30 +02:00
Rafa de la Torre
1596bd56d8 Improve another EXECUTE+FOUND #141 2015-09-14 17:54:35 +02:00
Rafa de la Torre
dfd0454be3 Improve comment #141 2015-09-14 17:53:34 +02:00
Rafa de la Torre
731ee0a9ba Fix the_geom_webmercator already exists #141 2015-09-14 17:06:24 +02:00
Rafa de la Torre
e3bba2ee4b Fix the_geom already exists error #141 2015-09-14 17:05:14 +02:00
Rafa de la Torre
581835d4ff Extract query into _cdb_geom_candidate_columns #141 2015-09-14 11:50:10 +02:00
Rafa de la Torre
9ec24c1aff Fix FOUND in _CDB_Geometry_SRID #141 2015-09-14 11:18:12 +02:00
Rafa de la Torre
e546c15770 Test for failing scenario #141 2015-09-11 16:16:54 +02:00
Rafa de la Torre
c12ae7f4a8 Merge pull request #146 from CartoDB/138-fix-cartodbfy-no-default-seq-value3
138 fix cartodbfy no default seq value3
2015-09-11 11:00:04 +02:00
Rafa de la Torre
7a247c1ab2 Recover usage of cartodb id if has_usable_primary_key #138 2015-09-10 18:20:52 +02:00
Rafa de la Torre
85b206fdba Improve test about existing cartodb_id values #138 2015-09-10 18:18:13 +02:00
Rafa de la Torre
75b37d5a88 Improve tests #138 2015-09-09 18:34:55 +02:00
Rafa de la Torre
ef21128099 Explicitly check if there's a sequence on PK #138 2015-09-09 18:33:06 +02:00
Rafa de la Torre
497034c285 Add test for failing scenario #138 2015-09-09 18:33:06 +02:00
Rafa de la Torre
6e4a5b5635 Add CASCADE to DROP SCHEMA... in tear_down #138 2015-09-09 18:33:06 +02:00
Raul Ochoa
d67f097703 Merge pull request #145 from CartoDB/fix-cdb_stats-test
Do not use random() for the distribution to test CDB_Stats functions
2015-09-09 17:12:07 +02:00
Alejandro Martínez
c460b59c07 Merge pull request #143 from CartoDB/readd-update-updated-at
Readd update_updated_at function (still used by old tables)
2015-09-09 17:09:06 +02:00
Raul Ochoa
1853ee6306 Do not use random() for the distribution to test CDB_Stats functions
Fixes #144
2015-09-09 17:08:32 +02:00
Alejandro Martínez
9ec5d9000a Readd update_updated_at function (still used by old tables) 2015-09-09 14:56:34 +02:00
Juan Ignacio Sánchez Lara
206cee1647 Deletion operations return 204 2015-09-09 12:24:54 +02:00
Juan Ignacio Sánchez Lara
f70fd1a4c7 Merge branch 'master' into 103-Extension_Group_API 2015-09-07 13:37:21 +02:00
Raul Ochoa
0ec579984b Stubs next version 2015-09-07 13:17:22 +02:00
Raul Ochoa
c6f2903221 Release 0.10.0 2015-09-07 13:16:27 +02:00
Raul Ochoa
03f42e36c9 Update news and bump version 2015-09-07 13:02:05 +02:00
Raul Ochoa
af546b35ab Merge pull request #134 from CartoDB/cdb_querytables_quoted
Quote schema and table names returned by CDB_QueryTables
2015-09-07 12:20:17 +02:00
Raul Ochoa
5abe6e0b3d Merge branch 'master' into cdb_querytables_quoted
Conflicts:
	test/extension/test.sh
2015-09-07 12:17:36 +02:00
Raul Ochoa
1eabc5e880 Merge pull request #131 from CartoDB/column-regclass-functions
Column regclass
2015-09-07 12:11:59 +02:00
Raul Ochoa
c6cdaea626 Merge pull request #124 from CartoDB/add-kurtosis
Add kurtosis and skewness
2015-09-07 12:11:34 +02:00
Juan Ignacio Sánchez Lara
7b04267366 Merge pull request #137 from CartoDB/136-Add_support_for_adding_a_batch_of_users_to_a_group
136 add support for adding a batch of users to a group
2015-09-07 11:48:53 +02:00
Juan Ignacio Sánchez Lara
275e5154fd Fixed comment 2015-09-07 11:48:18 +02:00
Juan Ignacio Sánchez Lara
4405ecb466 Multiple users test 2015-09-07 11:43:57 +02:00
Juan Ignacio Sánchez Lara
154eff6d25 Array notation for batch group functions 2015-09-07 11:43:46 +02:00
Juan Ignacio Sánchez Lara
b73eb486a5 Old functions cleanup 2015-09-07 10:35:32 +02:00
Juan Ignacio Sánchez Lara
59d144d91d Batch add/remove users support 2015-09-07 10:35:04 +02:00
Juan Ignacio Sánchez Lara
428a2391ad Refactor Member -> User 2015-09-07 09:56:59 +02:00
Andy Eschbacher
b5a9fb9fcf Merge branch 'add-kurtosis' of https://github.com/CartoDB/cartodb-postgresql into add-kurtosis 2015-09-03 22:44:06 -04:00
Andy Eschbacher
83b7f47617 removing raise notices and lower test bounds 2015-09-03 22:43:25 -04:00
Raul Ochoa
25cf48d4a4 Raise min message so we don't have to validate notices 2015-09-04 00:02:30 +02:00
Raul Ochoa
29efdf2ee7 Fix symlink for CDB_Stats.sql 2015-09-04 00:00:30 +02:00
Juan Ignacio Sánchez Lara
0896b1451a Spaces support fixes #135 2015-09-03 20:41:19 +02:00
Juan Ignacio Sánchez Lara
dfec191a9a Support for spaces inside group names, fixed 2015-09-03 16:51:06 +02:00
Juan Ignacio Sánchez Lara
1b5b3f741f Support for spaces inside group names 2015-09-03 16:38:12 +02:00
Raul Ochoa
4be7d4a497 Use quote_ident to quote schema and table names when necessary
Fixes #133
2015-09-03 13:12:29 +02:00
Raul Ochoa
350c76f847 Add option to run tests by prefix
`bash test/extension/test.sh test_cdb_querytables`
will run all tests that start with test_cdb_querytables
2015-09-03 12:59:20 +02:00
Andy Eschbacher
d00e71309d really add tests 2015-09-02 22:35:03 -04:00
Andy Eschbacher
07280321ab adding tests 2015-09-02 22:19:07 -04:00
Raul Ochoa
e28b6344aa Assert it's not possible to get column names from a table without permissions 2015-09-02 12:32:43 +02:00
Raul Ochoa
2867a6fbad Assert user can use its schema to retrieve column names 2015-09-02 12:32:34 +02:00
Raul Ochoa
afecef0e31 Removing redundant ::regclass casting 2015-09-02 12:25:44 +02:00
Raul Ochoa
7582f2cbc5 CDB_ColumnType uses schema and table from regclass
Fixes #130
2015-09-02 12:06:04 +02:00
Raul Ochoa
4b5c5dd275 CDB_ColumnNames uses schema and table name from regclass
Fixes #122
2015-09-02 12:04:52 +02:00
Raul Ochoa
eb6fc4fefb Use CDB_ColumnType and CDB_ColumnNames in bash tests 2015-09-02 12:01:43 +02:00
Rafa de la Torre
4fe85a6a76 Merge pull request #129 from CartoDB/120-fix-extension-upgrade
Do not remove old function #120
2015-08-31 14:05:55 +02:00
Juan Ignacio Sánchez Lara
a003ab7f6a Merge branch 'master' into 103-Extension_Group_API 2015-08-31 13:27:21 +02:00
Rafa de la Torre
2269dc0cb5 Add explanation in NEWS file #120
as suggested in PR.
2015-08-31 12:56:16 +02:00
Rafa de la Torre
0ba57f436a Do not remove old function #120
The `DROP FUNCTION IF EXISTS` was added as transient code and not needed
anymore. See the ticket #120 for more information on this.
2015-08-31 12:01:04 +02:00
Juan Ignacio Sánchez Lara
15aece1fbc Use %s for sequence name, which is already quoted 2015-08-27 17:03:13 +02:00
Juan Ignacio Sánchez Lara
e1f8a65cce Use %s for sequence name, which is already quoted 2015-08-27 17:02:05 +02:00
Juan Ignacio Sánchez Lara
fc32d457eb String interpolation with %I, which includes quoting 2015-08-27 10:25:52 +02:00
Juan Ignacio Sánchez Lara
a4952f6a1e Granting RW permission on a table should also grant permission on default values sequences 2015-08-26 13:33:01 +02:00
Juan Ignacio Sánchez Lara
1f67b52bf7 Documented the need for create extension and separated from cdb_conf creation 2015-08-26 13:23:32 +02:00
Andy Eschbacher
14e2a65523 adding symlink 2015-08-25 23:11:09 -04:00
Andy Eschbacher
d723487f67 updated definition 2015-08-25 23:10:26 -04:00
Andy Eschbacher
db323f3e13 adding skewness 2015-08-25 22:58:31 -04:00
Andy Eschbacher
49c4cea4e7 adding kurtosis 2015-08-25 22:45:55 -04:00
Juan Ignacio Sánchez Lara
c6fa292f01 Extension installation ready 2015-08-20 17:39:28 +02:00
Juan Ignacio Sánchez Lara
faa4f203d6 Changed sample config 2015-08-20 17:32:36 +02:00
Juan Ignacio Sánchez Lara
66e2082266 Missing cartodb schema 2015-08-20 13:02:02 +02:00
Juan Ignacio Sánchez Lara
43d41e5c26 Removed cached (won't work between sessions) 2015-08-20 12:55:22 +02:00
Juan Ignacio Sánchez Lara
bd31419e94 Fixed return auth 2015-08-20 12:54:46 +02:00
Juan Ignacio Sánchez Lara
a885f5328e Fix conf tests (json values) 2015-08-20 10:45:24 +02:00
Juan Ignacio Sánchez Lara
600f9159fb {} >> dict() 2015-08-20 10:25:31 +02:00
Juan Ignacio Sánchez Lara
eb912b48bf Removed not needed json import 2015-08-20 10:22:44 +02:00
Juan Ignacio Sánchez Lara
9c70e5f91a Merge branch 'master' into 103-Extension_Group_API 2015-08-20 10:17:00 +02:00
Juan Ignacio Sánchez Lara
551e09ff6f Secured _CDB_Group_API_Request 2015-08-20 10:03:48 +02:00
Juan Ignacio Sánchez Lara
97dd8e5720 Conf value type to json 2015-08-20 08:44:59 +02:00
Juan Ignacio Sánchez Lara
e1d195a21f Merge branch 'master' into 103-Extension_Group_API 2015-08-19 18:51:37 +02:00
Juan Ignacio Sánchez Lara
75c4308ea9 Grant and revoking permissions API sync 2015-08-19 18:43:25 +02:00
Juan Ignacio Sánchez Lara
70fe432102 Secured configuration access 2015-08-19 11:20:06 +02:00
Juan Ignacio Sánchez Lara
e1dde3c36c Removed old code 2015-08-19 11:08:05 +02:00
Juan Ignacio Sánchez Lara
6c1369f2a9 Documentation about roles and functions 2015-08-19 11:05:32 +02:00
Juan Ignacio Sánchez Lara
726f3c31f7 Documentation about roles and functions 2015-08-19 11:03:07 +02:00
Juan Ignacio Sánchez Lara
2245c05b1e Don't allow users to pick database name, keeping group operations inside their org 2015-08-19 10:52:07 +02:00
Juan Ignacio Sánchez Lara
1fe9bb2e84 Don't allow users to pick database name, keeping group operations inside their org 2015-08-19 10:37:52 +02:00
Juan Ignacio Sánchez Lara
0cb55d043a Revoke select on table and add security definer for conf getter 2015-08-19 10:35:23 +02:00
Juan Ignacio Sánchez Lara
8a8d4b5b00 Don't upgrade version until release is planned 2015-08-18 16:09:34 +02:00
Juan Ignacio Sánchez Lara
fd25a02b45 Merge branch 'master' into 103-Extension_Group_API 2015-08-18 16:07:22 +02:00
Juan Ignacio Sánchez Lara
67d7e28684 409 is a valid renaming response 2015-08-18 13:26:23 +02:00
Juan Ignacio Sánchez Lara
a8b9ec345a valid_return_codes parameter 2015-08-18 11:53:38 +02:00
Juan Ignacio Sánchez Lara
a75a337296 _CDB_Conf_Cache SD-based 2015-08-18 10:44:10 +02:00
Juan Ignacio Sánchez Lara
1217b4e4a4 Cache http client with private SD 2015-08-18 08:27:14 +02:00
Juan Ignacio Sánchez Lara
d6410d91bd Cache http client 2015-08-18 08:24:30 +02:00
Juan Ignacio Sánchez Lara
9d03e755b8 _CDB_Group_API_Request refactor 2015-08-18 08:10:02 +02:00
Juan Ignacio Sánchez Lara
87a955b56a Removed cdb_ prefix from local variables 2015-08-17 15:23:39 +02:00
Juan Ignacio Sánchez Lara
653eae21b3 _CDB_Group_RemoveMember_API 2015-08-17 15:20:15 +02:00
Juan Ignacio Sánchez Lara
e4a56371c0 _CDB_Group_AddMember_API 2015-08-17 15:05:09 +02:00
Juan Ignacio Sánchez Lara
00e9cc5a79 Explicit null check for not found role 2015-08-17 15:02:21 +02:00
Juan Ignacio Sánchez Lara
566adfb0ce CDB_Group_RenameGroup_API 2015-08-17 13:37:34 +02:00
Juan Ignacio Sánchez Lara
99641b827c Authorization type moved to function 2015-08-17 12:55:42 +02:00
Juan Ignacio Sánchez Lara
df531e9e37 auth inside param reading 2015-08-17 12:26:38 +02:00
Juan Ignacio Sánchez Lara
6c3555f21a Configuration parameters refactor 2015-08-17 11:49:31 +02:00
Juan Ignacio Sánchez Lara
a08600a1f8 Exclude cartodb schema from CDB_UserTables 2015-08-14 16:31:19 +02:00
Juan Ignacio Sánchez Lara
e11f4ef169 Group name validation delegated to role creation 2015-08-14 15:40:36 +02:00
Juan Ignacio Sánchez Lara
db89bf1a94 Grant select on configuration table to org members 2015-08-14 15:28:19 +02:00
Juan Ignacio Sánchez Lara
466e4d81c6 format instead of string concatenation 2015-08-14 15:22:00 +02:00
Juan Ignacio Sánchez Lara
ae634e7814 Server notification must happen after role creation 2015-08-14 15:04:14 +02:00
Juan Ignacio Sánchez Lara
d1f19a0234 Groups API configuration example 2015-08-14 14:03:53 +02:00
Juan Ignacio Sánchez Lara
d4bcb97f9b CDB_CONF and create and drop group api calls 2015-08-14 14:00:58 +02:00
Juan Ignacio Sánchez Lara
a0aac4e9c9 Info about if not exist log output 2015-08-14 14:00:58 +02:00
Juan Ignacio Sánchez Lara
725453ce2b Configuration table and functions 2015-08-14 14:00:58 +02:00
Juan Ignacio Sánchez Lara
7262d34b06 IMMUTABLE-STABLE-VOLATILE specification 2015-08-14 14:00:58 +02:00
Juan Ignacio Sánchez Lara
3ee4978240 Roles simplification, without md5 and prepending database name 2015-08-14 14:00:57 +02:00
Juan Ignacio Sánchez Lara
2ece2979a6 Drop cartodb schema before dropping publicuser 2015-08-14 14:00:57 +02:00
Juan Ignacio Sánchez Lara
401d3e9066 publicuser back 2015-08-14 14:00:57 +02:00
Juan Ignacio Sánchez Lara
79e1926766 Group management done by organization admin 2015-08-14 14:00:57 +02:00
Juan Ignacio Sánchez Lara
e2dd1e014e test_valid_group_names and test_not_valid_group_names 2015-08-14 14:00:57 +02:00
Juan Ignacio Sánchez Lara
1915e28a0f Cleaner debug output 2015-08-14 14:00:57 +02:00
Juan Ignacio Sánchez Lara
bd46796bb7 Fix spacing 2015-08-14 14:00:57 +02:00
Juan Ignacio Sánchez Lara
898d3c14fd test_group_management_functions_cant_be_used_by_normal_members and warning -> error processing 2015-08-14 14:00:57 +02:00
Juan Ignacio Sánchez Lara
154f6df1dc _CDB_Group_GroupRole based on current database m5 2015-08-14 14:00:57 +02:00
Juan Ignacio Sánchez Lara
9a3fbb668c Dynamic variable binding 2015-08-14 14:00:57 +02:00
Juan Ignacio Sánchez Lara
6baa626756 Groups will be 0.9.0 2015-08-14 14:00:56 +02:00
Juan Ignacio Sánchez Lara
c29733eb87 publicuser uncommenting 2015-08-14 14:00:26 +02:00
Juan Ignacio Sánchez Lara
52f73b1a01 CDB_Group_Table_GrantReadWrite 2015-08-14 14:00:26 +02:00
Juan Ignacio Sánchez Lara
28af048c92 Methods doc 2015-08-14 14:00:26 +02:00
Juan Ignacio Sánchez Lara
1279742e50 CDB_Group_CreateGroup should not return role, since it's an internal implementation detail 2015-08-14 14:00:26 +02:00
Juan Ignacio Sánchez Lara
b633466724 Non-public API method naming 2015-08-14 14:00:26 +02:00
Juan Ignacio Sánchez Lara
e04f0caa6c Permission granting 2015-08-14 14:00:25 +02:00
Juan Ignacio Sánchez Lara
5afdd77dcf Rename group 2015-08-14 14:00:25 +02:00
Juan Ignacio Sánchez Lara
eafb0f4557 Groups API extension version 2015-08-14 14:00:25 +02:00
Juan Ignacio Sánchez Lara
42e72ac9d5 cartodb.CDB_Group_CreateGroup cartodb.CDB_Group_DropGroup 2015-08-14 13:58:10 +02:00
Juan Ignacio Sánchez Lara
2824a9c457 Ignore vim temporal files 2015-08-14 13:58:10 +02:00
158 changed files with 12196 additions and 1750 deletions

3
.gitignore vendored
View File

@@ -5,4 +5,5 @@ results/
regression.*
expected/test
sql/test
.idea/*
.idea/*
*.swp

View File

@@ -1,25 +1,43 @@
language: c
sudo: required
addons:
postgresql: 9.3
env:
global:
- PGUSER=postgres
- PGDATABASE=postgres
- PGOPTIONS='-c client_min_messages=NOTICE'
- PGPORT=5432
before_install:
- sudo apt-get update
#- sudo apt-get install -q postgresql-9.3-postgis-2.1
- sudo apt-get update
- sudo apt-get install -q postgresql-server-dev-9.3
- sudo apt-get install -q postgresql-plpython-9.3
# Install schema_triggers
- hg clone https://bitbucket.org/malloclabs/pg_schema_triggers &&
cd pg_schema_triggers && make && sudo make install && cd -
# Preload schema_triggers module
# NOTE: might change if we make it part of the installcheck instead
- echo "shared_preload_libraries = 'schema_triggers.so'" |
sudo tee -a /etc/postgresql/9.3/main/postgresql.conf &&
sudo service postgresql restart
jobs:
include:
- env: POSTGRESQL_VERSION="9.6" POSTGIS_VERSION="2.5"
dist: xenial
- env: POSTGRESQL_VERSION="10" POSTGIS_VERSION="2.5"
dist: xenial
- env: POSTGRESQL_VERSION="11" POSTGIS_VERSION="2.5"
dist: xenial
- env: POSTGRESQL_VERSION="12" POSTGIS_VERSION="2.5"
dist: bionic
- env: POSTGRESQL_VERSION="12" POSTGIS_VERSION="3"
dist: bionic
script:
- sudo service postgresql stop;
- sudo apt-get remove postgresql* -y
- sudo apt-get install -y --allow-unauthenticated --no-install-recommends --no-install-suggests postgresql-$POSTGRESQL_VERSION postgresql-client-$POSTGRESQL_VERSION postgresql-server-dev-$POSTGRESQL_VERSION postgresql-common
- if [[ $POSTGRESQL_VERSION == '9.6' ]]; then sudo apt-get install -y postgresql-contrib-9.6; fi;
- sudo apt-get install -y --allow-unauthenticated postgresql-$POSTGRESQL_VERSION-postgis-$POSTGIS_VERSION postgresql-$POSTGRESQL_VERSION-postgis-$POSTGIS_VERSION-scripts postgis
# For pre12, install plpython2. For PG12 install plpython3
- if [[ $POSTGRESQL_VERSION != '12' ]]; then sudo apt-get install -y postgresql-plpython-$POSTGRESQL_VERSION python python-redis; else sudo apt-get install -y postgresql-plpython3-12 python3 python3-redis; fi;
- sudo pg_dropcluster --stop $POSTGRESQL_VERSION main
- sudo rm -rf /etc/postgresql/$POSTGRESQL_VERSION /var/lib/postgresql/$POSTGRESQL_VERSION
- sudo pg_createcluster -u postgres $POSTGRESQL_VERSION main -- --auth-local trust --auth-host password
- sudo /etc/init.d/postgresql start $POSTGRESQL_VERSION || sudo journalctl -xe
- make
- sudo make install
- PGOPTIONS='-c client_min_messages=NOTICE' PGUSER=postgres make installcheck ||
{ cat regression.diffs; false; }
- make installcheck
after_failure:
- pg_lsclusters
- cat regression.out
- cat regression.diffs

View File

@@ -22,13 +22,18 @@ and upgrade of the objects. This means using CREATE OR REPLACE for
the functions, and whatever it takes to check existence of any previous
version of objects in other cases.
When used as an extension (probably always from version 0.2.0 onwards)
all the objects will be installed in a "cartodb" schema. Take this into
account to fully-qualify internal calls to avoid (possibly dangerous)
name clashes.
When adding a new function or modifying an exiting one make sure that the
[VOLATILITY](https://www.postgresql.org/docs/current/static/xfunc-volatility.html) and [PARALLEL](https://www.postgresql.org/docs/9.6/static/parallel-safety.html) categories are updated accordingly.
Although the extension will usually be installed in the "cartodb" schema, please
use @extschema@ to fully-qualify internal calls to avoid name clashes.
When you use postgis functions or types, please fully-qualify them by using
@postgisschema@ (it's changed to "public" by the install script) to avoid
pg_upgrade issues.
Every new feature (as well as bugfixes) should come with a test case,
see next section.
see the 'Writing testcases' section.
Writing testcases
-----------------
@@ -44,7 +49,7 @@ the extension into your test database.
During development the cartodb extension version doesn't change with
every commit, so testing latest change requires cheating with PostgreSQL
so to enforce re-load of the scripts. To help with cheating, "make install"
as to enforce the scripts to reload. To help with cheating, "make install"
also installs migration scripts to go from "V" to "V"next and from "V"next
to "V". Example to upgrade a 0.2.0dev version:
@@ -62,3 +67,7 @@ A useful query:
```sql
SELECT * FROM pg_extension_update_paths('cartodb') WHERE path IS NOT NULL AND source = cdb_version();
```
## Submitting Contributions
* You will need to sign a Contributor License Agreement (CLA) before making a submission. [Learn more here](https://carto.com/contributions).

144
Makefile
View File

@@ -1,16 +1,17 @@
# cartodb/Makefile
EXTENSION = cartodb
EXTVERSION = 0.9.4
EXTVERSION = 0.35.0
SED = sed
AWK = awk
CDBSCRIPTS = \
scripts-enabled/*.sql \
scripts-available/CDB_SearchPath.sql \
scripts-available/CDB_DDLTriggers.sql \
scripts-available/CDB_ExtensionPost.sql \
scripts-available/CDB_ExtensionUtils.sql \
scripts-available/CDB_Helper.sql \
$(END)
UPGRADABLE = \
@@ -47,6 +48,66 @@ UPGRADABLE = \
0.9.2 \
0.9.3 \
0.9.4 \
0.10.0 \
0.10.1 \
0.10.2 \
0.11.0 \
0.11.1 \
0.11.2 \
0.11.3 \
0.11.4 \
0.11.5 \
0.12.0 \
0.13.0 \
0.13.1 \
0.14.0 \
0.14.1 \
0.14.2 \
0.14.3 \
0.14.4 \
0.15.0 \
0.15.1 \
0.16.0 \
0.16.1 \
0.16.2 \
0.16.3 \
0.16.4 \
0.17.0 \
0.17.1 \
0.18.0 \
0.18.1 \
0.18.2 \
0.18.3 \
0.18.4 \
0.18.5 \
0.19.0 \
0.19.1 \
0.19.2 \
0.20.0 \
0.21.0 \
0.22.0 \
0.22.1 \
0.22.2 \
0.23.0 \
0.23.1 \
0.23.2 \
0.24.0 \
0.24.1 \
0.25.0 \
0.26.0 \
0.26.1 \
0.27.0 \
0.27.1 \
0.27.2 \
0.28.0 \
0.28.1 \
0.29.0 \
0.30.0 \
0.31.0 \
0.32.0 \
0.33.0 \
0.34.0 \
0.35.0 \
$(EXTVERSION)dev \
$(EXTVERSION)next \
$(END)
@@ -68,20 +129,29 @@ DATA_built = \
EXTRA_CLEAN = cartodb_version.sql
DOCS = README.md
REGRESS_NEW = test_ddl_triggers
REGRESS_OLD = $(wildcard test/*.sql)
REGRESS_LEGACY = $(REGRESS_OLD:.sql=)
REGRESS = test_setup $(REGRESS_NEW) $(REGRESS_LEGACY)
REGRESS = test/test_setup $(REGRESS_LEGACY)
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
$(EXTENSION)--$(EXTVERSION).sql: $(CDBSCRIPTS) cartodb_version.sql Makefile
PG_VERSION := $(shell $(PG_CONFIG) --version | $(AWK) '{split($$2,a,"."); print a[1]}')
PG_12_GE := $(shell [ $(PG_VERSION) -ge 12 ] && echo true)
PLPYTHONU := plpythonu
ifeq ($(PG_12_GE), true)
PLPYTHONU := plpython3u
endif
PGPORT ?= '5432'
PGUSER ?= 'postgres'
$(EXTENSION)--$(EXTVERSION).sql: $(CDBSCRIPTS) cartodb_version.sql Makefile
echo '\echo Use "CREATE EXTENSION $(EXTENSION)" to load this file. \quit' > $@
cat $(CDBSCRIPTS) | \
$(SED) -e 's/public\./cartodb./g' \
-e 's/:DATABASE_USERNAME/cdb_org_admin/g' >> $@
$(SED) -e 's/@extschema@/cartodb/g' \
-e 's/@postgisschema@/public/g' \
-e 's/@@plpythonu@@/$(PLPYTHONU)/g' >> $@
echo "GRANT USAGE ON SCHEMA cartodb TO public;" >> $@
cat cartodb_version.sql >> $@
@@ -95,28 +165,48 @@ $(EXTENSION)--$(EXTVERSION)--$(EXTVERSION)next.sql: $(EXTENSION)--$(EXTVERSION).
cp $< $@
$(EXTENSION).control: $(EXTENSION).control.in Makefile
$(SED) -e 's/@@VERSION@@/$(EXTVERSION)/' $< > $@
$(SED) -e 's/@@VERSION@@/$(EXTVERSION)/g' -e 's/@@plpythonu@@/$(PLPYTHONU)/g' $< > $@
cartodb_version.sql: cartodb_version.sql.in Makefile $(GITDIR)/index
$(SED) -e 's/@@VERSION@@/$(EXTVERSION)/' $< > $@
$(SED) -e 's/@@VERSION@@/$(EXTVERSION)/' -e 's/@extschema@/cartodb/g' -e "s/@postgisschema@/public/g" -e 's/@@plpythonu@@/$(PLPYTHONU)/g' $< > $@
# Needed for consistent `echo` results with backslashes
SHELL = bash
legacy_regress: $(REGRESS_OLD) Makefile
mkdir -p sql/test/
mkdir -p expected/test/
mkdir -p results/test/
cat sql/test_setup.sql | \
$(SED) -e 's/@@VERSION@@/$(EXTVERSION)/' -e 's/@extschema@/cartodb/g' -e "s/@postgisschema@/public/g" -e 's/@@plpythonu@@/$(PLPYTHONU)/g' \
> sql/test/test_setup.sql
cp sql/test_setup_expect expected/test/test_setup.out
for f in $(REGRESS_OLD); do \
tn=`basename $${f} .sql`; \
of=sql/test/$${tn}.sql; \
echo '\\set ECHO none' > $${of}; \
echo '\\a' >> $${of}; \
echo '\\t' >> $${of}; \
echo '\\set QUIET off' >> $${of}; \
cat $${f} | \
$(SED) -e 's/public\./cartodb./g' >> $${of}; \
exp=expected/test/$${tn}.out; \
echo '\\set ECHO none' > $${exp}; \
cat test/$${tn}_expect >> $${exp}; \
done
tn=`basename $${f} .sql`; \
of=sql/test/$${tn}.sql; \
echo '\set ECHO none' > $${of}; \
echo '\a' >> $${of}; \
echo '\t' >> $${of}; \
echo '\set QUIET off' >> $${of}; \
cat $${f} | \
$(SED) -e 's/@@VERSION@@/$(EXTVERSION)/' \
-e 's/@extschema@/cartodb/g' \
-e "s/@postgisschema@/public/g" \
-e 's/@@plpythonu@@/$(PLPYTHONU)/g' \
-e 's/@@PGPORT@@/$(PGPORT)/g' \
-e 's/@@PGUSER@@/$(PGUSER)/g' \
>> $${of}; \
exp=expected/test/$${tn}.out; \
echo '\set ECHO none' > $${exp}; \
cat test/$${tn}_expect | \
$(SED) -e 's/@@VERSION@@/$(EXTVERSION)/' \
-e 's/@extschema@/cartodb/g' \
-e "s/@postgisschema@/public/g" \
-e 's/@@plpythonu@@/$(PLPYTHONU)/g' \
-e 's/@@PGPORT@@/$(PGPORT)/g' \
-e 's/@@PGUSER@@/$(PGUSER)/g' \
>> $${exp}; \
done
test_organization:
bash test/organization/test.sh
@@ -124,7 +214,15 @@ test_organization:
test_extension_new:
bash test/extension/test.sh
legacy_tests: legacy_regress
legacy_tests: legacy_regress $(EXTENSION)--unpackaged--$(EXTVERSION).sql
installcheck: legacy_tests test_extension_new test_organization
PGREGRESS := $(shell dirname `$(PG_CONFIG) --pgxs`)/../../src/test/regress/pg_regress
PGBINDIR := $(shell $(PG_CONFIG) --bindir)
PGREGRESSDATABASE = 'contrib_regression'
regress: legacy_tests
PGUSER=$(PGUSER) \
PGPORT=$(PGPORT) \
$(PGREGRESS) --inputdir=./ --bindir='$(PGBINDIR)' --dbname=$(PGREGRESSDATABASE) $(REGRESS)
installcheck: test_extension_new test_organization
$(MAKE) -C . regress

317
NEWS.md
View File

@@ -1,3 +1,320 @@
0.35.0 (2019-12-30)
* Reapply the changes in 0.33.0 (the issue we were looking for was unrelated)
* Reapply `Make PG12 depend on plpython3u instead of plpythonu`
* Fix identifier quotation in `CDB_UserDataSize`
0.34.0 (2019-12-23)
* Revert changes done in 0.33.0, keeping function signature to drop them
0.33.0 (2019-12-20)
* Revert `Make PG12 depend on plpython3u instead of plpythonu`.
* Add functions to manage Federated Tables (Foreign Data Wrapper)
0.32.0 (2019-11-08)
* Fix oAuth ownership re-assignation for functions
* Some fixes for PG12.
* Make PG12 depend on plpython3u instead of plpythonu
* CDB_UserDataSize is now compatible with postgis 3 without postgis_raster.
* Makefile: Add regress target (checks regress tests without needing to install the extension)
0.31.0 (2019-10-08)
* Ghost tables: Add missing tags (#370)
* Set search_path in security definer functions.
0.30.0 (2019-07-17)
* Added new admin functions to connect CARTO with user FDW's (#369)
0.29.0 (2019-07-15)
* Added new function CDB_OAuth:
* Install event trigger to check for table/view/sequence/function creation
* Reassign the ownership of new objects to a defined role in the cdb_conf
* Changed MakeFile to support different expects for differents PG versions
0.28.1 (2019-07-04)
* Avoid temporary tables creation in CDB_SyncTable (#366)
* Make CDB_Get_Foreign_Updated_At robust to missing CDB_TableMetadata (#362)
0.28.0 (2019-07-01)
* New function CDB_SyncTable (#355)
0.27.2 (2019-06-21)
* Improvements and fixes in Ghost tables functions (#360)
0.27.1 (2019-06-03)
* Add some qualifications that were left in the previous release.
0.27.0 (2019-06-03)
* Fully qualify function calls
* Several improvements to bash tests.
* Avoid dropping publicuser in tests.
* Raise minimum requirement to PostgreSQL 9.6.
0.26.1 (2019-03-19)
* Remove default TIS values from Ghost tables functions
0.26.0 (2019-03-11)
* Use `ST_ShiftLongitude` instead of `ST_Shift_Longitude`.
* Add Ghost tables functions to install triggers and enqueue the linking process
0.25.0 (2019-02-22)
* Add `CDB_Username` to get the cartodb username from the current PostgreSQL user
0.24.1 (2019-01-02)
* Drop functions removed in 0.12 (#341)
* Travis: Test with PostgreSQL 9.5, 10 and 11.
0.24.0 (2018-09-13)
* Travis: Test with PostgreSQL 9.5 and 10.
* _cdb_estimated_extent: Fix bug with ST_EstimatedExtent interaction.
* Improvements in `CDB_JenksBins`.
* Now it ignores NULLs.
* No longer puts the same value in multiple categories.
* Removes all limits related to size.
* If not set, the number of iterations done is based now on the size of the array.
* Fixed multiple bugs.
* The internal function `CDB_JenksBinsIteration` has changed its signature.
0.23.2 (2018-07-19)
* Fix `CDB_QueryTablesText` with parenthesized queries (#335)
0.23.1 (2018-07-19)
* Fix `CDB_EstimateRowCount` parallelizability #333
0.23.0 (2018-07-03)
* Add a new helper function `_CDB_Table_Exists(table_name_with_optional_schema TEXT)` #332
0.22.2 (2018-05-29)
* Fix: Fix hyphenates usernames in 0.22.1 fix (#331)
0.22.1 (2018-05-29)
* Fix: Correctly grant permission to all sequences related with table (#330)
0.22.0 (2018-03-22)
* Fix: allow older ogr2ogr to work in -append mode (#319,#325)
* Refactors CDB_QuantileBins to rely on PostgreSQL function `percentile_disc` #316
0.21.0 (2018-02-15)
* Add optional parameter to limit the number of cells in grid-generation functions #322
* Fix: grant usage on cartodb_id sequence when sharing read write #323
* Fix: Change sed in-place for tmpfiles 524319
0.20.0 (2017-11-08)
* Added VOLATILITY and PARALLEL categories to all functions
0.19.2 (2017-06-30)
* Improved functions to generate unique identifiers #305
0.19.1 (2017-06-05)
* Fixed a deadlock problem when trying to regenarate overviews #302
0.19.0 (2017-04-11)
* Add new function `CDB_EstimateRowCount` #295
0.18.5 (2016-11-30)
* Add to new overview creation strategies #290
* Fix tests: race condition with publicuser #157
* Fix: CDB_Stats divisions by zero #181
* Better implementation of `CDB_EqualIntervalBins` #244
* New tests for binning functions #249
0.18.4 (2016-11-04)
* No functional changes; fixes the migration from previous versions #288
0.18.3 (2016-11-03)
* Exclude analysis cache tables from the quota #281
0.18.2 (2016-10-20)
-------------------
* Fix: cleanup inconsistent position of `username` column in analysis catalog after upgrades
[#285](https://github.com/cartodb/cartodb-postgresql/pull/285)
0.18.1 (2016-10-19)
-------------------
* Increase analysis limit factor to 2 [#284](https://github.com/CartoDB/cartodb-postgresql/pull/284)
0.18.0 (2016-10-17)
-------------------
* Fix: exclude NULL geometries when creating Overviews #269
* Function to check analysis tables limits #279
0.17.1 (2016-08-16)
-------------------
* Add cache_tables column to cdb_analysis_catalog table #274.
0.17.0 (2016-07-04)
-------------------
* Add export config for cdb_analysis_catalog table #268.
* Add some extra fields to cdb_analysis_catalog table. Track user, error_message for failures, and last entity modifying the node #267.
* Exclude overviews from user data size #262.
0.16.4 (2016-05-27)
-------------------
* Change CDB_ZoomFromScale() to use a formula and raise
maximum overview level from 23 to 29.
[#259](https://github.com/CartoDB/cartodb-postgresql/pull/259)
* Fix bug in overview creating causing it to fail when `x` or
`y` columns exist with non-integer type. Prevent also
potential integer overflows limiting maximum overview level
to 23.
[#258](https://github.com/CartoDB/cartodb-postgresql/pull/258)
0.16.3 (2016-05-09)
-------------------
* Fix overview creation problem for organization users
with names that require quoting:
[#253](https://github.com/CartoDB/cartodb-postgresql/pull/253)
0.16.2 (2016-04-27)
-------------------
* Use the mode to aggregate category columns in overviews
[#246](https://github.com/CartoDB/cartodb-postgresql/pull/246)
0.16.1 (2016-04-25)
-------------------
* Optimize column information functions performance
[#238](https://github.com/CartoDB/cartodb-postgresql/pull/238)
* Adjust overview points to pixel CDB_EqualIntervalBins
[#242](https://github.com/CartoDB/cartodb-postgresql/pull/242)
* Compute webmercator resolution using full numeric precision
[#243](https://github.com/CartoDB/cartodb-postgresql/pull/243)
0.16.0 (2016-04-15)
-------------------
* Adds table for storing camshaft analysis nodes
[#237](https://github.com/CartoDB/cartodb-postgresql/pull/237)
0.15.1 (2016-04-15)
-------------------
* Fix problems with org users in overviews functions
[#224](https://github.com/CartoDB/cartodb-postgresql/pull/224)
* Add `_feature_count` to overviews
[#227](https://github.com/CartoDB/cartodb-postgresql/pull/227)
* Change point clustering behaviour of overviews
[#228](https://github.com/CartoDB/cartodb-postgresql/pull/228)
* Change default tolerance of overviews
[#230](https://github.com/CartoDB/cartodb-postgresql/pull/230)
* Fix problem with aggregated numerical fields in overviews
[#233](https://github.com/CartoDB/cartodb-postgresql/pull/233)
* Enhance aggregation of text fields in overviews
[#234]https://github.com/CartoDB/cartodb-postgresql/pull/234
0.15.0 (2016-04-05)
-------------------
* New function CDB_CreateOverviewsWithToleranceInPixels that adds tolerance parameter for overview creation
[#221](https://github.com/CartoDB/cartodb-postgresql/pull/221)
* New default value for the overviews tolerance in pixels is 2 (used to be 7.5) (also in #221)
* The feature density limit used to choose the reference Z level now depends on the tolerance in pixels (also in #221)
* Tables that require an explicit schema can now be passed to overview functions
[#220](https://github.com/CartoDB/cartodb-postgresql/pull/220)
0.14.4 (2016-03-29)
-------------------
* Fix creating overviews for tables with boolean columns
[#214](https://github.com/CartoDB/cartodb-postgresql/pull/214)
* Fix tests for some systems [#215](https://github.com/CartoDB/cartodb-postgresql/pull/215)
0.14.3 (2016-03-17)
-------------------
* Fix for `cartodb_id` bigint casting hardcoded in 0.14.2 to support `cartodb_id` text columns [#210](https://github.com/CartoDB/cartodb-postgresql/pull/210)
0.14.2 (2016-03-15)
-------------------
* Support text `cartodb_id` columns in `_CDB_Has_Usable_Primary_ID` [#202](https://github.com/CartoDB/cartodb-postgresql/pull/202)
0.14.1 (2016-03-07)
-------------------
* Fully qualify table names in cache cdb_invalidate_varnish calls [#198](https://github.com/CartoDB/cartodb-postgresql/issues/198)
0.14.0 (2016-02-14)
-------------------
* Add CDB_ForeignTable.sql to support FDW's [#199](https://github.com/CartoDB/cartodb-postgresql/pull/199)
0.13.1 (2016-02-01)
-------------------
* Fix migration fron unpackaged. [193](https://github.com/CartoDB/cartodb-postgresql/pull/193)
0.13.0 (2016-01-29)
-------------------
* Add CDB_CreateOverviews, CDB_DropOverviews and CDB_Overviews for vector overviews support. [185](https://github.com/CartoDB/cartodb-postgresql/pull/185)
* Convert some simple functions from plpgsql to sql. [188](https://github.com/CartoDB/cartodb-postgresql/pull/188)
0.12.0 (2016-01-27)
-------------------
* Remove schema_triggers extension dependency, to ensure compatibility with PostgreSQL 9.5. [#190](https://github.com/CartoDB/cartodb-postgresql/pull/190)
* Remove DDL trigger functions (unused by CartoDB).
0.11.5 (2015-11-27)
-------------------
* Disable log invalidation time [#178](https://github.com/CartoDB/cartodb-postgresql/pull/178)
0.11.4 (2015-11-24)
-------------------
* Fix for existing PK cartodb_id problem [#174](https://github.com/CartoDB/cartodb-postgresql/issues/174)
* Add cartodbfication support for column names with embedded points to fix [#6114](https://github.com/CartoDB/cartodb/issues/6114)
* Add CDB_GreatCircle for creating great circle routes between two points [#171](https://github.com/CartoDB/cartodb-postgresql/pull/171)
* Fix to prevent cartodbfication problems [#155](https://github.com/CartoDB/cartodb-postgresql/issues/155)
0.11.3 (2015-10-27)
-------------------
* Added CDB_Helper.sql [#173](https://github.com/CartoDB/cartodb-postgresql/pull/173)
* Added `_CDB_Unique_Identifier` for creating UTF8 aware unique identifiers
* Added `_CDB_Unique_Column_Identifier` for creating UTF8 aware unique identifiers for columns
* Added `_CDB_Octet_Truncate` that truncates text to a certain amount of octets.
0.11.2 (2015-10-19)
-------------------
* Fix schema not being specified on pg_get_serial_sequence [#170](https://github.com/CartoDB/cartodb-postgresql/pull/170)
* Log invalidation function call duration in seconds [#163](https://github.com/CartoDB/cartodb-postgresql/pull/163)
0.11.1 (2015-10-06)
-------------------
* Added CDB_DateToNumber(timestamp with time zone) [#169](https://github.com/CartoDB/cartodb-postgresql/pull/169)
* cartodbfy now discards cartodb_id candidates that contain nulls [#148](https://github.com/CartoDB/cartodb-postgresql/issues/148)
0.11.0 (2015-09-dd)
-------------------
* Groups API
0.10.2 (2015-09-24)
-------------------
* Add back the `DROP FUNCTION IF EXISTS CDB_UserTables(text);` to be able to upgrade from `0.7.3` upward [#160](https://github.com/CartoDB/cartodb-postgresql/issues/160)
0.10.1 (2015-09-16)
-------------------
* Get back the `update_updated_at` function (still used by old tables) [#143](https://github.com/CartoDB/cartodb-postgresql/pull/143)
* Fix for CDB_StatsTest.sql test failing randomly [#144](https://github.com/CartoDB/cartodb-postgresql/issues/144)
* Fix for table cartodbfy'ed without default seq value [#138](https://github.com/CartoDB/cartodb-postgresql/issues/138)
* Fix for cartodbfy error column `the_geom` already exists [#141](https://github.com/CartoDB/cartodb-postgresql/issues/141)
* Fix for columns with geometry cartodbfy'ed without SRID [#154](https://github.com/CartoDB/cartodb-postgresql/issues/154)
0.10.0 (2015-09-07)
-----------------
* Quote schema and table names returned by CDB_QueryTables [#134](https://github.com/CartoDB/cartodb-postgresql/pull/134). Use quote_ident to quote schema and table names when necessary.
* Fixed CDB_ColumnNames [#122](https://github.com/CartoDB/cartodb-postgresql/issues/122) and CDB_ColumnType [#130](https://github.com/CartoDB/cartodb-postgresql/issues/130) should honor regclass, returning columns for just the table in the schema and not in any other one [#131](https://github.com/CartoDB/cartodb-postgresql/pull/131).
* Add kurtosis and skewness [#124](https://github.com/CartoDB/cartodb-postgresql/pull/124).
* Removed `DROP FUNCTION IF EXISTS cdb_usertables(text);` [#129](https://github.com/CartoDB/cartodb-postgresql/pull/129). This was needed for upgrading between 0.7.4 to 0.8.0 but is no longer needed.
0.9.4 (2015-08-28)
------------------
* Fixed issue with indices when renaming tables [#123](https://github.com/CartoDB/cartodb-postgresql/issues/123)

View File

@@ -1,21 +1,18 @@
cartodb-postgresql
==================
[![Build Status](http://travis-ci.org/CartoDB/cartodb-postgresql.png)]
(http://travis-ci.org/CartoDB/cartodb-postgresql)
[![Build Status](http://api.travis-ci.org/CartoDB/cartodb-postgresql.svg?branch=master)](http://travis-ci.org/CartoDB/cartodb-postgresql)
PostgreSQL extension for CartoDB
See https://github.com/CartoDB/cartodb/wiki/CartoDB-PostgreSQL-extension
See [the cartodb-postgresql wiki](https://github.com/CartoDB/cartodb-postgresql/wiki).
Dependencies
------------
* PostgreSQL 9.3+ (with plpythonu extension and xml support)
* [PostGIS extension](http://postgis.net)
* [Schema triggers extension]
(https://bitbucket.org/malloclabs/pg_schema_triggers)
(or [fork](https://github.com/CartoDB/pg_schema_triggers))
* PostgreSQL 9.6+ (with plpythonu extension and xml support). For PostgreSQL 12+ plpython3u is required instead of plpythonu.
* [PostGIS extension](http://postgis.net)
* Python with [Redis module](https://pypi.org/project/redis/)
Install
-------
@@ -31,10 +28,6 @@ Test installation
make installcheck
```
NOTE: if ``test_ddl_triggers`` fails it's likely due to an incomplete
installation of schema_triggers: you need to add ``schema_triggers.so``
to the ``shared_preload_libraries`` setting in postgresql.conf !
NOTE: you need to run the installcheck as a superuser, use PGUSER
env variable if needed, like: PGUSER=postgres make installcheck
@@ -47,7 +40,6 @@ In a database that needs to be turned into a "cartodb" user database, run:
```sql
CREATE EXTENSION postgis;
CREATE EXTENSION schema_triggers;
CREATE EXTENSION cartodb;
```
@@ -63,7 +55,6 @@ be in the "cartodb" schema.
```sql
CREATE EXTENSION postgis FROM unpackaged;
CREATE EXTENSION schema_triggers;
CREATE EXTENSION cartodb FROM unpackaged;
```
@@ -98,3 +89,8 @@ ls `pg_config --sharedir`/extension/cartodb*
During development the cartodb extension version doesn't change with
every commit, so testing latest change requires special steps documented
in the CONTRIBUTING document, under "Testing changes live".
Limitations
-----------
- The main schema of an organization user must have one only owner (the user).

11
carto-package.json Normal file
View File

@@ -0,0 +1,11 @@
{
"name": "carto_postgresql_ext",
"current_version": {
"requires": {
"postgresql": ">=10.0.0",
"postgis": ">=2.4.0.0"
},
"works_with": {
}
}
}

View File

@@ -3,4 +3,4 @@ comment = 'Turn a database into a cartodb user database.'
superuser = true
relocatable = false
schema = cartodb
requires = 'plpythonu, schema_triggers, postgis'
requires = '@@plpythonu@@, postgis'

View File

@@ -1,6 +1,6 @@
DO $$ BEGIN IF EXISTS (SELECT * FROM pg_proc p, pg_namespace n WHERE p.proname = 'cdb_transformtowebmercator' AND p.pronamespace = n.oid AND n.nspname = 'public') THEN RAISE EXCEPTION 'Use CREATE EXTENSION cartodb FROM unpackaged'; END IF; END; $$ LANGUAGE 'plpgsql'; -- forbid duplicated extension
CREATE OR REPLACE FUNCTION cartodb.CDB_version()
CREATE OR REPLACE FUNCTION @extschema@.CDB_version()
RETURNS text AS $$
SELECT '@@VERSION@@'::text;
$$ language 'sql' IMMUTABLE STRICT;

View File

@@ -0,0 +1,25 @@
Estimate the number of rows of a query.
#### Using the function
```sql
SELECT CDB_EstimateRowCount($$
UPDATE addresses SET the_geom = cdb_geocode_street_point(addr, city, state, 'US');
$$) AS row_count;
```
Result:
```
row_count
-----------
5
(1 row)
```
#### Arguments
CDB_EstimateRowCount(query)
* **query** text: the SQL query to estimate the row count for.

16
doc/CDB_GreatCircle.md Normal file
View File

@@ -0,0 +1,16 @@
Based on Paul Ramsey's [blog post](http://blog.cartodb.com/jets-and-datelines/).
#### Using the function
Creates a great circle line.
```sql
SELECT CDB_GreatCircle(start_point, end_point) FROM table_name
-- Results a line reprsenting the great circle between the two points
```
#### Arguments
CDB_GreatCircle(start_point, end_point)
* **start_point** ST_Point indicating the start of the line.
* **end_point** ST_point indicating the end of the line.

123
doc/CDB_Overviews.md Normal file
View File

@@ -0,0 +1,123 @@
Overviews are tables that represent a *reduced* version of a dataset intended
for efficient rendering at certain zoom levels while preserving the
general visual appearance of the complete dataset.
The *reduction* consists in havig a fewer number of records
(while each overview record may represent an aggregation of multiple records)
and/or simplified record geometries.
Overviews are created through the `CDB_CreateOverviews` function.
The statement timeout may need to be adjusted before using this function,
as overview creation for large tables is a time-consuming operation.
The `CDB_Overviews` function can be used determine what overview tables
exist for a given dataset table and which zoom levels correspond to it.
The `CDB_DropOverviews` function removes a dataset's existing overviews.
To know if overview tables exist for some base table, and to obtain
a list of which overview tables are approrpiate for which zoom levels,
the `CDB_Overviews` functions can be used.
The zoom level we're referring here to are those used
by the tiler: http://wiki.openstreetmap.org/wiki/Zoom_levels
### CDB_CreateOverviews
Create overviews for vector dataset.
#### Using the function
The table for which overviews will be generated should be
a Cartodbfied dataset with vector geometry.
```sql
SELECT CDB_CreateOverviews('table_name');
--- Generates overview tables for the dataset
```
#### Arguments
CDB_CreateOverviews(table_name, ref_z_strategy, reduction_strategy)
* **table_name** regclass, table for which overviews will be generated
* **ref_z_strategy** regproc, optional function that provides
the Z-scale strategy.
It returns the base Z level for the dataset.
It should have these arguments:
- **table_name** regclass, table to compute the reference Z scale for
* **reduction_strategy** regproc, optional function that provides
the reduction strategy to generate an overview table from a table
for a smaller scale (higher Z number).
It returns the name of the generated table.
It should have these arguments:
- **base_table_name** regclass, base table to be reduced.
- **base_z** integer, base Z level assigned to the base table.
- **overview_z** integer, Z level for which to generate the overview.
#### Tolerance / level of detail
The level of detail to be representable by each overview layer can
be specified as a tolerance in pixels (if different from the default of 1 pixel)
with the function `CDB_CreateOverviewsWithToleranceInPixels`
which has as a second additional argument the desired tolerance.
This tolerance defines the maximum deviation in pixels of the overviews
geometries with respect to the original geometries when overview tables
are used for their intendend zoom level.
### CDB_Overviews
Obtain overview metadata for a given table (existing overviews).
The returned relation will be empty if the table has no overviews.
The function can be applied to a single table:
```sql
SELECT CDB_Overviews('table_name');
--- Return existing overview Z levels and corresponding tables
```
Or to multiple tables passed as an array; this can be used
to obtain the overviews that can be applied to a query by
combining it with `CDB_QueryTablesText`:
```sql
SELECT CDB_Overviews(CDB_QueryTablesText('SELECT * FROM table1, table2'));
--- Return existing overview Z levels and corresponding tables
```
The result of `CDB_Overviews` has three columns:
| base_table | z | overview_table |
| ---------- | - | -------------- |
| table1 | 1 | table1_ov1 |
| table1 | 2 | table1_ov2 |
| table1 | 4 | table1_ov4 |
| table2 | 1 | table1_ov1 |
| table2 | 2 | table1_ov2 |
#### Arguments
CDB_Overviews(table_name)
* **table_name** regclass, oid of table to obtain existing overviews for
CDB_Overviews(table_names)
* **table_names** regclass[], array of table oids
### CDB_DropOverviews
Remove the overviews of a table, if present.
```sql
SELECT CDB_DropOverviews('table_name');
```
#### Arguments
CDB_Overviews(table_name)
* **table_name** regclass, table for which to drop existing overviews.

56
doc/CDB_SyncTable.md Normal file
View File

@@ -0,0 +1,56 @@
Synchronize two tables. This function will synchronize a *destination* table with a *source* table.
The idea is that the *destination* is a replica of *source* and *source* has been subject to
modifications that are to be applied to *destination*.
This will be achieved by deleting the rows in the destination not present
in the source, inserting rows of the source not in the destination and updating modified rows.
If the destination table does not exist it will be created and all the rows of the source inserted into it.
Both tables must have a consistent `cartodb_id` primary key column which will be used to match
the source and destination rows.
Note that both tables do not necessarily become identical after the synchronization, since additional columns
may have been added to the destination; those columns will not be altered by the synchronization.
In addition some source columns may be skipped by listing them in the optional last argument; such columns
will not be updated in the destination, so if they are present in it their values won't be altered.
#### Using the function
Import some data using COPY FROM into a temporary table, then synchronize a table with the data and
finally delete the temporary table. This could be used import and update some data periodically while
allowing to add columns to the data that will be preserved across updates.
```sql
CREATE tmp_pois(cartodb_id int, name text, type text, longitude double precision, latitude double precision, rank int);
COPY tmp_pois FROM '/tmp/pois.csv';
SELECT CDB_SyncTable('tmp_pois', 'public', 'pois');
DROP TABLE tmp_pois;
```
Now we could perform some changes to the `pois` to maintain our own ranking:
```sql
UPDATE pois SET rank = random()*4 + 1;
```
Then, if the source were updated at `/tmp/pois.csv` we could synchronize with it while preserving our `rank` values with:
```sql
CREATE tmp_pois(cartodb_id int, name text, type text, longitude double precision, latitude double precision, rank int);
COPY tmp_pois FROM '/tmp/pois.csv';
SELECT CDB_SyncTable('tmp_pois', 'public', 'pois', '{rank}');
DROP TABLE tmp_pois;
```
#### Arguments
```
CDB_SyncTable(src_table, dst_schema, dst_table, skip_cols)
```
* **src_table** REGCLASS the source data for the synchronization
* **dst_scgena** REGNAMESPACE the destination schema
* **dst_table** NAME the destination table to be updated
* **skip_cols** NAME[] an array of column names, empty by default, which will be skipped

View File

@@ -3,7 +3,11 @@ List the name of available tables (only the usable ones)
#### Using the function
```sql
--- Returns a row for each table having given permission with the table name
--- Returns a row for each table having given permission with the table name.
--- It also returns tables from others users if you've permission to see them. For example, consider the following scenario:
--- User X and User Y at account C.
--- User X has a public table T.
--- User Y will see table T.
--- Currently accepted permissions are: 'public', 'private' or 'all'
SELECT CDB_UserTables(perms)
```

View File

@@ -1,29 +0,0 @@
A "cartodb" user table is a table with a well-known set of fields and a well-known set of triggers attached on.
The fields are:
- `cartodb_id`, a numerical primary key of serial type
- `created_at`, timestamp with timezone not null default now()
- `updated_at`, timestamp with timezone not null default now()
- `the_geom`, geometry, GiST indexed, constrained (see below)
- `the_geom_webmercator`, geometry, GiST indexed, constrained (see below)
The values of "the_geom" and "the_geom_webmercator" must match these constraints:
- Only POINT, MULTILINE, MULTIPOLYGON types ? Maybe UNCONSTRAINED
- Only 2 dimensions ? Maybe UNCONSTRAINED
- SRID=4326 for the_geom and SRID=3857 for the_geom_webmercator
The triggers are:
- `track_updates` after modifying statement updates cdb_tablemetadata
- `test_quota` before changing statement to forbid if overquota
- `test_quota_per_row` before changing row to forbod if overquota (checked on a probabilistic basis)
- `update_the_geom_webmercator` before insert or update row to maintain the_geom_webmercator
- `update_updated_at_trigger` before update row to maintain updated_at
Some conversions will be attempted to perform upon cartodbfication when certain fields appear:
- `cartodb_id`: If found type TEXT will be attempted to cast
- `created_at`: If found type TEXT will be attempted to cast
- `updated_at`: If found type TEXT will be attempted to cast

View File

@@ -0,0 +1,68 @@
CartoDB User Table
==================
Introduction
----------
A CartoDB user table is a table with a well-known set of columns and a well-known set of triggers attached on.
Columns
----------
The required columns of a CartoDB table are:
- ``cartodb_id``
- This column will be used as the primary key of the table and it has a sequence as default value
- Its values must be integer, non-zero, non-null and unique
- B-Tree indexed
- ``the_geom``
- This column stores the main geometric features of a table
- The type of the column in the Postgres database is ``geometry(Geometry,4326)```
- GiST indexed
- geometry, GiST indexed, constrained (see below)
- ``the_geom_webmercator``
- This column stores the geometries used for rendering purposes
- The type of the column in the Postgres database is ``geometry(Geometry,3857)``
- GiST indexed
- This column is automatically updated by the system when the ``the_geom`` column is updated or when there is an insertion of a new row into the table (See triggers below)
The values of ``the_geom`` and ``the_geom_webmercator`` must be two-dimensional Points, MultiLineStrings or MultiPolygons. Different geometric types in a CartoDB table are not supported.
Described table example
^^^^^^^^^^
::
Column | Type | Modifiers
----------------------+-------------------------+--------------------------------------------------------
cartodb_id | bigint | not null default nextval('t_cartodb_id_seq'::regclass)
the_geom | geometry(Geometry,4326) |
the_geom_webmercator | geometry(Geometry,3857) |
Indexes:
"table_name_pkey" PRIMARY KEY, btree (cartodb_id)
"table_name_the_geom_idx" gist (the_geom)
"table_name_the_geom_webmercator_idx" gist (the_geom_webmercator)
Triggers
----------
The triggers generated in each CartoDB table are:
- ``track_updates`` after modifying statement updates ``cdb_tablemetadata``
- ``test_quota`` before changing statement to forbid if overquota
- ``test_quota_per_row`` before insert ot update row to forbid if overquota (checked on a probabilistic basis)
- ``update_the_geom_webmercator`` before insert or update row to maintain the ``the_geom_webmercator`` updated with the contents in ``the_geom``
Described triggers example
^^^^^^^^^^
::
test_quota BEFORE INSERT OR UPDATE ON t FOR EACH STATEMENT EXECUTE PROCEDURE cdb_checkquota('0.1', '-1', 'public')
test_quota_per_row BEFORE INSERT OR UPDATE ON t FOR EACH ROW EXECUTE PROCEDURE cdb_checkquota('0.001', '-1', 'public')
track_updates AFTER INSERT OR DELETE OR UPDATE OR TRUNCATE ON t FOR EACH STATEMENT EXECUTE PROCEDURE cdb_tablemetadata_trigger()
update_the_geom_webmercator_trigger BEFORE INSERT OR UPDATE OF the_geom ON t FOR EACH ROW EXECUTE PROCEDURE _cdb_update_the_geom_webmercator()
Further details
----------
Some conversions will be attempted to perform upon cartodbfication when certain fields appear:
- ``cartodb_id``: If found type TEXT will be attempted to cast to integer. If not casteable, an eror will be raised.
- ``the_geom``: If found type TEXT will be attempted to cast to geometry(Geometry,4326).

View File

@@ -20,29 +20,4 @@ The CartoDB PostgreSQL extension is a module to load into each CartoDB user data
# Checks
No user other than the superuser should be allowed to change `statement_timeout` for the session (SET statement_timeout disallowed).
User tables need to match certain structure criteria (See [[CartoDB-user-table]]) so the extension should provide a mean to enforce such structure everytime an attempt to change structure is encountered.
# Events
The events we want some function to be called upon are:
| event | arguments to handler function | function duty | OK* |
|------------------------|--------------------------------------|----------------------------------|-----|
| SET variable | name of variable | forbid changing some vars | |
| RENAME table | old and new name + oid of the table | flush cache | |
| ADD/DROP/ALTER column | oid of the table | flush cache, cartodbfy, upd meta | Y |
| DISABLE/DROP trigger | oid of table, name of trigger | cartodbfy or forbid | |
| DROP table | oid of the table | flush cache and metadata | Y |
| CREATE table | oid of the table | cartodby, upd metadata | Y |
| GRANT | oid of table, privilege, role | flush cache, upd metadata |
| REVOKE | oid of table, privilege, role | flush cache, upd metadata |
* event available by installing https://github.com/CartoDB/pg_schema_triggers
At this stage we don't need more than this, but the number of events and the number of arguments passed to the handler function may expand in the future, so the extension should be written in a way to easily allow that.
Some of the handler will need to act _after_ the statement is completed (CREATE TABLE, for example).

View File

@@ -0,0 +1,63 @@
CartoDBfy Requirements
======================
Introduction
------------
This document aims at describing what the CartoDBfication is and what its formal requirements are, with the following goals in mind:
- Clarify what are the expectations of the "cartodbfycation process".
- Define an important part of what should be a stable, public API
- Allow for better testing, which should in turn...
- ...ease modifications and increase quality of the code
What is the CartoDBfycation
---------------------------
The CartoDBfycation is the process of converting an arbitrary postgres table into a valid CartoDB table, and register it in the system so that it can be used in the CartoDB editor and platform to generate maps and analysis.
It is performed by running the function ``CDB_CartodbfyTable(reloid REGCLASS)`` over a target table.
Valid CartoDB tables
--------------------
A valid CartoDB table shall meet the following conditions:
- Have a ``cartodb_id`` column with integer, unique, non-zero and non-null values as primary key with a sequence as default value
- Have a ``the_geom`` column of type ``Geometry`` with SRID 4326
- Have a ``the_geom_webmercator`` column of type ``Geometry`` with SRID 3857
- The columns ``the_geom`` and ``the_geom_webmercator`` shall be in sync (task of the ``update_the_geom_webmercator`` trigger)
Additionally, a CartoDB table can contain other columns.
See the `CartoDB User Table documentation`_
.. _CartoDB User Table documentation: https://github.com/CartoDB/cartodb-postgresql/blob/master/doc/CartoDB-user-table.rst
for further information.
High level requirements
-----------------------
Here is a list of high level requirments for the public function ``CDB_CartodbfyTable()``:
- A call to the function shall modify/rewrite the table and produce a valid CartoDB table with the same name.
- A call to the function shall cause the registration of the table into the platform.
- It shall be idempotent, meaning that successive calls to the function shall not produce any visible effect in the system.
- If there's a column containing a geometry, it shall be used to generate ``the_geom`` and the ``the_geom_webmercator`` columns.
- Exporting and re-importing the same table in CartoDB shall produce equivalent tables, with the same features associated to the same ``cartodb_id``'s.
Note that there should be only one geometry per row in the source table. If there's more than one, then which one is used for ``the_geom`` and ``the_geom_webmercator`` fields is not determined.
Low-level requirements
----------------------
- If the original table contains a valid (integer, unique, non-zero and not null) ``cartodb_id`` column, it shall be used
- If the original table contains a ``the_geom`` column or a ``the_geom_webmercator`` geometric column in the expected projection (EPSG 4326 and EPSG 3857, respectively) they shall be used.
- A modification of a cartodbfy'ed table shall insert or update a row in ``CDB_TableMetadata``
- A cartodbfy'ed table shall have a ``btree`` index on ``cartodb_id``
- A cartodbfy'ed table shall have ``gist`` indices on ``the_geom`` and ``the_geom_webmercator``
- Cartodbfy shall deal with text columns for imports, regarding CartoDB columns (``cartodb_id``, ``the_geom``, ``the_geom_webmercator``)

View File

@@ -1,197 +0,0 @@
\set VERBOSITY terse
-- Set user quota to infinite
SELECT CDB_SetUserQuotaInBytes(0);
cdb_setuserquotainbytes
-------------------------
0
(1 row)
-- Enable ddl triggers
SELECT cartodb.cdb_enable_ddl_hooks();
NOTICE: event trigger "cdb_on_relation_create" does not exist, skipping
NOTICE: event trigger "cdb_on_relation_drop" does not exist, skipping
NOTICE: event trigger "cdb_on_alter_column" does not exist, skipping
NOTICE: event trigger "cdb_on_drop_column" does not exist, skipping
NOTICE: event trigger "cdb_on_add_column" does not exist, skipping
cdb_enable_ddl_hooks
----------------------
(1 row)
create schema c;
SELECT CDB_SetUserQuotaInBytes('c', 0);
cdb_setuserquotainbytes
-------------------------
0
(1 row)
DROP USER IF EXISTS cartodb_postgresql_unpriv_user;
NOTICE: role "cartodb_postgresql_unpriv_user" does not exist, skipping
CREATE USER cartodb_postgresql_unpriv_user;
GRANT ALL ON SCHEMA c to cartodb_postgresql_unpriv_user;
SET SESSION AUTHORIZATION 'cartodb_postgresql_unpriv_user';
--SELECT session_user, current_user;
----------------------
-- CREATE TABLE
----------------------
SET SESSION AUTHORIZATION 'cartodb_postgresql_unpriv_user';
select 1 as i INTO c.t3;
NOTICE: trigger "track_updates" for table "c.t3" does not exist, skipping
NOTICE: trigger "update_the_geom_webmercator_trigger" for table "c.t3" does not exist, skipping
NOTICE: trigger "test_quota" for table "c.t3" does not exist, skipping
NOTICE: trigger "test_quota_per_row" for table "c.t3" does not exist, skipping
NOTICE: event trigger "cdb_on_relation_create" does not exist, skipping
NOTICE: event trigger "cdb_on_relation_drop" does not exist, skipping
NOTICE: event trigger "cdb_on_alter_column" does not exist, skipping
NOTICE: event trigger "cdb_on_drop_column" does not exist, skipping
NOTICE: event trigger "cdb_on_add_column" does not exist, skipping
NOTICE: cdb_invalidate_varnish(c.t3) called
RESET SESSION AUTHORIZATION;
select
tabname::text,
round(extract('secs' from now() - updated_at)) as age
FROM CDB_TableMetadata WHERE tabname = 'c.t3'::regclass;
tabname | age
---------+-----
c.t3 | 0
(1 row)
SET SESSION AUTHORIZATION 'cartodb_postgresql_unpriv_user';
-- Table with cartodb_id field, see
-- http://github.com/CartoDB/cartodb-postgresql/issues/32
select 1 as cartodb_id INTO c.t4;
NOTICE: trigger "track_updates" for table "c.t4" does not exist, skipping
NOTICE: trigger "update_the_geom_webmercator_trigger" for table "c.t4" does not exist, skipping
NOTICE: trigger "test_quota" for table "c.t4" does not exist, skipping
NOTICE: trigger "test_quota_per_row" for table "c.t4" does not exist, skipping
NOTICE: event trigger "cdb_on_relation_create" does not exist, skipping
NOTICE: event trigger "cdb_on_relation_drop" does not exist, skipping
NOTICE: event trigger "cdb_on_alter_column" does not exist, skipping
NOTICE: event trigger "cdb_on_drop_column" does not exist, skipping
NOTICE: event trigger "cdb_on_add_column" does not exist, skipping
NOTICE: cdb_invalidate_varnish(c.t4) called
RESET SESSION AUTHORIZATION;
select
tabname::text,
round(extract('secs' from now() - updated_at)) as age
FROM CDB_TableMetadata WHERE tabname = 'c.t4'::regclass;
tabname | age
---------+-----
c.t4 | 0
(1 row)
----------------------------
-- ALTER TABLE RENAME COLUMN
----------------------------
SET SESSION AUTHORIZATION 'cartodb_postgresql_unpriv_user';
select pg_sleep(.1);
pg_sleep
----------
(1 row)
alter table c.t3 rename column the_geom_webmercator to webmerc;
NOTICE: event trigger "cdb_on_relation_create" does not exist, skipping
NOTICE: event trigger "cdb_on_relation_drop" does not exist, skipping
NOTICE: event trigger "cdb_on_alter_column" does not exist, skipping
NOTICE: event trigger "cdb_on_drop_column" does not exist, skipping
NOTICE: event trigger "cdb_on_add_column" does not exist, skipping
NOTICE: cdb_invalidate_varnish(c.t3) called
RESET SESSION AUTHORIZATION;
select
tabname::text,
round(extract('secs' from now() - updated_at)*10) as agecs
FROM CDB_TableMetadata WHERE tabname = 'c.t3'::regclass;
tabname | agecs
---------+-------
c.t3 | 0
(1 row)
SET SESSION AUTHORIZATION 'cartodb_postgresql_unpriv_user';
select pg_sleep(.1);
pg_sleep
----------
(1 row)
alter table c.t3 rename column the_geom_webmercator to webmerc2;
NOTICE: event trigger "cdb_on_relation_create" does not exist, skipping
NOTICE: event trigger "cdb_on_relation_drop" does not exist, skipping
NOTICE: event trigger "cdb_on_alter_column" does not exist, skipping
NOTICE: event trigger "cdb_on_drop_column" does not exist, skipping
NOTICE: event trigger "cdb_on_add_column" does not exist, skipping
NOTICE: cdb_invalidate_varnish(c.t3) called
RESET SESSION AUTHORIZATION;
select
tabname::text,
round(extract('secs' from now() - updated_at)*10) as agecs
FROM CDB_TableMetadata WHERE tabname = 'c.t3'::regclass;
tabname | agecs
---------+-------
c.t3 | 0
(1 row)
----------------------------
-- ALTER TABLE DROP COLUMN
----------------------------
SET SESSION AUTHORIZATION 'cartodb_postgresql_unpriv_user';
select pg_sleep(.1);
pg_sleep
----------
(1 row)
alter table c.t3 drop column the_geom_webmercator;
NOTICE: event trigger "cdb_on_relation_create" does not exist, skipping
NOTICE: event trigger "cdb_on_relation_drop" does not exist, skipping
NOTICE: event trigger "cdb_on_alter_column" does not exist, skipping
NOTICE: event trigger "cdb_on_drop_column" does not exist, skipping
NOTICE: event trigger "cdb_on_add_column" does not exist, skipping
NOTICE: cdb_invalidate_varnish(c.t3) called
RESET SESSION AUTHORIZATION;
select
tabname::text,
round(extract('secs' from now() - updated_at)*10) as agecs
FROM CDB_TableMetadata WHERE tabname = 'c.t3'::regclass;
tabname | agecs
---------+-------
c.t3 | 0
(1 row)
----------------------------
-- ALTER TABLE ADD COLUMN
----------------------------
SET SESSION AUTHORIZATION 'cartodb_postgresql_unpriv_user';
select pg_sleep(.1);
pg_sleep
----------
(1 row)
alter table c.t3 add column id2 int;
NOTICE: cdb_invalidate_varnish(c.t3) called
RESET SESSION AUTHORIZATION;
select
tabname::text,
round(extract('secs' from now() - updated_at)*10) as agecs
FROM CDB_TableMetadata WHERE tabname = 'c.t3'::regclass;
tabname | agecs
---------+-------
c.t3 | 0
(1 row)
----------------------------
-- DROP TABLE
----------------------------
RESET SESSION AUTHORIZATION;
drop schema c cascade;
NOTICE: drop cascades to 3 other objects
select count(*) from CDB_TableMetadata;
count
-------
0
(1 row)
DROP OWNED BY cartodb_postgresql_unpriv_user;
DROP ROLE cartodb_postgresql_unpriv_user;
DROP FUNCTION _CDB_UserQuotaInBytes();

View File

@@ -1,7 +1,5 @@
CREATE EXTENSION postgis;
CREATE EXTENSION schema_triggers;
CREATE EXTENSION plpythonu;
CREATE EXTENSION cartodb;
SET client_min_messages TO error;
CREATE EXTENSION cartodb CASCADE;
CREATE FUNCTION public.cdb_invalidate_varnish(table_name text)
RETURNS void AS $$
BEGIN

View File

@@ -0,0 +1,95 @@
-- Table to register analysis nodes from https://github.com/cartodb/camshaft
CREATE TABLE IF NOT EXISTS
@extschema@.cdb_analysis_catalog (
-- md5 hex hash
node_id char(40) CONSTRAINT cdb_analysis_catalog_pkey PRIMARY KEY,
-- being json allows to do queries like analysis_def->>'type' = 'buffer'
analysis_def json NOT NULL,
-- can reference other nodes in this very same table, allowing recursive queries
input_nodes char(40) ARRAY NOT NULL DEFAULT '{}',
status TEXT NOT NULL DEFAULT 'pending',
CONSTRAINT valid_status CHECK (
status IN ( 'pending', 'waiting', 'running', 'canceled', 'failed', 'ready' )
),
created_at timestamp with time zone NOT NULL DEFAULT now(),
-- should be updated when some operation was performed in the node
-- and anything associated to it might have changed
updated_at timestamp with time zone DEFAULT NULL,
-- should register last time the node was used
used_at timestamp with time zone NOT NULL DEFAULT now(),
-- should register the number of times the node was used
hits NUMERIC DEFAULT 0,
-- should register what was the last node using current node
last_used_from char(40),
-- last job modifying the node
last_modified_by uuid,
-- store error message for failures
last_error_message text,
-- cached tables involved in the analysis
cache_tables regclass[] NOT NULL DEFAULT '{}',
-- useful for multi account deployments
username text
);
-- This can only be called from an SQL script executed by CREATE EXTENSION
DO LANGUAGE 'plpgsql' $$
BEGIN
PERFORM pg_catalog.pg_extension_config_dump('@extschema@.cdb_analysis_catalog', '');
END
$$;
-- Migrations to add new columns from old versions.
-- IMPORTANT: Those columns will be added in order of creation. To be consistent
-- in column order, ensure that new columns are added at the end and in the same order.
DO $$
BEGIN
BEGIN
ALTER TABLE @extschema@.cdb_analysis_catalog ADD COLUMN last_modified_by uuid;
EXCEPTION
WHEN duplicate_column THEN END;
END;
$$;
DO $$
BEGIN
BEGIN
ALTER TABLE @extschema@.cdb_analysis_catalog ADD COLUMN last_error_message text;
EXCEPTION
WHEN duplicate_column THEN END;
END;
$$;
DO $$
BEGIN
BEGIN
ALTER TABLE @extschema@.cdb_analysis_catalog ADD COLUMN cache_tables regclass[] NOT NULL DEFAULT '{}';
EXCEPTION
WHEN duplicate_column THEN END;
END;
$$;
DO $$
BEGIN
BEGIN
ALTER TABLE @extschema@.cdb_analysis_catalog ADD COLUMN username text;
EXCEPTION
WHEN duplicate_column THEN END;
END;
$$;
-- We want the "username" column to be moved to the last position if it was on a position from other versions
-- see https://github.com/CartoDB/cartodb-postgresql/issues/276
DO LANGUAGE 'plpgsql' $$
DECLARE
column_index int;
BEGIN
SELECT ordinal_position FROM information_schema.columns WHERE table_name='cdb_analysis_catalog' AND table_schema='@extschema@' AND column_name='username' INTO column_index;
IF column_index = 1 OR column_index = 10 THEN
ALTER TABLE @extschema@.cdb_analysis_catalog ADD COLUMN username_final text;
UPDATE @extschema@.cdb_analysis_catalog SET username_final = username;
ALTER TABLE @extschema@.cdb_analysis_catalog DROP COLUMN username;
ALTER TABLE @extschema@.cdb_analysis_catalog RENAME COLUMN username_final TO username;
END IF;
END;
$$;

View File

@@ -0,0 +1,65 @@
-- Read configuration parameter analysis_quota_factor, making it
-- accessible to regular users (which don't have access to cdb_conf)
CREATE OR REPLACE FUNCTION @extschema@._CDB_GetConfAnalysisQuotaFactor()
RETURNS float8 AS
$$
BEGIN
RETURN @extschema@.CDB_Conf_GetConf('analysis_quota_factor')::text::float8;
END;
$$ LANGUAGE 'plpgsql'
STABLE
PARALLEL SAFE
SECURITY DEFINER
SET search_path = pg_temp;
-- Get the factor (fraction of the quota) for Camshaft cached analysis tables
CREATE OR REPLACE FUNCTION @extschema@._CDB_AnalysisQuotaFactor()
RETURNS float8 AS
$$
DECLARE
factor float8;
BEGIN
-- We use a floating point cdb_conf parameter
factor := @extschema@._CDB_GetConfAnalysisQuotaFactor();
-- With a default value
IF factor IS NULL THEN
factor := 2;
END IF;
RETURN factor;
END;
$$
LANGUAGE 'plpgsql' STABLE PARALLEL SAFE;
-- This checks the space used up by Camshaft cached analysis tables.
-- An exception will be raised if the limits are exceeded.
-- The name of an analysis table is passed; this, in addition to the
-- db role that executes this function is used to determined which
-- analysis tables will be considered.
CREATE OR REPLACE FUNCTION @extschema@.CDB_CheckAnalysisQuota(table_name TEXT)
RETURNS void AS
$$
DECLARE
schema_name TEXT;
user_name TEXT;
nominal_quota int8;
cache_size float8;
BEGIN
-- We rely on the search_path to determine the user's schema and
-- check for all analysis tables in that schema.
-- An alternative would be to use cdb_analysis_catalog to
-- select analysis tables (cache_tables) from the same user, analysis or node.
-- For example:
-- SELECT unnest(cache_tables) FROM cdb_analysis_catalog
-- WHERE username IN (SELECT username FROM cdb_analysis_catalog
-- WHERE table_name::regclass = ANY (cache_tables));
-- At the moment we're not using the provided table_name.
SELECT current_schema() INTO schema_name;
EXECUTE FORMAT('SELECT %I._CDB_UserQuotaInBytes();', schema_name) INTO nominal_quota;
IF nominal_quota * @extschema@._CDB_AnalysisQuotaFactor() < @extschema@._CDB_AnalysisDataSize(schema_name) THEN
-- The limit is defined by a factor applied to the total space quota for the user
RAISE EXCEPTION 'Analysis cache space limits exceeded';
END IF;
END;
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;

View File

@@ -0,0 +1,55 @@
-- Internal auxiliar functions to deal with [Camshaft](https://github.com/cartodb/camshaft) cached analysis tables.
-- This function returns TRUE if a given table name corresponds to a Camshaft cached analysis table
-- Scope: private.
CREATE OR REPLACE FUNCTION @extschema@._CDB_IsAnalysisTableName(table_name TEXT)
RETURNS BOOLEAN
AS $$
BEGIN
RETURN table_name SIMILAR TO '\Aanalysis_[0-9a-f]{10}_[0-9a-f]{40}\Z';
END;
$$ LANGUAGE PLPGSQL IMMUTABLE PARALLEL SAFE;
-- This function returns a relation of Camshaft cached analysis tables in the given schema.
-- If the schema name parameter is NULL, then tables from all schemas
-- that may contain user tables are returned.
-- For each table, the regclass, schema name and table name are returned.
-- Scope: private.
CREATE OR REPLACE FUNCTION @extschema@._CDB_AnalysisTablesInSchema(schema_name text DEFAULT NULL)
RETURNS TABLE(table_regclass REGCLASS, schema_name TEXT, table_name TEXT)
AS $$
SELECT * FROM @extschema@._CDB_UserTablesInSchema(schema_name) WHERE @extschema@._CDB_IsAnalysisTableName(table_name);
$$ LANGUAGE 'sql' STABLE PARALLEL SAFE;
-- This function returns a relation user tables excluding analysis tables
-- If the schema name parameter is NULL, then tables from all schemas
-- that may contain user tables are returned.
-- For each table, the regclass, schema name and table name are returned.
-- Scope: private.
CREATE OR REPLACE FUNCTION @extschema@._CDB_NonAnalysisTablesInSchema(schema_name text DEFAULT NULL)
RETURNS TABLE(table_regclass REGCLASS, schema_name TEXT, table_name TEXT)
AS $$
SELECT * FROM @extschema@._CDB_UserTablesInSchema(schema_name) WHERE Not @extschema@._CDB_IsAnalysisTableName(table_name);
$$ LANGUAGE 'sql' STABLE PARALLEL SAFE;
-- Total spaced used up by Camshaft cached analysis tables in the given schema.
-- Scope: private.
CREATE OR REPLACE FUNCTION @extschema@._CDB_AnalysisDataSize(schema_name TEXT DEFAULT NULL)
RETURNS bigint AS
$$
DECLARE
total_size bigint;
BEGIN
WITH analysis_tables AS (
SELECT t.schema_name, t.table_name FROM @extschema@._CDB_AnalysisTablesInSchema(schema_name) t
)
SELECT COALESCE(INT8(SUM(@extschema@._CDB_total_relation_size(analysis_tables.schema_name, analysis_tables.table_name))))::int8
INTO total_size FROM analysis_tables;
IF total_size IS NOT NULL THEN
RETURN total_size;
ELSE
RETURN 0;
END IF;
END;
$$
LANGUAGE 'plpgsql' VOLATILE PARALLEL UNSAFE;

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,16 @@
-- Function returning the column names of a table
CREATE OR REPLACE FUNCTION CDB_ColumnNames(REGCLASS)
CREATE OR REPLACE FUNCTION @extschema@.CDB_ColumnNames(REGCLASS)
RETURNS SETOF information_schema.sql_identifier
AS $$
SELECT column_name
FROM information_schema.columns
WHERE
table_name IN (SELECT CDB_UserTables())
AND table_name = '' || $1 || '';
$$ LANGUAGE SQL;
SELECT
a.attname::information_schema.sql_identifier column_name
FROM pg_class c
LEFT JOIN pg_attribute a ON a.attrelid = c.oid
WHERE c.oid = $1::oid
AND a.attstattarget < 0 -- exclude system columns
ORDER BY a.attnum;
$$ LANGUAGE SQL STABLE PARALLEL SAFE;
-- This is to migrate from pre-0.2.0 version
-- See http://github.com/CartoDB/cartodb-postgresql/issues/36
GRANT EXECUTE ON FUNCTION CDB_ColumnNames(REGCLASS) TO PUBLIC;
GRANT EXECUTE ON FUNCTION @extschema@.CDB_ColumnNames(REGCLASS) TO PUBLIC;

View File

@@ -1,17 +1,16 @@
-- Function returning the type of a column
CREATE OR REPLACE FUNCTION CDB_ColumnType(REGCLASS, TEXT)
CREATE OR REPLACE FUNCTION @extschema@.CDB_ColumnType(REGCLASS, TEXT)
RETURNS information_schema.character_data
AS $$
SELECT data_type
FROM information_schema.columns
WHERE
table_name IN (SELECT CDB_UserTables())
AND table_name = '' || $1 || ''
AND column_name = '' || quote_ident($2) || '';
$$ LANGUAGE SQL;
SELECT
format_type(a.atttypid, NULL)::information_schema.character_data data_type
FROM pg_class c
LEFT JOIN pg_attribute a ON a.attrelid = c.oid
WHERE c.oid = $1::oid
AND a.attname = $2
AND a.attstattarget < 0; -- exclude system columns
$$ LANGUAGE SQL STABLE PARALLEL SAFE;
-- This is to migrate from pre-0.2.0 version
-- See http://github.com/CartoDB/cartodb-postgresql/issues/36
GRANT EXECUTE ON FUNCTION CDB_ColumnType(REGCLASS, TEXT) TO public;
GRANT EXECUTE ON FUNCTION @extschema@.CDB_ColumnType(REGCLASS, TEXT) TO public;

View File

@@ -0,0 +1,48 @@
----------------------------------
-- CONF MANAGEMENT FUNCTIONS
--
-- Meant to be used by superadmin user.
-- Functions needing reading configuration should use SECURITY DEFINER.
----------------------------------
-- This will trigger NOTICE if @extschema@.CDB_CONF already exists
DO LANGUAGE 'plpgsql' $$
BEGIN
CREATE TABLE IF NOT EXISTS @extschema@.CDB_CONF ( KEY TEXT PRIMARY KEY, VALUE JSON NOT NULL );
END
$$;
-- This can only be called from an SQL script executed by CREATE EXTENSION
DO LANGUAGE 'plpgsql' $$
BEGIN
PERFORM pg_catalog.pg_extension_config_dump('@extschema@.CDB_CONF', '');
END
$$;
CREATE OR REPLACE
FUNCTION @extschema@.CDB_Conf_SetConf(key text, value JSON)
RETURNS void AS $$
BEGIN
PERFORM @extschema@.CDB_Conf_RemoveConf(key);
EXECUTE 'INSERT INTO @extschema@.CDB_CONF (KEY, VALUE) VALUES ($1, $2);' USING key, value;
END
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
CREATE OR REPLACE
FUNCTION @extschema@.CDB_Conf_RemoveConf(key text)
RETURNS void AS $$
BEGIN
EXECUTE 'DELETE FROM @extschema@.CDB_CONF WHERE KEY = $1;' USING key;
END
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
CREATE OR REPLACE
FUNCTION @extschema@.CDB_Conf_GetConf(key text)
RETURNS JSON AS $$
DECLARE
value JSON;
BEGIN
EXECUTE 'SELECT VALUE FROM @extschema@.CDB_CONF WHERE KEY = $1;' INTO value USING key;
RETURN value;
END
$$ LANGUAGE PLPGSQL STABLE PARALLEL SAFE;

View File

@@ -1,214 +1,14 @@
-- Table creation
-- {
CREATE OR REPLACE FUNCTION cartodb.cdb_handle_create_table ()
RETURNS event_trigger SECURITY DEFINER LANGUAGE plpgsql AS $$
DECLARE
event_info RECORD;
rel RECORD;
newtable REGCLASS;
BEGIN
event_info := schema_triggers.get_relation_create_eventinfo();
--
-- Legacy file
-- Introduced again to make sure that updates do not leave dangling functions
--
-- We're only interested in real relations
IF (event_info.new).relkind != 'r' THEN RETURN; END IF;
SELECT c.relname, c.relnamespace, c.relkind, n.nspname
FROM pg_class c
JOIN pg_namespace n
ON c.relnamespace = n.oid
WHERE c.oid = event_info.relation
INTO rel;
RAISE DEBUG 'Relation % of kind % created in table % namespace % (oid %)',
event_info.relation, rel.relkind, rel.relname, rel.nspname, rel.relnamespace;
-- We don't want to react to alters triggered by superuser,
IF current_setting('is_superuser') = 'on' THEN
RAISE DEBUG 'no ddl trigger for superuser';
RETURN;
END IF;
PERFORM cartodb.cdb_disable_ddl_hooks();
-- CDB_CartodbfyTable must not create tables, or infinite loop will happen
newtable := cartodb.CDB_CartodbfyTable(rel.nspname, event_info.relation);
PERFORM cartodb.cdb_enable_ddl_hooks();
RAISE DEBUG 'Inserting into cartodb.CDB_TableMetadata';
-- Add entry to CDB_TableMetadata (should CartodbfyTable do this?)
INSERT INTO cartodb.CDB_TableMetadata(tabname, updated_at)
VALUES (newtable, now());
END; $$;
-- }
-- Table drop
-- {
CREATE OR REPLACE FUNCTION cartodb.cdb_handle_drop_table ()
RETURNS event_trigger SECURITY DEFINER LANGUAGE plpgsql AS $$
DECLARE
event_info RECORD;
BEGIN
event_info := schema_triggers.get_relation_drop_eventinfo();
-- We're only interested in real relations
IF (event_info.old).relkind != 'r' THEN RETURN; END IF;
RAISE DEBUG 'Relation % of kind % dropped from namespace oid %',
event_info.old_relation_oid, (event_info.old).relkind, (event_info.old).relnamespace;
-- delete record from CDB_TableMetadata (should invalidate varnish)
DELETE FROM cartodb.CDB_TableMetadata WHERE tabname = event_info.old_relation_oid;
END; $$;
-- }
-- Column alter
-- {
CREATE OR REPLACE FUNCTION cartodb.cdb_handle_alter_column ()
RETURNS event_trigger SECURITY DEFINER LANGUAGE plpgsql AS $$
DECLARE
event_info RECORD;
rel RECORD;
newtable REGCLASS;
BEGIN
event_info := schema_triggers.get_column_alter_eventinfo();
SELECT c.relname, c.relnamespace, c.relkind, n.nspname
FROM pg_class c
JOIN pg_namespace n
ON c.relnamespace = n.oid
WHERE c.oid = event_info.relation
INTO rel;
RAISE DEBUG 'Column % altered by % (superuser? %) in relation % of kind %',
(event_info.old).attname, current_user, current_setting('is_superuser'), rel.relname, rel.relkind;
-- We're only interested in real relations
IF rel.relkind != 'r' THEN RETURN; END IF;
-- We don't want to react to alters triggered by superuser,
IF current_setting('is_superuser') = 'on' THEN
RAISE DEBUG 'no ddl trigger for superuser';
RETURN;
END IF;
PERFORM cartodb.cdb_disable_ddl_hooks();
newtable := cartodb.CDB_CartodbfyTable(rel.nspname, event_info.relation);
PERFORM cartodb.cdb_enable_ddl_hooks();
-- update CDB_TableMetadata.updated_at (should invalidate varnish)
UPDATE cartodb.CDB_TableMetadata SET updated_at = NOW(), tabname = newtable
WHERE tabname = event_info.relation;
END; $$;
-- }
-- Column drop
-- {
CREATE OR REPLACE FUNCTION cartodb.cdb_handle_drop_column ()
RETURNS event_trigger SECURITY DEFINER LANGUAGE plpgsql AS $$
DECLARE
event_info RECORD;
rel RECORD;
newtable REGCLASS;
BEGIN
event_info := schema_triggers.get_column_drop_eventinfo();
SELECT c.relname, c.relnamespace, c.relkind, n.nspname
FROM pg_class c
JOIN pg_namespace n
ON c.relnamespace = n.oid
WHERE c.oid = event_info.relation
INTO rel;
RAISE DEBUG 'Column % drop by % (superuser? %) in relation % of kind %',
(event_info.old).attname, current_user, current_setting('is_superuser'), rel.relname, rel.relkind;
-- We're only interested in real relations
IF rel.relkind != 'r' THEN RETURN; END IF;
-- We don't want to react to drops triggered by superuser,
IF current_setting('is_superuser') = 'on' THEN
RAISE DEBUG 'no ddl trigger for superuser';
RETURN;
END IF;
DROP FUNCTION IF EXISTS @extschema@.cdb_handle_create_table();
DROP FUNCTION IF EXISTS @extschema@.cdb_handle_drop_table();
DROP FUNCTION IF EXISTS @extschema@.cdb_handle_alter_column();
DROP FUNCTION IF EXISTS @extschema@.cdb_handle_drop_column();
DROP FUNCTION IF EXISTS @extschema@.cdb_handle_add_column();
DROP FUNCTION IF EXISTS @extschema@.cdb_disable_ddl_hooks();
DROP FUNCTION IF EXISTS @extschema@.cdb_enable_ddl_hooks();
PERFORM cartodb.cdb_disable_ddl_hooks();
newtable := cartodb.CDB_CartodbfyTable(rel.nspname, event_info.relation);
PERFORM cartodb.cdb_enable_ddl_hooks();
-- update CDB_TableMetadata.updated_at (should invalidate varnish)
UPDATE cartodb.CDB_TableMetadata SET updated_at = NOW(), tabname = newtable
WHERE tabname = event_info.relation;
END; $$;
-- }
-- Column add
-- {
CREATE OR REPLACE FUNCTION cartodb.cdb_handle_add_column ()
RETURNS event_trigger SECURITY DEFINER LANGUAGE plpgsql AS $$
DECLARE
event_info RECORD;
rel RECORD;
BEGIN
event_info := schema_triggers.get_column_add_eventinfo();
SELECT c.relname, c.relnamespace, c.relkind, n.nspname
FROM pg_class c
JOIN pg_namespace n
ON c.relnamespace = n.oid
WHERE c.oid = event_info.relation
INTO rel;
RAISE DEBUG 'Column % added by % (superuser? %) in relation % of kind %',
(event_info.new).attname, current_user, current_setting('is_superuser'), rel.relname, rel.relkind;
-- We're only interested in real relations
IF rel.relkind != 'r' THEN RETURN; END IF;
-- We don't want to react to drops triggered by superuser,
IF current_setting('is_superuser') = 'on' THEN
RAISE DEBUG 'no ddl trigger for superuser';
RETURN;
END IF;
-- update CDB_TableMetadata.updated_at (should invalidate varnish)
UPDATE cartodb.CDB_TableMetadata SET updated_at = NOW()
WHERE tabname = event_info.relation;
END; $$;
-- }
CREATE OR REPLACE FUNCTION cartodb.cdb_disable_ddl_hooks() returns void AS $$
DROP EVENT TRIGGER IF EXISTS cdb_on_relation_create;
DROP EVENT TRIGGER IF EXISTS cdb_on_relation_drop;
DROP EVENT TRIGGER IF EXISTS cdb_on_alter_column;
DROP EVENT TRIGGER IF EXISTS cdb_on_drop_column;
DROP EVENT TRIGGER IF EXISTS cdb_on_add_column;
$$ LANGUAGE sql;
CREATE OR REPLACE FUNCTION cartodb.cdb_enable_ddl_hooks() returns void AS $$
SELECT cartodb.cdb_disable_ddl_hooks();
CREATE EVENT TRIGGER cdb_on_relation_create
ON "relation_create" EXECUTE PROCEDURE cartodb.cdb_handle_create_table();
CREATE EVENT TRIGGER cdb_on_relation_drop
ON "relation_drop" EXECUTE PROCEDURE cartodb.cdb_handle_drop_table();
CREATE EVENT TRIGGER cdb_on_alter_column
ON "column_alter" EXECUTE PROCEDURE cartodb.cdb_handle_alter_column();
CREATE EVENT TRIGGER cdb_on_drop_column
ON "column_drop" EXECUTE PROCEDURE cartodb.cdb_handle_drop_column();
CREATE EVENT TRIGGER cdb_on_add_column
ON "column_add" EXECUTE PROCEDURE cartodb.cdb_handle_add_column();
$$ LANGUAGE sql;
-- Do not enable hooks by default
--SELECT cartodb.cdb_enable_ddl_hooks();

View File

@@ -1,6 +1,6 @@
-- Convert timestamp to double precision
--
CREATE OR REPLACE FUNCTION CDB_DateToNumber(input timestamp)
CREATE OR REPLACE FUNCTION @extschema@.CDB_DateToNumber(input timestamp)
RETURNS double precision AS $$
DECLARE output double precision;
BEGIN
@@ -12,4 +12,20 @@ BEGIN
RETURN output;
END;
$$
LANGUAGE 'plpgsql' STABLE STRICT;
LANGUAGE 'plpgsql' IMMUTABLE STRICT PARALLEL UNSAFE;
-- Convert timestamp with time zone to double precision
--
CREATE OR REPLACE FUNCTION @extschema@.CDB_DateToNumber(input timestamp with time zone)
RETURNS double precision AS $$
DECLARE output double precision;
BEGIN
BEGIN
SELECT extract (EPOCH FROM input) INTO output;
EXCEPTION WHEN OTHERS THEN
RETURN NULL;
END;
RETURN output;
END;
$$
LANGUAGE 'plpgsql' IMMUTABLE STRICT PARALLEL UNSAFE;

View File

@@ -1,5 +1,5 @@
-- Find thousand and decimal digits separators
CREATE OR REPLACE FUNCTION CDB_DigitSeparator (rel REGCLASS, fld TEXT, OUT t CHAR, OUT d CHAR)
CREATE OR REPLACE FUNCTION @extschema@.CDB_DigitSeparator (rel REGCLASS, fld TEXT, OUT t CHAR, OUT d CHAR)
as $$
DECLARE
sql TEXT;
@@ -50,4 +50,4 @@ BEGIN
END
$$
LANGUAGE 'plpgsql' STABLE STRICT;
LANGUAGE 'plpgsql' STABLE STRICT PARALLEL SAFE;

View File

@@ -10,7 +10,7 @@
-- 1. width_bucket/histograms: http://tapoueh.org/blog/2014/02/21-PostgreSQL-histogram
-- 2. R implementation: https://github.com/cran/agrmt
CREATE OR REPLACE FUNCTION CDB_DistType ( in_array NUMERIC[] ) RETURNS text as $$
CREATE OR REPLACE FUNCTION @extschema@.CDB_DistType ( in_array NUMERIC[] ) RETURNS text as $$
DECLARE
element_count INT4;
minv numeric;
@@ -60,16 +60,16 @@ BEGIN
i := i + 1;
END LOOP;
signature = _CDB_DistTypeClassify(ajus);
signature = @extschema@._CDB_DistTypeClassify(ajus);
END IF;
RETURN signature;
END;
$$ language plpgsql IMMUTABLE;
$$ language plpgsql IMMUTABLE STRICT PARALLEL SAFE;
-- Classify data into AJUSFL
CREATE OR REPLACE FUNCTION _CDB_DistTypeClassify ( in_array INT[] ) RETURNS text as $$
CREATE OR REPLACE FUNCTION @extschema@._CDB_DistTypeClassify ( in_array INT[] ) RETURNS text as $$
DECLARE
element_count INT4;
maxv numeric;
@@ -119,4 +119,4 @@ BEGIN
RETURN type;
END;
$$ language plpgsql IMMUTABLE;
$$ language plpgsql IMMUTABLE STRICT PARALLEL SAFE;

View File

@@ -5,7 +5,7 @@
--
--
CREATE OR REPLACE FUNCTION CDB_DistinctMeasure ( in_array text[], threshold numeric DEFAULT null ) RETURNS numeric as $$
CREATE OR REPLACE FUNCTION @extschema@.CDB_DistinctMeasure ( in_array text[], threshold numeric DEFAULT null ) RETURNS numeric as $$
DECLARE
element_count INT4;
maxval numeric;
@@ -43,4 +43,4 @@ BEGIN
RETURN passes;
END;
$$ language plpgsql IMMUTABLE;
$$ language plpgsql IMMUTABLE PARALLEL SAFE;

View File

@@ -1,8 +1,8 @@
--
-- Calculate the equal interval bins for a given column
--
-- @param in_array A numeric array of numbers to determine the best
-- to determine the bin boundary
-- @param in_array An array of numbers to determine the best
-- bin boundary
--
-- @param breaks The number of bins you want to find.
--
@@ -11,27 +11,14 @@
--
--
CREATE OR REPLACE FUNCTION CDB_EqualIntervalBins ( in_array NUMERIC[], breaks INT ) RETURNS NUMERIC[] as $$
DECLARE
diff numeric;
min_val numeric;
max_val numeric;
tmp_val numeric;
i INT := 1;
reply numeric[];
BEGIN
SELECT min(e), max(e) INTO min_val, max_val FROM ( SELECT unnest(in_array) e ) x WHERE e IS NOT NULL;
diff = (max_val - min_val) / breaks::numeric;
LOOP
IF i < breaks THEN
tmp_val = min_val + i::numeric * diff;
reply = array_append(reply, tmp_val);
i := i+1;
ELSE
reply = array_append(reply, max_val);
EXIT;
END IF;
END LOOP;
RETURN reply;
END;
$$ language plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION @extschema@.CDB_EqualIntervalBins ( in_array anyarray, breaks INT ) RETURNS anyarray as $$
WITH stats AS (
SELECT min(e), (max(e)-min(e))/breaks AS del
FROM (SELECT unnest(in_array) e) AS p)
SELECT array_agg(bins)
FROM (
SELECT min + generate_series(1,breaks)*del AS bins
FROM stats) q;
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
DROP FUNCTION IF EXISTS @extschema@.CDB_EqualIntervalBins( numeric[], integer);

View File

@@ -0,0 +1,36 @@
-- Internal function to generate stats for a table if they don't exist
CREATE OR REPLACE FUNCTION @extschema@._CDB_GenerateStats(reloid REGCLASS)
RETURNS VOID
AS $$
DECLARE
has_stats BOOLEAN;
BEGIN
SELECT EXISTS (
SELECT * FROM pg_catalog.pg_statistic WHERE starelid = reloid
) INTO has_stats;
IF NOT has_stats THEN
EXECUTE Format('ANALYZE %s;', reloid);
END IF;
END
$$ LANGUAGE 'plpgsql'
VOLATILE
STRICT
PARALLEL UNSAFE
SECURITY DEFINER
SET search_path = pg_temp;
-- Return a row count estimate of the result of a query using statistics
CREATE OR REPLACE FUNCTION @extschema@.CDB_EstimateRowCount(query text)
RETURNS Numeric
AS $$
DECLARE
plan JSON;
BEGIN
-- Make sure statistics exist for all the tables of the query
PERFORM @extschema@._CDB_GenerateStats(tabname) FROM unnest(@extschema@.CDB_QueryTablesText(query)) AS tabname;
-- Use the query planner to obtain an estimate of the number of result rows
EXECUTE 'EXPLAIN (FORMAT JSON) ' || query INTO STRICT plan;
RETURN plan->0->'Plan'->'Plan Rows';
END
$$ LANGUAGE 'plpgsql' VOLATILE STRICT PARALLEL UNSAFE;

View File

@@ -1,2 +1,2 @@
SELECT pg_catalog.pg_extension_config_dump('cartodb.cdb_tablemetadata','');
SELECT pg_catalog.pg_extension_config_dump('@extschema@.cdb_tablemetadata','');

View File

@@ -1,20 +1,20 @@
CREATE OR REPLACE FUNCTION cartodb.cdb_extension_reload() RETURNS void
CREATE OR REPLACE FUNCTION @extschema@.cdb_extension_reload() RETURNS void
AS $$
DECLARE
ver TEXT;
sql TEXT;
BEGIN
ver := split_part(cartodb.cdb_version(), ' ', 1);
ver := split_part(@extschema@.cdb_version(), ' ', 1);
sql := 'ALTER EXTENSION cartodb UPDATE TO ''' || ver || 'next''';
EXECUTE sql;
sql := 'ALTER EXTENSION cartodb UPDATE TO ''' || ver || '''';
EXECUTE sql;
END;
$$ language 'plpgsql' VOLATILE;
$$ language 'plpgsql' VOLATILE PARALLEL UNSAFE;
CREATE OR REPLACE FUNCTION cartodb.schema_exists(schema_name text)
CREATE OR REPLACE FUNCTION @extschema@.schema_exists(schema_name text)
RETURNS boolean AS
$$
SELECT EXISTS(SELECT 1 FROM pg_namespace WHERE nspname = schema_name::text);
$$
language sql VOLATILE;
language sql STABLE PARALLEL SAFE;

View File

@@ -0,0 +1,437 @@
--------------------------------------------------------------------------------
-- Private functions
--------------------------------------------------------------------------------
--
-- This function is just a placement to store and use the pattern for
-- foreign object names
-- Servers: cdb_fs_$(server_name)
-- View schema: cdb_fs_$(server_name)
-- > This is where all views created when importing tables are placed
-- > One server has only one view schema
-- Import Schemas: cdb_fs_schema_$(md5sum(server_name || remote_schema_name))
-- > This is where the foreign tables are placed
-- > One server has one import schema per remote schema plus auxiliar ones used
-- to access the remote catalog (pg_catalog, information_schema...)
-- Owner role: cdb_fs_$(md5sum(current_database() || server_name)
-- > This is the role than owns all schemas and tables related to the server
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Name_Pattern()
RETURNS TEXT
AS $$
SELECT 'cdb_fs_'::text;
$$
LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
--
-- Produce a valid DB name for servers generated for the Federated Server
-- If check_existence is true, it'll throw if the server doesn't exists
-- This name is also used as the schema to store views
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Generate_Server_Name(input_name TEXT, check_existence BOOL)
RETURNS NAME
AS $$
DECLARE
internal_server_name text := format('%s%s', @extschema@.__CDB_FS_Name_Pattern(), input_name);
BEGIN
IF input_name IS NULL OR char_length(input_name) = 0 THEN
RAISE EXCEPTION 'Server name cannot be NULL';
END IF;
-- We discard anything that would be truncated
IF (char_length(internal_server_name) >= 64) THEN
RAISE EXCEPTION 'Server name (%) is too long to be used as identifier', input_name;
END IF;
IF (check_existence AND (NOT EXISTS (SELECT * FROM pg_foreign_server WHERE srvname = internal_server_name))) THEN
RAISE EXCEPTION 'Server "%" does not exist', input_name;
END IF;
RETURN internal_server_name::name;
END
$$
LANGUAGE PLPGSQL IMMUTABLE PARALLEL SAFE;
--
-- Given the internal name for a remote server, it returns the name used by the user
-- Reverses __CDB_FS_Generate_Server_Name
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Extract_Server_Name(internal_server_name NAME)
RETURNS TEXT
AS $$
SELECT right(internal_server_name,
char_length(internal_server_name::TEXT) - char_length(@extschema@.__CDB_FS_Name_Pattern()))::TEXT;
$$
LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
--
-- Produce a valid name for a schema generated for the Federated Server
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Generate_Schema_Name(internal_server_name NAME, schema_name TEXT)
RETURNS NAME
AS $$
DECLARE
hash_value text := md5(internal_server_name::text || '__' || schema_name::text);
BEGIN
IF schema_name IS NULL THEN
RAISE EXCEPTION 'Schema name cannot be NULL';
END IF;
RETURN format('%s%s%s', @extschema@.__CDB_FS_Name_Pattern(), 'schema_', hash_value)::name;
END
$$
LANGUAGE PLPGSQL IMMUTABLE PARALLEL SAFE;
--
-- Produce a valid name for a role generated for the Federated Server
-- This needs to include the current database in its hash to avoid collisions in clusters with more than one database
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Generate_Server_Role_Name(internal_server_name NAME)
RETURNS NAME
AS $$
DECLARE
hash_value text := md5(current_database()::text || '__' || internal_server_name::text);
role_name text := format('%s%s%s', @extschema@.__CDB_FS_Name_Pattern(), 'role_', hash_value);
BEGIN
RETURN role_name::name;
END
$$
LANGUAGE PLPGSQL STABLE PARALLEL SAFE;
--
-- Creates (if not exist) a schema to place the objects for a remote schema
-- The schema is with the same AUTHORIZATION as the server
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Create_Schema(internal_server_name NAME, schema_name TEXT)
RETURNS NAME
AS $$
DECLARE
schema_name name := @extschema@.__CDB_FS_Generate_Schema_Name(internal_server_name, schema_name);
role_name name := @extschema@.__CDB_FS_Generate_Server_Role_Name(internal_server_name);
BEGIN
-- By changing the local role to the owner of the server we have an
-- easy way to check for permissions and keep all objects under the same owner
BEGIN
EXECUTE 'SET LOCAL ROLE ' || quote_ident(role_name);
EXCEPTION
WHEN invalid_parameter_value THEN
RAISE EXCEPTION 'Server "%" does not exist',
@extschema@.__CDB_FS_Extract_Server_Name(internal_server_name);
WHEN OTHERS THEN
RAISE EXCEPTION 'Not enough permissions to access the server "%"',
@extschema@.__CDB_FS_Extract_Server_Name(internal_server_name);
END;
IF NOT EXISTS (SELECT oid FROM pg_namespace WHERE nspname = schema_name) THEN
EXECUTE 'CREATE SCHEMA ' || quote_ident(schema_name) || ' AUTHORIZATION ' || quote_ident(role_name);
END IF;
RETURN schema_name;
END
$$
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
--
-- Returns the type of a server by internal name
-- Currently all of them should be postgres_fdw
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_server_type(internal_server_name NAME)
RETURNS name
AS $$
SELECT f.fdwname
FROM pg_foreign_server s
JOIN pg_foreign_data_wrapper f ON s.srvfdw = f.oid
WHERE s.srvname = internal_server_name;
$$
LANGUAGE SQL VOLATILE PARALLEL UNSAFE;
--
-- Take a config jsonb and transform it to an input suitable for _CDB_SetUp_User_PG_FDW_Server
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_credentials_to_user_mapping(input_config JSONB)
RETURNS jsonb
AS $$
DECLARE
mapping jsonb := '{}'::jsonb;
BEGIN
IF NOT (input_config ? 'credentials') THEN
RAISE EXCEPTION 'Credentials are mandatory';
END IF;
-- For now, allow not passing username or password
IF input_config->'credentials'->'username' IS NOT NULL THEN
mapping := jsonb_build_object('user', input_config->'credentials'->'username');
END IF;
IF input_config->'credentials'->'password' IS NOT NULL THEN
mapping := mapping || jsonb_build_object('password', input_config->'credentials'->'password');
END IF;
RETURN (input_config - 'credentials')::jsonb || jsonb_build_object('user_mapping', mapping);
END
$$
LANGUAGE PLPGSQL IMMUTABLE PARALLEL SAFE;
-- Take a config jsonb as input and return it augmented with default
-- options
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_add_default_options(input_config jsonb)
RETURNS jsonb
AS $$
DECLARE
default_options jsonb := '{
"extensions": "postgis",
"updatable": "false",
"use_remote_estimate": "true",
"fetch_size": "1000"
}';
server_config jsonb;
BEGIN
IF NOT (input_config ? 'server') THEN
RAISE EXCEPTION 'Server information is mandatory';
END IF;
server_config := default_options || to_jsonb(input_config->'server');
RETURN jsonb_set(input_config, '{server}'::text[], server_config);
END
$$
LANGUAGE PLPGSQL IMMUTABLE PARALLEL SAFE;
-- Given an server name, returns the username used in the configuration if the caller has rights to access it
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_get_usermapping_username(internal_server_name NAME)
RETURNS text
AS $$
DECLARE
role_name name := @extschema@.__CDB_FS_Generate_Server_Role_Name(internal_server_name);
username text;
BEGIN
BEGIN
EXECUTE 'SET LOCAL ROLE ' || quote_ident(role_name);
EXCEPTION WHEN OTHERS THEN
RETURN NULL;
END;
SELECT (SELECT option_value FROM pg_options_to_table(u.umoptions) WHERE option_name LIKE 'user') as name INTO username
FROM pg_foreign_server s
LEFT JOIN pg_user_mappings u
ON u.srvid = s.oid
WHERE s.srvname = internal_server_name
ORDER BY 1;
RESET ROLE;
RETURN username;
END
$$
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
--------------------------------------------------------------------------------
-- Public functions
--------------------------------------------------------------------------------
--
-- Registers a new PG server
--
-- Example config: '{
-- "server": {
-- "dbname": "fdw_target",
-- "host": "localhost",
-- "port": 5432,
-- "extensions": "postgis",
-- "updatable": "false",
-- "use_remote_estimate": "true",
-- "fetch_size": "1000"
-- },
-- "credentials": {
-- "username": "fdw_user",
-- "password": "foobarino"
-- }
-- }'
--
-- The configuration from __CDB_FS_add_default_options will be appended
--
CREATE OR REPLACE FUNCTION @extschema@.CDB_Federated_Server_Register_PG(server TEXT, config JSONB)
RETURNS void
AS $$
DECLARE
server_internal name := @extschema@.__CDB_FS_Generate_Server_Name(input_name => server, check_existence => false);
final_config json := @extschema@.__CDB_FS_credentials_to_user_mapping(@extschema@.__CDB_FS_add_default_options(config));
role_name name := @extschema@.__CDB_FS_Generate_Server_Role_Name(server_internal);
row record;
option record;
BEGIN
IF NOT EXISTS (SELECT * FROM pg_extension WHERE extname = 'postgres_fdw') THEN
RAISE EXCEPTION 'postgres_fdw extension is not installed'
USING HINT = 'Please install it with `CREATE EXTENSION postgres_fdw`';
END IF;
-- We only create server and roles if the server didn't exist before
IF NOT EXISTS (SELECT * FROM pg_foreign_server WHERE srvname = server_internal) THEN
BEGIN
EXECUTE FORMAT('CREATE SERVER %I FOREIGN DATA WRAPPER postgres_fdw', server_internal);
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = role_name) THEN
EXECUTE FORMAT('CREATE ROLE %I NOLOGIN', role_name);
END IF;
EXECUTE FORMAT('GRANT ALL PRIVILEGES ON DATABASE %I TO %I', current_database(), role_name);
-- These grants over `@extschema@` and `@postgisschema@` are necessary for the cases
-- where the schemas aren't accessible to PUBLIC, which is what happens in a CARTO database
EXECUTE FORMAT('GRANT USAGE ON SCHEMA %I TO %I', '@extschema@', role_name);
EXECUTE FORMAT('GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA %I TO %I', '@extschema@', role_name);
EXECUTE FORMAT('GRANT USAGE ON SCHEMA %I TO %I', '@postgisschema@', role_name);
EXECUTE FORMAT('GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA %I TO %I', '@postgisschema@', role_name);
EXECUTE FORMAT('GRANT SELECT ON ALL TABLES IN SCHEMA %I TO %I', '@postgisschema@', role_name);
EXECUTE FORMAT('GRANT USAGE ON FOREIGN DATA WRAPPER postgres_fdw TO %I', role_name);
EXECUTE FORMAT('GRANT USAGE ON FOREIGN DATA WRAPPER postgres_fdw TO %I', role_name);
EXECUTE FORMAT('GRANT USAGE ON FOREIGN SERVER %I TO %I', server_internal, role_name);
EXECUTE FORMAT('ALTER SERVER %I OWNER TO %I', server_internal, role_name);
EXECUTE FORMAT ('CREATE USER MAPPING FOR %I SERVER %I', role_name, server_internal);
EXCEPTION WHEN OTHERS THEN
RAISE EXCEPTION 'Could not create server %: %', server, SQLERRM
USING HINT = 'Please clean the left over objects';
END;
END IF;
-- Add new options
FOR row IN SELECT p.key, p.value from lateral json_each_text(final_config->'server') p
LOOP
IF NOT EXISTS (
WITH a AS (
SELECT split_part(unnest(srvoptions), '=', 1) AS options FROM pg_foreign_server WHERE srvname=server_internal
) SELECT * from a where options = row.key)
THEN
EXECUTE FORMAT('ALTER SERVER %I OPTIONS (ADD %I %L)', server_internal, row.key, row.value);
ELSE
EXECUTE FORMAT('ALTER SERVER %I OPTIONS (SET %I %L)', server_internal, row.key, row.value);
END IF;
END LOOP;
-- Update user mapping settings
FOR option IN SELECT o.key, o.value from lateral json_each_text(final_config->'user_mapping') o
LOOP
IF NOT EXISTS (
WITH a AS (
SELECT split_part(unnest(umoptions), '=', 1) as options from pg_user_mappings WHERE srvname = server_internal AND usename = role_name
) SELECT * from a where options = option.key)
THEN
EXECUTE FORMAT('ALTER USER MAPPING FOR %I SERVER %I OPTIONS (ADD %I %L)', role_name, server_internal, option.key, option.value);
ELSE
EXECUTE FORMAT('ALTER USER MAPPING FOR %I SERVER %I OPTIONS (SET %I %L)', role_name, server_internal, option.key, option.value);
END IF;
END LOOP;
END
$$
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
--
-- Drops a registered server and all the objects associated with it
--
CREATE OR REPLACE FUNCTION @extschema@.CDB_Federated_Server_Unregister(server TEXT)
RETURNS void
AS $$
DECLARE
server_internal name := @extschema@.__CDB_FS_Generate_Server_Name(input_name => server, check_existence => true);
role_name name := @extschema@.__CDB_FS_Generate_Server_Role_Name(server_internal);
BEGIN
SET client_min_messages = ERROR;
BEGIN
EXECUTE FORMAT ('DROP USER MAPPING FOR %I SERVER %I', role_name, server_internal);
EXECUTE FORMAT ('DROP OWNED BY %I', role_name);
EXECUTE FORMAT ('DROP ROLE %I', role_name);
EXCEPTION WHEN OTHERS THEN
RAISE EXCEPTION 'Not enough permissions to drop the server "%"', server;
END;
END
$$
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
--
-- List registered servers
--
CREATE OR REPLACE FUNCTION @extschema@.CDB_Federated_Server_List_Servers(server TEXT DEFAULT '%')
RETURNS TABLE (
name text,
driver text,
host text,
port text,
dbname text,
readmode text,
username text
)
AS $$
DECLARE
server_name text := concat(@extschema@.__CDB_FS_Name_Pattern(), server);
BEGIN
RETURN QUERY SELECT
-- Name as shown to the user
@extschema@.__CDB_FS_Extract_Server_Name(s.srvname) AS "Name",
-- Which driver are we using (postgres_fdw, odbc_fdw...)
@extschema@.__CDB_FS_server_type(s.srvname)::text AS "Driver",
-- Read options from pg_foreign_server
(SELECT option_value FROM pg_options_to_table(s.srvoptions) WHERE option_name LIKE 'host') AS "Host",
(SELECT option_value FROM pg_options_to_table(s.srvoptions) WHERE option_name LIKE 'port') AS "Port",
(SELECT option_value FROM pg_options_to_table(s.srvoptions) WHERE option_name LIKE 'dbname') AS "DBName",
CASE WHEN (SELECT NOT option_value::boolean FROM pg_options_to_table(s.srvoptions) WHERE option_name LIKE 'updatable') THEN 'read-only' ELSE 'read-write' END AS "ReadMode",
@extschema@.__CDB_FS_get_usermapping_username(s.srvname)::text AS "Username"
FROM pg_foreign_server s
LEFT JOIN pg_user_mappings u
ON u.srvid = s.oid
WHERE s.srvname ILIKE server_name
ORDER BY 1;
END
$$
LANGUAGE PLPGSQL VOLATILE PARALLEL SAFE;
--
-- Grant access to a server
-- In the future we might consider adding the server's view schema to the role search_path
-- to make it easier to access the created views
--
CREATE OR REPLACE FUNCTION @extschema@.CDB_Federated_Server_Grant_Access(server TEXT, db_role NAME)
RETURNS void
AS $$
DECLARE
server_internal name := @extschema@.__CDB_FS_Generate_Server_Name(input_name => server, check_existence => true);
server_role_name name := @extschema@.__CDB_FS_Generate_Server_Role_Name(server_internal);
BEGIN
IF (db_role IS NULL) THEN
RAISE EXCEPTION 'User role "%" cannot be NULL', username;
END IF;
BEGIN
EXECUTE format('GRANT %I TO %I', server_role_name, db_role);
EXCEPTION
WHEN insufficient_privilege THEN
RAISE EXCEPTION 'You do not have rights to grant access on "%"', server;
WHEN OTHERS THEN
RAISE EXCEPTION 'Could not grant access on "%" to "%": %', server, db_role, SQLERRM;
END;
END
$$
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
--
-- Revoke access to a server
--
CREATE OR REPLACE FUNCTION @extschema@.CDB_Federated_Server_Revoke_Access(server TEXT, db_role NAME)
RETURNS void
AS $$
DECLARE
server_internal name := @extschema@.__CDB_FS_Generate_Server_Name(input_name => server, check_existence => true);
server_role_name name := @extschema@.__CDB_FS_Generate_Server_Role_Name(server_internal);
BEGIN
IF (db_role IS NULL) THEN
RAISE EXCEPTION 'User role "%" cannot be NULL', username;
END IF;
BEGIN
EXECUTE format('REVOKE %I FROM %I', server_role_name, db_role);
EXCEPTION
WHEN insufficient_privilege THEN
RAISE EXCEPTION 'You do not have rights to revoke access on "%"', server;
WHEN OTHERS THEN
RAISE EXCEPTION 'Could not revoke access on "%" to "%": %', server, db_role, SQLERRM;
END;
END
$$
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;

View File

@@ -0,0 +1,243 @@
--------------------------------------------------------------------------------
-- Private functions
--------------------------------------------------------------------------------
--
-- Import a foreign table if it does not exist
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Import_If_Not_Exists(server_internal name, remote_schema name, remote_table name)
RETURNS void
AS $$
DECLARE
local_schema name := @extschema@.__CDB_FS_Create_Schema(server_internal, remote_schema);
BEGIN
IF NOT EXISTS (
SELECT * FROM pg_class
WHERE relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = local_schema)
AND relname = remote_table
) THEN
EXECUTE format('IMPORT FOREIGN SCHEMA %I LIMIT TO (%I) FROM SERVER %I INTO %I',
remote_schema, remote_table, server_internal, local_schema);
END IF;
END
$$
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
--
-- Get the version of a remote PG server
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Foreign_Server_Version_PG(server_internal name)
RETURNS text
AS $$
DECLARE
remote_schema name := 'pg_catalog';
remote_table name := 'pg_settings';
local_schema name := @extschema@.__CDB_FS_Create_Schema(server_internal, remote_schema);
remote_server_version text;
BEGIN
PERFORM @extschema@.__CDB_FS_Import_If_Not_Exists(server_internal, remote_schema, remote_table);
BEGIN
EXECUTE format('
SELECT setting FROM %I.%I WHERE name = ''server_version'';
', local_schema, remote_table) INTO remote_server_version;
EXCEPTION WHEN OTHERS THEN
RAISE EXCEPTION 'Not enough permissions to access the server "%"',
@extschema@.__CDB_FS_Extract_Server_Name(server_internal);
END;
RETURN remote_server_version;
END
$$
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
--
-- Get the PostGIS extension version of a remote PG server
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Foreign_PostGIS_Version_PG(server_internal name)
RETURNS text
AS $$
DECLARE
remote_schema name := 'pg_catalog';
remote_table name := 'pg_extension';
local_schema name := @extschema@.__CDB_FS_Create_Schema(server_internal, remote_schema);
remote_postgis_version text;
BEGIN
PERFORM @extschema@.__CDB_FS_Import_If_Not_Exists(server_internal, remote_schema, remote_table);
BEGIN
EXECUTE format('
SELECT extversion FROM %I.%I WHERE extname = ''postgis'';
', local_schema, remote_table) INTO remote_postgis_version;
EXCEPTION WHEN OTHERS THEN
RAISE EXCEPTION 'Not enough permissions to access the server "%"',
@extschema@.__CDB_FS_Extract_Server_Name(server_internal);
END;
RETURN remote_postgis_version;
END
$$
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
--
-- Get the foreign server options of a remote PG server
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Foreign_Server_Options_PG(server_internal name)
RETURNS jsonb
AS $$
-- See https://www.postgresql.org/docs/current/catalog-pg-foreign-server.html
-- See https://www.postgresql.org/docs/current/functions-info.html
SELECT jsonb_object_agg(opt.option_name, opt.option_value) FROM (
SELECT (pg_options_to_table(srvoptions)).*
FROM pg_foreign_server
WHERE srvname = server_internal
) AS opt;
$$
LANGUAGE SQL VOLATILE PARALLEL UNSAFE;
--
-- Get a foreign PG server hostname from the catalog
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Foreign_Server_Host_PG(server_internal name)
RETURNS text
AS $$
SELECT option_value FROM (
SELECT (pg_options_to_table(srvoptions)).*
FROM pg_foreign_server WHERE srvname = server_internal
) AS opt WHERE opt.option_name = 'host';
$$
LANGUAGE SQL VOLATILE PARALLEL UNSAFE;
--
-- Get a foreign PG server port from the catalog
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Foreign_Server_Port_PG(server_internal name)
RETURNS integer
AS $$
SELECT option_value::integer FROM (
SELECT (pg_options_to_table(srvoptions)).*
FROM pg_foreign_server WHERE srvname = server_internal
) AS opt WHERE opt.option_name = 'port';
$$
LANGUAGE SQL VOLATILE PARALLEL UNSAFE;
--
-- Get one measure of network latency in ms to a remote TCP server
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_TCP_Foreign_Server_Latency(
server_internal name,
timeout_seconds float DEFAULT 5.0,
n_samples integer DEFAULT 10
)
RETURNS jsonb
AS $$
import socket
import json
import math
from timeit import default_timer as timer
plan = plpy.prepare("SELECT @extschema@.__CDB_FS_Foreign_Server_Host_PG($1) AS host", ['name'])
rv = plpy.execute(plan, [server_internal], 1)
host = rv[0]['host']
plan = plpy.prepare("SELECT @extschema@.__CDB_FS_Foreign_Server_Port_PG($1) AS port", ['name'])
rv = plpy.execute(plan, [server_internal], 1)
port = rv[0]['port'] or 5432
n_errors = 0
samples = []
for i in range(n_samples):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(timeout_seconds)
t_start = timer()
try:
s.connect((host, int(port)))
t_stop = timer()
s.shutdown(socket.SHUT_RD)
except (socket.timeout, OSError, socket.error) as ex:
plpy.warning('could not connect to server %s:%d, %s' % (host, port, str(ex)))
n_errors += 1
finally:
s.close()
t_connect = (t_stop - t_start) * 1000.0
plpy.debug('TCP connection %s:%d time=%.2f ms' % (host, port, t_connect))
samples.append(t_connect)
stats = {
'n_samples': n_samples,
'n_errors': n_errors,
}
n = len(samples)
if n >= 1:
mean = sum(samples) / n
stats.update({
'avg': round(mean, 3),
'min': round(min(samples), 3),
'max': round(max(samples), 3)
})
if n >= 2:
var = sum([ (x - mean)**2 for x in samples ]) / (n-1)
stdev = math.sqrt(var)
stats.update({
'stdev': round(stdev, 3)
})
return json.dumps(stats)
$$
LANGUAGE @@plpythonu@@ VOLATILE PARALLEL UNSAFE;
--
-- Collect and return diagnostics info from a remote PG into a jsonb
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Server_Diagnostics_PG(server_internal name)
RETURNS jsonb
AS $$
DECLARE
remote_server_version text := @extschema@.__CDB_FS_Foreign_Server_Version_PG(server_internal);
remote_postgis_version text := @extschema@.__CDB_FS_Foreign_PostGIS_Version_PG(server_internal);
remote_server_options jsonb := @extschema@.__CDB_FS_Foreign_Server_Options_PG(server_internal);
remote_server_latency_ms jsonb := @extschema@.__CDB_FS_TCP_Foreign_Server_Latency(server_internal);
BEGIN
RETURN jsonb_build_object(
'server_version', remote_server_version,
'postgis_version', remote_postgis_version,
'server_options', remote_server_options,
'server_latency_ms', remote_server_latency_ms
);
END
$$
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
--------------------------------------------------------------------------------
-- Public functions
--------------------------------------------------------------------------------
--
-- Collect and return diagnostics info from a remote PG into a jsonb
--
CREATE OR REPLACE FUNCTION @extschema@.CDB_Federated_Server_Diagnostics(server TEXT)
RETURNS jsonb
AS $$
DECLARE
server_internal name := @extschema@.__CDB_FS_Generate_Server_Name(input_name => server, check_existence => true);
server_type name := @extschema@.__CDB_FS_server_type(server_internal);
BEGIN
CASE server_type
WHEN 'postgres_fdw' THEN
RETURN @extschema@.__CDB_FS_Server_Diagnostics_PG(server_internal);
ELSE
RAISE EXCEPTION 'Not implemented server type % for remote server %', server_type, server;
END CASE;
END
$$
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;

View File

@@ -0,0 +1,298 @@
--------------------------------------------------------------------------------
-- Private functions
--------------------------------------------------------------------------------
--
-- List the schemas of a remote PG server
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_List_Foreign_Schemas_PG(server_internal name)
RETURNS TABLE(remote_schema name)
AS $$
DECLARE
-- Import schemata from the information schema
--
-- "The view schemata contains all schemas in the current database
-- that the current user has access to (by way of being the owner
-- or having some privilege)."
-- See https://www.postgresql.org/docs/11/infoschema-schemata.html
--
-- "The information schema is defined in the SQL standard and can
-- therefore be expected to be portable and remain stable"
-- See https://www.postgresql.org/docs/11/information-schema.html
inf_schema name := 'information_schema';
remote_table name := 'schemata';
local_schema name := @extschema@.__CDB_FS_Create_Schema(server_internal, inf_schema);
BEGIN
-- Import the foreign schemata table
IF NOT EXISTS (
SELECT * FROM pg_class
WHERE relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = local_schema)
AND relname = remote_table
) THEN
EXECUTE format('IMPORT FOREIGN SCHEMA %I LIMIT TO (%I) FROM SERVER %I INTO %I',
inf_schema, remote_table, server_internal, local_schema);
END IF;
-- Return the result we're interested in. Exclude toast and temp schemas
BEGIN
RETURN QUERY EXECUTE format('
SELECT schema_name::name AS remote_schema FROM %I.%I
WHERE schema_name NOT LIKE %s
ORDER BY remote_schema
', local_schema, remote_table, '''pg_%''');
EXCEPTION WHEN OTHERS THEN
RAISE EXCEPTION 'Not enough permissions to access the server "%"',
@extschema@.__CDB_FS_Extract_Server_Name(server_internal);
END;
END
$$
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
--
-- List the names of the tables in a remote PG schema
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_List_Foreign_Tables_PG(server_internal name, remote_schema name)
RETURNS TABLE(remote_table name)
AS $func$
DECLARE
-- Import `tables` from the information schema
--
-- "The view tables contains all tables and views defined in the
-- current database. Only those tables and views are shown that
-- the current user has access to (by way of being the owner or
-- having some privilege)."
-- https://www.postgresql.org/docs/11/infoschema-tables.html
-- Create local target schema if it does not exists
inf_schema name := 'information_schema';
remote_table name := 'tables';
local_schema name := @extschema@.__CDB_FS_Create_Schema(server_internal, inf_schema);
BEGIN
-- Import the foreign `tables` if not done
IF NOT EXISTS (
SELECT * FROM pg_class
WHERE relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = local_schema)
AND relname = remote_table
) THEN
EXECUTE format('IMPORT FOREIGN SCHEMA %I LIMIT TO (%I) FROM SERVER %I INTO %I',
inf_schema, remote_table, server_internal, local_schema);
END IF;
-- Note: in this context, schema names are not to be quoted
RETURN QUERY EXECUTE format($q$
SELECT table_name::name AS remote_table FROM %I.%I WHERE table_schema = '%s' ORDER BY table_name
$q$, local_schema, remote_table, remote_schema);
END
$func$
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
--
-- List the columns in a remote PG schema
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_List_Foreign_Columns_PG(server_internal name, remote_schema name)
RETURNS TABLE(table_name name, column_name name, column_type text)
AS $func$
DECLARE
-- Import `columns` from the information schema
--
-- "The view columns contains information about all table columns (or view columns)
-- in the database. System columns (oid, etc.) are not included. Only those columns
-- are shown that the current user has access to (by way of being the owner or having some privilege)."
-- https://www.postgresql.org/docs/11/infoschema-columns.html
-- Create local target schema if it does not exists
inf_schema name := 'information_schema';
remote_col_table name := 'columns';
local_schema name := @extschema@.__CDB_FS_Create_Schema(server_internal, inf_schema);
BEGIN
-- Import the foreign `columns` if not done
IF NOT EXISTS (
SELECT * FROM pg_class
WHERE relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = local_schema)
AND relname = remote_col_table
) THEN
EXECUTE format('IMPORT FOREIGN SCHEMA %I LIMIT TO (%I) FROM SERVER %I INTO %I',
inf_schema, remote_col_table, server_internal, local_schema);
END IF;
-- Note: in this context, schema names are not to be quoted
-- We join with the geometry columns to change the type `USER-DEFINED`
-- by its appropiate geometry and srid
RETURN QUERY EXECUTE format($q$
SELECT
a.table_name::name,
a.column_name::name,
COALESCE(b.column_type, a.data_type)::TEXT as column_type
FROM
%I.%I a
LEFT JOIN
@extschema@.__CDB_FS_List_Foreign_Geometry_Columns_PG('%s', '%s') b
ON a.table_name = b.table_name AND a.column_name = b.column_name
WHERE table_schema = '%s'
ORDER BY a.table_name, a.column_name $q$,
local_schema, remote_col_table,
server_internal, remote_schema,
remote_schema);
END
$func$
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
--
-- List the geometry columns in a remote PG schema
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_List_Foreign_Geometry_Columns_PG(server_internal name, remote_schema name, postgis_schema name DEFAULT 'public')
RETURNS TABLE(table_name name, column_name name, column_type text)
AS $func$
DECLARE
-- Import `geometry_columns` and `geography_columns` from the postgis schema
-- We assume that postgis is installed in the public schema
-- Create local target schema if it does not exists
remote_geometry_view name := 'geometry_columns';
remote_geography_view name := 'geography_columns';
local_schema name := @extschema@.__CDB_FS_Create_Schema(server_internal, postgis_schema);
BEGIN
-- Import the foreign `geometry_columns` and `geography_columns` if not done
IF NOT EXISTS (
SELECT * FROM pg_class
WHERE relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = local_schema)
AND relname = remote_geometry_view
) THEN
EXECUTE format('IMPORT FOREIGN SCHEMA %I LIMIT TO (%I, %I) FROM SERVER %I INTO %I',
postgis_schema, remote_geometry_view, remote_geography_view, server_internal, local_schema);
END IF;
BEGIN
-- Note: We return both the type and srid as the type
RETURN QUERY EXECUTE format($q$
SELECT
f_table_name::NAME as table_name,
f_geometry_column::NAME as column_name,
type::TEXT || ',' || srid::TEXT as column_type
FROM
(
SELECT * FROM %I.%I UNION ALL SELECT * FROM %I.%I
) _geo_views
WHERE f_table_schema = '%s'
$q$,
local_schema, remote_geometry_view,
local_schema, remote_geography_view,
remote_schema);
EXCEPTION WHEN OTHERS THEN
RAISE INFO 'Could not find Postgis installation in the remote "%" schema in server "%"',
postgis_schema, @extschema@.__CDB_FS_Extract_Server_Name(server_internal);
RETURN;
END;
END
$func$
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
--------------------------------------------------------------------------------
-- Public functions
--------------------------------------------------------------------------------
--
-- List remote schemas in a federated server that the current user has access to.
--
CREATE OR REPLACE FUNCTION @extschema@.CDB_Federated_Server_List_Remote_Schemas(server TEXT)
RETURNS TABLE(remote_schema name)
AS $$
DECLARE
server_internal name := @extschema@.__CDB_FS_Generate_Server_Name(input_name => server, check_existence => true);
server_type name := @extschema@.__CDB_FS_server_type(server_internal);
BEGIN
CASE server_type
WHEN 'postgres_fdw' THEN
RETURN QUERY SELECT @extschema@.__CDB_FS_List_Foreign_Schemas_PG(server_internal);
ELSE
RAISE EXCEPTION 'Not implemented server type % for remote server %', server_type, server;
END CASE;
END
$$
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
--
-- List remote tables in a federated server that the current user has access to.
-- For registered tables it returns also the associated configuration
--
CREATE OR REPLACE FUNCTION @extschema@.CDB_Federated_Server_List_Remote_Tables(server TEXT, remote_schema TEXT)
RETURNS TABLE(
registered boolean,
remote_table TEXT,
local_qualified_name TEXT,
id_column_name TEXT,
geom_column_name TEXT,
webmercator_column_name TEXT,
columns JSON
)
AS $$
DECLARE
server_internal name := @extschema@.__CDB_FS_Generate_Server_Name(input_name => server, check_existence => true);
server_type name := @extschema@.__CDB_FS_server_type(server_internal);
BEGIN
CASE server_type
WHEN 'postgres_fdw' THEN
RETURN QUERY
SELECT
coalesce(registered_tables.registered, false)::boolean as registered,
foreign_tables.remote_table::text as remote_table,
registered_tables.local_qualified_name as local_qualified_name,
registered_tables.id_column_name as id_column_name,
registered_tables.geom_column_name as geom_column_name,
registered_tables.webmercator_column_name as webmercator_column_name,
remote_columns.columns as columns
FROM
@extschema@.__CDB_FS_List_Foreign_Tables_PG(server_internal, remote_schema) foreign_tables
LEFT JOIN
@extschema@.__CDB_FS_List_Registered_Tables(server_internal, remote_schema) registered_tables
ON foreign_tables.remote_table = registered_tables.remote_table
LEFT JOIN
( -- Extract and group columns with their remote table
SELECT table_name,
json_agg(json_build_object('Name', column_name, 'Type', column_type)) as columns
FROM @extschema@.__CDB_FS_List_Foreign_Columns_PG(server_internal, remote_schema)
GROUP BY table_name
) remote_columns
ON foreign_tables.remote_table = remote_columns.table_name
ORDER BY foreign_tables.remote_table;
ELSE
RAISE EXCEPTION 'Not implemented server type % for remote server %', server_type, remote_server;
END CASE;
END
$$
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
--
-- List the columns of a remote table in a federated server that the current user has access to.
--
CREATE OR REPLACE FUNCTION @extschema@.CDB_Federated_Server_List_Remote_Columns(
server TEXT,
remote_schema TEXT,
remote_table TEXT)
RETURNS TABLE(column_n name, column_t text)
AS $$
DECLARE
server_internal name := @extschema@.__CDB_FS_Generate_Server_Name(input_name => server, check_existence => true);
server_type name := @extschema@.__CDB_FS_server_type(server_internal);
BEGIN
IF remote_table IS NULL THEN
RAISE EXCEPTION 'Remote table name cannot be NULL';
END IF;
CASE server_type
WHEN 'postgres_fdw' THEN
RETURN QUERY
SELECT
column_name,
column_type
FROM @extschema@.__CDB_FS_List_Foreign_Columns_PG(server_internal, remote_schema)
WHERE table_name = remote_table
ORDER BY column_name;
ELSE
RAISE EXCEPTION 'Not implemented server type % for remote server %', server_type, remote_server;
END CASE;
END
$$
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;

View File

@@ -0,0 +1,345 @@
--------------------------------------------------------------------------------
-- Private functions
--------------------------------------------------------------------------------
--
-- Checks if a column is of integer type
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Column_Is_Integer(input_table REGCLASS, colname NAME)
RETURNS boolean
AS $$
BEGIN
PERFORM atttypid FROM pg_catalog.pg_attribute
WHERE attrelid = input_table
AND attname = colname
AND atttypid IN (SELECT oid FROM pg_type
WHERE typname IN
('smallint', 'integer', 'bigint', 'int2', 'int4', 'int8'));
RETURN FOUND;
END
$$
LANGUAGE PLPGSQL STABLE PARALLEL UNSAFE;
--
-- Checks if a column is of geometry type
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Column_Is_Geometry(input_table REGCLASS, colname NAME)
RETURNS boolean
AS $$
BEGIN
PERFORM atttypid FROM pg_catalog.pg_attribute
WHERE attrelid = input_table
AND attname = colname
AND atttypid = '@postgisschema@.geometry'::regtype;
RETURN FOUND;
END
$$
LANGUAGE PLPGSQL STABLE PARALLEL UNSAFE;
--
-- Returns the name of all the columns from a table
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_GetColumns(input_table REGCLASS)
RETURNS SETOF NAME
AS $$
SELECT
a.attname as "colname"
FROM pg_catalog.pg_attribute a
WHERE
a.attnum > 0
AND NOT a.attisdropped
AND a.attrelid = (
SELECT c.oid
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.oid = input_table::oid
)
ORDER BY a.attnum;
$$ LANGUAGE SQL STABLE PARALLEL UNSAFE;
--
-- Returns the id column from a view definition
-- Note: The id is always of one of this forms:
-- SELECT t.cartodb_id,
-- SELECT t.my_id as cartodb_id,
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Get_View_id_column(view_def TEXT)
RETURNS TEXT
AS $$
WITH column_definitions AS
(
SELECT regexp_split_to_array(trim(leading from regexp_split_to_table(view_def, '\n')), ' ') AS col_def
)
SELECT trim(trailing ',' FROM split_part(col_def[2], '.', 2))
FROM column_definitions
WHERE trim(trailing ',' FROM col_def[array_length(col_def, 1)]) IN ('t.cartodb_id', 'cartodb_id')
LIMIT 1;
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
--
-- Returns the geom column from a view definition
--
-- Note: The the_geom is always of one of this forms:
-- t.the_geom,
-- t.my_geom as the_geom,
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Get_View_geom_column(view_def TEXT)
RETURNS TEXT
AS $$
WITH column_definitions AS
(
SELECT regexp_split_to_array(trim(leading from regexp_split_to_table(view_def, '\n')), ' ') AS col_def
)
SELECT trim(trailing ',' FROM split_part(col_def[1], '.', 2))
FROM column_definitions
WHERE trim(trailing ',' FROM col_def[array_length(col_def, 1)]) IN ('t.the_geom', 'the_geom')
LIMIT 1;
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
--
-- Returns the webmercatorcolumn from a view definition
-- Note: The the_geom_webmercator is always of one of this forms:
-- t.the_geom_webmercator,
-- t.my_geom as the_geom_webmercator,
-- Or without the trailing comma:
-- t.the_geom_webmercator
-- t.my_geom as the_geom_webmercator
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Get_View_webmercator_column(view_def TEXT)
RETURNS TEXT
AS $$
WITH column_definitions AS
(
SELECT regexp_split_to_array(trim(leading from regexp_split_to_table(view_def, '\n')), ' ') AS col_def
)
SELECT trim(trailing ',' FROM split_part(col_def[1], '.', 2))
FROM column_definitions
WHERE trim(trailing ',' FROM col_def[array_length(col_def, 1)]) IN ('t.the_geom_webmercator', 'the_geom_webmercator')
LIMIT 1;
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
--
-- List all registered tables in a server + schema
--
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_List_Registered_Tables(
server_internal NAME,
remote_schema TEXT
)
RETURNS TABLE(
registered boolean,
remote_table TEXT,
local_qualified_name TEXT,
id_column_name TEXT,
geom_column_name TEXT,
webmercator_column_name TEXT
)
AS $$
DECLARE
local_schema name := @extschema@.__CDB_FS_Create_Schema(server_internal, remote_schema);
BEGIN
RETURN QUERY SELECT
true as registered,
source_table::text as remote_table,
format('%I.%I', dependent_schema, dependent_view)::text as local_qualified_name,
@extschema@.__CDB_FS_Get_View_id_column(view_definition) as id_column_name,
@extschema@.__CDB_FS_Get_View_geom_column(view_definition) as geom_column_name,
@extschema@.__CDB_FS_Get_View_webmercator_column(view_definition) as webmercator_column_name
FROM
(
SELECT DISTINCT
dependent_ns.nspname as dependent_schema,
dependent_view.relname as dependent_view,
source_table.relname as source_table,
pg_get_viewdef(dependent_view.oid) as view_definition
FROM pg_depend
JOIN pg_rewrite ON pg_depend.objid = pg_rewrite.oid
JOIN pg_class as dependent_view ON pg_rewrite.ev_class = dependent_view.oid
JOIN pg_class as source_table ON pg_depend.refobjid = source_table.oid
JOIN pg_namespace dependent_ns ON dependent_ns.oid = dependent_view.relnamespace
JOIN pg_namespace source_ns ON source_ns.oid = source_table.relnamespace
WHERE
source_ns.nspname = local_schema
ORDER BY 1,2
) _aux;
END
$$
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
--------------------------------------------------------------------------------
-- Public functions
--------------------------------------------------------------------------------
--
-- Sets up a Federated Table
--
-- Precondition: the federated server has to be set up via
-- CDB_Federated_Server_Register_PG
--
-- Postcondition: it generates a view in the schema of the user that
-- can be used through SQL and Maps API's.
-- If the table was already exported, it will be dropped and re-imported
--
-- The view is placed under the server's view schema (cdb_fs_$(server_name))
--
-- E.g:
-- SELECT cartodb.CDB_SetUp_PG_Federated_Table(
-- 'amazon', -- mandatory, name of the federated server
-- 'my_remote_schema', -- mandatory, schema name
-- 'my_remote_table', -- mandatory, table name
-- 'id', -- mandatory, name of the id column
-- 'geom', -- optional, name of the geom column, preferably in 4326
-- 'webmercator' -- optional, should be in 3857 if present
-- 'local_name' -- optional, name of the local view (uses the remote_name if not declared)
-- );
--
CREATE OR REPLACE FUNCTION @extschema@.CDB_Federated_Table_Register(
server TEXT,
remote_schema TEXT,
remote_table TEXT,
id_column TEXT,
geom_column TEXT DEFAULT NULL,
webmercator_column TEXT DEFAULT NULL,
local_name NAME DEFAULT NULL
)
RETURNS void
AS $$
DECLARE
server_internal name := @extschema@.__CDB_FS_Generate_Server_Name(input_name => server, check_existence => false);
local_schema name := @extschema@.__CDB_FS_Create_Schema(server_internal, remote_schema);
role_name name := @extschema@.__CDB_FS_Generate_Server_Role_Name(server_internal);
src_table REGCLASS; -- import_schema.remote_table - import_schema is local_schema
local_view text; -- view_schema.local_name - view_schema is server_internal
rest_of_cols TEXT[];
geom_expression TEXT;
webmercator_expression TEXT;
carto_columns_expression TEXT[];
BEGIN
IF remote_table IS NULL THEN
RAISE EXCEPTION 'Remote table name cannot be NULL';
END IF;
-- Make do with whatever columns are provided
IF webmercator_column IS NULL THEN
webmercator_column := geom_column;
ELSIF geom_column IS NULL THEN
geom_column := webmercator_column;
END IF;
IF local_name IS NULL THEN
local_name := remote_table;
END IF;
-- Import the foreign table
-- Drop the old view / table if there was one
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = local_schema AND table_name = remote_table) THEN
EXECUTE @extschema@.CDB_Federated_Table_Unregister(server, remote_schema, remote_table);
END IF;
BEGIN
EXECUTE FORMAT('IMPORT FOREIGN SCHEMA %I LIMIT TO (%I) FROM SERVER %I INTO %I;',
remote_schema, remote_table, server_internal, local_schema);
EXCEPTION WHEN OTHERS THEN
RAISE EXCEPTION 'Could not import schema "%" of server "%": %', remote_schema, server, SQLERRM;
END;
BEGIN
src_table := format('%I.%I', local_schema, remote_table);
EXCEPTION WHEN OTHERS THEN
RAISE EXCEPTION 'Could not import table "%.%" of server "%"', remote_schema, remote_table, server;
END;
-- Check id_column is numeric
IF NOT @extschema@.__CDB_FS_Column_Is_Integer(src_table, id_column) THEN
RAISE EXCEPTION 'non integer id_column "%"', id_column;
END IF;
-- Check if the geom and mercator columns have a geometry type (if provided)
IF geom_column IS NOT NULL AND NOT @extschema@.__CDB_FS_Column_Is_Geometry(src_table, geom_column) THEN
RAISE EXCEPTION 'non geometry column "%"', geom_column;
END IF;
IF webmercator_column IS NOT NULL AND NOT @extschema@.__CDB_FS_Column_Is_Geometry(src_table, webmercator_column) THEN
RAISE EXCEPTION 'non geometry column "%"', webmercator_column;
END IF;
-- Get a list of columns excluding the id, geom and the_geom_webmercator
SELECT ARRAY(
SELECT quote_ident(c) FROM @extschema@.__CDB_FS_GetColumns(src_table) AS c
WHERE c NOT IN (SELECT * FROM (SELECT unnest(ARRAY[id_column, geom_column, webmercator_column, 'cartodb_id', 'the_geom', 'the_geom_webmercator']) col) carto WHERE carto.col IS NOT NULL)
) INTO rest_of_cols;
IF geom_column IS NULL
THEN
geom_expression := 'NULL AS the_geom';
ELSIF @postgisschema@.Find_SRID(local_schema::varchar, remote_table::varchar, geom_column::varchar) = 4326
THEN
geom_expression := format('t.%I AS the_geom', geom_column);
ELSE
-- It needs an ST_Transform to 4326
geom_expression := format('@postgisschema@.ST_Transform(t.%I,4326) AS the_geom', geom_column);
END IF;
IF webmercator_column IS NULL
THEN
webmercator_expression := 'NULL AS the_geom_webmercator';
ELSIF @postgisschema@.Find_SRID(local_schema::varchar, remote_table::varchar, webmercator_column::varchar) = 3857
THEN
webmercator_expression := format('t.%I AS the_geom_webmercator', webmercator_column);
ELSE
-- It needs an ST_Transform to 3857
webmercator_expression := format('@postgisschema@.ST_Transform(t.%I,3857) AS the_geom_webmercator', webmercator_column);
END IF;
-- CARTO columns expressions
carto_columns_expression := ARRAY[
format('t.%1$I AS cartodb_id', id_column),
geom_expression,
webmercator_expression
];
-- Create view schema if it doesn't exist
IF NOT EXISTS (SELECT oid FROM pg_namespace WHERE nspname = server_internal) THEN
EXECUTE 'CREATE SCHEMA ' || quote_ident(server_internal) || ' AUTHORIZATION ' || quote_ident(role_name);
END IF;
-- Create a view with homogeneous CDB fields
BEGIN
EXECUTE format(
'CREATE OR REPLACE VIEW %1$I.%2$I AS
SELECT %3s
FROM %4$s t',
server_internal, local_name,
array_to_string(carto_columns_expression || rest_of_cols, ','),
src_table
);
EXCEPTION WHEN OTHERS THEN
IF EXISTS (SELECT to_regclass(format('%1$I.%2$I', server_internal, local_name))) THEN
RAISE EXCEPTION 'Could not import table "%" as "%.%" already exists', remote_table, server_internal, local_name;
ELSE
RAISE EXCEPTION 'Could not import table "%" as "%": %', remote_table, local_name, SQLERRM;
END IF;
END;
END
$$
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
--
-- Unregisters a remote table. Any dependent object will be dropped
--
CREATE OR REPLACE FUNCTION @extschema@.CDB_Federated_Table_Unregister(
server TEXT,
remote_schema TEXT,
remote_table TEXT
)
RETURNS void
AS $$
DECLARE
server_internal name := @extschema@.__CDB_FS_Generate_Server_Name(input_name => server, check_existence => false);
local_schema name := @extschema@.__CDB_FS_Create_Schema(server_internal, remote_schema);
BEGIN
EXECUTE FORMAT ('DROP FOREIGN TABLE %I.%I CASCADE;', local_schema, remote_table);
END
$$
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;

View File

@@ -0,0 +1,215 @@
---------------------------
-- FDW MANAGEMENT FUNCTIONS
--
-- All the FDW settings are read from the `cdb_conf.fdws` entry json file.
---------------------------
CREATE OR REPLACE FUNCTION @extschema@._CDB_Setup_FDW(fdw_name text, config json)
RETURNS void
AS $$
DECLARE
row record;
option record;
org_role text;
BEGIN
-- This function tries to be as idempotent as possible, by not creating anything more than once
-- (not even using IF NOT EXIST to avoid throwing warnings)
IF NOT EXISTS ( SELECT * FROM pg_extension WHERE extname = 'postgres_fdw') THEN
CREATE EXTENSION postgres_fdw;
END IF;
-- Create FDW first if it does not exist
IF NOT EXISTS ( SELECT * FROM pg_foreign_server WHERE srvname = fdw_name)
THEN
EXECUTE FORMAT('CREATE SERVER %I FOREIGN DATA WRAPPER postgres_fdw', fdw_name);
END IF;
-- Set FDW settings
FOR row IN SELECT p.key, p.value from lateral json_each_text(config->'server') p
LOOP
IF NOT EXISTS (WITH a AS (select split_part(unnest(srvoptions), '=', 1) as options from pg_foreign_server where srvname=fdw_name) SELECT * from a where options = row.key)
THEN
EXECUTE FORMAT('ALTER SERVER %I OPTIONS (ADD %I %L)', fdw_name, row.key, row.value);
ELSE
EXECUTE FORMAT('ALTER SERVER %I OPTIONS (SET %I %L)', fdw_name, row.key, row.value);
END IF;
END LOOP;
-- Create user mappings
FOR row IN SELECT p.key, p.value from lateral json_each(config->'users') p LOOP
-- Check if entry on pg_user_mappings exists
IF NOT EXISTS ( SELECT * FROM pg_user_mappings WHERE srvname = fdw_name AND usename = row.key ) THEN
EXECUTE FORMAT ('CREATE USER MAPPING FOR %I SERVER %I', row.key, fdw_name);
END IF;
-- Update user mapping settings
FOR option IN SELECT o.key, o.value from lateral json_each_text(row.value) o LOOP
IF NOT EXISTS (WITH a AS (select split_part(unnest(umoptions), '=', 1) as options from pg_user_mappings WHERE srvname = fdw_name AND usename = row.key) SELECT * from a where options = option.key) THEN
EXECUTE FORMAT('ALTER USER MAPPING FOR %I SERVER %I OPTIONS (ADD %I %L)', row.key, fdw_name, option.key, option.value);
ELSE
EXECUTE FORMAT('ALTER USER MAPPING FOR %I SERVER %I OPTIONS (SET %I %L)', row.key, fdw_name, option.key, option.value);
END IF;
END LOOP;
END LOOP;
-- Create schema if it does not exist.
IF NOT EXISTS ( SELECT * from pg_namespace WHERE nspname=fdw_name) THEN
EXECUTE FORMAT ('CREATE SCHEMA %I', fdw_name);
END IF;
-- Give the organization role usage permisions over the schema
SELECT @extschema@.CDB_Organization_Member_Group_Role_Member_Name() INTO org_role;
EXECUTE FORMAT ('GRANT USAGE ON SCHEMA %I TO %I', fdw_name, org_role);
-- Bring here the remote cdb_tablemetadata
IF NOT EXISTS ( SELECT * FROM PG_CLASS WHERE relnamespace = (SELECT oid FROM pg_namespace WHERE nspname=fdw_name) and relname='cdb_tablemetadata') THEN
EXECUTE FORMAT ('CREATE FOREIGN TABLE %I.cdb_tablemetadata (tabname text, updated_at timestamp with time zone) SERVER %I OPTIONS (table_name ''cdb_tablemetadata_text'', schema_name ''@extschema@'', updatable ''false'')', fdw_name, fdw_name);
END IF;
EXECUTE FORMAT ('GRANT SELECT ON %I.cdb_tablemetadata TO %I', fdw_name, org_role);
END
$$
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
CREATE OR REPLACE FUNCTION @extschema@._CDB_Setup_FDWS()
RETURNS VOID AS
$$
DECLARE
row record;
BEGIN
FOR row IN SELECT p.key, p.value from lateral json_each(@extschema@.CDB_Conf_GetConf('fdws')) p LOOP
EXECUTE 'SELECT @extschema@._CDB_Setup_FDW($1, $2)' USING row.key, row.value;
END LOOP;
END
$$
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
CREATE OR REPLACE FUNCTION @extschema@._CDB_Setup_FDW(fdw_name text)
RETURNS void AS
$BODY$
DECLARE
config json;
BEGIN
SELECT p.value FROM LATERAL json_each(@extschema@.CDB_Conf_GetConf('fdws')) p WHERE p.key = fdw_name INTO config;
EXECUTE 'SELECT @extschema@._CDB_Setup_FDW($1, $2)' USING fdw_name, config;
END
$BODY$
LANGUAGE plpgsql VOLATILE PARALLEL UNSAFE;
CREATE OR REPLACE FUNCTION @extschema@.CDB_Add_Remote_Table(source text, table_name text)
RETURNS void AS
$$
BEGIN
PERFORM @extschema@._CDB_Setup_FDW(source);
EXECUTE FORMAT ('IMPORT FOREIGN SCHEMA %I LIMIT TO (%I) FROM SERVER %I INTO %I;', source, table_name, source, source);
--- Grant SELECT to publicuser
EXECUTE FORMAT ('GRANT SELECT ON %I.%I TO publicuser;', source, table_name);
END
$$
LANGUAGE plpgsql VOLATILE PARALLEL UNSAFE;
CREATE OR REPLACE FUNCTION @extschema@.CDB_Get_Foreign_Updated_At(foreign_table regclass)
RETURNS timestamp with time zone AS
$$
DECLARE
remote_table_name text;
fdw_schema_name text;
time timestamp with time zone;
BEGIN
-- This will turn a local foreign table (referenced as regclass) to its fully qualified text remote table reference.
WITH a AS (SELECT ftoptions FROM pg_foreign_table WHERE ftrelid=foreign_table LIMIT 1),
b as (SELECT (pg_options_to_table(ftoptions)).* FROM a)
SELECT FORMAT('%I.%I', (SELECT option_value FROM b WHERE option_name='schema_name'), (SELECT option_value FROM b WHERE option_name='table_name'))
INTO remote_table_name;
-- We assume that the remote cdb_tablemetadata is called cdb_tablemetadata and is on the same schema as the queried table.
SELECT nspname FROM pg_class c, pg_namespace n WHERE c.oid=foreign_table AND c.relnamespace = n.oid INTO fdw_schema_name;
BEGIN
EXECUTE FORMAT('SELECT updated_at FROM %I.cdb_tablemetadata WHERE tabname=%L ORDER BY updated_at DESC LIMIT 1', fdw_schema_name, remote_table_name) INTO time;
EXCEPTION
WHEN undefined_table THEN
-- If you add a GET STACKED DIAGNOSTICS text_var = RETURNED_SQLSTATE
-- you get a code 42P01 which corresponds to undefined_table
RAISE NOTICE 'CDB_Get_Foreign_Updated_At: could not find %.cdb_tablemetadata while checking % updated_at, returning NULL timestamp', fdw_schema_name, foreign_table;
END;
RETURN time;
END
$$
LANGUAGE plpgsql VOLATILE PARALLEL UNSAFE;
CREATE OR REPLACE FUNCTION @extschema@._cdb_dbname_of_foreign_table(reloid oid)
RETURNS TEXT AS $$
SELECT option_value FROM pg_options_to_table((
SELECT fs.srvoptions
FROM pg_foreign_table ft
LEFT JOIN pg_foreign_server fs ON ft.ftserver = fs.oid
WHERE ft.ftrelid = reloid
)) WHERE option_name='dbname';
$$ LANGUAGE SQL VOLATILE PARALLEL UNSAFE;
-- Return a set of (dbname, schema_name, table_name, updated_at)
-- It is aware of foreign tables
-- It assumes the local (schema_name, table_name) map to the remote ones with the same name
-- Note: dbname is never quoted whereas schema and table names are when needed.
CREATE OR REPLACE FUNCTION @extschema@.CDB_QueryTables_Updated_At(query text)
RETURNS TABLE(dbname text, schema_name text, table_name text, updated_at timestamptz)
AS $$
WITH query_tables AS (
SELECT unnest(@extschema@.CDB_QueryTablesText(query)) schema_table_name
), query_tables_oid AS (
SELECT schema_table_name, schema_table_name::regclass::oid AS reloid
FROM query_tables
),
fqtn AS (
SELECT
(CASE WHEN c.relkind = 'f' THEN @extschema@._cdb_dbname_of_foreign_table(query_tables_oid.reloid)
ELSE current_database()
END)::text AS dbname,
quote_ident(n.nspname::text) schema_name,
quote_ident(c.relname::text) table_name,
c.relkind,
query_tables_oid.reloid
FROM query_tables_oid, pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid
WHERE c.oid = query_tables_oid.reloid
)
SELECT fqtn.dbname, fqtn.schema_name, fqtn.table_name,
(CASE WHEN relkind = 'f' THEN @extschema@.CDB_Get_Foreign_Updated_At(reloid)
ELSE (SELECT md.updated_at FROM @extschema@.CDB_TableMetadata md WHERE md.tabname = reloid)
END) AS updated_at
FROM fqtn;
$$ LANGUAGE SQL VOLATILE PARALLEL UNSAFE;
-- Return the last updated time of a set of tables
-- It is aware of foreign tables
-- It assumes the local (schema_name, table_name) map to the remote ones with the same name
CREATE OR REPLACE FUNCTION @extschema@.CDB_Last_Updated_Time(tables text[])
RETURNS timestamptz AS $$
WITH t AS (
SELECT unnest(tables) AS schema_table_name
), t_oid AS (
SELECT (t.schema_table_name)::regclass::oid as reloid FROM t
), t_updated_at AS (
SELECT
(CASE WHEN relkind = 'f' THEN @extschema@.CDB_Get_Foreign_Updated_At(reloid)
ELSE (SELECT md.updated_at FROM @extschema@.CDB_TableMetadata md WHERE md.tabname = reloid)
END) AS updated_at
FROM t_oid
LEFT JOIN pg_catalog.pg_class c ON c.oid = reloid
) SELECT max(updated_at) FROM t_updated_at;
$$ LANGUAGE SQL VOLATILE PARALLEL UNSAFE;
--------------------------------------------------------------------------------
-- Deprecated
--------------------------------------------------------------------------------
DROP FUNCTION IF EXISTS @extschema@.__CDB_User_FDW_Object_Names(name);
DROP FUNCTION IF EXISTS @extschema@._CDB_SetUp_User_PG_FDW_Server(name, json);
DROP FUNCTION IF EXISTS @extschema@._CDB_Drop_User_PG_FDW_Server(name, boolean);
DROP FUNCTION IF EXISTS @extschema@.CDB_SetUp_User_PG_FDW_Table(name, name, name);

View File

@@ -0,0 +1,159 @@
-- Enqueues a job to run Ghost tables linking process for the provided username
CREATE OR REPLACE FUNCTION @extschema@._CDB_LinkGhostTables(username text, db_name text, event_name text)
RETURNS void
AS $$
if not username:
return
if 'json' not in GD:
import json
GD['json'] = json
else:
json = GD['json']
tis_config = plpy.execute("select @extschema@.CDB_Conf_GetConf('invalidation_service');")[0]['cdb_conf_getconf']
if not tis_config:
plpy.warning('Invalidation service configuration not found. Skipping Ghost Tables linking.')
return
tis_config_dict = json.loads(tis_config)
tis_host = tis_config_dict.get('host')
tis_port = tis_config_dict.get('port')
tis_timeout = tis_config_dict.get('timeout', 5)
tis_retry = tis_config_dict.get('retry', 5)
client = GD.get('invalidation', None)
while True:
if not client:
try:
import redis
client = redis.Redis(host=tis_host, port=tis_port, socket_timeout=tis_timeout)
GD['invalidation'] = client
except Exception as err:
# NOTE: no retries on connection error
plpy.warning('Error trying to connect to Invalidation Service to link Ghost Tables: ' + str(err))
break
try:
client.execute_command('DBSCH', db_name, username, event_name)
break
except Exception as err:
client = GD['invalidation'] = None # force reconnect
if not tis_retry:
plpy.warning('Error calling Invalidation Service to link Ghost Tables: ' + str(err))
break
tis_retry -= 1 # try reconnecting
$$ LANGUAGE '@@plpythonu@@' VOLATILE PARALLEL UNSAFE;
-- Enqueues a job to run Ghost tables linking process for the current user
CREATE OR REPLACE FUNCTION @extschema@.CDB_LinkGhostTables(event_name text DEFAULT 'USER')
RETURNS void
AS $$
DECLARE
username TEXT;
db_name TEXT;
BEGIN
EXECUTE 'SELECT @extschema@.CDB_Username();' INTO username;
EXECUTE 'SELECT current_database();' INTO db_name;
PERFORM @extschema@._CDB_LinkGhostTables(username, db_name, event_name);
RAISE INFO '_CDB_LinkGhostTables() called with username=%, event_name=%', username, event_name;
END;
$$ LANGUAGE plpgsql
VOLATILE
PARALLEL UNSAFE
SECURITY DEFINER
SET search_path = pg_temp;
-- Trigger function to call CDB_LinkGhostTables()
CREATE OR REPLACE FUNCTION @extschema@._CDB_LinkGhostTablesTrigger()
RETURNS trigger
AS $$
DECLARE
ddl_tag TEXT;
BEGIN
EXECUTE 'DELETE FROM @extschema@.cdb_ddl_execution WHERE txid = txid_current() RETURNING tag;' INTO ddl_tag;
PERFORM @extschema@.CDB_LinkGhostTables(ddl_tag);
RETURN NULL;
END;
$$ LANGUAGE plpgsql
VOLATILE
PARALLEL UNSAFE
SECURITY DEFINER
SET search_path = pg_temp;
-- Event trigger to save the current transaction in @extschema@.cdb_ddl_execution
CREATE OR REPLACE FUNCTION @extschema@.CDB_SaveDDLTransaction()
RETURNS event_trigger
AS $$
BEGIN
INSERT INTO @extschema@.cdb_ddl_execution VALUES (txid_current(), tg_tag) ON CONFLICT ON CONSTRAINT cdb_ddl_execution_pkey DO NOTHING;
END;
$$ LANGUAGE plpgsql
VOLATILE
PARALLEL UNSAFE
SECURITY DEFINER
SET search_path = pg_temp;
-- Creates the trigger on DDL events to link ghost tables
CREATE OR REPLACE FUNCTION @extschema@.CDB_EnableGhostTablesTrigger()
RETURNS void
AS $$
BEGIN
DROP EVENT TRIGGER IF EXISTS link_ghost_tables;
DROP TRIGGER IF EXISTS check_ddl_update ON @extschema@.cdb_ddl_execution;
-- Table to store the transaction id from DDL events to avoid multiple executions
CREATE TABLE IF NOT EXISTS @extschema@.cdb_ddl_execution(txid bigint PRIMARY KEY, tag text);
CREATE CONSTRAINT TRIGGER check_ddl_update
AFTER INSERT ON @extschema@.cdb_ddl_execution
INITIALLY DEFERRED
FOR EACH ROW
EXECUTE PROCEDURE @extschema@._CDB_LinkGhostTablesTrigger();
CREATE EVENT TRIGGER link_ghost_tables
ON ddl_command_end
WHEN TAG IN ('CREATE TABLE',
'SELECT INTO',
'DROP TABLE',
'ALTER TABLE',
'CREATE TRIGGER',
'DROP TRIGGER',
'ALTER TRIGGER',
'CREATE VIEW',
'DROP VIEW',
'ALTER VIEW',
'CREATE FOREIGN TABLE',
'ALTER FOREIGN TABLE',
'DROP FOREIGN TABLE',
'ALTER MATERIALIZED VIEW',
'CREATE MATERIALIZED VIEW',
'DROP MATERIALIZED VIEW',
'IMPORT FOREIGN SCHEMA',
'DROP EXTENSION',
'DROP SCHEMA',
'DROP SERVER',
'DROP TYPE')
EXECUTE PROCEDURE @extschema@.CDB_SaveDDLTransaction();
END;
$$ LANGUAGE plpgsql VOLATILE PARALLEL UNSAFE;
-- Drops the trigger on DDL events to link ghost tables
CREATE OR REPLACE FUNCTION @extschema@.CDB_DisableGhostTablesTrigger()
RETURNS void
AS $$
BEGIN
DROP EVENT TRIGGER IF EXISTS link_ghost_tables;
DROP TRIGGER IF EXISTS check_ddl_update ON @extschema@.cdb_ddl_execution;
DROP TABLE IF EXISTS @extschema@.cdb_ddl_execution;
END;
$$ LANGUAGE plpgsql VOLATILE PARALLEL UNSAFE;

View File

@@ -0,0 +1,26 @@
-- Great circle point-to-point routes, based on:
-- http://blog.cartodb.com/jets-and-datelines/
--
CREATE OR REPLACE FUNCTION @extschema@.CDB_GreatCircle(start_point @postgisschema@.geometry, end_point @postgisschema@.geometry, max_segment_length NUMERIC DEFAULT 100000)
RETURNS @postgisschema@.geometry AS $$
DECLARE
line @postgisschema@.geometry;
BEGIN
line = @postgisschema@.ST_Segmentize(
@postgisschema@.ST_Makeline(
start_point,
end_point
)::geography,
max_segment_length
)::geometry;
IF @postgisschema@.ST_XMax(line) - @postgisschema@.ST_XMin(line) > 180 THEN
line = @postgisschema@.ST_Difference(
@postgisschema@.ST_ShiftLongitude(line),
@postgisschema@.ST_Buffer(@postgisschema@.ST_GeomFromText('LINESTRING(180 90, 180 -90)', 4326), 0.00001)
);
END IF;
RETURN line;
END;
$$
LANGUAGE 'plpgsql' IMMUTABLE STRICT PARALLEL SAFE;

View File

@@ -0,0 +1,252 @@
----------------------------------
-- GROUP MANAGEMENT FUNCTIONS
--
-- Meant to be used by org admin. See CDB_Organization_AddAdmin.
----------------------------------
-- Creates a new group
CREATE OR REPLACE
FUNCTION @extschema@.CDB_Group_CreateGroup(group_name text)
RETURNS VOID AS $$
DECLARE
group_role TEXT;
BEGIN
group_role := @extschema@._CDB_Group_GroupRole(group_name);
EXECUTE format('CREATE ROLE %I NOLOGIN;', group_role);
PERFORM @extschema@._CDB_Group_CreateGroup_API(group_name, group_role);
END
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
-- Drops group and everything that role owns
-- TODO: LIMITATION: in order to drop a role all its owned objects must be dropped before.
-- Right now this is done with DROP OWNED, which can only be done by a superadmin.
-- Not even the role creator can drop the role and the objects it owns.
-- All group owned objects by the group are permissions.
CREATE OR REPLACE
FUNCTION @extschema@.CDB_Group_DropGroup(group_name text)
RETURNS VOID AS $$
DECLARE
group_role TEXT;
BEGIN
group_role := @extschema@._CDB_Group_GroupRole(group_name);
EXECUTE format('DROP OWNED BY %I', group_role);
EXECUTE format('DROP ROLE IF EXISTS %I', group_role);
PERFORM @extschema@._CDB_Group_DropGroup_API(group_name);
END
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
-- Renames a group
CREATE OR REPLACE
FUNCTION @extschema@.CDB_Group_RenameGroup(old_group_name text, new_group_name text)
RETURNS VOID AS $$
DECLARE
old_group_role TEXT;
new_group_role TEXT;
BEGIN
old_group_role = @extschema@._CDB_Group_GroupRole(old_group_name);
new_group_role = @extschema@._CDB_Group_GroupRole(new_group_name);
EXECUTE format('ALTER ROLE %I RENAME TO %I', old_group_role, new_group_role);
PERFORM @extschema@._CDB_Group_RenameGroup_API(old_group_name, new_group_name, new_group_role);
END
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
-- Adds users to a group
CREATE OR REPLACE
FUNCTION @extschema@.CDB_Group_AddUsers(group_name text, usernames text[])
RETURNS VOID AS $$
DECLARE
group_role TEXT;
user_role TEXT;
username TEXT;
BEGIN
group_role := @extschema@._CDB_Group_GroupRole(group_name);
foreach username in array usernames
loop
user_role := @extschema@._CDB_User_RoleFromUsername(username);
IF(group_role IS NULL OR user_role IS NULL)
THEN
RAISE EXCEPTION 'Group role (%) and user role (%) must be already existing', group_role, user_role;
END IF;
EXECUTE format('GRANT %I TO %I', group_role, user_role);
end loop;
PERFORM @extschema@._CDB_Group_AddUsers_API(group_name, usernames);
END
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
-- Removes users from a group
CREATE OR REPLACE
FUNCTION @extschema@.CDB_Group_RemoveUsers(group_name text, usernames text[])
RETURNS VOID AS $$
DECLARE
group_role TEXT;
user_role TEXT;
username TEXT;
BEGIN
group_role := @extschema@._CDB_Group_GroupRole(group_name);
foreach username in array usernames
loop
user_role := @extschema@._CDB_User_RoleFromUsername(username);
EXECUTE format('REVOKE %I FROM %I', group_role, user_role);
end loop;
PERFORM @extschema@._CDB_Group_RemoveUsers_API(group_name, usernames);
END
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
----------------------------------
-- TABLE MANAGEMENT FUNCTIONS
--
-- Meant to be used by table owners.
----------------------------------
-- Grants table read permission to a group
CREATE OR REPLACE
FUNCTION @extschema@.CDB_Group_Table_GrantRead(group_name text, username text, table_name text)
RETURNS VOID AS $$
DECLARE
group_role TEXT;
BEGIN
PERFORM @extschema@._CDB_Group_Table_GrantRead(group_name, username, table_name, true);
END
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
CREATE OR REPLACE
FUNCTION @extschema@._CDB_Group_Table_GrantRead(group_name text, username text, table_name text, sync boolean)
RETURNS VOID AS $$
DECLARE
group_role TEXT;
BEGIN
group_role := @extschema@._CDB_Group_GroupRole(group_name);
EXECUTE format('GRANT USAGE ON SCHEMA %I TO %I', username, group_role);
EXECUTE format('GRANT SELECT ON TABLE %I.%I TO %I', username, table_name, group_role );
IF(sync) THEN
PERFORM @extschema@._CDB_Group_Table_GrantPermission_API(group_name, username, table_name, 'r');
END IF;
END
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
-- Grants table write permission to a group
CREATE OR REPLACE
FUNCTION @extschema@.CDB_Group_Table_GrantReadWrite(group_name text, username text, table_name text)
RETURNS VOID AS $$
DECLARE
group_role TEXT;
BEGIN
PERFORM @extschema@._CDB_Group_Table_GrantReadWrite(group_name, username, table_name, true);
END
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
CREATE OR REPLACE
FUNCTION @extschema@._CDB_Group_Table_GrantReadWrite(group_name text, username text, table_name text, sync boolean)
RETURNS VOID AS $$
DECLARE
group_role TEXT;
BEGIN
group_role := @extschema@._CDB_Group_GroupRole(group_name);
EXECUTE format('GRANT USAGE ON SCHEMA %I TO %I', username, group_role);
EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE %I.%I TO %I', username, table_name, group_role);
PERFORM @extschema@._CDB_Group_TableSequences_Permission(group_name, username, table_name, true);
IF(sync) THEN
PERFORM @extschema@._CDB_Group_Table_GrantPermission_API(group_name, username, table_name, 'w');
END IF;
END
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
-- Granting and revoking permissions on sequences
CREATE OR REPLACE
FUNCTION @extschema@._CDB_Group_TableSequences_Permission(group_name text, username text, table_name text, do_grant bool)
RETURNS VOID AS $$
DECLARE
column_name TEXT;
sequence_name TEXT;
group_role TEXT;
BEGIN
group_role := @extschema@._CDB_Group_GroupRole(group_name);
FOR column_name IN EXECUTE 'SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_CATALOG = current_database() AND TABLE_SCHEMA = $1 AND TABLE_NAME = $2 AND COLUMN_DEFAULT LIKE ''nextval%''' USING username, table_name
LOOP
EXECUTE format('SELECT PG_GET_SERIAL_SEQUENCE(''%I.%I'', ''%I'')', username, table_name, column_name) INTO sequence_name;
IF sequence_name IS NOT NULL THEN
IF do_grant THEN
-- Here %s is needed since sequence_name has quotes
EXECUTE format('GRANT USAGE, SELECT, UPDATE ON SEQUENCE %s TO %I', sequence_name, group_role);
ELSE
EXECUTE format('REVOKE ALL ON SEQUENCE %s FROM %I', sequence_name, group_role);
END IF;
END IF;
END LOOP;
RETURN;
END
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
-- Revokes all permissions on a table from a group
CREATE OR REPLACE
FUNCTION @extschema@.CDB_Group_Table_RevokeAll(group_name text, username text, table_name text)
RETURNS VOID AS $$
DECLARE
group_role TEXT;
BEGIN
PERFORM @extschema@._CDB_Group_Table_RevokeAll(group_name, username, table_name, true);
END
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
CREATE OR REPLACE
FUNCTION @extschema@._CDB_Group_Table_RevokeAll(group_name text, username text, table_name text, sync boolean)
RETURNS VOID AS $$
DECLARE
group_role TEXT;
BEGIN
group_role := @extschema@._CDB_Group_GroupRole(group_name);
EXECUTE format('REVOKE ALL ON TABLE %I.%I FROM %I', username, table_name, group_role);
PERFORM @extschema@._CDB_Group_TableSequences_Permission(group_name, username, table_name, false);
IF(sync) THEN
PERFORM @extschema@._CDB_Group_Table_RevokeAllPermission_API(group_name, username, table_name);
END IF;
END
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
-----------------------
-- Helper functions
-----------------------
-- Given a group name returns a role. group_name must be a valid PostgreSQL idenfifier. See http://www.postgresql.org/docs/9.2/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
CREATE OR REPLACE
FUNCTION @extschema@._CDB_Group_GroupRole(group_name text)
RETURNS TEXT AS $$
DECLARE
group_role TEXT;
prefix TEXT;
max_length constant INTEGER := 63;
BEGIN
prefix = format('%s_g_', @extschema@._CDB_Group_ShortDatabaseName());
group_role := format('%s%s', prefix, group_name);
IF LENGTH(group_role) > max_length
THEN
RAISE EXCEPTION 'Group name must be shorter. It can''t have more than % characters, but it is longer (%): %', max_length - LENGTH(prefix), length(group_name), group_name;
END IF;
RETURN group_role;
END
$$ LANGUAGE PLPGSQL STABLE PARALLEL SAFE;
-- Returns the first owner of the schema matching username. Organization user schemas must have one only owner.
CREATE OR REPLACE
FUNCTION @extschema@._CDB_User_RoleFromUsername(username text)
RETURNS TEXT AS $$
DECLARE
user_role TEXT;
BEGIN
-- This was preferred, but non-superadmins won't get results
-- SELECT SCHEMA_OWNER FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = $1 LIMIT 1'
SELECT pg_get_userbyid(nspowner) FROM pg_namespace WHERE nspname = username INTO user_role;
RETURN user_role;
END
$$ LANGUAGE PLPGSQL STABLE PARALLEL SAFE;
-- Database names are too long, we need a shorter version for composing role names
CREATE OR REPLACE
FUNCTION @extschema@._CDB_Group_ShortDatabaseName()
RETURNS TEXT AS $$
DECLARE
short_database_name TEXT;
BEGIN
SELECT md5(current_database()) INTO short_database_name;
RETURN short_database_name;
END
$$ LANGUAGE PLPGSQL STABLE PARALLEL SAFE;

View File

@@ -0,0 +1,243 @@
----------------------------------
-- GROUP METADATA API FUNCTIONS
--
-- Meant to be used by CDB_Group_* functions to sync data with the editor.
-- Requires configuration parameter. Example: SELECT @extschema@.CDB_Conf_SetConf('groups_api', '{ "host": "127.0.0.1", "port": 3000, "timeout": 10, "username": "extension", "password": "elephant" }');
----------------------------------
DROP FUNCTION IF EXISTS @extschema@.CDB_Group_AddMember(group_name text, username text);
DROP FUNCTION IF EXISTS @extschema@.CDB_Group_RemoveMember(group_name text, username text);
DROP FUNCTION IF EXISTS @extschema@._CDB_Group_AddMember_API(group_name text, username text);
DROP FUNCTION IF EXISTS @extschema@._CDB_Group_RemoveMember_API(group_name text, username text);
-- Sends the create group request
CREATE OR REPLACE
FUNCTION @extschema@._CDB_Group_CreateGroup_API(group_name text, group_role text)
RETURNS VOID AS
$$
import string
url = '/api/v1/databases/{0}/groups'
body = '{ "name": "%s", "database_role": "%s" }' % (group_name, group_role)
query = "select @extschema@._CDB_Group_API_Request('POST', '%s', '%s', '{200, 409}') as response_status" % (url, body)
plpy.execute(query)
$$ LANGUAGE '@@plpythonu@@'
VOLATILE
PARALLEL UNSAFE
SECURITY DEFINER
SET search_path = pg_temp;
CREATE OR REPLACE
FUNCTION @extschema@._CDB_Group_DropGroup_API(group_name text)
RETURNS VOID AS
$$
import string
try:
from urllib import pathname2url
except:
from urllib.request import pathname2url
url = '/api/v1/databases/{0}/groups/%s' % (pathname2url(group_name))
query = "select @extschema@._CDB_Group_API_Request('DELETE', '%s', '', '{204, 404}') as response_status" % url
plpy.execute(query)
$$ LANGUAGE '@@plpythonu@@'
VOLATILE
PARALLEL UNSAFE
SECURITY DEFINER
SET search_path = pg_temp;
CREATE OR REPLACE
FUNCTION @extschema@._CDB_Group_RenameGroup_API(old_group_name text, new_group_name text, new_group_role text)
RETURNS VOID AS
$$
import string
try:
from urllib import pathname2url
except:
from urllib.request import pathname2url
url = '/api/v1/databases/{0}/groups/%s' % (pathname2url(old_group_name))
body = '{ "name": "%s", "database_role": "%s" }' % (new_group_name, new_group_role)
query = "select @extschema@._CDB_Group_API_Request('PUT', '%s', '%s', '{200, 409}') as response_status" % (url, body)
plpy.execute(query)
$$ LANGUAGE '@@plpythonu@@'
VOLATILE
PARALLEL UNSAFE
SECURITY DEFINER
SET search_path = pg_temp;
CREATE OR REPLACE
FUNCTION @extschema@._CDB_Group_AddUsers_API(group_name text, usernames text[])
RETURNS VOID AS
$$
import string
try:
from urllib import pathname2url
except:
from urllib.request import pathname2url
url = '/api/v1/databases/{0}/groups/%s/users' % (pathname2url(group_name))
body = "{ \"users\": [\"%s\"] }" % "\",\"".join(usernames)
query = "select @extschema@._CDB_Group_API_Request('POST', '%s', '%s', '{200, 409}') as response_status" % (url, body)
plpy.execute(query)
$$ LANGUAGE '@@plpythonu@@'
VOLATILE
PARALLEL UNSAFE
SECURITY DEFINER
SET search_path = pg_temp;
CREATE OR REPLACE
FUNCTION @extschema@._CDB_Group_RemoveUsers_API(group_name text, usernames text[])
RETURNS VOID AS
$$
import string
try:
from urllib import pathname2url
except:
from urllib.request import pathname2url
url = '/api/v1/databases/{0}/groups/%s/users' % (pathname2url(group_name))
body = "{ \"users\": [\"%s\"] }" % "\",\"".join(usernames)
query = "select @extschema@._CDB_Group_API_Request('DELETE', '%s', '%s', '{200, 404}') as response_status" % (url, body)
plpy.execute(query)
$$ LANGUAGE '@@plpythonu@@'
VOLATILE
PARALLEL UNSAFE
SECURITY DEFINER
SET search_path = pg_temp;
DO LANGUAGE 'plpgsql' $$
BEGIN
-- Needed for dropping type
DROP FUNCTION IF EXISTS @extschema@._CDB_Group_API_Conf();
DROP TYPE IF EXISTS @extschema@._CDB_Group_API_Params;
END
$$;
CREATE OR REPLACE
FUNCTION @extschema@._CDB_Group_Table_GrantPermission_API(group_name text, username text, table_name text, access text)
RETURNS VOID AS
$$
import string
try:
from urllib import pathname2url
except:
from urllib.request import pathname2url
url = '/api/v1/databases/{0}/groups/%s/permission/%s/tables/%s' % (pathname2url(group_name), username, table_name)
body = '{ "access": "%s" }' % access
query = "select @extschema@._CDB_Group_API_Request('PUT', '%s', '%s', '{200, 409}') as response_status" % (url, body)
plpy.execute(query)
$$ LANGUAGE '@@plpythonu@@'
VOLATILE
PARALLEL UNSAFE
SECURITY DEFINER
SET search_path = pg_temp;
DO LANGUAGE 'plpgsql' $$
BEGIN
-- Needed for dropping type
DROP FUNCTION IF EXISTS @extschema@._CDB_Group_API_Conf();
DROP TYPE IF EXISTS @extschema@._CDB_Group_API_Params;
END
$$;
CREATE OR REPLACE
FUNCTION @extschema@._CDB_Group_Table_RevokeAllPermission_API(group_name text, username text, table_name text)
RETURNS VOID AS
$$
import string
try:
from urllib import pathname2url
except:
from urllib.request import pathname2url
url = '/api/v1/databases/{0}/groups/%s/permission/%s/tables/%s' % (pathname2url(group_name), username, table_name)
query = "select @extschema@._CDB_Group_API_Request('DELETE', '%s', '', '{200, 404}') as response_status" % url
plpy.execute(query)
$$ LANGUAGE '@@plpythonu@@'
VOLATILE
PARALLEL UNSAFE
SECURITY DEFINER
SET search_path = pg_temp;
DO LANGUAGE 'plpgsql' $$
BEGIN
-- Needed for dropping type
DROP FUNCTION IF EXISTS @extschema@._CDB_Group_API_Conf();
DROP TYPE IF EXISTS @extschema@._CDB_Group_API_Params;
END
$$;
CREATE TYPE @extschema@._CDB_Group_API_Params AS (
host text,
port int,
timeout int,
auth text
);
-- This must be explicitally extracted because "composite types are currently not supported".
-- See http://www.postgresql.org/docs/9.3/static/plpython-database.html.
CREATE OR REPLACE
FUNCTION @extschema@._CDB_Group_API_Conf()
RETURNS @extschema@._CDB_Group_API_Params AS
$$
conf = plpy.execute("SELECT @extschema@.CDB_Conf_GetConf('groups_api') conf")[0]['conf']
if conf is None:
return None
else:
import json
params = json.loads(conf)
auth = 'Basic %s' % plpy.execute("SELECT @extschema@._CDB_Group_API_Auth('%s', '%s') as auth" % (params['username'], params['password']))[0]['auth']
return { "host": params['host'], "port": params['port'], 'timeout': params['timeout'], 'auth': auth }
$$ LANGUAGE '@@plpythonu@@' VOLATILE PARALLEL UNSAFE;
CREATE OR REPLACE
FUNCTION @extschema@._CDB_Group_API_Auth(username text, password text)
RETURNS TEXT AS
$$
import base64
return base64.encodestring('%s:%s' % (username, password)).replace('\n', '')
$$ LANGUAGE '@@plpythonu@@' VOLATILE PARALLEL UNSAFE;
-- url must contain a '%s' placeholder that will be replaced by current_database, for security reasons.
CREATE OR REPLACE
FUNCTION @extschema@._CDB_Group_API_Request(method text, url text, body text, valid_return_codes int[])
RETURNS int AS
$$
try:
import httplib as client
except:
from http import client
params = plpy.execute("select c.host, c.port, c.timeout, c.auth from @extschema@._CDB_Group_API_Conf() c;")[0]
if params['host'] is None:
return None
headers = { 'Authorization': params['auth'], 'Content-Type': 'application/json', 'X-Forwarded-Proto': 'https' }
retry = 3
last_err = None
while retry > 0:
try:
conn = SD['groups_api_client'] = client.HTTPConnection(params['host'], params['port'], False, params['timeout'])
database_name = plpy.execute("select current_database();")[0]['current_database']
conn.request(method, url.format(database_name), body, headers)
response = conn.getresponse()
assert response.status in valid_return_codes
return response.status
except Exception as err:
retry -= 1
last_err = err
plpy.warning('Retrying after: ' + str(err))
conn = SD['groups_api_client'] = None
if last_err is not None:
plpy.error('Fatal Group API error: ' + str(last_err))
raise last_err
return None
$$ LANGUAGE '@@plpythonu@@' VOLATILE PARALLEL UNSAFE;
revoke all on function @extschema@._CDB_Group_API_Request(text, text, text, int[]) from public;

View File

@@ -8,7 +8,7 @@
--
--
CREATE OR REPLACE FUNCTION CDB_HeadsTailsBins ( in_array NUMERIC[], breaks INT) RETURNS NUMERIC[] as $$
CREATE OR REPLACE FUNCTION @extschema@.CDB_HeadsTailsBins ( in_array NUMERIC[], breaks INT) RETURNS NUMERIC[] as $$
DECLARE
element_count INT4;
arr_mean numeric;
@@ -43,4 +43,4 @@ BEGIN
END LOOP;
RETURN reply;
END;
$$ language plpgsql IMMUTABLE;
$$ language plpgsql IMMUTABLE PARALLEL SAFE;

View File

@@ -0,0 +1,177 @@
-- Create a sequence that belongs to the schema of the extension.
-- It will be used to generate unique identifiers within the
-- UTF8 safe and length aware. Find a unique identifier with a given prefix
-- and/or suffix and withing a schema. If a schema is not specified, the identifier
-- is guaranteed to be unique for all schemas.
CREATE OR REPLACE FUNCTION @extschema@._CDB_Unique_Identifier(prefix TEXT, relname TEXT, suffix TEXT, schema TEXT DEFAULT NULL)
RETURNS TEXT
AS $$
DECLARE
maxlen CONSTANT INTEGER := 63;
rec RECORD;
usedspace INTEGER;
ident TEXT;
origident TEXT;
candrelname TEXT;
i INTEGER;
BEGIN
-- Accounts for the XXXX incremental suffix in case the identifier is taken
usedspace := 4;
usedspace := usedspace + coalesce(octet_length(prefix), 0);
usedspace := usedspace + coalesce(octet_length(suffix), 0);
candrelname := @extschema@._CDB_Octet_Truncate(relname, maxlen - usedspace);
IF candrelname = '' THEN
PERFORM @extschema@._CDB_Error('prefixes are to long to generate a valid identifier', '_CDB_Unique_Identifier');
END IF;
ident := coalesce(prefix, '') || candrelname || coalesce(suffix, '');
i := 0;
origident := ident;
WHILE i < 10000 LOOP
IF schema IS NOT NULL THEN
SELECT c.relname, n.nspname
INTO rec
FROM pg_class c
JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE c.relname = ident
AND n.nspname = schema;
ELSE
SELECT c.relname, n.nspname
INTO rec
FROM pg_class c
JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE c.relname = ident;
END IF;
IF NOT FOUND THEN
RETURN ident;
END IF;
ident := origident || i;
i := i + 1;
END LOOP;
PERFORM @extschema@._CDB_Error('looping too far', '_CDB_Unique_Identifier');
END;
$$ LANGUAGE 'plpgsql' VOLATILE PARALLEL UNSAFE;
-- UTF8 safe and length aware. Find a unique identifier for a column with a given prefix
-- and/or suffix based on colname and within a relation specified via reloid.
CREATE OR REPLACE FUNCTION @extschema@._CDB_Unique_Column_Identifier(prefix TEXT, colname TEXT, suffix TEXT, reloid REGCLASS)
RETURNS TEXT
AS $$
DECLARE
maxlen CONSTANT INTEGER := 63;
rec RECORD;
candcolname TEXT;
usedspace INTEGER;
ident TEXT;
origident TEXT;
i INTEGER;
BEGIN
-- Accounts for the XXXX incremental suffix in case the identifier is taken
usedspace := 4;
usedspace := usedspace + coalesce(octet_length(prefix), 0);
usedspace := usedspace + coalesce(octet_length(suffix), 0);
candcolname := @extschema@._CDB_Octet_Truncate(colname, maxlen - usedspace);
IF candcolname = '' THEN
PERFORM @extschema@._CDB_Error('prefixes are to long to generate a valid identifier', '_CDB_Unique_Column_Identifier');
END IF;
ident := coalesce(prefix, '') || candcolname || coalesce(suffix, '');
i := 0;
origident := ident;
WHILE i < 10000 LOOP
SELECT a.attname
INTO rec
FROM pg_class c
JOIN pg_attribute a ON a.attrelid = c.oid
WHERE NOT a.attisdropped
AND a.attnum > 0
AND c.oid = reloid
AND a.attname = ident;
IF NOT FOUND THEN
RETURN ident;
END IF;
ident := origident || i;
i := i + 1;
END LOOP;
PERFORM @extschema@._CDB_Error('looping too far', '_CDB_Unique_Column_Identifier');
END;
$$ LANGUAGE 'plpgsql' VOLATILE PARALLEL SAFE;
-- Truncates a given string to a max_octets octets taking care
-- not to leave characters in half. UTF8 safe.
CREATE OR REPLACE FUNCTION @extschema@._CDB_Octet_Truncate(string TEXT, max_octets INTEGER)
RETURNS TEXT
AS $$
DECLARE
extcharlen CONSTANT INTEGER := octet_length('ñ');
expected INTEGER;
examined INTEGER;
strlen INTEGER;
i INTEGER;
BEGIN
IF max_octets <= 0 THEN
RETURN '';
ELSIF max_octets >= octet_length(string) THEN
RETURN string;
END IF;
strlen := char_length(string);
expected := char_length(string);
examined := octet_length(string);
IF expected = examined THEN
RETURN left(string, max_octets);
END IF;
i := max_octets / extcharlen;
WHILE octet_length(left(string, i)) <= max_octets LOOP
i := i + 1;
END LOOP;
RETURN left(string, (i - 1));
END;
$$ LANGUAGE 'plpgsql' IMMUTABLE PARALLEL SAFE;
-- Checks if a given text representing a qualified or unqualified table name (relation)
-- actually exists in the database. It is meant to be used as a guard for other function/queries.
CREATE OR REPLACE FUNCTION @extschema@._CDB_Table_Exists(table_name_with_optional_schema TEXT)
RETURNS bool
AS $$
DECLARE
table_exists bool := false;
BEGIN
table_exists := EXISTS(SELECT * FROM pg_class WHERE table_name_with_optional_schema::regclass::oid = oid AND relkind = 'r');
RETURN table_exists;
EXCEPTION
WHEN invalid_schema_name OR undefined_table THEN
RETURN false;
END;
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;

View File

@@ -1,14 +1,18 @@
-- Return an Hexagon with given center and side (or maximal radius)
CREATE OR REPLACE FUNCTION CDB_MakeHexagon(center GEOMETRY, radius FLOAT8)
CREATE OR REPLACE FUNCTION @extschema@.CDB_MakeHexagon(center GEOMETRY, radius FLOAT8)
RETURNS GEOMETRY
AS $$
SELECT ST_MakePolygon(ST_MakeLine(geom))
SELECT @postgisschema@.ST_MakePolygon(@postgisschema@.ST_MakeLine(geom))
FROM
(
SELECT (ST_DumpPoints(ST_ExteriorRing(ST_Buffer($1, $2, 3)))).*
SELECT (@postgisschema@.ST_DumpPoints(@postgisschema@.ST_ExteriorRing(@postgisschema@.ST_Buffer($1, $2, 3)))).*
) as points
WHERE path[1] % 2 != 0
$$ LANGUAGE 'sql' IMMUTABLE STRICT;
$$ LANGUAGE 'sql' IMMUTABLE STRICT PARALLEL SAFE;
-- In older versions of the extension, CDB_HexagonGrid had a different signature
DROP FUNCTION IF EXISTS @extschema@.CDB_HexagonGrid(GEOMETRY, FLOAT8, GEOMETRY);
--
-- Fill given extent with an hexagonal coverage
@@ -25,10 +29,13 @@ $$ LANGUAGE 'sql' IMMUTABLE STRICT;
-- If omitted the origin will be 0,0.
-- The parameter is checked for having the same SRID
-- as the extent.
--
--
-- @param maxcells Optional maximum number of grid cells to generate;
-- if the grid requires more cells to cover the extent
-- and exception will occur.
----
-- DROP FUNCTION IF EXISTS CDB_HexagonGrid(ext GEOMETRY, side FLOAT8);
CREATE OR REPLACE FUNCTION CDB_HexagonGrid(ext GEOMETRY, side FLOAT8, origin GEOMETRY DEFAULT NULL)
CREATE OR REPLACE FUNCTION @extschema@.CDB_HexagonGrid(ext GEOMETRY, side FLOAT8, origin GEOMETRY DEFAULT NULL, maxcells INTEGER DEFAULT 512*512)
RETURNS SETOF GEOMETRY
AS $$
DECLARE
@@ -73,11 +80,11 @@ BEGIN
yoff := 0;
IF origin IS NOT NULL THEN
IF ST_SRID(origin) != srid THEN
IF @postgisschema@.ST_SRID(origin) != srid THEN
RAISE EXCEPTION 'SRID mismatch between extent (%) and origin (%)', srid, ST_SRID(origin);
END IF;
xoff := ST_X(origin);
yoff := ST_Y(origin);
xoff := @postgisschema@.ST_X(origin);
yoff := @postgisschema@.ST_Y(origin);
END IF;
RAISE DEBUG 'X offset: %', xoff;
@@ -89,47 +96,53 @@ BEGIN
RAISE DEBUG 'Y grid size: %', ygrd;
-- Tweak horizontal start on hstep*2 grid from origin
hskip := ceil((ST_XMin(ext)-xoff)/hstep);
hskip := ceil((@postgisschema@.ST_XMin(ext)-xoff)/hstep);
RAISE DEBUG 'hskip: %', hskip;
hstart := xoff + hskip*hstep;
RAISE DEBUG 'hstart: %', hstart;
-- Tweak vertical start on hstep grid from origin
vstart := yoff + ceil((ST_Ymin(ext)-yoff)/vstep)*vstep;
vstart := yoff + ceil((@postgisschema@.ST_Ymin(ext)-yoff)/vstep)*vstep;
RAISE DEBUG 'vstart: %', vstart;
hend := ST_XMax(ext);
vend := ST_YMax(ext);
hend := @postgisschema@.ST_XMax(ext);
vend := @postgisschema@.ST_YMax(ext);
IF vstart - (vstep/2.0) < ST_YMin(ext) THEN
IF vstart - (vstep/2.0) < @postgisschema@.ST_YMin(ext) THEN
vstartary := ARRAY[ vstart + (vstep/2.0), vstart ];
ELSE
vstartary := ARRAY[ vstart - (vstep/2.0), vstart ];
END IF;
If maxcells IS NOT NULL AND maxcells > 0 THEN
IF CEIL((CEIL((vend-vstart)/(vstep/2.0)) * CEIL((hend-hstart)/(hstep*2.0/3.0)))/3.0)::integer > maxcells THEN
RAISE EXCEPTION 'The requested grid is too big to be rendered';
END IF;
END IF;
vstartidx := abs(hskip)%2;
RAISE DEBUG 'vstartary: % : %', vstartary[1], vstartary[2];
RAISE DEBUG 'vstartidx: %', vstartidx;
c := ST_SetSRID(ST_MakePoint(hstart, vstartary[vstartidx+1]), srid);
h := ST_SnapToGrid(CDB_MakeHexagon(c, side), xoff, yoff, xgrd, ygrd);
c := @postgisschema@.ST_SetSRID(@postgisschema@.ST_MakePoint(hstart, vstartary[vstartidx+1]), srid);
h := @postgisschema@.ST_SnapToGrid(@extschema@.CDB_MakeHexagon(c, side), xoff, yoff, xgrd, ygrd);
vstartidx := (vstartidx + 1) % 2;
WHILE ST_X(c) < hend LOOP -- over X
WHILE @postgisschema@.ST_X(c) < hend LOOP -- over X
--RAISE DEBUG 'X loop starts, center point: %', ST_AsText(c);
WHILE ST_Y(c) < vend LOOP -- over Y
WHILE @postgisschema@.ST_Y(c) < vend LOOP -- over Y
--RAISE DEBUG 'Center: %', ST_AsText(c);
--h := ST_SnapToGrid(CDB_MakeHexagon(c, side), xoff, yoff, xgrd, ygrd);
RETURN NEXT h;
h := ST_SnapToGrid(ST_Translate(h, 0, vstep), xoff, yoff, xgrd, ygrd);
c := ST_Translate(c, 0, vstep); -- TODO: drop ?
h := @postgisschema@.ST_SnapToGrid(ST_Translate(h, 0, vstep), xoff, yoff, xgrd, ygrd);
c := @postgisschema@.ST_Translate(c, 0, vstep); -- TODO: drop ?
END LOOP;
-- TODO: translate h direcly ...
c := ST_SetSRID(ST_MakePoint(ST_X(c)+hstep, vstartary[vstartidx+1]), srid);
h := ST_SnapToGrid(CDB_MakeHexagon(c, side), xoff, yoff, xgrd, ygrd);
c := @postgisschema@.ST_SetSRID(@postgisschema@.ST_MakePoint(ST_X(c)+hstep, vstartary[vstartidx+1]), srid);
h := @postgisschema@.ST_SnapToGrid(@extschema@.CDB_MakeHexagon(c, side), xoff, yoff, xgrd, ygrd);
vstartidx := (vstartidx + 1) % 2;
END LOOP;
RETURN;
END
$$ LANGUAGE 'plpgsql' IMMUTABLE;
$$ LANGUAGE 'plpgsql' IMMUTABLE PARALLEL SAFE;

View File

@@ -10,212 +10,337 @@
--
-- @param invert Optional wheter to return the top of each bin (default)
-- or the bottom. BOOLEAN, default=FALSE.
--
--
--
CREATE OR REPLACE FUNCTION @extschema@.CDB_JenksBins(in_array NUMERIC[], breaks INT, iterations INT DEFAULT 0, invert BOOLEAN DEFAULT FALSE)
RETURNS NUMERIC[] as
$$
DECLARE
in_matrix NUMERIC[][];
in_unique_count BIGINT;
CREATE OR REPLACE FUNCTION CDB_JenksBins ( in_array NUMERIC[], breaks INT, iterations INT DEFAULT 5, invert BOOLEAN DEFAULT FALSE) RETURNS NUMERIC[] as $$
DECLARE
element_count INT4;
shuffles INT;
arr_mean NUMERIC;
sdam NUMERIC;
i INT;
bot INT;
top INT;
tops INT[];
classes INT[][];
i INT := 1; j INT := 1;
j INT := 1;
curr_result NUMERIC[];
best_result NUMERIC[];
seedtarget TEXT;
quant NUMERIC[];
shuffles INT;
BEGIN
-- get the total size of our row
element_count := array_length(in_array, 1); --array_upper(in_array, 1) - array_lower(in_array, 1);
-- ensure the ordering of in_array
SELECT array_agg(e) INTO in_array FROM (SELECT unnest(in_array) e ORDER BY e) x;
-- stop if no rows
IF element_count IS NULL THEN
RETURN NULL;
END IF;
-- stop if our breaks are more than our input array size
IF element_count < breaks THEN
RETURN in_array;
END IF;
-- We clean the input array (remove NULLs) and create 2 arrays
-- [1] contains the unique values in in_array
-- [2] contains the number of appearances of those unique values
SELECT ARRAY[array_agg(value), array_agg(count)] FROM
(
SELECT value, count(1)::numeric as count
FROM unnest(in_array) AS value
WHERE value is NOT NULL
GROUP BY value
ORDER BY value
) __clean_array_q INTO in_matrix;
shuffles := LEAST(GREATEST(floor(2500000.0/(element_count::float*iterations::float)), 1), 750)::int;
-- get our mean value
SELECT avg(v) INTO arr_mean FROM ( SELECT unnest(in_array) as v ) x;
-- Get the number of unique values
in_unique_count := array_length(in_matrix[1:1], 2);
-- assume best is actually Quantile
SELECT CDB_QuantileBins(in_array, breaks) INTO quant;
-- if data is very very large, just return quant and be done
IF element_count > 5000000 THEN
RETURN quant;
IF in_unique_count IS NULL THEN
RETURN NULL;
END IF;
-- change quant into bottom, top markers
LOOP
IF i = 1 THEN
bot = 1;
ELSE
-- use last top to find this bot
bot = top+1;
END IF;
IF i = breaks THEN
top = element_count;
IF in_unique_count <= breaks THEN
-- There isn't enough distinct values for the requested breaks
RETURN ARRAY(Select unnest(in_matrix[1:1])) _a;
END IF;
-- If not declated explicitly we iterate based on the length of the array
IF iterations < 1 THEN
-- This is based on a 'looks fine' heuristic
iterations := log(in_unique_count)::integer + 1;
END IF;
-- We set the number of shuffles per iteration as the number of unique values but
-- this is just another 'looks fine' heuristic
shuffles := in_unique_count;
-- Get the mean value of the whole vector (already ignores NULLs)
SELECT avg(v) INTO arr_mean FROM ( SELECT unnest(in_array) as v ) x;
-- Calculate the sum of squared deviations from the array mean (SDAM).
SELECT sum(((arr_mean - v)^2) * w) INTO sdam FROM (
SELECT unnest(in_matrix[1:1]) as v, unnest(in_matrix[2:2]) as w
) x;
-- To start, we create ranges with approximately the same amount of different values
top := 0;
i := 1;
LOOP
bot := top + 1;
top := ROUND(i * in_unique_count::numeric / breaks::NUMERIC);
IF i = 1 THEN
classes = ARRAY[ARRAY[bot,top]];
ELSE
SELECT count(*) INTO top FROM ( SELECT unnest(in_array) as v) x WHERE v <= quant[i];
END IF;
IF i = 1 THEN
classes = ARRAY[ARRAY[bot,top]];
ELSE
classes = ARRAY_CAT(classes,ARRAY[bot,top]);
classes = ARRAY_CAT(classes, ARRAY[bot,top]);
END IF;
i := i + 1;
IF i > breaks THEN EXIT; END IF;
i = i+1;
END LOOP;
best_result = CDB_JenksBinsIteration( in_array, breaks, classes, invert, element_count, arr_mean, shuffles);
best_result = @extschema@.CDB_JenksBinsIteration(in_matrix, breaks, classes, invert, sdam, shuffles);
--set the seed so we can ensure the same results
SELECT setseed(0.4567) INTO seedtarget;
--loop through random starting positions
LOOP
IF j > iterations-1 THEN EXIT; END IF;
IF j > iterations-1 THEN EXIT; END IF;
i = 1;
tops = ARRAY[element_count];
tops = ARRAY[in_unique_count];
LOOP
IF i = breaks THEN EXIT; END IF;
SELECT array_agg(distinct e) INTO tops FROM (SELECT unnest(array_cat(tops, ARRAY[floor(random()*element_count::float)::int])) as e ORDER BY e) x WHERE e != 1;
i = array_length(tops, 1);
END LOOP;
IF i = breaks THEN EXIT; END IF;
SELECT array_agg(distinct e) INTO tops FROM (
SELECT unnest(array_cat(tops, ARRAY[trunc(random() * in_unique_count::float8)::int + 1])) as e ORDER BY e
) x;
i = array_length(tops, 1);
END LOOP;
top := 0;
i = 1;
LOOP
IF i > breaks THEN EXIT; END IF;
IF i = 1 THEN
bot = 1;
ELSE
bot = top+1;
END IF;
LOOP
bot := top + 1;
top = tops[i];
IF i = 1 THEN
classes = ARRAY[ARRAY[bot,top]];
ELSE
classes = ARRAY_CAT(classes,ARRAY[bot,top]);
IF i = 1 THEN
classes = ARRAY[ARRAY[bot,top]];
ELSE
classes = ARRAY_CAT(classes, ARRAY[bot,top]);
END IF;
i := i+1;
END LOOP;
curr_result = CDB_JenksBinsIteration( in_array, breaks, classes, invert, element_count, arr_mean, shuffles);
i := i+1;
IF i > breaks THEN EXIT; END IF;
END LOOP;
curr_result = @extschema@.CDB_JenksBinsIteration(in_matrix, breaks, classes, invert, sdam, shuffles);
IF curr_result[1] > best_result[1] THEN
best_result = curr_result;
j = j-1; -- if we found a better result, add one more search
END IF;
j = j+1;
END LOOP;
RETURN (best_result)[2:array_upper(best_result, 1)];
END;
$$ language plpgsql IMMUTABLE;
$$ LANGUAGE PLPGSQL IMMUTABLE PARALLEL RESTRICTED;
--
-- Perform a single iteration of the Jenks classification
--
-- Returns an array with:
-- - First element: gvf
-- - Second to 2+n: Category limits
DROP FUNCTION IF EXISTS @extschema@.CDB_JenksBinsIteration ( in_matrix NUMERIC[], breaks INT, classes INT[], invert BOOLEAN, element_count INT4, arr_mean NUMERIC, max_search INT); -- Old signature
CREATE OR REPLACE FUNCTION @extschema@.CDB_JenksBinsIteration ( in_matrix NUMERIC[], breaks INT, classes INT[], invert BOOLEAN, sdam NUMERIC, max_search INT DEFAULT 50) RETURNS NUMERIC[] as $$
DECLARE
i INT;
iterations INT = 0;
CREATE OR REPLACE FUNCTION CDB_JenksBinsIteration ( in_array NUMERIC[], breaks INT, classes INT[][], invert BOOLEAN, element_count INT4, arr_mean NUMERIC, max_search INT DEFAULT 50) RETURNS NUMERIC[] as $$
DECLARE
tmp_val numeric;
new_classes int[][];
tmp_class int[];
i INT := 1;
j INT := 1;
side INT := 2;
sdam numeric;
gvf numeric := 0.0;
new_gvf numeric;
arr_gvf numeric[];
class_avg numeric;
class_max_i INT;
class_min_i INT;
class_max numeric;
class_min numeric;
reply numeric[];
BEGIN
-- Calculate the sum of squared deviations from the array mean (SDAM).
SELECT sum((arr_mean - e)^2) INTO sdam FROM ( SELECT unnest(in_array) as e ) x;
--Identify the breaks for the lowest GVF
LOOP
i = 1;
LOOP
-- get our mean
SELECT avg(e) INTO class_avg FROM ( SELECT unnest(in_array[classes[i][1]:classes[i][2]]) as e) x;
-- find the deviation
SELECT sum((class_avg-e)^2) INTO tmp_val FROM ( SELECT unnest(in_array[classes[i][1]:classes[i][2]]) as e ) x;
IF i = 1 THEN
arr_gvf = ARRAY[tmp_val];
-- init our min/max map for later
class_max = arr_gvf[i];
class_min = arr_gvf[i];
class_min_i = 1;
class_max_i = 1;
ELSE
arr_gvf = array_append(arr_gvf, tmp_val);
END IF;
i := i+1;
IF i > breaks THEN EXIT; END IF;
END LOOP;
-- calculate our new GVF
SELECT sdam-sum(e) INTO new_gvf FROM ( SELECT unnest(arr_gvf) as e ) x;
-- if no improvement was made, exit
IF new_gvf < gvf THEN EXIT; END IF;
gvf = new_gvf;
IF j > max_search THEN EXIT; END IF;
j = j+1;
i = 1;
LOOP
--establish directionality (uppward through classes or downward)
IF arr_gvf[i] < class_min THEN
class_min = arr_gvf[i];
class_min_i = i;
END IF;
IF arr_gvf[i] > class_max THEN
class_max = arr_gvf[i];
class_max_i = i;
END IF;
i := i+1;
IF i > breaks THEN EXIT; END IF;
END LOOP;
IF class_max_i > class_min_i THEN
class_min_i = class_max_i - 1;
gvf numeric := 0.0;
new_gvf numeric;
arr_gvf numeric[];
arr_avg numeric[];
class_avg numeric;
class_dev numeric;
class_max_i INT = 0;
class_min_i INT = 0;
dev_max numeric;
dev_min numeric;
best_classes INT[] = classes;
best_gvf numeric[];
best_avg numeric[];
move_elements INT = 1;
reply numeric[];
BEGIN
-- We fill the arrays with the initial values
i = 0;
LOOP
IF i = breaks THEN EXIT; END IF;
i = i + 1;
-- Get class mean
SELECT (sum(v * w) / sum(w)) INTO class_avg FROM (
SELECT unnest(in_matrix[1:1][classes[i][1]:classes[i][2]]) as v,
unnest(in_matrix[2:2][classes[i][1]:classes[i][2]]) as w
) x;
-- Get class deviation
SELECT sum((class_avg - v)^2 * w) INTO class_dev FROM (
SELECT unnest(in_matrix[1:1][classes[i][1]:classes[i][2]]) as v,
unnest(in_matrix[2:2][classes[i][1]:classes[i][2]]) as w
) x;
IF i = 1 THEN
arr_avg = ARRAY[class_avg];
arr_gvf = ARRAY[class_dev];
ELSE
class_min_i = class_max_i + 1;
arr_avg = array_append(arr_avg, class_avg);
arr_gvf = array_append(arr_gvf, class_dev);
END IF;
--Move from higher class to a lower gid order
IF class_max_i > class_min_i THEN
classes[class_max_i][1] = classes[class_max_i][1] + 1;
classes[class_min_i][2] = classes[class_min_i][2] + 1;
ELSE -- Move from lower class UP into a higher class by gid
classes[class_max_i][2] = classes[class_max_i][2] - 1;
classes[class_min_i][1] = classes[class_min_i][1] - 1;
END LOOP;
-- We copy the values to avoid recalculation when a failure happens
best_avg = arr_avg;
best_gvf = arr_gvf;
iterations = 0;
LOOP
IF iterations = max_search THEN EXIT; END IF;
iterations = iterations + 1;
-- calculate our new GVF
SELECT sdam - sum(e) INTO new_gvf FROM ( SELECT unnest(arr_gvf) as e ) x;
-- Check if any improvement was made
IF new_gvf <= gvf THEN
-- If we were moving too many elements, go back and move less
IF move_elements <= 2 OR class_max_i = class_min_i THEN
EXIT;
END IF;
END LOOP;
move_elements = GREATEST(move_elements / 8, 1);
-- Rollback from saved statuses
classes = best_classes;
new_gvf = gvf;
i = class_min_i;
LOOP
arr_avg[i] = best_avg[i];
arr_gvf[i] = best_gvf[i];
IF i = class_max_i THEN EXIT; END IF;
i = i + 1;
END LOOP;
END IF;
-- We search for the classes with the min and max deviation
i = 1;
class_min_i = 1;
class_max_i = 1;
dev_max = arr_gvf[1];
dev_min = arr_gvf[1];
LOOP
IF i = breaks THEN EXIT; END IF;
i = i + 1;
IF arr_gvf[i] < dev_min THEN
dev_min = arr_gvf[i];
class_min_i = i;
ELSE
IF arr_gvf[i] > dev_max THEN
dev_max = arr_gvf[i];
class_max_i = i;
END IF;
END IF;
END LOOP;
-- Save best values for comparison and output
gvf = new_gvf;
best_classes = classes;
-- Limit the moved elements as to not remove everything from class_max_i
move_elements = LEAST(move_elements, classes[class_max_i][2] - classes[class_max_i][1]);
-- Move `move_elements` from class_max_i to class_min_i
IF class_min_i < class_max_i THEN
i := class_min_i;
LOOP
IF i = class_max_i THEN EXIT; END IF;
classes[i][2] = classes[i][2] + move_elements;
i := i + 1;
END LOOP;
i := class_max_i;
LOOP
IF i = class_min_i THEN EXIT; END IF;
classes[i][1] = classes[i][1] + move_elements;
i := i - 1;
END LOOP;
ELSE
i := class_min_i;
LOOP
IF i = class_max_i THEN EXIT; END IF;
classes[i][1] = classes[i][1] - move_elements;
i := i - 1;
END LOOP;
i := class_max_i;
LOOP
IF i = class_min_i THEN EXIT; END IF;
classes[i][2] = classes[i][2] - move_elements;
i := i + 1;
END LOOP;
END IF;
-- Recalculate avg and deviation ONLY for the affected classes
i = LEAST(class_min_i, class_max_i);
class_max_i = GREATEST(class_min_i, class_max_i);
class_min_i = i;
LOOP
SELECT (sum(v * w) / sum(w)) INTO class_avg FROM (
SELECT unnest(in_matrix[1:1][classes[i][1]:classes[i][2]]) as v,
unnest(in_matrix[2:2][classes[i][1]:classes[i][2]]) as w
) x;
SELECT sum((class_avg - v)^2 * w) INTO class_dev FROM (
SELECT unnest(in_matrix[1:1][classes[i][1]:classes[i][2]]) as v,
unnest(in_matrix[2:2][classes[i][1]:classes[i][2]]) as w
) x;
-- Save status (in case it's needed for rollback) and store the new one
best_avg[i] = arr_avg[i];
arr_avg[i] = class_avg;
best_gvf[i] = arr_gvf[i];
arr_gvf[i] = class_dev;
IF i = class_max_i THEN EXIT; END IF;
i = i + 1;
END LOOP;
move_elements = move_elements * 2;
END LOOP;
i = 1;
LOOP
LOOP
IF invert = TRUE THEN
side = 1; --default returns bottom side of breaks, invert returns top side
END IF;
reply = array_append(reply, in_array[classes[i][side]]);
i = i+1;
IF i > breaks THEN EXIT; END IF;
END LOOP;
RETURN array_prepend(gvf, reply);
reply = array_append(reply, unnest(in_matrix[1:1][best_classes[i][side]:best_classes[i][side]]));
i = i+1;
IF i > breaks THEN EXIT; END IF;
END LOOP;
END;
$$ language plpgsql IMMUTABLE;
reply = array_prepend(gvf, reply);
RETURN reply;
END;
$$ LANGUAGE PLPGSQL IMMUTABLE PARALLEL SAFE;

View File

@@ -7,17 +7,11 @@
--
--
CREATE OR REPLACE FUNCTION CDB_LatLng (lat NUMERIC, lng NUMERIC) RETURNS geometry as $$
BEGIN
-- this function is silly
RETURN ST_SetSRID(ST_MakePoint(lng,lat),4326);
END;
$$ language plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION @extschema@.CDB_LatLng (lat NUMERIC, lng NUMERIC) RETURNS @postgisschema@.geometry as $$
SELECT @postgisschema@.ST_SetSRID(@postgisschema@.ST_MakePoint(lng,lat), 4326);
$$ language SQL IMMUTABLE PARALLEL SAFE;
CREATE OR REPLACE FUNCTION CDB_LatLng (lat FLOAT8, lng FLOAT8) RETURNS geometry as $$
BEGIN
-- this function is silly
RETURN ST_SetSRID(ST_MakePoint(lng,lat),4326);
END;
$$ language plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION @extschema@.CDB_LatLng (lat FLOAT8, lng FLOAT8) RETURNS @postgisschema@.geometry as $$
SELECT @postgisschema@.ST_SetSRID(@postgisschema@.ST_MakePoint(lng,lat), 4326);
$$ language SQL IMMUTABLE PARALLEL SAFE;

View File

@@ -4,7 +4,7 @@
-- Mode
-- https://wiki.postgresql.org/wiki/Aggregate_Mode
CREATE OR REPLACE FUNCTION cartodb._CDB_Math_final_mode(anyarray)
CREATE OR REPLACE FUNCTION @extschema@._CDB_Math_final_mode(anyarray)
RETURNS anyelement AS
$BODY$
SELECT a
@@ -13,14 +13,15 @@ $BODY$
ORDER BY COUNT(1) DESC, 1
LIMIT 1;
$BODY$
LANGUAGE 'sql' IMMUTABLE;
LANGUAGE 'sql' IMMUTABLE PARALLEL SAFE;
DROP AGGREGATE IF EXISTS cartodb.CDB_Math_Mode(anyelement);
DROP AGGREGATE IF EXISTS @extschema@.CDB_Math_Mode(anyelement);
CREATE AGGREGATE cartodb.CDB_Math_Mode(anyelement) (
CREATE AGGREGATE @extschema@.CDB_Math_Mode(anyelement) (
SFUNC=array_append,
STYPE=anyarray,
FINALFUNC=_CDB_Math_final_mode,
FINALFUNC=@extschema@._CDB_Math_final_mode,
PARALLEL = SAFE,
INITCOND='{}'
);

View File

@@ -0,0 +1,65 @@
-- Function that reassign the owner of a table to their ownership_role
CREATE OR REPLACE FUNCTION @extschema@.CDB_OAuthReassignTableOwnerOnCreation()
RETURNS event_trigger
AS $$
DECLARE
obj record;
owner_role text;
creator_role text;
BEGIN
FOR obj IN SELECT * FROM pg_event_trigger_ddl_commands()
LOOP
RAISE DEBUG '% ddl object: % % % %',
tg_tag,
obj.command_tag,
obj.object_type,
obj.schema_name,
obj.object_identity;
IF obj.object_type = 'function' THEN
SELECT rolname FROM pg_proc JOIN pg_roles ON proowner = pg_roles.oid WHERE pg_proc.oid = obj.objid INTO creator_role;
ELSE
SELECT rolname FROM pg_class JOIN pg_roles ON relowner = pg_roles.oid WHERE pg_class.oid = obj.objid INTO creator_role;
END IF;
SELECT value->>'ownership_role_name' from @extschema@.CDB_Conf_GetConf('api_keys_' || quote_ident(creator_role)) value INTO owner_role;
IF owner_role IS NULL OR owner_role = '' THEN
RAISE DEBUG 'owner_role not found';
CONTINUE;
ELSE
EXECUTE 'ALTER ' || obj.object_type || ' ' || obj.object_identity || ' OWNER TO ' || quote_ident(owner_role);
IF obj.object_type = 'function' THEN
EXECUTE 'GRANT ALL ON FUNCTION ' || obj.object_identity || ' TO ' || QUOTE_IDENT(creator_role);
ELSE
EXECUTE 'GRANT ALL ON ' || obj.object_identity || ' TO ' || QUOTE_IDENT(creator_role);
END IF;
RAISE DEBUG 'Changing ownership from % to %', creator_role, owner_role;
END IF;
END LOOP;
END;
$$ LANGUAGE plpgsql
VOLATILE
PARALLEL UNSAFE
SECURITY DEFINER
SET search_path = pg_temp;
-- Creates the trigger on DDL events in order to reassign the owner
CREATE OR REPLACE FUNCTION @extschema@.CDB_EnableOAuthReassignTablesTrigger()
RETURNS void
AS $$
BEGIN
DROP EVENT TRIGGER IF EXISTS oauth_reassign_tables_trigger;
CREATE EVENT TRIGGER oauth_reassign_tables_trigger
ON ddl_command_end
WHEN TAG IN ('CREATE TABLE', 'CREATE TABLE AS', 'SELECT INTO', 'CREATE VIEW', 'CREATE FOREIGN TABLE', 'CREATE MATERIALIZED VIEW', 'CREATE SEQUENCE', 'CREATE FUNCTION')
EXECUTE PROCEDURE @extschema@.CDB_OAuthReassignTableOwnerOnCreation();
END;
$$ LANGUAGE plpgsql VOLATILE PARALLEL UNSAFE;
-- Deletes the trigger on DDL events in order to reassign the owner
CREATE OR REPLACE FUNCTION @extschema@.CDB_DisableOAuthReassignTablesTrigger()
RETURNS void
AS $$
BEGIN
DROP EVENT TRIGGER IF EXISTS oauth_reassign_tables_trigger;
END;
$$ LANGUAGE plpgsql VOLATILE PARALLEL UNSAFE;

View File

@@ -1,14 +1,23 @@
CREATE OR REPLACE
FUNCTION cartodb.CDB_Organization_Member_Group_Role_Member_Name()
FUNCTION @extschema@.CDB_Organization_Member_Group_Role_Member_Name()
RETURNS TEXT
AS 'SELECT ''cdb_org_member''::text || ''_'' || md5(current_database());'
LANGUAGE SQL IMMUTABLE;
AS $$
SELECT 'cdb_org_member'::text || '_' || md5(current_database());
$$
LANGUAGE SQL STABLE PARALLEL SAFE;
----- ########################## WARNING ##########################
----- The code below creates a new role for the organization but
----- only when the extension is INSTALLED in a database, i.e. it
----- won't work if you clone a database that has it installed.
----- If you do, you need to update the extension to next and back
----- ########################## WARNING ##########################
DO LANGUAGE 'plpgsql' $$
DECLARE
cdb_org_member_role_name TEXT;
BEGIN
cdb_org_member_role_name := cartodb.CDB_Organization_Member_Group_Role_Member_Name();
cdb_org_member_role_name := @extschema@.CDB_Organization_Member_Group_Role_Member_Name();
IF NOT EXISTS ( SELECT * FROM pg_roles WHERE rolname= cdb_org_member_role_name )
THEN
EXECUTE 'CREATE ROLE "' || cdb_org_member_role_name || '" NOLOGIN;';
@@ -17,59 +26,144 @@ END
$$;
CREATE OR REPLACE
FUNCTION cartodb.CDB_Organization_Create_Member(role_name text)
FUNCTION @extschema@.CDB_Organization_Create_Member(role_name text)
RETURNS void
AS $$
BEGIN
EXECUTE 'GRANT "' || cartodb.CDB_Organization_Member_Group_Role_Member_Name() || '" TO "' || role_name || '"';
EXECUTE 'GRANT "' || @extschema@.CDB_Organization_Member_Group_Role_Member_Name() || '" TO "' || role_name || '"';
END
$$ LANGUAGE PLPGSQL VOLATILE;
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
-------------------------------------------------------------------------------
-- Administrator
-------------------------------------------------------------------------------
CREATE OR REPLACE
FUNCTION @extschema@._CDB_Organization_Admin_Role_Name()
RETURNS TEXT
AS $$
SELECT current_database() || '_a'::text;
$$
LANGUAGE SQL STABLE PARALLEL SAFE;
----- ########################## WARNING ##########################
----- The code below creates a new role for the organization but
----- only when the extension is INSTALLED in a database, i.e. it
----- won't work if you clone a database that has it installed.
----- If you do, you need to update the extension to next and back
----- ########################## WARNING ##########################
-- Administrator role creation on extension install
DO LANGUAGE 'plpgsql' $$
DECLARE
cdb_org_admin_role_name TEXT;
BEGIN
cdb_org_admin_role_name := @extschema@._CDB_Organization_Admin_Role_Name();
IF NOT EXISTS ( SELECT * FROM pg_roles WHERE rolname= cdb_org_admin_role_name )
THEN
EXECUTE format('CREATE ROLE %I CREATEROLE NOLOGIN;', cdb_org_admin_role_name);
END IF;
END
$$;
CREATE OR REPLACE
FUNCTION @extschema@.CDB_Organization_AddAdmin(username text)
RETURNS void
AS $$
DECLARE
cdb_user_role TEXT;
cdb_admin_role TEXT;
BEGIN
cdb_admin_role := @extschema@._CDB_Organization_Admin_Role_Name();
cdb_user_role := @extschema@._CDB_User_RoleFromUsername(username);
EXECUTE format('GRANT %I TO %I WITH ADMIN OPTION', cdb_admin_role, cdb_user_role);
-- CREATEROLE is not inherited, and is needed for user creation
EXECUTE format('ALTER ROLE %I CREATEROLE', cdb_user_role);
END
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
CREATE OR REPLACE
FUNCTION @extschema@.CDB_Organization_RemoveAdmin(username text)
RETURNS void
AS $$
DECLARE
cdb_user_role TEXT;
cdb_admin_role TEXT;
BEGIN
cdb_admin_role := @extschema@._CDB_Organization_Admin_Role_Name();
cdb_user_role := @extschema@._CDB_User_RoleFromUsername(username);
EXECUTE format('ALTER ROLE %I NOCREATEROLE', cdb_user_role);
EXECUTE format('REVOKE %I FROM %I', cdb_admin_role, cdb_user_role);
END
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
-------------------------------------------------------------------------------
-- Sharing tables
-------------------------------------------------------------------------------
CREATE OR REPLACE
FUNCTION cartodb.CDB_Organization_Add_Table_Read_Permission(from_schema text, table_name text, to_role_name text)
FUNCTION @extschema@.CDB_Organization_Add_Table_Read_Permission(from_schema text, table_name text, to_role_name text)
RETURNS void
AS $$
BEGIN
EXECUTE 'GRANT USAGE ON SCHEMA "' || from_schema || '" TO "' || to_role_name || '"';
EXECUTE 'GRANT SELECT ON "' || from_schema || '"."' || table_name || '" TO "' || to_role_name || '"';
END
$$ LANGUAGE PLPGSQL VOLATILE;
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
CREATE OR REPLACE
FUNCTION cartodb.CDB_Organization_Add_Table_Organization_Read_Permission(from_schema text, table_name text)
FUNCTION @extschema@.CDB_Organization_Add_Table_Organization_Read_Permission(from_schema text, table_name text)
RETURNS void
AS $$
BEGIN
EXECUTE 'SELECT cartodb.CDB_Organization_Add_Table_Read_Permission(''' || from_schema || ''', ''' || table_name || ''', ''' || cartodb.CDB_Organization_Member_Group_Role_Member_Name() || ''');';
EXECUTE 'SELECT @extschema@.CDB_Organization_Add_Table_Read_Permission(''' || from_schema || ''', ''' || table_name || ''', ''' || @extschema@.CDB_Organization_Member_Group_Role_Member_Name() || ''');';
END
$$ LANGUAGE PLPGSQL VOLATILE;
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
CREATE OR REPLACE
FUNCTION cartodb.CDB_Organization_Add_Table_Read_Write_Permission(from_schema text, table_name text, to_role_name text)
FUNCTION @extschema@._CDB_Organization_Get_Table_Sequences(from_schema text, table_name text)
RETURNS SETOF TEXT
AS $$
BEGIN
RETURN QUERY EXECUTE 'SELECT
quote_ident(n.nspname) || ''.'' || quote_ident(c.relname)
FROM
pg_depend d
JOIN pg_class c ON d.objid = c.oid
JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE
d.refobjsubid > 0 AND
d.classid = ''pg_class''::regclass AND
c.relkind = ''S''::"char" AND
d.refobjid = (''' || quote_ident(from_schema) || '.' || quote_ident(table_name) ||''')::regclass';
END
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
CREATE OR REPLACE
FUNCTION @extschema@.CDB_Organization_Add_Table_Read_Write_Permission(from_schema text, table_name text, to_role_name text)
RETURNS void
AS $$
DECLARE
sequence_name TEXT;
BEGIN
EXECUTE 'GRANT USAGE ON SCHEMA "' || from_schema || '" TO "' || to_role_name || '"';
EXECUTE 'GRANT SELECT, INSERT, UPDATE, DELETE ON "' || from_schema || '"."' || table_name || '" TO "' || to_role_name || '"';
FOR sequence_name IN SELECT * FROM @extschema@._CDB_Organization_Get_Table_Sequences(from_schema, table_name) LOOP
EXECUTE 'GRANT USAGE, SELECT ON SEQUENCE ' || sequence_name || ' TO "' || to_role_name || '"';
END LOOP;
END
$$ LANGUAGE PLPGSQL VOLATILE;
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
CREATE OR REPLACE
FUNCTION cartodb.CDB_Organization_Add_Table_Organization_Read_Write_Permission(from_schema text, table_name text)
FUNCTION @extschema@.CDB_Organization_Add_Table_Organization_Read_Write_Permission(from_schema text, table_name text)
RETURNS void
AS $$
BEGIN
EXECUTE 'SELECT cartodb.CDB_Organization_Add_Table_Read_Write_Permission(''' || from_schema || ''', ''' || table_name || ''', ''' || cartodb.CDB_Organization_Member_Group_Role_Member_Name() || ''');';
EXECUTE 'SELECT @extschema@.CDB_Organization_Add_Table_Read_Write_Permission(''' || from_schema || ''', ''' || table_name || ''', ''' || @extschema@.CDB_Organization_Member_Group_Role_Member_Name() || ''');';
END
$$ LANGUAGE PLPGSQL VOLATILE;
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
CREATE OR REPLACE
FUNCTION cartodb.CDB_Organization_Remove_Access_Permission(from_schema text, table_name text, to_role_name text)
FUNCTION @extschema@.CDB_Organization_Remove_Access_Permission(from_schema text, table_name text, to_role_name text)
RETURNS void
AS $$
BEGIN
@@ -78,13 +172,20 @@ BEGIN
-- We need to revoke usage on schema only if we are revoking privileges from the last table where to_role_name has
-- any permission granted within the schema from_schema
END
$$ LANGUAGE PLPGSQL VOLATILE;
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
CREATE OR REPLACE
FUNCTION cartodb.CDB_Organization_Remove_Organization_Access_Permission(from_schema text, table_name text)
FUNCTION @extschema@.CDB_Organization_Remove_Organization_Access_Permission(from_schema text, table_name text)
RETURNS void
AS $$
BEGIN
EXECUTE 'SELECT cartodb.CDB_Organization_Remove_Access_Permission(''' || from_schema || ''', ''' || table_name || ''', ''' || cartodb.CDB_Organization_Member_Group_Role_Member_Name() || ''');';
EXECUTE 'SELECT @extschema@.CDB_Organization_Remove_Access_Permission(''' || from_schema || ''', ''' || table_name || ''', ''' || @extschema@.CDB_Organization_Member_Group_Role_Member_Name() || ''');';
END
$$ LANGUAGE PLPGSQL VOLATILE;
$$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
--------------------------------------------------------------------------------
-- Deprecated
--------------------------------------------------------------------------------
DROP FUNCTION IF EXISTS @extschema@.CDB_Organization_Grant_Role(name);
DROP FUNCTION IF EXISTS @extschema@.CDB_Organization_Revoke_Role(name);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,173 @@
-- Auxiliary overviews FUNCTIONS
-- Maximum zoom level for which overviews may be created
CREATE OR REPLACE FUNCTION @extschema@._CDB_MaxOverviewLevel()
RETURNS INTEGER
AS $$
BEGIN
-- Zoom level will be limited so that both tile coordinates
-- and gridding coordinates within a tile up to 1px
-- (i.e. tile coordinates / 256)
-- can be stored in a 32-bit signed integer.
-- We have 31 bits por positive numbers
-- For zoom level Z coordinates range from 0 to 2^Z-1, so they
-- need Z bits, and need 8 bits more to address pixels within a tile
-- (gridding), so we'll limit Z to a maximum of 31 - 8
RETURN 23;
END;
$$ LANGUAGE PLPGSQL IMMUTABLE PARALLEL SAFE;
-- Maximum zoom level usable with integer coordinates
CREATE OR REPLACE FUNCTION @extschema@._CDB_MaxZoomLevel()
RETURNS INTEGER
AS $$
BEGIN
RETURN 31;
END;
$$ LANGUAGE PLPGSQL IMMUTABLE PARALLEL SAFE;
-- Information about tables in a schema.
-- If the schema name parameter is NULL, then tables from all schemas
-- that may contain user tables are returned.
-- For each table, the regclass, schema name and table name are returned.
-- Scope: private.
CREATE OR REPLACE FUNCTION @extschema@._CDB_UserTablesInSchema(schema_name text DEFAULT NULL)
RETURNS TABLE(table_regclass REGCLASS, schema_name TEXT, table_name TEXT)
AS $$
SELECT
c.oid::regclass AS table_regclass,
n.nspname::text AS schema_name,
c.relname::text AS table_relname
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = 'r'
AND c.relname NOT IN ('cdb_tablemetadata', 'cdb_analysis_catalog', 'cdb_conf', 'spatial_ref_sys')
AND CASE WHEN schema_name IS NULL
THEN n.nspname NOT IN ('pg_catalog', 'information_schema', 'topology', '@extschema@')
ELSE n.nspname = schema_name
END;
$$ LANGUAGE 'sql' STABLE PARALLEL SAFE;
-- Pattern that can be used to detect overview tables and Extract
-- the intended zoom level from the table name.
-- Scope: private.
CREATE OR REPLACE FUNCTION @extschema@._CDB_OverviewTableDiscriminator()
RETURNS TEXT
AS $$
BEGIN
RETURN '\A_vovw_(\d+)_';
END;
$$ LANGUAGE PLPGSQL IMMUTABLE PARALLEL SAFE;
-- substring(tablename from _CDB_OverviewTableDiscriminator())
-- Pattern matched by the overview tables of a given base table name.
-- Scope: private.
CREATE OR REPLACE FUNCTION @extschema@._CDB_OverviewTablePattern(base_table TEXT)
RETURNS TEXT
AS $$
BEGIN
RETURN @extschema@._CDB_OverviewTableDiscriminator() || base_table;
END;
$$ LANGUAGE PLPGSQL IMMUTABLE PARALLEL SAFE;
-- tablename SIMILAR TO _CDB_OverviewTablePattern(base_table)
-- Name of an overview table, given the base table name and the Z level
-- Scope: private.
CREATE OR REPLACE FUNCTION @extschema@._CDB_OverviewTableName(base_table TEXT, z INTEGER)
RETURNS TEXT
AS $$
BEGIN
RETURN '_vovw_' || z::text || '_' || base_table;
END;
$$ LANGUAGE PLPGSQL IMMUTABLE PARALLEL SAFE;
-- Condition to check if a tabla is an overview table of some base table
-- Scope: private.
CREATE OR REPLACE FUNCTION @extschema@._CDB_IsOverviewTableOf(base_table TEXT, otable TEXT)
RETURNS BOOLEAN
AS $$
BEGIN
RETURN otable SIMILAR TO @extschema@._CDB_OverviewTablePattern(base_table);
END;
$$ LANGUAGE PLPGSQL IMMUTABLE PARALLEL SAFE;
-- Extract the Z level from an overview table name
-- Scope: private.
CREATE OR REPLACE FUNCTION @extschema@._CDB_OverviewTableZ(otable TEXT)
RETURNS INTEGER
AS $$
BEGIN
RETURN substring(otable from @extschema@._CDB_OverviewTableDiscriminator())::integer;
END;
$$ LANGUAGE PLPGSQL IMMUTABLE PARALLEL SAFE;
-- Name of the base table corresponding to an overview table
-- Scope: private.
CREATE OR REPLACE FUNCTION @extschema@._CDB_OverviewBaseTableName(overview_table TEXT)
RETURNS TEXT
AS $$
BEGIN
IF @extschema@._CDB_OverviewTableZ(overview_table) IS NULL THEN
RETURN overview_table;
ELSE
RETURN regexp_replace(overview_table, @extschema@._CDB_OverviewTableDiscriminator(), '');
END IF;
END;
$$ LANGUAGE PLPGSQL IMMUTABLE PARALLEL SAFE;
CREATE OR REPLACE FUNCTION @extschema@._CDB_OverviewBaseTable(overview_table REGCLASS)
RETURNS REGCLASS
AS $$
DECLARE
table_name TEXT;
schema_name TEXT;
base_name TEXT;
base_table REGCLASS;
BEGIN
SELECT * FROM @extschema@._cdb_split_table_name(overview_table) INTO schema_name, table_name;
base_name := @extschema@._CDB_OverviewBaseTableName(table_name);
IF base_name != table_name THEN
base_table := Format('%I.%I', schema_name, base_name)::regclass;
ELSE
base_table := overview_table;
END IF;
RETURN base_table;
END;
$$ LANGUAGE PLPGSQL IMMUTABLE PARALLEL SAFE;
-- Schema and relation names of a table given its reloid
-- Scope: private.
-- Parameters
-- reloid: oid of the table.
-- Return (schema_name, table_name)
-- note that returned names will be quoted if necessary
CREATE OR REPLACE FUNCTION @extschema@._cdb_split_table_name(reloid REGCLASS, OUT schema_name TEXT, OUT table_name TEXT)
AS $$
BEGIN
SELECT n.nspname, c.relname
INTO STRICT schema_name, table_name
FROM pg_class c JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE c.oid = reloid;
END
$$ LANGUAGE PLPGSQL IMMUTABLE PARALLEL SAFE;
-- Schema and relation names of a table given its reloid
-- Scope: private.
-- Parameters
-- reloid: oid of the table.
-- Return (schema_name, table_name)
-- note that returned names will be quoted if necessary
CREATE OR REPLACE FUNCTION @extschema@._cdb_schema_name(reloid REGCLASS)
RETURNS TEXT
AS $$
DECLARE
schema_name TEXT;
BEGIN
SELECT n.nspname
INTO STRICT schema_name
FROM pg_class c JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE c.oid = reloid;
RETURN schema_name;
END
$$ LANGUAGE PLPGSQL IMMUTABLE PARALLEL SAFE;

View File

@@ -5,39 +5,14 @@
-- bins based on the Quantile method.
--
-- @param breaks The number of bins you want to find.
--
--
CREATE OR REPLACE FUNCTION CDB_QuantileBins ( in_array NUMERIC[], breaks INT) RETURNS NUMERIC[] as $$
DECLARE
element_count INT4;
break_size numeric;
tmp_val numeric;
i INT := 1;
reply numeric[];
BEGIN
-- sort our values
SELECT array_agg(e) INTO in_array FROM (SELECT unnest(in_array) e ORDER BY e ASC) x;
-- get the total size of our data
element_count := array_length(in_array, 1);
break_size := element_count::numeric / breaks;
-- slice our bread
LOOP
IF i < breaks THEN
IF break_size * i % 1 > 0 THEN
SELECT e INTO tmp_val FROM ( SELECT unnest(in_array) e LIMIT 1 OFFSET ceil(break_size * i) - 1) x;
ELSE
SELECT avg(e) INTO tmp_val FROM ( SELECT unnest(in_array) e LIMIT 2 OFFSET ceil(break_size * i) - 1 ) x;
END IF;
ELSIF i = breaks THEN
-- select the last value
SELECT max(e) INTO tmp_val FROM ( SELECT unnest(in_array) e ) x;
ELSE
EXIT;
END IF;
reply = array_append(reply, tmp_val);
i := i+1;
END LOOP;
RETURN reply;
END;
$$ language plpgsql IMMUTABLE;
--
CREATE OR REPLACE FUNCTION @extschema@.CDB_QuantileBins(in_array numeric[], breaks int)
RETURNS numeric[]
AS $$
SELECT
percentile_disc(Array(SELECT generate_series(1, breaks) / breaks::numeric))
WITHIN GROUP (ORDER BY x ASC) AS p
FROM
unnest(in_array) AS x;
$$ language SQL IMMUTABLE STRICT PARALLEL SAFE;

View File

@@ -3,7 +3,7 @@
-- Regexp curtesy of Hubert Lubaczewski (depesz)
-- Implemented in plpython for performance reasons
--
CREATE OR REPLACE FUNCTION CDB_QueryStatements(query text)
CREATE OR REPLACE FUNCTION @extschema@.CDB_QueryStatements(query text)
RETURNS SETOF TEXT AS $$
import re
pat = re.compile( r'''((?:[^'"$;]+|"[^"]*"|'[^']*'|(\$[^$]*\$).*?\2)+)''', re.DOTALL )
@@ -11,4 +11,4 @@ RETURNS SETOF TEXT AS $$
cleaned = match[0].strip()
if ( cleaned ):
yield cleaned
$$ language 'plpythonu' IMMUTABLE STRICT;
$$ language '@@plpythonu@@' IMMUTABLE STRICT PARALLEL SAFE;

View File

@@ -2,7 +2,7 @@
--
-- Requires PostgreSQL 9.x+
--
CREATE OR REPLACE FUNCTION CDB_QueryTablesText(query text)
CREATE OR REPLACE FUNCTION @extschema@.CDB_QueryTablesText(query text)
RETURNS text[]
AS $$
DECLARE
@@ -11,19 +11,16 @@ DECLARE
rec RECORD;
rec2 RECORD;
BEGIN
tables := '{}';
FOR rec IN SELECT CDB_QueryStatements(query) q LOOP
IF NOT ( rec.q ilike 'select%' or rec.q ilike 'with%' ) THEN
--RAISE WARNING 'Skipping %', rec.q;
CONTINUE;
END IF;
FOR rec IN SELECT @extschema@.CDB_QueryStatements(query) q LOOP
BEGIN
EXECUTE 'EXPLAIN (FORMAT XML, VERBOSE) ' || rec.q INTO STRICT exp;
EXCEPTION WHEN others THEN
EXCEPTION WHEN syntax_error THEN
-- We can get a syntax error if the user tries to EXPLAIN a DDL
CONTINUE;
WHEN others THEN
-- TODO: if error is 'relation "xxxxxx" does not exist', take xxxxxx as
-- the affected table ?
RAISE WARNING 'CDB_QueryTables cannot explain query: % (%: %)', rec.q, SQLSTATE, SQLERRM;
@@ -41,11 +38,11 @@ BEGIN
xpath('//x:Relation-Name/text()', exp, ARRAY[ARRAY['x', 'http://www.postgresql.org/2009/explain']]) as x,
xpath('//x:Relation-Name/../x:Schema/text()', exp, ARRAY[ARRAY['x', 'http://www.postgresql.org/2009/explain']]) as s
)
SELECT unnest(x) as p, unnest(s) as sc from inp
SELECT unnest(x)::text as p, unnest(s)::text as sc from inp
LOOP
-- RAISE DEBUG 'tab: %', rec2.p;
-- RAISE DEBUG 'sc: %', rec2.sc;
tables := array_append(tables, (rec2.sc || '.' || rec2.p));
tables := array_append(tables, format('%s.%s', quote_ident(rec2.sc), quote_ident(rec2.p)));
END LOOP;
-- RAISE DEBUG 'Tables: %', tables;
@@ -64,15 +61,15 @@ BEGIN
return tables;
END
$$ LANGUAGE 'plpgsql' VOLATILE STRICT;
$$ LANGUAGE 'plpgsql' VOLATILE STRICT PARALLEL UNSAFE;
-- Keep CDB_QueryTables with same signature for backwards compatibility.
-- It should probably be removed in the future.
CREATE OR REPLACE FUNCTION CDB_QueryTables(query text)
CREATE OR REPLACE FUNCTION @extschema@.CDB_QueryTables(query text)
RETURNS name[]
AS $$
BEGIN
RETURN CDB_QueryTablesText(query)::name[];
RETURN @extschema@.CDB_QueryTablesText(query)::name[];
END
$$ LANGUAGE 'plpgsql' VOLATILE STRICT;
$$ LANGUAGE 'plpgsql' VOLATILE STRICT PARALLEL UNSAFE;

View File

@@ -1,4 +1,4 @@
CREATE OR REPLACE FUNCTION cartodb._CDB_total_relation_size(_schema_name TEXT, _table_name TEXT)
CREATE OR REPLACE FUNCTION @extschema@._CDB_total_relation_size(_schema_name TEXT, _table_name TEXT)
RETURNS bigint AS
$$
DECLARE relation_size bigint := 0;
@@ -7,47 +7,63 @@ BEGIN
SELECT pg_total_relation_size(format('"%s"."%s"', _schema_name, _table_name)) INTO relation_size;
EXCEPTION
WHEN undefined_table OR OTHERS THEN
RAISE NOTICE 'cartodb._CDB_total_relation_size(''%'', ''%'') caught error: % (%)', _schema_name, _table_name, SQLERRM, SQLSTATE;
RAISE NOTICE '@extschema@._CDB_total_relation_size(''%'', ''%'') caught error: % (%)', _schema_name, _table_name, SQLERRM, SQLSTATE;
END;
RETURN relation_size;
END;
$$
LANGUAGE 'plpgsql' VOLATILE;
LANGUAGE 'plpgsql' VOLATILE PARALLEL UNSAFE;
-- Return the estimated size of user data. Used for quota checking.
CREATE OR REPLACE FUNCTION CDB_UserDataSize(schema_name TEXT)
CREATE OR REPLACE FUNCTION @extschema@.CDB_UserDataSize(schema_name TEXT)
RETURNS bigint AS
$$
DECLARE
total_size INT8;
raster_available BOOLEAN;
raster_read_query TEXT;
BEGIN
-- Postgis 3+ might not install raster
raster_available := EXISTS (
SELECT 1
FROM pg_views
WHERE schemaname = '@postgisschema@'
AND viewname = 'raster_overviews'
);
IF raster_available THEN
raster_read_query := Format('SELECT o_table_name, r_table_name FROM @postgisschema@.raster_overviews
WHERE o_table_schema = %L AND o_table_catalog = current_database()', schema_name);
ELSE
raster_read_query := 'SELECT NULL::text AS o_table_name, NULL::text AS r_table_name';
END IF;
EXECUTE Format('
WITH raster_tables AS (
SELECT o_table_name, r_table_name FROM raster_overviews
WHERE o_table_schema = schema_name AND o_table_catalog = current_database()
%s
),
user_tables AS (
SELECT table_name FROM information_schema.tables
WHERE table_catalog = current_database() AND table_schema = schema_name
AND table_name != 'spatial_ref_sys'
AND table_name != 'cdb_tablemetadata'
AND table_type = 'BASE TABLE'
SELECT table_name FROM @extschema@._CDB_NonAnalysisTablesInSchema(%L)
),
table_cat AS (
SELECT
table_name,
EXISTS(select * from raster_tables where o_table_name = table_name) AS is_overview,
(
EXISTS(select * from raster_tables where o_table_name = table_name)
OR table_name SIMILAR TO @extschema@._CDB_OverviewTableDiscriminator() || ''[\w\d]*''
) AS is_overview,
EXISTS(SELECT * FROM raster_tables WHERE r_table_name = table_name) AS is_raster
FROM user_tables
),
sizes AS (
SELECT COALESCE(INT8(SUM(cartodb._CDB_total_relation_size(schema_name, table_name)))) table_size,
SELECT COALESCE(INT8(SUM(@extschema@._CDB_total_relation_size(%L, table_name)))) table_size,
CASE
WHEN is_overview THEN 0
WHEN is_raster THEN 1
ELSE 0.5 -- Division by 2 is for not counting the_geom_webmercator
END AS multiplier FROM table_cat GROUP BY is_overview, is_raster
)
SELECT sum(table_size*multiplier)::int8 INTO total_size FROM sizes;
SELECT sum(table_size*multiplier)::int8 FROM sizes
', raster_read_query, schema_name, schema_name) INTO total_size;
IF total_size IS NOT NULL THEN
RETURN total_size;
@@ -56,20 +72,20 @@ BEGIN
END IF;
END;
$$
LANGUAGE 'plpgsql' VOLATILE;
LANGUAGE 'plpgsql' VOLATILE PARALLEL UNSAFE;
-- Return the estimated size of user data. Used for quota checking.
-- Implicit schema version for backwards compatibility
CREATE OR REPLACE FUNCTION CDB_UserDataSize()
CREATE OR REPLACE FUNCTION @extschema@.CDB_UserDataSize()
RETURNS bigint AS
$$
SELECT public.CDB_UserDataSize('public');
SELECT @extschema@.CDB_UserDataSize('public');
$$
LANGUAGE 'sql' VOLATILE;
LANGUAGE 'sql' VOLATILE PARALLEL UNSAFE;
-- Triggers cannot have declared arguments: pbfact float8, qmax int8, schema_name text
CREATE OR REPLACE FUNCTION CDB_CheckQuota()
CREATE OR REPLACE FUNCTION @extschema@.CDB_CheckQuota()
RETURNS trigger AS
$$
DECLARE
@@ -81,7 +97,7 @@ DECLARE
BEGIN
IF TG_NARGS = 3 THEN
schema_name := TG_ARGV[2];
IF cartodb.schema_exists(schema_name) = false THEN
IF @extschema@.schema_exists(schema_name) = false THEN
RAISE EXCEPTION 'Invalid schema name "%"', schema_name;
END IF;
ELSE
@@ -112,7 +128,7 @@ BEGIN
RETURN NEW;
END IF;
SELECT public.CDB_UserDataSize(schema_name) INTO quota;
SELECT @extschema@.CDB_UserDataSize(schema_name) INTO quota;
IF quota > qmax THEN
RAISE EXCEPTION 'Quota exceeded by %KB', (quota-qmax)/1024;
ELSE RAISE DEBUG 'User quota in bytes: % < % (max allowed)', quota, qmax;
@@ -122,16 +138,16 @@ BEGIN
RETURN NEW;
END;
$$
LANGUAGE 'plpgsql' VOLATILE;
LANGUAGE 'plpgsql' VOLATILE PARALLEL UNSAFE;
CREATE OR REPLACE FUNCTION CDB_SetUserQuotaInBytes(schema_name text, bytes int8)
CREATE OR REPLACE FUNCTION @extschema@.CDB_SetUserQuotaInBytes(schema_name text, bytes int8)
RETURNS int8 AS
$$
DECLARE
sql text;
BEGIN
IF cartodb.schema_exists(schema_name::text) = false THEN
IF @extschema@.schema_exists(schema_name::text) = false THEN
RAISE EXCEPTION 'Invalid schema name "%"', schema_name::text;
END IF;
@@ -143,14 +159,14 @@ BEGIN
return bytes;
END
$$
LANGUAGE 'plpgsql' VOLATILE STRICT;
LANGUAGE 'plpgsql' VOLATILE STRICT PARALLEL UNSAFE;
CREATE OR REPLACE FUNCTION CDB_SetUserQuotaInBytes(bytes int8)
CREATE OR REPLACE FUNCTION @extschema@.CDB_SetUserQuotaInBytes(bytes int8)
RETURNS int8 AS
$$
BEGIN
return public.CDB_SetUserQuotaInBytes('public', bytes);
return @extschema@.CDB_SetUserQuotaInBytes('public', bytes);
END;
$$
LANGUAGE 'plpgsql' VOLATILE STRICT;
LANGUAGE 'plpgsql' VOLATILE STRICT PARALLEL UNSAFE;

View File

@@ -15,7 +15,7 @@
--
--
-- }{
CREATE OR REPLACE FUNCTION CDB_RandomTids(in_table regclass, in_nsamples integer)
CREATE OR REPLACE FUNCTION @extschema@.CDB_RandomTids(in_table regclass, in_nsamples integer)
RETURNS tid[]
AS $$
DECLARE
@@ -64,6 +64,6 @@ BEGIN
RETURN tidlist;
END
$$ LANGUAGE 'plpgsql' STABLE STRICT;
$$ LANGUAGE 'plpgsql' STABLE STRICT PARALLEL SAFE;
-- }

View File

@@ -1,3 +1,6 @@
-- In older versions of the extension, CDB_RectangleGrid had a different signature
DROP FUNCTION IF EXISTS @extschema@.CDB_RectangleGrid(GEOMETRY, FLOAT8, FLOAT8, GEOMETRY);
--
-- Fill given extent with a rectangular coverage
--
@@ -6,7 +9,7 @@
-- be emitted. The returned hexagons will have the same SRID
-- as this extent.
--
-- @param width With of each rectangle
-- @param width Width of each rectangle
--
-- @param height Height of each rectangle
--
@@ -14,9 +17,12 @@
-- If omitted the origin will be 0,0.
-- The parameter is checked for having the same SRID
-- as the extent.
--
--
CREATE OR REPLACE FUNCTION CDB_RectangleGrid(ext GEOMETRY, width FLOAT8, height FLOAT8, origin GEOMETRY DEFAULT NULL)
-- @param maxcells Optional maximum number of grid cells to generate;
-- if the grid requires more cells to cover the extent
-- and exception will occur.
--
CREATE OR REPLACE FUNCTION @extschema@.CDB_RectangleGrid(ext GEOMETRY, width FLOAT8, height FLOAT8, origin GEOMETRY DEFAULT NULL, maxcells INTEGER DEFAULT 512*512)
RETURNS SETOF GEOMETRY
AS $$
DECLARE
@@ -38,17 +44,17 @@ DECLARE
srid INTEGER;
BEGIN
srid := ST_SRID(ext);
srid := @postgisschema@.ST_SRID(ext);
xoff := 0;
yoff := 0;
IF origin IS NOT NULL THEN
IF ST_SRID(origin) != srid THEN
IF @postgisschema@.ST_SRID(origin) != srid THEN
RAISE EXCEPTION 'SRID mismatch between extent (%) and origin (%)', srid, ST_SRID(origin);
END IF;
xoff := ST_X(origin);
yoff := ST_Y(origin);
xoff := @postgisschema@.ST_X(origin);
yoff := @postgisschema@.ST_Y(origin);
END IF;
--RAISE DEBUG 'X offset: %', xoff;
@@ -66,11 +72,11 @@ BEGIN
vstep := height;
-- Tweak horizontal start on hstep grid from origin
hstart := xoff + ceil((ST_XMin(ext)-xoff)/hstep)*hstep;
hstart := xoff + ceil((@postgisschema@.ST_XMin(ext)-xoff)/hstep)*hstep;
--RAISE DEBUG 'hstart: %', hstart;
-- Tweak vertical start on vstep grid from origin
vstart := yoff + ceil((ST_Ymin(ext)-yoff)/vstep)*vstep;
vstart := yoff + ceil((@postgisschema@.ST_Ymin(ext)-yoff)/vstep)*vstep;
--RAISE DEBUG 'vstart: %', vstart;
hend := ST_XMax(ext);
@@ -79,13 +85,19 @@ BEGIN
--RAISE DEBUG 'hend: %', hend;
--RAISE DEBUG 'vend: %', vend;
If maxcells IS NOT NULL AND maxcells > 0 THEN
IF ((hend - hstart)/hstep * (vend - vstart)/vstep)::integer > maxcells THEN
RAISE EXCEPTION 'The requested grid is too big to be rendered';
END IF;
END IF;
x := hstart;
WHILE x < hend LOOP -- over X
y := vstart;
h := ST_MakeEnvelope(x-hw, y-hh, x+hw, y+hh, srid);
h := @postgisschema@.ST_MakeEnvelope(x-hw, y-hh, x+hw, y+hh, srid);
WHILE y < vend LOOP -- over Y
RETURN NEXT h;
h := ST_Translate(h, 0, vstep);
h := @postgisschema@.ST_Translate(h, 0, vstep);
y := yoff + round(((y + vstep)-yoff)/ygrd)*ygrd; -- round to grid
END LOOP;
x := xoff + round(((x + hstep)-xoff)/xgrd)*xgrd; -- round to grid
@@ -93,4 +105,4 @@ BEGIN
RETURN;
END
$$ LANGUAGE 'plpgsql' IMMUTABLE;
$$ LANGUAGE 'plpgsql' IMMUTABLE PARALLEL SAFE;

View File

@@ -1,4 +1,4 @@
---- Make sure 'cartodb' is in database search path
---- Make sure '@extschema@' is in database search path
DO
$$
DECLARE
@@ -8,13 +8,13 @@ BEGIN
SELECT reset_val INTO var_cur_search_path
FROM pg_settings WHERE name = 'search_path';
IF var_cur_search_path LIKE '%cartodb%' THEN
RAISE DEBUG '"cartodb" already in database search_path';
IF var_cur_search_path LIKE '%@extschema@%' THEN
RAISE DEBUG '"@extschema@" already in database search_path';
ELSE
var_cur_search_path := var_cur_search_path || ', "cartodb"';
var_cur_search_path := var_cur_search_path || ', "@extschema@"';
EXECUTE 'ALTER DATABASE ' || quote_ident(current_database()) ||
' SET search_path = ' || var_cur_search_path;
RAISE DEBUG '"cartodb" has been added to end of database search_path';
RAISE DEBUG '"@extschema@" has been added to end of database search_path';
END IF;
-- Reset search_path

View File

@@ -0,0 +1,53 @@
--
-- Calculate basic statistics of a given dataset
--
-- @param in_array A numeric array of numbers
--
-- Returns: statistical quantity chosen
--
-- References: http://www.itl.nist.gov/div898/handbook/eda/section3/eda35b.htm
--
-- Calculate kurtosis
CREATE OR REPLACE FUNCTION @extschema@.CDB_Kurtosis ( in_array NUMERIC[] ) RETURNS NUMERIC as $$
DECLARE
a numeric;
c numeric;
k numeric;
BEGIN
SELECT AVG(e), COUNT(e)::numeric * power(stddev(e),4) INTO a, c FROM ( SELECT unnest(in_array) e ) x;
IF c=0 THEN
RETURN 0;
ELSE
EXECUTE 'SELECT sum(power($1 - e, 4)) / ($2 ) - 3
FROM (SELECT unnest($3) e ) x'
INTO k
USING a, c, in_array;
RETURN k;
END IF;
END;
$$ language plpgsql IMMUTABLE STRICT PARALLEL SAFE;
-- Calculate skewness
CREATE OR REPLACE FUNCTION @extschema@.CDB_Skewness ( in_array NUMERIC[] ) RETURNS NUMERIC as $$
DECLARE
a numeric;
c numeric;
sk numeric;
BEGIN
SELECT AVG(e), COUNT(e)::numeric * power(stddev(e),3) INTO a, c FROM ( SELECT unnest(in_array) e ) x;
IF c=0 THEN
RETURN 0;
ELSE
EXECUTE 'SELECT sum(power($1 - e, 3)) / ( $2 )
FROM (SELECT unnest($3) e ) x'
INTO sk
USING a, c, in_array;
RETURN sk;
END IF;
END;
$$ language plpgsql IMMUTABLE STRICT PARALLEL SAFE;

View File

@@ -1,7 +1,7 @@
-- Convert string to date
--
DROP FUNCTION IF EXISTS CDB_StringToDate(character varying);
CREATE OR REPLACE FUNCTION CDB_StringToDate(input character varying)
DROP FUNCTION IF EXISTS @extschema@.CDB_StringToDate(character varying);
CREATE OR REPLACE FUNCTION @extschema@.CDB_StringToDate(input character varying)
RETURNS TIMESTAMP AS $$
DECLARE output TIMESTAMP;
BEGIN
@@ -17,4 +17,4 @@ BEGIN
RETURN output;
END;
$$
LANGUAGE 'plpgsql' STABLE STRICT;
LANGUAGE 'plpgsql' IMMUTABLE STRICT PARALLEL UNSAFE;

View File

@@ -0,0 +1,167 @@
/*
Gets the column names of a given table.
Sample usage:
SELECT @extschema@._CDB_GetColumns('public.films');
*/
CREATE OR REPLACE FUNCTION @extschema@._CDB_GetColumns(src_table REGCLASS)
RETURNS SETOF NAME
AS $$
SELECT
a.attname as "colname"
FROM
pg_catalog.pg_attribute a
WHERE
a.attnum > 0
AND NOT a.attisdropped
AND a.attrelid = (
SELECT c.oid
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.oid = src_table::oid
AND pg_catalog.pg_table_is_visible(c.oid)
)
ORDER BY a.attnum;
$$ LANGUAGE sql STABLE PARALLEL UNSAFE;
/*
Given an array of quoted column names, it generates an UPDATE SET
clause with the following form:
the_geom = changed.the_geom,
id = changed.id,
elevation = changed.elevation
Example of usage:
SELECT @extschema@.__CDB_GetUpdateSetClause('{the_geom, id, elevation}', 'changed');
*/
CREATE OR REPLACE FUNCTION @extschema@.__CDB_GetUpdateSetClause(colnames TEXT[], update_source TEXT)
RETURNS TEXT
AS $$
DECLARE
set_clause_list TEXT[];
col TEXT;
BEGIN
FOREACH col IN ARRAY colnames
LOOP
set_clause_list := array_append(set_clause_list, format('%1$s = %2$s.%1$s', col, update_source));
END lOOP;
RETURN array_to_string(set_clause_list, ', ');
END;
$$ LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
/*
Given a prefix, generate a safe unique NAME for a temp table.
Example of usage:
SELECT @extschema@.__CDB_GenerateUniqueName('src_sync'); --> src_sync_718794_120106
*/
CREATE OR REPLACE FUNCTION @extschema@.__CDB_GenerateUniqueName(prefix TEXT)
RETURNS NAME
AS $$
SELECT format('%s_%s_%s', prefix, txid_current(), (random()*1000000)::int)::NAME;
$$ LANGUAGE sql VOLATILE PARALLEL UNSAFE;
/*
Given a table name and an array of column names,
return array of column names qualified with the table name and quoted when necessary
tablename and colnames should be properly quoted, and for this reason the type NAME is not
used for them (with quotes they could exceed the maximum identifier length)
Example of usage:
SELECT @extschema@.__CDB_QualifyColumns('t', ARRAY['a','"b-1"']); --> ARRAY['t.a','t."b-1"']
*/
CREATE OR REPLACE FUNCTION @extschema@.__CDB_QualifyColumns(tablename NAME, colnames NAME[]) RETURNS TEXT[] AS
$$
SELECT array_agg(tablename || '.' || _colname) from unnest(colnames) _colname;
$$ LANGUAGE sql IMMUTABLE PARALLEL SAFE;
/*
A Table Syncer
Assumptions:
- Both tables contain a consistent cartodb_id column
- Destination table has all columns of the source or does not exist
Sample usage:
SELECT CDB_SyncTable('radar_stations', 'public', 'syncdest');
SELECT CDB_SyncTable('test_sync_source', 'public', 'test_sync_dest', '{the_geom, the_geom_webmercator}');
*/
CREATE OR REPLACE FUNCTION @extschema@.CDB_SyncTable(src_table REGCLASS, dst_schema REGNAMESPACE, dst_table NAME, skip_cols NAME[] = '{}')
RETURNS void
AS $$
DECLARE
fq_dest_table TEXT;
colnames TEXT[];
dst_colnames TEXT;
src_colnames TEXT;
update_set_clause TEXT;
num_rows BIGINT;
err_context text;
t timestamptz;
BEGIN
-- If the destination table does not exist, just copy the source table
fq_dest_table := format('%s.%I', dst_schema, dst_table);
EXECUTE format('CREATE TABLE IF NOT EXISTS %s as TABLE %s', fq_dest_table, src_table);
GET DIAGNOSTICS num_rows = ROW_COUNT;
IF num_rows > 0 THEN
RAISE NOTICE 'INSERTED % row(s)', num_rows;
RETURN;
END IF;
skip_cols := skip_cols || '{cartodb_id}';
-- Get the list of columns from the source table, excluding skip_cols
SELECT ARRAY(SELECT quote_ident(c) FROM @extschema@._CDB_GetColumns(src_table) as c EXCEPT SELECT unnest(skip_cols)) INTO colnames;
-- Deal with deleted rows: ids in dest but not in source
t := clock_timestamp();
EXECUTE format(
'DELETE FROM %1$s _dst WHERE NOT EXISTS (SELECT * FROM %2$s _src WHERE _src.cartodb_id=_dst.cartodb_id)',
fq_dest_table, src_table);
GET DIAGNOSTICS num_rows = ROW_COUNT;
RAISE NOTICE 'DELETED % row(s)', num_rows;
RAISE DEBUG 'DELETE time (s): %', clock_timestamp() - t;
-- Deal with inserted rows: ids in source but not in dest
t := clock_timestamp();
EXECUTE format('
INSERT INTO %1$s(cartodb_id, %2$s)
SELECT cartodb_id, %2$s FROM %3$s _src WHERE NOT EXISTS (SELECT * FROM %1$s _dst WHERE _src.cartodb_id=_dst.cartodb_id)
', fq_dest_table, array_to_string(colnames, ','), src_table);
GET DIAGNOSTICS num_rows = ROW_COUNT;
RAISE NOTICE 'INSERTED % row(s)', num_rows;
RAISE DEBUG 'INSERT time (s): %', clock_timestamp() - t;
-- Deal with modified rows: ids in source and dest but different hashes
t := clock_timestamp();
update_set_clause := @extschema@.__CDB_GetUpdateSetClause(colnames, '_changed');
dst_colnames := array_to_string(@extschema@.__CDB_QualifyColumns('_dst', colnames), ',');
src_colnames := array_to_string(@extschema@.__CDB_QualifyColumns('_src', colnames), ',');
EXECUTE format('
UPDATE %1$s _update SET %2$s
FROM (
SELECT _src.* FROM %3$s _src JOIN %1$s _dst ON (_dst.cartodb_id = _src.cartodb_id)
WHERE md5(ROW(%4$s)::text) <> md5(ROW(%5$s)::text)
) _changed
WHERE _update.cartodb_id = _changed.cartodb_id;
', fq_dest_table, update_set_clause, src_table, dst_colnames, src_colnames);
GET DIAGNOSTICS num_rows = ROW_COUNT;
RAISE NOTICE 'MODIFIED % row(s)', num_rows;
RAISE DEBUG 'UPDATE time (s): %', clock_timestamp() - t;
END;
$$ LANGUAGE plpgsql VOLATILE PARALLEL UNSAFE;

View File

@@ -1,5 +1,5 @@
-- Function returning indexes for a table
CREATE OR REPLACE FUNCTION CDB_TableIndexes(REGCLASS)
CREATE OR REPLACE FUNCTION @extschema@.CDB_TableIndexes(REGCLASS)
RETURNS TABLE(index_name name, index_unique bool, index_primary bool, index_keys text array)
AS $$
@@ -20,8 +20,8 @@ AS $$
AND pg_class.relname=pg_indexes.indexname
;
$$ LANGUAGE SQL;
$$ LANGUAGE SQL STABLE PARALLEL SAFE;
-- This is to migrate from pre-0.2.0 version
-- See http://github.com/CartoDB/cartodb-postgresql/issues/36
GRANT EXECUTE ON FUNCTION CDB_TableIndexes(REGCLASS) TO public;
GRANT EXECUTE ON FUNCTION @extschema@.CDB_TableIndexes(REGCLASS) TO public;

View File

@@ -1,13 +1,18 @@
CREATE TABLE IF NOT EXISTS
public.CDB_TableMetadata (
@extschema@.CDB_TableMetadata (
tabname regclass not null primary key,
updated_at timestamp with time zone not null default now()
);
CREATE OR REPLACE VIEW @extschema@.CDB_TableMetadata_Text AS
SELECT FORMAT('%I.%I', n.nspname::text, c.relname::text) tabname, updated_at
FROM @extschema@.CDB_TableMetadata m JOIN pg_catalog.pg_class c ON m.tabname::oid = c.oid
LEFT JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid;
-- No one can see this
-- Updates are only possible trough the security definer trigger
-- GRANT SELECT ON public.CDB_TableMetadata TO public;
-- GRANT SELECT ON @extschema@.CDB_TableMetadata TO public;
--
-- Trigger logging updated_at in the CDB_TableMetadata
@@ -22,48 +27,53 @@ CREATE TABLE IF NOT EXISTS
--
-- NOTE: _never_ attach to CDB_TableMetadata ...
--
CREATE OR REPLACE FUNCTION CDB_TableMetadata_Trigger()
CREATE OR REPLACE FUNCTION @extschema@.CDB_TableMetadata_Trigger()
RETURNS trigger AS
$$
BEGIN
-- Guard against infinite loop
IF TG_RELID = 'public.CDB_TableMetadata'::regclass::oid THEN
IF TG_RELID = '@extschema@.CDB_TableMetadata'::regclass::oid THEN
RETURN NULL;
END IF;
-- Cleanup stale entries
DELETE FROM public.CDB_TableMetadata
DELETE FROM @extschema@.CDB_TableMetadata
WHERE NOT EXISTS (
SELECT oid FROM pg_class WHERE oid = tabname
);
WITH nv as (
SELECT TG_RELID as tabname, NOW() as t
SELECT TG_RELID as tabname, now() as t
), updated as (
UPDATE public.CDB_TableMetadata x SET updated_at = nv.t
UPDATE @extschema@.CDB_TableMetadata x SET updated_at = nv.t
FROM nv WHERE x.tabname = nv.tabname
RETURNING x.tabname
)
INSERT INTO public.CDB_TableMetadata SELECT nv.*
INSERT INTO @extschema@.CDB_TableMetadata SELECT nv.*
FROM nv LEFT JOIN updated USING(tabname)
WHERE updated.tabname IS NULL;
RETURN NULL;
END;
$$
LANGUAGE plpgsql VOLATILE SECURITY DEFINER;
$$ LANGUAGE plpgsql
VOLATILE
PARALLEL UNSAFE
SECURITY DEFINER
SET search_path = pg_temp;
--
-- Trigger invalidating varnish whenever CDB_TableMetadata
-- record change.
--
CREATE OR REPLACE FUNCTION _CDB_TableMetadata_Updated()
CREATE OR REPLACE FUNCTION @extschema@._CDB_TableMetadata_Updated()
RETURNS trigger AS
$$
DECLARE
tabname TEXT;
tabname regclass;
rec RECORD;
found BOOL;
schema_name TEXT;
table_name TEXT;
BEGIN
IF TG_OP = 'UPDATE' or TG_OP = 'INSERT' THEN
@@ -86,21 +96,22 @@ BEGIN
--
-- Call the first varnish invalidation function owned
-- by a superuser found in cartodb or public schema
-- by a superuser found in @extschema@ or public schema
-- (in that order)
found := false;
FOR rec IN SELECT u.usesuper, u.usename, n.nspname, p.proname
FROM pg_proc p, pg_namespace n, pg_user u
WHERE p.proname = 'cdb_invalidate_varnish'
AND p.pronamespace = n.oid
AND n.nspname IN ('public', 'cartodb')
AND n.nspname IN ('public', '@extschema@')
AND u.usesysid = p.proowner
AND u.usesuper
ORDER BY n.nspname
LOOP
SELECT n.nspname, c.relname FROM pg_class c, pg_namespace n WHERE c.oid=tabname AND c.relnamespace = n.oid INTO schema_name, table_name;
EXECUTE 'SELECT ' || quote_ident(rec.nspname) || '.'
|| quote_ident(rec.proname)
|| '(' || quote_literal(tabname) || ')';
|| '(' || quote_literal(quote_ident(schema_name) || '.' || quote_ident(table_name)) || ')';
found := true;
EXIT;
END LOOP;
@@ -108,31 +119,34 @@ BEGIN
RETURN NULL;
END;
$$
LANGUAGE plpgsql VOLATILE SECURITY DEFINER;
$$ LANGUAGE plpgsql
VOLATILE
PARALLEL UNSAFE
SECURITY DEFINER
SET search_path = pg_temp;
DROP TRIGGER IF EXISTS table_modified ON CDB_TableMetadata;
DROP TRIGGER IF EXISTS table_modified ON @extschema@.CDB_TableMetadata;
-- NOTE: on DELETE we would be unable to convert the table
-- oid (regclass) to its name
CREATE TRIGGER table_modified AFTER INSERT OR UPDATE
ON CDB_TableMetadata FOR EACH ROW EXECUTE PROCEDURE
_CDB_TableMetadata_Updated();
ON @extschema@.CDB_TableMetadata FOR EACH ROW EXECUTE PROCEDURE
@extschema@._CDB_TableMetadata_Updated();
-- similar to TOUCH(1) in unix filesystems but for table in cdb_tablemetadata
CREATE OR REPLACE FUNCTION public.CDB_TableMetadataTouch(tablename regclass)
CREATE OR REPLACE FUNCTION @extschema@.CDB_TableMetadataTouch(tablename regclass)
RETURNS void AS
$$
BEGIN
WITH upsert AS (
UPDATE public.cdb_tablemetadata
UPDATE @extschema@.cdb_tablemetadata
SET updated_at = NOW()
WHERE tabname = tablename
RETURNING *
)
INSERT INTO public.cdb_tablemetadata (tabname, updated_at)
INSERT INTO @extschema@.cdb_tablemetadata (tabname, updated_at)
SELECT tablename, NOW()
WHERE NOT EXISTS (SELECT * FROM upsert);
END;
$$
LANGUAGE 'plpgsql' VOLATILE STRICT;
LANGUAGE 'plpgsql' VOLATILE STRICT PARALLEL UNSAFE;

View File

@@ -5,19 +5,19 @@
-- for web mercator by "clipping" anything outside to the valid
-- range.
--
CREATE OR REPLACE FUNCTION CDB_TransformToWebmercator(geom geometry)
RETURNS geometry
CREATE OR REPLACE FUNCTION @extschema@.CDB_TransformToWebmercator(geom @postgisschema@.geometry)
RETURNS @postgisschema@.geometry
AS
$$
DECLARE
valid_extent GEOMETRY;
latlon_input GEOMETRY;
clipped_input GEOMETRY;
to_webmercator GEOMETRY;
ret GEOMETRY;
valid_extent @postgisschema@.GEOMETRY;
latlon_input @postgisschema@.GEOMETRY;
clipped_input @postgisschema@.GEOMETRY;
to_webmercator @postgisschema@.GEOMETRY;
ret @postgisschema@.GEOMETRY;
BEGIN
IF ST_Srid(geom) = 3857 THEN
IF @postgisschema@.ST_Srid(geom) = 3857 THEN
RETURN geom;
END IF;
@@ -27,52 +27,56 @@ BEGIN
-- to -85.0511 to 85.0511 but as long as proj
-- does not complain we are happy
--
valid_extent := ST_MakeEnvelope(-180, -89, 180, 89, 4326);
valid_extent := @postgisschema@.ST_MakeEnvelope(-180, -89, 180, 89, 4326);
-- Then we transform to WGS84 latlon, which is
-- where we have known coordinates for the clipping
--
latlon_input := ST_Transform(geom, 4326);
--
latlon_input := @postgisschema@.ST_Transform(geom, 4326);
-- Don't bother clipping if the geometry boundary doesn't
-- go outside the valid extent.
IF latlon_input @ valid_extent THEN
RETURN ST_Transform(latlon_input, 3857);
BEGIN
RETURN @postgisschema@.ST_Transform(latlon_input, 3857);
EXCEPTION WHEN OTHERS THEN
RETURN NULL;
END;
END IF;
-- Since we're going to use ST_Intersection on input
-- we'd better ensure the input is valid
-- TODO: only do this if the first ST_Intersection fails ?
IF ST_Dimension(geom) != 0 AND
IF @postgisschema@.ST_Dimension(geom) != 0 AND
-- See http://trac.osgeo.org/postgis/ticket/1719
GeometryType(geom) != 'GEOMETRYCOLLECTION'
@postgisschema@.GeometryType(geom) != 'GEOMETRYCOLLECTION'
THEN
BEGIN
latlon_input := ST_MakeValid(latlon_input);
latlon_input := @postgisschema@.ST_MakeValid(latlon_input);
EXCEPTION
WHEN OTHERS THEN
-- See http://github.com/Vizzuality/cartodb/issues/931
RAISE WARNING 'Could not clean input geometry: %', SQLERRM;
RETURN NULL;
RETURN NULL;
END;
latlon_input := ST_CollectionExtract(latlon_input, ST_Dimension(geom)+1);
latlon_input := @postgisschema@.ST_CollectionExtract(latlon_input, ST_Dimension(geom)+1);
END IF;
-- Then we clip, trying to retain the input type
-- TODO: catch exceptions here too ?
clipped_input := ST_Intersection(latlon_input, valid_extent);
clipped_input := @postgisschema@.ST_Intersection(latlon_input, valid_extent);
-- We transform to web mercator
to_webmercator := ST_Transform(clipped_input, 3857);
to_webmercator := @postgisschema@.ST_Transform(clipped_input, 3857);
-- Finally we convert EMPTY to NULL
-- Finally we convert EMPTY to NULL
-- See https://github.com/Vizzuality/cartodb/issues/706
-- And retain "multi" status
ret := CASE WHEN ST_IsEmpty(to_webmercator) THEN NULL::geometry
WHEN GeometryType(geom) LIKE 'MULTI%' THEN ST_Multi(to_webmercator)
ret := CASE WHEN @postgisschema@.ST_IsEmpty(to_webmercator) THEN NULL::@postgisschema@.geometry
WHEN @postgisschema@.GeometryType(geom) LIKE 'MULTI%' THEN @postgisschema@.ST_Multi(to_webmercator)
ELSE to_webmercator
END;
RETURN ret;
END
$$ LANGUAGE 'plpgsql' IMMUTABLE STRICT;
$$ LANGUAGE 'plpgsql' IMMUTABLE STRICT PARALLEL UNSAFE;

View File

@@ -5,8 +5,8 @@
--
-- Currently accepted permissions are: 'public', 'private' or 'all'
--
DROP FUNCTION IF EXISTS cdb_usertables(text);
CREATE OR REPLACE FUNCTION CDB_UserTables(perm text DEFAULT 'all')
DROP FUNCTION IF EXISTS @extschema@.CDB_UserTables(text);
CREATE OR REPLACE FUNCTION @extschema@.CDB_UserTables(perm text DEFAULT 'all')
RETURNS SETOF name
AS $$
@@ -14,15 +14,15 @@ SELECT c.relname
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = 'r'
AND c.relname NOT IN ('cdb_tablemetadata', 'spatial_ref_sys')
AND n.nspname NOT IN ('pg_catalog', 'information_schema', 'topology')
AND c.relname NOT IN ('cdb_tablemetadata', 'cdb_analysis_catalog', 'cdb_conf', 'spatial_ref_sys')
AND n.nspname NOT IN ('pg_catalog', 'information_schema', 'topology', '@extschema@')
AND CASE WHEN perm = 'public' THEN has_table_privilege('publicuser', c.oid, 'SELECT')
WHEN perm = 'private' THEN has_table_privilege(current_user, c.oid, 'SELECT') AND NOT has_table_privilege('publicuser', c.oid, 'SELECT')
WHEN perm = 'all' THEN has_table_privilege(current_user, c.oid, 'SELECT') OR has_table_privilege('publicuser', c.oid, 'SELECT')
ELSE false END;
$$ LANGUAGE 'sql';
$$ LANGUAGE 'sql' STABLE PARALLEL SAFE;
-- This is to migrate from pre-0.2.0 version
-- See http://github.com/CartoDB/cartodb-postgresql/issues/36
GRANT EXECUTE ON FUNCTION CDB_UserTables(text) TO public;
GRANT EXECUTE ON FUNCTION @extschema@.CDB_UserTables(text) TO public;

View File

@@ -0,0 +1,10 @@
-- Returns the cartodb username of the current PostgreSQL session
CREATE OR REPLACE FUNCTION @extschema@.CDB_Username()
RETURNS text
AS $$
SELECT @extschema@.CDB_Conf_GetConf(concat('api_keys_', session_user))->>'username';
$$ LANGUAGE SQL
STABLE
PARALLEL SAFE
SECURITY DEFINER
SET search_path = pg_temp;

View File

@@ -1,28 +1,12 @@
-- {
-- Return pixel resolution at the given zoom level
-- }{
CREATE OR REPLACE FUNCTION CDB_XYZ_Resolution(z INTEGER)
CREATE OR REPLACE FUNCTION @extschema@.CDB_XYZ_Resolution(z INTEGER)
RETURNS FLOAT8
AS $$
DECLARE
earth_circumference FLOAT8;
tile_size INTEGER;
full_resolution FLOAT8;
BEGIN
-- Earth equatorial circumference in meters (according to wikipedia)
earth_circumference := 40075017;
-- Size of each tile in pixels (1:1 aspect ratio)
tile_size := 256;
full_resolution := earth_circumference/tile_size;
RETURN full_resolution / (power(2,z));
END
$$ LANGUAGE 'plpgsql' IMMUTABLE STRICT;
-- circumference divided by 256 is z0 resolution, then divide by 2^z
SELECT 6378137.0*2.0*pi() / 256.0 / power(2.0, z);
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE STRICT;
-- }
-- {
@@ -31,7 +15,7 @@ $$ LANGUAGE 'plpgsql' IMMUTABLE STRICT;
-- SRID of the returned polygon is forceably 3857
--
-- }{
CREATE OR REPLACE FUNCTION CDB_XYZ_Extent(x INTEGER, y INTEGER, z INTEGER)
CREATE OR REPLACE FUNCTION @extschema@.CDB_XYZ_Extent(x INTEGER, y INTEGER, z INTEGER)
RETURNS GEOMETRY
AS $$
DECLARE
@@ -50,7 +34,7 @@ BEGIN
-- Size of each tile in pixels (1:1 aspect ratio)
tile_size := 256;
initial_resolution := CDB_XYZ_Resolution(0);
initial_resolution := @extschema@.CDB_XYZ_Resolution(0);
--RAISE DEBUG 'Initial resolution: %', initial_resolution;
origin_shift := (initial_resolution * tile_size) / 2.0;
@@ -72,8 +56,7 @@ BEGIN
--RAISE DEBUG 'ymin: %', ymin;
--RAISE DEBUG 'ymax: %', ymax;
RETURN ST_MakeEnvelope(xmin, ymin, xmax, ymax, 3857);
RETURN @postgisschema@.ST_MakeEnvelope(xmin, ymin, xmax, ymax, 3857);
END
$$ LANGUAGE 'plpgsql' IMMUTABLE STRICT;
$$ LANGUAGE 'plpgsql' IMMUTABLE STRICT PARALLEL SAFE;
-- }

View File

@@ -1,31 +1,36 @@
CREATE OR REPLACE FUNCTION cartodb.CDB_ZoomFromScale(scaleDenominator numeric) RETURNS int AS $$
BEGIN
CASE
WHEN scaleDenominator > 1000000000 THEN RETURN 0;
WHEN scaleDenominator <= 1000000000 AND scaleDenominator > 500000000 THEN RETURN 1;
WHEN scaleDenominator <= 500000000 AND scaleDenominator > 200000000 THEN RETURN 2;
WHEN scaleDenominator <= 200000000 AND scaleDenominator > 100000000 THEN RETURN 3;
WHEN scaleDenominator <= 100000000 AND scaleDenominator > 50000000 THEN RETURN 3;
WHEN scaleDenominator <= 50000000 AND scaleDenominator > 25000000 THEN RETURN 4;
WHEN scaleDenominator <= 25000000 AND scaleDenominator > 12500000 THEN RETURN 5;
WHEN scaleDenominator <= 12500000 AND scaleDenominator > 6500000 THEN RETURN 6;
WHEN scaleDenominator <= 6500000 AND scaleDenominator > 3000000 THEN RETURN 7;
WHEN scaleDenominator <= 3000000 AND scaleDenominator > 1500000 THEN RETURN 8;
WHEN scaleDenominator <= 1500000 AND scaleDenominator > 750000 THEN RETURN 9;
WHEN scaleDenominator <= 750000 AND scaleDenominator > 400000 THEN RETURN 10;
WHEN scaleDenominator <= 400000 AND scaleDenominator > 200000 THEN RETURN 11;
WHEN scaleDenominator <= 200000 AND scaleDenominator > 100000 THEN RETURN 12;
WHEN scaleDenominator <= 100000 AND scaleDenominator > 50000 THEN RETURN 13;
WHEN scaleDenominator <= 50000 AND scaleDenominator > 25000 THEN RETURN 14;
WHEN scaleDenominator <= 25000 AND scaleDenominator > 12500 THEN RETURN 15;
WHEN scaleDenominator <= 12500 AND scaleDenominator > 5000 THEN RETURN 16;
WHEN scaleDenominator <= 5000 AND scaleDenominator > 2500 THEN RETURN 17;
WHEN scaleDenominator <= 2500 AND scaleDenominator > 1500 THEN RETURN 18;
WHEN scaleDenominator <= 1500 AND scaleDenominator > 750 THEN RETURN 19;
WHEN scaleDenominator <= 750 AND scaleDenominator > 500 THEN RETURN 20;
WHEN scaleDenominator <= 500 AND scaleDenominator > 250 THEN RETURN 21;
WHEN scaleDenominator <= 250 AND scaleDenominator > 100 THEN RETURN 22;
WHEN scaleDenominator <= 100 THEN RETURN 23;
END CASE;
END
$$ LANGUAGE plpgsql IMMUTABLE;
-- Maximum supported zoom level
CREATE OR REPLACE FUNCTION @extschema@._CDB_MaxSupportedZoom()
RETURNS int
LANGUAGE SQL
IMMUTABLE PARALLEL SAFE
AS $$
-- The maximum zoom level has to be limited for various reasons,
-- e.g. zoom levels greater than 31 would require tile coordinates
-- that would not fit in an INTEGER (which is signed, 32 bits long).
-- We'll choose 20 as a limit which is safe also when the JavaScript shift
-- operator (<<) is used for computing powers of two.
SELECT 29;
$$;
CREATE OR REPLACE FUNCTION @extschema@.CDB_ZoomFromScale(scaleDenominator numeric)
RETURNS int
LANGUAGE SQL
IMMUTABLE PARALLEL SAFE
AS $$
SELECT
CASE
WHEN scaleDenominator > 600000000 THEN
-- Scale is smaller than zoom level 0
NULL
WHEN scaleDenominator = 0 THEN
-- Actual zoom level would be infinite
@extschema@._CDB_MaxSupportedZoom()
ELSE
CAST (
LEAST(
ROUND(LOG(2, 559082264.028/scaleDenominator)),
@extschema@._CDB_MaxSupportedZoom()
)
AS INTEGER)
END;
$$;

View File

@@ -0,0 +1 @@
../scripts-available/CDB_OverviewsSupport.sql

View File

@@ -0,0 +1 @@
../scripts-available/CDB_GreatCircle.sql

View File

@@ -0,0 +1 @@
../scripts-available/CDB_Overviews.sql

View File

@@ -0,0 +1 @@
../scripts-available/CDB_ForeignTable.sql

View File

@@ -0,0 +1 @@
../scripts-available/CDB_AnalysisCatalog.sql

View File

@@ -0,0 +1 @@
../scripts-available/CDB_AnalysisSupport.sql

View File

@@ -0,0 +1 @@
../scripts-available/CDB_AnalysisCheck.sql

View File

@@ -0,0 +1 @@
../scripts-available/CDB_EstimateRowCount.sql

View File

@@ -0,0 +1 @@
../scripts-available/CDB_GhostTables.sql

View File

@@ -0,0 +1 @@
../scripts-available/CDB_OAuth.sql

View File

@@ -0,0 +1 @@
../scripts-available/CDB_FederatedServer.sql

View File

@@ -0,0 +1 @@
../scripts-available/CDB_FederatedServerTables.sql

View File

@@ -0,0 +1 @@
../scripts-available/CDB_FederatedServerListRemote.sql

View File

@@ -0,0 +1 @@
../scripts-available/CDB_FederatedServerDiagnostics.sql

View File

@@ -0,0 +1 @@
../scripts-available/CDB_DDLTriggers.sql

View File

@@ -0,0 +1 @@
../scripts-available/CDB_Conf.sql

View File

@@ -0,0 +1 @@
../scripts-available/CDB_Username.sql

View File

@@ -0,0 +1 @@
../scripts-available/CDB_Groups.sql

View File

@@ -0,0 +1 @@
../scripts-available/CDB_Groups_API.sql

View File

@@ -0,0 +1 @@
../scripts-available/CDB_Stats.sql

View File

@@ -0,0 +1 @@
../scripts-available/CDB_SyncTable.sql

View File

@@ -1,102 +0,0 @@
\set VERBOSITY terse
-- Set user quota to infinite
SELECT CDB_SetUserQuotaInBytes(0);
-- Enable ddl triggers
SELECT cartodb.cdb_enable_ddl_hooks();
create schema c;
SELECT CDB_SetUserQuotaInBytes('c', 0);
DROP USER IF EXISTS cartodb_postgresql_unpriv_user;
CREATE USER cartodb_postgresql_unpriv_user;
GRANT ALL ON SCHEMA c to cartodb_postgresql_unpriv_user;
SET SESSION AUTHORIZATION 'cartodb_postgresql_unpriv_user';
--SELECT session_user, current_user;
----------------------
-- CREATE TABLE
----------------------
SET SESSION AUTHORIZATION 'cartodb_postgresql_unpriv_user';
select 1 as i INTO c.t3;
RESET SESSION AUTHORIZATION;
select
tabname::text,
round(extract('secs' from now() - updated_at)) as age
FROM CDB_TableMetadata WHERE tabname = 'c.t3'::regclass;
SET SESSION AUTHORIZATION 'cartodb_postgresql_unpriv_user';
-- Table with cartodb_id field, see
-- http://github.com/CartoDB/cartodb-postgresql/issues/32
select 1 as cartodb_id INTO c.t4;
RESET SESSION AUTHORIZATION;
select
tabname::text,
round(extract('secs' from now() - updated_at)) as age
FROM CDB_TableMetadata WHERE tabname = 'c.t4'::regclass;
----------------------------
-- ALTER TABLE RENAME COLUMN
----------------------------
SET SESSION AUTHORIZATION 'cartodb_postgresql_unpriv_user';
select pg_sleep(.1);
alter table c.t3 rename column the_geom_webmercator to webmerc;
RESET SESSION AUTHORIZATION;
select
tabname::text,
round(extract('secs' from now() - updated_at)*10) as agecs
FROM CDB_TableMetadata WHERE tabname = 'c.t3'::regclass;
SET SESSION AUTHORIZATION 'cartodb_postgresql_unpriv_user';
select pg_sleep(.1);
alter table c.t3 rename column the_geom_webmercator to webmerc2;
RESET SESSION AUTHORIZATION;
select
tabname::text,
round(extract('secs' from now() - updated_at)*10) as agecs
FROM CDB_TableMetadata WHERE tabname = 'c.t3'::regclass;
----------------------------
-- ALTER TABLE DROP COLUMN
----------------------------
SET SESSION AUTHORIZATION 'cartodb_postgresql_unpriv_user';
select pg_sleep(.1);
alter table c.t3 drop column the_geom_webmercator;
RESET SESSION AUTHORIZATION;
select
tabname::text,
round(extract('secs' from now() - updated_at)*10) as agecs
FROM CDB_TableMetadata WHERE tabname = 'c.t3'::regclass;
----------------------------
-- ALTER TABLE ADD COLUMN
----------------------------
SET SESSION AUTHORIZATION 'cartodb_postgresql_unpriv_user';
select pg_sleep(.1);
alter table c.t3 add column id2 int;
RESET SESSION AUTHORIZATION;
select
tabname::text,
round(extract('secs' from now() - updated_at)*10) as agecs
FROM CDB_TableMetadata WHERE tabname = 'c.t3'::regclass;
----------------------------
-- DROP TABLE
----------------------------
RESET SESSION AUTHORIZATION;
drop schema c cascade;
select count(*) from CDB_TableMetadata;
DROP OWNED BY cartodb_postgresql_unpriv_user;
DROP ROLE cartodb_postgresql_unpriv_user;
DROP FUNCTION _CDB_UserQuotaInBytes();

View File

@@ -1,10 +1,14 @@
\set ECHO none
\set QUIET on
SET client_min_messages TO error;
CREATE EXTENSION postgis;
CREATE EXTENSION schema_triggers;
CREATE EXTENSION plpythonu;
CREATE EXTENSION cartodb;
CREATE EXTENSION @@plpythonu@@;
CREATE SCHEMA cartodb;
\i 'cartodb--unpackaged--@@VERSION@@.sql'
CREATE FUNCTION public.cdb_invalidate_varnish(table_name text)
RETURNS void AS $$
BEGIN
RAISE NOTICE 'cdb_invalidate_varnish(%) called', table_name;
END;
$$ LANGUAGE 'plpgsql';
$$ LANGUAGE 'plpgsql';
\set QUIET off

1
sql/test_setup_expect Normal file
View File

@@ -0,0 +1 @@
\set ECHO none

View File

@@ -0,0 +1,20 @@
SET client_min_messages TO error;
\set VERBOSITY terse
SELECT CDB_SetUserQuotaInBytes(1000000);
SELECT _CDB_AnalysisTablesInSchema('public');
SELECT _CDB_AnalysisDataSize('public');
CREATE TABLE analysis_2f13a3dbd7_41bd92976fc6dd97072afe4ee450054f4c0715d5(id int);
CREATE TABLE analysis_2f13a3dbd7_f00cee44e9e6152b450bde3a92eb9ae0d099da94(id int);
CREATE TABLE analysis_2f13a3dbd7_f00cee44e9e6152b450bde3a92eb9ae0d099da9(id int);
SELECT _CDB_AnalysisTablesInSchema('public') t ORDER BY t;
SELECT _CDB_AnalysisDataSize('public');
SELECT CDB_CheckAnalysisQuota('analysis_2f13a3dbd7_f00cee44e9e6152b450bde3a92eb9ae0d099da94');
SELECT CDB_SetUserQuotaInBytes(1);
SELECT CDB_CheckAnalysisQuota('analysis_2f13a3dbd7_f00cee44e9e6152b450bde3a92eb9ae0d099da94');
INSERT INTO analysis_2f13a3dbd7_41bd92976fc6dd97072afe4ee450054f4c0715d5(id) VALUES (1),(2),(3),(4),(5);
SELECT CDB_CheckAnalysisQuota('analysis_2f13a3dbd7_f00cee44e9e6152b450bde3a92eb9ae0d099da94');
DROP TABLE analysis_2f13a3dbd7_41bd92976fc6dd97072afe4ee450054f4c0715d5;
DROP TABLE analysis_2f13a3dbd7_f00cee44e9e6152b450bde3a92eb9ae0d099da94;
DROP TABLE analysis_2f13a3dbd7_f00cee44e9e6152b450bde3a92eb9ae0d099da9;
DROP FUNCTION "public"._CDB_UserQuotaInBytes();

View File

@@ -0,0 +1,18 @@
SET
1000000
0
CREATE TABLE
CREATE TABLE
CREATE TABLE
(analysis_2f13a3dbd7_41bd92976fc6dd97072afe4ee450054f4c0715d5,public,analysis_2f13a3dbd7_41bd92976fc6dd97072afe4ee450054f4c0715d5)
(analysis_2f13a3dbd7_f00cee44e9e6152b450bde3a92eb9ae0d099da94,public,analysis_2f13a3dbd7_f00cee44e9e6152b450bde3a92eb9ae0d099da94)
0
1
INSERT 0 5
ERROR: Analysis cache space limits exceeded
DROP TABLE
DROP TABLE
DROP TABLE
DROP FUNCTION

View File

@@ -1,5 +1,5 @@
SET client_min_messages TO error;
\set VERBOSITY default
\set VERBOSITY terse
CREATE OR REPLACE FUNCTION CDB_CartodbfyTableCheck(tabname regclass, label text)
RETURNS text AS
@@ -16,8 +16,8 @@ DECLARE
BEGIN
-- Save current constraints on geometry columns, if any
ogc_geom = ('','','','',0,0,'GEOMETRY');
ogc_merc = ogc_geom;
ogc_geom = ('','','','',0,0,'GEOMETRY');
ogc_merc = ogc_geom;
sql := 'SELECT gc.* FROM geometry_columns gc, pg_class c, pg_namespace n '
|| 'WHERE c.oid = ' || tabname::oid || ' AND n.oid = c.relnamespace'
|| ' AND gc.f_table_schema = n.nspname AND gc.f_table_name = c.relname'
@@ -66,7 +66,7 @@ BEGIN
ELSE 3857 END as expsrid,
CASE WHEN gc.f_geometry_column = 'the_geom' THEN ogc_geom.type
ELSE ogc_merc.type END as exptype, gc.*
FROM geometry_columns gc, pg_class c, pg_namespace n
FROM geometry_columns gc, pg_class c, pg_namespace n
WHERE c.oid = tabname::oid AND n.oid = c.relnamespace
AND gc.f_table_schema = n.nspname AND gc.f_table_name = c.relname
AND gc.f_geometry_column IN ( 'the_geom', 'the_geom_webmercator')
@@ -88,7 +88,7 @@ BEGIN
RAISE EXCEPTION '% entries found for table % in geometry_columns, expected 2', tmp, tabname;
END IF;
-- Check GiST index
-- Check GiST index
sql := 'SELECT a.attname, count(ri.relname) FROM'
|| ' pg_index i, pg_class c, pg_class ri, pg_attribute a, pg_opclass o'
|| ' WHERE i.indrelid = c.oid AND ri.oid = i.indexrelid'
@@ -124,13 +124,21 @@ END;
$$
LANGUAGE 'plpgsql';
-- table with single non-geometrical column
-- check cartodbfytable idempotence
CREATE TABLE t AS SELECT 1::int as a;
SELECT CDB_CartodbfyTable('public', 't'); -- should fail
SELECT CDB_SetUserQuotaInBytes(0); -- Set user quota to infinite
SELECT CDB_CartodbfyTableCheck('t', 'single non-geometrical column');
DROP TABLE t;
-- table with single non-geometrical column
CREATE TABLE t AS SELECT ST_SetSRID(ST_MakePoint(-1,-1),4326) as the_geom, 1::int as cartodb_id, 'this is a sentence' as description;
SELECT CDB_CartodbfyTableCheck('t', 'check function idempotence');
SELECT cartodb_id, the_geom, description FROM t;
SELECT CDB_CartodbfyTableCheck('t', 'check function idempotence');
SELECT cartodb_id, the_geom, description FROM t;
DROP TABLE t;
-- table with existing srid-unconstrained (but type-constrained) the_geom
CREATE TABLE t AS SELECT ST_SetSRID(ST_MakePoint(0,0),4326)::geometry(point) as the_geom;
SELECT CDB_CartodbfyTableCheck('t', 'srid-unconstrained the_geom');
@@ -164,48 +172,51 @@ SELECT CDB_CartodbfyTableCheck('t', 'trigger-protected the_geom');
SELECT 'extent',ST_Extent(ST_SnapToGrid(the_geom,0.2)) FROM t;
DROP TABLE t;
-- INFO: disabled because cartodbfy does not longer consider text columns for primary ID
-- -- table with existing cartodb_id field of type text
-- CREATE TABLE t AS SELECT 10::text as cartodb_id;
-- SELECT CDB_CartodbfyTableCheck('t', 'text cartodb_id');
-- select cartodb_id/2 FROM t;
-- DROP TABLE t;
-- table with existing cartodb_id field of type text
CREATE TABLE t AS SELECT 10::text as cartodb_id;
SELECT CDB_CartodbfyTableCheck('t', 'text cartodb_id');
select cartodb_id/2 FROM t;
DROP TABLE t;
-- INFO: disabled because cartodbfy does not longer consider text columns for primary ID
-- -- table with existing cartodb_id field of type text not casting
-- CREATE TABLE t AS SELECT 'nan' as cartodb_id;
-- SELECT CDB_CartodbfyTableCheck('t', 'uncasting text cartodb_id');
-- select cartodb_id,_cartodb_id0 FROM t;
-- DROP TABLE t;
-- table with existing cartodb_id field of type text not casting
CREATE TABLE t AS SELECT 'nan'::text as cartodb_id;
SELECT CDB_CartodbfyTableCheck('t', 'uncasting text cartodb_id');
DROP TABLE t;
-- table with empty cartodb_id field of type text
CREATE TABLE t AS SELECT null::text as cartodb_id;
SELECT CDB_CartodbfyTableCheck('t', 'empty text cartodb_id');
SELECT cartodb_id from t;
DROP TABLE t;
-- table with existing cartodb_id field of type int4 not sequenced
CREATE TABLE t AS SELECT 1::int4 as cartodb_id;
SELECT CDB_CartodbfyTableCheck('t', 'unsequenced cartodb_id');
SELECT cartodb_id FROM t;
SELECT cartodb_id FROM t;
DROP TABLE t;
-- table with text geometry column
CREATE TABLE t AS SELECT 'SRID=4326;POINT(1 1)'::text AS the_geom, 1::int4 as cartodb_id;
SELECT CDB_CartodbfyTableCheck('t', 'text the_geom column');
SELECT cartodb_id FROM t;
SELECT cartodb_id FROM t;
DROP TABLE t;
-- table with text geometry column, no SRS
CREATE TABLE t AS SELECT 'POINT(1 1)'::text AS the_geom, 1::int4 as cartodb_id;
SELECT CDB_CartodbfyTableCheck('t', 'text the_geom column, no srs');
SELECT cartodb_id FROM t;
SELECT cartodb_id FROM t;
DROP TABLE t;
-- table with text geometry column, unusual SRS
CREATE TABLE t AS SELECT 'SRID=26910;POINT(1 1)'::text AS the_geom, 1::int4 as cartodb_id;
SELECT CDB_CartodbfyTableCheck('t', 'text the_geom column, srs = 26819');
SELECT cartodb_id FROM t;
SELECT cartodb_id FROM t;
DROP TABLE t;
-- table with text unparseable geometry column
CREATE TABLE t AS SELECT 'SRID=26910;PONT(1 1)'::text AS the_geom, 1::int4 as cartodb_id;
SELECT CDB_CartodbfyTableCheck('t', 'text the_geom column, unparseable content');
SELECT cartodb_id FROM t;
SELECT cartodb_id FROM t;
DROP TABLE t;
-- table with existing cartodb_id serial primary key
@@ -225,6 +236,160 @@ SELECT CDB_CartodbfyTable('original');
DROP TABLE original_renamed;
DROP TABLE original;
-- Table always have a default seq value after cartodbfy #138
CREATE TABLE bug_empty_table_no_seq (
cartodb_id integer,
the_geom geometry(Geometry,4326),
the_geom_webmercator geometry(Geometry,3857),
name text,
description text
);
SELECT CDB_CartodbfyTableCheck('bug_empty_table_no_seq', 'Table always have a default seq value after cartodbfy #138');
INSERT INTO bug_empty_table_no_seq DEFAULT VALUES;
DROP TABLE bug_empty_table_no_seq;
-- Existing cartodb_id values are respected
CREATE table existing_cartodb_id (
cartodb_id integer,
the_geom geometry(Geometry,4326),
the_geom_webmercator geometry(Geometry,3857),
name text,
description text
);
INSERT INTO existing_cartodb_id (cartodb_id, description) VALUES
(10, 'a'),
(20, 'b'),
(30, 'c');
SELECT CDB_CartodbfyTableCheck('existing_cartodb_id', 'Existing cartodb_id values are respected #138');
SELECT cartodb_id,the_geom,the_geom_webmercator,description,name from existing_cartodb_id;
DROP TABLE existing_cartodb_id;
-- Table with both the_geom and wkb_geometry
CREATE TABLE many_geometry_columns (
the_geom geometry,
wkb_geometry geometry(MultiPoint,4326),
description varchar
);
INSERT INTO many_geometry_columns (the_geom, wkb_geometry) VALUES
('0104000020E61000000100000001010000007108B023698052C03CEEA53A2E5D4440', '0104000020E61000000100000001010000007108B023698052C03CEEA53A2E5D4440'),
('0104000020E6100000010000000101000000864C9E57618052C0994F0C7F3C5B4440', '0104000020E6100000010000000101000000864C9E57618052C0994F0C7F3C5B4440');
SELECT CDB_CartodbfyTableCheck('many_geometry_columns', 'Table with both the_geom and wkb_geometry #141');
SELECT * FROM many_geometry_columns;
DROP TABLE many_geometry_columns;
-- Many colliding geom columns
CREATE TABLE many_colliding_columns (
the_geom varchar,
the_geom_webmercator varchar,
my_geom geometry,
my_mercgeom geometry(Point, 3857),
cartodb_id varchar,
my_pk integer primary key
);
INSERT INTO many_colliding_columns VALUES (
'foo', 'bar', 'SRID=4326;POINT(0 0)', 'SRID=3857;POINT(0 0)', 'nerf', 1
);
SELECT CDB_CartodbfyTableCheck('many_colliding_columns', 'Many colliding columns #141');
DROP TABLE many_colliding_columns;
-- Table with null cartodb_id
CREATE TABLE test (
cartodb_id integer
);
INSERT INTO test VALUES
(1),
(2),
(NULL),
(3);
SELECT CDB_CartodbfyTableCheck('test', 'Table with null cartodb_id #148');
SELECT cartodb_id from test;
DROP TABLE test;
-- Table with non unique cartodb_id
CREATE TABLE test (
cartodb_id integer
);
INSERT INTO test VALUES
(1),
(2),
(2);
SELECT CDB_CartodbfyTableCheck('test', 'Table with non unique cartodb_id #148');
SELECT cartodb_id from test;
DROP TABLE test;
-- Table with non unique and null cartodb_id
CREATE TABLE test (
cartodb_id integer
);
INSERT INTO test VALUES
(1),
(2),
(NULL),
(2);
SELECT CDB_CartodbfyTableCheck('test', 'Table with non unique and null cartodb_id #148');
SELECT cartodb_id from test;
DROP TABLE test;
CREATE TABLE test (
cartodb_id integer
);
CREATE UNIQUE INDEX "test_cartodb_id_key" ON test (cartodb_id);
CREATE UNIQUE INDEX "test_cartodb_id_pkey" ON test (cartodb_id);
ALTER TABLE test ADD CONSTRAINT "test_pkey" PRIMARY KEY USING INDEX test_cartodb_id_pkey;
INSERT INTO test VALUES
(1),
(2),
(3);
SELECT CDB_CartodbfyTableCheck('test', 'Table with primary key and unique index on it #174');
SELECT cartodb_id from test;
DROP TABLE test;
CREATE TABLE test (
name varchar,
"first.value" integer,
"second.value" integer
);
INSERT INTO test VALUES ('one', 1, 2), ('two', 3, 4);
SELECT CDB_CartodbfyTableCheck('test', 'Table with dots in name columns (cartodb #6114)');
SELECT name, "first.value" from test;
DROP TABLE test;
SET client_min_messages TO notice;
-- _CDB_create_cartodb_id_column with cartodb_id integer already present
CREATE TABLE test (cartodb_id integer);
SELECT _CDB_Create_Cartodb_ID_Column('test'::regclass);
SELECT column_name FROM information_schema.columns WHERE table_name = 'test' AND column_name = '_cartodb_id0';
DROP TABLE test;
-- _CDB_create_cartodb_id_column with cartodb_id text already present
CREATE TABLE test (cartodb_id text);
SELECT _CDB_Create_Cartodb_ID_Column('test'::regclass);
SELECT column_name FROM information_schema.columns WHERE table_name = 'test' AND column_name = '_cartodb_id0';
DROP TABLE test;
SET client_min_messages TO error;
-- Unique identifier generation can break CDB_CartodbfyTable #305
BEGIN;
DO $$
BEGIN
FOR i IN 1..150 LOOP
EXECUTE 'CREATE TABLE untitled_table();';
EXECUTE $query$SELECT CDB_CartodbfyTable('untitled_table');$query$;
EXECUTE 'ALTER TABLE untitled_table RENAME TO my_renamed_table_' || i;
END LOOP;
END;
$$;
ROLLBACK;
-- Long table name could cause possible sequence rename collision #325
CREATE TABLE "wadus_table_9473e8f6-2da1-11e8-8bca-0204e4dfe4d8" ( cartodb_id serial primary key );
SELECT CDB_CartodbfyTableCheck('wadus_table_9473e8f6-2da1-11e8-8bca-0204e4dfe4d8'::REGCLASS, 'Long table name could cause sequence collision while renaming #325');
DROP TABLE "wadus_table_9473e8f6-2da1-11e8-8bca-0204e4dfe4d8";
-- TODO: table with existing custom-triggered the_geom
DROP FUNCTION CDB_CartodbfyTableCheck(regclass, text);

View File

@@ -2,12 +2,16 @@ SET
CREATE FUNCTION
SELECT 1
ERROR: Please set user quota before cartodbfying tables.
CONTEXT: SQL statement "SELECT cartodb._CDB_check_prerequisites(destschema, reloid)"
PL/pgSQL function cdb_cartodbfytable(text,regclass) line 21 at PERFORM
0
single non-geometrical column cartodbfied fine
DROP TABLE
SELECT 1
check function idempotence cartodbfied fine
1|0101000020E6100000000000000000F0BF000000000000F0BF|this is a sentence
check function idempotence cartodbfied fine
1|0101000020E6100000000000000000F0BF000000000000F0BF|this is a sentence
DROP TABLE
SELECT 1
srid-unconstrained the_geom cartodbfied fine
DROP TABLE
SELECT 2
@@ -26,6 +30,17 @@ SELECT 1
CREATE TRIGGER
trigger-protected the_geom cartodbfied fine
extent|BOX(1 1,2 2)
DROP TABLE
SELECT 1
text cartodb_id cartodbfied fine
5
DROP TABLE
SELECT 1
ERROR: CDB(_CDB_Has_Usable_Primary_ID: Error: invalid cartodb_id, cartodb_id): ALTER TABLE t ADD CONSTRAINT cartodb_id_pk PRIMARY KEY (cartodb_id), ADD CONSTRAINT cartodb_id_integer CHECK (cartodb_id::integer >=0);
DROP TABLE
SELECT 1
ERROR: CDB(_CDB_Has_Usable_Primary_ID: Error: invalid cartodb_id, cartodb_id): ALTER TABLE t ADD CONSTRAINT cartodb_id_pk PRIMARY KEY (cartodb_id), ADD CONSTRAINT cartodb_id_integer CHECK (cartodb_id::integer >=0);
DROP TABLE
SELECT 1
unsequenced cartodb_id cartodbfied fine
@@ -58,5 +73,85 @@ CREATE TABLE
original
DROP TABLE
DROP TABLE
CREATE TABLE
Table always have a default seq value after cartodbfy #138 cartodbfied fine
INSERT 0 1
DROP TABLE
CREATE TABLE
INSERT 0 3
Existing cartodb_id values are respected #138 cartodbfied fine
10|||a|
20|||b|
30|||c|
DROP TABLE
CREATE TABLE
INSERT 0 2
Table with both the_geom and wkb_geometry #141 cartodbfied fine
1|0104000020E61000000100000001010000007108B023698052C03CEEA53A2E5D4440|0104000020110F00000100000001010000004A9F662B456D5FC11392690DC3F75241|
2|0104000020E6100000010000000101000000864C9E57618052C0994F0C7F3C5B4440|0104000020110F00000100000001010000002858E0EC376D5FC1CAE8DB4B95F55241|
DROP TABLE
CREATE TABLE
INSERT 0 1
ERROR: CDB(_CDB_Has_Usable_Primary_ID: multiple primary keys for table "many_colliding_columns" are not allowed): ALTER TABLE many_colliding_columns ADD CONSTRAINT cartodb_id_pk PRIMARY KEY (cartodb_id), ADD CONSTRAINT cartodb_id_integer CHECK (cartodb_id::integer >=0);
DROP TABLE
CREATE TABLE
INSERT 0 4
ERROR: CDB(_CDB_Has_Usable_Primary_ID: Error: invalid cartodb_id, cartodb_id): ALTER TABLE test ADD CONSTRAINT cartodb_id_pk PRIMARY KEY (cartodb_id), ADD CONSTRAINT cartodb_id_integer CHECK (cartodb_id::integer >=0);
1
2
3
DROP TABLE
CREATE TABLE
INSERT 0 3
ERROR: CDB(_CDB_Has_Usable_Primary_ID: Error: invalid cartodb_id, cartodb_id): ALTER TABLE test ADD CONSTRAINT cartodb_id_pk PRIMARY KEY (cartodb_id), ADD CONSTRAINT cartodb_id_integer CHECK (cartodb_id::integer >=0);
1
2
2
DROP TABLE
CREATE TABLE
INSERT 0 4
ERROR: CDB(_CDB_Has_Usable_Primary_ID: Error: invalid cartodb_id, cartodb_id): ALTER TABLE test ADD CONSTRAINT cartodb_id_pk PRIMARY KEY (cartodb_id), ADD CONSTRAINT cartodb_id_integer CHECK (cartodb_id::integer >=0);
1
2
2
DROP TABLE
CREATE TABLE
CREATE INDEX
CREATE INDEX
ALTER TABLE
INSERT 0 3
Table with primary key and unique index on it #174 cartodbfied fine
1
2
3
DROP TABLE
CREATE TABLE
INSERT 0 2
Table with dots in name columns (cartodb #6114) cartodbfied fine
one|1
two|3
DROP TABLE
SET
CREATE TABLE
NOTICE: Column cartodb_id already exists
NOTICE: Existing cartodb_id field does not have an associated sequence, renaming
NOTICE: Trying to recover data from _cartodb_id0 column
DROP TABLE
CREATE TABLE
NOTICE: Column cartodb_id already exists
NOTICE: Existing cartodb_id field is of invalid type text (need int2, int4 or int8), renaming
NOTICE: Trying to recover data from _cartodb_id0 column
DROP TABLE
SET
BEGIN
DO
ROLLBACK
CREATE TABLE
Long table name could cause sequence collision while renaming #325 cartodbfied fine
DROP TABLE
DROP FUNCTION
DROP FUNCTION

Some files were not shown because too many files have changed in this diff Show More