Giter VIP home page Giter VIP logo

node-red-contrib-postgresql's Introduction

node-red-contrib-postgresql

node-red-contrib-postgresql is a Node-RED node to query a PostgreSQL 🐘 database.

It supports splitting the resultset and backpressure (flow control), to allow working with large datasets.

It supports parameterized queries and multiple queries.

Outputs

The response (rows) is provided in msg.payload as an array.

An exception is if the Split results option is enabled and the Number of rows per message is set to 1, then msg.payload is not an array but the single-row response.

Additional information is provided as msg.pgsql.rowCount and msg.pgsql.command. See the underlying documentation for details.

In the case of multiple queries, then msg.pgsql is an array.

Inputs

SQL query template

This node uses the Mustache template system to generate queries based on the message:

-- INTEGER id column
SELECT * FROM table WHERE id = {{{ msg.id }}};

-- TEXT id column
SELECT * FROM table WHERE id = '{{{ msg.id }}}';

Dynamic SQL queries

As an alternative to using the query template above, this node also accepts an SQL query via the msg.query parameter.

Parameterized query (numeric)

Parameters for parameterized queries can be passed as a parameter array msg.params:

// In a function, provide parameters for the parameterized query
msg.params = [ msg.id ];
-- In this node, use a parameterized query
SELECT * FROM table WHERE id = $1;

Named parameterized query

As an alternative to numeric parameters, named parameters for parameterized queries can be passed as a parameter object msg.queryParameters:

// In a function, provide parameters for the named parameterized query
msg.queryParameters.id = msg.id;
-- In this node, use a named parameterized query
SELECT * FROM table WHERE id = $id;

Note: named parameters are not natively supported by PostgreSQL, and this library just emulates them, so this is less robust than numeric parameters.

Dynamic PostgreSQL connection parameters

If the information about which database server to connect and how needs to be dynamic, it is possible to pass a custom client configuration in the message:

msg.pgConfig = {
  user?: string, // default process.env.PGUSER || process.env.USER
  password?: string, //or function, default process.env.PGPASSWORD
  host?: string, // default process.env.PGHOST
  database?: string, // default process.env.PGDATABASE || process.env.USER
  port?: number, // default process.env.PGPORT
  connectionString?: string, // e.g. postgres://user:password@host:5432/database
  ssl?: any, // passed directly to node.TLSSocket, supports all tls.connect options
  types?: any, // custom type parsers
  statement_timeout?: number, // number of milliseconds before a statement in query will time out, default is no timeout
  query_timeout?: number, // number of milliseconds before a query call will timeout, default is no timeout
  application_name?: string, // The name of the application that created this Client instance
  connectionTimeoutMillis?: number, // number of milliseconds to wait for connection, default is no timeout
  idle_in_transaction_session_timeout?: number, // number of milliseconds before terminating any session with an open idle transaction, default is no timeout
};

However, this does not use a connection pool, and is therefore less efficient. It is therefore recommended in most cases not to use msg.pgConfig at all and instead stick to the built-in configuration node.

Installation

Using the Node-RED Editor

You can install node-red-contrib-postgresql directly using the editor: Select Manage Palette from the menu (top right), and then select the Install tab in the palette.

Using npm

You can alternatively install the npm-packaged node:

  • Locally within your user data directory (by default, $HOME/.node-red):
cd $HOME/.node-red
npm i node-red-contrib-postgresql
  • or globally alongside Node-RED:
npm i -g node-red-contrib-postgresql

You will then need to restart Node-RED.

Backpressure

This node supports backpressure / flow control: when the Split results option is enabled, it waits for a tick before releasing the next batch of lines, to make sure the rest of your Node-RED flow is ready to process more data (instead of risking an out-of-memory condition), and also conveys this information upstream.

So when the Split results option is enabled, this node will only output one message at first, and then awaits a message containing a truthy msg.tick before releasing the next message.

To make this behaviour potentially automatic (avoiding manual wires), this node declares its ability by exposing a truthy node.tickConsumer for downstream nodes to detect this feature, and a truthy node.tickProvider for upstream nodes. Likewise, this node detects upstream nodes using the same back-pressure convention, and automatically sends ticks.

Example of flow

Example adding a new column in a table, then streaming (split) many lines from that table, batch-updating several lines at a time, then getting a sample consisting of a few lines:

Example: flow.json

Node-RED flow

The debug nodes illustrate some relevant information to look at.

Sequences for split results

When the Split results option is enabled (streaming), the messages contain some information following the conventions for messages sequences.

{
  payload: '...',
  parts: {
    id: 0.1234, // sequence ID, randomly generated (changes for every sequence)
    index: 5, // incremented for each message of the same sequence
    count: 6, // total number of messages; only available in the last message of a sequence
    parts: {}, // optional upstream parts information
  },
  complete: true, // True only for the last message of a sequence
}

Credits

Major rewrite in July 2021 by Alexandre Alapetite (Alexandra Institute), of parents forks: andreabat / ymedlop / HySoaKa, with inspiration from node-red-contrib-re-postgres (code).

This node builds uppon the node-postgres (pg) library.

Contributions and collaboration welcome.

node-red-contrib-postgresql's People

Contributors

aformusatii avatar alkarex avatar andreabat avatar dependabot[bot] avatar hysoaka avatar tedeh avatar wodka avatar ymedlop avatar zinen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

node-red-contrib-postgresql's Issues

return list of pg records successfully inserted as an array in msg.payload

Use-case: As a Node-RED user with the postgres node installed, I am inserting records into a postgres database that assigns a UUID/GUID to each record as part of DB logic, therefore I need the list of pg records successfully returned in order to successfully perform additional updates on those records using the DB assigned UUID.

Current outcome: as a user of the postgres node, the only data returned from a successful INSERT is the msg.psql object which informs how many rows were impacted by the given operation, but no other data is returned.

Please let me know if I am missing something/need to assign a param somewhere. Thanks!

dynamic global and flow variables

Hi, and thank you for this node!
I have to address different postgres server, therefore I tried to set the HOST via "flow" or "global" variables.

If I change the HOST to "flow.sqlip" and deploy the flow, I immediately receive an error in the debug area:
123

Deploying with "global.sqlip" does not throw an error in the debug area but unfortunately it does not work as well if the variable gets updated while the flow is running. Example: Lets say global.sqlip is set to 10.0.0.15 and the flow is deployed, after some time global.sqlip gets updated to 10.0.0.18 (programmatically) without redeploying -> then I receive a connection timeout because the node still try's to connect to 10.0.0.15 (I think).

Is this is a known issue?

node-red-contrib-postgresql crashes on Citrix virtualized Windows 10 desktop host but not on physical Linux host

I am trying to migrate my flows from a physical Linux (Ubuntu) host to a Citrix virtualized Windows 10 desktop host.
Even the simplest flow containing postgresql crashes when triggered.
Interestingly, node-red-contrib-postgres-variable does not crash.

On the Windows environment, which is virtualized via Citrix, I used Powershell to globally install nsm and all the nsm packages, and used the node-red pallete manage to install the same palette as on Linux / node-red.

The linux is a physical laptop.

I have attached both flows.

In the Windows system, clicking either of these crashes node-red, and I have to remove the flows in .node-red in my user directory and import or start over.

image

But injecting to the (green) -variable ones work.
image

two postgresql flows.zip

Postgres Node fails multiple insert statements with parameterized inputs

Environment
Node-RED version: 2.2.0
node-red-contrib-postgresql version: 0.8.0

Expected outcome: as a Node-Red editor user, I can propagate the msg.params variable to the postgres node in my Node-RED flow which will successfully execute a multiple insert statements using the numeric parameters approach.

Current outcome: the postgres node returns an error when attempting to perform multiple insert (and update!) statements in a single node query editor.

Error statement

error: {
message: "error: cannot insert multiple commands into a prepared statement"
}

Sample statement encountering error

INSERT INTO public.users ( "firstName","lastName","email","username","password","isPoliticallyExposed",
"onboardingStatus","apiKey","resetPasswordToken","resetPasswordTokenCreated","emailConfirmationToken",
"emailConfirmationDate","secondLastName","city","country","addressLine1","addressLine2","region",
"postalCode","dialingCode","phoneNumber","currentOrganizationId","cifId","politicalPosition","mfaToken",
"mfaTokenExpiry"
)VALUES (
    $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26
);
-- insert user record

-- 2. insert organization record
INSERT INTO public.organizations( "type","onboardingStatus","legalName","commercialName",
"natureofBusiness","businessType","totalShares","country","addressLine1","addressLine2","city",
"region","postalCode","taxId","createdBy","kybStatus",
)VALUES(
$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$40,$41,$42,(select id from public.users where "username"=$4),$44
);

-- insert user_organization record
INSERT INTO public.user_organizations (
    "userId","role","organizationId"
)VALUES(
(select id from public.users where "username"=$1),'ADMIN',(select id from public.organizations where "username"=$4)
)
RETURNING id as user_organization_id;

UPDATE public.users SET "currentOrganizationId" = (select id from public.organizations where "legalName"=$4) WHERE username=$4;

Please consider, the postgres node behaves as expected when performing multiple inserts for non-numeric parameterized queries such as this:

CREATE TEMP TABLE organization(
    organization_id serial,
    organization_name varchar(128),
    organization_type varchar(64),
    created_date_time timestamp DEFAULT now()
);
INSERT INTO organization(organization_name,organization_type)VALUES('someone's org 1','personal'),('someone's org 2','personal'),
('someone's org3 org','personal'),('someone's org4','personal'),('someone's org5','personal'),('someone's org6 org','personal');
-- create user junction table
CREATE TEMP TABLE user__organization(user_id varchar(64), organization_id varchar(64),user_role varchar(32));
-- insert junction records into this temp table
INSERT INTO user__organization VALUES('1','1','Admin'),('3','2','Admin'),('4','3','Admin'),('2','5','Admin'),('5','6','Admin');

select u."id","firstName","lastName","email",user_role,o.organization_id,o.organization_name,o.created_date_time
FROM public.user u JOIN user__organization uo ON text(u."id") = uo.user_id
JOIN organization o ON uo.organization_id = text(o.organization_id);

error when using number as column name

I receive the following error message:

error: syntax error at or near "`" UPDATE people
SET `5`='{"pet":"dog"}'
WHERE id = '5';

The syntax seems correct

SSL error

Hi,

Thanks for the node.

I am using the node for a simple query and I get "Error: self signed certificate in certificate chain" error if I set ssl:true
If I set ssl:false I get "error: no pg_hba.conf entry for host "", user "postgres", database "<db_name>", no encryption"

Postgres engine version: 15.4

Thanks

Feature: accept input msg.query

A feature request.

Accept input query via eg. msg.query and thereby be able to use node red native template node for queries with variables.

Error with name that contains an uppercase letter

Hi,
thanks for the node.
I have a problem when i am trying to reach a table with a uppercase letter.
I have a table named "Gant"
image
When i try to select from it i receive an error back:
"error: relation "public.gant" does not exist"
image
I think the problem is that the node is searching for "gant" and not for "Gant", if i rename the table from PostgreSQL in "gant" everything work.

Edit:
The same error is recurring with the Columns name
image

image

SSL: self signed certificate

While upgrading from an older version of nodered to the latest, I tested this node.
When trying to connect to a Digital Ocean managed database with SSL=true I get the following error:
"Error: self signed certificate in certificate chain"

With SSL=false i get this error:
error: no pg_hba.conf entry for host "xxx", user "xxx", database "xxx", SSL off

I think the reason for these errors are that pg since v. 8.0 sets
rejectUnathurized = true
as default as described here: https://node-postgres.com/announcements

At the same time DO probably self-signs their certificates as speculated here: https://github.com/Budibase/budibase/issues/1967#issuecomment-879981467

I am able to connect to my database by passing this config node as described in the documentation:

msg.pgConfig = {
  user: 'xxx',
  password:'xxx',
  host: 'xx.xx.xx',
  database: 'xxx',
  port: xxxx, 
  ssl: {
  rejectUnauthorized: false
  }
};

But it would be neat to be able to set rejectUnathorized in the properties setting in the node:
image

no msg.complete or msg.count when using sequence

thanks for the node.
I dont get msg.count on any message , or msg.complete when using the split function.
I also dont get rowCount or Command

Not sure why?

I get rowCount and Command if I don't use the split function

Can't get SSL CA file to work with config

Hi,
I have a self-signed CA and want to load the CA file into the config of this node.
Now have it working with {"rejectUnauthorized": false} in the SSL options, but whatever I do, I don't get the ca file to be accepted. Doesn't seem to do anything.

Tried:
{
"rejectUnauthorized": true and false,
"ca": "/path/to/file"
}
-AND-
{
"rejectUnauthorized": true and false,
"ca": "COMPLETE_CA_CERT_STRING"
}

When rejectUnauthorized is set to false it always works. When set to true it doesn't work.
The only message that shows up is: Error: self-signed certificate in certificate chain
I don't get an error stating that the CA file cannot be found or is invalid, suspecting that that part of the config isn't used.

Version: 0.14.0

Thanks in advance for your help.

[QUESTION] Protection against SQL-Injections

Hello,

from what I saw while skimming through the repository and documentation, this Node does not have built-in protection against SQL-Injections, correct?
So if I want a secure app, I would have to manually sanitize my inputs beforehand?

Add option for batch insert

Based on https://node-postgres.com

There are a few different approaches to consider:

Copy streams: https://github.com/brianc/node-pg-copy-streams

Multiple executes:

CREATE TABLE person (
  id SERIAL PRIMARY KEY,
  name TEXT,
  age INTEGER
);

--

PREPARE insert_person_plan (text, integer) AS
INSERT INTO person (name, age)
VALUES ($1, $2);

BEGIN;
EXECUTE insert_person_plan('Alice', 25);
EXECUTE insert_person_plan('Bob', 30);
EXECUTE insert_person_plan('Charlie', 35);
COMMIT;

{
	"execute": {
		"insert_person_plan": [
			["Alice", 25],
			["Bob", 30],
			["Charlie", 35],
		]
	}
}

--

DEALLOCATE insert_person_plan;

SELECT * FROM person;

DROP TABLE person;

Error: Connection terminated due to connection timeout

Hello,

I have this issue : Error: Connection terminated due to connection timeout select * from ...
I do a simple code using directly pg package and I have not got thie issue.

Could you please explain me if Pool object is the orign of this problem.

Thanks in advance for your help

How to handle database errors?

Is there a way to identify and handle database errors (such as a table or database not existing)? Currently it seems like the plugin is just putting the error into the msg.payload and then passing it along like a normal message, but I don't want to display the errors (which includes the SQL that caused the error) to the users.

Transaction support

Hi,
not properly an issue but i don't understand if it's possible in some way to use transaction with automatic rollback if an error occoured.

If yes, how/where to find some example/documentation about that?

Thanks in advance.

timestamp without timezone format issue

Querying a table with a column of the type timestamp without timezone returns the time in the given format: [date][“T”][time][“Z”].
However, the “Z” notation indicates that the time is UTC and as such I think the format should be changed to [date][“T”][time].

DateTime type error

Hello,
every things ok but....
I'd like to insert timestamp in my database, this the last value of my query, but I don't know why the format is changed as we can see in this capture:
image

Why the query convert the time in GMT ?

Originally posted by @FlorianBfr in #41 (comment)

Abrupt termination after some time running - [error] Error: Connection terminated unexpectedly

Hello!

Being unable to find a solution there, I'm bringing this issue here from my post in Node-RED forum. I figured since the error happens at the pg lib, I might find a clarification here.

I've been using Node-RED with Docker, trying to run the flow below:

flow node-red

It's a simple flow: get some data from this postgres db, do something, then insert the data into this other postgres db.

This is the error I was having:

1 Sep 13:39:40 - [red] Uncaught Exception:
1 Sep 13:39:40 - [error] Error: Connection terminated unexpectedly
at Connection. (/data/node_modules/pg/lib/client.js:132:73)
at Object.onceWrapper (node:events:627:28)
at Connection.emit (node:events:513:28)
at Socket. (/data/node_modules/pg/lib/connection.js:63:12)
at Socket.emit (node:events:513:28)
at TCP. (node:net:301:12)

No exception was caught by the catch:all node in my flow and Node-RED just terminates.

When I run the same flow, also with Docker using my laptop, it works, it keeps running with no problems. For reference, this PC with the error uses Windows 10, my laptop uses Windows 11.

Something odd happened, though. Trying to uncover where the error was happening in my flow, I:

  1. Removed the inserts from my flow and let it run;
  2. Attested it was running for some time (hours) without terminating;
  3. Added back the inserts, goal to test and reproduce the termination;
  4. Attested that the program ran 2,5 days straight with no problems, until I terminated it this morning.

I mean, it is working now, but still couldn't figure it out that error and sudden termination, and I'm afraid it could come back.

Node-red version: 3.0.2
Node-js version: 16.20.1
node-red-contrib-posgresql version: 0.13.0

Any clarification or insight would be very appreciated and I'm here to provide further information. Thanks!

Enable projects settings do not work

Hey,

We have a problem that if we connect postgre in our settings.js
Screenshot 2024-05-07 at 15 26 48

and we want to enable also "projects" settings - the entire app is not working.
We did tests with pure example project with just added changes from the screenshot above.

Thanks in advance!

possible to query directly in node-red function

Is it possible to query postgres directly in a node-red function?
I found an article that explains the process for mysql and I'm hoping that there's something similar.
`// Initialize the MySQL node
var mysql = context.get('mysql');

// Define the SQL query to be executed
var sql = 'SELECT * FROM users WHERE id = 1';

// Execute the query and retrieve the results
var result = await mysql.query(sql);

// Use the results in your JavaScript code
msg.payload = result;`

https://community.home-assistant.io/t/access-sql-database-from-within-a-node-red-function-node/501344

Server connection pool getting filled by idle "wait: ClientRead" connections when sending queries rapidly

Hey, thanks for this node-red node. I was able to get it up and running pretty quick, but I'm running into a small issue. Simple insert queries are hanging when fired off too fast. It causes the connection pool on the server to fill up, which causes later queries to fail due to "Error: timeout exceeded when trying to connect".

A workaround is to add a rate-limit delay node, which tells me that something is getting forgotten when more than one query is being run at a time. I believe this would be insufficient if I had many query nodes in my flows because any collision would leave a connection hanging and eventually lead to pool exhaustion.

I'm not doing anything too clever. Postgres is installed and connected over 127.0.0.1, and it's a clean install of Postgres 14. No other applications are connecting at this time -- I have shut down grafana, which is the only other thing connected to the server.

My query is this:

INSERT INTO "public"."metrics"
("name", "metric", "units", "type")
VALUES('{{{ msg.topic }}}', {{{ msg.payload.value }}}, 'ºF', '{{{ msg.payload.name }}}')

It gets expanded correctly and is received by postgres like this, which I pulled from the query log:

INSERT INTO "public"."metrics"
("name", "metric", "units", "type")
VALUES('Sensor 2', 39.46, 'ºF', 'temperature')

The first batch of events query node execute fine and data ends up in the table. But the n-1 queries never finishes and the connection is left hanging open:

> psql
psql (14.0)
Type "help" for help.

robert=# select client_addr, wait_event, state, query from pg_stat_activity;
 client_addr |     wait_event      | state  |                                                               query
-------------+---------------------+--------+-----------------------------------------------------------------------------------------------------------------------------------
             | AutoVacuumMain      |        | 
             | LogicalLauncherMain |        | 
             |                     | active | select client_addr, wait_event, state, query from pg_stat_activity;
 127.0.0.1   | ClientRead          | active | INSERT INTO "public"."metrics" ("name", "metric", "units", "type") VALUES('Sensor 1', 60.35, 'ºF', 'temperature')
 127.0.0.1   | ClientRead          | idle   | INSERT INTO "public"."metrics" ("name", "metric", "units", "type") VALUES('Sensor 2', 39.46, 'ºF', 'temperature')
 127.0.0.1   | ClientRead          | active | INSERT INTO "public"."metrics" ("name", "metric", "units", "type") VALUES('Sensor 2', 39.46, 'ºF', 'temperature')
 127.0.0.1   | ClientRead          | idle   | INSERT INTO "public"."metrics" ("name", "metric", "units", "type") VALUES('Sensor 2', 39.46, 'ºF', 'temperature')
             | BgWriterMain        |        | 
             | CheckpointerMain    |        | 
             | WalWriterMain       |        | 
(10 rows)

These connections listed here will never close -- triggering my flow again fires 5 queries and 4 of them will never correctly finish.

Here are some screenshots:

Node-Red flow:
A working node-red flow:

Crashing on nodered 2.22

Morn. So latest docker nodered image, if I install your posgres node, nodered runs ok. If i drag and drop on workspace, nodered keeps on crashing. Before even I put credentials.

Your node is awesome bro. I use it on thousand flows. Please help.
btw. I run the latest docker image. SO please test on docker image.
Regards

Jakes

Cannot read properties of null (reading 'tickConsumer')

Hi,

I am using the node-red-contrib-postgresql to insert data into a postgres db. I have this error with one my my flows:

4 Jan 09:02:43 - [error] TypeError: Cannot read properties of null (reading 'tickConsumer') at /data/node_modules/node-red-contrib-postgresql/postgresql.js:159:74 at findInputNodeId (/data/node_modules/node-red-contrib-postgresql/postgresql.js:19:49) at PostgreSQLNode._inputCallback (/data/node_modules/node-red-contrib-postgresql/postgresql.js:159:22) at /usr/src/node-red/node_modules/@node-red/runtime/lib/nodes/Node.js:210:26 at Object.trigger (/usr/src/node-red/node_modules/@node-red/util/lib/hooks.js:166:13) at PostgreSQLNode.Node._emitInput (/usr/src/node-red/node_modules/@node-red/runtime/lib/nodes/Node.js:202:11) at PostgreSQLNode.Node.emit (/usr/src/node-red/node_modules/@node-red/runtime/lib/nodes/Node.js:186:25) at PostgreSQLNode.Node.receive (/usr/src/node-red/node_modules/@node-red/runtime/lib/nodes/Node.js:485:10) at Immediate.<anonymous> (/usr/src/node-red/node_modules/@node-red/runtime/lib/flows/Flow.js:831:52) at processImmediate (node:internal/timers:466:21)

Any ideas?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.