Compare commits

..

122 Commits
0.4.0 ... cdb

Author SHA1 Message Date
javi
513488da0e change random value for quota test again 2015-07-28 09:05:03 +02:00
javi
7921cad4f5 readded removed tests by error 2015-07-27 16:49:59 +02:00
javi santana
10ba742324 Merge pull request #100 from CartoDB/release_0.8.2
Release 0.8.2
2015-07-27 16:19:16 +02:00
javi
788d2a7f10 ready for 0.8.2 2015-07-27 16:12:42 +02:00
javi
189a73ce4d fixed tests 2015-07-27 16:12:15 +02:00
javi santana
d52e05c474 Merge pull request #99 from CartoDB/usertables_fix
added tests for usertables to check private tables are not returned
2015-07-27 16:04:45 +02:00
javi
400248cd5d remove connection permissions to public user 2015-07-27 11:20:55 +02:00
javi
92b5d1f8f4 creating in setup 2015-07-27 11:15:14 +02:00
javi
68fdd9ce33 just add login permissions to public user 2015-07-27 11:07:46 +02:00
javi
53e6b38c32 enabling user again (no sense) 2015-07-27 11:03:21 +02:00
javi
c71faf21e2 do not create publicuser since a previous tests is doing it 2015-07-27 10:57:38 +02:00
javi
12260b9fc3 test cleanup 2015-07-27 10:54:43 +02:00
javi
1b3db28a74 added tests for organization 2015-07-27 10:51:20 +02:00
javi
5d6c2111bf updates tests 2015-07-27 10:37:07 +02:00
javi
df36e83cb5 revoke permissions to list private tables to public user 2015-07-27 10:31:55 +02:00
javi
e05613d5c4 added tests for usertables to check private tables are not returned 2015-07-27 10:25:44 +02:00
Paul Ramsey
565046c3d4 Merge pull request #97 from CartoDB/b0.8
PR for 0.8.1 release
2015-07-08 12:55:02 -07:00
Paul Ramsey
011a007f04 Return test results in deterministic order (closes #96) 2015-07-07 06:13:02 -07:00
Paul Ramsey
08cdb38730 Prepare for 0.8.1 release 2015-07-07 06:07:41 -07:00
Paul Ramsey
734561de4c Use 'publicuser' as public role, not 'public', closes #95.
This is consistent with cartodb behaviour, but not exactly
the same as the contract that the 'public' role guarantees
access to public resources. Possibly a better fix would be
to audit (ug) everything and make sure that it's really
using the public role to mean public, rather than the
'publicuser' connection role. That CDB creates.
2015-07-07 05:49:28 -07:00
Paul Ramsey
8516cbd4c3 Splling fix 2015-07-01 07:03:13 -07:00
Paul Ramsey
509944ea6d Move doc from wiki to repo, closes #85 2015-07-01 07:01:50 -07:00
Rafa de la Torre
ac8203eec4 Merge pull request #93 from CartoDB/fix-upgrade-issue
Fix for upgrade issue from 0.7.4 to 0.8.0
2015-06-30 12:58:23 +02:00
Rafa de la Torre
a6fd829669 Fix for upgrade issue from 0.7.4 to 0.8.0
This fixes the following problem found during testing:
```
ALTER EXTENSION cartodb UPDATE TO '0.8.0';
ERROR:  cannot change return type of existing function
HINT:  Use DROP FUNCTION cdb_usertables(text) first.
```
2015-06-30 12:20:29 +02:00
Rafa de la Torre
0045fb20e8 Update NEWS.md 2015-06-30 11:34:59 +02:00
Raul Ochoa
8190edb461 Merge pull request #83 from CartoDB/64-usertables
Replace CDB_UserTables with something that can handle multi-user accounts
2015-06-30 11:33:32 +02:00
Rafa de la Torre
373e9f5db8 Merge pull request #92 from CartoDB/fix-versioning
Fix versioning by creating a 0.8.0
2015-06-30 11:25:32 +02:00
Rafa de la Torre
6b29c9e67d Fix versioning by creating a 0.8.0
Fix versioning by creating a new major version since it contains new
features. Keep version 0.7.4 that should've never existed and provide an
upgrade path for the new version.
2015-06-30 11:11:24 +02:00
Rafa de la Torre
2b46a2d56f Merge pull request #91 from CartoDB/upgrade-version-0-7-4
Update Makefile and NEWS.md for new version
2015-06-29 12:37:30 +02:00
Rafa de la Torre
371d84ea0c Update Makefile and NEWS.md for new version 2015-06-29 12:09:35 +02:00
Andy Eschbacher
e5897f3dad Merge pull request #87 from CartoDB/categ-distrib
Function deciding criteria for using a category column in a map
2015-06-25 11:50:56 -04:00
Andy Eschbacher
b9fe204007 Merge pull request #81 from CartoDB/equalint
adding equal interval function for consistency
2015-06-25 11:08:24 -04:00
Rafa de la Torre
9b2cff15c5 Merge pull request #88 from CartoDB/86-CDB_QueryTables-fix-long-names
Add a new function CDB_QueryTablesText #86
2015-06-25 16:20:08 +02:00
Andy Eschbacher
13946b4d47 update test output 2015-06-25 08:17:41 -04:00
Andy Eschbacher
97140b17c9 added more flexible output values 2015-06-24 11:03:16 -04:00
Rafa de la Torre
c3eea08f66 Remove ECHO from expectation #86
Remove the `\set ECHO none` from expectation that is automatically
removed by the test harness but still appears in the output when a test
fails.
2015-06-24 16:29:40 +02:00
Rafa de la Torre
22fc962d09 Change expectation #86
Just add CONTEXT lines since they are now added in case of
WARNING/ERROR as a result of having CDB_QueryTables calling
CDB_QueryTablesText.
2015-06-24 16:01:45 +02:00
Rafa de la Torre
ddb6b2c5b5 Return text instead of regclass #86
This way the schema is always returned and backwards compatibility is
kept, should it be needed.
2015-06-24 14:14:00 +02:00
Rafa de la Torre
9a94b3879a Add a new function CDB_QueryTablesRegclass #86
The return values of it can be safely used when len(schema.table_name)
exceeds the 63 char limit of the postgres type `name`.
2015-06-24 11:53:09 +02:00
Andy Eschbacher
d124776c4e simplified assignment 2015-06-23 18:49:59 -04:00
Andy Eschbacher
5941b473ca removed notice 2015-06-23 18:39:15 -04:00
Andy Eschbacher
3ad3038c5e fixed symlink path, other minor items 2015-06-23 18:32:16 -04:00
Andy Eschbacher
c7bb57b405 add symlink 2015-06-23 18:08:32 -04:00
Andy Eschbacher
f8542af57a add tests 2015-06-23 18:07:48 -04:00
Andy Eschbacher
cda6953ea6 initial commit 2015-06-23 16:27:27 -04:00
Andy Eschbacher
189309e1a5 Merge pull request #84 from CartoDB/add-dist-classify
Add distribution classifier
2015-06-12 08:53:42 -04:00
Andy Eschbacher
1d223b77cc changed subfunction name, replaced function with case statement 2015-06-10 10:50:01 -04:00
Andy Eschbacher
6ab1b1d3d0 removed unneeded variables 2015-06-08 18:36:07 -04:00
Andy Eschbacher
c7f4209270 added alias and line 2015-06-08 15:11:58 -04:00
Andy Eschbacher
8e2d86414f updating function 2015-06-08 15:02:39 -04:00
Andy Eschbacher
9cb1fe30d8 adding tests 2015-06-08 15:01:50 -04:00
Andy Eschbacher
424564e324 initial commit 2015-06-08 13:37:27 -04:00
Paul Ramsey
dd3f125339 Fix test expectation 2015-06-01 11:10:06 -07:00
Paul Ramsey
e7ef5e7e8e Clean up after tests
For #64
2015-06-01 10:57:30 -07:00
Paul Ramsey
54973142f6 Handle "unsupported argument" case for CDB_UserTables
in support of #64
2015-06-01 10:37:46 -07:00
Paul Ramsey
ba521461fe Replace CDB_UserTables with new version
fix for #64
2015-06-01 09:47:02 -07:00
Andy Eschbacher
42a617e79c ugh bad filename 2015-05-19 16:03:54 -04:00
Andy Eschbacher
bf4a31842b new result 2015-05-19 15:50:34 -04:00
Andy Eschbacher
a3c8d7bce4 initial commit 2015-05-19 15:28:17 -04:00
Andy Eschbacher
737dc1c1f1 updated formating of test 2015-05-18 12:12:55 -04:00
Andy Eschbacher
d0c85855f5 fixed test expectation value 2015-05-18 12:00:42 -04:00
Andy Eschbacher
ee1df92561 fixed precision in tests 2015-05-14 15:45:57 -04:00
Andy Eschbacher
16d0dc739a added tests improved func 2015-05-14 15:32:58 -04:00
Andy Eschbacher
dcd35fc3d7 Merge branch 'master' into equalint 2015-05-07 17:07:34 -04:00
Andy Eschbacher
2ad3ff547d initial 2015-05-07 15:49:35 -04:00
Andy Eschbacher
b1e1723e75 Merge pull request #80 from CartoDB/sariogonfer-master
updates quantile bins algorithm
2015-05-07 10:55:19 -04:00
Andy Eschbacher
d9e254dbd5 missed updating value 2015-04-28 10:21:34 -04:00
Andy Eschbacher
7d0efa95fb updated test 2015-04-28 09:59:57 -04:00
Andy Eschbacher
1552c03dd4 removed group by; made binning more reliable 2015-04-27 17:59:40 -04:00
sariogonfer
de418ab36d Merge pull request #1 from sariogonfer/sariogonfer-patch-2
Update CDB_QuantileBins.sql
2015-04-27 12:05:23 +02:00
sariogonfer
cbd3c447b6 Update CDB_QuantileBins.sql 2015-04-14 20:45:37 +02:00
Raul Ochoa
fc95566ddd Remove test for unexistent table as there was already one 2015-03-31 16:01:49 +02:00
Raul Ochoa
7f58e1f690 Adds tests for cdb_tablemetadatatouch
- fixes tableoid by using the proper table oid
 - tests quoted and unqouted call with OID
 - tests non existent table to fail
2015-03-31 14:48:45 +02:00
Rafa de la Torre
ca643b2e03 Merge pull request #75 from CartoDB/73-fix-upgrade-of-cdb-stringtodate
73 fix upgrade of cdb stringtodate
2015-03-03 17:27:45 +01:00
Rafa de la Torre
a7a52a23ea fix indentation of Makefile #73 2015-03-03 16:10:56 +00:00
Rafa de la Torre
1c9e5f241f Fix upgrade of CDB_StringToDate function #73 2015-03-03 16:09:57 +00:00
Raul Ochoa
38d32371c8 Adds test to validate CDB_TableMetadataTouch usage with OID 2015-03-03 12:09:25 +01:00
Rafa de la Torre
e80ea92c57 Merge pull request #74 from CartoDB/73-fix-timestamps
Fix conversion of strings to datetimes #73
2015-03-03 11:03:27 +01:00
Rafa de la Torre
61804187c8 Fix conversion of strings to datetimes #73 2015-03-03 09:49:33 +00:00
Kartones
9114d4e463 #revert-size_calc Stop this madness 2015-02-27 11:08:19 +01:00
Kartones
5db9dc6a9f #revert-size_calc 3KB diff at expected result 2015-02-27 10:58:13 +01:00
Kartones
0a3d08edc3 #revert-size_calc 2015-02-27 10:53:14 +01:00
Raul Ochoa
b913defebb Stubs next version 2015-02-19 14:34:32 +01:00
Raul Ochoa
978742f868 Release 0.7.0 2015-02-19 14:33:21 +01:00
Raul Ochoa
5080e3d985 Merge pull request #71 from CartoDB/CDB_ZoomFromScale
Adds CDB_ZoomFromScale function
2015-02-19 14:28:30 +01:00
Raul Ochoa
cb61fd8747 Enable DB_ZoomFromScale 2015-02-19 14:24:10 +01:00
Raul Ochoa
ebcca141bd Adds CDB_ZoomFromScale function. Closes #62 2015-02-19 14:20:35 +01:00
Raul Ochoa
9d679614c8 Stubs next version 2015-02-19 14:11:54 +01:00
Raul Ochoa
bebebc255a Release 0.6.0 2015-02-19 14:10:15 +01:00
Raul Ochoa
11bf7f6fdf Fix release notes for 0.5.3 2015-02-19 14:09:49 +01:00
Raul Ochoa
05617382a9 Merge pull request #70 from CartoDB/remove-grant-select-from-cdb_tablemetadata-to-public
Remove grant select from cdb tablemetadata to public
2015-02-19 14:04:56 +01:00
Raul Ochoa
f16f53ceab Adds test for non-authorized writes to cdb_tablemetadata through CDB_TableMetadataTouch 2015-02-19 14:02:27 +01:00
Raul Ochoa
27aec0d4b4 Adds tests for qualified table names 2015-02-18 18:01:29 +01:00
Raul Ochoa
f18232037d Release notes and version bump 2015-02-18 17:31:04 +01:00
Raul Ochoa
da7b3b7080 Adds CDB_TableMetadataTouch function to be able to upsert updated_at
value in cdb_tablemetadata
2015-02-18 17:08:46 +01:00
Raul Ochoa
38fe98d983 Merge branch 'master' into remove-grant-select-from-cdb_tablemetadata-to-public 2015-02-18 15:43:16 +01:00
Kartones
39e16ebc59 Update NEWS.md 2015-02-17 16:25:16 +01:00
Kartones
dbc0e069c5 #69 Updated version at makefile 2015-02-17 15:47:18 +01:00
Kartones
6c7706672f #69 now using pg_relation_size 2015-02-17 15:40:26 +01:00
javi
d43e141291 updated news 2015-02-17 11:34:49 +01:00
javi santana
0d5a1c3e49 Merge pull request #68 from CartoDB/fix_querytables
try to fix security problem
2015-02-17 11:27:46 +01:00
javi
519ea075d6 fixed reg exp 2015-02-13 17:32:14 +01:00
javi
0223d00a54 fixed security problem 2015-02-12 10:57:12 +01:00
Raul Ochoa
3cf62ecd2e Do not grant select permission to public user
- Fake the behaviour in tests by switching between users
2015-02-10 15:27:42 +01:00
Rafa de la Torre
ee8a031ea0 Merge pull request #67 from CartoDB/faster-quota-check
Optimize CDB_UserDataSize (on behalf of @javisantana) #65
2015-01-29 18:06:46 +01:00
Rafa de la Torre
f0bf8a85a5 Fix Makefile versioning stuff #65 2015-01-29 16:37:59 +00:00
Rafa de la Torre
693b147ef1 Fix corner case (no tables) in CDB_UserDataSize #65 2015-01-29 15:46:08 +00:00
Rafa de la Torre
73232b8802 Increase version number to 0.5.2 #65 2015-01-29 14:02:38 +00:00
Rafa de la Torre
a4e42571cd Add a comment to CDB_UserDataSize (from PR) #65 2015-01-28 17:10:04 +00:00
Rafa de la Torre
bf622ae5a6 Optimize CDB_UserDataSize (on behalf of @javisantana) #65 2015-01-28 16:54:50 +00:00
Kartones
dbb6f42b99 #1368 fixed escapings 2014-12-05 17:30:47 +01:00
Kartones
626b883cfc Reactivating sh specs after stabilization 2014-11-19 10:53:52 +01:00
Kartones
cd9e44b266 #1138 Fixed DDL triggers to properly use new cartodbfy signature, fixed cartodbfy to properly send params to check raster table 2014-11-19 10:00:04 +01:00
Kartones
fd9d79372f #1138 Found issue with DDL triggers 2014-11-18 19:00:33 +01:00
Kartones
61b47617b8 #1138 fixes for specs 2014-11-18 17:35:11 +01:00
Kartones
3b5c1f65cb #1138 Quota changes, raster import cartodbfication and quota spec 2014-11-18 15:24:54 +01:00
Kartones
b7c2336ae0 #1138 not counting raster overviews for quota 2014-11-14 10:34:18 +01:00
Kartones
6f80b52c92 Merge branch 'master' of github.com:CartoDB/cartodb-postgresql 2014-10-21 16:48:51 +02:00
Kartones
dc6ac7f56b Merge tag '0.4.1'
v0.4.1
2014-10-21 16:48:23 +02:00
Kartones
68e132ade5 Merge pull request #56 from CartoDB/CDB-4418
CDB-4418 CDB_CartodbfyTable does not create Primary Key on cartodb_id
2014-10-21 16:44:41 +02:00
Kartones
c9ff282b17 CDB-4418 2014-10-21 16:37:59 +02:00
Kartones
f251e12d35 CDB-4418 2014-10-21 16:19:44 +02:00
58 changed files with 1493 additions and 111 deletions

View File

@@ -1,7 +1,7 @@
# cartodb/Makefile
EXTENSION = cartodb
EXTVERSION = 0.4.0
EXTVERSION = 0.8.2
SED = sed
@@ -27,6 +27,20 @@ UPGRADABLE = \
0.3.4 \
0.3.5 \
0.3.6 \
0.4.0 \
0.4.1 \
0.5.0 \
0.5.1 \
0.5.2 \
0.5.3 \
0.6.0 \
0.7.0 \
0.7.1 \
0.7.2 \
0.7.3 \
0.7.4 \
0.8.0 \
0.8.1 \
$(EXTVERSION)dev \
$(EXTVERSION)next \
$(END)
@@ -87,21 +101,24 @@ legacy_regress: $(REGRESS_OLD) Makefile
for f in $(REGRESS_OLD); do \
tn=`basename $${f} .sql`; \
of=sql/test/$${tn}.sql; \
echo '\\set ECHO off' > $${of}; \
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 off' > $${exp}; \
echo '\\set ECHO none' > $${exp}; \
cat test/$${tn}_expect >> $${exp}; \
done
test_organization:
bash test/organization/test.sh
test_extension_new:
bash test/extension/test.sh
legacy_tests: legacy_regress
installcheck: legacy_tests test_organization
installcheck: legacy_tests test_extension_new test_organization

67
NEWS.md
View File

@@ -1,3 +1,70 @@
0.8.2 (2015-07-27)
------------------
* Fix for CDB_UserTables returning wrong listings when publicuser is used
0.8.1 (2015-06-30)
------------------
* Fix for [#95](https://github.com/CartoDB/cartodb-postgresql/issues/95) *cdb_usertables should return public tables when the user is publicuser*
0.8.0 (2015-06-30)
------------------
* Adds new function CDB_QueryTablesText that can deal with "schema.table_name"
longer than 63 chars.
* Adds a set of statistical functions:
- CDB_DistType
- CDB_DistinctMeasure
- CDB_EqualIntervalBins
* Fix for CDB_UserTables returns 0 entries for multiuser accounts [#64](https://github.com/CartoDB/cartodb-postgresql/issues/64)
0.7.4 (2015-06-29)
------------------
Dummy transitional version.
0.7.3 (2015-03-03)
------------------
* Fix upgrade of CDB_StringToDate function
* Add a test for to validate CDB_TableMetadataTouch usage with OID
0.7.2 (2015-03-03)
------------------
* Fix conversion of strings to datetime
0.7.1 (2015-02-27)
------------------
* Revert quota checks to `pg_total_relation_size`
0.7.0 (2015-02-19)
------------------
* Adds CDB_ZoomFromScale function
0.6.0 (2015-02-19)
------------------
* Select permission in CDB_TableMetadata no longer granted to public
* New function to upsert the updated_at in CDB_TableMetadata for a regclass
0.5.3 (2015-02-17)
------------------
* Fixed security problem related with system tables
* Changed quota checks to use `pg_relation_size` instead of `pg_total_relation_size`
0.5.2 (2015-01-29)
------------------
* Improvement: make CDB_UserDataSize functions much faster.
0.5.1 (2014-11-21)
------------------
* Bugfix: Quota check and some organization permissions functions were not properly escaping table name.
0.5.0 (2014-11-03)
------------------
* Support of raster tables for cartodbfication
* Modified quota functions: vector tables stay the same, raster tables count as full size (as have no
the_geom + the_geom_webmercator combo) and raster overviews are not counted
0.4.1 (2014-09-21)
------------------
* Bugfix for Cartodbfication: Set primary key of the table if not already present (e.g. tables created from SQL API)
0.4.0 (2014-08-27)
------------------
Added CDB_Math_Mode function

View File

@@ -11,7 +11,7 @@ See https://github.com/CartoDB/cartodb/wiki/CartoDB-PostgreSQL-extension
Dependencies
------------
* PostgreSQL 9.3+ (with plpythonu extension)
* PostgreSQL 9.3+ (with plpythonu extension and xml support)
* [PostGIS extension](http://postgis.net)
* [Schema triggers extension]
(https://bitbucket.org/malloclabs/pg_schema_triggers)

14
doc/CDB_ColumnNames.md Normal file
View File

@@ -0,0 +1,14 @@
Retrieve all column names in a particular table
#### Using the function
```sql
SELECT CDB_ColumnNames('table_name')
--- Returns a set of rows with column names
```
#### Arguments
CDB_ColumnNames(table_name)
* **table_name** text

15
doc/CDB_ColumnType.md Normal file
View File

@@ -0,0 +1,15 @@
Returns a column type for any column in a table
#### Using the function
```sql
SELECT CDB_ColumnType('column_name','table_name')
--- Returns a set of rows with column types
```
#### Arguments
CDB_ColumnType(column_name, table_name)
* **column_name** text
* **table_name** text

21
doc/CDB_HeadsTailsBins.md Normal file
View File

@@ -0,0 +1,21 @@
Find the breaks for N categories in a numerical column based on the [Heads/Tails optimization](http://arxiv.org/pdf/1209.2801v1.pdf). Below, Heads/Tails used to color based on the area of the polygons.
![headtails](https://f.cloud.github.com/assets/370259/140655/6eebb918-7228-11e2-89fa-149745f25d34.png)
#### Using the function
We can determine the 7 most optimal breaks in a column of numerical data as follows,
```sql
SELECT CDB_HeadsTailsBins(array_agg(numeric_column), 7) FROM table_name
-- Results in an ordered array like, {7824,23492,52696,233857,666089,1001709,1638094}
-- Each break happens up to, and equal, to a number:
-- (bin1 is less than or equal to 7824, bin2 is less than or equal to 23492, etc.)
```
#### Arguments
CDB_HeadsTailsBins(in_array, breaks)
* **in_array** numeric[]. A NUMERIC array of values.
* **breaks** int. The number of categories you want to create

43
doc/CDB_HexagonGrid.md Normal file
View File

@@ -0,0 +1,43 @@
Fill given extent with an hexagonal coverage
#### Using the function
Create a hexagonal grid from a polygon geometry. For example, take the geometry
```sql
ST_SetSRID(
ST_Envelope(
ST_Collect(
ST_MakePoint(10000000,-10000000),
ST_MakePoint(-10000000,10000000)
)
),
3857)
```
We can create a grid as follows,
```sql
SELECT CDB_HexagonGrid(
ST_SetSRID(
ST_Envelope(
ST_Collect(
ST_MakePoint(10000000,-10000000),
ST_MakePoint(-10000000,10000000)
)
),
3857),
1000000) the_geom_webmercator
```
Which will look something like this,
![grid tile](http://i.imgur.com/4rZXGMb.png)
#### Arguments
CDB_HexagonGrid(ext, side, origin)
* **ext** geometry. Extent to fill. Only hexagons with center point falling inside the extent (or at the lower or leftmost edge) will be emitted. The returned hexagons will have the same SRID as this extent.
* **side** float. Side measure for the hexagon. Maximum diameter will be 2 * side. Measure is in the same projection as **ext**
* **origin** OPTIONAL geometry. Optional origin to allow for exact tiling. If omitted the origin will be 0,0. The parameter is checked for having the same SRID as the extent.

23
doc/CDB_JenksBins.md Normal file
View File

@@ -0,0 +1,23 @@
Find the breaks for N categories in a numerical column based on the [Jenks optimization](http://en.wikipedia.org/wiki/Jenks_natural_breaks_optimization). Below, Jenks used to color based on the area of the polygons.
![Jenks](https://f.cloud.github.com/assets/370259/140093/b64a9382-7210-11e2-81a4-c65cce3c885e.png)
#### Using the function
We can determine the 7 most optimal breaks in a column of numerical data as follows,
```sql
SELECT CDB_JenksBins(array_agg(numeric_column), 7) FROM table_name
-- Results in an ordered array like, {0,73,2568,9408,29411,768230,1638094}
-- Each break happens up to, and equal, to a number:
-- (bin1 is less than or equal to 0, bin2 is less than or equal to 73, etc.)
```
#### Arguments
CDB_JenksBins(in_array, breaks, invert)
* **in_array** numeric[]. A NUMERIC array of values.
* **breaks** int. The number of categories you want to create
* **iterations** OPTIONAL int. The number of iterations used for calculating breaks.
* **invert** OPTIONAL boolean. Flips whether you receive top down breaks or bottom up breaks. Default is top down (so, <=). Bottom up would give you values that define the lower-end start of a bin (so >=).

21
doc/CDB_MakeHexagon.md Normal file
View File

@@ -0,0 +1,21 @@
Return an Hexagon with given center and side (or maximal radius)
#### Using the function
Running the following SQL
```sql
SELECT CDB_MakeHexagon(ST_MakePoint(0,0),10000000)
```
Would give you back a single hexagon geometry,
![hexagon](http://i.imgur.com/6jeGStb.png)
#### Arguments
CDB_MakeHexagon(center, radius)
* **center** geometry
* **radius** float. Radius of hexagon measured in same projection as **center**

21
doc/CDB_QuantileBins.md Normal file
View File

@@ -0,0 +1,21 @@
Find the breaks for N categories in a numerical column based on the [Quantile bins]. Below, the quantile method is used to determine color based on the area of the polygons.
![qunatile](https://f.cloud.github.com/assets/370259/140714/932ed0e6-722b-11e2-9807-ffbd0fddb9ac.png)
#### Using the function
We can determine the 7 most optimal breaks in a column of numerical data as follows,
```sql
SELECT CDB_QuantileBins(array_agg(numeric_column), 7) FROM table_name
-- Results in an ordered array like, {80,2281,7162,17652,39730,91077,1638094}
-- Each break happens up to, and equal, to a number:
-- (bin1 is less than or equal to 80, bin2 is less than or equal to 2281, etc.)
```
#### Arguments
CDB_QuantileBins(in_array, breaks)
* **in_array** numeric[]. A NUMERIC array of values.
* **breaks** int. The number of categories you want to create

46
doc/CDB_RectangleGrid.md Normal file
View File

@@ -0,0 +1,46 @@
Fill given extent with a rectangular coverage
#### Using the function
Create a rectangular grid from a polygon geometry. For example, take the geometry
```sql
ST_SetSRID(
ST_Envelope(
ST_Collect(
ST_MakePoint(10000000,-10000000),
ST_MakePoint(-10000000,10000000)
)
),
3857)
```
We can create a grid as follows,
```sql
SELECT CDB_RectangleGrid(
ST_SetSRID(
ST_Envelope(
ST_Collect(
ST_MakePoint(10000000,-10000000),
ST_MakePoint(-10000000,10000000)
)
),
3857),
1000000,
1000000
) the_geom_webmercator
```
Which will look something like this,
![rect grid](http://i.imgur.com/HuhOJRs.png)
#### Arguments
CDB_RectangleGrid(ext, width, height, origin)
* **ext** geometry. Extent to fill. Only rectangles with center point falling inside the extent (or at the lower or leftmost edge) will be emitted. The returned hexagons will have the same SRID as this extent.
* **width** float. Width of each rectangle. Measure is in the same projection as **ext**
* **height** float. Height of each rectangle. Measure is in the same projection as **ext**
* **origin** OPTIONAL geometry. Optional origin to allow for exact tiling. If omitted the origin will be 0,0. The parameter is checked for having the same SRID as the extent.

View File

@@ -0,0 +1,11 @@
Sets user quota in bytes (superuser only)
#### Using the function
```sql
SELECT CDB_SetUserQuotaInBytes(10485760);
--- Returns the previously set quota.
--- Use 0 to disable quota.
```
REF: https://github.com/CartoDB/cartodb-postgresql/blob/master/scripts-available/CDB_Quota.sql

View File

@@ -0,0 +1,44 @@
Function to "safely" transform to webmercator. This function is most useful for rendering custom geometries using the CartoDB tiler. Often, transforming a projection like WGS84 can cause issues with extents beyond what are actually valid in webmercator, this attempts to fix those issues.
#### Using the function
Using a box that is nearly the full globe,
```sql
ST_SetSRID(
ST_Envelope(
ST_Collect(
ST_MakePoint(-180,60),
ST_MakePoint(180,-60)
)
),
4326
)
```
We can then convert it to a renderable webmercator geometry.
```sql
SELECT CDB_TransformToWebmercator(
ST_SetSRID(
ST_Envelope(
ST_Collect(
ST_MakePoint(-10,60),
ST_MakePoint(300,-60)
)
),
4326
)
)
```
Would give you back a single valid rectangle in webmercator. Since a longitude of 300 would convert to an unallowed webmercator coordinate, it gets clipped first. Valid extent is WGS84 (-180, -89, 180, 89)
![valid geom](http://i.imgur.com/EFdXiqt.png)
#### Arguments
CDB_TransformToWebmercator(geom)
* **geom** geometry

11
doc/CDB_UserTables.md Normal file
View File

@@ -0,0 +1,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
--- Currently accepted permissions are: 'public', 'private' or 'all'
SELECT CDB_UserTables(perms)
```
REF: https://github.com/CartoDB/cartodb-postgresql/blob/master/scripts-available/CDB_UserTables.sql

22
doc/CDB_XYZ_Extent.md Normal file
View File

@@ -0,0 +1,22 @@
Determine the spatial extent of a tile based on the tile's XYZ coordinate.
#### Using the function
Take a common tile with coordinates x=3, y=2, z=2,
![2/3/2](https://viz2.cartodb.com/tiles/quantile_breaks/2/3/2.png)
To determine its extent you would run,
```sql
SELECT CDB_XYZ_Extent(3,2,2)
--- Returns a WKB polygon in Webmercator (SRID 3857)
```
#### Arguments
CDB_XYZ_Extent(x,y,z)
* **x** integer
* **y** integer
* **z** integer

20
doc/CDB_XYZ_Resolution.md Normal file
View File

@@ -0,0 +1,20 @@
Return pixel resolution of tiles at a given zoom level
#### Using the function
Take a common tile with zoom, z=2,
![2/3/2](https://viz2.cartodb.com/tiles/quantile_breaks/2/3/2.png)
To determine the resolution of these pixels,
```sql
SELECT CDB_XYZ_Resolution(2)
--- Returns a float, 39135.7587890625
```
#### Arguments
CDB_XYZ_Resolution(z)
* **z** integer

38
doc/CartoDB-PLpgSQL.md Normal file
View File

@@ -0,0 +1,38 @@
INTRODUCTION
============
CartoDB uses a number of custom [PLpgSQL](http://www.postgresql.org/docs/8.3/static/plpgsql.html) functions to perform a few magical things. Those functions are accessible to users on CartoDB as well, so we would like to document what they are and what they do here.
## Spatial functions
[CDB_HexagonGrid](CDB_HexagonGrid) - create hexagonal grid from extent and size
[CDB_MakeHexagon](CDB_MakeHexagon) - make a hexagon with given center and side
[CDB_RectangleGrid](CDB_RectangleGrid) - fill given extent with a rectangular coverage
##### Tile based
[CDB_XYZ_Extent](CDB_XYZ_Extent) - Find the extent of a tile by XYZ
[CDB_XYZ_Resolution](CDB_XYZ_Resolution) - Find the pixel resolution of tiles
[CDB_TransformToWebmercator](CDB_TransformToWebmercator) - Convert a geometry to valid webmercator
## Statistical functions
[CDB_JenksBins](CDB_JenksBins) - Find breaks in an array of numbers using Jenks method
[CDB_HeadsTailsBins](CDB_HeadsTailsBins) - Find breaks in an array of numbers using Heads/Tails method
[CDB_QuantileBins](CDB_QuantileBins) - Find quantile breaks in an array of numbers
## System functions
[CDB_UserTables](CDB_UserTables) - Get a list of all tables in your account
[[CDB_SetUserQuotaInBytes]] - Set maximum user quota in bytes
column names - now returned in JSON response
column types - now returned in JSON response

29
doc/CartoDB-user-table.md Normal file
View File

@@ -0,0 +1,29 @@
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

48
doc/README.md Normal file
View File

@@ -0,0 +1,48 @@
# Contents
* [CartoDB-user-table](CartoDB-user-table.md)
* [CartoDB-PLpgSQL](CartoDB-PLpgSQL.md)
* [CDB_ColumnNames](CDB_ColumnNames.md)
* [CDB_ColumnType](CDB_ColumnType.md)
* [CDB_HeadsTailsBins](CDB_HeadsTailsBins.md)
* [CDB_HexagonGrid](CDB_HexagonGrid.md)
* [CDB_JenksBins](CDB_JenksBins.md)
* [CDB_MakeHexagon](CDB_MakeHexagon.md)
* [CDB_QuantileBins](CDB_QuantileBins.md)
* [CDB_RectangleGrid](CDB_RectangleGrid.md)
* [CDB_SetUserQuotaInBytes](CDB_SetUserQuotaInBytes.md)
* [CDB_TransformToWebmercator](CDB_TransformToWebmercator.md)
* [CDB_UserTables](CDB_UserTables.md)
* [CDB_XYZ_Extent](CDB_XYZ_Extent.md)
* [CDB_XYZ_Resolution](CDB_XYZ_Resolution.md)
The CartoDB PostgreSQL extension is a module to load into each CartoDB user database to perform cartodb-specific security and functionality checks.
# 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

@@ -19,6 +19,12 @@ NOTICE: event trigger "cdb_on_add_column" does not exist, skipping
(1 row)
create schema c;
SELECT CDB_SetUserQuotaInBytes('c', 0);
cdb_setuserquotainbytes
-------------------------
0
(1 row)
CREATE USER cartodb_postgresql_unpriv_user;
GRANT ALL ON SCHEMA c to cartodb_postgresql_unpriv_user;
SET SESSION AUTHORIZATION 'cartodb_postgresql_unpriv_user';
@@ -26,6 +32,7 @@ SET SESSION AUTHORIZATION 'cartodb_postgresql_unpriv_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
@@ -49,6 +56,7 @@ from c.t3;
1 | t | t | | | 1
(1 row)
RESET SESSION AUTHORIZATION;
select
tabname::text,
round(extract('secs' from now() - updated_at)) as age
@@ -58,6 +66,7 @@ FROM CDB_TableMetadata WHERE tabname = 'c.t3'::regclass;
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;
@@ -85,6 +94,7 @@ from c.t4;
1 | t | t | |
(1 row)
RESET SESSION AUTHORIZATION;
select
tabname::text,
round(extract('secs' from now() - updated_at)) as age
@@ -97,6 +107,7 @@ FROM CDB_TableMetadata WHERE tabname = 'c.t4'::regclass;
----------------------------
-- ALTER TABLE RENAME COLUMN
----------------------------
SET SESSION AUTHORIZATION 'cartodb_postgresql_unpriv_user';
select pg_sleep(.1);
pg_sleep
----------
@@ -125,6 +136,7 @@ from c.t3;
1 | t | t | | | 1 |
(1 row)
RESET SESSION AUTHORIZATION;
select
tabname::text,
round(extract('secs' from now() - updated_at)*10) as agecs
@@ -134,6 +146,7 @@ FROM CDB_TableMetadata WHERE tabname = 'c.t3'::regclass;
c.t3 | 0
(1 row)
SET SESSION AUTHORIZATION 'cartodb_postgresql_unpriv_user';
select pg_sleep(.1);
pg_sleep
----------
@@ -162,6 +175,7 @@ from c.t3;
1 | t | t | | | 1 | |
(1 row)
RESET SESSION AUTHORIZATION;
select
tabname::text,
round(extract('secs' from now() - updated_at)*10) as agecs
@@ -174,6 +188,7 @@ FROM CDB_TableMetadata WHERE tabname = 'c.t3'::regclass;
----------------------------
-- ALTER TABLE DROP COLUMN
----------------------------
SET SESSION AUTHORIZATION 'cartodb_postgresql_unpriv_user';
select pg_sleep(.1);
pg_sleep
----------
@@ -202,6 +217,7 @@ from c.t3;
1 | t | t | | | 1 | |
(1 row)
RESET SESSION AUTHORIZATION;
select
tabname::text,
round(extract('secs' from now() - updated_at)*10) as agecs
@@ -214,6 +230,7 @@ FROM CDB_TableMetadata WHERE tabname = 'c.t3'::regclass;
----------------------------
-- ALTER TABLE ADD COLUMN
----------------------------
SET SESSION AUTHORIZATION 'cartodb_postgresql_unpriv_user';
select pg_sleep(.1);
pg_sleep
----------
@@ -233,6 +250,7 @@ from c.t3;
1 | t | t | | | 1 | | |
(1 row)
RESET SESSION AUTHORIZATION;
select
tabname::text,
round(extract('secs' from now() - updated_at)*10) as agecs
@@ -247,7 +265,7 @@ FROM CDB_TableMetadata WHERE tabname = 'c.t3'::regclass;
----------------------------
RESET SESSION AUTHORIZATION;
drop schema c cascade;
NOTICE: drop cascades to 2 other objects
NOTICE: drop cascades to 3 other objects
select count(*) from CDB_TableMetadata;
count
-------

View File

@@ -1,10 +1,10 @@
-- Depends on:
-- * CDB_ExtensionUtils.sql
-- * CDB_TransformToWebmercator.sql
-- * CDB_TableMetadata.sql
-- * CDB_Quota.sql
-- * _CDB_UserQuotaInBytes() function, installed by rails
-- (user.rebuild_quota_trigger, called by rake task
-- cartodb:db:update_test_quota_trigger)
-- (user.rebuild_quota_trigger, called by rake task cartodb:db:update_test_quota_trigger)
-- 1) Required checks before running cartodbfication
-- Either will pass silenty or raise an exception
@@ -22,7 +22,7 @@ BEGIN
BEGIN
EXECUTE FORMAT('SELECT %I._CDB_UserQuotaInBytes();', schema_name::text) INTO sql;
EXCEPTION WHEN undefined_function THEN
RAISE EXCEPTION 'Please set user quota before cartodbfying tables.';
RAISE EXCEPTION 'Please set user quota before cartodbfying tables.';
END;
END;
$$ LANGUAGE PLPGSQL;
@@ -67,6 +67,7 @@ DECLARE
had_column BOOLEAN;
i INTEGER;
new_name TEXT;
cartodb_id_name TEXT;
BEGIN
<< cartodb_id_setup >>
LOOP --{
@@ -75,6 +76,7 @@ BEGIN
sql := 'ALTER TABLE ' || reloid::text || ' ADD cartodb_id SERIAL NOT NULL UNIQUE';
RAISE DEBUG 'Running %', sql;
EXECUTE sql;
cartodb_id_name := 'cartodb_id';
EXIT cartodb_id_setup;
EXCEPTION
WHEN duplicate_column THEN
@@ -114,6 +116,7 @@ BEGIN
BEGIN
RAISE DEBUG 'Running %', sql;
EXECUTE sql;
cartodb_id_name := 'cartodb_id';
EXIT cartodb_id_setup;
EXCEPTION
WHEN unique_violation OR not_null_violation THEN
@@ -139,13 +142,14 @@ BEGIN
WHEN others THEN
RAISE EXCEPTION 'Cartodbfying % (renaming cartodb_id): % (%)', reloid, SQLERRM, SQLSTATE;
END;
cartodb_id_name := new_name;
EXIT rename_column;
END LOOP; --}
CONTINUE cartodb_id_setup;
END IF;
END LOOP; -- }
-- Try to copy data from new name if possible
-- Try to copy data from new name if possible
IF new_name IS NOT NULL THEN
RAISE NOTICE 'Trying to recover data from % column', new_name;
BEGIN
@@ -185,6 +189,18 @@ BEGIN
END;
END IF;
-- Set primary key of the table if not already present (e.g. tables created from SQL API)
IF cartodb_id_name IS NULL THEN
RAISE EXCEPTION 'Cartodbfying % (Didnt get cartodb_id field name)', reloid;
END IF;
BEGIN
sql := 'ALTER TABLE ' || reloid::text || ' ADD PRIMARY KEY (cartodb_id)';
EXECUTE sql;
EXCEPTION
WHEN others THEN
RAISE DEBUG 'Table % Already had PRIMARY KEY', reloid;
END;
END;
$$ LANGUAGE PLPGSQL;
@@ -450,7 +466,7 @@ END;
$$ LANGUAGE PLPGSQL;
-- 8) Create all triggers
-- 8.a) Create all triggers
-- NOTE: drop/create has the side-effect of re-enabling disabled triggers
CREATE OR REPLACE FUNCTION _CDB_create_triggers(schema_name TEXT, reloid REGCLASS)
RETURNS void
@@ -496,6 +512,46 @@ BEGIN
END;
$$ LANGUAGE PLPGSQL;
-- 8.b) Create all raster triggers
-- NOTE: drop/create has the side-effect of re-enabling disabled triggers
CREATE OR REPLACE FUNCTION _CDB_create_raster_triggers(schema_name TEXT, reloid REGCLASS)
RETURNS void
AS $$
DECLARE
sql TEXT;
BEGIN
-- "track_updates"
sql := 'CREATE trigger track_updates AFTER INSERT OR UPDATE OR DELETE OR TRUNCATE ON '
|| reloid::text
|| ' FOR EACH STATEMENT EXECUTE PROCEDURE public.cdb_tablemetadata_trigger()';
EXECUTE sql;
-- "update_updated_at"
-- TODO: why _before_ and not after ?
sql := 'CREATE trigger update_updated_at_trigger BEFORE UPDATE ON '
|| reloid::text
|| ' FOR EACH ROW EXECUTE PROCEDURE public._CDB_update_updated_at()';
EXECUTE sql;
-- "test_quota" and "test_quota_per_row"
sql := 'CREATE TRIGGER test_quota BEFORE UPDATE OR INSERT ON '
|| reloid::text
|| ' EXECUTE PROCEDURE public.CDB_CheckQuota(1, ''-1'', '''
|| schema_name::text
|| ''')';
EXECUTE sql;
sql := 'CREATE TRIGGER test_quota_per_row BEFORE UPDATE OR INSERT ON '
|| reloid::text
|| ' FOR EACH ROW EXECUTE PROCEDURE public.CDB_CheckQuota(0.001, ''-1'', '''
|| schema_name::text
|| ''')';
EXECUTE sql;
END;
$$ LANGUAGE PLPGSQL;
-- Update the_geom_webmercator
CREATE OR REPLACE FUNCTION _CDB_update_the_geom_webmercator()
@@ -516,15 +572,50 @@ END;
$$ LANGUAGE plpgsql VOLATILE;
-- Auxiliary function
CREATE OR REPLACE FUNCTION cartodb._CDB_is_raster_table(schema_name TEXT, reloid REGCLASS)
RETURNS BOOLEAN
AS $$
DECLARE
sql TEXT;
is_raster BOOLEAN;
rel_name TEXT;
BEGIN
IF cartodb.schema_exists(schema_name) = FALSE THEN
RAISE EXCEPTION 'Invalid schema name "%"', schema_name;
END IF;
SELECT relname FROM pg_class WHERE oid=reloid INTO rel_name;
BEGIN
sql := 'SELECT the_raster_webmercator FROM '
|| quote_ident(schema_name::TEXT)
|| '.'
|| quote_ident(rel_name::TEXT)
|| ' LIMIT 1';
is_raster = TRUE;
EXECUTE sql;
EXCEPTION WHEN undefined_column THEN
is_raster = FALSE;
END;
RETURN is_raster;
END;
$$ LANGUAGE PLPGSQL;
-- ////////////////////////////////////////////////////
-- Ensure a table is a "cartodb" table
-- See https://github.com/CartoDB/cartodb/wiki/CartoDB-user-table
-- Ensure a table is a "cartodb" table (See https://github.com/CartoDB/cartodb/wiki/CartoDB-user-table)
-- Rails code replicates this call at User.cartodbfy()
CREATE OR REPLACE FUNCTION CDB_CartodbfyTable(schema_name TEXT, reloid REGCLASS)
RETURNS void
AS $$
DECLARE
exists_geom_cols BOOLEAN[];
is_raster BOOLEAN;
BEGIN
PERFORM cartodb._CDB_check_prerequisites(schema_name, reloid);
@@ -534,13 +625,19 @@ BEGIN
-- Ensure required fields exist
PERFORM cartodb._CDB_create_cartodb_id_column(reloid);
PERFORM cartodb._CDB_create_timestamp_columns(reloid);
SELECT cartodb._CDB_create_the_geom_columns(reloid) INTO exists_geom_cols;
-- Both only populate if proceeds
PERFORM cartodb._CDB_populate_the_geom_from_the_geom_webmercator(reloid, exists_geom_cols);
PERFORM cartodb._CDB_populate_the_geom_webmercator_from_the_geom(reloid, exists_geom_cols);
SELECT cartodb._CDB_is_raster_table(schema_name, reloid) INTO is_raster;
IF is_raster THEN
PERFORM cartodb._CDB_create_raster_triggers(schema_name, reloid);
ELSE
SELECT cartodb._CDB_create_the_geom_columns(reloid) INTO exists_geom_cols;
PERFORM cartodb._CDB_create_triggers(schema_name, reloid);
-- Both only populate if proceeds
PERFORM cartodb._CDB_populate_the_geom_from_the_geom_webmercator(reloid, exists_geom_cols);
PERFORM cartodb._CDB_populate_the_geom_webmercator_from_the_geom(reloid, exists_geom_cols);
PERFORM cartodb._CDB_create_triggers(schema_name, reloid);
END IF;
END;
$$ LANGUAGE PLPGSQL;

View File

@@ -4,14 +4,17 @@ CREATE OR REPLACE FUNCTION cartodb.cdb_handle_create_table ()
RETURNS event_trigger SECURITY DEFINER LANGUAGE plpgsql AS $$
DECLARE
event_info RECORD;
rel_namespace TEXT;
BEGIN
event_info := schema_triggers.get_relation_create_eventinfo();
-- We're only interested in real relations
IF (event_info.new).relkind != 'r' THEN RETURN; END IF;
RAISE DEBUG 'Relation % of kind % created in namespace oid %',
event_info.relation, (event_info.new).relkind, (event_info.new).relnamespace;
SELECT nspname FROM pg_namespace WHERE oid=(event_info.new).relnamespace INTO rel_namespace;
RAISE DEBUG 'Relation % of kind % created in table % namespace % (oid %)',
event_info.relation, (event_info.new).relkind, (event_info.new).relname::TEXT, rel_namespace, (event_info.new).relnamespace;
-- We don't want to react to alters triggered by superuser,
IF current_setting('is_superuser') = 'on' THEN
@@ -22,7 +25,7 @@ BEGIN
PERFORM cartodb.cdb_disable_ddl_hooks();
-- CDB_CartodbfyTable must not create tables, or infinite loop will happen
PERFORM cartodb.CDB_CartodbfyTable(event_info.relation);
PERFORM cartodb.CDB_CartodbfyTable(rel_namespace, event_info.relation);
PERFORM cartodb.cdb_enable_ddl_hooks();
@@ -63,6 +66,7 @@ RETURNS event_trigger SECURITY DEFINER LANGUAGE plpgsql AS $$
DECLARE
event_info RECORD;
rel RECORD;
rel_namespace TEXT;
BEGIN
event_info := schema_triggers.get_column_alter_eventinfo();
@@ -80,9 +84,11 @@ BEGIN
RETURN;
END IF;
SELECT nspname FROM pg_namespace WHERE oid = rel.relnamespace INTO rel_namespace;
PERFORM cartodb.cdb_disable_ddl_hooks();
PERFORM cartodb.CDB_CartodbfyTable(event_info.relation);
PERFORM cartodb.CDB_CartodbfyTable(rel_namespace, event_info.relation);
PERFORM cartodb.cdb_enable_ddl_hooks();
@@ -100,6 +106,7 @@ RETURNS event_trigger SECURITY DEFINER LANGUAGE plpgsql AS $$
DECLARE
event_info RECORD;
rel RECORD;
rel_namespace TEXT;
BEGIN
event_info := schema_triggers.get_column_drop_eventinfo();
@@ -117,9 +124,11 @@ BEGIN
RETURN;
END IF;
SELECT nspname FROM pg_namespace WHERE oid = rel.relnamespace INTO rel_namespace;
PERFORM cartodb.cdb_disable_ddl_hooks();
PERFORM cartodb.CDB_CartodbfyTable(event_info.relation);
PERFORM cartodb.CDB_CartodbfyTable(rel_namespace, event_info.relation);
PERFORM cartodb.cdb_enable_ddl_hooks();

View File

@@ -0,0 +1,122 @@
--
-- CDB_DistType classifies the histograms of a column into
-- one of the basic types listed by Galtung: http://druedin.com/2012/12/08/galtungs-ajus-system/
--
-- Future improvements:
-- variable number of bins (7 is baked in right now)
-- catch the number of items to ensure that the sample is large enough
--
-- Refs:
-- 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 $$
DECLARE
element_count INT4;
minv numeric;
maxv numeric;
bins numeric[];
freqs numeric[];
ajus INT[];
freq INT4;
signature text;
i INT := 1;
BEGIN
SELECT min(e), max(e), count(e) INTO minv, maxv, element_count FROM ( SELECT unnest(in_array) e ) x;
IF abs(maxv - minv) < 1e-7 THEN -- if max and min are nearly equal, call if 'F' (make relative to maxv?)
signature = 'F';
ELSE
-- Calculate bins and count in bins
EXECUTE 'WITH stats as (
SELECT min(e) as minv,
max(e) as maxv,
count(e) as total
FROM (SELECT unnest($1) e) x
WHERE e is not null
),
hist as (
SELECT width_bucket(e, s.minv, s.maxv, 7) bucket,
count(*) freq
FROM (SELECT unnest($1) e) x, stats s
WHERE e is not null
GROUP BY 1
ORDER BY 1
)
SELECT array_agg(round(100.0 * hist.freq::numeric / stats.total::numeric,1)) freqs,
array_agg(hist.bucket) buckets
FROM hist, stats'
INTO freqs, bins
USING in_array;
LOOP
IF i < 7 THEN
ajus[i] = CASE WHEN freqs[i] > freqs[i+1] THEN -1
WHEN abs(freqs[i] - freqs[i+1]) <= 0.05 THEN 0
ELSE 1 END;
ELSE
EXIT;
END IF;
i := i + 1;
END LOOP;
signature = _CDB_DistTypeClassify(ajus);
END IF;
RETURN signature;
END;
$$ language plpgsql IMMUTABLE;
-- Classify data into AJUSFL
CREATE OR REPLACE FUNCTION _CDB_DistTypeClassify ( in_array INT[] ) RETURNS text as $$
DECLARE
element_count INT4;
maxv numeric;
minv numeric;
uniques INT[];
type text;
BEGIN
SELECT max(e), min(e) INTO maxv, minv FROM ( SELECT unnest(in_array) e ) x;
IF (maxv = 0 AND minv = 0) THEN
type = 'F';
ELSIF maxv < 1 THEN
type = 'L';
ELSIF minv > -1 THEN
type = 'J';
ELSE
-- Get distinct elements ordered by original position
EXECUTE 'WITH b AS (
SELECT a
FROM (SELECT unnest($1) a) x
),
c AS (
SELECT a, row_number() OVER () r
FROM b
),
d AS (
SELECT DISTINCT a
FROM c
),
e AS (
SELECT a FROM d ORDER BY (
SELECT r FROM c WHERE d.a = c.a ORDER BY r ASC LIMIT 1
) ASC)
SELECT array_agg(a) FROM e'
INTO uniques
USING in_array;
-- Decide if it's an A, U, or other
IF (uniques = ARRAY[1,-1] OR uniques = ARRAY[1,0,-1] OR uniques = ARRAY[1,-1,0] OR uniques = ARRAY[0,1,-1]) THEN
type = 'A';
ELSIF (uniques = ARRAY[-1,1] OR uniques = ARRAY[-1,0,1] OR uniques = ARRAY[-1,1,0] OR uniques = ARRAY[0,-1,1]) THEN
type = 'U';
ELSE
type = 'S';
END IF;
END IF;
RETURN type;
END;
$$ language plpgsql IMMUTABLE;

View File

@@ -0,0 +1,46 @@
--
-- CDB_DistinctMeasure
-- calculates the fraction of rows in the 10 most common distinct categories
-- returns true if the number of rows in these 10 categories is >= 0.9 * total number of rows
--
--
CREATE OR REPLACE FUNCTION CDB_DistinctMeasure ( in_array text[], threshold numeric DEFAULT null ) RETURNS numeric as $$
DECLARE
element_count INT4;
maxval numeric;
passes numeric;
BEGIN
SELECT count(e) INTO element_count FROM ( SELECT unnest(in_array) e ) x;
-- count number of occurrences per bin
-- calculate the normalized cumulative sum
-- return the max value: which corresponds nth entry
-- for n <= 10 depending on # of distinct values
EXECUTE 'WITH a As (
SELECT
count(*) cnt
FROM
(SELECT * FROM unnest($2) e ) x
WHERE e is not null
GROUP BY e
ORDER BY cnt DESC
),
b As (
SELECT
sum(cnt) OVER (ORDER BY cnt DESC) / $1 As cumsum
FROM a
LIMIT 10
)
SELECT max(cumsum) maxval FROM b'
INTO maxval
USING element_count, in_array;
IF threshold is null THEN
passes = maxval;
ELSE
passes = CASE WHEN (maxval >= threshold) THEN 1 ELSE 0 END;
END IF;
RETURN passes;
END;
$$ language plpgsql IMMUTABLE;

View File

@@ -0,0 +1,37 @@
--
-- 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 breaks The number of bins you want to find.
--
--
-- Returns: upper edges of bins
--
--
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;

View File

@@ -35,7 +35,7 @@ FUNCTION cartodb.CDB_Organization_Add_Table_Read_Permission(from_schema text, ta
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 || '"';
EXECUTE 'GRANT SELECT ON "' || from_schema || '"."' || table_name || '" TO "' || to_role_name || '"';
END
$$ LANGUAGE PLPGSQL VOLATILE;
@@ -54,7 +54,7 @@ FUNCTION cartodb.CDB_Organization_Add_Table_Read_Write_Permission(from_schema te
AS $$
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 || '"';
EXECUTE 'GRANT SELECT, INSERT, UPDATE, DELETE ON "' || from_schema || '"."' || table_name || '" TO "' || to_role_name || '"';
END
$$ LANGUAGE PLPGSQL VOLATILE;
@@ -73,7 +73,7 @@ FUNCTION cartodb.CDB_Organization_Remove_Access_Permission(from_schema text, tab
RETURNS void
AS $$
BEGIN
EXECUTE 'REVOKE ALL PRIVILEGES ON TABLE "' || from_schema || '".' || table_name || ' FROM "' || to_role_name || '"';
EXECUTE 'REVOKE ALL PRIVILEGES ON TABLE "' || from_schema || '"."' || table_name || '" FROM "' || to_role_name || '"';
-- EXECUTE 'REVOKE USAGE ON SCHEMA ' || from_schema || ' FROM "' || to_role_name || '"';
-- 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

View File

@@ -15,18 +15,29 @@ DECLARE
i INT := 1;
reply numeric[];
BEGIN
-- get our unique values
SELECT array_agg(e) INTO in_array FROM (SELECT unnest(in_array) e GROUP BY e ORDER BY e ASC) x;
-- get the total size of our row
element_count := array_upper(in_array, 1) - array_lower(in_array, 1);
-- 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 EXIT; END IF;
SELECT e INTO tmp_val FROM ( SELECT unnest(in_array) e LIMIT 1 OFFSET round(break_size * i)) x;
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;
i := i+1;
END LOOP;
RETURN reply;
END;
$$ language plpgsql IMMUTABLE;
$$ language plpgsql IMMUTABLE;

View File

@@ -2,12 +2,12 @@
--
-- Requires PostgreSQL 9.x+
--
CREATE OR REPLACE FUNCTION CDB_QueryTables(query text)
RETURNS name[]
CREATE OR REPLACE FUNCTION CDB_QueryTablesText(query text)
RETURNS text[]
AS $$
DECLARE
exp XML;
tables NAME[];
tables text[];
rec RECORD;
rec2 RECORD;
BEGIN
@@ -16,9 +16,9 @@ BEGIN
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;
IF NOT ( rec.q ilike 'select%' or rec.q ilike 'with%' ) THEN
--RAISE WARNING 'Skipping %', rec.q;
CONTINUE;
END IF;
BEGIN
@@ -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)::name as p, unnest(s)::name as sc from inp
SELECT unnest(x) as p, unnest(s) as sc from inp
LOOP
-- RAISE DEBUG 'tab: %', rec2.p;
-- RAISE DEBUG 'sc: %', rec2.sc;
tables := array_append(tables, (rec2.sc || '.' || rec2.p)::name);
tables := array_append(tables, (rec2.sc || '.' || rec2.p));
END LOOP;
-- RAISE DEBUG 'Tables: %', tables;
@@ -65,3 +65,14 @@ BEGIN
return tables;
END
$$ LANGUAGE 'plpgsql' VOLATILE STRICT;
-- 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)
RETURNS name[]
AS $$
BEGIN
RETURN CDB_QueryTablesText(query)::name[];
END
$$ LANGUAGE 'plpgsql' VOLATILE STRICT;

View File

@@ -2,20 +2,45 @@
CREATE OR REPLACE FUNCTION CDB_UserDataSize(schema_name TEXT)
RETURNS bigint AS
$$
-- TODO: double check this query. Maybe use CDB_TableMetadata for lookup ?
-- also, it's "table_name" sounds sensible to search_path
--
-- NOTE: division by 2 is an hack for the_geom_webmercator
--
SELECT coalesce(int8(sum(pg_total_relation_size(schema_name || '.' || table_name)) / 2), 0)
AS quota
FROM information_schema.tables
WHERE table_catalog = current_database() AND table_schema = schema_name
DECLARE
total_size INT8;
BEGIN
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()
),
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';
AND table_type = 'BASE TABLE'
),
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 r_table_name = table_name) AS is_raster
FROM user_tables
),
sizes AS (
SELECT COALESCE(INT8(SUM(pg_total_relation_size('"' || schema_name || '"."' || 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;
IF total_size IS NOT NULL THEN
RETURN total_size;
ELSE
RETURN 0;
END IF;
END;
$$
LANGUAGE 'sql' VOLATILE;
LANGUAGE 'plpgsql' VOLATILE;
-- Return the estimated size of user data. Used for quota checking.

View File

@@ -1,8 +1,9 @@
-- Convert string to date
--
DROP FUNCTION IF EXISTS CDB_StringToDate(character varying);
CREATE OR REPLACE FUNCTION CDB_StringToDate(input character varying)
RETURNS date AS $$
DECLARE output DATE;
RETURNS TIMESTAMP AS $$
DECLARE output TIMESTAMP;
BEGIN
BEGIN
output := input::date;

View File

@@ -5,9 +5,9 @@ CREATE TABLE IF NOT EXISTS
updated_at timestamp with time zone not null default now()
);
-- Anyone can see this, but updates are only possible trough
-- the security definer trigger
GRANT SELECT ON public.CDB_TableMetadata TO public;
-- No one can see this
-- Updates are only possible trough the security definer trigger
-- GRANT SELECT ON public.CDB_TableMetadata TO public;
--
-- Trigger logging updated_at in the CDB_TableMetadata
@@ -118,3 +118,21 @@ CREATE TRIGGER table_modified AFTER INSERT OR UPDATE
ON CDB_TableMetadata FOR EACH ROW EXECUTE PROCEDURE
_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)
RETURNS void AS
$$
BEGIN
WITH upsert AS (
UPDATE public.cdb_tablemetadata
SET updated_at = NOW()
WHERE tabname = tablename
RETURNING *
)
INSERT INTO public.cdb_tablemetadata (tabname, updated_at)
SELECT tablename, NOW()
WHERE NOT EXISTS (SELECT * FROM upsert);
END;
$$
LANGUAGE 'plpgsql' VOLATILE STRICT;

View File

@@ -5,35 +5,22 @@
--
-- 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')
RETURNS SETOF information_schema.sql_identifier
RETURNS SETOF name
AS $$
WITH usertables AS (
-- TODO: query CDB_TableMetadata for this ?
-- See http://github.com/CartoDB/cartodb/issues/254#issuecomment-26044777
SELECT table_name as t
FROM information_schema.tables
WHERE
table_type='BASE TABLE'
AND table_schema='public'
AND table_name NOT IN (
'cdb_tablemetadata',
'spatial_ref_sys'
)
), perms AS (
SELECT t, has_table_privilege('public', 'public'||'.'||t, 'SELECT') as p
FROM usertables
)
SELECT t FROM perms
WHERE (
p = CASE WHEN $1 = 'private' THEN false
WHEN $1 = 'public' THEN true
ELSE not p -- none
END
OR $1 = 'all'
)
AND has_table_privilege('public'||'.'||t, 'SELECT')
;
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 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';
-- This is to migrate from pre-0.2.0 version

View File

@@ -0,0 +1,31 @@
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;

View File

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

View File

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

View File

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

View File

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

View File

@@ -8,6 +8,8 @@ SELECT cartodb.cdb_enable_ddl_hooks();
create schema c;
SELECT CDB_SetUserQuotaInBytes('c', 0);
CREATE USER cartodb_postgresql_unpriv_user;
GRANT ALL ON SCHEMA c to cartodb_postgresql_unpriv_user;
SET SESSION AUTHORIZATION 'cartodb_postgresql_unpriv_user';
@@ -16,7 +18,7 @@ SET SESSION AUTHORIZATION 'cartodb_postgresql_unpriv_user';
----------------------
-- CREATE TABLE
----------------------
SET SESSION AUTHORIZATION 'cartodb_postgresql_unpriv_user';
select 1 as i INTO c.t3;
select
@@ -26,11 +28,13 @@ select
i
from 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;
@@ -39,6 +43,8 @@ select
NOW() - updated_at < '1 secs' as "u<1s",
the_geom, the_geom_webmercator
from c.t4;
RESET SESSION AUTHORIZATION;
select
tabname::text,
round(extract('secs' from now() - updated_at)) as age
@@ -47,6 +53,7 @@ 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;
@@ -58,11 +65,13 @@ select
i, webmerc
from c.t3;
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;
@@ -73,6 +82,7 @@ select
i, webmerc, webmerc2
from c.t3;
RESET SESSION AUTHORIZATION;
select
tabname::text,
round(extract('secs' from now() - updated_at)*10) as agecs
@@ -81,7 +91,7 @@ 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;
@@ -92,6 +102,7 @@ select
i, webmerc, webmerc2
from c.t3;
RESET SESSION AUTHORIZATION;
select
tabname::text,
round(extract('secs' from now() - updated_at)*10) as agecs
@@ -100,7 +111,7 @@ 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;
@@ -111,6 +122,7 @@ select
i, webmerc, webmerc2, id2
from c.t3;
RESET SESSION AUTHORIZATION;
select
tabname::text,
round(extract('secs' from now() - updated_at)*10) as agecs

View File

@@ -1,5 +1,5 @@
SET client_min_messages TO error;
\set VERBOSITY terse;
\set VERBOSITY default
CREATE OR REPLACE FUNCTION CDB_CartodbfyTableCheck(tabname regclass, label text)
RETURNS text AS

View File

@@ -3,7 +3,7 @@ CREATE FUNCTION
SELECT 1
ERROR: Please set user quota before cartodbfying tables.
CONTEXT: SQL statement "SELECT cartodb._CDB_check_prerequisites(schema_name, reloid)"
PL/pgSQL function cdb_cartodbfytable(text,regclass) line 6 at PERFORM
PL/pgSQL function cdb_cartodbfytable(text,regclass) line 7 at PERFORM
0
single non-geometrical column cartodbfied fine
DROP TABLE

View File

@@ -0,0 +1,4 @@
WITH data AS (
SELECT pow(x,3)::numeric x FROM generate_series(-100,100) x
)
SELECT CDB_DistType(array_agg(x)) FROM data

View File

@@ -0,0 +1 @@
A

View File

@@ -0,0 +1,20 @@
-- a - j add up to 89%, k-m add up to 11%
WITH a As (
SELECT (
repeat('a',12) ||
repeat('b',11) ||
repeat('c',11) ||
repeat('d',10) ||
repeat('e',10) ||
repeat('f',9) ||
repeat('g',8) ||
repeat('h',7) ||
repeat('i',6) ||
repeat('j',5) ||
repeat('k',4) ||
repeat('l',4) ||
repeat('m',3)
)::text AS x
)
SELECT CDB_DistinctMeasure(string_to_array(x,null),0.90) from a

View File

@@ -0,0 +1 @@
0

View File

@@ -0,0 +1,5 @@
WITH data AS (
SELECT array_agg(x::numeric) s FROM generate_series(1,300) x
WHERE x % 5 != 0 AND x % 7 != 0
)
SELECT round(unnest(CDB_EqualIntervalBins(s, 7)),7) FROM data

View File

@@ -0,0 +1,7 @@
43.5714286
86.1428571
128.7142857
171.2857143
213.8571429
256.4285714
299.0000000

View File

@@ -1,7 +1,7 @@
16
13
29
43
57
71
83
86
99

View File

@@ -31,3 +31,9 @@ create table sc.test (a int);
insert into sc.test values (1);
WITH inp AS ( select 'select * from sc.test'::text as q )
SELECT q, CDB_QueryTables(q) from inp;
DROP TABLE sc.test;
DROP SCHEMA sc;
WITH inp AS ( select 'SELECT
* FROM geometry_columns'::text as q )
SELECT q, CDB_QueryTables(q) from inp;

View File

@@ -4,12 +4,20 @@ CREATE table "my'tab;le" as select 1|{}
SELECT a.oid, b.oid FROM pg_class a, pg_class b|{pg_catalog.pg_class}
SELECT 1 as col1; select 2 as col2|{}
WARNING: CDB_QueryTables cannot explain query: select 1 from nonexistant (42P01: relation "nonexistant" does not exist)
CONTEXT: PL/pgSQL function cdb_querytables(text) line 3 at RETURN
ERROR: relation "nonexistant" does not exist
CONTEXT: PL/pgSQL function cdb_querytables(text) line 3 at RETURN
begin; select * from pg_class; commit;|{pg_catalog.pg_class}
WARNING: CDB_QueryTables cannot explain query: select * from test (42P01: relation "test" does not exist)
CONTEXT: PL/pgSQL function cdb_querytables(text) line 3 at RETURN
ERROR: relation "test" does not exist
CONTEXT: PL/pgSQL function cdb_querytables(text) line 3 at RETURN
WITH a AS (select * from pg_class) select * from a|{pg_catalog.pg_class}
CREATE SCHEMA
CREATE TABLE
INSERT 0 1
select * from sc.test|{sc.test}
DROP TABLE
DROP SCHEMA
SELECT
* FROM geometry_columns|{pg_catalog.pg_attribute,pg_catalog.pg_class,pg_catalog.pg_namespace,pg_catalog.pg_type}

View File

@@ -1,5 +1,6 @@
set client_min_messages to ERROR;
\set VERBOSITY terse
set client_min_messages to error;
\set VERBOSITY default
CREATE TABLE big(a int);
-- Try the legacy interface
-- See https://github.com/CartoDB/cartodb-postgresql/issues/13
@@ -9,8 +10,10 @@ INSERT INTO big VALUES (1); -- allowed, check runs before
INSERT INTO big VALUES (1); -- disallowed, quota exceeds before
SELECT CDB_SetUserQuotaInBytes(0);
SELECT CDB_CartodbfyTable('big');
INSERT INTO big SELECT generate_series(1,1024);
SELECT CDB_SetUserQuotaInBytes(8);
INSERT INTO big SELECT generate_series(1,2048);
INSERT INTO big SELECT generate_series(1,2048);
INSERT INTO big SELECT generate_series(1,2048);
SELECT CDB_SetUserQuotaInBytes(2);
INSERT INTO big VALUES (1);
SELECT CDB_SetUserQuotaInBytes(0);
INSERT INTO big VALUES (1);

View File

@@ -5,9 +5,11 @@ INSERT 0 1
ERROR: Quota exceeded by 3.9990234375KB
0
INSERT 0 1024
8
ERROR: Quota exceeded by 103.9921875KB
INSERT 0 2048
INSERT 0 2048
INSERT 0 2048
2
ERROR: Quota exceeded by 567.998046875KB
0
INSERT 0 1
DROP TABLE

View File

@@ -1,11 +1,19 @@
create table pub(a int);
create table prv(a int);
GRANT SELECT ON TABLE pub TO public;
REVOKE SELECT ON TABLE prv FROM public;
CREATE ROLE publicuser LOGIN;
CREATE TABLE pub(a int);
CREATE TABLE prv(a int);
GRANT SELECT ON TABLE pub TO publicuser;
REVOKE SELECT ON TABLE prv FROM publicuser;
SELECT CDB_UserTables() ORDER BY 1;
SELECT 'all',CDB_UserTables('all') ORDER BY 2;
SELECT 'public',CDB_UserTables('public') ORDER BY 2;
SELECT 'private',CDB_UserTables('private') ORDER BY 2;
SELECT '--unsupported--',CDB_UserTables('--unsupported--') ORDER BY 2;
drop table pub;
drop table prv;
-- now tests with public user
\c contrib_regression publicuser
SELECT 'all_publicuser',CDB_UserTables('all') ORDER BY 2;
SELECT 'public_publicuser',CDB_UserTables('public') ORDER BY 2;
SELECT 'private_publicuser',CDB_UserTables('private') ORDER BY 2;
\c contrib_regression postgres
DROP TABLE pub;
DROP TABLE prv;
DROP ROLE publicuser;

View File

@@ -1,3 +1,4 @@
CREATE ROLE
CREATE TABLE
CREATE TABLE
GRANT
@@ -8,5 +9,10 @@ all|prv
all|pub
public|pub
private|prv
You are now connected to database "contrib_regression" as user "publicuser".
all_publicuser|pub
public_publicuser|pub
You are now connected to database "contrib_regression" as user "postgres".
DROP TABLE
DROP TABLE
DROP ROLE

View File

@@ -5,5 +5,5 @@ inp AS ( select z0.z, r1.r as x, r2.r as y FROM zoom z0, range r1, range r2 WHER
ext AS ( select x,y,z,CDB_XYZ_Extent(x,y,z) as g from inp )
select X::text || ',' || Y::text || ',' || Z::text as xyz,
st_xmin(g), st_xmax(g), st_ymin(g), st_ymax(g)
from ext;
from ext order by xyz;

View File

@@ -1,13 +1,13 @@
0,0,0|-20037508.5|20037508.5|-20037508.5|20037508.5
0,0,1|-20037508.5|0|0|20037508.5
0,1,1|-20037508.5|0|-20037508.5|0
1,0,1|0|20037508.5|0|20037508.5
1,1,1|0|20037508.5|-20037508.5|0
0,0,2|-20037508.5|-10018754.25|10018754.25|20037508.5
0,1,1|-20037508.5|0|-20037508.5|0
0,1,2|-20037508.5|-10018754.25|0|10018754.25
0,2,2|-20037508.5|-10018754.25|-10018754.25|0
0,3,2|-20037508.5|-10018754.25|-20037508.5|-10018754.25
1,0,1|0|20037508.5|0|20037508.5
1,0,2|-10018754.25|0|10018754.25|20037508.5
1,1,1|0|20037508.5|-20037508.5|0
1,1,2|-10018754.25|0|0|10018754.25
1,2,2|-10018754.25|0|-10018754.25|0
1,3,2|-10018754.25|0|-20037508.5|-10018754.25

View File

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

344
test/extension/test.sh Executable file
View File

@@ -0,0 +1,344 @@
#!/bin/sh
#
# Tests for the extension since version 0.5.0. They don't replace SQL based ones, for now need to run both
#
# It is expected that you run this script as a PostgreSQL superuser, for example:
#
# PGUSER=postgres bash ./test.sh
#
DATABASE=test_extension
CMD='echo psql'
CMD=psql
OK=0
PARTIALOK=0
function set_failed() {
OK=1
PARTIALOK=1
}
function clear_partial_result() {
PARTIALOK=0
}
function sql() {
local ROLE
local QUERY
if [[ $# -ge 2 ]]
then
ROLE="$1"
QUERY="$2"
else
QUERY="$1"
fi
if [ -n "${ROLE}" ]; then
log_debug "Executing query '${QUERY}' as ${ROLE}"
RESULT=`${CMD} -U "${ROLE}" ${DATABASE} -c "${QUERY}" -A -t`
else
log_debug "Executing query '${QUERY}'"
RESULT=`${CMD} ${DATABASE} -c "${QUERY}" -A -t`
fi
CODERESULT=$?
echo ${RESULT}
echo
if [[ ${CODERESULT} -ne 0 ]]
then
echo -n "FAILED TO EXECUTE QUERY: "
log_warning "${QUERY}"
if [[ "$3" != "fails" ]]
then
log_error "${QUERY}"
set_failed
fi
else
if [[ "$3" == "fails" ]]
then
log_error "QUERY: '${QUERY}' was expected to fail and it did not fail"
set_failed
fi
fi
if [[ "$3" == "should" ]]
then
if [[ "${RESULT}" != "$4" ]]
then
log_error "QUERY '${QUERY}' expected result '${4}' but got '${RESULT}'"
set_failed
fi
fi
if [[ "$3" == "should-not" ]]
then
if [[ "${RESULT}" == "$4" ]]
then
log_error "QUERY '${QUERY}' did not expect '${RESULT}'"
set_failed
fi
fi
}
function log_info()
{
echo
echo
echo
_log "1;34m" "$1"
}
function log_error() {
_log "1;31m" "$1"
}
function log_debug() {
_log "1;32m" "> $1"
}
function log_warning() {
_log "0;33m" "$1"
}
function _log() {
echo -e "\033[$1$2\033[0m"
}
# '############################ HELPERS #############################'
function create_role_and_schema() {
local ROLE=$1
sql "CREATE ROLE ${ROLE} LOGIN;"
sql "GRANT CONNECT ON DATABASE \"${DATABASE}\" TO ${ROLE};"
sql "CREATE SCHEMA ${ROLE} AUTHORIZATION ${ROLE};"
sql "SELECT cartodb.CDB_Organization_Create_Member('${ROLE}');"
}
function drop_role_and_schema() {
local ROLE=$1
sql "DROP SCHEMA \"${ROLE}\";"
sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM \"${ROLE}\";"
sql "DROP ROLE \"${ROLE}\";"
}
function create_table() {
if [[ $# -ne 2 ]]
then
log_error "create_table requires two arguments: role and table_name"
exit 1
fi
local ROLE="$1"
local TABLENAME="$2"
sql ${ROLE} "CREATE TABLE ${ROLE}.${TABLENAME} ( a int );"
}
function create_raster_table() {
if [[ $# -ne 2 ]]
then
log_error "create_raster_table requires two arguments: role and table_name"
exit 1
fi
local RASTER_COL="the_raster_webmercator"
local ROLE="$1"
local TABLENAME="$2"
local OVERVIEW_TABLENAME="o_2_${TABLENAME}"
sql ${ROLE} "CREATE TABLE ${ROLE}.${TABLENAME} (rid serial PRIMARY KEY, ${RASTER_COL} raster);"
sql ${ROLE} "CREATE TABLE ${ROLE}.${OVERVIEW_TABLENAME} (rid serial PRIMARY KEY, ${RASTER_COL} raster);"
sql ${ROLE} "SELECT AddOverviewConstraints('${ROLE}','${OVERVIEW_TABLENAME}','${RASTER_COL}','${ROLE}','${TABLENAME}','${RASTER_COL}',2);"
}
function drop_raster_table() {
if [[ $# -ne 2 ]]
then
log_error "drop_raster_table requires two arguments: role and table_name"
exit 1
fi
local ROLE="$1"
local TABLENAME="$2"
local OVERVIEW_TABLENAME="o_2_${TABLENAME}"
sql ${ROLE} "DROP TABLE ${ROLE}.${OVERVIEW_TABLENAME};"
sql ${ROLE} "DROP TABLE ${ROLE}.${TABLENAME};"
}
function setup() {
${CMD} -c "CREATE DATABASE ${DATABASE}"
sql "CREATE SCHEMA cartodb;"
sql "GRANT USAGE ON SCHEMA cartodb TO public;"
sql "CREATE EXTENSION postgis;"
log_info "########################### BOOTSTRAP ###########################"
${CMD} -d ${DATABASE} -f scripts-available/CDB_Organizations.sql
# trick to allow forcing a schema when loading SQL files (see: http://bit.ly/1HeLnhL)
${CMD} -d ${DATABASE} -f test/extension/run_at_cartodb_schema.sql
log_info "############################# SETUP #############################"
create_role_and_schema cdb_testmember_1
create_role_and_schema cdb_testmember_2
create_table cdb_testmember_1 foo
sql cdb_testmember_1 'INSERT INTO cdb_testmember_1.foo VALUES (1), (2), (3), (4), (5), (6);'
sql cdb_testmember_1 'SELECT * FROM cdb_testmember_1.foo;'
create_table cdb_testmember_2 bar
sql cdb_testmember_2 'INSERT INTO bar VALUES (1), (2), (3);'
sql cdb_testmember_2 'SELECT * FROM cdb_testmember_2.bar;'
}
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');"
sql cdb_testmember_2 "SELECT * FROM cartodb.CDB_Organization_Remove_Access_Permission('cdb_testmember_2', 'bar', 'cdb_testmember_1');"
sql cdb_testmember_1 'DROP TABLE cdb_testmember_1.foo;'
sql cdb_testmember_2 'DROP TABLE cdb_testmember_2.bar;'
sql "DROP SCHEMA cartodb CASCADE"
log_info "########################### TEAR DOWN ###########################"
sql 'DROP SCHEMA cdb_testmember_1;'
sql 'DROP SCHEMA cdb_testmember_2;'
sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_testmember_1;"
sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_testmember_2;"
sql 'DROP ROLE cdb_testmember_1;'
sql 'DROP ROLE cdb_testmember_2;'
${CMD} -c "DROP DATABASE ${DATABASE}"
}
function run_tests() {
local FAILED_TESTS=()
local TESTS
if [[ $# -ge 1 ]]
then
TESTS="$@"
else
TESTS=`cat $0 | perl -n -e'/function (test.*)\(\)/ && print "$1\n"'`
fi
for t in ${TESTS}
do
echo "####################################################################"
echo "#"
echo "# Running: ${t}"
echo "#"
echo "####################################################################"
clear_partial_result
setup
eval ${t}
if [[ ${PARTIALOK} -ne 0 ]]
then
FAILED_TESTS+=(${t})
fi
tear_down
done
if [[ ${OK} -ne 0 ]]
then
echo
log_error "The following tests are failing:"
printf -- '\t%s\n' "${FAILED_TESTS[@]}"
fi
}
#################################################### TESTS GO HERE ####################################################
# Tests quota checking taking into account both geom and raster tables
function test_quota_for_each_user() {
# Normal tables add 4096 bytes
# Raster tables no longer add anything so also count as 4096
sql cdb_testmember_1 "SELECT cartodb.CDB_UserDataSize('cdb_testmember_1'::TEXT);" should 4096
sql cdb_testmember_2 "SELECT cartodb.CDB_UserDataSize('cdb_testmember_2'::TEXT);" should 4096
create_raster_table cdb_testmember_1 raster_1
create_raster_table cdb_testmember_2 raster_2
sql cdb_testmember_1 "SELECT cartodb.CDB_UserDataSize('cdb_testmember_1'::TEXT);" should 20480
sql cdb_testmember_2 "SELECT cartodb.CDB_UserDataSize('cdb_testmember_2'::TEXT);" should 20480
create_raster_table cdb_testmember_1 raster_3
sql cdb_testmember_1 "SELECT cartodb.CDB_UserDataSize('cdb_testmember_1'::TEXT);" should 36864
sql cdb_testmember_2 "SELECT cartodb.CDB_UserDataSize('cdb_testmember_2'::TEXT);" should 20480
drop_raster_table cdb_testmember_1 raster_1
drop_raster_table cdb_testmember_2 raster_2
drop_raster_table cdb_testmember_1 raster_3
sql cdb_testmember_1 "SELECT cartodb.CDB_UserDataSize('cdb_testmember_1'::TEXT);" should 4096
sql cdb_testmember_2 "SELECT cartodb.CDB_UserDataSize('cdb_testmember_2'::TEXT);" should 4096
}
function test_cdb_tablemetadatatouch() {
sql "CREATE TABLE touch_example (a int)"
sql postgres "SELECT updated_at FROM CDB_TableMetadata WHERE tabname = 'touch_example'::regclass;" should ''
sql "SELECT CDB_TableMetadataTouch('touch_example');"
sql postgres "SELECT updated_at FROM CDB_TableMetadata WHERE tabname = 'touch_example'::regclass;" should-not ''
# Another call doesn't fail
sql "SELECT CDB_TableMetadataTouch('touch_example');"
sql postgres "SELECT updated_at FROM CDB_TableMetadata WHERE tabname = 'touch_example'::regclass;" should-not ''
# Works with qualified tables
sql "SELECT CDB_TableMetadataTouch('public.touch_example');"
sql "SELECT CDB_TableMetadataTouch('public.\"touch_example\"');"
sql "SELECT CDB_TableMetadataTouch('\"public\".touch_example');"
sql "SELECT CDB_TableMetadataTouch('\"public\".\"touch_example\"');"
# Works with OID
sql postgres "SELECT tabname from CDB_TableMetadata;" should 'touch_example'
sql postgres "SELECT count(*) from CDB_TableMetadata;" should 1
TABLE_OID=`${CMD} -U postgres ${DATABASE} -c "SELECT attrelid FROM pg_attribute WHERE attrelid = 'touch_example'::regclass limit 1;" -A -t`
# quoted OID works
sql "SELECT CDB_TableMetadataTouch('${TABLE_OID}');"
sql postgres "SELECT tabname from CDB_TableMetadata;" should 'touch_example'
sql postgres "SELECT count(*) from CDB_TableMetadata;" should 1
# non quoted OID works
sql "SELECT CDB_TableMetadataTouch(${TABLE_OID});"
sql postgres "SELECT tabname from CDB_TableMetadata;" should 'touch_example'
sql postgres "SELECT count(*) from CDB_TableMetadata;" should 1
#### test tear down
sql 'DROP TABLE touch_example;'
}
function test_cdb_tablemetadatatouch_fails_for_unexistent_table() {
sql postgres "SELECT CDB_TableMetadataTouch('unexistent_example');" fails
}
function test_cdb_tablemetadatatouch_fails_from_user_without_permission() {
sql "CREATE TABLE touch_example (a int);"
sql postgres "SELECT CDB_TableMetadataTouch('touch_example');"
sql cdb_testmember_1 "SELECT CDB_TableMetadataTouch('touch_example');" fails
sql postgres "GRANT ALL ON CDB_TableMetadata TO cdb_testmember_1;"
sql cdb_testmember_1 "SELECT CDB_TableMetadataTouch('touch_example');"
sql postgres "REVOKE ALL ON CDB_TableMetadata FROM cdb_testmember_1;"
}
#################################################### TESTS END HERE ####################################################
run_tests $@
exit ${OK}

View File

@@ -142,6 +142,8 @@ function setup() {
log_info "############################# SETUP #############################"
create_role_and_schema cdb_testmember_1
create_role_and_schema cdb_testmember_2
sql "CREATE ROLE publicuser LOGIN;"
sql "GRANT CONNECT ON DATABASE \"${DATABASE}\" TO publicuser;"
create_table cdb_testmember_1 foo
sql cdb_testmember_1 'INSERT INTO cdb_testmember_1.foo VALUES (1), (2), (3), (4), (5);'
@@ -168,9 +170,11 @@ function tear_down() {
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 'DROP ROLE cdb_testmember_1;'
sql 'DROP ROLE cdb_testmember_2;'
sql 'DROP ROLE publicuser;'
${CMD} -c "DROP DATABASE ${DATABASE}"
}
@@ -346,6 +350,25 @@ function test_cdb_querytables_does_not_return_functions_as_part_of_the_resultset
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}"
}
function test_cdb_usertables_should_work_with_orgusers() {
sql "GRANT USAGE ON SCHEMA cartodb TO publicuser;"
${CMD} -d ${DATABASE} -f scripts-available/CDB_UserTables.sql
sql cdb_testmember_1 "CREATE TABLE test_perms_pub (a int)"
sql cdb_testmember_1 "CREATE TABLE test_perms_priv (a int)"
sql cdb_testmember_1 "GRANT SELECT ON TABLE test_perms_pub TO publicuser"
sql publicuser "SELECT count(*) FROM CDB_UserTables('all')" should 1
sql publicuser "SELECT count(*) FROM CDB_UserTables('public')" should 1
sql publicuser "SELECT count(*) FROM CDB_UserTables('private')" should 0
# the following tests are for https://github.com/CartoDB/cartodb-postgresql/issues/98
#sql cdb_testmember_2 "SELECT count(*) FROM CDB_UserTables('all')" should 1
#sql cdb_testmember_2 "SELECT count(*) FROM CDB_UserTables('public')" should 1
#sql cdb_testmember_2 "SELECT count(*) FROM CDB_UserTables('private')" should 0
sql cdb_testmember_1 "DROP TABLE test_perms_pub"
sql cdb_testmember_1 "DROP TABLE test_perms_priv"
}
#################################################### TESTS END HERE ####################################################