Newbie Q: a C function like 'paste' ??

N

Nicolao

Sorry to use an non-C word like 'paste' but it's the quickest way to
describe my problem. My knowledge of C is clearly incomplete, to say
the least; I'm struggling to find a way to do what I need, and am way
out of my depth.

I'm trying to write a program which retrieves data from a postgreSQL
database (e.g. I enter a word, and the program checks with the database
what part-of-speech it is). I've adapted a script I found and I can
retrieve the data fine, but I don't want to just display it, I want to
store it. That's where I hit the problem, and I don't know enough of C
to solve it, and experimenting with the 2 books I have hasn't given me
a solution.

Obviously the retrieved data (e.g. 'noun') is in a buffer somewhere,
and if this were Filemaker on my Mac I could simply issue a 'paste'
command into an appropriate field. But I can't find a successful way to
assign what's in the buffer to the variable 'part'.

I'll show you what I have, and mark where I reckon the missing move
should be. I'd really appreciate some advice here, and please forgive
the gaping holes in my knowledge - I sure must have missed something!

Incidentally, I'm doing this on a Debian box (woody on a powerpc)

Nic



/* WORDFETCH.C, a program to consult database 'wordpart' */
/* compile like this: gcc -o wordfetch -I/usr/include/postgresql
wordfetch.c -lpq */


#include <stdio.h>
#include <stdlib.h>
#include "libpq-fe.h"

int main()
{
char word[9]; /* holds word entered by user */
char part[12]; /* to hold copied part-of-speech from database */
char query_string[256]; /* holds constructed SQL query */
PGconn *conn; /* holds database connection */
PGresult *res; /* holds query result */
int i;

conn = PQconnectdb("dbname=wordpart"); /* connect to database */

if (PQstatus(conn) == CONNECTION_BAD) /* did connection fail? */
{
fprintf(stderr, "Connection to database failed.\n");
fprintf(stderr, "%s", PQerrorMessage(conn));
exit(1);
}

printf("Type a word: "); /* prompt user for word to be analysed */
scanf("%s", word);

sprintf(query_string, "SELECT part FROM list WHERE word = '%s'",
word); /* create SQL query string */

res = PQexec(conn, query_string); /* sends the query */

if (PQresultStatus(res) != PGRES_TUPLES_OK) /* did the query fail? */
{
fprintf(stderr, "SELECT query failed.\n");
PQclear(res);
PQfinish(conn);
exit(1);
}

for (i = 0; i < PQntuples(res); i++) /* loop through all
rows */
printf("result = %s\n", PQgetvalue(res, i, 0)); /* display the
value returned */


/* HERE IS WHERE I THINK THE ASSIGNMENT SHOULD BE; I want to 'paste'
into 'part' */


PQclear(res); /* free result */

PQfinish(conn); /* disconnect from database */

printf("%s = %s\n", word, part); /* a tester to check */

return 0;
}
 
J

Joona I Palaste

Nicolao said:
Sorry to use an non-C word like 'paste' but it's the quickest way to
describe my problem. My knowledge of C is clearly incomplete, to say
the least; I'm struggling to find a way to do what I need, and am way
out of my depth.
I'm trying to write a program which retrieves data from a postgreSQL
database (e.g. I enter a word, and the program checks with the database
what part-of-speech it is). I've adapted a script I found and I can
retrieve the data fine, but I don't want to just display it, I want to
store it. That's where I hit the problem, and I don't know enough of C
to solve it, and experimenting with the 2 books I have hasn't given me
a solution.
Obviously the retrieved data (e.g. 'noun') is in a buffer somewhere,
and if this were Filemaker on my Mac I could simply issue a 'paste'
command into an appropriate field. But I can't find a successful way to
assign what's in the buffer to the variable 'part'.

Looks like you want strcpy(). If that's not what you want, please try
to explain in more detail, using programming language jargon instead of
Mac desktop application jargon.
 
M

Malcolm

Nicolao said:
I'm trying to write a program which retrieves data from a postgreSQL
database (e.g. I enter a word, and the program checks with the database
what part-of-speech it is). I've adapted a script I found and I can
retrieve the data fine, but I don't want to just display it, I want to
store it. >

/* WORDFETCH.C, a program to consult database 'wordpart' */
/* compile like this: gcc -o wordfetch -I/usr/include/postgresql
wordfetch.c -lpq */


#include <stdio.h>
#include <stdlib.h>
#include "libpq-fe.h"

int main()
{
char word[9]; /* holds word entered by user */
char part[12]; /* to hold copied part-of-speech from database */
char query_string[256]; /* holds constructed SQL query */
PGconn *conn; /* holds database connection */
PGresult *res; /* holds query result */
int i;

conn = PQconnectdb("dbname=wordpart"); /* connect to database */

if (PQstatus(conn) == CONNECTION_BAD) /* did connection fail? */
{
fprintf(stderr, "Connection to database failed.\n");
fprintf(stderr, "%s", PQerrorMessage(conn));
exit(1);
}

printf("Type a word: "); /* prompt user for word to be analysed */
scanf("%s", word);

sprintf(query_string, "SELECT part FROM list WHERE word = '%s'",
word); /* create SQL query string */

res = PQexec(conn, query_string); /* sends the query */

if (PQresultStatus(res) != PGRES_TUPLES_OK) /* did the query fail? */
{
fprintf(stderr, "SELECT query failed.\n");
PQclear(res);
PQfinish(conn);
exit(1);
}

for (i = 0; i < PQntuples(res); i++) /* loop through all
rows */
printf("result = %s\n", PQgetvalue(res, i, 0)); /* display the
value returned */

Delete these two lines. Instead of printf(), call PQgetvalue(res, i, 0) and
assign the result to a temporary pointer.

for (i = 0; i < PQntuples(res); i++)
{
const char *ptr;
ptr = PQgetvalues(res, i, 0);

/* now we can use ptr however we want */
e.g.
strcpy(part, ptr); /* copy the string to part */
printf("Query returned %s\n", ptr); /* print it out */
printf("Length %d\n", strlen(ptr)); /* get the length of the result */
if(!strcmp(ptr, "NOUN")) /* test it to use the value */
printf("It is a noun!");
}

On problem is that the query may return more than one value. It could be
that, because of the way your database is set up, you actually know that
PQNtuples() will always return 1. However words like "dream" could be either
nouns or verbs, so this might not be the case. As I have set things up,
"part" will be overwritten, and so set to the last value.
Unfortunately I cannot tell you how to handle this, since I don't know what
you wnat to achieve with the data.
 
N

Nicolao

Malcolm said:
Nicolao said:
I'm trying to write a program which retrieves data from a postgreSQL
database (e.g. I enter a word, and the program checks with the database
what part-of-speech it is). I've adapted a script I found and I can
retrieve the data fine, but I don't want to just display it, I want to
store it. >

/* WORDFETCH.C, a program to consult database 'wordpart' */
/* compile like this: gcc -o wordfetch -I/usr/include/postgresql
wordfetch.c -lpq */


#include <stdio.h>
#include <stdlib.h>
#include "libpq-fe.h"

int main()
{
char word[9]; /* holds word entered by user */
char part[12]; /* to hold copied part-of-speech from database */
char query_string[256]; /* holds constructed SQL query */
PGconn *conn; /* holds database connection */
PGresult *res; /* holds query result */
int i;

conn = PQconnectdb("dbname=wordpart"); /* connect to database */

if (PQstatus(conn) == CONNECTION_BAD) /* did connection fail? */
{
fprintf(stderr, "Connection to database failed.\n");
fprintf(stderr, "%s", PQerrorMessage(conn));
exit(1);
}

printf("Type a word: "); /* prompt user for word to be analysed */
scanf("%s", word);

sprintf(query_string, "SELECT part FROM list WHERE word = '%s'",
word); /* create SQL query string */

res = PQexec(conn, query_string); /* sends the query */

if (PQresultStatus(res) != PGRES_TUPLES_OK) /* did the query fail? */
{
fprintf(stderr, "SELECT query failed.\n");
PQclear(res);
PQfinish(conn);
exit(1);
}

for (i = 0; i < PQntuples(res); i++) /* loop through all
rows */
printf("result = %s\n", PQgetvalue(res, i, 0)); /* display the
value returned */

Delete these two lines. Instead of printf(), call PQgetvalue(res, i, 0) and
assign the result to a temporary pointer.

for (i = 0; i < PQntuples(res); i++)
{
const char *ptr;
ptr = PQgetvalues(res, i, 0);

/* now we can use ptr however we want */
e.g.
strcpy(part, ptr); /* copy the string to part */
printf("Query returned %s\n", ptr); /* print it out */
printf("Length %d\n", strlen(ptr)); /* get the length of the result */
if(!strcmp(ptr, "NOUN")) /* test it to use the value */
printf("It is a noun!");
}

On problem is that the query may return more than one value. It could be
that, because of the way your database is set up, you actually know that
PQNtuples() will always return 1. However words like "dream" could be either
nouns or verbs, so this might not be the case. As I have set things up,
"part" will be overwritten, and so set to the last value.
Unfortunately I cannot tell you how to handle this, since I don't know what
you wnat to achieve with the data.
/* HERE IS WHERE I THINK THE ASSIGNMENT SHOULD BE; I want to 'paste'
into 'part' */


PQclear(res); /* free result */

PQfinish(conn); /* disconnect from database */

printf("%s = %s\n", word, part); /* a tester to check */

return 0;
}
Thanks a bunch, Malclom - and yes it's time I moved on to the chapter
about Arrays and Pointers!

As you can imagine, I have anticipated the problem of multiple uses of
the same character-strings (aka 'words'). At this point, my decision is
one-string-one-row, with special codes for multiples. Since I'm working
in English, and English is word-order dominated, my working hypothesis
is that I can make calculations on syntax through analysis of the
relative position in the sequence. And if that DOESN'T work out, then
the implications of that are interesting, from a viewpoint of Learning
Theory.

Yes, you guessed it - this is a Linguistics application, and at present
it's a) fun, and b) a real-world context for learning a programming
language. I like the idea of one sort of language assessing another.

So I shall implement your scheme, and doubtless leave the question of
PQNtuples() for somewhat later - if I can get a script that works! I'm
assuming I shall need to #include <string.h>.

My warmly genuine thanks to you for those pointers (sorry) and I'll
report back in case you're interested.

Nic
 
N

Nicolao

I tried that, but still have a problem. Here's how I modified the code,
and at the end why gcc refused it

#include <stdio.h>
#include <stdlib.h>
#include "libpq-fe.h"
#include <string.h>

int main()
{
char word[9]; /* holds word entered by user */
char part[12]; /* holds copied part-of-speech from
database */
char query_string[256]; /* holds constructed SQL query */
PGconn *conn; /* holds database connection */
PGresult *res; /* holds query result */
int i; /* for counting rows in database?? */

conn = PQconnectdb("dbname=wordpart"); /* connect to database */

if (PQstatus(conn) == CONNECTION_BAD) /* did connection fail? */
{
fprintf(stderr, "Connection to database failed.\n");
fprintf(stderr, "%s", PQerrorMessage(conn));
exit(1);
}

printf("Type a word: "); /* prompt user for word to be analysed */
scanf("%s", word);
sprintf(query_string, "SELECT part FROM list WHERE word = '%s'",
word); /* create SQL query string */
res = PQexec(conn, query_string); /* sends the query */

if (PQresultStatus(res) != PGRES_TUPLES_OK) /* did the query fail? */
{
fprintf(stderr, "SELECT query failed.\n");
PQclear(res);
PQfinish(conn);
exit(1);
}

for (i = 0; i < PQntuples(res); i++)
{
const char * ptr;
ptr = PQgetvalues(res, i, 0);
strcpy(part, ptr); /* copies the string to
part */

printf("Query returned %s\n", ptr); /* print it out */
printf("Length %d\n", strlen(ptr)); /* get the length of the
result */
printf("%s = %s\n\n", word, part);
}

PQclear(res); /* free result */
PQfinish(conn); /* disconnect from database */
return 0;
}

-------------

When I tried to compile this, gcc (Debian prerelease 2.95.4) refused:

wordgetfix.c In function 'main':
wordgetfix.c:45: warning: assignment makes pointer from integer without
a cast
/tmp/ccgSnYaQ.o: In function 'main':
/tmp/ccgSnYaQ.o(.text+0x160): undefined reference to 'PQgetvalues'
/tmp/ccgSnYaQ.o(.text+0x160): relocatipn truncated to fit: R_PPC_REL24
PQgetvalues


Any clues ??

Nic
 
C

Carlos

I tried that, but still have a problem. Here's how I modified the code,
and at the end why gcc refused it [...]
ptr = PQgetvalues(res, i, 0);

You wrote PQgetvalue in your first message.

[...]
 
R

Richard Bos

Nicolao said:
ptr = PQgetvalues(res, i, 0);

Let me guess. This is line 45, right?
wordgetfix.c In function 'main':
wordgetfix.c:45: warning: assignment makes pointer from integer without
a cast
/tmp/ccgSnYaQ.o: In function 'main':
/tmp/ccgSnYaQ.o(.text+0x160): undefined reference to 'PQgetvalues'
/tmp/ccgSnYaQ.o(.text+0x160): relocatipn truncated to fit: R_PPC_REL24
PQgetvalues

And this is really just one error message, plus the result of it. The
real error is that you haven't defined PQgetvalues() - make sure that's
the correct spelling of the name. The result of this is that you don't
have a declaration for it, either, so the compiler is required to assume
that it returns an int - but then you assign it to a pointer, without a
cast. For the correct spelling of the name, with a correct declaration,
this is probably correct - but not for the automatic declaration of the
incorrect name.

Richard
 
N

Nicolao

Richard Bos said:
Let me guess. This is line 45, right?


And this is really just one error message, plus the result of it. The
real error is that you haven't defined PQgetvalues() - make sure that's
the correct spelling of the name. The result of this is that you don't
have a declaration for it, either, so the compiler is required to assume
that it returns an int - but then you assign it to a pointer, without a
cast. For the correct spelling of the name, with a correct declaration,
this is probably correct - but not for the automatic declaration of the
incorrect name.

Richard

Whoops, thrashing about here, am I not. And, however I correct what
I've done, I still get some kind of error. The problem - with this
being a rehash of someone else's program - is there's too much I don't
understand yet, like why none of those PQ* doodads is formally
declared, whereas the PG* ones are. Guess I should be patient and read
quite a bit more before biting off more than I can chew and then coming
to you guys for advice.

Thanks to all - for help and no less for the tactful indication of my
howlers!

Nic
 
C

CBFalconer

Nicolao said:
.... snip ...

Thanks to all - for help and no less for the tactful indication of
my howlers!

There's a first - calling us tactful. We are more used to being
called clumsy boorish inconsiderate tactless oafs when making
corrections and suggestions.
 
N

Nicolao

CBFalconer said:
There's a first - calling us tactful. We are more used to being
called clumsy boorish inconsiderate tactless oafs when making
corrections and suggestions.

Maybe another Newbie Error? :)

No way - I meant what I said.

Nic
 
R

Richard Bos

Nicolao said:
Whoops, thrashing about here, am I not. And, however I correct what
I've done, I still get some kind of error. The problem - with this
being a rehash of someone else's program - is there's too much I don't
understand yet, like why none of those PQ* doodads is formally
declared, whereas the PG* ones are.

But they are - if they weren't, the compiler would have complained about
several of them, not just about the one you misspelled. They're probably
declared in that non-Standard header you #include. (And so, one
presumes, are the PG* types.)

Richard
 
N

Nicolao

Richard Bos said:
But they are - if they weren't, the compiler would have complained about
several of them, not just about the one you misspelled. They're probably
declared in that non-Standard header you #include. (And so, one
presumes, are the PG* types.)

Richard

Thanks Richard,

I've since opened up the libpq-fe.h file and found it full of stuff -
some of which makes sense, even to my unprogrammed mind. However, I'm
beginning to question whether C is the most appropriate langauge to use
for this particular task. It's a hard guess to make, when you have so
little ground knowledge. For example, Perl & Python are built-ins for
postgreSQL, and some tutorial pages I've accessed suggest Python deals
with strings in a more adaptable manner.

Perhaps I should explain the task. What I need my program to do is:
convert a linear steam of text (one sentence at a time) into a group of
syntactical units, their purpose in the sentence, and the relationships
they have to each other, coded from data stored in a postgreSQL
backend.

In the db, each 'word' has a codestring which contains a detailed
syntactical analysis. So I'm going to need a language which will 1)
readily fetch those codestrings from the db and place them alongside
their 'words', and 2) be easily splitable into segments (e.g. the 1st
character of the string might determine whether the word is a noun, and
the 2nd, whether that noun is singular or plural - etc).

Now - I've really enjoyed my learning of C, but now I get to this
specific area of useage, it seems suddenly to be counter-intuitive to
work with, and present me with a whole ladder of steps where I'd
expected one (i.e. get data from one place, stick it in another). Now
that MAY mean that I have heaps more to learn (which is fine), but it
might ALSO mean I am - in my innocence and ignorance - using the wrong
tool for the job.

Any thoughts? Or, if this is an inappropriate question here, any
nominations for the best group to ask that question.

Nic
 
R

Richard Bos

Nicolao said:
I've since opened up the libpq-fe.h file and found it full of stuff -
some of which makes sense, even to my unprogrammed mind.

Don't worry - most of the time you don't need to bother with the details
of what's in those header files. All you need to know is _what_ is
declared in a header (i.e., which types, which functions); _as_ what
they are declared (i.e., as a function taking two ints and returning a
char *, as a struct with such-and-such members, as an opaque type which
you can pass to library functions but need not examine in depth, and so
forth); but rarely exactly _how_ they are declared (or defined, in the
case of types and macros).
What's more, you shouldn't need to get this information from the header
file itself. There should be some form of documentation with the library
detailing what it provides. That is a necessity if only because you
can't actually use its functions without knowing what it does.
However, I'm beginning to question whether C is the most appropriate
langauge to use for this particular task.

That's impossible for me to say without in-depth knowledge of the
project, but using C for a database project is far from unheard-of.
Perhaps I should explain the task. What I need my program to do is:
convert a linear steam of text (one sentence at a time) into a group of
syntactical units, their purpose in the sentence, and the relationships
they have to each other,

This is natural language processing? There are languages that try to
cater specifically to such tasks. Have you seen Snobol or Icon?
In the db, each 'word' has a codestring which contains a detailed
syntactical analysis. So I'm going to need a language which will 1)
readily fetch those codestrings from the db and place them alongside
their 'words', and 2) be easily splitable into segments (e.g. the 1st
character of the string might determine whether the word is a noun, and
the 2nd, whether that noun is singular or plural - etc).

Both are entirely possible in C, but might be easier in specialist
languages. I wouldn't require Perl unless you like reading line noise,
though :-/

Richard
 
N

Nicolao

[snip]
This is natural language processing? There are languages that try to
cater specifically to such tasks. Have you seen Snobol or Icon?


Both are entirely possible in C, but might be easier in specialist
languages. I wouldn't require Perl unless you like reading line noise,
though :-/

Richard

Thanks Richard

I'll certainly check out Snobol & Icon, but I'd prefer it to be
possible in C, as so far I've enjoyed my little experiments. So I
reckon to stick at it.

Thanks for your help

Nic
 
F

Frank Way

Nicolao said:
[snip]

This is natural language processing? There are languages that try to
cater specifically to such tasks. Have you seen Snobol or Icon?



Both are entirely possible in C, but might be easier in specialist
languages. I wouldn't require Perl unless you like reading line noise,
though :-/

Richard


Thanks Richard

I'll certainly check out Snobol & Icon, but I'd prefer it to be
possible in C, as so far I've enjoyed my little experiments. So I
reckon to stick at it.

Thanks for your help

Nic

Perhaps this has already been posted, and I missed it, but

http://www.postgresql.org/docs/7.4/static/index.html

has some pretty comprehensive documentation. Chapter 27 deals
specifically with the C interface to PostgreSQL.

What you are trying to do is not that difficult, and from what I have
read you're getting closer.

And, while it is probably beyond the scope here, a word to the wise --
if the program is not just for YOUR general use, it is always a good
idea to either escape the input you get via your scanf (PQescapeString
is the call I believe), or else use prepared queries to avoid SQL
injection attacks. But again, probably beyond the scope until you get
your basic functionality up and running....

Hope this helps a bit,
Frank
 
N

Nicolao

Frank Way said:
Perhaps this has already been posted, and I missed it, but

http://www.postgresql.org/docs/7.4/static/index.html

has some pretty comprehensive documentation. Chapter 27 deals
specifically with the C interface to PostgreSQL.

What you are trying to do is not that difficult, and from what I have
read you're getting closer.

And, while it is probably beyond the scope here, a word to the wise --
if the program is not just for YOUR general use, it is always a good
idea to either escape the input you get via your scanf (PQescapeString
is the call I believe), or else use prepared queries to avoid SQL
injection attacks. But again, probably beyond the scope until you get
your basic functionality up and running....

Hope this helps a bit,
Frank

Thanks Frank, I got my original blueprint from such a source - if not
actually that one. Your comments reminded me to look again, and perhaps
you are right and I am "getting closer", for on the whole what I saw
seemed far less 'mystical' than before! However, this may not be
sufficient basis for a general theory of 'progress' :=)

I dare say if I get this idea running, I shall be inputting &
outputting via files, rather than working with scanf input. SQL
injections sound a last resort! I'll try to stick to gradual
absorption of C. Fortunately I like oranges.

Thanks again for yet more helpful advice. I've certainly come to the
right place.

Nic
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top