XS, Advanced XS Callback Patch For OCI, Part IV Finally Some Code but no Perl and just a little XS

Adding some more for the new chapter in XS Fun. Today I am just going to go carry on with the first part of the patch but like the title says I don't think there well be any Perl or XS today


So now that we have defined what our patch will fit into the DBI API lets look into how we get our values into our 'c' code.

Well DBD::Oracle, and most DBD for that matter, there is set pattern to get an value from the Perl attribute Hash-Ref and load it into our 'c' code. This is of course mostly due to 'c' language being a very closely typed and strictly structured language so playing about with variables and alike require much more care than your typical Perl mash-up.

So where we have to do this is in dbdimp.c and it has a

 
int
dbd_db_STORE_attrib(SV *dbh, imp_dbh_t *imp_dbh, SV *keysv, SV *valuesv)

function which takes our value from the perl attributes has and as the name implies stores it to memory.

We also need to get this value from memory so dbdimp.c has a

 
SV *
dbd_db_FETCH_attrib(SV *dbh, imp_dbh_t *imp_dbh, SV *keysv)

function which again gets our has value from memory.

What these functions basically mimic the "STORE" and "FETCH" functions found with a Perl hash, this is 'c' of course so things are a little more verbose than in Perl. So lets look at int dbd_db_STORE_attrib in detail

it is expecting 4 prams

  1. SV *dbh, a pointer to SV 'Scalar Value' that is the current DBI DB Handle
  2. imp_dbh_t *imp_dbh, a pointer to a structure called 'imp_dbh_t' that is used store our value
  3. SV *keysv, a 'SV' pointer to the key for the value
  4. SV *valuesv, and finally a 'SV' pointer to the value

Now in the above case the SV are our Perl values while the 'imp_dbh_t' is where in our 'c' code we are going to save the incoming data. Well so there is some XS code here after all.

So the patch for this function is
 
	}
        else if (kl==13 && strEQ(key, "ora_drcp_incr") ) {
            imp_dbh->pool_incr = SvIV (valuesv);
       }
++	else if (kl==15 && strEQ(key, "ora_ha_function") ) {
++		if (imp_dbh->ha_function)
++			SvREFCNT_dec(imp_dbh->ha_function);
			
++		imp_dbh->ha_function = newSVsv(valuesv);
++		if (SvTRUE(valuesv)) {
++			enable_ha(dbh, imp_dbh);
++		} else {
++			disable_ha(imp_dbh);
++		}
++	}
#endif
    else if (kl==16 && strEQ(key, "ora_taf_function") ) {
        if (imp_dbh->taf_function)
Now what is going on here. Well first you will notice I have added inside the '#endif' which is the lower part of '#ifdef ORA_OCI_112' so for the less 'c' inclined out there this is a compiler directive so the code in this block will only be compiled if the present version of OCI is 11.2 as the ha callback we are going to use will only work with that client or later.

Next we check to make sure the length of the key we are interested in matches up with the length of the key passed in by checking 'kl' against the exact length of our incoming key 'ora_ha_function', now we cheat 'c' a little here by using a Perl XS macro 'strEQ' to check the value of our incoming key against a static string value of our key.

Next is a little bit of garbage collection as if this function had been created before on we use the XS macro 'SvREFCNT_dec' to set the reference counter of the old value to '0' so it is garbage collected by Perl.

Next I set the value of 'ha_function' on the imp_dbh_t to an exact duplicate of the incoming value using another XS macro called newSVsv and This way I can pass both a code reference or just the name of function.

Finally I use another XS macro 'SvTRUE' to ensure what I passed in is a good value and if it is I invoke the enable_ha function that will set up my callback. If it fails from some reason or if I want to remove the callback by setting it to undef the 'disable_ha' function is called which removes the callback

and now bedtime

images22.jpg

2 Comments

A feature request for XSFun - would you consider advanced topics concerning things like memory management in the future? I had a problem I dropped a while back about removing a node from a Boost::Graph object because the size of the graph means I start running out of memory to run some of the algorithms. It would be nice if I could be assured that I was doing the right thing and freeing up memory. Chapters 1-xx look good so far. Anything that helps people adapt existing C libraries cannot be a bad thing.

Leave a comment

About byterock

user-pic Long time Perl guy, a few CPAN mods allot of work on DBD::Oracle and a few YAPC presentations