Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 894aba3

Browse files
saihajlutter
authored andcommitted
store/postgres: insist on a database with C locale
1 parent 9435720 commit 894aba3

File tree

4 files changed

+84
-1
lines changed

4 files changed

+84
-1
lines changed

NEWS.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- The two affected deployments are: `Qmccst5mbV5a6vT6VvJMLPKMAA1VRgT6NGbxkLL8eDRsE7` and `Qmd9nZKCH8UZU1pBzk7G8ECJr3jX3a2vAf3vowuTwFvrQg`;
99
- Here's an example [manifest](https://ipfs.io/ipfs/Qmd9nZKCH8UZU1pBzk7G8ECJr3jX3a2vAf3vowuTwFvrQg), taking a look at the data sources of name `ERC721` and `CryptoKitties`, both listen to the `Transfer(...)` event. Considering a block where there's only one occurence of this event, `graph-node` would duplicate it and call `handleTransfer` twice. Now this is fixed and it will be called only once per event/call that happened on chain.
1010
- In the case you're indexing one of those, you should first upgrade the `graph-node` version, then rewind the affected subgraphs to the smallest `startBlock` of their subgraph manifest. To achieve that the `graphman rewind` CLI command can be used.
11+
- We now check that the database uses the `C` locale and `UTF8` character encoding. For new installations, `graph-node` will panic on startup if the database uses any other locale. The easiest way to make sure this check passes is to create the database cluster with `initdb -E UTF8 --locale C`. We will provide instructions on migrating existing installations in the future.
1112

1213
## v0.28.2
1314

@@ -42,7 +43,7 @@ Yanked. Please migrate to `v0.28.2`.
4243
E.g. `$ graphman --node-id index_node_0 --config graph-node.toml config provider mainnet`
4344
- Experimental support for GraphQL API versioning has landed. [#3185](https://github.com/graphprotocol/graph-node/pull/3185)
4445
- Progress towards experimental support for off-chain data sources. [#3791](https://github.com/graphprotocol/graph-node/pull/3791)
45-
- Experimental integration for substreams. [#3777](https://github.com/graphprotocol/graph-node/pull/3777), [#3784](https://github.com/graphprotocol/graph-node/pull/3784), [#3897](https://github.com/graphprotocol/graph-node/pull/3897), [#3765](https://github.com/graphprotocol/graph-node/pull/3765), and others
46+
- Experimental integration for substreams. [#3777](https://github.com/graphprotocol/graph-node/pull/3777), [#3784](https://github.com/graphprotocol/graph-node/pull/3784), [#3897](https://github.com/graphprotocol/graph-node/pull/3897), [#3765](https://github.com/graphprotocol/graph-node/pull/3765), and others
4647

4748
### Bug fixes
4849

store/postgres/src/catalog.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ table! {
4545
name -> Text,
4646
}
4747
}
48+
// Readonly; only mapping the columns we want
49+
table! {
50+
pg_database(datname) {
51+
datname -> Text,
52+
datcollate -> Text,
53+
datctype -> Text,
54+
}
55+
}
4856

4957
// Readonly; not all columns are mapped
5058
table! {
@@ -114,6 +122,56 @@ const CREATE_EXCLUSION_CONSTRAINT: bool = true;
114122
#[cfg(not(debug_assertions))]
115123
const CREATE_EXCLUSION_CONSTRAINT: bool = false;
116124

125+
pub struct Locale {
126+
collate: String,
127+
ctype: String,
128+
encoding: String,
129+
}
130+
131+
impl Locale {
132+
/// Load locale information for current database
133+
pub fn load(conn: &PgConnection) -> Result<Locale, StoreError> {
134+
use diesel::dsl::sql;
135+
use pg_database as db;
136+
137+
let (collate, ctype, encoding) = db::table
138+
.filter(db::datname.eq(sql("current_database()")))
139+
.select((
140+
db::datcollate,
141+
db::datctype,
142+
sql::<Text>("pg_encoding_to_char(encoding)::text"),
143+
))
144+
.get_result::<(String, String, String)>(conn)?;
145+
Ok(Locale {
146+
collate,
147+
ctype,
148+
encoding,
149+
})
150+
}
151+
152+
pub fn suitable(&self) -> Result<(), String> {
153+
if self.collate != "C" {
154+
return Err(format!(
155+
"database collation is `{}` but must be `C`",
156+
self.collate
157+
));
158+
}
159+
if self.ctype != "C" {
160+
return Err(format!(
161+
"database ctype is `{}` but must be `C`",
162+
self.ctype
163+
));
164+
}
165+
if self.encoding != "UTF8" {
166+
return Err(format!(
167+
"database encoding is `{}` but must be `UTF8`",
168+
self.encoding
169+
));
170+
}
171+
Ok(())
172+
}
173+
}
174+
117175
/// Information about what tables and columns we have in the database
118176
#[derive(Debug, Clone)]
119177
pub struct Catalog {

store/postgres/src/connection_pool.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -980,6 +980,19 @@ impl PoolInner {
980980
let conn = self.get().map_err(|_| StoreError::DatabaseUnavailable)?;
981981

982982
let start = Instant::now();
983+
if let Err(msg) = catalog::Locale::load(&conn)?.suitable() {
984+
if &self.shard == &*PRIMARY_SHARD && primary::is_empty(&conn)? {
985+
die(
986+
&pool.logger,
987+
"Database does not use C locale. \
988+
Please check the graph-node documentation for how to set up the database locale",
989+
&msg,
990+
);
991+
} else {
992+
warn!(pool.logger, "{}.\nPlease check the graph-node documentation for how to set up the database locale", msg);
993+
}
994+
}
995+
983996
advisory_lock::lock_migration(&conn)
984997
.unwrap_or_else(|err| die(&pool.logger, "failed to get migration lock", &err));
985998
// This code can cause a race in database setup: if pool A has had

store/postgres/src/primary.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1519,6 +1519,17 @@ impl<'a> Connection<'a> {
15191519
}
15201520
}
15211521

1522+
/// Return `true` if we deem this installation to be empty, defined as
1523+
/// having no deployments and no subgraph names in the database
1524+
pub fn is_empty(conn: &PgConnection) -> Result<bool, StoreError> {
1525+
use deployment_schemas as ds;
1526+
use subgraph as s;
1527+
1528+
let empty = ds::table.count().get_result::<i64>(conn)? == 0
1529+
&& s::table.count().get_result::<i64>(conn)? == 0;
1530+
Ok(empty)
1531+
}
1532+
15221533
/// A struct that reads from pools in order, trying each pool in turn until
15231534
/// a query returns either success or anything but a
15241535
/// `Err(StoreError::DatabaseUnavailable)`. This only works for tables that

0 commit comments

Comments
 (0)