Postgresql c function returning one row with 2 fileds - postgresql

I'm new in postgresql c function and I start following examples.
I want to write a simple function that has inside an SQL and receiving parameter evaluete and return 2 fields as sum of 2 columns, separately (for now to be simpler).
The function below has problem passing the check
(get_call_result_type(fcinfo, &resultTypeId, &resultTupleDesc) != TYPEFUNC_COMPOSITE)
If I remove this line I get 1 integer as result from this query
select * from pdc_imuanno(2012);
and error from
select (a).* from pdc_imuanno(2012) a;
because is not a composite type.
Question is I how I can prepare template for tuple if it's not correct this
resultTupleDesc = CreateTemplateTupleDesc(2, false);
TupleDescInitEntry(resultTupleDesc, (AttrNumber) 1, "abp1", FLOAT4OID, -1, 0);
TupleDescInitEntry(resultTupleDesc, (AttrNumber) 2, "abp2", FLOAT4OID, -1, 0);
And more in
get_call_result_type(fcinfo, &resultTypeId, &resultTupleDesc)
fcinfo what is and where come from?
source table:
CREATE TABLE imu.calcolo (
codfis character varying(16) NOT NULL,
anno integer NOT NULL,
abp1 numeric,
abp2 numeric,
CONSTRAINT imucalcolo_pkey PRIMARY KEY (codfis, anno)
)
WITH ( OIDS=FALSE );
-------------------------------------------------------
#include "postgres.h"
#include "fmgr.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "executor/spi.h"
#include "lib/stringinfo.h"
#include "miscadmin.h"
#include <math.h>
#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/numeric.h"
#include "access/htup_details.h"
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
PG_FUNCTION_INFO_V1(test_query);
Datum test_query(PG_FUNCTION_ARGS);
Datum
test_query(PG_FUNCTION_ARGS)
{
TupleDesc resultTupleDesc, tupledesc;
bool bisnull, cisnull;
Oid resultTypeId;
Datum retvals[2];
bool retnulls[2];
HeapTuple rettuple;
sprintf(query,"SELECT anno, abp1::real, abp2::real "
"FROM imu.calcolo WHERE anno = %d;",PG_GETARG_INT32(0));
int ret;
int proc;
float abp1 = 0;
float abp2 = 0;
SPI_connect();
ret = SPI_exec(query,0);
proc = SPI_processed;
if (ret > 0 && SPI_tuptable != NULL)
{
HeapTuple tuple;
tupledesc = SPI_tuptable->tupdesc;
SPITupleTable *tuptable = SPI_tuptable;
for (j = 0; j < proc; j++)
{
tuple = tuptable->vals[j];
abp1 += DatumGetFloat4(SPI_getbinval(tuple, tupledesc, 2, &bisnull));
abp2 += DatumGetFloat4(SPI_getbinval(tuple, tupledesc, 3, &cisnull));
}
}
resultTupleDesc = CreateTemplateTupleDesc(2, false);
TupleDescInitEntry(resultTupleDesc, (AttrNumber) 1, "abp1", FLOAT4OID, -1, 0);
TupleDescInitEntry(resultTupleDesc, (AttrNumber) 2, "abp2", FLOAT4OID, -1, 0);
if (get_call_result_type(fcinfo, &resultTypeId, &resultTupleDesc) != TYPEFUNC_COMPOSITE) {
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("function returning record called in context that cannot accept type record")));
}
resultTupleDesc = BlessTupleDesc(resultTupleDesc);
SPI_finish();
retvals[0] = Float4GetDatum(abp1);
retvals[1] = Float4GetDatum(abp2);
retnulls[1] = bisnull;
retnulls[2] = cisnull;
rettuple = heap_form_tuple( resultTupleDesc, retvals, retnulls);
PG_RETURN_DATUM( HeapTupleGetDatum( rettuple ) );
}
creation function:
CREATE FUNCTION pdc_imuanno(integer)
RETURNS float
AS 'pdc','test_query'
LANGUAGE C STABLE STRICT;
ALTER FUNCTION pdc_imuanno(integer) OWNER TO www;
query:
select * from pdc_imuanno(2012);
Ok I find the simple and silly error
I create the function retunrning 1 field by myself and I expeted to see as return 2 fields.
with this creation sql it works
CREATE FUNCTION pdc_imuanno(integer)
RETURNS TABLE(abp1 real, abp2 real)
AS 'pdc','test_query'
LANGUAGE C STABLE STRICT;
Anyway it works with limited number of rows to sum and if I extend the rows number it crash
in this point
rettuple = heap_form_tuple( resultTupleDesc, retvals, retnulls);
I guess there are some error in types for values
so I query on the table fields as numeric::real, I get them as float4 and I output them as datum.
Where is my error?
Thanks a lot for any help.
This in my first post in StackOverflow.
Luca

in:
get_call_result_type(fcinfo, &resultTypeId, &resultTupleDesc)
fcinfo - what is and where come from?
fcinfo is part of PG_FUNCTION_ARGS in the v1 calling convention. It's the context of the function call and contains all sorts of details like parameters, etc. Much of this is handled behind the scenes by the GETARG macros, etc, but you need to pass it around to helper functions.
The rest of the question is hard to understand because of the typos etc. I'm guessing that you want to write a function in C to add two values together and return the result? If so, that doesn't make much sense to return as two fields in a composite type. Please show the relevant CREATE TYPE statements, the CREATE OR REPLACE FUNCTION declaration you used to define the function, and explain what you are trying to do and why.
(If you edit your question, post a comment in reply to this answer otherwise or I won't know you edited.)

Related

C question in logical OR: 2 operands evaluated (0) false, but the result works as TRUE range

My doubt is about the basic theory of "or logical operator". Especifically, logical OR returns true only if either one operand is true.
For instance, in this OR expression (x<O || x> 8) using x=5 when I evalute the 2 operand, I interpret it as both of them are false.
But I have an example that does not fit wiht it rule. On the contrary the expression works as range between 0 and 8, both included.
Following the code:
#include <stdio.h>
int main(void)
{
int x ; //This is the variable for being evaluated
do
{
printf("Imput a figure between 1 and 8 : ");
scanf("%i", &x);
}
while ( x < 1 || x > 8); // Why this expression write in this way determinate the range???
{
printf("Your imput was ::: %d ",x);
printf("\n");
}
printf("\n");
}
I have modified my first question. I really appreciate any helpo in order to clarify my doubt
In advance, thank you very much. Otto
It's not a while loop; it's a do ... while loop. The formatting makes it hard to see. Reformatted:
#include <stdio.h>
int main(void) {
int x;
// Execute the code in the `do { }` block once, no matter what.
// Keep executing it again and again, so long as the condition
// in `while ( )` is true.
do {
printf("Imput a figure between 1 and 8 : ");
scanf("%i", &x);
} while (x < 1 || x > 8);
// This creates a new scope. While perfectly valid C,
// this does absolutely nothing in this particular case here.
{
printf("Your imput was ::: %d ",x);
printf("\n");
}
printf("\n");
}
The block with the two printf calls is not part of the loop. The while (x < 1 || x > 8) makes it so that the code in the do { } block runs, so long as x < 1 or x > 8. In other words, it runs until x is between 1 and 8. This has the effect of asking the user to input a number again and again, until they finally input a number that's between 1 and 8.

strncpy functions produces wrong file names

I am new in C and writing a code to help my data analysis. Part of it opens predetermined files.
This piece of code is giving me problems and I cannot understand why.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLOGGERS 26
// Declare the input files
char inputfile[];
char inputfile_hum[MAXLOGGERS][8];
// Declare the output files
char newfile[];
char newfile_hum[MAXLOGGERS][8];
int main()
{
int n = 2;
while (n > MAXLOGGERS)
{
printf("n error, n must be < %d: ", MAXLOGGERS);
scanf("%d", &n);
}
// Initialize the input and output file names
strncpy(inputfile_hum[1], "Ahum.csv", 8);
strncpy(inputfile_hum[2], "Bhum.csv", 8);
strncpy(newfile_hum[1], "Ahum.txt", 8);
strncpy(newfile_hum[2], "Bhum.txt", 8);
for (int i = 1; i < n + 1; i++)
{
strncpy(inputfile, inputfile_hum[i], 8);
FILE* file1 = fopen(inputfile, "r");
// Safety check
while (file1 == NULL)
{
printf("\nError: %s == NULL\n", inputfile);
printf("\nPress enter to exit:");
getchar();
return 0;
}
strncpy(newfile, newfile_hum[i], 8);
FILE* file2 = fopen(newfile, "w");
// Safety check
if (file2 == NULL)
{
printf("Error: file2 == NULL\n");
getchar();
return 0;
}
for (int c = fgetc(file1); c != EOF; c = fgetc(file1))
{
fprintf(file2, "%c", c);
}
fclose(file1);
fclose(file2);
}
// system("Ahum.txt");
// system("Bhum.txt");
}
This code produces two files but instead of the names:
Ahum.txt
Bhum.txt
the files are named:
Ahum.txtv
Bhum.txtv
The reason I am using strncpy in the for loop is because n will actually be inputted by the user later.
I see at least three problems here.
The first problem is that your character array is too small for your strings.
"ahum.txt", etc. will need to take nine characters. Eight for the actual text plus one more for the null terminating character.
The second problem is that you have declared the character arrays "newfile" and "inputfile" as empty arrays. These also need to be a number able to contain the strings (at least 9).
You're lucky to have not had a crash from overwriting memory out the program space.
The third and final problem is your use of strcpy().
strncpy(dest, src, n) will copy n characters from src to dest, but it won't copy final null terminator character if n is equal or less than size of the src string.
From strncpy() manpage: https://linux.die.net/man/3/strncpy
The strncpy() function ... at most n bytes of src are copied.
Warning: If there is no null byte among the first n bytes of src,
the string placed in dest will not be null-terminated.
Normally what you would want to do is have "n" be the size of the destination buffer minus 1 to allow for the null character.
For example:
strncpy(dest, src, sizeof(dest) - 1); // assuming dest is char array
There are a couple of problems with your code.
inputfile_hum, newfile_hum, need to be to be one char bigger for the trailing '\0' on strings.
char inputfile_hum[MAXLOGGERS][9];
...
char newfile_hum[MAXLOGGERS][9];
strncpy expects the first argument to be a char * region big enough to hold the expected results, so inputfile[] and outputfile[] need to be declared:
char inputfile[9];
char outputfile[9];

No Symbols Loaded: libmex.pdb not loaded (throw_segv_longjmp_seh_filter() = EXCEPTION_CONTINUE_SEARCH : C++ exception)

In order to create a MEX function and use it in my MATLAB code, like this:
[pow,index] = mx_minimum_power(A11,A12,A13,A22,A23,A33);
I've created the file mx_minimum_power.cpp and written the following code in it:
#include <math.h>
#include <complex>
#include "mex.h"
#include "matrix.h"
#include "cvm.h"
#include "blas.h"
#include "cfun.h"
using std::complex;
using namespace cvm;
/* The gateway function */
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
const int arraysize = 62172;
const int matrixDimention = 3;
float *inMatrixA11 = (float *)mxGetPr(prhs[0]);
complex<float> *inMatrixA12 = (complex<float> *)mxGetPr(prhs[1]);
complex<float> *inMatrixA13 = (complex<float> *)mxGetPr(prhs[2]);
float *inMatrixA22 = (float *)mxGetPr(prhs[3]);
complex<float> *inMatrixA23 = (complex<float> *)mxGetPr(prhs[4]);
float *inMatrixA33 = (float *)mxGetPr(prhs[5]);
basic_schmatrix< float, complex<float> > A(matrixDimention);
int i = 0;
for (i = 0; i < arraysize; i++)
{
A.set(1, 1, inMatrixA11[i]);
A.set(1, 2, inMatrixA12[i]);
A.set(1, 3, inMatrixA13[i]);
A.set(2, 2, inMatrixA22[i]);
A.set(2, 3, inMatrixA23[i]);
A.set(3, 3, inMatrixA33[i]);
}
}
And then in order to be able to debug the code, I've created the mx_minimum_power.pdb and mx_minimum_power.mexw64 files, using the following code in the Matlab Command Window:
mex -g mx_minimum_power.cpp cvm_em64t_debug.lib
The files blas.h, cfun.h, cvm.h and cvm_em64t_debug.lib are in the same directory as mx_minimum_power.cpp.
They are the headers and library files of the CVM Class Library.
Then I've attached MATLAB.exe to Visual Studio 2013, using the way explained here.
and have set a breakpoint at line40:
When I run my MATLAB code, there's no error until the specified line.
But if I click on the Step Over button, I'll encounter the following message:
With the following information added to the Output:
First-chance exception at 0x000007FEFCAE9E5D in MATLAB.exe: Microsoft C++ exception: cvm::cvmexception at memory location 0x0000000004022570.
> throw_segv_longjmp_seh_filter()
throw_segv_longjmp_seh_filter(): C++ exception
< throw_segv_longjmp_seh_filter() = EXCEPTION_CONTINUE_SEARCH
Can you suggest me why libmex.pdb is needed at that line and how should I solve the issue?
If I stop debugging, I'll get the following information in MATLAB Command Window:
Unexpected Standard exception from MEX file.
What() is:First index value 0 is out of [1,4) range
Right before pressing the step over button, we have the following values for A11[0],A12[0],A13[0],A22[0],A23[0],A33[0]:
that are just right as my expectations, according to what MATLAB passes to the MEX function:
Maybe the problem is because of wrong allocation for matrix A, it is as follows just before pressing the step over button.
The problem occurs because we have the following code in lines 48 to 53 of the cvm.h file:
// 5.7 0-based indexing
#if defined (CVM_ZERO_BASED)
# define CVM0 TINT_ZERO //!< Index base, 1 by default or 0 when \c CVM_ZERO_BASED is defined
#else
# define CVM0 TINT_ONE //!< Index base, 1 by default or 0 when \c CVM_ZERO_BASED is defined
#endif
That makes CVM0 = 1 by default. So if we press the Step Into(F11) button at the specified line two times, we will get into line 34883 of the file cvm.h:
basic_schmatrix& set(tint nRow, tint nCol, TC c) throw(cvmexception)
{
this->_set_at(nRow - CVM0, nCol - CVM0, c);
return *this;
}
Press Step Into(F11) at line this->_set_at(nRow - CVM0, nCol - CVM0, c); and you'll go to the definition of the function _set_at:
// sets both elements to keep matrix hermitian, checks ranges
// zero based
void _set_at(tint nRow, tint nCol, TC val) throw(cvmexception)
{
_check_lt_ge(CVM_OUTOFRANGE_LTGE1, nRow, CVM0, this->msize() + CVM0);
_check_lt_ge(CVM_OUTOFRANGE_LTGE2, nCol, CVM0, this->nsize() + CVM0);
if (nRow == nCol && _abs(val.imag()) > basic_cvmMachMin<TR>()) { // only reals on main diagonal
throw cvmexception(CVM_BREAKS_HERMITIANITY, "real number");
}
this->get()[this->ld() * nCol + nRow] = val;
if (nRow != nCol) {
this->get()[this->ld() * nRow + nCol] = _conjugate(val);
}
}
pressing Step Over(F10) button,you'll get the result:
so in order to get nRow=1 and nCol=1 and not nRow=0 and nCol=0, which is out of the range [1,4), you should write that line of code as:
A.set(2, 2, inMatrixA11[i]);

Failing to marshal char** between native x32 shared library and matlab

I'm trying to call a function in a native shared library from matlab using loadlibrary and calllib but I'm failing to obtain a string that is allocated from inside the library as char**.
Here is the (simplified) code of the native library:
#include <malloc.h>
#include <string.h>
#define DllExport __declspec(dllexport)
DllExport __int32 __stdcall MyFunction1()
{
return 42;
}
DllExport __int32 __stdcall MyFunction2(__int32 handle, const char* format, char** info)
{
*info = _strdup(format);
return handle;
}
And here is the (test) code from matlab side:
function [] = test()
%[
loadlibrary('MyDll', #prototypes);
try
% Testing function 1
val1 = calllib('MyDll', 'MyFunction1');
disp(val1); % ==> ok the display value is 42
% Testing function 2
info = libpointer('stringPtrPtr', {''});
val2 = calllib('MyDll', 'MyFunction2', 666, 'kikou', info);
disp(val2); % ==> ok the value is 666
disp(info.Value{1}); % ==> ko!! The value is still '' instead of 'kikou'
catch
end
unloadlibrary('MyDll');
%]
%% --- Define prototypes for 'MyDll'
function [methodinfo, structs, enuminfo] = prototypes()
%[
% Init
ival = {cell(1,0)};
fcns = struct('name',ival,'calltype',ival,'LHS',ival,'RHS',ival,'alias',ival);
structs = []; enuminfo = []; fcnNum = 0;
% Declaration for '__int32 __stdcall MyFunction1()'
fcnNum = fcnNum+1; fcns.name{fcnNum} = 'MyFunction1'; fcns.calltype{fcnNum} = 'stdcall'; fcns.LHS{fcnNum} = 'int32'; fcns.RHS{fcnNum} = {};
% Declaration for '__int32 __stdcall MyFunction2(__int32 handle, const char* format, char** info)'
fcnNum = fcnNum+1; fcns.name{fcnNum} = 'MyFunction2'; fcns.calltype{fcnNum} = 'stdcall'; fcns.LHS{fcnNum} = 'int32'; fcns.RHS{fcnNum} = { 'int32', 'cstring', 'stringPtrPtr'};
methodinfo = fcns;
%]
As you can see from prototypes sub-function, handle is marshaled as int32, format as cstring and info as stringPtrPtr. This is what by default perl's script creates from 'MyDll.h' and also what is suggested in this thread.
I've tried many other marshaling types but could not figure out how to obtain correct value for info.
NB: It is not reported here, but the native library also defines a function to free the memory allocated for info argument. My Matlab version is 7.2.0.232
Last time I tried this, I discovered that input arguments of pointer types were not modified in place, instead additional output arguments were returned containing a copy of any pointer type input with any changes.
You can see this fact with:
>> libfunctions MyDll -full
Functions in library MyDll:
[int32, cstring, stringPtrPtr] MyFunction2(int32, cstring, stringPtrPtr)
The weird thing is that when I just tried this again on the latest R2013a, input arguments are indeed modified. Something must have changed since then :)
So in your case, you should call:
info = libpointer('stringPtrPtr',{''});
[val,~,info2] = calllib('MyDll', 'MyFunction2', 666, 'kikou', info)
and check the output info2

Expression result unused

I got some codes and I'm trying to fix some compiling bugs:
StkFrames& PRCRev :: tick( StkFrames& frames, unsigned int channel )
{
#if defined(_STK_DEBUG_)
if ( channel >= frames.channels() - 1 ) {
errorString_ << "PRCRev::tick(): channel and StkFrames arguments are incompatible!";
handleError( StkError::FUNCTION_ARGUMENT );
}
#endif
StkFloat *samples = &frames[channel];
unsigned int hop = frames.channels();
for ( unsigned int i=0; i<frames.frames(); i++, samples += hop ) {
*samples = tick( *samples );
*samples++; <<<<<<<<<--------- Expression result unused.
*samples = lastFrame_[1];
}
return frames;
}
I don't understand what the codes is trying to do. The codes are huge and I fixed quite a few. But googling didn't work for this.
Any ideas?
First, you do an increment (the line which actually gives you warning).
*samples++;
And then you assign to that variable something else, which makes previous action unused.
*samples = lastFrame_[1];
I recommend you to read this code inside 'for' loop more carefully. It doesn't look very logical.