Add ability to use symbols as field names instead of strings#306
Add ability to use symbols as field names instead of strings#306larskanis merged 7 commits intoged:masterfrom
Conversation
d63dbd0 to
48f1163
Compare
| return this->pgresult; | ||
| } | ||
|
|
||
| static VALUE pg_cstr_to_sym(char *cstr, unsigned int flags, int enc_idx) |
There was a problem hiding this comment.
The signature of this function could be more clear that it is specific to field names.
There was a problem hiding this comment.
Shrug! I don't care much about static function names.
| this->fnames[i] = pg_cstr_to_sym(cfname, this->flags, this->enc_idx); | ||
| this->nfields = i + 1; | ||
|
|
||
| RB_GC_GUARD(fname); |
There was a problem hiding this comment.
I suppose the call to (or return from?) pg_cstr_to_sym makes this redundant?
There was a problem hiding this comment.
A static function like pg_cstr_to_sym() could be inlined by the compiler, so it's not safe to protect the VALUE from being GC'ed. However a call to a non-static function is sufficient to protect it from being GC'ed, so the call to rb_obj_freeze() is (and was) already enough.
| * res.fname( index ) -> String | ||
| * res.fname( index ) -> String or Symbol | ||
| * | ||
| * Returns the name of the column corresponding to _index_. |
There was a problem hiding this comment.
It seems worth mentioning field_name_type in these cases where "string or symbol" may be returned.
There was a problem hiding this comment.
Yes, I'll change this.
| * It can be set to one of: | ||
| * * +:string+ to use String based field names | ||
| * * +:symbol+ to use Symbol based field names | ||
| * * +:static_symbol+ to use pinned Symbol (can not be garbage collected) - Don't use this, it will probably removed in future. |
There was a problem hiding this comment.
Why deprecate :static_symbol the moment it is introduced? Is there a use case for having it?
There was a problem hiding this comment.
:static_symbol is the classic way to create symbols from C and it is also used by mysql2 gem. So I wanted to be able compare and benchmark it a bit more. So far I think it is mostly obsolete.
| VALUE result = pg_new_result(this->pgresult, this->connection); | ||
| t_pg_result *newthis = pgresult_get_this(result); | ||
| UNUSED(nfields); | ||
| newthis->flags = this->flags; |
There was a problem hiding this comment.
I don't grok pg_new_result, so this is a naive question: should this copy happen inside pg_new_result?
There was a problem hiding this comment.
Hmm, good question! If I think about it a bit, I notice that the initial struct values are copied from this->connection in pg_new_result, but they should be copied from this instead. So currently typemap= is broken on stream_each_tuple, unless it's already set on the connection. I'll think a bit more about it, how this can be solved best.
There was a problem hiding this comment.
I fixed this issue in commit 6a450fa on the master branch by introducing a result copy function instead of reusing pg_new_result. Thank you for highlighting this!
|
Thank you @cbandy for your valuable feedback! I'll come back with an improved version. |
1191f40 to
cb1047d
Compare
|
@ged I would appreciate an opinion from you. Is the API OK for you? |
|
@larskanis : Yes, this looks good to me. Just to clarify: you're including |
|
@ged : No, not to compare against What do you think about |
|
Ah, okay. The method name makes sense to me, as does keeping the :static_symbol setting. 👍 |
|
@ged The second question was more about adding |
|
Oh, then yes I think that'd be useful. I guess I took its utility for granted. ;) |
This adds: * PG::Result#field_name_type= * PG::Result#field_name_type * PG::Result#field_names_as Symbol comparison and lookup is faster, since the string hash is generated at Symbol creation. So retrieval of Symbol based field names is somewhat slower, but this is easily outperformed in frameworks that do a lot of lookups. This raises ruby version requirement to 2.2, since it depends on GC'able symbols. Fixes ged#278
0ae39a9 to
fd66f35
Compare
Truffleruby doesn't support rb_check_symbol_cstr() so far, but all symbols in Truffleruby are GC'd anyway. So we can use classic ID2SYM to allocate the Symbol objects. Discussed here: truffleruby/truffleruby#1814
It allows to set the field name type on a connection scope.
Added methods are:
* PG::Connection#field_name_type=
* PG::Connection#field_name_type
330b4de to
fb49bba
Compare
| { | ||
| VALUE fname; | ||
| if( flags & PG_RESULT_FIELD_NAMES_SYMBOL ){ | ||
| #ifndef TRUFFLERUBY |
There was a problem hiding this comment.
The code here looks correct for :symbol and :string on truffle ruby, but it looks like :static_symbol will produce strings.
It was using strings before.
|
Excellent work as usual sir! 👍 |
This adds:
Comparison and lookup is faster on symbols than on strings, since the string hash of symbols is generated at Symbol creation. So retrieval of Symbol based field names is somewhat slower, but this is easily outperformed in frameworks that do a lot of lookups.
There are currently two ways to create hashes in C: dynamic and static symbols. Dynamic symbols are GC'ed and static symbols aren't. I added both ways to this PR. Non-GC'able symbols can have unexpected memory bloat, when field names are dynamically generated. Since both ways showed comparable timings, I think we could remove static symbols again.
Mysql2 implements symbol keys since ages, but only as static symbols. Maybe the possible memory bloat is a reason why
symbolize_keysisn't used in ActiveRecord.This raises ruby version requirement to 2.2, since it depends on GC'able dynamic symbols.
Fixes #278