mirror of
https://github.com/timescale/timescaledb.git
synced 2025-04-20 03:21:15 +08:00
Add proper permissions handling for associated (chunk) schemas
A hypertable's associated schema is used to create and store internal data tables (chunks). A hypertable creates tables in that schema, typically with full superuser permissions, regardless of whether the hypertable's owner or the current user have permissions for the schema. If the schema doesn't exist, the hypertable will create it when creating the first chunk, even though the user or table owner does not have permissions to create schemas in the database. This change adds proper permissions checks to create_hypertable() so that users cannot create hypertables with a custom associated schema unless they have the proper permissions on the schema or the database. Chunks are also no longer created with internal schema permissions if the associated schema is something different from the internal schema.
This commit is contained in:
parent
21efcce95c
commit
4df8f287a6
@ -40,16 +40,21 @@ DECLARE
|
||||
is_partitioned BOOLEAN;
|
||||
chunk_time_interval_actual BIGINT;
|
||||
time_type REGTYPE;
|
||||
relowner OID;
|
||||
BEGIN
|
||||
-- Early abort if lacking permissions
|
||||
PERFORM _timescaledb_internal.check_role(main_table);
|
||||
|
||||
SELECT relname, nspname, reltablespace, relkind = 'p'
|
||||
INTO STRICT table_name, schema_name, tablespace_oid, is_partitioned
|
||||
SELECT c.relname, n.nspname, c.reltablespace, c.relkind = 'p', c.relowner
|
||||
INTO STRICT table_name, schema_name, tablespace_oid, is_partitioned, relowner
|
||||
FROM pg_class c
|
||||
INNER JOIN pg_namespace n ON (n.OID = c.relnamespace)
|
||||
WHERE c.OID = main_table;
|
||||
|
||||
-- Check that the user has permissions to create chunks in the
|
||||
-- associated schema
|
||||
PERFORM _timescaledb_internal.check_associated_schema_permissions(associated_schema_name, relowner);
|
||||
|
||||
IF is_partitioned THEN
|
||||
RAISE EXCEPTION 'table % is already partitioned', main_table
|
||||
USING ERRCODE = 'IO110';
|
||||
|
@ -22,6 +22,9 @@ BEGIN
|
||||
END
|
||||
$BODY$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION _timescaledb_internal.check_associated_schema_permissions(schema_name NAME, userid OID)
|
||||
RETURNS VOID AS '$libdir/timescaledb', 'hypertable_check_associated_schema_permissions' LANGUAGE C;
|
||||
|
||||
-- Creates a hypertable row.
|
||||
CREATE OR REPLACE FUNCTION _timescaledb_internal.create_hypertable(
|
||||
main_table REGCLASS,
|
||||
|
48
src/chunk.c
48
src/chunk.c
@ -13,6 +13,7 @@
|
||||
#include <utils/builtins.h>
|
||||
#include <utils/lsyscache.h>
|
||||
#include <utils/hsearch.h>
|
||||
#include <miscadmin.h>
|
||||
|
||||
#include "chunk.h"
|
||||
#include "chunk_index.h"
|
||||
@ -26,6 +27,7 @@
|
||||
#include "scanner.h"
|
||||
#include "process_utility.h"
|
||||
#include "trigger.h"
|
||||
#include "compat.h"
|
||||
|
||||
typedef bool (*on_chunk_func) (ChunkScanCtx *ctx, Chunk *chunk);
|
||||
|
||||
@ -341,21 +343,59 @@ chunk_add_constraints(Chunk *chunk)
|
||||
return num_added;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a chunk's table.
|
||||
*
|
||||
* A chunk inherits from the main hypertable and will have the same owner. Since
|
||||
* chunks can be created either in the TimescaleDB internal schema or in a
|
||||
* user-specified schema, some care has to be taken to use the right
|
||||
* permissions, depending on the case:
|
||||
*
|
||||
* 1. if the chunk is created in the internal schema, we create it as the
|
||||
* catalog/schema owner (i.e., anyone can create chunks there via inserting into
|
||||
* a hypertable, but can not do it via CREATE TABLE).
|
||||
*
|
||||
* 2. if the chunk is created in a user-specified "associated schema", then we
|
||||
* shouldn't use the catalog owner to create the table since that typically
|
||||
* implies super-user permissions. If we would allow that, anyone can specify
|
||||
* someone else's schema in create_hypertable() and create chunks in it without
|
||||
* having the proper permissions to do so. With this logic, the hypertable owner
|
||||
* must have permissions to create tables in the associated schema, or else
|
||||
* table creation will fail. If the schema doesn't yet exist, the table owner
|
||||
* instead needs the proper permissions on the database to create the schema.
|
||||
*/
|
||||
static Oid
|
||||
chunk_create_table(Chunk *chunk, Hypertable *ht)
|
||||
{
|
||||
Catalog *catalog = catalog_get();
|
||||
Relation rel;
|
||||
ObjectAddress objaddr;
|
||||
CatalogSecurityContext sec_ctx;
|
||||
int sec_ctx;
|
||||
CreateStmt stmt = {
|
||||
.type = T_CreateStmt,
|
||||
.relation = makeRangeVar(NameStr(chunk->fd.schema_name), NameStr(chunk->fd.table_name), 0),
|
||||
.inhRelations = list_make1(makeRangeVar(NameStr(ht->fd.schema_name), NameStr(ht->fd.table_name), 0)),
|
||||
.tablespacename = hypertable_select_tablespace(ht, chunk),
|
||||
};
|
||||
Oid uid,
|
||||
saved_uid;
|
||||
|
||||
rel = heap_open(ht->main_table_relid, AccessShareLock);
|
||||
catalog_become_owner(catalog_get(), &sec_ctx);
|
||||
|
||||
/*
|
||||
* If the chunk is created in the internal schema, become the catalog
|
||||
* owner, otherwise become the hypertable owner
|
||||
*/
|
||||
if (namestrcmp(&chunk->fd.schema_name, INTERNAL_SCHEMA_NAME) == 0)
|
||||
uid = catalog->owner_uid;
|
||||
else
|
||||
uid = rel->rd_rel->relowner;
|
||||
|
||||
GetUserIdAndSecContext(&saved_uid, &sec_ctx);
|
||||
|
||||
if (uid != saved_uid)
|
||||
SetUserIdAndSecContext(uid, sec_ctx | SECURITY_LOCAL_USERID_CHANGE);
|
||||
|
||||
objaddr = DefineRelation(&stmt,
|
||||
RELKIND_RELATION,
|
||||
rel->rd_rel->relowner,
|
||||
@ -365,7 +405,9 @@ chunk_create_table(Chunk *chunk, Hypertable *ht)
|
||||
#endif
|
||||
);
|
||||
|
||||
catalog_restore_user(&sec_ctx);
|
||||
if (uid != saved_uid)
|
||||
SetUserIdAndSecContext(saved_uid, sec_ctx);
|
||||
|
||||
heap_close(rel, AccessShareLock);
|
||||
|
||||
return objaddr.objectId;
|
||||
|
@ -4,9 +4,11 @@
|
||||
#include <utils/syscache.h>
|
||||
#include <utils/memutils.h>
|
||||
#include <utils/builtins.h>
|
||||
#include <utils/acl.h>
|
||||
#include <nodes/memnodes.h>
|
||||
#include <catalog/namespace.h>
|
||||
#include <commands/tablespace.h>
|
||||
#include <commands/dbcommands.h>
|
||||
#include <miscadmin.h>
|
||||
|
||||
#include "hypertable.h"
|
||||
@ -360,3 +362,67 @@ hypertable_validate_triggers(PG_FUNCTION_ARGS)
|
||||
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
TS_FUNCTION_INFO_V1(hypertable_check_associated_schema_permissions);
|
||||
|
||||
/*
|
||||
* Check that the current user can create chunks in a hypertable's associated
|
||||
* schema.
|
||||
*
|
||||
* This function is typically called from create_hypertable() to verify that the
|
||||
* table owner has CREATE permissions for the schema (if it already exists) or
|
||||
* the database (if the schema does not exist and needs to be created).
|
||||
*/
|
||||
Datum
|
||||
hypertable_check_associated_schema_permissions(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Name schema_name;
|
||||
Oid schema_oid;
|
||||
Oid user_oid;
|
||||
|
||||
if (PG_NARGS() != 2)
|
||||
elog(ERROR, "Invalid number of arguments");
|
||||
|
||||
/*
|
||||
* If the schema name is NULL, it implies the internal catalog schema and
|
||||
* anyone should be able to create chunks there.
|
||||
*/
|
||||
if (PG_ARGISNULL(0))
|
||||
PG_RETURN_VOID();
|
||||
|
||||
schema_name = PG_GETARG_NAME(0);
|
||||
|
||||
/* Anyone can create chunks in the internal schema */
|
||||
if (namestrcmp(schema_name, INTERNAL_SCHEMA_NAME) == 0)
|
||||
PG_RETURN_VOID();
|
||||
|
||||
if (PG_ARGISNULL(1))
|
||||
user_oid = GetUserId();
|
||||
else
|
||||
user_oid = PG_GETARG_OID(1);
|
||||
|
||||
schema_oid = get_namespace_oid(NameStr(*schema_name), true);
|
||||
|
||||
if (!OidIsValid(schema_oid))
|
||||
{
|
||||
/*
|
||||
* Schema does not exist, so we must check that the user has
|
||||
* privileges to create the schema in the current database
|
||||
*/
|
||||
if (pg_database_aclcheck(MyDatabaseId, user_oid, ACL_CREATE) != ACLCHECK_OK)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("User %s lacks permissions to create schema \"%s\" in database \"%s\"",
|
||||
GetUserNameFromId(user_oid, false),
|
||||
NameStr(*schema_name),
|
||||
get_database_name(MyDatabaseId))));
|
||||
}
|
||||
else if (pg_namespace_aclcheck(schema_oid, user_oid, ACL_CREATE) != ACLCHECK_OK)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
errmsg("User %s lacks permissions to create chunks in schema \"%s\"",
|
||||
GetUserNameFromId(user_oid, false),
|
||||
NameStr(*schema_name))));
|
||||
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
@ -12,6 +12,9 @@ CREATE INDEX ON PUBLIC."one_Partition" ("timeCustom" DESC NULLS LAST, series_0)
|
||||
CREATE INDEX ON PUBLIC."one_Partition" ("timeCustom" DESC NULLS LAST, series_1) WHERE series_1 IS NOT NULL;
|
||||
CREATE INDEX ON PUBLIC."one_Partition" ("timeCustom" DESC NULLS LAST, series_2) WHERE series_2 IS NOT NULL;
|
||||
CREATE INDEX ON PUBLIC."one_Partition" ("timeCustom" DESC NULLS LAST, series_bool) WHERE series_bool IS NOT NULL;
|
||||
\c single :ROLE_SUPERUSER
|
||||
CREATE SCHEMA "one_Partition" AUTHORIZATION :ROLE_DEFAULT_PERM_USER;
|
||||
\c single :ROLE_DEFAULT_PERM_USER;
|
||||
SELECT * FROM create_hypertable('"public"."one_Partition"', 'timeCustom', associated_schema_name=>'one_Partition', chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month'));
|
||||
create_hypertable
|
||||
-------------------
|
||||
@ -39,6 +42,9 @@ INSERT 0 1
|
||||
\c single :ROLE_SUPERUSER
|
||||
--needed for ddl ops:
|
||||
CREATE SCHEMA IF NOT EXISTS "customSchema" AUTHORIZATION :ROLE_DEFAULT_PERM_USER_2;
|
||||
--needed for ROLE_DEFAULT_PERM_USER_2 to write to the 'one_Partition' schema which
|
||||
--is owned by ROLE_DEFAULT_PERM_USER
|
||||
GRANT CREATE ON SCHEMA "one_Partition" TO :ROLE_DEFAULT_PERM_USER_2;
|
||||
--test creating and using schema as non-superuser
|
||||
\c single :ROLE_DEFAULT_PERM_USER_2
|
||||
\dt
|
||||
|
@ -1,5 +1,6 @@
|
||||
\c single :ROLE_SUPERUSER
|
||||
create schema test_schema AUTHORIZATION :ROLE_DEFAULT_PERM_USER;
|
||||
create schema chunk_schema AUTHORIZATION :ROLE_DEFAULT_PERM_USER_2;
|
||||
SET ROLE :ROLE_DEFAULT_PERM_USER;
|
||||
create table test_schema.test_table(time BIGINT, temp float8, device_id text, device_type text, location text, id int, id2 int);
|
||||
\set ON_ERROR_STOP 0
|
||||
@ -71,7 +72,18 @@ SELECT * FROM test.show_columns('test_schema.test_table_no_not_null');
|
||||
device_id | text | f
|
||||
(2 rows)
|
||||
|
||||
select * from create_hypertable('test_schema.test_table', 'time', 'device_id', 2, chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month'));
|
||||
RESET ROLE;
|
||||
SET ROLE :ROLE_DEFAULT_PERM_USER;
|
||||
\set ON_ERROR_STOP 0
|
||||
-- No permissions on associated schema should fail
|
||||
select * from create_hypertable('test_schema.test_table', 'time', 'device_id', 2, chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month'), associated_schema_name => 'chunk_schema');
|
||||
ERROR: User default_perm_user lacks permissions to create chunks in schema "chunk_schema"
|
||||
\set ON_ERROR_STOP 1
|
||||
-- Granting permissions on chunk_schema should make things work
|
||||
RESET ROLE;
|
||||
GRANT CREATE ON SCHEMA chunk_schema TO :ROLE_DEFAULT_PERM_USER;
|
||||
SET ROLE :ROLE_DEFAULT_PERM_USER;
|
||||
select * from create_hypertable('test_schema.test_table', 'time', 'device_id', 2, chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month'), associated_schema_name => 'chunk_schema');
|
||||
NOTICE: Adding NOT NULL constraint to time column time (NULL time values not allowed)
|
||||
create_hypertable
|
||||
-------------------
|
||||
@ -94,7 +106,7 @@ select add_dimension('test_schema.test_table', 'location', 2);
|
||||
select * from _timescaledb_catalog.hypertable where table_name = 'test_table';
|
||||
id | schema_name | table_name | associated_schema_name | associated_table_prefix | num_dimensions
|
||||
----+-------------+------------+------------------------+-------------------------+----------------
|
||||
2 | test_schema | test_table | _timescaledb_internal | _hyper_2 | 3
|
||||
2 | test_schema | test_table | chunk_schema | _hyper_2 | 3
|
||||
(1 row)
|
||||
|
||||
select * from _timescaledb_catalog.dimension;
|
||||
@ -123,7 +135,7 @@ NOTICE: Adding NOT NULL constraint to time column id (NULL time values not allo
|
||||
select * from _timescaledb_catalog.hypertable where table_name = 'test_table';
|
||||
id | schema_name | table_name | associated_schema_name | associated_table_prefix | num_dimensions
|
||||
----+-------------+------------+------------------------+-------------------------+----------------
|
||||
2 | test_schema | test_table | _timescaledb_internal | _hyper_2 | 4
|
||||
2 | test_schema | test_table | chunk_schema | _hyper_2 | 4
|
||||
(1 row)
|
||||
|
||||
select * from _timescaledb_catalog.dimension;
|
||||
@ -204,6 +216,14 @@ insert into test_schema.test_table values (123456789, 23.8, 'blue', 'type1', 'ny
|
||||
select add_dimension('test_schema.test_table', 'device_type', 2);
|
||||
ERROR: Cannot add new dimension to a non-empty table
|
||||
\set ON_ERROR_STOP 1
|
||||
--show chunks in the associated schema
|
||||
\dt "chunk_schema".*
|
||||
List of relations
|
||||
Schema | Name | Type | Owner
|
||||
--------------+------------------+-------+-------------------
|
||||
chunk_schema | _hyper_2_2_chunk | table | default_perm_user
|
||||
(1 row)
|
||||
|
||||
--test partitioning in only time dimension
|
||||
create table test_schema.test_1dim(time timestamp, temp float);
|
||||
select create_hypertable('test_schema.test_1dim', 'time');
|
||||
@ -220,10 +240,10 @@ SELECT * FROM _timescaledb_internal.get_create_command('test_1dim');
|
||||
(1 row)
|
||||
|
||||
\dt "test_schema".*
|
||||
List of relations
|
||||
Schema | Name | Type | Owner
|
||||
-------------+------------------------+-------+---------------------
|
||||
test_schema | test_1dim | table | default_perm_user_2
|
||||
List of relations
|
||||
Schema | Name | Type | Owner
|
||||
-------------+------------------------+-------+-------------------
|
||||
test_schema | test_1dim | table | default_perm_user
|
||||
test_schema | test_table | table | default_perm_user
|
||||
test_schema | test_table_no_not_null | table | default_perm_user
|
||||
(3 rows)
|
||||
|
@ -12,6 +12,9 @@ CREATE INDEX ON PUBLIC."one_Partition" ("timeCustom" DESC NULLS LAST, series_0)
|
||||
CREATE INDEX ON PUBLIC."one_Partition" ("timeCustom" DESC NULLS LAST, series_1) WHERE series_1 IS NOT NULL;
|
||||
CREATE INDEX ON PUBLIC."one_Partition" ("timeCustom" DESC NULLS LAST, series_2) WHERE series_2 IS NOT NULL;
|
||||
CREATE INDEX ON PUBLIC."one_Partition" ("timeCustom" DESC NULLS LAST, series_bool) WHERE series_bool IS NOT NULL;
|
||||
\c single :ROLE_SUPERUSER
|
||||
CREATE SCHEMA "one_Partition" AUTHORIZATION :ROLE_DEFAULT_PERM_USER;
|
||||
\c single :ROLE_DEFAULT_PERM_USER;
|
||||
SELECT * FROM create_hypertable('"public"."one_Partition"', 'timeCustom', associated_schema_name=>'one_Partition', chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month'));
|
||||
create_hypertable
|
||||
-------------------
|
||||
|
@ -49,7 +49,7 @@ SELECT count(*)
|
||||
AND refobjid = (SELECT oid FROM pg_extension WHERE extname = 'timescaledb');
|
||||
count
|
||||
-------
|
||||
114
|
||||
115
|
||||
(1 row)
|
||||
|
||||
SELECT * FROM test.show_columns('public."two_Partitions"');
|
||||
@ -235,7 +235,7 @@ SELECT count(*)
|
||||
AND refobjid = (SELECT oid FROM pg_extension WHERE extname = 'timescaledb');
|
||||
count
|
||||
-------
|
||||
114
|
||||
115
|
||||
(1 row)
|
||||
|
||||
--main table and chunk schemas should be the same
|
||||
|
@ -18,6 +18,9 @@ CREATE TABLE PUBLIC."testNs" (
|
||||
series_bool BOOLEAN NULL
|
||||
);
|
||||
CREATE INDEX ON PUBLIC."testNs" (device_id, "timeCustom" DESC NULLS LAST) WHERE device_id IS NOT NULL;
|
||||
\c single :ROLE_SUPERUSER
|
||||
CREATE SCHEMA "testNs" AUTHORIZATION :ROLE_DEFAULT_PERM_USER;
|
||||
\c single :ROLE_DEFAULT_PERM_USER
|
||||
SELECT * FROM create_hypertable('"public"."testNs"', 'timeCustom', 'device_id', 2, associated_schema_name=>'testNs' );
|
||||
create_hypertable
|
||||
-------------------
|
||||
@ -234,7 +237,7 @@ SELECT time_bucket(INTERVAL '1 day', TIMESTAMP '2011-01-02 01:01:01');
|
||||
Sun Jan 02 00:00:00 2011
|
||||
(1 row)
|
||||
|
||||
SELECT time, time_bucket(INTERVAL '2 day ', time)
|
||||
SELECT time, time_bucket(INTERVAL '2 day ', time)
|
||||
FROM unnest(ARRAY[
|
||||
TIMESTAMP '2011-01-01 01:01:01',
|
||||
TIMESTAMP '2011-01-02 01:01:01',
|
||||
@ -249,7 +252,7 @@ FROM unnest(ARRAY[
|
||||
Tue Jan 04 01:01:01 2011 | Mon Jan 03 00:00:00 2011
|
||||
(4 rows)
|
||||
|
||||
SELECT int_def, time_bucket(int_def,TIMESTAMP '2011-01-02 01:01:01.111')
|
||||
SELECT int_def, time_bucket(int_def,TIMESTAMP '2011-01-02 01:01:01.111')
|
||||
FROM unnest(ARRAY[
|
||||
INTERVAL '1 millisecond',
|
||||
INTERVAL '1 second',
|
||||
@ -282,7 +285,7 @@ ERROR: interval defined in terms of month, year, century etc. not supported
|
||||
SELECT time_bucket(INTERVAL '1 month',TIMESTAMP '2011-01-02 01:01:01.111');
|
||||
ERROR: interval defined in terms of month, year, century etc. not supported
|
||||
\set ON_ERROR_STOP 1
|
||||
SELECT time, time_bucket(INTERVAL '5 minute', time)
|
||||
SELECT time, time_bucket(INTERVAL '5 minute', time)
|
||||
FROM unnest(ARRAY[
|
||||
TIMESTAMP '1970-01-01 00:59:59.999999',
|
||||
TIMESTAMP '1970-01-01 01:01:00',
|
||||
@ -297,7 +300,7 @@ FROM unnest(ARRAY[
|
||||
Thu Jan 01 01:05:00 1970 | Thu Jan 01 01:05:00 1970
|
||||
(4 rows)
|
||||
|
||||
SELECT time, time_bucket(INTERVAL '5 minute', time)
|
||||
SELECT time, time_bucket(INTERVAL '5 minute', time)
|
||||
FROM unnest(ARRAY[
|
||||
TIMESTAMP '2011-01-02 01:04:59.999999',
|
||||
TIMESTAMP '2011-01-02 01:05:00',
|
||||
@ -343,7 +346,7 @@ FROM unnest(ARRAY[
|
||||
Sun Jan 02 01:08:00 2011 | Sun Jan 02 01:08:00 2011
|
||||
(4 rows)
|
||||
|
||||
--example to align with an origin
|
||||
--example to align with an origin
|
||||
SELECT time, time_bucket(INTERVAL '5 minute', time - (TIMESTAMP '2011-01-02 00:02:00' - TIMESTAMP 'epoch')) + (TIMESTAMP '2011-01-02 00:02:00'-TIMESTAMP 'epoch')
|
||||
FROM unnest(ARRAY[
|
||||
TIMESTAMP '2011-01-02 01:01:59.999999',
|
||||
@ -462,7 +465,7 @@ FROM unnest(ARRAY[
|
||||
Mon Jan 03 18:01:01 2011 EST | Mon Jan 03 00:00:00 2011 EST | Mon Jan 03 00:00:00 2011 EST
|
||||
(3 rows)
|
||||
|
||||
--dst: same local hour bucketed as two different hours.
|
||||
--dst: same local hour bucketed as two different hours.
|
||||
SELECT time, time_bucket(INTERVAL '1 hour', time), date_trunc('hour', time)
|
||||
FROM unnest(ARRAY[
|
||||
TIMESTAMP WITH TIME ZONE '2017-11-05 12:05:00+07',
|
||||
@ -506,7 +509,7 @@ FROM unnest(ARRAY[
|
||||
Sun Nov 05 03:05:00 2017 EST | Sun Nov 05 02:00:00 2017
|
||||
(4 rows)
|
||||
|
||||
SELECT time, time_bucket(10, time)
|
||||
SELECT time, time_bucket(10, time)
|
||||
FROM unnest(ARRAY[
|
||||
'99',
|
||||
'100',
|
||||
@ -521,7 +524,7 @@ FROM unnest(ARRAY[
|
||||
110 | 110
|
||||
(4 rows)
|
||||
|
||||
SELECT time, time_bucket(10, time,2)
|
||||
SELECT time, time_bucket(10, time,2)
|
||||
FROM unnest(ARRAY[
|
||||
'101',
|
||||
'102',
|
||||
@ -536,7 +539,7 @@ FROM unnest(ARRAY[
|
||||
112 | 112
|
||||
(4 rows)
|
||||
|
||||
SELECT time, time_bucket(10, time, -2)
|
||||
SELECT time, time_bucket(10, time, -2)
|
||||
FROM unnest(ARRAY[
|
||||
'97',
|
||||
'98',
|
||||
|
@ -13,6 +13,9 @@ CREATE INDEX ON PUBLIC."one_Partition" ("timeCustom" DESC NULLS LAST, series_0)
|
||||
CREATE INDEX ON PUBLIC."one_Partition" ("timeCustom" DESC NULLS LAST, series_1) WHERE series_1 IS NOT NULL;
|
||||
CREATE INDEX ON PUBLIC."one_Partition" ("timeCustom" DESC NULLS LAST, series_2) WHERE series_2 IS NOT NULL;
|
||||
CREATE INDEX ON PUBLIC."one_Partition" ("timeCustom" DESC NULLS LAST, series_bool) WHERE series_bool IS NOT NULL;
|
||||
\c single :ROLE_SUPERUSER
|
||||
CREATE SCHEMA "one_Partition" AUTHORIZATION :ROLE_DEFAULT_PERM_USER;
|
||||
\c single :ROLE_DEFAULT_PERM_USER;
|
||||
SELECT * FROM create_hypertable('"public"."one_Partition"', 'timeCustom', associated_schema_name=>'one_Partition', chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month'));
|
||||
--output command tags
|
||||
\set QUIET off
|
||||
|
@ -5,6 +5,10 @@
|
||||
--needed for ddl ops:
|
||||
CREATE SCHEMA IF NOT EXISTS "customSchema" AUTHORIZATION :ROLE_DEFAULT_PERM_USER_2;
|
||||
|
||||
--needed for ROLE_DEFAULT_PERM_USER_2 to write to the 'one_Partition' schema which
|
||||
--is owned by ROLE_DEFAULT_PERM_USER
|
||||
GRANT CREATE ON SCHEMA "one_Partition" TO :ROLE_DEFAULT_PERM_USER_2;
|
||||
|
||||
--test creating and using schema as non-superuser
|
||||
\c single :ROLE_DEFAULT_PERM_USER_2
|
||||
\dt
|
||||
|
@ -1,5 +1,6 @@
|
||||
\c single :ROLE_SUPERUSER
|
||||
create schema test_schema AUTHORIZATION :ROLE_DEFAULT_PERM_USER;
|
||||
create schema chunk_schema AUTHORIZATION :ROLE_DEFAULT_PERM_USER_2;
|
||||
|
||||
SET ROLE :ROLE_DEFAULT_PERM_USER;
|
||||
create table test_schema.test_table(time BIGINT, temp float8, device_id text, device_type text, location text, id int, id2 int);
|
||||
@ -43,7 +44,20 @@ SELECT * FROM test.show_columns('test_schema.test_table_no_not_null');
|
||||
SELECT _timescaledb_internal.set_time_columns_not_null();
|
||||
SELECT * FROM test.show_columns('test_schema.test_table_no_not_null');
|
||||
|
||||
select * from create_hypertable('test_schema.test_table', 'time', 'device_id', 2, chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month'));
|
||||
RESET ROLE;
|
||||
SET ROLE :ROLE_DEFAULT_PERM_USER;
|
||||
|
||||
\set ON_ERROR_STOP 0
|
||||
-- No permissions on associated schema should fail
|
||||
select * from create_hypertable('test_schema.test_table', 'time', 'device_id', 2, chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month'), associated_schema_name => 'chunk_schema');
|
||||
\set ON_ERROR_STOP 1
|
||||
|
||||
-- Granting permissions on chunk_schema should make things work
|
||||
RESET ROLE;
|
||||
GRANT CREATE ON SCHEMA chunk_schema TO :ROLE_DEFAULT_PERM_USER;
|
||||
SET ROLE :ROLE_DEFAULT_PERM_USER;
|
||||
select * from create_hypertable('test_schema.test_table', 'time', 'device_id', 2, chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month'), associated_schema_name => 'chunk_schema');
|
||||
|
||||
SELECT * FROM _timescaledb_internal.get_create_command('test_table');
|
||||
|
||||
--test adding one more closed dimension
|
||||
@ -99,6 +113,9 @@ insert into test_schema.test_table values (123456789, 23.8, 'blue', 'type1', 'ny
|
||||
select add_dimension('test_schema.test_table', 'device_type', 2);
|
||||
\set ON_ERROR_STOP 1
|
||||
|
||||
--show chunks in the associated schema
|
||||
\dt "chunk_schema".*
|
||||
|
||||
--test partitioning in only time dimension
|
||||
create table test_schema.test_1dim(time timestamp, temp float);
|
||||
select create_hypertable('test_schema.test_1dim', 'time');
|
||||
|
@ -12,6 +12,10 @@ CREATE INDEX ON PUBLIC."one_Partition" ("timeCustom" DESC NULLS LAST, series_1)
|
||||
CREATE INDEX ON PUBLIC."one_Partition" ("timeCustom" DESC NULLS LAST, series_2) WHERE series_2 IS NOT NULL;
|
||||
CREATE INDEX ON PUBLIC."one_Partition" ("timeCustom" DESC NULLS LAST, series_bool) WHERE series_bool IS NOT NULL;
|
||||
|
||||
\c single :ROLE_SUPERUSER
|
||||
CREATE SCHEMA "one_Partition" AUTHORIZATION :ROLE_DEFAULT_PERM_USER;
|
||||
\c single :ROLE_DEFAULT_PERM_USER;
|
||||
|
||||
SELECT * FROM create_hypertable('"public"."one_Partition"', 'timeCustom', associated_schema_name=>'one_Partition', chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month'));
|
||||
|
||||
--output command tags
|
||||
|
@ -19,8 +19,11 @@ CREATE TABLE PUBLIC."testNs" (
|
||||
series_bool BOOLEAN NULL
|
||||
);
|
||||
CREATE INDEX ON PUBLIC."testNs" (device_id, "timeCustom" DESC NULLS LAST) WHERE device_id IS NOT NULL;
|
||||
SELECT * FROM create_hypertable('"public"."testNs"', 'timeCustom', 'device_id', 2, associated_schema_name=>'testNs' );
|
||||
|
||||
\c single :ROLE_SUPERUSER
|
||||
CREATE SCHEMA "testNs" AUTHORIZATION :ROLE_DEFAULT_PERM_USER;
|
||||
\c single :ROLE_DEFAULT_PERM_USER
|
||||
SELECT * FROM create_hypertable('"public"."testNs"', 'timeCustom', 'device_id', 2, associated_schema_name=>'testNs' );
|
||||
|
||||
\c single
|
||||
INSERT INTO PUBLIC."testNs"("timeCustom", device_id, series_0, series_1) VALUES
|
||||
@ -142,7 +145,7 @@ SELECT time_bucket('25 hour', DATE '2012-01-01');
|
||||
|
||||
SELECT time_bucket(INTERVAL '1 day', TIMESTAMP '2011-01-02 01:01:01');
|
||||
|
||||
SELECT time, time_bucket(INTERVAL '2 day ', time)
|
||||
SELECT time, time_bucket(INTERVAL '2 day ', time)
|
||||
FROM unnest(ARRAY[
|
||||
TIMESTAMP '2011-01-01 01:01:01',
|
||||
TIMESTAMP '2011-01-02 01:01:01',
|
||||
@ -151,7 +154,7 @@ FROM unnest(ARRAY[
|
||||
]) AS time;
|
||||
|
||||
|
||||
SELECT int_def, time_bucket(int_def,TIMESTAMP '2011-01-02 01:01:01.111')
|
||||
SELECT int_def, time_bucket(int_def,TIMESTAMP '2011-01-02 01:01:01.111')
|
||||
FROM unnest(ARRAY[
|
||||
INTERVAL '1 millisecond',
|
||||
INTERVAL '1 second',
|
||||
@ -170,7 +173,7 @@ SELECT time_bucket(INTERVAL '1 year',TIMESTAMP '2011-01-02 01:01:01.111');
|
||||
SELECT time_bucket(INTERVAL '1 month',TIMESTAMP '2011-01-02 01:01:01.111');
|
||||
\set ON_ERROR_STOP 1
|
||||
|
||||
SELECT time, time_bucket(INTERVAL '5 minute', time)
|
||||
SELECT time, time_bucket(INTERVAL '5 minute', time)
|
||||
FROM unnest(ARRAY[
|
||||
TIMESTAMP '1970-01-01 00:59:59.999999',
|
||||
TIMESTAMP '1970-01-01 01:01:00',
|
||||
@ -179,7 +182,7 @@ FROM unnest(ARRAY[
|
||||
]) AS time;
|
||||
|
||||
|
||||
SELECT time, time_bucket(INTERVAL '5 minute', time)
|
||||
SELECT time, time_bucket(INTERVAL '5 minute', time)
|
||||
FROM unnest(ARRAY[
|
||||
TIMESTAMP '2011-01-02 01:04:59.999999',
|
||||
TIMESTAMP '2011-01-02 01:05:00',
|
||||
@ -204,7 +207,7 @@ FROM unnest(ARRAY[
|
||||
TIMESTAMP '2011-01-02 01:08:00'
|
||||
]) AS time;
|
||||
|
||||
--example to align with an origin
|
||||
--example to align with an origin
|
||||
SELECT time, time_bucket(INTERVAL '5 minute', time - (TIMESTAMP '2011-01-02 00:02:00' - TIMESTAMP 'epoch')) + (TIMESTAMP '2011-01-02 00:02:00'-TIMESTAMP 'epoch')
|
||||
FROM unnest(ARRAY[
|
||||
TIMESTAMP '2011-01-02 01:01:59.999999',
|
||||
@ -273,7 +276,7 @@ FROM unnest(ARRAY[
|
||||
TIMESTAMP WITH TIME ZONE '2011-01-04 01:01:01+02'
|
||||
]) AS time;
|
||||
|
||||
--dst: same local hour bucketed as two different hours.
|
||||
--dst: same local hour bucketed as two different hours.
|
||||
SELECT time, time_bucket(INTERVAL '1 hour', time), date_trunc('hour', time)
|
||||
FROM unnest(ARRAY[
|
||||
TIMESTAMP WITH TIME ZONE '2017-11-05 12:05:00+07',
|
||||
@ -299,7 +302,7 @@ FROM unnest(ARRAY[
|
||||
]) AS time;
|
||||
|
||||
|
||||
SELECT time, time_bucket(10, time)
|
||||
SELECT time, time_bucket(10, time)
|
||||
FROM unnest(ARRAY[
|
||||
'99',
|
||||
'100',
|
||||
@ -307,7 +310,7 @@ FROM unnest(ARRAY[
|
||||
'110'
|
||||
]::int[]) AS time;
|
||||
|
||||
SELECT time, time_bucket(10, time,2)
|
||||
SELECT time, time_bucket(10, time,2)
|
||||
FROM unnest(ARRAY[
|
||||
'101',
|
||||
'102',
|
||||
@ -315,7 +318,7 @@ FROM unnest(ARRAY[
|
||||
'112'
|
||||
]::int[]) AS time;
|
||||
|
||||
SELECT time, time_bucket(10, time, -2)
|
||||
SELECT time, time_bucket(10, time, -2)
|
||||
FROM unnest(ARRAY[
|
||||
'97',
|
||||
'98',
|
||||
|
Loading…
x
Reference in New Issue
Block a user