XS, Advanced XS Callback Patch For OCI, Part V Much More 'C' 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 next part of the patch which is very similar overview of the next function that is going to be patched.


Now that we fully understand 'dbd_db_STORE_attrib' function we can move on to the next part of our patch and that is updating the 'dbd_db_FETCH_attrib' function so lets look at that in detail

it is expecting only 3 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

Like the last function the SV are our Perl values while the 'imp_dbh_t' is where in our 'c' code is going to look for the data we are asking for.

So the patch for this function is a little less complex


	else if (kl==13 && strEQ(key, "ora_drcp_incr") ) {
		retsv = newSViv(imp_dbh->pool_incr);
++	else if (kl==15 && strEQ(key, "ora_ha_function") ) {
++		if (imp_dbh->ora_ha_function)) {
++			retsv = newSVsv(imp_dbh->ora_ha_function));
++		}
++	}
	else if (kl==16 && strEQ(key, "ora_taf_function") ) {

Again we place it within that #ifdef ORA_OCI_112 compiler directive like the last patch.
Following the same pattern again we check 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' yet again with the 'strEQ' macro against a static string value of our key.

Now we check to make sure there is a value for 'ora_ha_function' in our 'c' and if there is we simply use another XS macro 'newSVsv' to create a new SV and stick it in restsc so it can be returned later in the function. We use this here rather than say something like this


newSVpv((char *)imp_dbh->ha_function,0);

which would return a string representation of our function. As we are setting this up to take either a 'name' or reference to a function I have gone with 'newSVsv' as that will handle both properly.

Now two last points before I leave this function so first if you look at the bottom of the function at this code
	if (cacheit) {	/* cache for next time (via DBI quick_FETCH)	*/
		SV **svp = hv_fetch((HV*)SvRV(dbh), key, kl, 1);
		*svp = retsv;
		(void)SvREFCNT_inc(retsv);	/* so sv_2mortal won't free it	*/

you will see a little XS clean up going on, so first if this item is being cached I wan to add that to my originating Perl object so I no not have to use this function to get it. So on the first line I have SV that is a pointer to a pointer and that takes the SV** that comes from the XS macro call 'hv_fetch' where I coerce a hashvalue pointer (HV*) from my dbh and I use the SvRV macro to deferace the dbh pointer back to the perl where it looks for my key value (key and kl)
Now if I find it I get rid of the present values by useing the XM macro sv_free but not to the pointer to the pointer just to the pointer, one '*', then I set the pointer to point to the value that was passed in and then to stop it from being freed too soon I increment its retrace counter by one with yet another XM macro SvREFCNT_inc.

Now in the next snippet at the very end

     if (retsv == &PL_sv_yes || retsv == &PL_sv_no)
		return retsv; /* no need to mortalize yes or no */

	return sv_2mortal(retsv);

I simply return if my return my value it it the same as PL_sv_yes or PL_sv_no. Now these two XS variable are a very easy way for the XS programmer can set something to true and false rather that the very risky use of (SV *) 0 which can it used incorrectly result in a null pointer being returned which can really spoil you programming day.

Finally the last line I moralize the retsv with, you guessed it another XS macro sv_2mortal which sets retsv to be garbage collected once all references to it are gone.

Well that is enough for tonight.

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