-
Notifications
You must be signed in to change notification settings - Fork 180
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ability to use symbols as field names instead of strings #306
Conversation
d63dbd0
to
48f1163
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests look good.
@@ -390,6 +395,27 @@ pgresult_get(VALUE self) | |||
return this->pgresult; | |||
} | |||
|
|||
static VALUE pg_cstr_to_sym(char *cstr, unsigned int flags, int enc_idx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The signature of this function could be more clear that it is specific to field names.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shrug! I don't care much about static function names.
this->nfields = i + 1; | ||
|
||
RB_GC_GUARD(fname); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose the call to (or return from?) pg_cstr_to_sym
makes this redundant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
@@ -583,24 +606,23 @@ pgresult_nfields(VALUE self) | |||
|
|||
/* | |||
* call-seq: | |||
* 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems worth mentioning field_name_type
in these cases where "string or symbol" may be returned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why deprecate :static_symbol
the moment it is introduced? Is there a use case for having it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
: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.
ext/pg_result.c
Outdated
UNUSED(nfields); | ||
newthis->flags = this->flags; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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: oracle/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
ext/pg_result.c
Outdated
{ | ||
VALUE fname; | ||
if( flags & PG_RESULT_FIELD_NAMES_SYMBOL ){ | ||
#ifndef TRUFFLERUBY |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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_keys
isn't used in ActiveRecord.This raises ruby version requirement to 2.2, since it depends on GC'able dynamic symbols.
Fixes #278