Skip to content

Commit

Permalink
repo-sqale: modifyObject updates fullObject (not attributes yet)
Browse files Browse the repository at this point in the history
  • Loading branch information
virgo47 committed Jan 27, 2021
1 parent 3937852 commit 3175ce4
Show file tree
Hide file tree
Showing 14 changed files with 191 additions and 58 deletions.
Expand Up @@ -34,6 +34,10 @@ public PrismContext getPrismContext() {
return prismContext;
}

public RelationRegistry relationRegistry() {
return relationRegistry;
}

public GetOperationOptionsBuilder getOperationOptionsBuilder() {
return new GetOperationOptionsBuilderImpl(prismContext);
}
Expand Down
33 changes: 19 additions & 14 deletions repo/repo-sqale/sql/pgnew-repo.sql
Expand Up @@ -62,13 +62,14 @@ END
$$;

-- BEFORE UPDATE trigger - must be declared on all concrete m_object sub-tables.
-- Checks that OID is not changed.
CREATE OR REPLACE FUNCTION update_object_oid()
-- Checks that OID is not changed and updates db_modified column.
CREATE OR REPLACE FUNCTION before_update_object()
RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
IF NEW.oid = OLD.oid THEN
NEW.db_modified = current_timestamp;
-- must return NEW, NULL would skip the update
RETURN NEW;
END IF;
Expand Down Expand Up @@ -126,6 +127,10 @@ CREATE TABLE m_object (
-- add GIN index for concrete tables where more than hundreds of entries are expected (see m_user)
ext JSONB,

-- these are purely DB-managed metadata, not mapped to in midPoint
db_created TIMESTAMPTZ NOT NULL DEFAULT current_timestamp,
db_modified TIMESTAMPTZ NOT NULL DEFAULT current_timestamp, -- updated in update trigger

-- prevents inserts to this table, but not to inherited ones; this makes it "abstract" table
CHECK (FALSE) NO INHERIT
);
Expand All @@ -147,8 +152,8 @@ CREATE TABLE m_resource (

CREATE TRIGGER m_resource_oid_insert_tr BEFORE INSERT ON m_resource
FOR EACH ROW EXECUTE PROCEDURE insert_object_oid();
CREATE TRIGGER m_resource_oid_update_tr BEFORE UPDATE ON m_resource
FOR EACH ROW EXECUTE PROCEDURE update_object_oid();
CREATE TRIGGER m_resource_update_tr BEFORE UPDATE ON m_resource
FOR EACH ROW EXECUTE PROCEDURE before_update_object();
CREATE TRIGGER m_resource_oid_delete_tr AFTER DELETE ON m_resource
FOR EACH ROW EXECUTE PROCEDURE delete_object_oid();

Expand Down Expand Up @@ -210,8 +215,8 @@ CREATE TABLE m_user (

CREATE TRIGGER m_user_oid_insert_tr BEFORE INSERT ON m_user
FOR EACH ROW EXECUTE PROCEDURE insert_object_oid();
CREATE TRIGGER m_user_oid_update_tr BEFORE UPDATE ON m_user
FOR EACH ROW EXECUTE PROCEDURE update_object_oid();
CREATE TRIGGER m_user_update_tr BEFORE UPDATE ON m_user
FOR EACH ROW EXECUTE PROCEDURE before_update_object();
CREATE TRIGGER m_user_oid_delete_tr AFTER DELETE ON m_user
FOR EACH ROW EXECUTE PROCEDURE delete_object_oid();

Expand Down Expand Up @@ -243,8 +248,8 @@ CREATE TABLE m_shadow (

CREATE TRIGGER m_shadow_oid_insert_tr BEFORE INSERT ON m_shadow
FOR EACH ROW EXECUTE PROCEDURE insert_object_oid();
CREATE TRIGGER m_shadow_oid_update_tr BEFORE UPDATE ON m_shadow
FOR EACH ROW EXECUTE PROCEDURE update_object_oid();
CREATE TRIGGER m_shadow_update_tr BEFORE UPDATE ON m_shadow
FOR EACH ROW EXECUTE PROCEDURE before_update_object();
CREATE TRIGGER m_shadow_oid_delete_tr AFTER DELETE ON m_shadow
FOR EACH ROW EXECUTE PROCEDURE delete_object_oid();

Expand Down Expand Up @@ -330,8 +335,8 @@ CREATE TABLE m_acc_cert_campaign (

CREATE TRIGGER m_acc_cert_campaign_oid_insert_tr BEFORE INSERT ON m_acc_cert_campaign
FOR EACH ROW EXECUTE PROCEDURE insert_object_oid();
CREATE TRIGGER m_acc_cert_campaign_oid_update_tr BEFORE UPDATE ON m_acc_cert_campaign
FOR EACH ROW EXECUTE PROCEDURE update_object_oid();
CREATE TRIGGER m_acc_cert_campaign_update_tr BEFORE UPDATE ON m_acc_cert_campaign
FOR EACH ROW EXECUTE PROCEDURE before_update_object();
CREATE TRIGGER m_acc_cert_campaign_oid_delete_tr AFTER DELETE ON m_acc_cert_campaign
FOR EACH ROW EXECUTE PROCEDURE delete_object_oid();

Expand Down Expand Up @@ -392,8 +397,8 @@ CREATE TABLE m_acc_cert_definition (

CREATE TRIGGER m_acc_cert_definition_oid_insert_tr BEFORE INSERT ON m_acc_cert_definition
FOR EACH ROW EXECUTE PROCEDURE insert_object_oid();
CREATE TRIGGER m_acc_cert_definition_oid_update_tr BEFORE UPDATE ON m_acc_cert_definition
FOR EACH ROW EXECUTE PROCEDURE update_object_oid();
CREATE TRIGGER m_acc_cert_definition_update_tr BEFORE UPDATE ON m_acc_cert_definition
FOR EACH ROW EXECUTE PROCEDURE before_update_object();
CREATE TRIGGER m_acc_cert_definition_oid_delete_tr AFTER DELETE ON m_acc_cert_definition
FOR EACH ROW EXECUTE PROCEDURE delete_object_oid();

Expand Down Expand Up @@ -437,8 +442,8 @@ CREATE TABLE m_node (

CREATE TRIGGER m_node_oid_insert_tr BEFORE INSERT ON m_node
FOR EACH ROW EXECUTE PROCEDURE insert_object_oid();
CREATE TRIGGER m_node_oid_update_tr BEFORE UPDATE ON m_node
FOR EACH ROW EXECUTE PROCEDURE update_object_oid();
CREATE TRIGGER m_node_update_tr BEFORE UPDATE ON m_node
FOR EACH ROW EXECUTE PROCEDURE before_update_object();
CREATE TRIGGER m_node_oid_delete_tr AFTER DELETE ON m_node
FOR EACH ROW EXECUTE PROCEDURE delete_object_oid();

Expand Down
Expand Up @@ -13,6 +13,7 @@

import com.google.common.base.Strings;
import com.querydsl.core.Tuple;
import com.querydsl.sql.dml.SQLUpdateClause;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

Expand All @@ -24,6 +25,7 @@
import com.evolveum.midpoint.prism.delta.ItemDelta;
import com.evolveum.midpoint.prism.delta.ItemDeltaCollectionsUtil;
import com.evolveum.midpoint.prism.delta.PropertyDelta;
import com.evolveum.midpoint.prism.equivalence.EquivalenceStrategy;
import com.evolveum.midpoint.prism.polystring.PolyString;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.repo.api.*;
Expand All @@ -39,6 +41,8 @@
import com.evolveum.midpoint.schema.internals.InternalsConfig;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.result.OperationResultStatus;
import com.evolveum.midpoint.schema.util.ObjectTypeUtil;
import com.evolveum.midpoint.util.DebugUtil;
import com.evolveum.midpoint.util.exception.*;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
Expand All @@ -57,15 +61,17 @@ public class SqaleRepositoryService implements RepositoryService {
private static final String OP_NAME_PREFIX = SqaleRepositoryService.class.getSimpleName() + '.';

private final SqlRepoContext sqlRepoContext;
private final SchemaHelper schemaService;
private final SqlQueryExecutor sqlQueryExecutor;
private final SqlTransformerContext transformerContext;

public SqaleRepositoryService(
SqlRepoContext sqlRepoContext,
SchemaHelper schemaService) {
this.sqlRepoContext = sqlRepoContext;
this.schemaService = schemaService;
this.sqlQueryExecutor = new SqlQueryExecutor(sqlRepoContext);
this.transformerContext = new SqlTransformerContext(schemaService);
this.transformerContext = new SqlTransformerContext(schemaService, sqlRepoContext);
}

@Override
Expand Down Expand Up @@ -278,12 +284,12 @@ private <S extends ObjectType, Q extends QObject<R>, R extends MObject> String a
sqlRepoContext.getMappingBySchemaType(object.getCompileTimeClass());
Q root = rootMapping.defaultAlias();

try (JdbcSession jdbcSession = sqlRepoContext.newJdbcSession().startTransaction()) {
ObjectSqlTransformer<S, Q, R> transformer = (ObjectSqlTransformer<S, Q, R>)
rootMapping.createTransformer(transformerContext, sqlRepoContext);
ObjectSqlTransformer<S, Q, R> transformer = (ObjectSqlTransformer<S, Q, R>)
rootMapping.createTransformer(transformerContext, sqlRepoContext);
R row = transformer.toRowObjectWithoutFullObject(object.asObjectable());

try (JdbcSession jdbcSession = sqlRepoContext.newJdbcSession().startTransaction()) {
// first insert without full object, because we don't know the OID yet
R row = transformer.toRowObjectWithoutFullObject(object.asObjectable());
UUID oid = jdbcSession.newInsert(root)
.populate(row)
.executeWithKey(root.oid);
Expand Down Expand Up @@ -355,7 +361,8 @@ public <T extends ObjectType> ModifyObjectResult<T> modifyObject(

if (modifications.isEmpty() && !RepoModifyOptions.isForceReindex(options)) {
LOGGER.debug("Modification list is empty, nothing was modified.");
subResult.recordStatus(OperationResultStatus.SUCCESS, "Modification list is empty, nothing was modified.");
subResult.recordStatus(OperationResultStatus.SUCCESS,
"Modification list is empty, nothing was modified.");
return new ModifyObjectResult<>(modifications);
}

Expand All @@ -372,10 +379,77 @@ public <T extends ObjectType> ModifyObjectResult<T> modifyObject(
logTraceModifications(modifications);

try (JdbcSession jdbcSession = sqlRepoContext.newJdbcSession().startTransaction()) {
T object = readByOid(jdbcSession, type, oidUuid, null);
GetOperationOptionsBuilder getOptionsBuilder = schemaService.getOperationOptionsBuilder();
T object = readByOid(jdbcSession, type, oidUuid, getOptionsBuilder.build());
//noinspection unchecked
PrismObject<T> prismObject = (PrismObject<T>) object.asPrismObject();
if (precondition != null && !precondition.holds(prismObject)) {
throw new PreconditionViolationException("Modification precondition does not hold for " + prismObject);
}
// invokeConflictWatchers(w -> w.beforeModifyObject(prismObject)); TODO

PrismObject<T> originalObject = prismObject.clone();

modifyObjectAttempt(jdbcSession, prismObject, modifications);

/*
RObject rObject = objectDeltaUpdater.modifyObject(type, oid, modifications, prismObject, modifyOptions, session, attemptContext);
LOGGER.trace("OBJECT after:\n{}", prismObject.debugDumpLazily());
// Continuing the photo treatment: should we remove the (now obsolete) focus photo?
// We have to test prismObject at this place, because updateFullObject (below) removes photo property from the prismObject.
shouldPhotoBeRemoved =
containsFocusPhotoModification && ((FocusType) prismObject.asObjectable()).getJpegPhoto() == null;
updateFullObject(rObject, prismObject);
LOGGER.trace("Starting save.");
session.save(rObject);
LOGGER.trace("Save finished.");
*/

// TODO is modifications cloning unavoidable? see the clone at the start of ObjectUpdater.modifyObjectAttempt
// If cloning will be necessary, do it at the beginning of modifyObjectAttempt,
// especially if called potentially multiple times.
return new ModifyObjectResult<>(originalObject, prismObject, modifications);
}
return null;
// TODO
}

/**
* @param <S> schema type
* @param <Q> type of entity path
* @param <R> row type related to the {@link Q}
*/
private <S extends ObjectType, Q extends QObject<R>, R extends MObject>
void modifyObjectAttempt(
JdbcSession jdbcSession,
PrismObject<S> prismObject,
Collection<? extends ItemDelta<?, ?>> modifications) throws SchemaException {

Collection<? extends ItemDelta<?, ?>> narrowedModifications =
prismObject.narrowModifications(modifications, EquivalenceStrategy.DATA,
EquivalenceStrategy.REAL_VALUE_CONSIDER_DIFFERENT_IDS, true);
LOGGER.trace("Narrowed modifications:\n{}", DebugUtil.debugDumpLazily(narrowedModifications));

SqaleModelMapping<S, Q, R> rootMapping =
sqlRepoContext.getMappingBySchemaType(prismObject.getCompileTimeClass());
Q root = rootMapping.defaultAlias();
// TODO update will probably be replaced by some "update context" to be able to update multiple tables (+insert/delete of details)
SQLUpdateClause update = jdbcSession.newUpdate(root)
.where(root.oid.eq(UUID.fromString(prismObject.getOid())));

// TODO taken from "legacy" branch, how is this worse/different from ObjectDeltaUpdater.handleObjectCommonAttributes()?
ItemDeltaCollectionsUtil.applyTo(modifications, prismObject);
ObjectTypeUtil.normalizeAllRelations(prismObject, schemaService.relationRegistry());
// TODO generate missing container IDs? is it needed? doesn't model do it? see old repo PrismIdentifierGenerator

int newVersion = SqaleUtils.objectVersionAsInt(prismObject) + 1;
prismObject.setVersion(String.valueOf(newVersion));
ObjectSqlTransformer<S, Q, R> transformer = (ObjectSqlTransformer<S, Q, R>)
rootMapping.createTransformer(transformerContext, sqlRepoContext);
update.set(root.fullObject, transformer.createFullObject(prismObject.asObjectable()));
update.set(root.version, newVersion);
update.execute();
}

private void logTraceModifications(@NotNull Collection<? extends ItemDelta<?, ?>> modifications) {
Expand Down Expand Up @@ -638,7 +712,7 @@ public void destroy() {
/**
* Handles exception outside of transaction - this does not handle transactional problems.
*/
private void handleGeneralException(Throwable ex, OperationResult result) {
private void handleGeneralException(@NotNull Throwable ex, OperationResult result) {
LOGGER.error("General checked exception occurred.", ex);
recordException(ex, result,
sqlRepoContext.getJdbcRepositoryConfiguration().isFatalException(ex));
Expand All @@ -649,9 +723,8 @@ private void handleGeneralException(Throwable ex, OperationResult result) {
}

private void recordException(@NotNull Throwable ex, OperationResult result, boolean fatal) {
String message = ex != null && Strings.isNullOrEmpty(ex.getMessage())
? ex.getMessage() : "null";
if (Strings.isNullOrEmpty(message) && ex != null) {
String message = Strings.isNullOrEmpty(ex.getMessage()) ? ex.getMessage() : "null";
if (Strings.isNullOrEmpty(message)) {
message = ex.getMessage();
}

Expand Down
Expand Up @@ -17,7 +17,6 @@
import org.slf4j.LoggerFactory;

import com.evolveum.midpoint.repo.sqlbase.SqlTransformerContext;
import com.evolveum.midpoint.repo.sqlbase.SqlRepoContext;
import com.evolveum.midpoint.repo.sqlbase.mapping.QueryModelMapping;
import com.evolveum.midpoint.repo.sqlbase.mapping.SqlTransformer;
import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase;
Expand All @@ -35,13 +34,12 @@ public abstract class SqaleTransformerBase<S, Q extends FlexibleRelationalPathBa

protected final SqlTransformerContext transformerContext;
protected final QueryModelMapping<S, Q, R> mapping;
protected final SqlRepoContext sqlRepoContext;

protected SqaleTransformerBase(SqlTransformerContext transformerContext,
QueryModelMapping<S, Q, R> mapping, SqlRepoContext sqlRepoContext) {
protected SqaleTransformerBase(
SqlTransformerContext transformerContext,
QueryModelMapping<S, Q, R> mapping) {
this.transformerContext = transformerContext;
this.mapping = mapping;
this.sqlRepoContext = sqlRepoContext;
}

/**
Expand Down
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2010-2021 Evolveum and contributors
*
* This work is dual-licensed under the Apache License 2.0
* and European Union Public License. See LICENSE file for details.
*/
package com.evolveum.midpoint.repo.sqale;

import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;

public class SqaleUtils {

/**
* Returns version from midPoint object as a number.
* Returns 0 for any non-number version, never returns null.
*/
public static int objectVersionAsInt(ObjectType schemaObject) {
String version = schemaObject.getVersion();
if (version != null) {
try {
return Integer.parseInt(version);
} catch (NumberFormatException e) {
// ignorable, version will be 0
}
}
return 0;
}

/**
* Returns version from prism object as a number.
* Returns 0 for any non-number version, never returns null.
*/
public static int objectVersionAsInt(PrismObject<?> prismObject) {
String version = prismObject.getVersion();
if (version != null) {
try {
return Integer.parseInt(version);
} catch (NumberFormatException e) {
// ignorable, version will be 0
}
}
return 0;
}
}
Expand Up @@ -8,18 +8,17 @@

import org.jetbrains.annotations.NotNull;

import com.evolveum.midpoint.repo.sqlbase.SqlTransformerContext;
import com.evolveum.midpoint.repo.sqale.qbean.MNode;
import com.evolveum.midpoint.repo.sqale.qmodel.QNode;
import com.evolveum.midpoint.repo.sqlbase.SqlRepoContext;
import com.evolveum.midpoint.repo.sqlbase.SqlTransformerContext;
import com.evolveum.midpoint.xml.ns._public.common.common_3.NodeType;

public class NodeSqlTransformer
extends ObjectSqlTransformer<NodeType, QNode, MNode> {

public NodeSqlTransformer(
SqlTransformerContext transformerContext, QNodeMapping mapping, SqlRepoContext sqlRepoContext) {
super(transformerContext, mapping, sqlRepoContext);
SqlTransformerContext transformerContext, QNodeMapping mapping) {
super(transformerContext, mapping);
}

@Override
Expand Down

0 comments on commit 3175ce4

Please sign in to comment.