|
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
These are some specific questions about PostgreSQL functionality. The answers are all available in various issues of General Bits as well as the current 7.3 documentation. This test is for fun and learning only. Give it a try. Let me know if it was easy or hard. But have fun.
The answers to these questions will be published in the next edition of General Bits.
A table containing a column with an unformatted phone number and another column with a formatted phone number is wanted. The question is how to set one from the other to ensure they are always "the same." Using elaborate substring functions, it was suggested that the plain number can be converted into the formatted number. This in turn can be stored in the second column with a trigger. This problem illustrates the primary reason why it is not a good idea to store the same information twice. To ensure that the values stay in sync and are always equal often elaborate checks, triggers and formatting are required. Unless the checks are made completely fault-proof, somehow, somewhere, one will be updated with a value and the other will not. The actual requirement here is to provide the one phone number in both formatted and unformatted form. This is easily done using various formatting functions alone. The first query here will get you the unformatted phone number. The second will give you a formatted version and the third will get you both. It is assumed that the phone number is numeric. If it is not, cast it to numeric. select fname, lname, phone from addresses; select fname, lname, to_char( phone, 'FM(999)999-9999') from addresses; select fname, lname, phone, to_char( phone, 'FM(999)999-9999') from addresses; select fname, lname, phone from addresses; A view can be created to retrieve the formatted version easily if it needs to be done often. The base datum, the phone number, need be stored only once eliminating verification and the possibility of having the number and the formatted number be different. This also shows the distinction between the data and the formatted output.
Everyone likes a good tale with a happy ending. But they start bad... For the first time in six years, a table or tables were corrupted due to space filling up on a server. Ideally the data should be recovered instead of resorting to a restore. First a "SELECT * ..." revealed that the server could not come up. These were the error messages: LOG: ReadRecord: unexpected pageaddr 5/27498000 in log file 5, segment 45, offset 4816896 LOG: redo is not required PANIC: XLogWrite: write request 5/2D498000 is past end of log 5/2D498000 DEBUG: reaping dead processes LOG: startup process (pid 17031) was terminated by signal 6 LOG: aborting startup due to startup process failure Our hero, Tom, suggests that the startup failure is a bug in 7.3.3 and that an update to 7.3.4 is appropriate. This upgrade does not require a dump and restore (which would be impossible!) and it just so happened that the 7.3.4 release was readily available. The installation was quickly updated and so the server could restart and further analysis was possible. A "SELECT * ... LIMIT 5" from the table known to be corrupt now gives this error: PANIC: read of clog file 5, offset 16384 failed: Success server closed the connection unexpectedly This probably means the server terminated abnormally before or while processing the request. The connection to the server was lost. Attempting reset: Failed. !#The prognosis does not look good at this point. However, following up on the error message, the request was made for the names and sizes of files in the $PGDATA/pg_clog directory. This showed: -rw------- 1 postgres users 262144 Jul 20 15:53 0000 -rw------- 1 postgres users 262144 Jul 31 12:57 0001 -rw------- 1 postgres users 262144 Aug 12 17:32 0002 -rw------- 1 postgres users 262144 Aug 26 00:15 0003 -rw------- 1 postgres users 262144 Sep 9 23:44 0004 -rw------- 1 postgres users 16384 Sep 10 21:21 0005Obviously there is something wrong with file 0005. Note that the offset that caused the panic is the same as the size of the file. The server is trying to read off the end of the file for a transaction the pg_clog did not record. pg_clog tracks transactions. It was deduced that it was likely that pg_clog file 0005 was short because of the original space issue. The next suggestion was that the server be shutdown and the file be artificially increased by adding an 8K page of 0s at the end. This would at least alleviate the problem of running off the end of the file. Adding more than one page might be necessary and if data were recovered a good data consistency check is imperative. To add the zeros to the file the following statement was used. /dev/zero is a source for 0 data. dd, which copies binary data is told that the output should be 8K is size and that the input from /dev/zero. The output should be appended to the problem pg_clog file. dd bs=8k count=1 < /dev/zero >> $PGDATA/pg_clog/0005 After this operation, it was discovered that all of the data from the corrupt tables was indeed present. And everyone breathed a sigh of relief. This is not a technique that should be tried haphazardly. This particular set of error messages led to this particular solution. When in doubt, ask for help!
This is another twist on the standard example of the people table which contains parents and kids. The table contains all people individually, but the kid have a reference to one of their parents. This is usually an example of inheritance, however, this example will not use inheritance. Instead it will use simple referential integrity. The actual case in question is a table of accounts. Accounts may have master accounts. If they do have a master account, that account must be a row in the account table. account master_account details 1 NULL ... 2 NULL ... 4 2 ... 5 2 ... 6 3 ... <-- This is the case to preventTo ensure that all master accounts, if present are legitimate accounts in their own right define a foreign key constraint on the master_account referencing account. ALTER TABLE accounts ADD CONSTRAINT my_self_fk FOREIGN KEY (master_account) REFERENCES accounts (account);This constraint allows master_account to be NULL, but when it is not NULL, the value will be a proper account number.
|
||||||||||||||||||||||||||||||||
Comments and Corrections are welcome. Suggestions and contributions of items are also welcome. Send them in! Copyright A. Elein Mustain 2003, 2004, 2005, 2006, 2007, 2008, 2009 |