Postgres: Boundless `Text` and Back Again
brandur.org
brandur.org
To cope with this, in the same transaction that you're increasing the length of the varchar, you will also need to drop and recreate all such dependent views (and any other views that depend upon those views, etc).
This is not fun.
In comparison: increase the maximum length of the check constraint, job done.
Arguably, this could extend to real numerical data (use NUMERIC everywhere as a default), but the performance impacts of that are far more severe.
Eg: `ALTER TABLE users ADD CONSTRAINT username_max_len CHECK LENGTH(username) <= 100 NOT VALID;`
The NOT_VALID option skips checking the existing data, so the migration is quasi-instant.
That way the constraint can easily be swapped out by removing the old one and adding a new one, and you have maximum flexibility going forward.
This also doesn't require an index rebuild, and better models what's actually happening internally.
The index rebuild is still a bit of an open question — I wouldn't be surprised if Postgres had some optimizations there as well to not need it in instances where it's not necessary, but I might be wrong on that one.
I don’t think that’s the case when you have views on the table though.
The locking could also be a concern, altering the table will almost certainly need an exclusive write lock, altering a contraint may not (to check). Even if the operation is very short, the need to block every read coming after the DDL can be quite impactful to service.
If you have a legal name, you might want to write that person a letter (an invoice, injunction, notification of breach, whatever), so it must fit into the address field. If you allow a 2000 character name, it likely won't fit. Same for street names and the likes.
Not fitting a full name into a field sucks, but at least it gives the one filling it the choice how to shorten it.
If the data goes into some kind of webpage, does it even render properly if it's very large? If it goes into a hover text, or in a box that's too small for a proper scroll bar, it becomes unreadable it too big.
If text becomes really big (and it might be gigabytes if there's no limit), storage cost becomes an issue.
From this perspective, you basically never want unlimited TEXT fields anywhere, at least not exposed to customers. Maybe it's OK for internal some internal, at least if you can yell at your users if they abuse it too much.
That doesn’t help you decide how long a single line can be, though. Also, does the single-line text field prohibit newlines and how do you do that properly?
The text thing is awesome but I never thought I could be so excited about Policies. It makes everything feel so much more relaxing knowing you can’t accidentally give someone access to something they shouldn’t be able to edit.
A word of caution when using domains: many SaaS offerings that replicate your Postgres database to a data warehouse do not support domains.
Interesting on the data warehouse note — we haven't actually implemented the domain idea yet (what's in the article is more musing about it), but it's good to know about this possible downside.
(Incidentally, distinguishing between "text" and "varchar" the way you do in the article can be confusing, because in PostgreSQL plain `varchar` instead of `varchar(N)` is another way of getting an unconstrained character type.)
I'm not convinced 200 is liberal enough for some of that.
For email, a 64 character local part is RFC compliant, then 1 for the '@', and the domain can be 253 characters.
Probably similar edge cases for addresses.
The idea I was trying to get across is that of order of magnitude tiers so that you don't end up with VARCHARs of a hundred random lengths.
I tend to think that there is a point where you trade off some correctness for pragmatism. It is true that you could have a user with a 250 character email address, but in a lot of years I've never really seen a legitimate one, and the likelihood is that if you do see one then it's someone doing something weird as opposed to a legitimate customer.
Email is actually one that you might want to just leave as `TEXT` and make sure you're validating with a package, which is something you might want to do anyway. However, I still think it serves as a useful example because most people have a good feel for about how long an email address is.
---
Why should the database be the input sanitizer, though? Intermediary systems can break or degrade before it reaches PostgreSQL.
More in the realm of traditional business IT than what HN is focused on, the database is often the point of integration between several different systems, with views and triggers providing the means of abstraction at the interface boundry.
Of course ideally all such systems would only ever profer perfectly valid data, but in practice ...
It's almost like those people back in the 60s and 70s had thought about this.
That is not actually true but the GP might have gotten their wires crossed a bit between MySQL's behaviour of strait truncating and the SQL Standard's behaviour (which postgres implements) of truncating trailing spaces if they go beyond the specified length limit.
So per-spec "xxx" will fail to insert in a varchar(2), but "xx " will succeed returning just "xx" when fetching.
AFAIK Postgres has always triggered an error in that case, though it was apparently not documented in 7.1 here is the documentation from 7.2:
> Both of these types can store strings up to n characters in length. An attempt to store a longer string into a column of these types will result in an error
What you may be referring to is the following note:
> unless the excess characters are all spaces, in which case the string will be truncated to the maximum length. (This somewhat bizarre exception is required by the SQL standard.)
So the SQL standard requires silently stripping (truncating spaces) from the end until the value fits or no more spaces can be truncated.
Author here. Could you elaborate with some specifics?
One of the dangers in switching to high level languages is that people have lost any sense of data size. In C you almost always specify a max string width because that is the easiest easy to deal with strings. While C has many shortcomings, forcing the responsible programmer to deal with string width is a good thing.
Honestly as a stripe user, this sort of unvalidated input terrifies me. Stripe deals with money. All inputs ought to be validated. I figured the company would spend a lot of engineering time making sure data was cleaned and couldn't escape like this.
Today it's a string width issue. Tomorrow it's a sql injection. I'm surprised stripe let you publish this.
This is the result of build fast and break things mentality which is toxic