Commit Graph

326 Commits

Author SHA1 Message Date
Michael Bayne f33a376f7e Formatting tweaks. 2008-09-23 17:17:05 +00:00
Michael Bayne d7f864dfe4 Don't try to manage the cache manager. Push that burden out to the caller who
may have their own needs and arrangements.
2008-09-20 03:30:49 +00:00
Michael Bayne 3e8ac68af6 Properly handle @GeneratedValue(strategy=GenerationType.IDENTITY,
initialValue=N) for non-zero values of N. This is complicated. Depot used to
"initialize" value generators pretty much every time a table schema was
migrated. For TableValueGenerator it could just NOOP if the proper row was in
the sequence table. IdentityValueGenerator was just broken and ignored any
request to configure an initialValue, so it never did anything.

First I looked into preserving this frequent reinitialization behavior, but it
turns out that it's not possible to read the current value of a sequence in
Postgres without modifying it. So trying to do something like:

SELECT setval('"FooRecord_fooId_seq"', max(currval('"FooRecord_fooId_seq"'),
                                           cast(initialValue as bigint)));

doesn't work because you can't call currval() without first having called
nextval() (and furthermore when you do that, the Postgres client grabs a block
of sequence values for this client so that multiple clients can add rows to a
table without having to coordinate with the server and one another to assign a
new value every time a row is inserted).

So I changed Depot around to not reinitialize value generators unless it really
believes that the column in question is newly added. We can't rely on our own
auto-column creation because it's possible for someone to create a column
through a custom entity migration, so instead we just keep track of what
columns we had before we started all of our migrations (automatic and custom)
and check to see if there are any new columns after all is said and done and if
any of those have value generators, we "create" them.

This allows us to just setval() the sequence to the desired initial value
without first reading it.

This all fails if someone renames a column with a value generator. The column
will appear to Depot to be new and it will try to recreate the value generator
on that column. For TableValueGenerators that will basically NOOP and
everything will be just like it was before. For IdentityValueGenerators,
because of the way that Postgres magically creates a tablename_columnname_seq
sequence for identity value generation, when the column is renamed, the
sequence will retain the old column name and when Depot goes to try to setval()
the sequence based on the new column name, it won't exist and the migration
will fail. So at least we're not silently reinitializing the value generator to
its initial value when a column (with an identity value generator) is renamed.
We also don't try to do anything if the initialValue is not 1 (the default). So
we avoid failing or doing anything wrong if those kinds of columns are renamed.

So we only fail if someone renames a column with an identity value generator
with a non-default initial value. Since one can only put a value generator on a
primary key field and an identity value generator generally means you have
something simple like FooRecord with fooId. This means someone is renaming
their simple auto incrementing primary key field which seems extremely unlikely
because those columns usually have an obvious name that you're never going to
change. No problem!

I also haven't fixed this problem for MySQL yet. I can only handle so much
database befuckaroundery in one go.
2008-09-17 19:09:08 +00:00
Michael Bayne 5ac15a99ca Use varying size blobs for int[] columns like we do byte[]. 2008-09-16 22:51:59 +00:00
Michael Bayne b64658fd83 Handle conversion from int[] to byte[] manually rather than relying on the JDBC
driver to know how to do it.
2008-09-16 22:49:11 +00:00
Michael Bayne 9112b3c7e2 Javadoc fix from Dave. 2008-09-16 21:54:21 +00:00
Michael Bayne 84dd3c6b5f Amazingly, we had apparently never tried to insert a preconfigured row into a
table that had field generators on its primary key. The code just blindly
overwrite the supplied primary key and ran the generators anyway.

We now only run the generators if the record has no primary key. This means we
can't use field generators on non-primary-key fields, but I'm not sure we ever
meant to support that in the first place.
2008-09-16 21:33:22 +00:00
Michael Bayne e25aa25bd6 Nixed unused imports. 2008-09-16 02:01:19 +00:00
Michael Bayne 2b1b2e8334 Missed a spot. 2008-09-15 18:46:48 +00:00
Michael Bayne 759fb587dc Name things a bit more clearly to indicate that we're manipulating field
definitions, not necessarily field overrides.
2008-09-15 18:42:12 +00:00
Michael Bayne a507308c2b Zell reminds me that I want to use FieldDefinition rather than FieldOverride
which is meant to be used only in certain circumstances.
2008-09-15 18:37:04 +00:00
Michael Bayne 7e8c7fadcb Don't log a warning if we don't get a result for every primary key provided
when we're doing a query with primary keys provided by a random caller. We have
know idea where they got those keys or where they have been before we got our
filthy mitts on them.
2008-09-15 18:33:21 +00:00
Michael Bayne 2f57697c32 We're going to allow FieldOverride on @Computed records, just not on @Computed
fields. Maybe Zell will remind me why this was disallowed, but it seems that to
disallow this is to make FieldOverride useless.
2008-09-15 18:22:18 +00:00
Michael Bayne 98ac644ad9 Ah, entities.keySet() is misleading because it contains records that were found
in the cache as well as records loaded from earlier passes in cases where we
split our query up to avoid database breaking in() clause sizes. Now we track
exactly what we got this time around and report that.
2008-09-12 01:55:54 +00:00
Michael Bayne 2611a1076b Let's have a stack trace here because these mismatches are just plain bizarre. 2008-09-12 01:49:06 +00:00
Michael Bayne d47e85fe9f If we're going to magically convert ByteEnum to an integer type, then we should
magically assign it a default value of 0 like we do for our other integer types.
2008-09-12 00:24:14 +00:00
Michael Bayne 96bd8b56a0 We're seeing some weirdness here, so let's log the original statement along
with the actual set of wanted and obtained keys when we have a mismatch.
2008-09-10 18:09:23 +00:00
Michael Bayne 27b619d59b Let's log a stack trace on lazy initialization so that we can see who the
culprit is.
2008-09-10 18:01:24 +00:00
Michael Bayne c4ddf1853c Created an explicit EntityMigration.Add for when you want to add a column to a
database and need to provide a defaultValue at the time that you add it, but
don't want to have to define a permanent default value on the field.
2008-09-10 02:00:19 +00:00
Michael Bayne 00d6ae5492 Don't try to do the primary key lookup on delete for records that define no
primary key.
2008-09-08 19:01:30 +00:00
Michael Bayne ffeb6534c4 Cope with the goddamned broken generics implementation in JDK 1.5. 2008-09-08 18:58:12 +00:00
Michael Bayne f1dd34e4b3 We need Key to export a Key.Expression which we can use inside the SQL for a
KeySet so that the "where" keyword is not repeated every time we bind a key.
2008-09-08 17:54:11 +00:00
Michael Bayne 56c4394b29 Beans/frank. 2008-09-08 16:48:32 +00:00
Michael Bayne d5619a3b28 Automatically add the shadow to our type set for @Computed(shadowOf=FooRecord)
record classes.
2008-09-06 02:38:20 +00:00
Michael Bayne 9a7a78080c We need to set up our _builder in WithKeys. Also moved loadRecords() down below
loadAndResolve().
2008-09-06 02:27:53 +00:00
Michael Bayne 2f335c4dc8 Actually, if we use Key we don't need to specify the type. It's already in the
keys. So we can have loadAll(Class,Collection<Comparable>) and
loadAll(Collection<Key>) and not run into type erasure problems. Yay!
2008-09-06 02:06:44 +00:00
Michael Bayne 9a21071c82 Type jockeying. 2008-09-06 01:59:52 +00:00
Michael Bayne 35f654a8c1 Added loadAll() which takes a collection of primary keys. Since we've already
got the primary keys, this goes right to phase two wherein we check the cache
for hits and load the remaining records by primary key (and cache them).
2008-09-06 01:54:08 +00:00
Michael Bayne 52de64001d Allow the cache to be explicitly bypassed. 2008-09-06 00:34:29 +00:00
Michael Bayne 089706427e Be sure to report that we throw DatabaseException for documentation purposes. 2008-09-06 00:30:25 +00:00
Michael Bayne fe1aff3842 Tidying. 2008-09-06 00:17:52 +00:00
Michael Bayne 84c32cc5e3 We need to use the key in our or clause, not its non-existent where expression. 2008-09-06 00:13:05 +00:00
Michael Bayne 263529c929 Use the SelectClause to obtain our types so that the main record class is
always properly added. Also made SelectClause freak out if it's provided with
bogus clauses.
2008-09-05 23:17:37 +00:00
Michael Bayne 8b6f575af8 Nixed unused import. 2008-09-05 23:03:49 +00:00
Michael Bayne ae9e0acef8 We need to let you express whether or not you want your keys from the master
server or if it's OK to get them from a (potentially slightly out of date)
replica. If you're going to modify rows based on the results of findAllKeys(),
you should probably get them from the master server, if you're just reading
data, you can talk to a replica.
2008-09-05 23:03:08 +00:00
Michael Bayne 2e4decf18a Added findAllKeys() for when you only need the keys. 2008-09-05 22:58:05 +00:00
Michael Bayne 95d316d28e One more unused import. 2008-09-05 22:43:38 +00:00
Michael Bayne 709a6ce203 Unused import patrol. 2008-09-05 22:43:06 +00:00
Michael Bayne cd8184f34f Some method ordering. 2008-09-05 22:37:23 +00:00
Michael Bayne fb64881c82 We're handling Key query construction directly instead of letting it look like
a WhereClause, so we need to add our own where.
2008-09-05 22:36:53 +00:00
Michael Bayne 4c41561f0f PrimaryKeySet -> KeySet. 2008-09-05 22:16:55 +00:00
Michael Bayne 249f4a5106 Now we don't have to provide our values as an ArrayList. 2008-09-05 20:07:43 +00:00
Michael Bayne 4bcfda861d Ah, Key actually is PrimaryKey and does not in fact keep the primary key
columns around. Cleaned some things up along those lines.
2008-09-05 20:05:44 +00:00
Michael Bayne 84622e56c7 Formalized the two-phase "get primary keys that match an arbitrary query, then
load or modify the rows that match those keys" pattern so that we can almost
always just magically do the right thing with regard to the cache. Added a
version of deleteAll() that makes use of this.

Also nixed a bunch of checked exception tomfoolery which was almost entirely
unnecessary and now with DatabaseException is completely unnecessary.

A few things remain to be done:

- PrimaryKeySet tries to be "smart" if its passed 0 keys and use
LiteralExp("false") but that causes things to freak out because Depot then
doesn't know what primary class it's dealing with. I'm probably going to make
All and None expressions that match all and none of the records in a table
respectively.

- deleteAll() doesn't currently split its keys into chunks small enough to be
digestible by the database if we match more than 32,768 rows. I'll see if I
can't abstract out that code from FindAllQuery so that we can easily use it
everywhere. It would be cool to handle that a a lower level and allow the
WhereClause to say that it needs to be run in phases, but that would probably
complicate the crap out of the low-level code.

- I need to create PrimaryKey to go between Key and PrimaryKeySet so that we
can avoid duplicating the primary key columns thousands of times in a large
PrimaryKeySet.
2008-09-05 19:39:08 +00:00
Michael Bayne 67bdfda3fe Changed Depot to throw a RuntimeException on unexpected database error instead
of a checked exception. Invariably, we don't do anything with our
PersistenceExceptions except let them percolate all the way to the top and then
log a warning. We can probably automate the process of logging a warning with
useful information and save ourselves the trouble of doing it manually
everywhere.
2008-09-03 16:10:06 +00:00
Michael Bayne 2fd131c0d2 Any collection of anything that extends QueryClause is generally all we need. 2008-09-03 00:55:07 +00:00
Michael Bayne beef018b03 Nixed unused import. 2008-08-25 18:16:35 +00:00
Michael Bayne 43e1a38703 Let's go all the way up to Short.MAX_VALUE. 2008-08-25 16:27:43 +00:00
Michael Bayne d54c633401 Don't try to use an IN() clause with more than 16738 entries. 2008-08-25 15:57:43 +00:00
Michael Bayne 01962836f7 Nixed unneeded log message. 2008-08-20 18:17:52 +00:00