ig has asked for the wisdom of the Perl Monks concerning the following question:

I have been looking at perguts and perlapi and the perl source but I can't yet answer my question.

My question arises because I have been looking at BerkeleyDB and either I don't understand how magic should be handled (this is quite likely because I know little about it) or it is being handled incorrectly (it seems so to me, but I suspect I simply don't understand correctly).

Key values passed to various methods of BerkelyDB are handled by the following typemap

T_dbtkeydatum_btree { SV* my_sv = $arg ; DBM_ckFilter(my_sv, filter_store_key, \"filter_store_key\" +); DBT_clear($var) ; SvGETMAGIC($arg) ; if (db->recno_or_queue || (db->type == DB_BTREE && flagSet(DB_SET_RECNO))) { Value = GetRecnoKey(db, SvIV(my_sv)) ; $var.data = & Value; $var.size = (int)sizeof(db_recno_t); } else { STRLEN len; $var.data = SvPV(my_sv, len); $var.size = (int)len; } }

The relevant bit of the resulting C code for the db_get method is

SV* my_sv = ST(1) ; DBM_ckFilter(my_sv, filter_store_key, "filter_store_key"); DBT_clear(key) ; SvGETMAGIC(ST(1)) ;

If a store filter has been set, the DBM_ckFilter() call may modify my_sv.

It seems to me that SvGETMAGIC, if it is called at all, should be called before the SV is accessed and that SvSETMAGIC should be called after the filter has run in case the value has been changed, ideally only if the filter has modified the value. Calling SvGETMAGIC after the filter has read and modified the value seems to be too late and although the value may be modified there is no provision for calling set magic.

Various instances of SvGETMAGIC and mg_get in sv.c and elsewhere seem to call SvGETMAGIC/mg_get before using the SV but, confusingly for me, perlapi says:

mg_get Do magic after a value is retrieved from the SV. See "sv_magic". int mg_get(SV* sv)

but perlguts says, in its description of MGVTBL:

svt_get Do something before the value of the SV is retrieved.

which seems more consistent with most of the examples I have looked at.

In most descriptions of mg_get/SvGETMAGIC that I have found, there is no indication of the order that should be followed. In contrast, there are many comments and API documentation that mg_set/SvSETMAGIC should be called after the value of the SV is changed.

Do I understand correctly that SvGETMAGIC/mg_get should be called before accessing an SV?

When accessing an SV passed to an XS routine, should SvGETMAGIC always be called before calling an access method that does not handle magic (e.g. SvTRUE)?

In the case of BerkelyDB, would it be better to call SvGETMAGIC and SvSETMAGIC before and after the filter respectively, as follows:

SV* my_sv = ST(1) ; SvGETMAGIC(ST(1)) ; DBM_ckFilter(my_sv, filter_store_key, "filter_store_key"); SvSETMAGIC(ST(1)) ; DBT_clear(key) ;

Or is it more approriate to trust that the filter, which is a perl subroutine, will handle magic appropropriately and therefore there is no need to call SvGETMAGIC or SvSETMAGIC?

Or am I totally misunderstanding and it is correct/best as it is?

Also, will bad things happen if SvGETMAGIC or SvSETMAGIC are called excessively (e.g. if, not being sure, I call them just to be "safe")? I suppose this depends on what the magic is and how it is implemented, in which case I am very uncertain about when I should or shouldn't call them. Any guidance would be appreciated.

update: DB_File calls SvGETMAGIC in the same way as BerkeleyDB. I am comming to the conclusion that the SvGETMAGIC is to be called before accessing an SV with magic, despite the description of mg_get in perlapi, and that in the example in BerkeleyDB noted above it is called to handle the case that there is no filter. If there is a filter, it must call get and/or set magic appropriately itself.

update2: My answer to my question is:

SvGETMAGIC should be called before accessing an SV with a method that does not handle magic if it is possible that that SV has magic. Note that this includes a method which sets the SV (i.e. get magic should be called before any access). If the SV does not have magic it merely checks the flags, so if one is unsure it is best to call it before accessing an SV.

SvSETMAGIC should be called after setting an SV with a method that does not handle magic if it is possible that that SV has magic. As for SvGETMAGIC, there is no harm if the SV does not have magic, so better to call it if one is uncertain.

perlapi identifies methods which handle magic. If the documentation of a method does not specify whether it handles magic, it may be best to call SvGETMAGIC before and SvSETMAGIC after, according with the operation.

update3: Links