Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

escape columns in InsertQueryBuilder.orUpdate #6316

Merged
merged 1 commit into from
Feb 8, 2021

Conversation

Vrtak-CZ
Copy link
Contributor

@Vrtak-CZ Vrtak-CZ commented Jun 26, 2020

Fixies this use-case

await repository
        .createQueryBuilder()
        .insert()
        .values({
            name,
            code,
            createdAt: new Date(),
            updatedAt: new Date(),
        })
        .orUpdate({
            conflict_target: ['name'],
            overwrite: ['code', 'updatedAt'],
        })
        .execute();

because it generates:

INSERT INTO "my_table"("id", "name", "code", "createdAt", "updatedAt") VALUES (DEFAULT, $1, $2, $3, $4) ON CONFLICT  ( name )  DO UPDATE SET code = EXCLUDED.code, updatedAt = EXCLUDED.updatedAt

and it causes:

ERROR:  column excluded.updatedat does not exist
LINE 1: ...  DO UPDATE SET code = EXCLUDED.code, updatedAt = EXCLUDED.u...
                                                             ^
HINT:  Perhaps you meant to reference the column "excluded.updatedAt".

instead of:

INSERT INTO "my_table"("id", "name", "code", "createdAt", "updatedAt") VALUES (DEFAULT, $1, $2, $3, $4) ON CONFLICT  ( "name" )  DO UPDATE SET "code" = EXCLUDED."code", "updatedAt" = EXCLUDED."updatedAt"

@Vrtak-CZ Vrtak-CZ changed the title esacpe columns in InsertQueryBuilder.orUpdate escape columns in InsertQueryBuilder.orUpdate Jun 29, 2020
if (statement && Array.isArray(statement.columns))
this.expressionMap.onUpdate.columns = statement.columns.map(column => `${column} = :${column}`).join(", ");
this.expressionMap.onUpdate.columns = statement.columns.map(column => `${this.escape(column)} = :${column}`).join(", ");
if (statement && Array.isArray(statement.overwrite)) {
if (this.connection.driver instanceof MysqlDriver || this.connection.driver instanceof AuroraDataApiDriver) {
this.expressionMap.onUpdate.overwrite = statement.overwrite.map(column => `${column} = VALUES(${column})`).join(", ");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did you ignore a mysql?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i do not work with MySQL so i don't know if it's needed

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MySQL might not need this as it preserves case sensitivity for column names if no quotes. https://seeq.atlassian.net/wiki/spaces/KB/pages/443088907/SQL+Column+Names+and+Case+Sensitivity

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we escape MySQL anyways as part of this to improve that side of things as well?

Copy link

@gintsgints gintsgints Oct 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In code for columns pleerock removed extra escaping from columns some two years ago :) . So probably more stable decision needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so what is the decision? should i add escaping for MySQL or not? I didn't work with MySQL for few years now so i do not know if it's needed or if it breaks something when it's escaped when you don't need to escape.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gintsgints do you have any insights on why we removed extra escaping?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Vrtak-CZ it will be consistent if we add for MySQL as well. Case sensitivity preservation is a configuration option that is different by default in different databases.

@pleerock
Copy link
Member

pleerock commented Jul 6, 2020

You are sure conflict_target and overwrite only accept a column names as their values? Can you please add tests, so we can be sure functionality is properly working for all platforms and won't break in future

@Vrtak-CZ
Copy link
Contributor Author

Vrtak-CZ commented Aug 6, 2020

You are sure conflict_target and overwrite only accept a column names as their values?

I'm not.

 Can you please add tests, so we can be sure functionality is properly working for all platforms and won't break in future.

Few tests added

@imnotjames
Copy link
Contributor

Can you rebase against master so the tests kick off fully?

@Vrtak-CZ
Copy link
Contributor Author

@imnotjames done

@imnotjames imnotjames self-requested a review October 14, 2020 22:29
@imnotjames
Copy link
Contributor

Unfortunately, some test failures.

query builder > insertion > on conflict 1) "before all" hook for "should perform insertion correctly" 2) "after all" hook for "should perform insertion correctly" 371 passing (2m) 9 pending 2 failing 1) query builder > insertion > on conflict "before all" hook for "should perform insertion correctly": DataTypeNotSupportedError: Data type "timestamp with time zone" in "Post.date" is not supported by "better-sqlite3" database. at new DataTypeNotSupportedError (build/compiled/src/error/DataTypeNotSupportedError.js:2:568) at /typeorm/build/compiled/src/metadata-builder/EntityMetadataValidator.js:29:2316 at Array.forEach (<anonymous>) at EntityMetadataValidator.validate (build/compiled/src/metadata-builder/EntityMetadataValidator.js:29:2045) at /typeorm/src/metadata-builder/EntityMetadataValidator.ts:27:100 at Array.forEach (<anonymous>) at EntityMetadataValidator.validateMany (src/metadata-builder/EntityMetadataValidator.ts:27:100) at Connection.buildMetadatas (src/connection/Connection.ts:177:29) at Connection.<anonymous> (build/compiled/src/connection/Connection.js:39:31) at step (node_modules/tslib/tslib.js:141:27) at Object.next (node_modules/tslib/tslib.js:122:57) at fulfilled (node_modules/tslib/tslib.js:112:62) 2) query builder > insertion > on conflict "after all" hook for "should perform insertion correctly": TypeError: Cannot read property 'map' of undefined at Object.closeTestingConnections (test/utils/test-utils.ts:289:36) at Context.<anonymous> (test/functional/query-builder/insert-on-conflict/query-builder-insert-on-conflict.ts:14:17) at processImmediate

@Vrtak-CZ Vrtak-CZ force-pushed the escape-columns branch 2 times, most recently from 1f73bd6 to 86198a6 Compare October 18, 2020 12:15
Copy link
Contributor

@imnotjames imnotjames left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a great change to make. Test cases can be improved, maybe.

if (statement && Array.isArray(statement.columns))
this.expressionMap.onUpdate.columns = statement.columns.map(column => `${column} = :${column}`).join(", ");
this.expressionMap.onUpdate.columns = statement.columns.map(column => `${this.escape(column)} = :${column}`).join(", ");
if (statement && Array.isArray(statement.overwrite)) {
if (this.connection.driver instanceof MysqlDriver || this.connection.driver instanceof AuroraDataApiDriver) {
this.expressionMap.onUpdate.overwrite = statement.overwrite.map(column => `${column} = VALUES(${column})`).join(", ");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we escape MySQL anyways as part of this to improve that side of things as well?

@Vrtak-CZ Vrtak-CZ force-pushed the escape-columns branch 2 times, most recently from 50d9fb6 to 717ccc1 Compare October 20, 2020 16:45
@Vrtak-CZ
Copy link
Contributor Author

is there anything more I can do?

@pleerock pleerock merged commit ab56e07 into typeorm:master Feb 8, 2021
@pleerock
Copy link
Member

pleerock commented Feb 8, 2021

Sorry for delayed merge. Thank you for contribution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants