macOS 13.3 (M1 pro) - Xcode 14.3
Mon application en c++ doit se connecter à un server Postgresql.
Avec Macports, libpqxx-7.2.dylib (universal) OK, mais intégré à l'application 7 erreur du format :
Undefined symbol: pqxx::field::c_str() const &
aucun code de l'applicaton ne comprend pqxx::field::c_str()
même chose pour les 6 autres erreurs.
Avec la dernière version de libpqxx obtenue sur github, libpqxx-master (=7.8.0), build complet, mais impossible d'obtenir l'universal de libpqxx-7.8 :
Xcode trouve aucun pqxx::... dans le code.
./configure --prefix=/opt/local CC="gcc -arch arm64 -arch x86_64" CXXFLAGS="-std=c++20 -O3" --enable-shared --with-postgres-include=/opt/local/include/postgresql13
Je passe sur les essais intermédiaires que je fais depuis plusieurs jours.
NB: mon appli fait plus de 20000 lignes de code, donc pas réaliste de passer à libpq : trop de conversions de types
dans une autre vie ça marchait...
Merci de l'aide
]]> sprintf( sql_text, "PREPARE TRANSACTION '%s' ", idtx );
EXEC SQL EXECUTE IMMEDIATE :sql_text ;
EXEC SQL SET AUTOCOMMIT TO ON;
sprintf( sql_text, "COMMIT PREPARED '%s' ", idtx );
EXEC SQL EXECUTE IMMEDIATE :sql_text ;
EXEC SQL SET AUTOCOMMIT TO OFF;
EXEC SQL ROLLBACK; --pour eviter unexpected EOF on client connection with an open transaction
Par contre j'ai encore du mal a comprendre la philosophie que: l'autocommit n'ouvre pas une transaction explicite alors qu'un ordre EXEC SQL sans BEGIN WORK pour ouvrir un transaction, va ouvrir de lui même une transaction. J'aurai pensé que c'était l'inverse.
Merci encore pour votre aide.
]]>J'ai l'impression que c'est l'étape que vous n'avez pas dans votre programme.
Ce découpage est fait dans psql avec un analyseur lexical dédié fait avec lex, qui lui même est une copie de l'analyseur lexical du moteur SQL. Voir https://git.postgresql.org/gitweb/?p=po … psqlscan.l
* This code is mainly concerned with determining where the end of a SQL
* statement is: we are looking for semicolons that are not within quotes,
* comments, or parentheses. The most reliable way to handle this is to
* borrow the backend's flex lexer rules, lock, stock, and barrel. The rules
* below are (except for a few) the same as the backend's, but their actions
* are just ECHO whereas the backend's actions generally do other things.
On peut toujours envoyer un énorme bloc plein de requêtes SQL accolées à PQexec en espérant que ça va passer, mais à titre d'exemple si on envoie ça à PQexec:
CREATE DATABASE dbtest; select 1;
ça échouera avec une erreur disant que CREATE DATABASE ne marche pas dans une transaction, alors qu'avec psql ça passerait sans erreur, parce qu'il aura découpé ça en 2 requêtes à envoyer séparément.
]]>Nous souhaitons migrer une application d'un SGBD IngresSQL vers PostgreSQL.
Sous Ingres, nous utilisons du code du style :
EXEC SQL SELECT clicode, clinom
INTO :cli.clicode, :cli.clinom
FROM CLIENT ORDER BY CLICODE;
printf("SELECT - sqlcode = %d sqlstate = %s\n", sqlca.sqlcode, sqlca.sqlstate);
EXEC SQL BEGIN;
printf("LOOP Client %d %s\n", cli.clicode, cli.clinom);
EXEC SQL END;
Ce qui permet sans passer par un curseur d'effectuer du code après chaque enregistrement trouvé dans la requête.
Sous Postgre, la précompilation se passe bien, mais en exécution, après le select, on à l'erreur sqlcode -203 (ECPG_TOO_MANY_MATCHES) sqlstate 21000 (cardinality_violation).
Ce qui sous-entend visiblement que le select donne plusieurs enregistrements, ce qui ne serait pas permis.
Nous avons utilisé cette méthode dans de nombreux programmes et nous cherchons à effectuer un minimum de modifications si c'est possible
Est-ce que quelqu'un saurait comment palier à ce problème (sans passer par un curseur évidemment)
Merci à tous
]]>QVariant QSqlRecord :: value (const QString & name ) const
Ceci est une fonction surchargée.
Renvoie la valeur du champ appelé nom dans l'enregistrement. Si le nom du champ n'existe pas, une variante non valide est renvoyée.
Voir aussi indexOf ().
]]>EXEC SQL DECLARE testcsc_csr3 CURSOR FOR SELECT....
EXEC SQL OPEN testcsc_csr3;
EXEC SQL FETCH testcsc_csr3....;
EXEC SQL COMMIT;
EXEC SQL FETCH testcsc_csr3...;
ERROR: cursor "testcsc_csr3" does not exist
La raison est la suivante : le curseur n'a pas été déclaré avec la mention WITH HOLD
voir ici la documentation sur la signification du WITH/WITHOUT HOLD :
http://www.postgresql.org/docs/current/ … clare.html
Fred
]]>La réponse de la part de Michael Meskes :
"
> Why the indicator equals 0 (is not strictly positive) and the value is
> truncated (modified) ?
Because according to standard C types it is not truncated. The string does
have more digits tha a flot can handle, but they are all valid, i.e. a
convesion does correctly eat them all but the internal representation is not
able to store them all.
You bring up an interesting point here, the data is not exactly truncated, it
is just rounded. Not sure what (if anything) the standard says.
> Why this error message whereas an example is given in the PostgreSQL 9.4
> documentation (see above) ?
I guess the documentation is wrong, but I have to look into it. Normally the
varchar type needs a length (as an array of char) or it will become a pointer
to char.
"
J'ai un peu galéré pour y arriver (je comprends .... lentement), je me dis que cela pourrait servir à d'autres, alors voici l'exemple.
A exécuter sur psql :
\echo -- ------------------------------
\echo -- creation de la fonction qui renvoie un record
\echo -- contenant 2 parametres :
\echo -- po_number bigint
\echo -- po_coderet bigint
\echo -- ------------------------------
CREATE OR REPLACE FUNCTION zz0001t_seq(
pi_classe text,
pi_nbre bigint DEFAULT 1)
RETURNS record AS
$BODY$
DECLARE
ret RECORD;
po_number bigint;
po_coderet bigint;
BEGIN
-- doing some stuff...
po_number:=23456;
po_coderet:=12;
-- je retourne 2 parametres valorises dans un record (bigint,bigint)
ret := (po_number,po_coderet);
return ret;
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
\echo -- -----------------------------------------
\echo -- appel de la fonction avec psql pour test
\echo -- -----------------------------------------
select N_NUMBER, TS_CODE_RETOUR
FROM zz0001t_seq('ENIMODIFCL',1)
AS (N_NUMBER bigint, TS_CODE_RETOUR bigint)
\echo -- ------------------------------
\echo -- creation de la fonction qui va appeler une autre fonction PL/pgSQL
\echo -- et afficher les 2 parametres
\echo -- ------------------------------
CREATE OR REPLACE FUNCTION zz0001t_appel ()
RETURNS void
as
$BODY$
DECLARE
WS_IDENT bigint;
WS_CODERET bigint;
ret RECORD;
BEGIN
-- Recuperer identifiant systeme
select N_NUMBER, TS_CODE_RETOUR
FROM zz0001t_seq('ENIMODIFCL',1)
AS (N_NUMBER bigint, TS_CODE_RETOUR bigint)
INTO WS_IDENT, WS_CODERET;
-- Affichage
RAISE INFO 'sequence lue %',WS_IDENT;
RAISE INFO 'Code retour %',WS_CODERET;
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
\echo -- ------------------------------
\echo -- appel de la fonction
\echo -- ------------------------------
select zz0001t_appel();
L'exécuton sur pgsql donne ceci :
idev05=> \i demo_2_param_out.sql
-- ------------------------------
-- creation de la fonction qui renvoie un record
-- contenant 2 parametres :
-- po_number bigint
-- po_coderet bigint
-- ------------------------------
CREATE FUNCTION
-- -----------------------------------------
-- appel de la fonction avec psql pour test
-- -----------------------------------------
n_number | ts_code_retour
----------+----------------
23456 | 12
(1 ligne)
-- ------------------------------
-- creation de la fonction qui va appeler une autre fonction PL/pgSQL
-- et afficher les 2 parametres
-- ------------------------------
CREATE FUNCTION
-- ------------------------------
-- appel de la fonction
-- ------------------------------
psql:demo_2_param_out.sql:66: INFO: sequence lue 23456
psql:demo_2_param_out.sql:66: INFO: Code retour 12
zz0001t_appel
---------------
(1 ligne)
Pour l'appel en ecpg,l'écriture est la suivante :
EXEC SQL SELECT a, b INTO :N_NUMBER,:TS_CODE_RETOUR
FROM zz0001t_seq(:N_CLASS,:N_INCREMENT)
AS (a bigint, b bigint);
voila, j'espère que je n'ai pas dit trop de bêtises, si vous avez plus simple, je suis preneur.
Fred
]]>\set AUTOCOMMIT off
-- debut DDL
drop table fred;
create table fred (
cle integer not null,
libelle varchar(30) not null);
alter table fred add constraint fred_pk primary key (cle);
commit;
-- fin DDL
-- debut DML
begin transaction;
insert into fred (cle, libelle ) values (10,'frederic');
insert into fred (cle, libelle ) values (20,'frederic');
-- on genere un plantage, pour continuer, il faut faire rollback;
savepoint CLE_DUPLIQUEE;
insert into fred (cle, libelle) values (10,'frederic');
rollback to savepoint CLE_DUPLIQUEE;
update fred set libelle='fred' where cle=10;
commit;
select * from fred order by 1;
DROP TABLE
CREATE TABLE
ALTER TABLE
COMMIT
BEGIN
INSERT 0 1
INSERT 0 1
SAVEPOINT
psql:test_transaction2.sql:23: ERREUR: la valeur d'une clé dupliquée rompt la contrainte unique « fred_pk »
DÉTAIL : La clé « (cle)=(10) » existe déjà.
ROLLBACK
UPDATE 1
COMMIT
cle | libelle
-----+----------
10 | fred
20 | frederic
(2 lignes)
Pour répondre à votre question:
Sinon, je ne comprend pas tout à fait votre problématique, vous chercher à stocker les méta-données de fichiers volumineux uniquement dans postgres ou le fichier volumineux y compris ?
Les deux, je voudrais au moment de l'insert utiliser une librairie externe pour par exemple, dans le cadre d'un vidéo extraire les métas (encodage vidéo, son, auteur, durée ..... ) dans un champ qui serait l'image de la signature de la vidéo.
Olivier
]]>a) je maintiens que la fonction ne fonctionne pas tel que décrite sous pgadmin et ecpg dans la doc.
b) la réponse pour que les deux fonctionne
EXEC SQL AT pg_RTABLE DECLARE pg_RTABLE_cur CURSOR FOR
select
cl.table_catalog
,cl.table_name
,d.description
,cl.column_name
,e.description
,cl.ORDINAL_POSITION
,cl.DATA_TYPE
,coalesce(cl.CHARACTER_MAXIMUM_LENGTH,0)
,coalesce(cl.NUMERIC_PRECISION,0)
,coalesce(cl.NUMERIC_SCALE,0)
from
information_schema.columns cl ,
pg_catalog.pg_attribute a
inner join pg_catalog.pg_class c on a.attrelid = c.oid,
pg_catalog.pg_description d,
pg_catalog.pg_description e
where
cl.table_catalog =:nzdbname
and c.relname =:nzfile
and a.attnum > 0
and a.attisdropped is false
and pg_catalog.pg_table_is_visible(c.oid)
and cl.table_name = c.relname
and cl.ORDINAL_POSITION = a.attnum
and d.objoid = a.attrelid
and d.objsubid = 0
and e.objoid = a.attrelid
and e.objsubid = a.attnum
order by a.attnum;
EXEC SQL AT pg_RTABLE OPEN pg_RTABLE_cur ;
EXEC SQL AT pg_RTABLE FETCH pg_RTABLE_cur INTO :nzSERVER, :nzTABLE, :nzTEXT , :nCNAME, :nCTEXT, :nCPOS, :nCTYP, :nCLEN, :nCDEC, :nCVIR ;
fprintf(stderr, "\n db_read_RTABLE \n zSERVER: %s \n zTABLE: %s \n zTEXT: %s \n zNAME: %s \n CTEXT: %s \n CPOS: %d \n CTYP: %s \n CLEN: %d \n CDEC: %d \n CVIR: %d \n ",
nzSERVER, nzTABLE, nzTEXT, nCNAME, nCTEXT, nCPOS, nCTYP, nCLEN, nCDEC, nCVIR);
là ça fonctionne
je souhaite que cela serve pour les autres
pour info
EXEC SQL BEGIN DECLARE SECTION;
/* $FIELD */
char* nzdbname ; /* connection user name */
char* nzfile ; /* connection user name */
char* nzSERVER ;
char* nzTABLE ;
char* nCNAME ;
int nCPOS ; /* Position */
char* nCTYP ;
int nCLEN ; /* Longueur zone alpha */
int nCDEC ; /* ENTIER */
int nCVIR ; /* NBR CHIFFRE APRES VIRGULE */
char* nzTEXT ; /* texte Table */
char* nCTEXT ; /* texte de la Colonne */
int nCCOL ; /* Nbr colonne */
int nCKEY ; /* Nbr key */
EXEC SQL END DECLARE SECTION;
attention ne pas oublier
,coalesce(cl.CHARACTER_MAXIMUM_LENGTH,0)
,coalesce(cl.NUMERIC_PRECISION,0)
,coalesce(cl.NUMERIC_SCALE,0)
sino error (les valeurs sont NULL donc les forcer a zeros )
pour donner ce résultat:
<?xml version="1.0" encoding="UTF-8"?>
<FILE>
<ENTETE>
<VERSION>20170217144517</VERSION>
<SERVEUR>CGIFCH</SERVEUR>
<TABLE>FC0CLI</TABLE>
<TEXT>CLIENT FACTURATION</TEXT>
<NBRCOL>031</NBRCOL>
<NBRKEY>001</NBRKEY>
</ENTETE>
<ZONED>
<row NAME="C0CDEP" TEXT="CODE DEPARTEMENT" ORD="1" TYP="character" LEN="3" ENT="0" DEC="0" LNG="3"/>
<row NAME="C0CFAC" TEXT="CODE FACTURATION" ORD="2" TYP="character" LEN="1" ENT="0" DEC="0" LNG="1"/>
<row NAME="C0CJRD" TEXT="CODE FORME JURIDIQUE" ORD="3" TYP="character" LEN="4" ENT="0" DEC="0" LNG="4"/>
<row NAME="C0CPAY" TEXT="CODE PAYS" ORD="4" TYP="character" LEN="3" ENT="0" DEC="0" LNG="3"/>
<row NAME="C0CRGI" TEXT="CODE REGION ECONOMIQ" ORD="5" TYP="numeric" LEN="0" ENT="2" DEC="0" LNG="3"/>
<row NAME="C0CRGL" TEXT="CODE REGLEMENT" ORD="6" TYP="numeric" LEN="0" ENT="3" DEC="0" LNG="4"/>
<row NAME="C0CST1" TEXT="CODE REGION STAT." ORD="7" TYP="numeric" LEN="0" ENT="2" DEC="0" LNG="3"/>
<row NAME="C0CST2" TEXT="CODE SECTEUR STAT." ORD="8" TYP="numeric" LEN="0" ENT="2" DEC="0" LNG="3"/>
<row NAME="C0CTRS" TEXT="CODE TRESORERIE" ORD="9" TYP="numeric" LEN="0" ENT="2" DEC="0" LNG="3"/>
<row NAME="C0CTTV" TEXT="CODE TVA EXO EXPORT" ORD="10" TYP="character" LEN="1" ENT="0" DEC="0" LNG="1"/>
<row NAME="C0999E" TEXT="DATE DE CREATION ENR" ORD="11" TYP="date" ENT="0" DEC="0" LNG="8" LEN="8"/>
<row NAME="C0999M" TEXT="DATE DE MODIFCATION" ORD="12" TYP="date" ENT="0" DEC="0" LNG="8" LEN="8"/>
<row NAME="C0NARR" TEXT="N. ARRONDISSEMENT" ORD="13" TYP="numeric" LEN="0" ENT="3" DEC="0" LNG="4"/>
<row NAME="C0NCLI" TEXT="N° CLIENT" ORD="14" TYP="numeric" LEN="0" ENT="6" DEC="0" LNG="7"/>
<row NAME="C0NPTT" TEXT="N. CODE POSTAL" ORD="15" TYP="numeric" LEN="0" ENT="5" DEC="0" LNG="6"/>
<row NAME="C0NESC" TEXT="N. ESCOMPTE" ORD="16" TYP="numeric" LEN="0" ENT="2" DEC="1" LNG="3"/>
<row NAME="C0SHS" TEXT="0/1 N=0 O=1 H.SERVICE" ORD="17" TYP="numeric" LEN="0" ENT="1" DEC="0" LNG="2"/>
<row NAME="C0SLCR" TEXT="O/N L.C.R." ORD="18" TYP="character" LEN="1" ENT="0" DEC="0" LNG="1"/>
<row NAME="C0SMLG" TEXT="O/N MAILING" ORD="19" TYP="character" LEN="1" ENT="0" DEC="0" LNG="1"/>
<row NAME="C0TRPL" TEXT="TYPE BLOCAGE RAPPEL" ORD="20" TYP="character" LEN="1" ENT="0" DEC="0" LNG="1"/>
<row NAME="C0ZPTT" TEXT="Z. CODE POSTAL" ORD="21" TYP="character" LEN="10" ENT="0" DEC="0" LNG="10"/>
<row NAME="C0ZCTC" TEXT="PERSONNE A CONTACTER" ORD="22" TYP="character" LEN="30" ENT="0" DEC="0" LNG="30"/>
<row NAME="C0ZDST" TEXT="PERSONNE DESTINATAIR" ORD="23" TYP="character" LEN="30" ENT="0" DEC="0" LNG="30"/>
<row NAME="C0ZNOM" TEXT="NOM / RAISON SOCIAL" ORD="24" TYP="character" LEN="30" ENT="0" DEC="0" LNG="30"/>
<row NAME="C0ZOBS" TEXT="OBSERVATIONS" ORD="25" TYP="character" LEN="30" ENT="0" DEC="0" LNG="30"/>
<row NAME="C0ZTVA" TEXT="REFERENCE TVA" ORD="26" TYP="character" LEN="15" ENT="0" DEC="0" LNG="15"/>
<row NAME="C0ZRU1" TEXT="NOM / RUE1" ORD="27" TYP="character" LEN="30" ENT="0" DEC="0" LNG="30"/>
<row NAME="C0ZRU2" TEXT="SUITE NOM / RUE1" ORD="28" TYP="character" LEN="30" ENT="0" DEC="0" LNG="30"/>
<row NAME="C0ZTL1" TEXT="N. TEL. PERS. A CONT" ORD="29" TYP="character" LEN="15" ENT="0" DEC="0" LNG="15"/>
<row NAME="C0ZTLX" TEXT="N. TELEX / TELECOPIE" ORD="30" TYP="character" LEN="15" ENT="0" DEC="0" LNG="15"/>
<row NAME="C0ZVIL" TEXT="VILLE" ORD="31" TYP="character" LEN="25" ENT="0" DEC="0" LNG="25"/>
</ZONED>
<ZONEK>
<row NAME="C0NCLI" ORD="1" TYP="numeric" LEN="0" ENT="6" DEC="0" LNG="7"/>
</ZONEK>
</FILE>
compteurI = htonl(1);
]]>Je reprends un peu le fil de la conversation, j'ai toujours des problèmes de performances. J'ai remarqué des différences notables entre Oracle et PostGre. Sur une table de plusieurs millions d'enregistrements, je remarque une différence notable entre les requêtes suivantes :
Oracle (via oci.dll, 8 sec, avec un forçage pour l'utilisation de l'index)
SELECT /*+ index_asc(F60 if60a) */ F60.*, ROWID FROM F60 WHERE f60type>' ' ORDER BY f60type, f60n_pers
PostGre (via libpq, 30sec)
BEGIN
DECLARE F60c1 CURSOR WITH HOLD FOR SELECT F60.*, OID FROM F60 WHERE f60type>' ' ORDER BY f60type, f60n_pers
FETCH 1 FROM F60c1
COMMIT
Dans la librairie oci.dll, on peut itérer sur un résultat via des fonctions spécifiques (OCIfetch), c'est pourquoi je n'utilise pas de curseur en Oracle.
VACUUM ANALYSE effectué sur toute la table.
Pour Postgre, la requête est exécutée lors de l'appel au premier FETCH, est-ce que le fait de passer par un curseur ralentit les performances ?
Est-ce que je dois me tourner vers la configuration des indexs? Optimiser la configuration de la base Postgre?
Ci-dessous la configuration de mes indexs :
Oracle
-INDEX- -uniqueness- -status- -type- -temporary- -partitioned- -join index- -columns-
IF60A NONUNIQUE VALID NORMAL N NO NO F60TYPE, F60N_PERS
IF60B NONUNIQUE VALID NORMAL N NO NO F60TYPE, F60ATOME
PostGre
CREATE INDEX if60a
ON f60
USING btree
(f60type COLLATE pg_catalog."default", f60n_pers COLLATE pg_catalog."default");
Cordialement,
Thomas