Compare commits

..

165 Commits

Author SHA1 Message Date
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
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
Rafa de la Torre
a5ccbdddcf Update version to 0.9.4 in Makefile #123 2015-08-27 16:47:10 +02:00
Rafa de la Torre
45383d7c8a Merge pull request #127 from CartoDB/123-fix-indices
Fix for index generation when renaming table #123
2015-08-27 16:44:19 +02:00
Rafa de la Torre
0057e2ddec Fix for index generation when renaming table #123 2015-08-27 16:33:46 +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
26 changed files with 1162 additions and 119 deletions

3
.gitignore vendored
View File

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

View File

@@ -1,7 +1,7 @@
# cartodb/Makefile
EXTENSION = cartodb
EXTVERSION = 0.9.3
EXTVERSION = 0.11.0
SED = sed
@@ -46,6 +46,11 @@ UPGRADABLE = \
0.9.1 \
0.9.2 \
0.9.3 \
0.9.4 \
0.10.0 \
0.10.1 \
0.10.2 \
0.11.0 \
$(EXTVERSION)dev \
$(EXTVERSION)next \
$(END)

30
NEWS.md
View File

@@ -1,3 +1,33 @@
next (2015-mm-dd)
-----------------
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)
0.9.3 (2015-08-27)
------------------
* Modify sampling of quota trigger [#126](https://github.com/CartoDB/cartodb-postgresql/issues/126)

View File

@@ -98,3 +98,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).

View File

@@ -91,6 +91,7 @@ select pg_sleep(.1);
(1 row)
alter table c.t3 rename column the_geom_webmercator to webmerc;
NOTICE: column "the_geom_webmercator" of relation "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
@@ -115,6 +116,7 @@ select pg_sleep(.1);
(1 row)
alter table c.t3 rename column the_geom_webmercator to webmerc2;
NOTICE: column "the_geom_webmercator" of relation "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

View File

@@ -280,6 +280,16 @@ BEGIN
END;
$$ LANGUAGE plpgsql VOLATILE;
--- Trigger to update the updated_at column. No longer added by default
--- but kept here for compatibility with old tables which still have this behavior
--- and have it added
CREATE OR REPLACE FUNCTION _CDB_update_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at := now();
RETURN NEW;
END;
$$ LANGUAGE plpgsql VOLATILE;
-- Auxiliary function
CREATE OR REPLACE FUNCTION cartodb._CDB_is_raster_table(schema_name TEXT, reloid REGCLASS)
@@ -497,30 +507,6 @@ BEGIN
END;
$$ LANGUAGE 'plpgsql';
-- Return the geometry SRID from the column metadata or
-- the geometry of the very first entry in a given column.
CREATE OR REPLACE FUNCTION _CDB_Geometry_SRID(reloid REGCLASS, columnname TEXT)
RETURNS INTEGER
AS $$
DECLARE
rec RECORD;
BEGIN
RAISE DEBUG 'CDB(%): %', '_CDB_Geometry_SRID', 'entered function';
EXECUTE Format('SELECT ST_SRID(%I) AS srid FROM %s LIMIT 1', columnname, reloid::text)
INTO rec;
IF FOUND THEN
RETURN rec.srid;
END IF;
RETURN 0;
END;
$$ LANGUAGE 'plpgsql';
-- Find out if the table already has a usable primary key
@@ -654,9 +640,72 @@ END;
$$ LANGUAGE 'plpgsql';
DROP FUNCTION IF EXISTS _CDB_Has_Usable_Geom(regclass);
CREATE OR REPLACE FUNCTION _CDB_Has_Usable_PK_Sequence(reloid REGCLASS)
RETURNS BOOLEAN
AS $$
DECLARE
seq TEXT;
const RECORD;
has_sequence BOOLEAN = false;
BEGIN
const := _CDB_Columns();
SELECT pg_get_serial_sequence(reloid::text, const.pkey)
INTO STRICT seq;
has_sequence := seq IS NOT NULL;
RETURN has_sequence;
END;
$$ LANGUAGE 'plpgsql';
-- Return a set of columns that can be candidates to be the_geom[webmercator]
-- with some extra information to analyze them.
CREATE OR REPLACE FUNCTION _cdb_geom_candidate_columns(reloid REGCLASS)
RETURNS TABLE (attname name, srid integer, typname name, desired_attname text, desired_srid integer)
AS $$
DECLARE
const RECORD;
BEGIN
const := _CDB_Columns();
RETURN QUERY
SELECT
a.attname,
CASE WHEN t.typname = 'geometry' THEN postgis_typmod_srid(a.atttypmod) ELSE NULL END AS srid,
t.typname,
f.desired_attname, f.desired_srid
FROM pg_class c
JOIN pg_attribute a ON a.attrelid = c.oid
JOIN pg_type t ON a.atttypid = t.oid,
(VALUES (const.geomcol, 4326), (const.mercgeomcol, 3857) ) as f(desired_attname, desired_srid)
WHERE c.oid = reloid
AND a.attnum > 0
AND NOT a.attisdropped
AND postgis_typmod_srid(a.atttypmod) IN (4326, 3857, 0)
ORDER BY t.oid ASC;
END;
$$ LANGUAGE 'plpgsql';
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = '_cdb_has_usable_geom_record') THEN
CREATE TYPE _cdb_has_usable_geom_record
AS (has_usable_geoms boolean,
text_geom_column boolean,
text_geom_column_name text,
text_geom_column_srid boolean,
has_geom boolean,
has_geom_name text,
has_mercgeom boolean,
has_mercgeom_name text);
END IF;
END$$;
DROP FUNCTION IF EXISTS _CDB_Has_Usable_Geom(REGCLASS);
CREATE OR REPLACE FUNCTION _CDB_Has_Usable_Geom(reloid REGCLASS)
RETURNS RECORD
RETURNS _cdb_has_usable_geom_record
AS $$
DECLARE
r1 RECORD;
@@ -688,20 +737,7 @@ BEGIN
-- Do we have a column we can use?
FOR r1 IN
SELECT
a.attname,
CASE WHEN t.typname = 'geometry' THEN postgis_typmod_srid(a.atttypmod) ELSE NULL END AS srid,
t.typname,
f.desired_attname, f.desired_srid
FROM pg_class c
JOIN pg_attribute a ON a.attrelid = c.oid
JOIN pg_type t ON a.atttypid = t.oid,
(VALUES (const.geomcol, 4326), (const.mercgeomcol, 3857) ) as f(desired_attname, desired_srid)
WHERE c.oid = reloid
AND a.attnum > 0
AND NOT a.attisdropped
AND postgis_typmod_srid(a.atttypmod) IN (4326, 3857, 0)
ORDER BY t.oid ASC
SELECT * FROM _cdb_geom_candidate_columns(reloid)
LOOP
RAISE DEBUG 'CDB(_CDB_Has_Usable_Geom): %', Format('checking column ''%s''', r1.attname);
@@ -756,7 +792,7 @@ BEGIN
-- If it's the right SRID, we can use it in place without
-- transforming it!
IF r1.srid = r1.desired_srid OR _CDB_Geometry_SRID(reloid, r1.attname) = r1.desired_srid THEN
IF r1.srid = r1.desired_srid THEN
RAISE DEBUG 'CDB(_CDB_Has_Usable_Geom): %', Format('found acceptable ''%s''', r1.attname);
@@ -769,7 +805,7 @@ BEGIN
END IF;
-- If it's an unknown SRID, we need to know that too
ELSIF r1.srid = 0 OR _CDB_Geometry_SRID(reloid, r1.attname) = 0 THEN
ELSIF r1.srid = 0 THEN
-- Unknown SRID, we'll have to fill it in later
text_geom_column_srid := true;
@@ -780,23 +816,13 @@ BEGIN
END LOOP;
-- If geom is the wrong name, just rename it.
IF has_geom AND has_geom_name != const.geomcol THEN
sql := Format('ALTER TABLE %s RENAME COLUMN %s TO %s', reloid::text, has_geom_name, const.geomcol);
PERFORM _CDB_SQL(sql,'_CDB_Has_Usable_Geom');
END IF;
-- If mercgeom is the wrong name, just rename it.
IF has_mercgeom AND has_mercgeom_name != const.mercgeomcol THEN
sql := Format('ALTER TABLE %s RENAME COLUMN %s TO %s', reloid::text, has_mercgeom_name, const.mercgeomcol);
PERFORM _CDB_SQL(sql,'_CDB_Has_Usable_Geom');
END IF;
SELECT
-- If table is perfect (no transforms required), return TRUE!
has_geom AND has_mercgeom AS has_usable_geoms,
-- If the geometry column is hiding in a text field, return enough info to deal w/ it.
text_geom_column, text_geom_column_name, text_geom_column_srid
text_geom_column, text_geom_column_name, text_geom_column_srid,
-- Return enough info to rename geom columns if needed
has_geom, has_geom_name, has_mercgeom, has_mercgeom_name
INTO rv;
RAISE DEBUG 'CDB(_CDB_Has_Usable_Geom): %', Format('returning %s', rv);
@@ -806,6 +832,7 @@ BEGIN
END;
$$ LANGUAGE 'plpgsql';
-- Create a copy of the table. Assumes that the "Has usable" functions
-- have already been run, so that if there is a 'cartodb_id' column, it is
-- a "good" one, and the same for the geometry columns. If all the required
@@ -840,6 +867,7 @@ DECLARE
geom_srid INTEGER;
has_usable_primary_key BOOLEAN;
has_usable_pk_sequence BOOLEAN;
BEGIN
@@ -867,35 +895,58 @@ BEGIN
RAISE DEBUG 'CDB(_CDB_Rewrite_Table): has_usable_primary_key %', has_usable_primary_key;
-- See if the candidate primary key column has a sequence for default
-- values. No usable pk implies has_usable_pk_sequence = false.
has_usable_pk_sequence := false;
IF has_usable_primary_key THEN
SELECT _CDB_Has_Usable_PK_Sequence(reloid)
INTO STRICT has_usable_pk_sequence;
END IF;
-- See if the geometry columns we need are already available
-- on the table. If they are, we don't need to do any bulk
-- transformation of the table, we can just ensure proper
-- indexes are in place and apply a rename
SELECT *
FROM _CDB_Has_Usable_Geom(reloid)
AS (has_usable_geoms boolean,
text_geom_column boolean,
text_geom_column_name text,
text_geom_column_srid boolean)
INTO STRICT gc;
-- If geom is the wrong name, just rename it.
IF gc.has_geom AND gc.has_geom_name != const.geomcol THEN
sql := Format('ALTER TABLE %s DROP COLUMN IF EXISTS %I', reloid::text, const.geomcol);
PERFORM _CDB_SQL(sql,'_CDB_Rewrite_Table');
sql := Format('ALTER TABLE %s RENAME COLUMN %I TO %I', reloid::text, gc.has_geom_name, const.geomcol);
PERFORM _CDB_SQL(sql,'_CDB_Rewrite_Table');
END IF;
-- If mercgeom is the wrong name, just rename it.
IF gc.has_mercgeom AND gc.has_mercgeom_name != const.mercgeomcol THEN
sql := Format('ALTER TABLE %s DROP COLUMN IF EXISTS %I', reloid::text, const.mercgeomcol);
PERFORM _CDB_SQL(sql,'_CDB_Rewrite_Table');
sql := Format('ALTER TABLE %s RENAME COLUMN %I TO %I', reloid::text, gc.has_mercgeom_name, const.mercgeomcol);
PERFORM _CDB_SQL(sql,'_CDB_Rewrite_Table');
END IF;
RAISE DEBUG 'CDB(_CDB_Rewrite_Table): has_usable_geoms %', gc.has_usable_geoms;
-- We can only avoid a rewrite if both the key and
-- geometry are usable
-- No table re-write is required, BUT a rename is required to
-- No table re-write is required, BUT a rename is required to
-- a destination schema, so do that now
IF has_usable_primary_key AND gc.has_usable_geoms AND destschema != relschema THEN
RAISE DEBUG 'CDB(_CDB_Rewrite_Table): perfect table needs to be moved to schema (%)', destschema;
PERFORM _CDB_SQL(Format('ALTER TABLE %s SET SCHEMA %I', reloid::text, destschema), '_CDB_Rewrite_Table');
RETURN true;
IF has_usable_primary_key AND has_usable_pk_sequence AND gc.has_usable_geoms THEN
IF destschema != relschema THEN
-- Don't move anything, just make sure our destination information is set right
ELSIF has_usable_primary_key AND gc.has_usable_geoms AND destschema = relschema THEN
RAISE DEBUG 'CDB(_CDB_Rewrite_Table): perfect table needs to be moved to schema (%)', destschema;
PERFORM _CDB_SQL(Format('ALTER TABLE %s SET SCHEMA %I', reloid::text, destschema), '_CDB_Rewrite_Table');
ELSE
RAISE DEBUG 'CDB(_CDB_Rewrite_Table): perfect table in the perfect place';
END IF;
RAISE DEBUG 'CDB(_CDB_Rewrite_Table): perfect table in the perfect place';
RETURN true;
END IF;
@@ -1029,15 +1080,11 @@ BEGIN
)
SELECT ', ST_Transform('
|| t.missing_srid_start || t.attname || t.missing_srid_end
|| ',4326)::Geometry('
|| t.geomtype
|| ',4326) AS '
|| ',4326)::Geometry(GEOMETRY,4326) AS '
|| const.geomcol
|| ', cartodb.CDB_TransformToWebmercator('
|| t.missing_srid_start || t.attname || t.missing_srid_end
|| ')::Geometry('
|| t.geomtype
|| ',3857) AS '
|| ')::Geometry(GEOMETRY,3857) AS '
|| const.mercgeomcol,
t.attname
INTO geom_transform_sql, geom_column_source
@@ -1094,27 +1141,24 @@ BEGIN
-- Set up the primary key sequence
-- If we copied the primary key from the original data, we need
-- to set the sequence to the maximum value of that key
IF has_usable_primary_key THEN
EXECUTE Format('SELECT max(%s) FROM %s',
const.pkey, copyname)
INTO destseqmax;
IF FOUND AND destseqmax IS NOT NULL THEN
PERFORM _CDB_SQL(Format('SELECT setval(''%s'', %s)', destseq, destseqmax), '_CDB_Rewrite_Table');
END IF;
EXECUTE Format('SELECT max(%s) FROM %s',
const.pkey, copyname)
INTO destseqmax;
IF destseqmax IS NOT NULL THEN
PERFORM _CDB_SQL(Format('SELECT setval(''%s'', %s)', destseq, destseqmax), '_CDB_Rewrite_Table');
END IF;
-- Make the primary key use the sequence as its default value
sql := Format('ALTER TABLE %s ALTER COLUMN %s SET DEFAULT nextval(''%s'')',
-- Make the primary key use the sequence as its default value
sql := Format('ALTER TABLE %s ALTER COLUMN %s SET DEFAULT nextval(''%s'')',
copyname, const.pkey, destseq);
PERFORM _CDB_SQL(sql, '_CDB_Rewrite_Table');
-- Make the sequence owned by the table, so when the table drops,
-- Make the sequence owned by the table, so when the table drops,
-- the sequence does too
sql := Format('ALTER SEQUENCE %s OWNED BY %s.%s', destseq, copyname, const.pkey);
PERFORM _CDB_SQL(sql,'_CDB_Rewrite_Table');
-- We just made a copy, so we can drop the original now
sql := Format('DROP TABLE %s', reloid::text);
@@ -1234,7 +1278,7 @@ BEGIN
AND c.oid = reloid
AND am.amname != 'gist'
LOOP
sql := Format('CREATE INDEX %s_%s_gix ON %s USING GIST (%s)', relname, rec.attname, reloid::text, rec.attname);
sql := Format('CREATE INDEX ON %s USING GIST (%s)', reloid::text, rec.attname);
PERFORM _CDB_SQL(sql, '_CDB_Add_Indexes');
END LOOP;

View File

@@ -3,11 +3,12 @@ CREATE OR REPLACE FUNCTION 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 || '';
SELECT c.column_name
FROM information_schema.columns c, pg_class _tn, pg_namespace _sn
WHERE table_name = _tn.relname
AND table_schema = _sn.nspname
AND _tn.oid = $1::oid
AND _sn.oid = _tn.relnamespace;
$$ LANGUAGE SQL;

View File

@@ -3,12 +3,13 @@ CREATE OR REPLACE FUNCTION 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) || '';
SELECT c.data_type
FROM information_schema.columns c, pg_class _tn, pg_namespace _sn
WHERE table_name = _tn.relname
AND table_schema = _sn.nspname
AND column_name = $2
AND _tn.oid = $1::oid
AND _sn.oid = _tn.relnamespace;
$$ LANGUAGE SQL;

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 cartodb.CDB_CONF already exists
DO LANGUAGE 'plpgsql' $$
BEGIN
CREATE TABLE IF NOT EXISTS cartodb.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('cartodb.CDB_CONF', '');
END
$$;
CREATE OR REPLACE
FUNCTION cartodb.CDB_Conf_SetConf(key text, value JSON)
RETURNS void AS $$
BEGIN
PERFORM cartodb.CDB_Conf_RemoveConf(key);
EXECUTE 'INSERT INTO cartodb.CDB_CONF (KEY, VALUE) VALUES ($1, $2);' USING key, value;
END
$$ LANGUAGE PLPGSQL VOLATILE;
CREATE OR REPLACE
FUNCTION cartodb.CDB_Conf_RemoveConf(key text)
RETURNS void AS $$
BEGIN
EXECUTE 'DELETE FROM cartodb.CDB_CONF WHERE KEY = $1;' USING key;
END
$$ LANGUAGE PLPGSQL VOLATILE;
CREATE OR REPLACE
FUNCTION cartodb.CDB_Conf_GetConf(key text)
RETURNS JSON AS $$
DECLARE
value JSON;
BEGIN
EXECUTE 'SELECT VALUE FROM cartodb.CDB_CONF WHERE KEY = $1;' INTO value USING key;
RETURN value;
END
$$ LANGUAGE PLPGSQL STABLE;

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 cartodb.CDB_Group_CreateGroup(group_name text)
RETURNS VOID AS $$
DECLARE
group_role TEXT;
BEGIN
group_role := cartodb._CDB_Group_GroupRole(group_name);
EXECUTE format('CREATE ROLE %I NOLOGIN;', group_role);
PERFORM cartodb._CDB_Group_CreateGroup_API(group_name, group_role);
END
$$ LANGUAGE PLPGSQL VOLATILE;
-- 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 cartodb.CDB_Group_DropGroup(group_name text)
RETURNS VOID AS $$
DECLARE
group_role TEXT;
BEGIN
group_role := cartodb._CDB_Group_GroupRole(group_name);
EXECUTE format('DROP OWNED BY %I', group_role);
EXECUTE format('DROP ROLE IF EXISTS %I', group_role);
PERFORM cartodb._CDB_Group_DropGroup_API(group_name);
END
$$ LANGUAGE PLPGSQL VOLATILE;
-- Renames a group
CREATE OR REPLACE
FUNCTION cartodb.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 = cartodb._CDB_Group_GroupRole(old_group_name);
new_group_role = cartodb._CDB_Group_GroupRole(new_group_name);
EXECUTE format('ALTER ROLE %I RENAME TO %I', old_group_role, new_group_role);
PERFORM cartodb._CDB_Group_RenameGroup_API(old_group_name, new_group_name, new_group_role);
END
$$ LANGUAGE PLPGSQL VOLATILE;
-- Adds users to a group
CREATE OR REPLACE
FUNCTION cartodb.CDB_Group_AddUsers(group_name text, usernames text[])
RETURNS VOID AS $$
DECLARE
group_role TEXT;
user_role TEXT;
username TEXT;
BEGIN
group_role := cartodb._CDB_Group_GroupRole(group_name);
foreach username in array usernames
loop
user_role := cartodb._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 cartodb._CDB_Group_AddUsers_API(group_name, usernames);
END
$$ LANGUAGE PLPGSQL VOLATILE;
-- Removes users from a group
CREATE OR REPLACE
FUNCTION cartodb.CDB_Group_RemoveUsers(group_name text, usernames text[])
RETURNS VOID AS $$
DECLARE
group_role TEXT;
user_role TEXT;
username TEXT;
BEGIN
group_role := cartodb._CDB_Group_GroupRole(group_name);
foreach username in array usernames
loop
user_role := cartodb._CDB_User_RoleFromUsername(username);
EXECUTE format('REVOKE %I FROM %I', group_role, user_role);
end loop;
PERFORM cartodb._CDB_Group_RemoveUsers_API(group_name, usernames);
END
$$ LANGUAGE PLPGSQL VOLATILE;
----------------------------------
-- TABLE MANAGEMENT FUNCTIONS
--
-- Meant to be used by table owners.
----------------------------------
-- Grants table read permission to a group
CREATE OR REPLACE
FUNCTION cartodb.CDB_Group_Table_GrantRead(group_name text, username text, table_name text)
RETURNS VOID AS $$
DECLARE
group_role TEXT;
BEGIN
PERFORM cartodb._CDB_Group_Table_GrantRead(group_name, username, table_name, true);
END
$$ LANGUAGE PLPGSQL VOLATILE;
CREATE OR REPLACE
FUNCTION cartodb._CDB_Group_Table_GrantRead(group_name text, username text, table_name text, sync boolean)
RETURNS VOID AS $$
DECLARE
group_role TEXT;
BEGIN
group_role := cartodb._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 cartodb._CDB_Group_Table_GrantPermission_API(group_name, username, table_name, 'r');
END IF;
END
$$ LANGUAGE PLPGSQL VOLATILE;
-- Grants table write permission to a group
CREATE OR REPLACE
FUNCTION cartodb.CDB_Group_Table_GrantReadWrite(group_name text, username text, table_name text)
RETURNS VOID AS $$
DECLARE
group_role TEXT;
BEGIN
PERFORM cartodb._CDB_Group_Table_GrantReadWrite(group_name, username, table_name, true);
END
$$ LANGUAGE PLPGSQL VOLATILE;
CREATE OR REPLACE
FUNCTION cartodb._CDB_Group_Table_GrantReadWrite(group_name text, username text, table_name text, sync boolean)
RETURNS VOID AS $$
DECLARE
group_role TEXT;
BEGIN
group_role := cartodb._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 cartodb._CDB_Group_TableSequences_Permission(group_name, username, table_name, true);
IF(sync) THEN
PERFORM cartodb._CDB_Group_Table_GrantPermission_API(group_name, username, table_name, 'w');
END IF;
END
$$ LANGUAGE PLPGSQL VOLATILE;
-- Granting and revoking permissions on sequences
CREATE OR REPLACE
FUNCTION cartodb._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 := cartodb._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 'SELECT PG_GET_SERIAL_SEQUENCE($1, $2)' USING 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;
-- Revokes all permissions on a table from a group
CREATE OR REPLACE
FUNCTION cartodb.CDB_Group_Table_RevokeAll(group_name text, username text, table_name text)
RETURNS VOID AS $$
DECLARE
group_role TEXT;
BEGIN
PERFORM cartodb._CDB_Group_Table_RevokeAll(group_name, username, table_name, true);
END
$$ LANGUAGE PLPGSQL VOLATILE;
CREATE OR REPLACE
FUNCTION cartodb._CDB_Group_Table_RevokeAll(group_name text, username text, table_name text, sync boolean)
RETURNS VOID AS $$
DECLARE
group_role TEXT;
BEGIN
group_role := cartodb._CDB_Group_GroupRole(group_name);
EXECUTE format('REVOKE ALL ON TABLE %I.%I FROM %I', username, table_name, group_role);
PERFORM cartodb._CDB_Group_TableSequences_Permission(group_name, username, table_name, false);
IF(sync) THEN
PERFORM cartodb._CDB_Group_Table_RevokeAllPermission_API(group_name, username, table_name);
END IF;
END
$$ LANGUAGE PLPGSQL VOLATILE;
-----------------------
-- 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 cartodb._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_', cartodb._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;
-- Returns the first owner of the schema matching username. Organization user schemas must have one only owner.
CREATE OR REPLACE
FUNCTION cartodb._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;
-- Database names are too long, we need a shorter version for composing role names
CREATE OR REPLACE
FUNCTION cartodb._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;

View File

@@ -0,0 +1,195 @@
----------------------------------
-- GROUP METADATA API FUNCTIONS
--
-- Meant to be used by CDB_Group_* functions to sync data with the editor.
-- Requires configuration parameter. Example: SELECT cartodb.CDB_Conf_SetConf('groups_api', '{ "host": "127.0.0.1", "port": 3000, "timeout": 10, "username": "extension", "password": "elephant" }');
----------------------------------
-- TODO: delete this development cleanup before final merge
DROP FUNCTION IF EXISTS cartodb.CDB_Group_AddMember(group_name text, username text);
DROP FUNCTION IF EXISTS cartodb.CDB_Group_RemoveMember(group_name text, username text);
DROP FUNCTION IF EXISTS cartodb._CDB_Group_AddMember_API(group_name text, username text);
DROP FUNCTION IF EXISTS cartodb._CDB_Group_RemoveMember_API(group_name text, username text);
-- Sends the create group request
CREATE OR REPLACE
FUNCTION cartodb._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 cartodb._CDB_Group_API_Request('POST', '%s', '%s', '{200, 409}') as response_status" % (url, body)
plpy.execute(query)
$$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER;
CREATE OR REPLACE
FUNCTION cartodb._CDB_Group_DropGroup_API(group_name text)
RETURNS VOID AS
$$
import string
import urllib
url = '/api/v1/databases/{0}/groups/%s' % (urllib.pathname2url(group_name))
query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '', '{204, 404}') as response_status" % url
plpy.execute(query)
$$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER;
CREATE OR REPLACE
FUNCTION cartodb._CDB_Group_RenameGroup_API(old_group_name text, new_group_name text, new_group_role text)
RETURNS VOID AS
$$
import string
import urllib
url = '/api/v1/databases/{0}/groups/%s' % (urllib.pathname2url(old_group_name))
body = '{ "name": "%s", "database_role": "%s" }' % (new_group_name, new_group_role)
query = "select cartodb._CDB_Group_API_Request('PUT', '%s', '%s', '{200, 409}') as response_status" % (url, body)
plpy.execute(query)
$$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER;
CREATE OR REPLACE
FUNCTION cartodb._CDB_Group_AddUsers_API(group_name text, usernames text[])
RETURNS VOID AS
$$
import string
import urllib
url = '/api/v1/databases/{0}/groups/%s/users' % (urllib.pathname2url(group_name))
body = "{ \"users\": [\"%s\"] }" % "\",\"".join(usernames)
query = "select cartodb._CDB_Group_API_Request('POST', '%s', '%s', '{200, 409}') as response_status" % (url, body)
plpy.execute(query)
$$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER;
CREATE OR REPLACE
FUNCTION cartodb._CDB_Group_RemoveUsers_API(group_name text, usernames text[])
RETURNS VOID AS
$$
import string
import urllib
url = '/api/v1/databases/{0}/groups/%s/users' % (urllib.pathname2url(group_name))
body = "{ \"users\": [\"%s\"] }" % "\",\"".join(usernames)
query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '%s', '{200, 404}') as response_status" % (url, body)
plpy.execute(query)
$$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER;
DO LANGUAGE 'plpgsql' $$
BEGIN
-- Needed for dropping type
DROP FUNCTION IF EXISTS cartodb._CDB_Group_API_Conf();
DROP TYPE IF EXISTS _CDB_Group_API_Params;
END
$$;
CREATE OR REPLACE
FUNCTION cartodb._CDB_Group_Table_GrantPermission_API(group_name text, username text, table_name text, access text)
RETURNS VOID AS
$$
import string
import urllib
url = '/api/v1/databases/{0}/groups/%s/permission/%s/tables/%s' % (urllib.pathname2url(group_name), username, table_name)
body = '{ "access": "%s" }' % access
query = "select cartodb._CDB_Group_API_Request('PUT', '%s', '%s', '{200, 409}') as response_status" % (url, body)
plpy.execute(query)
$$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER;
DO LANGUAGE 'plpgsql' $$
BEGIN
-- Needed for dropping type
DROP FUNCTION IF EXISTS cartodb._CDB_Group_API_Conf();
DROP TYPE IF EXISTS _CDB_Group_API_Params;
END
$$;
CREATE OR REPLACE
FUNCTION cartodb._CDB_Group_Table_RevokeAllPermission_API(group_name text, username text, table_name text)
RETURNS VOID AS
$$
import string
import urllib
url = '/api/v1/databases/{0}/groups/%s/permission/%s/tables/%s' % (urllib.pathname2url(group_name), username, table_name)
query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '', '{200, 404}') as response_status" % url
plpy.execute(query)
$$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER;
DO LANGUAGE 'plpgsql' $$
BEGIN
-- Needed for dropping type
DROP FUNCTION IF EXISTS cartodb._CDB_Group_API_Conf();
DROP TYPE IF EXISTS _CDB_Group_API_Params;
END
$$;
CREATE TYPE _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 cartodb._CDB_Group_API_Conf()
RETURNS _CDB_Group_API_Params AS
$$
conf = plpy.execute("SELECT cartodb.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 cartodb._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;
CREATE OR REPLACE
FUNCTION cartodb._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;
-- url must contain a '%s' placeholder that will be replaced by current_database, for security reasons.
CREATE OR REPLACE
FUNCTION cartodb._CDB_Group_API_Request(method text, url text, body text, valid_return_codes int[])
RETURNS int AS
$$
import httplib
params = plpy.execute("select c.host, c.port, c.timeout, c.auth from cartodb._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:
client = SD['groups_api_client'] = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout'])
database_name = plpy.execute("select current_database();")[0]['current_database']
client.request(method, url.format(database_name), body, headers)
response = client.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))
client = 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;
revoke all on function cartodb._CDB_Group_API_Request(text, text, text, int[]) from public;

View File

@@ -1,14 +1,16 @@
CREATE OR REPLACE
FUNCTION cartodb.CDB_Organization_Member_Group_Role_Member_Name()
RETURNS TEXT
AS 'SELECT ''cdb_org_member''::text || ''_'' || md5(current_database());'
AS $$
SELECT 'cdb_org_member'::text || '_' || md5(current_database());
$$
LANGUAGE SQL IMMUTABLE;
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 := cartodb.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;';
@@ -25,6 +27,60 @@ BEGIN
END
$$ LANGUAGE PLPGSQL VOLATILE;
-------------------------------------------------------------------------------
-- Administrator
-------------------------------------------------------------------------------
CREATE OR REPLACE
FUNCTION cartodb._CDB_Organization_Admin_Role_Name()
RETURNS TEXT
AS $$
SELECT current_database() || '_a'::text;
$$
LANGUAGE SQL IMMUTABLE;
-- Administrator role creation on extension install
DO LANGUAGE 'plpgsql' $$
DECLARE
cdb_org_admin_role_name TEXT;
BEGIN
cdb_org_admin_role_name := cartodb._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 cartodb.CDB_Organization_AddAdmin(username text)
RETURNS void
AS $$
DECLARE
cdb_user_role TEXT;
cdb_admin_role TEXT;
BEGIN
cdb_admin_role := cartodb._CDB_Organization_Admin_Role_Name();
cdb_user_role := cartodb._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;
CREATE OR REPLACE
FUNCTION cartodb.CDB_Organization_RemoveAdmin(username text)
RETURNS void
AS $$
DECLARE
cdb_user_role TEXT;
cdb_admin_role TEXT;
BEGIN
cdb_admin_role := cartodb._CDB_Organization_Admin_Role_Name();
cdb_user_role := cartodb._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;
-------------------------------------------------------------------------------
-- Sharing tables

View File

@@ -41,11 +41,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;

View File

@@ -0,0 +1,47 @@
--
-- 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 CDB_Kurtosis ( in_array NUMERIC[] ) RETURNS NUMERIC as $$
DECLARE
a numeric;
c numeric;
s numeric;
k numeric;
BEGIN
SELECT AVG(e), COUNT(e)::numeric, stddev(e) INTO a, c, s FROM ( SELECT unnest(in_array) e ) x;
EXECUTE 'SELECT sum(power($1 - e, 4)) / ( $2 * power($3, 4)) - 3
FROM (SELECT unnest($4) e ) x'
INTO k
USING a, c, s, in_array;
RETURN k;
END;
$$ language plpgsql IMMUTABLE;
-- Calculate skewness
CREATE OR REPLACE FUNCTION CDB_Skewness ( in_array NUMERIC[] ) RETURNS NUMERIC as $$
DECLARE
a numeric;
c numeric;
s numeric;
sk numeric;
BEGIN
SELECT AVG(e), COUNT(e)::numeric, stddev(e) INTO a, c, s FROM ( SELECT unnest(in_array) e ) x;
EXECUTE 'SELECT sum(power($1 - e, 3)) / ( $2 * power($3, 3))
FROM (SELECT unnest($4) e ) x'
INTO sk
USING a, c, s, in_array;
RETURN sk;
END;
$$ language plpgsql IMMUTABLE;

View File

@@ -5,7 +5,7 @@
--
-- Currently accepted permissions are: 'public', 'private' or 'all'
--
DROP FUNCTION IF EXISTS cdb_usertables(text);
DROP FUNCTION IF EXISTS CDB_UserTables(text);
CREATE OR REPLACE FUNCTION CDB_UserTables(perm text DEFAULT 'all')
RETURNS SETOF name
AS $$
@@ -15,7 +15,7 @@ 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 n.nspname NOT IN ('pg_catalog', 'information_schema', 'topology', 'cartodb')
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')

View File

@@ -0,0 +1 @@
../scripts-available/CDB_Conf.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

@@ -216,6 +216,72 @@ WHERE c.conrelid = 't'::regclass and a.attrelid = c.conrelid
AND c.conkey[1] = a.attnum AND NOT a.attisdropped;
DROP TABLE t;
-- tables can be renamed and there's no index name clashing #123
CREATE TABLE original();
SELECT CDB_CartodbfyTable('original');
ALTER TABLE original RENAME TO original_renamed;
CREATE TABLE original();
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 * 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;
-- TODO: table with existing custom-triggered the_geom
DROP FUNCTION CDB_CartodbfyTableCheck(regclass, text);

View File

@@ -51,5 +51,33 @@ CREATE TABLE
cartodb_id serial primary key cartodbfied fine
t_pkey|cartodb_id
DROP TABLE
CREATE TABLE
original
ALTER TABLE
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
Many colliding columns #141 cartodbfied fine
DROP TABLE
DROP FUNCTION
DROP FUNCTION

13
test/CDB_StatsTest.sql Normal file
View File

@@ -0,0 +1,13 @@
-- continuous uniform distribution has kurtosis = -6/5, skewness = 0.0
-- http://mathworld.wolfram.com/UniformDistribution.html
set client_min_messages to ERROR;
WITH dist AS (
SELECT generate_series(0,10000)::numeric / 10000.0 i
)
SELECT
abs(CDB_Kurtosis(array_agg(i)) + 1.2) < 1e-3 AS kurtosis,
abs(CDB_Skewness(array_agg(i))) < 1e-3 AS skewness
FROM dist;
set client_min_messages to NOTICE;

View File

@@ -0,0 +1,3 @@
SET
t|t
SET

View File

@@ -1,4 +1,6 @@
SET SCHEMA 'cartodb';
\i scripts-available/CDB_Quota.sql
\i scripts-available/CDB_TableMetadata.sql
\i scripts-available/CDB_ColumnNames.sql
\i scripts-available/CDB_ColumnType.sql
SET SCHEMA 'public';

View File

@@ -123,7 +123,7 @@ function create_role_and_schema() {
function drop_role_and_schema() {
local ROLE=$1
sql "DROP SCHEMA \"${ROLE}\";"
sql "DROP SCHEMA \"${ROLE}\" CASCADE;"
sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM \"${ROLE}\";"
sql "DROP ROLE \"${ROLE}\";"
}
@@ -178,6 +178,7 @@ function setup() {
sql "CREATE SCHEMA cartodb;"
sql "GRANT USAGE ON SCHEMA cartodb TO public;"
sql "CREATE EXTENSION postgis;"
sql "CREATE EXTENSION plpythonu;"
log_info "########################### BOOTSTRAP ###########################"
${CMD} -d ${DATABASE} -f scripts-available/CDB_Organizations.sql
@@ -209,8 +210,8 @@ function tear_down() {
sql "DROP SCHEMA cartodb CASCADE"
log_info "########################### TEAR DOWN ###########################"
sql 'DROP SCHEMA cdb_testmember_1;'
sql 'DROP SCHEMA cdb_testmember_2;'
sql 'DROP SCHEMA cdb_testmember_1 CASCADE;'
sql 'DROP SCHEMA cdb_testmember_2 CASCADE;'
sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_testmember_1;"
sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_testmember_2;"
@@ -227,7 +228,12 @@ function run_tests() {
local TESTS
if [[ $# -ge 1 ]]
then
TESTS="$@"
if [[ $# -eq 1 ]]
then
TESTS=`cat $0 | grep -o "$1[^\(]*"`
else
TESTS="$@"
fi
else
TESTS=`cat $0 | perl -n -e'/function (test.*)\(\)/ && print "$1\n"'`
fi
@@ -337,6 +343,92 @@ function test_cdb_tablemetadatatouch_fails_from_user_without_permission() {
sql postgres "REVOKE ALL ON CDB_TableMetadata FROM cdb_testmember_1;"
}
function test_cdb_column_names() {
sql cdb_testmember_1 'CREATE TABLE cdb_testmember_1.table_cnames(c int, a int, r int, t int, o int);'
sql cdb_testmember_2 'CREATE TABLE cdb_testmember_2.table_cnames(d int, b int);'
sql cdb_testmember_1 "SELECT string_agg(c,'') from (SELECT cartodb.CDB_ColumnNames('table_cnames') c) as s" should "carto"
sql cdb_testmember_2 "SELECT string_agg(c,'') from (SELECT cartodb.CDB_ColumnNames('table_cnames') c) as s" should "db"
sql postgres "SELECT string_agg(c,'') from (SELECT cartodb.CDB_ColumnNames('cdb_testmember_1.table_cnames'::regclass) c) as s" should "carto"
sql postgres "SELECT string_agg(c,'') from (SELECT cartodb.CDB_ColumnNames('cdb_testmember_2.table_cnames') c) as s" should "db"
# Using schema from owner
sql cdb_testmember_1 "SELECT string_agg(c,'') from (SELECT cartodb.CDB_ColumnNames('cdb_testmember_1.table_cnames') c) as s" should "carto"
## it's not possible to get column names from a table where you don't have permissions
sql cdb_testmember_2 "SELECT string_agg(c,'') from (SELECT cartodb.CDB_ColumnNames('cdb_testmember_1.table_cnames') c) as s" fails
sql cdb_testmember_1 'DROP TABLE cdb_testmember_1.table_cnames'
sql cdb_testmember_2 'DROP TABLE cdb_testmember_2.table_cnames'
}
function test_cdb_column_type() {
sql cdb_testmember_1 'CREATE TABLE cdb_testmember_1.table_ctype(c int, a int, r int, t int, o int);'
sql cdb_testmember_2 'CREATE TABLE cdb_testmember_2.table_ctype(c text, a text, r text, t text, o text);'
sql cdb_testmember_1 "SELECT cartodb.CDB_ColumnType('table_ctype', 'c')" should "integer"
sql cdb_testmember_2 "SELECT cartodb.CDB_ColumnType('table_ctype', 'c')" should "text"
sql postgres "SELECT cartodb.CDB_ColumnType('cdb_testmember_1.table_ctype', 'c')" should "integer"
sql postgres "SELECT cartodb.CDB_ColumnType('cdb_testmember_2.table_ctype', 'c')" should "text"
sql cdb_testmember_1 'DROP TABLE cdb_testmember_1.table_ctype'
sql cdb_testmember_2 'DROP TABLE cdb_testmember_2.table_ctype'
}
function test_cdb_querytables_schema_and_table_names_with_dots() {
${CMD} -d ${DATABASE} -f scripts-available/CDB_QueryStatements.sql
${CMD} -d ${DATABASE} -f scripts-available/CDB_QueryTables.sql
sql postgres 'CREATE SCHEMA "foo.bar";'
sql postgres 'CREATE TABLE "foo.bar"."c.a.r.t.o.d.b" (a int);'
sql postgres 'INSERT INTO "foo.bar"."c.a.r.t.o.d.b" values (1);'
sql postgres 'SELECT a FROM "foo.bar"."c.a.r.t.o.d.b";' should 1
sql postgres 'SELECT CDB_QueryTablesText($q$select * from "foo.bar"."c.a.r.t.o.d.b"$q$);' should '{"\"foo.bar\".\"c.a.r.t.o.d.b\""}'
sql postgres 'SELECT CDB_QueryTables($q$select * from "foo.bar"."c.a.r.t.o.d.b"$q$);' should '{"\"foo.bar\".\"c.a.r.t.o.d.b\""}'
sql postgres 'DROP TABLE "foo.bar"."c.a.r.t.o.d.b";'
sql postgres 'DROP SCHEMA "foo.bar";'
}
function test_cdb_querytables_table_name_with_dots() {
${CMD} -d ${DATABASE} -f scripts-available/CDB_QueryStatements.sql
${CMD} -d ${DATABASE} -f scripts-available/CDB_QueryTables.sql
sql postgres 'CREATE TABLE "w.a.d.u.s" (a int);';
sql postgres 'SELECT CDB_QueryTablesText($q$select * from "w.a.d.u.s"$q$);' should '{"public.\"w.a.d.u.s\""}'
sql postgres 'SELECT CDB_QueryTables($q$select * from "w.a.d.u.s"$q$);' should '{"public.\"w.a.d.u.s\""}'
sql postgres 'DROP TABLE "w.a.d.u.s";';
}
function test_cdb_querytables_happy_cases() {
${CMD} -d ${DATABASE} -f scripts-available/CDB_QueryStatements.sql
${CMD} -d ${DATABASE} -f scripts-available/CDB_QueryTables.sql
sql postgres 'CREATE TABLE wadus (a int);';
sql postgres 'CREATE TABLE "FOOBAR" (a int);';
sql postgres 'CREATE SCHEMA foo;'
sql postgres 'CREATE TABLE foo.wadus (a int);';
## See how it does NOT quote anything here
sql postgres 'SELECT CDB_QueryTablesText($q$select * from wadus$q$);' should '{public.wadus}'
sql postgres 'SELECT CDB_QueryTablesText($q$select * from foo.wadus$q$);' should '{foo.wadus}'
sql postgres 'SELECT CDB_QueryTables($q$select * from wadus$q$);' should '{public.wadus}'
sql postgres 'SELECT CDB_QueryTables($q$select * from foo.wadus$q$);' should '{foo.wadus}'
## But it quotes when it's needed even if table name has no dots but was created with quotes
sql postgres 'SELECT CDB_QueryTablesText($q$select * from "FOOBAR"$q$);' should '{"public.\"FOOBAR\""}'
sql postgres 'DROP TABLE wadus;'
sql postgres 'DROP TABLE "FOOBAR";'
sql postgres 'DROP TABLE foo.wadus;'
sql postgres 'DROP SCHEMA foo;'
}
#################################################### TESTS END HERE ####################################################
run_tests $@

View File

@@ -28,6 +28,7 @@ function clear_partial_result() {
function sql() {
local ROLE
local QUERY
ERROR_OUTPUT_FILE='/tmp/test_error.log'
if [[ $# -ge 2 ]]
then
ROLE="$1"
@@ -37,15 +38,40 @@ function sql() {
fi
if [ -n "${ROLE}" ]; then
log_debug "Executing query '${QUERY}' as ${ROLE}"
RESULT=`${CMD} -U "${ROLE}" ${DATABASE} -c "${QUERY}" -A -t`
log_debug "Executing query '${QUERY}' as ${ROLE}"
RESULT=`${CMD} -U "${ROLE}" ${DATABASE} -c "${QUERY}" -A -t 2>"${ERROR_OUTPUT_FILE}"`
else
log_debug "Executing query '${QUERY}'"
RESULT=`${CMD} ${DATABASE} -c "${QUERY}" -A -t`
log_debug "Executing query '${QUERY}'"
RESULT=`${CMD} ${DATABASE} -c "${QUERY}" -A -t 2>"${ERROR_OUTPUT_FILE}"`
fi
CODERESULT=$?
ERROR_OUTPUT=`cat "${ERROR_OUTPUT_FILE}"`
rm ${ERROR_OUTPUT_FILE}
echo ${RESULT}
echo -n "> Code Result: "
echo -n ${CODERESULT}
echo -n "; Result: "
echo -n ${RESULT}
echo -n "; Error output: "
echo -n ${ERROR_OUTPUT}
# Some warnings should actually be failures
if [[ ${CODERESULT} == "0" ]]
then
case "${ERROR_OUTPUT}" in
WARNING:*no*privileges*were*granted*for*)
echo -n "FAILED BECAUSE OF PRIVILEGES GRANTING WARNING"
CODERESULT=1
;;
WARNING:*no*privileges*could*be*revoked*for*)
echo -n "FAILED BECAUSE OF PRIVILEGES REVOKING WARNING"
CODERESULT=1
;;
*) ;;
esac
echo -n "; Code result after warnings: "
echo -n ${CODERESULT}
fi
echo
if [[ ${CODERESULT} -ne 0 ]]
@@ -133,13 +159,18 @@ function create_table() {
function setup() {
${CMD} -c "CREATE DATABASE ${DATABASE}"
sql "CREATE SCHEMA cartodb;"
sql "CREATE EXTENSION plpythonu;"
sql "GRANT USAGE ON SCHEMA cartodb TO public;"
log_info "########################### BOOTSTRAP ###########################"
${CMD} -d ${DATABASE} -f scripts-available/CDB_Organizations.sql
${CMD} -d ${DATABASE} -f scripts-available/CDB_Conf.sql
${CMD} -d ${DATABASE} -f scripts-available/CDB_Groups.sql
${CMD} -d ${DATABASE} -f scripts-available/CDB_Groups_API.sql
log_info "############################# SETUP #############################"
create_role_and_schema cdb_org_admin
sql "SELECT cartodb.CDB_Organization_AddAdmin('cdb_org_admin');"
create_role_and_schema cdb_testmember_1
create_role_and_schema cdb_testmember_2
sql "CREATE ROLE publicuser LOGIN;"
@@ -152,8 +183,16 @@ function setup() {
create_table cdb_testmember_2 bar
sql cdb_testmember_2 'INSERT INTO bar VALUES (1), (2), (3), (4), (5);'
sql cdb_testmember_2 'SELECT * FROM cdb_testmember_2.bar;'
sql "SELECT cartodb.CDB_Group_CreateGroup('group_a_tmp')"
sql "SELECT cartodb.CDB_Group_RenameGroup('group_a_tmp', 'group_a')"
sql "SELECT cartodb.CDB_Group_AddUsers('group_a', ARRAY['cdb_testmember_1'])"
sql "SELECT cartodb.CDB_Group_CreateGroup('group_b')"
}
function tear_down() {
log_info "########################### USER TEAR DOWN ###########################"
sql cdb_testmember_1 "SELECT * FROM cartodb.CDB_Organization_Remove_Access_Permission('cdb_testmember_1', 'foo', 'cdb_testmember_2');"
@@ -162,19 +201,29 @@ function tear_down() {
sql cdb_testmember_1 'DROP TABLE cdb_testmember_1.foo;'
sql cdb_testmember_2 'DROP TABLE cdb_testmember_2.bar;'
sql "select cartodb.CDB_Group_DropGroup('group_b')"
sql "SELECT cartodb.CDB_Group_RemoveUsers('group_a', ARRAY['cdb_testmember_1'])"
sql "select cartodb.CDB_Group_DropGroup('group_a')"
sql "SELECT cartodb.CDB_Organization_RemoveAdmin('cdb_org_admin');"
sql "DROP SCHEMA cartodb CASCADE"
log_info "########################### TEAR DOWN ###########################"
sql 'DROP SCHEMA cdb_testmember_1;'
sql 'DROP SCHEMA cdb_testmember_2;'
sql 'DROP SCHEMA cdb_org_admin;'
sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_testmember_1;"
sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_testmember_2;"
sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM publicuser;"
sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_org_admin;"
sql 'DROP ROLE cdb_testmember_1;'
sql 'DROP ROLE cdb_testmember_2;'
sql 'DROP ROLE publicuser;'
sql 'DROP ROLE cdb_org_admin;'
${CMD} -c "DROP DATABASE ${DATABASE}"
}
@@ -198,6 +247,7 @@ function run_tests() {
echo "####################################################################"
clear_partial_result
setup
log_info "############################# TESTS #############################"
eval ${t}
if [[ ${PARTIALOK} -ne 0 ]]
then
@@ -330,21 +380,18 @@ function test_user_can_read_when_it_has_permission_after_organization_permission
}
function test_cdb_querytables_returns_schema_and_table_name() {
sql "CREATE EXTENSION plpythonu;"
${CMD} -d ${DATABASE} -f scripts-available/CDB_QueryStatements.sql
${CMD} -d ${DATABASE} -f scripts-available/CDB_QueryTables.sql
sql cdb_testmember_1 "select * from CDB_QueryTables('select * from foo');" should "{cdb_testmember_1.foo}"
}
function test_cdb_querytables_returns_schema_and_table_name_for_several_schemas() {
sql "CREATE EXTENSION plpythonu;"
${CMD} -d ${DATABASE} -f scripts-available/CDB_QueryStatements.sql
${CMD} -d ${DATABASE} -f scripts-available/CDB_QueryTables.sql
sql postgres "select * from CDB_QueryTables('select * from cdb_testmember_1.foo, cdb_testmember_2.bar');" should "{cdb_testmember_1.foo,cdb_testmember_2.bar}"
}
function test_cdb_querytables_does_not_return_functions_as_part_of_the_resultset() {
sql "CREATE EXTENSION plpythonu;"
${CMD} -d ${DATABASE} -f scripts-available/CDB_QueryStatements.sql
${CMD} -d ${DATABASE} -f scripts-available/CDB_QueryTables.sql
sql postgres "select * from CDB_QueryTables('select * from cdb_testmember_1.foo, cdb_testmember_2.bar, plainto_tsquery(''foo'')');" should "{cdb_testmember_1.foo,cdb_testmember_2.bar}"
@@ -393,6 +440,107 @@ function test_cdb_usertables_should_work_with_orgusers() {
sql cdb_testmember_1 "DROP TABLE test_perms_priv"
}
function test_CDB_Group_Table_GrantRead_should_grant_select_and_RevokeAll_should_remove_it() {
create_table cdb_testmember_2 shared_with_group
sql cdb_testmember_1 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;' fails
sql cdb_testmember_2 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;'
sql cdb_testmember_2 "select cartoDB.CDB_Group_Table_GrantRead('group_a', 'cdb_testmember_2', 'shared_with_group')"
sql cdb_testmember_1 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;'
sql cdb_testmember_2 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;'
sql cdb_testmember_2 "select cartoDB.CDB_Group_Table_RevokeAll('group_a', 'cdb_testmember_2', 'shared_with_group')"
sql cdb_testmember_1 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;' fails
sql cdb_testmember_2 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;'
sql cdb_testmember_2 'DROP TABLE cdb_testmember_2.shared_with_group;'
}
function test_CDB_Group_Table_GrantReadWrite_should_grant_insert_and_RevokeAll_should_remove_it() {
create_table cdb_testmember_2 shared_with_group
sql cdb_testmember_1 'INSERT INTO cdb_testmember_2.shared_with_group VALUES (1), (2), (3), (4), (5)' fails
sql cdb_testmember_2 'INSERT INTO cdb_testmember_2.shared_with_group VALUES (1), (2), (3), (4), (5)'
sql cdb_testmember_2 "select cartoDB.CDB_Group_Table_GrantReadWrite('group_a', 'cdb_testmember_2', 'shared_with_group')"
sql cdb_testmember_1 'INSERT INTO cdb_testmember_2.shared_with_group VALUES (1), (2), (3), (4), (5)'
sql cdb_testmember_2 'INSERT INTO cdb_testmember_2.shared_with_group VALUES (1), (2), (3), (4), (5)'
sql cdb_testmember_2 "select cartoDB.CDB_Group_Table_RevokeAll('group_a', 'cdb_testmember_2', 'shared_with_group')"
sql cdb_testmember_1 'INSERT INTO cdb_testmember_2.shared_with_group VALUES (1), (2), (3), (4), (5)' fails
sql cdb_testmember_2 'INSERT INTO cdb_testmember_2.shared_with_group VALUES (1), (2), (3), (4), (5)'
sql cdb_testmember_2 'DROP TABLE cdb_testmember_2.shared_with_group;'
}
function test_group_management_functions_cant_be_used_by_normal_members() {
sql cdb_testmember_1 "SELECT cartodb.CDB_Group_CreateGroup('group_x_1');" fails
sql cdb_testmember_1 "SELECT cartodb.CDB_Group_RenameGroup('group_a', 'group_x_2');" fails
sql cdb_testmember_1 "SELECT cartodb.CDB_Group_DropGroup('group_a');" fails
sql cdb_testmember_1 "SELECT cartodb.CDB_Group_AddUsers('group_a', ARRAY['cdb_testmember_2']);" fails
sql cdb_testmember_1 "SELECT cartodb.CDB_Group_RemoveUsers('group_a', ARRAY['cdb_testmember_1']);" fails
}
function test_group_permission_functions_cant_be_used_by_normal_members() {
create_table cdb_testmember_2 shared_with_group
sql cdb_testmember_1 "select cartoDB.CDB_Group_Table_GrantRead('group_a', 'cdb_testmember_2', 'shared_with_group');" fails
sql cdb_testmember_1 "select cartoDB.CDB_Group_Table_GrantReadWrite('group_a', 'cdb_testmember_2', 'shared_with_group');" fails
# Checks that you can't grant even if your group has RW permissions
sql cdb_testmember_2 "select cartoDB.CDB_Group_Table_GrantReadWrite('group_a', 'cdb_testmember_2', 'shared_with_group')"
sql cdb_testmember_1 "select cartoDB.CDB_Group_Table_GrantRead('group_a', 'cdb_testmember_2', 'shared_with_group');" fails
sql cdb_testmember_1 "select cartoDB.CDB_Group_Table_GrantReadWrite('group_b', 'cdb_testmember_2', 'shared_with_group');" fails
sql cdb_testmember_1 "select cartoDB.CDB_Group_Table_RevokeAll('group_b', 'cdb_testmember_2', 'shared_with_group');" fails
sql cdb_testmember_2 'DROP TABLE cdb_testmember_2.shared_with_group;'
}
function test_group_management_functions_can_be_used_by_org_admin() {
sql cdb_org_admin "SELECT cartodb.CDB_Group_CreateGroup('group_x_tmp');"
sql cdb_org_admin "SELECT cartodb.CDB_Group_RenameGroup('group_x_tmp', 'group_x');"
sql cdb_org_admin "SELECT cartodb.CDB_Group_AddUsers('group_x', ARRAY['cdb_testmember_1', 'cdb_testmember_2']);"
sql cdb_org_admin "SELECT cartodb.CDB_Group_RemoveUsers('group_x', ARRAY['cdb_testmember_1', 'cdb_testmember_2']);"
# TODO: workaround superadmin limitation
sql "SELECT cartodb.CDB_Group_DropGroup('group_x');"
}
function test_org_admin_cant_grant_permissions_on_tables_he_does_not_own() {
create_table cdb_testmember_2 shared_with_group
sql cdb_org_admin "select cartoDB.CDB_Group_Table_GrantRead('group_a', 'cdb_testmember_2', 'shared_with_group');" fails
sql cdb_org_admin "select cartoDB.CDB_Group_Table_GrantReadWrite('group_a', 'cdb_testmember_2', 'shared_with_group');" fails
# Checks that you can't grant even if your group has RW permissions
sql cdb_testmember_2 "select cartoDB.CDB_Group_Table_GrantReadWrite('group_a', 'cdb_testmember_2', 'shared_with_group')"
sql cdb_org_admin "select cartoDB.CDB_Group_Table_GrantRead('group_a', 'cdb_testmember_2', 'shared_with_group');" fails
sql cdb_org_admin "select cartoDB.CDB_Group_Table_GrantReadWrite('group_b', 'cdb_testmember_2', 'shared_with_group');" fails
sql cdb_org_admin "select cartoDB.CDB_Group_Table_RevokeAll('group_b', 'cdb_testmember_2', 'shared_with_group');" fails
sql cdb_testmember_2 'DROP TABLE cdb_testmember_2.shared_with_group;'
}
function test_valid_group_names() {
sql postgres "select cartodb._CDB_Group_GroupRole('group_1$_a');"
sql postgres "select cartodb._CDB_Group_GroupRole('GROUP_1$_A');"
sql postgres "select cartodb._CDB_Group_GroupRole('_group_1$_a');"
}
function test_administrator_name_generation() {
sql postgres "select cartodb._CDB_Organization_Admin_Role_Name();"
}
function test_conf() {
sql postgres "SELECT cartodb.CDB_Conf_GetConf('test_conf')" should ''
sql postgres "SELECT cartodb.CDB_Conf_GetConf('test_conf_2')" should ''
sql postgres "SELECT cartodb.CDB_Conf_SetConf('test_conf', '{ \"a_key\": \"test_val\" }')"
sql postgres "SELECT cartodb.CDB_Conf_GetConf('test_conf')" should '{ "a_key": "test_val" }'
sql postgres "SELECT cartodb.CDB_Conf_GetConf('test_conf_2')" should ''
sql postgres "SELECT cartodb.CDB_Conf_RemoveConf('test_conf')"
sql postgres "SELECT cartodb.CDB_Conf_GetConf('test_conf')" should ''
sql postgres "SELECT cartodb.CDB_Conf_GetConf('test_conf_2')" should ''
}
#################################################### TESTS END HERE ####################################################